MYSymmetricKey-iPhone.m
author Jens Alfke <jens@mooseyard.com>
Tue Jul 21 10:13:08 2009 -0700 (2009-07-21)
changeset 27 d0aadddb9c64
parent 23 39fec79de6e8
permissions -rw-r--r--
MYCertificate now checks validity of self-signed certs loaded from the keychain (because the Security framework doesn't validate self-signed certs.)
     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 #define kAlgorithmNone 0xFFFFFFFF
    17 
    18 
    19 typedef uint32_t CSSM_ALGORITHMS;
    20 enum {
    21 // Taken from cssmtype.h in OS X 10.5 SDK:
    22 	CSSM_ALGID_NONE =					0x00000000L,
    23 	CSSM_ALGID_DES =					CSSM_ALGID_NONE + 14,
    24 	CSSM_ALGID_3DES_3KEY_EDE =			CSSM_ALGID_NONE + 17,
    25 	CSSM_ALGID_3DES_3KEY =           	CSSM_ALGID_3DES_3KEY_EDE,
    26 	CSSM_ALGID_RC4 =					CSSM_ALGID_NONE + 25,
    27 	CSSM_ALGID_CAST =					CSSM_ALGID_NONE + 27,
    28 	CSSM_ALGID_VENDOR_DEFINED =			CSSM_ALGID_NONE + 0x80000000L,
    29 	CSSM_ALGID_AES
    30 };
    31 
    32 static const CSSM_ALGORITHMS kCSSMAlgorithms[] = {
    33 CSSM_ALGID_AES, CSSM_ALGID_DES, CSSM_ALGID_3DES_3KEY, CSSM_ALGID_CAST, CSSM_ALGID_RC4
    34 };
    35 
    36 static const char *kCCAlgorithmNames[] = {"AES", "DES", "DES^3", "CAST", "RC4"};
    37 
    38 
    39 @implementation MYSymmetricKey
    40 
    41 
    42 - (id) initWithKeyRef: (SecKeyRef)key {
    43     self = [super initWithKeyRef: key];
    44     if (self) {
    45         _algorithm = kAlgorithmNone;
    46     }
    47     return self;
    48 }
    49 
    50 - (id) _initWithKeyData: (NSData*)keyData
    51               algorithm: (CCAlgorithm)algorithm
    52              inKeychain: (MYKeychain*)keychain
    53 {
    54     Assert(algorithm <= kCCAlgorithmRC4);
    55     Assert(keyData);
    56     unsigned keySizeInBits = keyData.length * 8;
    57     NSMutableDictionary *keyAttrs = $mdict( {(id)kSecClass, (id)kSecClassKey},
    58                                             {(id)kSecAttrKeyClass, (id)kSecAttrKeyClassSymmetric},
    59                                             {(id)kSecAttrKeyType, $object(kCSSMAlgorithms[algorithm])},
    60                                             {(id)kSecValueData, keyData},
    61                                             {(id)kSecAttrKeySizeInBits, $object(keySizeInBits)},
    62                                             {(id)kSecAttrEffectiveKeySize, $object(keySizeInBits)},
    63                                             {(id)kSecAttrIsPermanent, keychain ?$true :$false},
    64                                             {(id)kSecAttrCanEncrypt, $true},
    65                                             {(id)kSecAttrCanDecrypt, $true},
    66                                             {(id)kSecAttrCanWrap, $false},
    67                                             {(id)kSecAttrCanUnwrap, $false},
    68                                             {(id)kSecAttrCanDerive, $false},
    69                                             {(id)kSecAttrCanSign, $false},
    70                                             {(id)kSecAttrCanVerify, $false});
    71     SecKeyRef keyRef = (SecKeyRef) [MYKeychain _addItemWithInfo: keyAttrs];
    72     if (!keyRef) {
    73         [self release];
    74         return nil;
    75     }
    76     self = [self initWithKeyRef: keyRef];
    77     if (self) {
    78         _algorithm = algorithm;
    79         _keySizeInBits = keySizeInBits;
    80     }
    81     CFRelease(keyRef);
    82     return self;
    83 }
    84 
    85 - (id) initWithKeyData: (NSData*)keyData
    86              algorithm: (CCAlgorithm)algorithm
    87 {
    88     return [self _initWithKeyData: keyData algorithm: algorithm inKeychain: nil];
    89 }
    90 
    91 + (MYSymmetricKey*) _generateSymmetricKeyOfSize: (unsigned)keySizeInBits
    92                                       algorithm: (CCAlgorithm)algorithm
    93                                      inKeychain: (MYKeychain*)keychain
    94 {
    95     return [[[self alloc] _initWithKeyData: [MYCryptor randomKeyOfLength: keySizeInBits]
    96                                  algorithm: algorithm
    97                                 inKeychain: keychain]
    98                     autorelease];
    99 }
   100 
   101 + (MYSymmetricKey*) generateSymmetricKeyOfSize: (unsigned)keySizeInBits
   102                                      algorithm: (CCAlgorithm)algorithm {
   103     return [self _generateSymmetricKeyOfSize: keySizeInBits
   104                                    algorithm: algorithm
   105                                   inKeychain: nil];
   106 }
   107 
   108 
   109 - (SecExternalItemType) keyClass {
   110     return kSecAttrKeyClassSymmetric;
   111 }
   112 
   113 - (CCAlgorithm) algorithm {
   114     if (_algorithm == kAlgorithmNone) {
   115         CSSM_ALGORITHMS cssmAlg;
   116         id keyType = [self _attribute: kSecAttrKeyType];
   117         Assert(keyType!=nil, @"Key has no kSecAttrKeyType");
   118         cssmAlg = [keyType unsignedIntValue];
   119         switch(cssmAlg) {
   120             case CSSM_ALGID_AES:
   121                 _algorithm = kCCAlgorithmAES128;
   122                 break;
   123             case CSSM_ALGID_DES:
   124                 _algorithm = kCCAlgorithmDES;
   125                 break;
   126             case CSSM_ALGID_3DES_3KEY:
   127                 _algorithm = kCCAlgorithm3DES;
   128                 break;
   129             case CSSM_ALGID_CAST:
   130                 _algorithm = kCCAlgorithmCAST;
   131                 break;
   132             case CSSM_ALGID_RC4:
   133                 _algorithm = kCCAlgorithmRC4;
   134                 break;
   135             default:
   136                 Warn(@"CSSM_ALGORITHMS #%u doesn't map to any CCAlgorithm", cssmAlg);
   137                 break;
   138         }
   139     }
   140     return _algorithm;
   141 }
   142 
   143 - (const char*) algorithmName {
   144     CCAlgorithm a = self.algorithm;
   145     if (a >= 0 && a <= kCCAlgorithmRC4)
   146         return kCCAlgorithmNames[a];
   147     else
   148         return "???";
   149 }
   150 
   151 - (unsigned) keySizeInBits {
   152     if (_keySizeInBits == 0) {
   153         id keySize = [self _attribute: kSecAttrKeySizeInBits];
   154         Assert(keySize!=nil, @"Key has no kSecAttrKeySizeInBits");
   155         _keySizeInBits = [keySize unsignedIntValue];
   156     }
   157     return _keySizeInBits;
   158 }
   159 
   160 
   161 - (NSString*) description {
   162     return $sprintf(@"%@[%u-bit %s]", [self class], self.keySizeInBits, self.algorithmName);
   163 }
   164 
   165 
   166 - (NSData*) _cryptData: (NSData*)data operation: (CCOperation)op options: (CCOptions)options
   167 {
   168     NSData *keyData = self.keyData;
   169     Assert(keyData, @"Couldn't get key data");
   170     NSMutableData *output = [NSMutableData dataWithLength: data.length + 256];
   171     size_t bytesWritten = 0;
   172     CCCryptorStatus status = CCCrypt(op, self.algorithm, options, 
   173                                      keyData.bytes, keyData.length, NULL,
   174                                      data.bytes, data.length, output.mutableBytes, output.length,
   175                                      &bytesWritten);
   176     if (status) {
   177         Warn(@"MYSymmetricKey: CCCrypt returned error %i",status);
   178         return nil;
   179     }
   180     output.length = bytesWritten;
   181     return output;
   182 }
   183 
   184 - (NSData*) encryptData: (NSData*)data {
   185     return [self _cryptData: data operation: kCCEncrypt options: kCCOptionPKCS7Padding];
   186 }
   187 
   188 
   189 - (NSData*) decryptData: (NSData*)data {
   190     return [self _cryptData: data operation: kCCDecrypt options: kCCOptionPKCS7Padding];
   191 }
   192 
   193 
   194 @end
   195 
   196 
   197 #endif MYCRYPTO_USE_IPHONE_API
   198 
   199 
   200 
   201 /*
   202  Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
   203  
   204  Redistribution and use in source and binary forms, with or without modification, are permitted
   205  provided that the following conditions are met:
   206  
   207  * Redistributions of source code must retain the above copyright notice, this list of conditions
   208  and the following disclaimer.
   209  * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
   210  and the following disclaimer in the documentation and/or other materials provided with the
   211  distribution.
   212  
   213  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   214  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   215  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   216  BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   217  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   218   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   219  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   220  THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   221  */