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