forked from rachanon/stdbWeb
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
456 lines
15 KiB
456 lines
15 KiB
/*! rsasign-1.2.7.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license |
|
*/ |
|
/* |
|
* rsa-sign.js - adding signing functions to RSAKey class. |
|
* |
|
* version: 1.2.7 (2013 Aug 25) |
|
* |
|
* Copyright (c) 2010-2013 Kenji Urushima (kenji.urushima@gmail.com) |
|
* |
|
* This software is licensed under the terms of the MIT License. |
|
* http://kjur.github.com/jsrsasign/license/ |
|
* |
|
* The above copyright and license notice shall be |
|
* included in all copies or substantial portions of the Software. |
|
*/ |
|
|
|
/** |
|
* @fileOverview |
|
* @name rsasign-1.2.js |
|
* @author Kenji Urushima kenji.urushima@gmail.com |
|
* @version rsasign 1.2.7 |
|
* @license <a href="http://kjur.github.io/jsrsasign/license/">MIT License</a> |
|
*/ |
|
|
|
var _RE_HEXDECONLY = new RegExp(""); |
|
_RE_HEXDECONLY.compile("[^0-9a-f]", "gi"); |
|
|
|
// ======================================================================== |
|
// Signature Generation |
|
// ======================================================================== |
|
|
|
function _rsasign_getHexPaddedDigestInfoForString(s, keySize, hashAlg) { |
|
var hashFunc = function(s) { return KJUR.crypto.Util.hashString(s, hashAlg); }; |
|
var sHashHex = hashFunc(s); |
|
|
|
return KJUR.crypto.Util.getPaddedDigestInfoHex(sHashHex, hashAlg, keySize); |
|
} |
|
|
|
function _zeroPaddingOfSignature(hex, bitLength) { |
|
var s = ""; |
|
var nZero = bitLength / 4 - hex.length; |
|
for (var i = 0; i < nZero; i++) { |
|
s = s + "0"; |
|
} |
|
return s + hex; |
|
} |
|
|
|
/** |
|
* sign for a message string with RSA private key.<br/> |
|
* @name signString |
|
* @memberOf RSAKey |
|
* @function |
|
* @param {String} s message string to be signed. |
|
* @param {String} hashAlg hash algorithm name for signing.<br/> |
|
* @return returns hexadecimal string of signature value. |
|
*/ |
|
function _rsasign_signString(s, hashAlg) { |
|
var hashFunc = function(s) { return KJUR.crypto.Util.hashString(s, hashAlg); }; |
|
var sHashHex = hashFunc(s); |
|
|
|
return this.signWithMessageHash(sHashHex, hashAlg); |
|
} |
|
|
|
/** |
|
* sign hash value of message to be signed with RSA private key.<br/> |
|
* @name signWithMessageHash |
|
* @memberOf RSAKey |
|
* @function |
|
* @param {String} sHashHex hexadecimal string of hash value of message to be signed. |
|
* @param {String} hashAlg hash algorithm name for signing.<br/> |
|
* @return returns hexadecimal string of signature value. |
|
* @since rsasign 1.2.6 |
|
*/ |
|
function _rsasign_signWithMessageHash(sHashHex, hashAlg) { |
|
var hPM = KJUR.crypto.Util.getPaddedDigestInfoHex(sHashHex, hashAlg, this.n.bitLength()); |
|
var biPaddedMessage = parseBigInt(hPM, 16); |
|
var biSign = this.doPrivate(biPaddedMessage); |
|
var hexSign = biSign.toString(16); |
|
return _zeroPaddingOfSignature(hexSign, this.n.bitLength()); |
|
} |
|
|
|
function _rsasign_signStringWithSHA1(s) { |
|
return _rsasign_signString.call(this, s, 'sha1'); |
|
} |
|
|
|
function _rsasign_signStringWithSHA256(s) { |
|
return _rsasign_signString.call(this, s, 'sha256'); |
|
} |
|
|
|
// PKCS#1 (PSS) mask generation function |
|
function pss_mgf1_str(seed, len, hash) { |
|
var mask = '', i = 0; |
|
|
|
while (mask.length < len) { |
|
mask += hextorstr(hash(rstrtohex(seed + String.fromCharCode.apply(String, [ |
|
(i & 0xff000000) >> 24, |
|
(i & 0x00ff0000) >> 16, |
|
(i & 0x0000ff00) >> 8, |
|
i & 0x000000ff])))); |
|
i += 1; |
|
} |
|
|
|
return mask; |
|
} |
|
|
|
/** |
|
* sign for a message string with RSA private key by PKCS#1 PSS signing.<br/> |
|
* @name signStringPSS |
|
* @memberOf RSAKey |
|
* @function |
|
* @param {String} s message string to be signed. |
|
* @param {String} hashAlg hash algorithm name for signing. |
|
* @param {Integer} sLen salt byte length from 0 to (keybytelen - hashbytelen - 2). |
|
* There are two special values: |
|
* <ul> |
|
* <li>-1: sets the salt length to the digest length</li> |
|
* <li>-2: sets the salt length to maximum permissible value |
|
* (i.e. keybytelen - hashbytelen - 2)</li> |
|
* </ul> |
|
* DEFAULT is -1. (NOTE: OpenSSL's default is -2.) |
|
* @return returns hexadecimal string of signature value. |
|
*/ |
|
function _rsasign_signStringPSS(s, hashAlg, sLen) { |
|
var hashFunc = function(sHex) { return KJUR.crypto.Util.hashHex(sHex, hashAlg); } |
|
var hHash = hashFunc(rstrtohex(s)); |
|
|
|
if (sLen === undefined) sLen = -1; |
|
return this.signWithMessageHashPSS(hHash, hashAlg, sLen); |
|
} |
|
|
|
/** |
|
* sign hash value of message with RSA private key by PKCS#1 PSS signing.<br/> |
|
* @name signWithMessageHashPSS |
|
* @memberOf RSAKey |
|
* @function |
|
* @param {String} hHash hexadecimal hash value of message to be signed. |
|
* @param {String} hashAlg hash algorithm name for signing. |
|
* @param {Integer} sLen salt byte length from 0 to (keybytelen - hashbytelen - 2). |
|
* There are two special values: |
|
* <ul> |
|
* <li>-1: sets the salt length to the digest length</li> |
|
* <li>-2: sets the salt length to maximum permissible value |
|
* (i.e. keybytelen - hashbytelen - 2)</li> |
|
* </ul> |
|
* DEFAULT is -1. (NOTE: OpenSSL's default is -2.) |
|
* @return returns hexadecimal string of signature value. |
|
* @since rsasign 1.2.6 |
|
*/ |
|
function _rsasign_signWithMessageHashPSS(hHash, hashAlg, sLen) { |
|
var mHash = hextorstr(hHash); |
|
var hLen = mHash.length; |
|
var emBits = this.n.bitLength() - 1; |
|
var emLen = Math.ceil(emBits / 8); |
|
var i; |
|
var hashFunc = function(sHex) { return KJUR.crypto.Util.hashHex(sHex, hashAlg); } |
|
|
|
if (sLen === -1 || sLen === undefined) { |
|
sLen = hLen; // same as hash length |
|
} else if (sLen === -2) { |
|
sLen = emLen - hLen - 2; // maximum |
|
} else if (sLen < -2) { |
|
throw "invalid salt length"; |
|
} |
|
|
|
if (emLen < (hLen + sLen + 2)) { |
|
throw "data too long"; |
|
} |
|
|
|
var salt = ''; |
|
|
|
if (sLen > 0) { |
|
salt = new Array(sLen); |
|
new SecureRandom().nextBytes(salt); |
|
salt = String.fromCharCode.apply(String, salt); |
|
} |
|
|
|
var H = hextorstr(hashFunc(rstrtohex('\x00\x00\x00\x00\x00\x00\x00\x00' + mHash + salt))); |
|
var PS = []; |
|
|
|
for (i = 0; i < emLen - sLen - hLen - 2; i += 1) { |
|
PS[i] = 0x00; |
|
} |
|
|
|
var DB = String.fromCharCode.apply(String, PS) + '\x01' + salt; |
|
var dbMask = pss_mgf1_str(H, DB.length, hashFunc); |
|
var maskedDB = []; |
|
|
|
for (i = 0; i < DB.length; i += 1) { |
|
maskedDB[i] = DB.charCodeAt(i) ^ dbMask.charCodeAt(i); |
|
} |
|
|
|
var mask = (0xff00 >> (8 * emLen - emBits)) & 0xff; |
|
maskedDB[0] &= ~mask; |
|
|
|
for (i = 0; i < hLen; i++) { |
|
maskedDB.push(H.charCodeAt(i)); |
|
} |
|
|
|
maskedDB.push(0xbc); |
|
|
|
return _zeroPaddingOfSignature(this.doPrivate(new BigInteger(maskedDB)).toString(16), |
|
this.n.bitLength()); |
|
} |
|
|
|
// ======================================================================== |
|
// Signature Verification |
|
// ======================================================================== |
|
|
|
function _rsasign_getDecryptSignatureBI(biSig, hN, hE) { |
|
var rsa = new RSAKey(); |
|
rsa.setPublic(hN, hE); |
|
var biDecryptedSig = rsa.doPublic(biSig); |
|
return biDecryptedSig; |
|
} |
|
|
|
function _rsasign_getHexDigestInfoFromSig(biSig, hN, hE) { |
|
var biDecryptedSig = _rsasign_getDecryptSignatureBI(biSig, hN, hE); |
|
var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, ''); |
|
return hDigestInfo; |
|
} |
|
|
|
function _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo) { |
|
for (var algName in KJUR.crypto.Util.DIGESTINFOHEAD) { |
|
var head = KJUR.crypto.Util.DIGESTINFOHEAD[algName]; |
|
var len = head.length; |
|
if (hDigestInfo.substring(0, len) == head) { |
|
var a = [algName, hDigestInfo.substring(len)]; |
|
return a; |
|
} |
|
} |
|
return []; |
|
} |
|
|
|
function _rsasign_verifySignatureWithArgs(sMsg, biSig, hN, hE) { |
|
var hDigestInfo = _rsasign_getHexDigestInfoFromSig(biSig, hN, hE); |
|
var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo); |
|
if (digestInfoAry.length == 0) return false; |
|
var algName = digestInfoAry[0]; |
|
var diHashValue = digestInfoAry[1]; |
|
var ff = function(s) { return KJUR.crypto.Util.hashString(s, algName); }; |
|
var msgHashValue = ff(sMsg); |
|
return (diHashValue == msgHashValue); |
|
} |
|
|
|
function _rsasign_verifyHexSignatureForMessage(hSig, sMsg) { |
|
var biSig = parseBigInt(hSig, 16); |
|
var result = _rsasign_verifySignatureWithArgs(sMsg, biSig, |
|
this.n.toString(16), |
|
this.e.toString(16)); |
|
return result; |
|
} |
|
|
|
/** |
|
* verifies a sigature for a message string with RSA public key.<br/> |
|
* @name verifyString |
|
* @memberOf RSAKey# |
|
* @function |
|
* @param {String} sMsg message string to be verified. |
|
* @param {String} hSig hexadecimal string of siganture.<br/> |
|
* non-hexadecimal charactors including new lines will be ignored. |
|
* @return returns 1 if valid, otherwise 0 |
|
*/ |
|
function _rsasign_verifyString(sMsg, hSig) { |
|
hSig = hSig.replace(_RE_HEXDECONLY, ''); |
|
hSig = hSig.replace(/[ \n]+/g, ""); |
|
var biSig = parseBigInt(hSig, 16); |
|
if (biSig.bitLength() > this.n.bitLength()) return 0; |
|
var biDecryptedSig = this.doPublic(biSig); |
|
var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, ''); |
|
var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo); |
|
|
|
if (digestInfoAry.length == 0) return false; |
|
var algName = digestInfoAry[0]; |
|
var diHashValue = digestInfoAry[1]; |
|
var ff = function(s) { return KJUR.crypto.Util.hashString(s, algName); }; |
|
var msgHashValue = ff(sMsg); |
|
return (diHashValue == msgHashValue); |
|
} |
|
|
|
/** |
|
* verifies a sigature for a message string with RSA public key.<br/> |
|
* @name verifyWithMessageHash |
|
* @memberOf RSAKey |
|
* @function |
|
* @param {String} sHashHex hexadecimal hash value of message to be verified. |
|
* @param {String} hSig hexadecimal string of siganture.<br/> |
|
* non-hexadecimal charactors including new lines will be ignored. |
|
* @return returns 1 if valid, otherwise 0 |
|
* @since rsasign 1.2.6 |
|
*/ |
|
function _rsasign_verifyWithMessageHash(sHashHex, hSig) { |
|
hSig = hSig.replace(_RE_HEXDECONLY, ''); |
|
hSig = hSig.replace(/[ \n]+/g, ""); |
|
var biSig = parseBigInt(hSig, 16); |
|
if (biSig.bitLength() > this.n.bitLength()) return 0; |
|
var biDecryptedSig = this.doPublic(biSig); |
|
var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, ''); |
|
var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo); |
|
|
|
if (digestInfoAry.length == 0) return false; |
|
var algName = digestInfoAry[0]; |
|
var diHashValue = digestInfoAry[1]; |
|
return (diHashValue == sHashHex); |
|
} |
|
|
|
/** |
|
* verifies a sigature for a message string with RSA public key by PKCS#1 PSS sign.<br/> |
|
* @name verifyStringPSS |
|
* @memberOf RSAKey |
|
* @function |
|
* @param {String} sMsg message string to be verified. |
|
* @param {String} hSig hexadecimal string of signature value |
|
* @param {String} hashAlg hash algorithm name |
|
* @param {Integer} sLen salt byte length from 0 to (keybytelen - hashbytelen - 2). |
|
* There are two special values: |
|
* <ul> |
|
* <li>-1: sets the salt length to the digest length</li> |
|
* <li>-2: sets the salt length to maximum permissible value |
|
* (i.e. keybytelen - hashbytelen - 2)</li> |
|
* </ul> |
|
* DEFAULT is -1. (NOTE: OpenSSL's default is -2.) |
|
* @return returns true if valid, otherwise false |
|
*/ |
|
function _rsasign_verifyStringPSS(sMsg, hSig, hashAlg, sLen) { |
|
var hashFunc = function(sHex) { return KJUR.crypto.Util.hashHex(sHex, hashAlg); }; |
|
var hHash = hashFunc(rstrtohex(sMsg)); |
|
|
|
if (sLen === undefined) sLen = -1; |
|
return this.verifyWithMessageHashPSS(hHash, hSig, hashAlg, sLen); |
|
} |
|
|
|
/** |
|
* verifies a sigature for a hash value of message string with RSA public key by PKCS#1 PSS sign.<br/> |
|
* @name verifyWithMessageHashPSS |
|
* @memberOf RSAKey |
|
* @function |
|
* @param {String} hHash hexadecimal hash value of message string to be verified. |
|
* @param {String} hSig hexadecimal string of signature value |
|
* @param {String} hashAlg hash algorithm name |
|
* @param {Integer} sLen salt byte length from 0 to (keybytelen - hashbytelen - 2). |
|
* There are two special values: |
|
* <ul> |
|
* <li>-1: sets the salt length to the digest length</li> |
|
* <li>-2: sets the salt length to maximum permissible value |
|
* (i.e. keybytelen - hashbytelen - 2)</li> |
|
* </ul> |
|
* DEFAULT is -1 (NOTE: OpenSSL's default is -2.) |
|
* @return returns true if valid, otherwise false |
|
* @since rsasign 1.2.6 |
|
*/ |
|
function _rsasign_verifyWithMessageHashPSS(hHash, hSig, hashAlg, sLen) { |
|
var biSig = new BigInteger(hSig, 16); |
|
|
|
if (biSig.bitLength() > this.n.bitLength()) { |
|
return false; |
|
} |
|
|
|
var hashFunc = function(sHex) { return KJUR.crypto.Util.hashHex(sHex, hashAlg); }; |
|
var mHash = hextorstr(hHash); |
|
var hLen = mHash.length; |
|
var emBits = this.n.bitLength() - 1; |
|
var emLen = Math.ceil(emBits / 8); |
|
var i; |
|
|
|
if (sLen === -1 || sLen === undefined) { |
|
sLen = hLen; // same as hash length |
|
} else if (sLen === -2) { |
|
sLen = emLen - hLen - 2; // recover |
|
} else if (sLen < -2) { |
|
throw "invalid salt length"; |
|
} |
|
|
|
if (emLen < (hLen + sLen + 2)) { |
|
throw "data too long"; |
|
} |
|
|
|
var em = this.doPublic(biSig).toByteArray(); |
|
|
|
for (i = 0; i < em.length; i += 1) { |
|
em[i] &= 0xff; |
|
} |
|
|
|
while (em.length < emLen) { |
|
em.unshift(0); |
|
} |
|
|
|
if (em[emLen -1] !== 0xbc) { |
|
throw "encoded message does not end in 0xbc"; |
|
} |
|
|
|
em = String.fromCharCode.apply(String, em); |
|
|
|
var maskedDB = em.substr(0, emLen - hLen - 1); |
|
var H = em.substr(maskedDB.length, hLen); |
|
|
|
var mask = (0xff00 >> (8 * emLen - emBits)) & 0xff; |
|
|
|
if ((maskedDB.charCodeAt(0) & mask) !== 0) { |
|
throw "bits beyond keysize not zero"; |
|
} |
|
|
|
var dbMask = pss_mgf1_str(H, maskedDB.length, hashFunc); |
|
var DB = []; |
|
|
|
for (i = 0; i < maskedDB.length; i += 1) { |
|
DB[i] = maskedDB.charCodeAt(i) ^ dbMask.charCodeAt(i); |
|
} |
|
|
|
DB[0] &= ~mask; |
|
|
|
var checkLen = emLen - hLen - sLen - 2; |
|
|
|
for (i = 0; i < checkLen; i += 1) { |
|
if (DB[i] !== 0x00) { |
|
throw "leftmost octets not zero"; |
|
} |
|
} |
|
|
|
if (DB[checkLen] !== 0x01) { |
|
throw "0x01 marker not found"; |
|
} |
|
|
|
return H === hextorstr(hashFunc(rstrtohex('\x00\x00\x00\x00\x00\x00\x00\x00' + mHash + |
|
String.fromCharCode.apply(String, DB.slice(-sLen))))); |
|
} |
|
|
|
RSAKey.prototype.signWithMessageHash = _rsasign_signWithMessageHash; |
|
RSAKey.prototype.signString = _rsasign_signString; |
|
RSAKey.prototype.signStringWithSHA1 = _rsasign_signStringWithSHA1; |
|
RSAKey.prototype.signStringWithSHA256 = _rsasign_signStringWithSHA256; |
|
RSAKey.prototype.sign = _rsasign_signString; |
|
RSAKey.prototype.signWithSHA1 = _rsasign_signStringWithSHA1; |
|
RSAKey.prototype.signWithSHA256 = _rsasign_signStringWithSHA256; |
|
|
|
RSAKey.prototype.signWithMessageHashPSS = _rsasign_signWithMessageHashPSS; |
|
RSAKey.prototype.signStringPSS = _rsasign_signStringPSS; |
|
RSAKey.prototype.signPSS = _rsasign_signStringPSS; |
|
RSAKey.SALT_LEN_HLEN = -1; |
|
RSAKey.SALT_LEN_MAX = -2; |
|
|
|
RSAKey.prototype.verifyWithMessageHash = _rsasign_verifyWithMessageHash; |
|
RSAKey.prototype.verifyString = _rsasign_verifyString; |
|
RSAKey.prototype.verifyHexSignatureForMessage = _rsasign_verifyHexSignatureForMessage; |
|
RSAKey.prototype.verify = _rsasign_verifyString; |
|
RSAKey.prototype.verifyHexSignatureForByteArrayMessage = _rsasign_verifyHexSignatureForMessage; |
|
|
|
RSAKey.prototype.verifyWithMessageHashPSS = _rsasign_verifyWithMessageHashPSS; |
|
RSAKey.prototype.verifyStringPSS = _rsasign_verifyStringPSS; |
|
RSAKey.prototype.verifyPSS = _rsasign_verifyStringPSS; |
|
RSAKey.SALT_LEN_RECOVER = -2; |
|
|
|
/** |
|
* @name RSAKey |
|
* @class key of RSA public key algorithm |
|
* @description Tom Wu's RSA Key class and extension |
|
*/
|
|
|