Code cleanup, more header comments.
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