// for use in future crypto/ctf challenge; probably hilariously insecure, but that's kinda the point
// callable like jQuery, e.g. Sha1StreamCipher('key_text').encrypt('super secret message').then((ct) => console.log(ct));
function Sha1StreamCipher (key) {
function init (key) {
async function getKeyStream (l) {
var keyBytes = [], hash;
// get first 20 bytes
hash = await crypto.subtle.digest('SHA-1', key);
keyBytes = keyBytes.slice.call(new Uint8Array(hash));
// get more until we have enough
while (keyBytes.length < l) {
hash = await crypto.subtle.digest('SHA-1', hash);
keyBytes = keyBytes.concat(keyBytes.slice.call(new Uint8Array(hash)));
}
return keyBytes;
}
this.encrypt = async function (plaintext) {
var keyBytes, ciphertext;
plaintext = typeof plaintext == 'string' ? toUint8(plaintext) : plaintext;
keyBytes = await getKeyStream(plaintext.length);
ciphertext = new Uint8Array(plaintext.length);
for (var i=0, il=plaintext.length; i<il; ++i) {
ciphertext[i] = plaintext[i] ^ keyBytes[i];
}
return toHex(ciphertext);
};
this.decrypt = async function (ciphertext) {
var keyBytes, plaintext;
ciphertext = isHex(ciphertext) ? fromHex(ciphertext) : typeof ciphertext == 'string' ? toUint8(ciphertext) : ciphertext;
keyBytes = await getKeyStream(ciphertext.length);
plaintext = new Uint8Array(ciphertext.length);
for (var i=0, il=ciphertext.length; i<il; ++i) {
plaintext[i] = ciphertext[i] ^ keyBytes[i];
}
return toText(plaintext);
};
this.getKeyBytes = async function (length) {
return await getKeyStream(length | 0);
};
function toUint8 (text) {
var arr = new Uint8Array(text.length);
for (var i=0, il=text.length; i<il; ++i) {
arr[i] = text.charCodeAt(i);
}
return arr;
}
function toText (arr) {
var text = '';
for (var i=0, il=arr.length; i<il; ++i) {
text += String.fromCharCode(arr[i]);
}
return text;
}
function fromHex (input) {
input = input.length % 2 ? '0' + input : input;
var output = new Uint8Array(input.length / 2);
for (var i=0, l=input.length; i<l; i+=2) {
output[i / 2] = parseInt(input[i] + input[i+1], 16);
}
return output;
}
function toHex (arr) {
arr = arr instanceof Uint8Array ? arr : toUint8(arr);
var text = '', char = '';
for (var i=0, il=arr.length; i<il; ++i) {
char = arr[i].toString(16);
text += char.length == 2 ? char : '0' + char;
}
return text;
}
function isHex (str) {
return (/^[a-fA-F0-9]+$/).test(str);
}
key = toUint8(key);
};
return new init(key);
}
Comments