首先了解一下几个相关概念,以方便后面遇到的问题的解决:

  • RSA算法:1977年由Ron Rivest、Adi Shamirh和LenAdleman发明的,RSA就是取自他们三个人的名字。算法基于一个数论:将两个大素数相乘非常容易,但要对这个乘积的结果进行因式分解却非常困难,因此可以把乘积公开作为公钥。该算法能够抵抗目前已知的所有密码***。RSA算法是一种非对称算法,算法需要一对密钥,使用其中一个加密,需要使用另外一个才能解密。我们在进行RSA加密通讯时,就把公钥放在客户端,私钥留在服务器。

  • DER, PEM:既然使用RSA需要一对密钥,那么我们当然是要先使用工具来生成这样一对密钥了。在linux、unix下,最简单方便的就是使用openssl命令行了。而DER、PEM就是生成的密钥可选择的两种文件格式。DER是Distinguished Encoding Rules的简称,是一种信息传输语法规则,在ITU X.690中定义的。在ios端,我们的公钥就是需要这样一种格式的,我们可以从Certificate, Key, and Trust Services Reference这篇文档的SecCertificateCreateWithData函数的data参数的说明中看到。而PEM格式是一种对DER进行封装的格式,他只是把der的内容进行了base64编码并加上了头尾说明。openssl命令行默认输出的都是PEM格式的文件,要能够在ios下使用,我们需要指定使用DER或者先生成PEM然后转换称DER。

使用openssl命令行生成密钥对

1
openssl req -x509 -out public_key.der -outform der -new -newkey rsa:1024 -keyout private_key.pem

按照提示,填入私钥的密码,签名证书的组织名、邮件等信息之后,就会生成包含有公钥的证书文件public_key.der合私钥文件private_key.pem。public_key.der文件用于分发到ios客户端进行公钥加解密,而private_key.pem文件留在服务器端供php使用。当然,如果为了在服务器端进行加解密测试,那么我们还可以生成一个服务器端PHP使用的pem公钥文件:

1
openssl rsa -inprivate_key.pem -pubout -out public_key.pem

上面这个命令就会根据输入的私钥文件生成pem格式的公钥文件了。从这里也可以看到,根据私钥,我们是可以生成相对应的公钥的,这也就是为什么我们要把公钥放在客户端,而不是私钥放在客户端的原因了。

服务器端PHP的加解密函数

闲话不多说,贴一段代码,肯定能看懂的了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
classRSAEncryptTest {
constPRIVATE_KEY = "-----BEGIN ENCRYPTED PRIVATE KEY-----
MIICxjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQI2aEhi35m/scCAggA
MBQGCCqGSIb3DQMHBAihDOZw68gfKwSCAoAu2E/d2a9FgHDWoinhK2nMc2MlrgL+
kpWcZ5YyUEWUw87DFKrG7dkpAYOgLIpyDatXUVFy2EekZH0Iplqo+yswtho8NtpJ
7T7KJ0nbUXo4we658Ez0EHAnWw+xZegsmJGk2+5QRCALDFyYEIMp3UvqxBjPjfDM
1rEZ0j2o9U40ouDqUVxTpq7ZwHkx/EkB8xHwKpFexz8J0s6gjPy6yLUjX2ut63LD
6X4YPBQLCJIcaLZORoAQ01cxCaM+78WTLUjdhcaFvff9f1xkiUU3XrQQTpuM/3YH
MQ6SMYDAgiOLqSCiMc0VABwf0/kdBnxu9/C/CK82ehA29cVAe8o7HgKg+WszCzTE
+QRCJ2fa7nOd7UXzCDfKh5Hhq1RjLFocVK8OW7tIgW3ircltM1ow30FfEzIdvzmv
LP0QhfGI3o9VT7r5qihGxtXtnGeUEGwvK0j0ozznfsNej7sVFP0Jfw39TdUlEENh
OPjtuBBBHv/oafQ3jqYnrI4R12ZrEU0acm85vRJm32K1RT1ROMFpc5sU20S8nMGC
I3iCzUlJPQF0t07bKexayvfWlJVAwEqBBCPTnvfTMBEt33iC72dQELbzMAM/n7th
TcY/sReO/J4beGk3//c7PImKIOcIvKF9Gp99l/+BM/LMZ7Thd/qwMOV6Eb3T4BvY
ItC+P5Lr29XeINmLRHXKwr27uTxX0fwDpmpwkPbGreVXA2cCxHnEzkh2WP3qGa7q
+Cwi03ISTEcZbNxLRGArtFUOIvNpz4+FS07OLWVKGl6K6bTffBx1tlZ492SqyNAC
7aP4/4I9Malnt0VjRKYPBCkTvVhoWBG+ThoOav5IV+w7ZDy8mtcrcAII
-----ENDENCRYPTED PRIVATE KEY-----";
constPUBLIC_KEY = "-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDAqjJs08oHvNdhlWC+kGBd90PD
7CVjClhRTk3nn+2NNaP4Bi5N/A18rdrV6clNAGUz4i/5q/VQXeLiGYYqgmAkKCJe
gReMsfcnoOSWu+Tvxih/48pu1hwBrmMLFZPOOUWQ9YjQEo7SYBe0HKoEl6XMqNwz
HV7sk9x6BKz9QeLi5QIDAQAB
-----ENDPUBLIC KEY-----";
privatestatic$private_key;
privatestatic$public_key;
publicstaticfunctionprivate_encrypt($str){
self::setup_key();
if(openssl_private_encrypt($str, $encrypted, self::$private_key))
return$encrypted;
}
publicstaticfunctionprivate_decrypt($str){
self::setup_key();
if(openssl_private_decrypt($str, $decrypted, self::$private_key))
return$decrypted;
}
publicstaticfunctionpublic_decrypt($str){
self::setup_key();
if(openssl_public_decrypt($str, $decrypted, self::$public_key))
return$decrypted;
}
publicstaticfunctionpublic_encrypt($str){
self::setup_key();
if(openssl_public_encrypt($str, $encrypted, self::$public_key))
return$encrypted;
}
privatestaticfunctionsetup_key(){
if(!self::$private_key){
// 这里的test就是在生成证书的时候设置的私钥密码
self::$private_key= openssl_pkey_get_private(self::PRIVATE_KEY, "test");
}
if(!self::$public_key)
self::$public_key= openssl_pkey_get_public(self::PUBLIC_KEY);
}
}

IOS客户端的加解密

首先我们需要导入Security.framework,在ios中,我们主要关注四个函数

  • SecKeyEncrypt:使用公钥对数据进行加密

  • SecKeyDecrypt:使用私钥对数据进行解密

  • SecKeyRawVerify:使用公钥对数字签名和数据进行验证,以确认该数据的来源合法性。什么是数字签名,可以参考百度百科这篇文章?

  • SecKeyRawSign:使用私钥对数据进行摘要并生成数字签名

从这几个函数中,我们可以看到,我们使用公钥能做的事情就有两个:加密数据,以及对服务器端发来的数据进行签名认证,但是如果你想跟我之前想的一样,要使用公钥来对数据进行解密,那就没有自带API了。如果想在服务器端使用私钥加密数据,然后再在客户端使用公钥进行解密,以图这样来对交互数据进行加密,看来是行不通的。其实也应该是这样,公钥是公开的,因为他可以编译到二进制文本里面就认为他不能被获取其实是不对的。同时,RSA因为都是做大数的运算,算法性能上比较差,如果做大数据量的加解密,对IOS来讲,肯定也是不合适的。

这里就把使用公钥进行加密的代码贴出来:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
// 我们在前面使用openssl生成的public_key.der文件的base64值,用你自己的替换掉这里
#define RSA_KEY_BASE64 @"MIIC5DCCAk2gAwIBAgIJALUk4hrYth9oMA0GCSqGSIb3DQEBBQUAMIGKMQswCQYDVQQGEwJ\
DTjERMA8GA1UECAwIU2hhbmdoYWkxETAPBgNVBAcMCFNoYW5naGFpMQ4wDAYDVQQKDAVCYWl5aTEOMAwGA1UECwwFQmFpeWk\
xEDAOBgNVBAMMB1lvcmsuR3UxIzAhBgkqhkiG9w0BCQEWFGd5cTUzMTk5MjBAZ21haWwuY29tMB4XDTExMTAyNjAyNDUzMlo\
XDTExMTEyNTAyNDUzM1owgYoxCzAJBgNVBAYTAkNOMREwDwYDVQQIDAhTaGFuZ2hhaTERMA8GA1UEBwwIU2hhbmdoYWkxDjA\
MBgNVBAoMBUJhaXlpMQ4wDAYDVQQLDAVCYWl5aTEQMA4GA1UEAwwHWW9yay5HdTEjMCEGCSqGSIb3DQEJARYUZ3lxNTMxOTk\
yMEBnbWFpbC5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAK3cKya7oOi8jVMkRGVuNn/SiSS1y5knKLh6t98JukB\
DJZqo30LVPXXL9nHcYXBTulJgzutCOGQxw8ODfAKvXYxmX7QvLwlJRFEzrqzi3eAM2FYtZZeKbgV6PximOwCG6DqaFqd8X0W\
ezP1B2eWKz4kLIuSUKOmt0h3RpIPkatPBAgMBAAGjUDBOMB0GA1UdDgQWBBSIiLi2mehEgi/MwRZOld1mLlhl7TAfBgNVHSM\
EGDAWgBSIiLi2mehEgi/MwRZOld1mLlhl7TAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAB0GUsssoVEDs9vQxk0\
DzNr8pB0idfI+Farl46OZnW5ZwPu3dvSmhQ+yRdh7Ba54JCyvRy0JcWB+fZgO4QorNRbVVbBSuPg6wLzPuasy9TpmaaYaLLK\
Iena6Z60aFWRwhazd6+hIsKTMTExaWjndblEbhAsjdpg6QMsKurs9+izr"
staticSecKeyRef_public_key=nil;
+ (SecKeyRef) getPublicKey{ // 从公钥证书文件中获取到公钥的SecKeyRef指针
if(_public_key == nil){
NSData*certificateData = [Base64 decode:RSA_KEY_BASE64];
SecCertificateRefmyCertificate = SecCertificateCreateWithData(kCFAllocatorDefault, (CFDataRef)certificateData);
SecPolicyRefmyPolicy = SecPolicyCreateBasicX509();
SecTrustRefmyTrust;
OSStatusstatus = SecTrustCreateWithCertificates(myCertificate,myPolicy,&myTrust);
SecTrustResultType trustResult;
if(status == noErr) {
status = SecTrustEvaluate(myTrust, &trustResult);
}
_public_key = SecTrustCopyPublicKey(myTrust);
CFRelease(myCertificate);
CFRelease(myPolicy);
CFRelease(myTrust);
}
return_public_key;
}
+ (NSData*) rsaEncryptString:(NSString*) string{
SecKeyRefkey = [selfgetPublicKey];
size_tcipherBufferSize = SecKeyGetBlockSize(key);
uint8_t*cipherBuffer = malloc(cipherBufferSize * sizeof(uint8_t));
NSData*stringBytes = [string dataUsingEncoding:NSUTF8StringEncoding];
size_tblockSize = cipherBufferSize - 11;
size_tblockCount = (size_t)ceil([stringBytes length] / (double)blockSize);
NSMutableData*encryptedData = [[[NSMutableDataalloc] init] autorelease];
for(inti=0; i<blockCount; i++) {
intbufferSize = MIN(blockSize,[stringBytes length] - i * blockSize);
NSData*buffer = [stringBytes subdataWithRange:NSMakeRange(i * blockSize, bufferSize)];
OSStatusstatus = SecKeyEncrypt(key, kSecPaddingPKCS1, (constuint8_t*)[buffer bytes],
[buffer length], cipherBuffer, &cipherBufferSize);
if(status == noErr){
NSData*encryptedBytes = [[NSDataalloc] initWithBytes:(constvoid*)cipherBuffer length:cipherBufferSize];
[encryptedData appendData:encryptedBytes];
[encryptedBytes release];
}else{
if(cipherBuffer) free(cipherBuffer);
returnnil;
}
}
if(cipherBuffer) free(cipherBuffer);
// NSLog(@"Encrypted text (%d bytes): %@", [encryptedData length], [encryptedData description]);
// NSLog(@"Encrypted text base64: %@", [Base64 encode:encryptedData]);
returnencryptedData;
}

http://blog.yorkgu.me/2011/10/27/rsa-in-ios-using-publick-key-generated-by-openssl/

转载于:https://blog.51cto.com/techforlcl/1323131

ios下使用rsa算法与php进行加解密通讯相关推荐

  1. linux安装php7 nagnx,iOS下使用rsa算法與php進行加解密通訊

    首先了解一下幾個相關概念,以方便后面遇到的問題的解決: RSA算法:1977年由Ron Rivest.Adi Shamirh和LenAdleman發明的,RSA就是取自他們三個人的名字.算法基於一個數 ...

  2. java中使用openssl生成的rsa公私钥进行数据加解密_使用openssl生成RSA公钥和私钥对...

    在ubuntu上要使用openssl的话需要先进行安装,命令如下: sudo apt-get install openssl 安装完成就可以使用openssl了. 首先需要进入openssl的交互界面 ...

  3. Java中使用OpenSSL生成的RSA公私钥进行数据加解密

    本文出处:http://blog.csdn.net/chaijunkun/article/details/7275632,转载请注明.由于本人不定期会整理相关博文,会对相应内容作出完善.因此强烈建议在 ...

  4. RSA生成公私钥并加解密

    1.RSA简介 RSA是目前使用最广泛的公钥密码体制之一,可以实现非对称加密.它是1977年由罗纳德·李维斯特(Ron Rivest).阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leona ...

  5. Java OpenSSL生成的RSA公私钥进行数据加解密详细介绍

    最近用到企业微信向银行卡转账功能,因为需要使用到:标准RSA算法 故在网上了解一下相关的信息 SA是什么:RSA公钥加密算法是1977年由Ron Rivest.Adi Shamirh和LenAdlem ...

  6. Java中不依赖于第三方库使用OpenSSL生成的RSA公私钥进行数据加解密

    本文出处:http://blog.csdn.net/chaijunkun/article/details/7275632,转载请注明.由于本人不定期会整理相关博文,会对相应内容作出完善.因此强烈建议在 ...

  7. 【转】国密算法sm4 CBC模式加解密

    一.什么是CBC模式? CBC模式的全称是Cipher Block Chaining模式(密文分组链接模式),之所以叫这个名字,是因为密文分组像链条一样相互连接在一起. 在CBC模式中,首先将明文分组 ...

  8. java rsa enc 源码_RSA加解密源码 | 学步园

    源码: #include #include #include #include #include #include #include typedef struct{ unsigned char enc ...

  9. 基于AES算法的英文文字加解密

    目录 一.理论基础 二.核心程序 三.仿真结论 一.理论基础 AES算法是一种对称加密算法,被广泛应用于数据加密和保护领域中.将介绍如何使用AES算法对英文文字进行加解密. 一.AES算法概述 AES ...

最新文章

  1. ES6中export及export default的区别
  2. 第二节认识计算机教案,第二章 第二节 局域网的构建 教学设计_博客
  3. 安装php时,configure: error: xml2-config not found. Please check your libxml2 installation
  4. Solr(搜索引擎服务)和MongoDB通过mongodb-connector进行数据同步的解决方案,以及遇到的各种坑的总结(针对solr-5.3.x版本),mongodb和solr实现实时增量索引
  5. 能够提高开发效率的Eclipse实用操作
  6. 热部署在java中的包名_09-springboot工程中的热部署实现。
  7. 5G时代到来,是机遇还是灾难?
  8. csp真题字符串匹配c语言,CCF CSP认证考试历年真题 模板生成系统 C语言实现
  9. Azure SQL 数据库:服务级别与性能问答
  10. (9) tomcat中实现同一虚拟机中所有应用程序单点登录SSO
  11. Javascript语言精粹--The Excellence in Javascript
  12. 去除水印-Teorex Inpaint 序列号
  13. 单片机STM8S测量电压电路_万用表检测电子电路:电阻测量法,电压测量法
  14. openjdk和jdk_OpenJDK和HashMap…。 安全地教老狗新技巧(堆!)
  15. 国标28181:实时视频播放
  16. 硬纪元干货|爱奇艺吴霜:看好互动视频、AI陪伴以及VR直播
  17. Navicat Data Modeler(ndm2)数据模型逆向生成表
  18. MYSQL语句优化:limit和count的优化
  19. java开发一款雷电游戏
  20. 从水果连连看到两条序列比对

热门文章

  1. openjudge基础题3计算书费
  2. Linux C语言C++ makefile文件编写
  3. C++ 继承关系图 01
  4. sql语句的经典练习
  5. 【汇编语言】程序设计过程,如何避免数据类型匹配错误?
  6. Makefile规则介绍
  7. 腾讯T2亲自讲解!搞懂开源框架设计思想真的这么重要吗?系列篇
  8. 餐厅点餐系统:测试与部署
  9. 【类】变量复用,函数复用
  10. PhotoKit 照片库的管理-获取图像