js-libp2p-crypto/src/keys/rsa-class.js

167 lines
3.8 KiB
JavaScript
Raw Normal View History

2017-07-22 10:57:27 -07:00
'use strict'
const multihashing = require('multihashing-async')
const protobuf = require('protons')
const bs58 = require('bs58')
2017-07-22 10:57:27 -07:00
const crypto = require('./rsa')
const pbm = protobuf(require('./keys.proto'))
require('node-forge/lib/sha512')
require('node-forge/lib/pbe')
const forge = require('node-forge/lib/forge')
2017-07-22 10:57:27 -07:00
class RsaPublicKey {
constructor (key) {
this._key = key
}
async verify (data, sig) { // eslint-disable-line require-await
return crypto.hashAndVerify(this._key, sig, data)
2017-07-22 10:57:27 -07:00
}
marshal () {
return crypto.utils.jwkToPkix(this._key)
}
get bytes () {
return pbm.PublicKey.encode({
2017-07-22 10:57:27 -07:00
Type: pbm.KeyType.RSA,
Data: this.marshal()
})
}
encrypt (bytes) {
return this._key.encrypt(bytes, 'RSAES-PKCS1-V1_5')
}
equals (key) {
return this.bytes.equals(key.bytes)
}
async hash () { // eslint-disable-line require-await
return multihashing(this.bytes, 'sha2-256')
2017-07-22 10:57:27 -07:00
}
}
class RsaPrivateKey {
// key - Object of the jwk format
// publicKey - Buffer of the spki format
constructor (key, publicKey) {
this._key = key
this._publicKey = publicKey
}
genSecret () {
return crypto.getRandomValues(16)
2017-07-22 10:57:27 -07:00
}
async sign (message) { // eslint-disable-line require-await
return crypto.hashAndSign(this._key, message)
2017-07-22 10:57:27 -07:00
}
get public () {
if (!this._publicKey) {
throw new Error('public key not provided')
}
return new RsaPublicKey(this._publicKey)
}
marshal () {
return crypto.utils.jwkToPkcs1(this._key)
}
get bytes () {
return pbm.PrivateKey.encode({
2017-07-22 10:57:27 -07:00
Type: pbm.KeyType.RSA,
Data: this.marshal()
})
}
equals (key) {
return this.bytes.equals(key.bytes)
}
async hash () { // eslint-disable-line require-await
return multihashing(this.bytes, 'sha2-256')
2017-07-22 10:57:27 -07:00
}
/**
* Gets the ID of the key.
*
* The key id is the base58 encoding of the SHA-256 multihash of its public key.
* The public key is a protobuf encoding containing a type and the DER encoding
* of the PKCS SubjectPublicKeyInfo.
*
* @returns {Promise<String>}
*/
async id () {
const hash = await this.public.hash()
return bs58.encode(hash)
}
/**
* Exports the key into a password protected PEM format
*
* @param {string} [format] - Defaults to 'pkcs-8'.
* @param {string} password - The password to read the encrypted PEM
* @returns {KeyInfo}
*/
async export (format, password) { // eslint-disable-line require-await
if (password == null) {
password = format
format = 'pkcs-8'
}
let pem = null
const buffer = new forge.util.ByteBuffer(this.marshal())
const asn1 = forge.asn1.fromDer(buffer)
const privateKey = forge.pki.privateKeyFromAsn1(asn1)
if (format === 'pkcs-8') {
const options = {
algorithm: 'aes256',
count: 10000,
saltSize: 128 / 8,
prfAlgorithm: 'sha512'
}
pem = forge.pki.encryptRsaPrivateKey(privateKey, password, options)
} else {
throw new Error(`Unknown export format '${format}'`)
}
return pem
}
2017-07-22 10:57:27 -07:00
}
async function unmarshalRsaPrivateKey (bytes) {
2017-07-22 10:57:27 -07:00
const jwk = crypto.utils.pkcs1ToJwk(bytes)
const keys = await crypto.unmarshalPrivateKey(jwk)
return new RsaPrivateKey(keys.privateKey, keys.publicKey)
2017-07-22 10:57:27 -07:00
}
function unmarshalRsaPublicKey (bytes) {
const jwk = crypto.utils.pkixToJwk(bytes)
return new RsaPublicKey(jwk)
}
async function fromJwk (jwk) {
const keys = await crypto.unmarshalPrivateKey(jwk)
return new RsaPrivateKey(keys.privateKey, keys.publicKey)
}
async function generateKeyPair (bits) {
const keys = await crypto.generateKey(bits)
return new RsaPrivateKey(keys.privateKey, keys.publicKey)
2017-07-22 10:57:27 -07:00
}
module.exports = {
RsaPublicKey,
RsaPrivateKey,
unmarshalRsaPublicKey,
unmarshalRsaPrivateKey,
generateKeyPair,
fromJwk
2017-07-22 10:57:27 -07:00
}