Files
wt 7db327c588
iOS CI / Build and Test SwiftUI App (push) Canceled after 0s
Build Unsigned iOS and macOS Apps / Build Unsigned iOS IPA (push) Canceled after 0s
Build Unsigned iOS and macOS Apps / Build macOS ZIP (push) Canceled after 0s
added omemo2
2026-08-30 05:40:44 +07:00

143 lines
5.5 KiB
Swift

//
// SignalSessionCipher.swift
//
// TigaseSwift OMEMO
// Copyright (C) 2019 "Tigase, Inc." <office@tigase.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. Look for COPYING file in the top folder.
// If not, see https://www.gnu.org/licenses/.
//
import Foundation
import libsignal
open class SignalSessionCipher {
fileprivate var cipher: OpaquePointer;
fileprivate let context: SignalContext;
fileprivate let address: SignalAddress;
public init?(withAddress address: SignalAddress, andContext context: SignalContext) {
var cipher: OpaquePointer?;
self.address = address;
guard session_cipher_create(&cipher, context.storage.storeContext, self.address.address, context.globalContext) >= 0 && cipher != nil else {
return nil;
}
self.context = context;
self.cipher = cipher!;
}
deinit {
session_cipher_free(cipher);
}
public func encrypt(data: Data) -> Result<Key,SignalError> {
var message: OpaquePointer?;
let error = data.withUnsafeBytes({ (bytes) -> SignalError? in
return SignalError.from(code : session_cipher_encrypt(cipher, bytes.baseAddress!.assumingMemoryBound(to: UInt8.self), data.count, &message));
})
guard error == nil && message != nil else {
return .failure(error ?? .unknown);
}
let serialized = ciphertext_message_get_serialized(message);
let result = Data(bytes: signal_buffer_data(serialized), count: signal_buffer_len(serialized));
defer {
signal_type_unref(message);
}
return .success(Key(key: result, deviceId: address.deviceId, prekey: ciphertext_message_get_type(message) == CIPHERTEXT_PREKEY_TYPE));
}
public func decrypt(key: Key) -> Result<Data, SignalError> {
if key.prekey {
return decryptPreKeyMessage(key: key);
} else {
return decryptSignalMessage(key: key);
}
}
fileprivate func decryptPreKeyMessage(key: Key) -> Result<Data,SignalError> {
let result = key.key.withUnsafeBytes({ (bytes) -> Result<OpaquePointer, SignalError> in
var output: OpaquePointer?;
var preKeySignalMessage: OpaquePointer?;
var error = SignalError.from(code: pre_key_signal_message_deserialize(&preKeySignalMessage, bytes.baseAddress!.assumingMemoryBound(to: UInt8.self), key.key.count, self.context.globalContext));
guard error == nil && preKeySignalMessage != nil else {
return .failure(error ?? .unknown);
}
defer {
signal_type_unref(preKeySignalMessage);
}
error = SignalError.from(code: session_cipher_decrypt_pre_key_signal_message(cipher, preKeySignalMessage, nil, &output));
guard error == nil && output != nil else {
return .failure(error ?? .unknown);
}
return .success(output!);
})
switch result {
case .failure(let error):
return .failure(error);
case .success(let preKeySignalMessage):
defer {
signal_buffer_free(preKeySignalMessage);
}
return .success(Data(bytes: signal_buffer_data(preKeySignalMessage), count: signal_buffer_len(preKeySignalMessage)));
}
}
fileprivate func decryptSignalMessage(key: Key) -> Result<Data, SignalError> {
let result = key.key.withUnsafeBytes({ (bytes) -> Result<OpaquePointer,SignalError> in
var output: OpaquePointer?;
var signalMessage: OpaquePointer?;
var error = SignalError.from(code: signal_message_deserialize(&signalMessage, bytes.baseAddress!.assumingMemoryBound(to: UInt8.self), key.key.count, self.context.globalContext));
guard error == nil && signalMessage != nil else {
return .failure(error ?? .unknown);
}
defer {
signal_type_unref(signalMessage);
}
error = SignalError.from(code: session_cipher_decrypt_signal_message(cipher, signalMessage, nil, &output));
guard error == nil && output != nil else {
return .failure(error ?? .unknown);
}
return .success(output!);
});
switch result {
case .failure(let error):
return .failure(error);
case .success(let signalMessage):
defer {
signal_buffer_free(signalMessage);
}
return .success(Data(bytes: signal_buffer_data(signalMessage), count: signal_buffer_len(signalMessage)));
}
}
open class Key {
public let key: Data;
public let deviceId: Int32;
public let prekey: Bool;
public init(key: Data, deviceId: Int32, prekey: Bool) {
self.key = key;
self.deviceId = deviceId;
self.prekey = prekey;
}
}
}