加密解密笔记
密码技术
- 原文:或者叫明文,就是被隐藏的文字。
- 加密法:指隐藏原文的法则。
- 密文:或者叫伪文,指对原文按照加密法处理过后生成的可公开传递的文字。
- 密钥:在加密法中起决定性的因素,可能是数字、词汇,也可能是一些字母,或者这些东西的组合。
1. 对称加密算法
对称加密是指加密和解密使用同一个密钥。对称加密只有一个密钥,作为私钥。
具体的算法有:DES、3DES、TDEA、Blowfish、RC5、IDEA。常用的有:DES、AES
优点:计算量小、加密速度快
缺点:不太安全,需要保存好密钥,而且,一般会为每个用户准备不同私钥,存储量大。
1.1. ECB 和 CBC
- ECB 模式
Electronic Codebook 电码本。将数据按照8个字节一段进行DES加密或解密得到一段段的8个字节的密文或者明文,最后一段不足8个字节(一般补0或者F),按照需求补足8个字节进行计算(并行计算),之后按照顺序将计算所得的数据连在一起即可,各段数据之间互不影响。
- CBC 模式
Cipher Block Chaining 密文分组链接模式。
(1) 将数据按照 8 字节分组,得到D1, D2, … , Dn(若数据不是8的整数倍,用指定的PADDING数据补位)
(2) 第一组数据 D1 与初始化向量 I 异或后的结果进行 DES 加密得到第一组密文 C1
(3) 第二组数据 D2 与第一组的加密结果 C1 异或以后的结果进行 DES 加密,得到第二组密文 C2
(4) 之后的数据以此类推,得到Cn
(5) 按顺序连为C1C2C3…Cn即为加密结果。
1.2. DES
分组密码,以 64 位为分组对数据加密,密钥长度是 56 位。穷举法进行搜索,运算次数为 $2^{56}$
代码
- PHP
php 7.1 之前加密与解密参考这里
php 7.1 之后加密解密 —— openssl
加密与解密
- pkcs7Padding 函数
可能在填充字节的过程中遇到。如果是 pkcs5Padding,固定传入 $size = 8 即可
- php 7.1 之前加密与解密
如果与 Java 系统对接,建议传入 $key 固定为 8 位,保持与 Java 加解密库兼容。
- php 7.1 之后加密解密 —— openssl
1 | function openssl_encrypt( |
参数说明:
参数 | 说明 |
---|---|
$data | 数据 |
$options | OPENSSL_NO_PADDING:需要手动填充,否则不对齐返回 false OPENSSL_RAW_DATA:自动以 pkcs5 填充 |
- Java 加密解密
Java DESKeySpec 需要密码至少 8 字节,如果超过 8 字节,只取前 8 字节。
1.2. AES
介绍
AES 是一个高级加密标准(Advanced Encryption Standard)。
AES 按加密方式分为:AES-128、AES-192、AES-256
按加密模式分为:ECB、CBC、CTR、CFB、OCF
对称分组密码体制,分组长度 128 位。这种加密算法是美国联邦政府采用的区块加密标准,AES 标准用来代替原先的 DES。
javax.crypto 包下。
加解密功能由 Cipher 组件提供,
在设置 Cipher 类的时候注意点:
(1) Cipher 在使用时需以参数方式指定 transformation
(2) transformation 格式为 algorithm/mode/padding,其中 algorithm 为必输项,
(3) 缺省的 mode 为 ECB,缺省的 padding 为 PKCS5Padding
(4) 在 block 算法与流加密模式组合时,需在 mode 后面指定每次处理的 bit 数,如 DES/CFB8/NoPadding,如未指定则使用缺省值,SunJCE 缺省值为 64 bits
(5) Cipher 有 4 中操作模式:ENCRYPT_MODE(加密)、DECRYPT_MODE(解密)、WRAP_MODE(导出Key)、UNWRAP_MODE(导入Key),初始化(init)时需要指定某种操作模式
代码参考
1.3. Discuz
php 论坛框架 discuz 的加密算法,也兼容过期时间校验。
2. 非对称加密算法
加密和解密用的不是同一个密钥。每个用户拥有 2 把钥匙,公钥和私钥。顾名思义,公钥,是可以对外发布的,私钥是自己保存,只有自己知道的。
应用
信息加密和解密 用 A 用户的公钥加密后只能用 A 用户的私钥解密。B 需要告诉 A:请来 X 区域找我。B 使用 A 的公钥进行加密,将密文发送给 A,其他人拿到密文没有 A 私钥是无法知道内容的,只有 A 拿到密文之后使用私钥解密才行。
加签和解签 公钥是用来解密信息的,确保别人知道这条消息是由我发布的,且是完整的。
A 用户通过私钥加密:我是 A,我收到了你的信息。此时,B 通过 A 的公钥解密,确认 A 已经收到了自己的消息。
生成 RSA 密钥对
openssl 命令
1
2# 1024 密钥长度
openssl genrsa -out key.pem 1024参数 说明 -out 指定生成文件,包含公钥和私钥 Java 代码生成
1
2
3
4
5
6
7int keySize = 1028;
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(keySize);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic());PHP 代码生成
1
2
3
4
5
6
7
8
9
10
11
12$opensslConfigPath = 'D:\wampserver\bin\apache\apache2.4.46\conf\openssl.cnf';
$config = array(
'digest_alg' => 'sha512',
'private_key_bits' => 1024,
'private_key_type' => OPENSSL_KEYTYPE_RSA,
'config'=> $opensslConfigPath
);
$res = openssl_pkey_new($config); //创建密钥对
openssl_pkey_export($res, $privkey, null, $config); //生成私钥
$pubKey = openssl_pkey_get_details($res)['key']; //生成公钥
print_r($privkey);
print_r($pubKey);
RSA 加密与解密
Java
Java 公钥加密
1
2
3
4
5
6
7
8BigInteger modulus = new BigInteger("", 16);
BigInteger pubExp = new BigInteger("", 16);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(modulus, pubExp);
RSAPublicKey key = (RSAPublicKey) keyFactory.generatePublic(pubKeySpec);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] cipherData = cipher.doFinal("密文".getBytes());Java 私钥解密
1
2
3
4
5
6
7
8byte[] encrypted = ""; // 密文,需要 base64 解码
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode("非 PEM 格式私钥"));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPrivateKey privateKey = (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decrptyed = cipher.doFinal(encrypted);
System.out.println(new String(decrptyed));
JavaScript
- 公钥加密
使用 JSEncrypt 库
1 | import { JSEncrypt } from 'jsencrypt/lib/JSEncrypt' |
1 | const publicKey = '' // PEM 格式公钥 |
- 私钥解密
1
2
3
4
5const privateKey = '' //
const encrypted = '' // 传递 base64 编码的加密值
const jsEncrypt = new JSEncrypt()
jsEncrypt.setPrivateKey(privateKey)
const decrypted = jsEncrypt.decrypt(msg)
PHP
- 解密
1
2
3
4$encrypted = ''; // 密文,如果有必要需要进行 base64 解码
$decrypted = ''; // 解密之后存放的变量
$private_key = ''; // PEM 格式私钥
openssl_private_decrypt($password, $decrypted, $private_key);
摘要算法
通过对所有数据提取指纹信息以实现数据签名、数据完整性校验等功能。数据摘要算法也被称为哈希算法或散列算法。
具体摘要算法:
CRC8 CRC16 CRC 32
MD2 MD4 MD5
SHA1 SHA256 SHA384 SHA512,SHA(Secure Hash Algorithm)是由美国专门制定密码算法的标准机构——美国国家标准技术研究院制定。
RIPEMD、PANAMA、TIGER、ADLER32
bcrypt
1 | $2b$[cost]$[22 character salt][31 character hash] |
1 | $2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy |
$2a$
hash算法的唯一标志
10 代价因子,这里是 2 的 10 次方,
N9qo8uLOickgx2ZMRZoMye 16 字节的 salt经过 base64 编码得到的 22 长度字符
IjZAgcfl7p92ldGxad68LJZdL17lhWy 是 24 个字节的 hash,经过 base64 编码的 31 长度字符
若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏
扫描二维码,分享此文章