/*! rsasign-1.2.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license | |
*/ | |
// | |
// rsa-sign.js - adding signing functions to RSAKey class. | |
// | |
// | |
// version: 1.2.1 (08 May 2012) | |
// | |
// Copyright (c) 2010-2012 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. | |
// | |
// Depends on: | |
// function sha1.hex(s) of sha1.js | |
// jsbn.js | |
// jsbn2.js | |
// rsa.js | |
// rsa2.js | |
// | |
// keysize / pmstrlen | |
// 512 / 128 | |
// 1024 / 256 | |
// 2048 / 512 | |
// 4096 / 1024 | |
/** | |
* @property {Dictionary} _RSASIGN_DIHEAD | |
* @description Array of head part of hexadecimal DigestInfo value for hash algorithms. | |
* You can add any DigestInfo hash algorith for signing. | |
* See PKCS#1 v2.1 spec (p38). | |
*/ | |
var _RSASIGN_DIHEAD = []; | |
_RSASIGN_DIHEAD['sha1'] = "3021300906052b0e03021a05000414"; | |
_RSASIGN_DIHEAD['sha256'] = "3031300d060960864801650304020105000420"; | |
_RSASIGN_DIHEAD['sha384'] = "3041300d060960864801650304020205000430"; | |
_RSASIGN_DIHEAD['sha512'] = "3051300d060960864801650304020305000440"; | |
_RSASIGN_DIHEAD['md2'] = "3020300c06082a864886f70d020205000410"; | |
_RSASIGN_DIHEAD['md5'] = "3020300c06082a864886f70d020505000410"; | |
_RSASIGN_DIHEAD['ripemd160'] = "3021300906052b2403020105000414"; | |
/** | |
* @property {Dictionary} _RSASIGN_HASHHEXFUNC | |
* @description Array of functions which calculate hash and returns it as hexadecimal. | |
* You can add any hash algorithm implementations. | |
*/ | |
var _RSASIGN_HASHHEXFUNC = []; | |
_RSASIGN_HASHHEXFUNC['sha1'] = function(s){return hex_sha1(s);}; // http://pajhome.org.uk/crypt/md5/md5.html | |
_RSASIGN_HASHHEXFUNC['sha256'] = function(s){return hex_sha256(s);} // http://pajhome.org.uk/crypt/md5/md5.html | |
_RSASIGN_HASHHEXFUNC['sha512'] = function(s){return hex_sha512(s);} // http://pajhome.org.uk/crypt/md5/md5.html | |
_RSASIGN_HASHHEXFUNC['md5'] = function(s){return hex_md5(s);}; // http://pajhome.org.uk/crypt/md5/md5.html | |
_RSASIGN_HASHHEXFUNC['ripemd160'] = function(s){return hex_rmd160(s);}; // http://pajhome.org.uk/crypt/md5/md5.html | |
//@author axelcdv | |
var _RSASIGN_HASHBYTEFUNC = []; | |
_RSASIGN_HASHBYTEFUNC['sha256'] = function(byteArray){return hex_sha256_from_bytes(byteArray);}; | |
//_RSASIGN_HASHHEXFUNC['sha1'] = function(s){return sha1.hex(s);} // http://user1.matsumoto.ne.jp/~goma/js/hash.html | |
//_RSASIGN_HASHHEXFUNC['sha256'] = function(s){return sha256.hex;} // http://user1.matsumoto.ne.jp/~goma/js/hash.html | |
var _RE_HEXDECONLY = new RegExp(""); | |
_RE_HEXDECONLY.compile("[^0-9a-f]", "gi"); | |
// ======================================================================== | |
// Signature Generation | |
// ======================================================================== | |
function _rsasign_getHexPaddedDigestInfoForString(s, keySize, hashAlg) { | |
var pmStrLen = keySize / 4; | |
var hashFunc = _RSASIGN_HASHHEXFUNC[hashAlg]; | |
var sHashHex = hashFunc(s); | |
var sHead = "0001"; | |
var sTail = "00" + _RSASIGN_DIHEAD[hashAlg] + sHashHex; | |
var sMid = ""; | |
var fLen = pmStrLen - sHead.length - sTail.length; | |
for (var i = 0; i < fLen; i += 2) { | |
sMid += "ff"; | |
} | |
sPaddedMessageHex = sHead + sMid + sTail; | |
return sPaddedMessageHex; | |
} | |
//@author: Meki Cheraoui | |
function _rsasign_getHexPaddedDigestInfoForStringHEX(s, keySize, hashAlg) { | |
var pmStrLen = keySize / 4; | |
var hashFunc = _RSASIGN_HASHHEXFUNC[hashAlg]; | |
var sHashHex = hashFunc(s); | |
var sHead = "0001"; | |
var sTail = "00" + _RSASIGN_DIHEAD[hashAlg] + sHashHex; | |
var sMid = ""; | |
var fLen = pmStrLen - sHead.length - sTail.length; | |
for (var i = 0; i < fLen; i += 2) { | |
sMid += "ff"; | |
} | |
sPaddedMessageHex = sHead + sMid + sTail; | |
return sPaddedMessageHex; | |
} | |
/** | |
* Apply padding, then computes the hash of the given byte array, according to the key size and with the hash algorithm | |
* @param byteArray (byte[]) | |
* @param keySize (int) | |
* @param hashAlg the hash algorithm to apply (string) | |
* @return the hash of byteArray | |
*/ | |
function _rsasign_getHexPaddedDigestInfoForByteArray(byteArray, keySize, hashAlg){ | |
var pmStrLen = keySize / 4; | |
var hashFunc = _RSASIGN_HASHBYTEFUNC[hashAlg]; | |
var sHashHex = hashFunc(byteArray); //returns hex hash | |
var sHead = "0001"; | |
var sTail = "00" + _RSASIGN_DIHEAD[hashAlg] + sHashHex; | |
var sMid = ""; | |
var fLen = pmStrLen - sHead.length - sTail.length; | |
for (var i = 0; i < fLen; i += 2) { | |
sMid += "ff"; | |
} | |
sPaddedMessageHex = sHead + sMid + sTail; | |
return sPaddedMessageHex; | |
} | |
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) { | |
//alert("this.n.bitLength() = " + this.n.bitLength()); | |
var hPM = _rsasign_getHexPaddedDigestInfoForString(s, this.n.bitLength(), hashAlg); | |
var biPaddedMessage = parseBigInt(hPM, 16); | |
var biSign = this.doPrivate(biPaddedMessage); | |
var hexSign = biSign.toString(16); | |
return _zeroPaddingOfSignature(hexSign, this.n.bitLength()); | |
} | |
//@author: ucla-cs | |
function _rsasign_signStringHEX(s, hashAlg) { | |
//alert("this.n.bitLength() = " + this.n.bitLength()); | |
var hPM = _rsasign_getHexPaddedDigestInfoForString(s, this.n.bitLength(), hashAlg); | |
var biPaddedMessage = parseBigInt(hPM, 16); | |
var biSign = this.doPrivate(biPaddedMessage); | |
var hexSign = biSign.toString(16); | |
return _zeroPaddingOfSignature(hexSign, this.n.bitLength()); | |
} | |
/** | |
* Sign a message byteArray with an RSA private key | |
* @name signByteArray | |
* @memberOf RSAKey# | |
* @function | |
* @param {byte[]} byteArray | |
* @param {Sring} hashAlg the hash algorithm to apply | |
* @param {RSAKey} rsa key to sign with: hack because the context is lost here | |
* @return hexadecimal string of signature value | |
*/ | |
function _rsasign_signByteArray(byteArray, hashAlg, rsaKey) { | |
var hPM = _rsasign_getHexPaddedDigestInfoForByteArray(byteArray, rsaKey.n.bitLength(), hashAlg); ///hack because the context is lost here | |
var biPaddedMessage = parseBigInt(hPM, 16); | |
var biSign = rsaKey.doPrivate(biPaddedMessage); //hack because the context is lost here | |
var hexSign = biSign.toString(16); | |
return _zeroPaddingOfSignature(hexSign, rsaKey.n.bitLength()); //hack because the context is lost here | |
} | |
/** | |
* Sign a byte array with the Sha-256 algorithm | |
* @param {byte[]} byteArray | |
* @return hexadecimal string of signature value | |
*/ | |
function _rsasign_signByteArrayWithSHA256(byteArray){ | |
return _rsasign_signByteArray(byteArray, 'sha256', this); //Hack because the context is lost in the next function | |
} | |
function _rsasign_signStringWithSHA1(s) { | |
return _rsasign_signString(s, 'sha1'); | |
} | |
function _rsasign_signStringWithSHA256(s) { | |
return _rsasign_signString(s, 'sha256'); | |
} | |
// ======================================================================== | |
// 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 _RSASIGN_DIHEAD) { | |
var head = _RSASIGN_DIHEAD[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 = _RSASIGN_HASHHEXFUNC[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, ''); | |
if(LOG>3)console.log('n is '+this.n); | |
if(LOG>3)console.log('e is '+this.e); | |
if (hSig.length != this.n.bitLength() / 4) return 0; | |
hSig = hSig.replace(/[ \n]+/g, ""); | |
var biSig = parseBigInt(hSig, 16); | |
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 = _RSASIGN_HASHHEXFUNC[algName]; | |
var msgHashValue = ff(sMsg); | |
return (diHashValue == msgHashValue); | |
} | |
/** | |
* verifies a sigature for a message byte array with RSA public key.<br/> | |
* @name verifyByteArray | |
* @memberOf RSAKey# | |
* @function | |
* @param {byte[]} byteArray message byte array to be verified. | |
* @param {String} hSig hexadecimal string of signature.<br/> | |
* non-hexadecimal charactors including new lines will be ignored. | |
* @return returns 1 if valid, otherwise 0 | |
*/ | |
function _rsasign_verifyByteArray(byteArray, hSig) { | |
hSig = hSig.replace(_RE_HEXDECONLY, ''); | |
if(LOG>3)console.log('n is '+this.n); | |
if(LOG>3)console.log('e is '+this.e); | |
if (hSig.length != this.n.bitLength() / 4) return 0; | |
hSig = hSig.replace(/[ \n]+/g, ""); | |
var biSig = parseBigInt(hSig, 16); | |
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 = _RSASIGN_HASHBYTEFUNC[algName]; | |
var msgHashValue = ff(byteArray); | |
return (diHashValue == msgHashValue); | |
} | |
RSAKey.prototype.signString = _rsasign_signString; | |
RSAKey.prototype.signByteArray = _rsasign_signByteArray; //@author axelcdv | |
RSAKey.prototype.signByteArrayWithSHA256 = _rsasign_signByteArrayWithSHA256; //@author axelcdv | |
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.signStringHEX = _rsasign_signStringHEX; | |
RSAKey.prototype.signStringWithSHA1HEX = _rsasign_signStringWithSHA1HEX; | |
RSAKey.prototype.signStringWithSHA256HEX = _rsasign_signStringWithSHA256HEX; | |
RSAKey.prototype.signHEX = _rsasign_signStringHEX; | |
RSAKey.prototype.signWithSHA1HEX = _rsasign_signStringWithSHA1HEX; | |
RSAKey.prototype.signWithSHA256HEX = _rsasign_signStringWithSHA256HEX; | |
*/ | |
RSAKey.prototype.verifyByteArray = _rsasign_verifyByteArray; | |
RSAKey.prototype.verifyString = _rsasign_verifyString; | |
RSAKey.prototype.verifyHexSignatureForMessage = _rsasign_verifyHexSignatureForMessage; | |
RSAKey.prototype.verify = _rsasign_verifyString; | |
RSAKey.prototype.verifyHexSignatureForByteArrayMessage = _rsasign_verifyHexSignatureForMessage; | |
/* | |
RSAKey.prototype.verifyStringHEX = _rsasign_verifyStringHEX; | |
RSAKey.prototype.verifyHexSignatureForMessageHEX = _rsasign_verifyHexSignatureForMessageHEX; | |
RSAKey.prototype.verifyHEX = _rsasign_verifyStringHEX; | |
RSAKey.prototype.verifyHexSignatureForByteArrayMessageHEX = _rsasign_verifyHexSignatureForMessageHEX; | |
*/ | |
/** | |
* @name RSAKey | |
* @class | |
* @description Tom Wu's RSA Key class and extension | |
*/ |