Initial checkin. Passes tests on Mac and in iPhone simulator.
authorsnej@snej.local
Sat Apr 04 20:42:03 2009 -0700 (2009-04-04)
changeset 00a6527af039b
child 1 60e4cbbb5128
Initial checkin. Passes tests on Mac and in iPhone simulator.
.hgignore
MYCertificate-iPhone.m
MYCertificate.h
MYCertificate.m
MYCrypto-iPhone.xcodeproj/project.pbxproj
MYCrypto.xcconfig
MYCrypto.xcodeproj/TemplateIcon.icns
MYCrypto.xcodeproj/project.pbxproj
MYCryptoTest.m
MYCrypto_Debug.xcconfig
MYCrypto_Private.h
MYCrypto_main.m
MYCryptor.h
MYCryptor.m
MYDigest.h
MYDigest.m
MYKey-iPhone.m
MYKey.h
MYKey.m
MYKeyPair-iPhone.m
MYKeyPair.h
MYKeyPair.m
MYKeychain-iPhone.m
MYKeychain.h
MYKeychain.m
MYKeychainItem.h
MYKeychainItem.m
MYPublicKey-iPhone.m
MYPublicKey.h
MYPublicKey.m
MYSymmetricKey.h
MYSymmetricKey.m
iPhone/MYCrypto_iPhone-Info.plist
iPhone/MYCrypto_iPhoneAppDelegate.h
iPhone/MYCrypto_iPhoneAppDelegate.m
iPhone/MYCrypto_iPhone_main.m
iPhone/MainWindow.xib
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/.hgignore	Sat Apr 04 20:42:03 2009 -0700
     1.3 @@ -0,0 +1,10 @@
     1.4 +syntax: glob
     1.5 +.DS_Store
     1.6 +build
     1.7 +Documentation
     1.8 +Doxyfile
     1.9 +.svn
    1.10 +*.pbxuser
    1.11 +*.perspectivev3
    1.12 +*.mpkg
    1.13 +*.framework
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/MYCertificate-iPhone.m	Sat Apr 04 20:42:03 2009 -0700
     2.3 @@ -0,0 +1,77 @@
     2.4 +//
     2.5 +//  MYCertificate-iPhone.m
     2.6 +//  MYCrypto-iPhone
     2.7 +//
     2.8 +//  Created by Jens Alfke on 3/30/09.
     2.9 +//  Copyright 2009 Jens Alfke. All rights reserved.
    2.10 +//
    2.11 +
    2.12 +#import "MYCertificate.h"
    2.13 +#import "MYCrypto_Private.h"
    2.14 +
    2.15 +#if USE_IPHONE_API
    2.16 +
    2.17 +
    2.18 +@implementation MYCertificate
    2.19 +
    2.20 +
    2.21 +/** Creates a MYCertificate object for an existing Keychain certificate reference. */
    2.22 +- (id) initWithCertificateRef: (SecCertificateRef)certificateRef {
    2.23 +    self = [super initWithKeychainItemRef: (SecKeychainItemRef)certificateRef];
    2.24 +    if (self) {
    2.25 +        _certificateRef = certificateRef;     // superclass has already CFRetained it
    2.26 +    }
    2.27 +    return self;
    2.28 +}
    2.29 +
    2.30 +/** Creates a MYCertificate object from exported key data, but does not add it to any keychain. */
    2.31 +- (id) initWithCertificateData: (NSData*)data
    2.32 +{
    2.33 +    SecCertificateRef certificateRef = SecCertificateCreateWithData(NULL, (CFDataRef)data);
    2.34 +    self = [self initWithCertificateRef: certificateRef];
    2.35 +    CFRelease(certificateRef);
    2.36 +    return self;
    2.37 +}
    2.38 +
    2.39 +
    2.40 +@synthesize certificateRef=_certificateRef;
    2.41 +
    2.42 +- (NSData*) certificateData {
    2.43 +    CFDataRef data = SecCertificateCopyData(_certificateRef);
    2.44 +    return data ?[(id)CFMakeCollectable(data) autorelease] :nil;
    2.45 +}
    2.46 +
    2.47 +- (MYPublicKey*) publicKey {
    2.48 +    SecTrustRef trust = NULL;
    2.49 +    SecPolicyRef policy = SecPolicyCreateBasicX509();
    2.50 +    OSStatus err = SecTrustCreateWithCertificates((CFArrayRef)$array((id)_certificateRef),
    2.51 +                                                  policy,
    2.52 +                                                  &trust);
    2.53 +    CFRelease(policy);
    2.54 +    if (!check(err,@"SecTrustCreateWithCertificates"))
    2.55 +        return nil;
    2.56 +    
    2.57 +    MYPublicKey *key = nil;
    2.58 +    SecKeyRef keyRef = SecTrustCopyPublicKey(trust);
    2.59 +    if (keyRef) {
    2.60 +        key = [[[MYPublicKey alloc] initWithKeyRef: keyRef] autorelease];
    2.61 +        CFRelease(keyRef);
    2.62 +    }
    2.63 +    CFRelease(trust);
    2.64 +    return key;
    2.65 +}
    2.66 +
    2.67 +
    2.68 +- (NSString*) commonName {
    2.69 +    CFStringRef name = SecCertificateCopySubjectSummary(_certificateRef);
    2.70 +    return name ?[(id)CFMakeCollectable(name) autorelease] :nil;
    2.71 +}
    2.72 +
    2.73 +- (NSArray*) emailAddresses {
    2.74 +    return nil; //FIX UNIMPLEMENTED
    2.75 +}
    2.76 +
    2.77 +
    2.78 +@end
    2.79 +
    2.80 +#endif USE_IPHONE_API
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/MYCertificate.h	Sat Apr 04 20:42:03 2009 -0700
     3.3 @@ -0,0 +1,56 @@
     3.4 +//
     3.5 +//  MYCertificate.h
     3.6 +//  MYCrypto
     3.7 +//
     3.8 +//  Created by Jens Alfke on 3/26/09.
     3.9 +//  Copyright 2009 Jens Alfke. All rights reserved.
    3.10 +//
    3.11 +
    3.12 +#import "MYKeychainItem.h"
    3.13 +
    3.14 +#if !TARGET_OS_IPHONE
    3.15 +#import <Security/cssmtype.h>
    3.16 +#endif
    3.17 +
    3.18 +@class MYPublicKey;
    3.19 +
    3.20 +
    3.21 +/** An X.509 certificate. */
    3.22 +@interface MYCertificate : MYKeychainItem {
    3.23 +    SecCertificateRef _certificateRef;
    3.24 +}
    3.25 +
    3.26 +/** Creates a MYCertificate object for an existing Keychain certificate reference. */
    3.27 +- (id) initWithCertificateRef: (SecCertificateRef)certificateRef;
    3.28 +
    3.29 +/** Creates a MYCertificate object from exported key data, but does not add it to any keychain. */
    3.30 +- (id) initWithCertificateData: (NSData*)data;
    3.31 +
    3.32 +#if !TARGET_OS_IPHONE
    3.33 +/** Creates a MYCertificate object from exported key data, but does not add it to any keychain. */
    3.34 +- (id) initWithCertificateData: (NSData*)data
    3.35 +                          type: (CSSM_CERT_TYPE) type
    3.36 +                      encoding: (CSSM_CERT_ENCODING) encoding;
    3.37 +#endif
    3.38 +
    3.39 +/** The Keychain object reference for this key. */
    3.40 +@property (readonly) SecCertificateRef certificateRef;
    3.41 +
    3.42 +/** The certificate's data. */
    3.43 +@property (readonly) NSData *certificateData;
    3.44 +
    3.45 +/** The certificate's public key. */
    3.46 +@property (readonly) MYPublicKey *publicKey;
    3.47 +
    3.48 +@property (readonly) NSString *commonName;
    3.49 +@property (readonly) NSArray *emailAddresses;
    3.50 +
    3.51 +#if !TARGET_OS_IPHONE
    3.52 +/** Finds the current 'preferred' certificate for the given name string. */
    3.53 ++ (MYCertificate*) preferredCertificateForName: (NSString*)name;
    3.54 +
    3.55 +/** Associates the receiver as the preferred certificate for the given name string. */
    3.56 +- (BOOL) setPreferredCertificateForName: (NSString*)name;
    3.57 +#endif
    3.58 +
    3.59 +@end
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/MYCertificate.m	Sat Apr 04 20:42:03 2009 -0700
     4.3 @@ -0,0 +1,104 @@
     4.4 +//
     4.5 +//  MYCertificate.m
     4.6 +//  MYCrypto
     4.7 +//
     4.8 +//  Created by Jens Alfke on 3/26/09.
     4.9 +//  Copyright 2009 Jens Alfke. All rights reserved.
    4.10 +//
    4.11 +
    4.12 +#import "MYCertificate.h"
    4.13 +#import "MYCrypto_Private.h"
    4.14 +
    4.15 +#if !USE_IPHONE_API
    4.16 +
    4.17 +
    4.18 +@implementation MYCertificate
    4.19 +
    4.20 +
    4.21 +/** Creates a MYCertificate object for an existing Keychain certificate reference. */
    4.22 +- (id) initWithCertificateRef: (SecCertificateRef)certificateRef {
    4.23 +    self = [super initWithKeychainItemRef: (SecKeychainItemRef)certificateRef];
    4.24 +    if (self) {
    4.25 +        _certificateRef = certificateRef;     // superclass has already CFRetained it
    4.26 +    }
    4.27 +    return self;
    4.28 +}
    4.29 +
    4.30 +/** Creates a MYCertificate object from exported key data, but does not add it to any keychain. */
    4.31 +- (id) initWithCertificateData: (NSData*)data
    4.32 +                          type: (CSSM_CERT_TYPE) type
    4.33 +                      encoding: (CSSM_CERT_ENCODING) encoding
    4.34 +{
    4.35 +    Assert(data);
    4.36 +    CSSM_DATA cssmData = {.Data=(void*)data.bytes, .Length=data.length};
    4.37 +    SecCertificateRef certificateRef = NULL;
    4.38 +    if (!check(SecCertificateCreateFromData(&cssmData, type, encoding, &certificateRef),
    4.39 +        @"SecCertificateCreateFromData")) {
    4.40 +        [self release];
    4.41 +        return nil;
    4.42 +    }
    4.43 +    self = [self initWithCertificateRef: certificateRef];
    4.44 +    CFRelease(certificateRef);
    4.45 +    return self;
    4.46 +}
    4.47 +
    4.48 +- (id) initWithCertificateData: (NSData*)data {
    4.49 +    return [self initWithCertificateData: data 
    4.50 +                                    type: CSSM_CERT_X_509v3 
    4.51 +                                encoding: CSSM_CERT_ENCODING_BER];
    4.52 +}
    4.53 +
    4.54 ++ (MYCertificate*) preferredCertificateForName: (NSString*)name {
    4.55 +    SecCertificateRef certRef = NULL;
    4.56 +    if (!check(SecCertificateCopyPreference((CFStringRef)name, 0, &certRef),
    4.57 +               @"SecCertificateCopyPreference"))
    4.58 +        return nil;
    4.59 +    return [[[MYCertificate alloc] initWithCertificateRef: certRef] autorelease];
    4.60 +}
    4.61 +
    4.62 +- (BOOL) setPreferredCertificateForName: (NSString*)name {
    4.63 +    return check(SecCertificateSetPreference(_certificateRef, (CFStringRef)name, 0, NULL),
    4.64 +                 @"SecCertificateSetPreference");
    4.65 +}
    4.66 +
    4.67 +@synthesize certificateRef=_certificateRef;
    4.68 +
    4.69 +- (NSData*) certificateData {
    4.70 +    CSSM_DATA cssmData;
    4.71 +    if (!check(SecCertificateGetData(_certificateRef, &cssmData),
    4.72 +               @"SecCertificateGetData"))
    4.73 +        return nil;
    4.74 +    return [NSData dataWithBytes: cssmData.Data length: cssmData.Length];
    4.75 +}
    4.76 +
    4.77 +- (MYPublicKey*) publicKey {
    4.78 +    SecKeyRef keyRef = NULL;
    4.79 +    if (!check(SecCertificateCopyPublicKey(_certificateRef, &keyRef),
    4.80 +               @"SecCertificateCopyPublicKey") || !keyRef)
    4.81 +        return nil;
    4.82 +    MYPublicKey *key = [[[MYPublicKey alloc] initWithKeyRef: keyRef] autorelease];
    4.83 +    CFRelease(keyRef);
    4.84 +    return key;
    4.85 +}
    4.86 +
    4.87 +- (NSString*) commonName {
    4.88 +    CFStringRef name = NULL;
    4.89 +    if (!check(SecCertificateCopyCommonName(_certificateRef, &name),
    4.90 +               @"SecCertificateCopyCommonName") || !name)
    4.91 +        return nil;
    4.92 +    return [(id)CFMakeCollectable(name) autorelease];
    4.93 +}
    4.94 +
    4.95 +- (NSArray*) emailAddresses {
    4.96 +    CFArrayRef addrs = NULL;
    4.97 +    if (!check(SecCertificateCopyEmailAddresses(_certificateRef, &addrs),
    4.98 +               @"SecCertificateCopyEmailAddresses") || !addrs)
    4.99 +        return nil;
   4.100 +    return [(id)CFMakeCollectable(addrs) autorelease];
   4.101 +}
   4.102 +
   4.103 +
   4.104 +@end
   4.105 +
   4.106 +
   4.107 +#endif !USE_IPHONE_API
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/MYCrypto-iPhone.xcodeproj/project.pbxproj	Sat Apr 04 20:42:03 2009 -0700
     5.3 @@ -0,0 +1,367 @@
     5.4 +// !$*UTF8*$!
     5.5 +{
     5.6 +	archiveVersion = 1;
     5.7 +	classes = {
     5.8 +	};
     5.9 +	objectVersion = 45;
    5.10 +	objects = {
    5.11 +
    5.12 +/* Begin PBXBuildFile section */
    5.13 +		1D3623260D0F684500981E51 /* MYCrypto_iPhoneAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D3623250D0F684500981E51 /* MYCrypto_iPhoneAppDelegate.m */; };
    5.14 +		1D60589B0D05DD56006BFB54 /* MYCrypto_iPhone_main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* MYCrypto_iPhone_main.m */; };
    5.15 +		1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; };
    5.16 +		1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */; };
    5.17 +		273391A30F81E5E9009414D9 /* MYKeyPair-iPhone.m in Sources */ = {isa = PBXBuildFile; fileRef = 273391A20F81E5E9009414D9 /* MYKeyPair-iPhone.m */; };
    5.18 +		273391A50F81E606009414D9 /* MYPublicKey-iPhone.m in Sources */ = {isa = PBXBuildFile; fileRef = 273391A40F81E606009414D9 /* MYPublicKey-iPhone.m */; };
    5.19 +		273391CD0F81EC70009414D9 /* MYCertificate-iPhone.m in Sources */ = {isa = PBXBuildFile; fileRef = 273391CC0F81EC70009414D9 /* MYCertificate-iPhone.m */; };
    5.20 +		273392120F8283B8009414D9 /* MYKeychain-iPhone.m in Sources */ = {isa = PBXBuildFile; fileRef = 273392110F8283B8009414D9 /* MYKeychain-iPhone.m */; };
    5.21 +		276FB13F0F84090900CB326E /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 276FB13E0F84090900CB326E /* Security.framework */; };
    5.22 +		276FB16E0F84152B00CB326E /* MYCryptoTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 276FB16D0F84152B00CB326E /* MYCryptoTest.m */; };
    5.23 +		276FB3190F856AA700CB326E /* MYPublicKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 276FB3180F856AA700CB326E /* MYPublicKey.m */; };
    5.24 +		276FB3390F856AC300CB326E /* MYKeyPair.m in Sources */ = {isa = PBXBuildFile; fileRef = 276FB3380F856AC300CB326E /* MYKeyPair.m */; };
    5.25 +		276FB33B0F856ACB00CB326E /* MYKeychain.m in Sources */ = {isa = PBXBuildFile; fileRef = 276FB33A0F856ACB00CB326E /* MYKeychain.m */; };
    5.26 +		276FB34B0F856CA400CB326E /* MYCertificate.m in Sources */ = {isa = PBXBuildFile; fileRef = 276FB34A0F856CA400CB326E /* MYCertificate.m */; };
    5.27 +		27A430120F87C6C10063D362 /* MYKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 27E823110F81D56E0019BE60 /* MYKey.m */; };
    5.28 +		27A430140F87C6D50063D362 /* MYSymmetricKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 27A430130F87C6D50063D362 /* MYSymmetricKey.m */; };
    5.29 +		27E823210F81D56E0019BE60 /* MYCryptor.m in Sources */ = {isa = PBXBuildFile; fileRef = 27E8230F0F81D56E0019BE60 /* MYCryptor.m */; };
    5.30 +		27E823240F81D56E0019BE60 /* MYKeychainItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 27E823150F81D56E0019BE60 /* MYKeychainItem.m */; };
    5.31 +		27E823270F81D56E0019BE60 /* MYDigest.m in Sources */ = {isa = PBXBuildFile; fileRef = 27E8231C0F81D56E0019BE60 /* MYDigest.m */; };
    5.32 +		27E823290F81D56E0019BE60 /* MYCrypto.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 27E8231E0F81D56E0019BE60 /* MYCrypto.xcconfig */; };
    5.33 +		27E8232A0F81D56E0019BE60 /* MYCrypto_Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 27E8231F0F81D56E0019BE60 /* MYCrypto_Debug.xcconfig */; };
    5.34 +		27E823370F81D5760019BE60 /* CollectionUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 27E8232D0F81D5760019BE60 /* CollectionUtils.m */; };
    5.35 +		27E823380F81D5760019BE60 /* ExceptionUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 27E8232F0F81D5760019BE60 /* ExceptionUtils.m */; };
    5.36 +		27E823390F81D5760019BE60 /* Logging.m in Sources */ = {isa = PBXBuildFile; fileRef = 27E823310F81D5760019BE60 /* Logging.m */; };
    5.37 +		27E8233A0F81D5760019BE60 /* Test.m in Sources */ = {isa = PBXBuildFile; fileRef = 27E823330F81D5760019BE60 /* Test.m */; };
    5.38 +		27E8233B0F81D5760019BE60 /* MYErrorUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 27E823350F81D5760019BE60 /* MYErrorUtils.m */; };
    5.39 +		27E8233C0F81D5760019BE60 /* MYError_CSSMErrorDomain.strings in Resources */ = {isa = PBXBuildFile; fileRef = 27E823360F81D5760019BE60 /* MYError_CSSMErrorDomain.strings */; };
    5.40 +		27FE453F0F87CC8500A86D63 /* MYKey-iPhone.m in Sources */ = {isa = PBXBuildFile; fileRef = 27FE453E0F87CC8500A86D63 /* MYKey-iPhone.m */; };
    5.41 +		288765FD0DF74451002DB57D /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288765FC0DF74451002DB57D /* CoreGraphics.framework */; };
    5.42 +		28AD733F0D9D9553002E5188 /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 28AD733E0D9D9553002E5188 /* MainWindow.xib */; };
    5.43 +/* End PBXBuildFile section */
    5.44 +
    5.45 +/* Begin PBXFileReference section */
    5.46 +		1D30AB110D05D00D00671497 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
    5.47 +		1D3623240D0F684500981E51 /* MYCrypto_iPhoneAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYCrypto_iPhoneAppDelegate.h; sourceTree = "<group>"; };
    5.48 +		1D3623250D0F684500981E51 /* MYCrypto_iPhoneAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYCrypto_iPhoneAppDelegate.m; sourceTree = "<group>"; };
    5.49 +		1D6058910D05DD3D006BFB54 /* MYCrypto-iPhone.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "MYCrypto-iPhone.app"; sourceTree = BUILT_PRODUCTS_DIR; };
    5.50 +		1DF5F4DF0D08C38300B7A737 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
    5.51 +		273391A20F81E5E9009414D9 /* MYKeyPair-iPhone.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MYKeyPair-iPhone.m"; sourceTree = "<group>"; };
    5.52 +		273391A40F81E606009414D9 /* MYPublicKey-iPhone.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MYPublicKey-iPhone.m"; sourceTree = "<group>"; };
    5.53 +		273391CC0F81EC70009414D9 /* MYCertificate-iPhone.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MYCertificate-iPhone.m"; sourceTree = "<group>"; };
    5.54 +		273392110F8283B8009414D9 /* MYKeychain-iPhone.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MYKeychain-iPhone.m"; sourceTree = "<group>"; };
    5.55 +		276FB13E0F84090900CB326E /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
    5.56 +		276FB16D0F84152B00CB326E /* MYCryptoTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYCryptoTest.m; sourceTree = "<group>"; };
    5.57 +		276FB3180F856AA700CB326E /* MYPublicKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYPublicKey.m; sourceTree = "<group>"; };
    5.58 +		276FB3380F856AC300CB326E /* MYKeyPair.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYKeyPair.m; sourceTree = "<group>"; };
    5.59 +		276FB33A0F856ACB00CB326E /* MYKeychain.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYKeychain.m; sourceTree = "<group>"; };
    5.60 +		276FB34A0F856CA400CB326E /* MYCertificate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYCertificate.m; sourceTree = "<group>"; };
    5.61 +		27A430130F87C6D50063D362 /* MYSymmetricKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYSymmetricKey.m; sourceTree = "<group>"; };
    5.62 +		27A430150F87C6DB0063D362 /* MYSymmetricKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYSymmetricKey.h; sourceTree = "<group>"; };
    5.63 +		27E8230C0F81D56E0019BE60 /* MYCertificate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYCertificate.h; sourceTree = "<group>"; };
    5.64 +		27E8230E0F81D56E0019BE60 /* MYCryptor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYCryptor.h; sourceTree = "<group>"; };
    5.65 +		27E8230F0F81D56E0019BE60 /* MYCryptor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYCryptor.m; sourceTree = "<group>"; };
    5.66 +		27E823100F81D56E0019BE60 /* MYKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYKey.h; sourceTree = "<group>"; };
    5.67 +		27E823110F81D56E0019BE60 /* MYKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYKey.m; sourceTree = "<group>"; };
    5.68 +		27E823120F81D56E0019BE60 /* MYKeychain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYKeychain.h; sourceTree = "<group>"; };
    5.69 +		27E823140F81D56E0019BE60 /* MYKeychainItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYKeychainItem.h; sourceTree = "<group>"; };
    5.70 +		27E823150F81D56E0019BE60 /* MYKeychainItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYKeychainItem.m; sourceTree = "<group>"; };
    5.71 +		27E823160F81D56E0019BE60 /* MYKeyPair.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYKeyPair.h; sourceTree = "<group>"; };
    5.72 +		27E823180F81D56E0019BE60 /* MYPublicKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYPublicKey.h; sourceTree = "<group>"; };
    5.73 +		27E8231A0F81D56E0019BE60 /* MYCrypto_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYCrypto_Private.h; sourceTree = "<group>"; };
    5.74 +		27E8231B0F81D56E0019BE60 /* MYDigest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYDigest.h; sourceTree = "<group>"; };
    5.75 +		27E8231C0F81D56E0019BE60 /* MYDigest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYDigest.m; sourceTree = "<group>"; };
    5.76 +		27E8231E0F81D56E0019BE60 /* MYCrypto.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = MYCrypto.xcconfig; sourceTree = "<group>"; };
    5.77 +		27E8231F0F81D56E0019BE60 /* MYCrypto_Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = MYCrypto_Debug.xcconfig; sourceTree = "<group>"; };
    5.78 +		27E8232C0F81D5760019BE60 /* CollectionUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CollectionUtils.h; path = ../MYUtilities/CollectionUtils.h; sourceTree = SOURCE_ROOT; };
    5.79 +		27E8232D0F81D5760019BE60 /* CollectionUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CollectionUtils.m; path = ../MYUtilities/CollectionUtils.m; sourceTree = SOURCE_ROOT; };
    5.80 +		27E8232E0F81D5760019BE60 /* ExceptionUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ExceptionUtils.h; path = ../MYUtilities/ExceptionUtils.h; sourceTree = SOURCE_ROOT; };
    5.81 +		27E8232F0F81D5760019BE60 /* ExceptionUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ExceptionUtils.m; path = ../MYUtilities/ExceptionUtils.m; sourceTree = SOURCE_ROOT; };
    5.82 +		27E823300F81D5760019BE60 /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../MYUtilities/Logging.h; sourceTree = SOURCE_ROOT; };
    5.83 +		27E823310F81D5760019BE60 /* Logging.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Logging.m; path = ../MYUtilities/Logging.m; sourceTree = SOURCE_ROOT; };
    5.84 +		27E823320F81D5760019BE60 /* Test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Test.h; path = ../MYUtilities/Test.h; sourceTree = SOURCE_ROOT; };
    5.85 +		27E823330F81D5760019BE60 /* Test.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Test.m; path = ../MYUtilities/Test.m; sourceTree = SOURCE_ROOT; };
    5.86 +		27E823340F81D5760019BE60 /* MYErrorUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MYErrorUtils.h; path = ../MYUtilities/MYErrorUtils.h; sourceTree = SOURCE_ROOT; };
    5.87 +		27E823350F81D5760019BE60 /* MYErrorUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MYErrorUtils.m; path = ../MYUtilities/MYErrorUtils.m; sourceTree = SOURCE_ROOT; };
    5.88 +		27E823360F81D5760019BE60 /* MYError_CSSMErrorDomain.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = MYError_CSSMErrorDomain.strings; path = ../MYUtilities/MYError_CSSMErrorDomain.strings; sourceTree = SOURCE_ROOT; };
    5.89 +		27FE453E0F87CC8500A86D63 /* MYKey-iPhone.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MYKey-iPhone.m"; sourceTree = "<group>"; };
    5.90 +		288765FC0DF74451002DB57D /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
    5.91 +		28AD733E0D9D9553002E5188 /* MainWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MainWindow.xib; sourceTree = "<group>"; };
    5.92 +		29B97316FDCFA39411CA2CEA /* MYCrypto_iPhone_main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYCrypto_iPhone_main.m; sourceTree = "<group>"; };
    5.93 +		8D1107310486CEB800E47090 /* MYCrypto_iPhone-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "MYCrypto_iPhone-Info.plist"; plistStructureDefinitionIdentifier = "com.apple.xcode.plist.structure-definition.iphone.info-plist"; sourceTree = "<group>"; };
    5.94 +/* End PBXFileReference section */
    5.95 +
    5.96 +/* Begin PBXFrameworksBuildPhase section */
    5.97 +		1D60588F0D05DD3D006BFB54 /* Frameworks */ = {
    5.98 +			isa = PBXFrameworksBuildPhase;
    5.99 +			buildActionMask = 2147483647;
   5.100 +			files = (
   5.101 +				1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */,
   5.102 +				1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */,
   5.103 +				288765FD0DF74451002DB57D /* CoreGraphics.framework in Frameworks */,
   5.104 +				276FB13F0F84090900CB326E /* Security.framework in Frameworks */,
   5.105 +			);
   5.106 +			runOnlyForDeploymentPostprocessing = 0;
   5.107 +		};
   5.108 +/* End PBXFrameworksBuildPhase section */
   5.109 +
   5.110 +/* Begin PBXGroup section */
   5.111 +		080E96DDFE201D6D7F000001 /* iPhone */ = {
   5.112 +			isa = PBXGroup;
   5.113 +			children = (
   5.114 +				1D3623240D0F684500981E51 /* MYCrypto_iPhoneAppDelegate.h */,
   5.115 +				1D3623250D0F684500981E51 /* MYCrypto_iPhoneAppDelegate.m */,
   5.116 +				29B97316FDCFA39411CA2CEA /* MYCrypto_iPhone_main.m */,
   5.117 +				28AD733E0D9D9553002E5188 /* MainWindow.xib */,
   5.118 +				8D1107310486CEB800E47090 /* MYCrypto_iPhone-Info.plist */,
   5.119 +			);
   5.120 +			path = iPhone;
   5.121 +			sourceTree = "<group>";
   5.122 +		};
   5.123 +		19C28FACFE9D520D11CA2CBB /* Products */ = {
   5.124 +			isa = PBXGroup;
   5.125 +			children = (
   5.126 +				1D6058910D05DD3D006BFB54 /* MYCrypto-iPhone.app */,
   5.127 +			);
   5.128 +			name = Products;
   5.129 +			sourceTree = "<group>";
   5.130 +		};
   5.131 +		27E8230B0F81D56E0019BE60 /* Source */ = {
   5.132 +			isa = PBXGroup;
   5.133 +			children = (
   5.134 +				27E8230C0F81D56E0019BE60 /* MYCertificate.h */,
   5.135 +				276FB34A0F856CA400CB326E /* MYCertificate.m */,
   5.136 +				273391CC0F81EC70009414D9 /* MYCertificate-iPhone.m */,
   5.137 +				27E8230E0F81D56E0019BE60 /* MYCryptor.h */,
   5.138 +				27E8230F0F81D56E0019BE60 /* MYCryptor.m */,
   5.139 +				27E823100F81D56E0019BE60 /* MYKey.h */,
   5.140 +				27E823110F81D56E0019BE60 /* MYKey.m */,
   5.141 +				27FE453E0F87CC8500A86D63 /* MYKey-iPhone.m */,
   5.142 +				27E823120F81D56E0019BE60 /* MYKeychain.h */,
   5.143 +				276FB33A0F856ACB00CB326E /* MYKeychain.m */,
   5.144 +				273392110F8283B8009414D9 /* MYKeychain-iPhone.m */,
   5.145 +				27E823140F81D56E0019BE60 /* MYKeychainItem.h */,
   5.146 +				27E823150F81D56E0019BE60 /* MYKeychainItem.m */,
   5.147 +				27E823160F81D56E0019BE60 /* MYKeyPair.h */,
   5.148 +				276FB3380F856AC300CB326E /* MYKeyPair.m */,
   5.149 +				273391A20F81E5E9009414D9 /* MYKeyPair-iPhone.m */,
   5.150 +				27E823180F81D56E0019BE60 /* MYPublicKey.h */,
   5.151 +				276FB3180F856AA700CB326E /* MYPublicKey.m */,
   5.152 +				273391A40F81E606009414D9 /* MYPublicKey-iPhone.m */,
   5.153 +				27A430150F87C6DB0063D362 /* MYSymmetricKey.h */,
   5.154 +				27A430130F87C6D50063D362 /* MYSymmetricKey.m */,
   5.155 +				27E8231B0F81D56E0019BE60 /* MYDigest.h */,
   5.156 +				27E8231C0F81D56E0019BE60 /* MYDigest.m */,
   5.157 +				27E8231A0F81D56E0019BE60 /* MYCrypto_Private.h */,
   5.158 +				276FB16D0F84152B00CB326E /* MYCryptoTest.m */,
   5.159 +				27E8231E0F81D56E0019BE60 /* MYCrypto.xcconfig */,
   5.160 +				27E8231F0F81D56E0019BE60 /* MYCrypto_Debug.xcconfig */,
   5.161 +			);
   5.162 +			name = Source;
   5.163 +			sourceTree = "<group>";
   5.164 +		};
   5.165 +		27E8232B0F81D5760019BE60 /* MYUtilities */ = {
   5.166 +			isa = PBXGroup;
   5.167 +			children = (
   5.168 +				27E8232C0F81D5760019BE60 /* CollectionUtils.h */,
   5.169 +				27E8232D0F81D5760019BE60 /* CollectionUtils.m */,
   5.170 +				27E8232E0F81D5760019BE60 /* ExceptionUtils.h */,
   5.171 +				27E8232F0F81D5760019BE60 /* ExceptionUtils.m */,
   5.172 +				27E823300F81D5760019BE60 /* Logging.h */,
   5.173 +				27E823310F81D5760019BE60 /* Logging.m */,
   5.174 +				27E823320F81D5760019BE60 /* Test.h */,
   5.175 +				27E823330F81D5760019BE60 /* Test.m */,
   5.176 +				27E823340F81D5760019BE60 /* MYErrorUtils.h */,
   5.177 +				27E823350F81D5760019BE60 /* MYErrorUtils.m */,
   5.178 +				27E823360F81D5760019BE60 /* MYError_CSSMErrorDomain.strings */,
   5.179 +			);
   5.180 +			name = MYUtilities;
   5.181 +			sourceTree = "<group>";
   5.182 +		};
   5.183 +		29B97314FDCFA39411CA2CEA /* CustomTemplate */ = {
   5.184 +			isa = PBXGroup;
   5.185 +			children = (
   5.186 +				27E8230B0F81D56E0019BE60 /* Source */,
   5.187 +				27E8232B0F81D5760019BE60 /* MYUtilities */,
   5.188 +				080E96DDFE201D6D7F000001 /* iPhone */,
   5.189 +				29B97323FDCFA39411CA2CEA /* Frameworks */,
   5.190 +				19C28FACFE9D520D11CA2CBB /* Products */,
   5.191 +				276FB13E0F84090900CB326E /* Security.framework */,
   5.192 +			);
   5.193 +			name = CustomTemplate;
   5.194 +			sourceTree = "<group>";
   5.195 +		};
   5.196 +		29B97323FDCFA39411CA2CEA /* Frameworks */ = {
   5.197 +			isa = PBXGroup;
   5.198 +			children = (
   5.199 +				1DF5F4DF0D08C38300B7A737 /* UIKit.framework */,
   5.200 +				1D30AB110D05D00D00671497 /* Foundation.framework */,
   5.201 +				288765FC0DF74451002DB57D /* CoreGraphics.framework */,
   5.202 +			);
   5.203 +			name = Frameworks;
   5.204 +			sourceTree = "<group>";
   5.205 +		};
   5.206 +/* End PBXGroup section */
   5.207 +
   5.208 +/* Begin PBXNativeTarget section */
   5.209 +		1D6058900D05DD3D006BFB54 /* MYCrypto-iPhone */ = {
   5.210 +			isa = PBXNativeTarget;
   5.211 +			buildConfigurationList = 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "MYCrypto-iPhone" */;
   5.212 +			buildPhases = (
   5.213 +				1D60588D0D05DD3D006BFB54 /* Resources */,
   5.214 +				1D60588E0D05DD3D006BFB54 /* Sources */,
   5.215 +				1D60588F0D05DD3D006BFB54 /* Frameworks */,
   5.216 +			);
   5.217 +			buildRules = (
   5.218 +			);
   5.219 +			dependencies = (
   5.220 +			);
   5.221 +			name = "MYCrypto-iPhone";
   5.222 +			productName = "MYCrypto-iPhone";
   5.223 +			productReference = 1D6058910D05DD3D006BFB54 /* MYCrypto-iPhone.app */;
   5.224 +			productType = "com.apple.product-type.application";
   5.225 +		};
   5.226 +/* End PBXNativeTarget section */
   5.227 +
   5.228 +/* Begin PBXProject section */
   5.229 +		29B97313FDCFA39411CA2CEA /* Project object */ = {
   5.230 +			isa = PBXProject;
   5.231 +			buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "MYCrypto-iPhone" */;
   5.232 +			compatibilityVersion = "Xcode 3.1";
   5.233 +			hasScannedForEncodings = 1;
   5.234 +			mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */;
   5.235 +			projectDirPath = "";
   5.236 +			projectRoot = "";
   5.237 +			targets = (
   5.238 +				1D6058900D05DD3D006BFB54 /* MYCrypto-iPhone */,
   5.239 +			);
   5.240 +		};
   5.241 +/* End PBXProject section */
   5.242 +
   5.243 +/* Begin PBXResourcesBuildPhase section */
   5.244 +		1D60588D0D05DD3D006BFB54 /* Resources */ = {
   5.245 +			isa = PBXResourcesBuildPhase;
   5.246 +			buildActionMask = 2147483647;
   5.247 +			files = (
   5.248 +				28AD733F0D9D9553002E5188 /* MainWindow.xib in Resources */,
   5.249 +				27E823290F81D56E0019BE60 /* MYCrypto.xcconfig in Resources */,
   5.250 +				27E8232A0F81D56E0019BE60 /* MYCrypto_Debug.xcconfig in Resources */,
   5.251 +				27E8233C0F81D5760019BE60 /* MYError_CSSMErrorDomain.strings in Resources */,
   5.252 +			);
   5.253 +			runOnlyForDeploymentPostprocessing = 0;
   5.254 +		};
   5.255 +/* End PBXResourcesBuildPhase section */
   5.256 +
   5.257 +/* Begin PBXSourcesBuildPhase section */
   5.258 +		1D60588E0D05DD3D006BFB54 /* Sources */ = {
   5.259 +			isa = PBXSourcesBuildPhase;
   5.260 +			buildActionMask = 2147483647;
   5.261 +			files = (
   5.262 +				1D60589B0D05DD56006BFB54 /* MYCrypto_iPhone_main.m in Sources */,
   5.263 +				1D3623260D0F684500981E51 /* MYCrypto_iPhoneAppDelegate.m in Sources */,
   5.264 +				27E823210F81D56E0019BE60 /* MYCryptor.m in Sources */,
   5.265 +				27E823240F81D56E0019BE60 /* MYKeychainItem.m in Sources */,
   5.266 +				27E823270F81D56E0019BE60 /* MYDigest.m in Sources */,
   5.267 +				27E823370F81D5760019BE60 /* CollectionUtils.m in Sources */,
   5.268 +				27E823380F81D5760019BE60 /* ExceptionUtils.m in Sources */,
   5.269 +				27E823390F81D5760019BE60 /* Logging.m in Sources */,
   5.270 +				27E8233A0F81D5760019BE60 /* Test.m in Sources */,
   5.271 +				27E8233B0F81D5760019BE60 /* MYErrorUtils.m in Sources */,
   5.272 +				273391A30F81E5E9009414D9 /* MYKeyPair-iPhone.m in Sources */,
   5.273 +				273391A50F81E606009414D9 /* MYPublicKey-iPhone.m in Sources */,
   5.274 +				273391CD0F81EC70009414D9 /* MYCertificate-iPhone.m in Sources */,
   5.275 +				273392120F8283B8009414D9 /* MYKeychain-iPhone.m in Sources */,
   5.276 +				276FB16E0F84152B00CB326E /* MYCryptoTest.m in Sources */,
   5.277 +				276FB3190F856AA700CB326E /* MYPublicKey.m in Sources */,
   5.278 +				276FB3390F856AC300CB326E /* MYKeyPair.m in Sources */,
   5.279 +				276FB33B0F856ACB00CB326E /* MYKeychain.m in Sources */,
   5.280 +				276FB34B0F856CA400CB326E /* MYCertificate.m in Sources */,
   5.281 +				27A430120F87C6C10063D362 /* MYKey.m in Sources */,
   5.282 +				27A430140F87C6D50063D362 /* MYSymmetricKey.m in Sources */,
   5.283 +				27FE453F0F87CC8500A86D63 /* MYKey-iPhone.m in Sources */,
   5.284 +			);
   5.285 +			runOnlyForDeploymentPostprocessing = 0;
   5.286 +		};
   5.287 +/* End PBXSourcesBuildPhase section */
   5.288 +
   5.289 +/* Begin XCBuildConfiguration section */
   5.290 +		1D6058940D05DD3E006BFB54 /* Debug */ = {
   5.291 +			isa = XCBuildConfiguration;
   5.292 +			baseConfigurationReference = 27E8231F0F81D56E0019BE60 /* MYCrypto_Debug.xcconfig */;
   5.293 +			buildSettings = {
   5.294 +				ALWAYS_SEARCH_USER_PATHS = NO;
   5.295 +				COPY_PHASE_STRIP = NO;
   5.296 +				GCC_DYNAMIC_NO_PIC = NO;
   5.297 +				GCC_OPTIMIZATION_LEVEL = 0;
   5.298 +				GCC_PRECOMPILE_PREFIX_HEADER = YES;
   5.299 +				GCC_PREFIX_HEADER = ../MYUtilities/MYUtilities_Prefix.pch;
   5.300 +				INFOPLIST_FILE = "iPhone/MYCrypto_iPhone-Info.plist";
   5.301 +				PRODUCT_NAME = "MYCrypto-iPhone";
   5.302 +			};
   5.303 +			name = Debug;
   5.304 +		};
   5.305 +		1D6058950D05DD3E006BFB54 /* Release */ = {
   5.306 +			isa = XCBuildConfiguration;
   5.307 +			baseConfigurationReference = 27E8231E0F81D56E0019BE60 /* MYCrypto.xcconfig */;
   5.308 +			buildSettings = {
   5.309 +				ALWAYS_SEARCH_USER_PATHS = NO;
   5.310 +				COPY_PHASE_STRIP = YES;
   5.311 +				GCC_PRECOMPILE_PREFIX_HEADER = YES;
   5.312 +				GCC_PREFIX_HEADER = MYCrypto_iPhone_Prefix.pch;
   5.313 +				INFOPLIST_FILE = "MYCrypto_iPhone-Info.plist";
   5.314 +				PRODUCT_NAME = "MYCrypto-iPhone";
   5.315 +			};
   5.316 +			name = Release;
   5.317 +		};
   5.318 +		C01FCF4F08A954540054247B /* Debug */ = {
   5.319 +			isa = XCBuildConfiguration;
   5.320 +			buildSettings = {
   5.321 +				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
   5.322 +				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: Jens Alfke";
   5.323 +				GCC_C_LANGUAGE_STANDARD = c99;
   5.324 +				GCC_WARN_ABOUT_RETURN_TYPE = YES;
   5.325 +				GCC_WARN_UNUSED_VARIABLE = YES;
   5.326 +				ONLY_ACTIVE_ARCH = YES;
   5.327 +				PREBINDING = NO;
   5.328 +				"PROVISIONING_PROFILE[sdk=iphoneos*]" = "84D61190-B2EB-4F8E-A189-99F18EE9A07E";
   5.329 +				SDKROOT = iphoneos3.0;
   5.330 +			};
   5.331 +			name = Debug;
   5.332 +		};
   5.333 +		C01FCF5008A954540054247B /* Release */ = {
   5.334 +			isa = XCBuildConfiguration;
   5.335 +			buildSettings = {
   5.336 +				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
   5.337 +				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
   5.338 +				GCC_C_LANGUAGE_STANDARD = c99;
   5.339 +				GCC_WARN_ABOUT_RETURN_TYPE = YES;
   5.340 +				GCC_WARN_UNUSED_VARIABLE = YES;
   5.341 +				PREBINDING = NO;
   5.342 +				SDKROOT = iphoneos3.0;
   5.343 +			};
   5.344 +			name = Release;
   5.345 +		};
   5.346 +/* End XCBuildConfiguration section */
   5.347 +
   5.348 +/* Begin XCConfigurationList section */
   5.349 +		1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "MYCrypto-iPhone" */ = {
   5.350 +			isa = XCConfigurationList;
   5.351 +			buildConfigurations = (
   5.352 +				1D6058940D05DD3E006BFB54 /* Debug */,
   5.353 +				1D6058950D05DD3E006BFB54 /* Release */,
   5.354 +			);
   5.355 +			defaultConfigurationIsVisible = 0;
   5.356 +			defaultConfigurationName = Release;
   5.357 +		};
   5.358 +		C01FCF4E08A954540054247B /* Build configuration list for PBXProject "MYCrypto-iPhone" */ = {
   5.359 +			isa = XCConfigurationList;
   5.360 +			buildConfigurations = (
   5.361 +				C01FCF4F08A954540054247B /* Debug */,
   5.362 +				C01FCF5008A954540054247B /* Release */,
   5.363 +			);
   5.364 +			defaultConfigurationIsVisible = 0;
   5.365 +			defaultConfigurationName = Release;
   5.366 +		};
   5.367 +/* End XCConfigurationList section */
   5.368 +	};
   5.369 +	rootObject = 29B97313FDCFA39411CA2CEA /* Project object */;
   5.370 +}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/MYCrypto.xcconfig	Sat Apr 04 20:42:03 2009 -0700
     6.3 @@ -0,0 +1,11 @@
     6.4 +//
     6.5 +//  MYCrypto.xcconfig
     6.6 +//  MYCrypto
     6.7 +//
     6.8 +//  Created by Jens Alfke on 3/28/09.
     6.9 +//  Copyright 2009 Jens Alfke. All rights reserved.
    6.10 +//
    6.11 +
    6.12 +#include "../MYUtilities/MYUtilities.xcconfig"
    6.13 +
    6.14 +GCC_PREFIX_HEADER = ../MYUtilities/MYUtilities_Prefix.pch
     7.1 Binary file MYCrypto.xcodeproj/TemplateIcon.icns has changed
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/MYCrypto.xcodeproj/project.pbxproj	Sat Apr 04 20:42:03 2009 -0700
     8.3 @@ -0,0 +1,307 @@
     8.4 +// !$*UTF8*$!
     8.5 +{
     8.6 +	archiveVersion = 1;
     8.7 +	classes = {
     8.8 +	};
     8.9 +	objectVersion = 45;
    8.10 +	objects = {
    8.11 +
    8.12 +/* Begin PBXBuildFile section */
    8.13 +		27A42CBF0F8578B40063D362 /* MYCryptoTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 27A42CBE0F8578B40063D362 /* MYCryptoTest.m */; };
    8.14 +		27A42D1E0F8586CE0063D362 /* MYKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 27E822A10F81C5660019BE60 /* MYKey.m */; };
    8.15 +		27A42D420F858ED80063D362 /* MYSymmetricKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 27A42D410F858ED80063D362 /* MYSymmetricKey.m */; };
    8.16 +		27CFF4C10F7E8535000B418E /* MYCertificate.m in Sources */ = {isa = PBXBuildFile; fileRef = 27CFF4B20F7E8535000B418E /* MYCertificate.m */; };
    8.17 +		27CFF4C20F7E8535000B418E /* MYCryptor.m in Sources */ = {isa = PBXBuildFile; fileRef = 27CFF4B40F7E8535000B418E /* MYCryptor.m */; };
    8.18 +		27CFF4C30F7E8535000B418E /* MYKeychain.m in Sources */ = {isa = PBXBuildFile; fileRef = 27CFF4B60F7E8535000B418E /* MYKeychain.m */; };
    8.19 +		27CFF4C40F7E8535000B418E /* MYKeychainItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 27CFF4B80F7E8535000B418E /* MYKeychainItem.m */; };
    8.20 +		27CFF4C60F7E8535000B418E /* MYKeyPair.m in Sources */ = {isa = PBXBuildFile; fileRef = 27CFF4BB0F7E8535000B418E /* MYKeyPair.m */; };
    8.21 +		27CFF4C70F7E8535000B418E /* MYPublicKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 27CFF4BD0F7E8535000B418E /* MYPublicKey.m */; };
    8.22 +		27CFF4C80F7E8535000B418E /* MYDigest.m in Sources */ = {isa = PBXBuildFile; fileRef = 27CFF4C00F7E8535000B418E /* MYDigest.m */; };
    8.23 +		27CFF4D50F7E8726000B418E /* CollectionUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 27CFF4CE0F7E8726000B418E /* CollectionUtils.m */; };
    8.24 +		27CFF4D60F7E8726000B418E /* ExceptionUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 27CFF4D00F7E8726000B418E /* ExceptionUtils.m */; };
    8.25 +		27CFF4D70F7E8726000B418E /* Logging.m in Sources */ = {isa = PBXBuildFile; fileRef = 27CFF4D20F7E8726000B418E /* Logging.m */; };
    8.26 +		27CFF4D80F7E8726000B418E /* Test.m in Sources */ = {isa = PBXBuildFile; fileRef = 27CFF4D40F7E8726000B418E /* Test.m */; };
    8.27 +		27CFF51F0F7E94AE000B418E /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 27CFF51E0F7E94AE000B418E /* Security.framework */; };
    8.28 +		27CFF5220F7E94DF000B418E /* MYCrypto_main.m in Sources */ = {isa = PBXBuildFile; fileRef = 27CFF5210F7E94DF000B418E /* MYCrypto_main.m */; };
    8.29 +		27CFF5760F7E999B000B418E /* MYErrorUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 27CFF5750F7E999B000B418E /* MYErrorUtils.m */; };
    8.30 +		27E820720F7EA6260019BE60 /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 27E820710F7EA6260019BE60 /* CoreServices.framework */; };
    8.31 +		8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB779EFE84155DC02AAC07 /* Foundation.framework */; };
    8.32 +/* End PBXBuildFile section */
    8.33 +
    8.34 +/* Begin PBXCopyFilesBuildPhase section */
    8.35 +		8DD76F9E0486AA7600D96B5E /* CopyFiles */ = {
    8.36 +			isa = PBXCopyFilesBuildPhase;
    8.37 +			buildActionMask = 8;
    8.38 +			dstPath = /usr/share/man/man1/;
    8.39 +			dstSubfolderSpec = 0;
    8.40 +			files = (
    8.41 +			);
    8.42 +			runOnlyForDeploymentPostprocessing = 1;
    8.43 +		};
    8.44 +/* End PBXCopyFilesBuildPhase section */
    8.45 +
    8.46 +/* Begin PBXFileReference section */
    8.47 +		08FB779EFE84155DC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
    8.48 +		27A42CBE0F8578B40063D362 /* MYCryptoTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYCryptoTest.m; sourceTree = "<group>"; };
    8.49 +		27A42D400F858ED80063D362 /* MYSymmetricKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYSymmetricKey.h; sourceTree = "<group>"; };
    8.50 +		27A42D410F858ED80063D362 /* MYSymmetricKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYSymmetricKey.m; sourceTree = "<group>"; };
    8.51 +		27A42ECC0F8689D30063D362 /* MYCertGen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYCertGen.h; sourceTree = "<group>"; };
    8.52 +		27A42ECD0F8689D30063D362 /* MYCertGen.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYCertGen.m; sourceTree = "<group>"; };
    8.53 +		27CFF4B10F7E8535000B418E /* MYCertificate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYCertificate.h; sourceTree = "<group>"; };
    8.54 +		27CFF4B20F7E8535000B418E /* MYCertificate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYCertificate.m; sourceTree = "<group>"; };
    8.55 +		27CFF4B30F7E8535000B418E /* MYCryptor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYCryptor.h; sourceTree = "<group>"; };
    8.56 +		27CFF4B40F7E8535000B418E /* MYCryptor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYCryptor.m; sourceTree = "<group>"; };
    8.57 +		27CFF4B50F7E8535000B418E /* MYKeychain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYKeychain.h; sourceTree = "<group>"; };
    8.58 +		27CFF4B60F7E8535000B418E /* MYKeychain.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYKeychain.m; sourceTree = "<group>"; };
    8.59 +		27CFF4B70F7E8535000B418E /* MYKeychainItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYKeychainItem.h; sourceTree = "<group>"; };
    8.60 +		27CFF4B80F7E8535000B418E /* MYKeychainItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYKeychainItem.m; sourceTree = "<group>"; };
    8.61 +		27CFF4BA0F7E8535000B418E /* MYKeyPair.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYKeyPair.h; sourceTree = "<group>"; };
    8.62 +		27CFF4BB0F7E8535000B418E /* MYKeyPair.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYKeyPair.m; sourceTree = "<group>"; };
    8.63 +		27CFF4BC0F7E8535000B418E /* MYPublicKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYPublicKey.h; sourceTree = "<group>"; };
    8.64 +		27CFF4BD0F7E8535000B418E /* MYPublicKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYPublicKey.m; sourceTree = "<group>"; };
    8.65 +		27CFF4BE0F7E8535000B418E /* MYCrypto_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYCrypto_Private.h; sourceTree = "<group>"; };
    8.66 +		27CFF4BF0F7E8535000B418E /* MYDigest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYDigest.h; sourceTree = "<group>"; };
    8.67 +		27CFF4C00F7E8535000B418E /* MYDigest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYDigest.m; sourceTree = "<group>"; };
    8.68 +		27CFF4CD0F7E8726000B418E /* CollectionUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CollectionUtils.h; path = ../MYUtilities/CollectionUtils.h; sourceTree = SOURCE_ROOT; };
    8.69 +		27CFF4CE0F7E8726000B418E /* CollectionUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CollectionUtils.m; path = ../MYUtilities/CollectionUtils.m; sourceTree = SOURCE_ROOT; };
    8.70 +		27CFF4CF0F7E8726000B418E /* ExceptionUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ExceptionUtils.h; path = ../MYUtilities/ExceptionUtils.h; sourceTree = SOURCE_ROOT; };
    8.71 +		27CFF4D00F7E8726000B418E /* ExceptionUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ExceptionUtils.m; path = ../MYUtilities/ExceptionUtils.m; sourceTree = SOURCE_ROOT; };
    8.72 +		27CFF4D10F7E8726000B418E /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../MYUtilities/Logging.h; sourceTree = SOURCE_ROOT; };
    8.73 +		27CFF4D20F7E8726000B418E /* Logging.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Logging.m; path = ../MYUtilities/Logging.m; sourceTree = SOURCE_ROOT; };
    8.74 +		27CFF4D30F7E8726000B418E /* Test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Test.h; path = ../MYUtilities/Test.h; sourceTree = SOURCE_ROOT; };
    8.75 +		27CFF4D40F7E8726000B418E /* Test.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Test.m; path = ../MYUtilities/Test.m; sourceTree = SOURCE_ROOT; };
    8.76 +		27CFF5120F7E9212000B418E /* MYCrypto.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = MYCrypto.xcconfig; sourceTree = "<group>"; };
    8.77 +		27CFF51E0F7E94AE000B418E /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
    8.78 +		27CFF5210F7E94DF000B418E /* MYCrypto_main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYCrypto_main.m; sourceTree = "<group>"; };
    8.79 +		27CFF5400F7E9653000B418E /* MYCrypto_Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = MYCrypto_Debug.xcconfig; sourceTree = "<group>"; };
    8.80 +		27CFF5740F7E999B000B418E /* MYErrorUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYErrorUtils.h; sourceTree = "<group>"; };
    8.81 +		27CFF5750F7E999B000B418E /* MYErrorUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYErrorUtils.m; sourceTree = "<group>"; };
    8.82 +		27CFF57C0F7EA117000B418E /* MYError_CSSMErrorDomain.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; path = MYError_CSSMErrorDomain.strings; sourceTree = "<group>"; };
    8.83 +		27E820710F7EA6260019BE60 /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = System/Library/Frameworks/CoreServices.framework; sourceTree = SDKROOT; };
    8.84 +		27E822A00F81C5660019BE60 /* MYKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYKey.h; sourceTree = "<group>"; };
    8.85 +		27E822A10F81C5660019BE60 /* MYKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYKey.m; sourceTree = "<group>"; };
    8.86 +		8DD76FA10486AA7600D96B5E /* MYCrypto */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = MYCrypto; sourceTree = BUILT_PRODUCTS_DIR; };
    8.87 +/* End PBXFileReference section */
    8.88 +
    8.89 +/* Begin PBXFrameworksBuildPhase section */
    8.90 +		8DD76F9B0486AA7600D96B5E /* Frameworks */ = {
    8.91 +			isa = PBXFrameworksBuildPhase;
    8.92 +			buildActionMask = 2147483647;
    8.93 +			files = (
    8.94 +				8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */,
    8.95 +				27CFF51F0F7E94AE000B418E /* Security.framework in Frameworks */,
    8.96 +				27E820720F7EA6260019BE60 /* CoreServices.framework in Frameworks */,
    8.97 +			);
    8.98 +			runOnlyForDeploymentPostprocessing = 0;
    8.99 +		};
   8.100 +/* End PBXFrameworksBuildPhase section */
   8.101 +
   8.102 +/* Begin PBXGroup section */
   8.103 +		08FB7794FE84155DC02AAC07 /* MYCrypto */ = {
   8.104 +			isa = PBXGroup;
   8.105 +			children = (
   8.106 +				08FB7795FE84155DC02AAC07 /* Source */,
   8.107 +				27CFF4CC0F7E86E8000B418E /* MYUtilities */,
   8.108 +				C6859EA2029092E104C91782 /* Documentation */,
   8.109 +				08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */,
   8.110 +				1AB674ADFE9D54B511CA2CBB /* Products */,
   8.111 +				27CFF51E0F7E94AE000B418E /* Security.framework */,
   8.112 +				27E820710F7EA6260019BE60 /* CoreServices.framework */,
   8.113 +			);
   8.114 +			name = MYCrypto;
   8.115 +			sourceTree = "<group>";
   8.116 +		};
   8.117 +		08FB7795FE84155DC02AAC07 /* Source */ = {
   8.118 +			isa = PBXGroup;
   8.119 +			children = (
   8.120 +				27CFF4B10F7E8535000B418E /* MYCertificate.h */,
   8.121 +				27CFF4B20F7E8535000B418E /* MYCertificate.m */,
   8.122 +				27CFF4B30F7E8535000B418E /* MYCryptor.h */,
   8.123 +				27CFF4B40F7E8535000B418E /* MYCryptor.m */,
   8.124 +				27E822A00F81C5660019BE60 /* MYKey.h */,
   8.125 +				27E822A10F81C5660019BE60 /* MYKey.m */,
   8.126 +				27CFF4B50F7E8535000B418E /* MYKeychain.h */,
   8.127 +				27CFF4B60F7E8535000B418E /* MYKeychain.m */,
   8.128 +				27CFF4B70F7E8535000B418E /* MYKeychainItem.h */,
   8.129 +				27CFF4B80F7E8535000B418E /* MYKeychainItem.m */,
   8.130 +				27CFF4BA0F7E8535000B418E /* MYKeyPair.h */,
   8.131 +				27CFF4BB0F7E8535000B418E /* MYKeyPair.m */,
   8.132 +				27CFF4BC0F7E8535000B418E /* MYPublicKey.h */,
   8.133 +				27CFF4BD0F7E8535000B418E /* MYPublicKey.m */,
   8.134 +				27A42D400F858ED80063D362 /* MYSymmetricKey.h */,
   8.135 +				27A42D410F858ED80063D362 /* MYSymmetricKey.m */,
   8.136 +				27CFF4BF0F7E8535000B418E /* MYDigest.h */,
   8.137 +				27CFF4C00F7E8535000B418E /* MYDigest.m */,
   8.138 +				27CFF4BE0F7E8535000B418E /* MYCrypto_Private.h */,
   8.139 +				27A42CBE0F8578B40063D362 /* MYCryptoTest.m */,
   8.140 +				27CFF5210F7E94DF000B418E /* MYCrypto_main.m */,
   8.141 +				27A42ECC0F8689D30063D362 /* MYCertGen.h */,
   8.142 +				27A42ECD0F8689D30063D362 /* MYCertGen.m */,
   8.143 +				27CFF5120F7E9212000B418E /* MYCrypto.xcconfig */,
   8.144 +				27CFF5400F7E9653000B418E /* MYCrypto_Debug.xcconfig */,
   8.145 +			);
   8.146 +			name = Source;
   8.147 +			sourceTree = "<group>";
   8.148 +		};
   8.149 +		08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */ = {
   8.150 +			isa = PBXGroup;
   8.151 +			children = (
   8.152 +				08FB779EFE84155DC02AAC07 /* Foundation.framework */,
   8.153 +			);
   8.154 +			name = "External Frameworks and Libraries";
   8.155 +			sourceTree = "<group>";
   8.156 +		};
   8.157 +		1AB674ADFE9D54B511CA2CBB /* Products */ = {
   8.158 +			isa = PBXGroup;
   8.159 +			children = (
   8.160 +				8DD76FA10486AA7600D96B5E /* MYCrypto */,
   8.161 +			);
   8.162 +			name = Products;
   8.163 +			sourceTree = "<group>";
   8.164 +		};
   8.165 +		27CFF4CC0F7E86E8000B418E /* MYUtilities */ = {
   8.166 +			isa = PBXGroup;
   8.167 +			children = (
   8.168 +				27CFF4CD0F7E8726000B418E /* CollectionUtils.h */,
   8.169 +				27CFF4CE0F7E8726000B418E /* CollectionUtils.m */,
   8.170 +				27CFF4CF0F7E8726000B418E /* ExceptionUtils.h */,
   8.171 +				27CFF4D00F7E8726000B418E /* ExceptionUtils.m */,
   8.172 +				27CFF4D10F7E8726000B418E /* Logging.h */,
   8.173 +				27CFF4D20F7E8726000B418E /* Logging.m */,
   8.174 +				27CFF4D30F7E8726000B418E /* Test.h */,
   8.175 +				27CFF4D40F7E8726000B418E /* Test.m */,
   8.176 +				27CFF5740F7E999B000B418E /* MYErrorUtils.h */,
   8.177 +				27CFF5750F7E999B000B418E /* MYErrorUtils.m */,
   8.178 +				27CFF57C0F7EA117000B418E /* MYError_CSSMErrorDomain.strings */,
   8.179 +			);
   8.180 +			name = MYUtilities;
   8.181 +			sourceTree = MYUtilities;
   8.182 +		};
   8.183 +		C6859EA2029092E104C91782 /* Documentation */ = {
   8.184 +			isa = PBXGroup;
   8.185 +			children = (
   8.186 +			);
   8.187 +			name = Documentation;
   8.188 +			sourceTree = "<group>";
   8.189 +		};
   8.190 +/* End PBXGroup section */
   8.191 +
   8.192 +/* Begin PBXNativeTarget section */
   8.193 +		8DD76F960486AA7600D96B5E /* MYCrypto */ = {
   8.194 +			isa = PBXNativeTarget;
   8.195 +			buildConfigurationList = 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "MYCrypto" */;
   8.196 +			buildPhases = (
   8.197 +				8DD76F990486AA7600D96B5E /* Sources */,
   8.198 +				8DD76F9B0486AA7600D96B5E /* Frameworks */,
   8.199 +				8DD76F9E0486AA7600D96B5E /* CopyFiles */,
   8.200 +			);
   8.201 +			buildRules = (
   8.202 +			);
   8.203 +			dependencies = (
   8.204 +			);
   8.205 +			name = MYCrypto;
   8.206 +			productInstallPath = "$(HOME)/bin";
   8.207 +			productName = MYCrypto;
   8.208 +			productReference = 8DD76FA10486AA7600D96B5E /* MYCrypto */;
   8.209 +			productType = "com.apple.product-type.tool";
   8.210 +		};
   8.211 +/* End PBXNativeTarget section */
   8.212 +
   8.213 +/* Begin PBXProject section */
   8.214 +		08FB7793FE84155DC02AAC07 /* Project object */ = {
   8.215 +			isa = PBXProject;
   8.216 +			buildConfigurationList = 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "MYCrypto" */;
   8.217 +			compatibilityVersion = "Xcode 3.1";
   8.218 +			hasScannedForEncodings = 1;
   8.219 +			mainGroup = 08FB7794FE84155DC02AAC07 /* MYCrypto */;
   8.220 +			projectDirPath = "";
   8.221 +			projectRoot = "";
   8.222 +			targets = (
   8.223 +				8DD76F960486AA7600D96B5E /* MYCrypto */,
   8.224 +			);
   8.225 +		};
   8.226 +/* End PBXProject section */
   8.227 +
   8.228 +/* Begin PBXSourcesBuildPhase section */
   8.229 +		8DD76F990486AA7600D96B5E /* Sources */ = {
   8.230 +			isa = PBXSourcesBuildPhase;
   8.231 +			buildActionMask = 2147483647;
   8.232 +			files = (
   8.233 +				27CFF4C10F7E8535000B418E /* MYCertificate.m in Sources */,
   8.234 +				27CFF4C20F7E8535000B418E /* MYCryptor.m in Sources */,
   8.235 +				27CFF4C30F7E8535000B418E /* MYKeychain.m in Sources */,
   8.236 +				27CFF4C40F7E8535000B418E /* MYKeychainItem.m in Sources */,
   8.237 +				27CFF4C60F7E8535000B418E /* MYKeyPair.m in Sources */,
   8.238 +				27CFF4C70F7E8535000B418E /* MYPublicKey.m in Sources */,
   8.239 +				27CFF4C80F7E8535000B418E /* MYDigest.m in Sources */,
   8.240 +				27CFF4D50F7E8726000B418E /* CollectionUtils.m in Sources */,
   8.241 +				27CFF4D60F7E8726000B418E /* ExceptionUtils.m in Sources */,
   8.242 +				27CFF4D70F7E8726000B418E /* Logging.m in Sources */,
   8.243 +				27CFF4D80F7E8726000B418E /* Test.m in Sources */,
   8.244 +				27CFF5220F7E94DF000B418E /* MYCrypto_main.m in Sources */,
   8.245 +				27CFF5760F7E999B000B418E /* MYErrorUtils.m in Sources */,
   8.246 +				27A42CBF0F8578B40063D362 /* MYCryptoTest.m in Sources */,
   8.247 +				27A42D1E0F8586CE0063D362 /* MYKey.m in Sources */,
   8.248 +				27A42D420F858ED80063D362 /* MYSymmetricKey.m in Sources */,
   8.249 +			);
   8.250 +			runOnlyForDeploymentPostprocessing = 0;
   8.251 +		};
   8.252 +/* End PBXSourcesBuildPhase section */
   8.253 +
   8.254 +/* Begin XCBuildConfiguration section */
   8.255 +		1DEB927508733DD40010E9CD /* Debug */ = {
   8.256 +			isa = XCBuildConfiguration;
   8.257 +			buildSettings = {
   8.258 +				COPY_PHASE_STRIP = NO;
   8.259 +				INSTALL_PATH = /usr/local/bin;
   8.260 +				PRODUCT_NAME = MYCrypto;
   8.261 +			};
   8.262 +			name = Debug;
   8.263 +		};
   8.264 +		1DEB927608733DD40010E9CD /* Release */ = {
   8.265 +			isa = XCBuildConfiguration;
   8.266 +			buildSettings = {
   8.267 +				INSTALL_PATH = /usr/local/bin;
   8.268 +				PRODUCT_NAME = MYCrypto;
   8.269 +			};
   8.270 +			name = Release;
   8.271 +		};
   8.272 +		1DEB927908733DD40010E9CD /* Debug */ = {
   8.273 +			isa = XCBuildConfiguration;
   8.274 +			baseConfigurationReference = 27CFF5400F7E9653000B418E /* MYCrypto_Debug.xcconfig */;
   8.275 +			buildSettings = {
   8.276 +			};
   8.277 +			name = Debug;
   8.278 +		};
   8.279 +		1DEB927A08733DD40010E9CD /* Release */ = {
   8.280 +			isa = XCBuildConfiguration;
   8.281 +			baseConfigurationReference = 27CFF5120F7E9212000B418E /* MYCrypto.xcconfig */;
   8.282 +			buildSettings = {
   8.283 +			};
   8.284 +			name = Release;
   8.285 +		};
   8.286 +/* End XCBuildConfiguration section */
   8.287 +
   8.288 +/* Begin XCConfigurationList section */
   8.289 +		1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "MYCrypto" */ = {
   8.290 +			isa = XCConfigurationList;
   8.291 +			buildConfigurations = (
   8.292 +				1DEB927508733DD40010E9CD /* Debug */,
   8.293 +				1DEB927608733DD40010E9CD /* Release */,
   8.294 +			);
   8.295 +			defaultConfigurationIsVisible = 0;
   8.296 +			defaultConfigurationName = Release;
   8.297 +		};
   8.298 +		1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "MYCrypto" */ = {
   8.299 +			isa = XCConfigurationList;
   8.300 +			buildConfigurations = (
   8.301 +				1DEB927908733DD40010E9CD /* Debug */,
   8.302 +				1DEB927A08733DD40010E9CD /* Release */,
   8.303 +			);
   8.304 +			defaultConfigurationIsVisible = 0;
   8.305 +			defaultConfigurationName = Release;
   8.306 +		};
   8.307 +/* End XCConfigurationList section */
   8.308 +	};
   8.309 +	rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
   8.310 +}
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/MYCryptoTest.m	Sat Apr 04 20:42:03 2009 -0700
     9.3 @@ -0,0 +1,295 @@
     9.4 +//
     9.5 +//  MYCryptoTest.m
     9.6 +//  MYCrypto-iPhone
     9.7 +//
     9.8 +//  Created by Jens Alfke on 4/1/09.
     9.9 +//  Copyright 2009 Jens Alfke. All rights reserved.
    9.10 +//
    9.11 +
    9.12 +#import "MYKeyPair.h"
    9.13 +#import "MYKeychain.h"
    9.14 +#import "MYDigest.h"
    9.15 +#import "MYCrypto_Private.h"
    9.16 +
    9.17 +
    9.18 +#if DEBUG
    9.19 +
    9.20 +#pragma mark -
    9.21 +#pragma mark KEYCHAIN:
    9.22 +
    9.23 +
    9.24 +TestCase(MYKeychain) {
    9.25 +    MYKeychain *kc = [MYKeychain defaultKeychain];
    9.26 +    Log(@"Default keychain = %@", kc);
    9.27 +    CAssert(kc);
    9.28 +#if !USE_IPHONE_API
    9.29 +    CAssert(kc.path);
    9.30 +#endif
    9.31 +    
    9.32 +    kc = [MYKeychain allKeychains];
    9.33 +    Log(@"All-keychains = %@", kc);
    9.34 +    CAssert(kc);
    9.35 +    CAssertEq(kc.path,nil);
    9.36 +}
    9.37 +
    9.38 +
    9.39 +TestCase(EnumerateKeys) {
    9.40 +    RequireTestCase(MYKeychain);
    9.41 +    NSEnumerator *e = [[MYKeychain allKeychains] enumeratePublicKeys];
    9.42 +    Log(@"Public Key Enumerator = %@", e);
    9.43 +    CAssert(e);
    9.44 +    for (MYPublicKey *key in e) {
    9.45 +        Log(@"Found %@ -- name=%@", key, key.name);
    9.46 +    }
    9.47 +    
    9.48 +    e = [[MYKeychain allKeychains] enumerateKeyPairs];
    9.49 +    Log(@"Key-Pair Enumerator = %@", e);
    9.50 +    CAssert(e);
    9.51 +    for (MYKeyPair *key in e) {
    9.52 +        Log(@"Found %@ -- name=%@", key, key.name);
    9.53 +    }
    9.54 +    
    9.55 +    e = [[MYKeychain allKeychains] enumerateSymmetricKeys];
    9.56 +    Log(@"Symmetric Key Enumerator = %@", e);
    9.57 +    CAssert(e);
    9.58 +    for (MYSymmetricKey *key in e) {
    9.59 +        Log(@"Found %@ -- name=%@", key, key.name);
    9.60 +    }
    9.61 +}
    9.62 +
    9.63 +
    9.64 +TestCase(EnumerateCerts) {
    9.65 +    RequireTestCase(MYKeychain);
    9.66 +    NSEnumerator *e = [[MYKeychain allKeychains] enumerateCertificates];
    9.67 +    Log(@"Enumerator = %@", e);
    9.68 +    CAssert(e);
    9.69 +    for (MYCertificate *cert in e) {
    9.70 +        //Log(@"Found %@ -- name=%@, email=%@", cert, cert.commonName, cert.emailAddresses);
    9.71 +    }
    9.72 +}
    9.73 +
    9.74 +
    9.75 +#pragma mark -
    9.76 +#pragma mark SYMMETRIC KEYS:
    9.77 +
    9.78 +
    9.79 +TestCase(MYSymmetricKey) {
    9.80 +    #define kNTests 11
    9.81 +    static const CCAlgorithm kTestAlgorithms[kNTests] = {
    9.82 +        kCCAlgorithmAES128, kCCAlgorithmAES128, kCCAlgorithmAES128,
    9.83 +        kCCAlgorithmDES, kCCAlgorithm3DES,
    9.84 +        kCCAlgorithmCAST, kCCAlgorithmCAST, kCCAlgorithmCAST,
    9.85 +        kCCAlgorithmRC4, kCCAlgorithmRC4, kCCAlgorithmRC4};
    9.86 +    
    9.87 +    static const unsigned kTestBitSizes[kNTests] = {
    9.88 +        128, 192, 256,
    9.89 +        64, 3*64,
    9.90 +        40, 80, 128,
    9.91 +        32, 200, 512*8};
    9.92 +
    9.93 +    for (int i=0; i<kNTests; i++) {
    9.94 +        NSAutoreleasePool *pool = [NSAutoreleasePool new];
    9.95 +        Log(@"Test #%2i: algorithm = %3u-bit #%i", i+1, kTestBitSizes[i], (int)kTestAlgorithms[i]);
    9.96 +        // Generate key:
    9.97 +        MYSymmetricKey *key = [MYSymmetricKey generateSymmetricKeyOfSize: kTestBitSizes[i]
    9.98 +                                                               algorithm: kTestAlgorithms[i]];
    9.99 +        CAssert(key);
   9.100 +#if !TARGET_OS_IPHONE
   9.101 +        CAssert(key.cssmKey != NULL);
   9.102 +#endif
   9.103 +        Log(@"Key data = %@", key.keyData);
   9.104 +        CAssertEq(key.keyData.length, kTestBitSizes[i]/8);
   9.105 +
   9.106 +        // Encrypt a small amount of text:
   9.107 +        NSData *cleartext = [@"This is a test. This is only a test." dataUsingEncoding: NSUTF8StringEncoding];
   9.108 +        NSData *encrypted = [key encryptData: cleartext];
   9.109 +        Log(@"Encrypted = %u bytes: %@", encrypted.length, encrypted);
   9.110 +        CAssert(encrypted.length >= cleartext.length);
   9.111 +        NSData *decrypted = [key decryptData: encrypted];
   9.112 +        CAssertEqual(decrypted, cleartext);
   9.113 +        
   9.114 +        // Encrypt large binary data:
   9.115 +        cleartext = [NSData dataWithContentsOfFile: @"/Library/Desktop Pictures/Nature/Zen Garden.jpg"];
   9.116 +        CAssert(cleartext);
   9.117 +        encrypted = [key encryptData: cleartext];
   9.118 +        Log(@"Encrypted = %u bytes", encrypted.length);
   9.119 +        CAssert(encrypted.length >= cleartext.length);
   9.120 +        decrypted = [key decryptData: encrypted];
   9.121 +        CAssertEqual(decrypted, cleartext);
   9.122 +        
   9.123 +        [pool drain];
   9.124 +    }
   9.125 +}
   9.126 +
   9.127 +
   9.128 +#pragma mark -
   9.129 +#pragma mark KEY-PAIRS:
   9.130 +
   9.131 +
   9.132 +TestCase(KeyPair) {
   9.133 +    RequireTestCase(MYKeychain);
   9.134 +    
   9.135 +    Log(@"Generating key pair...");
   9.136 +    MYKeyPair *pair = [[MYKeychain defaultKeychain] generateRSAKeyPairOfSize: 512];
   9.137 +    CAssert(pair);
   9.138 +    CAssert(pair.keyRef);
   9.139 +    CAssert(pair.privateKeyRef);
   9.140 +    Log(@"...created pair.");
   9.141 +    
   9.142 +    @try{
   9.143 +        [pair setName: @"Test KeyPair Label"];
   9.144 +        CAssertEqual(pair.name, @"Test KeyPair Label");
   9.145 +#if !TARGET_OS_IPHONE
   9.146 +        [pair setComment: @"This key-pair was generated automatically by a test case."];
   9.147 +        CAssertEqual(pair.comment, @"This key-pair was generated automatically by a test case.");
   9.148 +#endif
   9.149 +        [pair setAlias: @"TestCase@mooseyard.com"];
   9.150 +        CAssertEqual(pair.alias, @"TestCase@mooseyard.com");
   9.151 +        
   9.152 +        NSData *pubKeyData = pair.keyData;
   9.153 +        Log(@"Public key = %@ (%u bytes)",pubKeyData,pubKeyData.length);
   9.154 +        CAssert(pubKeyData);
   9.155 +        
   9.156 +        MYSHA1Digest *pubKeyDigest = pair.publicKeyDigest;
   9.157 +        Log(@"Public key digest = %@",pubKeyDigest);
   9.158 +        
   9.159 +        Log(@"SHA1 of pub key = %@", pubKeyData.my_SHA1Digest.asData);
   9.160 +        
   9.161 +        NSData *data = [@"This is a test. This is only a test!" dataUsingEncoding: NSUTF8StringEncoding];
   9.162 +        NSData *sig = [pair signData: data];
   9.163 +        Log(@"Signature = %@ (%u bytes)",sig,sig.length);
   9.164 +        CAssert(sig);
   9.165 +        CAssert( [pair verifySignature: sig ofData: data] );
   9.166 +        
   9.167 +        // Test creating a standalone public key:
   9.168 +        MYPublicKey *pub = [[MYPublicKey alloc] initWithKeyRef: pair.keyRef];
   9.169 +        CAssert( [pub verifySignature: sig ofData: data] );
   9.170 +        Log(@"Verified signature.");
   9.171 +
   9.172 +        // Test creating a public key from data:
   9.173 +        Log(@"Reconstituting public key from data...");
   9.174 +        pub = [[MYPublicKey alloc] initWithKeyData: pubKeyData];
   9.175 +        CAssert(pub);
   9.176 +        CAssertEqual(pub.keyData, pubKeyData);
   9.177 +        CAssertEqual(pub.publicKeyDigest, pubKeyDigest);
   9.178 +        CAssert( [pub verifySignature: sig ofData: data] );
   9.179 +        Log(@"Verified signature from reconstituted key.");
   9.180 +                
   9.181 +        // Now let's encrypt...
   9.182 +        NSData *crypted = [pub encryptData: data];
   9.183 +        Log(@"Encrypted = %@ (%u bytes)",crypted,crypted.length);
   9.184 +        CAssert(crypted);
   9.185 +        
   9.186 +        CAssertEqual([pair decryptData: crypted], data);
   9.187 +        Log(@"Verified decryption.");
   9.188 +        
   9.189 +        CAssert([pair removeFromKeychain]);
   9.190 +        Log(@"Removed key-pair.");
   9.191 +        pair = nil;
   9.192 +        
   9.193 +    }@finally {
   9.194 +        if (pair) {
   9.195 +            if ([pair removeFromKeychain])
   9.196 +                Log(@"Removed key-pair from keychain.");
   9.197 +            else
   9.198 +                Warn(@"Unable to remove test key-pair from keychain");
   9.199 +        }
   9.200 +    }
   9.201 +}
   9.202 +
   9.203 +
   9.204 +
   9.205 +#pragma mark -
   9.206 +#pragma mark KEYPAIR EXPORT:
   9.207 +
   9.208 +
   9.209 +static void testKeyPairExportWithPrompt(BOOL withPrompt) {
   9.210 +    MYKeychain *keychain = [MYKeychain allKeychains];
   9.211 +    Log(@"Generating key pair...");
   9.212 +    MYKeyPair *pair = [keychain generateRSAKeyPairOfSize: 512];
   9.213 +    CAssert(pair);
   9.214 +    CAssert(pair.keyRef);
   9.215 +    CAssert(pair.privateKeyRef);
   9.216 +    Log(@"...created pair.");
   9.217 +    
   9.218 +    @try{
   9.219 +        NSData *pubKeyData = pair.keyData;
   9.220 +        CAssert(pubKeyData.length >= 512/8);
   9.221 +        [pair setName: @"Test KeyPair Label"];
   9.222 +        CAssertEqual(pair.name, @"Test KeyPair Label");
   9.223 +#if !TARGET_OS_IPHONE
   9.224 +        [pair setComment: @"This key-pair was generated automatically by a test case."];
   9.225 +        CAssertEqual(pair.comment, @"This key-pair was generated automatically by a test case.");
   9.226 +#endif
   9.227 +        [pair setAlias: @"TestCase@mooseyard.com"];
   9.228 +        CAssertEqual(pair.alias, @"TestCase@mooseyard.com");
   9.229 +        
   9.230 +#if !TARGET_OS_IPHONE
   9.231 +        Log(@"Exporting key-pair...");
   9.232 +        NSString *passphrase = @"passphrase";
   9.233 +        NSData *privKeyData;
   9.234 +        if (withPrompt)
   9.235 +            privKeyData = [pair exportPrivateKey];
   9.236 +        else
   9.237 +            privKeyData = [pair _exportPrivateKeyInFormat: kSecFormatWrappedOpenSSL
   9.238 +                                                  withPEM: YES
   9.239 +                                               passphrase: passphrase];
   9.240 +        Log(@"Exported data = %@ (%u bytes)", privKeyData,privKeyData.length);
   9.241 +        CAssert(privKeyData);
   9.242 +        [privKeyData writeToFile: @"ExportedPrivKey" atomically: YES];
   9.243 +#endif
   9.244 +        
   9.245 +        // Check key lookup:
   9.246 +        Log(@"Looking up public key of pair in keychain...");
   9.247 +        MYSHA1Digest *digest = pair.publicKeyDigest;
   9.248 +        MYPublicKey *foundKey = [keychain publicKeyWithDigest: digest];
   9.249 +        CAssertEqual(foundKey, pair.asPublicKey);
   9.250 +        CAssert([keychain.enumeratePublicKeys.allObjects containsObject: pair.asPublicKey]);
   9.251 +        MYKeyPair *foundPair = [keychain keyPairWithDigest: digest];
   9.252 +        CAssertEqual(foundPair, pair);
   9.253 +        CAssert([keychain.enumerateKeyPairs.allObjects containsObject: pair]);
   9.254 +        
   9.255 +        Log(@"Removing key-pair from keychain...");
   9.256 +        CAssert([pair removeFromKeychain]);
   9.257 +        pair = nil;
   9.258 +        CAssert([keychain publicKeyWithDigest: digest] == nil);
   9.259 +        
   9.260 +#if !TARGET_OS_IPHONE
   9.261 +        Log(@"Importing key-pair...");
   9.262 +        if (withPrompt) {
   9.263 +            pair = [keychain importPublicKey: pubKeyData 
   9.264 +                                  privateKey: privKeyData];
   9.265 +        } else {
   9.266 +            pair = [[[MYKeyPair alloc] _initWithPublicKeyData: pubKeyData
   9.267 +                                               privateKeyData: privKeyData
   9.268 +                                                  forKeychain: keychain.keychainRefOrDefault
   9.269 +                                                   passphrase: passphrase]
   9.270 +                    autorelease];
   9.271 +        }
   9.272 +        CAssert(pair);
   9.273 +        CAssertEqual(pair.keyData, pubKeyData);
   9.274 +#endif
   9.275 +    }@finally {
   9.276 +        if (pair) {
   9.277 +            if ([pair removeFromKeychain])
   9.278 +                Log(@"Removed key-pair from keychain.");
   9.279 +            else
   9.280 +                Warn(@"Unable to remove test key-pair from keychain");
   9.281 +        }
   9.282 +    }
   9.283 +}
   9.284 +
   9.285 +TestCase(KeyPairExport) {
   9.286 +    RequireTestCase(MYKeychain);
   9.287 +    RequireTestCase(KeyPair);
   9.288 +    testKeyPairExportWithPrompt(NO);
   9.289 +}
   9.290 +
   9.291 +TestCase(KeyPairExportWithUI) {
   9.292 +    RequireTestCase(KeyPairExport);
   9.293 +    testKeyPairExportWithPrompt(YES);
   9.294 +}
   9.295 +
   9.296 +
   9.297 +#endif DEBUG
   9.298 +
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/MYCrypto_Debug.xcconfig	Sat Apr 04 20:42:03 2009 -0700
    10.3 @@ -0,0 +1,13 @@
    10.4 +//
    10.5 +//  MYCrypto_Debug.xcconfig
    10.6 +//  MYCrypto
    10.7 +//
    10.8 +//  Created by Jens Alfke on 3/28/09.
    10.9 +//  Copyright 2009 Jens Alfke. All rights reserved.
   10.10 +//
   10.11 +
   10.12 +#include "MYCrypto.xcconfig"
   10.13 +
   10.14 +GCC_PREPROCESSOR_DEFINITIONS = DEBUG=1
   10.15 +GCC_OPTIMIZATION_LEVEL = 0
   10.16 +COPY_PHASE_STRIP = NO
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/MYCrypto_Private.h	Sat Apr 04 20:42:03 2009 -0700
    11.3 @@ -0,0 +1,124 @@
    11.4 +//
    11.5 +//  MYCrypto_Private.h
    11.6 +//  MYCrypto
    11.7 +//
    11.8 +//  Created by Jens Alfke on 3/23/09.
    11.9 +//  Copyright 2009 Jens Alfke. All rights reserved.
   11.10 +//
   11.11 +
   11.12 +#import "MYKeychain.h"
   11.13 +#import "MYKey.h"
   11.14 +#import "MYSymmetricKey.h"
   11.15 +#import "MYKeyPair.h"
   11.16 +#import "MYCertificate.h"
   11.17 +#import "Test.h"
   11.18 +#import <Security/Security.h>
   11.19 +
   11.20 +/*  The iPhone simulator actually has the Mac OS X security API, not the iPhone one.
   11.21 +    So don't use the iPhone API when configured to run in the simulator. */
   11.22 +#if TARGET_OS_IPHONE
   11.23 +#if !TARGET_IPHONE_SIMULATOR
   11.24 +#define USE_IPHONE_API 1
   11.25 +#endif
   11.26 +#endif
   11.27 +
   11.28 +#ifndef USE_IPHONE_API
   11.29 +#define USE_IPHONE_API 0
   11.30 +#endif
   11.31 +
   11.32 +
   11.33 +#if USE_IPHONE_API
   11.34 +typedef CFTypeRef SecKeychainAttrType;
   11.35 +typedef CFTypeRef SecKeychainItemRef;
   11.36 +typedef CFTypeRef SecKeychainRef;
   11.37 +#endif
   11.38 +
   11.39 +@interface MYKeychainItem (Private);
   11.40 +- (NSData*) _getContents: (OSStatus*)outError;
   11.41 +- (NSString*) stringValueOfAttribute: (SecKeychainAttrType)attr;
   11.42 +- (BOOL) setValue: (NSString*)valueStr ofAttribute: (SecKeychainAttrType)attr;
   11.43 ++ (NSData*) _getAttribute: (SecKeychainAttrType)attr ofItem: (MYKeychainItemRef)item;
   11.44 +- (id) _attribute: (SecKeychainAttrType)attribute;
   11.45 ++ (NSString*) _getStringAttribute: (SecKeychainAttrType)attr ofItem: (MYKeychainItemRef)item;
   11.46 ++ (BOOL) _setAttribute: (SecKeychainAttrType)attr ofItem: (MYKeychainItemRef)item
   11.47 +           stringValue: (NSString*)stringValue;
   11.48 +@end      
   11.49 +
   11.50 +
   11.51 +@interface MYKey (Private)
   11.52 +- (id) _initWithKeyData: (NSData*)data
   11.53 +            forKeychain: (SecKeychainRef)keychain;
   11.54 +#if !USE_IPHONE_API
   11.55 +@property (readonly) const CSSM_KEY* cssmKey;
   11.56 +- (NSData*) exportKeyInFormat: (SecExternalFormat)format withPEM: (BOOL)withPEM;
   11.57 +#endif
   11.58 +@property (readonly) NSArray* _itemList;
   11.59 +@end
   11.60 +
   11.61 +
   11.62 +@interface MYSymmetricKey (Private)
   11.63 ++ (MYSymmetricKey*) _generateSymmetricKeyOfSize: (unsigned)keySizeInBits
   11.64 +                                      algorithm: (CCAlgorithm)algorithm
   11.65 +                                     inKeychain: (MYKeychain*)keychain;
   11.66 +@end
   11.67 +
   11.68 +
   11.69 +@interface MYPublicKey (Private)
   11.70 ++ (MYSHA1Digest*) _digestOfKey: (SecKeyRef)key;
   11.71 +- (BOOL) setValue: (NSString*)valueStr ofAttribute: (SecKeychainAttrType)attr;
   11.72 +@end
   11.73 +
   11.74 +
   11.75 +@interface MYKeyPair (Private)
   11.76 ++ (MYKeyPair*) _generateRSAKeyPairOfSize: (unsigned)keySize
   11.77 +                            inKeychain: (SecKeychainRef)keychain;
   11.78 +- (id) _initWithPublicKeyData: (NSData*)pubKeyData 
   11.79 +               privateKeyData: (NSData*)privKeyData
   11.80 +                  forKeychain: (SecKeychainRef)keychain
   11.81 +                   alertTitle: (NSString*)title
   11.82 +                  alertPrompt: (NSString*)prompt;
   11.83 +- (id) _initWithPublicKeyData: (NSData*)pubKeyData 
   11.84 +               privateKeyData: (NSData*)privKeyData
   11.85 +                  forKeychain: (SecKeychainRef)keychain 
   11.86 +                   passphrase: (NSString*)passphrase;
   11.87 +#if !TARGET_OS_IPHONE
   11.88 +- (NSData*) _exportPrivateKeyInFormat: (SecExternalFormat)format
   11.89 +                              withPEM: (BOOL)withPEM
   11.90 +                           passphrase: (NSString*)passphrase;
   11.91 +#endif
   11.92 +@end
   11.93 +
   11.94 +
   11.95 +#if TARGET_OS_IPHONE && !USE_IPHONE_API
   11.96 +@interface MYCertificate (Private)
   11.97 +- (id) initWithCertificateData: (NSData*)data
   11.98 +                          type: (CSSM_CERT_TYPE) type
   11.99 +                      encoding: (CSSM_CERT_ENCODING) encoding;
  11.100 +@end
  11.101 +#endif
  11.102 +
  11.103 +
  11.104 +#if TARGET_OS_IPHONE && !USE_IPHONE_API
  11.105 +@interface MYKeychain (Private)
  11.106 +- (id) initWithKeychainRef: (SecKeychainRef)keychainRef;
  11.107 +@property (readonly) SecKeychainRef keychainRef, keychainRefOrDefault;
  11.108 +@property (readonly) CSSM_CSP_HANDLE CSPHandle;
  11.109 +@property (readonly) NSString* path;
  11.110 +@end
  11.111 +#endif
  11.112 +
  11.113 +
  11.114 +NSData* _crypt(SecKeyRef key, NSData *data, CCOperation op);
  11.115 +
  11.116 +#undef check
  11.117 +BOOL check(OSStatus err, NSString *what);
  11.118 +
  11.119 +#if !USE_IPHONE_API
  11.120 +BOOL checkcssm(CSSM_RETURN err, NSString *what);
  11.121 +
  11.122 +SecKeyRef importKey(NSData *data, 
  11.123 +                    SecExternalItemType type,
  11.124 +                    SecKeychainRef keychain,
  11.125 +                    SecKeyImportExportParameters *params /*non-null*/);
  11.126 +CSSM_CC_HANDLE cssmCreateSignatureContext(SecKeyRef key);
  11.127 +#endif
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/MYCrypto_main.m	Sat Apr 04 20:42:03 2009 -0700
    12.3 @@ -0,0 +1,23 @@
    12.4 +/*
    12.5 + *  MYCrypto_main.c
    12.6 + *  MYCrypto
    12.7 + *
    12.8 + *  Created by Jens Alfke on 3/28/09.
    12.9 + *  Copyright 2009 Jens Alfke. All rights reserved.
   12.10 + *
   12.11 + */
   12.12 +
   12.13 +
   12.14 +#import "Test.h"
   12.15 +
   12.16 +
   12.17 +int main(int argc, const char **argv) {
   12.18 +    if (argc<2) {
   12.19 +        static const char *testArgs[] = {"MYCrypto", "Test_All"};
   12.20 +        argc = 2;
   12.21 +        argv = testArgs;
   12.22 +    }
   12.23 +    
   12.24 +    RunTestCases(argc,argv);
   12.25 +    return 0;
   12.26 +}
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/MYCryptor.h	Sat Apr 04 20:42:03 2009 -0700
    13.3 @@ -0,0 +1,86 @@
    13.4 +//
    13.5 +//  Cryptor.h
    13.6 +//  MYCrypto
    13.7 +//
    13.8 +//  Created by Jens Alfke on 3/21/09.
    13.9 +//  Copyright 2009 Jens Alfke. All rights reserved.
   13.10 +//
   13.11 +
   13.12 +#import <Foundation/Foundation.h>
   13.13 +#import <CommonCrypto/CommonCryptor.h>
   13.14 +
   13.15 +
   13.16 +/** Symmetric encryption: a Cocoa wrapper for CommonCrypto/commonCryptor.h */
   13.17 +@interface MYCryptor : NSObject
   13.18 +{
   13.19 +    NSData *_key;
   13.20 +    CCOperation _operation;
   13.21 +    CCAlgorithm _algorithm;
   13.22 +    CCOptions _options;
   13.23 +    CCCryptorRef _cryptor;
   13.24 +    NSError *_error;
   13.25 +    NSOutputStream *_outputStream;
   13.26 +    NSMutableData *_output;
   13.27 +    size_t _outputExtraBytes;
   13.28 +}
   13.29 +
   13.30 +/** CommonCryptor.h defines key size and size-range constants, like kCCKeySizeAES128 */
   13.31 ++ (NSData*) randomKeyOfLength: (size_t)length;
   13.32 +
   13.33 ++ (NSData*) keyOfLength: (size_t)lengthInBits fromPassphrase: (NSString*)passphrase;
   13.34 +
   13.35 +/** Creates a MYCryptor configured to encrypt data. */
   13.36 +- (id) initEncryptorWithKey: (NSData*)key
   13.37 +                  algorithm: (CCAlgorithm)algorithm;
   13.38 +
   13.39 +/** Creates a MYCryptor configured to decrypt data. */
   13.40 +- (id) initDecryptorWithKey: (NSData*)key
   13.41 +                  algorithm: (CCAlgorithm)algorithm;
   13.42 +
   13.43 +/** Setting this property tells the cryptor to send its output to the stream,
   13.44 +    instead of accumulating itself in the outputData property. */
   13.45 +@property (retain) NSOutputStream *outputStream;
   13.46 +
   13.47 +/** The encryption/decryption key; same as the 'key' parameter to the initializer. */
   13.48 +@property (readonly) NSData *key;
   13.49 +
   13.50 +/** The cipher to use; initial value is the 'algorithm' parameter to the initializer.
   13.51 +    You can change this before the first call to -addData:, but not after. */
   13.52 +@property CCAlgorithm algorithm;
   13.53 +
   13.54 +/** Block-mode cipher options; you can set flags to enable PKCS7 padding or ECB mode
   13.55 +    (default is CBC.)
   13.56 +    You can change this before the first call to -addData:, but not after. */
   13.57 +@property CCOptions options;
   13.58 +
   13.59 +/** The error state, if any, of this cryptor.
   13.60 +    After -addData: or -finish: returns NO, check this property. */
   13.61 +@property (readonly, retain) NSError *error;
   13.62 +
   13.63 +/** Adds input data.
   13.64 +    @return  YES if the operation succeeded, NO if it failed. */
   13.65 +- (BOOL) addData: (NSData*)data;
   13.66 +
   13.67 +/** Finishes up the encryption/decryption and flushes the remaining bytes of output.
   13.68 +    After this is called, you cannot add any more bytes of data.
   13.69 +    @return  YES if the operation succeeded, NO if it failed. */
   13.70 +- (BOOL) finish;
   13.71 +
   13.72 +/** The output of the cryptor. Accessing this property implicitly calls -finish, so don't
   13.73 +    do it until you've added all of the input. (And don't add any more input afterwards.)
   13.74 +    This property will be nil if the outputStream property has been set. */
   13.75 +@property (readonly) NSData *outputData;
   13.76 +
   13.77 +@end
   13.78 +
   13.79 +
   13.80 +
   13.81 +/** NSError domain for MYCryptor operations. Error code is interpreted as a CCCryptorStatus,
   13.82 +    with additional error code(s) defined below. */
   13.83 +extern NSString* const CryptorErrorDomain;
   13.84 +
   13.85 +enum {
   13.86 +    /** Indicates that the outputStream couldn't write all the bytes given to it (this is legal
   13.87 +        behavior for an NSOutputStream, but MYCryptor can't handle this yet.) */
   13.88 +    kMYCryptorErrorOutputStreamChoked = -777000
   13.89 +};
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/MYCryptor.m	Sat Apr 04 20:42:03 2009 -0700
    14.3 @@ -0,0 +1,325 @@
    14.4 +//
    14.5 +//  Cryptor.m
    14.6 +//  MYCrypto
    14.7 +//
    14.8 +//  Created by Jens Alfke on 3/21/09.
    14.9 +//  Copyright 2009 Jens Alfke. All rights reserved.
   14.10 +//
   14.11 +
   14.12 +#import "MYCryptor.h"
   14.13 +#import "MYDigest.h"
   14.14 +#import "Test.h"
   14.15 +
   14.16 +#if USE_IPHONE_API
   14.17 +#import <Security/SecRandom.h>
   14.18 +#else
   14.19 +#import "MYCrypto_Private.h"
   14.20 +#import "MYKeychain.h"
   14.21 +#import <stdlib.h>
   14.22 +#endif
   14.23 +
   14.24 +
   14.25 +NSString* const CryptorErrorDomain = @"CCCryptor";
   14.26 +
   14.27 +#if !USE_IPHONE_API
   14.28 +static BOOL generateRandomBytes(CSSM_CSP_HANDLE module, uint32_t lengthInBytes, void *dstBytes);
   14.29 +#endif
   14.30 +
   14.31 +
   14.32 +@interface MYCryptor ()
   14.33 +@property (readwrite, retain) NSError *error;
   14.34 +@end
   14.35 +
   14.36 +
   14.37 +
   14.38 +@implementation MYCryptor
   14.39 +
   14.40 +
   14.41 ++ (NSData*) randomKeyOfLength: (size_t)length {
   14.42 +    NSParameterAssert(length<100000);
   14.43 +    uint8_t *bytes = malloc(length);
   14.44 +    if (!bytes) return nil;
   14.45 +#if USE_IPHONE_API
   14.46 +    BOOL ok = SecRandomCopyBytes(kSecRandomDefault, length,bytes) >= 0;
   14.47 +#else
   14.48 +    BOOL ok = generateRandomBytes([[MYKeychain defaultKeychain] CSPHandle], length, bytes);
   14.49 +#endif
   14.50 +    if (ok)
   14.51 +        return [NSData dataWithBytesNoCopy: bytes length: length freeWhenDone: YES];
   14.52 +    else {
   14.53 +        free(bytes);
   14.54 +        return nil;
   14.55 +    }
   14.56 +}
   14.57 +
   14.58 ++ (NSData*) keyOfLength: (size_t)lengthInBits fromPassphrase: (NSString*)passphrase
   14.59 +{
   14.60 +    size_t lengthInBytes = (lengthInBits + 7)/8;
   14.61 +    MYDigest *digest = [[passphrase dataUsingEncoding: NSUTF8StringEncoding] my_SHA256Digest];
   14.62 +    if (lengthInBytes <= digest.length)
   14.63 +        return [digest.asData subdataWithRange: NSMakeRange(0,lengthInBytes)];
   14.64 +    else
   14.65 +        return nil;
   14.66 +}
   14.67 +
   14.68 +
   14.69 +- (id) initWithKey: (NSData*)key
   14.70 +         algorithm: (CCAlgorithm)algorithm
   14.71 +         operation: (CCOperation)op {
   14.72 +    self = [super init];
   14.73 +    if (self) {
   14.74 +        NSParameterAssert(key);
   14.75 +        _key = [key copy];
   14.76 +        _operation = op;
   14.77 +        _algorithm = algorithm;
   14.78 +        _options = kCCOptionPKCS7Padding;
   14.79 +    }
   14.80 +    return self;
   14.81 +}
   14.82 +
   14.83 +- (id) initEncryptorWithKey: (NSData*)key algorithm: (CCAlgorithm)algorithm {
   14.84 +    return [self initWithKey: key algorithm: algorithm operation: kCCEncrypt];
   14.85 +}
   14.86 +
   14.87 +- (id) initDecryptorWithKey: (NSData*)key algorithm: (CCAlgorithm)algorithm {
   14.88 +    return [self initWithKey: key algorithm: algorithm operation: kCCDecrypt];
   14.89 +}
   14.90 +
   14.91 +- (void) dealloc
   14.92 +{
   14.93 +    if (_cryptor)
   14.94 +        CCCryptorRelease(_cryptor);
   14.95 +    [_key autorelease];
   14.96 +    [_output autorelease];
   14.97 +    [_outputStream release];
   14.98 +    [super dealloc];
   14.99 +}
  14.100 +
  14.101 +
  14.102 +@synthesize key=_key, algorithm=_algorithm, options=_options,
  14.103 +    outputStream=_outputStream, error=_error;
  14.104 +
  14.105 +
  14.106 +- (BOOL) _check: (CCCryptorStatus)status {
  14.107 +    if (status == kCCSuccess)
  14.108 +        return YES;
  14.109 +    else {
  14.110 +        Warn(@"MYCryptor: CCCryptor error %i", status);
  14.111 +        self.error = [NSError errorWithDomain: CryptorErrorDomain code: status userInfo: nil];
  14.112 +        return NO;
  14.113 +    }
  14.114 +}
  14.115 +
  14.116 +
  14.117 +- (BOOL) _outputBytes: (const void*)bytes length: (size_t)length {
  14.118 +    if (_outputStream) {
  14.119 +        NSInteger written = [_outputStream write: bytes maxLength: length];
  14.120 +        if (written < 0) {
  14.121 +            self.error = _outputStream.streamError;
  14.122 +            if (_error)
  14.123 +                Warn(@"MYCryptor: NSOutputStream error %@", _error);
  14.124 +            else
  14.125 +                [self _check: kMYCryptorErrorOutputStreamChoked];
  14.126 +            return NO;
  14.127 +        } else if (written < length) {
  14.128 +            [self _check: kMYCryptorErrorOutputStreamChoked];
  14.129 +            return NO;
  14.130 +        }
  14.131 +    } else if (length > 0) {
  14.132 +        [_output appendBytes: bytes length: length];
  14.133 +    }
  14.134 +    return YES;
  14.135 +}
  14.136 +
  14.137 +
  14.138 +- (BOOL) _start {
  14.139 +    if (!_cryptor && !_error) {
  14.140 +        if ([self _check: CCCryptorCreate(_operation, _algorithm, _options,
  14.141 +                                          _key.bytes, _key.length, NULL, &_cryptor)]) {
  14.142 +            _output = [[NSMutableData alloc] initWithCapacity: 1024];
  14.143 +        }
  14.144 +    }
  14.145 +    return !_error;
  14.146 +}
  14.147 +
  14.148 +
  14.149 +- (BOOL) addBytes: (const void*)bytes length: (size_t)length {
  14.150 +    if (length > 0) {
  14.151 +        NSParameterAssert(bytes!=NULL);
  14.152 +        if(!_error && (_cryptor || [self _start])) {
  14.153 +            size_t outputLength = CCCryptorGetOutputLength(_cryptor,length,false);
  14.154 +            void *output = malloc(outputLength);
  14.155 +            if ([self _check: CCCryptorUpdate(_cryptor, bytes, length,
  14.156 +                                              output, outputLength, &outputLength)]) {
  14.157 +                [self _outputBytes: output length: outputLength];
  14.158 +            }
  14.159 +            free(output);
  14.160 +        }
  14.161 +    }
  14.162 +    return !_error;
  14.163 +}
  14.164 +
  14.165 +- (BOOL) addData: (NSData*)data
  14.166 +{
  14.167 +    return [self addBytes: data.bytes length: data.length];
  14.168 +}
  14.169 +
  14.170 +- (BOOL) addString: (NSString*)str {
  14.171 +    return [self addData: [str dataUsingEncoding: NSUTF8StringEncoding]];
  14.172 +}
  14.173 +
  14.174 +
  14.175 +- (BOOL) addFromStream: (NSInputStream*)input
  14.176 +{
  14.177 +    uint8_t inputBuffer[1024];
  14.178 +    size_t avail;
  14.179 +    while (!_error && input.hasBytesAvailable) {
  14.180 +        avail = sizeof(inputBuffer);
  14.181 +        NSInteger nRead = [input read: inputBuffer maxLength: sizeof(inputBuffer)];
  14.182 +        if (nRead < 0) {
  14.183 +            self.error = input.streamError;
  14.184 +            return NO;
  14.185 +        } else if (nRead == 0) {
  14.186 +            break;
  14.187 +        } else if (![self addBytes: inputBuffer length: nRead])
  14.188 +            return NO;
  14.189 +    }
  14.190 +    return YES;
  14.191 +}
  14.192 +
  14.193 +
  14.194 +- (BOOL) finish
  14.195 +{
  14.196 +    if(!_error && (_cryptor || [self _start])) {
  14.197 +        size_t outputLength = 100; //CCCryptorGetOutputLength(_cryptor,1,true);
  14.198 +        void *output = malloc(outputLength);
  14.199 +        if ([self _check: CCCryptorFinal(_cryptor, output, outputLength, &outputLength)]) {
  14.200 +            [self _outputBytes: output length: outputLength];
  14.201 +        }
  14.202 +        free(output);
  14.203 +    }
  14.204 +    CCCryptorRelease(_cryptor);
  14.205 +    _cryptor = NULL;
  14.206 +    return !_error;
  14.207 +}
  14.208 +
  14.209 +
  14.210 +- (NSData*) outputData {
  14.211 +    if (_cryptor) [self finish];
  14.212 +    if(_error) {
  14.213 +        [_output release];
  14.214 +        _output = nil;
  14.215 +    }
  14.216 +    return _output;
  14.217 +}
  14.218 +
  14.219 +- (NSString*) outputString {
  14.220 +    NSData *output = self.outputData;
  14.221 +    if (output) {
  14.222 +        NSString *str = [[NSString alloc] initWithData: output encoding: NSUTF8StringEncoding];
  14.223 +        return [str autorelease];
  14.224 +    } else
  14.225 +        return nil;
  14.226 +}
  14.227 +
  14.228 +
  14.229 +// NSStream delegate method
  14.230 +- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode {
  14.231 +    switch (eventCode) {
  14.232 +        case NSStreamEventHasBytesAvailable:
  14.233 +            [self addFromStream: (NSInputStream*)stream];
  14.234 +            break;
  14.235 +        case NSStreamEventEndEncountered:
  14.236 +            [self finish];
  14.237 +            break;
  14.238 +        case NSStreamEventErrorOccurred:
  14.239 +            if (!_error)
  14.240 +                self.error = stream.streamError;
  14.241 +            break;
  14.242 +        default:
  14.243 +            break;
  14.244 +    }
  14.245 +}
  14.246 +
  14.247 +
  14.248 +
  14.249 +@end
  14.250 +
  14.251 +
  14.252 +
  14.253 +
  14.254 +#if !USE_IPHONE_API
  14.255 +static BOOL generateRandomBytes(CSSM_CSP_HANDLE module, uint32_t lengthInBytes, void *dstBytes) {
  14.256 +    // Adapted from code in Keychain.framework's KeychainUtils.m by Wade Tregaskis.
  14.257 +    CSSM_CC_HANDLE ccHandle;
  14.258 +    if (!checkcssm(CSSM_CSP_CreateRandomGenContext(module, CSSM_ALGID_APPLE_YARROW, NULL,
  14.259 +                                                  lengthInBytes, &ccHandle),
  14.260 +                   @"CSSM_CSP_CreateRandomGenContext"))
  14.261 +        return NO;
  14.262 +    CSSM_DATA data = {.Data=dstBytes, .Length=lengthInBytes};
  14.263 +    BOOL ok = checkcssm(CSSM_GenerateRandom(ccHandle, &data), @"CSSM_GenerateRandom");
  14.264 +    CSSM_DeleteContext(ccHandle);
  14.265 +    return ok;
  14.266 +}
  14.267 +#endif
  14.268 +
  14.269 +
  14.270 +
  14.271 +
  14.272 +TestCase(MYCryptor) {
  14.273 +    // Encryption:
  14.274 +    NSData *key = [MYCryptor randomKeyOfLength: kCCKeySizeAES256];
  14.275 +    Log(@"Key = %@",key);
  14.276 +    MYCryptor *enc = [[MYCryptor alloc] initEncryptorWithKey: key algorithm: kCCAlgorithmAES128];
  14.277 +    CAssert(enc);
  14.278 +    CAssert([enc addString: @"This is a test. "]);
  14.279 +    CAssert([enc addString: @"This is only a test."]);
  14.280 +    CAssertEqual(enc.error, nil);
  14.281 +    NSData *encrypted = enc.outputData;
  14.282 +    CAssertEqual(enc.error, nil);
  14.283 +    CAssert(encrypted.length > 0);
  14.284 +    [enc release];
  14.285 +    Log(@"Encrypted = %@", encrypted);
  14.286 +    
  14.287 +    // Decryption:
  14.288 +    MYCryptor *dec = [[MYCryptor alloc] initDecryptorWithKey: key algorithm: kCCAlgorithmAES128];
  14.289 +    CAssert(dec);
  14.290 +    CAssert([dec addData: encrypted]);
  14.291 +    NSString *decrypted = dec.outputString;
  14.292 +    CAssertEqual(dec.error, nil);
  14.293 +    [dec release];
  14.294 +    Log(@"Decrypted = '%@'", decrypted);
  14.295 +    CAssertEqual(decrypted, @"This is a test. This is only a test.");
  14.296 +    
  14.297 +    // Encryption to stream:
  14.298 +    key = [MYCryptor randomKeyOfLength: kCCKeySizeAES256];
  14.299 +    Log(@"Key = %@",key);
  14.300 +    enc = [[MYCryptor alloc] initEncryptorWithKey: key algorithm: kCCAlgorithmAES128];
  14.301 +    CAssert(enc);
  14.302 +    enc.outputStream = [NSOutputStream outputStreamToMemory];
  14.303 +    [enc.outputStream open];
  14.304 +    CAssert([enc addString: @"This is a test. "]);
  14.305 +    CAssert([enc addString: @"This is only a test."]);
  14.306 +    CAssert([enc finish]);
  14.307 +    CAssertEqual(enc.error, nil);
  14.308 +    encrypted = [[enc.outputStream propertyForKey: NSStreamDataWrittenToMemoryStreamKey] retain];
  14.309 +    CAssert(encrypted.length > 0);
  14.310 +    [enc release];
  14.311 +    Log(@"Encrypted = %@", encrypted);
  14.312 +    
  14.313 +    dec = [[MYCryptor alloc] initDecryptorWithKey: key algorithm: kCCAlgorithmAES128];
  14.314 +    CAssert(dec);
  14.315 +    dec.outputStream = [NSOutputStream outputStreamToMemory];
  14.316 +    [dec.outputStream open];
  14.317 +    CAssert([dec addData: encrypted]);
  14.318 +    CAssert([dec finish]);
  14.319 +    CAssertEqual(dec.error, nil);
  14.320 +    NSData *decryptedData = [dec.outputStream propertyForKey: NSStreamDataWrittenToMemoryStreamKey];
  14.321 +    [dec release];
  14.322 +    decrypted = [[NSString alloc] initWithData: decryptedData
  14.323 +                                                      encoding: NSUTF8StringEncoding];
  14.324 +    Log(@"Decrypted = '%@'", decrypted);
  14.325 +    CAssertEqual(decrypted, @"This is a test. This is only a test.");
  14.326 +    [encrypted release];
  14.327 +    [decrypted release];
  14.328 +}
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/MYDigest.h	Sat Apr 04 20:42:03 2009 -0700
    15.3 @@ -0,0 +1,81 @@
    15.4 +//
    15.5 +//  MYDigest.h
    15.6 +//  MYCrypto
    15.7 +//
    15.8 +//  Created by Jens Alfke on 1/4/08.
    15.9 +//  Copyright 2008 Jens Alfke. All rights reserved.
   15.10 +//
   15.11 +
   15.12 +#import <Foundation/Foundation.h>
   15.13 +
   15.14 +
   15.15 +/** Abstract superclass for cryptographic digests (aka hashes).
   15.16 +    Each specific type of digest has its own concrete subclass. */
   15.17 +@interface MYDigest : NSObject <NSCoding, NSCopying>
   15.18 +{
   15.19 +    void *_rawDigest;
   15.20 +}
   15.21 +
   15.22 +- (id) initWithRawDigest: (const void*)rawDigest length: (size_t)length;
   15.23 +
   15.24 ++ (MYDigest*) digestFromDigestData: (NSData*)digestData;
   15.25 ++ (MYDigest*) digestFromHexString: (NSString*)hexString;
   15.26 +
   15.27 ++ (MYDigest*) digestOfData: (NSData*)data;
   15.28 ++ (MYDigest*) digestOfBytes: (const void*)bytes length: (size_t)length;
   15.29 +
   15.30 +- (NSComparisonResult) compare: (MYDigest*)other;
   15.31 +
   15.32 +@property (readonly) NSData *asData;
   15.33 +@property (readonly) NSString *hexString, *abbreviatedHexString;
   15.34 +
   15.35 +@property (readonly) uint32_t /*CSSM_ALGORITHMS*/ algorithm;
   15.36 +@property (readonly) size_t length;
   15.37 +@property (readonly) const void* bytes;
   15.38 +
   15.39 ++ (uint32_t /*CSSM_ALGORITHMS*/) algorithm;
   15.40 ++ (size_t) length;
   15.41 +
   15.42 +/** Primitive digest generation method; abstract of course. */
   15.43 ++ (void) computeDigest: (void*)dstDigest ofBytes: (const void*)bytes length: (size_t)length;
   15.44 +
   15.45 +@end
   15.46 +
   15.47 +
   15.48 +/** A simple C struct containing a 160-bit SHA-1 digest. */
   15.49 +typedef struct {
   15.50 +    UInt8 bytes[20];
   15.51 +} RawSHA1Digest;
   15.52 +    
   15.53 +/** A 160-bit SHA-1 digest encapsulated in an object. */
   15.54 +@interface MYSHA1Digest : MYDigest
   15.55 +
   15.56 +- (MYSHA1Digest*) initWithRawSHA1Digest: (const RawSHA1Digest*)rawDigest;
   15.57 ++ (MYSHA1Digest*) digestFromRawSHA1Digest: (const RawSHA1Digest*)rawDigest;
   15.58 +
   15.59 +@property (readonly) const RawSHA1Digest* rawSHA1Digest;
   15.60 +
   15.61 +@end
   15.62 +
   15.63 +
   15.64 +/** A simple C struct containing a 256-bit SHA-256 digest. */
   15.65 +typedef struct {
   15.66 +    UInt8 bytes[32];
   15.67 +} RawSHA256Digest;
   15.68 +
   15.69 +/** A 256-bit SHA-256 digest encapsulated in an object. */
   15.70 +@interface MYSHA256Digest : MYDigest
   15.71 +
   15.72 +- (MYSHA256Digest*) initWithRawSHA256Digest: (const RawSHA256Digest*)rawDigest;
   15.73 ++ (MYSHA256Digest*) digestFromRawSHA256Digest: (const RawSHA256Digest*)rawDigest;
   15.74 +
   15.75 +@property (readonly) const RawSHA256Digest* rawSHA256Digest;
   15.76 +
   15.77 +@end
   15.78 +
   15.79 +
   15.80 +/** Convenience methods for NSData objects */
   15.81 +@interface NSData (MYDigest)
   15.82 +@property (readonly) MYSHA1Digest* my_SHA1Digest;
   15.83 +@property (readonly) MYSHA256Digest* my_SHA256Digest;
   15.84 +@end
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/MYDigest.m	Sat Apr 04 20:42:03 2009 -0700
    16.3 @@ -0,0 +1,278 @@
    16.4 +//
    16.5 +//  MYDigest.m
    16.6 +//  MYCrypto
    16.7 +//
    16.8 +//  Created by Jens Alfke on 1/4/08.
    16.9 +//  Copyright 2008 Jens Alfke. All rights reserved.
   16.10 +//
   16.11 +
   16.12 +#import "MYDigest.h"
   16.13 +#import <CommonCrypto/CommonDigest.h>
   16.14 +#import "MYCrypto_Private.h"
   16.15 +
   16.16 +
   16.17 +#if USE_IPHONE_API
   16.18 +enum {
   16.19 +    CSSM_ALGID_SHA1 = 8,
   16.20 +    CSSM_ALGID_SHA256 = 0x80000000 + 14
   16.21 +};
   16.22 +#endif
   16.23 +
   16.24 +
   16.25 +@implementation MYDigest
   16.26 +
   16.27 ++ (uint32_t) algorithm {
   16.28 +    AssertAbstractMethod();
   16.29 +}
   16.30 +
   16.31 ++ (size_t) length {
   16.32 +    AssertAbstractMethod();
   16.33 +}
   16.34 +
   16.35 ++ (void) computeDigest: (void*)dstDigest ofBytes: (const void*)bytes length: (size_t)length {
   16.36 +    AssertAbstractMethod();
   16.37 +}
   16.38 +
   16.39 +
   16.40 +- (id) initWithRawDigest: (const void*)rawDigest length: (size_t)length {
   16.41 +    Assert([self class] != [MYDigest class], @"MYDigest is an abstract class");
   16.42 +    Assert(rawDigest!=NULL);
   16.43 +    AssertEq(length,[[self class] length]);
   16.44 +    self = [super init];
   16.45 +    if (self) {
   16.46 +        _rawDigest = malloc(length);
   16.47 +        Assert(_rawDigest);
   16.48 +        memcpy(_rawDigest,rawDigest,length);
   16.49 +    }
   16.50 +    return self;
   16.51 +}
   16.52 +
   16.53 +- (void) dealloc
   16.54 +{
   16.55 +    if(_rawDigest) free(_rawDigest);
   16.56 +    [super dealloc];
   16.57 +}
   16.58 +
   16.59 +
   16.60 +- (id) copyWithZone: (NSZone*)zone
   16.61 +{
   16.62 +    return [self retain];
   16.63 +}
   16.64 +
   16.65 +- (id)initWithCoder:(NSCoder *)decoder
   16.66 +{
   16.67 +    NSUInteger length;
   16.68 +    const void *bytes = [decoder decodeBytesForKey: @"digest" returnedLength: &length];
   16.69 +    return [self initWithRawDigest: bytes length: length];
   16.70 +}
   16.71 +
   16.72 +
   16.73 +- (void)encodeWithCoder:(NSCoder *)coder
   16.74 +{
   16.75 +    [coder encodeBytes: self.bytes length: self.length forKey: @"digest"];
   16.76 +}
   16.77 +
   16.78 +
   16.79 ++ (MYDigest*) digestFromDigestData: (NSData*)digestData {
   16.80 +    return [[[self alloc] initWithRawDigest: digestData.bytes length: digestData.length] autorelease];
   16.81 +}
   16.82 +
   16.83 ++ (MYDigest*) digestFromHexString: (NSString*)hexString
   16.84 +{
   16.85 +    const char *cStr = [hexString UTF8String];
   16.86 +    const size_t length = [self length];
   16.87 +    if( !cStr || strlen(cStr)!=2*length )
   16.88 +        return nil;
   16.89 +    uint8_t digest[length];
   16.90 +    for( int i=0; i<length; i++ ) {
   16.91 +        if( sscanf(cStr, "%2hhx", &digest[i]) != 1 )
   16.92 +            return nil;
   16.93 +        cStr += 2;
   16.94 +    }
   16.95 +    return [[[self alloc] initWithRawDigest: &digest length: length] autorelease];
   16.96 +}
   16.97 +
   16.98 ++ (MYDigest*) digestOfData: (NSData*)data {
   16.99 +    return [self digestOfBytes: data.bytes length: data.length];
  16.100 +}
  16.101 ++ (MYDigest*) digestOfBytes: (const void*)bytes length: (size_t)length {
  16.102 +    const size_t digestLength = [self length];
  16.103 +    uint8_t digest[digestLength];
  16.104 +    [self computeDigest: digest ofBytes: bytes length: length];
  16.105 +    return [[[self alloc] initWithRawDigest: &digest length: digestLength] autorelease];
  16.106 +}
  16.107 +
  16.108 +- (uint32_t) algorithm {
  16.109 +    return [[self class] algorithm];
  16.110 +}
  16.111 +
  16.112 +- (size_t) length {
  16.113 +    return [[self class] length];
  16.114 +}
  16.115 +
  16.116 +- (const void*) bytes {
  16.117 +    return _rawDigest;
  16.118 +}
  16.119 +
  16.120 +
  16.121 +- (BOOL) isEqual: (id)digest
  16.122 +{
  16.123 +    return [digest isKindOfClass: [MYDigest class]]
  16.124 +        && [digest algorithm] == self.algorithm
  16.125 +        && memcmp(self.bytes, [digest bytes], self.length)==0;
  16.126 +}
  16.127 +
  16.128 +- (NSUInteger) hash
  16.129 +{
  16.130 +    return *(NSUInteger*)self.bytes;
  16.131 +    //? This makes the hashcode endian-dependent. Does that matter?
  16.132 +}
  16.133 +
  16.134 +- (NSComparisonResult) compare: (MYDigest*)other
  16.135 +{
  16.136 +    size_t size=self.length, otherSize=other.length;
  16.137 +    NSComparisonResult cmp = memcmp(self.bytes, other.bytes, MIN(size,otherSize));
  16.138 +    return cmp ? cmp : ((int)size - (int)otherSize);
  16.139 +}
  16.140 +
  16.141 +
  16.142 +- (NSData*) asData
  16.143 +{
  16.144 +    return [NSData dataWithBytes: self.bytes length: self.length];
  16.145 +}
  16.146 +
  16.147 +- (NSString*) description
  16.148 +{
  16.149 +    return [NSString stringWithFormat: @"%@[%@]", [self class], [self abbreviatedHexString]];
  16.150 +}
  16.151 +
  16.152 +- (NSString*) hexString
  16.153 +{
  16.154 +    const uint8_t *bytes = self.bytes;
  16.155 +    size_t length = self.length;
  16.156 +    char out[2*length+1];
  16.157 +    char *dst = &out[0];
  16.158 +    for( int i=0; i<length; i+=1 )
  16.159 +        dst += sprintf(dst,"%02X", bytes[i]);
  16.160 +    return [[[NSString alloc] initWithBytes: out length: 2*length encoding: NSASCIIStringEncoding]
  16.161 +            autorelease];
  16.162 +}
  16.163 +
  16.164 +- (NSString*) abbreviatedHexString
  16.165 +{
  16.166 +    const uint8_t *bytes = self.bytes;
  16.167 +    return [NSString stringWithFormat: @"%02hhX%02hhX%02hhX%02hhX...",
  16.168 +            bytes[0],bytes[1],bytes[2],bytes[3]];
  16.169 +}
  16.170 +
  16.171 +
  16.172 +@end
  16.173 +
  16.174 +
  16.175 +
  16.176 +@implementation MYSHA1Digest
  16.177 +
  16.178 ++ (void) computeDigest: (void*)dstDigest ofBytes: (const void*)bytes length: (size_t)length {
  16.179 +    NSParameterAssert(bytes!=NULL);
  16.180 +    NSParameterAssert(length>0);
  16.181 +    CC_SHA1(bytes,length, dstDigest);
  16.182 +}
  16.183 +
  16.184 ++ (uint32_t) algorithm            {return CSSM_ALGID_SHA1;}
  16.185 ++ (size_t) length               {return sizeof(RawSHA1Digest);}
  16.186 +
  16.187 +- (MYSHA1Digest*) initWithRawSHA1Digest: (const RawSHA1Digest*)rawDigest {
  16.188 +    return [super initWithRawDigest: rawDigest length: sizeof(*rawDigest)];
  16.189 +}
  16.190 +
  16.191 ++ (MYSHA1Digest*) digestFromRawSHA1Digest: (const RawSHA1Digest*)rawDigest {
  16.192 +    return [[[self alloc] initWithRawSHA1Digest: rawDigest] autorelease];
  16.193 +}
  16.194 +
  16.195 +- (const RawSHA1Digest*) rawSHA1Digest {
  16.196 +    return self.bytes;
  16.197 +}
  16.198 +
  16.199 +
  16.200 +@end
  16.201 +
  16.202 +
  16.203 +
  16.204 +@implementation MYSHA256Digest
  16.205 +
  16.206 ++ (void) computeDigest: (void*)dstDigest ofBytes: (const void*)bytes length: (size_t)length {
  16.207 +    NSParameterAssert(bytes!=NULL);
  16.208 +    NSParameterAssert(length>0);
  16.209 +    CC_SHA256(bytes,length, dstDigest);
  16.210 +}
  16.211 +
  16.212 ++ (uint32_t) algorithm            {return CSSM_ALGID_SHA256;}
  16.213 ++ (size_t) length               {return sizeof(RawSHA256Digest);}
  16.214 +
  16.215 +- (MYSHA256Digest*) initWithRawSHA256Digest: (const RawSHA256Digest*)rawDigest {
  16.216 +    return [super initWithRawDigest: rawDigest length: sizeof(*rawDigest)];
  16.217 +}
  16.218 +
  16.219 ++ (MYSHA256Digest*) digestFromRawSHA256Digest: (const RawSHA256Digest*)rawDigest {
  16.220 +    return [[[self alloc] initWithRawSHA256Digest: rawDigest] autorelease];
  16.221 +}
  16.222 +
  16.223 +- (const RawSHA256Digest*) rawSHA256Digest {
  16.224 +    return self.bytes;
  16.225 +}
  16.226 +
  16.227 +
  16.228 +@end
  16.229 +
  16.230 +
  16.231 +
  16.232 +@implementation NSData (MYDigest)
  16.233 +
  16.234 +- (MYSHA1Digest*) my_SHA1Digest
  16.235 +{
  16.236 +    return (MYSHA1Digest*) [MYSHA1Digest digestOfData: self];
  16.237 +}
  16.238 +
  16.239 +- (MYSHA256Digest*) my_SHA256Digest
  16.240 +{
  16.241 +    return (MYSHA256Digest*) [MYSHA256Digest digestOfData: self];
  16.242 +}
  16.243 +
  16.244 +@end
  16.245 +
  16.246 +
  16.247 +
  16.248 +#import "Test.h"
  16.249 +
  16.250 +
  16.251 +static void testDigestOf( NSData *src, NSString *expectedSHA1Hex, NSString *expectedSHA256Hex )
  16.252 +{
  16.253 +    MYSHA1Digest *d1 = [src my_SHA1Digest];
  16.254 +    NSString *hex = d1.hexString;
  16.255 +    Log(@"Digesting %u bytes to %@",src.length,hex);
  16.256 +    if( expectedSHA1Hex )
  16.257 +        CAssertEqual(hex,expectedSHA1Hex);
  16.258 +    MYSHA1Digest *d2 = (MYSHA1Digest*) [MYSHA1Digest digestFromHexString: hex];
  16.259 +    CAssertEqual(d1,d2);
  16.260 +    CAssertEqual(d2.hexString,hex);
  16.261 +
  16.262 +    MYSHA256Digest *d256 = [src my_SHA256Digest];
  16.263 +    hex = d256.hexString;
  16.264 +    Log(@"Digesting %u bytes to %@",src.length,hex);
  16.265 +    if( expectedSHA256Hex )
  16.266 +        CAssertEqual(hex,expectedSHA256Hex);
  16.267 +    MYSHA256Digest *d256_2 = (MYSHA256Digest*) [MYSHA256Digest digestFromHexString: hex];
  16.268 +    CAssertEqual(d256,d256_2);
  16.269 +    CAssertEqual(d256_2.hexString,hex);
  16.270 +}
  16.271 +
  16.272 +
  16.273 +TestCase(MYDigest) {
  16.274 +    testDigestOf([@"Pack my box with five dozen liquor jugs, you ugly potatoe pie!" 
  16.275 +                          dataUsingEncoding: NSUTF8StringEncoding],
  16.276 +                 @"4F254781ED6C0103BE056DD8418EFBAC0C2EBE3C",
  16.277 +                 @"08AA4BCDDF7654D7AB5CDD25395A4DD8F3BEB5C79FE567D10C1A21B9134F48FD");
  16.278 +    testDigestOf([NSData dataWithContentsOfFile: @"/Library/Desktop Pictures/Nature/Zen Garden.jpg"],
  16.279 +                 @"62A17839B3B86D3543EB2E34D2718A0FE044FA31",
  16.280 +                 @"FBD25FA6CEE794049973DE3BDF752345617FCA81018C8FC65350BCDD901142DB");
  16.281 +}
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/MYKey-iPhone.m	Sat Apr 04 20:42:03 2009 -0700
    17.3 @@ -0,0 +1,151 @@
    17.4 +//
    17.5 +//  MYKey-iPhone.m
    17.6 +//  MYCrypto-iPhone
    17.7 +//
    17.8 +//  Created by Jens Alfke on 4/4/09.
    17.9 +//  Copyright 2009 Jens Alfke. All rights reserved.
   17.10 +//
   17.11 +
   17.12 +
   17.13 +#import "MYCrypto_Private.h"
   17.14 +
   17.15 +#if USE_IPHONE_API
   17.16 +
   17.17 +#import "MYDigest.h"
   17.18 +#import "MYErrorUtils.h"
   17.19 +
   17.20 +
   17.21 +#pragma mark -
   17.22 +@implementation MYKey
   17.23 +
   17.24 +
   17.25 +- (id) initWithKeyRef: (SecKeyRef)key {
   17.26 +    self = [super initWithKeychainItemRef: (SecKeychainItemRef)key];
   17.27 +    if (self) {
   17.28 +        _key = key;     // superclass has already CFRetained it
   17.29 +    }
   17.30 +    return self;
   17.31 +}
   17.32 +
   17.33 +
   17.34 +- (id) _initWithKeyData: (NSData*)data
   17.35 +            forKeychain: (SecKeychainRef)keychain
   17.36 +{
   17.37 +    NSDictionary *info = $dict( {(id)kSecClass, (id)kSecClassKey},
   17.38 +                                {(id)kSecAttrKeyType, (id)kSecAttrKeyTypeRSA},
   17.39 +                                {(id)kSecValueData, data},
   17.40 +                                {(id)kSecAttrIsPermanent, $object(keychain!=nil)},
   17.41 +                                {(id)kSecReturnRef, $true} );
   17.42 +    SecKeyRef key;
   17.43 +    if (!check(SecItemAdd((CFDictionaryRef)info, (CFTypeRef*)&key), @"SecItemAdd"))
   17.44 +        return nil;
   17.45 +    else
   17.46 +        return [self initWithKeyRef: (SecKeyRef)key];
   17.47 +}
   17.48 +
   17.49 +- (id) initWithKeyData: (NSData*)data {
   17.50 +    return [self _initWithKeyData: data forKeychain: nil];
   17.51 +}
   17.52 +
   17.53 +
   17.54 +- (NSString*) description {
   17.55 +    return $sprintf(@"%@[%p]", [self class], _key);     //FIX: Can we do anything better?
   17.56 +}
   17.57 +
   17.58 +
   17.59 +- (SecExternalItemType) keyType {
   17.60 +    AssertAbstractMethod();
   17.61 +}
   17.62 +
   17.63 +
   17.64 +- (NSData*) keyData {
   17.65 +    NSDictionary *info = $dict( {(id)kSecClass, (id)kSecClassKey},
   17.66 +                                {(id)kSecAttrKeyType, (id)self.keyType},
   17.67 +                                {(id)kSecMatchItemList, $array((id)_key)},
   17.68 +                                {(id)kSecReturnData, $true} );
   17.69 +    CFDataRef data;
   17.70 +    if (!check(SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef*)&data), @"SecItemCopyMatching"))
   17.71 +        return nil;
   17.72 +    else
   17.73 +        return [(id)CFMakeCollectable(data) autorelease];
   17.74 +}
   17.75 +
   17.76 +
   17.77 +@synthesize keyRef=_key;
   17.78 +
   17.79 +
   17.80 +- (MYKey*) asKey {
   17.81 +    return self;
   17.82 +}
   17.83 +
   17.84 +
   17.85 +- (id) _attribute: (CFTypeRef)attribute {
   17.86 +    NSDictionary *info = $dict( {(id)kSecClass, (id)kSecClassKey},
   17.87 +                                {(id)kSecAttrKeyType, (id)self.keyType},
   17.88 +                                {(id)kSecMatchItemList, $array((id)_key)},
   17.89 +                                {(id)kSecReturnAttributes, $true} );
   17.90 +    CFDictionaryRef attrs;
   17.91 +    if (!check(SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef*)&attrs), @"SecItemCopyMatching"))
   17.92 +        return nil;
   17.93 +    CFTypeRef rawValue = CFDictionaryGetValue(attrs,attribute);
   17.94 +    id value = rawValue ?[[(id)CFMakeCollectable(rawValue) retain] autorelease] :nil;
   17.95 +    CFRelease(attrs);
   17.96 +    return value;
   17.97 +}
   17.98 +
   17.99 +- (BOOL) setValue: (NSString*)value ofAttribute: (SecKeychainAttrType)attribute {
  17.100 +    if (!value)
  17.101 +        value = (id)[NSNull null];
  17.102 +    NSDictionary *query = $dict( {(id)kSecClass, (id)kSecClassKey},
  17.103 +                                {(id)kSecAttrKeyType, (id)self.keyType},
  17.104 +                                {(id)kSecMatchItemList, self._itemList} );
  17.105 +    NSDictionary *attrs = $dict( {(id)attribute, value} );
  17.106 +    return check(SecItemUpdate((CFDictionaryRef)query, (CFDictionaryRef)attrs), @"SecItemUpdate");
  17.107 +}
  17.108 +
  17.109 +
  17.110 +- (NSString*) name {
  17.111 +    return [self _attribute: kSecAttrLabel];
  17.112 +}
  17.113 +
  17.114 +- (void) setName: (NSString*)name {
  17.115 +    [self setValue: name ofAttribute: kSecAttrLabel];
  17.116 +}
  17.117 +
  17.118 +- (NSString*) alias {
  17.119 +    return [self _attribute: kSecAttrApplicationTag];
  17.120 +}
  17.121 +
  17.122 +- (void) setAlias: (NSString*)alias {
  17.123 +    [self setValue: alias ofAttribute: kSecAttrApplicationTag];
  17.124 +}
  17.125 +
  17.126 +
  17.127 +@end
  17.128 +
  17.129 +
  17.130 +#endif USE_IPHONE_API
  17.131 +
  17.132 +
  17.133 +
  17.134 +/*
  17.135 + Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
  17.136 + 
  17.137 + Redistribution and use in source and binary forms, with or without modification, are permitted
  17.138 + provided that the following conditions are met:
  17.139 + 
  17.140 + * Redistributions of source code must retain the above copyright notice, this list of conditions
  17.141 + and the following disclaimer.
  17.142 + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
  17.143 + and the following disclaimer in the documentation and/or other materials provided with the
  17.144 + distribution.
  17.145 + 
  17.146 + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
  17.147 + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
  17.148 + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
  17.149 + BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  17.150 + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
  17.151 +  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
  17.152 + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
  17.153 + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  17.154 + */
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/MYKey.h	Sat Apr 04 20:42:03 2009 -0700
    18.3 @@ -0,0 +1,78 @@
    18.4 +//
    18.5 +//  MYKey.h
    18.6 +//  MYCrypto
    18.7 +//
    18.8 +//  Created by Jens Alfke on 3/30/09.
    18.9 +//  Copyright 2009 Jens Alfke. All rights reserved.
   18.10 +//
   18.11 +
   18.12 +#import "MYKeychainItem.h"
   18.13 +
   18.14 +#if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
   18.15 +typedef CFTypeRef SecExternalItemType;
   18.16 +#endif
   18.17 +
   18.18 +
   18.19 +@interface MYKey : MYKeychainItem
   18.20 +{
   18.21 +    @private
   18.22 +    SecKeyRef _key;
   18.23 +}
   18.24 +
   18.25 +/** Creates a MYKey object for an existing Keychain key reference. */
   18.26 +- (id) initWithKeyRef: (SecKeyRef)keyRef;
   18.27 +
   18.28 +/** Creates a MYKey object from exported key data, but does not add it to any keychain. */
   18.29 +- (id) initWithKeyData: (NSData*)data;
   18.30 +
   18.31 +#if !TARGET_OS_IPHONE
   18.32 +/** Converts the key into a data blob in one of several standard formats, suitable for storing in
   18.33 +    a file or sending over the network.
   18.34 +    @param format  The data format: kSecFormatOpenSSL, kSecFormatSSH, kSecFormatBSAFE or kSecFormatSSHv2.
   18.35 +    @param withPEM  YES if the data should be encoded in PEM format, which converts into short lines
   18.36 +        of printable ASCII characters, suitable for sending in email. */
   18.37 +- (NSData*) exportKeyInFormat: (SecExternalFormat)format withPEM: (BOOL)withPEM;
   18.38 +#endif
   18.39 +
   18.40 +/** The Keychain object reference for this key. */
   18.41 +@property (readonly) SecKeyRef keyRef;
   18.42 +
   18.43 +/** The key's raw data in OpenSSL format. This is the same as calling
   18.44 +    -exportKeyInFormat: kSecFormatOpenSSL withPEM: NO */
   18.45 +@property (readonly) NSData *keyData;
   18.46 +
   18.47 +@property (readonly) SecExternalItemType keyType;
   18.48 +
   18.49 +/** The user-visible name (kSecKeyPrintName) associated with this key in the Keychain.
   18.50 +    The user can edit this, so don't expect it to be immutable. */
   18.51 +@property (copy) NSString *name;
   18.52 +
   18.53 +/** An application-specific string (kSecKeyAlias) associated with this key in the Keychain.
   18.54 +    Not visible to or editable by the user.
   18.55 +    If you own this key, you can store any associated metadata you like here, although be aware
   18.56 +    that it can be read and modified by any other app that can access this key. */
   18.57 +@property (copy) NSString *alias;
   18.58 +
   18.59 +#if !TARGET_OS_IPHONE
   18.60 +/** The user-visible comment (kSecKeyApplicationTag) associated with this key in the Keychain.
   18.61 +    The user can edit this, so don't expect it to be immutable. */
   18.62 +@property (copy) NSString *comment;
   18.63 +#endif
   18.64 +
   18.65 +@end
   18.66 +
   18.67 +
   18.68 +
   18.69 +@protocol MYEncryption <NSObject>
   18.70 +
   18.71 +/** Encrypts data using this key, returning the raw encrypted result. */
   18.72 +- (NSData*) encryptData: (NSData*)data;
   18.73 +
   18.74 +@end
   18.75 +
   18.76 +@protocol MYDecryption <NSObject>
   18.77 +
   18.78 +/** Decrypts data using this key, returning the original data. */
   18.79 +- (NSData*) decryptData: (NSData*)data;
   18.80 +
   18.81 +@end
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/MYKey.m	Sat Apr 04 20:42:03 2009 -0700
    19.3 @@ -0,0 +1,174 @@
    19.4 +//
    19.5 +//  MYKey.m
    19.6 +//  MYCrypto
    19.7 +//
    19.8 +//  Created by Jens Alfke on 3/21/09.
    19.9 +//  Copyright 2009 Jens Alfke. All rights reserved.
   19.10 +//
   19.11 +
   19.12 +#import "MYKey.h"
   19.13 +#import "MYCrypto_Private.h"
   19.14 +#import "MYDigest.h"
   19.15 +#import "MYErrorUtils.h"
   19.16 +
   19.17 +#if !USE_IPHONE_API
   19.18 +
   19.19 +
   19.20 +#pragma mark -
   19.21 +@implementation MYKey
   19.22 +
   19.23 +
   19.24 +- (id) initWithKeyRef: (SecKeyRef)key {
   19.25 +    self = [super initWithKeychainItemRef: (SecKeychainItemRef)key];
   19.26 +    if (self) {
   19.27 +        _key = key;     // superclass has already CFRetained it
   19.28 +    }
   19.29 +    return self;
   19.30 +}
   19.31 +
   19.32 +- (id) _initWithKeyData: (NSData*)data
   19.33 +            forKeychain: (SecKeychainRef)keychain {
   19.34 +    SecKeyImportExportParameters params = {};
   19.35 +    SecKeyRef key = importKey(data, self.keyType, keychain, &params);
   19.36 +    if (!key) {
   19.37 +        [self release];
   19.38 +        return nil;
   19.39 +    }
   19.40 +    self = [super initWithKeychainItemRef: (SecKeychainItemRef)key];
   19.41 +    if (self) {
   19.42 +        _key = key;
   19.43 +    }
   19.44 +    CFRelease(key);
   19.45 +    return self;
   19.46 +}
   19.47 +
   19.48 +- (id) initWithKeyData: (NSData*)data {
   19.49 +    return [self _initWithKeyData: data forKeychain: nil];
   19.50 +}
   19.51 +
   19.52 +
   19.53 +- (NSString*) description {
   19.54 +    return $sprintf(@"%@[%p]", [self class], _key);     //FIX: Can we do anything better?
   19.55 +}
   19.56 +
   19.57 +
   19.58 +- (SecExternalItemType) keyType {
   19.59 +    AssertAbstractMethod();
   19.60 +}
   19.61 +
   19.62 +
   19.63 +@synthesize keyRef=_key;
   19.64 +
   19.65 +
   19.66 +- (MYKey*) asKey {
   19.67 +    return self;
   19.68 +}
   19.69 +
   19.70 +- (const CSSM_KEY*) cssmKey {
   19.71 +    const CSSM_KEY *cssmKey = NULL;
   19.72 +    Assert(check(SecKeyGetCSSMKey(_key, &cssmKey), @"SecKeyGetCSSMKey"), @"Failed to get CSSM_KEY");
   19.73 +    return cssmKey;
   19.74 +}
   19.75 +
   19.76 +- (NSData*) exportKeyInFormat: (SecExternalFormat)format withPEM: (BOOL)withPEM {
   19.77 +    CFDataRef data = NULL;
   19.78 +    if (check(SecKeychainItemExport(_key, format, (withPEM ?kSecItemPemArmour :0), NULL, &data),
   19.79 +              @"SecKeychainItemExport"))
   19.80 +        return [(id)CFMakeCollectable(data) autorelease];
   19.81 +    else
   19.82 +        return nil;
   19.83 +}
   19.84 +
   19.85 +- (NSData*) keyData {
   19.86 +    return [self exportKeyInFormat: kSecFormatRawKey withPEM: NO];
   19.87 +}
   19.88 +
   19.89 +- (NSString*) name {
   19.90 +    return [self stringValueOfAttribute: kSecKeyPrintName];
   19.91 +}
   19.92 +
   19.93 +- (void) setName: (NSString*)name {
   19.94 +    [self setValue: name ofAttribute: kSecKeyPrintName];
   19.95 +}
   19.96 +
   19.97 +- (NSString*) comment {
   19.98 +    return [self stringValueOfAttribute: kSecKeyApplicationTag];
   19.99 +}
  19.100 +
  19.101 +- (void) setComment: (NSString*)comment {
  19.102 +    [self setValue: comment ofAttribute: kSecKeyApplicationTag];
  19.103 +}
  19.104 +
  19.105 +- (NSString*) alias {
  19.106 +    return [self stringValueOfAttribute: kSecKeyAlias];
  19.107 +}
  19.108 +
  19.109 +- (void) setAlias: (NSString*)alias {
  19.110 +    [self setValue: alias ofAttribute: kSecKeyAlias];
  19.111 +}
  19.112 +
  19.113 +
  19.114 +@end
  19.115 +
  19.116 +
  19.117 +
  19.118 +
  19.119 +#pragma mark -
  19.120 +#pragma mark UTILITY FUNCTIONS:
  19.121 +
  19.122 +
  19.123 +SecKeyRef importKey(NSData *data, 
  19.124 +                    SecExternalItemType type,
  19.125 +                    SecKeychainRef keychain,
  19.126 +                    SecKeyImportExportParameters *params) {
  19.127 +    SecExternalFormat inputFormat = (type==kSecItemTypeSessionKey) ?kSecFormatRawKey :kSecFormatOpenSSL;
  19.128 +    CFArrayRef items = NULL;
  19.129 +    
  19.130 +    params->version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
  19.131 +    params->flags |= kSecKeyImportOnlyOne;
  19.132 +    if (keychain) {
  19.133 +        params->keyAttributes = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT;
  19.134 +        if (type==kSecItemTypeSessionKey)
  19.135 +            params->keyUsage = CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT;
  19.136 +        else if (type==kSecItemTypePublicKey)
  19.137 +            params->keyUsage = CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_VERIFY;
  19.138 +        else if (type==kSecItemTypePrivateKey)
  19.139 +            params->keyUsage = CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_SIGN;
  19.140 +    }
  19.141 +    if (!check(SecKeychainItemImport((CFDataRef)data, NULL, &inputFormat, &type,
  19.142 +                                     0, params, keychain, &items),
  19.143 +               @"SecKeychainItemImport"))
  19.144 +        return nil;
  19.145 +    if (!items || CFArrayGetCount(items) != 1)
  19.146 +        return nil;
  19.147 +    SecKeyRef key = (SecKeyRef)CFRetain(CFArrayGetValueAtIndex(items,0));
  19.148 +    CFRelease(items);
  19.149 +    return key; // caller must CFRelease
  19.150 +}    
  19.151 +
  19.152 +
  19.153 +#endif USE_IPHONE_API
  19.154 +
  19.155 +
  19.156 +
  19.157 +/*
  19.158 + Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
  19.159 + 
  19.160 + Redistribution and use in source and binary forms, with or without modification, are permitted
  19.161 + provided that the following conditions are met:
  19.162 + 
  19.163 + * Redistributions of source code must retain the above copyright notice, this list of conditions
  19.164 + and the following disclaimer.
  19.165 + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
  19.166 + and the following disclaimer in the documentation and/or other materials provided with the
  19.167 + distribution.
  19.168 + 
  19.169 + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
  19.170 + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
  19.171 + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
  19.172 + BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  19.173 + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
  19.174 +  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
  19.175 + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
  19.176 + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  19.177 + */
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/MYKeyPair-iPhone.m	Sat Apr 04 20:42:03 2009 -0700
    20.3 @@ -0,0 +1,81 @@
    20.4 +//
    20.5 +//  MYKeyPair-iPhone.m
    20.6 +//  MYNetwork-iPhone
    20.7 +//
    20.8 +//  Created by Jens Alfke on 3/22/09.
    20.9 +//  Copyright 2009 Jens Alfke. All rights reserved.
   20.10 +//
   20.11 +
   20.12 +
   20.13 +#import "MYKeyPair.h"
   20.14 +#import "MYCrypto_Private.h"
   20.15 +
   20.16 +#if USE_IPHONE_API
   20.17 +
   20.18 +
   20.19 +@implementation MYKeyPair
   20.20 +
   20.21 +
   20.22 ++ (MYKeyPair*) _generateKeyPairOfSize: (unsigned)keySize inKeychain: (MYKeychain*)keychain {
   20.23 +    Assert( keySize == 512 || keySize == 1024 || keySize == 2048, @"Unsupported key size %u", keySize );
   20.24 +    SecKeyRef pubKey=NULL, privKey=NULL;
   20.25 +    OSStatus err;
   20.26 +    NSDictionary *pubKeyAttrs = $dict({(id)kSecAttrIsPermanent, $true});
   20.27 +    NSDictionary *privKeyAttrs = $dict({(id)kSecAttrIsPermanent, $true});
   20.28 +    NSDictionary *keyAttrs = $dict( {(id)kSecAttrKeyType, (id)kSecAttrKeyTypeRSA},
   20.29 +                                    {(id)kSecAttrKeySizeInBits, $object(keySize)},
   20.30 +                                    {(id)kSecPublicKeyAttrs, pubKeyAttrs},
   20.31 +                                    {(id)kSecPrivateKeyAttrs, privKeyAttrs} );
   20.32 +    err = SecKeyGeneratePair((CFDictionaryRef)keyAttrs,&pubKey,&privKey);
   20.33 +    if (err) {
   20.34 +        Warn(@"Failed to create key-pair: %i", err);
   20.35 +        return nil;
   20.36 +    } else
   20.37 +        return [[[self alloc] initWithPublicKeyRef: pubKey privateKeyRef: privKey] autorelease];
   20.38 +}
   20.39 +
   20.40 +- (id) initWithPublicKeyRef: (SecKeyRef)publicKey privateKeyRef: (SecKeyRef)privateKey {
   20.41 +    self = [super initWithKeyRef: publicKey];
   20.42 +    if (self) {
   20.43 +        NSParameterAssert(privateKey);
   20.44 +        _privateKey = (SecKeyRef) CFRetain(privateKey);
   20.45 +    }
   20.46 +    return self;
   20.47 +}
   20.48 +
   20.49 +
   20.50 +- (NSArray*) _itemList {
   20.51 +    return $array((id)_privateKey,(id)self.keyRef);
   20.52 +}
   20.53 +
   20.54 +
   20.55 +@synthesize privateKeyRef=_privateKey;
   20.56 +
   20.57 +
   20.58 +- (NSData*) decryptData: (NSData*)data {
   20.59 +    return _crypt(_privateKey,data,kCCDecrypt);
   20.60 +}
   20.61 +    
   20.62 +
   20.63 +- (NSData*) signData: (NSData*)data {
   20.64 +    Assert(data);
   20.65 +    uint8_t digest[CC_SHA1_DIGEST_LENGTH];
   20.66 +    CC_SHA1(data.bytes,data.length, digest);
   20.67 +
   20.68 +    size_t sigLen = 1024;
   20.69 +    uint8_t sigBuf[sigLen];
   20.70 +    OSStatus err = SecKeyRawSign(_privateKey, kSecPaddingPKCS1SHA1,
   20.71 +                                   digest,sizeof(digest), //data.bytes, data.length,
   20.72 +                                   sigBuf, &sigLen);
   20.73 +    if(err) {
   20.74 +        Warn(@"SecKeyRawSign failed: %i",err);
   20.75 +        return nil;
   20.76 +    } else
   20.77 +        return [NSData dataWithBytes: sigBuf length: sigLen];
   20.78 +}
   20.79 +
   20.80 +
   20.81 +@end
   20.82 +
   20.83 +
   20.84 +#endif USE_IPHONE_API
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/MYKeyPair.h	Sat Apr 04 20:42:03 2009 -0700
    21.3 @@ -0,0 +1,54 @@
    21.4 +//
    21.5 +//  KeyPair.h
    21.6 +//  MYCrypto
    21.7 +//
    21.8 +//  Created by Jens Alfke on 3/21/09.
    21.9 +//  Copyright 2009 Jens Alfke. All rights reserved.
   21.10 +//
   21.11 +
   21.12 +#import "MYPublicKey.h"
   21.13 +
   21.14 +
   21.15 +/** A key-pair consisting of a public and a private key.
   21.16 +    Can be used for signing and decrypting, as well as the inherited encrypting/verifying. */
   21.17 +@interface MYKeyPair : MYPublicKey <MYDecryption>
   21.18 +{
   21.19 +    SecKeyRef _privateKey;
   21.20 +}
   21.21 +
   21.22 +/** Creates a MYKeyPair object from existing Keychain key references. */
   21.23 +- (id) initWithPublicKeyRef: (SecKeyRef)publicKey privateKeyRef: (SecKeyRef)privateKey;
   21.24 +
   21.25 +#if !TARGET_OS_IPHONE
   21.26 +/** Exports the private key as a data blob, so that it can be stored as a backup, or transferred
   21.27 +    to another computer. Since the key is sensitive, it must be exported in encrypted form
   21.28 +    using a user-chosen passphrase. This method will display a standard alert panel, run by
   21.29 +    the Security agent, that prompts the user to enter a new passphrase for encrypting the key.
   21.30 +    The same passphrase must be re-entered when importing the key from the data blob.
   21.31 +    @param format  The data format: kSecFormatOpenSSL, kSecFormatSSH, kSecFormatBSAFE or kSecFormatSSHv2.
   21.32 +    @param withPEM  YES if the data should be encoded in PEM format, which converts into short lines
   21.33 +        of printable ASCII characters, suitable for sending in email.
   21.34 +    @param alertTitle  An optional title for the alert panel. (Currently ignored by the OS?)
   21.35 +    @param prompt  An optional prompt message to display in the alert panel. */
   21.36 +- (NSData*) exportPrivateKeyInFormat: (SecExternalFormat)format
   21.37 +                             withPEM: (BOOL)withPEM
   21.38 +                          alertTitle: (NSString*)title
   21.39 +                         alertPrompt: (NSString*)prompt;
   21.40 +
   21.41 +/** A convenient shorthand for the full exportPrivateKeyInFormat... method.
   21.42 +    Uses OpenSSL format, wrapped with PEM, and default title and prompt for the alert. */
   21.43 +- (NSData*) exportPrivateKey;
   21.44 +#endif
   21.45 +
   21.46 +/** The underlying Keychain key reference for the private key. */
   21.47 +@property (readonly) SecKeyRef privateKeyRef;
   21.48 +
   21.49 +/** Decrypts data that was encrypted using the public key. */
   21.50 +- (NSData*) decryptData: (NSData*)data;
   21.51 +
   21.52 +/** Generates a signature of data, using the private key.
   21.53 +    The resulting signature can be verified using the matching MYPublicKey's
   21.54 +    verifySignature:ofData: method. */
   21.55 +- (NSData*) signData: (NSData*)data;
   21.56 +
   21.57 +@end
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/MYKeyPair.m	Sat Apr 04 20:42:03 2009 -0700
    22.3 @@ -0,0 +1,234 @@
    22.4 +//
    22.5 +//  KeyPair.m
    22.6 +//  MYCrypto
    22.7 +//
    22.8 +//  Created by Jens Alfke on 3/21/09.
    22.9 +//  Copyright 2009 Jens Alfke. All rights reserved.
   22.10 +//
   22.11 +
   22.12 +#import "MYKeyPair.h"
   22.13 +#import "MYCrypto_Private.h"
   22.14 +#import <CommonCrypto/CommonDigest.h>
   22.15 +
   22.16 +#if !USE_IPHONE_API
   22.17 +
   22.18 +
   22.19 +#pragma mark -
   22.20 +
   22.21 +@implementation MYKeyPair
   22.22 +
   22.23 +
   22.24 ++ (MYKeyPair*) _generateRSAKeyPairOfSize: (unsigned)keySize
   22.25 +                            inKeychain: (SecKeychainRef)keychain {
   22.26 +    Assert( keySize == 512 || keySize == 1024 || keySize == 2048, @"Unsupported key size %u", keySize );
   22.27 +    SecKeyRef pubKey=NULL, privKey=NULL;
   22.28 +    OSStatus err;
   22.29 +    err = SecKeyCreatePair(keychain, CSSM_ALGID_RSA, keySize, 0LL,
   22.30 +                           CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_VERIFY,        // public key
   22.31 +                           CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT,
   22.32 +                           CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_SIGN,          // private key
   22.33 +                           CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_SENSITIVE | CSSM_KEYATTR_PERMANENT,
   22.34 +                           NULL, // SecAccessRef
   22.35 +                           &pubKey, &privKey);
   22.36 +    if (!check(err, @"SecKeyCreatePair")) {
   22.37 +        return nil;
   22.38 +    } else
   22.39 +        return [[[self alloc] initWithPublicKeyRef: pubKey privateKeyRef: privKey] autorelease];
   22.40 +}
   22.41 +
   22.42 +
   22.43 +- (id) initWithPublicKeyRef: (SecKeyRef)publicKey privateKeyRef: (SecKeyRef)privateKey {
   22.44 +    self = [super initWithKeyRef: publicKey];
   22.45 +    if (self) {
   22.46 +        NSParameterAssert(privateKey);
   22.47 +        _privateKey = (SecKeyRef) CFRetain(privateKey);
   22.48 +    }
   22.49 +    return self;
   22.50 +}
   22.51 +
   22.52 +- (id) _initWithPublicKeyData: (NSData*)pubKeyData
   22.53 +                   privateKey: (SecKeyRef)privateKey 
   22.54 +                  forKeychain: (SecKeychainRef)keychain {
   22.55 +    if (!privateKey) {
   22.56 +        [self release];
   22.57 +        return nil;
   22.58 +    }
   22.59 +    self = [self _initWithKeyData: pubKeyData forKeychain: keychain];
   22.60 +    if (self) {
   22.61 +        _privateKey = privateKey;
   22.62 +    } else {
   22.63 +        SecKeychainItemDelete((SecKeychainItemRef)privateKey);
   22.64 +        CFRelease(privateKey);
   22.65 +    }
   22.66 +    return self;
   22.67 +}
   22.68 +
   22.69 +
   22.70 +// The public API for this is in MYKeychain.
   22.71 +- (id) _initWithPublicKeyData: (NSData*)pubKeyData 
   22.72 +               privateKeyData: (NSData*)privKeyData
   22.73 +                  forKeychain: (SecKeychainRef)keychain 
   22.74 +                   alertTitle: (NSString*)title
   22.75 +                  alertPrompt: (NSString*)prompt
   22.76 +{
   22.77 +    // Try to import the private key first, since the user might cancel the passphrase alert.
   22.78 +    SecKeyImportExportParameters params = {
   22.79 +        .flags = kSecKeySecurePassphrase,
   22.80 +        .alertTitle = (CFStringRef) title,
   22.81 +        .alertPrompt = (CFStringRef) prompt
   22.82 +    };
   22.83 +    SecKeyRef privateKey = importKey(privKeyData,kSecItemTypePrivateKey,keychain,&params);
   22.84 +    return [self _initWithPublicKeyData: pubKeyData privateKey: privateKey forKeychain: keychain];
   22.85 +}
   22.86 +
   22.87 +// This method is for testing, so unit-tests don't require user intervention.
   22.88 +// It's deliberately not made public, to discourage clients from trying to manage the passphrases
   22.89 +// themselves (this is less secure than letting the Security agent do it.)
   22.90 +- (id) _initWithPublicKeyData: (NSData*)pubKeyData 
   22.91 +               privateKeyData: (NSData*)privKeyData
   22.92 +                  forKeychain: (SecKeychainRef)keychain 
   22.93 +                   passphrase: (NSString*)passphrase
   22.94 +{
   22.95 +    SecKeyImportExportParameters params = {
   22.96 +        .passphrase = (CFStringRef) passphrase,
   22.97 +    };
   22.98 +    SecKeyRef privateKey = importKey(privKeyData,kSecItemTypePrivateKey,keychain,&params);
   22.99 +    return [self _initWithPublicKeyData: pubKeyData privateKey: privateKey forKeychain: keychain];
  22.100 +}
  22.101 +
  22.102 +
  22.103 +- (void) dealloc
  22.104 +{
  22.105 +    if (_privateKey) CFRelease(_privateKey);
  22.106 +    [super dealloc];
  22.107 +}
  22.108 +
  22.109 +
  22.110 +- (NSUInteger)hash {
  22.111 +    // Ensure that a KeyPair doesn't hash the same as its corresponding PublicKey:
  22.112 +    return super.hash ^ 0xFFFFFFFF;
  22.113 +}
  22.114 +
  22.115 +
  22.116 +- (MYPublicKey*) asPublicKey {
  22.117 +    return [[[MYPublicKey alloc] initWithKeyRef: self.keyRef] autorelease];
  22.118 +}
  22.119 +
  22.120 +
  22.121 +- (NSData*) exportPrivateKeyInFormat: (SecExternalFormat)format
  22.122 +                             withPEM: (BOOL)withPEM
  22.123 +                          alertTitle: (NSString*)title
  22.124 +                         alertPrompt: (NSString*)prompt
  22.125 +{
  22.126 +    SecKeyImportExportParameters params = {
  22.127 +        .version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION,
  22.128 +        .flags = kSecKeySecurePassphrase,
  22.129 +        .alertTitle = (CFStringRef)title,
  22.130 +        .alertPrompt = (CFStringRef)prompt
  22.131 +    };
  22.132 +    CFDataRef data = NULL;
  22.133 +    if (check(SecKeychainItemExport(_privateKey, //$array((id)_publicKey,(id)_privateKey),
  22.134 +                                    format, (withPEM ?kSecItemPemArmour :0), 
  22.135 +                                    &params, &data),
  22.136 +              @"SecKeychainItemExport"))
  22.137 +        return [(id)CFMakeCollectable(data) autorelease];
  22.138 +    else
  22.139 +        return nil;
  22.140 +}
  22.141 +
  22.142 +- (NSData*) exportPrivateKey {
  22.143 +    return [self exportPrivateKeyInFormat: kSecFormatWrappedOpenSSL withPEM: YES
  22.144 +                               alertTitle: @"Export Private Key"
  22.145 +                              alertPrompt: @"Enter a passphrase to protect the private-key file.\n"
  22.146 +            "You will need to re-enter the passphrase later when importing the key from this file, "
  22.147 +            "so keep it in a safe place."];
  22.148 +    //FIX: Should make these messages localizable.
  22.149 +}
  22.150 +
  22.151 +
  22.152 +- (NSData*) _exportPrivateKeyInFormat: (SecExternalFormat)format
  22.153 +                              withPEM: (BOOL)withPEM
  22.154 +                           passphrase: (NSString*)passphrase
  22.155 +{
  22.156 +    SecKeyImportExportParameters params = {
  22.157 +        .version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION,
  22.158 +        .passphrase = (CFStringRef)passphrase
  22.159 +    };
  22.160 +    CFDataRef data = NULL;
  22.161 +    if (check(SecKeychainItemExport(_privateKey,
  22.162 +                                    format, (withPEM ?kSecItemPemArmour :0), 
  22.163 +                                    &params, &data),
  22.164 +              @"SecKeychainItemExport"))
  22.165 +        return [(id)CFMakeCollectable(data) autorelease];
  22.166 +    else
  22.167 +        return nil;
  22.168 +}
  22.169 +
  22.170 +- (BOOL) removeFromKeychain {
  22.171 +    return check(SecKeychainItemDelete((SecKeychainItemRef)_privateKey), @"delete private key")
  22.172 +        && [super removeFromKeychain];
  22.173 +}
  22.174 +
  22.175 +
  22.176 +@synthesize privateKeyRef=_privateKey;
  22.177 +
  22.178 +
  22.179 +- (NSData*) decryptData: (NSData*)data {
  22.180 +    return _crypt(_privateKey,data,kCCDecrypt);
  22.181 +}
  22.182 +    
  22.183 +
  22.184 +- (NSData*) signData: (NSData*)data {
  22.185 +    Assert(data);
  22.186 +    uint8_t digest[CC_SHA1_DIGEST_LENGTH];
  22.187 +    CC_SHA1(data.bytes,data.length, digest);
  22.188 +    NSData *signature = nil;
  22.189 +    CSSM_CC_HANDLE ccHandle = cssmCreateSignatureContext(_privateKey);
  22.190 +    if (!ccHandle) return nil;
  22.191 +    CSSM_DATA original = {data.length, (void*)data.bytes};
  22.192 +    CSSM_DATA result = {0,NULL};
  22.193 +    if (checkcssm(CSSM_SignData(ccHandle, &original, 1, CSSM_ALGID_NONE, &result), @"CSSM_SignData"))
  22.194 +        signature = [NSData dataWithBytesNoCopy: result.Data length: result.Length
  22.195 +                                   freeWhenDone: YES];
  22.196 +    CSSM_DeleteContext(ccHandle);
  22.197 +    return signature;
  22.198 +}
  22.199 +
  22.200 +
  22.201 +- (BOOL) setValue: (NSString*)valueStr ofAttribute: (SecKeychainAttrType)attr {
  22.202 +    return [super setValue: valueStr ofAttribute: attr]
  22.203 +        && [[self class] _setAttribute: attr 
  22.204 +                                ofItem: (SecKeychainItemRef)_privateKey
  22.205 +                           stringValue: valueStr];
  22.206 +}
  22.207 +
  22.208 +
  22.209 +@end
  22.210 +
  22.211 +
  22.212 +#endif !USE_IPHONE_API
  22.213 +
  22.214 +
  22.215 +
  22.216 +
  22.217 +/*
  22.218 + Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
  22.219 + 
  22.220 + Redistribution and use in source and binary forms, with or without modification, are permitted
  22.221 + provided that the following conditions are met:
  22.222 + 
  22.223 + * Redistributions of source code must retain the above copyright notice, this list of conditions
  22.224 + and the following disclaimer.
  22.225 + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
  22.226 + and the following disclaimer in the documentation and/or other materials provided with the
  22.227 + distribution.
  22.228 + 
  22.229 + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
  22.230 + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
  22.231 + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
  22.232 + BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  22.233 + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
  22.234 +  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
  22.235 + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
  22.236 + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  22.237 + */
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/MYKeychain-iPhone.m	Sat Apr 04 20:42:03 2009 -0700
    23.3 @@ -0,0 +1,269 @@
    23.4 +//
    23.5 +//  MYKeychain-iPhone.m
    23.6 +//  MYCrypto-iPhone
    23.7 +//
    23.8 +//  Created by Jens Alfke on 3/31/09.
    23.9 +//  Copyright 2009 Jens Alfke. All rights reserved.
   23.10 +//
   23.11 +
   23.12 +#import "MYCrypto_Private.h"
   23.13 +#import "MYDigest.h"
   23.14 +
   23.15 +#if USE_IPHONE_API
   23.16 +
   23.17 +
   23.18 +@interface MYKeyEnumerator : NSEnumerator
   23.19 +{
   23.20 +    CFArrayRef _results;
   23.21 +    CFTypeRef _itemClass;
   23.22 +    CFIndex _index;
   23.23 +}
   23.24 +
   23.25 +- (id) initWithQuery: (NSMutableDictionary*)query;
   23.26 ++ (id) firstItemWithQuery: (NSMutableDictionary*)query;
   23.27 +@end
   23.28 +
   23.29 +
   23.30 +
   23.31 +@implementation MYKeychain
   23.32 +
   23.33 +
   23.34 ++ (MYKeychain*) allKeychains
   23.35 +{
   23.36 +    // iPhone only has a single keychain.
   23.37 +    return [self defaultKeychain];
   23.38 +}
   23.39 +
   23.40 ++ (MYKeychain*) defaultKeychain
   23.41 +{
   23.42 +    static MYKeychain *sDefaultKeychain;
   23.43 +    @synchronized(self) {
   23.44 +        if (!sDefaultKeychain) {
   23.45 +            sDefaultKeychain = [[self alloc] init];
   23.46 +        }
   23.47 +    }
   23.48 +    return sDefaultKeychain;
   23.49 +}
   23.50 +
   23.51 +
   23.52 +- (id) copyWithZone: (NSZone*)zone {
   23.53 +    // It's not necessary to make copies of Keychain objects. This makes it more efficient
   23.54 +    // to use instances as NSDictionary keys or store them in NSSets.
   23.55 +    return [self retain];
   23.56 +}
   23.57 +
   23.58 +
   23.59 +
   23.60 +#pragma mark -
   23.61 +#pragma mark SEARCHING:
   23.62 +
   23.63 +
   23.64 +- (MYPublicKey*) publicKeyWithDigest: (MYSHA1Digest*)pubKeyDigest {
   23.65 +    return [MYKeyEnumerator firstItemWithQuery:
   23.66 +                $mdict({(id)kSecClass, (id)kSecClassKey},
   23.67 +                      {(id)kSecAttrPublicKeyHash, pubKeyDigest.asData},
   23.68 +                      {(id)kSecReturnRef, $true})];
   23.69 +}   
   23.70 +
   23.71 +- (NSEnumerator*) enumeratePublicKeys {
   23.72 +    NSMutableDictionary *query = $mdict({(id)kSecClass, (id)kSecClassKey},
   23.73 +                                {(id)kSecAttrKeyClass, (id)kSecAttrKeyClassPublic},
   23.74 +                                {(id)kSecMatchLimit, (id)kSecMatchLimitAll},
   23.75 +                                {(id)kSecReturnRef, $true});
   23.76 +    return [[[MYKeyEnumerator alloc] initWithQuery: query] autorelease];
   23.77 +}
   23.78 +
   23.79 +
   23.80 +- (MYKeyPair*) keyPairWithDigest: (MYSHA1Digest*)pubKeyDigest {
   23.81 +    return [MYKeyEnumerator firstItemWithQuery:
   23.82 +                $mdict({(id)kSecClass, (id)kSecClassKey},
   23.83 +                      {(id)kSecAttrKeyClass, (id)kSecAttrKeyClassPrivate},
   23.84 +                      {(id)kSecAttrPublicKeyHash, pubKeyDigest.asData},
   23.85 +                      {(id)kSecReturnRef, $true})];
   23.86 +}
   23.87 +
   23.88 +- (NSEnumerator*) enumerateKeyPairs {
   23.89 +    NSMutableDictionary *query = $mdict({(id)kSecClass, (id)kSecClassKey},
   23.90 +                                {(id)kSecAttrKeyClass, (id)kSecAttrKeyClassPrivate},
   23.91 +                                {(id)kSecMatchLimit, (id)kSecMatchLimitAll},
   23.92 +                                {(id)kSecReturnRef, $true});
   23.93 +    return [[[MYKeyEnumerator alloc] initWithQuery: query] autorelease];
   23.94 +}
   23.95 +
   23.96 +- (MYCertificate*) certificateWithDigest: (MYSHA1Digest*)pubKeyDigest {
   23.97 +    return [MYKeyEnumerator firstItemWithQuery:
   23.98 +                $mdict({(id)kSecClass, (id)kSecClassCertificate},
   23.99 +                      {(id)kSecAttrPublicKeyHash, pubKeyDigest.asData},
  23.100 +                      {(id)kSecReturnRef, $true})];
  23.101 +}
  23.102 +
  23.103 +- (NSEnumerator*) enumerateCertificates {
  23.104 +    NSMutableDictionary *query = $mdict({(id)kSecClass, (id)kSecClassCertificate},
  23.105 +                                {(id)kSecMatchLimit, (id)kSecMatchLimitAll},
  23.106 +                                {(id)kSecReturnRef, $true});
  23.107 +    return [[[MYKeyEnumerator alloc] initWithQuery: query] autorelease];
  23.108 +}
  23.109 +
  23.110 +- (NSEnumerator*) enumerateSymmetricKeys {
  23.111 +    NSMutableDictionary *query = $mdict({(id)kSecClass, (id)kSecClassKey},
  23.112 +                                {(id)kSecAttrKeyClass, (id)kSecAttrKeyClassSymmetric},
  23.113 +                                {(id)kSecMatchLimit, (id)kSecMatchLimitAll},
  23.114 +                                {(id)kSecReturnRef, $true});
  23.115 +    return [[[MYKeyEnumerator alloc] initWithQuery: query] autorelease];
  23.116 +}
  23.117 +
  23.118 +- (NSEnumerator*) symmetricKeysWithAlias: (NSString*)alias {
  23.119 +    NSMutableDictionary *query = $mdict({(id)kSecClass, (id)kSecClassKey},
  23.120 +                                {(id)kSecAttrKeyClass, (id)kSecAttrKeyClassSymmetric},
  23.121 +                                {(id)kSecAttrApplicationTag, alias},
  23.122 +                                {(id)kSecMatchLimit, (id)kSecMatchLimitAll},
  23.123 +                                {(id)kSecReturnRef, $true});
  23.124 +    return [[[MYKeyEnumerator alloc] initWithQuery: query] autorelease];
  23.125 +}
  23.126 +
  23.127 +
  23.128 +#pragma mark -
  23.129 +#pragma mark IMPORT:
  23.130 +
  23.131 +
  23.132 +- (MYPublicKey*) importPublicKey: (NSData*)keyData {
  23.133 +    return [[[MYPublicKey alloc] _initWithKeyData: keyData 
  23.134 +                                      forKeychain: self]
  23.135 +            autorelease];
  23.136 +}
  23.137 +
  23.138 +- (MYCertificate*) importCertificate: (NSData*)data
  23.139 +{
  23.140 +    Assert(data);
  23.141 +    NSDictionary *info = $dict( {(id)kSecClass, (id)kSecClassCertificate},
  23.142 +                                {(id)kSecValueData, data},
  23.143 +                                {(id)kSecReturnRef, $true} );
  23.144 +    SecCertificateRef cert;
  23.145 +    if (!check(SecItemAdd((CFDictionaryRef)info, (CFTypeRef*)&cert), @"SecItemAdd"))
  23.146 +        return nil;
  23.147 +    return [[[MYCertificate alloc] initWithCertificateRef: cert] autorelease];
  23.148 +}
  23.149 +
  23.150 +
  23.151 +#pragma mark -
  23.152 +#pragma mark GENERATION:
  23.153 +
  23.154 +
  23.155 +- (MYSymmetricKey*) generateSymmetricKeyOfSize: (unsigned)keySizeInBits
  23.156 +                                     algorithm: (CCAlgorithm)algorithm
  23.157 +{
  23.158 +    return [MYSymmetricKey _generateSymmetricKeyOfSize: keySizeInBits
  23.159 +                                             algorithm: algorithm inKeychain: self];
  23.160 +}
  23.161 +
  23.162 +- (MYKeyPair*) generateRSAKeyPairOfSize: (unsigned)keySize {
  23.163 +    return [MYKeyPair _generateRSAKeyPairOfSize: keySize inKeychain: self];
  23.164 +}
  23.165 +
  23.166 +
  23.167 +
  23.168 +@end
  23.169 +
  23.170 +
  23.171 +
  23.172 +#pragma mark -
  23.173 +@implementation MYKeyEnumerator
  23.174 +
  23.175 +- (id) initWithQuery: (NSMutableDictionary*)query {
  23.176 +    self = [super init];
  23.177 +    if (self) {
  23.178 +        if (![query objectForKey: (id)kSecMatchLimit])
  23.179 +            [query setObject: (id)kSecMatchLimitAll forKey: (id)kSecMatchLimit];
  23.180 +        OSStatus err = SecItemCopyMatching((CFDictionaryRef)query, (CFTypeRef*)&_results);
  23.181 +        if (err && err != errSecItemNotFound) {
  23.182 +            check(err,@"SecItemCopyMatching");
  23.183 +            [self release];
  23.184 +            return nil;
  23.185 +        }
  23.186 +        if (_results) CFRetain(_results);
  23.187 +        _itemClass = (CFTypeRef)[query objectForKey: (id)kSecClass];
  23.188 +        if (_itemClass == kSecClassKey)
  23.189 +            _itemClass = (CFTypeRef)[query objectForKey: (id)kSecAttrKeyClass];
  23.190 +        if (_itemClass) CFRetain(_itemClass);
  23.191 +    }
  23.192 +    return self;
  23.193 +}
  23.194 +
  23.195 ++ (id) firstItemWithQuery: (NSMutableDictionary*)query {
  23.196 +    MYKeyEnumerator *e = [[self alloc] initWithQuery: query];
  23.197 +    MYKeychainItem *item = e.nextObject;
  23.198 +    [e release];
  23.199 +    return item;
  23.200 +}    
  23.201 +
  23.202 +- (void) dealloc
  23.203 +{
  23.204 +    if (_itemClass) CFRelease(_itemClass);
  23.205 +    if (_results) CFRelease(_results);
  23.206 +    [super dealloc];
  23.207 +}
  23.208 +
  23.209 +
  23.210 +- (id) nextObject {
  23.211 +    if (!_results)
  23.212 +        return nil;
  23.213 +    MYKeychainItem *next = nil;
  23.214 +    for (; next==nil && _index < CFArrayGetCount(_results); _index++) {
  23.215 +        CFTypeRef found = CFArrayGetValueAtIndex(_results, _index); 
  23.216 +        if (_itemClass == kSecAttrKeyClassPrivate) {
  23.217 +            MYSHA1Digest *digest = [MYPublicKey _digestOfKey: (SecKeyRef)found];
  23.218 +            if (digest) {
  23.219 +                MYPublicKey *publicKey = [[MYKeychain defaultKeychain] publicKeyWithDigest: digest];
  23.220 +                if (publicKey)
  23.221 +                    next = [[[MYKeyPair alloc] initWithPublicKeyRef: publicKey.keyRef
  23.222 +                                                     privateKeyRef: (SecKeyRef)found]
  23.223 +                           autorelease];
  23.224 +                else {
  23.225 +                    // The matching public key won't turn up if it's embedded in a certificate;
  23.226 +                    // I'd have to search for certs if I wanted to look that up. Skip it for now.
  23.227 +                    //Warn(@"Couldn't find matching public key for private key!");
  23.228 +                }
  23.229 +            }
  23.230 +            break;
  23.231 +        } else if (_itemClass == kSecAttrKeyClassPublic) {
  23.232 +            next = [[[MYPublicKey alloc] initWithKeyRef: (SecKeyRef)found] autorelease];
  23.233 +            break;
  23.234 +        } else if (_itemClass == kSecAttrKeyClassSymmetric) {
  23.235 +            next = [[[MYSymmetricKey alloc] initWithKeyRef: (SecKeyRef)found] autorelease];
  23.236 +            break;
  23.237 +        } else if (_itemClass == kSecClassCertificate) {
  23.238 +            next = [[[MYCertificate alloc] initWithCertificateRef: (SecCertificateRef)found] autorelease];
  23.239 +            break;
  23.240 +        }
  23.241 +        CFRelease(found);
  23.242 +    }
  23.243 +    return next;
  23.244 +}
  23.245 +
  23.246 +
  23.247 +@end
  23.248 +
  23.249 +#endif USE_IPHONE_API
  23.250 +
  23.251 +
  23.252 +/*
  23.253 + Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
  23.254 + 
  23.255 + Redistribution and use in source and binary forms, with or without modification, are permitted
  23.256 + provided that the following conditions are met:
  23.257 + 
  23.258 + * Redistributions of source code must retain the above copyright notice, this list of conditions
  23.259 + and the following disclaimer.
  23.260 + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
  23.261 + and the following disclaimer in the documentation and/or other materials provided with the
  23.262 + distribution.
  23.263 + 
  23.264 + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
  23.265 + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
  23.266 + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
  23.267 + BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  23.268 + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
  23.269 +  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
  23.270 + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
  23.271 + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  23.272 + */
    24.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.2 +++ b/MYKeychain.h	Sat Apr 04 20:42:03 2009 -0700
    24.3 @@ -0,0 +1,162 @@
    24.4 +//
    24.5 +//  MYKeychain.h
    24.6 +//  MYCrypto
    24.7 +//
    24.8 +//  Created by Jens Alfke on 3/23/09.
    24.9 +//  Copyright 2009 Jens Alfke. All rights reserved.
   24.10 +//
   24.11 +
   24.12 +#import <Foundation/Foundation.h>
   24.13 +@class MYSymmetricKey, MYPublicKey, MYKeyPair, MYCertificate, MYSHA1Digest;
   24.14 +
   24.15 +
   24.16 +/** A Keychain, a secure database of cryptographic keys.
   24.17 +    This class wraps the Security framework's SecKeychain API. */
   24.18 +@interface MYKeychain : NSObject 
   24.19 +{
   24.20 +#if !TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
   24.21 +    SecKeychainRef _keychain;
   24.22 +#endif
   24.23 +}
   24.24 +
   24.25 +/** Returns a MYKeychain instance representing the user's default keychain.
   24.26 +    This is the instance you'll usually want to add keys to. */
   24.27 ++ (MYKeychain*) defaultKeychain;
   24.28 +
   24.29 +/** Returns a MYKeychain instance representing the aggregate of all open keychains.
   24.30 +    This is the instance you'll usually want to search for keys with. */
   24.31 ++ (MYKeychain*) allKeychains;
   24.32 +
   24.33 +#pragma mark SYMMETRIC KEYS:
   24.34 +
   24.35 +- (MYSymmetricKey*) generateSymmetricKeyOfSize: (unsigned)keySizeInBits
   24.36 +                                     algorithm: (uint32_t/*CCAlgorithm*/)algorithm;
   24.37 +- (NSEnumerator*) enumerateSymmetricKeys;
   24.38 +- (NSEnumerator*) symmetricKeysWithAlias: (NSString*)alias;
   24.39 +
   24.40 +/** Enumerates all symmetric keys in the keychain. */
   24.41 +- (NSEnumerator*) enumerateSymmetricKeys;
   24.42 +
   24.43 +#pragma mark PUBLIC KEYS:
   24.44 +
   24.45 +/** Looks up an existing public key with the given digest.
   24.46 +    Returns nil if there is no such key in the keychain.
   24.47 +    (This method does not look for keys embedded in certificates, only 'bare' keys.) */
   24.48 +- (MYPublicKey*) publicKeyWithDigest: (MYSHA1Digest*)pubKeyDigest;
   24.49 +
   24.50 +/** Enumerates all public keys in the keychain.
   24.51 +    (This method does not find keys embedded in certificates, only 'bare' keys.) */
   24.52 +- (NSEnumerator*) enumeratePublicKeys;
   24.53 +
   24.54 +/** Imports a public key into the keychain, given its external representation
   24.55 +    (as generated by -[MYPublicKey exportDataInFormat:withPEM:].) */
   24.56 +- (MYPublicKey*) importPublicKey: (NSData*)keyData;
   24.57 +
   24.58 +#pragma mark CERTIFICATES:
   24.59 +
   24.60 +/** Looks up an existing certificate with the given public-key digest.
   24.61 +    Returns nil if there is no such certificate in the keychain. */
   24.62 +- (MYCertificate*) certificateWithDigest: (MYSHA1Digest*)pubKeyDigest;
   24.63 +
   24.64 +/** Enumerates all certificates in the keychain. */
   24.65 +- (NSEnumerator*) enumerateCertificates;
   24.66 +
   24.67 +/** Imports a certificate into the keychain, given its external representation. */
   24.68 +- (MYCertificate*) importCertificate: (NSData*)data;
   24.69 +
   24.70 +#pragma mark KEY-PAIRS:
   24.71 +
   24.72 +/** Looks up an existing key-pair whose public key has the given digest.
   24.73 +    Returns nil if there is no such key-pair in the keychain.
   24.74 +    (This method does not look for keys embedded in certificates, only 'bare' keys.) */
   24.75 +- (MYKeyPair*) keyPairWithDigest: (MYSHA1Digest*)pubKeyDigest;
   24.76 +
   24.77 +/** Enumerates all key-pairs in the keychain.
   24.78 +    (This method does not find keys embedded in certificates, only 'bare' keys.) */
   24.79 +- (NSEnumerator*) enumerateKeyPairs;
   24.80 +
   24.81 +/** Generates a new RSA key-pair and adds both keys to the keychain.
   24.82 +    This is very slow -- it may take several seconds, depending on the key size, CPU speed,
   24.83 +    and other random factors. You should probably show some kind of progress indicator before
   24.84 +    calling this method, so the user doesn't think the app has locked up!
   24.85 +    @param keySize  The RSA key length in bits. Must be a power of two. Longer keys are harder
   24.86 +        to break, but operate more slowly and generate larger signatures.
   24.87 +        2048 is a good default choice. You could use 1024 if the data and signatures won't need
   24.88 +        to stay secure for years; or you could use 4096 if you're extremely paranoid. */
   24.89 +- (MYKeyPair*) generateRSAKeyPairOfSize: (unsigned)keySize;
   24.90 +
   24.91 +@end
   24.92 +
   24.93 +
   24.94 +
   24.95 +
   24.96 +#pragma mark -
   24.97 +#pragma mark METHODS NOT SUPPORTED ON IPHONE:
   24.98 +
   24.99 +
  24.100 +#if !TARGET_OS_IPHONE
  24.101 +
  24.102 +@interface MYKeychain (MacOnly)
  24.103 +
  24.104 +/** Creates a MYKeychain for an existing SecKeychainRef. */
  24.105 +- (id) initWithKeychainRef: (SecKeychainRef)keychainRef;
  24.106 +
  24.107 +/** Opens a keychain file. */
  24.108 ++ (MYKeychain*) openKeychainAtPath: (NSString*)path;
  24.109 +
  24.110 +/** Creates a new keychain file. */
  24.111 ++ (MYKeychain*) createKeychainAtPath: (NSString*)path
  24.112 +                        withPassword: (NSString*)password;
  24.113 +
  24.114 +/** Closes and deletes the keychain's file. You should not use this object any more. */
  24.115 +- (BOOL) deleteKeychainFile;
  24.116 +
  24.117 +/** Returns the underlying SecKeychainRef for this keychain.
  24.118 +    This will be NULL for the special allKeychains instance, because it doesn't
  24.119 +    represent a single specific keychain. To handle that case, use the
  24.120 +    keychainRefOrDefault property instead. */
  24.121 +@property (readonly) SecKeychainRef keychainRef;
  24.122 +
  24.123 +/** Returns the underlying SecKeychainRef for this keychain.
  24.124 +    The special allKeychains instance returns a reference to the default keychain,
  24.125 +    as a convenience. */
  24.126 +@property (readonly) SecKeychainRef keychainRefOrDefault;
  24.127 +
  24.128 +/** The path of this keychain's file. */
  24.129 +@property (readonly) NSString* path;
  24.130 +
  24.131 +/** The underlying CSSM storage handle; used when calling CSSM APIs. */
  24.132 +@property (readonly) CSSM_CSP_HANDLE CSPHandle;
  24.133 +
  24.134 +
  24.135 +/** Enumerates all public keys in the keychain that have the given alias string. */
  24.136 +- (NSEnumerator*) symmetricKeysWithAlias: (NSString*)alias;
  24.137 +
  24.138 +/** Enumerates all public keys in the keychain that have the given alias string. */
  24.139 +- (NSEnumerator*) publicKeysWithAlias: (NSString*)alias;
  24.140 +
  24.141 +
  24.142 +/** Imports a certificate into the keychain, given its external representation. */
  24.143 +- (MYCertificate*) importCertificate: (NSData*)data
  24.144 +                                type: (CSSM_CERT_TYPE) type
  24.145 +                            encoding: (CSSM_CERT_ENCODING) encoding;
  24.146 +
  24.147 +/** Imports a key-pair into the keychain, given the external representations
  24.148 +    of both the public and private keys.
  24.149 +    Since the private key data is encrypted, the Security agent will prompt the user to enter
  24.150 +    the passphrase. */
  24.151 +- (MYKeyPair*) importPublicKey: (NSData*)pubKeyData 
  24.152 +                    privateKey: (NSData*)privKeyData;
  24.153 +
  24.154 +/** Imports a key-pair into the keychain, given the external representations
  24.155 +    of both the public and private keys.
  24.156 +    Since the private key data is encrypted, the Security agent will prompt the user to enter
  24.157 +    the passphrase. You can specify the title and prompt message for this alert panel. */
  24.158 +- (MYKeyPair*) importPublicKey: (NSData*)pubKeyData 
  24.159 +                    privateKey: (NSData*)privKeyData
  24.160 +                    alertTitle: (NSString*)title
  24.161 +                   alertPrompt: (NSString*)prompt;
  24.162 +
  24.163 +@end
  24.164 +
  24.165 +#endif
    25.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.2 +++ b/MYKeychain.m	Sat Apr 04 20:42:03 2009 -0700
    25.3 @@ -0,0 +1,443 @@
    25.4 +//
    25.5 +//  MYKeychain.m
    25.6 +//  MYCrypto
    25.7 +//
    25.8 +//  Created by Jens Alfke on 3/23/09.
    25.9 +//  Copyright 2009 Jens Alfke. All rights reserved.
   25.10 +//
   25.11 +
   25.12 +#import "MYKeychain.h"
   25.13 +#import "MYCrypto_Private.h"
   25.14 +#import "MYDigest.h"
   25.15 +
   25.16 +#if !USE_IPHONE_API
   25.17 +
   25.18 +
   25.19 +@interface MYKeyEnumerator : NSEnumerator
   25.20 +{
   25.21 +    MYKeychain *_keychain;
   25.22 +    SecKeychainSearchRef _search;
   25.23 +    SecItemClass _itemClass;
   25.24 +}
   25.25 +
   25.26 +- (id) initWithKeychain: (MYKeychain*)keychain
   25.27 +              itemClass: (SecItemClass)itemClass
   25.28 +             attributes: (SecKeychainAttribute[])attributes 
   25.29 +                  count: (unsigned)count;
   25.30 +@end
   25.31 +
   25.32 +
   25.33 +
   25.34 +@implementation MYKeychain
   25.35 +
   25.36 +
   25.37 +- (id) initWithKeychainRef: (SecKeychainRef)keychainRef
   25.38 +{
   25.39 +    self = [super init];
   25.40 +    if (self != nil) {
   25.41 +        if (keychainRef) {
   25.42 +            CFRetain(keychainRef);
   25.43 +            _keychain = keychainRef;
   25.44 +        }
   25.45 +    }
   25.46 +    return self;
   25.47 +}
   25.48 +
   25.49 ++ (MYKeychain*) _readableKeychainWithRef: (SecKeychainRef)keychainRef fromPath: (NSString*)path {
   25.50 +    if (!keychainRef)
   25.51 +        return nil;
   25.52 +    SecKeychainStatus status;
   25.53 +    BOOL ok = check(SecKeychainGetStatus(keychainRef, &status), @"SecKeychainGetStatus");
   25.54 +    if (ok && !(status & kSecReadPermStatus)) {
   25.55 +        Warn(@"Can't open keychain at %@ : not readable (status=%i)", path,status);
   25.56 +        ok = NO;
   25.57 +    }
   25.58 +    MYKeychain *keychain = nil;
   25.59 +    if (ok)
   25.60 +        keychain = [[[self alloc] initWithKeychainRef: keychainRef] autorelease];
   25.61 +    CFRelease(keychainRef);
   25.62 +    return keychain;
   25.63 +}
   25.64 +
   25.65 ++ (MYKeychain*) openKeychainAtPath: (NSString*)path
   25.66 +{
   25.67 +    Assert(path);
   25.68 +    SecKeychainRef keychainRef = NULL;
   25.69 +    if (!check(SecKeychainOpen(path.fileSystemRepresentation, &keychainRef), @"SecKeychainOpen"))
   25.70 +        return nil;
   25.71 +    return [self _readableKeychainWithRef: keychainRef fromPath: path];
   25.72 +}
   25.73 +
   25.74 ++ (MYKeychain*) createKeychainAtPath: (NSString*)path
   25.75 +                        withPassword: (NSString*)password
   25.76 +{
   25.77 +    Assert(path);
   25.78 +    const char *passwordStr = [password UTF8String];
   25.79 +    SecKeychainRef keychainRef = NULL;
   25.80 +    if (!check(SecKeychainCreate(path.fileSystemRepresentation,
   25.81 +                                 passwordStr ?strlen(passwordStr) :0,
   25.82 +                                 passwordStr, 
   25.83 +                                 (password==nil), 
   25.84 +                                 NULL, 
   25.85 +                                 &keychainRef),
   25.86 +               @"SecKeychainCreate"))
   25.87 +        return nil;
   25.88 +    return [self _readableKeychainWithRef: keychainRef fromPath: path];
   25.89 +}
   25.90 +
   25.91 +- (BOOL) deleteKeychainFile {
   25.92 +    Assert(_keychain);
   25.93 +    return check(SecKeychainDelete(_keychain), @"SecKeychainDelete");
   25.94 +}
   25.95 +
   25.96 +
   25.97 +- (void) dealloc
   25.98 +{
   25.99 +    if (_keychain) CFRelease(_keychain);
  25.100 +    [super dealloc];
  25.101 +}
  25.102 +
  25.103 +
  25.104 ++ (MYKeychain*) allKeychains
  25.105 +{
  25.106 +    static MYKeychain *sAllKeychains;
  25.107 +    @synchronized(self) {
  25.108 +        if (!sAllKeychains)
  25.109 +            sAllKeychains = [[self alloc] initWithKeychainRef: nil];
  25.110 +    }
  25.111 +    return sAllKeychains;
  25.112 +}
  25.113 +
  25.114 +
  25.115 ++ (MYKeychain*) defaultKeychain
  25.116 +{
  25.117 +    static MYKeychain *sDefaultKeychain;
  25.118 +    @synchronized(self) {
  25.119 +        if (!sDefaultKeychain) {
  25.120 +            SecKeychainRef kc = NULL;
  25.121 +            OSStatus err = SecKeychainCopyDomainDefault(kSecPreferencesDomainUser,&kc);
  25.122 +#if TARGET_OS_IPHONE
  25.123 +            // In the simulator, an app is run in a sandbox that has no keychain by default.
  25.124 +            // As a convenience, create one if necessary:
  25.125 +            if (err == errSecNoDefaultKeychain) {
  25.126 +                Log(@"No default keychain in simulator; creating one...");
  25.127 +                NSString *path = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,
  25.128 +                                                                      NSUserDomainMask, YES) objectAtIndex: 0];
  25.129 +                path = [path stringByAppendingPathComponent: @"MYCrypto.keychain"];
  25.130 +                sDefaultKeychain = [[self createKeychainAtPath: path withPassword: nil] retain];
  25.131 +                Assert(sDefaultKeychain, @"Couldn't create default keychain");
  25.132 +                SecKeychainSetDomainDefault(kSecPreferencesDomainUser, sDefaultKeychain.keychainRef);
  25.133 +                Log(@"...created %@", sDefaultKeychain);
  25.134 +                return sDefaultKeychain;
  25.135 +            }
  25.136 +#endif
  25.137 +            if (!check(err, @"SecKeychainCopyDefault"))
  25.138 +                kc = NULL;
  25.139 +
  25.140 +            Assert(kc, @"No default keychain");
  25.141 +            sDefaultKeychain = [[self alloc] initWithKeychainRef: kc];
  25.142 +            CFRelease(kc);
  25.143 +        }
  25.144 +    }
  25.145 +    return sDefaultKeychain;
  25.146 +}
  25.147 +
  25.148 +
  25.149 +- (id) copyWithZone: (NSZone*)zone {
  25.150 +    // It's not necessary to make copies of Keychain objects. This makes it more efficient
  25.151 +    // to use instances as NSDictionary keys or store them in NSSets.
  25.152 +    return [self retain];
  25.153 +}
  25.154 +
  25.155 +- (BOOL) isEqual: (id)obj {
  25.156 +    return (obj == self) || 
  25.157 +            ([obj isKindOfClass: [MYKeychain class]] && CFEqual(_keychain, [obj keychainRef]));
  25.158 +}
  25.159 +
  25.160 +
  25.161 +- (SecKeychainRef) keychainRef {
  25.162 +    return _keychain;
  25.163 +}
  25.164 +
  25.165 +
  25.166 +- (SecKeychainRef) keychainRefOrDefault {
  25.167 +    if (_keychain)
  25.168 +        return _keychain;
  25.169 +    else
  25.170 +        return [[[self class] defaultKeychain] keychainRef];
  25.171 +}
  25.172 +    
  25.173 +    
  25.174 +- (NSString*) path {
  25.175 +    if (!_keychain)
  25.176 +        return nil;
  25.177 +    char pathBuf[PATH_MAX];
  25.178 +    UInt32 pathLen = sizeof(pathBuf);
  25.179 +    if (!check(SecKeychainGetPath(_keychain, &pathLen, pathBuf), @"SecKeychainGetPath"))
  25.180 +        return nil;
  25.181 +    return [[NSFileManager defaultManager] stringWithFileSystemRepresentation: pathBuf length: pathLen];
  25.182 +}
  25.183 +
  25.184 +- (NSString*) description {
  25.185 +    if (_keychain)
  25.186 +        return $sprintf(@"%@[%p, %@]", [self class], _keychain, self.path);
  25.187 +    else
  25.188 +        return $sprintf(@"%@[all]", [self class]);
  25.189 +}
  25.190 +
  25.191 +
  25.192 +#pragma mark -
  25.193 +#pragma mark SEARCHING:
  25.194 +
  25.195 +
  25.196 +- (MYKeychainItem*) itemOfClass: (SecItemClass)itemClass 
  25.197 +                     withDigest: (MYSHA1Digest*)pubKeyDigest 
  25.198 +{
  25.199 +    SecKeychainAttribute attr = {.tag= (itemClass==kSecCertificateItemClass ?kSecPublicKeyHashItemAttr :kSecKeyLabel), 
  25.200 +                                 .length= pubKeyDigest.length, 
  25.201 +                                 .data= (void*) pubKeyDigest.bytes};
  25.202 +    MYKeyEnumerator *e = [[MYKeyEnumerator alloc] initWithKeychain: self
  25.203 +                                                         itemClass: itemClass
  25.204 +                                                        attributes: &attr count: 1];
  25.205 +    MYKeychainItem *item = e.nextObject;
  25.206 +    [e release];
  25.207 +    return item;
  25.208 +}
  25.209 +
  25.210 +- (MYPublicKey*) publicKeyWithDigest: (MYSHA1Digest*)pubKeyDigest {
  25.211 +    return (MYPublicKey*) [self itemOfClass: kSecPublicKeyItemClass withDigest: pubKeyDigest];
  25.212 +}   
  25.213 +
  25.214 +- (NSEnumerator*) enumeratePublicKeys {
  25.215 +    return [[[MYKeyEnumerator alloc] initWithKeychain: self
  25.216 +                                            itemClass: kSecPublicKeyItemClass
  25.217 +                                           attributes: NULL count: 0] autorelease];
  25.218 +}
  25.219 +
  25.220 +- (NSEnumerator*) publicKeysWithAlias: (NSString*)alias {
  25.221 +    NSData *utf8 = [alias dataUsingEncoding: NSUTF8StringEncoding];
  25.222 +    SecKeychainAttribute attr = {.tag=kSecKeyAlias, .length=utf8.length, .data=(void*)utf8.bytes};
  25.223 +    return [[[MYKeyEnumerator alloc] initWithKeychain: self
  25.224 +                                            itemClass: kSecPublicKeyItemClass
  25.225 +                                           attributes: &attr count: 1] autorelease];
  25.226 +}
  25.227 +
  25.228 +
  25.229 +- (MYKeyPair*) keyPairWithDigest: (MYSHA1Digest*)pubKeyDigest {
  25.230 +    return (MYKeyPair*) [self itemOfClass: kSecPrivateKeyItemClass withDigest: pubKeyDigest];
  25.231 +}
  25.232 +
  25.233 +- (NSEnumerator*) enumerateKeyPairs {
  25.234 +    return [[[MYKeyEnumerator alloc] initWithKeychain: self
  25.235 +                                            itemClass: kSecPrivateKeyItemClass
  25.236 +                                           attributes: NULL count: 0] autorelease];
  25.237 +}
  25.238 +
  25.239 +- (MYCertificate*) certificateWithDigest: (MYSHA1Digest*)pubKeyDigest {
  25.240 +    return (MYCertificate*) [self itemOfClass: kSecCertificateItemClass withDigest: pubKeyDigest];
  25.241 +}
  25.242 +
  25.243 +- (NSEnumerator*) enumerateCertificates {
  25.244 +    return [[[MYKeyEnumerator alloc] initWithKeychain: self
  25.245 +                                            itemClass: kSecCertificateItemClass
  25.246 +                                           attributes: NULL count: 0] autorelease];
  25.247 +}
  25.248 +
  25.249 +- (NSEnumerator*) enumerateSymmetricKeys {
  25.250 +    return [[[MYKeyEnumerator alloc] initWithKeychain: self
  25.251 +                                            itemClass: kSecSymmetricKeyItemClass
  25.252 +                                           attributes: NULL count: 0] autorelease];
  25.253 +}
  25.254 +
  25.255 +- (NSEnumerator*) symmetricKeysWithAlias: (NSString*)alias {
  25.256 +    NSData *utf8 = [alias dataUsingEncoding: NSUTF8StringEncoding];
  25.257 +    SecKeychainAttribute attr = {.tag=kSecKeyAlias, .length=utf8.length, .data=(void*)utf8.bytes};
  25.258 +    return [[[MYKeyEnumerator alloc] initWithKeychain: self
  25.259 +                                            itemClass: kSecSymmetricKeyItemClass
  25.260 +                                           attributes: &attr count: 1] autorelease];
  25.261 +}
  25.262 +
  25.263 +
  25.264 +
  25.265 +#pragma mark -
  25.266 +#pragma mark IMPORT:
  25.267 +
  25.268 +
  25.269 +- (MYPublicKey*) importPublicKey: (NSData*)keyData {
  25.270 +    return [[[MYPublicKey alloc] _initWithKeyData: keyData 
  25.271 +                                      forKeychain: self.keychainRefOrDefault]
  25.272 +            autorelease];
  25.273 +}
  25.274 +
  25.275 +- (MYKeyPair*) importPublicKey: (NSData*)pubKeyData 
  25.276 +                    privateKey: (NSData*)privKeyData 
  25.277 +                    alertTitle: (NSString*)title
  25.278 +                   alertPrompt: (NSString*)prompt {
  25.279 +    return [[[MYKeyPair alloc] _initWithPublicKeyData: pubKeyData
  25.280 +                                       privateKeyData: privKeyData
  25.281 +                                          forKeychain: self.keychainRefOrDefault
  25.282 +                                           alertTitle: (NSString*)title
  25.283 +                                          alertPrompt: (NSString*)prompt]
  25.284 +            autorelease];
  25.285 +}
  25.286 +
  25.287 +- (MYKeyPair*) importPublicKey: (NSData*)pubKeyData 
  25.288 +                    privateKey: (NSData*)privKeyData 
  25.289 +{
  25.290 +    return [self importPublicKey: pubKeyData privateKey: privKeyData
  25.291 +                      alertTitle: @"Import Private Key"
  25.292 +                     alertPrompt: @"To import your saved private key, please re-enter the "
  25.293 +                                   "passphrase you used when you exported it."];
  25.294 +}
  25.295 +
  25.296 +- (MYCertificate*) importCertificate: (NSData*)data
  25.297 +                                type: (CSSM_CERT_TYPE) type
  25.298 +                            encoding: (CSSM_CERT_ENCODING) encoding;
  25.299 +{
  25.300 +    MYCertificate *cert = [[[MYCertificate alloc] initWithCertificateData: data 
  25.301 +                                                                    type: type
  25.302 +                                                                encoding: encoding]
  25.303 +                           autorelease];
  25.304 +    if (cert) {
  25.305 +        if (!check(SecCertificateAddToKeychain(cert.certificateRef, self.keychainRefOrDefault),
  25.306 +                   @"SecCertificateAddToKeychain"))
  25.307 +            cert = nil;
  25.308 +    }
  25.309 +    return cert;
  25.310 +}
  25.311 +
  25.312 +- (MYCertificate*) importCertificate: (NSData*)data {
  25.313 +    return [self importCertificate: data 
  25.314 +                              type: CSSM_CERT_X_509v3 
  25.315 +                          encoding: CSSM_CERT_ENCODING_BER];
  25.316 +}
  25.317 +
  25.318 +
  25.319 +- (MYSymmetricKey*) generateSymmetricKeyOfSize: (unsigned)keySizeInBits
  25.320 +                                     algorithm: (CCAlgorithm)algorithm
  25.321 +{
  25.322 +    return [MYSymmetricKey _generateSymmetricKeyOfSize: keySizeInBits
  25.323 +                                             algorithm: algorithm inKeychain: self];
  25.324 +}
  25.325 +
  25.326 +- (MYKeyPair*) generateRSAKeyPairOfSize: (unsigned)keySize {
  25.327 +    return [MYKeyPair _generateRSAKeyPairOfSize: keySize inKeychain: self.keychainRefOrDefault];
  25.328 +}
  25.329 +
  25.330 +
  25.331 +- (CSSM_CSP_HANDLE) CSPHandle {
  25.332 +    CSSM_CSP_HANDLE cspHandle = 0;
  25.333 +    Assert(check(SecKeychainGetCSPHandle(self.keychainRefOrDefault, &cspHandle), @"SecKeychainGetCSPHandle"));
  25.334 +    return cspHandle;
  25.335 +}
  25.336 +
  25.337 +
  25.338 +@end
  25.339 +
  25.340 +
  25.341 +
  25.342 +#pragma mark -
  25.343 +@implementation MYKeyEnumerator
  25.344 +
  25.345 +- (id) initWithKeychain: (MYKeychain*)keychain
  25.346 +              itemClass: (SecItemClass)itemClass
  25.347 +             attributes: (SecKeychainAttribute[])attributes 
  25.348 +                  count: (unsigned)count {
  25.349 +    self = [super init];
  25.350 +    if (self) {
  25.351 +        _keychain = [keychain retain];
  25.352 +        _itemClass = itemClass;
  25.353 +        SecKeychainAttributeList list = {.count=count, .attr=attributes};
  25.354 +        if (!check(SecKeychainSearchCreateFromAttributes(keychain.keychainRef,
  25.355 +                                                         itemClass,
  25.356 +                                                         &list,
  25.357 +                                                         &_search),
  25.358 +                   @"SecKeychainSearchCreateFromAttributes")) {
  25.359 +            [self release];
  25.360 +            return nil;
  25.361 +        }
  25.362 +    }
  25.363 +    return self;
  25.364 +}
  25.365 +
  25.366 +- (void) dealloc
  25.367 +{
  25.368 +    [_keychain release];
  25.369 +    if (_search) CFRelease(_search);
  25.370 +    [super dealloc];
  25.371 +}
  25.372 +
  25.373 +
  25.374 +- (id) nextObject {
  25.375 +    if (!_search)
  25.376 +        return nil;
  25.377 +    MYPublicKey *key = nil;
  25.378 +    do{
  25.379 +        SecKeychainItemRef found = NULL;
  25.380 +        OSStatus err = SecKeychainSearchCopyNext(_search, &found);
  25.381 +        if (err || !found) {
  25.382 +            if (err != errSecItemNotFound)
  25.383 +                check(err,@"SecKeychainSearchCopyNext");
  25.384 +            CFRelease(_search);
  25.385 +            _search = NULL;
  25.386 +            return nil;
  25.387 +        }
  25.388 +        
  25.389 +        switch (_itemClass) {
  25.390 +            case kSecPrivateKeyItemClass: {
  25.391 +                MYSHA1Digest *digest = [MYPublicKey _digestOfKey: (SecKeyRef)found];
  25.392 +                if (digest) {
  25.393 +                    MYPublicKey *publicKey = [_keychain publicKeyWithDigest: digest];
  25.394 +                    if (publicKey)
  25.395 +                        key = [[[MYKeyPair alloc] initWithPublicKeyRef: publicKey.keyRef
  25.396 +                                                         privateKeyRef: (SecKeyRef)found]
  25.397 +                               autorelease];
  25.398 +                    else {
  25.399 +                        // The matching public key won't turn up if it's embedded in a certificate;
  25.400 +                        // I'd have to search for certs if I wanted to look that up. Skip it for now.
  25.401 +                        //Warn(@"Couldn't find matching public key for private key! digest=%@",digest);
  25.402 +                    }
  25.403 +                }
  25.404 +                break;
  25.405 +            }
  25.406 +            case kSecCertificateItemClass:
  25.407 +                key = [[[MYCertificate alloc] initWithCertificateRef: (SecCertificateRef)found] autorelease];
  25.408 +                break;
  25.409 +            case kSecPublicKeyItemClass:
  25.410 +                key = [[[MYPublicKey alloc] initWithKeyRef: (SecKeyRef)found] autorelease];
  25.411 +                break;
  25.412 +        }
  25.413 +        CFRelease(found);
  25.414 +    } while (key==nil);
  25.415 +    return key;
  25.416 +}
  25.417 +
  25.418 +
  25.419 +@end
  25.420 +
  25.421 +
  25.422 +#endif !USE_IPHONE_API
  25.423 +
  25.424 +
  25.425 +
  25.426 +/*
  25.427 + Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
  25.428 + 
  25.429 + Redistribution and use in source and binary forms, with or without modification, are permitted
  25.430 + provided that the following conditions are met:
  25.431 + 
  25.432 + * Redistributions of source code must retain the above copyright notice, this list of conditions
  25.433 + and the following disclaimer.
  25.434 + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
  25.435 + and the following disclaimer in the documentation and/or other materials provided with the
  25.436 + distribution.
  25.437 + 
  25.438 + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
  25.439 + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
  25.440 + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
  25.441 + BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  25.442 + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
  25.443 +  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
  25.444 + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
  25.445 + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25.446 + */
    26.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.2 +++ b/MYKeychainItem.h	Sat Apr 04 20:42:03 2009 -0700
    26.3 @@ -0,0 +1,36 @@
    26.4 +//
    26.5 +//  MYKeychainItem.h
    26.6 +//  MYCrypto
    26.7 +//
    26.8 +//  Created by Jens Alfke on 3/26/09.
    26.9 +//  Copyright 2009 Jens Alfke. All rights reserved.
   26.10 +//
   26.11 +
   26.12 +#import <Foundation/Foundation.h>
   26.13 +#import <Security/Security.h>
   26.14 +@class MYKeychain;
   26.15 +
   26.16 +#if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
   26.17 +typedef CFTypeRef MYKeychainItemRef;
   26.18 +#else
   26.19 +typedef SecKeychainItemRef MYKeychainItemRef;
   26.20 +#endif
   26.21 +
   26.22 +
   26.23 +/** Abstract base class for keychain items: MYPublicKey, MYKeyPair and MYCertificate. */
   26.24 +@interface MYKeychainItem : NSObject
   26.25 +{
   26.26 +    @private
   26.27 +    MYKeychainItemRef _itemRef;
   26.28 +}
   26.29 +
   26.30 +- (id) initWithKeychainItemRef: (MYKeychainItemRef)itemRef;
   26.31 +
   26.32 +@property (readonly) MYKeychainItemRef keychainItemRef;
   26.33 +
   26.34 +@property (readonly) MYKeychain *keychain;
   26.35 +
   26.36 +/** Removes the item from its keychain, if any. */
   26.37 +- (BOOL) removeFromKeychain;
   26.38 +
   26.39 +@end
    27.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    27.2 +++ b/MYKeychainItem.m	Sat Apr 04 20:42:03 2009 -0700
    27.3 @@ -0,0 +1,216 @@
    27.4 +//
    27.5 +//  MYKeychainItem.m
    27.6 +//  MYCrypto
    27.7 +//
    27.8 +//  Created by Jens Alfke on 3/26/09.
    27.9 +//  Copyright 2009 Jens Alfke. All rights reserved.
   27.10 +//
   27.11 +
   27.12 +#import "MYKeychainItem.h"
   27.13 +#import "MYCrypto_Private.h"
   27.14 +#import "MYErrorUtils.h"
   27.15 +
   27.16 +
   27.17 +NSString* const MYCSSMErrorDomain = @"CSSMErrorDomain";
   27.18 +
   27.19 +
   27.20 +@implementation MYKeychainItem
   27.21 +
   27.22 +
   27.23 +- (id) initWithKeychainItemRef: (MYKeychainItemRef)itemRef;
   27.24 +{
   27.25 +    Assert(itemRef!=NULL);
   27.26 +    self = [super init];
   27.27 +    if (self != nil) {
   27.28 +        _itemRef = itemRef;
   27.29 +        CFRetain(_itemRef);
   27.30 +    }
   27.31 +    return self;
   27.32 +}
   27.33 +
   27.34 +
   27.35 +@synthesize keychainItemRef=_itemRef;
   27.36 +
   27.37 +- (void) dealloc
   27.38 +{
   27.39 +    if (_itemRef) CFRelease(_itemRef);
   27.40 +    [super dealloc];
   27.41 +}
   27.42 +
   27.43 +- (id) copyWithZone: (NSZone*)zone {
   27.44 +    // As keys are immutable, it's not necessary to make copies of them. This makes it more efficient
   27.45 +    // to use instances as NSDictionary keys or store them in NSSets.
   27.46 +    return [self retain];
   27.47 +}
   27.48 +
   27.49 +- (BOOL) isEqual: (id)obj {
   27.50 +    // Require the objects to be of the same class, so that a MYPublicKey will not be equal to a
   27.51 +    // MYKeyPair with the same public key.
   27.52 +    return (obj == self) || 
   27.53 +           ([obj class] == [self class] && CFEqual(_itemRef, [obj keychainItemRef]));
   27.54 +}
   27.55 +
   27.56 +- (NSUInteger) hash {
   27.57 +    return CFHash(_itemRef);
   27.58 +}
   27.59 +
   27.60 +- (NSArray*) _itemList {
   27.61 +    return $array((id)_itemRef);
   27.62 +}
   27.63 +
   27.64 +#if USE_IPHONE_API
   27.65 +- (CFDictionaryRef) asQuery {
   27.66 +    return (CFDictionaryRef) $dict( {(id)kSecClass, (id)kSecClassKey},//FIX
   27.67 +                                    {(id)kSecMatchItemList, self._itemList} );
   27.68 +}
   27.69 +#endif
   27.70 +
   27.71 +
   27.72 +- (MYKeychain*) keychain {
   27.73 +#if USE_IPHONE_API
   27.74 +    return [MYKeychain defaultKeychain];
   27.75 +#else
   27.76 +    MYKeychain *keychain = nil;
   27.77 +    SecKeychainRef keychainRef = NULL;
   27.78 +    if (check(SecKeychainItemCopyKeychain((SecKeychainItemRef)_itemRef, &keychainRef), @"SecKeychainItemCopyKeychain")) {
   27.79 +        if (keychainRef) {
   27.80 +            keychain = [[[MYKeychain alloc] initWithKeychainRef: keychainRef] autorelease];
   27.81 +            CFRelease(keychainRef);
   27.82 +        }
   27.83 +    }
   27.84 +    return keychain;
   27.85 +#endif
   27.86 +}
   27.87 +
   27.88 +- (BOOL) removeFromKeychain {
   27.89 +#if USE_IPHONE_API
   27.90 +    return check(SecItemDelete(self.asQuery), @"SecItemDelete");
   27.91 +#else
   27.92 +    return check(SecKeychainItemDelete((SecKeychainItemRef)_itemRef), @"SecKeychainItemDelete");
   27.93 +#endif
   27.94 +}
   27.95 +
   27.96 +
   27.97 +#pragma mark -
   27.98 +#pragma mark DATA / METADATA ACCESSORS:
   27.99 +
  27.100 +
  27.101 +- (NSData*) _getContents: (OSStatus*)outError {
  27.102 +    NSData *contents = nil;
  27.103 +#if USE_IPHONE_API
  27.104 +#else
  27.105 +	UInt32 length = 0;
  27.106 +    void *bytes = NULL;
  27.107 +    *outError = SecKeychainItemCopyAttributesAndData(_itemRef, NULL, NULL, NULL, &length, &bytes);
  27.108 +    if (!*outError && bytes) {
  27.109 +        contents = [NSData dataWithBytes: bytes length: length];
  27.110 +        SecKeychainItemFreeAttributesAndData(NULL, bytes);
  27.111 +    }
  27.112 +#endif
  27.113 +    return contents;
  27.114 +}
  27.115 +
  27.116 ++ (NSData*) _getAttribute: (SecKeychainAttrType)attr ofItem: (MYKeychainItemRef)item {
  27.117 +    NSData *value = nil;
  27.118 +#if USE_IPHONE_API
  27.119 +    NSDictionary *info = $dict( {(id)kSecClass, (id)kSecClassKey},
  27.120 +                                {(id)kSecMatchItemList, $array((id)item)},
  27.121 +                                {(id)kSecReturnAttributes, $true} );
  27.122 +    CFDictionaryRef attrs;
  27.123 +    if (!check(SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef*)&attrs), @"SecItemCopyMatching"))
  27.124 +        return nil;
  27.125 +    CFTypeRef rawValue = CFDictionaryGetValue(attrs,attr);
  27.126 +    value = rawValue ?[[(id)CFMakeCollectable(rawValue) retain] autorelease] :nil;
  27.127 +    CFRelease(attrs);
  27.128 +    
  27.129 +#else
  27.130 +	UInt32 format = kSecFormatUnknown;
  27.131 +	SecKeychainAttributeInfo info = {.count=1, .tag=(UInt32*)&attr, .format=&format};
  27.132 +    SecKeychainAttributeList *list = NULL;
  27.133 +	
  27.134 +    if (check(SecKeychainItemCopyAttributesAndData((SecKeychainItemRef)item, &info,
  27.135 +                                                   NULL, &list, NULL, NULL),
  27.136 +              @"SecKeychainItemCopyAttributesAndData")) {
  27.137 +        if (list) {
  27.138 +            if (list->count == 1)
  27.139 +                value = [NSData dataWithBytes: list->attr->data
  27.140 +                                       length: list->attr->length];
  27.141 +            else if (list->count > 1)
  27.142 +                Warn(@"Multiple values for keychain item attribute");
  27.143 +            SecKeychainItemFreeAttributesAndData(list, NULL);
  27.144 +        }
  27.145 +    }
  27.146 +#endif
  27.147 +    return value;
  27.148 +}
  27.149 +
  27.150 ++ (NSString*) _getStringAttribute: (SecKeychainAttrType)attr ofItem: (MYKeychainItemRef)item {
  27.151 +    NSData *value = [self _getAttribute: attr ofItem: item];
  27.152 +    if (!value) return nil;
  27.153 +    const char *bytes = value.bytes;
  27.154 +    size_t length = value.length;
  27.155 +    if (length>0 && bytes[length-1] == 0)
  27.156 +        length--;           // Some values are null-terminated!?
  27.157 +    NSString *str = [[NSString alloc] initWithBytes: bytes length: length
  27.158 +                                           encoding: NSUTF8StringEncoding];
  27.159 +    if (!str)
  27.160 +        Warn(@"MYKeychainItem: Couldn't decode attr value as string");
  27.161 +    return [str autorelease];
  27.162 +}
  27.163 +
  27.164 +- (NSString*) stringValueOfAttribute: (SecKeychainAttrType)attr {
  27.165 +    return [[self class] _getStringAttribute: attr ofItem: _itemRef];
  27.166 +}
  27.167 +
  27.168 +
  27.169 ++ (BOOL) _setAttribute: (SecKeychainAttrType)attr ofItem: (MYKeychainItemRef)item
  27.170 +           stringValue: (NSString*)stringValue
  27.171 +{
  27.172 +#if USE_IPHONE_API
  27.173 +    id value = stringValue ?(id)stringValue :(id)[NSNull null];
  27.174 +    NSDictionary *query = $dict({(id)kSecClass, (id)kSecClassKey},
  27.175 +                                {(id)kSecAttrKeyType, (id)attr},
  27.176 +                                {(id)kSecMatchItemList, $array((id)item)});
  27.177 +    NSDictionary *attrs = $dict({(id)attr, value});
  27.178 +    return check(SecItemUpdate((CFDictionaryRef)query, (CFDictionaryRef)attrs), @"SecItemUpdate");
  27.179 +    
  27.180 +#else
  27.181 +    NSData *data = [stringValue dataUsingEncoding: NSUTF8StringEncoding];
  27.182 +    SecKeychainAttribute attribute = {.tag=attr, .length=data.length, .data=(void*)data.bytes};
  27.183 +	SecKeychainAttributeList list = {.count=1, .attr=&attribute};
  27.184 +    return check(SecKeychainItemModifyAttributesAndData((SecKeychainItemRef)item, &list, 0, NULL),
  27.185 +                 @"SecKeychainItemModifyAttributesAndData");
  27.186 +#endif
  27.187 +}
  27.188 +
  27.189 +- (BOOL) setValue: (NSString*)valueStr ofAttribute: (SecKeychainAttrType)attr {
  27.190 +    return [[self class] _setAttribute: attr ofItem: _itemRef stringValue: valueStr];
  27.191 +}
  27.192 +
  27.193 +
  27.194 +@end
  27.195 +
  27.196 +
  27.197 +
  27.198 +
  27.199 +BOOL check(OSStatus err, NSString *what) {
  27.200 +    if (err) {
  27.201 +#if !USE_IPHONE_API
  27.202 +        if (err < -2000000000)
  27.203 +            return checkcssm(err,what);
  27.204 +#endif
  27.205 +        Warn(@"MYCrypto error, %@: %@", what, MYErrorName(NSOSStatusErrorDomain,err));
  27.206 +        return NO;
  27.207 +    } else
  27.208 +        return YES;
  27.209 +}
  27.210 +
  27.211 +#if !USE_IPHONE_API
  27.212 +BOOL checkcssm(CSSM_RETURN err, NSString *what) {
  27.213 +    if (err != CSSM_OK) {
  27.214 +        Warn(@"MYCrypto error, %@: %@", what, MYErrorName(MYCSSMErrorDomain,err));
  27.215 +        return NO;
  27.216 +    } else
  27.217 +        return YES;
  27.218 +}
  27.219 +#endif
    28.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    28.2 +++ b/MYPublicKey-iPhone.m	Sat Apr 04 20:42:03 2009 -0700
    28.3 @@ -0,0 +1,96 @@
    28.4 +//
    28.5 +//  MYPublicKey-iPhone.m
    28.6 +//  MYCrypto-iPhone
    28.7 +//
    28.8 +//  Created by Jens Alfke on 3/30/09.
    28.9 +//  Copyright 2009 Jens Alfke. All rights reserved.
   28.10 +//
   28.11 +
   28.12 +#import "MYPublicKey.h"
   28.13 +#import "MYCrypto_Private.h"
   28.14 +
   28.15 +#if USE_IPHONE_API
   28.16 +
   28.17 +#import "MYDigest.h"
   28.18 +#import "MYErrorUtils.h"
   28.19 +
   28.20 +
   28.21 +@implementation MYPublicKey
   28.22 +
   28.23 +
   28.24 +- (void) dealloc
   28.25 +{
   28.26 +    [_digest release];
   28.27 +    [super dealloc];
   28.28 +}
   28.29 +
   28.30 +
   28.31 +- (SecExternalItemType) keyType {
   28.32 +    return kSecAttrKeyClassPublic;
   28.33 +}
   28.34 +
   28.35 +
   28.36 +- (MYPublicKey*) asPublicKey {
   28.37 +    return self;
   28.38 +}
   28.39 +
   28.40 +
   28.41 +
   28.42 +- (MYSHA1Digest*) publicKeyDigest {
   28.43 +    NSData *digestData = [self _attribute: kSecAttrApplicationLabel];
   28.44 +    if (digestData)
   28.45 +        return (MYSHA1Digest*) [MYSHA1Digest digestFromDigestData: digestData];
   28.46 +    else {
   28.47 +        Warn(@"MYKeyPair: public key didn't have digest attribute");
   28.48 +        return nil;
   28.49 +    }
   28.50 +}
   28.51 +
   28.52 +
   28.53 +- (NSData*) encryptData: (NSData*)data {
   28.54 +    return _crypt(self.keyRef,data,kCCEncrypt);
   28.55 +}
   28.56 +
   28.57 +
   28.58 +- (BOOL) verifySignature: (NSData*)signature ofData: (NSData*)data {
   28.59 +    Assert(data);
   28.60 +    Assert(signature);
   28.61 +    uint8_t digest[CC_SHA1_DIGEST_LENGTH];
   28.62 +    CC_SHA1(data.bytes,data.length, digest);
   28.63 +    OSStatus err = SecKeyRawVerify(self.keyRef, kSecPaddingPKCS1SHA1,
   28.64 +                                   digest,sizeof(digest), //data.bytes, data.length,
   28.65 +                                   signature.bytes, signature.length);
   28.66 +    return err==noErr;
   28.67 +}
   28.68 +
   28.69 +
   28.70 +@end
   28.71 +
   28.72 +
   28.73 +
   28.74 +
   28.75 +NSData* _crypt(SecKeyRef key, NSData *data, CCOperation op) {
   28.76 +    CAssert(data);
   28.77 +    size_t dataLength = data.length;
   28.78 +    size_t outputLength = MAX(dataLength, SecKeyGetBlockSize(key));
   28.79 +    void *outputBuf = malloc(outputLength);
   28.80 +    if (!outputBuf) return nil;
   28.81 +    OSStatus err;
   28.82 +    if (op==kCCEncrypt)
   28.83 +        err = SecKeyEncrypt(key, kSecPaddingNone,//PKCS1, 
   28.84 +                            data.bytes, dataLength,
   28.85 +                            outputBuf, &outputLength);
   28.86 +    else
   28.87 +        err = SecKeyDecrypt(key, kSecPaddingNone,//PKCS1, 
   28.88 +                            data.bytes, dataLength,
   28.89 +                            outputBuf, &outputLength);
   28.90 +    if (err) {
   28.91 +        free(outputBuf);
   28.92 +        Warn(@"%scrypting failed (%i)", (op==kCCEncrypt ?"En" :"De"), err);
   28.93 +        // Note: One of the errors I've seen is -9809, which is errSSLCrypto (SecureTransport.h)
   28.94 +        return nil;
   28.95 +    } else
   28.96 +        return [NSData dataWithBytesNoCopy: outputBuf length: outputLength freeWhenDone: YES];
   28.97 +}
   28.98 +
   28.99 +#endif USE_IPHONE_API
    29.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.2 +++ b/MYPublicKey.h	Sat Apr 04 20:42:03 2009 -0700
    29.3 @@ -0,0 +1,51 @@
    29.4 +//
    29.5 +//  MYPublicKey.h
    29.6 +//  MYCrypto
    29.7 +//
    29.8 +//  Created by Jens Alfke on 3/25/09.
    29.9 +//  Copyright 2009 Jens Alfke. All rights reserved.
   29.10 +//
   29.11 +
   29.12 +#import "MYKey.h"
   29.13 +@class MYSHA1Digest;
   29.14 +
   29.15 +#if !TARGET_OS_IPHONE
   29.16 +#import <Security/SecKey.h>
   29.17 +#endif
   29.18 +
   29.19 +
   29.20 +/** Error domain for CSSM (low-level crypto) errors */
   29.21 +extern NSString* const MYCSSMErrorDomain;
   29.22 +
   29.23 +
   29.24 +/** A public key, which can be used for encrypting data and verifying signatures. */
   29.25 +@interface MYPublicKey : MYKey <MYEncryption>
   29.26 +{
   29.27 +    MYSHA1Digest *_digest;
   29.28 +}
   29.29 +
   29.30 +/** The public key's SHA-1 digest. This is a convenient short (20-byte) identifier for the key. */
   29.31 +@property (readonly) MYSHA1Digest *publicKeyDigest;
   29.32 +
   29.33 +/** Returns the receiver as a MYPublicKey.
   29.34 +    If the receiver already is a MYPublicKey, this just returns self.
   29.35 +    If it's a MYKeyPair, it returns a new MYPublicKey containing just the public key. */
   29.36 +@property (readonly) MYPublicKey *asPublicKey;
   29.37 +
   29.38 +/** Encrypts a short piece of data using this key, returning the raw encrypted result.
   29.39 +    RSA can encrypt only <i>short</i> pieces of data, smaller than the key size in bits; this
   29.40 +    method will fail and return nil if the data is too long.
   29.41 +    RSA encryption is also much slower than regular symmetric-key encryption, so the correct
   29.42 +    way to encrypt a large block of data using a public key is to first generate a random
   29.43 +    symmetric key, called the "session key" (using a Cryptor), encrypt that session key with the 
   29.44 +    public key, and then encrypt your data with the session key. Send the encrypted session key
   29.45 +    and the encrypted data. */
   29.46 +- (NSData*) encryptData: (NSData*)data;
   29.47 +
   29.48 +/** Verifies the signature of a block of data. If the result is YES, you can be assured that
   29.49 +    the signature was generated from the data using this key's matching private key.
   29.50 +    If the result is NO, something is wrong: either the data or the signature was modified,
   29.51 +    or the signature was generated by a different private key. */
   29.52 +- (BOOL) verifySignature: (NSData*)signature ofData: (NSData*)data;
   29.53 +    
   29.54 +@end
    30.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.2 +++ b/MYPublicKey.m	Sat Apr 04 20:42:03 2009 -0700
    30.3 @@ -0,0 +1,211 @@
    30.4 +//
    30.5 +//  MYPublicKey.m
    30.6 +//  MYCrypto
    30.7 +//
    30.8 +//  Created by Jens Alfke on 3/21/09.
    30.9 +//  Copyright 2009 Jens Alfke. All rights reserved.
   30.10 +//
   30.11 +
   30.12 +#import "MYPublicKey.h"
   30.13 +#import "MYCrypto_Private.h"
   30.14 +
   30.15 +#if !USE_IPHONE_API
   30.16 +
   30.17 +#import "MYDigest.h"
   30.18 +#import "MYErrorUtils.h"
   30.19 +#import <CommonCrypto/CommonDigest.h>
   30.20 +
   30.21 +
   30.22 +static CSSM_CC_HANDLE cssmCreatePassThroughContext(SecKeyRef key);
   30.23 +
   30.24 +
   30.25 +#pragma mark -
   30.26 +@implementation MYPublicKey
   30.27 +
   30.28 +
   30.29 +- (void) dealloc
   30.30 +{
   30.31 +    [_digest release];
   30.32 +    [super dealloc];
   30.33 +}
   30.34 +
   30.35 +- (SecExternalItemType) keyType {
   30.36 +    return kSecItemTypePublicKey;
   30.37 +}
   30.38 +- (NSUInteger)hash {
   30.39 +    return self.publicKeyDigest.hash;
   30.40 +}
   30.41 +
   30.42 +- (NSString*) description {
   30.43 +    return $sprintf(@"%@[%@]", [self class], self.publicKeyDigest.abbreviatedHexString);
   30.44 +}
   30.45 +
   30.46 +- (MYPublicKey*) asPublicKey {
   30.47 +    return self;
   30.48 +}
   30.49 +
   30.50 +
   30.51 ++ (MYSHA1Digest*) _digestOfKey: (SecKeyRef)key {
   30.52 +    Assert(key);
   30.53 +    MYSHA1Digest *digest = nil;
   30.54 +    CSSM_DATA *keyDigest = NULL;
   30.55 +    CSSM_CC_HANDLE context = cssmCreatePassThroughContext(key);
   30.56 +    if (context) {
   30.57 +        if (checkcssm(CSSM_CSP_PassThrough(context, CSSM_APPLECSP_KEYDIGEST, NULL, (void**)&keyDigest),
   30.58 +                      @"CSSM_CSP_PassThrough")) {
   30.59 +            if (keyDigest && keyDigest->Data) {
   30.60 +                digest = [[[MYSHA1Digest alloc] initWithRawDigest: keyDigest->Data
   30.61 +                                                           length: keyDigest->Length] autorelease];
   30.62 +            }
   30.63 +        } else {
   30.64 +            // Note - CSSM_CSP_PassThrough fails on a couple of private keys I've seen; it seems to
   30.65 +            // be ones that are either expired or don't have a matching public key at all (?)
   30.66 +            Warn(@"Failed to get digest of SecKeyRef %p (name='%@' appTag='%@')", key,
   30.67 +                 [self _getStringAttribute: kSecKeyPrintName ofItem: (SecKeychainItemRef)key],
   30.68 +                 [self _getStringAttribute: kSecKeyApplicationTag ofItem: (SecKeychainItemRef)key]);
   30.69 +            NSData *digestData = [self _getAttribute: kSecKeyLabel ofItem: (SecKeychainItemRef)key];
   30.70 +            if (digestData) {
   30.71 +                digest = (MYSHA1Digest*) [MYSHA1Digest digestFromDigestData: digestData];
   30.72 +                if (!digest)
   30.73 +                    Warn(@"Digest property of key %p was invalid SHA-1: %@", key,digestData);
   30.74 +            }
   30.75 +        }
   30.76 +        CSSM_DeleteContext(context);
   30.77 +    }
   30.78 +    return digest;
   30.79 +}
   30.80 +
   30.81 +- (MYSHA1Digest*) publicKeyDigest {
   30.82 +    if (!_digest)
   30.83 +        _digest = [[[self class] _digestOfKey: self.keyRef] retain];
   30.84 +    return _digest;
   30.85 +}
   30.86 +
   30.87 +- (NSData*) keyData {
   30.88 +    return [self exportKeyInFormat: kSecFormatOpenSSL withPEM: NO];
   30.89 +}
   30.90 +
   30.91 +
   30.92 +- (NSData*) encryptData: (NSData*)data {
   30.93 +    return _crypt(self.keyRef,data,kCCEncrypt);
   30.94 +}
   30.95 +
   30.96 +
   30.97 +- (BOOL) verifySignature: (NSData*)signature ofData: (NSData*)data {
   30.98 +    Assert(data);
   30.99 +    Assert(signature);
  30.100 +    uint8_t digest[CC_SHA1_DIGEST_LENGTH];
  30.101 +    CC_SHA1(data.bytes,data.length, digest);
  30.102 +    CSSM_CC_HANDLE ccHandle = cssmCreateSignatureContext(self.keyRef);
  30.103 +    if (!ccHandle) return NO;
  30.104 +    CSSM_DATA original = {data.length, (void*)data.bytes};
  30.105 +    CSSM_DATA sig = {signature.length, (void*)signature.bytes};
  30.106 +    CSSM_RETURN cssmErr = CSSM_VerifyData(ccHandle, &original, 1, CSSM_ALGID_NONE, &sig);
  30.107 +    CSSM_DeleteContext(ccHandle);
  30.108 +    if (cssmErr == CSSM_OK)
  30.109 +        return YES;
  30.110 +    if (cssmErr != CSSMERR_CSP_VERIFY_FAILED)
  30.111 +        Warn(@"CSSM error verifying signature: %u", MYErrorName(MYCSSMErrorDomain,cssmErr));
  30.112 +    return NO;
  30.113 +}
  30.114 +
  30.115 +
  30.116 +@end
  30.117 +
  30.118 +
  30.119 +
  30.120 +
  30.121 +#pragma mark -
  30.122 +#pragma mark UTILITY FUNCTIONS:
  30.123 +
  30.124 +
  30.125 +NSData* _crypt(SecKeyRef key, NSData *data, CCOperation op) {
  30.126 +    CAssert(data);
  30.127 +    const CSSM_KEY* cssmKey;
  30.128 +    const CSSM_ACCESS_CREDENTIALS *credentials;
  30.129 +    CSSM_CSP_HANDLE cspHandle;
  30.130 +    CSSM_CC_HANDLE ccHandle;
  30.131 +    if (!check(SecKeyGetCSSMKey(key, &cssmKey), @"GetCSSMKey")
  30.132 +            || !check(SecKeyGetCredentials(key, CSSM_ACL_AUTHORIZATION_SIGN, kSecCredentialTypeWithUI,
  30.133 +                                           &credentials), @"GetCredentials")
  30.134 +            || !check(SecKeyGetCSPHandle(key, &cspHandle), @"GetCSPHandle")
  30.135 +        
  30.136 +            || !checkcssm(CSSM_CSP_CreateAsymmetricContext(cspHandle, CSSM_ALGID_RSA,
  30.137 +                                                               credentials, cssmKey,
  30.138 +                                                               CSSM_PADDING_PKCS1, &ccHandle),
  30.139 +                          @"CSSM_CSP_CreateAsymmetricContext"))
  30.140 +        return nil;
  30.141 +    
  30.142 +    CSSM_DATA original = {data.length, (void*)data.bytes};
  30.143 +    CSSM_DATA result = {};
  30.144 +    size_t outputLength;
  30.145 +    BOOL ok;
  30.146 +    if (op==kCCEncrypt)
  30.147 +        ok = checkcssm(CSSM_EncryptData(ccHandle, &original, 1, &result, 1, &outputLength, &result),
  30.148 +                       @"CSSM_EncryptData");
  30.149 +    else
  30.150 +        ok = checkcssm(CSSM_DecryptData(ccHandle, &original, 1, &result, 1, &outputLength, &result),
  30.151 +                       @"CSSM_DecryptData");
  30.152 +    CSSM_DeleteContext(ccHandle);
  30.153 +    return ok ?[NSData dataWithBytesNoCopy: result.Data length: outputLength freeWhenDone: YES] :nil;
  30.154 +}
  30.155 +
  30.156 +
  30.157 +CSSM_CC_HANDLE cssmCreateSignatureContext(SecKeyRef key) 
  30.158 +{
  30.159 +    const CSSM_KEY* cssmKey;
  30.160 +    const CSSM_ACCESS_CREDENTIALS *credentials;
  30.161 +    CSSM_CSP_HANDLE cspHandle;
  30.162 +    CSSM_CC_HANDLE ccHandle;
  30.163 +    if (check(SecKeyGetCSSMKey(key, &cssmKey), @"GetCSSMKey")
  30.164 +            && check(SecKeyGetCredentials(key, CSSM_ACL_AUTHORIZATION_SIGN, kSecCredentialTypeWithUI,
  30.165 +                               &credentials), @"GetCredentials")
  30.166 +            && check(SecKeyGetCSPHandle(key, &cspHandle), @"GetCSPHandle")
  30.167 +            && checkcssm(CSSM_CSP_CreateSignatureContext(cspHandle, CSSM_ALGID_SHA1WithRSA, 
  30.168 +                                                          credentials,
  30.169 +                                                          cssmKey, &ccHandle),
  30.170 +                         @"CSSM_CSP_CreateSignatureContext") )
  30.171 +        return ccHandle;
  30.172 +    else
  30.173 +        return 0;
  30.174 +}
  30.175 +
  30.176 +static CSSM_CC_HANDLE cssmCreatePassThroughContext(SecKeyRef key) 
  30.177 +{
  30.178 +    const CSSM_KEY* cssmKey;
  30.179 +    CSSM_CSP_HANDLE cspHandle;
  30.180 +    CSSM_CC_HANDLE ccHandle;
  30.181 +    if (check(SecKeyGetCSSMKey(key, &cssmKey), @"GetCSSMKey")
  30.182 +            && check(SecKeyGetCSPHandle(key, &cspHandle), @"GetCSPHandle")
  30.183 +            && checkcssm(CSSM_CSP_CreatePassThroughContext(cspHandle, cssmKey, &ccHandle), 
  30.184 +                          @"CSSM_CSP_CreatePassThroughContext") )
  30.185 +        return ccHandle;
  30.186 +    else
  30.187 +        return 0;
  30.188 +}
  30.189 +
  30.190 +#endif !USE_IPHONE_API
  30.191 +
  30.192 +
  30.193 +
  30.194 +/*
  30.195 + Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
  30.196 + 
  30.197 + Redistribution and use in source and binary forms, with or without modification, are permitted
  30.198 + provided that the following conditions are met:
  30.199 + 
  30.200 + * Redistributions of source code must retain the above copyright notice, this list of conditions
  30.201 + and the following disclaimer.
  30.202 + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
  30.203 + and the following disclaimer in the documentation and/or other materials provided with the
  30.204 + distribution.
  30.205 + 
  30.206 + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
  30.207 + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
  30.208 + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
  30.209 + BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  30.210 + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
  30.211 +  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
  30.212 + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
  30.213 + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30.214 + */
    31.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    31.2 +++ b/MYSymmetricKey.h	Sat Apr 04 20:42:03 2009 -0700
    31.3 @@ -0,0 +1,20 @@
    31.4 +//
    31.5 +//  MYSymmetricKey.h
    31.6 +//  MYCrypto
    31.7 +//
    31.8 +//  Created by Jens Alfke on 4/2/09.
    31.9 +//  Copyright 2009 Jens Alfke. All rights reserved.
   31.10 +//
   31.11 +
   31.12 +#import "MYKey.h"
   31.13 +#import <CommonCrypto/CommonCryptor.h>
   31.14 +
   31.15 +
   31.16 +@interface MYSymmetricKey : MYKey <MYEncryption, MYDecryption>
   31.17 +
   31.18 ++ (MYSymmetricKey*) generateSymmetricKeyOfSize: (unsigned)keySizeInBits
   31.19 +                                     algorithm: (CCAlgorithm)algorithm;
   31.20 +
   31.21 +@property (readonly) CCAlgorithm algorithm;
   31.22 +
   31.23 +@end
    32.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    32.2 +++ b/MYSymmetricKey.m	Sat Apr 04 20:42:03 2009 -0700
    32.3 @@ -0,0 +1,180 @@
    32.4 +//
    32.5 +//  MYSymmetricKey.m
    32.6 +//  MYCrypto
    32.7 +//
    32.8 +//  Created by Jens Alfke on 4/2/09.
    32.9 +//  Copyright 2009 Jens Alfke. All rights reserved.
   32.10 +//
   32.11 +
   32.12 +#import "MYSymmetricKey.h"
   32.13 +#import "MYCryptor.h"
   32.14 +#import "MYCrypto_Private.h"
   32.15 +
   32.16 +
   32.17 +#if USE_IPHONE_API
   32.18 +typedef uint32_t CSSM_ALGORITHMS;
   32.19 +enum {
   32.20 +// Taken from cssmtype.h in OS X 10.5 SDK:
   32.21 +	CSSM_ALGID_NONE =					0x00000000L,
   32.22 +	CSSM_ALGID_DES =					CSSM_ALGID_NONE + 14,
   32.23 +	CSSM_ALGID_3DES_3KEY_EDE =			CSSM_ALGID_NONE + 17,
   32.24 +	CSSM_ALGID_3DES_3KEY =           	CSSM_ALGID_3DES_3KEY_EDE,
   32.25 +	CSSM_ALGID_RC4 =					CSSM_ALGID_NONE + 25,
   32.26 +	CSSM_ALGID_CAST =					CSSM_ALGID_NONE + 27,
   32.27 +	CSSM_ALGID_VENDOR_DEFINED =			CSSM_ALGID_NONE + 0x80000000L,
   32.28 +	CSSM_ALGID_AES
   32.29 +};
   32.30 +#else
   32.31 +#import <Security/cssmtype.h>
   32.32 +#endif
   32.33 +
   32.34 +static const CSSM_ALGORITHMS kCSSMAlgorithms[] = {
   32.35 +    CSSM_ALGID_AES, CSSM_ALGID_DES, CSSM_ALGID_3DES_3KEY, CSSM_ALGID_CAST, CSSM_ALGID_RC4
   32.36 +};
   32.37 +
   32.38 +
   32.39 +#pragma mark -
   32.40 +@implementation MYSymmetricKey
   32.41 +
   32.42 +
   32.43 ++ (MYSymmetricKey*) _generateSymmetricKeyOfSize: (unsigned)keySizeInBits
   32.44 +                                      algorithm: (CCAlgorithm)algorithm
   32.45 +                                     inKeychain: (MYKeychain*)keychain
   32.46 +{
   32.47 +    Assert(algorithm <= kCCAlgorithmRC4);
   32.48 +    SecKeyRef keyRef = NULL;
   32.49 +    
   32.50 +#if USE_IPHONE_API
   32.51 +    NSData *keyBits = [MYCryptor randomKeyOfLength: (keySizeInBits+7)/8];
   32.52 +    NSDictionary *keyAttrs = $dict( {(id)kSecClass, (id)kSecClassKey},
   32.53 +                                    {(id)kSecAttrKeyType, $object(kCSSMAlgorithms[algorithm])},
   32.54 +                                    {(id)kSecAttrKeySizeInBits, $object(keySizeInBits)},
   32.55 +                                    {(id)kSecAttrEffectiveKeySize, $object(keySizeInBits)},
   32.56 +                                    {(id)kSecAttrIsPermanent, keychain ?$true :$false},
   32.57 +                                    {(id)kSecValueData, keyBits} );
   32.58 +    if (!check(SecItemAdd((CFDictionaryRef)keyAttrs, (CFTypeRef*)&keyRef), @"SecItemAdd"))
   32.59 +        return nil;
   32.60 +    
   32.61 +#else
   32.62 +    CSSM_KEYATTR_FLAGS flags = CSSM_KEYATTR_EXTRACTABLE;
   32.63 +    if (keychain)
   32.64 +        flags |= CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_SENSITIVE | CSSM_KEYATTR_EXTRACTABLE;
   32.65 +    CSSM_KEYUSE usage = CSSM_KEYUSE_ANY;
   32.66 +    if (!check(SecKeyGenerate(keychain.keychainRefOrDefault,    // nil kc generates a transient key
   32.67 +                              kCSSMAlgorithms[algorithm],
   32.68 +                              keySizeInBits, 
   32.69 +                              0, usage, flags, NULL, &keyRef),
   32.70 +               @"SecKeyGenerate")) {
   32.71 +        return nil;
   32.72 +    }
   32.73 +#endif
   32.74 +    return [[[self alloc] initWithKeyRef: keyRef] autorelease];
   32.75 +}
   32.76 +
   32.77 ++ (MYSymmetricKey*) generateSymmetricKeyOfSize: (unsigned)keySizeInBits
   32.78 +                                     algorithm: (CCAlgorithm)algorithm {
   32.79 +    return [self _generateSymmetricKeyOfSize: keySizeInBits
   32.80 +                                   algorithm: algorithm
   32.81 +                                  inKeychain: nil];
   32.82 +}
   32.83 +
   32.84 +
   32.85 +
   32.86 +- (SecExternalItemType) keyType {
   32.87 +#if USE_IPHONE_API
   32.88 +    return kSecAttrKeyClassSymmetric;
   32.89 +#else
   32.90 +    return kSecItemTypeSessionKey;
   32.91 +#endif
   32.92 +}
   32.93 +
   32.94 +- (CCAlgorithm) algorithm {
   32.95 +    CSSM_ALGORITHMS cssmAlg;
   32.96 +#if USE_IPHONE_API
   32.97 +    id keyType = [self _attribute: kSecAttrKeyType];
   32.98 +    Assert(keyType!=nil, @"Key has no kSecAttrKeyType");
   32.99 +    cssmAlg = [keyType unsignedIntValue];
  32.100 +#else
  32.101 +    cssmAlg = self.cssmKey->KeyHeader.AlgorithmId;
  32.102 +#endif
  32.103 +    switch(cssmAlg) {
  32.104 +        case CSSM_ALGID_AES:
  32.105 +            return kCCAlgorithmAES128;
  32.106 +        case CSSM_ALGID_DES:
  32.107 +            return kCCAlgorithmDES;	
  32.108 +        case CSSM_ALGID_3DES_3KEY:
  32.109 +            return kCCAlgorithm3DES;
  32.110 +        case CSSM_ALGID_CAST:
  32.111 +            return kCCAlgorithmCAST;
  32.112 +        case CSSM_ALGID_RC4:
  32.113 +            return kCCAlgorithmRC4;	
  32.114 +        default:
  32.115 +            Warn(@"CSSM_ALGORITHMS #%u doesn't map to any CCAlgorithm", cssmAlg);
  32.116 +            return (CCAlgorithm)-1;
  32.117 +    }
  32.118 +}
  32.119 +
  32.120 +
  32.121 +- (NSData*) _cryptData: (NSData*)data operation: (CCOperation)op options: (CCOptions)options
  32.122 +{
  32.123 +    NSData *keyData = self.keyData;
  32.124 +    Assert(keyData, @"Couldn't get key data");
  32.125 +    NSMutableData *output = [NSMutableData dataWithLength: data.length + 256];
  32.126 +    size_t bytesWritten = 0;
  32.127 +    CCCryptorStatus status = CCCrypt(op, self.algorithm, options, 
  32.128 +                                     keyData.bytes, keyData.length, NULL,
  32.129 +                                     data.bytes, data.length, output.mutableBytes, output.length,
  32.130 +                                     &bytesWritten);
  32.131 +    if (status) {
  32.132 +        Warn(@"MYSymmetricKey: CCCrypt returned error %i",status);
  32.133 +        return nil;
  32.134 +    }
  32.135 +    output.length = bytesWritten;
  32.136 +    return output;
  32.137 +}
  32.138 +
  32.139 +- (NSData*) encryptData: (NSData*)data {
  32.140 +    return [self _cryptData: data operation: kCCEncrypt options: kCCOptionPKCS7Padding];
  32.141 +}
  32.142 +
  32.143 +
  32.144 +- (NSData*) decryptData: (NSData*)data {
  32.145 +    return [self _cryptData: data operation: kCCDecrypt options: kCCOptionPKCS7Padding];
  32.146 +}
  32.147 +
  32.148 +
  32.149 +@end
  32.150 +
  32.151 +
  32.152 +/* (Turned out I could just use SecKeyExport for this.)
  32.153 + 
  32.154 +static NSData* wrap(SecKeyRef key, CSSM_ALGORITHMS algorithm) {
  32.155 +    CAssert(key);
  32.156 +    const CSSM_KEY* cssmKey;
  32.157 +    const CSSM_ACCESS_CREDENTIALS *credentials;
  32.158 +    CSSM_CSP_HANDLE cspHandle;
  32.159 +    CSSM_CC_HANDLE ccHandle;
  32.160 +    if (!check(SecKeyGetCSSMKey(key, &cssmKey), @"GetCSSMKey")
  32.161 +        || !check(SecKeyGetCredentials(key, 
  32.162 +                                       CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED, 
  32.163 +                                       kSecCredentialTypeDefault,
  32.164 +                                       &credentials), @"GetCredentials")
  32.165 +        || !check(SecKeyGetCSPHandle(key, &cspHandle), @"GetCSPHandle")
  32.166 +        
  32.167 +        || !checkcssm(CSSM_CSP_CreateSymmetricContext(cspHandle, algorithm, CSSM_ALGMODE_WRAP,
  32.168 +                                                      NULL, NULL, NULL,
  32.169 +                                                      CSSM_PADDING_NONE, NULL, &ccHandle),
  32.170 +                      @"CSSM_CSP_CreateSymmetricContext"))
  32.171 +        return nil;
  32.172 +    
  32.173 +    CSSM_WRAP_KEY wrapped;
  32.174 +    NSData *result = nil;
  32.175 +    if(checkcssm(CSSM_WrapKey(ccHandle, credentials, cssmKey, NULL, &wrapped),
  32.176 +                 @"CSSM_WrapKey")) {
  32.177 +        result = [NSData dataWithBytes: wrapped.KeyData.Data 
  32.178 +                                length: wrapped.KeyData.Length];
  32.179 +    }
  32.180 +    CSSM_DeleteContext(ccHandle);
  32.181 +    return result;
  32.182 +}
  32.183 +*/
    33.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    33.2 +++ b/iPhone/MYCrypto_iPhone-Info.plist	Sat Apr 04 20:42:03 2009 -0700
    33.3 @@ -0,0 +1,30 @@
    33.4 +<?xml version="1.0" encoding="UTF-8"?>
    33.5 +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    33.6 +<plist version="1.0">
    33.7 +<dict>
    33.8 +	<key>CFBundleDevelopmentRegion</key>
    33.9 +	<string>English</string>
   33.10 +	<key>CFBundleDisplayName</key>
   33.11 +	<string>${PRODUCT_NAME}</string>
   33.12 +	<key>CFBundleExecutable</key>
   33.13 +	<string>${EXECUTABLE_NAME}</string>
   33.14 +	<key>CFBundleIconFile</key>
   33.15 +	<string></string>
   33.16 +	<key>CFBundleIdentifier</key>
   33.17 +	<string>com.yourcompany.${PRODUCT_NAME:rfc1034identifier}</string>
   33.18 +	<key>CFBundleInfoDictionaryVersion</key>
   33.19 +	<string>6.0</string>
   33.20 +	<key>CFBundleName</key>
   33.21 +	<string>${PRODUCT_NAME}</string>
   33.22 +	<key>CFBundlePackageType</key>
   33.23 +	<string>APPL</string>
   33.24 +	<key>CFBundleSignature</key>
   33.25 +	<string>????</string>
   33.26 +	<key>CFBundleVersion</key>
   33.27 +	<string>1.0</string>
   33.28 +	<key>LSRequiresIPhoneOS</key>
   33.29 +	<true/>
   33.30 +	<key>NSMainNibFile</key>
   33.31 +	<string>MainWindow</string>
   33.32 +</dict>
   33.33 +</plist>
    34.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    34.2 +++ b/iPhone/MYCrypto_iPhoneAppDelegate.h	Sat Apr 04 20:42:03 2009 -0700
    34.3 @@ -0,0 +1,18 @@
    34.4 +//
    34.5 +//  MYCrypto_iPhoneAppDelegate.h
    34.6 +//  MYCrypto-iPhone
    34.7 +//
    34.8 +//  Created by Jens Alfke on 3/30/09.
    34.9 +//  Copyright Jens Alfke 2009. All rights reserved.
   34.10 +//
   34.11 +
   34.12 +#import <UIKit/UIKit.h>
   34.13 +
   34.14 +@interface MYCrypto_iPhoneAppDelegate : NSObject <UIApplicationDelegate> {
   34.15 +    UIWindow *window;
   34.16 +}
   34.17 +
   34.18 +@property (nonatomic, retain) IBOutlet UIWindow *window;
   34.19 +
   34.20 +@end
   34.21 +
    35.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    35.2 +++ b/iPhone/MYCrypto_iPhoneAppDelegate.m	Sat Apr 04 20:42:03 2009 -0700
    35.3 @@ -0,0 +1,36 @@
    35.4 +//
    35.5 +//  MYCrypto_iPhoneAppDelegate.m
    35.6 +//  MYCrypto-iPhone
    35.7 +//
    35.8 +//  Created by Jens Alfke on 3/30/09.
    35.9 +//  Copyright Jens Alfke 2009. All rights reserved.
   35.10 +//
   35.11 +
   35.12 +#import "MYCrypto_iPhoneAppDelegate.h"
   35.13 +#import "MYErrorUtils.h"
   35.14 +
   35.15 +
   35.16 +@implementation MYCrypto_iPhoneAppDelegate
   35.17 +
   35.18 +@synthesize window;
   35.19 +
   35.20 +
   35.21 +- (void)applicationDidFinishLaunching:(UIApplication *)application {    
   35.22 +
   35.23 +    // Override point for customization after application launch
   35.24 +    [window makeKeyAndVisible];
   35.25 +    
   35.26 +    static const char *testArgs[] = {"MYCrypto", "Test_All"};
   35.27 +    int argc = 2;
   35.28 +    const char **argv = testArgs;
   35.29 +    RunTestCases(argc,argv);
   35.30 +}
   35.31 +
   35.32 +
   35.33 +- (void)dealloc {
   35.34 +    [window release];
   35.35 +    [super dealloc];
   35.36 +}
   35.37 +
   35.38 +
   35.39 +@end
    36.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    36.2 +++ b/iPhone/MYCrypto_iPhone_main.m	Sat Apr 04 20:42:03 2009 -0700
    36.3 @@ -0,0 +1,25 @@
    36.4 +//
    36.5 +//  main.m
    36.6 +//  MYCrypto-iPhone
    36.7 +//
    36.8 +//  Created by Jens Alfke on 3/30/09.
    36.9 +//  Copyright Jens Alfke 2009. All rights reserved.
   36.10 +//
   36.11 +
   36.12 +#import <UIKit/UIKit.h>
   36.13 +
   36.14 +int main(int argc, char *argv[]) {
   36.15 +    /*
   36.16 +    if (argc<2) {
   36.17 +        static char *testArgs[] = {"MYCrypto", "Test_All"};
   36.18 +        argc = 2;
   36.19 +        argv = testArgs;
   36.20 +    }
   36.21 +    RunTestCases(argc,(const char**)argv);
   36.22 +     */
   36.23 +    
   36.24 +    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
   36.25 +    int retVal = UIApplicationMain(argc, argv, nil, nil);
   36.26 +    [pool release];
   36.27 +    return retVal;
   36.28 +}
    37.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    37.2 +++ b/iPhone/MainWindow.xib	Sat Apr 04 20:42:03 2009 -0700
    37.3 @@ -0,0 +1,190 @@
    37.4 +<?xml version="1.0" encoding="UTF-8"?>
    37.5 +<archive type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="7.10">
    37.6 +	<data>
    37.7 +		<int key="IBDocument.SystemTarget">768</int>
    37.8 +		<string key="IBDocument.SystemVersion">10A288</string>
    37.9 +		<string key="IBDocument.InterfaceBuilderVersion">715</string>
   37.10 +		<string key="IBDocument.AppKitVersion">1010</string>
   37.11 +		<string key="IBDocument.HIToolboxVersion">411.00</string>
   37.12 +		<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
   37.13 +			<string key="NS.key.0">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
   37.14 +			<string key="NS.object.0">46</string>
   37.15 +		</object>
   37.16 +		<object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
   37.17 +			<bool key="EncodedWithXMLCoder">YES</bool>
   37.18 +			<integer value="2"/>
   37.19 +		</object>
   37.20 +		<object class="NSArray" key="IBDocument.PluginDependencies">
   37.21 +			<bool key="EncodedWithXMLCoder">YES</bool>
   37.22 +			<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
   37.23 +		</object>
   37.24 +		<object class="NSMutableDictionary" key="IBDocument.Metadata">
   37.25 +			<bool key="EncodedWithXMLCoder">YES</bool>
   37.26 +			<object class="NSArray" key="dict.sortedKeys" id="0">
   37.27 +				<bool key="EncodedWithXMLCoder">YES</bool>
   37.28 +			</object>
   37.29 +			<object class="NSMutableArray" key="dict.values">
   37.30 +				<bool key="EncodedWithXMLCoder">YES</bool>
   37.31 +			</object>
   37.32 +		</object>
   37.33 +		<object class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
   37.34 +			<bool key="EncodedWithXMLCoder">YES</bool>
   37.35 +			<object class="IBProxyObject" id="841351856">
   37.36 +				<string key="IBProxiedObjectIdentifier">IBFilesOwner</string>
   37.37 +			</object>
   37.38 +			<object class="IBProxyObject" id="427554174">
   37.39 +				<string key="IBProxiedObjectIdentifier">IBFirstResponder</string>
   37.40 +			</object>
   37.41 +			<object class="IBUICustomObject" id="664661524"/>
   37.42 +			<object class="IBUIWindow" id="380026005">
   37.43 +				<reference key="NSNextResponder"/>
   37.44 +				<int key="NSvFlags">1316</int>
   37.45 +				<object class="NSPSMatrix" key="NSFrameMatrix"/>
   37.46 +				<string key="NSFrameSize">{320, 480}</string>
   37.47 +				<reference key="NSSuperview"/>
   37.48 +				<object class="NSColor" key="IBUIBackgroundColor">
   37.49 +					<int key="NSColorSpace">1</int>
   37.50 +					<bytes key="NSRGB">MSAxIDEAA</bytes>
   37.51 +				</object>
   37.52 +				<bool key="IBUIOpaque">NO</bool>
   37.53 +				<bool key="IBUIClearsContextBeforeDrawing">NO</bool>
   37.54 +				<object class="IBUISimulatedStatusBarMetrics" key="IBUISimulatedStatusBarMetrics"/>
   37.55 +			</object>
   37.56 +		</object>
   37.57 +		<object class="IBObjectContainer" key="IBDocument.Objects">
   37.58 +			<object class="NSMutableArray" key="connectionRecords">
   37.59 +				<bool key="EncodedWithXMLCoder">YES</bool>
   37.60 +				<object class="IBConnectionRecord">
   37.61 +					<object class="IBCocoaTouchOutletConnection" key="connection">
   37.62 +						<string key="label">delegate</string>
   37.63 +						<reference key="source" ref="841351856"/>
   37.64 +						<reference key="destination" ref="664661524"/>
   37.65 +					</object>
   37.66 +					<int key="connectionID">4</int>
   37.67 +				</object>
   37.68 +				<object class="IBConnectionRecord">
   37.69 +					<object class="IBCocoaTouchOutletConnection" key="connection">
   37.70 +						<string key="label">window</string>
   37.71 +						<reference key="source" ref="664661524"/>
   37.72 +						<reference key="destination" ref="380026005"/>
   37.73 +					</object>
   37.74 +					<int key="connectionID">5</int>
   37.75 +				</object>
   37.76 +			</object>
   37.77 +			<object class="IBMutableOrderedSet" key="objectRecords">
   37.78 +				<object class="NSArray" key="orderedObjects">
   37.79 +					<bool key="EncodedWithXMLCoder">YES</bool>
   37.80 +					<object class="IBObjectRecord">
   37.81 +						<int key="objectID">0</int>
   37.82 +						<reference key="object" ref="0"/>
   37.83 +						<reference key="children" ref="1000"/>
   37.84 +						<nil key="parent"/>
   37.85 +					</object>
   37.86 +					<object class="IBObjectRecord">
   37.87 +						<int key="objectID">2</int>
   37.88 +						<reference key="object" ref="380026005"/>
   37.89 +						<object class="NSMutableArray" key="children">
   37.90 +							<bool key="EncodedWithXMLCoder">YES</bool>
   37.91 +						</object>
   37.92 +						<reference key="parent" ref="0"/>
   37.93 +					</object>
   37.94 +					<object class="IBObjectRecord">
   37.95 +						<int key="objectID">-1</int>
   37.96 +						<reference key="object" ref="841351856"/>
   37.97 +						<reference key="parent" ref="0"/>
   37.98 +						<string key="objectName">File's Owner</string>
   37.99 +					</object>
  37.100 +					<object class="IBObjectRecord">
  37.101 +						<int key="objectID">3</int>
  37.102 +						<reference key="object" ref="664661524"/>
  37.103 +						<reference key="parent" ref="0"/>
  37.104 +					</object>
  37.105 +					<object class="IBObjectRecord">
  37.106 +						<int key="objectID">-2</int>
  37.107 +						<reference key="object" ref="427554174"/>
  37.108 +						<reference key="parent" ref="0"/>
  37.109 +					</object>
  37.110 +				</object>
  37.111 +			</object>
  37.112 +			<object class="NSMutableDictionary" key="flattenedProperties">
  37.113 +				<bool key="EncodedWithXMLCoder">YES</bool>
  37.114 +				<object class="NSArray" key="dict.sortedKeys">
  37.115 +					<bool key="EncodedWithXMLCoder">YES</bool>
  37.116 +					<string>-1.CustomClassName</string>
  37.117 +					<string>-2.CustomClassName</string>
  37.118 +					<string>2.IBAttributePlaceholdersKey</string>
  37.119 +					<string>2.IBEditorWindowLastContentRect</string>
  37.120 +					<string>2.IBPluginDependency</string>
  37.121 +					<string>3.CustomClassName</string>
  37.122 +					<string>3.IBPluginDependency</string>
  37.123 +				</object>
  37.124 +				<object class="NSMutableArray" key="dict.values">
  37.125 +					<bool key="EncodedWithXMLCoder">YES</bool>
  37.126 +					<string>UIApplication</string>
  37.127 +					<string>UIResponder</string>
  37.128 +					<object class="NSMutableDictionary">
  37.129 +						<bool key="EncodedWithXMLCoder">YES</bool>
  37.130 +						<reference key="dict.sortedKeys" ref="0"/>
  37.131 +						<object class="NSMutableArray" key="dict.values">
  37.132 +							<bool key="EncodedWithXMLCoder">YES</bool>
  37.133 +						</object>
  37.134 +					</object>
  37.135 +					<string>{{438, 320}, {320, 480}}</string>
  37.136 +					<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
  37.137 +					<string>MYCrypto_iPhoneAppDelegate</string>
  37.138 +					<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
  37.139 +				</object>
  37.140 +			</object>
  37.141 +			<object class="NSMutableDictionary" key="unlocalizedProperties">
  37.142 +				<bool key="EncodedWithXMLCoder">YES</bool>
  37.143 +				<reference key="dict.sortedKeys" ref="0"/>
  37.144 +				<object class="NSMutableArray" key="dict.values">
  37.145 +					<bool key="EncodedWithXMLCoder">YES</bool>
  37.146 +				</object>
  37.147 +			</object>
  37.148 +			<nil key="activeLocalization"/>
  37.149 +			<object class="NSMutableDictionary" key="localizations">
  37.150 +				<bool key="EncodedWithXMLCoder">YES</bool>
  37.151 +				<reference key="dict.sortedKeys" ref="0"/>
  37.152 +				<object class="NSMutableArray" key="dict.values">
  37.153 +					<bool key="EncodedWithXMLCoder">YES</bool>
  37.154 +				</object>
  37.155 +			</object>
  37.156 +			<nil key="sourceID"/>
  37.157 +			<int key="maxID">9</int>
  37.158 +		</object>
  37.159 +		<object class="IBClassDescriber" key="IBDocument.Classes">
  37.160 +			<object class="NSMutableArray" key="referencedPartialClassDescriptions">
  37.161 +				<bool key="EncodedWithXMLCoder">YES</bool>
  37.162 +				<object class="IBPartialClassDescription">
  37.163 +					<string key="className">MYCrypto_iPhoneAppDelegate</string>
  37.164 +					<string key="superclassName">NSObject</string>
  37.165 +					<object class="NSMutableDictionary" key="outlets">
  37.166 +						<string key="NS.key.0">window</string>
  37.167 +						<string key="NS.object.0">UIWindow</string>
  37.168 +					</object>
  37.169 +					<object class="IBClassDescriptionSource" key="sourceIdentifier">
  37.170 +						<string key="majorKey">IBProjectSource</string>
  37.171 +						<string key="minorKey">Classes/MYCrypto_iPhoneAppDelegate.h</string>
  37.172 +					</object>
  37.173 +				</object>
  37.174 +				<object class="IBPartialClassDescription">
  37.175 +					<string key="className">MYCrypto_iPhoneAppDelegate</string>
  37.176 +					<string key="superclassName">NSObject</string>
  37.177 +					<object class="IBClassDescriptionSource" key="sourceIdentifier">
  37.178 +						<string key="majorKey">IBUserSource</string>
  37.179 +						<string key="minorKey"/>
  37.180 +					</object>
  37.181 +				</object>
  37.182 +			</object>
  37.183 +		</object>
  37.184 +		<int key="IBDocument.localizationMode">0</int>
  37.185 +		<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
  37.186 +			<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3</string>
  37.187 +			<integer value="3100" key="NS.object.0"/>
  37.188 +		</object>
  37.189 +		<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
  37.190 +		<string key="IBDocument.LastKnownRelativeProjectPath">MYCrypto-iPhone.xcodeproj</string>
  37.191 +		<int key="IBDocument.defaultPropertyAccessControl">3</int>
  37.192 +	</data>
  37.193 +</archive>