利用BBRSACryptor实现iOS端的RSA加解密

背景

RSA这种非对称加密被广泛的运用于网络数据的传输,但其在iOS上很难直接实现,BBRSACryptor框架通过移植openssl实现了iOS端的RSA,本文将介绍如何使用BBRSACryptor生成证书,加载公钥,以及后端如何用php读取证书,加载私钥。

iOS加密

新建工程并集成BBRSACryptor

这个框架自带的demo将工程文件与框架放在了同一目录,因此在配置Header Search Paths时没有包含工程文件夹,一定注意,下面新建的工程将框架放在了工程文件夹内,因此头文件寻找路径需要包含上工程目录。详细步骤如下。 
1. 新建一个iOS工程,将BBRSACryptor、GTMBase64、OpenSSL三个文件夹拖入工程,目录结构如下。 

2.在Build Settings中配置Header Search Pathes。 
 
注意最前面的文件夹名称要和自己的工程名相同

3.打开BBRSACryptor.m文件,修改存储证书的目录和文件路径,默认的是隐藏目录(前加点),为了方便查看与复制证书,建议将路径前面的点去掉,例如:

#define OpenSSLRSAKeyDir [DocumentsDir stringByAppendingPathComponent:@"openssl_rsa"]
#define OpenSSLRSAPublicKeyFile [OpenSSLRSAKeyDir stringByAppendingPathComponent:@"publicKey.pem"]
#define OpenSSLRSAPrivateKeyFile [OpenSSLRSAKeyDir stringByAppendingPathComponent:@"privateKey.pem"]
  • 1
  • 2
  • 3

4.打开ViewController.m,导入BBRSACryptor.h和GTMBase64.h,使用下面的代码生成证书。

BBRSACryptor *rsaCryptor = [[BBRSACryptor alloc] init];
[rsaCryptor generateRSAKeyPairWithKeySize:1024];
  • 1
  • 2

运行后,在控制台会打印出证书路径,进入路径后,可以看到公钥和私钥证书。 

5.使用TextEdit打开公钥证书,将—–BEGIN PUBLIC KEY—–和—–END PUBLIC KEY—–之间的部分复制,然后在工程中新建一个宏,来保存这个公钥,以便后续读取。

#define PublicKey @"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDjYyZoASYgT+MIc/5YkSJngRbNYEQEI3UF7RVijF0STcMs93pH0qhjLJIQnsvUn2ghEVM4X+S+tQ0XhS+7tmL1UMEFgDgYwG/xr/ZjUozgQyvqeUejA08pbun0E0/Yx9WuBQfCpCc5vNka/ENDZEy/2PbEO5KD3hgsnH1JyNqNnwIDAQAB"
  • 1
  • 2

客户端仅保存公钥即可,私钥放在服务器上。使用php可以直接读取证书。

6.在客户端加载公钥与进行加密 
前面已经创建了宏,以后通过宏即可加载公钥。如下:

BBRSACryptor *rsaCryptor = [[BBRSACryptor alloc] init];
// PublicKey是从公钥证书中复制的内容创建的宏,见上文。
[rsaCryptor importRSAPublicKeyBase64:PublicKey];
NSData *data = [rsaCryptor encryptWithPublicKeyUsingPadding:RSA_PADDING_TYPE_PKCS1 plainData:[@"客户端加密的内容" dataUsingEncoding:NSUTF8StringEncoding]];
NSString *baseStr = [GTMBase64 stringByEncodingData:data];
NSLog(@"%@",baseStr);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

先加载公钥,然后把要加密的内容转换成NSData,加密后的内容先进行base64编码后再传输。为了验证能够解密,最后对base64编码的加密内容进行了打印,将这个内容先复制到剪贴板,后面贴在php中进行解密。

php解密

为了方便,将按照上文方法生成的私钥证书复制到服务器的某个目录,并在这个目录下创建一个php文件,并添加如下代码:

<?php
    header("Content-type:text/html; charset=utf-8");
    /**
     * 密钥文件的路径
     */
    $privateKeyFilePath = ‘privateKey.pem‘;
    /**
     * 公钥文件的路径
     */
    $publicKeyFilePath = ‘publicKey.pem‘;

    extension_loaded(‘openssl‘) or die(‘php需要openssl扩展支持‘);

    (file_exists($privateKeyFilePath) && file_exists($publicKeyFilePath))
    or die(‘密钥或者公钥的文件路径不正确‘);
    /**
     * 生成Resource类型的密钥,如果密钥文件内容被破坏,openssl_pkey_get_private函数返回false
     */
    $privateKey = openssl_pkey_get_private(file_get_contents($privateKeyFilePath));
    /**
     * 生成Resource类型的公钥,如果公钥文件内容被破坏,openssl_pkey_get_public函数返回false
     */
    $publicKey = openssl_pkey_get_public(file_get_contents($publicKeyFilePath));

    ($privateKey && $publicKey) or die(‘密钥或者公钥不可用‘);
    // 这段内容来自上面iOS端打印的加密内容的base64编码
    $encryptData = ‘J0oTqBCNbsJauVwRz+380y519sSa7ficUO1NvRKiMGKUGJF0pomOu20fHqC77NmsKle9/L4DyYNr3xDgDa4SpO0in39rA9EYXzmx3rlyI1c8iPjAkQ6XpwZk7BsThiCFB/6QmkTW5pMIo4b0axRv/4lq1Rqx/YtuIsGkXQTNntI=‘;
    $ee = base64_decode($encryptData);
    $decryptData =‘‘;

    if (openssl_private_decrypt($ee, $decryptData, $privateKey)) {

        echo ‘解密成功,解密后数据为:‘, $decryptData, PHP_EOL;

    } else {
        die(‘解密成功‘);
    }
?>
  • 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

访问这个脚本,如果前面做的没有问题,会得到解密的结果: 

php加密

使用私钥加密后,可以在客户端利用公钥解密。使用下面的代码进行加密。

<?php
    header("Content-type:text/html; charset=utf-8");
    /**
     * 密钥文件的路径
     */
    $privateKeyFilePath = ‘privateKey.pem‘;
    /**
     * 公钥文件的路径
     */
    $publicKeyFilePath = ‘publicKey.pem‘;

    extension_loaded(‘openssl‘) or die(‘php需要openssl扩展支持‘);

    (file_exists($privateKeyFilePath) && file_exists($publicKeyFilePath))
    or die(‘密钥或者公钥的文件路径不正确‘);
    /**
     * 生成Resource类型的密钥,如果密钥文件内容被破坏,openssl_pkey_get_private函数返回false
     */
    $privateKey = openssl_pkey_get_private(file_get_contents($privateKeyFilePath));
    /**
     * 生成Resource类型的公钥,如果公钥文件内容被破坏,openssl_pkey_get_public函数返回false
     */
    $publicKey = openssl_pkey_get_public(file_get_contents($publicKeyFilePath));

    ($privateKey && $publicKey) or die(‘密钥或者公钥不可用‘);
$originalData = ‘服务器加密的内容‘;
    /**
     * 加密以后的数据,用于在网路上传输
     */
    $encryptData = ‘‘;
    echo ‘原数据为:‘, $originalData, PHP_EOL;
    ///////////////////////////////用私钥加密////////////////////////
    if (openssl_private_encrypt($originalData, $encryptData, $privateKey)) {
        echo ‘加密成功,加密后数据(base64_encode后)为:‘, base64_encode($encryptData), PHP_EOL;

    } else {
        die(‘加密失败‘);
    }
?>
  • 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

访问脚本后会打印出加密的base64编码,将这个编码复制到客户端进行解密,来验证可用性。

iOS解密

要在iOS端解密,和加密类似,先加载公钥,然后把base64编码的加密内容解码,解密后转为NSString即可。

BBRSACryptor *rsaCryptor = [[BBRSACryptor alloc] init];
[rsaCryptor importRSAPublicKeyBase64:PublicKey];
NSData *enCryptorDataBase64 = [@"aWdbPQHiQzU5CUOAIGQT3OD/MPqcqoXHXDFtYQPVRo9/Mb1S/aVcKQVHDjBpLgfzw+0mWxgHN6SuOfH8z9WobgQrTZh+pxhau3DnfukLmENGPWVMqquWMxTkEU7yCkx/RI7XEwv3jk9d4UgFOv35eqNUgYyWDq2gGatEpfnUg6U=" dataUsingEncoding:NSUTF8StringEncoding];
NSData *deCryptorData = [rsaCryptor decryptWithPublicKeyUsingPadding:RSA_PADDING_TYPE_PKCS1 cipherData:[GTMBase64 decodeData:enCryptorDataBase64]];
NSLog(@"%@",[[NSString alloc] initWithData:deCryptorData encoding:NSUTF8StringEncoding]);
  • 1
  • 2
  • 3
  • 4
  • 5

不出意外的话,控制台将会打印出解密后的内容。

原文

时间: 2024-09-28 17:12:06

利用BBRSACryptor实现iOS端的RSA加解密的相关文章

java与IOS之间的RSA加解密

很简单的一个需求,ipad端给密码RSA加密,传到java后台,解密.RSA加密算法是基于一个密钥对的,分为公钥和私钥,一般情况公钥加密,私钥解密,但也可私钥加密,公钥解密.还可以验签,就是先用私钥对数据进行加密,然后对加密后的数据进行签名,得到一个签名值.然后再用公钥先验签,证明是对应私钥加密过的数据才解密.主要是为了防止来源不确定的数据.     根据上面的介绍,大家也都知道,RSA算法的关键就是密钥对,我和IOS的同事各自找了RSA的算法实现代码,都能正常根据密钥对加解密.问题是我们各自使

OpenSSL RSA加解密 (.Net公钥加密/ Linux端私钥解密)

要求在.Net端生成公钥私钥对. 然后在.Net端使用RSA公钥加密:在Linux端使用RSA私钥解密. 最初的尝试是:.Net端使用RSACryptoServiceProvider; linux端使用OpenSSL 搞了整整5个小时,有木有啊,有木有啊! .Net的RSA和OpenSSL对不上,有木有啊,有木有啊! 人都搞晕了就是对不上.最后解决方式换成了,.Net端使用 OpenSSL.NET. .Net端代码 string publicKeyFile = context.Server.Ma

全面解决.Net与Java互通时的RSA加解密问题,使用PEM格式的密钥文件

一.缘由 RSA是一种常用的非对称加密算法.所以有时需要在不用编程语言中分别使用RSA的加密.解密.例如用Java做后台服务端,用C#开发桌面的客户端软件时.由于 .Net.Java 的RSA类库存在很多细节区别,尤其是它们支持的密钥格式不同.导致容易出现“我加密的数据对方不能解密,对方加密的数据我不能解密,但是自身是可以正常加密解密”等情况.虽然网上已经有很多文章讨论 .Net与Java互通的RSA加解密,但是存在不够全面.需要第三方dll.方案复杂 等问题.于是我仔细研究了这一课题,得到了一

java rsa加解密算法的实现

RSAUtils:RSA加解密的实现 package com.rsa.test; import java.io.ByteArrayOutputStream; import java.nio.charset.Charset; import java.security.Key; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import jav

【转】 Java 进行 RSA 加解密时不得不考虑到的那些事儿

[转] Java 进行 RSA 加解密时不得不考虑到的那些事儿 1. 加密的系统不要具备解密的功能,否则 RSA 可能不太合适 公钥加密,私钥解密.加密的系统和解密的系统分开部署,加密的系统不应该同时具备解密的功能,这样即使黑客攻破了加密系统,他拿到的也只是一堆无法破解的密文数据.否则的话,你就要考虑你的场景是否有必要用 RSA 了. 2. 可以通过修改生成密钥的长度来调整密文长度 生成密文的长度等于密钥长度.密钥长度越大,生成密文的长度也就越大,加密的速度也就越慢,而密文也就越难被破解掉.著名

PHP RSA加解密示例(转)

1.生成密钥和公钥 开始前需要准备openssl环境 linux 需要安装openssl工具包,传送门http://www.openssl.org/source/ window 下需要安装openssl的程序,传送门http://slproweb.com/products/Win32OpenSSL.html 如果不想安装,可以用本例提供的密钥和公钥进行测试. 密钥生成 openssl genrsa 用于生成rsa私钥文件,生成是可以指定私钥长度和密码保护,具体参数请参考文档. openssl g

java RSA加解密以及用途

在公司当前版本的中间件通信框架中,为了防止非授权第三方和到期客户端的连接,我们通过AES和RSA两种方式的加解密策略进行认证.对于非对称RSA加解密,因为其性能耗费较大,一般仅用于认证连接,不会用于每次报文本身的加解密(这一般使用AES/DES加密),对于较为安全的支付通道,则一般是约定定期交换加解密密钥,交换过程本身的报文则是通过RSA进行加解密的.这样就在单纯的对称加密的基础上提供了更好的保障,只要签名复杂,定期的更新足以使得破坏的成本高昂到超过破解的成本. 一般来说,公钥会发布给客户端,客

【go语言】RSA加解密

关于go语言的RSA加解密的介绍,这里有一篇文章,已经介绍的很完整了. 对应的go语言的加解密代码,参考git. 因为原文跨语言是跟php,我这里要跟c语言进行交互,所以,这里贴上c语言的例子. 参考原文:http://hayageek.com/rsa-encryption-decryption-openssl-c/ #include <openssl/pem.h> #include <openssl/ssl.h> #include <openssl/rsa.h> #i

[转]PHP,Android,IOS通信之AES128加解密

转自:http://s00s10.blog.163.com/blog/static/43988552201411913011459/ android上使用: mcrypt = new MCrypt(); /* 加密*/ String encrypted = MCrypt.bytesToHex( mcrypt.encrypt("需加密的字符") ); /* 解密*/ String decrypted = new String( mcrypt.decrypt( encrypted ) );