Implemented wrap/unwrap of session key using a key-pair.
authorsnej@snej.local
Sun Apr 19 00:01:41 2009 -0700 (2009-04-19)
changeset 136fd9177eb6da
parent 12 e4c971be4079
child 14 3af1d1c0ceb5
Implemented wrap/unwrap of session key using a key-pair.
MYCrypto.xcodeproj/project.pbxproj
MYCryptoTest.m
MYCrypto_Private.h
MYKey.h
MYKey.m
MYKeychainItem.m
MYPrivateKey.h
MYPrivateKey.m
MYPublicKey.h
MYPublicKey.m
MYSymmetricKey.h
MYSymmetricKey.m
     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,