import Foundation
import ThreemaProtocols
enum MetadataCoderError: Error {
case missingPrivateKey
}
public final class MetadataCoder: NSObject {
private let myIdentityStore: MyIdentityStoreProtocol
init(_ myIdentityStore: MyIdentityStoreProtocol) {
self.myIdentityStore = myIdentityStore
}
@objc override public convenience init() {
self.init(MyIdentityStore.shared())
}
@objc public func encode(metadata: MessageMetadata, nonce: Data, publicKey: Data) -> Data? {
var pbMetadata = CspE2e_MessageMetadata()
if let nickname = metadata.nickname {
pbMetadata.padding = Data(count: max(0, 16 - Data(nickname.utf8).count))
pbMetadata.nickname = nickname
}
if let messageID = metadata.messageID {
pbMetadata.messageID = messageID.paddedLittleEndian()
}
if let createdAt = metadata.createdAt {
pbMetadata.createdAt = UInt64(createdAt.timeIntervalSince1970 * 1000)
}
do {
let protobuf = try pbMetadata.serializedData()
return try NaClCrypto.shared()
.symmetricEncryptData(protobuf, withKey: deriveMetadataKey(publicKey: publicKey), nonce: nonce)
}
catch {
return nil
}
}
@objc public func decode(nonce: Data, box: Data, publicKey: Data) throws -> MessageMetadata {
let protobuf = try NaClCrypto.shared()
.symmetricDecryptData(box, withKey: deriveMetadataKey(publicKey: publicKey), nonce: nonce)
let pbMetadata = try CspE2e_MessageMetadata(serializedBytes: protobuf!)
var nickname: String?
var messageID: Data?
var createdAt: Date?
if !pbMetadata.nickname.isEmpty {
nickname = pbMetadata.nickname
}
if pbMetadata.messageID != 0 {
messageID = pbMetadata.messageID.littleEndianData
}
if pbMetadata.createdAt != 0 {
createdAt = Date(timeIntervalSince1970: Double(pbMetadata.createdAt) / 1000)
}
return MessageMetadata(nickname: nickname, messageID: messageID, createdAt: createdAt)
}
private func deriveMetadataKey(publicKey: Data) throws -> Data {
guard let sharedSecret = myIdentityStore.sharedSecret(withPublicKey: publicKey) else {
throw MetadataCoderError.missingPrivateKey
}
let kdf = ThreemaKDF(personal: "3ma-csp")
return kdf.deriveKey(salt: "mm", key: sharedSecret)!
}
}
¤ Dauer der Verarbeitung: 0.1 Sekunden
(vorverarbeitet am 2026-11-04)
¤
*© Formatika GbR, Deutschland