MYSymmetricKey.m
changeset 3 1dfe820d7ebe
parent 1 60e4cbbb5128
child 4 f4709533c816
     1.1 --- a/MYSymmetricKey.m	Sat Apr 04 22:56:13 2009 -0700
     1.2 +++ b/MYSymmetricKey.m	Wed Apr 08 16:30:52 2009 -0700
     1.3 @@ -11,7 +11,7 @@
     1.4  #import "MYCrypto_Private.h"
     1.5  
     1.6  
     1.7 -#if USE_IPHONE_API
     1.8 +#if MYCRYPTO_USE_IPHONE_API
     1.9  typedef uint32_t CSSM_ALGORITHMS;
    1.10  enum {
    1.11  // Taken from cssmtype.h in OS X 10.5 SDK:
    1.12 @@ -32,6 +32,8 @@
    1.13      CSSM_ALGID_AES, CSSM_ALGID_DES, CSSM_ALGID_3DES_3KEY, CSSM_ALGID_CAST, CSSM_ALGID_RC4
    1.14  };
    1.15  
    1.16 +static const char *kCCAlgorithmNames[] = {"AES", "DES", "DES^3", "CAST", "RC4"};
    1.17 +
    1.18  
    1.19  #pragma mark -
    1.20  @implementation MYSymmetricKey
    1.21 @@ -44,21 +46,41 @@
    1.22      Assert(algorithm <= kCCAlgorithmRC4);
    1.23      Assert(keyData);
    1.24      SecKeyRef keyRef = NULL;
    1.25 -#if USE_IPHONE_API
    1.26 -    unsigned keySizeInBits = keyData.length / 8;
    1.27 +#if MYCRYPTO_USE_IPHONE_API
    1.28 +    NSNumber *keySizeInBits = [NSNumber numberWithUnsignedInt: keyData.length * 8];
    1.29      NSDictionary *keyAttrs = $dict( {(id)kSecClass, (id)kSecClassKey},
    1.30 -                                    {(id)kSecAttrKeyClass, (id)kSecAttrKeyClassSymmetric},
    1.31 -                                    {(id)kSecAttrKeyType, $object(kCSSMAlgorithms[algorithm])},
    1.32 -                                    {(id)kSecAttrKeySizeInBits, $object(keySizeInBits)},
    1.33 -                                    {(id)kSecAttrEffectiveKeySize, $object(keySizeInBits)},
    1.34 +                                    //{(id)kSecAttrKeyClass, (id)kSecAttrKeyClassSymmetric},
    1.35 +                                    {(id)kSecAttrKeyType, [NSNumber numberWithUnsignedInt: kCSSMAlgorithms[algorithm]]},
    1.36 +                                    {(id)kSecAttrKeySizeInBits, keySizeInBits},
    1.37 +                                    {(id)kSecAttrEffectiveKeySize, keySizeInBits},
    1.38                                      {(id)kSecAttrIsPermanent, keychain ?$true :$false},
    1.39 -                                    {(id)kSecValueData, keyData} );
    1.40 +                                    {(id)kSecAttrCanEncrypt, $true},
    1.41 +                                    {(id)kSecAttrCanDecrypt, $true},
    1.42 +                                    {(id)kSecAttrCanWrap, $false},
    1.43 +                                    {(id)kSecAttrCanUnwrap, $false},
    1.44 +                                    {(id)kSecAttrCanDerive, $false},
    1.45 +                                    {(id)kSecAttrCanSign, $false},
    1.46 +                                    {(id)kSecAttrCanVerify, $false},
    1.47 +                                    {(id)kSecValueData, keyData},
    1.48 +    //{(id)kSecAttrApplicationTag, [@"foo" dataUsingEncoding: NSUTF8StringEncoding]}, //TEMP
    1.49 +                                    {(id)kSecReturnPersistentRef, $true});
    1.50      if (!check(SecItemAdd((CFDictionaryRef)keyAttrs, (CFTypeRef*)&keyRef), @"SecItemAdd")) {
    1.51          [self release];
    1.52          return nil;
    1.53      }
    1.54 +    Log(@"SecItemAdd returned %@", keyRef);//TEMP
    1.55 +    Assert(keyRef, @"SecItemAdd didn't return anything");
    1.56  #else
    1.57      Assert(NO,@"Unimplemented"); //FIX
    1.58 +    /* The technique below doesn't work, because there's no way to tell SecKeychainItemImport
    1.59 +       what algorithm to use when importing a raw key. Still looking for a solution... --jpa 4/2009
    1.60 +    SecKeyImportExportParameters params = {};
    1.61 +    keyRef = importKey(keyData, kSecItemTypeSessionKey, keychain.keychainRefOrDefault, &params);
    1.62 +    if (!keyRef) {
    1.63 +        [self release];
    1.64 +        return nil;
    1.65 +    }
    1.66 +     */
    1.67  #endif
    1.68      self = [self initWithKeyRef: keyRef];
    1.69      CFRelease(keyRef);
    1.70 @@ -75,8 +97,8 @@
    1.71                                        algorithm: (CCAlgorithm)algorithm
    1.72                                       inKeychain: (MYKeychain*)keychain
    1.73  {
    1.74 -#if USE_IPHONE_API
    1.75 -    return [[[self alloc] _initWithKeyData: [MYCryptor randomKeyOfLength: (keySizeInBits+7)/8]
    1.76 +#if MYCRYPTO_USE_IPHONE_API
    1.77 +    return [[[self alloc] _initWithKeyData: [MYCryptor randomKeyOfLength: keySizeInBits]
    1.78                                   algorithm: algorithm
    1.79                                  inKeychain: keychain]
    1.80                      autorelease];
    1.81 @@ -106,9 +128,28 @@
    1.82  }
    1.83  
    1.84  
    1.85 +#if !TARGET_OS_IPHONE
    1.86 +- (NSData*) exportKeyInFormat: (SecExternalFormat)format
    1.87 +                      withPEM: (BOOL)withPEM
    1.88 +{
    1.89 +    SecKeyImportExportParameters params = {
    1.90 +        .version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION,
    1.91 +        .flags = kSecKeySecurePassphrase,
    1.92 +    };
    1.93 +    CFDataRef data = NULL;
    1.94 +    if (check(SecKeychainItemExport(self.keyRef,
    1.95 +                                    format, (withPEM ?kSecItemPemArmour :0), 
    1.96 +                                    &params, &data),
    1.97 +              @"SecKeychainItemExport"))
    1.98 +        return [(id)CFMakeCollectable(data) autorelease];
    1.99 +    else
   1.100 +        return nil;
   1.101 +}
   1.102 +#endif
   1.103 +
   1.104  
   1.105  - (SecExternalItemType) keyType {
   1.106 -#if USE_IPHONE_API
   1.107 +#if MYCRYPTO_USE_IPHONE_API
   1.108      return kSecAttrKeyClassSymmetric;
   1.109  #else
   1.110      return kSecItemTypeSessionKey;
   1.111 @@ -117,7 +158,7 @@
   1.112  
   1.113  - (CCAlgorithm) algorithm {
   1.114      CSSM_ALGORITHMS cssmAlg;
   1.115 -#if USE_IPHONE_API
   1.116 +#if MYCRYPTO_USE_IPHONE_API
   1.117      id keyType = [self _attribute: kSecAttrKeyType];
   1.118      Assert(keyType!=nil, @"Key has no kSecAttrKeyType");
   1.119      cssmAlg = [keyType unsignedIntValue];
   1.120 @@ -141,6 +182,31 @@
   1.121      }
   1.122  }
   1.123  
   1.124 +- (const char*) algorithmName {
   1.125 +    CCAlgorithm a = self.algorithm;
   1.126 +    if (a >= 0 && a <= kCCAlgorithmRC4)
   1.127 +        return kCCAlgorithmNames[a];
   1.128 +    else
   1.129 +        return "???";
   1.130 +}
   1.131 +
   1.132 +- (unsigned) keySizeInBits {
   1.133 +#if MYCRYPTO_USE_IPHONE_API
   1.134 +    id keySize = [self _attribute: kSecAttrKeySizeInBits];
   1.135 +    Assert(keySize!=nil, @"Key has no kSecAttrKeySizeInBits");
   1.136 +    return [keySize unsignedIntValue];
   1.137 +#else
   1.138 +    const CSSM_KEY *key = self.cssmKey;
   1.139 +    Assert(key);
   1.140 +    return key->KeyHeader.LogicalKeySizeInBits;
   1.141 +#endif
   1.142 +}
   1.143 +
   1.144 +
   1.145 +- (NSString*) description {
   1.146 +    return $sprintf(@"%@[%u-bit %s]", [self class], self.keySizeInBits, self.algorithmName);
   1.147 +}
   1.148 +
   1.149  
   1.150  - (NSData*) _cryptData: (NSData*)data operation: (CCOperation)op options: (CCOptions)options
   1.151  {