EN
JavaScript - One-time Pad encryption with XOR on strings
9 points
In this short article, we would like to show a simple JavaScript implementation of the most save encryption that was invented by humans - One-time Pad encryption with XOR on strings.
Encryption example:
xxxxxxxxxx
1
Used secret keys (one key per one byte):
2
3
[238, 203, 230, 91, 223, 161, 59, 10, 105, 200, 45, 145, 64, 145, 210]
4
5
6
Input string --> Encrypted string bytes --> Decrypted string
7
8
abc --> [143, 169, 133] --> abc
9
123 --> [106, 237, 146] --> 123
10
abc --> [90, 104, 10] --> abc
In this section you can find example One-time Pad strings encryption. In the example we encode strings to UTF-8 bytes. To show the main idea we encoded 3 strings: abc
, 123
and abc
again - as we can see encoded text is always different that makes algorithm stronger.
Hint: the below algorithm source code extends this article - adds posibility to encrypt and decrypt strings.
The algorithm is as strong as perfectly random numbers have been used as secret keys.
xxxxxxxxxx
1
// Converts string to UTF-8 bytes.
2
// Source: https://dirask.com/posts/JavaScript-convert-string-to-bytes-array-1XkbEj
3
//
4
const toBytes = (text) => {
5
const surrogate = encodeURIComponent(text);
6
const result = [];
7
for (let i = 0; i < surrogate.length;) {
8
const character = surrogate[i];
9
i += 1;
10
if (character == '%') {
11
const hex = surrogate.substring(i, i += 2);
12
if (hex) {
13
result.push(parseInt(hex, 16));
14
}
15
} else {
16
result.push(character.charCodeAt(0));
17
}
18
}
19
return result;
20
};
21
22
// Converts UTF-8 bytes to string.
23
// Source: https://dirask.com/posts/JavaScript-convert-bytes-array-to-string-Dn0e7j
24
//
25
const toString = (bytes) => {
26
var result = '';
27
for (var i = 0; i < bytes.length; ++i) {
28
const byte = bytes[i];
29
const text = byte.toString(16);
30
result += (byte < 16 ? '%0' : '%') + text;
31
}
32
return decodeURIComponent(result);
33
};
34
35
// Provides simple implementation of One-time Pad encryption with XOR.
36
// Source: https://dirask.com/posts/JavaScript-One-time-Pad-encryption-with-XOR-DlKdw1
37
//
38
const BytesCipher = (secretKeys) => {
39
const createScope = () => {
40
let secretOffset = 0;
41
const execute = (inputBytes) => {
42
if (secretOffset + inputBytes.length > secretKeys.length) {
43
throw new Error('There is not enought secret keys to encode / decode bytes.');
44
}
45
const outputBytes = Array(inputBytes.length);
46
for (let i = 0; i < inputBytes.length; i += 1, secretOffset += 1) {
47
outputBytes[i] = secretKeys[secretOffset] ^ inputBytes[i];
48
}
49
return outputBytes;
50
};
51
return execute;
52
};
53
return {
54
encrypt: createScope(),
55
decrypt: createScope() // to decrypt we use same formula like in the encryption case
56
};
57
};
58
59
// Provides simple implementation of One-time Pad encryption with XOR on strings.
60
//
61
const StringsCipher = (secretKeys) => {
62
const cipher = BytesCipher(secretKeys);
63
return {
64
encrypt: (inputString) => {
65
const inputBytes = toBytes(inputString);
66
return cipher.encrypt(inputBytes);
67
},
68
decrypt: (inputBytes) => {
69
const outputBytes = cipher.decrypt(inputBytes);
70
return toString(outputBytes);
71
}
72
};
73
};
74
75
76
// Usage example:
77
78
// common - the information that know both (sender and recipient)
79
80
// in our case we use random bytes - be sure that the values are from 0 to 255
81
const secretKeys = [238, 203, 230, 91, 223, 161, 59, 10, 105, 200, 45, 145, 64, 145, 210]; // random numbers sequence used as secret key
82
83
84
// sender
85
86
const senderCipher = StringsCipher(secretKeys);
87
88
const encryptedBytes1 = senderCipher.encrypt('abc');
89
const encryptedBytes2 = senderCipher.encrypt('123');
90
const encryptedBytes3 = senderCipher.encrypt('abc');
91
92
console.log(`Encrypted 1: ${encryptedBytes1}`); // Encrypted 1: [143, 169, 133]
93
console.log(`Encrypted 2: ${encryptedBytes2}`); // Encrypted 2: [106, 237, 146]
94
console.log(`Encrypted 3: ${encryptedBytes3}`); // Encrypted 3: [90, 104, 10]
95
96
97
// recipient
98
99
const recipientCipher = StringsCipher(secretKeys);
100
101
const decryptedBytes1 = recipientCipher.decrypt(encryptedBytes1);
102
const decryptedBytes2 = recipientCipher.decrypt(encryptedBytes2);
103
const decryptedBytes3 = recipientCipher.decrypt(encryptedBytes3);
104
105
console.log(`Decrypted 1: ${decryptedBytes1}`); // Decrypted 1: abc
106
console.log(`Decrypted 2: ${decryptedBytes2}`); // Decrypted 2: 123
107
console.log(`Decrypted 3: ${decryptedBytes3}`); // Decrypted 3: abc
Conclusions:
abc
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.