Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/provider/DSA.java
38830 views
/*1* Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.provider;2627import java.io.*;28import java.util.*;29import java.math.BigInteger;30import java.nio.ByteBuffer;3132import java.security.*;33import java.security.SecureRandom;34import java.security.interfaces.*;35import java.security.spec.*;3637import sun.security.util.Debug;38import sun.security.util.DerValue;39import sun.security.util.DerInputStream;40import sun.security.util.DerOutputStream;41import sun.security.x509.AlgIdDSA;42import sun.security.jca.JCAUtil;4344/**45* The Digital Signature Standard (using the Digital Signature46* Algorithm), as described in fips186-3 of the National Instute of47* Standards and Technology (NIST), using SHA digest algorithms48* from FIPS180-3.49*50* This file contains both the signature implementation for the51* commonly used SHA1withDSA (DSS), SHA224withDSA, SHA256withDSA,52* as well as RawDSA, used by TLS among others. RawDSA expects53* the 20 byte SHA-1 digest as input via update rather than the54* original data like other signature implementations.55*56* @author Benjamin Renaud57*58* @since 1.159*60* @see DSAPublicKey61* @see DSAPrivateKey62*/63abstract class DSA extends SignatureSpi {6465/* Are we debugging? */66private static final boolean debug = false;6768/* The number of bits used in exponent blinding */69private static final int BLINDING_BITS = 7;7071/* The constant component of the exponent blinding value */72private static final BigInteger BLINDING_CONSTANT =73BigInteger.valueOf(1 << BLINDING_BITS);7475/* The parameter object */76private DSAParams params;7778/* algorithm parameters */79private BigInteger presetP, presetQ, presetG;8081/* The public key, if any */82private BigInteger presetY;8384/* The private key, if any */85private BigInteger presetX;8687/* The RNG used to output a seed for generating k */88private SecureRandom signingRandom;8990/* The message digest object used */91private final MessageDigest md;9293/**94* Construct a blank DSA object. It must be95* initialized before being usable for signing or verifying.96*/97DSA(MessageDigest md) {98super();99this.md = md;100}101102private static void checkKey(DSAParams params, int digestLen, String mdAlgo)103throws InvalidKeyException {104// FIPS186-3 states in sec4.2 that a hash function which provides105// a lower security strength than the (L, N) pair ordinarily should106// not be used.107int valueN = params.getQ().bitLength();108if (valueN > digestLen) {109throw new InvalidKeyException("The security strength of " +110mdAlgo + " digest algorithm is not sufficient for this key size");111}112}113114/**115* Initialize the DSA object with a DSA private key.116*117* @param privateKey the DSA private key118*119* @exception InvalidKeyException if the key is not a valid DSA private120* key.121*/122protected void engineInitSign(PrivateKey privateKey)123throws InvalidKeyException {124if (!(privateKey instanceof java.security.interfaces.DSAPrivateKey)) {125throw new InvalidKeyException("not a DSA private key: " +126privateKey);127}128129java.security.interfaces.DSAPrivateKey priv =130(java.security.interfaces.DSAPrivateKey)privateKey;131132// check for algorithm specific constraints before doing initialization133DSAParams params = priv.getParams();134if (params == null) {135throw new InvalidKeyException("DSA private key lacks parameters");136}137138// check key size against hash output size for signing139// skip this check for verification to minimize impact on existing apps140if (md.getAlgorithm() != "NullDigest20") {141checkKey(params, md.getDigestLength()*8, md.getAlgorithm());142}143144this.params = params;145this.presetX = priv.getX();146this.presetY = null;147this.presetP = params.getP();148this.presetQ = params.getQ();149this.presetG = params.getG();150this.md.reset();151}152/**153* Initialize the DSA object with a DSA public key.154*155* @param publicKey the DSA public key.156*157* @exception InvalidKeyException if the key is not a valid DSA public158* key.159*/160protected void engineInitVerify(PublicKey publicKey)161throws InvalidKeyException {162if (!(publicKey instanceof java.security.interfaces.DSAPublicKey)) {163throw new InvalidKeyException("not a DSA public key: " +164publicKey);165}166java.security.interfaces.DSAPublicKey pub =167(java.security.interfaces.DSAPublicKey)publicKey;168169// check for algorithm specific constraints before doing initialization170DSAParams params = pub.getParams();171if (params == null) {172throw new InvalidKeyException("DSA public key lacks parameters");173}174this.params = params;175this.presetY = pub.getY();176this.presetX = null;177this.presetP = params.getP();178this.presetQ = params.getQ();179this.presetG = params.getG();180this.md.reset();181}182183/**184* Update a byte to be signed or verified.185*/186protected void engineUpdate(byte b) {187md.update(b);188}189190/**191* Update an array of bytes to be signed or verified.192*/193protected void engineUpdate(byte[] data, int off, int len) {194md.update(data, off, len);195}196197protected void engineUpdate(ByteBuffer b) {198md.update(b);199}200201202/**203* Sign all the data thus far updated. The signature is formatted204* according to the Canonical Encoding Rules, returned as a DER205* sequence of Integer, r and s.206*207* @return a signature block formatted according to the Canonical208* Encoding Rules.209*210* @exception SignatureException if the signature object was not211* properly initialized, or if another exception occurs.212*213* @see sun.security.DSA#engineUpdate214* @see sun.security.DSA#engineVerify215*/216protected byte[] engineSign() throws SignatureException {217BigInteger k = generateK(presetQ);218BigInteger r = generateR(presetP, presetQ, presetG, k);219BigInteger s = generateS(presetX, presetQ, r, k);220221try {222DerOutputStream outseq = new DerOutputStream(100);223outseq.putInteger(r);224outseq.putInteger(s);225DerValue result = new DerValue(DerValue.tag_Sequence,226outseq.toByteArray());227228return result.toByteArray();229230} catch (IOException e) {231throw new SignatureException("error encoding signature");232}233}234235/**236* Verify all the data thus far updated.237*238* @param signature the alledged signature, encoded using the239* Canonical Encoding Rules, as a sequence of integers, r and s.240*241* @exception SignatureException if the signature object was not242* properly initialized, or if another exception occurs.243*244* @see sun.security.DSA#engineUpdate245* @see sun.security.DSA#engineSign246*/247protected boolean engineVerify(byte[] signature)248throws SignatureException {249return engineVerify(signature, 0, signature.length);250}251252/**253* Verify all the data thus far updated.254*255* @param signature the alledged signature, encoded using the256* Canonical Encoding Rules, as a sequence of integers, r and s.257*258* @param offset the offset to start from in the array of bytes.259*260* @param length the number of bytes to use, starting at offset.261*262* @exception SignatureException if the signature object was not263* properly initialized, or if another exception occurs.264*265* @see sun.security.DSA#engineUpdate266* @see sun.security.DSA#engineSign267*/268protected boolean engineVerify(byte[] signature, int offset, int length)269throws SignatureException {270271BigInteger r = null;272BigInteger s = null;273// first decode the signature.274try {275// Enforce strict DER checking for signatures276DerInputStream in =277new DerInputStream(signature, offset, length, false);278DerValue[] values = in.getSequence(2);279280// check number of components in the read sequence281// and trailing data282if ((values.length != 2) || (in.available() != 0)) {283throw new IOException("Invalid encoding for signature");284}285r = values[0].getBigInteger();286s = values[1].getBigInteger();287} catch (IOException e) {288throw new SignatureException("Invalid encoding for signature", e);289}290291// some implementations do not correctly encode values in the ASN.1292// 2's complement format. force r and s to be positive in order to293// to validate those signatures294if (r.signum() < 0) {295r = new BigInteger(1, r.toByteArray());296}297if (s.signum() < 0) {298s = new BigInteger(1, s.toByteArray());299}300301if ((r.compareTo(presetQ) == -1) && (s.compareTo(presetQ) == -1)) {302BigInteger w = generateW(presetP, presetQ, presetG, s);303BigInteger v = generateV(presetY, presetP, presetQ, presetG, w, r);304return v.equals(r);305} else {306throw new SignatureException("invalid signature: out of range values");307}308}309310@Deprecated311protected void engineSetParameter(String key, Object param) {312throw new InvalidParameterException("No parameter accepted");313}314315@Override316protected void engineSetParameter(AlgorithmParameterSpec params)317throws InvalidAlgorithmParameterException {318if (params != null) {319throw new InvalidAlgorithmParameterException("No parameter accepted");320}321}322323@Deprecated324protected Object engineGetParameter(String key) {325return null;326}327328@Override329protected AlgorithmParameters engineGetParameters() {330return null;331}332333334private BigInteger generateR(BigInteger p, BigInteger q, BigInteger g,335BigInteger k) {336337// exponent blinding to hide information from timing channel338SecureRandom random = getSigningRandom();339// start with a random blinding component340BigInteger blindingValue = new BigInteger(BLINDING_BITS, random);341// add the fixed blinding component342blindingValue = blindingValue.add(BLINDING_CONSTANT);343// replace k with a blinded value that is congruent (mod q)344k = k.add(q.multiply(blindingValue));345346BigInteger temp = g.modPow(k, p);347return temp.mod(q);348}349350private BigInteger generateS(BigInteger x, BigInteger q,351BigInteger r, BigInteger k) throws SignatureException {352353byte[] s2;354try {355s2 = md.digest();356} catch (RuntimeException re) {357// Only for RawDSA due to its 20-byte length restriction358throw new SignatureException(re.getMessage());359}360// get the leftmost min(N, outLen) bits of the digest value361int nBytes = q.bitLength()/8;362if (nBytes < s2.length) {363s2 = Arrays.copyOfRange(s2, 0, nBytes);364}365BigInteger z = new BigInteger(1, s2);366BigInteger k1 = k.modInverse(q);367368return x.multiply(r).add(z).multiply(k1).mod(q);369}370371private BigInteger generateW(BigInteger p, BigInteger q,372BigInteger g, BigInteger s) {373return s.modInverse(q);374}375376private BigInteger generateV(BigInteger y, BigInteger p,377BigInteger q, BigInteger g, BigInteger w, BigInteger r)378throws SignatureException {379380byte[] s2;381try {382s2 = md.digest();383} catch (RuntimeException re) {384// Only for RawDSA due to its 20-byte length restriction385throw new SignatureException(re.getMessage());386}387// get the leftmost min(N, outLen) bits of the digest value388int nBytes = q.bitLength()/8;389if (nBytes < s2.length) {390s2 = Arrays.copyOfRange(s2, 0, nBytes);391}392BigInteger z = new BigInteger(1, s2);393394BigInteger u1 = z.multiply(w).mod(q);395BigInteger u2 = (r.multiply(w)).mod(q);396397BigInteger t1 = g.modPow(u1,p);398BigInteger t2 = y.modPow(u2,p);399BigInteger t3 = t1.multiply(t2);400BigInteger t5 = t3.mod(p);401return t5.mod(q);402}403404protected BigInteger generateK(BigInteger q) {405// Implementation defined in FIPS 186-4 AppendixB.2.1.406SecureRandom random = getSigningRandom();407byte[] kValue = new byte[(q.bitLength() + 7)/8 + 8];408409random.nextBytes(kValue);410return new BigInteger(1, kValue).mod(411q.subtract(BigInteger.ONE)).add(BigInteger.ONE);412}413414// Use the application-specified SecureRandom Object if provided.415// Otherwise, use our default SecureRandom Object.416protected SecureRandom getSigningRandom() {417if (signingRandom == null) {418if (appRandom != null) {419signingRandom = appRandom;420} else {421signingRandom = JCAUtil.getSecureRandom();422}423}424return signingRandom;425}426427/**428* Return a human readable rendition of the engine.429*/430public String toString() {431String printable = "DSA Signature";432if (presetP != null && presetQ != null && presetG != null) {433printable += "\n\tp: " + Debug.toHexString(presetP);434printable += "\n\tq: " + Debug.toHexString(presetQ);435printable += "\n\tg: " + Debug.toHexString(presetG);436} else {437printable += "\n\t P, Q or G not initialized.";438}439if (presetY != null) {440printable += "\n\ty: " + Debug.toHexString(presetY);441}442if (presetY == null && presetX == null) {443printable += "\n\tUNINIIALIZED";444}445return printable;446}447448/**449* Standard SHA224withDSA implementation as defined in FIPS186-3.450*/451public static final class SHA224withDSA extends DSA {452public SHA224withDSA() throws NoSuchAlgorithmException {453super(MessageDigest.getInstance("SHA-224"));454}455}456457/**458* Standard SHA256withDSA implementation as defined in FIPS186-3.459*/460public static final class SHA256withDSA extends DSA {461public SHA256withDSA() throws NoSuchAlgorithmException {462super(MessageDigest.getInstance("SHA-256"));463}464}465466/**467* Standard SHA1withDSA implementation.468*/469public static final class SHA1withDSA extends DSA {470public SHA1withDSA() throws NoSuchAlgorithmException {471super(MessageDigest.getInstance("SHA-1"));472}473}474475/**476* RawDSA implementation.477*478* RawDSA requires the data to be exactly 20 bytes long. If it is479* not, a SignatureException is thrown when sign()/verify() is called480* per JCA spec.481*/482public static final class RawDSA extends DSA {483// Internal special-purpose MessageDigest impl for RawDSA484// Only override whatever methods used485// NOTE: no clone support486public static final class NullDigest20 extends MessageDigest {487// 20 byte digest buffer488private final byte[] digestBuffer = new byte[20];489490// offset into the buffer; use Integer.MAX_VALUE to indicate491// out-of-bound condition492private int ofs = 0;493494protected NullDigest20() {495super("NullDigest20");496}497protected void engineUpdate(byte input) {498if (ofs == digestBuffer.length) {499ofs = Integer.MAX_VALUE;500} else {501digestBuffer[ofs++] = input;502}503}504protected void engineUpdate(byte[] input, int offset, int len) {505if (len > (digestBuffer.length - ofs)) {506ofs = Integer.MAX_VALUE;507} else {508System.arraycopy(input, offset, digestBuffer, ofs, len);509ofs += len;510}511}512protected final void engineUpdate(ByteBuffer input) {513int inputLen = input.remaining();514if (inputLen > (digestBuffer.length - ofs)) {515ofs = Integer.MAX_VALUE;516} else {517input.get(digestBuffer, ofs, inputLen);518ofs += inputLen;519}520}521protected byte[] engineDigest() throws RuntimeException {522if (ofs != digestBuffer.length) {523throw new RuntimeException524("Data for RawDSA must be exactly 20 bytes long");525}526reset();527return digestBuffer;528}529protected int engineDigest(byte[] buf, int offset, int len)530throws DigestException {531if (ofs != digestBuffer.length) {532throw new DigestException533("Data for RawDSA must be exactly 20 bytes long");534}535if (len < digestBuffer.length) {536throw new DigestException537("Output buffer too small; must be at least 20 bytes");538}539System.arraycopy(digestBuffer, 0, buf, offset, digestBuffer.length);540reset();541return digestBuffer.length;542}543544protected void engineReset() {545ofs = 0;546}547protected final int engineGetDigestLength() {548return digestBuffer.length;549}550}551552public RawDSA() throws NoSuchAlgorithmException {553super(new NullDigest20());554}555}556}557558559