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

独奏

学习思考|2015-5-16|最后更新: 2023-2-23|
type
Post
status
Published
date
May 16, 2015
slug
summary
tags
HTTP
category
学习思考
icon
password
曾经写过一篇 RSA 加密的文章,没想到今天使用 RSA 加密的时候还是会面临这么多问题,这里就再整理一下。
现在的项目是在接口部分使用 RSA 加密了一个时间戳用作验证字段,防止接口攻击。由于服务器是 JAVA 的,最开始由服务器生成的私钥和公钥,公钥给的 der 文件,但是在 iOS 上面测试发现使用系统 API 无法设置公钥,后来在一个三方库的代码里发现在验证 der 文件的时候有如下一段代码
if (c_key[idx++] != 0x30) return(nil);
因此就很好奇这个0x30开头是个什么东西,结果就引出了以下问题。。。

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. 用于数据加密(验证)
  1. 用于 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公钥证书来进行网络连接了。

扩展阅读