2017-11-10 141 views
2

前段时间我们已经迁移到PHPSecLib,但没有迁移旧的PEAR \ Crypt_RSA库加密的旧数据。我们已经达到了将数据迁移到PHPSecLib的RSA格式的地步。在调查这个时,我碰到了this old forum thread。我试图在响应中应用此建议,但无法使其成功解密我们的数据。它没有出错或任何东西,它似乎仍然是加密或编码。我们目前正在运行PHPSecLib 2.0.6,我怀疑这些说明是针对1.x的。是否可以从PEAR Crypt迁移到PHPSecLib RSA?

这里是我的适应解密流的粗加工版本(基于关闭论坛线程):

$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); 
+0

“......它似乎仍然是加密或编码......”没有显示你的代码,这个问题应该关闭作为离题。寻求调试帮助的问题(“为什么这个代码不工作?”)必须包含所需的行为,特定的问题或错误以及在问题本身中重现问题所需的最短代码。没有明确问题陈述的问题对其他读者无益。请参阅:[如何创建一个最小,完整和可验证的示例](https://stackoverflow.com/help/mcve) –

+1

@JamesKPolk,感谢您的支持。我认为这不是一个调试问题,而是一个“这个东西实际上可行吗?”问题,但据说,我提供了一个粗略的代码流示例。我也修改了帖子的标题以尝试符合我的意图。 – bgrahamfs

回答

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)为我工作:与toPEMString生成

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, "\0")); 
    return $plaintext[strlen($plaintext) - 1] == "\1" ? 
     substr($plaintext, 0, -1) : false; 
} 

$key = loadKey($private_key); 
$plaintext = decrypt($key, $ciphertext); 
echo $plaintext; 

私钥()

通过PEAR的Crypt_RSA,您可以使用另一种方式生成私钥:

$key_pair->toPEMString(); 

此方法无需更改代码。如果您使用此方法生成私钥,则私钥以-----BEGIN RSA PRIVATE KEY-----开头。如果是这种情况,那么你不需要使用我写的loadKey函数。你可以这样做:

$key = new RSA(); 
$key->loadKey('...'); 
$plaintext = decrypt($key, $ciphertext); 
echo $plaintext; 
+1

@bgrahamfs - '$ key-> loadKey('...')基本上会尝试每个支持的密钥格式,直到找到加载密钥的格式。支持的密钥格式之一是'RSA :: PUBLIC_FORMAT_RAW',它接受数组。它是接受数组作为输入的唯一关键格式:https://github.com/phpseclib/phpseclib/blob/2.0.7/phpseclib/Crypt/RSA.php#L1030 – neubert

+2

感谢您的澄清和伟大的代码示例。我现在对加密和解密都有大致的概念验证。 – bgrahamfs

相关问题