XXTEA 加密算法的 C# 实现

原创作品,欢迎转载,转载请注明出处。

前面我在 XXTEA 加密算法的 JavaScript 和 PHP 实现 一文中介绍了 XXTEA 加密算法,并给出了 JavaScript 和 PHP 两种实现,并且将其应用到了 PHPRPC 中。最近打算写 PHPRPC 的 .NET 实现,因此写了这个 C# 实现的 XXTEA 加密算法。因为感觉 .NET 的加密体系太过复杂,而且 .NET 加密体系中的加密算法都是需要一个 Key 和一个 IV,但是其他语言中加密算法(比如 Java 或 PHP)都是只需要一个 Key,为了让 .NET 加密的内容用其他语言中的实现也能够解密,因此我写的XXTEA 加密算法实现没有继承自 .NET 加密算法类,并且用法非常简单,全都是静态方法,无须创建对象,加密的内容用其它语言实现的算法也可以解密,反之亦然。下面是算法代码:

xxtea.cs
  1. /* XXTEA.cs
  2. *
  3. * Author:       Ma Bingyao <andot@ujn.edu.cn>
  4. * Copyright:    CoolCode.CN
  5. * Version:      1.4
  6. * LastModified: 2006-07-23
  7. * This library is free.  You can redistribute it and/or modify it.
  8. * http://www.coolcode.cn/?p=163
  9. */
  10.  
  11. using System;
  12.  
  13. public class XXTEAException : Exception
  14. {
  15.     public XXTEAException() { }
  16.     public XXTEAException(string message) : base(message) { }
  17.     public XXTEAException(string message, Exception inner) : base(message, inner) { }
  18. }
  19.  
  20. public class XXTEA
  21. {
  22.     private XXTEA()
  23.     {
  24.     }
  25.     public static Byte[] Encrypt(Byte[] Data, Byte[] Key)
  26.     {
  27.         if (Data.Length == 0)
  28.         {
  29.             return Data;
  30.         }
  31.         return ToByteArray(Encrypt(ToUInt32Array(Data, true), ToUInt32Array(Key, false)), false);
  32.     }
  33.     public static Byte[] Decrypt(Byte[] Data, Byte[] Key)
  34.     {
  35.         if (Data.Length == 0)
  36.         {
  37.             return Data;
  38.         }
  39.         return ToByteArray(Decrypt(ToUInt32Array(Data, false), ToUInt32Array(Key, false)), true);
  40.     }
  41.  
  42.     public static UInt32[] Encrypt(UInt32[] v, UInt32[] k)
  43.     {
  44.         Int32 n = v.Length - 1;
  45.         if (n < 1)
  46.         {
  47.             return v;
  48.         }
  49.         if (k.Length < 4)
  50.         {
  51.             UInt32[] Key = new UInt32[4];
  52.             k.CopyTo(Key, 0);
  53.             k = Key;
  54.         }
  55.         UInt32 z = v[n], y = v[0], delta = 0x9E3779B9, sum = 0, e;
  56.         Int32 p, q = 6 + 52 / (n + 1);
  57.         while (0 < q--)
  58.         {
  59.             sum = unchecked(sum + delta);
  60.             e = sum >> 2 & 3;
  61.             for (p = 0; p < n; p++)
  62.             {
  63.                 y = v[p + 1];
  64.                 z = unchecked(v[p] += (z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z));
  65.             }
  66.             y = v[0];
  67.             z = unchecked(v[n] += (z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z));
  68.         }
  69.         return v;
  70.     }
  71.     public static UInt32[] Decrypt(UInt32[] v, UInt32[] k)
  72.     {
  73.         Int32 n = v.Length - 1;
  74.         if (n < 1)
  75.         {
  76.             return v;
  77.         }
  78.         if (k.Length < 4)
  79.         {
  80.             UInt32[] Key = new UInt32[4];
  81.             k.CopyTo(Key, 0);
  82.             k = Key;
  83.         }
  84.         UInt32 z = v[n], y = v[0], delta = 0x9E3779B9, sum, e;
  85.         Int32 p, q = 6 + 52 / (n + 1);
  86.         sum = unchecked((UInt32)(q * delta));
  87.         while (sum != 0)
  88.         {
  89.             e = sum >> 2 & 3;
  90.             for (p = n; p > 0; p--)
  91.             {
  92.                 z = v[p - 1];
  93.                 y = unchecked(v[p] -= (z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z));
  94.             }
  95.             z = v[n];
  96.             y = unchecked(v[0] -= (z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z));
  97.             sum = unchecked(sum - delta);
  98.         }
  99.         return v;
  100.     }
  101.     private static UInt32[] ToUInt32Array(Byte[] Data, Boolean IncludeLength)
  102.     {
  103.         Int32 n = (((Data.Length & 3) == 0) ? (Data.Length >> 2) : ((Data.Length >> 2) + 1));
  104.         UInt32[] Result;
  105.         if (IncludeLength)
  106.         {
  107.             Result = new UInt32[n + 1];
  108.             Result[n] = (UInt32)Data.Length;
  109.         }
  110.         else
  111.         {
  112.             Result = new UInt32[n];
  113.         }
  114.         n = Data.Length;
  115.         for (Int32 i = 0; i < n; i++)
  116.         {
  117.             Result[i >> 2] |= (UInt32)Data[i] << ((i & 3) << 3);
  118.         }
  119.         return Result;
  120.     }
  121.     private static Byte[] ToByteArray(UInt32[] Data, Boolean IncludeLength)
  122.     {
  123.         Int32 n = Data.Length << 2;
  124.         if (IncludeLength)
  125.         {
  126.             Int32 m = (Int32)Data[Data.Length - 1];
  127.             if (m > n)
  128.             {
  129.                 throw new XXTEAException("XXTEA Decrypt Error: Wrong input data.");
  130.             }
  131.             else {
  132.                 n = m;
  133.             }
  134.         }
  135.         Byte[] Result = new Byte[n];
  136.         for (Int32 i = 0; i < n; i++)
  137.         {
  138.             Result[i] = (Byte)(Data[i >> 2] >> ((i & 3) << 3));
  139.         }
  140.         return Result;
  141.     }
  142. }

需要注意的是,这里加密的是字节数组,而不是字符串。因为 C# 字符串是按照 Unicode 编码保存的。要加密字符串的话,需要用 System.Text.Encoding.UTF8 (或者其他编码器)的 GetBytes 方法转化为字节数组,然后才能对其加密,密钥也是一样的。密钥长度是 128 位,也就是 16 个元素的字节数组,不过少于 16 个字节或多于 16 个字节都可以正常工作,少于 16 个字节时,会自动通过补零来充填到 16 个字节,多于 16 个字节之后的元素会被忽略。

另外还需要注意一点,加密以后的内容也是字节数组,但是你不能用 System.Text.Encoding.UTF8 把它转化为字符串,否则会造成信息丢失。

你还可以通过下载该实例来了解如何使用该算法进行加密:xxtea.cs.zip

标签: Cryptology, .NET

« 上一篇 | 下一篇 »

只显示10条记录相关文章

2 条回复至 "XXTEA 加密算法的 C# 实现" 的评论

前面说的UTF8转换为字节数组时,是因为转换的是原文,后面说的不能用UTF8转换的是指加密后的密文,密文只有在解密成原文之后才能再次转换为字符串。

andot 于 2011-07-30 12:13:43 提交#1

”但是你不能用 System.Text.Encoding.UTF8 把它转化为字符串,否则会造成信息丢失。“
前面说可以用UTF8转字节数组,后面有说不能用UTF8 转化?????

由 quht 于 2011-07-28 23:49:49 提交#2


发表评论

评论 (必须):