Initial checkin. Passes tests on Mac and in iPhone simulator.
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, ¶ms);
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,¶ms);
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,¶ms);
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 + ¶ms, &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 + ¶ms, &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>