Meki Cherkaoui | 88d59cd | 2012-05-14 07:34:58 -0700 | [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 |
|
Axel Colin de Verdiere | 49c08a7 | 2012-06-05 23:04:16 -0700 | [diff] [blame] | 59 | //@author axelcdv
|
| 60 | var _RSASIGN_HASHBYTEFUNC = [];
|
| 61 | _RSASIGN_HASHBYTEFUNC['sha256'] = function(byteArray){return hex_sha256_from_bytes(byteArray);};
|
| 62 |
|
Meki Cherkaoui | 88d59cd | 2012-05-14 07:34:58 -0700 | [diff] [blame] | 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 |
|
Jeff Thompson | 146d7de | 2012-11-17 16:15:28 -0800 | [diff] [blame] | 90 | //@author: Meki Cheraoui
|
Meki Cherkaoui | 88d59cd | 2012-05-14 07:34:58 -0700 | [diff] [blame] | 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 |
|
Axel Colin de Verdiere | 49c08a7 | 2012-06-05 23:04:16 -0700 | [diff] [blame] | 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 |
|
Meki Cherkaoui | 88d59cd | 2012-05-14 07:34:58 -0700 | [diff] [blame] | 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 |
|
Axel Colin de Verdiere | 49c08a7 | 2012-06-05 23:04:16 -0700 | [diff] [blame] | 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 |
|
Meki Cherkaoui | 88d59cd | 2012-05-14 07:34:58 -0700 | [diff] [blame] | 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 |
|
Axel Colin de Verdiere | 49c08a7 | 2012-06-05 23:04:16 -0700 | [diff] [blame] | 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 | */
|
Wentao Shang | 882e34e | 2013-01-05 02:49:51 -0800 | [diff] [blame] | 293 | function _rsasign_verifyByteArray(byteArray, witness, hSig) {
|
Axel Colin de Verdiere | 49c08a7 | 2012-06-05 23:04:16 -0700 | [diff] [blame] | 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];
|
Wentao Shang | 882e34e | 2013-01-05 02:49:51 -0800 | [diff] [blame] | 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 | h = hex_sha256_from_bytes(byteArray);
|
| 317 | index = witness.path.index;
|
| 318 | for (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);
|
Axel Colin de Verdiere | 49c08a7 | 2012-06-05 23:04:16 -0700 | [diff] [blame] | 332 | return (diHashValue == msgHashValue);
|
| 333 | }
|
| 334 |
|
Wentao Shang | 882e34e | 2013-01-05 02:49:51 -0800 | [diff] [blame] | 335 |
|
Meki Cherkaoui | 88d59cd | 2012-05-14 07:34:58 -0700 | [diff] [blame] | 336 | RSAKey.prototype.signString = _rsasign_signString;
|
| 337 |
|
Axel Colin de Verdiere | 49c08a7 | 2012-06-05 23:04:16 -0700 | [diff] [blame] | 338 | RSAKey.prototype.signByteArray = _rsasign_signByteArray; //@author axelcdv
|
| 339 | RSAKey.prototype.signByteArrayWithSHA256 = _rsasign_signByteArrayWithSHA256; //@author axelcdv
|
| 340 |
|
Meki Cherkaoui | 88d59cd | 2012-05-14 07:34:58 -0700 | [diff] [blame] | 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 |
|
Axel Colin de Verdiere | 49c08a7 | 2012-06-05 23:04:16 -0700 | [diff] [blame] | 356 | RSAKey.prototype.verifyByteArray = _rsasign_verifyByteArray;
|
Meki Cherkaoui | 88d59cd | 2012-05-14 07:34:58 -0700 | [diff] [blame] | 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 | */
|