Handle ED25519 key pairs

authentication
Niels Andriesse 4 years ago
parent 88c002ca8e
commit eb0f83f91d

@ -40,6 +40,22 @@ extension Storage {
return "SNClosedGroupAuthenticationKeyPairCollection-\(groupPublicKey)"
}
public func getClosedGroupAuthenticationKeyPairs(for groupPublicKey: String) -> [Sign.KeyPair] {
let collection = Storage.getClosedGroupAuthenticationKeyPairCollection(for: groupPublicKey)
var timestampsAndKeyPairs: [(timestamp: Double, keyPair: Sign.KeyPair)] = []
Storage.read { transaction in
transaction.enumerateKeysAndObjects(inCollection: collection) { key, object, _ in
guard let timestamp = Double(key), let keyPair = object as? Sign.KeyPair else { return }
timestampsAndKeyPairs.append((timestamp, keyPair))
}
}
return timestampsAndKeyPairs.sorted { $0.timestamp < $1.timestamp }.map { $0.keyPair }
}
public func getLatestClosedGroupAuthenticationKeyPair(for groupPublicKey: String) -> Sign.KeyPair? {
return getClosedGroupAuthenticationKeyPairs(for: groupPublicKey).last
}
public func addClosedGroupAuthenticationKeyPair(_ keyPair: Sign.KeyPair, for groupPublicKey: String, timestamp: String, using transaction: Any) {
let collection = Storage.getClosedGroupAuthenticationKeyPairCollection(for: groupPublicKey)
(transaction as! YapDatabaseReadWriteTransaction).setObject(keyPair, forKey: timestamp, inCollection: collection)

@ -1,4 +1,5 @@
import SessionUtilitiesKit
import Sodium
public final class ClosedGroupControlMessage : ControlMessage {
public var kind: Kind?
@ -14,7 +15,7 @@ public final class ClosedGroupControlMessage : ControlMessage {
// MARK: Kind
public enum Kind : CustomStringConvertible {
case new(publicKey: Data, name: String, encryptionKeyPair: ECKeyPair, members: [Data], admins: [Data], expirationTimer: UInt32)
case new(publicKey: Data, name: String, x25519KeyPair: ECKeyPair, members: [Data], admins: [Data], expirationTimer: UInt32, ed25519KeyPair: Sign.KeyPair?)
/// The group x25519 and ed25519 encryption key pairs encrypted for each member individually.
///
/// - Note: `publicKey` is only set when an encryption key pair is sent in a one-to-one context (i.e. not in a group).
@ -94,7 +95,7 @@ public final class ClosedGroupControlMessage : ControlMessage {
public override var isValid: Bool {
guard super.isValid, let kind = kind else { return false }
switch kind {
case .new(let publicKey, let name, let encryptionKeyPair, let members, let admins, _):
case .new(let publicKey, let name, let encryptionKeyPair, let members, let admins, _, _):
return !publicKey.isEmpty && !name.isEmpty && !encryptionKeyPair.publicKey.isEmpty
&& !encryptionKeyPair.privateKey.isEmpty && !members.isEmpty && !admins.isEmpty
case .encryptionKeyPair: return true
@ -114,11 +115,12 @@ public final class ClosedGroupControlMessage : ControlMessage {
case "new":
guard let publicKey = coder.decodeObject(forKey: "publicKey") as? Data,
let name = coder.decodeObject(forKey: "name") as? String,
let encryptionKeyPair = coder.decodeObject(forKey: "encryptionKeyPair") as? ECKeyPair,
let x25519KeyPair = coder.decodeObject(forKey: "encryptionKeyPair") as? ECKeyPair,
let members = coder.decodeObject(forKey: "members") as? [Data],
let admins = coder.decodeObject(forKey: "admins") as? [Data] else { return nil }
let expirationTimer = coder.decodeObject(forKey: "expirationTimer") as? UInt32 ?? 0
self.kind = .new(publicKey: publicKey, name: name, encryptionKeyPair: encryptionKeyPair, members: members, admins: admins, expirationTimer: expirationTimer)
let ed25519KeyPair = coder.decodeObject(forKey: "ed25519KeyPair") as? Sign.KeyPair
self.kind = .new(publicKey: publicKey, name: name, x25519KeyPair: x25519KeyPair, members: members, admins: admins, expirationTimer: expirationTimer, ed25519KeyPair: ed25519KeyPair)
case "encryptionKeyPair":
let publicKey = coder.decodeObject(forKey: "publicKey") as? Data
guard let wrappers = coder.decodeObject(forKey: "wrappers") as? [KeyPairWrapper] else { return nil }
@ -144,7 +146,7 @@ public final class ClosedGroupControlMessage : ControlMessage {
super.encode(with: coder)
guard let kind = kind else { return }
switch kind {
case .new(let publicKey, let name, let encryptionKeyPair, let members, let admins, let expirationTimer):
case .new(let publicKey, let name, let encryptionKeyPair, let members, let admins, let expirationTimer, let ed25519KeyPair):
coder.encode("new", forKey: "kind")
coder.encode(publicKey, forKey: "publicKey")
coder.encode(name, forKey: "name")
@ -152,6 +154,7 @@ public final class ClosedGroupControlMessage : ControlMessage {
coder.encode(members, forKey: "members")
coder.encode(admins, forKey: "admins")
coder.encode(expirationTimer, forKey: "expirationTimer")
coder.encode(ed25519KeyPair, forKey: "ed25519KeyPair")
case .encryptionKeyPair(let publicKey, let wrappers):
coder.encode("encryptionKeyPair", forKey: "kind")
coder.encode(publicKey, forKey: "publicKey")
@ -179,12 +182,16 @@ public final class ClosedGroupControlMessage : ControlMessage {
switch closedGroupControlMessageProto.type {
case .new:
guard let publicKey = closedGroupControlMessageProto.publicKey, let name = closedGroupControlMessageProto.name,
let encryptionKeyPairAsProto = closedGroupControlMessageProto.x25519 else { return nil }
let x25519KeyPairAsProto = closedGroupControlMessageProto.x25519 else { return nil }
let expirationTimer = closedGroupControlMessageProto.expirationTimer
do {
let encryptionKeyPair = try ECKeyPair(publicKeyData: encryptionKeyPairAsProto.publicKey.removing05PrefixIfNeeded(), privateKeyData: encryptionKeyPairAsProto.privateKey)
kind = .new(publicKey: publicKey, name: name, encryptionKeyPair: encryptionKeyPair,
members: closedGroupControlMessageProto.members, admins: closedGroupControlMessageProto.admins, expirationTimer: expirationTimer)
let x25519KeyPair = try ECKeyPair(publicKeyData: x25519KeyPairAsProto.publicKey.removing05PrefixIfNeeded(), privateKeyData: x25519KeyPairAsProto.privateKey)
var ed25519KeyPair: Sign.KeyPair? = nil
if let ed25519 = closedGroupControlMessageProto.ed25519 {
ed25519KeyPair = Sign.KeyPair(publicKey: Bytes(ed25519.publicKey), secretKey: Bytes(ed25519.privateKey))
}
kind = .new(publicKey: publicKey, name: name, x25519KeyPair: x25519KeyPair,
members: closedGroupControlMessageProto.members, admins: closedGroupControlMessageProto.admins, expirationTimer: expirationTimer, ed25519KeyPair: ed25519KeyPair)
} catch {
SNLog("Couldn't parse key pair.")
return nil
@ -216,13 +223,17 @@ public final class ClosedGroupControlMessage : ControlMessage {
do {
let closedGroupControlMessage: SNProtoDataMessageClosedGroupControlMessage.SNProtoDataMessageClosedGroupControlMessageBuilder
switch kind {
case .new(let publicKey, let name, let encryptionKeyPair, let members, let admins, let expirationTimer):
case .new(let publicKey, let name, let x25519KeyPair, let members, let admins, let expirationTimer, let ed25519KeyPair):
closedGroupControlMessage = SNProtoDataMessageClosedGroupControlMessage.builder(type: .new)
closedGroupControlMessage.setPublicKey(publicKey)
closedGroupControlMessage.setName(name)
let encryptionKeyPairAsProto = SNProtoKeyPair.builder(publicKey: encryptionKeyPair.publicKey, privateKey: encryptionKeyPair.privateKey)
let x25519KeyPairAsProto = SNProtoKeyPair.builder(publicKey: x25519KeyPair.publicKey, privateKey: x25519KeyPair.privateKey)
do {
closedGroupControlMessage.setX25519(try encryptionKeyPairAsProto.build())
closedGroupControlMessage.setX25519(try x25519KeyPairAsProto.build())
if let ed25519KeyPair = ed25519KeyPair {
let ed25519KeyPairAsProto = try SNProtoKeyPair.builder(publicKey: Data(ed25519KeyPair.publicKey), privateKey: Data(ed25519KeyPair.secretKey)).build()
closedGroupControlMessage.setEd25519(ed25519KeyPairAsProto)
}
} catch {
SNLog("Couldn't construct closed group update proto from: \(self).")
return nil

@ -204,8 +204,8 @@ extension MessageReceiver {
let allClosedGroupPublicKeys = storage.getUserClosedGroupPublicKeys()
for closedGroup in message.closedGroups {
guard !allClosedGroupPublicKeys.contains(closedGroup.publicKey) else { continue }
handleNewClosedGroup(groupPublicKey: closedGroup.publicKey, name: closedGroup.name, encryptionKeyPair: closedGroup.encryptionKeyPair,
members: [String](closedGroup.members), admins: [String](closedGroup.admins), expirationTimer: closedGroup.expirationTimer,
handleNewClosedGroup(groupPublicKey: closedGroup.publicKey, name: closedGroup.name, x25519KeyPair: closedGroup.encryptionKeyPair,
members: [String](closedGroup.members), admins: [String](closedGroup.admins), expirationTimer: closedGroup.expirationTimer, ed25519KeyPair: nil,
messageSentTimestamp: message.sentTimestamp!, using: transaction)
}
// Open groups
@ -357,15 +357,15 @@ extension MessageReceiver {
}
private static func handleNewClosedGroup(_ message: ClosedGroupControlMessage, using transaction: Any) {
guard case let .new(publicKeyAsData, name, encryptionKeyPair, membersAsData, adminsAsData, expirationTimer) = message.kind else { return }
guard case let .new(publicKeyAsData, name, x25519KeyPair, membersAsData, adminsAsData, expirationTimer, ed25519KeyPair) = message.kind else { return }
let groupPublicKey = publicKeyAsData.toHexString()
let members = membersAsData.map { $0.toHexString() }
let admins = adminsAsData.map { $0.toHexString() }
handleNewClosedGroup(groupPublicKey: groupPublicKey, name: name, encryptionKeyPair: encryptionKeyPair,
members: members, admins: admins, expirationTimer: expirationTimer, messageSentTimestamp: message.sentTimestamp!, using: transaction)
handleNewClosedGroup(groupPublicKey: groupPublicKey, name: name, x25519KeyPair: x25519KeyPair,
members: members, admins: admins, expirationTimer: expirationTimer, ed25519KeyPair: ed25519KeyPair, messageSentTimestamp: message.sentTimestamp!, using: transaction)
}
private static func handleNewClosedGroup(groupPublicKey: String, name: String, encryptionKeyPair: ECKeyPair, members: [String], admins: [String], expirationTimer: UInt32, messageSentTimestamp: UInt64, using transaction: Any) {
private static func handleNewClosedGroup(groupPublicKey: String, name: String, x25519KeyPair: ECKeyPair, members: [String], admins: [String], expirationTimer: UInt32, ed25519KeyPair: Sign.KeyPair?, messageSentTimestamp: UInt64, using transaction: Any) {
let transaction = transaction as! YapDatabaseReadWriteTransaction
// Create the group
let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey)
@ -393,8 +393,11 @@ extension MessageReceiver {
configuration.save(with: transaction)
// Add the group to the user's set of public keys to poll for
Storage.shared.addClosedGroupPublicKey(groupPublicKey, using: transaction)
// Store the key pair
Storage.shared.addClosedGroupEncryptionKeyPair(encryptionKeyPair, for: groupPublicKey, using: transaction)
// Store the encryption and authentication key pairs
let timestamp = Storage.shared.addClosedGroupEncryptionKeyPair(x25519KeyPair, for: groupPublicKey, using: transaction)
if let ed25519KeyPair = ed25519KeyPair {
Storage.shared.addClosedGroupAuthenticationKeyPair(ed25519KeyPair, for: groupPublicKey, timestamp: timestamp, using: transaction)
}
// Store the formation timestamp
Storage.shared.setClosedGroupFormationTimestamp(to: messageSentTimestamp, for: groupPublicKey, using: transaction)
// Start polling

@ -1,7 +1,9 @@
import PromiseKit
import Sodium
extension MessageSender {
public static var distributingClosedGroupEncryptionKeyPairs: [String:[ECKeyPair]] = [:]
private static var distributingClosedGroupX25519KeyPairs: [String:[ECKeyPair]] = [:]
private static var distributingClosedGroupED25519KeyPairs: [String:[Sign.KeyPair]] = [:]
public static func createClosedGroup(name: String, members: Set<String>, transaction: YapDatabaseReadWriteTransaction) -> Promise<TSGroupThread> {
// Prepare
@ -9,8 +11,14 @@ extension MessageSender {
let userPublicKey = getUserHexEncodedPublicKey()
// Generate the group's public key
let groupPublicKey = Curve25519.generateKeyPair().hexEncodedPublicKey // Includes the "05" prefix
// Generate the key pair that'll be used for encryption and decryption
let encryptionKeyPair = Curve25519.generateKeyPair()
// Generate:
// The key pair that'll be used for encryption and decryption (the X25519 key pair)
// The key pair that'll be used for authenticated message retrieval (the ED25519 key pair)
let sodium = Sodium()
let ed25519KeyPair = sodium.sign.keyPair()!
let x25519PublicKey = sodium.sign.toX25519(ed25519PublicKey: ed25519KeyPair.publicKey)!
let x25519SecretKey = sodium.sign.toX25519(ed25519SecretKey: ed25519KeyPair.secretKey)!
let x25519KeyPair = try! ECKeyPair(publicKeyData: Data(x25519PublicKey), privateKeyData: Data(x25519SecretKey))
// Ensure the current user is included in the member list
members.insert(userPublicKey)
let membersAsData = members.map { Data(hex: $0) }
@ -27,7 +35,7 @@ extension MessageSender {
let thread = TSContactThread.getOrCreateThread(withContactSessionID: member, transaction: transaction)
thread.save(with: transaction)
let closedGroupControlMessageKind = ClosedGroupControlMessage.Kind.new(publicKey: Data(hex: groupPublicKey), name: name,
encryptionKeyPair: encryptionKeyPair, members: membersAsData, admins: adminsAsData, expirationTimer: 0)
x25519KeyPair: x25519KeyPair, members: membersAsData, admins: adminsAsData, expirationTimer: 0, ed25519KeyPair: ed25519KeyPair)
let closedGroupControlMessage = ClosedGroupControlMessage(kind: closedGroupControlMessageKind)
// Sending this non-durably is okay because we show a loader to the user. If they close the app while the
// loader is still showing, it's within expectation that the group creation might be incomplete.
@ -36,8 +44,9 @@ extension MessageSender {
}
// Add the group to the user's set of public keys to poll for
Storage.shared.addClosedGroupPublicKey(groupPublicKey, using: transaction)
// Store the key pair
Storage.shared.addClosedGroupEncryptionKeyPair(encryptionKeyPair, for: groupPublicKey, using: transaction)
// Store the encryption and authentication key pairs
let timestamp = Storage.shared.addClosedGroupEncryptionKeyPair(x25519KeyPair, for: groupPublicKey, using: transaction)
Storage.shared.addClosedGroupAuthenticationKeyPair(ed25519KeyPair, for: groupPublicKey, timestamp: timestamp, using: transaction)
// Notify the PN server
promises.append(PushNotificationAPI.performOperation(.subscribe, for: groupPublicKey, publicKey: userPublicKey))
// Notify the user
@ -67,30 +76,49 @@ extension MessageSender {
SNLog("Can't distribute new encryption key pair as a non-admin.")
return Promise(error: Error.invalidClosedGroupUpdate)
}
// Generate the new encryption key pair
let newKeyPair = Curve25519.generateKeyPair()
// Generate:
// The key pair that'll be used for encryption and decryption (the X25519 key pair)
// The key pair that'll be used for authenticated message retrieval (the ED25519 key pair)
let sodium = Sodium()
let ed25519KeyPair = sodium.sign.keyPair()!
let x25519PublicKey = sodium.sign.toX25519(ed25519PublicKey: ed25519KeyPair.publicKey)!
let x25519SecretKey = sodium.sign.toX25519(ed25519SecretKey: ed25519KeyPair.secretKey)!
let x25519KeyPair = try! ECKeyPair(publicKeyData: Data(x25519PublicKey), privateKeyData: Data(x25519SecretKey))
// Distribute it
let proto = try! SNProtoKeyPair.builder(publicKey: newKeyPair.publicKey,
privateKey: newKeyPair.privateKey).build()
let plaintext = try! proto.serializedData()
let x25519KeyPairAsProto = try! SNProtoKeyPair.builder(publicKey: x25519KeyPair.publicKey,
privateKey: x25519KeyPair.privateKey).build()
let serializedX25519KeyPairProto = try! x25519KeyPairAsProto.serializedData()
let ed25519KeyPairAsProto = try! SNProtoKeyPair.builder(publicKey: Data(ed25519KeyPair.publicKey),
privateKey: Data(ed25519KeyPair.secretKey)).build()
let serializedED25519KeyPairProto = try! ed25519KeyPairAsProto.serializedData()
let wrappers = targetMembers.compactMap { publicKey -> ClosedGroupControlMessage.KeyPairWrapper in
let encryptedX25519KeyPair = try! MessageSender.encryptWithSessionProtocol(plaintext, for: publicKey)
return ClosedGroupControlMessage.KeyPairWrapper(publicKey: publicKey, encryptedX25519KeyPair: encryptedX25519KeyPair, encryptedED25519KeyPair: nil)
let encryptedX25519KeyPair = try! MessageSender.encryptWithSessionProtocol(serializedX25519KeyPairProto, for: publicKey)
let encryptedED25519KeyPair = try! MessageSender.encryptWithSessionProtocol(serializedED25519KeyPairProto, for: publicKey)
return ClosedGroupControlMessage.KeyPairWrapper(publicKey: publicKey, encryptedX25519KeyPair: encryptedX25519KeyPair, encryptedED25519KeyPair: encryptedED25519KeyPair)
}
let closedGroupControlMessage = ClosedGroupControlMessage(kind: .encryptionKeyPair(publicKey: nil, wrappers: wrappers))
var distributingKeyPairs = distributingClosedGroupEncryptionKeyPairs[groupPublicKey] ?? []
distributingKeyPairs.append(newKeyPair)
distributingClosedGroupEncryptionKeyPairs[groupPublicKey] = distributingKeyPairs
var distributingX25519KeyPairs = distributingClosedGroupX25519KeyPairs[groupPublicKey] ?? []
distributingX25519KeyPairs.append(x25519KeyPair)
distributingClosedGroupX25519KeyPairs[groupPublicKey] = distributingX25519KeyPairs
var distributingED25519KeyPairs = distributingClosedGroupED25519KeyPairs[groupPublicKey] ?? []
distributingED25519KeyPairs.append(ed25519KeyPair)
distributingClosedGroupED25519KeyPairs[groupPublicKey] = distributingED25519KeyPairs
return MessageSender.sendNonDurably(closedGroupControlMessage, in: thread, using: transaction).done {
// Store it * after * having sent out the message to the group
// Store the new key pairs * after * having sent out the message to the group
SNMessagingKitConfiguration.shared.storage.write { transaction in
Storage.shared.addClosedGroupEncryptionKeyPair(newKeyPair, for: groupPublicKey, using: transaction)
let timestamp = Storage.shared.addClosedGroupEncryptionKeyPair(x25519KeyPair, for: groupPublicKey, using: transaction)
Storage.shared.addClosedGroupAuthenticationKeyPair(ed25519KeyPair, for: groupPublicKey, timestamp: timestamp, using: transaction)
}
var distributingKeyPairs = distributingClosedGroupEncryptionKeyPairs[groupPublicKey] ?? []
if let index = distributingKeyPairs.firstIndex(of: newKeyPair) {
distributingKeyPairs.remove(at: index)
var distributingX25519KeyPairs = distributingClosedGroupX25519KeyPairs[groupPublicKey] ?? []
if let index = distributingX25519KeyPairs.firstIndex(of: x25519KeyPair) {
distributingX25519KeyPairs.remove(at: index)
}
distributingClosedGroupEncryptionKeyPairs[groupPublicKey] = distributingKeyPairs
distributingClosedGroupX25519KeyPairs[groupPublicKey] = distributingX25519KeyPairs
var distributingED25519KeyPairs = distributingClosedGroupED25519KeyPairs[groupPublicKey] ?? []
if let index = distributingED25519KeyPairs.firstIndex(where: { $0.publicKey == ed25519KeyPair.publicKey }) {
distributingED25519KeyPairs.remove(at: index)
}
distributingClosedGroupED25519KeyPairs[groupPublicKey] = distributingED25519KeyPairs
}.map { _ in }
}
@ -164,10 +192,11 @@ extension MessageSender {
let membersAsData = members.map { Data(hex: $0) }
let adminsAsData = group.groupAdminIds.map { Data(hex: $0) }
let expirationTimer = thread.disappearingMessagesDuration(with: transaction)
guard let encryptionKeyPair = Storage.shared.getLatestClosedGroupEncryptionKeyPair(for: groupPublicKey) else {
guard let x25519KeyPair = Storage.shared.getLatestClosedGroupEncryptionKeyPair(for: groupPublicKey) else {
SNLog("Couldn't find encryption key pair for closed group: \(groupPublicKey).")
return Promise(error: Error.noKeyPair)
}
let ed25519KeyPair = Storage.shared.getLatestClosedGroupAuthenticationKeyPair(for: groupPublicKey)
// Send the update to the group
let closedGroupControlMessage = ClosedGroupControlMessage(kind: .membersAdded(members: newMembers.map { Data(hex: $0) }))
MessageSender.send(closedGroupControlMessage, in: thread, using: transaction)
@ -176,7 +205,7 @@ extension MessageSender {
let thread = TSContactThread.getOrCreateThread(withContactSessionID: member, transaction: transaction)
thread.save(with: transaction)
let closedGroupControlMessageKind = ClosedGroupControlMessage.Kind.new(publicKey: Data(hex: groupPublicKey), name: group.groupName!,
encryptionKeyPair: encryptionKeyPair, members: membersAsData, admins: adminsAsData, expirationTimer: expirationTimer)
x25519KeyPair: x25519KeyPair, members: membersAsData, admins: adminsAsData, expirationTimer: expirationTimer, ed25519KeyPair: ed25519KeyPair)
let closedGroupControlMessage = ClosedGroupControlMessage(kind: closedGroupControlMessageKind)
MessageSender.send(closedGroupControlMessage, in: thread, using: transaction)
}
@ -322,15 +351,24 @@ extension MessageSender {
return SNLog("Refusing to send latest encryption key pair to non-member.")
}
// Get the latest encryption key pair
guard let encryptionKeyPair = distributingClosedGroupEncryptionKeyPairs[groupPublicKey]?.last
guard let x25519KeyPair = distributingClosedGroupX25519KeyPairs[groupPublicKey]?.last
?? Storage.shared.getLatestClosedGroupEncryptionKeyPair(for: groupPublicKey) else { return }
let ed25519KeyPair = distributingClosedGroupED25519KeyPairs[groupPublicKey]?.last
?? Storage.shared.getLatestClosedGroupAuthenticationKeyPair(for: groupPublicKey)
// Send it
guard let proto = try? SNProtoKeyPair.builder(publicKey: encryptionKeyPair.publicKey,
privateKey: encryptionKeyPair.privateKey).build(), let plaintext = try? proto.serializedData() else { return }
guard let x25519KeyPairAsProto = try? SNProtoKeyPair.builder(publicKey: x25519KeyPair.publicKey,
privateKey: x25519KeyPair.privateKey).build(),
let serializedX25519KeyPairProto = try? x25519KeyPairAsProto.serializedData() else { return }
let contactThread = TSContactThread.getOrCreateThread(withContactSessionID: publicKey, transaction: transaction)
guard let ciphertext = try? MessageSender.encryptWithSessionProtocol(plaintext, for: publicKey) else { return }
SNLog("Sending latest encryption key pair to: \(publicKey).")
let wrapper = ClosedGroupControlMessage.KeyPairWrapper(publicKey: publicKey, encryptedX25519KeyPair: ciphertext, encryptedED25519KeyPair: nil)
guard let encryptedX25519KeyPair = try? MessageSender.encryptWithSessionProtocol(serializedX25519KeyPairProto, for: publicKey) else { return }
SNLog("Sending latest encryption and authentication key pairs to: \(publicKey).")
var encryptedED25519KeyPair: Data? = nil
if let ed25519KeyPair = ed25519KeyPair,
let ed25519KeyPairAsProto = try? SNProtoKeyPair.builder(publicKey: Data(ed25519KeyPair.publicKey), privateKey: Data(ed25519KeyPair.secretKey)).build(),
let serializedED25519KeyPairProto = try? ed25519KeyPairAsProto.serializedData() {
encryptedED25519KeyPair = try? MessageSender.encryptWithSessionProtocol(serializedED25519KeyPairProto, for: publicKey)
}
let wrapper = ClosedGroupControlMessage.KeyPairWrapper(publicKey: publicKey, encryptedX25519KeyPair: encryptedX25519KeyPair, encryptedED25519KeyPair: encryptedED25519KeyPair)
let closedGroupControlMessage = ClosedGroupControlMessage(kind: .encryptionKeyPair(publicKey: Data(hex: groupPublicKey), wrappers: [ wrapper ]))
MessageSender.send(closedGroupControlMessage, in: contactThread, using: transaction)
}

Loading…
Cancel
Save