AES,密码学中的高级加密标准(Advanced Encryption Standard,AES),又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。经过五年的甄选流程,高级加密标准由美国国家标准与技术研究院(NIST)于20##年11月26日发布于FIPS PUB 197,并在20##年5月26日成为有效的标准。20##年,高级加密标准已然成为对称密钥加密中最流行的算法之一。AES 有一个固定的128位的块大小和128,192或256位大小的密钥大小。Rijndael算法汇聚了安全性、效率高、易实现性和灵活性等优点,是一种较DES更好的算法。
该算法为比利时密码学家Joan Daemen和Vincent Rijmen所设计,结合两位作者的名字,以Rijndael之命名之,投稿高级加密标准的甄选流程。(Rijdael的发音近于 "Rhine doll"。)AES在软体及硬件上都能快速地加解密,相对来说较易于实作,且只需要很少的记忆体。作为一个新的加密标准,目前正被部署应用到更广大的范围.
①抵抗所有已知的攻击。
②在多个平台上速度快,编码紧凑。
③设计简单。
Ø 当前的大多数分组密码,其轮函数是Feistel结构。
Ø Rijndael没有这种结构。
Ø Rijndael轮函数是由3个不同的可逆均匀变换
n 分组和密钥长度可变,各自可独立指定为128、192、256比特。
n 状态
n 算法中间的结果也需要分组,称之为状态,状态可以用以字节为元素的矩阵阵列表示,该阵列有4行,列数Nb为分组长度除32
n 种子密钥
n 以字节为元素的矩阵阵列描述,阵列为4行,列数Nk为密钥长度除32
基本要求部分:
1. 在深入理解AES加密/解密算法理论的基础上,设计一个AES加密/解密软件系统;
主要功能模块如下:
非线性代换是可逆的,由以下两个变换的合成得到:
① 首先,将字节看作GF(28)上的元素,映射到自己的乘法逆元,‘00’映射到自己。
② 其次,对字节做如下仿射变换:
图 1 字节代换示意图
将状态阵列的各行进行循环移位,移位量与分组长度的关系
0行:不动
图2 行移位示意图
图3 列混合示意图
状态阵列的每个列a(x)与一个固定的多项式c(x)进行模x4+1乘法后混淆为b(x).记为
c(x)是模x4+1可逆的多项式‘03’x3+‘01’x2+‘01’x+‘02’
逆d(x)=‘0B’x3+‘0D’x2+‘09’x+‘0E’
图4 轮密钥加示意图
密钥加:轮密钥与状态进行逐比特异或。轮密钥长度等于分组长度Nb。
密钥加运算的逆运算是其自身。
通过逆S盒的映射变换得到
图5 逆行移位示意图
与加密时的行移位区别在于移位方向相反。
图6 逆列混合示意图
加密与解密系统流程图如下所示,
3.AES算法java实现
3.1 代码见附录1
3.2测试结果:
RC4
RC4加密算法是大名鼎鼎的RSA三人组中的头号人物Ronald Rivest在1987年设计的密钥长度可变的流加密算法簇。之所以称其为簇,是由于其核心部分的S-box长度可为任意,但一般为256字节。该算法的速度可以达到DES加密的10倍左右,且具有很高级别的非线性。RC4起初是用于保护商业机密的。但是在1994年9月,它的算法被发布在互联网上,也就不再有什么商业机密了。RC4也被叫做ARC4
基本要求部分:
分析RC4的实现过程。
用程序设计语言将算法过程编程实现。
完成字符串数据的加密运算和解密运算
主要功能模块如下:
RC4算法的原理很简单,包括初始化算法(KSA)和伪随机子密码生成算法(PRGA)两大部分。
3.RC4算法java实现
2.1 代码见附录2
2.2测试结果:
[问题讨论]
1. 改变明文或密钥中的一个比特值可能影响AES值中的多少比特?
答:明文和密钥在S盒置换时,不同的字节会替换出不同的结果。算法过程 中一共进行了10轮加密,所以改变一个比特值可能影响AES值中的80比特(8 x 10)。
2. 在RC4的密钥流生成中,改变初始密钥的一个比特值可能影响输出中的多少比特?
答:初始密钥的不同会导致S盒的不同,所以可能影响输出中的256比特。
3. 分析实验中在编辑编译运行等各环节中所出现的问题及解决方法。
答:在算法的实现过程中,对于异或等平时很难接触到的位操作不熟悉导致在轮密钥加密等过程的实现变得很艰难,并且使用java这种面向对象的高级语言来处理数据从速度上就会慢很多。最难处理的是字符串对的补足长度问题,这个问题在设计之初并没有想到过导致最后测试时出现了很多问题,最后通过查阅资料等方式解决了这些问题。
SKEY
1.SKEY协议的作用
身份认证,是任何网络安全方案的一个基础。如在大部分情况下,需要认证的实体是通信的发送者,即需要确定访问者的合法性问题。 S/KEY协议主要是用于身份认证。
2.SKEY协议的安全性分析。
S/KEY身份认证解决方案,可以有效解决重放攻击。重放攻击是指攻击者通过某种方式在网络连接中获取他人的登陆账户与口令,然后利用它多某个网络资源的访问权限。而现在S/Key协议分配给访问者的口令每次都不同,所以,就可以有效解决口令泄漏问题。因此,可以避免重放攻击。
3.SKEY协议的实现过程。
3.1实现过程分析:
为了实现起来简单明了一些,我采用了一个比较简单的方式进行。要模拟客户端保存数据比较不容易实现,对服务器生成的hash值,保存在本地文件中,当然这个hash的值是动态的,每次hash都会加上相应的登陆次数(这个hash方式和一般的s/key协议有些不同),这样可以动态的获取。通过文件读写的方式获得。对于生成的hash值从100到0次访问的问题也是使用一个文件来储存,每次验证完成后,都会把前一次存的数据减1然后重新的写入文件中。
为了模拟登陆过程,我用到了两个文件client.txt,sever.txt分别模拟客户端和服务器端,分别存储客户端和服务器端密钥
3.1实现过程流程图:
4.SKEY协议的java实现
4.1 Java实现
代码见附录三
4.2实现结果:
服务器端返回true表明认证成功
附录1
/**
* AES字节数组加密算法类
*
* @author DC 20##/11/5
*/
publicclass Aes
{
/*************************** 成员变量 ************************************/
privateint Nb;// 以32位为单位的字长
privateint Nk;// 以32位为单位的密钥长度
privateint Nr;// 轮数
privatebyte[] key;// 密钥
privatebyte[][] Sbox;// S盒矩阵
privatebyte[][] iSbox;// s盒逆矩阵
privatebyte[][] w;// 密钥调度表
privatebyte[][] Rcon;// 轮常数表
privatebyte[][] State;// 状态矩阵
/**
* 构造方法
*
* @param keySize
* @param keyBytes
*/
public Aes(int keySize, byte[] keyBytes, int Nb)
{
SetNbNkNr(keySize, Nb);
this.key = newbyte[this.Nk * 4];
this.key = keyBytes;
BuildSbox();
BuildInvSbox();
BuildRcon();
KeyExpansion();
}
/*************************** 私有方法 ************************************/
/**
* 生成Rcon轮常数矩阵
*/
privatevoid BuildRcon()
{
// 0x00,0x01,0x02,0x04,
// 0x08,0x10,0x20,0x40,
// 0x80,0x1b,0x36,0x6c,
// 0xd8,0xab,0x4d,0x9a,
// 0x2f,0x5e,0xbc,0x63,
// 0xc6,0x97,0x35,0x6a,
// 0xd4,0xb3,0x7d,0xfa,
// 0xef,0xc5,0x91,0x39};
this.Rcon = newbyte[100][4];
Rcon[0][0]=0x00;//Rcon[1][0]=0x01;
for(int i=1;i<100;i++)
{
Rcon[i][0]=gfmultby02(Rcon[i-1][0]);
}
}
/**
* 设置Nb,Nk,Nr
*
* @param keysize
*/
privatevoid SetNbNkNr(int keysize, int Nb)
{
this.Nb = Nb;
switch (keysize)
{
case KEYSIZE.Bit128:
this.Nk = 4;
this.Nr = 10;
break;
case KEYSIZE.Bit192:
this.Nk = 6;
this.Nr = 12;
break;
case KEYSIZE.Bit256:
this.Nk = 8;
this.Nr = 14;
break;
}
}
/**
* 生成S盒矩阵
*/
privatevoid BuildSbox()
{
this.Sbox = newbyte[][] {
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
/* 0 */{ 0x63, 0x7c, 0x77, 0x7b, (byte) 0xf2, 0x6b, 0x6f,
(byte) 0xc5, 0x30, 0x01, 0x67, 0x2b, (byte) 0xfe,
(byte) 0xd7, (byte) 0xab, 0x76 },
/* 1 */{ (byte) 0xca, (byte) 0x82, (byte) 0xc9, 0x7d,
(byte) 0xfa, 0x59, 0x47, (byte) 0xf0, (byte) 0xad,
(byte) 0xd4, (byte) 0xa2, (byte) 0xaf, (byte) 0x9c,
(byte) 0xa4, 0x72, (byte) 0xc0 },
/* 2 */{ (byte) 0xb7, (byte) 0xfd, (byte) 0x93, 0x26, 0x36,
0x3f, (byte) 0xf7, (byte) 0xcc, 0x34, (byte) 0xa5,
(byte) 0xe5, (byte) 0xf1, 0x71, (byte) 0xd8, 0x31, 0x15 },
/* 3 */{ 0x04, (byte) 0xc7, 0x23, (byte) 0xc3, 0x18,
(byte) 0x96, 0x05, (byte) 0x9a, 0x07, 0x12,
(byte) 0x80, (byte) 0xe2, (byte) 0xeb, 0x27,
(byte) 0xb2, 0x75 },
/* 4 */{ 0x09, (byte) 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a,
(byte) 0xa0, 0x52, 0x3b, (byte) 0xd6, (byte) 0xb3,
0x29, (byte) 0xe3, 0x2f, (byte) 0x84 },
/* 5 */{ 0x53, (byte) 0xd1, 0x00, (byte) 0xed, 0x20,
(byte) 0xfc, (byte) 0xb1, 0x5b, 0x6a, (byte) 0xcb,
(byte) 0xbe, 0x39, 0x4a, 0x4c, 0x58, (byte) 0xcf },
/* 6 */{ (byte) 0xd0, (byte) 0xef, (byte) 0xaa, (byte) 0xfb,
0x43, 0x4d, 0x33, (byte) 0x85, 0x45, (byte) 0xf9, 0x02,
0x7f, 0x50, 0x3c, (byte) 0x9f, (byte) 0xa8 },
/* 7 */{ 0x51, (byte) 0xa3, 0x40, (byte) 0x8f, (byte) 0x92,
(byte) 0x9d, 0x38, (byte) 0xf5, (byte) 0xbc,
(byte) 0xb6, (byte) 0xda, 0x21, 0x10, (byte) 0xff,
(byte) 0xf3, (byte) 0xd2 },
/* 8 */{ (byte) 0xcd, 0x0c, 0x13, (byte) 0xec, 0x5f,
(byte) 0x97, 0x44, 0x17, (byte) 0xc4, (byte) 0xa7,
0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73 },
/* 9 */{ 0x60, (byte) 0x81, 0x4f, (byte) 0xdc, 0x22, 0x2a,
(byte) 0x90, (byte) 0x88, 0x46, (byte) 0xee,
(byte) 0xb8, 0x14, (byte) 0xde, 0x5e, 0x0b, (byte) 0xdb },
/* a */{ (byte) 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
(byte) 0xc2, (byte) 0xd3, (byte) 0xac, 0x62,
(byte) 0x91, (byte) 0x95, (byte) 0xe4, 0x79 },
/* b */{ (byte) 0xe7, (byte) 0xc8, 0x37, 0x6d, (byte) 0x8d,
(byte) 0xd5, 0x4e, (byte) 0xa9, 0x6c, 0x56,
(byte) 0xf4, (byte) 0xea, 0x65, 0x7a, (byte) 0xae, 0x08 },
/* c */{ (byte) 0xba, 0x78, 0x25, 0x2e, 0x1c, (byte) 0xa6,
(byte) 0xb4, (byte) 0xc6, (byte) 0xe8, (byte) 0xdd,
0x74, 0x1f, 0x4b, (byte) 0xbd, (byte) 0x8b, (byte) 0x8a },
/* d */{ 0x70, 0x3e, (byte) 0xb5, 0x66, 0x48, 0x03,
(byte) 0xf6, 0x0e, 0x61, 0x35, 0x57, (byte) 0xb9,
(byte) 0x86, (byte) 0xc1, 0x1d, (byte) 0x9e },
/* e */{ (byte) 0xe1, (byte) 0xf8, (byte) 0x98, 0x11, 0x69,
(byte) 0xd9, (byte) 0x8e, (byte) 0x94, (byte) 0x9b,
0x1e, (byte) 0x87, (byte) 0xe9, (byte) 0xce, 0x55,
0x28, (byte) 0xdf },
/* f */{ (byte) 0x8c, (byte) 0xa1, (byte) 0x89, 0x0d,
(byte) 0xbf, (byte) 0xe6, 0x42, 0x68, 0x41,
(byte) 0x99, 0x2d, 0x0f, (byte) 0xb0, 0x54,
(byte) 0xbb, 0x16 } };
}
/**
* 生成逆s盒矩阵
*/
privatevoid BuildInvSbox()
{
// this.Sbox = new byte[][] {};
// 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,
int x, y;
this.iSbox = newbyte[16][16];
for (int i = 0; i < 16; i++)
{
// System.out.println("i="+i);
for (int j = 0; j < 16; j++)
{
x = (int) ((this.Sbox[i][j] >> 4) & 0x0f);
y = (int) (this.Sbox[i][j] & 0x0f);
// System.out.println("x="+x+" y="+y);
this.iSbox[x][y] = (byte) (16 * i + j);
}
}
}
/**
* 扩展密钥
*/
privatevoid KeyExpansion()
{
this.w = newbyte[Nb * (Nr + 1)][4];
for (int row = 0; row < Nk; ++row)
{
this.w[row][0] = this.key[4 * row];
this.w[row][1] = this.key[4 * row + 1];
this.w[row][2] = this.key[4 * row + 2];
this.w[row][3] = this.key[4 * row + 3];
}
byte[] temp = newbyte[Nb];
for (int row = Nk; row < Nb * (Nr + 1); ++row)
{
temp[0] = this.w[row - 1][0];
temp[1] = this.w[row - 1][1];
temp[2] = this.w[row - 1][2];
temp[3] = this.w[row - 1][3];
if (row % Nk == 0)
{
temp = SubWord(RotWord(temp));
temp[0] = (byte) (temp[0] ^ this.Rcon[row / Nk][0]);
temp[1] = (byte) (temp[1] ^ this.Rcon[row / Nk][1]);
temp[2] = (byte) (temp[2] ^ this.Rcon[row / Nk][2]);
temp[3] = (byte) (temp[3] ^ this.Rcon[row / Nk][3]);
} elseif (Nk > 6 && (row % Nk == 4))
{
temp = SubWord(temp);
}
this.w[row][0] = (byte) (this.w[row - Nk][0] ^ temp[0]);
this.w[row][1] = (byte) (this.w[row - Nk][1] ^ temp[1]);
this.w[row][2] = (byte) (this.w[row - Nk][2] ^ temp[2]);
this.w[row][3] = (byte) (this.w[row - Nk][3] ^ temp[3]);
}
}
/**
* SubWord方法
*
* @param subWord
* @return
*/
privatebyte[] SubWord(byte[] subWord)
{
for (int c = 0; c < subWord.length; ++c)
{
subWord[c] = this.Sbox[(subWord[c] >> 4) & 0x0f][(subWord[c] & 0x0f)];
}
return subWord;
}
/**
* RotWord方法
*
* @param rotWord
* @return
*/
privatebyte[] RotWord(byte[] rotWord)
{
byte[] temp = rotWord;
byte[] b = newbyte[4];
for (int i = 0; i < 4; i++)
{
b[i] = temp[(i + 1) % 4];
}
return b;
}
/**
* 轮密钥加
*
* @param round
*/
privatevoid AddRoundKey(int round)
{
for (int r = 0; r < 4; ++r)
{
for (int c = 0; c < Nb; ++c)
{
this.State[r][c] = (byte) (this.State[r][c] ^ w[(round * Nb)
+ c][r]);
}
}
}
/**
* SubBytes方法
*/
privatevoid SubBytes()
{
for (int r = 0; r < 4; ++r)
{
for (int c = 0; c < Nb; ++c)
{
this.State[r][c] = this.Sbox[(this.State[r][c] >> 4) & 0x0f][(this.State[r][c] & 0x0f)];
}
}
}
/**
* InvSubBytes方法
*/
privatevoid InvSubBytes()
{
for (int r = 0; r < 4; ++r)
{
for (int c = 0; c < Nb; ++c)
{
this.State[r][c] = this.iSbox[(this.State[r][c] >> 4) & 0x0f][(this.State[r][c] & 0x0f)];
}
}
}
/**
* 行移位
*/
privatevoid ShiftRows()
{
byte[][] temp = newbyte[4][Nb];
for (int r = 0; r < 4; ++r)
{
for (int c = 0; c < Nb; ++c)
{
temp[r][c] = this.State[r][c];
}
}
for (int r = 1; r < 4; ++r)
{
for (int c = 0; c < Nb; ++c)
{
this.State[r][c] = temp[r][(c + r) % Nb];
}
}
// System.out.println();
// for (int r = 0; r < 4; r++)
// {
// for (int c = 0; c < 4; c++)
// {
// System.out.print(State[r][c]+" ");
// }
// System.out.println();
// }
//
}
/**
* 逆行移位
*/
privatevoid InvShiftRows()
{
byte[][] temp = newbyte[4][Nb];
for (int r = 0; r < 4; ++r)
{
for (int c = 0; c < Nb; ++c)
{
temp[r][c] = this.State[r][c];
}
}
for (int r = 1; r < 4; ++r)
{
for (int c = 0; c < Nb; ++c)
{
this.State[r][c] = temp[r][(c - r + Nb) % Nb];
}
}
// System.out.println();
// for (int r = 0; r < 4; ++r)
// {
// for (int c = 0; c < 4; ++c)
// {
// System.out.print(this.State[r][c] + " ");
// }
// System.out.println();
// }
}
/**
* 列混合
*/
privatevoid MixColumns()
{
byte[][] temp = newbyte[4][Nb];
for (int r = 0; r < 4; ++r)
{
for (int c = 0; c < Nb; ++c)
{
temp[r][c] = this.State[r][c];
}
}
for (int c = 0; c < Nb; ++c)
{
this.State[0][c] = (byte) (gfmultby02(temp[0][c])
^ gfmultby03(temp[1][c]) ^ gfmultby01(temp[2][c]) ^ gfmultby01(temp[3][c]));
this.State[1][c] = (byte) (gfmultby01(temp[0][c])
^ gfmultby02(temp[1][c]) ^ gfmultby03(temp[2][c]) ^ gfmultby01(temp[3][c]));
this.State[2][c] = (byte) (gfmultby01(temp[0][c]) ^ (gfmultby01(temp[1][c])
^ gfmultby02(temp[2][c]) ^ gfmultby03(temp[3][c])));
this.State[3][c] = (byte) (gfmultby03(temp[0][c])
^ gfmultby01(temp[1][c]) ^ (gfmultby01(temp[2][c]) ^ gfmultby02(temp[3][c])));
}
}
/**
* 逆列混合
*/
privatevoid InvMixColumns()
{
byte[][] temp = newbyte[4][Nb];
for (int r = 0; r < 4; ++r)
{
for (int c = 0; c < Nb; ++c)
{
temp[r][c] = this.State[r][c];
}
}
for (int c = 0; c < Nb; c++)
{
this.State[0][c] = (byte) (gfmultby0e(temp[0][c])
^ gfmultby0b(temp[1][c]) ^ gfmultby0d(temp[2][c]) ^ gfmultby09(temp[3][c]));
this.State[1][c] = (byte) (gfmultby09(temp[0][c])
^ gfmultby0e(temp[1][c]) ^ gfmultby0b(temp[2][c]) ^ gfmultby0d(temp[3][c]));
this.State[2][c] = (byte) (gfmultby0d(temp[0][c]) ^ (gfmultby09(temp[1][c])
^ gfmultby0e(temp[2][c]) ^ gfmultby0b(temp[3][c])));
this.State[3][c] = (byte) (gfmultby0b(temp[0][c])
^ gfmultby0d(temp[1][c]) ^ (gfmultby09(temp[2][c]) ^ gfmultby0e(temp[3][c])));
}
}
// 有限域GF(28)部分变换
privatebyte gfmultby01(byte b)
{
return b;
}
privatebyte gfmultby02(byte b)
{
// if (b < 0x80 && b >= 0) // !!!!!!!这里比较大小的时候注意符号位
// return (byte) (b << 1);
// else
// return (byte) ((b << 1) ^ (byte) 0x1b);
if (((b >> 7) & 0x01) == 0) // !!!!!!!这里比较大小的时候注意符号位
return (byte) (b << 1);
else
return (byte) ((b << 1) ^ (byte) 0x1b);
// 消除符号位可以用b&0xff
}
privatebyte gfmultby03(byte b)
{
return (byte) (gfmultby02(b) ^ gfmultby01(b));
}
privatebyte gfmultby09(byte b)
{
return (byte) (gfmultby02(gfmultby02(gfmultby02(b))) ^ gfmultby01(b));
}
privatebyte gfmultby0b(byte b)
{
return (byte) (gfmultby02(gfmultby02(gfmultby02(b))) ^ gfmultby02(b) ^ gfmultby01(b));
}
privatebyte gfmultby0d(byte b)
{
return (byte) (gfmultby02(gfmultby02(gfmultby02(b)))
^ gfmultby02(gfmultby02(b)) ^ gfmultby01(b));
}
privatebyte gfmultby0e(byte b)
{
return (byte) (gfmultby02(gfmultby02(gfmultby02(b)))
^ gfmultby02(gfmultby02(b)) ^ gfmultby02(b));
}
/*************************** 公有方法 ************************************/
/**
* 加密过程
*
* @param input
* @param output
*/
publicvoid Cipher(byte[] input, byte[] output)
{
this.State = newbyte[4][Nb];
for (int i = 0; i < (4 * Nb); i++)
{
this.State[i / Nb][i % Nb] = input[i];
}// 初始化状态矩阵
AddRoundKey(0);// 轮密钥加
for (int round = 1; round < Nr; ++round)
{
SubBytes();// S盒变换
ShiftRows();// 行移位
MixColumns();// 列混合
AddRoundKey(round);
}
SubBytes();// S盒置换
ShiftRows();// 行移位
AddRoundKey(Nr);// 轮密钥加
for (int i = 0; i < (4 * Nb); i++)
{
output[i] = this.State[i / Nb][i % Nb];
System.out.println((i%Nb));
}// 输出密文
}
publicvoid Cipher(String input, String output)
{
}
/**
* 解密过程
*
* @param inputs
* @param output
*/
publicvoid Invcipher(byte[] input, byte[] output)
{
this.State = newbyte[4][Nb];
for (int i = 0; i < (4 * Nb); ++i)
{
this.State[i / Nb][i % Nb] = input[i];
}// 初始化状态矩阵
AddRoundKey(Nr);// 轮密钥加
for (int round = Nr - 1; round > 0; round--)
{
InvShiftRows();// 逆行移位
InvSubBytes();// 逆S盒置换
AddRoundKey(round);// 轮密钥加
InvMixColumns();// 逆列混合
}
InvShiftRows();// 逆行移位
InvSubBytes();// 逆S盒置换
AddRoundKey(0);// 轮密钥加
for (int i = 0; i < (4 * Nb); ++i)
{
output[i] = this.State[i / Nb][i % Nb];
}// 输出结果
}
}
/**
* 辅助类 处理明文字符输入字节数不匹配等问题
*
* @author DC
*
*/
publicclass AesCipherAndInvCipher
{
privatebyte[] key;// 密钥
privatebyte[] pt;// 明文字节数组
privatebyte[] ct;
privateint mode;
privateint Nb = 0;
privateint dataLength;
privateint blockSize = 4;// 分组大小32位,4bytes
public AesCipherAndInvCipher(byte[] kb)
{
this.key=kb;
}
/**
* 加密
*
* @param kb
* @param plainText
* @return 加密后密文字节数组
*/
privatebyte[] Eecrypt(String plainText, byte[] kb) throws InvalidKeyException
{
try
{
pt = plainText.getBytes("UTF-8");// 获取明文字节数组
//System.out.println("明文字节数组:");
//DisplayAsBytes(pt);
} catch (UnsupportedEncodingException e)
{
System.out.println("不支持的编码类型!");
e.printStackTrace();
}
dataLength = pt.length;
// System.out.println(dataLength);
mode = dataLength % blockSize;// 判断明文数组长度是否与分组长度匹配
ct = newbyte[mode == 0 ? pt.length : dataLength / blockSize * 4 + 32];// 密文字节数组
Nb = dataLength / blockSize;
// System.out.println(ct.length);
Aes a1 = new Aes(KEYSIZE.Bit192, kb, Nb);
Aes a2 = new Aes(KEYSIZE.Bit192, kb, 4);
Aes a3 = new Aes(KEYSIZE.Bit192, kb, 4);
if (mode == 0)
{
a1.Cipher(pt, ct);
} else
{
//System.out.println("长度不匹配");
byte[] b1 = newbyte[blockSize * Nb];// 匹配的部分
//System.out.println(blockSize * Nb);
byte[] b2 = newbyte[16];// 剩余部分
byte[] b3 = newbyte[16];// 存明文长度
byte[] c1 = newbyte[b1.length];
byte[] c2 = newbyte[b2.length];
byte[] c3 = newbyte[b3.length];
System.arraycopy(pt, 0, b1, 0, b1.length);
// System.out.println("匹配明文字节数组:");
// DisplayAsBytes(b1);
System.arraycopy(pt, Nb * blockSize, b2, 0, mode);
b3 = intToByteArray(dataLength);
// System.out.println(ct.length);
a1.Cipher(b1, c1);
//System.out.println("c1:");
//DisplayAsBytes(c1);
// DisplayAsBytes(b3);
a2.Cipher(b2, c2);
a3.Cipher(b3, c3);
System.arraycopy(c1, 0, ct, 0, c1.length);
System.arraycopy(c2, 0, ct, b1.length, c2.length);
System.arraycopy(c3, 0, ct, b1.length + b2.length, c3.length);
}
return ct;
}
publicbyte[] EecryptToBytes(String plainText, byte[] kb) throws InvalidKeyException
{
byte[] ct=Eecrypt(plainText,kb);
return ct;
}
public String EecryptToString(String plainText, byte[] kb) throws InvalidKeyException
{
byte[] ct = Eecrypt(plainText,kb);
//System.out.println("密文:"+BytesToString(ct));
returnBytesToString(ct);
}
/**
* 解密
*/
public String Decrypt(byte[] ct,byte[] kb)
{
String s="";
if (mode == 0)
{
byte[] output = newbyte[dataLength];
Aes a = new Aes(KEYSIZE.Bit192, kb, Nb);
a.Invcipher(ct, output);
try
{
s = new String(output, "UTF-8");
System.out.println("解密:" + s);
} catch (UnsupportedEncodingException e)
{
System.out.println("不支持的编码格式!");
e.printStackTrace();
}
} else
{
byte[] length = newbyte[16];
byte[] plainText1 = newbyte[ct.length - 32];
byte[] plainText2 = newbyte[16];
Aes a1 = new Aes(KEYSIZE.Bit192, kb, Nb);
Aes a2 = new Aes(KEYSIZE.Bit192, kb, 4);
Aes a3 = new Aes(KEYSIZE.Bit192, kb, 4);
byte[] c1 = newbyte[ct.length - 32];
byte[] c2 = newbyte[16];
byte[] c3 = newbyte[16];
System.arraycopy(ct, ct.length - 16, c3, 0, c3.length);
System.arraycopy(ct, ct.length - 32, c2, 0, c2.length);
System.arraycopy(ct, 0, c1, 0, Nb * blockSize);
//System.out.println("密文匹配部分c1:");
//DisplayAsBytes(c1);
a3.Invcipher(c3, length);// 解密明文字节数组长度
a2.Invcipher(c2, plainText2);// 解密剩余的部分
a1.Invcipher(c1, plainText1);// 解密匹配的部分
// System.out.println(plainText1.length);
//System.out.println("解密后字节数组长度:");
//DisplayAsBytes(length);
//System.out.println("解密后匹配部分:");
//DisplayAsBytes(plainText1);
//System.out.println("解密后剩余部分:");
//DisplayAsBytes(plainText2);
// DisplayAsBytes(output);
// int length;
int length1 = byteArrayToInt(length);
//System.out.println("\n解密长度后:" + length1);
byte[] output = newbyte[length1];
System.arraycopy(plainText1, 0, output, 0, plainText1.length);
System.arraycopy(plainText2, 0, output, plainText1.length, length1
- plainText1.length);
//System.out.println("解密后字节数组:");
//DisplayAsBytes(output);
try
{
s = new String(output, "UTF-8");
System.out.println("解密后明文:" + s);
} catch (UnsupportedEncodingException e)
{
System.out.println("不支持的编码格式!");
e.printStackTrace();
}
}
return s;
}
public String Decrypt(String cryptText,byte[] kb)
{
//System.out.println(cryptText+" "+cryptText.length());
byte[] ct=StringToBytes(cryptText);
//DisplayAsBytes(ct);
return Decrypt(ct,kb);
}
public String Decrypt(Byte[] ct,byte[] kb)
{
return Decrypt(ct,kb);
}
/**
* int转化为Byte数组
*
* @param value
* @return
*/
privatestaticbyte[] intToByteArray(int value)
{
byte[] b = newbyte[16];
for (int i = 0; i < 4; i++)
{
int offset = (b.length - 1 - i) * 8;
b[i] = (byte) ((value >>> offset) & 0xFF);
}
for (int i = 4; i < 16; i++)
{
b[i] = 0;
}
return b;
}
/**
* byte数组转化为int
*
* @param b
* @return
*/
privatestaticfinalint byteArrayToInt(byte[] b)
{
byte[] b1 = newbyte[4];
System.arraycopy(b, 0, b1, 0, 4);
//DisplayAsBytes(b1);
//System.out.println(b1[0] << 24);
return (b1[0] << 24) + ((b1[1] & 0xFF) << 16) + ((b1[2] & 0xFF) << 8)
+ (b1[3] & 0xFF);
// targets[0] = (byte) (res & 0xff);// 最低位
// targets[1] = (byte) ((res >> 8) & 0xff);// 次低位
// targets[2] = (byte) ((res >> 16) & 0xff);// 次高位
// targets[3] = (byte) (res >>> 24);// 最高位,无符号右移。
// return targets;
}
/**
* 显示字节数组
*
* @param b
*/
privatestaticvoidDisplayAsBytes(byte[] b)
{
for (int i = 0; i < b.length; i++)
{
String hex = Integer.toHexString(b[i] & 0xFF);
if (hex.length() == 1)
{
hex = '0' + hex;
}
System.out.print(hex.toUpperCase() + " ");
}
System.out.println();
}
privatestatic String BytesToString(byte[] b)
{
String s = "";
for (int i = 0; i < b.length; i++)
{
String hex = Integer.toHexString(b[i] & 0xFF);
if (hex.length() == 1)
{
hex = '0' + hex;
}
s+=hex;
}
return s;
}
privatestaticbyte[] StringToBytes(String cryptText)
{
byte[] b=newbyte[cryptText.length()/2];
int[] a=newint[cryptText.length()];
for(int i=0;i<cryptText.length();++i)
{
String s=cryptText.substring(i, i+1);
//System.out.print(i);
if(s.equals("a"))
a[i]=10;
elseif(s.equals("b"))
a[i]=11;
elseif(s.equals("c"))
a[i]=12;
elseif(s.equals("d"))
a[i]=13;
elseif(s.equals("e"))
a[i]=14;
elseif(s.equals("f"))
a[i]=15;
else
a[i]=Integer.valueOf(s);
}
for(int i=0;i<cryptText.length()/2;i++)
{
b[i]=(byte) (a[2*i]*16+a[2*i+1]);
}
return b;
}
}
publicclass generateKey
{
privatestaticbyte[] key;
/**
* 随机生成key
* @param keySize
* @return
* @throws InvalidKeyException
*/
publicstaticbyte[] generateRandomKey(int keySize) throws InvalidKeyException
{
if (keySize == KEYSIZE.Bit128 | keySize == KEYSIZE.Bit192
| keySize == KEYSIZE.Bit256)
{
key = newbyte[keySize / 8];
for (int i = 0; i < keySize / 8; i++)
{
Random r = new Random();
int tempByte = r.nextInt() * 255;
key[i] = (byte) tempByte;
}
// DisplayAsBytes(key);
returnkey;
} else
{
thrownew InvalidKeyException("密钥长度错误,正确长度为128,192或者256位!");
}
}
/**
* 根据字符串生成key
* @param keyStr
* @return
*/
publicstaticbyte[] generateKeyFromString(String keyStr)
{
byte[] tempkey=null;
try
{
tempkey = keyStr.getBytes("UTF-8");
} catch (UnsupportedEncodingException e)
{
System.out.println("不支持的编码类型!");
e.printStackTrace();
}
//System.out.println("\n密钥字节数组:" + key);
if(tempkey.length<128)
{
key=newbyte[16];
byte lastByte=tempkey[tempkey.length-1];
for(int i=tempkey.length;i<16;i++)
{
key[i]=gfmultby02(lastByte);
lastByte=key[i-1];
}
//DisplayAsBytes(key);
}
elseif(tempkey.length>128&&tempkey.length<192)
{
key=newbyte[24];
byte lastByte=tempkey[tempkey.length-1];
for(int i=tempkey.length;i<24;i++)
{
key[i]=gfmultby02(lastByte);
lastByte=key[i-1];
}
//DisplayAsBytes(key);
}
elseif(tempkey.length>192&&tempkey.length<256)
{
key=newbyte[32];
byte lastByte=tempkey[tempkey.length-1];
for(int i=tempkey.length;i<32;i++)
{
key[i]=gfmultby02(lastByte);
lastByte=key[i-1];
}
//DisplayAsBytes(key);
}
elseif(tempkey.length>256)
{
key=newbyte[32];
System.arraycopy(tempkey, 0, key, 0, 32);
}
else
{
key=tempkey;
}
returnkey;
}
publicint getKeyLength()
{
returnkey.length;
}
privatestaticbyte gfmultby02(byte b)
{
// if (b < 0x80 && b >= 0) // !!!!!!!这里比较大小的时候注意符号位
// return (byte) (b << 1);
// else
// return (byte) ((b << 1) ^ (byte) 0x1b);
if (((b >> 7) & 0x01) == 0) // !!!!!!!这里比较大小的时候注意符号位
return (byte) (b << 1);
else
return (byte) ((b << 1) ^ (byte) 0x1b);
// 消除符号位可以用b&0xff
}
// public static void DisplayAsBytes(byte[] b)
// {
// for (int i = 0; i < b.length; i++)
// {
// String hex = Integer.toHexString(b[i] & 0xFF);
// if (hex.length() == 1)
// {
// hex = '0' + hex;
// }
// System.out.print(hex.toUpperCase() + " ");
// }
// System.out.println();
// }
}
/**
* 密钥长度
*
* @author DC
*/
publicclass KEYSIZE
{
publicstaticfinalintBit128 = 128;//128位
publicstaticfinalintBit192 = 192;//192位
publicstaticfinalintBit256 = 256;//256位
}
publicclass TestAes {
publicstaticvoid main(String[] args)
{
// *************************加密*******************************************
byte[] plainText = newbyte[] { 0x11, 0x11, 0x22, 0x33, 0x44, 0x55,
0x66, 0x77, (byte) 0x88, (byte) 0x99, (byte) 0xaa, (byte) 0xbb,
(byte) 0xcc, (byte) 0xdd, (byte) 0xee, (byte) 0xff, 0x00, 0x11,// 0x22,
0x66, 0x77 };// 明文
byte[] cipherText = newbyte[20];
byte[] decipheredText = newbyte[20];
byte[] keyBytes = null;
try
{
keyBytes = generateKey.generateKeyFromString("段聪wrwe2432v112wwwwwwwwwwwwwwwwwwww@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@wwwwwwwwwwwwwwwwwwwwwww34@#%$1234fffffffffffffffffffffff");
} catch (Exception e1)
{
// TODO Auto-generated catch block
e1.printStackTrace();
}
Aes a = new Aes(KEYSIZE.Bit192, keyBytes, 5);
System.out.println("***********************测试1****************************");
byte[] key1 = null;
try
{
key1 = generateKey.generateRandomKey(KEYSIZE.Bit192);
} catch (InvalidKeyException e1)
{
e1.printStackTrace();
}
AesCipherAndInvCipher aes = new AesCipherAndInvCipher(key1);
byte[] dt = null;
String ss = null;
try
{
dt = newbyte[16];
dt = aes.EecryptToBytes("段聪wrwe2432v1343", keyBytes);
ss = aes.EecryptToString("段聪wrwe2432v1343", keyBytes);
System.out.println("明文:段聪wrwe2432v1343");
} catch (InvalidKeyException e)
{
e.printStackTrace();
}
aes.Decrypt(dt, keyBytes);
aes.Decrypt(ss, keyBytes);
System.out.println("*************************测试2*****************************");
AesCipherAndInvCipher aes1 = new AesCipherAndInvCipher(key1);
byte[] dt1 = null;
try
{
// dt = new byte[16];
String plainText1 = "uuid=FSFASW24S-0342-FEW3-3F33-F44F2SE523432D";
dt1 = aes1.EecryptToBytes(plainText1, keyBytes);
System.out.println("明文:" + plainText1);
} catch (InvalidKeyException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
aes1.Decrypt(dt1, keyBytes);
}
/**
* 显示16进制
*
* @param b
*/
publicstaticvoid DisplayAsBytes(byte[] b)
{
for (int i = 0; i < b.length; i++)
{
String hex = Integer.toHexString(b[i] & 0xFF);
if (hex.length() == 1)
{
hex = '0' + hex;
}
System.out.print(hex.toUpperCase() + " ");
}
System.out.println();
}
}
附录2:
public class Rc4 {
publicstatic String HloveyRC4(String aInput,String aKey)
{
int[] iS = newint[256];
byte[] iK = newbyte[256];
for (int i=0;i<256;i++)
iS[i]=i;
int j = 1;
for (short i= 0;i<256;i++)
{
iK[i]=(byte)aKey.charAt((i % aKey.length()));
}
j=0;
for (int i=0;i<255;i++)
{
j=(j+iS[i]+iK[i]) % 256;
int temp = iS[i];
iS[i]=iS[j];
iS[j]=temp;
}
int i=0;
j=0;
char[] iInputChar = aInput.toCharArray();
char[] iOutputChar = newchar[iInputChar.length];
for(short x = 0;x<iInputChar.length;x++)
{
i = (i+1) % 256;
j = (j+iS[i]) % 256;
int temp = iS[i];
iS[i]=iS[j];
iS[j]=temp;
int t = (iS[i]+(iS[j] % 256)) % 256;
int iY = iS[t];
char iCY = (char)iY;
iOutputChar[x] =(char)( iInputChar[x] ^ iCY) ;
}
returnnew String(iOutputChar);
}
publicstaticvoid main(String[] args) {
String inputStr = "郁博文";
String key = "333417";
String str = HloveyRC4(inputStr,key);
//打印加密后的字符串
System.out.println("RC4密文:"+str);
//打印解密后的字符串
System.out.println("解密明文:"+HloveyRC4(str,key));
}
}
附录3
//哈希函数
publicclass APHash {
String key;
publicstaticintAPHash(String key) {
int hash = 0;
int n = key.length();
for (int i = 0; i < n; i++) {
if ((i & 1) == 0) {
hash ^= ((hash << 7) ^ key.charAt(i) ^ (hash >> 3));
} else {
hash ^= (~((hash << 11) ^ key.charAt(i) ^ (hash >> 5)));
}
}
return (hash & 0x7FFFFFFF);
}
}
publicclass SkeyDemo {
static String client = "D://client.txt";
static String sever = "D://sever.txt";
static File file_client = new File(client);
static File file_sever = new File(sever);
static String encoding = "GBK";
publicstatic String read(File file) {
String string = "";
try {
InputStreamReader read = new InputStreamReader(new FileInputStream(
file), encoding);
BufferedReader bufferedReader = new BufferedReader(read);
String lineTxt = null;
while ((lineTxt = bufferedReader.readLine()) != null) {
string = string + lineTxt;
}
read.close();
} catch (Exception e) {
e.printStackTrace();
}
return string;
}
publicstatic String change(String string) {
for (int i = 0; i < 100; i++) {
string = APHash.APHash(string) + "";
}
return string;
}
publicstaticvoid write(File file, String string) {
try {
BufferedWriter output = new BufferedWriter(new FileWriter(file));
output.write(string);
output.close();
} catch (Exception e) {
e.printStackTrace();
}
}
publicstaticvoid s2c() {
String to = change(read(file_client));
write(file_client, to);
write(file_sever, APHash.APHash(to) + "");
}
publicstatic Boolean judge() {
if ((APHash.APHash(read(file_client)) + "").equals(read(file_sever))) {
write(file_client, read(file_sever));
write(file_sever, APHash.APHash(read(file_sever)) + "");
returntrue;
} else {
returnfalse;
}
}
publicstaticvoid main(String[] args) {
s2c();
System.out.println(judge());
}
}
信息安全实验报告学号学生姓名班级实验三密码学实验一古典密码算法实验一实验目的通过编程实现替代密码算法和置换密码算法加深对古典密码体…
密码学与网络安全技术课程上机报告学号119xx4339姓名许海龙班级网112班教师卫琳娜安徽工业大学密码学实验一古典密码算法实验一…
密码学实验报告学院计算机科学与技术班级学号姓名指导老师实验日志实验题目DES或AES分组密码实验目的熟悉分组密码加解密算法的基本原…
密码学实验报告实验一DES加密算法实验一实验目的理解对称加解密算法的原理和特点理解DES算法的加解密原理二实验背景DES算法为密码…
江苏大学学院专业姓名学号计算机学院信息安全09023090604035小组成员AES对称加密算法实现一AES对称加密算法实现原理A…
信息安全实验报告学号学生姓名班级实验三密码学实验一古典密码算法实验一实验目的通过编程实现替代密码算法和置换密码算法加深对古典密码体…
密码学实验报告实验一DES加密算法实验一实验目的理解对称加解密算法的原理和特点理解DES算法的加解密原理二实验背景DES算法为密码…
密码学与网络安全技术课程上机报告学号119xx4339姓名许海龙班级网112班教师卫琳娜安徽工业大学密码学实验一古典密码算法实验一…
哈尔滨工程大学实验报告实验名称RC4加密班级学号姓名实验时间20xx615成绩指导教师实验室名称哈尔滨工程大学实验室与资产管理处制…
网络与信息安全IntroductiontoNetworkandSecurityDES加密解密算法的C实现姓名学号学院20xx年10…