1 /* rsasign-1.3.1.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.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("[^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 "invalid salt length";
152     }
153 
154     if (emLen < (hLen + sLen + 2)) {
155         throw "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     hSig = hSig.replace(_RE_HEXDECONLY, '');
263     hSig = hSig.replace(/[ \n]+/g, "");
264     var biSig = parseBigInt(hSig, 16);
265     if (biSig.bitLength() > this.n.bitLength()) return 0;
266     var biDecryptedSig = this.doPublic(biSig);
267     var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, '');
268     var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo);
269   
270     if (digestInfoAry.length == 0) return false;
271     var algName = digestInfoAry[0];
272     var diHashValue = digestInfoAry[1];
273     return (diHashValue == sHashHex);
274 };
275 
276 /**
277  * verifies a sigature for a message string with RSA public key by PKCS#1 PSS sign.<br/>
278  * @name verifyPSS
279  * @memberOf RSAKey
280  * @function
281  * @param {String} sMsg message string to be verified.
282  * @param {String} hSig hexadecimal string of signature value
283  * @param {String} hashAlg hash algorithm name
284  * @param {Integer} sLen salt byte length from 0 to (keybytelen - hashbytelen - 2).
285  *        There are two special values:
286  *        <ul>
287  *        <li>-1: sets the salt length to the digest length</li>
288  *        <li>-2: sets the salt length to maximum permissible value
289  *           (i.e. keybytelen - hashbytelen - 2)</li>
290  *        </ul>
291  *        DEFAULT is -1. (NOTE: OpenSSL's default is -2.)
292  * @return returns true if valid, otherwise false
293  */
294 RSAKey.prototype.verifyPSS = function(sMsg, hSig, hashAlg, sLen) {
295     var hashFunc = function(sHex) { return KJUR.crypto.Util.hashHex(sHex, hashAlg); };
296     var hHash = hashFunc(rstrtohex(sMsg));
297 
298     if (sLen === undefined) sLen = -1;
299     return this.verifyWithMessageHashPSS(hHash, hSig, hashAlg, sLen);
300 }
301 
302 /**
303  * verifies a sigature for a hash value of message string with RSA public key by PKCS#1 PSS sign.<br/>
304  * @name verifyWithMessageHashPSS
305  * @memberOf RSAKey
306  * @function
307  * @param {String} hHash hexadecimal hash value of message string to be verified.
308  * @param {String} hSig hexadecimal string of signature value
309  * @param {String} hashAlg hash algorithm name
310  * @param {Integer} sLen salt byte length from 0 to (keybytelen - hashbytelen - 2).
311  *        There are two special values:
312  *        <ul>
313  *        <li>-1: sets the salt length to the digest length</li>
314  *        <li>-2: sets the salt length to maximum permissible value
315  *           (i.e. keybytelen - hashbytelen - 2)</li>
316  *        </ul>
317  *        DEFAULT is -1 (NOTE: OpenSSL's default is -2.)
318  * @return returns true if valid, otherwise false
319  * @since rsasign 1.2.6
320  */
321 RSAKey.prototype.verifyWithMessageHashPSS = function(hHash, hSig, hashAlg, sLen) {
322     var biSig = new BigInteger(hSig, 16);
323 
324     if (biSig.bitLength() > this.n.bitLength()) {
325         return false;
326     }
327 
328     var hashFunc = function(sHex) { return KJUR.crypto.Util.hashHex(sHex, hashAlg); };
329     var mHash = hextorstr(hHash);
330     var hLen = mHash.length;
331     var emBits = this.n.bitLength() - 1;
332     var emLen = Math.ceil(emBits / 8);
333     var i;
334 
335     if (sLen === -1 || sLen === undefined) {
336         sLen = hLen; // same as hash length
337     } else if (sLen === -2) {
338         sLen = emLen - hLen - 2; // recover
339     } else if (sLen < -2) {
340         throw "invalid salt length";
341     }
342 
343     if (emLen < (hLen + sLen + 2)) {
344         throw "data too long";
345     }
346 
347     var em = this.doPublic(biSig).toByteArray();
348 
349     for (i = 0; i < em.length; i += 1) {
350         em[i] &= 0xff;
351     }
352 
353     while (em.length < emLen) {
354         em.unshift(0);
355     }
356 
357     if (em[emLen -1] !== 0xbc) {
358         throw "encoded message does not end in 0xbc";
359     }
360 
361     em = String.fromCharCode.apply(String, em);
362 
363     var maskedDB = em.substr(0, emLen - hLen - 1);
364     var H = em.substr(maskedDB.length, hLen);
365 
366     var mask = (0xff00 >> (8 * emLen - emBits)) & 0xff;
367 
368     if ((maskedDB.charCodeAt(0) & mask) !== 0) {
369         throw "bits beyond keysize not zero";
370     }
371 
372     var dbMask = pss_mgf1_str(H, maskedDB.length, hashFunc);
373     var DB = [];
374 
375     for (i = 0; i < maskedDB.length; i += 1) {
376         DB[i] = maskedDB.charCodeAt(i) ^ dbMask.charCodeAt(i);
377     }
378 
379     DB[0] &= ~mask;
380 
381     var checkLen = emLen - hLen - sLen - 2;
382 
383     for (i = 0; i < checkLen; i += 1) {
384         if (DB[i] !== 0x00) {
385             throw "leftmost octets not zero";
386         }
387     }
388 
389     if (DB[checkLen] !== 0x01) {
390         throw "0x01 marker not found";
391     }
392 
393     return H === hextorstr(hashFunc(rstrtohex('\x00\x00\x00\x00\x00\x00\x00\x00' + mHash +
394 				     String.fromCharCode.apply(String, DB.slice(-sLen)))));
395 }
396 
397 RSAKey.SALT_LEN_HLEN = -1;
398 RSAKey.SALT_LEN_MAX = -2;
399 RSAKey.SALT_LEN_RECOVER = -2;
400 
401 /**
402  * @name RSAKey
403  * @class key of RSA public key algorithm
404  * @description Tom Wu's RSA Key class and extension
405  */
406