1 /* rsasign-1.3.3.js (c) 2010-2020 Kenji Urushima | kjur.github.com/jsrsasign/license
  2  */
  3 /*
  4  * rsa-sign.js - adding signing functions to RSAKey class.
  5  *
  6  * Copyright (c) 2010-2020 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.18 rsasign 1.3.3 (2020-Jun-21)
 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 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 1 if valid, otherwise 0
232  */
233 RSAKey.prototype.verify = function(sMsg, hSig) {
234     hSig = hSig.replace(_RE_HEXDECONLY, '');
235     hSig = hSig.replace(/[ \n]+/g, "");
236     var biSig = parseBigInt(hSig, 16);
237     if (biSig.bitLength() > this.n.bitLength()) return 0;
238     var biDecryptedSig = this.doPublic(biSig);
239     var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, '');
240     var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo);
241   
242     if (digestInfoAry.length == 0) return false;
243     var algName = digestInfoAry[0];
244     var diHashValue = digestInfoAry[1];
245     var ff = function(s) { return KJUR.crypto.Util.hashString(s, algName); };
246     var msgHashValue = ff(sMsg);
247     return (diHashValue == msgHashValue);
248 };
249 
250 /**
251  * verifies a sigature for a message string with RSA public key.<br/>
252  * @name verifyWithMessageHash
253  * @memberOf RSAKey
254  * @function
255  * @param {String} sHashHex hexadecimal hash value of message to be verified.
256  * @param {String} hSig hexadecimal string of siganture.<br/>
257  *                 non-hexadecimal charactors including new lines will be ignored.
258  * @return returns 1 if valid, otherwise 0
259  * @since rsasign 1.2.6
260  */
261 RSAKey.prototype.verifyWithMessageHash = function(sHashHex, hSig) {
262     if (hSig.length != Math.ceil(this.n.bitLength() / 4.0)) {
263 	return false;
264     }
265 
266     var biSig = parseBigInt(hSig, 16);
267 
268     if (biSig.bitLength() > this.n.bitLength()) return 0;
269 
270     var biDecryptedSig = this.doPublic(biSig);
271     var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, '');
272     var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo);
273   
274     if (digestInfoAry.length == 0) return false;
275     var algName = digestInfoAry[0];
276     var diHashValue = digestInfoAry[1];
277     return (diHashValue == sHashHex);
278 };
279 
280 /**
281  * verifies a sigature for a message string with RSA public key by PKCS#1 PSS sign.<br/>
282  * @name verifyPSS
283  * @memberOf RSAKey
284  * @function
285  * @param {String} sMsg message string to be verified.
286  * @param {String} hSig hexadecimal string of signature value
287  * @param {String} hashAlg hash algorithm name
288  * @param {Integer} sLen salt byte length from 0 to (keybytelen - hashbytelen - 2).
289  *        There are two special values:
290  *        <ul>
291  *        <li>-1: sets the salt length to the digest length</li>
292  *        <li>-2: sets the salt length to maximum permissible value
293  *           (i.e. keybytelen - hashbytelen - 2)</li>
294  *        </ul>
295  *        DEFAULT is -1. (NOTE: OpenSSL's default is -2.)
296  * @return returns true if valid, otherwise false
297  */
298 RSAKey.prototype.verifyPSS = function(sMsg, hSig, hashAlg, sLen) {
299     var hashFunc = function(sHex) { return KJUR.crypto.Util.hashHex(sHex, hashAlg); };
300     var hHash = hashFunc(rstrtohex(sMsg));
301 
302     if (sLen === undefined) sLen = -1;
303     return this.verifyWithMessageHashPSS(hHash, hSig, hashAlg, sLen);
304 }
305 
306 /**
307  * verifies a sigature for a hash value of message string with RSA public key by PKCS#1 PSS sign.<br/>
308  * @name verifyWithMessageHashPSS
309  * @memberOf RSAKey
310  * @function
311  * @param {String} hHash hexadecimal hash value of 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  * @since rsasign 1.2.6
324  */
325 RSAKey.prototype.verifyWithMessageHashPSS = function(hHash, hSig, hashAlg, sLen) {
326     if (hSig.length != Math.ceil(this.n.bitLength() / 4.0)) {
327 	return false;
328     }
329 
330     var biSig = new BigInteger(hSig, 16);
331 
332     var hashFunc = function(sHex) { return KJUR.crypto.Util.hashHex(sHex, hashAlg); };
333     var mHash = hextorstr(hHash);
334     var hLen = mHash.length;
335     var emBits = this.n.bitLength() - 1;
336     var emLen = Math.ceil(emBits / 8);
337     var i;
338 
339     if (sLen === -1 || sLen === undefined) {
340         sLen = hLen; // same as hash length
341     } else if (sLen === -2) {
342         sLen = emLen - hLen - 2; // recover
343     } else if (sLen < -2) {
344         throw new Error("invalid salt length");
345     }
346 
347     if (emLen < (hLen + sLen + 2)) {
348         throw new Error("data too long");
349     }
350 
351     var em = this.doPublic(biSig).toByteArray();
352 
353     for (i = 0; i < em.length; i += 1) {
354         em[i] &= 0xff;
355     }
356 
357     while (em.length < emLen) {
358         em.unshift(0);
359     }
360 
361     if (em[emLen -1] !== 0xbc) {
362         throw new Error("encoded message does not end in 0xbc");
363     }
364 
365     em = String.fromCharCode.apply(String, em);
366 
367     var maskedDB = em.substr(0, emLen - hLen - 1);
368     var H = em.substr(maskedDB.length, hLen);
369 
370     var mask = (0xff00 >> (8 * emLen - emBits)) & 0xff;
371 
372     if ((maskedDB.charCodeAt(0) & mask) !== 0) {
373         throw new Error("bits beyond keysize not zero");
374     }
375 
376     var dbMask = pss_mgf1_str(H, maskedDB.length, hashFunc);
377     var DB = [];
378 
379     for (i = 0; i < maskedDB.length; i += 1) {
380         DB[i] = maskedDB.charCodeAt(i) ^ dbMask.charCodeAt(i);
381     }
382 
383     DB[0] &= ~mask;
384 
385     var checkLen = emLen - hLen - sLen - 2;
386 
387     for (i = 0; i < checkLen; i += 1) {
388         if (DB[i] !== 0x00) {
389             throw new Error("leftmost octets not zero");
390         }
391     }
392 
393     if (DB[checkLen] !== 0x01) {
394         throw new Error("0x01 marker not found");
395     }
396 
397     return H === hextorstr(hashFunc(rstrtohex('\x00\x00\x00\x00\x00\x00\x00\x00' + mHash +
398 				     String.fromCharCode.apply(String, DB.slice(-sLen)))));
399 }
400 
401 RSAKey.SALT_LEN_HLEN = -1;
402 RSAKey.SALT_LEN_MAX = -2;
403 RSAKey.SALT_LEN_RECOVER = -2;
404 
405 /**
406  * @name RSAKey
407  * @class key of RSA public key algorithm
408  * @description Tom Wu's RSA Key class and extension
409  */
410