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