Static site. Every demo computes in your browser, and nothing you type is sent anywhere.
25%
Key stream = primer, then the plaintext. Recover a block, and you hold the next key.
ciphertext, all the attacker holds
WYAOF IYISS EVFOD HELEE SRE
There is no period, so Kasiski has nothing to count and the index of coincidence has nothing to detect. But the key stream is the plaintext, and English is guessable.
Its length is also a guess at the primer length. That is what makes the crib line up with the key stream.
One guess unzips the rest
positions
key = plaintext already recovered
which decrypts
7…13
WEHAVEA
MOLEABO
14…20
MOLEABO
RTTHEDE
21…22
RT
AL
recovered
WEHAV EAMOL EABOR TTHED EAL
Correct crib, and the whole message falls out of it. Every letter recovered is the key for the next block.
No crib: try every primer, length 1 to 8
length
primer it settles on
bigram score
χ²
plaintext it produces
m = 1
Y
-41.9
96.4
YAAORRHBRBDSNBCFZMSMGLT
m = 2
KO
-30.2
21.8
MKOEREHELOTHMHRANLRTBYD
m = 3
MHS
-33.9
35.1
KRIEOAUUSYKDHEAAALEEHNA
m = 4
EUWU
-30.3
19.9
SEEUNEUOFOKHAATAELLEOGT
m = 5
SRMKF
-33.6
23.2
EHOEAERUOSAELALHAAETLRE
m = 6
DEAAFU
-36.0
21.5
TUAOAOFOSEEHAALDAEEEHOE
m = 7
OUMOOUY
-29.8
20.8
IEOAROAAOEEERODTAHANEOL
m = 8
IKWXOUVU
-26.9
30.3
OOERRODOEEAEOAATAHEAERE
23 letters, 936 trials
Where the bigram score comes from
score = Σ log10 P(pair), over every adjacent pair of the candidate
pair
P, from the table
log₁₀ of it
in the table?
ER
2.05%
+0.312
yes
RO
0.73%
-0.137
yes
EA
0.69%
-0.161
yes
OO
0.01%
-2.000
no, floored
OE
0.01%
-2.000
no, floored
The reference table holds 50 of the 676 possible pairs. Anything missing takes BIGRAM_FLOOR = 0.01%, and log₁₀(0.01) = −2. On this candidate 8 of 22 pairs are in the table and 14 are floored, which sums to -26.9.
A probability below 1 has a negative logarithm, so the score is negative by construction, and higher is better. That is the opposite of chi-square, where lower wins. The score also grows with length, so two candidates are only comparable over the same ciphertext. Every row of the table above is one message, which is what makes that column fair.
Guessing all 8 primer letters at once would be 208,827,064,576 combinations. Nobody searches that. The stream is the primer and then the plaintext, so for i ≥ m the key at iis the plaintext at i−m, which makes p[i] = c[i] − p[i−m]. That link only reaches back by m, so the positions fall into m chains that never touch: r, r+m, r+2m and so on. One letter fixes a whole chain, and the chains are independent, so they are never combined. Length 8 costs 26 × 8 = 208 trials, and sweeping every length from 1 to 8 costs 936. On 23 letters it does not land. At m = 8 each chain holds only about 3 letters. Choosing among a chain’s 26 candidates means scoring those few letters against English frequency, and that few letters cannot settle it, so the winner is close to arbitrary. The wrong primer it returns looks exactly like a right one: nothing in the output tells you it guessed. Press Use a paragraph and run it again. The attack does not get cleverer; the message gets longer.
Two scores, one answer. Bigrams see order and chi-square does not, which is why the columnar attack later in this module needs bigrams: a transposition moves letters without changing a single count, and chi-square cannot see it at all. Here that blindness costs nothing. A wrong m breaks the recurrence, so only the first letter of each chain is tuned and the rest come out as rubbish that either score can spot. Both columns pick the same length, and chi-square separates it more sharply. The heavier statistic was not needed for this one.
Removing the repetition removed the wrong weakness. Autokey fixed the thing Kasiski attacks and left the key stream made of English, which is a structure the attacker knows at least as well as the sender does. A key stream has to be independent of the message, and the only classical cipher that manages it is the one-time pad.