1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/MYKeyPair.m Sat Apr 04 20:42:03 2009 -0700
1.3 @@ -0,0 +1,234 @@
1.4 +//
1.5 +// KeyPair.m
1.6 +// MYCrypto
1.7 +//
1.8 +// Created by Jens Alfke on 3/21/09.
1.9 +// Copyright 2009 Jens Alfke. All rights reserved.
1.10 +//
1.11 +
1.12 +#import "MYKeyPair.h"
1.13 +#import "MYCrypto_Private.h"
1.14 +#import <CommonCrypto/CommonDigest.h>
1.15 +
1.16 +#if !USE_IPHONE_API
1.17 +
1.18 +
1.19 +#pragma mark -
1.20 +
1.21 +@implementation MYKeyPair
1.22 +
1.23 +
1.24 ++ (MYKeyPair*) _generateRSAKeyPairOfSize: (unsigned)keySize
1.25 + inKeychain: (SecKeychainRef)keychain {
1.26 + Assert( keySize == 512 || keySize == 1024 || keySize == 2048, @"Unsupported key size %u", keySize );
1.27 + SecKeyRef pubKey=NULL, privKey=NULL;
1.28 + OSStatus err;
1.29 + err = SecKeyCreatePair(keychain, CSSM_ALGID_RSA, keySize, 0LL,
1.30 + CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_VERIFY, // public key
1.31 + CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT,
1.32 + CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_SIGN, // private key
1.33 + CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_SENSITIVE | CSSM_KEYATTR_PERMANENT,
1.34 + NULL, // SecAccessRef
1.35 + &pubKey, &privKey);
1.36 + if (!check(err, @"SecKeyCreatePair")) {
1.37 + return nil;
1.38 + } else
1.39 + return [[[self alloc] initWithPublicKeyRef: pubKey privateKeyRef: privKey] autorelease];
1.40 +}
1.41 +
1.42 +
1.43 +- (id) initWithPublicKeyRef: (SecKeyRef)publicKey privateKeyRef: (SecKeyRef)privateKey {
1.44 + self = [super initWithKeyRef: publicKey];
1.45 + if (self) {
1.46 + NSParameterAssert(privateKey);
1.47 + _privateKey = (SecKeyRef) CFRetain(privateKey);
1.48 + }
1.49 + return self;
1.50 +}
1.51 +
1.52 +- (id) _initWithPublicKeyData: (NSData*)pubKeyData
1.53 + privateKey: (SecKeyRef)privateKey
1.54 + forKeychain: (SecKeychainRef)keychain {
1.55 + if (!privateKey) {
1.56 + [self release];
1.57 + return nil;
1.58 + }
1.59 + self = [self _initWithKeyData: pubKeyData forKeychain: keychain];
1.60 + if (self) {
1.61 + _privateKey = privateKey;
1.62 + } else {
1.63 + SecKeychainItemDelete((SecKeychainItemRef)privateKey);
1.64 + CFRelease(privateKey);
1.65 + }
1.66 + return self;
1.67 +}
1.68 +
1.69 +
1.70 +// The public API for this is in MYKeychain.
1.71 +- (id) _initWithPublicKeyData: (NSData*)pubKeyData
1.72 + privateKeyData: (NSData*)privKeyData
1.73 + forKeychain: (SecKeychainRef)keychain
1.74 + alertTitle: (NSString*)title
1.75 + alertPrompt: (NSString*)prompt
1.76 +{
1.77 + // Try to import the private key first, since the user might cancel the passphrase alert.
1.78 + SecKeyImportExportParameters params = {
1.79 + .flags = kSecKeySecurePassphrase,
1.80 + .alertTitle = (CFStringRef) title,
1.81 + .alertPrompt = (CFStringRef) prompt
1.82 + };
1.83 + SecKeyRef privateKey = importKey(privKeyData,kSecItemTypePrivateKey,keychain,¶ms);
1.84 + return [self _initWithPublicKeyData: pubKeyData privateKey: privateKey forKeychain: keychain];
1.85 +}
1.86 +
1.87 +// This method is for testing, so unit-tests don't require user intervention.
1.88 +// It's deliberately not made public, to discourage clients from trying to manage the passphrases
1.89 +// themselves (this is less secure than letting the Security agent do it.)
1.90 +- (id) _initWithPublicKeyData: (NSData*)pubKeyData
1.91 + privateKeyData: (NSData*)privKeyData
1.92 + forKeychain: (SecKeychainRef)keychain
1.93 + passphrase: (NSString*)passphrase
1.94 +{
1.95 + SecKeyImportExportParameters params = {
1.96 + .passphrase = (CFStringRef) passphrase,
1.97 + };
1.98 + SecKeyRef privateKey = importKey(privKeyData,kSecItemTypePrivateKey,keychain,¶ms);
1.99 + return [self _initWithPublicKeyData: pubKeyData privateKey: privateKey forKeychain: keychain];
1.100 +}
1.101 +
1.102 +
1.103 +- (void) dealloc
1.104 +{
1.105 + if (_privateKey) CFRelease(_privateKey);
1.106 + [super dealloc];
1.107 +}
1.108 +
1.109 +
1.110 +- (NSUInteger)hash {
1.111 + // Ensure that a KeyPair doesn't hash the same as its corresponding PublicKey:
1.112 + return super.hash ^ 0xFFFFFFFF;
1.113 +}
1.114 +
1.115 +
1.116 +- (MYPublicKey*) asPublicKey {
1.117 + return [[[MYPublicKey alloc] initWithKeyRef: self.keyRef] autorelease];
1.118 +}
1.119 +
1.120 +
1.121 +- (NSData*) exportPrivateKeyInFormat: (SecExternalFormat)format
1.122 + withPEM: (BOOL)withPEM
1.123 + alertTitle: (NSString*)title
1.124 + alertPrompt: (NSString*)prompt
1.125 +{
1.126 + SecKeyImportExportParameters params = {
1.127 + .version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION,
1.128 + .flags = kSecKeySecurePassphrase,
1.129 + .alertTitle = (CFStringRef)title,
1.130 + .alertPrompt = (CFStringRef)prompt
1.131 + };
1.132 + CFDataRef data = NULL;
1.133 + if (check(SecKeychainItemExport(_privateKey, //$array((id)_publicKey,(id)_privateKey),
1.134 + format, (withPEM ?kSecItemPemArmour :0),
1.135 + ¶ms, &data),
1.136 + @"SecKeychainItemExport"))
1.137 + return [(id)CFMakeCollectable(data) autorelease];
1.138 + else
1.139 + return nil;
1.140 +}
1.141 +
1.142 +- (NSData*) exportPrivateKey {
1.143 + return [self exportPrivateKeyInFormat: kSecFormatWrappedOpenSSL withPEM: YES
1.144 + alertTitle: @"Export Private Key"
1.145 + alertPrompt: @"Enter a passphrase to protect the private-key file.\n"
1.146 + "You will need to re-enter the passphrase later when importing the key from this file, "
1.147 + "so keep it in a safe place."];
1.148 + //FIX: Should make these messages localizable.
1.149 +}
1.150 +
1.151 +
1.152 +- (NSData*) _exportPrivateKeyInFormat: (SecExternalFormat)format
1.153 + withPEM: (BOOL)withPEM
1.154 + passphrase: (NSString*)passphrase
1.155 +{
1.156 + SecKeyImportExportParameters params = {
1.157 + .version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION,
1.158 + .passphrase = (CFStringRef)passphrase
1.159 + };
1.160 + CFDataRef data = NULL;
1.161 + if (check(SecKeychainItemExport(_privateKey,
1.162 + format, (withPEM ?kSecItemPemArmour :0),
1.163 + ¶ms, &data),
1.164 + @"SecKeychainItemExport"))
1.165 + return [(id)CFMakeCollectable(data) autorelease];
1.166 + else
1.167 + return nil;
1.168 +}
1.169 +
1.170 +- (BOOL) removeFromKeychain {
1.171 + return check(SecKeychainItemDelete((SecKeychainItemRef)_privateKey), @"delete private key")
1.172 + && [super removeFromKeychain];
1.173 +}
1.174 +
1.175 +
1.176 +@synthesize privateKeyRef=_privateKey;
1.177 +
1.178 +
1.179 +- (NSData*) decryptData: (NSData*)data {
1.180 + return _crypt(_privateKey,data,kCCDecrypt);
1.181 +}
1.182 +
1.183 +
1.184 +- (NSData*) signData: (NSData*)data {
1.185 + Assert(data);
1.186 + uint8_t digest[CC_SHA1_DIGEST_LENGTH];
1.187 + CC_SHA1(data.bytes,data.length, digest);
1.188 + NSData *signature = nil;
1.189 + CSSM_CC_HANDLE ccHandle = cssmCreateSignatureContext(_privateKey);
1.190 + if (!ccHandle) return nil;
1.191 + CSSM_DATA original = {data.length, (void*)data.bytes};
1.192 + CSSM_DATA result = {0,NULL};
1.193 + if (checkcssm(CSSM_SignData(ccHandle, &original, 1, CSSM_ALGID_NONE, &result), @"CSSM_SignData"))
1.194 + signature = [NSData dataWithBytesNoCopy: result.Data length: result.Length
1.195 + freeWhenDone: YES];
1.196 + CSSM_DeleteContext(ccHandle);
1.197 + return signature;
1.198 +}
1.199 +
1.200 +
1.201 +- (BOOL) setValue: (NSString*)valueStr ofAttribute: (SecKeychainAttrType)attr {
1.202 + return [super setValue: valueStr ofAttribute: attr]
1.203 + && [[self class] _setAttribute: attr
1.204 + ofItem: (SecKeychainItemRef)_privateKey
1.205 + stringValue: valueStr];
1.206 +}
1.207 +
1.208 +
1.209 +@end
1.210 +
1.211 +
1.212 +#endif !USE_IPHONE_API
1.213 +
1.214 +
1.215 +
1.216 +
1.217 +/*
1.218 + Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
1.219 +
1.220 + Redistribution and use in source and binary forms, with or without modification, are permitted
1.221 + provided that the following conditions are met:
1.222 +
1.223 + * Redistributions of source code must retain the above copyright notice, this list of conditions
1.224 + and the following disclaimer.
1.225 + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
1.226 + and the following disclaimer in the documentation and/or other materials provided with the
1.227 + distribution.
1.228 +
1.229 + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
1.230 + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
1.231 + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
1.232 + BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1.233 + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
1.234 + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
1.235 + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
1.236 + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1.237 + */