initial chacha20 code;
This commit is contained in:
120
contrib/js/nntpchan/chacha20.js
Normal file
120
contrib/js/nntpchan/chacha20.js
Normal file
@@ -0,0 +1,120 @@
|
||||
/* chacha20 - 256 bits */
|
||||
|
||||
// Written in 2014 by Devi Mandiri. Public domain.
|
||||
//
|
||||
// Implementation derived from chacha-ref.c version 20080118
|
||||
// See for details: http://cr.yp.to/chacha/chacha-20080128.pdf
|
||||
|
||||
function U8TO32_LE(x, i) {
|
||||
if(x === undefined) return;
|
||||
return x[i] | (x[i+1]<<8) | (x[i+2]<<16) | (x[i+3]<<24);
|
||||
}
|
||||
|
||||
function U32TO8_LE(x, i, u) {
|
||||
x[i] = u; u >>>= 8;
|
||||
x[i+1] = u; u >>>= 8;
|
||||
x[i+2] = u; u >>>= 8;
|
||||
x[i+3] = u;
|
||||
}
|
||||
|
||||
function ROTATE(v, c) {
|
||||
return (v << c) | (v >>> (32 - c));
|
||||
}
|
||||
|
||||
function Chacha20(key, nonce, counter) {
|
||||
this.input = new Uint32Array(16);
|
||||
|
||||
// https://tools.ietf.org/html/draft-irtf-cfrg-chacha20-poly1305-01#section-2.3
|
||||
this.input[0] = 1634760805;
|
||||
this.input[1] = 857760878;
|
||||
this.input[2] = 2036477234;
|
||||
this.input[3] = 1797285236;
|
||||
this.input[4] = U8TO32_LE(key, 0);
|
||||
this.input[5] = U8TO32_LE(key, 4);
|
||||
this.input[6] = U8TO32_LE(key, 8);
|
||||
this.input[7] = U8TO32_LE(key, 12);
|
||||
this.input[8] = U8TO32_LE(key, 16);
|
||||
this.input[9] = U8TO32_LE(key, 20);
|
||||
this.input[10] = U8TO32_LE(key, 24);
|
||||
this.input[11] = U8TO32_LE(key, 28);
|
||||
// be compatible with the reference ChaCha depending on the nonce size
|
||||
if(nonce.length == 12)
|
||||
{
|
||||
this.input[12] = counter;
|
||||
this.input[13] = U8TO32_LE(nonce, 0);
|
||||
this.input[14] = U8TO32_LE(nonce, 4);
|
||||
this.input[15] = U8TO32_LE(nonce, 8);
|
||||
}else{
|
||||
this.input[12] = counter;
|
||||
this.input[13] = 0;
|
||||
this.input[14] = U8TO32_LE(nonce, 0);
|
||||
this.input[15] = U8TO32_LE(nonce, 4);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
Chacha20.prototype.quarterRound = function(x, a, b, c, d) {
|
||||
x[a] += x[b]; x[d] = ROTATE(x[d] ^ x[a], 16);
|
||||
x[c] += x[d]; x[b] = ROTATE(x[b] ^ x[c], 12);
|
||||
x[a] += x[b]; x[d] = ROTATE(x[d] ^ x[a], 8);
|
||||
x[c] += x[d]; x[b] = ROTATE(x[b] ^ x[c], 7);
|
||||
};
|
||||
|
||||
Chacha20.prototype.encrypt = function(dst, src, len) {
|
||||
var x = new Uint32Array(16);
|
||||
var output = new Uint8Array(64);
|
||||
var i, dpos = 0, spos = 0;
|
||||
|
||||
while (len > 0 ) {
|
||||
for (i = 16; i--;) x[i] = this.input[i];
|
||||
for (i = 20; i > 0; i -= 2) {
|
||||
this.quarterRound(x, 0, 4, 8,12);
|
||||
this.quarterRound(x, 1, 5, 9,13);
|
||||
this.quarterRound(x, 2, 6,10,14);
|
||||
this.quarterRound(x, 3, 7,11,15);
|
||||
this.quarterRound(x, 0, 5,10,15);
|
||||
this.quarterRound(x, 1, 6,11,12);
|
||||
this.quarterRound(x, 2, 7, 8,13);
|
||||
this.quarterRound(x, 3, 4, 9,14);
|
||||
}
|
||||
for (i = 16; i--;) x[i] += this.input[i];
|
||||
for (i = 16; i--;) U32TO8_LE(output, 4*i, x[i]);
|
||||
|
||||
this.input[12] += 1;
|
||||
if (!this.input[12]) {
|
||||
this.input[13] += 1;
|
||||
}
|
||||
if (len <= 64) {
|
||||
for (i = len; i--;) {
|
||||
dst[i+dpos] = src[i+spos] ^ output[i];
|
||||
}
|
||||
return;
|
||||
}
|
||||
for (i = 64; i--;) {
|
||||
dst[i+dpos] = src[i+spos] ^ output[i];
|
||||
}
|
||||
len -= 64;
|
||||
spos += 64;
|
||||
dpos += 64;
|
||||
}
|
||||
};
|
||||
|
||||
Chacha20.prototype.keystream = function(dst, len) {
|
||||
for (var i = 0; i < len; ++i) dst[i] = 0;
|
||||
this.encrypt(dst, dst, len);
|
||||
};
|
||||
|
||||
var Cipher = Chacha20;
|
||||
|
||||
var chacha_encrypt;
|
||||
var chacha_decrypt;
|
||||
|
||||
chacha_decrypt = function(key, nonce, data)
|
||||
{
|
||||
var cipher = new Chacha20(key, nonce, 0);
|
||||
var ret = new Uint8Array(data.length);
|
||||
cipher.encrypt(ret, data, data.length);
|
||||
return ret;
|
||||
};
|
||||
|
||||
chacha_encrypt = chacha_decrypt;
|
68
contrib/js/nntpchan/crypto.js
Normal file
68
contrib/js/nntpchan/crypto.js
Normal file
@@ -0,0 +1,68 @@
|
||||
|
||||
var nntpchan_ToBase64 = function (u8) {
|
||||
return btoa(String.fromCharCode.apply(null, u8));
|
||||
};
|
||||
|
||||
var nntpchan_FromBase64 = function (str) {
|
||||
return atob(str).split('').map(function (c) { return c.charCodeAt(0); });
|
||||
};
|
||||
|
||||
|
||||
function nntpchan_keygen() {
|
||||
var crypto = window.crypto || window.msCrypto;
|
||||
if(!crypto) {
|
||||
throw "no crypto";
|
||||
}
|
||||
var key = new Uint8Array(32);
|
||||
crypto.getRandomValues(key);
|
||||
var nonce = new Uint8Array(12);
|
||||
crypto.getRandomValues(nonce);
|
||||
return nntpchan_ToBase64(key) + ":" + nntpchan_ToBase64(nonce);
|
||||
}
|
||||
|
||||
function nntpchan_chacha_nonce(blob) {
|
||||
var parts = blob.split(":");
|
||||
return nntpchan_FromBase64(parts[1]);
|
||||
}
|
||||
|
||||
function nntpchan_chacha_key(blob) {
|
||||
var parts = blob.split(":");
|
||||
return nntpchan_FromBase64(parts[0]);
|
||||
}
|
||||
|
||||
// encrypt text from an element using symettric key and nonce
|
||||
// output to element.innerHTML as base64
|
||||
function nntpchan_encrypt_element(inelem, outelem, key, nonce) {
|
||||
var plaintext = inelem.innerHTML;
|
||||
console.log(plaintext);
|
||||
var ciphertext = chacha_encrypt(key, nonce, plaintext);
|
||||
outelem.innerHTML = nntpchan_ToBase64(ciphertext);
|
||||
}
|
||||
|
||||
// encrypt text from an element using symettric key and nonce
|
||||
// output to element.innerHTML as base64
|
||||
function nntpchan_decrypt_element(inelem, outelem, key, nonce) {
|
||||
var ciphertext = nntpchan_FromBase64(inelem.innerHTML);
|
||||
console.log(ciphertext);
|
||||
var plaintext = chacha_decrypt(key, nonce, ciphertext);
|
||||
console.log(plaintext);
|
||||
while(outelem.children.length > 0) {
|
||||
outelem.children[0].remove();
|
||||
}
|
||||
outelem.appendChild(document.createTextNode(plaintext));
|
||||
}
|
||||
|
||||
|
||||
|
||||
function nntpchan_crypto_test() {
|
||||
console.log("begin crypto test");
|
||||
var genelem = $("#test_keygen");
|
||||
genelem[0].innerHTML = nntpchan_keygen();
|
||||
var inelem = $("#encrypt_in")[0];
|
||||
var outelem = $("#encrypt_out")[0];
|
||||
var decryptelem = $("#decrypt_out")[0];
|
||||
var key = nntpchan_chacha_key(genelem[0].innerHTML);
|
||||
var nonce = nntpchan_chacha_nonce(genelem[0].innerHTML);
|
||||
nntpchan_encrypt_element(inelem, outelem, key, nonce);
|
||||
nntpchan_decrypt_element(outelem, decryptelem, key, nonce);
|
||||
}
|
Reference in New Issue
Block a user