/*! 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 MIT License */ 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.
* @name signString * @memberOf RSAKey * @function * @param {String} s message string to be signed. * @param {String} hashAlg hash algorithm name for signing.
* @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.
* @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.
* @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.
* @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: * * 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.
* @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: * * 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.
* @name verifyString * @memberOf RSAKey# * @function * @param {String} sMsg message string to be verified. * @param {String} hSig hexadecimal string of siganture.
* 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.
* @name verifyWithMessageHash * @memberOf RSAKey * @function * @param {String} sHashHex hexadecimal hash value of message to be verified. * @param {String} hSig hexadecimal string of siganture.
* 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.
* @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: * * 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.
* @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: * * 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 */