我正在使用 这个示例 进行 javascript 加密,使用 php
openssl
库生成的密钥,但是 $details = openssl_pkey_get_details($resource)
没有返回公共指数 ($details['rsa']['e']
)。
这就是我生成它的方式:
function genKeys() {
// Create the keypair
$res=openssl_pkey_new();
// Get private key
$pass = bin2hex(mcrypt_create_iv(100, MCRYPT_DEV_URANDOM));
openssl_pkey_export($res, $pk, $pass);
$details = openssl_pkey_get_details($res);
print_r($details);
$details = array('n'=>$details['rsa']['n'],'e'=>$details['rsa']['e']);
return array($pk,$details,$pass);
}
function to_hex($data)
{
return strtoupper(bin2hex($data));
}
$details = genKeys()[1];
当我使用
print_r
打印出 $details
数组时,我得到:
Array
(
[bits] => 2048
[key] => -----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt+S0ZxgyQ7BPcmz/JEa7
yEhcKDZTE9TgOF/9cW1w+quFvC43daYmyRpT3asYOm7YPGCmaQ7hUx9XKUUlEdXz
Zr1uvvDyFZdtS45+4nQ5DOI20mZoUHGV82rAMmvf5vote/JJu8Gt01ZUARfsMl+K
DtwpVDHN6LGPBOW8l8abktk1tL/oiwLSVrO2cM/IgBZETDkQpUaZxZx3yUcueEQ+
BFrtS3IYaEny938daQzElNdCaip0f68Ig0gOTPzwkzDOgyOhyjFRxx4aisGzIlXu
TFkqzIz7oC3JysgS5EhlwmsEIAelbZWpgc17HK2aWIzqlT99hB+kKv2fauxH/fgT
nQIDAQAB
-----END PUBLIC KEY-----
[rsa] => Array
(
[n] => ���g2C�Orl�$F��H\(6S��8_�qmp����.7u�&�Sݫ:n�<`�i�SW)E%��f�n����mK�~�t9�6�fhPq��j�2k���-{�I����VT�2_��)T1�豏弗ƛ��5�����V��p�ȀDL9�F�Ŝw�G.xD>Z�KrhI��iĔ�Bj*t��HL���0#��1Q����"U�LY*̌��-����He�k �m����{��X���?}��*��j�G���
[e] =>
[d] => ~����G�P�t���@��5��z�nEk�m��� qИ���i�k�%�ĨS���{/�:(��0�И<MS��ʓ�r�kڷ��lRu}q��?���V���g|�i��H��]2-X%U��R�\|9h�Xs��&g���܉9S8�\����bL�_`[.w}6��d�Ù
IroD�N�*��\�Q��3|���X�k7�mYs����.�m���Ã�#��~�ǀ�8{�L�s`�O���]�T��
��
[p] => ���ɺ;�n%\,b4�]7��)��Z���е삽�66i8a�`��P#�?.�ޙ,���sq��L�HF����{8��C ���"�
>H,���A������������H�g��̓3G�mBrY`�S�
[q] => ���.VӦ�(����hZ�jTY���3���B��ք9SuMw&.^�Ƹ�d�T!9i�u�K�#�*Fc�FY��*\�iO0b���Б]iei��� �OMDӒw,V�wӾK��r�%X��[��˓4=-�h�2
[dmp1] => �ី���X��U�ܵ���}�-#́�|~�.�=�0���SjN@����V+A�<e!$3��~�"��g�������~s�� y
x5�i��(�Y�X�;X�Tn���<w�$#�#��P�3�d�Uk�
[dmq1] => �$�!Q3��Zk�{ӗ�\����I2[*V5���&kے��yr�����b�[1gpc�y?�0Gf3��i���=א�!ܜ�7�a^܉I��a$����v�x����˲�[=��ʹW�'���%�"�B
[iqmp] => &���jx�� ������&��'��Ya�B�����)��H-�<�uĮ1��H���Fwy����Xbt[;����I�2*�6���������i�ډ���3@�;�Lt.���`h�qb�N�2�"����
)
[type] => 0
)
所以,在 javascript 中,当我使用:
var rsa = new RSAKey();
rsa.setPublic('<?php echo to_hex($details['rsa']['n']) ?>', '<?php echo to_hex($details['rsa']['e']) ?>');
我没有为公共指数输入任何内容,当我尝试在服务器上解密它时,它什么也没有返回。
因为这是我发现的唯一可能性,所以我认为这可能是错误的原因。
我正在解密它:
function prKeyDecrypt($data,$prKey,$passKey){
$data = pack('H*', $data);
$pkres = openssl_pkey_get_private($prKey,$passKey);
if (openssl_private_decrypt($data, $r, $pkres)) {
return $r;
} else {
return "error";
}
}
if(isset($_POST['data'])echo prKeyDecrypt($_POST['data'],$prKey,$passKey);
其中
$prKey
和 $passKey
都是从之前的 genKeys()
语句中获得的。
是否有不同的方法来做到这一点,或者可能有不同的方法来使用服务器上的 php 中生成的公钥信息来加密客户端上的 javascript 中的数据?设置得很好,所以我想使用我所拥有的,但如果有其他方法可以工作(例如不同的 javascript 库),那么,工作总比不工作好。 :)
这是一个有趣的谜题。这是一种获取模数和公共指数的迂回方法。
您可以在这里找到用 PHP 编写的简单 ASN.1 解析器。生成 RSA 密钥对后:
// Create the keypair
$res = openssl_pkey_new();
$details = openssl_pkey_get_details($res);
您可以将公钥从 PEM 转换为 ASN.1 解析器的 DER 格式,然后将其提供给解析器:
function pem2der($pem)
{
$matches = array();
preg_match('~^-----BEGIN ([A-Z ]+)-----\s*?([A-Za-z0-9+=/\r\n]+)\s*?-----END \1-----\s*$~D', $pem, $matches);
return base64_decode(str_replace(array("\r", "\n"), array('', ''), $matches[2]));
}
$der = pem2der($details['key']);
$asn = ASN_BASE::parseASNstring($der);
然后您可以访问 ASN.1 格式的公钥,并提取模数和指数 - 我们直接知道在哪里可以找到它们。
这个特定的 ASN.1 解析器收集修改后的 Base64 格式的值,该格式可以反转,然后将值转换为十六进制以传输到客户端:
function asn_integer_to_hex($value)
{
// The ASN.1 parser strtr'd these -- strtr them back
$bin = base64_decode(strtr($value, '-_', '+/'));
// Remove any leading 0x00 byte, too, and return hex
return bin2hex(ord($bin[0]) == 0 ? substr($bin, 1) : $bin);
}
$arr = $asn[0]->data[1]->data[0]->data;
$n = asn_integer_to_hex($arr[0]->value);
$e = asn_integer_to_hex($arr[1]->value);
这些应与私钥中找到的详细信息匹配:
echo "$details n: ".bin2hex($details['rsa']['n'])."\n";
echo "$details e: ".bin2hex($details['rsa']['e'])."\n";
echo "n: ".$n."\n";
echo "e: ".$e."\n";
也就是说,如果 $details['rsa'] 有任何内容要显示。我无法解释为什么 ['e'] 在您的情况下为空,但您应该能够通过解析 ASN.1 从公钥中提取指数。
这是我的做法(比建议的方法简单得多);
<?php
include('Crypt/RSA.php');
$rsa = new Crypt_RSA();
$rsa->loadKey('-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt+S0ZxgyQ7BPcmz/JEa7
yEhcKDZTE9TgOF/9cW1w+quFvC43daYmyRpT3asYOm7YPGCmaQ7hUx9XKUUlEdXz
Zr1uvvDyFZdtS45+4nQ5DOI20mZoUHGV82rAMmvf5vote/JJu8Gt01ZUARfsMl+K
DtwpVDHN6LGPBOW8l8abktk1tL/oiwLSVrO2cM/IgBZETDkQpUaZxZx3yUcueEQ+
BFrtS3IYaEny938daQzElNdCaip0f68Ig0gOTPzwkzDOgyOhyjFRxx4aisGzIlXu
TFkqzIz7oC3JysgS5EhlwmsEIAelbZWpgc17HK2aWIzqlT99hB+kKv2fauxH/fgT
nQIDAQAB
-----END PUBLIC KEY-----');
$publickey = $rsa->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_RAW);
echo $publickey['e'];
您需要phpseclib,一个纯 PHP RSA 实现来完成此操作。
尽管
print_r()
中的指数看起来为空,但它绝对不是;获取您在问题中生成的公钥:
$key = openssl_pkey_get_public('-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt+S0ZxgyQ7BPcmz/JEa7
yEhcKDZTE9TgOF/9cW1w+quFvC43daYmyRpT3asYOm7YPGCmaQ7hUx9XKUUlEdXz
Zr1uvvDyFZdtS45+4nQ5DOI20mZoUHGV82rAMmvf5vote/JJu8Gt01ZUARfsMl+K
DtwpVDHN6LGPBOW8l8abktk1tL/oiwLSVrO2cM/IgBZETDkQpUaZxZx3yUcueEQ+
BFrtS3IYaEny938daQzElNdCaip0f68Ig0gOTPzwkzDOgyOhyjFRxx4aisGzIlXu
TFkqzIz7oC3JysgS5EhlwmsEIAelbZWpgc17HK2aWIzqlT99hB+kKv2fauxH/fgT
nQIDAQAB
-----END PUBLIC KEY-----');
$details = openssl_pkey_get_details($key);
echo bin2hex($details['rsa']['e']); // "010001"