@li0ard/gost 0.1.6 → 0.1.8

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/modes/mac.js CHANGED
@@ -1,10 +1,19 @@
1
- import {} from "@noble/hashes/utils.js";
1
+ import { concatBytes } from "@noble/hashes/utils.js";
2
2
  import { pad1, pad3, xorBytes } from "../utils.js";
3
- import { bytesToNumberBE, numberToVarBytesBE } from "@noble/curves/utils.js";
3
+ import { bytesToNumberBE, bytesToNumberLE, numberToBytesLE, numberToVarBytesBE } from "@noble/curves/utils.js";
4
4
  import { magmaKeySequences, Magma } from "../magma/index.js";
5
5
  import { acpkm_master } from "./_keytransform.js";
6
6
  const Rb64 = 0b11011;
7
7
  const Rb128 = 0b10000111;
8
+ const shift1 = (src, dst) => {
9
+ let b = 0;
10
+ for (let i = src.length - 1; i >= 0; i--) {
11
+ const bb = src[i] >> 7;
12
+ dst[i] = src[i] << 1 | b;
13
+ b = bb;
14
+ }
15
+ return b;
16
+ };
8
17
  /**
9
18
  * **EN:** Message Authentication Code (MAC) mode
10
19
  *
@@ -12,36 +21,36 @@ const Rb128 = 0b10000111;
12
21
  */
13
22
  export const mac = (cipher) => {
14
23
  const encrypter = cipher.encrypt.bind(cipher);
15
- const macShift = (data, xorLsb = 0) => numberToVarBytesBE((bytesToNumberBE(data) * BigInt(2)) ^ BigInt(xorLsb)).slice(-cipher.blockSize);
16
- const macKs = () => {
17
- const Rb = cipher.blockSize === 16 ? Rb128 : Rb64;
18
- const l = encrypter(new Uint8Array(cipher.blockSize));
19
- let k1;
20
- if ((l[0] & 0x80) !== 0)
21
- k1 = macShift(l, Rb);
22
- else
23
- k1 = macShift(l);
24
- let k2;
25
- if ((k1[0] & 0x80) !== 0)
26
- k2 = macShift(k1, Rb);
27
- else
28
- k2 = macShift(k1);
29
- return [k1, k2];
30
- };
24
+ const Rb = cipher.blockSize === 16 ? Rb128 : Rb64;
25
+ const L = encrypter(new Uint8Array(cipher.blockSize));
31
26
  return {
32
27
  compute: (msg) => {
33
- const [k1, k2] = macKs();
34
- let tailOffset;
35
- if (msg.length % cipher.blockSize === 0)
36
- tailOffset = msg.length - cipher.blockSize;
37
- else
38
- tailOffset = msg.length - (msg.length % cipher.blockSize);
39
- let prev = new Uint8Array(cipher.blockSize);
40
- for (let i = 0; i < tailOffset; i += cipher.blockSize)
41
- prev = encrypter(xorBytes(msg.subarray(i, i + cipher.blockSize), prev));
42
- const tail = msg.subarray(tailOffset);
43
- const xorWithPrev = xorBytes(pad3(tail, cipher.blockSize), prev);
44
- return encrypter(xorBytes(xorWithPrev, (tail.length === cipher.blockSize ? k1 : k2)));
28
+ const k1 = new Uint8Array(cipher.blockSize);
29
+ const msb = shift1(L, k1);
30
+ if (msb)
31
+ k1[cipher.blockSize - 1] ^= Rb;
32
+ const k2 = new Uint8Array(cipher.blockSize);
33
+ const msb2 = shift1(k1, k2);
34
+ if (msb2)
35
+ k2[cipher.blockSize - 1] ^= Rb;
36
+ const n = Math.ceil(msg.length / cipher.blockSize) || 1;
37
+ const lastBlockComplete = msg.length > 0 && msg.length % cipher.blockSize === 0;
38
+ let buf = new Uint8Array(cipher.blockSize);
39
+ for (let i = 0; i < n - 1; i++) {
40
+ const m = msg.subarray(i * cipher.blockSize, (i + 1) * cipher.blockSize);
41
+ buf = encrypter(xorBytes(buf, m));
42
+ }
43
+ let lastBlock;
44
+ if (lastBlockComplete && msg.length > 0)
45
+ lastBlock = xorBytes(msg.subarray((n - 1) * cipher.blockSize, n * cipher.blockSize), k1);
46
+ else {
47
+ const padded = new Uint8Array(cipher.blockSize);
48
+ const remaining = msg.length - (n - 1) * cipher.blockSize;
49
+ padded.set(msg.subarray((n - 1) * cipher.blockSize));
50
+ padded[remaining] = 0x80;
51
+ lastBlock = xorBytes(padded, k2);
52
+ }
53
+ return encrypter(xorBytes(buf, lastBlock));
45
54
  }
46
55
  };
47
56
  };
@@ -52,19 +61,16 @@ export const mac = (cipher) => {
52
61
  */
53
62
  export const mac_legacy = (cipher, iv = new Uint8Array(cipher.blockSize)) => {
54
63
  const split = (data) => [
55
- (data[0] | data[1] << 8 | data[2] << 16 | data[3] << 24) >>> 0,
56
- (data[4] | data[5] << 8 | data[6] << 16 | data[7] << 24) >>> 0
64
+ Number(bytesToNumberLE(data.subarray(0, 4))),
65
+ Number(bytesToNumberLE(data.subarray(4, 8)))
57
66
  ];
58
- const join = (ns) => new Uint8Array([
59
- (ns[1] >> 0) & 0xFF, (ns[1] >> 8) & 0xFF, (ns[1] >> 16) & 0xFF, (ns[1] >> 24) & 0xFF,
60
- (ns[0] >> 0) & 0xFF, (ns[0] >> 8) & 0xFF, (ns[0] >> 16) & 0xFF, (ns[0] >> 24) & 0xFF
61
- ]);
67
+ const join = (ns) => concatBytes(numberToBytesLE(ns[1], 4), numberToBytesLE(ns[0], 4));
62
68
  return {
63
69
  compute: (msg) => {
64
70
  const paddedData = pad1(msg, cipher.blockSize);
65
71
  let prev = split(iv).reverse();
66
72
  for (let i = 0; i < paddedData.length; i += cipher.blockSize)
67
- prev = split(Magma.reverseChunks(cipher.proceedBlock(Magma.reverseChunks(xorBytes(paddedData.subarray(i, i + cipher.blockSize), join(prev))), magmaKeySequences.MAC)));
73
+ prev = split(cipher.proceedBlock(xorBytes(paddedData.subarray(i, i + cipher.blockSize), join(prev)), magmaKeySequences.MAC));
68
74
  return join(prev);
69
75
  }
70
76
  };
package/modes/mgm.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { concatBytes } from "@noble/hashes/utils.js";
2
2
  import { bytesToNumberBE, equalBytes, numberToBytesBE } from "@noble/curves/utils.js";
3
3
  import { pad1, xorBytes } from "../utils.js";
4
+ import { gf64Multiply, gf128Multiply } from "../gf/index.js";
4
5
  /**
5
6
  * **EN:** Multilinear Galois (MGM) mode (AEAD)
6
7
  *
@@ -15,29 +16,13 @@ export const mgm = (cipher, nonce, tagSize = cipher.blockSize) => {
15
16
  throw new Error("Invalid tagSize");
16
17
  const encrypter = cipher.encrypt.bind(cipher);
17
18
  const maxSize = (1n << BigInt(cipher.blockSize * 4)) - 1n;
18
- const r = (cipher.blockSize == 8 ? 0x1B : 0x87);
19
19
  const validateSizes = (plaintext, additional) => {
20
20
  if (plaintext.length == 0 && additional.length == 0)
21
21
  throw new Error("At least one of plaintext or additional_data required");
22
22
  if ((plaintext.length + additional.length) > maxSize)
23
23
  throw new Error("plaintext+additional_data are too big");
24
24
  };
25
- const mul = (a, b) => {
26
- let x = bytesToNumberBE(a);
27
- let y = bytesToNumberBE(b);
28
- let z = 0n;
29
- const max_bit = 1n << (BigInt(cipher.blockSize) * 8n - 1n);
30
- while (y > 0n) {
31
- if ((y & 1n) == 1n)
32
- z ^= x;
33
- if ((x & max_bit) > 0n)
34
- x = ((x ^ max_bit) << 1n) ^ BigInt(r);
35
- else
36
- x <<= 1n;
37
- y >>= 1n;
38
- }
39
- return numberToBytesBE(z, cipher.blockSize);
40
- };
25
+ const mul = (cipher.blockSize == 8 ? gf64Multiply : gf128Multiply);
41
26
  const crypt = (icn, data) => {
42
27
  icn[0] &= 0x7F;
43
28
  let enc = encrypter(icn);
package/modes/wrap.d.ts CHANGED
@@ -11,4 +11,4 @@ export declare const kexp15: (cipherEnc: Cipher, cipherMac: Cipher, iv: TArg<Uin
11
11
  *
12
12
  * **RU:** Режим обёртки ключей шифрования согласно ГОСТ 28147-89
13
13
  */
14
- export declare const kwp: (kek: TArg<Uint8Array>, isCryptoPro?: boolean, sbox?: TArg<Uint8Array>[]) => WrapModeMagma;
14
+ export declare const kwp: (kek: TArg<Uint8Array>, isCryptoPro?: boolean, sbox?: TArg<Uint8Array>) => WrapModeMagma;
package/modes/wrap.js CHANGED
@@ -2,7 +2,7 @@ import { concatBytes } from "@noble/hashes/utils.js";
2
2
  import { mac as _mac, mac_legacy } from "./mac.js";
3
3
  import { ctr } from "./ctr.js";
4
4
  import { equalBytes } from "@noble/curves/utils.js";
5
- import { ID_GOST_28147_89_CRYPTO_PRO_A_PARAM_SET } from "../magma/const";
5
+ import { ID_GOST_28147_89_CRYPTO_PRO_A_PARAM_SET } from "../magma/const.js";
6
6
  import { Magma } from "../magma/index.js";
7
7
  import { ecb } from "./ecb.js";
8
8
  import { cp_kek_diversify } from "./_keytransform.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@li0ard/gost",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "main": "index.js",
5
5
  "types": "index.d.ts",
6
6
  "type": "module",
@@ -15,7 +15,11 @@ declare abstract class Streebog<T extends Streebog<T>> implements Hash<Streebog<
15
15
  digest(): TRet<Uint8Array>;
16
16
  digestInto(buf: TArg<Uint8Array>): void;
17
17
  }
18
- /** Streebog-256 (GOST R 34.11-2012) hash function */
18
+ /**
19
+ * **Streebog-256 hash function**
20
+ *
21
+ * Described by GOST R 34.11-2012 ([RFC 6986](https://datatracker.ietf.org/doc/html/rfc6986.html))
22
+ */
19
23
  export declare class Streebog256 extends Streebog<Streebog256> {
20
24
  /** Streebog-256 (GOST R 34.11-2012) hash function */
21
25
  constructor();
@@ -24,7 +28,11 @@ export declare class Streebog256 extends Streebog<Streebog256> {
24
28
  clone(): Streebog256;
25
29
  _cloneInto(to?: Streebog256): Streebog256;
26
30
  }
27
- /** Streebog-512 (GOST R 34.11-2012) hash function */
31
+ /**
32
+ * **Streebog-512 hash function**
33
+ *
34
+ * Described by GOST R 34.11-2012 ([RFC 6986](https://datatracker.ietf.org/doc/html/rfc6986.html))
35
+ */
28
36
  export declare class Streebog512 extends Streebog<Streebog512> {
29
37
  /** Streebog-512 (GOST R 34.11-2012) hash function */
30
38
  constructor();
@@ -33,8 +41,11 @@ export declare class Streebog512 extends Streebog<Streebog512> {
33
41
  clone(): Streebog512;
34
42
  _cloneInto(to?: Streebog512): Streebog512;
35
43
  }
36
- /** Streebog-256 (GOST R 34.11-2012) hash function */
37
- export declare const streebog256: {
44
+ /**
45
+ * **Streebog-256 hash function**
46
+ *
47
+ * Described by GOST R 34.11-2012 ([RFC 6986](https://datatracker.ietf.org/doc/html/rfc6986.html))
48
+ */ export declare const streebog256: {
38
49
  outputLen: number;
39
50
  blockLen: number;
40
51
  canXOF: boolean;
@@ -48,8 +59,11 @@ export declare const streebog256: {
48
59
  oid?: TRet<Uint8Array> | undefined;
49
60
  create: () => Streebog256;
50
61
  };
51
- /** Streebog-512 (GOST R 34.11-2012) hash function */
52
- export declare const streebog512: {
62
+ /**
63
+ * **Streebog-512 hash function**
64
+ *
65
+ * Described by GOST R 34.11-2012 ([RFC 6986](https://datatracker.ietf.org/doc/html/rfc6986.html))
66
+ */ export declare const streebog512: {
53
67
  outputLen: number;
54
68
  blockLen: number;
55
69
  canXOF: boolean;
package/streebog/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { concatBytes, createHasher } from "@noble/hashes/utils.js";
1
+ import { concatBytes, copyBytes, createHasher } from "@noble/hashes/utils.js";
2
2
  import { A, C, TAU } from "./const.js";
3
3
  import { PI } from "../kuznyechik/const.js";
4
4
  import { pad1, xorBytes } from "../utils.js";
@@ -8,8 +8,7 @@ const _0020 = new Uint8Array([0, 0, 2, 0]);
8
8
  const _0 = new Uint8Array(64);
9
9
  const add512 = (a, b) => {
10
10
  const c = new Uint8Array(64);
11
- const tmpA = new Uint8Array(64);
12
- const tmpB = new Uint8Array(64);
11
+ const tmpA = new Uint8Array(64), tmpB = new Uint8Array(64);
13
12
  for (let i = 0; i < a.length; i++)
14
13
  tmpA[63 - i] = a[a.length - i - 1];
15
14
  for (let i = 0; i < b.length; i++)
@@ -122,7 +121,7 @@ class Streebog {
122
121
  return buffer;
123
122
  }
124
123
  digestInto(buf) {
125
- const message = this.buffer.slice().reverse();
124
+ const message = copyBytes(this.buffer).reverse();
126
125
  let n = new Uint8Array(this.blockLen);
127
126
  let sigma = new Uint8Array(this.blockLen);
128
127
  let hash = new Uint8Array(this.blockLen).fill(this.is512 ? 0 : 1);
@@ -144,13 +143,17 @@ class Streebog {
144
143
  }
145
144
  hash = G(_0, G(_0, G(n, hash, paddedMsg), add512(n, numberToBytesBE(msg.length * 8, 4))), add512(sigma, paddedMsg));
146
145
  if (this.is512)
147
- buf.set(hash.slice().reverse());
146
+ buf.set(copyBytes(hash).reverse());
148
147
  else
149
148
  buf.set(hash.slice(0, 32).reverse());
150
149
  this.destroy();
151
150
  }
152
151
  }
153
- /** Streebog-256 (GOST R 34.11-2012) hash function */
152
+ /**
153
+ * **Streebog-256 hash function**
154
+ *
155
+ * Described by GOST R 34.11-2012 ([RFC 6986](https://datatracker.ietf.org/doc/html/rfc6986.html))
156
+ */
154
157
  export class Streebog256 extends Streebog {
155
158
  /** Streebog-256 (GOST R 34.11-2012) hash function */
156
159
  constructor() { super(false); }
@@ -163,7 +166,11 @@ export class Streebog256 extends Streebog {
163
166
  return to;
164
167
  }
165
168
  }
166
- /** Streebog-512 (GOST R 34.11-2012) hash function */
169
+ /**
170
+ * **Streebog-512 hash function**
171
+ *
172
+ * Described by GOST R 34.11-2012 ([RFC 6986](https://datatracker.ietf.org/doc/html/rfc6986.html))
173
+ */
167
174
  export class Streebog512 extends Streebog {
168
175
  /** Streebog-512 (GOST R 34.11-2012) hash function */
169
176
  constructor() { super(true); }
@@ -176,7 +183,13 @@ export class Streebog512 extends Streebog {
176
183
  return to;
177
184
  }
178
185
  }
179
- /** Streebog-256 (GOST R 34.11-2012) hash function */
180
- export const streebog256 = createHasher(Streebog256.create);
181
- /** Streebog-512 (GOST R 34.11-2012) hash function */
182
- export const streebog512 = createHasher(Streebog512.create);
186
+ /**
187
+ * **Streebog-256 hash function**
188
+ *
189
+ * Described by GOST R 34.11-2012 ([RFC 6986](https://datatracker.ietf.org/doc/html/rfc6986.html))
190
+ */ export const streebog256 = createHasher(Streebog256.create);
191
+ /**
192
+ * **Streebog-512 hash function**
193
+ *
194
+ * Described by GOST R 34.11-2012 ([RFC 6986](https://datatracker.ietf.org/doc/html/rfc6986.html))
195
+ */ export const streebog512 = createHasher(Streebog512.create);