1 /* ecdsa-modified-1.2.2.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-2021 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 jsrsasign 10.5.16 ecdsa-modified 1.2.2 (2022-Apr-08) 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>secp192k1</li> 39 * <li>secp256r1, NIST P-256, P-256, prime256v1 (*)</li> 40 * <li>secp256k1 (*)</li> 41 * <li>secp384r1, NIST P-384, P-384 (*)</li> 42 * <li>secp521r1, NIST P-521, P-521 (*)</li> 43 * </ul> 44 * </p> 45 */ 46 KJUR.crypto.ECDSA = function(params) { 47 var curveName = "secp256r1"; // curve name default 48 var ecparams = null; 49 var prvKeyHex = null; 50 var pubKeyHex = null; 51 var _Error = Error, 52 _BigInteger = BigInteger, 53 _ECPointFp = ECPointFp, 54 _KJUR_crypto_ECDSA = KJUR.crypto.ECDSA, 55 _KJUR_crypto_ECParameterDB = KJUR.crypto.ECParameterDB, 56 _getName = _KJUR_crypto_ECDSA.getName, 57 _ASN1HEX = ASN1HEX, 58 _getVbyListEx = _ASN1HEX.getVbyListEx, 59 _isASN1HEX = _ASN1HEX.isASN1HEX; 60 61 var rng = new SecureRandom(); 62 63 var P_OVER_FOUR = null; 64 65 this.type = "EC"; 66 this.isPrivate = false; 67 this.isPublic = false; 68 69 function implShamirsTrick(P, k, Q, l) { 70 var m = Math.max(k.bitLength(), l.bitLength()); 71 var Z = P.add2D(Q); 72 var R = P.curve.getInfinity(); 73 74 for (var i = m - 1; i >= 0; --i) { 75 R = R.twice2D(); 76 77 R.z = _BigInteger.ONE; 78 79 if (k.testBit(i)) { 80 if (l.testBit(i)) { 81 R = R.add2D(Z); 82 } else { 83 R = R.add2D(P); 84 } 85 } else { 86 if (l.testBit(i)) { 87 R = R.add2D(Q); 88 } 89 } 90 } 91 92 return R; 93 }; 94 95 //=========================== 96 // PUBLIC METHODS 97 //=========================== 98 this.getBigRandom = function (limit) { 99 return new _BigInteger(limit.bitLength(), rng) 100 .mod(limit.subtract(_BigInteger.ONE)) 101 .add(_BigInteger.ONE) 102 ; 103 }; 104 105 this.setNamedCurve = function(curveName) { 106 this.ecparams = _KJUR_crypto_ECParameterDB.getByName(curveName); 107 this.prvKeyHex = null; 108 this.pubKeyHex = null; 109 this.curveName = curveName; 110 }; 111 112 this.setPrivateKeyHex = function(prvKeyHex) { 113 this.isPrivate = true; 114 this.prvKeyHex = prvKeyHex; 115 }; 116 117 this.setPublicKeyHex = function(pubKeyHex) { 118 this.isPublic = true; 119 this.pubKeyHex = pubKeyHex; 120 }; 121 122 /** 123 * get X and Y hexadecimal string value of public key 124 * @name getPublicKeyXYHex 125 * @memberOf KJUR.crypto.ECDSA# 126 * @function 127 * @return {Array} associative array of x and y value of public key 128 * @since ecdsa-modified 1.0.5 jsrsasign 5.0.14 129 * @example 130 * ec = new KJUR.crypto.ECDSA({'curve': 'secp256r1', 'pub': pubHex}); 131 * ec.getPublicKeyXYHex() → { x: '01bacf...', y: 'c3bc22...' } 132 */ 133 this.getPublicKeyXYHex = function() { 134 var h = this.pubKeyHex; 135 if (h.substr(0, 2) !== "04") 136 throw "this method supports uncompressed format(04) only"; 137 138 var charlen = this.ecparams.keycharlen; 139 if (h.length !== 2 + charlen * 2) 140 throw "malformed public key hex length"; 141 142 var result = {}; 143 result.x = h.substr(2, charlen); 144 result.y = h.substr(2 + charlen); 145 return result; 146 }; 147 148 /** 149 * get NIST curve short name such as "P-256" or "P-384" 150 * @name getShortNISTPCurveName 151 * @memberOf KJUR.crypto.ECDSA# 152 * @function 153 * @return {String} short NIST P curve name such as "P-256" or "P-384" if it's NIST P curve otherwise null; 154 * @since ecdsa-modified 1.0.5 jsrsasign 5.0.14 155 * @example 156 * ec = new KJUR.crypto.ECDSA({'curve': 'secp256r1', 'pub': pubHex}); 157 * ec.getShortPCurveName() → "P-256"; 158 */ 159 this.getShortNISTPCurveName = function() { 160 var s = this.curveName; 161 if (s === "secp256r1" || s === "NIST P-256" || 162 s === "P-256" || s === "prime256v1") 163 return "P-256"; 164 if (s === "secp384r1" || s === "NIST P-384" || s === "P-384") 165 return "P-384"; 166 if (s === "secp521r1" || s === "NIST P-521" || s === "P-521") 167 return "P-521"; 168 return null; 169 }; 170 171 /** 172 * generate a EC key pair 173 * @name generateKeyPairHex 174 * @memberOf KJUR.crypto.ECDSA# 175 * @function 176 * @return {Array} associative array of hexadecimal string of private and public key 177 * @since ecdsa-modified 1.0.1 178 * @example 179 * var ec = new KJUR.crypto.ECDSA({'curve': 'secp256r1'}); 180 * var keypair = ec.generateKeyPairHex(); 181 * var pubhex = keypair.ecpubhex; // hexadecimal string of EC public key 182 * var prvhex = keypair.ecprvhex; // hexadecimal string of EC private key (=d) 183 */ 184 this.generateKeyPairHex = function() { 185 var biN = this.ecparams['n']; 186 var biPrv = this.getBigRandom(biN); 187 var charlen = this.ecparams.keycharlen; 188 var hPrv = ("0000000000" + biPrv.toString(16)).slice(- charlen); 189 this.setPrivateKeyHex(hPrv); 190 var hPub = this.generatePublicKeyHex(); 191 return {'ecprvhex': hPrv, 'ecpubhex': hPub}; 192 }; 193 194 /** 195 * generate public key for EC private key 196 * @name generatePublicKeyHex 197 * @memberOf KJUR.crypto.ECDSA# 198 * @function 199 * @return {String} associative array of hexadecimal string of private and public key 200 * @example 201 * var ec = new KJUR.crypto.ECDSA({'curve': 'secp256r1', 'prv': prvHex}); 202 * var pubhex = ec.generatePublicKeyHex(); // hexadecimal string of EC public key 203 * var pub ec.getPublicKeyXYHex() → { x: '01bacf...', y: 'c3bc22...' } 204 */ 205 this.generatePublicKeyHex = function() { 206 var biPrv = new _BigInteger(this.prvKeyHex, 16); 207 var epPub = this.ecparams['G'].multiply(biPrv); 208 var biX = epPub.getX().toBigInteger(); 209 var biY = epPub.getY().toBigInteger(); 210 var charlen = this.ecparams.keycharlen;; 211 var hX = ("0000000000" + biX.toString(16)).slice(- charlen); 212 var hY = ("0000000000" + biY.toString(16)).slice(- charlen); 213 var hPub = "04" + hX + hY; 214 this.setPublicKeyHex(hPub); 215 return hPub; 216 } 217 218 this.signWithMessageHash = function(hashHex) { 219 return this.signHex(hashHex, this.prvKeyHex); 220 }; 221 222 /** 223 * signing to message hash 224 * @name signHex 225 * @memberOf KJUR.crypto.ECDSA# 226 * @function 227 * @param {String} hashHex hexadecimal string of hash value of signing message 228 * @param {String} privHex hexadecimal string of EC private key 229 * @return {String} hexadecimal string of ECDSA signature 230 * @since ecdsa-modified 1.0.1 231 * @example 232 * var ec = new KJUR.crypto.ECDSA({'curve': 'secp256r1'}); 233 * var sigValue = ec.signHex(hash, prvKey); 234 */ 235 this.signHex = function (hashHex, privHex) { 236 var d = new _BigInteger(privHex, 16); 237 var n = this.ecparams['n']; 238 239 // message hash is truncated with curve key length (FIPS 186-4 6.4) 240 var e = new _BigInteger(hashHex.substring(0, this.ecparams.keycharlen), 16); 241 242 do { 243 var k = this.getBigRandom(n); 244 var G = this.ecparams['G']; 245 var Q = G.multiply(k); 246 var r = Q.getX().toBigInteger().mod(n); 247 } while (r.compareTo(_BigInteger.ZERO) <= 0); 248 249 var s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n); 250 251 return _KJUR_crypto_ECDSA.biRSSigToASN1Sig(r, s); 252 }; 253 254 this.sign = function (hash, priv) { 255 var d = priv; 256 var n = this.ecparams['n']; 257 var e = _BigInteger.fromByteArrayUnsigned(hash); 258 259 do { 260 var k = this.getBigRandom(n); 261 var G = this.ecparams['G']; 262 var Q = G.multiply(k); 263 var r = Q.getX().toBigInteger().mod(n); 264 } while (r.compareTo(BigInteger.ZERO) <= 0); 265 266 var s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n); 267 return this.serializeSig(r, s); 268 }; 269 270 this.verifyWithMessageHash = function(hashHex, sigHex) { 271 return this.verifyHex(hashHex, sigHex, this.pubKeyHex); 272 }; 273 274 /** 275 * verifying signature with message hash and public key 276 * @name verifyHex 277 * @memberOf KJUR.crypto.ECDSA# 278 * @function 279 * @param {String} hashHex hexadecimal string of hash value of signing message 280 * @param {String} sigHex hexadecimal string of signature value 281 * @param {String} pubkeyHex hexadecimal string of public key 282 * @return {Boolean} true if the signature is valid, otherwise false 283 * @since ecdsa-modified 1.0.1 284 * @example 285 * var ec = new KJUR.crypto.ECDSA({'curve': 'secp256r1'}); 286 * var result = ec.verifyHex(msgHashHex, sigHex, pubkeyHex); 287 */ 288 this.verifyHex = function(hashHex, sigHex, pubkeyHex) { 289 try { 290 var r,s; 291 292 var obj = _KJUR_crypto_ECDSA.parseSigHex(sigHex); 293 r = obj.r; 294 s = obj.s; 295 296 var Q = _ECPointFp.decodeFromHex(this.ecparams['curve'], pubkeyHex); 297 298 // message hash is truncated with curve key length (FIPS 186-4 6.4) 299 var e = new _BigInteger(hashHex.substring(0, this.ecparams.keycharlen), 16); 300 301 return this.verifyRaw(e, r, s, Q); 302 } catch (ex) { 303 return false; 304 } 305 }; 306 307 this.verify = function (hash, sig, pubkey) { 308 var r,s; 309 if (Bitcoin.Util.isArray(sig)) { 310 var obj = this.parseSig(sig); 311 r = obj.r; 312 s = obj.s; 313 } else if ("object" === typeof sig && sig.r && sig.s) { 314 r = sig.r; 315 s = sig.s; 316 } else { 317 throw "Invalid value for signature"; 318 } 319 320 var Q; 321 if (pubkey instanceof ECPointFp) { 322 Q = pubkey; 323 } else if (Bitcoin.Util.isArray(pubkey)) { 324 Q = _ECPointFp.decodeFrom(this.ecparams['curve'], pubkey); 325 } else { 326 throw "Invalid format for pubkey value, must be byte array or ECPointFp"; 327 } 328 var e = _BigInteger.fromByteArrayUnsigned(hash); 329 330 return this.verifyRaw(e, r, s, Q); 331 }; 332 333 this.verifyRaw = function (e, r, s, Q) { 334 var n = this.ecparams['n']; 335 var G = this.ecparams['G']; 336 337 if (r.compareTo(_BigInteger.ONE) < 0 || 338 r.compareTo(n) >= 0) 339 return false; 340 341 if (s.compareTo(_BigInteger.ONE) < 0 || 342 s.compareTo(n) >= 0) 343 return false; 344 345 var c = s.modInverse(n); 346 347 var u1 = e.multiply(c).mod(n); 348 var u2 = r.multiply(c).mod(n); 349 350 // TODO(!!!): For some reason Shamir's trick isn't working with 351 // signed message verification!? Probably an implementation 352 // error! 353 //var point = implShamirsTrick(G, u1, Q, u2); 354 var point = G.multiply(u1).add(Q.multiply(u2)); 355 356 var v = point.getX().toBigInteger().mod(n); 357 358 return v.equals(r); 359 }; 360 361 /** 362 * Serialize a signature into DER format. 363 * 364 * Takes two BigIntegers representing r and s and returns a byte array. 365 */ 366 this.serializeSig = function (r, s) { 367 var rBa = r.toByteArraySigned(); 368 var sBa = s.toByteArraySigned(); 369 370 var sequence = []; 371 sequence.push(0x02); // INTEGER 372 sequence.push(rBa.length); 373 sequence = sequence.concat(rBa); 374 375 sequence.push(0x02); // INTEGER 376 sequence.push(sBa.length); 377 sequence = sequence.concat(sBa); 378 379 sequence.unshift(sequence.length); 380 sequence.unshift(0x30); // SEQUENCE 381 return sequence; 382 }; 383 384 /** 385 * Parses a byte array containing a DER-encoded signature. 386 * 387 * This function will return an object of the form: 388 * 389 * { 390 * r: BigInteger, 391 * s: BigInteger 392 * } 393 */ 394 this.parseSig = function (sig) { 395 var cursor; 396 if (sig[0] != 0x30) 397 throw new Error("Signature not a valid DERSequence"); 398 399 cursor = 2; 400 if (sig[cursor] != 0x02) 401 throw new Error("First element in signature must be a DERInteger");; 402 var rBa = sig.slice(cursor+2, cursor+2+sig[cursor+1]); 403 404 cursor += 2+sig[cursor+1]; 405 if (sig[cursor] != 0x02) 406 throw new Error("Second element in signature must be a DERInteger"); 407 var sBa = sig.slice(cursor+2, cursor+2+sig[cursor+1]); 408 409 cursor += 2+sig[cursor+1]; 410 411 //if (cursor != sig.length) 412 // throw new Error("Extra bytes in signature"); 413 414 var r = _BigInteger.fromByteArrayUnsigned(rBa); 415 var s = _BigInteger.fromByteArrayUnsigned(sBa); 416 417 return {r: r, s: s}; 418 }; 419 420 this.parseSigCompact = function (sig) { 421 if (sig.length !== 65) { 422 throw "Signature has the wrong length"; 423 } 424 425 // Signature is prefixed with a type byte storing three bits of 426 // information. 427 var i = sig[0] - 27; 428 if (i < 0 || i > 7) { 429 throw "Invalid signature type"; 430 } 431 432 var n = this.ecparams['n']; 433 var r = _BigInteger.fromByteArrayUnsigned(sig.slice(1, 33)).mod(n); 434 var s = _BigInteger.fromByteArrayUnsigned(sig.slice(33, 65)).mod(n); 435 436 return {r: r, s: s, i: i}; 437 }; 438 439 /** 440 * read an ASN.1 hexadecimal string of PKCS#1/5 plain ECC private key<br/> 441 * @name readPKCS5PrvKeyHex 442 * @memberOf KJUR.crypto.ECDSA# 443 * @function 444 * @param {String} h hexadecimal string of PKCS#1/5 ECC private key 445 * @since jsrsasign 7.1.0 ecdsa-modified 1.1.0 446 */ 447 this.readPKCS5PrvKeyHex = function(h) { 448 if (_isASN1HEX(h) === false) 449 throw new Error("not ASN.1 hex string"); 450 451 var hCurve, hPrv, hPub; 452 try { 453 hCurve = _getVbyListEx(h, 0, ["[0]", 0], "06"); 454 hPrv = _getVbyListEx(h, 0, [1], "04"); 455 try { 456 hPub = _getVbyListEx(h, 0, ["[1]", 0], "03"); 457 } catch(ex) {}; 458 } catch(ex) { 459 throw new Error("malformed PKCS#1/5 plain ECC private key"); 460 } 461 462 this.curveName = _getName(hCurve); 463 if (this.curveName === undefined) throw "unsupported curve name"; 464 465 this.setNamedCurve(this.curveName); 466 this.setPublicKeyHex(hPub); 467 this.setPrivateKeyHex(hPrv); 468 this.isPublic = false; 469 }; 470 471 /** 472 * read an ASN.1 hexadecimal string of PKCS#8 plain ECC private key<br/> 473 * @name readPKCS8PrvKeyHex 474 * @memberOf KJUR.crypto.ECDSA# 475 * @function 476 * @param {String} h hexadecimal string of PKCS#8 ECC private key 477 * @since jsrsasign 7.1.0 ecdsa-modified 1.1.0 478 */ 479 this.readPKCS8PrvKeyHex = function(h) { 480 if (_isASN1HEX(h) === false) 481 throw new _Error("not ASN.1 hex string"); 482 483 var hECOID, hCurve, hPrv, hPub; 484 try { 485 hECOID = _getVbyListEx(h, 0, [1, 0], "06"); 486 hCurve = _getVbyListEx(h, 0, [1, 1], "06"); 487 hPrv = _getVbyListEx(h, 0, [2, 0, 1], "04"); 488 try { 489 hPub = _getVbyListEx(h, 0, [2, 0, "[1]", 0], "03"); //.substr(2); 490 } catch(ex) {}; 491 } catch(ex) { 492 throw new _Error("malformed PKCS#8 plain ECC private key"); 493 } 494 495 this.curveName = _getName(hCurve); 496 if (this.curveName === undefined) 497 throw new _Error("unsupported curve name"); 498 499 this.setNamedCurve(this.curveName); 500 this.setPublicKeyHex(hPub); 501 this.setPrivateKeyHex(hPrv); 502 this.isPublic = false; 503 }; 504 505 /** 506 * read an ASN.1 hexadecimal string of PKCS#8 ECC public key<br/> 507 * @name readPKCS8PubKeyHex 508 * @memberOf KJUR.crypto.ECDSA# 509 * @function 510 * @param {String} h hexadecimal string of PKCS#8 ECC public key 511 * @since jsrsasign 7.1.0 ecdsa-modified 1.1.0 512 */ 513 this.readPKCS8PubKeyHex = function(h) { 514 if (_isASN1HEX(h) === false) 515 throw new _Error("not ASN.1 hex string"); 516 517 var hECOID, hCurve, hPub; 518 try { 519 hECOID = _getVbyListEx(h, 0, [0, 0], "06"); 520 hCurve = _getVbyListEx(h, 0, [0, 1], "06"); 521 hPub = _getVbyListEx(h, 0, [1], "03"); //.substr(2); 522 } catch(ex) { 523 throw new _Error("malformed PKCS#8 ECC public key"); 524 } 525 526 this.curveName = _getName(hCurve); 527 if (this.curveName === null) 528 throw new _Error("unsupported curve name"); 529 530 this.setNamedCurve(this.curveName); 531 this.setPublicKeyHex(hPub); 532 }; 533 534 /** 535 * read an ASN.1 hexadecimal string of X.509 ECC public key certificate<br/> 536 * @name readCertPubKeyHex 537 * @memberOf KJUR.crypto.ECDSA# 538 * @function 539 * @param {String} h hexadecimal string of X.509 ECC public key certificate 540 * @param {Integer} nthPKI nth index of publicKeyInfo. (DEFAULT: 6 for X509v3) 541 * @since jsrsasign 7.1.0 ecdsa-modified 1.1.0 542 */ 543 this.readCertPubKeyHex = function(h, nthPKI) { 544 if (_isASN1HEX(h) === false) 545 throw new _Error("not ASN.1 hex string"); 546 547 var hCurve, hPub; 548 try { 549 hCurve = _getVbyListEx(h, 0, [0, 5, 0, 1], "06"); 550 hPub = _getVbyListEx(h, 0, [0, 5, 1], "03"); 551 } catch(ex) { 552 throw new _Error("malformed X.509 certificate ECC public key"); 553 } 554 555 this.curveName = _getName(hCurve); 556 if (this.curveName === null) 557 throw new _Error("unsupported curve name"); 558 559 this.setNamedCurve(this.curveName); 560 this.setPublicKeyHex(hPub); 561 }; 562 563 /* 564 * Recover a public key from a signature. 565 * 566 * See SEC 1: Elliptic Curve Cryptography, section 4.1.6, "Public 567 * Key Recovery Operation". 568 * 569 * http://www.secg.org/download/aid-780/sec1-v2.pdf 570 */ 571 /* 572 recoverPubKey: function (r, s, hash, i) { 573 // The recovery parameter i has two bits. 574 i = i & 3; 575 576 // The less significant bit specifies whether the y coordinate 577 // of the compressed point is even or not. 578 var isYEven = i & 1; 579 580 // The more significant bit specifies whether we should use the 581 // first or second candidate key. 582 var isSecondKey = i >> 1; 583 584 var n = this.ecparams['n']; 585 var G = this.ecparams['G']; 586 var curve = this.ecparams['curve']; 587 var p = curve.getQ(); 588 var a = curve.getA().toBigInteger(); 589 var b = curve.getB().toBigInteger(); 590 591 // We precalculate (p + 1) / 4 where p is if the field order 592 if (!P_OVER_FOUR) { 593 P_OVER_FOUR = p.add(BigInteger.ONE).divide(BigInteger.valueOf(4)); 594 } 595 596 // 1.1 Compute x 597 var x = isSecondKey ? r.add(n) : r; 598 599 // 1.3 Convert x to point 600 var alpha = x.multiply(x).multiply(x).add(a.multiply(x)).add(b).mod(p); 601 var beta = alpha.modPow(P_OVER_FOUR, p); 602 603 var xorOdd = beta.isEven() ? (i % 2) : ((i+1) % 2); 604 // If beta is even, but y isn't or vice versa, then convert it, 605 // otherwise we're done and y == beta. 606 var y = (beta.isEven() ? !isYEven : isYEven) ? beta : p.subtract(beta); 607 608 // 1.4 Check that nR is at infinity 609 var R = new ECPointFp(curve, 610 curve.fromBigInteger(x), 611 curve.fromBigInteger(y)); 612 R.validate(); 613 614 // 1.5 Compute e from M 615 var e = BigInteger.fromByteArrayUnsigned(hash); 616 var eNeg = BigInteger.ZERO.subtract(e).mod(n); 617 618 // 1.6 Compute Q = r^-1 (sR - eG) 619 var rInv = r.modInverse(n); 620 var Q = implShamirsTrick(R, s, G, eNeg).multiply(rInv); 621 622 Q.validate(); 623 if (!this.verifyRaw(e, r, s, Q)) { 624 throw "Pubkey recovery unsuccessful"; 625 } 626 627 var pubKey = new Bitcoin.ECKey(); 628 pubKey.pub = Q; 629 return pubKey; 630 }, 631 */ 632 633 /* 634 * Calculate pubkey extraction parameter. 635 * 636 * When extracting a pubkey from a signature, we have to 637 * distinguish four different cases. Rather than putting this 638 * burden on the verifier, Bitcoin includes a 2-bit value with the 639 * signature. 640 * 641 * This function simply tries all four cases and returns the value 642 * that resulted in a successful pubkey recovery. 643 */ 644 /* 645 calcPubkeyRecoveryParam: function (address, r, s, hash) { 646 for (var i = 0; i < 4; i++) { 647 try { 648 var pubkey = Bitcoin.ECDSA.recoverPubKey(r, s, hash, i); 649 if (pubkey.getBitcoinAddress().toString() == address) { 650 return i; 651 } 652 } catch (e) {} 653 } 654 throw "Unable to find valid recovery factor"; 655 } 656 */ 657 658 if (params !== undefined) { 659 if (params['curve'] !== undefined) { 660 this.curveName = params['curve']; 661 } 662 } 663 if (this.curveName === undefined) this.curveName = curveName; 664 this.setNamedCurve(this.curveName); 665 if (params !== undefined) { 666 if (params.prv !== undefined) this.setPrivateKeyHex(params.prv); 667 if (params.pub !== undefined) this.setPublicKeyHex(params.pub); 668 } 669 }; 670 671 /** 672 * parse ASN.1 DER encoded ECDSA signature 673 * @name parseSigHex 674 * @memberOf KJUR.crypto.ECDSA 675 * @function 676 * @static 677 * @param {String} sigHex hexadecimal string of ECDSA signature value 678 * @return {Array} associative array of signature field r and s of BigInteger 679 * @since ecdsa-modified 1.0.1 680 * @see {@link KJUR.crypto.ECDSA.parseSigHexInHexRS} 681 * @see {@link ASN1HEX.checkStrictDER} 682 * @throws Error when signature value is malformed. 683 * @example 684 * var ec = new KJUR.crypto.ECDSA({'curve': 'secp256r1'}); 685 * var sig = ec.parseSigHex('30...'); 686 * var biR = sig.r; // BigInteger object for 'r' field of signature. 687 * var biS = sig.s; // BigInteger object for 's' field of signature. 688 */ 689 KJUR.crypto.ECDSA.parseSigHex = function(sigHex) { 690 var p = KJUR.crypto.ECDSA.parseSigHexInHexRS(sigHex); 691 var biR = new BigInteger(p.r, 16); 692 var biS = new BigInteger(p.s, 16); 693 694 return {'r': biR, 's': biS}; 695 }; 696 697 /** 698 * parse ASN.1 DER encoded ECDSA signature 699 * @name parseSigHexInHexRS 700 * @memberOf KJUR.crypto.ECDSA 701 * @function 702 * @static 703 * @param {String} sigHex hexadecimal string of ECDSA signature value 704 * @return {Array} associative array of signature field r and s in hexadecimal 705 * @since ecdsa-modified 1.0.3 706 * @see {@link KJUR.crypto.ECDSA.parseSigHex} 707 * @see {@link ASN1HEX.checkStrictDER} 708 * @throws Error when signature value is malformed. 709 * @example 710 * var ec = new KJUR.crypto.ECDSA({'curve': 'secp256r1'}); 711 * var sig = ec.parseSigHexInHexRS('30...'); 712 * var hR = sig.r; // hexadecimal string for 'r' field of signature. 713 * var hS = sig.s; // hexadecimal string for 's' field of signature. 714 */ 715 KJUR.crypto.ECDSA.parseSigHexInHexRS = function(sigHex) { 716 var _ASN1HEX = ASN1HEX, 717 _getChildIdx = _ASN1HEX.getChildIdx, 718 _getV = _ASN1HEX.getV; 719 720 // 1. strict DER check 721 _ASN1HEX.checkStrictDER(sigHex, 0); 722 723 // 2. ASN.1 Sequence Check 724 if (sigHex.substr(0, 2) != "30") 725 throw new Error("signature is not a ASN.1 sequence"); 726 727 // 2. Items of ASN.1 Sequence Check 728 var a = _getChildIdx(sigHex, 0); 729 if (a.length != 2) 730 throw new Error("signature shall have two elements"); 731 732 // 3. Integer tag check 733 var iTLV1 = a[0]; 734 var iTLV2 = a[1]; 735 736 if (sigHex.substr(iTLV1, 2) != "02") 737 throw new Error("1st item not ASN.1 integer"); 738 if (sigHex.substr(iTLV2, 2) != "02") 739 throw new Error("2nd item not ASN.1 integer"); 740 741 // 4. getting value and least zero check for DER 742 var hR = _getV(sigHex, iTLV1); 743 var hS = _getV(sigHex, iTLV2); 744 745 return {'r': hR, 's': hS}; 746 }; 747 748 /** 749 * convert hexadecimal ASN.1 encoded signature to concatinated signature 750 * @name asn1SigToConcatSig 751 * @memberOf KJUR.crypto.ECDSA 752 * @function 753 * @static 754 * @param {String} asn1Hex hexadecimal string of ASN.1 encoded ECDSA signature value 755 * @return {String} r-s concatinated format of ECDSA signature value 756 * @throws Error when signature length is unsupported 757 * @since ecdsa-modified 1.0.3 758 */ 759 KJUR.crypto.ECDSA.asn1SigToConcatSig = function(asn1Sig) { 760 var pSig = KJUR.crypto.ECDSA.parseSigHexInHexRS(asn1Sig); 761 var hR = pSig.r; 762 var hS = pSig.s; 763 764 // P-521 special case (65-66 bytes are allowed) 765 if (hR.length >= 130 && hR.length <= 134) { 766 if (hR.length % 2 != 0) { 767 throw Error("unknown ECDSA sig r length error"); 768 } 769 if (hS.length % 2 != 0) { 770 throw Error("unknown ECDSA sig s length error"); 771 } 772 if (hR.substr(0, 2) == "00") hR = hR.substr(2); 773 if (hS.substr(0, 2) == "00") hS = hS.substr(2); 774 775 // make sure they have the same length 776 var length = Math.max(hR.length, hS.length); 777 hR = ("000000" + hR).slice(- length); 778 hS = ("000000" + hS).slice(- length); 779 780 return hR + hS; 781 } 782 783 // R and S length is assumed multiple of 128bit(32chars in hex). 784 // If leading is "00" and modulo of length is 2(chars) then 785 // leading "00" is for two's complement and will be removed. 786 if (hR.substr(0, 2) == "00" && (hR.length % 32) == 2) 787 hR = hR.substr(2); 788 789 if (hS.substr(0, 2) == "00" && (hS.length % 32) == 2) 790 hS = hS.substr(2); 791 792 // R and S length is assumed multiple of 128bit(32chars in hex). 793 // If missing two chars then it will be padded by "00". 794 if ((hR.length % 32) == 30) hR = "00" + hR; 795 if ((hS.length % 32) == 30) hS = "00" + hS; 796 797 // If R and S length is not still multiple of 128bit(32 chars), 798 // then error 799 if (hR.length % 32 != 0) 800 throw Error("unknown ECDSA sig r length error"); 801 if (hS.length % 32 != 0) 802 throw Error("unknown ECDSA sig s length error"); 803 804 return hR + hS; 805 }; 806 807 /** 808 * convert hexadecimal concatinated signature to ASN.1 encoded signature 809 * @name concatSigToASN1Sig 810 * @memberOf KJUR.crypto.ECDSA 811 * @function 812 * @static 813 * @param {String} concatSig r-s concatinated format of ECDSA signature value 814 * @return {String} hexadecimal string of ASN.1 encoded ECDSA signature value 815 * @throws Error when signature length is unsupported 816 * @since ecdsa-modified 1.0.3 817 */ 818 KJUR.crypto.ECDSA.concatSigToASN1Sig = function(concatSig) { 819 if (concatSig.length % 4 != 0) { 820 throw Error("unknown ECDSA concatinated r-s sig length error"); 821 } 822 823 var hR = concatSig.substr(0, concatSig.length / 2); 824 var hS = concatSig.substr(concatSig.length / 2); 825 return KJUR.crypto.ECDSA.hexRSSigToASN1Sig(hR, hS); 826 }; 827 828 /** 829 * convert hexadecimal R and S value of signature to ASN.1 encoded signature 830 * @name hexRSSigToASN1Sig 831 * @memberOf KJUR.crypto.ECDSA 832 * @function 833 * @static 834 * @param {String} hR hexadecimal string of R field of ECDSA signature value 835 * @param {String} hS hexadecimal string of S field of ECDSA signature value 836 * @return {String} hexadecimal string of ASN.1 encoded ECDSA signature value 837 * @since ecdsa-modified 1.0.3 838 */ 839 KJUR.crypto.ECDSA.hexRSSigToASN1Sig = function(hR, hS) { 840 var biR = new BigInteger(hR, 16); 841 var biS = new BigInteger(hS, 16); 842 return KJUR.crypto.ECDSA.biRSSigToASN1Sig(biR, biS); 843 }; 844 845 /** 846 * convert R and S BigInteger object of signature to ASN.1 encoded signature 847 * @name biRSSigToASN1Sig 848 * @memberOf KJUR.crypto.ECDSA 849 * @function 850 * @static 851 * @param {BigInteger} biR BigInteger object of R field of ECDSA signature value 852 * @param {BigInteger} biS BIgInteger object of S field of ECDSA signature value 853 * @return {String} hexadecimal string of ASN.1 encoded ECDSA signature value 854 * @since ecdsa-modified 1.0.3 855 */ 856 KJUR.crypto.ECDSA.biRSSigToASN1Sig = function(biR, biS) { 857 var _KJUR_asn1 = KJUR.asn1; 858 var derR = new _KJUR_asn1.DERInteger({'bigint': biR}); 859 var derS = new _KJUR_asn1.DERInteger({'bigint': biS}); 860 var derSeq = new _KJUR_asn1.DERSequence({'array': [derR, derS]}); 861 return derSeq.tohex(); 862 }; 863 864 /** 865 * static method to get normalized EC curve name from curve name or hexadecimal OID value 866 * @name getName 867 * @memberOf KJUR.crypto.ECDSA 868 * @function 869 * @static 870 * @param {String} s curve name (ex. P-256) or hexadecimal OID value (ex. 2a86...) 871 * @return {String} normalized EC curve name (ex. secp256r1) 872 * @since jsrsasign 7.1.0 ecdsa-modified 1.1.0 873 * @description 874 * This static method returns normalized EC curve name 875 * which is supported in jsrsasign 876 * from curve name or hexadecimal OID value. 877 * When curve is not supported in jsrsasign, this method returns null. 878 * Normalized name will be "secp*" in jsrsasign. 879 * @example 880 * KJUR.crypto.ECDSA.getName("2b8104000a") → "secp256k1" 881 * KJUR.crypto.ECDSA.getName("NIST P-256") → "secp256r1" 882 * KJUR.crypto.ECDSA.getName("P-521") → undefined // not supported 883 */ 884 KJUR.crypto.ECDSA.getName = function(s) { 885 if (s === "2b8104001f") return "secp192k1"; // 1.3.132.0.31 886 if (s === "2a8648ce3d030107") return "secp256r1"; // 1.2.840.10045.3.1.7 887 if (s === "2b8104000a") return "secp256k1"; // 1.3.132.0.10 888 if (s === "2b81040021") return "secp224r1"; // 1.3.132.0.33 889 if (s === "2b81040022") return "secp384r1"; // 1.3.132.0.34 890 if (s === "2b81040023") return "secp521r1"; // 1.3.132.0.35 891 if ("|secp256r1|NIST P-256|P-256|prime256v1|".indexOf(s) !== -1) return "secp256r1"; 892 if ("|secp256k1|".indexOf(s) !== -1) return "secp256k1"; 893 if ("|secp224r1|NIST P-224|P-224|".indexOf(s) !== -1) return "secp224r1"; 894 if ("|secp384r1|NIST P-384|P-384|".indexOf(s) !== -1) return "secp384r1"; 895 if ("|secp521r1|NIST P-521|P-521|".indexOf(s) !== -1) return "secp521r1"; 896 return null; 897 }; 898 899 900 901