snej@0
|
1 |
//
|
snej@0
|
2 |
// MYPublicKey.m
|
snej@0
|
3 |
// MYCrypto
|
snej@0
|
4 |
//
|
snej@0
|
5 |
// Created by Jens Alfke on 3/21/09.
|
snej@0
|
6 |
// Copyright 2009 Jens Alfke. All rights reserved.
|
snej@0
|
7 |
//
|
snej@0
|
8 |
|
snej@0
|
9 |
#import "MYPublicKey.h"
|
snej@0
|
10 |
#import "MYCrypto_Private.h"
|
snej@0
|
11 |
#import "MYDigest.h"
|
jens@21
|
12 |
#import "MYASN1Object.h"
|
jens@21
|
13 |
#import "MYDEREncoder.h"
|
jens@21
|
14 |
#import "MYBERParser.h"
|
snej@0
|
15 |
#import "MYErrorUtils.h"
|
snej@0
|
16 |
#import <CommonCrypto/CommonDigest.h>
|
snej@0
|
17 |
|
snej@0
|
18 |
|
snej@0
|
19 |
#pragma mark -
|
snej@0
|
20 |
@implementation MYPublicKey
|
snej@0
|
21 |
|
snej@0
|
22 |
|
jens@21
|
23 |
- (id) initWithModulus: (NSData*)modulus exponent: (unsigned)exponent {
|
jens@21
|
24 |
// An RSA key is encoded in ASN.1 as a sequence of modulus and exponent, both as integers.
|
jens@21
|
25 |
MYASN1BigInteger *modulusInt = [[MYASN1BigInteger alloc] initWithUnsignedData: modulus];
|
jens@21
|
26 |
id asn1 = $array( modulusInt, $object(exponent) );
|
jens@21
|
27 |
[modulusInt release];
|
jens@21
|
28 |
NSData *keyData = [MYDEREncoder encodeRootObject: asn1 error: nil];
|
jens@21
|
29 |
return [self initWithKeyData: keyData];
|
jens@21
|
30 |
}
|
jens@21
|
31 |
|
snej@0
|
32 |
- (void) dealloc
|
snej@0
|
33 |
{
|
snej@0
|
34 |
[_digest release];
|
snej@0
|
35 |
[super dealloc];
|
snej@0
|
36 |
}
|
snej@0
|
37 |
|
jens@23
|
38 |
- (SecExternalItemType) keyClass {
|
snej@3
|
39 |
#if MYCRYPTO_USE_IPHONE_API
|
snej@3
|
40 |
return kSecAttrKeyClassPublic;
|
snej@3
|
41 |
#else
|
snej@0
|
42 |
return kSecItemTypePublicKey;
|
snej@3
|
43 |
#endif
|
snej@0
|
44 |
}
|
snej@3
|
45 |
|
jens@23
|
46 |
#if MYCRYPTO_USE_IPHONE_API
|
jens@23
|
47 |
- (SecExternalItemType) keyType {
|
jens@23
|
48 |
return kSecAttrKeyTypeRSA;
|
jens@23
|
49 |
}
|
jens@23
|
50 |
#endif
|
jens@23
|
51 |
|
snej@0
|
52 |
- (NSUInteger)hash {
|
snej@0
|
53 |
return self.publicKeyDigest.hash;
|
snej@0
|
54 |
}
|
snej@0
|
55 |
|
snej@0
|
56 |
- (NSString*) description {
|
snej@0
|
57 |
return $sprintf(@"%@[%@]", [self class], self.publicKeyDigest.abbreviatedHexString);
|
snej@0
|
58 |
}
|
snej@0
|
59 |
|
snej@0
|
60 |
- (MYSHA1Digest*) publicKeyDigest {
|
snej@0
|
61 |
if (!_digest)
|
snej@3
|
62 |
_digest = [[self _keyDigest] retain];
|
snej@0
|
63 |
return _digest;
|
snej@0
|
64 |
}
|
snej@0
|
65 |
|
snej@3
|
66 |
#if !MYCRYPTO_USE_IPHONE_API
|
snej@13
|
67 |
- (SecExternalFormat) _externalFormat {
|
snej@14
|
68 |
return kSecFormatBSAFE;
|
snej@0
|
69 |
}
|
snej@3
|
70 |
#endif
|
snej@0
|
71 |
|
snej@0
|
72 |
|
jens@21
|
73 |
- (BOOL) getModulus: (NSData**)outModulus exponent: (unsigned*)outExponent {
|
jens@21
|
74 |
Assert(outModulus!=nil);
|
jens@21
|
75 |
Assert(outExponent!=nil);
|
jens@21
|
76 |
NSArray *asn1 = $castIf(NSArray, MYBERParse(self.keyData, nil));
|
jens@21
|
77 |
if (!asn1 || asn1.count != 2)
|
jens@21
|
78 |
return NO;
|
jens@21
|
79 |
*outModulus = $castIf(MYASN1BigInteger, [asn1 objectAtIndex: 0]).unsignedData;
|
jens@21
|
80 |
*outExponent = $castIf(NSNumber, [asn1 objectAtIndex: 1]).unsignedIntValue;
|
jens@21
|
81 |
return (*outModulus!=nil && *outExponent>=3);
|
jens@21
|
82 |
}
|
jens@21
|
83 |
|
jens@21
|
84 |
|
snej@13
|
85 |
- (NSData*) rawEncryptData: (NSData*)data {
|
snej@3
|
86 |
return [self _crypt: data operation: YES];
|
snej@0
|
87 |
}
|
snej@0
|
88 |
|
snej@0
|
89 |
|
snej@0
|
90 |
- (BOOL) verifySignature: (NSData*)signature ofData: (NSData*)data {
|
snej@0
|
91 |
Assert(data);
|
snej@0
|
92 |
Assert(signature);
|
snej@1
|
93 |
|
snej@3
|
94 |
#if MYCRYPTO_USE_IPHONE_API
|
snej@3
|
95 |
uint8_t digest[CC_SHA1_DIGEST_LENGTH];
|
snej@3
|
96 |
CC_SHA1(data.bytes,data.length, digest);
|
snej@3
|
97 |
OSStatus err = SecKeyRawVerify(self.keyRef, kSecPaddingPKCS1SHA1,
|
snej@3
|
98 |
digest,sizeof(digest), //data.bytes, data.length,
|
snej@3
|
99 |
signature.bytes, signature.length);
|
snej@3
|
100 |
return err==noErr;
|
snej@3
|
101 |
|
snej@3
|
102 |
#else
|
jens@17
|
103 |
CSSM_CC_HANDLE ccHandle = [self _createSignatureContext: CSSM_ALGID_SHA1WithRSA];
|
snej@0
|
104 |
if (!ccHandle) return NO;
|
snej@0
|
105 |
CSSM_DATA original = {data.length, (void*)data.bytes};
|
snej@0
|
106 |
CSSM_DATA sig = {signature.length, (void*)signature.bytes};
|
snej@0
|
107 |
CSSM_RETURN cssmErr = CSSM_VerifyData(ccHandle, &original, 1, CSSM_ALGID_NONE, &sig);
|
snej@0
|
108 |
CSSM_DeleteContext(ccHandle);
|
snej@0
|
109 |
if (cssmErr == CSSM_OK)
|
snej@0
|
110 |
return YES;
|
snej@0
|
111 |
if (cssmErr != CSSMERR_CSP_VERIFY_FAILED)
|
snej@0
|
112 |
Warn(@"CSSM error verifying signature: %u", MYErrorName(MYCSSMErrorDomain,cssmErr));
|
snej@0
|
113 |
return NO;
|
snej@3
|
114 |
#endif
|
snej@0
|
115 |
}
|
snej@0
|
116 |
|
snej@0
|
117 |
|
snej@4
|
118 |
#if !TARGET_OS_IPHONE
|
snej@4
|
119 |
- (CSSM_WRAP_KEY*) _unwrappedCSSMKey {
|
snej@4
|
120 |
const CSSM_KEY *key = self.cssmKey;
|
snej@4
|
121 |
|
snej@4
|
122 |
if (key->KeyHeader.BlobType == CSSM_KEYBLOB_WRAPPED) {
|
snej@4
|
123 |
Warn(@"Key is already wrapped.\n");
|
snej@4
|
124 |
return NULL;
|
snej@4
|
125 |
}
|
snej@4
|
126 |
|
snej@4
|
127 |
if (key->KeyHeader.KeyClass != CSSM_KEYCLASS_PUBLIC_KEY)
|
snej@4
|
128 |
Warn(@"Warning: Null wrapping a non-public key - this is a dangerous operation.\n");
|
snej@4
|
129 |
|
snej@4
|
130 |
const CSSM_ACCESS_CREDENTIALS* credentials;
|
snej@4
|
131 |
credentials = [self cssmCredentialsForOperation: CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED
|
snej@4
|
132 |
type: kSecCredentialTypeDefault error: nil];
|
snej@4
|
133 |
CSSM_CC_HANDLE ccHandle;
|
snej@4
|
134 |
if (!checkcssm(CSSM_CSP_CreateSymmetricContext(self.cssmCSPHandle,
|
snej@4
|
135 |
CSSM_ALGID_NONE, CSSM_ALGMODE_WRAP,
|
snej@4
|
136 |
NULL, NULL, NULL,
|
snej@4
|
137 |
CSSM_PADDING_NONE, NULL,
|
snej@4
|
138 |
&ccHandle),
|
snej@4
|
139 |
@"CSSM_CSP_CreateSymmetricContext"))
|
snej@4
|
140 |
return NULL;
|
snej@4
|
141 |
|
snej@4
|
142 |
CSSM_WRAP_KEY *result = malloc(sizeof(CSSM_WRAP_KEY));
|
snej@4
|
143 |
if (!checkcssm(CSSM_WrapKey(ccHandle, credentials, key, NULL, result),
|
snej@4
|
144 |
@"CSSM_WrapKey")) {
|
snej@4
|
145 |
free(result);
|
snej@4
|
146 |
result = NULL;
|
snej@4
|
147 |
}
|
snej@4
|
148 |
CSSM_DeleteContext(ccHandle);
|
snej@4
|
149 |
return result;
|
snej@4
|
150 |
}
|
snej@13
|
151 |
|
snej@13
|
152 |
|
snej@13
|
153 |
- (NSData*) wrapSessionKey: (MYSymmetricKey*)sessionKey {
|
snej@13
|
154 |
const CSSM_ACCESS_CREDENTIALS* credentials;
|
snej@13
|
155 |
credentials = [self cssmCredentialsForOperation: CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED
|
snej@13
|
156 |
type: kSecCredentialTypeDefault error: nil];
|
snej@13
|
157 |
CSSM_CSP_HANDLE cspHandle = self.cssmCSPHandle;
|
snej@13
|
158 |
CSSM_CC_HANDLE ctx;
|
snej@13
|
159 |
if (!checkcssm(CSSM_CSP_CreateAsymmetricContext(cspHandle,
|
snej@13
|
160 |
self.cssmAlgorithm,
|
snej@13
|
161 |
credentials,
|
snej@13
|
162 |
self.cssmKey,
|
snej@13
|
163 |
CSSM_PADDING_PKCS1,
|
snej@13
|
164 |
&ctx),
|
snej@13
|
165 |
@"CSSM_CSP_CreateAsymmetricContext"))
|
snej@13
|
166 |
return nil;
|
snej@14
|
167 |
|
snej@13
|
168 |
// Now wrap the key:
|
snej@13
|
169 |
NSData *result = nil;
|
snej@13
|
170 |
CSSM_WRAP_KEY wrappedKey = {};
|
snej@14
|
171 |
CSSM_DATA descriptiveData = {};
|
snej@14
|
172 |
if (checkcssm(CSSM_WrapKey(ctx, credentials, sessionKey.cssmKey, &descriptiveData, &wrappedKey),
|
snej@13
|
173 |
@"CSSM_WrapKey")) {
|
snej@13
|
174 |
// ...and copy the wrapped key data to the result NSData:
|
snej@13
|
175 |
result = [NSData dataWithBytes: wrappedKey.KeyData.Data length: wrappedKey.KeyData.Length];
|
snej@13
|
176 |
CSSM_FreeKey(cspHandle, credentials, &wrappedKey, NO);
|
snej@13
|
177 |
}
|
snej@13
|
178 |
// Finally, delete the context
|
snej@13
|
179 |
CSSM_DeleteContext(ctx);
|
snej@13
|
180 |
return result;
|
snej@13
|
181 |
}
|
snej@13
|
182 |
|
snej@13
|
183 |
|
snej@4
|
184 |
#endif
|
snej@4
|
185 |
|
snej@4
|
186 |
|
snej@0
|
187 |
@end
|
snej@0
|
188 |
|
snej@0
|
189 |
|
snej@0
|
190 |
|
snej@0
|
191 |
/*
|
snej@0
|
192 |
Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
|
snej@0
|
193 |
|
snej@0
|
194 |
Redistribution and use in source and binary forms, with or without modification, are permitted
|
snej@0
|
195 |
provided that the following conditions are met:
|
snej@0
|
196 |
|
snej@0
|
197 |
* Redistributions of source code must retain the above copyright notice, this list of conditions
|
snej@0
|
198 |
and the following disclaimer.
|
snej@0
|
199 |
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions
|
snej@0
|
200 |
and the following disclaimer in the documentation and/or other materials provided with the
|
snej@0
|
201 |
distribution.
|
snej@0
|
202 |
|
snej@0
|
203 |
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
snej@0
|
204 |
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
snej@0
|
205 |
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
|
snej@0
|
206 |
BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
snej@0
|
207 |
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
snej@0
|
208 |
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
snej@0
|
209 |
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
snej@0
|
210 |
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
snej@0
|
211 |
*/
|