ecdsa

#include <openssl/rand.h>

#include <openssl/ecdsa.h>

#include <openssl/obj_mac.h>

#include <openssl/err.h>

#include <openssl/pem.h>

#include <openssl/evp.h>

#import <CommonCrypto/CommonDigest.h>

- (void)viewDidLoad {

    [super viewDidLoad];

    self.view.backgroundColor = UIColor.whiteColor;

    self.pubKey = [NSMutableString string];

    [self deleteKeyAsync];

}

#define Secp256r1CurveLen     256

unsigned char Secp256r1header[] =

{

    0x30, 0x59, 0x30, 0x13, 0x06, 0x07,

    0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02,

    0x01, 0x06, 0x08, 0x2A, 0x86, 0x48,

    0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03,

    0x42, 0x00

};

#define Secp256r1headerLen    26

#define PublicKeyInitialTag       @"-----BEGIN PUBLIC KEY-----\n"

#define PublicKeyFinalTag         @"\n-----END PUBLIC KEY-----"

//产生密钥

- (void)generateKeyAsync {

    

    CFErrorRef error = NULL;

    SecAccessControlRef sacObject;

    

    //设置ACL,使用kSecAccessControlTouchIDAny表示使用Touch ID来保护密钥。

    sacObject = SecAccessControlCreateWithFlags(kCFAllocatorDefault,

                                                kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,

                                                kSecAccessControlTouchIDAny |

                                                kSecAccessControlPrivateKeyUsage, &error);

    

    NSDictionary *parameters = @{

                                 (__bridge id)kSecAttrTokenID: (__bridge id)kSecAttrTokenIDSecureEnclave,//表示使用SecureEnclave来保存密钥

                                 (__bridge id)kSecAttrKeyType: (__bridge id)kSecAttrKeyTypeECSECPrimeRandom,//表示产生ECC密钥对,注意目前只支持256位的ECC算法

                                 (__bridge id)kSecAttrKeySizeInBits: @256,

                                 (__bridge id)kSecPrivateKeyAttrs: @{

                                         (__bridge id)kSecAttrAccessControl: (__bridge_transfer id)sacObject,

                                         (__bridge id)kSecAttrIsPermanent: @YES,

                                         (__bridge id)kSecAttrLabel: @"my-seec-key",

                                         },

                                 };

    

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        SecKeyRef publicKey, privateKey;

        OSStatus status = SecKeyGeneratePair((__bridge CFDictionaryRef)parameters, &publicKey, &privateKey);

        if (status == errSecSuccess) {

            NSLog(@"产生密码成功");

            

            //这里先把公钥保存到keychain才能拿到真正的公钥数据

            NSDictionary *pubDict = @{

                                      (__bridge id)kSecClass              : (__bridge id)kSecClassKey,

                                      (__bridge id)kSecAttrKeyType        : (__bridge id)kSecAttrKeyTypeECSECPrimeRandom,

                                      (__bridge id)kSecAttrLabel          : @"public",

                                      (__bridge id)kSecAttrIsPermanent    : @(YES),

                                      (__bridge id)kSecValueRef           : (__bridge id)publicKey,

                                      (__bridge id)kSecAttrKeyClass       : (__bridge id)kSecAttrKeyClassPublic,

                                      (__bridge id)kSecReturnData         : @(YES)

                                      };

            

            CFTypeRef dataRef = NULL;

            status = SecItemAdd((__bridge CFDictionaryRef)pubDict, &dataRef);

            if(status == errSecSuccess){

                NSLog(@"导出公钥成功");

                

                //下面是将公钥转换为PEM格式,为了后面使用openssl验证签名

                //PEM格式 = PublicKeyInitialTag +  Base64(Secp256r1header + publicKeyData) + PublicKeyFinalTag

                NSData *publicKeyData = (__bridge NSData *)dataRef;

                NSLog(@"publicKeyData :%@",publicKeyData);

                NSMutableData *data = [NSMutableData dataWithBytes:Secp256r1header

                                                            length:sizeof(Secp256r1header)];

                [data appendData:publicKeyData];

                NSString *base64String = [data base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];

                NSMutableString *publicKeyStr = [NSMutableString string];

                [publicKeyStr appendString:PublicKeyInitialTag];

                [publicKeyStr appendString:base64String];

                [publicKeyStr appendString:PublicKeyFinalTag];

                self.pubKey = publicKeyStr;

                NSLog(@"++++%@",self.pubKey);

            }else{

                NSLog(@"导出公钥失败");

            }

            

            CFRelease(dataRef);

            CFRelease(privateKey);

            CFRelease(publicKey);

            

            dispatch_async(dispatch_get_main_queue(), ^{

                [self useKeyAsync];

            });

        }else{

            NSLog(@"产生密码失败");

        }

    });

}

//使用密钥

- (void)useKeyAsync {

    

    NSDictionary *query = @{

                            (__bridge id)kSecClass: (__bridge id)kSecClassKey,

                            (__bridge id)kSecAttrKeyClass: (__bridge id)kSecAttrKeyClassPrivate,

                            (__bridge id)kSecAttrLabel: @"my-seec-key",

                            (__bridge id)kSecReturnRef: @YES,

                            (__bridge id)kSecUseOperationPrompt: @"验证签名"

                            };

    

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        SecKeyRef privateKey;

        OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&privateKey);

        

        if (status == errSecSuccess) {

            const unsigned char tmp[] = "123";

            NSData *rawData = [[NSData alloc] initWithBytes:tmp length:3];

            

            //调用SecKeyRawSign的时候系统会自动调起Touch ID验证用户指纹

            //指纹的验证和数据的签名都在Secure Enclave中进行保证了安全

//            status = SecKeyRawSign(privateKey, kSecPaddingPKCS1, dataToSign, sizeof(dataToSign), sign, &signatureLength);

            NSError *error;

            NSData *signature = CFBridgingRelease(SecKeyCreateSignature(privateKey, kSecKeyAlgorithmECDSASignatureMessageX962SHA256, (CFDataRef)rawData, (void *)&error));

            

            if (!error) {

                NSLog(@"SecKeyRawSign签名数据成功");

                //使用openSSL验证签名

                const char *pemPubKey = [self.pubKey UTF8String];

                BIO *buf = BIO_new_mem_buf((void*)pemPubKey, (int)self.pubKey.length);

                EC_KEY *ecKey = PEM_read_bio_EC_PUBKEY(buf, NULL, NULL, NULL);

                EC_KEY_print_fp(stdout, ecKey, 2);

                

                const uint8_t *dataToSign = [rawData bytes];

                size_t dataToSignLen = rawData.length;

                uint8_t hash[CC_SHA256_DIGEST_LENGTH];

                CC_SHA256(dataToSign, (uint32_t)dataToSignLen, hash);

                

                int ret = ECDSA_verify(0, hash, CC_SHA256_DIGEST_LENGTH, [signature bytes], signature.length, ecKey);

                if (ret == 1) {

                    NSLog(@"openssl 验证签名成功");

                }else{

                    NSLog(@"openssl 验证签名失败");

                }

            }

            CFRelease(privateKey);

        }

        else {

            NSLog(@"SecKeyRawSign签名数据失败");

        }

    });

}

//删除密钥

- (void)deleteKeyAsync {

    

    NSDictionary *query = @{

                            (__bridge id)kSecAttrTokenID: (__bridge id)kSecAttrTokenIDSecureEnclave,

                            (__bridge id)kSecClass: (__bridge id)kSecClassKey,

                            (__bridge id)kSecAttrKeyClass: (__bridge id)kSecAttrKeyClassPrivate,

                            (__bridge id)kSecAttrLabel: @"my-seec-key",

                            (__bridge id)kSecReturnRef: @YES,

                            };

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        OSStatus status = SecItemDelete((__bridge CFDictionaryRef)query);

        if(status == errSecSuccess){

            NSLog(@"delete success");

        }else{

            NSLog(@"delete fail");

        }

        

        [self generateKeyAsync];

    });

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值