maandag 2 februari 2015

Simple encryption and decryption using GnuPG

About a year ago, I started to experiment with encryption. My goal was to be able to encrypt a file from Java, since I am a Java developer and I believe that it should be a basic skill to be able to encrypt and decrypt files from your programming environment.

For encryption from Java, the Bouncy Castle libraries are recommended, and I want to come up with a simple as possible Java program that will encrypt and decrypt a file, but that will be in some later post. Using the Bouncy Castle libraries is far from easy, and they tend to change now and then, so that when you upgrade to a newer version, you might have to change your code.
This is from experience, because my Java program, which used some 1.48 version, didn't compile with the latest, 1.51 version... and when I found an example of a Java program, that did compile with the 1.51 version, the compiler gave a lot of "deprecated" warnings and that new example is way more complicated than I have in mind when thinking of "the most simple" example.

Luckily, I still have my examples of encryption and decryption from the command line, and these examples are more stable, in that they will keep working even if you upgrade the software. And that software is GnuPG, which I run in a Cygwin environment.
I would recommend to anyone, who wants to learn encryption in Java, to learn to use this tool, because it is an easier way to learn about the concepts of encryption, which will be helpful when you start to use it in Java, and it provides a check to see if your Java program produces the file you wanted it to produce.

And so my first post about encryption will summarize some basic commands for encryption and decryption from the command line, using GnuPG.
If you are in a Windows environment, you can install Cygwin, and then in the setup, you find gnupg in the tools section. Just select it and install it.
If you are in a Linux environment, then probably you will find GnuPG ready at the command line.

Just type
$ gpg --version

and it will give you information about the version and the available ciphers, like this:

gpg (GnuPG) 1.4.18
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Home: ~/.gnupg
Supported algorithms:
Pubkey: RSA, RSA-E, RSA-S, ELG-E, DSA
Cipher: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH,
        CAMELLIA128, CAMELLIA192, CAMELLIA256
Hash: MD5, SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
Compression: Uncompressed, ZIP, ZLIB, BZIP2

I don't know if we shoudn't use GnuPG version 2, and for what reason. This version (1.4.18) includes ciphers like RSA-2048, and AES256, so what do we need more?
Also SHA256 and SHA512 are available for hashing, so that's all we need.

If you have never used gpg before, then, on running it the first time, it will create the directory .gnupg in your home directory, and in that directory the keys will be stored.
With GnuPG you can encrypt using a Public Key Infrastructure, that's asymmetric encryption, and symmetric encryption as well. In practice, both are being used.

In this post, I will concentrate on PKI-encryption, because that is the starting point for secure communication.

In PKI, every participant generates a couple of keys: a pair that consists of a public key and a private key. If you want to send an encrypted message to a friend, you encrypt the message with his public key, and then he will be the only one that will be able to decrypt the message, using his private key.
One of the most important points in here is, that you need to be sure that the public key you use, is indeed the public key of your friend. There are techniques to verify this, like exchanging the key in person, or exchanging the key fingerprint on a phone call, see the man page for how to make a fingerprint.

Anyway, let's start with generating our keys:

$ gpg --gen-key

This command will prompt you to make some choices and we can use the defaults, that is: RSA-2048 and keys that never expire.
Then type in a name, which should be unique, optionally an email-address, and a description. Name and description can both be used for identification of the key.
Then type a passphrase, in this example I will use "MyPassphrase" and the keys will be generated.
For this example I chose the name "Edward" and comment "Developer".
The keys will be stored in directory .gnupg in your home directory.
You can list the keys anytime with:

$ gpg --list-keys

and that will give us the list of available keys, like this:

/home/edward/.gnupg/pubring.gpg
---------------------------------
pub   2048R/B3CFA5C4 2015-02-01
uid                  Edward (Developer)
sub   2048R/74199587 2015-02-01

If you want to share your key, then you need to export your key, and for that, use the command:

$ gpg --armor --export "Edward (Developer)"

This gives the following output:

-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1

mQENBFTOph0BCAC4HxY7laoONh6Pcy6PEL89+UVG0SbQHYJ1w2h6jToZvSdC2nF1
wM4LubIe6kDwk7FZaPxwaLVLYyMkgWIC+bV02fAimSt0jIcERL1F0kCSkikXR9OJ
1Im6oOMDd3kqSG/KHkIn4HasDIpG4cizEbWURYUqKCCuZcmu7nfiHI5IfqfrHqKE
gS/mflewA8C2JX+T2HGL4U+vJtL0X1n0b5iN/EVH4C6a0AdWs6+PLeIF9OMLAK1Q
m4pD+8J/UlHhMEs3IMwbLA2kvPKdwM2nDwkMsJDUyNv3m7D/Cq+b6Z9Ukd84DVJY
BD2ma4yxnKmsXWBnwtVFKJ4lrKYSx03eKrVjABEBAAG0EkVkd2FyZCAoRGV2ZWxv
cGVyKYkBOAQTAQIAIgUCVM6mHQIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AA
CgkQl+yj1bPPpcQSXgf/Y6JP6abLqBselP5p9Xnn2cc2nTK8o/1YYWGQlodGCDG4
cgCJtDZLQoH2PHEhFNpJ1ZDPE7ndKB3zx5ndoR66rnWZZ7TwJHKh32kuHux9VTQQ
0tngKIX+izfKSlcTHGXXl+sKqaXxvGeNOPr81cl+3ZYEkWrlgBraWJGr/SpZzaK7
csROzg90D6s6NRCyAAS0DyKfAPhVccuFC6wArlEuG5IAmEwjOfOC8EHgbcWKDv9m
KGpczSWpx92/9UEjrl62pgk+hJVDWCkZPN7w+/kQWAaMOaJJuOwMksjnoeKGKaKm
dd46rkGFeZO4QnM+M9oS/IMeCJpfKaWcxjeeEyOZPbkBDQRUzqYdAQgAu47ZfZ8t
/VzTnZ0Ok4Jjc1jwXTjQThVfSif5MRW7SZnYkxv+Pxvl7s8prBWn0U3oD45mbfwg
8PV9gOja3VnbJOXQ8VYSfUXra2+5E2NvGJhO8/gdI62M9te31pJtcuHmocyYsHUI
GpJrrHoD8CCut6DymyF/ibIN7q6vwtWLTBr+UmDj/4KwaOj/s5mE37U56Rzcfy8/
+kOleivAiHdRVLFA6GncH50gS1iCVME76p+mHInwwjN6+Nx4hvJunko0+9RAJ4M6
OSEHRvIKV4M1VWcmvNuVfS8lyCc1lEctBv/PJly8XoVBHkXHW2j5u1eYNluBG907
icErystem1ZtdQARAQABiQEfBBgBAgAJBQJUzqYdAhsMAAoJEJfso9Wzz6XEc1QH
/1uhJ2esonovm4W2sDTZOKVQeSEpPtpmnn5igx5Mky/Ulu2T+h9ecFU9E8c+Z9Jc
k67OKKniGEHXY81Hjm/d0hkE8zGv+uBVgqwjK97R0rbLB58B7hYxFSIoQ97DiWfs
F9sXIEDIxQNhEeAT5wjuoVBcR/qey+seGuwdtz5rHE9VEr6Ca7AaQegjcd0iYC4I
rzTZ/ZiAyzIc+XQLNzmcG39qDTXihEq/5qxZHO+/wtYJKX5lbgSSA44EX9AYLJ2x
T4NfLfqQPU/XWxRkmjrFc7CVtDGcE+W4HB0VVDbk5YK2isBaHAKlVaj00GEZTty1
zLR423RBMYpMMEydQv5+Muc=
=mxbq
-----END PGP PUBLIC KEY BLOCK-----

When you leave out the option --armor, then the key will be exported in binary format, and when you leave out the name, then every public key in your file will be exported.

So now we are ready to encrypt some file. Let's make a file, named text_to_encrypt.txt with contents:

This text is going to be encrypted.

With the following command:

$ gpg --encrypt text_to_encrypt.txt

after choosing a user ID, which can be "Edward (Developer)", we will produce the (binary) file

text_to_encrypt.txt.gpg

If you prefer to get an ASCII file, include the option --armor, so type:

$ gpg --encrypt --armor text_to_encrypt.txt

and this will produce the file:

text_to_encrypt.txt.asc

Since it is an ASCII file, we can read the output, and it will be:

$ cat text_to_encrypt.txt.asc
-----BEGIN PGP MESSAGE-----
Version: GnuPG v1

hQEMA7U9b+J0GZWHAQf/XJAt74zj2f1TVjhGGG+dI5OYSopRX6Uou2H0nq+ZeOuv
S1PFIobJqjpPv7tAxT3I4DIexZe6ym3ae3sV1gW1zQ+FXHqKnSMOGLGZ1L8t0qZ5
5avfpaWvzCySKxf65RLsDS6OTAmUq9r/IawXJUKGidyUaBOoLwSGROsZ8bxuT5Ka
yI62F5v3PMBbqr++dh8rRxMst0mT//AkV/44k4wqgZG/WWPwUo1trmYconQq6wuP
rN7LNtTJwzbftlvKa/d4XXzVA+8kS4EFIELVL5TxqRxUW3rfbnfbYbjH++RwKQy/
HEY2cspQdct+BgO4oszoqCMAhuIEyiLf6vSW9F/nbdJqAaqom3XCT/BkWhHYa7B0
1pASEMtkpJJdflTKALHGw84Q7lkzD8FNDSAExmYCYbHFbePEvTqouApQhUhvGl70
7N3Jb8TvgwH//CjkMJMOIiVl4bbe5ncsx1FHP1bhHJXUhijYWh+KRXGJZg==
=YpjA
-----END PGP MESSAGE-----

Now, to decrypt, we can use the command:

$ gpg --decrypt

Which will output the decrypted context to standard output, and we can redirect it to a file like:

$ gpg --decrypt text_to_encrypt.txt.asc > decrypted_text.txt

As input-file we can use either the binary, or the ASCII file, and the result of this command will be the followig:

You need a passphrase to unlock the secret key for
user: "Edward (Developer)"
2048-bit RSA key, ID 74199587, created 2015-02-01 (main key ID B3CFA5C4)

Enter passphrase:

And after entering our passphrase, the file decrypted_text.txt will be created and its contents will be:

$ cat decrypted_text.txt
This text is going to be encrypted.

That's about it for this post.
I just want to say this. The method of encryption used, RSA, is not suitable for encrypting large files. There is a limit to the maximum file size that can be encrypted and it is about 245 bytes. Also RSA encryption seems to be rather slow.
For encrypting large files, usually a symmetric cipher is used, like AES-Rijndael.

With GnuPG we just need to add the option --symmetric to the encrypt command, and it will first ask us for a passphrase with confirmation, and then for the user id.

$ gpg --encrypt --symmetric --armor text_to_encrypt.txt
You did not specify a user ID. (you may use "-r")

Current recipients:

Enter the user ID.  End with an empty line: Edward (Developer)

Current recipients:
2048R/74199587 2015-02-01 "Edward (Developer)"

and the result will be the following:

$ cat text_to_encrypt.txt.asc
-----BEGIN PGP MESSAGE-----
Version: GnuPG v1

hQEMA7U9b+J0GZWHAQgAjF4/vOl+ZHI1NN94wN/8kezQKj7cQ4QnVvZERBPCnBI2
pZSCAUUPPiDIDpeBSFpplcM50EohlORP0k/CbtcqzSNm47u10f60mT913wO9HSxS
G+aMlrR5jyW3HYPTmjLSUW0wSTTC+oMVhGaxoOGRiHnDDZ+loGvRNCfwtXyaB1Jv
RRFwHIEOTfkBPHv4JtQ1S56PSorncnpeeEWhkonsLl+d2/F3ONLwON8Nk+9bUSlL
GI/XsF6FEBpYZw5Z/vif4m1V/zfBJigxH++iSG7SoJpUSTYWuTIgZCM3ZS0moFAP
KG6zYcqUHs7dbysHcZe2REkeRrXaTBdWPTeXARjskYwuBAMDAsdcbIpkoSC7YOCT
tfP+2wcCchRck/Z4yjhx4sopi3FHJexNBiNHjd8GqtJqAf/cKju6HHujlXCP7RrR
G5F0LGEio6UfyiNcjLEV1dao6m3dovtiSNPTOypEfIoIXN6yP9SQdankJPx4HSHt
eojxbi9D4iHSOtPPxJ4+X2hc4a/RMFTGvPZTENsJ/Yt68z8MzrKDCUOxpg==
=QuxQ
-----END PGP MESSAGE-----

Decryption goes with the same command as before:

$ gpg --decrypt text_to_encrypt.txt.asc

and it will result in

You need a passphrase to unlock the secret key for
user: "Edward (Developer)"
2048-bit RSA key, ID 74199587, created 2015-02-01 (main key ID B3CFA5C4)

gpg: encrypted with 1 passphrase
gpg: encrypted with 2048-bit RSA key, ID 74199587, created 2015-02-01
      "Edward (Developer)"
This text is going to be encrypted.