再谈RSA-客户端与服务器互通

曾经写过一篇 RSA 加密的文章,没想到今天使用 RSA 加密的时候还是会面临这么多问题,这里就再整理一下。

现在的项目是在接口部分使用 RSA 加密了一个时间戳用作验证字段,防止接口攻击。由于服务器是 JAVA 的,最开始由服务器生成的私钥和公钥,公钥给的 der 文件,但是在 iOS 上面测试发现使用系统 API 无法设置公钥,后来在一个三方库的代码里发现在验证 der 文件的时候有如下一段代码

if (c_key[idx++] != 0x30) return(nil);

因此就很好奇这个0x30开头是个什么东西,结果就引出了以下问题。。。

DER 编码规则

RSA私钥DER编码规则

这个文章说明了 DER 文件的相关编码规则,从中得知,DER 文件的二进制开头必然是0x30,但是看了下服务器那边给的 DER 文件,好像不对。跟服务器沟通后,决定由我们生成公私钥,再把私钥发给服务器。

生成公私钥和DER证书

最开始只是从网上找了一段代码生成公私钥

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

这个命令可以在 osx 系统上直接生成 PEM 的私钥和 DER 的公钥,后来发现这个代码生成的私钥是经过 DES 加密后的私钥。所以只能一步一步来了。

其实上面那个命令包含了多个步骤。下面是一步一步拆解:

1)创建私钥

openssl genrsa -out rsa_private_key.pem 1024

这里私钥可以指定位数,通常使用1024位的

2)生成公钥

openssl rsa -in rsa_private_key.pem -out rsa_public_key.pem -pubout

RSA加密浅析我们可以知道公私钥是一一对应的,所以生成公钥需要指定一个私钥。

3)创建证书请求

openssl req -new -out cert.csr -key rsa_private_key.pem

这里是生成了一个 csr 文件,这个 csr 文件其实跟我们在 osx 系统的钥匙串的证书助理里面从证书颁发机构请求证书后生成的certSigningRequest文件是一样的,csr 其实就是certSigningRequest的缩写。

4)自签署生成公钥证书

openssl x509 -req -in cert.csr -out rsa_public_key.der -outform der -signkey rsa_private_key.pem -days 3650

经过上一步之后我们就可以拿着 csr 文件去生成一个 DER 证书文件了

这个命令需要指定公钥证书标准为x509,因为 iOS 的 API 只支持这种标准的证书。
同时还要指定证书的有效期,由于我是用于客户端和服务器通信的,所以有效期设置了一个很大的值,3650天(10年)。

5)公钥转成 PKCS#8 格式

openssl pkcs8 -topk8 -in rsa_private_key.pem -out pkcs8_rsa_private_key.pem -nocrypt

如果你的服务器端是 PHP 的话,那么这一步就不是必须的了,第一步生成的私钥直接丢给你的服务器开发人员就可以使用了。

但是如果你的服务器是 java 或者 .NET 的,那么他们对公钥的格式还有进一步的要求,必须是 PKCS#8 格式的公钥,所以你需要同过这个命令把私钥转成 PKCS#8格式的。

公私钥的使用

通过前面步骤我们会得到以下几个文件

  • rsa_private_key.pem: 私钥文件
  • pkcs8_rsa_private_key.pem: PKCS#8格式的私钥文件
  • rsa_public_key.pem: 公钥文件
  • cert.csr: 公钥的证书请求
  • rsa_public_key.der: 公钥的证书文件

在客户端与服务器的通信中 RSA通常有两个用途

  1. 用于数据加密(验证)
  2. 用于 https 协议的自签署证书

下面说一下服务器与客户端的配置问题:

1)服务器

如果你的服务器端是 PHP 的,那么直接使用rsa_private_key.pem私钥文件就可以了
如果你的服务器是 JAVA 或者.NET 的,那么你需要pkcs8_rsa_private_key.pem私钥文件

2)Android

Android 客户端直接使用rsa_public_key.pem就可以了

3)iOS

如果使用 RSA 只使用来做数据的验证或者加解密,那么 iOS 既可以使用rsa_public_key.pem公钥文件又可以使用rsa_public_key.der公钥证书。
如果你的网络通信是使用 https 协议自签署证书的话,那你就需要使用rsa_public_key.der公钥证书来进行网络连接了。

扩展阅读

使用openssl命令剖析RSA私钥文件格式
RSA私钥DER编码规则
x509和pkcs12以及pkcs7的关系
openssl数字证书常见格式与协议介绍
iOS下的RSA加密方法
RSA加密