From 546f31cd0f6baa5112c70da87a6111168fb6d57e Mon Sep 17 00:00:00 2001 From: Mircea Nistor Date: Wed, 27 Sep 2023 20:53:23 +0200 Subject: [PATCH] fix: accept 32 or 64 bytes as keys for EdDSASigner (#299) Only the first 32 bytes are used as the actual key fixes #289 --- src/__tests__/EdDSASigner.test.ts | 4 ++-- src/signers/EdDSASigner.ts | 14 ++++++++++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/__tests__/EdDSASigner.test.ts b/src/__tests__/EdDSASigner.test.ts index 48d5bbb0..f120a800 100644 --- a/src/__tests__/EdDSASigner.test.ts +++ b/src/__tests__/EdDSASigner.test.ts @@ -54,12 +54,12 @@ describe('EdDSASigner', () => { ) }) - it('refuses wrong key size (half)', async () => { + it('accepts 32 byte keys size (github #289)', async () => { expect.assertions(1) const privateKey = '278a5de700e29faae8e40e366ec5012b5ec63d36ec77e8a2417154cc1d25383f' expect(() => { EdDSASigner(hexToBytes(privateKey)) - }).toThrowError(/^bad_key: Invalid private key format.*/) + }).not.toThrow() }) it('refuses wrong key size', async () => { diff --git a/src/signers/EdDSASigner.ts b/src/signers/EdDSASigner.ts index 0c71491e..e30cce44 100644 --- a/src/signers/EdDSASigner.ts +++ b/src/signers/EdDSASigner.ts @@ -5,7 +5,13 @@ import { bytesToBase64url, stringToBytes } from '../util.js' /** * Creates a configured signer function for signing data using the EdDSA (Ed25519) algorithm. * - * The signing function itself takes the data as a `Uint8Array` or `string` and returns a `base64Url`-encoded signature + * The private key is expected to be a `Uint8Array` of 32 bytes, but for compatibility 64 bytes are also acceptable. + * Users of `@stablelib/ed25519` or `tweetnacl` will be able to use the 64 byte secret keys that library generates. + * These libraries precompute the public key and append it as the last 32 bytes of the secretKey, to speed up later + * signing operations. + * + * The signing function itself takes the data as a `Uint8Array` or utf8 `string` and returns a `base64Url`-encoded + * signature * * @example * ```typescript @@ -13,13 +19,13 @@ import { bytesToBase64url, stringToBytes } from '../util.js' * const signature: string = await sign(data) * ``` * - * @param {String} secretKey a 64 byte secret key as `Uint8Array` + * @param {String} secretKey a 32 or 64 byte secret key as `Uint8Array` * @return {Function} a configured signer function `(data: string | Uint8Array): Promise` */ export function EdDSASigner(secretKey: Uint8Array): Signer { const privateKeyBytes: Uint8Array = secretKey - if (privateKeyBytes.length !== 64) { - throw new Error(`bad_key: Invalid private key format. Expecting 64 bytes, but got ${privateKeyBytes.length}`) + if (![32, 64].includes(privateKeyBytes.length)) { + throw new Error(`bad_key: Invalid private key format. Expecting 32 or 64 bytes, but got ${privateKeyBytes.length}`) } return async (data: string | Uint8Array): Promise => { const dataBytes: Uint8Array = typeof data === 'string' ? stringToBytes(data) : data