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 0) +++ modules/security/src/main/java/common/org/apache/harmony/security/provider/crypto/CryptoProvider.java (revision 0) @@ -0,0 +1,64 @@ +/* + * 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; + } + } + ); + } +} Index: modules/security/src/main/java/common/org/apache/harmony/security/provider/crypto/SHA1_MessageDigestImpl.java =================================================================== --- modules/security/src/main/java/common/org/apache/harmony/security/provider/crypto/SHA1_MessageDigestImpl.java (revision 0) +++ modules/security/src/main/java/common/org/apache/harmony/security/provider/crypto/SHA1_MessageDigestImpl.java (revision 0) @@ -0,0 +1,326 @@ +/* + * 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.MessageDigestSpi; +import java.security.DigestException; + +import java.nio.ByteBuffer; +import java.nio.BufferUnderflowException; + +import java.util.Arrays; + +import org.apache.harmony.security.provider.crypto.SHA1_Data; +import org.apache.harmony.security.provider.crypto.SHA1Impl; + + +/** + * This class extends the MessageDigestSpi class implementing all its abstract methods; + * it overrides the "Object clone()" and "int engineGetDigestLength()" methods.
+ * The class implements the Cloneable interface. + */ + + +public class SHA1_MessageDigestImpl extends MessageDigestSpi + implements Cloneable, SHA1_Data { + + + private int buffer[]; // buffer has the following structure: + // - 0-16 - frame for accumulating a message + // - 17-79 - for SHA1Impl methods + // - 80 - unused + // - 81 - to store length of the message + // - 82-86 - frame for current message digest + + private byte oneByte[]; // one byte buffer needed to use in engineUpdate(byte) + // having buffer as private field is just optimization + + private int messageLength; // total length of bytes supplied by user + + + /** + * The constructor creates needed buffers and sets the engine at initial state + */ + public SHA1_MessageDigestImpl() { + + // BYTES_OFFSET +6 is minimal length required by methods in SHA1Impl + buffer = new int[BYTES_OFFSET +6]; + + oneByte = new byte[1]; + + engineReset(); + } + + + /** + * The method performs final actions and invokes the "computeHash(int[])" method. + * In case if there is no enough words in current frame + * after processing its data, extra frame is prepared and + * the "computeHash(int[])" method is invoked second time.
+ * + * After processing, the method resets engine's state + * + * @param + * digest - byte array + * @param + * offset - offset in digest + */ + private void processDigest(byte[] digest, int offset) { + + int i, j; // implementation variables + int lastWord; // + + long nBits = messageLength <<3 ; // length has to be calculated before padding + + engineUpdate( (byte) 0x80 ); // beginning byte in padding + + i = 0; // i contains number of beginning word for following loop + + lastWord = (buffer[BYTES_OFFSET] + 3)>>2 ; // computing of # of full words by shifting + // # of bytes + + // possible cases: + // + // - buffer[BYTES_OFFSET] == 0 - buffer frame is empty, + // padding byte was 64th in previous frame + // current frame should contain only message's length + // + // - lastWord < 14 - two last, these are 14 & 15, words in 16 word frame are free; + // no extra frame needed + // - lastWord = 14 - only one last, namely 15-th, word in frame doesn't contain bytes; + // extra frame is needed + // - lastWord > 14 - last word in frame is not full; + // extra frame is needed + + if ( buffer[BYTES_OFFSET] != 0 ) { + + if ( lastWord < 15 ) { + i = lastWord; + } else { + if ( lastWord == 15 ) { + buffer[15] = 0; // last word in frame is set to "0" + } + SHA1Impl.computeHash(buffer); + i = 0; + } + } + Arrays.fill(buffer, i, 14, 0); + + buffer[14] = (int)( nBits >>>32 ); + buffer[15] = (int)( nBits & 0xFFFFFFFF ); + SHA1Impl.computeHash(buffer); + + // converting 5-word frame into 20 bytes + j = offset; + for ( i = HASH_OFFSET; i < HASH_OFFSET +5; i++ ) { + int k = buffer[i]; + digest[j ] = (byte) ( k >>>24 ); // getting first byte from left + digest[j+1] = (byte) ( k >>>16 ); // getting second byte from left + digest[j+2] = (byte) ( k >>> 8 ); // getting third byte from left + digest[j+3] = (byte) ( k ); // getting fourth byte from left + j += 4; + } + + engineReset(); + } + + // methods specified in java.security.MessageDigestSpi + + /** + * Returns a "deep" copy of this SHA1MDImpl object.
+ * + * The method overrides "clone()" in class Object.
+ * + * @return + * a clone of this object + */ + public Object clone() throws CloneNotSupportedException { + + SHA1_MessageDigestImpl cloneObj = (SHA1_MessageDigestImpl) super.clone(); + + cloneObj.buffer = ( int[])buffer.clone(); + cloneObj.oneByte = (byte[])oneByte.clone(); + + return cloneObj; + } + + + /** + * Computes a message digest value.
+ * + * The method resets the engine.
+ * + * The method overrides "engineDigest()" in class MessageDigestSpi.
+ * + * @return + * byte array containing message digest value + */ + protected byte[] engineDigest() { + + byte[] hash = new byte[DIGEST_LENGTH]; + + processDigest(hash, 0); + return hash; + } + + + /** + * Computes message digest value. + * Upon return, the value is stored in "buf" buffer beginning "offset" byte.
+ * + * The method resets the engine.
+ * + * The method overrides "engineDigest(byte[],int,int) in class MessageDigestSpi. + * + * @param + * buf byte array to store a message digest returned + * @param + * offset a position in the array for first byte of the message digest + * @param + * len number of bytes within buffer allotted for the message digest; + * as this implementation doesn't provide partial digests, + * len should be >= 20, DigestException is thrown otherwise + * @return + * the length of the message digest stored in the "buf" buffer; + * in this implementation the length=20 + * + * @throws IllegalArgumentException + * if null is passed to the "buf" argument
+ * if offset + len > buf.length
+ * if offset > buf.length or len > buf.length + * + * @throws DigestException + * if len < 20 + * + * @throws ArrayIndexOutOfBoundsException + * if offset < 0 + */ + protected int engineDigest(byte[] buf, int offset, int len) throws DigestException { + + if ( buf == null ) { + throw new IllegalArgumentException("null is passed to 'buf' parameter"); + } + if ( offset > buf.length || len > buf.length || (len + offset) > buf.length ) { + throw new IllegalArgumentException( + "buf.lendth doesn't fit supplied offset and len"); + } + if ( len < DIGEST_LENGTH ) { + throw new DigestException(" len < digest's length (which is 20 bytes) "); + } + if ( offset < 0 ) { + throw new ArrayIndexOutOfBoundsException("negative offset: " + offset); + } + + processDigest(buf, offset); + + return DIGEST_LENGTH; + } + + + /** + * Returns a message digest length.
+ * + * The method overrides "engineGetDigestLength()" in class MessageDigestSpi.
+ * + * @return + * total length of current message digest as an int value + */ + protected int engineGetDigestLength() { + return DIGEST_LENGTH; + } + + + /** + * Resets the engine.
+ * + * The method overrides "engineReset()" in class MessageDigestSpi.
+ */ + protected void engineReset() { + + messageLength = 0; + + buffer[BYTES_OFFSET] = 0; + buffer[HASH_OFFSET ] = H0; + buffer[HASH_OFFSET +1] = H1; + buffer[HASH_OFFSET +2] = H2; + buffer[HASH_OFFSET +3] = H3; + buffer[HASH_OFFSET +4] = H4; + } + + + /** + * Supplements a byte to current message.
+ * + * The method overrides "engineUpdate(byte)" in class MessageDigestSpi.
+ * + * @param + * input byte to add to current message + */ + protected void engineUpdate(byte input) { + + oneByte[0] = input; + SHA1Impl.updateHash( buffer, oneByte, 0, 0 ); + messageLength++; + } + + + /** + * Updates current message.
+ * + * The method overrides "engineUpdate(byte[],intint)" in class MessageDigestSpi.
+ * + * The method silently returns if "len" <= 0. + * + * @param + * input a byte array + * @param + * offset a number of first byte in the "input" array to use for updating + * @param + * len a number of bytes to use + * + * @throws NullPointerException + * if null is passed to the "buf" argument + * + * @throws IllegalArgumentException + * if offset > buf.length or len > buf.length or + * (len + offset) > buf.length + * @throws ArrayIndexOutOfBoundsException + * offset < 0 + */ + protected void engineUpdate(byte[] input, int offset, int len) { + + if ( input == null ) { + throw new IllegalArgumentException("no byte[] passed to 'input' parameter"); + } + if ( len <= 0 ) { + return; + } + if ( offset < 0 ) { + throw new ArrayIndexOutOfBoundsException("offset < 0 : " + offset); + } + if ( offset > input.length || len > input.length || (len + offset) > input.length ) { + throw new IllegalArgumentException( + "input.lendth doesn't fit supplied offset and len"); + } + + SHA1Impl.updateHash(buffer, input, offset, offset + len -1 ); + messageLength += len; + } + +}