I have developed a class named Cipher that allows you to encrypt and decrypt files or strings using the OpenSSL AES-256-CBC cipher and SHA1 digest algorithms. It is interoperable with the openssl
command line tool which makes it a good introduction to using OpenSSL for ciphers.
The project has been moved to github: https://github.com/jlinoff/openssl-aes-cipher. The latest version is 1.3. It has been updated to work with the opaque contexts that were introduced in openssl-1.1.
I am re-releasing version 1.2 into the public domain on 2013-11-21 because I wish that I had found something like it when I was starting out with OpenSSL.
Release | Date | Description |
---|---|---|
1.2 | 2013-11-21 | Fixed the problem reported by Mihai Todor at line 300 in cipher.cc . |
1.1 | 2012-09-22 | Fixed a valgrind problem at line 298 in cipher.cc as reported by an anonymous user. |
1.0 | 2012-02-14 | Initial release with source links corrected as reported by nvanwyen. |
1 Downloads
You can download the source code in the following formats:
File | Size | Check Sum | Uncompress Command |
---|---|---|---|
cipher-1.2.tar.bz2 | 15K | 17148 | tar jxf cipher-1.2.tar.bz2 |
cipher-1.2.tar.gz | 16K | 29380 | tar zxf cipher-1.2.tar.gz |
cipher-1.2.zip | 19K | 1134 | unzip cipher-1.2.zip |
2 Build and Test
To build and test the project type make
. You must have the openssl headers installed.
- On CentOS you can install the openssl headers by running “
yum install openssl-devel
“. - On cygwin you must download the openssl development package.
- On Ubuntu you can install it by running “
apt-get install openssl libssl-dev
“.
It uses the g++ compiler and has been tested on CentOS 5.5, CentOS 6.4, Ubuntu 11.04, cygwin and Mac OS X 10.9.
2.1 Source Files
Here is the list of source files.
File | Description |
---|---|
a.h | Doxygen main-page. |
cipher.cc | Class implementation. |
cipher.h | Class interface. |
ct.cc | Tool that allows you to use the class. |
doxygen.cfg | Doxygen configuration file. |
Makefile | Makefile. |
test.cc | Tester. |
3 ct
Once it is built there will be a tool called ct.exe. It uses the Cipher class to allow you to encrypt and decrypt files and strings. Type ./ct.exe -h
to get information about how to use the tool.
3.1 Example
The following example shows how to use the ct program.
1 2 3 4 5 6 7 8 9 10 11 |
% # Encrypt stdin to stdout % echo 'Lorem ipsum dolor sit amet' | ./ct.exe -e U2FsdGVkX19nxmlzUf9K7K0Z40ZlovVWSfndp4VHLKSl9j5FXuvHi7dz08nVDsrV % # Decrypt stdin to stdout % echo U2FsdGVkX19nxmlzUf9K7K0Z40ZlovVWSfndp4VHLKSl9j5FXuvHi7dz08nVDsrV \ | ./ct.exe -d Lorem ipsum dolor sit amet |
3.2 Help
Here is the program help.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
NAME ct - Cipher tool that used to encrypt or decrypt files. SYNOPSIS ct [OPTIONS] DESCRIPTION Encrypt or decrypt a file. OPTIONS -c Count of number of init rounds. -C The name of the cipher to use (ex. aes-256-cbc). --d Decrypt. -D The name of the digest to use (ex. sha1). --debug Turn on internal debugging. --e Encrypt. -h This help message. -i Input file. -o Output file. -p Passphrase. -s Salt as a string. -x Salt as hex digits (16).. -v Increase the level of verbosity. -V Print the version number and exit. EXAMPLES % # Help % ./ct.exe -h % # Encrypt stdin to stdout % echo 'Lorem ipsum dolor sit amet' | ./ct.exe -e U2FsdGVkX19nxmlzUf9K7K0Z40ZlovVWSfndp4VHLKSl9j5FXuvHi7dz08nVDsrV % # Decrypt stdin to stdout % echo U2FsdGVkX19nxmlzUf9K7K0Z40ZlovVWSfndp4VHLKSl9j5FXuvHi7dz08nVDsrV | ./ct.exe -d Lorem ipsum dolor sit amet % # Encrypt a file % # It is okay to reference the same file. % ./ct.exe -e -p 'Tally Ho!' -i foo.txt -o foo.txt % # Decrypt a file % # It is okay to reference the same file. % ./ct.exe -d -p 'Tally Ho!' -i foo.txt -o foo.txt AUTHOR Joe Linoff |
Enjoy!
.
Your source code links don’t work.
Thank you for pointing that out. I have fixed them so you should be able to download now.
I’m trying too and isn’t working, pls help…
Which OS are you using? What sort of problems are you seeing?
Hi,
Thanx for sharing this.
I’m trying to use your ct.exe (and also your cipher class) to decrypt files that have been encrypted with the commandline version of openssl.
Encryption:
openssl aes-256-cbc -a -salt -in file.txt -out file.enc -pass pass:opensesamy
Decryption:
ct.exe -d -i file.enc -p opensesamy -o file2.txt
I’m getting
“ERROR: EVP_DecryptFinal_ex() failed”
Do you know if this is due to miss-matching passwords? And if so how to supply the password when encrypting the file with openssl?
Stupid me – totally focusing on the password.
The problem was of course that I didn’t specify the “message digest” when encrypting the file.
Which you have described perfectly at http://projects.joelinoff.com/cipher-1.0/doxydocs/html/
Thanks again for sharing.
Updated to version 1.1 after fixing a buffer size problem at line 298 at cipher.cc that was reported by an anonymous user.
thanks for this, 2 questions. here is a very simple example using your code
#include
#include
#include
#include
#include
#include “cipher.h”
void testDecrypt()
{
std::string in = “A9ZeZTZfb0nmrXlCOtf5rw==\n”;
std::string salt = “”;
Cipher mgr(CIPHER_DEFAULT_CIPHER,CIPHER_DEFAULT_DIGEST,5,true);
mgr.debug(true);
std::string out = mgr.decrypt(in,”password”,salt );
printf( “decrypted username = %s \n”, out.c_str());
}
void testEncrypt()
{
std::string salt = “”;
Cipher mgr(CIPHER_DEFAULT_CIPHER,CIPHER_DEFAULT_DIGEST,5,false);
mgr.debug(true);
std::string in = “hello”;
std::string out = mgr.encrypt(in,”password”,salt );
printf( “password = %s \n”, out.c_str());
}
int main(int argc, char *argv[])
{
testDecrypt();
testEncrypt();
return 0;
}
question 1) like this it works.. if i flip the testEncrypt(); and testDecrypt(); around in sequence i get a
../src/cipher.cc:368: FCT decode_cipher
terminate called after throwing an instance of ‘std::runtime_error’
what(): EVP_DecryptFinal_ex() failed
Aborted
question2) why do i need to add a “\n” to the base64 encoded in string in testDecrypt to get it to work ?
The run time error is occurring because your ciphertext fits into a 64 byte block.
The reason that you have to add the new line because of an implementation artifact of the OpenSSL base64 processing. I have no idea why they did that.
See Mihal Todor’s comments for more details.
I have been playing with your Cipher library in order to encrypt some strings with AES for a small project and I think I ran into a bug.
For example, by running the code below:
I get the following error:
I am compiling on the latest version of Ubuntu using GCC 4.7.3 with the libssl-dev package installed.
I traced the error down to your decode_base64(…) function, which seems to malfunction if it passes to OpenSSL a base64 encoded string that doesn’t contain new lines. This happens when the ciphertext is small enough to fit in a single base64 block, and, thus, encode_base64(…) does not place any new lines in it. Apparently, the block size of base64, as implemented in OpenSSL, is 64 characters.
I managed to come up with a fix, by adding the following code in decode_base64(…), right after BIO* b64 = BIO_new(BIO_f_base64());
Ideally, I think both decode_base64(…) and encode_base64(…) should set the BIO_FLAGS_BASE64_NO_NL flag by default, such that the resulting base64 string doesn’t contain any new lines. This behavior can be achieved with the ‘-A’ switch for the
openssl enc
command line utility.The fact that OpenSSL requires a special flag to be able to decode a base64 string without new lines in it makes me sad. It’s just not possible for anybody to use their API correctly.
Best regards,
Mihai Todor
I have been away on vacation and just got back. I will make this change and add a comment noting your contribution. Thank you.
Thank you again, I have updated Cipher 1.2 with the change that you suggested.