MYSymmetricKey.m
author Jens Alfke <jens@mooseyard.com>
Tue Jun 02 13:16:28 2009 -0700 (2009-06-02)
changeset 16 c409dbc4f068
parent 14 3af1d1c0ceb5
child 23 39fec79de6e8
permissions -rw-r--r--
* Added ASN.1 / BER / DER utilities, to be used in generating and parsing X.509 certs.
* Added Keychain user-interaction-allowed setter. Added doc comments to MYSymmetricKey.
     1 //
     2 //  MYSymmetricKey.m
     3 //  MYCrypto
     4 //
     5 //  Created by Jens Alfke on 4/2/09.
     6 //  Copyright 2009 Jens Alfke. All rights reserved.
     7 //
     8 
     9 #import "MYSymmetricKey.h"
    10 #import "MYCryptor.h"
    11 #import "MYCrypto_Private.h"
    12 
    13 #if !MYCRYPTO_USE_IPHONE_API
    14 
    15 #import <Security/cssmtype.h>
    16 
    17 
    18 CSSM_ALGORITHMS CSSMFromCCAlgorithm( CCAlgorithm ccAlgorithm ) {
    19     static const CSSM_ALGORITHMS kCSSMAlgorithms[] = {
    20         CSSM_ALGID_AES, CSSM_ALGID_DES, CSSM_ALGID_3DES_3KEY, CSSM_ALGID_CAST, CSSM_ALGID_RC4
    21     };
    22     if (ccAlgorithm >=0 && ccAlgorithm <= kCCAlgorithmRC4)
    23         return kCSSMAlgorithms[ccAlgorithm];
    24     else
    25         return CSSM_ALGID_NONE;
    26 }
    27 
    28 static const char *kCCAlgorithmNames[] = {"AES", "DES", "DES^3", "CAST", "RC4"};
    29 
    30 
    31 /** Undocumented Security function. Unfortunately this is the only way I can find to create
    32     a SecKeyRef from a CSSM_KEY. */
    33 extern OSStatus SecKeyCreate(const CSSM_KEY *key, SecKeyRef* keyRef) WEAK_IMPORT_ATTRIBUTE;
    34 
    35 static CSSM_KEY* cssmKeyFromData( NSData *keyData, CSSM_ALGORITHMS algorithm,
    36                                  MYKeychain *keychain);
    37 
    38 #if !TARGET_OS_IPHONE
    39 static CSSM_KEY* unwrapCssmKeyFromData(NSData *wrappedData,
    40                                        CSSM_ALGORITHMS algorithm,
    41                                        unsigned sizeInBits);
    42 static CSSM_ENCRYPT_MODE defaultModeForAlgorithm(CSSM_ALGORITHMS algorithm);
    43 static CSSM_PADDING defaultPaddingForAlgorithm(CSSM_ALGORITHMS algorithm);
    44 #endif
    45 
    46 static CSSM_DATA makeSalt( id salty, size_t length );
    47 static CSSM_RETURN impExpCreatePassKey(
    48 	const SecKeyImportExportParameters *keyParams,  // required
    49 	CSSM_CSP_HANDLE		cspHand,		// MUST be CSPDL
    50 	BOOL                verifyPhrase,   // use 2nd passphrase textfield for verification?
    51 	CSSM_KEY_PTR		*passKey);	// mallocd and RETURNED
    52 
    53 
    54 #pragma mark -
    55 @implementation MYSymmetricKey
    56 
    57 
    58 - (id) _initWithCSSMKey: (CSSM_KEY*)cssmKey {
    59     if (!cssmKey) {
    60         [self release];
    61         return nil;
    62     }
    63     SecKeyRef keyRef = NULL;
    64     if (SecKeyCreate == NULL) {
    65         // If weak-linked SPI fn no longer exists
    66         Warn(@"Unable to call SecKeyCreate SPI -- not available");
    67         [self release];
    68         return nil;
    69     }
    70     if (!check(SecKeyCreate(cssmKey,&keyRef), @"SecKeyCreate")) {
    71         [self release];
    72         return nil;
    73     }
    74     self = [self initWithKeyRef: keyRef];
    75     if (self) {
    76         _ownedCSSMKey = cssmKey;            // (so I'll remember to free it)
    77     }
    78     return self;
    79 }
    80 
    81 
    82 - (id) _initWithKeyData: (NSData*)keyData
    83               algorithm: (CCAlgorithm)algorithm
    84              inKeychain: (MYKeychain*)keychain
    85 {
    86     Assert(algorithm <= kCCAlgorithmRC4);
    87     Assert(keyData);
    88     CSSM_KEY *key = cssmKeyFromData(keyData, CSSMFromCCAlgorithm(algorithm), keychain);
    89     return [self _initWithCSSMKey: key];
    90 }
    91 
    92 - (id) initWithKeyData: (NSData*)keyData
    93              algorithm: (CCAlgorithm)algorithm
    94 {
    95     return [self _initWithKeyData: keyData algorithm: algorithm inKeychain: nil];
    96 }
    97 
    98 + (MYSymmetricKey*) _generateSymmetricKeyOfSize: (unsigned)keySizeInBits
    99                                       algorithm: (CCAlgorithm)algorithm
   100                                      inKeychain: (MYKeychain*)keychain
   101 {
   102     Assert(algorithm <= kCCAlgorithmRC4);
   103     CSSM_KEYATTR_FLAGS flags = CSSM_KEYATTR_EXTRACTABLE;
   104     if (keychain)
   105         flags |= CSSM_KEYATTR_PERMANENT; // | CSSM_KEYATTR_SENSITIVE;   //FIX: Re-enable this bit
   106     else {
   107         flags |= CSSM_KEYATTR_RETURN_REF;
   108         keychain = [MYKeychain defaultKeychain]; // establish a context for the key
   109     }
   110     CSSM_KEYUSE usage = CSSM_KEYUSE_ANY;
   111     SecKeyRef keyRef = NULL;
   112     if (!check(SecKeyGenerate(keychain.keychainRefOrDefault,
   113                               CSSMFromCCAlgorithm(algorithm),
   114                               keySizeInBits, 
   115                               0, usage, flags, NULL, &keyRef),
   116                @"SecKeyGenerate")) {
   117         return nil;
   118     }
   119     return [[[self alloc] initWithKeyRef: keyRef] autorelease];
   120 }
   121 
   122 + (MYSymmetricKey*) generateSymmetricKeyOfSize: (unsigned)keySizeInBits
   123                                      algorithm: (CCAlgorithm)algorithm {
   124     return [self _generateSymmetricKeyOfSize: keySizeInBits
   125                                    algorithm: algorithm
   126                                   inKeychain: nil];
   127 }
   128 
   129 + (NSString*) promptForPassphraseWithAlertTitle: (NSString*)alertTitle
   130                                     alertPrompt: (NSString*)prompt
   131                                         creating: (BOOL)creating
   132 {
   133     // Ask the user for a passphrase:
   134     SecKeyImportExportParameters params = {
   135         .version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION,
   136         .flags = kSecKeySecurePassphrase,
   137         .alertTitle = (CFStringRef)alertTitle,
   138         .alertPrompt = (CFStringRef)prompt,
   139         .keyUsage = CSSM_KEYUSE_ANY,
   140         .keyAttributes = CSSM_KEYATTR_EXTRACTABLE
   141     };
   142     CSSM_CSP_HANDLE cspHandle = [[MYKeychain defaultKeychain] CSPHandle];
   143     CSSM_KEY *passphraseKey = NULL;
   144     if (impExpCreatePassKey(&params, 
   145                             cspHandle, 
   146                             creating,
   147                             &passphraseKey) != CSSM_OK)
   148         return nil;
   149     
   150     MYSymmetricKey *key = [[self alloc] _initWithCSSMKey: passphraseKey];
   151     NSData *keyData = key.keyData;
   152     Assert(keyData);
   153     NSString *passphrase = [[NSString alloc] initWithData: keyData
   154                                                  encoding: NSUTF8StringEncoding];
   155     [key release];
   156     return [passphrase autorelease];
   157 }
   158 
   159 
   160 #define PKCS5_V2_SALT_LEN		8
   161 #define PKCS5_V2_ITERATIONS		2048
   162 #define PKCS5_V2_DES_IV_SIZE	8
   163 
   164 + (MYSymmetricKey*) generateFromUserPassphraseWithAlertTitle: (NSString*)alertTitle
   165                                                  alertPrompt: (NSString*)prompt
   166                                                      creating: (BOOL)creating
   167                                                         salt: (id)saltObj
   168 {
   169     MYSymmetricKey *generatedKey = nil;
   170 
   171     // Ask the user for a passphrase:
   172     SecKeyImportExportParameters params = {
   173         .version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION,
   174         .flags = kSecKeySecurePassphrase,
   175         .alertTitle = (CFStringRef)alertTitle,
   176         .alertPrompt = (CFStringRef)prompt,
   177         .keyUsage = CSSM_KEYUSE_ANY,
   178         .keyAttributes = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_SENSITIVE
   179     };
   180     CSSM_CSP_HANDLE cspHandle = [[MYKeychain defaultKeychain] CSPHandle];
   181     CSSM_KEY *passphraseKey = NULL;
   182     if (impExpCreatePassKey(&params, 
   183                             cspHandle, 
   184                             creating,
   185                             &passphraseKey) != CSSM_OK)
   186         return nil;
   187 
   188     CSSM_DATA saltData = makeSalt(saltObj,PKCS5_V2_SALT_LEN);
   189     CSSM_CRYPTO_DATA seed = {};
   190     
   191     // Now use the secure passphrase to generate a symmetric key:
   192     CSSM_CC_HANDLE ctx = 0;
   193     CSSM_ACCESS_CREDENTIALS credentials = {};
   194     if (checkcssm(CSSM_CSP_CreateDeriveKeyContext(cspHandle,
   195                                                   CSSM_ALGID_PKCS5_PBKDF2,
   196                                                   CSSM_ALGID_AES, 128,
   197                                                   &credentials,
   198                                                   passphraseKey, 
   199                                                   PKCS5_V2_ITERATIONS,
   200                                                   &saltData,
   201                                                   &seed,
   202                                                   &ctx),
   203                   @"CSSM_CSP_CreateDeriveKeyContext")) {
   204         CSSM_PKCS5_PBKDF2_PARAMS params = {.PseudoRandomFunction=CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1};
   205         CSSM_DATA paramData = {.Data=(void*)&params, .Length=sizeof(params)};
   206         CSSM_KEY *cssmKey = calloc(1,sizeof(CSSM_KEY));
   207         if (checkcssm(CSSM_DeriveKey(ctx,
   208                                      &paramData,
   209                                      CSSM_KEYUSE_ANY,
   210                                      CSSM_KEYATTR_EXTRACTABLE, //| CSSM_KEYATTR_SENSITIVE, 
   211                                      NULL, 
   212                                      NULL, 
   213                                      cssmKey),
   214                       @"CSSM_DeriveKey")) {
   215             generatedKey = [[[self alloc] _initWithCSSMKey: cssmKey] autorelease];
   216         }
   217     }
   218     CSSM_DeleteContext(ctx);
   219     CSSM_FreeKey(cspHandle, &credentials, passphraseKey, YES);
   220     return generatedKey;        
   221 }
   222 
   223 
   224 - (void) dealloc
   225 {
   226     if(_ownedCSSMKey) 
   227         CSSM_FreeKey(self.cssmCSPHandle, NULL, _ownedCSSMKey, YES);
   228     [super dealloc];
   229 }
   230 
   231 
   232 #if !TARGET_OS_IPHONE
   233 - (id) initWithWrappedKeyData: (NSData*)wrappedKeyData {
   234     return [self _initWithCSSMKey: unwrapCssmKeyFromData(wrappedKeyData,
   235                                                          CSSM_ALGID_AES,128)];
   236 }
   237 
   238 
   239 - (NSData*) exportWrappedKeyWithPassphrasePrompt: (NSString*)prompt
   240 {
   241     // Prompt user for a passphrase to use for the wrapping key:
   242     MYSymmetricKey *wrappingKey = [MYSymmetricKey 
   243                                    generateFromUserPassphraseWithAlertTitle: @"Export Key" 
   244                                    alertPrompt: prompt 
   245                                    creating: YES
   246                                    salt: [MYCryptor randomKeyOfLength: PKCS5_V2_SALT_LEN*8]];
   247     if (!wrappingKey)
   248         return nil;
   249     Log(@"Wrapping using %@",wrappingKey);
   250     
   251     // Create the context:
   252     CSSM_ACCESS_CREDENTIALS credentials = {};
   253     CSSM_CSP_HANDLE cspHandle = self.cssmCSPHandle;
   254     CSSM_ALGORITHMS algorithm = wrappingKey.cssmAlgorithm;
   255     uint8 iv[16] = {0}; // Right size for AES. Are zeros OK? //FIX: Support other algorithms
   256     CSSM_DATA ivData = {.Data=(void*)&iv, .Length=sizeof(iv)};
   257     CSSM_CC_HANDLE ctx;
   258     if (!checkcssm(CSSM_CSP_CreateSymmetricContext(cspHandle,
   259                                                    algorithm, //CSSM_ALGID_3DES_3KEY_EDE
   260                                                    defaultModeForAlgorithm(algorithm),
   261                                                    &credentials, 
   262                                                    wrappingKey.cssmKey,
   263                                                    &ivData,
   264                                                    defaultPaddingForAlgorithm(algorithm),
   265                                                    NULL,
   266                                                    &ctx), 
   267                    @"CSSM_CSP_CreateSymmetricContext"))
   268         return nil;
   269     
   270     // Now wrap the key:
   271     NSData *result = nil;
   272     CSSM_WRAP_KEY wrappedKey = {};
   273     if (checkcssm(CSSM_WrapKey(ctx, &credentials, self.cssmKey, NULL, &wrappedKey),
   274                   @"CSSM_WrapKey")) {
   275         // ...and copy the wrapped key data to the result NSData:
   276         result = [NSData dataWithBytes: wrappedKey.KeyData.Data length: wrappedKey.KeyData.Length];
   277         CSSM_FreeKey(cspHandle, &credentials, &wrappedKey, NO);
   278     }
   279     // Finally, delete the context
   280     CSSM_DeleteContext(ctx);
   281     return result;
   282 }
   283 #endif
   284 
   285 
   286 - (SecExternalItemType) keyType {
   287     return kSecItemTypeSessionKey;
   288 }
   289 
   290 - (CCAlgorithm) algorithm {
   291     CSSM_ALGORITHMS cssmAlg;
   292     cssmAlg = self.cssmKey->KeyHeader.AlgorithmId;
   293     switch(cssmAlg) {
   294         case CSSM_ALGID_AES:
   295             return kCCAlgorithmAES128;
   296         case CSSM_ALGID_DES:
   297             return kCCAlgorithmDES;	
   298         case CSSM_ALGID_3DES_3KEY:
   299             return kCCAlgorithm3DES;
   300         case CSSM_ALGID_CAST:
   301             return kCCAlgorithmCAST;
   302         case CSSM_ALGID_RC4:
   303             return kCCAlgorithmRC4;	
   304         default:
   305             Warn(@"CSSM_ALGORITHMS #%u doesn't map to any CCAlgorithm", cssmAlg);
   306             return (CCAlgorithm)-1;
   307     }
   308 }
   309 
   310 - (const char*) algorithmName {
   311     CCAlgorithm a = self.algorithm;
   312     if (a >= 0 && a <= kCCAlgorithmRC4)
   313         return kCCAlgorithmNames[a];
   314     else
   315         return "???";
   316 }
   317 
   318 - (unsigned) keySizeInBits {
   319     const CSSM_KEY *key = self.cssmKey;
   320     Assert(key);
   321     return key->KeyHeader.LogicalKeySizeInBits;
   322 }
   323 
   324 
   325 - (NSString*) description {
   326     return $sprintf(@"%@[%u-bit %s]", [self class], self.keySizeInBits, self.algorithmName);
   327 }
   328 
   329 
   330 - (NSData*) _cryptData: (NSData*)data operation: (CCOperation)op options: (CCOptions)options
   331 {
   332     NSData *keyData = self.keyData;
   333     Assert(keyData, @"Couldn't get key data");
   334     NSMutableData *output = [NSMutableData dataWithLength: data.length + 256];
   335     size_t bytesWritten = 0;
   336     CCCryptorStatus status = CCCrypt(op, self.algorithm, options, 
   337                                      keyData.bytes, keyData.length, NULL,
   338                                      data.bytes, data.length, output.mutableBytes, output.length,
   339                                      &bytesWritten);
   340     if (status) {
   341         Warn(@"MYSymmetricKey: CCCrypt returned error %i",status);
   342         return nil;
   343     }
   344     output.length = bytesWritten;
   345     return output;
   346 }
   347 
   348 - (NSData*) encryptData: (NSData*)data {
   349     return [self _cryptData: data operation: kCCEncrypt options: kCCOptionPKCS7Padding];
   350 }
   351 
   352 
   353 - (NSData*) decryptData: (NSData*)data {
   354     return [self _cryptData: data operation: kCCDecrypt options: kCCOptionPKCS7Padding];
   355 }
   356 
   357 
   358 @end
   359 
   360 
   361 #pragma mark -
   362 
   363 
   364 static CSSM_KEY* cssmKeyFromData( NSData *keyData, 
   365                                  CSSM_ALGORITHMS algorithm,
   366                                  MYKeychain *keychain ) {
   367     // Thanks to Jim Murphy for showing the way!
   368     if (!keychain) keychain = [MYKeychain defaultKeychain];
   369     CSSM_CC_HANDLE ccHandle;
   370     if (!checkcssm(CSSM_CSP_CreateSymmetricContext([keychain CSPHandle],
   371                                                    CSSM_ALGID_NONE, CSSM_ALGMODE_WRAP,
   372                                                    NULL, NULL, NULL,
   373                                                    CSSM_PADDING_NONE, NULL,
   374                                                    &ccHandle), 
   375                    @"CSSM_CSP_CreateSymmetricContext"))
   376         return NO;
   377     
   378     CSSM_KEY wrappedKey = {
   379         .KeyHeader = {
   380             .BlobType = CSSM_KEYBLOB_RAW,
   381             .Format = CSSM_KEYBLOB_RAW_FORMAT_NONE,
   382             .AlgorithmId = algorithm,
   383             .KeyClass = CSSM_KEYCLASS_SESSION_KEY,
   384             .LogicalKeySizeInBits = keyData.length*8,
   385             .KeyAttr = CSSM_KEYATTR_EXTRACTABLE,
   386             .KeyUsage = CSSM_KEYUSE_ANY
   387         },
   388         .KeyData = {
   389             .Data = (void*)keyData.bytes,
   390             .Length = keyData.length
   391         }
   392     };
   393     
   394     CSSM_KEY *outKey = calloc(sizeof(CSSM_KEY),1);
   395     CSSM_DATA desc = {};
   396     if (!checkcssm(CSSM_UnwrapKey(ccHandle,
   397                                   NULL,
   398                                   &wrappedKey,
   399                                   CSSM_KEYUSE_ANY,
   400                                   CSSM_KEYATTR_EXTRACTABLE,
   401                                   NULL,
   402                                   NULL,
   403                                   outKey,
   404                                   &desc),
   405                    @"CSSM_UnwrapKey")) {
   406         free(outKey);
   407         outKey = NULL;
   408     }
   409     CSSM_DeleteContext(ccHandle);
   410     return outKey;
   411 }
   412 
   413 
   414 #if !TARGET_OS_IPHONE
   415 static CSSM_KEY* unwrapCssmKeyFromData(NSData *wrappedData,
   416                                        CSSM_ALGORITHMS algorithm,
   417                                        unsigned sizeInBits) {
   418     Warn(@"MYSymmetricKey: unwrapping is unimplemented; sorry");
   419     return nil;
   420 #if 0 //not finished yet
   421     // First create a wrapped-key structure from the data:
   422     CSSM_WRAP_KEY wrappedKey = {
   423         .KeyHeader = {
   424             .BlobType = CSSM_KEYBLOB_WRAPPED,
   425             .Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS3,
   426             .AlgorithmId = algorithm,
   427             .KeyClass = CSSM_KEYCLASS_SESSION_KEY,
   428             .LogicalKeySizeInBits = sizeInBits,
   429             .KeyAttr = CSSM_KEYATTR_EXTRACTABLE,
   430             .KeyUsage = CSSM_KEYUSE_ANY,
   431             .WrapAlgorithmId = CSSM_ALGID_AES,
   432         },
   433         .KeyData = {
   434             .Data = (void*)wrappedData.bytes,
   435             .Length = wrappedData.length
   436         }
   437     };
   438 #endif
   439 }    
   440 #endif
   441 
   442 
   443 // Create salt data of a specific length from an arbitrary NSObject. */
   444 static CSSM_DATA makeSalt( id salty, size_t length ) {
   445     // Convert to NSData if necessary:
   446     CAssert(salty!=nil);
   447     if (![salty isKindOfClass: [NSData class]])
   448         salty = [[salty description] dataUsingEncoding: NSUTF8StringEncoding];
   449     // Repeat enough times to fill the desired length:
   450     NSMutableData *salt = [[salty mutableCopy] autorelease];
   451     CAssert(salt.length>0);
   452     while (salt.length < length) {
   453         [salt appendData: salt];
   454     }
   455     // Truncate to length and return it:
   456     salt.length = length;
   457     return (CSSM_DATA){.Data=(void*)salt.bytes, .Length=salt.length};
   458 }
   459 
   460 
   461 #pragma mark -
   462 // Code from Keychain.framework:
   463 
   464 #if !TARGET_OS_IPHONE
   465 #if 1
   466 static CSSM_ENCRYPT_MODE defaultModeForAlgorithm(CSSM_ALGORITHMS algorithm) {
   467     switch(algorithm) {
   468         // 8-byte block ciphers
   469         case CSSM_ALGID_DES:
   470         case CSSM_ALGID_3DES_3KEY_EDE:
   471         case CSSM_ALGID_RC5:
   472         case CSSM_ALGID_RC2:
   473             return CSSM_ALGMODE_CBCPadIV8; break;
   474         // 16-byte block ciphers
   475         case CSSM_ALGID_AES:
   476             return CSSM_ALGMODE_CBCPadIV8; break;
   477         // stream ciphers
   478         case CSSM_ALGID_ASC:
   479         case CSSM_ALGID_RC4:
   480             return CSSM_ALGMODE_NONE; break;
   481         // Unknown
   482         default:
   483         	Warn(@"Asked for the default mode for algorithm %d, but don't know that algorithm.\n", algorithm);
   484             return CSSM_ALGMODE_NONE;
   485     }
   486 }
   487 #endif
   488 
   489 #if 1
   490 static CSSM_PADDING defaultPaddingForAlgorithm(CSSM_ALGORITHMS algorithm) {
   491     switch(algorithm) {
   492         /* 8-byte block ciphers */
   493         case CSSM_ALGID_DES:
   494         case CSSM_ALGID_3DES_3KEY_EDE:
   495         case CSSM_ALGID_RC5:
   496         case CSSM_ALGID_RC2:
   497             return CSSM_PADDING_PKCS5; break;
   498             /* 16-byte block ciphers */
   499         case CSSM_ALGID_AES:
   500             return CSSM_PADDING_PKCS7; break;
   501             /* stream ciphers */
   502         case CSSM_ALGID_ASC:
   503         case CSSM_ALGID_RC4:
   504             return CSSM_PADDING_NONE; break;
   505             /* RSA/DSA asymmetric */
   506         case CSSM_ALGID_DSA:
   507         case CSSM_ALGID_RSA:
   508             return CSSM_PADDING_PKCS1; break;
   509             /* Unknown */
   510         default:
   511         	Warn(@"Asked for the default padding mode for %d, but don't know that algorithm.\n", algorithm);
   512             return CSSM_PADDING_NONE;
   513     }
   514 }
   515 #endif
   516 #endif
   517 
   518 #pragma mark -
   519 // Code below was copied from SecImportExportUtils.cpp in Apple's libsecurity_keychain project
   520 
   521 
   522 /*
   523  * Given a context specified via a CSSM_CC_HANDLE, add a new
   524  * CSSM_CONTEXT_ATTRIBUTE to the context as specified by AttributeType,
   525  * AttributeLength, and an untyped pointer.
   526  */
   527 static CSSM_RETURN impExpAddContextAttribute(CSSM_CC_HANDLE CCHandle,
   528 	uint32 AttributeType,
   529 	uint32 AttributeLength,
   530 	const void *AttributePtr)
   531 {
   532 	CSSM_CONTEXT_ATTRIBUTE		newAttr;	
   533 	
   534 	newAttr.AttributeType     = AttributeType;
   535 	newAttr.AttributeLength   = AttributeLength;
   536 	newAttr.Attribute.Data    = (CSSM_DATA_PTR)AttributePtr;
   537 	return CSSM_UpdateContextAttributes(CCHandle, 1, &newAttr);
   538 }
   539 
   540 /* 
   541 * Add a CFString to a crypto context handle. 
   542 */
   543 static CSSM_RETURN impExpAddStringAttr(
   544 	CSSM_CC_HANDLE ccHand, 
   545 	CFStringRef str,
   546 	CSSM_ATTRIBUTE_TYPE attrType)
   547 {
   548 	/* CFStrings are passed as external rep in UTF8 encoding by convention */
   549 	CFDataRef outData;
   550 	outData = CFStringCreateExternalRepresentation(NULL,
   551 		str, kCFStringEncodingUTF8,	0);		// lossByte 0 ==> no loss allowed 
   552 	if(outData == NULL) {
   553 		Warn(@"impExpAddStringAttr: bad string format");
   554 		return paramErr;
   555 	}
   556 	
   557 	CSSM_DATA attrData;
   558 	attrData.Data = (uint8 *)CFDataGetBytePtr(outData);
   559 	attrData.Length = CFDataGetLength(outData);
   560 	CSSM_RETURN crtn = impExpAddContextAttribute(ccHand, attrType, sizeof(CSSM_DATA),
   561 		&attrData);
   562 	CFRelease(outData);
   563 	if(crtn) {
   564 		Warn(@"impExpAddStringAttr: CSSM_UpdateContextAttributes error");
   565 	}
   566 	return crtn;
   567 }
   568 
   569 /*
   570  * Generate a secure passphrase key. Caller must eventually CSSM_FreeKey the result. 
   571  */
   572 static CSSM_RETURN impExpCreatePassKey(
   573 	const SecKeyImportExportParameters *keyParams,  // required
   574 	CSSM_CSP_HANDLE		cspHand,		// MUST be CSPDL
   575 	BOOL                verifyPhrase,   // use 2nd passphrase textfield for verification?
   576 	CSSM_KEY_PTR		*passKey)		// mallocd and RETURNED
   577 {
   578 	CSSM_RETURN crtn;
   579 	CSSM_CC_HANDLE ccHand;
   580 	uint32 verifyAttr;
   581 	CSSM_DATA dummyLabel;
   582 	CSSM_KEY_PTR ourKey = NULL;
   583 	
   584 	Log(@"Generating secure passphrase key");
   585 	ourKey = (CSSM_KEY_PTR)malloc(sizeof(CSSM_KEY));
   586 	if(ourKey == NULL) {
   587 		return memFullErr;
   588 	}
   589 	memset(ourKey, 0, sizeof(CSSM_KEY));
   590 	
   591 	crtn = CSSM_CSP_CreateKeyGenContext(cspHand,
   592 		CSSM_ALGID_SECURE_PASSPHRASE,
   593 		4,				// keySizeInBits must be non zero
   594 		NULL,			// Seed
   595 		NULL,			// Salt
   596 		NULL,			// StartDate
   597 		NULL,			// EndDate
   598 		NULL,			// Params
   599 		&ccHand);
   600 	if(crtn) {
   601 		checkcssm(crtn,@"CSSM_CSP_CreateKeyGenContext");
   602 		return crtn;
   603 	}
   604 	/* subsequent errors to errOut: */
   605 	
   606 	/* additional context attributes specific to this type of key gen */
   607 	CAssert(keyParams != NULL);			// or we wouldn't be here
   608 	if(keyParams->alertTitle != NULL) {
   609 		crtn = impExpAddStringAttr(ccHand, keyParams->alertTitle, 
   610 			CSSM_ATTRIBUTE_ALERT_TITLE);
   611 		if(crtn) {
   612 			goto errOut;
   613 		}
   614 	}
   615 	if(keyParams->alertPrompt != NULL) {
   616 		crtn = impExpAddStringAttr(ccHand, keyParams->alertPrompt, 
   617 			CSSM_ATTRIBUTE_PROMPT);
   618 		if(crtn) {
   619 			goto errOut;
   620 		}
   621 	}
   622 	verifyAttr = verifyPhrase ? 1 : 0;
   623 	crtn = impExpAddContextAttribute(ccHand, CSSM_ATTRIBUTE_VERIFY_PASSPHRASE,
   624 		sizeof(uint32), (const void *)verifyAttr);
   625 	if(crtn) {
   626 		checkcssm(crtn,@"impExpAddContextAttribute");
   627 		goto errOut;
   628 	}
   629 
   630 	dummyLabel.Data = (uint8 *)"Secure Passphrase";
   631 	dummyLabel.Length = strlen((char *)dummyLabel.Data);
   632     
   633     uint32 keyAttr = keyParams->keyAttributes;
   634     if (keyAttr & CSSM_KEYATTR_SENSITIVE)
   635         keyAttr |= CSSM_KEYATTR_RETURN_REF;
   636     else
   637         keyAttr |= CSSM_KEYATTR_EXTRACTABLE;
   638 
   639 	crtn = CSSM_GenerateKey(ccHand,
   640         keyParams->keyUsage ?: CSSM_KEYUSE_ANY,
   641 		keyAttr,
   642 		&dummyLabel,
   643 		NULL,			// ACL
   644 		ourKey);
   645 	if(crtn) {
   646 		checkcssm(crtn,@"CSSM_GenerateKey");
   647 	}
   648 errOut:
   649 	CSSM_DeleteContext(ccHand);
   650 	if(crtn == CSSM_OK) {
   651 		*passKey = ourKey;
   652 	}
   653 	else if(ourKey != NULL) {
   654 		free(ourKey);
   655 	}
   656 	return crtn;
   657 }
   658 	
   659 
   660 #endif !MYCRYPTO_USE_IPHONE_API
   661 
   662 
   663 
   664 /*
   665  Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
   666  
   667  Redistribution and use in source and binary forms, with or without modification, are permitted
   668  provided that the following conditions are met:
   669  
   670  * Redistributions of source code must retain the above copyright notice, this list of conditions
   671  and the following disclaimer.
   672  * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
   673  and the following disclaimer in the documentation and/or other materials provided with the
   674  distribution.
   675  
   676  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   677  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   678  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   679  BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   680  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   681   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   682  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   683  THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   684  */