1 /*! crypto-1.1.5.js (c) 2013 Kenji Urushima | kjur.github.com/jsrsasign/license
  2  */
  3 /*
  4  * crypto.js - Cryptographic Algorithm Provider class
  5  *
  6  * Copyright (c) 2013 Kenji Urushima (kenji.urushima@gmail.com)
  7  *
  8  * This software is licensed under the terms of the MIT License.
  9  * http://kjur.github.com/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 crypto-1.1.js
 18  * @author Kenji Urushima kenji.urushima@gmail.com
 19  * @version 1.1.5 (2013-Oct-06)
 20  * @since jsrsasign 2.2
 21  * @license <a href="http://kjur.github.io/jsrsasign/license/">MIT License</a>
 22  */
 23 
 24 /** 
 25  * kjur's class library name space
 26  * @name KJUR
 27  * @namespace kjur's class library name space
 28  */
 29 if (typeof KJUR == "undefined" || !KJUR) KJUR = {};
 30 /**
 31  * kjur's cryptographic algorithm provider library name space
 32  * <p>
 33  * This namespace privides following crytpgrahic classes.
 34  * <ul>
 35  * <li>{@link KJUR.crypto.MessageDigest} - Java JCE(cryptograhic extension) style MessageDigest class</li>
 36  * <li>{@link KJUR.crypto.Signature} - Java JCE(cryptograhic extension) style Signature class</li>
 37  * <li>{@link KJUR.crypto.Util} - cryptographic utility functions and properties</li>
 38  * </ul>
 39  * NOTE: Please ignore method summary and document of this namespace. This caused by a bug of jsdoc2.
 40  * </p>
 41  * @name KJUR.crypto
 42  * @namespace
 43  */
 44 if (typeof KJUR.crypto == "undefined" || !KJUR.crypto) KJUR.crypto = {};
 45 
 46 /**
 47  * static object for cryptographic function utilities
 48  * @name KJUR.crypto.Util
 49  * @class static object for cryptographic function utilities
 50  * @property {Array} DIGESTINFOHEAD PKCS#1 DigestInfo heading hexadecimal bytes for each hash algorithms
 51  * @property {Array} DEFAULTPROVIDER associative array of default provider name for each hash and signature algorithms
 52  * @description
 53  */
 54 KJUR.crypto.Util = new function() {
 55     this.DIGESTINFOHEAD = {
 56 	'sha1':      "3021300906052b0e03021a05000414",
 57         'sha224':    "302d300d06096086480165030402040500041c",
 58 	'sha256':    "3031300d060960864801650304020105000420",
 59 	'sha384':    "3041300d060960864801650304020205000430",
 60 	'sha512':    "3051300d060960864801650304020305000440",
 61 	'md2':       "3020300c06082a864886f70d020205000410",
 62 	'md5':       "3020300c06082a864886f70d020505000410",
 63 	'ripemd160': "3021300906052b2403020105000414",
 64     };
 65 
 66     /*
 67      * @since crypto 1.1.1
 68      */
 69     this.DEFAULTPROVIDER = {
 70 	'md5':			'cryptojs',
 71 	'sha1':			'cryptojs',
 72 	'sha224':		'cryptojs',
 73 	'sha256':		'cryptojs',
 74 	'sha384':		'cryptojs',
 75 	'sha512':		'cryptojs',
 76 	'ripemd160':		'cryptojs',
 77 	'hmacmd5':		'cryptojs',
 78 	'hmacsha1':		'cryptojs',
 79 	'hmacsha224':		'cryptojs',
 80 	'hmacsha256':		'cryptojs',
 81 	'hmacsha384':		'cryptojs',
 82 	'hmacsha512':		'cryptojs',
 83 	'hmacripemd160':	'cryptojs',
 84 
 85 	'MD5withRSA':		'cryptojs/jsrsa',
 86 	'SHA1withRSA':		'cryptojs/jsrsa',
 87 	'SHA224withRSA':	'cryptojs/jsrsa',
 88 	'SHA256withRSA':	'cryptojs/jsrsa',
 89 	'SHA384withRSA':	'cryptojs/jsrsa',
 90 	'SHA512withRSA':	'cryptojs/jsrsa',
 91 	'RIPEMD160withRSA':	'cryptojs/jsrsa',
 92 
 93 	'MD5withECDSA':		'cryptojs/jsrsa',
 94 	'SHA1withECDSA':	'cryptojs/jsrsa',
 95 	'SHA224withECDSA':	'cryptojs/jsrsa',
 96 	'SHA256withECDSA':	'cryptojs/jsrsa',
 97 	'SHA384withECDSA':	'cryptojs/jsrsa',
 98 	'SHA512withECDSA':	'cryptojs/jsrsa',
 99 	'RIPEMD160withECDSA':	'cryptojs/jsrsa',
100 
101 	'SHA1withDSA':		'cryptojs/jsrsa',
102 	'SHA224withDSA':	'cryptojs/jsrsa',
103 	'SHA256withDSA':	'cryptojs/jsrsa',
104 
105 	'MD5withRSAandMGF1':		'cryptojs/jsrsa',
106 	'SHA1withRSAandMGF1':		'cryptojs/jsrsa',
107 	'SHA224withRSAandMGF1':		'cryptojs/jsrsa',
108 	'SHA256withRSAandMGF1':		'cryptojs/jsrsa',
109 	'SHA384withRSAandMGF1':		'cryptojs/jsrsa',
110 	'SHA512withRSAandMGF1':		'cryptojs/jsrsa',
111 	'RIPEMD160withRSAandMGF1':	'cryptojs/jsrsa',
112     };
113 
114     /*
115      * @since crypto 1.1.2
116      */
117     this.CRYPTOJSMESSAGEDIGESTNAME = {
118 	'md5':		'CryptoJS.algo.MD5',
119 	'sha1':		'CryptoJS.algo.SHA1',
120 	'sha224':	'CryptoJS.algo.SHA224',
121 	'sha256':	'CryptoJS.algo.SHA256',
122 	'sha384':	'CryptoJS.algo.SHA384',
123 	'sha512':	'CryptoJS.algo.SHA512',
124 	'ripemd160':	'CryptoJS.algo.RIPEMD160'
125     };
126 
127     /**
128      * get hexadecimal DigestInfo
129      * @name getDigestInfoHex
130      * @memberOf KJUR.crypto.Util
131      * @function
132      * @param {String} hHash hexadecimal hash value
133      * @param {String} alg hash algorithm name (ex. 'sha1')
134      * @return {String} hexadecimal string DigestInfo ASN.1 structure
135      */
136     this.getDigestInfoHex = function(hHash, alg) {
137 	if (typeof this.DIGESTINFOHEAD[alg] == "undefined")
138 	    throw "alg not supported in Util.DIGESTINFOHEAD: " + alg;
139 	return this.DIGESTINFOHEAD[alg] + hHash;
140     };
141 
142     /**
143      * get PKCS#1 padded hexadecimal DigestInfo
144      * @name getPaddedDigestInfoHex
145      * @memberOf KJUR.crypto.Util
146      * @function
147      * @param {String} hHash hexadecimal hash value of message to be signed
148      * @param {String} alg hash algorithm name (ex. 'sha1')
149      * @param {Integer} keySize key bit length (ex. 1024)
150      * @return {String} hexadecimal string of PKCS#1 padded DigestInfo
151      */
152     this.getPaddedDigestInfoHex = function(hHash, alg, keySize) {
153 	var hDigestInfo = this.getDigestInfoHex(hHash, alg);
154 	var pmStrLen = keySize / 4; // minimum PM length
155 
156 	if (hDigestInfo.length + 22 > pmStrLen) // len(0001+ff(*8)+00+hDigestInfo)=22
157 	    throw "key is too short for SigAlg: keylen=" + keySize + "," + alg;
158 
159 	var hHead = "0001";
160 	var hTail = "00" + hDigestInfo;
161 	var hMid = "";
162 	var fLen = pmStrLen - hHead.length - hTail.length;
163 	for (var i = 0; i < fLen; i += 2) {
164 	    hMid += "ff";
165 	}
166 	var hPaddedMessage = hHead + hMid + hTail;
167 	return hPaddedMessage;
168     };
169 
170     /**
171      * get hexadecimal hash of string with specified algorithm
172      * @name hashString
173      * @memberOf KJUR.crypto.Util
174      * @function
175      * @param {String} s input string to be hashed
176      * @param {String} alg hash algorithm name
177      * @return {String} hexadecimal string of hash value
178      * @since 1.1.1
179      */
180     this.hashString = function(s, alg) {
181         var md = new KJUR.crypto.MessageDigest({'alg': alg});
182         return md.digestString(s);
183     };
184 
185     /**
186      * get hexadecimal hash of hexadecimal string with specified algorithm
187      * @name hashHex
188      * @memberOf KJUR.crypto.Util
189      * @function
190      * @param {String} sHex input hexadecimal string to be hashed
191      * @param {String} alg hash algorithm name
192      * @return {String} hexadecimal string of hash value
193      * @since 1.1.1
194      */
195     this.hashHex = function(sHex, alg) {
196         var md = new KJUR.crypto.MessageDigest({'alg': alg});
197         return md.digestHex(sHex);
198     };
199 
200     /**
201      * get hexadecimal SHA1 hash of string
202      * @name sha1
203      * @memberOf KJUR.crypto.Util
204      * @function
205      * @param {String} s input string to be hashed
206      * @return {String} hexadecimal string of hash value
207      * @since 1.0.3
208      */
209     this.sha1 = function(s) {
210         var md = new KJUR.crypto.MessageDigest({'alg':'sha1', 'prov':'cryptojs'});
211         return md.digestString(s);
212     };
213 
214     /**
215      * get hexadecimal SHA256 hash of string
216      * @name sha256
217      * @memberOf KJUR.crypto.Util
218      * @function
219      * @param {String} s input string to be hashed
220      * @return {String} hexadecimal string of hash value
221      * @since 1.0.3
222      */
223     this.sha256 = function(s) {
224         var md = new KJUR.crypto.MessageDigest({'alg':'sha256', 'prov':'cryptojs'});
225         return md.digestString(s);
226     };
227 
228     this.sha256Hex = function(s) {
229         var md = new KJUR.crypto.MessageDigest({'alg':'sha256', 'prov':'cryptojs'});
230         return md.digestHex(s);
231     };
232 
233     /**
234      * get hexadecimal SHA512 hash of string
235      * @name sha512
236      * @memberOf KJUR.crypto.Util
237      * @function
238      * @param {String} s input string to be hashed
239      * @return {String} hexadecimal string of hash value
240      * @since 1.0.3
241      */
242     this.sha512 = function(s) {
243         var md = new KJUR.crypto.MessageDigest({'alg':'sha512', 'prov':'cryptojs'});
244         return md.digestString(s);
245     };
246 
247     this.sha512Hex = function(s) {
248         var md = new KJUR.crypto.MessageDigest({'alg':'sha512', 'prov':'cryptojs'});
249         return md.digestHex(s);
250     };
251 
252     /**
253      * get hexadecimal MD5 hash of string
254      * @name md5
255      * @memberOf KJUR.crypto.Util
256      * @function
257      * @param {String} s input string to be hashed
258      * @return {String} hexadecimal string of hash value
259      * @since 1.0.3
260      */
261     this.md5 = function(s) {
262         var md = new KJUR.crypto.MessageDigest({'alg':'md5', 'prov':'cryptojs'});
263         return md.digestString(s);
264     };
265 
266     /**
267      * get hexadecimal RIPEMD160 hash of string
268      * @name ripemd160
269      * @memberOf KJUR.crypto.Util
270      * @function
271      * @param {String} s input string to be hashed
272      * @return {String} hexadecimal string of hash value
273      * @since 1.0.3
274      */
275     this.ripemd160 = function(s) {
276         var md = new KJUR.crypto.MessageDigest({'alg':'ripemd160', 'prov':'cryptojs'});
277         return md.digestString(s);
278     };
279 
280     /*
281      * @since 1.1.2
282      */
283     this.getCryptoJSMDByName = function(s) {
284 	
285     };
286 };
287 
288 /**
289  * MessageDigest class which is very similar to java.security.MessageDigest class
290  * @name KJUR.crypto.MessageDigest
291  * @class MessageDigest class which is very similar to java.security.MessageDigest class
292  * @param {Array} params parameters for constructor
293  * @description
294  * <br/>
295  * Currently this supports following algorithm and providers combination:
296  * <ul>
297  * <li>md5 - cryptojs</li>
298  * <li>sha1 - cryptojs</li>
299  * <li>sha224 - cryptojs</li>
300  * <li>sha256 - cryptojs</li>
301  * <li>sha384 - cryptojs</li>
302  * <li>sha512 - cryptojs</li>
303  * <li>ripemd160 - cryptojs</li>
304  * <li>sha256 - sjcl (NEW from crypto.js 1.0.4)</li>
305  * </ul>
306  * @example
307  * // CryptoJS provider sample
308  * <script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/components/core.js"></script>
309  * <script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/components/sha1.js"></script>
310  * <script src="crypto-1.0.js"></script>
311  * var md = new KJUR.crypto.MessageDigest({alg: "sha1", prov: "cryptojs"});
312  * md.updateString('aaa')
313  * var mdHex = md.digest()
314  *
315  * // SJCL(Stanford JavaScript Crypto Library) provider sample
316  * <script src="http://bitwiseshiftleft.github.io/sjcl/sjcl.js"></script>
317  * <script src="crypto-1.0.js"></script>
318  * var md = new KJUR.crypto.MessageDigest({alg: "sha256", prov: "sjcl"}); // sjcl supports sha256 only
319  * md.updateString('aaa')
320  * var mdHex = md.digest()
321  */
322 KJUR.crypto.MessageDigest = function(params) {
323     var md = null;
324     var algName = null;
325     var provName = null;
326 
327     /**
328      * set hash algorithm and provider
329      * @name setAlgAndProvider
330      * @memberOf KJUR.crypto.MessageDigest
331      * @function
332      * @param {String} alg hash algorithm name
333      * @param {String} prov provider name
334      * @description
335      * @example
336      * // for SHA1
337      * md.setAlgAndProvider('sha1', 'cryptojs');
338      * // for RIPEMD160
339      * md.setAlgAndProvider('ripemd160', 'cryptojs');
340      */
341     this.setAlgAndProvider = function(alg, prov) {
342 	if (alg != null && prov === undefined) prov = KJUR.crypto.Util.DEFAULTPROVIDER[alg];
343 
344 	// for cryptojs
345 	if (':md5:sha1:sha224:sha256:sha384:sha512:ripemd160:'.indexOf(alg) != -1 &&
346 	    prov == 'cryptojs') {
347 	    try {
348 		this.md = eval(KJUR.crypto.Util.CRYPTOJSMESSAGEDIGESTNAME[alg]).create();
349 	    } catch (ex) {
350 		throw "setAlgAndProvider hash alg set fail alg=" + alg + "/" + ex;
351 	    }
352 	    this.updateString = function(str) {
353 		this.md.update(str);
354 	    };
355 	    this.updateHex = function(hex) {
356 		var wHex = CryptoJS.enc.Hex.parse(hex);
357 		this.md.update(wHex);
358 	    };
359 	    this.digest = function() {
360 		var hash = this.md.finalize();
361 		return hash.toString(CryptoJS.enc.Hex);
362 	    };
363 	    this.digestString = function(str) {
364 		this.updateString(str);
365 		return this.digest();
366 	    };
367 	    this.digestHex = function(hex) {
368 		this.updateHex(hex);
369 		return this.digest();
370 	    };
371 	}
372 	if (':sha256:'.indexOf(alg) != -1 &&
373 	    prov == 'sjcl') {
374 	    try {
375 		this.md = new sjcl.hash.sha256();
376 	    } catch (ex) {
377 		throw "setAlgAndProvider hash alg set fail alg=" + alg + "/" + ex;
378 	    }
379 	    this.updateString = function(str) {
380 		this.md.update(str);
381 	    };
382 	    this.updateHex = function(hex) {
383 		var baHex = sjcl.codec.hex.toBits(hex);
384 		this.md.update(baHex);
385 	    };
386 	    this.digest = function() {
387 		var hash = this.md.finalize();
388 		return sjcl.codec.hex.fromBits(hash);
389 	    };
390 	    this.digestString = function(str) {
391 		this.updateString(str);
392 		return this.digest();
393 	    };
394 	    this.digestHex = function(hex) {
395 		this.updateHex(hex);
396 		return this.digest();
397 	    };
398 	}
399     };
400 
401     /**
402      * update digest by specified string
403      * @name updateString
404      * @memberOf KJUR.crypto.MessageDigest
405      * @function
406      * @param {String} str string to update
407      * @description
408      * @example
409      * md.updateString('New York');
410      */
411     this.updateString = function(str) {
412 	throw "updateString(str) not supported for this alg/prov: " + this.algName + "/" + this.provName;
413     };
414 
415     /**
416      * update digest by specified hexadecimal string
417      * @name updateHex
418      * @memberOf KJUR.crypto.MessageDigest
419      * @function
420      * @param {String} hex hexadecimal string to update
421      * @description
422      * @example
423      * md.updateHex('0afe36');
424      */
425     this.updateHex = function(hex) {
426 	throw "updateHex(hex) not supported for this alg/prov: " + this.algName + "/" + this.provName;
427     };
428 
429     /**
430      * completes hash calculation and returns hash result
431      * @name digest
432      * @memberOf KJUR.crypto.MessageDigest
433      * @function
434      * @description
435      * @example
436      * md.digest()
437      */
438     this.digest = function() {
439 	throw "digest() not supported for this alg/prov: " + this.algName + "/" + this.provName;
440     };
441 
442     /**
443      * performs final update on the digest using string, then completes the digest computation
444      * @name digestString
445      * @memberOf KJUR.crypto.MessageDigest
446      * @function
447      * @param {String} str string to final update
448      * @description
449      * @example
450      * md.digestString('aaa')
451      */
452     this.digestString = function(str) {
453 	throw "digestString(str) not supported for this alg/prov: " + this.algName + "/" + this.provName;
454     };
455 
456     /**
457      * performs final update on the digest using hexadecimal string, then completes the digest computation
458      * @name digestHex
459      * @memberOf KJUR.crypto.MessageDigest
460      * @function
461      * @param {String} hex hexadecimal string to final update
462      * @description
463      * @example
464      * md.digestHex('0f2abd')
465      */
466     this.digestHex = function(hex) {
467 	throw "digestHex(hex) not supported for this alg/prov: " + this.algName + "/" + this.provName;
468     };
469 
470     if (params !== undefined) {
471 	if (params['alg'] !== undefined) {
472 	    this.algName = params['alg'];
473 	    if (params['prov'] === undefined)
474 		this.provName = KJUR.crypto.Util.DEFAULTPROVIDER[this.algName];
475 	    this.setAlgAndProvider(this.algName, this.provName);
476 	}
477     }
478 };
479 
480 /**
481  * Mac(Message Authentication Code) class which is very similar to java.security.Mac class 
482  * @name KJUR.crypto.Mac
483  * @class Mac class which is very similar to java.security.Mac class
484  * @param {Array} params parameters for constructor
485  * @description
486  * <br/>
487  * Currently this supports following algorithm and providers combination:
488  * <ul>
489  * <li>hmacmd5 - cryptojs</li>
490  * <li>hmacsha1 - cryptojs</li>
491  * <li>hmacsha224 - cryptojs</li>
492  * <li>hmacsha256 - cryptojs</li>
493  * <li>hmacsha384 - cryptojs</li>
494  * <li>hmacsha512 - cryptojs</li>
495  * </ul>
496  * NOTE: HmacSHA224 and HmacSHA384 issue was fixed since jsrsasign 4.1.4.
497  * Please use 'ext/cryptojs-312-core-fix*.js' instead of 'core.js' of original CryptoJS
498  * to avoid those issue.
499  * @example
500  * var mac = new KJUR.crypto.Mac({alg: "HmacSHA1", prov: "cryptojs", "pass": "pass"});
501  * mac.updateString('aaa')
502  * var macHex = md.doFinal()
503  */
504 KJUR.crypto.Mac = function(params) {
505     var mac = null;
506     var pass = null;
507     var algName = null;
508     var provName = null;
509     var algProv = null;
510 
511     this.setAlgAndProvider = function(alg, prov) {
512 	if (alg == null) alg = "hmacsha1";
513 
514 	alg = alg.toLowerCase();
515         if (alg.substr(0, 4) != "hmac") {
516 	    throw "setAlgAndProvider unsupported HMAC alg: " + alg;
517 	}
518 
519 	if (prov === undefined) prov = KJUR.crypto.Util.DEFAULTPROVIDER[alg];
520 	this.algProv = alg + "/" + prov;
521 
522 	var hashAlg = alg.substr(4);
523 
524 	// for cryptojs
525 	if (':md5:sha1:sha224:sha256:sha384:sha512:ripemd160:'.indexOf(hashAlg) != -1 &&
526 	    prov == 'cryptojs') {
527 	    try {
528 		var mdObj = eval(KJUR.crypto.Util.CRYPTOJSMESSAGEDIGESTNAME[hashAlg]);
529 		this.mac = CryptoJS.algo.HMAC.create(mdObj, this.pass);
530 	    } catch (ex) {
531 		throw "setAlgAndProvider hash alg set fail hashAlg=" + hashAlg + "/" + ex;
532 	    }
533 	    this.updateString = function(str) {
534 		this.mac.update(str);
535 	    };
536 	    this.updateHex = function(hex) {
537 		var wHex = CryptoJS.enc.Hex.parse(hex);
538 		this.mac.update(wHex);
539 	    };
540 	    this.doFinal = function() {
541 		var hash = this.mac.finalize();
542 		return hash.toString(CryptoJS.enc.Hex);
543 	    };
544 	    this.doFinalString = function(str) {
545 		this.updateString(str);
546 		return this.doFinal();
547 	    };
548 	    this.doFinalHex = function(hex) {
549 		this.updateHex(hex);
550 		return this.doFinal();
551 	    };
552 	}
553     };
554 
555     /**
556      * update digest by specified string
557      * @name updateString
558      * @memberOf KJUR.crypto.Mac
559      * @function
560      * @param {String} str string to update
561      * @description
562      * @example
563      * md.updateString('New York');
564      */
565     this.updateString = function(str) {
566 	throw "updateString(str) not supported for this alg/prov: " + this.algProv;
567     };
568 
569     /**
570      * update digest by specified hexadecimal string
571      * @name updateHex
572      * @memberOf KJUR.crypto.Mac
573      * @function
574      * @param {String} hex hexadecimal string to update
575      * @description
576      * @example
577      * md.updateHex('0afe36');
578      */
579     this.updateHex = function(hex) {
580 	throw "updateHex(hex) not supported for this alg/prov: " + this.algProv;
581     };
582 
583     /**
584      * completes hash calculation and returns hash result
585      * @name doFinal
586      * @memberOf KJUR.crypto.Mac
587      * @function
588      * @description
589      * @example
590      * md.digest()
591      */
592     this.doFinal = function() {
593 	throw "digest() not supported for this alg/prov: " + this.algProv;
594     };
595 
596     /**
597      * performs final update on the digest using string, then completes the digest computation
598      * @name doFinalString
599      * @memberOf KJUR.crypto.Mac
600      * @function
601      * @param {String} str string to final update
602      * @description
603      * @example
604      * md.digestString('aaa')
605      */
606     this.doFinalString = function(str) {
607 	throw "digestString(str) not supported for this alg/prov: " + this.algProv;
608     };
609 
610     /**
611      * performs final update on the digest using hexadecimal string, 
612      * then completes the digest computation
613      * @name doFinalHex
614      * @memberOf KJUR.crypto.Mac
615      * @function
616      * @param {String} hex hexadecimal string to final update
617      * @description
618      * @example
619      * md.digestHex('0f2abd')
620      */
621     this.doFinalHex = function(hex) {
622 	throw "digestHex(hex) not supported for this alg/prov: " + this.algProv;
623     };
624 
625     if (params !== undefined) {
626 	if (params['pass'] !== undefined) {
627 	    this.pass = params['pass'];
628 	}
629 	if (params['alg'] !== undefined) {
630 	    this.algName = params['alg'];
631 	    if (params['prov'] === undefined)
632 		this.provName = KJUR.crypto.Util.DEFAULTPROVIDER[this.algName];
633 	    this.setAlgAndProvider(this.algName, this.provName);
634 	}
635     }
636 };
637 
638 /**
639  * Signature class which is very similar to java.security.Signature class
640  * @name KJUR.crypto.Signature
641  * @class Signature class which is very similar to java.security.Signature class
642  * @param {Array} params parameters for constructor
643  * @property {String} state Current state of this signature object whether 'SIGN', 'VERIFY' or null
644  * @description
645  * <br/>
646  * As for params of constructor's argument, it can be specify following attributes:
647  * <ul>
648  * <li>alg - signature algorithm name (ex. {MD5,SHA1,SHA224,SHA256,SHA384,SHA512,RIPEMD160}with{RSA,ECDSA,DSA})</li>
649  * <li>provider - currently 'cryptojs/jsrsa' only</li>
650  * </ul>
651  * <h4>SUPPORTED ALGORITHMS AND PROVIDERS</h4>
652  * This Signature class supports following signature algorithm and provider names:
653  * <ul>
654  * <li>MD5withRSA - cryptojs/jsrsa</li>
655  * <li>SHA1withRSA - cryptojs/jsrsa</li>
656  * <li>SHA224withRSA - cryptojs/jsrsa</li>
657  * <li>SHA256withRSA - cryptojs/jsrsa</li>
658  * <li>SHA384withRSA - cryptojs/jsrsa</li>
659  * <li>SHA512withRSA - cryptojs/jsrsa</li>
660  * <li>RIPEMD160withRSA - cryptojs/jsrsa</li>
661  * <li>MD5withECDSA - cryptojs/jsrsa</li>
662  * <li>SHA1withECDSA - cryptojs/jsrsa</li>
663  * <li>SHA224withECDSA - cryptojs/jsrsa</li>
664  * <li>SHA256withECDSA - cryptojs/jsrsa</li>
665  * <li>SHA384withECDSA - cryptojs/jsrsa</li>
666  * <li>SHA512withECDSA - cryptojs/jsrsa</li>
667  * <li>RIPEMD160withECDSA - cryptojs/jsrsa</li>
668  * <li>MD5withRSAandMGF1 - cryptojs/jsrsa</li>
669  * <li>SHA1withRSAandMGF1 - cryptojs/jsrsa</li>
670  * <li>SHA224withRSAandMGF1 - cryptojs/jsrsa</li>
671  * <li>SHA256withRSAandMGF1 - cryptojs/jsrsa</li>
672  * <li>SHA384withRSAandMGF1 - cryptojs/jsrsa</li>
673  * <li>SHA512withRSAandMGF1 - cryptojs/jsrsa</li>
674  * <li>RIPEMD160withRSAandMGF1 - cryptojs/jsrsa</li>
675  * <li>SHA1withDSA - cryptojs/jsrsa</li>
676  * <li>SHA224withDSA - cryptojs/jsrsa</li>
677  * <li>SHA256withDSA - cryptojs/jsrsa</li>
678  * </ul>
679  * Here are supported elliptic cryptographic curve names and their aliases for ECDSA:
680  * <ul>
681  * <li>secp256k1</li>
682  * <li>secp256r1, NIST P-256, P-256, prime256v1</li>
683  * <li>secp384r1, NIST P-384, P-384</li>
684  * </ul>
685  * NOTE1: DSA signing algorithm is also supported since crypto 1.1.5.
686  * <h4>EXAMPLES</h4>
687  * @example
688  * // RSA signature generation
689  * var sig = new KJUR.crypto.Signature({"alg": "SHA1withRSA"});
690  * sig.init(prvKeyPEM);
691  * sig.updateString('aaa');
692  * var hSigVal = sig.sign();
693  *
694  * // DSA signature validation
695  * var sig2 = new KJUR.crypto.Signature({"alg": "SHA1withDSA"});
696  * sig2.init(certPEM);
697  * sig.updateString('aaa');
698  * var isValid = sig2.verify(hSigVal);
699  * 
700  * // ECDSA signing
701  * var sig = new KJUR.crypto.Signature({'alg':'SHA1withECDSA'});
702  * sig.init(prvKeyPEM);
703  * sig.updateString('aaa');
704  * var sigValueHex = sig.sign();
705  *
706  * // ECDSA verifying
707  * var sig2 = new KJUR.crypto.Signature({'alg':'SHA1withECDSA'});
708  * sig.init(certPEM);
709  * sig.updateString('aaa');
710  * var isValid = sig.verify(sigValueHex);
711  */
712 KJUR.crypto.Signature = function(params) {
713     var prvKey = null; // RSAKey/KJUR.crypto.{ECDSA,DSA} object for signing
714     var pubKey = null; // RSAKey/KJUR.crypto.{ECDSA,DSA} object for verifying
715 
716     var md = null; // KJUR.crypto.MessageDigest object
717     var sig = null;
718     var algName = null;
719     var provName = null;
720     var algProvName = null;
721     var mdAlgName = null;
722     var pubkeyAlgName = null;	// rsa,ecdsa,rsaandmgf1(=rsapss)
723     var state = null;
724     var pssSaltLen = -1;
725     var initParams = null;
726 
727     var sHashHex = null; // hex hash value for hex
728     var hDigestInfo = null;
729     var hPaddedDigestInfo = null;
730     var hSign = null;
731 
732     this._setAlgNames = function() {
733 	if (this.algName.match(/^(.+)with(.+)$/)) {
734 	    this.mdAlgName = RegExp.$1.toLowerCase();
735 	    this.pubkeyAlgName = RegExp.$2.toLowerCase();
736 	}
737     };
738 
739     this._zeroPaddingOfSignature = function(hex, bitLength) {
740 	var s = "";
741 	var nZero = bitLength / 4 - hex.length;
742 	for (var i = 0; i < nZero; i++) {
743 	    s = s + "0";
744 	}
745 	return s + hex;
746     };
747 
748     /**
749      * set signature algorithm and provider
750      * @name setAlgAndProvider
751      * @memberOf KJUR.crypto.Signature
752      * @function
753      * @param {String} alg signature algorithm name
754      * @param {String} prov provider name
755      * @description
756      * @example
757      * md.setAlgAndProvider('SHA1withRSA', 'cryptojs/jsrsa');
758      */
759     this.setAlgAndProvider = function(alg, prov) {
760 	this._setAlgNames();
761 	if (prov != 'cryptojs/jsrsa')
762 	    throw "provider not supported: " + prov;
763 
764 	if (':md5:sha1:sha224:sha256:sha384:sha512:ripemd160:'.indexOf(this.mdAlgName) != -1) {
765 	    try {
766 		this.md = new KJUR.crypto.MessageDigest({'alg':this.mdAlgName});
767 	    } catch (ex) {
768 		throw "setAlgAndProvider hash alg set fail alg=" +
769                       this.mdAlgName + "/" + ex;
770 	    }
771 
772 	    this.init = function(keyparam, pass) {
773 		var keyObj = null;
774 		try {
775 		    if (pass === undefined) {
776 			keyObj = KEYUTIL.getKey(keyparam);
777 		    } else {
778 			keyObj = KEYUTIL.getKey(keyparam, pass);
779 		    }
780 		} catch (ex) {
781 		    throw "init failed:" + ex;
782 		}
783 
784 		if (keyObj.isPrivate === true) {
785 		    this.prvKey = keyObj;
786 		    this.state = "SIGN";
787 		} else if (keyObj.isPublic === true) {
788 		    this.pubKey = keyObj;
789 		    this.state = "VERIFY";
790 		} else {
791 		    throw "init failed.:" + keyObj;
792 		}
793 	    };
794 
795 	    this.initSign = function(params) {
796 		if (typeof params['ecprvhex'] == 'string' &&
797                     typeof params['eccurvename'] == 'string') {
798 		    this.ecprvhex = params['ecprvhex'];
799 		    this.eccurvename = params['eccurvename'];
800 		} else {
801 		    this.prvKey = params;
802 		}
803 		this.state = "SIGN";
804 	    };
805 
806 	    this.initVerifyByPublicKey = function(params) {
807 		if (typeof params['ecpubhex'] == 'string' &&
808 		    typeof params['eccurvename'] == 'string') {
809 		    this.ecpubhex = params['ecpubhex'];
810 		    this.eccurvename = params['eccurvename'];
811 		} else if (params instanceof KJUR.crypto.ECDSA) {
812 		    this.pubKey = params;
813 		} else if (params instanceof RSAKey) {
814 		    this.pubKey = params;
815 		}
816 		this.state = "VERIFY";
817 	    };
818 
819 	    this.initVerifyByCertificatePEM = function(certPEM) {
820 		var x509 = new X509();
821 		x509.readCertPEM(certPEM);
822 		this.pubKey = x509.subjectPublicKeyRSA;
823 		this.state = "VERIFY";
824 	    };
825 
826 	    this.updateString = function(str) {
827 		this.md.updateString(str);
828 	    };
829 	    this.updateHex = function(hex) {
830 		this.md.updateHex(hex);
831 	    };
832 
833 	    this.sign = function() {
834 		this.sHashHex = this.md.digest();
835 		if (typeof this.ecprvhex != "undefined" &&
836 		    typeof this.eccurvename != "undefined") {
837 		    var ec = new KJUR.crypto.ECDSA({'curve': this.eccurvename});
838 		    this.hSign = ec.signHex(this.sHashHex, this.ecprvhex);
839 		} else if (this.pubkeyAlgName == "rsaandmgf1") {
840 		    this.hSign = this.prvKey.signWithMessageHashPSS(this.sHashHex,
841 								    this.mdAlgName,
842 								    this.pssSaltLen);
843 		} else if (this.pubkeyAlgName == "rsa") {
844 		    this.hSign = this.prvKey.signWithMessageHash(this.sHashHex,
845 								 this.mdAlgName);
846 		} else if (this.prvKey instanceof KJUR.crypto.ECDSA) {
847 		    this.hSign = this.prvKey.signWithMessageHash(this.sHashHex);
848 		} else if (this.prvKey instanceof KJUR.crypto.DSA) {
849 		    this.hSign = this.prvKey.signWithMessageHash(this.sHashHex);
850 		} else {
851 		    throw "Signature: unsupported public key alg: " + this.pubkeyAlgName;
852 		}
853 		return this.hSign;
854 	    };
855 	    this.signString = function(str) {
856 		this.updateString(str);
857 		return this.sign();
858 	    };
859 	    this.signHex = function(hex) {
860 		this.updateHex(hex);
861 		return this.sign();
862 	    };
863 	    this.verify = function(hSigVal) {
864 	        this.sHashHex = this.md.digest();
865 		if (typeof this.ecpubhex != "undefined" &&
866 		    typeof this.eccurvename != "undefined") {
867 		    var ec = new KJUR.crypto.ECDSA({curve: this.eccurvename});
868 		    return ec.verifyHex(this.sHashHex, hSigVal, this.ecpubhex);
869 		} else if (this.pubkeyAlgName == "rsaandmgf1") {
870 		    return this.pubKey.verifyWithMessageHashPSS(this.sHashHex, hSigVal, 
871 								this.mdAlgName,
872 								this.pssSaltLen);
873 		} else if (this.pubkeyAlgName == "rsa") {
874 		    return this.pubKey.verifyWithMessageHash(this.sHashHex, hSigVal);
875 		} else if (this.pubKey instanceof KJUR.crypto.ECDSA) {
876 		    return this.pubKey.verifyWithMessageHash(this.sHashHex, hSigVal);
877 		} else if (this.pubKey instanceof KJUR.crypto.DSA) {
878 		    return this.pubKey.verifyWithMessageHash(this.sHashHex, hSigVal);
879 		} else {
880 		    throw "Signature: unsupported public key alg: " + this.pubkeyAlgName;
881 		}
882 	    };
883 	}
884     };
885 
886     /**
887      * Initialize this object for signing or verifying depends on key
888      * @name init
889      * @memberOf KJUR.crypto.Signature
890      * @function
891      * @param {Object} key specifying public or private key as plain/encrypted PKCS#5/8 PEM file, certificate PEM or {@link RSAKey}, {@link KJUR.crypto.DSA} or {@link KJUR.crypto.ECDSA} object
892      * @param {String} pass (OPTION) passcode for encrypted private key
893      * @since crypto 1.1.3
894      * @description
895      * This method is very useful initialize method for Signature class since
896      * you just specify key then this method will automatically initialize it
897      * using {@link KEYUTIL.getKey} method.
898      * As for 'key',  following argument type are supported:
899      * <h5>signing</h5>
900      * <ul>
901      * <li>PEM formatted PKCS#8 encrypted RSA/ECDSA private key concluding "BEGIN ENCRYPTED PRIVATE KEY"</li>
902      * <li>PEM formatted PKCS#5 encrypted RSA/DSA private key concluding "BEGIN RSA/DSA PRIVATE KEY" and ",ENCRYPTED"</li>
903      * <li>PEM formatted PKCS#8 plain RSA/ECDSA private key concluding "BEGIN PRIVATE KEY"</li>
904      * <li>PEM formatted PKCS#5 plain RSA/DSA private key concluding "BEGIN RSA/DSA PRIVATE KEY" without ",ENCRYPTED"</li>
905      * <li>RSAKey object of private key</li>
906      * <li>KJUR.crypto.ECDSA object of private key</li>
907      * <li>KJUR.crypto.DSA object of private key</li>
908      * </ul>
909      * <h5>verification</h5>
910      * <ul>
911      * <li>PEM formatted PKCS#8 RSA/EC/DSA public key concluding "BEGIN PUBLIC KEY"</li>
912      * <li>PEM formatted X.509 certificate with RSA/EC/DSA public key concluding
913      *     "BEGIN CERTIFICATE", "BEGIN X509 CERTIFICATE" or "BEGIN TRUSTED CERTIFICATE".</li>
914      * <li>RSAKey object of public key</li>
915      * <li>KJUR.crypto.ECDSA object of public key</li>
916      * <li>KJUR.crypto.DSA object of public key</li>
917      * </ul>
918      * @example
919      * sig.init(sCertPEM)
920      */
921     this.init = function(key, pass) {
922 	throw "init(key, pass) not supported for this alg:prov=" +
923 	      this.algProvName;
924     };
925 
926     /**
927      * Initialize this object for verifying with a public key
928      * @name initVerifyByPublicKey
929      * @memberOf KJUR.crypto.Signature
930      * @function
931      * @param {Object} param RSAKey object of public key or associative array for ECDSA
932      * @since 1.0.2
933      * @deprecated from crypto 1.1.5. please use init() method instead.
934      * @description
935      * Public key information will be provided as 'param' parameter and the value will be
936      * following:
937      * <ul>
938      * <li>{@link RSAKey} object for RSA verification</li>
939      * <li>associative array for ECDSA verification
940      *     (ex. <code>{'ecpubhex': '041f..', 'eccurvename': 'secp256r1'}</code>)
941      * </li>
942      * </ul>
943      * @example
944      * sig.initVerifyByPublicKey(rsaPrvKey)
945      */
946     this.initVerifyByPublicKey = function(rsaPubKey) {
947 	throw "initVerifyByPublicKey(rsaPubKeyy) not supported for this alg:prov=" +
948 	      this.algProvName;
949     };
950 
951     /**
952      * Initialize this object for verifying with a certficate
953      * @name initVerifyByCertificatePEM
954      * @memberOf KJUR.crypto.Signature
955      * @function
956      * @param {String} certPEM PEM formatted string of certificate
957      * @since 1.0.2
958      * @deprecated from crypto 1.1.5. please use init() method instead.
959      * @description
960      * @example
961      * sig.initVerifyByCertificatePEM(certPEM)
962      */
963     this.initVerifyByCertificatePEM = function(certPEM) {
964 	throw "initVerifyByCertificatePEM(certPEM) not supported for this alg:prov=" +
965 	    this.algProvName;
966     };
967 
968     /**
969      * Initialize this object for signing
970      * @name initSign
971      * @memberOf KJUR.crypto.Signature
972      * @function
973      * @param {Object} param RSAKey object of public key or associative array for ECDSA
974      * @deprecated from crypto 1.1.5. please use init() method instead.
975      * @description
976      * Private key information will be provided as 'param' parameter and the value will be
977      * following:
978      * <ul>
979      * <li>{@link RSAKey} object for RSA signing</li>
980      * <li>associative array for ECDSA signing
981      *     (ex. <code>{'ecprvhex': '1d3f..', 'eccurvename': 'secp256r1'}</code>)</li>
982      * </ul>
983      * @example
984      * sig.initSign(prvKey)
985      */
986     this.initSign = function(prvKey) {
987 	throw "initSign(prvKey) not supported for this alg:prov=" + this.algProvName;
988     };
989 
990     /**
991      * Updates the data to be signed or verified by a string
992      * @name updateString
993      * @memberOf KJUR.crypto.Signature
994      * @function
995      * @param {String} str string to use for the update
996      * @description
997      * @example
998      * sig.updateString('aaa')
999      */
1000     this.updateString = function(str) {
1001 	throw "updateString(str) not supported for this alg:prov=" + this.algProvName;
1002     };
1003 
1004     /**
1005      * Updates the data to be signed or verified by a hexadecimal string
1006      * @name updateHex
1007      * @memberOf KJUR.crypto.Signature
1008      * @function
1009      * @param {String} hex hexadecimal string to use for the update
1010      * @description
1011      * @example
1012      * sig.updateHex('1f2f3f')
1013      */
1014     this.updateHex = function(hex) {
1015 	throw "updateHex(hex) not supported for this alg:prov=" + this.algProvName;
1016     };
1017 
1018     /**
1019      * Returns the signature bytes of all data updates as a hexadecimal string
1020      * @name sign
1021      * @memberOf KJUR.crypto.Signature
1022      * @function
1023      * @return the signature bytes as a hexadecimal string
1024      * @description
1025      * @example
1026      * var hSigValue = sig.sign()
1027      */
1028     this.sign = function() {
1029 	throw "sign() not supported for this alg:prov=" + this.algProvName;
1030     };
1031 
1032     /**
1033      * performs final update on the sign using string, then returns the signature bytes of all data updates as a hexadecimal string
1034      * @name signString
1035      * @memberOf KJUR.crypto.Signature
1036      * @function
1037      * @param {String} str string to final update
1038      * @return the signature bytes of a hexadecimal string
1039      * @description
1040      * @example
1041      * var hSigValue = sig.signString('aaa')
1042      */
1043     this.signString = function(str) {
1044 	throw "digestString(str) not supported for this alg:prov=" + this.algProvName;
1045     };
1046 
1047     /**
1048      * performs final update on the sign using hexadecimal string, then returns the signature bytes of all data updates as a hexadecimal string
1049      * @name signHex
1050      * @memberOf KJUR.crypto.Signature
1051      * @function
1052      * @param {String} hex hexadecimal string to final update
1053      * @return the signature bytes of a hexadecimal string
1054      * @description
1055      * @example
1056      * var hSigValue = sig.signHex('1fdc33')
1057      */
1058     this.signHex = function(hex) {
1059 	throw "digestHex(hex) not supported for this alg:prov=" + this.algProvName;
1060     };
1061 
1062     /**
1063      * verifies the passed-in signature.
1064      * @name verify
1065      * @memberOf KJUR.crypto.Signature
1066      * @function
1067      * @param {String} str string to final update
1068      * @return {Boolean} true if the signature was verified, otherwise false
1069      * @description
1070      * @example
1071      * var isValid = sig.verify('1fbcefdca4823a7(snip)')
1072      */
1073     this.verify = function(hSigVal) {
1074 	throw "verify(hSigVal) not supported for this alg:prov=" + this.algProvName;
1075     };
1076 
1077     this.initParams = params;
1078 
1079     if (params !== undefined) {
1080 	if (params['alg'] !== undefined) {
1081 	    this.algName = params['alg'];
1082 	    if (params['prov'] === undefined) {
1083 		this.provName = KJUR.crypto.Util.DEFAULTPROVIDER[this.algName];
1084 	    } else {
1085 		this.provName = params['prov'];
1086 	    }
1087 	    this.algProvName = this.algName + ":" + this.provName;
1088 	    this.setAlgAndProvider(this.algName, this.provName);
1089 	    this._setAlgNames();
1090 	}
1091 
1092 	if (params['psssaltlen'] !== undefined) this.pssSaltLen = params['psssaltlen'];
1093 
1094 	if (params['prvkeypem'] !== undefined) {
1095 	    if (params['prvkeypas'] !== undefined) {
1096 		throw "both prvkeypem and prvkeypas parameters not supported";
1097 	    } else {
1098 		try {
1099 		    var prvKey = new RSAKey();
1100 		    prvKey.readPrivateKeyFromPEMString(params['prvkeypem']);
1101 		    this.initSign(prvKey);
1102 		} catch (ex) {
1103 		    throw "fatal error to load pem private key: " + ex;
1104 		}
1105 	    }
1106 	}
1107     }
1108 };
1109 
1110 /**
1111  * static object for cryptographic function utilities
1112  * @name KJUR.crypto.OID
1113  * @class static object for cryptography related OIDs
1114  * @property {Array} oidhex2name key value of hexadecimal OID and its name
1115  *           (ex. '2a8648ce3d030107' and 'secp256r1')
1116  * @since crypto 1.1.3
1117  * @description
1118  */
1119 
1120 
1121 KJUR.crypto.OID = new function() {
1122     this.oidhex2name = {
1123 	'2a864886f70d010101': 'rsaEncryption',
1124 	'2a8648ce3d0201': 'ecPublicKey',
1125 	'2a8648ce380401': 'dsa',
1126 	'2a8648ce3d030107': 'secp256r1',
1127 	'2b8104001f': 'secp192k1',
1128 	'2b81040021': 'secp224r1',
1129 	'2b8104000a': 'secp256k1',
1130 	'2b81040023': 'secp521r1',
1131 	'2b81040022': 'secp384r1',
1132 	'2a8648ce380403': 'SHA1withDSA', // 1.2.840.10040.4.3
1133 	'608648016503040301': 'SHA224withDSA', // 2.16.840.1.101.3.4.3.1
1134 	'608648016503040302': 'SHA256withDSA', // 2.16.840.1.101.3.4.3.2
1135     };
1136 };
1137