openssl_pkey_get_details($ res)不返回公共指数

时间:2014-06-22 01:38:01

标签: javascript php encryption openssl rsa

我使用this example使用php openssl库生成的密钥进行javascript加密,但$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库),那么工作比不工作:)

3 个答案:

答案 0 :(得分:0)

这是一个有趣的谜题。这是一种获得模数和公共指数的圆形方法。

您可以找到一个用PHP here编写的简单ASN.1解析器。生成RSA密钥对后:

// Create the keypair
$res = openssl_pkey_new();
$details = openssl_pkey_get_details($res);

您可以将公钥从PEM转换为DER格式以用于ASN.1解析器,然后将其提供给解析器:

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 [&#39; rsa&#39;]有任何要显示的内容。我无法解释为什么[&#39; e&#39;]在您的情况下为空,但您应该能够通过解析ASN.1将指数从公钥中拉出来。

答案 1 :(得分:0)

即使指数在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"

答案 2 :(得分:0)

以下是我的工作方式(比拟议的方法简单得多);

<?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, a pure PHP RSA implementation来执行此操作。