Elliptic Curve Cryptography with SJCL in JS and OpenSSL in Ruby

I am working on a web application that should be able to encrypt data using ECC on the server side and decrypt it in a browser. The only library I found capable of this in JS is SJCL. However, since ECC support in SJCL seems a bit abandoned at the moment, I used fork , which has support for key serialization and a demo for easier understanding.

First, I create an ECC key pair in JS:

keypair = sjcl.ecc.elGamal.generateKeys(384, 10); document.writeln(JSON.stringify(keypair.pub.serialize())); 

This outputs something like:

 {"point":[1110230655,241884220,775655552,-849225963,-883815628,-1984298210,-736346431,1387519594,-1810604283,-1235638489,1333314084,-1219216530,614640565,-1148742381,1038670260,1013716131,758346573,1162278003,1232401864,-1948620456,533899535,-1478577959,1853846180,-1553049184],"curve":384} 

Then I tried to convert this public key into a format that OpenSSL understood.

 ar = [1110230655,241884220,775655552,-849225963,-883815628,-1984298210,-736346431,1387519594,-1810604283,-1235638489,1333314084,-1219216530,614640565,-1148742381,1038670260,1013716131,758346573,1162278003,1232401864,-1948620456,533899535,-1478577959,1853846180,-1553049184] # ugly bit magic to somehow convert the above array into a proper byte array (in form of a string) kstr = [(ar.map { |i| (i>=0)?('0'*(8-i.to_s(16).length)+i.to_s(16)):("%08X" % (2**32-1+i+1)) }*'').upcase].pack("H*") # opening a public key generated with the openssl cli tool showed a structure like this: algokey = OpenSSL::ASN1::ObjectId 'id-ecPublicKey' algovalue = OpenSSL::ASN1::ObjectId 'secp384r1' algo = OpenSSL::ASN1::Sequence.new [algokey,algovalue] # for some reason OpenSSL seems to prepend 0x04 to all public keys key = OpenSSL::ASN1::BitString.new "\x04#{kstr}" root = OpenSSL::ASN1::Sequence.new [algo,key] pub = OpenSSL::PKey.read(root.to_der) 

Until this moment, my code is working fine. That is, he does not give any exceptions.

However, when creating a shared secret in both libraries, I found that SJCL generated a 96-byte tag, while OpenSSL selected 48 bytes.

Turns out my problem is that SJCL is not using simple ECDH. It uses something that seems ECMQV based on a quick Google search. Therefore, the SJCL “tag” output was a point on the curve (x and y coordinates of the point, 2 * 48 bytes), and the OpenSSL output was a shared secret (x coordinate of the point, as dictated by ECDH).

My problem is that I do not know if there is ECMQV support in OpenSSL (there are problems with the stock if I am right). Even if it did, the ruby ​​binding didn't seem to support him.

So my current questions are:

  • Are my findings documented above correct?
  • If so, does anyone know of any other ruby ​​library that I could use instead of OpenSSL that supports ECMQV?
+7
source share
1 answer

It looks like you are using ElGamal in your javascript code. I could not find any implementation for ruby, alternatives use Crypto ++ or libgcrypt and writing some glue code.

Ps: instead of this line kstr = you can just write kstr = ar.pack 'N*'

+2
source

All Articles