23

I'm interested in knowing how and where OpenSSL inserts the generated salt on an AES encrypted data. Why? Im encrypting data in Java classes and need to guarantee that I can use OpenSSL to decrypt them.

For instance, let's say I have this encrypted base64 string, generated with the passphrase "abc":

U2FsdGVkX1+tfvgUkjErP6j2kUAVwWZzNlaAmTqhzTk= 

# generated with "openssl enc -aes-256-cbc -a"

To decrypt it we can use:

echo U2FsdGVkX1+tfvgUkjErP6j2kUAVwWZzNlaAmTqhzTk= | openssl enc -d -a -aes-256-cbc -p

# enc -d
#     decryption
# -a 
#     input is base64
# -aes-256-cbc 
#     the aes algorithm used in encryption
# -p 
#     print salt, key and iv params

Running this using the "abc" passphrase will result in:

salt=AD7EF81492312B3F
key=DEC1F5A1E5EAAA7DD539BBCFCEB1BB18868B974186ED056C27046ADD3A752C8B
iv =95A770DE9E0130E77C8E5D796D1B4EF5
Polaco

Now, we know that for AES to decrypt the data it needs the key and the Initialization Vector.

In the case of OpenSSL, the manual says the key is generated from the passphrase and a salt, and the Initialization Vector is derived from the key itself (if not manually specified). That means that the generated data doesn't need to have the IV on it, but it does need to have the salt on it, or else the key for decryption will never be generated correctly.

So, the point is, where's the salt and how's it inserted in the resulting data? Doing some basic analysis on the generated data (decoding from base64 and outputting the hex values) we can see that the salt is not prepended or appended to the resulting data, but somehow it is there:

# salt: AD7EF81492312B3F
echo U2FsdGVkX1+tfvgUkjErP6j2kUAVwWZzNlaAmTqhzTk= | openssl enc -d -base64 | od -x                                                                                                                                                                                         
0000000 6153 746c 6465 5f5f 7ead 14f8 3192 3f2b
0000020 f6a8 4091 c115 7366 5636 9980 a13a 39cd
0000040

You can see that the salt "AD7E..." is not directly present in the encrypted data. Looks like some transformation occurred.

It looks like the salt is switched pair by pair and inserted in the data, starting on byte #9. Is this a common practice or something that only OpenSSL implements?

# salt:                     AD7E F814 9231 2B3F
# switch pair by pair:      7EAD 14F8 3192 3F2B
# data: 6153 746c 6465 5f5f 7ead 14f8 3192 3f2b f6a8 4091 c115 7366 5636 9980 a13a 39cd

Edit

As Thomas Pornin stated, the problem here is that od -x outputs the raw data. As my computer is x86_64, the data is in little endian and the salt looks "swapped". I had forgotten how endianness is tricky. Now I will always remember to use od -t x1

Anyway, I'm still interested in knowing if inserting the salt at the 9th byte is a common practice or an OpenSSL specific implementation. I also noticed that the first bytes are the characters Salted__

StackzOfZtuff
  • 17,783
  • 1
  • 50
  • 86
bcap
  • 348
  • 1
  • 2
  • 6
  • Just a clarification, as I don't know the answer. In which scenario would you be using AES to encrypt data using a salt ? There was a discussion here : http://security.stackexchange.com/questions/10476/is-aes-encrypting-a-password-with-itself-more-secure-than-sha1 Are you trying to do something similar ? – sudhacker Sep 24 '12 at 19:15
  • @Polaco, thank you for this information. I was looking for the same so I can use openssl command-line tool to decrypt the text encrypted by other means. Were you able to succesfully decrypt by prefixing 'Salted__+salt_used' to the Java encrypted stuff with openssl? – Arul Selvan Mar 09 '13 at 16:52
  • related: ["Is there a standard for OpenSSL-interoperable AES encryption?"](http://crypto.stackexchange.com/questions/3298/is-there-a-standard-for-openssl-interoperable-aes-encryption) – David Cary Jan 24 '14 at 03:49

2 Answers2

14

Yes, a transformation occurred: endianness...

Look at the bytes 8 to 15: 7ead 14f8 3192 3f2b. That's your salt. It is a known quirk of od: it decodes data by 16-bit units, little-endian, then shows them "numerically", so this incurs an apparent byte swap.

Use od -t x1 to get a nicer output.

Edit: to answer your other question, what OpenSSL does is neither standard nor common practice; it is just "what OpenSSL has always done". It is not well documented.

Thomas Pornin
  • 320,799
  • 57
  • 780
  • 949
  • Thanks! All the work to analyse and write down this and the od default -x is little endian... why not big endian? legacy defaults? – bcap Sep 24 '12 at 18:42
  • 1
    @Polaco Because your computer is little-endian. And od probably just loads the bytes directly into memory so it isn't even aware of the endianess. – Zzz Sep 24 '12 at 19:44
1

Previous versions of openssl used a very weak key derivation process to derive an encryption key from the password. Version 1.1.1 of openssl now supports key derivation using PBKDF2 with a randomly generated salt, and multiple iterations (10,000 by default) of sha256 hashing. This answer is based on openssl version 1.1.1, using PBKDF2 with a randomly generated salt and 10,000 iterations of sha256 to derive a key (and iv) from the password.

First, use openssl to encrypt some plaintext, using the key derivation process described above:

echo -n 'this is the plaintext' | openssl aes-256-cbc -e -salt -pbkdf2 -iter 10000 -out ciphertext.enc -p

For more information on the options used in the openssl command above, see https://www.openssl.org/docs/man1.1.1/man1/openssl-enc.html. The -p option is used to make openssl display the salt, key, and iv. After entering the password, the -p option produces:

salt=7EFCC65B38A0ACAA
key=5A81937CD1FBB6A32C2DB9BDB2AAE5CB47D82198ED861C0C1AF6CAA18B21295E
iv =D829763E72F2DFEEBEFAA30E12E29266

xxd can be used to show the bytes in the ciphertext file produced by openssl:

xxd ciphertext.enc 

This produces:

00000000: 5361 6c74 6564 5f5f 7efc c65b 38a0 acaa  Salted__~..[8...
00000010: 5d4d 957f 380e 71ba 4a1c 0913 43ee 5791  ]M..8.q.J...C.W.
00000020: 0c29 c5c8 9f0c 1c0e f8d5 c453 e7c1 b3b6  .).........S....

As you can see, the first eight bytes of the file are the ascii codes for the string, 'Salted__'. Then, the following eight bytes are the salt itself, the same as those shown in the output produced by the -p option in the openssl command used above to encrypt the plaintext.

The following command can be used to decrypt the ciphertext file:

openssl aes-256-cbc -d -salt -pbkdf2 -iter 10000 -in ciphertext.enc -p

Again, the -p option is used to display the salt, key, and iv. After entering the password, the -p option shows the same salt, key, and iv as before. Then, the ciphertext is decrypted, producing the original plaintext:

salt=0E2FC30932D8371F
key=88DA1F925B6B64A36844FC0EC33A2DBB01B6F72C98AE36602217D00E126AC237
iv =1D5F234D86FA64C208A59FC1BA3AC915
this is the plaintext

For what it's worth, the iv is generated by the PBKDF2 function, as well as the key. The PBKDF2 function generates 48 bytes. Bytes 0-31 are the key. Bytes 32-47 are the iv. For more information, see https://crypto.stackexchange.com/questions/3298/is-there-a-standard-for-openssl-interoperable-aes-encryption/79855#79855.

mti2935
  • 19,868
  • 2
  • 45
  • 64