Website/node_modules/sshpk/lib/fingerprint.js

141 lines
3.3 KiB
JavaScript

// Copyright 2015 Joyent, Inc.
module.exports = Fingerprint;
var assert = require('assert-plus');
var algs = require('./algs');
var crypto = require('crypto');
var errs = require('./errors');
var Key = require('./key');
var utils = require('./utils');
var FingerprintFormatError = errs.FingerprintFormatError;
var InvalidAlgorithmError = errs.InvalidAlgorithmError;
function Fingerprint(opts) {
assert.object(opts, 'options');
assert.buffer(opts.hash, 'options.hash');
assert.string(opts.algorithm, 'options.algorithm');
this.algorithm = opts.algorithm.toLowerCase();
if (algs.hashAlgs[this.algorithm] !== true)
throw (new InvalidAlgorithmError(this.algorithm));
this.hash = opts.hash;
}
Fingerprint.prototype.toString = function (format) {
if (format === undefined) {
if (this.algorithm === 'md5')
format = 'hex';
else
format = 'base64';
}
assert.string(format);
switch (format) {
case 'hex':
return (addColons(this.hash.toString('hex')));
case 'base64':
return (sshBase64Format(this.algorithm,
this.hash.toString('base64')));
default:
throw (new FingerprintFormatError(undefined, format));
}
};
Fingerprint.prototype.matches = function (key) {
assert.object(key, 'key');
utils.assertCompatible(key, Key, [1, 0], 'key');
var theirHash = key.hash(this.algorithm);
var theirHash2 = crypto.createHash(this.algorithm).
update(theirHash).digest('base64');
if (this.hash2 === undefined)
this.hash2 = crypto.createHash(this.algorithm).
update(this.hash).digest('base64');
return (this.hash2 === theirHash2);
};
Fingerprint.parse = function (fp, enAlgs) {
assert.string(fp, 'fingerprint');
var alg, hash;
assert.optionalArrayOfString(enAlgs, 'algorithms');
var parts = fp.split(':');
if (parts.length == 2) {
alg = parts[0].toLowerCase();
/*JSSTYLED*/
var base64RE = /^[A-Za-z0-9+\/=]+$/;
if (!base64RE.test(parts[1]))
throw (new FingerprintFormatError(fp));
try {
hash = new Buffer(parts[1], 'base64');
} catch (e) {
throw (new FingerprintFormatError(fp));
}
} else if (parts.length > 2) {
alg = 'md5';
if (parts[0].toLowerCase() === 'md5')
parts = parts.slice(1);
parts = parts.join('');
/*JSSTYLED*/
var md5RE = /^[a-fA-F0-9]+$/;
if (!md5RE.test(parts))
throw (new FingerprintFormatError(fp));
try {
hash = new Buffer(parts, 'hex');
} catch (e) {
throw (new FingerprintFormatError(fp));
}
}
if (alg === undefined)
throw (new FingerprintFormatError(fp));
if (algs.hashAlgs[alg] === undefined)
throw (new InvalidAlgorithmError(alg));
if (enAlgs !== undefined) {
enAlgs = enAlgs.map(function (a) { return a.toLowerCase(); });
if (enAlgs.indexOf(alg) === -1)
throw (new InvalidAlgorithmError(alg));
}
return (new Fingerprint({algorithm: alg, hash: hash}));
};
function addColons(s) {
/*JSSTYLED*/
return (s.replace(/(.{2})(?=.)/g, '$1:'));
}
function base64Strip(s) {
/*JSSTYLED*/
return (s.replace(/=*$/, ''));
}
function sshBase64Format(alg, h) {
return (alg.toUpperCase() + ':' + base64Strip(h));
}
Fingerprint.isFingerprint = function (obj, ver) {
return (utils.isCompatible(obj, Fingerprint, ver));
};
/*
* API versions for Fingerprint:
* [1,0] -- initial ver
* [1,1] -- first tagged ver
*/
Fingerprint.prototype._sshpkApiVersion = [1, 1];
Fingerprint._oldVersionDetect = function (obj) {
assert.func(obj.toString);
assert.func(obj.matches);
return ([1, 0]);
};