// node.js 0.5 Diffie-Hellman example
var crypto = require("crypto");
// the prime is shared by everyone
var server = crypto.createDiffieHellman(512);
var prime = server.getPrime();
// sharing secret key on a pair
var alice = crypto.createDiffieHellman(prime);
alice.generateKeys();
var alicePub = alice.getPublicKey();
var bob = crypto.createDiffieHellman(prime);
bob.generateKeys();
var bobPub = bob.getPublicKey();
var bobAliceSecret = bob.computeSecret(alicePub);
var aliceBobSecret = alice.computeSecret(bobPub);
I am trying to understand how to use the NodeJS crypto library for a diffie-hellman implementation, and got the above code to compute a shared secret. The problem is both Alice and Bob generate their keys after getting the shared prime. I need them to generate their respective key pairs without having to use any shared information, later than can use shared information to compute the shared secret. I can't get to see how that can be done using the NodeJS crypto library.
I see your confusion.
The Diffie-Hellman prime represents some group of numbers (cyclic group) that you perform the DH function inside, however it's not randomly generated for each person.
Check out my answer here.
The prime/group is known prior to key generation and static.
There are only few groups used, see here for more.
To be clear, in order to generate the same keys, you just need to make sure both ppl are operating inside the same group with the same DH params.
Related
I am trying to implement a client side method to encrypt data in transit, and the key will be generated from client side with node.js
Right now, i am stuck in a situation that, it seems only RSA key can satisfy the asymmetric encryption for my use case, but the key can only be generated randomly but not deterministically. However, I want the client to be able to regenerate the key from a seed (e.g. a long hash) every time they log on the system, and the key must not be stored on a server.
Is that any workaround or other encryption method that suits my use case? Did some research and came across the npm package below, which said to be able to go the above with RSA.
is there some potential risk for the implementation?
As I pointed out in another answer, you can use node-forge to create a "rigged" prng that consistently returns an appropriately formatted seed rather than a pseudo-random value.
Code could look like the following, grabbing user's input and generating a long hash from it:
import forge from "node-forge"
const userInput = 'The quick brown fox jumps over the lazy dog'
const md = forge.md.sha256.create();
md.update(userInput);
const seed = md.digest().toHex());
console.log(seed) // output: d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592
Then creating the PRNG and generating the keys deterministically:
// "Rigged" PRNG
const prng = forge.random.createInstance()
prng.seedFileSync = () => seed
// Deterministic key generation
const { privateKey, publicKey } = forge.pki.rsa.generateKeyPair({ bits: 4096, prng })
In order to deterministically generate a new secp256k1 key from existing key, is it safe to just take the sha256 result from old key and use it as entropy to generate a new secp256k1 key? Using this method, I can get the derived key as long as I have oldPrivKeyHex.
const ec = new EC('secp256k1');
const keyHash = shajs('sha256')
.update(oldPrivKeyHex)
.digest();
var newKey = ec.genKeyPair({ entropy: keyHash });
lib src:
https://github.com/indutny/elliptic
It is possible, but I would do it differently. I'd use the hash over the other key (or even better, the result of a key derivation function or KDF) and then directly use it for the fromPrivate method or to use the KeyPair constructor with the private key as parameter.
The reason is that the random number generator hasn't been precisely specified. If anything happens with the handling of the random number generation then you might suddenly get a different key.
The KDF or hash method will already make sure that the entropy is compressed, so the random number generator isn't required anymore. I'd of course rather use SHA-512 or SHA-256 (in that order) than a hash algorithm that provides less than 256 bits.
server code:
cipher = createCipher('aes128', 'password');
str = cipher.update('message', 'utf8', 'base64');
str += cipher.final('base64')
I want the client code (the browser) have the same algorithm as above, given the same message and password, produce the same output as the server's.
I tried CryptoJS, SJCL and some other libraries, but they use iv and salt which makes the result entirely different. In my situation, that security isn't necessary.
(I don't know exactly what iv and salt is, I just hope the code can function without them.)
UPDATE: I find that without proper knowledge of the encryption itself, using the function in this way is a huge mistake.
Per doc:
password is used to derive key and IV, which must be a 'binary'
encoded string or a buffer.
I'm going to learn some basics first.
Before asking i searched SO and found this answer which essentially says GUID are predictable and thus should never be used for anything random. But from my understanding i disagree. However this question is about squishing a GUID
From my understanding a GUID is made of part MAC address, time and random number. I dont know what part of the GUID is what but this function essentially uses it as 2 64bit ints and XOR them together. I currently use the result as 1) A reset key for people who want to reset their password. 2) Login key. When you login it sets the key in the db and cookie. Everytime you visit the site it checks to see if the cookie matches the userid and loginkey with the databases.
Is this secure? To me it feels random enough. The bytes aren't use to encrypt things and even if you know when a person logged in down to the 100milliseconds i doubt it can guess it (keep in mind checking is via network connection, not checking the DB directly in which case you have/can see the value already)
Is there a problem with this use?
public static Int64 GuidInt64(bool noZero=true)
{
Int64 randNum;
do
{
var g = Guid.NewGuid();
var buf = g.ToByteArray();
var l0 = BitConverter.ToInt64(buf, 0);
var l1 = BitConverter.ToInt64(buf, 8);
randNum = l0 ^ l1;
} while (noZero && randNum == 0);
return randNum;
}
"Secure enough" is relative, and varies based on how sensitive the data is that you're protecting, and the likelihood of an attack.
On a banking system I'd have doubts, but on a site like StackOverflow, where there's not much sensitive data or not much that can be done with a stolen identity (except trash a reputation) I'd say it's secure enough.
It all boils down to risk and reasonable mitigation of the risk.
That said, with so many good, existing encryption algorithms, it's still better to use a one-way hash to store username and password, or other similar security keys.
Why are you using a GUID at all?
using (var rng = new System.Security.Cryptography.RNGCryptoServiceProvider())
{
byte[] inBytes = new byte[4];
rng.GetBytes(inBytes);
return BitConverter.ToInt64(inBytes,0);
}
you may also want to check for collisions before accepting the generated value.
I'm using a technique borrowed out of a book by Bruce Schneier and Niels Ferguson called Practical Cryptography. Basically, it boils down to this:
Bob does this:
pubk_A = Alice's public key
entropy = bytes from cryptographic quality PRNG
encrypted_entropy = RSA_Encryptpubk_A(entropy)
hashed_entropy = SHA2-512(entropy)
encrypt_keyBA = hashed_entropy[0:32]
encrypt_nonceBA = hashed_entropy[32:48]
hmac_keyBA = hashed_entropy[48:64]
Bob then sends encrypted_entropy to Alice.
Then Alice does this:
privk_A = Alice's private key
entropy = RSA_Decryptprivk_A(encrypted_entropy)
hashed_entropy = SHA2-512(entropy)
encrypt_keyBA = hashed_entropy[0:32]
encrypt_nonceBA = hashed_entropy[32:48]
hmac_keyBA = hashed_entropy[48:64]
This works great for generating keys that can be used to communicate from Bob to Alice. But I need keys I can use in both directions. I was thinking of modifying the algorithm in this way:
Bob does this with entropy:
pubk_B = Bob's public key
hashed_entropyBA = SHA2-512(SHA2-256(pubk_A) + entropy
encrypt_keyBA = hashed_entropy[0:32]
encrypt_nonceBA = hashed_entropy[32:48]
hmac_keyBA = hashed_entropy[48:64]
hashed_entropyAB = SHA2-512(SHA2-256(pubk_B) + entropy
encrypt_keyAB = hashed_entropy[0:32]
encrypt_nonceAB = hashed_entropy[32:48]
hmac_keyAB = hashed_entropy[48:64]
Alice can do the same thing on her side after she obtains entropy by decrypting encrypted_entropy.
As you can see, now there are two sets of keys, one used for communicating from Bob to Alice, and another for communicating from Alice to Bob.
Is there anything wrong with this? What security risks am I taking? Is the security of the system less or more than if I simply had one party tweak a bit in the nonce? Is there a better way to handle this problem without adding round-trips?
There shouldn't be a problem with both Alice and Bob having a shared key for bi-directional communication. In fact this is a lot like SSL/TLS's shared master secret. The only consideration is that you cannot use the same iv+master key combo with any packet. Also this iv must be random.
One improvement that can be made to this Schneier/Ferguson protocol is using cmac mode, which would remove the need for the hmac_key. This would reduce bandwidth used in the handshake and cpu usage for each packet.
In terms of your variant of this protocol. You still have to rely upon transmitting encrypted_entropy = RSA_Encryptpubk_A(entropy). This is an important step because you need to have a shared secret. The use of a known value pubk_A in the key generation bothers me. Keep in mind that it should be assumed that any public key is known to the attacker. The use of sha256 doesn't make this value more random or more difficult to brute force. Thus the number of guesses the attacker has to make is equivalent for these three calculations: sha512(sha256(pubk_A)+entropy),sha512(pubk_A+entropy),sha512(entropy). Which means this is a waste of resources because you are not obtaining an advantage over your attacker.