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.
		
		
		
		
		
			
		
			
				
	
	
		
			253 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			Swift
		
	
			
		
		
	
	
			253 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			Swift
		
	
| // Copyright © 2023 Rangeproof Pty Ltd. All rights reserved.
 | |
| //
 | |
| // stringlint:disable
 | |
| 
 | |
| import Foundation
 | |
| import CryptoKit
 | |
| import GRDB
 | |
| import SessionUtil
 | |
| import SessionUtilitiesKit
 | |
| 
 | |
| public extension Crypto.Generator {
 | |
|     /// Constructs a "blinded" key pair (`ka, kA`) based on an open group server `publicKey` and an ed25519 `keyPair`
 | |
|     static func blinded15KeyPair(
 | |
|         serverPublicKey: String,
 | |
|         ed25519SecretKey: [UInt8]
 | |
|     ) -> Crypto.Generator<KeyPair> {
 | |
|         return Crypto.Generator(
 | |
|             id: "blinded15KeyPair",
 | |
|             args: [serverPublicKey, ed25519SecretKey]
 | |
|         ) {
 | |
|             var cEd25519SecretKey: [UInt8] = Array(ed25519SecretKey)
 | |
|             var cServerPublicKey: [UInt8] = Array(Data(hex: serverPublicKey))
 | |
|             var cBlindedPubkey: [UInt8] = [UInt8](repeating: 0, count: 32)
 | |
|             var cBlindedSeckey: [UInt8] = [UInt8](repeating: 0, count: 32)
 | |
|             
 | |
|             guard
 | |
|                 cEd25519SecretKey.count == 64,
 | |
|                 cServerPublicKey.count == 32,
 | |
|                 session_blind15_key_pair(
 | |
|                     &cEd25519SecretKey,
 | |
|                     &cServerPublicKey,
 | |
|                     &cBlindedPubkey,
 | |
|                     &cBlindedSeckey
 | |
|                 )
 | |
|             else { throw CryptoError.keyGenerationFailed }
 | |
|             
 | |
|             return KeyPair(publicKey: cBlindedPubkey, secretKey: cBlindedSeckey)
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /// Constructs a "blinded" key pair (`ka, kA`) based on an open group server `publicKey` and an ed25519 `keyPair`
 | |
|     static func blinded25KeyPair(
 | |
|         serverPublicKey: String,
 | |
|         ed25519SecretKey: [UInt8]
 | |
|     ) -> Crypto.Generator<KeyPair> {
 | |
|         return Crypto.Generator(
 | |
|             id: "blinded25KeyPair",
 | |
|             args: [serverPublicKey, ed25519SecretKey]
 | |
|         ) {
 | |
|             var cEd25519SecretKey: [UInt8] = Array(ed25519SecretKey)
 | |
|             var cServerPublicKey: [UInt8] = Array(Data(hex: serverPublicKey))
 | |
|             var cBlindedPubkey: [UInt8] = [UInt8](repeating: 0, count: 32)
 | |
|             var cBlindedSeckey: [UInt8] = [UInt8](repeating: 0, count: 32)
 | |
|             
 | |
|             guard
 | |
|                 cEd25519SecretKey.count == 64,
 | |
|                 cServerPublicKey.count == 32,
 | |
|                 session_blind25_key_pair(
 | |
|                     &cEd25519SecretKey,
 | |
|                     &cServerPublicKey,
 | |
|                     &cBlindedPubkey,
 | |
|                     &cBlindedSeckey
 | |
|                 )
 | |
|             else { throw CryptoError.keyGenerationFailed }
 | |
|             
 | |
|             return KeyPair(publicKey: cBlindedPubkey, secretKey: cBlindedSeckey)
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     static func signatureBlind15(
 | |
|         message: [UInt8],
 | |
|         serverPublicKey: String,
 | |
|         ed25519SecretKey: [UInt8]
 | |
|     ) -> Crypto.Generator<[UInt8]> {
 | |
|         return Crypto.Generator(
 | |
|             id: "signatureBlind15",
 | |
|             args: [message, serverPublicKey, ed25519SecretKey]
 | |
|         ) {
 | |
|             var cEd25519SecretKey: [UInt8] = ed25519SecretKey
 | |
|             var cServerPublicKey: [UInt8] = Array(Data(hex: serverPublicKey))
 | |
|             var cMessage: [UInt8] = message
 | |
|             var cSignature: [UInt8] = [UInt8](repeating: 0, count: 64)
 | |
| 
 | |
|             guard
 | |
|                 cEd25519SecretKey.count == 64,
 | |
|                 cServerPublicKey.count == 32,
 | |
|                 session_blind15_sign(
 | |
|                     &cEd25519SecretKey,
 | |
|                     &cServerPublicKey,
 | |
|                     &cMessage,
 | |
|                     cMessage.count,
 | |
|                     &cSignature
 | |
|                 )
 | |
|             else { throw CryptoError.signatureGenerationFailed }
 | |
| 
 | |
|             return cSignature
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     static func signatureBlind25(
 | |
|         message: [UInt8],
 | |
|         serverPublicKey: String,
 | |
|         ed25519SecretKey: [UInt8]
 | |
|     ) -> Crypto.Generator<[UInt8]> {
 | |
|         return Crypto.Generator(
 | |
|             id: "signatureBlind25",
 | |
|             args: [message, serverPublicKey, ed25519SecretKey]
 | |
|         ) {
 | |
|             var cEd25519SecretKey: [UInt8] = ed25519SecretKey
 | |
|             var cServerPublicKey: [UInt8] = Array(Data(hex: serverPublicKey))
 | |
|             var cMessage: [UInt8] = message
 | |
|             var cSignature: [UInt8] = [UInt8](repeating: 0, count: 64)
 | |
| 
 | |
|             guard
 | |
|                 cEd25519SecretKey.count == 64,
 | |
|                 cServerPublicKey.count == 32,
 | |
|                 session_blind25_sign(
 | |
|                     &cEd25519SecretKey,
 | |
|                     &cServerPublicKey,
 | |
|                     &cMessage,
 | |
|                     cMessage.count,
 | |
|                     &cSignature
 | |
|                 )
 | |
|             else { throw CryptoError.signatureGenerationFailed }
 | |
| 
 | |
|             return cSignature
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| public extension Crypto.Verification {
 | |
|     /// This method should be used to check if a users standard sessionId matches a blinded one
 | |
|     static func sessionId(
 | |
|         _ standardSessionId: String,
 | |
|         matchesBlindedId blindedSessionId: String,
 | |
|         serverPublicKey: String
 | |
|     ) -> Crypto.Verification {
 | |
|         return Crypto.Verification(
 | |
|             id: "sessionId",
 | |
|             args: [standardSessionId, blindedSessionId, serverPublicKey]
 | |
|         ) {
 | |
|             guard
 | |
|                 var cStandardSessionId: [CChar] = standardSessionId.cString(using: .utf8),
 | |
|                 var cBlindedSessionId: [CChar] = blindedSessionId.cString(using: .utf8),
 | |
|                 var cServerPublicKey: [CChar] = serverPublicKey.cString(using: .utf8)
 | |
|             else { return false }
 | |
|             
 | |
|             return session_id_matches_blinded_id(
 | |
|                 &cStandardSessionId,
 | |
|                 &cBlindedSessionId,
 | |
|                 &cServerPublicKey
 | |
|             )
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| // MARK: - Messages
 | |
| 
 | |
| public extension Crypto.Generator {
 | |
|     static func ciphertextWithSessionBlindingProtocol(
 | |
|         _ db: Database,
 | |
|         plaintext: Data,
 | |
|         recipientBlindedId: String,
 | |
|         serverPublicKey: String,
 | |
|         using dependencies: Dependencies
 | |
|     ) -> Crypto.Generator<Data> {
 | |
|         return Crypto.Generator(
 | |
|             id: "ciphertextWithSessionBlindingProtocol",
 | |
|             args: [plaintext, serverPublicKey]
 | |
|         ) {
 | |
|             let ed25519KeyPair: KeyPair = try Identity.fetchUserEd25519KeyPair(db) ?? {
 | |
|                 throw MessageSenderError.noUserED25519KeyPair
 | |
|             }()
 | |
| 
 | |
|             var cPlaintext: [UInt8] = Array(plaintext)
 | |
|             var cEd25519SecretKey: [UInt8] = ed25519KeyPair.secretKey
 | |
|             var cRecipientBlindedId: [UInt8] = Array(Data(hex: recipientBlindedId))
 | |
|             var cServerPublicKey: [UInt8] = Array(Data(hex: serverPublicKey))
 | |
|             var maybeCiphertext: UnsafeMutablePointer<UInt8>? = nil
 | |
|             var ciphertextLen: Int = 0
 | |
| 
 | |
|             guard
 | |
|                 cEd25519SecretKey.count == 64,
 | |
|                 cServerPublicKey.count == 32,
 | |
|                 session_encrypt_for_blinded_recipient(
 | |
|                     &cPlaintext,
 | |
|                     cPlaintext.count,
 | |
|                     &cEd25519SecretKey,
 | |
|                     &cServerPublicKey,
 | |
|                     &cRecipientBlindedId,
 | |
|                     &maybeCiphertext,
 | |
|                     &ciphertextLen
 | |
|                 ),
 | |
|                 ciphertextLen > 0,
 | |
|                 let ciphertext: Data = maybeCiphertext.map({ Data(bytes: $0, count: ciphertextLen) })
 | |
|             else { throw MessageSenderError.encryptionFailed }
 | |
| 
 | |
|             maybeCiphertext?.deallocate()
 | |
| 
 | |
|             return ciphertext
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     static func plaintextWithSessionBlindingProtocol(
 | |
|         _ db: Database,
 | |
|         ciphertext: Data,
 | |
|         senderId: String,
 | |
|         recipientId: String,
 | |
|         serverPublicKey: String,
 | |
|         using dependencies: Dependencies
 | |
|     ) -> Crypto.Generator<(plaintext: Data, senderSessionIdHex: String)> {
 | |
|         return Crypto.Generator(
 | |
|             id: "plaintextWithSessionBlindingProtocol",
 | |
|             args: [ciphertext, senderId, recipientId]
 | |
|         ) {
 | |
|             let ed25519KeyPair: KeyPair = try Identity.fetchUserEd25519KeyPair(db) ?? {
 | |
|                 throw MessageSenderError.noUserED25519KeyPair
 | |
|             }()
 | |
|             
 | |
|             var cCiphertext: [UInt8] = Array(ciphertext)
 | |
|             var cEd25519SecretKey: [UInt8] = ed25519KeyPair.secretKey
 | |
|             var cSenderId: [UInt8] = Array(Data(hex: senderId))
 | |
|             var cRecipientId: [UInt8] = Array(Data(hex: recipientId))
 | |
|             var cServerPublicKey: [UInt8] = Array(Data(hex: serverPublicKey))
 | |
|             var cSenderSessionId: [CChar] = [CChar](repeating: 0, count: 67)
 | |
|             var maybePlaintext: UnsafeMutablePointer<UInt8>? = nil
 | |
|             var plaintextLen: Int = 0
 | |
| 
 | |
|             guard
 | |
|                 cEd25519SecretKey.count == 64,
 | |
|                 cServerPublicKey.count == 32,
 | |
|                 session_decrypt_for_blinded_recipient(
 | |
|                     &cCiphertext,
 | |
|                     cCiphertext.count,
 | |
|                     &cEd25519SecretKey,
 | |
|                     &cServerPublicKey,
 | |
|                     &cSenderId,
 | |
|                     &cRecipientId,
 | |
|                     &cSenderSessionId,
 | |
|                     &maybePlaintext,
 | |
|                     &plaintextLen
 | |
|                 ),
 | |
|                 plaintextLen > 0,
 | |
|                 let plaintext: Data = maybePlaintext.map({ Data(bytes: $0, count: plaintextLen) })
 | |
|             else { throw MessageReceiverError.decryptionFailed }
 | |
| 
 | |
|             maybePlaintext?.deallocate()
 | |
| 
 | |
|             return (plaintext, String(cString: cSenderSessionId))
 | |
|         }
 | |
|     }
 | |
| }
 |