Skip to content
File

Blob: src/worker/services/crypto.ts

typescript44 lines
1export const timingSafeEqual = (left: Uint8Array, right: Uint8Array): boolean => {
2 const lengthsMatch = left.byteLength === right.byteLength;
3 // subtle.timingSafeEqual throws when inputs differ in length.
4 // Compare left against itself to keep execution time constant, then
5 // negate to produce the expected false for mismatched lengths.
6 return lengthsMatch ? crypto.subtle.timingSafeEqual(left, right) : !crypto.subtle.timingSafeEqual(left, left);
7};
8 
9export const encodeHex = (value: Uint8Array): string =>
10 Array.from(value, (byte) => byte.toString(16).padStart(2, "0")).join("");
11 
12export const encodeBase64 = (value: Uint8Array): string => {
13 let binary = "";
14 for (const byte of value) {
15 binary += String.fromCharCode(byte);
16 }
17 
18 return btoa(binary);
19};
20 
21export const decodeBase64 = (value: string): Uint8Array => {
22 let normalized = value.trim().replace(/-/gu, "+").replace(/_/gu, "/");
23 const remainder = normalized.length % 4;
24 if (remainder > 0) {
25 normalized = normalized.padEnd(normalized.length + (4 - remainder), "=");
26 }
27 
28 const binary = atob(normalized);
29 const output = new Uint8Array(binary.length);
30 for (let index = 0; index < binary.length; index += 1) {
31 output[index] = binary.charCodeAt(index);
32 }
33 
34 return output;
35};
36 
37export const encodeBase64Url = (value: Uint8Array): string =>
38 encodeBase64(value).replace(/\+/gu, "-").replace(/\//gu, "_").replace(/=+$/u, "");
39 
40export const decodeBase64Url = (value: string): Uint8Array => decodeBase64(value);
41 
42export const toArrayBuffer = (value: Uint8Array): ArrayBuffer =>
43 value.buffer.slice(value.byteOffset, value.byteOffset + value.byteLength) as ArrayBuffer;