浅浅了解一下加密知识

1,292 阅读7分钟

背景

事情起因是上半年做了个小需求,是一个查询数据的页面。开发的时候习惯性地将查询过的参数存在了url里,方便用户可以直接从带参数的url进入查看查询结果。

然而上线后发现线上环境其中一个参数对象内容很多,里面有二十几个属性,导致stringify后url巨长无比,影响了系统的统一登录鉴权,进而影响了图表的查询……

我当时的心情如下:

测试环境翻车.gif

因为开发测试环境数据量确实比线上少很多,所以问题没能提前暴露出来,导致上线后出了问题。

修复问题的时候有考虑过通过编码or加密等方法来改变url长度,不过最后和pm沟通后直接去掉了可能影响查询结果的查询参数。

事后复盘这个问题,发现自己对于加解密算法的知识完全是临时抱佛脚(甚至还没抱起来就不用抱了),因此决定好好学习一下。 怪不好意思的.jpg

加密和解密

首先来介绍下什么是加密和解密。

加密

加密(Encryption)是将明文信息改变为难以读取的密文内容,使之不可读的过程。只有拥有解密方法的对象,经由解密过程,才能将密文还原为正常可读的内容。

明文(Plaintext)是指传送方想要接收方获得的可读信息。 明文经过加密所产生的信息被称为密文,而密文经过解密还原得来的信息被称为明文。

解密

解密(Decryption)即加密的逆过程,指将密文内容还原为明文信息的过程。

两个过程如下图所示:

加密解密.png

对称加密和非对称加密

在加密和解密过程中,应用的密码信息被称作密钥(key)。

在现实世界中的钥匙用来打开锁,而密码算法中的“钥匙”也就是密钥,则用来“打开”密文。

根据密钥的种类,我们将加密过程分为两类:对称加密和非对称加密。

对称加密

也称作私钥加密共享密钥加密。

这类算法在加密和解密时使用**相同的密钥。**通信方必须具有相同的密钥才能实现安全通信。

相对于非对称加密,对称加密的速度会更快一些,因为只需要一把私钥即可实现加密和解密。

非对称加密

也称作公钥加密。

这类算法需要两个密钥:公钥和私钥。

它的特点是用公钥加密后得到的密文,只能用对应的私钥进行解密;或者用私钥加密后得到密文,只能用对应的公钥进行解密。公钥和私钥不相等,即需要两个不同的密钥,故称作非对称加密。

公钥可以公开发布,私钥不可以公开,必须由用户自行严格秘密保管。

两种加密过程如下图所示:

对称和非对称加密.png

常见的加密算法

DES

DES(Data Encryption Standard) 是一种对称的块加密算法。块加密(也叫做分组加密),即把明文划分为很多个等长的块(block),对每个块进行加密,最后以某种手段拼在一起。

DES 加密算法分组的大小是 64 位,如果加密的数据长度不是 64 位的倍数,可以按照某种具体的规则来填充位。密钥长度为 64 位,实际参与运算是 56 位,其中每个字节的最高位不参与运算。

DES 算法的特点就是分组比较短、密钥太短、运算速度较慢。

3DES

3DES 是三重数据加密算法的通称,它相当于是使用三条不同的密钥对每个数据块应用三次 DES 加密算法。

由于计算机运算能力的增强,原版 DES 密码的密钥长度变得容易被暴力破解,3DES 即是设计用来提供一种相对简单的方法,即通过增加 DES 的密钥长度来避免类似的攻击,而不是设计一种全新的块加密算法。相对于 DES,3DES 算法更安全。

AES

AES(Advanced Encryption Standard)高级加密标准是用来替代原先的DES加密算法的,目前已经成为对称加密中最流行的算法之一。

AES 也是一种对称的快加密算法。AES 支持三种长度的密钥:128位,192位,256位,所以平时所说的AES128、AES192、AES256,就是指使用不同长度密钥的 AES 算法。

AES 加密时首先将明文拆成长度为 128 位的明文块,对每个块进行加密,最后以某种手段拼在一起作为加密结果。如果明文块长度不足 128 位,则按照某种填充方式进行填充后再进行加密。

RSA

RSA 是目前最有影响力的非对称加密算法,该算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,但想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥,即公钥,而两个大素数组合成私钥。公钥是可发布的供任何人使用,私钥则为自己所有,供解密之用。

由于进行的都是大数计算,因此对比 DES 这种对称加密,RSA 的加密速度要慢上很多。

ECC

ECC(Elliptic Curve Cryptography,椭圆加密算法)是一种公钥加密算法,其数学基础是利用椭圆曲线上的有理点构成 Abel 加法群上椭圆离散对数的计算困难性。

ECC 的主要优势是在某些情况下它比其他的方法使用更小的密钥(比如 RSA),提供相当的或更高等级的安全。不过一个缺点是加密和解密操作的实现比其他机制花费的时间长。

MD5

严格来说 MD5 不能算是加密算法,它是一种哈希散列算法,可以产生出一个 128 位的散列值(hash value),用于确保信息传输完整一致。

一般 128 位的MD5散列被表示为 32 位的十六进制数字。

SHA-1

和 MD5 类似,SHA-1(Secure Hash Algorithm 1) 也是一种哈希散列算法,SHA-1 可以生成一个 160 位的散列值(称做消息摘要),散列值通常呈现为 40 位十六进制数。

Base64

放在最后说 Base64,是因为 Base64 并不是加密方式,它只是一种编码方式,只是将数据转换为肉眼不可读的状态,并不具有保密性。

Base64 是一种基于 64 个可打印字符来表示二进制数据的表示方法,常用在处理文本数据场合,表示、传输、存储一些二进制数据,包括电子邮件及 XML 的一些复杂数据。

前端应用

这里用 Crypto-JS 来演示下常见的几种加密方式。

DES:

import CryptoJS from 'crypto-js';
const text = 'This is my message';
const key = 'Secret key'

const ciphertext = CryptoJS.DES.encrypt(text, key);
const decrypted = CryptoJS.DES.decrypt(ciphertext, key);
// cryptojs中未指定salt值,则每次加密会随机生成salt值,加密结果每次会不同
// U2FsdGVkX19eJ8L1bdpcn93HkbPdK7ogc38bWukE8ICs/oXfSIbhIw==
const originalText = decrypted.toString(CryptoJS.enc.Utf8);

3DES:

const ciphertext = CryptoJS.TripleDES.encrypt(text, key);
const decrypted = CryptoJS.TripleDES.decrypt(ciphertext, key);
// U2FsdGVkX19EB5kvEelv5Z5ivgiV7jwT26PJV4NTo7MObnjTUJ9UJA==
const originalText = decrypted.toString(CryptoJS.enc.Utf8);

AES:

const ciphertext = CryptoJS.AES.encrypt(text, key);
const decrypted = CryptoJS.AES.decrypt(ciphertext, key);
// U2FsdGVkX1/kf8yJB1roiXVnUuoRFek1TsYabV7W09UqzCIfbISvRyRsxjyowJnX
const originalText = decrypted.toString(CryptoJS.enc.Utf8);

MD5:

const hash = CryptoJS.MD5(text).toString()
// 91c395cbd350da6bedfe3b24db9517b0

SHA-1:

const hash = CryptoJS.SHA1(text).toString()
//4618ea8e820ddf616f19b9d48b8a7eb2c1c0a107

Base64:

const wordArray = CryptoJS.enc.Utf8.parse(text);
// 54686973206973206d79206d657373616765
const base64 = CryptoJS.enc.Base64.stringify(wordArray);
// VGhpcyBpcyBteSBtZXNzYWdl

总结

最后再回到前文的问题。现在再思考一下,其实查询字符串中显然不应该使用编码or加密的方式来处理,因为本质上无论是编码还是加密都不能达到缩短字符串的目的。

虽然问题没有通过加密手段来解决,但却因此发现了知识盲区,也是好事,多学多记,总会有用到知识的那天。