Index: modules/security/src/main/java/common/org/apache/harmony/security/provider/crypto/SHA1withDSA_SignatureImpl.java =================================================================== --- modules/security/src/main/java/common/org/apache/harmony/security/provider/crypto/SHA1withDSA_SignatureImpl.java (revision 0) +++ modules/security/src/main/java/common/org/apache/harmony/security/provider/crypto/SHA1withDSA_SignatureImpl.java (revision 0) @@ -0,0 +1,442 @@ +/* + * Copyright 2006 The Apache Software Software Foundation or its licensors, as applicable. + * + * Licensed 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.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Signature; + +import java.security.InvalidKeyException; +import java.security.InvalidParameterException; +import java.security.NoSuchAlgorithmException; +import java.security.SignatureException; + +import java.security.interfaces.DSAParams; +import java.security.interfaces.DSAKey; +import java.security.interfaces.DSAPrivateKey; +import java.security.interfaces.DSAPublicKey; + +import java.security.MessageDigest; + + +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("null argument"); + } + 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, g, x; + + int n; + + if ( privateKey == null || !(privateKey instanceof DSAPrivateKey) ) { + throw new InvalidKeyException("'privateKey' is not instanceof DSAPrivateKey"); + } + + params = ((DSAPrivateKey)privateKey).getParams(); + p = params.getP(); + q = params.getQ(); + g = params.getG(); + 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 is not positive or >= 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, g, y; + + int n1; + + if ( publicKey == null || !(publicKey instanceof DSAPublicKey) ) { + throw new InvalidKeyException("'publicKey' is not instanceof DSAPublicKey"); + } + + DSAParams params = ((DSAPublicKey)publicKey).getParams(); + p = params.getP(); + q = params.getQ(); + g = params.getG(); + 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 is not positive"); + } + + dsaKey = (DSAKey)publicKey; + + msgDigest.reset(); + } + + + /* + * Deprecated method. + * + * @throws + * InvalidParameterException + */ + protected void engineSetParameter(String param, Object value) + throws InvalidParameterException { + if ( param == null ) { + throw new NullPointerException("null is passed for 'param'"); + } + 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 digest[]; + byte rBytes[], sBytes[], 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 containg 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("null passed for 'sigBytes'"); + } + + 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 alotted 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); + } + +} Index: modules/security/src/main/java/common/org/apache/harmony/security/provider/crypto/CryptoProvider.java =================================================================== --- modules/security/src/main/java/common/org/apache/harmony/security/provider/crypto/CryptoProvider.java (revision 427433) +++ modules/security/src/main/java/common/org/apache/harmony/security/provider/crypto/CryptoProvider.java (working copy) @@ -1,64 +1,92 @@ -/* - * Copyright 2006 The Apache Software Software Foundation or its licensors, as applicable. - * - * Licensed 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.security.Provider; -import java.security.AccessController; - - -/** - * Implementation of Provider for MessageDigest - * using a Secure Hash Algorithm, SHA-1; - * see SECURE HASH STANDARD, FIPS PUB 180-2 - * (http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf)
- *
- * The implementation supports "SHA-1" algorithms described in - * JavaTM Cryptography Architecture, API Specification & Reference - */ - - -public final class CryptoProvider extends Provider { - - - /** - * Creates a Provider and puts parameters - */ - public CryptoProvider() { - - super("Crypto", 1.0, "HARMONY CryptoProvider"); - - // names of classes implementing services - final String MD_NAME = - "org.apache.harmony.security.provider.crypto.SHA1_MessageDigestImpl"; - - AccessController.doPrivileged( - new java.security.PrivilegedAction() { - public Object run() { - - put("MessageDigest.SHA-1", MD_NAME); - put("MessageDigest.SHA-1 ImplementedIn", "Software"); - put("Alg.Alias.MessageDigest.SHA1", "SHA-1"); - put("Alg.Alias.MessageDigest.SHA", "SHA-1"); - - return null; - } - } - ); - } -} +/* + * Copyright 2006 The Apache Software Software Foundation or its licensors, as applicable. + * + * Licensed 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.security.Provider; +import java.security.AccessController; + +import org.apache.harmony.security.provider.crypto.RandomBitsSupplier; + + +/** + * Implementation of Provider for SecureRandom, MessageDigest and Signature + * using a Secure Hash Algorithm, SHA-1; + * see SECURE HASH STANDARD, FIPS PUB 180-1 (http://www.itl.nist.gov/fipspubs/fip180-1.htm)
+ *
+ * The implementation supports "SHA1PRNG", "SHA-1" and "SHA1withDSA" algorithms described in + * JavaTM Cryptography Architecture, API Specification & Reference + */ + + +public final class CryptoProvider extends Provider { + + + /** + * Creates a Provider and puts parameters + */ + public CryptoProvider() { + + super("Crypto", 1.0, "HARMONY (SHA1 digest; SecureRandom; SHA1withDSA signature)"); + + // names of classes implementing services + final String MD_NAME = + "org.apache.harmony.security.provider.crypto.SHA1_MessageDigestImpl"; + final String SR_NAME = + "org.apache.harmony.security.provider.crypto.SHA1PRNG_SecureRandomImpl"; + + final String SIGN_NAME = + "org.apache.harmony.security.provider.crypto.SHA1withDSA_SignatureImpl"; + + final String SIGN_ALIAS = "SHA1withDSA"; + + AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Object run() { + + put("MessageDigest.SHA-1", MD_NAME); + put("MessageDigest.SHA-1 ImplementedIn", "Software"); + put("Alg.Alias.MessageDigest.SHA1", "SHA-1"); + put("Alg.Alias.MessageDigest.SHA", "SHA-1"); + + if ( RandomBitsSupplier.isServiceAvailable() ) { + put("SecureRandom.SHA1PRNG", SR_NAME); + put("SecureRandom.SHA1PRNG ImplementedIn", "Software"); + } + + put("Signature.SHA1withDSA", SIGN_NAME); + put("Signature.SHA1withDSA ImplementedIn", "Software"); + put("Alg.Alias.Signature.SHAwithDSA", SIGN_ALIAS); + put("Alg.Alias.Signature.DSAwithSHA1", SIGN_ALIAS); + put("Alg.Alias.Signature.SHA1/DSA", SIGN_ALIAS); + put("Alg.Alias.Signature.SHA/DSA", SIGN_ALIAS); + put("Alg.Alias.Signature.SHA-1/DSA", SIGN_ALIAS); + put("Alg.Alias.Signature.DSA", SIGN_ALIAS); + put("Alg.Alias.Signature.DSS", SIGN_ALIAS); + + put("Alg.Alias.Signature.OID.1.2.840.10040.4.3", SIGN_ALIAS); + put("Alg.Alias.Signature.1.2.840.10040.4.3", SIGN_ALIAS); + put("Alg.Alias.Signature.1.3.14.3.2.13", SIGN_ALIAS); + put("Alg.Alias.Signature.1.3.14.3.2.27", SIGN_ALIAS); + + return null; + } + } + ); + } +}