The MindReader Encryption / Decryption Algorithms

Abstract

This document describes the encryption and decryption transforms used by Mindreader, gives pseudocode for their implemntation, and small sets of sample plain/ciphertext.

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.

Introduction

There are two transforms, one used for encryption, one for encryption. They are merely transforms and are just labelled encryption and decryption - i.e. the decryption transform may be used for encryption, and vice versa. They may be use several times, i.e. the plaintext an be transformed with the encryption transform with one password, then transformed with the decryption transfor with another password.

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].

Feedback

(This section to be weritten in terms of the recurrence relation)

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

spLen=(2+passwordLen)/2.

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.

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.

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.