f2h2h1.github.io

密码学入门简明指南

这篇文章不涉及密码学的数学原理,只提及相关概念和应用

相关的概念

信息安全

信息安全五要素

各个密码学概念对应的要素

各种攻击所对应的要素

以 https 为例解释信息安全的五要素

信息安全常识

  1. 不要使用保密的密码算法
  2. 使用低强度的密码比不进行任何加密更危险
    • 低强度的密码和没有加密同样不安全。但是使用了密码会给用户一种错误的安全感,导致用户容易泄露一些机密的信息。
  3. 任何密码总有一天都会被破解
  4. 密码只是信息安全的一部分

3A

信息安全的基本原则

为了达到信息安全的目标,各种信息安全技术的使用必须遵守一些基本的原则。

随机数

随机数的性质

  1. 随机性,不存在统计学偏差,是完全杂乱的数列
  2. 不可预测性,不能从过去的数列推测出下一个出现的数列
  3. 不可重现性,除非将数列本身保存下来,否则不能重现相同的数列

随机数的分类

随机数的作用

  1. 生成密钥
    • 用于对称密码和消息认证码
  2. 生成公钥密码
    • 用于生成公钥密码和数字签名
  3. 生成初始化向量 IV
    • 用于分组密码中的 CBC、CFB、OFB 模式
  4. 生成 nonce
    • 用于防御重放攻击和分组密码中的 CTR 模式
  5. 生成盐
    • 用于基于口令密码的 PBE 等

在 linux 下生成随机数

/dev/random 在类 UNIX 系统中是一个特殊的设备文件,可以用作随机数生成器。

/dev/random 的随机数的提供是依赖与外部中断事件的,如果没有足够多中断事件,就会阻塞。 /dev/random 生成的是真随机数。

/dev/urandom(“unblocked”,非阻塞的随机数生成器)是 /dev/random 的一个副本 ,它会重复使用熵池中的数据以产生伪随机数据。 这表示对 /dev/urandom 的读取操作不会产生阻塞,但其输出的熵可能小于 /dev/random 的。 它可以作为生成较低强度密码的伪随机数生成器,不建议用于生成高强度长期密码。

/dev/random 和 /dev/urandom 会输出二进制数据流,可以用 od 命令转换,或者用 base64 命令转换。

/dev/random 和 /dev/urandom 生成的都是符合密码学安全的随机数。因为 /dev/random 可能会阻塞,所以大部分情况下用 /dev/urandom 就可以了。

大部分情况下都是用 TRNG 生成的随机数作为种子,然后再用 CSPRNG 生成密码学安全的随机数。这样既能保证安全也能效率也不会太低。

命令行下的使用示例

# 不能直接用 cat ,因为 /dev/random 会一直输出
head -n 1 /dev/random | od -x
head -n 1 /dev/urandom | od -x
# 生成随机字符串
head -n 1 /dev/urandom | base64 | head -n 1
head -n 1 /dev/urandom | base64 | head -n 1
# 只生成数字
head -n 1 /dev/urandom | base64 | head -n 1 | tr -dc '0-9'
# 环境变量里的 $RANDOM 是一个随机数字
echo $RANDOM

OpenSSL 的一般使用

OpenSSL是一个开放源代码的软件库包。这个包广泛被应用在互联网的网页服务器上。 其主要库是以C语言所写成,实现了基本的加密功能,实现了SSL与TLS协议。

以下命令均在 cygwin 或 linux 下运行

以下命令是在这个版本 OpenSSL 1.1.1g 21 Apr 2020 下的 OpenSSL 运行的

openssl req -new \
    -key rsa_private_key.pem \
    -keyform PEM \
    -out myserver.csr
# -new 生成一个新的 csr 文件
# -key 私钥文件路径
# -keyform 私钥的格式
# -out 生成的 csr 文件路径

生成多个域名的证书

一般使用 OpenSSL 生成证书时都是 v1 版的,不带扩展属性。 多域名证书需要用到 v3 版的 extensions 的 Subject Alternative Name (SAN 主题替代名称)

  1. 寻找默认配置文件
    find / -name openssl.cnf
    
  2. 复制一份默认配置文件
    cp /usr/ssl/openssl.cnf openssl.cnf
    
  3. 编辑 openssl.cnf
    1. [ req ] 字段下加入 req_extensions = v3_req
    2. [ v3_req ] 字段下加入 subjectAltName = @alt_names
    3. 在配置文件的最后最后新建一个字段 [ alt_names ]
    4. 在 [ alt_names ] 里按以下格式写入多个域名
       [ alt_names ]
       DNS.1 = 3.example.com
       DNS.2 = 4.example.com
      
  4. 新建私钥
    openssl genrsa -out rsa_private_key.pem 4096
    
  5. 生成 csr 文件
    openssl req -new \
     -key rsa_private_key.pem \
     -keyform PEM \
     -config openssl.cnf \
     -out myserver.csr
    
  6. 生成数字证书
    openssl x509 \
     -sha256 \
     -signkey rsa_private_key.pem \
     -in myserver2.csr \
     -extensions v3_req \
     -extfile openssl.cnf \
     -req -days 365 -out domain.crt
    

自建 CA

  1. 创建 CA 目录
    mkdir -p ~/ssl/demoCA/{certs,newcerts,crl,private}
    cd ~/ssl/demoCA
    Touch index.txt
    echo "01" > serial
    
  2. 寻找默认配置文件
    find / -name openssl.cnf
    
  3. 复制一份默认配置文件
    cp /usr/ssl/openssl.cnf ~/ssl/openssl.cnf
    
  4. 修改 openssl.cnf 文件
    • 把 [ CA_default ] 的 dir 修改成 ~/ssl/demoCA/ 的绝对路径,类似于这样
        [ CA_default ]
        dir		= /root/ssl/demoCA		# Where everything is kept
      
  5. 生成 CA 根证书及密钥
    openssl req -new -x509 -newkey rsa:4096 -nodes -keyout cakey.key -out cacert.crt -config openssl.cnf -days 365
    
  6. 生成客户端私钥
    openssl genrsa -out client.key 4096
    
  7. 用该客户端私钥生成证书签名请求
    openssl req -new -key client.key -out client.csr -config openssl.cnf
    
  8. 使用 CA 根证书签发客户端证书
    openssl ca -in client.csr -out client.crt -cert cacert.crt -keyfile cakey.key -config openssl.cnf
    

证书链合并

一些情况下,从 CA 那里申请到的 SSL 证书需要配置证书链,因为颁发的 CA 只是一个中间 CA 。 这个时候,需要把 CA 的证书和 SSL 证书都转换成 pem 格式。 然后新建一个文件,按照 最终实体证书 -> 中间证书 -> 根证书 这样的顺序,把证书的 pem 格式的内容复制进去,证书之间用一个空行隔开。 例如这样

-----BEGIN CERTIFICATE-----
这是 最终实体证书
------END CERTIFICATE------

-----BEGIN CERTIFICATE-----
这是 中间证书
------END CERTIFICATE------

-----BEGIN CERTIFICATE-----
这是 根证书
------END CERTIFICATE------

根证书大多数情况下都会内置在客户端,所以大多数情况下都只需要 最终实体证书 和 中间证书。 有时 中间证书 可能有多个,按照签发顺序排列就好,反正就是下面的证书颁发上面的证书。

有时还需要把私钥和证书合并成一个文件,一般是把私钥放在前面,证书放在后面,例如 这样

cat server.key server.crt > server.pem

其它命令

openssl s_time 用于测试 TSL 服务

openssl s_server 用于测试 TSL 客户端,例如浏览器对各个加密套件的支持情况

openssl s_server -accept 2009 -key rsa_private_key.pem -cert domain.crt -www -debug -msg
# -accept 监听的端口 -key 私钥路径 -crt 证书路径 -www http请求返回状态信息
# 可以用浏览器输测试,直接输入网址 https://127.0.0.1:2009
# 可以用 curl 测试 curl -k -i -v https://127.0.0.1:2009
# 可以用 openssl s_client 测试 openssl s_client -connect 127.0.0.1:2009 -showcerts

openssl s_client 用于测试 TSL 服务端

openssl smime 用于处理S/MIME邮件,它能加密、解密、签名和验证S/MIME消息

openssl ca ca命令是一个小型CA系统。它能签发证书请求和生成CRL。它维护一个已签发证书状态的文本数据库。

OpenSSH 的一般使用

OpenSSH (OpenBSD Secure Shell) 是 OpenBSD 的子项目。 OpenSSH 常常被误认以为与 OpenSSL 有关系,但实际上这两个项目有不同的目的,不同的发展团队,名称相近只是因为两者有同样的软件发展目标──提供开放源代码的加密通信软件。

程序主要包括了几个部分:

   
ssh rlogin 与 Telnet 的替代方案
scp sftp rcp ftp 的替代方案,将文件复制到其他电脑上
sshd SSH服务器
ssh-keygen 产生 RSA 或 ECDSA 密钥,用来认证用
ssh-agent ssh-add 帮助用户不需要每次都要输入密钥密码的工具

以下命令是在这个版本 OpenSSH_8.5p1, OpenSSL 1.1.1k 25 Mar 2021 下的 OpenSSH 运行的

sshd

ssh

sftp

OpenSSH 和 OpenSSL

OpenSSH 是 SSH 协议的实现,实现过程中,需要用到密钥交换算法,对称/非对称加密算法,随机数算法,等密码学相关的算法。 早期版本的 OpenSSH 是通过调用 OpenSSL 的库来实现这些算法的。 2014年4月的心脏出血漏洞事件之后, OpenBSD 项目成员以 OpenSSL 1.0.1g 作为分支,创建一个名为 LibreSSL 的项目。 OpenSSH 会逐渐减少对 OpenSSL 的依赖。

GnuPG 的一般使用

1991 年,程序员 Phil Zimmermann 为了避开政府的监视,开发了加密软件 PGP (Pretty Good Privacy)。 但是,它是商业软不能自由使用。所以,自由软件基金会决定,开发一个 PGP 的替代品取名为 GnuPG (GNU Privacy Guard)。 OpenPGP (Pretty Good Privacy) 是一种加密标准。 GnuPG 是实现该标准的软件。

gpg 在需要用到私钥的地方都需要口令。 gpg 会对消息进行压缩。

gpg 的配置文件一般会保存在这个位置

linux ~/.gnupg
windows 系统盘/Users/用户名/.gnupg

加密和解密

签名和验签

一些命令参考

以下命令是在这个版本 gpg (GnuPG) 2.2.28 下的 GnuPG 运行的

GnuPG 和 email

很多邮件客户端都支持使用 GPG 来加密邮件。

只要导入发件人的私钥和收件人的公钥,就能发送加密的邮件。发件人的邮箱地址需要和私钥的邮箱地址对应,收件人的邮箱地址需要和公钥的邮箱地址对应。 使用加密后,会把整个邮件报文加密,包括主题,然后把密文保存在一个文件里,作为附件发送。 如果收件人的邮件客户端不支持直接解密邮件,可以把邮件的附件下载下来然后再用 GPG 解密。像这样 gpg --recipient [接收者ID] --output demo.de.txt --decrypt encrypted.asc

其实把明文加密后再把密文复制到邮件内容里发送也可以,但收件人的邮件客户端未必能解密,因为一般加密的邮件都是整个报文加密的,这种可能需要把邮件里的密文保存到单独的文件后再解密。

参考

https://zh.wikipedia.org/wiki/%E5%85%AC%E9%92%A5%E5%AF%86%E7%A0%81%E5%AD%A6%E6%A0%87%E5%87%86

https://zh.wikipedia.org/wiki/%E4%BF%A1%E6%81%AF%E5%AE%89%E5%85%A8

https://yeasy.gitbook.io/blockchain_guide/ 区块链技术指南 虽然是讲区块链的,但密码学部分很有参考价值

https://book.douban.com/subject/26822106/ 图解密码技术(第3版)

https://www.gnupg.org/howtos/zh/index.html GnuPG 袖珍 HOWTO (中文版)

https://docs.azure.cn/zh-cn/articles/azure-operations-guide/application-gateway/aog-application-gateway-howto-create-self-signed-cert-via-openssl