Ciphers

CAST5 (ECB)

CAST-128 from RFC 2144, the cipher OpenPGP told everyone to carry next to AES. Feistel rounds on 8-byte blocks, here in ECB with PKCS#7 padding.
IDcast546 / 55block · feistel
Cipher / Feistel

CAST5 (ECB)

The cipher RFC 4880 asked OpenPGP to carry, rotations and eight stored S-boxes.

Keyspace
2^40 to 2^128
Decode
same options back
Works on
UTF-8 or hex, hex out
Family
8 in feistel
required 1 / 2

Options

keystring
required
10 to 32 hex digits, an even number (a 40 to 128-bit key)
bytesstring
default text
What the plain side is: text for UTF-8 text, or hex to read and write hex there, for bytes that are not text

Access

Createcreate("cast5")
CLIciphers encode cast5 'ATTACK AT DAWN' --key 0123456712345678234567893456789a
Tryplayground with the sample above
Kindes, desx, triple-des, triple-des-cbc +3

Found an old PGP message? Check for CAST5 inside. Carlisle Adams published it as RFC 2144 in May 1997, under the name CAST-128. RFC 4880, the OpenPGP spec, then said every implementation must have Triple DES and should have AES-128 and CAST5. So for years it sat right there in the menu.

Here it runs on its own, in ECB, like blowfish and idea. UTF-8 text in, PKCS#7 padding, hex out.

ts
const cast5 = create("cast5");
const key = "0123456712345678234567893456789a";
cast5.encode("ATTACK AT DAWN", { key }).text; // "585e13962a59ed5274e0ab1bdcde47a3"
cast5.decode("585e13962a59ed5274e0ab1bdcde47a3", { key }).text; // "ATTACK AT DAWN"

That key is the one RFC 2144 uses for its own vectors.

What a round does

It's a Feistel cipher. The block splits into two 32-bit halves, and each round runs the right half through a function into the left. The function takes two subkeys. One is a 32-bit masking key, the other a 5-bit rotation. Mask, rotate, split into four bytes, look each byte up in its own S-box, combine the four words.

Three round types take turns. Type 1 adds the mask and combines with XOR, subtract, add. Type 2 starts with XOR, type 3 with a subtraction. Same parts, different order, round after round.

The key is 40 to 128 bits in steps of 8, so 10 to 32 hex digits. A shorter key gets padded with zeros to 128 bits. And up to 80 bits it runs 12 rounds instead of 16. Weaker key, less work. Fair, in a way.

Eight S-boxes, copied, not grown

blowfish computes its tables from the digits of pi. mars grows its S-box from SHA-1. CAST5 has nothing like that. Its eight boxes of 256 words came out of the CAST design procedure Adams wrote up in a paper. No formula, so they're stored. Four run the rounds, four run the key schedule. The file holds them exactly as RFC 2144 Appendix A prints them, eight hex words to a line. A script lifted them from the RFC text, not a pair of tired eyes.

Checked against

RFC 2144 B.1 for the 128, 80 and 40-bit keys, both ways. Then UTF-8 text against openssl enc -cast5-ecb with the legacy provider. The RFC also has a maintenance test: a million rounds of two 128-bit values encrypting each other. It took 21 seconds in a local run and ended on the RFC's exact values. Too slow for the test suite, so it ran once.

Should you encrypt with it?

No. RFC 9580, the OpenPGP spec that replaced RFC 4880 in 2024, says implementations must not encrypt with IDEA, Triple DES or CAST5 anymore. Decrypting old messages is still allowed. GnuPG 2.4 refuses to encrypt with it out of the box. And this page is ECB on top, which leaks every repeated block.

Got a whole PGP message rather than raw blocks? That's openpgp, which runs CAST5 inside OpenPGP's CFB.

A key that isn't 10 to 32 hex digits, or isn't whole bytes, is an InvalidOptionError. A missing key is a MissingOptionError. On decode, ciphertext that isn't whole 8-byte blocks, or doesn't end in PKCS#7 padding, is a CipherError.

Plain TypeScript, not constant time. Old messages and learning, not secrets.