diff --git a/README.md b/README.md index 64123e8..3a9ac2e 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,11 @@ Parse and verify in fastify web server, implements ActivityPub inbox ```ts import Fastify from 'fastify'; import fastifyRawBody from 'fastify-raw-body'; -import { parseRequestSignature, verifyDraftSignature, verifyDigestHeader } from '@misskey-dev/node-http-message-signatures'; +import { + verifyDigestHeader, + parseRequestSignature, + verifyDraftSignature, +} from '@misskey-dev/node-http-message-signatures'; /** * Prepare keyId-publicKeyPem Map @@ -101,7 +105,7 @@ await fastify.register(fastifyRawBody, { runFirst: true, }); fastify.post('/inbox', { config: { rawBody: true } }, async (request, reply) => { - const verifyDigest = verifyDigestHeader(request.raw, request.rawBody, true); + const verifyDigest = await verifyDigestHeader(request.raw, request.rawBody, true); if (!verifyDigest) { reply.code(401); return; @@ -133,7 +137,11 @@ fastify.post('/inbox', { config: { rawBody: true } }, async (request, reply) => ### Sign and Post ```ts -import { signAsDraftToRequest, genRFC3230DigestHeader, RequestLike } from '@misskey-dev/node-http-message-signatures'; +import { + genRFC3230DigestHeader, + signAsDraftToRequest, + RequestLike, +} from '@misskey-dev/node-http-message-signatures'; /** * Prepare keyId-privateKeyPem Map @@ -168,7 +176,7 @@ export async function send(url: string, body: string, keyId: string) { // TODO } else { // Draft - request.headers['Digest'] = genRFC3230DigestHeader(body); + request.headers['Digest'] = await genRFC3230DigestHeader(body); await signAsDraftToRequest(request, { keyId, privateKeyPem }, includeHeaders); diff --git a/dist/digest/digest-rfc3230.d.ts b/dist/digest/digest-rfc3230.d.ts index d8df759..2734a80 100644 --- a/dist/digest/digest-rfc3230.d.ts +++ b/dist/digest/digest-rfc3230.d.ts @@ -1,14 +1,5 @@ -/// +import { DigestSource } from './utils'; import { DigestHashAlgorithm, IncomingRequest } from '../types'; -import { BinaryLike } from 'node:crypto'; -export declare const digestHashAlgosForDecoding: { - readonly SHA: "sha1"; - readonly 'SHA-1': "sha1"; - readonly 'SHA-256': "sha256"; - readonly 'SHA-384': "sha384"; - readonly 'SHA-512': "sha512"; - readonly MD5: "md5"; -}; -export declare function genRFC3230DigestHeader(body: string, hashAlgorithm?: DigestHashAlgorithm): string; +export declare function genRFC3230DigestHeader(body: string, hashAlgorithm: DigestHashAlgorithm): Promise; export declare const digestHeaderRegEx: RegExp; -export declare function verifyRFC3230DigestHeader(request: IncomingRequest, rawBody: BinaryLike, failOnNoDigest?: boolean, errorLogger?: ((message: any) => any)): boolean; +export declare function verifyRFC3230DigestHeader(request: IncomingRequest, rawBody: DigestSource, failOnNoDigest?: boolean, errorLogger?: ((message: any) => any)): Promise; diff --git a/dist/digest/digest.d.ts b/dist/digest/digest.d.ts index 16ee9c3..af6f904 100644 --- a/dist/digest/digest.d.ts +++ b/dist/digest/digest.d.ts @@ -1,4 +1,4 @@ /// import { IncomingRequest } from "src/types"; import { BinaryLike } from "crypto"; -export declare function verifyDigestHeader(request: IncomingRequest, rawBody: BinaryLike, failOnNoDigest?: boolean, errorLogger?: ((message: any) => any)): boolean; +export declare function verifyDigestHeader(request: IncomingRequest, rawBody: BinaryLike, failOnNoDigest?: boolean, errorLogger?: ((message: any) => any)): Promise; diff --git a/dist/digest/utils.d.ts b/dist/digest/utils.d.ts index c45fba8..a209c54 100644 --- a/dist/digest/utils.d.ts +++ b/dist/digest/utils.d.ts @@ -1,6 +1,7 @@ /// -import { BinaryLike } from 'node:crypto'; +import { webcrypto as crypto } from 'node:crypto'; import { DigestHashAlgorithm } from '../types'; -export declare function createBase64Digest(body: BinaryLike, hash: DigestHashAlgorithm): string; -export declare function createBase64Digest(body: BinaryLike, hash: Ks): Map; -export declare function createBase64Digest(body: BinaryLike): string; +export type DigestSource = crypto.BufferSource | string; +export declare function createBase64Digest(body: DigestSource, hash: DigestHashAlgorithm): Promise; +export declare function createBase64Digest(body: DigestSource, hash: Ks): Promise>; +export declare function createBase64Digest(body: DigestSource): Promise; diff --git a/dist/index.cjs b/dist/index.cjs index 6c8cf8f..bbe98ad 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -49,7 +49,6 @@ __export(src_exports, { checkClockSkew: () => checkClockSkew, decodeBase64ToUint8Array: () => decodeBase64ToUint8Array, decodePem: () => decodePem, - digestHashAlgosForDecoding: () => digestHashAlgosForDecoding, digestHeaderRegEx: () => digestHeaderRegEx, encodeArrayBufferToBase64: () => encodeArrayBufferToBase64, exportPrivateKeyPem: () => exportPrivateKeyPem, @@ -308,12 +307,7 @@ function encodeArrayBufferToBase64(buffer) { return btoa(binary); } function decodeBase64ToUint8Array(base64) { - const binary = atob(base64); - const uint8Array = new Uint8Array(binary.length); - for (let i = 0; i < binary.length; i++) { - uint8Array[i] = binary.charCodeAt(i); - } - return uint8Array; + return Uint8Array.from(atob(base64), (s) => s.charCodeAt(0)); } var KeyValidationError = class extends Error { constructor(message) { @@ -792,34 +786,28 @@ async function genEd448KeyPair(keyUsage) { // src/digest/utils.ts var import_node_crypto = require("node:crypto"); -function createBase64Digest(body, hash = "sha256") { +async function createBase64Digest(body, hash = "SHA-256") { if (Array.isArray(hash)) { - return new Map(hash.map((h) => [h, createBase64Digest(body, h)])); + return new Map(await Promise.all(hash.map((h) => { + return (async () => [h, await createBase64Digest(body, h)])(); + }))); + } + if (hash === "SHA") { + hash = "SHA-1"; } - return (0, import_node_crypto.createHash)(hash).update(body).digest("base64"); + if (typeof body === "string") { + body = new TextEncoder().encode(body); + } + const hashAb = await import_node_crypto.webcrypto.subtle.digest(hash, body); + return encodeArrayBufferToBase64(hashAb); } // src/digest/digest-rfc3230.ts -var digestHashAlgosForEncoding = { - "sha1": "SHA", - "sha256": "SHA-256", - "sha384": "SHA-384", - "sha512": "SHA-512", - "md5": "MD5" -}; -var digestHashAlgosForDecoding = { - "SHA": "sha1", - "SHA-1": "sha1", - "SHA-256": "sha256", - "SHA-384": "sha384", - "SHA-512": "sha512", - "MD5": "md5" -}; -function genRFC3230DigestHeader(body, hashAlgorithm = "sha256") { - return `${digestHashAlgosForEncoding[hashAlgorithm]}=${createBase64Digest(body, hashAlgorithm)}`; +async function genRFC3230DigestHeader(body, hashAlgorithm) { + return `${hashAlgorithm}=${await createBase64Digest(body, hashAlgorithm)}`; } var digestHeaderRegEx = /^([a-zA-Z0-9\-]+)=([^\,]+)/; -function verifyRFC3230DigestHeader(request, rawBody, failOnNoDigest = true, errorLogger) { +async function verifyRFC3230DigestHeader(request, rawBody, failOnNoDigest = true, errorLogger) { let digestHeader = lcObjectGet(request.headers, "digest"); if (!digestHeader) { if (failOnNoDigest) { @@ -844,13 +832,13 @@ function verifyRFC3230DigestHeader(request, rawBody, failOnNoDigest = true, erro errorLogger("Invalid Digest header format"); return false; } - const algo = digestHashAlgosForDecoding[match[1].toUpperCase()]; + const algo = match[1]; if (!algo) { if (errorLogger) errorLogger(`Invalid Digest header algorithm: ${match[1]}`); return false; } - const hash = createBase64Digest(rawBody, algo); + const hash = await createBase64Digest(rawBody, algo); if (hash !== value) { if (errorLogger) errorLogger(`Digest header hash mismatch`); @@ -860,12 +848,12 @@ function verifyRFC3230DigestHeader(request, rawBody, failOnNoDigest = true, erro } // src/digest/digest.ts -function verifyDigestHeader(request, rawBody, failOnNoDigest = true, errorLogger) { +async function verifyDigestHeader(request, rawBody, failOnNoDigest = true, errorLogger) { const headerKeys = objectLcKeys(request.headers); if (headerKeys.has("content-digest")) { throw new Error("Not implemented yet"); } else if (headerKeys.has("digest")) { - return verifyRFC3230DigestHeader(request, rawBody, failOnNoDigest, errorLogger); + return await verifyRFC3230DigestHeader(request, rawBody, failOnNoDigest, errorLogger); } if (failOnNoDigest) { if (errorLogger) @@ -977,7 +965,6 @@ async function verifyDraftSignature(parsed, publicKeyPem, errorLogger) { checkClockSkew, decodeBase64ToUint8Array, decodePem, - digestHashAlgosForDecoding, digestHeaderRegEx, encodeArrayBufferToBase64, exportPrivateKeyPem, diff --git a/dist/index.mjs b/dist/index.mjs index 48c5ace..681cefe 100644 --- a/dist/index.mjs +++ b/dist/index.mjs @@ -210,12 +210,7 @@ function encodeArrayBufferToBase64(buffer) { return btoa(binary); } function decodeBase64ToUint8Array(base64) { - const binary = atob(base64); - const uint8Array = new Uint8Array(binary.length); - for (let i = 0; i < binary.length; i++) { - uint8Array[i] = binary.charCodeAt(i); - } - return uint8Array; + return Uint8Array.from(atob(base64), (s) => s.charCodeAt(0)); } var KeyValidationError = class extends Error { constructor(message) { @@ -693,35 +688,29 @@ async function genEd448KeyPair(keyUsage) { } // src/digest/utils.ts -import { createHash } from "node:crypto"; -function createBase64Digest(body, hash = "sha256") { +import { webcrypto as crypto } from "node:crypto"; +async function createBase64Digest(body, hash = "SHA-256") { if (Array.isArray(hash)) { - return new Map(hash.map((h) => [h, createBase64Digest(body, h)])); + return new Map(await Promise.all(hash.map((h) => { + return (async () => [h, await createBase64Digest(body, h)])(); + }))); + } + if (hash === "SHA") { + hash = "SHA-1"; } - return createHash(hash).update(body).digest("base64"); + if (typeof body === "string") { + body = new TextEncoder().encode(body); + } + const hashAb = await crypto.subtle.digest(hash, body); + return encodeArrayBufferToBase64(hashAb); } // src/digest/digest-rfc3230.ts -var digestHashAlgosForEncoding = { - "sha1": "SHA", - "sha256": "SHA-256", - "sha384": "SHA-384", - "sha512": "SHA-512", - "md5": "MD5" -}; -var digestHashAlgosForDecoding = { - "SHA": "sha1", - "SHA-1": "sha1", - "SHA-256": "sha256", - "SHA-384": "sha384", - "SHA-512": "sha512", - "MD5": "md5" -}; -function genRFC3230DigestHeader(body, hashAlgorithm = "sha256") { - return `${digestHashAlgosForEncoding[hashAlgorithm]}=${createBase64Digest(body, hashAlgorithm)}`; +async function genRFC3230DigestHeader(body, hashAlgorithm) { + return `${hashAlgorithm}=${await createBase64Digest(body, hashAlgorithm)}`; } var digestHeaderRegEx = /^([a-zA-Z0-9\-]+)=([^\,]+)/; -function verifyRFC3230DigestHeader(request, rawBody, failOnNoDigest = true, errorLogger) { +async function verifyRFC3230DigestHeader(request, rawBody, failOnNoDigest = true, errorLogger) { let digestHeader = lcObjectGet(request.headers, "digest"); if (!digestHeader) { if (failOnNoDigest) { @@ -746,13 +735,13 @@ function verifyRFC3230DigestHeader(request, rawBody, failOnNoDigest = true, erro errorLogger("Invalid Digest header format"); return false; } - const algo = digestHashAlgosForDecoding[match[1].toUpperCase()]; + const algo = match[1]; if (!algo) { if (errorLogger) errorLogger(`Invalid Digest header algorithm: ${match[1]}`); return false; } - const hash = createBase64Digest(rawBody, algo); + const hash = await createBase64Digest(rawBody, algo); if (hash !== value) { if (errorLogger) errorLogger(`Digest header hash mismatch`); @@ -762,12 +751,12 @@ function verifyRFC3230DigestHeader(request, rawBody, failOnNoDigest = true, erro } // src/digest/digest.ts -function verifyDigestHeader(request, rawBody, failOnNoDigest = true, errorLogger) { +async function verifyDigestHeader(request, rawBody, failOnNoDigest = true, errorLogger) { const headerKeys = objectLcKeys(request.headers); if (headerKeys.has("content-digest")) { throw new Error("Not implemented yet"); } else if (headerKeys.has("digest")) { - return verifyRFC3230DigestHeader(request, rawBody, failOnNoDigest, errorLogger); + return await verifyRFC3230DigestHeader(request, rawBody, failOnNoDigest, errorLogger); } if (failOnNoDigest) { if (errorLogger) @@ -878,7 +867,6 @@ export { checkClockSkew, decodeBase64ToUint8Array, decodePem, - digestHashAlgosForDecoding, digestHeaderRegEx, encodeArrayBufferToBase64, exportPrivateKeyPem, diff --git a/dist/types.d.ts b/dist/types.d.ts index 4377e82..3d10356 100644 --- a/dist/types.d.ts +++ b/dist/types.d.ts @@ -49,7 +49,7 @@ export type PrivateKey = { export type KeyAlgorithmName = 'RSASSA-PKCS1-v1_5' | 'DSA' | 'DH' | 'KEA' | 'EC' | 'Ed25519' | 'Ed448'; export type ECNamedCurve = 'P-192' | 'P-224' | 'P-256' | 'P-384' | 'P-521'; export type SignatureHashAlgorithmUpperSnake = 'SHA-1' | 'SHA-256' | 'SHA-384' | 'SHA-512' | null; -export type DigestHashAlgorithm = 'sha1' | 'sha256' | 'sha384' | 'sha512' | 'md5'; +export type DigestHashAlgorithm = 'SHA' | 'SHA-1' | 'SHA-256' | 'SHA-384' | 'SHA-512'; export type DraftSignatureAlgorithm = 'rsa-sha1' | 'rsa-sha256' | 'rsa-sha384' | 'rsa-sha512' | 'ecdsa-sha1' | 'ecdsa-sha256' | 'ecdsa-sha384' | 'ecdsa-sha512' | 'ed25519-sha512' | 'ed25519' | 'ed448'; export type ParsedDraftSignature = { version: 'draft'; diff --git a/dist/utils.d.ts b/dist/utils.d.ts index bea5185..88c0e85 100644 --- a/dist/utils.d.ts +++ b/dist/utils.d.ts @@ -16,13 +16,18 @@ export declare function objectLcKeys>(src: T): Set * convert number to Uint8Array, for ASN.1 length field */ export declare function numberToUint8Array(num: number | bigint): Uint8Array; +/** + * Generate ASN.1 length field + * @param length Length of the content + * @returns ASN.1 length field + */ export declare function genASN1Length(length: number | bigint): Uint8Array; /** - * For web + * ArrayBuffer to base64 */ export declare function encodeArrayBufferToBase64(buffer: ArrayBuffer): string; /** - * for Web + * base64 to Uint8Array */ export declare function decodeBase64ToUint8Array(base64: string): Uint8Array; export declare class KeyValidationError extends Error { diff --git a/package.json b/package.json index 7a06864..260a650 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@misskey-dev/node-http-message-signatures", - "version": "0.0.0-alpha.17", + "version": "0.0.1", "description": "", "type": "module", "keywords": [ diff --git a/src/digest/digest-rfc3230.test.ts b/src/digest/digest-rfc3230.test.ts index 6083402..bc2097d 100644 --- a/src/digest/digest-rfc3230.test.ts +++ b/src/digest/digest-rfc3230.test.ts @@ -1,14 +1,9 @@ import { digestHeaderRegEx, verifyRFC3230DigestHeader } from './digest-rfc3230'; +import { verifyDigestHeader } from './digest'; import { createBase64Digest } from './utils'; describe('rfc3230', () => { describe('regex', () => { - test('normal MD5', () => { - const result = digestHeaderRegEx.exec('MD5=foo'); - expect(result).toBeTruthy(); - expect(result![1]).toBe('MD5'); - expect(result![2]).toBe('foo'); - }); test('normal SHA-1', () => { const result = digestHeaderRegEx.exec('SHA=foo'); expect(result).toBeTruthy(); @@ -34,29 +29,32 @@ describe('rfc3230', () => { }); describe(verifyRFC3230DigestHeader, () => { - test('normal MD5', () => { - const request = { - headers: { - 'digest': `MD5=${createBase64Digest('foo', 'md5')}`, - }, - } as any; - expect(verifyRFC3230DigestHeader(request, 'foo')).toBe(true); - }); - test('normal SHA-1', () => { + test('normal SHA-1', async () => { const request = { headers: { - 'digest': `SHA=${createBase64Digest('foo', 'sha1')}`, + 'digest': `SHA=${await createBase64Digest('foo', 'SHA-1')}`, }, } as any; - expect(verifyRFC3230DigestHeader(request, 'foo')).toBe(true); + expect(await verifyRFC3230DigestHeader(request, 'foo')).toBe(true); }); - test('normal SHA-256', () => { + test('normal SHA-256', async () => { const request = { headers: { - 'digest': `SHA-256=${createBase64Digest('foo', 'sha256')}`, + 'digest': `SHA-256=${await createBase64Digest('foo', 'SHA-256')}`, }, } as any; - expect(verifyRFC3230DigestHeader(request, 'foo')).toBe(true); + expect(await verifyRFC3230DigestHeader(request, 'foo')).toBe(true); }); }); }); + +describe(verifyDigestHeader, () => { + test('RFC3230', async () => { + const request = { + headers: { + 'digest': `SHA-256=${await createBase64Digest('foo', 'SHA-256')}`, + }, + } as any; + expect(await verifyDigestHeader(request, 'foo')).toBe(true); + }); +}); diff --git a/src/digest/digest-rfc3230.ts b/src/digest/digest-rfc3230.ts index 509911b..cbc7f81 100644 --- a/src/digest/digest-rfc3230.ts +++ b/src/digest/digest-rfc3230.ts @@ -1,34 +1,16 @@ import { lcObjectGet } from '../utils'; -import { createBase64Digest } from './utils'; +import { DigestSource, createBase64Digest } from './utils'; import { DigestHashAlgorithm, IncomingRequest } from '../types'; -import { BinaryLike } from 'node:crypto'; -const digestHashAlgosForEncoding = { - 'sha1': 'SHA', - 'sha256': 'SHA-256', - 'sha384': 'SHA-384', - 'sha512': 'SHA-512', - 'md5': 'MD5', -} as const satisfies Record; - -export const digestHashAlgosForDecoding = { - 'SHA': 'sha1', - 'SHA-1': 'sha1', - 'SHA-256': 'sha256', - 'SHA-384': 'sha384', - 'SHA-512': 'sha512', - 'MD5': 'md5', -} as const satisfies Record; - -export function genRFC3230DigestHeader(body: string, hashAlgorithm: DigestHashAlgorithm = 'sha256') { - return `${digestHashAlgosForEncoding[hashAlgorithm]}=${createBase64Digest(body, hashAlgorithm)}`; +export async function genRFC3230DigestHeader(body: string, hashAlgorithm: DigestHashAlgorithm) { + return `${hashAlgorithm}=${await createBase64Digest(body, hashAlgorithm)}`; } export const digestHeaderRegEx = /^([a-zA-Z0-9\-]+)=([^\,]+)/; -export function verifyRFC3230DigestHeader( +export async function verifyRFC3230DigestHeader( request: IncomingRequest, - rawBody: BinaryLike, + rawBody: DigestSource, failOnNoDigest = true, errorLogger?: ((message: any) => any) ) { @@ -56,13 +38,13 @@ export function verifyRFC3230DigestHeader( return false; } - const algo = digestHashAlgosForDecoding[match[1].toUpperCase()] as DigestHashAlgorithm | undefined; + const algo = match[1] as DigestHashAlgorithm; if (!algo) { if (errorLogger) errorLogger(`Invalid Digest header algorithm: ${match[1]}`); return false; } - const hash = createBase64Digest(rawBody, algo); + const hash = await createBase64Digest(rawBody, algo); if (hash !== value) { if (errorLogger) errorLogger(`Digest header hash mismatch`); return false; diff --git a/src/digest/digest.ts b/src/digest/digest.ts index e4c3714..5f70a71 100644 --- a/src/digest/digest.ts +++ b/src/digest/digest.ts @@ -3,7 +3,7 @@ import { objectLcKeys } from "src/utils"; import { verifyRFC3230DigestHeader } from "./digest-rfc3230"; import { BinaryLike } from "crypto"; -export function verifyDigestHeader( +export async function verifyDigestHeader( request: IncomingRequest, rawBody: BinaryLike, failOnNoDigest = true, @@ -13,7 +13,7 @@ export function verifyDigestHeader( if (headerKeys.has('content-digest')) { throw new Error('Not implemented yet'); } else if (headerKeys.has('digest')) { - return verifyRFC3230DigestHeader(request, rawBody, failOnNoDigest, errorLogger); + return await verifyRFC3230DigestHeader(request, rawBody, failOnNoDigest, errorLogger); } if (failOnNoDigest) { if (errorLogger) errorLogger('Content-Digest or Digest header not found'); diff --git a/src/digest/utils.ts b/src/digest/utils.ts index 9745f4e..36d393f 100644 --- a/src/digest/utils.ts +++ b/src/digest/utils.ts @@ -1,15 +1,28 @@ -import { createHash, BinaryLike } from 'node:crypto'; +import { webcrypto as crypto } from 'node:crypto'; import { DigestHashAlgorithm } from '../types'; +import { encodeArrayBufferToBase64 } from '../utils'; -export function createBase64Digest(body: BinaryLike, hash: DigestHashAlgorithm): string; -export function createBase64Digest(body: BinaryLike, hash: Ks): Map; -export function createBase64Digest(body: BinaryLike): string -export function createBase64Digest( - body: BinaryLike, - hash: DigestHashAlgorithm | DigestHashAlgorithm[] = 'sha256', -): Map | string { +export type DigestSource = crypto.BufferSource | string; + +export async function createBase64Digest(body: DigestSource, hash: DigestHashAlgorithm): Promise; +export async function createBase64Digest(body: DigestSource, hash: Ks): Promise>; +export async function createBase64Digest(body: DigestSource): Promise +export async function createBase64Digest( + body: DigestSource, + hash: DigestHashAlgorithm | DigestHashAlgorithm[] = 'SHA-256', +): Promise | string> { if (Array.isArray(hash)) { - return new Map(hash.map((h) => [h, createBase64Digest(body, h)])); + return new Map(await Promise.all(hash.map((h) => { + return (async () => [h, await createBase64Digest(body, h)] as const)(); + }))); + } + + if (hash === 'SHA') { + hash = 'SHA-1'; + } + if (typeof body === 'string') { + body = (new TextEncoder()).encode(body); } - return createHash(hash).update(body).digest('base64'); + const hashAb = await crypto.subtle.digest(hash, body); + return encodeArrayBufferToBase64(hashAb); } diff --git a/src/types.ts b/src/types.ts index 3296532..a8dcaef 100644 --- a/src/types.ts +++ b/src/types.ts @@ -56,7 +56,7 @@ export type PrivateKey = { export type KeyAlgorithmName = 'RSASSA-PKCS1-v1_5' | 'DSA' | 'DH' | 'KEA' | 'EC' | 'Ed25519' | 'Ed448'; export type ECNamedCurve = 'P-192' | 'P-224' | 'P-256' | 'P-384' | 'P-521'; export type SignatureHashAlgorithmUpperSnake = 'SHA-1' | 'SHA-256' | 'SHA-384' | 'SHA-512' | null; -export type DigestHashAlgorithm = 'sha1' | 'sha256' | 'sha384' | 'sha512' | 'md5'; +export type DigestHashAlgorithm = 'SHA' | 'SHA-1' | 'SHA-256' | 'SHA-384' | 'SHA-512'; // sign専用 export type DraftSignatureAlgorithm = 'rsa-sha1' | 'rsa-sha256' | 'rsa-sha384' | 'rsa-sha512' | 'ecdsa-sha1' | 'ecdsa-sha256' | 'ecdsa-sha384' | 'ecdsa-sha512' | 'ed25519-sha512' | 'ed25519' | 'ed448'; diff --git a/src/utils.ts b/src/utils.ts index 9ac1fa9..d23295c 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -46,6 +46,11 @@ export function numberToUint8Array(num: number | bigint): Uint8Array { return viewUint8Array.slice(firstNonZero); } +/** + * Generate ASN.1 length field + * @param length Length of the content + * @returns ASN.1 length field + */ export function genASN1Length(length: number | bigint): Uint8Array { if (length < 0x80n) { return new Uint8Array([Number(length)]); @@ -55,7 +60,7 @@ export function genASN1Length(length: number | bigint): Uint8Array { } /** - * For web + * ArrayBuffer to base64 */ export function encodeArrayBufferToBase64(buffer: ArrayBuffer): string { const uint8Array = new Uint8Array(buffer); @@ -64,15 +69,10 @@ export function encodeArrayBufferToBase64(buffer: ArrayBuffer): string { } /** - * for Web + * base64 to Uint8Array */ export function decodeBase64ToUint8Array(base64: string): Uint8Array { - const binary = atob(base64); - const uint8Array = new Uint8Array(binary.length); - for (let i = 0; i < binary.length; i++) { - uint8Array[i] = binary.charCodeAt(i); - } - return uint8Array; + return Uint8Array.from(atob(base64), s => s.charCodeAt(0)); } export class KeyValidationError extends Error { diff --git a/test/performance/draft.js b/test/performance/draft.js index c78aebf..d979b60 100644 --- a/test/performance/draft.js +++ b/test/performance/draft.js @@ -38,7 +38,7 @@ console.log('Performance test, TRYES:', TRYES); */ { const request = getBasicOutgoingRequest(); - request.headers['Digest'] = genRFC3230DigestHeader(request.body, 'sha256'); + request.headers['Digest'] = await genRFC3230DigestHeader(request.body, 'SHA-256'); /** * RSA4096, SHA-256 @@ -78,7 +78,7 @@ console.log('Performance test, TRYES:', TRYES); */ { const request = getBasicOutgoingRequest(); - request.headers['Digest'] = genRFC3230DigestHeader(request.body, 'sha256'); + request.headers['Digest'] = await genRFC3230DigestHeader(request.body, 'SHA-256'); await signAsDraftToRequest(request, { keyId: 'test', privateKeyPem: rsa4096.privateKey }, basicIncludeHeaders, { hashAlgorithm: 'SHA-256' }); const parsed = parseRequestSignature(request); @@ -122,7 +122,7 @@ console.log('Performance test, TRYES:', TRYES); */ { const request = getBasicOutgoingRequest(); - request.headers['Digest'] = genRFC3230DigestHeader(request.body, 'sha256'); + request.headers['Digest'] = await genRFC3230DigestHeader(request.body, 'SHA-256'); await signAsDraftToRequest(request, { keyId: 'test', privateKeyPem: ed25519.privateKey }, basicIncludeHeaders, { hashAlgorithm: null }); const parsed = parseRequestSignature(request);