summaryrefslogtreecommitdiffhomepage
path: root/packages/server/src/helpers/iso/isoCrypto.ts
blob: df3f150f27b9bf0cf2c26b6addcb7fa736069795 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import { webcrypto } from 'node:crypto';

/**
 * Fill up the provided bytes array with random bytes equal to its length.
 *
 * @returns the same bytes array passed into the method
 */
export function getRandomValues(array: Uint8Array): Uint8Array {
  if (globalThis.crypto) {
    // We're in a browser-like runtime, use global Crypto
    globalThis.crypto.getRandomValues(array);
  } else {
    // We're in Node, use Node's Crypto
    webcrypto.getRandomValues(array);
  }

  return array;
}

/**
 * Generate a digest of the provided data.
 *
 * @param data The data to generate a digest of
 * @param algorithm Must be one of the following values:
 * - `"SHA-1"`
 * - `"SHA-256"`
 * - `"SHA-384"`
 * - `"SHA-512"`
 */
export async function digest(data: Uint8Array, algorithm: string): Promise<Uint8Array> {
  algorithm = normalizeAlgorithm(algorithm);

  let hashed: ArrayBuffer
  if (globalThis.crypto) {
    // We're in a browser-like runtime, use global Crypto
    hashed = await globalThis.crypto.subtle.digest(algorithm, data);
  } else {
    // We're in Node, use Node's Crypto
    hashed = await webcrypto.subtle.digest(algorithm, data);
  }

  return new Uint8Array(hashed);
}

/**
 * Convert algorithms like "SHA1", "sha256", etc... into values like "SHA-1", "SHA-256", etc...
 * that `.digest()` will accept
 */
function normalizeAlgorithm(algorithm: string): string {
  if (/sha\d{1,3}/i.test(algorithm)) {
    algorithm = algorithm.toUpperCase().replace('SHA', 'SHA-');
  }

  return algorithm;
/**
 * Convert a COSE crv ID into a corresponding string value that WebCrypto APIs expect
 */
function mapCoseCrvToWebCryptoCrv(crv: number): SubtleCryptoCrv {
  if (crv === 1) {
    return 'P-256';
  }

  if (crv === 2) {
    return 'P-384';
  }

  if (crv === 3) {
    return 'P-521';
  }

  throw new Error(`Unexpected COSE crv value of ${crv}`);
}
type SubtleCryptoCrv = "P-256" | "P-384" | "P-521";

/**
 * Convert a COSE alg ID into a corresponding string value that WebCrypto APIs expect
 */
function mapCoseAlgToWebCryptoAlg(alg: number): SubtleCryptoAlg {
  if ([-65535].indexOf(alg) >= 0) {
    return 'SHA-1';
  } else if ([-7, -37, -257].indexOf(alg) >= 0) {
    return 'SHA-256';
  } else if ([-35, -38, -258].indexOf(alg) >= 0) {
    return 'SHA-384'
  } else if ([-8, -36, -39, -259].indexOf(alg) >= 0) {
    return 'SHA-512';
  }

  throw new Error(`Unexpected COSE alg value of ${alg}`);
}
export type SubtleCryptoAlg = "SHA-1" | "SHA-256" | "SHA-384" | "SHA-512";