mirror of
https://github.com/fluencelabs/js-libp2p-crypto
synced 2025-03-15 19:50:58 +00:00
feat: key exchange with jsrsasign (#115)
* feat: export/import password protected RSA key * docs: crypto.key.import * test: import with wrong password * fix: lint * test: importing openssl keys * just to trigger circle with new ubuntu * feat: get the RSA key id * feat: get the ED 25519 key id * feat: pbkdf2 * fix(pbkdf2): base64 has more chars to guess than hex * chore: update deps
This commit is contained in:
parent
f3cb8ced36
commit
b3421284f9
21
README.md
21
README.md
@ -35,6 +35,7 @@ This repo contains the JavaScript implementation of the crypto primitives needed
|
|||||||
- [`unmarshalPublicKey(buf)`](#unmarshalpublickeybuf)
|
- [`unmarshalPublicKey(buf)`](#unmarshalpublickeybuf)
|
||||||
- [`marshalPrivateKey(key[, type])`](#marshalprivatekeykey-type)
|
- [`marshalPrivateKey(key[, type])`](#marshalprivatekeykey-type)
|
||||||
- [`unmarshalPrivateKey(buf, callback)`](#unmarshalprivatekeybuf-callback)
|
- [`unmarshalPrivateKey(buf, callback)`](#unmarshalprivatekeybuf-callback)
|
||||||
|
- [`import(pem, password, callback)`](#importpem-password-callback)
|
||||||
- [`webcrypto`](#webcrypto)
|
- [`webcrypto`](#webcrypto)
|
||||||
- [Contribute](#contribute)
|
- [Contribute](#contribute)
|
||||||
- [License](#license)
|
- [License](#license)
|
||||||
@ -183,12 +184,30 @@ Converts a private key object into a protobuf serialized private key.
|
|||||||
|
|
||||||
Converts a protobuf serialized private key into its representative object.
|
Converts a protobuf serialized private key into its representative object.
|
||||||
|
|
||||||
|
### `crypto.keys.import(pem, password, callback)`
|
||||||
|
|
||||||
|
- `pem: string`
|
||||||
|
- `password: string`
|
||||||
|
- `callback: Function`
|
||||||
|
|
||||||
|
Converts a PEM password protected private key into its representative object.
|
||||||
|
|
||||||
### `crypto.randomBytes(number)`
|
### `crypto.randomBytes(number)`
|
||||||
|
|
||||||
- `number: Number`
|
- `number: Number`
|
||||||
|
|
||||||
Generates a Buffer with length `number` populated by random bytes.
|
Generates a Buffer with length `number` populated by random bytes.
|
||||||
|
|
||||||
|
### `crypto.pbkdf2(password, salt, iterations, keySize, hash)`
|
||||||
|
|
||||||
|
- `password: String`
|
||||||
|
- `salt: String`
|
||||||
|
- `iterations: Number`
|
||||||
|
- `keySize: Number` in bytes
|
||||||
|
- `hash: String` the hashing algorithm ('sha1', 'sha2-512', ...)
|
||||||
|
|
||||||
|
Computes the Password Based Key Derivation Function 2; returning a new password.
|
||||||
|
|
||||||
## Contribute
|
## Contribute
|
||||||
|
|
||||||
Feel free to join in. All welcome. Open an [issue](https://github.com/libp2p/js-libp2p-crypto/issues)!
|
Feel free to join in. All welcome. Open an [issue](https://github.com/libp2p/js-libp2p-crypto/issues)!
|
||||||
@ -199,4 +218,4 @@ This repository falls under the IPFS [Code of Conduct](https://github.com/ipfs/c
|
|||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
[MIT](LICENSE)
|
[MIT](./LICENSE)
|
||||||
|
@ -33,19 +33,22 @@
|
|||||||
"asn1.js": "^5.0.0",
|
"asn1.js": "^5.0.0",
|
||||||
"async": "^2.6.0",
|
"async": "^2.6.0",
|
||||||
"browserify-aes": "^1.1.1",
|
"browserify-aes": "^1.1.1",
|
||||||
|
"bs58": "^4.0.1",
|
||||||
|
"jsrsasign": "^8.0.4",
|
||||||
"keypair": "^1.0.1",
|
"keypair": "^1.0.1",
|
||||||
"libp2p-crypto-secp256k1": "~0.2.2",
|
"libp2p-crypto-secp256k1": "~0.2.2",
|
||||||
"multihashing-async": "~0.4.7",
|
"multihashing-async": "~0.4.7",
|
||||||
"pem-jwk": "^1.5.1",
|
"pem-jwk": "^1.5.1",
|
||||||
"protons": "^1.0.0",
|
"protons": "^1.0.1",
|
||||||
"rsa-pem-to-jwk": "^1.1.3",
|
"rsa-pem-to-jwk": "^1.1.3",
|
||||||
"tweetnacl": "^1.0.0",
|
"tweetnacl": "^1.0.0",
|
||||||
"webcrypto-shim": "github:dignifiedquire/webcrypto-shim#master"
|
"webcrypto-shim": "github:dignifiedquire/webcrypto-shim#master"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"aegir": "^12.2.0",
|
"aegir": "^12.3.0",
|
||||||
"benchmark": "^2.1.4",
|
"benchmark": "^2.1.4",
|
||||||
"chai": "^4.1.2",
|
"chai": "^4.1.2",
|
||||||
|
"chai-string": "^1.4.0",
|
||||||
"dirty-chai": "^2.0.1",
|
"dirty-chai": "^2.0.1",
|
||||||
"pre-commit": "^1.2.2"
|
"pre-commit": "^1.2.2"
|
||||||
},
|
},
|
||||||
|
@ -10,3 +10,4 @@ exports.aes = aes
|
|||||||
exports.hmac = hmac
|
exports.hmac = hmac
|
||||||
exports.keys = keys
|
exports.keys = keys
|
||||||
exports.randomBytes = require('./random-bytes')
|
exports.randomBytes = require('./random-bytes')
|
||||||
|
exports.pbkdf2 = require('./pbkdf2')
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
const multihashing = require('multihashing-async')
|
const multihashing = require('multihashing-async')
|
||||||
const protobuf = require('protons')
|
const protobuf = require('protons')
|
||||||
|
const bs58 = require('bs58')
|
||||||
|
|
||||||
const crypto = require('./ed25519')
|
const crypto = require('./ed25519')
|
||||||
const pbm = protobuf(require('./keys.proto'))
|
const pbm = protobuf(require('./keys.proto'))
|
||||||
@ -77,6 +78,25 @@ class Ed25519PrivateKey {
|
|||||||
ensure(callback)
|
ensure(callback)
|
||||||
multihashing(this.bytes, 'sha2-256', callback)
|
multihashing(this.bytes, 'sha2-256', callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @param {function(Error, id)} callback
|
||||||
|
* @returns {undefined}
|
||||||
|
*/
|
||||||
|
id (callback) {
|
||||||
|
this.public.hash((err, hash) => {
|
||||||
|
if (err) {
|
||||||
|
return callback(err)
|
||||||
|
}
|
||||||
|
callback(null, bs58.encode(hash))
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function unmarshalEd25519PrivateKey (bytes, callback) {
|
function unmarshalEd25519PrivateKey (bytes, callback) {
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
const protobuf = require('protons')
|
const protobuf = require('protons')
|
||||||
const keysPBM = protobuf(require('./keys.proto'))
|
const keysPBM = protobuf(require('./keys.proto'))
|
||||||
|
const jsrsasign = require('jsrsasign')
|
||||||
|
const KEYUTIL = jsrsasign.KEYUTIL
|
||||||
|
|
||||||
exports = module.exports
|
exports = module.exports
|
||||||
|
|
||||||
@ -115,3 +117,17 @@ exports.marshalPrivateKey = (key, type) => {
|
|||||||
|
|
||||||
return key.bytes
|
return key.bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exports.import = (pem, password, callback) => {
|
||||||
|
try {
|
||||||
|
const key = KEYUTIL.getKey(pem, password)
|
||||||
|
if (key instanceof jsrsasign.RSAKey) {
|
||||||
|
const jwk = KEYUTIL.getJWKFromKey(key)
|
||||||
|
return supportedKeys.rsa.fromJwk(jwk, callback)
|
||||||
|
} else {
|
||||||
|
throw new Error(`Unknown key type '${key.prototype.toString()}'`)
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
callback(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -105,9 +105,7 @@ function derivePublicFromPrivate (jwKey) {
|
|||||||
{
|
{
|
||||||
kty: jwKey.kty,
|
kty: jwKey.kty,
|
||||||
n: jwKey.n,
|
n: jwKey.n,
|
||||||
e: jwKey.e,
|
e: jwKey.e
|
||||||
alg: jwKey.alg,
|
|
||||||
kid: jwKey.kid
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'RSASSA-PKCS1-v1_5',
|
name: 'RSASSA-PKCS1-v1_5',
|
||||||
|
@ -2,9 +2,12 @@
|
|||||||
|
|
||||||
const multihashing = require('multihashing-async')
|
const multihashing = require('multihashing-async')
|
||||||
const protobuf = require('protons')
|
const protobuf = require('protons')
|
||||||
|
const bs58 = require('bs58')
|
||||||
|
|
||||||
const crypto = require('./rsa')
|
const crypto = require('./rsa')
|
||||||
const pbm = protobuf(require('./keys.proto'))
|
const pbm = protobuf(require('./keys.proto'))
|
||||||
|
const KEYUTIL = require('jsrsasign').KEYUTIL
|
||||||
|
const setImmediate = require('async/setImmediate')
|
||||||
|
|
||||||
class RsaPublicKey {
|
class RsaPublicKey {
|
||||||
constructor (key) {
|
constructor (key) {
|
||||||
@ -89,6 +92,60 @@ class RsaPrivateKey {
|
|||||||
ensure(callback)
|
ensure(callback)
|
||||||
multihashing(this.bytes, 'sha2-256', callback)
|
multihashing(this.bytes, 'sha2-256', callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @param {function(Error, id)} callback
|
||||||
|
* @returns {undefined}
|
||||||
|
*/
|
||||||
|
id (callback) {
|
||||||
|
this.public.hash((err, hash) => {
|
||||||
|
if (err) {
|
||||||
|
return callback(err)
|
||||||
|
}
|
||||||
|
callback(null, 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
|
||||||
|
* @param {function(Error, KeyInfo)} callback
|
||||||
|
* @returns {undefined}
|
||||||
|
*/
|
||||||
|
export (format, password, callback) {
|
||||||
|
if (typeof password === 'function') {
|
||||||
|
callback = password
|
||||||
|
password = format
|
||||||
|
format = 'pkcs-8'
|
||||||
|
}
|
||||||
|
|
||||||
|
setImmediate(() => {
|
||||||
|
ensure(callback)
|
||||||
|
|
||||||
|
let err = null
|
||||||
|
let pem = null
|
||||||
|
try {
|
||||||
|
const key = KEYUTIL.getKey(this._key) // _key is a JWK (JSON Web Key)
|
||||||
|
if (format === 'pkcs-8') {
|
||||||
|
pem = KEYUTIL.getPEM(key, 'PKCS8PRV', password)
|
||||||
|
} else {
|
||||||
|
err = new Error(`Unknown export format '${format}'`)
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
err = e
|
||||||
|
}
|
||||||
|
|
||||||
|
callback(err, pem)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function unmarshalRsaPrivateKey (bytes, callback) {
|
function unmarshalRsaPrivateKey (bytes, callback) {
|
||||||
@ -108,6 +165,16 @@ function unmarshalRsaPublicKey (bytes) {
|
|||||||
return new RsaPublicKey(jwk)
|
return new RsaPublicKey(jwk)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function fromJwk (jwk, callback) {
|
||||||
|
crypto.unmarshalPrivateKey(jwk, (err, keys) => {
|
||||||
|
if (err) {
|
||||||
|
return callback(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
callback(null, new RsaPrivateKey(keys.privateKey, keys.publicKey))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
function generateKeyPair (bits, cb) {
|
function generateKeyPair (bits, cb) {
|
||||||
crypto.generateKey(bits, (err, keys) => {
|
crypto.generateKey(bits, (err, keys) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
@ -129,5 +196,6 @@ module.exports = {
|
|||||||
RsaPrivateKey,
|
RsaPrivateKey,
|
||||||
unmarshalRsaPublicKey,
|
unmarshalRsaPublicKey,
|
||||||
unmarshalRsaPrivateKey,
|
unmarshalRsaPrivateKey,
|
||||||
generateKeyPair
|
generateKeyPair,
|
||||||
|
fromJwk
|
||||||
}
|
}
|
||||||
|
41
src/pbkdf2.js
Normal file
41
src/pbkdf2.js
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const crypto = require('jsrsasign').CryptoJS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps an IPFS hash name to its jsrsasign equivalent.
|
||||||
|
*
|
||||||
|
* See https://github.com/multiformats/multihash/blob/master/hashtable.csv
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
const hashName = {
|
||||||
|
sha1: crypto.algo.SHA1,
|
||||||
|
'sha2-256': crypto.algo.SHA256,
|
||||||
|
'sha2-512': crypto.algo.SHA512
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes the Password-Based Key Derivation Function 2.
|
||||||
|
*
|
||||||
|
* @param {string} password
|
||||||
|
* @param {string} salt
|
||||||
|
* @param {number} iterations
|
||||||
|
* @param {number} keySize (in bytes)
|
||||||
|
* @param {string} hash - The hash name ('sha1', 'sha2-512, ...)
|
||||||
|
* @returns {string} - A new password
|
||||||
|
*/
|
||||||
|
function pbkdf2 (password, salt, iterations, keySize, hash) {
|
||||||
|
const opts = {
|
||||||
|
iterations: iterations,
|
||||||
|
keySize: keySize / 4, // convert bytes to words (32 bits)
|
||||||
|
hasher: hashName[hash]
|
||||||
|
}
|
||||||
|
if (!opts.hasher) {
|
||||||
|
throw new Error(`Hash '${hash}' is unknown or not supported`)
|
||||||
|
}
|
||||||
|
const words = crypto.PBKDF2(password, salt, opts)
|
||||||
|
return crypto.enc.Base64.stringify(words)
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = pbkdf2
|
@ -107,6 +107,32 @@ describe('libp2p-crypto', function () {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('pbkdf2', () => {
|
||||||
|
it('generates a derived password using sha1', () => {
|
||||||
|
const p1 = crypto.pbkdf2('password', 'at least 16 character salt', 500, 512 / 8, 'sha1')
|
||||||
|
expect(p1).to.exist()
|
||||||
|
expect(p1).to.be.a('string')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('generates a derived password using sha2-512', () => {
|
||||||
|
const p1 = crypto.pbkdf2('password', 'at least 16 character salt', 500, 512 / 8, 'sha2-512')
|
||||||
|
expect(p1).to.exist()
|
||||||
|
expect(p1).to.be.a('string')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('generates the same derived password with the same options', () => {
|
||||||
|
const p1 = crypto.pbkdf2('password', 'at least 16 character salt', 10, 512 / 8, 'sha1')
|
||||||
|
const p2 = crypto.pbkdf2('password', 'at least 16 character salt', 10, 512 / 8, 'sha1')
|
||||||
|
const p3 = crypto.pbkdf2('password', 'at least 16 character salt', 11, 512 / 8, 'sha1')
|
||||||
|
expect(p2).to.equal(p1)
|
||||||
|
expect(p3).to.not.equal(p2)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws on invalid hash name', () => {
|
||||||
|
expect(() => crypto.pbkdf2('password', 'at least 16 character salt', 500, 512 / 8, 'shaX-xxx')).to.throw()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('randomBytes', () => {
|
describe('randomBytes', () => {
|
||||||
it('throws with no number passed', () => {
|
it('throws with no number passed', () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
|
@ -117,6 +117,15 @@ describe('ed25519', function () {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('key id', (done) => {
|
||||||
|
key.id((err, id) => {
|
||||||
|
expect(err).to.not.exist()
|
||||||
|
expect(id).to.exist()
|
||||||
|
expect(id).to.be.a('string')
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('key equals', () => {
|
describe('key equals', () => {
|
||||||
it('equals itself', () => {
|
it('equals itself', () => {
|
||||||
expect(
|
expect(
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
/* eslint max-nested-callbacks: ["error", 8] */
|
||||||
/* eslint-env mocha */
|
/* eslint-env mocha */
|
||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
@ -5,6 +6,7 @@ const chai = require('chai')
|
|||||||
const dirtyChai = require('dirty-chai')
|
const dirtyChai = require('dirty-chai')
|
||||||
const expect = chai.expect
|
const expect = chai.expect
|
||||||
chai.use(dirtyChai)
|
chai.use(dirtyChai)
|
||||||
|
chai.use(require('chai-string'))
|
||||||
|
|
||||||
const crypto = require('../../src')
|
const crypto = require('../../src')
|
||||||
const rsa = crypto.keys.supportedKeys.rsa
|
const rsa = crypto.keys.supportedKeys.rsa
|
||||||
@ -78,6 +80,15 @@ describe('RSA', function () {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('key id', (done) => {
|
||||||
|
key.id((err, id) => {
|
||||||
|
expect(err).to.not.exist()
|
||||||
|
expect(id).to.exist()
|
||||||
|
expect(id).to.be.a('string')
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('key equals', () => {
|
describe('key equals', () => {
|
||||||
it('equals itself', () => {
|
it('equals itself', () => {
|
||||||
expect(key.equals(key)).to.eql(true)
|
expect(key.equals(key)).to.eql(true)
|
||||||
@ -134,6 +145,44 @@ describe('RSA', function () {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('export and import', () => {
|
||||||
|
it('password protected PKCS #8', (done) => {
|
||||||
|
key.export('pkcs-8', 'my secret', (err, pem) => {
|
||||||
|
expect(err).to.not.exist()
|
||||||
|
expect(pem).to.startsWith('-----BEGIN ENCRYPTED PRIVATE KEY-----')
|
||||||
|
crypto.keys.import(pem, 'my secret', (err, clone) => {
|
||||||
|
expect(err).to.not.exist()
|
||||||
|
expect(clone).to.exist()
|
||||||
|
expect(key.equals(clone)).to.eql(true)
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('defaults to PKCS #8', (done) => {
|
||||||
|
key.export('another secret', (err, pem) => {
|
||||||
|
expect(err).to.not.exist()
|
||||||
|
expect(pem).to.startsWith('-----BEGIN ENCRYPTED PRIVATE KEY-----')
|
||||||
|
crypto.keys.import(pem, 'another secret', (err, clone) => {
|
||||||
|
expect(err).to.not.exist()
|
||||||
|
expect(clone).to.exist()
|
||||||
|
expect(key.equals(clone)).to.eql(true)
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('needs correct password', (done) => {
|
||||||
|
key.export('another secret', (err, pem) => {
|
||||||
|
expect(err).to.not.exist()
|
||||||
|
crypto.keys.import(pem, 'not the secret', (err, clone) => {
|
||||||
|
expect(err).to.exist()
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('returns error via cb instead of crashing', () => {
|
describe('returns error via cb instead of crashing', () => {
|
||||||
const key = crypto.keys.unmarshalPublicKey(fixtures.verify.publicKey)
|
const key = crypto.keys.unmarshalPublicKey(fixtures.verify.publicKey)
|
||||||
testGarbage.doTests('key.verify', key.verify.bind(key), 2, true)
|
testGarbage.doTests('key.verify', key.verify.bind(key), 2, true)
|
||||||
@ -152,4 +201,170 @@ describe('RSA', function () {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('openssl interop', () => {
|
||||||
|
it('can read a private key', (done) => {
|
||||||
|
/*
|
||||||
|
* Generated with
|
||||||
|
* openssl genpkey -algorithm RSA
|
||||||
|
* -pkeyopt rsa_keygen_bits:3072
|
||||||
|
* -pkeyopt rsa_keygen_pubexp:65537
|
||||||
|
*/
|
||||||
|
const pem = `-----BEGIN PRIVATE KEY-----
|
||||||
|
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
|
||||||
|
4pMwXeXP+LO8NIfRXV8mgrm86g==
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
|
`
|
||||||
|
crypto.keys.import(pem, '', (err, key) => {
|
||||||
|
expect(err).to.not.exist()
|
||||||
|
expect(key).to.exist()
|
||||||
|
key.id((err, id) => {
|
||||||
|
expect(err).to.not.exist()
|
||||||
|
expect(id).to.equal('QmfWu2Xp8DZzCkZZzoPB9rcrq4R4RZid6AWE6kmrUAzuHy')
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// AssertionError: expected 'this only supports pkcs5PBES2' to not exist
|
||||||
|
it.skip('can read a private encrypted key (v1)', (done) => {
|
||||||
|
/*
|
||||||
|
* Generated with
|
||||||
|
* openssl genpkey -algorithm RSA
|
||||||
|
* -pkeyopt rsa_keygen_bits:1024
|
||||||
|
* -pkeyopt rsa_keygen_pubexp:65537
|
||||||
|
* -out foo.pem
|
||||||
|
* openssl pkcs8 -in foo.pem -topk8 -passout pass:mypassword
|
||||||
|
*/
|
||||||
|
const pem = `-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||||
|
MIICoTAbBgkqhkiG9w0BBQMwDgQI2563Jugj/KkCAggABIICgPxHkKtUUE8EWevq
|
||||||
|
eX9nTjqpbsv0QoXQMhegfxDELJLU8tj6V0bWNt7QDdfQ1n6FRgnNvNGick6gyqHH
|
||||||
|
yH9qC2oXwkDFP7OrHp2NEZd7DHQLLc+L4KJ/0dzsiZ1U9no7XzQMUay9Bc918ADE
|
||||||
|
pN2/EqigWkaG4gNjkAeKWr6+BNRevDXlSvls7YDboNcTiACi5zJkthivB9g3vT1m
|
||||||
|
gPdN6Gf/mmqtBTDHeqj5QsmXYqeCyo5b26JgYsziABVZDHph4ekPUsTvudRpE9Ex
|
||||||
|
baXwdYEAZxVpSbTvQ3A5qysjSZeM9ttfRTSSwL391q7dViz4+aujpk0Vj7piH+1B
|
||||||
|
CkfO8/XudRdRlnOe+KjMidktKCsMGCIOW92IlfMvIQ/Zn1GTYj9bRXONFNJ2WPND
|
||||||
|
UmCKnL7cmworwg/weRorrGKBWIGspU+tDASOPSvIGKo6Hoxm4CN1TpDRY7DAGlgm
|
||||||
|
Y3TEbMYfpXyzkPjvAhJDt03D3J9PrTO6uM5d7YUaaTmJ2TQFQVF2Lc3Uz8lDJLs0
|
||||||
|
ZYtfQ/4H+YY2RrX7ua7t6ArUcYXZtv0J4lRYWjwV8fGPUVc0d8xLJU0Yjf4BD7K8
|
||||||
|
rsavHo9b5YvBUX7SgUyxAEembEOe3SjQ+gPu2U5wovcjUuC9eItEEsXGrx30BQ0E
|
||||||
|
8BtK2+hp0eMkW5/BYckJkH+Yl8ypbzRGRRIZzLgeI4JveSx/mNhewfgTr+ORPThZ
|
||||||
|
mBdkD5r+ixWF174naw53L8U9wF8kiK7pIE1N9TR4USEeovLwX6Ni/2MMDZedOfof
|
||||||
|
2f77eUdLsK19/5/lcgAAYaXauXWhy2d2r3SayFrC9woy0lh2VLKRMBjcx1oWb7dp
|
||||||
|
0uxzo5Y=
|
||||||
|
-----END ENCRYPTED PRIVATE KEY-----
|
||||||
|
`
|
||||||
|
crypto.keys.import(pem, 'mypassword', (err, key) => {
|
||||||
|
expect(err).to.not.exist()
|
||||||
|
expect(key).to.exist()
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// AssertionError: expected 'this only supports TripleDES' to not exist
|
||||||
|
it.skip('can read a private encrypted key (v2 aes-256-cbc)', (done) => {
|
||||||
|
/*
|
||||||
|
* Generated with
|
||||||
|
* openssl genpkey -algorithm RSA
|
||||||
|
* -pkeyopt rsa_keygen_bits:1024
|
||||||
|
* -pkeyopt rsa_keygen_pubexp:65537
|
||||||
|
* -out foo.pem
|
||||||
|
* openssl pkcs8 -in foo.pem -topk8 -v2 aes-256-cbc -passout pass:mypassword
|
||||||
|
*/
|
||||||
|
const pem = `-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||||
|
MIICzzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQIhuL894loRucCAggA
|
||||||
|
MB0GCWCGSAFlAwQBKgQQEoEtsjW3iC9/u0uGvkxX7wSCAoAsX3l6JoR2OGbT8CkY
|
||||||
|
YT3RQFqquOgItYOHw6E3tir2YrmxEAo99nxoL8pdto37KSC32eAGnfv5R1zmHHSx
|
||||||
|
0M3/y2AWiCBTX95EEzdtGC1hK3PBa/qpp/xEmcrsjYN6NXxMAkhC0hMP/HdvqMAg
|
||||||
|
ee7upvaYJsJcl8QLFNayAWr8b8cZA/RBhGEIRl59Eyj6nNtxDt3bCrfe06o1CPCV
|
||||||
|
50/fRZEwFOi/C6GYvPN6MrPZO3ALBWgopLT2yQqycTKtfxYWIdOsMBkAjKf2D6Pk
|
||||||
|
u2mqBsaP4b71jIIeT4euSJLsoJV+O39s8YHXtW8GtOqp7V5kIlnm90lZ9wzeLTZ7
|
||||||
|
HJsD/jEdYto5J3YWm2wwEDccraffJSm7UDtJBvQdIx832kxeFCcGQjW38Zl1qqkg
|
||||||
|
iTH1PLTypxj2ZuviS2EkXVFb/kVU6leWwOt6fqWFC58UvJKeCk/6veazz3PDnTWM
|
||||||
|
92ClUqFd+CZn9VT4CIaJaAc6v5NLpPp+T9sRX9AtequPm7FyTeevY9bElfyk9gW9
|
||||||
|
JDKgKxs6DGWDa16RL5vzwtU+G3o6w6IU+mEwa6/c+hN+pRFs/KBNLLSP9OHBx7BJ
|
||||||
|
X/32Ft+VFhJaK+lQ+f+hve7od/bgKnz4c/Vtp7Dh51DgWgCpBgb8p0vqu02vTnxD
|
||||||
|
BXtDv3h75l5PhvdWfVIzpMWRYFvPR+vJi066FjAz2sjYc0NMLSYtZWyWoIInjhoX
|
||||||
|
Dp5CQujCtw/ZSSlwde1DKEWAW4SeDZAOQNvuz0rU3eosNUJxEmh3aSrcrRtDpw+Y
|
||||||
|
mBUuWAZMpz7njBi7h+JDfmSW/GAaMwrVFC2gef5375R0TejAh+COAjItyoeYEvv8
|
||||||
|
DQd8
|
||||||
|
-----END ENCRYPTED PRIVATE KEY-----
|
||||||
|
`
|
||||||
|
crypto.keys.import(pem, 'mypassword', (err, key) => {
|
||||||
|
expect(err).to.not.exist()
|
||||||
|
expect(key).to.exist()
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('can read a private encrypted key (v2 des3)', (done) => {
|
||||||
|
/*
|
||||||
|
* Generated with
|
||||||
|
* openssl genpkey -algorithm RSA
|
||||||
|
* -pkeyopt rsa_keygen_bits:1024
|
||||||
|
* -pkeyopt rsa_keygen_pubexp:65537
|
||||||
|
* -out foo.pem
|
||||||
|
* openssl pkcs8 -in foo.pem -topk8 -v2 des3 -passout pass:mypassword
|
||||||
|
*/
|
||||||
|
const pem = `-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||||
|
MIICxjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQISznrfHd+D58CAggA
|
||||||
|
MBQGCCqGSIb3DQMHBAhx0DnnUvDiHASCAoCceplm+Cmwlgvn4hNsv6e4c/S1iA7w
|
||||||
|
2hU7Jt8JgRCIMWjP2FthXOAFLa2fD4g3qncYXcDAFBXNyoh25OgOwstO14YkxhDi
|
||||||
|
wG4TeppGUt9IlyyCol6Z4WhQs1TGm5OcD5xDta+zBXsBnlgmKLD5ZXPEYB+3v/Dg
|
||||||
|
SvM4sQz6NgkVHN52hchERsnknwSOghiK9mIBH0RZU5LgzlDy2VoBCiEPVdZ7m4F2
|
||||||
|
dft5e82zFS58vwDeNN/0r7fC54TyJf/8k3q94+4Hp0mseZ67LR39cvnEKuDuFROm
|
||||||
|
kLPLekWt5R2NGdunSQlA79BkrNB1ADruO8hQOOHMO9Y3/gNPWLKk+qrfHcUni+w3
|
||||||
|
Ofq+rdfakHRb8D6PUmsp3wQj6fSOwOyq3S50VwP4P02gKcZ1om1RvEzTbVMyL3sh
|
||||||
|
hZcVB3vViu3DO2/56wo29lPVTpj9bSYjw/CO5jNpPBab0B/Gv7JAR0z4Q8gn6OPy
|
||||||
|
qf+ddyW4Kcb6QUtMrYepghDthOiS3YJV/zCNdL3gTtVs5Ku9QwQ8FeM0/5oJZPlC
|
||||||
|
TxGuOFEJnYRWqIdByCP8mp/qXS5alSR4uoYQSd7vZG4vkhkPNSAwux/qK1IWfqiW
|
||||||
|
3XlZzrbD//9IzFVqGRs4nRIFq85ULK0zAR57HEKIwGyn2brEJzrxpV6xsHBp+m4w
|
||||||
|
6r0+PtwuWA0NauTCUzJ1biUdH8t0TgBL6YLaMjlrfU7JstH3TpcZzhJzsjfy0+zV
|
||||||
|
NT2TO3kSzXpQ5M2VjOoHPm2fqxD/js+ThDB3QLi4+C7HqakfiTY1lYzXl9/vayt6
|
||||||
|
DUD29r9pYL9ErB9tYko2rat54EY7k7Ts6S5jf+8G7Zz234We1APhvqaG
|
||||||
|
-----END ENCRYPTED PRIVATE KEY-----
|
||||||
|
`
|
||||||
|
crypto.keys.import(pem, 'mypassword', (err, key) => {
|
||||||
|
expect(err).to.not.exist()
|
||||||
|
expect(key).to.exist()
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
Loading…
x
Reference in New Issue
Block a user