Last active
December 28, 2019 17:03
-
-
Save nealfennimore/b2c4a77a93b7a841b338deba195cf16e to your computer and use it in GitHub Desktop.
XOR encryption and decryption
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Convert character string to binary | |
* | |
* @param {String} str Character string | |
* @returns Binary String | |
*/ | |
function toBinary(str) { | |
let binary = ''; | |
for (let i = 0, l = str.length; i < l; i++) { | |
binary += str.codePointAt(i).toString(2).padStart(8, '0'); | |
} | |
return binary; | |
} | |
console.assert( | |
toBinary('a') === '01100001' | |
); | |
console.assert( | |
toBinary('abc') === '011000010110001001100011' | |
); | |
/** | |
* Convert binary string to character string | |
* | |
* @param {String} binary Binary String | |
* @returns Character String | |
*/ | |
function toText(binary){ | |
let str = ''; | |
for (let i = 0, l = binary.length / 8; i < l; i++) { | |
const start = i * 8; | |
const byte = binary.slice(start, start + 8); | |
const codePoint = parseInt(byte, 2); | |
str += String.fromCodePoint(codePoint); | |
} | |
return str; | |
} | |
console.assert( | |
toText('01100001') === 'a' | |
); | |
console.assert( | |
toText('011000010110001001100011') === 'abc' | |
); | |
/** | |
* Perform exclusive OR operation | |
* | |
* @param {Number|String} a | |
* @param {Number|String} b | |
* @returns {Number} 0 or 1 | |
*/ | |
function xor(a, b) { | |
return +(a !== b); | |
} | |
console.assert( | |
xor(1, 0) === 1 | |
); | |
console.assert( | |
xor(0, 1) === 1 | |
); | |
console.assert( | |
xor(1, 1) === 0 | |
); | |
console.assert( | |
xor(0, 0) === 0 | |
); | |
/** | |
* Perform XOR operations on two strings | |
* | |
* @param {String} key Key to XOR | |
* @param {String} text Text to XOR | |
* @returns {String} XOR'd string | |
*/ | |
function xorStrings(key, text){ | |
const keyBin = toBinary(key); | |
const keyLength = keyBin.length; | |
const textBin = toBinary(text); | |
const textLength = textBin.length; | |
let xorText = ''; | |
for (let i = 0; i < textLength; i++) { | |
const ctElement = textBin[i]; | |
const keyElement = keyBin[i % keyLength]; | |
xorText += xor(ctElement, keyElement).toString(); | |
} | |
return xorText; | |
} | |
console.assert( | |
xorStrings('a', 'b') === '00000011' | |
); | |
console.assert( | |
xorStrings('b', 'a') === '00000011' | |
); | |
console.assert( | |
xorStrings('abc', 'cba') === '000000100000000000000010' | |
); | |
/** | |
* Encrypt text using key | |
* | |
* @param {String} key | |
* @param {String} clearText | |
* @returns {String} Encrypted text | |
*/ | |
function encrypt(key, clearText){ | |
return toText( xorStrings( key, clearText ) ); | |
} | |
console.assert( | |
encrypt('a', 'bc') === '' | |
); | |
/** | |
* Decrypt encrypted text using key | |
* | |
* @param {String} key | |
* @param {String} cipherText | |
* @returns {String} Decrypted text | |
*/ | |
function decrypt(key, cipherText) { | |
return toText( xorStrings(key, cipherText) ); | |
} | |
console.assert( | |
decrypt( 'key', encrypt( 'key', 'abc' ) ) === 'abc' | |
); | |
console.assert( | |
decrypt('whatever', encrypt('whatever', 'what is this sentence huh')) === 'what is this sentence huh' | |
); | |
console.assert( | |
decrypt('abc', encrypt('abc', 'cba')) === 'cba' | |
); | |
console.assert( | |
decrypt('wrong-key', encrypt('whatever', 'I should not work')) !== 'I should not work' | |
); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment