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