EN
JavaScript - One-time Pad encryption with XOR
9 points
In this short article, we would like to show a simple JavaScript implementation of the most save encrytion that was invented by humans - One-time Pad encryption with XOR.
Used XOR formula:
xxxxxxxxxx
1
Encryption:
2
3
00110100 input byte
4
XOR 11000111 secret key
5
--------
6
11110011 encrypted byte
7
8
Decription:
9
10
11110010 encrypted byte
11
XOR 11000111 secret key
12
--------
13
11110011 decrypted byte == input byte
Quick solution:
1. single byte encryption
xxxxxxxxxx
1
const inputByte = 97;
2
const secretKey = 238; // random byte used as secret key
3
4
const encryptedByte = inputByte ^ secretKey; // Encryption
5
const decryptedByte = encryptedByte ^ secretKey; // Decription
6
7
console.log(inputByte); // 97
8
console.log(encryptedByte); // 143
9
console.log(decryptedByte); // 97
2. multiple bytes encryption
xxxxxxxxxx
1
// Logic:
2
3
const encryptBytes = (secretKeys, inputBytes) => {
4
const encryptedBytes = Array(inputBytes.length);
5
for (let i = 0; i < inputBytes.length; ++i) {
6
encryptedBytes[i] = inputBytes[i] ^ secretKeys[i];
7
}
8
return encryptedBytes;
9
};
10
11
const decryptBytes = (secretKeys, encryptedBytes) => {
12
const decryptedBytes = Array(encryptedBytes.length);
13
for (let i = 0; i < encryptedBytes.length; ++i) {
14
decryptedBytes[i] = encryptedBytes[i] ^ secretKeys[i];
15
}
16
return decryptedBytes;
17
};
18
19
// Input:
20
21
const inputBytes = [97, 98, 99]; // what is 'abc' when we use UTF-8 bytes
22
const secretKeys = [238, 203, 230]; // 3 random bytes used as secret keys
23
24
// Encryption / Decryption:
25
26
const encryptedBytes = encryptBytes(secretKeys, inputBytes);
27
const decryptedBytes = decryptBytes(secretKeys, encryptedBytes);
28
29
// Result:
30
31
console.log(inputBytes); // [97, 98, 99]
32
console.log(encryptedBytes); // [143, 169, 133]
33
console.log(decryptedBytes); // [97, 98, 99]
The algorithm is as strong as perfectly random numbers have been used as secret keys.
The main concept of the algorithm is to:
- use XOR formula on the data units to encode and decode,
Hint: check Wikipedia reference to see other than XOR encryption formula.
- store on sender and recipient devices, secret keys composed of perfect random numbers
(the numbers from computer algorithms may be predictable, so use nature-based approaches), - never share the random numbers with others than the sender and the recipient,
- use always only part of secret keys to encrypt or decrypt some sent message (one byte encoded by one secret key),
- never use 2 times the same secret keys.
This implementation provides a cipher that stores information about lastly used keys, preventing against breaking rule 5 (never use 2 times the same secret key).
xxxxxxxxxx
1
// One-time Pad encryption with XOR
2
3
const Cipher = (secretKeys) => {
4
const createScope = () => {
5
let secretOffset = 0;
6
const execute = (inputBytes) => {
7
if (secretOffset + inputBytes.length > secretKeys.length) {
8
throw new Error('There is not enought secret keys to encode / decode bytes.');
9
}
10
const outputBytes = Array(inputBytes.length);
11
for (let i = 0; i < inputBytes.length; i += 1, secretOffset += 1) {
12
outputBytes[i] = secretKeys[secretOffset] ^ inputBytes[i];
13
}
14
return outputBytes;
15
};
16
return execute;
17
};
18
return {
19
encrypt: createScope(),
20
decrypt: createScope() // to decrypt we use same formula like in the encryption case
21
};
22
};
23
24
25
// Usage example:
26
27
// common - the information that know both (sender and recipient)
28
29
// in our case we use random bytes - be sure that the values are from 0 to 255
30
const secretKeys = [238, 203, 230, 91, 223, 161, 59, 10, 105, 200, 45, 145, 64, 145, 210]; // random numbers sequence used as secret key
31
32
33
// sender
34
35
const senderCipher = Cipher(secretKeys);
36
37
const encryptedBytes1 = senderCipher.encrypt([97, 98, 99]); // what is 'abc' as UTF-8 bytes
38
const encryptedBytes2 = senderCipher.encrypt([49, 50, 51]); // what is '123' as UTF-8 bytes
39
const encryptedBytes3 = senderCipher.encrypt([97, 98, 99]); // what is 'abc' as UTF-8 bytes
40
41
console.log(`Encrypted 1: ${encryptedBytes1}`); // Encrypted 1: [143, 169, 133]
42
console.log(`Encrypted 2: ${encryptedBytes2}`); // Encrypted 2: [106, 237, 146]
43
console.log(`Encrypted 3: ${encryptedBytes3}`); // Encrypted 3: [90, 104, 10]
44
45
46
// recipient
47
48
const recipientCipher = Cipher(secretKeys);
49
50
const decryptedBytes1 = recipientCipher.decrypt(encryptedBytes1);
51
const decryptedBytes2 = recipientCipher.decrypt(encryptedBytes2);
52
const decryptedBytes3 = recipientCipher.decrypt(encryptedBytes3);
53
54
console.log(`Decrypted 1: ${decryptedBytes1}`); // Decrypted 1: [97, 98, 99]
55
console.log(`Decrypted 2: ${decryptedBytes2}`); // Decrypted 2: [49, 50, 51]
56
console.log(`Decrypted 3: ${decryptedBytes3}`); // Decrypted 3: [97, 98, 99]
Conclusions:
[97,98,99]
encrypted 2 times returned 2 different results:[143,169,133]
and[90,104,10]
- it is provided by once time secret key usage composed of random numbers.
xxxxxxxxxx
1
const maskBytes = (offset, key, bytes) => {
2
const result = Array(bytes.length);
3
for (let i = 0; i < bytes.length; ++i) {
4
result[i] = key[offset + i] ^ bytes[i];
5
}
6
return result;
7
};
8
9
const Cipher = (secret) => {
10
let offset = 0;
11
const execute = (bytes) => {
12
if (offset + bytes.length > secretSequence.length) {
13
throw new Error('There is not enought numbers in the secret sequence to encode / decode bytes.');
14
}
15
const result = maskBytes(offset, secret, bytes);
16
offset += result.length;
17
return result;
18
};
19
return {
20
encrypt: execute,
21
decrypt: execute
22
};
23
};