Compact Framework 的 Tiny Encryption Algorithm (TEA)
了解如何使用 TEA 加密来保护敏感数据。
引言
Compact Framework 省略了 Cryptography 命名空间中的主要加密功能,以便为更重要的功能腾出空间。 幸运的是,实现某种加密来隐藏您的敏感数据并非难事。 我想找到一种安全且可移植的小型算法。 经过一番搜索,我偶然发现了微型加密算法 (TEA)。 该算法由剑桥大学的 David Wheeler 和 Roger Needham 于 1994 年开发。 该算法非常便携且速度快。 原始 TEA 算法已经成功进行了密码分析,导致原始作者修改了 TEA 算法。 修改后的算法称为 XTEA。 关于此算法的信息不多,因此无法保证 XTEA 算法也未被破解。 但是,对于不需要最高安全性的应用程序,此算法仍然有用。 原始算法是用 C 语言开发的,但构造方式使其易于移植到其他语言,如 C#。 我能够以最小的更改将原始 C 算法移植到 C#。 我在完整的 .NET Framework 以及 .NET Compact Framework 上测试了该算法,它在两个平台上都运行良好,无需任何更改。
有关 TEA 加密如何工作的更多信息,请参阅本文底部的链接。
背景
微型加密算法基于成对的数据块的原理。 这使得准备用于加密的字符串更具挑战性,因为您需要将无符号整数对传递给算法,然后以某种方式存储它们,以便可以在以后的某个时间点恢复数据。 我使用一些位移来在整数和字符串之间进行转换,因此对数字系统的一些了解将对您有所帮助。
使用代码
将代码移植到 C# 很容易。 将 C 算法移植到 C# 后,我最终得到以下加密函数
private void code(uint[] v, uint[] k)
{
uint y = v[0];
uint z = v[1];
uint sum = 0;
uint delta=0x9e3779b9;
uint n=32;
while(n-->0)
{
y += (z << 4 ^ z >> 5) + z ^ sum + k[sum & 3];
sum += delta;
z += (y << 4 ^ y >> 5) + y ^ sum + k[sum >> 11 & 3];
}
v[0]=y;
v[1]=z;
}
简单吧? 它们不是没有理由称之为微型! 这是解密函数
private void decode(uint[] v, uint[] k)
{
uint n=32;
uint sum;
uint y=v[0];
uint z=v[1];
uint delta=0x9e3779b9;
sum = delta << 5 ;
while(n-->0)
{
z -= (y << 4 ^ y >> 5) + y ^ sum + k[sum >> 11 & 3];
sum -= delta;
y -= (z << 4 ^ z >> 5) + z ^ sum + k[sum & 3];
}
v[0]=y;
v[1]=z;
}
注意:我只修改了编译代码所需的内容。 我还格式化了代码,使其更易于阅读。 在原始算法中,他们使用 unsigned long 作为变量。 在 C 中,unsigned 是一个 32 位无符号整数。 在 .NET 领域中,等效的是一个无符号整数。
现在我们已经到了具有挑战性的部分。 要将该算法与字符串一起使用,我们必须将字符串转换为可接受的格式。 这是我为使用该算法所做工作的基本过程
- 如有必要,通过在字符串末尾添加空格,使字符串的长度为偶数。 我们需要这样做,因为该算法期望成对的数据。
- 将字符串转换为字节数组。
- 循环遍历数组并将一对值传递给加密函数。
- 将两个密码值转换为字符串并附加到一个长字符串。
我的 Encrypt
函数看起来像这样
public string Encrypt(string Data, string Key)
{
uint[] formattedKey = FormatKey(Key);
if(Data.Length%2!=0) Data += '\0'; // Make sure array is even in length.
byte[] dataBytes = System.Text.ASCIIEncoding.ASCII.GetBytes(Data);
string cipher = string.Empty;
uint[] tempData = new uint[2];
for(int i=0; i<dataBytes.Length; i+=2)
{
tempData[0] = dataBytes[i];
tempData[1] = dataBytes[i+1];
code(tempData, formattedKey);
cipher += ConvertUIntToString(tempData[0]) +
ConvertUIntToString(tempData[1]);
}
return cipher;
}
Decrypt
函数基本上只是加密函数的反向操作
public string Decrypt(string Data, string Key)
{
uint[] formattedKey = FormatKey(Key);
int x = 0;
uint[] tempData = new uint[2];
byte[] dataBytes = new byte[Data.Length / 8 * 2];
for(int i=0; i<Data.Length; i+=8)
{
tempData[0] = ConvertStringToUInt(Data.Substring(i, 4));
tempData[1] = ConvertStringToUInt(Data.Substring(i+4, 4));
decode(tempData, formattedKey);
dataBytes[x++] = (byte)tempData[0];
dataBytes[x++] = (byte)tempData[1];
}
string decipheredString =
System.Text.ASCIIEncoding.ASCII.GetString(dataBytes,
0, dataBytes.Length);
// Strip the null char if it was added.
if(decipheredString[decipheredString.Length - 1] == '\0')
decipheredString = decipheredString.Substring(0,
decipheredString.Length - 1);
return decipheredString;
}
ConvertUIntToString
函数利用一些移位和按位与 (&) 将 32 位无符号整数转换为长度为 4 的字符串。 由于一个字符的长度为 1 字节,我们可以组合 4 个字符来生成 4 个字节或 32 位。 哇,这将很好地保存一个 32 位无符号整数 (uint
)! 哇!private string ConvertUIntToString(uint Input)
{
System.Text.StringBuilder output = new System.Text.StringBuilder();
output.Append((char)((Input & 0xFF)));
output.Append((char)((Input >> 8) & 0xFF));
output.Append((char)((Input >> 16) & 0xFF));
output.Append((char)((Input >> 24) & 0xFF));
return output.ToString();
}
这是撤消 ConvertUIntToString
操作的函数
private uint ConvertStringToUInt(string Input)
{
uint output;
output = ((uint)Input[0]);
output += ((uint)Input[1] << 8);
output += ((uint)Input[2] << 16);
output += ((uint)Input[3] << 24);
return output;
}
将移位的输入与 0xFF
进行与运算将仅返回 1 个字节。
示例代码包括 .NET Framework 和 .NET Compact Framework 的示例应用程序。
关注点
历史
- 2004 年 2 月 29 日 - 将 XTEA 算法添加到文章和源代码。
- 2004 年 2 月 19 日 - 原始文章。