简单的回答:
证书也叫CA(Certification Authority)证书;密钥就是用来加解密用的文件或者字符串;rsa即非对称加密算法。
密钥
密钥在非对称加密的领域里,指的是私钥和公钥,他们总是成对出现,其主要作用是加密和解密,具体原理可以参考RSA加密算法。
需要指出的是,WIKI中提到1999年,RSA-155 (512 bits)被成功分解,2009年12月12日,编号为RSA-768(768 bits, 232 digits)数也被成功分解,目前老高建议直接使用2048-bit或4086-bit的加密强度。
openssl
在说私钥公钥之前,大家可能需要先熟悉熟悉openssl命令行工具,openssl是一个强大的加密、解密工具,由开源组织维护。利用openssl工具,我们可以实现一些常见的摘要算法,如Linux下简单计算md5,base64,sha1,sha2
# 帮助信息
Standard(标准) commands
asn1parse ca ciphers crl crl2pkcs7
dgst dh dhparam dsa dsaparam
ec ecparam enc engine errstr
gendh gendsa genrsa nseq ocsp
passwd pkcs12 pkcs7 pkcs8 prime
rand req rsa rsautl s_client
s_server s_time sess_id smime speed
spkac verify version x509
Message Digest(信息摘要) commands (see the `dgst' command for more details)
md2 md4 md5 mdc2 rmd160
sha sha1
Cipher(加密) commands (see the `enc' command for more details)
aes-128-cbc aes-128-ecb aes-192-cbc aes-192-ecb aes-256-cbc
aes-256-ecb base64 bf bf-cbc bf-cfb
bf-ecb bf-ofb cast cast-cbc cast5-cbc
cast5-cfb cast5-ecb cast5-ofb des des-cbc
des-cfb des-ecb des-ede des-ede-cbc des-ede-cfb
des-ede-ofb des-ede3 des-ede3-cbc des-ede3-cfb des-ede3-ofb
des-ofb des3 desx rc2 rc2-40-cbc
rc2-64-cbc rc2-cbc rc2-cfb rc2-ecb rc2-ofb
rc4 rc4-40 seed seed-cbc seed-cfb
seed-ecb seed-ofb
# 加密的相关命令
options are
-in <file> input file
-out <file> output file
-pass <arg> pass phrase source
-e encrypt
-d decrypt
-a/-base64 base64 encode/decode, depending on encryption flag
-k passphrase is the next argument
-kfile passphrase is the first line of the file argument
-md the next argument is the md to use to create a key
from a passphrase. One of md2, md5, sha or sha1
-K/-iv key/iv in hex is the next argument
-[pP] print the iv/key (then exit if -P)
-bufsize <n> buffer size
-engine e use engine e, possibly a hardware device.
处理数据
信息摘要
# base64
echo -n "phpgao" | openssl base64
# 解密 -d == decrypt
echo "cGhwZ2Fv" | openssl base64 -d
# 对一个文件计算摘要,下同
openssl base64 -in nginx.conf
# md5
echo -n "phpgao" | openssl md5
# sha128
echo -n "phpgao" | openssl sha1
加密解密
# 使用rc4算法加密php字符串,使用密钥phpgao,输出使用base64编码
echo -n "php" | openssl rc4 -k phpgao -base64
# 使用rc4算法解密字符串,使用密钥phpgao,输入使用base64编码
echo U2FsdGVkX18f3qEoEhVf+hsNOg== | openssl rc4 -d -k phpgao -base64
密钥相关操作
# 生成私钥
# genrsa 指使用rsa算法生成密钥文件
# -des3 指的是给私钥加密的算法(可选)
openssl genrsa -des3 -out key_rsa 4096
openssl genrsa -out key_rsa 4096
# 移除已经存在的密码(先做一下备份)
cp key_rsa old.key
openssl rsa -in old.key -out key_rsa
# 根据刚才创建的私钥创建公钥
openssl rsa -in key_rsa -pubout -out key_rsa.pub
# 使用公钥加密数据
# -in 输入文件
echo -n "phpgao" | openssl rsautl -encrypt -pubin -inkey key_rsa.pub -out a.txt
# 使用私钥解密数据
openssl rsautl -decrypt -inkey key_rsa -in a.txt
# 查看密钥信息
openssl rsa -in key_rsa -text -noout
openssl rsa -pubin -in key_rsa.pub -text -noout
# 检查私钥
openssl rsa -check -in key_rsa
# 检查一个CSR文件(后面有讲)
openssl req -text -noout -verify -in domain.csr
# 检查证书信息
openssl x509 -text -noout -in domain.crt
一些补充
关于密钥的格式
密钥的格式有很多种,我们在使用的时候需要注意。我们刚才使用openssl生成的密钥格式叫PKCS#1,不同的程序可能需要不同格式的密钥,不同格式的密钥是可以转换的。
RSA Private Key (PKCS#1):
-----BEGIN RSA PRIVATE KEY-----
BASE64 ENCODED DATA
-----END RSA PRIVATE KEY-----
PKCS#1 RSA Public Key:
-----BEGIN RSA PUBLIC KEY-----
BASE64 ENCODED DATA
-----END RSA PUBLIC KEY-----
X.509 Public Key:
-----BEGIN PUBLIC KEY-----
BASE64 ENCODED DATA
-----END PUBLIC KEY-----
PKCS#8 Private Key:
-----BEGIN PRIVATE KEY-----
BASE64 ENCODED DATA
-----END PRIVATE KEY-----
PKCS#8 Encrypted Private Key:
-----BEGIN ENCRYPTED PRIVATE KEY-----
BASE64 ENCODED DATA
-----END ENCRYPTED PRIVATE KEY-----
SSH public key:
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC6Fo/HHPELU4TLdQwZtidB4hph8xTQberQ8467l2wkXFKV1dlBncCLUA6SUD9JypHIb3I6VNv3rnoEWtRsQYFX5TwGqnxxxH7ZjMt2O1NE9OTEf7H50QmkhHBEKruuEt+OrRXSL6gwHwuAYvGl2nWyKhdaKPg2AMHV6NV3hKEiyEhCe9XCg72KTdHTOVpDS2RjnsU4spyioi9OVj5Eu3vjBeQUifULJzbgMqB0kYS+mJSiol+ZK2YOp1HdiR7vxqfi7r+d8LDhGox8mO00nlYc4h7LBOe75G5KktSbTt5Pyiim+DF6efvmtj2zJ/nN3H2ZHG1dLVQl82QJ8Kz3Rosh laogao@local
参考Converting OpenSSH public keys,我们可以使用命令 ssh-keygen -f id_rsa.pub -e -m pem
将ssh-rsa格式转为PKCS#1 PEM格式。
更多格式(我们经常用到的没几个):
#define PEM_STRING_X509_OLD "X509 CERTIFICATE"
#define PEM_STRING_X509 "CERTIFICATE"
#define PEM_STRING_X509_PAIR "CERTIFICATE PAIR"
#define PEM_STRING_X509_TRUSTED "TRUSTED CERTIFICATE"
#define PEM_STRING_X509_REQ_OLD "NEW CERTIFICATE REQUEST"
#define PEM_STRING_X509_REQ "CERTIFICATE REQUEST"
#define PEM_STRING_X509_CRL "X509 CRL"
#define PEM_STRING_EVP_PKEY "ANY PRIVATE KEY"
#define PEM_STRING_PUBLIC "PUBLIC KEY"
#define PEM_STRING_RSA "RSA PRIVATE KEY"
#define PEM_STRING_RSA_PUBLIC "RSA PUBLIC KEY"
#define PEM_STRING_DSA "DSA PRIVATE KEY"
#define PEM_STRING_DSA_PUBLIC "DSA PUBLIC KEY"
#define PEM_STRING_PKCS7 "PKCS7"
#define PEM_STRING_PKCS7_SIGNED "PKCS #7 SIGNED DATA"
#define PEM_STRING_PKCS8 "ENCRYPTED PRIVATE KEY"
#define PEM_STRING_PKCS8INF "PRIVATE KEY"
#define PEM_STRING_DHPARAMS "DH PARAMETERS"
#define PEM_STRING_DHXPARAMS "X9.42 DH PARAMETERS"
#define PEM_STRING_SSL_SESSION "SSL SESSION PARAMETERS"
#define PEM_STRING_DSAPARAMS "DSA PARAMETERS"
#define PEM_STRING_ECDSA_PUBLIC "ECDSA PUBLIC KEY"
#define PEM_STRING_ECPARAMETERS "EC PARAMETERS"
#define PEM_STRING_ECPRIVATEKEY "EC PRIVATE KEY"
#define PEM_STRING_PARAMETERS "PARAMETERS"
#define PEM_STRING_CMS "CMS"
列表来自what is the differences between “BEGIN RSA PRIVATE KEY” and “BEGIN PRIVATE KEY”
CA证书
证书与密钥不同,CA证书指的是权威机构给我们颁发的证书,我们的电脑或者电子设备中内置了根证书,我们的电脑信任根证书。
+-----------------+ +--------------------+
| | | |
| | | |
| | | |
| browser/PC | ① GET / HTTP/1.0 | |
| |--------------------> sites over https |
| ① WAIT! Where is CA ?| |
| +--------------------> |
| | ④ Anyway,give me | |
+-----+----^------+ the code! +--------------------+
| |
| |
| |③ He is good!
② Is's it| |
a bad site? |
| | +----------------------+
| | | |
| +----+ |
| | |
| | CA |
+---------> |
| |
| |
+----------------------+
证书原理
CA证书能够帮助我们鉴别某一个网站的合法性,简单的概括一下原理:
- 生成我的公钥
- CA机构用自己的私钥加密我的公钥以及相关信息
- 客户信任CA,并拥有CA的公钥,客户就可以使用公钥解密加密后的证书,并从证书中得到我的公钥
- 如果能用CA的公钥解密出数据,说明我的证书是经过CA认证过的,客户就可以放心访问了,如果系统发现证书不是权威CA机构颁发的,会警告用户
- 客户使用我的公钥解密数据,然后进行信息交换
有一些需要注意的地方:
- 证书有有效期这一说
- 证书中的相关信息,需要包括改证书到根证书的信任链,如下图,bing.com的证书中,就能够顺藤摸瓜,找到根CA机构,所以在生成自己的证书后,一定要加入这个信任链才能让系统正确的识别到与证书相关的最终根CA。
↑ bing的证书信息
↑ blog.phpgao.com的证书信息
证书格式
SSL使用X.509证书标准,编码格式有两种。
证书的编码格式
PEM(Privacy Enhanced Mail),通常用于数字证书认证机构(Certificate Authorities,CA),扩展名为.pem, .crt, .cer, and .key。内容为Base64编码的ASCII码文件,有类似"—–BEGIN CERTIFICATE—–" 和 “—–END CERTIFICATE—–“的头尾标记。服务器认证证书,中级认证证书和私钥都可以储存为PEM格式(认证证书其实就是公钥)。Apache和nginx等类似的服务器使用PEM格式证书。
DER(Distinguished Encoding Rules),与PEM不同之处在于其使用二进制而不是Base64编码的ASCII。扩展名为.der,但也经常使用.cer用作扩展名,所有类型的认证证书和私钥都可以存储为DER格式。Java使其典型使用平台。
证书编码的转换
# PEM转为DER
openssl x509 -in cert.crt -outform der -out cert.der
# DER转为PEM
openssl x509 -in cert.crt -inform der -outform pem -out cert.pem
CSR
In public key infrastructure (PKI) systems, a certificate signing request (also CSR or certification request) is a message sent from an applicant to a certificate authority in order to apply for a digital identity certificate. The most common format for CSRs is the PKCS #10 specification and another is the Signed Public Key and Challenge Spkac format generated by some Web browsers. - Wiki of Certificate signing request
CSR(Certificate Signing Request),它是向CA机构申请数字身份证书时使用的请求文件,他最常见的格式是PKCS #10。在生成请求文件前,我们需要准备一对对称密钥。私钥信息自己保存,请求中会附上公钥信息以及国家,城市,域名,Email等信息,csr中还会附上签名信息。当我们准备好CSR文件后就可以提交给CA机构,等待他们给我们签名,签好名后我们会收到crt文件,即证书。
# 帮助
openssl req -h
# 生成CSR请求文件和私钥
openssl req -nodes -days 365 -newkey rsa:2048 -keyout key_rsa -out domain.csr
# 从已存在的私钥生生成CSR请求文件
openssl req -new -days 365 -key key_rsa -out domain.csr
# 信息可以直接写好
openssl req -new -days 3650 -key key_rsa -out domain.csr -subj \
"/C=CN/ST=Shanghai/L=Shanghai/O=Qihoo 360/OU=IT Dept/CN=blog.phpgao.com/emailAddress=admin@phpgao.com"
# 检查CSR文件信息
openssl req -text -noout -verify -in domain.csr
CRT
其实我们最终就需要一个私钥文件和证书文件,这一步骤我们会得到CRT文件。
自签名
当我们生成好CSR文件后,就可以开始签名了,是的,自己给自己签名!
openssl ca -h
# 先生成一个CA根证书
openssl req -x509 -nodes -days 36500 -newkey rsa:2048 -keyout key_ca_rsa -out ca.crt
# 使用CA的私钥签名
openssl ca -policy policy_anything -days 365 -cert ca.crt -keyfile key_rsa -in domain.csr -out domain.crt
# 可能会出错,因为缺少一些必要文件
mkdir -p demoCA/newCerts
touch demoCA/index.txt
echo -n "01" > demoCA/serial
直接生成证书
我们当然也可以直接生成CRT文件。
# 生成证书和私钥
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout key_rsa -out key.crt
# 从已存在的私钥生成生成证书
openssl req -x509 -new -days 365 -key domain.key -out domain.crt
# 检查证书信息
openssl x509 -text -noout -in domain.crt
补充信息
CSR所需要的信息
CN = Country Name (2 letter code)
ST = State or Province Name (full name)
L = Locality Name (eg, city)
O = Organization Name (eg, company)
OU = Organizational Unit Name
CN = Common Name (eg, your name or your server's hostname)
# 例子
Country Name (2 letter code) [AU]:CN
State or Province Name (full name) [Some-State]:Shanghai
Locality Name (eg, city) []:Shanghai
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Qihoo 360
Organizational Unit Name (eg, section) []:IT Dept
Common Name (e.g. server FQDN or YOUR name) []:blog.phpgao.com
Email Address []:admin@phpgao.com
# 我们可以在需要输入以上信息的时候直接用下面的选项,就不用在一个一个输入了
-subj \
"/C=CN/ST=Shanghai/L=Shanghai/O=Qihoo 360/OU=IT Dept/CN=blog.phpgao.com/emailAddress=admin@phpgao.com"
Diffie-Hellman
Diffie-Hellman加密算法的最终目的是为了完成通信双方对称秘钥的交互,但是它牛逼在即使处在不安全的环境(有人侦听)也不会造成秘钥泄露,生成的时间会比较长,请耐心等待。
openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048
使用方法:
ssl_dhparam /etc/ssl/certs/dhparam.pem;
SSL的nginx配置
# from https://cipherli.st/
# and https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_ecdh_curve secp384r1;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
SSL在线工具
Reference: