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