Skip to content

开发者实用密码学

软件开发人员在日常工作中会经常用到密码学,例如哈希(信息摘要),加密,数字签名。实现加密算法通常很复杂,各种数学概念,本文实用密码学旨在如何理解密码学中的部分概念和如何使用现有的库。

密码学概念

原文

原文是指待加密的内容。原文本身不难以理解,但如何在加密库中将原文输入则需要细细道来。

在你对密码世界没有任何概念的时候,你通常都会认为原文就是一个普通的字符串,实际上加密都是针对二进制数据进行的,因此我们需要了解如何将原文转化成二进制数据。

通常你所使用的加密库都已自带将原文转化为二进制内容的方法, 下面是一个例子

对称加密

使用相同的密钥来加密和解密消息。

例如 AES, DES, ChaCha20。

伪代码:

ts
const key = 'key'

// 加密
const encrypted = encrypt('原文', key)

// 解密
const decrypted = decrypt(encrypted, key) // 原文

非对称加密

通常使用一对密钥来进行加解密。有两种情况:

  1. 公钥加密私钥解密,就是用于一般的加密保证数据安全性。
  2. 私钥加密公钥解密,用于身份认证判断某个用户的真实性(签名)。

RSA是一个常用的非对称加密算法。

数字签名和消息认证

数字签名实际上就是用私钥进行加密(签名),公钥进行解密(验证)。

数字签名和在真实世界的签名一样,一但签名经由你的手发生,意味着以下几个信息:

  1. 内容生效,通常不得再更改(不可否认)。
  2. 内容发生对象确定,也就是你本人(真实性)。
  3. 内容已经被你确定(完整性)。

随机数

如果没有随机数,每次加密时生成的密文都是一样的,加密时输入随机数会让每次加密的密文不一样增加安全性。

初始化向量(IV)就是一种随机数。

需要注意的是:所有的软件中的随机数都是伪随机数,因此伪随机数的随机性显得尤为重要。

随机数通常并不像密钥那样保密。

初始化向量IV(Initialization Vector)

初始化向量通常用于分组加密的第一个分组,因为大部分加密模式需要与前一个密文分组进行运算加密,而第一个分组没有前置密文,因此需要一个和分组长度相等的值来承担这个角色,所以这个值就被称为初始化向量。

IV应该是一个固定长度的随机数或者伪随机数,如果IV每次都一致,那么得到的密文每次都会一致,没有意义。

解密时的IV应该与加密时的IV保持相同,如果密文需要传输给接收方解密,那么iv也需要一起传输过去。

通常来说,iv如果不指定那么它将默认是一个16字节大小的0填充数值,这个0填充是二进制的0,等价为new Uint8Array(16)。

混淆

混淆不只是密码学中的概念,它本质上是指使事物变得不可理解或者难以理解的一种方式。

混淆通常就是改变排列方式和置换原文。

比如现代前端代码都经由构建工具打包,生成的JS代码被压缩后通常都是难以阅读的,因为压缩就是原文置换的一种,因此你可以认为这种压缩过的代码就是混淆过的代码。

现代防盗(比如某些小说网站)大量地使用到了混淆,这也是你看某些dao ban小说会出现奇怪乱码的原因。

长度

经常会看到AES-128, SHA-256之类的数字,有以下几种指代:

  1. 生成的密文长度
  2. 密钥的长度
  3. 加密区块的长度

这些数字准确地来讲都是8的倍数,8的单位是bit,8bit就是一个字节的长度,像AES-128实际上就是指的生成128位也即16字节长度的密文,并且加密密钥也需要使用16字节长度的密钥,区块长度也为16字节,甚至原文数据也要是128的倍数(不满足的会进行填充)。

分组加密

常见的对称加密算法, AES, DES, 3DES都是分组加密算法,他们只能加密固定长度的明文数据。

分组加密将输入的数据划分为固定大小的数据块(称为分组),然后对每个分组进行独立的加密和解密操作。

分组加密伴随着两个概念:算法模式和填充

分组加密——模式

模式指定算法按照什么样的过程和组合方式来加密数据。

常见的模式:

  1. ECB: 电子密码本模式(Electronic CodeBook)
  2. CBC: 密码分组链接模式(Cipher Block Chaining)
  3. CFB: 密文反馈模式(Cipher Feedback mode)
  4. OFB: 输出反馈模式(Output Feedback mode)
  5. CTR: 计数器模式(Counter mode)

你不需要理解这些模式的内容和过程,因为你无需实现这些算法,但需要注意的是除了ECB模式外,其他的模式都可以提供一个初始化向量(IV: Initialization Vector)来增加生成的密文的安全性,ECB本质上对每个分组进行单独加密,每个分组不会产生相关性。因此ECB相对其他模式来讲是不安全的。

分组加密——填充

在密码学中,填充(padding)是指在加密算法中对数据进行补位的过程。填充通常用于确保待加密的数据长度符合特定的加密算法要求。

我们不需要了解不同的填充方法,只要加解密时填充保证填充方式一致即可。

MIT Licensed