Let's examine the code, here's the heart of the decryption:
Code: Select all
$cryptchar=$characternumber+$stringcharacter-$stringlength-$keycharval-$step-$wholekeyvalue;
Or in a more human-readable form:
Pi = Ci + i - len(C) - Kj - step - W
(P = plaintext, Pi = i-th plaintext character; C = ciphertext, K= key; W = wholekeyvalue)
First, we can eliminate len(C), i and step from the equation, because they are values we know (step depends on i and len(K) ). Which gives us:
Pi = Ci - Kj - W or
Ci = Pi + Kj + W
We should also note that K(j) is actually K(i % 31 + 1). Here's why:
Code: Select all
if($keychar>$keylength){$keychar=1; $step=$step+1;}
Notice that $keychar wraps to 1, not 0. So, let's arrange our C in 31 columns like this (omitting C(0) )
Code: Select all
C01 C02 ... C31
C32 C33 ... C62
C63 C64 ... C93
or, with the last equation we have:
Code: Select all
P01+K1+W P02+K2+W ... P31+K31+W
P32+K1+W P33+K2+W ... P62+K31+W
P63+K1+W ....
Notice something?
Yep, column 0 is P(1+i%31) + (K1+W)!
It consists of every 31th letter of the message, offset with a constant (aka Caesar cipher). One frequency analysis later, and we know the most probable values of P(1+i%31). We can't check directly if these values are real plaintext, because they are spaced 31 bytes away from each other (i.e. we can't use a dictionary). What we can do is to take the frequencies, apply them to the other 30 columns, and then check the linear plaintext. If it looks it contains English (or whatever) words - store it for human review. If it doesn't, backtrack to the frequency table, and try another distribution.
Edit: Notice that in this attack we eliminated the key K altogether. Later, knowing P and C we can recover K, and directly decrypt any later messages encrypted with the same key.