Question

I'm having serious problems with what I was hoping would be a simple call to PHP's openssl_public_encrypt();

Sadly, I get an invalid public key warning.

My goal is to simply RSA encrypt a users password using public key provided by their API which currently looks like this:

+Tir6+unMOaQ5tHqjjjwnlAMhccnCSMFEi3a0mhIxbW+O/GukjomGyzckQT2h0Ys70JezHbNq5YS3sYkNF29kCkz4HuNfy9eEjE/clA9/zyfT8ZcbnusLcLz2xNgbTp62fQdzBnReI5+dpj/N24krYvHaYIr8ACxDqBv2TR3E9M=AQAB

Apparently a working implementation using the same service I'm trying to use found a solution with these steps:

  1. Extract the modulus and exponent from the public key
  2. Re-constructs the key in the MS PUBLICKEYBLOB format
  3. Call OpenSSL to convert the key to PEM format
  4. Load the PEM public key from the converted file
  5. Encrypts the password (after converting to UTF-16LE)

However not only that I dont know if its possible to do in PHP , I think there Must be an easier way!

One post I saw hinted that the exponent may come after the last = sign (so AQAB) but I don't know if this is reliable.

Était-ce utile?

La solution

Something like this do what you want?:

<?php
$key = '+Tir6+unMOaQ5tHqjjjwnlAMhccnCSMFEi3a0mhIxbW+O/GukjomGyzckQT2h0Ys70JezHbNq5YS3sYkNF29kCkz4HuNfy9eEjE/clA9/zyfT8ZcbnusLcLz2xNgbTp62fQdzBnReI5+dpj/N24krYvHaYIr8ACxDqBv2TR3E9M=AQAB';

include('Crypt/RSA.php');

$rsa = new Crypt_RSA();
$rsa->loadKey(array(
    'e' => new Math_BigInteger(65537),
    'n' => new Math_BigInteger(substr($key, 0, -4), -256)
));
$ciphertext = $rsa->encrypt('password');

echo bin2hex($ciphertext);
?>

This example uses phpseclib, a pure PHP RSA implementation. Although phpseclib does not support the format of the key you posted it does support raw public keys and as such converting to PKCS1 style keys is unnecessar. And the ciphertext's produced by phpseclib are perfectly interoperable with OpenSSL.

Autres conseils

OK, so what you need to do:

  1. remove the AQAB part and use the value 65537 for the public exponent
  2. base 64 decode the modulus
  3. create a DER encoding of the public key in PKCS#1 format (see below)
  4. base64 encode the DER encoding using 64 character line length and DOS line endings
  5. add PEM header & footer
  6. use the PEM encoded string to create a public key and finally
  7. encrypt the password

The following ASN.1 spec defines the public key in PKCS#1 format:

RSAPublicKey ::= SEQUENCE {
      modulus           INTEGER,  -- n
      publicExponent    INTEGER   -- e
}

Now the identifier octet or tag of SEQUENCE is 30 in hex, INTEGER is 02 and the length should be specified like this. So you get something like:

30818902818100F938ABEBEBA730E690E6D1EA8E38F09E500C85C727092305122DDAD26848C5B5BE3BF1AE923A261B2CDC9104F687462CEF425ECC76CDAB9612DEC624345DBD902933E07B8D7F2F5E12313F72503DFF3C9F4FC65C6E7BAC2DC2F3DB13606D3A7AD9F41DCC19D1788E7E7698FF376E24AD8BC769822BF000B10EA06FD9347713D30203010001

in hexadecimals. So after base 64 encoding and adding the header and footer line you should get:

-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQH5OKvr66cw5pDm0eqOOPCeUAyFxycJIwUSLdrSaEjFtb478a6SOiYbLNyRBPaHRizvQl7Mds2rlhLexiQ0Xb2QKTPge41/L14SMT9yUD3/PJ9Pxlxue6wt
wvPbE2BtOnrZ9B3MGdF4jn52mP83biSti8dpgivwALEOoG/ZNHcT0wIDAQAB
-----END RSA PUBLIC KEY-----

Happy coding.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top