Where does Linux openssl AES save the IV [duplicate] - encryption

I've generated a random 256 bit symmetric key, in a file, to use for encrypting some data using the OpenSSL command line which I need to decrypt later programmatically using the OpenSSL library. I'm not having success, and I think the problem might be in the initialization vector I'm using (or not using).
I encrypt the data using this command:
/usr/bin/openssl enc -aes-256-cbc -salt -in input_filename -out output_filename -pass file:keyfile
I'm using the following call to initialize the decrypting of the data:
EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, keyfile.data(), nullptr))
keyfile is a vector<unsigned char> that holds the 32 bytes of the key. My question is regarding that last parameter. It's supposed to be an initialization vector to the cipher algorithm. I didn't specify an IV when encrypting, so some default must have been used.
Does passing nullptr for that parameter mean "use the default"? Is the default null, and nothing is added to the first cipher block?
I should mention that I'm able to decrypt from the command line without supplying an IV.

What is the default IV when encrypting with EVP_aes_256_cbc() [sic] cipher...
Does passing nullptr for that parameter mean "use the default"? Is the default null, and nothing is added to the first cipher block?
There is none. You have to supply it. For completeness, the IV should be non-predictable.
Non-Predictable is slightly different than both Unique and Random. For example, SSLv3 used to use the last block of ciphertext for the next block's IV. It was Unique, but it was neither Random nor Non-Predictable, and it made SSLv3 vulnerable to chosen plaintext attacks.
Other libraries do clever things like provide a null vector (a string of 0's). Their attackers thank them for it. Also see Why is using a Non-Random IV with CBC Mode a vulnerability? on Stack Overflow and Is AES in CBC mode secure if a known and/or fixed IV is used? on Crypto.SE.
/usr/bin/openssl enc -aes-256-cbc...
I should mention that I'm able to decrypt from the command line without supplying an IV.
OpenSSL uses an internal mashup/key derivation function which takes the password, and derives a key and iv. Its called EVP_BytesToKey, and you can read about it in the man pages. The man pages also say:
If the total key and IV length is less than the digest length and MD5 is used then the derivation algorithm is compatible with PKCS#5 v1.5 otherwise a non standard extension is used to derive the extra data.
There are plenty of examples of EVP_BytesToKey once you know what to look for. Openssl password to key is one in C. How to decrypt file in Java encrypted with openssl command using AES in one in Java.
EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, keyfile.data(), nullptr))
I didn't specify an IV when encrypting, so some default must have been used.
Check your return values. A call should have failed somewhere along the path. Maybe not at EVP_DecryptInit_ex, but surely before EVP_DecryptFinal.
If its not failing, then please file a bug report.

EVP_DecryptInit_ex is an interface to the AES decryption primitive. That is just one piece of what you need to decrypt the OpenSSL encryption format. The OpenSSL encryption format is not well documented, but you can work it backwards from the code and some of the docs. The key and IV computation is explained in the EVP_BytesToKey documentation:
The key and IV is derived by concatenating D_1, D_2, etc until enough
data is available for the key and IV. D_i is defined as:
D_i = HASH^count(D_(i-1) || data || salt)
where || denotes concatentaion, D_0 is empty, HASH is the digest
algorithm in use, HASH^1(data) is simply HASH(data), HASH^2(data) is
HASH(HASH(data)) and so on.
The initial bytes are used for the key and the subsequent bytes for the
IV.
"HASH" here is MD5. In practice, this means you compute hashes like this:
Hash0 = ''
Hash1 = MD5(Hash0 + Password + Salt)
Hash2 = MD5(Hash1 + Password + Salt)
Hash3 = MD5(Hash2 + Password + Salt)
...
Then you pull of the bytes you need for the key, and then pull the bytes you need for the IV. For AES-128 that means Hash1 is the key and Hash2 is the IV. For AES-256, the key is Hash1+Hash2 (concatenated, not added) and Hash3 is the IV.
You need to strip off the leading Salted___ header, then use the salt to compute the key and IV. Then you'll have the pieces to feed into EVP_DecryptInit_ex.
Since you're doing this in C++, though, you can probably just dig through the enc code and reuse it (after verifying its license is compatible with your use).
Note that the OpenSSL IV is randomly generated, since it's the output of a hashing process involving a random salt. The security of the first block doesn't depend on the IV being random per se; it just requires that a particular IV+Key pair never be repeated. The OpenSSL process ensures that as long as the random salt is never repeated.
It is possible that using MD5 this way entangles the key and IV in a way that leaks information, but I've never seen an analysis that claims that. If you have to use the OpenSSL format, I wouldn't have any hesitations over its IV generation. The big problems with the OpenSSL format is that it's fast to brute force (4 rounds of MD5 is not enough stretching) and it lacks any authentication.

Related

JASYPT: How to Decrypt the Digested String using StandardByteDigester

I am pretty new to this JASYPT library and I am working on a Project that uses JASYPT StandardByteDigester for Encrypting passwords. Now I want to get the decrypted string, and can't find any function that does the same.
String password = "Password";
byte[] password_bytes = password.getBytes("UTF-8");
byte[] digest = this.byteDigester.digest(messageBytes);
What is the reverse of this ? I mean how to enter the encrypted bytes, and get the decrypted String ?
StandardByteDigester() creates the hash of the password, this process is not reversible. If you want to test the equality with a second password, this second password is also to be hashed and the hashes are to be compared.
StandardByteDigester uses by default MD5 (which is insecure), a random 8 bytes salt and 1000 iterations (nowadays generally too small). But this can be changed.
Note that to compare two passwords, the parameters used, i.e. digest, salt, and iterations, must be the same.

How to encrypt in AES using CryptoJS with key size of 128?

I have searched and found examples of AES with the default 256 key size and find it worked already. But when I want to use 128 key size, there is little information.
I have extracted code from the aes test from CryptoJS:
var C = CryptoJS;
var plainText = '00112233445566778899aabbccddeeff';
var key = '000102030405060708090a0b0c0d0e0f';
var encryptedText = C.AES.encrypt(C.enc.Hex.parse(plainText), C.enc.Hex.parse(key), { mode: C.mode.ECB, padding: C.pad.NoPadding }).ciphertext.toString();
console.log(encryptedText);
var decryptedText = C.AES.decrypt(C.lib.CipherParams.create({ ciphertext: C.enc.Hex.parse(encryptedText) }), C.enc.Hex.parse(key), { mode: C.mode.ECB, padding: C.pad.NoPadding }).toString();
console.log(decryptedText);
This worked, but if I want to use a different plain text like 'Hello World' then it failed. Also what if I want to use a password like 'my-key-001'? As I have read that CryptoJS expect to use 256 key size if I pass a password.
Your help is much appreciated.
This worked, but if I want to use a different plain text like 'Hello World' then it failed.
You have used the noPadding and that is the issue. The example is multiple of 16-byte that causes no problem, however your next plaintext is not. You can use noPadding if
your message is an exact multiple of the block size, though still not recommended.
you want to pad the message yourself, probably that is you want to test a new padding scheme that we don't see in your code.
You should you padding like
padding: CryptoJS.pad.Pkcs7
As I have read that CryptoJS expect to use 256 key size if I pass a password.
CryptoJS supports AES-128, AES-192, and AES-256. According to your key size it will select the key variants. If you use a password it will generate a 256-bit size. That is %40 times slower than AES-128 since it requires 14 rounds. However use a good password, see below.
Also what if I want to use a password like 'my-key-001'?
A password with high entropy is important otherwise the attackers can be successful by testing passwords. The key generation cannot increase entropy. Therefore you need a good way to generate high entropy passwords like using diceware.
How to encrypt in AES using CryptoJS with key size of 128?
Just provide a 128-bit key.
Does AES-128 has 128-bit security
Any block cipher, not only AES, has vulnerable to multi-target attacks. In that case it is not providing 128-bit security. Therefore you should use 192 or 256-bit keys.
For a more detailed see this question Has AES-128 been fully broken?
mode: C.mode.ECB
The ECB mode of operations is not advised, it is insecure and it leaks pattern. You should use modern encryption modes like AES-GCM which provides you not confidentiality but also, integrity and authentication.
While using GCM mode, make sure that you never use the same IV/nonce again under the same key. AES-GCM uses CTR mode for encryption and under the same key if the IV/nonce repeated then crig-dragging is possible. Also, it can leak the authentication key.

MD5 Public-Private Key Encryption (python)

I've trying to encrypt my data using asymmetric encryption. I've chosen MD5 as the algorithm. PS: I know about MD5 collisions.
I'm following this blog to encrypt and decrypt my data. This uses SHA256. I'm able to run the code successfully with SHA1, SHA512 as well, but not with MD5.
Whenever, I change the algorithm to MD5, it says
cryptography.exceptions.UnsupportedAlgorithm: This combination of padding and hash algorithm is not supported by this backend.
Which padding should be used to encrypt the data with MD5?
My Code:-
# ########## Encrypting and decrypting ##########
message = b'encrypt me!'
encrypted = public_key.encrypt(
message,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.MD5()),
algorithm=hashes.MD5(),
label=None
)
)
original_message = private_key.decrypt(
encrypted,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.MD5()),
algorithm=hashes.MD5(),
label=None
)
)
Actually, MD5 is (an old) hash algorithm, it is not an encryption algorithm. A hash is used to get a sort of "checksum" for a given text (or data byte array). That "checksum" as a fix length, whatever is the size of the text you hash.
In cryptography, you typically may use hash function to get a private (symmetric) key from a passphrase or you may encrypt a hash with a private key : this is a digital signature.

how can i set blowfish for CRYPT_BLOWFISH function in php

i use this code for encrypt my data to blwofish but i dont know really to convert to blowfish or other encryption.
echo crypt('ab','$2a$09$anexamplestringforsalt$')."\n";
and i'm try bottom code but it's false
echo CRYPT_BLOWFISH('ab','$2a$09$anexamplestringforsalt$')."\n";
It is the crypt parameter string, that defines which algorithm is used:
$2a : This describes the algorithm (BCrypt) but should be 2y nowadays
$09 : This is the number of rounds and is usually 10 or higher
$anexamplestringforsalt : This should be a really random salt of a given alphabet
To generate a BCrypt hash, it is much safer to use the new password_hash() function though, there exists also a compatibility pack for earlier PHP versions.
// Hash a new password for storing in the database.
// The function automatically generates a cryptographically safe salt.
$hashToStoreInDb = password_hash($password, PASSWORD_BCRYPT);
// Check if the hash of the entered login password, matches the stored hash.
// The salt and the cost factor will be extracted from $existingHashFromDb.
$isPasswordCorrect = password_verify($password, $existingHashFromDb);

Encrypt for SagePay forms using ColdFusion

I am trying to follow a specification for an encrypted field in SagePay 3.00 using ColdFusion 10.
The requirement is to encrypt the string as AES(block size 128-bit) in CBC mode with PKCS#5 padding using the provided password as both the key and initialisation vector and encode the result in hex.
It's the "using the provided password" that is causing the problem.
At the moment I have
myStr = 'assortednamevaluepairsetc';
providedPassword = 'abcdefghijklmnop';
myCrypt = Encrypt(myStr,providedPassword,'AES/CBC/PKCS5Padding','HEX',providedPassword,1);
but that won't work because the value I have been given by SagePay causes an error - "key specified is not a valid key for this encryption: Invalid AES key length" as its only 16 characters long
According to the CF docs you need to use generateSecretKey to guarantee the key length for AES, so I've tried this but although it gives a result, it's not the right result in terms of the encryption
myStr = 'assortednamevaluepairsetc';
providedPassword = 'abcdefghijklmnop';
mySecret = GenerateSecretKey('AES');
myCrypt = Encrypt(myStr,mySecret,'AES/CBC/PKCS5Padding','HEX',providedPassword,1);
Any help on this gratefully received.
use generateSecretKey to
guarantee the key length for AES
That function is only used when you need to generate a completely new encryption key. You already have one. The primary purpose of generateSecretKey is to ensure you generate a strong encryption key, that is sufficiently random.
won't work because the value I have been given by SagePay causes an
error - "key specified is not a valid key for this encryption: Invalid
AES key length" as its only 16 characters long
A key length of 16 bytes (ie 128 bits) is acceptable for AES. The problem is encrypt() expects the "key" to be a base64 encoded string, which is about thirty-three percent longer than a plain string. When you invoke encrypt(..), CF decodes the provided "key" string into bytes, ie Essentially doing this:
<cfset keyBytes = binaryDecode(yourPassword, "base64")>
<cfoutput>length = #arrayLen(keyBytes)# bytes</cfoutput>
Since your password string is not base64 encoded, the resulting key length is too small, ie (12) instead of (16) bytes. Hence the error message.
The solution is to base64 encode it first. How you do that depends on the encoding of the string. It sounds like it is just a plain text string (hopefully a sufficiently random one...). If so, use charsetDecode to decode the string from the relevant charset (ie utf-8, etcetera), then binaryEncode it to base64:
<cfset keyIVBytes = charsetDecode(yourKeyString, "utf-8")>
<cfset base64Key = binaryEncode(keyIVBytes, "base64")>
Also, the iv parameter should be binary. Since key and iv are one in the same, simply use the byte array from the previous step. Also, drop the iterations parameter, as it does not apply. With those changes it should work as expected:
encrypt(myStr, base64Key,"AES/CBC/PKCS5Padding", "hex", keyIVBytes)
NB: I am not an encryption expert but ... using the key as an iv is NOT a great idea... Might want to check with them to see if there are other options.

Resources