TEA加密算法
内容纲要
加密算法用处渐渐多了起来,可以使用简单的加密算法对JS加密/解密,这里实现一个简单的微加密算法。
微加密算法(TEA)及其相关变种(XTEA,Block TEA,XXTEA) 都是分组加密算法,实现也比较简单。

TEA 算法最初是由剑桥计算机实验室的 David Wheeler 和 Roger Needham 在 1994 年设计的。该算法使用 128 位的密钥为 64 位的信息块进行加密,它需要进行 64 轮迭代,尽管作者认为 32 轮已经足够了。该算法使用了一个神秘常数δ作为倍数,它来源于黄金比率,以保证每一轮加密都不相同。但δ的精确值似乎并不重要,这里 TEA 把它定义为 δ=「(√5 – 1)231」(也就是程序中的 0×9E3779B9)。
之后 TEA 算法被发现存在缺陷,作为回应,设计者提出了一个 TEA 的升级版本——XTEA(有时也被称为“tean”)。XTEA 跟 TEA 使用了相同的简单运算,但它采用了截然不同的顺序,为了阻止密钥表攻击,四个子密钥(在加密过程中,原 128 位的密钥被拆分为 4 个 32 位的子密钥)采用了一种不太正规的方式进行混合,但速度更慢了。
以下是这个算法的ECMAScript当下版本的实现过程:
class Tea {
private static round: number = 32;
private static key: string = "3A DA 75 21 DB E3 DB B3 62 B7 49 01 A5 C6 EA D5";
public static teaEncrypt(enData: ByteArray): ByteArray {
enData.position = 0;
let len: number = Math.ceil(enData.length / 8);
let keyArr: any[] = this.getKey(this.key);
let keyBytes: ByteArray = new ByteArray();
keyBytes.position;
keyBytes.endian = Endian.LITTLE_ENDIAN;
for (let i = 0; i < keyArr.length; i++) {
keyBytes.writeByte(keyArr[i]);
}
let resData: ByteArray = new ByteArray();
resData.position = 0;
resData.endian = Endian.LITTLE_ENDIAN;
let nData: ByteArray = new ByteArray();
nData.position = 0;
nData.endian = Endian.LITTLE_ENDIAN;
enData.position = 0;
for (let i: number = 0; i < len; i++) {
let enBytes: ByteArray = new ByteArray();
enBytes.position = 0;
enBytes.endian = Endian.LITTLE_ENDIAN;
if (enData.bytesAvailable >= 8) {
enData.readBytes(enBytes, 0, 8);
let encrypted: ByteArray = new ByteArray();
encrypted.position = 0;
encrypted.endian = Endian.LITTLE_ENDIAN;
let encryptencrypted = this.encrypt(enBytes, keyBytes);
resData.writeBytes(encrypted, 0, encrypted.length);
encrypted.clear();
encrypted = null;
} else {
enData.readBytes(nData, 0, enData.bytesAvailable);
}
enBytes.clear();
}
nData.position = 0;
if (nData.length > 0) {
resData.writeBytes(nData, 0, nData.length);
}
keyBytes.clear();
return resData;
enData.clear();
}
public static teaDecrypt(decData: ByteArray): ByteArray {
decData.position = 0;
let len: number = Math.ceil(decData.length / 8);
let keyArr: any[] = this.getKey(this.key);
let keyBytes: ByteArray = new ByteArray();
keyBytes.position;
keyBytes.endian = Endian.LITTLE_ENDIAN;
//将密钥写入缓冲区
for (let i = 0; i < keyArr.length; i++) {
keyBytes.writeByte(keyArr[i]);
}
let resData: ByteArray = new ByteArray();
resData.position = 0;
resData.endian = Endian.LITTLE_ENDIAN;
decData.position = 0;
for (let i: number = 0; i < len; i++) {
let decBytes: ByteArray = new ByteArray();
decBytes.position = 0;
decBytes.endian = Endian.LITTLE_ENDIAN;
if (decData.bytesAvailable >= 8) {
decData.readBytes(decBytes, 0, 8);
let decrypted: ByteArray = new ByteArray();
decrypted.position = 0;
decrypted.endian = Endian.LITTLE_ENDIAN;
let decryptdecrypted = this.decrypt(decBytes, keyBytes);
resData.writeBytes(decrypted, 0, decrypted.length);
decrypted.clear();
} else {
var nData: ByteArray = new ByteArray();
nData.position = 0;
nData.endian = Endian.LITTLE_ENDIAN;
decData.readBytes(nData, 0, decData.bytesAvailable);
}
}
keyBytes.clear();
decData.clear();
trace("解密后数据>>>>" + this.ByteArrayToLongArray(resData, false));
if (nData.length > 0) {
nData.readBytes(resData, 0, nData.length);
}
trace("---->" + nData.length);
return resData;
resData.clear();
}
private static LongArrayToByteArray(data: any[], includeLength: Boolean): ByteArray {
let length: number = data.length;
let n: number = (length - 1) << 2;
if (includeLength) {
let m: number = data[length - 1];
if ((m < n - 3) || (m > n)) {
return null;
}
n = m;
}
let result: ByteArray = new ByteArray();
result.endian = Endian.LITTLE_ENDIAN;
for (let i: number = 0; i < length; i++) {
result.writeUnsignedInt(data[i]);
}
if (includeLength) {
result.length = n;
return result;
} else {
return result;
}
}
private static ByteArrayToLongArray(data: ByteArray, includeLength: Boolean): any[] {
let length: number = data.length;
let n: number = length >> 2;
if (length % 4 > 0) {
n++;
data.length += (4 - (length % 4));
}
data.endian = Endian.LITTLE_ENDIAN;
data.position = 0;
let result: any[] = [];
for (let i: number = 0; i < n; i++) {
result[i] = data.readUnsignedInt();
}
if (includeLength) {
result[n] = length;
}
data.length = length;
return result;
}
private static encrypt(data: ByteArray, key: ByteArray): ByteArray {
if (data.length == 0) {
return new ByteArray();
}
let v: any[] = this.ByteArrayToLongArray(data, false);
let k: any[] = [987395361, 3689143219, 1656178945, 2781276885];
if (k.length < 4) {
k.length = 4;
}
let n: number = v.length - 1;
let y: number = v[0];
let z: number = v[1];
let a: number = k[0];
let b: number = k[1];
let c: number = k[2];
let d: number = k[3];
let delta = 0x9E3779B9;/* (sqrt(5)-1)/2*2^32 */
let sum: number = 0;
for (let i: number = 0; i < this.round; i++) {
sum += delta;
y += ((z << 4) + a) ^ (z + sum) ^ ((z >>> 5) + b);
z += ((y << 4) + c) ^ (y + sum) ^ ((y >>> 5) + d);/* end cycle */
}
v[0] = y;
v[1] = z;
return this.LongArrayToByteArray(v, false);
}
private static decrypt(data: ByteArray, key: ByteArray): ByteArray {
if (data.length == 0) {
return new ByteArray();
}
let v: any[] = this.ByteArrayToLongArray(data, false);
let k: any[] = [987395361, 3689143219, 1656178945, 2781276885];//密钥写死
if (k.length < 4) {
k.length = 4;
}
let n: number = v.length - 1;
let y: number = v[0];
let z: number = v[1];
let a: number = k[0];
let b: number = k[1];
let c: number = k[2];
let d: number = k[3];
let delta = 0x9E3779B9;/* (sqrt(5)-1)/2*2^32 */
let sum: number = 0xE3779B90;
if (this.round == 32) {
sum = 0xC6EF3720;//delta << 5
} else if (this.round == 16) {
sum = 0xE3779B90;
}
for (let i: number = 0; i < this.round; i++) {
z -= ((y << 4) + c) ^ (y + sum) ^ ((y >>> 5) + d);
y -= ((z << 4) + a) ^ (z + sum) ^ ((z >>> 5) + b);
sum -= delta;
}
v[0] = y;
v[1] = z;
return this.LongArrayToByteArray(v, false);
}
private static getKey(keyStr: string): any[] {
let key: string = keyStr;
let arr: any[] = new Array();
let res: any[] = new Array();
let target: any[] = new Array();
arr = key.split(" ");
let curStr: string = "";
let len: number = arr.length;
for (let i: number = 0; i < arr.length; i++) {
let newArr: any[] = new Array();
curStr = arr[i];
for (let j: number = 0; j < 2; j++) {
let char: string = curStr.charAt(j);
newArr.push(char);
}
target.push(newArr);
}
for (let i = 0; i < target.length; i++) {
let a: number = this.isNumber(target[i][0]);
let b: number = this.isNumber(target[i][1]);
let resNum: number = a * 16 + b;
res.push(resNum);
}
return res;
}
private static isNumber(char: string): number {
let arr: any[] = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"];
for (let i: number = 0; i < arr.length; i++) {
if (char == arr[i]) {
return Number(char);
break;
}
}
let id: number = 0;
switch (char) {
case "A":
id = 10;
break;
case "B":
id = 11;
break;
case "C":
id = 12;
break;
case "D":
id = 13;
break;
case "E":
id = 14;
break;
case "F":
id = 15;
break;
default:
break;
}
return id;
}
private static intToHexChar(index: number): string {
let hex: string[] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'];
return hex[index];
}
private static intToHexString(arr: string[]): string {
let myStr: string = "";
for (let i: number = 0; i < arr.length; ++i) {
let t: any = arr[i];
let a: number = Math.floor(t / 16);
let b: number = Math.floor(t % 16);
myStr += this.intToHexChar(a);
myStr += this.intToHexChar(b);
myStr += " ";
}
return myStr;
}
}
function trace(msg: any): void {
console.log(msg);
}
ByteArray和Endian可以自己实现,这里不在赘述。
code enjoy! 🧐🧐🧐
作者:indeex
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。