1 /* dsa-2.1.2.js (c) 2016-2020 Kenji Urushimma | kjur.github.io/jsrsasign/license 2 */ 3 /* 4 * dsa.js - new DSA class 5 * 6 * Copyright (c) 2016-2020 Kenji Urushima (kenji.urushima@gmail.com) 7 * 8 * This software is licensed under the terms of the MIT License. 9 * https://kjur.github.io/jsrsasign/license 10 * 11 * The above copyright and license notice shall be 12 * included in all copies or substantial portions of the Software. 13 */ 14 15 /** 16 * @fileOverview 17 * @name dsa-2.0.js 18 * @author Kenji Urushima kenji.urushima@gmail.com 19 * @version jsrsasign 8.0.21 dsa 2.1.2 (2020-Jul-24) 20 * @since jsrsasign 7.0.0 21 * @license <a href="https://kjur.github.io/jsrsasign/license/">MIT License</a> 22 */ 23 24 if (typeof KJUR == "undefined" || !KJUR) KJUR = {}; 25 if (typeof KJUR.crypto == "undefined" || !KJUR.crypto) KJUR.crypto = {}; 26 27 /** 28 * class for DSA signing and verification 29 * @name KJUR.crypto.DSA 30 * @class class for DSA signing and verifcation 31 * @since jsrsasign 7.0.0 dsa 2.0.0 32 * @description 33 * <p> 34 * CAUTION: Most of the case, you don't need to use this class. 35 * Please use {@link KJUR.crypto.Signature} class instead. 36 * </p> 37 * <p> 38 * NOTE: Until jsrsasign 6.2.3, DSA class have used codes from openpgpjs library 1.0.0 39 * licenced under LGPL licence. To avoid license issue dsa-2.0.js was re-written with 40 * my own codes in jsrsasign 7.0.0. 41 * Some random number generators used in dsa-2.0.js was newly defined 42 * in KJUR.crypto.Util class. Now all of LGPL codes are removed. 43 * </p> 44 */ 45 KJUR.crypto.DSA = function() { 46 var _ASN1HEX = ASN1HEX, 47 _getVbyList = _ASN1HEX.getVbyList, 48 _getVbyListEx = _ASN1HEX.getVbyListEx, 49 _isASN1HEX = _ASN1HEX.isASN1HEX, 50 _BigInteger = BigInteger; 51 this.p = null; 52 this.q = null; 53 this.g = null; 54 this.y = null; 55 this.x = null; 56 this.type = "DSA"; 57 this.isPrivate = false; 58 this.isPublic = false; 59 60 //=========================== 61 // PUBLIC METHODS 62 //=========================== 63 64 /** 65 * set DSA private key by key parameters of BigInteger object 66 * @name setPrivate 67 * @memberOf KJUR.crypto.DSA# 68 * @function 69 * @param {BigInteger} p prime P parameter 70 * @param {BigInteger} q sub prime Q parameter 71 * @param {BigInteger} g base G parameter 72 * @param {BigInteger} y public key Y or null 73 * @param {BigInteger} x private key X 74 * @since jsrsasign 7.0.0 dsa 2.0.0 75 */ 76 this.setPrivate = function(p, q, g, y, x) { 77 this.isPrivate = true; 78 this.p = p; 79 this.q = q; 80 this.g = g; 81 this.y = y; 82 this.x = x; 83 }; 84 85 /** 86 * set DSA private key by key parameters of hexadecimal string 87 * @name setPrivateHex 88 * @memberOf KJUR.crypto.DSA# 89 * @function 90 * @param {String} hP prime P parameter 91 * @param {String} hQ sub prime Q parameter 92 * @param {String} hG base G parameter 93 * @param {String} hY public key Y or null 94 * @param {String} hX private key X 95 * @since jsrsasign 7.1.0 dsa 2.1.0 96 */ 97 this.setPrivateHex = function(hP, hQ, hG, hY, hX) { 98 var biP, biQ, biG, biY, biX; 99 biP = new BigInteger(hP, 16); 100 biQ = new BigInteger(hQ, 16); 101 biG = new BigInteger(hG, 16); 102 if (typeof hY === "string" && hY.length > 1) { 103 biY = new BigInteger(hY, 16); 104 } else { 105 biY = null; 106 } 107 biX = new BigInteger(hX, 16); 108 this.setPrivate(biP, biQ, biG, biY, biX); 109 }; 110 111 /** 112 * set DSA public key by key parameters of BigInteger object 113 * @name setPublic 114 * @memberOf KJUR.crypto.DSA# 115 * @function 116 * @param {BigInteger} p prime P parameter 117 * @param {BigInteger} q sub prime Q parameter 118 * @param {BigInteger} g base G parameter 119 * @param {BigInteger} y public key Y 120 * @since jsrsasign 7.0.0 dsa 2.0.0 121 */ 122 this.setPublic = function(p, q, g, y) { 123 this.isPublic = true; 124 this.p = p; 125 this.q = q; 126 this.g = g; 127 this.y = y; 128 this.x = null; 129 }; 130 131 /** 132 * set DSA public key by key parameters of hexadecimal string 133 * @name setPublicHex 134 * @memberOf KJUR.crypto.DSA# 135 * @function 136 * @param {String} hP prime P parameter 137 * @param {String} hQ sub prime Q parameter 138 * @param {String} hG base G parameter 139 * @param {String} hY public key Y 140 * @since jsrsasign 7.1.0 dsa 2.1.0 141 */ 142 this.setPublicHex = function(hP, hQ, hG, hY) { 143 var biP, biQ, biG, biY; 144 biP = new BigInteger(hP, 16); 145 biQ = new BigInteger(hQ, 16); 146 biG = new BigInteger(hG, 16); 147 biY = new BigInteger(hY, 16); 148 this.setPublic(biP, biQ, biG, biY); 149 }; 150 151 /** 152 * sign to hashed message by this DSA private key object 153 * @name signWithMessageHash 154 * @memberOf KJUR.crypto.DSA# 155 * @function 156 * @param {String} sHashHex hexadecimal string of hashed message 157 * @return {String} hexadecimal string of ASN.1 encoded DSA signature value 158 * @since jsrsasign 7.0.0 dsa 2.0.0 159 */ 160 this.signWithMessageHash = function(sHashHex) { 161 var p = this.p; // parameter p 162 var q = this.q; // parameter q 163 var g = this.g; // parameter g 164 var y = this.y; // public key (p q g y) 165 var x = this.x; // private key 166 167 // NIST FIPS 186-4 4.5 DSA Per-Message Secret Number (p18) 168 // 1. get random k where 0 < k < q 169 var k = KJUR.crypto.Util.getRandomBigIntegerMinToMax(BigInteger.ONE.add(BigInteger.ONE), 170 q.subtract(BigInteger.ONE)); 171 172 // NIST FIPS 186-4 4.6 DSA Signature Generation (p19) 173 // 2. get z where the left most min(N, outlen) bits of Hash(M) 174 var hZ = sHashHex.substr(0, q.bitLength() / 4); 175 var z = new BigInteger(hZ, 16); 176 177 // 3. get r where (g^k mod p) mod q, r != 0 178 var r = (g.modPow(k,p)).mod(q); 179 180 // 4. get s where k^-1 (z + xr) mod q, s != 0 181 var s = (k.modInverse(q).multiply(z.add(x.multiply(r)))).mod(q); 182 183 // 5. signature (r, s) 184 var result = KJUR.asn1.ASN1Util.jsonToASN1HEX({ 185 "seq": [{"int": {"bigint": r}}, {"int": {"bigint": s}}] 186 }); 187 return result; 188 }; 189 190 /** 191 * verify signature by this DSA public key object 192 * @name verifyWithMessageHash 193 * @memberOf KJUR.crypto.DSA# 194 * @function 195 * @param {String} sHashHex hexadecimal string of hashed message 196 * @param {String} hSigVal hexadecimal string of ASN.1 encoded DSA signature value 197 * @return {Boolean} true if the signature is valid otherwise false. 198 * @since jsrsasign 7.0.0 dsa 2.0.0 199 */ 200 this.verifyWithMessageHash = function(sHashHex, hSigVal) { 201 var p = this.p; // parameter p 202 var q = this.q; // parameter q 203 var g = this.g; // parameter g 204 var y = this.y; // public key (p q g y) 205 206 // 1. parse ASN.1 signature (r, s) 207 var rs = this.parseASN1Signature(hSigVal); 208 var r = rs[0]; 209 var s = rs[1]; 210 211 // NIST FIPS 186-4 4.6 DSA Signature Generation (p19) 212 // 2. get z where the left most min(N, outlen) bits of Hash(M) 213 var hZ = sHashHex.substr(0, q.bitLength() / 4); 214 var z = new BigInteger(hZ, 16); 215 216 // NIST FIPS 186-4 4.7 DSA Signature Validation (p19) 217 // 3.1. 0 < r < q 218 if (BigInteger.ZERO.compareTo(r) > 0 || r.compareTo(q) > 0) 219 throw "invalid DSA signature"; 220 221 // 3.2. 0 < s < q 222 if (BigInteger.ZERO.compareTo(s) >= 0 || s.compareTo(q) > 0) 223 throw "invalid DSA signature"; 224 225 // 4. get w where w = s^-1 mod q 226 var w = s.modInverse(q); 227 228 // 5. get u1 where u1 = z w mod q 229 var u1 = z.multiply(w).mod(q); 230 231 // 6. get u2 where u2 = r w mod q 232 var u2 = r.multiply(w).mod(q); 233 234 // 7. get v where v = ((g^u1 y^u2) mod p) mod q 235 var v = g.modPow(u1,p).multiply(y.modPow(u2,p)).mod(p).mod(q); 236 237 // 8. signature is valid when v == r 238 return v.compareTo(r) == 0; 239 }; 240 241 /** 242 * parse hexadecimal ASN.1 DSA signature value 243 * @name parseASN1Signature 244 * @memberOf KJUR.crypto.DSA# 245 * @function 246 * @param {String} hSigVal hexadecimal string of ASN.1 encoded DSA signature value 247 * @return {Array} array [r, s] of DSA signature value. Both r and s are BigInteger. 248 * @since jsrsasign 7.0.0 dsa 2.0.0 249 */ 250 this.parseASN1Signature = function(hSigVal) { 251 try { 252 var r = new _BigInteger(_getVbyListEx(hSigVal, 0, [0], "02"), 16); 253 var s = new _BigInteger(_getVbyListEx(hSigVal, 0, [1], "02"), 16); 254 return [r, s]; 255 } catch (ex) { 256 throw new Error("malformed ASN.1 DSA signature"); 257 } 258 } 259 260 /** 261 * read an ASN.1 hexadecimal string of PKCS#1/5 plain DSA private key<br/> 262 * @name readPKCS5PrvKeyHex 263 * @memberOf KJUR.crypto.DSA# 264 * @function 265 * @param {String} h hexadecimal string of PKCS#1/5 DSA private key 266 * @since jsrsasign 7.1.0 dsa 2.1.0 267 */ 268 this.readPKCS5PrvKeyHex = function(h) { 269 var hP, hQ, hG, hY, hX; 270 271 if (_isASN1HEX(h) === false) 272 throw new Error("not ASN.1 hex string"); 273 274 try { 275 hP = _getVbyListEx(h, 0, [1], "02"); 276 hQ = _getVbyListEx(h, 0, [2], "02"); 277 hG = _getVbyListEx(h, 0, [3], "02"); 278 hY = _getVbyListEx(h, 0, [4], "02"); 279 hX = _getVbyListEx(h, 0, [5], "02"); 280 } catch(ex) { 281 //console.log("EXCEPTION:" + ex); 282 throw new Error("malformed PKCS#1/5 plain DSA private key"); 283 } 284 285 this.setPrivateHex(hP, hQ, hG, hY, hX); 286 }; 287 288 /** 289 * read an ASN.1 hexadecimal string of PKCS#8 plain DSA private key<br/> 290 * @name readPKCS8PrvKeyHex 291 * @memberOf KJUR.crypto.DSA# 292 * @function 293 * @param {String} h hexadecimal string of PKCS#8 DSA private key 294 * @since jsrsasign 7.1.0 dsa 2.1.0 295 */ 296 this.readPKCS8PrvKeyHex = function(h) { 297 var hP, hQ, hG, hX; 298 299 if (_isASN1HEX(h) === false) 300 throw new Error("not ASN.1 hex string"); 301 302 try { 303 hP = _getVbyListEx(h, 0, [1, 1, 0], "02"); 304 hQ = _getVbyListEx(h, 0, [1, 1, 1], "02"); 305 hG = _getVbyListEx(h, 0, [1, 1, 2], "02"); 306 hX = _getVbyListEx(h, 0, [2, 0], "02"); 307 } catch(ex) { 308 //console.log("EXCEPTION:" + ex); 309 throw new Error("malformed PKCS#8 plain DSA private key"); 310 } 311 312 this.setPrivateHex(hP, hQ, hG, null, hX); 313 }; 314 315 /** 316 * read an ASN.1 hexadecimal string of PKCS#8 plain DSA private key<br/> 317 * @name readPKCS8PubKeyHex 318 * @memberOf KJUR.crypto.DSA# 319 * @function 320 * @param {String} h hexadecimal string of PKCS#8 DSA private key 321 * @since jsrsasign 7.1.0 dsa 2.1.0 322 */ 323 this.readPKCS8PubKeyHex = function(h) { 324 var hP, hQ, hG, hY; 325 326 if (_isASN1HEX(h) === false) 327 throw new Error("not ASN.1 hex string"); 328 329 try { 330 hP = _getVbyListEx(h, 0, [0, 1, 0], "02"); 331 hQ = _getVbyListEx(h, 0, [0, 1, 1], "02"); 332 hG = _getVbyListEx(h, 0, [0, 1, 2], "02"); 333 hY = _getVbyListEx(h, 0, [1, 0], "02"); 334 } catch(ex) { 335 //console.log("EXCEPTION:" + ex); 336 throw new Error("malformed PKCS#8 DSA public key"); 337 } 338 339 this.setPublicHex(hP, hQ, hG, hY); 340 }; 341 342 /** 343 * read an ASN.1 hexadecimal string of X.509 DSA public key certificate<br/> 344 * @name readCertPubKeyHex 345 * @memberOf KJUR.crypto.DSA# 346 * @function 347 * @param {String} h hexadecimal string of X.509 DSA public key certificate 348 * @param {Integer} nthPKI (DEPRECATED to use) 349 * @since jsrsasign 7.1.0 dsa 2.1.0 350 * @description 351 * This method reads a hexadecimal string of X.509 DSA public key certificate 352 * and set public key parameter internally. 353 * @example 354 * dsa = new KJUR.crypto.DSA(); 355 * dsa.readCertPubKeyHex("30..."); 356 */ 357 this.readCertPubKeyHex = function(h, nthPKI) { 358 //if (nthPKI !== 5) nthPKI = 6; 359 var hP, hQ, hG, hY; 360 361 if (_isASN1HEX(h) === false) 362 throw new Error("not ASN.1 hex string"); 363 364 try { 365 hP = _getVbyListEx(h, 0, [0, 5, 0, 1, 0], "02"); 366 hQ = _getVbyListEx(h, 0, [0, 5, 0, 1, 1], "02"); 367 hG = _getVbyListEx(h, 0, [0, 5, 0, 1, 2], "02"); 368 hY = _getVbyListEx(h, 0, [0, 5, 1, 0], "02"); 369 } catch(ex) { 370 //console.log("EXCEPTION:" + ex); 371 throw new Error("malformed X.509 certificate DSA public key"); 372 } 373 374 this.setPublicHex(hP, hQ, hG, hY); 375 }; 376 } 377