提交物业报修模块
This commit is contained in:
1 parent
60cb1b09f8
commit
2371080245
597 files changed
+100361
-4145
No files matched your search
+179
@@ -0,0 +1,179 @@
|
||||
/**
|
||||
* PKCS_OAEP signature scheme
|
||||
*/
|
||||
|
||||
var BigInteger = require('../libs/jsbn');
|
||||
var crypt = require('crypto');
|
||||
|
||||
module.exports = {
|
||||
isEncryption: true,
|
||||
isSignature: false
|
||||
};
|
||||
|
||||
module.exports.digestLength = {
|
||||
md4: 16,
|
||||
md5: 16,
|
||||
ripemd160: 20,
|
||||
rmd160: 20,
|
||||
sha1: 20,
|
||||
sha224: 28,
|
||||
sha256: 32,
|
||||
sha384: 48,
|
||||
sha512: 64
|
||||
};
|
||||
|
||||
var DEFAULT_HASH_FUNCTION = 'sha1';
|
||||
|
||||
/*
|
||||
* OAEP Mask Generation Function 1
|
||||
* Generates a buffer full of pseudorandom bytes given seed and maskLength.
|
||||
* Giving the same seed, maskLength, and hashFunction will result in the same exact byte values in the buffer.
|
||||
*
|
||||
* https://tools.ietf.org/html/rfc3447#appendix-B.2.1
|
||||
*
|
||||
* Parameters:
|
||||
* seed [Buffer] The pseudo random seed for this function
|
||||
* maskLength [int] The length of the output
|
||||
* hashFunction [String] The hashing function to use. Will accept any valid crypto hash. Default "sha1"
|
||||
* Supports "sha1" and "sha256".
|
||||
* To add another algorythm the algorythem must be accepted by crypto.createHash, and then the length of the output of the hash function (the digest) must be added to the digestLength object below.
|
||||
* Most RSA implementations will be expecting sha1
|
||||
*/
|
||||
module.exports.eme_oaep_mgf1 = function (seed, maskLength, hashFunction) {
|
||||
hashFunction = hashFunction || DEFAULT_HASH_FUNCTION;
|
||||
var hLen = module.exports.digestLength[hashFunction];
|
||||
var count = Math.ceil(maskLength / hLen);
|
||||
var T = Buffer.alloc(hLen * count);
|
||||
var c = Buffer.alloc(4);
|
||||
for (var i = 0; i < count; ++i) {
|
||||
var hash = crypt.createHash(hashFunction);
|
||||
hash.update(seed);
|
||||
c.writeUInt32BE(i, 0);
|
||||
hash.update(c);
|
||||
hash.digest().copy(T, i * hLen);
|
||||
}
|
||||
return T.slice(0, maskLength);
|
||||
};
|
||||
|
||||
module.exports.makeScheme = function (key, options) {
|
||||
function Scheme(key, options) {
|
||||
this.key = key;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
Scheme.prototype.maxMessageLength = function () {
|
||||
return this.key.encryptedDataLength - 2 * module.exports.digestLength[this.options.encryptionSchemeOptions.hash || DEFAULT_HASH_FUNCTION] - 2;
|
||||
};
|
||||
|
||||
/**
|
||||
* Pad input
|
||||
* alg: PKCS1_OAEP
|
||||
*
|
||||
* https://tools.ietf.org/html/rfc3447#section-7.1.1
|
||||
*/
|
||||
Scheme.prototype.encPad = function (buffer) {
|
||||
var hash = this.options.encryptionSchemeOptions.hash || DEFAULT_HASH_FUNCTION;
|
||||
var mgf = this.options.encryptionSchemeOptions.mgf || module.exports.eme_oaep_mgf1;
|
||||
var label = this.options.encryptionSchemeOptions.label || Buffer.alloc(0);
|
||||
var emLen = this.key.encryptedDataLength;
|
||||
|
||||
var hLen = module.exports.digestLength[hash];
|
||||
|
||||
// Make sure we can put message into an encoded message of emLen bytes
|
||||
if (buffer.length > emLen - 2 * hLen - 2) {
|
||||
throw new Error("Message is too long to encode into an encoded message with a length of " + emLen + " bytes, increase" +
|
||||
"emLen to fix this error (minimum value for given parameters and options: " + (emLen - 2 * hLen - 2) + ")");
|
||||
}
|
||||
|
||||
var lHash = crypt.createHash(hash);
|
||||
lHash.update(label);
|
||||
lHash = lHash.digest();
|
||||
|
||||
var PS = Buffer.alloc(emLen - buffer.length - 2 * hLen - 1); // Padding "String"
|
||||
PS.fill(0); // Fill the buffer with octets of 0
|
||||
PS[PS.length - 1] = 1;
|
||||
|
||||
var DB = Buffer.concat([lHash, PS, buffer]);
|
||||
var seed = crypt.randomBytes(hLen);
|
||||
|
||||
// mask = dbMask
|
||||
var mask = mgf(seed, DB.length, hash);
|
||||
// XOR DB and dbMask together.
|
||||
for (var i = 0; i < DB.length; i++) {
|
||||
DB[i] ^= mask[i];
|
||||
}
|
||||
// DB = maskedDB
|
||||
|
||||
// mask = seedMask
|
||||
mask = mgf(DB, hLen, hash);
|
||||
// XOR seed and seedMask together.
|
||||
for (i = 0; i < seed.length; i++) {
|
||||
seed[i] ^= mask[i];
|
||||
}
|
||||
// seed = maskedSeed
|
||||
|
||||
var em = Buffer.alloc(1 + seed.length + DB.length);
|
||||
em[0] = 0;
|
||||
seed.copy(em, 1);
|
||||
DB.copy(em, 1 + seed.length);
|
||||
|
||||
return em;
|
||||
};
|
||||
|
||||
/**
|
||||
* Unpad input
|
||||
* alg: PKCS1_OAEP
|
||||
*
|
||||
* Note: This method works within the buffer given and modifies the values. It also returns a slice of the EM as the return Message.
|
||||
* If the implementation requires that the EM parameter be unmodified then the implementation should pass in a clone of the EM buffer.
|
||||
*
|
||||
* https://tools.ietf.org/html/rfc3447#section-7.1.2
|
||||
*/
|
||||
Scheme.prototype.encUnPad = function (buffer) {
|
||||
var hash = this.options.encryptionSchemeOptions.hash || DEFAULT_HASH_FUNCTION;
|
||||
var mgf = this.options.encryptionSchemeOptions.mgf || module.exports.eme_oaep_mgf1;
|
||||
var label = this.options.encryptionSchemeOptions.label || Buffer.alloc(0);
|
||||
|
||||
var hLen = module.exports.digestLength[hash];
|
||||
|
||||
// Check to see if buffer is a properly encoded OAEP message
|
||||
if (buffer.length < 2 * hLen + 2) {
|
||||
throw new Error("Error decoding message, the supplied message is not long enough to be a valid OAEP encoded message");
|
||||
}
|
||||
|
||||
var seed = buffer.slice(1, hLen + 1); // seed = maskedSeed
|
||||
var DB = buffer.slice(1 + hLen); // DB = maskedDB
|
||||
|
||||
var mask = mgf(DB, hLen, hash); // seedMask
|
||||
// XOR maskedSeed and seedMask together to get the original seed.
|
||||
for (var i = 0; i < seed.length; i++) {
|
||||
seed[i] ^= mask[i];
|
||||
}
|
||||
|
||||
mask = mgf(seed, DB.length, hash); // dbMask
|
||||
// XOR DB and dbMask together to get the original data block.
|
||||
for (i = 0; i < DB.length; i++) {
|
||||
DB[i] ^= mask[i];
|
||||
}
|
||||
|
||||
var lHash = crypt.createHash(hash);
|
||||
lHash.update(label);
|
||||
lHash = lHash.digest();
|
||||
|
||||
var lHashEM = DB.slice(0, hLen);
|
||||
if (lHashEM.toString("hex") != lHash.toString("hex")) {
|
||||
throw new Error("Error decoding message, the lHash calculated from the label provided and the lHash in the encrypted data do not match.");
|
||||
}
|
||||
|
||||
// Filter out padding
|
||||
i = hLen;
|
||||
while (DB[i++] === 0 && i < DB.length);
|
||||
if (DB[i - 1] != 1) {
|
||||
throw new Error("Error decoding message, there is no padding message separator byte");
|
||||
}
|
||||
|
||||
return DB.slice(i); // Message
|
||||
};
|
||||
|
||||
return new Scheme(key, options);
|
||||
};
|
||||
+238
@@ -0,0 +1,238 @@
|
||||
/**
|
||||
* PKCS1 padding and signature scheme
|
||||
*/
|
||||
|
||||
var BigInteger = require('../libs/jsbn');
|
||||
var crypt = require('crypto');
|
||||
var constants = require('constants');
|
||||
var SIGN_INFO_HEAD = {
|
||||
md2: Buffer.from('3020300c06082a864886f70d020205000410', 'hex'),
|
||||
md5: Buffer.from('3020300c06082a864886f70d020505000410', 'hex'),
|
||||
sha1: Buffer.from('3021300906052b0e03021a05000414', 'hex'),
|
||||
sha224: Buffer.from('302d300d06096086480165030402040500041c', 'hex'),
|
||||
sha256: Buffer.from('3031300d060960864801650304020105000420', 'hex'),
|
||||
sha384: Buffer.from('3041300d060960864801650304020205000430', 'hex'),
|
||||
sha512: Buffer.from('3051300d060960864801650304020305000440', 'hex'),
|
||||
ripemd160: Buffer.from('3021300906052b2403020105000414', 'hex'),
|
||||
rmd160: Buffer.from('3021300906052b2403020105000414', 'hex')
|
||||
};
|
||||
|
||||
var SIGN_ALG_TO_HASH_ALIASES = {
|
||||
'ripemd160': 'rmd160'
|
||||
};
|
||||
|
||||
var DEFAULT_HASH_FUNCTION = 'sha256';
|
||||
|
||||
module.exports = {
|
||||
isEncryption: true,
|
||||
isSignature: true
|
||||
};
|
||||
|
||||
module.exports.makeScheme = function (key, options) {
|
||||
function Scheme(key, options) {
|
||||
this.key = key;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
Scheme.prototype.maxMessageLength = function () {
|
||||
if (this.options.encryptionSchemeOptions && this.options.encryptionSchemeOptions.padding == constants.RSA_NO_PADDING) {
|
||||
return this.key.encryptedDataLength;
|
||||
}
|
||||
return this.key.encryptedDataLength - 11;
|
||||
};
|
||||
|
||||
/**
|
||||
* Pad input Buffer to encryptedDataLength bytes, and return Buffer.from
|
||||
* alg: PKCS#1
|
||||
* @param buffer
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
Scheme.prototype.encPad = function (buffer, options) {
|
||||
options = options || {};
|
||||
var filled;
|
||||
if (buffer.length > this.key.maxMessageLength) {
|
||||
throw new Error("Message too long for RSA (n=" + this.key.encryptedDataLength + ", l=" + buffer.length + ")");
|
||||
}
|
||||
if (this.options.encryptionSchemeOptions && this.options.encryptionSchemeOptions.padding == constants.RSA_NO_PADDING) {
|
||||
//RSA_NO_PADDING treated like JAVA left pad with zero character
|
||||
filled = Buffer.alloc(this.key.maxMessageLength - buffer.length);
|
||||
filled.fill(0);
|
||||
return Buffer.concat([filled, buffer]);
|
||||
}
|
||||
|
||||
/* Type 1: zeros padding for private key encrypt */
|
||||
if (options.type === 1) {
|
||||
filled = Buffer.alloc(this.key.encryptedDataLength - buffer.length - 1);
|
||||
filled.fill(0xff, 0, filled.length - 1);
|
||||
filled[0] = 1;
|
||||
filled[filled.length - 1] = 0;
|
||||
|
||||
return Buffer.concat([filled, buffer]);
|
||||
} else {
|
||||
/* random padding for public key encrypt */
|
||||
filled = Buffer.alloc(this.key.encryptedDataLength - buffer.length);
|
||||
filled[0] = 0;
|
||||
filled[1] = 2;
|
||||
var rand = crypt.randomBytes(filled.length - 3);
|
||||
for (var i = 0; i < rand.length; i++) {
|
||||
var r = rand[i];
|
||||
while (r === 0) { // non-zero only
|
||||
r = crypt.randomBytes(1)[0];
|
||||
}
|
||||
filled[i + 2] = r;
|
||||
}
|
||||
filled[filled.length - 1] = 0;
|
||||
return Buffer.concat([filled, buffer]);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Unpad input Buffer and, if valid, return the Buffer object
|
||||
* alg: PKCS#1 (type 2, random)
|
||||
* @param buffer
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
Scheme.prototype.encUnPad = function (buffer, options) {
|
||||
options = options || {};
|
||||
var i = 0;
|
||||
|
||||
if (this.options.encryptionSchemeOptions && this.options.encryptionSchemeOptions.padding == constants.RSA_NO_PADDING) {
|
||||
//RSA_NO_PADDING treated like JAVA left pad with zero character
|
||||
var unPad;
|
||||
if (typeof buffer.lastIndexOf == "function") { //patch for old node version
|
||||
unPad = buffer.slice(buffer.lastIndexOf('\0') + 1, buffer.length);
|
||||
} else {
|
||||
unPad = buffer.slice(String.prototype.lastIndexOf.call(buffer, '\0') + 1, buffer.length);
|
||||
}
|
||||
return unPad;
|
||||
}
|
||||
|
||||
if (buffer.length < 4) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/* Type 1: zeros padding for private key decrypt */
|
||||
if (options.type === 1) {
|
||||
if (buffer[0] !== 0 || buffer[1] !== 1) {
|
||||
return null;
|
||||
}
|
||||
i = 3;
|
||||
while (buffer[i] !== 0) {
|
||||
if (buffer[i] != 0xFF || ++i >= buffer.length) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* random padding for public key decrypt */
|
||||
if (buffer[0] !== 0 || buffer[1] !== 2) {
|
||||
return null;
|
||||
}
|
||||
i = 3;
|
||||
while (buffer[i] !== 0) {
|
||||
if (++i >= buffer.length) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return buffer.slice(i + 1, buffer.length);
|
||||
};
|
||||
|
||||
Scheme.prototype.sign = function (buffer) {
|
||||
var hashAlgorithm = this.options.signingSchemeOptions.hash || DEFAULT_HASH_FUNCTION;
|
||||
if (this.options.environment === 'browser') {
|
||||
hashAlgorithm = SIGN_ALG_TO_HASH_ALIASES[hashAlgorithm] || hashAlgorithm;
|
||||
|
||||
var hasher = crypt.createHash(hashAlgorithm);
|
||||
hasher.update(buffer);
|
||||
var hash = this.pkcs1pad(hasher.digest(), hashAlgorithm);
|
||||
var res = this.key.$doPrivate(new BigInteger(hash)).toBuffer(this.key.encryptedDataLength);
|
||||
|
||||
return res;
|
||||
} else {
|
||||
var signer = crypt.createSign('RSA-' + hashAlgorithm.toUpperCase());
|
||||
signer.update(buffer);
|
||||
return signer.sign(this.options.rsaUtils.exportKey('private'));
|
||||
}
|
||||
};
|
||||
|
||||
Scheme.prototype.verify = function (buffer, signature, signature_encoding) {
|
||||
if (this.options.encryptionSchemeOptions && this.options.encryptionSchemeOptions.padding == constants.RSA_NO_PADDING) {
|
||||
//RSA_NO_PADDING has no verify data
|
||||
return false;
|
||||
}
|
||||
var hashAlgorithm = this.options.signingSchemeOptions.hash || DEFAULT_HASH_FUNCTION;
|
||||
if (this.options.environment === 'browser') {
|
||||
hashAlgorithm = SIGN_ALG_TO_HASH_ALIASES[hashAlgorithm] || hashAlgorithm;
|
||||
|
||||
if (signature_encoding) {
|
||||
signature = Buffer.from(signature, signature_encoding);
|
||||
}
|
||||
|
||||
var hasher = crypt.createHash(hashAlgorithm);
|
||||
hasher.update(buffer);
|
||||
var hash = this.pkcs1pad(hasher.digest(), hashAlgorithm);
|
||||
var m = this.key.$doPublic(new BigInteger(signature));
|
||||
|
||||
return m.toBuffer().toString('hex') == hash.toString('hex');
|
||||
} else {
|
||||
var verifier = crypt.createVerify('RSA-' + hashAlgorithm.toUpperCase());
|
||||
verifier.update(buffer);
|
||||
return verifier.verify(this.options.rsaUtils.exportKey('public'), signature, signature_encoding);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* PKCS#1 zero pad input buffer to max data length
|
||||
* @param hashBuf
|
||||
* @param hashAlgorithm
|
||||
* @returns {*}
|
||||
*/
|
||||
Scheme.prototype.pkcs0pad = function (buffer) {
|
||||
var filled = Buffer.alloc(this.key.maxMessageLength - buffer.length);
|
||||
filled.fill(0);
|
||||
return Buffer.concat([filled, buffer]);
|
||||
};
|
||||
|
||||
Scheme.prototype.pkcs0unpad = function (buffer) {
|
||||
var unPad;
|
||||
if (typeof buffer.lastIndexOf == "function") { //patch for old node version
|
||||
unPad = buffer.slice(buffer.lastIndexOf('\0') + 1, buffer.length);
|
||||
} else {
|
||||
unPad = buffer.slice(String.prototype.lastIndexOf.call(buffer, '\0') + 1, buffer.length);
|
||||
}
|
||||
|
||||
return unPad;
|
||||
};
|
||||
|
||||
/**
|
||||
* PKCS#1 pad input buffer to max data length
|
||||
* @param hashBuf
|
||||
* @param hashAlgorithm
|
||||
* @returns {*}
|
||||
*/
|
||||
Scheme.prototype.pkcs1pad = function (hashBuf, hashAlgorithm) {
|
||||
var digest = SIGN_INFO_HEAD[hashAlgorithm];
|
||||
if (!digest) {
|
||||
throw Error('Unsupported hash algorithm');
|
||||
}
|
||||
|
||||
var data = Buffer.concat([digest, hashBuf]);
|
||||
|
||||
if (data.length + 10 > this.key.encryptedDataLength) {
|
||||
throw Error('Key is too short for signing algorithm (' + hashAlgorithm + ')');
|
||||
}
|
||||
|
||||
var filled = Buffer.alloc(this.key.encryptedDataLength - data.length - 1);
|
||||
filled.fill(0xff, 0, filled.length - 1);
|
||||
filled[0] = 1;
|
||||
filled[filled.length - 1] = 0;
|
||||
|
||||
var res = Buffer.concat([filled, data]);
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
return new Scheme(key, options);
|
||||
};
|
||||
|
||||
|
||||
+183
@@ -0,0 +1,183 @@
|
||||
/**
|
||||
* PSS signature scheme
|
||||
*/
|
||||
|
||||
var BigInteger = require('../libs/jsbn');
|
||||
var crypt = require('crypto');
|
||||
|
||||
module.exports = {
|
||||
isEncryption: false,
|
||||
isSignature: true
|
||||
};
|
||||
|
||||
var DEFAULT_HASH_FUNCTION = 'sha1';
|
||||
var DEFAULT_SALT_LENGTH = 20;
|
||||
|
||||
module.exports.makeScheme = function (key, options) {
|
||||
var OAEP = require('./schemes').pkcs1_oaep;
|
||||
|
||||
/**
|
||||
* @param key
|
||||
* @param options
|
||||
* options [Object] An object that contains the following keys that specify certain options for encoding.
|
||||
* └>signingSchemeOptions
|
||||
* ├>hash [String] Hash function to use when encoding and generating masks. Must be a string accepted by node's crypto.createHash function. (default = "sha1")
|
||||
* ├>mgf [function] The mask generation function to use when encoding. (default = mgf1SHA1)
|
||||
* └>sLen [uint] The length of the salt to generate. (default = 20)
|
||||
* @constructor
|
||||
*/
|
||||
function Scheme(key, options) {
|
||||
this.key = key;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
Scheme.prototype.sign = function (buffer) {
|
||||
var mHash = crypt.createHash(this.options.signingSchemeOptions.hash || DEFAULT_HASH_FUNCTION);
|
||||
mHash.update(buffer);
|
||||
|
||||
var encoded = this.emsa_pss_encode(mHash.digest(), this.key.keySize - 1);
|
||||
return this.key.$doPrivate(new BigInteger(encoded)).toBuffer(this.key.encryptedDataLength);
|
||||
};
|
||||
|
||||
Scheme.prototype.verify = function (buffer, signature, signature_encoding) {
|
||||
if (signature_encoding) {
|
||||
signature = Buffer.from(signature, signature_encoding);
|
||||
}
|
||||
signature = new BigInteger(signature);
|
||||
|
||||
var emLen = Math.ceil((this.key.keySize - 1) / 8);
|
||||
var m = this.key.$doPublic(signature).toBuffer(emLen);
|
||||
|
||||
var mHash = crypt.createHash(this.options.signingSchemeOptions.hash || DEFAULT_HASH_FUNCTION);
|
||||
mHash.update(buffer);
|
||||
|
||||
return this.emsa_pss_verify(mHash.digest(), m, this.key.keySize - 1);
|
||||
};
|
||||
|
||||
/*
|
||||
* https://tools.ietf.org/html/rfc3447#section-9.1.1
|
||||
*
|
||||
* mHash [Buffer] Hashed message to encode
|
||||
* emBits [uint] Maximum length of output in bits. Must be at least 8hLen + 8sLen + 9 (hLen = Hash digest length in bytes | sLen = length of salt in bytes)
|
||||
* @returns {Buffer} The encoded message
|
||||
*/
|
||||
Scheme.prototype.emsa_pss_encode = function (mHash, emBits) {
|
||||
var hash = this.options.signingSchemeOptions.hash || DEFAULT_HASH_FUNCTION;
|
||||
var mgf = this.options.signingSchemeOptions.mgf || OAEP.eme_oaep_mgf1;
|
||||
var sLen = this.options.signingSchemeOptions.saltLength || DEFAULT_SALT_LENGTH;
|
||||
|
||||
var hLen = OAEP.digestLength[hash];
|
||||
var emLen = Math.ceil(emBits / 8);
|
||||
|
||||
if (emLen < hLen + sLen + 2) {
|
||||
throw new Error("Output length passed to emBits(" + emBits + ") is too small for the options " +
|
||||
"specified(" + hash + ", " + sLen + "). To fix this issue increase the value of emBits. (minimum size: " +
|
||||
(8 * hLen + 8 * sLen + 9) + ")"
|
||||
);
|
||||
}
|
||||
|
||||
var salt = crypt.randomBytes(sLen);
|
||||
|
||||
var Mapostrophe = Buffer.alloc(8 + hLen + sLen);
|
||||
Mapostrophe.fill(0, 0, 8);
|
||||
mHash.copy(Mapostrophe, 8);
|
||||
salt.copy(Mapostrophe, 8 + mHash.length);
|
||||
|
||||
var H = crypt.createHash(hash);
|
||||
H.update(Mapostrophe);
|
||||
H = H.digest();
|
||||
|
||||
var PS = Buffer.alloc(emLen - salt.length - hLen - 2);
|
||||
PS.fill(0);
|
||||
|
||||
var DB = Buffer.alloc(PS.length + 1 + salt.length);
|
||||
PS.copy(DB);
|
||||
DB[PS.length] = 0x01;
|
||||
salt.copy(DB, PS.length + 1);
|
||||
|
||||
var dbMask = mgf(H, DB.length, hash);
|
||||
|
||||
// XOR DB and dbMask together
|
||||
var maskedDB = Buffer.alloc(DB.length);
|
||||
for (var i = 0; i < dbMask.length; i++) {
|
||||
maskedDB[i] = DB[i] ^ dbMask[i];
|
||||
}
|
||||
|
||||
var bits = 8 * emLen - emBits;
|
||||
var mask = 255 ^ (255 >> 8 - bits << 8 - bits);
|
||||
maskedDB[0] = maskedDB[0] & mask;
|
||||
|
||||
var EM = Buffer.alloc(maskedDB.length + H.length + 1);
|
||||
maskedDB.copy(EM, 0);
|
||||
H.copy(EM, maskedDB.length);
|
||||
EM[EM.length - 1] = 0xbc;
|
||||
|
||||
return EM;
|
||||
};
|
||||
|
||||
/*
|
||||
* https://tools.ietf.org/html/rfc3447#section-9.1.2
|
||||
*
|
||||
* mHash [Buffer] Hashed message
|
||||
* EM [Buffer] Signature
|
||||
* emBits [uint] Length of EM in bits. Must be at least 8hLen + 8sLen + 9 to be a valid signature. (hLen = Hash digest length in bytes | sLen = length of salt in bytes)
|
||||
* @returns {Boolean} True if signature(EM) matches message(M)
|
||||
*/
|
||||
Scheme.prototype.emsa_pss_verify = function (mHash, EM, emBits) {
|
||||
var hash = this.options.signingSchemeOptions.hash || DEFAULT_HASH_FUNCTION;
|
||||
var mgf = this.options.signingSchemeOptions.mgf || OAEP.eme_oaep_mgf1;
|
||||
var sLen = this.options.signingSchemeOptions.saltLength || DEFAULT_SALT_LENGTH;
|
||||
|
||||
var hLen = OAEP.digestLength[hash];
|
||||
var emLen = Math.ceil(emBits / 8);
|
||||
|
||||
if (emLen < hLen + sLen + 2 || EM[EM.length - 1] != 0xbc) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var DB = Buffer.alloc(emLen - hLen - 1);
|
||||
EM.copy(DB, 0, 0, emLen - hLen - 1);
|
||||
|
||||
var mask = 0;
|
||||
for (var i = 0, bits = 8 * emLen - emBits; i < bits; i++) {
|
||||
mask |= 1 << (7 - i);
|
||||
}
|
||||
|
||||
if ((DB[0] & mask) !== 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var H = EM.slice(emLen - hLen - 1, emLen - 1);
|
||||
var dbMask = mgf(H, DB.length, hash);
|
||||
|
||||
// Unmask DB
|
||||
for (i = 0; i < DB.length; i++) {
|
||||
DB[i] ^= dbMask[i];
|
||||
}
|
||||
|
||||
bits = 8 * emLen - emBits;
|
||||
mask = 255 ^ (255 >> 8 - bits << 8 - bits);
|
||||
DB[0] = DB[0] & mask;
|
||||
|
||||
// Filter out padding
|
||||
for (i = 0; DB[i] === 0 && i < DB.length; i++);
|
||||
if (DB[i] != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var salt = DB.slice(DB.length - sLen);
|
||||
|
||||
var Mapostrophe = Buffer.alloc(8 + hLen + sLen);
|
||||
Mapostrophe.fill(0, 0, 8);
|
||||
mHash.copy(Mapostrophe, 8);
|
||||
salt.copy(Mapostrophe, 8 + mHash.length);
|
||||
|
||||
var Hapostrophe = crypt.createHash(hash);
|
||||
Hapostrophe.update(Mapostrophe);
|
||||
Hapostrophe = Hapostrophe.digest();
|
||||
|
||||
return H.toString("hex") === Hapostrophe.toString("hex");
|
||||
};
|
||||
|
||||
return new Scheme(key, options);
|
||||
};
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
module.exports = {
|
||||
pkcs1: require('./pkcs1'),
|
||||
pkcs1_oaep: require('./oaep'),
|
||||
pss: require('./pss'),
|
||||
|
||||
/**
|
||||
* Check if scheme has padding methods
|
||||
* @param scheme {string}
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
isEncryption: function (scheme) {
|
||||
return module.exports[scheme] && module.exports[scheme].isEncryption;
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if scheme has sign/verify methods
|
||||
* @param scheme {string}
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
isSignature: function (scheme) {
|
||||
return module.exports[scheme] && module.exports[scheme].isSignature;
|
||||
}
|
||||
};
|
||||
Reference in new issue
Block a user