Updated the README for the 0.1 release.
5 // Created by Jens Alfke on 4/1/09.
6 // Copyright 2009 Jens Alfke. All rights reserved.
9 #import "MYPublicKey.h"
10 #import "MYPrivateKey.h"
11 #import "MYKeychain.h"
13 #import "MYIdentity.h"
14 #import "MYCrypto_Private.h"
20 #pragma mark KEYCHAIN:
23 TestCase(MYKeychain) {
24 MYKeychain *kc = [MYKeychain defaultKeychain];
25 Log(@"Default keychain = %@", kc);
27 #if !MYCRYPTO_USE_IPHONE_API
31 kc = [MYKeychain allKeychains];
32 Log(@"All-keychains = %@", kc);
34 #if !MYCRYPTO_USE_IPHONE_API
35 CAssertEq(kc.path,nil);
40 TestCase(EnumerateKeys) {
41 RequireTestCase(MYKeychain);
42 NSEnumerator *e = [[MYKeychain allKeychains] enumeratePublicKeys];
43 Log(@"Public Key Enumerator = %@", e);
45 for (MYPublicKey *key in e) {
46 Log(@"Found %@ -- name=%@", key, key.name);
49 e = [[MYKeychain allKeychains] enumeratePrivateKeys];
50 Log(@"Key-Pair Enumerator = %@", e);
52 for (MYPrivateKey *key in e) {
53 Log(@"Found %@ -- name=%@", key, key.name);
56 e = [[MYKeychain allKeychains] enumerateSymmetricKeys];
57 Log(@"Symmetric Key Enumerator = %@", e);
59 for (MYSymmetricKey *key in e) {
60 Log(@"Found %@ -- name=%@", key, key.name);
65 TestCase(EnumerateCerts) {
66 RequireTestCase(MYKeychain);
67 NSEnumerator *e = [[MYKeychain allKeychains] enumerateCertificates];
68 Log(@"Enumerator = %@", e);
70 for (MYCertificate *cert in e) {
71 //Log(@"Found %@ -- name=%@, email=%@", cert, cert.commonName, cert.emailAddresses);
75 TestCase(EnumerateIdentities) {
76 RequireTestCase(MYKeychain);
77 NSEnumerator *e = [[MYKeychain allKeychains] enumerateIdentities];
78 Log(@"Enumerator = %@", e);
80 for (MYIdentity *ident in e) {
81 Log(@"Found %@ -- name=%@, emails=(%@), key=%@",
82 ident, ident.commonName,
86 [ident.emailAddresses componentsJoinedByString: @", "],
94 #pragma mark SYMMETRIC KEYS:
97 static void testSymmetricKey( CCAlgorithm algorithm, unsigned sizeInBits ) {
98 NSAutoreleasePool *pool = [NSAutoreleasePool new];
99 Log(@"--- Testing %3u-bit #%i", sizeInBits, (int)algorithm);
101 MYSymmetricKey *key = [MYSymmetricKey generateSymmetricKeyOfSize: sizeInBits
102 algorithm: algorithm];
103 Log(@"Created %@", key);
105 CAssertEq(key.algorithm, algorithm);
106 CAssertEq(key.keySizeInBits, sizeInBits);
107 #if !TARGET_OS_IPHONE
108 CAssert(key.cssmKey != NULL);
111 NSData *keyData = key.keyData;
112 Log(@"Key data = %@", keyData);
113 CAssertEq(keyData.length, sizeInBits/8);
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);
123 // Encrypt large binary data:
124 cleartext = [NSData dataWithContentsOfFile: @"/Library/Desktop Pictures/Nature/Zen Garden.jpg"];
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);
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.
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);
146 Warn(@"Unable to export key in PKCS8");
152 TestCase(MYSymmetricKey) {
154 static const CCAlgorithm kTestAlgorithms[kNTests] = {
155 kCCAlgorithmAES128, kCCAlgorithmAES128, kCCAlgorithmAES128,
156 kCCAlgorithmDES, kCCAlgorithm3DES,
157 kCCAlgorithmCAST, kCCAlgorithmCAST, kCCAlgorithmCAST,
158 kCCAlgorithmRC4, kCCAlgorithmRC4, kCCAlgorithmRC4};
160 static const unsigned kTestBitSizes[kNTests] = {
166 for (int i=0; i<kNTests; i++)
167 testSymmetricKey(kTestAlgorithms[i], kTestBitSizes[i]);
172 #pragma mark KEY-PAIRS:
175 TestCase(MYPrivateKey) {
176 RequireTestCase(MYKeychain);
178 Log(@"Generating key pair...");
179 MYPrivateKey *pair = [[MYKeychain defaultKeychain] generateRSAKeyPairOfSize: 512];
180 Log(@"...created { %@ , %@ }.", pair, pair.publicKey);
182 CAssert(pair.keyRef);
183 MYPublicKey *publicKey = pair.publicKey;
184 CAssert(publicKey.keyRef);
187 NSData *pubKeyData = publicKey.keyData;
188 Log(@"Public key = %@ (%u bytes)",pubKeyData,pubKeyData.length);
191 MYSHA1Digest *pubKeyDigest = publicKey.publicKeyDigest;
192 Log(@"Public key digest = %@",pubKeyDigest);
193 CAssertEqual(pair.publicKeyDigest, pubKeyDigest);
195 Log(@"SHA1 of pub key = %@", pubKeyData.my_SHA1Digest.asData);
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);
201 CAssert( [publicKey verifySignature: sig ofData: data] );
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.");
211 [pair setAlias: @"TestCase@mooseyard.com"];
212 CAssertEqual(pair.alias, @"TestCase@mooseyard.com");
213 CAssertEqual(publicKey.alias, @"TestCase@mooseyard.com");
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.");
220 // Test creating a public key from data:
221 Log(@"Reconstituting public key from data...");
222 pub = [[MYPublicKey alloc] initWithKeyData: pubKeyData];
224 CAssertEqual(pub.keyData, pubKeyData);
225 CAssertEqual(pub.publicKeyDigest, pubKeyDigest);
226 CAssert( [pub verifySignature: sig ofData: data] );
227 Log(@"Verified signature from reconstituted key.");
229 // Now let's encrypt...
230 NSData *crypted = [pub encryptData: data];
231 Log(@"Encrypted = %@ (%u bytes)",crypted,crypted.length);
234 CAssertEqual([pair decryptData: crypted], data);
235 Log(@"Verified decryption.");
237 CAssert([pair removeFromKeychain]);
238 Log(@"Removed key-pair.");
243 if ([pair removeFromKeychain])
244 Log(@"Removed key-pair from keychain.");
246 Warn(@"Unable to remove test key-pair from keychain");
254 #pragma mark KEYPAIR EXPORT:
257 static void testKeyPairExportWithPrompt(BOOL withPrompt) {
258 MYKeychain *keychain = [MYKeychain allKeychains];
259 Log(@"Generating key pair...");
260 MYPrivateKey *pair = [keychain generateRSAKeyPairOfSize: 512];
262 CAssert(pair.keyRef);
263 CAssert(pair.publicKey.keyRef);
264 Log(@"...created pair.");
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.");
275 [pair setAlias: @"TestCase@mooseyard.com"];
276 CAssertEqual(pair.alias, @"TestCase@mooseyard.com");
278 #if !TARGET_OS_IPHONE
279 Log(@"Exporting key-pair...");
280 NSString *passphrase = @"passphrase";
283 privKeyData = [pair exportKey];
285 privKeyData = [pair _exportKeyInFormat: kSecFormatWrappedOpenSSL
287 passphrase: passphrase];
288 Log(@"Exported data = %@ (%u bytes)", privKeyData,privKeyData.length);
289 CAssert(privKeyData);
290 [privKeyData writeToFile: @"ExportedPrivKey" atomically: YES];
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]);
303 Log(@"Removing key-pair from keychain...");
304 CAssert([pair removeFromKeychain]);
306 CAssert([keychain publicKeyWithDigest: digest] == nil);
308 #if !TARGET_OS_IPHONE
309 Log(@"Importing key-pair...");
311 pair = [keychain importPublicKey: pubKeyData
312 privateKey: privKeyData];
314 pair = [[[MYPrivateKey alloc] _initWithKeyData: privKeyData
315 publicKeyData: pubKeyData
316 forKeychain: keychain.keychainRefOrDefault
317 passphrase: passphrase]
321 CAssertEqual(pair.publicKey.keyData, pubKeyData);
325 if ([pair removeFromKeychain])
326 Log(@"Removed key-pair from keychain.");
328 Warn(@"Unable to remove test key-pair from keychain");
333 TestCase(KeyPairExport) {
334 RequireTestCase(MYKeychain);
335 RequireTestCase(MYPrivateKey);
336 testKeyPairExportWithPrompt(NO);
339 TestCase(KeyPairExportWithUI) {
340 RequireTestCase(KeyPairExport);
341 testKeyPairExportWithPrompt(YES);