How to encrypt with AES-256-GCM in Erlang
By: Bruce Yinhe
Tags: Encryption, Aes Gcm, Erlang, Aes256, Crypto

AES (Advanced Encryption Standard) with Galois/Counter Mode (AES-GCM) is specified in NIST Special Publication 800–38D. To encrypt a string with AES-256-GCM algorithm you need a 256-bit key, an initialization vector (IV) (also called a nonce), as well as any additional authenticated data (AAD, or associated data). The outcome of the encryption includes an encrypted cipher text of the same length as the original string, as well as an authentication tag (the “tag”), also called message authentication code (MAC) or integrity check value (ICV) [1]. The tag is calculated during the AES encryption process [2], and ensures the integrity of both the encrypted cipher text and the plaintext additional authenticated data (AAD), and is a part of the input to the decryption process [3]. The additional authenticated data (AAD) is an unencrypted plain text and is also a part of the input to the decryption. When AES-GCM is only used to authenticate the AAD, the calculated tag (MAC) is called a Galois message authentication code (GMAC) [4].

Here we are making use of the Erlang functions crypto:crypto_one_time_aead/5 and crypto:crypto_one_time_aead/6 [5] for both encryption and decryption. AEAD stands for Authenticated encryption with associated data (AEAD).

Encrypt:

1> Key = <<1:256>>. % Key length 32 bytes

<<0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,

0,...>> 2> IV = <<0:128>>. % IV length ≥ 1 byte

<<0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0>> 3> Text = <<"Hello">>. % Any length

<<"Hello">> 4> AAD = <<>>. % AAD any length, here 0 byte

<<>> 5> {CipherText, Tag} = crypto:crypto_one_time_aead(aes_256_gcm, Key, IV, Text, AAD, true). % Tag length 1-16, here using default 16

{<<254,190,31,199,21>>,

<<26,210,128,46,78,47,171,160,82,197,153,57,151,240,254,

209>>} 6> {CipherText, Tag1} = crypto:crypto_one_time_aead(aes_256_gcm, Key, IV, Text, AAD, 12, true). % Use 12 byte tag

{<<254,190,31,199,21>>,

<<26,210,128,46,78,47,171,160,82,197,153,57>>}

Decrypt:

1> Key = <<1:256>>.

<<0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,

0,...>> 2> IV = <<0:128>>.

<<0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0>> 3> CipherText = <<254,190,31,199,21>>.

<<254,190,31,199,21>> 4> Tag = <<26,210,128,46,78,47,171,160,82,197,153,57,151,240,254,209>>.

<<26,210,128,46,78,47,171,160,82,197,153,57,151,240,254,209>> 5> AAD = <<>>.

<<>> 6> crypto:crypto_one_time_aead(aes_256_gcm, Key, IV, CipherText, AAD, Tag, false).

<<"Hello">>

The Erlang crypto:crypto_one_time_aead functions also support other AEAD ciphers ( gcm and ccm ) of different key, IV, and tag lengths, such as aes_128_gcm , aes_192_gcm , aes_256_gcm , aes_128_ccm , aes_192_ccm , aes_256_ccm , and chacha20_poly1305 [6].

From OTP 22.0, the new crypto API crypto:crypto_one_time_aead replaces the obsolete crypto:block_encrypt and crypto:block_decrypt [7].

Read more:

[1] AES-GCM authenticated encryption https://www.cryptosys.net/pki/manpki/pki_aesgcmauthencryption.html

[2] https://cryptobook.nakov.com/symmetric-key-ciphers/aes-cipher-concepts

[3] https://crypto.stackexchange.com/questions/17999/aes256-gcm-can-someone-explain-how-to-use-it-securely-ruby

[4] Galois/Counter Mode (GCM) and GMAC https://www.youtube.com/watch?v=V2TlG3JbGp0

[5] https://erlang.org/doc/man/crypto.html#crypto_one_time_aead-6

[6] https://erlang.org/doc/apps/crypto/algorithm_details.html#ciphers

[7] https://erlang.org/doc/apps/crypto/new_api.html#the-new-api

[8] https://en.wikipedia.org/wiki/Galois/Counter_Mode

[9] https://csrc.nist.gov/publications/detail/sp/800-38d/final

[10] https://en.wikipedia.org/wiki/Authenticated_encryption#Authenticated_encryption_with_associated_data_(AEAD)

[11] What is GCM? Galois Counter Mode (of operation) (usually seen as AES-GCM) https://www.youtube.com/watch?v=g_eY7JXOc8U