session-ios/SignalServiceKit/tests/Util/CryptographyTests.m

207 lines
7.5 KiB
Objective-C

//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import <XCTest/XCTest.h>
#import "Cryptography.h"
#import "NSData+Base64.h"
NS_ASSUME_NONNULL_BEGIN
@interface Cryptography (TestingPrivateMethods)
+ (nullable NSData *)decryptAESGCMWithInitializationVector:(NSData *)initializationVector
ciphertext:(NSData *)ciphertext
authTag:(NSData *)authTagFromEncrypt
key:(OWSAES256Key *)key;
@end
@interface CryptographyTests : XCTestCase
@end
@interface Cryptography (Test)
+ (NSData *)truncatedSHA256HMAC:(NSData *)dataToHMAC withHMACKey:(NSData *)HMACKey truncation:(int)bytes;
+ (NSData *)encryptCBCMode:(NSData *)dataToEncrypt
withKey:(NSData *)key
withIV:(NSData *)iv
withVersion:(NSData *)version
withHMACKey:(NSData *)hmacKey
withHMACType:(TSMACType)hmacType
computedHMAC:(NSData **)hmac;
+ (NSData *)decryptCBCMode:(NSData *)dataToDecrypt
key:(NSData *)key
IV:(NSData *)iv
version:(NSData *)version
HMACKey:(NSData *)hmacKey
HMACType:(TSMACType)hmacType
matchingHMAC:(NSData *)hmac;
@end
@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];
NSData *badKey = [Cryptography generateRandomBytes:64];
NSData *decryptedData = [Cryptography decryptAttachment:cipherText withKey:badKey digest:generatedDigest];
XCTAssertNil(decryptedData);
}
- (void)testDecryptAttachmentWithBadDigest
{
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 *badDigest = [Cryptography generateRandomBytes:32];
NSData *decryptedData = [Cryptography decryptAttachment:cipherText withKey:generatedKey digest:badDigest];
XCTAssertNil(decryptedData);
}
- (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);
}
- (void)testGCMRoundTrip
{
NSData *plainTextData = [@"Super🔥secret🔥test🔥data🏁🏁" dataUsingEncoding:NSUTF8StringEncoding];
// Sanity Check
XCTAssertEqual(39, plainTextData.length);
OWSAES256Key *key = [OWSAES256Key new];
NSData *_Nullable encryptedData = [Cryptography encryptAESGCMWithData:plainTextData key:key];
const NSUInteger ivLength = 12;
const NSUInteger tagLength = 16;
XCTAssertEqual(ivLength + plainTextData.length + tagLength, encryptedData.length);
NSData *_Nullable decryptedData = [Cryptography decryptAESGCMWithData:encryptedData key:key];
XCTAssert(decryptedData != nil);
XCTAssertEqual(39, decryptedData.length);
XCTAssertEqualObjects(plainTextData, decryptedData);
XCTAssertEqualObjects(@"Super🔥secret🔥test🔥data🏁🏁", [[NSString alloc] initWithData:decryptedData encoding:NSUTF8StringEncoding]);
}
- (void)testGCMWithBadTag
{
NSData *plainTextData = [@"Super🔥secret🔥test🔥data🏁🏁" dataUsingEncoding:NSUTF8StringEncoding];
// Sanity Check
XCTAssertEqual(39, plainTextData.length);
OWSAES256Key *key = [OWSAES256Key new];
NSData *_Nullable encryptedData = [Cryptography encryptAESGCMWithData:plainTextData key:key];
const NSUInteger ivLength = 12;
const NSUInteger tagLength = 16;
XCTAssertEqual(ivLength + plainTextData.length + tagLength, encryptedData.length);
// Logic to slice up encryptedData copied from `[Cryptography decryptAESGCMWithData:key:]`
// encryptedData layout: initializationVector || cipherText || authTag
NSUInteger cipherTextLength = encryptedData.length - ivLength - tagLength;
NSData *initializationVector = [encryptedData subdataWithRange:NSMakeRange(0, ivLength)];
NSData *cipherText = [encryptedData subdataWithRange:NSMakeRange(ivLength, cipherTextLength)];
NSData *authTag = [encryptedData subdataWithRange:NSMakeRange(ivLength + cipherTextLength, tagLength)];
NSData *_Nullable decryptedData = [Cryptography decryptAESGCMWithInitializationVector:initializationVector
ciphertext:cipherText
authTag:authTag
key:key];
// Before we corrupt the tag, make sure we can decrypt the text as a sanity check to ensure we divided up the
// encryptedData correctly.
XCTAssert(decryptedData != nil);
XCTAssertEqualObjects(
@"Super🔥secret🔥test🔥data🏁🏁", [[NSString alloc] initWithData:decryptedData encoding:NSUTF8StringEncoding]);
// Now that we know it decrypts, try again with a bogus authTag
NSMutableData *bogusAuthTag = [authTag mutableCopy];
// Corrupt one byte in the bogusAuthTag
uint8_t flippedByte;
[bogusAuthTag getBytes:&flippedByte length:1];
flippedByte = flippedByte ^ 0xff;
[bogusAuthTag replaceBytesInRange:NSMakeRange(0, 1) withBytes:&flippedByte];
decryptedData = [Cryptography decryptAESGCMWithInitializationVector:initializationVector
ciphertext:cipherText
authTag:bogusAuthTag
key:key];
XCTAssertNil(decryptedData, @"Should have failed to decrypt");
}
@end
NS_ASSUME_NONNULL_END