Python 这里使用什么字符移位/伪加密算法?

Python 这里使用什么字符移位/伪加密算法?,python,winapi,cryptography,jython,cryptoapi,Python,Winapi,Cryptography,Jython,Cryptoapi,这是你们所有密码学家的求救之声 场景:我有一个Windows应用程序(可能是用VC++或VB构建的,随后被移动到.Net),它将一些密码保存在XML文件中。给定一个密码A0123456789abcDEFGH,得到的“加密”值是040770409404093049204204040404040409040409040409040904091044091040900408040804087040860408050404040404404407404073040720407104070 查看字符串,我

这是你们所有密码学家的求救之声

场景:我有一个Windows应用程序(可能是用VC++或VB构建的,随后被移动到.Net),它将一些密码保存在XML文件中。给定一个密码
A0123456789abcDEFGH
,得到的“加密”值是
040770409404093049204204040404040409040409040409040904091044091040900408040804087040860408050404040404404407404073040720407104070

查看字符串,我发现这只是字符移位:“04”分隔实际的字符值,它们是十进制的;如果我从142中减去这些值,我会得到原始的ASCII码。在Jython(2.2)中,我的解密例程如下所示(由于评论中的建议而编辑):

这对于ASCII值(总共127个)和一些重音字母来说是不错的,但是8位字符集还有128个字符;从十进制角度来看,将接受值限制为142是没有意义的

编辑:我在我们的系统中翻找,发现了三个非ASCII字符:

è 03910
Ø 03926
Õ 03929
从这些值来看,实际上从4142中减去4个数字块(只留下“0”作为分隔符)就得到了正确的字符

所以我的问题是:

  • 有人熟悉Windows世界中的这种模糊处理方案吗?这可能是标准库函数的产物吗?老实说,我不太熟悉Win32和.Net开发,所以我可能遗漏了一些非常简单的东西

  • 如果它不是一个库函数,你能想出一个更好的方法来消除这些值的混淆,而不必求助于magic 142数字,也就是说,一个方案实际上可以应用于非ASCII字符,而无需对其进行特殊的大小写吗?我不擅长移位之类的,所以我可能又错过了一些对训练有素的眼睛来说显而易见的东西

有人熟悉Windows世界中的这种模糊处理方案吗

一旦你正确地理解了它,它只是一个简单的旋转密码

为什么会有人用这个

嗯,一般来说,这是很常见的。假设您有一些需要混淆的数据。但是解密算法和密钥必须嵌入到观众拥有的软件中。使用像AES这样花哨的东西是没有意义的,因为有人总是可以从代码中挖掘算法和密钥,而不是破解AES。一个比查找隐藏密钥更难破解的加密方案与一个完美的加密方案一样好,它足以吓阻偶然的观众,对严重的攻击者毫无用处。(通常情况下,您甚至不担心阻止攻击,而是担心在您的攻击者出于合同/法律原因恶意行事后进行证明。)因此,您可以使用简单的旋转密码,也可以使用简单的xor密码。它速度快,很难出错,而且很容易调试,如果最坏的情况发生,您甚至可以手动解密以恢复损坏的数据

至于详情:

如果您想处理非ASCII字符,您几乎必须使用Unicode。如果使用固定的8位字符集或本地系统的OEM字符集,则无法处理来自其他机器的密码

Python脚本几乎肯定会处理Unicode字符,因为在Python中,要么在
str
中处理字节,要么在
Unicode
中处理Unicode字符。但Windows C或.NET应用程序更可能使用UTF-16,因为Windows本机API在
WCHAR*
中处理UTF-16-LE代码点(也称为16位字字符串)

那么,为什么是4142?其实,关键是什么并不重要。我猜是一些程序员建议的。他的经理接着说:“听起来不太安全。”他叹了口气说,“我已经解释了为什么没有钥匙比……你知道吗,算了,4142怎么样?”经理说,“哦,听起来像是一个非常安全的号码!”这就是4142的原因


如果它不是一个库函数,你能想出一个更好的方法来消除这些值的模糊,而不用求助于神奇的142数字吗

您确实需要求助于神奇的4142,但您可以让它变得简单得多:

def decrypt(block):
    return struct.pack('>H', (4142 - int(block, 10)) % 65536)
因此,每个5个字符的块是UTF-16代码单元的十进制表示,使用C无符号短环绕规则从4142中减去

在本机WindowsC中实现这一点很简单,但在Python中要稍微困难一些。我能想到的最好的转换函数是:

def decrypt_block(block):
    return struct.pack('>H', (4142 - int(block, 10)) % 65536)

def decrypt(pwd):
    blocks = [pwd[i:i+5] for i in range(0, len(pwd), 5)] 
    return ''.join(map(decrypt_block, blocks)).decode('utf-16-be')
在C或C#中,这可能要简单得多,这可能是他们实现东西的地方,所以让我解释一下我在做什么

您已经知道如何将字符串转换为5个字符的块序列

我的
int(block,10)
与您的
int(block.lstrip('0'))
做了同样的事情,确保
'0'
前缀不会使Python将其视为八进制数字而不是十进制数字,而是更明确。我不认为这在Jython2.2中是必要的(在更现代的Python/Jython中肯定不是),但我把它留了下来以防万一

接下来,在C中,只需执行
无符号短x=4142U-y,将自动适当下溢。Python没有
无符号的short
值,只是有符号的
int
,因此我们必须手动执行下溢。(因为Python使用了最小除法和余数,所以符号总是与除数相同——这在C中是不正确的,至少在C99和大多数平台的C89中是不正确的。)

然后,在C中,我们将无符号短字符转换为16位的“宽字符”;Python没有任何方法可以做到这一点,所以我们必须使用。(请注意,我正在将其转换为big-endian,因为我认为这使调试更容易;在C中,您将转换为本机endian,因为这是Windows,这将是little-endian。)

那么,现在
def decrypt_block(block):
    return struct.pack('>H', (4142 - int(block, 10)) % 65536)

def decrypt(pwd):
    blocks = [pwd[i:i+5] for i in range(0, len(pwd), 5)] 
    return ''.join(map(decrypt_block, blocks)).decode('utf-16-be')