]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_cryptkit/lib/NSFEEPublicKey.m
Security-58286.1.32.tar.gz
[apple/security.git] / OSX / libsecurity_cryptkit / lib / NSFEEPublicKey.m
1 /* Copyright (c) 1998,2011,2014 Apple Inc. All Rights Reserved.
2 *
3 * NOTICE: USE OF THE MATERIALS ACCOMPANYING THIS NOTICE IS SUBJECT
4 * TO THE TERMS OF THE SIGNED "FAST ELLIPTIC ENCRYPTION (FEE) REFERENCE
5 * SOURCE CODE EVALUATION AGREEMENT" BETWEEN APPLE, INC. AND THE
6 * ORIGINAL LICENSEE THAT OBTAINED THESE MATERIALS FROM APPLE,
7 * INC. ANY USE OF THESE MATERIALS NOT PERMITTED BY SUCH AGREEMENT WILL
8 * EXPOSE YOU TO LIABILITY.
9 ***************************************************************************
10 *
11 * NSFEEPublicKey.m - NSFEEPublicKey class implementation
12 *
13 * Revision History
14 * ----------------
15 * 17 Jul 97 at Apple
16 * Added ECDSA signature routines.
17 * 21 Aug 96 at NeXT
18 * Modified to use C-only FeePublicKey module.
19 * ???? 1994 Blaine Garst at NeXT
20 * Created.
21 */
22
23 #import <Foundation/Foundation.h>
24 #import <Foundation/NSUtilities.h>
25
26 #import "NSCryptors.h"
27 #import "NSFEEPublicKeyPrivate.h"
28 #import "feePublicKey.h"
29 #import "feePublicKeyPrivate.h"
30 #import "ckutilities.h"
31 #import "mutils.h"
32 #import "feeTypes.h"
33 #import "curveParams.h"
34 #import "falloc.h"
35 #import "feeDigitalSignature.h"
36 #import "feeHash.h"
37 #import "feeFunctions.h"
38 #import "feeFEEDExp.h"
39
40 /*
41 Elliptic curve algebra over finite fields F(p**k), where p = 2**q -1 is a
42 Mersenne prime.
43 q is bit-depth.
44 A private key (a) is a large integer that when multiplied by an initial
45 curve point P yields the public key aP.
46 Public keys can be used to generate one-time pads because multiplication
47 is commutative:
48
49 a(bP) == b(aP)
50 */
51
52 @implementation NSFEEPublicKey
53
54 /*
55 * Root method to create new public key from private "password" data.
56 */
57 + keyWithPrivateData:(NSData *)passwd
58 depth:(unsigned)depth
59 usageName:(NSString *)uname
60 {
61 NSFEEPublicKey *result;
62 feeReturn frtn;
63 unichar *uc;
64
65 result = [[self alloc] autorelease];
66 result->_pubKey = feePubKeyAlloc();
67 uc = fmalloc([uname length] * sizeof(unichar));
68 [uname getCharacters:uc];
69 frtn = feePubKeyInitFromPrivData(result->_pubKey,
70 [passwd bytes], [passwd length],
71 uc, [uname length],
72 depth);
73 ffree(uc);
74 if(frtn) {
75 NSLog(@"keyWithPrivateData: %s\n", feeReturnString(frtn));
76 return nil;
77 }
78 return result;
79 }
80
81 /*
82 * Create new key with curve parameters matching existing oldKey.
83 */
84 + keyWithPrivateData:(NSData *)passwd
85 andKey:(NSFEEPublicKey *)oldKey
86 usageName:(NSString *)uname
87 {
88 NSFEEPublicKey *result;
89 feeReturn frtn;
90 unichar *uc;
91
92 result = [[self alloc] autorelease];
93 result->_pubKey = feePubKeyAlloc();
94 uc = fmalloc([uname length] * sizeof(unichar));
95 [uname getCharacters:uc];
96 frtn = feePubKeyInitFromKey(result->_pubKey,
97 [passwd bytes], [passwd length],
98 uc, [uname length],
99 oldKey->_pubKey);
100 ffree(uc);
101 if(frtn) {
102 NSLog(@"keyWithPrivateData:andKey: %s\n",
103 feeReturnString(frtn));
104 return nil;
105 }
106 return result;
107 }
108
109 + keyWithPrivateData:(NSData *)passwd
110 usageName:(NSString *)uname
111 {
112 // 4 gives 127 bits of protection
113 // although the RSA challenge number of 127 bits has been
114 // broken, FEE is much stronger at the same length
115 return [self keyWithPrivateData:passwd
116 depth:FEE_DEPTH_DEFAULT
117 usageName:uname];
118 }
119
120 /*
121 * The standard way of creating a new key given a private "password" string.
122 */
123 + keyWithPrivateString:(NSString *)private
124 usageName:(NSString *)uname
125 {
126 NSData *pdata;
127 id result;
128
129 /*
130 * FIXME - handle other encodings?
131 */
132 pdata = [private dataUsingEncoding:NSUTF8StringEncoding];
133 result = [self keyWithPrivateData:pdata usageName:uname];
134 return result;
135 }
136
137 + keyWithPrivateString:(NSString *)private
138 andKey:(NSFEEPublicKey *)oldKey
139 usageName:(NSString *)uname
140 {
141 NSData *pdata;
142 id result;
143
144 if (!uname) return nil;
145
146 pdata = [private dataUsingEncoding:NSUTF8StringEncoding];
147 result = [self keyWithPrivateData:pdata andKey:oldKey usageName:uname];
148 return result;
149 }
150
151 + keyWithPrivateString:(NSString *)private
152 depth:(unsigned)depth
153 usageName:(NSString *)uname
154 {
155 NSData *pdata;
156 id result;
157
158 if (!uname) return nil;
159
160 pdata = [private dataUsingEncoding:NSUTF8StringEncoding];
161 result = [self keyWithPrivateData:pdata depth:depth usageName:uname];
162 return result;
163 }
164
165 /*
166 * The standard way of creating a new key given a public key string.
167 */
168 + keyWithPublicKeyString:(NSString *)hexstr
169 {
170 NSFEEPublicKey *result;
171 feeReturn frtn;
172 NSStringEncoding defEndoding;
173 const char *s;
174
175 /*
176 * Protect against gross errors in the key string formatting...
177 */
178 defEndoding = [NSString defaultCStringEncoding];
179 if([hexstr canBeConvertedToEncoding:defEndoding] == NO) {
180 NSLog(@"NSFEEPublicKey: Bad Public Key String Format (1)\n");
181 return nil;
182 }
183
184 /*
185 * FIXME - docs say this string is "autoreleased". How is a cString
186 * autoreleased?
187 */
188 s = [hexstr cString];
189 result = [[self alloc] autorelease];
190 result->_pubKey = feePubKeyAlloc();
191
192 frtn = feePubKeyInitFromKeyString(result->_pubKey,
193 s, strlen(s));
194 if(frtn) {
195 NSLog(@"keyWithPublicKeyString:andKey: %s\n",
196 feeReturnString(frtn));
197 return nil;
198 }
199 return result;
200 }
201
202 - (void)dealloc
203 {
204 if(_pubKey) {
205 feePubKeyFree(_pubKey);
206 }
207 [super dealloc];
208 }
209
210 /*
211 * Create a public key in the form of a string. This string contains an
212 * encoded version of all of our ivars except for _private.
213 *
214 * See KeyStringFormat.doc for info on the format of the public key string;
215 * PLEASE UPDATE THIS DOCUMENT WHEN YOU MAKE CHANGES TO THE STRING FORMAT.
216 */
217 - (NSString *)publicKeyString
218 {
219 char *keyStr;
220 unsigned keyStrLen;
221 feeReturn frtn;
222 NSString *result;
223
224 if(_pubKey == NULL) {
225 return nil;
226 }
227 frtn = feePubKeyCreateKeyString(_pubKey, &keyStr, &keyStrLen);
228 if(frtn) {
229 NSLog(@"publicKeyString: %s\n",
230 feeReturnString(frtn));
231 return nil;
232 }
233 result = [NSString stringWithCString:keyStr];
234 ffree((void *)keyStr);
235 return result;
236 }
237
238 - (BOOL)isEqual:(NSFEEPublicKey *)other
239 {
240 if((other == nil) || (other->_pubKey == NULL) || (_pubKey == NULL)) {
241 return NO;
242 }
243 if(feePubKeyIsEqual(_pubKey, other->_pubKey)) {
244 return YES;
245 }
246 else {
247 return NO;
248 }
249 }
250
251 - (unsigned)keyBitsize
252 {
253 if(_pubKey == NULL) {
254 return 0;
255 }
256 return feePubKeyBitsize(_pubKey);
257 }
258
259 - (NSString *)algorithmName
260 {
261 return [NSString stringWithCString:feePubKeyAlgorithmName()];
262 }
263
264 - (NSString *)usageName
265 {
266 unsigned unameLen;
267 const feeUnichar *uname;
268 NSString *result;
269
270 if(_pubKey == NULL) {
271 return nil;
272 }
273 uname = feePubKeyUsageName(_pubKey, &unameLen);
274 result = [NSString stringWithCharacters:uname length:unameLen];
275 return result;
276 }
277
278 - (NSString *)signer
279 {
280 return [self usageName];
281 }
282
283 - (NSData *)padWithPublicKey:(id <NSObject,NSPublicKey>)otherKey
284 {
285 NSFEEPublicKey *other;
286 NSMutableData *result;
287 feeReturn frtn;
288 unsigned char *padData;
289 unsigned padDataLen;
290
291 if(_pubKey == NULL) {
292 return nil;
293 }
294 if (![otherKey isMemberOfClass:isa]) {
295 return nil;
296 }
297 other = otherKey;
298 if(other->_pubKey == NULL) {
299 return nil;
300 }
301 frtn = feePubKeyCreatePad(_pubKey,
302 other->_pubKey,
303 &padData,
304 &padDataLen);
305 if(frtn) {
306 NSLog(@"padWithPublicKey: %s\n", feeReturnString(frtn));
307 return nil;
308 }
309 result = [NSData dataWithBytesNoCopy:padData length:padDataLen];
310 return result;
311 }
312
313 - (NSData *)encryptData:(NSData *)data
314 {
315 feeFEEDExp feed;
316 NSData *result;
317 feeReturn frtn;
318 unsigned char *ctext;
319 unsigned ctextLen;
320
321 if(_pubKey == NULL) {
322 return nil;
323 }
324 feed = feeFEEDExpNewWithPubKey(_pubKey);
325 frtn = feeFEEDExpEncrypt(feed,
326 [data bytes],
327 [data length],
328 &ctext,
329 &ctextLen);
330 if(frtn == FR_Success) {
331 result = [NSData dataWithBytesNoCopy:ctext length:ctextLen];
332 }
333 else {
334 NSLog(@"feeFEEDEncrypt: %s\n", feeReturnString(frtn));
335 result = nil;
336 }
337 feeFEEDExpFree(feed);
338 return result;
339 }
340
341 - (NSData *)decryptData:(NSData *)data
342 {
343 feeFEEDExp feed;
344 NSData *result;
345 feeReturn frtn;
346 unsigned char *ptext;
347 unsigned ptextLen;
348
349 if(_pubKey == NULL) {
350 return nil;
351 }
352 feed = feeFEEDExpNewWithPubKey(_pubKey);
353 frtn = feeFEEDExpDecrypt(feed,
354 [data bytes],
355 [data length],
356 &ptext,
357 &ptextLen);
358 if(frtn == FR_Success) {
359 result = [NSData dataWithBytesNoCopy:ptext length:ptextLen];
360 }
361 else {
362 NSLog(@"feeFEEDDecrypt: %s\n", feeReturnString(frtn));
363 result = nil;
364 }
365 feeFEEDExpFree(feed);
366 return result;
367 }
368
369 /*
370 * When 1, we use ECDSA unless we're using a depth which does not
371 * have curve orders.
372 * WARNING - enabling ECDSA by default breaks ICE and compatibility
373 * with Java signatures, at least until we have a Java ECDSA
374 * implementation.
375 */
376 #define ECDSA_SIG_DEFAULT 0
377
378 - (NSData *)digitalSignatureForData:(NSData *)data
379 {
380 NSData *result;
381 unsigned char *sig;
382 unsigned sigLen;
383 feeReturn frtn;
384 curveParams *cp;
385
386 if(_pubKey == NULL) {
387 return nil;
388 }
389 cp = feePubKeyCurveParams(_pubKey);
390 if(!ECDSA_SIG_DEFAULT || isZero(cp->x1OrderPlus)) {
391 frtn = feePubKeyCreateSignature(_pubKey,
392 [data bytes],
393 [data length],
394 &sig,
395 &sigLen);
396 }
397 else {
398 frtn = feePubKeyCreateECDSASignature(_pubKey,
399 [data bytes],
400 [data length],
401 &sig,
402 &sigLen);
403 }
404 if(frtn) {
405 NSLog(@"digitalSignatureForData: %s\n", feeReturnString(frtn));
406 return nil;
407 }
408 result = [NSData dataWithBytesNoCopy:sig length:sigLen];
409 return result;
410 }
411
412 - (BOOL)isValidDigitalSignature:(NSData *)signa
413 forData:(NSData *)data
414 {
415 feeReturn frtn;
416 feeUnichar *sigSigner;
417 unsigned sigSignerLen;
418 curveParams *cp;
419
420 if(_pubKey == NULL) {
421 return NO;
422 }
423 cp = feePubKeyCurveParams(_pubKey);
424 if(!ECDSA_SIG_DEFAULT || isZero(cp->x1OrderPlus)) {
425 frtn = feePubKeyVerifySignature(_pubKey,
426 [data bytes],
427 [data length],
428 [signa bytes],
429 [signa length],
430 &sigSigner,
431 &sigSignerLen);
432 }
433 else {
434 frtn = feePubKeyVerifyECDSASignature(_pubKey,
435 [data bytes],
436 [data length],
437 [signa bytes],
438 [signa length],
439 &sigSigner,
440 &sigSignerLen);
441 }
442
443 /*
444 * FIXME - We just throw away the signer for now...
445 */
446 if(sigSignerLen) {
447 ffree(sigSigner);
448 }
449
450 switch(frtn) {
451 case FR_Success:
452 return YES;
453 case FR_InvalidSignature:
454 return NO;
455 default:
456 /*
457 * Something other than simple signature mismatch...
458 */
459 NSLog(@"isValidDigitalSignature: %s\n", feeReturnString(frtn));
460 return NO;
461 }
462 }
463
464 @end
465
466 @implementation NSFEEPublicKey(Private)
467
468 - (key)minus
469 {
470 if(_pubKey == NULL) {
471 return NULL;
472 }
473 return feePubKeyMinusCurve(_pubKey);
474 }
475
476 - (key)plus
477 {
478 if(_pubKey == NULL) {
479 return NULL;
480 }
481 return feePubKeyPlusCurve(_pubKey);
482 }
483
484 - (feePubKey)feePubKey
485 {
486 return _pubKey;
487 }
488
489 #if FEE_DEBUG
490 - (void)dump
491 {
492 printPubKey(_pubKey);
493 }
494 #endif FEE_DEBUG
495
496 @end