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