Language: English

tools / aes

aes/

AES symmetric encryption and decryption. Mode, padding, key and IV formats and charset are all configurable, results match Java and CryptoJS, and your key never leaves the browser.

Plaintext

Ciphertext

History

Each successful encryption or decryption is saved automatically. The latest 20 are kept, only in this device's browser. Keys are never saved, but IVs and decrypted plaintext are, so clear the history when you are done on a shared computer.

AES, DES and RSA: what they are and how they differ

AES and DES are symmetric ciphers: the same key encrypts and decrypts, like one key that both locks and unlocks a door. They are fast and suit large amounts of data; the hard part is getting that key to the other side safely.

DES is an old standard from the 1970s with an effective key of only 56 bits, which dedicated hardware or computer clusters can now brute-force, so it is only for talking to legacy systems that still use it. AES replaced DES as the standard. It uses 128, 192 or 256-bit keys, has no practical attack today, and is the default choice for encrypting data.

RSA is asymmetric: there is a key pair. The public key can be given to anyone and is used to encrypt; the private key stays with you and is used to decrypt, like a mailbox anyone can drop letters into but only you can open. No shared key has to be agreed in advance, but RSA is slow and can only encrypt a few hundred bytes at a time. Real systems often combine the two: RSA encrypts a randomly generated AES key for the other side, and AES encrypts the actual data.

What is a cipher mode, and which one to use?

AES encrypts 16 bytes at a time; the mode decides how longer data is split into blocks and how the blocks are linked. ECB encrypts each block on its own, so identical content gives identical ciphertext and leaks patterns; avoid it. CBC mixes each block with the previous ciphertext block before encrypting, and the first block with the IV; it is the most common choice. CFB, OFB and CTR turn AES into a keystream that is XORed with the data byte by byte, so no padding is needed. GCM adds an authentication tag on top of CTR, so tampered ciphertext fails to decrypt; it is the recommended mode today.

What are the IV and padding for?

The IV (initialization vector) makes the same content encrypt differently each time. It does not need to be secret and can travel with the ciphertext, but never reuse one with the same key, especially in GCM. Every mode except ECB needs an IV: 12 bytes is recommended for GCM, and the other modes require exactly 16 bytes.

ECB and CBC need the data length to be a multiple of 16 bytes, so short data is filled up according to the padding. PKCS5Padding and PKCS7Padding are identical for AES and the most common. ZeroPadding fills with zeros and strips every trailing zero byte on decryption, so plaintext that itself ends in zero bytes loses them. NoPadding adds nothing, so you must get the length right yourself. GCM uses no padding.

Mapping to Java and CryptoJS

Java's Cipher.getInstance("AES/CBC/PKCS5Padding") means CBC with PKCS5Padding; plain "AES" defaults to ECB with PKCS5Padding. In Java, CTR and GCM only work with NoPadding, and the GCM tag must be 96 to 128 bits. CryptoJS's CryptoJS.pad.Pkcs7 is PKCS7Padding, and ZeroPadding, AnsiX923, Iso10126 and Iso97971 match by name. If you pass a string passphrase to CryptoJS.AES.encrypt, it derives the key itself and outputs a result starting with U2FsdGVkX1; that usage is not supported here, so pass a 16, 24 or 32-byte key and an IV instead.

What are the GCM tag and AAD?

The tag is the check value GCM computes; it is the last bytes of the ciphertext (16 bytes for a 128-bit tag). AAD is additional authenticated data, such as a message header. It is not encrypted but is covered by the check, so you must enter the same AAD when decrypting or the check fails.

FAQ

What should I do about "The key is N bytes" or "The IV is N bytes"?

First check that the format is right: the same 32 characters are 32 bytes in string format but only 16 bytes in hex. An AES key must be 16, 24 or 32 bytes, and apart from ECB and GCM the IV must be exactly 16 bytes; nothing is padded or truncated for you, and the current byte count is shown next to the Key and IV labels. In string format the count follows the selected charset, so one Chinese character takes 3 bytes in UTF-8. If your backend first processes the passphrase, for example by zero-padding or hashing it, work out the final bytes first and enter them in hex or base64.

What should I do when decryption says the padding is invalid?

It means the last decrypted block does not follow the selected padding rule. Usually one of the key, IV, mode or padding differs from what was used to encrypt, or the ciphertext was copied incompletely. Compare every parameter with the encrypting side; a wrong key format or ciphertext format (hex versus base64) causes the same error. ZeroPadding and NoPadding do not check the padding, so they will not raise this error, but the result is garbage if the parameters are wrong.

The start of the decrypted text is garbled, or it says the result is not valid UTF-8 text

Check the IV first. When the ciphertext is longer than one block, a wrong IV in CBC and CFB mode ruins only the first 16-byte block, the rest comes out fine and no padding error appears, so you see garbage at the start and correct text after it. If the message says the result is not valid text, the charset may differ from the one used to encrypt, for example the other side used GBK. Setting the output format to hex lets you check the decrypted bytes themselves first.

What should I do when GCM decryption says the tag check failed?

It means one of the key, IV, AAD or tag length differs from encryption, or the ciphertext was modified. The last bytes of the input are treated as the tag, with a length set by the "Tag length" option (128 bits by default, which is 16 bytes), so the ciphertext and tag must be entered together; if the other side gives you the tag separately, append it to the ciphertext first. The AAD format defaults to hex, so change it when you enter string content, and if no AAD was used to encrypt, leave it empty when decrypting.

My result does not match Java, Python or another backend. How do I troubleshoot?

Check these in order: mode and padding, the format and byte count of the key and IV, the charset, and the input and output formats. Plaintext in string format is not trimmed, so one extra trailing newline makes it different data. CTR, CFB and OFB also pad to the selected padding here, so with PKCS5Padding the ciphertext is longer than the plaintext; if the backend uses NoPadding, choose NoPadding here too. CFB here is the 128-bit full-block variant, so it will not match a backend that uses CFB8.

Should the ciphertext be hex or base64, and what happens if I choose wrongly?

Follow whatever the other side produces: text made only of 0-9 and a-f is hex, and text with mixed-case letters, +, / or a trailing = is base64. Choosing wrongly when decrypting does not always fail at once, because every hex character is also a valid base64 character; you simply get the wrong bytes, and it shows up later as "not a multiple of 16" or invalid padding. Base64 with - and _ (the URL-safe form) or with missing = is accepted, and spaces, colons and a 0x prefix in hex are ignored.

What does the history store, and is it uploaded?

It lives only in the localStorage of this device's browser and is never uploaded; the page code makes no network requests. One entry is added after each successful encryption or decryption, up to 20 are kept, and anything whose input or result is over 20,000 characters is not recorded. An entry holds the parameters, IV, AAD, input and result, plus an 8-character fingerprint derived from the key (the characters after the # in each entry, used to tell whether it is the same key), but never the key itself, so after clicking "Load" you need to enter the key again. Each entry can be deleted on its own, and on a shared computer click "Clear history" when you are done.

Can it generate a random key or IV for me?

No. There is no generate button, so you enter the key and IV yourself. The same plaintext, key, IV and parameters always give the same result; only ISO10126 padding mixes in random bytes and so changes it. When you need random values, generate them yourself, for example openssl rand -hex 16 on the command line prints 16 bytes, which you can enter with the format set to hex.