cryptokeycomposer
A library to decompose and compose crypto keys of different types and formats.
Installation
$ npm install cryptokeycomposer
This library is written in modern JavaScript and is published in both CommonJS and ES module transpiled variants. If you target older browsers please make sure to transpile accordingly. Moreover, some of this library's dependencies use the native Node Buffer module. This means that you must compile your app through a bundler that automatically injects a Buffer compatible implementation for the browser, such as Webpack.
API
decomposePrivateKey(inputKey, [options])
composePrivateKey(decomposedKey, [options])
decomposePublicKey(inputKey, [options])
composePublicKey(decomposedKey)
getKeyTypeFromAlgorithm(keyAlgorithm)
decomposePrivateKey(inputKey, [options])
Parses a private key, extracting information containing its format
, keyAlgorithm
, keyData
and encryptionAlgorithm
.
import { decomposePrivateKey } from 'cryptokeycomposer';
const myPrivatePemKey = `
BEGIN RSA PRIVATE KEY
ACTUAL KEY BASE64 HERE
END RSA PRIVATE KEY
`
const myPrivateDecomposedKey = decomposePrivateKey(myPrivatePemKey)
// {
// format: 'pkcs1pem',
// keyAlgorithm: {
// id: 'rsaencryption'
// },
// keyData: {
// modulus: Uint8Array(...),
// publicExponent: Uint8Array(...),
// privateExponent: Uint8Array(...),
// // ...
// },
// encryptionAlgorithm: null
// }
The inputKey
may be a TypedArray (including Node's Buffer), an ArrayBuffer or a binary string.
⚠️ Do not use thekeyAlgorithm.id
to identify the key type. The reason is that several identifiers map to the same key type. As an example,rsaencryption
,sha512withrsaencryption
,rsaoaep
andrsassapss
are all RSA keys. Instead, usegetKeyTypeFromAlgorithm
to properly get the key type.
Available options:
name  type  default  description 

format  string/Array  ['rawpem', 'pkcs8pem'] 
Limit the parsing to one or more formats

password  string  The password to use to decrypt the key 
Meaningful errors with codes are thrown if something went wrong. When options.format
is an array, this function will attempt to decompose the key for the specified formats, in order and one by one. It will succeed if the key is using one of the formats or fail if it's using another format, throwing an AggregatedError containing a errors
property with the errors indexed by format.
composePrivateKey(decomposedKey, [options])
Composes a private key from its parts: format
, keyAlgorithm
, keyData
and encryptionAlgorithm
. This function is the inverse of decomposePrivateKey
.
import { composePrivateKey } from 'cryptokeycomposer';
const myPrivatePemKey = composePrivateKey({
format: 'pkcs1pem',
keyAlgorithm: {
id: 'rsaencryption',
},
keyData: {
modulus: Uint8Array(...),
publicExponent: Uint8Array(...),
privateExponent: Uint8Array(...),
// ...
}
});
The return value depends on the format. PEM based formats return a regular string while DER based formats return a Uint8Array.
Available options:
name  type  default  description 

password  string  The password to use to encrypt the key 
Meaningful errors with codes are thrown if something went wrong.
decomposePublicKey(inputKey, [options])
Parses a public key, extracting information containing its format
, keyAlgorithm
and keyData
.
import { decomposePublicKey } from 'cryptokeycomposer';
const myPublicPemKey = `
BEGIN PUBLIC KEY
ACTUAL KEY BASE64 HERE
END PUBLIC KEY
`
const myDecomposedPublicKey = decomposePublicKey(myPublicPemKey)
// {
// format: 'spkipem',
// keyAlgorithm: {
// id: 'rsaencryption'
// },
// keyData: {
// modulus: Uint8Array(...),
// publicExponent: Uint8Array(...)
// },
// encryptionAlgorithm: null
// }
The inputKey
may be a TypedArray (including Node's Buffer), an ArrayBuffer or a binary string.
⚠️ Do not use thekeyAlgorithm.id
to identify the key type. The reason is that several identifiers map to the same key type. As an example,rsaencryption
,rsaesoaep
andrsassapss
are all RSA keys. Instead, usegetKeyTypeFromAlgorithm
to properly get the key type.
Available options:
name  type  default  description 

format  string/Array  ['rawpem', 'spkipem'] 
Limit the parsing to one or more formats 
Meaningful errors with codes are thrown if something went wrong. When options.format
is an array, this function will attempt to decompose the key for the specified formats, in order and one by one. It will succeed if the key is using one of the formats or fail if it's using another format, throwing an AggregatedError containing a errors
property with the errors indexed by format.
composePublicKey(decomposedKey)
Composes a public key from its parts: format
, keyAlgorithm
and keyData
. This function is the inverse of decomposePublicKey
.
import { composePublicKey } from 'cryptokeycomposer';
const myPublicPemKey = composePublicKey({
format: 'spkipem',
keyAlgorithm: {
id: 'rsaencryption',
},
keyData: {
modulus: Uint8Array(...),
publicExponent: Uint8Array(...)
}
});
The return value depends on the format. PEM based formats return a regular string while DER based formats return a Uint8Array.
Meaningful errors with codes are thrown if something went wrong.
getKeyTypeFromAlgorithm(keyAlgorithm)
Returns the key type based on the passed key algorithm. The keyAlgorithm
might be an object or a string.
import { getKeyTypeFromAlgorithm } from 'cryptokeycomposer';
getKeyTypeFromAlgorithm({ id: 'rsaencryption' }) // rsa
getKeyTypeFromAlgorithm('rsaencryption') // rsa
getKeyTypeFromAlgorithm('ed25519') // ed25519
Supported formats and algorithms
Formats
Below you will find the list of supported formats for private and public keys.
rawder (public & private)
The rawder
is the DER encoded ASN1 format defined in RFC 8017 for RSA keys and in RFC5915 for EC keys.
Supported public key algorithms:
 Just the standard
rsaencryption
RSA algorithm (or thersa
alias)
Supported private key algorithms:
 Just the standard
rsaencryption
RSA algorithm (or thersa
alias)  Just the standard
ecpublickey
EC algorithm (or theec
alias)
Supported encryption algorithms: none
⚠️ It's recommended to use the newer PKCS8 & SPKI formats for private and public keys respectively because they are able to store more types of keys. Moreover, PKCS8 keys may be encrypted.
rawpem (public & private)
The rawpem
is the PEM encoded version of rawder
and is defined in RFC 1421.
Supported public key algorithms:
 Just the standard
rsaencryption
RSA algorithm (or thersa
alias)
Supported private key algorithms:
 Just the standard
rsaencryption
RSA algorithm (or thersa
alias)  Just the standard
ecpublickey
RSA algorithm (or theec
alias)
Supported encryption algorithms:
 keyDerivationFunc:
opensslderivebytes
(default)  encryptionScheme:
aes256cbc
(default),aes192cbc
,aes128cbc
,desede3cbc
,descbc
,rc2cbc
⚠️ It's recommended to use the newer PKCS8 & SPKI formats for private and public keys respectively because they are able to store more types of keys. Moreover, PKCS8 keys have stronger encryption.
pkcs1der (private)
The pkcs1der
is the DER encoded ASN1 format defined in RFC 8017. It's a subset of the rawder
format, supporting only RSA keys.
Supported private key algorithms:
 Just the standard
rsaencryption
RSA algorithm (or thersa
alias)
Supported encryption algorithms: none
⚠️ It's recommended to use the newer PKCS8 format for private keys because it's able to store more types of keys and support encryption.
pkcs1pem (private)
The pkcs1pem
is the PEM encoded version of pkcs1der
and is defined in RFC 1421. It's a subset of the rawpem
format, supporting only RSA keys.
Supported private key algorithms:
 Just the standard
rsaencryption
RSA algorithm (or thersa
alias)
Supported encryption algorithms:
 keyDerivationFunc:
opensslderivebytes
(default)  encryptionScheme:
aes256cbc
(default),aes192cbc
,aes128cbc
,desede3cbc
,descbc
,rc2cbc
⚠️ It's recommended to use the newer PKCS8 format for private keys because it's able to store more types of keys and support stronger encryption algorithms.
pkcs8der (private)
The pkcs8der
is the DER encoded ASN1 format defined in RFC 5208 and RFC 5985.
Supported private key algorithms:
 RSA keys
 EC keys
 ED25519 keys
Supported encryption algorithms (PKCS#5):
 keyDerivationFunc:
pbkdf2
(default)  encryptionScheme:
aes256cbc
(default),aes192cbc
,aes128cbc
,desede3cbc
,descbc
,rc2cbc
pkcs8pem (private)
The pkcs8pem
is the PEM encoded version of pkcs8der
and is defined in RFC 1421.
Supported private key algorithms:
 RSA keys
 EC keys
 ED25519 keys
Supported encryption algorithms (PKCS#5):
 keyDerivationFunc:
pbkdf2
(default)  encryptionScheme:
aes256cbc
(default),aes192cbc
,aes128cbc
,desede3cbc
,descbc
,rc2cbc
spkider (public)
The spkider
is a format to represent various types of public keys and is defined in RFC 5280.
Supported public key algorithms:
 RSA keys
 EC keys
 ED25519 keys
Supported encryption algorithms: does not apply
spkipem (public)
The spkipem
is the PEM encoded version of spkider
and is defined in RFC 1421.
Supported public key algorithms:
 RSA keys
 EC keys
 ED25519 keys
Supported encryption algorithms: does not apply
Key Algorithms
Below you will find the list of supported key algorithms. Because the actual supported key algorithms vary from format to format, be sure to also check the Formats section.
RSA keys
The following RSA key algorithms are supported:
rsaencryption
md2withrsaencryption
md4withrsaencryption
md5withrsaencryption
sha1withrsaencryption
sha224withrsaencryption
sha256withrsaencryption
sha384withrsaencryption
sha512withrsaencryption
sha512224withrsaencryption
sha512256withrsaencryption
⚠️ At the moment,rsaesoaep
andrsassapss
are not yet supported (see issue #4).
All of them are expressed like so:
{
keyAlgorithm: {
id: 'rsaencryption'
}
}
Because they have no parameters, the example above may also be expressed like so:
{
keyAlgorithm: 'rsaencryption'
}
You may use the rsa
alias in the key algorithm id, which maps to rsaencryption
.
EC keys
The following EC (elliptic curve) algorithms are supported:
ecpublickey
ecdh
ecmqv
Only named curves may be used. The following curves are supported:
sect163k1
sect163r1
sect239k1
sect113r1
sect113r2
secp112r1
secp112r2
secp160r1
secp160k1
secp256k1
sect163r2
sect283k1
sect283r1
sect131r1
sect131r2
sect193r1
sect193r2
sect233k1
sect233r1
secp128r1
secp128r2
secp160r2
secp192k1
secp224k1
secp224r1
secp384r1
secp521r1
sect409k1
sect409r1
sect571k1
sect571r1
secp192r1
secp256r1
The combination of the key algorithm and the named curve are expressed like so:
{
keyAlgorithm: {
id: 'ecpublickey',
namedCurve: 'secp256k1',
}
}
You may use the ec
alias in the key algorithm id, which maps to ecpublickey
.
ED25519 keys
ED25519 keys just have a single algorithm, ed25519
, and may be expressed like so:
{
keyAlgorithm: {
id: 'ed25519'
}
}
Because there are no parameters, the example above may also be expressed like so:
{
keyAlgorithm: 'ed25519'
}
Key Data
The key data is the interpreted key contents. Below, you will find the key data structure for each key type.
RSA private keys
{
keyData: {
modulus: Uint8Array(/* ... */),
publicExponent: Uint8Array(/* ... */),
privateExponent: Uint8Array(/* ... */),
prime1: Uint8Array(/* ... */),
prime2: Uint8Array(/* ... */),
exponent1: Uint8Array(/* ... */),
exponent2: Uint8Array(/* ... */),
coefficient: Uint8Array(/* ... */),
// Only defined if number of primes is greater than 2
otherPrimeInfos: [
{
prime: Uint8Array(/* ... */),
exponent: Uint8Array(/* ... */),
coefficient Uint8Array(/* ... */)
}
]
}
}
RSA public keys
{
keyData: {
modulus: Uint8Array(/* ... */),
publicExponent: Uint8Array(/* ... */)
}
}
EC private keys
{
keyData: {
d: Uint8Array(/* ... */),
x: Uint8Array(/* ... */),
y: Uint8Array(/* ... */),
}
}
EC public keys
{
keyData: {
x: Uint8Array(/* ... */),
y: Uint8Array(/* ... */),
}
}
ED25519 private keys
{
keyData: {
seed: Uint8Array( /* 32 bytes */)
}
}
The seed is composed of 32 bytes which serves as the basis to derive the 64 bytes private key and the 32 bytes public key. This closely follows what is defined in RFC 8032.
ED25519 public keys
{
keyData: {
bytes: Uint8Array( /* 32 bytes */)
}
}
Encryption Algorithms
The encryption algorithm only apply for private keys and is composed by two parts: Key Derivation Function and the Encryption Scheme. Below you will find the supported algorithms for these parts. Because the actual supported encryption algorithms vary from format to format, be sure to also check the Formats section.
Key Derivation Function
OpenSSL derive bytes
The opensslderivebytes
is used when encrypting PKCS#1 PEM keys and was pionereed by OpenSSL to derive a key from the password.
{
encryptionAlgorithm: {
keyDerivationFunc: {
id: 'opensslderivebytes',
}
encryptionScheme: ...
}
}
Because there are no parameters, the example above may also be expressed like so:
{
encryptionAlgorithm: {
keyDerivationFunc: 'opensslderivebytes',
encryptionScheme: ...
}
}
PBKDF2
The pbkdf2
is used when encrypting PKCS#8 keys and is part of PKCS#5 defined by RFC 8018.
{
encryptionAlgorithm: {
keyDerivationFunc: {
id: 'pbkdf2',
iterationCount: 10000, // The number of iterations
keyLength: 32, // Automatic, based on the `encryptionScheme`
prf: 'hmacwithsha512' // The pseudorandom function
}
encryptionScheme: ...
}
}
The parameters above are the default ones and may be omited if you don't need to tweak them. In that case, you may express the example above like so:
{
encryptionAlgorithm: {
keyDerivationFunc: 'pbkdf2',
encryptionScheme: ...
}
}
The supported prf
values are hmacwithsha512
(default), hmacwithsha384
, hmacwithsha256
and hmacwithsha1
.
Encryption Scheme
AES
The supported AES algorithms are aes256cbc
, aes192cbc
and aes128cbc
. Here's an example:
{
encryptionAlgorithm: {
keyDerivationFunc: ...,
encryptionScheme: {
id: 'aes256cbc',
iv: Uint8Array(/* random bytes */)
}
}
}
The parameters may be omited if you don't need to tweak them. In that case, you may express the example above like so:
{
encryptionAlgorithm: {
keyDerivationFunc: ...,
encryptionScheme: 'aes256cbc'
}
}
DES
The supported DES algorithms are descbc
and desede3cbc
(triple DES). Here's an example:
{
encryptionAlgorithm: {
keyDerivationFunc: ...,
encryptionScheme: {
id: 'desede3cbc',
iv: Uint8Array(/* random bytes */)
}
}
}
The parameters may be omited if you don't need to tweak them. In that case, you may express the example above like so:
{
encryptionAlgorithm: {
keyDerivationFunc: ...,
encryptionScheme: 'aes256cbc'
}
}
RC2
The supported RC2 algorithm is just rc2cbc
with 128
(default), 64
or 40
bits. Here's an example:
{
encryptionAlgorithm: {
keyDerivationFunc: ...,
encryptionScheme: {
id: 'rc2cbc',
iv: Uint8Array(/* random bytes */),
bits: 128
}
}
}
The parameters may be omited if you don't need to tweak them. In that case, you may express the example above like so:
{
encryptionAlgorithm: {
keyDerivationFunc: ...,
encryptionScheme: 'rc2cbc'
}
}
Tests
$ npm test
$ npm test  watch # during development
License
Released under the MIT License.