I am using the BigInteger Javascript library to create a symmetric key using Diffie-Hellman protocol. I want to create 128,160 or 192-bit keys. After some research, I have found out that I should use Diffle Hellman 2048 bits, but :

  • What bit-length should be the D-H parameters : p, g, a (and b) ? I am currently using p 2048-bit and a,b 256 bit, is that good ?
  • At the end of the protocol, I get a BigInteger 2048-bits key, how can I derive a 128, 162 or 192-bit key from it ?

I am also using Stanford Javascript Crypto library to encrypt/decrypt messages using AES-128/160/192. AES takes as argument a key of type bitArray or string.

  • Once I get a 128-bit BigInteger key, how can I use it with the AES protocol ?

I thought at first to convert the BigInteger key to a string key and then use it with AES but I don't think it's right. Because I don't know how the function sjcl.encrypt(key,message) convert the key when it's a string, if it converts it from a utf8String to a bitArray then the key won't be 128-bit but much more. So I think the best idea would be to convert the BigInteger key to a bitArray key. If so, do you have any idea how to to that ?

Otherwise, if you know a library that would allow me to use the DH protocol and that fit well with the Stanford library ...

Thank you for your help.

EDIT : I am not inventing my own crypto, I am implementing the HCBK protocol, which provides authenticity.

  • 1
    At a glance that big integer library seems vulnerable to timing attacks. Jul 5, 2013 at 6:20

3 Answers 3


What bit-length should be the D-H parameters : p, g, a (and b) ? I am currently using p 2048-bit and a,b 256 bit, is that good ?

DHKE is based on the discrete logarithm problem (same as DSA and ElGamal), so the size should be fine.

At the end of the protocol, I get a BigInteger 2048-bits key, how can I derive a 128, 162 or 192-bit key from it ?

I have to admit that I'm not 100% sure. If you want to be safe, hash it and then take 16 or 24 bytes from the output of the hash function. Or see below.

Once I get a 128-bit BigInteger key, how can I use it with the AES protocol ?

The Stanford Crypto Library actually exports a high-level encrypt function (see sjcl.json.encrypt), which takes as arguments a ciphertext and a password. You could simply pass in the whole 2048-bit key from the previous step as a password. This also handles block modes and generating an IV for you.

Please note (and the only reason I'm answering is to tell you this), that you're doing everything wrong. First of all, you are running your own crypto(-graphic protocol). Diffie-Hellman, in schoolbook mode, isn't safe though. Moreover, JavaScript crypto isn't safe. Secure delivery of script requires HTTPS, and if you have HTTPS, you probably don't need more crypto.

Please read all of the links and think twice, before you run crypto in production.

  • 3
    I agree that JS crypto loaded over HTTP should not be used as a replacement for TLS to be used for encryption during transport from client to server for say credit card transactions or sending passwords. However, encryption in JS can still be quite useful. E.g., one could write a JS browser extension (downloaded from a trusted source using TLS), and you encrypt your text client-side, then paste the encrypted text into gmail and send it to a recipient who has a browser plugin at their end that decrypts it; preventing any eavesdroppers who may have access to google's servers.
    – dr jimbob
    Jul 5, 2013 at 4:03
  • 1
    Though +1 for the other advice. DH can be man-in-the-middled fairly easily (Eve intercepts communication between Alice and Bob and does DH key exchange with both decrypting and re-encrypting every message with neither being the wiser). So you do have to be very careful in how you apply your cryptography. Granted, SJCL is good open-source code library written by Dan Boneh (a cryptographic expert) and his students. So the implementation of AES, RSA, probably are much better than ones you would implement yourself. (Though you need 16 bytes of a hash to get a 128 bit AES key).
    – dr jimbob
    Jul 5, 2013 at 4:18
  • " take 8 bytes from the output of the hash function" That'd be a 64 bit key, not a 128-256 bit key like AES expects. Jul 5, 2013 at 6:10
  • @drjimbob The library has a disclaimer on the front page: (Unfortunately, this is not as great as in desktop applications because it is not feasible to completely protect against code injection, malicious servers and side-channel attacks.) The worst part, however, is his own implementation of DH and a key exchange protocol. There are too many things that could go wrong there
    – copy
    Jul 5, 2013 at 13:42
  • @dr jimbob, that's exactly what I am doing. I should have mentionned in the topic.
    – Kheil
    Jul 5, 2013 at 13:46

I write this message for the pedagogical interest; I strongly hope that you are not envisioning slapping together your own crypto protocol and implementation, and then deploy that in production, because much sorrow and grinding of teeth usually awaits the poor developer who tries to walk that path.

Diffie-Hellman is a protocol which takes places in a group; the "plain" DH works in a subgroup of non-zero integers modulo a given prime p, with multiplication as group law. So you have:

  • the modulus, a big prime p
  • a "generator" g, which is an integer modulo p and has order r

g must not be equal to 0 or 1. The order of g is the smallest non-zero integer r such that gr = 1 mod p. Let's call q the biggest prime factor of r. Depending on how p and g are produced in the first place, you might arrange for r = q (i.e. the order of g is prime).

For DH to be secure, it is necessary that both p is large enough, and q is large enough, to make discrete logarithm unfeasible. That's not the same notion of "large". Roughly speaking, p should be 2048-bit long, and q should be 256-bit long or so. There is no condition on g itself; you can have g = 2 with no ill effect, as long as it generates a subgroup whose order admits a large enough prime factor q.

In DH, party X generates a random x (ideally an integer chosen uniformly modulo q, but a random 256-bit integer is fine too) and computes and sends gx mod p to party Y. Similarly, Y generates y and sends gy mod p to party X. The "shared secret" is the value z = gxy mod p, which both X and Y can compute. The value z is an integer modulo p, and actually a member of the subgroup generated by g; but X and Y need a "symmetric key", i.e. a sequence of bits with some uniformity. There must be some transform which yields a value of the right size while hiding mathematical structure, and not losing entropy. The usual expedient is to encode z into a sequence of bytes (256 bytes, since that's a number in the 1..p range, and p has length 2048 bits) and then hash it with a good hash function (say, SHA-256). This will yield a hash output that you can, then (and only then) truncate to the size you need (e.g. 128 bits).

Note that raw DH does not include authentication. It is weak to a man-in-the-middle attack unless at least one party (say, the client) has some strong guarantee that it has the correct DH public value from the server, and not a fake one. DH won't offer that guarantee.

Also, once you have a shared 128-bit key, you are not at the end of your trouble. Proper symmetric encryption is hard. A block cipher such as AES is a primitive which does not encrypt messages per se; you have to use it in mode of operation, which has some extra requirements such as a properly generated IV. You will also need some kind of MAC for integrity; combining encryption and MAC is a matter of subtlety. The overall protocol must also make some provisions to avoid replay attacks and reordering of individual packets.

Basically, you have to build something like SSL, which takes care of all these details. So this begs the question: why don't you use SSL ? Javascript runs in a Web browser who already includes a complete SSL implementation (that's what is used when the URL begins with https://).

  • Thanks for the details on DH, I was not aware of the number q so I'll check that. So I follow you well, I gotta convert my BigInteger 2048-bit to a byte array then hash it with sha256. However, I read that the input of sha256 must not be greater than 64-bit, is that true ? The protocol takes care of authentication so value of DH that parties receive are guarantee.
    – Kheil
    Jul 5, 2013 at 13:51
  • 1
    No, you read it wrong: the length (in bits) of the input to SHA-256 must fit on 64 bits, which means that the input must be no longer than 2^64-1 bits (i.e. 18446744073709551615 bits, which is approximately 2 millions of terabytes). Jul 5, 2013 at 14:06

As everyone says, make sure experts analyze and try to break your cryptosystem even if it is largely pieced together from other cryptosystems in a secure manner. Even then, I would still treat it as a potential insecure application and only use it for "toy" needs (versus thinking it has been equally vetted compared to well known tools like openssl / GPG -- and even these tools have had well-publicized flaws found years later). Personally, you don't seem to be familiar with cryptographic hashes (thinking that SHA-256 can't encrypt more than 64-bits), so I strongly recommend taking a course or two on cryptography. (Coursera has two great courses by Dan Boneh; and udacity has a good course in Applied Cryptography).

It's very easy to use a javascript crypto library in a very weak way:

  • have a user go to a web page, get served a javascript file over http from that webpage to perform cryptography (e.g., user types a phrase, enters a passphrase that derives a key and generates an encrypted message). This makes it trivial for an attacker to modify the JS file.
  • Even using https to deliver it, means anyone at the delivering servers end could maliciously alter the file compromising its security. Therefore, this scenario fundamentally allows the server to alter the javascript file in a way that could compromise the security.

However, javascript (really ECMAScript) is just a programming language - it is not only used in web browsers from freshly served pages. It could be used in long lived browser extensions (downloaded once over SSL from a trusted source, run many times, in a manner analogous to how OpenSSL or GPG is initially downloaded once from a trusted source, installed, and run repeatedly), or as just another scripting language in the shell (node.js). A claim that "JS crypto is insecure" is roughly similar to say "python crypto is insecure" and not too far from "C++ crypto is insecure".

I'm not particularly familiar with Hash Commitment Before Knowledge protocol (and not really interested in learning about it as the link you mentioned talked about patent restrictions in the upper right), so will analyze a much simpler scenario where JS crypto could be used.

Alice and Bob both share a passphrase (established in person, generated randomly from a diceware dictionary) and have agreed on a good password based key derivation function (say 5000 rounds of SHA-512 and take first 256-bits) and a symmetric encryption protocol (AES-256 randomized CTR mode). They want to use cloud services (like google drive or dropbox or amazon web services) to store their encrypted data, but only store the javascript encryption/decryption script on a local non-shared computer they keep secure. In principle, they could use a JS crypto library to run AES-256, store it in their web-browser as a browser extension. They could both have the same browser extension stored on both their computers that upon input of their passphrase will generate their key and can encrypt or decrypt messages/files for them.

In this sort of scenario, timing attacks on the client-side local key generation phase would be irrelevant - as long as no network information goes out when the key begins to be generated. Replay attacks may be of significance, though messages could contain an encrypted time-stamp (so if you repeated the message "Transfer $100 from Alice to Bob- sent: July 4th, 2013 at noon" you won't repeat the action if you already performed the action on July 4th). Yes it would be trivial for an attacker with access to a computer with the browser extension to maliciously modify it (e.g., add a keylogger and record/transmit the key to someone). But this is not that different from an attacker installing a keylogger on a compromised machine or downloading the source code for OpenSSL, compiling it, and replacing OpenSSL with a compromised version. Again, if the computer you are using for encryption/decryption is compromised, don't expect to be able to keep your cryptosystem secure.

Granted as a browser extension, you must be very careful that you don't accidentally leak information via AJAX calls. Your web browser works with a lot of javascript files being executed simultaneously. For example, let's say you wanted to AES encrypt your gmail messages. You go to mail.google.com press compose, start typing out your message in the compose window, finish your message, run your browser extension which replaces your plaintext in the message body with AES-encrypted ciphertext, and then press send. This is insecure. Gmail automatically sends your draft in the compose window to their servers via AJAX calls while you are typing it (to save as a draft in case your connection gets cut off).

PS: I deliberately have a flaw in my simple AES encryption scheme where no message authentication was present that would allow a man-in-the-middle to change a message "Attack at dawn" to "Attack at dusk" very easily. (Originally I wasn't going to point this out; but I'm trying to repeat the point that encryption is subtle").

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .