Files
libsignal/swift/Sources/LibSignalClient/SealedSender.swift
Jordan Rose 0542686e70 Update artifact/package/module names across all three app languages
- Java: org.whispersystems:signal-client-java ->
    org.signal:libsignal-client
- Java: org.whispersystems:signal-client-android ->
    org.signal:libsignal-android
- Java: org.whispersystems:libsignal-server ->
    org.signal:libsignal-server
- Swift: SignalClient -> LibSignalClient
- NPM: @signalapp/signal-client -> @signalapp/libsignal-client
- Repository: github.com/signalapp/libsignal-client ->
    github.com/signalapp/libsignal
2022-03-23 10:49:09 -07:00

280 lines
12 KiB
Swift

//
// Copyright 2020-2022 Signal Messenger, LLC.
// SPDX-License-Identifier: AGPL-3.0-only
//
import SignalFfi
import Foundation
@inlinable
public func sealedSenderEncrypt<Bytes: ContiguousBytes>(message: Bytes,
for address: ProtocolAddress,
from senderCert: SenderCertificate,
sessionStore: SessionStore,
identityStore: IdentityKeyStore,
context: StoreContext) throws -> [UInt8] {
let ciphertextMessage = try signalEncrypt(message: message,
for: address,
sessionStore: sessionStore,
identityStore: identityStore,
context: context)
let usmc = try UnidentifiedSenderMessageContent(ciphertextMessage,
from: senderCert,
contentHint: .default,
groupId: [])
return try sealedSenderEncrypt(usmc, for: address, identityStore: identityStore, context: context)
}
public class UnidentifiedSenderMessageContent: NativeHandleOwner {
public struct ContentHint: RawRepresentable, Hashable {
public var rawValue: UInt32
public init(rawValue: UInt32) {
self.rawValue = rawValue
}
internal init(_ knownType: SignalContentHint) {
self.init(rawValue: UInt32(knownType.rawValue))
}
public static var `default`: Self {
return Self(SignalContentHint_Default)
}
public static var resendable: Self {
return Self(SignalContentHint_Resendable)
}
public static var implicit: Self {
return Self(SignalContentHint_Implicit)
}
}
public convenience init<Bytes: ContiguousBytes>(message sealedSenderMessage: Bytes,
identityStore: IdentityKeyStore,
context: StoreContext) throws {
var result: OpaquePointer?
try sealedSenderMessage.withUnsafeBorrowedBuffer { messageBuffer in
try context.withOpaquePointer { context in
try withIdentityKeyStore(identityStore) { ffiIdentityStore in
try checkError(
signal_sealed_session_cipher_decrypt_to_usmc(
&result,
messageBuffer,
ffiIdentityStore,
context))
}
}
}
self.init(owned: result!)
}
public convenience init<GroupIdBytes: ContiguousBytes>(_ message: CiphertextMessage,
from sender: SenderCertificate,
contentHint: ContentHint,
groupId: GroupIdBytes) throws {
var result: OpaquePointer?
try withNativeHandles(message, sender) { messageHandle, senderHandle in
try groupId.withUnsafeBorrowedBuffer { groupIdBuffer in
try checkError(
signal_unidentified_sender_message_content_new(&result,
messageHandle,
senderHandle,
contentHint.rawValue,
groupIdBuffer))
}
}
self.init(owned: result!)
}
internal override class func destroyNativeHandle(_ handle: OpaquePointer) -> SignalFfiErrorRef? {
return signal_unidentified_sender_message_content_destroy(handle)
}
public var senderCertificate: SenderCertificate {
return withNativeHandle { nativeHandle in
failOnError {
try invokeFnReturningNativeHandle {
signal_unidentified_sender_message_content_get_sender_cert($0, nativeHandle)
}
}
}
}
public var messageType: CiphertextMessage.MessageType {
let rawType = withNativeHandle { nativeHandle in
failOnError {
try invokeFnReturningInteger {
signal_unidentified_sender_message_content_get_msg_type($0, nativeHandle)
}
}
}
return .init(rawValue: rawType)
}
public var contents: [UInt8] {
return withNativeHandle { nativeHandle in
failOnError {
try invokeFnReturningArray {
signal_unidentified_sender_message_content_get_contents($0, $1, nativeHandle)
}
}
}
}
public var groupId: [UInt8]? {
return withNativeHandle { nativeHandle in
failOnError {
try invokeFnReturningOptionalArray {
signal_unidentified_sender_message_content_get_group_id($0, $1, nativeHandle)
}
}
}
}
public var contentHint: ContentHint {
let rawHint = withNativeHandle { nativeHandle in
failOnError {
try invokeFnReturningInteger {
signal_unidentified_sender_message_content_get_content_hint($0, nativeHandle)
}
}
}
return .init(rawValue: rawHint)
}
}
public func sealedSenderEncrypt(_ content: UnidentifiedSenderMessageContent,
for recipient: ProtocolAddress,
identityStore: IdentityKeyStore,
context: StoreContext) throws -> [UInt8] {
return try withNativeHandles(recipient, content) { recipientHandle, contentHandle in
try context.withOpaquePointer { context in
try withIdentityKeyStore(identityStore) { ffiIdentityStore in
try invokeFnReturningArray {
signal_sealed_session_cipher_encrypt($0, $1,
recipientHandle,
contentHandle,
ffiIdentityStore, context)
}
}
}
}
}
public func sealedSenderMultiRecipientEncrypt(_ content: UnidentifiedSenderMessageContent,
for recipients: [ProtocolAddress],
identityStore: IdentityKeyStore,
sessionStore: SessionStore,
context: StoreContext) throws -> [UInt8] {
let sessions = try sessionStore.loadExistingSessions(for: recipients, context: context)
// Use withExtendedLifetime instead of withNativeHandle for the arrays of wrapper objects,
// which aren't compatible with withNativeHandle's simple lexical scoping.
return try withExtendedLifetime((recipients, sessions)) {
let recipientHandles = recipients.map { $0.unsafeNativeHandle }
let sessionHandles = sessions.map { $0.unsafeNativeHandle }
return try content.withNativeHandle { contentHandle in
return try recipientHandles.withUnsafeBufferPointer { recipientHandles in
let recipientHandlesBuffer = SignalBorrowedSliceOfProtocolAddress(base: recipientHandles.baseAddress, length: UInt(recipientHandles.count))
return try sessionHandles.withUnsafeBufferPointer { sessionHandles in
let sessionHandlesBuffer = SignalBorrowedSliceOfSessionRecord(base: sessionHandles.baseAddress, length: UInt(sessionHandles.count))
return try context.withOpaquePointer { context in
try withIdentityKeyStore(identityStore) { ffiIdentityStore in
try invokeFnReturningArray {
signal_sealed_sender_multi_recipient_encrypt($0, $1,
recipientHandlesBuffer,
sessionHandlesBuffer,
contentHandle,
ffiIdentityStore, context)
}
}
}
}
}
}
}
}
// For testing only.
internal func sealedSenderMultiRecipientMessageForSingleRecipient(_ message: [UInt8]) throws -> [UInt8] {
return try message.withUnsafeBorrowedBuffer { message in
try invokeFnReturningArray {
signal_sealed_sender_multi_recipient_message_for_single_recipient($0, $1, message)
}
}
}
public struct SealedSenderAddress: Hashable {
public var e164: String?
public var uuidString: String
public var deviceId: UInt32
public init(e164: String?, uuidString: String, deviceId: UInt32) throws {
self.e164 = e164
self.uuidString = uuidString
self.deviceId = deviceId
}
}
public struct SealedSenderResult {
public var message: [UInt8]
public var sender: SealedSenderAddress
}
public func sealedSenderDecrypt<Bytes: ContiguousBytes>(message: Bytes,
from localAddress: SealedSenderAddress,
trustRoot: PublicKey,
timestamp: UInt64,
sessionStore: SessionStore,
identityStore: IdentityKeyStore,
preKeyStore: PreKeyStore,
signedPreKeyStore: SignedPreKeyStore,
context: StoreContext) throws -> SealedSenderResult {
var senderE164: UnsafePointer<CChar>?
var senderUUID: UnsafePointer<CChar>?
var senderDeviceId: UInt32 = 0
let plaintext = try trustRoot.withNativeHandle { trustRootHandle in
try message.withUnsafeBorrowedBuffer { messageBuffer in
try context.withOpaquePointer { context in
try withSessionStore(sessionStore) { ffiSessionStore in
try withIdentityKeyStore(identityStore) { ffiIdentityStore in
try withPreKeyStore(preKeyStore) { ffiPreKeyStore in
try withSignedPreKeyStore(signedPreKeyStore) { ffiSignedPreKeyStore in
try invokeFnReturningArray {
signal_sealed_session_cipher_decrypt(
$0,
$1,
&senderE164,
&senderUUID,
&senderDeviceId,
messageBuffer,
trustRootHandle,
timestamp,
localAddress.e164,
localAddress.uuidString,
localAddress.deviceId,
ffiSessionStore,
ffiIdentityStore,
ffiPreKeyStore,
ffiSignedPreKeyStore,
context)
}
}
}
}
}
}
}
}
defer {
signal_free_string(senderE164)
signal_free_string(senderUUID)
}
return SealedSenderResult(message: plaintext,
sender: try SealedSenderAddress(e164: senderE164.map(String.init(cString:)),
uuidString: String(cString: senderUUID!),
deviceId: senderDeviceId))
}