|
Note: Note that this document talks in terms of a "scratchpad", and doesn't explain that the algorithms are actually recurrence relations - this needs expanding upon, and will get written up soon.
Of course the usual usage would be that the
plaintext is encrypted with the encryption transform using the password, then
later decrypted with the decryption transform using the same password, again
yielding the plaintext.
Passwords and Keys
Password to key transformation
Passwords can contain any printable
ASCII characters, and are between 5 and 10 characters in length.
The password is transformed into the key by the following process, expressed in C-like pseudocode; arrays start at element 0:
// shift password down so 'sp' => 0, '!' => 1, ' " ' => 2 etc. byte passMod[passLen]; for (i=0; i<passLen; i++) passMod[i] = password[i] - 32; // transform password to key keyLen = (3+passLen) / 2; byte key[keyLen]; key[0] = 0; for (i=1, k=0; i<keyLen; i++, k+=2) { key[i] =(passMod[k]+ passMod[k+1]) % 95; key[0] = (190 + key[0] - key[i]) % 95; }
This transform effectively folds pairs of characters from the password into the bytes of the key.
Five and six character passwords are transformed into four byte keys, seven and eight character passwords are transformed into five byte keys, and nine and ten character passwords are transformed into six byte keys.
Keyspace size
This yields the following keyspace size:
4-byte keys => 954 = 81,450,625
5-byte keys => 955 = 7,737,809,375
6-byte keys => 956 = 735,091,890,625
Leading to a total of 742,911,150,625 keys.
Keyspace density
It is unlikely that
we need to consider the entire keyspace: multiple passwords will fold into the
same key, and certain ASCII characters are more likely to be used in
passwords. However, due to the additive nature of the password-to-key
transform, even if password character n is an unlikely one, it's
possible that character n+1 is a frequently-used one, hence leading
to an 'average' value for that key byte.
Given the usual frequencies of letters/pairs in English, it should be possible to order the keyspace into a most-likely-first, and to bring forward those keys derived from dictionary words. However, this has not yet been attempted; current efforts are based around a sequential search through the entire keyspace. Initial attempts using a farly large dictionary were unsuccessful, leading us to believe that the password was not an exact dictionary word, or that multiple transforms with different passwords were used.
The Main Transforms
Symmetry
Encryption and decryption transforms are symmetric:
E(plaintext, K) = ciphertext, and D(ciphertext, K) = plaintext. The transforms
may also be used the "wrong way round", i.e. D(plaintext, K) = ciphertext and
E(ciphertext, K) = plaintext.
White space preservation
The transforms do not affect white space in
the plaintext: characters whose ASCII value is <= 32 are not changed, thereby
preserving the sentence and paragraph spacing of the plaintext in the
ciphertext.
The Recurrence Relations
The transforms are recurrence relations; successive terms of the relations rely
on earlier terms.
Let P[] be the plaintext data (with white spaces removed, for simplicity), and let K[] be the key data, of length keyLen, as discussed above. C[] is the ciphertext data.
The ith element of the ciphertext C[] is computed by the encryption recurrence relation:
Ci = [ (Pi - 33) + 2 * Ci-1 - Ci-encLen - Pi - keyLen ] mod 95
Conversely, the ith element of the plaintext P[] is computed by the decryption recurrence relation:
Pi = ( [ Ci - 2 * Ci-1 + Ci-encLen + Pi - keyLen ] mod 95 ) + 33
(Need to double check these relations)
Noting that then i=0, there are entries before the ciphertext in C[], such that C[-1] = C[-2] = ... = C[-encLen] = 0, and that the transforms feedback the initial values of the key by storing the key "before" the plain text, such that P[-keyLen] = K[0], P[-keyLen+1] = K[1], ..., P[-1] = K[keyLen-1].
In the current C implementation, during transformation,a small scratchpad is
used. This is initialsed with zeroes.
Two values from the scratchpad and
one from the key are used in the transformation of each byte of input text
(this being the plaintext in the encryption transform, and the ciphertext in
the decryption transform).
The indices into the scratchpad iterate over
the scratchpad modulo its length, thereby repeatedly looping through it.
The length of the scratchpad is
The index into the key used in the transform is modulo its length [ which is
(3+passwordLength)/2, see earlier section on password to key transformation ],
thereby repeatedly looping through it.
After transforming a byte of input
text into output text, a single byte of the scratchpad, and a single byte of
the key are modified, thereby providing two sources of feedback.
Next, the two indices
into the scratchpad are determined. The first, ex starts at the first
character of the scratchpad; the second, e1 is always one place behind ex,
modulo spLen. It starts at the final character of the scratchpad, then moves
to the first.
Feedback
(This section to be weritten in terms of the recurrence relation)
spLen=(2+passwordLen)/2.
Note on the transform algorithms
The following descriptions of the
two transforms require the removal of white space in the input text (which
would be skipped in a proper implementation; this complicates the algorithm a
little).
The Encryption Transform
for (i=0; i<spLen; i++)
sp[i]=0;
for (i=0; i<plainLen; i++) {
c=plainText[i]-33;
ex=i%spLen;
e1=(i+spLen-1)%spLen;
x=(380+c+2*sp[e1]-sp[ex]-
key[i%keyLen]) % 95;
sp[ex]=x;
cipherText[i]=x+33;
key[i%keyLen]=c;
}
The Decryption Transform
for (i=0; i<spLen; i++)
sp[i]=0;
for (i=0; i<cipherLen; i++) {
c=cipherText[i]-33;
ex=i%spLen;
e1=(i+spLen-1)%spLen;
x=(380+c-2*sp[e1]+sp[ex]+
key[i%keyLen]) % 95;
sp[ex]=c;
plainText[i]=x+33;
key[i%keyLen]=x;
}
Notes on the transforms
Before transforming each character, it has 33
subtracted from it. This shifts the ASCII set down so that space becomes value
0, ! becomes 1, " becomes 2, etc. The result is that the printable ASCII set
then falls in the range of arithmetic modulo 95.