session-ios/SessionMessagingKit/Sending & Receiving/MessageSender+Encryption.swift

73 lines
3.4 KiB
Swift

// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import Foundation
import Sodium
import SessionUtilitiesKit
extension MessageSender {
internal static func encryptWithSessionProtocol(
_ plaintext: Data,
for recipientHexEncodedX25519PublicKey: String,
using dependencies: SMKDependencies = SMKDependencies()
) throws -> Data {
guard let userEd25519KeyPair: Box.KeyPair = dependencies.storage.read({ db in Identity.fetchUserEd25519KeyPair(db) }) else {
throw MessageSenderError.noUserED25519KeyPair
}
let recipientX25519PublicKey = Data(hex: recipientHexEncodedX25519PublicKey.removingIdPrefixIfNeeded())
let verificationData = plaintext + Data(userEd25519KeyPair.publicKey) + recipientX25519PublicKey
guard let signature = dependencies.sign.signature(message: Bytes(verificationData), secretKey: userEd25519KeyPair.secretKey) else {
throw MessageSenderError.signingFailed
}
let plaintextWithMetadata = plaintext + Data(userEd25519KeyPair.publicKey) + Data(signature)
guard let ciphertext = dependencies.box.seal(message: Bytes(plaintextWithMetadata), recipientPublicKey: Bytes(recipientX25519PublicKey)) else {
throw MessageSenderError.encryptionFailed
}
return Data(ciphertext)
}
internal static func encryptWithSessionBlindingProtocol(
_ plaintext: Data,
for recipientBlindedId: String,
openGroupPublicKey: String,
using dependencies: SMKDependencies = SMKDependencies()
) throws -> Data {
guard SessionId.Prefix(from: recipientBlindedId) == .blinded else { throw MessageSenderError.signingFailed }
guard let userEd25519KeyPair: Box.KeyPair = dependencies.storage.read({ db in Identity.fetchUserEd25519KeyPair(db) }) else {
throw MessageSenderError.noUserED25519KeyPair
}
guard let blindedKeyPair = dependencies.sodium.blindedKeyPair(serverPublicKey: openGroupPublicKey, edKeyPair: userEd25519KeyPair, genericHash: dependencies.genericHash) else {
throw MessageSenderError.signingFailed
}
let recipientBlindedPublicKey = Data(hex: recipientBlindedId.removingIdPrefixIfNeeded())
/// Step one: calculate the shared encryption key, sending from A to B
guard let enc_key: Bytes = dependencies.sodium.sharedBlindedEncryptionKey(
secretKey: userEd25519KeyPair.secretKey,
otherBlindedPublicKey: recipientBlindedPublicKey.bytes,
fromBlindedPublicKey: blindedKeyPair.publicKey,
toBlindedPublicKey: recipientBlindedPublicKey.bytes,
genericHash: dependencies.genericHash
) else {
throw MessageSenderError.signingFailed
}
/// Inner data: msg || A (i.e. the sender's ed25519 master pubkey, *not* kA blinded pubkey)
let innerBytes: Bytes = (plaintext.bytes + userEd25519KeyPair.publicKey)
/// Encrypt using xchacha20-poly1305
let nonce: Bytes = dependencies.nonceGenerator24.nonce()
guard let ciphertext = dependencies.aeadXChaCha20Poly1305Ietf.encrypt(message: innerBytes, secretKey: enc_key, nonce: nonce) else {
throw MessageSenderError.encryptionFailed
}
/// data = b'\x00' + ciphertext + nonce
return Data(Bytes(arrayLiteral: 0) + ciphertext + nonce)
}
}