๐ฎ Cheat activated โ skipping to text encryption
Password Hashing โ Password hashing: slow on purpose
In plain English
p =
q =
K1 =
K2 =
Showing
yยฒ = xยณ โ 3x + 5 over [โ3.2, 3.2]. The curve is symmetric about the x-axis because y is squared. Discriminant 4aยณ + 27bยฒ โ 0 guarantees the curve is non-singular โ no cusps or self-intersections โ so the group operations are well-defined.
P = (0, โ5) โ (0, )
Q = (2, โ7) โ (2, )
P + Q = (, )
Geometrically: draw the line through P and Q, find where it hits the curve a third time, reflect across the x-axis. That's P+Q.
P = (2, โ7) โ (2, )
2P = (, )
When P = Q, the "line through them" is the tangent at P. Same recipe: find where it hits the curve a second time, reflect.
k =
kยทP = (, )
Computed via double-and-add: write k in binary, walk LSBโMSB, double at each step, add P when the current bit is 1.
All points (x, y) โ [0, 17)ยฒ satisfying
yยฒ โก xยณ + 7 (mod 17). 17 affine points + the "point at infinity" (the group identity). Same point-addition rules as over the reals โ just modular arithmetic. No smooth curve, but the group structure is identical.
The orbit of G = (15, 13) under repeated addition on
yยฒ โก xยณ + 7 (mod 17):1ยทG = (15, 13)
2ยทG = (2, 10)
3ยทG = (8, 3)
4ยทG = (12, 1)
5ยทG = (6, 6)
6ยทG = (5, 8)
7ยทG = (10, 15)
8ยทG = (1, 12)
9ยทG = (3, 0)
10ยทG = (1, 5)
11ยทG = (10, 2)
12ยทG = (5, 9)
13ยทG = (6, 11)
14ยทG = (12, 16)
15ยทG = (8, 14)
16ยทG = (2, 7)
17ยทG = (15, 4)
18ยทG = โ (identity)
No pattern: 1ยทG โ 2ยทG goes from (15,13) to (2,10), but 7ยทG โ 8ยทG goes from (10,15) to (1,12). The hops look random. Given just (15,13) and, say, (8,3), which k did that? For our 18-point orbit, you can brute-force; for secp256k1's ~2ยฒโตโถ points, brute force takes longer than the age of the universe. That asymmetry โ fast forward, infeasible reverse โ is ECDLP, the bedrock of every elliptic-curve crypto primitive on this site.
N:
Discovered prime factor:
Other factor:
Pollard's iterations:
Brent's iterations (same N):
For 1024-bit primes (~300 decimal digits), Pollard's rho would need ~2256 iterations. Infeasible. That's why real RSA uses huge primes.
Scenario 1: sending an HTTP request body (need integrity)
Scenario 2: encrypting database fields (identical secrets must look different)
Scenario 3: per-record disk encryption with random access (no integrity required)
Or type one:
No quick picks available โ type a value yourself:
Your toy lesson script
Your full Python script
Playground
Type anything (โค500 printable ASCII chars). The table re-encrypts as you type, using .
ยท decoded:
In the real world
What you just did is textbook RSA โ the bare math. Production systems differ in three important ways:
- RSA almost never encrypts the actual message. Each RSA block can only hold a number smaller than n โ for a 2048-bit key that's ~214 bytes after padding. For anything larger, you don't split-and-RSA. You generate a random AES key, RSA-encrypt that key (one small block), then AES-encrypt the message (no size limit). HTTPS, SSH, and PGP all work this way. It's called hybrid encryption.
-
Real RSA always uses padding.
Your per-character ciphertext leaks the alphabet โ every
einwould encrypt to the same number, so frequency analysis breaks it instantly. Real protocols use OAEP padding to add randomness, so the same plaintext produces different ciphertexts each time. - RSA also signs. Same math, opposite roles: hash the message (SHA-256), RSA-encrypt the hash with your private key. Anyone can verify with your public key. The message itself can be any size because only the fixed-size hash is touched by RSA.
AES S-box (highlighted cell = answer for input 0x53)
Row 1 (input)
โ
Row 1 (after shift left by 1)
??
One column (input)
ร
[2 3 1 1]
[1 2 3 1]
[1 1 2 3]
[3 1 1 2]
(GF(2โธ))
[2 3 1 1]
[1 2 3 1]
[1 1 2 3]
[3 1 1 2]
(GF(2โธ))
โ
Output column
State byte
0xED (237 = 11101101)
XOR
Round-key byte
0x2B (43 = 00101011)
=
Output
??
A real 16-byte state going through all four transformations of one round. Demo uses a fixed input + round key; values computed client-side via the actual S-box, ShiftRows offsets, MixColumns matrix, and XOR.
Last operation:
Input:
Signature (hex):
Result:
โ Signature valid
โ Signature invalid (tampered or wrong key)
โ
PIN: ยท PAN:
| Zone | Key (fingerprint) | Ciphertext (hex) |
|---|---|---|
| Terminal (encrypted under TPK) |
โฆ | |
| Acquirer HSM (translated to ZPK1) |
โฆ | |
| Network HSM (translated to ZPK2) |
โฆ | |
| Issuer HSM (verifies PIN) |
โ | (verification only) |
โ
โ PIN matches expected โ transaction approved
โ PIN mismatch
Original:
AES-128 key:
IV (nonce):
Ciphertext:
Decrypted: โ matches
โ
SHA-256("hello")
SHA-256("Hello")
Bit-level diff (red = differing bits)
โ flipping a single bit of input changes โhalf the output bits. That's avalanche.
Input:
Key:
Message:
HMAC-SHA256:
Message used:
MAC checked:
โ MAC verified โ message authentic
โ MAC mismatch โ message altered or wrong key
Alice's public key:
Bob's public key:
Shared secret (from Alice's side):
โ Both sides derived the same secret โ KEX succeeded
Note: this browser doesn't support Web Crypto X25519, so the page is showing the canonical RFC 7748 ยง6.1 test vectors instead.
Last operation:
Input:
Signature (hex):
Result:
โ Signature valid
โ Signature invalid (tampered or wrong key)
โ
Plaintext:
AAD:
Key:
Nonce:
Ciphertext:
Tag:
Decrypted: โ matches
โ Tamper test: a single-byte flip in the ciphertext made decryption fail (InvalidTag). That's the AEAD guarantee.
โ
Original (32ร32 silhouette)
After ECB encryption
The outline is still visible after ECB encryption โ identical plaintext blocks produced identical ciphertext blocks. ECB hides byte values, not patterns. Never use ECB.
Plaintext (3 blocks):
IV:
All three plaintext blocks are identical ("YELLOW SUBMARINE"), but the three ciphertext blocks differ โ that's CBC chaining doing its job.
Scenario 1 (HTTP body): โ
Scenario 2 (DB fields): โ
Scenario 3 (disk, random access): โ
Target ciphertext:
Queries sent to oracle:
Recovered byte (last byte of plaintext):
No key. No decryption-with-key. Just observing whether the server said "bad padding" or "ok" for each forged ciphertext.
Recovered plaintext: ""
Hex:
Total queries: (โ 128 per byte ร 16 bytes)
Input: "password123"
SHA-256:
Computed in <1 ms. A GPU farm tries ~10 billion such guesses per second. Plain SHA-256 is not a password hash.
Password: ยท Iterations:
Salt:
PBKDF2-SHA256:
Took:
(cited)
Log scale. SHA-256 is microseconds; password hashes are hundreds of milliseconds. That โ100,000ร gap is the whole point.
PRK:
client write key:
server write key:
client IV:
server IV:
All four came from the SAME PRK + different info strings. That's how one ECDH shared secret turns into a whole tree of working keys.
Last operation:
Input:
Signature (hex):
Result:
โ Signature valid
โ Signature invalid
โ
Last operation:
Input:
Signature (WOTS+ chain + Merkle path, hex):
Leaf index:
Result:
โ Signature valid
โ Signature invalid
โ
Last operation:
Input:
Signature (hex, 256 bytes):
Result:
โ Signature valid
โ Signature invalid
โ
Toy RSA modulus: bits (n = )
Target ciphertext (encrypted under the public key):
Queries sent to vulnerable oracle:
Conforming s values found:
Recovered plaintext: ""
No knowledge of the private key, no factoring of n โ just observing whether each chosen ciphertext decrypted to something that started with
0x0002. ROBOT (2017) and DROWN (2016) showed this attack is still relevant 25+ years later.Blob 1 (first 16 hex bytes):
Blob 2 (first 16 hex bytes):
Bytes that differ between the two: of
MD5(blob1) = MD5(blob2) =
โ COLLISION CONFIRMED โ different inputs, same hash
SHAttered.io published two PDFs that both hash to:
Each PDF is bytes โ too big to embed inline here. Download them from shattered.io and verify locally:
Hash space: 2 = possible values
Birthday bound: 1.18 ยท โN โ attempts
You found a collision after: attempts
Input A: ""
Input B: ""
Shared 16-bit truncated hash:
For MD5 (128 bits), the same math gives 264 โ 1.8ยท1019 attempts. Nation-state budget. That's why we don't use MD5 anymore.
Password:
Cost factor: (2 = iterations)
Time:
Output (synthetic, not real bcrypt format):
Each +1 to cost doubles the work. Real bcrypt at cost 14 takes ~1 second per hash โ that's 30,000ร slower than plain SHA-256. Brute-forcing rainbow tables becomes infeasible.
Original request:
Observed signature:
โ attacker now uses signature as resumption point, hashes only the extension โ
Glue padding (hex):
Forged request:
Forged signature:
Server response:
โ ACCEPTED โ extension is now signed
โ rejected
Attacker never learned the secret. They forged a valid signature anyway. That's why every modern protocol uses HMAC instead of
H(secret || msg).Ciphertext (Vigenรจre, key length 5):
Recovered key:
Recovered plaintext:
Frequency analysis split the ciphertext into 5 streams (one per key-letter position), brute-forced each as a Caesar cipher against English letter frequencies, and reassembled.
Keypair (this session): x = , X =
Last operation:
Input:
Signature (R, s): (, )
Check gs mod p == R ยท Xe mod p:
lhs =
rhs =
โ Signature valid
โ Signature invalid (tampered or wrong message)
โ
| char | binary | ascii | encrypted |
|---|---|---|---|
Original:
Encrypted:
Decrypted:
โ matches
Python for this step