2

my first post.

I'm trying to asymmetrically encrypt data in JavaScript (in the user's browser), using the existing public key that I've used to successfully encrypt data in our native iOS and Android app.

I created the keys this way:

openssl req -x509 -out public_key.der -outform der -new -newkey rsa:1024 -keyout private_key.pem -days 3650

(Thanks to http://jslim.net/blog/2013/01/05/rsa-encryption-in-ios-and-decrypt-it-using-php/)

When I use these wonderful JavaScipt examples:

  1. Example.
  2. Another example.

When I paste in my PEM formatted key, and encrypt a short string, I get what appears to be legitimate ciphertext in Base64, but it doesn't decrypt (I get a blank string). The decryption code works perfectly with the Base64 ciphertext from Android / iPhone.

The PEM public keys in these tutorials are generated with:

openssl genrsa -out rsa.pem 1024 
openssl rsa -in rsa.pem -pubout

I converted my existing DER public key to PEM this way:

openssl x509 -in public_key.der -out nopass_public_with_cert.pem -inform DER -outform PEM
openssl x509 -pubkey -in nopass_public_with_cert.pem > public.pem

I believe the problem is the format/type of keys and files. Or misunderstanding of why certificates are involved / what I've actually created using the above openssl command. (What is PKCS?)

My question: How can I encrypt in Javascript using the existing keys, or convert these files into a format usable by JavaScript libraries?

If it helps to explain what I've done, here is the successful encryption in Android:

import java.security.(...);

import javax.crypto.Cipher;

String publickeybase64 = go_get_file_bytes_as_base64("public_key.der");
byte[]decode = Base64.decode(publickeybase64, Base64.DEFAULT);
CertificateFactory certificateFactory = CertificateFactory.getInstance("X509");
Certificate certificate = certificateFactory.generateCertificate(new ByteArrayInputStream(decode));
PublicKey publicKey = certificate.getPublicKey();
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
String plaintext = "hello world";
String encryptedstring = new String(Base64.encode(cipher.doFinal(plaintext.getBytes()),Base64.NO_WRAP));

Thankyou all!

President James K. Polk
  • 40,516
  • 21
  • 95
  • 125
legoblocks
  • 525
  • 1
  • 6
  • 16

1 Answers1

2

There seems to be a slight mismatch in your understanding what a public key consists of and the JavaScript libs that you're using.


An X5.09 certificate is a DER structure that contains a public key. It also contains a lot of other data of the holder, issuer, key and of course the signature of the issuer.

A public key is usually also encoded as (PKCS#1) DER encoded data, but it only consists of the modulus and the public exponent (for RSA).

PEM is just an ASCII armor with DER inside.


Now your Android software seems to use the certificate for encryption. That's fine, the underlying Cipher implementation just retrieves the public key and encrypts with it. Your JavaScript code however just takes the public key, not a certificate. So you'll need some kind of library to retrieve the public key from the certificate.


The big issue is of course how to make sure that JavaScript can trust the public key. This can be solved on iOS and Android by including a trusted (higher level CA) certificate in the application and verify the certificate or public key with that. That's usually not possible for JavaScript where the code gets distributed using the same untrusted channel as the public key. So technically solving this issue may not bring you real security.

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
  • Hi Maarten. Thanks for your reply! You mention retrieving just the public key from the existing certificate. Are there any openssl gurus out there who can extract a public key from the existing DER file? What command would this be? I've made attempts, but the result was mangled (I am indeed in unfamiliar territory). Good points, I agree that the JavaScript public key is open to MITM attacks, any one user could be attacked this way, but the aim is for the data on the server to be stored encrypted. At best a mitigation, but far more secure than plaintext this way. Thanks again for your help! – legoblocks Mar 10 '15 at 13:16
  • http://stackoverflow.com/q/13539535/589259 seems to retrieve the public key from the certificate in the question. Mind the answer too. – Maarten Bodewes Mar 10 '15 at 17:09
  • The Q+A in this link doesn't take in the public key (as I have it, DER), and doesn't provide it in the format I need it to be (PEM), but thankyou no less. I'll ask another more specific question on SO. Cheers – legoblocks Mar 14 '15 at 12:40
  • 1
    No problem, sometimes I wish I could just take over the keyboard and screen and help fix issues, but I guess that would really go beyond what SO is for :) – Maarten Bodewes Mar 14 '15 at 12:43