All Tools
Tools/AES Calculator
🔐
Cryptography & KeysAvailable

AES Calculator

Encrypt and decrypt data using AES-128, AES-192 or AES-256 in ECB, CBC, CTR or GCM mode — every mode runs on an in-page AES implementation (SP 800-38A / 38D), so AES-192 works in every browser and your key material never leaves this page.

Follows NIST SP 800-38A / SP 800-38DECB, CBC, CTR, GCM·verified Oct 2026· double-checked Oct 2026— SP 800-38A F.1–F.5 vectors incl. AES-192; GCM test cases 1–4, 7–12 and 16; all modes on an in-page AES

Use test data only. All calculations run locally in your browser — PayProbe never sees, transmits, or stores your PAN, CVV, keys, PINs, or cryptographic inputs. How we handle data →

Inputs

About AES modes

AES-CBC

Cipher Block Chaining — each plaintext block is XORed with the previous ciphertext block before encryption. Requires a random, unpredictable IV and provides only confidentiality. Padding oracle attacks are possible if unauthenticated; always pair with a MAC (e.g. HMAC-SHA256) in production. Common in EMV/payment HSM contexts (ISO 9797, PIN blocks, key diversification).

AES-GCM

Galois/Counter Mode — authenticated encryption with associated data (AEAD). Provides both confidentiality and integrity/authenticity via a 128-bit auth tag. Uses a 12-byte nonce; never reuse a nonce with the same key — doing so fatally compromises both confidentiality and authenticity. Preferred for TLS 1.3, API payloads and any new protocol.

AES-CTR

Counter mode — a stream cipher built from AES: each 16-byte counter block is encrypted and XORed with the data, so no padding is needed and ciphertext length equals plaintext length. This tool follows NIST SP 800-38A: the whole 128-bit block is the counter, incremented big-endian. Like GCM, a counter value must never repeat under the same key.

AES-ECB — test use only

Electronic Codebook mode encrypts each block independently, so identical plaintext blocks produce identical ciphertext blocks. This leaks structural information (the classic "ECB penguin" problem) and is trivially distinguishable from random. It is offered here for key check values and for reproducing test vectors (any whole number of blocks) — never for bulk data.

Padding (ECB / CBC)

PKCS#7 always adds 1–16 bytes of value n (what most libraries do by default). ISO/IEC 9797-1 method 2 always adds 0x80 then zeros. Zero padding (method 1) adds zeros only when needed and cannot be removed unambiguously, so decrypt leaves it in place. CTR and GCM need no padding.

Key sizes

AES-128: 16-byte key — adequate for most use-cases, fast on all hardware.
AES-192: 24-byte key — rare, not used in TLS or most standards.
AES-256: 32-byte key — required by NSA CNSA 2.0 for US national security systems; NIST still approves all three sizes (AES-128 included) and its post-quantum guidance does not retire AES-128. All three have the same block size (16 bytes) and differ only in key schedule rounds (10 / 12 / 14).

</> Code Implementation
# AES-CBC and AES-GCM encrypt/decrypt
# Requires: pip install pycryptodome
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad

def aes_cbc_encrypt(key: bytes, iv: bytes, plaintext: bytes) -> bytes:
    cipher = AES.new(key, AES.MODE_CBC, iv)
    return cipher.encrypt(pad(plaintext, AES.block_size))

def aes_cbc_decrypt(key: bytes, iv: bytes, ciphertext: bytes) -> bytes:
    cipher = AES.new(key, AES.MODE_CBC, iv)
    return unpad(cipher.decrypt(ciphertext), AES.block_size)

def aes_gcm_encrypt(key: bytes, nonce: bytes, plaintext: bytes) -> tuple:
    cipher = AES.new(key, AES.MODE_GCM, nonce=nonce)
    ciphertext, tag = cipher.encrypt_and_digest(plaintext)
    return ciphertext, tag

def aes_gcm_decrypt(key: bytes, nonce: bytes, ciphertext: bytes, tag: bytes) -> bytes:
    cipher = AES.new(key, AES.MODE_GCM, nonce=nonce)
    return cipher.decrypt_and_verify(ciphertext, tag)

# Example — AES-128-CBC, NIST SP 800-38A F.2.1 key/IV/block 1.
# These snippets use PKCS#7 padding: select "PKCS#7" in the tool to get the same bytes
# (with padding "None" the tool returns just the first block, 7649ABAC…197D).
key   = bytes.fromhex("2B7E151628AED2A6ABF7158809CF4F3C")
iv    = bytes.fromhex("000102030405060708090A0B0C0D0E0F")
plain = bytes.fromhex("6BC1BEE22E409F96E93D7E117393172A")
enc   = aes_cbc_encrypt(key, iv, plain)
dec   = aes_cbc_decrypt(key, iv, enc)
print(f"Encrypted : {enc.hex().upper()}")  # 7649ABAC8119B246CEE98E9B12E9197D8964E0B149C10B7B682E6E39AAEB731C
print(f"Decrypted : {dec.hex().upper()}")  # 6BC1BEE22E409F96E93D7E117393172A
Something wrong or missing? Report a problem— we check reports against the specs and fix them.