]> git.saurik.com Git - apple/security.git/blobdiff - Security/libsecurity_cryptkit/lib/NSFEEPublicKey.m
Security-57031.1.35.tar.gz
[apple/security.git] / 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 (file)
index 0000000..034af79
--- /dev/null
@@ -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 <Foundation/Foundation.h>
+#import <Foundation/NSUtilities.h>
+
+#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 <NSObject,NSPublicKey>)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