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