Skip to content

Commit

Permalink
feat: allow specifying modulusLength when generating RSA Key Pairs
Browse files Browse the repository at this point in the history
resolves #121
  • Loading branch information
panva committed Dec 1, 2020
1 parent 98a6844 commit 5f7a0e9
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 18 deletions.
31 changes: 20 additions & 11 deletions src/runtime/browser/generate.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import crypto, { ensureSecureContext } from './webcrypto.js'
import { JOSENotSupported } from '../../util/errors.js'
import random from './random.js'

const modulusLength = 2048
const publicExponent = new Uint8Array([0x01, 0x00, 0x01])
import type { GenerateKeyPairOptions } from '../../util/generate_key_pair.js'

export async function generateSecret(alg: string) {
let length: number
Expand Down Expand Up @@ -46,19 +44,30 @@ export async function generateSecret(alg: string) {
return crypto.subtle.generateKey(algorithm, false, keyUsages) as Promise<CryptoKey>
}

interface Options {
crv?: string
function getModulusLengthOption(options?: GenerateKeyPairOptions) {
const modulusLength = options?.modulusLength ?? 2048
if (typeof modulusLength !== 'number' || modulusLength < 2048) {
throw new JOSENotSupported(
'invalid or unsupported modulusLength option provided, 2048 bits or larger keys must be used',
)
}
return modulusLength
}

export async function generateKeyPair(alg: string, options?: Options) {
export async function generateKeyPair(alg: string, options?: GenerateKeyPairOptions) {
let algorithm: RsaHashedKeyGenParams | EcKeyGenParams
let keyUsages: KeyUsage[]

switch (alg) {
case 'PS256':
case 'PS384':
case 'PS512':
algorithm = { name: 'RSA-PSS', hash: `SHA-${alg.substr(-3)}`, publicExponent, modulusLength }
algorithm = {
name: 'RSA-PSS',
hash: `SHA-${alg.substr(-3)}`,
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
modulusLength: getModulusLengthOption(options),
}
keyUsages = ['sign', 'verify']
break
case 'RS256':
Expand All @@ -67,8 +76,8 @@ export async function generateKeyPair(alg: string, options?: Options) {
algorithm = {
name: 'RSASSA-PKCS1-v1_5',
hash: `SHA-${alg.substr(-3)}`,
publicExponent,
modulusLength,
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
modulusLength: getModulusLengthOption(options),
}
keyUsages = ['sign', 'verify']
break
Expand All @@ -79,8 +88,8 @@ export async function generateKeyPair(alg: string, options?: Options) {
algorithm = {
name: 'RSA-OAEP',
hash: `SHA-${parseInt(alg.substr(-3), 10) || 1}`,
publicExponent,
modulusLength,
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
modulusLength: getModulusLengthOption(options),
}
keyUsages = ['decrypt', 'unwrapKey', 'encrypt', 'wrapKey']
break
Expand Down
25 changes: 18 additions & 7 deletions src/runtime/node/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import { createSecretKey, generateKeyPair as generateKeyPairCb } from 'crypto'
import { promisify } from 'util'

import random from './random.js'
import { setModulusLength } from './check_modulus_length.js'
import { JOSENotSupported } from '../../util/errors.js'
import type { GenerateKeyPairOptions } from '../../util/generate_key_pair.js'

const generate = promisify(generateKeyPairCb)

Expand Down Expand Up @@ -35,11 +37,7 @@ export async function generateSecret(alg: string) {
return createSecretKey(random(new Uint8Array(length >> 3)))
}

interface Options {
crv?: string
}

export async function generateKeyPair(alg: string, options?: Options) {
export async function generateKeyPair(alg: string, options?: GenerateKeyPairOptions) {
switch (alg) {
case 'RS256':
case 'RS384':
Expand All @@ -51,8 +49,21 @@ export async function generateKeyPair(alg: string, options?: Options) {
case 'RSA-OAEP-256':
case 'RSA-OAEP-384':
case 'RSA-OAEP-512':
case 'RSA1_5':
return generate('rsa', { modulusLength: 2048, publicExponent: 0x10001 })
case 'RSA1_5': {
const modulusLength = options?.modulusLength ?? 2048
if (typeof modulusLength !== 'number' || modulusLength < 2048) {
throw new JOSENotSupported(
'invalid or unsupported modulusLength option provided, 2048 bits or larger keys must be used',
)
}
const keypair = await generate('rsa', {
modulusLength,
publicExponent: 0x10001,
})
setModulusLength(keypair.privateKey, modulusLength)
setModulusLength(keypair.publicKey, modulusLength)
return keypair
}
case 'ES256':
return generate('ec', { namedCurve: 'P-256' })
case 'ES256K':
Expand Down
6 changes: 6 additions & 0 deletions src/util/generate_key_pair.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ export interface GenerateKeyPairOptions {
* the given JWA algorithm identifier.
*/
crv?: string

/**
* A hint for RSA algorithms to generate an RSA key of a given `modulusLength`
* (Key size in bits). JOSE requires 2048 bits or larger. Default is 2048.
*/
modulusLength?: number
}

/**
Expand Down

0 comments on commit 5f7a0e9

Please sign in to comment.