文章目录
最近密码学学到了分组密码体制。本文主要分享了AES算法的基础知识和C语言的简单实现。
AES是分组密码,安全性良好。
与3DES比较:比3DES快、至少和3DES一样安全。
AES分组长度:128 bit
密钥长度:128/192/256 bit
对应的加密轮数:10/12/14 轮
【本文是以分组长度128bit,密钥长度128bit 为例】
AES加解密流程图:

以密钥长度128bit(10轮变换)为例
文字描述如下:
准备:明文plaintext [16]
初始密钥和 10 个扩展密钥 函数:密钥扩展函数 KeyExpansion()
一:初始变换。
轮密钥加 函数:AddRoundKey()
二:9轮循环
1.S盒字节代换 函数:SubBytes() InvSubBytes()
2.行移位 函数:ShiftRows() InvShiftRows()
3.列混合 函数: MixColumns() InvMixColumns()
字节乘法 函数:Mul()
4.轮密钥加 函数:AddRoundKey()
三:最终轮
1.S盒字节代换 函数:SubBytes() InvSubBytes()
2.行移位 函数:ShiftRows() InvShiftRows()
3.轮密钥加 函数:AddRoundKey()
AES解密算法顺序 从下往上,当然使用密钥顺序也是反的 。
AES加解密优化版流程图:

两个流程图找找不同?
原因:
补充:

密钥编排功能:首先初始条件里面应该有一个128bit(16个字母) 的初始密钥Key[16],由于AES有10轮变换,所以需要由初始密钥扩展出10轮密钥,分别进行每一轮变换。
结果:最终得到 扩展秘钥矩阵 k[11][16],其中k[0][16]就是初始密钥Key[16]。
过程:从初始密钥开始,矩阵按列展开,根据1个字分wi
对wi的操作:
从上图可以看出当 i=4 的倍数 时,wi对应矩阵k[i]的下标为{0,1,2 ,3}。
下面以计算 w4一列中第一个数 为例来具体阐述 i=4的倍数 时的变换,信息如图:

w[4]=w[0]⊕ T[3]
T[3]: 对w[3]变换
①字循环(左移): (n p q m) 对应下标 {13,14,15,12}
②字节代换(S盒) : (n p q m)
③轮常量异或RC ^( 0x01 0 0 0)
代码编写需与k[11][16]矩阵联系起来:

代码如下:
void KeyExpansion(unsigned char K[16],unsigned char k[11][16])
{
unsigned char RC[10];
RC[0]=1;
int i;
for(i=1;i<10;i++)
RC[i]=Mul(0x02,RC[i-1]);
for(i=0;i<16;i++)
k[0][i]=K[i];
for(i=1;i<11;i++)
{
k[i][0]=k[i-1][0]^S[k[i-1][13]]^RC[i-1];
k[i][1]=k[i-1][1]^S[k[i-1][14]];
k[i][2]=k[i-1][2]^S[k[i-1][15]];
k[i][3]=k[i-1][3]^S[k[i-1][12]];
k[i][4]=k[i-1][4]^k[i][0];
k[i][5]=k[i-1][5]^k[i][1];
k[i][6]=k[i-1][6]^k[i][2];
k[i][7]=k[i-1][7]^k[i][3];
k[i][8]=k[i-1][8]^k[i][4];
k[i][9]=k[i-1][9]^k[i][5];
k[i][10]=k[i-1][10]^k[i][6];
k[i][11]=k[i-1][11]^k[i][7];
k[i][12]=k[i-1][12]^k[i][8];
k[i][13]=k[i-1][13]^k[i][9];
k[i][14]=k[i-1][14]^k[i][10];
k[i][15]=k[i-1][15]^k[i][11];
}
}
解释:就是进行异或操作

密钥加运算的逆运算是自己。
void AddRoundKey( unsigned char *a , unsigned char *Key ) { // 轮密钥加
for( int i = 0 ; i < 16 ; i ++ )
a[i] ^= Key[i] ;
}
性质:关于字节的非线性变换
利用:代换表(即S盒)。AES有S盒和逆S盒。
解释:在矩阵中,根据当前字符的下标,去找S盒中对应的字符,并进行替换。

S盒参数:
unsigned char S[256] = { // S盒
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
};
unsigned char IS[256] = { // S盒的逆
0x52,0x09,0x6a,0xd5,0x30,0x36,0xa5,0x38,0xbf,0x40,0xa3,0x9e,0x81,0xf3,0xd7,0xfb,
0x7c,0xe3,0x39,0x82,0x9b,0x2f,0xff,0x87,0x34,0x8e,0x43,0x44,0xc4,0xde,0xe9,0xcb,
0x54,0x7b,0x94,0x32,0xa6,0xc2,0x23,0x3d,0xee,0x4c,0x95,0x0b,0x42,0xfa,0xc3,0x4e,
0x08,0x2e,0xa1,0x66,0x28,0xd9,0x24,0xb2,0x76,0x5b,0xa2,0x49,0x6d,0x8b,0xd1,0x25,
0x72,0xf8,0xf6,0x64,0x86,0x68,0x98,0x16,0xd4,0xa4,0x5c,0xcc,0x5d,0x65,0xb6,0x92,
0x6c,0x70,0x48,0x50,0xfd,0xed,0xb9,0xda,0x5e,0x15,0x46,0x57,0xa7,0x8d,0x9d,0x84,
0x90,0xd8,0xab,0x00,0x8c,0xbc,0xd3,0x0a,0xf7,0xe4,0x58,0x05,0xb8,0xb3,0x45,0x06,
0xd0,0x2c,0x1e,0x8f,0xca,0x3f,0x0f,0x02,0xc1,0xaf,0xbd,0x03,0x01,0x13,0x8a,0x6b,
0x3a,0x91,0x11,0x41,0x4f,0x67,0xdc,0xea,0x97,0xf2,0xcf,0xce,0xf0,0xb4,0xe6,0x73,
0x96,0xac,0x74,0x22,0xe7,0xad,0x35,0x85,0xe2,0xf9,0x37,0xe8,0x1c,0x75,0xdf,0x6e,
0x47,0xf1,0x1a,0x71,0x1d,0x29,0xc5,0x89,0x6f,0xb7,0x62,0x0e,0xaa,0x18,0xbe,0x1b,
0xfc,0x56,0x3e,0x4b,0xc6,0xd2,0x79,0x20,0x9a,0xdb,0xc0,0xfe,0x78,0xcd,0x5a,0xf4,
0x1f,0xdd,0xa8,0x33,0x88,0x07,0xc7,0x31,0xb1,0x12,0x10,0x59,0x27,0x80,0xec,0x5f,
0x60,0x51,0x7f,0xa9,0x19,0xb5,0x4a,0x0d,0x2d,0xe5,0x7a,0x9f,0x93,0xc9,0x9c,0xef,
0xa0,0xe0,0x3b,0x4d,0xae,0x2a,0xf5,0xb0,0xc8,0xeb,0xbb,0x3c,0x83,0x53,0x99,0x61,
0x17,0x2b,0x04,0x7e,0xba,0x77,0xd6,0x26,0xe1,0x69,0x14,0x63,0x55,0x21,0x0c,0x7d
};
代码如下:
void SubBytes( unsigned char *input ) { // S盒字节代换
for( int i = 0 ; i < 16 ; i ++ )
input[i] = S[input[i]] ;
}
void InvSubBytes( unsigned char *input ) { // S盒字节代换逆变换
for( int i = 0 ; i < 16 ; i ++ )
input[i] = IS[input[i]] ;
}
解释:在分组长度为128bit的情况下,第0行不动,第一行循环左移1个字节,第二行循环左移2个字节,第三行循环左移3个字节
注意:不同分组长度的位移量不同。
行移位前提:根据AES分组的特点,首先要将原矩阵按列展开。搞清楚行列关系。下图给出了对应的下标,有助于理解代码。

代码如下:
void ShiftRows( unsigned char *a ) { // 行移位—矩阵按列展开
unsigned char b[16] ;
b[ 0] = a[ 0] ; b[ 4] = a[ 4] ; b[ 8] = a[ 8] ; b[12] = a[12] ;
b[ 1] = a[ 5] ; b[ 5] = a[ 9] ; b[ 9] = a[13] ; b[13] = a[ 1] ;
b[ 2] = a[10] ; b[ 6] = a[14] ; b[10] = a[ 2] ; b[14] = a[ 6] ;
b[ 3] = a[15] ; b[ 7] = a[ 3] ; b[11] = a[ 7] ; b[15] = a[11] ;
for( int i = 0 ; i < 16 ; i ++ )
a[i] = b[i] ;
}
void InvShiftRows( unsigned char *a ) { // 行移位逆变换
unsigned char b[16] ;
b[ 0] = a[ 0] ; b[ 4] = a[ 4] ; b[ 8] = a[ 8] ; b[12] = a[12] ;
b[ 1] = a[13] ; b[ 5] = a[ 1] ; b[ 9] = a[ 5] ; b[13] = a[ 9] ;
b[ 2] = a[10] ; b[ 6] = a[14] ; b[10] = a[ 2] ; b[14] = a[ 6] ;
b[ 3] = a[ 7] ; b[ 7] = a[11] ; b[11] = a[15] ; b[15] = a[ 3] ;
for( int i = 0 ; i < 16 ; i ++ )
a[i] = b[i] ;
}
解释:原矩阵与一个固定矩阵的乘法

(1)固定矩阵c(x) (也是16进制):

(02 03 01 01)(0E 0B 0D 09)(2)运算:乘法运算
矩阵乘法
概括:字节乘法 和 异或操作

字节乘法
x乘法:

解释:
M–左移一位(最低位为0)–>N
If :0bM(M的二进制形式)的最高位为0,N为原值
Else:0bM的最高位为1,N⊕00011011
字节乘法举例:
计算: 57 * 83 = ? (两个16进制数相乘:0x57*0x83)

字节乘法实现代码如下:
unsigned char Mul(unsigned char a, unsigned char b)
{
unsigned char i;
unsigned char temp;
unsigned char result[8];
unsigned char sum=0;
result[0] = a;
for(i=1;i<8;i++) //x乘法
{
temp=result[i-1]; //>>右移,<<左移,^异或 ,&与操作(同1为1)
temp=temp>>7; //temp为最高位,判断 最高位 是0还是1
if(temp==1)
{
result[i]=result[i-1]<<1^0x1b; // 0x1b=0b 00011011
}
else
{
result[i]=result[i-1]<<1;
}
}
for(i=0;i<8;i++){ //左移之后补零
temp=b<<i&0x80; //判断 b二进制的哪几位为1
if(temp==0x80)
{
sum^=result[7-i];
}
}
return sum;
}
列混合代码如下:
// 列混合
void MixColumns( unsigned char *a ) {
unsigned char b[16] ;
b[ 0] = Mul(0x02,a[0]) ^ Mul(0x03,a[1]) ^ a[2] ^ a[3];
b[ 1] = Mul(0x02,a[1]) ^ Mul(0x03,a[2]) ^ a[3] ^ a[0];
b[ 2] = Mul(0x02,a[2]) ^ Mul(0x03,a[3]) ^ a[0] ^ a[1];
b[ 3] = Mul(0x02,a[3]) ^ Mul(0x03,a[0]) ^ a[1] ^ a[2];
b[ 4] = Mul(0x02,a[4]) ^ Mul(0x03,a[5]) ^ a[6] ^ a[7];
b[ 5] = Mul(0x02,a[5]) ^ Mul(0x03,a[6]) ^ a[7] ^ a[4];
b[ 6] = Mul(0x02,a[6]) ^ Mul(0x03,a[7]) ^ a[4] ^ a[5];
b[ 7] = Mul(0x02,a[7]) ^ Mul(0x03,a[4]) ^ a[5] ^ a[6];
b[ 8] = Mul(0x02,a[8]) ^ Mul(0x03,a[9]) ^ a[10] ^ a[11];
b[ 9] = Mul(0x02,a[9]) ^ Mul(0x03,a[10]) ^ a[11] ^ a[8];
b[10] = Mul(0x02,a[10]) ^ Mul(0x03,a[11]) ^ a[8] ^ a[9];
b[11] = Mul(0x02,a[11]) ^ Mul(0x03,a[8]) ^ a[9] ^ a[10];
b[12] = Mul(0x02,a[12]) ^ Mul(0x03,a[13]) ^ a[14] ^ a[15];
b[13] = Mul(0x02,a[13]) ^ Mul(0x03,a[14]) ^ a[15] ^ a[12];
b[14] = Mul(0x02,a[14]) ^ Mul(0x03,a[15]) ^ a[12] ^ a[13];
b[15] = Mul(0x02,a[15]) ^ Mul(0x03,a[12]) ^ a[13] ^ a[14];
for( int i = 0 ; i < 16 ; i ++ )
a[i] = b[i] ;
}
//列混合的逆
void InvMixColumns(unsigned char *a)
{
unsigned char b[16];
b[0] = Mul(0x0E, a[0]) ^ Mul(0x0B, a[1]) ^ Mul(0x0D, a[2]) ^ Mul(0x09, a[3]);
b[1] = Mul(0x0E, a[1]) ^ Mul(0x0B, a[2]) ^ Mul(0x0D, a[3]) ^ Mul(0x09, a[0]);
b[2] = Mul(0x0E, a[2]) ^ Mul(0x0B, a[3]) ^ Mul(0x0D, a[0]) ^ Mul(0x09, a[1]);
b[3] = Mul(0x0E, a[3]) ^ Mul(0x0B, a[0]) ^ Mul(0x0D, a[1]) ^ Mul(0x09, a[2]);
b[4] = Mul(0x0E, a[4]) ^ Mul(0x0B, a[5]) ^ Mul(0x0D, a[6]) ^ Mul(0x09, a[7]);
b[5] = Mul(0x0E, a[5]) ^ Mul(0x0B, a[6]) ^ Mul(0x0D, a[7]) ^ Mul(0x09, a[4]);
b[6] = Mul(0x0E, a[6]) ^ Mul(0x0B, a[7]) ^ Mul(0x0D, a[4]) ^ Mul(0x09, a[5]);
b[7] = Mul(0x0E, a[7]) ^ Mul(0x0B, a[4]) ^ Mul(0x0D, a[5]) ^ Mul(0x09, a[6]);
b[8] = Mul(0x0E, a[8]) ^ Mul(0x0B, a[9]) ^ Mul(0x0D, a[10]) ^ Mul(0x09, a[11]);
b[9] = Mul(0x0E, a[9]) ^ Mul(0x0B, a[10]) ^ Mul(0x0D, a[11]) ^ Mul(0x09, a[8]);
b[10] = Mul(0x0E, a[10]) ^ Mul(0x0B, a[11]) ^ Mul(0x0D, a[8]) ^ Mul(0x09, a[9]);
b[11] = Mul(0x0E, a[11]) ^ Mul(0x0B, a[8]) ^ Mul(0x0D, a[9]) ^ Mul(0x09, a[10]);
b[12] = Mul(0x0E, a[12]) ^ Mul(0x0B, a[13]) ^ Mul(0x0D, a[14]) ^ Mul(0x09, a[15]);
b[13] = Mul(0x0E, a[13]) ^ Mul(0x0B, a[14]) ^ Mul(0x0D, a[15]) ^ Mul(0x09, a[12]);
b[14] = Mul(0x0E, a[14]) ^ Mul(0x0B, a[15]) ^ Mul(0x0D, a[12]) ^ Mul(0x09, a[13]);
b[15] = Mul(0x0E, a[15]) ^ Mul(0x0B, a[12]) ^ Mul(0x0D, a[13]) ^ Mul(0x09, a[14]);
for (int i = 0; i < 16; i++)
a[i] = b[i];
}
上文提到了AES加解密顺序,具体代码如下:
//AES算法加密函数
void AES(unsigned char plaintext[16], unsigned char ciphertext[16], unsigned char k[11][16],int Round)
{
int i,round;
for(i=0;i<16;i++){
ciphertext[i]=plaintext[i];} //此处注意代码思想
AddRoundKey(ciphertext,k[0]);
for(round=1;round<Round;round++){
SubBytes(ciphertext);
ShiftRows(ciphertext);
MixColumns(ciphertext);
AddRoundKey(ciphertext,k[round]);
}
SubBytes(ciphertext);
ShiftRows(ciphertext);
AddRoundKey(ciphertext,k[Round]);
}
//AES解密常规模式
void RAES(unsigned char plaintext[16], unsigned char ciphertext[16], unsigned char k[11][16], int Round)
{
int i,round;
for(i=0;i<16;i++){
plaintext[i]=ciphertext[i];}
AddRoundKey(plaintext,k[Round]);
InvShiftRows(plaintext);
InvSubBytes(plaintext);
for(round=9;round>0;round--){
AddRoundKey(plaintext,k[round]);
InvMixColumns(plaintext);
InvShiftRows(plaintext);
InvSubBytes(plaintext);
}
AddRoundKey(plaintext,k[0]);
}
另外给出主函数:
int main()
{
int i;
unsigned char k[11][16]; //扩展秘钥
unsigned char ciphertext[16]; //密文
unsigned char plaintext[16]={
0x01,0x23,0x45,0x67, // 明文
0x89,0xab,0xcd,0xef,
0x01,0x23,0x45,0x67,
0x89,0xab,0xcd,0xef
};
unsigned char Key[16]={
0x01,0x23,0x45,0x67, // 初始密钥
0x89,0xab,0xcd,0xef,
0x01,0x23,0x45,0x67,
0x89,0xab,0xcd,0xef
};
printf("明文为:\n");
for(i=0;i<16;i++){
printf("%02x ",plaintext[i]);} //明文
printf("\n");
KeyExpansion(Key,k);
//加密
AES(plaintext,ciphertext,k,10);
printf("加密后的密文为:\n");
for(i=0;i<16;i++){
printf("%02x ",ciphertext[i]);
}
printf("\n");
//解密
RAES(plaintext,ciphertext,k,10);
printf("解密后的明文为:\n");
for(i=0;i<16;i++){
printf("%02x ",plaintext[i]);
}
printf("\n");
return 0;
}
纵观全文,本文主要还是介绍了AES的一些基础的东西,介绍了AES算法流程,详细介绍了主要函数的原理,并给出了代码参考。
完整代码参考请见:AES加解密(C语言优化版)
AES算法内容比较复杂,但是安全性较高,还有很多算法可以优化AES算法并提高AES的运行效率。如果还需要用到AES,我还会再进行下一步的学习。
感谢评论区伙伴们的反馈,部分错误已经修改~
参考资料:
https://www.sohu.com/a/201169795_466846
http://www.uooc.net.cn/course/2117859688?cycleid=1216670014
https://blog.csdn.net/gulang03/article/details/81175854
我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚
我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden
有没有办法在这个简单的get方法中添加超时选项?我正在使用法拉第3.3。Faraday.get(url)四处寻找,我只能先发起连接后应用超时选项,然后应用超时选项。或者有什么简单的方法?这就是我现在正在做的:conn=Faraday.newresponse=conn.getdo|req|req.urlurlreq.options.timeout=2#2secondsend 最佳答案 试试这个:conn=Faraday.newdo|conn|conn.options.timeout=20endresponse=conn.get(url
几个月前,我读了一篇关于rubygem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:
我想在Ruby中创建一个用于开发目的的极其简单的Web服务器(不,不想使用现成的解决方案)。代码如下:#!/usr/bin/rubyrequire'socket'server=TCPServer.new('127.0.0.1',8080)whileconnection=server.acceptheaders=[]length=0whileline=connection.getsheaders想法是从命令行运行这个脚本,提供另一个脚本,它将在其标准输入上获取请求,并在其标准输出上返回完整的响应。到目前为止一切顺利,但事实证明这真的很脆弱,因为它在第二个请求上中断并出现错误:/usr/b
我意识到这可能是一个非常基本的问题,但我现在已经花了几天时间回过头来解决这个问题,但出于某种原因,Google就是没有帮助我。(我认为部分问题在于我是一个初学者,我不知道该问什么......)我也看过O'Reilly的RubyCookbook和RailsAPI,但我仍然停留在这个问题上.我找到了一些关于多态关系的信息,但它似乎不是我需要的(尽管如果我错了请告诉我)。我正在尝试调整MichaelHartl'stutorial创建一个包含用户、文章和评论的博客应用程序(不使用脚手架)。我希望评论既属于用户又属于文章。我的主要问题是:我不知道如何将当前文章的ID放入评论Controller。
我的工作要求我为某些测试自动生成电子邮件。我一直在四处寻找,但未能找到可以快速实现的合理解决方案。它需要在outlook而不是其他邮件服务器中,因为我们有一些奇怪的身份验证规则,我们需要保存草稿而不是仅仅发送邮件的选项。显然win32ole可以做到这一点,但我找不到任何相当简单的例子。 最佳答案 假设存储了Outlook凭据并且您设置为自动登录到Outlook,WIN32OLE可以很好地完成此操作:require'win32ole'outlook=WIN32OLE.new('Outlook.Application')message=
目录一.加解密算法数字签名对称加密DES(DataEncryptionStandard)3DES(TripleDES)AES(AdvancedEncryptionStandard)RSA加密法DSA(DigitalSignatureAlgorithm)ECC(EllipticCurvesCryptography)非对称加密签名与加密过程非对称加密的应用对称加密与非对称加密的结合二.数字证书图解一.加解密算法加密简单而言就是通过一种算法将明文信息转换成密文信息,信息的的接收方能够通过密钥对密文信息进行解密获得明文信息的过程。根据加解密的密钥是否相同,算法可以分为对称加密、非对称加密、对称加密和非
华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o
?博客主页:https://xiaoy.blog.csdn.net?本文由呆呆敲代码的小Y原创,首发于CSDN??学习专栏推荐:Unity系统学习专栏?游戏制作专栏推荐:游戏制作?Unity实战100例专栏推荐:Unity实战100例教程?欢迎点赞?收藏⭐留言?如有错误敬请指正!?未来很长,值得我们全力奔赴更美好的生活✨------------------❤️分割线❤️-------------------------