// // Copyright 2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only // import Foundation public import LibSignalClient @objc(ECKeyPair) public final class ECKeyPair: NSObject, NSSecureCoding { public let keyPair: IdentityKeyPair public var identityKeyPair: IdentityKeyPair { keyPair } init(_ keyPair: IdentityKeyPair) { self.keyPair = keyPair } /** * Build a keypair from existing key data. * If you need a *new* keypair, user `ECKeyPair.generateKeyPair` instead. */ convenience init(publicKeyData: Data, privateKeyData: Data) throws { let publicKey = try PublicKey(keyData: publicKeyData) let privateKey = try PrivateKey(privateKeyData) self.init(IdentityKeyPair(publicKey: publicKey, privateKey: privateKey)) } private static let TSECKeyPairPublicKey = "TSECKeyPairPublicKey" private static let TSECKeyPairPrivateKey = "TSECKeyPairPrivateKey" public convenience init?(coder: NSCoder) { var returnedLength = 0 let publicKeyBuffer = coder.decodeBytes(forKey: Self.TSECKeyPairPublicKey, returnedLength: &returnedLength) guard let publicKeyBuffer else { return nil } let publicKeyData = Data(bytes: publicKeyBuffer, count: returnedLength) returnedLength = 0 let privateKeyBuffer = coder.decodeBytes(forKey: Self.TSECKeyPairPrivateKey, returnedLength: &returnedLength) guard let privateKeyBuffer else { return nil } let privateKeyData = Data(bytes: privateKeyBuffer, count: returnedLength) do { try self.init(publicKeyData: publicKeyData, privateKeyData: privateKeyData) } catch { Logger.warn("\(error)") return nil } } public func encode(with coder: NSCoder) { self.identityKeyPair.publicKey.keyBytes.withUnsafeBytes { coder.encodeBytes($0.baseAddress, length: $0.count, forKey: Self.TSECKeyPairPublicKey) } self.identityKeyPair.privateKey.serialize().withUnsafeBytes { coder.encodeBytes($0.baseAddress, length: $0.count, forKey: Self.TSECKeyPairPrivateKey) } } public class var supportsSecureCoding: Bool { return true } public static func generateKeyPair() -> ECKeyPair { return ECKeyPair(IdentityKeyPair.generate()) } private func sign(_ data: Data) throws -> Data { return identityKeyPair.privateKey.generateSignature(message: data) } public var publicKey: Data { return identityKeyPair.publicKey.keyBytes } public var privateKey: Data { return identityKeyPair.privateKey.serialize() } } extension IdentityKeyPair { public var asECKeyPair: ECKeyPair { return .init(self) } }