首先,是大家都懂的事情

有多种加密算法可以选择:RC4, 3DES, AES 首先需要生成key和iv

1
openssl enc -nosalt -aes-256-cbc -k password -P

会生成密钥和iv:

1
2
key=9F86D081884C7D659A2FEAA0C55AD015A3BF4F1B2B0B822CD15D6C15B0F00A08
iv =206DFC4E0335FA0AD986B9C1942DD653

用密钥来加密文件,然后传给对方:

1
openssl enc -nosalt -aes-256-cbc -in message.txt -out message.txt.enc -base64 -K 9F86D081884C7D659A2FEAA0C55AD015A3BF4F1B2B0B822CD15D6C15B0F00A08 -iv 206DFC4E0335FA0AD986B9C1942DD653

对方收到这个后,需要用相同的密钥来解密:

1
openssl enc -nosalt -aes-256-cbc -d -in message.txt.enc -base64 -K 9F86D081884C7D659A2FEAA0C55AD015A3BF4F1B2B0B822CD15D6C15B0F00A08 -iv 206DFC4E0335FA0AD986B9C1942DD653

讲一个故事:

  • 张三对李四说: 我要给你一些东西,但是不能让别人知道是什么,所以我会把东西发放在一个箱子里,然后用钥匙锁上,你收到箱子后,用钥匙打开。因为这把钥匙只有我们俩有,所以别人拿到箱子,也没用。
  • 李四:可是钥匙你怎么给我?
  • 张三:我找个邮差把钥匙寄给你呗。
  • 李四:那钥匙中途被人拿去又配了一副怎么办?
  • 张三:。。。

可以看出,这种方法的一个前提条件是,双方要共享同一个密钥。但如何把密钥安全得发送给对方呢?如果第三方也知道了密钥,就可以破解传输得信息了。

如何产生用密码保护的非对称密钥对

在继续我们的故事前,先学习知识。

1
openssl genrsa -des3 -out ca.key 4096

此时产生的文件ca.key里实际上包含了密钥和公钥,可以用如下命令来读出密钥的信息:

1
openssl rsa -inform PEM -in ./ca.key -text -noout

但因为这个文件是用密码保护的,没办法直接读出公钥的信息,可以用间接的方法,首先把公钥从文件里独立出来,然后再读取公钥的信息:

1
2
openssl rsa -in ca.key -pubout -out ca_pub.pem
openssl rsa -inform PEM -pubin -in ./ca_pub.pem -text -noout

这样你就有了一对密钥,公钥加密的信息,只能用私钥解密:

1
2
openssl rsautl -encrypt -in message -pubin -inkey ca_pub.pem  -out message_enc
openssl rsautl -decrypt -in message_enc -inkey ca.key

这种加密方式,叫做非对称加密,之前讲过的加密方法,只有一个密钥,叫做对称加密。公钥可以发送给别人,用来认证和保护你们之间的通信。只要我们能得到对方的公钥,就可以安全的发送通信给持有私钥的一方了。

如何传输密钥

继续我们的故事。

  • 张三:这样吧,你把你的公钥邮寄给我,我用你的公钥把我的钥匙锁在箱子里发给你,就算中途有人拿到了箱子,他没有密钥,就没办法打开箱子。你只要把密钥保存好就行。
  • 三天后,邮差上门,叮咚:你好,这是李四寄给你的东西。
  • 张三:谢谢。我现在就用这个公钥锁上密钥发给李四,我可真是太聪明了。等等,,,我怎么知道这把公钥一定是李四发给我的?要是不是李四发的,那我把钥匙锁在里面,被人拿到,然后我再用这把钥匙发出的东西,不就被人知道了么。这可怎么办呢。

我们来看下张三面临的问题:他收到一份文件,但不能确定这份文件是不是李四发来的,或者在途中有没有被人改过。解决这个问题,就么用到签名了。

签名

非对称加密中,是用私钥来生成签名,公钥来验证签名。 签名的作用是证明有二:

  1. 证明被签名的文件确实是由持有密钥的人签名的
  2. 证明被签名的文件内容是没有被篡改过的

把要签名的文件内容先做Hash,然后再用密钥加密,得到的就是签名文件。

1
2
3
openssl dgst -sha256 -sign ca.key -out hello.sha256 hello
openssl base64 -in hello.sha256 -out hello.sign
rm hello.sha256

收到文件和签名的人,用公钥解密签名,如果能够成功,就证明这个签名确实是用对应的密钥加密的。之后再对文件做Hash,和解密的结果两相对照,如果内容一致,就证明文件的内容是没有被改过的了。

1
2
3
openssl base64 -d -in hello.sign -out hello.sha256
openssl dgst -sha256 -verify ca_pub.pem -signature hello.sha256 hello
rm hello.sha256

所以,非对称加密相对于对称加密的最大区别,就是能够验证某些信息,确实是持有私钥的人生成的,没有被篡改过。如果你能信任这个人,你就能信任这些信息。

是时候呼唤我们的朋友出场了。

回到之前的例子:张三和李四有一个共同的朋友小明,这个朋友有一个技能,会做蜡封,他做的蜡封,别人无法仿造,而且张三和李四都认识小明做的蜡封。 于是,李四为了把公钥交给张三,一天,他去找小明。

  • 李四:我把我的公钥放在了一个信封里,想请你给给做一个蜡封。为了保证信封不被调包,请你来我家做这个蜡封。
  • 于是小明就来到李四的家在信封上做了一个蜡封。
  • 之后,李四叫来了邮差,请他把信封送给张三.
  • 当张三受到这个信封,首先,他看到信封上有小明的蜡封,这个蜡封没有别人会做,所以张三知道,信封里的信息,是小明确认过的。那么会不会在传递过程中,有人把内容调包了呢?也不会,因为如果有人打开信封,就会破坏掉蜡封,因此只要检查蜡封是完整的,就能排除掉这种可能。
  • 现在,张三打开信封,里面有一份信和一份公钥,信上写着,这是李四的公钥。这样,张三就可以放心的用这个公钥来把密钥传给李四了。

在实际场景中,这个共同的朋友小明就是CA,放着公钥的信封,就是证书,而蜡封就是签名。

把这些结合起来

  • 首先小明创建自己的非对称密钥对:

    1
    2
    
    openssl genrsa -des3 -out ca.key 2048
    openssl rsa -in ca.key -pubout -out ca_pub.pem
    

    然后把自己的公钥用自己的私钥加上签名变成证书,这个证书,我们叫它根证书,之后有用。

    1
    
    openssl req -new -x509 -days 1826 -key ca.key -out ca.crt
    

    可以用如下命令来读取证书的内容:

    1
    
    openssl x509 -in ca.crt -text
    
  • 李四现在产生自己的密钥对:

    1
    
    openssl genrsa -des3 -out server.key 2048
    

    下面两条命令,是让小明用自己的私钥来为李四的公钥加上签名,变成一个证书:

    1
    2
    
    openssl req -new -out server.csr -key server.key
    openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 360
    

    现在,李四手里有了一个私钥,这个东西他要好好保存,还有一个证书,里面包含了他的公钥以及小明的签名。李四叫来邮差,请他把证书送给张三。

  • 张三的家: 从邮差的手里接过李四的证书,张三给小明打电话。

    • 张三:我现在收到李四的证书,我怎么证明确实是李四发给我的?
    • 小明:我这里有一份根证书,里面含有我自己的公钥,你用它就能够验证所有由我签发的证书。

    于是小明亲自跑了一趟,把这份公钥交给了张三。现在张三可以用小明的根证书来验证李四的证书了:

    1
    
    openssl verify -CAfile ca.crt  server.crt
    
  • 生成并分发通信用的密钥: 张三可以放心的用李四发来的证书加密通信密钥了:

    1
    2
    3
    
    openssl enc -nosalt -aes-256-cbc -k password -P > aes.key
    openssl x509 -in server.crt -pubkey  -noout > server_pub.pem
    openssl rsautl -encrypt -in aes.key -pubin -inkey server_pub.pem  -out aes.key.enc
    

    将加密后的通信密钥发给李四,李四收到后用自己保存的密钥来解密:

    1
    
    openssl rsautl -decrypt -in aes.key.enc -inkey server.key
    

    通过以上这些步骤,张三和李四终于可以放心的发送任何他们想传递的信息了。

    1
    
    openssl enc -nosalt -aes-256-cbc -in message.txt -out message.txt.enc -base64 -K 9F86D081884C7D659A2FEAA0C55AD015A3BF4F1B2B0B822CD15D6C15B0F00A08 -iv 206DFC4E0335FA0AD986B9C1942DD653
    

    对方收到这个后,需要用相同的密钥来解密:

    1
    
    openssl enc -nosalt -aes-256-cbc -d -in message.txt.enc -base64 -K 9F86D081884C7D659A2FEAA0C55AD015A3BF4F1B2B0B822CD15D6C15B0F00A08 -iv 206DFC4E0335FA0AD986B9C1942DD653
    

原来你想说的是这个啊。

打开浏览器,连接某一个网站,请输入你的银行卡密码。

  • 浏览器:天哪,这种东西,万一被人知道了怎么办。
  • 网站:没关系,你生成一个临时的密钥,发给我,我们之后的通信都是加密的,不会有别人知道的。
  • 浏览器:你说的不就是TLS么,咱懂啊,开始吧。
  • 浏览器:你好,我能支持TLS.
  • 网站:那好,我把我的证书发给你。
  • 浏览器:看一下这个证书,恩,是DigiCert签的,我有DigiCert的根证书,拿来检查下,没错,证书是对的。好,我现在生成临时的通信密钥,然后用网站的证书里公钥加密,发给网站。
  • 网站:收到浏览器加密的通信密钥了,用我的私钥解密,恩成功,好,现在可以开始愉快的聊天了。

好了,你现在懂TLS了。

如何自己签根证书

  1. 创建CA根私钥文件,用这个文件可以生成对应的根公钥文件和根证书文件,但一般公钥文件不会单独存在,因为从私钥里随时可以产生公钥,所以要么使只有私钥文件,要么

是把公钥放在证书里。

1
openssl genrsa -des3 -out ca/private/cakey.pem 4096 -config ./openssl.cnf
  1. 生成CA根证书:
1
openssl req -x509 -new -key ca/private/cakey.pem -out ca/cacert.crt -days 36500 -config ./openssl.cnf
  1. 创建二级CA私钥:
1
openssl genrsa -des3 -out TCHtestkey.pem 2048 -config ./openssl.cnf
  1. 创建二级CA证书请求文件
1
openssl  req -new -key TCHtestkey.pem -out TCHtest.csr -config ./openssl.cnf
  1. 用CA根证书和CA根私钥来签二级CA证书请求文件,生成二级CA证书
1
openssl x509 -req -in TCHtest.csr -CA ca/cacert.crt -CAkey ca/private/cakey.pem -CAcreateserial -out TCHtest.crt -days 3650
  1. 把这个二级证书变为hash的名字,分发给client

    1
    
    cp TCHtest.crt $(openssl x509 -hash -noout -in TCHtest.crt).0
    
  2. 当我有一个个人网站,为网站生成一个密钥,并用二级证书来为这个密钥签一个证书

1
2
3
openssl genrsa -des3 -out test-bj.technicolor.com.pem 2048 -config ./openssl.cnf
openssl  req -new -key test-bj.technicolor.com.pem -out test-bj.technicolor.csr -config ./openssl.cnf
openssl x509 -req -in test.bj.tch.csr -CA TCHtest.crt -CAkey TCHtestkey.pem -CAcreateserial -out test.bj.tch.crt -days 3650

可以用如下命令去掉密钥的密码保护:

1
openssl rsa -in test.bj.tch.pem -out test.bj.tch.pem
  1. client访问我的网站,网站会把server.crt发送给client,client收到后,用自己以及收到的二级CA证书来校验,校验通过,client就可以信任这个网站了。

  2. client生成一个对称密钥key,然后用收到的证书server.crt来加密,生成key.enc,然后把key.enc发送回server。serve收到后,用自己的密钥server.key来解密,

如果能成功,server就得到了key,然后server和client就可以利用key来通信了。