diff --git a/native/expo-modules/comm-expo-package/ios/AESCryptoModule.swift b/native/expo-modules/comm-expo-package/ios/AESCryptoModule.swift index e8ffa736f..731cc62ec 100644 --- a/native/expo-modules/comm-expo-package/ios/AESCryptoModule.swift +++ b/native/expo-modules/comm-expo-package/ios/AESCryptoModule.swift @@ -1,202 +1,202 @@ import ExpoModulesCore import CryptoKit private let KEY_SIZE = 32 // bytes private let IV_LENGTH = 12 // bytes, IV - unique Initialization Vector (nonce) private let TAG_LENGTH = 16 // bytes - GCM auth tag // Expo module called from the RN app JS code public class AESCryptoModule: Module { public func definition() -> ModuleDefinition { Name("AESCrypto") Function("generateKey") { (destination: Uint8Array) throws in - try! generateKey(destinationPtr: destination.rawBufferPtr(), + try generateKey(destinationPtr: destination.rawBufferPtr(), byteLength: destination.byteLength) } Function("encrypt") { (rawKey: Uint8Array, plaintext: Uint8Array, destination: Uint8Array) throws in - try! encrypt(rawKey: rawKey.data(), + try encrypt(rawKey: rawKey.data(), plaintext: plaintext.data(), plaintextLength: plaintext.byteLength, destinationPtr: destination.rawBufferPtr(), destinationLength: destination.byteLength) } Function("decrypt") { (rawKey: Uint8Array, sealedData: Uint8Array, destination: Uint8Array) throws in - try! decrypt(rawKey: rawKey.data(), + try decrypt(rawKey: rawKey.data(), sealedData: sealedData.data(), sealedDataLength: sealedData.byteLength, destinationPtr: destination.rawBufferPtr(), destinationLength: destination.byteLength) } } } // ObjC-compatible module, used from Objective-C code in NSE and from Rust @objc(AESCryptoModuleObjCCompat) public class AESCryptoModuleObjCCompat: NSObject { @objc(generateKey:withError:) public func generateKeyCompat(destination: NSMutableData) throws { let destinationPtr = UnsafeMutableRawBufferPointer(start: destination.mutableBytes, count: KEY_SIZE) - try! generateKey(destinationPtr: destinationPtr, + try generateKey(destinationPtr: destinationPtr, byteLength: destination.length) } @objc(generateKey:destinationLength:withError:) public static func generateKeyCompat(destinationPtr: UnsafeMutableRawPointer, destinationLength: Int) throws { let destinationBufferPtr = UnsafeMutableRawBufferPointer(start: destinationPtr, count: destinationLength) try generateKey(destinationPtr: destinationBufferPtr, byteLength: destinationLength) } @objc(encryptedLength:) public func encryptedLengthCompat(plaintext: Data) -> NSInteger { return plaintext.count + IV_LENGTH + TAG_LENGTH } @objc(encryptWithKey:plaintext:destination:withError:) public func encryptCompat(rawKey: Data, plaintext: Data, destination: NSMutableData) throws { let destinationPtr = UnsafeMutableRawBufferPointer(start: destination.mutableBytes, count: destination.length) - try! encrypt(rawKey: rawKey, + try encrypt(rawKey: rawKey, plaintext: plaintext, plaintextLength: plaintext.count, destinationPtr: destinationPtr, destinationLength: destination.length) } @objc(encryptWithKey:plaintext:destinationPtr:destinationLength:withError:) public static func encryptCompat(rawKey: Data, plaintext: Data, destinationPtr: UnsafeMutableRawPointer, destinationLength: Int) throws { let destinationBufferPtr = UnsafeMutableRawBufferPointer(start: destinationPtr, count: destinationLength) try encrypt(rawKey: rawKey, plaintext: plaintext, plaintextLength: plaintext.count, destinationPtr: destinationBufferPtr, destinationLength: destinationLength) } @objc(decryptedLength:) public func decryptedLengthCompat(sealedData: Data) -> NSInteger { return sealedData.count - IV_LENGTH - TAG_LENGTH } @objc(decryptWithKey:sealedData:destination:withError:) public func decryptCompat(rawKey: Data, sealedData: Data, destination: NSMutableData) throws { let destinationPtr = UnsafeMutableRawBufferPointer(start: destination.mutableBytes, count: destination.length) - try! decrypt(rawKey: rawKey, + try decrypt(rawKey: rawKey, sealedData: sealedData, sealedDataLength: sealedData.count, destinationPtr: destinationPtr, destinationLength: destination.length) } @objc(decryptWithKey:sealedData:destinationPtr:destinationLength:withError:) public static func decryptCompat(rawKey: Data, sealedData: Data, destinationPtr: UnsafeMutableRawPointer, destinationLength: Int) throws { let destinationBufferPtr = UnsafeMutableRawBufferPointer(start: destinationPtr, count: destinationLength) try decrypt(rawKey: rawKey, sealedData: sealedData, sealedDataLength: sealedData.count, destinationPtr: destinationBufferPtr, destinationLength: destinationLength) } } // MARK: - Function implementations private func generateKey(destinationPtr: UnsafeMutableRawBufferPointer, byteLength: Int) throws { guard byteLength == KEY_SIZE else { throw InvalidKeyLengthException() } let key = SymmetricKey(size: .bits256) key.withUnsafeBytes { bytes in let _ = bytes.copyBytes(to: destinationPtr) } } private func encrypt(rawKey: Data, plaintext: Data, plaintextLength: Int, destinationPtr: UnsafeMutableRawBufferPointer, destinationLength: Int) throws { guard destinationLength == plaintextLength + IV_LENGTH + TAG_LENGTH else { throw InvalidDataLengthException() } let key = SymmetricKey(data: rawKey) let iv = AES.GCM.Nonce() let encryptionResult = try AES.GCM.seal(plaintext, using: key, nonce: iv) // 'combined' returns concatenated: iv || ciphertext || tag guard let sealedData = encryptionResult.combined else { // this happens only if Nonce/IV != 12 bytes long throw EncryptionFailedException("Incorrect AES configuration") } guard sealedData.count == destinationLength else { throw EncryptionFailedException("Encrypted data has unexpected length") } sealedData.copyBytes(to: destinationPtr) } private func decrypt(rawKey: Data, sealedData: Data, sealedDataLength: Int, destinationPtr: UnsafeMutableRawBufferPointer, destinationLength: Int) throws { guard destinationLength == sealedDataLength - IV_LENGTH - TAG_LENGTH else { throw InvalidDataLengthException() } let key = SymmetricKey(data: rawKey) let sealedBox = try AES.GCM.SealedBox(combined: sealedData) let plaintext = try AES.GCM.open(sealedBox, using: key) plaintext.copyBytes(to: destinationPtr) } // MARK: - Exception definitions private class InvalidKeyLengthException: Exception { override var reason: String { "The AES key has invalid length" } } private class InvalidDataLengthException: Exception { override var reason: String { "Source or destination array has invalid length" } } private class EncryptionFailedException: GenericException { override var reason: String { "Failed to encrypt data: \(param)" } }