| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.harmony.security.provider.crypto; |
| |
| import java.math.BigInteger; |
| import java.security.InvalidKeyException; |
| import java.security.InvalidParameterException; |
| import java.security.MessageDigest; |
| import java.security.NoSuchAlgorithmException; |
| import java.security.PrivateKey; |
| import java.security.PublicKey; |
| import java.security.SecureRandom; |
| import java.security.Signature; |
| import java.security.SignatureException; |
| import java.security.interfaces.DSAKey; |
| import java.security.interfaces.DSAParams; |
| import java.security.interfaces.DSAPrivateKey; |
| import java.security.interfaces.DSAPublicKey; |
| |
| public class SHA1withDSA_SignatureImpl extends Signature { |
| |
| private MessageDigest msgDigest; |
| |
| private DSAKey dsaKey; |
| |
| /** |
| * The solo constructor. |
| */ |
| public SHA1withDSA_SignatureImpl() throws NoSuchAlgorithmException { |
| |
| super("SHA1withDSA"); |
| |
| msgDigest = MessageDigest.getInstance("SHA1"); |
| } |
| |
| /** |
| * Deprecated method. |
| * |
| * @return |
| * null |
| */ |
| protected Object engineGetParameter(String param) |
| throws InvalidParameterException { |
| if (param == null) { |
| throw new NullPointerException("param == null"); |
| } |
| return null; |
| } |
| |
| /** |
| * Initializes this signature object with PrivateKey object |
| * passed as argument to the method. |
| * |
| * @params |
| * privateKey DSAPrivateKey object |
| * @throws |
| * InvalidKeyException if privateKey is not DSAPrivateKey object |
| */ |
| protected void engineInitSign(PrivateKey privateKey) |
| throws InvalidKeyException { |
| |
| DSAParams params; |
| |
| // parameters and private key |
| BigInteger p, q, x; |
| |
| int n; |
| |
| if (privateKey == null || !(privateKey instanceof DSAPrivateKey)) { |
| throw new InvalidKeyException(); |
| } |
| |
| params = ((DSAPrivateKey) privateKey).getParams(); |
| p = params.getP(); |
| q = params.getQ(); |
| x = ((DSAPrivateKey) privateKey).getX(); |
| |
| // checks described in DSA standard |
| n = p.bitLength(); |
| if (p.compareTo(BigInteger.valueOf(1)) != 1 || n < 512 || n > 1024 || (n & 077) != 0) { |
| throw new InvalidKeyException("bad p"); |
| } |
| if (q.signum() != 1 && q.bitLength() != 160) { |
| throw new InvalidKeyException("bad q"); |
| } |
| if (x.signum() != 1 || x.compareTo(q) != -1) { |
| throw new InvalidKeyException("x <= 0 || x >= q"); |
| } |
| |
| dsaKey = (DSAKey) privateKey; |
| |
| msgDigest.reset(); |
| } |
| |
| /** |
| * Initializes this signature object with PublicKey object |
| * passed as argument to the method. |
| * |
| * @params |
| * publicKey DSAPublicKey object |
| * @throws |
| * InvalidKeyException if publicKey is not DSAPublicKey object |
| */ |
| protected void engineInitVerify(PublicKey publicKey) |
| throws InvalidKeyException { |
| |
| // parameters and public key |
| BigInteger p, q, y; |
| |
| int n1; |
| |
| if (publicKey == null || !(publicKey instanceof DSAPublicKey)) { |
| throw new InvalidKeyException("publicKey is not an instance of DSAPublicKey"); |
| } |
| |
| DSAParams params = ((DSAPublicKey) publicKey).getParams(); |
| p = params.getP(); |
| q = params.getQ(); |
| y = ((DSAPublicKey) publicKey).getY(); |
| |
| // checks described in DSA standard |
| n1 = p.bitLength(); |
| if (p.compareTo(BigInteger.valueOf(1)) != 1 || n1 < 512 || n1 > 1024 || (n1 & 077) != 0) { |
| throw new InvalidKeyException("bad p"); |
| } |
| if (q.signum() != 1 || q.bitLength() != 160) { |
| throw new InvalidKeyException("bad q"); |
| } |
| if (y.signum() != 1) { |
| throw new InvalidKeyException("y <= 0"); |
| } |
| |
| dsaKey = (DSAKey) publicKey; |
| |
| msgDigest.reset(); |
| } |
| |
| /* |
| * Deprecated method. |
| * |
| * @throws |
| * InvalidParameterException |
| */ |
| protected void engineSetParameter(String param, Object value) throws InvalidParameterException { |
| if (param == null) { |
| throw new NullPointerException("param == null"); |
| } |
| throw new InvalidParameterException("invalid parameter for this engine"); |
| } |
| |
| /** |
| * Returns signature bytes as byte array containing |
| * ASN1 representation for two BigInteger objects |
| * which is SEQUENCE of two INTEGERS. |
| * Length of sequence varies from less than 46 to 48. |
| * |
| * Resets object to the state it was in |
| * when previous call to either "initSign" method was called. |
| * |
| * @return |
| * byte array containing signature in ASN1 representation |
| * @throws |
| * SignatureException if object's state is not SIGN or |
| * signature algorithm cannot process data |
| */ |
| |
| protected byte[] engineSign() throws SignatureException { |
| |
| // names of below BigIntegers are the same as they are defined in DSA standard |
| BigInteger r = null; |
| BigInteger s = null; |
| BigInteger k = null; |
| |
| // parameters and private key |
| BigInteger p, q, g, x; |
| |
| // BigInteger for message digest |
| BigInteger digestBI; |
| |
| // various byte array being used in computing signature |
| byte[] randomBytes; |
| byte[] rBytes; |
| byte[] sBytes; |
| byte[] signature; |
| |
| int n, n1, n2; |
| |
| DSAParams params; |
| |
| if (appRandom == null) { |
| appRandom = new SecureRandom(); |
| } |
| |
| params = dsaKey.getParams(); |
| p = params.getP(); |
| q = params.getQ(); |
| g = params.getG(); |
| x = ((DSAPrivateKey) dsaKey).getX(); |
| |
| // forming signature according algorithm described in chapter 5 of DSA standard |
| |
| digestBI = new BigInteger(1, msgDigest.digest()); |
| |
| randomBytes = new byte[20]; |
| |
| for (;;) { |
| |
| appRandom.nextBytes(randomBytes); |
| |
| k = new BigInteger(1, randomBytes); |
| if (k.compareTo(q) != -1) { |
| continue; |
| } |
| r = g.modPow(k, p).mod(q); |
| if (r.signum() == 0) { |
| continue; |
| } |
| |
| s = k.modInverse(q).multiply(digestBI.add(x.multiply(r)).mod(q)) |
| .mod(q); |
| |
| if (s.signum() != 0) { |
| break; |
| } |
| } |
| |
| // forming signature's ASN1 representation which is SEQUENCE of two INTEGERs |
| // |
| rBytes = r.toByteArray(); |
| n1 = rBytes.length; |
| if ((rBytes[0] & 0x80) != 0) { |
| n1++; |
| } |
| sBytes = s.toByteArray(); |
| n2 = sBytes.length; |
| if ((sBytes[0] & 0x80) != 0) { |
| n2++; |
| } |
| |
| signature = new byte[6 + n1 + n2]; // 48 is max. possible length of signature |
| signature[0] = (byte) 0x30; // ASN1 SEQUENCE tag |
| signature[1] = (byte) (4 + n1 + n2); // total length of two INTEGERs |
| signature[2] = (byte) 0x02; // ASN1 INTEGER tag |
| signature[3] = (byte) n1; // length of r |
| signature[4 + n1] = (byte) 0x02; // ASN1 INTEGER tag |
| signature[5 + n1] = (byte) n2; // length of s |
| |
| if (n1 == rBytes.length) { |
| n = 4; |
| } else { |
| n = 5; |
| } |
| System.arraycopy(rBytes, 0, signature, n, rBytes.length); |
| |
| if (n2 == sBytes.length) { |
| n = 6 + n1; |
| } else { |
| n = 7 + n1; |
| } |
| System.arraycopy(sBytes, 0, signature, n, sBytes.length); |
| |
| return signature; |
| } |
| |
| /** |
| * Updates data to sign or to verify. |
| * |
| * @params |
| * b byte to update |
| * @throws |
| * SignatureException if object was not initialized for signing or verifying |
| */ |
| protected void engineUpdate(byte b) throws SignatureException { |
| |
| msgDigest.update(b); |
| } |
| |
| /** |
| * Updates data to sign or to verify. |
| * |
| * @params |
| * b byte array containing bytes to update |
| * @params |
| * off offset in byte array to start from |
| * @params |
| * len number of bytes to use for updating |
| * @throws |
| * SignatureException if object was not initialized for signing or verifying |
| */ |
| protected void engineUpdate(byte[] b, int off, int len) |
| throws SignatureException { |
| |
| msgDigest.update(b, off, len); |
| } |
| |
| private boolean checkSignature(byte[] sigBytes, int offset, int length) |
| throws SignatureException { |
| |
| // names of below BigIntegers are the same as they are defined in DSA standard |
| BigInteger r, s, w; |
| BigInteger u1, u2, v; |
| |
| // parameters and public key |
| BigInteger p, q, g, y; |
| |
| DSAParams params; |
| |
| int n1, n2; |
| |
| byte[] bytes; |
| byte[] digest; |
| |
| // checking up on signature's ASN1 |
| try { |
| byte dummy; |
| n1 = sigBytes[offset + 3]; |
| n2 = sigBytes[offset + n1 + 5]; |
| |
| if (sigBytes[offset + 0] != 0x30 || sigBytes[offset + 2] != 2 |
| || sigBytes[offset + n1 + 4] != 2 |
| || sigBytes[offset + 1] != (n1 + n2 + 4) || n1 > 21 |
| || n2 > 21 |
| || (length != 0 && (sigBytes[offset + 1] + 2) > length)) { |
| throw new SignatureException("signature bytes have invalid encoding"); |
| } |
| |
| dummy = sigBytes[5 + n1 + n2]; // to check length of sigBytes |
| } catch (ArrayIndexOutOfBoundsException e) { |
| throw new SignatureException("bad argument: byte[] is too small"); |
| } |
| |
| digest = msgDigest.digest(); |
| |
| bytes = new byte[n1]; |
| System.arraycopy(sigBytes, offset + 4, bytes, 0, n1); |
| r = new BigInteger(bytes); |
| |
| bytes = new byte[n2]; |
| System.arraycopy(sigBytes, offset + 6 + n1, bytes, 0, n2); |
| s = new BigInteger(bytes); |
| |
| params = dsaKey.getParams(); |
| p = params.getP(); |
| q = params.getQ(); |
| g = params.getG(); |
| y = ((DSAPublicKey) dsaKey).getY(); |
| |
| // forming signature according algorithm described in chapter 6 of DSA standard |
| |
| if (r.signum() != 1 || r.compareTo(q) != -1 || s.signum() != 1 |
| || s.compareTo(q) != -1) { |
| return false; |
| } |
| |
| w = s.modInverse(q); |
| |
| u1 = (new BigInteger(1, digest)).multiply(w).mod(q); |
| u2 = r.multiply(w).mod(q); |
| |
| v = g.modPow(u1, p).multiply(y.modPow(u2, p)).mod(p).mod(q); |
| |
| if (v.compareTo(r) != 0) { |
| return false; |
| } |
| return true; |
| } |
| |
| /** |
| * Verifies the signature bytes. |
| * |
| * @params |
| * sigBytes byte array with signature bytes to verify. |
| * @return |
| * true if signature bytes were verified, false otherwise |
| * @throws |
| * SignatureException if object's state is not VERIFY or |
| * signature format is not ASN1 representation or |
| * signature algorithm cannot process data |
| */ |
| protected boolean engineVerify(byte[] sigBytes) throws SignatureException { |
| if (sigBytes == null) { |
| throw new NullPointerException("sigBytes == null"); |
| } |
| |
| return checkSignature(sigBytes, 0, 0); |
| } |
| |
| /** |
| * Verifies the signature bytes. |
| * |
| * @params |
| * sigBytes byte array with signature bytes to verify. |
| * @params |
| * offset index in sigBytes to start from |
| * @params |
| * length number of bytes allotted for signature |
| * @return |
| * true if signature bytes were verified, false otherwise |
| * @throws |
| * SignatureException if object's state is not VERIFY or |
| * signature format is not ASN1 representation or |
| * signature algorithm cannot process data |
| */ |
| protected boolean engineVerify(byte[] sigBytes, int offset, int length) |
| throws SignatureException { |
| return checkSignature(sigBytes, offset, length); |
| } |
| } |