Merge branch 'mkirk/attachment-digest'

// FREEBIE
pull/1/head
Michael Kirk 8 years ago
commit b21c628d56

@ -144,4 +144,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: 1a7633963dbcaa43f298949d83c42c1cd1dce940 PODFILE CHECKSUM: 1a7633963dbcaa43f298949d83c42c1cd1dce940
COCOAPODS: 1.1.1 COCOAPODS: 1.2.0

@ -20,7 +20,6 @@
454021ED1D960ABF00F2126D /* OWSDisappearingMessageFinderTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 454021EC1D960ABF00F2126D /* OWSDisappearingMessageFinderTest.m */; }; 454021ED1D960ABF00F2126D /* OWSDisappearingMessageFinderTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 454021EC1D960ABF00F2126D /* OWSDisappearingMessageFinderTest.m */; };
454092FA1DB7AFDE00579DE1 /* OWSFakeNetworkManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 454092F91DB7AFDE00579DE1 /* OWSFakeNetworkManager.m */; }; 454092FA1DB7AFDE00579DE1 /* OWSFakeNetworkManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 454092F91DB7AFDE00579DE1 /* OWSFakeNetworkManager.m */; };
45458B751CC342B600A02153 /* SignedPreKeyDeletionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 45458B6A1CC342B600A02153 /* SignedPreKeyDeletionTests.m */; }; 45458B751CC342B600A02153 /* SignedPreKeyDeletionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 45458B6A1CC342B600A02153 /* SignedPreKeyDeletionTests.m */; };
45458B761CC342B600A02153 /* TSAttachmentsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 45458B6C1CC342B600A02153 /* TSAttachmentsTest.m */; };
45458B771CC342B600A02153 /* TSMessageStorageTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 45458B6E1CC342B600A02153 /* TSMessageStorageTests.m */; }; 45458B771CC342B600A02153 /* TSMessageStorageTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 45458B6E1CC342B600A02153 /* TSMessageStorageTests.m */; };
45458B781CC342B600A02153 /* TSStorageIdentityKeyStoreTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 45458B6F1CC342B600A02153 /* TSStorageIdentityKeyStoreTests.m */; }; 45458B781CC342B600A02153 /* TSStorageIdentityKeyStoreTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 45458B6F1CC342B600A02153 /* TSStorageIdentityKeyStoreTests.m */; };
45458B791CC342B600A02153 /* TSStoragePreKeyStoreTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 45458B701CC342B600A02153 /* TSStoragePreKeyStoreTests.m */; }; 45458B791CC342B600A02153 /* TSStoragePreKeyStoreTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 45458B701CC342B600A02153 /* TSStoragePreKeyStoreTests.m */; };
@ -79,7 +78,6 @@
454092F81DB7AFDE00579DE1 /* OWSFakeNetworkManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSFakeNetworkManager.h; path = ../../../tests/TestSupport/Fakes/OWSFakeNetworkManager.h; sourceTree = "<group>"; }; 454092F81DB7AFDE00579DE1 /* OWSFakeNetworkManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSFakeNetworkManager.h; path = ../../../tests/TestSupport/Fakes/OWSFakeNetworkManager.h; sourceTree = "<group>"; };
454092F91DB7AFDE00579DE1 /* OWSFakeNetworkManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSFakeNetworkManager.m; path = ../../../tests/TestSupport/Fakes/OWSFakeNetworkManager.m; sourceTree = "<group>"; }; 454092F91DB7AFDE00579DE1 /* OWSFakeNetworkManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSFakeNetworkManager.m; path = ../../../tests/TestSupport/Fakes/OWSFakeNetworkManager.m; sourceTree = "<group>"; };
45458B6A1CC342B600A02153 /* SignedPreKeyDeletionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SignedPreKeyDeletionTests.m; sourceTree = "<group>"; }; 45458B6A1CC342B600A02153 /* SignedPreKeyDeletionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SignedPreKeyDeletionTests.m; sourceTree = "<group>"; };
45458B6C1CC342B600A02153 /* TSAttachmentsTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSAttachmentsTest.m; sourceTree = "<group>"; };
45458B6E1CC342B600A02153 /* TSMessageStorageTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSMessageStorageTests.m; sourceTree = "<group>"; }; 45458B6E1CC342B600A02153 /* TSMessageStorageTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSMessageStorageTests.m; sourceTree = "<group>"; };
45458B6F1CC342B600A02153 /* TSStorageIdentityKeyStoreTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSStorageIdentityKeyStoreTests.m; sourceTree = "<group>"; }; 45458B6F1CC342B600A02153 /* TSStorageIdentityKeyStoreTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSStorageIdentityKeyStoreTests.m; sourceTree = "<group>"; };
45458B701CC342B600A02153 /* TSStoragePreKeyStoreTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSStoragePreKeyStoreTests.m; sourceTree = "<group>"; }; 45458B701CC342B600A02153 /* TSStoragePreKeyStoreTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSStoragePreKeyStoreTests.m; sourceTree = "<group>"; };
@ -178,15 +176,6 @@
path = ../../../tests/Account; path = ../../../tests/Account;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
45458B6B1CC342B600A02153 /* Attachments */ = {
isa = PBXGroup;
children = (
45458B6C1CC342B600A02153 /* TSAttachmentsTest.m */,
);
name = Attachments;
path = ../../../tests/Attachments;
sourceTree = "<group>";
};
45458B6D1CC342B600A02153 /* Storage */ = { 45458B6D1CC342B600A02153 /* Storage */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -333,7 +322,6 @@
children = ( children = (
453E1FD41DA83DD500DDD7B7 /* TestSupport */, 453E1FD41DA83DD500DDD7B7 /* TestSupport */,
45458B691CC342B600A02153 /* Account */, 45458B691CC342B600A02153 /* Account */,
45458B6B1CC342B600A02153 /* Attachments */,
459850BF1D22C6C4006FFEDB /* Contacts */, 459850BF1D22C6C4006FFEDB /* Contacts */,
45D7243D1D67894100E0CA54 /* Devices */, 45D7243D1D67894100E0CA54 /* Devices */,
45C6A0971D2F0254007D8AC0 /* Messages */, 45C6A0971D2F0254007D8AC0 /* Messages */,
@ -568,7 +556,6 @@
452EE6D51D4AC43300E934BA /* OWSOrphanedDataCleanerTest.m in Sources */, 452EE6D51D4AC43300E934BA /* OWSOrphanedDataCleanerTest.m in Sources */,
450E3C9A1D96DD2600BF4EB6 /* OWSDisappearingMessagesJobTest.m in Sources */, 450E3C9A1D96DD2600BF4EB6 /* OWSDisappearingMessagesJobTest.m in Sources */,
452EE6CF1D4A754C00E934BA /* TSThreadTest.m in Sources */, 452EE6CF1D4A754C00E934BA /* TSThreadTest.m in Sources */,
45458B761CC342B600A02153 /* TSAttachmentsTest.m in Sources */,
45C6A09A1D2F029B007D8AC0 /* TSMessageTest.m in Sources */, 45C6A09A1D2F029B007D8AC0 /* TSMessageTest.m in Sources */,
453E1FCF1DA8313100DDD7B7 /* OWSMessageSenderTest.m in Sources */, 453E1FCF1DA8313100DDD7B7 /* OWSMessageSenderTest.m in Sources */,
45AE484C1E072871004D96C2 /* OWSFakeCallMessageHandler.m in Sources */, 45AE484C1E072871004D96C2 /* OWSFakeCallMessageHandler.m in Sources */,

@ -133,6 +133,7 @@ message AttachmentPointer {
optional bytes key = 3; optional bytes key = 3;
optional uint32 size = 4; optional uint32 size = 4;
optional bytes thumbnail = 5; optional bytes thumbnail = 5;
optional bytes digest = 6;
} }
message GroupContext { message GroupContext {

@ -65,6 +65,7 @@ NS_ASSUME_NONNULL_BEGIN
for (OWSSignalServiceProtosAttachmentPointer *attachmentProto in attachmentProtos) { for (OWSSignalServiceProtosAttachmentPointer *attachmentProto in attachmentProtos) {
TSAttachmentPointer *pointer = [[TSAttachmentPointer alloc] initWithServerId:attachmentProto.id TSAttachmentPointer *pointer = [[TSAttachmentPointer alloc] initWithServerId:attachmentProto.id
key:attachmentProto.key key:attachmentProto.key
digest:attachmentProto.digest
contentType:attachmentProto.contentType contentType:attachmentProto.contentType
relay:relay]; relay:relay];
@ -159,7 +160,8 @@ NS_ASSUME_NONNULL_BEGIN
success:(void (^)(TSAttachmentStream *attachmentStream))successHandler success:(void (^)(TSAttachmentStream *attachmentStream))successHandler
failure:(void (^)(NSError *error))failureHandler failure:(void (^)(NSError *error))failureHandler
{ {
NSData *plaintext = [Cryptography decryptAttachment:cipherText withKey:attachment.encryptionKey]; NSData *plaintext =
[Cryptography decryptAttachment:cipherText withKey:attachment.encryptionKey digest:attachment.digest];
if (!plaintext) { if (!plaintext) {
NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeFailedToDecryptMessage, NSLocalizedString(@"ERROR_MESSAGE_INVALID_MESSAGE", @"")); NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeFailedToDecryptMessage, NSLocalizedString(@"ERROR_MESSAGE_INVALID_MESSAGE", @""));

@ -1,5 +1,6 @@
// Created by Frederic Jacobs on 17/12/14. //
// Copyright (c) 2014 Open Whisper Systems. All rights reserved. // Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import "TSAttachment.h" #import "TSAttachment.h"
@ -12,6 +13,7 @@ NS_ASSUME_NONNULL_BEGIN
- (instancetype)initWithServerId:(UInt64)serverId - (instancetype)initWithServerId:(UInt64)serverId
key:(NSData *)key key:(NSData *)key
digest:(NSData *)digest
contentType:(NSString *)contentType contentType:(NSString *)contentType
relay:(NSString *)relay NS_DESIGNATED_INITIALIZER; relay:(NSString *)relay NS_DESIGNATED_INITIALIZER;
@ -19,6 +21,10 @@ NS_ASSUME_NONNULL_BEGIN
@property (atomic, readwrite, getter=isDownloading) BOOL downloading; @property (atomic, readwrite, getter=isDownloading) BOOL downloading;
@property (atomic, readwrite, getter=hasFailed) BOOL failed; @property (atomic, readwrite, getter=hasFailed) BOOL failed;
// Though now required, `digest` may be null for pre-existing records or from
// messages received from other clients
@property (nullable, nonatomic, readonly) NSData *digest;
@end @end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END

@ -1,5 +1,6 @@
// Created by Frederic Jacobs on 17/12/14. //
// Copyright (c) 2014 Open Whisper Systems. All rights reserved. // Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import "TSAttachmentPointer.h" #import "TSAttachmentPointer.h"
@ -9,6 +10,7 @@ NS_ASSUME_NONNULL_BEGIN
- (instancetype)initWithServerId:(UInt64)serverId - (instancetype)initWithServerId:(UInt64)serverId
key:(NSData *)key key:(NSData *)key
digest:(NSData *)digest
contentType:(NSString *)contentType contentType:(NSString *)contentType
relay:(NSString *)relay relay:(NSString *)relay
{ {
@ -17,6 +19,8 @@ NS_ASSUME_NONNULL_BEGIN
return self; return self;
} }
OWSAssert(digest != nil);
_digest = digest;
_failed = NO; _failed = NO;
_downloading = NO; _downloading = NO;
_relay = relay; _relay = relay;

@ -1,5 +1,6 @@
// Created by Frederic Jacobs on 17/12/14. //
// Copyright (c) 2014 Open Whisper Systems. All rights reserved. // Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import "TSAttachment.h" #import "TSAttachment.h"
#if TARGET_OS_IPHONE #if TARGET_OS_IPHONE
@ -18,6 +19,10 @@ NS_ASSUME_NONNULL_BEGIN
@property (atomic, readwrite) BOOL isDownloaded; @property (atomic, readwrite) BOOL isDownloaded;
// Though now required, `digest` may be null for pre-existing records or from
// messages received from other clients
@property (nullable, nonatomic) NSData *digest;
#if TARGET_OS_IPHONE #if TARGET_OS_IPHONE
- (nullable UIImage *)image; - (nullable UIImage *)image;
#endif #endif

@ -203,6 +203,7 @@ NS_ASSUME_NONNULL_BEGIN
[builder setId:attachmentStream.serverId]; [builder setId:attachmentStream.serverId];
[builder setContentType:attachmentStream.contentType]; [builder setContentType:attachmentStream.contentType];
[builder setKey:attachmentStream.encryptionKey]; [builder setKey:attachmentStream.encryptionKey];
[builder setDigest:attachmentStream.digest];
return [builder build]; return [builder build];
} }

@ -1277,17 +1277,20 @@ NSString *NSStringFromOWSSignalServiceProtosGroupContextType(OWSSignalServicePro
#define AttachmentPointer_key @"key" #define AttachmentPointer_key @"key"
#define AttachmentPointer_size @"size" #define AttachmentPointer_size @"size"
#define AttachmentPointer_thumbnail @"thumbnail" #define AttachmentPointer_thumbnail @"thumbnail"
#define AttachmentPointer_digest @"digest"
@interface OWSSignalServiceProtosAttachmentPointer : PBGeneratedMessage<GeneratedMessageProtocol> { @interface OWSSignalServiceProtosAttachmentPointer : PBGeneratedMessage<GeneratedMessageProtocol> {
@private @private
BOOL hasId_:1; BOOL hasId_:1;
BOOL hasContentType_:1; BOOL hasContentType_:1;
BOOL hasKey_:1; BOOL hasKey_:1;
BOOL hasThumbnail_:1; BOOL hasThumbnail_:1;
BOOL hasDigest_:1;
BOOL hasSize_:1; BOOL hasSize_:1;
UInt64 id; UInt64 id;
NSString* contentType; NSString* contentType;
NSData* key; NSData* key;
NSData* thumbnail; NSData* thumbnail;
NSData* digest;
UInt32 size; UInt32 size;
} }
- (BOOL) hasId; - (BOOL) hasId;
@ -1295,11 +1298,13 @@ NSString *NSStringFromOWSSignalServiceProtosGroupContextType(OWSSignalServicePro
- (BOOL) hasKey; - (BOOL) hasKey;
- (BOOL) hasSize; - (BOOL) hasSize;
- (BOOL) hasThumbnail; - (BOOL) hasThumbnail;
- (BOOL) hasDigest;
@property (readonly) UInt64 id; @property (readonly) UInt64 id;
@property (readonly, strong) NSString* contentType; @property (readonly, strong) NSString* contentType;
@property (readonly, strong) NSData* key; @property (readonly, strong) NSData* key;
@property (readonly) UInt32 size; @property (readonly) UInt32 size;
@property (readonly, strong) NSData* thumbnail; @property (readonly, strong) NSData* thumbnail;
@property (readonly, strong) NSData* digest;
+ (instancetype) defaultInstance; + (instancetype) defaultInstance;
- (instancetype) defaultInstance; - (instancetype) defaultInstance;
@ -1360,6 +1365,11 @@ NSString *NSStringFromOWSSignalServiceProtosGroupContextType(OWSSignalServicePro
- (NSData*) thumbnail; - (NSData*) thumbnail;
- (OWSSignalServiceProtosAttachmentPointerBuilder*) setThumbnail:(NSData*) value; - (OWSSignalServiceProtosAttachmentPointerBuilder*) setThumbnail:(NSData*) value;
- (OWSSignalServiceProtosAttachmentPointerBuilder*) clearThumbnail; - (OWSSignalServiceProtosAttachmentPointerBuilder*) clearThumbnail;
- (BOOL) hasDigest;
- (NSData*) digest;
- (OWSSignalServiceProtosAttachmentPointerBuilder*) setDigest:(NSData*) value;
- (OWSSignalServiceProtosAttachmentPointerBuilder*) clearDigest;
@end @end
#define GroupContext_id @"id" #define GroupContext_id @"id"

@ -5319,6 +5319,7 @@ static OWSSignalServiceProtosSyncMessageRead* defaultOWSSignalServiceProtosSyncM
@property (strong) NSData* key; @property (strong) NSData* key;
@property UInt32 size; @property UInt32 size;
@property (strong) NSData* thumbnail; @property (strong) NSData* thumbnail;
@property (strong) NSData* digest;
@end @end
@implementation OWSSignalServiceProtosAttachmentPointer @implementation OWSSignalServiceProtosAttachmentPointer
@ -5358,6 +5359,13 @@ static OWSSignalServiceProtosSyncMessageRead* defaultOWSSignalServiceProtosSyncM
hasThumbnail_ = !!_value_; hasThumbnail_ = !!_value_;
} }
@synthesize thumbnail; @synthesize thumbnail;
- (BOOL) hasDigest {
return !!hasDigest_;
}
- (void) setHasDigest:(BOOL) _value_ {
hasDigest_ = !!_value_;
}
@synthesize digest;
- (instancetype) init { - (instancetype) init {
if ((self = [super init])) { if ((self = [super init])) {
self.id = 0L; self.id = 0L;
@ -5365,6 +5373,7 @@ static OWSSignalServiceProtosSyncMessageRead* defaultOWSSignalServiceProtosSyncM
self.key = [NSData data]; self.key = [NSData data];
self.size = 0; self.size = 0;
self.thumbnail = [NSData data]; self.thumbnail = [NSData data];
self.digest = [NSData data];
} }
return self; return self;
} }
@ -5399,6 +5408,9 @@ static OWSSignalServiceProtosAttachmentPointer* defaultOWSSignalServiceProtosAtt
if (self.hasThumbnail) { if (self.hasThumbnail) {
[output writeData:5 value:self.thumbnail]; [output writeData:5 value:self.thumbnail];
} }
if (self.hasDigest) {
[output writeData:6 value:self.digest];
}
[self.unknownFields writeToCodedOutputStream:output]; [self.unknownFields writeToCodedOutputStream:output];
} }
- (SInt32) serializedSize { - (SInt32) serializedSize {
@ -5423,6 +5435,9 @@ static OWSSignalServiceProtosAttachmentPointer* defaultOWSSignalServiceProtosAtt
if (self.hasThumbnail) { if (self.hasThumbnail) {
size_ += computeDataSize(5, self.thumbnail); size_ += computeDataSize(5, self.thumbnail);
} }
if (self.hasDigest) {
size_ += computeDataSize(6, self.digest);
}
size_ += self.unknownFields.serializedSize; size_ += self.unknownFields.serializedSize;
memoizedSerializedSize = size_; memoizedSerializedSize = size_;
return size_; return size_;
@ -5473,6 +5488,9 @@ static OWSSignalServiceProtosAttachmentPointer* defaultOWSSignalServiceProtosAtt
if (self.hasThumbnail) { if (self.hasThumbnail) {
[output appendFormat:@"%@%@: %@\n", indent, @"thumbnail", self.thumbnail]; [output appendFormat:@"%@%@: %@\n", indent, @"thumbnail", self.thumbnail];
} }
if (self.hasDigest) {
[output appendFormat:@"%@%@: %@\n", indent, @"digest", self.digest];
}
[self.unknownFields writeDescriptionTo:output withIndent:indent]; [self.unknownFields writeDescriptionTo:output withIndent:indent];
} }
- (void) storeInDictionary:(NSMutableDictionary *)dictionary { - (void) storeInDictionary:(NSMutableDictionary *)dictionary {
@ -5491,6 +5509,9 @@ static OWSSignalServiceProtosAttachmentPointer* defaultOWSSignalServiceProtosAtt
if (self.hasThumbnail) { if (self.hasThumbnail) {
[dictionary setObject: self.thumbnail forKey: @"thumbnail"]; [dictionary setObject: self.thumbnail forKey: @"thumbnail"];
} }
if (self.hasDigest) {
[dictionary setObject: self.digest forKey: @"digest"];
}
[self.unknownFields storeInDictionary:dictionary]; [self.unknownFields storeInDictionary:dictionary];
} }
- (BOOL) isEqual:(id)other { - (BOOL) isEqual:(id)other {
@ -5512,6 +5533,8 @@ static OWSSignalServiceProtosAttachmentPointer* defaultOWSSignalServiceProtosAtt
(!self.hasSize || self.size == otherMessage.size) && (!self.hasSize || self.size == otherMessage.size) &&
self.hasThumbnail == otherMessage.hasThumbnail && self.hasThumbnail == otherMessage.hasThumbnail &&
(!self.hasThumbnail || [self.thumbnail isEqual:otherMessage.thumbnail]) && (!self.hasThumbnail || [self.thumbnail isEqual:otherMessage.thumbnail]) &&
self.hasDigest == otherMessage.hasDigest &&
(!self.hasDigest || [self.digest isEqual:otherMessage.digest]) &&
(self.unknownFields == otherMessage.unknownFields || (self.unknownFields != nil && [self.unknownFields isEqual:otherMessage.unknownFields])); (self.unknownFields == otherMessage.unknownFields || (self.unknownFields != nil && [self.unknownFields isEqual:otherMessage.unknownFields]));
} }
- (NSUInteger) hash { - (NSUInteger) hash {
@ -5531,6 +5554,9 @@ static OWSSignalServiceProtosAttachmentPointer* defaultOWSSignalServiceProtosAtt
if (self.hasThumbnail) { if (self.hasThumbnail) {
hashCode = hashCode * 31 + [self.thumbnail hash]; hashCode = hashCode * 31 + [self.thumbnail hash];
} }
if (self.hasDigest) {
hashCode = hashCode * 31 + [self.digest hash];
}
hashCode = hashCode * 31 + [self.unknownFields hash]; hashCode = hashCode * 31 + [self.unknownFields hash];
return hashCode; return hashCode;
} }
@ -5589,6 +5615,9 @@ static OWSSignalServiceProtosAttachmentPointer* defaultOWSSignalServiceProtosAtt
if (other.hasThumbnail) { if (other.hasThumbnail) {
[self setThumbnail:other.thumbnail]; [self setThumbnail:other.thumbnail];
} }
if (other.hasDigest) {
[self setDigest:other.digest];
}
[self mergeUnknownFields:other.unknownFields]; [self mergeUnknownFields:other.unknownFields];
return self; return self;
} }
@ -5630,6 +5659,10 @@ static OWSSignalServiceProtosAttachmentPointer* defaultOWSSignalServiceProtosAtt
[self setThumbnail:[input readData]]; [self setThumbnail:[input readData]];
break; break;
} }
case 50: {
[self setDigest:[input readData]];
break;
}
} }
} }
} }
@ -5713,6 +5746,22 @@ static OWSSignalServiceProtosAttachmentPointer* defaultOWSSignalServiceProtosAtt
resultAttachmentPointer.thumbnail = [NSData data]; resultAttachmentPointer.thumbnail = [NSData data];
return self; return self;
} }
- (BOOL) hasDigest {
return resultAttachmentPointer.hasDigest;
}
- (NSData*) digest {
return resultAttachmentPointer.digest;
}
- (OWSSignalServiceProtosAttachmentPointerBuilder*) setDigest:(NSData*) value {
resultAttachmentPointer.hasDigest = YES;
resultAttachmentPointer.digest = value;
return self;
}
- (OWSSignalServiceProtosAttachmentPointerBuilder*) clearDigest {
resultAttachmentPointer.hasDigest = NO;
resultAttachmentPointer.digest = [NSData data];
return self;
}
@end @end
@interface OWSSignalServiceProtosGroupContext () @interface OWSSignalServiceProtosGroupContext ()

@ -68,10 +68,12 @@ NS_ASSUME_NONNULL_BEGIN
} }
NSData *encryptionKey; NSData *encryptionKey;
NSData *digest;
NSData *encryptedAttachmentData = NSData *encryptedAttachmentData =
[Cryptography encryptAttachmentData:attachmentData outKey:&encryptionKey]; [Cryptography encryptAttachmentData:attachmentData outKey:&encryptionKey outDigest:&digest];
attachmentStream.encryptionKey = encryptionKey; attachmentStream.encryptionKey = encryptionKey;
attachmentStream.digest = digest;
[self uploadDataWithProgress:encryptedAttachmentData [self uploadDataWithProgress:encryptedAttachmentData
location:location location:location

@ -1,5 +1,8 @@
// Created by Christine Corbett Moran on 3/26/13. //
// Copyright (c) 2013 Open Whisper Systems. All rights reserved. // Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
NS_ASSUME_NONNULL_BEGIN
@interface Cryptography : NSObject @interface Cryptography : NSObject
@ -13,7 +16,12 @@ typedef NS_ENUM(NSInteger, TSMACType) {
#pragma mark SHA and HMAC methods #pragma mark SHA and HMAC methods
+ (NSData *)computeSHA256:(NSData *)data truncatedToBytes:(NSUInteger)truncatedBytes; // Full length SHA256 digest for `data`
+ (NSData *)computeSHA256Digest:(NSData *)data;
// Truncated SHA256 digest for `data`
+ (NSData *)computeSHA256Digest:(NSData *)data truncatedToBytes:(NSUInteger)truncatedBytes;
+ (NSString *)truncatedSHA1Base64EncodedWithoutPadding:(NSString *)string; + (NSString *)truncatedSHA1Base64EncodedWithoutPadding:(NSString *)string;
+ (NSString *)computeSHA1DigestForString:(NSString *)input; + (NSString *)computeSHA1DigestForString:(NSString *)input;
@ -24,8 +32,12 @@ typedef NS_ENUM(NSInteger, TSMACType) {
+ (NSData *)decryptAppleMessagePayload:(NSData *)payload withSignalingKey:(NSString *)signalingKeyString; + (NSData *)decryptAppleMessagePayload:(NSData *)payload withSignalingKey:(NSString *)signalingKeyString;
#pragma mark encrypt and decrypt attachment data #pragma mark encrypt and decrypt attachment data
+ (NSData *)decryptAttachment:(NSData *)dataToDecrypt withKey:(NSData *)key; + (NSData *)decryptAttachment:(NSData *)dataToDecrypt withKey:(NSData *)key digest:(nullable NSData *)digest;
+ (NSData *)encryptAttachmentData:(NSData *)attachmentData outKey:(NSData **)outKey; + (NSData *)encryptAttachmentData:(NSData *)attachmentData
outKey:(NSData *_Nonnull *_Nullable)outKey
outDigest:(NSData *_Nonnull *_Nullable)outDigest;
@end @end
NS_ASSUME_NONNULL_END

@ -1,9 +1,5 @@
// //
// Cryptography.m // Copyright (c) 2017 Open Whisper Systems. All rights reserved.
// TextSecureiOS
//
// Created by Christine Corbett Moran on 3/26/13.
// Copyright (c) 2013 Open Whisper Systems. All rights reserved.
// //
#import <CommonCrypto/CommonCryptor.h> #import <CommonCrypto/CommonCryptor.h>
@ -11,12 +7,15 @@
#import "Cryptography.h" #import "Cryptography.h"
#import "NSData+Base64.h" #import "NSData+Base64.h"
#import "NSData+OWSConstantTimeCompare.h"
#define HMAC256_KEY_LENGTH 32 #define HMAC256_KEY_LENGTH 32
#define HMAC256_OUTPUT_LENGTH 32 #define HMAC256_OUTPUT_LENGTH 32
#define AES_CBC_IV_LENGTH 16 #define AES_CBC_IV_LENGTH 16
#define AES_KEY_SIZE 32 #define AES_KEY_SIZE 32
NS_ASSUME_NONNULL_BEGIN
@implementation Cryptography @implementation Cryptography
@ -65,8 +64,14 @@
return output; return output;
} }
#pragma mark SHA256 #pragma mark SHA256 Digest
+ (NSData *)computeSHA256:(NSData *)data truncatedToBytes:(NSUInteger)truncatedBytes { + (NSData *)computeSHA256Digest:(NSData *)data
{
return [self computeSHA256Digest:(NSData *)data truncatedToBytes:CC_SHA256_DIGEST_LENGTH];
}
+ (NSData *)computeSHA256Digest:(NSData *)data truncatedToBytes:(NSUInteger)truncatedBytes
{
uint8_t digest[CC_SHA256_DIGEST_LENGTH]; uint8_t digest[CC_SHA256_DIGEST_LENGTH];
CC_SHA256(data.bytes, (unsigned int)data.length, digest); CC_SHA256(data.bytes, (unsigned int)data.length, digest);
return return
@ -98,104 +103,65 @@
#pragma mark AES CBC Mode #pragma mark AES CBC Mode
+ (NSData *)encryptCBCMode:(NSData *)dataToEncrypt
withKey:(NSData *)key
withIV:(NSData *)iv
withVersion:(NSData *)version
withHMACKey:(NSData *)hmacKey
withHMACType:(TSMACType)hmacType
computedHMAC:(NSData **)hmac {
/* AES256 CBC encrypt then mac
Returns nil if encryption fails
*/
size_t bufferSize = [dataToEncrypt length] + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
if (buffer == NULL) {
DDLogError(@"Failed to allocate memory.");
return nil;
}
size_t bytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
kCCAlgorithmAES128,
kCCOptionPKCS7Padding,
[key bytes],
[key length],
[iv bytes],
[dataToEncrypt bytes],
[dataToEncrypt length],
buffer,
bufferSize,
&bytesEncrypted);
if (cryptStatus == kCCSuccess) {
NSData *encryptedData = [NSData dataWithBytesNoCopy:buffer length:bytesEncrypted];
// compute hmac of version||encrypted data||iv
NSMutableData *dataToHmac = [NSMutableData data];
if (version != nil) {
[dataToHmac appendData:version];
}
[dataToHmac appendData:iv];
[dataToHmac appendData:encryptedData];
if (hmacType == TSHMACSHA1Truncated10Bytes) {
*hmac = [Cryptography truncatedSHA1HMAC:dataToHmac withHMACKey:hmacKey truncation:10];
} else if (hmacType == TSHMACSHA256Truncated10Bytes) {
*hmac = [Cryptography truncatedSHA256HMAC:dataToHmac withHMACKey:hmacKey truncation:10];
} else if (hmacType == TSHMACSHA256AttachementType) {
*hmac = [Cryptography truncatedSHA256HMAC:dataToHmac withHMACKey:hmacKey truncation:HMAC256_OUTPUT_LENGTH];
}
return encryptedData;
}
free(buffer);
return nil;
}
/**
* AES256 CBC encrypt then mac. Used to decrypt both signal messages and attachment blobs
*
* @return decrypted data or nil if hmac invalid/decryption fails
*/
+ (NSData *)decryptCBCMode:(NSData *)dataToDecrypt + (NSData *)decryptCBCMode:(NSData *)dataToDecrypt
key:(NSData *)key key:(NSData *)key
IV:(NSData *)iv IV:(NSData *)iv
version:(NSData *)version version:(nullable NSData *)version
HMACKey:(NSData *)hmacKey HMACKey:(NSData *)hmacKey
HMACType:(TSMACType)hmacType HMACType:(TSMACType)hmacType
matchingHMAC:(NSData *)hmac { matchingHMAC:(NSData *)hmac
/* AES256 CBC encrypt then mac digest:(nullable NSData *)digest
{
Returns nil if hmac invalid or decryption fails // Verify hmac of: version? || iv || encrypted data
*/ NSMutableData *dataToAuth = [NSMutableData data];
// verify hmac of version||encrypted data||iv
NSMutableData *dataToHmac = [NSMutableData data];
if (version != nil) { if (version != nil) {
[dataToHmac appendData:version]; [dataToAuth appendData:version];
} }
[dataToHmac appendData:iv]; [dataToAuth appendData:iv];
[dataToHmac appendData:dataToDecrypt]; [dataToAuth appendData:dataToDecrypt];
NSData *ourHmacData; NSData *ourHmacData;
if (hmacType == TSHMACSHA1Truncated10Bytes) { if (hmacType == TSHMACSHA1Truncated10Bytes) {
ourHmacData = [Cryptography truncatedSHA1HMAC:dataToHmac withHMACKey:hmacKey truncation:10]; ourHmacData = [Cryptography truncatedSHA1HMAC:dataToAuth withHMACKey:hmacKey truncation:10];
} else if (hmacType == TSHMACSHA256Truncated10Bytes) { } else if (hmacType == TSHMACSHA256Truncated10Bytes) {
ourHmacData = [Cryptography truncatedSHA256HMAC:dataToHmac withHMACKey:hmacKey truncation:10]; ourHmacData = [Cryptography truncatedSHA256HMAC:dataToAuth withHMACKey:hmacKey truncation:10];
} else if (hmacType == TSHMACSHA256AttachementType) { } else if (hmacType == TSHMACSHA256AttachementType) {
ourHmacData = ourHmacData =
[Cryptography truncatedSHA256HMAC:dataToHmac withHMACKey:hmacKey truncation:HMAC256_OUTPUT_LENGTH]; [Cryptography truncatedSHA256HMAC:dataToAuth withHMACKey:hmacKey truncation:HMAC256_OUTPUT_LENGTH];
}
if (hmac == nil || ![ourHmacData ows_constantTimeIsEqualToData:hmac]) {
DDLogError(@"%@ %s Bad HMAC on decrypting payload. Their MAC: %@, our MAC: %@", self.tag, __PRETTY_FUNCTION__, hmac, ourHmacData);
return nil;
} }
if (hmac == nil || ![ourHmacData isEqualToData:hmac]) { // Optionally verify digest of: version? || iv || encrypted data || hmac
DDLogError(@"Bad HMAC on decrypting payload"); if (digest) {
DDLogDebug(@"%@ %s verifying their digest: %@", self.tag, __PRETTY_FUNCTION__, digest);
[dataToAuth appendData:ourHmacData];
NSData *ourDigest = [Cryptography computeSHA256Digest:dataToAuth];
if (!ourDigest || ![ourDigest ows_constantTimeIsEqualToData:digest]) {
DDLogWarn(@"%@ Bad digest on decrypting payload. Their digest: %@, our digest: %@", self.tag, digest, ourDigest);
return nil; return nil;
} }
} else {
DDLogVerbose(@"%@ %s no digest to verify", self.tag, __PRETTY_FUNCTION__);
}
// decrypt // decrypt
size_t bufferSize = [dataToDecrypt length] + kCCBlockSizeAES128; size_t bufferSize = [dataToDecrypt length] + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize); void *buffer = malloc(bufferSize);
if (buffer == NULL) { if (buffer == NULL) {
DDLogError(@"Failed to allocate memory."); DDLogError(@"%@ Failed to allocate memory.", self.tag);
return nil; return nil;
} }
@ -212,9 +178,9 @@
bufferSize, bufferSize,
&bytesDecrypted); &bytesDecrypted);
if (cryptStatus == kCCSuccess) { if (cryptStatus == kCCSuccess) {
return [NSData dataWithBytesNoCopy:buffer length:bytesDecrypted]; return [NSData dataWithBytesNoCopy:buffer length:bytesDecrypted freeWhenDone:YES];
} else { } else {
DDLogError(@"Failed CBC decryption"); DDLogError(@"%@ Failed CBC decryption", self.tag);
free(buffer); free(buffer);
} }
@ -246,13 +212,15 @@
version:[NSData dataWithBytes:version length:1] version:[NSData dataWithBytes:version length:1]
HMACKey:signalingKeyHMACKeyMaterial HMACKey:signalingKeyHMACKeyMaterial
HMACType:TSHMACSHA256Truncated10Bytes HMACType:TSHMACSHA256Truncated10Bytes
matchingHMAC:[NSData dataWithBytes:mac length:10]]; matchingHMAC:[NSData dataWithBytes:mac length:10]
digest:nil];
} }
+ (NSData *)decryptAttachment:(NSData *)dataToDecrypt withKey:(NSData *)key { + (NSData *)decryptAttachment:(NSData *)dataToDecrypt withKey:(NSData *)key digest:(nullable NSData *)digest
{
if (([dataToDecrypt length] < AES_CBC_IV_LENGTH + HMAC256_OUTPUT_LENGTH) || if (([dataToDecrypt length] < AES_CBC_IV_LENGTH + HMAC256_OUTPUT_LENGTH) ||
([key length] < AES_KEY_SIZE + HMAC256_KEY_LENGTH)) { ([key length] < AES_KEY_SIZE + HMAC256_KEY_LENGTH)) {
DDLogError(@"Message shorter than crypto overhead!"); DDLogError(@"%@ Message shorter than crypto overhead!", self.tag);
return nil; return nil;
} }
@ -274,36 +242,84 @@
version:nil version:nil
HMACKey:hmacKey HMACKey:hmacKey
HMACType:TSHMACSHA256AttachementType HMACType:TSHMACSHA256AttachementType
matchingHMAC:hmac]; matchingHMAC:hmac
digest:digest];
} }
+ (NSData *)encryptAttachmentData:(NSData *)attachmentData outKey:(NSData **)outKey + (NSData *)encryptAttachmentData:(NSData *)attachmentData
outKey:(NSData *_Nonnull *_Nullable)outKey
outDigest:(NSData *_Nonnull *_Nullable)outDigest
{ {
NSData *iv = [Cryptography generateRandomBytes:AES_CBC_IV_LENGTH]; NSData *iv = [Cryptography generateRandomBytes:AES_CBC_IV_LENGTH];
NSData *encryptionKey = [Cryptography generateRandomBytes:AES_KEY_SIZE]; NSData *encryptionKey = [Cryptography generateRandomBytes:AES_KEY_SIZE];
NSData *hmacKey = [Cryptography generateRandomBytes:HMAC256_KEY_LENGTH]; NSData *hmacKey = [Cryptography generateRandomBytes:HMAC256_KEY_LENGTH];
// The concatenated key for storage // The concatenated key for storage
NSMutableData *key = [NSMutableData data]; NSMutableData *attachmentKey = [NSMutableData data];
[key appendData:encryptionKey]; [attachmentKey appendData:encryptionKey];
[key appendData:hmacKey]; [attachmentKey appendData:hmacKey];
*outKey = [key copy]; *outKey = [attachmentKey copy];
NSData *computedHMAC; // Encrypt
NSData *ciphertext = [Cryptography encryptCBCMode:attachmentData size_t bufferSize = [attachmentData length] + kCCBlockSizeAES128;
withKey:encryptionKey void *buffer = malloc(bufferSize);
withIV:iv
withVersion:nil if (buffer == NULL) {
withHMACKey:hmacKey DDLogError(@"%@ Failed to allocate memory.", self.tag);
withHMACType:TSHMACSHA256AttachementType return nil;
computedHMAC:&computedHMAC]; }
size_t bytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
kCCAlgorithmAES128,
kCCOptionPKCS7Padding,
[encryptionKey bytes],
[encryptionKey length],
[iv bytes],
[attachmentData bytes],
[attachmentData length],
buffer,
bufferSize,
&bytesEncrypted);
if (cryptStatus != kCCSuccess) {
DDLogError(@"%@ %s CCCrypt failed with status: %d", self.tag, __PRETTY_FUNCTION__, (int32_t)cryptStatus);
free(buffer);
return nil;
}
NSData *cipherText = [NSData dataWithBytesNoCopy:buffer length:bytesEncrypted freeWhenDone:YES];
NSMutableData *encryptedAttachmentData = [NSMutableData data]; NSMutableData *encryptedAttachmentData = [NSMutableData data];
[encryptedAttachmentData appendData:iv]; [encryptedAttachmentData appendData:iv];
[encryptedAttachmentData appendData:ciphertext]; [encryptedAttachmentData appendData:cipherText];
[encryptedAttachmentData appendData:computedHMAC];
// compute hmac of: iv || encrypted data
NSData *hmac =
[Cryptography truncatedSHA256HMAC:encryptedAttachmentData withHMACKey:hmacKey truncation:HMAC256_OUTPUT_LENGTH];
DDLogVerbose(@"%@ computed hmac: %@", self.tag, hmac);
[encryptedAttachmentData appendData:hmac];
return encryptedAttachmentData; // compute digest of: iv || encrypted data || hmac
*outDigest = [self computeSHA256Digest:encryptedAttachmentData];
DDLogVerbose(@"%@ computed digest: %@", self.tag, *outDigest);
return [encryptedAttachmentData copy];
}
#pragma mark - Logging
+ (NSString *)tag
{
return [NSString stringWithFormat:@"[%@]", self.class];
}
- (NSString *)tag
{
return self.class.tag;
} }
@end @end
NS_ASSUME_NONNULL_END

@ -0,0 +1,16 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
NS_ASSUME_NONNULL_BEGIN
@interface NSData (OWSConstantTimeCompare)
/**
* Compares data in constant time so as to help avoid potential timing attacks.
*/
- (BOOL)ows_constantTimeIsEqualToData:(NSData *)other;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,32 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import "NSData+OWSConstantTimeCompare.h"
NS_ASSUME_NONNULL_BEGIN
@implementation NSData (OWSConstantTimeCompare)
- (BOOL)ows_constantTimeIsEqualToData:(NSData *)other
{
BOOL isEqual = YES;
if (self.length != other.length) {
return NO;
}
UInt8 *leftBytes = (UInt8 *)self.bytes;
UInt8 *rightBytes = (UInt8 *)other.bytes;
for (int i = 0; i < self.length; i++) {
// rather than returning as soon as we find a discrepency, we compare the rest of
// the byte stream to maintain a constant time comparison
isEqual = isEqual && (leftBytes[i] == rightBytes[i]);
}
return isEqual;
}
@end
NS_ASSUME_NONNULL_END

@ -1,30 +0,0 @@
// Created by Frederic Jacobs on 21/12/14.
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
#import <XCTest/XCTest.h>
#import "TSAttachmentStream.h"
#import "Cryptography.h"
NS_ASSUME_NONNULL_BEGIN
@interface TSAttachmentsTest : XCTestCase
@end
@implementation TSAttachmentsTest
- (void)testAttachmentEncryptionDecryption
{
NSData *plaintext = [Cryptography generateRandomBytes:100];
NSData *encryptionKey;
NSData *encryptedData = [Cryptography encryptAttachmentData:plaintext outKey:&encryptionKey];
NSData *plaintextBis = [Cryptography decryptAttachment:encryptedData withKey:encryptionKey];
XCTAssert([plaintext isEqualToData:plaintextBis], @"Attachments encryption failed");
}
@end
NS_ASSUME_NONNULL_END

@ -1,20 +1,17 @@
// //
// CryptographyTests.m // Copyright (c) 2017 Open Whisper Systems. All rights reserved.
// TextSecureiOS
//
// Created by Christine Corbett Moran on 12/19/13.
// Copyright (c) 2013 Open Whisper Systems. All rights reserved.
// //
#import <XCTest/XCTest.h> #import <XCTest/XCTest.h>
#import "Cryptography.h" #import "Cryptography.h"
#import "NSData+Base64.h" #import "NSData+Base64.h"
NS_ASSUME_NONNULL_BEGIN
@interface CryptographyTests : XCTestCase @interface CryptographyTests : XCTestCase
@end @end
@interface Cryptography (Test) @interface Cryptography (Test)
+ (NSData *)truncatedSHA256HMAC:(NSData *)dataToHMAC withHMACKey:(NSData *)HMACKey truncation:(int)bytes; + (NSData *)truncatedSHA256HMAC:(NSData *)dataToHMAC withHMACKey:(NSData *)HMACKey truncation:(int)bytes;
+ (NSData *)encryptCBCMode:(NSData *)dataToEncrypt + (NSData *)encryptCBCMode:(NSData *)dataToEncrypt
@ -36,55 +33,94 @@
@implementation CryptographyTests @implementation CryptographyTests
- (void)testEncryptAttachmentData
{
NSString *plainText = @"SGF3YWlpIGlzIEF3ZXNvbWUh";
NSData *plainTextData = [NSData dataFromBase64String:plainText];
// Sanity
XCTAssertNotNil(plainTextData);
NSData *generatedKey;
NSData *generatedDigest;
NSData *cipherText =
[Cryptography encryptAttachmentData:plainTextData outKey:&generatedKey outDigest:&generatedDigest];
NSData *decryptedData = [Cryptography decryptAttachment:cipherText withKey:generatedKey digest:generatedDigest];
XCTAssertEqualObjects(plainTextData, decryptedData);
}
- (void)testDecryptAttachmentWithBadKey
{
NSString *plainText = @"SGF3YWlpIGlzIEF3ZXNvbWUh";
NSData *plainTextData = [NSData dataFromBase64String:plainText];
// Sanity
XCTAssertNotNil(plainTextData);
NSData *generatedKey;
NSData *generatedDigest;
NSData *cipherText =
[Cryptography encryptAttachmentData:plainTextData outKey:&generatedKey outDigest:&generatedDigest];
- (void)testLocalDecryption { NSData *badKey = [Cryptography generateRandomBytes:64];
NSString *originalMessage = @"Hawaii is awesome";
NSString *signalingKeyString = @"VJuRzZcwuY/6VjGw+QSPy5ROzHo8xE36mKwHNvkfyZ+mSPaDlSDcenUqavIX1Vwn\nRRIdrg=="; NSData *decryptedData = [Cryptography decryptAttachment:cipherText withKey:badKey digest:generatedDigest];
NSData *signalingKey = [NSData dataFromBase64String:signalingKeyString];
XCTAssertTrue([signalingKey length] == 52, XCTAssertNil(decryptedData);
@"signaling key is not 52 bytes but %llu", }
(unsigned long long)[signalingKey length]);
NSData *signalingKeyAESKeyMaterial = [signalingKey subdataWithRange:NSMakeRange(0, 32)]; - (void)testDecryptAttachmentWithBadDigest
NSData *signalingKeyHMACKeyMaterial = [signalingKey subdataWithRange:NSMakeRange(32, 20)]; {
NSData *iv = [Cryptography generateRandomBytes:16]; NSString *plainText = @"SGF3YWlpIGlzIEF3ZXNvbWUh";
NSData *version = [Cryptography generateRandomBytes:1]; NSData *plainTextData = [NSData dataFromBase64String:plainText];
NSData *mac;
// Sanity
NSData *encryption = [Cryptography encryptCBCMode:[originalMessage dataUsingEncoding:NSUTF8StringEncoding] XCTAssertNotNil(plainTextData);
withKey:signalingKeyAESKeyMaterial
withIV:iv NSData *generatedKey;
withVersion:version NSData *generatedDigest;
withHMACKey:signalingKeyHMACKeyMaterial
withHMACType:TSHMACSHA1Truncated10Bytes NSData *cipherText =
computedHMAC:&mac]; // Encrypt [Cryptography encryptAttachmentData:plainTextData outKey:&generatedKey outDigest:&generatedDigest];
NSMutableData *dataToHmac = [NSMutableData data]; NSData *badDigest = [Cryptography generateRandomBytes:32];
[dataToHmac appendData:version];
[dataToHmac appendData:iv]; NSData *decryptedData = [Cryptography decryptAttachment:cipherText withKey:generatedKey digest:badDigest];
[dataToHmac appendData:encryption];
XCTAssertNil(decryptedData);
NSData *expectedHmac =
[Cryptography truncatedSHA1HMAC:dataToHmac withHMACKey:signalingKeyHMACKeyMaterial truncation:10];
XCTAssertTrue([mac isEqualToData:expectedHmac],
@"Hmac of encrypted data %@, not equal to expected hmac %@",
[mac base64EncodedString],
[expectedHmac base64EncodedString]);
NSData *decryption = [Cryptography decryptCBCMode:encryption
key:signalingKeyAESKeyMaterial
IV:iv
version:version
HMACKey:signalingKeyHMACKeyMaterial
HMACType:TSHMACSHA1Truncated10Bytes
matchingHMAC:mac];
NSString *decryptedMessage = [[NSString alloc] initWithData:decryption encoding:NSUTF8StringEncoding];
XCTAssertTrue([decryptedMessage isEqualToString:originalMessage],
@"Decrypted message: %@ is not equal to original: %@",
decryptedMessage,
originalMessage);
} }
- (void)testComputeSHA256Digest
{
NSString *plainText = @"SGF3YWlpIGlzIEF3ZXNvbWUh";
NSData *plainTextData = [NSData dataFromBase64String:plainText];
NSData *digest = [Cryptography computeSHA256Digest:plainTextData];
const uint8_t expectedBytes[] = {
0xba, 0x5f, 0xf1, 0x26,
0x82, 0xbb, 0xb2, 0x51,
0x8b, 0xe6, 0x06, 0x48,
0xc5, 0x53, 0xd0, 0xa2,
0xbf, 0x71, 0xf1, 0xec,
0xb4, 0xdb, 0x02, 0x12,
0x5f, 0x80, 0xea, 0x34,
0xc9, 0x8d, 0xee, 0x1f
};
NSData *expectedDigest = [NSData dataWithBytes:expectedBytes length:32];
XCTAssertEqualObjects(expectedDigest, digest);
NSData *expectedTruncatedDigest = [NSData dataWithBytes:expectedBytes length:10];
NSData *truncatedDigest = [Cryptography computeSHA256Digest:plainTextData truncatedToBytes:10];
XCTAssertEqualObjects(expectedTruncatedDigest, truncatedDigest);
}
@end @end
NS_ASSUME_NONNULL_END

Loading…
Cancel
Save