当前位置: 首页 > news >正文

iOS-在项目中引入RSA算法

1.前言

契机是公司换了一套新接口,要求进行全报文加密。以前公司项目基本上都使用的对称加密的模式3DESAES,由于对称加密的密钥只有一对,有很大的密钥泄露风险。身处金融这个极为敏感的行业,对安全的要求也是极高。趁着这个机会,把项目中的加密模式统一替换成RSA非对称加密。

2.关于加密算法

本篇不会对RSA加密算法原理进行详细的解释。在互联网异常发达的今天,RSA算法详细的资料很容易就能获取到。安全领域也是一个能够深挖的领域,本篇文章偏向工程向,仅对一些基本基本概念进行简单的解释。

  • 对称加密和非对称加密

  1. 对称加密 :加密和解密用的是同一套密钥,缺陷是密钥管理存在风险。常用的加密方式有:DES3DESAES等。

  2. 非对称加密 :加密和解密用的不同的密钥,公钥加密私钥解密。常用的加密方式有RSA

  • RSA常见用法

  1. 公钥加密,私钥解密;

  2. 私钥签名;

  3. 公钥验签。

3.实践

1、生成密钥:

使用终端openssl命令生成密钥

1).生成私钥,密钥长度为2048bit,base64编码。

openssl genrsa -out rsa_private_key.pem 2048
复制代码

关于密钥长度,这里要进行一下特别说明。每次加密的数据不能超出密钥的长度,2048bit长度的密钥,只能单次只能加密(2048 / 8 - 11) = 245byte长度的数据。(那11byte是RSA预留的长度)。若待加密的数据长度超过了245byte,就需要对数据进行分段加密。

2).根据之前生成的私钥生成公钥:

openssl rsa -in rsa_private_key.pem -out rsa_public_key.pem -pubout
复制代码

3).转换公钥为PKCS8格式,这种格式可以直接在iOS项目中使用:

openssl pkcs8 -topk8 -in rsa_private_key.pem -out pkcs8_rsa_private_key.pem -nocrypt
复制代码

我司的情况是由公司后台生成私钥和公钥,提供.pem格式的公钥给移动端,因此我直接使用的是pkcs8格式的公钥。

注意:不建议将私钥保存在客户端,私钥泄露后果会很严重!

2、在项目中使用:

Demo地址:github.com/Hstripe/RHR…

以上是我使用的RSA工具类,支持RSA在移动端的各种日常用法:加密、解密、加签、验签。跟网上很多工具类不同的是不需要导入p12der格式的密钥文件,支持字符串形式的密钥文件非常方便。而且使用的是Apple自家的Security.framework。网上很多例程都是使用的openSSL那一套加密工具类,实现也很方便就是包体积略微有点大。

若使用IDEXcode8及以上,请在Capabilities中将KeyChain sharing设置为YES

1.)公钥加密

NSString *string = @"doRSAEncrypt";

NSString *publickey = @"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA61sODmFj/OXnrHUYzams\
 c/6XLni9G0HYv9sBewaPjF6qlu845nwmYSA6dQ9zPk231o5l3tmHLpUQGNnp/5rH\
 +84iB/tM+Y+2kTI8uILGbmby2DL3rgzBG+I9h7e3w3QktpdcD8Z+ZuEVa/CY3Xez\
 8X1uknEVzIIhDKY7ipAoebchVdELbTlH1BRLz8RH6mQ+Z8REH4UL0TiQLfSfTotv\
 1G5ZerNxVZ7Toi4K9KFDA+1UD+LeDGg8PY/sdg0AJpR4o6bfDBko50wKLDz4UYyp\
 7EFZv661o2Mr7+KoQ6Tpb7w8bTl7wrRKz9ugB5+tM2F7aDvv1mzr7STIF+2c7tEx\
 DQIDAQAB";

NSString *encryptString = [IPNRSAUtil encryptString:string publicKey:publickey];
复制代码

2.)私钥解密

NSString *privatekey = @"MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDrWw4OYWP85ees\
 dRjNqaxz/pcueL0bQdi/2wF7Bo+MXqqW7zjmfCZhIDp1D3M+TbfWjmXe2YculRAY\
 2en/msf7ziIH+0z5j7aRMjy4gsZuZvLYMveuDMEb4j2Ht7fDdCS2l1wPxn5m4RVr\
 8Jjdd7PxfW6ScRXMgiEMpjuKkCh5tyFV0QttOUfUFEvPxEfqZD5nxEQfhQvROJAt\
 9J9Oi2/Ubll6s3FVntOiLgr0oUMD7VQP4t4MaDw9j+x2DQAmlHijpt8MGSjnTAos\
 PPhRjKnsQVm/rrWjYyvv4qhDpOlvvDxtOXvCtErP26AHn60zYXtoO+/WbOvtJMgX\
 7Zzu0TENAgMBAAECggEBAOMf6w+ror9y6sE9+6K1hEwoO6NIN06vm8mCQwqDiVIw\
 JTYlQ+cBllQSsvc24sMUYz32C48ko1Ur2u3wleXqa+Wvxp2nQWBw9QFn1rtE0NPI\
 G8DSZr0bZ9xN1406mWdQlQF0Tg6XQnJr8q1I8WyAUTHSFzvRT/Uc+2Hmpf0RI05Y\
 t0dt5bsGn/g+ijGbCm63Z2U8u5yWXidxWfU/KyYf1Y3mw9lGLR6IJc/q9N+TO4ih\
 JM5pCraMFI4zWblGobkN2WKy7MrQ45FLSKul4W00+VyM/rVivW/fYUaqFEnlBog3\
 /4hgI6Bsw2IuSk2Ubhbc4fp//146vJf6oL4WAJHmAiECgYEA+e3AFph8joC5gC1Q\
 ok97tLJqt95fZCx4VCw6lPPbWxOHG6TJlvlo7kZIeUfKrGIlOWn38yuw5thEZKwW\
 bzE8kn5WGlUgkOQ7hJ6Iiw/TzCFPRHxV63WBKa8OnyFIn3w91zI8ZTcUgrgyns+F\
 gE5uxkEjb6iIyxxnpqC7Fk3lnikCgYEA8RKtn7kqoe0T/Yv7UsPLm7KzuWn3/01r\
 LGA+x+GCp4rP2Lf0u1K+7VY6Dv/ceTBuA/2Yujenkjt0LaF+Bz0tLWFB5BTw3n+u\
 6QshVdP3O1im4w6p3e8O9mfBCSV/CX5oBkbamemyQ7DTB9VtYNNmtGTs2aySuoel\
 zPU0czETEEUCgYAjVhwclb62nzibCM0nxbkl2TwBdy1hinAQ5pf5y2iuPdqSbAAc\
 mnLdjY5dp2reaJn+vh7SgNDoMpeo7DPX0MxRog8mdfa+xaYsoAWKM9isOeFtO28i\
 dWCnthqJITmVYwmTTYUAgoMh4E036vtjIrPC0B7kgJ2mqgN1qbAJ/UWD0QKBgFSO\
 U53hacWwDUHydm2aRXFQJd/T/mtq8Tt4aqzbOWOgubRvGYUWyecfRm/6aI+NYBlA\
 OvCeEsWk2uQib70ERTNUmLLycWXpbSVKhR/AoEgNmUOs4gH5FstwqvGVWFCxKLWC\
 5qvzn1ZE0FBAGQRMQgrmF3lmIXURnSMdoo8A2IntAoGAVCFmPpXvI8rMk2N3CvQ4\
 dkDfP3W6w1KpyMzuQRZE9N1IUBYh3KN25HfzeW1OIFHPuxInMm/6zaU/rUHJSy/b\
 ynVdQ6jvM4ZIt3rYUXZN6+a14AeA/MNNrY2LzCYlCxWIbVyNj9UN8/uda0zEtZ73\
 RWYX1BlKVMSIx5Bf7eNH4fI=";

NSString *decryptString = [IPNRSAUtil decryptString:encryptString privateKey:privatekey];
复制代码

3.)私钥加签

 NSString *signature = [IPNRSAUtil rsaSignString:string WithPrivateKey:privatekey];
复制代码

4.)公钥验签

BOOL result = [IPNRSAUtil rsaVerifySignature:signature plainString:string WithPublicKey:publickey];
复制代码

5.)分段加密

若待加密的数据长度大于密钥长度,就需要对待加密的数据进行分段加密

// n为密钥单次加密长度,这里使用的是2048位的密钥,因此n的值为245(2048/8 - 11)。
NSInteger n = 245;
NSMutableData *preData = [[NSMutableData alloc] init];
for (NSInteger i=0; i<=ceilf(string.length / n); i++) {
    NSString *subString = [string substringWithRange:NSMakeRange(i * n, MIN(n, string.length - i * 245))];
    NSData *encryptData = [IPNRSAUtil encryptData:[subString dataUsingEncoding:NSUTF8StringEncoding] publicKey:publickey];
// 分段加密需要拼接加密后的data数据,不要将data转换成字符串再拼接,这样会导致结果错误。
    [preData appendData:encryptData];
}

NSData *finalData = [[NSData alloc] initWithData:preData];
finalData = [finalData base64EncodedDataWithOptions:0];
NSString *result = [[NSString alloc] initWithData:finalData encoding:NSUTF8StringEncoding];
复制代码

4.后记

为了搞这个工具类前前后后花了也有半个多月的时间了,看了很多文档和例程加上自己的实践调试才有了这个工具类。一开始使用的是openSSL那一套加密工具实现的,但是觉得openSSL占用的空间略大,还是用Security.framework来实现的。平时总是忙于业务需求的实现,忽视了客户端方面的安全,网上对客户端安全这一块的资源也比较有限,但愿我这篇文章能对后来人有所帮助吧。

5.参考资料

看的资料比较多就不一一列举了,主要还是通过GoogleGitHubStackOverFlow简书知乎等平台来获取相关资源的。最后,就在这里统一感谢一下相关资源的贡献者吧。

转载于:https://juejin.im/post/5cca54ca518825408a3d0317

相关文章:

  • 简单的数学题
  • 关于JS引擎优化的理解
  • 如何优雅的备份账号相关信息
  • mybatis学习总结
  • 全球首个大规模光电芯片到来
  • 1.4T的mysql表删除
  • MYSQL-SELECT查
  • css 浮动的时候如何,div进行居中
  • 大文件如何传输,大文件的传输方式有哪些?
  • 5 分钟掌握 JavaScript 实用窍门
  • Kubernetes弹性伸缩全场景解读(五) - 定时伸缩组件发布与开源
  • Linux下Python3.6的安装及避坑指南
  • 四川建筑企业资质办理材料详细说明
  • 组件化页面:封装el-form
  • Redis过期策略
  • 实现windows 窗体的自己画,网上摘抄的,学习了
  • Mybatis初体验
  • Sass Day-01
  • SpringBoot几种定时任务的实现方式
  • 大整数乘法-表格法
  • 道格拉斯-普克 抽稀算法 附javascript实现
  • 分享自己折腾多时的一套 vue 组件 --we-vue
  • 服务器从安装到部署全过程(二)
  • 简析gRPC client 连接管理
  • 马上搞懂 GeoJSON
  • 使用 Xcode 的 Target 区分开发和生产环境
  • 一道闭包题引发的思考
  • ​LeetCode解法汇总2696. 删除子串后的字符串最小长度
  • ###STL(标准模板库)
  • (day 2)JavaScript学习笔记(基础之变量、常量和注释)
  • (附源码)ssm基于web技术的医务志愿者管理系统 毕业设计 100910
  • (论文阅读笔记)Network planning with deep reinforcement learning
  • (原創) 如何解决make kernel时『clock skew detected』的warning? (OS) (Linux)
  • (转)visual stdio 书签功能介绍
  • (转)菜鸟学数据库(三)——存储过程
  • .NET Framework与.NET Framework SDK有什么不同?
  • .net Signalr 使用笔记
  • .NET 跨平台图形库 SkiaSharp 基础应用
  • .net6解除文件上传限制。Multipart body length limit 16384 exceeded
  • .NET开源项目介绍及资源推荐:数据持久层
  • .Net中wcf服务生成及调用
  • [ Linux ] git工具的基本使用(仓库的构建,提交)
  • [ vulhub漏洞复现篇 ] AppWeb认证绕过漏洞(CVE-2018-8715)
  • []利用定点式具实现:文件读取,完成不同进制之间的
  • [Android View] 可绘制形状 (Shape Xml)
  • [android]-如何在向服务器发送request时附加已保存的cookie数据
  • [C puzzle book] types
  • [codeforces] 25E Test || hash
  • [Contest20180313]灵大会议
  • [HOW TO]如何在iPhone应用程序中发送邮件
  • [java]删除数组中的某一个元素
  • [java刷算法]牛客—剑指offer链表有环的入口、反转链表、合并排序链表
  • [Linux](16)网络编程:网络概述,网络基本原理,套接字,UDP,TCP,并发服务器编程,守护(精灵)进程
  • [Notes]python argparse模块
  • [PTP][1588v2] Delay_Resp消息