Alexander Afanasyev | 181a8b9 | 2013-02-28 13:28:53 -0800 | [diff] [blame] | 1 | /*! rsasign-1.2.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license |
| 2 | */ |
| 3 | // |
| 4 | // rsa-sign.js - adding signing functions to RSAKey class. |
| 5 | // |
| 6 | // |
| 7 | // version: 1.2.1 (08 May 2012) |
| 8 | // |
| 9 | // Copyright (c) 2010-2012 Kenji Urushima (kenji.urushima@gmail.com) |
| 10 | // |
| 11 | // This software is licensed under the terms of the MIT License. |
| 12 | // http://kjur.github.com/jsrsasign/license/ |
| 13 | // |
| 14 | // The above copyright and license notice shall be |
| 15 | // included in all copies or substantial portions of the Software. |
| 16 | |
| 17 | // |
| 18 | // Depends on: |
| 19 | // function sha1.hex(s) of sha1.js |
| 20 | // jsbn.js |
| 21 | // jsbn2.js |
| 22 | // rsa.js |
| 23 | // rsa2.js |
| 24 | // |
| 25 | |
| 26 | // keysize / pmstrlen |
| 27 | // 512 / 128 |
| 28 | // 1024 / 256 |
| 29 | // 2048 / 512 |
| 30 | // 4096 / 1024 |
| 31 | |
| 32 | /** |
| 33 | * @property {Dictionary} _RSASIGN_DIHEAD |
| 34 | * @description Array of head part of hexadecimal DigestInfo value for hash algorithms. |
| 35 | * You can add any DigestInfo hash algorith for signing. |
| 36 | * See PKCS#1 v2.1 spec (p38). |
| 37 | */ |
| 38 | var _RSASIGN_DIHEAD = []; |
| 39 | _RSASIGN_DIHEAD['sha1'] = "3021300906052b0e03021a05000414"; |
| 40 | _RSASIGN_DIHEAD['sha256'] = "3031300d060960864801650304020105000420"; |
| 41 | _RSASIGN_DIHEAD['sha384'] = "3041300d060960864801650304020205000430"; |
| 42 | _RSASIGN_DIHEAD['sha512'] = "3051300d060960864801650304020305000440"; |
| 43 | _RSASIGN_DIHEAD['md2'] = "3020300c06082a864886f70d020205000410"; |
| 44 | _RSASIGN_DIHEAD['md5'] = "3020300c06082a864886f70d020505000410"; |
| 45 | _RSASIGN_DIHEAD['ripemd160'] = "3021300906052b2403020105000414"; |
| 46 | |
| 47 | /** |
| 48 | * @property {Dictionary} _RSASIGN_HASHHEXFUNC |
| 49 | * @description Array of functions which calculate hash and returns it as hexadecimal. |
| 50 | * You can add any hash algorithm implementations. |
| 51 | */ |
| 52 | var _RSASIGN_HASHHEXFUNC = []; |
| 53 | _RSASIGN_HASHHEXFUNC['sha1'] = function(s){return hex_sha1(s);}; // http://pajhome.org.uk/crypt/md5/md5.html |
| 54 | _RSASIGN_HASHHEXFUNC['sha256'] = function(s){return hex_sha256(s);} // http://pajhome.org.uk/crypt/md5/md5.html |
| 55 | _RSASIGN_HASHHEXFUNC['sha512'] = function(s){return hex_sha512(s);} // http://pajhome.org.uk/crypt/md5/md5.html |
| 56 | _RSASIGN_HASHHEXFUNC['md5'] = function(s){return hex_md5(s);}; // http://pajhome.org.uk/crypt/md5/md5.html |
| 57 | _RSASIGN_HASHHEXFUNC['ripemd160'] = function(s){return hex_rmd160(s);}; // http://pajhome.org.uk/crypt/md5/md5.html |
| 58 | |
| 59 | //@author axelcdv |
| 60 | var _RSASIGN_HASHBYTEFUNC = []; |
| 61 | _RSASIGN_HASHBYTEFUNC['sha256'] = function(byteArray){return hex_sha256_from_bytes(byteArray);}; |
| 62 | |
| 63 | //_RSASIGN_HASHHEXFUNC['sha1'] = function(s){return sha1.hex(s);} // http://user1.matsumoto.ne.jp/~goma/js/hash.html |
| 64 | //_RSASIGN_HASHHEXFUNC['sha256'] = function(s){return sha256.hex;} // http://user1.matsumoto.ne.jp/~goma/js/hash.html |
| 65 | |
| 66 | var _RE_HEXDECONLY = new RegExp(""); |
| 67 | _RE_HEXDECONLY.compile("[^0-9a-f]", "gi"); |
| 68 | |
| 69 | // ======================================================================== |
| 70 | // Signature Generation |
| 71 | // ======================================================================== |
| 72 | |
| 73 | function _rsasign_getHexPaddedDigestInfoForString(s, keySize, hashAlg) { |
| 74 | var pmStrLen = keySize / 4; |
| 75 | var hashFunc = _RSASIGN_HASHHEXFUNC[hashAlg]; |
| 76 | var sHashHex = hashFunc(s); |
| 77 | |
| 78 | var sHead = "0001"; |
| 79 | var sTail = "00" + _RSASIGN_DIHEAD[hashAlg] + sHashHex; |
| 80 | var sMid = ""; |
| 81 | var fLen = pmStrLen - sHead.length - sTail.length; |
| 82 | for (var i = 0; i < fLen; i += 2) { |
| 83 | sMid += "ff"; |
| 84 | } |
| 85 | sPaddedMessageHex = sHead + sMid + sTail; |
| 86 | return sPaddedMessageHex; |
| 87 | } |
| 88 | |
| 89 | |
| 90 | //@author: Meki Cheraoui |
| 91 | function _rsasign_getHexPaddedDigestInfoForStringHEX(s, keySize, hashAlg) { |
| 92 | var pmStrLen = keySize / 4; |
| 93 | var hashFunc = _RSASIGN_HASHHEXFUNC[hashAlg]; |
| 94 | var sHashHex = hashFunc(s); |
| 95 | |
| 96 | var sHead = "0001"; |
| 97 | var sTail = "00" + _RSASIGN_DIHEAD[hashAlg] + sHashHex; |
| 98 | var sMid = ""; |
| 99 | var fLen = pmStrLen - sHead.length - sTail.length; |
| 100 | for (var i = 0; i < fLen; i += 2) { |
| 101 | sMid += "ff"; |
| 102 | } |
| 103 | sPaddedMessageHex = sHead + sMid + sTail; |
| 104 | return sPaddedMessageHex; |
| 105 | } |
| 106 | |
| 107 | /** |
| 108 | * Apply padding, then computes the hash of the given byte array, according to the key size and with the hash algorithm |
| 109 | * @param byteArray (byte[]) |
| 110 | * @param keySize (int) |
| 111 | * @param hashAlg the hash algorithm to apply (string) |
| 112 | * @return the hash of byteArray |
| 113 | */ |
| 114 | function _rsasign_getHexPaddedDigestInfoForByteArray(byteArray, keySize, hashAlg){ |
| 115 | var pmStrLen = keySize / 4; |
| 116 | var hashFunc = _RSASIGN_HASHBYTEFUNC[hashAlg]; |
| 117 | var sHashHex = hashFunc(byteArray); //returns hex hash |
| 118 | |
| 119 | var sHead = "0001"; |
| 120 | var sTail = "00" + _RSASIGN_DIHEAD[hashAlg] + sHashHex; |
| 121 | var sMid = ""; |
| 122 | var fLen = pmStrLen - sHead.length - sTail.length; |
| 123 | for (var i = 0; i < fLen; i += 2) { |
| 124 | sMid += "ff"; |
| 125 | } |
| 126 | sPaddedMessageHex = sHead + sMid + sTail; |
| 127 | return sPaddedMessageHex; |
| 128 | } |
| 129 | |
| 130 | function _zeroPaddingOfSignature(hex, bitLength) { |
| 131 | var s = ""; |
| 132 | var nZero = bitLength / 4 - hex.length; |
| 133 | for (var i = 0; i < nZero; i++) { |
| 134 | s = s + "0"; |
| 135 | } |
| 136 | return s + hex; |
| 137 | } |
| 138 | |
| 139 | /** |
| 140 | * sign for a message string with RSA private key.<br/> |
| 141 | * @name signString |
| 142 | * @memberOf RSAKey# |
| 143 | * @function |
| 144 | * @param {String} s message string to be signed. |
| 145 | * @param {String} hashAlg hash algorithm name for signing.<br/> |
| 146 | * @return returns hexadecimal string of signature value. |
| 147 | */ |
| 148 | function _rsasign_signString(s, hashAlg) { |
| 149 | //alert("this.n.bitLength() = " + this.n.bitLength()); |
| 150 | var hPM = _rsasign_getHexPaddedDigestInfoForString(s, this.n.bitLength(), hashAlg); |
| 151 | var biPaddedMessage = parseBigInt(hPM, 16); |
| 152 | var biSign = this.doPrivate(biPaddedMessage); |
| 153 | var hexSign = biSign.toString(16); |
| 154 | return _zeroPaddingOfSignature(hexSign, this.n.bitLength()); |
| 155 | } |
| 156 | |
| 157 | //@author: ucla-cs |
| 158 | function _rsasign_signStringHEX(s, hashAlg) { |
| 159 | //alert("this.n.bitLength() = " + this.n.bitLength()); |
| 160 | var hPM = _rsasign_getHexPaddedDigestInfoForString(s, this.n.bitLength(), hashAlg); |
| 161 | var biPaddedMessage = parseBigInt(hPM, 16); |
| 162 | var biSign = this.doPrivate(biPaddedMessage); |
| 163 | var hexSign = biSign.toString(16); |
| 164 | return _zeroPaddingOfSignature(hexSign, this.n.bitLength()); |
| 165 | } |
| 166 | |
| 167 | |
| 168 | /** |
| 169 | * Sign a message byteArray with an RSA private key |
| 170 | * @name signByteArray |
| 171 | * @memberOf RSAKey# |
| 172 | * @function |
| 173 | * @param {byte[]} byteArray |
| 174 | * @param {Sring} hashAlg the hash algorithm to apply |
| 175 | * @param {RSAKey} rsa key to sign with: hack because the context is lost here |
| 176 | * @return hexadecimal string of signature value |
| 177 | */ |
| 178 | function _rsasign_signByteArray(byteArray, hashAlg, rsaKey) { |
| 179 | var hPM = _rsasign_getHexPaddedDigestInfoForByteArray(byteArray, rsaKey.n.bitLength(), hashAlg); ///hack because the context is lost here |
| 180 | var biPaddedMessage = parseBigInt(hPM, 16); |
| 181 | var biSign = rsaKey.doPrivate(biPaddedMessage); //hack because the context is lost here |
| 182 | var hexSign = biSign.toString(16); |
| 183 | return _zeroPaddingOfSignature(hexSign, rsaKey.n.bitLength()); //hack because the context is lost here |
| 184 | } |
| 185 | |
| 186 | /** |
| 187 | * Sign a byte array with the Sha-256 algorithm |
| 188 | * @param {byte[]} byteArray |
| 189 | * @return hexadecimal string of signature value |
| 190 | */ |
| 191 | function _rsasign_signByteArrayWithSHA256(byteArray){ |
| 192 | return _rsasign_signByteArray(byteArray, 'sha256', this); //Hack because the context is lost in the next function |
| 193 | } |
| 194 | |
| 195 | |
| 196 | function _rsasign_signStringWithSHA1(s) { |
| 197 | return _rsasign_signString(s, 'sha1'); |
| 198 | } |
| 199 | |
| 200 | function _rsasign_signStringWithSHA256(s) { |
| 201 | return _rsasign_signString(s, 'sha256'); |
| 202 | } |
| 203 | |
| 204 | // ======================================================================== |
| 205 | // Signature Verification |
| 206 | // ======================================================================== |
| 207 | |
| 208 | function _rsasign_getDecryptSignatureBI(biSig, hN, hE) { |
| 209 | var rsa = new RSAKey(); |
| 210 | rsa.setPublic(hN, hE); |
| 211 | var biDecryptedSig = rsa.doPublic(biSig); |
| 212 | return biDecryptedSig; |
| 213 | } |
| 214 | |
| 215 | function _rsasign_getHexDigestInfoFromSig(biSig, hN, hE) { |
| 216 | var biDecryptedSig = _rsasign_getDecryptSignatureBI(biSig, hN, hE); |
| 217 | var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, ''); |
| 218 | return hDigestInfo; |
| 219 | } |
| 220 | |
| 221 | function _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo) { |
| 222 | for (var algName in _RSASIGN_DIHEAD) { |
| 223 | var head = _RSASIGN_DIHEAD[algName]; |
| 224 | var len = head.length; |
| 225 | if (hDigestInfo.substring(0, len) == head) { |
| 226 | var a = [algName, hDigestInfo.substring(len)]; |
| 227 | return a; |
| 228 | } |
| 229 | } |
| 230 | return []; |
| 231 | } |
| 232 | |
| 233 | function _rsasign_verifySignatureWithArgs(sMsg, biSig, hN, hE) { |
| 234 | var hDigestInfo = _rsasign_getHexDigestInfoFromSig(biSig, hN, hE); |
| 235 | var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo); |
| 236 | if (digestInfoAry.length == 0) return false; |
| 237 | var algName = digestInfoAry[0]; |
| 238 | var diHashValue = digestInfoAry[1]; |
| 239 | var ff = _RSASIGN_HASHHEXFUNC[algName]; |
| 240 | var msgHashValue = ff(sMsg); |
| 241 | return (diHashValue == msgHashValue); |
| 242 | } |
| 243 | |
| 244 | function _rsasign_verifyHexSignatureForMessage(hSig, sMsg) { |
| 245 | var biSig = parseBigInt(hSig, 16); |
| 246 | var result = _rsasign_verifySignatureWithArgs(sMsg, biSig, |
| 247 | this.n.toString(16), |
| 248 | this.e.toString(16)); |
| 249 | return result; |
| 250 | } |
| 251 | |
| 252 | /** |
| 253 | * verifies a sigature for a message string with RSA public key.<br/> |
| 254 | * @name verifyString |
| 255 | * @memberOf RSAKey# |
| 256 | * @function |
| 257 | * @param {String} sMsg message string to be verified. |
| 258 | * @param {String} hSig hexadecimal string of siganture.<br/> |
| 259 | * non-hexadecimal charactors including new lines will be ignored. |
| 260 | * @return returns 1 if valid, otherwise 0 |
| 261 | */ |
| 262 | function _rsasign_verifyString(sMsg, hSig) { |
| 263 | hSig = hSig.replace(_RE_HEXDECONLY, ''); |
| 264 | |
| 265 | if(LOG>3)console.log('n is '+this.n); |
| 266 | if(LOG>3)console.log('e is '+this.e); |
| 267 | |
| 268 | if (hSig.length != this.n.bitLength() / 4) return 0; |
| 269 | hSig = hSig.replace(/[ \n]+/g, ""); |
| 270 | var biSig = parseBigInt(hSig, 16); |
| 271 | var biDecryptedSig = this.doPublic(biSig); |
| 272 | var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, ''); |
| 273 | var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo); |
| 274 | |
| 275 | if (digestInfoAry.length == 0) return false; |
| 276 | var algName = digestInfoAry[0]; |
| 277 | var diHashValue = digestInfoAry[1]; |
| 278 | var ff = _RSASIGN_HASHHEXFUNC[algName]; |
| 279 | var msgHashValue = ff(sMsg); |
| 280 | return (diHashValue == msgHashValue); |
| 281 | } |
| 282 | |
| 283 | /** |
| 284 | * verifies a sigature for a message byte array with RSA public key.<br/> |
| 285 | * @name verifyByteArray |
| 286 | * @memberOf RSAKey# |
| 287 | * @function |
| 288 | * @param {byte[]} byteArray message byte array to be verified. |
| 289 | * @param {String} hSig hexadecimal string of signature.<br/> |
| 290 | * non-hexadecimal charactors including new lines will be ignored. |
| 291 | * @return returns 1 if valid, otherwise 0 |
| 292 | */ |
| 293 | function _rsasign_verifyByteArray(byteArray, witness, hSig) { |
| 294 | hSig = hSig.replace(_RE_HEXDECONLY, ''); |
| 295 | |
| 296 | if(LOG>3)console.log('n is '+this.n); |
| 297 | if(LOG>3)console.log('e is '+this.e); |
| 298 | |
| 299 | if (hSig.length != this.n.bitLength() / 4) return 0; |
| 300 | hSig = hSig.replace(/[ \n]+/g, ""); |
| 301 | var biSig = parseBigInt(hSig, 16); |
| 302 | var biDecryptedSig = this.doPublic(biSig); |
| 303 | var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, ''); |
| 304 | var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo); |
| 305 | |
| 306 | if (digestInfoAry.length == 0) return false; |
| 307 | var algName = digestInfoAry[0]; |
| 308 | var diHashValue = digestInfoAry[1]; |
| 309 | var msgHashValue = null; |
| 310 | |
| 311 | if (witness == null) { |
| 312 | var ff = _RSASIGN_HASHBYTEFUNC[algName]; |
| 313 | msgHashValue = ff(byteArray); |
| 314 | } else { |
| 315 | // Compute merkle hash |
| 316 | var h = hex_sha256_from_bytes(byteArray); |
| 317 | var index = witness.path.index; |
| 318 | for (var i = witness.path.digestList.length - 1; i >= 0; i--) { |
| 319 | var str = ""; |
| 320 | if (index % 2 == 0) { |
| 321 | str = h + witness.path.digestList[i]; |
| 322 | } else { |
| 323 | str = witness.path.digestList[i] + h; |
| 324 | } |
| 325 | h = hex_sha256_from_bytes(DataUtils.toNumbers(str)); |
| 326 | index = Math.floor(index / 2); |
| 327 | } |
| 328 | msgHashValue = hex_sha256_from_bytes(DataUtils.toNumbers(h)); |
| 329 | } |
| 330 | //console.log(diHashValue); |
| 331 | //console.log(msgHashValue); |
| 332 | return (diHashValue == msgHashValue); |
| 333 | } |
| 334 | |
| 335 | |
| 336 | RSAKey.prototype.signString = _rsasign_signString; |
| 337 | |
| 338 | RSAKey.prototype.signByteArray = _rsasign_signByteArray; //@author axelcdv |
| 339 | RSAKey.prototype.signByteArrayWithSHA256 = _rsasign_signByteArrayWithSHA256; //@author axelcdv |
| 340 | |
| 341 | RSAKey.prototype.signStringWithSHA1 = _rsasign_signStringWithSHA1; |
| 342 | RSAKey.prototype.signStringWithSHA256 = _rsasign_signStringWithSHA256; |
| 343 | RSAKey.prototype.sign = _rsasign_signString; |
| 344 | RSAKey.prototype.signWithSHA1 = _rsasign_signStringWithSHA1; |
| 345 | RSAKey.prototype.signWithSHA256 = _rsasign_signStringWithSHA256; |
| 346 | |
| 347 | |
| 348 | /*RSAKey.prototype.signStringHEX = _rsasign_signStringHEX; |
| 349 | RSAKey.prototype.signStringWithSHA1HEX = _rsasign_signStringWithSHA1HEX; |
| 350 | RSAKey.prototype.signStringWithSHA256HEX = _rsasign_signStringWithSHA256HEX; |
| 351 | RSAKey.prototype.signHEX = _rsasign_signStringHEX; |
| 352 | RSAKey.prototype.signWithSHA1HEX = _rsasign_signStringWithSHA1HEX; |
| 353 | RSAKey.prototype.signWithSHA256HEX = _rsasign_signStringWithSHA256HEX; |
| 354 | */ |
| 355 | |
| 356 | RSAKey.prototype.verifyByteArray = _rsasign_verifyByteArray; |
| 357 | RSAKey.prototype.verifyString = _rsasign_verifyString; |
| 358 | RSAKey.prototype.verifyHexSignatureForMessage = _rsasign_verifyHexSignatureForMessage; |
| 359 | RSAKey.prototype.verify = _rsasign_verifyString; |
| 360 | RSAKey.prototype.verifyHexSignatureForByteArrayMessage = _rsasign_verifyHexSignatureForMessage; |
| 361 | |
| 362 | /* |
| 363 | RSAKey.prototype.verifyStringHEX = _rsasign_verifyStringHEX; |
| 364 | RSAKey.prototype.verifyHexSignatureForMessageHEX = _rsasign_verifyHexSignatureForMessageHEX; |
| 365 | RSAKey.prototype.verifyHEX = _rsasign_verifyStringHEX; |
| 366 | RSAKey.prototype.verifyHexSignatureForByteArrayMessageHEX = _rsasign_verifyHexSignatureForMessageHEX; |
| 367 | */ |
| 368 | |
| 369 | |
| 370 | /** |
| 371 | * @name RSAKey |
| 372 | * @class |
| 373 | * @description Tom Wu's RSA Key class and extension |
| 374 | */ |