AES/CBC/PKCS7Padding加密算法(C版+Java版)(上)

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介: 笔记

项目中使用到了AES加密算法,因为要保证终端与服务器加密解密算法一致,并且由于终端形式多样,有C开发的,也有Java/Kotlin开发的,所以需要一套支持前后端的多语言算法,保证通信的安全性和完整性。

AES算法原理的相关文章多如牛毛,本文不再叙述。在实际开发和应用中,AES的算法并不一定是完全按照标准应用的,不同开发人员会对算法进行细微的调整。

Java和C语言基本涵盖了大部分的开发场景,本文就两种语言进行了整合,测试,保证数据的一致性,能够实现Java版本算法加密,C语言版本解密,反之亦可。

本文主要叙述在开发中的应用,简要描述原理


一、算法描述


本文中算法是AES/CBC/PKCS7Padding,即AES算法,采用CBC工作模式,补码方式采用PKCS7Padding,什么意思呢?


AES是什么

高级加密标准(Advanced Encryption Standard),属于对称加密,就是说加密和解密的过程算法是相反的。AES由DES算法升级而来。


CBC:密码分组链接模式,AES工作模式之一

AES共有五种工作模式:

  1. 电码本模式(Electronic Codebook Book (ECB));
  2. 密码分组链接模式(Cipher Block Chaining (CBC));
  3. 计算器模式(Counter (CTR));
  4. 密码反馈模式(Cipher FeedBack (CFB));
  5. 输出反馈模式(Output FeedBack (OFB))

CBC工作模式除了密钥KEY,还需要有初始化向量IV,IV与密钥等长。


PKCS7Padding-填充模式

填充的作用是在加密前将普通文本的长度扩展到需要的长度。关键在于填充的数据能够在解密后正确的移除。

AES有以下几种填充模式:

  1. NoPadding--顾名思义,就是不填充。缺点就是只能加密长为128bits倍数的信息,一般不会使用
  2. PKCS#7 & PKCS#5--缺几个字节就填几个缺的字节数。
  3. ZerosPadding--全部填充0x00,无论缺多少全部填充0x00
  4. ISO 10126--最后一个字节是填充的字节数(包括最后一字节),其他全部填随机数
  5. ANSI X9.23--跟ISO 10126很像,只不过ANSI X9.23其他字节填的都是0而不是随机数


二、AES算法原理简述


算法应用模型

1.png

image.png

AES算法过程

AES加密过程涉及到4种操作,分别是字节代换、行移位、列混淆和轮密钥加。解密过程分别为对应的逆操作。由于每一步操作都是可逆的,按照相反的顺序进行解密即可恢复明文。加解密中每轮的密钥分别由初始密钥扩展得到。

AES的明文输入被分为16字节的数组,每个16字节进行加密/解密处理。

下面以加密过程为例详细说明,解密过程按步骤反过来即可。

1、字节代换

代换的规则是什么呢?

明文每个字节的高4位作为行值,低4位作为列值,然后取出S盒中对应行列的元素作为输出。字节替换实际就查表和替换操作,AES定义了S盒(加密用的一张表)和逆S盒(解密时用的另外一张表),在加密/解密时,从S盒中找到要替换的字节放到被替换字节的位置上。

例如下面示例代码:

#include <iostream>
using namespace std;
unsigned char sbox[]={
        0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,  
        0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,
        0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15, 
        0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75, 
        0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84, 
        0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,
        0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,
        0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2, 
        0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,  
        0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,
        0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79, 
        0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08, 
        0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,
        0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e, 
        0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf, 
        0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16,  
};
void PrintMatrix(unsigned char m[4][4])
{
    for(int i=0;i<4;i++)
    {
        for(int j=0;j<4;j++)
        {
            printf("%4x",m[i][j]);
            if(j%4==3)
            puts("");
        }
    }
}
void SubByte(unsigned char state[][4])
{
    for(int i=0;i<4;i++)
    {
        for(int j=0;j<4;j++)
        {
            state[i][j]=sbox[state[i][j]];      //S盒查表操作
        }
    }
}
int main()
{
    unsigned char state[4][4]={
                0,4,8,12,
            1,5,9,13,
            2,6,10,14,
            3,7,11,15,
    };
    printf("明文为:\n");PrintMatrix(state);
    SubByte(state);            //调用SubByte函数
    printf("S盒代换后输出:\n");PrintMatrix(state);
    return 0;
}

运行结果:

输入明文为:
  0 4 8 12
  1 5 9 13
  2 6 10 14
  3 7 11 15
S盒代换后输出:
  63 f2 30 fe
  73 6b 1,d7
  77 6f 67 ab
  7b c5 2b 76

2.行移位变换

行移位变换完成基于行的循环移位操作,变换方法为:第0行不变,第1行循环左移1个字节,第2行循环左移两个字节,第3行循环左移3个字节。


2.png

image.png


示例代码:

#include <iostream>
using namespace std;
void PrintfMatrix(unsigned char m[4][4])      //该函数是输出数组方法
{
    for(int i=0;i<4;i++)
    {
        for(int j=0;j<4;j++)
        {
        printf("%2x",m[i][j]);
        if(j%4==3)
            puts("");
        }
    }
}
void ShiftRow(unsigned char state[4][4])     //行移位变换函数
{
    unsigned char st[4];
    int i,j;
    for(i=1;i<4;i++)
    {
        for(j=0;j<4;j++)
        {
            st[j]=state[i][(j+i)%4];
        }
        for(j=0;j<4;j++)
        {
            state[i][j]=st[j];
        }
    }
}
int main()
{
    unsigned char state[4][4]={
        0,4,8,12,
            1,5,9,13,
            2,6,10,14,
            3,7,11,15,
    };
    printf("明文为:\n");PrintfMatrix(state);
    ShiftRow(state);          //调用行移位函数
        printf("移位后:\n");      
    PrintfMatrix(state);
    return 0;
}

运行结果:


3.png

image.png

3.列混淆变换

在AES算法中,需要模多项式m(x)=x8+x4+x^3+x+1。列混合即是用一个常矩阵乘以第二步变换后的矩阵,以达到矩阵中每一个元素都是该元素原所在列所有元素的加权和

4.png

image.png

计算示例:


5.png

image.png

6.png

image.png

C语言代码实现:

#include <iostream>
using namespace std;
void PrintfMatrix(unsigned char m[4][4])
{
    for(int i=0;i<4;i++)
    {
        for(int j=0;j<4;j++)
        {
        printf("%4x",m[i][j]);
        if(j%4==3)
            puts("");
        }
    }
}
unsigned char xtime(unsigned char st)
{
    return (st<<1)^((st&0x80)?0x1b:0x00);     //x乘法   二进制串左移一位,判断最高位是否溢出,溢出要异或0x1b
}
void mixcolumns(unsigned char state[4][4],unsigned char cipher[4][4])
{
    for(int j=0;j<4;j++)
    {
        for(int i=0;i<4;i++)
        {
            cipher[i][j]=xtime(state[i%4][j])      //0x02乘法
                         ^(state[(i+1)%4][j])^xtime(state[(i+1)%4][j])//0x03乘法
                      ^state[(i+2)%4][j]      //0x01乘法
                                          // ^state[(i+2)%4][j];     //0x01乘法   这句写错了,so结果不对,应该是i+3
                       ^state[(i+3)%4][j];     //0x01乘法
        }
    }
}
int main()
{
    unsigned char state[4][4]={
        /*0,4,8,12,
           1,5,9,13,
           2,6,10,14,
           3,7,11,15,*/
        0x87,0xF2,0x4D,0x97,
           0x6E,0x4C,0x90,0xEC,
            0x46,0xE7,0x4A,0xC3,
            0xA6,0x8C,0xD8,0x95,
    };
    unsigned char cipher[4][4]; 
    printf("明文为:\n");PrintfMatrix(state);
    mixcolumns(state,cipher);
    printf("列混合结果:\n");PrintfMatrix(cipher);
    return 0;
}

运行结果:


7.png

                                      image.png

根据矩阵的乘法可知,在列混淆(利用域GF(28)上的算术特性的一个代替)的过程中,每个字节对应的值只与该列的4个值有关系。此处的乘法和加法需要注意如下几点:

  • (1)将某个字节所对应的值乘以2,其结果就是将该值的二进制位左移一位,如果该值的最高位为1(表示该数值不小于128),则还需要将移位后的结果异或00011011
  • (2)乘法对加法满足分配率,例如:07·S0,0=(01⊕02⊕04)·S0,0= S0,0⊕(02·S0,0)(04·S0,0)
  • (3)此处的矩阵乘法与一般意义上矩阵的乘法有所不同,各个值在相加时使用的是模2加法(异或运算)。
    因为:说明两个矩阵互逆,经过一次逆向列混淆后即可恢复原文。
    如下图:
    8.png
                                               image.png

4.轮密钥加

轮密钥加:加密过程中,每轮的输入与轮密钥异或一次(当前分组和扩展密钥的一部分进行按位异或);因为二进制数连续异或一个数结果是不变的,所以在解密时再异或上该轮的密钥即可恢复输入。首尾使用轮密钥加的理由:若将其他不需要密钥的阶段放在首尾,在不用密钥的情况下就能完成逆过程,这就降低了算法的安全性。

加密原理:轮密钥加本身不难被破解,另外三个阶段分别提供了混淆和非线性功能。可是字节替换、行移位、列混淆阶段没有涉及密钥,就它们自身而言,并没有提供算法的安全性。但该算法经历一个分组的异或加密(轮密钥加),再对该分组混淆扩散(其他三个阶段),再接着又是异或加密,如此交替进行,这种方式非常有效非常安全。

算法动画演示

在线演示

波士顿大学Howard Straubing AES动画演示

云盘下载链接

提取码:sqpe


目录
相关文章
|
2月前
|
存储 算法 安全
探究‘公司禁用 U 盘’背后的哈希表算法与 Java 实现
在数字化办公时代,信息安全至关重要。许多公司采取“禁用U盘”策略,利用哈希表算法高效管理外接设备的接入权限。哈希表通过哈希函数将设备标识映射到数组索引,快速判断U盘是否授权。例如,公司预先将允许的U盘标识存入哈希表,新设备接入时迅速验证,未授权则禁止传输并报警。这有效防止恶意软件和数据泄露,保障企业信息安全。 代码示例展示了如何用Java实现简单的哈希表,模拟公司U盘管控场景。哈希表不仅用于设备管理,还在文件索引、用户权限等多方面助力信息安全防线的构建,为企业数字化进程保驾护航。
|
3月前
|
监控 算法 网络协议
Java 实现局域网电脑屏幕监控算法揭秘
在数字化办公环境中,局域网电脑屏幕监控至关重要。本文介绍用Java实现这一功能的算法,涵盖图像采集、数据传输和监控端显示三个关键环节。通过Java的AWT/Swing库和Robot类抓取屏幕图像,使用Socket进行TCP/IP通信传输图像数据,并利用ImageIO类在监控端展示图像。整个过程确保高效、实时和准确,为提升数字化管理提供了技术基础。
95 15
|
5月前
|
存储 人工智能 算法
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
这篇文章详细介绍了Dijkstra和Floyd算法,这两种算法分别用于解决单源和多源最短路径问题,并且提供了Java语言的实现代码。
135 3
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
|
1月前
|
存储 缓存 Java
java语言后台管理ruoyi后台管理框架-登录提示“无效的会话,或者会话已过期,请重新登录。”-扩展知识数据库中密码加密的方法-问题如何解决-以及如何重置若依后台管理框架admin密码-优雅草卓伊凡
java语言后台管理ruoyi后台管理框架-登录提示“无效的会话,或者会话已过期,请重新登录。”-扩展知识数据库中密码加密的方法-问题如何解决-以及如何重置若依后台管理框架admin密码-优雅草卓伊凡
97 3
java语言后台管理ruoyi后台管理框架-登录提示“无效的会话,或者会话已过期,请重新登录。”-扩展知识数据库中密码加密的方法-问题如何解决-以及如何重置若依后台管理框架admin密码-优雅草卓伊凡
|
1月前
|
存储 算法 Java
解锁“分享文件”高效密码:探秘 Java 二叉搜索树算法
在信息爆炸的时代,文件分享至关重要。二叉搜索树(BST)以其高效的查找性能,为文件分享优化提供了新路径。本文聚焦Java环境下BST的应用,介绍其基础结构、实现示例及进阶优化。BST通过有序节点快速定位文件,结合自平衡树、多线程和权限管理,大幅提升文件分享效率与安全性。代码示例展示了文件插入与查找的基本操作,适用于大规模并发场景,确保分享过程流畅高效。掌握BST算法,助力文件分享创新发展。
|
2月前
|
存储 人工智能 算法
解锁分布式文件分享的 Java 一致性哈希算法密码
在数字化时代,文件分享成为信息传播与协同办公的关键环节。本文深入探讨基于Java的一致性哈希算法,该算法通过引入虚拟节点和环形哈希空间,解决了传统哈希算法在分布式存储中的“哈希雪崩”问题,确保文件分配稳定高效。文章还展示了Java实现代码,并展望了其在未来文件分享技术中的应用前景,如结合AI优化节点布局和区块链增强数据安全。
|
2月前
|
算法 安全 Java
Java线程调度揭秘:从算法到策略,让你面试稳赢!
在社招面试中,关于线程调度和同步的相关问题常常让人感到棘手。今天,我们将深入解析Java中的线程调度算法、调度策略,探讨线程调度器、时间分片的工作原理,并带你了解常见的线程同步方法。让我们一起破解这些面试难题,提升你的Java并发编程技能!
98 16
|
2月前
|
运维 监控 算法
企业局域网监控软件中 Java 优先队列算法的核心优势
企业局域网监控软件是数字化时代企业网络安全与高效运营的基石,犹如一位洞察秋毫的卫士。通过Java实现的优先队列算法,它能依据事件优先级排序,确保关键网络事件如异常流量、数据泄露等被优先处理,保障系统稳定与安全。代码示例展示了如何定义网络事件类并使用PriorityQueue处理高优先级事件,尤其在面对疑似风险时迅速启动应急措施。这一核心技术助力企业在复杂网络环境中稳健前行,护航业务腾飞。
69 32
|
2月前
|
存储 监控 算法
剖析基于Java算法驱动的智能局域网管控之道
本文探讨了基于Java语言的局域网控制方案,结合链表数据结构与令牌桶算法,解决设备管理和流量调度难题。通过链表灵活存储网络设备信息,实现高效设备管理;令牌桶算法则精准控制流量,确保网络平稳运行。二者相辅相成,为校园、企业等局域网提供稳固高效的控制体系,保障业务连续性和数据安全。
|
2月前
|
算法 搜索推荐 Java
【潜意识Java】深度解析黑马项目《苍穹外卖》与蓝桥杯算法的结合问题
本文探讨了如何将算法学习与实际项目相结合,以提升编程竞赛中的解题能力。通过《苍穹外卖》项目,介绍了订单配送路径规划(基于动态规划解决旅行商问题)和商品推荐系统(基于贪心算法)。这些实例不仅展示了算法在实际业务中的应用,还帮助读者更好地准备蓝桥杯等编程竞赛。结合具体代码实现和解析,文章详细说明了如何运用算法优化项目功能,提高解决问题的能力。
84 6

热门文章

最新文章