Re-add missing Signal protocol bits
This commit is contained in:
parent
8f443a38af
commit
82b12901b9
|
@ -4,9 +4,54 @@ import SessionUtilities
|
|||
internal extension MessageSender {
|
||||
|
||||
static func encryptWithSignalProtocol(_ plaintext: Data, for publicKey: String, using transaction: Any) throws -> Data {
|
||||
return Data()
|
||||
|
||||
}
|
||||
|
||||
// NSError *error;
|
||||
// LKSessionResetImplementation *sessionResetImplementation = [LKSessionResetImplementation new];
|
||||
//
|
||||
// SMKSecretSessionCipher *_Nullable secretCipher =
|
||||
// [[SMKSecretSessionCipher alloc] initWithSessionResetImplementation:sessionResetImplementation
|
||||
// sessionStore:self.primaryStorage
|
||||
// preKeyStore:self.primaryStorage
|
||||
// signedPreKeyStore:self.primaryStorage
|
||||
// identityStore:self.identityManager
|
||||
// error:&error];
|
||||
// if (error || !secretCipher) {
|
||||
// OWSRaiseException(@"SecretSessionCipherFailure", @"Can't create secret session cipher.");
|
||||
// }
|
||||
//
|
||||
// // Loki: The way this works is:
|
||||
// // • Alice sends a session request (i.e. a pre key bundle) to Bob using fallback encryption.
|
||||
// // • She may send any number of subsequent messages also encrypted using fallback encryption.
|
||||
// // • When Bob receives the session request, he sets up his Signal cipher session locally and sends back a null message,
|
||||
// // now encrypted using Signal encryption.
|
||||
// // • Alice receives this, sets up her Signal cipher session locally, and sends any subsequent messages
|
||||
// // using Signal encryption.
|
||||
//
|
||||
// BOOL shouldUseFallbackEncryption = [LKSessionManagementProtocol shouldUseFallbackEncryptionForMessage:message recipientID:recipientID transaction:transaction];
|
||||
//
|
||||
// if (shouldUseFallbackEncryption) {
|
||||
// [LKLogger print:@"[Loki] Using fallback encryption"];
|
||||
// } else {
|
||||
// [LKLogger print:@"[Loki] Using Signal Encryption"];
|
||||
// }
|
||||
//
|
||||
// serializedMessage = [secretCipher throwswrapped_encryptMessageWithRecipientPublicKey:recipientID
|
||||
// deviceID:@(OWSDevicePrimaryDeviceId).intValue
|
||||
// paddedPlaintext:plainText.paddedMessageBody
|
||||
// senderCertificate:messageSend.senderCertificate
|
||||
// protocolContext:transaction
|
||||
// useFallbackSessionCipher:shouldUseFallbackEncryption
|
||||
// error:&error];
|
||||
//
|
||||
// SCKRaiseIfExceptionWrapperError(error);
|
||||
// if (serializedMessage == nil || error != nil) {
|
||||
// OWSFailDebug(@"Error while UD encrypting message: %@.", error);
|
||||
// return nil;
|
||||
// }
|
||||
// messageType = TSUnidentifiedSenderMessageType;
|
||||
|
||||
static func encryptWithSharedSenderKeys(_ plaintext: Data, for groupPublicKey: String, using transaction: Any) throws -> Data {
|
||||
// 1. ) Encrypt the data with the user's sender key
|
||||
guard let userPublicKey = Configuration.shared.storage.getUserPublicKey() else {
|
||||
|
|
|
@ -5,8 +5,12 @@ FOUNDATION_EXPORT const unsigned char SessionProtocolKitVersionString[];
|
|||
|
||||
#import <SessionProtocolKit/AxolotlStore.h>
|
||||
#import <SessionProtocolKit/ClosedGroupCiphertextMessage.h>
|
||||
#import <SessionProtocolKit/Cryptography.h>
|
||||
#import <SessionProtocolKit/FallbackMessage.h>
|
||||
#import <SessionProtocolKit/NSData+OWS.h>
|
||||
#import <SessionProtocolKit/NSObject+OWS.h>
|
||||
#import <SessionProtocolKit/NSString+OWS.h>
|
||||
#import <SessionProtocolKit/OWSLogs.h>
|
||||
#import <SessionProtocolKit/PreKeyBundle.h>
|
||||
#import <SessionProtocolKit/SerializationUtilities.h>
|
||||
#import <SessionProtocolKit/SessionCipher.h>
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
// See:
|
||||
// https://github.com/signalapp/libsignal-protocol-java/blob/87fae0f98332e98a32bbb82515428b4edeb4181f/java/src/main/java/org/whispersystems/libsignal/ecc/ECPrivateKey.java
|
||||
@objc public class ECPrivateKey: NSObject {
|
||||
|
||||
@objc
|
||||
public let keyData: Data
|
||||
|
||||
@objc
|
||||
public init(keyData: Data) throws {
|
||||
guard keyData.count == ECCKeyLength else {
|
||||
throw SMKError.assertionError(description: "\(ECPrivateKey.logTag) key has invalid length")
|
||||
}
|
||||
|
||||
self.keyData = keyData
|
||||
}
|
||||
|
||||
open override func isEqual(_ object: Any?) -> Bool {
|
||||
if let object = object as? ECPrivateKey {
|
||||
return keyData == object.keyData
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
public override var hash: Int {
|
||||
return keyData.hashValue
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
// See:
|
||||
// https://github.com/signalapp/libsignal-protocol-java/blob/87fae0f98332e98a32bbb82515428b4edeb4181f/java/src/main/java/org/whispersystems/libsignal/ecc/DjbECPublicKey.java
|
||||
@objc public class ECPublicKey: NSObject {
|
||||
|
||||
@objc
|
||||
public static let keyTypeDJB: UInt8 = 0x05
|
||||
|
||||
@objc
|
||||
public let keyData: Data
|
||||
|
||||
@objc
|
||||
public init(keyData: Data) throws {
|
||||
guard keyData.count == ECCKeyLength else {
|
||||
throw SMKError.assertionError(description: "\(ECPublicKey.logTag) key has invalid length")
|
||||
}
|
||||
|
||||
self.keyData = keyData
|
||||
}
|
||||
|
||||
// https://github.com/signalapp/libsignal-protocol-java/blob/master/java/src/main/java/org/whispersystems/libsignal/ecc/Curve.java#L30
|
||||
@objc
|
||||
public init(serializedKeyData: Data) throws {
|
||||
let parser = OWSDataParser(data: serializedKeyData)
|
||||
|
||||
let typeByte = try parser.nextByte(name: "type byte")
|
||||
guard typeByte == ECPublicKey.keyTypeDJB else {
|
||||
throw SMKError.assertionError(description: "\(ECPublicKey.logTag) key data has invalid type byte")
|
||||
}
|
||||
|
||||
let keyData = try parser.remainder(name: "key data")
|
||||
guard keyData.count == ECCKeyLength else {
|
||||
throw SMKError.assertionError(description: "\(ECPublicKey.logTag) key has invalid length")
|
||||
}
|
||||
|
||||
self.keyData = keyData
|
||||
}
|
||||
|
||||
@objc public var serialized: Data {
|
||||
let typeBytes = [ECPublicKey.keyTypeDJB]
|
||||
let typeData = Data(bytes: typeBytes)
|
||||
return NSData.join([typeData, keyData])
|
||||
}
|
||||
|
||||
open override func isEqual(_ object: Any?) -> Bool {
|
||||
if let object = object as? ECPublicKey {
|
||||
return keyData == object.keyData
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
public override var hash: Int {
|
||||
return keyData.hashValue
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
import CryptoSwift
|
||||
import Curve25519Kit
|
||||
import SessionUtilities
|
||||
|
||||
/// A fallback session cipher which uses the the recipient's public key to encrypt data.
|
||||
@objc public final class FallBackSessionCipher : NSObject {
|
||||
/// The hex encoded public key of the recipient.
|
||||
private let recipientPublicKey: String
|
||||
private let privateKey: Data?
|
||||
private let ivSize: Int32 = 16
|
||||
|
||||
private lazy var recipientPublicKeyAsData: Data = {
|
||||
var recipientPublicKey = self.recipientPublicKey
|
||||
if recipientPublicKey.count == 66 && recipientPublicKey.hasPrefix("05") {
|
||||
let index = recipientPublicKey.index(recipientPublicKey.startIndex, offsetBy: 2)
|
||||
recipientPublicKey = recipientPublicKey.substring(from: index)
|
||||
}
|
||||
return Data(hex: recipientPublicKey)
|
||||
}()
|
||||
|
||||
private lazy var symmetricKey: Data? = {
|
||||
guard let privateKey = privateKey else { return nil }
|
||||
let keyPair = ECKeyPair(publicKey: recipientPublicKeyAsData, privateKey: privateKey)
|
||||
return Curve25519.generateSharedSecret(fromPublicKey: recipientPublicKeyAsData, andKeyPair: keyPair)
|
||||
}()
|
||||
|
||||
@objc public init(recipientPublicKey: String, privateKey: Data?) {
|
||||
self.recipientPublicKey = recipientPublicKey
|
||||
self.privateKey = privateKey
|
||||
super.init()
|
||||
}
|
||||
|
||||
@objc public func encrypt(_ plaintext: Data) -> Data? {
|
||||
guard let symmetricKey = symmetricKey else { return nil }
|
||||
do {
|
||||
return try DiffieHellman.encrypt(plaintext, using: symmetricKey)
|
||||
} catch {
|
||||
print("[Loki] Couldn't encrypt message using fallback session cipher due to error: \(error).")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@objc public func decrypt(_ ivAndCiphertext: Data) -> Data? {
|
||||
guard let symmetricKey = symmetricKey else { return nil }
|
||||
do {
|
||||
return try DiffieHellman.decrypt(ivAndCiphertext, using: symmetricKey)
|
||||
} catch {
|
||||
print("[Loki] Couldn't decrypt message using fallback session cipher due to error: \(error).")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
import Foundation
|
||||
|
||||
@objc(LKSessionCipher)
|
||||
public final class LokiSessionCipher : SessionCipher {
|
||||
private let sessionResetImplementation: SessionRestorationProtocol?
|
||||
private let sessionStore: SessionStore
|
||||
private let preKeyStore: PreKeyStore
|
||||
private let recipientID: String
|
||||
private let deviceID: Int32
|
||||
|
||||
@objc public static let newSessionAdoptedNotification = "LKNewSessionAdoptedNotification"
|
||||
@objc public static let contactKey = "LKContactKey"
|
||||
|
||||
@objc public init(sessionResetImplementation: SessionRestorationProtocol, sessionStore: SessionStore, preKeyStore: PreKeyStore, signedPreKeyStore: SignedPreKeyStore, identityKeyStore: IdentityKeyStore, recipientID: String, deviceID: Int32) {
|
||||
self.sessionResetImplementation = sessionResetImplementation
|
||||
self.sessionStore = sessionStore
|
||||
self.preKeyStore = preKeyStore
|
||||
self.recipientID = recipientID
|
||||
self.deviceID = deviceID
|
||||
super.init(sessionStore: sessionStore, preKeyStore: preKeyStore, signedPreKeyStore: signedPreKeyStore, identityKeyStore: identityKeyStore, recipientId: recipientID, deviceId: deviceID)
|
||||
}
|
||||
|
||||
@available(*, unavailable)
|
||||
override convenience private init(axolotlStore sessionStore: AxolotlStore, recipientId: String, deviceId: Int32) {
|
||||
self.init(sessionStore: sessionStore, preKeyStore: sessionStore, signedPreKeyStore: sessionStore, identityKeyStore: sessionStore, recipientId: recipientId, deviceId: deviceId)
|
||||
}
|
||||
|
||||
override private init(sessionStore: SessionStore, preKeyStore: PreKeyStore, signedPreKeyStore: SignedPreKeyStore, identityKeyStore: IdentityKeyStore, recipientId: String, deviceId: Int32) {
|
||||
self.sessionResetImplementation = nil
|
||||
self.sessionStore = sessionStore
|
||||
self.preKeyStore = preKeyStore
|
||||
self.recipientID = recipientId
|
||||
self.deviceID = deviceId
|
||||
super.init(sessionStore: sessionStore, preKeyStore: preKeyStore, signedPreKeyStore: signedPreKeyStore, identityKeyStore: identityKeyStore, recipientId: recipientId, deviceId: deviceId)
|
||||
}
|
||||
|
||||
override public func decrypt(_ whisperMessage: CipherMessage, protocolContext: Any?) throws -> Data {
|
||||
// Note that while decrypting our state may change internally
|
||||
let currentState = getCurrentState(protocolContext: protocolContext)
|
||||
if (currentState == nil && whisperMessage.cipherMessageType == .prekey) {
|
||||
try sessionResetImplementation?.validatePreKeyWhisperMessage(for: recipientID, whisperMessage: whisperMessage, using: protocolContext!)
|
||||
}
|
||||
let plainText = try super.decrypt(whisperMessage, protocolContext: protocolContext)
|
||||
handleSessionReset(for: whisperMessage, previousState: currentState, protocolContext: protocolContext!)
|
||||
return plainText
|
||||
}
|
||||
|
||||
private func getCurrentState(protocolContext: Any?) -> SessionState? {
|
||||
let record = sessionStore.loadSession(recipientID, deviceId: deviceID, protocolContext: protocolContext)
|
||||
return record.isFresh() ? nil : record.sessionState()
|
||||
}
|
||||
|
||||
private func handleSessionReset(for whisperMessage: CipherMessage, previousState: SessionState?, protocolContext: Any) {
|
||||
// Don't bother doing anything if we didn't have a session before
|
||||
guard let previousState = previousState else { return }
|
||||
let sessionResetStatus = sessionResetImplementation?.getSessionRestorationStatus(for: recipientID) ?? SessionRestorationStatus.none
|
||||
// Bail early if no session reset is in progress
|
||||
guard sessionResetStatus != .none else { return }
|
||||
let currentState = getCurrentState(protocolContext: protocolContext)
|
||||
// Check if our previous state and our current state differ
|
||||
if (currentState == nil || currentState!.aliceBaseKey != previousState.aliceBaseKey) {
|
||||
if sessionResetStatus == .requestReceived {
|
||||
// The other user used an old session to contact us. Wait for them to use a new one
|
||||
restoreSession(previousState, protocolContext: protocolContext)
|
||||
} else {
|
||||
// Our session reset went through successfully.
|
||||
// We initiated a session reset and got a different session back from the user.
|
||||
deleteAllSessions(except: currentState, protocolContext: protocolContext)
|
||||
notifySessionAdopted(protocolContext)
|
||||
}
|
||||
} else if sessionResetStatus == .requestReceived {
|
||||
// Our session reset went through successfully.
|
||||
// We got a message with the same session from the other user.
|
||||
deleteAllSessions(except: previousState, protocolContext: protocolContext)
|
||||
notifySessionAdopted(protocolContext)
|
||||
}
|
||||
}
|
||||
|
||||
private func notifySessionAdopted(_ protocolContext: Any) {
|
||||
self.sessionResetImplementation?.handleNewSessionAdopted(for: recipientID, using: protocolContext)
|
||||
NotificationCenter.default.post(name: NSNotification.Name(rawValue: LokiSessionCipher.newSessionAdoptedNotification), object: nil, userInfo: [ LokiSessionCipher.contactKey : recipientID ])
|
||||
}
|
||||
|
||||
private func deleteAllSessions(except state: SessionState?, protocolContext: Any?) {
|
||||
let record = sessionStore.loadSession(recipientID, deviceId: deviceID, protocolContext: protocolContext)
|
||||
record.removePreviousSessionStates()
|
||||
let newState = state ?? SessionState()
|
||||
record.setState(newState)
|
||||
sessionStore.storeSession(recipientID, deviceId: deviceID, session: record, protocolContext: protocolContext)
|
||||
}
|
||||
|
||||
private func restoreSession(_ state: SessionState, protocolContext: Any?) {
|
||||
let record = sessionStore.loadSession(recipientID, deviceId: deviceID, protocolContext: protocolContext)
|
||||
// Remove the state from previous session states
|
||||
record.previousSessionStates()?.enumerateObjects(options: .reverse) { obj, index, stop in
|
||||
guard let obj = obj as? SessionState, state.aliceBaseKey == obj.aliceBaseKey else { return }
|
||||
record.previousSessionStates()?.removeObject(at: index)
|
||||
stop.pointee = true
|
||||
}
|
||||
// Promote so the previous state gets archived
|
||||
record.promoteState(state)
|
||||
sessionStore.storeSession(recipientID, deviceId: deviceID, session: record, protocolContext: protocolContext)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
@interface NSData (messagePadding)
|
||||
|
||||
- (NSData *)removePadding;
|
||||
|
||||
- (NSData *)paddedMessageBody;
|
||||
|
||||
@end
|
|
@ -0,0 +1,60 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "OWSAsserts.h"
|
||||
#import "NSData+messagePadding.h"
|
||||
|
||||
@implementation NSData (messagePadding)
|
||||
|
||||
- (NSData *)removePadding {
|
||||
unsigned long paddingStart = self.length;
|
||||
|
||||
Byte data[self.length];
|
||||
[self getBytes:data length:self.length];
|
||||
|
||||
for (long i = (long)self.length - 1; i >= 0; i--) {
|
||||
if (data[i] == (Byte)0x80) {
|
||||
paddingStart = (unsigned long)i;
|
||||
break;
|
||||
} else if (data[i] != (Byte)0x00) {
|
||||
OWSLogWarn(@"Failed to remove padding, returning unstripped padding");
|
||||
return self;
|
||||
}
|
||||
}
|
||||
|
||||
return [self subdataWithRange:NSMakeRange(0, paddingStart)];
|
||||
}
|
||||
|
||||
|
||||
- (NSData *)paddedMessageBody {
|
||||
// From
|
||||
// https://github.com/signalapp/TextSecure/blob/master/libtextsecure/src/main/java/org/whispersystems/textsecure/internal/push/PushTransportDetails.java#L55
|
||||
// NOTE: This is dumb. We have our own padding scheme, but so does the cipher.
|
||||
// The +1 -1 here is to make sure the Cipher has room to add one padding byte,
|
||||
// otherwise it'll add a full 16 extra bytes.
|
||||
|
||||
NSUInteger paddedMessageLength = [self paddedMessageLength:(self.length + 1)] - 1;
|
||||
NSMutableData *paddedMessage = [NSMutableData dataWithLength:paddedMessageLength];
|
||||
|
||||
Byte paddingByte = 0x80;
|
||||
|
||||
[paddedMessage replaceBytesInRange:NSMakeRange(0, self.length) withBytes:[self bytes]];
|
||||
[paddedMessage replaceBytesInRange:NSMakeRange(self.length, 1) withBytes:&paddingByte];
|
||||
|
||||
return paddedMessage;
|
||||
}
|
||||
|
||||
- (NSUInteger)paddedMessageLength:(NSUInteger)messageLength {
|
||||
NSUInteger messageLengthWithTerminator = messageLength + 1;
|
||||
NSUInteger messagePartCount = messageLengthWithTerminator / 160;
|
||||
|
||||
if (messageLengthWithTerminator % 160 != 0) {
|
||||
messagePartCount++;
|
||||
}
|
||||
|
||||
return messagePartCount * 160;
|
||||
}
|
||||
|
||||
@end
|
|
@ -3,10 +3,16 @@ PROTOC=protoc \
|
|||
WRAPPER_SCRIPT=../../../../session-ios/Scripts/ProtoWrappers.py \
|
||||
--proto-dir='./' --verbose --add-log-tag
|
||||
|
||||
all: webrtc_data_proto
|
||||
all: webrtc_data_proto unidentified_delivery_protos
|
||||
|
||||
webrtc_data_proto: WhisperTextProtocol.proto
|
||||
$(PROTOC) --swift_out=. \
|
||||
WhisperTextProtocol.proto
|
||||
$(WRAPPER_SCRIPT) --dst-dir=. \
|
||||
--wrapper-prefix=SPKProto --proto-prefix=SPKProtos --proto-file=WhisperTextProtocol.proto
|
||||
|
||||
unidentified_delivery_protos: OWSUnidentifiedDelivery.proto
|
||||
$(PROTOC) --swift_out=../SignalMetadataKit/src/Generated \
|
||||
OWSUnidentifiedDelivery.proto
|
||||
$(WRAPPER_SCRIPT) --dst-dir=../SignalMetadataKit/src/Generated \
|
||||
--wrapper-prefix=SMKProto --proto-prefix=SMKProtos --proto-file=OWSUnidentifiedDelivery.proto
|
||||
|
|
|
@ -0,0 +1,571 @@
|
|||
// DO NOT EDIT.
|
||||
// swift-format-ignore-file
|
||||
//
|
||||
// Generated by the Swift generator plugin for the protocol buffer compiler.
|
||||
// Source: OWSUnidentifiedDelivery.proto
|
||||
//
|
||||
// For information on using the generated types, please see the documentation:
|
||||
// https://github.com/apple/swift-protobuf/
|
||||
|
||||
//*
|
||||
// Copyright (C) 2014-2016 Open Whisper Systems
|
||||
//
|
||||
// Licensed according to the LICENSE file in this repository.
|
||||
|
||||
/// iOS - since we use a modern proto-compiler, we must specify
|
||||
/// the legacy proto format.
|
||||
|
||||
import Foundation
|
||||
import SwiftProtobuf
|
||||
|
||||
// If the compiler emits an error on this type, it is because this file
|
||||
// was generated by a version of the `protoc` Swift plug-in that is
|
||||
// incompatible with the version of SwiftProtobuf to which you are linking.
|
||||
// Please ensure that you are building against the same version of the API
|
||||
// that was used to generate this file.
|
||||
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
|
||||
typealias Version = _2
|
||||
}
|
||||
|
||||
struct SMKProtos_ServerCertificate {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
/// @required
|
||||
var certificate: Data {
|
||||
get {return _certificate ?? SwiftProtobuf.Internal.emptyData}
|
||||
set {_certificate = newValue}
|
||||
}
|
||||
/// Returns true if `certificate` has been explicitly set.
|
||||
var hasCertificate: Bool {return self._certificate != nil}
|
||||
/// Clears the value of `certificate`. Subsequent reads from it will return its default value.
|
||||
mutating func clearCertificate() {self._certificate = nil}
|
||||
|
||||
/// @required
|
||||
var signature: Data {
|
||||
get {return _signature ?? SwiftProtobuf.Internal.emptyData}
|
||||
set {_signature = newValue}
|
||||
}
|
||||
/// Returns true if `signature` has been explicitly set.
|
||||
var hasSignature: Bool {return self._signature != nil}
|
||||
/// Clears the value of `signature`. Subsequent reads from it will return its default value.
|
||||
mutating func clearSignature() {self._signature = nil}
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
struct Certificate {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
/// @required
|
||||
var id: UInt32 {
|
||||
get {return _id ?? 0}
|
||||
set {_id = newValue}
|
||||
}
|
||||
/// Returns true if `id` has been explicitly set.
|
||||
var hasID: Bool {return self._id != nil}
|
||||
/// Clears the value of `id`. Subsequent reads from it will return its default value.
|
||||
mutating func clearID() {self._id = nil}
|
||||
|
||||
/// @required
|
||||
var key: Data {
|
||||
get {return _key ?? SwiftProtobuf.Internal.emptyData}
|
||||
set {_key = newValue}
|
||||
}
|
||||
/// Returns true if `key` has been explicitly set.
|
||||
var hasKey: Bool {return self._key != nil}
|
||||
/// Clears the value of `key`. Subsequent reads from it will return its default value.
|
||||
mutating func clearKey() {self._key = nil}
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
init() {}
|
||||
|
||||
fileprivate var _id: UInt32? = nil
|
||||
fileprivate var _key: Data? = nil
|
||||
}
|
||||
|
||||
init() {}
|
||||
|
||||
fileprivate var _certificate: Data? = nil
|
||||
fileprivate var _signature: Data? = nil
|
||||
}
|
||||
|
||||
struct SMKProtos_SenderCertificate {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
/// @required
|
||||
var sender: String {
|
||||
get {return _sender ?? String()}
|
||||
set {_sender = newValue}
|
||||
}
|
||||
/// Returns true if `sender` has been explicitly set.
|
||||
var hasSender: Bool {return self._sender != nil}
|
||||
/// Clears the value of `sender`. Subsequent reads from it will return its default value.
|
||||
mutating func clearSender() {self._sender = nil}
|
||||
|
||||
/// @required
|
||||
var senderDevice: UInt32 {
|
||||
get {return _senderDevice ?? 0}
|
||||
set {_senderDevice = newValue}
|
||||
}
|
||||
/// Returns true if `senderDevice` has been explicitly set.
|
||||
var hasSenderDevice: Bool {return self._senderDevice != nil}
|
||||
/// Clears the value of `senderDevice`. Subsequent reads from it will return its default value.
|
||||
mutating func clearSenderDevice() {self._senderDevice = nil}
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
struct Certificate {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
/// @required
|
||||
var sender: String {
|
||||
get {return _sender ?? String()}
|
||||
set {_sender = newValue}
|
||||
}
|
||||
/// Returns true if `sender` has been explicitly set.
|
||||
var hasSender: Bool {return self._sender != nil}
|
||||
/// Clears the value of `sender`. Subsequent reads from it will return its default value.
|
||||
mutating func clearSender() {self._sender = nil}
|
||||
|
||||
/// @required
|
||||
var senderDevice: UInt32 {
|
||||
get {return _senderDevice ?? 0}
|
||||
set {_senderDevice = newValue}
|
||||
}
|
||||
/// Returns true if `senderDevice` has been explicitly set.
|
||||
var hasSenderDevice: Bool {return self._senderDevice != nil}
|
||||
/// Clears the value of `senderDevice`. Subsequent reads from it will return its default value.
|
||||
mutating func clearSenderDevice() {self._senderDevice = nil}
|
||||
|
||||
/// @required
|
||||
var expires: UInt64 {
|
||||
get {return _expires ?? 0}
|
||||
set {_expires = newValue}
|
||||
}
|
||||
/// Returns true if `expires` has been explicitly set.
|
||||
var hasExpires: Bool {return self._expires != nil}
|
||||
/// Clears the value of `expires`. Subsequent reads from it will return its default value.
|
||||
mutating func clearExpires() {self._expires = nil}
|
||||
|
||||
/// @required
|
||||
var identityKey: Data {
|
||||
get {return _identityKey ?? SwiftProtobuf.Internal.emptyData}
|
||||
set {_identityKey = newValue}
|
||||
}
|
||||
/// Returns true if `identityKey` has been explicitly set.
|
||||
var hasIdentityKey: Bool {return self._identityKey != nil}
|
||||
/// Clears the value of `identityKey`. Subsequent reads from it will return its default value.
|
||||
mutating func clearIdentityKey() {self._identityKey = nil}
|
||||
|
||||
/// @required
|
||||
var signer: SMKProtos_ServerCertificate {
|
||||
get {return _signer ?? SMKProtos_ServerCertificate()}
|
||||
set {_signer = newValue}
|
||||
}
|
||||
/// Returns true if `signer` has been explicitly set.
|
||||
var hasSigner: Bool {return self._signer != nil}
|
||||
/// Clears the value of `signer`. Subsequent reads from it will return its default value.
|
||||
mutating func clearSigner() {self._signer = nil}
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
init() {}
|
||||
|
||||
fileprivate var _sender: String? = nil
|
||||
fileprivate var _senderDevice: UInt32? = nil
|
||||
fileprivate var _expires: UInt64? = nil
|
||||
fileprivate var _identityKey: Data? = nil
|
||||
fileprivate var _signer: SMKProtos_ServerCertificate? = nil
|
||||
}
|
||||
|
||||
init() {}
|
||||
|
||||
fileprivate var _sender: String? = nil
|
||||
fileprivate var _senderDevice: UInt32? = nil
|
||||
}
|
||||
|
||||
struct SMKProtos_UnidentifiedSenderMessage {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
/// @required
|
||||
var ephemeralPublic: Data {
|
||||
get {return _ephemeralPublic ?? SwiftProtobuf.Internal.emptyData}
|
||||
set {_ephemeralPublic = newValue}
|
||||
}
|
||||
/// Returns true if `ephemeralPublic` has been explicitly set.
|
||||
var hasEphemeralPublic: Bool {return self._ephemeralPublic != nil}
|
||||
/// Clears the value of `ephemeralPublic`. Subsequent reads from it will return its default value.
|
||||
mutating func clearEphemeralPublic() {self._ephemeralPublic = nil}
|
||||
|
||||
/// @required
|
||||
var encryptedStatic: Data {
|
||||
get {return _encryptedStatic ?? SwiftProtobuf.Internal.emptyData}
|
||||
set {_encryptedStatic = newValue}
|
||||
}
|
||||
/// Returns true if `encryptedStatic` has been explicitly set.
|
||||
var hasEncryptedStatic: Bool {return self._encryptedStatic != nil}
|
||||
/// Clears the value of `encryptedStatic`. Subsequent reads from it will return its default value.
|
||||
mutating func clearEncryptedStatic() {self._encryptedStatic = nil}
|
||||
|
||||
/// @required
|
||||
var encryptedMessage: Data {
|
||||
get {return _encryptedMessage ?? SwiftProtobuf.Internal.emptyData}
|
||||
set {_encryptedMessage = newValue}
|
||||
}
|
||||
/// Returns true if `encryptedMessage` has been explicitly set.
|
||||
var hasEncryptedMessage: Bool {return self._encryptedMessage != nil}
|
||||
/// Clears the value of `encryptedMessage`. Subsequent reads from it will return its default value.
|
||||
mutating func clearEncryptedMessage() {self._encryptedMessage = nil}
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
struct Message {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
/// @required
|
||||
var type: SMKProtos_UnidentifiedSenderMessage.Message.TypeEnum {
|
||||
get {return _type ?? .prekeyMessage}
|
||||
set {_type = newValue}
|
||||
}
|
||||
/// Returns true if `type` has been explicitly set.
|
||||
var hasType: Bool {return self._type != nil}
|
||||
/// Clears the value of `type`. Subsequent reads from it will return its default value.
|
||||
mutating func clearType() {self._type = nil}
|
||||
|
||||
/// @required
|
||||
var senderCertificate: SMKProtos_SenderCertificate {
|
||||
get {return _senderCertificate ?? SMKProtos_SenderCertificate()}
|
||||
set {_senderCertificate = newValue}
|
||||
}
|
||||
/// Returns true if `senderCertificate` has been explicitly set.
|
||||
var hasSenderCertificate: Bool {return self._senderCertificate != nil}
|
||||
/// Clears the value of `senderCertificate`. Subsequent reads from it will return its default value.
|
||||
mutating func clearSenderCertificate() {self._senderCertificate = nil}
|
||||
|
||||
/// @required
|
||||
var content: Data {
|
||||
get {return _content ?? SwiftProtobuf.Internal.emptyData}
|
||||
set {_content = newValue}
|
||||
}
|
||||
/// Returns true if `content` has been explicitly set.
|
||||
var hasContent: Bool {return self._content != nil}
|
||||
/// Clears the value of `content`. Subsequent reads from it will return its default value.
|
||||
mutating func clearContent() {self._content = nil}
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
enum TypeEnum: SwiftProtobuf.Enum {
|
||||
typealias RawValue = Int
|
||||
case prekeyMessage // = 1
|
||||
case message // = 2
|
||||
case fallbackMessage // = 3
|
||||
|
||||
init() {
|
||||
self = .prekeyMessage
|
||||
}
|
||||
|
||||
init?(rawValue: Int) {
|
||||
switch rawValue {
|
||||
case 1: self = .prekeyMessage
|
||||
case 2: self = .message
|
||||
case 3: self = .fallbackMessage
|
||||
default: return nil
|
||||
}
|
||||
}
|
||||
|
||||
var rawValue: Int {
|
||||
switch self {
|
||||
case .prekeyMessage: return 1
|
||||
case .message: return 2
|
||||
case .fallbackMessage: return 3
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
init() {}
|
||||
|
||||
fileprivate var _type: SMKProtos_UnidentifiedSenderMessage.Message.TypeEnum? = nil
|
||||
fileprivate var _senderCertificate: SMKProtos_SenderCertificate? = nil
|
||||
fileprivate var _content: Data? = nil
|
||||
}
|
||||
|
||||
init() {}
|
||||
|
||||
fileprivate var _ephemeralPublic: Data? = nil
|
||||
fileprivate var _encryptedStatic: Data? = nil
|
||||
fileprivate var _encryptedMessage: Data? = nil
|
||||
}
|
||||
|
||||
#if swift(>=4.2)
|
||||
|
||||
extension SMKProtos_UnidentifiedSenderMessage.Message.TypeEnum: CaseIterable {
|
||||
// Support synthesized by the compiler.
|
||||
}
|
||||
|
||||
#endif // swift(>=4.2)
|
||||
|
||||
// MARK: - Code below here is support for the SwiftProtobuf runtime.
|
||||
|
||||
fileprivate let _protobuf_package = "SMKProtos"
|
||||
|
||||
extension SMKProtos_ServerCertificate: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = _protobuf_package + ".ServerCertificate"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "certificate"),
|
||||
2: .same(proto: "signature"),
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
switch fieldNumber {
|
||||
case 1: try decoder.decodeSingularBytesField(value: &self._certificate)
|
||||
case 2: try decoder.decodeSingularBytesField(value: &self._signature)
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
if let v = self._certificate {
|
||||
try visitor.visitSingularBytesField(value: v, fieldNumber: 1)
|
||||
}
|
||||
if let v = self._signature {
|
||||
try visitor.visitSingularBytesField(value: v, fieldNumber: 2)
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
static func ==(lhs: SMKProtos_ServerCertificate, rhs: SMKProtos_ServerCertificate) -> Bool {
|
||||
if lhs._certificate != rhs._certificate {return false}
|
||||
if lhs._signature != rhs._signature {return false}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
extension SMKProtos_ServerCertificate.Certificate: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = SMKProtos_ServerCertificate.protoMessageName + ".Certificate"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "id"),
|
||||
2: .same(proto: "key"),
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
switch fieldNumber {
|
||||
case 1: try decoder.decodeSingularUInt32Field(value: &self._id)
|
||||
case 2: try decoder.decodeSingularBytesField(value: &self._key)
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
if let v = self._id {
|
||||
try visitor.visitSingularUInt32Field(value: v, fieldNumber: 1)
|
||||
}
|
||||
if let v = self._key {
|
||||
try visitor.visitSingularBytesField(value: v, fieldNumber: 2)
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
static func ==(lhs: SMKProtos_ServerCertificate.Certificate, rhs: SMKProtos_ServerCertificate.Certificate) -> Bool {
|
||||
if lhs._id != rhs._id {return false}
|
||||
if lhs._key != rhs._key {return false}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
extension SMKProtos_SenderCertificate: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = _protobuf_package + ".SenderCertificate"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "sender"),
|
||||
2: .same(proto: "senderDevice"),
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
switch fieldNumber {
|
||||
case 1: try decoder.decodeSingularStringField(value: &self._sender)
|
||||
case 2: try decoder.decodeSingularUInt32Field(value: &self._senderDevice)
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
if let v = self._sender {
|
||||
try visitor.visitSingularStringField(value: v, fieldNumber: 1)
|
||||
}
|
||||
if let v = self._senderDevice {
|
||||
try visitor.visitSingularUInt32Field(value: v, fieldNumber: 2)
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
static func ==(lhs: SMKProtos_SenderCertificate, rhs: SMKProtos_SenderCertificate) -> Bool {
|
||||
if lhs._sender != rhs._sender {return false}
|
||||
if lhs._senderDevice != rhs._senderDevice {return false}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
extension SMKProtos_SenderCertificate.Certificate: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = SMKProtos_SenderCertificate.protoMessageName + ".Certificate"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "sender"),
|
||||
2: .same(proto: "senderDevice"),
|
||||
3: .same(proto: "expires"),
|
||||
4: .same(proto: "identityKey"),
|
||||
5: .same(proto: "signer"),
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
switch fieldNumber {
|
||||
case 1: try decoder.decodeSingularStringField(value: &self._sender)
|
||||
case 2: try decoder.decodeSingularUInt32Field(value: &self._senderDevice)
|
||||
case 3: try decoder.decodeSingularFixed64Field(value: &self._expires)
|
||||
case 4: try decoder.decodeSingularBytesField(value: &self._identityKey)
|
||||
case 5: try decoder.decodeSingularMessageField(value: &self._signer)
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
if let v = self._sender {
|
||||
try visitor.visitSingularStringField(value: v, fieldNumber: 1)
|
||||
}
|
||||
if let v = self._senderDevice {
|
||||
try visitor.visitSingularUInt32Field(value: v, fieldNumber: 2)
|
||||
}
|
||||
if let v = self._expires {
|
||||
try visitor.visitSingularFixed64Field(value: v, fieldNumber: 3)
|
||||
}
|
||||
if let v = self._identityKey {
|
||||
try visitor.visitSingularBytesField(value: v, fieldNumber: 4)
|
||||
}
|
||||
if let v = self._signer {
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 5)
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
static func ==(lhs: SMKProtos_SenderCertificate.Certificate, rhs: SMKProtos_SenderCertificate.Certificate) -> Bool {
|
||||
if lhs._sender != rhs._sender {return false}
|
||||
if lhs._senderDevice != rhs._senderDevice {return false}
|
||||
if lhs._expires != rhs._expires {return false}
|
||||
if lhs._identityKey != rhs._identityKey {return false}
|
||||
if lhs._signer != rhs._signer {return false}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
extension SMKProtos_UnidentifiedSenderMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = _protobuf_package + ".UnidentifiedSenderMessage"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "ephemeralPublic"),
|
||||
2: .same(proto: "encryptedStatic"),
|
||||
3: .same(proto: "encryptedMessage"),
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
switch fieldNumber {
|
||||
case 1: try decoder.decodeSingularBytesField(value: &self._ephemeralPublic)
|
||||
case 2: try decoder.decodeSingularBytesField(value: &self._encryptedStatic)
|
||||
case 3: try decoder.decodeSingularBytesField(value: &self._encryptedMessage)
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
if let v = self._ephemeralPublic {
|
||||
try visitor.visitSingularBytesField(value: v, fieldNumber: 1)
|
||||
}
|
||||
if let v = self._encryptedStatic {
|
||||
try visitor.visitSingularBytesField(value: v, fieldNumber: 2)
|
||||
}
|
||||
if let v = self._encryptedMessage {
|
||||
try visitor.visitSingularBytesField(value: v, fieldNumber: 3)
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
static func ==(lhs: SMKProtos_UnidentifiedSenderMessage, rhs: SMKProtos_UnidentifiedSenderMessage) -> Bool {
|
||||
if lhs._ephemeralPublic != rhs._ephemeralPublic {return false}
|
||||
if lhs._encryptedStatic != rhs._encryptedStatic {return false}
|
||||
if lhs._encryptedMessage != rhs._encryptedMessage {return false}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
extension SMKProtos_UnidentifiedSenderMessage.Message: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = SMKProtos_UnidentifiedSenderMessage.protoMessageName + ".Message"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "type"),
|
||||
2: .same(proto: "senderCertificate"),
|
||||
3: .same(proto: "content"),
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
switch fieldNumber {
|
||||
case 1: try decoder.decodeSingularEnumField(value: &self._type)
|
||||
case 2: try decoder.decodeSingularMessageField(value: &self._senderCertificate)
|
||||
case 3: try decoder.decodeSingularBytesField(value: &self._content)
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
if let v = self._type {
|
||||
try visitor.visitSingularEnumField(value: v, fieldNumber: 1)
|
||||
}
|
||||
if let v = self._senderCertificate {
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 2)
|
||||
}
|
||||
if let v = self._content {
|
||||
try visitor.visitSingularBytesField(value: v, fieldNumber: 3)
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
static func ==(lhs: SMKProtos_UnidentifiedSenderMessage.Message, rhs: SMKProtos_UnidentifiedSenderMessage.Message) -> Bool {
|
||||
if lhs._type != rhs._type {return false}
|
||||
if lhs._senderCertificate != rhs._senderCertificate {return false}
|
||||
if lhs._content != rhs._content {return false}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
extension SMKProtos_UnidentifiedSenderMessage.Message.TypeEnum: SwiftProtobuf._ProtoNameProviding {
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "PREKEY_MESSAGE"),
|
||||
2: .same(proto: "MESSAGE"),
|
||||
3: .same(proto: "FALLBACK_MESSAGE"),
|
||||
]
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/**
|
||||
* Copyright (C) 2014-2016 Open Whisper Systems
|
||||
*
|
||||
* Licensed according to the LICENSE file in this repository.
|
||||
*/
|
||||
|
||||
// iOS - since we use a modern proto-compiler, we must specify
|
||||
// the legacy proto format.
|
||||
syntax = "proto2";
|
||||
|
||||
// iOS - package name determines class prefix
|
||||
package SMKProtos;
|
||||
|
||||
option java_package = "org.signal.libsignal.metadata";
|
||||
option java_outer_classname = "SignalProtos";
|
||||
|
||||
message ServerCertificate {
|
||||
message Certificate {
|
||||
// @required
|
||||
optional uint32 id = 1;
|
||||
// @required
|
||||
optional bytes key = 2;
|
||||
}
|
||||
|
||||
// @required
|
||||
optional bytes certificate = 1;
|
||||
// @required
|
||||
optional bytes signature = 2;
|
||||
}
|
||||
|
||||
message SenderCertificate {
|
||||
message Certificate {
|
||||
// @required
|
||||
optional string sender = 1;
|
||||
// @required
|
||||
optional uint32 senderDevice = 2;
|
||||
// @required
|
||||
optional fixed64 expires = 3;
|
||||
// @required
|
||||
optional bytes identityKey = 4;
|
||||
// @required
|
||||
optional ServerCertificate signer = 5;
|
||||
}
|
||||
|
||||
// @required
|
||||
optional string sender = 1;
|
||||
// @required
|
||||
optional uint32 senderDevice = 2;
|
||||
}
|
||||
|
||||
message UnidentifiedSenderMessage {
|
||||
message Message {
|
||||
enum Type {
|
||||
PREKEY_MESSAGE = 1;
|
||||
MESSAGE = 2;
|
||||
FALLBACK_MESSAGE = 3;
|
||||
}
|
||||
|
||||
// @required
|
||||
optional Type type = 1;
|
||||
// @required
|
||||
optional SenderCertificate senderCertificate = 2;
|
||||
// @required
|
||||
optional bytes content = 3;
|
||||
}
|
||||
|
||||
// @required
|
||||
optional bytes ephemeralPublic = 1;
|
||||
// @required
|
||||
optional bytes encryptedStatic = 2;
|
||||
// @required
|
||||
optional bytes encryptedMessage = 3;
|
||||
}
|
|
@ -0,0 +1,782 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
// WARNING: This code is generated. Only edit within the markers.
|
||||
|
||||
public enum SMKProtoError: Error {
|
||||
case invalidProtobuf(description: String)
|
||||
}
|
||||
|
||||
// MARK: - SMKProtoServerCertificateCertificate
|
||||
|
||||
@objc public class SMKProtoServerCertificateCertificate: NSObject {
|
||||
|
||||
// MARK: - SMKProtoServerCertificateCertificateBuilder
|
||||
|
||||
@objc public class func builder(id: UInt32, key: Data) -> SMKProtoServerCertificateCertificateBuilder {
|
||||
return SMKProtoServerCertificateCertificateBuilder(id: id, key: key)
|
||||
}
|
||||
|
||||
// asBuilder() constructs a builder that reflects the proto's contents.
|
||||
@objc public func asBuilder() -> SMKProtoServerCertificateCertificateBuilder {
|
||||
let builder = SMKProtoServerCertificateCertificateBuilder(id: id, key: key)
|
||||
return builder
|
||||
}
|
||||
|
||||
@objc public class SMKProtoServerCertificateCertificateBuilder: NSObject {
|
||||
|
||||
private var proto = SMKProtos_ServerCertificate.Certificate()
|
||||
|
||||
@objc fileprivate override init() {}
|
||||
|
||||
@objc fileprivate init(id: UInt32, key: Data) {
|
||||
super.init()
|
||||
|
||||
setId(id)
|
||||
setKey(key)
|
||||
}
|
||||
|
||||
@objc public func setId(_ valueParam: UInt32) {
|
||||
proto.id = valueParam
|
||||
}
|
||||
|
||||
@objc public func setKey(_ valueParam: Data) {
|
||||
proto.key = valueParam
|
||||
}
|
||||
|
||||
@objc public func build() throws -> SMKProtoServerCertificateCertificate {
|
||||
return try SMKProtoServerCertificateCertificate.parseProto(proto)
|
||||
}
|
||||
|
||||
@objc public func buildSerializedData() throws -> Data {
|
||||
return try SMKProtoServerCertificateCertificate.parseProto(proto).serializedData()
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate let proto: SMKProtos_ServerCertificate.Certificate
|
||||
|
||||
@objc public let id: UInt32
|
||||
|
||||
@objc public let key: Data
|
||||
|
||||
private init(proto: SMKProtos_ServerCertificate.Certificate,
|
||||
id: UInt32,
|
||||
key: Data) {
|
||||
self.proto = proto
|
||||
self.id = id
|
||||
self.key = key
|
||||
}
|
||||
|
||||
@objc
|
||||
public func serializedData() throws -> Data {
|
||||
return try self.proto.serializedData()
|
||||
}
|
||||
|
||||
@objc public class func parseData(_ serializedData: Data) throws -> SMKProtoServerCertificateCertificate {
|
||||
let proto = try SMKProtos_ServerCertificate.Certificate(serializedData: serializedData)
|
||||
return try parseProto(proto)
|
||||
}
|
||||
|
||||
fileprivate class func parseProto(_ proto: SMKProtos_ServerCertificate.Certificate) throws -> SMKProtoServerCertificateCertificate {
|
||||
guard proto.hasID else {
|
||||
throw SMKProtoError.invalidProtobuf(description: "\(logTag) missing required field: id")
|
||||
}
|
||||
let id = proto.id
|
||||
|
||||
guard proto.hasKey else {
|
||||
throw SMKProtoError.invalidProtobuf(description: "\(logTag) missing required field: key")
|
||||
}
|
||||
let key = proto.key
|
||||
|
||||
// MARK: - Begin Validation Logic for SMKProtoServerCertificateCertificate -
|
||||
|
||||
// MARK: - End Validation Logic for SMKProtoServerCertificateCertificate -
|
||||
|
||||
let result = SMKProtoServerCertificateCertificate(proto: proto,
|
||||
id: id,
|
||||
key: key)
|
||||
return result
|
||||
}
|
||||
|
||||
@objc public override var debugDescription: String {
|
||||
return "\(proto)"
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
|
||||
extension SMKProtoServerCertificateCertificate {
|
||||
@objc public func serializedDataIgnoringErrors() -> Data? {
|
||||
return try! self.serializedData()
|
||||
}
|
||||
}
|
||||
|
||||
extension SMKProtoServerCertificateCertificate.SMKProtoServerCertificateCertificateBuilder {
|
||||
@objc public func buildIgnoringErrors() -> SMKProtoServerCertificateCertificate? {
|
||||
return try! self.build()
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// MARK: - SMKProtoServerCertificate
|
||||
|
||||
@objc public class SMKProtoServerCertificate: NSObject {
|
||||
|
||||
// MARK: - SMKProtoServerCertificateBuilder
|
||||
|
||||
@objc public class func builder(certificate: Data, signature: Data) -> SMKProtoServerCertificateBuilder {
|
||||
return SMKProtoServerCertificateBuilder(certificate: certificate, signature: signature)
|
||||
}
|
||||
|
||||
// asBuilder() constructs a builder that reflects the proto's contents.
|
||||
@objc public func asBuilder() -> SMKProtoServerCertificateBuilder {
|
||||
let builder = SMKProtoServerCertificateBuilder(certificate: certificate, signature: signature)
|
||||
return builder
|
||||
}
|
||||
|
||||
@objc public class SMKProtoServerCertificateBuilder: NSObject {
|
||||
|
||||
private var proto = SMKProtos_ServerCertificate()
|
||||
|
||||
@objc fileprivate override init() {}
|
||||
|
||||
@objc fileprivate init(certificate: Data, signature: Data) {
|
||||
super.init()
|
||||
|
||||
setCertificate(certificate)
|
||||
setSignature(signature)
|
||||
}
|
||||
|
||||
@objc public func setCertificate(_ valueParam: Data) {
|
||||
proto.certificate = valueParam
|
||||
}
|
||||
|
||||
@objc public func setSignature(_ valueParam: Data) {
|
||||
proto.signature = valueParam
|
||||
}
|
||||
|
||||
@objc public func build() throws -> SMKProtoServerCertificate {
|
||||
return try SMKProtoServerCertificate.parseProto(proto)
|
||||
}
|
||||
|
||||
@objc public func buildSerializedData() throws -> Data {
|
||||
return try SMKProtoServerCertificate.parseProto(proto).serializedData()
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate let proto: SMKProtos_ServerCertificate
|
||||
|
||||
@objc public let certificate: Data
|
||||
|
||||
@objc public let signature: Data
|
||||
|
||||
private init(proto: SMKProtos_ServerCertificate,
|
||||
certificate: Data,
|
||||
signature: Data) {
|
||||
self.proto = proto
|
||||
self.certificate = certificate
|
||||
self.signature = signature
|
||||
}
|
||||
|
||||
@objc
|
||||
public func serializedData() throws -> Data {
|
||||
return try self.proto.serializedData()
|
||||
}
|
||||
|
||||
@objc public class func parseData(_ serializedData: Data) throws -> SMKProtoServerCertificate {
|
||||
let proto = try SMKProtos_ServerCertificate(serializedData: serializedData)
|
||||
return try parseProto(proto)
|
||||
}
|
||||
|
||||
fileprivate class func parseProto(_ proto: SMKProtos_ServerCertificate) throws -> SMKProtoServerCertificate {
|
||||
guard proto.hasCertificate else {
|
||||
throw SMKProtoError.invalidProtobuf(description: "\(logTag) missing required field: certificate")
|
||||
}
|
||||
let certificate = proto.certificate
|
||||
|
||||
guard proto.hasSignature else {
|
||||
throw SMKProtoError.invalidProtobuf(description: "\(logTag) missing required field: signature")
|
||||
}
|
||||
let signature = proto.signature
|
||||
|
||||
// MARK: - Begin Validation Logic for SMKProtoServerCertificate -
|
||||
|
||||
// MARK: - End Validation Logic for SMKProtoServerCertificate -
|
||||
|
||||
let result = SMKProtoServerCertificate(proto: proto,
|
||||
certificate: certificate,
|
||||
signature: signature)
|
||||
return result
|
||||
}
|
||||
|
||||
@objc public override var debugDescription: String {
|
||||
return "\(proto)"
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
|
||||
extension SMKProtoServerCertificate {
|
||||
@objc public func serializedDataIgnoringErrors() -> Data? {
|
||||
return try! self.serializedData()
|
||||
}
|
||||
}
|
||||
|
||||
extension SMKProtoServerCertificate.SMKProtoServerCertificateBuilder {
|
||||
@objc public func buildIgnoringErrors() -> SMKProtoServerCertificate? {
|
||||
return try! self.build()
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// MARK: - SMKProtoSenderCertificateCertificate
|
||||
|
||||
@objc public class SMKProtoSenderCertificateCertificate: NSObject {
|
||||
|
||||
// MARK: - SMKProtoSenderCertificateCertificateBuilder
|
||||
|
||||
@objc public class func builder(sender: String, senderDevice: UInt32, expires: UInt64, identityKey: Data, signer: SMKProtoServerCertificate) -> SMKProtoSenderCertificateCertificateBuilder {
|
||||
return SMKProtoSenderCertificateCertificateBuilder(sender: sender, senderDevice: senderDevice, expires: expires, identityKey: identityKey, signer: signer)
|
||||
}
|
||||
|
||||
// asBuilder() constructs a builder that reflects the proto's contents.
|
||||
@objc public func asBuilder() -> SMKProtoSenderCertificateCertificateBuilder {
|
||||
let builder = SMKProtoSenderCertificateCertificateBuilder(sender: sender, senderDevice: senderDevice, expires: expires, identityKey: identityKey, signer: signer)
|
||||
return builder
|
||||
}
|
||||
|
||||
@objc public class SMKProtoSenderCertificateCertificateBuilder: NSObject {
|
||||
|
||||
private var proto = SMKProtos_SenderCertificate.Certificate()
|
||||
|
||||
@objc fileprivate override init() {}
|
||||
|
||||
@objc fileprivate init(sender: String, senderDevice: UInt32, expires: UInt64, identityKey: Data, signer: SMKProtoServerCertificate) {
|
||||
super.init()
|
||||
|
||||
setSender(sender)
|
||||
setSenderDevice(senderDevice)
|
||||
setExpires(expires)
|
||||
setIdentityKey(identityKey)
|
||||
setSigner(signer)
|
||||
}
|
||||
|
||||
@objc public func setSender(_ valueParam: String) {
|
||||
proto.sender = valueParam
|
||||
}
|
||||
|
||||
@objc public func setSenderDevice(_ valueParam: UInt32) {
|
||||
proto.senderDevice = valueParam
|
||||
}
|
||||
|
||||
@objc public func setExpires(_ valueParam: UInt64) {
|
||||
proto.expires = valueParam
|
||||
}
|
||||
|
||||
@objc public func setIdentityKey(_ valueParam: Data) {
|
||||
proto.identityKey = valueParam
|
||||
}
|
||||
|
||||
@objc public func setSigner(_ valueParam: SMKProtoServerCertificate) {
|
||||
proto.signer = valueParam.proto
|
||||
}
|
||||
|
||||
@objc public func build() throws -> SMKProtoSenderCertificateCertificate {
|
||||
return try SMKProtoSenderCertificateCertificate.parseProto(proto)
|
||||
}
|
||||
|
||||
@objc public func buildSerializedData() throws -> Data {
|
||||
return try SMKProtoSenderCertificateCertificate.parseProto(proto).serializedData()
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate let proto: SMKProtos_SenderCertificate.Certificate
|
||||
|
||||
@objc public let sender: String
|
||||
|
||||
@objc public let senderDevice: UInt32
|
||||
|
||||
@objc public let expires: UInt64
|
||||
|
||||
@objc public let identityKey: Data
|
||||
|
||||
@objc public let signer: SMKProtoServerCertificate
|
||||
|
||||
private init(proto: SMKProtos_SenderCertificate.Certificate,
|
||||
sender: String,
|
||||
senderDevice: UInt32,
|
||||
expires: UInt64,
|
||||
identityKey: Data,
|
||||
signer: SMKProtoServerCertificate) {
|
||||
self.proto = proto
|
||||
self.sender = sender
|
||||
self.senderDevice = senderDevice
|
||||
self.expires = expires
|
||||
self.identityKey = identityKey
|
||||
self.signer = signer
|
||||
}
|
||||
|
||||
@objc
|
||||
public func serializedData() throws -> Data {
|
||||
return try self.proto.serializedData()
|
||||
}
|
||||
|
||||
@objc public class func parseData(_ serializedData: Data) throws -> SMKProtoSenderCertificateCertificate {
|
||||
let proto = try SMKProtos_SenderCertificate.Certificate(serializedData: serializedData)
|
||||
return try parseProto(proto)
|
||||
}
|
||||
|
||||
fileprivate class func parseProto(_ proto: SMKProtos_SenderCertificate.Certificate) throws -> SMKProtoSenderCertificateCertificate {
|
||||
guard proto.hasSender else {
|
||||
throw SMKProtoError.invalidProtobuf(description: "\(logTag) missing required field: sender")
|
||||
}
|
||||
let sender = proto.sender
|
||||
|
||||
guard proto.hasSenderDevice else {
|
||||
throw SMKProtoError.invalidProtobuf(description: "\(logTag) missing required field: senderDevice")
|
||||
}
|
||||
let senderDevice = proto.senderDevice
|
||||
|
||||
guard proto.hasExpires else {
|
||||
throw SMKProtoError.invalidProtobuf(description: "\(logTag) missing required field: expires")
|
||||
}
|
||||
let expires = proto.expires
|
||||
|
||||
guard proto.hasIdentityKey else {
|
||||
throw SMKProtoError.invalidProtobuf(description: "\(logTag) missing required field: identityKey")
|
||||
}
|
||||
let identityKey = proto.identityKey
|
||||
|
||||
guard proto.hasSigner else {
|
||||
throw SMKProtoError.invalidProtobuf(description: "\(logTag) missing required field: signer")
|
||||
}
|
||||
let signer = try SMKProtoServerCertificate.parseProto(proto.signer)
|
||||
|
||||
// MARK: - Begin Validation Logic for SMKProtoSenderCertificateCertificate -
|
||||
|
||||
// MARK: - End Validation Logic for SMKProtoSenderCertificateCertificate -
|
||||
|
||||
let result = SMKProtoSenderCertificateCertificate(proto: proto,
|
||||
sender: sender,
|
||||
senderDevice: senderDevice,
|
||||
expires: expires,
|
||||
identityKey: identityKey,
|
||||
signer: signer)
|
||||
return result
|
||||
}
|
||||
|
||||
@objc public override var debugDescription: String {
|
||||
return "\(proto)"
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
|
||||
extension SMKProtoSenderCertificateCertificate {
|
||||
@objc public func serializedDataIgnoringErrors() -> Data? {
|
||||
return try! self.serializedData()
|
||||
}
|
||||
}
|
||||
|
||||
extension SMKProtoSenderCertificateCertificate.SMKProtoSenderCertificateCertificateBuilder {
|
||||
@objc public func buildIgnoringErrors() -> SMKProtoSenderCertificateCertificate? {
|
||||
return try! self.build()
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// MARK: - SMKProtoSenderCertificate
|
||||
|
||||
@objc public class SMKProtoSenderCertificate: NSObject {
|
||||
|
||||
// MARK: - SMKProtoSenderCertificateBuilder
|
||||
|
||||
@objc public class func builder(sender: String, senderDevice: UInt32) -> SMKProtoSenderCertificateBuilder {
|
||||
return SMKProtoSenderCertificateBuilder(sender: sender, senderDevice: senderDevice)
|
||||
}
|
||||
|
||||
// asBuilder() constructs a builder that reflects the proto's contents.
|
||||
@objc public func asBuilder() -> SMKProtoSenderCertificateBuilder {
|
||||
let builder = SMKProtoSenderCertificateBuilder(sender: sender, senderDevice: senderDevice)
|
||||
return builder
|
||||
}
|
||||
|
||||
@objc public class SMKProtoSenderCertificateBuilder: NSObject {
|
||||
|
||||
private var proto = SMKProtos_SenderCertificate()
|
||||
|
||||
@objc fileprivate override init() {}
|
||||
|
||||
@objc fileprivate init(sender: String, senderDevice: UInt32) {
|
||||
super.init()
|
||||
|
||||
setSender(sender)
|
||||
setSenderDevice(senderDevice)
|
||||
}
|
||||
|
||||
@objc public func setSender(_ valueParam: String) {
|
||||
proto.sender = valueParam
|
||||
}
|
||||
|
||||
@objc public func setSenderDevice(_ valueParam: UInt32) {
|
||||
proto.senderDevice = valueParam
|
||||
}
|
||||
|
||||
@objc public func build() throws -> SMKProtoSenderCertificate {
|
||||
return try SMKProtoSenderCertificate.parseProto(proto)
|
||||
}
|
||||
|
||||
@objc public func buildSerializedData() throws -> Data {
|
||||
return try SMKProtoSenderCertificate.parseProto(proto).serializedData()
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate let proto: SMKProtos_SenderCertificate
|
||||
|
||||
@objc public let sender: String
|
||||
|
||||
@objc public let senderDevice: UInt32
|
||||
|
||||
private init(proto: SMKProtos_SenderCertificate,
|
||||
sender: String,
|
||||
senderDevice: UInt32) {
|
||||
self.proto = proto
|
||||
self.sender = sender
|
||||
self.senderDevice = senderDevice
|
||||
}
|
||||
|
||||
@objc
|
||||
public func serializedData() throws -> Data {
|
||||
return try self.proto.serializedData()
|
||||
}
|
||||
|
||||
@objc public class func parseData(_ serializedData: Data) throws -> SMKProtoSenderCertificate {
|
||||
let proto = try SMKProtos_SenderCertificate(serializedData: serializedData)
|
||||
return try parseProto(proto)
|
||||
}
|
||||
|
||||
fileprivate class func parseProto(_ proto: SMKProtos_SenderCertificate) throws -> SMKProtoSenderCertificate {
|
||||
guard proto.hasSender else {
|
||||
throw SMKProtoError.invalidProtobuf(description: "\(logTag) missing required field: sender")
|
||||
}
|
||||
let sender = proto.sender
|
||||
|
||||
guard proto.hasSenderDevice else {
|
||||
throw SMKProtoError.invalidProtobuf(description: "\(logTag) missing required field: senderDevice")
|
||||
}
|
||||
let senderDevice = proto.senderDevice
|
||||
|
||||
// MARK: - Begin Validation Logic for SMKProtoSenderCertificate -
|
||||
|
||||
// MARK: - End Validation Logic for SMKProtoSenderCertificate -
|
||||
|
||||
let result = SMKProtoSenderCertificate(proto: proto,
|
||||
sender: sender,
|
||||
senderDevice: senderDevice)
|
||||
return result
|
||||
}
|
||||
|
||||
@objc public override var debugDescription: String {
|
||||
return "\(proto)"
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
|
||||
extension SMKProtoSenderCertificate {
|
||||
@objc public func serializedDataIgnoringErrors() -> Data? {
|
||||
return try! self.serializedData()
|
||||
}
|
||||
}
|
||||
|
||||
extension SMKProtoSenderCertificate.SMKProtoSenderCertificateBuilder {
|
||||
@objc public func buildIgnoringErrors() -> SMKProtoSenderCertificate? {
|
||||
return try! self.build()
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// MARK: - SMKProtoUnidentifiedSenderMessageMessage
|
||||
|
||||
@objc public class SMKProtoUnidentifiedSenderMessageMessage: NSObject {
|
||||
|
||||
// MARK: - SMKProtoUnidentifiedSenderMessageMessageType
|
||||
|
||||
@objc public enum SMKProtoUnidentifiedSenderMessageMessageType: Int32 {
|
||||
case prekeyMessage = 1
|
||||
case message = 2
|
||||
case fallbackMessage = 3
|
||||
}
|
||||
|
||||
private class func SMKProtoUnidentifiedSenderMessageMessageTypeWrap(_ value: SMKProtos_UnidentifiedSenderMessage.Message.TypeEnum) -> SMKProtoUnidentifiedSenderMessageMessageType {
|
||||
switch value {
|
||||
case .prekeyMessage: return .prekeyMessage
|
||||
case .message: return .message
|
||||
case .fallbackMessage: return .fallbackMessage
|
||||
}
|
||||
}
|
||||
|
||||
private class func SMKProtoUnidentifiedSenderMessageMessageTypeUnwrap(_ value: SMKProtoUnidentifiedSenderMessageMessageType) -> SMKProtos_UnidentifiedSenderMessage.Message.TypeEnum {
|
||||
switch value {
|
||||
case .prekeyMessage: return .prekeyMessage
|
||||
case .message: return .message
|
||||
case .fallbackMessage: return .fallbackMessage
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - SMKProtoUnidentifiedSenderMessageMessageBuilder
|
||||
|
||||
@objc public class func builder(type: SMKProtoUnidentifiedSenderMessageMessageType, senderCertificate: SMKProtoSenderCertificate, content: Data) -> SMKProtoUnidentifiedSenderMessageMessageBuilder {
|
||||
return SMKProtoUnidentifiedSenderMessageMessageBuilder(type: type, senderCertificate: senderCertificate, content: content)
|
||||
}
|
||||
|
||||
// asBuilder() constructs a builder that reflects the proto's contents.
|
||||
@objc public func asBuilder() -> SMKProtoUnidentifiedSenderMessageMessageBuilder {
|
||||
let builder = SMKProtoUnidentifiedSenderMessageMessageBuilder(type: type, senderCertificate: senderCertificate, content: content)
|
||||
return builder
|
||||
}
|
||||
|
||||
@objc public class SMKProtoUnidentifiedSenderMessageMessageBuilder: NSObject {
|
||||
|
||||
private var proto = SMKProtos_UnidentifiedSenderMessage.Message()
|
||||
|
||||
@objc fileprivate override init() {}
|
||||
|
||||
@objc fileprivate init(type: SMKProtoUnidentifiedSenderMessageMessageType, senderCertificate: SMKProtoSenderCertificate, content: Data) {
|
||||
super.init()
|
||||
|
||||
setType(type)
|
||||
setSenderCertificate(senderCertificate)
|
||||
setContent(content)
|
||||
}
|
||||
|
||||
@objc public func setType(_ valueParam: SMKProtoUnidentifiedSenderMessageMessageType) {
|
||||
proto.type = SMKProtoUnidentifiedSenderMessageMessageTypeUnwrap(valueParam)
|
||||
}
|
||||
|
||||
@objc public func setSenderCertificate(_ valueParam: SMKProtoSenderCertificate) {
|
||||
proto.senderCertificate = valueParam.proto
|
||||
}
|
||||
|
||||
@objc public func setContent(_ valueParam: Data) {
|
||||
proto.content = valueParam
|
||||
}
|
||||
|
||||
@objc public func build() throws -> SMKProtoUnidentifiedSenderMessageMessage {
|
||||
return try SMKProtoUnidentifiedSenderMessageMessage.parseProto(proto)
|
||||
}
|
||||
|
||||
@objc public func buildSerializedData() throws -> Data {
|
||||
return try SMKProtoUnidentifiedSenderMessageMessage.parseProto(proto).serializedData()
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate let proto: SMKProtos_UnidentifiedSenderMessage.Message
|
||||
|
||||
@objc public let type: SMKProtoUnidentifiedSenderMessageMessageType
|
||||
|
||||
@objc public let senderCertificate: SMKProtoSenderCertificate
|
||||
|
||||
@objc public let content: Data
|
||||
|
||||
private init(proto: SMKProtos_UnidentifiedSenderMessage.Message,
|
||||
type: SMKProtoUnidentifiedSenderMessageMessageType,
|
||||
senderCertificate: SMKProtoSenderCertificate,
|
||||
content: Data) {
|
||||
self.proto = proto
|
||||
self.type = type
|
||||
self.senderCertificate = senderCertificate
|
||||
self.content = content
|
||||
}
|
||||
|
||||
@objc
|
||||
public func serializedData() throws -> Data {
|
||||
return try self.proto.serializedData()
|
||||
}
|
||||
|
||||
@objc public class func parseData(_ serializedData: Data) throws -> SMKProtoUnidentifiedSenderMessageMessage {
|
||||
let proto = try SMKProtos_UnidentifiedSenderMessage.Message(serializedData: serializedData)
|
||||
return try parseProto(proto)
|
||||
}
|
||||
|
||||
fileprivate class func parseProto(_ proto: SMKProtos_UnidentifiedSenderMessage.Message) throws -> SMKProtoUnidentifiedSenderMessageMessage {
|
||||
guard proto.hasType else {
|
||||
throw SMKProtoError.invalidProtobuf(description: "\(logTag) missing required field: type")
|
||||
}
|
||||
let type = SMKProtoUnidentifiedSenderMessageMessageTypeWrap(proto.type)
|
||||
|
||||
guard proto.hasSenderCertificate else {
|
||||
throw SMKProtoError.invalidProtobuf(description: "\(logTag) missing required field: senderCertificate")
|
||||
}
|
||||
let senderCertificate = try SMKProtoSenderCertificate.parseProto(proto.senderCertificate)
|
||||
|
||||
guard proto.hasContent else {
|
||||
throw SMKProtoError.invalidProtobuf(description: "\(logTag) missing required field: content")
|
||||
}
|
||||
let content = proto.content
|
||||
|
||||
// MARK: - Begin Validation Logic for SMKProtoUnidentifiedSenderMessageMessage -
|
||||
|
||||
// MARK: - End Validation Logic for SMKProtoUnidentifiedSenderMessageMessage -
|
||||
|
||||
let result = SMKProtoUnidentifiedSenderMessageMessage(proto: proto,
|
||||
type: type,
|
||||
senderCertificate: senderCertificate,
|
||||
content: content)
|
||||
return result
|
||||
}
|
||||
|
||||
@objc public override var debugDescription: String {
|
||||
return "\(proto)"
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
|
||||
extension SMKProtoUnidentifiedSenderMessageMessage {
|
||||
@objc public func serializedDataIgnoringErrors() -> Data? {
|
||||
return try! self.serializedData()
|
||||
}
|
||||
}
|
||||
|
||||
extension SMKProtoUnidentifiedSenderMessageMessage.SMKProtoUnidentifiedSenderMessageMessageBuilder {
|
||||
@objc public func buildIgnoringErrors() -> SMKProtoUnidentifiedSenderMessageMessage? {
|
||||
return try! self.build()
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// MARK: - SMKProtoUnidentifiedSenderMessage
|
||||
|
||||
@objc public class SMKProtoUnidentifiedSenderMessage: NSObject {
|
||||
|
||||
// MARK: - SMKProtoUnidentifiedSenderMessageBuilder
|
||||
|
||||
@objc public class func builder(ephemeralPublic: Data, encryptedStatic: Data, encryptedMessage: Data) -> SMKProtoUnidentifiedSenderMessageBuilder {
|
||||
return SMKProtoUnidentifiedSenderMessageBuilder(ephemeralPublic: ephemeralPublic, encryptedStatic: encryptedStatic, encryptedMessage: encryptedMessage)
|
||||
}
|
||||
|
||||
// asBuilder() constructs a builder that reflects the proto's contents.
|
||||
@objc public func asBuilder() -> SMKProtoUnidentifiedSenderMessageBuilder {
|
||||
let builder = SMKProtoUnidentifiedSenderMessageBuilder(ephemeralPublic: ephemeralPublic, encryptedStatic: encryptedStatic, encryptedMessage: encryptedMessage)
|
||||
return builder
|
||||
}
|
||||
|
||||
@objc public class SMKProtoUnidentifiedSenderMessageBuilder: NSObject {
|
||||
|
||||
private var proto = SMKProtos_UnidentifiedSenderMessage()
|
||||
|
||||
@objc fileprivate override init() {}
|
||||
|
||||
@objc fileprivate init(ephemeralPublic: Data, encryptedStatic: Data, encryptedMessage: Data) {
|
||||
super.init()
|
||||
|
||||
setEphemeralPublic(ephemeralPublic)
|
||||
setEncryptedStatic(encryptedStatic)
|
||||
setEncryptedMessage(encryptedMessage)
|
||||
}
|
||||
|
||||
@objc public func setEphemeralPublic(_ valueParam: Data) {
|
||||
proto.ephemeralPublic = valueParam
|
||||
}
|
||||
|
||||
@objc public func setEncryptedStatic(_ valueParam: Data) {
|
||||
proto.encryptedStatic = valueParam
|
||||
}
|
||||
|
||||
@objc public func setEncryptedMessage(_ valueParam: Data) {
|
||||
proto.encryptedMessage = valueParam
|
||||
}
|
||||
|
||||
@objc public func build() throws -> SMKProtoUnidentifiedSenderMessage {
|
||||
return try SMKProtoUnidentifiedSenderMessage.parseProto(proto)
|
||||
}
|
||||
|
||||
@objc public func buildSerializedData() throws -> Data {
|
||||
return try SMKProtoUnidentifiedSenderMessage.parseProto(proto).serializedData()
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate let proto: SMKProtos_UnidentifiedSenderMessage
|
||||
|
||||
@objc public let ephemeralPublic: Data
|
||||
|
||||
@objc public let encryptedStatic: Data
|
||||
|
||||
@objc public let encryptedMessage: Data
|
||||
|
||||
private init(proto: SMKProtos_UnidentifiedSenderMessage,
|
||||
ephemeralPublic: Data,
|
||||
encryptedStatic: Data,
|
||||
encryptedMessage: Data) {
|
||||
self.proto = proto
|
||||
self.ephemeralPublic = ephemeralPublic
|
||||
self.encryptedStatic = encryptedStatic
|
||||
self.encryptedMessage = encryptedMessage
|
||||
}
|
||||
|
||||
@objc
|
||||
public func serializedData() throws -> Data {
|
||||
return try self.proto.serializedData()
|
||||
}
|
||||
|
||||
@objc public class func parseData(_ serializedData: Data) throws -> SMKProtoUnidentifiedSenderMessage {
|
||||
let proto = try SMKProtos_UnidentifiedSenderMessage(serializedData: serializedData)
|
||||
return try parseProto(proto)
|
||||
}
|
||||
|
||||
fileprivate class func parseProto(_ proto: SMKProtos_UnidentifiedSenderMessage) throws -> SMKProtoUnidentifiedSenderMessage {
|
||||
guard proto.hasEphemeralPublic else {
|
||||
throw SMKProtoError.invalidProtobuf(description: "\(logTag) missing required field: ephemeralPublic")
|
||||
}
|
||||
let ephemeralPublic = proto.ephemeralPublic
|
||||
|
||||
guard proto.hasEncryptedStatic else {
|
||||
throw SMKProtoError.invalidProtobuf(description: "\(logTag) missing required field: encryptedStatic")
|
||||
}
|
||||
let encryptedStatic = proto.encryptedStatic
|
||||
|
||||
guard proto.hasEncryptedMessage else {
|
||||
throw SMKProtoError.invalidProtobuf(description: "\(logTag) missing required field: encryptedMessage")
|
||||
}
|
||||
let encryptedMessage = proto.encryptedMessage
|
||||
|
||||
// MARK: - Begin Validation Logic for SMKProtoUnidentifiedSenderMessage -
|
||||
|
||||
// MARK: - End Validation Logic for SMKProtoUnidentifiedSenderMessage -
|
||||
|
||||
let result = SMKProtoUnidentifiedSenderMessage(proto: proto,
|
||||
ephemeralPublic: ephemeralPublic,
|
||||
encryptedStatic: encryptedStatic,
|
||||
encryptedMessage: encryptedMessage)
|
||||
return result
|
||||
}
|
||||
|
||||
@objc public override var debugDescription: String {
|
||||
return "\(proto)"
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
|
||||
extension SMKProtoUnidentifiedSenderMessage {
|
||||
@objc public func serializedDataIgnoringErrors() -> Data? {
|
||||
return try! self.serializedData()
|
||||
}
|
||||
}
|
||||
|
||||
extension SMKProtoUnidentifiedSenderMessage.SMKProtoUnidentifiedSenderMessageBuilder {
|
||||
@objc public func buildIgnoringErrors() -> SMKProtoUnidentifiedSenderMessage? {
|
||||
return try! self.build()
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,106 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public enum SMKCertificateError: Error {
|
||||
case invalidCertificate(description: String)
|
||||
}
|
||||
|
||||
@objc public protocol SMKCertificateValidator: class {
|
||||
|
||||
@objc func throwswrapped_validate(senderCertificate: SMKSenderCertificate, validationTime: UInt64) throws
|
||||
|
||||
@objc func throwswrapped_validate(serverCertificate: SMKServerCertificate) throws
|
||||
}
|
||||
|
||||
// See: https://github.com/signalapp/libsignal-metadata-java/blob/master/java/src/main/java/org/signal/libsignal/metadata/certificate/CertificateValidator.java
|
||||
//public class CertificateValidator {
|
||||
@objc public class SMKCertificateDefaultValidator: NSObject, SMKCertificateValidator {
|
||||
|
||||
// @SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
|
||||
// private static final Set<Integer> REVOKED = new HashSet<Integer>() {{
|
||||
//
|
||||
// }};
|
||||
private static let kRevokedCertificateIds = Set<UInt32>()
|
||||
|
||||
//
|
||||
// private final ECPublicKey trustRoot;
|
||||
private let trustRoot: ECPublicKey
|
||||
|
||||
// public CertificateValidator(ECPublicKey trustRoot) {
|
||||
// this.trustRoot = trustRoot;
|
||||
// }
|
||||
@objc public init(trustRoot: ECPublicKey ) {
|
||||
self.trustRoot = trustRoot
|
||||
}
|
||||
|
||||
// public void validate(SenderCertificate certificate, long validationTime) throws InvalidCertificateException {
|
||||
@objc public func throwswrapped_validate(senderCertificate: SMKSenderCertificate, validationTime: UInt64) throws {
|
||||
// try {
|
||||
// ServerCertificate serverCertificate = certificate.getSigner();
|
||||
// let serverCertificate = senderCertificate.signer
|
||||
|
||||
// validate(serverCertificate);
|
||||
// try throwswrapped_validate(serverCertificate: serverCertificate)
|
||||
|
||||
// if (!Curve.verifySignature(serverCertificate.getKey(), certificate.getCertificate(), certificate.getSignature())) {
|
||||
// throw new InvalidCertificateException("Signature failed");
|
||||
// }
|
||||
// let certificateData = try senderCertificate.toProto().certificate
|
||||
// guard try Ed25519.verifySignature(senderCertificate.signatureData,
|
||||
// publicKey: serverCertificate.key.keyData,
|
||||
// data: certificateData) else {
|
||||
// Logger.error("Sender certificate signature verification failed.")
|
||||
// let error = SMKCertificateError.invalidCertificate(description: "Sender certificate signature verification failed.")
|
||||
// Logger.error("\(error)")
|
||||
// throw error
|
||||
// }
|
||||
|
||||
// if (validationTime > certificate.getExpiration()) {
|
||||
// throw new InvalidCertificateException("Certificate is expired");
|
||||
// }
|
||||
// guard validationTime <= senderCertificate.expirationTimestamp else {
|
||||
// let error = SMKCertificateError.invalidCertificate(description: "Certficate is expired.")
|
||||
// Logger.error("\(error)")
|
||||
// throw error
|
||||
// }
|
||||
|
||||
// } catch (InvalidKeyException e) {
|
||||
// throw new InvalidCertificateException(e);
|
||||
// }
|
||||
}
|
||||
|
||||
// // VisibleForTesting
|
||||
// void validate(ServerCertificate certificate) throws InvalidCertificateException {
|
||||
@objc public func throwswrapped_validate(serverCertificate: SMKServerCertificate) throws {
|
||||
// try {
|
||||
// if (!Curve.verifySignature(trustRoot, certificate.getCertificate(), certificate.getSignature())) {
|
||||
// throw new InvalidCertificateException("Signature failed");
|
||||
// }
|
||||
let certificateBuilder = SMKProtoServerCertificateCertificate.builder(id: serverCertificate.keyId,
|
||||
key: serverCertificate.key.serialized)
|
||||
let certificateData = try certificateBuilder.build().serializedData()
|
||||
|
||||
// let certificateData = try serverCertificate.toProto().certificate
|
||||
guard try Ed25519.verifySignature(serverCertificate.signatureData,
|
||||
publicKey: trustRoot.keyData,
|
||||
data: certificateData) else {
|
||||
let error = SMKCertificateError.invalidCertificate(description: "Server certificate signature verification failed.")
|
||||
Logger.error("\(error)")
|
||||
throw error
|
||||
}
|
||||
// if (REVOKED.contains(certificate.getKeyId())) {
|
||||
// throw new InvalidCertificateException("Server certificate has been revoked");
|
||||
// }
|
||||
guard !SMKCertificateDefaultValidator.kRevokedCertificateIds.contains(serverCertificate.keyId) else {
|
||||
let error = SMKCertificateError.invalidCertificate(description: "Revoked certificate.")
|
||||
Logger.error("\(error)")
|
||||
throw error
|
||||
}
|
||||
// } catch (InvalidKeyException e) {
|
||||
// throw new InvalidCertificateException(e);
|
||||
// }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public enum SMKError: Error {
|
||||
case assertionError(description: String)
|
||||
}
|
|
@ -0,0 +1,590 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import HKDFKit
|
||||
|
||||
@objc
|
||||
public class SecretSessionKnownSenderError: NSObject, CustomNSError {
|
||||
|
||||
@objc
|
||||
public static let kSenderRecipientIdKey = "kSenderRecipientIdKey"
|
||||
|
||||
@objc
|
||||
public static let kSenderDeviceIdKey = "kSenderDeviceIdKey"
|
||||
|
||||
public let senderRecipientId: String
|
||||
public let senderDeviceId: UInt32
|
||||
public let underlyingError: Error
|
||||
|
||||
init(senderRecipientId: String, senderDeviceId: UInt32, underlyingError: Error) {
|
||||
self.senderRecipientId = senderRecipientId
|
||||
self.senderDeviceId = senderDeviceId
|
||||
self.underlyingError = underlyingError
|
||||
}
|
||||
|
||||
public var errorUserInfo: [String: Any] {
|
||||
return [
|
||||
type(of: self).kSenderRecipientIdKey: self.senderRecipientId,
|
||||
type(of: self).kSenderDeviceIdKey: self.senderDeviceId,
|
||||
NSUnderlyingErrorKey: (underlyingError as NSError)
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@objc
|
||||
public enum SMKSecretSessionCipherError: Int, Error {
|
||||
case selfSentMessage
|
||||
}
|
||||
|
||||
// See:
|
||||
// https://github.com/signalapp/libsignal-metadata-java/blob/master/java/src/main/java/org/signal/libsignal/metadata/SecretSessionCipher.java
|
||||
|
||||
public extension ECKeyPair {
|
||||
|
||||
// TODO: Rename to publicKey(), rename existing publicKey() method to publicKeyData().
|
||||
func ecPublicKey() throws -> ECPublicKey {
|
||||
guard publicKey().count == ECCKeyLength else {
|
||||
throw SMKError.assertionError(description: "\(logTag) public key has invalid length")
|
||||
}
|
||||
|
||||
// NOTE: we don't use ECPublicKey(serializedKeyData:) since the
|
||||
// key data should not have a type byte.
|
||||
return try ECPublicKey(keyData: publicKey())
|
||||
}
|
||||
|
||||
// TODO: Rename to privateKey(), rename existing privateKey() method to privateKeyData().
|
||||
func ecPrivateKey() throws -> ECPrivateKey {
|
||||
guard privateKey().count == ECCKeyLength else {
|
||||
throw SMKError.assertionError(description: "\(logTag) private key has invalid length")
|
||||
}
|
||||
|
||||
return try ECPrivateKey(keyData: privateKey())
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
private class SMKSecretKeySpec: NSObject {
|
||||
|
||||
@objc public let keyData: Data
|
||||
@objc public let algorithm: String
|
||||
|
||||
init(keyData: Data, algorithm: String) {
|
||||
self.keyData = keyData
|
||||
self.algorithm = algorithm
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
private class SMKEphemeralKeys: NSObject {
|
||||
|
||||
@objc public let chainKey: Data
|
||||
@objc public let cipherKey: SMKSecretKeySpec
|
||||
@objc public let macKey: SMKSecretKeySpec
|
||||
|
||||
init(chainKey: Data, cipherKey: Data, macKey: Data) {
|
||||
self.chainKey = chainKey
|
||||
self.cipherKey = SMKSecretKeySpec(keyData: cipherKey, algorithm: "AES")
|
||||
self.macKey = SMKSecretKeySpec(keyData: macKey, algorithm: "HmacSHA256")
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
private class SMKStaticKeys: NSObject {
|
||||
|
||||
@objc public let cipherKey: SMKSecretKeySpec
|
||||
@objc public let macKey: SMKSecretKeySpec
|
||||
|
||||
init(cipherKey: Data, macKey: Data) {
|
||||
self.cipherKey = SMKSecretKeySpec(keyData: cipherKey, algorithm: "AES")
|
||||
self.macKey = SMKSecretKeySpec(keyData: macKey, algorithm: "HmacSHA256")
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
@objc
|
||||
public class SMKDecryptResult: NSObject {
|
||||
|
||||
@objc public let senderRecipientId: String
|
||||
@objc public let senderDeviceId: Int
|
||||
@objc public let paddedPayload: Data
|
||||
@objc public let messageType: SMKMessageType
|
||||
|
||||
init(senderRecipientId: String,
|
||||
senderDeviceId: Int,
|
||||
paddedPayload: Data,
|
||||
messageType: SMKMessageType) {
|
||||
self.senderRecipientId = senderRecipientId
|
||||
self.senderDeviceId = senderDeviceId
|
||||
self.paddedPayload = paddedPayload
|
||||
self.messageType = messageType
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
@objc public class SMKSecretSessionCipher: NSObject {
|
||||
|
||||
private let kUDPrefixString = "UnidentifiedDelivery"
|
||||
|
||||
private let kSMKSecretSessionCipherMacLength: UInt = 10
|
||||
|
||||
private let sessionResetImplementation: SessionRestorationProtocol!
|
||||
private let sessionStore: SessionStore
|
||||
private let preKeyStore: PreKeyStore
|
||||
private let signedPreKeyStore: SignedPreKeyStore
|
||||
private let identityStore: IdentityKeyStore
|
||||
|
||||
@objc public init(sessionResetImplementation: SessionRestorationProtocol!,
|
||||
sessionStore: SessionStore,
|
||||
preKeyStore: PreKeyStore,
|
||||
signedPreKeyStore: SignedPreKeyStore,
|
||||
identityStore: IdentityKeyStore) throws {
|
||||
self.sessionResetImplementation = sessionResetImplementation
|
||||
self.sessionStore = sessionStore
|
||||
self.preKeyStore = preKeyStore
|
||||
self.signedPreKeyStore = signedPreKeyStore
|
||||
self.identityStore = identityStore
|
||||
}
|
||||
|
||||
@objc public convenience init(sessionStore: SessionStore,
|
||||
preKeyStore: PreKeyStore,
|
||||
signedPreKeyStore: SignedPreKeyStore,
|
||||
identityStore: IdentityKeyStore) throws {
|
||||
try self.init(sessionResetImplementation: nil, sessionStore: sessionStore, preKeyStore: preKeyStore, signedPreKeyStore: signedPreKeyStore, identityStore: identityStore)
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
@objc
|
||||
public func throwswrapped_encryptMessage(recipientPublicKey: String,
|
||||
deviceID: Int32,
|
||||
paddedPlaintext: Data,
|
||||
senderCertificate: SMKSenderCertificate,
|
||||
protocolContext: Any,
|
||||
useFallbackSessionCipher: Bool) throws -> Data {
|
||||
guard recipientPublicKey.count > 0 else {
|
||||
throw SMKError.assertionError(description: "\(SMKSecretSessionCipher.logTag) invalid recipientId")
|
||||
}
|
||||
|
||||
guard deviceID > 0 else {
|
||||
throw SMKError.assertionError(description: "\(SMKSecretSessionCipher.logTag) invalid deviceId")
|
||||
}
|
||||
|
||||
guard let ourIdentityKeyPair = identityStore.identityKeyPair(protocolContext) else {
|
||||
throw SMKError.assertionError(description: "\(logTag) Missing our identity key pair.")
|
||||
}
|
||||
|
||||
let encryptedMessage: CipherMessage
|
||||
if useFallbackSessionCipher {
|
||||
let cipher = FallBackSessionCipher(recipientPublicKey: recipientPublicKey, privateKey: try ourIdentityKeyPair.privateKey())
|
||||
let ivAndCiphertext = cipher.encrypt(paddedPlaintext)!
|
||||
encryptedMessage = FallbackMessage(_throws_with: ivAndCiphertext)
|
||||
} else {
|
||||
let cipher = SessionCipher(sessionStore: sessionStore,
|
||||
preKeyStore: preKeyStore,
|
||||
signedPreKeyStore: signedPreKeyStore,
|
||||
identityKeyStore: identityStore,
|
||||
recipientId: recipientPublicKey,
|
||||
deviceId: deviceID)
|
||||
encryptedMessage = try cipher.encryptMessage(paddedPlaintext, protocolContext: protocolContext)
|
||||
}
|
||||
|
||||
guard let encryptedMessageData = encryptedMessage.serialized() else {
|
||||
throw SMKError.assertionError(description: "\(logTag) Could not serialize encrypted message.")
|
||||
}
|
||||
|
||||
guard let theirIdentityKeyData = Data.data(fromHex: recipientPublicKey.substring(from: recipientPublicKey.index(recipientPublicKey.startIndex, offsetBy: 2))) else {
|
||||
throw SMKError.assertionError(description: "\(logTag) Missing their public identity key.")
|
||||
}
|
||||
|
||||
// NOTE: we don't use ECPublicKey(serializedKeyData) since the
|
||||
// key data should not have a type byte.
|
||||
let theirIdentityKey = try ECPublicKey(keyData: theirIdentityKeyData)
|
||||
|
||||
let ephemeral = Curve25519.generateKeyPair()!
|
||||
|
||||
guard let prefixData = kUDPrefixString.data(using: String.Encoding.utf8) else {
|
||||
throw SMKError.assertionError(description: "\(logTag) Could not encode prefix.")
|
||||
}
|
||||
|
||||
let ephemeralSalt = NSData.join([
|
||||
prefixData,
|
||||
theirIdentityKey.serialized,
|
||||
try ephemeral.ecPublicKey().serialized
|
||||
])
|
||||
|
||||
let ephemeralKeys = try throwswrapped_calculateEphemeralKeys(ephemeralPublicKey: theirIdentityKey,
|
||||
ephemeralPrivateKey: ephemeral.ecPrivateKey(),
|
||||
salt: ephemeralSalt)
|
||||
|
||||
let staticKeyCipherData = try encrypt(cipherKey: ephemeralKeys.cipherKey,
|
||||
macKey: ephemeralKeys.macKey,
|
||||
plaintextData: ourIdentityKeyPair.ecPublicKey().serialized)
|
||||
|
||||
let staticSalt = NSData.join([
|
||||
ephemeralKeys.chainKey,
|
||||
staticKeyCipherData
|
||||
])
|
||||
|
||||
let staticKeys = try throwswrapped_calculateStaticKeys(staticPublicKey: theirIdentityKey,
|
||||
staticPrivateKey: ourIdentityKeyPair.ecPrivateKey(),
|
||||
salt: staticSalt)
|
||||
|
||||
let messageType: SMKMessageType
|
||||
switch encryptedMessage.cipherMessageType {
|
||||
case .prekey:
|
||||
messageType = .prekey
|
||||
case .whisper:
|
||||
messageType = .whisper
|
||||
case .fallback:
|
||||
messageType = .fallback
|
||||
default:
|
||||
throw SMKError.assertionError(description: "\(logTag) Unknown cipher message type.")
|
||||
}
|
||||
|
||||
let messageContent = SMKUnidentifiedSenderMessageContent(messageType: messageType,
|
||||
senderCertificate: senderCertificate,
|
||||
contentData: encryptedMessageData)
|
||||
|
||||
let messageData = try encrypt(cipherKey: staticKeys.cipherKey,
|
||||
macKey: staticKeys.macKey,
|
||||
plaintextData: try messageContent.serialized())
|
||||
|
||||
let message = SMKUnidentifiedSenderMessage(ephemeralKey: try ephemeral.ecPublicKey(),
|
||||
encryptedStatic: staticKeyCipherData,
|
||||
encryptedMessage: messageData)
|
||||
|
||||
return try message.serialized()
|
||||
}
|
||||
|
||||
@objc
|
||||
public func throwswrapped_decryptMessage(certificateValidator: SMKCertificateValidator,
|
||||
cipherTextData: Data,
|
||||
timestamp: UInt64,
|
||||
localRecipientId: String,
|
||||
localDeviceId: Int32,
|
||||
protocolContext: Any) throws -> SMKDecryptResult {
|
||||
guard timestamp > 0 else {
|
||||
throw SMKError.assertionError(description: "\(logTag) invalid timestamp")
|
||||
}
|
||||
|
||||
guard let ourIdentityKeyPair = identityStore.identityKeyPair(protocolContext) else {
|
||||
throw SMKError.assertionError(description: "\(logTag) Missing our identity key pair.")
|
||||
}
|
||||
|
||||
let wrapper = try SMKUnidentifiedSenderMessage.parse(dataAndPrefix: cipherTextData)
|
||||
|
||||
guard let prefixData = kUDPrefixString.data(using: String.Encoding.utf8) else {
|
||||
throw SMKError.assertionError(description: "\(logTag) Could not encode prefix.")
|
||||
}
|
||||
|
||||
let ephemeralSalt = NSData.join([
|
||||
prefixData,
|
||||
try ourIdentityKeyPair.ecPublicKey().serialized,
|
||||
wrapper.ephemeralKey.serialized
|
||||
])
|
||||
|
||||
let ephemeralKeys = try throwswrapped_calculateEphemeralKeys(ephemeralPublicKey: wrapper.ephemeralKey,
|
||||
ephemeralPrivateKey: ourIdentityKeyPair.ecPrivateKey(),
|
||||
salt: ephemeralSalt)
|
||||
|
||||
let staticKeyBytes = try decrypt(cipherKey: ephemeralKeys.cipherKey,
|
||||
macKey: ephemeralKeys.macKey,
|
||||
cipherTextWithMac: wrapper.encryptedStatic)
|
||||
|
||||
let staticKey = try ECPublicKey(serializedKeyData: staticKeyBytes)
|
||||
|
||||
let staticSalt = NSData.join([
|
||||
ephemeralKeys.chainKey,
|
||||
wrapper.encryptedStatic
|
||||
])
|
||||
|
||||
let staticKeys = try throwswrapped_calculateStaticKeys(staticPublicKey: staticKey,
|
||||
staticPrivateKey: ourIdentityKeyPair.ecPrivateKey(),
|
||||
salt: staticSalt)
|
||||
|
||||
let messageBytes = try decrypt(cipherKey: staticKeys.cipherKey,
|
||||
macKey: staticKeys.macKey,
|
||||
cipherTextWithMac: wrapper.encryptedMessage)
|
||||
|
||||
let messageContent = try SMKUnidentifiedSenderMessageContent.parse(data: messageBytes)
|
||||
|
||||
let senderRecipientId = messageContent.senderCertificate.senderRecipientId
|
||||
let senderDeviceId = messageContent.senderCertificate.senderDeviceId
|
||||
|
||||
guard senderRecipientId != localRecipientId || senderDeviceId != localDeviceId else {
|
||||
Logger.info("Discarding self-sent message")
|
||||
throw SMKSecretSessionCipherError.selfSentMessage
|
||||
}
|
||||
|
||||
// validator.validate(content.getSenderCertificate(), timestamp);
|
||||
|
||||
let wrapAsKnownSenderError = { (underlyingError: Error) in
|
||||
return SecretSessionKnownSenderError(senderRecipientId: senderRecipientId, senderDeviceId: senderDeviceId, underlyingError: underlyingError)
|
||||
}
|
||||
|
||||
do {
|
||||
try certificateValidator.throwswrapped_validate(senderCertificate: messageContent.senderCertificate,
|
||||
validationTime: timestamp)
|
||||
} catch {
|
||||
throw wrapAsKnownSenderError(error)
|
||||
}
|
||||
|
||||
// if (!MessageDigest.isEqual(content.getSenderCertificate().getKey().serialize(), staticKeyBytes)) {
|
||||
// throw new InvalidKeyException("Sender's certificate key does not match key used in message");
|
||||
// }
|
||||
|
||||
// // NOTE: Constant time comparison.
|
||||
// guard messageContent.senderCertificate.key.serialized.ows_constantTimeIsEqual(to: staticKeyBytes) else {
|
||||
// let underlyingError = SMKError.assertionError(description: "\(logTag) Sender's certificate key does not match key used in message.")
|
||||
// throw wrapAsKnownSenderError(underlyingError)
|
||||
// }
|
||||
|
||||
let paddedMessagePlaintext: Data
|
||||
do {
|
||||
paddedMessagePlaintext = try throwswrapped_decrypt(messageContent: messageContent, protocolContext: protocolContext)
|
||||
} catch {
|
||||
throw wrapAsKnownSenderError(error)
|
||||
}
|
||||
|
||||
// NOTE: We use the sender properties from the sender certificate, not from this class' properties.
|
||||
guard senderDeviceId >= 0 && senderDeviceId <= INT_MAX else {
|
||||
let underlyingError = SMKError.assertionError(description: "\(logTag) Invalid senderDeviceId.")
|
||||
throw wrapAsKnownSenderError(underlyingError)
|
||||
}
|
||||
|
||||
return SMKDecryptResult(senderRecipientId: senderRecipientId,
|
||||
senderDeviceId: Int(senderDeviceId),
|
||||
paddedPayload: paddedMessagePlaintext,
|
||||
messageType: messageContent.messageType)
|
||||
}
|
||||
|
||||
// MARK: - Encrypt
|
||||
|
||||
// private EphemeralKeys calculateEphemeralKeys(ECPublicKey ephemeralPublic, ECPrivateKey ephemeralPrivate, byte[] salt)
|
||||
// throws InvalidKeyException {
|
||||
private func throwswrapped_calculateEphemeralKeys(ephemeralPublicKey: ECPublicKey,
|
||||
ephemeralPrivateKey: ECPrivateKey,
|
||||
salt: Data) throws -> SMKEphemeralKeys {
|
||||
guard ephemeralPublicKey.keyData.count > 0 else {
|
||||
throw SMKError.assertionError(description: "\(logTag) invalid ephemeralPublicKey")
|
||||
}
|
||||
|
||||
guard ephemeralPrivateKey.keyData.count > 0 else {
|
||||
throw SMKError.assertionError(description: "\(logTag) invalid ephemeralPrivateKey")
|
||||
}
|
||||
|
||||
guard salt.count > 0 else {
|
||||
throw SMKError.assertionError(description: "\(logTag) invalid salt")
|
||||
}
|
||||
|
||||
// byte[] ephemeralSecret = Curve.calculateAgreement(ephemeralPublic, ephemeralPrivate);
|
||||
//
|
||||
// See:
|
||||
// https://github.com/signalapp/libsignal-protocol-java/blob/master/java/src/main/java/org/whispersystems/libsignal/ecc/Curve.java#L30
|
||||
let keyPair = ECKeyPair(publicKey: ephemeralPublicKey.keyData, privateKey: ephemeralPrivateKey.keyData)
|
||||
let ephemeralSecret = try Curve25519.generateSharedSecret(fromPublicKey: ephemeralPublicKey.keyData, andKeyPair: keyPair)
|
||||
|
||||
// byte[] ephemeralDerived = new HKDFv3().deriveSecrets(ephemeralSecret, salt, new byte[0], 96);
|
||||
let kEphemeralDerivedLength: UInt = 96
|
||||
let ephemeralDerived: Data =
|
||||
try HKDFKit.deriveKey(ephemeralSecret, info: Data(), salt: salt, outputSize: Int32(kEphemeralDerivedLength))
|
||||
guard ephemeralDerived.count == kEphemeralDerivedLength else {
|
||||
throw SMKError.assertionError(description: "\(logTag) derived ephemeral has unexpected length: \(ephemeralDerived.count).")
|
||||
}
|
||||
|
||||
let ephemeralDerivedParser = OWSDataParser(data: ephemeralDerived)
|
||||
let chainKey = try ephemeralDerivedParser.nextData(length: 32, name: "chain key")
|
||||
let cipherKey = try ephemeralDerivedParser.nextData(length: 32, name: "cipher key")
|
||||
let macKey = try ephemeralDerivedParser.nextData(length: 32, name: "mac key")
|
||||
guard ephemeralDerivedParser.isEmpty else {
|
||||
throw SMKError.assertionError(description: "\(logTag) could not parse derived ephemeral.")
|
||||
}
|
||||
|
||||
return SMKEphemeralKeys(chainKey: chainKey, cipherKey: cipherKey, macKey: macKey)
|
||||
}
|
||||
|
||||
// private StaticKeys calculateStaticKeys(ECPublicKey staticPublic, ECPrivateKey staticPrivate, byte[] salt) throws
|
||||
// InvalidKeyException {
|
||||
private func throwswrapped_calculateStaticKeys(staticPublicKey: ECPublicKey,
|
||||
staticPrivateKey: ECPrivateKey,
|
||||
salt: Data) throws -> SMKStaticKeys {
|
||||
guard staticPublicKey.keyData.count > 0 else {
|
||||
throw SMKError.assertionError(description: "\(logTag) invalid staticPublicKey")
|
||||
}
|
||||
guard staticPrivateKey.keyData.count > 0 else {
|
||||
throw SMKError.assertionError(description: "\(logTag) invalid staticPrivateKey")
|
||||
}
|
||||
guard salt.count > 0 else {
|
||||
throw SMKError.assertionError(description: "\(logTag) invalid salt")
|
||||
}
|
||||
|
||||
// byte[] staticSecret = Curve.calculateAgreement(staticPublic, staticPrivate);
|
||||
//
|
||||
// See:
|
||||
// https://github.com/signalapp/libsignal-protocol-java/blob/master/java/src/main/java/org/whispersystems/libsignal/ecc/Curve.java#L30
|
||||
let keyPair = ECKeyPair(publicKey: staticPublicKey.keyData, privateKey: staticPrivateKey.keyData)
|
||||
let staticSecret = Curve25519.generateSharedSecret(fromPublicKey: staticPublicKey.keyData, andKeyPair: keyPair)
|
||||
|
||||
// byte[] staticDerived = new HKDFv3().deriveSecrets(staticSecret, salt, new byte[0], 96);
|
||||
let kStaticDerivedLength: UInt = 96
|
||||
let staticDerived: Data =
|
||||
HKDFKit.deriveKey(staticSecret, info: Data(), salt: salt, outputSize: Int32(kStaticDerivedLength))
|
||||
guard staticDerived.count == kStaticDerivedLength else {
|
||||
throw SMKError.assertionError(description: "\(logTag) could not derive static.")
|
||||
}
|
||||
|
||||
// byte[][] staticDerivedParts = ByteUtil.split(staticDerived, 32, 32, 32);
|
||||
let staticDerivedParser = OWSDataParser(data: staticDerived)
|
||||
_ = try staticDerivedParser.nextData(length: 32)
|
||||
let cipherKey = try staticDerivedParser.nextData(length: 32)
|
||||
let macKey = try staticDerivedParser.nextData(length: 32)
|
||||
guard staticDerivedParser.isEmpty else {
|
||||
throw SMKError.assertionError(description: "\(logTag) invalid derived static.")
|
||||
}
|
||||
|
||||
// return new StaticKeys(staticDerivedParts[1], staticDerivedParts[2]);
|
||||
return SMKStaticKeys(cipherKey: cipherKey, macKey: macKey)
|
||||
}
|
||||
|
||||
// private byte[] encrypt(SecretKeySpec cipherKey, SecretKeySpec macKey, byte[] plaintext) {
|
||||
private func encrypt(cipherKey: SMKSecretKeySpec,
|
||||
macKey: SMKSecretKeySpec,
|
||||
plaintextData: Data) throws -> Data {
|
||||
|
||||
// Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
|
||||
// cipher.init(Cipher.ENCRYPT_MODE, cipherKey, new IvParameterSpec(new byte[16]));
|
||||
// byte[] ciphertext = cipher.doFinal(plaintext);
|
||||
guard let aesKey = OWSAES256Key(data: cipherKey.keyData) else {
|
||||
throw SMKError.assertionError(description: "\(logTag) Invalid encryption key.")
|
||||
}
|
||||
|
||||
// NOTE: The IV is all zeroes. This is fine since we're using a unique key.
|
||||
let initializationVector = Data(count: Int(kAES256CTR_IVLength))
|
||||
|
||||
guard let encryptionResult = Cryptography.encryptAESCTR(plaintextData: plaintextData, initializationVector: initializationVector, key: aesKey) else {
|
||||
throw SMKError.assertionError(description: "\(logTag) Could not encrypt data.")
|
||||
}
|
||||
let cipherText = encryptionResult.ciphertext
|
||||
|
||||
// Mac mac = Mac.getInstance("HmacSHA256");
|
||||
// mac.init(macKey);
|
||||
//
|
||||
// byte[] ourFullMac = mac.doFinal(ciphertext);
|
||||
// byte[] ourMac = ByteUtil.trim(ourFullMac, 10);
|
||||
guard let ourMac = Cryptography.truncatedSHA256HMAC(cipherText, withHMACKey: macKey.keyData, truncation: 10) else {
|
||||
throw SMKError.assertionError(description: "\(logTag) Could not compute HmacSHA256.")
|
||||
}
|
||||
|
||||
// return ByteUtil.combine(ciphertext, ourMac);
|
||||
let result = NSData.join([
|
||||
cipherText,
|
||||
ourMac
|
||||
])
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// MARK: - Decrypt
|
||||
|
||||
private func throwswrapped_decrypt(messageContent: SMKUnidentifiedSenderMessageContent,
|
||||
protocolContext: Any) throws -> Data {
|
||||
// NOTE: We use the sender properties from the sender certificate, not from this class' properties.
|
||||
let senderRecipientId = messageContent.senderCertificate.senderRecipientId
|
||||
let senderDeviceId = messageContent.senderCertificate.senderDeviceId
|
||||
guard senderDeviceId >= 0 && senderDeviceId <= INT32_MAX else {
|
||||
throw SMKError.assertionError(description: "\(logTag) Invalid senderDeviceId.")
|
||||
}
|
||||
|
||||
let cipherMessage: CipherMessage
|
||||
switch (messageContent.messageType) {
|
||||
case .whisper:
|
||||
cipherMessage = try WhisperMessage(data: messageContent.contentData)
|
||||
case .prekey:
|
||||
cipherMessage = try PreKeyWhisperMessage(data: messageContent.contentData)
|
||||
case .fallback:
|
||||
let privateKey = try? identityStore.identityKeyPair(protocolContext)?.privateKey()
|
||||
let cipher = FallBackSessionCipher(recipientPublicKey: senderRecipientId, privateKey: privateKey)
|
||||
let plaintext = cipher.decrypt(messageContent.contentData)!
|
||||
return plaintext
|
||||
}
|
||||
|
||||
let cipher = LokiSessionCipher(sessionResetImplementation: sessionResetImplementation,
|
||||
sessionStore: sessionStore,
|
||||
preKeyStore: preKeyStore,
|
||||
signedPreKeyStore: signedPreKeyStore,
|
||||
identityKeyStore: identityStore,
|
||||
recipientID: senderRecipientId,
|
||||
deviceID: Int32(senderDeviceId))
|
||||
|
||||
let plaintextData = try cipher.decrypt(cipherMessage, protocolContext: protocolContext)
|
||||
return plaintextData
|
||||
}
|
||||
|
||||
// private byte[] decrypt(SecretKeySpec cipherKey, SecretKeySpec macKey, byte[] ciphertext) throws InvalidMacException {
|
||||
private func decrypt(cipherKey: SMKSecretKeySpec,
|
||||
macKey: SMKSecretKeySpec,
|
||||
cipherTextWithMac: Data) throws -> Data {
|
||||
|
||||
// if (ciphertext.count < 10) {
|
||||
// throw new InvalidMacException("Ciphertext not long enough for MAC!");
|
||||
// }
|
||||
if (cipherTextWithMac.count < kSMKSecretSessionCipherMacLength) {
|
||||
throw SMKError.assertionError(description: "\(logTag) Cipher text not long enough for MAC.")
|
||||
}
|
||||
|
||||
// byte[][] ciphertextParts = ByteUtil.split(ciphertext, ciphertext.count - 10, 10);
|
||||
let cipherTextWithMacParser = OWSDataParser(data: cipherTextWithMac)
|
||||
let cipherTextLength = UInt(cipherTextWithMac.count) - kSMKSecretSessionCipherMacLength
|
||||
let cipherText = try cipherTextWithMacParser.nextData(length: cipherTextLength, name: "cipher text")
|
||||
let theirMac = try cipherTextWithMacParser.nextData(length: kSMKSecretSessionCipherMacLength, name: "their mac")
|
||||
guard cipherTextWithMacParser.isEmpty else {
|
||||
throw SMKError.assertionError(description: "\(logTag) Could not parse cipher text.")
|
||||
}
|
||||
|
||||
// Mac mac = Mac.getInstance("HmacSHA256");
|
||||
// mac.init(macKey);
|
||||
//
|
||||
// byte[] digest = mac.doFinal(ciphertextParts[0]);
|
||||
guard let ourFullMac = Cryptography.computeSHA256HMAC(cipherText, withHMACKey: macKey.keyData) else {
|
||||
throw SMKError.assertionError(description: "\(logTag) Could not compute HmacSHA256.")
|
||||
}
|
||||
|
||||
// byte[] ourMac = ByteUtil.trim(digest, 10);
|
||||
guard ourFullMac.count >= kSMKSecretSessionCipherMacLength else {
|
||||
throw SMKError.assertionError(description: "\(logTag) HmacSHA256 has unexpected length.")
|
||||
}
|
||||
|
||||
let ourMac = ourFullMac[0..<kSMKSecretSessionCipherMacLength]
|
||||
|
||||
// if (!MessageDigest.isEqual(ourMac, theirMac)) {
|
||||
// throw new InvalidMacException("Bad mac!");
|
||||
// }
|
||||
//
|
||||
// NOTE: Constant time comparison.
|
||||
guard ourMac.ows_constantTimeIsEqual(to: theirMac) else {
|
||||
throw SMKError.assertionError(description: "\(logTag) macs do not match.")
|
||||
}
|
||||
|
||||
// Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
|
||||
// cipher.init(Cipher.DECRYPT_MODE, cipherKey, new IvParameterSpec(new byte[16]));
|
||||
guard let aesKey = OWSAES256Key(data: cipherKey.keyData) else {
|
||||
throw SMKError.assertionError(description: "\(logTag) could not parse AES256 key.")
|
||||
}
|
||||
|
||||
// NOTE: The IV is all zeroes. This is fine since we're using a unique key.
|
||||
let initializationVector = Data(count: Int(kAES256CTR_IVLength))
|
||||
|
||||
guard let plaintext = Cryptography.decryptAESCTR(cipherText: cipherText, initializationVector: initializationVector, key: aesKey) else {
|
||||
throw SMKError.assertionError(description: "\(logTag) could not decrypt AESGCM.")
|
||||
}
|
||||
|
||||
return plaintext
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
// See:
|
||||
// https://github.com/signalapp/libsignal-metadata-java/blob/cac0dde9de416a192e64a8940503982820870090/java/src/main/java/org/signal/libsignal/metadata/certificate/SenderCertificate.java
|
||||
@objc public class SMKSenderCertificate: NSObject {
|
||||
|
||||
@objc public let senderDeviceId: UInt32
|
||||
@objc public let senderRecipientId: String
|
||||
|
||||
@objc public init(senderDeviceId: UInt32, senderRecipientId: String) {
|
||||
self.senderDeviceId = senderDeviceId
|
||||
self.senderRecipientId = senderRecipientId
|
||||
}
|
||||
|
||||
@objc public class func parse(data: Data) throws -> SMKSenderCertificate {
|
||||
let proto = try SMKProtoSenderCertificate.parseData(data)
|
||||
return try parse(proto: proto)
|
||||
}
|
||||
|
||||
@objc public class func parse(proto: SMKProtoSenderCertificate) throws -> SMKSenderCertificate {
|
||||
|
||||
let sender = proto.sender
|
||||
let senderDevice = proto.senderDevice
|
||||
|
||||
return SMKSenderCertificate(senderDeviceId: senderDevice, senderRecipientId: sender)
|
||||
}
|
||||
|
||||
@objc public func toProto() throws -> SMKProtoSenderCertificate {
|
||||
let builder =
|
||||
SMKProtoSenderCertificate.builder(sender: senderRecipientId, senderDevice: senderDeviceId)
|
||||
return try builder.build()
|
||||
}
|
||||
|
||||
@objc public func serialized() throws -> Data {
|
||||
return try toProto().serializedData()
|
||||
}
|
||||
|
||||
open override func isEqual(_ other: Any?) -> Bool {
|
||||
if let other = other as? SMKSenderCertificate {
|
||||
return (senderDeviceId == other.senderDeviceId && senderRecipientId == other.senderRecipientId)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
public override var hash: Int {
|
||||
return senderDeviceId.hashValue ^ senderRecipientId.hashValue
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
// See:
|
||||
// https://github.com/signalapp/libsignal-metadata-java/blob/cac0dde9de416a192e64a8940503982820870090/java/src/main/java/org/signal/libsignal/metadata/certificate/ServerCertificate.java
|
||||
@objc public class SMKServerCertificate: NSObject {
|
||||
|
||||
@objc public let keyId: UInt32
|
||||
@objc public let key: ECPublicKey
|
||||
@objc public let signatureData: Data
|
||||
|
||||
public init(keyId: UInt32,
|
||||
key: ECPublicKey,
|
||||
signatureData: Data) {
|
||||
self.keyId = keyId
|
||||
self.key = key
|
||||
self.signatureData = signatureData
|
||||
}
|
||||
|
||||
@objc public class func parse(data: Data) throws -> SMKServerCertificate {
|
||||
let proto = try SMKProtoServerCertificate.parseData(data)
|
||||
return try parse(proto: proto)
|
||||
}
|
||||
|
||||
@objc public class func parse(proto: SMKProtoServerCertificate) throws -> SMKServerCertificate {
|
||||
let signatureData = proto.signature
|
||||
let certificateData = proto.certificate
|
||||
let certificateProto = try SMKProtoServerCertificateCertificate.parseData(certificateData)
|
||||
let keyId = certificateProto.id
|
||||
let keyData = certificateProto.key
|
||||
let key = try ECPublicKey(serializedKeyData: keyData)
|
||||
return SMKServerCertificate(keyId: keyId, key: key, signatureData: signatureData)
|
||||
}
|
||||
|
||||
@objc public func toProto() throws -> SMKProtoServerCertificate {
|
||||
let certificateBuilder = SMKProtoServerCertificateCertificate.builder(id: keyId, key: key.serialized)
|
||||
|
||||
let builder =
|
||||
SMKProtoServerCertificate.builder(certificate: try certificateBuilder.buildSerializedData(),
|
||||
signature: signatureData)
|
||||
return try builder.build()
|
||||
}
|
||||
|
||||
@objc public func serialized() throws -> Data {
|
||||
return try toProto().serializedData()
|
||||
}
|
||||
|
||||
open override func isEqual(_ other: Any?) -> Bool {
|
||||
if let other = other as? SMKServerCertificate {
|
||||
return (keyId == other.keyId &&
|
||||
key.isEqual(other.key) &&
|
||||
(signatureData == other.signatureData))
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
public override var hash: Int {
|
||||
return keyId.hashValue ^ key.hashValue ^ signatureData.hashValue
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@objc
|
||||
public class SMKUDAccessKey: NSObject {
|
||||
|
||||
@objc
|
||||
public static let kUDAccessKeyLength: Int = 16
|
||||
|
||||
@objc
|
||||
public let keyData: Data
|
||||
|
||||
@objc
|
||||
public init(profileKey: Data) throws {
|
||||
guard let aesGcmKey = OWSAES256Key(data: profileKey) else {
|
||||
throw SMKError.assertionError(description: "Profile key is not valid AES GCM key.")
|
||||
}
|
||||
|
||||
// We derive the "ud access key" from the private key by encrypting zeroes.
|
||||
let emptyPlaintextLength = 16
|
||||
let emptyPlaintext = Data(count: Int(emptyPlaintextLength))
|
||||
let initializationVector = Data(count: Int(kAESGCM256_IVLength))
|
||||
guard let keyData = Cryptography.encryptAESGCM(plainTextData: emptyPlaintext,
|
||||
initializationVector: initializationVector,
|
||||
additionalAuthenticatedData: nil,
|
||||
key: aesGcmKey) else {
|
||||
throw SMKError.assertionError(description: "Could not derive UD access key from profile key.")
|
||||
}
|
||||
guard keyData.ciphertext.count == SMKUDAccessKey.kUDAccessKeyLength else {
|
||||
throw SMKError.assertionError(description: "\(SMKUDAccessKey.logTag) key has invalid length")
|
||||
}
|
||||
|
||||
self.keyData = keyData.ciphertext
|
||||
}
|
||||
|
||||
@objc
|
||||
public init(randomKeyData: ()) {
|
||||
self.keyData = Randomness.generateRandomBytes(Int32(SMKUDAccessKey.kUDAccessKeyLength))
|
||||
}
|
||||
|
||||
// MARK:
|
||||
|
||||
override public func isEqual(_ object: Any?) -> Bool {
|
||||
guard let other = object as? SMKUDAccessKey else { return false }
|
||||
return self.keyData == other.keyData
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
// https://github.com/signalapp/libsignal-metadata-java/blob/master/java/src/main/java/org/signal/libsignal/metadata/protocol/UnidentifiedSenderMessage.java
|
||||
@objc public class SMKUnidentifiedSenderMessage: NSObject {
|
||||
|
||||
@objc public static let kSMKMessageCipherTextVersion: UInt = 1
|
||||
|
||||
public let cipherTextVersion: UInt
|
||||
public let ephemeralKey: ECPublicKey
|
||||
public let encryptedStatic: Data
|
||||
public let encryptedMessage: Data
|
||||
|
||||
public init(cipherTextVersion: UInt,
|
||||
ephemeralKey: ECPublicKey,
|
||||
encryptedStatic: Data,
|
||||
encryptedMessage: Data) {
|
||||
self.cipherTextVersion = cipherTextVersion
|
||||
self.ephemeralKey = ephemeralKey
|
||||
self.encryptedStatic = encryptedStatic
|
||||
self.encryptedMessage = encryptedMessage
|
||||
}
|
||||
|
||||
public init(ephemeralKey: ECPublicKey,
|
||||
encryptedStatic: Data,
|
||||
encryptedMessage: Data) {
|
||||
self.cipherTextVersion = SMKUnidentifiedSenderMessage.kSMKMessageCipherTextVersion
|
||||
self.ephemeralKey = ephemeralKey
|
||||
self.encryptedStatic = encryptedStatic
|
||||
self.encryptedMessage = encryptedMessage
|
||||
}
|
||||
|
||||
@objc public class func parse(dataAndPrefix: Data) throws -> SMKUnidentifiedSenderMessage {
|
||||
// public UnidentifiedSenderMessage(byte[] serialized)
|
||||
// throws InvalidMetadataMessageException, InvalidMetadataVersionException
|
||||
|
||||
let parser = OWSDataParser(data: dataAndPrefix)
|
||||
|
||||
// this.version = ByteUtil.highBitsToInt(serialized[0]);
|
||||
let versionByte = try parser.nextByte(name: "version byte")
|
||||
let cipherTextVersion = UInt(SerializationUtilities.highBitsToInt(fromByte: versionByte))
|
||||
|
||||
// if (version > CIPHERTEXT_VERSION) {
|
||||
// throw new InvalidMetadataVersionException("Unknown version: " + this.version);
|
||||
// }
|
||||
guard cipherTextVersion <= SMKUnidentifiedSenderMessage.kSMKMessageCipherTextVersion else {
|
||||
throw SMKError.assertionError(description: "\(logTag) unknown cipher text version: \(cipherTextVersion)")
|
||||
}
|
||||
|
||||
// SignalProtos.UnidentifiedSenderMessage unidentifiedSenderMessage =
|
||||
// SignalProtos.UnidentifiedSenderMessage.parseFrom(ByteString.copyFrom(serialized, 1, serialized.length - 1));
|
||||
let protoData = try parser.remainder(name: "proto data")
|
||||
let proto = try SMKProtoUnidentifiedSenderMessage.parseData(protoData)
|
||||
|
||||
// if (!unidentifiedSenderMessage.hasEphemeralPublic() ||
|
||||
// !unidentifiedSenderMessage.hasEncryptedStatic() ||
|
||||
// !unidentifiedSenderMessage.hasEncryptedMessage())
|
||||
// {
|
||||
// throw new InvalidMetadataMessageException("Missing fields");
|
||||
// }
|
||||
// NOTE: These fields are required in the proto schema.
|
||||
|
||||
// this.ephemeral = Curve.decodePoint(unidentifiedSenderMessage.getEphemeralPublic().toByteArray(), 0);
|
||||
let ephemeralKeyData = proto.ephemeralPublic
|
||||
let ephemeralKey = try ECPublicKey(serializedKeyData: ephemeralKeyData)
|
||||
|
||||
// this.encryptedStatic = unidentifiedSenderMessage.getEncryptedStatic().toByteArray();
|
||||
let encryptedStatic = proto.encryptedStatic
|
||||
|
||||
// this.encryptedMessage = unidentifiedSenderMessage.getEncryptedMessage().toByteArray();
|
||||
let encryptedMessage = proto.encryptedMessage
|
||||
|
||||
return SMKUnidentifiedSenderMessage(cipherTextVersion: cipherTextVersion, ephemeralKey: ephemeralKey, encryptedStatic: encryptedStatic, encryptedMessage: encryptedMessage)
|
||||
}
|
||||
|
||||
@objc public func toProto() throws -> SMKProtoUnidentifiedSenderMessage {
|
||||
let builder = SMKProtoUnidentifiedSenderMessage.builder(ephemeralPublic: ephemeralKey.serialized,
|
||||
encryptedStatic: encryptedStatic,
|
||||
encryptedMessage: encryptedMessage)
|
||||
return try builder.build()
|
||||
}
|
||||
|
||||
@objc public func serialized() throws -> Data {
|
||||
let versionByte: UInt8 = UInt8((self.cipherTextVersion << 4 | self.cipherTextVersion) & 0xFF)
|
||||
let versionBytes = [versionByte]
|
||||
let versionData = Data(bytes: versionBytes)
|
||||
let messageData = try toProto().serializedData()
|
||||
|
||||
return NSData.join([versionData, messageData])
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@objc public enum SMKMessageType: Int {
|
||||
case whisper
|
||||
case prekey
|
||||
case fallback
|
||||
}
|
||||
|
||||
// See:
|
||||
// https://github.com/signalapp/libsignal-metadata-java/blob/0cbbbf23eaf9f46fdf2d9463f3dfab2fb3271292/java/src/main/java/org/signal/libsignal/metadata/protocol/UnidentifiedSenderMessageContent.java
|
||||
@objc public class SMKUnidentifiedSenderMessageContent: NSObject {
|
||||
|
||||
@objc public let messageType: SMKMessageType
|
||||
@objc public let senderCertificate: SMKSenderCertificate
|
||||
@objc public let contentData: Data
|
||||
|
||||
@objc public init(messageType: SMKMessageType,
|
||||
senderCertificate: SMKSenderCertificate,
|
||||
contentData: Data) {
|
||||
self.messageType = messageType
|
||||
self.senderCertificate = senderCertificate
|
||||
self.contentData = contentData
|
||||
}
|
||||
|
||||
@objc public class func parse(data: Data) throws -> SMKUnidentifiedSenderMessageContent {
|
||||
|
||||
let proto = try SMKProtoUnidentifiedSenderMessageMessage.parseData(data)
|
||||
|
||||
// TODO: Should we have a default case in our switches? Probably.
|
||||
var messageType: SMKMessageType
|
||||
switch (proto.type) {
|
||||
case .prekeyMessage:
|
||||
messageType = .prekey
|
||||
case .message:
|
||||
messageType = .whisper
|
||||
case .fallbackMessage:
|
||||
messageType = .fallback
|
||||
}
|
||||
|
||||
let contentData = proto.content
|
||||
let senderCertificateProto = proto.senderCertificate
|
||||
let senderCertificate = try SMKSenderCertificate.parse(proto: senderCertificateProto)
|
||||
|
||||
return SMKUnidentifiedSenderMessageContent(messageType: messageType, senderCertificate: senderCertificate, contentData: contentData)
|
||||
}
|
||||
|
||||
@objc public func toProto() throws -> SMKProtoUnidentifiedSenderMessageMessage {
|
||||
let builderType: SMKProtoUnidentifiedSenderMessageMessage.SMKProtoUnidentifiedSenderMessageMessageType
|
||||
switch messageType {
|
||||
case .whisper:
|
||||
builderType = .message
|
||||
case .prekey:
|
||||
builderType = .prekeyMessage
|
||||
case .fallback:
|
||||
builderType = .fallbackMessage
|
||||
}
|
||||
|
||||
let builder = SMKProtoUnidentifiedSenderMessageMessage.builder(type: builderType,
|
||||
senderCertificate: try senderCertificate.toProto(),
|
||||
content: contentData)
|
||||
return try builder.build()
|
||||
}
|
||||
|
||||
@objc public func serialized() throws -> Data {
|
||||
return try toProto().serializedData()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
@objc(LKSessionRestorationProtocol)
|
||||
public protocol SessionRestorationProtocol {
|
||||
|
||||
func validatePreKeyWhisperMessage(for recipientPublicKey: String, whisperMessage: CipherMessage, using transaction: Any) throws
|
||||
func getSessionRestorationStatus(for recipientPublicKey: String) -> SessionRestorationStatus
|
||||
func handleNewSessionAdopted(for recipientPublicKey: String, using transaction: Any)
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
|
||||
@objc(LKSessionRestorationStatus)
|
||||
public enum SessionRestorationStatus : Int {
|
||||
case none, initiated, requestReceived
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
import CryptoSwift
|
||||
import Curve25519Kit
|
||||
|
||||
public final class DiffieHellman : NSObject {
|
||||
public static let ivSize: UInt = 16
|
||||
|
||||
public enum Error : LocalizedError {
|
||||
case decryptionFailed
|
||||
case sharedSecretGenerationFailed
|
||||
|
||||
public var errorDescription: String {
|
||||
switch self {
|
||||
case .decryptionFailed: return "Couldn't decrypt data"
|
||||
case .sharedSecretGenerationFailed: return "Couldn't generate a shared secret."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private override init() { }
|
||||
|
||||
public static func encrypt(_ plaintext: Data, using symmetricKey: Data) throws -> Data {
|
||||
let iv = Data.getSecureRandomData(ofSize: ivSize)!
|
||||
let cbc = CBC(iv: iv.bytes)
|
||||
let aes = try AES(key: symmetricKey.bytes, blockMode: cbc)
|
||||
let ciphertext = try aes.encrypt(plaintext.bytes)
|
||||
let ivAndCiphertext = iv.bytes + ciphertext
|
||||
return Data(ivAndCiphertext)
|
||||
}
|
||||
|
||||
public static func encrypt(_ plaintext: Data, publicKey: Data, privateKey: Data) throws -> Data {
|
||||
let keyPair = ECKeyPair(publicKey: publicKey, privateKey: privateKey)
|
||||
guard let symmetricKey = Curve25519.generateSharedSecret(fromPublicKey: publicKey, andKeyPair: keyPair) else { throw Error.sharedSecretGenerationFailed }
|
||||
return try encrypt(plaintext, using: symmetricKey)
|
||||
}
|
||||
|
||||
public static func decrypt(_ ivAndCiphertext: Data, using symmetricKey: Data) throws -> Data {
|
||||
guard ivAndCiphertext.count >= ivSize else { throw Error.decryptionFailed }
|
||||
let iv = ivAndCiphertext[..<ivSize]
|
||||
let ciphertext = ivAndCiphertext[ivSize...]
|
||||
let cbc = CBC(iv: iv.bytes)
|
||||
let aes = try AES(key: symmetricKey.bytes, blockMode: cbc)
|
||||
let plaintext = try aes.decrypt(ciphertext.bytes)
|
||||
return Data(plaintext)
|
||||
}
|
||||
|
||||
public static func decrypt(_ ivAndCiphertext: Data, publicKey: Data, privateKey: Data) throws -> Data {
|
||||
let keyPair = ECKeyPair(publicKey: publicKey, privateKey: privateKey)
|
||||
guard let symmetricKey = Curve25519.generateSharedSecret(fromPublicKey: publicKey, andKeyPair: keyPair) else { throw Error.sharedSecretGenerationFailed }
|
||||
return try decrypt(ivAndCiphertext, using: symmetricKey)
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
@interface ECKeyPair (Utilities)
|
||||
|
||||
- (ECKeyPair *)initWithPublicKey:(NSData *)publicKey privateKey:(NSData *)privateKey;
|
||||
- (NSData *)privateKey;
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -12,6 +12,11 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return keyPair;
|
||||
}
|
||||
|
||||
- (NSData *)privateKey
|
||||
{
|
||||
return [NSData dataWithBytes:self->privateKey length:32];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
@ -634,6 +634,25 @@
|
|||
C3A71D0B2558989C0043A11F /* MessageWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A71D0A2558989C0043A11F /* MessageWrapper.swift */; };
|
||||
C3A71D1E25589AC30043A11F /* WebSocketProto.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A71D1C25589AC30043A11F /* WebSocketProto.swift */; };
|
||||
C3A71D1F25589AC30043A11F /* WebSocketResources.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A71D1D25589AC30043A11F /* WebSocketResources.pb.swift */; };
|
||||
C3A71D2925589EBF0043A11F /* SessionRestorationProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A71D2825589EBF0043A11F /* SessionRestorationProtocol.swift */; };
|
||||
C3A71D3B25589F2B0043A11F /* SessionRestorationStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A71D3A25589F2B0043A11F /* SessionRestorationStatus.swift */; };
|
||||
C3A71D5025589FF30043A11F /* SMKUDAccessKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A71D4425589FF10043A11F /* SMKUDAccessKey.swift */; };
|
||||
C3A71D5125589FF30043A11F /* ECPublicKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A71D4525589FF10043A11F /* ECPublicKey.swift */; };
|
||||
C3A71D5225589FF30043A11F /* SMKError.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A71D4625589FF10043A11F /* SMKError.swift */; };
|
||||
C3A71D5325589FF30043A11F /* ECPrivateKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A71D4725589FF10043A11F /* ECPrivateKey.swift */; };
|
||||
C3A71D5425589FF30043A11F /* NSData+messagePadding.m in Sources */ = {isa = PBXBuildFile; fileRef = C3A71D4825589FF20043A11F /* NSData+messagePadding.m */; };
|
||||
C3A71D5525589FF30043A11F /* SMKSenderCertificate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A71D4925589FF20043A11F /* SMKSenderCertificate.swift */; };
|
||||
C3A71D5625589FF30043A11F /* SMKServerCertificate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A71D4A25589FF20043A11F /* SMKServerCertificate.swift */; };
|
||||
C3A71D5725589FF30043A11F /* SMKCertificateValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A71D4B25589FF20043A11F /* SMKCertificateValidator.swift */; };
|
||||
C3A71D5825589FF30043A11F /* SMKSecretSessionCipher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A71D4C25589FF30043A11F /* SMKSecretSessionCipher.swift */; };
|
||||
C3A71D5925589FF30043A11F /* SMKUnidentifiedSenderMessageContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A71D4D25589FF30043A11F /* SMKUnidentifiedSenderMessageContent.swift */; };
|
||||
C3A71D5A25589FF30043A11F /* NSData+messagePadding.h in Headers */ = {isa = PBXBuildFile; fileRef = C3A71D4E25589FF30043A11F /* NSData+messagePadding.h */; };
|
||||
C3A71D5B25589FF30043A11F /* SMKUnidentifiedSenderMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A71D4F25589FF30043A11F /* SMKUnidentifiedSenderMessage.swift */; };
|
||||
C3A71D672558A0170043A11F /* FallbackSessionCipher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A71D642558A0170043A11F /* FallbackSessionCipher.swift */; };
|
||||
C3A71D682558A0170043A11F /* LokiSessionCipher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A71D652558A0170043A11F /* LokiSessionCipher.swift */; };
|
||||
C3A71D742558A0F60043A11F /* SMKProto.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A71D722558A0F60043A11F /* SMKProto.swift */; };
|
||||
C3A71D752558A0F60043A11F /* OWSUnidentifiedDelivery.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A71D732558A0F60043A11F /* OWSUnidentifiedDelivery.pb.swift */; };
|
||||
C3A71D862558A28A0043A11F /* DiffieHellman.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A71D662558A0170043A11F /* DiffieHellman.swift */; };
|
||||
C3AABDDF2553ECF00042FF4C /* Array+Description.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5D12553860800C340D1 /* Array+Description.swift */; };
|
||||
C3BBE0762554CDA60050F1E3 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3BBE0752554CDA60050F1E3 /* Configuration.swift */; };
|
||||
C3BBE0802554CDD70050F1E3 /* Storage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3BBE07F2554CDD70050F1E3 /* Storage.swift */; };
|
||||
|
@ -1651,6 +1670,25 @@
|
|||
C3A71D0A2558989C0043A11F /* MessageWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageWrapper.swift; sourceTree = "<group>"; };
|
||||
C3A71D1C25589AC30043A11F /* WebSocketProto.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebSocketProto.swift; sourceTree = "<group>"; };
|
||||
C3A71D1D25589AC30043A11F /* WebSocketResources.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebSocketResources.pb.swift; sourceTree = "<group>"; };
|
||||
C3A71D2825589EBF0043A11F /* SessionRestorationProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionRestorationProtocol.swift; sourceTree = "<group>"; };
|
||||
C3A71D3A25589F2B0043A11F /* SessionRestorationStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionRestorationStatus.swift; sourceTree = "<group>"; };
|
||||
C3A71D4425589FF10043A11F /* SMKUDAccessKey.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SMKUDAccessKey.swift; sourceTree = "<group>"; };
|
||||
C3A71D4525589FF10043A11F /* ECPublicKey.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ECPublicKey.swift; sourceTree = "<group>"; };
|
||||
C3A71D4625589FF10043A11F /* SMKError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SMKError.swift; sourceTree = "<group>"; };
|
||||
C3A71D4725589FF10043A11F /* ECPrivateKey.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ECPrivateKey.swift; sourceTree = "<group>"; };
|
||||
C3A71D4825589FF20043A11F /* NSData+messagePadding.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+messagePadding.m"; sourceTree = "<group>"; };
|
||||
C3A71D4925589FF20043A11F /* SMKSenderCertificate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SMKSenderCertificate.swift; sourceTree = "<group>"; };
|
||||
C3A71D4A25589FF20043A11F /* SMKServerCertificate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SMKServerCertificate.swift; sourceTree = "<group>"; };
|
||||
C3A71D4B25589FF20043A11F /* SMKCertificateValidator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SMKCertificateValidator.swift; sourceTree = "<group>"; };
|
||||
C3A71D4C25589FF30043A11F /* SMKSecretSessionCipher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SMKSecretSessionCipher.swift; sourceTree = "<group>"; };
|
||||
C3A71D4D25589FF30043A11F /* SMKUnidentifiedSenderMessageContent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SMKUnidentifiedSenderMessageContent.swift; sourceTree = "<group>"; };
|
||||
C3A71D4E25589FF30043A11F /* NSData+messagePadding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+messagePadding.h"; sourceTree = "<group>"; };
|
||||
C3A71D4F25589FF30043A11F /* SMKUnidentifiedSenderMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SMKUnidentifiedSenderMessage.swift; sourceTree = "<group>"; };
|
||||
C3A71D642558A0170043A11F /* FallbackSessionCipher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FallbackSessionCipher.swift; sourceTree = "<group>"; };
|
||||
C3A71D652558A0170043A11F /* LokiSessionCipher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LokiSessionCipher.swift; sourceTree = "<group>"; };
|
||||
C3A71D662558A0170043A11F /* DiffieHellman.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DiffieHellman.swift; sourceTree = "<group>"; };
|
||||
C3A71D722558A0F60043A11F /* SMKProto.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SMKProto.swift; path = Protos/SMKProto.swift; sourceTree = "<group>"; };
|
||||
C3A71D732558A0F60043A11F /* OWSUnidentifiedDelivery.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSUnidentifiedDelivery.pb.swift; path = Protos/OWSUnidentifiedDelivery.pb.swift; sourceTree = "<group>"; };
|
||||
C3AA6BB824CE8F1B002358B6 /* Migrating Translations from Android.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = "Migrating Translations from Android.md"; sourceTree = "<group>"; };
|
||||
C3AECBEA24EF5244005743DE /* fa */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fa; path = translations/fa.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
C3BBE0752554CDA60050F1E3 /* Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Configuration.swift; sourceTree = "<group>"; };
|
||||
|
@ -3368,6 +3406,7 @@
|
|||
C3C2A5D12553860800C340D1 /* Array+Description.swift */,
|
||||
C3C2ABD12553C6C900C340D1 /* Data+SecureRandom.swift */,
|
||||
C3C2A5D52553860A00C340D1 /* Dictionary+Description.swift */,
|
||||
C3A71D662558A0170043A11F /* DiffieHellman.swift */,
|
||||
C3471F5525553DA000297E91 /* ECKeyPair+Utilities.h */,
|
||||
C3471F6725553E7600297E91 /* ECKeyPair+Utilities.m */,
|
||||
C3C2A5BC255385EE00C340D1 /* HTTP.swift */,
|
||||
|
@ -3501,6 +3540,8 @@
|
|||
children = (
|
||||
C3C2A8E52553B59B00C340D1 /* SPKProto.swift */,
|
||||
C3C2A8E42553B59B00C340D1 /* WhisperTextProtocol.pb.swift */,
|
||||
C3A71D722558A0F60043A11F /* SMKProto.swift */,
|
||||
C3A71D732558A0F60043A11F /* OWSUnidentifiedDelivery.pb.swift */,
|
||||
);
|
||||
name = Protos;
|
||||
sourceTree = "<group>";
|
||||
|
@ -3613,6 +3654,22 @@
|
|||
C3C2A9352553B5C300C340D1 /* Sessions */,
|
||||
C3C2A9562553B5F600C340D1 /* State */,
|
||||
C3C2A9692553B62B00C340D1 /* Utility */,
|
||||
C3A71D4725589FF10043A11F /* ECPrivateKey.swift */,
|
||||
C3A71D4525589FF10043A11F /* ECPublicKey.swift */,
|
||||
C3A71D4E25589FF30043A11F /* NSData+messagePadding.h */,
|
||||
C3A71D4825589FF20043A11F /* NSData+messagePadding.m */,
|
||||
C3A71D4B25589FF20043A11F /* SMKCertificateValidator.swift */,
|
||||
C3A71D4625589FF10043A11F /* SMKError.swift */,
|
||||
C3A71D4C25589FF30043A11F /* SMKSecretSessionCipher.swift */,
|
||||
C3A71D4925589FF20043A11F /* SMKSenderCertificate.swift */,
|
||||
C3A71D4A25589FF20043A11F /* SMKServerCertificate.swift */,
|
||||
C3A71D4425589FF10043A11F /* SMKUDAccessKey.swift */,
|
||||
C3A71D4F25589FF30043A11F /* SMKUnidentifiedSenderMessage.swift */,
|
||||
C3A71D4D25589FF30043A11F /* SMKUnidentifiedSenderMessageContent.swift */,
|
||||
C3A71D642558A0170043A11F /* FallbackSessionCipher.swift */,
|
||||
C3A71D652558A0170043A11F /* LokiSessionCipher.swift */,
|
||||
C3A71D2825589EBF0043A11F /* SessionRestorationProtocol.swift */,
|
||||
C3A71D3A25589F2B0043A11F /* SessionRestorationStatus.swift */,
|
||||
);
|
||||
path = Signal;
|
||||
sourceTree = "<group>";
|
||||
|
@ -3871,6 +3928,7 @@
|
|||
C3C2A9F42553B9C400C340D1 /* Threading.h in Headers */,
|
||||
C3C2A90A2553B5B200C340D1 /* Chain.h in Headers */,
|
||||
C3C2A8882553B4CC00C340D1 /* AxolotlExceptions.h in Headers */,
|
||||
C3A71D5A25589FF30043A11F /* NSData+messagePadding.h in Headers */,
|
||||
C3C2A89E2553B4F600C340D1 /* WhisperMessage.h in Headers */,
|
||||
C3C2A8D92553B57C00C340D1 /* PreKeyRecord.h in Headers */,
|
||||
C3C2A90B2553B5B200C340D1 /* MessageKeys.h in Headers */,
|
||||
|
@ -4959,6 +5017,7 @@
|
|||
C3BBE0A72554D4DE0050F1E3 /* Promise+Retrying.swift in Sources */,
|
||||
C3BBE0A92554D4DE0050F1E3 /* HTTP.swift in Sources */,
|
||||
C300A60D2554B31900555489 /* Logging.swift in Sources */,
|
||||
C3A71D862558A28A0043A11F /* DiffieHellman.swift in Sources */,
|
||||
C300A6322554B6D100555489 /* NSDate+Timestamp.mm in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -5012,38 +5071,52 @@
|
|||
files = (
|
||||
C3C2A91B2553B5B200C340D1 /* BobAxolotlParameters.m in Sources */,
|
||||
C3C2A8D82553B57C00C340D1 /* PreKeyRecord.m in Sources */,
|
||||
C3A71D3B25589F2B0043A11F /* SessionRestorationStatus.swift in Sources */,
|
||||
C3A71D5825589FF30043A11F /* SMKSecretSessionCipher.swift in Sources */,
|
||||
C3C2A9712553B63C00C340D1 /* SerializationUtilities.m in Sources */,
|
||||
C3A71D5925589FF30043A11F /* SMKUnidentifiedSenderMessageContent.swift in Sources */,
|
||||
C3C2ABEE2553C76900C340D1 /* ClosedGroupSenderKey.swift in Sources */,
|
||||
C3C2A9172553B5B200C340D1 /* RootKey.m in Sources */,
|
||||
C3C2A9112553B5B200C340D1 /* ChainKey.m in Sources */,
|
||||
C3C2A8C32553B55600C340D1 /* AES-CBC.m in Sources */,
|
||||
C3C2AA012553B9C400C340D1 /* Threading.m in Sources */,
|
||||
C3C2A9F32553B9C400C340D1 /* String+OWS.swift in Sources */,
|
||||
C3A71D682558A0170043A11F /* LokiSessionCipher.swift in Sources */,
|
||||
C3C2A9F12553B9C400C340D1 /* OWSLogs.m in Sources */,
|
||||
C3C2A9F22553B9C400C340D1 /* NSObject+OWS.m in Sources */,
|
||||
C3A71D5B25589FF30043A11F /* SMKUnidentifiedSenderMessage.swift in Sources */,
|
||||
C3C2A9182553B5B200C340D1 /* SendingChain.m in Sources */,
|
||||
C3C2A8A02553B4F600C340D1 /* PreKeyWhisperMessage.m in Sources */,
|
||||
C3A71D5225589FF30043A11F /* SMKError.swift in Sources */,
|
||||
C3C2A93F2553B5D700C340D1 /* SessionState.m in Sources */,
|
||||
C3C2A9F02553B9C400C340D1 /* OWSAsserts.m in Sources */,
|
||||
C3A71D5125589FF30043A11F /* ECPublicKey.swift in Sources */,
|
||||
C3C2ABF82553C8A300C340D1 /* Storage.swift in Sources */,
|
||||
C3C2A9F72553B9C400C340D1 /* NSData+OWS.m in Sources */,
|
||||
C3C2A90D2553B5B200C340D1 /* RKCK.m in Sources */,
|
||||
C3C2A8E72553B59B00C340D1 /* SPKProto.swift in Sources */,
|
||||
C3A71D5325589FF30043A11F /* ECPrivateKey.swift in Sources */,
|
||||
C3A71D5525589FF30043A11F /* SMKSenderCertificate.swift in Sources */,
|
||||
C3C2A91E2553B5B200C340D1 /* ChainAndIndex.m in Sources */,
|
||||
C3C2A91A2553B5B200C340D1 /* TSDerivedSecrets.m in Sources */,
|
||||
C3A71D5025589FF30043A11F /* SMKUDAccessKey.swift in Sources */,
|
||||
C3C2A91C2553B5B200C340D1 /* ReceivingChain.m in Sources */,
|
||||
C3C2AA032553B9C400C340D1 /* Randomness.m in Sources */,
|
||||
C3C2A9EF2553B9C400C340D1 /* OWSDataParser.swift in Sources */,
|
||||
C3C2A8A32553B4F600C340D1 /* FallbackMessage.m in Sources */,
|
||||
C3A71D5425589FF30043A11F /* NSData+messagePadding.m in Sources */,
|
||||
C3C2AA072553B9C400C340D1 /* Cryptography.m in Sources */,
|
||||
C3C2A9F52553B9C400C340D1 /* NSDate+OWS.mm in Sources */,
|
||||
C3C2ABE42553C74400C340D1 /* ClosedGroupRatchet.swift in Sources */,
|
||||
C3C2A93E2553B5D700C340D1 /* SessionRecord.m in Sources */,
|
||||
C3A71D742558A0F60043A11F /* SMKProto.swift in Sources */,
|
||||
C3C2AA052553B9C400C340D1 /* SCKExceptionWrapper.m in Sources */,
|
||||
C3A71D2925589EBF0043A11F /* SessionRestorationProtocol.swift in Sources */,
|
||||
C3C2A8D62553B57C00C340D1 /* PreKeyBundle.m in Sources */,
|
||||
C3C2A9F62553B9C400C340D1 /* Data+OWS.swift in Sources */,
|
||||
C3C2A89D2553B4F600C340D1 /* ClosedGroupCiphertextMessage.m in Sources */,
|
||||
C3C2A9FB2553B9C400C340D1 /* Logger.swift in Sources */,
|
||||
C3A71D672558A0170043A11F /* FallbackSessionCipher.swift in Sources */,
|
||||
C3C2AC0A2553C9A100C340D1 /* Configuration.swift in Sources */,
|
||||
C3C2A96E2553B63C00C340D1 /* NSData+keyVersionByte.m in Sources */,
|
||||
C3C2A8E62553B59B00C340D1 /* WhisperTextProtocol.pb.swift in Sources */,
|
||||
|
@ -5052,9 +5125,12 @@
|
|||
C3C2A9FA2553B9C400C340D1 /* OWSSwiftUtils.swift in Sources */,
|
||||
C3C2A92C2553B5BE00C340D1 /* SessionCipher.m in Sources */,
|
||||
C3C2A8D42553B57C00C340D1 /* SignedPrekeyRecord.m in Sources */,
|
||||
C3A71D752558A0F60043A11F /* OWSUnidentifiedDelivery.pb.swift in Sources */,
|
||||
C3A71D5625589FF30043A11F /* SMKServerCertificate.swift in Sources */,
|
||||
C3C2A8A12553B4F600C340D1 /* WhisperMessage.m in Sources */,
|
||||
C3C2A9192553B5B200C340D1 /* MessageKeys.m in Sources */,
|
||||
C3C2A90F2553B5B200C340D1 /* RatchetingSession.m in Sources */,
|
||||
C3A71D5725589FF30043A11F /* SMKCertificateValidator.swift in Sources */,
|
||||
C3C2A93D2553B5D700C340D1 /* SessionBuilder.m in Sources */,
|
||||
C3C2AA082553B9C400C340D1 /* NSString+OWS.m in Sources */,
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue