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.
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 })
I am using Node.JS and the crypto module. I have a SHA-256 hash in hex string and would like to create a crypto.Hash instance out of it. I only found ways to hash the input string itself, but not to update or create a new hash. Am I missing something from the documentation?
I am looking for something like (for UUID though):
crypto.Hash.from("sha256", "hex", "d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592")
Generally there are not many libraries that do what you ask of them. There are certainly libraries where the internal state can be retrieved and restored such as Bouncy Castle, but as yet I haven't seen it in any JavaScript library. It would be very easy to create though.
Indeed, the 256 bit (total) intermediate values after each block of 512 bits will be used as final output after the last block is hashed. So if you can "restore" those values (i.e. put them in the state) then you could continue hashing after that.
This might not be that useful though, as those values already contain the padding and message size encoded into a 64 bit representation at the end of the block. So if you continue hashing after that, that padding and length will likely be included again, but now with different values.
One trick sometimes used in smart cards is to upload the intermediate values (including number of bits hashed) before the last data to be hashed, and let the smart card perform the padding, the length encoding and the final hash block operation. This is usually performed during signature calculation over large amounts of data (because you really don't want to send a whole document to smart card).
Pretty dumb if you ask me, just directly signing using a pre-calculated hash value is the way forward. Or making sure that the large swath of data is pre-hashed, and the hash is then signed (including another pass of the hash) - that way the entire problem can be avoided without special tricks.
The following small example code hashes a string to a base64- and hex string encoding.
This is the output:
buf: The quick brown fox jumps over the lazy dog
sha256 (Base64): 16j7swfXgJRpypq8sAguT41WUeRtPNt2LQLQvzfJ5ZI=
sha256 (hex): d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592
code:
var crypto = require('crypto');
const plaintext = 'The quick brown fox jumps over the lazy dog';
const buf = Buffer.from(plaintext, 'utf8');
console.log('buf: ' + buf);
const sha256Base64 = crypto.createHash('sha256').update(buf).digest('base64');
console.log('sha256 (Base64): ' + sha256Base64);
const sha256Hex = crypto.createHash('sha256').update(buf).digest('hex');
console.log('sha256 (hex): ' + sha256Hex);
Edit: I misunderstood the question, the task is to run several SHA-256 update calls (e.g. for different strings) and receive a (intermediate) result. Later this result should be used as "input" and the hashing should be proceeded with more update calls, finished with by "final"/"digest" to get the final sha-256 value about all parts.
Unfortunately there seems to be no way as the intermediate value is a final value and there (again) seems to be no way back because the final/digest calls make so additional computations (has to do with the underlying Merkle-Damgård constructions). The only way would be use an own written SHA-256 function and save the state of all internal registers, reset the registers when continuing and get the final value in the end.
An advice could be to grab the source code of a sha-256 implementation and save the internal states of all used variables. When proceeding you need to restore these variables and run the next update calls. I viewed some (Java) imps, and it does not look very difficult for me.
I need to have a limit in the output length of my cipher. I know it depends on which algorithm you use, but I didnt find how do do this.
const crypto = require('crypto');
const options = {secret : 'SECRET', algorithm : 'CAST-cbc'};
exports.encrypt = (url) => {
const encrypt = crypto.createCipher(options.algorithm, options.secret);
let cipher = encrypt.update(url, 'utf8', 'hex');
cipher += encrypt.final('hex');
return cipher;
};
This is how im generating the cipher. Thanks.
limit in the output length of my cipher
...
'm trying to build a url shortener without having to have a database behind it
Encryption will be always longer than the original plaintext. You will need to have some IV (initialization vector), encrypted information, optionally an authentication code and then all encoded into an url safe format.
In theory you may sacrifice some level of security and have some sort of format-preserving encryption, but it will be at least as long as the original source.
final hash example: 1d6ca5252ff0e6fe1fa8477f6e8359b4
You won't be able to reconstruct original value from a hash. That's why for serious url shortening service you will need a database with key-value pair, where the key can be id or hash
You may still properly encrypt and encode the original data, just the output won't be shorter.
The output depends on input, always. What you could do is pad the input or output to the desired length to generate a consistent final hash. This requires there be a maximum length to the input, however.
Beyond that, there is no way to force a length and still have something decryptable. If you simply need a hash for validation, that's a bit different. If you clarify the purpose we can help more.
Given the updates that you need a hash, not encryption, then here is how this works.
You hash the original URL and save a file to disk (or wherever, S3). That file has the name that corresponds to the hash. So if the URL is 'http://google.com' the hash may be 'C7B920F57E553DF2BB68272F61570210' (MD5 hash), so you would save 'C7B920F57E553DF2BB68272F61570210'.txt or something on the server with 'http://google.com' as the file contents.
Now when someone goes to http://yourURLShortnener.com/C7B920F57E553DF2BB68272F61570210 you just look on disk for that file and load the contents, then issue a redirect for that URL.
Obviously you'd prefer a shorter hash, but you can just take a 10 digit substring from the original hash. It increases chances of hash collisions, but that's just the risk you take.
I want to implement password reset in my Node.Js app using a very good advice from here https://stackoverflow.com/a/27580553/712347 where I would not have to record any tokens into my database.
Instead #airtonix suggested to use a hash function based on the user's login, email, password, timestamp, secret and salt.
What I don't understand is how do hash functions actually work — let's say I get a certain sequence from the data above — what would be the algorithm (and the library) to use to check if it was generated from the same data using a different salt?
Or am I misunderstanding the whole thing?
How do Hash functions generally actually work -
Hash Algorithms create a digital fingerprint of data usually called Digest or Hash. You primarily see Hash Algorithms used for comparison purposes rather than encryption.
Secure Hash Algorithms have some fundamental characteristics such as:
Non-reversible (one way function). You cannot determine the original set of data from the Digest.
The Digest will be a fixed size regardless of the original data's size.
Unique. Two different data sets cannot produce the same Digest.
What would be the algorithm and the library to use?
I would recommend SHA-2 (SHA-256 or SHA-512) as the hashing algorithm and utilize the Crypto module. It provides cryptographic functionality and a set of wrappers for OpenSSL's hash, HMAC, cipher, decipher, sign, and verify functions.
So lets say we have the following information (user.id, user.email, user.password, timestamp), concatenate it and pass it as the data parameter.
const hash = function hash(data){
// Returns a buffer containing raw bytes and converts to string
const salt = crypto.randomBytes(128).toString('base64')
// Creates and returns a Hmac object that uses the given algorithm
const hmac = crypto.createHmac('sha512', salt)
// Updates the Hmac object content with the given data
hmac.update(data)
// Calculates the digest of all of the data passed to be hashed
const digest = hmac.digest('hex')
return {
'salt' : salt,
'digest': digest
}
}
Running the above function with the same data but a different salt would result in a completely different Digest.
I am beginnging to wonder if the implementation of AES is different across libraries..
Currently i have a plaintext encrypted with PyCrypto.
Im trying to decrypt the ciphertext with Node.js's Crypto Library..
Basically with PyCrypto..
im using AES-128-CBC with a random generated IV. (which decrypts perfectly in PyCrypto)
However..
On Node.js im doing this
var buf = new Buffer(ciphertext)
var decipher = crypto.createDecipher('aes-128-cbc',aeskey)
buf = decipher.update(buf,'binary', 'binary')
buf += decipher.final('binary')
Which spits out a bunch of Garbage.... ( changing 'binary' to hex/utf8 doesnt help)
As i am using CBC (Cipher Block Chaining)...
i am prepending the IV to the beginning of the ciphertext (16 blocks)..
In PyCrypto this works perfectly, similarly to the specification of PGP, CFB usage..
Does anyone know for what reason this is not working???
Am i expecting too much of Node.js's standard libraries?
Documentation does not mention this, but aeskey you're passing to crypto.createDecipher is not the key, but a password, handled to OpenSSL's EVP_BytesToKey function.
To pass the actual raw key data one should use (presently undocumented) crypto.createDecipheriv(cipher, key, iv) function. This applies to ECB mode too, even though there's no IV in ECB.
If this fails, I think, the first step in debugging would be to try with AES KATs to see whenever the decryption code is correct.
I've tripped on a similar issue here: https://github.com/joyent/node/issues/1318
AES is a rijndael standard. It shouldn't be different. You should look into data types and default settings that are hidden. Something must be set different between the two. The key sizes might be different as 128 bit "hello" is padded with zeros I think and a smaller key would start with "hello" but have a smaller padding, therefore different.
The short answer to your question is: Yes, AES is the same in PyCrypto and Node.js' crypto module. Node's crypto is just a wrapper around openssl on your system, and PyCrypto is interoperable with OpenSSL (see http://lists.dlitz.net/pipermail/pycrypto/2010q4/000301.html).
Having said that, there are definitely bugs in the Node crypto module (though I've only experienced problems with base64 encoding, myself). So whether it's a bug or not, the problems you're experiencing are almost certainly happening in the data encoding/decoding stages.
What does your ciphertext look like? Is it a hexadecimal string? If so, then you need to do
buf = decipher.update(buf, 'hex', 'binary')
That's not how IV works in Node, you have to use crypto.createDecipheriv(cipher, key, iv) instead, otherwise you get a default baked-in one. Even in PyCrypto you should be using the third argument to AES.new as the IV, not stuffing it into the bytestream.
Make sure you use the same key and IV in both pycrypto and node.js!! Not only that, but make sure you have the same encoding in both ends:
cipher = AES.new(key.decode('hex'), AES.MODE_CBC, iv.decode('hex'))
text = json.dumps(payload)
pad = lambda s: s + (16 - len(s) % 16) * '\x07'
encryptedText = base64.b64encode(cipher.encrypt(pad(text)))
Then in node.js (sorry, no easy access to that code now), also make sure you decode your key and iv to hex