Skip to content

Instantly share code, notes, and snippets.

@CMCDragonkai
Last active June 21, 2023 13:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CMCDragonkai/6724fb42800cd0b8c438ef543f1ab604 to your computer and use it in GitHub Desktop.
Save CMCDragonkai/6724fb42800cd0b8c438ef543f1ab604 to your computer and use it in GitHub Desktop.
Crypto generation of RSA, ECDSA and Ed25519 KeyPairs using Node Crypto and Webcrypto
import type { JsonWebKey } from 'crypto';
import crypto from 'crypto';
/**
* Generates equivalent to RSASSA-PKCS1-v1_5 keypair
*/
async function generateKeyPairRSA(): Promise<{
publicKey: JsonWebKey,
privateKey: JsonWebKey
}> {
return new Promise((resolve, reject) => {
crypto.generateKeyPair('rsa', {
modulusLength: 2048,
}, (err, publicKey, privateKey) => {
if (err) {
reject(err);
} else {
resolve({
publicKey: publicKey.export({ format: 'jwk' }),
privateKey: privateKey.export({ format: 'jwk' }),
});
}
});
});
}
async function generateKeyPairECDSA(): Promise<{
publicKey: JsonWebKey,
privateKey: JsonWebKey,
}> {
return new Promise((resolve, reject) => {
crypto.generateKeyPair('ec', {
namedCurve: 'P-256',
}, (err, publicKey, privateKey) => {
if (err) {
reject(err);
} else {
resolve({
publicKey: publicKey.export({
format: 'jwk'
}),
privateKey: privateKey.export({
format: 'jwk'
})
});
}
});
});
}
async function generateKeyPairEd25519(): Promise<{
publicKey: JsonWebKey,
privateKey: JsonWebKey
}> {
return new Promise((resolve, reject) => {
crypto.generateKeyPair(
'ed25519',
undefined,
(e, publicKey, privateKey) => {
if (e) {
reject(e);
} else {
resolve({
publicKey: publicKey.export({
format: 'jwk'
}),
privateKey: privateKey.export({
format: 'jwk'
})
});
}
}
);
});
}
async function main() {
console.log(await generateKeyPairRSA());
console.log(await generateKeyPairECDSA());
console.log(await generateKeyPairEd25519());
}
void main();
import { Crypto } from '@peculiar/webcrypto';
/**
* WebCrypto polyfill from @peculiar/webcrypto
* This behaves differently with respect to Ed25519 keys
* See: https://github.com/PeculiarVentures/webcrypto/issues/55
*/
const webcrypto = new Crypto();
/**
* Generates equivalent to RSASSA-PKCS1-v1_5 keypair
*/
async function generateKeyPairRSA(): Promise<{
publicKey: JsonWebKey;
privateKey: JsonWebKey;
}> {
const keyPair = await webcrypto.subtle.generateKey(
{
name: 'RSASSA-PKCS1-v1_5',
modulusLength: 2048,
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
hash: 'SHA-256'
},
true,
[
'sign',
'verify',
]
);
return {
publicKey: await webcrypto.subtle.exportKey(
'jwk',
keyPair.publicKey
),
privateKey: await webcrypto.subtle.exportKey(
'jwk',
keyPair.privateKey
)
};
}
async function generateKeyPairECDSA(): Promise<{
publicKey: JsonWebKey;
privateKey: JsonWebKey;
}> {
const keyPair = await webcrypto.subtle.generateKey(
{
name: 'ECDSA',
namedCurve: 'P-256'
},
true,
[
'sign',
'verify'
]
);
return {
publicKey: await webcrypto.subtle.exportKey(
'jwk',
keyPair.publicKey
),
privateKey: await webcrypto.subtle.exportKey(
'jwk',
keyPair.privateKey
)
};
}
async function generateKeyPairEd25519(): Promise<{
publicKey: JsonWebKey;
privateKey: JsonWebKey;
}> {
const keyPair = await webcrypto.subtle.generateKey(
{
name: 'EdDSA',
namedCurve: 'Ed25519'
},
true,
[
'sign',
'verify'
]
) as CryptoKeyPair;
return {
publicKey: await webcrypto.subtle.exportKey(
'jwk',
keyPair.publicKey
),
privateKey: await webcrypto.subtle.exportKey(
'jwk',
keyPair.privateKey
)
};
}
async function main() {
console.log(await generateKeyPairRSA());
console.log(await generateKeyPairECDSA());
console.log(await generateKeyPairEd25519());
}
void main();
import { webcrypto } from 'crypto';
/**
* Generates equivalent to Node's regular RSA keypair
*/
async function generateKeyPairRSA(): Promise<{
publicKey: JsonWebKey;
privateKey: JsonWebKey;
}> {
const keyPair = await webcrypto.subtle.generateKey(
{
name: 'RSASSA-PKCS1-v1_5',
modulusLength: 2048,
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
hash: 'SHA-256'
},
true,
[
'sign',
'verify',
]
);
return {
publicKey: await webcrypto.subtle.exportKey(
'jwk',
keyPair.publicKey
),
privateKey: await webcrypto.subtle.exportKey(
'jwk',
keyPair.privateKey
)
};
}
async function generateKeyPairECDSA(): Promise<{
publicKey: JsonWebKey;
privateKey: JsonWebKey;
}> {
const keyPair = await webcrypto.subtle.generateKey(
{
name: 'ECDSA',
namedCurve: 'P-256'
},
true,
[
'sign',
'verify'
]
);
return {
publicKey: await webcrypto.subtle.exportKey(
'jwk',
keyPair.publicKey
),
privateKey: await webcrypto.subtle.exportKey(
'jwk',
keyPair.privateKey
)
};
}
/**
* This is only available inside Node.
* This is not part of the webcrypto specification.
*/
async function generateKeyPairEd25519(): Promise<{
publicKey: JsonWebKey;
privateKey: JsonWebKey;
}> {
const keyPair = await webcrypto.subtle.generateKey(
{
name: 'ED25519',
},
true,
[
'sign',
'verify'
]
) as webcrypto.CryptoKeyPair;
return {
publicKey: await webcrypto.subtle.exportKey(
'jwk',
keyPair.publicKey
),
privateKey: await webcrypto.subtle.exportKey(
'jwk',
keyPair.privateKey
)
};
}
async function main() {
console.log(await generateKeyPairRSA());
console.log(await generateKeyPairECDSA());
console.log(await generateKeyPairEd25519());
}
void main();
@CMCDragonkai
Copy link
Author

For RSA, the most compatible is always the PKCS1-v1.5, this is most commonly used in TLS.

For ECDSA, the most common curve is P-256.

Ed25519 is the best of course, but it's not fully supported everywhere.

@CMCDragonkai
Copy link
Author

Note that @peculiar/webcrypto has different API with webcrypto in Node.js for Ed25519.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment