📄 crypter.java
字号:
}
if(pos == 8)
encrypt8Bytes();
}
// 头部填充完了,这里开始填真正的明文了,也是满了8字节就加密,一直到明文读完
int i = offset;
while(len > 0) {
if(pos < 8) {
plain[pos++] = in[i++];
len--;
}
if(pos == 8)
encrypt8Bytes();
}
// 最后填上0,以保证是8字节的倍数
padding = 1;
while(padding <= 7) {
if(pos < 8) {
plain[pos++] = 0x0;
padding++;
}
if(pos == 8)
encrypt8Bytes();
}
return out;
}
/**
* @param in
* 需要加密的明文
* @param inLen
* 明文长度
* @param k
* 密钥
* @return Message 密文
*/
public byte[] encrypt(byte[] in, byte[] k) {
return encrypt(in, 0, in.length, k);
}
/**
* 加密一个8字节块
*
* @param in
* 明文字节数组
* @return
* 密文字节数组
*/
private byte[] encipher(byte[] in) {
// 迭代次数,16次
int loop = 0x10;
// 得到明文和密钥的各个部分,注意java没有无符号类型,所以为了表示一个无符号的整数
// 我们用了long,这个long的前32位是全0的,我们通过这种方式模拟无符号整数,后面用到的long也都是一样的
// 而且为了保证前32位为0,需要和0xFFFFFFFF做一下位与
long y = Util.getUnsignedInt(in, 0, 4);
long z = Util.getUnsignedInt(in, 4, 4);
long a = Util.getUnsignedInt(key, 0, 4);
long b = Util.getUnsignedInt(key, 4, 4);
long c = Util.getUnsignedInt(key, 8, 4);
long d = Util.getUnsignedInt(key, 12, 4);
// 这是算法的一些控制变量,为什么delta是0x9E3779B9呢?
// 这个数是TEA算法的delta,实际是就是(sqr(5) - 1) * 2^31 (根号5,减1,再乘2的31次方)
long sum = 0;
long delta = 0x9E3779B9;
delta &= 0xFFFFFFFFL;
// 开始迭代了,乱七八糟的,我也看不懂,反正和DES之类的差不多,都是这样倒来倒去
while (loop-- > 0) {
sum += delta;
sum &= 0xFFFFFFFFL;
y += ((z << 4) + a) ^ (z + sum) ^ ((z >>> 5) + b);
y &= 0xFFFFFFFFL;
z += ((y << 4) + c) ^ (y + sum) ^ ((y >>> 5) + d);
z &= 0xFFFFFFFFL;
}
// 最后,我们输出密文,因为我用的long,所以需要强制转换一下变成int
baos.reset();
writeInt((int)y);
writeInt((int)z);
return baos.toByteArray();
}
/**
* 解密从offset开始的8字节密文
*
* @param in
* 密文字节数组
* @param offset
* 密文开始位置
* @return
* 明文
*/
private byte[] decipher(byte[] in, int offset) {
// 迭代次数,16次
int loop = 0x10;
// 得到密文和密钥的各个部分,注意java没有无符号类型,所以为了表示一个无符号的整数
// 我们用了long,这个long的前32位是全0的,我们通过这种方式模拟无符号整数,后面用到的long也都是一样的
// 而且为了保证前32位为0,需要和0xFFFFFFFF做一下位与
long y = Util.getUnsignedInt(in, offset, 4);
long z = Util.getUnsignedInt(in, offset + 4, 4);
long a = Util.getUnsignedInt(key, 0, 4);
long b = Util.getUnsignedInt(key, 4, 4);
long c = Util.getUnsignedInt(key, 8, 4);
long d = Util.getUnsignedInt(key, 12, 4);
// 算法的一些控制变量,sum在这里也有数了,这个sum和迭代次数有关系
// 因为delta是这么多,所以sum如果是这么多的话,迭代的时候减减减,减16次,最后
// 得到0。反正这就是为了得到和加密时相反顺序的控制变量,这样才能解密呀~~
long sum = 0xE3779B90;
sum &= 0xFFFFFFFFL;
long delta = 0x9E3779B9;
delta &= 0xFFFFFFFFL;
// 迭代开始了, @_@
while(loop-- > 0) {
z -= ((y << 4) + c) ^ (y + sum) ^ ((y >>> 5) + d);
z &= 0xFFFFFFFFL;
y -= ((z << 4) + a) ^ (z + sum) ^ ((z >>> 5) + b);
y &= 0xFFFFFFFFL;
sum -= delta;
sum &= 0xFFFFFFFFL;
}
baos.reset();
writeInt((int)y);
writeInt((int)z);
return baos.toByteArray();
}
/**
* 写入一个整型到输出流,高字节优先
*
* @param t
*/
private void writeInt(int t) {
baos.write(t >>> 24);
baos.write(t >>> 16);
baos.write(t >>> 8);
baos.write(t);
}
/**
* 解密
*
* @param in
* 密文
* @return
* 明文
*/
private byte[] decipher(byte[] in) {
return decipher(in, 0);
}
/**
* 加密8字节
*/
private void encrypt8Bytes() {
// 这部分完成我上面所说的 plain ^ preCrypt,注意这里判断了是不是第一个8字节块,如果是的话,那个prePlain就当作preCrypt用
for(pos = 0; pos < 8; pos++) {
if(header)
plain[pos] ^= prePlain[pos];
else
plain[pos] ^= out[preCrypt + pos];
}
// 这个完成我上面说的 f(plain ^ preCrypt)
byte[] crypted = encipher(plain);
// 这个没什么,就是拷贝一下,java不像c,所以我只好这么干,c就不用这一步了
System.arraycopy(crypted, 0, out, crypt, 8);
// 这个完成了 f(plain ^ preCrypt) ^ prePlain,ok,下面拷贝一下就行了
for(pos = 0; pos < 8; pos++)
out[crypt + pos] ^= prePlain[pos];
System.arraycopy(plain, 0, prePlain, 0, 8);
// 完成了加密,现在是调整crypt,preCrypt等等东西的时候了
preCrypt = crypt;
crypt += 8;
pos = 0;
header = false;
}
/**
* 解密8个字节
*
* @param in
* 密文字节数组
* @param offset
* 从何处开始解密
* @param len
* 密文的长度
* @return
* true表示解密成功
*/
private boolean decrypt8Bytes(byte[] in , int offset, int len) {
// 这里第一步就是判断后面还有没有数据,没有就返回,如果有,就执行 crypt ^ prePlain
for(pos = 0; pos < 8; pos++) {
if(contextStart + pos >= len)
return true;
prePlain[pos] ^= in[offset + crypt + pos];
}
// 好,这里执行到了 d(crypt ^ prePlain)
prePlain = decipher(prePlain);
if(prePlain == null)
return false;
// 解密完成,最后一步好像没做?
// 这里最后一步放到decrypt里面去做了,因为解密的步骤有点不太一样
// 调整这些变量的值先
contextStart += 8;
crypt += 8;
pos = 0;
return true;
}
/**
* 这是个随机因子产生器,用来填充头部的,如果为了调试,可以用一个固定值
* 随机因子可以使相同的明文每次加密出来的密文都不一样
*
* @return
* 随机因子
*/
private int rand() {
return random.nextInt();
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -