diff -r 60e4cbbb5128 -r 1dfe820d7ebe MYSymmetricKey.m --- a/MYSymmetricKey.m Sat Apr 04 22:56:13 2009 -0700 +++ b/MYSymmetricKey.m Wed Apr 08 16:30:52 2009 -0700 @@ -11,7 +11,7 @@ #import "MYCrypto_Private.h" -#if USE_IPHONE_API +#if MYCRYPTO_USE_IPHONE_API typedef uint32_t CSSM_ALGORITHMS; enum { // Taken from cssmtype.h in OS X 10.5 SDK: @@ -32,6 +32,8 @@ CSSM_ALGID_AES, CSSM_ALGID_DES, CSSM_ALGID_3DES_3KEY, CSSM_ALGID_CAST, CSSM_ALGID_RC4 }; +static const char *kCCAlgorithmNames[] = {"AES", "DES", "DES^3", "CAST", "RC4"}; + #pragma mark - @implementation MYSymmetricKey @@ -44,21 +46,41 @@ Assert(algorithm <= kCCAlgorithmRC4); Assert(keyData); SecKeyRef keyRef = NULL; -#if USE_IPHONE_API - unsigned keySizeInBits = keyData.length / 8; +#if MYCRYPTO_USE_IPHONE_API + NSNumber *keySizeInBits = [NSNumber numberWithUnsignedInt: keyData.length * 8]; NSDictionary *keyAttrs = $dict( {(id)kSecClass, (id)kSecClassKey}, - {(id)kSecAttrKeyClass, (id)kSecAttrKeyClassSymmetric}, - {(id)kSecAttrKeyType, $object(kCSSMAlgorithms[algorithm])}, - {(id)kSecAttrKeySizeInBits, $object(keySizeInBits)}, - {(id)kSecAttrEffectiveKeySize, $object(keySizeInBits)}, + //{(id)kSecAttrKeyClass, (id)kSecAttrKeyClassSymmetric}, + {(id)kSecAttrKeyType, [NSNumber numberWithUnsignedInt: kCSSMAlgorithms[algorithm]]}, + {(id)kSecAttrKeySizeInBits, keySizeInBits}, + {(id)kSecAttrEffectiveKeySize, keySizeInBits}, {(id)kSecAttrIsPermanent, keychain ?$true :$false}, - {(id)kSecValueData, keyData} ); + {(id)kSecAttrCanEncrypt, $true}, + {(id)kSecAttrCanDecrypt, $true}, + {(id)kSecAttrCanWrap, $false}, + {(id)kSecAttrCanUnwrap, $false}, + {(id)kSecAttrCanDerive, $false}, + {(id)kSecAttrCanSign, $false}, + {(id)kSecAttrCanVerify, $false}, + {(id)kSecValueData, keyData}, + //{(id)kSecAttrApplicationTag, [@"foo" dataUsingEncoding: NSUTF8StringEncoding]}, //TEMP + {(id)kSecReturnPersistentRef, $true}); if (!check(SecItemAdd((CFDictionaryRef)keyAttrs, (CFTypeRef*)&keyRef), @"SecItemAdd")) { [self release]; return nil; } + Log(@"SecItemAdd returned %@", keyRef);//TEMP + Assert(keyRef, @"SecItemAdd didn't return anything"); #else Assert(NO,@"Unimplemented"); //FIX + /* The technique below doesn't work, because there's no way to tell SecKeychainItemImport + what algorithm to use when importing a raw key. Still looking for a solution... --jpa 4/2009 + SecKeyImportExportParameters params = {}; + keyRef = importKey(keyData, kSecItemTypeSessionKey, keychain.keychainRefOrDefault, ¶ms); + if (!keyRef) { + [self release]; + return nil; + } + */ #endif self = [self initWithKeyRef: keyRef]; CFRelease(keyRef); @@ -75,8 +97,8 @@ algorithm: (CCAlgorithm)algorithm inKeychain: (MYKeychain*)keychain { -#if USE_IPHONE_API - return [[[self alloc] _initWithKeyData: [MYCryptor randomKeyOfLength: (keySizeInBits+7)/8] +#if MYCRYPTO_USE_IPHONE_API + return [[[self alloc] _initWithKeyData: [MYCryptor randomKeyOfLength: keySizeInBits] algorithm: algorithm inKeychain: keychain] autorelease]; @@ -106,9 +128,28 @@ } +#if !TARGET_OS_IPHONE +- (NSData*) exportKeyInFormat: (SecExternalFormat)format + withPEM: (BOOL)withPEM +{ + SecKeyImportExportParameters params = { + .version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION, + .flags = kSecKeySecurePassphrase, + }; + CFDataRef data = NULL; + if (check(SecKeychainItemExport(self.keyRef, + format, (withPEM ?kSecItemPemArmour :0), + ¶ms, &data), + @"SecKeychainItemExport")) + return [(id)CFMakeCollectable(data) autorelease]; + else + return nil; +} +#endif + - (SecExternalItemType) keyType { -#if USE_IPHONE_API +#if MYCRYPTO_USE_IPHONE_API return kSecAttrKeyClassSymmetric; #else return kSecItemTypeSessionKey; @@ -117,7 +158,7 @@ - (CCAlgorithm) algorithm { CSSM_ALGORITHMS cssmAlg; -#if USE_IPHONE_API +#if MYCRYPTO_USE_IPHONE_API id keyType = [self _attribute: kSecAttrKeyType]; Assert(keyType!=nil, @"Key has no kSecAttrKeyType"); cssmAlg = [keyType unsignedIntValue]; @@ -141,6 +182,31 @@ } } +- (const char*) algorithmName { + CCAlgorithm a = self.algorithm; + if (a >= 0 && a <= kCCAlgorithmRC4) + return kCCAlgorithmNames[a]; + else + return "???"; +} + +- (unsigned) keySizeInBits { +#if MYCRYPTO_USE_IPHONE_API + id keySize = [self _attribute: kSecAttrKeySizeInBits]; + Assert(keySize!=nil, @"Key has no kSecAttrKeySizeInBits"); + return [keySize unsignedIntValue]; +#else + const CSSM_KEY *key = self.cssmKey; + Assert(key); + return key->KeyHeader.LogicalKeySizeInBits; +#endif +} + + +- (NSString*) description { + return $sprintf(@"%@[%u-bit %s]", [self class], self.keySizeInBits, self.algorithmName); +} + - (NSData*) _cryptData: (NSData*)data operation: (CCOperation)op options: (CCOptions)options {