salty-crypto 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,41 @@
1
+ import { BLAKE2s } from '../../src/blake2';
2
+ import { it, expect } from '../harness';
3
+
4
+ it('Appendix B of RFC 7693', () => {
5
+ expect(BLAKE2s.digest(new TextEncoder().encode("abc"))).toEqual(Uint8Array.from([
6
+ 0x50, 0x8C, 0x5E, 0x8C, 0x32, 0x7C, 0x14, 0xE2, 0xE1, 0xA7, 0x2B, 0xA3, 0x4E, 0xEB, 0x45, 0x2F,
7
+ 0x37, 0x45, 0x8B, 0x20, 0x9E, 0xD6, 0x3A, 0x29, 0x4D, 0x99, 0x9B, 0x4C, 0x86, 0x67, 0x59, 0x82,
8
+ ]));
9
+ });
10
+
11
+ it('Appendix E of RFC 7693', () => {
12
+ function seq(len: number, seed: number): Uint8Array {
13
+ let a = (0xDEAD4BAD * seed) | 0;
14
+ let b = 1;
15
+ const out = new Uint8Array(len);
16
+ for (let i = 0; i < len; i++) {
17
+ const t = (a + b) | 0;
18
+ a = b;
19
+ b = t;
20
+ out[i] = (t >> 24) & 0xff;
21
+ }
22
+ return out;
23
+ }
24
+
25
+ const ctx = new BLAKE2s();
26
+
27
+ [16, 20, 28, 32].forEach(outlen => {
28
+ [0, 3, 64, 65, 255, 1024].forEach(inlen => {
29
+ const input = seq(inlen, inlen);
30
+ ctx.update(BLAKE2s.digest(input, outlen));
31
+ ctx.update(BLAKE2s.digest(input, outlen, seq(outlen, outlen)));
32
+ });
33
+ });
34
+
35
+ expect(ctx.final()).toEqual(Uint8Array.from([
36
+ 0x6A, 0x41, 0x1F, 0x08, 0xCE, 0x25, 0xAD, 0xCD,
37
+ 0xFB, 0x02, 0xAB, 0xA6, 0x41, 0x45, 0x1C, 0xEC,
38
+ 0x53, 0xC5, 0x98, 0xB2, 0x4F, 0x4F, 0xC7, 0x87,
39
+ 0xFB, 0xDC, 0x88, 0x79, 0x7F, 0x4C, 0x1D, 0xFE,
40
+ ]));
41
+ });
@@ -0,0 +1,81 @@
1
+ import * as ChaCha from '../../src/chacha20';
2
+ import { it, expect } from '../harness';
3
+
4
+ it('chacha20_quarter_round 1', () => {
5
+ const s = new Uint32Array(4);
6
+ s[0] = 0x11111111;
7
+ s[1] = 0x01020304;
8
+ s[2] = 0x9b8d6f43;
9
+ s[3] = 0x01234567;
10
+ ChaCha.chacha20_quarter_round(s, 0, 1, 2, 3);
11
+ expect(Array.from(s)).toEqual([0xea2a92f4, 0xcb1cf8ce, 0x4581472e, 0x5881c4bb]);
12
+ });
13
+
14
+ it('chacha20_quarter_round 2', () => {
15
+ const s = Uint32Array.from([
16
+ 0x879531e0, 0xc5ecf37d, 0x516461b1, 0xc9a62f8a,
17
+ 0x44c20ef3, 0x3390af7f, 0xd9fc690b, 0x2a5f714c,
18
+ 0x53372767, 0xb00a5631, 0x974c541a, 0x359e9963,
19
+ 0x5c971061, 0x3d631689, 0x2098d9d6, 0x91dbd320,
20
+ ]);
21
+ ChaCha.chacha20_quarter_round(s, 2, 7, 8, 13);
22
+ expect(s).toEqual(Uint32Array.from([
23
+ 0x879531e0, 0xc5ecf37d, 0xbdb886dc, 0xc9a62f8a,
24
+ 0x44c20ef3, 0x3390af7f, 0xd9fc690b, 0xcfacafd2,
25
+ 0xe46bea80, 0xb00a5631, 0x974c541a, 0x359e9963,
26
+ 0x5c971061, 0xccc07c79, 0x2098d9d6, 0x91dbd320,
27
+ ]));
28
+ });
29
+
30
+ it('chacha20_block', () => {
31
+ const key8 = new Uint8Array(ChaCha.CHACHA20_KEYBYTES);
32
+ for (let i = 0; i < key8.length; i++) key8[i] = i;
33
+ const key = new DataView(key8.buffer);
34
+
35
+ const nonce8 = new Uint8Array(ChaCha.CHACHA20_NONCEBYTES);
36
+ nonce8[3] = 0x09;
37
+ nonce8[7] = 0x4a;
38
+ const nonce = new DataView(nonce8.buffer);
39
+
40
+ const block = 1;
41
+
42
+ const output = ChaCha.chacha20_block(key, block, nonce);
43
+ expect(output).toEqual(Uint32Array.from([
44
+ 0xe4e7f110, 0x15593bd1, 0x1fdd0f50, 0xc47120a3,
45
+ 0xc7f4d1c7, 0x0368c033, 0x9aaa2204, 0x4e6cd4c3,
46
+ 0x466482d2, 0x09aa9f07, 0x05d7c214, 0xa2028bd9,
47
+ 0xd19c12b5, 0xb94e16de, 0xe883d0cb, 0x4e3c50a2,
48
+ ]));
49
+ });
50
+
51
+ it('chacha20', () => {
52
+ const key8 = new Uint8Array(ChaCha.CHACHA20_KEYBYTES);
53
+ for (let i = 0; i < key8.length; i++) key8[i] = i;
54
+ const key = new DataView(key8.buffer);
55
+
56
+ const nonce8 = new Uint8Array(ChaCha.CHACHA20_NONCEBYTES);
57
+ nonce8[7] = 0x4a;
58
+ const nonce = new DataView(nonce8.buffer);
59
+
60
+ const initial_counter = 1;
61
+
62
+ const sunscreen_str = "Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it.";
63
+ const sunscreen = new TextEncoder().encode(sunscreen_str);
64
+ const output = new Uint8Array(sunscreen.byteLength);
65
+
66
+ ChaCha.chacha20(key, nonce, sunscreen, output, initial_counter);
67
+ expect(output).toEqual(Uint8Array.from([
68
+ 0x6e, 0x2e, 0x35, 0x9a, 0x25, 0x68, 0xf9, 0x80, 0x41, 0xba, 0x07, 0x28, 0xdd, 0x0d, 0x69, 0x81,
69
+ 0xe9, 0x7e, 0x7a, 0xec, 0x1d, 0x43, 0x60, 0xc2, 0x0a, 0x27, 0xaf, 0xcc, 0xfd, 0x9f, 0xae, 0x0b,
70
+ 0xf9, 0x1b, 0x65, 0xc5, 0x52, 0x47, 0x33, 0xab, 0x8f, 0x59, 0x3d, 0xab, 0xcd, 0x62, 0xb3, 0x57,
71
+ 0x16, 0x39, 0xd6, 0x24, 0xe6, 0x51, 0x52, 0xab, 0x8f, 0x53, 0x0c, 0x35, 0x9f, 0x08, 0x61, 0xd8,
72
+ 0x07, 0xca, 0x0d, 0xbf, 0x50, 0x0d, 0x6a, 0x61, 0x56, 0xa3, 0x8e, 0x08, 0x8a, 0x22, 0xb6, 0x5e,
73
+ 0x52, 0xbc, 0x51, 0x4d, 0x16, 0xcc, 0xf8, 0x06, 0x81, 0x8c, 0xe9, 0x1a, 0xb7, 0x79, 0x37, 0x36,
74
+ 0x5a, 0xf9, 0x0b, 0xbf, 0x74, 0xa3, 0x5b, 0xe6, 0xb4, 0x0b, 0x8e, 0xed, 0xf2, 0x78, 0x5e, 0x42,
75
+ 0x87, 0x4d,
76
+ ]));
77
+
78
+ // Test in-place encryption
79
+ ChaCha.chacha20(key, nonce, sunscreen, sunscreen, initial_counter);
80
+ expect(sunscreen).toEqual(output);
81
+ });
@@ -0,0 +1,144 @@
1
+ import { DHKeyPair, NoiseHandshake, NoiseProtocolAlgorithms, TransportState } from '../../src/noise';
2
+ import { isOneWay, lookupPattern } from '../../src/patterns';
3
+ import { Noise_25519_ChaChaPoly_BLAKE2s } from '../../src/profiles';
4
+ import { scalarMultBase } from '../../src/x25519';
5
+ import { describe, it, expect } from '../harness';
6
+
7
+ import fs from 'fs';
8
+ import path from 'path';
9
+
10
+ type OldTest = {
11
+ name: string,
12
+
13
+ init_prologue?: string,
14
+ init_ephemeral?: string,
15
+ init_static?: string,
16
+ init_remote_static?: string,
17
+ init_psk?: string,
18
+
19
+ resp_prologue?: string,
20
+ resp_ephemeral?: string,
21
+ resp_static?: string,
22
+ resp_remote_static?: string,
23
+ resp_psk?: string,
24
+
25
+ messages: Array<{
26
+ payload: string,
27
+ ciphertext: string,
28
+ }>,
29
+ };
30
+
31
+ type CurrentTest = {
32
+ protocol_name: string,
33
+
34
+ init_prologue?: string,
35
+ init_ephemeral?: string,
36
+ init_static?: string,
37
+ init_remote_static?: string,
38
+ init_psks?: string[],
39
+
40
+ resp_prologue?: string,
41
+ resp_ephemeral?: string,
42
+ resp_static?: string,
43
+ resp_remote_static?: string,
44
+ resp_psks?: string[],
45
+
46
+ messages: Array<{
47
+ payload: string,
48
+ ciphertext: string,
49
+ }>,
50
+ };
51
+
52
+ type Test = OldTest | CurrentTest;
53
+
54
+ function unhex(s: string): Uint8Array;
55
+ function unhex(s: undefined): undefined;
56
+ function unhex(s: string | undefined): Uint8Array | undefined;
57
+ function unhex(s: string | undefined): Uint8Array | undefined {
58
+ if (s === void 0) return void 0;
59
+ return Uint8Array.from(Buffer.from(s, 'hex'));
60
+ }
61
+
62
+ function hex(bs: Uint8Array): string {
63
+ return Buffer.from(bs).toString('hex');
64
+ }
65
+
66
+ function skToKeypair(sk: Uint8Array | undefined): DHKeyPair | undefined {
67
+ if (sk === void 0) return void 0;
68
+ return {
69
+ public: scalarMultBase(sk),
70
+ secret: sk,
71
+ };
72
+ }
73
+
74
+ const unit = (v: string | undefined): [string] | undefined => v === void 0 ? void 0 : [v];
75
+
76
+ async function testsuite_test(t: Test, algorithms: NoiseProtocolAlgorithms) {
77
+ const isOld = 'name' in t;
78
+ const patternName = algorithms.matchingPattern(isOld ? t.name : t.protocol_name);
79
+ if (!patternName) return;
80
+ const pattern = lookupPattern(patternName);
81
+ if (!pattern) return;
82
+ const oneWay = isOneWay(pattern);
83
+
84
+ await it(pattern.name, async () => {
85
+ const I = new NoiseHandshake(algorithms, pattern, 'initiator', {
86
+ prologue: unhex(t.init_prologue),
87
+ staticKeypair: skToKeypair(unhex(t.init_static)),
88
+ remoteStaticPublicKey: unhex(t.init_remote_static),
89
+ pregeneratedEphemeralKeypair: skToKeypair(unhex(t.init_ephemeral)),
90
+ preSharedKeys: (isOld ? unit(t.init_psk) : t.init_psks)?.map(k => unhex(k)),
91
+ });
92
+ const R = new NoiseHandshake(algorithms, pattern, 'responder', {
93
+ prologue: unhex(t.resp_prologue),
94
+ staticKeypair: skToKeypair(unhex(t.resp_static)),
95
+ remoteStaticPublicKey: unhex(t.resp_remote_static),
96
+ pregeneratedEphemeralKeypair: skToKeypair(unhex(t.resp_ephemeral)),
97
+ preSharedKeys: (isOld ? unit(t.resp_psk) : t.resp_psks)?.map(k => unhex(k)),
98
+ });
99
+ let sender = I;
100
+ let receiver = R;
101
+ let senderCss: TransportState | null = null;
102
+ let receiverCss: TransportState | null = null;
103
+ function swapRoles() {
104
+ const t = sender; sender = receiver; receiver = t;
105
+ const c = senderCss; senderCss = receiverCss; receiverCss = c;
106
+ }
107
+ for (let step = 0; step < t.messages.length; step++) {
108
+ const m = t.messages[step];
109
+ if (senderCss && receiverCss) {
110
+ const actualCiphertext = senderCss.send.encrypt(unhex(m.payload));
111
+ expect(hex(actualCiphertext)).toEqual(m.ciphertext);
112
+ const actualMessage = receiverCss.recv.decrypt(actualCiphertext);
113
+ expect(hex(actualMessage)).toEqual(m.payload);
114
+ } else {
115
+ const { packet: actualCiphertext, finished: senderFinished } =
116
+ sender.writeMessage(unhex(m.payload));
117
+ expect(hex(actualCiphertext)).toEqual(m.ciphertext);
118
+ const { message: actualMessage, finished: receiverFinished } =
119
+ receiver.readMessage(actualCiphertext);
120
+ expect(hex(actualMessage)).toEqual(m.payload);
121
+ expect(senderFinished).toEqual(receiverFinished);
122
+ senderCss = senderFinished;
123
+ receiverCss = receiverFinished;
124
+ }
125
+ if (!oneWay) swapRoles();
126
+ };
127
+ });
128
+ }
129
+
130
+ (async () => {
131
+ const algorithms = new Noise_25519_ChaChaPoly_BLAKE2s();
132
+ const load = (n: string) => JSON.parse(fs.readFileSync(path.join('test-vectors', n), 'utf-8'));
133
+
134
+ await describe('https://github.com/mcginty/snow/', async () => {
135
+ for (const t of load('snow.txt').vectors as Test[]) {
136
+ await testsuite_test(t, algorithms);
137
+ }
138
+ });
139
+ await describe('https://github.com/rweather/noise-c/', async () => {
140
+ for (const t of load('noise-c-basic.txt').vectors as Test[]) {
141
+ await testsuite_test(t, algorithms);
142
+ }
143
+ });
144
+ })();
@@ -0,0 +1,16 @@
1
+ import { Poly1305 } from '../../src/poly1305';
2
+ import { it, expect } from '../harness';
3
+
4
+ it('section 2.5.2 from rfc 8439', () => {
5
+ const key = Uint8Array.from([
6
+ 0x85, 0xd6, 0xbe, 0x78, 0x57, 0x55, 0x6d, 0x33,
7
+ 0x7f, 0x44, 0x52, 0xfe, 0x42, 0xd5, 0x06, 0xa8,
8
+ 0x01, 0x03, 0x80, 0x8a, 0xfb, 0x0d, 0xb2, 0xfd,
9
+ 0x4a, 0xbf, 0xf6, 0xaf, 0x41, 0x49, 0xf5, 0x1b,
10
+ ]);
11
+ const message = new TextEncoder().encode("Cryptographic Forum Research Group");
12
+ expect(Poly1305.digest(key, message)).toEqual(Uint8Array.from([
13
+ 0xa8, 0x06, 0x1d, 0xc1, 0x30, 0x51, 0x36, 0xc6,
14
+ 0xc2, 0x2b, 0x8b, 0xaf, 0x0c, 0x01, 0x27, 0xa9,
15
+ ]));
16
+ });