UNPKG

crypto-conditions

Version:

Implementation of crypto-conditions in JavaScript

173 lines (125 loc) 7.48 kB
"use strict"; 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 _fill = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/fill")); var _concat = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/concat")); var _slice = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/slice")); var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/createClass")); var _crypto = require("crypto"); var _mgf = _interopRequireDefault(require("./mgf1")); var _xor = _interopRequireDefault(require("../util/xor")); var Pss = /*#__PURE__*/function () { function Pss(opts) { (0, _classCallCheck2.default)(this, Pss); opts = opts || {}; this.hashAlgorithm = opts.hashAlgorithm || 'sha256'; this.hashLength = (0, _crypto.createHash)(this.hashAlgorithm).digest().length; this.saltLength = this.hashLength; } /** * Create padded message for signing. * * This is an implementation of EMSA-PSS-ENCODE from RFC3447, section 9.1.1. * * @param {Buffer} message Message to sign. * @param {Number} encodedMessageBits Number of bits of the resulting padded * message. * @return {Buffer} Padded message of length encodedMessageBits bits */ (0, _createClass2.default)(Pss, [{ key: "encode", value: function encode(message, encodedMessageBits) { var _context, _context2; // Calculate emLen var encodedMessageBytes = Math.ceil(encodedMessageBits / 8); // Step 2. mHash = Hash(M) var messageHash = (0, _crypto.createHash)(this.hashAlgorithm).update(message).digest(); // Step 3. If emLen < hLen + sLen + 2, output "encoding error" and stop. if (encodedMessageBytes < this.hashLength + this.saltLength + 2) { throw new Error('Encoding error: RSA modulus is too small for ' + this.hashAlgorithm); } // Step 4. Generate a random salt var salt = (0, _crypto.randomBytes)(this.saltLength); // Step 5. M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt // Step 6. H = Hash(M') var hash = (0, _crypto.createHash)(this.hashAlgorithm).update((0, _fill.default)(_context = Buffer.alloc(8)).call(_context, 0)).update(messageHash).update(salt).digest(); // Step 7. Generate an octet string PS consisting of emLen - sLen - hLen - 2 // zero octets. // Step 8. Let DB = PS || 0x01 || salt var dataBlock = (0, _concat.default)(Buffer).call(Buffer, [(0, _fill.default)(_context2 = Buffer.alloc(encodedMessageBytes - this.saltLength - this.hashLength - 2)).call(_context2, 0), Buffer.from([1]), salt]); // Step 9. Let dbMask = MGF(H, emLen - hLen - 1) var mgf1 = new _mgf.default({ hashAlgorithm: this.hashAlgorithm }); var dataBlockMask = mgf1.generate(hash, encodedMessageBytes - this.hashLength - 1); // Step 10. Let maskedDB = DB \xor dbMask var maskedDataBlock = (0, _xor.default)(dataBlock, dataBlockMask); // Step 11. Set the leftmost 8emLen - emBits bits of the leftmost octet in // maskedDB to zero. maskedDataBlock[0] &= 0xff >>> encodedMessageBytes * 8 - encodedMessageBits; // Step 12. Let EM = maskedDB || H || 0xbc. // Step 13. Output EM. return (0, _concat.default)(Buffer).call(Buffer, [maskedDataBlock, hash, Buffer.from([0xbc])]); } /** * Verify that a padded message matches a specimen message. * * Used for RSA signature verification. * * This is an implementation of EMSA-PSS-VERIFY from RFC3447, section 9.1.2. * * @param {Buffer} message Message to be verified. * @param {Buffer} encodedMessage Padded message to be compared. * @param {Number} encodedMessageBits Number of bits in the padded message. * @return {Boolean} Verification result. */ }, { key: "verify", value: function verify(message, encodedMessage, encodedMessageBits) { var _context3; // Calculate emLen var encodedMessageBytes = Math.ceil(encodedMessageBits / 8); // Step 2. mHash = Hash(M) var messageHash = (0, _crypto.createHash)(this.hashAlgorithm).update(message).digest(); // Step 3. If emLen < hLen + sLen + 2, output "inconsistent" and stop. if (encodedMessageBytes < this.hashLength + this.saltLength + 2) { return false; } // Step 4. If the rightmost octet of EM does not have hexadecimal value // 0xbc, output "inconsistent" and stop. if (encodedMessage[encodedMessage.length - 1] !== 0xbc) { return false; } // Step 5. Let maskedDB be the leftmost emLen - hLen - 1 octets of EM, and // let H be the next hLen octets. var dataBlockLength = encodedMessageBytes - this.hashLength - 1; var maskedDataBlock = (0, _slice.default)(encodedMessage).call(encodedMessage, 0, dataBlockLength); var hash = (0, _slice.default)(encodedMessage).call(encodedMessage, dataBlockLength, dataBlockLength + this.hashLength); // Step 6. If the leftmost 8emLen - emBits bits of the leftmost octet in // maskedDB are not all equal to zero, output "inconsistent" and // stop. var expectedMask = 0xff >>> encodedMessageBytes * 8 - encodedMessageBits; if (maskedDataBlock[0] & ~expectedMask) { return false; } // Step 7. Let dbMask = MGF(H, emLen - hLen - 1). var mgf1 = new _mgf.default({ hashAlgorithm: this.hashAlgorithm }); var dataBlockMask = mgf1.generate(hash, encodedMessageBytes - this.hashLength - 1); // Step 8. Let DB = maskedDB \xor dbMask. var dataBlock = (0, _xor.default)(maskedDataBlock, dataBlockMask); // Step 9. Set the leftmost 8emLen - emBits bits of the leftmost octet in DB // to zero. dataBlock[0] &= expectedMask; // Step 10. If the emLen - hLen - sLen - 2 leftmost octets of DB are not zero // or if the octet at position emLen - hLen - sLen - 1 (the leftmost // position is "position 1") does not have hexadecimal value 0x01, // output "inconsistent" and stop. var prefixLength = encodedMessageBytes - this.hashLength - this.saltLength - 2; for (var i = 0; i < prefixLength; i++) { if (dataBlock[i] !== 0) { return false; } } if (dataBlock[prefixLength] !== 0x01) { return false; } // Step 11. Let salt be the last sLen octets of DB. var salt = (0, _slice.default)(dataBlock).call(dataBlock, dataBlock.length - this.saltLength); // Step 12. Let M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt // Step 13. Let H' = Hash(M'), an octet string of length hLen. var reconstructedHash = (0, _crypto.createHash)(this.hashAlgorithm).update((0, _fill.default)(_context3 = Buffer.alloc(8)).call(_context3, 0)).update(messageHash).update(salt).digest(); // Step 14. If H = H', output "consistent." Otherwise, output "inconsistent." return Buffer.compare(hash, reconstructedHash) === 0; } }]); return Pss; }(); Pss.EMPTY_BUFFER = Buffer.alloc(0); var _default = Pss; exports.default = _default;