snej@0: // snej@0: // MYSymmetricKey.m snej@0: // MYCrypto snej@0: // snej@0: // Created by Jens Alfke on 4/2/09. snej@0: // Copyright 2009 Jens Alfke. All rights reserved. snej@0: // snej@0: snej@0: #import "MYSymmetricKey.h" snej@0: #import "MYCryptor.h" snej@0: #import "MYCrypto_Private.h" snej@0: snej@12: #if !MYCRYPTO_USE_IPHONE_API snej@0: snej@0: #import snej@12: snej@0: snej@13: CSSM_ALGORITHMS CSSMFromCCAlgorithm( CCAlgorithm ccAlgorithm ) { snej@13: static const CSSM_ALGORITHMS kCSSMAlgorithms[] = { snej@13: CSSM_ALGID_AES, CSSM_ALGID_DES, CSSM_ALGID_3DES_3KEY, CSSM_ALGID_CAST, CSSM_ALGID_RC4 snej@13: }; snej@13: if (ccAlgorithm >=0 && ccAlgorithm <= kCCAlgorithmRC4) snej@13: return kCSSMAlgorithms[ccAlgorithm]; snej@13: else snej@13: return CSSM_ALGID_NONE; snej@13: } snej@0: snej@2: static const char *kCCAlgorithmNames[] = {"AES", "DES", "DES^3", "CAST", "RC4"}; snej@2: snej@0: snej@12: /** Undocumented Security function. Unfortunately this is the only way I can find to create snej@12: a SecKeyRef from a CSSM_KEY. */ snej@12: extern OSStatus SecKeyCreate(const CSSM_KEY *key, SecKeyRef* keyRef) WEAK_IMPORT_ATTRIBUTE; snej@12: snej@12: static CSSM_KEY* cssmKeyFromData( NSData *keyData, CSSM_ALGORITHMS algorithm, snej@12: MYKeychain *keychain); jens@16: jens@16: #if !TARGET_OS_IPHONE jens@16: static CSSM_KEY* unwrapCssmKeyFromData(NSData *wrappedData, jens@16: CSSM_ALGORITHMS algorithm, jens@16: unsigned sizeInBits); jens@16: static CSSM_ENCRYPT_MODE defaultModeForAlgorithm(CSSM_ALGORITHMS algorithm); jens@16: static CSSM_PADDING defaultPaddingForAlgorithm(CSSM_ALGORITHMS algorithm); jens@16: #endif jens@16: snej@12: static CSSM_DATA makeSalt( id salty, size_t length ); snej@12: static CSSM_RETURN impExpCreatePassKey( snej@12: const SecKeyImportExportParameters *keyParams, // required snej@12: CSSM_CSP_HANDLE cspHand, // MUST be CSPDL snej@12: BOOL verifyPhrase, // use 2nd passphrase textfield for verification? snej@12: CSSM_KEY_PTR *passKey); // mallocd and RETURNED snej@12: snej@12: snej@0: #pragma mark - snej@0: @implementation MYSymmetricKey snej@0: snej@0: snej@12: - (id) _initWithCSSMKey: (CSSM_KEY*)cssmKey { jens@16: if (!cssmKey) { jens@16: [self release]; jens@16: return nil; jens@16: } snej@12: SecKeyRef keyRef = NULL; snej@12: if (SecKeyCreate == NULL) { snej@12: // If weak-linked SPI fn no longer exists snej@12: Warn(@"Unable to call SecKeyCreate SPI -- not available"); snej@12: [self release]; snej@12: return nil; snej@12: } snej@12: if (!check(SecKeyCreate(cssmKey,&keyRef), @"SecKeyCreate")) { snej@12: [self release]; snej@12: return nil; snej@12: } snej@12: self = [self initWithKeyRef: keyRef]; snej@12: if (self) { snej@12: _ownedCSSMKey = cssmKey; // (so I'll remember to free it) snej@12: } snej@12: return self; snej@12: } snej@12: snej@12: snej@1: - (id) _initWithKeyData: (NSData*)keyData snej@1: algorithm: (CCAlgorithm)algorithm snej@1: inKeychain: (MYKeychain*)keychain snej@1: { snej@1: Assert(algorithm <= kCCAlgorithmRC4); snej@1: Assert(keyData); snej@13: CSSM_KEY *key = cssmKeyFromData(keyData, CSSMFromCCAlgorithm(algorithm), keychain); snej@12: return [self _initWithCSSMKey: key]; snej@1: } snej@1: snej@1: - (id) initWithKeyData: (NSData*)keyData snej@1: algorithm: (CCAlgorithm)algorithm snej@1: { snej@1: return [self _initWithKeyData: keyData algorithm: algorithm inKeychain: nil]; snej@1: } snej@1: snej@0: + (MYSymmetricKey*) _generateSymmetricKeyOfSize: (unsigned)keySizeInBits snej@0: algorithm: (CCAlgorithm)algorithm snej@0: inKeychain: (MYKeychain*)keychain snej@0: { snej@0: Assert(algorithm <= kCCAlgorithmRC4); snej@0: CSSM_KEYATTR_FLAGS flags = CSSM_KEYATTR_EXTRACTABLE; snej@0: if (keychain) snej@13: flags |= CSSM_KEYATTR_PERMANENT; // | CSSM_KEYATTR_SENSITIVE; //FIX: Re-enable this bit snej@13: else { snej@13: flags |= CSSM_KEYATTR_RETURN_REF; snej@13: keychain = [MYKeychain defaultKeychain]; // establish a context for the key snej@13: } snej@0: CSSM_KEYUSE usage = CSSM_KEYUSE_ANY; snej@1: SecKeyRef keyRef = NULL; snej@13: if (!check(SecKeyGenerate(keychain.keychainRefOrDefault, snej@13: CSSMFromCCAlgorithm(algorithm), snej@0: keySizeInBits, snej@0: 0, usage, flags, NULL, &keyRef), snej@0: @"SecKeyGenerate")) { snej@0: return nil; snej@0: } snej@1: return [[[self alloc] initWithKeyRef: keyRef] autorelease]; snej@0: } snej@0: snej@0: + (MYSymmetricKey*) generateSymmetricKeyOfSize: (unsigned)keySizeInBits snej@0: algorithm: (CCAlgorithm)algorithm { snej@0: return [self _generateSymmetricKeyOfSize: keySizeInBits snej@0: algorithm: algorithm snej@0: inKeychain: nil]; snej@0: } snej@0: snej@12: + (NSString*) promptForPassphraseWithAlertTitle: (NSString*)alertTitle snej@12: alertPrompt: (NSString*)prompt snej@12: creating: (BOOL)creating snej@12: { snej@12: // Ask the user for a passphrase: snej@12: SecKeyImportExportParameters params = { snej@12: .version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION, snej@12: .flags = kSecKeySecurePassphrase, snej@12: .alertTitle = (CFStringRef)alertTitle, snej@12: .alertPrompt = (CFStringRef)prompt, snej@12: .keyUsage = CSSM_KEYUSE_ANY, snej@12: .keyAttributes = CSSM_KEYATTR_EXTRACTABLE snej@12: }; snej@12: CSSM_CSP_HANDLE cspHandle = [[MYKeychain defaultKeychain] CSPHandle]; snej@12: CSSM_KEY *passphraseKey = NULL; snej@12: if (impExpCreatePassKey(¶ms, snej@12: cspHandle, snej@12: creating, snej@12: &passphraseKey) != CSSM_OK) snej@12: return nil; snej@12: snej@12: MYSymmetricKey *key = [[self alloc] _initWithCSSMKey: passphraseKey]; snej@12: NSData *keyData = key.keyData; snej@12: Assert(keyData); snej@12: NSString *passphrase = [[NSString alloc] initWithData: keyData snej@12: encoding: NSUTF8StringEncoding]; snej@12: [key release]; snej@12: return [passphrase autorelease]; snej@12: } snej@12: snej@12: snej@12: #define PKCS5_V2_SALT_LEN 8 snej@12: #define PKCS5_V2_ITERATIONS 2048 snej@12: #define PKCS5_V2_DES_IV_SIZE 8 snej@12: snej@12: + (MYSymmetricKey*) generateFromUserPassphraseWithAlertTitle: (NSString*)alertTitle snej@12: alertPrompt: (NSString*)prompt snej@12: creating: (BOOL)creating snej@12: salt: (id)saltObj snej@12: { snej@12: MYSymmetricKey *generatedKey = nil; snej@12: snej@12: // Ask the user for a passphrase: snej@12: SecKeyImportExportParameters params = { snej@12: .version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION, snej@12: .flags = kSecKeySecurePassphrase, snej@12: .alertTitle = (CFStringRef)alertTitle, snej@12: .alertPrompt = (CFStringRef)prompt, snej@12: .keyUsage = CSSM_KEYUSE_ANY, snej@12: .keyAttributes = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_SENSITIVE snej@12: }; snej@12: CSSM_CSP_HANDLE cspHandle = [[MYKeychain defaultKeychain] CSPHandle]; snej@12: CSSM_KEY *passphraseKey = NULL; snej@12: if (impExpCreatePassKey(¶ms, snej@12: cspHandle, snej@12: creating, snej@12: &passphraseKey) != CSSM_OK) snej@12: return nil; snej@12: snej@12: CSSM_DATA saltData = makeSalt(saltObj,PKCS5_V2_SALT_LEN); snej@12: CSSM_CRYPTO_DATA seed = {}; snej@12: snej@12: // Now use the secure passphrase to generate a symmetric key: snej@12: CSSM_CC_HANDLE ctx = 0; snej@12: CSSM_ACCESS_CREDENTIALS credentials = {}; snej@12: if (checkcssm(CSSM_CSP_CreateDeriveKeyContext(cspHandle, snej@12: CSSM_ALGID_PKCS5_PBKDF2, snej@12: CSSM_ALGID_AES, 128, snej@12: &credentials, snej@12: passphraseKey, snej@12: PKCS5_V2_ITERATIONS, snej@12: &saltData, snej@12: &seed, snej@12: &ctx), snej@12: @"CSSM_CSP_CreateDeriveKeyContext")) { snej@12: CSSM_PKCS5_PBKDF2_PARAMS params = {.PseudoRandomFunction=CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1}; snej@12: CSSM_DATA paramData = {.Data=(void*)¶ms, .Length=sizeof(params)}; snej@12: CSSM_KEY *cssmKey = calloc(1,sizeof(CSSM_KEY)); snej@12: if (checkcssm(CSSM_DeriveKey(ctx, snej@12: ¶mData, snej@12: CSSM_KEYUSE_ANY, snej@12: CSSM_KEYATTR_EXTRACTABLE, //| CSSM_KEYATTR_SENSITIVE, snej@12: NULL, snej@12: NULL, snej@12: cssmKey), snej@12: @"CSSM_DeriveKey")) { snej@12: generatedKey = [[[self alloc] _initWithCSSMKey: cssmKey] autorelease]; snej@12: } snej@12: } snej@12: CSSM_DeleteContext(ctx); snej@12: CSSM_FreeKey(cspHandle, &credentials, passphraseKey, YES); snej@12: return generatedKey; snej@12: } snej@12: snej@12: snej@12: - (void) dealloc snej@12: { snej@12: if(_ownedCSSMKey) snej@12: CSSM_FreeKey(self.cssmCSPHandle, NULL, _ownedCSSMKey, YES); snej@12: [super dealloc]; snej@12: } snej@12: snej@0: snej@2: #if !TARGET_OS_IPHONE jens@16: - (id) initWithWrappedKeyData: (NSData*)wrappedKeyData { jens@16: return [self _initWithCSSMKey: unwrapCssmKeyFromData(wrappedKeyData, jens@16: CSSM_ALGID_AES,128)]; jens@16: } jens@16: jens@16: snej@13: - (NSData*) exportWrappedKeyWithPassphrasePrompt: (NSString*)prompt snej@2: { jens@16: // Prompt user for a passphrase to use for the wrapping key: snej@13: MYSymmetricKey *wrappingKey = [MYSymmetricKey snej@13: generateFromUserPassphraseWithAlertTitle: @"Export Key" snej@13: alertPrompt: prompt snej@13: creating: YES snej@13: salt: [MYCryptor randomKeyOfLength: PKCS5_V2_SALT_LEN*8]]; snej@12: if (!wrappingKey) snej@12: return nil; snej@13: Log(@"Wrapping using %@",wrappingKey); snej@12: snej@12: // Create the context: snej@13: CSSM_ACCESS_CREDENTIALS credentials = {}; snej@12: CSSM_CSP_HANDLE cspHandle = self.cssmCSPHandle; jens@16: CSSM_ALGORITHMS algorithm = wrappingKey.cssmAlgorithm; jens@16: uint8 iv[16] = {0}; // Right size for AES. Are zeros OK? //FIX: Support other algorithms jens@16: CSSM_DATA ivData = {.Data=(void*)&iv, .Length=sizeof(iv)}; snej@12: CSSM_CC_HANDLE ctx; snej@12: if (!checkcssm(CSSM_CSP_CreateSymmetricContext(cspHandle, jens@16: algorithm, //CSSM_ALGID_3DES_3KEY_EDE jens@16: defaultModeForAlgorithm(algorithm), snej@13: &credentials, snej@12: wrappingKey.cssmKey, jens@16: &ivData, jens@16: defaultPaddingForAlgorithm(algorithm), snej@12: NULL, snej@12: &ctx), snej@12: @"CSSM_CSP_CreateSymmetricContext")) snej@12: return nil; snej@12: snej@13: // Now wrap the key: snej@12: NSData *result = nil; snej@13: CSSM_WRAP_KEY wrappedKey = {}; snej@13: if (checkcssm(CSSM_WrapKey(ctx, &credentials, self.cssmKey, NULL, &wrappedKey), snej@13: @"CSSM_WrapKey")) { snej@13: // ...and copy the wrapped key data to the result NSData: snej@13: result = [NSData dataWithBytes: wrappedKey.KeyData.Data length: wrappedKey.KeyData.Length]; snej@13: CSSM_FreeKey(cspHandle, &credentials, &wrappedKey, NO); snej@12: } snej@12: // Finally, delete the context snej@12: CSSM_DeleteContext(ctx); snej@12: return result; snej@2: } snej@2: #endif snej@2: snej@0: jens@23: - (SecExternalItemType) keyClass { snej@0: return kSecItemTypeSessionKey; snej@0: } snej@0: snej@0: - (CCAlgorithm) algorithm { snej@0: CSSM_ALGORITHMS cssmAlg; snej@0: cssmAlg = self.cssmKey->KeyHeader.AlgorithmId; snej@0: switch(cssmAlg) { snej@0: case CSSM_ALGID_AES: snej@0: return kCCAlgorithmAES128; snej@0: case CSSM_ALGID_DES: snej@0: return kCCAlgorithmDES; snej@0: case CSSM_ALGID_3DES_3KEY: snej@0: return kCCAlgorithm3DES; snej@0: case CSSM_ALGID_CAST: snej@0: return kCCAlgorithmCAST; snej@0: case CSSM_ALGID_RC4: snej@0: return kCCAlgorithmRC4; snej@0: default: snej@0: Warn(@"CSSM_ALGORITHMS #%u doesn't map to any CCAlgorithm", cssmAlg); snej@0: return (CCAlgorithm)-1; snej@0: } snej@0: } snej@0: snej@2: - (const char*) algorithmName { snej@2: CCAlgorithm a = self.algorithm; snej@2: if (a >= 0 && a <= kCCAlgorithmRC4) snej@2: return kCCAlgorithmNames[a]; snej@2: else snej@2: return "???"; snej@2: } snej@2: snej@2: snej@2: - (NSString*) description { snej@2: return $sprintf(@"%@[%u-bit %s]", [self class], self.keySizeInBits, self.algorithmName); snej@2: } snej@2: snej@0: snej@0: - (NSData*) _cryptData: (NSData*)data operation: (CCOperation)op options: (CCOptions)options snej@0: { snej@0: NSData *keyData = self.keyData; snej@0: Assert(keyData, @"Couldn't get key data"); snej@0: NSMutableData *output = [NSMutableData dataWithLength: data.length + 256]; snej@0: size_t bytesWritten = 0; snej@0: CCCryptorStatus status = CCCrypt(op, self.algorithm, options, snej@0: keyData.bytes, keyData.length, NULL, snej@0: data.bytes, data.length, output.mutableBytes, output.length, snej@0: &bytesWritten); snej@0: if (status) { snej@0: Warn(@"MYSymmetricKey: CCCrypt returned error %i",status); snej@0: return nil; snej@0: } snej@0: output.length = bytesWritten; snej@0: return output; snej@0: } snej@0: snej@0: - (NSData*) encryptData: (NSData*)data { snej@0: return [self _cryptData: data operation: kCCEncrypt options: kCCOptionPKCS7Padding]; snej@0: } snej@0: snej@0: snej@0: - (NSData*) decryptData: (NSData*)data { snej@0: return [self _cryptData: data operation: kCCDecrypt options: kCCOptionPKCS7Padding]; snej@0: } snej@0: snej@0: snej@0: @end snej@0: snej@0: snej@12: #pragma mark - snej@12: snej@12: snej@12: static CSSM_KEY* cssmKeyFromData( NSData *keyData, snej@12: CSSM_ALGORITHMS algorithm, snej@12: MYKeychain *keychain ) { snej@12: // Thanks to Jim Murphy for showing the way! snej@12: if (!keychain) keychain = [MYKeychain defaultKeychain]; snej@0: CSSM_CC_HANDLE ccHandle; snej@12: if (!checkcssm(CSSM_CSP_CreateSymmetricContext([keychain CSPHandle], snej@12: CSSM_ALGID_NONE, CSSM_ALGMODE_WRAP, snej@12: NULL, NULL, NULL, snej@12: CSSM_PADDING_NONE, NULL, snej@12: &ccHandle), snej@12: @"CSSM_CSP_CreateSymmetricContext")) snej@12: return NO; snej@0: snej@12: CSSM_KEY wrappedKey = { snej@12: .KeyHeader = { snej@12: .BlobType = CSSM_KEYBLOB_RAW, snej@12: .Format = CSSM_KEYBLOB_RAW_FORMAT_NONE, snej@12: .AlgorithmId = algorithm, snej@12: .KeyClass = CSSM_KEYCLASS_SESSION_KEY, snej@12: .LogicalKeySizeInBits = keyData.length*8, snej@12: .KeyAttr = CSSM_KEYATTR_EXTRACTABLE, snej@12: .KeyUsage = CSSM_KEYUSE_ANY snej@12: }, snej@12: .KeyData = { snej@12: .Data = (void*)keyData.bytes, snej@12: .Length = keyData.length snej@12: } snej@12: }; snej@12: snej@12: CSSM_KEY *outKey = calloc(sizeof(CSSM_KEY),1); snej@12: CSSM_DATA desc = {}; snej@12: if (!checkcssm(CSSM_UnwrapKey(ccHandle, snej@12: NULL, snej@12: &wrappedKey, snej@12: CSSM_KEYUSE_ANY, snej@12: CSSM_KEYATTR_EXTRACTABLE, snej@12: NULL, snej@12: NULL, snej@12: outKey, snej@12: &desc), snej@12: @"CSSM_UnwrapKey")) { snej@12: free(outKey); snej@12: outKey = NULL; snej@0: } snej@0: CSSM_DeleteContext(ccHandle); snej@12: return outKey; snej@0: } snej@12: snej@12: jens@16: #if !TARGET_OS_IPHONE jens@16: static CSSM_KEY* unwrapCssmKeyFromData(NSData *wrappedData, jens@16: CSSM_ALGORITHMS algorithm, jens@16: unsigned sizeInBits) { jens@16: Warn(@"MYSymmetricKey: unwrapping is unimplemented; sorry"); jens@16: return nil; jens@16: #if 0 //not finished yet jens@16: // First create a wrapped-key structure from the data: jens@16: CSSM_WRAP_KEY wrappedKey = { jens@16: .KeyHeader = { jens@16: .BlobType = CSSM_KEYBLOB_WRAPPED, jens@16: .Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS3, jens@16: .AlgorithmId = algorithm, jens@16: .KeyClass = CSSM_KEYCLASS_SESSION_KEY, jens@16: .LogicalKeySizeInBits = sizeInBits, jens@16: .KeyAttr = CSSM_KEYATTR_EXTRACTABLE, jens@16: .KeyUsage = CSSM_KEYUSE_ANY, jens@16: .WrapAlgorithmId = CSSM_ALGID_AES, jens@16: }, jens@16: .KeyData = { jens@16: .Data = (void*)wrappedData.bytes, jens@16: .Length = wrappedData.length jens@16: } jens@16: }; jens@16: #endif jens@16: } jens@16: #endif jens@16: jens@16: snej@12: // Create salt data of a specific length from an arbitrary NSObject. */ snej@12: static CSSM_DATA makeSalt( id salty, size_t length ) { snej@12: // Convert to NSData if necessary: snej@12: CAssert(salty!=nil); snej@12: if (![salty isKindOfClass: [NSData class]]) snej@12: salty = [[salty description] dataUsingEncoding: NSUTF8StringEncoding]; snej@12: // Repeat enough times to fill the desired length: snej@12: NSMutableData *salt = [[salty mutableCopy] autorelease]; snej@12: CAssert(salt.length>0); snej@12: while (salt.length < length) { snej@12: [salt appendData: salt]; snej@12: } snej@12: // Truncate to length and return it: snej@12: salt.length = length; snej@12: return (CSSM_DATA){.Data=(void*)salt.bytes, .Length=salt.length}; snej@12: } snej@12: snej@12: snej@13: #pragma mark - snej@13: // Code from Keychain.framework: jens@16: jens@16: #if !TARGET_OS_IPHONE jens@16: #if 1 snej@13: static CSSM_ENCRYPT_MODE defaultModeForAlgorithm(CSSM_ALGORITHMS algorithm) { snej@13: switch(algorithm) { snej@13: // 8-byte block ciphers snej@13: case CSSM_ALGID_DES: snej@13: case CSSM_ALGID_3DES_3KEY_EDE: snej@13: case CSSM_ALGID_RC5: snej@13: case CSSM_ALGID_RC2: snej@13: return CSSM_ALGMODE_CBCPadIV8; break; snej@13: // 16-byte block ciphers snej@13: case CSSM_ALGID_AES: snej@13: return CSSM_ALGMODE_CBCPadIV8; break; snej@13: // stream ciphers snej@13: case CSSM_ALGID_ASC: snej@13: case CSSM_ALGID_RC4: snej@13: return CSSM_ALGMODE_NONE; break; snej@13: // Unknown snej@13: default: snej@13: Warn(@"Asked for the default mode for algorithm %d, but don't know that algorithm.\n", algorithm); snej@13: return CSSM_ALGMODE_NONE; snej@13: } snej@13: } jens@16: #endif snej@13: jens@16: #if 1 jens@16: static CSSM_PADDING defaultPaddingForAlgorithm(CSSM_ALGORITHMS algorithm) { snej@13: switch(algorithm) { snej@13: /* 8-byte block ciphers */ snej@13: case CSSM_ALGID_DES: snej@13: case CSSM_ALGID_3DES_3KEY_EDE: snej@13: case CSSM_ALGID_RC5: snej@13: case CSSM_ALGID_RC2: snej@13: return CSSM_PADDING_PKCS5; break; snej@13: /* 16-byte block ciphers */ snej@13: case CSSM_ALGID_AES: snej@13: return CSSM_PADDING_PKCS7; break; snej@13: /* stream ciphers */ snej@13: case CSSM_ALGID_ASC: snej@13: case CSSM_ALGID_RC4: snej@13: return CSSM_PADDING_NONE; break; snej@13: /* RSA/DSA asymmetric */ snej@13: case CSSM_ALGID_DSA: snej@13: case CSSM_ALGID_RSA: snej@13: return CSSM_PADDING_PKCS1; break; snej@13: /* Unknown */ snej@13: default: snej@13: Warn(@"Asked for the default padding mode for %d, but don't know that algorithm.\n", algorithm); snej@13: return CSSM_PADDING_NONE; snej@13: } snej@13: } snej@13: #endif jens@16: #endif snej@13: snej@13: #pragma mark - snej@13: // Code below was copied from SecImportExportUtils.cpp in Apple's libsecurity_keychain project snej@13: snej@13: snej@12: /* snej@12: * Given a context specified via a CSSM_CC_HANDLE, add a new snej@12: * CSSM_CONTEXT_ATTRIBUTE to the context as specified by AttributeType, snej@12: * AttributeLength, and an untyped pointer. snej@12: */ snej@12: static CSSM_RETURN impExpAddContextAttribute(CSSM_CC_HANDLE CCHandle, snej@12: uint32 AttributeType, snej@12: uint32 AttributeLength, snej@12: const void *AttributePtr) snej@12: { snej@12: CSSM_CONTEXT_ATTRIBUTE newAttr; snej@12: snej@12: newAttr.AttributeType = AttributeType; snej@12: newAttr.AttributeLength = AttributeLength; snej@12: newAttr.Attribute.Data = (CSSM_DATA_PTR)AttributePtr; snej@12: return CSSM_UpdateContextAttributes(CCHandle, 1, &newAttr); snej@12: } snej@12: snej@12: /* snej@12: * Add a CFString to a crypto context handle. snej@0: */ snej@12: static CSSM_RETURN impExpAddStringAttr( snej@12: CSSM_CC_HANDLE ccHand, snej@12: CFStringRef str, snej@12: CSSM_ATTRIBUTE_TYPE attrType) snej@12: { snej@12: /* CFStrings are passed as external rep in UTF8 encoding by convention */ snej@12: CFDataRef outData; snej@12: outData = CFStringCreateExternalRepresentation(NULL, snej@12: str, kCFStringEncodingUTF8, 0); // lossByte 0 ==> no loss allowed snej@12: if(outData == NULL) { snej@12: Warn(@"impExpAddStringAttr: bad string format"); snej@12: return paramErr; snej@12: } snej@12: snej@12: CSSM_DATA attrData; snej@12: attrData.Data = (uint8 *)CFDataGetBytePtr(outData); snej@12: attrData.Length = CFDataGetLength(outData); snej@12: CSSM_RETURN crtn = impExpAddContextAttribute(ccHand, attrType, sizeof(CSSM_DATA), snej@12: &attrData); snej@12: CFRelease(outData); snej@12: if(crtn) { snej@12: Warn(@"impExpAddStringAttr: CSSM_UpdateContextAttributes error"); snej@12: } snej@12: return crtn; snej@12: } snej@12: snej@12: /* snej@12: * Generate a secure passphrase key. Caller must eventually CSSM_FreeKey the result. snej@12: */ snej@12: static CSSM_RETURN impExpCreatePassKey( snej@12: const SecKeyImportExportParameters *keyParams, // required snej@12: CSSM_CSP_HANDLE cspHand, // MUST be CSPDL snej@12: BOOL verifyPhrase, // use 2nd passphrase textfield for verification? snej@12: CSSM_KEY_PTR *passKey) // mallocd and RETURNED snej@12: { snej@12: CSSM_RETURN crtn; snej@12: CSSM_CC_HANDLE ccHand; snej@12: uint32 verifyAttr; snej@12: CSSM_DATA dummyLabel; snej@12: CSSM_KEY_PTR ourKey = NULL; snej@12: snej@12: Log(@"Generating secure passphrase key"); snej@12: ourKey = (CSSM_KEY_PTR)malloc(sizeof(CSSM_KEY)); snej@12: if(ourKey == NULL) { snej@12: return memFullErr; snej@12: } snej@12: memset(ourKey, 0, sizeof(CSSM_KEY)); snej@12: snej@12: crtn = CSSM_CSP_CreateKeyGenContext(cspHand, snej@12: CSSM_ALGID_SECURE_PASSPHRASE, snej@12: 4, // keySizeInBits must be non zero snej@12: NULL, // Seed snej@12: NULL, // Salt snej@12: NULL, // StartDate snej@12: NULL, // EndDate snej@12: NULL, // Params snej@12: &ccHand); snej@12: if(crtn) { snej@12: checkcssm(crtn,@"CSSM_CSP_CreateKeyGenContext"); snej@12: return crtn; snej@12: } snej@12: /* subsequent errors to errOut: */ snej@12: snej@12: /* additional context attributes specific to this type of key gen */ snej@12: CAssert(keyParams != NULL); // or we wouldn't be here snej@12: if(keyParams->alertTitle != NULL) { snej@12: crtn = impExpAddStringAttr(ccHand, keyParams->alertTitle, snej@12: CSSM_ATTRIBUTE_ALERT_TITLE); snej@12: if(crtn) { snej@12: goto errOut; snej@12: } snej@12: } snej@12: if(keyParams->alertPrompt != NULL) { snej@12: crtn = impExpAddStringAttr(ccHand, keyParams->alertPrompt, snej@12: CSSM_ATTRIBUTE_PROMPT); snej@12: if(crtn) { snej@12: goto errOut; snej@12: } snej@12: } snej@12: verifyAttr = verifyPhrase ? 1 : 0; snej@12: crtn = impExpAddContextAttribute(ccHand, CSSM_ATTRIBUTE_VERIFY_PASSPHRASE, snej@12: sizeof(uint32), (const void *)verifyAttr); snej@12: if(crtn) { snej@12: checkcssm(crtn,@"impExpAddContextAttribute"); snej@12: goto errOut; snej@12: } snej@12: snej@12: dummyLabel.Data = (uint8 *)"Secure Passphrase"; snej@12: dummyLabel.Length = strlen((char *)dummyLabel.Data); snej@12: snej@12: uint32 keyAttr = keyParams->keyAttributes; snej@12: if (keyAttr & CSSM_KEYATTR_SENSITIVE) snej@12: keyAttr |= CSSM_KEYATTR_RETURN_REF; snej@12: else snej@12: keyAttr |= CSSM_KEYATTR_EXTRACTABLE; snej@12: snej@12: crtn = CSSM_GenerateKey(ccHand, snej@12: keyParams->keyUsage ?: CSSM_KEYUSE_ANY, snej@12: keyAttr, snej@12: &dummyLabel, snej@12: NULL, // ACL snej@12: ourKey); snej@12: if(crtn) { snej@12: checkcssm(crtn,@"CSSM_GenerateKey"); snej@12: } snej@12: errOut: snej@12: CSSM_DeleteContext(ccHand); snej@12: if(crtn == CSSM_OK) { snej@12: *passKey = ourKey; snej@12: } snej@12: else if(ourKey != NULL) { snej@12: free(ourKey); snej@12: } snej@12: return crtn; snej@12: } snej@12: snej@12: snej@12: #endif !MYCRYPTO_USE_IPHONE_API snej@14: snej@14: snej@14: snej@14: /* snej@14: Copyright (c) 2009, Jens Alfke . All rights reserved. snej@14: snej@14: Redistribution and use in source and binary forms, with or without modification, are permitted snej@14: provided that the following conditions are met: snej@14: snej@14: * Redistributions of source code must retain the above copyright notice, this list of conditions snej@14: and the following disclaimer. snej@14: * Redistributions in binary form must reproduce the above copyright notice, this list of conditions snej@14: and the following disclaimer in the documentation and/or other materials provided with the snej@14: distribution. snej@14: snej@14: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR snej@14: IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND snej@14: FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI- snej@14: BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES snej@14: (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR snej@14: PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN snej@14: CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF snej@14: THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. snej@14: */