MYSymmetricKey.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@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
snej@2
   319
- (NSString*) description {
snej@2
   320
    return $sprintf(@"%@[%u-bit %s]", [self class], self.keySizeInBits, self.algorithmName);
snej@2
   321
}
snej@2
   322
snej@0
   323
snej@0
   324
- (NSData*) _cryptData: (NSData*)data operation: (CCOperation)op options: (CCOptions)options
snej@0
   325
{
snej@0
   326
    NSData *keyData = self.keyData;
snej@0
   327
    Assert(keyData, @"Couldn't get key data");
snej@0
   328
    NSMutableData *output = [NSMutableData dataWithLength: data.length + 256];
snej@0
   329
    size_t bytesWritten = 0;
snej@0
   330
    CCCryptorStatus status = CCCrypt(op, self.algorithm, options, 
snej@0
   331
                                     keyData.bytes, keyData.length, NULL,
snej@0
   332
                                     data.bytes, data.length, output.mutableBytes, output.length,
snej@0
   333
                                     &bytesWritten);
snej@0
   334
    if (status) {
snej@0
   335
        Warn(@"MYSymmetricKey: CCCrypt returned error %i",status);
snej@0
   336
        return nil;
snej@0
   337
    }
snej@0
   338
    output.length = bytesWritten;
snej@0
   339
    return output;
snej@0
   340
}
snej@0
   341
snej@0
   342
- (NSData*) encryptData: (NSData*)data {
snej@0
   343
    return [self _cryptData: data operation: kCCEncrypt options: kCCOptionPKCS7Padding];
snej@0
   344
}
snej@0
   345
snej@0
   346
snej@0
   347
- (NSData*) decryptData: (NSData*)data {
snej@0
   348
    return [self _cryptData: data operation: kCCDecrypt options: kCCOptionPKCS7Padding];
snej@0
   349
}
snej@0
   350
snej@0
   351
snej@0
   352
@end
snej@0
   353
snej@0
   354
snej@12
   355
#pragma mark -
snej@12
   356
snej@12
   357
snej@12
   358
static CSSM_KEY* cssmKeyFromData( NSData *keyData, 
snej@12
   359
                                 CSSM_ALGORITHMS algorithm,
snej@12
   360
                                 MYKeychain *keychain ) {
snej@12
   361
    // Thanks to Jim Murphy for showing the way!
snej@12
   362
    if (!keychain) keychain = [MYKeychain defaultKeychain];
snej@0
   363
    CSSM_CC_HANDLE ccHandle;
snej@12
   364
    if (!checkcssm(CSSM_CSP_CreateSymmetricContext([keychain CSPHandle],
snej@12
   365
                                                   CSSM_ALGID_NONE, CSSM_ALGMODE_WRAP,
snej@12
   366
                                                   NULL, NULL, NULL,
snej@12
   367
                                                   CSSM_PADDING_NONE, NULL,
snej@12
   368
                                                   &ccHandle), 
snej@12
   369
                   @"CSSM_CSP_CreateSymmetricContext"))
snej@12
   370
        return NO;
snej@0
   371
    
snej@12
   372
    CSSM_KEY wrappedKey = {
snej@12
   373
        .KeyHeader = {
snej@12
   374
            .BlobType = CSSM_KEYBLOB_RAW,
snej@12
   375
            .Format = CSSM_KEYBLOB_RAW_FORMAT_NONE,
snej@12
   376
            .AlgorithmId = algorithm,
snej@12
   377
            .KeyClass = CSSM_KEYCLASS_SESSION_KEY,
snej@12
   378
            .LogicalKeySizeInBits = keyData.length*8,
snej@12
   379
            .KeyAttr = CSSM_KEYATTR_EXTRACTABLE,
snej@12
   380
            .KeyUsage = CSSM_KEYUSE_ANY
snej@12
   381
        },
snej@12
   382
        .KeyData = {
snej@12
   383
            .Data = (void*)keyData.bytes,
snej@12
   384
            .Length = keyData.length
snej@12
   385
        }
snej@12
   386
    };
snej@12
   387
    
snej@12
   388
    CSSM_KEY *outKey = calloc(sizeof(CSSM_KEY),1);
snej@12
   389
    CSSM_DATA desc = {};
snej@12
   390
    if (!checkcssm(CSSM_UnwrapKey(ccHandle,
snej@12
   391
                                  NULL,
snej@12
   392
                                  &wrappedKey,
snej@12
   393
                                  CSSM_KEYUSE_ANY,
snej@12
   394
                                  CSSM_KEYATTR_EXTRACTABLE,
snej@12
   395
                                  NULL,
snej@12
   396
                                  NULL,
snej@12
   397
                                  outKey,
snej@12
   398
                                  &desc),
snej@12
   399
                   @"CSSM_UnwrapKey")) {
snej@12
   400
        free(outKey);
snej@12
   401
        outKey = NULL;
snej@0
   402
    }
snej@0
   403
    CSSM_DeleteContext(ccHandle);
snej@12
   404
    return outKey;
snej@0
   405
}
snej@12
   406
snej@12
   407
jens@16
   408
#if !TARGET_OS_IPHONE
jens@16
   409
static CSSM_KEY* unwrapCssmKeyFromData(NSData *wrappedData,
jens@16
   410
                                       CSSM_ALGORITHMS algorithm,
jens@16
   411
                                       unsigned sizeInBits) {
jens@16
   412
    Warn(@"MYSymmetricKey: unwrapping is unimplemented; sorry");
jens@16
   413
    return nil;
jens@16
   414
#if 0 //not finished yet
jens@16
   415
    // First create a wrapped-key structure from the data:
jens@16
   416
    CSSM_WRAP_KEY wrappedKey = {
jens@16
   417
        .KeyHeader = {
jens@16
   418
            .BlobType = CSSM_KEYBLOB_WRAPPED,
jens@16
   419
            .Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS3,
jens@16
   420
            .AlgorithmId = algorithm,
jens@16
   421
            .KeyClass = CSSM_KEYCLASS_SESSION_KEY,
jens@16
   422
            .LogicalKeySizeInBits = sizeInBits,
jens@16
   423
            .KeyAttr = CSSM_KEYATTR_EXTRACTABLE,
jens@16
   424
            .KeyUsage = CSSM_KEYUSE_ANY,
jens@16
   425
            .WrapAlgorithmId = CSSM_ALGID_AES,
jens@16
   426
        },
jens@16
   427
        .KeyData = {
jens@16
   428
            .Data = (void*)wrappedData.bytes,
jens@16
   429
            .Length = wrappedData.length
jens@16
   430
        }
jens@16
   431
    };
jens@16
   432
#endif
jens@16
   433
}    
jens@16
   434
#endif
jens@16
   435
jens@16
   436
snej@12
   437
// Create salt data of a specific length from an arbitrary NSObject. */
snej@12
   438
static CSSM_DATA makeSalt( id salty, size_t length ) {
snej@12
   439
    // Convert to NSData if necessary:
snej@12
   440
    CAssert(salty!=nil);
snej@12
   441
    if (![salty isKindOfClass: [NSData class]])
snej@12
   442
        salty = [[salty description] dataUsingEncoding: NSUTF8StringEncoding];
snej@12
   443
    // Repeat enough times to fill the desired length:
snej@12
   444
    NSMutableData *salt = [[salty mutableCopy] autorelease];
snej@12
   445
    CAssert(salt.length>0);
snej@12
   446
    while (salt.length < length) {
snej@12
   447
        [salt appendData: salt];
snej@12
   448
    }
snej@12
   449
    // Truncate to length and return it:
snej@12
   450
    salt.length = length;
snej@12
   451
    return (CSSM_DATA){.Data=(void*)salt.bytes, .Length=salt.length};
snej@12
   452
}
snej@12
   453
snej@12
   454
snej@13
   455
#pragma mark -
snej@13
   456
// Code from Keychain.framework:
jens@16
   457
jens@16
   458
#if !TARGET_OS_IPHONE
jens@16
   459
#if 1
snej@13
   460
static CSSM_ENCRYPT_MODE defaultModeForAlgorithm(CSSM_ALGORITHMS algorithm) {
snej@13
   461
    switch(algorithm) {
snej@13
   462
        // 8-byte block ciphers
snej@13
   463
        case CSSM_ALGID_DES:
snej@13
   464
        case CSSM_ALGID_3DES_3KEY_EDE:
snej@13
   465
        case CSSM_ALGID_RC5:
snej@13
   466
        case CSSM_ALGID_RC2:
snej@13
   467
            return CSSM_ALGMODE_CBCPadIV8; break;
snej@13
   468
        // 16-byte block ciphers
snej@13
   469
        case CSSM_ALGID_AES:
snej@13
   470
            return CSSM_ALGMODE_CBCPadIV8; break;
snej@13
   471
        // stream ciphers
snej@13
   472
        case CSSM_ALGID_ASC:
snej@13
   473
        case CSSM_ALGID_RC4:
snej@13
   474
            return CSSM_ALGMODE_NONE; break;
snej@13
   475
        // Unknown
snej@13
   476
        default:
snej@13
   477
        	Warn(@"Asked for the default mode for algorithm %d, but don't know that algorithm.\n", algorithm);
snej@13
   478
            return CSSM_ALGMODE_NONE;
snej@13
   479
    }
snej@13
   480
}
jens@16
   481
#endif
snej@13
   482
jens@16
   483
#if 1
jens@16
   484
static CSSM_PADDING defaultPaddingForAlgorithm(CSSM_ALGORITHMS algorithm) {
snej@13
   485
    switch(algorithm) {
snej@13
   486
        /* 8-byte block ciphers */
snej@13
   487
        case CSSM_ALGID_DES:
snej@13
   488
        case CSSM_ALGID_3DES_3KEY_EDE:
snej@13
   489
        case CSSM_ALGID_RC5:
snej@13
   490
        case CSSM_ALGID_RC2:
snej@13
   491
            return CSSM_PADDING_PKCS5; break;
snej@13
   492
            /* 16-byte block ciphers */
snej@13
   493
        case CSSM_ALGID_AES:
snej@13
   494
            return CSSM_PADDING_PKCS7; break;
snej@13
   495
            /* stream ciphers */
snej@13
   496
        case CSSM_ALGID_ASC:
snej@13
   497
        case CSSM_ALGID_RC4:
snej@13
   498
            return CSSM_PADDING_NONE; break;
snej@13
   499
            /* RSA/DSA asymmetric */
snej@13
   500
        case CSSM_ALGID_DSA:
snej@13
   501
        case CSSM_ALGID_RSA:
snej@13
   502
            return CSSM_PADDING_PKCS1; break;
snej@13
   503
            /* Unknown */
snej@13
   504
        default:
snej@13
   505
        	Warn(@"Asked for the default padding mode for %d, but don't know that algorithm.\n", algorithm);
snej@13
   506
            return CSSM_PADDING_NONE;
snej@13
   507
    }
snej@13
   508
}
snej@13
   509
#endif
jens@16
   510
#endif
snej@13
   511
snej@13
   512
#pragma mark -
snej@13
   513
// Code below was copied from SecImportExportUtils.cpp in Apple's libsecurity_keychain project
snej@13
   514
snej@13
   515
snej@12
   516
/*
snej@12
   517
 * Given a context specified via a CSSM_CC_HANDLE, add a new
snej@12
   518
 * CSSM_CONTEXT_ATTRIBUTE to the context as specified by AttributeType,
snej@12
   519
 * AttributeLength, and an untyped pointer.
snej@12
   520
 */
snej@12
   521
static CSSM_RETURN impExpAddContextAttribute(CSSM_CC_HANDLE CCHandle,
snej@12
   522
	uint32 AttributeType,
snej@12
   523
	uint32 AttributeLength,
snej@12
   524
	const void *AttributePtr)
snej@12
   525
{
snej@12
   526
	CSSM_CONTEXT_ATTRIBUTE		newAttr;	
snej@12
   527
	
snej@12
   528
	newAttr.AttributeType     = AttributeType;
snej@12
   529
	newAttr.AttributeLength   = AttributeLength;
snej@12
   530
	newAttr.Attribute.Data    = (CSSM_DATA_PTR)AttributePtr;
snej@12
   531
	return CSSM_UpdateContextAttributes(CCHandle, 1, &newAttr);
snej@12
   532
}
snej@12
   533
snej@12
   534
/* 
snej@12
   535
* Add a CFString to a crypto context handle. 
snej@0
   536
*/
snej@12
   537
static CSSM_RETURN impExpAddStringAttr(
snej@12
   538
	CSSM_CC_HANDLE ccHand, 
snej@12
   539
	CFStringRef str,
snej@12
   540
	CSSM_ATTRIBUTE_TYPE attrType)
snej@12
   541
{
snej@12
   542
	/* CFStrings are passed as external rep in UTF8 encoding by convention */
snej@12
   543
	CFDataRef outData;
snej@12
   544
	outData = CFStringCreateExternalRepresentation(NULL,
snej@12
   545
		str, kCFStringEncodingUTF8,	0);		// lossByte 0 ==> no loss allowed 
snej@12
   546
	if(outData == NULL) {
snej@12
   547
		Warn(@"impExpAddStringAttr: bad string format");
snej@12
   548
		return paramErr;
snej@12
   549
	}
snej@12
   550
	
snej@12
   551
	CSSM_DATA attrData;
snej@12
   552
	attrData.Data = (uint8 *)CFDataGetBytePtr(outData);
snej@12
   553
	attrData.Length = CFDataGetLength(outData);
snej@12
   554
	CSSM_RETURN crtn = impExpAddContextAttribute(ccHand, attrType, sizeof(CSSM_DATA),
snej@12
   555
		&attrData);
snej@12
   556
	CFRelease(outData);
snej@12
   557
	if(crtn) {
snej@12
   558
		Warn(@"impExpAddStringAttr: CSSM_UpdateContextAttributes error");
snej@12
   559
	}
snej@12
   560
	return crtn;
snej@12
   561
}
snej@12
   562
snej@12
   563
/*
snej@12
   564
 * Generate a secure passphrase key. Caller must eventually CSSM_FreeKey the result. 
snej@12
   565
 */
snej@12
   566
static CSSM_RETURN impExpCreatePassKey(
snej@12
   567
	const SecKeyImportExportParameters *keyParams,  // required
snej@12
   568
	CSSM_CSP_HANDLE		cspHand,		// MUST be CSPDL
snej@12
   569
	BOOL                verifyPhrase,   // use 2nd passphrase textfield for verification?
snej@12
   570
	CSSM_KEY_PTR		*passKey)		// mallocd and RETURNED
snej@12
   571
{
snej@12
   572
	CSSM_RETURN crtn;
snej@12
   573
	CSSM_CC_HANDLE ccHand;
snej@12
   574
	uint32 verifyAttr;
snej@12
   575
	CSSM_DATA dummyLabel;
snej@12
   576
	CSSM_KEY_PTR ourKey = NULL;
snej@12
   577
	
snej@12
   578
	Log(@"Generating secure passphrase key");
snej@12
   579
	ourKey = (CSSM_KEY_PTR)malloc(sizeof(CSSM_KEY));
snej@12
   580
	if(ourKey == NULL) {
snej@12
   581
		return memFullErr;
snej@12
   582
	}
snej@12
   583
	memset(ourKey, 0, sizeof(CSSM_KEY));
snej@12
   584
	
snej@12
   585
	crtn = CSSM_CSP_CreateKeyGenContext(cspHand,
snej@12
   586
		CSSM_ALGID_SECURE_PASSPHRASE,
snej@12
   587
		4,				// keySizeInBits must be non zero
snej@12
   588
		NULL,			// Seed
snej@12
   589
		NULL,			// Salt
snej@12
   590
		NULL,			// StartDate
snej@12
   591
		NULL,			// EndDate
snej@12
   592
		NULL,			// Params
snej@12
   593
		&ccHand);
snej@12
   594
	if(crtn) {
snej@12
   595
		checkcssm(crtn,@"CSSM_CSP_CreateKeyGenContext");
snej@12
   596
		return crtn;
snej@12
   597
	}
snej@12
   598
	/* subsequent errors to errOut: */
snej@12
   599
	
snej@12
   600
	/* additional context attributes specific to this type of key gen */
snej@12
   601
	CAssert(keyParams != NULL);			// or we wouldn't be here
snej@12
   602
	if(keyParams->alertTitle != NULL) {
snej@12
   603
		crtn = impExpAddStringAttr(ccHand, keyParams->alertTitle, 
snej@12
   604
			CSSM_ATTRIBUTE_ALERT_TITLE);
snej@12
   605
		if(crtn) {
snej@12
   606
			goto errOut;
snej@12
   607
		}
snej@12
   608
	}
snej@12
   609
	if(keyParams->alertPrompt != NULL) {
snej@12
   610
		crtn = impExpAddStringAttr(ccHand, keyParams->alertPrompt, 
snej@12
   611
			CSSM_ATTRIBUTE_PROMPT);
snej@12
   612
		if(crtn) {
snej@12
   613
			goto errOut;
snej@12
   614
		}
snej@12
   615
	}
snej@12
   616
	verifyAttr = verifyPhrase ? 1 : 0;
snej@12
   617
	crtn = impExpAddContextAttribute(ccHand, CSSM_ATTRIBUTE_VERIFY_PASSPHRASE,
snej@12
   618
		sizeof(uint32), (const void *)verifyAttr);
snej@12
   619
	if(crtn) {
snej@12
   620
		checkcssm(crtn,@"impExpAddContextAttribute");
snej@12
   621
		goto errOut;
snej@12
   622
	}
snej@12
   623
snej@12
   624
	dummyLabel.Data = (uint8 *)"Secure Passphrase";
snej@12
   625
	dummyLabel.Length = strlen((char *)dummyLabel.Data);
snej@12
   626
    
snej@12
   627
    uint32 keyAttr = keyParams->keyAttributes;
snej@12
   628
    if (keyAttr & CSSM_KEYATTR_SENSITIVE)
snej@12
   629
        keyAttr |= CSSM_KEYATTR_RETURN_REF;
snej@12
   630
    else
snej@12
   631
        keyAttr |= CSSM_KEYATTR_EXTRACTABLE;
snej@12
   632
snej@12
   633
	crtn = CSSM_GenerateKey(ccHand,
snej@12
   634
        keyParams->keyUsage ?: CSSM_KEYUSE_ANY,
snej@12
   635
		keyAttr,
snej@12
   636
		&dummyLabel,
snej@12
   637
		NULL,			// ACL
snej@12
   638
		ourKey);
snej@12
   639
	if(crtn) {
snej@12
   640
		checkcssm(crtn,@"CSSM_GenerateKey");
snej@12
   641
	}
snej@12
   642
errOut:
snej@12
   643
	CSSM_DeleteContext(ccHand);
snej@12
   644
	if(crtn == CSSM_OK) {
snej@12
   645
		*passKey = ourKey;
snej@12
   646
	}
snej@12
   647
	else if(ourKey != NULL) {
snej@12
   648
		free(ourKey);
snej@12
   649
	}
snej@12
   650
	return crtn;
snej@12
   651
}
snej@12
   652
	
snej@12
   653
snej@12
   654
#endif !MYCRYPTO_USE_IPHONE_API
snej@14
   655
snej@14
   656
snej@14
   657
snej@14
   658
/*
snej@14
   659
 Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
snej@14
   660
 
snej@14
   661
 Redistribution and use in source and binary forms, with or without modification, are permitted
snej@14
   662
 provided that the following conditions are met:
snej@14
   663
 
snej@14
   664
 * Redistributions of source code must retain the above copyright notice, this list of conditions
snej@14
   665
 and the following disclaimer.
snej@14
   666
 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
snej@14
   667
 and the following disclaimer in the documentation and/or other materials provided with the
snej@14
   668
 distribution.
snej@14
   669
 
snej@14
   670
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
snej@14
   671
 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
snej@14
   672
 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
snej@14
   673
 BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
snej@14
   674
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
snej@14
   675
  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
snej@14
   676
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
snej@14
   677
 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
snej@14
   678
 */