写点什么

AES/CBC/PKCS5Padding 到底是什么

用户头像
kof11321
关注
发布于: 2021 年 01 月 14 日

为什么 JAVA 里指定算法时,写的是 AES/CBC/PKCS5Padding,每个都是什么含义,又有什么作用。

  1. AES,加解密算法

  2. CBC,数据分组模式

  3. PKCS5Padding,数据按照一定的大小进行分组,最后分剩下那一组,不够长度,就需要进行补齐

简单的说:拿到一个原始数据以后,首先需要对数据进行分组,分组以后如果长度不满足分组条件,需要进行补齐,最后形成多个分组,在使用加解密算法,对这多个分组进行加解密。所以这个过程中,AES,CBC,PKCS5Padding 缺一不可。

PKCS5Padding 和 PKCS7Padding

在对数据进行加解密时,通常将数据按照固定的大小(block size)分成多个组,那么随之就产生了一个问题,如果分到最后一组,不够一个 block size 了,要怎么办?此时就需要进行补齐操作。

补齐规则:The value of each added byte is the number of bytes that are added, i.e. N bytes, each of value N are added. 

举例:

36 位的 UUID,如果按照 block size=16 字节(即 128 比特),那么就需要补齐到 48 位,差 12 个字节。那么最后填充的 12 个字节的内容,都是字节表示的 0x0c(即 12)。

填充规则


PKCS5Padding=PKCS7Padding

AES 加解密算法

AES 对称加解密算法,是 2000 年在一堆加解密候选算法中,选出了由比利时科学家发明的 Rijndeal 的分组密码算法。在 AES 的规格中,分组长度固定为 128 比特,秘钥长度只有 128,192 和 256 比特三种。

AES 算法,也是需要经过很多轮的加密和解密。每一轮分为

SubBytes

输入分组是 128 比特,即 16 个字节。16 个字节构成一个 4X4 的正方形。对 16 个字节中的每个字节,从替换表(可以认为是一个 key value 的对照表)中找到对应的替换字节


ShiftRows:对行进行移位

MixColumns:对其中一列(4 个字节)进行 bit 运算


AddRoundKey:使用轮秘钥将前三步的输入,进行异或,得到最终结果


这就最终完成了一轮运算

AES 加解密需要计算多少轮:10 到 14 轮

分组模式 CBC

以上的 AES 算法,仅仅描述了,对于一个数据块,如果进行加密解密。然后在真实世界中,数据大小不一,这就需要对原始数据按照固定的块大小(block size)进行分组。ECB 模式的分组强烈不建议使用,所以简单讨论下 CBC 模式

根据图示,在 CBC 模式下,使用 AES 加解密方式进行分组加解密时,需要用到的两个参数

  1. 初始化向量

  2. 加解密秘钥(即前面介绍的轮秘钥)

go 编程

// 补齐算法func PKCSPadding(ciphertext []byte, blockSize int) []byte {	padding := blockSize - len(ciphertext)%blockSize	padtext := bytes.Repeat([]byte{byte(padding)}, padding)	return append(ciphertext, padtext...)}
func PKCSUnPadding(origData []byte) []byte { length := len(origData) unpadding := int(origData[length-1]) return origData[:(length - unpadding)]}
// 注意:本示例中轮秘钥和初始化向量使用相同的字节数据,真实场景不推荐func AesEncryptCBC(origData, key []byte) ([]byte, error) { // AES算法的轮秘钥 key block, err := aes.NewCipher(key) if err != nil { log.Errorf(" encrypt error %v", err) return nil, err }
blockSize := block.BlockSize() origData = PKCSPadding(origData, blockSize) // key[:blockSize]初始化向量 origData = PKCSPadding(origData, blockSize) blockMode := cipher.NewCBCEncrypter(block, key[:blockSize]) crypted := make([]byte, len(origData)) blockMode.CryptBlocks(crypted, origData) log.Infof(" encrypt base64 string %s", base64.StdEncoding.EncodeToString(crypted))
return crypted, nil}
func AesDecryptCBC(crypted, key []byte) ([]byte, error) { block, err := aes.NewCipher(key) if err != nil { log.Errorf(" encrypt error %v", err) return nil, err }
blockSize := block.BlockSize() blockMode := cipher.NewCBCDecrypter(block, key[:blockSize]) origData := make([]byte, len(crypted)) blockMode.CryptBlocks(origData, crypted) origData = PKCSUnPadding(origData) return origData, nil}
复制代码

java 编程

// 注意:本示例中轮秘钥和初始化向量使用相同的字节数据,真实场景不推荐public static byte[] decrypt(byte[] data, byte[] key) {        try {            // 轮秘钥            SecretKey secretKey = new SecretKeySpec(key, "AES");            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");            // 初始化,设置为解密模式,设置初始化向量            cipher.init(Cipher.DECRYPT_MODE, k, new IvParameterSpec(key));            return cipher.doFinal(data);        }catch (Exception e){            e.printStackTrace();        }        return null;    }
复制代码

结论

任何编程语言,原理最重要。不知道原理,只靠拷贝粘贴是没有用的。

发布于: 2021 年 01 月 14 日阅读数: 59
用户头像

kof11321

关注

还未添加个人签名 2018.08.14 加入

还未添加个人简介

评论

发布
暂无评论
AES/CBC/PKCS5Padding到底是什么