package org.bouncycastle.jcajce.provider.asymmetric.dsa; import java.io.IOException; import java.math.BigInteger; import java.security.InvalidKeyException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.SecureRandom; import java.security.SignatureException; import java.security.SignatureSpi; import java.security.spec.AlgorithmParameterSpec; import org.bouncycastle.asn1.ASN1Encoding; import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.x509.X509ObjectIdentifiers; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.DSA; import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.digests.NullDigest; // Android-added: Check DSA keys when generated import org.bouncycastle.crypto.params.DSAKeyParameters; import org.bouncycastle.crypto.params.DSAParameters; import org.bouncycastle.crypto.params.ParametersWithRandom; // Android-removed: Unsupported algorithm // import org.bouncycastle.crypto.signers.HMacDSAKCalculator; // Android-changed: Use Android digests // import org.bouncycastle.crypto.util.DigestFactory; import org.bouncycastle.crypto.digests.AndroidDigestFactory; import org.bouncycastle.util.Arrays; public class DSASigner extends SignatureSpi implements PKCSObjectIdentifiers, X509ObjectIdentifiers { private Digest digest; private DSA signer; private SecureRandom random; protected DSASigner( Digest digest, DSA signer) { this.digest = digest; this.signer = signer; } protected void engineInitVerify( PublicKey publicKey) throws InvalidKeyException { CipherParameters param = DSAUtil.generatePublicKeyParameter(publicKey); digest.reset(); signer.init(false, param); } protected void engineInitSign( PrivateKey privateKey, SecureRandom random) throws InvalidKeyException { this.random = random; engineInitSign(privateKey); } protected void engineInitSign( PrivateKey privateKey) throws InvalidKeyException { CipherParameters param = DSAUtil.generatePrivateKeyParameter(privateKey); // Android-added: Check DSA keys when generated DSAParameters dsaParam = ((DSAKeyParameters) param).getParameters(); checkKey(dsaParam); if (random != null) { param = new ParametersWithRandom(param, random); } digest.reset(); signer.init(true, param); } protected void engineUpdate( byte b) throws SignatureException { digest.update(b); } protected void engineUpdate( byte[] b, int off, int len) throws SignatureException { digest.update(b, off, len); } protected byte[] engineSign() throws SignatureException { byte[] hash = new byte[digest.getDigestSize()]; digest.doFinal(hash, 0); try { BigInteger[] sig = signer.generateSignature(hash); return derEncode(sig[0], sig[1]); } catch (Exception e) { throw new SignatureException(e.toString()); } } protected boolean engineVerify( byte[] sigBytes) throws SignatureException { byte[] hash = new byte[digest.getDigestSize()]; digest.doFinal(hash, 0); BigInteger[] sig; try { sig = derDecode(sigBytes); } catch (Exception e) { throw new SignatureException("error decoding signature bytes."); } return signer.verifySignature(hash, sig[0], sig[1]); } protected void engineSetParameter( AlgorithmParameterSpec params) { throw new UnsupportedOperationException("engineSetParameter unsupported"); } // BEGIN Android-added: Check DSA keys when generated protected void checkKey(DSAParameters params) throws InvalidKeyException { int valueL = params.getP().bitLength(); int valueN = params.getQ().bitLength(); int digestSize = digest.getDigestSize(); // The checks are consistent with DSAParametersGenerator's init method. if ((valueL < 1024 || valueL > 3072) || valueL % 1024 != 0) { throw new InvalidKeyException("valueL values must be between 1024 and 3072 and a multiple of 1024"); } else if (valueL == 1024 && valueN != 160) { throw new InvalidKeyException("valueN must be 160 for valueL = 1024"); } else if (valueL == 2048 && (valueN != 224 && valueN != 256)) { throw new InvalidKeyException("valueN must be 224 or 256 for valueL = 2048"); } else if (valueL == 3072 && valueN != 256) { throw new InvalidKeyException("valueN must be 256 for valueL = 3072"); } if (!(digest instanceof NullDigest) && valueN > digestSize * 8) { throw new InvalidKeyException("Key is too strong for this signature algorithm"); } } // END Android-added: Check DSA keys when generated /** * @deprecated replaced with */ protected void engineSetParameter( String param, Object value) { throw new UnsupportedOperationException("engineSetParameter unsupported"); } /** * @deprecated */ protected Object engineGetParameter( String param) { throw new UnsupportedOperationException("engineSetParameter unsupported"); } private byte[] derEncode( BigInteger r, BigInteger s) throws IOException { ASN1Integer[] rs = new ASN1Integer[]{ new ASN1Integer(r), new ASN1Integer(s) }; return new DERSequence(rs).getEncoded(ASN1Encoding.DER); } private BigInteger[] derDecode( byte[] encoding) throws IOException { ASN1Sequence s = (ASN1Sequence)ASN1Primitive.fromByteArray(encoding); if (s.size() != 2) { throw new IOException("malformed signature"); } if (!Arrays.areEqual(encoding, s.getEncoded(ASN1Encoding.DER))) { throw new IOException("malformed signature"); } return new BigInteger[]{ ((ASN1Integer)s.getObjectAt(0)).getValue(), ((ASN1Integer)s.getObjectAt(1)).getValue() }; } static public class stdDSA extends DSASigner { public stdDSA() { // Android-changed: Use Android digests // super(DigestFactory.createSHA1(), new org.bouncycastle.crypto.signers.DSASigner()); super(AndroidDigestFactory.getSHA1(), new org.bouncycastle.crypto.signers.DSASigner()); } } // BEGIN Android-removed: Unsupported algorithm /* static public class detDSA extends DSASigner { public detDSA() { super(DigestFactory.createSHA1(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA1()))); } } */ // END Android-removed: Unsupported algorithm static public class dsa224 extends DSASigner { public dsa224() { // Android-changed: Use Android digests // super(DigestFactory.createSHA224(), new org.bouncycastle.crypto.signers.DSASigner()); super(AndroidDigestFactory.getSHA224(), new org.bouncycastle.crypto.signers.DSASigner()); } } // BEGIN Android-removed: Unsupported algorithm /* static public class detDSA224 extends DSASigner { public detDSA224() { super(DigestFactory.createSHA224(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA224()))); } } */ // END Android-removed: Unsupported algorithm static public class dsa256 extends DSASigner { public dsa256() { // Android-changed: Use Android digests // super(DigestFactory.createSHA256(), new org.bouncycastle.crypto.signers.DSASigner()); super(AndroidDigestFactory.getSHA256(), new org.bouncycastle.crypto.signers.DSASigner()); } } // BEGIN Android-removed: Unsupported algorithms /* static public class detDSA256 extends DSASigner { public detDSA256() { super(DigestFactory.createSHA256(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA256()))); } } static public class dsa384 extends DSASigner { public dsa384() { super(DigestFactory.createSHA384(), new org.bouncycastle.crypto.signers.DSASigner()); } } static public class detDSA384 extends DSASigner { public detDSA384() { super(DigestFactory.createSHA384(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA384()))); } } static public class dsa512 extends DSASigner { public dsa512() { super(DigestFactory.createSHA512(), new org.bouncycastle.crypto.signers.DSASigner()); } } static public class detDSA512 extends DSASigner { public detDSA512() { super(DigestFactory.createSHA512(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA512()))); } } static public class dsaSha3_224 extends DSASigner { public dsaSha3_224() { super(DigestFactory.createSHA3_224(), new org.bouncycastle.crypto.signers.DSASigner()); } } static public class detDSASha3_224 extends DSASigner { public detDSASha3_224() { super(DigestFactory.createSHA3_224(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_224()))); } } static public class dsaSha3_256 extends DSASigner { public dsaSha3_256() { super(DigestFactory.createSHA3_256(), new org.bouncycastle.crypto.signers.DSASigner()); } } static public class detDSASha3_256 extends DSASigner { public detDSASha3_256() { super(DigestFactory.createSHA3_256(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_256()))); } } static public class dsaSha3_384 extends DSASigner { public dsaSha3_384() { super(DigestFactory.createSHA3_384(), new org.bouncycastle.crypto.signers.DSASigner()); } } static public class detDSASha3_384 extends DSASigner { public detDSASha3_384() { super(DigestFactory.createSHA3_384(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_384()))); } } static public class dsaSha3_512 extends DSASigner { public dsaSha3_512() { super(DigestFactory.createSHA3_512(), new org.bouncycastle.crypto.signers.DSASigner()); } } static public class detDSASha3_512 extends DSASigner { public detDSASha3_512() { super(DigestFactory.createSHA3_512(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_512()))); } } */ // END Android-removed: Unsupported algorithms static public class noneDSA extends DSASigner { public noneDSA() { super(new NullDigest(), new org.bouncycastle.crypto.signers.DSASigner()); } } }