OpenSSL学习笔记
OpenSSL 是一个开源软件库,提供了一组用于处理安全通信的工具和库函数,它可以用于多种不同的用途。
对称加密AES
AES ECB
ECB是不需要初始化向量,每个数据块单独进行加密,没有依赖关系,相同的明文块将始终加密为相同的密文块,无法隐藏明文块的模式。
随机生成256比特的密钥:
1 | openssl rand -out ecb.key 32 |
在vscode中可以用hexdump插件查看:
1 | ee11f36abfa2835cea739da5b954e7d031ee90647c4c2c0ac9c760ccef623ba7 |
加密:
1.txt的内容:
1 | test |
用256位密钥进行ecb模式的aes加密。
1 | openssl enc -e -aes-256-ecb -in 1.txt -out enc -pass file:ecb.key |
结果为:
1 | 53616c7465645f5f80e6464003d40b8142a8df7a239f9d0ee94a28c9a93118c9 |
解密:
1 | openssl enc -d -aes-256-ecb -in enc -out 2.txt -pass file:ecb.key |
解密成功:
前缀Salted
但是这样openssl加密的密文前缀都有”Salted”,因为enc加密默认是加盐值的。在密码学中,使用盐值(salt)进行加密是一种增强密码安全性的技术。盐值是一个随机生成的固定长度的字符串,它与密码结合使用,以产生密文。但这里不知道为什么前缀都是’Salted’,容易被识别出是加密以后的密文。
用-nosalt
可以去掉这个前缀。
1 | openssl enc -e -aes-256-ecb -nosalt -in 2.txt -out enc4 -pass file:ecb.key |
前缀出现的原因
openssl默认加盐,但没有指定盐值,所以盐值都是随机生成的,所以会把盐也写到密文文件中。-p
命令可以打印本次加密的向量和密钥值。
1 | -p Print the iv/key |
测试一下:
1 | openssl enc -e -aes-256-ecb -in 1.txt -out out2 -pass file:ecb.key -p |
再打开out2文件可以发现,前缀Salted__
后面紧跟的就是本次随机生成的盐值。
python验证加密结果
写一个简单的AES加密python脚本:
1 | from Crypto.Cipher import AES |
运行结果:
和上图对比可知,加密结果和openssl一致。
指定盐值
用-S
来指定盐值。
这样既保证了安全性,生成的文件中又仅有密文:
AES CBC
实际生产环境中一般用更安全的CBC模式。CBC(Cipher Block Chaining)模式使用前一个密文块与当前明文块进行异或运算,然后再加密,需要一个初始化向量(IV),用于第一个明文块的加密。CBC模式具有扩散效应,相同的明文块在不同的加密过程中会产生不同的密文块。此外,CBC模式支持并行加密解密操作。
前文是根据文件生成密钥的,如果不指定file
,也可以根据控制台输入来生成密钥和向量:
1 | openssl enc -e -aes-256-cbc -in 1.txt -out cbc1 -p -pbkdf2 |
-pbkdf2
是选用更推荐的密钥生成函数。
解密:
1 | openssl enc -d -aes-256-cbc -in cbc1 -p -pbkdf2 |
非对称加密RSA
RSA(Rivest-Shamir-Adleman)是一种非对称加密算法,广泛用于数据加密、数字签名和密钥交换等安全应用中。RSA 算法的基本原理是基于数论中的大数分解难题。它使用两个密钥,一个是公钥用于加密数据,另一个是私钥用于解密数据。公钥可以公开,而私钥必须保密。
以下是 RSA 算法的主要步骤:
密钥生成:
- 选择两个大素数 p 和 q,计算它们的乘积 n = p * q。
- 计算欧拉函数值 φ(n) = (p - 1) * (q - 1)。
- 选择一个小于 φ(n) 的整数 e,作为公钥指数。
- 计算与 e 互素的整数 d,作为私钥指数。即满足 (e * d) mod φ(n) = 1。
- 公钥是 (e, n),私钥是 (d, n)。
加密:
- 将明文消息转换为整数 m,使得 0 ≤ m < n。
- 使用公钥 (e, n) 对 m 进行加密,得到密文 c = m^e mod n。
解密:
- 使用私钥 (d, n) 对密文 c 进行解密,得到明文消息 m = c^d mod n。
RSA 算法的安全性基于大整数分解的困难性。要破解 RSA,需要通过分解 n 来计算出 p 和 q,这在当前技术下对于足够大的素数 p 和 q 是非常困难的。
密钥生成
生成私钥:
1 | openssl genrsa -out pri_key.pem 1024 |
1024是私钥长度。
根据私钥生成公钥:
1 | openssl rsa -in pri_key.pem -pubout -out pub_key.pem |
加密解密
公钥加密:
1 | openssl pkeyutl -encrypt -pubin -inkey pub_key.pem -in 1.txt -out rsa1 |
私钥解密:
1 | openssl pkeyutl -decrypt -inkey pri_key.pem -in rsa1 |
结果如下:
python验证
这里发生了小插曲,突然发现rsa加密每次结果都是不一样的,这是因为加密过程中使用了随机生成的填充数据。参考这篇文章:
1 | openssl rsautl -decrypt -raw -inkey pri_key.pem -in rsa1 -out out1 |
可以看到中间填充的数据应该是随机的:
虽然每次生成的密文不一样,但只要私钥正确,都可以正常解密出来。
python rsa库
rsa库的常用方法:
1 | import rsa |
此处出现了一些问题,RSA库用的是pkcs1格式的密钥文件,而本文之前生成的是pkcs8格式,会出现错误:
1 | No PEM start marker "b'-----BEGIN RSA PRIVATE KEY-----'" found |
对于公钥读取,可以用load_pkcs1_openssl_pem
方法代替load_pkcs1
;对于私钥,只能用openssl命令把pkcs8格式转换为pkcs1了:
1 | openssl pkcs8 -in pri_key.pem -nocrypt -out private_pkcs1.pem -traditional |
似乎有的版本不需要-traditional
。
解密openssl生成的密文:
1 | out=rsa.decrypt(bytes.fromhex("94c21061a08cdf3043c089e5d7b8229e139a60a095ea64b02d1d43d90c1773b4ebb491802b13cfa53f88c9c3e27ed4ab30fc3238fb983ae792f8425aebd077d34661f93ada40a5a768bb608bed43d152004ddb5390e7cac322af3d39685a70757f962dcaeeace23510e60086c7451e22d466e098dc33fa943bac52083a332f32"),private_key) |
python Crypto
常用方法:
1 | from Crypto.PublicKey import RSA |
解密openssl生成的密文:
1 | print(cipher.decrypt(bytes.fromhex("94c21061a08cdf3043c089e5d7b8229e139a60a095ea64b02d1d43d90c1773b4ebb491802b13cfa53f88c9c3e27ed4ab30fc3238fb983ae792f8425aebd077d34661f93ada40a5a768bb608bed43d152004ddb5390e7cac322af3d39685a70757f962dcaeeace23510e60086c7451e22d466e098dc33fa943bac52083a332f32"),0)) |
apache配置https
本文的apache环境是之前基于wamp配置的,理论上配置https比原生apache服务器难。参考
openssl部分
创建证书请求文件:
CSR 文件是一个包含有关证书请求者(例如服务器或个人)信息的文件,需要经过 CA 的验证和签名,以生成最终的数字证书(CRT 文件)。
1 | openssl req -new -key pri_key.pem -out server.csr |
签发证书:
CRT 文件是证书颁发机构对证书请求者进行验证后生成的,用于证明证书请求者的身份和提供公钥给通信对方。
1 | openssl x509 -req -days 365 -sha256 -in server.csr -signkey pri_key.pem -out servernew.crt |
apache部分
把servernew.crt
和pri_key.pem
文件移到apache的conf
目录下。
apache调用ssl模块:
在httpd.conf文件中开启如下选项:
修改conf/extra/httpd-ssl.comf
文件:
把C:\Windows\System32\drivers\etc\hosts
中添加(一般已经添加过了):
1 | 127.0.0.1 localhost |
访问https://localhost
点高级
:
使用 OpenSSL 生成证书时,默认情况下生成的证书是自签名的(self-signed)。自签名证书意味着该证书的颁发者和主题是相同的,没有经过第三方可信的证书颁发机构(CA)进行验证和签名。大多数浏览器和操作系统会发出类似的警告信息,提示证书不被信任。这是因为浏览器和操作系统内置了一组受信任的根证书颁发机构列表,用于验证和信任通过这些机构签名的证书。自签名证书不在这个受信任列表中,因此会被视为不可信。
接收风险并继续即可。
为了每次新访问都出现警告,可以导入自签名证书到受信任的根证书列表,点击CRT证书:
用别的浏览器访问,没有危险警告了。
可以通过windows+R
,运行certmgr.msc
进行证书管理。
https流量分析
基于前文配置好的https,用wires hark进行抓包进行数据分析。篇幅问题记录在HTTPS流量抓包分析(附代码验证)