【密码学】Padding模式

简介: 在对于数据进行加密的时候,某些加密算法需要明文满足某些长度的要求,比如DES和AES等分组加密需要明文满足是分组的倍数,但是大多数情况下,明文恰好满足需求的概率是非常低的,在之前的实现中,我的实现均没有考虑不满足加密长度的情况,也就是我自己保证了我传入的内容就是满足需求的,本文将聊一聊在不满足的情况下如何进行「Padding」。

密码学番外篇 - Padding模式


M2VOTE1(6CR84~LL~Q4H%2P.jpgPadding模式

在对于数据进行加密的时候,某些加密算法需要明文满足某些长度的要求,比如DES和AES等分组加密需要明文满足是分组的倍数,但是大多数情况下,明文恰好满足需求的概率是非常低的,在之前的实现中,我的实现均没有考虑不满足加密长度的情况,也就是我自己保证了我传入的内容就是满足需求的,本文将聊一聊在不满足的情况下如何进行「Padding」


NoPadding

顾名思义,这个就是不填充,也就是之前我采取的模式,这个要求原始数据必须就是满足分组要求的数据,不满足的时候,无法使用该模式。

GK8LM5QVM}F0Y$HR@UZX_XS.jpg

image.gifNoPadding


PKCS5/PKCS7

填充至符合块大小的整数倍,填充值为填充数量数,PKCS5Padding的块大小应为8个字节,而PKCS7Padding的块大小可以在1~255的范围内。因为AES块的大小恰好为8个字节,因此对于AES的Padding来说,这两种方式是一样的。

LYTFUO7~~)P]A`40(G[}7{H.png

image.gifPKCS5/PKCS7


X923Padding

填充至符合块大小的整数倍,填充值最后一个字节为填充的数量数,其他字节填0

D~_5FRBK2O@A6FX13}R5G_S.png

image.gifX923Padding


ISO10126Padding

填充至符合块大小的整数倍,填充值最后一个字节为填充的数量数,其他字节填充随机字节。

OXWD%%8E%TCC130QTA)_O99.png

image.gifISO10126Padding


ISO7816-4Padding

填充至符合块大小的整数倍,填充值第一个字节为0x80,其他字节填0x00

image.gif$UT7%%QYPUD9@~HDDG]CSFB.png

ISO7816-4Padding


TBCPadding(Trailling-Bit-Compliment)

填充至符合块大小的整数倍,原文最后一位为1时填充0x00,最后一位为0时填充0xFF

QJ@L_2N52I4ET9]M_(E]739.pngTBCPadding


PKCS1Padding

填充格式如下:

Padding = 00 + BT + PS + 00 + D
  • 00为固定字节
  • BT为处理模式
  • PS为填充字节,填充数量为k - 3 - Dk表示密钥长度, D表示原文长度。PS的最小长度为8个字节。填充的值根据BT值来定:
  • BT = 00时,填充全00
  • BT = 01时,填充全FF
  • BT = 02时,随机填充,但不能为00

@)WUMA8B6SA0$V2{K0F946I.png

image.gifPKCS1Padding


总结

上面我只是介绍了几个比较常见的Padding方案,下面来做一个总结,来对比一下这几个Padding方案的区别。

Padding方案 是否记录长度 是否有随机字节的参与
PKCS5/PKCS7
X923Padding
ISO10126Padding
ISO7816-4Padding
TBCPadding
PKCS1Padding


代码实现

这次代码引入了一个package,因为有些padding需要随机数的参与。

// add package: rand = "0.6.3"
use rand::Rng;
use std::iter::repeat;
pub struct Padding {}
impl Padding {
    pub fn no_padding(bytes: &[u8], _block_size: u8) -> Vec<u8> {
        return bytes.to_owned();
    }
    pub fn zero_padding(bytes: &[u8], block_size: u8) -> Vec<u8> {
        let mut padding_length = block_size as usize - bytes.len() % block_size as usize;
        let mut result = bytes.to_owned();
        while padding_length > 0 {
            padding_length -= 1;
            result.push(0x0);
        }
        return result;
    }
    pub fn iso10126_padding(bytes: &[u8], block_size: u8) -> Vec<u8> {
        let mut result = bytes.to_owned();
        let mut rng = rand::thread_rng();
        while (result.len() + 1) % block_size as usize != 0 {
            result.push(rng.gen())
        }
        result.push((result.len() - bytes.len() + 1) as u8);
        return result;
    }
    pub fn iso7816_4padding(bytes: &[u8], block_size: u8) -> Vec<u8> {
        let mut result = bytes.to_owned();
        result.push(0x80);
        while result.len() % block_size as usize != 0 {
            result.push(0x00);
        }
        result
    }
    pub fn pkcs5_padding(bytes: &[u8], block_size: u8) -> Vec<u8> {
        let mut result = bytes.to_owned();
        let padding_length = block_size as usize - bytes.len() % block_size as usize;
        result.extend(repeat(padding_length as u8).take(padding_length));
        return result;
    }
    pub fn x923_padding(bytes: &[u8], block_size: u8) -> Vec<u8> {
        let mut result = bytes.to_owned();
        while (result.len() + 1) % block_size as usize != 0 {
            result.push(0x00);
        }
        result.push((result.len() - bytes.len() + 1) as u8);
        result
    }
    pub fn tbc_padding(bytes: &[u8], block_size: u8) -> Vec<u8> {
        let last_bit = bytes[bytes.len() - 1] & 0x1;
        let mut result = bytes.to_owned();
        let padding_byte = match last_bit != 0 {
            true => 0x00u8,
            false => 0xFFu8,
        };
        while result.len() % block_size as usize != 0 {
            result.push(padding_byte);
        }
        result
    }
    pub fn pkcs1_padding(bytes: &[u8], block_size: u8) -> Vec<u8> {
        // 00 + BT + PS + 00 + D
        let mut result = bytes.to_owned();
        result.push(0x00);
        result.push(0x02);
        let mut padding_length = block_size as usize - 3 - bytes.len();
        let mut rng = rand::thread_rng();
        while padding_length > 0 {
            padding_length -= 1;
            result.push(rng.gen());
        }
        result.push(0x00);
        result.push(bytes.len() as u8);
        return result;
    }
}
#[cfg(test)]
mod test {
    use crate::padding::{Padding};
    #[test]
    fn test_no_padding() {
        let result = Padding::no_padding(&[1, 2, 3, 4], 0);
        assert_eq!(result, vec![1, 2, 3, 4]);
    }
    #[test]
    fn test_zero_padding() {
        let result = Padding::zero_padding(&[1, 2, 3, 4], 16);
        assert_eq!(result, vec![1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
    }
    #[test]
    fn test_iso10126_padding() {
        let result = Padding::iso10126_padding(&[1, 2, 3, 4], 16);
        assert_eq!(result[0..4], [1, 2, 3, 4]);
        assert_eq!(result.last(), Option::Some(&12u8));
    }
    #[test]
    fn test_iso7816_4padding() {
        let result = Padding::iso7816_4padding(&[1, 2, 3, 4], 16);
        assert_eq!(result, [1, 2, 3, 4, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
    }
    #[test]
    fn test_pkcs5_padding() {
        let result = Padding::pkcs5_padding(&[1, 2, 3, 4], 16);
        assert_eq!(result, vec![1, 2, 3, 4, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12])
    }
    #[test]
    fn test_pkcs1_padding() {
        let result = Padding::pkcs1_padding(&[1, 2, 3, 4], 16);
        assert_eq!(result[0..6], vec![1, 2, 3, 4, 0, 2]);
    }
    #[test]
    fn test_x923_padding() {
        let result = Padding::x923_padding(&[1, 2, 3, 4], 16);
        assert_eq!(result, [1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12])
    }
    #[test]
    fn test_tbc_padding() {
        let result = Padding::tbc_padding(&[1, 2, 3, 4], 16);
        assert_eq!(result, [1, 2, 3, 4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]);
        let result = Padding::tbc_padding(&[1, 2, 3, 5], 16);
        assert_eq!(result, [1, 2, 3, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
    }
}

相关文章
|
Rust 算法 安全
【密码学】一文读懂HMAC
本文将来聊一聊基于哈希函数的消息认证码,在此之前,先来科普一下什么是 「消息认证码」 (MAC), 先来看一个简单的栗子
2528 0
【密码学】一文读懂HMAC
|
小程序
微信小程序项目实例——幸运大转盘
微信小程序项目实例——幸运大转盘
|
Rust 算法 网络安全
【密码学】一文读懂CMAC
介于上一篇文章比较水,然后这个和上一篇也比较相似,CMAC是为了解决DAA当中安全性不足的问题而出现的,这个算法一共有三个密钥,K, K1, K2, 其中K1和K2可以由K导出,接下来就来一起看一下CMAC的具体过程吧,这一篇文章其实也不长。
5528 0
【密码学】一文读懂CMAC
|
6月前
|
人工智能 运维 自然语言处理
世优波塔推出轻量级网页SDK方案,15分钟实现大屏AI数字人集成
展厅升级AI数字人,无需漫长改造与高昂成本!世优科技推出波塔AI数字人网页SDK,15分钟极速集成,轻量化部署,支持自定义形象与多场景交互。适配各类大屏,打通数据系统与数字孪生,让智慧展厅迈入“分钟级”时代,每个空间都能拥有专属数字灵魂。
301 1
|
6月前
|
安全 Java 容器
Java的ConcurrentModificationException异常介绍和解决方案
ConcurrentModificationException(CME)是Java中一种快速失败(fail-fast)机制,当线程遍历集合时,若集合结构被修改(如add、remove),则抛出该异常。其原理基于`modCount`与`expectedModCount`的不一致。常见于ArrayList、HashMap等非线程安全集合。解决方法包括:使用Iterator.remove()、CopyOnWriteArrayList、倒序遍历、removeIf()或并发容器如ConcurrentHashMap,以避免并发修改问题。
387 0
|
人工智能 数据可视化 程序员
史上最全盘点:一文告诉你低代码(Low-Code)是什么?为什么要用?
在后疫情时代,低代码(Low-Code)+ 人工智能(AI)的组合被认为是加速社会数字化转型的重要技术。低代码通过可视化和模型驱动的理念,结合云原生和多端体验技术,显著提升了开发效率和灵活性。它不仅让专业开发者受益,还使业务人员成为“平民开发者”,弥补了专业人才缺口。此外,低代码平台能够快速响应市场变化,帮助企业构建各种应用,如四川某制造企业仅用一个月就搭建出一套内部协作和生产监控系统。结合AI的能力,低代码平台还能实现智能化的建议和优化,进一步提升用户体验和开发速度。
|
机器学习/深度学习 DataWorks 安全
CDP是什么?
CDP是什么?
1233 0
|
计算机视觉 Python
Python中Pillow库的常见用法和代码示例
Pillow是Python中广泛使用的图像处理库,支持丰富的图像操作功能,包括但不限于打开、保存、缩放、裁剪、旋转、调色等。本文通过一系列示例介绍Pillow的基本用法,涵盖图像的加载与显示、尺寸调整、裁剪与旋转、亮度调整、格式转换、滤镜应用、图像合成及像素级操作等。首先需通过`pip install pillow`安装库,随后可通过导入`PIL.Image`等模块开始图像处理任务。无论是初学者还是进阶用户,都能从Pillow提供的强大功能中获益。
890 0
|
算法 安全 虚拟化
北美码农面试流程,北美码农面试经验
北美码农面试流程,北美码农面试经验
374 0
|
算法 搜索推荐 安全
【密码学】一文读懂CCM
本文简单介绍了CCM模式下的认证和加密机制,实际上这个是AES-CTR模式和CMAC的一个组合,如果理解了前面这两个,本文应该还是比较好理解的。
4875 0
【密码学】一文读懂CCM