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