当前位置: 首页 > 编程日记 > 正文

iOS使用Security.framework进行RSA 加密解密签名和验证签名

iOS 上 Security.framework为我们提供了安全方面相关的api;

Security框架提供的RSA在iOS上使用的一些小结

  • 支持的RSA keySize 大小有:512,768,1024,2048位
  • 支持的RSA 填充方式有三种:NOPadding,PKCS1,OAEP 三种方式 ,填充方式影响最大分组加密数据块的大小
  • 签名使用的填充方式PKCS1, 支持的签名算法有 sha1,sha256,sha224,sha384,sha512
  • Nopadding填充最大数据块为 下面接口 SecKeyGetBlockSize 大小;
  • PKCS1 填充方式最大数据为 SecKeyGetBlockSize大小 减去11
  • OAEP 填充方式最大数据为 SecKeyGetBlockSize 大小减去 42
  • RSA加密解密签名,适合小块的数据处理,大量数量需要处理分组逻辑;密码学中推荐使用对称加密进行数据加密,使用RSA来加密对称密钥
  • iOS10,以及mac 10.12中新增加了几个接口,以下测试用的是老接口,支持iOS2.0+

在这里说明一下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的大小,如这里128kSecPaddingPKCS1     = 1,   要加密的数据块大小<=128-11kSecPaddingOAEP      = 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

//
//  NSData+KKHASH.h
//  SecurityiOS
//
//  Created by cocoa on 16/12/15.
//  Copyright © 2016年 dev.keke@gmail.com. All rights reserved.
//

#import <Foundation/Foundation.h>typedef enum : NSUInteger {//md2 16字节长度CCDIGEST_MD2 = 1000,//md4 16字节长度
    CCDIGEST_MD4,//md5 16字节长度
    CCDIGEST_MD5,//sha1 20字节长度
    CCDIGEST_SHA1,//SHA224 28字节长度
    CCDIGEST_SHA224,//SHA256 32字节长度
    CCDIGEST_SHA256,//SHA384 48字节长度
    CCDIGEST_SHA384,//SHA512 64字节长度
    CCDIGEST_SHA512,
} CCDIGESTAlgorithm;@interface NSData (KKHASH)/**计算数据的hash值,根据不同的算法*/
- (NSData *)hashDataWith:(CCDIGESTAlgorithm )ccAlgorithm;/**返回 hex string的 data*/
- (NSString *)hexString;@end
View Code
//
//  NSData+KKHASH.m
//  SecurityiOS
//
//  Created by cocoa on 16/12/15.
//  Copyright © 2016年 dev.keke@gmail.com. All rights reserved.
//

#import "NSData+KKHASH.h"
#include <CommonCrypto/CommonDigest.h>@implementation NSData (KKHASH)
- (NSData *)hashDataWith:(CCDIGESTAlgorithm )ccAlgorithm
{NSData *retData = nil;if (self.length <1) {return nil;}unsigned char *md;switch (ccAlgorithm) {case CCDIGEST_MD2:{md = malloc(CC_MD2_DIGEST_LENGTH);bzero(md, CC_MD2_DIGEST_LENGTH);CC_MD2(self.bytes, (CC_LONG)self.length, md);retData = [NSData dataWithBytes:md length:CC_MD2_DIGEST_LENGTH];}break;case CCDIGEST_MD4:{md = malloc(CC_MD4_DIGEST_LENGTH);bzero(md, CC_MD4_DIGEST_LENGTH);CC_MD4(self.bytes, (CC_LONG)self.length, md);retData = [NSData dataWithBytes:md length:CC_MD4_DIGEST_LENGTH];}break;case CCDIGEST_MD5:{md = malloc(CC_MD5_DIGEST_LENGTH);bzero(md, CC_MD5_DIGEST_LENGTH);CC_MD5(self.bytes, (CC_LONG)self.length, md);retData = [NSData dataWithBytes:md length:CC_MD5_DIGEST_LENGTH];}break;case CCDIGEST_SHA1:{md = malloc(CC_SHA1_DIGEST_LENGTH);bzero(md, CC_SHA1_DIGEST_LENGTH);CC_SHA1(self.bytes, (CC_LONG)self.length, md);retData = [NSData dataWithBytes:md length:CC_SHA1_DIGEST_LENGTH];}break;case CCDIGEST_SHA224:{md = malloc(CC_SHA224_DIGEST_LENGTH);bzero(md, CC_SHA224_DIGEST_LENGTH);CC_SHA224(self.bytes, (CC_LONG)self.length, md);retData = [NSData dataWithBytes:md length:CC_SHA224_DIGEST_LENGTH];}break;case CCDIGEST_SHA256:{md = malloc(CC_SHA256_DIGEST_LENGTH);bzero(md, CC_SHA256_DIGEST_LENGTH);CC_SHA256(self.bytes, (CC_LONG)self.length, md);retData = [NSData dataWithBytes:md length:CC_SHA256_DIGEST_LENGTH];}break;case CCDIGEST_SHA384:{md = malloc(CC_SHA384_DIGEST_LENGTH);bzero(md, CC_SHA384_DIGEST_LENGTH);CC_SHA384(self.bytes, (CC_LONG)self.length, md);retData = [NSData dataWithBytes:md length:CC_SHA384_DIGEST_LENGTH];}break;case CCDIGEST_SHA512:{md = malloc(CC_SHA512_DIGEST_LENGTH);bzero(md, CC_SHA512_DIGEST_LENGTH);CC_SHA512(self.bytes, (CC_LONG)self.length, md);retData = [NSData dataWithBytes:md length:CC_SHA512_DIGEST_LENGTH];}break;default:md = malloc(1);break;}free(md);md = NULL;return retData;}- (NSString *)hexString
{NSMutableString *result = nil;if (self.length <1) {return nil;}result = [[NSMutableString alloc] initWithCapacity:self.length * 2];for (size_t i = 0; i < self.length; i++) {[result appendFormat:@"%02x", ((const uint8_t *) self.bytes)[i]];}return result;
}@end
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/documentation/Security/Conceptual/cryptoservices/CryptographyConcepts/CryptographyConcepts.html#//apple_ref/doc/uid/TP40011172-CH8-SW1

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

相关文章:

Android APK反编译详解(附图)

这段时间在学Android应用开发&#xff0c;在想既然是用Java开发的应该很好反编译从而得到源代码吧&#xff0c;google了一下&#xff0c;确实很简单&#xff0c;以下是我的实践过程。 在此郑重声明&#xff0c;贴出来的目的不是为了去破解人家的软件&#xff0c;完全是一种学习…

你不知道的18个Python高效编程技巧

来源 | Python编程时光初识Python语言&#xff0c;觉得python满足了我上学时候对编程语言的所有要求。python语言的高效编程技巧让我们这些大学曾经苦逼学了四年c或者c的人&#xff0c;兴奋的不行不行的&#xff0c;终于解脱了。高级语言&#xff0c;如果做不到这样&#xff0c…

Alisql源码编译安装(详细篇)

前言 AliSQL 在 2016 云栖大会宣布开放源代码之后&#xff0c;迅速就获得了广泛的关注&#xff0c;目前(2016-10-27) star 数目已达 1187&#xff0c;欢迎访问 AliSQL GitHub 项目关注。社区反应也非常活跃&#xff0c;在 Issue 中提了不少反馈建议&#xff0c;其中有一部分是和…

如何给DataGrid添加自动增长列

作者&#xff1a; cuike519的专栏 http://blog.csdn.net/cuike519/我想我们都知道在数据库中如何添加自增长列&#xff0c;我们可以将这个自增长列绑定到DataGrid上使得用户方便的知道现在是第几行&#xff0c;今天我介绍一种不用数据库就可以简单显示出自增长列的方法&…

达摩院NLP团队斩获六项世界冠军背后,让AI没有难懂的语言

2018年末&#xff0c;BERT横空出世&#xff0c;它采用自编码对句子进行表示&#xff0c;通过预测掩盖词和上下句之间的关系作为语言模型学习任务&#xff0c;使用更多的数据&#xff0c;更大的模型&#xff0c;在多个自然语言处理&#xff08;NLP&#xff09;任务中显著超越之前…

提权巧用RAR.EXE

rar.exe是什么&#xff1f;它就是大名鼎鼎的winrar自带的命令行解压程序。在提权中我们经常要下载各种敏感文件&#xff0c;比如:SU目录。你想一下&#xff0c;如果su目录文件这么多&#xff0c;难道你要一个个的下载&#xff1f;&#xff1f;这明显就很麻烦&#xff0c;有了ra…

OSGI企业应用开发(二)Eclipse中搭建Felix运行环境

上篇文章介绍了什么是OSGI以及使用OSGI构建应用的优点&#xff0c;接着介绍了两款常用的OSGI实现&#xff0c;分别为Apache Felix和Equinox&#xff0c;接下来开始介绍如何在Eclipse中使用Apache Felix和Equinox搭建OSGI运行环境。 一、搭建Apache Felix运行环境 上篇文章中介绍…

马斯克脑机接口、BrainOS相继发布,不努力也能有出路了

作者 | 马超责编 | Carol封图 | CSDN 下载自视觉中国在北京时间的8月29日凌晨&#xff0c;钢铁侠埃隆马斯克投资1亿多美元的脑机接口初创公司公司Neuralink&#xff08;http://www.neurolink.company/&#xff09;进行了一次现场发布会&#xff0c;展示新一代的脑机接口设备。这…

C语言单向链表的实现

一个简单结点的结构体表示为&#xff1a;struct note{int data&#xff1b; /*数据成员可以是多个不同类型的数据*/struct note *next&#xff1b; /*指针变量成员只能是-个*/}&#xff1b; 一个简单的单向链表的图示1&#xff0e;链表是结构、指针相结合…

Java开发常用Linux命令

1.查找文件 find / -name filename.txt根据名称查找/目录下的filename.txt文件。 find . -name "*.xml"递归查找所有的xml文件 find . -name "*.xml" |xargs grep "hello world"递归查找所有文件内容中包含hello world的xml文件 grep -H spring …

数据库开发基本操作-安装Sql Server 2005出现“性能监视器计数器要求”错误解决方法...

今天在安装SQL Server 2005时&#xff0c;出现“性能监视器计数器要求”错误&#xff0c;因为以前出现过这种错误&#xff0c;得到了解决。今天又又出现这种错误&#xff0c;但并不是很清楚当时的解决办法&#xff0c;所以这次把解决方法记录下来&#xff0c;供自己以后参考&am…

华为昇腾师资培训沙龙·南京场 |华为昇腾 ACL 语言开发实践全程干货来了!看完就实操系列...

自今年疫情以来&#xff0c;AI 技术加速进入了人们的视线&#xff0c;在抗疫过程中发挥了重要作用&#xff0c;产业发展明显提速&#xff0c;我国逐步走出了一条由需求导向引领商业模式创新、市场应用倒逼基础理论和关键技术创新的发展道路&#xff0c;AI 人才的争夺战也正式打…

设计模式之C#实现---Builder

作者&#xff1a;cuike519的专栏 http://blog.csdn.net/cuike519/我们将要介绍一个和它比较像的创建型模式 Builder &#xff08;至于关于 Builder 的详细内容您可以参考 GOF 的书&#xff0c;在这里不重复了。&#xff09;。在 GOF 的书里 Builder 的目的是这样的&#xff1…

微信小程序开发之不能使用eval函数的问题

2019独角兽企业重金招聘Python工程师标准>>> 一 eval函数问题 JavaScript中的eval函数是颇受开发者争议的问题之一&#xff0c;问题主要在于其可能导致的不安全性。有关此方面问题&#xff0c;在此不再赘述&#xff0c;读者可能很容易地浏览到许多介绍性文章。 但是…

设计模式之C#实现--FactoryMethod

作者&#xff1a;cuike519的专栏 http://blog.csdn.net/cuike519/工厂方法的目的很明确就是定义一个用来创建对象的接口&#xff0c;但是他不直接创建对象&#xff0c;而由他的子类来创建&#xff0c;这样一来就将创建对象的责任推迟到了该接口的子类中&#xff0c;创建什么类…

美国AI博士指出,自学Python到底能做什么

我见过市面上很多的 Python 讲解教程和书籍&#xff0c;他们大都这样讲 Python 的&#xff1a;先从 Python 的发展历史开始&#xff0c;介绍 Python 的基本语法规则&#xff0c;Python 的 list, dict, tuple 等数据结构&#xff0c;然后再介绍字符串处理和正则表达式&#xff0…

关于微博溯源的后续问题

1、在进行关键词搜索的时候&#xff0c;如何分词&#xff0c;我们不可能用语料库进行匹配&#xff0c;已没有语料可以学习。 2、关于转折点的寻找。目前我们使用高级搜索&#xff0c;从当前时间往前推&#xff0c;根据搜索到微博的条数变化&#xff0c;确定时间发生具体时间&am…

python3的数据类型以及模块的含义

python3的数据类型以及模块的含义购物车转载于:https://blog.51cto.com/11834445/1884901

设计模式之C#实现---- ProtoType

作者&#xff1a; cuike519的专栏 http://blog.csdn.net/cuike519/该模式的意图是&#xff1a;用原型实例指定创建对象的种类&#xff0c;并且通过拷贝这些原型创建新的对象。那么首先我们应该已经有了一个对象&#xff0c;同时这个对象还支持自我复制&#xff08;科隆&…

快速排序(二)最后修改

1 //2012-07-162 void quickSort(element list[], int left, int right)//快速排序3 {4 int ileft;5 int jright;6 7 if(i > j) //判断需要i<j8 return;9 10 element templist[i]; 11 12 while(i<j) 13 { 14 while(i<j …

性能超越GPU、FPGA,华人学者提出软件算法架构加速AI实时化

作者 | 王言治&#xff0c;美国东北大学电子与计算机工程系助理教授出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;近年来&#xff0c;机器学习(Machine Learning)领域的研究和发展可谓是与日俱新&#xff0c;各式各样与机器学习相关的研究成果与应用层出不穷&#…

PHP获取毫秒时间戳,利用microtime()函数

PHP获取毫秒时间戳&#xff0c;利用microtime()函数 php本身没有提供返回毫秒数的函数&#xff0c;但提供了一个microtime()函数&#xff0c;借助此函数&#xff0c;可以很容易定义一个返回毫秒数的函数。php的毫秒是没有默认函数的&#xff0c;但提供了一个microtime()函数&am…

.NET中添加控件数组

作者&#xff1a;cuike519的专栏 http://blog.csdn.net/cuike519/添加控件数组 在.NET里面我好像没有找到有关于控件数组的说明,但是前两天偶在网上看到了一篇关于如何在.NET里面实现控件数组的文章(该文章请参看MSDN).记得大学的时候在使用VB的时候使用过控件数组,可是到了…

如何在机器学习的框架里实现隐私保护?

编者按&#xff1a;数据时代&#xff0c;人们从技术中获取便利的同时&#xff0c;也面临着隐私泄露的风险。微软倡导负责任的人工智能&#xff0c;因此机器学习中的隐私保护问题至关重要。本文介绍了目前机器学习中隐私保护领域的最新研究进展&#xff0c;讨论了机密计算、模型…

函数图像轻松画:教你用永中图象

函数图像轻松画&#xff1a;教你用永中图象 函数图像轻松画&#xff1a;教你用永中图象转载于:https://blog.51cto.com/premium/933220

c语言语系的命名风格和java系命名风格

c语言系的命名风格&#xff1a;单词之间使用下划线分隔。如上图。 java语言是另外一个系&#xff0c;javascript属于java语系(当年就是想借助java的名气所以命名javascript)。java语系是驼峰式命名法&#xff0c;如getElementById()。如果使用c语系命名风格则使用下划线分隔 ge…

全国IP地址分配表

xa.sn.cn,西安公众网,西安,陕西,CN,202.100.0.* xa.sn.cn,西安公众网,西安,陕西,CN,202.100.1.* xa.sn.cn,西安公众网,西安,陕西,CN,202.100.2.* xa.sn.cn,西安公众网,西安,陕西,CN,202.100.3.* xa.sn.cn,西安公众网,西安,陕西,CN,202.100.4.* xa.sn.cn,西安公众网,西安,陕西,C…

神同步!美国三地 Tesla 车主,自动驾驶都撞了警车

来源 | HyperAI超神经&#xff08;ID&#xff1a;HyperAI&#xff09;内容概要&#xff1a;上周在美国北卡州发生了一起交通事故&#xff0c;一辆自动驾驶模式下的 Tesla 撞击了停靠在路边的警车&#xff0c;虽未造成人员伤亡&#xff0c;但车辆损毁严重。事故调查中发现&#…

Q币才是腾讯真正的世界级产品

本文受《虚拟货币将是下一个大平台》启发而来。何玺认为&#xff0c;腾讯Q币本身就具有全球化虚拟货币的基因。 日前&#xff0c;有媒体报道了Pocket Change获得了由Google Ventures领投的500万美元A轮融资&#xff0c;使其融资总额达到640万美元。 Pocket Change是一个为Andro…

解决Office互操作错误检索COML类工厂中 CLSID为 {xxx}的组件时失败,原因是出现以下错误: 80070005...

Excel为例&#xff08;其他如Word也适用&#xff09;文件数据导入时报出以下错误: 检索COML类工厂中 CLSID为 {00024500-0000-0000-C000-000000000046}的组件时失败&#xff0c;原因是出现以下错误: 80070005&#xff0c;如图所示: 可以看到报出的异常类型为:UnauthorizedAcces…