More work, mostly on documentation.
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, ¶ms);
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 + ¶ms, &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 + */