#import "CryptoUtilTest.h"
#import "Util.h"
#import "CryptoTools.h"
#import "TestUtil.h"

@implementation CryptoUtilTest
-(void) testIsEqualToData_TimingSafe {
    test([[NSMutableData dataWithLength:0] isEqualToData_TimingSafe:[NSMutableData dataWithLength:0]]);
    test([[NSMutableData dataWithLength:1] isEqualToData_TimingSafe:[NSMutableData dataWithLength:1]]);
    test(![[NSMutableData dataWithLength:1] isEqualToData_TimingSafe:[NSMutableData dataWithLength:0]]);
    test([[@"01020304" decodedAsHexString] isEqualToData_TimingSafe:[@"01020304" decodedAsHexString]]);
    test(![[@"01020305" decodedAsHexString] isEqualToData_TimingSafe:[@"01020304" decodedAsHexString]]);
    test(![[@"05020305" decodedAsHexString] isEqualToData_TimingSafe:[@"01020304" decodedAsHexString]]);
    test(![[@"05020304" decodedAsHexString] isEqualToData_TimingSafe:[@"01020304" decodedAsHexString]]);
    test(![[@"01050304" decodedAsHexString] isEqualToData_TimingSafe:[@"01020304" decodedAsHexString]]);
}
-(void) testKnownHmacSha1 {
    char* keyText = "key";
    char* valText = "The quick brown fox jumps over the lazy dog";
    NSData* key = [NSMutableData dataWithBytes:keyText length:strlen(keyText)];
    NSData* val = [NSMutableData dataWithBytes:valText length:strlen(valText)];
    NSData* expected = [@"de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9" decodedAsHexString];
    NSData* actual = [val hmacWithSha1WithKey:key];
    test([actual isEqualToData:expected]);
}
-(void) testKnownHmacSha256 {
    char* keyText = "key";
    char* valText = "The quick brown fox jumps over the lazy dog";
    NSData* key = [NSMutableData dataWithBytes:keyText length:strlen(keyText)];
    NSData* val = [NSMutableData dataWithBytes:valText length:strlen(valText)];
    NSData* expected = [@"f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8" decodedAsHexString];
    NSData* actual = [val hmacWithSha256WithKey:key];
    test([actual isEqualToData:expected]);
}
-(void) testAesCipherBlockChainingPadding {
    NSData* iv = [@"000102030405060708090A0B0C0D0E0F" decodedAsHexString];
    NSData* plain =[@"10b80d8098f0283a820e" decodedAsHexString];
    NSData* key =[@"2b7e151628aed2a6abf7158809cf4f3c" decodedAsHexString];
    
    NSData* cipher = [plain encryptWithAesInCipherBlockChainingModeWithPkcs7PaddingWithKey:key andIv:iv];
    test([cipher length] % 16 == 0);
    NSData* replain = [cipher decryptWithAesInCipherBlockChainingModeWithPkcs7PaddingWithKey:key andIv:iv];
    test([plain length] == [replain length]);
}
-(void) testKnownSha256 {
    char* valText = "The quick brown fox jumps over the lazy dog";
    NSData* val = [NSMutableData dataWithBytes:valText length:strlen(valText)];
    NSData* expected = [@"d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592" decodedAsHexString];
    NSData* actual = [val hashWithSha256];
    test([actual isEqualToData:expected]);
}
-(void) testRandom {
    NSData* d = [CryptoTools generateSecureRandomData:8];
    NSData* d2 = [CryptoTools generateSecureRandomData:8];
    
    test(5 == [[CryptoTools generateSecureRandomData:5] length]);
    test(8 == [d length]);
    
    // extremely unlikely to fail if any reasonable amount of entropy is going into d and d2
    test(![d isEqualToData:d2]);
}
-(void) testKnownAesCipherFeedback {
    NSData* iv = [@"000102030405060708090a0b0c0d0e0f" decodedAsHexString];
    NSData* plain =[@"6bc1bee22e409f96e93d7e117393172a" decodedAsHexString];
    NSData* cipher =[@"3b3fd92eb72dad20333449f8e83cfb4a" decodedAsHexString];
    NSData* key =[@"2b7e151628aed2a6abf7158809cf4f3c" decodedAsHexString];

    test([[plain encryptWithAesInCipherFeedbackModeWithKey:key andIv:iv] isEqualToData:cipher]);
    test([[cipher decryptWithAesInCipherFeedbackModeWithKey:key andIv:iv] isEqualToData:plain]);
}
-(void) testPerturbedAesCipherFeedbackInverts {
    for (int repeat = 0; repeat < 100; repeat++) {
        NSData* iv = generatePseudoRandomData(16);
        NSData* input = generatePseudoRandomData(16);
        NSData* key = generatePseudoRandomData(16);
        
        test([[[input encryptWithAesInCipherFeedbackModeWithKey:key andIv:iv] decryptWithAesInCipherFeedbackModeWithKey:key andIv:iv] isEqualToData:input]);
        test([[[input decryptWithAesInCipherFeedbackModeWithKey:key andIv:iv] encryptWithAesInCipherFeedbackModeWithKey:key andIv:iv] isEqualToData:input]);
    }
}

-(void) testKnownAesCounter {
    NSData* iv = [@"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff" decodedAsHexString];
    NSData* plain =[@"6bc1bee22e409f96e93d7e117393172a" decodedAsHexString];
    NSData* cipher =[@"874d6191b620e3261bef6864990db6ce" decodedAsHexString];
    NSData* key =[@"2b7e151628aed2a6abf7158809cf4f3c" decodedAsHexString];
    
    test([[plain encryptWithAesInCounterModeWithKey:key andIv:iv] isEqualToData:cipher]);
    test([[cipher decryptWithAesInCounterModeWithKey:key andIv:iv] isEqualToData:plain]);
}
-(void) testAesCounterEndianness {
    NSData* iv = [@"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff" decodedAsHexString];
    NSData* plain =[@"6bc1bee22e409f96e93d7e117393172ab1661dadd153b245034f1fb3655dc560" decodedAsHexString];
    NSData* cipher =[@"874d6191b620e3261bef6864990db6ce874d6191b620e3261bef6864990db6ce" decodedAsHexString];
    NSData* key =[@"2b7e151628aed2a6abf7158809cf4f3c" decodedAsHexString];
    
    test([[plain encryptWithAesInCounterModeWithKey:key andIv:iv] isEqualToData:cipher]);
    test([[cipher decryptWithAesInCounterModeWithKey:key andIv:iv] isEqualToData:plain]);
}
-(void) testPerturbedAesCounterInverts {
    for (int repeat = 0; repeat < 100; repeat++) {
        NSData* iv = generatePseudoRandomData(16);
        NSData* input = generatePseudoRandomData(16);
        NSData* key = generatePseudoRandomData(16);
        
        test([[[input encryptWithAesInCounterModeWithKey:key andIv:iv] decryptWithAesInCipherFeedbackModeWithKey:key andIv:iv] isEqualToData:input]);
        test([[[input decryptWithAesInCounterModeWithKey:key andIv:iv] encryptWithAesInCipherFeedbackModeWithKey:key andIv:iv] isEqualToData:input]);
    }
}
-(void) testComputeKnownOtp {
    test([[CryptoTools computeOtpWithPassword:@"password" andCounter:123] isEqualToString:@"SiYZc8Xg6KSmCECSImVSmjnRNfc="]);
}
-(void) testMacAuthenticationSucceeds{
    
}
-(void) testMacAuthenticationFails{
    
}
@end
