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.
457 lines
15 KiB
457 lines
15 KiB
9 years ago
|
/*! 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
|
||
|
*/
|