Last active
June 21, 2023 13:23
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); |
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
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.