AES (ECB)
- create
- create("aes")
- family
- Substitution-permutation
- options
- --key
- self-inverse
- no
- keyspace
- 2^128, 2^192 or 2^256 keys
- try it
- ciphers aes "ATTACK AT DAWN" --key 2b7e151628aed2a6abf7158809cf4f3c
AES from FIPS-197 with a 128, 192 or 256-bit key, picked by the key length: 32, 48 or 64 hex digits. Case doesn't matter and spaces are ignored. The mode is ECB, the electronic codebook. The text is encoded as UTF-8 and padded with PKCS#7, then each 16-byte block is encrypted with the same key and nothing else. The ciphertext comes back as lowercase hex, and decode wants hex too.
const aes = create("aes");
const key = "2b7e151628aed2a6abf7158809cf4f3c";
aes.encode("ATTACK AT DAWN", { key }).text; // "bef12e48d0f1739d732326cbecbef389"
aes.decode("bef12e48d0f1739d732326cbecbef389", { key }).text; // "ATTACK AT DAWN"
OpenSSL gives the same bytes, so you can check it without this package:
printf %s "ATTACK AT DAWN" | openssl enc -aes-128-ecb -K 2b7e151628aed2a6abf7158809cf4f3c | xxd -p
The block function is tested against the FIPS-197 Appendix C examples and the ECB vectors from NIST SP 800-38A.
Why ECB leaks
Same key, same block, same output. Thirty-two As are two identical blocks of plaintext, and they come out as two identical blocks of ciphertext:
aes.encode("A".repeat(32), { key: "000102030405060708090a0b0c0d0e0f" }).text;
// dd4b1a0b47daa7067d0b59d95d58a6ae dd4b1a0b47daa7067d0b59d95d58a6ae 954f64f2e4e86e9eee82d20216684899
Spaces added here to show the blocks. The third block is only padding. That's the whole weakness: nobody learns the key, but anyone sees which blocks repeat, and can cut blocks out or swap them without knowing the key either. It's why ECB is the mode CTFs pick and the mode textbooks warn about.
A key that isn't 32, 48 or 64 hex digits is an InvalidOptionError, a missing one a MissingOptionError. On decode, a ciphertext that isn't whole 16-byte blocks of hex is a CipherError. So is a wrong key, because the last block then almost never ends in valid PKCS#7 padding. Decrypted bytes that aren't UTF-8 are an error too, the result is always text.
This implementation is for learning and for puzzles. It's plain TypeScript with table lookups, not constant time, and ECB hides nothing about the structure of the message. Don't protect anything real with it.