MYCryptoTest.m
author snej@snej.local
Thu Apr 09 22:46:48 2009 -0700 (2009-04-09)
changeset 6 2d7692f9b6b4
parent 4 f4709533c816
child 8 4c0eafa7b233
permissions -rw-r--r--
Updated the README for the 0.1 release.
snej@0
     1
//
snej@0
     2
//  MYCryptoTest.m
snej@0
     3
//  MYCrypto-iPhone
snej@0
     4
//
snej@0
     5
//  Created by Jens Alfke on 4/1/09.
snej@0
     6
//  Copyright 2009 Jens Alfke. All rights reserved.
snej@0
     7
//
snej@0
     8
snej@3
     9
#import "MYPublicKey.h"
snej@3
    10
#import "MYPrivateKey.h"
snej@0
    11
#import "MYKeychain.h"
snej@0
    12
#import "MYDigest.h"
snej@4
    13
#import "MYIdentity.h"
snej@0
    14
#import "MYCrypto_Private.h"
snej@0
    15
snej@0
    16
snej@0
    17
#if DEBUG
snej@0
    18
snej@0
    19
#pragma mark -
snej@0
    20
#pragma mark KEYCHAIN:
snej@0
    21
snej@0
    22
snej@0
    23
TestCase(MYKeychain) {
snej@0
    24
    MYKeychain *kc = [MYKeychain defaultKeychain];
snej@0
    25
    Log(@"Default keychain = %@", kc);
snej@0
    26
    CAssert(kc);
snej@2
    27
#if !MYCRYPTO_USE_IPHONE_API
snej@0
    28
    CAssert(kc.path);
snej@0
    29
#endif
snej@0
    30
    
snej@0
    31
    kc = [MYKeychain allKeychains];
snej@0
    32
    Log(@"All-keychains = %@", kc);
snej@0
    33
    CAssert(kc);
snej@2
    34
#if !MYCRYPTO_USE_IPHONE_API
snej@0
    35
    CAssertEq(kc.path,nil);
snej@1
    36
#endif
snej@0
    37
}
snej@0
    38
snej@0
    39
snej@0
    40
TestCase(EnumerateKeys) {
snej@0
    41
    RequireTestCase(MYKeychain);
snej@0
    42
    NSEnumerator *e = [[MYKeychain allKeychains] enumeratePublicKeys];
snej@0
    43
    Log(@"Public Key Enumerator = %@", e);
snej@0
    44
    CAssert(e);
snej@0
    45
    for (MYPublicKey *key in e) {
snej@0
    46
        Log(@"Found %@ -- name=%@", key, key.name);
snej@0
    47
    }
snej@0
    48
    
snej@3
    49
    e = [[MYKeychain allKeychains] enumeratePrivateKeys];
snej@0
    50
    Log(@"Key-Pair Enumerator = %@", e);
snej@0
    51
    CAssert(e);
snej@3
    52
    for (MYPrivateKey *key in e) {
snej@0
    53
        Log(@"Found %@ -- name=%@", key, key.name);
snej@0
    54
    }
snej@0
    55
    
snej@0
    56
    e = [[MYKeychain allKeychains] enumerateSymmetricKeys];
snej@0
    57
    Log(@"Symmetric Key Enumerator = %@", e);
snej@0
    58
    CAssert(e);
snej@0
    59
    for (MYSymmetricKey *key in e) {
snej@0
    60
        Log(@"Found %@ -- name=%@", key, key.name);
snej@0
    61
    }
snej@0
    62
}
snej@0
    63
snej@0
    64
snej@0
    65
TestCase(EnumerateCerts) {
snej@0
    66
    RequireTestCase(MYKeychain);
snej@0
    67
    NSEnumerator *e = [[MYKeychain allKeychains] enumerateCertificates];
snej@0
    68
    Log(@"Enumerator = %@", e);
snej@0
    69
    CAssert(e);
snej@0
    70
    for (MYCertificate *cert in e) {
snej@0
    71
        //Log(@"Found %@ -- name=%@, email=%@", cert, cert.commonName, cert.emailAddresses);
snej@0
    72
    }
snej@0
    73
}
snej@0
    74
snej@4
    75
TestCase(EnumerateIdentities) {
snej@4
    76
    RequireTestCase(MYKeychain);
snej@4
    77
    NSEnumerator *e = [[MYKeychain allKeychains] enumerateIdentities];
snej@4
    78
    Log(@"Enumerator = %@", e);
snej@4
    79
    CAssert(e);
snej@4
    80
    for (MYIdentity *ident in e) {
snej@4
    81
        Log(@"Found %@ -- name=%@, emails=(%@), key=%@",
snej@4
    82
            ident, ident.commonName, 
snej@5
    83
#if TARGET_OS_IPHONE
snej@5
    84
            nil,
snej@5
    85
#else
snej@4
    86
            [ident.emailAddresses componentsJoinedByString: @", "],
snej@5
    87
#endif
snej@4
    88
            ident.privateKey);
snej@4
    89
    }
snej@4
    90
}
snej@4
    91
snej@0
    92
snej@0
    93
#pragma mark -
snej@0
    94
#pragma mark SYMMETRIC KEYS:
snej@0
    95
snej@0
    96
snej@2
    97
static void testSymmetricKey( CCAlgorithm algorithm, unsigned sizeInBits ) {
snej@2
    98
    NSAutoreleasePool *pool = [NSAutoreleasePool new];
snej@2
    99
    Log(@"--- Testing %3u-bit #%i", sizeInBits, (int)algorithm);
snej@2
   100
    // Generate key:
snej@2
   101
    MYSymmetricKey *key = [MYSymmetricKey generateSymmetricKeyOfSize: sizeInBits
snej@2
   102
                                                           algorithm: algorithm];
snej@2
   103
    Log(@"Created %@", key);
snej@2
   104
    CAssert(key);
snej@2
   105
    CAssertEq(key.algorithm, algorithm);
snej@2
   106
    CAssertEq(key.keySizeInBits, sizeInBits);
snej@2
   107
#if !TARGET_OS_IPHONE
snej@2
   108
    CAssert(key.cssmKey != NULL);
snej@2
   109
#endif
snej@2
   110
    
snej@2
   111
    NSData *keyData = key.keyData;
snej@2
   112
    Log(@"Key data = %@", keyData);
snej@2
   113
    CAssertEq(keyData.length, sizeInBits/8);
snej@2
   114
    
snej@2
   115
    // Encrypt a small amount of text:
snej@2
   116
    NSData *cleartext = [@"This is a test. This is only a test." dataUsingEncoding: NSUTF8StringEncoding];
snej@2
   117
    NSData *encrypted = [key encryptData: cleartext];
snej@2
   118
    Log(@"Encrypted = %u bytes: %@", encrypted.length, encrypted);
snej@2
   119
    CAssert(encrypted.length >= cleartext.length);
snej@2
   120
    NSData *decrypted = [key decryptData: encrypted];
snej@2
   121
    CAssertEqual(decrypted, cleartext);
snej@2
   122
    
snej@2
   123
    // Encrypt large binary data:
snej@2
   124
    cleartext = [NSData dataWithContentsOfFile: @"/Library/Desktop Pictures/Nature/Zen Garden.jpg"];
snej@2
   125
    CAssert(cleartext);
snej@2
   126
    encrypted = [key encryptData: cleartext];
snej@2
   127
    Log(@"Encrypted = %u bytes", encrypted.length);
snej@2
   128
    CAssert(encrypted.length >= cleartext.length);
snej@2
   129
    decrypted = [key decryptData: encrypted];
snej@2
   130
    CAssertEqual(decrypted, cleartext);
snej@2
   131
    
snej@2
   132
#if !TARGET_OS_IPHONE
snej@2
   133
    // Try reconstituting the key from its data:
snej@2
   134
    NSData *exported = [key exportKeyInFormat: kSecFormatWrappedPKCS8 withPEM: NO];
snej@2
   135
    Log(@"Exported key: %@", exported);
snej@2
   136
    // CAssert(exported);
snej@2
   137
    //FIX: Exporting symmetric keys isn't working. Temporarily making this optional.
snej@2
   138
    if (exported) {
snej@2
   139
        CAssert(exported);
snej@2
   140
        MYSymmetricKey *key2 = [[MYSymmetricKey alloc] initWithKeyData: exported algorithm: algorithm];
snej@2
   141
        Log(@"Reconstituted as %@", key2);
snej@2
   142
        CAssertEqual(key2,key);
snej@2
   143
        decrypted = [key2 decryptData: encrypted];
snej@2
   144
        CAssertEqual(decrypted, cleartext);
snej@2
   145
    } else
snej@2
   146
        Warn(@"Unable to export key in PKCS8");
snej@2
   147
#endif
snej@2
   148
    [pool drain];
snej@2
   149
}
snej@2
   150
snej@2
   151
snej@0
   152
TestCase(MYSymmetricKey) {
snej@0
   153
    #define kNTests 11
snej@0
   154
    static const CCAlgorithm kTestAlgorithms[kNTests] = {
snej@0
   155
        kCCAlgorithmAES128, kCCAlgorithmAES128, kCCAlgorithmAES128,
snej@0
   156
        kCCAlgorithmDES, kCCAlgorithm3DES,
snej@0
   157
        kCCAlgorithmCAST, kCCAlgorithmCAST, kCCAlgorithmCAST,
snej@0
   158
        kCCAlgorithmRC4, kCCAlgorithmRC4, kCCAlgorithmRC4};
snej@0
   159
    
snej@0
   160
    static const unsigned kTestBitSizes[kNTests] = {
snej@0
   161
        128, 192, 256,
snej@0
   162
        64, 3*64,
snej@0
   163
        40, 80, 128,
snej@0
   164
        32, 200, 512*8};
snej@0
   165
snej@2
   166
    for (int i=0; i<kNTests; i++) 
snej@2
   167
        testSymmetricKey(kTestAlgorithms[i], kTestBitSizes[i]);
snej@0
   168
}
snej@0
   169
snej@0
   170
snej@0
   171
#pragma mark -
snej@0
   172
#pragma mark KEY-PAIRS:
snej@0
   173
snej@0
   174
snej@3
   175
TestCase(MYPrivateKey) {
snej@0
   176
    RequireTestCase(MYKeychain);
snej@0
   177
    
snej@0
   178
    Log(@"Generating key pair...");
snej@3
   179
    MYPrivateKey *pair = [[MYKeychain defaultKeychain] generateRSAKeyPairOfSize: 512];
snej@3
   180
    Log(@"...created { %@ , %@ }.", pair, pair.publicKey);
snej@0
   181
    CAssert(pair);
snej@0
   182
    CAssert(pair.keyRef);
snej@3
   183
    MYPublicKey *publicKey = pair.publicKey;
snej@3
   184
    CAssert(publicKey.keyRef);
snej@0
   185
    
snej@0
   186
    @try{
snej@3
   187
        NSData *pubKeyData = publicKey.keyData;
snej@0
   188
        Log(@"Public key = %@ (%u bytes)",pubKeyData,pubKeyData.length);
snej@0
   189
        CAssert(pubKeyData);
snej@0
   190
        
snej@3
   191
        MYSHA1Digest *pubKeyDigest = publicKey.publicKeyDigest;
snej@0
   192
        Log(@"Public key digest = %@",pubKeyDigest);
snej@3
   193
        CAssertEqual(pair.publicKeyDigest, pubKeyDigest);
snej@0
   194
        
snej@0
   195
        Log(@"SHA1 of pub key = %@", pubKeyData.my_SHA1Digest.asData);
snej@0
   196
        
snej@0
   197
        NSData *data = [@"This is a test. This is only a test!" dataUsingEncoding: NSUTF8StringEncoding];
snej@0
   198
        NSData *sig = [pair signData: data];
snej@0
   199
        Log(@"Signature = %@ (%u bytes)",sig,sig.length);
snej@0
   200
        CAssert(sig);
snej@3
   201
        CAssert( [publicKey verifySignature: sig ofData: data] );
snej@3
   202
        
snej@3
   203
        [pair setName: @"Test KeyPair Label"];
snej@3
   204
        CAssertEqual(pair.name, @"Test KeyPair Label");
snej@3
   205
        CAssertEqual(publicKey.name, @"Test KeyPair Label");
snej@3
   206
#if !TARGET_OS_IPHONE
snej@3
   207
        [pair setComment: @"This key-pair was generated automatically by a test case."];
snej@3
   208
        CAssertEqual(pair.comment, @"This key-pair was generated automatically by a test case.");
snej@3
   209
        CAssertEqual(publicKey.comment, @"This key-pair was generated automatically by a test case.");
snej@3
   210
#endif
snej@3
   211
        [pair setAlias: @"TestCase@mooseyard.com"];
snej@3
   212
        CAssertEqual(pair.alias, @"TestCase@mooseyard.com");
snej@3
   213
        CAssertEqual(publicKey.alias, @"TestCase@mooseyard.com");
snej@0
   214
        
snej@0
   215
        // Test creating a standalone public key:
snej@3
   216
        MYPublicKey *pub = [[MYPublicKey alloc] initWithKeyRef: publicKey.keyRef];
snej@0
   217
        CAssert( [pub verifySignature: sig ofData: data] );
snej@0
   218
        Log(@"Verified signature.");
snej@0
   219
snej@0
   220
        // Test creating a public key from data:
snej@0
   221
        Log(@"Reconstituting public key from data...");
snej@0
   222
        pub = [[MYPublicKey alloc] initWithKeyData: pubKeyData];
snej@0
   223
        CAssert(pub);
snej@0
   224
        CAssertEqual(pub.keyData, pubKeyData);
snej@0
   225
        CAssertEqual(pub.publicKeyDigest, pubKeyDigest);
snej@0
   226
        CAssert( [pub verifySignature: sig ofData: data] );
snej@0
   227
        Log(@"Verified signature from reconstituted key.");
snej@0
   228
                
snej@0
   229
        // Now let's encrypt...
snej@0
   230
        NSData *crypted = [pub encryptData: data];
snej@0
   231
        Log(@"Encrypted = %@ (%u bytes)",crypted,crypted.length);
snej@0
   232
        CAssert(crypted);
snej@0
   233
        
snej@0
   234
        CAssertEqual([pair decryptData: crypted], data);
snej@0
   235
        Log(@"Verified decryption.");
snej@0
   236
        
snej@0
   237
        CAssert([pair removeFromKeychain]);
snej@0
   238
        Log(@"Removed key-pair.");
snej@0
   239
        pair = nil;
snej@0
   240
        
snej@0
   241
    }@finally {
snej@0
   242
        if (pair) {
snej@0
   243
            if ([pair removeFromKeychain])
snej@0
   244
                Log(@"Removed key-pair from keychain.");
snej@0
   245
            else
snej@0
   246
                Warn(@"Unable to remove test key-pair from keychain");
snej@0
   247
        }
snej@0
   248
    }
snej@0
   249
}
snej@0
   250
snej@0
   251
snej@0
   252
snej@0
   253
#pragma mark -
snej@0
   254
#pragma mark KEYPAIR EXPORT:
snej@0
   255
snej@0
   256
snej@0
   257
static void testKeyPairExportWithPrompt(BOOL withPrompt) {
snej@0
   258
    MYKeychain *keychain = [MYKeychain allKeychains];
snej@0
   259
    Log(@"Generating key pair...");
snej@3
   260
    MYPrivateKey *pair = [keychain generateRSAKeyPairOfSize: 512];
snej@0
   261
    CAssert(pair);
snej@0
   262
    CAssert(pair.keyRef);
snej@3
   263
    CAssert(pair.publicKey.keyRef);
snej@0
   264
    Log(@"...created pair.");
snej@0
   265
    
snej@0
   266
    @try{
snej@3
   267
        NSData *pubKeyData = pair.publicKey.keyData;
snej@0
   268
        CAssert(pubKeyData.length >= 512/8);
snej@0
   269
        [pair setName: @"Test KeyPair Label"];
snej@0
   270
        CAssertEqual(pair.name, @"Test KeyPair Label");
snej@0
   271
#if !TARGET_OS_IPHONE
snej@0
   272
        [pair setComment: @"This key-pair was generated automatically by a test case."];
snej@0
   273
        CAssertEqual(pair.comment, @"This key-pair was generated automatically by a test case.");
snej@0
   274
#endif
snej@0
   275
        [pair setAlias: @"TestCase@mooseyard.com"];
snej@0
   276
        CAssertEqual(pair.alias, @"TestCase@mooseyard.com");
snej@0
   277
        
snej@0
   278
#if !TARGET_OS_IPHONE
snej@0
   279
        Log(@"Exporting key-pair...");
snej@0
   280
        NSString *passphrase = @"passphrase";
snej@0
   281
        NSData *privKeyData;
snej@0
   282
        if (withPrompt)
snej@3
   283
            privKeyData = [pair exportKey];
snej@0
   284
        else
snej@3
   285
            privKeyData = [pair _exportKeyInFormat: kSecFormatWrappedOpenSSL
snej@3
   286
                                          withPEM: YES
snej@3
   287
                                       passphrase: passphrase];
snej@0
   288
        Log(@"Exported data = %@ (%u bytes)", privKeyData,privKeyData.length);
snej@0
   289
        CAssert(privKeyData);
snej@0
   290
        [privKeyData writeToFile: @"ExportedPrivKey" atomically: YES];
snej@0
   291
#endif
snej@0
   292
        
snej@0
   293
        // Check key lookup:
snej@0
   294
        Log(@"Looking up public key of pair in keychain...");
snej@0
   295
        MYSHA1Digest *digest = pair.publicKeyDigest;
snej@0
   296
        MYPublicKey *foundKey = [keychain publicKeyWithDigest: digest];
snej@3
   297
        CAssertEqual(foundKey, pair.publicKey);
snej@3
   298
        CAssert([keychain.enumeratePublicKeys.allObjects containsObject: pair.publicKey]);
snej@3
   299
        MYPrivateKey *foundPair = [keychain privateKeyWithDigest: digest];
snej@0
   300
        CAssertEqual(foundPair, pair);
snej@3
   301
        CAssert([keychain.enumeratePrivateKeys.allObjects containsObject: pair]);
snej@0
   302
        
snej@0
   303
        Log(@"Removing key-pair from keychain...");
snej@0
   304
        CAssert([pair removeFromKeychain]);
snej@0
   305
        pair = nil;
snej@0
   306
        CAssert([keychain publicKeyWithDigest: digest] == nil);
snej@0
   307
        
snej@0
   308
#if !TARGET_OS_IPHONE
snej@0
   309
        Log(@"Importing key-pair...");
snej@0
   310
        if (withPrompt) {
snej@0
   311
            pair = [keychain importPublicKey: pubKeyData 
snej@0
   312
                                  privateKey: privKeyData];
snej@0
   313
        } else {
snej@3
   314
            pair = [[[MYPrivateKey alloc] _initWithKeyData: privKeyData
snej@3
   315
                                             publicKeyData: pubKeyData
snej@3
   316
                                               forKeychain: keychain.keychainRefOrDefault
snej@3
   317
                                                passphrase: passphrase]
snej@0
   318
                    autorelease];
snej@0
   319
        }
snej@0
   320
        CAssert(pair);
snej@3
   321
        CAssertEqual(pair.publicKey.keyData, pubKeyData);
snej@0
   322
#endif
snej@0
   323
    }@finally {
snej@0
   324
        if (pair) {
snej@0
   325
            if ([pair removeFromKeychain])
snej@0
   326
                Log(@"Removed key-pair from keychain.");
snej@0
   327
            else
snej@0
   328
                Warn(@"Unable to remove test key-pair from keychain");
snej@0
   329
        }
snej@0
   330
    }
snej@0
   331
}
snej@0
   332
snej@0
   333
TestCase(KeyPairExport) {
snej@0
   334
    RequireTestCase(MYKeychain);
snej@3
   335
    RequireTestCase(MYPrivateKey);
snej@0
   336
    testKeyPairExportWithPrompt(NO);
snej@0
   337
}
snej@0
   338
snej@0
   339
TestCase(KeyPairExportWithUI) {
snej@0
   340
    RequireTestCase(KeyPairExport);
snej@0
   341
    testKeyPairExportWithPrompt(YES);
snej@0
   342
}
snej@0
   343
snej@0
   344
snej@0
   345
#endif DEBUG
snej@0
   346