More work, mostly on documentation.
authorsnej@snej-mbp.mtv.corp.google.com
Tue Apr 07 10:56:58 2009 -0700 (2009-04-07)
changeset 28982b8fada63
parent 1 60e4cbbb5128
child 3 1dfe820d7ebe
More work, mostly on documentation.
MYCertificate-iPhone.m
MYCertificate.h
MYCertificate.m
MYCrypto-iPhone.xcodeproj/project.pbxproj
MYCrypto.xcodeproj/project.pbxproj
MYCryptoConfig.h
MYCryptoTest.m
MYCrypto_Private.h
MYCryptor.h
MYCryptor.m
MYDigest.h
MYDigest.m
MYKey-iPhone.m
MYKey.h
MYKey.m
MYKeyPair-iPhone.m
MYKeyPair.h
MYKeyPair.m
MYKeychain-iPhone.m
MYKeychain.h
MYKeychain.m
MYKeychainItem.h
MYKeychainItem.m
MYPublicKey-iPhone.m
MYPublicKey.m
MYSymmetricKey.h
MYSymmetricKey.m
README.textile
iPhone/MYCrypto_iPhoneAppDelegate.m
iPhone/MYCrypto_iPhone_main.m
maindocs.h
     1.1 --- a/MYCertificate-iPhone.m	Sat Apr 04 22:56:13 2009 -0700
     1.2 +++ b/MYCertificate-iPhone.m	Tue Apr 07 10:56:58 2009 -0700
     1.3 @@ -9,7 +9,7 @@
     1.4  #import "MYCertificate.h"
     1.5  #import "MYCrypto_Private.h"
     1.6  
     1.7 -#if USE_IPHONE_API
     1.8 +#if MYCRYPTO_USE_IPHONE_API
     1.9  
    1.10  
    1.11  @implementation MYCertificate
    1.12 @@ -70,4 +70,4 @@
    1.13  
    1.14  @end
    1.15  
    1.16 -#endif USE_IPHONE_API
    1.17 +#endif MYCRYPTO_USE_IPHONE_API
     2.1 --- a/MYCertificate.h	Sat Apr 04 22:56:13 2009 -0700
     2.2 +++ b/MYCertificate.h	Tue Apr 07 10:56:58 2009 -0700
     2.3 @@ -27,13 +27,6 @@
     2.4  /** Creates a MYCertificate object from exported key data, but does not add it to any keychain. */
     2.5  - (id) initWithCertificateData: (NSData*)data;
     2.6  
     2.7 -#if !TARGET_OS_IPHONE
     2.8 -/** Creates a MYCertificate object from exported key data, but does not add it to any keychain. */
     2.9 -- (id) initWithCertificateData: (NSData*)data
    2.10 -                          type: (CSSM_CERT_TYPE) type
    2.11 -                      encoding: (CSSM_CERT_ENCODING) encoding;
    2.12 -#endif
    2.13 -
    2.14  /** The Keychain object reference for this certificate. */
    2.15  @property (readonly) SecCertificateRef certificateRef;
    2.16  
    2.17 @@ -46,7 +39,18 @@
    2.18  /** The name of the subject (owner) of the certificate. */
    2.19  @property (readonly) NSString *commonName;
    2.20  
    2.21 +
    2.22 +/** @name Mac-Only
    2.23 + *  Functionality not available on iPhone. 
    2.24 + */
    2.25 +//@{
    2.26  #if !TARGET_OS_IPHONE
    2.27 +
    2.28 +/** Creates a MYCertificate object from exported key data, but does not add it to any keychain. */
    2.29 +- (id) initWithCertificateData: (NSData*)data
    2.30 +                          type: (CSSM_CERT_TYPE) type
    2.31 +                      encoding: (CSSM_CERT_ENCODING) encoding;
    2.32 +
    2.33  /** The list (if any) of the subject's email addresses. */
    2.34  @property (readonly) NSArray *emailAddresses;
    2.35  
    2.36 @@ -55,6 +59,8 @@
    2.37  
    2.38  /** Associates the receiver as the preferred certificate for the given name string. */
    2.39  - (BOOL) setPreferredCertificateForName: (NSString*)name;
    2.40 +
    2.41  #endif
    2.42 +//@}
    2.43  
    2.44  @end
     3.1 --- a/MYCertificate.m	Sat Apr 04 22:56:13 2009 -0700
     3.2 +++ b/MYCertificate.m	Tue Apr 07 10:56:58 2009 -0700
     3.3 @@ -9,7 +9,7 @@
     3.4  #import "MYCertificate.h"
     3.5  #import "MYCrypto_Private.h"
     3.6  
     3.7 -#if !USE_IPHONE_API
     3.8 +#if !MYCRYPTO_USE_IPHONE_API
     3.9  
    3.10  
    3.11  @implementation MYCertificate
    3.12 @@ -101,4 +101,4 @@
    3.13  @end
    3.14  
    3.15  
    3.16 -#endif !USE_IPHONE_API
    3.17 +#endif !MYCRYPTO_USE_IPHONE_API
     4.1 --- a/MYCrypto-iPhone.xcodeproj/project.pbxproj	Sat Apr 04 22:56:13 2009 -0700
     4.2 +++ b/MYCrypto-iPhone.xcodeproj/project.pbxproj	Tue Apr 07 10:56:58 2009 -0700
     4.3 @@ -57,6 +57,7 @@
     4.4  		276FB34A0F856CA400CB326E /* MYCertificate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYCertificate.m; sourceTree = "<group>"; };
     4.5  		27A430130F87C6D50063D362 /* MYSymmetricKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYSymmetricKey.m; sourceTree = "<group>"; };
     4.6  		27A430150F87C6DB0063D362 /* MYSymmetricKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYSymmetricKey.h; sourceTree = "<group>"; };
     4.7 +		27AAD9710F8927DB0064DD7C /* MYCryptoConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYCryptoConfig.h; sourceTree = "<group>"; };
     4.8  		27E8230C0F81D56E0019BE60 /* MYCertificate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYCertificate.h; sourceTree = "<group>"; };
     4.9  		27E8230E0F81D56E0019BE60 /* MYCryptor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYCryptor.h; sourceTree = "<group>"; };
    4.10  		27E8230F0F81D56E0019BE60 /* MYCryptor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYCryptor.m; sourceTree = "<group>"; };
    4.11 @@ -128,6 +129,7 @@
    4.12  		27E8230B0F81D56E0019BE60 /* Source */ = {
    4.13  			isa = PBXGroup;
    4.14  			children = (
    4.15 +				27AAD9710F8927DB0064DD7C /* MYCryptoConfig.h */,
    4.16  				27E8230C0F81D56E0019BE60 /* MYCertificate.h */,
    4.17  				276FB34A0F856CA400CB326E /* MYCertificate.m */,
    4.18  				273391CC0F81EC70009414D9 /* MYCertificate-iPhone.m */,
     5.1 --- a/MYCrypto.xcodeproj/project.pbxproj	Sat Apr 04 22:56:13 2009 -0700
     5.2 +++ b/MYCrypto.xcodeproj/project.pbxproj	Tue Apr 07 10:56:58 2009 -0700
     5.3 @@ -47,6 +47,7 @@
     5.4  		27A42D410F858ED80063D362 /* MYSymmetricKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYSymmetricKey.m; sourceTree = "<group>"; };
     5.5  		27A42ECC0F8689D30063D362 /* MYCertGen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYCertGen.h; sourceTree = "<group>"; };
     5.6  		27A42ECD0F8689D30063D362 /* MYCertGen.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYCertGen.m; sourceTree = "<group>"; };
     5.7 +		27AAD97B0F892A0D0064DD7C /* MYCryptoConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYCryptoConfig.h; sourceTree = "<group>"; };
     5.8  		27CFF4B10F7E8535000B418E /* MYCertificate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYCertificate.h; sourceTree = "<group>"; };
     5.9  		27CFF4B20F7E8535000B418E /* MYCertificate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYCertificate.m; sourceTree = "<group>"; };
    5.10  		27CFF4B30F7E8535000B418E /* MYCryptor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYCryptor.h; sourceTree = "<group>"; };
    5.11 @@ -80,6 +81,7 @@
    5.12  		27E820710F7EA6260019BE60 /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = System/Library/Frameworks/CoreServices.framework; sourceTree = SDKROOT; };
    5.13  		27E822A00F81C5660019BE60 /* MYKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYKey.h; sourceTree = "<group>"; };
    5.14  		27E822A10F81C5660019BE60 /* MYKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYKey.m; sourceTree = "<group>"; };
    5.15 +		27EAF0390F8B2D700091AF95 /* README.textile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README.textile; sourceTree = "<group>"; };
    5.16  		8DD76FA10486AA7600D96B5E /* MYCrypto */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = MYCrypto; sourceTree = BUILT_PRODUCTS_DIR; };
    5.17  /* End PBXFileReference section */
    5.18  
    5.19 @@ -118,6 +120,8 @@
    5.20  				27CFF4B20F7E8535000B418E /* MYCertificate.m */,
    5.21  				27CFF4B30F7E8535000B418E /* MYCryptor.h */,
    5.22  				27CFF4B40F7E8535000B418E /* MYCryptor.m */,
    5.23 +				27CFF4BF0F7E8535000B418E /* MYDigest.h */,
    5.24 +				27CFF4C00F7E8535000B418E /* MYDigest.m */,
    5.25  				27E822A00F81C5660019BE60 /* MYKey.h */,
    5.26  				27E822A10F81C5660019BE60 /* MYKey.m */,
    5.27  				27CFF4B50F7E8535000B418E /* MYKeychain.h */,
    5.28 @@ -130,8 +134,7 @@
    5.29  				27CFF4BD0F7E8535000B418E /* MYPublicKey.m */,
    5.30  				27A42D400F858ED80063D362 /* MYSymmetricKey.h */,
    5.31  				27A42D410F858ED80063D362 /* MYSymmetricKey.m */,
    5.32 -				27CFF4BF0F7E8535000B418E /* MYDigest.h */,
    5.33 -				27CFF4C00F7E8535000B418E /* MYDigest.m */,
    5.34 +				27AAD97B0F892A0D0064DD7C /* MYCryptoConfig.h */,
    5.35  				27CFF4BE0F7E8535000B418E /* MYCrypto_Private.h */,
    5.36  				27A42CBE0F8578B40063D362 /* MYCryptoTest.m */,
    5.37  				27CFF5210F7E94DF000B418E /* MYCrypto_main.m */,
    5.38 @@ -139,6 +142,7 @@
    5.39  				27A42ECD0F8689D30063D362 /* MYCertGen.m */,
    5.40  				27CFF5120F7E9212000B418E /* MYCrypto.xcconfig */,
    5.41  				27CFF5400F7E9653000B418E /* MYCrypto_Debug.xcconfig */,
    5.42 +				27EAF0390F8B2D700091AF95 /* README.textile */,
    5.43  			);
    5.44  			name = Source;
    5.45  			sourceTree = "<group>";
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/MYCryptoConfig.h	Tue Apr 07 10:56:58 2009 -0700
     6.3 @@ -0,0 +1,23 @@
     6.4 +//
     6.5 +//  MYCryptoConfig.h
     6.6 +//  MYCrypto
     6.7 +//
     6.8 +//  Created by Jens Alfke on 4/5/09.
     6.9 +//  Copyright 2009 Jens Alfke. All rights reserved.
    6.10 +//
    6.11 +
    6.12 +#import <Security/SecBase.h>
    6.13 +
    6.14 +/*  The iPhone simulator actually has the Mac OS X security API, not the iPhone one.
    6.15 +    So check which API is installed by looking for a preprocessor symbol that's defined
    6.16 +    only in the OS X version of SecBase.h. */
    6.17 +
    6.18 +#ifndef MYCRYPTO_USE_IPHONE_API
    6.19 +
    6.20 +#if TARGET_OS_IPHONE && !defined(__SEC_TYPES__)
    6.21 +#define MYCRYPTO_USE_IPHONE_API 1
    6.22 +#else
    6.23 +#define MYCRYPTO_USE_IPHONE_API 0
    6.24 +#endif
    6.25 +
    6.26 +#endif
    6.27 \ No newline at end of file
     7.1 --- a/MYCryptoTest.m	Sat Apr 04 22:56:13 2009 -0700
     7.2 +++ b/MYCryptoTest.m	Tue Apr 07 10:56:58 2009 -0700
     7.3 @@ -22,14 +22,14 @@
     7.4      MYKeychain *kc = [MYKeychain defaultKeychain];
     7.5      Log(@"Default keychain = %@", kc);
     7.6      CAssert(kc);
     7.7 -#if !USE_IPHONE_API
     7.8 +#if !MYCRYPTO_USE_IPHONE_API
     7.9      CAssert(kc.path);
    7.10  #endif
    7.11      
    7.12      kc = [MYKeychain allKeychains];
    7.13      Log(@"All-keychains = %@", kc);
    7.14      CAssert(kc);
    7.15 -#if !USE_IPHONE_API
    7.16 +#if !MYCRYPTO_USE_IPHONE_API
    7.17      CAssertEq(kc.path,nil);
    7.18  #endif
    7.19  }
    7.20 @@ -75,6 +75,61 @@
    7.21  #pragma mark SYMMETRIC KEYS:
    7.22  
    7.23  
    7.24 +static void testSymmetricKey( CCAlgorithm algorithm, unsigned sizeInBits ) {
    7.25 +    NSAutoreleasePool *pool = [NSAutoreleasePool new];
    7.26 +    Log(@"--- Testing %3u-bit #%i", sizeInBits, (int)algorithm);
    7.27 +    // Generate key:
    7.28 +    MYSymmetricKey *key = [MYSymmetricKey generateSymmetricKeyOfSize: sizeInBits
    7.29 +                                                           algorithm: algorithm];
    7.30 +    Log(@"Created %@", key);
    7.31 +    CAssert(key);
    7.32 +    CAssertEq(key.algorithm, algorithm);
    7.33 +    CAssertEq(key.keySizeInBits, sizeInBits);
    7.34 +#if !TARGET_OS_IPHONE
    7.35 +    CAssert(key.cssmKey != NULL);
    7.36 +#endif
    7.37 +    
    7.38 +    NSData *keyData = key.keyData;
    7.39 +    Log(@"Key data = %@", keyData);
    7.40 +    CAssertEq(keyData.length, sizeInBits/8);
    7.41 +    
    7.42 +    // Encrypt a small amount of text:
    7.43 +    NSData *cleartext = [@"This is a test. This is only a test." dataUsingEncoding: NSUTF8StringEncoding];
    7.44 +    NSData *encrypted = [key encryptData: cleartext];
    7.45 +    Log(@"Encrypted = %u bytes: %@", encrypted.length, encrypted);
    7.46 +    CAssert(encrypted.length >= cleartext.length);
    7.47 +    NSData *decrypted = [key decryptData: encrypted];
    7.48 +    CAssertEqual(decrypted, cleartext);
    7.49 +    
    7.50 +    // Encrypt large binary data:
    7.51 +    cleartext = [NSData dataWithContentsOfFile: @"/Library/Desktop Pictures/Nature/Zen Garden.jpg"];
    7.52 +    CAssert(cleartext);
    7.53 +    encrypted = [key encryptData: cleartext];
    7.54 +    Log(@"Encrypted = %u bytes", encrypted.length);
    7.55 +    CAssert(encrypted.length >= cleartext.length);
    7.56 +    decrypted = [key decryptData: encrypted];
    7.57 +    CAssertEqual(decrypted, cleartext);
    7.58 +    
    7.59 +#if !TARGET_OS_IPHONE
    7.60 +    // Try reconstituting the key from its data:
    7.61 +    NSData *exported = [key exportKeyInFormat: kSecFormatWrappedPKCS8 withPEM: NO];
    7.62 +    Log(@"Exported key: %@", exported);
    7.63 +    // CAssert(exported);
    7.64 +    //FIX: Exporting symmetric keys isn't working. Temporarily making this optional.
    7.65 +    if (exported) {
    7.66 +        CAssert(exported);
    7.67 +        MYSymmetricKey *key2 = [[MYSymmetricKey alloc] initWithKeyData: exported algorithm: algorithm];
    7.68 +        Log(@"Reconstituted as %@", key2);
    7.69 +        CAssertEqual(key2,key);
    7.70 +        decrypted = [key2 decryptData: encrypted];
    7.71 +        CAssertEqual(decrypted, cleartext);
    7.72 +    } else
    7.73 +        Warn(@"Unable to export key in PKCS8");
    7.74 +#endif
    7.75 +    [pool drain];
    7.76 +}
    7.77 +
    7.78 +
    7.79  TestCase(MYSymmetricKey) {
    7.80      #define kNTests 11
    7.81      static const CCAlgorithm kTestAlgorithms[kNTests] = {
    7.82 @@ -89,38 +144,8 @@
    7.83          40, 80, 128,
    7.84          32, 200, 512*8};
    7.85  
    7.86 -    for (int i=0; i<kNTests; i++) {
    7.87 -        NSAutoreleasePool *pool = [NSAutoreleasePool new];
    7.88 -        Log(@"Test #%2i: algorithm = %3u-bit #%i", i+1, kTestBitSizes[i], (int)kTestAlgorithms[i]);
    7.89 -        // Generate key:
    7.90 -        MYSymmetricKey *key = [MYSymmetricKey generateSymmetricKeyOfSize: kTestBitSizes[i]
    7.91 -                                                               algorithm: kTestAlgorithms[i]];
    7.92 -        CAssert(key);
    7.93 -#if !TARGET_OS_IPHONE
    7.94 -        CAssert(key.cssmKey != NULL);
    7.95 -#endif
    7.96 -        Log(@"Key data = %@", key.keyData);
    7.97 -        CAssertEq(key.keyData.length, kTestBitSizes[i]/8);
    7.98 -
    7.99 -        // Encrypt a small amount of text:
   7.100 -        NSData *cleartext = [@"This is a test. This is only a test." dataUsingEncoding: NSUTF8StringEncoding];
   7.101 -        NSData *encrypted = [key encryptData: cleartext];
   7.102 -        Log(@"Encrypted = %u bytes: %@", encrypted.length, encrypted);
   7.103 -        CAssert(encrypted.length >= cleartext.length);
   7.104 -        NSData *decrypted = [key decryptData: encrypted];
   7.105 -        CAssertEqual(decrypted, cleartext);
   7.106 -        
   7.107 -        // Encrypt large binary data:
   7.108 -        cleartext = [NSData dataWithContentsOfFile: @"/Library/Desktop Pictures/Nature/Zen Garden.jpg"];
   7.109 -        CAssert(cleartext);
   7.110 -        encrypted = [key encryptData: cleartext];
   7.111 -        Log(@"Encrypted = %u bytes", encrypted.length);
   7.112 -        CAssert(encrypted.length >= cleartext.length);
   7.113 -        decrypted = [key decryptData: encrypted];
   7.114 -        CAssertEqual(decrypted, cleartext);
   7.115 -        
   7.116 -        [pool drain];
   7.117 -    }
   7.118 +    for (int i=0; i<kNTests; i++) 
   7.119 +        testSymmetricKey(kTestAlgorithms[i], kTestBitSizes[i]);
   7.120  }
   7.121  
   7.122  
     8.1 --- a/MYCrypto_Private.h	Sat Apr 04 22:56:13 2009 -0700
     8.2 +++ b/MYCrypto_Private.h	Tue Apr 07 10:56:58 2009 -0700
     8.3 @@ -6,6 +6,7 @@
     8.4  //  Copyright 2009 Jens Alfke. All rights reserved.
     8.5  //
     8.6  
     8.7 +#import "MYCryptoConfig.h"
     8.8  #import "MYKeychain.h"
     8.9  #import "MYKey.h"
    8.10  #import "MYSymmetricKey.h"
    8.11 @@ -14,15 +15,8 @@
    8.12  #import "Test.h"
    8.13  #import <Security/Security.h>
    8.14  
    8.15 -/*  The iPhone simulator actually has the Mac OS X security API, not the iPhone one.
    8.16 -    So don't use the iPhone API when configured to run in the simulator. */
    8.17 -#if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
    8.18 -#define USE_IPHONE_API 1
    8.19 -#else
    8.20 -#define USE_IPHONE_API 0
    8.21 -#endif
    8.22  
    8.23 -#if USE_IPHONE_API
    8.24 +#if MYCRYPTO_USE_IPHONE_API
    8.25  typedef CFTypeRef SecKeychainAttrType;
    8.26  typedef CFTypeRef SecKeychainItemRef;
    8.27  typedef CFTypeRef SecKeychainRef;
    8.28 @@ -30,7 +24,7 @@
    8.29  #endif
    8.30  
    8.31  
    8.32 -#if TARGET_IPHONE_SIMULATOR
    8.33 +#if TARGET_OS_IPHONE && !MYCRYPTO_USE_IPHONE_API
    8.34  @interface MYKeychain (Private)
    8.35  - (id) initWithKeychainRef: (SecKeychainRef)keychainRef;
    8.36  @property (readonly) SecKeychainRef keychainRef, keychainRefOrDefault;
    8.37 @@ -58,7 +52,7 @@
    8.38  - (id) _initWithKeyData: (NSData*)data
    8.39              forKeychain: (SecKeychainRef)keychain;
    8.40  @property (readonly) SecExternalItemType keyType;
    8.41 -#if !USE_IPHONE_API
    8.42 +#if !MYCRYPTO_USE_IPHONE_API
    8.43  @property (readonly) const CSSM_KEY* cssmKey;
    8.44  - (NSData*) exportKeyInFormat: (SecExternalFormat)format withPEM: (BOOL)withPEM;
    8.45  #endif
    8.46 @@ -81,7 +75,7 @@
    8.47  
    8.48  @interface MYKeyPair (Private)
    8.49  + (MYKeyPair*) _generateRSAKeyPairOfSize: (unsigned)keySize
    8.50 -                            inKeychain: (SecKeychainRef)keychain;
    8.51 +                            inKeychain: (MYKeychain*)keychain;
    8.52  - (id) _initWithPublicKeyData: (NSData*)pubKeyData 
    8.53                 privateKeyData: (NSData*)privKeyData
    8.54                    forKeychain: (SecKeychainRef)keychain
    8.55 @@ -99,7 +93,7 @@
    8.56  @end
    8.57  
    8.58  
    8.59 -#if TARGET_IPHONE_SIMULATOR
    8.60 +#if TARGET_OS_IPHONE && !MYCRYPTO_USE_IPHONE_API
    8.61  @interface MYCertificate (Private)
    8.62  - (id) initWithCertificateData: (NSData*)data
    8.63                            type: (CSSM_CERT_TYPE) type
    8.64 @@ -113,7 +107,7 @@
    8.65  #undef check
    8.66  BOOL check(OSStatus err, NSString *what);
    8.67  
    8.68 -#if !USE_IPHONE_API
    8.69 +#if !MYCRYPTO_USE_IPHONE_API
    8.70  BOOL checkcssm(CSSM_RETURN err, NSString *what);
    8.71  
    8.72  SecKeyRef importKey(NSData *data, 
     9.1 --- a/MYCryptor.h	Sat Apr 04 22:56:13 2009 -0700
     9.2 +++ b/MYCryptor.h	Tue Apr 07 10:56:58 2009 -0700
     9.3 @@ -10,9 +10,9 @@
     9.4  #import <CommonCrypto/CommonCryptor.h>
     9.5  
     9.6  
     9.7 -/** Symmetric encryption: a simple Cocoa wrapper for CommonCrypto/commonCryptor.h.
     9.8 -    Provides a streaming interface for encrypting/decrypting data.
     9.9 -    This class will probably be merged into or integrated with MYSymmetricKey. */
    9.10 +/** Symmetric encryption: a streaming interface for encrypting/decrypting data.
    9.11 +    This is a simple Cocoa wrapper for CommonCrypto/commonCryptor.h. It will probably be
    9.12 +    merged into, or integrated with, MYSymmetricKey. */
    9.13  @interface MYCryptor : NSObject
    9.14  {
    9.15      @private
    9.16 @@ -27,12 +27,26 @@
    9.17      size_t _outputExtraBytes;
    9.18  }
    9.19  
    9.20 -/** Returns a block of cryptographically-random data, suitable for use as a symmetric key.
    9.21 -    (CommonCryptor.h defines constants for key sizes and size-ranges, like kCCKeySizeAES128.) */
    9.22 -+ (NSData*) randomKeyOfLength: (size_t)length;
    9.23 +/** Returns a randomly-generated symmetric key of the desired length (in bits).
    9.24 + *  @param lengthInBits  The length of the desired key, in bits (not bytes).
    9.25 + */
    9.26 ++ (NSData*) randomKeyOfLength: (size_t)lengthInBits;
    9.27  
    9.28 -/** Converts a passphrase into a block of data of the given size, suitable for use as a symmetric key. */
    9.29 -+ (NSData*) keyOfLength: (size_t)lengthInBits fromPassphrase: (NSString*)passphrase;
    9.30 +/** Converts a passphrase into a symmetric key of the desired length (in bits).
    9.31 + *  The same passphrase (and salt) will always return the same key, so you can use this method
    9.32 + *  to encrypt and decrypt data using a user-entered passphrase, without having to store the key
    9.33 + *  itself in the keychain.
    9.34 + *  @param lengthInBits  The length of the desired key, in bits (not bytes).
    9.35 + *  @param passphrase  The user-entered passphrase.
    9.36 + *  @param salt  An arbitrary value whose description will be appended to the passphrase before
    9.37 + *          hashing, to perturb the resulting bits. The purpose of this is to make it harder for
    9.38 + *          an attacker to brute-force the key using a precompiled list of digests of common
    9.39 + *          passwords. Changing the salt changes the key, so you need to pass the same value when
    9.40 + *          re-deriving the key as you did when first generating it.
    9.41 + */
    9.42 ++ (NSData*) keyOfLength: (size_t)lengthInBits
    9.43 +         fromPassphrase: (NSString*)passphrase
    9.44 +                   salt: (id)salt;
    9.45  
    9.46  /** Creates a MYCryptor configured to encrypt data. */
    9.47  - (id) initEncryptorWithKey: (NSData*)key
    10.1 --- a/MYCryptor.m	Sat Apr 04 22:56:13 2009 -0700
    10.2 +++ b/MYCryptor.m	Tue Apr 07 10:56:58 2009 -0700
    10.3 @@ -10,7 +10,7 @@
    10.4  #import "MYDigest.h"
    10.5  #import "Test.h"
    10.6  
    10.7 -#if USE_IPHONE_API
    10.8 +#if MYCRYPTO_USE_IPHONE_API
    10.9  #import <Security/SecRandom.h>
   10.10  #else
   10.11  #import "MYCrypto_Private.h"
   10.12 @@ -21,7 +21,7 @@
   10.13  
   10.14  NSString* const CryptorErrorDomain = @"CCCryptor";
   10.15  
   10.16 -#if !USE_IPHONE_API
   10.17 +#if !MYCRYPTO_USE_IPHONE_API
   10.18  static BOOL generateRandomBytes(CSSM_CSP_HANDLE module, uint32_t lengthInBytes, void *dstBytes);
   10.19  #endif
   10.20  
   10.21 @@ -35,25 +35,31 @@
   10.22  @implementation MYCryptor
   10.23  
   10.24  
   10.25 -+ (NSData*) randomKeyOfLength: (size_t)length {
   10.26 -    NSParameterAssert(length<100000);
   10.27 -    uint8_t *bytes = malloc(length);
   10.28 ++ (NSData*) randomKeyOfLength: (size_t)lengthInBits {
   10.29 +    size_t lengthInBytes = (lengthInBits + 7)/8;
   10.30 +    NSParameterAssert(lengthInBytes<100000);
   10.31 +    uint8_t *bytes = malloc(lengthInBytes);
   10.32      if (!bytes) return nil;
   10.33 -#if USE_IPHONE_API
   10.34 -    BOOL ok = SecRandomCopyBytes(kSecRandomDefault, length,bytes) >= 0;
   10.35 +#if MYCRYPTO_USE_IPHONE_API
   10.36 +    BOOL ok = SecRandomCopyBytes(kSecRandomDefault, lengthInBytes,bytes) >= 0;
   10.37  #else
   10.38 -    BOOL ok = generateRandomBytes([[MYKeychain defaultKeychain] CSPHandle], length, bytes);
   10.39 +    BOOL ok = generateRandomBytes([[MYKeychain defaultKeychain] CSPHandle], lengthInBytes, bytes);
   10.40  #endif
   10.41      if (ok)
   10.42 -        return [NSData dataWithBytesNoCopy: bytes length: length freeWhenDone: YES];
   10.43 +        return [NSData dataWithBytesNoCopy: bytes length: lengthInBytes freeWhenDone: YES];
   10.44      else {
   10.45          free(bytes);
   10.46          return nil;
   10.47      }
   10.48  }
   10.49  
   10.50 -+ (NSData*) keyOfLength: (size_t)lengthInBits fromPassphrase: (NSString*)passphrase
   10.51 ++ (NSData*) keyOfLength: (size_t)lengthInBits
   10.52 +         fromPassphrase: (NSString*)passphrase
   10.53 +                   salt: (id)salt
   10.54  {
   10.55 +    Assert(passphrase);
   10.56 +    Assert(salt);
   10.57 +    passphrase = $sprintf(@"MYCrypto|%@|%@", passphrase, salt);
   10.58      size_t lengthInBytes = (lengthInBits + 7)/8;
   10.59      MYDigest *digest = [[passphrase dataUsingEncoding: NSUTF8StringEncoding] my_SHA256Digest];
   10.60      if (lengthInBytes <= digest.length)
   10.61 @@ -95,6 +101,13 @@
   10.62      [super dealloc];
   10.63  }
   10.64  
   10.65 +- (void) finalize
   10.66 +{
   10.67 +    if (_cryptor)
   10.68 +        CCCryptorRelease(_cryptor);
   10.69 +    [super finalize];
   10.70 +}
   10.71 +
   10.72  
   10.73  @synthesize key=_key, algorithm=_algorithm, options=_options,
   10.74      outputStream=_outputStream, error=_error;
   10.75 @@ -248,7 +261,7 @@
   10.76  
   10.77  
   10.78  
   10.79 -#if !USE_IPHONE_API
   10.80 +#if !MYCRYPTO_USE_IPHONE_API
   10.81  static BOOL generateRandomBytes(CSSM_CSP_HANDLE module, uint32_t lengthInBytes, void *dstBytes) {
   10.82      // Adapted from code in Keychain.framework's KeychainUtils.m by Wade Tregaskis.
   10.83      CSSM_CC_HANDLE ccHandle;
   10.84 @@ -268,7 +281,7 @@
   10.85  
   10.86  TestCase(MYCryptor) {
   10.87      // Encryption:
   10.88 -    NSData *key = [MYCryptor randomKeyOfLength: kCCKeySizeAES256];
   10.89 +    NSData *key = [MYCryptor randomKeyOfLength: 256];
   10.90      Log(@"Key = %@",key);
   10.91      MYCryptor *enc = [[MYCryptor alloc] initEncryptorWithKey: key algorithm: kCCAlgorithmAES128];
   10.92      CAssert(enc);
   10.93 @@ -292,7 +305,7 @@
   10.94      CAssertEqual(decrypted, @"This is a test. This is only a test.");
   10.95      
   10.96      // Encryption to stream:
   10.97 -    key = [MYCryptor randomKeyOfLength: kCCKeySizeAES256];
   10.98 +    key = [MYCryptor randomKeyOfLength: 256];
   10.99      Log(@"Key = %@",key);
  10.100      enc = [[MYCryptor alloc] initEncryptorWithKey: key algorithm: kCCAlgorithmAES128];
  10.101      CAssert(enc);
    11.1 --- a/MYDigest.h	Sat Apr 04 22:56:13 2009 -0700
    11.2 +++ b/MYDigest.h	Tue Apr 07 10:56:58 2009 -0700
    11.3 @@ -10,7 +10,9 @@
    11.4  
    11.5  
    11.6  /** Abstract superclass for cryptographic digests (aka hashes).
    11.7 -    Each specific type of digest has its own concrete subclass. */
    11.8 +    Each specific type of digest has its own concrete subclass.
    11.9 +    Digests are full-fledged value objects, and can be compared, used as dictionary keys,
   11.10 +    copied, and archived. */
   11.11  @interface MYDigest : NSObject <NSCoding, NSCopying>
   11.12  {
   11.13      @private
   11.14 @@ -39,13 +41,15 @@
   11.15  /** Returns the digest as a hex string. */
   11.16  @property (readonly) NSString *hexString;
   11.17  
   11.18 -/** Returns the first 8 digits (32 bits) of the digest's hex string, followed by "..."
   11.19 +/** Returns the first 8 digits (32 bits) of the digest's hex string, followed by "...".
   11.20      This is intended only for use in log messages or object descriptions, since
   11.21      32 bits isn't nearly enough to provide any useful uniqueness. */
   11.22  @property (readonly) NSString *abbreviatedHexString;
   11.23  
   11.24 -/** The algorithm that created this digest. */
   11.25 -@property (readonly) uint32_t /*CSSM_ALGORITHMS*/ algorithm;
   11.26 +/** The algorithm that created this digest. 
   11.27 +    Values are defined in the CSSM_ALGORITHMS enum in cssmtype.h.
   11.28 +    (Abstract method.) */
   11.29 +@property (readonly) uint32_t algorithm;
   11.30  
   11.31  /** The length (in bytes, not bits!) of this digest. */
   11.32  @property (readonly) size_t length;
   11.33 @@ -54,7 +58,7 @@
   11.34  @property (readonly) const void* bytes;
   11.35  
   11.36  /** The algorithm used by this subclass. (Abstract method.) */
   11.37 -+ (uint32_t /*CSSM_ALGORITHMS*/) algorithm;
   11.38 ++ (uint32_t) algorithm;
   11.39  
   11.40  /** The length of digests created by this subclass. (Abstract method.) */
   11.41  + (size_t) length;
   11.42 @@ -65,15 +69,19 @@
   11.43  @end
   11.44  
   11.45  
   11.46 -/** A simple C struct containing a 160-bit SHA-1 digest. */
   11.47 +// A simple C struct containing a 160-bit SHA-1 digest. Used by the MYSHA1Digest class.
   11.48  typedef struct {
   11.49      UInt8 bytes[20];
   11.50  } RawSHA1Digest;
   11.51      
   11.52  /** A 160-bit SHA-1 digest encapsulated in an object. */
   11.53  @interface MYSHA1Digest : MYDigest
   11.54 +{ }
   11.55  
   11.56 +/** Initialize a MYSHA1Digest object given an existing raw SHA-1 digest. */
   11.57  - (MYSHA1Digest*) initWithRawSHA1Digest: (const RawSHA1Digest*)rawDigest;
   11.58 +
   11.59 +/** Create a MYSHA1Digest object given an existing raw SHA-1 digest. */
   11.60  + (MYSHA1Digest*) digestFromRawSHA1Digest: (const RawSHA1Digest*)rawDigest;
   11.61  
   11.62  @property (readonly) const RawSHA1Digest* rawSHA1Digest;
   11.63 @@ -81,15 +89,19 @@
   11.64  @end
   11.65  
   11.66  
   11.67 -/** A simple C struct containing a 256-bit SHA-256 digest. */
   11.68 +// A simple C struct containing a 256-bit SHA-256 digest.
   11.69  typedef struct {
   11.70      UInt8 bytes[32];
   11.71  } RawSHA256Digest;
   11.72  
   11.73 -/** A 256-bit SHA-256 digest encapsulated in an object. */
   11.74 +/** A 256-bit SHA-256 digest encapsulated in an object. Used by the MYSHA256Digest class. */
   11.75  @interface MYSHA256Digest : MYDigest
   11.76 +{ }
   11.77  
   11.78 +/** Initialize a MYSHA256Digest object given an existing raw SHA-1 digest. */
   11.79  - (MYSHA256Digest*) initWithRawSHA256Digest: (const RawSHA256Digest*)rawDigest;
   11.80 +
   11.81 +/** Create a MYSHA256Digest object given an existing raw SHA-1 digest. */
   11.82  + (MYSHA256Digest*) digestFromRawSHA256Digest: (const RawSHA256Digest*)rawDigest;
   11.83  
   11.84  @property (readonly) const RawSHA256Digest* rawSHA256Digest;
   11.85 @@ -97,8 +109,13 @@
   11.86  @end
   11.87  
   11.88  
   11.89 -/** Convenience methods for NSData objects */
   11.90 +/** Convenience methods for computing digests of NSData objects. */
   11.91  @interface NSData (MYDigest)
   11.92 +
   11.93 +/** The SHA-1 digest of the receiver's data. */
   11.94  @property (readonly) MYSHA1Digest* my_SHA1Digest;
   11.95 +
   11.96 +/** The SHA-256 digest of the receiver's data. */
   11.97  @property (readonly) MYSHA256Digest* my_SHA256Digest;
   11.98 +
   11.99  @end
    12.1 --- a/MYDigest.m	Sat Apr 04 22:56:13 2009 -0700
    12.2 +++ b/MYDigest.m	Tue Apr 07 10:56:58 2009 -0700
    12.3 @@ -11,7 +11,7 @@
    12.4  #import "MYCrypto_Private.h"
    12.5  
    12.6  
    12.7 -#if USE_IPHONE_API
    12.8 +#if MYCRYPTO_USE_IPHONE_API
    12.9  enum {
   12.10      CSSM_ALGID_SHA1 = 8,
   12.11      CSSM_ALGID_SHA256 = 0x80000000 + 14
   12.12 @@ -53,6 +53,12 @@
   12.13      [super dealloc];
   12.14  }
   12.15  
   12.16 +- (void) finalize
   12.17 +{
   12.18 +    if(_rawDigest) free(_rawDigest);
   12.19 +    [super finalize];
   12.20 +}
   12.21 +
   12.22  
   12.23  - (id) copyWithZone: (NSZone*)zone
   12.24  {
    13.1 --- a/MYKey-iPhone.m	Sat Apr 04 22:56:13 2009 -0700
    13.2 +++ b/MYKey-iPhone.m	Tue Apr 07 10:56:58 2009 -0700
    13.3 @@ -9,7 +9,7 @@
    13.4  
    13.5  #import "MYCrypto_Private.h"
    13.6  
    13.7 -#if USE_IPHONE_API
    13.8 +#if MYCRYPTO_USE_IPHONE_API
    13.9  
   13.10  #import "MYDigest.h"
   13.11  #import "MYErrorUtils.h"
   13.12 @@ -72,7 +72,7 @@
   13.13                                  {(id)kSecAttrKeyClass, (id)self.keyType},
   13.14                                  {(id)kSecMatchItemList, $array((id)self.keyRef)},
   13.15                                  {(id)kSecReturnAttributes, $true} );
   13.16 -    CFDictionaryRef attrs;
   13.17 +    CFDictionaryRef attrs = NULL;
   13.18      if (!check(SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef*)&attrs), @"SecItemCopyMatching"))
   13.19          return nil;
   13.20      CFTypeRef rawValue = CFDictionaryGetValue(attrs,attribute);
   13.21 @@ -112,7 +112,7 @@
   13.22  @end
   13.23  
   13.24  
   13.25 -#endif USE_IPHONE_API
   13.26 +#endif MYCRYPTO_USE_IPHONE_API
   13.27  
   13.28  
   13.29  
    14.1 --- a/MYKey.h	Sat Apr 04 22:56:13 2009 -0700
    14.2 +++ b/MYKey.h	Tue Apr 07 10:56:58 2009 -0700
    14.3 @@ -28,6 +28,7 @@
    14.4  /** Abstract superclass for keys.
    14.5      Concrete subclasses are MYSymmetricKey and MYPublicKey. */
    14.6  @interface MYKey : MYKeychainItem
    14.7 +{ }
    14.8  
    14.9  /** The key's raw data. */
   14.10  @property (readonly) NSData *keyData;
   14.11 @@ -42,17 +43,32 @@
   14.12      that it can be read and modified by any other app that can access this key. */
   14.13  @property (copy) NSString *alias;
   14.14  
   14.15 +
   14.16 +/** @name Mac-Only
   14.17 + *  Functionality not available on iPhone. 
   14.18 + */
   14.19 +//@{
   14.20  #if !TARGET_OS_IPHONE
   14.21 +
   14.22  /** The user-visible comment (kSecKeyApplicationTag) associated with this key in the Keychain.
   14.23 -    The user can edit this, so don't expect it to be immutable. */
   14.24 + The user can edit this, so don't expect it to be immutable. */
   14.25  @property (copy) NSString *comment;
   14.26 +
   14.27 +/** Converts the key into a data blob in one of several standard formats, suitable for storing in
   14.28 +    a file or sending over the network.
   14.29 +    @param format  The data format: kSecFormatOpenSSL, kSecFormatSSH, kSecFormatBSAFE or kSecFormatSSHv2.
   14.30 +    @param withPEM  YES if the data should be encoded in PEM format, which converts into short lines
   14.31 +        of printable ASCII characters, suitable for sending in email. */
   14.32 +- (NSData*) exportKeyInFormat: (SecExternalFormat)format withPEM: (BOOL)withPEM;
   14.33 +
   14.34  #endif
   14.35 +//@}
   14.36  
   14.37 -@end
   14.38  
   14.39 -
   14.40 -
   14.41 -@interface MYKey (Expert)
   14.42 +/** @name Expert
   14.43 + *  Advanced methods. 
   14.44 + */
   14.45 +//@{
   14.46  
   14.47  /** Creates a MYKey object for an existing Keychain key reference.
   14.48      This is abstract -- must be called on a MYSymmetricKey or MYPublicKey, as appropriate. */
   14.49 @@ -65,12 +81,26 @@
   14.50  /** The underlying CSSM_KEY structure; used with low-level crypto APIs. */
   14.51  @property (readonly) const struct cssm_key* cssmKey;
   14.52  
   14.53 -/** Converts the key into a data blob in one of several standard formats, suitable for storing in
   14.54 -    a file or sending over the network.
   14.55 -    @param format  The data format: kSecFormatOpenSSL, kSecFormatSSH, kSecFormatBSAFE or kSecFormatSSHv2.
   14.56 -    @param withPEM  YES if the data should be encoded in PEM format, which converts into short lines
   14.57 -        of printable ASCII characters, suitable for sending in email. */
   14.58 -- (NSData*) exportKeyInFormat: (SecExternalFormat)format withPEM: (BOOL)withPEM;
   14.59 +/** The underlying CSSM_CSP_HANDLE structure; used with low-level crypto APIs. */
   14.60 +@property (readonly) intptr_t /*CSSM_CSP_HANDLE*/ cssmCSPHandle;
   14.61 +
   14.62 +/** Gets CSSM authorization credentials for a specified operation, such as
   14.63 +    CSSM_ACL_AUTHORIZATION_ENCRYPT. This pointer is necessary for creating some CSSM operation
   14.64 +    contexts.
   14.65 +    @param operation  The type of operation you are going to perform (see the enum values in
   14.66 +            cssmType.h.)
   14.67 +    @param type  Specifies whether the operation should be allowed to present a UI. You'll usually
   14.68 +            want to pass kSecCredentialTypeDefault.
   14.69 +    @param outError  Will be set to point to an NSError on failure, or nil on success.
   14.70 +            Pass nil if you don't care about the specific error.
   14.71 +    @return  The access credentials, or NULL on failure. 
   14.72 +            This pointer is valid for as long as you have a reference
   14.73 +            to the key object. Do not free or delete it. */
   14.74 +- (const CSSM_ACCESS_CREDENTIALS*) cssmCredentialsForOperation: (CSSM_ACL_AUTHORIZATION_TAG)operation
   14.75 +                                                          type: (SecCredentialType)type
   14.76 +                                                         error: (NSError**)outError;
   14.77 +
   14.78  #endif
   14.79 +//@}
   14.80  
   14.81  @end
    15.1 --- a/MYKey.m	Sat Apr 04 22:56:13 2009 -0700
    15.2 +++ b/MYKey.m	Tue Apr 07 10:56:58 2009 -0700
    15.3 @@ -11,7 +11,7 @@
    15.4  #import "MYDigest.h"
    15.5  #import "MYErrorUtils.h"
    15.6  
    15.7 -#if !USE_IPHONE_API
    15.8 +#if !MYCRYPTO_USE_IPHONE_API
    15.9  
   15.10  
   15.11  #pragma mark -
   15.12 @@ -51,10 +51,32 @@
   15.13  
   15.14  - (const CSSM_KEY*) cssmKey {
   15.15      const CSSM_KEY *cssmKey = NULL;
   15.16 -    Assert(check(SecKeyGetCSSMKey(self.keyRef, &cssmKey), @"SecKeyGetCSSMKey"), @"Failed to get CSSM_KEY");
   15.17 +    Assert(check(SecKeyGetCSSMKey(self.keyRef, &cssmKey), @"SecKeyGetCSSMKey"), 
   15.18 +           @"Failed to get CSSM_KEY");
   15.19      return cssmKey;
   15.20  }
   15.21  
   15.22 +- (const CSSM_CSP_HANDLE) cssmCSPHandle {
   15.23 +    CSSM_CSP_HANDLE cspHandle = 0;
   15.24 +    Assert(check(SecKeyGetCSPHandle(self.keyRef, &cspHandle), @"SecKeyGetCSPHandle"),
   15.25 +           @"Failed to get CSSM_CSP_HANDLE");
   15.26 +    return cspHandle;
   15.27 +}
   15.28 +
   15.29 +- (const CSSM_ACCESS_CREDENTIALS*) cssmCredentialsForOperation: (CSSM_ACL_AUTHORIZATION_TAG)operation
   15.30 +                                                          type: (SecCredentialType)type
   15.31 +                                                         error: (NSError**)outError
   15.32 +{
   15.33 +    const CSSM_ACCESS_CREDENTIALS *credentials = NULL;
   15.34 +    OSStatus err = SecKeyGetCredentials(self.keyRef,
   15.35 +                                        operation,
   15.36 +                                        type,
   15.37 +                                        &credentials);
   15.38 +    if (!MYReturnError(outError, err,NSOSStatusErrorDomain, @"Couldn't get credentials for key"))
   15.39 +        return NULL;
   15.40 +    return credentials;
   15.41 +}
   15.42 +
   15.43  - (NSData*) exportKeyInFormat: (SecExternalFormat)format withPEM: (BOOL)withPEM {
   15.44      CFDataRef data = NULL;
   15.45      if (check(SecKeychainItemExport(self.keyRef, format, (withPEM ?kSecItemPemArmour :0), NULL, &data),
   15.46 @@ -111,8 +133,9 @@
   15.47      
   15.48      params->version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
   15.49      params->flags |= kSecKeyImportOnlyOne;
   15.50 +    params->keyAttributes |= CSSM_KEYATTR_EXTRACTABLE;
   15.51      if (keychain) {
   15.52 -        params->keyAttributes = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT;
   15.53 +        params->keyAttributes |= CSSM_KEYATTR_PERMANENT;
   15.54          if (type==kSecItemTypeSessionKey)
   15.55              params->keyUsage = CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT;
   15.56          else if (type==kSecItemTypePublicKey)
   15.57 @@ -132,7 +155,7 @@
   15.58  }    
   15.59  
   15.60  
   15.61 -#endif USE_IPHONE_API
   15.62 +#endif MYCRYPTO_USE_IPHONE_API
   15.63  
   15.64  
   15.65  
    16.1 --- a/MYKeyPair-iPhone.m	Sat Apr 04 22:56:13 2009 -0700
    16.2 +++ b/MYKeyPair-iPhone.m	Tue Apr 07 10:56:58 2009 -0700
    16.3 @@ -12,13 +12,13 @@
    16.4  #import <CommonCrypto/CommonDigest.h>
    16.5  
    16.6  
    16.7 -#if USE_IPHONE_API
    16.8 +#if MYCRYPTO_USE_IPHONE_API
    16.9  
   16.10  
   16.11  @implementation MYKeyPair
   16.12  
   16.13  
   16.14 -+ (MYKeyPair*) _generateKeyPairOfSize: (unsigned)keySize inKeychain: (MYKeychain*)keychain {
   16.15 ++ (MYKeyPair*) _generateRSAKeyPairOfSize: (unsigned)keySize inKeychain: (MYKeychain*)keychain {
   16.16      Assert( keySize == 512 || keySize == 1024 || keySize == 2048, @"Unsupported key size %u", keySize );
   16.17      SecKeyRef pubKey=NULL, privKey=NULL;
   16.18      OSStatus err;
   16.19 @@ -82,4 +82,4 @@
   16.20  @end
   16.21  
   16.22  
   16.23 -#endif USE_IPHONE_API
   16.24 +#endif MYCRYPTO_USE_IPHONE_API
    17.1 --- a/MYKeyPair.h	Sat Apr 04 22:56:13 2009 -0700
    17.2 +++ b/MYKeyPair.h	Tue Apr 07 10:56:58 2009 -0700
    17.3 @@ -30,7 +30,13 @@
    17.4      verifySignature:ofData: method. */
    17.5  - (NSData*) signData: (NSData*)data;
    17.6  
    17.7 +
    17.8 +/** @name Mac-Only
    17.9 + *  Functionality not available on iPhone. 
   17.10 + */
   17.11 +//@{
   17.12  #if !TARGET_OS_IPHONE
   17.13 +
   17.14  /** Exports the private key as a data blob, so that it can be stored as a backup, or transferred
   17.15      to another computer. Since the key is sensitive, it must be exported in encrypted form
   17.16      using a user-chosen passphrase. This method will display a standard alert panel, run by
   17.17 @@ -39,21 +45,7 @@
   17.18      (This is a convenient shorthand for the full exportPrivateKeyInFormat... method.
   17.19      It uses OpenSSL format, wrapped with PEM, and a default title and prompt for the alert.) */
   17.20  - (NSData*) exportPrivateKey;
   17.21 -#endif
   17.22  
   17.23 -@end
   17.24 -
   17.25 -
   17.26 -
   17.27 -@interface MYKeyPair (Expert)
   17.28 -
   17.29 -/** Creates a MYKeyPair object from existing Keychain key references. */
   17.30 -- (id) initWithPublicKeyRef: (SecKeyRef)publicKey privateKeyRef: (SecKeyRef)privateKey;
   17.31 -
   17.32 -/** The underlying Keychain key reference for the private key. */
   17.33 -@property (readonly) SecKeyRef privateKeyRef;
   17.34 -
   17.35 -#if !TARGET_OS_IPHONE
   17.36  /** Exports the private key as a data blob, so that it can be stored as a backup, or transferred
   17.37      to another computer. Since the key is sensitive, it must be exported in encrypted form
   17.38      using a user-chosen passphrase. This method will display a standard alert panel, run by
   17.39 @@ -66,8 +58,24 @@
   17.40      @param prompt  An optional prompt message to display in the alert panel. */
   17.41  - (NSData*) exportPrivateKeyInFormat: (SecExternalFormat)format
   17.42                               withPEM: (BOOL)withPEM
   17.43 -                          alertTitle: (NSString*)title
   17.44 +                          alertTitle: (NSString*)alertTitle
   17.45                           alertPrompt: (NSString*)prompt;
   17.46 +
   17.47  #endif
   17.48 +//@}
   17.49 +
   17.50 +
   17.51 +/** @name Expert
   17.52 + *  Advanced functionality.
   17.53 + */
   17.54 +//@{
   17.55 +
   17.56 +/** Creates a MYKeyPair object from existing Keychain key references. */
   17.57 +- (id) initWithPublicKeyRef: (SecKeyRef)publicKey privateKeyRef: (SecKeyRef)privateKey;
   17.58 +
   17.59 +/** The underlying Keychain key reference for the private key. */
   17.60 +@property (readonly) SecKeyRef privateKeyRef;
   17.61 +
   17.62 +//@}
   17.63  
   17.64  @end
    18.1 --- a/MYKeyPair.m	Sat Apr 04 22:56:13 2009 -0700
    18.2 +++ b/MYKeyPair.m	Tue Apr 07 10:56:58 2009 -0700
    18.3 @@ -10,7 +10,7 @@
    18.4  #import "MYCrypto_Private.h"
    18.5  #import <CommonCrypto/CommonDigest.h>
    18.6  
    18.7 -#if !USE_IPHONE_API
    18.8 +#if !MYCRYPTO_USE_IPHONE_API
    18.9  
   18.10  
   18.11  #pragma mark -
   18.12 @@ -19,11 +19,14 @@
   18.13  
   18.14  
   18.15  + (MYKeyPair*) _generateRSAKeyPairOfSize: (unsigned)keySize
   18.16 -                            inKeychain: (SecKeychainRef)keychain {
   18.17 +                            inKeychain: (MYKeychain*)keychain {
   18.18      Assert( keySize == 512 || keySize == 1024 || keySize == 2048, @"Unsupported key size %u", keySize );
   18.19      SecKeyRef pubKey=NULL, privKey=NULL;
   18.20      OSStatus err;
   18.21 -    err = SecKeyCreatePair(keychain, CSSM_ALGID_RSA, keySize, 0LL,
   18.22 +    err = SecKeyCreatePair(keychain.keychainRefOrDefault,
   18.23 +                           CSSM_ALGID_RSA, 
   18.24 +                           keySize,
   18.25 +                           0LL,
   18.26                             CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_VERIFY,        // public key
   18.27                             CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT,
   18.28                             CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_SIGN,          // private key
   18.29 @@ -103,6 +106,12 @@
   18.30      [super dealloc];
   18.31  }
   18.32  
   18.33 +- (void) finalize
   18.34 +{
   18.35 +    if (_privateKey) CFRelease(_privateKey);
   18.36 +    [super finalize];
   18.37 +}
   18.38 +
   18.39  
   18.40  - (NSUInteger)hash {
   18.41      // Ensure that a KeyPair doesn't hash the same as its corresponding PublicKey:
   18.42 @@ -209,7 +218,7 @@
   18.43  @end
   18.44  
   18.45  
   18.46 -#endif !USE_IPHONE_API
   18.47 +#endif !MYCRYPTO_USE_IPHONE_API
   18.48  
   18.49  
   18.50  
    19.1 --- a/MYKeychain-iPhone.m	Sat Apr 04 22:56:13 2009 -0700
    19.2 +++ b/MYKeychain-iPhone.m	Tue Apr 07 10:56:58 2009 -0700
    19.3 @@ -9,7 +9,7 @@
    19.4  #import "MYCrypto_Private.h"
    19.5  #import "MYDigest.h"
    19.6  
    19.7 -#if USE_IPHONE_API
    19.8 +#if MYCRYPTO_USE_IPHONE_API
    19.9  
   19.10  
   19.11  @interface MYKeyEnumerator : NSEnumerator
   19.12 @@ -208,8 +208,8 @@
   19.13      if (!_results)
   19.14          return nil;
   19.15      MYKeychainItem *next = nil;
   19.16 -    for (; next==nil && _index < CFArrayGetCount(_results); _index++) {
   19.17 -        CFTypeRef found = CFArrayGetValueAtIndex(_results, _index); 
   19.18 +    while (next==nil && _index < CFArrayGetCount(_results)) {
   19.19 +        CFTypeRef found = CFArrayGetValueAtIndex(_results, _index++); 
   19.20          if (_itemClass == kSecAttrKeyClassPrivate) {
   19.21              MYSHA1Digest *digest = [MYPublicKey _digestOfKey: (SecKeyRef)found];
   19.22              if (digest) {
   19.23 @@ -224,16 +224,12 @@
   19.24                      //Warn(@"Couldn't find matching public key for private key!");
   19.25                  }
   19.26              }
   19.27 -            break;
   19.28          } else if (_itemClass == kSecAttrKeyClassPublic) {
   19.29              next = [[[MYPublicKey alloc] initWithKeyRef: (SecKeyRef)found] autorelease];
   19.30 -            break;
   19.31          } else if (_itemClass == kSecAttrKeyClassSymmetric) {
   19.32              next = [[[MYSymmetricKey alloc] initWithKeyRef: (SecKeyRef)found] autorelease];
   19.33 -            break;
   19.34          } else if (_itemClass == kSecClassCertificate) {
   19.35              next = [[[MYCertificate alloc] initWithCertificateRef: (SecCertificateRef)found] autorelease];
   19.36 -            break;
   19.37          }
   19.38          CFRelease(found);
   19.39      }
   19.40 @@ -243,7 +239,7 @@
   19.41  
   19.42  @end
   19.43  
   19.44 -#endif USE_IPHONE_API
   19.45 +#endif MYCRYPTO_USE_IPHONE_API
   19.46  
   19.47  
   19.48  /*
    20.1 --- a/MYKeychain.h	Sat Apr 04 22:56:13 2009 -0700
    20.2 +++ b/MYKeychain.h	Tue Apr 07 10:56:58 2009 -0700
    20.3 @@ -7,6 +7,7 @@
    20.4  //
    20.5  
    20.6  #import <Foundation/Foundation.h>
    20.7 +#import "MYCryptoConfig.h"
    20.8  @class MYSymmetricKey, MYPublicKey, MYKeyPair, MYCertificate, MYSHA1Digest;
    20.9  
   20.10  
   20.11 @@ -15,7 +16,7 @@
   20.12  @interface MYKeychain : NSObject 
   20.13  {
   20.14      @private
   20.15 -#if !TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
   20.16 +#if !MYCRYPTO_USE_IPHONE_API
   20.17      SecKeychainRef _keychain;
   20.18  #endif
   20.19  }
   20.20 @@ -40,6 +41,10 @@
   20.21  
   20.22  #pragma mark PUBLIC KEYS:
   20.23  
   20.24 +/** Imports a public key into the keychain, given its external representation
   20.25 +    (as generated by -[MYPublicKey keyData].) */
   20.26 +- (MYPublicKey*) importPublicKey: (NSData*)keyData;
   20.27 +
   20.28  /** Looks up an existing public key with the given digest.
   20.29      Returns nil if there is no such key in the keychain.
   20.30      (This method does not look for keys embedded in certificates, only 'bare' keys.) */
   20.31 @@ -49,11 +54,10 @@
   20.32      (This method does not find keys embedded in certificates, only 'bare' keys.) */
   20.33  - (NSEnumerator*) enumeratePublicKeys;
   20.34  
   20.35 -/** Imports a public key into the keychain, given its external representation
   20.36 -    (as generated by -[MYPublicKey keyData].) */
   20.37 -- (MYPublicKey*) importPublicKey: (NSData*)keyData;
   20.38 +#pragma mark CERTIFICATES:
   20.39  
   20.40 -#pragma mark CERTIFICATES:
   20.41 +/** Imports a certificate into the keychain, given its external representation. */
   20.42 +- (MYCertificate*) importCertificate: (NSData*)data;
   20.43  
   20.44  /** Looks up an existing certificate with the given public-key digest.
   20.45      Returns nil if there is no such certificate in the keychain.
   20.46 @@ -63,20 +67,8 @@
   20.47  /** Enumerates all certificates in the keychain. */
   20.48  - (NSEnumerator*) enumerateCertificates;
   20.49  
   20.50 -/** Imports a certificate into the keychain, given its external representation. */
   20.51 -- (MYCertificate*) importCertificate: (NSData*)data;
   20.52 -
   20.53  #pragma mark KEY-PAIRS:
   20.54  
   20.55 -/** Looks up an existing key-pair whose public key has the given digest.
   20.56 -    Returns nil if there is no such key-pair in the keychain.
   20.57 -    (This method does not look for public keys embedded in certificates, only 'bare' keys.) */
   20.58 -- (MYKeyPair*) keyPairWithDigest: (MYSHA1Digest*)pubKeyDigest;
   20.59 -
   20.60 -/** Enumerates all key-pairs in the keychain.
   20.61 -    (This method does not find keys embedded in certificates, only 'bare' keys.) */
   20.62 -- (NSEnumerator*) enumerateKeyPairs;
   20.63 -
   20.64  /** Generates a new RSA key-pair and adds both keys to the keychain.
   20.65      This is very slow -- it may take seconds, depending on the key size, CPU speed,
   20.66      and other random factors. You may want to start some kind of progress indicator before
   20.67 @@ -87,19 +79,63 @@
   20.68          to stay secure for years; or you could use 4096 if you're extremely paranoid. */
   20.69  - (MYKeyPair*) generateRSAKeyPairOfSize: (unsigned)keySize;
   20.70  
   20.71 -@end
   20.72 +/** Looks up an existing key-pair whose public key has the given digest.
   20.73 +    Returns nil if there is no such key-pair in the keychain.
   20.74 +    (This method does not look for public keys embedded in certificates, only 'bare' keys.) */
   20.75 +- (MYKeyPair*) keyPairWithDigest: (MYSHA1Digest*)pubKeyDigest;
   20.76  
   20.77 -
   20.78 +/** Enumerates all key-pairs in the keychain.
   20.79 +    (This method does not find keys embedded in certificates, only 'bare' keys.) */
   20.80 +- (NSEnumerator*) enumerateKeyPairs;
   20.81  
   20.82  
   20.83  #pragma mark -
   20.84  #pragma mark METHODS NOT SUPPORTED ON IPHONE:
   20.85  
   20.86  
   20.87 +/** @name Mac-Only
   20.88 + *  Functionality not available on iPhone. 
   20.89 + */
   20.90 +//@{
   20.91  #if !TARGET_OS_IPHONE
   20.92  
   20.93 -/** Keychain functionality that's not supported on iPhone. */
   20.94 -@interface MYKeychain (MacOnly)
   20.95 +/** Enumerates all public keys in the keychain that have the given alias string. */
   20.96 +- (NSEnumerator*) symmetricKeysWithAlias: (NSString*)alias;
   20.97 +
   20.98 +/** Enumerates all public keys in the keychain that have the given alias string. */
   20.99 +- (NSEnumerator*) publicKeysWithAlias: (NSString*)alias;
  20.100 +
  20.101 +/** Imports a key-pair into the keychain, given the external representations
  20.102 +    of both the public and private keys.
  20.103 +    Since the private key data is wrapped (encrypted), the Security agent will prompt the user to enter
  20.104 +    the passphrase. */
  20.105 +- (MYKeyPair*) importPublicKey: (NSData*)pubKeyData 
  20.106 +                    privateKey: (NSData*)privKeyData;
  20.107 +
  20.108 +/** Imports a key-pair into the keychain, given the external representations
  20.109 +    of both the public and private keys.
  20.110 +    Since the private key data is wrapped (encrypted), the Security agent will prompt the user to enter
  20.111 +    the passphrase. You can specify the title and prompt message for this alert panel. */
  20.112 +- (MYKeyPair*) importPublicKey: (NSData*)pubKeyData 
  20.113 +                    privateKey: (NSData*)privKeyData
  20.114 +                    alertTitle: (NSString*)title
  20.115 +                   alertPrompt: (NSString*)prompt;
  20.116 +
  20.117 +/** Imports a certificate into the keychain, given its external representation. */
  20.118 +- (MYCertificate*) importCertificate: (NSData*)data
  20.119 +                                type: (CSSM_CERT_TYPE) type
  20.120 +                            encoding: (CSSM_CERT_ENCODING) encoding;
  20.121 +
  20.122 +//@}
  20.123 +#endif
  20.124 +
  20.125 +
  20.126 +
  20.127 +/** @name Expert (Mac-Only)
  20.128 + *  Advanced functionality, not available on iPhone. 
  20.129 + */
  20.130 +//@{
  20.131 +#if !TARGET_OS_IPHONE
  20.132  
  20.133  /** Creates a MYKeychain for an existing SecKeychainRef. */
  20.134  - (id) initWithKeychainRef: (SecKeychainRef)keychainRef;
  20.135 @@ -131,35 +167,8 @@
  20.136  /** The underlying CSSM storage handle; used when calling CSSM APIs. */
  20.137  @property (readonly) CSSM_CSP_HANDLE CSPHandle;
  20.138  
  20.139 -
  20.140 -/** Enumerates all public keys in the keychain that have the given alias string. */
  20.141 -- (NSEnumerator*) symmetricKeysWithAlias: (NSString*)alias;
  20.142 -
  20.143 -/** Enumerates all public keys in the keychain that have the given alias string. */
  20.144 -- (NSEnumerator*) publicKeysWithAlias: (NSString*)alias;
  20.145 -
  20.146 -
  20.147 -/** Imports a certificate into the keychain, given its external representation. */
  20.148 -- (MYCertificate*) importCertificate: (NSData*)data
  20.149 -                                type: (CSSM_CERT_TYPE) type
  20.150 -                            encoding: (CSSM_CERT_ENCODING) encoding;
  20.151 -
  20.152 -/** Imports a key-pair into the keychain, given the external representations
  20.153 -    of both the public and private keys.
  20.154 -    Since the private key data is wrapped (encrypted), the Security agent will prompt the user to enter
  20.155 -    the passphrase. */
  20.156 -- (MYKeyPair*) importPublicKey: (NSData*)pubKeyData 
  20.157 -                    privateKey: (NSData*)privKeyData;
  20.158 -
  20.159 -/** Imports a key-pair into the keychain, given the external representations
  20.160 -    of both the public and private keys.
  20.161 -    Since the private key data is wrapped (encrypted), the Security agent will prompt the user to enter
  20.162 -    the passphrase. You can specify the title and prompt message for this alert panel. */
  20.163 -- (MYKeyPair*) importPublicKey: (NSData*)pubKeyData 
  20.164 -                    privateKey: (NSData*)privKeyData
  20.165 -                    alertTitle: (NSString*)title
  20.166 -                   alertPrompt: (NSString*)prompt;
  20.167 +#endif
  20.168 +//@}
  20.169  
  20.170  @end
  20.171  
  20.172 -#endif
    21.1 --- a/MYKeychain.m	Sat Apr 04 22:56:13 2009 -0700
    21.2 +++ b/MYKeychain.m	Tue Apr 07 10:56:58 2009 -0700
    21.3 @@ -10,7 +10,7 @@
    21.4  #import "MYCrypto_Private.h"
    21.5  #import "MYDigest.h"
    21.6  
    21.7 -#if !USE_IPHONE_API
    21.8 +#if !MYCRYPTO_USE_IPHONE_API
    21.9  
   21.10  
   21.11  @interface MYKeyEnumerator : NSEnumerator
   21.12 @@ -97,6 +97,12 @@
   21.13      [super dealloc];
   21.14  }
   21.15  
   21.16 +- (void) finalize
   21.17 +{
   21.18 +    if (_keychain) CFRelease(_keychain);
   21.19 +    [super finalize];
   21.20 +}
   21.21 +
   21.22  
   21.23  + (MYKeychain*) allKeychains
   21.24  {
   21.25 @@ -321,7 +327,7 @@
   21.26  }
   21.27  
   21.28  - (MYKeyPair*) generateRSAKeyPairOfSize: (unsigned)keySize {
   21.29 -    return [MYKeyPair _generateRSAKeyPairOfSize: keySize inKeychain: self.keychainRefOrDefault];
   21.30 +    return [MYKeyPair _generateRSAKeyPairOfSize: keySize inKeychain: self];
   21.31  }
   21.32  
   21.33  
   21.34 @@ -367,6 +373,13 @@
   21.35      [super dealloc];
   21.36  }
   21.37  
   21.38 +- (void) finalize
   21.39 +{
   21.40 +    [_keychain release];
   21.41 +    if (_search) CFRelease(_search);
   21.42 +    [super finalize];
   21.43 +}
   21.44 +
   21.45  
   21.46  - (id) nextObject {
   21.47      if (!_search)
   21.48 @@ -416,7 +429,7 @@
   21.49  @end
   21.50  
   21.51  
   21.52 -#endif !USE_IPHONE_API
   21.53 +#endif !MYCRYPTO_USE_IPHONE_API
   21.54  
   21.55  
   21.56  
    22.1 --- a/MYKeychainItem.h	Sat Apr 04 22:56:13 2009 -0700
    22.2 +++ b/MYKeychainItem.h	Tue Apr 07 10:56:58 2009 -0700
    22.3 @@ -8,6 +8,7 @@
    22.4  
    22.5  #import <Foundation/Foundation.h>
    22.6  #import <Security/Security.h>
    22.7 +#import "MYCryptoConfig.h"
    22.8  @class MYKeychain;
    22.9  
   22.10  
   22.11 @@ -15,7 +16,7 @@
   22.12  extern NSString* const MYCSSMErrorDomain;
   22.13  
   22.14  
   22.15 -#if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
   22.16 +#if MYCRYPTO_USE_IPHONE_API
   22.17  typedef CFTypeRef MYKeychainItemRef;
   22.18  #else
   22.19  typedef SecKeychainItemRef MYKeychainItemRef;
    23.1 --- a/MYKeychainItem.m	Sat Apr 04 22:56:13 2009 -0700
    23.2 +++ b/MYKeychainItem.m	Tue Apr 07 10:56:58 2009 -0700
    23.3 @@ -37,6 +37,12 @@
    23.4      [super dealloc];
    23.5  }
    23.6  
    23.7 +- (void) finalize
    23.8 +{
    23.9 +    if (_itemRef) CFRelease(_itemRef);
   23.10 +    [super finalize];
   23.11 +}
   23.12 +
   23.13  - (id) copyWithZone: (NSZone*)zone {
   23.14      // As keys are immutable, it's not necessary to make copies of them. This makes it more efficient
   23.15      // to use instances as NSDictionary keys or store them in NSSets.
   23.16 @@ -63,7 +69,7 @@
   23.17      return $array((id)_itemRef);
   23.18  }
   23.19  
   23.20 -#if USE_IPHONE_API
   23.21 +#if MYCRYPTO_USE_IPHONE_API
   23.22  - (CFDictionaryRef) asQuery {
   23.23      return (CFDictionaryRef) $dict( {(id)kSecClass, (id)kSecClassKey},//FIX
   23.24                                      {(id)kSecMatchItemList, self._itemList} );
   23.25 @@ -72,7 +78,7 @@
   23.26  
   23.27  
   23.28  - (MYKeychain*) keychain {
   23.29 -#if USE_IPHONE_API
   23.30 +#if MYCRYPTO_USE_IPHONE_API
   23.31      return [MYKeychain defaultKeychain];
   23.32  #else
   23.33      MYKeychain *keychain = nil;
   23.34 @@ -88,7 +94,7 @@
   23.35  }
   23.36  
   23.37  - (BOOL) removeFromKeychain {
   23.38 -#if USE_IPHONE_API
   23.39 +#if MYCRYPTO_USE_IPHONE_API
   23.40      return check(SecItemDelete(self.asQuery), @"SecItemDelete");
   23.41  #else
   23.42      return check(SecKeychainItemDelete((SecKeychainItemRef)_itemRef), @"SecKeychainItemDelete");
   23.43 @@ -102,7 +108,7 @@
   23.44  
   23.45  - (NSData*) _getContents: (OSStatus*)outError {
   23.46      NSData *contents = nil;
   23.47 -#if USE_IPHONE_API
   23.48 +#if MYCRYPTO_USE_IPHONE_API
   23.49  #else
   23.50  	UInt32 length = 0;
   23.51      void *bytes = NULL;
   23.52 @@ -117,7 +123,7 @@
   23.53  
   23.54  + (NSData*) _getAttribute: (SecKeychainAttrType)attr ofItem: (MYKeychainItemRef)item {
   23.55      NSData *value = nil;
   23.56 -#if USE_IPHONE_API
   23.57 +#if MYCRYPTO_USE_IPHONE_API
   23.58      NSDictionary *info = $dict( {(id)kSecClass, (id)kSecClassKey},
   23.59                                  {(id)kSecMatchItemList, $array((id)item)},
   23.60                                  {(id)kSecReturnAttributes, $true} );
   23.61 @@ -171,7 +177,7 @@
   23.62  + (BOOL) _setAttribute: (SecKeychainAttrType)attr ofItem: (MYKeychainItemRef)item
   23.63             stringValue: (NSString*)stringValue
   23.64  {
   23.65 -#if USE_IPHONE_API
   23.66 +#if MYCRYPTO_USE_IPHONE_API
   23.67      id value = stringValue ?(id)stringValue :(id)[NSNull null];
   23.68      NSDictionary *query = $dict({(id)kSecClass, (id)kSecClassKey},
   23.69                                  {(id)kSecAttrKeyType, (id)attr},
   23.70 @@ -200,7 +206,7 @@
   23.71  
   23.72  BOOL check(OSStatus err, NSString *what) {
   23.73      if (err) {
   23.74 -#if !USE_IPHONE_API
   23.75 +#if !MYCRYPTO_USE_IPHONE_API
   23.76          if (err < -2000000000)
   23.77              return checkcssm(err,what);
   23.78  #endif
   23.79 @@ -210,7 +216,7 @@
   23.80          return YES;
   23.81  }
   23.82  
   23.83 -#if !USE_IPHONE_API
   23.84 +#if !MYCRYPTO_USE_IPHONE_API
   23.85  BOOL checkcssm(CSSM_RETURN err, NSString *what) {
   23.86      if (err != CSSM_OK) {
   23.87          Warn(@"MYCrypto error, %@: %@", what, MYErrorName(MYCSSMErrorDomain,err));
    24.1 --- a/MYPublicKey-iPhone.m	Sat Apr 04 22:56:13 2009 -0700
    24.2 +++ b/MYPublicKey-iPhone.m	Tue Apr 07 10:56:58 2009 -0700
    24.3 @@ -9,7 +9,7 @@
    24.4  #import "MYPublicKey.h"
    24.5  #import "MYCrypto_Private.h"
    24.6  
    24.7 -#if USE_IPHONE_API
    24.8 +#if MYCRYPTO_USE_IPHONE_API
    24.9  
   24.10  #import "MYDigest.h"
   24.11  #import "MYErrorUtils.h"
   24.12 @@ -36,18 +36,22 @@
   24.13  }
   24.14  
   24.15  
   24.16 -
   24.17 -- (MYSHA1Digest*) publicKeyDigest {
   24.18 -    NSData *digestData = [self _attribute: kSecAttrApplicationLabel];
   24.19 ++ (MYSHA1Digest*) _digestOfKey: (SecKeyRef)key {
   24.20 +    NSData *digestData = [MYKeychainItem _getAttribute: kSecAttrApplicationLabel ofItem: key];
   24.21      if (digestData)
   24.22          return (MYSHA1Digest*) [MYSHA1Digest digestFromDigestData: digestData];
   24.23      else {
   24.24 -        Warn(@"MYKeyPair: public key didn't have digest attribute");
   24.25 +        Warn(@"MYKeyPair: public keyref %p didn't have digest attribute", key);
   24.26          return nil;
   24.27      }
   24.28  }
   24.29  
   24.30  
   24.31 +- (MYSHA1Digest*) publicKeyDigest {
   24.32 +    return [[self class] _digestOfKey: self.keyRef];
   24.33 +}
   24.34 +
   24.35 +
   24.36  - (NSData*) encryptData: (NSData*)data {
   24.37      return _crypt(self.keyRef,data,kCCEncrypt);
   24.38  }
   24.39 @@ -94,4 +98,4 @@
   24.40          return [NSData dataWithBytesNoCopy: outputBuf length: outputLength freeWhenDone: YES];
   24.41  }
   24.42  
   24.43 -#endif USE_IPHONE_API
   24.44 +#endif MYCRYPTO_USE_IPHONE_API
    25.1 --- a/MYPublicKey.m	Sat Apr 04 22:56:13 2009 -0700
    25.2 +++ b/MYPublicKey.m	Tue Apr 07 10:56:58 2009 -0700
    25.3 @@ -9,7 +9,7 @@
    25.4  #import "MYPublicKey.h"
    25.5  #import "MYCrypto_Private.h"
    25.6  
    25.7 -#if !USE_IPHONE_API
    25.8 +#if !MYCRYPTO_USE_IPHONE_API
    25.9  
   25.10  #import "MYDigest.h"
   25.11  #import "MYErrorUtils.h"
   25.12 @@ -185,7 +185,7 @@
   25.13          return 0;
   25.14  }
   25.15  
   25.16 -#endif !USE_IPHONE_API
   25.17 +#endif !MYCRYPTO_USE_IPHONE_API
   25.18  
   25.19  
   25.20  
    26.1 --- a/MYSymmetricKey.h	Sat Apr 04 22:56:13 2009 -0700
    26.2 +++ b/MYSymmetricKey.h	Tue Apr 07 10:56:58 2009 -0700
    26.3 @@ -25,4 +25,7 @@
    26.4  /** The key's algorithm. */
    26.5  @property (readonly) CCAlgorithm algorithm;
    26.6  
    26.7 +/** The key's size/length, in bits. */
    26.8 +@property (readonly) unsigned keySizeInBits;
    26.9 +
   26.10  @end
    27.1 --- a/MYSymmetricKey.m	Sat Apr 04 22:56:13 2009 -0700
    27.2 +++ b/MYSymmetricKey.m	Tue Apr 07 10:56:58 2009 -0700
    27.3 @@ -11,7 +11,7 @@
    27.4  #import "MYCrypto_Private.h"
    27.5  
    27.6  
    27.7 -#if USE_IPHONE_API
    27.8 +#if MYCRYPTO_USE_IPHONE_API
    27.9  typedef uint32_t CSSM_ALGORITHMS;
   27.10  enum {
   27.11  // Taken from cssmtype.h in OS X 10.5 SDK:
   27.12 @@ -32,6 +32,8 @@
   27.13      CSSM_ALGID_AES, CSSM_ALGID_DES, CSSM_ALGID_3DES_3KEY, CSSM_ALGID_CAST, CSSM_ALGID_RC4
   27.14  };
   27.15  
   27.16 +static const char *kCCAlgorithmNames[] = {"AES", "DES", "DES^3", "CAST", "RC4"};
   27.17 +
   27.18  
   27.19  #pragma mark -
   27.20  @implementation MYSymmetricKey
   27.21 @@ -44,21 +46,41 @@
   27.22      Assert(algorithm <= kCCAlgorithmRC4);
   27.23      Assert(keyData);
   27.24      SecKeyRef keyRef = NULL;
   27.25 -#if USE_IPHONE_API
   27.26 -    unsigned keySizeInBits = keyData.length / 8;
   27.27 +#if MYCRYPTO_USE_IPHONE_API
   27.28 +    NSNumber *keySizeInBits = [NSNumber numberWithUnsignedInt: keyData.length * 8];
   27.29      NSDictionary *keyAttrs = $dict( {(id)kSecClass, (id)kSecClassKey},
   27.30 -                                    {(id)kSecAttrKeyClass, (id)kSecAttrKeyClassSymmetric},
   27.31 -                                    {(id)kSecAttrKeyType, $object(kCSSMAlgorithms[algorithm])},
   27.32 -                                    {(id)kSecAttrKeySizeInBits, $object(keySizeInBits)},
   27.33 -                                    {(id)kSecAttrEffectiveKeySize, $object(keySizeInBits)},
   27.34 +                                    //{(id)kSecAttrKeyClass, (id)kSecAttrKeyClassSymmetric},
   27.35 +                                    {(id)kSecAttrKeyType, [NSNumber numberWithUnsignedInt: kCSSMAlgorithms[algorithm]]},
   27.36 +                                    {(id)kSecAttrKeySizeInBits, keySizeInBits},
   27.37 +                                    {(id)kSecAttrEffectiveKeySize, keySizeInBits},
   27.38                                      {(id)kSecAttrIsPermanent, keychain ?$true :$false},
   27.39 -                                    {(id)kSecValueData, keyData} );
   27.40 +                                    {(id)kSecAttrCanEncrypt, $true},
   27.41 +                                    {(id)kSecAttrCanDecrypt, $true},
   27.42 +                                    {(id)kSecAttrCanWrap, $false},
   27.43 +                                    {(id)kSecAttrCanUnwrap, $false},
   27.44 +                                    {(id)kSecAttrCanDerive, $false},
   27.45 +                                    {(id)kSecAttrCanSign, $false},
   27.46 +                                    {(id)kSecAttrCanVerify, $false},
   27.47 +                                    {(id)kSecValueData, keyData},
   27.48 +    //{(id)kSecAttrApplicationTag, [@"foo" dataUsingEncoding: NSUTF8StringEncoding]}, //TEMP
   27.49 +                                    {(id)kSecReturnPersistentRef, $true});
   27.50      if (!check(SecItemAdd((CFDictionaryRef)keyAttrs, (CFTypeRef*)&keyRef), @"SecItemAdd")) {
   27.51          [self release];
   27.52          return nil;
   27.53      }
   27.54 +    Log(@"SecItemAdd returned %@", keyRef);//TEMP
   27.55 +    Assert(keyRef, @"SecItemAdd didn't return anything");
   27.56  #else
   27.57      Assert(NO,@"Unimplemented"); //FIX
   27.58 +    /* The technique below doesn't work, because there's no way to tell SecKeychainItemImport
   27.59 +       what algorithm to use when importing a raw key. Still looking for a solution... --jpa 4/2009
   27.60 +    SecKeyImportExportParameters params = {};
   27.61 +    keyRef = importKey(keyData, kSecItemTypeSessionKey, keychain.keychainRefOrDefault, &params);
   27.62 +    if (!keyRef) {
   27.63 +        [self release];
   27.64 +        return nil;
   27.65 +    }
   27.66 +     */
   27.67  #endif
   27.68      self = [self initWithKeyRef: keyRef];
   27.69      CFRelease(keyRef);
   27.70 @@ -75,8 +97,8 @@
   27.71                                        algorithm: (CCAlgorithm)algorithm
   27.72                                       inKeychain: (MYKeychain*)keychain
   27.73  {
   27.74 -#if USE_IPHONE_API
   27.75 -    return [[[self alloc] _initWithKeyData: [MYCryptor randomKeyOfLength: (keySizeInBits+7)/8]
   27.76 +#if MYCRYPTO_USE_IPHONE_API
   27.77 +    return [[[self alloc] _initWithKeyData: [MYCryptor randomKeyOfLength: keySizeInBits]
   27.78                                   algorithm: algorithm
   27.79                                  inKeychain: keychain]
   27.80                      autorelease];
   27.81 @@ -106,9 +128,28 @@
   27.82  }
   27.83  
   27.84  
   27.85 +#if !TARGET_OS_IPHONE
   27.86 +- (NSData*) exportKeyInFormat: (SecExternalFormat)format
   27.87 +                      withPEM: (BOOL)withPEM
   27.88 +{
   27.89 +    SecKeyImportExportParameters params = {
   27.90 +        .version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION,
   27.91 +        .flags = kSecKeySecurePassphrase,
   27.92 +    };
   27.93 +    CFDataRef data = NULL;
   27.94 +    if (check(SecKeychainItemExport(self.keyRef,
   27.95 +                                    format, (withPEM ?kSecItemPemArmour :0), 
   27.96 +                                    &params, &data),
   27.97 +              @"SecKeychainItemExport"))
   27.98 +        return [(id)CFMakeCollectable(data) autorelease];
   27.99 +    else
  27.100 +        return nil;
  27.101 +}
  27.102 +#endif
  27.103 +
  27.104  
  27.105  - (SecExternalItemType) keyType {
  27.106 -#if USE_IPHONE_API
  27.107 +#if MYCRYPTO_USE_IPHONE_API
  27.108      return kSecAttrKeyClassSymmetric;
  27.109  #else
  27.110      return kSecItemTypeSessionKey;
  27.111 @@ -117,7 +158,7 @@
  27.112  
  27.113  - (CCAlgorithm) algorithm {
  27.114      CSSM_ALGORITHMS cssmAlg;
  27.115 -#if USE_IPHONE_API
  27.116 +#if MYCRYPTO_USE_IPHONE_API
  27.117      id keyType = [self _attribute: kSecAttrKeyType];
  27.118      Assert(keyType!=nil, @"Key has no kSecAttrKeyType");
  27.119      cssmAlg = [keyType unsignedIntValue];
  27.120 @@ -141,6 +182,31 @@
  27.121      }
  27.122  }
  27.123  
  27.124 +- (const char*) algorithmName {
  27.125 +    CCAlgorithm a = self.algorithm;
  27.126 +    if (a >= 0 && a <= kCCAlgorithmRC4)
  27.127 +        return kCCAlgorithmNames[a];
  27.128 +    else
  27.129 +        return "???";
  27.130 +}
  27.131 +
  27.132 +- (unsigned) keySizeInBits {
  27.133 +#if MYCRYPTO_USE_IPHONE_API
  27.134 +    id keySize = [self _attribute: kSecAttrKeySizeInBits];
  27.135 +    Assert(keySize!=nil, @"Key has no kSecAttrKeySizeInBits");
  27.136 +    return [keySize unsignedIntValue];
  27.137 +#else
  27.138 +    const CSSM_KEY *key = self.cssmKey;
  27.139 +    Assert(key);
  27.140 +    return key->KeyHeader.LogicalKeySizeInBits;
  27.141 +#endif
  27.142 +}
  27.143 +
  27.144 +
  27.145 +- (NSString*) description {
  27.146 +    return $sprintf(@"%@[%u-bit %s]", [self class], self.keySizeInBits, self.algorithmName);
  27.147 +}
  27.148 +
  27.149  
  27.150  - (NSData*) _cryptData: (NSData*)data operation: (CCOperation)op options: (CCOptions)options
  27.151  {
    28.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    28.2 +++ b/README.textile	Tue Apr 07 10:56:58 2009 -0700
    28.3 @@ -0,0 +1,75 @@
    28.4 +h1=. MYCrypto
    28.5 +
    28.6 +p=. Version 0.1 -- 6 April 2009
    28.7 +
    28.8 +p=. By "Jens Alfke":mailto:jens@mooseyard.com <br>
    28.9 +Based in part on code by Wade Tregaskis, <br>
   28.10 +and sample code by Apple Computer.
   28.11 +
   28.12 +h2. Introduction
   28.13 +
   28.14 +*MYCrypto* is a high-level cryptography API for Mac OS X and iPhone. It's an Objective-C wrapper around the system
   28.15 +"*Keychain*":http://developer.apple.com/documentation/Security/Conceptual/keychainServConcepts/02concepts/concepts.html#//apple_ref/doc/uid/TP30000897-CH204-TP9
   28.16 +and *CSSM* APIs, which are notoriously hard to use, as well as *CommonCrypto*, which is easier but quite limited.
   28.17 +
   28.18 +MYCrypto gives you easy object-oriented interfaces to
   28.19 +
   28.20 +* Symmmetric cryptography (session keys and password-based encryption)
   28.21 +* Asymmetric cryptography (public and private keys; digital signatures)
   28.22 +* Cryptographic digests/hashes (effectively-unique IDs for data)
   28.23 +* The Keychain (a secure, encrypted storage system for keys and passwords)
   28.24 +
   28.25 +h3. Requirements
   28.26 +
   28.27 +* Mac OS X 10.5 or later _[has been tested on 10.5.6]_
   28.28 +* iPhone OS 2.0 or later _[not yet tested; see Limitations section below]_
   28.29 +* iPhone Simulator, for iPhone OS 2.0 or later
   28.30 +* The MYUtilities library, which is used by MYCrypto.
   28.31 +* _Some understanding of security and cryptography on your part!_ Even with convenient APIs, cryptographic operations still require care and knowledge to be used safely. There are already too many "examples":http://en.wikipedia.org/wiki/Wired_Equivalent_Privacy#Flaws of insecure systems that were incorrectly assembled from secure primitives; don't add your app to that list. Please read a good overview like "??Practical Cryptography??":http://www.schneier.com/book-practical.html before attempting anything the least bit fancy.
   28.32 +
   28.33 +h3. Current Limitations
   28.34 +
   28.35 +h4. First off, the biggest caveat of all:
   28.36 +
   28.37 +* *MYCrypto 0.1 is new code and has not yet been used in any real projects. Expect bugs.* (I'm talking about my wrapper/glue code. The underlying cryptographic functionality provided by the OS is robust.)
   28.38 +
   28.39 +h4. Further issues with the 0.1 release:
   28.40 +
   28.41 +* *MYCrypto does not yet work on the iPhone.* It currently builds, but runs into problems at runtime. I'm currently trying to figure these out. (The iPhone OS Security APIs are very different from the Mac OS X ones, and I'm much less familiar with them.) However, it does work in the iPhone Simulator, which uses the OS X APIs.
   28.42 +* Exporting symmetric keys in wrapped (encrypted) form will fail. Currently they can be exported only as raw key data.
   28.43 +* Importing symmetric keys, in any form, will fail ... kind of a deal-breaker for using them across two computers, unfortunately.
   28.44 +
   28.45 +h4. Current API limitations, to be remedied in the future:
   28.46 +
   28.47 +* No API for accessing passwords; fortunately there are several other utility libraries that provide this. And if your code is doing cryptographic operations, it probably needs to store the keys themselves, not passwords.
   28.48 +* No bulk data encryption/decryption using public/private keys. MYKeyPair only does raw RSA crypto, which is slow and limited to small chunks of data.
   28.49 +* No creating or signing certificate-requests, or creating self-signed certificates.
   28.50 +* No evaluation of trust in certificates (i.e. SecTrust and related APIs.)
   28.51 +* Error reporting is too limited. Most methods indicate an error by returning nil, NULL or NO, but don't provide the standard "out" NSError parameter to provide more information. Expect the API to be refactored in the near future to remedy this.
   28.52 +
   28.53 +h2. Overview
   28.54 +
   28.55 +The class hierarchy of MYCrypto looks like this:
   28.56 +
   28.57 +* "MYKeychainItem":Documentation/html/interfaceMYKeychainItem.html
   28.58 +** "MYKey":Documentation/html/interfaceMYKey.html
   28.59 +*** "*MYSymmetricKey*":Documentation/html/interfaceMYSymmetricKey.html
   28.60 +*** "*MYPublicKey*":Documentation/html/interfaceMYPublicKey.html
   28.61 +**** "*MYKeyPair*":Documentation/html/interfaceMYKeyPair.html
   28.62 +*** "*MYCertificate*":Documentation/html/interfaceMYCertificate.html
   28.63 +* "MYDigest":Documentation/html/interfaceMYDigest.html
   28.64 +** "*MYSHA1Digest*":Documentation/html/interfaceMYSHA1Digest.html
   28.65 +** "*MYSHA256Digest*":Documentation/html/interfaceMYSHA256Digest.html
   28.66 +* "MYCryptor":Documentation/html/interfaceMYCryptor.html
   28.67 +
   28.68 +(*Boldface* classes are concrete, others are abstract.)
   28.69 +
   28.70 +h2. References
   28.71 +
   28.72 +* "??Security Overview??":http://developer.apple.com/documentation/Security/Conceptual/Security_Overview/Introduction/Introduction.html (Apple)
   28.73 +* "??Secure Coding Guide??":http://developer.apple.com/documentation/Security/Conceptual/SecureCodingGuide/Introduction.html (Apple)
   28.74 +
   28.75 +* "??Common Security: CDSA and CSSM, Version 2??":http://www.opengroup.org/publications/catalog/c914.htm (The Open Group)
   28.76 +
   28.77 +* "??Practical Cryptography??":http://www.schneier.com/book-practical.html (Ferguson and Schneier)
   28.78 +* "??The Devil's InfoSec Dictionary??":http://www.csoonline.com/article/220527/The_Devil_s_Infosec_Dictionary (CSO Online)
   28.79 \ No newline at end of file
    29.1 --- a/iPhone/MYCrypto_iPhoneAppDelegate.m	Sat Apr 04 22:56:13 2009 -0700
    29.2 +++ b/iPhone/MYCrypto_iPhoneAppDelegate.m	Tue Apr 07 10:56:58 2009 -0700
    29.3 @@ -19,11 +19,12 @@
    29.4  
    29.5      // Override point for customization after application launch
    29.6      [window makeKeyAndVisible];
    29.7 -    
    29.8 +    /*
    29.9      static const char *testArgs[] = {"MYCrypto", "Test_All"};
   29.10      int argc = 2;
   29.11      const char **argv = testArgs;
   29.12      RunTestCases(argc,argv);
   29.13 +     */
   29.14  }
   29.15  
   29.16  
    30.1 --- a/iPhone/MYCrypto_iPhone_main.m	Sat Apr 04 22:56:13 2009 -0700
    30.2 +++ b/iPhone/MYCrypto_iPhone_main.m	Tue Apr 07 10:56:58 2009 -0700
    30.3 @@ -9,14 +9,12 @@
    30.4  #import <UIKit/UIKit.h>
    30.5  
    30.6  int main(int argc, char *argv[]) {
    30.7 -    /*
    30.8      if (argc<2) {
    30.9          static char *testArgs[] = {"MYCrypto", "Test_All"};
   30.10          argc = 2;
   30.11          argv = testArgs;
   30.12      }
   30.13      RunTestCases(argc,(const char**)argv);
   30.14 -     */
   30.15      
   30.16      NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
   30.17      int retVal = UIApplicationMain(argc, argv, nil, nil);
    31.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    31.2 +++ b/maindocs.h	Tue Apr 07 10:56:58 2009 -0700
    31.3 @@ -0,0 +1,53 @@
    31.4 +//
    31.5 +//  maindocs.h
    31.6 +//  MYCrypto
    31.7 +//
    31.8 +//  Created by Jens Alfke on 4/06/09.
    31.9 +//  Copyright 2009 Jens Alfke. All rights reserved.
   31.10 +//
   31.11 +// This file just contains the Doxygen comments that generate the main (index.html) page content.
   31.12 +
   31.13 +
   31.14 +/*! \mainpage MYCrypto: Mooseyard Cryptography Library
   31.15 + 
   31.16 +    <center><b>By <a href="/Jens/">Jens Alfke</a></b></center>
   31.17 +
   31.18 +\section intro_sec Introduction
   31.19 + 
   31.20 +    MYCrypto is a set of Objective-C cryptography classes for Cocoa applications on Mac OS X and iPhone.
   31.21 +    
   31.22 +    <a href="annotated.html">Browse the class documentation.</a>
   31.23 + 
   31.24 +\section license License
   31.25 + 
   31.26 + MYCrypto is released under a BSD license, which means you can freely use it in open-source
   31.27 + or commercial projects, provided you give credit in your documentation or About box.
   31.28 +   
   31.29 +\section config Configuration
   31.30 + 
   31.31 +    MYCrypto requires Mac OS X 10.5 or later, since it uses Objective-C 2 features like
   31.32 +    properties and for...in loops.
   31.33 + 
   31.34 +    MYCrypto uses my <a href="/hg/hgwebdir.cgi/MYUtilities">MYUtilities</a> library. You'll need to have downloaded that library, and added
   31.35 +    the necessary source files and headers to your project. See the MYCrypto Xcode project,
   31.36 +    which contains the minimal set of MYUtilities files needed to build MYUtilities. (That project
   31.37 +    has its search paths set up to assume that MYUtilities is in a directory next to MYCrypto.)
   31.38 +
   31.39 +\section download How To Get It
   31.40 +
   31.41 +    <ul>
   31.42 +    <li><a href="/hg/hgwebdir.cgi/MYCrypto/archive/tip.zip">Download the current source code</a>
   31.43 +    <li>To check out the source code using <a href="http://selenic.com/mercurial">Mercurial</a>:
   31.44 +    \verbatim hg clone /hg/hgwebdir.cgi/MYCrypto/ MYCrypto \endverbatim
   31.45 +    <li>As described above, you'll also need to download or check out <a href="/hg/hgwebdir.cgi/MYUtilities">MYUtilities</a> and put it in 
   31.46 +    a directory next to MYCrypto.
   31.47 +    </ul>
   31.48 +
   31.49 +    Or if you're just looking:
   31.50 +
   31.51 +    <ul>
   31.52 +    <li><a href="/hg/hgwebdir.cgi/MYCrypto/file/tip">Browse the source code</a>
   31.53 +    <li><a href="annotated.html">Browse the class documentation</a>
   31.54 +    </ul>
   31.55 +    
   31.56 + */