salty-crypto 0.0.5 → 0.1.0

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.
package/src/noise.ts CHANGED
@@ -1,368 +1,18 @@
1
1
  /// SPDX-License-Identifier: MIT
2
2
  /// SPDX-FileCopyrightText: Copyright © 2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
3
3
 
4
- export type DHKeyPair = { public: Uint8Array, secret: Uint8Array };
5
-
6
- export class Nonce {
7
- constructor(public lo = 0, public hi = 0) {}
8
-
9
- increment() {
10
- const oldLo = this.lo;
11
- const newLo = (oldLo + 1) | 0;
12
- this.lo = newLo;
13
- if (newLo < oldLo) this.hi = (this.hi + 1) | 0;
14
- }
15
-
16
- reset(lo = 0, hi = 0) {
17
- this.lo = lo;
18
- this.hi = hi;
19
- }
20
-
21
- static get MAX(): Nonce {
22
- return new Nonce(0xffffffff, 0xffffffff);
23
- }
24
- }
25
-
26
- export function bytesXor(a: Uint8Array, b: Uint8Array): Uint8Array {
27
- const len = Math.min(a.byteLength, b.byteLength);
28
- const r = new Uint8Array(len);
29
- for (let i = 0; i < len; i++) r[i] = a[i] ^ b[i];
30
- return r;
31
- }
32
-
33
- export function bytesAppend(a: Uint8Array, b: Uint8Array): Uint8Array {
34
- const r = new Uint8Array(a.byteLength + b.byteLength);
35
- r.set(a, 0);
36
- r.set(b, a.byteLength);
37
- return r;
38
- }
39
-
40
- const EMPTY_BYTES = new Uint8Array(0);
41
-
42
- export type HMAC = (key: Uint8Array, data: Uint8Array) => Uint8Array;
43
-
44
- function makeHMAC(algorithms: NoiseProtocolAlgorithms): HMAC {
45
- const HMAC_IPAD = new Uint8Array(algorithms.hashBlocklen()); HMAC_IPAD.fill(0x36);
46
- const HMAC_OPAD = new Uint8Array(algorithms.hashBlocklen()); HMAC_OPAD.fill(0x5c);
47
- return (key0, data) => {
48
- const key = algorithms._padOrHash(key0, algorithms.hashBlocklen());
49
- return algorithms.hash(bytesAppend(bytesXor(key, HMAC_OPAD),
50
- algorithms.hash(bytesAppend(bytesXor(key, HMAC_IPAD),
51
- data))));
52
- };
53
- }
54
-
55
- export abstract class NoiseProtocolAlgorithms {
56
- readonly dhlen: number;
57
- readonly hmac: HMAC;
58
-
59
- constructor (hmac?: HMAC) {
60
- const tmp = this.generateKeypair();
61
- this.dhlen = this.dh(tmp, tmp.public).byteLength;
62
- this.hmac = hmac ?? makeHMAC(this);
63
- }
64
-
65
- abstract dhName(): string;
66
- abstract generateKeypair(): DHKeyPair;
67
- abstract dh(kp: DHKeyPair, pk: Uint8Array): Uint8Array;
68
-
69
- abstract cipherName(): string;
70
- abstract encrypt(key: DataView, nonce: Nonce, p: Uint8Array, associated_data?: Uint8Array): Uint8Array;
71
- abstract decrypt(key: DataView, nonce: Nonce, c: Uint8Array, associated_data?: Uint8Array): Uint8Array;
72
-
73
- abstract hashName(): string;
74
- abstract hash(data: Uint8Array): Uint8Array;
75
- abstract hashBlocklen(): number;
76
-
77
- rekey(k: DataView): DataView {
78
- return new DataView(this.encrypt(k, Nonce.MAX, new Uint8Array(32)).buffer);
79
- }
80
-
81
- _padOrHash(bs0: Uint8Array, len: number): Uint8Array {
82
- const bs = bs0.byteLength > len ? this.hash(bs0) : bs0;
83
- return bytesAppend(bs, new Uint8Array(len - bs.byteLength));
84
- }
85
-
86
- hkdf(chainingKey: Uint8Array, input: Uint8Array, numOutputs: 2): [Uint8Array, Uint8Array];
87
- hkdf(chainingKey: Uint8Array, input: Uint8Array, numOutputs: 3): [Uint8Array, Uint8Array, Uint8Array];
88
- hkdf(chainingKey: Uint8Array, input: Uint8Array, numOutputs: 2 | 3): Uint8Array[] {
89
- const tempKey = this.hmac(chainingKey, input);
90
- const o1 = this.hmac(tempKey, Uint8Array.from([1]));
91
- const o2 = this.hmac(tempKey, bytesAppend(o1, Uint8Array.from([2])));
92
- switch (numOutputs) {
93
- case 2: return [o1, o2];
94
- case 3: return [o1, o2, this.hmac(tempKey, bytesAppend(o2, Uint8Array.from([3])))];
95
- }
96
- }
97
-
98
- matchingPattern(protocol_name: string): string | null {
99
- const r = new RegExp(`^Noise_([A-Za-z0-9+]+)_${this.dhName()}_${this.cipherName()}_${this.hashName()}$`);
100
- const m = r.exec(protocol_name);
101
- if (m === null) return null;
102
- return m[1];
103
- }
104
- }
105
-
106
- export interface HandshakePattern {
107
- name: string; // e.g. "NNpsk2"
108
- baseName: string; // e.g. "NN"
109
- messages: Token[][];
110
- initiatorPreMessage: PreMessage;
111
- responderPreMessage: PreMessage;
112
- }
113
-
114
- export class CipherState {
115
- view: DataView | null = null;
116
- nonce = new Nonce();
117
-
118
- constructor (public algorithms: NoiseProtocolAlgorithms,
119
- key?: Uint8Array)
120
- {
121
- if (key !== void 0) this.view = new DataView(key.buffer);
122
- }
123
-
124
- encrypt(plaintext: Uint8Array, associated_data?: Uint8Array): Uint8Array {
125
- if (this.view === null) return plaintext;
126
- const ciphertext = this.algorithms.encrypt(this.view, this.nonce, plaintext, associated_data);
127
- this.nonce.increment();
128
- return ciphertext;
129
- }
130
-
131
- decrypt(ciphertext: Uint8Array, associated_data?: Uint8Array): Uint8Array {
132
- if (this.view === null) return ciphertext;
133
- const plaintext = this.algorithms.decrypt(this.view, this.nonce, ciphertext, associated_data);
134
- this.nonce.increment();
135
- return plaintext;
136
- }
137
-
138
- rekey() {
139
- if (this.view === null) return;
140
- this.view = this.algorithms.rekey(this.view);
141
- }
142
- }
143
-
144
- export type Role = 'initiator' | 'responder';
145
-
146
- export type NoiseProtocolOptions = {
147
- prologue?: Uint8Array,
148
- staticKeypair?: DHKeyPair,
149
- remoteStaticPublicKey?: Uint8Array,
150
- pregeneratedEphemeralKeypair?: DHKeyPair,
151
- remotePregeneratedEphemeralPublicKey?: Uint8Array,
152
- preSharedKeys?: Uint8Array[],
153
- };
154
-
155
- export type KeyTransferToken = 'e' | 's';
156
- export type KeyMixToken = 'ee' | 'es' | 'se' | 'ss' | 'psk';
157
- export type Token = KeyTransferToken | KeyMixToken;
158
- export type PreMessage = ['e'] | ['s'] | ['e', 's'] | [];
159
-
160
- export type TransportState = { send: CipherState, recv: CipherState };
161
-
162
- export class NoiseHandshake {
163
- staticKeypair: DHKeyPair;
164
- remoteStaticPublicKey: Uint8Array | null;
165
- ephemeralKeypair: DHKeyPair;
166
- remoteEphemeralPublicKey: Uint8Array | null;
167
- preSharedKeys?: Uint8Array[];
168
- stepIndex = 0;
169
- cipherState: CipherState;
170
- chainingKey: Uint8Array;
171
- handshakeHash: Uint8Array;
172
-
173
- constructor (public algorithms: NoiseProtocolAlgorithms,
174
- public pattern: HandshakePattern,
175
- public role: Role,
176
- options: NoiseProtocolOptions = {})
177
- {
178
- this.staticKeypair = options.staticKeypair ?? this.algorithms.generateKeypair();
179
- this.remoteStaticPublicKey = options.remoteStaticPublicKey ?? null;
180
- this.ephemeralKeypair = options.pregeneratedEphemeralKeypair ?? this.algorithms.generateKeypair();
181
- this.remoteEphemeralPublicKey = options.remotePregeneratedEphemeralPublicKey ?? null;
182
- this.preSharedKeys = options.preSharedKeys;
183
- if (this.preSharedKeys) {
184
- this.preSharedKeys = this.preSharedKeys.slice();
185
- if (this.preSharedKeys.length === 0) this.preSharedKeys = void 0;
186
- }
187
-
188
- const protocolName = new TextEncoder().encode(
189
- 'Noise_' + this.pattern.name +
190
- '_' + this.algorithms.dhName() +
191
- '_' + this.algorithms.cipherName() +
192
- '_' + this.algorithms.hashName());
193
-
194
- this.cipherState = new CipherState(this.algorithms);
195
- this.chainingKey = this.algorithms._padOrHash(
196
- protocolName,
197
- this.algorithms.hash(EMPTY_BYTES).byteLength);
198
- this.handshakeHash = this.chainingKey;
199
-
200
- this.mixHash(options.prologue ?? EMPTY_BYTES);
201
- this.pattern.initiatorPreMessage.forEach(t => this.mixHash(t === 'e'
202
- ? (this.isInitiator ? this.ephemeralKeypair.public : this.remoteEphemeralPublicKey!)
203
- : (this.isInitiator ? this.staticKeypair.public : this.remoteStaticPublicKey!)));
204
- this.pattern.responderPreMessage.forEach(t => this.mixHash(t === 'e'
205
- ? (!this.isInitiator ? this.ephemeralKeypair.public : this.remoteEphemeralPublicKey!)
206
- : (!this.isInitiator ? this.staticKeypair.public : this.remoteStaticPublicKey!)));
207
- }
208
-
209
- get isInitiator(): boolean {
210
- return this.role === 'initiator';
211
- }
212
-
213
- mixHash(data: Uint8Array) {
214
- this.handshakeHash = this.algorithms.hash(bytesAppend(this.handshakeHash, data));
215
- }
216
-
217
- mixKey(input: Uint8Array) {
218
- const [newCk, k] = this.algorithms.hkdf(this.chainingKey, input, 2);
219
- this.chainingKey = newCk;
220
- this.cipherState = new CipherState(this.algorithms, k);
221
- }
222
-
223
- mixKeyAndHashNextPSK() {
224
- const psk = this.preSharedKeys!.shift()!;
225
- const [newCk, tempH, k] = this.algorithms.hkdf(this.chainingKey, psk, 3);
226
- this.chainingKey = newCk;
227
- this.mixHash(tempH);
228
- this.cipherState = new CipherState(this.algorithms, k);
229
- }
230
-
231
- encryptAndHash(p: Uint8Array) {
232
- const c = this.cipherState.encrypt(p, this.handshakeHash);
233
- this.mixHash(c);
234
- return c;
235
- }
236
-
237
- decryptAndHash(c: Uint8Array) {
238
- const p = this.cipherState.decrypt(c, this.handshakeHash);
239
- this.mixHash(c);
240
- return p;
241
- }
242
-
243
- _split(): TransportState | null {
244
- if (this.stepIndex < this.pattern.messages.length) {
245
- return null;
246
- } else {
247
- let [kI, kR] = this.algorithms.hkdf(this.chainingKey, EMPTY_BYTES, 2)
248
- .map(k => new CipherState(this.algorithms, k));
249
- return this.isInitiator ? { send: kI, recv: kR } : { send: kR, recv: kI };
250
- }
251
- }
252
-
253
- _nextStep(): Token[] {
254
- if (this.stepIndex >= this.pattern.messages.length) {
255
- throw new Error("Handshake already complete, cannot continue");
256
- }
257
- return this.pattern.messages[this.stepIndex++];
258
- }
259
-
260
- _processKeyMixToken(t: KeyMixToken) {
261
- switch (t) {
262
- case 'ee':
263
- this.mixKey(this.algorithms.dh(this.ephemeralKeypair, this.remoteEphemeralPublicKey!));
264
- break;
265
-
266
- case 'es':
267
- this.mixKey(this.isInitiator
268
- ? this.algorithms.dh(this.ephemeralKeypair, this.remoteStaticPublicKey!)
269
- : this.algorithms.dh(this.staticKeypair, this.remoteEphemeralPublicKey!));
270
- break;
271
-
272
- case 'se':
273
- this.mixKey(!this.isInitiator
274
- ? this.algorithms.dh(this.ephemeralKeypair, this.remoteStaticPublicKey!)
275
- : this.algorithms.dh(this.staticKeypair, this.remoteEphemeralPublicKey!));
276
- break;
277
-
278
- case 'ss':
279
- this.mixKey(this.algorithms.dh(this.staticKeypair, this.remoteStaticPublicKey!));
280
- break;
281
-
282
- case 'psk':
283
- this.mixKeyAndHashNextPSK();
284
- break;
285
- }
286
- }
287
-
288
- writeMessage(payload: Uint8Array): { packet: Uint8Array, finished: TransportState | null } {
289
- const pieces = [];
290
- this._nextStep().forEach(t => {
291
- switch (t) {
292
- case 'e':
293
- pieces.push(this.ephemeralKeypair.public);
294
- this.mixHash(this.ephemeralKeypair.public);
295
- if (this.preSharedKeys) this.mixKey(this.ephemeralKeypair.public);
296
- break;
297
-
298
- case 's':
299
- pieces.push(this.encryptAndHash(this.staticKeypair.public));
300
- break;
301
-
302
- default:
303
- this._processKeyMixToken(t);
304
- break;
305
- }
306
- });
307
- pieces.push(this.encryptAndHash(payload));
308
-
309
- let packet: Uint8Array;
310
- if (pieces.length === 1) {
311
- packet = pieces[0];
312
- } else {
313
- packet = new Uint8Array(pieces.reduce((ac, p) => ac + p.byteLength, 0));
314
- let offset = 0;
315
- pieces.forEach(p => { packet.set(p, offset); offset += p.byteLength; });
316
- }
317
-
318
- return { packet, finished: this._split() };
319
- }
320
-
321
- readMessage(packet: Uint8Array): { message: Uint8Array, finished: TransportState | null } {
322
- const take = (n: number): Uint8Array => {
323
- const bs = packet.slice(0, n);
324
- packet = packet.subarray(n);
325
- return bs;
326
- };
327
- this._nextStep().forEach(t => {
328
- switch (t) {
329
- case 'e':
330
- this.remoteEphemeralPublicKey = take(this.algorithms.dhlen);
331
- this.mixHash(this.remoteEphemeralPublicKey);
332
- if (this.preSharedKeys) this.mixKey(this.remoteEphemeralPublicKey);
333
- break;
334
-
335
- case 's':
336
- this.remoteStaticPublicKey = this.decryptAndHash(take(
337
- this.algorithms.dhlen + (this.cipherState.view ? 16 : 0)));
338
- break;
339
-
340
- default:
341
- this._processKeyMixToken(t);
342
- break;
343
- }
344
- });
345
-
346
- const message = this.decryptAndHash(packet);
347
- return { message, finished: this._split() };
348
- }
349
-
350
- async completeHandshake(writePacket: (packet: Uint8Array) => Promise<void>,
351
- readPacket: () => Promise<Uint8Array>,
352
- handleMessage = async (_m: Uint8Array): Promise<void> => {},
353
- produceMessage = async (): Promise<Uint8Array> => new Uint8Array(0))
354
- : Promise<TransportState>
355
- {
356
- const W = async (): Promise<TransportState> => {
357
- const { packet, finished } = this.writeMessage(await produceMessage());
358
- await writePacket(packet);
359
- return finished || R();
360
- };
361
- const R = async (): Promise<TransportState> => {
362
- const { message, finished } = this.readMessage(await readPacket());
363
- await handleMessage(message);
364
- return finished || W();
365
- };
366
- return (this.isInitiator ? W() : R());
367
- }
368
- }
4
+ export { Algorithms, matchPattern } from './noise/algorithms';
5
+ export { CipherState } from './noise/cipherstate';
6
+ export { Role, HandshakeOptions, TransportState, Handshake } from './noise/handshake';
7
+ export {
8
+ HandshakePattern,
9
+ KeyMixToken,
10
+ KeyTransferToken,
11
+ PATTERNS,
12
+ PreMessage,
13
+ Token,
14
+ isOneWay,
15
+ lookupPattern,
16
+ } from './noise/patterns';
17
+ export { Noise_25519_ChaChaPoly_BLAKE2s } from './noise/profiles';
18
+ export { Rekey } from './noise/rekey';
package/src/nonce.ts ADDED
@@ -0,0 +1,23 @@
1
+ /// SPDX-License-Identifier: MIT
2
+ /// SPDX-FileCopyrightText: Copyright © 2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
3
+
4
+ export class Nonce {
5
+ constructor(public lo = 0, public hi = 0, public extra = 0) {}
6
+
7
+ increment() {
8
+ const oldLo = this.lo;
9
+ const newLo = (oldLo + 1) | 0;
10
+ this.lo = newLo;
11
+ if (newLo < oldLo) this.hi = (this.hi + 1) | 0;
12
+ }
13
+
14
+ reset(lo = 0, hi = 0, extra = 0) {
15
+ this.lo = lo;
16
+ this.hi = hi;
17
+ this.extra = extra;
18
+ }
19
+
20
+ static get MAX(): Nonce {
21
+ return new Nonce(0xffffffff, 0xffffffff);
22
+ }
23
+ }
@@ -1,5 +1,4 @@
1
- import { AEAD } from '../../dist/salty-crypto.js';
2
- const { AEAD_CHACHA20_POLY1305_TAGBYTES, aead_encrypt_detached, aead_decrypt_detached } = AEAD;
1
+ import { ChaCha20Poly1305_RFC8439, Nonce } from '../../dist/salty-crypto.js';
3
2
  import { it, expect } from '../harness';
4
3
 
5
4
  it('section 2.8.2 from rfc 8439', () => {
@@ -18,10 +17,7 @@ it('section 2.8.2 from rfc 8439', () => {
18
17
  0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
19
18
  ]).buffer);
20
19
 
21
- const nonce = new DataView(new Uint8Array([
22
- 0x07, 0x00, 0x00, 0x00,
23
- 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
24
- ]).buffer);
20
+ const nonce = new Nonce(0x43424140, 0x47464544, 0x7);
25
21
 
26
22
  const expectedEncrypted = new Uint8Array([
27
23
  0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb, 0x7b, 0x86, 0xaf, 0xbc, 0x53, 0xef, 0x7e, 0xc2,
@@ -34,8 +30,9 @@ it('section 2.8.2 from rfc 8439', () => {
34
30
  0x61, 0x16,
35
31
  ]);
36
32
 
37
- const tag = new Uint8Array(AEAD_CHACHA20_POLY1305_TAGBYTES);
38
- aead_encrypt_detached(sunscreen, sunscreen, sunscreen.byteLength, tag, key, nonce, associated_data);
33
+ const tag = new Uint8Array(ChaCha20Poly1305_RFC8439.TAGBYTES);
34
+ ChaCha20Poly1305_RFC8439.encrypt_detached(
35
+ sunscreen, sunscreen, sunscreen.byteLength, tag, key, nonce, associated_data);
39
36
  expect(sunscreen).toEqual(expectedEncrypted);
40
37
  expect(tag).toEqual(new Uint8Array([
41
38
  0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09, 0xe2, 0x6a,
@@ -43,10 +40,13 @@ it('section 2.8.2 from rfc 8439', () => {
43
40
  ]));
44
41
 
45
42
  const sunscreen2 = Uint8Array.from(sunscreen);
46
- expect(aead_decrypt_detached(sunscreen2, sunscreen2, sunscreen2.byteLength, tag, key, nonce, associated_data)).toBe(true);
43
+ expect(ChaCha20Poly1305_RFC8439.decrypt_detached(
44
+ sunscreen2, sunscreen2, sunscreen2.byteLength, tag, key, nonce, associated_data))
45
+ .toBe(true);
47
46
  expect(new TextDecoder().decode(sunscreen2)).toBe(sunscreen_str);
48
47
 
49
48
  tag[0]++;
50
- expect(aead_decrypt_detached(sunscreen, sunscreen, sunscreen.byteLength, tag, key, nonce, associated_data)).toBe(false);
49
+ expect(ChaCha20Poly1305_RFC8439.decrypt_detached(
50
+ sunscreen, sunscreen, sunscreen.byteLength, tag, key, nonce, associated_data)).toBe(false);
51
51
  expect(sunscreen).toEqual(expectedEncrypted);
52
52
  });
@@ -1,5 +1,4 @@
1
- import { BLAKE2 } from '../../dist/salty-crypto.js';
2
- const { BLAKE2s } = BLAKE2;
1
+ import { BLAKE2s } from '../../dist/salty-crypto.js';
3
2
  import { it, expect } from '../harness';
4
3
 
5
4
  it('Appendix B of RFC 7693', () => {
@@ -28,8 +27,8 @@ it('Appendix E of RFC 7693', () => {
28
27
  [16, 20, 28, 32].forEach(outlen => {
29
28
  [0, 3, 64, 65, 255, 1024].forEach(inlen => {
30
29
  const input = seq(inlen, inlen);
31
- ctx.update(BLAKE2s.digest(input, outlen));
32
- ctx.update(BLAKE2s.digest(input, outlen, seq(outlen, outlen)));
30
+ ctx.update(BLAKE2s.digest(input, void 0, outlen));
31
+ ctx.update(BLAKE2s.digest(input, seq(outlen, outlen), outlen));
33
32
  });
34
33
  });
35
34
 
@@ -1,4 +1,5 @@
1
- import { ChaCha20 as ChaCha } from '../../dist/salty-crypto.js';
1
+ import { ChaCha20, INTERNALS, Nonce } from '../../dist/salty-crypto.js';
2
+ const { chacha20_quarter_round, chacha20_block } = INTERNALS.cipher.chacha20;
2
3
  import { it, expect } from '../harness';
3
4
 
4
5
  it('chacha20_quarter_round 1', () => {
@@ -7,7 +8,7 @@ it('chacha20_quarter_round 1', () => {
7
8
  s[1] = 0x01020304;
8
9
  s[2] = 0x9b8d6f43;
9
10
  s[3] = 0x01234567;
10
- ChaCha.chacha20_quarter_round(s, 0, 1, 2, 3);
11
+ chacha20_quarter_round(s, 0, 1, 2, 3);
11
12
  expect(Array.from(s)).toEqual([0xea2a92f4, 0xcb1cf8ce, 0x4581472e, 0x5881c4bb]);
12
13
  });
13
14
 
@@ -18,7 +19,7 @@ it('chacha20_quarter_round 2', () => {
18
19
  0x53372767, 0xb00a5631, 0x974c541a, 0x359e9963,
19
20
  0x5c971061, 0x3d631689, 0x2098d9d6, 0x91dbd320,
20
21
  ]);
21
- ChaCha.chacha20_quarter_round(s, 2, 7, 8, 13);
22
+ chacha20_quarter_round(s, 2, 7, 8, 13);
22
23
  expect(s).toEqual(Uint32Array.from([
23
24
  0x879531e0, 0xc5ecf37d, 0xbdb886dc, 0xc9a62f8a,
24
25
  0x44c20ef3, 0x3390af7f, 0xd9fc690b, 0xcfacafd2,
@@ -28,18 +29,18 @@ it('chacha20_quarter_round 2', () => {
28
29
  });
29
30
 
30
31
  it('chacha20_block', () => {
31
- const key8 = new Uint8Array(ChaCha.CHACHA20_KEYBYTES);
32
+ const key8 = new Uint8Array(ChaCha20.KEYBYTES);
32
33
  for (let i = 0; i < key8.length; i++) key8[i] = i;
33
34
  const key = new DataView(key8.buffer);
34
35
 
35
- const nonce8 = new Uint8Array(ChaCha.CHACHA20_NONCEBYTES);
36
+ const nonce8 = new Uint8Array(ChaCha20.NONCEBYTES);
36
37
  nonce8[3] = 0x09;
37
38
  nonce8[7] = 0x4a;
38
39
  const nonce = new DataView(nonce8.buffer);
39
40
 
40
41
  const block = 1;
41
42
 
42
- const output = ChaCha.chacha20_block(key, block, nonce);
43
+ const output = chacha20_block(key, block, nonce);
43
44
  expect(output).toEqual(Uint32Array.from([
44
45
  0xe4e7f110, 0x15593bd1, 0x1fdd0f50, 0xc47120a3,
45
46
  0xc7f4d1c7, 0x0368c033, 0x9aaa2204, 0x4e6cd4c3,
@@ -49,13 +50,11 @@ it('chacha20_block', () => {
49
50
  });
50
51
 
51
52
  it('chacha20', () => {
52
- const key8 = new Uint8Array(ChaCha.CHACHA20_KEYBYTES);
53
+ const key8 = new Uint8Array(ChaCha20.KEYBYTES);
53
54
  for (let i = 0; i < key8.length; i++) key8[i] = i;
54
55
  const key = new DataView(key8.buffer);
55
56
 
56
- const nonce8 = new Uint8Array(ChaCha.CHACHA20_NONCEBYTES);
57
- nonce8[7] = 0x4a;
58
- const nonce = new DataView(nonce8.buffer);
57
+ const nonce = new Nonce(0x4a000000, 0, 0);
59
58
 
60
59
  const initial_counter = 1;
61
60
 
@@ -63,7 +62,7 @@ it('chacha20', () => {
63
62
  const sunscreen = new TextEncoder().encode(sunscreen_str);
64
63
  const output = new Uint8Array(sunscreen.byteLength);
65
64
 
66
- ChaCha.chacha20(key, nonce, sunscreen, output, initial_counter);
65
+ ChaCha20.stream_xor(key, nonce, sunscreen, output, initial_counter);
67
66
  expect(output).toEqual(Uint8Array.from([
68
67
  0x6e, 0x2e, 0x35, 0x9a, 0x25, 0x68, 0xf9, 0x80, 0x41, 0xba, 0x07, 0x28, 0xdd, 0x0d, 0x69, 0x81,
69
68
  0xe9, 0x7e, 0x7a, 0xec, 0x1d, 0x43, 0x60, 0xc2, 0x0a, 0x27, 0xaf, 0xcc, 0xfd, 0x9f, 0xae, 0x0b,
@@ -76,6 +75,6 @@ it('chacha20', () => {
76
75
  ]));
77
76
 
78
77
  // Test in-place encryption
79
- ChaCha.chacha20(key, nonce, sunscreen, sunscreen, initial_counter);
78
+ ChaCha20.stream_xor(key, nonce, sunscreen, sunscreen, initial_counter);
80
79
  expect(sunscreen).toEqual(output);
81
80
  });
@@ -1,16 +1,14 @@
1
- import { Noise, Patterns, NoiseProfiles, X25519 } from '../../dist/salty-crypto.js';
2
-
3
- type DHKeyPair = Noise.DHKeyPair;
4
- type TransportState = Noise.TransportState;
5
- type NoiseProtocolAlgorithms = Noise.NoiseProtocolAlgorithms;
6
- const { NoiseHandshake } = Noise;
7
-
8
- const { isOneWay, lookupPattern } = Patterns;
9
-
10
- const { Noise_25519_ChaChaPoly_BLAKE2s } = NoiseProfiles;
11
-
12
- const { scalarMultBase } = X25519;
13
-
1
+ import {
2
+ Algorithms,
3
+ DHKeyPair,
4
+ Handshake,
5
+ INTERNALS,
6
+ Noise_25519_ChaChaPoly_BLAKE2s,
7
+ TransportState,
8
+ isOneWay,
9
+ lookupPattern,
10
+ matchPattern,
11
+ } from '../../dist/salty-crypto.js';
14
12
  import { describe, it, expect } from '../harness';
15
13
 
16
14
  import fs from 'fs';
@@ -75,30 +73,30 @@ function hex(bs: Uint8Array): string {
75
73
  function skToKeypair(sk: Uint8Array | undefined): DHKeyPair | undefined {
76
74
  if (sk === void 0) return void 0;
77
75
  return {
78
- public: scalarMultBase(sk),
76
+ public: INTERNALS.dh.x25519.scalarMultBase(sk),
79
77
  secret: sk,
80
78
  };
81
79
  }
82
80
 
83
81
  const unit = (v: string | undefined): [string] | undefined => v === void 0 ? void 0 : [v];
84
82
 
85
- async function testsuite_test(t: Test, algorithms: NoiseProtocolAlgorithms) {
83
+ async function testsuite_test(t: Test, algorithms: Algorithms) {
86
84
  const isOld = 'name' in t;
87
- const patternName = algorithms.matchingPattern(isOld ? t.name : t.protocol_name);
85
+ const patternName = matchPattern(algorithms, isOld ? t.name : t.protocol_name);
88
86
  if (!patternName) return;
89
87
  const pattern = lookupPattern(patternName);
90
88
  if (!pattern) return;
91
89
  const oneWay = isOneWay(pattern);
92
90
 
93
91
  await it(pattern.name, async () => {
94
- const I = new NoiseHandshake(algorithms, pattern, 'initiator', {
92
+ const I = new Handshake(algorithms, pattern, 'initiator', {
95
93
  prologue: unhex(t.init_prologue),
96
94
  staticKeypair: skToKeypair(unhex(t.init_static)),
97
95
  remoteStaticPublicKey: unhex(t.init_remote_static),
98
96
  pregeneratedEphemeralKeypair: skToKeypair(unhex(t.init_ephemeral)),
99
97
  preSharedKeys: (isOld ? unit(t.init_psk) : t.init_psks)?.map(k => unhex(k)),
100
98
  });
101
- const R = new NoiseHandshake(algorithms, pattern, 'responder', {
99
+ const R = new Handshake(algorithms, pattern, 'responder', {
102
100
  prologue: unhex(t.resp_prologue),
103
101
  staticKeypair: skToKeypair(unhex(t.resp_static)),
104
102
  remoteStaticPublicKey: unhex(t.resp_remote_static),
@@ -137,7 +135,7 @@ async function testsuite_test(t: Test, algorithms: NoiseProtocolAlgorithms) {
137
135
  }
138
136
 
139
137
  (async () => {
140
- const algorithms = new Noise_25519_ChaChaPoly_BLAKE2s();
138
+ const algorithms = Noise_25519_ChaChaPoly_BLAKE2s;
141
139
  const load = (n: string) => JSON.parse(fs.readFileSync(path.join('test-vectors', n), 'utf-8'));
142
140
 
143
141
  await describe('https://github.com/mcginty/snow/', async () => {
@@ -1,5 +1,4 @@
1
- import { Poly1305 as P } from '../../dist/salty-crypto.js';
2
- const { Poly1305 } = P;
1
+ import { Poly1305 } from '../../dist/salty-crypto.js';
3
2
 
4
3
  import { it, expect } from '../harness';
5
4
 
@@ -11,7 +10,7 @@ it('section 2.5.2 from rfc 8439', () => {
11
10
  0x4a, 0xbf, 0xf6, 0xaf, 0x41, 0x49, 0xf5, 0x1b,
12
11
  ]);
13
12
  const message = new TextEncoder().encode("Cryptographic Forum Research Group");
14
- expect(Poly1305.digest(key, message)).toEqual(Uint8Array.from([
13
+ expect(Poly1305.digest(message, key)).toEqual(Uint8Array.from([
15
14
  0xa8, 0x06, 0x1d, 0xc1, 0x30, 0x51, 0x36, 0xc6,
16
15
  0xc2, 0x2b, 0x8b, 0xaf, 0x0c, 0x01, 0x27, 0xa9,
17
16
  ]));