Use AES-GCM & AES-CTR from LibSignalClient
This commit is contained in:
parent
db2678e86b
commit
a47425f008
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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] {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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? {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user