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