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