rc4转16进制php,php - 将Windows RC4 CryptDeriveKey转换为openssl的PHP - 堆栈内存溢出

这是我们一直在尝试的遗留系统转换的第二部分。 我们已经设法完全匹配Windows :: CryptHashData生成的初始二进制密码/密钥。

该密码/密钥将传递给:: CryptDeriveKey,在此执行许多步骤来创建最终的密钥,以供:: CryptEncrypt使用。 我的研究使我进入了CryptDeriveKey文档,该文档清楚地描述了为:: CryptEncrypt导出密钥所需的步骤,但到目前为止,我还无法在PHP方面获得它来解密文件。

根据:: CryptDeriveKey文档,对于我们特定的传统密钥大小,可能还有一些其他未记录的步骤,可能无法很好地理解。 默认情况下,当前Windows :: CryptDeriveKey设置为ZERO SALT,这显然与NO_SALT有所不同。

我们的旧系统的CryptAPI上的参数如下:

提供程序类型:PROV_RSA_FULL

提供程序名称:MS_DEF_PROV

算法ID CALG_RC4

说明RC4流加密算法

密钥长度:40位。

盐长:88位。 ZERO_SALT

特别说明:然而,带有零值盐的40位对称密钥并不等同于没有盐的40位对称密钥。 为了实现互操作性,必须在不添加盐的情况下创建密钥。 此问题是由仅使用正好40位的密钥的默认情况导致的。

我不希望导出密钥,而是重现创建最终加密密钥的过程,该过程将最终的加密密钥传递给:: CryptEncrypt以用于RC4加密算法,并使其与openssl_decrypt一起使用。

这是当前适用于加密的Windows代码。

try {

BOOL bSuccess;

bSuccess = ::CryptAcquireContextA(&hCryptProv,

CE_CRYPTCONTEXT,

MS_DEF_PROV_A,

PROV_RSA_FULL,

CRYPT_MACHINE_KEYSET);

::CryptCreateHash(hCryptProv,

CALG_MD5,

0,

0,

&hSaveHash);

::CryptHashData(hSaveHash,

baKeyRandom,

(DWORD)sizeof(baKeyRandom),

0);

::CryptHashData(hSaveHash,

(LPBYTE)T2CW(pszSecret),

(DWORD)_tcslen(pszSecret) * sizeof(WCHAR),

0);

::CryptDeriveKey(hCryptProv,

CALG_RC4,

hSaveHash,

0,

&hCryptKey);

// Now Encrypt the value

BYTE * pData = NULL;

DWORD dwSize = (DWORD)_tcslen(pszToEncrypt) * sizeof(WCHAR);

// will be a wide str

DWORD dwReqdSize = dwSize;

::CryptEncrypt(hCryptKey,

NULL,

TRUE,

0,

(LPBYTE)NULL,

&dwReqdSize, 0);

dwReqdSize = max(dwReqdSize, dwSize);

pData = new BYTE[dwReqdSize];

memcpy(pData, T2CW(pszToEncrypt), dwSize);

if (!::CryptEncrypt(hCryptKey,

NULL,

TRUE,

0,

pData,

&dwSize,

dwReqdSize)) {

printf("%l\n", hCryptKey);

printf("error during CryptEncrypt\n");

}

if (*pbstrEncrypted)

::SysFreeString(*pbstrEncrypted);

*pbstrEncrypted = ::SysAllocStringByteLen((LPCSTR)pData, dwSize);

delete[] pData;

hr = S_OK;

}

这是PHP文档,试图按照文档中的描述复制:: CryptDeriveKey函数。

令n为所需的派生密钥长度(以字节为单位)。 派生密钥是CryptDeriveKey完成哈希计算之后的哈希值的前n个字节。 如果哈希不是SHA-2家族的成员,并且所需的密钥是3DES或AES,则密钥的导出如下:

通过重复常数0x36 64次来形成64字节的缓冲区。 令k为由输入参数hBaseData表示的哈希值的长度。 将缓冲区的前k个字节设置为使用输入参数hBaseData表示的哈希值对缓冲区的前k个字节进行XOR操作的结果。

通过重复常数0x5C 64次形成一个64字节的缓冲区。 将缓冲区的前k个字节设置为缓冲区的前k个字节与由输入参数hBaseData表示的哈希值进行XOR运算的结果。

通过使用与用于计算由hBaseData参数表示的哈希值的哈希算法相同的哈希算法来哈希步骤1的结果。

通过使用与用于计算由hBaseData参数表示的哈希值的哈希算法相同的哈希算法来哈希步骤2的结果。

将步骤3的结果与步骤4的结果连接起来。

使用步骤5的结果的前n个字节作为派生密钥。

:: CryptDeriveKey的PHP版本。

function cryptoDeriveKey($key){

//Put the hash key into an array

$hashKey1 = str_split($key,2);

$count = count($hashKey1);

$hashKeyInt = array();

for ($i=0; $i

$hashKeyInt[$i] = hexdec($hashKey1[$i]);

}

$hashKey = $hashKeyInt;

//Let n be the required derived key length, in bytes. CALG_RC4 = 40 bits key or 88 salt bytes

$n = 40/8;

//Let k be the length of the hash value that is represented by the input parameter hBaseData

$k = 16;

//Step 1 Form a 64-byte buffer by repeating the constant 0x36 64 times

$arraya = array_fill(0, 64, 0x36);

//Set the first k bytes of the buffer to the result of an XOR operation of the first k bytes of the buffer with the hash value

for ($i=0; $i

$arraya[$i] = $arraya[$i] ^ $hashKey[$i];

}

//Hash the result of step 1 by using the same hash algorithm as hBaseData

$arrayPacka = pack('c*', ...$arraya);

$hashArraya = md5($arrayPacka);

//Put the hash string back into the array

$hashKeyArraya = str_split($hashArraya,2);

$count = count($hashKeyArraya);

$hashKeyInta = array();

for ($i=0; $i

$hashKeyInta[$i] = hexdec($hashKeyArraya[$i]);

}

//Step 2 Form a 64-byte buffer by repeating the constant 0x5C 64 times.

$arrayb = array_fill(0, 64, 0x5C);

//Set the first k bytes of the buffer to the result of an XOR operation of the first k bytes of the buffer with the hash value

for ($i=0; $i

$arrayb[$i] = $arrayb[$i] ^ $hashKey[$i];

}

//Hash the result of step 2 by using the same hash algorithm as hBaseData

$arrayPackb = pack('c*', ...$arrayb);

$hashArrayb = md5($arrayPackb);

//Put the hash string back into the array

$hashKeyArrayb = str_split($hashArrayb,2);

$count = count($hashKeyArrayb);

$hashKeyIntb = array();

for ($i=0; $i

$hashKeyIntb[$i] = hexdec($hashKeyArrayb[$i]);

}

//Concatenate the result of step 3 with the result of step 4.

$combined = array_merge($hashKeyInta, $hashKeyIntb);

//Use the first n bytes of the result of step 5 as the derived key.

$finalKey = array();

for ($i=0; $i

$finalKey[$i] = $combined[$i];

}

$key = $finalKey;

return $key;

}

PHP解密功能

function decryptRC4($encrypted, $key){

$opts = OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING;

$cypher = ‘rc4-40’;

$decrypted = openssl_decrypt($encrypted, $cypher, $key, $opts);

return $decrypted;

}

因此,这里有个大问题:

有没有人能够在另一个系统上使用RC4成功复制:: CryptDeriveKey?

有谁知道我们创建的PHP脚本中缺少哪些内容,从而阻止该脚本创建相同的密钥并使用openssl_decrypt解密Windows CryptoAPI加密文件?

我们在哪里以及如何创建40位密钥所需的88位零盐?

可以接受此密钥并解密:: CryptDeriveKey生成的内容的正确的openssl_decrypt参数是什么?

是的,我们知道这是不安全的,并且不用于密码或PII。 我们希望摆脱这种古老而又不安全的方法,但是我们需要采取此过渡步骤,首先将原始加密转换为PHP,以实现与现有已部署系统的互操作性。 任何帮助或指导,将不胜感激。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值