Python AES-GCM Code Example (Online Runner)
Python AES-GCM examples with tag length, AAD, and encoding controls matching the AES-GCM tool.
Online calculator: use the site AES-GCM tool.
Note: This snippet requires locally installed dependencies and will not run in the online runner.
Calculation method
AES-GCM combines encryption and authentication. The tool lets you set key size, nonce, AAD, tag length, and encoding for ciphertext + tag. The helper below mirrors those fields using PyCryptodome.
Install the dependency first: pip install pycryptodome.
Implementation notes
- Package:
pycryptodomeprovidesCrypto.Cipher.AESwith GCM mode. - Implementation: the snippet concatenates ciphertext + tag and encodes them as hex/base64 to match the UI output. The tag length is in bytes (typically 16).
- Notes: nonces must be unique per key (12 bytes is standard). AAD must match during decryption or verification fails and raises an exception.
python
from __future__ import annotations
import base64
from typing import Literal
from Crypto.Cipher import AES
KeyEncoding = Literal["utf8", "hex"]
CipherEncoding = Literal["hex", "base64"]
def _decode_value(value: str, encoding: KeyEncoding) -> bytes:
return value.encode("utf-8") if encoding == "utf8" else bytes.fromhex(value)
def _encode_ciphertext(data: bytes, encoding: CipherEncoding) -> str:
return data.hex() if encoding == "hex" else base64.b64encode(data).decode("ascii")
def _decode_ciphertext(value: str, encoding: CipherEncoding) -> bytes:
return bytes.fromhex(value) if encoding == "hex" else base64.b64decode(value)
def _normalize_key(key: bytes, key_size: int) -> bytes:
return key[:key_size].ljust(key_size, b"\x00")
def aes_gcm_encrypt(
plaintext: str,
key: str,
nonce: str,
*,
key_encoding: KeyEncoding = "hex",
nonce_encoding: KeyEncoding = "hex",
aad: str | None = None,
aad_encoding: KeyEncoding = "utf8",
tag_length: int = 16,
key_size: int = 32,
output_encoding: CipherEncoding = "base64",
) -> str:
key_bytes = _normalize_key(_decode_value(key, key_encoding), key_size)
nonce_bytes = _decode_value(nonce, nonce_encoding)
cipher = AES.new(key_bytes, AES.MODE_GCM, nonce=nonce_bytes, mac_len=tag_length)
if aad:
cipher.update(_decode_value(aad, aad_encoding))
ciphertext, tag = cipher.encrypt_and_digest(plaintext.encode("utf-8"))
combined = ciphertext + tag
return _encode_ciphertext(combined, output_encoding)
def aes_gcm_decrypt(
combined: str,
key: str,
nonce: str,
*,
key_encoding: KeyEncoding = "hex",
nonce_encoding: KeyEncoding = "hex",
aad: str | None = None,
aad_encoding: KeyEncoding = "utf8",
tag_length: int = 16,
key_size: int = 32,
input_encoding: CipherEncoding = "base64",
) -> str:
key_bytes = _normalize_key(_decode_value(key, key_encoding), key_size)
nonce_bytes = _decode_value(nonce, nonce_encoding)
data = _decode_ciphertext(combined, input_encoding)
if len(data) < tag_length:
raise ValueError("Ciphertext must include the authentication tag")
ciphertext, tag = data[:-tag_length], data[-tag_length:]
cipher = AES.new(key_bytes, AES.MODE_GCM, nonce=nonce_bytes, mac_len=tag_length)
if aad:
cipher.update(_decode_value(aad, aad_encoding))
plaintext = cipher.decrypt_and_verify(ciphertext, tag)
return plaintext.decode("utf-8", errors="replace")
# Example usage
key = "00112233445566778899aabbccddeeff"
nonce = "0102030405060708090a0b0c"
payload = aes_gcm_encrypt(
"hello",
key,
nonce,
key_encoding="hex",
nonce_encoding="hex",
aad="context",
aad_encoding="utf8",
tag_length=16,
key_size=16,
output_encoding="hex",
)
print(payload)
plain = aes_gcm_decrypt(
payload,
key,
nonce,
key_encoding="hex",
nonce_encoding="hex",
aad="context",
aad_encoding="utf8",
tag_length=16,
key_size=16,
input_encoding="hex",
)
print(plain)
Complete script (implementation + tests)
python
from __future__ import annotations
import base64
from typing import Literal
from Crypto.Cipher import AES
KeyEncoding = Literal["utf8", "hex"]
CipherEncoding = Literal["hex", "base64"]
def _decode_value(value: str, encoding: KeyEncoding) -> bytes:
return value.encode("utf-8") if encoding == "utf8" else bytes.fromhex(value)
def _encode_ciphertext(data: bytes, encoding: CipherEncoding) -> str:
return data.hex() if encoding == "hex" else base64.b64encode(data).decode("ascii")
def _decode_ciphertext(value: str, encoding: CipherEncoding) -> bytes:
return bytes.fromhex(value) if encoding == "hex" else base64.b64decode(value)
def _normalize_key(key: bytes, key_size: int) -> bytes:
return key[:key_size].ljust(key_size, b"\x00")
def aes_gcm_encrypt(
plaintext: str,
key: str,
nonce: str,
*,
key_encoding: KeyEncoding = "hex",
nonce_encoding: KeyEncoding = "hex",
aad: str | None = None,
aad_encoding: KeyEncoding = "utf8",
tag_length: int = 16,
key_size: int = 32,
output_encoding: CipherEncoding = "base64",
) -> str:
key_bytes = _normalize_key(_decode_value(key, key_encoding), key_size)
nonce_bytes = _decode_value(nonce, nonce_encoding)
cipher = AES.new(key_bytes, AES.MODE_GCM, nonce=nonce_bytes, mac_len=tag_length)
if aad:
cipher.update(_decode_value(aad, aad_encoding))
ciphertext, tag = cipher.encrypt_and_digest(plaintext.encode("utf-8"))
combined = ciphertext + tag
return _encode_ciphertext(combined, output_encoding)
def aes_gcm_decrypt(
combined: str,
key: str,
nonce: str,
*,
key_encoding: KeyEncoding = "hex",
nonce_encoding: KeyEncoding = "hex",
aad: str | None = None,
aad_encoding: KeyEncoding = "utf8",
tag_length: int = 16,
key_size: int = 32,
input_encoding: CipherEncoding = "base64",
) -> str:
key_bytes = _normalize_key(_decode_value(key, key_encoding), key_size)
nonce_bytes = _decode_value(nonce, nonce_encoding)
data = _decode_ciphertext(combined, input_encoding)
if len(data) < tag_length:
raise ValueError("Ciphertext must include the authentication tag")
ciphertext, tag = data[:-tag_length], data[-tag_length:]
cipher = AES.new(key_bytes, AES.MODE_GCM, nonce=nonce_bytes, mac_len=tag_length)
if aad:
cipher.update(_decode_value(aad, aad_encoding))
plaintext = cipher.decrypt_and_verify(ciphertext, tag)
return plaintext.decode("utf-8", errors="replace")
def run_tests() -> None:
key = "00112233445566778899aabbccddeeff"
nonce = "0102030405060708090a0b0c"
combined = aes_gcm_encrypt("hello", key, nonce, key_encoding="hex", nonce_encoding="hex", output_encoding="hex", key_size=16)
recovered = aes_gcm_decrypt(combined, key, nonce, key_encoding="hex", nonce_encoding="hex", input_encoding="hex", key_size=16)
assert recovered == "hello"
print("AES-GCM tests passed")
if __name__ == "__main__":
run_tests()