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 497