xchacha20-js
Version:
Javascript implementations of ChaCha20, HChaCha20, and XChaCha20
211 lines (185 loc) • 10.4 kB
JavaScript
const expect = require('chai').expect;
const Util = require('../lib/util');
const ChaCha20 = require('../lib/chacha20');
const HChaCha20 = require('../lib/hchacha20');
const XChaCha20 = require('../lib/xchacha20');
let c = new ChaCha20();
let h = new HChaCha20();
let x = new XChaCha20();
describe('Test Vectors', function () {
it('ChaCha20 Addition', function () {
expect(0).to.be.equal(c.add(0xffffffff, 1));
expect(0xffffffff).to.be.equal(c.add(0xfffffffe, 1));
expect(0x80000000).to.be.equal(c.add(0x7fffffff, 1));
});
it('ChaCha20 Rotation', function () {
let rot = ChaCha20.rotate(parseInt('ffff0000', 16), 16);
expect('ffff').to.be.equal(rot.toString(16));
rot = ChaCha20.rotate(parseInt('ffff0000', 16), 32);
expect('ffff0000').to.be.equal(rot.toString(16));
rot = ChaCha20.rotate(parseInt('ffff0000', 16), 24);
expect('ffff00').to.be.equal(rot.toString(16));
rot = ChaCha20.rotate(parseInt('ffff0000', 16), 8);
expect('ff0000ff').to.be.equal(rot.toString(16));
rot = ChaCha20.rotate(parseInt('ffff0000', 16), 15);
expect('80007fff').to.be.equal(rot.toString(16));
rot = ChaCha20.rotate(parseInt('ffff0000', 16), 14);
expect('c0003fff').to.be.equal(rot.toString(16));
});
it('ChaCha20 XOR', function () {
expect(255).to.be.equal(c.xor(0, 255));
expect(0).to.be.equal(c.xor(255, 255));
expect(1).to.be.equal(c.xor(255, 254));
expect(2).to.be.equal(c.xor(255, 253));
expect(3).to.be.equal(c.xor(255, 252));
expect(4).to.be.equal(c.xor(255, 251));
expect(33).to.be.equal(c.xor(100, 69));
});
it('ChaCha20 Quarter Round Function', function () {
let key = Buffer.from('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f', 'hex');
let nonce = Buffer.from('000000090000004a0000000031415927', 'hex');
let ctx = h.createHCtx(key, nonce);
let x0 = ctx.readInt32BE(0) >>> 0;
let x4 = ctx.readInt32BE((4 << 2)) >>> 0;
let x8 = ctx.readInt32BE((8 << 2)) >>> 0;
let x12 = ctx.readInt32BE((12 << 2)) >>> 0;
expect('61707865').to.be.equal(x0.toString(16));
expect('3020100').to.be.equal(x4.toString(16));
expect('13121110').to.be.equal(x8.toString(16));
expect('9000000').to.be.equal(x12.toString(16));
x0 = parseInt('61707865', 16);
x4 = 128;
x8 = 0;
x12 = 0;
let output = ChaCha20.quarterRound(x0, x4, x8, x12);
expect('b78f8073').to.be.equal(output[0].toString(16));
expect('ecb158da').to.be.equal(output[1].toString(16));
expect('e3c6653f').to.be.equal(output[2].toString(16));
expect('6ae103cf').to.be.equal(output[3].toString(16));
});
it('HChaCha20', async function () {
let key = Buffer.from('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f', 'hex');
let nonce = Buffer.from('000000090000004a0000000031415927', 'hex');
expect(
'617078653320646e79622d326b20657403020100070605040b0a09080f0e0d0c13121110171615141b1a19181f1e1d1c090000004a0000000000000027594131'
).to.be.equal(
h.createHCtx(key, nonce).toString('hex')
);
expect(
'82413b4227b27bfed30e42508a877d73a0f9e4d58a74a853c12ec41326d3ecdc'
).to.be.equal(
(await h.hChaCha20Bytes(nonce, key)).toString('hex')
);
});
it('ChaCha20 -- test vectors (RFC 7539)', async function () {
let key = Buffer.alloc(32, 0);
let nonce = Buffer.alloc(12, 0);
let message;
expect(
(await c.ietfStream(64, nonce, key)).toString('hex')
).to.be.equal(
'76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7' +
'da41597c5157488d7724e03fb8d84a376a43b8f41518a11cc387b669b2ee6586'
);
expect(
(await c.ietfStreamIc(64, nonce, key, 1)).toString('hex')
).to.be.equal(
'9f07e7be5551387a98ba977c732d080dcb0f29a048e3656912c6533e32ee7aed' +
'29b721769ce64e43d57133b074d839d531ed1f28510afb45ace10a1f4b794d6f'
);
key = Buffer.from('0000000000000000000000000000000000000000000000000000000000000001', 'hex');
expect(
(await c.ietfStreamIc(64, nonce, key, 1)).toString('hex')
).to.be.equal(
'3aeb5224ecf849929b9d828db1ced4dd832025e8018b8160b82284f3c949aa5a' +
'8eca00bbb4a73bdad192b5c42f73f2fd4e273644c8b36125a64addeb006c13a0'
);
key = Buffer.alloc(32, 0);
nonce = Buffer.alloc(12, 0);
message = Buffer.alloc(128, 0);
expect(
(await c.ietfStreamXorIc(message, nonce, key, 0)).toString('hex')
).to.be.equal(
'76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7' +
'da41597c5157488d7724e03fb8d84a376a43b8f41518a11cc387b669b2ee6586' +
'9f07e7be5551387a98ba977c732d080dcb0f29a048e3656912c6533e32ee7aed' +
'29b721769ce64e43d57133b074d839d531ed1f28510afb45ace10a1f4b794d6f'
);
// A.2. ChaCha20 Encryption Test Vector #2:
key = Buffer.from('0000000000000000000000000000000000000000000000000000000000000001', 'hex');
nonce = Buffer.from('000000000000000000000002', 'hex');
message = Buffer.from(
'416e79207375626d697373696f6e20746f20746865204945544620696e74656e' +
'6465642062792074686520436f6e7472696275746f7220666f72207075626c69' +
'636174696f6e20617320616c6c206f722070617274206f6620616e2049455446' +
'20496e7465726e65742d4472616674206f722052464320616e6420616e792073' +
'746174656d656e74206d6164652077697468696e2074686520636f6e74657874' +
'206f6620616e204945544620616374697669747920697320636f6e7369646572' +
'656420616e20224945544620436f6e747269627574696f6e222e205375636820' +
'73746174656d656e747320696e636c756465206f72616c2073746174656d656e' +
'747320696e20494554462073657373696f6e732c2061732077656c6c20617320' +
'7772697474656e20616e6420656c656374726f6e696320636f6d6d756e696361' +
'74696f6e73206d61646520617420616e792074696d65206f7220706c6163652c' +
'207768696368206172652061646472657373656420746f',
'hex'
);
expect(
(await c.ietfStreamXorIc(message, nonce, key, 1)).toString('hex')
).to.be.equal(
'a3fbf07df3fa2fde4f376ca23e82737041605d9f4f4f57bd8cff2c1d4b7955ec' +
'2a97948bd3722915c8f3d337f7d370050e9e96d647b7c39f56e031ca5eb6250d' +
'4042e02785ececfa4b4bb5e8ead0440e20b6e8db09d881a7c6132f420e527950' +
'42bdfa7773d8a9051447b3291ce1411c680465552aa6c405b7764d5e87bea85a' +
'd00f8449ed8f72d0d662ab052691ca66424bc86d2df80ea41f43abf937d3259d' +
'c4b2d0dfb48a6c9139ddd7f76966e928e635553ba76c5c879d7b35d49eb2e62b' +
'0871cdac638939e25e8a1e0ef9d5280fa8ca328b351c3c765989cbcf3daa8b6c' +
'cc3aaf9f3979c92b3720fc88dc95ed84a1be059c6499b9fda236e7e818b04b0b' +
'c39c1e876b193bfe5569753f88128cc08aaa9b63d1a16f80ef2554d7189c411f' +
'5869ca52c5b83fa36ff216b9c1d30062bebcfd2dc5bce0911934fda79a86f6e6' +
'98ced759c3ff9b6477338f3da4f9cd8514ea9982ccafb341b2384dd902f3d1ab' +
'7ac61dd29c6f21ba5b862f3730e37cfdc4fd806c22f221'
);
// A.2. ChaCha20 Encryption Test Vector #3:
key = Buffer.from('1c9240a5eb55d38af333888604f6b5f0473917c1402b80099dca5cbc207075c0', 'hex');
nonce = Buffer.from('000000000000000000000002', 'hex');
message = Buffer.from(
'2754776173206272696c6c69672c20616e642074686520736c6974687920746f'+
'7665730a446964206779726520616e642067696d626c6520696e207468652077'+
'6162653a0a416c6c206d696d737920776572652074686520626f726f676f7665'+
'732c0a416e6420746865206d6f6d65207261746873206f757467726162652e',
'hex'
);
expect(
(await c.ietfStreamXorIc(message, nonce, key, 42)).toString('hex')
).to.be.equal(
'62e6347f95ed87a45ffae7426f27a1df5fb69110044c0d73118effa95b01e5cf'+
'166d3df2d721caf9b21e5fb14c616871fd84c54f9d65b283196c7fe4f60553eb'+
'f39c6402c42234e32a356b3e764312a61a5532055716ead6962568f87d3f3f77'+
'04c6a8d1bcd1bf4d50d6154b6da731b187b58dfd728afa36757a797ac188d1'
);
});
// https://datatracker.ietf.org/doc/draft-arciszewski-xchacha/
it('XChaCha20', async function () {
let key = Buffer.from('808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f', 'hex');
let nonce = Buffer.from('404142434445464748494a4b4c4d4e4f5051525354555658', 'hex');
let message = Buffer.from(
"The dhole (pronounced \"dole\") is also known as the Asiatic wild dog, red dog, and whistling dog. It" +
" is about the size of a German shepherd but looks more like a long-legged fox. This highly elusive and" +
" skilled jumper is classified with wolves, coyotes, jackals, and foxes in the taxonomic family Canidae."
);
expect(
(await x.encrypt(message, nonce, key, 1)).toString('hex')
).to.be.equal(
'7d0a2e6b7f7c65a236542630294e063b7ab9b555a5d5149aa21e4ae1e4fbce87'+
'ecc8e08a8b5e350abe622b2ffa617b202cfad72032a3037e76ffdcdc4376ee05'+
'3a190d7e46ca1de04144850381b9cb29f051915386b8a710b8ac4d027b8b050f'+
'7cba5854e028d564e453b8a968824173fc16488b8970cac828f11ae53cabd201'+
'12f87107df24ee6183d2274fe4c8b1485534ef2c5fbc1ec24bfc3663efaa08bc'+
'047d29d25043532db8391a8a3d776bf4372a6955827ccb0cdd4af403a7ce4c63'+
'd595c75a43e045f0cce1f29c8b93bd65afc5974922f214a40b7c402cdb91ae73'+
'c0b63615cdad0480680f16515a7ace9d39236464328a37743ffc28f4ddb324f4'+
'd0f5bbdc270c65b1749a6efff1fbaa09536175ccd29fb9e6057b307320d31683'+
'8a9c71f70b5b5907a66f7ea49aadc409'
);
})
});