游戏开发—数据加解密

    数据或文件加密是游戏中常见的需求,针对重要配置文件和敏感数据,加密存储,运行时解密使用,对游戏的安全性是很有必要的。我们项目中对个别配置文件和Lua文件也做了加密处理,加解密算法则采用广泛使用的XXTEA算法,下面简单介绍一下。

    TEA(Tiny Encryption Algorithm)是一种小型的对称加密解密算法,最初是由剑桥计算机实验室的 David Wheeler 和 Roger Needham 在 1994 年设计的。它支持128位密码,可以为 64 位的信息块进行加密,每次加密/解密8字节数据,需要进行 64 轮迭代。该算法使用了一个神秘常数δ作为倍数,来源于黄金比率,以保证每一轮加密都不相同,在程序中为0x9E3779B9。TEA特点是速度快、效率高,实现也非常简单。TEA后续发展出XTEA、Block TEA和XXTEA等版本。其中XXTE算法安全,非常快速,也适合大文件的加解密,所以被项目采用。

    XXTEA代码很简单,网上也有各种版本,下附一个C#版:

public class XXTEA
{
    #region Encrypt
    public static string Encrypt(string source, string key)
    {
        byte[] sourceByteArry = Encoding.UTF8.GetBytes(base64Encode(source));
        if (sourceByteArry.Length == 0)
        {
            return "";
        }

        byte[] keyByteArry = Encoding.UTF8.GetBytes(key);

        return Convert.ToBase64String(ToByteArray(Encrypt(ToUintArray(sourceByteArry, true), ToUintArray(keyByteArry, false)), false));
    }

    public static uint[] Encrypt(uint[] v, uint[] k)
    {
        int n = v.Length - 1;
        if (n < 1)
        {
            return v;
        }
        if (k.Length < 4)
        {
            uint[] Key = new uint[4];
            k.CopyTo(Key, 0);
            k = Key;
        }
        uint z = v[n], y = v[0], delta = 0x9E3779B9, sum = 0, e;
        int 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;
    }

    private static string base64Encode(string data)
    {
        try
        {
            byte[] encData_byte = new byte[data.Length];
            encData_byte = Encoding.UTF8.GetBytes(data);
            string encodedData = Convert.ToBase64String(encData_byte);
            return encodedData;
        }
        catch (Exception e)
        {
            throw new Exception("Error in base64Encode" + e.Message);
        }
    }
    #endregion

    #region Decrypt
    public static string Decrypt(string source, string key)
    {
        if (source.Length == 0)
        {
            return "";
        }

        byte[] bytData = Convert.FromBase64String(source);
        byte[] bytKey = Encoding.UTF8.GetBytes(key);

        return base64Decode(Encoding.UTF8.GetString(ToByteArray(Decrypt(ToUintArray(bytData, false), ToUintArray(bytKey, false)), true)));
    }

    public static uint[] Decrypt(uint[] v, uint[] k)
    {
        int n = v.Length - 1;
        if (n < 1)
        {
            return v;
        }
        if (k.Length < 4)
        {
            uint[] Key = new uint[4];
            k.CopyTo(Key, 0);
            k = Key;
        }
        uint z = v[n], y = v[0], delta = 0x9E3779B9, sum, e;
        int p, q = 6 + 52 / (n + 1);
        sum = unchecked((uint)(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;
    }

    private static string base64Decode(string data)
    {
        try
        {
            byte[] todecode_byte = Convert.FromBase64String(data);
            return Encoding.UTF8.GetString(todecode_byte);
        }
        catch (Exception e)
        {
            throw new Exception("Error in base64Decode" + e.Message);
        }
    }
    #endregion

    private static uint[] ToUintArray(byte[] Data, bool IncludeLength)
    {
        int n = (((Data.Length & 3) == 0) ? (Data.Length >> 2) : ((Data.Length >> 2) + 1));
        uint[] Result;
        if (IncludeLength)
        {
            Result = new uint[n + 1];
            Result[n] = (uint)Data.Length;
        }
        else
        {
            Result = new uint[n];
        }
        n = Data.Length;
        for (int i = 0; i < n; i++)
        {
            Result[i >> 2] |= (uint)Data[i] << ((i & 3) << 3);
        }
        return Result;
    }

    private static byte[] ToByteArray(uint[] Data, bool IncludeLength)
    {
        int n;
        if (IncludeLength)
        {
            n = (int)Data[Data.Length - 1];
        }
        else
        {
            n = Data.Length << 2;
        }
        byte[] Result = new byte[n];
        for (int i = 0; i < n; i++)
        {
            Result[i] = (byte)(Data[i >> 2] >> ((i & 3) << 3));
        }
        return Result;
    }
}

使用方法直接调用加/解密函数即可:

    class Program
    {
        static void Main(string[] args)
        {
            string content = "content_Test";
            string password = "ABC123";
            string encryptString = XXTEA.Encrypt(content, password);
            string result = XXTEA.Decrypt(encryptString, password);
            Console.WriteLine(result);
        }
    }

result输出 "content_Test"

你可能感兴趣的:(游戏开发—数据加解密)