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