40.4. One Time Pads - Unbreakable Encryption

40.4.1. Originally

Towards the end of The Great War, WWI, Joseph Mauborgne, a major heading the US Army cryptography research, came up with the idea of changing the keys in the Vigenère Cipher from a sequence of words to a random sequence of characters. That alone improved the security of using the Vigenère Cipher. Then he created a large number of sheets of paper each with a different random sequence of characters to be used as keys. The sender and the receiver should each get a copy of all the sheets/keys. The text to be sent is encrypted with the first key. Succesfully sent and received, the key is destroyed, not to be reused. The next message will de encrypted with the next key which is then destroyed upon a succesfull encryption/decryption phase.

This adaptation of the Vigenère cipher is called the one-time-pad cipher because each key is used once, and only once. If the protocol of using each key only once is followed it is unbreakable. [Sin99] has an example of a ciphertext that produces (at least) two different meaningful plaintexts when decrypted with two different keys. His example is a text of 21 characters that needs 26**21 equalling 5.2*1030 attempts to crack by brute force.

40.4.2. Computerized

In the era of the computer, the one time pad cipher has been adapted slightly. The plaintext and the keys are converted into a sequence of bits. The key must of course be at least as long as the plaintext. The the two bit sequences are added mod 2, bit by bit. This process is often called exclusive or, XOR. An example would be


 plaintext:   01100001 01100010 01000011    (abC)
       key: + 01100101 00110001 01111000    (e1x)
              -------- -------- --------
ciphertext: = 00000100 01010011 00111011    (...)
        

The very interesting thing now, is that if we take the ciphertext, and add it mod 2, XOR, to the same key used to encrypt it, we get, lo and behold, the plaintext back. Who says math isn't fun?


ciphertext:   00000100 01010011 00111011    (...)
       key: + 01100101 00110001 01111000    (e1x)
              -------- -------- --------
 plaintext: = 01100001 01100010 01000011    (abC)
        
Example 40.3.  XOR'ing with JavaScript nodeexps/xor1.js
/*
 * Python has encode/decode to convert a string to bytes and back,
 * Javascript has nothing, so get help from:
 * https://gist.github.com/ril3y/501020a4e3923f3422253a5501eff6fe
 * DART has an elegant way
 */
'use strict';
/*
 * ril3y's solution
 */
// ...
// something goes wrong when decoding ???


/*
 * DARTS solution, re link above
 * nmls comments:
 * xorString gets key as input
 * returns a generator function
 * call the generator with the text to be processed
 * loop through with generator.next().value
 * until text is exhausted
 */
function xorString(init) {
    const initArr = Array.from(init);
    const initLength = initArr.length;
    return function* (input) {
        let idx = 0;
        for (const ch of input) {
            yield initLength === 0 ? ch : String.fromCharCode(ch.charCodeAt(0) ^ initArr[(idx++) % initLength].charCodeAt(0));
        }
    }
}

/*
 * testing
 */
let p1 = 'Sandwich';
let k1 = 'abracadabra';
let f = xorString(k1);                  // get generator function built on key
let o = f(p1);                          // run it with plaintext
let c1 = '';                            // get crypto values byte by byte
while (true) {
    let y = o.next();
    if (y.done) {
        break;
    }
    c1 += y.value;
}
console.log(`DART\nplain: '${p1}', length: ${p1.length}, crypto: '${c1}', length: ${c1.length}`);   // unprintables in c1

f = xorString(k1);                      // build generator function on key
o = f(c1);                              // run it with cryptotext
let p11 = '';
while (true) {
    let y = o.next();
    if (y.done) {
        break;
    }
    p11 += y.value;
}
console.log(`DART\ncrypto: '${c1}', length: ${c1.length}, plain: '${p11}', length: ${p11.length}`);   // unprintables in c1

tested with

┌──(nml㉿kali)-[~/nodeexps]
└─$ node xor1
DART
plain: 'abC', crypto: 'S;'
DART
crypto: 'S;', plain: 'abC'