MYSymmetricKey-iPhone.m
author snej@snej.local
Sun Apr 19 00:01:41 2009 -0700 (2009-04-19)
changeset 13 6fd9177eb6da
child 14 3af1d1c0ceb5
permissions -rw-r--r--
Implemented wrap/unwrap of session key using a key-pair.
     1 //
     2 //  MYSymmetricKey-iPhone.m
     3 //  MYCrypto
     4 //
     5 //  Created by Jens Alfke on 4/17/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 
    16 typedef uint32_t CSSM_ALGORITHMS;
    17 enum {
    18 // Taken from cssmtype.h in OS X 10.5 SDK:
    19 	CSSM_ALGID_NONE =					0x00000000L,
    20 	CSSM_ALGID_DES =					CSSM_ALGID_NONE + 14,
    21 	CSSM_ALGID_3DES_3KEY_EDE =			CSSM_ALGID_NONE + 17,
    22 	CSSM_ALGID_3DES_3KEY =           	CSSM_ALGID_3DES_3KEY_EDE,
    23 	CSSM_ALGID_RC4 =					CSSM_ALGID_NONE + 25,
    24 	CSSM_ALGID_CAST =					CSSM_ALGID_NONE + 27,
    25 	CSSM_ALGID_VENDOR_DEFINED =			CSSM_ALGID_NONE + 0x80000000L,
    26 	CSSM_ALGID_AES
    27 };
    28 
    29 static const CSSM_ALGORITHMS kCSSMAlgorithms[] = {
    30 CSSM_ALGID_AES, CSSM_ALGID_DES, CSSM_ALGID_3DES_3KEY, CSSM_ALGID_CAST, CSSM_ALGID_RC4
    31 };
    32 
    33 static const char *kCCAlgorithmNames[] = {"AES", "DES", "DES^3", "CAST", "RC4"};
    34 
    35 
    36 @implementation MYSymmetricKey
    37 
    38 
    39 - (id) _initWithKeyData: (NSData*)keyData
    40               algorithm: (CCAlgorithm)algorithm
    41              inKeychain: (MYKeychain*)keychain
    42 {
    43     Assert(algorithm <= kCCAlgorithmRC4);
    44     Assert(keyData);
    45     NSNumber *keySizeInBits = [NSNumber numberWithUnsignedInt: keyData.length * 8];
    46     NSDictionary *keyAttrs = $dict( {(id)kSecClass, (id)kSecClassKey},
    47                                     //{(id)kSecAttrKeyClass, (id)kSecAttrKeyClassSymmetric},
    48                                     {(id)kSecAttrKeyType, [NSNumber numberWithUnsignedInt: kCSSMAlgorithms[algorithm]]},
    49                                     {(id)kSecAttrKeySizeInBits, keySizeInBits},
    50                                     {(id)kSecAttrEffectiveKeySize, keySizeInBits},
    51                                     {(id)kSecAttrIsPermanent, keychain ?$true :$false},
    52                                     {(id)kSecAttrCanEncrypt, $true},
    53                                     {(id)kSecAttrCanDecrypt, $true},
    54                                     {(id)kSecAttrCanWrap, $false},
    55                                     {(id)kSecAttrCanUnwrap, $false},
    56                                     {(id)kSecAttrCanDerive, $false},
    57                                     {(id)kSecAttrCanSign, $false},
    58                                     {(id)kSecAttrCanVerify, $false},
    59                                     {(id)kSecValueData, keyData},
    60                                     {(id)kSecReturnPersistentRef, $true});
    61     SecKeyRef keyRef = NULL;
    62     if (!check(SecItemAdd((CFDictionaryRef)keyAttrs, (CFTypeRef*)&keyRef), @"SecItemAdd")) {
    63         [self release];
    64         return nil;
    65     }
    66     Assert(keyRef, @"SecItemAdd didn't return anything");
    67     self = [self initWithKeyRef: keyRef];
    68     CFRelease(keyRef);
    69     return self;
    70 }
    71 
    72 - (id) initWithKeyData: (NSData*)keyData
    73              algorithm: (CCAlgorithm)algorithm
    74 {
    75     return [self _initWithKeyData: keyData algorithm: algorithm inKeychain: nil];
    76 }
    77 
    78 + (MYSymmetricKey*) _generateSymmetricKeyOfSize: (unsigned)keySizeInBits
    79                                       algorithm: (CCAlgorithm)algorithm
    80                                      inKeychain: (MYKeychain*)keychain
    81 {
    82     return [[[self alloc] _initWithKeyData: [MYCryptor randomKeyOfLength: keySizeInBits]
    83                                  algorithm: algorithm
    84                                 inKeychain: keychain]
    85                     autorelease];
    86 }
    87 
    88 + (MYSymmetricKey*) generateSymmetricKeyOfSize: (unsigned)keySizeInBits
    89                                      algorithm: (CCAlgorithm)algorithm {
    90     return [self _generateSymmetricKeyOfSize: keySizeInBits
    91                                    algorithm: algorithm
    92                                   inKeychain: nil];
    93 }
    94 
    95 
    96 - (SecExternalItemType) keyType {
    97     return kSecAttrKeyClassSymmetric;
    98 }
    99 
   100 - (CCAlgorithm) algorithm {
   101     CSSM_ALGORITHMS cssmAlg;
   102     id keyType = [self _attribute: kSecAttrKeyType];
   103     Assert(keyType!=nil, @"Key has no kSecAttrKeyType");
   104     cssmAlg = [keyType unsignedIntValue];
   105     switch(cssmAlg) {
   106         case CSSM_ALGID_AES:
   107             return kCCAlgorithmAES128;
   108         case CSSM_ALGID_DES:
   109             return kCCAlgorithmDES;	
   110         case CSSM_ALGID_3DES_3KEY:
   111             return kCCAlgorithm3DES;
   112         case CSSM_ALGID_CAST:
   113             return kCCAlgorithmCAST;
   114         case CSSM_ALGID_RC4:
   115             return kCCAlgorithmRC4;	
   116         default:
   117             Warn(@"CSSM_ALGORITHMS #%u doesn't map to any CCAlgorithm", cssmAlg);
   118             return (CCAlgorithm)-1;
   119     }
   120 }
   121 
   122 - (const char*) algorithmName {
   123     CCAlgorithm a = self.algorithm;
   124     if (a >= 0 && a <= kCCAlgorithmRC4)
   125         return kCCAlgorithmNames[a];
   126     else
   127         return "???";
   128 }
   129 
   130 - (unsigned) keySizeInBits {
   131     id keySize = [self _attribute: kSecAttrKeySizeInBits];
   132     Assert(keySize!=nil, @"Key has no kSecAttrKeySizeInBits");
   133     return [keySize unsignedIntValue];
   134 }
   135 
   136 
   137 - (NSString*) description {
   138     return $sprintf(@"%@[%u-bit %s]", [self class], self.keySizeInBits, self.algorithmName);
   139 }
   140 
   141 
   142 - (NSData*) _cryptData: (NSData*)data operation: (CCOperation)op options: (CCOptions)options
   143 {
   144     NSData *keyData = self.keyData;
   145     Assert(keyData, @"Couldn't get key data");
   146     NSMutableData *output = [NSMutableData dataWithLength: data.length + 256];
   147     size_t bytesWritten = 0;
   148     CCCryptorStatus status = CCCrypt(op, self.algorithm, options, 
   149                                      keyData.bytes, keyData.length, NULL,
   150                                      data.bytes, data.length, output.mutableBytes, output.length,
   151                                      &bytesWritten);
   152     if (status) {
   153         Warn(@"MYSymmetricKey: CCCrypt returned error %i",status);
   154         return nil;
   155     }
   156     output.length = bytesWritten;
   157     return output;
   158 }
   159 
   160 - (NSData*) encryptData: (NSData*)data {
   161     return [self _cryptData: data operation: kCCEncrypt options: kCCOptionPKCS7Padding];
   162 }
   163 
   164 
   165 - (NSData*) decryptData: (NSData*)data {
   166     return [self _cryptData: data operation: kCCDecrypt options: kCCOptionPKCS7Padding];
   167 }
   168 
   169 
   170 @end
   171 
   172 
   173 #endif MYCRYPTO_USE_IPHONE_API