How to use OpenSSL to encrypt/decrypt files?
Security Warning: AES-256-CBC does not provide authenticated encryption and is vulnerable to padding oracle attacks. You should use something like age instead.
Encrypt:
openssl aes-256-cbc -a -salt -pbkdf2 -in secrets.txt -out secrets.txt.enc
Decrypt:
openssl aes-256-cbc -d -a -pbkdf2 -in secrets.txt.enc -out secrets.txt.new
More details on the various flags
How to encrypt a small text using openssl with a given public Key
The output of the openssl rsautl
command that you posted is raw bytes, not text. That's why the output looks garbled when you open it in notepad.
If you want the output of openssl rsautl
to be displayable text, you can encode the output using base64 encoding, then write the base64 encoded ciphertext to a file. This can be done by stringing a few commands together on the command line, like so:
openssl rsautl -encrypt -pubin -inkey pub.key -in plaintext.txt | base64 > encrypted.txt
You should be able to open encrypted.txt in notepad, or view it on the command line, and see the base64 encoded ciphertext.
To decrypt the base64 encoded ciphertext, you would to the following:
cat encrypted.txt | base64 -d | openssl rsautl -decrypt -inkey priv.key
How to provide string IV and Key to openssl decrypt command?
The openssl enc
command by default uses a randomly generated salt value when encrypting. It starts the output with that value, preceded by a "magic number" that represents the characters Salted__
. Taking the enc
version of your command, you can see that illustrated here:
$ printf 1234567890123456 | openssl enc -aes-256-cbc -iv 0123456789012345 -k 01234567890123456789012345678901 | hexdump -C
00000000 53 61 6c 74 65 64 5f 5f ed 6c b5 aa e2 92 4a 00 |Salted__.l....J.|
00000010 68 f7 b2 40 d2 44 44 8b fa 4c 05 95 99 cf 76 32 |h..@.DD..L....v2|
00000020 4e 15 37 65 93 00 d6 b2 ff 4d 1b 6c af 46 64 f6 |N.7e.....M.l.Fd.|
00000030
When decrypting, this same magic number is expected. Your file does not contain it, hence the error. This is an OpenSSL proprietary thing.
It is possible (but not recommended) to avoid the salting, using the -nosalt
option:
$ printf 1234567890123456 | openssl enc -aes-256-cbc -iv 0123456789012345 -k 01234567890123456789012345678901 -nosalt | hexdump -C
00000000 54 05 6a fb c3 60 a9 32 3d 2e e0 4c 2a 21 4a a1 |T.j..`.2=..L*!J.|
00000010 3c a7 34 f3 8f c4 15 33 99 dd 08 f7 e5 ef ea 57 |<.4....3.......W|
00000020
Using that same -nosalt
option on your decryption command, you should no longer get that bad magic number
. You may still run into other issues, depending on what kind of padding (if any) you used when encrypting your data, but you did not give enough information to draw any conclusions on that.
Like mentioned in the comments, there is a difference between -k
lowercase and -K
uppercase. It is relevant for your situation and you are probably using the wrong one. Check out the openssl enc
man page for more info, and to read more about the -nosalt
option as well.
Decrypt String with OpenSSL Issue Output
From the (limited) description of what you are doing, two flaws can be identified.
First, the website that you are using does apply padding when encrypting data. The plaintext that you provided consists of 48 bytes:
$ echo -n 'e679932d-12b2-48a2-8ef7-301cdb9ab57b289YH3ITIXRH' | wc -c
48
This is a multiple of 16. But the ciphertext is 64 bytes long. This can be seen by base64 decoding the ciphertext string before feeding it into wc
:
$ echo -n 'AjL4iV8YSGnNOCQYOJXIP97GjCAYp2k0QLm56XxJN0p/yu5xQh5uitX3UmfP3bzZaXDd2u6hMwp6cxO3cNL1cg==' | openssl base64 -A -d | wc -c
64
The fact that 16 bytes are added to the ciphertext even though your plaintext was a multiple of 16 bytes long means that padding is applied. So in your openssl
command, you should not use the -nopad
option.
Secondly, your openssl
command provides the secret key as a passphrase, whereas the website does not interpret the 'Secret Key' input field as a passphrase. In stead of using -pass
in your openssl
command(s), you should be using -K
, which gives the key as an actual sequence of byte values.
As an example, the following openssl
commands can be successfully reproduced in the website form:
$ echo -n '1234567890123456' | openssl enc -aes-128-ecb -K 6162636465666768696a6b6c6d6e6f70 -nosalt -base64 -A -out string.txt
$ cat string.txt
M3q3c85LGdEj9k8iep/J145kzoc/F027JCP82BRYDhU=
for encryption and
$ cat string.txt | openssl enc -d -aes-128-ecb -K 6162636465666768696a6b6c6d6e6f70 -nosalt -base64 -A
1234567890123456
for decryption.
To achieve the same results in the website, the string to be used in the plaintext input field is 1234567890123456
and the string to be used in the Secret Key input field is abcdefghijklmnop
. The contents of the field "AES Encrypted Output" will be the same as the contents of string.txt
, and that is what you need to enter into the field "text to be Decrypted" as well.
(The -n
flag for echo
and the -A
flag for openssl enc
are used to avoid newlines being added at the end).
Decrypt a text with OpenSSL using key and salt only
@Wasif and I spent some time debugging in chat and in the end believe it's most likely a compatbility issue between OpenSSL 1.1.1.d
on Windows and OpenSSL 1.1.1.b
on macOS.
We went through a number of tests and permutations, using (Key, IV)
tuples in hex, using passwords, with and without salts, and ultimately our testing came down to a simple check.
Using openssl enc -a -aes-256-cbc -pass pass:MYPASSWORD -p -in input.txt
on Windows we got:
salt=E70092FEBA619144
key=29631452F8C259DFE6FD8E9372EC4B20392395F36B7A0B11769CEBEA987E90A0
iv =93BF2E94462A43B23EF585C0F4B3F1A8
U2FsdGVkX1/nAJL+umGRRGi3ybIPFXf7qrgov7SyXnI=
Using openssl aes-256-cbc -d -a -pass pass:MYPASSWORD -in cipherText.txt (which contains 'U2FsdGVkX1/nAJL+umGRRGi3ybIPFXf7qrgov7SyXnI='
on the Mac we got:
4593573484:error:06FFF064:digital envelope routines:CRYPTO_internal:bad decrypt
Despite this simple test failing, the Mac and Windows boxes successfully encrypted and decrypted locally.
Weird, but this looks like version incompatibility.
openssl-encrypt, PHP vs commandline - how to make IVs same
This works for me
<?php
// encrypt/decrypt string
$output = false;
$encrypt_method = "AES-256-CBC";
$key = hex2bin('905E17D5F5E4939D48BD04FF47F9DE906375B87B67068B2CE5D1BBBBC8DCA291');
$iv = hex2bin('905E17D5F5E4939D0000000000000000');
$string = "123456789ABCDEFG123456789ABCDEFG123456789ABCDEFG";
$output = openssl_encrypt($string, $encrypt_method, $key, 0, $iv);
echo $output;
?>
and in the CLI
echo -n "123456789ABCDEFG123456789ABCDEFG123456789ABCDEFG" |openssl aes-256-cbc -a -K 905e17d5f5e4939d48bd04ff47f9de906375b87b67068b2ce5d1bbbbc8dca291 -iv 905E17D5F5E4939D0000000000000000 -nosalt
The differences are
- I removed the line break in the CLI with
echo -n "foo"
instead ofecho "foo"
(Otherwise you encrypt a different string ten in the PHP code). - The CLI uses a hexadecimal string,Therefore also in PHP the key string needs to be converted to hex with
hex2bin()
.
Related Topics
How to Show Line Number When Executing Bash Script
How to Find Out Mount/Partition a Directory or File Is On? (Linux Server)
How to Get the Contents of a Webpage in a Shell Variable
How to List (Ls) the 5 Last Modified Files in a Directory
Get Final Url After Curl Is Redirected
Find All Storage Devices Attached to a Linux MAChine
Recursive Copy of a Specific File Type Maintaining the File Structure in Unix/Linux
When to Use Kernel Threads VS Workqueues in the Linux Kernel
Can You Prevent a Command from Going into the Bash Shell Command History
Linux Usb: Turning the Power on and Off
Replace Whitespaces with Tabs in Linux
What Is Raw Socket in Socket Programming
Using Grep to Search for a String That Has a Dot in It