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