🥫🍞

加密解密笔记

2022-07-10

加密解密笔记

密码技术

  • 原文:或者叫明文,就是被隐藏的文字。
  • 加密法:指隐藏原文的法则。
  • 密文:或者叫伪文,指对原文按照加密法处理过后生成的可公开传递的文字。
  • 密钥:在加密法中起决定性的因素,可能是数字、词汇,也可能是一些字母,或者这些东西的组合。

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
2
3
4
5
6
7
8
9
function openssl_encrypt(
string $data,
string $cipher_algo,
string $passphrase,
int $options = 0,
string $iv = "",
&$tag, string $aad = "",
int $tag_length = 16
): string|false

参数说明:

参数 说明
$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
    7
    int 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
    8
    BigInteger 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
    8
    byte[] 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
2
3
4
5
const publicKey = '' // PEM 格式公钥
const origin = '' // 需要加密的数据
const jsEncrypt = new JSEncrypt()
jsEncrypt.setPublicKey(publicKey)
const encrypted = jsEncrypt.encrypt(origin) // 返回的是 base64 编码的结果
  • 私钥解密
    1
    2
    3
    4
    5
    const 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
2
3
$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy
\__/\/ \____________________/\_____________________________/
Alg Cost Salt Hash

$2a$ hash算法的唯一标志

10 代价因子,这里是 2 的 10 次方,

N9qo8uLOickgx2ZMRZoMye 16 字节的 salt经过 base64 编码得到的 22 长度字符

IjZAgcfl7p92ldGxad68LJZdL17lhWy 是 24 个字节的 hash,经过 base64 编码的 31 长度字符

Tags: crpto
使用支付宝打赏
使用微信打赏

若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏

扫描二维码,分享此文章