首页 > 其他 > 详细

基于RSA的公钥体系下安全通信实战

时间:2015-09-28 19:27:11      阅读:505      评论:0      收藏:0      [点我收藏+]

目录

  1. 简说RSA

  2. 服务器的初始密钥对和认证请求

  3. 证书认证机构CA

  4. 服务器安装CA签名证书

  5. 客户机


网络是一个开放的世界,服务器可以被不法节点冒名顶替,传输的数据可以被整个通路上的任何一个节点监听。要保证客户机和服务器在网络中通信的安全,客户机首先要检查数字签名以验明服务器正身,然后还要加密要传输的数据,该数据到达服务器后再进行解密。

通信密码学里,非对称密码技术RSA已经在计算机网络中得到广泛的应用,密钥是成对出现的,一个是私钥一个公钥。它们既可以用以数字签名,又可以用作加密解密。

TOP

1. 简说RSA

RSA是MIT的Rivest、Shamir和Adleman在1977年提出,他们以此申请了专利并成立了数家公司,最有名的当数RSA SecurityVeriSign,它们分别被EMC和Symantec以21亿和12.8亿美元收购。1983年RSA算法申请了专利,直到2000年9月专利失效。由于RSA的广泛应用,他们被授予2002年度的图灵奖

1.1. 同余

称a、b对N同余,记为a ≡ b (mod N),当且仅当a、b除以N之后的余数相等。

加法性质:若a1 ≡ b1 (mod N),a2 ≡ b2 (mod N),则(a1 + a2) ≡ (b1 + b2) (mod N)。

乘法性质:若a1 ≡ b1 (mod N),a2 ≡ b2 (mod N),则a1 * a2 ≡ b1 * b2 (mod N)。

模数性质:若a ≡ b (mod N1),a ≡ b (mod N2),则a ≡ b (mod lcm[N1, N2]),其中 lcm[N1, N2]为N1, N2的最小公倍数。

1.2. 欧拉函数 

在小于等于N的正整数之中,与N构成互质关系(coprime)的整数的个数称为欧拉函数φ(N)。

质数的欧拉函数:显然,如果N是质数,则 φ(N)=N-1 。因为质数N与小于它的每一个数都构成互质关系。

质数乘积的欧拉函数:若p1和p2是质数,则 φ(p1*p2) = φ(p1)*φ(p2) = (p1-1)*(p2-1) 。

1.3. 欧拉定理

如果两个正整数a和N互质,则N的欧拉函数 φ(N) 可以让下面的等式成立:

a φ(N) ≡ 1 (mod N)

1.4. 费马小定理

在N为质数的时候,任何小于N的整数a,都和N互质。因此

若N为质数,则:a N-1 ≡ 1 (mod N)

1.5. RSA原理

首先随机选取2个大质数p1和p2,p1≠p2,令N=p1*p2,由此可得φ(N)=(p1-1)*(p2-1)

随机取一个小于φ(N),且与φ(N)互质的整数e

计算e对φ(N)同余的逆元d,它满足ed ≡ 1 (mod φ(N))

把(N,d)妥善保管作为私钥,(N,e)公开作为公钥。对于任何信息m,我们有

m ≡ me * d (mod N)

证明如下:

  1. 因为ed ≡ 1 (mod (p1-1)*(p2-1)),所以存在整数k使ed = k*(p1-1)*(p2-1) + 1

  2. 因此me * d  ≡ m * mk*(p1-1)*(p2-1)  (mod N)

  3. 因p1和p2为质数,由费马小定理,mk*(p1-1)*(p2-1) ≡ 1 (mod p1),mk*(p1-1)*(p2-1) ≡ 1 (mod p2)

  4. 所以mk*(p1-1)*(p2-1) ≡ 1 (mod lcm[p1,p2]),即mk*(p1-1)*(p2-1) ≡ 1 (mod N)

  5. 根据同余乘法性质,me * d  ≡ m (mod N)

证明毕。

1.6. RSA加密

发送方加密:以接受方公钥(N,e)对信息m计算 me (mod N)

接受方解密:以接受方私钥(N,d)还原信息m,计算 (me (mod N))d = me * d (mod N) = m

1.7. RSA签名

发送方签名:以发送方私钥(N,d)对信息m的散列函数h(m),计算 h(m)d (mod N) = h

接受方验证:用发送方公钥(N,e)计算 (hd (mod N))e = he * d (mod N) = h,比较其是否与h(m)值一致


基于RSA的网络通信过程在X.509规范的公钥体系(PKI - public key infrastructure)下得到完成,数据的加密解密由安全套接字层(SSL - secure socket layer)或传输层安全(TLS - transport layer security)实现。当客户机需要与某个服务器建立通信连接时,双方发生SSL握手过程:

  1. 客户机通过网络发送请求安全会话的消息(通常请求是HTTPS协议的形式)。服务器通过发送其X.509证书(包含公钥)进行响应。

  2. 客户机验证服务器证书的有效性,并检验该证书是否由可信任的证书认证机构(CA - certification authority)所签发。

  3. 当证书有效,客户机生成一次性的密钥,并用服务器的公钥对该密钥进行加密。然后,客户机把加密的会话密钥发送给服务器。

  4. 服务器用其私钥对其次进行解密,然后得到本次通讯的会话密钥。

  5. 客户机和服务器用其约定的会话密钥开始数据通信,直到一次会话结束。


由于编写密钥代码的复杂性,很多网站使用开源免费软件。OpenSSL就是这样的一套原码公开的C语言函数库,它最初由Eric和Tim在入职RSA公司前开发,其丰富的在线使用手册可以通过下列命令得到:

$ openssl -help


客户机、服务器和证书认证机构是涉足安全通信的三方。围绕证书这个技术关键,下面逐一细说三方通信过程中的协作。

TOP

2. 服务器的初始密钥对和认证请求

基于Java技术的Web服务器通常以服务导向架构为蓝本,通过HTTPS协议将应用程序功能作为服务发送给客户机。通信传输协议的SSL握手过程中,服务器首先将其X.509证书发送给客户机,然后由客户机依据其存储的根CA证书验证该证书的真实性。Java内部维护一个密钥库(keystore),用以存储私钥及其对应的附有证书链的证书。Java为密钥库设置了一个密码,密钥库中的每一个私钥及其证书又有一个密码来控制存取,keytool是管理密钥库的工具软件。

$ keytool -help

2.1 创建初始密钥库

若服务器FQDN是www.mysite.com,它在DNS中又有别名foo.mysite.com,创建JKS格式的初始密钥库可以用如下命令完成。

$ keytool -genkeypair -keystore mystore.jks -storepass mypass -alias www   -keypass mypass -keyalg rsa -dname "CN=www.mysite.com" -ext "SAN=dns:foo.mysite.com"
$ keytool -list -v -keystore mystore.jks -storepass mypass

可以看到,生成的密钥库mystore.jks里有一个私钥记录PrivateKeyEntry,记录中含有一个证书链(certificate chain),当然目前证书链里只包含一个证书Certificate[1]。我们来仔细研究一下私钥和证书的构成。

2.1.1 私钥

很难相信的一个事实是,keytool没有从密钥库中提取私钥的功能。因此要想得到私钥,只能把密钥库先转换成PKCS#12格式。

$ keytool -importkeystore -srckeystore mystore.jks -srcstorepass mypass -srcalias www   -srckeypass mypass -destkeystore mystore.p12 -deststorepass mypass   -destkeypass mypass -deststoretype pkcs12
$ keytool -list -v -keystore mystore.p12 -storepass mypass -storetype pkcs12 -alias www   -keypass mypass

从密钥库mystore.p12中可以用OpenSSL工具提取出私钥:

$ openssl pkcs12 -nocerts -in mystore.p12 -passin pass:mypass -passout pass:mypass   | awk "/--BEGIN/,/--END/" > xxx_private.key

得到的私钥受密码保护而存储在xxx_private.key文件中。可以进一步删除存储保护密码,从而得到一个PKCS#1格式的RSA私钥rsa_private.key

$ openssl rsa -in xxx_private.key -passin pass:mypass > rsa_private.key

显示私钥rsa_private.key的内容

$ openssl rsa -text -noout -in rsa_private.key
$ openssl asn1parse -in rsa_private.key

再进一步可以用OpenSSL工具,在RSA私钥的基础上加上版本号、算法标识等附加信息形成PKCS#8格式私钥,它是更一般格式的私钥形式,目的是为了包含RSA和其它一切格式的私钥。

$ openssl pkcs8 -topk8 -nocrypt -in rsa_private.key > private.key

显示私钥private.key的内容

$ openssl asn1parse -in private.key

用以下命令可以把PKCS#8格式的private.key中的RSA私钥提取出来。

$ openssl pkcs8 -nocrypt -in private.key
$ openssl rsa -text -in private.key | awk "/--BEGIN/,/--END/"
2.1.2 证书

从JKS格式的密钥库中提取自签名证书相对容易。

$ keytool -exportcert -rfc -alias www -keystore mystore.jks   -storepass mypass > public.crt

也可以从PKCS#12格式的密钥库中提取。

$ openssl pkcs12 -in mystore.p12 -nokeys -passin pass:mypass   | awk "/--BEGIN/,/--END/" > public.crt

分析证书public.crt的结构和具体内容

$ openssl x509 -text -in public.crt

可以看到证书包含Subject、Issuer、公钥和签名等信息。我们可以把其中的公钥单独提取出来

$ openssl x509 -pubkey -noout -in public.crt > public.key

我们还能从PKCS#8格式的private.key直接计算出其对应的公钥,以此可以与密钥库中提取出来的公钥进行比较。

$ openssl rsa -pubout -in private.key

显示公钥的内容

$ openssl rsa -text -noout -pubin -in public.key
2.1.3 私钥、公钥及证书的配对

鉴别私钥和证书是否成对,可以检查它们各自的模数。密钥对的私钥及其对应的公钥和证书,模数应该相同。

$ openssl rsa -modulus -noout -in private.key
$ openssl rsa -modulus -noout -pubin -in public.key
$ openssl x509 -modulus -noout -in public.crt

2.2 证书签名请求

初始建立的密钥库,包含一个私钥和一个自签名的证书。下一步需要生成证书签名请求(CSR - certificate signing request),然后把证书签名请求提交认证机构CA,等待该机构依据X.509国际标准对服务器进行验证,合格者签发证书。

$ keytool -certreq -keystore mystore.jks -storepass mypass -alias www -keypass mypass   -ext "SAN=dns:foo.mysite.com" -file www.csr

从证书签名请求www.csr可以提取出其间包含的公钥。还可以计算它的模数,与私钥公钥的模数进行比较。

$ openssl req -pubkey -noout -in www.csr
$ openssl req -modulus -noout -in www.csr

显示证书签名请求的内容

$ openssl req -text -noout -in www.csr

TOP

3. 证书认证机构CA

目前全球最著名的证书认证机构有:

3.1 根证书

通常证书认证机构有一个或若干根证书。作为演示,我们在这里生成这组根证书及其对应的私钥,根证书是以自签名的形式签发的。

$ mkdir root
$ openssl req -newkey rsa:4096 -keyout root/xxx_private.key   -out root/public.csr
$ openssl pkcs8 -topk8 -nocrypt -in root/xxx_private.key > root/private.key
$ openssl x509 -req -signkey root/private.key -in root/public.csr   -out root/public.crt

3.2 中级认证

机构还有一组中级认证:

$ mkdir intermediate
$ openssl req -newkey rsa:2048 -keyout intermediate/xxx_private.key   -out intermediate/public.csr
$ openssl pkcs8 -topk8 -nocrypt -in intermediate/xxx_private.key   > intermediate/private.key

中级认证证书是由根证书签发的。

touch root/database.txt
echo 01 > root/serial.txt
cat > root/openssl.cnf <<EOF
[ ca ]
default_ca = CA_default
[ CA_default ]
new_certs_dir = intermediate
serial = root/serial.txt
database = root/database.txt
certificate = root/public.crt
private_key = root/private.key
default_days = 3652
default_crl_days = 30
default_md = md5
policy = policy_any
[ policy_any ]
countryName = supplied
stateOrProvinceName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
EOF
$ openssl ca -config root/openssl.cnf -in intermediate/public.csr   -out intermediate/public.crt

有了中级证书,证书认证机构就具备了依据服务器的www.csr请求发送具有认证机构签名的服务证书的能力。

touch intermediate/database.txt
echo 01 > intermediate/serial.txt
cat > intermediate/openssl.cnf <<EOF
[ ca ]
default_ca = CA_default
[ CA_default ]
new_certs_dir = .
serial = intermediate/serial.txt
database = intermediate/database.txt
certificate = intermediate/public.crt
private_key = intermediate/private.key
default_days = 365
default_crl_days = 30
default_md = md5
policy = policy_any
[ policy_any ]
countryName = supplied
stateOrProvinceName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
EOF
$ openssl ca -config intermediate/openssl.cnf -in www.csr   -out www.crt

3.3 认证机构发送具有数字签名的数据

证书认证机构应答服务器的是具有数字签名的数据,其原理是这样的。认证机构把要发送的数据用私钥进行签名,然后把数据连同签名一并发送给服务器。

$ echo testing > 1.txt
$ openssl dgst -sha256 -sign root/private.key 1.txt > 2.xxx

服务器可以获取的根证书,以此得到认证机构的公钥。

$ openssl x509 -pubkey -noout -in root/public.crt > ca0.key

接受到认证机构的数据及其签名信息后,依据认证机构的公钥对其进行签名验证

$ openssl dgst -sha256 -verify ca0.key -signature 2.xxx 1.txt

我们观察www.crt的结构和内容不难发现,生成的证书包含一个公钥和一个签名。因此服务器收到这样的证书,就可以完成签名验证。

$ openssl x509 -text -noout -in www.crt

3.4 PKCS#7证书链

证书认证机构向证书申请部门颁发PKCS#7格式的证书链:

$ cat www.crt intermediate/public.crt | awk "/--BEGIN/,/--END/"   > chain.crt
$ openssl crl2pkcs7 -nocrl -certfile chain.crt -out chain.p7b
$ openssl pkcs7 -print_certs -in chain.p7b

TOP

4. 服务器安装CA签名证书

Java存储国际认可的认证机构的根CA证书在其Truststore中$JAVA_HOME/jre/lib/security/cacerts,默认密码通常为changeit。本文为了模拟,把自己生成的CA根证书加入其中。

$ keytool -importcert -trustcacerts -file root/public.crt   -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit   -alias myCA

服务器得到chain.p7b后,先把证书链分割成若干个单独的证书文件:

$ openssl pkcs7 -print_certs -in chain.p7b | awk   ‘BEGIN{i=0} /--BEGIN/{i=-i+1} {if(i>0) print>"ca" i ".crt"} /--END/{i=-i}‘

得到的签名证书,一般ca1.crt是和私钥配对的证书,而ca2.crt是CA中级证书。计算MD5值,以确定ca1.crt和自己的CSR请求一致。

$ openssl x509 -modulus -noout -in ca1.crt | openssl md5

确认正确即可以将它们安装到密钥库中,首先安装CA中级证书ca2.crt

$ keytool -importcert -trustcacerts -file ca2.crt -keystore mystore.jks   -storepass mypass -alias ca

然后再安装ca1.crt,以取代密钥库中原来的自签名证书。

$ keytool -importcert -trustcacerts -file ca1.crt -keystore mystore.jks   -storepass mypass -alias www -keypass mypass

如果需要,可以把修改后的密钥库重新转化成PKCS#12格式:

$ rm mystore.p12
$ keytool -importkeystore -srckeystore mystore.jks -srcstorepass mypass -srcalias www   -srckeypass mypass -destkeystore mystore.p12 -deststorepass mypass   -destkeypass mypass -deststoretype pkcs12

最后,再验证一下密钥库就可以看到一个具有三个证书构成的证书链。证书链最后一个是已经存储在Truststore的CA根证书,以此表明整个证书链是可信任的。

$ keytool -list -v -keystore mystore.jks -storepass mypass -alias www -keypass mypass
$ keytool -list -v -keystore mystore.p12 -storepass mypass -storetype pkcs12 -alias www   -keypass mypass

【JBoss】把下列配置加入$CATALINA_HOME/conf/server.xml

<-- Define a SSL Coyote HTTP/1.1 Connector on port 8443 -->
<Connector 
 port="8443" minSpareThreads="5" maxSpareThreads="75"
 enableLookups="true" disableUploadTimeout="true" 
 acceptCount="100"  maxThreads="200"
 scheme="https" secure="true" SSLEnabled="true"
 keystoreFile="${user.home}/keystore.jks" keystorePass="mypass"
 clientAuth="false" sslProtocol="TLS"/>

【Tomcat】把下列配置加入$CATALINA_BASE/conf/server.xml

<-- Define a SSL Coyote HTTP/1.1 Connector on port 8443 -->
<Connector
 protocol="org.apache.coyote.http11.Http11Protocol"
 port="8443" maxThreads="200"
 scheme="https" secure="true" SSLEnabled="true"
 keystoreFile="${user.home}/keystore.jks" keystorePass="mypass"
 clientAuth="false" sslProtocol="TLS"/>

TOP

5. 客户机

通常服务器提供给客户机的证书都附有证书链,它是由一系列CA证书发出的证书序列,最终以根CA证书结束。客户机预 先存储了一组可信任的根CA证书,服务器证书链的终结根CA证书若在其列,客户机即可确认该服务器可信任。在Windows查阅PC中存储的根CA证书, 可以在命令行中键入

C:\> certmgr.msc

客户机查询服务器的证书、测试能否用/etc/ssl/certs目录下存储的根CA证书与服务器成功完成SSL握手,可以执行如下OpenSSL的命令

$ openssl s_client -showcerts -connect www.mysite.com:443
$ openssl s_client -CApath /etc/ssl/certs -connect www.mysite.com:443

客户机一旦取得了服务器的证书链ca1.crt和ca2.crt,可以用其存储的根CA证书ca.crt验证该的真实性。

$ openssl verify -CAfile ca.crt ca1.crt
$ openssl verify -CAfile ca1.crt ca2.crt

客户机向服务器发送加密数据

客户机把要发送的数据有私钥进行签名

$ echo testing > 1.txt
$ openssl rsautl -encrypt -inkey ca1.crt -certin -in 1.txt -out 2.xxx

服务器对接受到数据进行解密

$ openssl rsautl -decrypt -inkey private.key -in 2.xxx -out 3.txt





未完待续...






本文出自 “倒背如流 Linux - Unix” 博客,请务必保留此出处http://xnuil.blog.51cto.com/10714423/1698673

基于RSA的公钥体系下安全通信实战

原文:http://xnuil.blog.51cto.com/10714423/1698673

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!