赞
踩
iOS 上 Security.framework为我们提供了安全方面相关的api;
Security框架提供的RSA在iOS上使用的一些小结
在这里说明一下RSA 相关的接口使用和示例;
1. 主要接口有
/*! //生成密钥对 */ OSStatus SecKeyGeneratePair(CFDictionaryRef parameters, SecKeyRef * _Nullable CF_RETURNS_RETAINED publicKey, SecKeyRef * _Nullable CF_RETURNS_RETAINED privateKey) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_2_0); //加密 OSStatus SecKeyEncrypt( SecKeyRef key, SecPadding padding, const uint8_t *plainText, size_t plainTextLen, uint8_t *cipherText, size_t *cipherTextLen) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_2_0); //解密 OSStatus SecKeyDecrypt( SecKeyRef key, /* Private key */ SecPadding padding, /* kSecPaddingNone, kSecPaddingPKCS1, kSecPaddingOAEP */ const uint8_t *cipherText, size_t cipherTextLen, /* length of cipherText */ uint8_t *plainText, size_t *plainTextLen) /* IN/OUT */ __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_2_0); //签名 OSStatus SecKeyRawSign( SecKeyRef key, SecPadding padding, const uint8_t *dataToSign, size_t dataToSignLen, uint8_t *sig, size_t *sigLen) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_2_0); //验证签名 OSStatus SecKeyRawVerify( SecKeyRef key, SecPadding padding, const uint8_t *signedData, size_t signedDataLen, const uint8_t *sig, size_t sigLen) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_2_0); //分组加密的数据块大小 size_t SecKeyGetBlockSize(SecKeyRef key) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_2_0);
2. 首先生成RSA密钥对,生成1024位,即是 128字节
#define kRSA_KEY_SIZE 1024 @interface ViewController : UIViewController { SecKeyRef publicKeyRef; //公钥 SecKeyRef privateKeyRef;//私钥 } //生成RSA密钥对,公钥和私钥,支持的SIZE有 // sizes for RSA keys are: 512, 768, 1024, 2048. - (void)generateRSAKeyPair:(int )keySize { OSStatus ret = 0; publicKeyRef = NULL; privateKeyRef = NULL; ret = SecKeyGeneratePair((CFDictionaryRef)@{(id)kSecAttrKeyType:(id)kSecAttrKeyTypeRSA,(id)kSecAttrKeySizeInBits:@(keySize)}, &publicKeyRef, &privateKeyRef); NSAssert(ret==errSecSuccess, @"密钥对生成失败:%d",ret); NSLog(@"%@",publicKeyRef); NSLog(@"%@",privateKeyRef); NSLog(@"max size:%lu",SecKeyGetBlockSize(privateKeyRef)); }
3. 使用上面生成的密钥对进行加密解密测试
//公钥加密私钥密钥测试 /** 三种填充方式区别 kSecPaddingNone = 0, 要加密的数据块大小<=SecKeyGetBlockSize的大小,如这里128 kSecPaddingPKCS1 = 1, 要加密的数据块大小<=128-11 kSecPaddingOAEP = 2, 要加密的数据块大小<=128-42 密码学中的设计原则,一般用RSA来加密 对称密钥,用对称密钥加密大量的数据 非对称加密速度慢,对称加密速度快 */ - (void)testRSAEncryptAndDecrypt { [self generateRSAKeyPair:kRSA_KEY_SIZE]; NSData *srcData = [@"0123456789" dataUsingEncoding:NSUTF8StringEncoding]; NSLog(@"%@",srcData); uint8_t encData[kRSA_KEY_SIZE/8] = {0}; uint8_t decData[kRSA_KEY_SIZE/8] = {0}; size_t blockSize = kRSA_KEY_SIZE / 8 ; OSStatus ret; ret = SecKeyEncrypt(publicKeyRef, kSecPaddingNone, srcData.bytes, srcData.length, encData, &blockSize); NSAssert(ret==errSecSuccess, @"加密失败"); ret = SecKeyDecrypt(privateKeyRef, kSecPaddingNone, encData, blockSize, decData, &blockSize); NSAssert(ret==errSecSuccess, @"解密失败"); NSData *dedData = [NSData dataWithBytes:decData length:blockSize]; NSLog(@"dec:%@",dedData); if (memcmp(srcData.bytes, dedData.bytes, srcData.length)==0) { NSLog(@"PASS"); } }
4. 使用公钥密钥进行数据签名和验证签名
对数据签名:首先对原始数据进行hash计算,可以得到数据的hash值;然后对hash值进行签名;
- (void)testSignAndVerify { [self generateRSAKeyPair:kRSA_KEY_SIZE]; NSString *tpath = [[NSBundle mainBundle] pathForResource:@"src.txt" ofType:nil]; NSData *ttDt = [NSData dataWithContentsOfFile:tpath]; //使用了下面封装的hash接口 NSData *sha1dg = [ttDt hashDataWith:CCDIGEST_SHA1]; OSStatus ret; //私钥签名,公钥验证签名 size_t siglen = SecKeyGetBlockSize(privateKeyRef); uint8_t *sig = malloc(siglen); bzero(sig, siglen); ret = SecKeyRawSign(privateKeyRef, kSecPaddingPKCS1SHA256, sha1dg.bytes, sha1dg.length, sig, &siglen); NSAssert(ret==errSecSuccess, @"签名失败"); ret = SecKeyRawVerify(publicKeyRef, kSecPaddingPKCS1SHA256, sha1dg.bytes, sha1dg.length,sig, siglen); NSAssert(ret==errSecSuccess, @"验证签名失败"); if (ret==errSecSuccess) { NSLog(@"SIGN VERIFY PASS"); } }
5. 另外 iOS上 CommonCrypto/CommonDigest.h 中提供了密码学中常用的hash算法
如下我封装了一个NSData的分类,可以在签名中直接使用
支持的hash算法有 md2,md4,md5,sha1,sha224,sha256,sha384,sha512
View Code
View Code
6. 另外如果密钥由服务器生成,可以生成p12文件,来在ios上调用接口导入开发
OSStatus SecPKCS12Import(CFDataRef pkcs12_data, CFDictionaryRef options, CFArrayRef * __nonnull CF_RETURNS_RETAINED items) __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_2_0);
7. 另外为了配合验证,可以用openssl 命令对数据进行RSA加密解密
//使用公钥加密 1024位密钥 ,128字节 //openssl rsautl -encrypt -out pubenc.txt -in src.txt -inkey public.pem -pubin //使用私钥解密 //openssl rsautl -decrypt -in pubenc.txt -inkey private.pem -out pridec.txt
总结:
另外RSA密钥,私钥保存在手机上是不安全的;
一般在非越狱的手机上,我们可以把生成的SecKeyRef 保存在 keychain中;
但是在越狱的手机上,也是不安全的,因为可以导出keychain中的所有数据;
没有绝对的安全,根据业务场景来实际开发吧
封装工具:https://github.com/cocoajin/Security-iOS
参考:
https://developer.apple.com/library/content/samplecode/CryptoExercise/Introduction/Intro.html#//apple_ref/doc/uid/DTS40008019
https://developer.apple.com/library/content/samplecode/CryptoCompatibility/Introduction/Intro.html#//apple_ref/doc/uid/DTS40013654
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。