k98kurz icon

Sha1StreamCipher.js

k98kurz | PRO | 07/14/21 11:04:10 PM UTC (Edited) | 0 ⭐ | 505 👁️ | Never ⏰ | []
JavaScript |

3.03 KB

|

None

|

0 👍

/

0 👎

// for use in future crypto/ctf challenge; probably hilariously insecure, but that's kinda the point
// usage example: var ssc = new Sha1StreamCipher('key_text');
// ssc.encrypt('super secret message').then((ct) => {console.log(ct); ssc.decrypt(ct).then((pt) => console.log(pt))});
 
function Sha1StreamCipher (key) {
    // main stuff
    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);
    };
 
    // other guff
    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);
    }
 
    // also do this
    key = toUint8(key);
}

Comments