Do string decryption require guid and iv (initialization vector) - netsuite

I am doing string encryption like below using the guid and storing the cipherout.ciphertext value but not storing the cipherout.iv value.
But when decrypting , why cant i just pass the key , instead of passing both key and cipherout.iv values. Because it is asking for both values while decrypting it. Do i need to store both key and cipherout.iv values for decrypting?
Please advice
FIRSTFILE.js :
var guid = "4ab23a136dc347d";
var inputString = "sometext";
// Create the key
var key = crypto.createSecretKey({guid:guid, encoding:encode.Encoding.UTF_8});
// Encrypt
var cipher = crypto.createCipher({algorithm: crypto.EncryptionAlg.AES, key: key});
cipher.update({input: inputString, inputEncoding: encode.Encoding.UTF_8});
var cipherout = cipher.final({outputEncoding: encode.Encoding.HEX});```
SECONDFILE.JS
// Decrypt
var decipher = crypto.createDecipher({algorithm: crypto.EncryptionAlg.AES, key: key, iv:cipherout.iv}); //HERE
decipher.update({input: cipherout.ciphertext, inputEncoding: encode.Encoding.HEX});
var decipherout = decipher.final({outputEncoding: encode.Encoding.UTF_8});```

Yes, You need to store both. Without initial vector it's not possible to decrypt message even with password. The idea is: password can be same for all messages, but IV is created when it was encrypted and it's different always.
IV can be encrypted with 4096 RSA, but all message cab be too long for RSA and you encryp it with AES.
AES is not good from security perspective, so we need use password AND one-time-key - initial vector.

Related

Cipher algorithm without initialization vector

I'm looking for a cipher algorithm which doesn't require an initialization vector. I use the NodeJS function crypto.createCipheriv which documents at least the option to pass no initialization vector.
If the cipher does not need an initialization vector, iv may be null.
const encryptionAlgoritm = 'aes-192-cbc';
const encryptionKey = '...';
const cipher = createCipheriv(encryptionAlgoritm, encryptionKey, null);
// Error: Missing IV for cipher aes-192-cbc
Which OpenSSL algorithm can be used without the iv parameter?
Background: I don't need to decrypt the encrypted value. I want to pass the encrypted value to the database and also query the database with the encrypted value. Therefore the encryption algorithm needs to be bijective.

nodejs recover createCipher data with createCipheriv

I have some encrypted data in my database
I did it few years ago using crypto.createCipher
const cipher = crypto.createCipher('aes192', password);
As createCipher and createDecipher is deprecated, I would like to change to createCipheriv and createDecipheriv. The problem is that the data I have in my database are encoded without iv.
Is it possible to decode with createDecipheriv data encoded with createDecipher and to generate the same secret with createCipher and createCipheriv.
I tried setting the iv to null but not working
Thanks, because the database migration is an heavy work !
I tried setting the iv to null but not working
This is because this method didn’t allow for passing an initialization vector (IV), and instead derived the IV from the key using the OpenSSL EVP_BytesToKey derivation function, using a null salt meaning that the IV would be deterministic for a given key which is an issue for ciphers with counter mode like CTR, GCM and CCM.
Looking at your code:
const cipher = crypto.createCipher('aes192', password);
If you want to make this code backwards compatible, you need to call OpenSSL’s EVP_BytesToKey function yourself, typically through evp_bytestokey module which makes it available in JS userland.
Is it possible to decode with createDecipheriv data encoded with createDecipher and to generate the same secret with createCipher and createCipheriv.
Yes, you can. check out my example code here:
const crypto = require('crypto');
const EVP_BytesToKey = require('evp_bytestokey')
const ALGO = 'aes192';
const password = 'Your_Password_Here';
const KEY_SIZE = 24;
function decrypt_legacy_using_IV(text) {
const result = EVP_BytesToKey(
password,
null,
KEY_SIZE * 8, // byte to bit size
16
)
let decipher = crypto.createDecipheriv(ALGO, result.key, result.iv);
let decrypted = decipher.update(text, 'hex','utf8') + decipher.final('utf8');
return decrypted.toString();
}
function encrypt_legacy_using_IV(text) {
const result = EVP_BytesToKey(
password,
null,
KEY_SIZE * 8, // byte to bit size
16
)
var cipher = crypto.createCipheriv(ALGO, result.key, result.iv);
var encrypted = cipher.update(text, 'utf8', 'hex') + cipher.final('hex');
return encrypted.toString();
}
For complete running example, clone node-snippets and run node apogee-legacy-crypto-cipheriv.js.
However the reason this function is deprecated in the first place is because you shouldn’t use it, and instead use a random unpredictable IV, which requires you to change your code to something like this:
const iv = crypto.randomBytes(16)
const cipher = crypto.createCipheriv('aes192', password, iv)
Here, for AES-192 in CBC mode (aes192 being aliased to AES-192-CBC by OpenSSL), the IV size is expected to be the same as the block size, which is always 16 bytes.
In order to decrypt the message, you will need the IV as well. Typically you’d store the IV together with the message, as the important part is for the IV to not be predictable ahead of time.

Is there a way to get same encrypted hash value with some secret key?

I want to encrypt sensitive data in an encrypted format and save it to db. But later I have to be able to decrypt with a secret key used to decrypt. Importantly, encryption must give always the same hash.
const algorithm = 'aes256';
const iv = crypto.randomBytes(16).toString('hex').slice(0, 16);
const key = crypto
.createHash('sha256')
.digest('base64')
.substr(0, 32);
const cipher = crypto.createCipheriv(algorithm, key, iv);
const encrypted =
cipher.update(String('tobeEncrypted'), 'utf8', 'hex') + cipher.final('hex');
console.log(encrypted);
console.log(encrypted);
//e08f733a4dace8b22db763cbd2d0029e
//90086251f083c33dd6aa017a2c6f35f4
// How can I always get the same hash value?
First, your key will be the same key value. Because the value to be hashed will be empty.
const key = crypto
.createHash("sha256") // Hash algorithm
.update(process.env.SECRET_KEY) // Data to hash
.digest('base64')
.substr(0, 32);
Your result will be always different because the IV is random in each execution. So, you could store the IV in the database, in the final message, or use a unique depending on other values like the key or the data.
There is no security risk if you save the IV in your database or if you expose it.
Refs:
Is it safe to store AES IV prepended to CipherText in a DB?
When using AES and CBC, is it necessary to keep the IV secret?

Node.js crypto: too short encryption key

I want to encrypt a user's data with AES-256 to store it securely in my database. However, I have the problem that the key must be 32 characters long. But the passwords of my users are usually much shorter. Is there a way how I can "extend" the length of the passwords?
I also thought about the fact that human-made passwords are usually weak. So I would need some kind of function that "links" the password to the encryption key?
Here is my code, which I use to encrypt and decrypt:
const crypto = require('crypto');
const algorithm = 'aes-256-cbc';
const key; //Here I would get the password of the user
function encrypt(text) {
const iv = crypto.randomBytes(16);
let cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(key), iv);
let encrypted = cipher.update(text);
encrypted = Buffer.concat([encrypted, cipher.final()]);
return { iv: iv.toString('hex'), encryptedData: encrypted.toString('hex') };
}
function decrypt(text) {
let iv = Buffer.from(text.iv, 'hex');
let encryptedText = Buffer.from(text.encryptedData, 'hex');
let decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(key), iv);
let decrypted = decipher.update(encryptedText);
decrypted = Buffer.concat([decrypted, decipher.final()]);
return decrypted.toString();
}
Many thanks for answers in advance.
Update 1.0:
After some research I have found the following code: (Source)
const crypto = require('crypto');
// Uses the PBKDF2 algorithm to stretch the string 's' to an arbitrary size,
// in a way that is completely deterministic yet impossible to guess without
// knowing the original string
function stretchString(s, outputLength) {
var salt = crypto.randomBytes(16);
return crypto.pbkdf2Sync(s, salt, 100000, outputLength, 'sha512');
}
// Stretches the password in order to generate a key (for encrypting)
// and a large salt (for hashing)
function keyFromPassword(password) {
// We need 32 bytes for the key
const keyPlusHashingSalt = stretchString(password, 32 + 16);
return {
cipherKey: keyPlusHashingSalt.slice(0, 32),
hashingSalt: keyPlusHashingSalt.slice(16)
};
}
If I got everything right, this should solve my problem: From any password I can generate a secure encryption key with a given length using the above function. The same password always generates the same encryption key with the function keyFromPassword(password), right?
Update 2.0:
Thanks to #President James K. Polk, who gave me some important tips, I have now updated my code. I hope that everything is fine now.
You should not be using your user's passwords directly as keys. Instead, you can use them as input to a key-derivation algorithm like pkbdf2.
As this paper on PKBDF2 explains:
Unfortunately, user-chosen passwords are generally short and
lack enough entropy [11], [21], [18]. For these reasons, they cannot
be directly used as a key to implement secure cryptographic systems. A possible solution to this issue is to adopt a key derivation
function (KDF), that is a function which takes a source of initial
keying material and derives from it one or more pseudorandom keys.
A library for computing pkbdf2 for Node.js, for example is found here.
Always add a salt to the text, and append it to the end of the text. The salt can be a randomly generated string of arbitrary length and can easily satisfy the 32-char length limit. In addition, adding salts before encryption strengthens the encryption.

Decrypt secret using ECDH and nodejs crypto

This is the nodejs documentation example:
const crypto = require('crypto');
const alice = crypto.createECDH('secp256k1');
const bob = crypto.createECDH('secp256k1');
// Note: This is a shortcut way to specify one of Alice's previous private
// keys. It would be unwise to use such a predictable private key in a real
// application.
alice.setPrivateKey(
crypto.createHash('sha256').update('alice', 'utf8').digest()
);
// Bob uses a newly generated cryptographically strong
// pseudorandom key pair bob.generateKeys();
const alice_secret = alice.computeSecret(bob.getPublicKey(), null, 'hex');
const bob_secret = bob.computeSecret(alice.getPublicKey(), null, 'hex');
// alice_secret and bob_secret should be the same shared secret value
console.log(alice_secret === bob_secret);
I don't understand where the secret comes in. Suppose I want to decrypt a message foo-bar from Bob (encrypted with Alice public key). I have Alice's private and public key, and Bob's encrypted message how can I decrypt the message having all this?
The steps above constitute the ECDH key agreement protocol to establish a shared secret (a symmetric key) between Alice and Bob which they can subsequently use to communicate securely.
The secret key alice_secret is computed using Alice's private key and Bob's public key at Alice's end.
The key bob_secret is computed using Bob's private key and Alice's public key at Bob's end.
Both keys will be equal. Now Alice and Bob has a shared secret (alice_secret=bob_secret) which they can use to ecnrypt/decrypt messages.
Note that only public keys are exchanged here and a Man-In-The-Middle cannot get hold of either Alice's or Bob's private key.
The shared secret should be ideally converted to a proper symmetric key suitable for algorithms like AES by using a Key Derivation Function. Refer KDF
Pseudo-code
-Bob encrypts using bob_secret and AES:
var crypto = require('crypto'),
algo = 'aes-256-ctr',
var cipher = crypto.createCipher(algo,bob_secret)
var encrypted = cipher.update("foo-bar",'utf8','hex')
encrypted += cipher.final('hex');
-Alice decrypts:
var decipher = crypto.createDecipher(algo,alice_secret)
var decrypted = decipher.update(encrypted,'hex','utf8')
decrypted += decipher.final('utf8');

Resources