mirror of https://github.com/oxen-io/session-ios
				
				
				
			
			You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
	
	
		
			68 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Swift
		
	
		
		
			
		
	
	
			68 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Swift
		
	
| 
											5 years ago
										 | import CryptoSwift | ||
|  | import Curve25519Kit | ||
|  | 
 | ||
| 
											5 years ago
										 | public enum AESGCM { | ||
|  |     public static let gcmTagSize: UInt = 16 | ||
|  |     public static let ivSize: UInt = 12 | ||
| 
											5 years ago
										 | 
 | ||
| 
											5 years ago
										 |     public struct EncryptionResult { public let ciphertext: Data, symmetricKey: Data, ephemeralPublicKey: Data } | ||
| 
											5 years ago
										 | 
 | ||
| 
											5 years ago
										 |     public enum Error : LocalizedError { | ||
| 
											5 years ago
										 |         case keyPairGenerationFailed | ||
|  |         case sharedSecretGenerationFailed | ||
|  | 
 | ||
|  |         public var errorDescription: String? { | ||
|  |             switch self { | ||
|  |             case .keyPairGenerationFailed: return "Couldn't generate a key pair." | ||
|  |             case .sharedSecretGenerationFailed: return "Couldn't generate a shared secret." | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     /// - Note: Sync. Don't call from the main thread. | ||
| 
											5 years ago
										 |     public static func decrypt(_ ivAndCiphertext: Data, with symmetricKey: Data) throws -> Data { | ||
| 
											5 years ago
										 |         if Thread.isMainThread { | ||
|  |             #if DEBUG | ||
|  |             preconditionFailure("It's illegal to call decrypt(_:usingAESGCMWithSymmetricKey:) from the main thread.") | ||
|  |             #endif | ||
|  |         } | ||
|  |         let iv = ivAndCiphertext[0..<Int(ivSize)] | ||
|  |         let ciphertext = ivAndCiphertext[Int(ivSize)...] | ||
|  |         let gcm = GCM(iv: iv.bytes, tagLength: Int(gcmTagSize), mode: .combined) | ||
|  |         let aes = try AES(key: symmetricKey.bytes, blockMode: gcm, padding: .noPadding) | ||
|  |         return Data(try aes.decrypt(ciphertext.bytes)) | ||
|  |     } | ||
|  | 
 | ||
|  |     /// - Note: Sync. Don't call from the main thread. | ||
| 
											5 years ago
										 |     public static func encrypt(_ plaintext: Data, with symmetricKey: Data) throws -> Data { | ||
| 
											5 years ago
										 |         if Thread.isMainThread { | ||
|  |             #if DEBUG | ||
|  |             preconditionFailure("It's illegal to call encrypt(_:usingAESGCMWithSymmetricKey:) from the main thread.") | ||
|  |             #endif | ||
|  |         } | ||
|  |         let iv = Data.getSecureRandomData(ofSize: ivSize)! | ||
|  |         let gcm = GCM(iv: iv.bytes, tagLength: Int(gcmTagSize), mode: .combined) | ||
|  |         let aes = try AES(key: symmetricKey.bytes, blockMode: gcm, padding: .noPadding) | ||
|  |         let ciphertext = try aes.encrypt(plaintext.bytes) | ||
|  |         return iv + Data(ciphertext) | ||
|  |     } | ||
|  | 
 | ||
|  |     /// - Note: Sync. Don't call from the main thread. | ||
| 
											5 years ago
										 |     public static func encrypt(_ plaintext: Data, for hexEncodedX25519PublicKey: String) throws -> EncryptionResult { | ||
| 
											5 years ago
										 |         if Thread.isMainThread { | ||
|  |             #if DEBUG | ||
|  |             preconditionFailure("It's illegal to call encrypt(_:forSnode:) from the main thread.") | ||
|  |             #endif | ||
|  |         } | ||
|  |         let x25519PublicKey = Data(hex: hexEncodedX25519PublicKey) | ||
| 
											5 years ago
										 |         let ephemeralKeyPair = Curve25519.generateKeyPair() | ||
|  |         guard let ephemeralSharedSecret = try? Curve25519.generateSharedSecret(fromPublicKey: x25519PublicKey, privateKey: ephemeralKeyPair.privateKey) else { | ||
| 
											5 years ago
										 |             throw Error.sharedSecretGenerationFailed | ||
|  |         } | ||
|  |         let salt = "LOKI" | ||
|  |         let symmetricKey = try HMAC(key: salt.bytes, variant: .sha256).authenticate(ephemeralSharedSecret.bytes) | ||
|  |         let ciphertext = try encrypt(plaintext, with: Data(symmetricKey)) | ||
| 
											5 years ago
										 |         return EncryptionResult(ciphertext: ciphertext, symmetricKey: Data(symmetricKey), ephemeralPublicKey: ephemeralKeyPair.publicKey) | ||
| 
											5 years ago
										 |     } | ||
|  | } |