Skip to content

Add ncrypto dependency, implement key handling operations #3463

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 24 commits into from
Feb 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
8fb5acd
Add ncrypto dependency
jasnell Feb 4, 2025
5901ca2
Use ncrypto for key derivation operations
jasnell Feb 4, 2025
5a34ca2
Use ncrypto for spkac apis
jasnell Feb 4, 2025
bf8468d
Use ncrypto for prime generation/checks
jasnell Feb 4, 2025
e253d49
Refinements to the node:crypto SecretKey impl
jasnell Feb 5, 2025
1baecbd
Begin working on createPrivateKey
jasnell Feb 6, 2025
b981699
Implement more of the private key details
jasnell Feb 6, 2025
e3ccb30
Implement createPublicKey
jasnell Feb 7, 2025
8b0706c
Consolidate ncrypto::Buffer creation into utility
jasnell Feb 7, 2025
62ca57f
Handle additional code review nits
jasnell Feb 7, 2025
3450e51
node:crypto asymmetric key jwk export
jasnell Feb 7, 2025
1c1061e
Implement JWK import/export for RSA, EC, OKP keys
jasnell Feb 7, 2025
f706b8c
Temporarily use ncrypto dev branch
jasnell Feb 7, 2025
7aff514
Remove now obsolete todo comment
jasnell Feb 7, 2025
f627a86
Support creating public key from PrivateKeyObject
jasnell Feb 7, 2025
c64fc73
Implement generateKey()/generateKeySync() for aes/hmac keys
jasnell Feb 8, 2025
317a08d
Address review feedback
jasnell Feb 10, 2025
50c209f
Argument validation for generateKeyPair
jasnell Feb 10, 2025
60bb9dc
Implement more key pair generation
jasnell Feb 11, 2025
35837ac
Additional keygen details
jasnell Feb 11, 2025
e802d54
Fixups to support internal use of boringssl+fips
jasnell Feb 13, 2025
418741f
Temporarily use ncrypto dev branch
jasnell Feb 13, 2025
3a480b0
Add some additional comments/notes on crypto keys impl
jasnell Feb 14, 2025
186fa11
Update ncrypto details in WORKSPACE
jasnell Feb 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .github/secret_scanning.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,28 @@ paths-ignore:
- "src/workerd/api/node/crypto_dh-test.js"
- "src/workerd/jsg/url-test-corpus-success.h"
- "src/workerd/api/node/tests/crypto_x509-test.js"
- "src/workerd/api/node/tests/fixtures/dh_private.pem"
- "src/workerd/api/node/tests/fixtures/dsa_private_pkcs8.pem"
- "src/workerd/api/node/tests/fixtures/ed25519_private.pem"
- "src/workerd/api/node/tests/fixtures/rsa_private_encrypted.pem"
- "src/workerd/api/node/tests/fixtures/rsa_pss_private_2048_sha1_sha1_20.pem"
- "src/workerd/api/node/tests/fixtures/dsa_private_1025.pem"
- "src/workerd/api/node/tests/fixtures/ec_p256_private.pem"
- "src/workerd/api/node/tests/fixtures/ed448_private.pem"
- "src/workerd/api/node/tests/fixtures/rsa_private.pem"
- "src/workerd/api/node/tests/fixtures/rsa_pss_private_2048_sha256_sha256_16.pem"
- "src/workerd/api/node/tests/fixtures/dsa_private_encrypted_1025.pem"
- "src/workerd/api/node/tests/fixtures/ec_p384_private.pem"
- "src/workerd/api/node/tests/fixtures/rsa_private_2048.pem"
- "src/workerd/api/node/tests/fixtures/rsa_private_pkcs8_bad.pem"
- "src/workerd/api/node/tests/fixtures/rsa_pss_private_2048_sha512_sha256_20.pem"
- "src/workerd/api/node/tests/fixtures/dsa_private_encrypted.pem"
- "src/workerd/api/node/tests/fixtures/ec_p521_private.pem"
- "src/workerd/api/node/tests/fixtures/rsa_private_4096.pem"
- "src/workerd/api/node/tests/fixtures/rsa_private_pkcs8.pem"
- "src/workerd/api/node/tests/fixtures/x25519_private.pem"
- "src/workerd/api/node/tests/fixtures/dsa_private.pem"
- "src/workerd/api/node/tests/fixtures/ec_secp256k1_private.pem"
- "src/workerd/api/node/tests/fixtures/rsa_private_b.pem"
- "src/workerd/api/node/tests/fixtures/rsa_pss_private_2048.pem"
- "src/workerd/api/node/tests/fixtures/x448_private.pem"
8 changes: 8 additions & 0 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,14 @@ http_archive(
url = "https://github.com/nodejs/nbytes/archive/refs/tags/v0.1.1.tar.gz",
)

http_archive(
name = "ncrypto",
sha256 = "b438cf71b1c24036e388f191a348cdc76aca75310eabca0fef5d81d5032a5d20",
strip_prefix = "ncrypto-1.0.1",
type = "tgz",
url = "https://github.com/nodejs/ncrypto/archive/refs/tags/1.0.1.tar.gz",
)

http_archive(
name = "pyodide",
build_file = "//:build/BUILD.pyodide",
Expand Down
2 changes: 2 additions & 0 deletions src/node/crypto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
createDiffieHellman,
createDiffieHellmanGroup,
getDiffieHellman,
diffieHellman,
} from 'node-internal:crypto_dh';

import {
Expand Down Expand Up @@ -77,6 +78,7 @@ export {
createDiffieHellman,
createDiffieHellmanGroup,
getDiffieHellman,
diffieHellman,
// Random
randomBytes,
randomFillSync,
Expand Down
69 changes: 56 additions & 13 deletions src/node/internal/crypto.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ export function randomPrime(
rem?: ArrayBufferView
): ArrayBuffer;

export function statelessDH(
privateKey: CryptoKey,
publicKey: CryptoKey
): ArrayBuffer;

// X509Certificate
export interface CheckOptions {
subject?: string;
Expand Down Expand Up @@ -113,6 +118,40 @@ export function createPublicKey(
key: InnerCreateAsymmetricKeyOptions
): CryptoKey;

export interface RsaKeyPairOptions {
type: string;
modulusLength: number;
publicExponent: number;
saltLength?: number;
hashAlgorithm?: string;
mgf1HashAlgorithm?: string;
}

export interface DsaKeyPairOptions {
modulusLength: number;
divisorLength: number;
}

export interface EcKeyPairOptions {
namedCurve: string;
paramEncoding: ParamEncoding;
}

export interface EdKeyPairOptions {
type: string;
}

export interface DhKeyPairOptions {
primeOrGroup: BufferSource | number | string;
generator?: number;
}

export function generateRsaKeyPair(options: RsaKeyPairOptions): CryptoKeyPair;
export function generateDsaKeyPair(options: DsaKeyPairOptions): CryptoKeyPair;
export function generateEcKeyPair(options: EcKeyPairOptions): CryptoKeyPair;
export function generateEdKeyPair(options: EdKeyPairOptions): CryptoKeyPair;
export function generateDhKeyPair(options: DhKeyPairOptions): CryptoKeyPair;

// Spkac
export function verifySpkac(input: ArrayBufferView | ArrayBuffer): boolean;
export function exportPublicKey(
Expand Down Expand Up @@ -206,14 +245,7 @@ export type SecretKeyFormat = 'buffer' | 'jwk';
export type AsymmetricKeyFormat = 'pem' | 'der' | 'jwk';
export type PublicKeyEncoding = 'pkcs1' | 'spki';
export type PrivateKeyEncoding = 'pkcs1' | 'pkcs8' | 'sec1';
export type AsymmetricKeyType =
| 'rsa'
| 'rsa-pss'
| 'dsa'
| 'ec'
| 'x25519'
| 'ed25519'
| 'dh';
export type AsymmetricKeyType = 'rsa' | 'ec' | 'x25519' | 'ed25519' | 'dh';
export type SecretKeyType = 'hmac' | 'aes';
export type ParamEncoding = 'named' | 'explicit';

Expand Down Expand Up @@ -261,19 +293,27 @@ export interface AsymmetricKeyDetails {
namedCurve?: string;
}

// The user-provided options passed to createPrivateKey or createPublicKey.
// This will be processed into an InnerCreateAsymmetricKeyOptions.
export interface CreateAsymmetricKeyOptions {
key: string | ArrayBuffer | ArrayBufferView | JsonWebKey;
format?: AsymmetricKeyFormat;
type?: PublicKeyEncoding | PrivateKeyEncoding;
passphrase?: string | Uint8Array;
passphrase?: string | Uint8Array | Buffer;
encoding?: string;
}

// The processed key options. The key property will be one of either
// an ArrayBuffer, an ArrayBufferView, a JWK, or a CryptoKey. The
// format and type options will be validated to known good values,
// and the passphrase will either be undefined or an ArrayBufferView.
export interface InnerCreateAsymmetricKeyOptions {
key?: ArrayBuffer | ArrayBufferView | JsonWebKey | CryptoKey;
format?: AsymmetricKeyFormat;
type?: PublicKeyEncoding | PrivateKeyEncoding;
passphrase?: Uint8Array;
// CryptoKey is only used when importing a public key derived from
// an existing private key.
key: ArrayBuffer | ArrayBufferView | JsonWebKey | CryptoKey;
format: AsymmetricKeyFormat;
type: PublicKeyEncoding | PrivateKeyEncoding | undefined;
passphrase: Buffer | ArrayBuffer | ArrayBufferView | undefined;
}

export interface GenerateKeyOptions {
Expand All @@ -283,14 +323,17 @@ export interface GenerateKeyOptions {
export interface GenerateKeyPairOptions {
modulusLength?: number;
publicExponent?: number | bigint;
hash?: string;
hashAlgorithm?: string;
mgf1Hash?: string;
mgf1HashAlgorithm?: string;
saltLength?: number;
divisorLength?: number;
namedCurve?: string;
prime?: Uint8Array;
primeLength?: number;
generator?: number;
group?: string;
groupName?: string;
paramEncoding?: ParamEncoding;
publicKeyEncoding?: PublicKeyExportOptions;
Expand Down
54 changes: 53 additions & 1 deletion src/node/internal/crypto_dh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,19 @@ import { Buffer } from 'node-internal:internal_buffer';
import { default as cryptoImpl } from 'node-internal:crypto';
type ArrayLike = cryptoImpl.ArrayLike;

import {
isKeyObject,
getKeyObjectHandle,
type PrivateKeyObject,
type PublicKeyObject,
} from 'node-internal:crypto_keys';

import {
ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY,
ERR_INVALID_ARG_TYPE,
} from 'node-internal:internal_errors';

import { validateInt32 } from 'node-internal:validators';
import { validateInt32, validateObject } from 'node-internal:validators';

import {
isArrayBufferView,
Expand Down Expand Up @@ -257,3 +264,48 @@ export function createDiffieHellmanGroup(name: string): DiffieHellmanGroup {
export function getDiffieHellman(name: string): DiffieHellmanGroup {
return createDiffieHellmanGroup(name);
}

export interface DiffieHellmanKeyPair {
publicKey: PublicKeyObject;
privateKey: PrivateKeyObject;
}

export function diffieHellman(options: DiffieHellmanKeyPair) {
validateObject(options, 'options');
const { publicKey, privateKey } = options;
if (!isKeyObject(publicKey)) {
throw new ERR_INVALID_ARG_TYPE('options.publicKey', 'KeyObject', publicKey);
}
if (!isKeyObject(privateKey)) {
throw new ERR_INVALID_ARG_TYPE(
'options.privateKey',
'KeyObject',
privateKey
);
}
if (publicKey.type !== 'public') {
throw new ERR_INVALID_ARG_TYPE(
'options.publicKey',
'public key',
publicKey
);
}
if (privateKey.type !== 'private') {
throw new ERR_INVALID_ARG_TYPE(
'options.privateKey',
'private key',
privateKey
);
}
if (
publicKey.asymmetricKeyType !== 'dh' ||
privateKey.asymmetricKeyType !== 'dh'
) {
throw new ERR_INVALID_ARG_TYPE('options', 'DiffieHellman keys', options);
}
const res = cryptoImpl.statelessDH(
getKeyObjectHandle(privateKey),
getKeyObjectHandle(publicKey)
);
return Buffer.from(res);
}
Loading
Loading