oven-sh / bun

Incredibly fast JavaScript runtime, bundler, test runner, and package manager ā€“ all in one
https://bun.sh
Other
73.53k stars 2.71k forks source link

crypto createPrivateKey elliptic curve "Invalid EC private key" #10475

Open hunterchainstarters opened 5 months ago

hunterchainstarters commented 5 months ago

What version of Bun is running?

1.1.4

What platform is your computer?

Linux 6.5.0-28-generic x86_64 x86_64

What steps can reproduce the bug?

Below is a code snippet to reproduce the error:

import { createPrivateKey } from 'crypto';
import elliptic from 'elliptic';

const getSigningKey = (key: string, secret: string) => {
    const pubKey = new elliptic.ec('p256').keyFromPublic(Buffer.from(key, 'base64'));
    const x = Buffer.from(pubKey.getPublic().getX().toBuffer()).toString('base64');
    const y = Buffer.from(pubKey.getPublic().getY().toBuffer()).toString('base64');
    return createPrivateKey({
    key: { kty: 'EC', crv: 'P-256', x, y, d: secret },
    format: 'jwk',
  })
};

const key = getSigningKey('A3DCYHILTmyFdTD+HS/5qzBPzW04RweI0fzQeny3qmSu', 'IXotyQe5J6jmiSc76GtwdfmWRfPEUPJRgEJGYKxjUFY')
console.log(`šŸƒ ~ key:`, key)

What is the expected behavior?

The code snippet (example.ts) produces a key object in ts-node:

šŸƒ ~ key: PrivateKeyObject [KeyObject] { [Symbol(kKeyType)]: 'private' }

What do you see instead?

But, in bun I get this error:

 9 |     key: { kty: 'EC', crv: 'P-256', x, y, d: secret },
10 |     format: 'jwk',
11 |   })
12 | };
13 | 
14 | const key = getSigningKey('A3DCYHILTmyFdTD+HS/5qzBPzW04RweI0fzQeny3qmSu', 'IXotyQe5J6jmiSc76GtwdfmWRfPEUPJRgEJGYKxjUFY')
                 ^
TypeError: Invalid EC private key
      at node:crypto:48:63
      at /home/$USER/code/example.ts:14:13

Additional information

migrating to bun, if this is working :)

Edit: The below code snippet seems to work, changing base64 encodings to base64url

import { createPrivateKey } from 'crypto';
import elliptic from 'elliptic';

const getSigningKey = (key: string, secret: string) => {
    const pubKey = new elliptic.ec('p256').keyFromPublic(Buffer.from(key, 'base64url'));
    const x = Buffer.from(pubKey.getPublic().getX().toBuffer()).toString('base64url');
    const y = Buffer.from(pubKey.getPublic().getY().toBuffer()).toString('base64url');
    return createPrivateKey({
    key: { kty: 'EC', crv: 'P-256', x, y, d: secret },
    format: 'jwk',
  })
};

const key = getSigningKey('A3DCYHILTmyFdTD+HS/5qzBPzW04RweI0fzQeny3qmSu', 'IXotyQe5J6jmiSc76GtwdfmWRfPEUPJRgEJGYKxjUFY')
console.log(`šŸƒ ~ key:`, key)
ioitiki commented 5 months ago

+1

ioitiki commented 4 months ago

@Electroid do you know if there is any discussion to tackle this bug in the upcoming releases? It is currently preventing my team from fully switching to Bun. Thanks :D

ioitiki commented 3 months ago

i see we've done several updates since this was discussed last (1.1.4 now it's on 1.1.15). any update on this bug?

@Electroid

Electroid commented 3 months ago

No update right now. This is among a backlog of bugs we want to fix.

ioitiki commented 3 months ago

No update right now. This is among a backlog of bugs we want to fix.

Thanks for the response šŸ˜Š

wpaulino commented 1 month ago

Encoding the strings as base64url should help you get around it for now. The JSON Web Algorithms RFC (https://datatracker.ietf.org/doc/html/rfc7518) mandates the use of base64url everywhere, but Node generally follows https://infra.spec.whatwg.org/#forgiving-base64-decode. Unfortunately, the relevant code path here for a lot of the crypto operations that involve some kind of base64 decoding go straight into the C++ backend, which does not support the mixed decoding approach at the moment, and instead always assumes you've given it a base64url encoded string.