9

I'm struggling to implement AES256-GCM on a Linux machine to encrypt files outgoing to another party.

We're usually exchanging files using PKI, but this particular party insists on AES256-GCM and will not allow PKI.

However, I've been struggling to make it work. We'd like to implement it on a Linux machine and to be able to automate encryption. It seems like the other party is okay with doing this manually on a Windows desktop, but we'd like to avoid that possibility.

I tried to do it using openssl, but I get this:

$ openssl aes-256-gcm
AEAD ciphers not supported by the enc utility

When I tried GPG, I get:

$ gpg --version
...
Cipher: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH,
        CAMELLIA128, CAMELLIA192, CAMELLIA256
...

The other party just suggested using what they have, which is some Windows EXE with BouncyCastle libraries, so I started investigating using BouncyCastle for this, but it's in Java, and I'd like to avoid using Java if possible.

I'd have to add a JDK to that particular server or set up another virtual machine just for the purpose of encrypting these files, which is completely non-optimal. Browsing BouncyCastle's documentation, it's not very helpful, at least I haven't found any real examples, and I must be doing something wrong, because even when I did a full text search looking for a reference to GCM, Galois Counter, or anything similar, I found nothing (do I have the wrong files?).

I figure I might work it out, but we've been given a tight deadline and we can't force them to use PKI. I hate to waste time looking in the wrong places, but I would really want to avoid using the simplistic manual process in Windows if it's at all possible.

Edit: The expected format is IV+ciphertext(plus, I presume, tag). I received a copy of their Java source code for a simple encrypt/decrypt utility and it's very simplistic with no allowances for complex encoding routines or anything, it's just meant to encrypt (or decrypt) a single file or a single zip package of multiple files. That's all.

The worst thing is that I saw references to being able to encrypt using OpenSSL (which is just an interface for enc, after all, so it should also work with gpg, for instance), and the best one I found was this: https://security.stackexchange.com/questions/128883/basic-question-regarding-openssl-and-aes-gcm

I guess I'll try that tomorrow and see if I can get it to work.

Marek
  • 133
  • 1
  • 1
  • 7

3 Answers3

5

LibreSSL supports AEAD ciphers, including aes-256-gcm:

$ openssl enc -aes-256-gcm -nosalt -p -in file.in -out file.out
enter aes-256-gcm encryption password:
Verifying - enter aes-256-gcm encryption password:
key=A744E1091C25BABD36B50E40FB8D311A672722729CEA6E217AD9FA8AF23CAF57
iv =BDEEA37B93BB989C6C40665B

If you don't mind writing your own software, there are plenty of crypto libraries supporting AES-GCM, such as OpenSSL itself (even if not available from the command line tool). Libsodium also provides AES256-GCM and may be easier to use.

That being said, using a common and trusted tool such as GPG would be way safer than implementing your own software, even if the resulting files are not encrypted using AES-GCM.

Frank Denis
  • 3,073
  • 19
  • 19
4

In the end, it was easiest to just code this in Python. For those interested, here's the bare basics code.

DO NOT USE THIS CODE IN PRODUCTION There's no real file handling, no handling of decryption errors, IV and key are in code and not randomly determined.

Importing relevant libraries:

import os
from cryptography.hazmat.primitives.ciphers.aead import AESGCM

For encryption:

with open('/path/to/file/plaintext', 'rb') as infile:
    data = infile.read()

aad = None
key = '12345678123456781234567812345678'
aesgcm = AESGCM(key.encode('utf-8'))
nonce = '123456781234'
ciphertxt = aesgcm.encrypt(nonce.encode('utf-8'), data, aad)

Next is writing the result. The first 12 bytes is the IV, ciphertext follows:

with open('/path/to/file/encrypted_output', 'wb+') as outfile:
    outfile.write(nonce.encode('utf-8'))
    outfile.write(ct)

As for decryption:

with open('/path/to/fileciphertext', 'rb') as infile:
    nonce = infile.read(12)
    data = infile.read()

aad = None
key = '12345678123456781234567812345678'
aesgcm = AESGCM(key.encode('utf-8'))
plaintxt = aesgcm.decrypt(nonce, data, aad)

with open('/path/to/output/plaintext', 'wb+') as outfile:
    outfile.write(plaintxt)

That's the format expected by the other party, so I hope this is enough. I'd be glad to hear about any and all errors in that code above.

Marek
  • 133
  • 1
  • 1
  • 7
1

You could also check if you're version of OpenSSL supports CCM mode. That's an authenticated mode just like GCM. I tried a version of OpenSSL I happened to have on my machine and it supports CCM, but not GCM.

Swashbuckler
  • 2,126
  • 11
  • 8