I am encrypting objects using Node.js native crypto methods like createCipherIv.
const algorithm = "aes256";
const inputEncoding = "utf8";
const outputEncoding = "hex";
const iv = randomBytes(16);
export async function encryptObject(dataToEncrypt: object, key: Buffer) {
const clear = JSON.stringify(dataToEncrypt);
const cipher = createCipheriv(algorithm, key, iv);
let ciphered = cipher.update(clear, inputEncoding, outputEncoding);
ciphered += cipher.final(outputEncoding);
return iv.toString(outputEncoding) + ":" + ciphered;
}
Sometimes I am encrypting the same object multiple times and send it over http(s). That makes me think a man in the middle could observe that communication and maybe gain information about my user by using something like a Rainbow table to map the encrypted Data to real data over time.
Now I'm not sure if my worries make sense, but I'm thinking, that my encryption could be more secure if a add a salt to it. So far I've only come accross salt when hashing, not encrypting. Hashing is not an option for me, because I cannot rely on hashes to be equivalent. I actually have to do something with the data, so I have to be able to decrypt it again.
So my questions are:
Do my thoughts add up, and I would be better of adding salt?
Is it possible to use Node.js native crypto functions for symmetric encryption while adding salt to the mechanism in order to have different encrypted results on every run?
Basically the IV is your salt. That's it purpose (apart from initializing the chaining algorithm). So you are ok with the code you posted here. Initialization vector is random so the encrypted bytes will be different every time.
Just check it with the simple console.log you will see that resulting bytes are totally different every time.
On the other hand I don't think that this (identical encrypted bytes) is much of a concern here. I would make rather sure that the chaining method is at least CBC. Here you can read more about it:
https://en.m.wikipedia.org/wiki/Block_cipher_mode_of_operation
Also if you want to be super secure with the man in the middle attack. You can add some HMAC to your message. This will ensure that no one can flip a bit in your message to make it different. In other words it provides
data integrity and authenticity of a message.
But still if you send data over httpS, all of those safety measures are already in place. Hence the name of the examplary https cipher:
tls_dhe_rsa_with_aes_256_gcm_sha384. Extracting the things that I mentioned here. It uses aes256 with gcm chaining mode and sha348 as a hashing method for the hmac.
Related
I just started playing around with WebAuthn on localhost. I was given to understand that the signature value found in credentials.response.signature was signing credentials.response.clientDataJSON. However, for the same inputs / challenge for navigator.credentials.get I seem to be getting a different signature. My best guess is there is a timestamp or counter going somewhere into the value that is signed?
I can't seem to decode the signature or authenticatorData, which would really help me to visualize what's going on inside. I'm able to decode clientDataJSON as follows, anyone have sample code with which I code decode the other two aforementioned params?
String.fromCharCode.apply(null, new Uint8Array(credentials.response.clientDataJSON))
I also found when decoding clientDataJSON I get the occasional extra field in Chrome, which is a little annoying for my use case.
My goal is to get the user to produce the same signature or hash each time when authenticating the same PublicKeyCredential. Is there a way to do this? or are there other methods within the scrope of WebAuthn or outside of its scope to benefit from the biometric auth with which I can produce identical signatures or hashes from the same inputs?
Please forgive any misconceptions I might have about WebAuthn, I'm quite new to this amazing tech. I completely understand that this is not the original intended use of WebAuthn so a janky workaround may be needed.
My goal is to get the user to produce the same signature or hash each time when authenticating the same PublicKeyCredential.
This is actually a really bad idea. The whole purpose of signing a message with a random challenge is to avoid replay attacks. Otherwise, if an attacker somehow intercepts an authentication message, that message could simply be reused to impersonate the user.
I was given to understand that the signature value found in credentials.response.signature was signing credentials.response.clientDataJSON
That is not accurate. The signature signs authenticatorData + SHA256(clientDataJSON).
Both are variable. The authenticatorData contains a "counter" increasing each time the credential key was used to authenticate and clientDataJSON should (or must to be secure) contain a randomly server side generated challenge.
I can't seem to decode the signature or authenticatorData, which would really help me to visualize what's going on inside. I'm able to decode clientDataJSON as follows, anyone have sample code with which I code decode the other two aforementioned params?
The signature cannot be "decoded", it can only be "verified" given the adequate public key. For the other paramters authenticatorData and clientDataJSON , check out the following link at the bottom, it will decode them.
https://webauthn.passwordless.id/demos/playground.html
I also found when decoding clientDataJSON I get the occasional extra field in Chrome, which is a little annoying for my use case.
I'm not sure, I believe this is related to localhost testing.
If you want a small, fixed bit of data associated with a credential then you may wish to investigate the credBlob or prf extensions. Not all authenticators will support them, however. Many more will support prf but support for that in Chromium won't appear for a few more months. So there's not a great answer here yet, but it may work better than trying to fix the signature.
So, first things first, in general it depends on the signature scheme used whether the same signature will be produced when you use the same data as input. Check this question https://crypto.stackexchange.com/questions/26974/ where they discuss about it.
Now, coming back to WebAuthn (assuming that you use a signature algorithm that for the the same input will generate the same signature) let's look how the signature is generated. Here is a small code from my virtual authenticator that is responsible for generating the WebAuthn signature:
let authData = this._concatUint8Arrays(
rp_id_hash,
flags,
sign_count, // The signature counter will always increase
this._getAAGUID(),
credential_id_length,
credential_id,
cose_key
);
// Attestation object
let attestation_object = {'fmt': 'none', 'attStmt': {}, 'authData': authData};
// ...
// Generate signature
let client_data_hash = new Uint8Array(await crypto.subtle.digest('SHA-256', client_data));
let signatureData = this._concatUint8Arrays(authData, client_data_hash);
let signature = await Algorithms.Sign(this.private_key, signatureData);
You will notice that the data to be signed include the authenticator's signature counter which should increase each time you use the authenticator. This helps detecting replay attacks or cloned authenticator attacks (more info here).
Thus, it is not feasible to generate the same signature.
If you want to look more into what is going on under the hood of WebAuthn you can have a look into my WebDevAuthn project and browser extension that allows you to inspect the WebAuthn requests and responses.
Following code is run on a web page via script tag. Every time I load the page or run the code in the browser console - I am getting different value...
var key = 'key-123:456';
var uid = 1234567890;
var encrypted = CryptoJS.AES.encrypt(id, key);
encrypted.toString();
How can I have single "encrypted value"for "single id" regardless of how many times I load the page or run the code in console?
AES is a "block" cipher, which means it operates deterministically on fixed-length blocks from plaintext to ciphertext (and vice versa). However, it's typical (and generally preferred) to use a "mode of operation" that adds non-determinism to the encryption process. For example, CBC mode (which CryptoJS uses by default) XORs a random initialization vector with the plaintext before encrypting it (and, correspondingly, after decrypting it):
This is vastly preferred because otherwise an eavesdropper can detect duplicate blocks, which might allow an attacker to eventually understand what is being communicated -- undoing the entire point of your encryption.
However, it sounds like you want your encryption to have this specific weakness, which suggests to me that maybe you don't really want encryption at all. Instead, you might want a hash, which is a deterministic one-way transformation. (CryptoJS supports several hashes.) With a hash, a given input A will always hash to the same hash value H, so you can compare Hash(A) == Hash(B) to see if A == B. (This isn't a perfect comparison, since hashes have an infinite input space and finite output space, but hashes are deliberately designed so that it's very, very difficult to find two inputs that produce the same output.) This is how websites securely store your password: the service stores Hash(password) instead of password itself, then when a user submits a password entry, the sites compares Hash(entry) and Hash(password) to see if the entry is correct.
var hash = CryptoJS.SHA3(message);
However, if you really do need to reverse the transformed value back into plaintext and not just compare it to another hashed value, then you do need encryption. In that case, you can use the cryptographically inferior ECB mode, which has the weaknesses described above. In CryptoJS, you can do this by supplying an options object with a mode property:
CryptoJS.AES.encrypt(msg, key, { mode: CryptoJS.mode.ECB });
I have done some research on encryption and learnt how it works and what it consists of but I'm yet to fully understand how to implement password encryption.
I'm trying to encrypt my passwords that are being sent to my database, how can I achieve this?
Thanks to the information you guys provided I have had a look at hash tables, am I correct in assuming a hash table basically converts a value to a different value for example:
var HashTable = { one: [1,10,5], two: [2], three: [3, 30, 300] }
and then passes the new value to the database?
Do not encrypt passwords, when the attacker gets the DB he will also get the encryption key.
Just using a hash function is not sufficient and just adding a salt does little to improve the security. Instead iIterate over an HMAC with a random salt for about a 100ms duration and save the salt with the hash. Use a function such as PBKDF2, Rfc2898DeriveBytes, password_hash, Bcrypt or similar functions. The point is to make the attacker spend a lot of time finding passwords by brute force.
Cryptographic hash functions are substantially more sophisticated than the example in the question, their output can not be distinguished from random bits/bytes, a one bit change on the input essentially causes 50% or the output bits to change and they are not reversible.
My current project is my first in Node.js (also using MongoDB, Mongoose, and Express, if it matters), and being easily distracted, I have fallen down the rabbit hole of crypto while deciding how to handle user authentication. (No other encryption is needed on this project).
Following the pattern on this page (pattern, not code - I am having problems with installing node.bcrypt but not with node-sodium) and also this page my process is
new user submits password over https
the schema generates a salt
schema hashes a concatenation of the password and salt
schema stores the salt and the password with the user information
Now I don't know if this my personal deficiency, but I am having trouble following the libsodium documentation. node-sodium does not provide any additional information for hashing (though it does have an example for encryption).
This is the code I want to use to generate the hash:
let buf = new Buffer(sodium.crypto_pwhash_STRBYTES);
sodium.randombytes_buf(buf, sodium.crypto_pwhash_STRBYTES);
let salt = buf.toString();
let preBuffer = "somePass" + salt;
let passwordBuf = Buffer.from(preBuffer);
let hash = sodium.crypto_pwhash_str(passwordBuf, sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE, sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE);
So the question is two parts. Is this a good process, and is the code appropriate?
I've used the scrypt-for-humans package in the past for exactly this reason.
https://github.com/joepie91/scrypt-for-humans
Scrypt is a very secure hashing library and this higher level wrapper makes it hard for you to mess anything up. It's also specifically designed for securely hashing passwords so thats a positive as well :)
At the moment the best password hashing algorithm is Argon 2. There is a module called secure-password written by Emil Bay. He talks more about cryptographically secure password hashing and best practices on this podcast. Here is a snippet of what he said about Argon 2.
Normally when you lay out a threat model, perfect security from a mathematical point of view is almost never practical. (In cryptography, can be referred to as perfect secrecy which means, even if you have an enormous computer the size of the universe, it doesn’t matter how big it is, you can never break the security, but that’s not really practical in the real world.) Instead you go for something called computational secrecy. Which means you can break this, but it will cost you too much money and take too much time.
The goal of these hash functions is to make it so expensive to brute force these algorithms that there would be no point in trying. In a threat model, you know that you are not going to get perfect security but can you make it so expensive for your adversary to attack you.
Argon 2 has two parameters that make it immune to large scale GPU attacks. You can control how much memory the function is allowed to use, and you can control how much computation time taken to make a hash. A CPU usually has a lot of memory but a few cores. A GPU has very little memory but thousands of cores. Argon 2 dials up a lot of memory that you can only do about 4 or 8 simultaneous Argon 2 hashes on a single GPU which makes it too expensive to try and crack. In secure-password, I’ve taken the values that Frank Denise who made sodium which it’s built on figured out. It’s within the bounds of an interactive service like a website can afford to create reasonable security without slowing down. To hash a password, you need about 16 or 32 Mb of memory and those parameters can be controlled in Argon 2.
Personally I've used crypto and I do exactly the same 4 steps you are doing right now (after checking a few conditions 7 chars pass, one symbol, one number... ). I'll share the code using crypto.
var salt =rand(160, 36);
var salted_pass = salt + password;
var token = crypto.randomBytes(64).toString('hex'); // I even generate a token for my users
var hashed_password = crypto.createHash('sha512').update(salted_pass).digest("hex");
EDIT: Warning this is not a completly safe method of doing it, as it may turn predictibly. Refer to comments below which explain why it is not a good method.
Let's say I have am creating a webapp, where users can create a nested tree of strings (with sensitive information). These strings are presumably quite short. I want to encrypt both keys and values in this tree before saving it. All values in the tree will be encrypted client-side using a symmetric key supplied by the user. Likewise they will be decrypted client-side, when reading.
The tree is persisted in a Mongo database.
I can't decide whether I should serialize the tree and encrypt it has a whole string or whether to encrypt values individually, considering that all data in the tree will be encrypted using the same key.
What are the pros and cons of either?
From what I can tell, AES uses a block size of 128 bits, meaning that any string can grow up to 15 characters in length when encoded, which speaks in favor of encoding a serialized string (if you want to avoid overhead)
Note: Although the webapp will use both HTTPS, IP whitelisting and multifactor authentication, I want to make an effort to prevent data breach in the event the Mongo database is stolen. That's what I'm going for here. Advice or thoughts on how to accomplish this is appreciated.
Update
Furthermore, I also want my service to inspire trust. Sending data in the clear (although over HTTPS) means the user must trust me to encrypt it before persisting it. Encrypting client-side allows me to emphasize that I don't know (or need to know) what I'm saving.
I can't think of a reason why these approaches would be different in terms of security of the actual strings (assuming they are both implemented correctly). Encrypting the strings individually obviously means that the structure of the tree will not be secret, but I'm not sure if you are concerned with that or not. For example, if you encrypt each string individually, someone seeing the ciphertexts could find out how many keys there are in the tree, and he could also learn something about the length of each key and value. If you encrypt the tree as a whole serialized blob, then someone seeing the ciphertext can tell roughly how much data is in the tree but nothing about the lengths or number of individual keys/values.
In terms of overhead, the padding would be a consideration, as you mentioned. A bigger source of storage overhead is IVs: if you are using a block cipher mode such as CTR, you need to use a distinct IV for each ciphertext. This means if you are encrypting each string individually, you need to store an IV for each string. If you encrypt the whole serialized tree, then you just need to store the one IV for that one ciphertext.
Before you implement this in Javascript, though, you should make sure that you're actually getting a real improvement in security from doing client-side encryption. This article is a classic: http://www.matasano.com/articles/javascript-cryptography/ One important point is to remember that the server is providing the Javascript encryption code, so encrypting data on the client doesn't protect it from the server. If your main concern is a stolen database, you could achieve the same security by just encrypting the data on the server before inserting it in the database.
First of all, I am not a security expert ;-)
I can't decide whether I should serialize the tree and encrypt it has a whole string or whether to encrypt values individually, considering that all data in the tree will be encrypted using the same key.
I would say serializing the tree first and encrypting the result of that has the biggest con.
What plays a huge role in successfully cracking encryption is often the knowledge about certain characters that appear quite often in the original text – for example the letters e and n in English language – and doing statistical analysis based on that on the encrypted text.
Now lets say you use for example JSON to serialize your tree client-side before encrypting it. As the attacker, I would easily know that, since I can analyze your client-side script at my leisure. So I also know already that the “letters” {, }, [, ], : and " will have a high percentage of occurrence in every “text” that you encrypt … and that the first letter of every text will have been either a { or a [ (based upon whether your tree is an object or an array) – that’s already quite a bit of potentially very useful knowledge about the texts that get encrypted by your app.