Code cleanup, more header comments.
authorsnej@snej.local
Sat Apr 04 22:56:13 2009 -0700 (2009-04-04)
changeset 160e4cbbb5128
parent 0 0a6527af039b
child 2 8982b8fada63
Code cleanup, more header comments.
MYCertificate-iPhone.m
MYCertificate.h
MYCryptoTest.m
MYCrypto_Private.h
MYCryptor.h
MYDigest.h
MYKey-iPhone.m
MYKey.h
MYKey.m
MYKeyPair-iPhone.m
MYKeyPair.h
MYKeyPair.m
MYKeychain.h
MYKeychainItem.h
MYKeychainItem.m
MYPublicKey-iPhone.m
MYPublicKey.h
MYPublicKey.m
MYSymmetricKey.h
MYSymmetricKey.m
     1.1 --- a/MYCertificate-iPhone.m	Sat Apr 04 20:42:03 2009 -0700
     1.2 +++ b/MYCertificate-iPhone.m	Sat Apr 04 22:56:13 2009 -0700
     1.3 @@ -67,10 +67,6 @@
     1.4      return name ?[(id)CFMakeCollectable(name) autorelease] :nil;
     1.5  }
     1.6  
     1.7 -- (NSArray*) emailAddresses {
     1.8 -    return nil; //FIX UNIMPLEMENTED
     1.9 -}
    1.10 -
    1.11  
    1.12  @end
    1.13  
     2.1 --- a/MYCertificate.h	Sat Apr 04 20:42:03 2009 -0700
     2.2 +++ b/MYCertificate.h	Sat Apr 04 22:56:13 2009 -0700
     2.3 @@ -17,6 +17,7 @@
     2.4  
     2.5  /** An X.509 certificate. */
     2.6  @interface MYCertificate : MYKeychainItem {
     2.7 +    @private
     2.8      SecCertificateRef _certificateRef;
     2.9  }
    2.10  
    2.11 @@ -33,7 +34,7 @@
    2.12                        encoding: (CSSM_CERT_ENCODING) encoding;
    2.13  #endif
    2.14  
    2.15 -/** The Keychain object reference for this key. */
    2.16 +/** The Keychain object reference for this certificate. */
    2.17  @property (readonly) SecCertificateRef certificateRef;
    2.18  
    2.19  /** The certificate's data. */
    2.20 @@ -42,10 +43,13 @@
    2.21  /** The certificate's public key. */
    2.22  @property (readonly) MYPublicKey *publicKey;
    2.23  
    2.24 +/** The name of the subject (owner) of the certificate. */
    2.25  @property (readonly) NSString *commonName;
    2.26 +
    2.27 +#if !TARGET_OS_IPHONE
    2.28 +/** The list (if any) of the subject's email addresses. */
    2.29  @property (readonly) NSArray *emailAddresses;
    2.30  
    2.31 -#if !TARGET_OS_IPHONE
    2.32  /** Finds the current 'preferred' certificate for the given name string. */
    2.33  + (MYCertificate*) preferredCertificateForName: (NSString*)name;
    2.34  
     3.1 --- a/MYCryptoTest.m	Sat Apr 04 20:42:03 2009 -0700
     3.2 +++ b/MYCryptoTest.m	Sat Apr 04 22:56:13 2009 -0700
     3.3 @@ -29,7 +29,9 @@
     3.4      kc = [MYKeychain allKeychains];
     3.5      Log(@"All-keychains = %@", kc);
     3.6      CAssert(kc);
     3.7 +#if !USE_IPHONE_API
     3.8      CAssertEq(kc.path,nil);
     3.9 +#endif
    3.10  }
    3.11  
    3.12  
     4.1 --- a/MYCrypto_Private.h	Sat Apr 04 20:42:03 2009 -0700
     4.2 +++ b/MYCrypto_Private.h	Sat Apr 04 22:56:13 2009 -0700
     4.3 @@ -16,24 +16,32 @@
     4.4  
     4.5  /*  The iPhone simulator actually has the Mac OS X security API, not the iPhone one.
     4.6      So don't use the iPhone API when configured to run in the simulator. */
     4.7 -#if TARGET_OS_IPHONE
     4.8 -#if !TARGET_IPHONE_SIMULATOR
     4.9 +#if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
    4.10  #define USE_IPHONE_API 1
    4.11 -#endif
    4.12 -#endif
    4.13 -
    4.14 -#ifndef USE_IPHONE_API
    4.15 +#else
    4.16  #define USE_IPHONE_API 0
    4.17  #endif
    4.18  
    4.19 -
    4.20  #if USE_IPHONE_API
    4.21  typedef CFTypeRef SecKeychainAttrType;
    4.22  typedef CFTypeRef SecKeychainItemRef;
    4.23  typedef CFTypeRef SecKeychainRef;
    4.24 +typedef CFTypeRef SecExternalItemType;
    4.25  #endif
    4.26  
    4.27 +
    4.28 +#if TARGET_IPHONE_SIMULATOR
    4.29 +@interface MYKeychain (Private)
    4.30 +- (id) initWithKeychainRef: (SecKeychainRef)keychainRef;
    4.31 +@property (readonly) SecKeychainRef keychainRef, keychainRefOrDefault;
    4.32 +@property (readonly) CSSM_CSP_HANDLE CSPHandle;
    4.33 +@property (readonly) NSString* path;
    4.34 +@end
    4.35 +#endif
    4.36 +
    4.37 +
    4.38  @interface MYKeychainItem (Private);
    4.39 +- (id) initWithKeychainItemRef: (MYKeychainItemRef)itemRef;
    4.40  - (NSData*) _getContents: (OSStatus*)outError;
    4.41  - (NSString*) stringValueOfAttribute: (SecKeychainAttrType)attr;
    4.42  - (BOOL) setValue: (NSString*)valueStr ofAttribute: (SecKeychainAttrType)attr;
    4.43 @@ -46,8 +54,10 @@
    4.44  
    4.45  
    4.46  @interface MYKey (Private)
    4.47 +- (id) initWithKeyData: (NSData*)data;
    4.48  - (id) _initWithKeyData: (NSData*)data
    4.49              forKeychain: (SecKeychainRef)keychain;
    4.50 +@property (readonly) SecExternalItemType keyType;
    4.51  #if !USE_IPHONE_API
    4.52  @property (readonly) const CSSM_KEY* cssmKey;
    4.53  - (NSData*) exportKeyInFormat: (SecExternalFormat)format withPEM: (BOOL)withPEM;
    4.54 @@ -89,7 +99,7 @@
    4.55  @end
    4.56  
    4.57  
    4.58 -#if TARGET_OS_IPHONE && !USE_IPHONE_API
    4.59 +#if TARGET_IPHONE_SIMULATOR
    4.60  @interface MYCertificate (Private)
    4.61  - (id) initWithCertificateData: (NSData*)data
    4.62                            type: (CSSM_CERT_TYPE) type
    4.63 @@ -98,16 +108,6 @@
    4.64  #endif
    4.65  
    4.66  
    4.67 -#if TARGET_OS_IPHONE && !USE_IPHONE_API
    4.68 -@interface MYKeychain (Private)
    4.69 -- (id) initWithKeychainRef: (SecKeychainRef)keychainRef;
    4.70 -@property (readonly) SecKeychainRef keychainRef, keychainRefOrDefault;
    4.71 -@property (readonly) CSSM_CSP_HANDLE CSPHandle;
    4.72 -@property (readonly) NSString* path;
    4.73 -@end
    4.74 -#endif
    4.75 -
    4.76 -
    4.77  NSData* _crypt(SecKeyRef key, NSData *data, CCOperation op);
    4.78  
    4.79  #undef check
     5.1 --- a/MYCryptor.h	Sat Apr 04 20:42:03 2009 -0700
     5.2 +++ b/MYCryptor.h	Sat Apr 04 22:56:13 2009 -0700
     5.3 @@ -10,9 +10,12 @@
     5.4  #import <CommonCrypto/CommonCryptor.h>
     5.5  
     5.6  
     5.7 -/** Symmetric encryption: a Cocoa wrapper for CommonCrypto/commonCryptor.h */
     5.8 +/** Symmetric encryption: a simple Cocoa wrapper for CommonCrypto/commonCryptor.h.
     5.9 +    Provides a streaming interface for encrypting/decrypting data.
    5.10 +    This class will probably be merged into or integrated with MYSymmetricKey. */
    5.11  @interface MYCryptor : NSObject
    5.12  {
    5.13 +    @private
    5.14      NSData *_key;
    5.15      CCOperation _operation;
    5.16      CCAlgorithm _algorithm;
    5.17 @@ -24,9 +27,11 @@
    5.18      size_t _outputExtraBytes;
    5.19  }
    5.20  
    5.21 -/** CommonCryptor.h defines key size and size-range constants, like kCCKeySizeAES128 */
    5.22 +/** Returns a block of cryptographically-random data, suitable for use as a symmetric key.
    5.23 +    (CommonCryptor.h defines constants for key sizes and size-ranges, like kCCKeySizeAES128.) */
    5.24  + (NSData*) randomKeyOfLength: (size_t)length;
    5.25  
    5.26 +/** Converts a passphrase into a block of data of the given size, suitable for use as a symmetric key. */
    5.27  + (NSData*) keyOfLength: (size_t)lengthInBits fromPassphrase: (NSString*)passphrase;
    5.28  
    5.29  /** Creates a MYCryptor configured to encrypt data. */
    5.30 @@ -37,22 +42,23 @@
    5.31  - (id) initDecryptorWithKey: (NSData*)key
    5.32                    algorithm: (CCAlgorithm)algorithm;
    5.33  
    5.34 -/** Setting this property tells the cryptor to send its output to the stream,
    5.35 -    instead of accumulating itself in the outputData property. */
    5.36 -@property (retain) NSOutputStream *outputStream;
    5.37 -
    5.38  /** The encryption/decryption key; same as the 'key' parameter to the initializer. */
    5.39  @property (readonly) NSData *key;
    5.40  
    5.41  /** The cipher to use; initial value is the 'algorithm' parameter to the initializer.
    5.42 -    You can change this before the first call to -addData:, but not after. */
    5.43 +    You can change this <i>before</i> the first call to -addData:, but not after. */
    5.44  @property CCAlgorithm algorithm;
    5.45  
    5.46  /** Block-mode cipher options; you can set flags to enable PKCS7 padding or ECB mode
    5.47      (default is CBC.)
    5.48 -    You can change this before the first call to -addData:, but not after. */
    5.49 +    You can change this <i>before</i> the first call to -addData:, but not after. */
    5.50  @property CCOptions options;
    5.51  
    5.52 +/** Setting this property tells the cryptor to send its output to the stream,
    5.53 +    instead of accumulating it in the outputData property.
    5.54 +    You can change this <i>before</i> the first call to -addData:, but not after. */
    5.55 +@property (retain) NSOutputStream *outputStream;
    5.56 +
    5.57  /** The error state, if any, of this cryptor.
    5.58      After -addData: or -finish: returns NO, check this property. */
    5.59  @property (readonly, retain) NSError *error;
     6.1 --- a/MYDigest.h	Sat Apr 04 20:42:03 2009 -0700
     6.2 +++ b/MYDigest.h	Sat Apr 04 22:56:13 2009 -0700
     6.3 @@ -13,30 +13,53 @@
     6.4      Each specific type of digest has its own concrete subclass. */
     6.5  @interface MYDigest : NSObject <NSCoding, NSCopying>
     6.6  {
     6.7 +    @private
     6.8      void *_rawDigest;
     6.9  }
    6.10  
    6.11 +/** Initializes a MYDigest from an existing raw digest.
    6.12 +    MYDigest itself is abstract, so this must be called on a subclass instance. */
    6.13  - (id) initWithRawDigest: (const void*)rawDigest length: (size_t)length;
    6.14  
    6.15 +/** Wraps an existing digest, stored in an NSData object, in a MYDigest object. */
    6.16  + (MYDigest*) digestFromDigestData: (NSData*)digestData;
    6.17 +
    6.18 +/** Wraps an existing digest, expressed as a hex string, in a MYDigest object. */
    6.19  + (MYDigest*) digestFromHexString: (NSString*)hexString;
    6.20  
    6.21 +/** Computes a cryptographic digest of the given data. */
    6.22  + (MYDigest*) digestOfData: (NSData*)data;
    6.23 +
    6.24 +/** Computes a cryptographic digest of the given data. */
    6.25  + (MYDigest*) digestOfBytes: (const void*)bytes length: (size_t)length;
    6.26  
    6.27 -- (NSComparisonResult) compare: (MYDigest*)other;
    6.28 +/** Returns the digest as an NSData object. */
    6.29 +@property (readonly) NSData *asData;
    6.30  
    6.31 -@property (readonly) NSData *asData;
    6.32 -@property (readonly) NSString *hexString, *abbreviatedHexString;
    6.33 +/** Returns the digest as a hex string. */
    6.34 +@property (readonly) NSString *hexString;
    6.35  
    6.36 +/** Returns the first 8 digits (32 bits) of the digest's hex string, followed by "..."
    6.37 +    This is intended only for use in log messages or object descriptions, since
    6.38 +    32 bits isn't nearly enough to provide any useful uniqueness. */
    6.39 +@property (readonly) NSString *abbreviatedHexString;
    6.40 +
    6.41 +/** The algorithm that created this digest. */
    6.42  @property (readonly) uint32_t /*CSSM_ALGORITHMS*/ algorithm;
    6.43 +
    6.44 +/** The length (in bytes, not bits!) of this digest. */
    6.45  @property (readonly) size_t length;
    6.46 +
    6.47 +/** A pointer to the raw bytes of digest data. */
    6.48  @property (readonly) const void* bytes;
    6.49  
    6.50 +/** The algorithm used by this subclass. (Abstract method.) */
    6.51  + (uint32_t /*CSSM_ALGORITHMS*/) algorithm;
    6.52 +
    6.53 +/** The length of digests created by this subclass. (Abstract method.) */
    6.54  + (size_t) length;
    6.55  
    6.56 -/** Primitive digest generation method; abstract of course. */
    6.57 +/** Primitive digest generation method. (Abstract.) */
    6.58  + (void) computeDigest: (void*)dstDigest ofBytes: (const void*)bytes length: (size_t)length;
    6.59  
    6.60  @end
     7.1 --- a/MYKey-iPhone.m	Sat Apr 04 20:42:03 2009 -0700
     7.2 +++ b/MYKey-iPhone.m	Sat Apr 04 22:56:13 2009 -0700
     7.3 @@ -20,11 +20,7 @@
     7.4  
     7.5  
     7.6  - (id) initWithKeyRef: (SecKeyRef)key {
     7.7 -    self = [super initWithKeychainItemRef: (SecKeychainItemRef)key];
     7.8 -    if (self) {
     7.9 -        _key = key;     // superclass has already CFRetained it
    7.10 -    }
    7.11 -    return self;
    7.12 +    return [super initWithKeychainItemRef: (SecKeychainItemRef)key];
    7.13  }
    7.14  
    7.15  
    7.16 @@ -32,7 +28,7 @@
    7.17              forKeychain: (SecKeychainRef)keychain
    7.18  {
    7.19      NSDictionary *info = $dict( {(id)kSecClass, (id)kSecClassKey},
    7.20 -                                {(id)kSecAttrKeyType, (id)kSecAttrKeyTypeRSA},
    7.21 +                                {(id)kSecAttrKeyClass, (id)self.keyType},
    7.22                                  {(id)kSecValueData, data},
    7.23                                  {(id)kSecAttrIsPermanent, $object(keychain!=nil)},
    7.24                                  {(id)kSecReturnRef, $true} );
    7.25 @@ -48,11 +44,6 @@
    7.26  }
    7.27  
    7.28  
    7.29 -- (NSString*) description {
    7.30 -    return $sprintf(@"%@[%p]", [self class], _key);     //FIX: Can we do anything better?
    7.31 -}
    7.32 -
    7.33 -
    7.34  - (SecExternalItemType) keyType {
    7.35      AssertAbstractMethod();
    7.36  }
    7.37 @@ -60,8 +51,8 @@
    7.38  
    7.39  - (NSData*) keyData {
    7.40      NSDictionary *info = $dict( {(id)kSecClass, (id)kSecClassKey},
    7.41 -                                {(id)kSecAttrKeyType, (id)self.keyType},
    7.42 -                                {(id)kSecMatchItemList, $array((id)_key)},
    7.43 +                                {(id)kSecAttrKeyClass, (id)self.keyType},
    7.44 +                                {(id)kSecMatchItemList, $array((id)self.keyRef)},
    7.45                                  {(id)kSecReturnData, $true} );
    7.46      CFDataRef data;
    7.47      if (!check(SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef*)&data), @"SecItemCopyMatching"))
    7.48 @@ -71,18 +62,15 @@
    7.49  }
    7.50  
    7.51  
    7.52 -@synthesize keyRef=_key;
    7.53 -
    7.54 -
    7.55 -- (MYKey*) asKey {
    7.56 -    return self;
    7.57 +- (SecKeyRef) keyRef {
    7.58 +    return (SecKeyRef) self.keychainItemRef;
    7.59  }
    7.60  
    7.61  
    7.62  - (id) _attribute: (CFTypeRef)attribute {
    7.63      NSDictionary *info = $dict( {(id)kSecClass, (id)kSecClassKey},
    7.64 -                                {(id)kSecAttrKeyType, (id)self.keyType},
    7.65 -                                {(id)kSecMatchItemList, $array((id)_key)},
    7.66 +                                {(id)kSecAttrKeyClass, (id)self.keyType},
    7.67 +                                {(id)kSecMatchItemList, $array((id)self.keyRef)},
    7.68                                  {(id)kSecReturnAttributes, $true} );
    7.69      CFDictionaryRef attrs;
    7.70      if (!check(SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef*)&attrs), @"SecItemCopyMatching"))
    7.71 @@ -97,7 +85,7 @@
    7.72      if (!value)
    7.73          value = (id)[NSNull null];
    7.74      NSDictionary *query = $dict( {(id)kSecClass, (id)kSecClassKey},
    7.75 -                                {(id)kSecAttrKeyType, (id)self.keyType},
    7.76 +                                {(id)kSecAttrKeyClass, (id)self.keyType},
    7.77                                  {(id)kSecMatchItemList, self._itemList} );
    7.78      NSDictionary *attrs = $dict( {(id)attribute, value} );
    7.79      return check(SecItemUpdate((CFDictionaryRef)query, (CFDictionaryRef)attrs), @"SecItemUpdate");
     8.1 --- a/MYKey.h	Sat Apr 04 20:42:03 2009 -0700
     8.2 +++ b/MYKey.h	Sat Apr 04 22:56:13 2009 -0700
     8.3 @@ -8,41 +8,30 @@
     8.4  
     8.5  #import "MYKeychainItem.h"
     8.6  
     8.7 -#if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
     8.8 -typedef CFTypeRef SecExternalItemType;
     8.9 -#endif
    8.10  
    8.11 +@protocol MYEncryption <NSObject>
    8.12  
    8.13 +/** Encrypts data using this key, returning the raw encrypted result. */
    8.14 +- (NSData*) encryptData: (NSData*)data;
    8.15 +
    8.16 +@end
    8.17 +
    8.18 +@protocol MYDecryption <NSObject>
    8.19 +
    8.20 +/** Decrypts data using this key, returning the original data. */
    8.21 +- (NSData*) decryptData: (NSData*)data;
    8.22 +
    8.23 +@end
    8.24 +
    8.25 +
    8.26 +
    8.27 +/** Abstract superclass for keys.
    8.28 +    Concrete subclasses are MYSymmetricKey and MYPublicKey. */
    8.29  @interface MYKey : MYKeychainItem
    8.30 -{
    8.31 -    @private
    8.32 -    SecKeyRef _key;
    8.33 -}
    8.34  
    8.35 -/** Creates a MYKey object for an existing Keychain key reference. */
    8.36 -- (id) initWithKeyRef: (SecKeyRef)keyRef;
    8.37 -
    8.38 -/** Creates a MYKey object from exported key data, but does not add it to any keychain. */
    8.39 -- (id) initWithKeyData: (NSData*)data;
    8.40 -
    8.41 -#if !TARGET_OS_IPHONE
    8.42 -/** Converts the key into a data blob in one of several standard formats, suitable for storing in
    8.43 -    a file or sending over the network.
    8.44 -    @param format  The data format: kSecFormatOpenSSL, kSecFormatSSH, kSecFormatBSAFE or kSecFormatSSHv2.
    8.45 -    @param withPEM  YES if the data should be encoded in PEM format, which converts into short lines
    8.46 -        of printable ASCII characters, suitable for sending in email. */
    8.47 -- (NSData*) exportKeyInFormat: (SecExternalFormat)format withPEM: (BOOL)withPEM;
    8.48 -#endif
    8.49 -
    8.50 -/** The Keychain object reference for this key. */
    8.51 -@property (readonly) SecKeyRef keyRef;
    8.52 -
    8.53 -/** The key's raw data in OpenSSL format. This is the same as calling
    8.54 -    -exportKeyInFormat: kSecFormatOpenSSL withPEM: NO */
    8.55 +/** The key's raw data. */
    8.56  @property (readonly) NSData *keyData;
    8.57  
    8.58 -@property (readonly) SecExternalItemType keyType;
    8.59 -
    8.60  /** The user-visible name (kSecKeyPrintName) associated with this key in the Keychain.
    8.61      The user can edit this, so don't expect it to be immutable. */
    8.62  @property (copy) NSString *name;
    8.63 @@ -63,16 +52,25 @@
    8.64  
    8.65  
    8.66  
    8.67 -@protocol MYEncryption <NSObject>
    8.68 +@interface MYKey (Expert)
    8.69  
    8.70 -/** Encrypts data using this key, returning the raw encrypted result. */
    8.71 -- (NSData*) encryptData: (NSData*)data;
    8.72 +/** Creates a MYKey object for an existing Keychain key reference.
    8.73 +    This is abstract -- must be called on a MYSymmetricKey or MYPublicKey, as appropriate. */
    8.74 +- (id) initWithKeyRef: (SecKeyRef)keyRef;
    8.75 +
    8.76 +/** The Keychain object reference for this key. */
    8.77 +@property (readonly) SecKeyRef keyRef;
    8.78 +
    8.79 +#if !TARGET_OS_IPHONE
    8.80 +/** The underlying CSSM_KEY structure; used with low-level crypto APIs. */
    8.81 +@property (readonly) const struct cssm_key* cssmKey;
    8.82 +
    8.83 +/** Converts the key into a data blob in one of several standard formats, suitable for storing in
    8.84 +    a file or sending over the network.
    8.85 +    @param format  The data format: kSecFormatOpenSSL, kSecFormatSSH, kSecFormatBSAFE or kSecFormatSSHv2.
    8.86 +    @param withPEM  YES if the data should be encoded in PEM format, which converts into short lines
    8.87 +        of printable ASCII characters, suitable for sending in email. */
    8.88 +- (NSData*) exportKeyInFormat: (SecExternalFormat)format withPEM: (BOOL)withPEM;
    8.89 +#endif
    8.90  
    8.91  @end
    8.92 -
    8.93 -@protocol MYDecryption <NSObject>
    8.94 -
    8.95 -/** Decrypts data using this key, returning the original data. */
    8.96 -- (NSData*) decryptData: (NSData*)data;
    8.97 -
    8.98 -@end
     9.1 --- a/MYKey.m	Sat Apr 04 20:42:03 2009 -0700
     9.2 +++ b/MYKey.m	Sat Apr 04 22:56:13 2009 -0700
     9.3 @@ -19,11 +19,7 @@
     9.4  
     9.5  
     9.6  - (id) initWithKeyRef: (SecKeyRef)key {
     9.7 -    self = [super initWithKeychainItemRef: (SecKeychainItemRef)key];
     9.8 -    if (self) {
     9.9 -        _key = key;     // superclass has already CFRetained it
    9.10 -    }
    9.11 -    return self;
    9.12 +    return [super initWithKeychainItemRef: (SecKeychainItemRef)key];
    9.13  }
    9.14  
    9.15  - (id) _initWithKeyData: (NSData*)data
    9.16 @@ -34,10 +30,7 @@
    9.17          [self release];
    9.18          return nil;
    9.19      }
    9.20 -    self = [super initWithKeychainItemRef: (SecKeychainItemRef)key];
    9.21 -    if (self) {
    9.22 -        _key = key;
    9.23 -    }
    9.24 +    self = [self initWithKeyRef: key];
    9.25      CFRelease(key);
    9.26      return self;
    9.27  }
    9.28 @@ -47,32 +40,24 @@
    9.29  }
    9.30  
    9.31  
    9.32 -- (NSString*) description {
    9.33 -    return $sprintf(@"%@[%p]", [self class], _key);     //FIX: Can we do anything better?
    9.34 -}
    9.35 -
    9.36 -
    9.37  - (SecExternalItemType) keyType {
    9.38      AssertAbstractMethod();
    9.39  }
    9.40  
    9.41  
    9.42 -@synthesize keyRef=_key;
    9.43 -
    9.44 -
    9.45 -- (MYKey*) asKey {
    9.46 -    return self;
    9.47 +- (SecKeyRef) keyRef {
    9.48 +    return (SecKeyRef) self.keychainItemRef;
    9.49  }
    9.50  
    9.51  - (const CSSM_KEY*) cssmKey {
    9.52      const CSSM_KEY *cssmKey = NULL;
    9.53 -    Assert(check(SecKeyGetCSSMKey(_key, &cssmKey), @"SecKeyGetCSSMKey"), @"Failed to get CSSM_KEY");
    9.54 +    Assert(check(SecKeyGetCSSMKey(self.keyRef, &cssmKey), @"SecKeyGetCSSMKey"), @"Failed to get CSSM_KEY");
    9.55      return cssmKey;
    9.56  }
    9.57  
    9.58  - (NSData*) exportKeyInFormat: (SecExternalFormat)format withPEM: (BOOL)withPEM {
    9.59      CFDataRef data = NULL;
    9.60 -    if (check(SecKeychainItemExport(_key, format, (withPEM ?kSecItemPemArmour :0), NULL, &data),
    9.61 +    if (check(SecKeychainItemExport(self.keyRef, format, (withPEM ?kSecItemPemArmour :0), NULL, &data),
    9.62                @"SecKeychainItemExport"))
    9.63          return [(id)CFMakeCollectable(data) autorelease];
    9.64      else
    10.1 --- a/MYKeyPair-iPhone.m	Sat Apr 04 20:42:03 2009 -0700
    10.2 +++ b/MYKeyPair-iPhone.m	Sat Apr 04 22:56:13 2009 -0700
    10.3 @@ -9,6 +9,8 @@
    10.4  
    10.5  #import "MYKeyPair.h"
    10.6  #import "MYCrypto_Private.h"
    10.7 +#import <CommonCrypto/CommonDigest.h>
    10.8 +
    10.9  
   10.10  #if USE_IPHONE_API
   10.11  
   10.12 @@ -49,7 +51,9 @@
   10.13  }
   10.14  
   10.15  
   10.16 -@synthesize privateKeyRef=_privateKey;
   10.17 +- (SecKeyRef) privateKeyRef {
   10.18 +    return _privateKey;
   10.19 +}
   10.20  
   10.21  
   10.22  - (NSData*) decryptData: (NSData*)data {
    11.1 --- a/MYKeyPair.h	Sat Apr 04 20:42:03 2009 -0700
    11.2 +++ b/MYKeyPair.h	Sat Apr 04 22:56:13 2009 -0700
    11.3 @@ -10,15 +10,49 @@
    11.4  
    11.5  
    11.6  /** A key-pair consisting of a public and a private key.
    11.7 -    Can be used for signing and decrypting, as well as the inherited encrypting/verifying. */
    11.8 +    Can be used for signing and decrypting, as well as the inherited encrypting/verifying.
    11.9 +    Instances are generated by MYKeychain objects. */
   11.10  @interface MYKeyPair : MYPublicKey <MYDecryption>
   11.11  {
   11.12 +    @private
   11.13      SecKeyRef _privateKey;
   11.14  }
   11.15  
   11.16 +/** Decrypts data that was encrypted using the public key.
   11.17 +    See the description of -[MYPublicKey encryptData:] for warnings and caveats.
   11.18 +    This method is usually used only to decrypt a symmetric session key, which then decrypts the
   11.19 +    rest of the data. */
   11.20 +- (NSData*) decryptData: (NSData*)data;
   11.21 +
   11.22 +/** Generates a signature of data, using the private key.
   11.23 +    (What's actually signed using RSA is the SHA-256 digest of the data.)
   11.24 +    The resulting signature can be verified using the matching MYPublicKey's
   11.25 +    verifySignature:ofData: method. */
   11.26 +- (NSData*) signData: (NSData*)data;
   11.27 +
   11.28 +#if !TARGET_OS_IPHONE
   11.29 +/** Exports the private key as a data blob, so that it can be stored as a backup, or transferred
   11.30 +    to another computer. Since the key is sensitive, it must be exported in encrypted form
   11.31 +    using a user-chosen passphrase. This method will display a standard alert panel, run by
   11.32 +    the Security agent, that prompts the user to enter a new passphrase for encrypting the key.
   11.33 +    The same passphrase must be re-entered when importing the key from the data blob.
   11.34 +    (This is a convenient shorthand for the full exportPrivateKeyInFormat... method.
   11.35 +    It uses OpenSSL format, wrapped with PEM, and a default title and prompt for the alert.) */
   11.36 +- (NSData*) exportPrivateKey;
   11.37 +#endif
   11.38 +
   11.39 +@end
   11.40 +
   11.41 +
   11.42 +
   11.43 +@interface MYKeyPair (Expert)
   11.44 +
   11.45  /** Creates a MYKeyPair object from existing Keychain key references. */
   11.46  - (id) initWithPublicKeyRef: (SecKeyRef)publicKey privateKeyRef: (SecKeyRef)privateKey;
   11.47  
   11.48 +/** The underlying Keychain key reference for the private key. */
   11.49 +@property (readonly) SecKeyRef privateKeyRef;
   11.50 +
   11.51  #if !TARGET_OS_IPHONE
   11.52  /** Exports the private key as a data blob, so that it can be stored as a backup, or transferred
   11.53      to another computer. Since the key is sensitive, it must be exported in encrypted form
   11.54 @@ -34,21 +68,6 @@
   11.55                               withPEM: (BOOL)withPEM
   11.56                            alertTitle: (NSString*)title
   11.57                           alertPrompt: (NSString*)prompt;
   11.58 -
   11.59 -/** A convenient shorthand for the full exportPrivateKeyInFormat... method.
   11.60 -    Uses OpenSSL format, wrapped with PEM, and default title and prompt for the alert. */
   11.61 -- (NSData*) exportPrivateKey;
   11.62  #endif
   11.63  
   11.64 -/** The underlying Keychain key reference for the private key. */
   11.65 -@property (readonly) SecKeyRef privateKeyRef;
   11.66 -
   11.67 -/** Decrypts data that was encrypted using the public key. */
   11.68 -- (NSData*) decryptData: (NSData*)data;
   11.69 -
   11.70 -/** Generates a signature of data, using the private key.
   11.71 -    The resulting signature can be verified using the matching MYPublicKey's
   11.72 -    verifySignature:ofData: method. */
   11.73 -- (NSData*) signData: (NSData*)data;
   11.74 -
   11.75  @end
    12.1 --- a/MYKeyPair.m	Sat Apr 04 20:42:03 2009 -0700
    12.2 +++ b/MYKeyPair.m	Sat Apr 04 22:56:13 2009 -0700
    12.3 @@ -170,7 +170,9 @@
    12.4  }
    12.5  
    12.6  
    12.7 -@synthesize privateKeyRef=_privateKey;
    12.8 +- (SecKeyRef) privateKeyRef {
    12.9 +    return _privateKey;
   12.10 +}
   12.11  
   12.12  
   12.13  - (NSData*) decryptData: (NSData*)data {
   12.14 @@ -180,8 +182,9 @@
   12.15  
   12.16  - (NSData*) signData: (NSData*)data {
   12.17      Assert(data);
   12.18 -    uint8_t digest[CC_SHA1_DIGEST_LENGTH];
   12.19 -    CC_SHA1(data.bytes,data.length, digest);
   12.20 +    uint8_t digest[CC_SHA256_DIGEST_LENGTH];
   12.21 +    CC_SHA256(data.bytes,data.length, digest);
   12.22 +    
   12.23      NSData *signature = nil;
   12.24      CSSM_CC_HANDLE ccHandle = cssmCreateSignatureContext(_privateKey);
   12.25      if (!ccHandle) return nil;
    13.1 --- a/MYKeychain.h	Sat Apr 04 20:42:03 2009 -0700
    13.2 +++ b/MYKeychain.h	Sat Apr 04 22:56:13 2009 -0700
    13.3 @@ -14,6 +14,7 @@
    13.4      This class wraps the Security framework's SecKeychain API. */
    13.5  @interface MYKeychain : NSObject 
    13.6  {
    13.7 +    @private
    13.8  #if !TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
    13.9      SecKeychainRef _keychain;
   13.10  #endif
   13.11 @@ -29,12 +30,12 @@
   13.12  
   13.13  #pragma mark SYMMETRIC KEYS:
   13.14  
   13.15 +/** Randomly generates a new symmetric key, using the given algorithm and key-size in bits.
   13.16 +    The key is persistently added to this keychain. */
   13.17  - (MYSymmetricKey*) generateSymmetricKeyOfSize: (unsigned)keySizeInBits
   13.18                                       algorithm: (uint32_t/*CCAlgorithm*/)algorithm;
   13.19 -- (NSEnumerator*) enumerateSymmetricKeys;
   13.20 -- (NSEnumerator*) symmetricKeysWithAlias: (NSString*)alias;
   13.21  
   13.22 -/** Enumerates all symmetric keys in the keychain. */
   13.23 +/** Enumerates all of the symmetric keys in the keychain, as MYSymmetricKey objects. */
   13.24  - (NSEnumerator*) enumerateSymmetricKeys;
   13.25  
   13.26  #pragma mark PUBLIC KEYS:
   13.27 @@ -49,13 +50,14 @@
   13.28  - (NSEnumerator*) enumeratePublicKeys;
   13.29  
   13.30  /** Imports a public key into the keychain, given its external representation
   13.31 -    (as generated by -[MYPublicKey exportDataInFormat:withPEM:].) */
   13.32 +    (as generated by -[MYPublicKey keyData].) */
   13.33  - (MYPublicKey*) importPublicKey: (NSData*)keyData;
   13.34  
   13.35  #pragma mark CERTIFICATES:
   13.36  
   13.37  /** Looks up an existing certificate with the given public-key digest.
   13.38 -    Returns nil if there is no such certificate in the keychain. */
   13.39 +    Returns nil if there is no such certificate in the keychain.
   13.40 +    (This method only looks for keys embedded in certificates, not 'bare' public keys.) */
   13.41  - (MYCertificate*) certificateWithDigest: (MYSHA1Digest*)pubKeyDigest;
   13.42  
   13.43  /** Enumerates all certificates in the keychain. */
   13.44 @@ -68,7 +70,7 @@
   13.45  
   13.46  /** Looks up an existing key-pair whose public key has the given digest.
   13.47      Returns nil if there is no such key-pair in the keychain.
   13.48 -    (This method does not look for keys embedded in certificates, only 'bare' keys.) */
   13.49 +    (This method does not look for public keys embedded in certificates, only 'bare' keys.) */
   13.50  - (MYKeyPair*) keyPairWithDigest: (MYSHA1Digest*)pubKeyDigest;
   13.51  
   13.52  /** Enumerates all key-pairs in the keychain.
   13.53 @@ -76,8 +78,8 @@
   13.54  - (NSEnumerator*) enumerateKeyPairs;
   13.55  
   13.56  /** Generates a new RSA key-pair and adds both keys to the keychain.
   13.57 -    This is very slow -- it may take several seconds, depending on the key size, CPU speed,
   13.58 -    and other random factors. You should probably show some kind of progress indicator before
   13.59 +    This is very slow -- it may take seconds, depending on the key size, CPU speed,
   13.60 +    and other random factors. You may want to start some kind of progress indicator before
   13.61      calling this method, so the user doesn't think the app has locked up!
   13.62      @param keySize  The RSA key length in bits. Must be a power of two. Longer keys are harder
   13.63          to break, but operate more slowly and generate larger signatures.
   13.64 @@ -96,6 +98,7 @@
   13.65  
   13.66  #if !TARGET_OS_IPHONE
   13.67  
   13.68 +/** Keychain functionality that's not supported on iPhone. */
   13.69  @interface MYKeychain (MacOnly)
   13.70  
   13.71  /** Creates a MYKeychain for an existing SecKeychainRef. */
   13.72 @@ -143,14 +146,14 @@
   13.73  
   13.74  /** Imports a key-pair into the keychain, given the external representations
   13.75      of both the public and private keys.
   13.76 -    Since the private key data is encrypted, the Security agent will prompt the user to enter
   13.77 +    Since the private key data is wrapped (encrypted), the Security agent will prompt the user to enter
   13.78      the passphrase. */
   13.79  - (MYKeyPair*) importPublicKey: (NSData*)pubKeyData 
   13.80                      privateKey: (NSData*)privKeyData;
   13.81  
   13.82  /** Imports a key-pair into the keychain, given the external representations
   13.83      of both the public and private keys.
   13.84 -    Since the private key data is encrypted, the Security agent will prompt the user to enter
   13.85 +    Since the private key data is wrapped (encrypted), the Security agent will prompt the user to enter
   13.86      the passphrase. You can specify the title and prompt message for this alert panel. */
   13.87  - (MYKeyPair*) importPublicKey: (NSData*)pubKeyData 
   13.88                      privateKey: (NSData*)privKeyData
    14.1 --- a/MYKeychainItem.h	Sat Apr 04 20:42:03 2009 -0700
    14.2 +++ b/MYKeychainItem.h	Sat Apr 04 22:56:13 2009 -0700
    14.3 @@ -10,6 +10,11 @@
    14.4  #import <Security/Security.h>
    14.5  @class MYKeychain;
    14.6  
    14.7 +
    14.8 +/** Error domain for CSSM (low-level crypto) errors */
    14.9 +extern NSString* const MYCSSMErrorDomain;
   14.10 +
   14.11 +
   14.12  #if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
   14.13  typedef CFTypeRef MYKeychainItemRef;
   14.14  #else
   14.15 @@ -17,17 +22,18 @@
   14.16  #endif
   14.17  
   14.18  
   14.19 -/** Abstract base class for keychain items: MYPublicKey, MYKeyPair and MYCertificate. */
   14.20 +/** Abstract base class for keychain items.
   14.21 +    Direct subclasses are MYKey and MYCertificate. */
   14.22  @interface MYKeychainItem : NSObject
   14.23  {
   14.24      @private
   14.25      MYKeychainItemRef _itemRef;
   14.26  }
   14.27  
   14.28 -- (id) initWithKeychainItemRef: (MYKeychainItemRef)itemRef;
   14.29 -
   14.30 +/** The Keychain item reference that this object represents. */
   14.31  @property (readonly) MYKeychainItemRef keychainItemRef;
   14.32  
   14.33 +/** The Keychain that contains this object, or nil. */
   14.34  @property (readonly) MYKeychain *keychain;
   14.35  
   14.36  /** Removes the item from its keychain, if any. */
    15.1 --- a/MYKeychainItem.m	Sat Apr 04 20:42:03 2009 -0700
    15.2 +++ b/MYKeychainItem.m	Sat Apr 04 22:56:13 2009 -0700
    15.3 @@ -54,6 +54,11 @@
    15.4      return CFHash(_itemRef);
    15.5  }
    15.6  
    15.7 +- (NSString*) description {
    15.8 +    return $sprintf(@"%@[%p]", [self class], _itemRef);     //FIX: Can we do anything better?
    15.9 +}
   15.10 +
   15.11 +
   15.12  - (NSArray*) _itemList {
   15.13      return $array((id)_itemRef);
   15.14  }
    16.1 --- a/MYPublicKey-iPhone.m	Sat Apr 04 20:42:03 2009 -0700
    16.2 +++ b/MYPublicKey-iPhone.m	Sat Apr 04 22:56:13 2009 -0700
    16.3 @@ -13,6 +13,7 @@
    16.4  
    16.5  #import "MYDigest.h"
    16.6  #import "MYErrorUtils.h"
    16.7 +#import <CommonCrypto/CommonDigest.h>
    16.8  
    16.9  
   16.10  @implementation MYPublicKey
    17.1 --- a/MYPublicKey.h	Sat Apr 04 20:42:03 2009 -0700
    17.2 +++ b/MYPublicKey.h	Sat Apr 04 22:56:13 2009 -0700
    17.3 @@ -14,13 +14,12 @@
    17.4  #endif
    17.5  
    17.6  
    17.7 -/** Error domain for CSSM (low-level crypto) errors */
    17.8 -extern NSString* const MYCSSMErrorDomain;
    17.9 -
   17.10 -
   17.11 -/** A public key, which can be used for encrypting data and verifying signatures. */
   17.12 +/** A public key, which can be used for encrypting data and verifying signatures.
   17.13 +    MYPublicKeys are created as part of generating a MYKeyPair, 
   17.14 +    or by being imported into a MYKeychain. */
   17.15  @interface MYPublicKey : MYKey <MYEncryption>
   17.16  {
   17.17 +    @private
   17.18      MYSHA1Digest *_digest;
   17.19  }
   17.20  
   17.21 @@ -33,7 +32,7 @@
   17.22  @property (readonly) MYPublicKey *asPublicKey;
   17.23  
   17.24  /** Encrypts a short piece of data using this key, returning the raw encrypted result.
   17.25 -    RSA can encrypt only <i>short</i> pieces of data, smaller than the key size in bits; this
   17.26 +    An RSA key can encrypt only blocks smaller than its own key size; this
   17.27      method will fail and return nil if the data is too long.
   17.28      RSA encryption is also much slower than regular symmetric-key encryption, so the correct
   17.29      way to encrypt a large block of data using a public key is to first generate a random
   17.30 @@ -43,9 +42,10 @@
   17.31  - (NSData*) encryptData: (NSData*)data;
   17.32  
   17.33  /** Verifies the signature of a block of data. If the result is YES, you can be assured that
   17.34 -    the signature was generated from the data using this key's matching private key.
   17.35 +    the signature was generated from the data by using this key's matching private key.
   17.36      If the result is NO, something is wrong: either the data or the signature was modified,
   17.37 -    or the signature was generated by a different private key. */
   17.38 +    or the signature was generated by a different private key.
   17.39 +    (What's actually verified using RSA is the SHA-256 digest of the data.) */
   17.40  - (BOOL) verifySignature: (NSData*)signature ofData: (NSData*)data;
   17.41      
   17.42  @end
    18.1 --- a/MYPublicKey.m	Sat Apr 04 20:42:03 2009 -0700
    18.2 +++ b/MYPublicKey.m	Sat Apr 04 22:56:13 2009 -0700
    18.3 @@ -94,8 +94,9 @@
    18.4  - (BOOL) verifySignature: (NSData*)signature ofData: (NSData*)data {
    18.5      Assert(data);
    18.6      Assert(signature);
    18.7 -    uint8_t digest[CC_SHA1_DIGEST_LENGTH];
    18.8 -    CC_SHA1(data.bytes,data.length, digest);
    18.9 +    uint8_t digest[CC_SHA256_DIGEST_LENGTH];
   18.10 +    CC_SHA256(data.bytes,data.length, digest);
   18.11 +    
   18.12      CSSM_CC_HANDLE ccHandle = cssmCreateSignatureContext(self.keyRef);
   18.13      if (!ccHandle) return NO;
   18.14      CSSM_DATA original = {data.length, (void*)data.bytes};
    19.1 --- a/MYSymmetricKey.h	Sat Apr 04 20:42:03 2009 -0700
    19.2 +++ b/MYSymmetricKey.h	Sat Apr 04 22:56:13 2009 -0700
    19.3 @@ -12,9 +12,17 @@
    19.4  
    19.5  @interface MYSymmetricKey : MYKey <MYEncryption, MYDecryption>
    19.6  
    19.7 +/** Initializes a symmetric key from the given key data and algorithm. */
    19.8 +- (id) initWithKeyData: (NSData*)keyData
    19.9 +             algorithm: (CCAlgorithm)algorithm;
   19.10 +
   19.11 +/** Randomly generates a new symmetric key, using the given algorithm and key-size in bits.
   19.12 +    The key is not added to any keychain; if you want to keep the key persistently, use
   19.13 +    the method of the same name in the MYKeychain class. */
   19.14  + (MYSymmetricKey*) generateSymmetricKeyOfSize: (unsigned)keySizeInBits
   19.15                                       algorithm: (CCAlgorithm)algorithm;
   19.16  
   19.17 +/** The key's algorithm. */
   19.18  @property (readonly) CCAlgorithm algorithm;
   19.19  
   19.20  @end
    20.1 --- a/MYSymmetricKey.m	Sat Apr 04 20:42:03 2009 -0700
    20.2 +++ b/MYSymmetricKey.m	Sat Apr 04 22:56:13 2009 -0700
    20.3 @@ -37,29 +37,56 @@
    20.4  @implementation MYSymmetricKey
    20.5  
    20.6  
    20.7 +- (id) _initWithKeyData: (NSData*)keyData
    20.8 +              algorithm: (CCAlgorithm)algorithm
    20.9 +             inKeychain: (MYKeychain*)keychain
   20.10 +{
   20.11 +    Assert(algorithm <= kCCAlgorithmRC4);
   20.12 +    Assert(keyData);
   20.13 +    SecKeyRef keyRef = NULL;
   20.14 +#if USE_IPHONE_API
   20.15 +    unsigned keySizeInBits = keyData.length / 8;
   20.16 +    NSDictionary *keyAttrs = $dict( {(id)kSecClass, (id)kSecClassKey},
   20.17 +                                    {(id)kSecAttrKeyClass, (id)kSecAttrKeyClassSymmetric},
   20.18 +                                    {(id)kSecAttrKeyType, $object(kCSSMAlgorithms[algorithm])},
   20.19 +                                    {(id)kSecAttrKeySizeInBits, $object(keySizeInBits)},
   20.20 +                                    {(id)kSecAttrEffectiveKeySize, $object(keySizeInBits)},
   20.21 +                                    {(id)kSecAttrIsPermanent, keychain ?$true :$false},
   20.22 +                                    {(id)kSecValueData, keyData} );
   20.23 +    if (!check(SecItemAdd((CFDictionaryRef)keyAttrs, (CFTypeRef*)&keyRef), @"SecItemAdd")) {
   20.24 +        [self release];
   20.25 +        return nil;
   20.26 +    }
   20.27 +#else
   20.28 +    Assert(NO,@"Unimplemented"); //FIX
   20.29 +#endif
   20.30 +    self = [self initWithKeyRef: keyRef];
   20.31 +    CFRelease(keyRef);
   20.32 +    return self;
   20.33 +}
   20.34 +
   20.35 +- (id) initWithKeyData: (NSData*)keyData
   20.36 +             algorithm: (CCAlgorithm)algorithm
   20.37 +{
   20.38 +    return [self _initWithKeyData: keyData algorithm: algorithm inKeychain: nil];
   20.39 +}
   20.40 +
   20.41  + (MYSymmetricKey*) _generateSymmetricKeyOfSize: (unsigned)keySizeInBits
   20.42                                        algorithm: (CCAlgorithm)algorithm
   20.43                                       inKeychain: (MYKeychain*)keychain
   20.44  {
   20.45 +#if USE_IPHONE_API
   20.46 +    return [[[self alloc] _initWithKeyData: [MYCryptor randomKeyOfLength: (keySizeInBits+7)/8]
   20.47 +                                 algorithm: algorithm
   20.48 +                                inKeychain: keychain]
   20.49 +                    autorelease];
   20.50 +#else
   20.51      Assert(algorithm <= kCCAlgorithmRC4);
   20.52 -    SecKeyRef keyRef = NULL;
   20.53 -    
   20.54 -#if USE_IPHONE_API
   20.55 -    NSData *keyBits = [MYCryptor randomKeyOfLength: (keySizeInBits+7)/8];
   20.56 -    NSDictionary *keyAttrs = $dict( {(id)kSecClass, (id)kSecClassKey},
   20.57 -                                    {(id)kSecAttrKeyType, $object(kCSSMAlgorithms[algorithm])},
   20.58 -                                    {(id)kSecAttrKeySizeInBits, $object(keySizeInBits)},
   20.59 -                                    {(id)kSecAttrEffectiveKeySize, $object(keySizeInBits)},
   20.60 -                                    {(id)kSecAttrIsPermanent, keychain ?$true :$false},
   20.61 -                                    {(id)kSecValueData, keyBits} );
   20.62 -    if (!check(SecItemAdd((CFDictionaryRef)keyAttrs, (CFTypeRef*)&keyRef), @"SecItemAdd"))
   20.63 -        return nil;
   20.64 -    
   20.65 -#else
   20.66      CSSM_KEYATTR_FLAGS flags = CSSM_KEYATTR_EXTRACTABLE;
   20.67      if (keychain)
   20.68          flags |= CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_SENSITIVE | CSSM_KEYATTR_EXTRACTABLE;
   20.69      CSSM_KEYUSE usage = CSSM_KEYUSE_ANY;
   20.70 +    SecKeyRef keyRef = NULL;
   20.71      if (!check(SecKeyGenerate(keychain.keychainRefOrDefault,    // nil kc generates a transient key
   20.72                                kCSSMAlgorithms[algorithm],
   20.73                                keySizeInBits, 
   20.74 @@ -67,8 +94,8 @@
   20.75                 @"SecKeyGenerate")) {
   20.76          return nil;
   20.77      }
   20.78 +    return [[[self alloc] initWithKeyRef: keyRef] autorelease];
   20.79  #endif
   20.80 -    return [[[self alloc] initWithKeyRef: keyRef] autorelease];
   20.81  }
   20.82  
   20.83  + (MYSymmetricKey*) generateSymmetricKeyOfSize: (unsigned)keySizeInBits