`
zzhangyx
  • 浏览: 68999 次
  • 性别: Icon_minigender_1
  • 来自: 福建
社区版块
存档分类
最新评论

TEA加密算法 Java实现

    博客分类:
  • JAVA
阅读更多

本文转自:http://geekerdever.yo2.cn/articles/tea%E5%8A%A0%E5%AF%86%E7%AE%97%E6%B3%95-java%E5%AE%9E%E7%8E%B0.html


TEA加密算法 Java实现

10月 29, 2009

最近在使用Java实现QQ的基本通讯协议,QQ的通讯协议中使用MD5算法两次加密密码,并将通讯中的所有数据包使用TEA算法进行加密。MD5加密可以通过Java API提供的MessageDigest直接进行,而TEA加密则需自己编写。

TEA加密每次使用128bit密钥加密64bit数据,生成加密数据亦为64bit,为典型的对称加密算法。该算法使用C语言实现非常简单,但使用Java进行实现时,受制于Java的特性,在实现上稍有复杂。

代码如下:

public class TEA {
/**
* value is 0xffffffff
* filter long to unsigned int
*/
public static Long UIFILTER = Long.decode("0xffffffff");
/**
* value is 0xff
* filter short to unsigned byte
*/
public static Short UBFILTER = Short.decode("0xff");
/**
* Encipher method
*
64bit plaintext, 128bit key
* @param v Plaintext
* @param k Key
* @return
*/
public static Short[] encipher(Short [] v, Short [] k)
{
Long[] vL = shortToLong(v);
Long[] kL = shortToLong(k);
Long[] wL = new Long[vL.length];
Short[] w = null;
long y = vL[0];
long z = vL[1];
long a = kL[0];
long b = kL[1];
long c = kL[2];
long d = kL[3];
long n = 0x10; /* do encrypt 16 (0x10) times */
long sum = 0;
long delta = Long.decode("0x9E3779B9"); /* 0x9E3779B9 - 0x100000000 = -0x61C88647 */
while (n-- > 0) {
sum += delta;
sum &= UIFILTER;
y += ((z << 4) + a) ^ (z + sum) ^ ((z >> 5) + b);
y &= UIFILTER;
z += ((y << 4) + c) ^ (y + sum) ^ ((y >> 5) + d);
z &= UIFILTER;
}
wL[0] = y;
wL[1] = z;
w = longToShort(wL);
return w;
}
/**
* Decipher method
*
64bit ciphertext, 128bit key
* @param v Ciphertext
* @param k Key
* @return
*/
public static Short[] decipher(Short [] v, Short [] k)
{
Long[] vL = shortToLong(v);
Long[] kL = shortToLong(k);
Long[] wL = new Long[vL.length];
Short[] w = null;
long y = vL[0];
long z = vL[1];
long a = kL[0];
long b = kL[1];
long c = kL[2];
long d = kL[3];
long n = 0x10;
/* sum = delta << 4, in general sum = delta * n */ long sum = Long.decode("0xE3779B90"); long delta = Long.decode("0x9E3779B9"); // use filter to get unsigned int // use ~x +1 instead -x while (n-- > 0) {
z += (~(((y << 4) + c) ^ (y + sum) ^ ((y >> 5) + d)) + 1);
z &= UIFILTER;
y += (~(((z << 4) + a) ^ (z + sum) ^ ((z >> 5) + b)) + 1);
y &= UIFILTER;
sum += ((~delta) + 1);
sum &= UIFILTER;
}
wL[0] = y;
wL[1] = z;
w = longToShort(wL);
return w;
}
/**
* convert bytes to longs, put every 4 bytes to 1 long
*
use long instead unsigned int
* use short instead unsigned byte
* @param source - the Short [] that save unsigned bytes to convert
* @return the Long [] save unsigned int
*/
public static Long [] shortToLong(Short [] source){
int sourlen = source.length;
int turn = sourlen / 4; // how many turns
int remainder = sourlen % 4; // how many bytes in first turn
int tarlen = turn + (remainder == 0 ? 0 : 1);
Long [] target = new Long[tarlen];
for(int i = 0; i < target.length; i++){ target[i] = Long.parseLong("0"); } int iter = 0; int turnIter = 0; for(turnIter = 0; turnIter < tarlen; turnIter++){ for(iter = 0; iter < 4; iter++){ target[turnIter] <<= 8; if((turnIter != turn - 1) || ((turnIter == turn - 1) && (iter < remainder || remainder == 0))) target[turnIter] += source[turnIter * 4 + iter]; } } return target; } /** * convert longs to bytes
*
cut 1 long(32bit valid to instead unsigned int) to 4 short(8bit valid to instead unsigned byte)
* use long instead unsigned int
* use short instead unsigned byte
* @param source - the Long [] that save unsigned int to convert
* @return the Short [] that save unsigned bytes
*/
public static Short [] longToShort(Long [] source){
int sourlen = source.length;
Short [] target = new Short[sourlen * 4];
int turn = target.length % 4;
int iter = 0;
int move = 0;
for(iter = 0; iter < target.length; iter++){ move = 8 * (3 - (iter % 4)); target[iter] = Short.parseShort(Long.toString((source[iter / 4] & (UBFILTER << move)) >> move));
}
return target;
}
}
[/code]
代码中需要注意的几点如下:
由于Java种没有无符号数的概念,故如int, long, byte等基础类型其最高位均为符号位,故不能使用该种类型进行无符号运算。本代码中使用long代替unsigned int,使用short代替unsigned byte。
相 对C语言代码,在解密时不使用减法,而是用取反加一的方式将减法转换为加法。这是由于Java中Long类型是有符号的,其进行的计算亦为有符号计算。若 被减数小于减数时,减法结果将为负数,这不符合无符号减法的规则。转化为加法运算后,将其高位溢出,则可得无符号减法的结果。
由于Java中不允许高位溢出,会抛出异常,故高位溢出需要手工完成,即将运算结果与0xffffffff或0xff进行与运算(视具体类型而定)。
测试类如下:
[code=java]
public class TestPoint {
public static void main(String [] args){
Long[] keyLong = new Long[4];
//加密解密所用的KEY
keyLong[0] = Long.decode("0x789f5645");
keyLong[1] = Long.decode("0xf68bd5a4");
keyLong[2] = Long.decode("0x81963ffa");
keyLong[3] = Long.decode("0x458fac58");
Short[] key = TEA.longToShort(keyLong);
Short[] info = new Short[]{
1, 2, 3, 4, 5, 6, 7, 8
};
System.out.print("原数据:");
for(Short i : info)
System.out.print(i + " ");
System.out.println();
Short[] secretInfo = TEA.encipher(info, key);
System.out.print("加密后的数据:");
for(Short i : secretInfo)
System.out.print(i + " ");
System.out.println();
Short[] decryptInfo = TEA.decipher(secretInfo, key);
System.out.print("解密后的数据:");
for(Short i : decryptInfo)
System.out.print(i + " ");
}
}
 
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics