1 /*! rsasign-1.2.7.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license 2 */ 3 /* 4 * rsa-sign.js - adding signing functions to RSAKey class. 5 * 6 * version: 1.2.7 (2013 Aug 25) 7 * 8 * Copyright (c) 2010-2013 Kenji Urushima (kenji.urushima@gmail.com) 9 * 10 * This software is licensed under the terms of the MIT License. 11 * http://kjur.github.com/jsrsasign/license/ 12 * 13 * The above copyright and license notice shall be 14 * included in all copies or substantial portions of the Software. 15 */ 16 17 /** 18 * @fileOverview 19 * @name rsasign-1.2.js 20 * @author Kenji Urushima kenji.urushima@gmail.com 21 * @version rsasign 1.2.7 22 * @license <a href="http://kjur.github.io/jsrsasign/license/">MIT License</a> 23 */ 24 25 var _RE_HEXDECONLY = new RegExp(""); 26 _RE_HEXDECONLY.compile("[^0-9a-f]", "gi"); 27 28 // ======================================================================== 29 // Signature Generation 30 // ======================================================================== 31 32 function _rsasign_getHexPaddedDigestInfoForString(s, keySize, hashAlg) { 33 var hashFunc = function(s) { return KJUR.crypto.Util.hashString(s, hashAlg); }; 34 var sHashHex = hashFunc(s); 35 36 return KJUR.crypto.Util.getPaddedDigestInfoHex(sHashHex, hashAlg, keySize); 37 } 38 39 function _zeroPaddingOfSignature(hex, bitLength) { 40 var s = ""; 41 var nZero = bitLength / 4 - hex.length; 42 for (var i = 0; i < nZero; i++) { 43 s = s + "0"; 44 } 45 return s + hex; 46 } 47 48 /** 49 * sign for a message string with RSA private key.<br/> 50 * @name signString 51 * @memberOf RSAKey 52 * @function 53 * @param {String} s message string to be signed. 54 * @param {String} hashAlg hash algorithm name for signing.<br/> 55 * @return returns hexadecimal string of signature value. 56 */ 57 function _rsasign_signString(s, hashAlg) { 58 var hashFunc = function(s) { return KJUR.crypto.Util.hashString(s, hashAlg); }; 59 var sHashHex = hashFunc(s); 60 61 return this.signWithMessageHash(sHashHex, hashAlg); 62 } 63 64 /** 65 * sign hash value of message to be signed with RSA private key.<br/> 66 * @name signWithMessageHash 67 * @memberOf RSAKey 68 * @function 69 * @param {String} sHashHex hexadecimal string of hash value of message to be signed. 70 * @param {String} hashAlg hash algorithm name for signing.<br/> 71 * @return returns hexadecimal string of signature value. 72 * @since rsasign 1.2.6 73 */ 74 function _rsasign_signWithMessageHash(sHashHex, hashAlg) { 75 var hPM = KJUR.crypto.Util.getPaddedDigestInfoHex(sHashHex, hashAlg, this.n.bitLength()); 76 var biPaddedMessage = parseBigInt(hPM, 16); 77 var biSign = this.doPrivate(biPaddedMessage); 78 var hexSign = biSign.toString(16); 79 return _zeroPaddingOfSignature(hexSign, this.n.bitLength()); 80 } 81 82 function _rsasign_signStringWithSHA1(s) { 83 return _rsasign_signString.call(this, s, 'sha1'); 84 } 85 86 function _rsasign_signStringWithSHA256(s) { 87 return _rsasign_signString.call(this, s, 'sha256'); 88 } 89 90 // PKCS#1 (PSS) mask generation function 91 function pss_mgf1_str(seed, len, hash) { 92 var mask = '', i = 0; 93 94 while (mask.length < len) { 95 mask += hextorstr(hash(rstrtohex(seed + String.fromCharCode.apply(String, [ 96 (i & 0xff000000) >> 24, 97 (i & 0x00ff0000) >> 16, 98 (i & 0x0000ff00) >> 8, 99 i & 0x000000ff])))); 100 i += 1; 101 } 102 103 return mask; 104 } 105 106 /** 107 * sign for a message string with RSA private key by PKCS#1 PSS signing.<br/> 108 * @name signStringPSS 109 * @memberOf RSAKey 110 * @function 111 * @param {String} s message string to be signed. 112 * @param {String} hashAlg hash algorithm name for signing. 113 * @param {Integer} sLen salt byte length from 0 to (keybytelen - hashbytelen - 2). 114 * There are two special values: 115 * <ul> 116 * <li>-1: sets the salt length to the digest length</li> 117 * <li>-2: sets the salt length to maximum permissible value 118 * (i.e. keybytelen - hashbytelen - 2)</li> 119 * </ul> 120 * DEFAULT is -1. (NOTE: OpenSSL's default is -2.) 121 * @return returns hexadecimal string of signature value. 122 */ 123 function _rsasign_signStringPSS(s, hashAlg, sLen) { 124 var hashFunc = function(sHex) { return KJUR.crypto.Util.hashHex(sHex, hashAlg); } 125 var hHash = hashFunc(rstrtohex(s)); 126 127 if (sLen === undefined) sLen = -1; 128 return this.signWithMessageHashPSS(hHash, hashAlg, sLen); 129 } 130 131 /** 132 * sign hash value of message with RSA private key by PKCS#1 PSS signing.<br/> 133 * @name signWithMessageHashPSS 134 * @memberOf RSAKey 135 * @function 136 * @param {String} hHash hexadecimal hash value of message to be signed. 137 * @param {String} hashAlg hash algorithm name for signing. 138 * @param {Integer} sLen salt byte length from 0 to (keybytelen - hashbytelen - 2). 139 * There are two special values: 140 * <ul> 141 * <li>-1: sets the salt length to the digest length</li> 142 * <li>-2: sets the salt length to maximum permissible value 143 * (i.e. keybytelen - hashbytelen - 2)</li> 144 * </ul> 145 * DEFAULT is -1. (NOTE: OpenSSL's default is -2.) 146 * @return returns hexadecimal string of signature value. 147 * @since rsasign 1.2.6 148 */ 149 function _rsasign_signWithMessageHashPSS(hHash, hashAlg, sLen) { 150 var mHash = hextorstr(hHash); 151 var hLen = mHash.length; 152 var emBits = this.n.bitLength() - 1; 153 var emLen = Math.ceil(emBits / 8); 154 var i; 155 var hashFunc = function(sHex) { return KJUR.crypto.Util.hashHex(sHex, hashAlg); } 156 157 if (sLen === -1 || sLen === undefined) { 158 sLen = hLen; // same as hash length 159 } else if (sLen === -2) { 160 sLen = emLen - hLen - 2; // maximum 161 } else if (sLen < -2) { 162 throw "invalid salt length"; 163 } 164 165 if (emLen < (hLen + sLen + 2)) { 166 throw "data too long"; 167 } 168 169 var salt = ''; 170 171 if (sLen > 0) { 172 salt = new Array(sLen); 173 new SecureRandom().nextBytes(salt); 174 salt = String.fromCharCode.apply(String, salt); 175 } 176 177 var H = hextorstr(hashFunc(rstrtohex('\x00\x00\x00\x00\x00\x00\x00\x00' + mHash + salt))); 178 var PS = []; 179 180 for (i = 0; i < emLen - sLen - hLen - 2; i += 1) { 181 PS[i] = 0x00; 182 } 183 184 var DB = String.fromCharCode.apply(String, PS) + '\x01' + salt; 185 var dbMask = pss_mgf1_str(H, DB.length, hashFunc); 186 var maskedDB = []; 187 188 for (i = 0; i < DB.length; i += 1) { 189 maskedDB[i] = DB.charCodeAt(i) ^ dbMask.charCodeAt(i); 190 } 191 192 var mask = (0xff00 >> (8 * emLen - emBits)) & 0xff; 193 maskedDB[0] &= ~mask; 194 195 for (i = 0; i < hLen; i++) { 196 maskedDB.push(H.charCodeAt(i)); 197 } 198 199 maskedDB.push(0xbc); 200 201 return _zeroPaddingOfSignature(this.doPrivate(new BigInteger(maskedDB)).toString(16), 202 this.n.bitLength()); 203 } 204 205 // ======================================================================== 206 // Signature Verification 207 // ======================================================================== 208 209 function _rsasign_getDecryptSignatureBI(biSig, hN, hE) { 210 var rsa = new RSAKey(); 211 rsa.setPublic(hN, hE); 212 var biDecryptedSig = rsa.doPublic(biSig); 213 return biDecryptedSig; 214 } 215 216 function _rsasign_getHexDigestInfoFromSig(biSig, hN, hE) { 217 var biDecryptedSig = _rsasign_getDecryptSignatureBI(biSig, hN, hE); 218 var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, ''); 219 return hDigestInfo; 220 } 221 222 function _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo) { 223 for (var algName in KJUR.crypto.Util.DIGESTINFOHEAD) { 224 var head = KJUR.crypto.Util.DIGESTINFOHEAD[algName]; 225 var len = head.length; 226 if (hDigestInfo.substring(0, len) == head) { 227 var a = [algName, hDigestInfo.substring(len)]; 228 return a; 229 } 230 } 231 return []; 232 } 233 234 function _rsasign_verifySignatureWithArgs(sMsg, biSig, hN, hE) { 235 var hDigestInfo = _rsasign_getHexDigestInfoFromSig(biSig, hN, hE); 236 var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo); 237 if (digestInfoAry.length == 0) return false; 238 var algName = digestInfoAry[0]; 239 var diHashValue = digestInfoAry[1]; 240 var ff = function(s) { return KJUR.crypto.Util.hashString(s, algName); }; 241 var msgHashValue = ff(sMsg); 242 return (diHashValue == msgHashValue); 243 } 244 245 function _rsasign_verifyHexSignatureForMessage(hSig, sMsg) { 246 var biSig = parseBigInt(hSig, 16); 247 var result = _rsasign_verifySignatureWithArgs(sMsg, biSig, 248 this.n.toString(16), 249 this.e.toString(16)); 250 return result; 251 } 252 253 /** 254 * verifies a sigature for a message string with RSA public key.<br/> 255 * @name verifyString 256 * @memberOf RSAKey# 257 * @function 258 * @param {String} sMsg message string to be verified. 259 * @param {String} hSig hexadecimal string of siganture.<br/> 260 * non-hexadecimal charactors including new lines will be ignored. 261 * @return returns 1 if valid, otherwise 0 262 */ 263 function _rsasign_verifyString(sMsg, hSig) { 264 hSig = hSig.replace(_RE_HEXDECONLY, ''); 265 hSig = hSig.replace(/[ \n]+/g, ""); 266 var biSig = parseBigInt(hSig, 16); 267 if (biSig.bitLength() > this.n.bitLength()) return 0; 268 var biDecryptedSig = this.doPublic(biSig); 269 var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, ''); 270 var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo); 271 272 if (digestInfoAry.length == 0) return false; 273 var algName = digestInfoAry[0]; 274 var diHashValue = digestInfoAry[1]; 275 var ff = function(s) { return KJUR.crypto.Util.hashString(s, algName); }; 276 var msgHashValue = ff(sMsg); 277 return (diHashValue == msgHashValue); 278 } 279 280 /** 281 * verifies a sigature for a message string with RSA public key.<br/> 282 * @name verifyWithMessageHash 283 * @memberOf RSAKey 284 * @function 285 * @param {String} sHashHex hexadecimal hash value of message to be verified. 286 * @param {String} hSig hexadecimal string of siganture.<br/> 287 * non-hexadecimal charactors including new lines will be ignored. 288 * @return returns 1 if valid, otherwise 0 289 * @since rsasign 1.2.6 290 */ 291 function _rsasign_verifyWithMessageHash(sHashHex, hSig) { 292 hSig = hSig.replace(_RE_HEXDECONLY, ''); 293 hSig = hSig.replace(/[ \n]+/g, ""); 294 var biSig = parseBigInt(hSig, 16); 295 if (biSig.bitLength() > this.n.bitLength()) return 0; 296 var biDecryptedSig = this.doPublic(biSig); 297 var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, ''); 298 var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo); 299 300 if (digestInfoAry.length == 0) return false; 301 var algName = digestInfoAry[0]; 302 var diHashValue = digestInfoAry[1]; 303 return (diHashValue == sHashHex); 304 } 305 306 /** 307 * verifies a sigature for a message string with RSA public key by PKCS#1 PSS sign.<br/> 308 * @name verifyStringPSS 309 * @memberOf RSAKey 310 * @function 311 * @param {String} sMsg message string to be verified. 312 * @param {String} hSig hexadecimal string of signature value 313 * @param {String} hashAlg hash algorithm name 314 * @param {Integer} sLen salt byte length from 0 to (keybytelen - hashbytelen - 2). 315 * There are two special values: 316 * <ul> 317 * <li>-1: sets the salt length to the digest length</li> 318 * <li>-2: sets the salt length to maximum permissible value 319 * (i.e. keybytelen - hashbytelen - 2)</li> 320 * </ul> 321 * DEFAULT is -1. (NOTE: OpenSSL's default is -2.) 322 * @return returns true if valid, otherwise false 323 */ 324 function _rsasign_verifyStringPSS(sMsg, hSig, hashAlg, sLen) { 325 var hashFunc = function(sHex) { return KJUR.crypto.Util.hashHex(sHex, hashAlg); }; 326 var hHash = hashFunc(rstrtohex(sMsg)); 327 328 if (sLen === undefined) sLen = -1; 329 return this.verifyWithMessageHashPSS(hHash, hSig, hashAlg, sLen); 330 } 331 332 /** 333 * verifies a sigature for a hash value of message string with RSA public key by PKCS#1 PSS sign.<br/> 334 * @name verifyWithMessageHashPSS 335 * @memberOf RSAKey 336 * @function 337 * @param {String} hHash hexadecimal hash value of message string to be verified. 338 * @param {String} hSig hexadecimal string of signature value 339 * @param {String} hashAlg hash algorithm name 340 * @param {Integer} sLen salt byte length from 0 to (keybytelen - hashbytelen - 2). 341 * There are two special values: 342 * <ul> 343 * <li>-1: sets the salt length to the digest length</li> 344 * <li>-2: sets the salt length to maximum permissible value 345 * (i.e. keybytelen - hashbytelen - 2)</li> 346 * </ul> 347 * DEFAULT is -1 (NOTE: OpenSSL's default is -2.) 348 * @return returns true if valid, otherwise false 349 * @since rsasign 1.2.6 350 */ 351 function _rsasign_verifyWithMessageHashPSS(hHash, hSig, hashAlg, sLen) { 352 var biSig = new BigInteger(hSig, 16); 353 354 if (biSig.bitLength() > this.n.bitLength()) { 355 return false; 356 } 357 358 var hashFunc = function(sHex) { return KJUR.crypto.Util.hashHex(sHex, hashAlg); }; 359 var mHash = hextorstr(hHash); 360 var hLen = mHash.length; 361 var emBits = this.n.bitLength() - 1; 362 var emLen = Math.ceil(emBits / 8); 363 var i; 364 365 if (sLen === -1 || sLen === undefined) { 366 sLen = hLen; // same as hash length 367 } else if (sLen === -2) { 368 sLen = emLen - hLen - 2; // recover 369 } else if (sLen < -2) { 370 throw "invalid salt length"; 371 } 372 373 if (emLen < (hLen + sLen + 2)) { 374 throw "data too long"; 375 } 376 377 var em = this.doPublic(biSig).toByteArray(); 378 379 for (i = 0; i < em.length; i += 1) { 380 em[i] &= 0xff; 381 } 382 383 while (em.length < emLen) { 384 em.unshift(0); 385 } 386 387 if (em[emLen -1] !== 0xbc) { 388 throw "encoded message does not end in 0xbc"; 389 } 390 391 em = String.fromCharCode.apply(String, em); 392 393 var maskedDB = em.substr(0, emLen - hLen - 1); 394 var H = em.substr(maskedDB.length, hLen); 395 396 var mask = (0xff00 >> (8 * emLen - emBits)) & 0xff; 397 398 if ((maskedDB.charCodeAt(0) & mask) !== 0) { 399 throw "bits beyond keysize not zero"; 400 } 401 402 var dbMask = pss_mgf1_str(H, maskedDB.length, hashFunc); 403 var DB = []; 404 405 for (i = 0; i < maskedDB.length; i += 1) { 406 DB[i] = maskedDB.charCodeAt(i) ^ dbMask.charCodeAt(i); 407 } 408 409 DB[0] &= ~mask; 410 411 var checkLen = emLen - hLen - sLen - 2; 412 413 for (i = 0; i < checkLen; i += 1) { 414 if (DB[i] !== 0x00) { 415 throw "leftmost octets not zero"; 416 } 417 } 418 419 if (DB[checkLen] !== 0x01) { 420 throw "0x01 marker not found"; 421 } 422 423 return H === hextorstr(hashFunc(rstrtohex('\x00\x00\x00\x00\x00\x00\x00\x00' + mHash + 424 String.fromCharCode.apply(String, DB.slice(-sLen))))); 425 } 426 427 RSAKey.prototype.signWithMessageHash = _rsasign_signWithMessageHash; 428 RSAKey.prototype.signString = _rsasign_signString; 429 RSAKey.prototype.signStringWithSHA1 = _rsasign_signStringWithSHA1; 430 RSAKey.prototype.signStringWithSHA256 = _rsasign_signStringWithSHA256; 431 RSAKey.prototype.sign = _rsasign_signString; 432 RSAKey.prototype.signWithSHA1 = _rsasign_signStringWithSHA1; 433 RSAKey.prototype.signWithSHA256 = _rsasign_signStringWithSHA256; 434 435 RSAKey.prototype.signWithMessageHashPSS = _rsasign_signWithMessageHashPSS; 436 RSAKey.prototype.signStringPSS = _rsasign_signStringPSS; 437 RSAKey.prototype.signPSS = _rsasign_signStringPSS; 438 RSAKey.SALT_LEN_HLEN = -1; 439 RSAKey.SALT_LEN_MAX = -2; 440 441 RSAKey.prototype.verifyWithMessageHash = _rsasign_verifyWithMessageHash; 442 RSAKey.prototype.verifyString = _rsasign_verifyString; 443 RSAKey.prototype.verifyHexSignatureForMessage = _rsasign_verifyHexSignatureForMessage; 444 RSAKey.prototype.verify = _rsasign_verifyString; 445 RSAKey.prototype.verifyHexSignatureForByteArrayMessage = _rsasign_verifyHexSignatureForMessage; 446 447 RSAKey.prototype.verifyWithMessageHashPSS = _rsasign_verifyWithMessageHashPSS; 448 RSAKey.prototype.verifyStringPSS = _rsasign_verifyStringPSS; 449 RSAKey.prototype.verifyPSS = _rsasign_verifyStringPSS; 450 RSAKey.SALT_LEN_RECOVER = -2; 451 452 /** 453 * @name RSAKey 454 * @class key of RSA public key algorithm 455 * @description Tom Wu's RSA Key class and extension 456 */ 457