X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/Security/libsecurity_cryptkit/lib/NSFEEPublicKey.m diff --git a/Security/libsecurity_cryptkit/lib/NSFEEPublicKey.m b/Security/libsecurity_cryptkit/lib/NSFEEPublicKey.m new file mode 100644 index 00000000..034af79d --- /dev/null +++ b/Security/libsecurity_cryptkit/lib/NSFEEPublicKey.m @@ -0,0 +1,496 @@ +/* Copyright (c) 1998,2011,2014 Apple Inc. All Rights Reserved. + * + * NOTICE: USE OF THE MATERIALS ACCOMPANYING THIS NOTICE IS SUBJECT + * TO THE TERMS OF THE SIGNED "FAST ELLIPTIC ENCRYPTION (FEE) REFERENCE + * SOURCE CODE EVALUATION AGREEMENT" BETWEEN APPLE, INC. AND THE + * ORIGINAL LICENSEE THAT OBTAINED THESE MATERIALS FROM APPLE, + * INC. ANY USE OF THESE MATERIALS NOT PERMITTED BY SUCH AGREEMENT WILL + * EXPOSE YOU TO LIABILITY. + *************************************************************************** + * + * NSFEEPublicKey.m - NSFEEPublicKey class implementation + * + * Revision History + * ---------------- + * 17 Jul 97 at Apple + * Added ECDSA signature routines. + * 21 Aug 96 at NeXT + * Modified to use C-only FeePublicKey module. + * ???? 1994 Blaine Garst at NeXT + * Created. + */ + +#import +#import + +#import "NSCryptors.h" +#import "NSFEEPublicKeyPrivate.h" +#import "feePublicKey.h" +#import "feePublicKeyPrivate.h" +#import "ckutilities.h" +#import "mutils.h" +#import "feeTypes.h" +#import "curveParams.h" +#import "falloc.h" +#import "feeDigitalSignature.h" +#import "feeHash.h" +#import "feeFunctions.h" +#import "feeFEEDExp.h" + +/* + Elliptic curve algebra over finite fields F(p**k), where p = 2**q -1 is a + Mersenne prime. + q is bit-depth. + A private key (a) is a large integer that when multiplied by an initial + curve point P yields the public key aP. + Public keys can be used to generate one-time pads because multiplication + is commutative: + + a(bP) == b(aP) + */ + +@implementation NSFEEPublicKey + +/* + * Root method to create new public key from private "password" data. + */ ++ keyWithPrivateData:(NSData *)passwd + depth:(unsigned)depth + usageName:(NSString *)uname +{ + NSFEEPublicKey *result; + feeReturn frtn; + unichar *uc; + + result = [[self alloc] autorelease]; + result->_pubKey = feePubKeyAlloc(); + uc = fmalloc([uname length] * sizeof(unichar)); + [uname getCharacters:uc]; + frtn = feePubKeyInitFromPrivData(result->_pubKey, + [passwd bytes], [passwd length], + uc, [uname length], + depth); + ffree(uc); + if(frtn) { + NSLog(@"keyWithPrivateData: %s\n", feeReturnString(frtn)); + return nil; + } + return result; +} + +/* + * Create new key with curve parameters matching existing oldKey. + */ ++ keyWithPrivateData:(NSData *)passwd + andKey:(NSFEEPublicKey *)oldKey + usageName:(NSString *)uname +{ + NSFEEPublicKey *result; + feeReturn frtn; + unichar *uc; + + result = [[self alloc] autorelease]; + result->_pubKey = feePubKeyAlloc(); + uc = fmalloc([uname length] * sizeof(unichar)); + [uname getCharacters:uc]; + frtn = feePubKeyInitFromKey(result->_pubKey, + [passwd bytes], [passwd length], + uc, [uname length], + oldKey->_pubKey); + ffree(uc); + if(frtn) { + NSLog(@"keyWithPrivateData:andKey: %s\n", + feeReturnString(frtn)); + return nil; + } + return result; +} + ++ keyWithPrivateData:(NSData *)passwd + usageName:(NSString *)uname +{ + // 4 gives 127 bits of protection + // although the RSA challenge number of 127 bits has been + // broken, FEE is much stronger at the same length + return [self keyWithPrivateData:passwd + depth:FEE_DEPTH_DEFAULT + usageName:uname]; +} + +/* + * The standard way of creating a new key given a private "password" string. + */ ++ keyWithPrivateString:(NSString *)private + usageName:(NSString *)uname +{ + NSData *pdata; + id result; + + /* + * FIXME - handle other encodings? + */ + pdata = [private dataUsingEncoding:NSUTF8StringEncoding]; + result = [self keyWithPrivateData:pdata usageName:uname]; + return result; +} + ++ keyWithPrivateString:(NSString *)private + andKey:(NSFEEPublicKey *)oldKey + usageName:(NSString *)uname +{ + NSData *pdata; + id result; + + if (!uname) return nil; + + pdata = [private dataUsingEncoding:NSUTF8StringEncoding]; + result = [self keyWithPrivateData:pdata andKey:oldKey usageName:uname]; + return result; +} + ++ keyWithPrivateString:(NSString *)private + depth:(unsigned)depth + usageName:(NSString *)uname +{ + NSData *pdata; + id result; + + if (!uname) return nil; + + pdata = [private dataUsingEncoding:NSUTF8StringEncoding]; + result = [self keyWithPrivateData:pdata depth:depth usageName:uname]; + return result; +} + +/* + * The standard way of creating a new key given a public key string. + */ ++ keyWithPublicKeyString:(NSString *)hexstr +{ + NSFEEPublicKey *result; + feeReturn frtn; + NSStringEncoding defEndoding; + const char *s; + + /* + * Protect against gross errors in the key string formatting... + */ + defEndoding = [NSString defaultCStringEncoding]; + if([hexstr canBeConvertedToEncoding:defEndoding] == NO) { + NSLog(@"NSFEEPublicKey: Bad Public Key String Format (1)\n"); + return nil; + } + + /* + * FIXME - docs say this string is "autoreleased". How is a cString + * autoreleased? + */ + s = [hexstr cString]; + result = [[self alloc] autorelease]; + result->_pubKey = feePubKeyAlloc(); + + frtn = feePubKeyInitFromKeyString(result->_pubKey, + s, strlen(s)); + if(frtn) { + NSLog(@"keyWithPublicKeyString:andKey: %s\n", + feeReturnString(frtn)); + return nil; + } + return result; +} + +- (void)dealloc +{ + if(_pubKey) { + feePubKeyFree(_pubKey); + } + [super dealloc]; +} + +/* + * Create a public key in the form of a string. This string contains an + * encoded version of all of our ivars except for _private. + * + * See KeyStringFormat.doc for info on the format of the public key string; + * PLEASE UPDATE THIS DOCUMENT WHEN YOU MAKE CHANGES TO THE STRING FORMAT. + */ +- (NSString *)publicKeyString +{ + char *keyStr; + unsigned keyStrLen; + feeReturn frtn; + NSString *result; + + if(_pubKey == NULL) { + return nil; + } + frtn = feePubKeyCreateKeyString(_pubKey, &keyStr, &keyStrLen); + if(frtn) { + NSLog(@"publicKeyString: %s\n", + feeReturnString(frtn)); + return nil; + } + result = [NSString stringWithCString:keyStr]; + ffree((void *)keyStr); + return result; +} + +- (BOOL)isEqual:(NSFEEPublicKey *)other +{ + if((other == nil) || (other->_pubKey == NULL) || (_pubKey == NULL)) { + return NO; + } + if(feePubKeyIsEqual(_pubKey, other->_pubKey)) { + return YES; + } + else { + return NO; + } +} + +- (unsigned)keyBitsize +{ + if(_pubKey == NULL) { + return 0; + } + return feePubKeyBitsize(_pubKey); +} + +- (NSString *)algorithmName +{ + return [NSString stringWithCString:feePubKeyAlgorithmName()]; +} + +- (NSString *)usageName +{ + unsigned unameLen; + const feeUnichar *uname; + NSString *result; + + if(_pubKey == NULL) { + return nil; + } + uname = feePubKeyUsageName(_pubKey, &unameLen); + result = [NSString stringWithCharacters:uname length:unameLen]; + return result; +} + +- (NSString *)signer +{ + return [self usageName]; +} + +- (NSData *)padWithPublicKey:(id )otherKey +{ + NSFEEPublicKey *other; + NSMutableData *result; + feeReturn frtn; + unsigned char *padData; + unsigned padDataLen; + + if(_pubKey == NULL) { + return nil; + } + if (![otherKey isMemberOfClass:isa]) { + return nil; + } + other = otherKey; + if(other->_pubKey == NULL) { + return nil; + } + frtn = feePubKeyCreatePad(_pubKey, + other->_pubKey, + &padData, + &padDataLen); + if(frtn) { + NSLog(@"padWithPublicKey: %s\n", feeReturnString(frtn)); + return nil; + } + result = [NSData dataWithBytesNoCopy:padData length:padDataLen]; + return result; +} + +- (NSData *)encryptData:(NSData *)data +{ + feeFEEDExp feed; + NSData *result; + feeReturn frtn; + unsigned char *ctext; + unsigned ctextLen; + + if(_pubKey == NULL) { + return nil; + } + feed = feeFEEDExpNewWithPubKey(_pubKey); + frtn = feeFEEDExpEncrypt(feed, + [data bytes], + [data length], + &ctext, + &ctextLen); + if(frtn == FR_Success) { + result = [NSData dataWithBytesNoCopy:ctext length:ctextLen]; + } + else { + NSLog(@"feeFEEDEncrypt: %s\n", feeReturnString(frtn)); + result = nil; + } + feeFEEDExpFree(feed); + return result; +} + +- (NSData *)decryptData:(NSData *)data +{ + feeFEEDExp feed; + NSData *result; + feeReturn frtn; + unsigned char *ptext; + unsigned ptextLen; + + if(_pubKey == NULL) { + return nil; + } + feed = feeFEEDExpNewWithPubKey(_pubKey); + frtn = feeFEEDExpDecrypt(feed, + [data bytes], + [data length], + &ptext, + &ptextLen); + if(frtn == FR_Success) { + result = [NSData dataWithBytesNoCopy:ptext length:ptextLen]; + } + else { + NSLog(@"feeFEEDDecrypt: %s\n", feeReturnString(frtn)); + result = nil; + } + feeFEEDExpFree(feed); + return result; +} + +/* + * When 1, we use ECDSA unless we're using a depth which does not + * have curve orders. + * WARNING - enabling ECDSA by default breaks ICE and compatibility + * with Java signatures, at least until we have a Java ECDSA + * implementation. + */ +#define ECDSA_SIG_DEFAULT 0 + +- (NSData *)digitalSignatureForData:(NSData *)data +{ + NSData *result; + unsigned char *sig; + unsigned sigLen; + feeReturn frtn; + curveParams *cp; + + if(_pubKey == NULL) { + return nil; + } + cp = feePubKeyCurveParams(_pubKey); + if(!ECDSA_SIG_DEFAULT || isZero(cp->x1OrderPlus)) { + frtn = feePubKeyCreateSignature(_pubKey, + [data bytes], + [data length], + &sig, + &sigLen); + } + else { + frtn = feePubKeyCreateECDSASignature(_pubKey, + [data bytes], + [data length], + &sig, + &sigLen); + } + if(frtn) { + NSLog(@"digitalSignatureForData: %s\n", feeReturnString(frtn)); + return nil; + } + result = [NSData dataWithBytesNoCopy:sig length:sigLen]; + return result; +} + +- (BOOL)isValidDigitalSignature:(NSData *)signa + forData:(NSData *)data +{ + feeReturn frtn; + feeUnichar *sigSigner; + unsigned sigSignerLen; + curveParams *cp; + + if(_pubKey == NULL) { + return NO; + } + cp = feePubKeyCurveParams(_pubKey); + if(!ECDSA_SIG_DEFAULT || isZero(cp->x1OrderPlus)) { + frtn = feePubKeyVerifySignature(_pubKey, + [data bytes], + [data length], + [signa bytes], + [signa length], + &sigSigner, + &sigSignerLen); + } + else { + frtn = feePubKeyVerifyECDSASignature(_pubKey, + [data bytes], + [data length], + [signa bytes], + [signa length], + &sigSigner, + &sigSignerLen); + } + + /* + * FIXME - We just throw away the signer for now... + */ + if(sigSignerLen) { + ffree(sigSigner); + } + + switch(frtn) { + case FR_Success: + return YES; + case FR_InvalidSignature: + return NO; + default: + /* + * Something other than simple signature mismatch... + */ + NSLog(@"isValidDigitalSignature: %s\n", feeReturnString(frtn)); + return NO; + } +} + +@end + +@implementation NSFEEPublicKey(Private) + +- (key)minus +{ + if(_pubKey == NULL) { + return NULL; + } + return feePubKeyMinusCurve(_pubKey); +} + +- (key)plus +{ + if(_pubKey == NULL) { + return NULL; + } + return feePubKeyPlusCurve(_pubKey); +} + +- (feePubKey)feePubKey +{ + return _pubKey; +} + +#if FEE_DEBUG +- (void)dump +{ + printPubKey(_pubKey); +} +#endif FEE_DEBUG + +@end