From a47425f008c08730f620343cbe204cdedd552b7d Mon Sep 17 00:00:00 2001 From: Max Radermacher Date: Mon, 13 Feb 2023 11:29:41 -0800 Subject: [PATCH] Use AES-GCM & AES-CTR from LibSignalClient --- .../KeyBackupService/KeyBackupService.swift | 70 +++++-------------- .../SGXContactDiscoveryOperation.swift | 55 +++++++-------- .../src/Messages/UD/SMKUDAccessKey.swift | 27 +++---- .../RemoteAttestation.swift | 12 ++-- SignalServiceKit/src/Util/DeviceNames.swift | 40 ++++------- .../src/Util/OWSUserProfile.swift | 7 +- 6 files changed, 73 insertions(+), 138 deletions(-) diff --git a/SignalServiceKit/KeyBackupService/KeyBackupService.swift b/SignalServiceKit/KeyBackupService/KeyBackupService.swift index 9eecad85d9..2316672813 100644 --- a/SignalServiceKit/KeyBackupService/KeyBackupService.swift +++ b/SignalServiceKit/KeyBackupService/KeyBackupService.swift @@ -4,6 +4,7 @@ // import Foundation +import LibSignalClient import SignalArgon2 import SignalCoreKit @@ -495,39 +496,19 @@ public class KeyBackupService: KeyBackupServiceProtocol { } public func encrypt(keyType: KBS.DerivedKey, data: Data) throws -> Data { - guard let keyData = self.data(for: keyType), let key = OWSAES256Key(data: keyData) else { + guard let keyData = self.data(for: keyType) else { owsFailDebug("missing derived key \(keyType)") throw KBS.KBSError.assertion } - - guard let encryptedData = Cryptography.encryptAESGCMWithDataAndConcatenateResults( - plainTextData: data, - initializationVectorLength: kAESGCM256_DefaultIVLength, - key: key - ) else { - owsFailDebug("Failed to encrypt data") - throw KBS.KBSError.assertion - } - - return encryptedData + return try Aes256GcmEncryptedData.encrypt(data, key: keyData).concatenate() } public func decrypt(keyType: KBS.DerivedKey, encryptedData: Data) throws -> Data { - guard let keyData = self.data(for: keyType), let key = OWSAES256Key(data: keyData) else { + guard let keyData = self.data(for: keyType) else { owsFailDebug("missing derived key \(keyType)") throw KBS.KBSError.assertion } - - guard let data = Cryptography.decryptAESGCMConcatenatedData( - encryptedData: encryptedData, - initializationVectorLength: kAESGCM256_DefaultIVLength, - key: key - ) else { - Logger.error("failed to decrypt data") - throw KBS.KBSError.assertion - } - - return data + return try Aes256GcmEncryptedData(concatenated: encryptedData).decrypt(key: keyData) } public func deriveRegistrationLockToken() -> String? { @@ -942,21 +923,17 @@ public class KeyBackupService: KeyBackupServiceProtocol { requestOption.set(on: requestBuilder) let kbRequestData = try requestBuilder.buildSerializedData() - guard let encryptionResult = Cryptography.encryptAESGCM( - plainTextData: kbRequestData, - initializationVectorLength: kAESGCM256_DefaultIVLength, - additionalAuthenticatedData: remoteAttestation.requestId, - key: remoteAttestation.keys.clientKey - ) else { - owsFailDebug("Failed to encrypt request data") - throw KBS.KBSError.assertion - } + let encryptionResult = try Aes256GcmEncryptedData.encrypt( + kbRequestData, + key: remoteAttestation.keys.clientKey.keyData, + associatedData: remoteAttestation.requestId + ) let request = OWSRequestFactory.kbsEnclaveRequest( withRequestId: remoteAttestation.requestId, data: encryptionResult.ciphertext, - cryptIv: encryptionResult.initializationVector, - cryptMac: encryptionResult.authTag, + cryptIv: encryptionResult.nonce, + cryptMac: encryptionResult.authenticationTag, enclaveName: remoteAttestation.enclaveName, authUsername: remoteAttestation.auth.username, authPassword: remoteAttestation.auth.password, @@ -996,25 +973,14 @@ public class KeyBackupService: KeyBackupServiceProtocol { } let iv = try parser.requiredBase64EncodedData(key: "iv") - guard iv.count == 12 else { - owsFailDebug("iv is invalid") - throw KBS.KBSError.assertion - } - let mac = try parser.requiredBase64EncodedData(key: "mac") - guard mac.count == 16 else { - owsFailDebug("mac is invalid") - throw KBS.KBSError.assertion - } - guard let encryptionResult = Cryptography.decryptAESGCM( - withInitializationVector: iv, - ciphertext: data, - additionalAuthenticatedData: nil, - authTag: mac, - key: remoteAttestation.keys.serverKey - ) else { - owsFailDebug("failed to decrypt KBS response") + let encryptionResult: Data + do { + let encryptedData = Aes256GcmEncryptedData(nonce: iv, ciphertext: data, authenticationTag: mac) + encryptionResult = try encryptedData.decrypt(key: remoteAttestation.keys.serverKey.keyData) + } catch { + owsFailDebug("failed to decrypt KBS response \(error)") throw KBS.KBSError.assertion } diff --git a/SignalServiceKit/src/Contacts/Discovery/SGXContactDiscoveryOperation.swift b/SignalServiceKit/src/Contacts/Discovery/SGXContactDiscoveryOperation.swift index 7daba19504..f7395c8d4f 100644 --- a/SignalServiceKit/src/Contacts/Discovery/SGXContactDiscoveryOperation.swift +++ b/SignalServiceKit/src/Contacts/Discovery/SGXContactDiscoveryOperation.swift @@ -4,6 +4,7 @@ // import Foundation +import LibSignalClient struct CDSRegisteredContact: Hashable { let signalUuid: UUID @@ -70,14 +71,12 @@ class SGXContactDiscoveryOperation: ContactDiscoveryOperation { guard let responseAttestion = respondingEnclaveAttestation?.value else { throw ContactDiscoveryError.assertionError(description: "Invalid responding enclave for requestId: \(response.requestId)") } - guard let plaintext = Cryptography.decryptAESGCM( - withInitializationVector: response.iv, + + let plaintext = try Aes256GcmEncryptedData( + nonce: response.iv, ciphertext: response.data, - additionalAuthenticatedData: nil, - authTag: response.mac, - key: responseAttestion.keys.serverKey) else { - throw ContactDiscoveryError.assertionError(description: "decryption failed") - } + authenticationTag: response.mac + ).decrypt(key: responseAttestion.keys.serverKey.keyData) // 16 bytes per UUID let contactCount = UInt(e164sToLookup.count) @@ -123,38 +122,36 @@ class SGXContactDiscoveryOperation: ContactDiscoveryOperation { let queryData = Data.join([noncePlainTextData, addressPlainTextData]) let key = OWSAES256Key.generateRandom() - guard let encryptionResult = Cryptography.encryptAESGCM(plainTextData: queryData, - initializationVectorLength: kAESGCM256_DefaultIVLength, - additionalAuthenticatedData: nil, - key: key) else { - throw ContactDiscoveryError.assertionError(description: "Encryption failure") - } + let encryptionResult = try Aes256GcmEncryptedData.encrypt(queryData, key: key.keyData) assert(encryptionResult.ciphertext.count == e164sToLookup.count * 8 + 32) let queryEnvelopes: [RemoteAttestation.CDSAttestation.Id: ContactDiscoveryService.IntersectionQuery.EnclaveEnvelope] = try remoteAttestations.mapValues { remoteAttestation in - guard let perEnclaveKey = Cryptography.encryptAESGCM(plainTextData: key.keyData, - initializationVectorLength: kAESGCM256_DefaultIVLength, - additionalAuthenticatedData: remoteAttestation.requestId, - key: remoteAttestation.keys.clientKey) else { - throw ContactDiscoveryError.assertionError(description: "failed to encrypt perEnclaveKey") - } + let perEnclaveKey = try Aes256GcmEncryptedData.encrypt( + key.keyData, + key: remoteAttestation.keys.clientKey.keyData, + associatedData: remoteAttestation.requestId + ) - return ContactDiscoveryService.IntersectionQuery.EnclaveEnvelope(requestId: remoteAttestation.requestId, - data: perEnclaveKey.ciphertext, - iv: perEnclaveKey.initializationVector, - mac: perEnclaveKey.authTag) + return ContactDiscoveryService.IntersectionQuery.EnclaveEnvelope( + requestId: remoteAttestation.requestId, + data: perEnclaveKey.ciphertext, + iv: perEnclaveKey.nonce, + mac: perEnclaveKey.authenticationTag + ) } guard let commitment = Cryptography.computeSHA256Digest(queryData) else { throw ContactDiscoveryError.assertionError(description: "commitment was unexpectedly nil") } - return ContactDiscoveryService.IntersectionQuery(addressCount: UInt(e164sToLookup.count), - commitment: commitment, - data: encryptionResult.ciphertext, - iv: encryptionResult.initializationVector, - mac: encryptionResult.authTag, - envelopes: queryEnvelopes) + return ContactDiscoveryService.IntersectionQuery( + addressCount: UInt(e164sToLookup.count), + commitment: commitment, + data: encryptionResult.ciphertext, + iv: encryptionResult.nonce, + mac: encryptionResult.authenticationTag, + envelopes: queryEnvelopes + ) } class func uuidArray(from data: Data) -> [UUID] { diff --git a/SignalServiceKit/src/Messages/UD/SMKUDAccessKey.swift b/SignalServiceKit/src/Messages/UD/SMKUDAccessKey.swift index 1da05f4d57..611c9484e4 100644 --- a/SignalServiceKit/src/Messages/UD/SMKUDAccessKey.swift +++ b/SignalServiceKit/src/Messages/UD/SMKUDAccessKey.swift @@ -4,6 +4,7 @@ // import Foundation +import LibSignalClient import SignalCoreKit @objc @@ -17,25 +18,15 @@ public class SMKUDAccessKey: NSObject { @objc public init(profileKey: Data) throws { - guard let aesGcmKey = OWSAES256Key(data: profileKey) else { - throw SMKError.assertionError(description: "Profile key is not valid AES GCM key.") - } - + let cipher = try Aes256GcmEncryption( + key: profileKey, + nonce: Data(count: Aes256GcmEncryptedData.nonceLength), + associatedData: [] + ) // We derive the "ud access key" from the private key by encrypting zeroes. - let emptyPlaintextLength = 16 - let emptyPlaintext = Data(count: Int(emptyPlaintextLength)) - let initializationVector = Data(count: Int(kAESGCM256_DefaultIVLength)) - guard let keyData = Cryptography.encryptAESGCM(plainTextData: emptyPlaintext, - initializationVector: initializationVector, - additionalAuthenticatedData: nil, - key: aesGcmKey) else { - throw SMKError.assertionError(description: "Could not derive UD access key from profile key.") - } - guard keyData.ciphertext.count == SMKUDAccessKey.kUDAccessKeyLength else { - throw SMKError.assertionError(description: "\(SMKUDAccessKey.logTag()) key has invalid length") - } - - self.keyData = keyData.ciphertext + var message = Data(count: Self.kUDAccessKeyLength) + try cipher.encrypt(&message) + self.keyData = message } @objc diff --git a/SignalServiceKit/src/Remote Attestation/RemoteAttestation.swift b/SignalServiceKit/src/Remote Attestation/RemoteAttestation.swift index a2f3a95e79..60fe8a3c3c 100644 --- a/SignalServiceKit/src/Remote Attestation/RemoteAttestation.swift +++ b/SignalServiceKit/src/Remote Attestation/RemoteAttestation.swift @@ -398,13 +398,11 @@ fileprivate extension RemoteAttestation { let quote = try RemoteAttestationQuote.parseQuote(from: quoteData) - guard let requestId = Cryptography.decryptAESGCM(withInitializationVector: encryptedRequestIv, - ciphertext: encryptedRequestId, - additionalAuthenticatedData: nil, - authTag: encryptedRequestTag, - key: keys.serverKey) else { - throw attestationError(reason: "failed to decrypt requestId") - } + let requestId = try Aes256GcmEncryptedData( + nonce: encryptedRequestIv, + ciphertext: encryptedRequestId, + authenticationTag: encryptedRequestTag + ).decrypt(key: keys.serverKey.keyData) try verifyServerQuote(quote, keys: keys, mrenclave: mrenclave) diff --git a/SignalServiceKit/src/Util/DeviceNames.swift b/SignalServiceKit/src/Util/DeviceNames.swift index 7c600a98c9..e99adb8132 100644 --- a/SignalServiceKit/src/Util/DeviceNames.swift +++ b/SignalServiceKit/src/Util/DeviceNames.swift @@ -3,8 +3,9 @@ // SPDX-License-Identifier: AGPL-3.0-only // -import Foundation import Curve25519Kit +import Foundation +import LibSignalClient public enum DeviceNameError: Error { case assertionFailure @@ -48,22 +49,15 @@ public class DeviceNames: NSObject { let cipherKey = try computeCipherKey(masterSecret: masterSecret, syntheticIV: syntheticIV) // cipher_text = AES-CTR(key=cipher_key, input=plaintext, counter=0) - // + var ciphertext = plaintextData // An all-zeros IV corresponds to an AES CTR counter of zero. - let ciphertextIV = Data(count: Int(kAES256CTR_IVLength)) - guard let ciphertextKey = OWSAES256Key(data: cipherKey) else { - owsFailDebug("Invalid cipher key.") - throw DeviceNameError.assertionFailure - } - guard let ciphertext: AES256CTREncryptionResult = Cryptography.encryptAESCTR(plaintextData: plaintextData, initializationVector: ciphertextIV, key: ciphertextKey) else { - owsFailDebug("Could not encrypt cipher text.") - throw DeviceNameError.assertionFailure - } + try Aes256Ctr32.process(&ciphertext, key: cipherKey, nonce: Data(count: Aes256Ctr32.nonceLength)) - let keyData = (ephemeralKeyPair.publicKey as NSData).prependKeyType() - let protoBuilder = SignalIOSProtoDeviceName.builder(ephemeralPublic: keyData as Data, - syntheticIv: syntheticIV, - ciphertext: ciphertext.ciphertext) + let protoBuilder = SignalIOSProtoDeviceName.builder( + ephemeralPublic: ephemeralKeyPair.publicKey.prependKeyType(), + syntheticIv: syntheticIV, + ciphertext: ciphertext + ) return try protoBuilder.buildSerializedData() } @@ -135,16 +129,12 @@ public class DeviceNames: NSObject { let ephemeralPublic: Data do { - ephemeralPublic = try (ephemeralPublicData as NSData).removeKeyType() as Data + ephemeralPublic = try ephemeralPublicData.removeKeyType() } catch { owsFailDebug("failed to remove key type") throw DeviceNameError.invalidInput } - guard ephemeralPublic.count > 0 else { - owsFailDebug("Invalid ephemeral public.") - throw DeviceNameError.assertionFailure - } guard receivedSyntheticIV.count == syntheticIVLength else { owsFailDebug("Invalid synthetic IV.") throw DeviceNameError.assertionFailure @@ -168,15 +158,9 @@ public class DeviceNames: NSObject { let cipherKey = try computeCipherKey(masterSecret: masterSecret, syntheticIV: receivedSyntheticIV) // plaintext = AES-CTR(key=cipher_key, input=ciphertext, counter=0) - // + var plaintextData = ciphertext // An all-zeros IV corresponds to an AES CTR counter of zero. - let ciphertextIV = Data(count: Int(kAES256CTR_IVLength)) - guard let ciphertextKey = OWSAES256Key(data: cipherKey) else { - throw DeviceNameError.cryptError("Invalid cipher key.") - } - guard let plaintextData = Cryptography.decryptAESCTR(cipherText: ciphertext, initializationVector: ciphertextIV, key: ciphertextKey) else { - throw DeviceNameError.cryptError("Could not decrypt cipher text.") - } + try Aes256Ctr32.process(&plaintextData, key: cipherKey, nonce: Data(count: Aes256Ctr32.nonceLength)) // Verify the synthetic IV was correct. // constant_time_compare(HmacSHA256(key=HmacSHA256(key=master_secret, input=”auth”), input=plaintext)[0:16], synthetic_iv) == true diff --git a/SignalServiceKit/src/Util/OWSUserProfile.swift b/SignalServiceKit/src/Util/OWSUserProfile.swift index be03f88e1b..e2e0e35c8f 100644 --- a/SignalServiceKit/src/Util/OWSUserProfile.swift +++ b/SignalServiceKit/src/Util/OWSUserProfile.swift @@ -4,6 +4,7 @@ // import Foundation +import LibSignalClient import Mantle @objc @@ -143,13 +144,11 @@ public extension OWSUserProfile { // MARK: - Encryption class func encrypt(profileData: Data, profileKey: OWSAES256Key) -> Data? { - assert(profileKey.keyData.count == kAES256_KeyByteLength) - return Cryptography.encryptAESGCMProfileData(plainTextData: profileData, key: profileKey) + return try? Aes256GcmEncryptedData.encrypt(profileData, key: profileKey.keyData).concatenate() } class func decrypt(profileData: Data, profileKey: OWSAES256Key) -> Data? { - assert(profileKey.keyData.count == kAES256_KeyByteLength) - return Cryptography.decryptAESGCMProfileData(encryptedData: profileData, key: profileKey) + return try? Aes256GcmEncryptedData(concatenated: profileData).decrypt(key: profileKey.keyData) } class func decrypt(profileNameData: Data, profileKey: OWSAES256Key, address: SignalServiceAddress) -> PersonNameComponents? {