MYSymmetricKey.m
author Jens Alfke <jens@mooseyard.com>
Wed Jun 10 09:02:18 2009 -0700 (2009-06-10)
changeset 25 38c3c3923e1f
parent 16 c409dbc4f068
child 26 d9c2a06d4e4e
permissions -rw-r--r--
Changed the X.509 version number in generated certs from 1 to 3, so that SecCertificateCreateFromData on iPhone will accept them. :-/
snej@0
     1
//
snej@0
     2
//  MYSymmetricKey.m
snej@0
     3
//  MYCrypto
snej@0
     4
//
snej@0
     5
//  Created by Jens Alfke on 4/2/09.
snej@0
     6
//  Copyright 2009 Jens Alfke. All rights reserved.
snej@0
     7
//
snej@0
     8
snej@0
     9
#import "MYSymmetricKey.h"
snej@0
    10
#import "MYCryptor.h"
snej@0
    11
#import "MYCrypto_Private.h"
snej@0
    12
snej@12
    13
#if !MYCRYPTO_USE_IPHONE_API
snej@0
    14
snej@0
    15
#import <Security/cssmtype.h>
snej@12
    16
snej@0
    17
snej@13
    18
CSSM_ALGORITHMS CSSMFromCCAlgorithm( CCAlgorithm ccAlgorithm ) {
snej@13
    19
    static const CSSM_ALGORITHMS kCSSMAlgorithms[] = {
snej@13
    20
        CSSM_ALGID_AES, CSSM_ALGID_DES, CSSM_ALGID_3DES_3KEY, CSSM_ALGID_CAST, CSSM_ALGID_RC4
snej@13
    21
    };
snej@13
    22
    if (ccAlgorithm >=0 && ccAlgorithm <= kCCAlgorithmRC4)
snej@13
    23
        return kCSSMAlgorithms[ccAlgorithm];
snej@13
    24
    else
snej@13
    25
        return CSSM_ALGID_NONE;
snej@13
    26
}
snej@0
    27
snej@2
    28
static const char *kCCAlgorithmNames[] = {"AES", "DES", "DES^3", "CAST", "RC4"};
snej@2
    29
snej@0
    30
snej@12
    31
/** Undocumented Security function. Unfortunately this is the only way I can find to create
snej@12
    32
    a SecKeyRef from a CSSM_KEY. */
snej@12
    33
extern OSStatus SecKeyCreate(const CSSM_KEY *key, SecKeyRef* keyRef) WEAK_IMPORT_ATTRIBUTE;
snej@12
    34
snej@12
    35
static CSSM_KEY* cssmKeyFromData( NSData *keyData, CSSM_ALGORITHMS algorithm,
snej@12
    36
                                 MYKeychain *keychain);
jens@16
    37
jens@16
    38
#if !TARGET_OS_IPHONE
jens@16
    39
static CSSM_KEY* unwrapCssmKeyFromData(NSData *wrappedData,
jens@16
    40
                                       CSSM_ALGORITHMS algorithm,
jens@16
    41
                                       unsigned sizeInBits);
jens@16
    42
static CSSM_ENCRYPT_MODE defaultModeForAlgorithm(CSSM_ALGORITHMS algorithm);
jens@16
    43
static CSSM_PADDING defaultPaddingForAlgorithm(CSSM_ALGORITHMS algorithm);
jens@16
    44
#endif
jens@16
    45
snej@12
    46
static CSSM_DATA makeSalt( id salty, size_t length );
snej@12
    47
static CSSM_RETURN impExpCreatePassKey(
snej@12
    48
	const SecKeyImportExportParameters *keyParams,  // required
snej@12
    49
	CSSM_CSP_HANDLE		cspHand,		// MUST be CSPDL
snej@12
    50
	BOOL                verifyPhrase,   // use 2nd passphrase textfield for verification?
snej@12
    51
	CSSM_KEY_PTR		*passKey);	// mallocd and RETURNED
snej@12
    52
snej@12
    53
snej@0
    54
#pragma mark -
snej@0
    55
@implementation MYSymmetricKey
snej@0
    56
snej@0
    57
snej@12
    58
- (id) _initWithCSSMKey: (CSSM_KEY*)cssmKey {
jens@16
    59
    if (!cssmKey) {
jens@16
    60
        [self release];
jens@16
    61
        return nil;
jens@16
    62
    }
snej@12
    63
    SecKeyRef keyRef = NULL;
snej@12
    64
    if (SecKeyCreate == NULL) {
snej@12
    65
        // If weak-linked SPI fn no longer exists
snej@12
    66
        Warn(@"Unable to call SecKeyCreate SPI -- not available");
snej@12
    67
        [self release];
snej@12
    68
        return nil;
snej@12
    69
    }
snej@12
    70
    if (!check(SecKeyCreate(cssmKey,&keyRef), @"SecKeyCreate")) {
snej@12
    71
        [self release];
snej@12
    72
        return nil;
snej@12
    73
    }
snej@12
    74
    self = [self initWithKeyRef: keyRef];
snej@12
    75
    if (self) {
snej@12
    76
        _ownedCSSMKey = cssmKey;            // (so I'll remember to free it)
snej@12
    77
    }
snej@12
    78
    return self;
snej@12
    79
}
snej@12
    80
snej@12
    81
snej@1
    82
- (id) _initWithKeyData: (NSData*)keyData
snej@1
    83
              algorithm: (CCAlgorithm)algorithm
snej@1
    84
             inKeychain: (MYKeychain*)keychain
snej@1
    85
{
snej@1
    86
    Assert(algorithm <= kCCAlgorithmRC4);
snej@1
    87
    Assert(keyData);
snej@13
    88
    CSSM_KEY *key = cssmKeyFromData(keyData, CSSMFromCCAlgorithm(algorithm), keychain);
snej@12
    89
    return [self _initWithCSSMKey: key];
snej@1
    90
}
snej@1
    91
snej@1
    92
- (id) initWithKeyData: (NSData*)keyData
snej@1
    93
             algorithm: (CCAlgorithm)algorithm
snej@1
    94
{
snej@1
    95
    return [self _initWithKeyData: keyData algorithm: algorithm inKeychain: nil];
snej@1
    96
}
snej@1
    97
snej@0
    98
+ (MYSymmetricKey*) _generateSymmetricKeyOfSize: (unsigned)keySizeInBits
snej@0
    99
                                      algorithm: (CCAlgorithm)algorithm
snej@0
   100
                                     inKeychain: (MYKeychain*)keychain
snej@0
   101
{
snej@0
   102
    Assert(algorithm <= kCCAlgorithmRC4);
snej@0
   103
    CSSM_KEYATTR_FLAGS flags = CSSM_KEYATTR_EXTRACTABLE;
snej@0
   104
    if (keychain)
snej@13
   105
        flags |= CSSM_KEYATTR_PERMANENT; // | CSSM_KEYATTR_SENSITIVE;   //FIX: Re-enable this bit
snej@13
   106
    else {
snej@13
   107
        flags |= CSSM_KEYATTR_RETURN_REF;
snej@13
   108
        keychain = [MYKeychain defaultKeychain]; // establish a context for the key
snej@13
   109
    }
snej@0
   110
    CSSM_KEYUSE usage = CSSM_KEYUSE_ANY;
snej@1
   111
    SecKeyRef keyRef = NULL;
snej@13
   112
    if (!check(SecKeyGenerate(keychain.keychainRefOrDefault,
snej@13
   113
                              CSSMFromCCAlgorithm(algorithm),
snej@0
   114
                              keySizeInBits, 
snej@0
   115
                              0, usage, flags, NULL, &keyRef),
snej@0
   116
               @"SecKeyGenerate")) {
snej@0
   117
        return nil;
snej@0
   118
    }
snej@1
   119
    return [[[self alloc] initWithKeyRef: keyRef] autorelease];
snej@0
   120
}
snej@0
   121
snej@0
   122
+ (MYSymmetricKey*) generateSymmetricKeyOfSize: (unsigned)keySizeInBits
snej@0
   123
                                     algorithm: (CCAlgorithm)algorithm {
snej@0
   124
    return [self _generateSymmetricKeyOfSize: keySizeInBits
snej@0
   125
                                   algorithm: algorithm
snej@0
   126
                                  inKeychain: nil];
snej@0
   127
}
snej@0
   128
snej@12
   129
+ (NSString*) promptForPassphraseWithAlertTitle: (NSString*)alertTitle
snej@12
   130
                                    alertPrompt: (NSString*)prompt
snej@12
   131
                                        creating: (BOOL)creating
snej@12
   132
{
snej@12
   133
    // Ask the user for a passphrase:
snej@12
   134
    SecKeyImportExportParameters params = {
snej@12
   135
        .version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION,
snej@12
   136
        .flags = kSecKeySecurePassphrase,
snej@12
   137
        .alertTitle = (CFStringRef)alertTitle,
snej@12
   138
        .alertPrompt = (CFStringRef)prompt,
snej@12
   139
        .keyUsage = CSSM_KEYUSE_ANY,
snej@12
   140
        .keyAttributes = CSSM_KEYATTR_EXTRACTABLE
snej@12
   141
    };
snej@12
   142
    CSSM_CSP_HANDLE cspHandle = [[MYKeychain defaultKeychain] CSPHandle];
snej@12
   143
    CSSM_KEY *passphraseKey = NULL;
snej@12
   144
    if (impExpCreatePassKey(&params, 
snej@12
   145
                            cspHandle, 
snej@12
   146
                            creating,
snej@12
   147
                            &passphraseKey) != CSSM_OK)
snej@12
   148
        return nil;
snej@12
   149
    
snej@12
   150
    MYSymmetricKey *key = [[self alloc] _initWithCSSMKey: passphraseKey];
snej@12
   151
    NSData *keyData = key.keyData;
snej@12
   152
    Assert(keyData);
snej@12
   153
    NSString *passphrase = [[NSString alloc] initWithData: keyData
snej@12
   154
                                                 encoding: NSUTF8StringEncoding];
snej@12
   155
    [key release];
snej@12
   156
    return [passphrase autorelease];
snej@12
   157
}
snej@12
   158
snej@12
   159
snej@12
   160
#define PKCS5_V2_SALT_LEN		8
snej@12
   161
#define PKCS5_V2_ITERATIONS		2048
snej@12
   162
#define PKCS5_V2_DES_IV_SIZE	8
snej@12
   163
snej@12
   164
+ (MYSymmetricKey*) generateFromUserPassphraseWithAlertTitle: (NSString*)alertTitle
snej@12
   165
                                                 alertPrompt: (NSString*)prompt
snej@12
   166
                                                     creating: (BOOL)creating
snej@12
   167
                                                        salt: (id)saltObj
snej@12
   168
{
snej@12
   169
    MYSymmetricKey *generatedKey = nil;
snej@12
   170
snej@12
   171
    // Ask the user for a passphrase:
snej@12
   172
    SecKeyImportExportParameters params = {
snej@12
   173
        .version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION,
snej@12
   174
        .flags = kSecKeySecurePassphrase,
snej@12
   175
        .alertTitle = (CFStringRef)alertTitle,
snej@12
   176
        .alertPrompt = (CFStringRef)prompt,
snej@12
   177
        .keyUsage = CSSM_KEYUSE_ANY,
snej@12
   178
        .keyAttributes = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_SENSITIVE
snej@12
   179
    };
snej@12
   180
    CSSM_CSP_HANDLE cspHandle = [[MYKeychain defaultKeychain] CSPHandle];
snej@12
   181
    CSSM_KEY *passphraseKey = NULL;
snej@12
   182
    if (impExpCreatePassKey(&params, 
snej@12
   183
                            cspHandle, 
snej@12
   184
                            creating,
snej@12
   185
                            &passphraseKey) != CSSM_OK)
snej@12
   186
        return nil;
snej@12
   187
snej@12
   188
    CSSM_DATA saltData = makeSalt(saltObj,PKCS5_V2_SALT_LEN);
snej@12
   189
    CSSM_CRYPTO_DATA seed = {};
snej@12
   190
    
snej@12
   191
    // Now use the secure passphrase to generate a symmetric key:
snej@12
   192
    CSSM_CC_HANDLE ctx = 0;
snej@12
   193
    CSSM_ACCESS_CREDENTIALS credentials = {};
snej@12
   194
    if (checkcssm(CSSM_CSP_CreateDeriveKeyContext(cspHandle,
snej@12
   195
                                                  CSSM_ALGID_PKCS5_PBKDF2,
snej@12
   196
                                                  CSSM_ALGID_AES, 128,
snej@12
   197
                                                  &credentials,
snej@12
   198
                                                  passphraseKey, 
snej@12
   199
                                                  PKCS5_V2_ITERATIONS,
snej@12
   200
                                                  &saltData,
snej@12
   201
                                                  &seed,
snej@12
   202
                                                  &ctx),
snej@12
   203
                  @"CSSM_CSP_CreateDeriveKeyContext")) {
snej@12
   204
        CSSM_PKCS5_PBKDF2_PARAMS params = {.PseudoRandomFunction=CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1};
snej@12
   205
        CSSM_DATA paramData = {.Data=(void*)&params, .Length=sizeof(params)};
snej@12
   206
        CSSM_KEY *cssmKey = calloc(1,sizeof(CSSM_KEY));
snej@12
   207
        if (checkcssm(CSSM_DeriveKey(ctx,
snej@12
   208
                                     &paramData,
snej@12
   209
                                     CSSM_KEYUSE_ANY,
snej@12
   210
                                     CSSM_KEYATTR_EXTRACTABLE, //| CSSM_KEYATTR_SENSITIVE, 
snej@12
   211
                                     NULL, 
snej@12
   212
                                     NULL, 
snej@12
   213
                                     cssmKey),
snej@12
   214
                      @"CSSM_DeriveKey")) {
snej@12
   215
            generatedKey = [[[self alloc] _initWithCSSMKey: cssmKey] autorelease];
snej@12
   216
        }
snej@12
   217
    }
snej@12
   218
    CSSM_DeleteContext(ctx);
snej@12
   219
    CSSM_FreeKey(cspHandle, &credentials, passphraseKey, YES);
snej@12
   220
    return generatedKey;        
snej@12
   221
}
snej@12
   222
snej@12
   223
snej@12
   224
- (void) dealloc
snej@12
   225
{
snej@12
   226
    if(_ownedCSSMKey) 
snej@12
   227
        CSSM_FreeKey(self.cssmCSPHandle, NULL, _ownedCSSMKey, YES);
snej@12
   228
    [super dealloc];
snej@12
   229
}
snej@12
   230
snej@0
   231
snej@2
   232
#if !TARGET_OS_IPHONE
jens@16
   233
- (id) initWithWrappedKeyData: (NSData*)wrappedKeyData {
jens@16
   234
    return [self _initWithCSSMKey: unwrapCssmKeyFromData(wrappedKeyData,
jens@16
   235
                                                         CSSM_ALGID_AES,128)];
jens@16
   236
}
jens@16
   237
jens@16
   238
snej@13
   239
- (NSData*) exportWrappedKeyWithPassphrasePrompt: (NSString*)prompt
snej@2
   240
{
jens@16
   241
    // Prompt user for a passphrase to use for the wrapping key:
snej@13
   242
    MYSymmetricKey *wrappingKey = [MYSymmetricKey 
snej@13
   243
                                   generateFromUserPassphraseWithAlertTitle: @"Export Key" 
snej@13
   244
                                   alertPrompt: prompt 
snej@13
   245
                                   creating: YES
snej@13
   246
                                   salt: [MYCryptor randomKeyOfLength: PKCS5_V2_SALT_LEN*8]];
snej@12
   247
    if (!wrappingKey)
snej@12
   248
        return nil;
snej@13
   249
    Log(@"Wrapping using %@",wrappingKey);
snej@12
   250
    
snej@12
   251
    // Create the context:
snej@13
   252
    CSSM_ACCESS_CREDENTIALS credentials = {};
snej@12
   253
    CSSM_CSP_HANDLE cspHandle = self.cssmCSPHandle;
jens@16
   254
    CSSM_ALGORITHMS algorithm = wrappingKey.cssmAlgorithm;
jens@16
   255
    uint8 iv[16] = {0}; // Right size for AES. Are zeros OK? //FIX: Support other algorithms
jens@16
   256
    CSSM_DATA ivData = {.Data=(void*)&iv, .Length=sizeof(iv)};
snej@12
   257
    CSSM_CC_HANDLE ctx;
snej@12
   258
    if (!checkcssm(CSSM_CSP_CreateSymmetricContext(cspHandle,
jens@16
   259
                                                   algorithm, //CSSM_ALGID_3DES_3KEY_EDE
jens@16
   260
                                                   defaultModeForAlgorithm(algorithm),
snej@13
   261
                                                   &credentials, 
snej@12
   262
                                                   wrappingKey.cssmKey,
jens@16
   263
                                                   &ivData,
jens@16
   264
                                                   defaultPaddingForAlgorithm(algorithm),
snej@12
   265
                                                   NULL,
snej@12
   266
                                                   &ctx), 
snej@12
   267
                   @"CSSM_CSP_CreateSymmetricContext"))
snej@12
   268
        return nil;
snej@12
   269
    
snej@13
   270
    // Now wrap the key:
snej@12
   271
    NSData *result = nil;
snej@13
   272
    CSSM_WRAP_KEY wrappedKey = {};
snej@13
   273
    if (checkcssm(CSSM_WrapKey(ctx, &credentials, self.cssmKey, NULL, &wrappedKey),
snej@13
   274
                  @"CSSM_WrapKey")) {
snej@13
   275
        // ...and copy the wrapped key data to the result NSData:
snej@13
   276
        result = [NSData dataWithBytes: wrappedKey.KeyData.Data length: wrappedKey.KeyData.Length];
snej@13
   277
        CSSM_FreeKey(cspHandle, &credentials, &wrappedKey, NO);
snej@12
   278
    }
snej@12
   279
    // Finally, delete the context
snej@12
   280
    CSSM_DeleteContext(ctx);
snej@12
   281
    return result;
snej@2
   282
}
snej@2
   283
#endif
snej@2
   284
snej@0
   285
jens@23
   286
- (SecExternalItemType) keyClass {
snej@0
   287
    return kSecItemTypeSessionKey;
snej@0
   288
}
snej@0
   289
snej@0
   290
- (CCAlgorithm) algorithm {
snej@0
   291
    CSSM_ALGORITHMS cssmAlg;
snej@0
   292
    cssmAlg = self.cssmKey->KeyHeader.AlgorithmId;
snej@0
   293
    switch(cssmAlg) {
snej@0
   294
        case CSSM_ALGID_AES:
snej@0
   295
            return kCCAlgorithmAES128;
snej@0
   296
        case CSSM_ALGID_DES:
snej@0
   297
            return kCCAlgorithmDES;	
snej@0
   298
        case CSSM_ALGID_3DES_3KEY:
snej@0
   299
            return kCCAlgorithm3DES;
snej@0
   300
        case CSSM_ALGID_CAST:
snej@0
   301
            return kCCAlgorithmCAST;
snej@0
   302
        case CSSM_ALGID_RC4:
snej@0
   303
            return kCCAlgorithmRC4;	
snej@0
   304
        default:
snej@0
   305
            Warn(@"CSSM_ALGORITHMS #%u doesn't map to any CCAlgorithm", cssmAlg);
snej@0
   306
            return (CCAlgorithm)-1;
snej@0
   307
    }
snej@0
   308
}
snej@0
   309
snej@2
   310
- (const char*) algorithmName {
snej@2
   311
    CCAlgorithm a = self.algorithm;
snej@2
   312
    if (a >= 0 && a <= kCCAlgorithmRC4)
snej@2
   313
        return kCCAlgorithmNames[a];
snej@2
   314
    else
snej@2
   315
        return "???";
snej@2
   316
}
snej@2
   317
snej@2
   318
- (unsigned) keySizeInBits {
snej@2
   319
    const CSSM_KEY *key = self.cssmKey;
snej@2
   320
    Assert(key);
snej@2
   321
    return key->KeyHeader.LogicalKeySizeInBits;
snej@2
   322
}
snej@2
   323
snej@2
   324
snej@2
   325
- (NSString*) description {
snej@2
   326
    return $sprintf(@"%@[%u-bit %s]", [self class], self.keySizeInBits, self.algorithmName);
snej@2
   327
}
snej@2
   328
snej@0
   329
snej@0
   330
- (NSData*) _cryptData: (NSData*)data operation: (CCOperation)op options: (CCOptions)options
snej@0
   331
{
snej@0
   332
    NSData *keyData = self.keyData;
snej@0
   333
    Assert(keyData, @"Couldn't get key data");
snej@0
   334
    NSMutableData *output = [NSMutableData dataWithLength: data.length + 256];
snej@0
   335
    size_t bytesWritten = 0;
snej@0
   336
    CCCryptorStatus status = CCCrypt(op, self.algorithm, options, 
snej@0
   337
                                     keyData.bytes, keyData.length, NULL,
snej@0
   338
                                     data.bytes, data.length, output.mutableBytes, output.length,
snej@0
   339
                                     &bytesWritten);
snej@0
   340
    if (status) {
snej@0
   341
        Warn(@"MYSymmetricKey: CCCrypt returned error %i",status);
snej@0
   342
        return nil;
snej@0
   343
    }
snej@0
   344
    output.length = bytesWritten;
snej@0
   345
    return output;
snej@0
   346
}
snej@0
   347
snej@0
   348
- (NSData*) encryptData: (NSData*)data {
snej@0
   349
    return [self _cryptData: data operation: kCCEncrypt options: kCCOptionPKCS7Padding];
snej@0
   350
}
snej@0
   351
snej@0
   352
snej@0
   353
- (NSData*) decryptData: (NSData*)data {
snej@0
   354
    return [self _cryptData: data operation: kCCDecrypt options: kCCOptionPKCS7Padding];
snej@0
   355
}
snej@0
   356
snej@0
   357
snej@0
   358
@end
snej@0
   359
snej@0
   360
snej@12
   361
#pragma mark -
snej@12
   362
snej@12
   363
snej@12
   364
static CSSM_KEY* cssmKeyFromData( NSData *keyData, 
snej@12
   365
                                 CSSM_ALGORITHMS algorithm,
snej@12
   366
                                 MYKeychain *keychain ) {
snej@12
   367
    // Thanks to Jim Murphy for showing the way!
snej@12
   368
    if (!keychain) keychain = [MYKeychain defaultKeychain];
snej@0
   369
    CSSM_CC_HANDLE ccHandle;
snej@12
   370
    if (!checkcssm(CSSM_CSP_CreateSymmetricContext([keychain CSPHandle],
snej@12
   371
                                                   CSSM_ALGID_NONE, CSSM_ALGMODE_WRAP,
snej@12
   372
                                                   NULL, NULL, NULL,
snej@12
   373
                                                   CSSM_PADDING_NONE, NULL,
snej@12
   374
                                                   &ccHandle), 
snej@12
   375
                   @"CSSM_CSP_CreateSymmetricContext"))
snej@12
   376
        return NO;
snej@0
   377
    
snej@12
   378
    CSSM_KEY wrappedKey = {
snej@12
   379
        .KeyHeader = {
snej@12
   380
            .BlobType = CSSM_KEYBLOB_RAW,
snej@12
   381
            .Format = CSSM_KEYBLOB_RAW_FORMAT_NONE,
snej@12
   382
            .AlgorithmId = algorithm,
snej@12
   383
            .KeyClass = CSSM_KEYCLASS_SESSION_KEY,
snej@12
   384
            .LogicalKeySizeInBits = keyData.length*8,
snej@12
   385
            .KeyAttr = CSSM_KEYATTR_EXTRACTABLE,
snej@12
   386
            .KeyUsage = CSSM_KEYUSE_ANY
snej@12
   387
        },
snej@12
   388
        .KeyData = {
snej@12
   389
            .Data = (void*)keyData.bytes,
snej@12
   390
            .Length = keyData.length
snej@12
   391
        }
snej@12
   392
    };
snej@12
   393
    
snej@12
   394
    CSSM_KEY *outKey = calloc(sizeof(CSSM_KEY),1);
snej@12
   395
    CSSM_DATA desc = {};
snej@12
   396
    if (!checkcssm(CSSM_UnwrapKey(ccHandle,
snej@12
   397
                                  NULL,
snej@12
   398
                                  &wrappedKey,
snej@12
   399
                                  CSSM_KEYUSE_ANY,
snej@12
   400
                                  CSSM_KEYATTR_EXTRACTABLE,
snej@12
   401
                                  NULL,
snej@12
   402
                                  NULL,
snej@12
   403
                                  outKey,
snej@12
   404
                                  &desc),
snej@12
   405
                   @"CSSM_UnwrapKey")) {
snej@12
   406
        free(outKey);
snej@12
   407
        outKey = NULL;
snej@0
   408
    }
snej@0
   409
    CSSM_DeleteContext(ccHandle);
snej@12
   410
    return outKey;
snej@0
   411
}
snej@12
   412
snej@12
   413
jens@16
   414
#if !TARGET_OS_IPHONE
jens@16
   415
static CSSM_KEY* unwrapCssmKeyFromData(NSData *wrappedData,
jens@16
   416
                                       CSSM_ALGORITHMS algorithm,
jens@16
   417
                                       unsigned sizeInBits) {
jens@16
   418
    Warn(@"MYSymmetricKey: unwrapping is unimplemented; sorry");
jens@16
   419
    return nil;
jens@16
   420
#if 0 //not finished yet
jens@16
   421
    // First create a wrapped-key structure from the data:
jens@16
   422
    CSSM_WRAP_KEY wrappedKey = {
jens@16
   423
        .KeyHeader = {
jens@16
   424
            .BlobType = CSSM_KEYBLOB_WRAPPED,
jens@16
   425
            .Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS3,
jens@16
   426
            .AlgorithmId = algorithm,
jens@16
   427
            .KeyClass = CSSM_KEYCLASS_SESSION_KEY,
jens@16
   428
            .LogicalKeySizeInBits = sizeInBits,
jens@16
   429
            .KeyAttr = CSSM_KEYATTR_EXTRACTABLE,
jens@16
   430
            .KeyUsage = CSSM_KEYUSE_ANY,
jens@16
   431
            .WrapAlgorithmId = CSSM_ALGID_AES,
jens@16
   432
        },
jens@16
   433
        .KeyData = {
jens@16
   434
            .Data = (void*)wrappedData.bytes,
jens@16
   435
            .Length = wrappedData.length
jens@16
   436
        }
jens@16
   437
    };
jens@16
   438
#endif
jens@16
   439
}    
jens@16
   440
#endif
jens@16
   441
jens@16
   442
snej@12
   443
// Create salt data of a specific length from an arbitrary NSObject. */
snej@12
   444
static CSSM_DATA makeSalt( id salty, size_t length ) {
snej@12
   445
    // Convert to NSData if necessary:
snej@12
   446
    CAssert(salty!=nil);
snej@12
   447
    if (![salty isKindOfClass: [NSData class]])
snej@12
   448
        salty = [[salty description] dataUsingEncoding: NSUTF8StringEncoding];
snej@12
   449
    // Repeat enough times to fill the desired length:
snej@12
   450
    NSMutableData *salt = [[salty mutableCopy] autorelease];
snej@12
   451
    CAssert(salt.length>0);
snej@12
   452
    while (salt.length < length) {
snej@12
   453
        [salt appendData: salt];
snej@12
   454
    }
snej@12
   455
    // Truncate to length and return it:
snej@12
   456
    salt.length = length;
snej@12
   457
    return (CSSM_DATA){.Data=(void*)salt.bytes, .Length=salt.length};
snej@12
   458
}
snej@12
   459
snej@12
   460
snej@13
   461
#pragma mark -
snej@13
   462
// Code from Keychain.framework:
jens@16
   463
jens@16
   464
#if !TARGET_OS_IPHONE
jens@16
   465
#if 1
snej@13
   466
static CSSM_ENCRYPT_MODE defaultModeForAlgorithm(CSSM_ALGORITHMS algorithm) {
snej@13
   467
    switch(algorithm) {
snej@13
   468
        // 8-byte block ciphers
snej@13
   469
        case CSSM_ALGID_DES:
snej@13
   470
        case CSSM_ALGID_3DES_3KEY_EDE:
snej@13
   471
        case CSSM_ALGID_RC5:
snej@13
   472
        case CSSM_ALGID_RC2:
snej@13
   473
            return CSSM_ALGMODE_CBCPadIV8; break;
snej@13
   474
        // 16-byte block ciphers
snej@13
   475
        case CSSM_ALGID_AES:
snej@13
   476
            return CSSM_ALGMODE_CBCPadIV8; break;
snej@13
   477
        // stream ciphers
snej@13
   478
        case CSSM_ALGID_ASC:
snej@13
   479
        case CSSM_ALGID_RC4:
snej@13
   480
            return CSSM_ALGMODE_NONE; break;
snej@13
   481
        // Unknown
snej@13
   482
        default:
snej@13
   483
        	Warn(@"Asked for the default mode for algorithm %d, but don't know that algorithm.\n", algorithm);
snej@13
   484
            return CSSM_ALGMODE_NONE;
snej@13
   485
    }
snej@13
   486
}
jens@16
   487
#endif
snej@13
   488
jens@16
   489
#if 1
jens@16
   490
static CSSM_PADDING defaultPaddingForAlgorithm(CSSM_ALGORITHMS algorithm) {
snej@13
   491
    switch(algorithm) {
snej@13
   492
        /* 8-byte block ciphers */
snej@13
   493
        case CSSM_ALGID_DES:
snej@13
   494
        case CSSM_ALGID_3DES_3KEY_EDE:
snej@13
   495
        case CSSM_ALGID_RC5:
snej@13
   496
        case CSSM_ALGID_RC2:
snej@13
   497
            return CSSM_PADDING_PKCS5; break;
snej@13
   498
            /* 16-byte block ciphers */
snej@13
   499
        case CSSM_ALGID_AES:
snej@13
   500
            return CSSM_PADDING_PKCS7; break;
snej@13
   501
            /* stream ciphers */
snej@13
   502
        case CSSM_ALGID_ASC:
snej@13
   503
        case CSSM_ALGID_RC4:
snej@13
   504
            return CSSM_PADDING_NONE; break;
snej@13
   505
            /* RSA/DSA asymmetric */
snej@13
   506
        case CSSM_ALGID_DSA:
snej@13
   507
        case CSSM_ALGID_RSA:
snej@13
   508
            return CSSM_PADDING_PKCS1; break;
snej@13
   509
            /* Unknown */
snej@13
   510
        default:
snej@13
   511
        	Warn(@"Asked for the default padding mode for %d, but don't know that algorithm.\n", algorithm);
snej@13
   512
            return CSSM_PADDING_NONE;
snej@13
   513
    }
snej@13
   514
}
snej@13
   515
#endif
jens@16
   516
#endif
snej@13
   517
snej@13
   518
#pragma mark -
snej@13
   519
// Code below was copied from SecImportExportUtils.cpp in Apple's libsecurity_keychain project
snej@13
   520
snej@13
   521
snej@12
   522
/*
snej@12
   523
 * Given a context specified via a CSSM_CC_HANDLE, add a new
snej@12
   524
 * CSSM_CONTEXT_ATTRIBUTE to the context as specified by AttributeType,
snej@12
   525
 * AttributeLength, and an untyped pointer.
snej@12
   526
 */
snej@12
   527
static CSSM_RETURN impExpAddContextAttribute(CSSM_CC_HANDLE CCHandle,
snej@12
   528
	uint32 AttributeType,
snej@12
   529
	uint32 AttributeLength,
snej@12
   530
	const void *AttributePtr)
snej@12
   531
{
snej@12
   532
	CSSM_CONTEXT_ATTRIBUTE		newAttr;	
snej@12
   533
	
snej@12
   534
	newAttr.AttributeType     = AttributeType;
snej@12
   535
	newAttr.AttributeLength   = AttributeLength;
snej@12
   536
	newAttr.Attribute.Data    = (CSSM_DATA_PTR)AttributePtr;
snej@12
   537
	return CSSM_UpdateContextAttributes(CCHandle, 1, &newAttr);
snej@12
   538
}
snej@12
   539
snej@12
   540
/* 
snej@12
   541
* Add a CFString to a crypto context handle. 
snej@0
   542
*/
snej@12
   543
static CSSM_RETURN impExpAddStringAttr(
snej@12
   544
	CSSM_CC_HANDLE ccHand, 
snej@12
   545
	CFStringRef str,
snej@12
   546
	CSSM_ATTRIBUTE_TYPE attrType)
snej@12
   547
{
snej@12
   548
	/* CFStrings are passed as external rep in UTF8 encoding by convention */
snej@12
   549
	CFDataRef outData;
snej@12
   550
	outData = CFStringCreateExternalRepresentation(NULL,
snej@12
   551
		str, kCFStringEncodingUTF8,	0);		// lossByte 0 ==> no loss allowed 
snej@12
   552
	if(outData == NULL) {
snej@12
   553
		Warn(@"impExpAddStringAttr: bad string format");
snej@12
   554
		return paramErr;
snej@12
   555
	}
snej@12
   556
	
snej@12
   557
	CSSM_DATA attrData;
snej@12
   558
	attrData.Data = (uint8 *)CFDataGetBytePtr(outData);
snej@12
   559
	attrData.Length = CFDataGetLength(outData);
snej@12
   560
	CSSM_RETURN crtn = impExpAddContextAttribute(ccHand, attrType, sizeof(CSSM_DATA),
snej@12
   561
		&attrData);
snej@12
   562
	CFRelease(outData);
snej@12
   563
	if(crtn) {
snej@12
   564
		Warn(@"impExpAddStringAttr: CSSM_UpdateContextAttributes error");
snej@12
   565
	}
snej@12
   566
	return crtn;
snej@12
   567
}
snej@12
   568
snej@12
   569
/*
snej@12
   570
 * Generate a secure passphrase key. Caller must eventually CSSM_FreeKey the result. 
snej@12
   571
 */
snej@12
   572
static CSSM_RETURN impExpCreatePassKey(
snej@12
   573
	const SecKeyImportExportParameters *keyParams,  // required
snej@12
   574
	CSSM_CSP_HANDLE		cspHand,		// MUST be CSPDL
snej@12
   575
	BOOL                verifyPhrase,   // use 2nd passphrase textfield for verification?
snej@12
   576
	CSSM_KEY_PTR		*passKey)		// mallocd and RETURNED
snej@12
   577
{
snej@12
   578
	CSSM_RETURN crtn;
snej@12
   579
	CSSM_CC_HANDLE ccHand;
snej@12
   580
	uint32 verifyAttr;
snej@12
   581
	CSSM_DATA dummyLabel;
snej@12
   582
	CSSM_KEY_PTR ourKey = NULL;
snej@12
   583
	
snej@12
   584
	Log(@"Generating secure passphrase key");
snej@12
   585
	ourKey = (CSSM_KEY_PTR)malloc(sizeof(CSSM_KEY));
snej@12
   586
	if(ourKey == NULL) {
snej@12
   587
		return memFullErr;
snej@12
   588
	}
snej@12
   589
	memset(ourKey, 0, sizeof(CSSM_KEY));
snej@12
   590
	
snej@12
   591
	crtn = CSSM_CSP_CreateKeyGenContext(cspHand,
snej@12
   592
		CSSM_ALGID_SECURE_PASSPHRASE,
snej@12
   593
		4,				// keySizeInBits must be non zero
snej@12
   594
		NULL,			// Seed
snej@12
   595
		NULL,			// Salt
snej@12
   596
		NULL,			// StartDate
snej@12
   597
		NULL,			// EndDate
snej@12
   598
		NULL,			// Params
snej@12
   599
		&ccHand);
snej@12
   600
	if(crtn) {
snej@12
   601
		checkcssm(crtn,@"CSSM_CSP_CreateKeyGenContext");
snej@12
   602
		return crtn;
snej@12
   603
	}
snej@12
   604
	/* subsequent errors to errOut: */
snej@12
   605
	
snej@12
   606
	/* additional context attributes specific to this type of key gen */
snej@12
   607
	CAssert(keyParams != NULL);			// or we wouldn't be here
snej@12
   608
	if(keyParams->alertTitle != NULL) {
snej@12
   609
		crtn = impExpAddStringAttr(ccHand, keyParams->alertTitle, 
snej@12
   610
			CSSM_ATTRIBUTE_ALERT_TITLE);
snej@12
   611
		if(crtn) {
snej@12
   612
			goto errOut;
snej@12
   613
		}
snej@12
   614
	}
snej@12
   615
	if(keyParams->alertPrompt != NULL) {
snej@12
   616
		crtn = impExpAddStringAttr(ccHand, keyParams->alertPrompt, 
snej@12
   617
			CSSM_ATTRIBUTE_PROMPT);
snej@12
   618
		if(crtn) {
snej@12
   619
			goto errOut;
snej@12
   620
		}
snej@12
   621
	}
snej@12
   622
	verifyAttr = verifyPhrase ? 1 : 0;
snej@12
   623
	crtn = impExpAddContextAttribute(ccHand, CSSM_ATTRIBUTE_VERIFY_PASSPHRASE,
snej@12
   624
		sizeof(uint32), (const void *)verifyAttr);
snej@12
   625
	if(crtn) {
snej@12
   626
		checkcssm(crtn,@"impExpAddContextAttribute");
snej@12
   627
		goto errOut;
snej@12
   628
	}
snej@12
   629
snej@12
   630
	dummyLabel.Data = (uint8 *)"Secure Passphrase";
snej@12
   631
	dummyLabel.Length = strlen((char *)dummyLabel.Data);
snej@12
   632
    
snej@12
   633
    uint32 keyAttr = keyParams->keyAttributes;
snej@12
   634
    if (keyAttr & CSSM_KEYATTR_SENSITIVE)
snej@12
   635
        keyAttr |= CSSM_KEYATTR_RETURN_REF;
snej@12
   636
    else
snej@12
   637
        keyAttr |= CSSM_KEYATTR_EXTRACTABLE;
snej@12
   638
snej@12
   639
	crtn = CSSM_GenerateKey(ccHand,
snej@12
   640
        keyParams->keyUsage ?: CSSM_KEYUSE_ANY,
snej@12
   641
		keyAttr,
snej@12
   642
		&dummyLabel,
snej@12
   643
		NULL,			// ACL
snej@12
   644
		ourKey);
snej@12
   645
	if(crtn) {
snej@12
   646
		checkcssm(crtn,@"CSSM_GenerateKey");
snej@12
   647
	}
snej@12
   648
errOut:
snej@12
   649
	CSSM_DeleteContext(ccHand);
snej@12
   650
	if(crtn == CSSM_OK) {
snej@12
   651
		*passKey = ourKey;
snej@12
   652
	}
snej@12
   653
	else if(ourKey != NULL) {
snej@12
   654
		free(ourKey);
snej@12
   655
	}
snej@12
   656
	return crtn;
snej@12
   657
}
snej@12
   658
	
snej@12
   659
snej@12
   660
#endif !MYCRYPTO_USE_IPHONE_API
snej@14
   661
snej@14
   662
snej@14
   663
snej@14
   664
/*
snej@14
   665
 Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
snej@14
   666
 
snej@14
   667
 Redistribution and use in source and binary forms, with or without modification, are permitted
snej@14
   668
 provided that the following conditions are met:
snej@14
   669
 
snej@14
   670
 * Redistributions of source code must retain the above copyright notice, this list of conditions
snej@14
   671
 and the following disclaimer.
snej@14
   672
 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
snej@14
   673
 and the following disclaimer in the documentation and/or other materials provided with the
snej@14
   674
 distribution.
snej@14
   675
 
snej@14
   676
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
snej@14
   677
 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
snej@14
   678
 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
snej@14
   679
 BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
snej@14
   680
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
snej@14
   681
  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
snej@14
   682
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
snej@14
   683
 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
snej@14
   684
 */