TEA和XxTEA跨平台加密算法

   TEA(Tiny Encryption Algorithm)是一种小型的对称加密解密算法,支持128位密码,与BlowFish一样TEA每次只能加密/解密8字节数据。TEA特点是速度快、效率高,实现也非常简单。由于针对TEA的攻击不断出现,所以TEA也发展出几个版本,分别是XTEA、Block TEA和XXTEA。

    TEA加密和解密时都使用一个常量值,这个常量值为0x9e3779b,这个值是近似黄金分割率,注意,有些编程人员为了避免在程序中直接出现"mov 变量,0x9e3779b",以免被破解者直接搜索0x9e3779b这个常数得知使用TEA算法,所以有时会使用"sub 变量,0x61C88647"代替"mov 变量,0x9e3779b",0x61C88647=-(0x9e3779b)。

     TEA算法每一次可以操作64bit(8byte),采用128bit(16byte)作为key,算法采用迭代的形式,推荐的迭代轮数是64轮,最少32轮。 

     标准的16轮运算TEA,如果要改成标准的32轮运算TEA,只需修改code和decode中的n为32,并将decode中的delta左移4位改成左移5位即可。

C#的实现代码:

复制代码
publicstaticclass Tea
    {

        publicstaticbyte[] Encrypt(byte[] data, byte[] key)
        {

            byte[] dataBytes;
            if (data.Length %2==0)
            {
                dataBytes = data;

            }
            else
            {
                dataBytes =newbyte[data.Length +1];
                Array.Copy(data, 0, dataBytes, 0, data.Length);
                dataBytes[data.Length] =0x0;

            }
            byte[] result =newbyte[dataBytes.Length *4];
            uint[] formattedKey = FormatKey(key);
            uint[] tempData =newuint[2];
            for (int i =0; i < dataBytes.Length; i +=2)
            {
                tempData[0] = dataBytes[i];
                tempData[1] = dataBytes[i +1];
                code(tempData, formattedKey);
                Array.Copy(ConvertUIntToByteArray(tempData[0]), 0, result, i *4, 4);
                Array.Copy(ConvertUIntToByteArray(tempData[1]), 0, result, i *4+4, 4);
            }
            return result;
        }

        publicstaticbyte[] Decrypt(byte[] data, byte[] key)
        {
            uint[] formattedKey = FormatKey(key);
            int x =0;
            uint[] tempData =newuint[2];
            byte[] dataBytes =newbyte[data.Length /8*2];
            for (int i =0; i < data.Length; i +=8)
            {
                tempData[0] = ConvertByteArrayToUInt(data, i);
                tempData[1] = ConvertByteArrayToUInt(data, i +4);
                decode(tempData, formattedKey);
                dataBytes[x++] = (byte)tempData[0];
                dataBytes[x++] = (byte)tempData[1];
            }
            //修剪添加的空字符
if (dataBytes[dataBytes.Length -1] ==0x0)
            {
                byte[] result =newbyte[dataBytes.Length -1];
                Array.Copy(dataBytes, 0, result, 0, dataBytes.Length -1);
            }
            return dataBytes;

        }

        staticuint[] FormatKey(byte[] key)
        {
            if (key.Length ==0)
                thrownew ArgumentException("Key must be between 1 and 16 characters in length");
            byte[] refineKey =newbyte[16];
            if (key.Length <16)
            {
                Array.Copy(key, 0, refineKey, 0, key.Length);
                for (int k = key.Length; k <16; k++)
                {
                    refineKey[k] =0x20;
                }
            }
            else
            {
                Array.Copy(key, 0, refineKey, 0, 16);
            }
            uint[] formattedKey =newuint[4];
            int j =0;
            for (int i =0; i < refineKey.Length; i +=4)
                formattedKey[j++] = ConvertByteArrayToUInt(refineKey, i);
            return formattedKey;
        }
        #region Tea Algorithm
        staticvoid code(uint[] v, uint[] k)
        {
            uint y = v[0];
            uint z = v[1];
            uint sum =0;
            uint delta =0x9e3779b9;
            uint n =16;
            while (n-->0)
            {
                sum += delta;
                y += (z <<4) + k[0] ^ z + sum ^ (z >>5) + k[1];
                z += (y <<4) + k[2] ^ y + sum ^ (y >>5) + k[3];
            }
            v[0] = y;
            v[1] = z;
        }

        staticvoid decode(uint[] v, uint[] k)
        {
            uint n =16;
            uint sum;
            uint y = v[0];
            uint z = v[1];
            uint delta =0x9e3779b9;
            /*
            * 由于进行16轮运算,所以将delta左移4位,减16次后刚好为0.
            */
            sum = delta <<4;
            while (n-->0)
            {
                z -= (y <<4) + k[2] ^ y + sum ^ (y >>5) + k[3];
                y -= (z <<4) + k[0] ^ z + sum ^ (z >>5) + k[1];
                sum -= delta;
            }
            v[0] = y;
            v[1] = z;
        }
        #endregion

        privatestaticbyte[] ConvertUIntToByteArray(uint v)
        {
            byte[] result =newbyte[4];
            result[0] = (byte)(v &0xFF);
            result[1] = (byte)((v >>8) &0xFF);
            result[2] = (byte)((v >>16) &0xFF);
            result[3] = (byte)((v >>24) &0xFF);
            return result;
        }

        privatestaticuint ConvertByteArrayToUInt(byte[] v, int offset)
        {
            if (offset +4> v.Length) return0;
            uint output;
            output = (uint)v[offset];
            output |= (uint)(v[offset +1] <<8);
            output |= (uint)(v[offset +2] <<16);
            output |= (uint)(v[offset +3] <<24);
            return output;
        }
    }
复制代码

     XTEA 跟 TEA 使用了相同的简单运算,但它采用了截然不同的顺序,为了阻止密钥表攻击,四个子密钥(在加密过程中,原 128 位的密钥被拆分为 4 个 32 位的子密钥)采用了一种不太正规的方式进行混合,但速度更慢了。在跟描述 XTEA 算法的同一份报告中,还介绍了另外一种被称为 Block TEA 算法的变种,它可以对 32 位大小任意倍数的变量块进行操作。该算法将 XTEA 轮循函数依次应用于块中的每个字,并且将它附加于它的邻字。该操作重复多少轮依赖于块的大小,但至少需要 6 轮。该方法的优势在于它无需操作模式(CBC,OFB,CFB 等),密钥可直接用于信息。对于长的信息它可能比 XTEA 更有效率。在 1998 年,Markku-Juhani Saarinen 给出了一个可有效攻击 Block TEA 算法的代码,但之后很快 David J. Wheeler 和 Roger M. Needham 就给出了 Block TEA 算法的修订版,这个算法被称为 XXTEA。XXTEA 使用跟 Block TEA 相似的结构,但在处理块中每个字时利用了相邻字。它利用一个更复杂的 MX 函数代替了 XTEA 轮循函数,MX 使用 2 个输入量。

     如果加密字符串长度不是 4 的整数倍,则这些实现的在加密后无法真正还原,还原以后的字符串实际上与原字符串不相等,而是后面多了一些 \0 的字符,或者少了一些 \0 的字符。原因在于 XXTEA 算法只定义了如何对 32 位的信息块数组(实际上是 32 位无符号整数数组)进行加密,而并没有定义如何来将字符串编码为这种数组。而现有的实现中在将字符串编码为整数数组时,都丢失了字符串长度信息,因此还原出现了问题。

C#的实现代码

复制代码
using System;

class XXTEA
{
    publicstatic Byte[] Encrypt(Byte[] Data, Byte[] Key)
    {
        if (Data.Length ==0)
        {
            return Data;
        }
        return ToByteArray(Encrypt(ToUInt32Array(Data, true), ToUInt32Array(Key, false)), false);
    }
    publicstatic Byte[] Decrypt(Byte[] Data, Byte[] Key)
    {
        if (Data.Length ==0)
        {
            return Data;
        }
        return ToByteArray(Decrypt(ToUInt32Array(Data, false), ToUInt32Array(Key, false)), true);
    }

    publicstatic UInt32[] Encrypt(UInt32[] v, UInt32[] k)
    {
        Int32 n = v.Length -1;
        if (n <1)
        {
            return v;
        }
        if (k.Length <4)
        {
            UInt32[] Key =new UInt32[4];
            k.CopyTo(Key, 0);
            k = Key;
        }
        UInt32 z = v[n], y = v[0], delta =0x9E3779B9, sum =0, e;
        Int32 p, q =6+52/ (n +1);
        while (q-->0)
        {
            sum =unchecked(sum + delta);
            e = sum >>2&3;
            for (p =0; p < n; p++)
            {
                y = v[p +1];
                z =unchecked(v[p] += (z >>5^ y <<2) + (y >>3^ z <<4) ^ (sum ^ y) + (k[p &3^ e] ^ z));
            }
            y = v[0];
            z =unchecked(v[n] += (z >>5^ y <<2) + (y >>3^ z <<4) ^ (sum ^ y) + (k[p &3^ e] ^ z));
        }
        return v;
    }
    publicstatic UInt32[] Decrypt(UInt32[] v, UInt32[] k)
    {
        Int32 n = v.Length -1;
        if (n <1)
        {
            return v;
        }
        if (k.Length <4)
        {
            UInt32[] Key =new UInt32[4];
            k.CopyTo(Key, 0);
            k = Key;
        }
        UInt32 z = v[n], y = v[0], delta =0x9E3779B9, sum, e;
        Int32 p, q =6+52/ (n +1);
        sum =unchecked((UInt32)(q * delta));
        while (sum !=0)
        {
            e = sum >>2&3;
            for (p = n; p >0; p--)
            {
                z = v[p -1];
                y =unchecked(v[p] -= (z >>5^ y <<2) + (y >>3^ z <<4) ^ (sum ^ y) + (k[p &3^ e] ^ z));
            }
            z = v[n];
            y =unchecked(v[0] -= (z >>5^ y <<2) + (y >>3^ z <<4) ^ (sum ^ y) + (k[p &3^ e] ^ z));
            sum =unchecked(sum - delta);
        }
        return v;
    }
    privatestatic UInt32[] ToUInt32Array(Byte[] Data, Boolean IncludeLength)
    {
        Int32 n = (((Data.Length &3) ==0) ? (Data.Length >>2) : ((Data.Length >>2) +1));
        UInt32[] Result;
        if (IncludeLength)
        {
            Result =new UInt32[n +1];
            Result[n] = (UInt32)Data.Length;
        }
        else
        {
            Result =new UInt32[n];
        }
        n = Data.Length;
        for (Int32 i =0; i < n; i++)
        {
            Result[i >>2] |= (UInt32)Data[i] << ((i &3) <<3);
        }
        return Result;
    }
    privatestatic Byte[] ToByteArray(UInt32[] Data, Boolean IncludeLength)
    {
        Int32 n;
        if (IncludeLength)
        {
            n = (Int32)Data[Data.Length -1];
        }
        else
        {
            n = Data.Length <<2;
        }
        Byte[] Result =new Byte[n];
        for (Int32 i =0; i < n; i++)
        {
            Result[i] = (Byte)(Data[i >>2] >> ((i &3) <<3));
        }
        return Result;
    }
}
复制代码
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值