1 /*! ecdsa-modified-1.0.4.js (c) Stephan Thomas, Kenji Urushima | github.com/bitcoinjs/bitcoinjs-lib/blob/master/LICENSE
  2  */
  3 /*
  4  * ecdsa-modified.js - modified Bitcoin.ECDSA class
  5  * 
  6  * Copyright (c) 2013 Stefan Thomas (github.com/justmoon)
  7  *                    Kenji Urushima (kenji.urushima@gmail.com)
  8  * LICENSE
  9  *   https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/LICENSE
 10  */
 11 
 12 /**
 13  * @fileOverview
 14  * @name ecdsa-modified-1.0.js
 15  * @author Stefan Thomas (github.com/justmoon) and Kenji Urushima (kenji.urushima@gmail.com)
 16  * @version 1.0.4 (2013-Oct-06)
 17  * @since jsrsasign 4.0
 18  * @license <a href="https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/LICENSE">MIT License</a>
 19  */
 20 
 21 if (typeof KJUR == "undefined" || !KJUR) KJUR = {};
 22 if (typeof KJUR.crypto == "undefined" || !KJUR.crypto) KJUR.crypto = {};
 23 
 24 /**
 25  * class for EC key generation,  ECDSA signing and verifcation
 26  * @name KJUR.crypto.ECDSA
 27  * @class class for EC key generation,  ECDSA signing and verifcation
 28  * @description
 29  * <p>
 30  * CAUTION: Most of the case, you don't need to use this class except
 31  * for generating an EC key pair. Please use {@link KJUR.crypto.Signature} class instead.
 32  * </p>
 33  * <p>
 34  * This class was originally developped by Stefan Thomas for Bitcoin JavaScript library.
 35  * (See {@link https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/src/ecdsa.js})
 36  * Currently this class supports following named curves and their aliases.
 37  * <ul>
 38  * <li>secp256r1, NIST P-256, P-256, prime256v1 (*)</li>
 39  * <li>secp256k1 (*)</li>
 40  * <li>secp384r1, NIST P-384, P-384 (*)</li>
 41  * </ul>
 42  * </p>
 43  */
 44 KJUR.crypto.ECDSA = function(params) {
 45     var curveName = "secp256r1";	// curve name default
 46     var ecparams = null;
 47     var prvKeyHex = null;
 48     var pubKeyHex = null;
 49 
 50     var rng = new SecureRandom();
 51 
 52     var P_OVER_FOUR = null;
 53 
 54     this.type = "EC";
 55 
 56     function implShamirsTrick(P, k, Q, l) {
 57 	var m = Math.max(k.bitLength(), l.bitLength());
 58 	var Z = P.add2D(Q);
 59 	var R = P.curve.getInfinity();
 60 
 61 	for (var i = m - 1; i >= 0; --i) {
 62 	    R = R.twice2D();
 63 
 64 	    R.z = BigInteger.ONE;
 65 
 66 	    if (k.testBit(i)) {
 67 		if (l.testBit(i)) {
 68 		    R = R.add2D(Z);
 69 		} else {
 70 		    R = R.add2D(P);
 71 		}
 72 	    } else {
 73 		if (l.testBit(i)) {
 74 		    R = R.add2D(Q);
 75 		}
 76 	    }
 77 	}
 78 	
 79 	return R;
 80     };
 81 
 82     //===========================
 83     // PUBLIC METHODS
 84     //===========================
 85     this.getBigRandom = function (limit) {
 86 	return new BigInteger(limit.bitLength(), rng)
 87 	.mod(limit.subtract(BigInteger.ONE))
 88 	.add(BigInteger.ONE)
 89 	;
 90     };
 91 
 92     this.setNamedCurve = function(curveName) {
 93 	this.ecparams = KJUR.crypto.ECParameterDB.getByName(curveName);
 94 	this.prvKeyHex = null;
 95 	this.pubKeyHex = null;
 96 	this.curveName = curveName;
 97     }
 98 
 99     this.setPrivateKeyHex = function(prvKeyHex) {
100         this.isPrivate = true;
101 	this.prvKeyHex = prvKeyHex;
102     }
103 
104     this.setPublicKeyHex = function(pubKeyHex) {
105         this.isPublic = true;
106 	this.pubKeyHex = pubKeyHex;
107     }
108 
109     /**
110      * generate a EC key pair
111      * @name generateKeyPairHex
112      * @memberOf KJUR.crypto.ECDSA
113      * @function
114      * @return {Array} associative array of hexadecimal string of private and public key
115      * @since ecdsa-modified 1.0.1
116      * @example
117      * var ec = new KJUR.crypto.ECDSA({'curve': 'secp256r1'});
118      * var keypair = ec.generateKeyPairHex();
119      * var pubhex = keypair.ecpubhex; // hexadecimal string of EC private key (=d)
120      * var prvhex = keypair.ecprvhex; // hexadecimal string of EC public key
121      */
122     this.generateKeyPairHex = function() {
123 	var biN = this.ecparams['n'];
124 	var biPrv = this.getBigRandom(biN);
125 	var epPub = this.ecparams['G'].multiply(biPrv);
126 	var biX = epPub.getX().toBigInteger();
127 	var biY = epPub.getY().toBigInteger();
128 
129 	var charlen = this.ecparams['keylen'] / 4;
130 	var hPrv = ("0000000000" + biPrv.toString(16)).slice(- charlen);
131 	var hX   = ("0000000000" + biX.toString(16)).slice(- charlen);
132 	var hY   = ("0000000000" + biY.toString(16)).slice(- charlen);
133 	var hPub = "04" + hX + hY;
134 
135 	this.setPrivateKeyHex(hPrv);
136 	this.setPublicKeyHex(hPub);
137 	return {'ecprvhex': hPrv, 'ecpubhex': hPub};
138     };
139 
140     this.signWithMessageHash = function(hashHex) {
141 	return this.signHex(hashHex, this.prvKeyHex);
142     };
143 
144     /**
145      * signing to message hash
146      * @name signHex
147      * @memberOf KJUR.crypto.ECDSA
148      * @function
149      * @param {String} hashHex hexadecimal string of hash value of signing message
150      * @param {String} privHex hexadecimal string of EC private key
151      * @return {String} hexadecimal string of ECDSA signature
152      * @since ecdsa-modified 1.0.1
153      * @example
154      * var ec = new KJUR.crypto.ECDSA({'curve': 'secp256r1'});
155      * var sigValue = ec.signHex(hash, prvKey);
156      */
157     this.signHex = function (hashHex, privHex) {
158 	var d = new BigInteger(privHex, 16);
159 	var n = this.ecparams['n'];
160 	var e = new BigInteger(hashHex, 16);
161 
162 	do {
163 	    var k = this.getBigRandom(n);
164 	    var G = this.ecparams['G'];
165 	    var Q = G.multiply(k);
166 	    var r = Q.getX().toBigInteger().mod(n);
167 	} while (r.compareTo(BigInteger.ZERO) <= 0);
168 
169 	var s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n);
170 
171 	return KJUR.crypto.ECDSA.biRSSigToASN1Sig(r, s);
172     };
173 
174     this.sign = function (hash, priv) {
175 	var d = priv;
176 	var n = this.ecparams['n'];
177 	var e = BigInteger.fromByteArrayUnsigned(hash);
178 
179 	do {
180 	    var k = this.getBigRandom(n);
181 	    var G = this.ecparams['G'];
182 	    var Q = G.multiply(k);
183 	    var r = Q.getX().toBigInteger().mod(n);
184 	} while (r.compareTo(BigInteger.ZERO) <= 0);
185 
186 	var s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n);
187 	return this.serializeSig(r, s);
188     };
189 
190     this.verifyWithMessageHash = function(hashHex, sigHex) {
191 	return this.verifyHex(hashHex, sigHex, this.pubKeyHex);
192     };
193 
194     /**
195      * verifying signature with message hash and public key
196      * @name verifyHex
197      * @memberOf KJUR.crypto.ECDSA
198      * @function
199      * @param {String} hashHex hexadecimal string of hash value of signing message
200      * @param {String} sigHex hexadecimal string of signature value
201      * @param {String} pubkeyHex hexadecimal string of public key
202      * @return {Boolean} true if the signature is valid, otherwise false
203      * @since ecdsa-modified 1.0.1
204      * @example
205      * var ec = new KJUR.crypto.ECDSA({'curve': 'secp256r1'});
206      * var result = ec.verifyHex(msgHashHex, sigHex, pubkeyHex);
207      */
208     this.verifyHex = function(hashHex, sigHex, pubkeyHex) {
209 	var r,s;
210 
211 	var obj = KJUR.crypto.ECDSA.parseSigHex(sigHex);
212 	r = obj.r;
213 	s = obj.s;
214 
215 	var Q;
216 	Q = ECPointFp.decodeFromHex(this.ecparams['curve'], pubkeyHex);
217 	var e = new BigInteger(hashHex, 16);
218 
219 	return this.verifyRaw(e, r, s, Q);
220     };
221 
222     this.verify = function (hash, sig, pubkey) {
223 	var r,s;
224 	if (Bitcoin.Util.isArray(sig)) {
225 	    var obj = this.parseSig(sig);
226 	    r = obj.r;
227 	    s = obj.s;
228 	} else if ("object" === typeof sig && sig.r && sig.s) {
229 	    r = sig.r;
230 	    s = sig.s;
231 	} else {
232 	    throw "Invalid value for signature";
233 	}
234 
235 	var Q;
236 	if (pubkey instanceof ECPointFp) {
237 	    Q = pubkey;
238 	} else if (Bitcoin.Util.isArray(pubkey)) {
239 	    Q = ECPointFp.decodeFrom(this.ecparams['curve'], pubkey);
240 	} else {
241 	    throw "Invalid format for pubkey value, must be byte array or ECPointFp";
242 	}
243 	var e = BigInteger.fromByteArrayUnsigned(hash);
244 
245 	return this.verifyRaw(e, r, s, Q);
246     };
247 
248     this.verifyRaw = function (e, r, s, Q) {
249 	var n = this.ecparams['n'];
250 	var G = this.ecparams['G'];
251 
252 	if (r.compareTo(BigInteger.ONE) < 0 ||
253 	    r.compareTo(n) >= 0)
254 	    return false;
255 
256 	if (s.compareTo(BigInteger.ONE) < 0 ||
257 	    s.compareTo(n) >= 0)
258 	    return false;
259 
260 	var c = s.modInverse(n);
261 
262 	var u1 = e.multiply(c).mod(n);
263 	var u2 = r.multiply(c).mod(n);
264 
265 	// TODO(!!!): For some reason Shamir's trick isn't working with
266 	// signed message verification!? Probably an implementation
267 	// error!
268 	//var point = implShamirsTrick(G, u1, Q, u2);
269 	var point = G.multiply(u1).add(Q.multiply(u2));
270 
271 	var v = point.getX().toBigInteger().mod(n);
272 
273 	return v.equals(r);
274     };
275 
276     /**
277      * Serialize a signature into DER format.
278      *
279      * Takes two BigIntegers representing r and s and returns a byte array.
280      */
281     this.serializeSig = function (r, s) {
282 	var rBa = r.toByteArraySigned();
283 	var sBa = s.toByteArraySigned();
284 
285 	var sequence = [];
286 	sequence.push(0x02); // INTEGER
287 	sequence.push(rBa.length);
288 	sequence = sequence.concat(rBa);
289 
290 	sequence.push(0x02); // INTEGER
291 	sequence.push(sBa.length);
292 	sequence = sequence.concat(sBa);
293 
294 	sequence.unshift(sequence.length);
295 	sequence.unshift(0x30); // SEQUENCE
296 	return sequence;
297     };
298 
299     /**
300      * Parses a byte array containing a DER-encoded signature.
301      *
302      * This function will return an object of the form:
303      *
304      * {
305      *   r: BigInteger,
306      *   s: BigInteger
307      * }
308      */
309     this.parseSig = function (sig) {
310 	var cursor;
311 	if (sig[0] != 0x30)
312 	    throw new Error("Signature not a valid DERSequence");
313 
314 	cursor = 2;
315 	if (sig[cursor] != 0x02)
316 	    throw new Error("First element in signature must be a DERInteger");;
317 	var rBa = sig.slice(cursor+2, cursor+2+sig[cursor+1]);
318 
319 	cursor += 2+sig[cursor+1];
320 	if (sig[cursor] != 0x02)
321 	    throw new Error("Second element in signature must be a DERInteger");
322 	var sBa = sig.slice(cursor+2, cursor+2+sig[cursor+1]);
323 
324 	cursor += 2+sig[cursor+1];
325 
326 	//if (cursor != sig.length)
327 	//  throw new Error("Extra bytes in signature");
328 
329 	var r = BigInteger.fromByteArrayUnsigned(rBa);
330 	var s = BigInteger.fromByteArrayUnsigned(sBa);
331 
332 	return {r: r, s: s};
333     };
334 
335     this.parseSigCompact = function (sig) {
336 	if (sig.length !== 65) {
337 	    throw "Signature has the wrong length";
338 	}
339 
340 	// Signature is prefixed with a type byte storing three bits of
341 	// information.
342 	var i = sig[0] - 27;
343 	if (i < 0 || i > 7) {
344 	    throw "Invalid signature type";
345 	}
346 
347 	var n = this.ecparams['n'];
348 	var r = BigInteger.fromByteArrayUnsigned(sig.slice(1, 33)).mod(n);
349 	var s = BigInteger.fromByteArrayUnsigned(sig.slice(33, 65)).mod(n);
350 
351 	return {r: r, s: s, i: i};
352     };
353 
354     /*
355      * Recover a public key from a signature.
356      *
357      * See SEC 1: Elliptic Curve Cryptography, section 4.1.6, "Public
358      * Key Recovery Operation".
359      *
360      * http://www.secg.org/download/aid-780/sec1-v2.pdf
361      */
362     /*
363     recoverPubKey: function (r, s, hash, i) {
364 	// The recovery parameter i has two bits.
365 	i = i & 3;
366 
367 	// The less significant bit specifies whether the y coordinate
368 	// of the compressed point is even or not.
369 	var isYEven = i & 1;
370 
371 	// The more significant bit specifies whether we should use the
372 	// first or second candidate key.
373 	var isSecondKey = i >> 1;
374 
375 	var n = this.ecparams['n'];
376 	var G = this.ecparams['G'];
377 	var curve = this.ecparams['curve'];
378 	var p = curve.getQ();
379 	var a = curve.getA().toBigInteger();
380 	var b = curve.getB().toBigInteger();
381 
382 	// We precalculate (p + 1) / 4 where p is if the field order
383 	if (!P_OVER_FOUR) {
384 	    P_OVER_FOUR = p.add(BigInteger.ONE).divide(BigInteger.valueOf(4));
385 	}
386 
387 	// 1.1 Compute x
388 	var x = isSecondKey ? r.add(n) : r;
389 
390 	// 1.3 Convert x to point
391 	var alpha = x.multiply(x).multiply(x).add(a.multiply(x)).add(b).mod(p);
392 	var beta = alpha.modPow(P_OVER_FOUR, p);
393 
394 	var xorOdd = beta.isEven() ? (i % 2) : ((i+1) % 2);
395 	// If beta is even, but y isn't or vice versa, then convert it,
396 	// otherwise we're done and y == beta.
397 	var y = (beta.isEven() ? !isYEven : isYEven) ? beta : p.subtract(beta);
398 
399 	// 1.4 Check that nR is at infinity
400 	var R = new ECPointFp(curve,
401 			      curve.fromBigInteger(x),
402 			      curve.fromBigInteger(y));
403 	R.validate();
404 
405 	// 1.5 Compute e from M
406 	var e = BigInteger.fromByteArrayUnsigned(hash);
407 	var eNeg = BigInteger.ZERO.subtract(e).mod(n);
408 
409 	// 1.6 Compute Q = r^-1 (sR - eG)
410 	var rInv = r.modInverse(n);
411 	var Q = implShamirsTrick(R, s, G, eNeg).multiply(rInv);
412 
413 	Q.validate();
414 	if (!this.verifyRaw(e, r, s, Q)) {
415 	    throw "Pubkey recovery unsuccessful";
416 	}
417 
418 	var pubKey = new Bitcoin.ECKey();
419 	pubKey.pub = Q;
420 	return pubKey;
421     },
422     */
423 
424     /*
425      * Calculate pubkey extraction parameter.
426      *
427      * When extracting a pubkey from a signature, we have to
428      * distinguish four different cases. Rather than putting this
429      * burden on the verifier, Bitcoin includes a 2-bit value with the
430      * signature.
431      *
432      * This function simply tries all four cases and returns the value
433      * that resulted in a successful pubkey recovery.
434      */
435     /*
436     calcPubkeyRecoveryParam: function (address, r, s, hash) {
437 	for (var i = 0; i < 4; i++) {
438 	    try {
439 		var pubkey = Bitcoin.ECDSA.recoverPubKey(r, s, hash, i);
440 		if (pubkey.getBitcoinAddress().toString() == address) {
441 		    return i;
442 		}
443 	    } catch (e) {}
444 	}
445 	throw "Unable to find valid recovery factor";
446     }
447     */
448 
449     if (params !== undefined) {
450 	if (params['curve'] !== undefined) {
451 	    this.curveName = params['curve'];
452 	}
453     }
454     if (this.curveName === undefined) this.curveName = curveName;
455     this.setNamedCurve(this.curveName);
456     if (params !== undefined) {
457 	if (params['prv'] !== undefined) this.setPrivateKeyHex(params['prv']);
458 	if (params['pub'] !== undefined) this.setPublicKeyHex(params['pub']);
459     }
460 };
461 
462 /**
463  * parse ASN.1 DER encoded ECDSA signature
464  * @name parseSigHex
465  * @memberOf KJUR.crypto.ECDSA
466  * @function
467  * @static
468  * @param {String} sigHex hexadecimal string of ECDSA signature value
469  * @return {Array} associative array of signature field r and s of BigInteger
470  * @since ecdsa-modified 1.0.1
471  * @example
472  * var ec = new KJUR.crypto.ECDSA({'curve': 'secp256r1'});
473  * var sig = ec.parseSigHex('30...');
474  * var biR = sig.r; // BigInteger object for 'r' field of signature.
475  * var biS = sig.s; // BigInteger object for 's' field of signature.
476  */
477 KJUR.crypto.ECDSA.parseSigHex = function(sigHex) {
478     var p = KJUR.crypto.ECDSA.parseSigHexInHexRS(sigHex);
479     var biR = new BigInteger(p.r, 16);
480     var biS = new BigInteger(p.s, 16);
481     
482     return {'r': biR, 's': biS};
483 };
484 
485 /**
486  * parse ASN.1 DER encoded ECDSA signature
487  * @name parseSigHexInHexRS
488  * @memberOf KJUR.crypto.ECDSA
489  * @function
490  * @static
491  * @param {String} sigHex hexadecimal string of ECDSA signature value
492  * @return {Array} associative array of signature field r and s in hexadecimal
493  * @since ecdsa-modified 1.0.3
494  * @example
495  * var ec = new KJUR.crypto.ECDSA({'curve': 'secp256r1'});
496  * var sig = ec.parseSigHexInHexRS('30...');
497  * var hR = sig.r; // hexadecimal string for 'r' field of signature.
498  * var hS = sig.s; // hexadecimal string for 's' field of signature.
499  */
500 KJUR.crypto.ECDSA.parseSigHexInHexRS = function(sigHex) {
501     // 1. ASN.1 Sequence Check
502     if (sigHex.substr(0, 2) != "30")
503 	throw "signature is not a ASN.1 sequence";
504 
505     // 2. Items of ASN.1 Sequence Check
506     var a = ASN1HEX.getPosArrayOfChildren_AtObj(sigHex, 0);
507     if (a.length != 2)
508 	throw "number of signature ASN.1 sequence elements seem wrong";
509     
510     // 3. Integer check
511     var iTLV1 = a[0];
512     var iTLV2 = a[1];
513     if (sigHex.substr(iTLV1, 2) != "02")
514 	throw "1st item of sequene of signature is not ASN.1 integer";
515     if (sigHex.substr(iTLV2, 2) != "02")
516 	throw "2nd item of sequene of signature is not ASN.1 integer";
517 
518     // 4. getting value
519     var hR = ASN1HEX.getHexOfV_AtObj(sigHex, iTLV1);
520     var hS = ASN1HEX.getHexOfV_AtObj(sigHex, iTLV2);
521     
522     return {'r': hR, 's': hS};
523 };
524 
525 /**
526  * convert hexadecimal ASN.1 encoded signature to concatinated signature
527  * @name asn1SigToConcatSig
528  * @memberOf KJUR.crypto.ECDSA
529  * @function
530  * @static
531  * @param {String} asn1Hex hexadecimal string of ASN.1 encoded ECDSA signature value
532  * @return {String} r-s concatinated format of ECDSA signature value
533  * @since ecdsa-modified 1.0.3
534  */
535 KJUR.crypto.ECDSA.asn1SigToConcatSig = function(asn1Sig) {
536     var pSig = KJUR.crypto.ECDSA.parseSigHexInHexRS(asn1Sig);
537     var hR = pSig.r;
538     var hS = pSig.s;
539 
540     if (hR.substr(0, 2) == "00" && (((hR.length / 2) * 8) % (16 * 8)) == 8) 
541 	hR = hR.substr(2);
542 
543     if (hS.substr(0, 2) == "00" && (((hS.length / 2) * 8) % (16 * 8)) == 8) 
544 	hS = hS.substr(2);
545 
546     if ((((hR.length / 2) * 8) % (16 * 8)) != 0)
547 	throw "unknown ECDSA sig r length error";
548 
549     if ((((hS.length / 2) * 8) % (16 * 8)) != 0)
550 	throw "unknown ECDSA sig s length error";
551 
552     return hR + hS;
553 };
554 
555 /**
556  * convert hexadecimal concatinated signature to ASN.1 encoded signature
557  * @name concatSigToASN1Sig
558  * @memberOf KJUR.crypto.ECDSA
559  * @function
560  * @static
561  * @param {String} concatSig r-s concatinated format of ECDSA signature value
562  * @return {String} hexadecimal string of ASN.1 encoded ECDSA signature value
563  * @since ecdsa-modified 1.0.3
564  */
565 KJUR.crypto.ECDSA.concatSigToASN1Sig = function(concatSig) {
566     if ((((concatSig.length / 2) * 8) % (16 * 8)) != 0)
567 	throw "unknown ECDSA concatinated r-s sig  length error";
568 
569     var hR = concatSig.substr(0, concatSig.length / 2);
570     var hS = concatSig.substr(concatSig.length / 2);
571     return KJUR.crypto.ECDSA.hexRSSigToASN1Sig(hR, hS);
572 };
573 
574 /**
575  * convert hexadecimal R and S value of signature to ASN.1 encoded signature
576  * @name hexRSSigToASN1Sig
577  * @memberOf KJUR.crypto.ECDSA
578  * @function
579  * @static
580  * @param {String} hR hexadecimal string of R field of ECDSA signature value
581  * @param {String} hS hexadecimal string of S field of ECDSA signature value
582  * @return {String} hexadecimal string of ASN.1 encoded ECDSA signature value
583  * @since ecdsa-modified 1.0.3
584  */
585 KJUR.crypto.ECDSA.hexRSSigToASN1Sig = function(hR, hS) {
586     var biR = new BigInteger(hR, 16);
587     var biS = new BigInteger(hS, 16);
588     return KJUR.crypto.ECDSA.biRSSigToASN1Sig(biR, biS);
589 };
590 
591 /**
592  * convert R and S BigInteger object of signature to ASN.1 encoded signature
593  * @name biRSSigToASN1Sig
594  * @memberOf KJUR.crypto.ECDSA
595  * @function
596  * @static
597  * @param {BigInteger} biR BigInteger object of R field of ECDSA signature value
598  * @param {BigInteger} biS BIgInteger object of S field of ECDSA signature value
599  * @return {String} hexadecimal string of ASN.1 encoded ECDSA signature value
600  * @since ecdsa-modified 1.0.3
601  */
602 KJUR.crypto.ECDSA.biRSSigToASN1Sig = function(biR, biS) {
603     var derR = new KJUR.asn1.DERInteger({'bigint': biR});
604     var derS = new KJUR.asn1.DERInteger({'bigint': biS});
605     var derSeq = new KJUR.asn1.DERSequence({'array': [derR, derS]});
606     return derSeq.getEncodedHex();
607 };
608 
609