Encryption code examples
Encrypting and decrypting "Hello, World!" with AES-256-GCM. Every example writes the same format: a random 12-byte nonce, then the ciphertext, then the 16-byte tag, all in Base64. So any of them can decrypt the others' output, and so can this site: choose Decrypt, AES-256, GCM, Key, paste the key below, and turn on The nonce is at the start.
Demo key (hex): 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
In real code, generate a random key once, keep it out of your source code (an environment variable or a secrets manager), and never reuse a nonce with the same key.
Encryption in JavaScript (browser)
Web Crypto's AES-GCM appends the 16-byte tag to the ciphertext, so nonce + result is the whole message.
const hex = (s) => Uint8Array.from(s.match(/../g), (h) => parseInt(h, 16));
const toB64 = (b) => btoa(String.fromCharCode(...b));
const fromB64 = (s) => Uint8Array.from(atob(s), (c) => c.charCodeAt(0));
const key = await crypto.subtle.importKey(
"raw", hex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"), "AES-GCM", false, ["encrypt", "decrypt"]
);
// Encrypt: random 12-byte nonce, then nonce + ciphertext + tag as Base64
const nonce = crypto.getRandomValues(new Uint8Array(12));
const ct = new Uint8Array(
await crypto.subtle.encrypt({ name: "AES-GCM", iv: nonce }, key, new TextEncoder().encode("Hello, World!"))
);
const message = toB64(new Uint8Array([...nonce, ...ct]));
console.log(message);
// Decrypt (throws if the key is wrong or the data was changed)
const data = fromB64(message);
const pt = await crypto.subtle.decrypt({ name: "AES-GCM", iv: data.slice(0, 12) }, key, data.slice(12));
console.log(new TextDecoder().decode(pt));Encryption in Node.js
import { createCipheriv, createDecipheriv, randomBytes } from "node:crypto";
const key = Buffer.from("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "hex");
// Encrypt
const nonce = randomBytes(12);
const cipher = createCipheriv("aes-256-gcm", key, nonce);
const ct = Buffer.concat([cipher.update("Hello, World!", "utf8"), cipher.final()]);
const message = Buffer.concat([nonce, ct, cipher.getAuthTag()]).toString("base64");
console.log(message);
// Decrypt
const data = Buffer.from(message, "base64");
const decipher = createDecipheriv("aes-256-gcm", key, data.subarray(0, 12));
decipher.setAuthTag(data.subarray(-16));
const pt = Buffer.concat([decipher.update(data.subarray(12, -16)), decipher.final()]);
console.log(pt.toString("utf8"));Encryption in Python
Install: pip install cryptography
import base64
import os
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
key = bytes.fromhex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")
aes = AESGCM(key)
# Encrypt (the tag is appended to the ciphertext)
nonce = os.urandom(12)
message = base64.b64encode(nonce + aes.encrypt(nonce, b"Hello, World!", None)).decode()
print(message)
# Decrypt (raises InvalidTag if the key is wrong or the data was changed)
data = base64.b64decode(message)
print(aes.decrypt(data[:12], data[12:], None).decode())Encryption in Java
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Base64;
import java.util.HexFormat;
import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class Main {
public static void main(String[] args) throws Exception {
SecretKeySpec key = new SecretKeySpec(HexFormat.of().parseHex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"), "AES");
// Encrypt (Java appends the tag to the ciphertext)
byte[] nonce = new byte[12];
new SecureRandom().nextBytes(nonce);
Cipher enc = Cipher.getInstance("AES/GCM/NoPadding");
enc.init(Cipher.ENCRYPT_MODE, key, new GCMParameterSpec(128, nonce));
byte[] ct = enc.doFinal("Hello, World!".getBytes(StandardCharsets.UTF_8));
byte[] all = new byte[nonce.length + ct.length];
System.arraycopy(nonce, 0, all, 0, 12);
System.arraycopy(ct, 0, all, 12, ct.length);
String message = Base64.getEncoder().encodeToString(all);
System.out.println(message);
// Decrypt (throws AEADBadTagException if the key is wrong or the data was changed)
byte[] data = Base64.getDecoder().decode(message);
Cipher dec = Cipher.getInstance("AES/GCM/NoPadding");
dec.init(Cipher.DECRYPT_MODE, key, new GCMParameterSpec(128, data, 0, 12));
System.out.println(new String(dec.doFinal(data, 12, data.length - 12), StandardCharsets.UTF_8));
}
}Encryption in C# / .NET
AesGcm needs .NET Core 3.0 or later. It keeps the tag separate, so it's written after the ciphertext by hand.
using System;
using System.Security.Cryptography;
using System.Text;
byte[] key = Convert.FromHexString("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f");
using var aes = new AesGcm(key, tagSizeInBytes: 16);
// Encrypt: nonce + ciphertext + tag
byte[] pt = Encoding.UTF8.GetBytes("Hello, World!");
byte[] all = new byte[12 + pt.Length + 16];
var nonce = all.AsSpan(0, 12);
RandomNumberGenerator.Fill(nonce);
aes.Encrypt(nonce, pt, all.AsSpan(12, pt.Length), all.AsSpan(12 + pt.Length));
string message = Convert.ToBase64String(all);
Console.WriteLine(message);
// Decrypt (throws AuthenticationTagMismatchException if the key is wrong or the data was changed)
byte[] data = Convert.FromBase64String(message);
byte[] plain = new byte[data.Length - 28];
aes.Decrypt(data.AsSpan(0, 12), data.AsSpan(12, plain.Length), data.AsSpan(data.Length - 16), plain);
Console.WriteLine(Encoding.UTF8.GetString(plain));Encryption in Go
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/base64"
"encoding/hex"
"fmt"
)
func main() {
key, _ := hex.DecodeString("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
gcm, err := cipher.NewGCM(block)
if err != nil {
panic(err)
}
// Encrypt: Seal appends ciphertext + tag to the nonce
nonce := make([]byte, gcm.NonceSize())
rand.Read(nonce)
message := base64.StdEncoding.EncodeToString(gcm.Seal(nonce, nonce, []byte("Hello, World!"), nil))
fmt.Println(message)
// Decrypt (errors if the key is wrong or the data was changed)
data, _ := base64.StdEncoding.DecodeString(message)
pt, err := gcm.Open(nil, data[:12], data[12:], nil)
if err != nil {
panic(err)
}
fmt.Println(string(pt))
}Encryption in Rust
Install: cargo add aes-gcm@0.10 base64 hex
These calls are from aes-gcm 0.10, the widely used release; 0.11 changed how nonces are made.
use aes_gcm::aead::{Aead, AeadCore, KeyInit, OsRng};
use aes_gcm::{Aes256Gcm, Key, Nonce};
use base64::{engine::general_purpose::STANDARD, Engine};
fn main() {
let key_bytes = hex::decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f").unwrap();
let cipher = Aes256Gcm::new(Key::<Aes256Gcm>::from_slice(&key_bytes));
// Encrypt: nonce + ciphertext + tag
let nonce = Aes256Gcm::generate_nonce(&mut OsRng);
let ct = cipher.encrypt(&nonce, b"Hello, World!".as_ref()).unwrap();
let message = STANDARD.encode([nonce.as_slice(), &ct].concat());
println!("{message}");
// Decrypt (errors if the key is wrong or the data was changed)
let data = STANDARD.decode(&message).unwrap();
let pt = cipher.decrypt(Nonce::from_slice(&data[..12]), &data[12..]).unwrap();
println!("{}", String::from_utf8(pt).unwrap());
}Encryption in PHP
<?php
$key = hex2bin("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f");
// Encrypt
$nonce = random_bytes(12);
$ct = openssl_encrypt("Hello, World!", "aes-256-gcm", $key, OPENSSL_RAW_DATA, $nonce, $tag);
$message = base64_encode($nonce . $ct . $tag);
echo $message, "\n";
// Decrypt (returns false if the key is wrong or the data was changed)
$data = base64_decode($message);
$pt = openssl_decrypt(substr($data, 12, -16), "aes-256-gcm", $key, OPENSSL_RAW_DATA, substr($data, 0, 12), substr($data, -16));
echo $pt, "\n";Encryption in OpenSSL (command line)
openssl enc can't do GCM, so this uses AES-256-CBC with a password. Decrypt the output here with Password, PBKDF2-SHA256 and 600000 iterations.
# Encrypt with a password (prompts for it), Base64 output on one line
echo -n 'Hello, World!' | openssl enc -aes-256-cbc -pbkdf2 -iter 600000 -a -A > message.txt
# Decrypt
openssl enc -d -aes-256-cbc -pbkdf2 -iter 600000 -a -A -in message.txt