Updated the code to support additional session id prefixes

pull/592/head
Morgan Pretty 3 years ago
parent 27d9e41eaf
commit 394b0646a3

@ -777,15 +777,16 @@
FCB11D8C1A129A76002F93FB /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FCB11D8B1A129A76002F93FB /* CoreMedia.framework */; };
FD5D200F27AA2B6000FEA984 /* MessageRequestResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5D200E27AA2B6000FEA984 /* MessageRequestResponse.swift */; };
FD5D201127AA331F00FEA984 /* ConfigurationMessage+Convenience.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5D201027AA331F00FEA984 /* ConfigurationMessage+Convenience.swift */; };
FD5D201E27B0D87C00FEA984 /* IdPrefix.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5D201D27B0D87C00FEA984 /* IdPrefix.swift */; };
FD659AC027A7649600F12C02 /* MessageRequestsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD659ABF27A7649600F12C02 /* MessageRequestsViewController.swift */; };
FD88BAD927A7439C00BBC442 /* MessageRequestsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD88BAD827A7439C00BBC442 /* MessageRequestsCell.swift */; };
FD88BADB27A750F200BBC442 /* MessageRequestsMigration.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD88BADA27A750F200BBC442 /* MessageRequestsMigration.swift */; };
FD705A8C278CDB5600F16121 /* SAEScreenLockViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD705A8B278CDB5600F16121 /* SAEScreenLockViewController.swift */; };
FD705A8E278CE29800F16121 /* String+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD705A8D278CE29800F16121 /* String+Localization.swift */; };
FD705A90278CEBBC00F16121 /* ShareAppExtensionContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD705A8F278CEBBC00F16121 /* ShareAppExtensionContext.swift */; };
FD705A92278D051200F16121 /* ReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD705A91278D051200F16121 /* ReusableView.swift */; };
FD705A94278D052B00F16121 /* UITableView+ReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD705A93278D052B00F16121 /* UITableView+ReusableView.swift */; };
FD705A98278E9F4D00F16121 /* UIColor+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD705A97278E9F4D00F16121 /* UIColor+Extensions.swift */; };
FD88BAD927A7439C00BBC442 /* MessageRequestsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD88BAD827A7439C00BBC442 /* MessageRequestsCell.swift */; };
FD88BADB27A750F200BBC442 /* MessageRequestsMigration.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD88BADA27A750F200BBC442 /* MessageRequestsMigration.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -1811,15 +1812,16 @@
FCB11D8B1A129A76002F93FB /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; };
FD5D200E27AA2B6000FEA984 /* MessageRequestResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageRequestResponse.swift; sourceTree = "<group>"; };
FD5D201027AA331F00FEA984 /* ConfigurationMessage+Convenience.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ConfigurationMessage+Convenience.swift"; sourceTree = "<group>"; };
FD5D201D27B0D87C00FEA984 /* IdPrefix.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdPrefix.swift; sourceTree = "<group>"; };
FD659ABF27A7649600F12C02 /* MessageRequestsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageRequestsViewController.swift; sourceTree = "<group>"; };
FD88BAD827A7439C00BBC442 /* MessageRequestsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageRequestsCell.swift; sourceTree = "<group>"; };
FD88BADA27A750F200BBC442 /* MessageRequestsMigration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageRequestsMigration.swift; sourceTree = "<group>"; };
FD705A8B278CDB5600F16121 /* SAEScreenLockViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SAEScreenLockViewController.swift; sourceTree = "<group>"; };
FD705A8D278CE29800F16121 /* String+Localization.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Localization.swift"; sourceTree = "<group>"; };
FD705A8F278CEBBC00F16121 /* ShareAppExtensionContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareAppExtensionContext.swift; sourceTree = "<group>"; };
FD705A91278D051200F16121 /* ReusableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReusableView.swift; sourceTree = "<group>"; };
FD705A93278D052B00F16121 /* UITableView+ReusableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITableView+ReusableView.swift"; sourceTree = "<group>"; };
FD705A97278E9F4D00F16121 /* UIColor+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+Extensions.swift"; sourceTree = "<group>"; };
FD88BAD827A7439C00BBC442 /* MessageRequestsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageRequestsCell.swift; sourceTree = "<group>"; };
FD88BADA27A750F200BBC442 /* MessageRequestsMigration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageRequestsMigration.swift; sourceTree = "<group>"; };
FD9039443F7CB729CF71350E /* Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionNotificationServiceExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionNotificationServiceExtension.debug.xcconfig"; path = "Pods/Target Support Files/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionNotificationServiceExtension/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionNotificationServiceExtension.debug.xcconfig"; sourceTree = "<group>"; };
FEDBAE1B98C49BBE8C87F575 /* Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionUtilitiesKit.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionUtilitiesKit.debug.xcconfig"; path = "Pods/Target Support Files/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionUtilitiesKit/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionUtilitiesKit.debug.xcconfig"; sourceTree = "<group>"; };
FF9BA33D021B115B1F5B4E46 /* Pods-SessionMessagingKit.app store release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SessionMessagingKit.app store release.xcconfig"; path = "Pods/Target Support Files/Pods-SessionMessagingKit/Pods-SessionMessagingKit.app store release.xcconfig"; sourceTree = "<group>"; };
@ -2362,6 +2364,7 @@
C38EF23D255B6D66007E1867 /* UIView+OWS.h */,
C38EF23E255B6D66007E1867 /* UIView+OWS.m */,
C38EF2EF255B6DBB007E1867 /* Weak.swift */,
FD5D201D27B0D87C00FEA984 /* IdPrefix.swift */,
);
path = General;
sourceTree = "<group>";
@ -4669,6 +4672,7 @@
B8F5F58325EC94A6003BF8D4 /* Collection+Subscripting.swift in Sources */,
C33FDEF8255A656D00E217F9 /* Promise+Delaying.swift in Sources */,
B8BC00C0257D90E30032E807 /* General.swift in Sources */,
FD5D201E27B0D87C00FEA984 /* IdPrefix.swift in Sources */,
C32C5A24256DB7DB003C73A2 /* SNUserDefaults.swift in Sources */,
C3D9E41F25676C870040E4F3 /* OWSPrimaryStorageProtocol.swift in Sources */,
C3BBE0A72554D4DE0050F1E3 /* Promise+Retrying.swift in Sources */,

@ -177,7 +177,7 @@ public final class ClosedGroupControlMessage : ControlMessage {
let encryptionKeyPairAsProto = closedGroupControlMessageProto.encryptionKeyPair else { return nil }
let expirationTimer = closedGroupControlMessageProto.expirationTimer
do {
let encryptionKeyPair = try ECKeyPair(publicKeyData: encryptionKeyPairAsProto.publicKey.removing05PrefixIfNeeded(), privateKeyData: encryptionKeyPairAsProto.privateKey)
let encryptionKeyPair = try ECKeyPair(publicKeyData: encryptionKeyPairAsProto.publicKey.removingIdPrefixIfNeeded(), privateKeyData: encryptionKeyPairAsProto.privateKey)
kind = .new(publicKey: publicKey, name: name, encryptionKeyPair: encryptionKeyPair,
members: closedGroupControlMessageProto.members, admins: closedGroupControlMessageProto.admins, expirationTimer: expirationTimer)
} catch {

@ -325,7 +325,7 @@ public final class OpenGroupAPIV2 : NSObject {
return nil
}
// Validate the message signature
let publicKey = Data(hex: sender.removing05PrefixIfNeeded())
let publicKey = Data(hex: sender.removingIdPrefixIfNeeded())
let isValid = (try? Ed25519.verifySignature(signature, publicKey: publicKey, data: data)) ?? false
guard isValid else {
SNLog("Ignoring message with invalid signature.")

@ -6,7 +6,7 @@ extension MessageReceiver {
internal static func decryptWithSessionProtocol(ciphertext: Data, using x25519KeyPair: ECKeyPair) throws -> (plaintext: Data, senderX25519PublicKey: String) {
let recipientX25519PrivateKey = x25519KeyPair.privateKey
let recipientX25519PublicKey = Data(hex: x25519KeyPair.hexEncodedPublicKey.removing05PrefixIfNeeded())
let recipientX25519PublicKey = Data(hex: x25519KeyPair.hexEncodedPublicKey.removingIdPrefixIfNeeded())
let sodium = Sodium()
let signatureSize = sodium.sign.Bytes
let ed25519PublicKeySize = sodium.sign.PublicKeyBytes
@ -25,6 +25,6 @@ extension MessageReceiver {
// 4. ) Get the sender's X25519 public key
guard let senderX25519PublicKey = sodium.sign.toX25519(ed25519PublicKey: senderED25519PublicKey) else { throw Error.decryptionFailed }
return (Data(plaintext), "05" + senderX25519PublicKey.toHexString())
return (Data(plaintext), IdPrefix.standard.rawValue + senderX25519PublicKey.toHexString())
}
}

@ -550,7 +550,7 @@ extension MessageReceiver {
}
let keyPair: ECKeyPair
do {
keyPair = try ECKeyPair(publicKeyData: proto.publicKey.removing05PrefixIfNeeded(), privateKeyData: proto.privateKey)
keyPair = try ECKeyPair(publicKeyData: proto.publicKey.removingIdPrefixIfNeeded(), privateKeyData: proto.privateKey)
} catch {
return SNLog("Couldn't parse closed group encryption key pair.")
}

@ -8,7 +8,7 @@ extension MessageSender {
var members = members
let userPublicKey = getUserHexEncodedPublicKey()
// Generate the group's public key
let groupPublicKey = Curve25519.generateKeyPair().hexEncodedPublicKey // Includes the "05" prefix
let groupPublicKey = Curve25519.generateKeyPair().hexEncodedPublicKey // Includes the 'IdPrefix.standard' prefix
// Generate the key pair that'll be used for encryption and decryption
let encryptionKeyPair = Curve25519.generateKeyPair()
// Ensure the current user is included in the member list

@ -5,7 +5,7 @@ extension MessageSender {
internal static func encryptWithSessionProtocol(_ plaintext: Data, for recipientHexEncodedX25519PublicKey: String) throws -> Data {
guard let userED25519KeyPair = SNMessagingKitConfiguration.shared.storage.getUserED25519KeyPair() else { throw Error.noUserED25519KeyPair }
let recipientX25519PublicKey = Data(hex: recipientHexEncodedX25519PublicKey.removing05PrefixIfNeeded())
let recipientX25519PublicKey = Data(hex: recipientHexEncodedX25519PublicKey.removingIdPrefixIfNeeded())
let sodium = Sodium()
let verificationData = plaintext + Data(userED25519KeyPair.publicKey) + recipientX25519PublicKey

@ -377,7 +377,7 @@ public final class SnodeAPI : NSObject {
return Promise<Set<Snode>> { $0.fulfill(cachedSwarm) }
} else {
SNLog("Getting swarm for: \((publicKey == SNSnodeKitConfiguration.shared.storage.getUserPublicKey()) ? "self" : publicKey).")
let parameters: [String:Any] = [ "pubKey" : Features.useTestnet ? publicKey.removing05PrefixIfNeeded() : publicKey ]
let parameters: [String:Any] = [ "pubKey" : Features.useTestnet ? publicKey.removingIdPrefixIfNeeded() : publicKey ]
return getRandomSnode().then2 { snode in
attempt(maxRetryCount: 4, recoveringOn: Threading.workQueue) {
invoke(.getSwarm, on: snode, associatedWith: publicKey, parameters: parameters)
@ -430,7 +430,7 @@ public final class SnodeAPI : NSObject {
// let signature = sodium.sign.signature(message: Bytes(verificationData), secretKey: userED25519KeyPair.secretKey)!
// Make the request
let parameters: JSON = [
"pubKey" : Features.useTestnet ? publicKey.removing05PrefixIfNeeded() : publicKey,
"pubKey" : Features.useTestnet ? publicKey.removingIdPrefixIfNeeded() : publicKey,
"lastHash" : lastHash,
// "timestamp" : timestamp,
// "pubkey_ed25519" : ed25519PublicKey,
@ -441,7 +441,7 @@ public final class SnodeAPI : NSObject {
public static func sendMessage(_ message: SnodeMessage) -> Promise<Set<RawResponsePromise>> {
let (promise, seal) = Promise<Set<RawResponsePromise>>.pending()
let publicKey = Features.useTestnet ? message.recipient.removing05PrefixIfNeeded() : message.recipient
let publicKey = Features.useTestnet ? message.recipient.removingIdPrefixIfNeeded() : message.recipient
Threading.workQueue.async {
getTargetSnodes(for: publicKey).map2 { targetSnodes in
let parameters = message.toJSON()
@ -464,7 +464,7 @@ public final class SnodeAPI : NSObject {
let storage = SNSnodeKitConfiguration.shared.storage
guard let userX25519PublicKey = storage.getUserPublicKey(),
let userED25519KeyPair = storage.getUserED25519KeyPair() else { return Promise(error: Error.noKeyPair) }
let publicKey = Features.useTestnet ? publicKey.removing05PrefixIfNeeded() : publicKey
let publicKey = Features.useTestnet ? publicKey.removingIdPrefixIfNeeded() : publicKey
return attempt(maxRetryCount: maxRetryCount, recoveringOn: Threading.workQueue) {
getSwarm(for: publicKey).then2 { swarm -> Promise<[String:Bool]> in
let snode = swarm.randomElement()!

@ -44,7 +44,7 @@ public final class SnodeMessage : NSObject, NSCoding { // NSObject/NSCoding conf
// MARK: JSON Conversion
public func toJSON() -> JSON {
return [
"pubKey" : Features.useTestnet ? recipient.removing05PrefixIfNeeded() : recipient,
"pubKey" : Features.useTestnet ? recipient.removingIdPrefixIfNeeded() : recipient,
"data" : data.description,
"ttl" : String(ttl),
"timestamp" : String(timestamp),

@ -7,15 +7,15 @@ public extension ECKeyPair {
}
@objc var hexEncodedPublicKey: String {
// Prefixing with "05" is necessary for what seems to be a sort of Signal public key versioning system
return "05" + publicKey.map { String(format: "%02hhx", $0) }.joined()
// Prefixing with 'IdPrefix.standard' is necessary for what seems to be a sort of Signal public key versioning system
return IdPrefix.standard.rawValue + publicKey.map { String(format: "%02hhx", $0) }.joined()
}
@objc static func isValidHexEncodedPublicKey(candidate: String) -> Bool {
// Check that it's a valid hexadecimal encoding
guard Hex.isValid(candidate) else { return false }
// Check that it has length 66 and a leading "05"
guard candidate.count == 66 && candidate.hasPrefix("05") else { return false }
// Check that it has length 66 and a valid prefix
guard candidate.count == 66 && IdPrefix.allCases.first(where: { candidate.hasPrefix($0.rawValue) }) != nil else { return false }
// It appears to be a valid public key
return true
}

@ -1,18 +1,18 @@
public extension Data {
func removing05PrefixIfNeeded() -> Data {
func removingIdPrefixIfNeeded() -> Data {
var result = self
if result.count == 33 && result.toHexString().hasPrefix("05") { result.removeFirst() }
if result.count == 33 && IdPrefix(with: result.toHexString()) != nil { result.removeFirst() }
return result
}
}
@objc public extension NSData {
@objc func removing05PrefixIfNeeded() -> NSData {
@objc func removingIdPrefixIfNeeded() -> NSData {
var result = self as Data
if result.count == 33 && result.toHexString().hasPrefix("05") { result.removeFirst() }
if result.count == 33 && IdPrefix(with: result.toHexString()) != nil { result.removeFirst() }
return result as NSData
}
}

@ -0,0 +1,8 @@
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import Foundation
public enum IdPrefix: String, CaseIterable {
case standard = "05" // Used for identified users, open groups, etc.
case blinded = "15" // Used for participants in open groups
}

@ -1,18 +1,18 @@
public extension String {
func removing05PrefixIfNeeded() -> String {
func removingIdPrefixIfNeeded() -> String {
var result = self
if result.count == 66 && result.hasPrefix("05") { result.removeFirst(2) }
if result.count == 66 && IdPrefix(with: result) != nil { result.removeFirst(2) }
return result
}
}
@objc public extension NSString {
@objc func removing05PrefixIfNeeded() -> NSString {
@objc func removingIdPrefixIfNeeded() -> NSString {
var result = self as String
if result.count == 66 && result.hasPrefix("05") { result.removeFirst(2) }
if result.count == 66 && IdPrefix(with: result) != nil { result.removeFirst(2) }
return result as NSString
}
}

@ -5,7 +5,7 @@ public final class Identicon : NSObject {
@objc public static func generatePlaceholderIcon(seed: String, text: String, size: CGFloat) -> UIImage {
let icon = PlaceholderIcon(seed: seed)
var content = text
if content.count > 2 && content.hasPrefix("05") {
if content.count > 2 && IdPrefix(with: content) != nil {
content.removeFirst(2)
}
let layer = icon.generateLayer(with: size, text: content.substring(to: 1))

Loading…
Cancel
Save