Skip to content

Commit

Permalink
fix: accept 32 or 64 bytes as keys for EdDSASigner (#299)
Browse files Browse the repository at this point in the history
Only the first 32 bytes are used as the actual key

fixes #289
  • Loading branch information
mirceanis authored Sep 27, 2023
1 parent c1293c8 commit 546f31c
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 6 deletions.
4 changes: 2 additions & 2 deletions src/__tests__/EdDSASigner.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
Expand Down
14 changes: 10 additions & 4 deletions src/signers/EdDSASigner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,27 @@ 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
* const sign: Signer = EdDSASigner(process.env.PRIVATE_KEY)
* 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<string>`
*/
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<string> => {
const dataBytes: Uint8Array = typeof data === 'string' ? stringToBytes(data) : data
Expand Down

0 comments on commit 546f31c

Please sign in to comment.