TEA加密算法

内容纲要

加密算法用处渐渐多了起来,可以使用简单的加密算法对JS加密/解密,这里实现一个简单的微加密算法。

微加密算法(TEA)及其相关变种(XTEA,Block TEA,XXTEA) 都是分组加密算法,实现也比较简单。

TEA加密算法

  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

链接:https://indeex.cc

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


发表评论

您的电子邮箱地址不会被公开。