65.9K
CodeProject 正在变化。 阅读更多。
Home

TEA 加密/解密变得简单

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.60/5 (10投票s)

2008 年 12 月 8 日

CPOL

5分钟阅读

viewsIcon

111601

downloadIcon

5484

易于使用的加密类,支持 TEA、XTEA 和 XXTEA 标准

tea.jpg

引言

当我们要根据简单数据类型隐藏用户数据时,有时可以寻求一种简单明了的方法——例如一个类、一个库或一个 DLL 等——而不必深入研究仅供专家使用的各种细节和加密理论。这个小型项目就是关于这个的。通过使用其中的唯一类 CEncryptDecrypt,你可以能够加密和解密简单数据类型,例如在 C 中与注册表进行数据的往返。

背景

基本思路保持简单:起初我想安全地将 PIN 码隐藏在注册表中。只想将 PIN 码写下来,然后在稍后读取它给需要它的(另一个)程序。为此,我必须先加密值,例如“2416”,然后将其传递,然后稍后做相反的事情将其读回。我当时**不知道**如何做到“相当”安全——所以一开始,我只是简单地搜索了这个问题,而不是陷入我无法理解的、可能有点小题大做的加密 API 中。很快,我在维基百科(Wiki)上找到了一系列或多或少相关联的文章。因此,此代码基于 Wiki 知识,**而非**加密 API。

另外,在下载并阅读这篇文章时,请记住我绝不是加密专家——绝非如此,我才刚刚开始——再次重申;我只想用简单的方式进行加密……然后,也许有一天会更深入地研究其背后的理论和数学。关于这些主题的讨论,请关注我添加到类核心方法的链接——即:TEAXTEAXXTEA

Using the Code

该类基于三个算法:小型加密算法(称为TEA)以及两个扩展且更安全的版本,称为XTEAXXTEA,可以看作是第一个的派生。

下面是对如何使用该项目和代码的简要描述。从外部来看,这确实很简单——正如我所希望的那样。

构建项目并运行对话框。现在您可以加密/解密:intTCHARCString——这在第一个版本和大多数企业中已经足够。要加密一个 int,请按“Encrypt int”,要恢复它,请按“Decrypt int”。其他类型也类似。我清楚有些人或许可以用他们的超级计算机和超级大脑来破解这种加密,但对于普通用户来说,这应该足够了——我希望如此。 :-) 此外,文章和互联网上充斥着关于攻击原理的信息——这很有趣,但超出了我的文章范围,也超出了一个快速的、95% 和“相当安全”的解决方案的范畴。反正没有什么是足够好的,也没有是100%的。

//
// To create a CEncryptDecrypt instance.
//
m_pEncryptDecrypt = new CEncryptDecrypt();

这使您默认访问最简单的标准 - TEA。

//
// To use another standard.
//
new CEncryptDecrypt(CEncryptDecrypt::eXTEA)
// or
new CEncryptDecrypt(CEncryptDecrypt::eXXTEA)

或者在运行时调用 m_pEncryptDecrypt->SetEncryptionStandard(CEncryptDecrypt::eXTEA)。要加密一个值,您需要进行

//
// To encrypt.
//
m_pEncryptDecrypt->Encrypt(456)
// or
m_pEncryptDecrypt->Encrypt('F')
// or
m_pEncryptDecrypt->Encrypt(CString(_T("Hey you."))).

当对象处于**加密**状态时,值保存在类内部的一个向量中。然后,该类提供方法来从向量构建逗号分隔列表,或将逗号分隔列表构建到向量中。这样,向量就可以被擦除,然后重新构建,并在此期间存储在文件或注册表中。反向进行解密——不出所料——同样简单。

//
// To decrypt.
//
int iVal = 0;
m_pEncryptDecrypt->Decrypt(iVal)
// or
TCHAR chVal = 0;
m_pEncryptDecrypt->Decrypt(chVal)
// or
CString cstrVal(_T(""));
m_pEncryptDecrypt->Decrypt(cstrVal)

就这些了,各位——给小白看的加密。

C 语言中的 TEA

TEAXTEA 中,密钥大小为 128 位,而在 XXTEA 中则更大(>= 4 个 32 位字)。要使其工作,您还需要确定一个神奇且任意的数字——要理解它是如何工作的,请在实现中找到:#define MAGIC_KEY 3594。这或多或少是 Wiki 定义 TEA 例程的方式。

inline const void TEAEncrypt(const int iOffset)
// Core encryption method (TEA) inspired from
// http://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm.
{
	ULONG ulSum = 0;
	ULONG ulVec[SIZE_OF_VEC_TEA] = { GetVec(iOffset + 0), GetVec(iOffset + 1) };
	for(register int iBit = 0; iBit < 32; iBit++)
	{
		ulSum += m_ulDelta;
		ulVec[0] += ((ulVec[1] << 4) + m_uKey[0]) ^
			(ulVec[1] + ulSum) ^ ((ulVec[1] >> 5) + m_uKey[1]);
		ulVec[1] += ((ulVec[0] << 4) + m_uKey[2]) ^
			(ulVec[0] + ulSum) ^ ((ulVec[0] >> 5) + m_uKey[3]);
	}
	SetVec(iOffset + 0, ulVec[0]);
	SetVec(iOffset + 1, ulVec[1]);
}
inline const void TEADecrypt(const int iOffset)
// Core decryption method (TEA) inspired from
// http://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm.
{
	ULONG ulSum = 0xc6ef3720;
	ULONG ulVec[SIZE_OF_VEC_TEA] = { GetVec(iOffset + 0), GetVec(iOffset + 1) };
	for(register int iBit = 0; iBit < 32; iBit++)
	{
		ulVec[1] -= ((ulVec[0] << 4) + m_uKey[2]) ^
			(ulVec[0] + ulSum) ^ ((ulVec[0] >> 5) + m_uKey[3]);
		ulVec[0] -= ((ulVec[1] << 4) + m_uKey[0]) ^
			(ulVec[1] + ulSum) ^ ((ulVec[1] >> 5) + m_uKey[1]);
		ulSum -= m_ulDelta;
	}
	SetVec(iOffset + 0, ulVec[0]);
	SetVec(iOffset + 1, ulVec[1]);
}

至于其他,请参阅实现细节。XXTEA 的实现被拆分成了两部分,而不是像 Wiki 建议的那样是单独一部分。暴露的用于调用加密/解密逻辑的 public 方法会根据您想处理的标准(通过 enum EEncryptDecryptStandard)将调用导向到下面的一级正确方法。加密/解密时不要更改标准!始终使用相同的标准进行加密/解密——就像 XTEA!为了更好地理解机制,请参阅 TEA,其中有操作员级别等正在发生的事情的图形显示。为了稍微加快速度,我正在处理原始类拥有的核心方法中的向量部分的本地对应部分。这就是为什么我在执行任何操作之前**复制到**数组,之后**从**数组复制到向量,使用 SetVec(...)/GetVec(...)

关注点

此类可以毫无问题地转换为 C# 类——所有代码都是内联的。该项目是 VC8.0 版本,本应是 9.0——但我的环境目前不愿意让我通过向导构建 MFC 对话框。但这真的不重要。请提出改进该类的想法。我不是说这些算法是最好的,但它们很小且易于实现。我认为将来很容易扩展该类,添加更多甚至更安全的加密例程。Wiki 似乎有很多。

问题与想法

我不觉得逗号分隔列表算是一个优雅的解决方案。也许将向量流式传输到文件或某个比特流会更好?希望您无论如何都喜欢它。

历史

  • 1.00: 08.12.08: 初始版本
  • 1.10: 18.12.08: 用 SLT vector<T> 替换 MFC CArray<T, T> 以降低对 MFC 的依赖。新的 Encrypt(...)/Decrypt(...) 方法使用 char[]
© . All rights reserved.