Compare commits

...

70 Commits

Author SHA1 Message Date
Michelle Linington
90f1776e63 Merge branch 'mlin/PR/ExposeUnsealedContent' 2021-09-17 13:12:55 -07:00
Michelle Linington
2ca9aafb27 Expose unsealed ciphertext content 2021-09-16 22:04:01 -07:00
Matthew Chen
998b761970 Fix build break. 2021-09-08 18:01:38 -03:00
Michelle Linington
4c8ddf0b04 Merge branch 'mlin/PR/ExposeGroupIdForSingleRecipientMessages' into feature/SignalClient-adoption 2021-08-12 19:45:14 -07:00
Michelle Linington
d8afca956d Callers can now add groupId to single recipient messages
We need to plumb through groupId. Desktop needs this to properly handle
resend responses.
2021-08-10 21:24:08 -07:00
Michelle Linington
7e59c7e818 Merge branch 'mlin/PR/ZeroedAccessKey' into feature/SignalClient-adoption 2021-08-04 17:08:53 -07:00
Michelle Linington
dcf17cdade Add zeroed SMKUDAccessKey
Used against the multi_recipient endpoint. The server doesn't need an
access key for unrestricted UD recipients.
2021-08-04 17:07:01 -07:00
Michelle Linington
882049b3f2 Adopt renames from SignalClient 2021-07-21 23:08:10 -07:00
Michelle Linington
c5f427f1bc Merge branch 'mlin/PR/LeftoverSenderKeyWork' into feature/SignalClient-adoption 2021-07-21 23:07:21 -07:00
Michelle Linington
242caf0d54 Plumbing of cipher type through decryption errors 2021-07-20 17:54:39 -07:00
Michelle Linington
06d7766c0e Support for decrypting PlaintextContent type
Also, returns the contentHint and groupId of any sealed-sender
decryption errors.
2021-06-02 21:19:12 -07:00
Michelle Linington
d1a3d73c5f Composable access keys
Sender key requires a derived access key that's composed of each
recipients access key xor-ed.
2021-05-28 00:33:53 -07:00
Michelle Linington
5c822fb4d0 Merge branch 'mlin/PR/SenderKey' into feature/SignalClient-adoption 2021-05-20 17:10:25 -07:00
Michelle Linington
6ac7b020fc PR Feedback and minor test change
Originally I used the `throwswrapped` prefix to match existing naming
convention. Jordan said this is a legacy convention.
2021-05-20 17:08:36 -07:00
Michelle Linington
bf0b0403bc Support for SealedSender SenderKeys 2021-05-20 01:22:25 -07:00
Jordan Rose
af0c4d1753 Merge branch 'jrose/remove-AxolotlKit' into feature/SignalClient-adoption 2021-03-22 16:09:30 -07:00
Jordan Rose
564fa5f1f7 Remove last references to AxolotlKit (and HKDFKit) 2021-03-19 18:27:32 -07:00
Jordan Rose
6bcb9a4e21 Update for SignalClient requiring SenderCertificates to have UUIDs
The removed test has been moved to SignalClient in
https://github.com/signalapp/libsignal-client/pull/197
2021-02-23 12:12:11 -08:00
Jordan Rose
c0b114797a Fix misuse of logTag, prefer Int32.max to INT32_MAX 2021-01-27 14:58:17 -08:00
Jordan Rose
7beae489c8 Update for SignalClient.StoreContext 2020-12-14 15:17:32 -08:00
Jordan Rose
bb1f262434 Update for 'throws' removal in SignalClient 2020-12-14 15:17:32 -08:00
Jordan Rose
902ed32a34 Remove SMK{Sender,Server}Certificate in favor of SignalClient 2020-12-14 15:17:32 -08:00
Jordan Rose
276a3cc873 Remove SMKSessionCipherTest
SessionCipher is still in use for classic message decryption (i.e. not
using SMKSecretSessionCipher), but it'll go away soon as well.
2020-12-10 15:21:18 -08:00
Jordan Rose
814a7121c7 Remove SMKEnvironment and SMKAccountIdFinder
SMKSecretSessionCipher now uses SMKAddress rather than an account ID,
leaving it up to SignalServiceKit to map things down to account IDs.
2020-12-10 15:21:18 -08:00
Jordan Rose
89dd24b617 Remove unused SMKUnidentifiedSenderMessage(Content) 2020-12-10 15:21:18 -08:00
Jordan Rose
07fbbfbedc Adopt SignalClient for en/decryption in SMKSecretSessionCipher 2020-12-10 15:21:18 -08:00
Jordan Rose
50fbd4fd21 Adopt SignalClient.PublicKey in certificate types 2020-11-11 16:43:59 -08:00
Jordan Rose
56876641ac Adopt SignalClient in tests to avoid prependKeyType() 2020-11-11 16:43:59 -08:00
Jordan Rose
65002cc8f4 Use SignalClient instead of Curve25519Kit for signature verification 2020-11-11 16:43:59 -08:00
Jordan Rose
c322b49ad2 Remove stray "bridging" header that was exposed as public 2020-11-11 16:43:59 -08:00
Jordan Rose
5b1d0ab759 Adjust testBadSignature to expect errors from SignalClient 2020-11-06 12:43:51 -08:00
Matthew Chen
7addcc1c4b Merge branch 'charlesmchen/prekeyLifecycle' 2020-08-25 21:25:11 -03:00
Matthew Chen
f337ab82f9 Use protocol contexts in prekey stores. 2020-08-25 20:19:29 -03:00
Matthew Chen
70bd1ed3c1 Use protocol contexts in prekey stores. 2020-08-25 20:08:50 -03:00
Michael Kirk
3fcb31137b Merge branch 'mkirk/fixup-tests-1' 2020-03-10 11:38:42 -06:00
Michael Kirk
967b5fa87d Fix tests: adapt to new SPK nullability annotations 2020-03-10 11:36:12 -06:00
Nora Trapp
1d738023e4 Merge branch 'nt/allow-longer-aesgcm-ivs' 2020-02-20 13:56:46 -08:00
Nora Trapp
a02ee0a422 allow different IV lengths for AESGCM256 2020-02-20 10:48:59 -08:00
Matthew Chen
33dc101ee6 Merge branch 'charlesmchen/fixBrokenTests' 2019-11-07 17:20:58 -03:00
Matthew Chen
17baff765b Fix broken tests. 2019-11-07 13:28:22 -03:00
Michael Kirk
b572f728d0 Merge branch 'mkirk/public-key-getters-to-curve' 2019-10-17 09:52:09 -06:00
Michael Kirk
b419ce0c50 move curve extensions to curve lib 2019-10-14 20:59:57 -06:00
Nora Trapp
ad13dd470c Merge branch 'nt/deployment-target' 2019-09-23 16:50:18 -07:00
Nora Trapp
d0b9ae1d7c Update deployment target to iOS 10 2019-09-23 10:44:31 -07:00
Matthew Chen
f7c0c7bd97 Merge branch 'charlesmchen/randomnessVsNil' 2019-07-29 14:55:04 -03:00
Matthew Chen
2c3986051d Fix build breakage around nil Randomness. 2019-07-29 14:50:58 -03:00
Michael Kirk
58e0316701 Merge branch 'mkirk/uuid' 2019-07-17 09:18:33 -06:00
Michael Kirk
5b1a6ad1b2 UUID support 2019-07-17 09:18:28 -06:00
Michael Kirk
e7db16f578 codegen 2019-07-16 23:15:27 -06:00
Michael Kirk
49f4bc19cf update protos for uuid 2019-07-16 23:15:20 -06:00
Michael Kirk
801b824c9e Merge branch 'mkirk/uuid-lossless-3' 2019-07-16 15:49:45 -06:00
Michael Kirk
22bb3def95 add round trip test 2019-07-16 15:47:41 -06:00
Michael Kirk
42b0a9d58e no change in behavior: formatting and ease-of-audit changes 2019-07-13 09:48:11 -06:00
Michael Kirk
5826648598 Losslessly encode protos 2019-07-13 09:46:56 -06:00
Michael Kirk
e0ed377f45 Merge branch 'mkirk/proto-enum' 2019-07-11 13:56:25 -06:00
Michael Kirk
39bab17821 adapt to optional enum 2019-06-26 10:08:48 -06:00
Michael Kirk
dab13fa22b make enum optional, regen 2019-06-26 10:08:38 -06:00
Michael Kirk
7f75e5eac0 fixup test 2019-06-20 16:57:42 -06:00
Michael Kirk
b2de463ac5 Merge branch 'mkirk/typed-protocol-context' 2019-05-22 14:58:17 -04:00
Michael Kirk
030f8cb1af Apply typed protocol context 2019-05-22 10:51:26 -04:00
Michael Kirk
10ac3abafd fix compiler warning - deprecated method 2019-05-22 10:51:09 -04:00
Matthew Chen
56f28fc3a6 Merge remote-tracking branch 'private/mkirk/cast-wrapped-error' 2018-11-29 18:03:06 -05:00
Michael Kirk
012c9e8905 convert underlyingError to NSError 2018-11-29 15:51:57 -07:00
Michael Kirk
b493b7b0db Merge branch 'mkirk/fixup-tests' 2018-11-19 09:27:16 -06:00
Michael Kirk
42d3565e4d Fixup SMK tests 2018-11-17 00:27:37 -06:00
Michael Kirk
a5473c8d33 Merge branch 'mkirk/return-sender-id' 2018-11-16 17:19:26 -06:00
Michael Kirk
5ac7778a48 custom nserror for sender details 2018-11-16 14:21:56 -06:00
Michael Kirk
6aeb45c532 format: fix indent 2018-11-16 10:43:10 -06:00
Michael Kirk
8a58636392 Merge branch 'mkirk/fix-tests-exceptions' 2018-11-12 09:32:08 -06:00
Michael Kirk
606528905e CR: renames for clarity 2018-11-12 09:32:03 -06:00
26 changed files with 1354 additions and 2057 deletions

View File

@ -21,9 +21,7 @@ A Swift & Objective-C library used by other Signal libraries.
s.source = { :git => "https://github.com/signalapp/SignalMetadataKit.git", :tag => s.version.to_s }
s.social_media_url = 'https://twitter.com/signalapp'
s.platform = :ios, '9.0'
#s.ios.deployment_target = '9.0'
#s.osx.deployment_target = '10.9'
s.platform = :ios, '10.0'
s.requires_arc = true
s.source_files = 'SignalMetadataKit/src/**/*.{h,m,mm,swift}', 'SignalMetadataKit/Private/**/*.{h,m,mm,swift}'
@ -41,10 +39,9 @@ A Swift & Objective-C library used by other Signal libraries.
s.resources = ["SignalMetadataKit/Resources/Certificates/*"]
s.dependency 'AxolotlKit'
s.dependency 'CocoaLumberjack'
s.dependency 'Curve25519Kit'
s.dependency 'HKDFKit'
s.dependency 'SignalClient'
s.dependency 'SignalCoreKit'
s.dependency 'SwiftProtobuf'

View File

@ -1,34 +0,0 @@
//
// 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
}
}

View File

@ -1,61 +0,0 @@
//
// 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
}
}

View File

@ -125,15 +125,23 @@ struct SMKProtos_SenderCertificate {
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// @required
var sender: String {
get {return _storage._sender ?? String()}
set {_uniqueStorage()._sender = newValue}
var senderE164: String {
get {return _storage._senderE164 ?? String()}
set {_uniqueStorage()._senderE164 = newValue}
}
/// Returns true if `sender` has been explicitly set.
var hasSender: Bool {return _storage._sender != nil}
/// Clears the value of `sender`. Subsequent reads from it will return its default value.
mutating func clearSender() {_storage._sender = nil}
/// Returns true if `senderE164` has been explicitly set.
var hasSenderE164: Bool {return _storage._senderE164 != nil}
/// Clears the value of `senderE164`. Subsequent reads from it will return its default value.
mutating func clearSenderE164() {_uniqueStorage()._senderE164 = nil}
var senderUuid: String {
get {return _storage._senderUuid ?? String()}
set {_uniqueStorage()._senderUuid = newValue}
}
/// Returns true if `senderUuid` has been explicitly set.
var hasSenderUuid: Bool {return _storage._senderUuid != nil}
/// Clears the value of `senderUuid`. Subsequent reads from it will return its default value.
mutating func clearSenderUuid() {_uniqueStorage()._senderUuid = nil}
/// @required
var senderDevice: UInt32 {
@ -143,7 +151,7 @@ struct SMKProtos_SenderCertificate {
/// Returns true if `senderDevice` has been explicitly set.
var hasSenderDevice: Bool {return _storage._senderDevice != nil}
/// Clears the value of `senderDevice`. Subsequent reads from it will return its default value.
mutating func clearSenderDevice() {_storage._senderDevice = nil}
mutating func clearSenderDevice() {_uniqueStorage()._senderDevice = nil}
/// @required
var expires: UInt64 {
@ -153,7 +161,7 @@ struct SMKProtos_SenderCertificate {
/// Returns true if `expires` has been explicitly set.
var hasExpires: Bool {return _storage._expires != nil}
/// Clears the value of `expires`. Subsequent reads from it will return its default value.
mutating func clearExpires() {_storage._expires = nil}
mutating func clearExpires() {_uniqueStorage()._expires = nil}
/// @required
var identityKey: Data {
@ -163,7 +171,7 @@ struct SMKProtos_SenderCertificate {
/// Returns true if `identityKey` has been explicitly set.
var hasIdentityKey: Bool {return _storage._identityKey != nil}
/// Clears the value of `identityKey`. Subsequent reads from it will return its default value.
mutating func clearIdentityKey() {_storage._identityKey = nil}
mutating func clearIdentityKey() {_uniqueStorage()._identityKey = nil}
/// @required
var signer: SMKProtos_ServerCertificate {
@ -173,7 +181,7 @@ struct SMKProtos_SenderCertificate {
/// Returns true if `signer` has been explicitly set.
var hasSigner: Bool {return _storage._signer != nil}
/// Clears the value of `signer`. Subsequent reads from it will return its default value.
mutating func clearSigner() {_storage._signer = nil}
mutating func clearSigner() {_uniqueStorage()._signer = nil}
var unknownFields = SwiftProtobuf.UnknownStorage()
@ -230,7 +238,6 @@ struct SMKProtos_UnidentifiedSenderMessage {
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// @required
var type: SMKProtos_UnidentifiedSenderMessage.Message.TypeEnum {
get {return _storage._type ?? .prekeyMessage}
set {_uniqueStorage()._type = newValue}
@ -238,7 +245,7 @@ struct SMKProtos_UnidentifiedSenderMessage {
/// Returns true if `type` has been explicitly set.
var hasType: Bool {return _storage._type != nil}
/// Clears the value of `type`. Subsequent reads from it will return its default value.
mutating func clearType() {_storage._type = nil}
mutating func clearType() {_uniqueStorage()._type = nil}
/// @required
var senderCertificate: SMKProtos_SenderCertificate {
@ -248,7 +255,7 @@ struct SMKProtos_UnidentifiedSenderMessage {
/// Returns true if `senderCertificate` has been explicitly set.
var hasSenderCertificate: Bool {return _storage._senderCertificate != nil}
/// Clears the value of `senderCertificate`. Subsequent reads from it will return its default value.
mutating func clearSenderCertificate() {_storage._senderCertificate = nil}
mutating func clearSenderCertificate() {_uniqueStorage()._senderCertificate = nil}
/// @required
var content: Data {
@ -258,7 +265,7 @@ struct SMKProtos_UnidentifiedSenderMessage {
/// Returns true if `content` has been explicitly set.
var hasContent: Bool {return _storage._content != nil}
/// Clears the value of `content`. Subsequent reads from it will return its default value.
mutating func clearContent() {_storage._content = nil}
mutating func clearContent() {_uniqueStorage()._content = nil}
var unknownFields = SwiftProtobuf.UnknownStorage()
@ -331,10 +338,10 @@ extension SMKProtos_ServerCertificate: SwiftProtobuf.Message, SwiftProtobuf._Mes
try unknownFields.traverse(visitor: &visitor)
}
func _protobuf_generated_isEqualTo(other: SMKProtos_ServerCertificate) -> Bool {
if self._certificate != other._certificate {return false}
if self._signature != other._signature {return false}
if unknownFields != other.unknownFields {return false}
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
}
}
@ -366,10 +373,10 @@ extension SMKProtos_ServerCertificate.Certificate: SwiftProtobuf.Message, SwiftP
try unknownFields.traverse(visitor: &visitor)
}
func _protobuf_generated_isEqualTo(other: SMKProtos_ServerCertificate.Certificate) -> Bool {
if self._id != other._id {return false}
if self._key != other._key {return false}
if unknownFields != other.unknownFields {return false}
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
}
}
@ -401,10 +408,10 @@ extension SMKProtos_SenderCertificate: SwiftProtobuf.Message, SwiftProtobuf._Mes
try unknownFields.traverse(visitor: &visitor)
}
func _protobuf_generated_isEqualTo(other: SMKProtos_SenderCertificate) -> Bool {
if self._certificate != other._certificate {return false}
if self._signature != other._signature {return false}
if unknownFields != other.unknownFields {return false}
static func ==(lhs: SMKProtos_SenderCertificate, rhs: SMKProtos_SenderCertificate) -> Bool {
if lhs._certificate != rhs._certificate {return false}
if lhs._signature != rhs._signature {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
@ -412,7 +419,8 @@ extension SMKProtos_SenderCertificate: SwiftProtobuf.Message, SwiftProtobuf._Mes
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"),
1: .same(proto: "senderE164"),
6: .same(proto: "senderUuid"),
2: .same(proto: "senderDevice"),
3: .same(proto: "expires"),
4: .same(proto: "identityKey"),
@ -420,7 +428,8 @@ extension SMKProtos_SenderCertificate.Certificate: SwiftProtobuf.Message, SwiftP
]
fileprivate class _StorageClass {
var _sender: String? = nil
var _senderE164: String? = nil
var _senderUuid: String? = nil
var _senderDevice: UInt32? = nil
var _expires: UInt64? = nil
var _identityKey: Data? = nil
@ -431,7 +440,8 @@ extension SMKProtos_SenderCertificate.Certificate: SwiftProtobuf.Message, SwiftP
private init() {}
init(copying source: _StorageClass) {
_sender = source._sender
_senderE164 = source._senderE164
_senderUuid = source._senderUuid
_senderDevice = source._senderDevice
_expires = source._expires
_identityKey = source._identityKey
@ -451,11 +461,12 @@ extension SMKProtos_SenderCertificate.Certificate: SwiftProtobuf.Message, SwiftP
try withExtendedLifetime(_storage) { (_storage: _StorageClass) in
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularStringField(value: &_storage._sender)
case 1: try decoder.decodeSingularStringField(value: &_storage._senderE164)
case 2: try decoder.decodeSingularUInt32Field(value: &_storage._senderDevice)
case 3: try decoder.decodeSingularFixed64Field(value: &_storage._expires)
case 4: try decoder.decodeSingularBytesField(value: &_storage._identityKey)
case 5: try decoder.decodeSingularMessageField(value: &_storage._signer)
case 6: try decoder.decodeSingularStringField(value: &_storage._senderUuid)
default: break
}
}
@ -464,7 +475,7 @@ extension SMKProtos_SenderCertificate.Certificate: SwiftProtobuf.Message, SwiftP
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
try withExtendedLifetime(_storage) { (_storage: _StorageClass) in
if let v = _storage._sender {
if let v = _storage._senderE164 {
try visitor.visitSingularStringField(value: v, fieldNumber: 1)
}
if let v = _storage._senderDevice {
@ -479,25 +490,29 @@ extension SMKProtos_SenderCertificate.Certificate: SwiftProtobuf.Message, SwiftP
if let v = _storage._signer {
try visitor.visitSingularMessageField(value: v, fieldNumber: 5)
}
if let v = _storage._senderUuid {
try visitor.visitSingularStringField(value: v, fieldNumber: 6)
}
}
try unknownFields.traverse(visitor: &visitor)
}
func _protobuf_generated_isEqualTo(other: SMKProtos_SenderCertificate.Certificate) -> Bool {
if _storage !== other._storage {
let storagesAreEqual: Bool = withExtendedLifetime((_storage, other._storage)) { (_args: (_StorageClass, _StorageClass)) in
static func ==(lhs: SMKProtos_SenderCertificate.Certificate, rhs: SMKProtos_SenderCertificate.Certificate) -> Bool {
if lhs._storage !== rhs._storage {
let storagesAreEqual: Bool = withExtendedLifetime((lhs._storage, rhs._storage)) { (_args: (_StorageClass, _StorageClass)) in
let _storage = _args.0
let other_storage = _args.1
if _storage._sender != other_storage._sender {return false}
if _storage._senderDevice != other_storage._senderDevice {return false}
if _storage._expires != other_storage._expires {return false}
if _storage._identityKey != other_storage._identityKey {return false}
if _storage._signer != other_storage._signer {return false}
let rhs_storage = _args.1
if _storage._senderE164 != rhs_storage._senderE164 {return false}
if _storage._senderUuid != rhs_storage._senderUuid {return false}
if _storage._senderDevice != rhs_storage._senderDevice {return false}
if _storage._expires != rhs_storage._expires {return false}
if _storage._identityKey != rhs_storage._identityKey {return false}
if _storage._signer != rhs_storage._signer {return false}
return true
}
if !storagesAreEqual {return false}
}
if unknownFields != other.unknownFields {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
@ -534,11 +549,11 @@ extension SMKProtos_UnidentifiedSenderMessage: SwiftProtobuf.Message, SwiftProto
try unknownFields.traverse(visitor: &visitor)
}
func _protobuf_generated_isEqualTo(other: SMKProtos_UnidentifiedSenderMessage) -> Bool {
if self._ephemeralPublic != other._ephemeralPublic {return false}
if self._encryptedStatic != other._encryptedStatic {return false}
if self._encryptedMessage != other._encryptedMessage {return false}
if unknownFields != other.unknownFields {return false}
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
}
}
@ -603,19 +618,19 @@ extension SMKProtos_UnidentifiedSenderMessage.Message: SwiftProtobuf.Message, Sw
try unknownFields.traverse(visitor: &visitor)
}
func _protobuf_generated_isEqualTo(other: SMKProtos_UnidentifiedSenderMessage.Message) -> Bool {
if _storage !== other._storage {
let storagesAreEqual: Bool = withExtendedLifetime((_storage, other._storage)) { (_args: (_StorageClass, _StorageClass)) in
static func ==(lhs: SMKProtos_UnidentifiedSenderMessage.Message, rhs: SMKProtos_UnidentifiedSenderMessage.Message) -> Bool {
if lhs._storage !== rhs._storage {
let storagesAreEqual: Bool = withExtendedLifetime((lhs._storage, rhs._storage)) { (_args: (_StorageClass, _StorageClass)) in
let _storage = _args.0
let other_storage = _args.1
if _storage._type != other_storage._type {return false}
if _storage._senderCertificate != other_storage._senderCertificate {return false}
if _storage._content != other_storage._content {return false}
let rhs_storage = _args.1
if _storage._type != rhs_storage._type {return false}
if _storage._senderCertificate != rhs_storage._senderCertificate {return false}
if _storage._content != rhs_storage._content {return false}
return true
}
if !storagesAreEqual {return false}
}
if unknownFields != other.unknownFields {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}

View File

@ -1,8 +1,9 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
import Foundation
import SignalCoreKit
// WARNING: This code is generated. Only edit within the markers.
@ -20,6 +21,12 @@ public enum SMKProtoError: Error {
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()
@ -94,6 +101,10 @@ public enum SMKProtoError: Error {
key: key)
return result
}
@objc public override var debugDescription: String {
return "\(proto)"
}
}
#if DEBUG
@ -122,6 +133,12 @@ extension SMKProtoServerCertificateCertificate.SMKProtoServerCertificateCertific
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()
@ -196,6 +213,10 @@ extension SMKProtoServerCertificateCertificate.SMKProtoServerCertificateCertific
signature: signature)
return result
}
@objc public override var debugDescription: String {
return "\(proto)"
}
}
#if DEBUG
@ -220,8 +241,20 @@ extension SMKProtoServerCertificate.SMKProtoServerCertificateBuilder {
// 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)
@objc public class func builder(senderDevice: UInt32, expires: UInt64, identityKey: Data, signer: SMKProtoServerCertificate) -> SMKProtoSenderCertificateCertificateBuilder {
return SMKProtoSenderCertificateCertificateBuilder(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(senderDevice: senderDevice, expires: expires, identityKey: identityKey, signer: signer)
if let _value = senderE164 {
builder.setSenderE164(_value)
}
if let _value = senderUuid {
builder.setSenderUuid(_value)
}
return builder
}
@objc public class SMKProtoSenderCertificateCertificateBuilder: NSObject {
@ -230,18 +263,21 @@ extension SMKProtoServerCertificate.SMKProtoServerCertificateBuilder {
@objc fileprivate override init() {}
@objc fileprivate init(sender: String, senderDevice: UInt32, expires: UInt64, identityKey: Data, signer: SMKProtoServerCertificate) {
@objc fileprivate init(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 setSenderE164(_ valueParam: String) {
proto.senderE164 = valueParam
}
@objc public func setSenderUuid(_ valueParam: String) {
proto.senderUuid = valueParam
}
@objc public func setSenderDevice(_ valueParam: UInt32) {
@ -271,8 +307,6 @@ extension SMKProtoServerCertificate.SMKProtoServerCertificateBuilder {
fileprivate let proto: SMKProtos_SenderCertificate.Certificate
@objc public let sender: String
@objc public let senderDevice: UInt32
@objc public let expires: UInt64
@ -281,14 +315,32 @@ extension SMKProtoServerCertificate.SMKProtoServerCertificateBuilder {
@objc public let signer: SMKProtoServerCertificate
@objc public var senderE164: String? {
guard proto.hasSenderE164 else {
return nil
}
return proto.senderE164
}
@objc public var hasSenderE164: Bool {
return proto.hasSenderE164
}
@objc public var senderUuid: String? {
guard proto.hasSenderUuid else {
return nil
}
return proto.senderUuid
}
@objc public var hasSenderUuid: Bool {
return proto.hasSenderUuid
}
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
@ -306,11 +358,6 @@ extension SMKProtoServerCertificate.SMKProtoServerCertificateBuilder {
}
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")
}
@ -336,13 +383,16 @@ extension SMKProtoServerCertificate.SMKProtoServerCertificateBuilder {
// 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
@ -371,6 +421,12 @@ extension SMKProtoSenderCertificateCertificate.SMKProtoSenderCertificateCertific
return SMKProtoSenderCertificateBuilder(certificate: certificate, signature: signature)
}
// asBuilder() constructs a builder that reflects the proto's contents.
@objc public func asBuilder() -> SMKProtoSenderCertificateBuilder {
let builder = SMKProtoSenderCertificateBuilder(certificate: certificate, signature: signature)
return builder
}
@objc public class SMKProtoSenderCertificateBuilder: NSObject {
private var proto = SMKProtos_SenderCertificate()
@ -445,6 +501,10 @@ extension SMKProtoSenderCertificateCertificate.SMKProtoSenderCertificateCertific
signature: signature)
return result
}
@objc public override var debugDescription: String {
return "\(proto)"
}
}
#if DEBUG
@ -490,8 +550,17 @@ extension SMKProtoSenderCertificate.SMKProtoSenderCertificateBuilder {
// MARK: - SMKProtoUnidentifiedSenderMessageMessageBuilder
@objc public class func builder(type: SMKProtoUnidentifiedSenderMessageMessageType, senderCertificate: SMKProtoSenderCertificate, content: Data) -> SMKProtoUnidentifiedSenderMessageMessageBuilder {
return SMKProtoUnidentifiedSenderMessageMessageBuilder(type: type, senderCertificate: senderCertificate, content: content)
@objc public class func builder(senderCertificate: SMKProtoSenderCertificate, content: Data) -> SMKProtoUnidentifiedSenderMessageMessageBuilder {
return SMKProtoUnidentifiedSenderMessageMessageBuilder(senderCertificate: senderCertificate, content: content)
}
// asBuilder() constructs a builder that reflects the proto's contents.
@objc public func asBuilder() -> SMKProtoUnidentifiedSenderMessageMessageBuilder {
let builder = SMKProtoUnidentifiedSenderMessageMessageBuilder(senderCertificate: senderCertificate, content: content)
if let _value = type {
builder.setType(_value)
}
return builder
}
@objc public class SMKProtoUnidentifiedSenderMessageMessageBuilder: NSObject {
@ -500,10 +569,9 @@ extension SMKProtoSenderCertificate.SMKProtoSenderCertificateBuilder {
@objc fileprivate override init() {}
@objc fileprivate init(type: SMKProtoUnidentifiedSenderMessageMessageType, senderCertificate: SMKProtoSenderCertificate, content: Data) {
@objc fileprivate init(senderCertificate: SMKProtoSenderCertificate, content: Data) {
super.init()
setType(type)
setSenderCertificate(senderCertificate)
setContent(content)
}
@ -531,18 +599,32 @@ extension SMKProtoSenderCertificate.SMKProtoSenderCertificateBuilder {
fileprivate let proto: SMKProtos_UnidentifiedSenderMessage.Message
@objc public let type: SMKProtoUnidentifiedSenderMessageMessageType
@objc public let senderCertificate: SMKProtoSenderCertificate
@objc public let content: Data
public var type: SMKProtoUnidentifiedSenderMessageMessageType? {
guard proto.hasType else {
return nil
}
return SMKProtoUnidentifiedSenderMessageMessage.SMKProtoUnidentifiedSenderMessageMessageTypeWrap(proto.type)
}
// This "unwrapped" accessor should only be used if the "has value" accessor has already been checked.
@objc public var unwrappedType: SMKProtoUnidentifiedSenderMessageMessageType {
if !hasType {
// TODO: We could make this a crashing assert.
owsFailDebug("Unsafe unwrap of missing optional: Message.type.")
}
return SMKProtoUnidentifiedSenderMessageMessage.SMKProtoUnidentifiedSenderMessageMessageTypeWrap(proto.type)
}
@objc public var hasType: Bool {
return proto.hasType
}
private init(proto: SMKProtos_UnidentifiedSenderMessage.Message,
type: SMKProtoUnidentifiedSenderMessageMessageType,
senderCertificate: SMKProtoSenderCertificate,
content: Data) {
self.proto = proto
self.type = type
self.senderCertificate = senderCertificate
self.content = content
}
@ -558,11 +640,6 @@ extension SMKProtoSenderCertificate.SMKProtoSenderCertificateBuilder {
}
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")
}
@ -578,11 +655,14 @@ extension SMKProtoSenderCertificate.SMKProtoSenderCertificateBuilder {
// 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
@ -611,6 +691,12 @@ extension SMKProtoUnidentifiedSenderMessageMessage.SMKProtoUnidentifiedSenderMes
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()
@ -700,6 +786,10 @@ extension SMKProtoUnidentifiedSenderMessageMessage.SMKProtoUnidentifiedSenderMes
encryptedMessage: encryptedMessage)
return result
}
@objc public override var debugDescription: String {
return "\(proto)"
}
}
#if DEBUG

View File

@ -1,7 +1,11 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
// Copyright (c) 2020 Open Whisper Systems. All rights reserved.
//
#import <Foundation/NSData.h>
NS_ASSUME_NONNULL_BEGIN
@interface NSData (messagePadding)
- (NSData *)removePadding;
@ -9,3 +13,5 @@
- (NSData *)paddedMessageBody;
@end
NS_ASSUME_NONNULL_END

View File

@ -1,10 +0,0 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import <AxolotlKit/AxolotlStore.h>
#import <Curve25519Kit/Curve25519.h>
#import <Foundation/Foundation.h>
#import <SignalCoreKit/NSObject+OWS.h>
#import <SignalCoreKit/OWSAsserts.h>
#import <HKDFKit/HKDFKit.h>

View File

@ -0,0 +1,70 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
import Foundation
public enum SMKAddress {
case both(uuid: UUID, e164: String)
case uuid(_ uuid: UUID)
case e164(_ e164: String)
}
public extension SMKAddress {
init(uuid: UUID?, e164: String?) throws {
switch (uuid, e164) {
case (.some(let uuid), .some(let e164)):
self = .both(uuid: uuid, e164: e164)
case (.some(let uuid), .none):
self = .uuid(uuid)
case (.none, .some(let e164)):
self = .e164(e164)
case (.none, .none):
throw SMKError.invalidInput("had neither uuid nor e164")
}
}
var uuid: UUID? {
switch self {
case .both(let uuid, _):
return uuid
case .uuid(let uuid):
return uuid
case .e164:
return nil
}
}
var e164: String? {
switch self {
case .both(_, let e164):
return e164
case .uuid:
return nil
case .e164(let e164):
return e164
}
}
func matches(_ other: SMKAddress) -> Bool {
switch self {
case .both(let uuid, let e164):
if other.uuid == uuid || other.e164 == e164 {
// If one matches, then the other should also match
// if it's available
assert(other.uuid == uuid || other.uuid == nil)
assert(other.e164 == e164 || other.e164 == nil)
return true
} else {
return false
}
case .uuid(let uuid):
return other.uuid == uuid
case .e164(let e164):
return other.e164 == e164
}
}
}
extension SMKAddress: Equatable, Hashable { }

View File

@ -1,18 +1,19 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
// Copyright (c) 2021 Open Whisper Systems. All rights reserved.
//
import Foundation
import Curve25519Kit
import SignalCoreKit
import SignalClient
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
public protocol SMKCertificateValidator {
func throwswrapped_validate(senderCertificate: SenderCertificate, validationTime: UInt64) throws
func throwswrapped_validate(serverCertificate: ServerCertificate) throws
}
// See: https://github.com/signalapp/libsignal-metadata-java/blob/master/java/src/main/java/org/signal/libsignal/metadata/certificate/CertificateValidator.java
@ -25,7 +26,6 @@ public enum SMKCertificateError: Error {
// }};
private static let kRevokedCertificateIds = Set<UInt32>()
//
// private final ECPublicKey trustRoot;
private let trustRoot: ECPublicKey
@ -37,10 +37,10 @@ public enum SMKCertificateError: Error {
}
// public void validate(SenderCertificate certificate, long validationTime) throws InvalidCertificateException {
@objc public func throwswrapped_validate(senderCertificate: SMKSenderCertificate, validationTime: UInt64) throws {
public func throwswrapped_validate(senderCertificate: SenderCertificate, validationTime: UInt64) throws {
// try {
// ServerCertificate serverCertificate = certificate.getSigner();
let serverCertificate = senderCertificate.signer
let serverCertificate = senderCertificate.serverCertificate
// validate(serverCertificate);
try throwswrapped_validate(serverCertificate: serverCertificate)
@ -48,10 +48,8 @@ public enum SMKCertificateError: Error {
// 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 {
guard try serverCertificate.publicKey.verifySignature(message: senderCertificate.certificateBytes,
signature: senderCertificate.signatureBytes) else {
Logger.error("Sender certificate signature verification failed.")
let error = SMKCertificateError.invalidCertificate(description: "Sender certificate signature verification failed.")
Logger.error("\(error)")
@ -61,7 +59,7 @@ public enum SMKCertificateError: Error {
// if (validationTime > certificate.getExpiration()) {
// throw new InvalidCertificateException("Certificate is expired");
// }
guard validationTime <= senderCertificate.expirationTimestamp else {
guard validationTime <= senderCertificate.expiration else {
let error = SMKCertificateError.invalidCertificate(description: "Certficate is expired.")
Logger.error("\(error)")
throw error
@ -72,35 +70,30 @@ public enum SMKCertificateError: Error {
// }
}
// // 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
// void validate(ServerCertificate certificate) throws InvalidCertificateException {
public func throwswrapped_validate(serverCertificate: ServerCertificate) throws {
// try {
// if (!Curve.verifySignature(trustRoot, certificate.getCertificate(), certificate.getSignature())) {
// throw new InvalidCertificateException("Signature failed");
// }
guard try trustRoot.key.verifySignature(message: serverCertificate.certificateBytes,
signature: serverCertificate.signatureBytes) 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");
// }
// 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);
// }
// } catch (InvalidKeyException e) {
// throw new InvalidCertificateException(e);
// }
}
}

View File

@ -6,4 +6,5 @@ import Foundation
public enum SMKError: Error {
case assertionError(description: String)
case invalidInput(_ description: String)
}

View File

@ -1,40 +1,37 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
// Copyright (c) 2020 Open Whisper Systems. All rights reserved.
//
import Foundation
import Curve25519Kit
import SignalCoreKit
import SignalClient
public struct SecretSessionKnownSenderError: Error {
public let senderAddress: SMKAddress
public let senderDeviceId: UInt32
public let cipherType: CiphertextMessage.MessageType
public let groupId: Data?
public let unsealedContent: Data
public let contentHint: UnidentifiedSenderMessageContent.ContentHint
public let underlyingError: Error
init(messageContent: UnidentifiedSenderMessageContent, underlyingError: Error) {
self.senderAddress = SMKAddress(messageContent.senderCertificate.sender)
self.senderDeviceId = messageContent.senderCertificate.sender.deviceId
self.cipherType = messageContent.messageType
self.groupId = messageContent.groupId.map { Data($0) }
self.unsealedContent = Data(messageContent.contents)
self.contentHint = messageContent.contentHint
self.underlyingError = underlyingError
}
}
@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 {
@ -78,19 +75,35 @@ private class SMKStaticKeys: NSObject {
// MARK: -
@objc public enum SMKMessageType: Int {
case whisper
case prekey
case senderKey
case plaintext
}
@objc
public class SMKDecryptResult: NSObject {
@objc public let senderRecipientId: String
public let senderAddress: SMKAddress
@objc public var senderE164: String? {
return senderAddress.e164
}
@objc public var senderUuid: UUID? {
return senderAddress.uuid
}
@objc public let senderDeviceId: Int
@objc public let paddedPayload: Data
@objc public let messageType: SMKMessageType
init(senderRecipientId: String,
init(senderAddress: SMKAddress,
senderDeviceId: Int,
paddedPayload: Data,
messageType: SMKMessageType) {
self.senderRecipientId = senderRecipientId
self.senderAddress = senderAddress
self.senderDeviceId = senderDeviceId
self.paddedPayload = paddedPayload
self.messageType = messageType
@ -99,6 +112,39 @@ public class SMKDecryptResult: NSObject {
// MARK: -
fileprivate extension ProtocolAddress {
convenience init(from recipientAddress: SMKAddress, deviceId: UInt32) throws {
try self.init(name: recipientAddress.uuid?.uuidString ?? recipientAddress.e164!, deviceId: deviceId)
}
convenience init(from senderAddress: SealedSenderAddress) throws {
try self.init(name: senderAddress.uuidString, deviceId: senderAddress.deviceId)
}
}
fileprivate extension SMKAddress {
init(_ address: SealedSenderAddress) {
try! self.init(uuid: UUID(uuidString: address.uuidString), e164: address.e164)
}
}
fileprivate extension SMKMessageType {
init(_ messageType: CiphertextMessage.MessageType) {
switch messageType {
case .whisper:
self = .whisper
case .preKey:
self = .prekey
case .senderKey:
self = .senderKey
case .plaintext:
self = .plaintext
default:
fatalError("not ready for other kinds of messages yet")
}
}
}
@objc public class SMKSecretSessionCipher: NSObject {
private let kUDPrefixString = "UnidentifiedDelivery"
@ -109,355 +155,147 @@ public class SMKDecryptResult: NSObject {
private let preKeyStore: PreKeyStore
private let signedPreKeyStore: SignedPreKeyStore
private let identityStore: IdentityKeyStore
private let senderKeyStore: SenderKeyStore
// public SecretSessionCipher(SignalProtocolStore signalProtocolStore) {
@objc public init(sessionStore: SessionStore,
preKeyStore: PreKeyStore,
signedPreKeyStore: SignedPreKeyStore,
identityStore: IdentityKeyStore) throws {
public init(sessionStore: SessionStore,
preKeyStore: PreKeyStore,
signedPreKeyStore: SignedPreKeyStore,
identityStore: IdentityKeyStore,
senderKeyStore: SenderKeyStore) throws {
self.sessionStore = sessionStore
self.preKeyStore = preKeyStore
self.signedPreKeyStore = signedPreKeyStore
self.identityStore = identityStore
self.senderKeyStore = senderKeyStore
}
// MARK: - Public
// public byte[] encrypt(SignalProtocolAddress destinationAddress, SenderCertificate senderCertificate, byte[]
// paddedPlaintext)
@objc
public func throwswrapped_encryptMessage(recipientId: String,
deviceId: Int32,
paddedPlaintext: Data,
senderCertificate: SMKSenderCertificate,
protocolContext: Any?) throws -> Data {
guard recipientId.count > 0 else {
throw SMKError.assertionError(description: "\(SMKSecretSessionCipher.logTag) invalid recipientId")
}
public func encryptMessage(
recipient: SMKAddress,
deviceId: Int32,
paddedPlaintext: Data,
contentHint: UnidentifiedSenderMessageContent.ContentHint,
groupId: Data?,
senderCertificate: SenderCertificate,
protocolContext: StoreContext
) throws -> Data {
guard deviceId > 0 else {
throw SMKError.assertionError(description: "\(SMKSecretSessionCipher.logTag) invalid deviceId")
throw SMKError.assertionError(description: "\(logTag) invalid deviceId")
}
let recipientAddress = try ProtocolAddress(from: recipient, deviceId: UInt32(bitPattern: deviceId))
// CiphertextMessage message = new SessionCipher(signalProtocolStore, destinationAddress).encrypt(paddedPlaintext);
let cipher = SessionCipher(sessionStore: sessionStore,
preKeyStore: preKeyStore,
signedPreKeyStore: signedPreKeyStore,
identityKeyStore: identityStore,
recipientId: recipientId,
deviceId: deviceId)
// CiphertextMessage message = new SessionCipher(signalProtocolStore, destinationAddress).encrypt(paddedPlaintext);
let encryptedMessage = try cipher.encryptMessage(paddedPlaintext, protocolContext: protocolContext)
let ciphertextMessage = try signalEncrypt(
message: paddedPlaintext,
for: recipientAddress,
sessionStore: sessionStore,
identityStore: identityStore,
context: protocolContext)
guard let encryptedMessageData = encryptedMessage.serialized() else {
throw SMKError.assertionError(description: "\(logTag) Could not serialize encrypted message.")
}
let usmc = try UnidentifiedSenderMessageContent(
ciphertextMessage,
from: senderCertificate,
contentHint: contentHint,
groupId: groupId ?? Data())
// IdentityKeyPair ourIdentity = signalProtocolStore.getIdentityKeyPair();
guard let ourIdentityKeyPair = identityStore.identityKeyPair(protocolContext) else {
throw SMKError.assertionError(description: "\(logTag) Missing our identity key pair.")
}
let outerBytes = try sealedSenderEncrypt(
usmc,
for: recipientAddress,
identityStore: identityStore,
context: protocolContext)
// ECPublicKey theirIdentity = signalProtocolStore.getIdentity(destinationAddress).getPublicKey();
guard let theirIdentityKeyData = identityStore.identityKey(forRecipientId: recipientId, protocolContext: protocolContext) 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)
// ECKeyPair ephemeral = Curve.generateKeyPair();
let ephemeral = Curve25519.generateKeyPair()
// byte[] ephemeralSalt = ByteUtil.combine("UnidentifiedDelivery".getBytes(), theirIdentity.serialize(),
// ephemeral.getPublicKey().serialize());
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
])
// EphemeralKeys ephemeralKeys = calculateEphemeralKeys(theirIdentity, ephemeral.getPrivateKey(), ephemeralSalt);
let ephemeralKeys = try throwswrapped_calculateEphemeralKeys(ephemeralPublicKey: theirIdentityKey,
ephemeralPrivateKey: ephemeral.ecPrivateKey(),
salt: ephemeralSalt)
// byte[] staticKeyCiphertext = encrypt(ephemeralKeys.cipherKey, ephemeralKeys.macKey,
// ourIdentity.getPublicKey().getPublicKey().serialize());
let staticKeyCipherData = try encrypt(cipherKey: ephemeralKeys.cipherKey,
macKey: ephemeralKeys.macKey,
plaintextData: ourIdentityKeyPair.ecPublicKey().serialized)
// byte[] staticSalt = ByteUtil.combine(ephemeralKeys.chainKey, staticKeyCiphertext);
let staticSalt = NSData.join([
ephemeralKeys.chainKey,
staticKeyCipherData
])
// StaticKeys staticKeys = calculateStaticKeys(theirIdentity, ourIdentity.getPrivateKey(), staticSalt);
let staticKeys = try throwswrapped_calculateStaticKeys(staticPublicKey: theirIdentityKey,
staticPrivateKey: ourIdentityKeyPair.ecPrivateKey(),
salt: staticSalt)
// UnidentifiedSenderMessageContent content = new UnidentifiedSenderMessageContent(message.getType(),
// senderCertificate, message.serialize());
var messageType: SMKMessageType
switch encryptedMessage.cipherMessageType {
case .prekey:
messageType = .prekey
case .whisper:
messageType = .whisper
default:
throw SMKError.assertionError(description: "\(logTag) Unknown cipher message type.")
}
let messageContent = SMKUnidentifiedSenderMessageContent(messageType: messageType,
senderCertificate: senderCertificate,
contentData: encryptedMessageData)
// byte[] messageBytes = encrypt(staticKeys.cipherKey, staticKeys.macKey, content.getSerialized());
let messageData = try encrypt(cipherKey: staticKeys.cipherKey,
macKey: staticKeys.macKey,
plaintextData: try messageContent.serialized())
// return new UnidentifiedSenderMessage(ephemeral.getPublicKey(), staticKeyCiphertext,
// messageBytes).getSerialized();
let message = SMKUnidentifiedSenderMessage(ephemeralKey: try ephemeral.ecPublicKey(),
encryptedStatic: staticKeyCipherData,
encryptedMessage: messageData)
return try message.serialized()
return Data(outerBytes)
}
// public Pair<SignalProtocolAddress, byte[]> decrypt(CertificateValidator validator, byte[] ciphertext, long
/// timestamp) /throws /InvalidMetadataMessageException, InvalidMetadataVersionException,
// ProtocolInvalidMessageException, ProtocolInvalidKeyException,
// ProtocolNoSessionException, ProtocolLegacyMessageException,
// ProtocolInvalidVersionException, ProtocolDuplicateMessageException,
// ProtocolInvalidKeyIdException, ProtocolUntrustedIdentityException
@objc
public func groupEncryptMessage(recipients: [ProtocolAddress],
paddedPlaintext: Data,
senderCertificate: SenderCertificate,
groupId: Data,
distributionId: UUID,
contentHint: UnidentifiedSenderMessageContent.ContentHint = .default,
protocolContext: StoreContext?) throws -> Data {
let senderAddress = try ProtocolAddress(from: senderCertificate.sender)
let ciphertext = try groupEncrypt(
paddedPlaintext,
from: senderAddress,
distributionId: distributionId,
store: senderKeyStore,
context: protocolContext ?? NullContext())
let udMessageContent = try UnidentifiedSenderMessageContent(
ciphertext,
from: senderCertificate,
contentHint: contentHint,
groupId: groupId)
let multiRecipientMessage = try sealedSenderMultiRecipientEncrypt(
udMessageContent,
for: recipients,
identityStore: identityStore,
sessionStore: sessionStore,
context: protocolContext ?? NullContext())
return Data(multiRecipientMessage)
}
// public Pair<SignalProtocolAddress, byte[]> decrypt(CertificateValidator validator, byte[] ciphertext, long timestamp)
// throws InvalidMetadataMessageException, InvalidMetadataVersionException, ProtocolInvalidMessageException, ProtocolInvalidKeyException, ProtocolNoSessionException, ProtocolLegacyMessageException, ProtocolInvalidVersionException, ProtocolDuplicateMessageException, ProtocolInvalidKeyIdException, ProtocolUntrustedIdentityException
public func throwswrapped_decryptMessage(certificateValidator: SMKCertificateValidator,
cipherTextData: Data,
timestamp: UInt64,
localRecipientId: String,
localDeviceId: Int32,
protocolContext: Any?) throws -> SMKDecryptResult {
cipherTextData: Data,
timestamp: UInt64,
localE164: String?,
localUuid: UUID?,
localDeviceId: Int32,
protocolContext: StoreContext?) throws -> SMKDecryptResult {
guard timestamp > 0 else {
throw SMKError.assertionError(description: "\(logTag) invalid timestamp")
}
guard timestamp > 0 else {
throw SMKError.assertionError(description: "\(logTag) invalid timestamp")
}
// Allow nil contexts for testing.
let context = protocolContext ?? NullContext()
let messageContent = try UnidentifiedSenderMessageContent(message: cipherTextData,
identityStore: self.identityStore,
context: context)
// IdentityKeyPair ourIdentity = signalProtocolStore.getIdentityKeyPair();
guard let ourIdentityKeyPair = identityStore.identityKeyPair(protocolContext) else {
throw SMKError.assertionError(description: "\(logTag) Missing our identity key pair.")
}
let senderAddress = messageContent.senderCertificate.sender
let localAddress = try SMKAddress(uuid: localUuid, e164: localE164)
// UnidentifiedSenderMessage wrapper = new UnidentifiedSenderMessage(ciphertext);
let wrapper = try SMKUnidentifiedSenderMessage.parse(dataAndPrefix: cipherTextData)
// byte[] ephemeralSalt = ByteUtil.combine("UnidentifiedDelivery".getBytes(),
// ourIdentity.getPublicKey().getPublicKey().serialize(), wrapper.getEphemeral().serialize());
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
])
// EphemeralKeys ephemeralKeys = calculateEphemeralKeys(wrapper.getEphemeral(), ourIdentity.getPrivateKey(),
// ephemeralSalt);
let ephemeralKeys = try throwswrapped_calculateEphemeralKeys(ephemeralPublicKey: wrapper.ephemeralKey,
ephemeralPrivateKey: ourIdentityKeyPair.ecPrivateKey(),
salt: ephemeralSalt)
// byte[] staticKeyBytes = decrypt(ephemeralKeys.cipherKey, ephemeralKeys.macKey, wrapper.getEncryptedStatic());
let staticKeyBytes = try decrypt(cipherKey: ephemeralKeys.cipherKey,
macKey: ephemeralKeys.macKey,
cipherTextWithMac: wrapper.encryptedStatic)
// ECPublicKey staticKey = Curve.decodePoint(staticKeyBytes, 0);
let staticKey = try ECPublicKey(serializedKeyData: staticKeyBytes)
// byte[] staticSalt = ByteUtil.combine(ephemeralKeys.chainKey, wrapper.getEncryptedStatic());
let staticSalt = NSData.join([
ephemeralKeys.chainKey,
wrapper.encryptedStatic
])
// StaticKeys staticKeys = calculateStaticKeys(staticKey, ourIdentity.getPrivateKey(), staticSalt);
let staticKeys = try throwswrapped_calculateStaticKeys(staticPublicKey: staticKey,
staticPrivateKey: ourIdentityKeyPair.ecPrivateKey(),
salt: staticSalt)
// byte[] messageBytes = decrypt(staticKeys.cipherKey, staticKeys.macKey, wrapper.getEncryptedMessage());
let messageBytes = try decrypt(cipherKey: staticKeys.cipherKey,
macKey: staticKeys.macKey,
cipherTextWithMac: wrapper.encryptedMessage)
// content = new UnidentifiedSenderMessageContent(messageBytes);
let messageContent = try SMKUnidentifiedSenderMessageContent.parse(data: messageBytes)
guard messageContent.senderCertificate.senderRecipientId != localRecipientId ||
messageContent.senderCertificate.senderDeviceId != localDeviceId else {
Logger.info("Discarding self-sent message")
throw SMKSecretSessionCipherError.selfSentMessage
}
guard !SMKAddress(senderAddress).matches(localAddress) ||
Int32(bitPattern: senderAddress.deviceId) != localDeviceId else {
Logger.info("Discarding self-sent message")
throw SMKSecretSessionCipherError.selfSentMessage
}
do {
// validator.validate(content.getSenderCertificate(), timestamp);
try certificateValidator.throwswrapped_validate(senderCertificate: messageContent.senderCertificate,
validationTime: timestamp)
try certificateValidator.throwswrapped_validate(
senderCertificate: messageContent.senderCertificate,
validationTime: timestamp)
// 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 {
throw SMKError.assertionError(description: "\(logTag) Sender's certificate key does not match key used in message.")
}
let paddedMessagePlaintext = try throwswrapped_decrypt(messageContent: messageContent, protocolContext: protocolContext)
let paddedMessagePlaintext = try throwswrapped_decrypt(messageContent: messageContent,
context: context)
// return new Pair<>(new SignalProtocolAddress(content.getSenderCertificate().getSender(),
// content.getSenderCertificate().getSenderDeviceId()),
// decrypt(content));
// content.getSenderCertificate().getSenderDeviceId()),
// decrypt(content));
//
// 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 <= INT_MAX else {
guard senderAddress.deviceId <= Int32.max else {
throw SMKError.assertionError(description: "\(logTag) Invalid senderDeviceId.")
}
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")
return SMKDecryptResult(senderAddress: SMKAddress(senderAddress),
senderDeviceId: Int(senderAddress.deviceId),
paddedPayload: Data(paddedMessagePlaintext),
messageType: SMKMessageType(messageContent.messageType))
} catch {
throw SecretSessionKnownSenderError(messageContent: messageContent,
underlyingError: error)
}
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 ephemeralSecret = try Curve25519.generateSharedSecret(fromPublicKey: ephemeralPublicKey.keyData, privateKey: ephemeralPrivateKey.keyData)
// 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 staticSecret = try Curve25519.generateSharedSecret(fromPublicKey: staticPublicKey.keyData, privateKey: staticPrivateKey.keyData)
// byte[] staticDerived = new HKDFv3().deriveSecrets(staticSecret, salt, new byte[0], 96);
let kStaticDerivedLength: UInt = 96
let staticDerived: Data =
try 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
@ -465,16 +303,15 @@ public class SMKDecryptResult: NSObject {
// private byte[] decrypt(UnidentifiedSenderMessageContent message)
// throws InvalidVersionException, InvalidMessageException, InvalidKeyException, DuplicateMessageException,
// InvalidKeyIdException, UntrustedIdentityException, LegacyMessageException, NoSessionException
private func throwswrapped_decrypt(messageContent: SMKUnidentifiedSenderMessageContent,
protocolContext: Any?) throws -> Data {
private func throwswrapped_decrypt(messageContent: UnidentifiedSenderMessageContent,
context: StoreContext) throws -> Data {
// SignalProtocolAddress sender = new SignalProtocolAddress(message.getSenderCertificate().getSender(),
// message.getSenderCertificate().getSenderDeviceId());
//
// 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 {
let sender = messageContent.senderCertificate.sender
guard sender.deviceId >= 0 && sender.deviceId <= Int32.max else {
throw SMKError.assertionError(description: "\(logTag) Invalid senderDeviceId.")
}
@ -484,82 +321,64 @@ public class SMKDecryptResult: NSObject {
// SessionCipher(signalProtocolStore, sender).decrypt(new PreKeySignalMessage(message.getContent())); default: throw
// new InvalidMessageException("Unknown type: " + message.getType());
// }
var cipherMessage: CipherMessage
switch (messageContent.messageType) {
let plaintextData: [UInt8]
switch messageContent.messageType {
case .whisper:
cipherMessage = try WhisperMessage(data: messageContent.contentData)
case .prekey:
cipherMessage = try PreKeyWhisperMessage(data: messageContent.contentData)
let cipherMessage = try SignalMessage(bytes: messageContent.contents)
plaintextData = try signalDecrypt(
message: cipherMessage,
from: ProtocolAddress(from: sender),
sessionStore: sessionStore,
identityStore: identityStore,
context: context)
case .preKey:
let cipherMessage = try PreKeySignalMessage(bytes: messageContent.contents)
plaintextData = try signalDecryptPreKey(
message: cipherMessage,
from: ProtocolAddress(from: sender),
sessionStore: sessionStore,
identityStore: identityStore,
preKeyStore: preKeyStore,
signedPreKeyStore: signedPreKeyStore,
context: context)
case .senderKey:
plaintextData = try groupDecrypt(
messageContent.contents,
from: ProtocolAddress(from: sender),
store: senderKeyStore,
context: context)
case .plaintext:
let plaintextMessage = try PlaintextContent(bytes: messageContent.contents)
plaintextData = plaintextMessage.body
case let unknownType:
throw SMKError.assertionError(
description: "\(logTag) Not prepared to handle this message type: \(unknownType.rawValue)")
}
let cipher = SessionCipher(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
return Data(plaintextData)
}
}
// MARK: - Internal for testing
extension SMKSecretSessionCipher {
// Only allow nil contexts for testing
func encryptMessage(
recipient: SMKAddress,
deviceId: Int32,
paddedPlaintext: Data,
contentHint: UnidentifiedSenderMessageContent.ContentHint = .default,
groupId: Data? = nil,
senderCertificate: SenderCertificate,
protocolContext: StoreContext? = nil
) throws -> Data {
try encryptMessage(
recipient: recipient,
deviceId: deviceId,
paddedPlaintext: paddedPlaintext,
contentHint: contentHint,
groupId: groupId,
senderCertificate: senderCertificate,
protocolContext: protocolContext ?? NullContext())
}
}

View File

@ -1,88 +0,0 @@
//
// 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 signer: SMKServerCertificate
@objc public let key: ECPublicKey
@objc public let senderDeviceId: UInt32
@objc public let senderRecipientId: String
@objc public let expirationTimestamp: UInt64
@objc public let signatureData: Data
@objc public init(signer: SMKServerCertificate,
key: ECPublicKey,
senderDeviceId: UInt32,
senderRecipientId: String,
expirationTimestamp: UInt64,
signatureData: Data) {
self.signer = signer
self.key = key
self.senderDeviceId = senderDeviceId
self.senderRecipientId = senderRecipientId
self.expirationTimestamp = expirationTimestamp
self.signatureData = signatureData
}
@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 certificateData = proto.certificate
let signatureData = proto.signature
let certificateProto = try SMKProtoSenderCertificateCertificate.parseData(certificateData)
let keyData = certificateProto.identityKey
let key = try ECPublicKey(serializedKeyData: keyData)
let senderDeviceId = certificateProto.senderDevice
let senderRecipientId = certificateProto.sender
let expirationTimestamp = certificateProto.expires
let signerProto = certificateProto.signer
let signer = try SMKServerCertificate.parse(proto: signerProto)
return SMKSenderCertificate(signer: signer, key: key, senderDeviceId: senderDeviceId, senderRecipientId: senderRecipientId, expirationTimestamp: expirationTimestamp, signatureData: signatureData)
}
@objc public func toProto() throws -> SMKProtoSenderCertificate {
let certificateBuilder = SMKProtoSenderCertificateCertificate.builder(sender: senderRecipientId,
senderDevice: senderDeviceId,
expires: expirationTimestamp,
identityKey: key.serialized,
signer: try signer.toProto())
let builder =
SMKProtoSenderCertificate.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? SMKSenderCertificate {
return (signer.isEqual(other.signer) &&
key.isEqual(other.key) &&
senderDeviceId == other.senderDeviceId &&
senderRecipientId == other.senderRecipientId &&
expirationTimestamp == other.expirationTimestamp &&
signatureData == other.signatureData)
} else {
return false
}
}
public override var hash: Int {
return signer.hashValue ^ key.hashValue ^ senderDeviceId.hashValue ^ senderRecipientId.hashValue ^ expirationTimestamp.hashValue ^ signatureData.hashValue
}
}

View File

@ -1,64 +0,0 @@
//
// 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
}
}

View File

@ -23,7 +23,7 @@ public class SMKUDAccessKey: NSObject {
// 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))
let initializationVector = Data(count: Int(kAESGCM256_DefaultIVLength))
guard let keyData = Cryptography.encryptAESGCM(plainTextData: emptyPlaintext,
initializationVector: initializationVector,
additionalAuthenticatedData: nil,
@ -42,10 +42,30 @@ public class SMKUDAccessKey: NSObject {
self.keyData = Randomness.generateRandomBytes(Int32(SMKUDAccessKey.kUDAccessKeyLength))
}
private init(keyData: Data) {
self.keyData = keyData
}
/// Used to compose multiple Unidentified-Access-Keys for the multiRecipient endpoint
public static func ^(lhs: SMKUDAccessKey, rhs: SMKUDAccessKey) -> SMKUDAccessKey {
owsAssert(lhs.keyData.count == SMKUDAccessKey.kUDAccessKeyLength)
owsAssert(rhs.keyData.count == SMKUDAccessKey.kUDAccessKeyLength)
let xoredBytes = zip(lhs.keyData, rhs.keyData).map(^)
return .init(keyData: Data(xoredBytes))
}
// MARK:
override public func isEqual(_ object: Any?) -> Bool {
guard let other = object as? SMKUDAccessKey else { return false }
return self.keyData == other.keyData
}
// Unrestricted UD recipients should have a zeroed access key sent to the multi-recipient endpoint
// For a collection of mixed recipients, a zeroed key will have no effect composing keys with xor
// For a collection of only unrestricted UD recipients, the server expects a zero access key
public static var zeroedKey: SMKUDAccessKey {
.init(keyData: Data(repeating: 0, count: kUDAccessKeyLength))
}
}

View File

@ -1,94 +0,0 @@
//
// 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])
}
}

View File

@ -1,66 +0,0 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
import Foundation
@objc public enum SMKMessageType: Int {
case whisper
case prekey
}
// 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
}
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
}
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()
}
}

View File

@ -1,15 +0,0 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
import Foundation
extension Data {
public func prependKeyType() -> Data {
return (self as NSData).prependKeyType() as Data
}
public func removeKeyType() throws -> Data {
return try (self as NSData).removeKeyType() as Data
}
}

View File

@ -1,9 +1,12 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
// Copyright (c) 2020 Open Whisper Systems. All rights reserved.
//
import XCTest
import SignalMetadataKit
@testable import SignalMetadataKit
import SignalCoreKit
import Curve25519Kit
import SignalClient
class SMKTest: XCTestCase {
@ -18,158 +21,111 @@ class SMKTest: XCTestCase {
}
func testECPrivateKey() {
let keyData = Randomness.generateRandomBytes(Int32(ECCKeyLength))!
let keyData = Randomness.generateRandomBytes(Int32(ECCKeyLength))
let key = try! ECPrivateKey(keyData: keyData)
let key2 = try! ECPrivateKey(keyData: keyData)
XCTAssertEqual(key, key2)
}
func testECPublicKey() {
let keyData = Randomness.generateRandomBytes(Int32(ECCKeyLength))!
let keyData = Randomness.generateRandomBytes(Int32(ECCKeyLength))
let key = try! ECPublicKey(keyData: keyData)
XCTAssertEqual(key.keyData, keyData)
let serializedData = key.serialized
let parsedKey = try! ECPublicKey(serializedKeyData: serializedData)
let parsedKey = try! ECPublicKey(serializedKeyData: key.serialized)
XCTAssertEqual(parsedKey.keyData, keyData)
XCTAssertEqual(key, parsedKey)
}
func testUDMessage() {
let keyData = Randomness.generateRandomBytes(Int32(ECCKeyLength))!
let ephemeralKey = try! ECPublicKey(keyData: keyData)
let encryptedStatic = Randomness.generateRandomBytes(100)!
let encryptedMessage = Randomness.generateRandomBytes(200)!
let message = SMKUnidentifiedSenderMessage(ephemeralKey: ephemeralKey,
encryptedStatic: encryptedStatic,
encryptedMessage: encryptedMessage)
let messageData = try! message.serialized()
let parsedMessage = try! SMKUnidentifiedSenderMessage.parse(dataAndPrefix: messageData)
XCTAssertEqual(message.cipherTextVersion, parsedMessage.cipherTextVersion)
XCTAssertEqual(message.ephemeralKey.keyData, parsedMessage.ephemeralKey.keyData)
XCTAssertEqual(message.encryptedStatic, parsedMessage.encryptedStatic)
XCTAssertEqual(message.encryptedMessage, parsedMessage.encryptedMessage)
}
func testUDServerCertificate() {
let keyId: UInt32 = 123
let key = try! ECPublicKey(keyData: Randomness.generateRandomBytes(Int32(ECCKeyLength))!)
let signatureData = Randomness.generateRandomBytes(100)!
let serverCertificate = SMKServerCertificate(keyId: keyId,
key: key,
signatureData: signatureData)
let serializedData = try! serverCertificate.serialized()
let parsed = try! SMKServerCertificate.parse(data: serializedData)
XCTAssertEqual(serverCertificate.keyId, parsed.keyId)
XCTAssertEqual(serverCertificate.key, parsed.key)
XCTAssertEqual(serverCertificate.signatureData, parsed.signatureData)
}
func testUDSenderCertificate() {
let serverCertificate = SMKServerCertificate(keyId: 123,
key: try! ECPublicKey(keyData: Randomness.generateRandomBytes(Int32(ECCKeyLength))!),
signatureData: Randomness.generateRandomBytes(100)!)
let key = try! ECPublicKey(keyData: Randomness.generateRandomBytes(Int32(ECCKeyLength))!)
let senderDeviceId: UInt32 = 456
let senderRecipientId = "+13213214321"
let expirationTimestamp: UInt64 = 789
let signatureData = Randomness.generateRandomBytes(100)!
let senderCertificate = SMKSenderCertificate(signer: serverCertificate,
key: key,
senderDeviceId: senderDeviceId,
senderRecipientId: senderRecipientId,
expirationTimestamp: expirationTimestamp,
signatureData: signatureData)
let serializedData = try! senderCertificate.serialized()
let parsed = try! SMKSenderCertificate.parse(data: serializedData)
XCTAssertEqual(senderCertificate.signer, parsed.signer)
XCTAssertEqual(senderCertificate.key, parsed.key)
XCTAssertEqual(senderCertificate.senderDeviceId, parsed.senderDeviceId)
XCTAssertEqual(senderCertificate.senderRecipientId, parsed.senderRecipientId)
XCTAssertEqual(senderCertificate.expirationTimestamp, parsed.expirationTimestamp)
XCTAssertEqual(senderCertificate.signatureData, parsed.signatureData)
}
func testUDMessageContent() {
let serverCertificate = SMKServerCertificate(keyId: 123,
key: try! ECPublicKey(keyData: Randomness.generateRandomBytes(Int32(ECCKeyLength))!),
signatureData: Randomness.generateRandomBytes(100)!)
let senderCertificate = SMKSenderCertificate(signer: serverCertificate,
key: try! ECPublicKey(keyData: Randomness.generateRandomBytes(Int32(ECCKeyLength))!),
senderDeviceId: 456,
senderRecipientId: "+13213214321",
expirationTimestamp: 789,
signatureData: Randomness.generateRandomBytes(100)!)
let contentData = Randomness.generateRandomBytes(200)!
let message = SMKUnidentifiedSenderMessageContent(messageType: .whisper,
senderCertificate: senderCertificate,
contentData: contentData)
let messageData = try! message.serialized()
let parsed = try! SMKUnidentifiedSenderMessageContent.parse(data: messageData)
XCTAssertEqual(message.messageType, parsed.messageType)
XCTAssertEqual(message.senderCertificate, parsed.senderCertificate)
XCTAssertEqual(message.contentData, parsed.contentData)
}
func testUDSessionCipher_encrypt() {
// NOTE: We use MockClient to ensure consistency between of our session state.
let aliceMockClient = MockClient(recipientId: "+13213214321", deviceId: 456, registrationId: 123)
let bobMockClient = MockClient(recipientId: "+13213214322", deviceId: 321, registrationId: 512)
let aliceMockClient = MockClient(address: aliceAddress, deviceId: 456, registrationId: 123)
let bobMockClient = MockClient(address: bobAddress, deviceId: 321, registrationId: 512)
let certificateValidator = MockCertificateValidator()
let bobPrekey = bobMockClient.generatePreKey()
let bobSignedPrekey = bobMockClient.generateSignedPreKey()
let bobPreKeyBundle = PreKeyBundle(registrationId: bobMockClient.registrationId,
deviceId: bobMockClient.deviceId,
preKeyId: bobPrekey.id,
preKeyPublic: try! bobPrekey.keyPair.ecPublicKey().serialized,
signedPreKeyPublic: try! bobSignedPrekey.keyPair.ecPublicKey().serialized,
signedPreKeyId: bobSignedPrekey.id,
signedPreKeySignature: bobSignedPrekey.signature,
identityKey: try! bobMockClient.identityKeyPair.ecPublicKey().serialized)!
let aliceToBobSessionBuilder = aliceMockClient.createSessionBuilder(forRecipient: bobMockClient)
try! aliceToBobSessionBuilder.processPrekeyBundle(bobPreKeyBundle, protocolContext: nil)
aliceMockClient.initializeSession(with: bobMockClient)
let aliceToBobCipher = try! aliceMockClient.createSecretSessionCipher()
let plaintext = Randomness.generateRandomBytes(200)!
let paddedPlaintext = (plaintext as NSData).paddedMessageBody()!
let serverCertificate = SMKServerCertificate(keyId: 123,
key: try! ECPublicKey(keyData: Randomness.generateRandomBytes(Int32(ECCKeyLength))!),
signatureData: Randomness.generateRandomBytes(100)!)
let senderCertificate = SMKSenderCertificate(signer: serverCertificate,
key: try! aliceMockClient.identityKeyPair.ecPublicKey(),
senderDeviceId: UInt32(aliceMockClient.deviceId),
senderRecipientId: aliceMockClient.recipientId,
expirationTimestamp: 789,
signatureData: Randomness.generateRandomBytes(100)!)
let encryptedMessage = try! aliceToBobCipher.throwswrapped_encryptMessage(recipientId: bobMockClient.recipientId,
deviceId: bobMockClient.deviceId,
paddedPlaintext: paddedPlaintext, senderCertificate: senderCertificate, protocolContext: nil)
let plaintext = Randomness.generateRandomBytes(200)
let paddedPlaintext = (plaintext as NSData).paddedMessageBody()
let senderCertificate = try! SenderCertificate(buildSenderCertificateProto(senderClient: aliceMockClient).serializedData())
let encryptedMessage = try! aliceToBobCipher.encryptMessage(recipient: bobMockClient.address,
deviceId: bobMockClient.deviceId,
paddedPlaintext: paddedPlaintext,
senderCertificate: senderCertificate)
let messageTimestamp = NSDate.ows_millisecondTimeStamp()
let bobToAliceCipher = try! bobMockClient.createSecretSessionCipher()
let decryptedMessage = try! bobToAliceCipher.throwswrapped_decryptMessage(certificateValidator: certificateValidator,
cipherTextData: encryptedMessage,
timestamp: messageTimestamp,
localRecipientId: bobMockClient.recipientId,
localDeviceId: bobMockClient.deviceId,
protocolContext: nil)
cipherTextData: encryptedMessage,
timestamp: messageTimestamp,
localE164: bobMockClient.recipientE164,
localUuid: bobMockClient.recipientUuid,
localDeviceId: bobMockClient.deviceId,
protocolContext: nil)
let payload = (decryptedMessage.paddedPayload as NSData).removePadding()
XCTAssertEqual(aliceMockClient.recipientId, decryptedMessage.senderRecipientId)
XCTAssertEqual(aliceMockClient.address, decryptedMessage.senderAddress)
XCTAssertEqual(aliceMockClient.deviceId, Int32(decryptedMessage.senderDeviceId))
XCTAssertEqual(plaintext, payload)
}
// MARK: - Util
func buildServerCertificateProto() -> SMKProtoServerCertificate {
let serverKey = try! Curve25519.generateKeyPair().ecPublicKey().serialized
let certificateData = try! SMKProtoServerCertificateCertificate.builder(id: 123,
key: serverKey ).buildSerializedData()
let signatureData = Randomness.generateRandomBytes(ECCSignatureLength)
let wrapperProto = SMKProtoServerCertificate.builder(certificate: certificateData,
signature: signatureData)
return try! wrapperProto.build()
}
func buildSenderCertificateProto(senderClient: MockClient? = nil) -> SMKProtoSenderCertificate {
let senderAddress: SMKAddress
let senderDevice: UInt32
let expires = NSDate.ows_millisecondTimeStamp() + kWeekInMs
let identityKey: IdentityKey
let signer = buildServerCertificateProto()
if let senderClient = senderClient {
senderAddress = senderClient.address
senderDevice = UInt32(senderClient.deviceId)
identityKey = senderClient.identityKeyPair.identityKey
} else {
senderAddress = .e164("+1235551234")
senderDevice = 123
identityKey = IdentityKeyPair.generate().identityKey
}
let certificateData: Data = {
let builder = SMKProtoSenderCertificateCertificate.builder(senderDevice: senderDevice,
expires: expires,
identityKey: Data(identityKey.serialize()),
signer: signer)
if let e164 = senderAddress.e164 {
builder.setSenderE164(e164)
}
if let uuidString = senderAddress.uuid?.uuidString {
builder.setSenderUuid(uuidString)
}
return try! builder.buildSerializedData()
}()
let signatureData = Randomness.generateRandomBytes(ECCSignatureLength)
let wrapperProto = try! SMKProtoSenderCertificate.builder(certificate: certificateData,
signature: signatureData).build()
return wrapperProto
}
}

View File

@ -1,357 +1,450 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
// Copyright (c) 2020 Open Whisper Systems. All rights reserved.
//
import XCTest
import SignalMetadataKit
@testable import SignalMetadataKit
@testable import SignalClient
import Curve25519Kit
import SignalCoreKit
// https://github.com/signalapp/libsignal-metadata-java/blob/master/tests/src/test/java/org/signal/libsignal/metadata/SecretSessionCipherTest.java
// public class SecretSessionCipherTest extends TestCase {
// public class SecretSessionCipherTest extends TestCase {
class SMKSecretSessionCipherTest: XCTestCase {
override func setUp() {
super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}
// public void testEncryptDecrypt() throws UntrustedIdentityException, InvalidKeyException, InvalidCertificateException, InvalidProtocolBufferException, InvalidMetadataMessageException, ProtocolDuplicateMessageException, ProtocolUntrustedIdentityException, ProtocolLegacyMessageException, ProtocolInvalidKeyException, InvalidMetadataVersionException, ProtocolInvalidVersionException, ProtocolInvalidMessageException, ProtocolInvalidKeyIdException, ProtocolNoSessionException {
// public void testEncryptDecrypt() throws UntrustedIdentityException, InvalidKeyException, InvalidCertificateException, InvalidProtocolBufferException, InvalidMetadataMessageException, ProtocolDuplicateMessageException, ProtocolUntrustedIdentityException, ProtocolLegacyMessageException, ProtocolInvalidKeyException, InvalidMetadataVersionException, ProtocolInvalidVersionException, ProtocolInvalidMessageException, ProtocolInvalidKeyIdException, ProtocolNoSessionException, SelfSendException {
func testEncryptDecrypt() {
// TestInMemorySignalProtocolStore aliceStore = new TestInMemorySignalProtocolStore();
// TestInMemorySignalProtocolStore bobStore = new TestInMemorySignalProtocolStore();
// NOTE: We use MockClient to ensure consistency between of our session state.
let aliceMockClient = MockClient(recipientId: "+14159999999", deviceId: 1, registrationId: 1234)
let bobMockClient = MockClient(recipientId: "+14158888888", deviceId: 1, registrationId: 1235)
let aliceMockClient = MockClient(address: aliceAddress, deviceId: 1, registrationId: 1234)
let bobMockClient = MockClient(address: bobAddress, deviceId: 1, registrationId: 1235)
// TestInMemorySignalProtocolStore aliceStore = new TestInMemorySignalProtocolStore();
// TestInMemorySignalProtocolStore bobStore = new TestInMemorySignalProtocolStore();
//
// initializeSessions(aliceStore, bobStore);
initializeSessions(aliceMockClient: aliceMockClient,
bobMockClient: bobMockClient)
// initializeSessions(aliceStore, bobStore);
initializeSessions(aliceMockClient: aliceMockClient, bobMockClient: bobMockClient)
// ECKeyPair trustRoot = Curve.generateKeyPair();
let trustRoot = Curve25519.generateKeyPair()
// SenderCertificate senderCertificate = createCertificateFor(trustRoot, "+14151111111", 1, aliceStore.getIdentityKeyPair().getPublicKey().getPublicKey(), 31337);
// ECKeyPair trustRoot = Curve.generateKeyPair();
let trustRoot = IdentityKeyPair.generate()
// SenderCertificate senderCertificate = createCertificateFor(trustRoot, "+14151111111", 1, aliceStore.getIdentityKeyPair().getPublicKey().getPublicKey(), 31337);
let senderCertificate = createCertificateFor(trustRoot: trustRoot,
senderRecipientId: aliceMockClient.recipientId,
senderAddress: aliceMockClient.address,
senderDeviceId: UInt32(aliceMockClient.deviceId),
identityKey: try! aliceMockClient.identityKeyPair.ecPublicKey(),
identityKey: aliceMockClient.identityKeyPair.publicKey,
expirationTimestamp: 31337)
// SecretSessionCipher aliceCipher = new SecretSessionCipher(aliceStore);
// SecretSessionCipher aliceCipher = new SecretSessionCipher(aliceStore);
let aliceCipher: SMKSecretSessionCipher = try! aliceMockClient.createSecretSessionCipher()
// byte[] ciphertext = aliceCipher.encrypt(new SignalProtocolAddress("+14152222222", 1),
// senderCertificate, "smert za smert".getBytes());
// byte[] ciphertext = aliceCipher.encrypt(new SignalProtocolAddress("+14152222222", 1),
// senderCertificate, "smert za smert".getBytes());
// NOTE: The java tests don't bother padding the plaintext.
let alicePlaintext = "smert za smert".data(using: String.Encoding.utf8)!
let ciphertext = try! aliceCipher.throwswrapped_encryptMessage(recipientId: bobMockClient.recipientId,
deviceId: bobMockClient.deviceId,
paddedPlaintext: alicePlaintext,
senderCertificate: senderCertificate,
protocolContext: nil)
let ciphertext = try! aliceCipher.encryptMessage(recipient: bobMockClient.address,
deviceId: bobMockClient.deviceId,
paddedPlaintext: alicePlaintext,
senderCertificate: senderCertificate)
// SecretSessionCipher bobCipher = new SecretSessionCipher(bobStore);
// SealedSessionCipher bobCipher = new SealedSessionCipher(bobStore, new SignalProtocolAddress("+14152222222", 1));
let bobCipher: SMKSecretSessionCipher = try! bobMockClient.createSecretSessionCipher()
// Pair<SignalProtocolAddress, byte[]> plaintext = bobCipher.decrypt(new CertificateValidator(trustRoot.getPublicKey()), ciphertext, 31335);
let certificateValidator = SMKCertificateDefaultValidator(trustRoot: try! trustRoot.ecPublicKey())
// Pair<SignalProtocolAddress, byte[]> plaintext = bobCipher.decrypt(new CertificateValidator(trustRoot.getPublicKey()), ciphertext, 31335);
let certificateValidator = SMKCertificateDefaultValidator(trustRoot: ECPublicKey(trustRoot.publicKey))
let bobPlaintext = try! bobCipher.throwswrapped_decryptMessage(certificateValidator: certificateValidator,
cipherTextData: ciphertext,
timestamp: 31335,
localRecipientId: bobMockClient.recipientId,
localDeviceId: bobMockClient.deviceId,
protocolContext: nil)
cipherTextData: ciphertext,
timestamp: 31335,
localE164: bobMockClient.recipientE164,
localUuid: bobMockClient.recipientUuid,
localDeviceId: bobMockClient.deviceId,
protocolContext: nil)
// assertEquals(new String(plaintext.second()), "smert za smert");
XCTAssertEqual(bobPlaintext.paddedPayload, alicePlaintext)
// assertEquals(plaintext.first().getName(), "+14151111111");
XCTAssertEqual(bobPlaintext.senderRecipientId, aliceMockClient.recipientId)
// assertEquals(plaintext.first().getDeviceId(), 1);
// assertEquals(new String(plaintext.second()), "smert za smert");
// assertEquals(plaintext.first().getName(), "+14151111111");
// assertEquals(plaintext.first().getDeviceId(), 1);
XCTAssertEqual(String(data: bobPlaintext.paddedPayload, encoding: .utf8), "smert za smert")
XCTAssertEqual(bobPlaintext.senderAddress, aliceMockClient.address)
XCTAssertEqual(bobPlaintext.senderDeviceId, Int(aliceMockClient.deviceId))
}
// public void testEncryptDecryptUntrusted() throws Exception {
// public void testEncryptDecryptUntrusted() throws Exception {
func testEncryptDecryptUntrusted() {
// TestInMemorySignalProtocolStore aliceStore = new TestInMemorySignalProtocolStore();
// TestInMemorySignalProtocolStore bobStore = new TestInMemorySignalProtocolStore();
// NOTE: We use MockClient to ensure consistency between of our session state.
let aliceMockClient = MockClient(recipientId: "+14159999999", deviceId: 1, registrationId: 1234)
let bobMockClient = MockClient(recipientId: "+14158888888", deviceId: 1, registrationId: 1235)
let aliceMockClient = MockClient(address: aliceAddress, deviceId: 1, registrationId: 1234)
let bobMockClient = MockClient(address: bobAddress, deviceId: 1, registrationId: 1235)
// TestInMemorySignalProtocolStore aliceStore = new TestInMemorySignalProtocolStore();
// TestInMemorySignalProtocolStore bobStore = new TestInMemorySignalProtocolStore();
//
// initializeSessions(aliceStore, bobStore);
initializeSessions(aliceMockClient: aliceMockClient,
bobMockClient: bobMockClient)
// initializeSessions(aliceStore, bobStore);
initializeSessions(aliceMockClient: aliceMockClient, bobMockClient: bobMockClient)
// ECKeyPair trustRoot = Curve.generateKeyPair();
// ECKeyPair falseTrustRoot = Curve.generateKeyPair();
let trustRoot = Curve25519.generateKeyPair()
let falseTrustRoot = Curve25519.generateKeyPair()
// SenderCertificate senderCertificate = createCertificateFor(falseTrustRoot, "+14151111111", 1, aliceStore.getIdentityKeyPair().getPublicKey().getPublicKey(), 31337);
// ECKeyPair trustRoot = Curve.generateKeyPair();
// ECKeyPair falseTrustRoot = Curve.generateKeyPair();
let trustRoot = IdentityKeyPair.generate()
let falseTrustRoot = IdentityKeyPair.generate()
// SenderCertificate senderCertificate = createCertificateFor(falseTrustRoot, "+14151111111", 1, aliceStore.getIdentityKeyPair().getPublicKey().getPublicKey(), 31337);
let senderCertificate = createCertificateFor(trustRoot: falseTrustRoot,
senderRecipientId: aliceMockClient.recipientId,
senderAddress: aliceMockClient.address,
senderDeviceId: UInt32(aliceMockClient.deviceId),
identityKey: try! aliceMockClient.identityKeyPair.ecPublicKey(),
identityKey: aliceMockClient.identityKeyPair.publicKey,
expirationTimestamp: 31337)
// SecretSessionCipher aliceCipher = new SecretSessionCipher(aliceStore);
// SecretSessionCipher aliceCipher = new SecretSessionCipher(aliceStore);
let aliceCipher: SMKSecretSessionCipher = try! aliceMockClient.createSecretSessionCipher()
// byte[] ciphertext = aliceCipher.encrypt(new SignalProtocolAddress("+14152222222", 1),
// senderCertificate, "и вот я".getBytes());
// byte[] ciphertext = aliceCipher.encrypt(new SignalProtocolAddress("+14152222222", 1),
// senderCertificate, "и вот я".getBytes());
// NOTE: The java tests don't bother padding the plaintext.
let alicePlaintext = "и вот я".data(using: String.Encoding.utf8)!
let ciphertext = try! aliceCipher.throwswrapped_encryptMessage(recipientId: bobMockClient.recipientId,
deviceId: bobMockClient.deviceId,
paddedPlaintext: alicePlaintext,
senderCertificate: senderCertificate,
protocolContext: nil)
let aliceGroupId = Randomness.generateRandomBytes(6)
let aliceContentHint = UnidentifiedSenderMessageContent.ContentHint.implicit
let ciphertext = try! aliceCipher.encryptMessage(recipient: bobMockClient.address,
deviceId: bobMockClient.deviceId,
paddedPlaintext: alicePlaintext,
contentHint: aliceContentHint,
groupId: aliceGroupId,
senderCertificate: senderCertificate)
// SecretSessionCipher bobCipher = new SecretSessionCipher(bobStore);
// SecretSessionCipher bobCipher = new SecretSessionCipher(bobStore);
let bobCipher: SMKSecretSessionCipher = try! bobMockClient.createSecretSessionCipher()
// try {
// bobCipher.decrypt(new CertificateValidator(trustRoot.getPublicKey()), ciphertext, 31335);
// throw new AssertionError();
// } catch (InvalidMetadataMessageException e) {
// // good
// }
let certificateValidator = SMKCertificateDefaultValidator(trustRoot: try! trustRoot.ecPublicKey())
// try {
// bobCipher.decrypt(new CertificateValidator(trustRoot.getPublicKey()), ciphertext, 31335);
// throw new AssertionError();
// } catch (InvalidMetadataMessageException e) {
// // good
// }
let certificateValidator = SMKCertificateDefaultValidator(trustRoot: ECPublicKey(trustRoot.publicKey))
do {
_ = try bobCipher.throwswrapped_decryptMessage(certificateValidator: certificateValidator,
cipherTextData: ciphertext,
timestamp: 31335,
localRecipientId: bobMockClient.recipientId,
localDeviceId: bobMockClient.deviceId,
protocolContext: nil)
cipherTextData: ciphertext,
timestamp: 31335,
localE164: bobMockClient.recipientE164,
localUuid: bobMockClient.recipientUuid,
localDeviceId: bobMockClient.deviceId,
protocolContext: nil)
XCTFail("Decryption should have failed.")
} catch _ as SMKCertificateError {
} catch let knownSenderError as SecretSessionKnownSenderError {
// Decryption is expected to fail.
XCTAssert(knownSenderError.underlyingError is SMKCertificateError )
XCTAssertEqual(knownSenderError.contentHint, aliceContentHint)
XCTAssertEqual(knownSenderError.groupId, aliceGroupId)
XCTAssertNoThrow(
try DecryptionErrorMessage(
originalMessageBytes: knownSenderError.unsealedContent,
type: knownSenderError.cipherType,
timestamp: 31335,
originalSenderDeviceId: knownSenderError.senderDeviceId
)
)
} catch {
XCTFail("Unexpected error: \(error)")
}
}
// public void testEncryptDecryptExpired() throws Exception {
// public void testEncryptDecryptExpired() throws Exception {
func testEncryptDecryptExpired() {
// TestInMemorySignalProtocolStore aliceStore = new TestInMemorySignalProtocolStore();
// TestInMemorySignalProtocolStore bobStore = new TestInMemorySignalProtocolStore();
// NOTE: We use MockClient to ensure consistency between of our session state.
let aliceMockClient = MockClient(recipientId: "+14159999999", deviceId: 1, registrationId: 1234)
let bobMockClient = MockClient(recipientId: "+14158888888", deviceId: 1, registrationId: 1235)
let aliceMockClient = MockClient(address: aliceAddress, deviceId: 1, registrationId: 1234)
let bobMockClient = MockClient(address: bobAddress, deviceId: 1, registrationId: 1235)
// TestInMemorySignalProtocolStore aliceStore = new TestInMemorySignalProtocolStore();
// TestInMemorySignalProtocolStore bobStore = new TestInMemorySignalProtocolStore();
//
// initializeSessions(aliceStore, bobStore);
initializeSessions(aliceMockClient: aliceMockClient,
bobMockClient: bobMockClient)
// initializeSessions(aliceStore, bobStore);
initializeSessions(aliceMockClient: aliceMockClient, bobMockClient: bobMockClient)
// ECKeyPair trustRoot = Curve.generateKeyPair();
let trustRoot = Curve25519.generateKeyPair()
// SenderCertificate senderCertificate = createCertificateFor(trustRoot, "+14151111111", 1, aliceStore.getIdentityKeyPair().getPublicKey().getPublicKey(), 31337);
// ECKeyPair trustRoot = Curve.generateKeyPair();
let trustRoot = IdentityKeyPair.generate()
// SenderCertificate senderCertificate = createCertificateFor(trustRoot, "+14151111111", 1, aliceStore.getIdentityKeyPair().getPublicKey().getPublicKey(), 31337);
let senderCertificate = createCertificateFor(trustRoot: trustRoot,
senderRecipientId: aliceMockClient.recipientId,
senderAddress: aliceMockClient.address,
senderDeviceId: UInt32(aliceMockClient.deviceId),
identityKey: try! aliceMockClient.identityKeyPair.ecPublicKey(),
identityKey: aliceMockClient.identityKeyPair.publicKey,
expirationTimestamp: 31337)
// SecretSessionCipher aliceCipher = new SecretSessionCipher(aliceStore);
// SecretSessionCipher aliceCipher = new SecretSessionCipher(aliceStore);
let aliceCipher: SMKSecretSessionCipher = try! aliceMockClient.createSecretSessionCipher()
// byte[] ciphertext = aliceCipher.encrypt(new SignalProtocolAddress("+14152222222", 1),
// senderCertificate, "и вот я".getBytes());
// byte[] ciphertext = aliceCipher.encrypt(new SignalProtocolAddress("+14152222222", 1),
// senderCertificate, "и вот я".getBytes());
// NOTE: The java tests don't bother padding the plaintext.
let alicePlaintext = "и вот я".data(using: String.Encoding.utf8)!
let ciphertext = try! aliceCipher.throwswrapped_encryptMessage(recipientId: bobMockClient.recipientId,
deviceId: bobMockClient.deviceId,
paddedPlaintext: alicePlaintext,
senderCertificate: senderCertificate,
protocolContext: nil)
let aliceGroupId = Randomness.generateRandomBytes(6)
let aliceContentHint = UnidentifiedSenderMessageContent.ContentHint.resendable
// SecretSessionCipher bobCipher = new SecretSessionCipher(bobStore);
let ciphertext = try! aliceCipher.encryptMessage(recipient: bobMockClient.address,
deviceId: bobMockClient.deviceId,
paddedPlaintext: alicePlaintext,
contentHint: aliceContentHint,
groupId: aliceGroupId,
senderCertificate: senderCertificate)
// SecretSessionCipher bobCipher = new SecretSessionCipher(bobStore);
let bobCipher: SMKSecretSessionCipher = try! bobMockClient.createSecretSessionCipher()
// try {
// bobCipher.decrypt(new CertificateValidator(trustRoot.getPublicKey()), ciphertext, 31338);
// throw new AssertionError();
// } catch (InvalidMetadataMessageException e) {
// // good
// }
let certificateValidator = SMKCertificateDefaultValidator(trustRoot: try! trustRoot.ecPublicKey())
// try {
// bobCipher.decrypt(new CertificateValidator(trustRoot.getPublicKey()), ciphertext, 31338);
// throw new AssertionError();
// } catch (InvalidMetadataMessageException e) {
// // good
// }
let certificateValidator = SMKCertificateDefaultValidator(trustRoot: ECPublicKey(trustRoot.publicKey))
do {
_ = try bobCipher.throwswrapped_decryptMessage(certificateValidator: certificateValidator,
cipherTextData: ciphertext,
timestamp: 31338,
localRecipientId: bobMockClient.recipientId,
localDeviceId: bobMockClient.deviceId,
protocolContext: nil)
cipherTextData: ciphertext,
timestamp: 31338,
localE164: bobMockClient.recipientE164,
localUuid: bobMockClient.recipientUuid,
localDeviceId: bobMockClient.deviceId,
protocolContext: nil)
XCTFail("Decryption should have failed.")
} catch _ as SMKCertificateError {
} catch let knownSenderError as SecretSessionKnownSenderError {
// Decryption is expected to fail.
XCTAssert(knownSenderError.underlyingError is SMKCertificateError )
XCTAssertEqual(knownSenderError.contentHint, aliceContentHint)
XCTAssertEqual(knownSenderError.groupId, aliceGroupId)
XCTAssertNoThrow(
try DecryptionErrorMessage(
originalMessageBytes: knownSenderError.unsealedContent,
type: knownSenderError.cipherType,
timestamp: 31338,
originalSenderDeviceId: knownSenderError.senderDeviceId
)
)
} catch {
XCTFail("Unexpected error: \(error)")
}
}
// public void testEncryptFromWrongIdentity() throws Exception {
func testEncryptFromWrongIdentity() {
// public void testEncryptFromWrongIdentity() throws Exception {
func testEncryptFromWrongIdentity() {
// TestInMemorySignalProtocolStore aliceStore = new TestInMemorySignalProtocolStore();
// TestInMemorySignalProtocolStore bobStore = new TestInMemorySignalProtocolStore();
// NOTE: We use MockClient to ensure consistency between of our session state.
let aliceMockClient = MockClient(recipientId: "+14159999999", deviceId: 1, registrationId: 1234)
let bobMockClient = MockClient(recipientId: "+14158888888", deviceId: 1, registrationId: 1235)
let aliceMockClient = MockClient(address: aliceAddress, deviceId: 1, registrationId: 1234)
let bobMockClient = MockClient(address: bobAddress, deviceId: 1, registrationId: 1235)
// TestInMemorySignalProtocolStore aliceStore = new TestInMemorySignalProtocolStore();
// TestInMemorySignalProtocolStore bobStore = new TestInMemorySignalProtocolStore();
//
// initializeSessions(aliceStore, bobStore);
// initializeSessions(aliceStore, bobStore);
initializeSessions(aliceMockClient: aliceMockClient,
bobMockClient: bobMockClient)
// ECKeyPair trustRoot = Curve.generateKeyPair();
let trustRoot = Curve25519.generateKeyPair()
// ECKeyPair randomKeyPair = Curve.generateKeyPair();
let randomKeyPair = Curve25519.generateKeyPair()
// SenderCertificate senderCertificate = createCertificateFor(trustRoot, "+14151111111", 1, randomKeyPair.getPublicKey(), 31337);
// ECKeyPair trustRoot = Curve.generateKeyPair();
let trustRoot = IdentityKeyPair.generate()
// ECKeyPair randomKeyPair = Curve.generateKeyPair();
let randomKeyPair = IdentityKeyPair.generate()
// SenderCertificate senderCertificate = createCertificateFor(trustRoot, "+14151111111", 1, randomKeyPair.getPublicKey(), 31337);
let senderCertificate = createCertificateFor(trustRoot: trustRoot,
senderRecipientId: aliceMockClient.recipientId,
senderAddress: aliceMockClient.address,
senderDeviceId: UInt32(aliceMockClient.deviceId),
identityKey: try! randomKeyPair.ecPublicKey(),
identityKey: randomKeyPair.publicKey,
expirationTimestamp: 31337)
// SecretSessionCipher aliceCipher = new SecretSessionCipher(aliceStore);
// SecretSessionCipher aliceCipher = new SecretSessionCipher(aliceStore);
let aliceCipher: SMKSecretSessionCipher = try! aliceMockClient.createSecretSessionCipher()
// byte[] ciphertext = aliceCipher.encrypt(new SignalProtocolAddress("+14152222222", 1),
// senderCertificate, "smert za smert".getBytes());
// byte[] ciphertext = aliceCipher.encrypt(new SignalProtocolAddress("+14152222222", 1),
// senderCertificate, "smert za smert".getBytes());
// NOTE: The java tests don't bother padding the plaintext.
let alicePlaintext = "smert za smert".data(using: String.Encoding.utf8)!
let ciphertext = try! aliceCipher.throwswrapped_encryptMessage(recipientId: bobMockClient.recipientId,
deviceId: bobMockClient.deviceId,
paddedPlaintext: alicePlaintext,
senderCertificate: senderCertificate,
protocolContext: nil)
let ciphertext = try! aliceCipher.encryptMessage(recipient: bobMockClient.address,
deviceId: bobMockClient.deviceId,
paddedPlaintext: alicePlaintext,
senderCertificate: senderCertificate)
// SecretSessionCipher bobCipher = new SecretSessionCipher(bobStore);
// SecretSessionCipher bobCipher = new SecretSessionCipher(bobStore);
let bobCipher: SMKSecretSessionCipher = try! bobMockClient.createSecretSessionCipher()
// try {
// bobCipher.decrypt(new CertificateValidator(trustRoot.getPublicKey()), ciphertext, 31335);
// } catch (InvalidMetadataMessageException e) {
// // good
// }
let certificateValidator = SMKCertificateDefaultValidator(trustRoot: try! trustRoot.ecPublicKey())
// try {
// bobCipher.decrypt(new CertificateValidator(trustRoot.getPublicKey()), ciphertext, 31335);
// } catch (InvalidMetadataMessageException e) {
// // good
// }
let certificateValidator = SMKCertificateDefaultValidator(trustRoot: ECPublicKey(trustRoot.publicKey))
do {
try bobCipher.throwswrapped_decryptMessage(certificateValidator: certificateValidator,
cipherTextData: ciphertext,
timestamp: 31335,
localRecipientId: bobMockClient.recipientId,
localDeviceId: bobMockClient.deviceId,
protocolContext: nil)
_ = try bobCipher.throwswrapped_decryptMessage(certificateValidator: certificateValidator,
cipherTextData: ciphertext,
timestamp: 31335,
localE164: bobMockClient.recipientE164,
localUuid: bobMockClient.recipientUuid,
localDeviceId: bobMockClient.deviceId,
protocolContext: nil)
XCTFail("Decryption should have failed.")
} catch {
} catch SignalError.invalidMessage(_) {
// Decryption is expected to fail.
XCTAssertTrue(error is SMKError)
// FIXME: This particular failure doesn't get wrapped as a SecretSessionKnownSenderError
// because it's checked before the unwrapped message is returned.
// Why? Because it uses crypto values calculated during unwrapping to validate the sender certificate.
} catch {
XCTFail("unexpected error: \(error)")
}
}
// MARK: - Utils
func testGroupEncryptDecrypt_Success() {
// Setup: Initialize sessions and sender certificate
let aliceMockClient = MockClient(address: aliceAddress, deviceId: 1, registrationId: 1234)
let bobMockClient = MockClient(address: bobAddress, deviceId: 1, registrationId: 1235)
initializeSessions(aliceMockClient: aliceMockClient, bobMockClient: bobMockClient)
// private SenderCertificate createCertificateFor(ECKeyPair trustRoot, String sender, int deviceId, ECPublicKey identityKey, long expires)
// throws InvalidKeyException, InvalidCertificateException, InvalidProtocolBufferException {
private func createCertificateFor(trustRoot: ECKeyPair,
senderRecipientId: String,
senderDeviceId: UInt32,
identityKey: ECPublicKey,
expirationTimestamp: UInt64) -> SMKSenderCertificate {
// ECKeyPair serverKey = Curve.generateKeyPair();
let serverKey = Curve25519.generateKeyPair()
let trustRoot = IdentityKeyPair.generate()
let senderCertificate = createCertificateFor(
trustRoot: trustRoot,
senderAddress: aliceMockClient.address,
senderDeviceId: UInt32(aliceMockClient.deviceId),
identityKey: aliceMockClient.identityKeyPair.publicKey,
expirationTimestamp: 31337)
// byte[] serverCertificateBytes = SignalProtos.ServerCertificate.Certificate.newBuilder()
// .setId(1)
// .setKey(ByteString.copyFrom(serverKey.getPublicKey().serialize()))
// .build()
// .toByteArray();
let keyId: UInt32 = 1
let unsignedServerCertificateBuilder = SMKProtoServerCertificateCertificate.builder(id: keyId,
key: try! serverKey.ecPublicKey().serialized)
let unsignedServerCertificateData = try! unsignedServerCertificateBuilder.build().serializedData()
// Setup: Distribute alice's sender key to bob's key store
let distributionId = UUID()
let aliceSenderKeyMessage = try! SenderKeyDistributionMessage(
from: aliceMockClient.protocolAddress,
distributionId: distributionId,
store: aliceMockClient.senderKeyStore,
context: NullContext())
// byte[] serverCertificateSignature = Curve.calculateSignature(trustRoot.getPrivateKey(), serverCertificateBytes);
let serverCertificateSignature = try! Ed25519.sign(unsignedServerCertificateData, with: trustRoot)
try! processSenderKeyDistributionMessage(
aliceSenderKeyMessage,
from: aliceMockClient.protocolAddress,
store: bobMockClient.senderKeyStore,
context: NullContext())
// ServerCertificate serverCertificate = new ServerCertificate(SignalProtos.ServerCertificate.newBuilder()
// .setCertificate(ByteString.copyFrom(serverCertificateBytes))
// .setSignature(ByteString.copyFrom(serverCertificateSignature))
// .build()
// .toByteArray());
let signedServerCertificate = SMKServerCertificate(keyId: keyId,
key: try! serverKey.ecPublicKey(),
signatureData: serverCertificateSignature)
XCTAssertEqual(try! signedServerCertificate.toProto().certificate, unsignedServerCertificateData)
let signedServerCertificateData = try! signedServerCertificate.serialized()
// Test: Alice encrypt's a message using `groupEncryptMessage`
let aliceCipher = try! aliceMockClient.createSecretSessionCipher()
let alicePlaintext = "beltalowda".data(using: String.Encoding.utf8)!
let aliceCiphertext = try! aliceCipher.groupEncryptMessage(
recipients: [bobMockClient.protocolAddress],
paddedPlaintext: alicePlaintext,
senderCertificate: senderCertificate,
groupId: Data(),
distributionId: distributionId,
contentHint: .implicit,
protocolContext: nil).map { $0 }
// byte[] senderCertificateBytes = SignalProtos.SenderCertificate.Certificate.newBuilder()
// .setSender(sender)
// .setSenderDevice(deviceId)
// .setIdentityKey(ByteString.copyFrom(identityKey.serialize()))
// .setExpires(expires)
// .setSigner(SignalProtos.ServerCertificate.parseFrom(serverCertificate.getSerialized()))
// .build()
// .toByteArray();
let unsignedSenderCertificateBuilder = SMKProtoSenderCertificateCertificate.builder(sender: senderRecipientId,
senderDevice: senderDeviceId,
expires: expirationTimestamp,
identityKey: identityKey.serialized,
signer: try! signedServerCertificate.toProto())
let unsignedSenderCertificateData = try! unsignedSenderCertificateBuilder.build().serializedData()
// This splits out irrelevant per-recipient data from the shared sender key message
// This is only necessary in tests. The server would usually handle this.
let singleRecipientCiphertext = try! sealedSenderMultiRecipientMessageForSingleRecipient(aliceCiphertext)
// byte[] senderCertificateSignature = Curve.calculateSignature(serverKey.getPrivateKey(), senderCertificateBytes);
let senderCertificateSignature = try! Ed25519.sign(unsignedSenderCertificateData, with: serverKey)
// Test: Bob decrypts the ciphertext
let bobCipher = try! bobMockClient.createSecretSessionCipher()
let bobValidator = SMKCertificateDefaultValidator(trustRoot: ECPublicKey(trustRoot.publicKey))
let bobPlaintext = try! bobCipher.throwswrapped_decryptMessage(
certificateValidator: bobValidator,
cipherTextData: Data(singleRecipientCiphertext),
timestamp: 31335,
localE164: bobMockClient.recipientE164,
localUuid: bobMockClient.recipientUuid,
localDeviceId: bobMockClient.deviceId,
protocolContext: nil)
// return new SenderCertificate(SignalProtos.SenderCertificate.newBuilder()
// .setCertificate(ByteString.copyFrom(senderCertificateBytes))
// .setSignature(ByteString.copyFrom(senderCertificateSignature))
// .build()
// .toByteArray());
let signedSenderCertificate = SMKSenderCertificate(signer: signedServerCertificate,
key: identityKey,
senderDeviceId: senderDeviceId,
senderRecipientId: senderRecipientId,
expirationTimestamp: expirationTimestamp,
signatureData: senderCertificateSignature)
XCTAssertEqual(try! signedSenderCertificate.signer.toProto().certificate, unsignedServerCertificateData)
return signedSenderCertificate
// Verify
XCTAssertEqual(String(data: bobPlaintext.paddedPayload, encoding: .utf8), "beltalowda")
XCTAssertEqual(bobPlaintext.senderAddress, aliceMockClient.address)
XCTAssertEqual(bobPlaintext.senderDeviceId, Int(aliceMockClient.deviceId))
XCTAssertEqual(bobPlaintext.messageType, .senderKey)
}
// private void initializeSessions(TestInMemorySignalProtocolStore aliceStore, TestInMemorySignalProtocolStore bobStore)
// throws InvalidKeyException, UntrustedIdentityException
// {
private func initializeSessions(aliceMockClient: MockClient,
bobMockClient: MockClient) {
// ECKeyPair bobPreKey = Curve.generateKeyPair();
let bobPreKey = bobMockClient.generatePreKey()
// IdentityKeyPair bobIdentityKey = bobStore.getIdentityKeyPair();
let bobIdentityKey = bobMockClient.identityKeyPair
// SignedPreKeyRecord bobSignedPreKey = KeyHelper.generateSignedPreKey(bobIdentityKey, 2);
let bobSignedPreKey = bobMockClient.generateSignedPreKey()
//
// PreKeyBundle bobBundle = new PreKeyBundle(1, 1, 1, bobPreKey.getPublicKey(), 2, bobSignedPreKey.getKeyPair().getPublicKey(), bobSignedPreKey.getSignature(), bobIdentityKey.getPublicKey());
let bobBundle = PreKeyBundle(registrationId: bobMockClient.registrationId,
deviceId: bobMockClient.deviceId,
preKeyId: bobPreKey.id,
preKeyPublic: try! bobPreKey.keyPair.ecPublicKey().serialized,
signedPreKeyPublic: try! bobSignedPreKey.keyPair.ecPublicKey().keyData.prependKeyType(),
signedPreKeyId: bobSignedPreKey.id,
signedPreKeySignature: bobSignedPreKey.signature,
identityKey: try! bobIdentityKey.ecPublicKey().keyData.prependKeyType())!
func testGroupEncryptDecrypt_Failure() {
// Setup: Initialize sessions and sender certificate
let aliceMockClient = MockClient(address: aliceAddress, deviceId: 1, registrationId: 1234)
let bobMockClient = MockClient(address: bobAddress, deviceId: 1, registrationId: 1235)
initializeSessions(aliceMockClient: aliceMockClient, bobMockClient: bobMockClient)
// SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, new SignalProtocolAddress("+14152222222", 1));
let aliceSessionBuilder = aliceMockClient.createSessionBuilder(forRecipient: bobMockClient)
// aliceSessionBuilder.process(bobBundle);
try! aliceSessionBuilder.processPrekeyBundle(bobBundle, protocolContext: nil)
let trustRoot = IdentityKeyPair.generate()
let senderCertificate = createCertificateFor(
trustRoot: trustRoot,
senderAddress: aliceMockClient.address,
senderDeviceId: UInt32(aliceMockClient.deviceId),
identityKey: aliceMockClient.identityKeyPair.publicKey,
expirationTimestamp: 31337)
// bobStore.storeSignedPreKey(2, bobSignedPreKey);
// bobStore.storePreKey(1, new PreKeyRecord(1, bobPreKey));
// NOTE: These stores are taken care of in the mocks' createKey() methods above.
// Setup: Alice creates a sender key
// Test: Bob intentionally does not process Alice's SKDM to simulate an unsent key
let distributionId = UUID()
let _ = try! SenderKeyDistributionMessage(
from: aliceMockClient.protocolAddress,
distributionId: distributionId,
store: aliceMockClient.senderKeyStore,
context: NullContext())
// Test: Alice encrypt's a message using `groupEncryptMessage`
let aliceCipher = try! aliceMockClient.createSecretSessionCipher()
let alicePlaintext = "beltalowda".data(using: String.Encoding.utf8)!
let aliceCiphertext = try! aliceCipher.groupEncryptMessage(
recipients: [bobMockClient.protocolAddress],
paddedPlaintext: alicePlaintext,
senderCertificate: senderCertificate,
groupId: "inyalowda".data(using: String.Encoding.utf8)!,
distributionId: distributionId,
contentHint: .resendable,
protocolContext: nil).map { $0 }
// This splits out irrelevant per-recipient data from the shared sender key message
// This is only necessary in tests. The server would usually handle this.
let singleRecipientCiphertext = try! sealedSenderMultiRecipientMessageForSingleRecipient(aliceCiphertext)
// Test: Bob decrypts the ciphertext
let bobCipher = try! bobMockClient.createSecretSessionCipher()
let bobValidator = SMKCertificateDefaultValidator(trustRoot: ECPublicKey(trustRoot.publicKey))
do {
_ = try bobCipher.throwswrapped_decryptMessage(
certificateValidator: bobValidator,
cipherTextData: Data(singleRecipientCiphertext),
timestamp: 31335,
localE164: bobMockClient.recipientE164,
localUuid: bobMockClient.recipientUuid,
localDeviceId: bobMockClient.deviceId,
protocolContext: nil)
XCTFail("Decryption should have failed.")
} catch let knownSenderError as SecretSessionKnownSenderError {
// Verify: We need to make sure that the sender, group, and contentHint are preserved
// through decryption failures because of missing a missing sender key. This will
// help with recovery.
XCTAssertEqual(knownSenderError.senderAddress, aliceMockClient.address)
XCTAssertEqual(knownSenderError.senderDeviceId, UInt32(aliceMockClient.deviceId))
XCTAssertEqual(Data(knownSenderError.groupId!), "inyalowda".data(using: String.Encoding.utf8)!)
XCTAssertEqual(knownSenderError.contentHint, .resendable)
XCTAssertNoThrow(
try DecryptionErrorMessage(
originalMessageBytes: knownSenderError.unsealedContent,
type: knownSenderError.cipherType,
timestamp: 31335,
originalSenderDeviceId: knownSenderError.senderDeviceId
)
)
if case SignalError.invalidState(_) = knownSenderError.underlyingError {
// Expected
} else {
XCTFail()
}
} catch {
XCTFail("Unexpected error: \(error)")
}
}
// MARK: - Utils
// private SenderCertificate createCertificateFor(ECKeyPair trustRoot, String sender, int deviceId, ECPublicKey identityKey, long expires)
// throws InvalidKeyException, InvalidCertificateException, InvalidProtocolBufferException {
private func createCertificateFor(trustRoot: IdentityKeyPair,
senderAddress: SMKAddress,
senderDeviceId: UInt32,
identityKey: PublicKey,
expirationTimestamp: UInt64) -> SenderCertificate {
let serverKey = IdentityKeyPair.generate()
let serverCertificate = try! ServerCertificate(keyId: 1,
publicKey: serverKey.publicKey,
trustRoot: trustRoot.privateKey)
return try! SenderCertificate(sender: SealedSenderAddress(e164: senderAddress.e164,
uuidString: senderAddress.uuid!.uuidString,
deviceId: senderDeviceId),
publicKey: identityKey,
expiration: expirationTimestamp,
signerCertificate: serverCertificate,
signerKey: serverKey.privateKey)
}
// private void initializeSessions(TestInMemorySignalProtocolStore aliceStore, TestInMemorySignalProtocolStore bobStore)
// throws InvalidKeyException, UntrustedIdentityException
private func initializeSessions(aliceMockClient: MockClient, bobMockClient: MockClient) {
aliceMockClient.initializeSession(with: bobMockClient)
}
}

View File

@ -1,220 +1,190 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
// Copyright (c) 2020 Open Whisper Systems. All rights reserved.
//
import XCTest
import SignalMetadataKit
import Curve25519Kit
import SignalClient
// See: https://github.com/signalapp/libsignal-metadata-java/blob/master/tests/src/test/java/org/signal/libsignal/metadata/certificate/SenderCertificateTest.java
//
//public class SenderCertificateTest extends TestCase {
class SMKSenderCertificateTest: XCTestCase {
override func setUp() {
super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}
// private final ECKeyPair trustRoot = Curve.generateKeyPair();
// private final ECKeyPair trustRoot = Curve.generateKeyPair();
let trustRoot = Curve25519.generateKeyPair()
// public void testSignature() throws InvalidCertificateException, InvalidKeyException {
// public void testSignature() throws InvalidCertificateException, InvalidKeyException {
func testSignature() {
// ECKeyPair serverKey = Curve.generateKeyPair();
// ECKeyPair key = Curve.generateKeyPair();
// ECKeyPair serverKey = Curve.generateKeyPair();
// ECKeyPair key = Curve.generateKeyPair();
let serverKey = Curve25519.generateKeyPair()
let key = Curve25519.generateKeyPair()
// byte[] certificateBytes = SignalProtos.SenderCertificate.Certificate.newBuilder()
// .setSender("+14152222222")
// .setSenderDevice(1)
// .setExpires(31337)
// .setIdentityKey(ByteString.copyFrom(key.getPublicKey().serialize()))
// .setSigner(getServerCertificate(serverKey))
// .build()
// .toByteArray();
// byte[] certificateBytes = SignalProtos.SenderCertificate.Certificate.newBuilder()
// .setSender("+14152222222")
// .setSenderDevice(1)
// .setExpires(31337)
// .setIdentityKey(ByteString.copyFrom(key.getPublicKey().serialize()))
// .setSigner(getServerCertificate(serverKey))
// .build()
// .toByteArray();
let signer = try! getServerCertificate(serverKey: serverKey)
let builder = try! SMKProtoSenderCertificateCertificate.builder(senderDevice: 1,
expires: 31337,
identityKey: key.ecPublicKey().serialized,
signer: signer)
builder.setSenderUuid(aliceAddress.uuid!.uuidString)
let certificateData = try! builder.buildSerializedData()
let senderRecipientId = "+14152222222"
let senderDeviceId: UInt32 = 1
let expirationTimestamp: UInt64 = 31337
// byte[] certificateSignature = Curve.calculateSignature(serverKey.getPrivateKey(), certificateBytes);
let certificateSignature = try! Ed25519.sign(certificateData, with: serverKey)
let serverCertificate = getServerCertificate(serverKey: serverKey, trustRoot: trustRoot)
let unsignedCertificateBuilder = SMKProtoSenderCertificateCertificate.builder(sender: senderRecipientId,
senderDevice: senderDeviceId,
expires: expirationTimestamp,
identityKey: try! key.ecPublicKey().serialized,
signer: try! serverCertificate.toProto())
unsignedCertificateBuilder.setSigner(try! serverCertificate.toProto())
let unsignedSenderCertificateData = try! unsignedCertificateBuilder.build().serializedData()
// SenderCertificate senderCertificate = new SenderCertificate(SignalProtos.SenderCertificate.newBuilder()
// .setCertificate(ByteString.copyFrom(certificateBytes))
// .setSignature(ByteString.copyFrom(certificateSignature))
// .build()
// .toByteArray());
let senderCertificateData = try! SMKProtoSenderCertificate.builder(certificate: certificateData,
signature: certificateSignature)
.buildSerializedData()
let senderCertificate = try! SenderCertificate(senderCertificateData)
// byte[] certificateSignature = Curve.calculateSignature(serverKey.getPrivateKey(), certificateBytes);
let senderCertificateSignature = try! Ed25519.sign(unsignedSenderCertificateData, with: serverKey)
// SenderCertificate senderCertificate = new SenderCertificate(SignalProtos.SenderCertificate.newBuilder()
// .setCertificate(ByteString.copyFrom(certificateBytes))
// .setSignature(ByteString.copyFrom(certificateSignature))
// .build()
// .toByteArray());
let signedSenderCertificate = SMKSenderCertificate(signer: serverCertificate,
key: try! key.ecPublicKey(),
senderDeviceId: senderDeviceId,
senderRecipientId: senderRecipientId,
expirationTimestamp: expirationTimestamp,
signatureData: senderCertificateSignature)
// new CertificateValidator(trustRoot.getPublicKey()).validate(senderCertificate, 31336);
// new CertificateValidator(trustRoot.getPublicKey()).validate(senderCertificate, 31336);
let certificateValidator = try! SMKCertificateDefaultValidator(trustRoot: trustRoot.ecPublicKey())
try! certificateValidator.throwswrapped_validate(senderCertificate: signedSenderCertificate, validationTime: 31336)
XCTAssertNoThrow(try certificateValidator.throwswrapped_validate(senderCertificate: senderCertificate,
validationTime: 31336))
}
// public void testExpiredSignature() throws InvalidCertificateException, InvalidKeyException {
// public void testExpiredSignature() throws InvalidCertificateException, InvalidKeyException {
func testExpiredSignature() {
// ECKeyPair serverKey = Curve.generateKeyPair();
// ECKeyPair key = Curve.generateKeyPair();
// ECKeyPair serverKey = Curve.generateKeyPair();
// ECKeyPair key = Curve.generateKeyPair();
let serverKey = Curve25519.generateKeyPair()
let key = Curve25519.generateKeyPair()
let key = Curve25519.generateKeyPair()
// byte[] certificateBytes = SignalProtos.SenderCertificate.Certificate.newBuilder()
// .setSender("+14152222222")
// .setSenderDevice(1)
// .setExpires(31337)
// .setIdentityKey(ByteString.copyFrom(key.getPublicKey().serialize()))
// .setSigner(getServerCertificate(serverKey))
// .build()
// .toByteArray();
let senderRecipientId = "+14152222222"
let senderDeviceId: UInt32 = 1
let expirationTimestamp: UInt64 = 31337
// byte[] certificateBytes = SignalProtos.SenderCertificate.Certificate.newBuilder()
// .setSender("+14152222222")
// .setSenderDevice(1)
// .setExpires(31337)
// .setIdentityKey(ByteString.copyFrom(key.getPublicKey().serialize()))
// .setSigner(getServerCertificate(serverKey))
// .build()
// .toByteArray();
let signer = try! getServerCertificate(serverKey: serverKey)
let builder = try! SMKProtoSenderCertificateCertificate.builder(senderDevice: 1,
expires: 31337,
identityKey: key.ecPublicKey().serialized,
signer: signer)
builder.setSenderUuid(aliceAddress.uuid!.uuidString)
let certificateData = try! builder.buildSerializedData()
let serverCertificate = getServerCertificate(serverKey: serverKey, trustRoot: trustRoot)
let unsignedCertificateBuilder = SMKProtoSenderCertificateCertificate.builder(sender: senderRecipientId,
senderDevice: senderDeviceId,
expires: expirationTimestamp,
identityKey: try! key.ecPublicKey().serialized,
signer: try! serverCertificate.toProto())
let unsignedSenderCertificateData = try! unsignedCertificateBuilder.build().serializedData()
// byte[] certificateSignature = Curve.calculateSignature(serverKey.getPrivateKey(), certificateBytes);
let certificateSignature = try! Ed25519.sign(certificateData, with: serverKey)
// byte[] certificateSignature = Curve.calculateSignature(serverKey.getPrivateKey(), certificateBytes);
let senderCertificateSignature = try! Ed25519.sign(unsignedSenderCertificateData, with: serverKey)
// SenderCertificate senderCertificate = new SenderCertificate(SignalProtos.SenderCertificate.newBuilder()
// .setCertificate(ByteString.copyFrom(certificateBytes))
// .setSignature(ByteString.copyFrom(certificateSignature))
// .build()
// .toByteArray());
let senderCertificateData = try! SMKProtoSenderCertificate.builder(certificate: certificateData,
signature: certificateSignature)
.buildSerializedData()
let senderCertificate = try! SenderCertificate(senderCertificateData)
// SenderCertificate senderCertificate = new SenderCertificate(SignalProtos.SenderCertificate.newBuilder()
// .setCertificate(ByteString.copyFrom(certificateBytes))
// .setSignature(ByteString.copyFrom(certificateSignature))
// .build()
// .toByteArray());
let signedSenderCertificate = SMKSenderCertificate(signer: serverCertificate,
key: try! key.ecPublicKey(),
senderDeviceId: senderDeviceId,
senderRecipientId: senderRecipientId,
expirationTimestamp: expirationTimestamp,
signatureData: senderCertificateSignature)
// try {
// new CertificateValidator(trustRoot.getPublicKey()).validate(senderCertificate, 31338);
// throw new AssertionError();
// } catch (InvalidCertificateException e) {
// // good
// }
// try {
// new CertificateValidator(trustRoot.getPublicKey()).validate(senderCertificate, 31338);
// throw new AssertionError();
// } catch (InvalidCertificateException e) {
// // good
// }
let certificateValidator = try! SMKCertificateDefaultValidator(trustRoot: trustRoot.ecPublicKey())
XCTAssertThrowsError(try certificateValidator.throwswrapped_validate(senderCertificate: signedSenderCertificate, validationTime: 31338))
XCTAssertThrowsError(try certificateValidator.throwswrapped_validate(senderCertificate: senderCertificate, validationTime: 31338))
}
// public void testBadSignature() throws InvalidCertificateException, InvalidKeyException {
// public void testBadSignature() throws InvalidCertificateException, InvalidKeyException {
func testBadSignature() {
// ECKeyPair serverKey = Curve.generateKeyPair();
// ECKeyPair key = Curve.generateKeyPair();
// ECKeyPair serverKey = Curve.generateKeyPair();
// ECKeyPair key = Curve.generateKeyPair();
let serverKey = Curve25519.generateKeyPair()
let key = Curve25519.generateKeyPair()
let key = Curve25519.generateKeyPair()
// byte[] certificateBytes = SignalProtos.SenderCertificate.Certificate.newBuilder()
// .setSender("+14152222222")
// .setSenderDevice(1)
// .setExpires(31337)
// .setIdentityKey(ByteString.copyFrom(key.getPublicKey().serialize()))
// .setSigner(getServerCertificate(serverKey))
// .build()
// .toByteArray();
let senderRecipientId = "+14152222222"
let senderDeviceId: UInt32 = 1
let expirationTimestamp: UInt64 = 31337
// byte[] certificateBytes = SignalProtos.SenderCertificate.Certificate.newBuilder()
// .setSender("+14152222222")
// .setSenderDevice(1)
// .setExpires(31337)
// .setIdentityKey(ByteString.copyFrom(key.getPublicKey().serialize()))
// .setSigner(getServerCertificate(serverKey))
// .build()
// .toByteArray();
let signer = try! getServerCertificate(serverKey: serverKey)
let builder = try! SMKProtoSenderCertificateCertificate.builder(senderDevice: 1,
expires: 31337,
identityKey: key.ecPublicKey().serialized,
signer: signer)
builder.setSenderUuid(aliceAddress.uuid!.uuidString)
let certificateData = try! builder.buildSerializedData()
let serverCertificate = getServerCertificate(serverKey: serverKey, trustRoot: trustRoot)
let unsignedCertificateBuilder = SMKProtoSenderCertificateCertificate.builder(sender: senderRecipientId,
senderDevice: senderDeviceId,
expires: expirationTimestamp,
identityKey: try! key.ecPublicKey().serialized,
signer: try! serverCertificate.toProto())
let unsignedSenderCertificateData = try! unsignedCertificateBuilder.build().serializedData()
// byte[] certificateSignature = Curve.calculateSignature(serverKey.getPrivateKey(), certificateBytes);
let certificateSignature = try! Ed25519.sign(certificateData, with: serverKey)
// byte[] certificateSignature = Curve.calculateSignature(serverKey.getPrivateKey(), certificateBytes);
let senderCertificateSignature = try! Ed25519.sign(unsignedSenderCertificateData, with: serverKey)
// for (int i=0;i<certificateSignature.length;i++) {
for i in 0..<senderCertificateSignature.count {
// for (int b=0;b<8;b++) {
// for (int i=0;i<certificateSignature.length;i++) {
// for (int b=0;b<8;b++) {
for i in 0..<certificateSignature.count {
for b in 0..<8 {
// byte[] badSignature = new byte[certificateSignature.length];
// System.arraycopy(certificateSignature, 0, badSignature, 0, certificateSignature.length);
var badSignature = senderCertificateSignature
// badSignature[i] = (byte)(badSignature[i] ^ 1 << b);
badSignature.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer<UInt8>) in
bytes[i] = (UInt8)(bytes[i] ^ 1 << b)
// byte[] badSignature = new byte[certificateSignature.length];
// System.arraycopy(certificateSignature, 0, badSignature, 0, certificateSignature.length);
//
// badSignature[i] = (byte)(badSignature[i] ^ 1 << b);
var badSignature = certificateSignature
badSignature.withUnsafeMutableBytes { (bytes: UnsafeMutableRawBufferPointer) in
bytes[i] = (bytes[i] ^ 1 << b)
}
// SenderCertificate senderCertificate = new SenderCertificate(SignalProtos.SenderCertificate.newBuilder()
// .setCertificate(ByteString.copyFrom(certificateBytes))
// .setSignature(ByteString.copyFrom(badSignature))
// .build()
// .toByteArray());
let signedSenderCertificate = SMKSenderCertificate(signer: serverCertificate,
key: try! key.ecPublicKey(),
senderDeviceId: senderDeviceId,
senderRecipientId: senderRecipientId,
expirationTimestamp: expirationTimestamp,
signatureData: badSignature)
// SenderCertificate senderCertificate = new SenderCertificate(SignalProtos.SenderCertificate.newBuilder()
// .setCertificate(ByteString.copyFrom(certificateBytes))
// .setSignature(ByteString.copyFrom(badSignature))
// .build()
// .toByteArray());
let serializedData = try! SMKProtoSenderCertificate.builder(certificate: certificateData,
signature: badSignature).buildSerializedData()
let senderCertificate = try! SenderCertificate(serializedData)
// try {
// new CertificateValidator(trustRoot.getPublicKey()).validate(senderCertificate, 31336);
// throw new AssertionError();
// } catch (InvalidCertificateException e) {
// // good
// }
// try {
// new CertificateValidator(trustRoot.getPublicKey()).validate(senderCertificate, 31336);
// throw new AssertionError();
// } catch (InvalidCertificateException e) {
// // good
// }
let certificateValidator = try! SMKCertificateDefaultValidator(trustRoot: trustRoot.ecPublicKey())
XCTAssertThrowsError(try certificateValidator.throwswrapped_validate(senderCertificate: signedSenderCertificate, validationTime: 31336))
XCTAssertThrowsError(try certificateValidator.throwswrapped_validate(senderCertificate: senderCertificate,
validationTime: 31336))
}
}
}
// MARK: - Utils
// private SignalProtos.ServerCertificate getServerCertificate(ECKeyPair serverKey) throws InvalidKeyException, InvalidCertificateException {
private func getServerCertificate(serverKey: ECKeyPair, trustRoot: ECKeyPair) -> SMKServerCertificate {
// byte[] certificateBytes = SignalProtos.ServerCertificate.Certificate.newBuilder()
// .setId(1)
// .setKey(ByteString.copyFrom(serverKey.getPublicKey().serialize()))
// .build()
// .toByteArray();
let keyId: UInt32 = 1
let unsignedServerCertificateBuilder = SMKProtoServerCertificateCertificate.builder(id: keyId,
key: try! serverKey.ecPublicKey().serialized)
let unsignedServerCertificateData = try! unsignedServerCertificateBuilder.build().serializedData()
// private SignalProtos.ServerCertificate getServerCertificate(ECKeyPair serverKey) throws InvalidKeyException, InvalidCertificateException {
private func getServerCertificate(serverKey: ECKeyPair) throws -> SMKProtoServerCertificate {
// byte[] certificateBytes = SignalProtos.ServerCertificate.Certificate.newBuilder()
// .setId(1)
// .setKey(ByteString.copyFrom(serverKey.getPublicKey().serialize()))
// .build()
// .toByteArray();
let certificateData = try! SMKProtoServerCertificateCertificate.builder(id: 1,
key: serverKey.ecPublicKey().serialized)
.buildSerializedData()
// byte[] certificateSignature = Curve.calculateSignature(trustRoot.getPrivateKey(), certificateBytes);
let serverCertificateSignature = try! Ed25519.sign(unsignedServerCertificateData, with: trustRoot)
// byte[] certificateSignature = Curve.calculateSignature(trustRoot.getPrivateKey(), certificateBytes);
let certificateSignature = try! Ed25519.sign(certificateData, with: trustRoot)
// return SignalProtos.ServerCertificate.newBuilder()
// .setCertificate(ByteString.copyFrom(certificateBytes))
// .setSignature(ByteString.copyFrom(certificateSignature))
// .build();
let signedServerCertificate = SMKServerCertificate(keyId: keyId,
key: try! serverKey.ecPublicKey(),
signatureData: serverCertificateSignature)
return signedServerCertificate
// return SignalProtos.ServerCertificate.newBuilder()
// .setCertificate(ByteString.copyFrom(certificateBytes))
// .setSignature(ByteString.copyFrom(certificateSignature))
// .build();
return try! SMKProtoServerCertificate.builder(certificate: certificateData,
signature: certificateSignature).build()
}
}

View File

@ -1,198 +1,185 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
// Copyright (c) 2020 Open Whisper Systems. All rights reserved.
//
import XCTest
import SwiftProtobuf
import Curve25519Kit
import SignalMetadataKit
import SignalClient
// See: https://github.com/signalapp/libsignal-metadata-java/blob/master/tests/src/test/java/org/signal/libsignal/metadata/certificate/ServerCertificateTest.java
//
// public class ServerCertificateTest extends TestCase {
class SMKServerCertificateTest: XCTestCase {
override func setUp() {
super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}
// public void testBadFields() {
// public void testBadFields() {
func testBadFields() {
// NOTE: We don't want to (and can't) test this.
// Our Swift proto wrappers ensure that we never have missing fields.
// SignalProtos.ServerCertificate.Certificate.Builder certificate = SignalProtos.ServerCertificate.Certificate.newBuilder();
//
// try {
// new ServerCertificate(SignalProtos.ServerCertificate.newBuilder().setSignature(ByteString.copyFrom(new byte[64])).build().toByteArray());
// throw new AssertionError();
// } catch (InvalidCertificateException e) {
// // good
// }
//
// try {
// new ServerCertificate(SignalProtos.ServerCertificate.newBuilder().setCertificate(certificate.build().toByteString())
// .setSignature(ByteString.copyFrom(new byte[64])).build().toByteArray());
// throw new AssertionError();
// } catch (InvalidCertificateException e) {
// // good
// }
//
// try {
// new ServerCertificate(SignalProtos.ServerCertificate.newBuilder().setCertificate(certificate.setId(1).build().toByteString())
// .setSignature(ByteString.copyFrom(new byte[64])).build().toByteArray());
// throw new AssertionError();
// } catch (InvalidCertificateException e) {
// // good
// }
// SignalProtos.ServerCertificate.Certificate.Builder certificate = SignalProtos.ServerCertificate.Certificate.newBuilder();
//
// try {
// new ServerCertificate(SignalProtos.ServerCertificate.newBuilder().setSignature(ByteString.copyFrom(new byte[64])).build().toByteArray());
// throw new AssertionError();
// } catch (InvalidCertificateException e) {
// // good
// }
//
// try {
// new ServerCertificate(SignalProtos.ServerCertificate.newBuilder().setCertificate(certificate.build().toByteString())
// .setSignature(ByteString.copyFrom(new byte[64])).build().toByteArray());
// throw new AssertionError();
// } catch (InvalidCertificateException e) {
// // good
// }
//
// try {
// new ServerCertificate(SignalProtos.ServerCertificate.newBuilder().setCertificate(certificate.setId(1).build().toByteString())
// .setSignature(ByteString.copyFrom(new byte[64])).build().toByteArray());
// throw new AssertionError();
// } catch (InvalidCertificateException e) {
// // good
// }
}
// public void testSignature() throws InvalidKeyException, InvalidCertificateException {
// public void testSignature() throws InvalidKeyException, InvalidCertificateException {
func testSignature() {
// ECKeyPair trustRoot = Curve.generateKeyPair();
// ECKeyPair keyPair = Curve.generateKeyPair();
// ECKeyPair trustRoot = Curve.generateKeyPair();
// ECKeyPair keyPair = Curve.generateKeyPair();
let trustRoot = Curve25519.generateKeyPair()
let keyPair = Curve25519.generateKeyPair()
// SignalProtos.ServerCertificate.Certificate certificate = SignalProtos.ServerCertificate.Certificate.newBuilder()
// .setId(1)
// .setKey(ByteString.copyFrom(keyPair.getPublicKey().serialize()))
// .build();
let keyId: UInt32 = 1
let unsignedServerCertificateBuilder = SMKProtoServerCertificateCertificate.builder(id: keyId,
key: try! keyPair.ecPublicKey().serialized)
// SignalProtos.ServerCertificate.Certificate certificate = SignalProtos.ServerCertificate.Certificate.newBuilder()
// .setId(1)
// .setKey(ByteString.copyFrom(keyPair.getPublicKey().serialize()))
// .build();
let certificateBuilder = SMKProtoServerCertificateCertificate.builder(id: 1,
key: try! keyPair.ecPublicKey().serialized)
// byte[] certificateBytes = certificate.toByteArray();
let certificateData = try! certificateBuilder.build().serializedData()
// byte[] certificateBytes = certificate.toByteArray();
let unsignedServerCertificateData = try! unsignedServerCertificateBuilder.build().serializedData()
// byte[] certificateSignature = Curve.calculateSignature(trustRoot.getPrivateKey(), certificateBytes);
let certificateSignature = try! Ed25519.sign(certificateData, with: trustRoot)
// byte[] certificateSignature = Curve.calculateSignature(trustRoot.getPrivateKey(), certificateBytes);
let serverCertificateSignature = try! Ed25519.sign(unsignedServerCertificateData, with: trustRoot)
// byte[] serialized = SignalProtos.ServerCertificate.newBuilder()
// .setCertificate(ByteString.copyFrom(certificateBytes))
// .setSignature(ByteString.copyFrom(certificateSignature))
// .build().toByteArray();
//
let serializedData = try! SMKProtoServerCertificate.builder(certificate: certificateData,
signature: certificateSignature)
.buildSerializedData()
// byte[] serialized = SignalProtos.ServerCertificate.newBuilder()
// .setCertificate(ByteString.copyFrom(certificateBytes))
// .setSignature(ByteString.copyFrom(certificateSignature))
// .build().toByteArray();
let signedServerCertificate = SMKServerCertificate(keyId: keyId,
key: try! keyPair.ecPublicKey(),
signatureData: serverCertificateSignature)
let serializedData = try! signedServerCertificate.serialized()
let parsed = try! SMKServerCertificate.parse(data: serializedData)
// new CertificateValidator(trustRoot.getPublicKey()).validate(new ServerCertificate(serialized));
// new CertificateValidator(trustRoot.getPublicKey()).validate(new ServerCertificate(serialized));
let serverCertificate = try! ServerCertificate(serializedData)
let certificateValidator = SMKCertificateDefaultValidator(trustRoot: try! trustRoot.ecPublicKey())
try! certificateValidator.throwswrapped_validate(serverCertificate: parsed)
try! certificateValidator.throwswrapped_validate(serverCertificate: serverCertificate)
}
// public void testBadSignature() throws Exception {
// public void testBadSignature() throws Exception {
func testBadSignature() {
// ECKeyPair trustRoot = Curve.generateKeyPair();
// ECKeyPair keyPair = Curve.generateKeyPair();
// ECKeyPair trustRoot = Curve.generateKeyPair();
// ECKeyPair keyPair = Curve.generateKeyPair();
let trustRoot = Curve25519.generateKeyPair()
let keyPair = Curve25519.generateKeyPair()
// SignalProtos.ServerCertificate.Certificate certificate = SignalProtos.ServerCertificate.Certificate.newBuilder()
// .setId(1)
// .setKey(ByteString.copyFrom(keyPair.getPublicKey().serialize()))
// .build();
let keyId: UInt32 = 1
let unsignedServerCertificateBuilder = SMKProtoServerCertificateCertificate.builder(id: keyId,
key: try! keyPair.ecPublicKey().serialized)
// SignalProtos.ServerCertificate.Certificate certificate = SignalProtos.ServerCertificate.Certificate.newBuilder()
// .setId(1)
// .setKey(ByteString.copyFrom(keyPair.getPublicKey().serialize()))
// .build();
let certificate = try! SMKProtoServerCertificateCertificate.builder(id: 1,
key: try! keyPair.ecPublicKey().serialized)
.build()
// byte[] certificateBytes = certificate.toByteArray();
let unsignedServerCertificateData = try! unsignedServerCertificateBuilder.build().serializedData()
// byte[] certificateBytes = certificate.toByteArray();
let certificateData = try! certificate.serializedData()
// byte[] certificateSignature = Curve.calculateSignature(trustRoot.getPrivateKey(), certificateBytes);
let serverCertificateSignature = try! Ed25519.sign(unsignedServerCertificateData, with: trustRoot)
// byte[] certificateSignature = Curve.calculateSignature(trustRoot.getPrivateKey(), certificateBytes);
let certificateSignature = try! Ed25519.sign(certificateData, with: trustRoot)
// for (int i=0;i<certificateSignature.length;i++) {
for i in 0..<serverCertificateSignature.count {
// for (int b=0;b<8;b++) {
// for (int i=0;i<certificateSignature.length;i++) {
// for (int b=0;b<8;b++) {
for i in 0..<certificateSignature.count {
for b in 0..<8 {
// byte[] badSignature = new byte[certificateSignature.length];
// System.arraycopy(certificateSignature, 0, badSignature, 0, badSignature.length);
var badSignature = serverCertificateSignature
// badSignature[i] = (byte) (badSignature[i] ^ (1 << b));
badSignature.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer<UInt8>) in
bytes[i] = (UInt8)(bytes[i] ^ 1 << b)
// byte[] badSignature = new byte[certificateSignature.length];
// System.arraycopy(certificateSignature, 0, badSignature, 0, badSignature.length);
//
// badSignature[i] = (byte) (badSignature[i] ^ (1 << b));
var badSignature = certificateSignature
badSignature.withUnsafeMutableBytes { (bytes: UnsafeMutableRawBufferPointer) in
bytes[i] = (bytes[i] ^ 1 << b)
}
// byte[] serialized = SignalProtos.ServerCertificate.newBuilder()
// .setCertificate(ByteString.copyFrom(certificateBytes))
// .setSignature(ByteString.copyFrom(badSignature))
// .build().toByteArray();
let signedServerCertificate = SMKServerCertificate(keyId: keyId,
key: try! keyPair.ecPublicKey(),
signatureData: badSignature)
let serializedData = try! signedServerCertificate.serialized()
let parsed = try! SMKServerCertificate.parse(data: serializedData)
// byte[] serialized = SignalProtos.ServerCertificate.newBuilder()
// .setCertificate(ByteString.copyFrom(certificateBytes))
// .setSignature(ByteString.copyFrom(badSignature))
// .build().toByteArray();
let serializedData = try! SMKProtoServerCertificate.builder(certificate: certificateData,
signature: badSignature)
.buildSerializedData()
// try {
// new CertificateValidator(trustRoot.getPublicKey()).validate(new ServerCertificate(serialized));
// throw new AssertionError();
// } catch (InvalidCertificateException e) {
// // good
// }
// try {
// new CertificateValidator(trustRoot.getPublicKey()).validate(new ServerCertificate(serialized));
// throw new AssertionError();
// } catch (InvalidCertificateException e) {
// // good
// }
let serverCertificate = try! ServerCertificate(serializedData)
let certificateValidator = SMKCertificateDefaultValidator(trustRoot: try! trustRoot.ecPublicKey())
XCTAssertThrowsError(try certificateValidator.throwswrapped_validate(serverCertificate: parsed))
XCTAssertThrowsError(try certificateValidator.throwswrapped_validate(serverCertificate: serverCertificate))
}
}
// for (int i=0;i<certificateBytes.length;i++) {
for i in 0..<unsignedServerCertificateData.count {
// for (int b=0;b<8;b++) {
// for (int i=0;i<certificateBytes.length;i++) {
// for (int b=0;b<8;b++) {
for i in 0..<certificateData.count {
for b in 0..<8 {
// byte[] badCertificate = new byte[certificateBytes.length];
// System.arraycopy(certificateBytes, 0, badCertificate, 0, badCertificate.length);
var badCertificate = unsignedServerCertificateData
// badCertificate[i] = (byte) (badCertificate[i] ^ (1 << b));
badCertificate.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer<UInt8>) in
bytes[i] = (UInt8)(bytes[i] ^ 1 << b)
// byte[] badCertificate = new byte[certificateBytes.length];
// System.arraycopy(certificateBytes, 0, badCertificate, 0, badCertificate.length);
//
// badCertificate[i] = (byte) (badCertificate[i] ^ (1 << b));
var badCertificate = certificateData
badCertificate.withUnsafeMutableBytes { (bytes: UnsafeMutableRawBufferPointer) in
bytes[i] = (bytes[i] ^ 1 << b)
}
// byte[] serialized = SignalProtos.ServerCertificate.newBuilder()
// .setCertificate(ByteString.copyFrom(badCertificate))
// .setSignature(ByteString.copyFrom(certificateSignature))
// .build().toByteArray();
let builder =
SMKProtoServerCertificate.builder(certificate: badCertificate, signature: serverCertificateSignature)
let serializedData = try! builder.buildSerializedData()
let parsed: SMKServerCertificate
// byte[] serialized = SignalProtos.ServerCertificate.newBuilder()
// .setCertificate(ByteString.copyFrom(badCertificate))
// .setSignature(ByteString.copyFrom(certificateSignature))
// .build().toByteArray();
let serializedData = try! SMKProtoServerCertificate.builder(certificate: badCertificate,
signature: certificateSignature)
.buildSerializedData()
// try {
// new CertificateValidator(trustRoot.getPublicKey()).validate(new ServerCertificate(serialized));
// throw new AssertionError();
// } catch (InvalidCertificateException e) {
// // good
// }
let serverCertificate: ServerCertificate
do {
parsed = try SMKServerCertificate.parse(data: serializedData)
} catch BinaryDecodingError.malformedProtobuf {
// Some bad certificates will fail to parse.
continue
} catch BinaryDecodingError.truncated {
// Some bad certificates will fail to parse.
continue
} catch SMKProtoError.invalidProtobuf {
// Some bad certificates will fail to parse.
continue
} catch SMKError.assertionError {
serverCertificate = try ServerCertificate(serializedData)
} catch SignalError.protobufError,
SignalError.invalidMessage,
SignalError.invalidKey {
// Some bad certificates will fail to parse.
continue
} catch {
XCTFail("Unexpected parsing error: \(error)")
continue
}
//
// try {
// new CertificateValidator(trustRoot.getPublicKey()).validate(new ServerCertificate(serialized));
// throw new AssertionError();
// } catch (InvalidCertificateException e) {
// // good
// }
// }
// try {
// new CertificateValidator(trustRoot.getPublicKey()).validate(new ServerCertificate(serialized));
// throw new AssertionError();
// } catch (InvalidCertificateException e) {
// // good
// }
let certificateValidator = SMKCertificateDefaultValidator(trustRoot: try! trustRoot.ecPublicKey())
XCTAssertThrowsError(try certificateValidator.throwswrapped_validate(serverCertificate: parsed))
XCTAssertThrowsError(try certificateValidator.throwswrapped_validate(serverCertificate: serverCertificate))
}
}
}

View File

@ -1,333 +0,0 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
import XCTest
import SignalMetadataKit
extension MutableCollection {
/// Shuffles the contents of this collection.
mutating func ows_shuffle() {
let c = count
guard c > 1 else { return }
for (firstUnshuffled, unshuffledCount) in zip(indices, stride(from: c, to: 1, by: -1)) {
// Change `Int` in the next line to `IndexDistance` in < Swift 4.1
let d: Int = numericCast(arc4random_uniform(numericCast(unshuffledCount)))
let i = index(firstUnshuffled, offsetBy: d)
swapAt(firstUnshuffled, i)
}
}
}
extension Sequence {
/// Returns an array with the contents of this sequence, shuffled.
func shuffled() -> [Element] {
var result = Array(self)
result.ows_shuffle()
return result
}
}
// See: https://github.com/signalapp/libsignal-metadata-java/blob/master/tests/src/test/java/org/signal/libsignal/metadata/SessionCipherTest.java
// public class SessionCipherTest extends TestCase {
class SMKSessionCipherTest: XCTestCase {
override func setUp() {
super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}
// public void testBasicSessionV3()
// throws InvalidKeyException, DuplicateMessageException,
// LegacyMessageException, InvalidMessageException, NoSuchAlgorithmException, NoSessionException, UntrustedIdentityException
func testBasicSessionV3() {
// NOTE: We use MockClient to ensure consistency between of our session state.
let aliceMockClient = MockClient(recipientId: "+14159999999", deviceId: 1, registrationId: 1234)
let bobMockClient = MockClient(recipientId: "+14158888888", deviceId: 1, registrationId: 1235)
// SessionRecord aliceSessionRecord = new SessionRecord();
// SessionRecord bobSessionRecord = new SessionRecord();
let aliceSessionRecord = SessionRecord()!
let bobSessionRecord = SessionRecord()!
// initializeSessionsV3(aliceSessionRecord.getSessionState(), bobSessionRecord.getSessionState());
initializeSessionsV3(aliceSessionState: aliceSessionRecord.sessionState()!,
bobSessionState: bobSessionRecord.sessionState()!,
aliceMockClient: aliceMockClient,
bobMockClient: bobMockClient)
// runInteraction(aliceSessionRecord, bobSessionRecord);
runInteraction(aliceSessionRecord: aliceSessionRecord,
bobSessionRecord: bobSessionRecord,
aliceMockClient: aliceMockClient,
bobMockClient: bobMockClient)
}
// public void testMessageKeyLimits() throws Exception {
func testMessageKeyLimits() {
// NOTE: We use MockClient to ensure consistency between of our session state.
let aliceMockClient = MockClient(recipientId: "+14159999999", deviceId: 1, registrationId: 1234)
let bobMockClient = MockClient(recipientId: "+14158888888", deviceId: 1, registrationId: 1235)
// SessionRecord aliceSessionRecord = new SessionRecord();
// SessionRecord bobSessionRecord = new SessionRecord();
let aliceSessionRecord = SessionRecord()!
let bobSessionRecord = SessionRecord()!
// initializeSessionsV3(aliceSessionRecord.getSessionState(), bobSessionRecord.getSessionState());
initializeSessionsV3(aliceSessionState: aliceSessionRecord.sessionState()!,
bobSessionState: bobSessionRecord.sessionState()!,
aliceMockClient: aliceMockClient,
bobMockClient: bobMockClient)
// SignalProtocolStore aliceStore = new TestInMemorySignalProtocolStore();
// SignalProtocolStore bobStore = new TestInMemorySignalProtocolStore();
//
// aliceStore.storeSession(new SignalProtocolAddress("+14159999999", 1), aliceSessionRecord);
// bobStore.storeSession(new SignalProtocolAddress("+14158888888", 1), bobSessionRecord);
aliceMockClient.sessionStore.storeSession(aliceMockClient.recipientId, deviceId: aliceMockClient.deviceId, session: aliceSessionRecord, protocolContext: nil)
bobMockClient.sessionStore.storeSession(bobMockClient.recipientId, deviceId: bobMockClient.deviceId, session: bobSessionRecord, protocolContext: nil)
// SessionCipher aliceCipher = new SessionCipher(aliceStore, new SignalProtocolAddress("+14159999999", 1));
// SessionCipher bobCipher = new SessionCipher(bobStore, new SignalProtocolAddress("+14158888888", 1));
let aliceCipher = aliceMockClient.createSessionCipher()
let bobCipher = bobMockClient.createSessionCipher()
// List<CiphertextMessage> inflight = new LinkedList<>();
var inflight = [CipherMessage]()
// for (int i=0;i<2010;i++) {
// inflight.add(aliceCipher.encrypt("you've never been so hungry, you've never been so cold".getBytes()));
// }
for _ in 1...2010 {
let plaintext = "you've never been so hungry, you've never been so cold".data(using: String.Encoding.utf8)!
let message = try! aliceCipher.encryptMessage(plaintext, protocolContext: nil)
inflight.append(message)
}
// bobCipher.decrypt(new SignalMessage(inflight.get(1000).serialize()));
// bobCipher.decrypt(new SignalMessage(inflight.get(inflight.size()-1).serialize()));
let midpointMessage = try! bobCipher.decrypt(inflight[1000], protocolContext: nil)
XCTAssertNotNil(midpointMessage)
let lastMessage = try! bobCipher.decrypt(inflight.last!, protocolContext: nil)
XCTAssertNotNil(lastMessage)
// TODO: Why isn't this failing?
let firstMessage = try! bobCipher.decrypt(inflight[0], protocolContext: nil)
XCTAssertNotNil(firstMessage)
// try {
// bobCipher.decrypt(new SignalMessage(inflight.get(0).serialize()));
// throw new AssertionError("Should have failed!");
// } catch (DuplicateMessageException dme) {
// // good
// }
}
// MARK: - Utils
// private void runInteraction(SessionRecord aliceSessionRecord, SessionRecord bobSessionRecord)
// throws DuplicateMessageException, LegacyMessageException, InvalidMessageException, NoSuchAlgorithmException, NoSessionException, UntrustedIdentityException {
private func runInteraction(aliceSessionRecord: SessionRecord,
bobSessionRecord: SessionRecord,
aliceMockClient: MockClient,
bobMockClient: MockClient) {
// SignalProtocolStore aliceStore = new TestInMemorySignalProtocolStore();
// SignalProtocolStore bobStore = new TestInMemorySignalProtocolStore();
// aliceStore.storeSession(new SignalProtocolAddress("+14159999999", 1), aliceSessionRecord);
// bobStore.storeSession(new SignalProtocolAddress("+14158888888", 1), bobSessionRecord);
aliceMockClient.sessionStore.storeSession(aliceMockClient.recipientId, deviceId: aliceMockClient.deviceId, session: aliceSessionRecord, protocolContext: nil)
bobMockClient.sessionStore.storeSession(bobMockClient.recipientId, deviceId: bobMockClient.deviceId, session: bobSessionRecord, protocolContext: nil)
// SessionCipher aliceCipher = new SessionCipher(aliceStore, new SignalProtocolAddress("+14159999999", 1));
// SessionCipher bobCipher = new SessionCipher(bobStore, new SignalProtocolAddress("+14158888888", 1));
let aliceCipher = aliceMockClient.createSessionCipher()
let bobCipher = bobMockClient.createSessionCipher()
// byte[] alicePlaintext = "This is a plaintext message.".getBytes();
let alicePlaintext = "This is a plaintext message.".data(using: String.Encoding.utf8)!
// TODO: Why isn't the java test padding the plaintext?
let alicePaddedPlaintext = (alicePlaintext as NSData).paddedMessageBody()!
// CiphertextMessage message = aliceCipher.encrypt(alicePlaintext);
let message = try! aliceCipher.encryptMessage(alicePaddedPlaintext, protocolContext: nil)
// byte[] bobPlaintext = bobCipher.decrypt(new SignalMessage(message.serialize()));
let bobPaddedPlaintext = try! bobCipher.decrypt(message, protocolContext: nil)
let bobPlaintext = (bobPaddedPlaintext as NSData).removePadding()
// assertTrue(Arrays.equals(alicePlaintext, bobPlaintext));
XCTAssertEqual(alicePlaintext, bobPlaintext)
// byte[] bobReply = "This is a message from Bob.".getBytes();
let bobReply = "This is a message from Bob.".data(using: String.Encoding.utf8)!
let bobReplyPadded = (bobReply as NSData).paddedMessageBody()!
// CiphertextMessage reply = bobCipher.encrypt(bobReply);
let reply = try! bobCipher.encryptMessage(bobReplyPadded, protocolContext: nil)
// byte[] receivedReply = aliceCipher.decrypt(new SignalMessage(reply.serialize()));
let receivedReplyPadded = try! aliceCipher.decrypt(reply, protocolContext: nil)
let receivedReply = (receivedReplyPadded as NSData).removePadding()
// assertTrue(Arrays.equals(bobReply, receivedReply));
XCTAssertEqual(bobReply, receivedReply)
// List<CiphertextMessage> aliceCiphertextMessages = new ArrayList<>();
// List<byte[]> alicePlaintextMessages = new ArrayList<>();
typealias MessageTuple = (plaintext: Data, message: CipherMessage)
var aliceMessages = [MessageTuple]()
// for (int i=0;i<50;i++) {
// alicePlaintextMessages.add(("смерть за смерть " + i).getBytes());
// aliceCiphertextMessages.add(aliceCipher.encrypt(("смерть за смерть " + i).getBytes()));
for i in 1...50 {
let plaintext = "смерть за смерть \(i)".data(using: String.Encoding.utf8)!
let message = try! aliceCipher.encryptMessage(plaintext, protocolContext: nil)
aliceMessages.append((plaintext:plaintext, message:message))
}
// long seed = System.currentTimeMillis();
//
// Collections.shuffle(aliceCiphertextMessages, new Random(seed));
// Collections.shuffle(alicePlaintextMessages, new Random(seed));
aliceMessages = aliceMessages.shuffled()
// for (int i=0;i<aliceCiphertextMessages.size() / 2;i++) {
// byte[] receivedPlaintext = bobCipher.decrypt(new SignalMessage(aliceCiphertextMessages.get(i).serialize()));
// assertTrue(Arrays.equals(receivedPlaintext, alicePlaintextMessages.get(i)));
// }
let alicePivot = aliceMessages.count / 2
let aliceMessagesLeft = aliceMessages[0 ..< alicePivot]
let aliceMessagesRight = aliceMessages[alicePivot ..< aliceMessages.count]
for (plaintext, message) in aliceMessagesLeft {
let receivedPlaintext = try! bobCipher.decrypt(message, protocolContext: nil)
XCTAssertEqual(plaintext, receivedPlaintext)
}
// List<CiphertextMessage> bobCiphertextMessages = new ArrayList<>();
// List<byte[]> bobPlaintextMessages = new ArrayList<>();
var bobMessages = [MessageTuple]()
// for (int i=0;i<20;i++) {
// bobPlaintextMessages.add(("смерть за смерть " + i).getBytes());
// bobCiphertextMessages.add(bobCipher.encrypt(("смерть за смерть " + i).getBytes()));
// }
for i in 1...20 {
let plaintext = "смерть за смерть \(i)".data(using: String.Encoding.utf8)!
let message = try! bobCipher.encryptMessage(plaintext, protocolContext: nil)
bobMessages.append((plaintext:plaintext, message:message))
}
// seed = System.currentTimeMillis();
//
// Collections.shuffle(bobCiphertextMessages, new Random(seed));
// Collections.shuffle(bobPlaintextMessages, new Random(seed));
bobMessages = bobMessages.shuffled()
// for (int i=0;i<bobCiphertextMessages.size() / 2;i++) {
// byte[] receivedPlaintext = aliceCipher.decrypt(new SignalMessage(bobCiphertextMessages.get(i).serialize()));
// assertTrue(Arrays.equals(receivedPlaintext, bobPlaintextMessages.get(i)));
// }
let bobPivot = bobMessages.count / 2
let bobMessagesLeft = bobMessages[0 ..< bobPivot]
let bobMessagesRight = bobMessages[bobPivot ..< bobMessages.count]
for (plaintext, message) in bobMessagesLeft {
let receivedPlaintext = try! aliceCipher.decrypt(message, protocolContext: nil)
XCTAssertEqual(plaintext, receivedPlaintext)
}
// for (int i=aliceCiphertextMessages.size()/2;i<aliceCiphertextMessages.size();i++) {
// byte[] receivedPlaintext = bobCipher.decrypt(new SignalMessage(aliceCiphertextMessages.get(i).serialize()));
// assertTrue(Arrays.equals(receivedPlaintext, alicePlaintextMessages.get(i)));
// }
for (plaintext, message) in aliceMessagesRight {
let receivedPlaintext = try! bobCipher.decrypt(message, protocolContext: nil)
XCTAssertEqual(plaintext, receivedPlaintext)
}
//
// for (int i=bobCiphertextMessages.size() / 2;i<bobCiphertextMessages.size(); i++) {
// byte[] receivedPlaintext = aliceCipher.decrypt(new SignalMessage(bobCiphertextMessages.get(i).serialize()));
// assertTrue(Arrays.equals(receivedPlaintext, bobPlaintextMessages.get(i)));
// }
for (plaintext, message) in bobMessagesRight {
let receivedPlaintext = try! aliceCipher.decrypt(message, protocolContext: nil)
XCTAssertEqual(plaintext, receivedPlaintext)
}
}
// private void initializeSessionsV3(SessionState aliceSessionState, SessionState bobSessionState)
// throws InvalidKeyException
// {
private func initializeSessionsV3(aliceSessionState: SessionState,
bobSessionState: SessionState,
aliceMockClient: MockClient,
bobMockClient: MockClient) {
// ECKeyPair aliceIdentityKeyPair = Curve.generateKeyPair();
let aliceIdentityKeyPair = aliceMockClient.identityKeyPair
// IdentityKeyPair aliceIdentityKey = new IdentityKeyPair(new IdentityKey(aliceIdentityKeyPair.getPublicKey()),
// aliceIdentityKeyPair.getPrivateKey());
// TODO: Is this necessary?
let aliceIdentityKey = aliceIdentityKeyPair
// ECKeyPair aliceBaseKey = Curve.generateKeyPair();
let aliceBaseKey = Curve25519.generateKeyPair()
// ECKeyPair aliceEphemeralKey = Curve.generateKeyPair();
// NOTE: aliceEphemeralKey isn't used.
// ECKeyPair alicePreKey = aliceBaseKey;
// NOTE: alicePreKey isn't used.
// ECKeyPair bobIdentityKeyPair = Curve.generateKeyPair();
let bobIdentityKeyPair = bobMockClient.identityKeyPair
// IdentityKeyPair bobIdentityKey = new IdentityKeyPair(new IdentityKey(bobIdentityKeyPair.getPublicKey()),
// bobIdentityKeyPair.getPrivateKey());
// TODO: Is this necessary?
let bobIdentityKey = bobIdentityKeyPair
// ECKeyPair bobBaseKey = Curve.generateKeyPair();
let bobBaseKey = Curve25519.generateKeyPair()
// ECKeyPair bobEphemeralKey = bobBaseKey;
let bobEphemeralKey = bobBaseKey
// ECKeyPair bobPreKey = Curve.generateKeyPair();
// NOTE: bobPreKey isn't used.
// AliceSignalProtocolParameters aliceParameters = AliceSignalProtocolParameters.newBuilder()
// .setOurBaseKey(aliceBaseKey)
// .setOurIdentityKey(aliceIdentityKey)
// .setTheirOneTimePreKey(Optional.<ECPublicKey>absent())
// .setTheirRatchetKey(bobEphemeralKey.getPublicKey())
// .setTheirSignedPreKey(bobBaseKey.getPublicKey())
// .setTheirIdentityKey(bobIdentityKey.getPublicKey())
// .create();
let aliceParameters = AliceAxolotlParameters(identityKey: aliceIdentityKey,
theirIdentityKey: bobIdentityKey.publicKey,
ourBaseKey: aliceBaseKey,
theirSignedPreKey: bobBaseKey.publicKey,
theirOneTimePreKey: nil,
theirRatchetKey: bobEphemeralKey.publicKey)
// BobSignalProtocolParameters bobParameters = BobSignalProtocolParameters.newBuilder()
// .setOurRatchetKey(bobEphemeralKey)
// .setOurSignedPreKey(bobBaseKey)
// .setOurOneTimePreKey(Optional.<ECKeyPair>absent())
// .setOurIdentityKey(bobIdentityKey)
// .setTheirIdentityKey(aliceIdentityKey.getPublicKey())
// .setTheirBaseKey(aliceBaseKey.getPublicKey())
// .create();
let bobParameters = BobAxolotlParameters(myIdentityKeyPair: bobIdentityKey,
theirIdentityKey: aliceIdentityKey.publicKey,
ourSignedPrekey: bobBaseKey,
ourRatchetKey: bobEphemeralKey,
ourOneTimePrekey: nil,
theirBaseKey: aliceBaseKey.publicKey)
// TODO: We could expose this constant in SessionBuilder.h.
let currentVersion: Int32 = 3
// RatchetingSession.initializeSession(aliceSessionState, aliceParameters);
try! RatchetingSession.initializeSession(aliceSessionState, sessionVersion: currentVersion, aliceParameters: aliceParameters)
// RatchetingSession.initializeSession(bobSessionState, bobParameters);
try! RatchetingSession.initializeSession(bobSessionState, sessionVersion: currentVersion, bobParameters: bobParameters)
}
}

View File

@ -1,89 +1,134 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
// Copyright (c) 2020 Open Whisper Systems. All rights reserved.
//
import Foundation
import SignalMetadataKit
import SignalClient
// Two manipulated-but-valid v1 UUIDs.
let aliceAddress: SMKAddress = .uuid(UUID(uuidString: "aaaaaaaa-7000-11eb-b32a-33b8a8a487a6")!)
let bobAddress: SMKAddress = .uuid(UUID(uuidString: "bbbbbbbb-7000-11eb-b32a-33b8a8a487a6")!)
class MockCertificateValidator: NSObject, SMKCertificateValidator {
@objc public func throwswrapped_validate(senderCertificate: SMKSenderCertificate, validationTime: UInt64) throws {
public func throwswrapped_validate(senderCertificate: SenderCertificate, validationTime: UInt64) throws {
// Do not throw
}
@objc public func throwswrapped_validate(serverCertificate: SMKServerCertificate) throws {
public func throwswrapped_validate(serverCertificate: ServerCertificate) throws {
// Do not throw
}
}
class MockClient: NSObject {
let recipientId: String
var recipientUuid: UUID? {
return address.uuid
}
var recipientE164: String? {
return address.e164
}
let address: SMKAddress
var protocolAddress: ProtocolAddress {
try! ProtocolAddress(name: address.uuid!.uuidString, deviceId: UInt32(deviceId))
}
let deviceId: Int32
let registrationId: Int32
let identityKeyPair: ECKeyPair
let identityKeyPair: IdentityKeyPair
let sessionStore: AxolotlInMemoryStore
let preKeyStore: AxolotlInMemoryStore
let signedPreKeyStore: AxolotlInMemoryStore
let identityStore: AxolotlInMemoryStore
let sessionStore: InMemorySignalProtocolStore
let preKeyStore: InMemorySignalProtocolStore
let signedPreKeyStore: InMemorySignalProtocolStore
let identityStore: InMemorySignalProtocolStore
let senderKeyStore: InMemorySignalProtocolStore
init(recipientId: String, deviceId: Int32, registrationId: Int32) {
self.recipientId = recipientId
init(address: SMKAddress, deviceId: Int32, registrationId: Int32) {
self.address = address
self.deviceId = deviceId
self.registrationId = registrationId
self.identityKeyPair = Curve25519.generateKeyPair()
self.identityKeyPair = IdentityKeyPair.generate()
let protocolStore = AxolotlInMemoryStore(identityKeyPair: identityKeyPair, localRegistrationId: registrationId)
let protocolStore = InMemorySignalProtocolStore(identity: identityKeyPair,
registrationId: UInt32(registrationId))
sessionStore = protocolStore
preKeyStore = protocolStore
signedPreKeyStore = protocolStore
identityStore = protocolStore
}
func createSessionCipher() -> SessionCipher {
return SessionCipher(sessionStore: sessionStore,
preKeyStore: preKeyStore,
signedPreKeyStore: signedPreKeyStore,
identityKeyStore: identityStore,
recipientId: recipientId,
deviceId: deviceId)
senderKeyStore = protocolStore
}
func createSecretSessionCipher() throws -> SMKSecretSessionCipher {
return try SMKSecretSessionCipher(sessionStore: sessionStore,
preKeyStore: preKeyStore,
signedPreKeyStore: signedPreKeyStore,
identityStore: identityStore)
preKeyStore: preKeyStore,
signedPreKeyStore: signedPreKeyStore,
identityStore: identityStore,
senderKeyStore: senderKeyStore)
}
func createSessionBuilder(forRecipient recipient: MockClient) -> SessionBuilder {
return SessionBuilder(sessionStore: sessionStore,
preKeyStore: preKeyStore,
signedPreKeyStore: signedPreKeyStore,
identityKeyStore: identityStore,
recipientId: recipient.recipientId,
deviceId: recipient.deviceId)
}
func generatePreKey() -> PreKeyRecord {
let preKeyId: Int32 = Int32(arc4random_uniform(UInt32(INT32_MAX)))
let keyPair = Curve25519.generateKeyPair()
let preKey = PreKeyRecord(id: preKeyId, keyPair: keyPair)!
self.preKeyStore.storePreKey(preKeyId, preKeyRecord: preKey)
func generateMockPreKey() -> PreKeyRecord {
let preKeyId = UInt32(Int32.random(in: 0...Int32.max))
let preKey = try! PreKeyRecord(id: preKeyId, privateKey: PrivateKey.generate())
try! self.preKeyStore.storePreKey(preKey, id: preKeyId, context: NullContext())
return preKey
}
func generateSignedPreKey() -> SignedPreKeyRecord {
let signedPreKeyId: Int32 = Int32(arc4random_uniform(UInt32(INT32_MAX)))
let keyPair = Curve25519.generateKeyPair()
func generateMockSignedPreKey() -> SignedPreKeyRecord {
let signedPreKeyId = UInt32(Int32.random(in: 0...Int32.max))
let keyPair = IdentityKeyPair.generate()
let generatedAt = Date()
let identityKeyPair = self.identityStore.identityKeyPair(nil)
let signature = try! Ed25519.sign((keyPair.publicKey as NSData).prependKeyType() as Data, with: identityKeyPair)
let signedPreKey = SignedPreKeyRecord(id: signedPreKeyId, keyPair: keyPair, signature: signature, generatedAt: generatedAt)!
self.signedPreKeyStore.storeSignedPreKey(signedPreKeyId, signedPreKeyRecord: signedPreKey)
let identityKeyPair = try! self.identityStore.identityKeyPair(context: NullContext())
let signature = identityKeyPair.privateKey.generateSignature(message: keyPair.publicKey.serialize())
let signedPreKey = try! SignedPreKeyRecord(id: signedPreKeyId,
timestamp: UInt64(generatedAt.timeIntervalSince1970),
privateKey: keyPair.privateKey,
signature: signature)
try! self.signedPreKeyStore.storeSignedPreKey(signedPreKey, id: signedPreKeyId, context: NullContext())
return signedPreKey
}
// Moved from SMKSecretSessionCipherTest.
// private void initializeSessions(TestInMemorySignalProtocolStore aliceStore, TestInMemorySignalProtocolStore bobStore)
// throws InvalidKeyException, UntrustedIdentityException
func initializeSession(with bobMockClient: MockClient) {
// ECKeyPair bobPreKey = Curve.generateKeyPair();
let bobPreKey = bobMockClient.generateMockPreKey()
// IdentityKeyPair bobIdentityKey = bobStore.getIdentityKeyPair();
let bobIdentityKey = bobMockClient.identityKeyPair
// SignedPreKeyRecord bobSignedPreKey = KeyHelper.generateSignedPreKey(bobIdentityKey, 2);
let bobSignedPreKey = bobMockClient.generateMockSignedPreKey()
// PreKeyBundle bobBundle = new PreKeyBundle(1, 1, 1, bobPreKey.getPublicKey(), 2, bobSignedPreKey.getKeyPair().getPublicKey(), bobSignedPreKey.getSignature(), bobIdentityKey.getPublicKey());
let bobBundle = try! PreKeyBundle(registrationId: UInt32(bitPattern: bobMockClient.registrationId),
deviceId: UInt32(bitPattern: bobMockClient.deviceId),
prekeyId: bobPreKey.id,
prekey: bobPreKey.publicKey,
signedPrekeyId: bobSignedPreKey.id,
signedPrekey: bobSignedPreKey.publicKey,
signedPrekeySignature: bobSignedPreKey.signature,
identity: bobIdentityKey.identityKey)
// SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, new SignalProtocolAddress("+14152222222", 1));
// aliceSessionBuilder.process(bobBundle);
let bobProtocolAddress = try! ProtocolAddress(
name: bobMockClient.address.uuid?.uuidString ?? bobMockClient.address.e164!,
deviceId: UInt32(bitPattern: bobMockClient.deviceId))
try! processPreKeyBundle(bobBundle,
for: bobProtocolAddress,
sessionStore: sessionStore,
identityStore: identityStore,
context: NullContext())
// bobStore.storeSignedPreKey(2, bobSignedPreKey);
// bobStore.storePreKey(1, new PreKeyRecord(1, bobPreKey));
// NOTE: These stores are taken care of in the mocks' createKey() methods above.
}
}

View File

@ -1,9 +1,10 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
// Copyright (c) 2020 Open Whisper Systems. All rights reserved.
//
import XCTest
import SignalMetadataKit
import SignalCoreKit
class SMKUDAccessKeyTest: XCTestCase {

View File

@ -3,7 +3,7 @@
PROTOC=protoc \
--proto_path='./'
WRAPPER_SCRIPT=../../Signal-iOS/Scripts/ProtoWrappers.py \
--proto-dir='./' --verbose
--proto-dir='./' --verbose --skip-address-helpers
all: unidentified_delivery_protos

View File

@ -30,8 +30,8 @@ message ServerCertificate {
message SenderCertificate {
message Certificate {
// @required
optional string sender = 1;
optional string senderE164 = 1;
optional string senderUuid = 6;
// @required
optional uint32 senderDevice = 2;
// @required
@ -55,7 +55,6 @@ message UnidentifiedSenderMessage {
MESSAGE = 2;
}
// @required
optional Type type = 1;
// @required
optional SenderCertificate senderCertificate = 2;
@ -69,4 +68,4 @@ message UnidentifiedSenderMessage {
optional bytes encryptedStatic = 2;
// @required
optional bytes encryptedMessage = 3;
}
}