unity字符串信息加密

最近有个想法,想给Unity程序进行加密,设置程序的使用权限,网上找到的方法有多种

1、给程序设置账号和密码,这个不用多说都明白

2、给程序设置使用的时间,如果程序超过这个时间就不能使用程序

3、给程序设置使用次数,如果程序超过使用次数将不能使用程序

4、给程序设置一个特定权限,只有拥有权限才能正常使用程序

不过上面的方式虽然可以起到限制作用,若是找到这些设置的权限信息再修改之后,就可以无视这个权限正常使用程序,既然要设置权限,这肯定不是我们想要的,所以就有了另外一种方式,把这些权限信息转换成无法正常读懂的信息保存就可以了,不过,世界上不存在绝对保密的东西,只要是加密,总会有解密使用的时候,加密之后虽然可以防止别人的修改,若是碰到高手,一样可以破解加密信息,既然还会被破解,那我们为什么还要加密干什么呢,我们要做的就是让别人不那么容易就获取我们的劳动成果。

 

开始重磅加密,在上代码之前,先说下各种加密的种类

加密分为对称加密和非对称加密

对称加密:加密和解密使用同一个密钥的加密方式

常见的对称加密算法有DES、3DES、AES。

 

非对称加密:非对称加密算法需要两个密钥:公开密钥和私有密钥,公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。

常见的非对称加密算法有:RSA、ECC(移动设备用)、DSA(数字签名用)。

 

还有比较特殊的加密,个人觉得不算是加密算法,这就是MD5和Base64编码,为什么说这是不是加密的加密呢,

首先,加密就是把数据转换以后,变成了另一种数据格式,除非拥有解密方式,否则没人能把数据转换回来。

MD5是一种信息摘要算法,是Hash算法的一种,又叫散列算法,Hash通常用于制作数字指纹,它是不可逆的,不可以解密。所以它只能算的上是一种单向加密算法。

Base64是一种数据编码方式,虽然是可逆的,但是它的编码方式是公开的,也就算不上加密。

 

好了,加密种类知道之后,我们就可以开始我们的代码编写进行信息加密

1、MD5 

虽然算不上是加密算法,却常用于确认信息传输是否完整一致,因为对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。

    //MD5散列加密
    void MD5Code()
    {
        string str1 = "Test_String";//需要加密的字符串
        byte[] byteStr = Encoding.UTF8.GetBytes(str1);
        MD5 md5 = MD5.Create();//创建MD5加密类
        byte[] md5Byte = md5.ComputeHash(byteStr);//使用MD5实例的ComputerHash()方法处理流数据

         //把加密后字符流转成可读字符串,由于是加密后流数据,使用Encoding类转换字符串是乱码信息
        string keyMD5 = hexConverter.BytesToHexStr(md5Byte);
        Debug.Log("MD5加密:" + keyMD5);
    }

输出结果:

unity字符串信息加密

2、Base64 

使用 Encoding.GetString 转换,可能得到很多方块或问号,这是由于某些整数序列无法对应于我们现实生活中的文字的原因,只能用方块或问号来代替,

base64绝对不存在任何不可读的字符,ToBase64String 使用 base 64 数字编码,它生成的全部是ASCII 字符,也不存在关键字冲突字符,不需要转义。

注意:不是使用base64编码的文字信息,若是由base64转换成byte[]会出错。

缺点:Base64比起它的原始文本增大约30%。

    //Base64位对称加密
    public void Base64Code()
    {
        string str1 = "Test";//原始字符串
        //加密
        byte[] byteStr = System.Text.Encoding.UTF8.GetBytes(str1);
        string str2 = Convert.ToBase64String(byteStr);//转换后的64位字符串
        Debug.Log("Base64加密:" + str2);
        //解密
        byte[] temp = Convert.FromBase64String(str2);
        string str3 = System.Text.Encoding.UTF8.GetString(temp);//64位恢复字符串
        Debug.Log("Base64解密:" + str3);
    }

输出结果:

unity字符串信息加密

对称加密

1、DES

DES算法只是使用了标准的算术和逻辑运算,其作用的数最多也只有64 位,因此用70年代末期的硬件技术很容易实现算法的重复特性使得它可以非常理想地用在一个专用芯片中。已破解,不再安全,是对称加密算法的基石,具有学习价值

密钥长度56(JDK)、56/64(BC)

    //加密
    public void DesEncry()
    {
        string info = "Test";//需要加密的信息
        string key = "KeysKeys";//密钥

        DESCryptoServiceProvider desc = new DESCryptoServiceProvider();
        byte[] infoByte = Encoding.UTF8.GetBytes(info);
        byte[] keyByte = Encoding.UTF8.GetBytes(key);
        MemoryStream mS = new MemoryStream();
        //使用内存流数据创建加密流数据
        CryptoStream cStream = new CryptoStream(mS, desc.CreateEncryptor(keyByte, keyByte), CryptoStreamMode.Write);
        cStream.Write(infoByte, 0, infoByte.Length);
        cStream.FlushFinalBlock();//更新数据缓冲区

        string data = hexConverter.BytesToHexStr(mS.ToArray());//把加密数据流转成字符串
        Debug.Log("DES加密:" + data);

        //解密
        DesDecry(data);
    }

    //解密
    public void DesDecry(string info)
    {
        byte[] keyByte = Encoding.UTF8.GetBytes("KeysKeys");
        byte[] infoByte = hexConverter.HexStrToBytes(info);//把加密后的密文转换成流数据
        MemoryStream mStream = new MemoryStream();
        DESCryptoServiceProvider descsp = new DESCryptoServiceProvider();
        //使用密钥创建解密数据
        CryptoStream CStream = new CryptoStream(mStream, descsp.CreateDecryptor(keyByte, keyByte), CryptoStreamMode.Write);
        CStream.Write(infoByte, 0, infoByte.Length);
        CStream.FlushFinalBlock();

        //把解密后的数据转成字符串
        string data = Encoding.UTF8.GetString(mStream.ToArray());
        mStream.Close();
        CStream.Close();
        Debug.Log("DES解密:" + data);
    }

2、AES

用来替代原先的DES,已经被多方分析且广为全世界所使用。已然成为对称密钥加密中最流行的算法之一,AES算法在对明文加密的时候,并不是把整个明文一下全部加密成一整段密文,而是把明文拆分成一个个独立的明文块,每一个明文块长度128bit。第二段若是不足128bit,需要对明文进行填充。这些明文块经过AES加密器的复杂处理,生成一个个独立的密文块,这些密文块拼接在一起,就是最终的AES加密结果。

密钥长度128/192/256,其中192与256需要配置无政策限制权限文件(JDK6)

    //加密
    void AESEncry()
    {
        string info = "Test";
        string key = "KeysKeysKeysKeys";//密钥使用128、192 和 256bit三种
        string IV = "KeysKeysTestTest";//密钥偏移量
        byte[] infoByte = Encoding.UTF8.GetBytes(info);
        RijndaelManaged aesM = new RijndaelManaged();
        aesM.Key = Encoding.UTF8.GetBytes(key);
        aesM.IV = Encoding.UTF8.GetBytes(IV);
        aesM.Mode = CipherMode.ECB;
        aesM.Padding = PaddingMode.PKCS7;

        ICryptoTransform cTrans = aesM.CreateEncryptor();
        byte[] resultByte = cTrans.TransformFinalBlock(infoByte, 0, infoByte.Length);

        string AesStr = hexConverter.BytesToHexStr(resultByte);
        Debug.Log("AES加密:" + AesStr);
        
        AESDecry(AesStr);//解密
    }

    //解密
    void AESDecry(string keyData)
    {
        string key = "KeysKeysKeysKeys";//密钥使用128、192 和 256bit三种
        string IV = "KeysKeysTestTest";
        byte[] infoByte = hexConverter.HexStrToBytes(keyData);
        RijndaelManaged aesM = new RijndaelManaged();
        aesM.Key = Encoding.UTF8.GetBytes(key);
        aesM.IV = Encoding.UTF8.GetBytes(IV);
        aesM.Mode = CipherMode.ECB;
        aesM.Padding = PaddingMode.PKCS7;

        ICryptoTransform cTrans = aesM.CreateDecryptor();
        byte[] resultByte = cTrans.TransformFinalBlock(infoByte, 0, infoByte.Length);

        string AesStr = Encoding.UTF8.GetString(resultByte);
        Debug.Log("AES解密:" + AesStr);
    }

非对称加密

1、RSA

RSA是第一个既能用于数据加密也能用于数字签名的算法,原理就是对一极大整数做因数分解的困难性来保证安全性。

加密过程表示:

unity字符串信息加密

由表达式可知,RSA加密是对明文的E次方后除以N后求余数的过程,E、N就是公钥,知道E、N的人就可以进行加密,是不是很简单,不过E、N也并不是那么容易就得到的,需要严格的数学计算才能得到,密钥越大,越不容易破解

解密过程表示:

unity字符串信息加密

密文进行D次方后除以N的余数就是明文,D、N就是密钥

    //公钥
    string publicKey = "<RSAKeyValue><Modulus>nJwV22wLJguL3PSqwpf3eiqK658HFQwwfnBboC5/BW1aQJxNDynvIyRRu8XxQAjMQvnUqWpKuDfoCoq+AiFOhfyA3Yn5WICLRD4/H31x0zHp+dH3wubf5jbKtv16FCT3xPxAet5i6VceTox8C1z3TW82YkK6J0US2Vlwg/+IpkM=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
    //私钥
    string privateKey = "<RSAKeyValue><Modulus>nJwV22wLJguL3PSqwpf3eiqK658HFQwwfnBboC5/BW1aQJxNDynvIyRRu8XxQAjMQvnUqWpKuDfoCoq+AiFOhfyA3Yn5WICLRD4/H31x0zHp+dH3wubf5jbKtv16FCT3xPxAet5i6VceTox8C1z3TW82YkK6J0US2Vlwg/+IpkM=</Modulus><Exponent>AQAB</Exponent><P>n2Qkqfyag7O2vSZqzQC5+c/sGuM5abaAadAE6W+JXwutZbz1KULNnGJFgJJGznZAXXl6cfTxeeBFSsY+rKcR/Q==</P><Q>+4hbFF1+il0MdXjMcFR736Zyk6TMpU5E0MXWEH2RqzgrpUp8nXh8WLaeX2Ug249XIXxWTTMUjRF8BPgQ2xTtPw==</Q><DP>C2YvFRUiu86LgCWSN80Yf9w154pencfWkTq2TzeR3IFKSl9kLSpA6DFDBTnw5G0il0zLzACXkH7QldNtwg1ExQ==</DP><DQ>Dla/mnGZ/RlA1JGGVgD67sz2SyRh5iqIEb61bUs7Op+BHXMZl4B+1i/S521Eaj/Jn8cOxGfdDA2rHD1n+JVA0Q==</DQ><InverseQ>E+XyDAa4uEvZH4zaNGzqaS75BIFHgHG9aCksU4QDp4ecwGeYb5r3pmOZVkJmVlvYlNksm1r4seP6n6YCyzCsSg==</InverseQ><D>f1RYYQJDPjd9C7TRcU1lJKqaMGAnvfEfLG3l0SJ8m8kA7C8oZ//MMmJBIc4aC9obWQkO4n9NKOIrgway3cB+uhssKeZ4H3nQKENvS8F0gml79NKm8n795p+nyooIgDA5wMdre/0DiA6GIOkLHp1K8IXZuXWjxethtM2NWiNc/SE=</D></RSAKeyValue>";
    //创建公钥和密钥   true为私钥,false为公钥
    public void GenerateRSAKey()
    {
        RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
        publicKey = rsa.ToXmlString(false);
        privateKey = rsa.ToXmlString(true);
        Debug.Log("公钥:" + publicKey);
        Debug.Log("私钥:" + privateKey);
    }


    //加密
    void RSAEncrypt()
    {
        string info = "Test";//待加密信息
        byte[] infoByte = Encoding.UTF8.GetBytes(info);
        RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
        rsa.FromXmlString(publicKey);//填入公钥
        byte[] keyInfo = rsa.Encrypt(infoByte, false);//使用公钥加密

        string keyInfoStr = hexConverter.BytesToHexStr(keyInfo);
        Debug.Log("RSA加密:" + keyInfoStr);

        RSADecrypt(keyInfoStr);
    }


    //加密后的字符串数据
    string Key = "529415124F36422C9DABF7125E4EBAA8423DC7FCFF70A7FAC7CA85D480F4D4FC5110675E175EF7CB5ACCE8C38E4BEDE1DFD2334C042B18CD45D13F346B76C8DE0B37FA1BE9A75D8A1E1CABE5F0F0791CF6F9E61F0B5F3073A470A0AE465A0E334F04DC75B91C2A0C67CEFBB5E4145CFB98401015BF3B5285B6E59646F1210FC4";
    //解密
    void RSADecrypt(string keyInfo)
    {
        byte[] keyByte = hexConverter.HexStrToBytes(keyInfo);//加密的字符串数据转换成流数据用于解密
        RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
        rsa.FromXmlString(privateKey);//填入私钥
        byte[] info = rsa.Decrypt(keyByte, false);//解密数据

        string infoStr = Encoding.UTF8.GetString(info);
        Debug.Log("RSA解密:" + infoStr);
    }

2、DSA 

DSA 是基于整数有限域离散对数难题的,DSA的一个重要特点是两个素数公开,这样,当使用别人的p和q时,即使不知道私钥,你也能确认它们是否是随机产生的,还是作了手脚。RSA算法却做不到。这是一种更高级的验证方式,用作数字签名。私钥加密生成数字签名,公钥验证数据及签名,如果数据和签名不匹配则认为验证失败。数字签名的作用就是校验数据在传输过程中不被修改,数字签名,是单向加密的升级。

DSA算法中应用参数:

p:L bits长的素数。L是64的倍数,范围是512到1024;

q:p – 1的160bits的素因子;

g:g = h^((p-1)/q) mod p,h满足h < p – 1, h^((p-1)/q) mod p > 1;

x:x < q,x为私钥 ;

y:y = g^x mod p ,( p, q, g, y )为公钥;

H( x ):One-Way Hash函数。DSS中选用SHA( Secure Hash Algorithm )。

p, q, g可由一组用户共享,但在实际应用中,使用公共模数可能会带来一定的威胁

1、创建密钥

    //公钥
    string publicKey = "<DSAKeyValue><P>krtnWEQWWFgpXWD4FI/l8MFWiyxxP2eg0M4HV0wgwWNf2nfa0kPtMmD4mSNLnWVZkz0ErgqwqOKdLZwl65VXsXyt7WFoi8E/ASuUPbSkdqV377De5De5cluHeRY1nPq1+h8vOFtzOPxun+Rag7S+ych8anXcpaQkjwwmEOFsOL0=</P><Q>tVODutrYbntda40rz2Ri6JZjaGE=</Q><G>ZQWwiHaWlqW5tJfA5s5880v730X8qIYcCy6p3ph6ULshtxQlOKpKSVcPH3u/VN+K16X5HksG+hLykd9qncGNGm3QrbLxid73gzmOT9lrHGidWcUthjcU39QyA/gxsLWU5s9jqCnrZJy9ilEcPkO5ypIIlycxFWNNrNi0SVZztUc=</G><Y>bhfo0+wx/s9isRMHMxC0YvyXIIJB0b1e//8OfYIkvcg06ls67w+8u8uHDCwf+qx6F3VD9aeT+Ew+fyUZiI2UQ3iXW2MbrX49Vdq8zT63CQgQZUMPxbzcYvppXlnbFrb0R10/D6YuLuo9GEELrwf7vE5aIkkJfvnxnGmMyBliqmw=</Y><J>zyjD7pFZAZhLDjCKkQC2LBbOLhgBtC5PPzae1Efek/Pup5XE3yNEhoOUwzbDEupZm5UISPpbQFzOEt5B2U8K6rGlYJyD2IYH+wPe5rmHyaJ9QJQ95sSZ+/oQPXKePJtxe65X81bAqvghrwI8</J><Seed>BNd59HiXB4inIcKR4mz3fT6geLY=</Seed><PgenCounter>1A==</PgenCounter></DSAKeyValue>";
    //私钥
    string privateKey = "<DSAKeyValue><P>krtnWEQWWFgpXWD4FI/l8MFWiyxxP2eg0M4HV0wgwWNf2nfa0kPtMmD4mSNLnWVZkz0ErgqwqOKdLZwl65VXsXyt7WFoi8E/ASuUPbSkdqV377De5De5cluHeRY1nPq1+h8vOFtzOPxun+Rag7S+ych8anXcpaQkjwwmEOFsOL0=</P><Q>tVODutrYbntda40rz2Ri6JZjaGE=</Q><G>ZQWwiHaWlqW5tJfA5s5880v730X8qIYcCy6p3ph6ULshtxQlOKpKSVcPH3u/VN+K16X5HksG+hLykd9qncGNGm3QrbLxid73gzmOT9lrHGidWcUthjcU39QyA/gxsLWU5s9jqCnrZJy9ilEcPkO5ypIIlycxFWNNrNi0SVZztUc=</G><Y>bhfo0+wx/s9isRMHMxC0YvyXIIJB0b1e//8OfYIkvcg06ls67w+8u8uHDCwf+qx6F3VD9aeT+Ew+fyUZiI2UQ3iXW2MbrX49Vdq8zT63CQgQZUMPxbzcYvppXlnbFrb0R10/D6YuLuo9GEELrwf7vE5aIkkJfvnxnGmMyBliqmw=</Y><J>zyjD7pFZAZhLDjCKkQC2LBbOLhgBtC5PPzae1Efek/Pup5XE3yNEhoOUwzbDEupZm5UISPpbQFzOEt5B2U8K6rGlYJyD2IYH+wPe5rmHyaJ9QJQ95sSZ+/oQPXKePJtxe65X81bAqvghrwI8</J><Seed>BNd59HiXB4inIcKR4mz3fT6geLY=</Seed><PgenCounter>1A==</PgenCounter><X>j2XGLOlE6lp4aGEJocs/S7yb5Rw=</X></DSAKeyValue>";

    DSAParameters dsaParameters_public;//公钥对象
    DSAParameters dsaParameters_privat;//私钥对象
    //创建公钥和私钥信息,true为私钥,false为公钥
    public void CreateKeys()
    {
        DSACryptoServiceProvider DSA = new DSACryptoServiceProvider();
        publicKey = DSA.ToXmlString(false);//公钥
        privateKey = DSA.ToXmlString(true);//私钥
        Debug.Log("公钥:" + publicKey);
        Debug.Log("私钥:" + privateKey);

        dsaParameters_public = DSA.ExportParameters(true);
        dsaParameters_privat = DSA.ExportParameters(false);
        Debug.Log("公钥Hash:" + dsaParameters_public.GetHashCode());
        Debug.Log("私钥Hash:" + dsaParameters_privat.GetHashCode());
    }

2、使用密钥的方式验证

    //加密
    public void DSAEncrypt1()
    {
        string str = "Test";//需要加密的信息
        byte[] bytes = Encoding.ASCII.GetBytes(str);
        DSACryptoServiceProvider dsac = new DSACryptoServiceProvider();
        dsac.FromXmlString(privateKey);
        byte[] sign = dsac.SignData(bytes);//DSA签名

        string infoKey = hexConverter.BytesToHexStr(sign);
        Debug.Log("DSA加密:" + infoKey);

        DSADecrypt1(infoKey);
    }
    //解密
    void DSADecrypt1(string infoKey)
    {
        byte[] key = hexConverter.HexStrToBytes("210FA35C4AB3E2E0A49CD4F4D8D0E7D3F4095EEE04340517E5A47148671D7AC60B86D8F0B03624F4");
        byte[] bytes = Encoding.ASCII.GetBytes("Test");
        DSACryptoServiceProvider dsac2 = new DSACryptoServiceProvider();
        dsac2.FromXmlString(publicKey);
        bool isKey = dsac2.VerifyData(bytes, key);//将指定的签名数据与为指定数据计算的签名进行比较来验证指定的签名数据。
        if (isKey)
            Debug.Log("DSA验证成功");
        else
            Debug.Log("DSA验证失败");
    }

3、使用加密对象验证

    //加密
    void DSAEncrypt2()
    {
        CreateKeys();
        DSACryptoServiceProvider DSA = new DSACryptoServiceProvider();
        DSA.ImportParameters(dsaParameters_public);//导入密钥信息,公钥加密,私钥解密,私钥加密,公钥解密

        //官方文档使用 20个ASCLL数字
        //byte[] Data = { 59, 4, 248, 102, 77, 97, 142, 201, 210, 12, 224, 93, 25, 41, 100, 197, 213, 134, 130, 135 };//Hash
        string info = "TestTestTestTestTest";
        byte[] Data = Encoding.ASCII.GetBytes(info);

        DSASignatureFormatter dsaFormatter = new DSASignatureFormatter(DSA);//传递密钥信息
        dsaFormatter.SetHashAlgorithm("SHA1");//设置Hash算法
        byte[] SignKey = dsaFormatter.CreateSignature(Data);//使用Hash算法创建签名

        string KeysInfo = hexConverter.BytesToHexStr(SignKey);
        Debug.Log("DSA加密:" + KeysInfo);

        DSADecrypt(KeysInfo);
    }

    //解密
    public void DSADecrypt(string infoKey)
    {
        byte[] infoByte = hexConverter.HexStrToBytes(infoKey);
        byte[] Data = Encoding.ASCII.GetBytes("TestTestTestTestTest");
        //byte[] Data = { 59, 4, 248, 102, 77, 97, 142, 201, 210, 12, 224, 93, 25, 41, 100, 197, 213, 134, 130, 135 };
        DSACryptoServiceProvider DSA = new DSACryptoServiceProvider();
        DSA.ImportParameters(dsaParameters_privat);
        DSASignatureDeformatter dsaDeformatter = new DSASignatureDeformatter(DSA);
        dsaDeformatter.SetHashAlgorithm("SHA1");
        bool isKey = dsaDeformatter.VerifySignature(Data, infoByte);
        if (isKey)
            Debug.Log("验证成功");
        else
            Debug.Log("验证失败");
    }

 

PS:DSA方式验证,没有明白,我查到官方文档是使用的验证DSAParameters 的方式验证明文和密文,虽然可以验证,在使用的时候不可能同时使用加密解密一起吧,而若是不同时使用,公钥对象和密钥对象又不是一起生成的,这样的验证方式还可以吗?所以实在没明白这块,若有大佬指点迷津,非常感激。

以上内容所有代码使用C#和Unity,完整代码包括添加时间限制和使用次数限制,若是由想要完整代码的可以下载。

源码下载链接:https://download.csdn.net/download/weixin_39186306/12231208

 

上一篇:DSA_03:数组


下一篇:如何在Java中使用OPENSSH私钥?