rsa-key
Version:
Converts between RSA key formats, detecting input format (PEM, DER, PKCS1, PKCS8). No OpenSSL needed.
362 lines (284 loc) • 11.4 kB
JavaScript
const { assert } = require('chai');
const RSAKey = require('../src');
const NodeRSA = require('node-rsa');
describe('Module entry point', function() {
it('should return RSAKey class', function() {
assert.equal(RSAKey.name, 'RSAKey');
});
});
describe('RSAKey', function() {
let testKey,
testEncodedPrivatePKCS8PEM,
testEncodedPublicPKCS8PEM,
pubKey,
privKey;
before(function() {
this.timeout(10000);
testKey = new NodeRSA({ b: 256 });
testEncodedPrivatePKCS8PEM = testKey.exportKey('pkcs8-private-pem');
testEncodedPublicPKCS8PEM = testKey.exportKey('pkcs8-public-pem');
pubKey = new RSAKey(testEncodedPublicPKCS8PEM);
privKey = new RSAKey(testEncodedPrivatePKCS8PEM);
});
describe('Creation and importing', function() {
let key;
it('should create an empty object', function() {
key = new RSAKey();
assert.instanceOf(key, RSAKey);
});
it('should have empty components property', function() {
assert.isObject(key.components);
assert.deepEqual(key.components, {});
});
it('hasKey should be false', function() {
assert.isFalse(key.hasKey());
});
it('isEmpty should be true', function() {
assert.isTrue(key.isEmpty());
});
it('getType should return null', function() {
assert.isNull(key.getType());
});
it('should fail trying to export key', function() {
assert.throws(() => {
key.exportKey();
}, 'key is empty');
});
it('should fail trying to generate fingerprint', function() {
assert.throws(() => {
key.getFingerprint();
}, 'key is empty');
});
it('_requireKey should throw', function() {
assert.throws(() => {
key._requireKey();
}, 'key is empty');
});
it('should import a key', function() {
assert.doesNotThrow(() => {
key.importKey(testEncodedPrivatePKCS8PEM);
assert.isObject(key.components);
});
});
it('should import a key while creating RSAKey object', function() {
assert.doesNotThrow(() => {
const keyImported = new RSAKey(testEncodedPublicPKCS8PEM);
assert.isObject(keyImported);
});
});
it('should import from another RSAKey instance', function() {
const newKey = new RSAKey();
newKey.importKey(key);
assert.deepEqual(newKey.components, key.components);
});
});
describe('Handling public keys', function() {
it('hasKey should be true', function() {
assert.isTrue(pubKey.hasKey());
});
it('isEmpty should be false', function() {
assert.isFalse(pubKey.isEmpty());
});
it('isPublic should be true', function() {
assert.isTrue(pubKey.isPublic());
});
it('isPublic(true) should be true', function() {
assert.isTrue(pubKey.isPublic(true));
});
it('isPrivate should be false', function() {
assert.isFalse(pubKey.isPrivate());
});
it('getType should return public', function() {
assert.equal(pubKey.getType(), 'public');
});
it('_requireKey should not throw', function() {
assert.doesNotThrow(() => {
pubKey._requireKey();
});
});
it('_requireKey should throw if private key is required', function() {
assert.throws(() => {
pubKey._requireKey('test', true);
}, 'this is a public key');
});
describe('exporting key', function() {
it('should fail trying to export private PKCS8 PEM key', function() {
assert.throws(() => {
pubKey.exportKey('pkcs8', 'private', 'pem');
}, 'components are missing');
});
it('should fail trying to export private PKCS1 PEM key', function() {
assert.throws(() => {
pubKey.exportKey('pkcs1', 'private', 'pem');
}, 'components are missing');
});
it('should export public PKCS8 PEM key', function() {
const exported = pubKey.exportKey('pkcs8', 'public', 'pem');
const correct = testKey.exportKey('pkcs8-public-pem');
assert.equal(exported, correct);
});
it('should export public PKCS1 PEM key', function() {
const exported = pubKey.exportKey('pkcs1', 'public', 'pem');
const correct = testKey.exportKey('pkcs1-public-pem');
assert.equal(exported, correct);
});
it('should fail trying to export private PKCS8 DER key', function() {
assert.throws(() => {
pubKey.exportKey('pkcs8', 'private', 'der').toString('base64');
}, 'components are missing');
});
it('should fail trying to export private PKCS1 DER key', function() {
assert.throws(() => {
pubKey.exportKey('pkcs1', 'private', 'der').toString('base64');
}, 'components are missing');
});
it('should export public PKCS8 DER key', function() {
const exported = pubKey.exportKey('pkcs8', 'public', 'der').toString('base64');
const correct = testKey.exportKey('pkcs8-public-der').toString('base64');
assert.equal(exported, correct);
});
it('should export public PKCS1 DER key', function() {
const exported = pubKey.exportKey('pkcs1', 'public', 'der').toString('base64');
const correct = testKey.exportKey('pkcs1-public-der').toString('base64');
assert.equal(exported, correct);
});
it('should export public PKCS8 PEM key by default', function() {
const exported = pubKey.exportKey();
const correct = testKey.exportKey('pkcs8-public-pem');
assert.equal(exported, correct);
});
});
});
describe('Handling private keys', function() {
it('hasKey should be true', function() {
assert.isTrue(privKey.hasKey());
});
it('isEmpty should be false', function() {
assert.isFalse(privKey.isEmpty());
});
it('isPublic should be true', function() {
assert.isTrue(privKey.isPublic());
});
it('isPublic(true) should be false', function() {
assert.isFalse(privKey.isPublic(true));
});
it('isPrivate should be true', function() {
assert.isTrue(privKey.isPrivate());
});
it('getType should return private', function() {
assert.equal(privKey.getType(), 'private');
});
it('_requireKey should not throw', function() {
assert.doesNotThrow(() => {
privKey._requireKey();
});
});
it('_requireKey should not throw if private key is required', function() {
assert.doesNotThrow(() => {
privKey._requireKey('test', true);
});
});
describe('exporting key', function() {
it('should export private PKCS8 PEM key', function() {
const exported = privKey.exportKey('pkcs8', 'private', 'pem');
const correct = testKey.exportKey('pkcs8-private-pem');
assert.equal(exported, correct);
});
it('should export private PKCS1 PEM key', function() {
const exported = privKey.exportKey('pkcs1', 'private', 'pem');
const correct = testKey.exportKey('pkcs1-private-pem');
assert.equal(exported, correct);
});
it('should export public PKCS8 PEM key', function() {
const exported = privKey.exportKey('pkcs8', 'public', 'pem');
const correct = testKey.exportKey('pkcs8-public-pem');
assert.equal(exported, correct);
});
it('should export public PKCS1 PEM key', function() {
const exported = privKey.exportKey('pkcs1', 'public', 'pem');
const correct = testKey.exportKey('pkcs1-public-pem');
assert.equal(exported, correct);
});
it('should export private PKCS8 DER key', function() {
const exported = privKey.exportKey('pkcs8', 'private', 'der').toString('base64');
const correct = testKey.exportKey('pkcs8-private-der').toString('base64');
assert.equal(exported, correct);
});
it('should export private PKCS1 DER key', function() {
const exported = privKey.exportKey('pkcs1', 'private', 'der').toString('base64');
const correct = testKey.exportKey('pkcs1-private-der').toString('base64');
assert.equal(exported, correct);
});
it('should export public PKCS8 DER key', function() {
const exported = privKey.exportKey('pkcs8', 'public', 'der').toString('base64');
const correct = testKey.exportKey('pkcs8-public-der').toString('base64');
assert.equal(exported, correct);
});
it('should export public PKCS1 DER key', function() {
const exported = privKey.exportKey('pkcs1', 'public', 'der').toString('base64');
const correct = testKey.exportKey('pkcs1-public-der').toString('base64');
assert.equal(exported, correct);
});
it('should export private PKCS8 PEM key by default', function() {
const exported = privKey.exportKey();
const correct = testKey.exportKey('pkcs8-private-pem');
assert.equal(exported, correct);
});
it('should fail trying to export key with invalid export params', function() {
assert.throws(() => {
privKey.exportKey('clearly-invalid-param');
}, 'Unknown key export parameter');
});
});
});
describe('Caching time-consuming operation results', function() {
let key, exported;
const specs = ['public', 'pkcs1', 'pem'];
it('should export key', function() {
key = new RSAKey(privKey);
exported = key.exportKey(...specs);
assert.isString(exported);
});
it('should export previously cached key', function() {
key.components.n = 'different value';
const newExport = key.exportKey(...specs);
assert.equal(newExport, exported);
});
it('should export a different key for different specs', function() {
key.components.n = privKey.components.n;
const newExport = key.exportKey(...specs, 'pkcs8');
assert.notEqual(newExport, exported);
});
it('should clear cache when importing key', function() {
key.importKey(pubKey);
key.components.n = 'different value';
const newExport = key.exportKey(...specs);
assert.notEqual(newExport, exported);
});
});
describe('Other methods', function() {
let key;
before(function() {
key = new RSAKey(testEncodedPrivatePKCS8PEM);
});
it('getKeySize should return key size in bits', function() {
const size = key.getKeySize();
assert.equal(size, testKey.getKeySize());
});
it('getKeySize should return 0 for empty key', function() {
const size = new RSAKey().getKeySize();
assert.equal(size, 0);
});
it('getFingerprint should return key fingerprint', function() {
const keyString = '-----BEGIN PUBLIC KEY-----\n' +
'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8Z9kXlY0FtPi25ZLwQnI7OamZ\n' +
'VjWSIkNRcDrzN971MNKu0Q6LjDicCYH77iZKla6OgNxAB3uBHoZ27Wz1mMlqddbg\n' +
'HXe6ToEBQCW8K0gP4zGF+osV5B8iLoqCPiqCiCGcuX6ePs01AmFLkSzsqGdVu+tX\n' +
'L/+q3MOEIa7XYlO/lwIDAQAB\n' +
'-----END PUBLIC KEY-----';
const correct = 'df:bc:31:2b:9e:10:6a:b9:2e:5f:27:5a:14:41:72:6f';
const fingerprint = new RSAKey(keyString).getFingerprint();
assert.equal(fingerprint, correct);
});
});
});