crypto-conditions
Version:
Implementation of crypto-conditions in JavaScript
229 lines (187 loc) • 7.54 kB
JavaScript
;
var _Reflect$construct = require("@babel/runtime-corejs3/core-js-stable/reflect/construct");
var _Object$defineProperty = require("@babel/runtime-corejs3/core-js-stable/object/define-property");
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
_Object$defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/classCallCheck"));
var _createClass2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/createClass"));
var _inherits2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/inherits"));
var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/possibleConstructorReturn"));
var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/getPrototypeOf"));
var _rsa = _interopRequireDefault(require("../crypto/rsa"));
var _pem = _interopRequireDefault(require("../util/pem"));
var _baseSha = _interopRequireDefault(require("./base-sha256"));
var _missingDataError = _interopRequireDefault(require("../errors/missing-data-error"));
var _validationError = _interopRequireDefault(require("../errors/validation-error"));
var _fingerprint = require("../schemas/fingerprint");
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2.default)(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2.default)(this).constructor; result = _Reflect$construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2.default)(this, result); }; }
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !_Reflect$construct) return false; if (_Reflect$construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(_Reflect$construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
// Instantiate RSA signer with standard settings
var rsa = new _rsa.default();
/**
* RSA-SHA-256: RSA signature condition using SHA-256.
*
* This RSA condition uses RSA-PSS padding with SHA-256. The salt length is set
* equal the digest length of 32 bytes.
*
* The public exponent is fixed at 65537 and the public modulus must be between
* 128 (1017 bits) and 512 bytes (4096 bits) long.
*
* RSA-SHA-256 is assigned the type ID 3. It relies on the SHA-256 and RSA-PSS
* feature suites which corresponds to a feature bitmask of 0x11.
*/
var RsaSha256 = /*#__PURE__*/function (_BaseSha) {
(0, _inherits2.default)(RsaSha256, _BaseSha);
var _super = _createSuper(RsaSha256);
function RsaSha256() {
var _this;
(0, _classCallCheck2.default)(this, RsaSha256);
_this = _super.call(this);
_this.modulus = null;
_this.signature = null;
return _this;
}
(0, _createClass2.default)(RsaSha256, [{
key: "parseJson",
value: function parseJson(json) {
this.modulus = Buffer.from(json.modulus, 'base64');
this.signature = Buffer.from(json.signature, 'base64');
}
/**
* Produce the contents of the condition hash.
*
* This function is called internally by the `getCondition` method.
*
* @return {Buffer} Encoded contents of fingerprint hash.
*
* @private
*/
}, {
key: "getFingerprintContents",
value: function getFingerprintContents() {
if (!this.modulus) {
throw new _missingDataError.default('Requires modulus');
}
return _fingerprint.RsaFingerprintContents.encode({
modulus: this.modulus
});
}
}, {
key: "getAsn1JsonPayload",
value: function getAsn1JsonPayload() {
return {
modulus: this.modulus,
signature: this.signature
};
}
/**
* Set the public modulus.
*
* This is the modulus of the RSA public key. It has to be provided as a raw
* buffer with no leading zeros.
*
* @param {Buffer} modulus Public RSA modulus
*/
}, {
key: "setPublicModulus",
value: function setPublicModulus(modulus) {
if (!Buffer.isBuffer(modulus)) {
throw new TypeError('Modulus must be a buffer, was: ' + modulus);
}
if (modulus[0] === 0) {
throw new Error('Modulus may not contain leading zeros');
}
if (modulus.length > 512 || modulus.length < 128) {
throw new Error('Modulus must be between 128 bytes (1017 bits) and ' + '512 bytes (4096 bits), was: ' + modulus.length + ' bytes');
}
this.modulus = modulus;
}
/**
* Set the signature manually.
*
* The signature must be a valid RSA-PSS siganture.
*
* @param {Buffer} signature RSA signature.
*/
}, {
key: "setSignature",
value: function setSignature(signature) {
if (!Buffer.isBuffer(signature)) {
throw new TypeError('Signature must be a buffer, was: ' + signature);
}
this.signature = signature;
}
/**
* Sign the message.
*
* This method will take the provided message and create a signature using the
* provided RSA private key. The resulting signature is stored in the
* fulfillment.
*
* The key should be provided as a PEM encoded private key string.
*
* The message is padded using RSA-PSS with SHA256.
*
* @param {Buffer} message Message to sign.
* @param {String} privateKey RSA private key
*/
}, {
key: "sign",
value: function sign(message, privateKey) {
if (!this.modulus) {
this.setPublicModulus(_pem.default.modulusFromPrivateKey(privateKey));
}
this.signature = rsa.sign(privateKey, message);
}
/**
* Calculate the cost of fulfilling this condition.
*
* The cost of the RSA condition is the size of the modulus squared, divided
* by 64.
*
* @return {Number} Expected maximum cost to fulfill this condition
* @private
*/
}, {
key: "calculateCost",
value: function calculateCost() {
if (!this.modulus) {
throw new _missingDataError.default('Requires a public modulus');
}
return Math.pow(rsa.getModulusBitLength(this.modulus), 2) >>> RsaSha256.COST_RIGHT_SHIFT;
}
/**
* Verify the signature of this RSA fulfillment.
*
* The signature of this RSA fulfillment is verified against the provided
* message and the condition's public modulus.
*
* @param {Buffer} message Message to verify.
* @return {Boolean} Whether this fulfillment is valid.
*/
}, {
key: "validate",
value: function validate(message) {
if (!Buffer.isBuffer(message)) {
throw new Error('Message must be provided as a Buffer, was: ' + message);
}
var pssResult = rsa.verify(this.modulus, message, this.signature);
if (!pssResult) {
throw new _validationError.default('Invalid RSA signature');
}
return true;
}
}]);
return RsaSha256;
}(_baseSha.default);
RsaSha256.TYPE_ID = 3;
RsaSha256.TYPE_NAME = 'rsa-sha-256';
RsaSha256.TYPE_ASN1_CONDITION = 'rsaSha256Condition';
RsaSha256.TYPE_ASN1_FULFILLMENT = 'rsaSha256Fulfillment';
RsaSha256.TYPE_CATEGORY = 'simple';
RsaSha256.COST_RIGHT_SHIFT = 6; // 2^6 = 64
var _default = RsaSha256;
exports.default = _default;