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