是否可以从 PEAR Crypt 迁移到 PHPSecLib RSA?
Is it Possible to migrate from PEAR Crypt to PHPSecLib RSA?
我们不久前迁移到 PHPSecLib,但没有迁移由旧 PEAR\Crypt_RSA 库加密的遗留数据。我们已经到了需要将该数据迁移到 PHPSecLib 的 RSA 格式的地步。在对此进行调查时,我遇到了 this old forum thread。我尝试在响应中应用该建议,但无法成功解密我们的数据。它没有出错或其他任何东西,它只是看起来仍然是加密或编码的。我们目前是 运行 PHPSecLib 2.0.6,我怀疑这些说明是针对 1.x.
这是我改编的解密流程的粗略版本(基于论坛主题):
$rsaDecryptor = new RSA();
// The Private Key is encrypted based off a password
$mc = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, '');
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($mc), MCRYPT_DEV_URANDOM);
$keySize = mcrypt_enc_get_key_size($mc);
$key = substr($rsaDecryptor->password, 0, $keySize);
mcrypt_generic_init($mc, $key, $iv);
$privateKey = mdecrypt_generic($mc, base64_decode($privateKey));
mcrypt_generic_deinit($mc);
mcrypt_module_close($mc);
list($privateKeyModulus, $privateKeyExponent) = unserialize(base64_decode($privateKey));
$privateKeyExponent = new BigInteger(strrev($privateKeyExponent), 256);
$privateKeyModulus = new BigInteger(strrev($privateKeyModulus), 256);
$rsaDecryptor->modulus = $privateKeyModulus;
$rsaDecryptor->exponent = $privateKeyExponent;
$rsaDecryptor->publicExponent = $privateKeyExponent;
$rsaDecryptor->k = strlen($this->decRSA->modulus->toBytes());
// ciphertext is the raw encrypted string created by PEAR\Crypt_RSA
$value = base64_decode($ciphertext);
$value = new BigInteger($value, 256);
$value = $rsaDecryptor->_exponentiate($value)->toBytes();
$value = substr($value, 1);
PEAR 中的错误 Crypt_RSA
所以我在玩这个。 PEAR 的 Crypt_RSA(最新版本)中存在一个错误,可能会完全阻止它工作。以下代码演示:
$key_pair = new Crypt_RSA_KeyPair(1024);
$privkey = $key_pair->getPrivateKey();
$pubkey = $key_pair->getPublicKey();
$a = $privkey->toString();
$b = $pubkey->toString();
echo $a == $b ? 'same' : 'different';
您希望 $a 和 $b 不同,不是吗?好吧,他们不是。这是因为 RSA/KeyPair.php 这样做:
$this->_public_key = &$obj;
...
$this->_private_key = &$obj;
如果删除 & 符号,它可以正常工作,但默认情况下它们在代码中。
截至 https://pear.php.net/bugs/bug.php?id=15900
,这似乎是一个未解决的问题
也许它在 PHP4 上的表现不同,但我不知道。
解密数据
假设上述错误对您来说不是问题,那么以下对我有用(使用 phpseclib 2.0):
function loadKey($key) // for keys genereated with $key->toString() vs $key->toPEMString()
{
if (!($key = base64_decode($key))) {
return false;
}
if (!($key = unserialize($key))) {
return false;
}
list($modulus, $exponent) = $key;
$modulus = new BigInteger(strrev($modulus), 256);
$exponent = new BigInteger(strrev($exponent), 256);
$rsa = new RSA();
$rsa->loadKey(compact('modulus', 'exponent'));
return $rsa;
}
function decrypt($key, $ciphertext)
{
if (!($ciphertext = base64_decode($ciphertext))) {
return false;
}
$key->setEncryptionMode(RSA::ENCRYPTION_NONE);
$ciphertext = strrev($ciphertext);
$plaintext = $key->decrypt($ciphertext);
$plaintext = strrev($plaintext);
$plaintext = substr($plaintext, 0, strpos($plaintext, "[=12=]"));
return $plaintext[strlen($plaintext) - 1] == "" ?
substr($plaintext, 0, -1) : false;
}
$key = loadKey($private_key);
$plaintext = decrypt($key, $ciphertext);
echo $plaintext;
使用 toPEMString() 生成的私钥
使用 PEAR 的 Crypt_RSA,您可以通过另一种方式生成私钥:
$key_pair->toPEMString();
此方法无需更改代码即可工作。如果您使用此方法生成私钥,则私钥以 -----BEGIN RSA PRIVATE KEY-----
开头。如果是这种情况,那么您不需要使用我编写的 loadKey
函数。您可以这样做:
$key = new RSA();
$key->loadKey('...');
$plaintext = decrypt($key, $ciphertext);
echo $plaintext;
我们不久前迁移到 PHPSecLib,但没有迁移由旧 PEAR\Crypt_RSA 库加密的遗留数据。我们已经到了需要将该数据迁移到 PHPSecLib 的 RSA 格式的地步。在对此进行调查时,我遇到了 this old forum thread。我尝试在响应中应用该建议,但无法成功解密我们的数据。它没有出错或其他任何东西,它只是看起来仍然是加密或编码的。我们目前是 运行 PHPSecLib 2.0.6,我怀疑这些说明是针对 1.x.
这是我改编的解密流程的粗略版本(基于论坛主题):
$rsaDecryptor = new RSA();
// The Private Key is encrypted based off a password
$mc = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, '');
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($mc), MCRYPT_DEV_URANDOM);
$keySize = mcrypt_enc_get_key_size($mc);
$key = substr($rsaDecryptor->password, 0, $keySize);
mcrypt_generic_init($mc, $key, $iv);
$privateKey = mdecrypt_generic($mc, base64_decode($privateKey));
mcrypt_generic_deinit($mc);
mcrypt_module_close($mc);
list($privateKeyModulus, $privateKeyExponent) = unserialize(base64_decode($privateKey));
$privateKeyExponent = new BigInteger(strrev($privateKeyExponent), 256);
$privateKeyModulus = new BigInteger(strrev($privateKeyModulus), 256);
$rsaDecryptor->modulus = $privateKeyModulus;
$rsaDecryptor->exponent = $privateKeyExponent;
$rsaDecryptor->publicExponent = $privateKeyExponent;
$rsaDecryptor->k = strlen($this->decRSA->modulus->toBytes());
// ciphertext is the raw encrypted string created by PEAR\Crypt_RSA
$value = base64_decode($ciphertext);
$value = new BigInteger($value, 256);
$value = $rsaDecryptor->_exponentiate($value)->toBytes();
$value = substr($value, 1);
PEAR 中的错误 Crypt_RSA
所以我在玩这个。 PEAR 的 Crypt_RSA(最新版本)中存在一个错误,可能会完全阻止它工作。以下代码演示:
$key_pair = new Crypt_RSA_KeyPair(1024);
$privkey = $key_pair->getPrivateKey();
$pubkey = $key_pair->getPublicKey();
$a = $privkey->toString();
$b = $pubkey->toString();
echo $a == $b ? 'same' : 'different';
您希望 $a 和 $b 不同,不是吗?好吧,他们不是。这是因为 RSA/KeyPair.php 这样做:
$this->_public_key = &$obj;
...
$this->_private_key = &$obj;
如果删除 & 符号,它可以正常工作,但默认情况下它们在代码中。
截至 https://pear.php.net/bugs/bug.php?id=15900
,这似乎是一个未解决的问题也许它在 PHP4 上的表现不同,但我不知道。
解密数据
假设上述错误对您来说不是问题,那么以下对我有用(使用 phpseclib 2.0):
function loadKey($key) // for keys genereated with $key->toString() vs $key->toPEMString()
{
if (!($key = base64_decode($key))) {
return false;
}
if (!($key = unserialize($key))) {
return false;
}
list($modulus, $exponent) = $key;
$modulus = new BigInteger(strrev($modulus), 256);
$exponent = new BigInteger(strrev($exponent), 256);
$rsa = new RSA();
$rsa->loadKey(compact('modulus', 'exponent'));
return $rsa;
}
function decrypt($key, $ciphertext)
{
if (!($ciphertext = base64_decode($ciphertext))) {
return false;
}
$key->setEncryptionMode(RSA::ENCRYPTION_NONE);
$ciphertext = strrev($ciphertext);
$plaintext = $key->decrypt($ciphertext);
$plaintext = strrev($plaintext);
$plaintext = substr($plaintext, 0, strpos($plaintext, "[=12=]"));
return $plaintext[strlen($plaintext) - 1] == "" ?
substr($plaintext, 0, -1) : false;
}
$key = loadKey($private_key);
$plaintext = decrypt($key, $ciphertext);
echo $plaintext;
使用 toPEMString() 生成的私钥
使用 PEAR 的 Crypt_RSA,您可以通过另一种方式生成私钥:
$key_pair->toPEMString();
此方法无需更改代码即可工作。如果您使用此方法生成私钥,则私钥以 -----BEGIN RSA PRIVATE KEY-----
开头。如果是这种情况,那么您不需要使用我编写的 loadKey
函数。您可以这样做:
$key = new RSA();
$key->loadKey('...');
$plaintext = decrypt($key, $ciphertext);
echo $plaintext;