-
Notifications
You must be signed in to change notification settings - Fork 988
Asymmetric Crypto
Asymmetric crypto first has to be enabled with the --with-ecc
option (see Getting Started). Once enabled, SJCL provides EC-ElGamal (for Diffie-Hellman exchanges) and ECDSA implementations.
Name | Location | Good Until |
---|---|---|
P-192 | sjcl.ecc.curves.c192 | 2020 |
P-224 | sjcl.ecc.curves.c224 | 2030 |
P-256 | sjcl.ecc.curves.c256 | >2030 |
P-384 | sjcl.ecc.curves.c384 | >>2030 |
P-521 | sjcl.ecc.curves.c521 | >>2030 |
secp192k1 | sjcl.ecc.curves.k192 | 2020 |
secp224k1 | sjcl.ecc.curves.k224 | 2030 |
secp256k1 | sjcl.ecc.curves.k256 | >2030 |
Curves beginning with a P
were defined by NIST and are generally the standard choice.
Curves beginning with secp
are called Koblitz curves--they work significantly faster than the NIST curves but are rarely seen outside of some specific, high-throughput environments.
The number at the end of the name denotes the curve's bitsize. On a curve of n
bits, the private key is n
bits and the public key is 2n
bits.
Generating a key pair is as simple as choosing the purpose and size:
// Curve P-256. If only a bitsize is given, SJCL assumes a P-* curve.
sjcl.ecc.elGamal.generateKeys(256)
sjcl.ecc.ecdsa.generateKeys(256)
// Curve K-256.
sjcl.ecc.elGamal.generateKeys(sjcl.ecc.curves.k256)
sjcl.ecc.ecdsa.generateKeys(sjcl.ecc.curves.k256)
Generating key pairs requires that the DRBG be seeded. For more information, see Generating Random Bytes
(Do not use an ElGamal key pair as an ECDSA key pair or vice versa!)
Sometimes it's necessary to serialize a public or private key for transmission or storage, so SJCL allows converting keys to and from bit arrays, which can then be fed through any of the Codecs.
var pair = sjcl.ecc.elGamal.generateKeys(256)
var pub = pair.pub.get(), sec = pair.sec.get()
// Serialized public key:
pub = sjcl.codec.base64.fromBits(pub.x.concat(pub.y))
// uQuXH/yeIpQq8hCWiwCTIMKdsaX...
// Unserialized public key:
pub = new sjcl.ecc.elGamal.publicKey(
sjcl.ecc.curves.c256,
sjcl.codec.base64.toBits(pub)
)
// Serialized private key:
sec = sjcl.codec.base64.fromBits(sec)
// IXkJSpYK3RHRaVrd...
// Unserialized private key:
sec = new sjcl.ecc.elGamal.secretKey(
sjcl.ecc.curves.c256,
sjcl.ecc.curves.c256.field.fromBits(sjcl.codec.base64.toBits(sec))
)
In addition to passwords or shared secret keys, the sjcl.encrypt
function can also take ElGamal public keys as input and encrypt data such that only the holder of the private key can decrypt it. The cipher modes, associated data, etc. still work as before in the Symmetric Crypto section.
var pair = sjcl.ecc.elGamal.generateKeys(256)
var ct = sjcl.encrypt(pair.pub, "Hello World!")
var pt = sjcl.decrypt(pair.sec, ct)
It should be noted that this design only authenticates the receiver--the sender is functionally anonymous.
In the event that you need the shared secret key directly (to build your own protocol or something), a raw Diffie-Hellman exchange can be performed:
// Party A's private key and party B's public key.
var pub = ..., sec = ...
// Returns shared secret key as bit array.
sec.dh(pub)
// [ 352201900, -2012199574, 600590189, ...
// Returns shared secret compatible with Java generateSecret.
sec.dhJavaEc(pub)
// [ 352201900, -2012199574, 600590189, ...
The derived key is the SHA-256 hash of the shared secret point. It doesn't necessarily need to be put through a KDF, but it wouldn't hurt.
To sign and verify a corpus of data:
// Must be ECDSA!
var pair = sjcl.ecc.ecdsa.generateKeys(256)
var sig = pair.sec.sign(sjcl.hash.sha256.hash("Hello World!"))
// [ 799253862, -791427911, -170134622, ...
var ok = pair.pub.verify(sjcl.hash.sha256.hash("Hello World!"), sig)
// Either `true` or an error will be thrown.
Like key pair generation, signature generation requires that the DRBG be seeded. The hash (SHA-256 in the example) can be changed to SHA-1 or SHA-512, but it'll be truncated if it's too large for the curve's field.