Skip to content

Instantly share code, notes, and snippets.

@rajasharan
Last active July 29, 2017 14:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rajasharan/efc547583174eed2c1f9c86cec5bbabd to your computer and use it in GitHub Desktop.
Save rajasharan/efc547583174eed2c1f9c86cec5bbabd to your computer and use it in GitHub Desktop.
bit level manipulation in javascript
const R = require('ramda');
/*
* https://cryptopals.com/sets/1/challenges/1
*/
const HEX_DIGITS = [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F" ];
const HEX_TO_BINARY_MAP = {
"0": "0000",
"1": "0001",
"2": "0010",
"3": "0011",
"4": "0100",
"5": "0101",
"6": "0110",
"7": "0111",
"8": "1000",
"9": "1001",
"A": "1010",
"B": "1011",
"C": "1100",
"D": "1101",
"E": "1110",
"F": "1111",
"a": "1010",
"b": "1011",
"c": "1100",
"d": "1101",
"e": "1110",
"f": "1111"
};
const BASE64_DIGITS = [
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "+", "/"
];
var binary = hex => HEX_TO_BINARY_MAP[hex];
var base64 = decimal => BASE64_DIGITS[decimal];
var hex = decimal => HEX_DIGITS[decimal];
var decimal = binary => {
let binaryDigits = R.compose(
R.map(parseInt),
R.split('')
)(binary);
let binaryMultiplier = R.compose(
R.reverse,
R.map(x => Math.pow(2, x)),
R.range(0),
R.length
)(binaryDigits);
let zippedArray = R.zipWith(R.multiply)(binaryDigits)(binaryMultiplier);
return R.sum(zippedArray);
};
var hexToBinary = R.compose(
R.join(''),
R.map(binary),
R.split('')
);
var binaryToBase64 = R.compose(
R.join(''),
R.map(base64),
R.map(decimal),
R.splitEvery(6)
);
var hexToBase64 = R.compose(
binaryToBase64,
hexToBinary
);
console.log(hexToBase64('49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d'));
//-> SSdtIGtpbGxpbmcgeW91ciBicmFpbiBsaWtlIGEgcG9pc29ub3VzIG11c2hyb29t
/*
* https://cryptopals.com/sets/1/challenges/2
*/
var binaryToHex = R.compose(
R.join(''),
R.map(hex),
R.map(decimal),
R.splitEvery(4)
);
var xor = (hex1, hex2) => R.compose(
binaryToHex,
R.join(''),
R.map(x => x? 0 : 1),
R.zipWith(R.equals, R.split('', hexToBinary(hex1))),
R.split('')
)(hexToBinary(hex2));
console.log(xor('1c0111001f010100061a024b53535009181c', '686974207468652062756c6c277320657965'));
//-> 746865206b696420646f6e277420706c6179
/*
* https://cryptopals.com/sets/1/challenges/3
*/
/* 32 to 126 */
const ASCII_CHARS = [
" ", "!", '"', "#", "$", "%", "%", "'", "(", ")", "*", "+", ",", "-", ".", "/",
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ";", "<", "=", ">", "?", "@",
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
"[", "\\", "]", "^", "_", "`",
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
"{", "|", "}", "~"
];
var asciiDecimal = char => R.ifElse(R.equals('\n'), () => 10, () => R.indexOf(char, ASCII_CHARS) + 32)(char);
var binary10 = decimal => {
let _binary10 = (decimal, result) => {
let quotient = Math.floor(decimal/2);
let reminder = R.modulo(decimal, 2);
result = R.append(reminder, result);
if (R.equals(0, quotient)) {
return result;
}
else {
return _binary10(quotient, result);
}
};
let binList = _binary10(decimal, []);
let binLen = R.length(binList);
let zeroList = R.repeat(0, 8 - binLen);
return R.pipe(R.concat, R.reverse, R.join(''))(binList, zeroList);
};
var ascii = binary => R.pipe(R.splitEvery(8), R.map(decimal), R.map(dec => ASCII_CHARS[dec - 32]), R.join(''))(binary);
var xor2 = (bin1, bin2) => R.compose(
R.join(''),
R.map(x => x? 0 : 1),
R.zipWith(R.equals, R.split('', bin1)),
R.split('')
)(bin2);
var repeatingKeyXor = (binaryStr, chars) => {
let byteCount = R.length(binaryStr) / 8;
let decimals = R.map(asciiDecimal)(chars);
let bytes = R.pipe(R.map(binary10), R.join(''))(decimals);
let byteStr = R.compose(R.join(''), R.flatten, R.repeat)(bytes, byteCount);
let xorBinary = xor2(binaryStr, byteStr);
return xorBinary;
};
var frequencyDistribution = str => R.pipe(R.split(''), R.groupBy(a => a), R.map(v => R.length(v)))(str);
const BASE_SCORES = {
"E": 20, "T": 19, "A": 18, "O": 17, "I": 16, "N": 15, " ": 14, "S": 13, "H": 12, "R": 11, "D": 10, "L": 7, "U": 8,
"e": 20, "t": 19, "a": 18, "o": 17, "i": 16, "n": 15, " ": 14, "s": 13, "h": 12, "r": 11, "d": 10, "l": 7, "u": 8
};
var _score = (val, key) => {
let baseScore = BASE_SCORES[key];
let score = R.isNil(baseScore)? 1 : val * baseScore;
return score;
};
var score = str => R.pipe(frequencyDistribution, R.mapObjIndexed(_score), R.values, R.sum)(str);
const ENCRYPTED_TEXT = '1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736';
var decryptObjs = encrptedText => R.map(char => {
let obj = {};
obj[char] = R.compose(ascii, repeatingKeyXor)(hexToBinary(encrptedText), [char]);
obj.score = R.compose(score, ascii, repeatingKeyXor)(hexToBinary(encrptedText), [char]);
return obj;
})(ASCII_CHARS);
var decryptObj = encrptedText => R.pipe(decryptObjs, R.sortBy(R.prop('score')), R.reverse)(encrptedText)[0];
console.log(decryptObj(ENCRYPTED_TEXT));
//-> { X: "Cooking MC's like a pound of bacon", score: 349 }
/*
* https://cryptopals.com/sets/1/challenges/4
*
const fs = require('fs');
fs.readFile('4.txt', { encoding:'utf8' }, (err, data) => {
let lines = R.split('\n', data);
let result = R.pipe(R.map(decryptObj), R.sortBy(R.prop('score')), R.reverse)(lines)[0];
console.log(result);
//-> { '5': 'Now that the party is jumping', score: 343 }
});
*
*/
/*
* https://cryptopals.com/sets/1/challenges/5
*/
const REPEATING_KEY = "ICE";
const ENG_MSG = "Burning 'em, if you ain't quick and nimble\nI go crazy when I hear a cymbal";
var binaryStr = ascii => R.pipe(R.split(''), R.map(asciiDecimal), R.map(binary10), R.join(''))(ascii);
var result = R.compose(
binaryToHex,
repeatingKeyXor
)(binaryStr(ENG_MSG), R.split('', REPEATING_KEY));
console.log(R.pipe(R.splitEvery(74), R.join('\n'))(result));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment