mirror of https://github.com/oxen-io/session-ios
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
250 lines
9.2 KiB
Objective-C
250 lines
9.2 KiB
Objective-C
//
|
|
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
|
//
|
|
|
|
#import "Cryptography.h"
|
|
#import "NSData+OWS.h"
|
|
#import <XCTest/XCTest.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];
|
|
|
|
|
|
NSError *error;
|
|
NSData *decryptedData = [Cryptography decryptAttachment:cipherText
|
|
withKey:generatedKey
|
|
digest:generatedDigest
|
|
unpaddedSize:(UInt32)cipherText.length
|
|
error:&error];
|
|
XCTAssertNil(error);
|
|
|
|
XCTAssertEqualObjects(plainTextData, decryptedData);
|
|
}
|
|
|
|
- (void)testEncryptAttachmentDataWithBadUnpaddedSize
|
|
{
|
|
|
|
NSString *plainText = @"SGF3YWlpIGlzIEF3ZXNvbWUh";
|
|
NSData *plainTextData = [NSData dataFromBase64String:plainText];
|
|
|
|
// Sanity
|
|
XCTAssertNotNil(plainTextData);
|
|
|
|
NSData *generatedKey;
|
|
NSData *generatedDigest;
|
|
|
|
NSData *cipherText =
|
|
[Cryptography encryptAttachmentData:plainTextData outKey:&generatedKey outDigest:&generatedDigest];
|
|
|
|
|
|
NSError *error;
|
|
NSData *decryptedData = [Cryptography decryptAttachment:cipherText
|
|
withKey:generatedKey
|
|
digest:generatedDigest
|
|
unpaddedSize:(UInt32)cipherText.length + 1
|
|
error:&error];
|
|
XCTAssertNotNil(error);
|
|
XCTAssertNil(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];
|
|
|
|
NSError *error;
|
|
NSData *decryptedData = [Cryptography decryptAttachment:cipherText
|
|
withKey:badKey
|
|
digest:generatedDigest
|
|
unpaddedSize:(UInt32)cipherText.length + 1
|
|
error:&error];
|
|
|
|
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];
|
|
|
|
NSError *error;
|
|
NSData *decryptedData = [Cryptography decryptAttachment:cipherText
|
|
withKey:generatedKey
|
|
digest:badDigest
|
|
unpaddedSize:(UInt32)cipherText.length + 1
|
|
error:&error];
|
|
|
|
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
|