在C#中可靠地再现在PHP中实现的传统密码散列方法

在C#中可靠地再现在PHP中实现的传统密码散列方法,c#,php,hash,passwords,C#,Php,Hash,Passwords,我们正在将一个在Linux上运行的PHP应用程序迁移到我们新的单点登录(SSO)基础设施,该基础设施在C#中实现,并在Windows上运行 作为迁移过程的一部分,我们需要我们的C#SSO基础设施能够以与PHP应用程序完全相同的方式散列密码 虽然PHP应用程序使用了一种相当合理的密码哈希算法,但除了密码和salt之外,不幸的是,被哈希的字符串还包含salt值的余弦(解释为整数)。。。一个相当不寻常的决定,说得中庸一点 不出所料,在PHP和C#中计算一个大整数的余弦会得到稍微不同的结果。这意味着我们

我们正在将一个在Linux上运行的PHP应用程序迁移到我们新的单点登录(SSO)基础设施,该基础设施在C#中实现,并在Windows上运行

作为迁移过程的一部分,我们需要我们的C#SSO基础设施能够以与PHP应用程序完全相同的方式散列密码

虽然PHP应用程序使用了一种相当合理的密码哈希算法,但除了密码和salt之外,不幸的是,被哈希的字符串还包含salt值的余弦(解释为整数)。。。一个相当不寻常的决定,说得中庸一点

不出所料,在PHP和C#中计算一个大整数的余弦会得到稍微不同的结果。这意味着我们可能无法在新的SSO基础架构中可靠地重新实现遗留密码哈希算法

我们考虑的一个解决方案是在AWS Lambda中运行PHP密码哈希函数,并从我们的SSO基础结构中查询该Lambda

你能想到其他的选择吗?

PHP将是glibc的
math.h
cos
实现。您可以看看该实现并在应用程序中重新创建它吗?这可能会令人毛骨悚然,因为glibc的数学知识相当复杂。如果在应用程序中使用glibc作为依赖项是可以接受的,那么您可以尝试这种方法吗?不管怎样,这就是我要开始的地方


另一个让我担心的问题是,您实际上也在处理一些PHP的奇数浮点处理,因此并非算法的所有“字符”都来自所涉及的trig函数。

在您编写的另一个问题中

用Visual Studio 2017编译的简单C程序中的C的
cos(double)
函数

c = -0.57977754519881342
虽然您没有直截了当地说出来,但这似乎就是您要寻找的结果(它肯定与
Math.Cos
的结果不同,不确定它是否与PHP按位相同)

因此,使用VS2017编译一个DLL,并p/调用它。或者在C运行时库DLL中P/invoke
cos()
,它肯定会导出所有这些
#include
函数

c:\Windows\System32>dumpbin /exports msvcr120.dll | find "cos"
       1442  5A1 00081C44 acos
       1443  5A2 00081F2C acosf
       1444  5A3 000821B8 acosh
       1445  5A4 0008227C acoshf
       1446  5A5 0008233C acoshl
       1472  5BF 00083ED4 cacos
       1473  5C0 00084208 cacosf
       1474  5C1 000844BC cacosh
       1475  5C2 00084824 cacoshf
       1476  5C3 00084AF4 cacoshl
       1477  5C4 00084E5C cacosl
       1497  5D8 00086CF4 ccos
       1498  5D9 00086D70 ccosf
       1499  5DA 00086EAC ccosh
       1500  5DB 0008714C ccoshf
       1501  5DC 000873AC ccoshl
       1502  5DD 0008756C ccosl
       1526  5F5 00088640 cos
       1527  5F6 00088BA0 cosf
       1528  5F7 000890A0 cosh
       1529  5F8 00089574 coshf

c:\Windows\System32>dumpbin /exports msvcrt.dll | find "cos"
       1046  415 000372D0 acos
       1047  416 00019BE0 acosf
       1069  42C 000118F0 cos
       1070  42D 00015480 cosf
       1071  42E 000868F0 cosh
       1072  42F 0001ABC0 coshf

据推测,盐与每个密码一起存储。您可以使用PHP代码计算余弦,并将其与密码一起存储。然后,我还会添加一个密码版本号,并将所有旧密码默认为版本1。然后,在您的C#代码中,对于任何新密码,您实现了一个新的哈希算法,并将这些密码哈希存储为密码版本2。对于任何版本1密码,要进行身份验证,您不必计算余弦,只需使用与密码哈希和salt一起存储的余弦即可。


那个PHP代码的程序员可能想做一个聪明的pepper版本。通过存储余弦或胡椒粉以及盐和密码散列,基本上将胡椒粉更改为salt2。因此,另一种无版本的方法是在C#哈希代码中使用两种盐。对于新密码,您可以将第二个salt留空或以其他方式分配。对于旧密码,它应该是余弦,但它已经计算出来了。

嗨,本,这正是我最终实现的解决方案。我创建了一个很小的DLL,它只是包装了use
cos()
,但我还没有想到要使用
msvcr120.DLL
!P/从C运行时调用
cos()
,效果非常好。太棒了,谢谢你的建议!有一个微妙之处:如果C#project P/Invoking
msvcr120.dll
是为“任何CPU”平台构建的,那么就使用x86版本的
msvcr120.dll
而不是x64版本,从而导致不精确的
cos()
版本。…@franceçoisbaune:我认为如果您构建自己的dll并指定使用SSE2进行浮点运算,你在x86上应该还好吧?您也可以尝试更新版本的C运行时(它们不再保存在System32中,因此除了p/invoke之外,C#app可能需要一些清单更改),不幸的是,我找不到一种方法来指示VC++使用自己的基于SSE[2]的cos()实现,而不是32位模式下的x87指令。我还尝试了VC++2017的标准库(
api-ms-win-crt-math-l1-1-0.dll
),但它给出了同样不准确的结果……最终我将这个答案移到了这里!(来自)。。。一年多过去了,我让你们大家都想知道为什么现在。