Implemented wrap/unwrap of session key using a key-pair.
1.1 --- a/MYCrypto.xcodeproj/project.pbxproj Sat Apr 18 18:12:06 2009 -0700
1.2 +++ b/MYCrypto.xcodeproj/project.pbxproj Sun Apr 19 00:01:41 2009 -0700
1.3 @@ -354,6 +354,7 @@
1.4 baseConfigurationReference = 27CFF5400F7E9653000B418E /* MYCrypto_Debug.xcconfig */;
1.5 buildSettings = {
1.6 ALWAYS_SEARCH_USER_PATHS = NO;
1.7 + GCC_WARN_UNUSED_FUNCTION = NO;
1.8 HEADER_SEARCH_PATHS = "/Code/MYCrypto/**";
1.9 };
1.10 name = Debug;
2.1 --- a/MYCryptoTest.m Sat Apr 18 18:12:06 2009 -0700
2.2 +++ b/MYCryptoTest.m Sun Apr 19 00:01:41 2009 -0700
2.3 @@ -155,11 +155,12 @@
2.4 #endif
2.5
2.6 #if !TARGET_OS_IPHONE
2.7 +#if 0 // TEMPORARILY OUT OF ORDER
2.8 // Try exporting and importing a wrapped key:
2.9 Log(@"Testing export/import...");
2.10 - NSData *exported = [key exportKeyInFormat: kSecFormatWrappedPKCS8 withPEM: NO];
2.11 + NSData *exported = [key exportWrappedKeyWithPassphrasePrompt: @"Export symmetric key with passphrase:"];
2.12 Log(@"Exported key: %@", exported);
2.13 - #if 0
2.14 + #if 1
2.15 CAssert(exported);
2.16 #else
2.17 //FIX: Exporting symmetric keys isn't working. Temporarily making this optional.
2.18 @@ -175,6 +176,7 @@
2.19 decrypted = [key2 decryptData: encrypted];
2.20 CAssertEqual(decrypted, cleartext);
2.21 }
2.22 +#endif 0
2.23 #endif
2.24 }@finally{
2.25 [key removeFromKeychain];
2.26 @@ -272,10 +274,10 @@
2.27 CAssert( [publicKey verifySignature: sig ofData: data] );
2.28
2.29 // Now let's encrypt...
2.30 - NSData *crypted = [publicKey encryptData: data];
2.31 + NSData *crypted = [publicKey rawEncryptData: data];
2.32 Log(@"Encrypted = %@ (%u bytes)",crypted,crypted.length);
2.33 CAssert(crypted);
2.34 - CAssertEqual([pair decryptData: crypted], data);
2.35 + CAssertEqual([pair rawDecryptData: crypted], data);
2.36 Log(@"Verified decryption.");
2.37
2.38 // Test creating a standalone public key:
2.39 @@ -294,6 +296,23 @@
2.40 }
2.41
2.42
2.43 +static void testWrapSessionKey( MYPrivateKey *privateKey ) {
2.44 + MYSymmetricKey *sessionKey = [MYSymmetricKey generateSymmetricKeyOfSize: 128 algorithm:kCCAlgorithmAES128];
2.45 + CAssert(sessionKey);
2.46 + Log(@"Wrapping session key %@, %@", sessionKey, sessionKey.keyData);
2.47 + NSData *wrapped = [privateKey.publicKey wrapSessionKey: sessionKey];
2.48 + Log(@"Wrapped session key = %u bytes: %@", wrapped.length,wrapped);
2.49 + CAssert(wrapped.length >= 128/8);
2.50 +
2.51 + MYSymmetricKey *unwrappedKey = [privateKey unwrapSessionKey: wrapped
2.52 + withAlgorithm: kCCAlgorithmAES128
2.53 + sizeInBits: 128];
2.54 + Log(@"Unwrapped session key = %@, %@", unwrappedKey, unwrappedKey.keyData);
2.55 + CAssert(unwrappedKey);
2.56 + CAssertEqual(unwrappedKey.keyData, sessionKey.keyData);
2.57 +}
2.58 +
2.59 +
2.60 TestCase(MYGenerateKeyPair) {
2.61 RequireTestCase(MYKeychain);
2.62
2.63 @@ -304,6 +323,7 @@
2.64
2.65 @try{
2.66 TestUseKeyPair(pair);
2.67 + testWrapSessionKey(pair);
2.68
2.69 [pair setName: @"Test KeyPair Label"];
2.70 CAssertEqual(pair.name, @"Test KeyPair Label");
3.1 --- a/MYCrypto_Private.h Sat Apr 18 18:12:06 2009 -0700
3.2 +++ b/MYCrypto_Private.h Sun Apr 19 00:01:41 2009 -0700
3.3 @@ -58,7 +58,6 @@
3.4 #if !MYCRYPTO_USE_IPHONE_API
3.5 @property (readonly) const CSSM_KEY* cssmKey;
3.6 @property (readonly) const CSSM_CSP_HANDLE cssmCSPHandle;
3.7 -- (NSData*) exportKeyInFormat: (SecExternalFormat)format withPEM: (BOOL)withPEM;
3.8 - (CSSM_CC_HANDLE) _createSignatureContext: (CSSM_ALGORITHMS)algorithm;
3.9 - (CSSM_CC_HANDLE) _createPassThroughContext;
3.10 #endif
3.11 @@ -67,6 +66,9 @@
3.12
3.13
3.14 @interface MYSymmetricKey (Private)
3.15 +#if !MYCRYPTO_USE_IPHONE_API
3.16 +- (id) _initWithCSSMKey: (CSSM_KEY*)cssmKey;
3.17 +#endif
3.18 + (MYSymmetricKey*) _generateSymmetricKeyOfSize: (unsigned)keySizeInBits
3.19 algorithm: (CCAlgorithm)algorithm
3.20 inKeychain: (MYKeychain*)keychain;
3.21 @@ -126,5 +128,6 @@
3.22 SecKeyImportExportParameters *params /*non-null*/);
3.23
3.24 NSString* OIDAsString(CSSM_OID OID);
3.25 +CSSM_ALGORITHMS CSSMFromCCAlgorithm( CCAlgorithm ccAlgorithm );
3.26
3.27 #endif
4.1 --- a/MYKey.h Sat Apr 18 18:12:06 2009 -0700
4.2 +++ b/MYKey.h Sun Apr 19 00:01:41 2009 -0700
4.3 @@ -54,13 +54,6 @@
4.4 The user can edit this, so don't expect it to be immutable. */
4.5 @property (copy) NSString *comment;
4.6
4.7 -/** Converts the key into a data blob in one of several standard formats, suitable for storing in
4.8 - a file or sending over the network.
4.9 - @param format The data format: kSecFormatOpenSSL, kSecFormatSSH, kSecFormatBSAFE or kSecFormatSSHv2.
4.10 - @param withPEM YES if the data should be encoded in PEM format, which converts into short lines
4.11 - of printable ASCII characters, suitable for sending in email. */
4.12 -- (NSData*) exportKeyInFormat: (SecExternalFormat)format withPEM: (BOOL)withPEM;
4.13 -
4.14 #endif
4.15 //@}
4.16
4.17 @@ -84,6 +77,8 @@
4.18 /** The underlying CSSM_CSP_HANDLE structure; used with low-level crypto APIs. */
4.19 @property (readonly) intptr_t /*CSSM_CSP_HANDLE*/ cssmCSPHandle;
4.20
4.21 +@property (readonly) CSSM_ALGORITHMS cssmAlgorithm;
4.22 +
4.23 /** Gets CSSM authorization credentials for a specified operation, such as
4.24 CSSM_ACL_AUTHORIZATION_ENCRYPT. This pointer is necessary for creating some CSSM operation
4.25 contexts.
5.1 --- a/MYKey.m Sat Apr 18 18:12:06 2009 -0700
5.2 +++ b/MYKey.m Sun Apr 19 00:01:41 2009 -0700
5.3 @@ -67,6 +67,10 @@
5.4 return cspHandle;
5.5 }
5.6
5.7 +- (CSSM_ALGORITHMS) cssmAlgorithm {
5.8 + return self.cssmKey->KeyHeader.AlgorithmId;
5.9 +}
5.10 +
5.11 - (const CSSM_ACCESS_CREDENTIALS*) cssmCredentialsForOperation: (CSSM_ACL_AUTHORIZATION_TAG)operation
5.12 type: (SecCredentialType)type
5.13 error: (NSError**)outError
5.14 @@ -81,19 +85,19 @@
5.15 return credentials;
5.16 }
5.17
5.18 -- (NSData*) exportKeyInFormat: (SecExternalFormat)format withPEM: (BOOL)withPEM {
5.19 +- (SecExternalFormat) _externalFormat {
5.20 + return kSecFormatRawKey;
5.21 +}
5.22 +
5.23 +- (NSData*) keyData {
5.24 CFDataRef data = NULL;
5.25 - if (check(SecKeychainItemExport(self.keyRef, format, (withPEM ?kSecItemPemArmour :0), NULL, &data),
5.26 + if (check(SecKeychainItemExport(self.keyRef, self._externalFormat, 0, NULL, &data),
5.27 @"SecKeychainItemExport"))
5.28 return [(id)CFMakeCollectable(data) autorelease];
5.29 else
5.30 return nil;
5.31 }
5.32
5.33 -- (NSData*) keyData {
5.34 - return [self exportKeyInFormat: kSecFormatRawKey withPEM: NO];
5.35 -}
5.36 -
5.37 - (NSString*) name {
5.38 return [self stringValueOfAttribute: kSecKeyPrintName];
5.39 }
6.1 --- a/MYKeychainItem.m Sat Apr 18 18:12:06 2009 -0700
6.2 +++ b/MYKeychainItem.m Sun Apr 19 00:01:41 2009 -0700
6.3 @@ -98,7 +98,7 @@
6.4 #else
6.5 err = SecKeychainItemDelete((SecKeychainItemRef)_itemRef);
6.6 #endif
6.7 - return err==errSecItemNotFound || check(err, @"SecKeychainItemDelete");
6.8 + return err==errSecItemNotFound || err==errSecInvalidItemRef || check(err, @"SecKeychainItemDelete");
6.9 }
6.10
6.11
7.1 --- a/MYPrivateKey.h Sat Apr 18 18:12:06 2009 -0700
7.2 +++ b/MYPrivateKey.h Sun Apr 19 00:01:41 2009 -0700
7.3 @@ -7,14 +7,15 @@
7.4 //
7.5
7.6 #import "MYKey.h"
7.7 -@class MYPublicKey, MYSHA1Digest, MYIdentity;
7.8 +#import <CommonCrypto/CommonCryptor.h>
7.9 +@class MYPublicKey, MYSHA1Digest, MYIdentity, MYSymmetricKey;
7.10
7.11
7.12 /** A private key, used for signing and decrypting data.
7.13 Always paired with a matching public key in a "key-pair".
7.14 MYPublicKeys are instantiated by MYKeychain: either by generating a new key-pair, by
7.15 looking up a key-pair by its attributes, or by importing a key-pair from data. */
7.16 -@interface MYPrivateKey : MYKey <MYDecryption>
7.17 +@interface MYPrivateKey : MYKey
7.18 {
7.19 @private
7.20 MYPublicKey *_publicKey;
7.21 @@ -33,7 +34,7 @@
7.22 See the description of -[MYPublicKey encryptData:] for warnings and caveats.
7.23 This method is usually used only to decrypt a symmetric session key, which then decrypts the
7.24 rest of the data. */
7.25 -- (NSData*) decryptData: (NSData*)data;
7.26 +- (NSData*) rawDecryptData: (NSData*)data;
7.27
7.28 /** Generates a signature of data.
7.29 (What's actually signed using RSA is the SHA-256 digest of the data.)
7.30 @@ -80,6 +81,15 @@
7.31 withPEM: (BOOL)withPEM
7.32 alertTitle: (NSString*)alertTitle
7.33 alertPrompt: (NSString*)prompt;
7.34 +
7.35 +/** Decrypts a session key that was wrapped (encrypted) using my matching public key.
7.36 + @param wrappedData The wrapped/encrypted session key
7.37 + @param algorithm The algorithm of the original session key
7.38 + @param sizeInBits The key size (in bits) of the original session key
7.39 + @return The reconstituted session key */
7.40 +- (MYSymmetricKey*) unwrapSessionKey: (NSData*)wrappedData
7.41 + withAlgorithm: (CCAlgorithm)algorithm
7.42 + sizeInBits: (unsigned)sizeInBits;
7.43 #endif
7.44 //@}
7.45
8.1 --- a/MYPrivateKey.m Sat Apr 18 18:12:06 2009 -0700
8.2 +++ b/MYPrivateKey.m Sun Apr 19 00:01:41 2009 -0700
8.3 @@ -153,7 +153,7 @@
8.4 CSSM_ALGID_RSA,
8.5 keySize,
8.6 0LL,
8.7 - CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_VERIFY, // public key
8.8 + CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_WRAP, // public key
8.9 CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT,
8.10 CSSM_KEYUSE_ANY, // private key
8.11 CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_SENSITIVE,
8.12 @@ -213,7 +213,7 @@
8.13 }
8.14
8.15
8.16 -- (NSData*) decryptData: (NSData*)data {
8.17 +- (NSData*) rawDecryptData: (NSData*)data {
8.18 return [self _crypt: data operation: NO];
8.19 }
8.20
8.21 @@ -300,6 +300,64 @@
8.22 return nil;
8.23 }
8.24
8.25 -#endif TARGET_OS_IPHONE
8.26 +
8.27 +- (MYSymmetricKey*) unwrapSessionKey: (NSData*)wrappedData
8.28 + withAlgorithm: (CCAlgorithm)algorithm
8.29 + sizeInBits: (unsigned)sizeInBits
8.30 +{
8.31 + // First create a wrapped-key structure from the data:
8.32 + CSSM_WRAP_KEY wrappedKey = {
8.33 + .KeyHeader = {
8.34 + .BlobType = CSSM_KEYBLOB_WRAPPED,
8.35 + .Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS3,
8.36 + .AlgorithmId = CSSMFromCCAlgorithm(algorithm),
8.37 + .KeyClass = CSSM_KEYCLASS_SESSION_KEY,
8.38 + .LogicalKeySizeInBits = sizeInBits,
8.39 + .KeyAttr = CSSM_KEYATTR_EXTRACTABLE,
8.40 + .KeyUsage = CSSM_KEYUSE_ANY,
8.41 + .WrapAlgorithmId = self.cssmAlgorithm,
8.42 + },
8.43 + .KeyData = {
8.44 + .Data = (void*)wrappedData.bytes,
8.45 + .Length = wrappedData.length
8.46 + }
8.47 + };
8.48 +
8.49 + const CSSM_ACCESS_CREDENTIALS* credentials;
8.50 + credentials = [self cssmCredentialsForOperation: CSSM_ACL_AUTHORIZATION_IMPORT_WRAPPED
8.51 + type: kSecCredentialTypeDefault error: nil];
8.52 + CSSM_CSP_HANDLE cspHandle = self.cssmCSPHandle;
8.53 + CSSM_CC_HANDLE ctx;
8.54 + if (!checkcssm(CSSM_CSP_CreateAsymmetricContext(cspHandle,
8.55 + self.cssmAlgorithm,
8.56 + credentials,
8.57 + self.cssmKey,
8.58 + CSSM_PADDING_PKCS1,
8.59 + &ctx),
8.60 + @"CSSM_CSP_CreateAsymmetricContext"))
8.61 + return nil;
8.62 +
8.63 + // Now unwrap the key:
8.64 + MYSymmetricKey *result = nil;
8.65 + CSSM_KEY *unwrappedKey = calloc(1,sizeof(CSSM_KEY));
8.66 + CSSM_DATA desc = {};
8.67 + if (checkcssm(CSSM_UnwrapKey(ctx,
8.68 + self.cssmKey,
8.69 + &wrappedKey,
8.70 + wrappedKey.KeyHeader.KeyUsage,
8.71 + wrappedKey.KeyHeader.KeyAttr,
8.72 + NULL, NULL,
8.73 + unwrappedKey,
8.74 + &desc),
8.75 + @"CSSM_UnwrapKey")) {
8.76 + result = [[[MYSymmetricKey alloc] _initWithCSSMKey: unwrappedKey] autorelease];
8.77 + }
8.78 + // Finally, delete the context
8.79 + CSSM_DeleteContext(ctx);
8.80 + return result;
8.81 +}
8.82 +
8.83 +
8.84 +#endif !TARGET_OS_IPHONE
8.85
8.86 @end
9.1 --- a/MYPublicKey.h Sat Apr 18 18:12:06 2009 -0700
9.2 +++ b/MYPublicKey.h Sun Apr 19 00:01:41 2009 -0700
9.3 @@ -7,7 +7,7 @@
9.4 //
9.5
9.6 #import "MYKey.h"
9.7 -@class MYSHA1Digest;
9.8 +@class MYSHA1Digest, MYSymmetricKey;
9.9
9.10 #if !TARGET_OS_IPHONE
9.11 #import <Security/SecKey.h>
9.12 @@ -17,7 +17,7 @@
9.13 /** A public key, which can be used for encrypting data and verifying signatures.
9.14 MYPublicKeys are created as part of generating a key-pair,
9.15 or by being imported from data into a MYKeychain. */
9.16 -@interface MYPublicKey : MYKey <MYEncryption>
9.17 +@interface MYPublicKey : MYKey
9.18 {
9.19 @private
9.20 MYSHA1Digest *_digest;
9.21 @@ -34,7 +34,7 @@
9.22 symmetric key, called the "session key" (using a Cryptor), encrypt that session key with the
9.23 public key, and then encrypt your data with the session key. Send the encrypted session key
9.24 and the encrypted data. */
9.25 -- (NSData*) encryptData: (NSData*)data;
9.26 +- (NSData*) rawEncryptData: (NSData*)data;
9.27
9.28 /** Verifies the signature of a block of data. If the result is YES, you can be assured that
9.29 the signature was generated from the data by using this key's matching private key.
9.30 @@ -42,5 +42,11 @@
9.31 or the signature was generated by a different private key.
9.32 (What's actually verified using RSA is the SHA-256 digest of the data.) */
9.33 - (BOOL) verifySignature: (NSData*)signature ofData: (NSData*)data;
9.34 -
9.35 +
9.36 +/** Encrypts a session key using this public key.
9.37 + The holder of the private key can then unwrap the session key from this data.
9.38 + @param sessionKey The symmetric session key to wrap/encrypt
9.39 + @return The encrypted data representing the session key */
9.40 +- (NSData*) wrapSessionKey: (MYSymmetricKey*)sessionKey;
9.41 +
9.42 @end
10.1 --- a/MYPublicKey.m Sat Apr 18 18:12:06 2009 -0700
10.2 +++ b/MYPublicKey.m Sun Apr 19 00:01:41 2009 -0700
10.3 @@ -46,13 +46,13 @@
10.4 }
10.5
10.6 #if !MYCRYPTO_USE_IPHONE_API
10.7 -- (NSData*) keyData {
10.8 - return [self exportKeyInFormat: kSecFormatOpenSSL withPEM: NO];
10.9 +- (SecExternalFormat) _externalFormat {
10.10 + return kSecFormatOpenSSL;
10.11 }
10.12 #endif
10.13
10.14
10.15 -- (NSData*) encryptData: (NSData*)data {
10.16 +- (NSData*) rawEncryptData: (NSData*)data {
10.17 return [self _crypt: data operation: YES];
10.18 }
10.19
10.20 @@ -118,6 +118,38 @@
10.21 CSSM_DeleteContext(ccHandle);
10.22 return result;
10.23 }
10.24 +
10.25 +
10.26 +- (NSData*) wrapSessionKey: (MYSymmetricKey*)sessionKey {
10.27 + const CSSM_ACCESS_CREDENTIALS* credentials;
10.28 + credentials = [self cssmCredentialsForOperation: CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED
10.29 + type: kSecCredentialTypeDefault error: nil];
10.30 + CSSM_CSP_HANDLE cspHandle = self.cssmCSPHandle;
10.31 + CSSM_CC_HANDLE ctx;
10.32 + if (!checkcssm(CSSM_CSP_CreateAsymmetricContext(cspHandle,
10.33 + self.cssmAlgorithm,
10.34 + credentials,
10.35 + self.cssmKey,
10.36 + CSSM_PADDING_PKCS1,
10.37 + &ctx),
10.38 + @"CSSM_CSP_CreateAsymmetricContext"))
10.39 + return nil;
10.40 +
10.41 + // Now wrap the key:
10.42 + NSData *result = nil;
10.43 + CSSM_WRAP_KEY wrappedKey = {};
10.44 + if (checkcssm(CSSM_WrapKey(ctx, credentials, sessionKey.cssmKey, NULL, &wrappedKey),
10.45 + @"CSSM_WrapKey")) {
10.46 + // ...and copy the wrapped key data to the result NSData:
10.47 + result = [NSData dataWithBytes: wrappedKey.KeyData.Data length: wrappedKey.KeyData.Length];
10.48 + CSSM_FreeKey(cspHandle, credentials, &wrappedKey, NO);
10.49 + }
10.50 + // Finally, delete the context
10.51 + CSSM_DeleteContext(ctx);
10.52 + return result;
10.53 +}
10.54 +
10.55 +
10.56 #endif
10.57
10.58
11.1 --- a/MYSymmetricKey.h Sat Apr 18 18:12:06 2009 -0700
11.2 +++ b/MYSymmetricKey.h Sun Apr 19 00:01:41 2009 -0700
11.3 @@ -53,6 +53,8 @@
11.4 /** The key's size/length, in bits. */
11.5 @property (readonly) unsigned keySizeInBits;
11.6
11.7 +- (NSData*) exportWrappedKeyWithPassphrasePrompt: (NSString*)prompt;
11.8 +
11.9
11.10 /** A utility that prompts for a passphrase, using the Security agent's nice modal panel,
11.11 and returns the raw passphrase as a string.
12.1 --- a/MYSymmetricKey.m Sat Apr 18 18:12:06 2009 -0700
12.2 +++ b/MYSymmetricKey.m Sun Apr 19 00:01:41 2009 -0700
12.3 @@ -15,9 +15,15 @@
12.4 #import <Security/cssmtype.h>
12.5
12.6
12.7 -static const CSSM_ALGORITHMS kCSSMAlgorithms[] = {
12.8 - CSSM_ALGID_AES, CSSM_ALGID_DES, CSSM_ALGID_3DES_3KEY, CSSM_ALGID_CAST, CSSM_ALGID_RC4
12.9 -};
12.10 +CSSM_ALGORITHMS CSSMFromCCAlgorithm( CCAlgorithm ccAlgorithm ) {
12.11 + static const CSSM_ALGORITHMS kCSSMAlgorithms[] = {
12.12 + CSSM_ALGID_AES, CSSM_ALGID_DES, CSSM_ALGID_3DES_3KEY, CSSM_ALGID_CAST, CSSM_ALGID_RC4
12.13 + };
12.14 + if (ccAlgorithm >=0 && ccAlgorithm <= kCCAlgorithmRC4)
12.15 + return kCSSMAlgorithms[ccAlgorithm];
12.16 + else
12.17 + return CSSM_ALGID_NONE;
12.18 +}
12.19
12.20 static const char *kCCAlgorithmNames[] = {"AES", "DES", "DES^3", "CAST", "RC4"};
12.21
12.22 @@ -28,6 +34,8 @@
12.23
12.24 static CSSM_KEY* cssmKeyFromData( NSData *keyData, CSSM_ALGORITHMS algorithm,
12.25 MYKeychain *keychain);
12.26 +//static CSSM_ENCRYPT_MODE defaultModeForAlgorithm(CSSM_ALGORITHMS algorithm);
12.27 +//CSSM_PADDING defaultPaddingForAlgorithm(CSSM_ALGORITHMS algorithm);
12.28 static CSSM_DATA makeSalt( id salty, size_t length );
12.29 static CSSM_RETURN impExpCreatePassKey(
12.30 const SecKeyImportExportParameters *keyParams, // required
12.31 @@ -66,7 +74,7 @@
12.32 {
12.33 Assert(algorithm <= kCCAlgorithmRC4);
12.34 Assert(keyData);
12.35 - CSSM_KEY *key = cssmKeyFromData(keyData, kCSSMAlgorithms[algorithm], keychain);
12.36 + CSSM_KEY *key = cssmKeyFromData(keyData, CSSMFromCCAlgorithm(algorithm), keychain);
12.37 if (!key) {
12.38 [self release];
12.39 return nil;
12.40 @@ -87,11 +95,15 @@
12.41 Assert(algorithm <= kCCAlgorithmRC4);
12.42 CSSM_KEYATTR_FLAGS flags = CSSM_KEYATTR_EXTRACTABLE;
12.43 if (keychain)
12.44 - flags |= CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_SENSITIVE | CSSM_KEYATTR_EXTRACTABLE;
12.45 + flags |= CSSM_KEYATTR_PERMANENT; // | CSSM_KEYATTR_SENSITIVE; //FIX: Re-enable this bit
12.46 + else {
12.47 + flags |= CSSM_KEYATTR_RETURN_REF;
12.48 + keychain = [MYKeychain defaultKeychain]; // establish a context for the key
12.49 + }
12.50 CSSM_KEYUSE usage = CSSM_KEYUSE_ANY;
12.51 SecKeyRef keyRef = NULL;
12.52 - if (!check(SecKeyGenerate(keychain.keychainRefOrDefault, // nil kc generates a transient key
12.53 - kCSSMAlgorithms[algorithm],
12.54 + if (!check(SecKeyGenerate(keychain.keychainRefOrDefault,
12.55 + CSSMFromCCAlgorithm(algorithm),
12.56 keySizeInBits,
12.57 0, usage, flags, NULL, &keyRef),
12.58 @"SecKeyGenerate")) {
12.59 @@ -211,54 +223,43 @@
12.60
12.61
12.62 #if !TARGET_OS_IPHONE
12.63 -- (NSData*) exportKeyInFormat: (SecExternalFormat)format
12.64 - withPEM: (BOOL)withPEM
12.65 +- (NSData*) exportWrappedKeyWithPassphrasePrompt: (NSString*)prompt
12.66 {
12.67 - if (format==kSecFormatRawKey || format==kSecFormatUnknown)
12.68 - return [super exportKeyInFormat: format withPEM: withPEM];
12.69 -
12.70 - // Get access credentials:
12.71 - const CSSM_ACCESS_CREDENTIALS *credentials;
12.72 - credentials = [self cssmCredentialsForOperation: CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED
12.73 - type: kSecCredentialTypeDefault
12.74 - error: nil];
12.75 - if (!credentials)
12.76 - return nil;
12.77 -
12.78 // Prompt use for a passphrase to use for the wrapping key:
12.79 - MYSymmetricKey *wrappingKey = [MYSymmetricKey generateFromUserPassphraseWithAlertTitle: @"Export Key" alertPrompt: @"Enter a passphrase to encrypt the key you're exporting from the Keychain:" creating: YES
12.80 - salt: [MYCryptor randomKeyOfLength: PKCS5_V2_SALT_LEN*8]];
12.81 + MYSymmetricKey *wrappingKey = [MYSymmetricKey
12.82 + generateFromUserPassphraseWithAlertTitle: @"Export Key"
12.83 + alertPrompt: prompt
12.84 + creating: YES
12.85 + salt: [MYCryptor randomKeyOfLength: PKCS5_V2_SALT_LEN*8]];
12.86 if (!wrappingKey)
12.87 return nil;
12.88 + Log(@"Wrapping using %@",wrappingKey);
12.89
12.90 // Create the context:
12.91 + CSSM_ACCESS_CREDENTIALS credentials = {};
12.92 CSSM_CSP_HANDLE cspHandle = self.cssmCSPHandle;
12.93 + //CSSM_ALGORITHMS algorithm = wrappingKey.cssmAlgorithm;
12.94 CSSM_CC_HANDLE ctx;
12.95 if (!checkcssm(CSSM_CSP_CreateSymmetricContext(cspHandle,
12.96 - CSSM_ALGID_NONE,
12.97 - CSSM_ALGMODE_WRAP,
12.98 - NULL,
12.99 + wrappingKey.cssmAlgorithm, //CSSM_ALGID_3DES_3KEY_EDE, //algorithm,
12.100 + CSSM_ALGMODE_CBCPadIV8, //defaultModeForAlgorithm(algorithm),
12.101 + &credentials,
12.102 wrappingKey.cssmKey,
12.103 NULL,
12.104 - CSSM_PADDING_NONE,
12.105 + CSSM_PADDING_PKCS7, //defaultPaddingForAlgorithm(algorithm),
12.106 NULL,
12.107 &ctx),
12.108 @"CSSM_CSP_CreateSymmetricContext"))
12.109 return nil;
12.110
12.111 - // Set the wrapped key format:
12.112 + // Now wrap the key:
12.113 NSData *result = nil;
12.114 - CSSM_CONTEXT_ATTRIBUTE attr = { CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT, sizeof(uint32) };
12.115 - attr.Attribute.Uint32 = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7;
12.116 - if (checkcssm(CSSM_UpdateContextAttributes(ctx, 1, &attr), @"CSSM_UpdateContextAttributes")) {
12.117 - // Now wrap the key:
12.118 - CSSM_WRAP_KEY wrappedKey = {};
12.119 - if (checkcssm(CSSM_WrapKey(ctx, credentials, self.cssmKey, NULL, &wrappedKey),
12.120 - @"CSSM_WrapKey")) {
12.121 - // ...and copy the wrapped key data to the result NSData:
12.122 - result = [NSData dataWithBytes: wrappedKey.KeyData.Data length: wrappedKey.KeyData.Length];
12.123 - CSSM_FreeKey(cspHandle, credentials, &wrappedKey, NO);
12.124 - }
12.125 + CSSM_WRAP_KEY wrappedKey = {};
12.126 + if (checkcssm(CSSM_WrapKey(ctx, &credentials, self.cssmKey, NULL, &wrappedKey),
12.127 + @"CSSM_WrapKey")) {
12.128 + // ...and copy the wrapped key data to the result NSData:
12.129 + result = [NSData dataWithBytes: wrappedKey.KeyData.Data length: wrappedKey.KeyData.Length];
12.130 + CSSM_FreeKey(cspHandle, &credentials, &wrappedKey, NO);
12.131 }
12.132 // Finally, delete the context
12.133 CSSM_DeleteContext(ctx);
12.134 @@ -413,7 +414,62 @@
12.135 }
12.136
12.137
12.138 -// Copied from SecImportExportUtils.cpp in Apple's libsecurity_keychain project
12.139 +#pragma mark -
12.140 +// Code from Keychain.framework:
12.141 +#if 0
12.142 +static CSSM_ENCRYPT_MODE defaultModeForAlgorithm(CSSM_ALGORITHMS algorithm) {
12.143 + switch(algorithm) {
12.144 + // 8-byte block ciphers
12.145 + case CSSM_ALGID_DES:
12.146 + case CSSM_ALGID_3DES_3KEY_EDE:
12.147 + case CSSM_ALGID_RC5:
12.148 + case CSSM_ALGID_RC2:
12.149 + return CSSM_ALGMODE_CBCPadIV8; break;
12.150 + // 16-byte block ciphers
12.151 + case CSSM_ALGID_AES:
12.152 + return CSSM_ALGMODE_CBCPadIV8; break;
12.153 + // stream ciphers
12.154 + case CSSM_ALGID_ASC:
12.155 + case CSSM_ALGID_RC4:
12.156 + return CSSM_ALGMODE_NONE; break;
12.157 + // Unknown
12.158 + default:
12.159 + Warn(@"Asked for the default mode for algorithm %d, but don't know that algorithm.\n", algorithm);
12.160 + return CSSM_ALGMODE_NONE;
12.161 + }
12.162 +}
12.163 +
12.164 +CSSM_PADDING defaultPaddingForAlgorithm(CSSM_ALGORITHMS algorithm) {
12.165 + switch(algorithm) {
12.166 + /* 8-byte block ciphers */
12.167 + case CSSM_ALGID_DES:
12.168 + case CSSM_ALGID_3DES_3KEY_EDE:
12.169 + case CSSM_ALGID_RC5:
12.170 + case CSSM_ALGID_RC2:
12.171 + return CSSM_PADDING_PKCS5; break;
12.172 + /* 16-byte block ciphers */
12.173 + case CSSM_ALGID_AES:
12.174 + return CSSM_PADDING_PKCS7; break;
12.175 + /* stream ciphers */
12.176 + case CSSM_ALGID_ASC:
12.177 + case CSSM_ALGID_RC4:
12.178 + return CSSM_PADDING_NONE; break;
12.179 + /* RSA/DSA asymmetric */
12.180 + case CSSM_ALGID_DSA:
12.181 + case CSSM_ALGID_RSA:
12.182 + return CSSM_PADDING_PKCS1; break;
12.183 + /* Unknown */
12.184 + default:
12.185 + Warn(@"Asked for the default padding mode for %d, but don't know that algorithm.\n", algorithm);
12.186 + return CSSM_PADDING_NONE;
12.187 + }
12.188 +}
12.189 +#endif
12.190 +
12.191 +#pragma mark -
12.192 +// Code below was copied from SecImportExportUtils.cpp in Apple's libsecurity_keychain project
12.193 +
12.194 +
12.195 /*
12.196 * Given a context specified via a CSSM_CC_HANDLE, add a new
12.197 * CSSM_CONTEXT_ATTRIBUTE to the context as specified by AttributeType,