import Foundation import CryptoKit extension SymmetricKey { var data: Data { withUnsafeBytes { Data(Array($0)) } } var base64: String { data.base64EncodedString() } var displayString: String { data.hexEncoded.uppercased().split(by: 4).joined(separator: " ") } var codeString: String { " {" + withUnsafeBytes { return Data(Array($0)) }.map(String.init).joined(separator: ", ") + "}," } } extension SHA256.Digest { var hexEncoded: String { Data(map { $0 }).hexEncoded } } extension String { func split(by length: Int) -> [String] { var startIndex = self.startIndex var results = [Substring]() while startIndex < self.endIndex { let endIndex = self.index(startIndex, offsetBy: length, limitedBy: self.endIndex) ?? self.endIndex results.append(self[startIndex.. (ephemeralPublicKeyData: Data, ciphertext: Data, signature: Data) { let ephemeralKey = Curve25519.KeyAgreement.PrivateKey() let ephemeralPublicKey = ephemeralKey.publicKey.rawRepresentation let sharedSecret = try ephemeralKey.sharedSecretFromKeyAgreement(with: theirEncryptionKey) let symmetricKey = sharedSecret.hkdfDerivedSymmetricKey(using: SHA256.self, salt: protocolSalt, sharedInfo: ephemeralPublicKey + theirEncryptionKey.rawRepresentation + ourSigningKey.publicKey.rawRepresentation, outputByteCount: 32) let ciphertext = try ChaChaPoly.seal(data, using: symmetricKey).combined let signature = try ourSigningKey.signature(for: ciphertext + ephemeralPublicKey + theirEncryptionKey.rawRepresentation) return (ephemeralPublicKey, ciphertext, signature) }