FileDocCategorySizeDatePackage
SHAOutputStream.javaAPI DocAndroid 1.5 API15669Wed May 06 22:41:04 BST 2009org.apache.harmony.luni.util

SHAOutputStream

public class SHAOutputStream extends OutputStream implements Cloneable
This class implements the Secure Hash Algorithm, SHA-1. The specification can be found at http://csrc.ncsl.nist.gov/fips/fip180-1.txt

Fields Summary
private static final int
K0_19
private static final int
K20_39
private static final int
K40_59
private static final int
K60_79
private static final int
H0
private static final int
H1
private static final int
H2
private static final int
H3
private static final int
H4
private static final int
HConstantsSize
private static final int
HashSizeInBytes
private static final int
BlockSizeInBytes
private static final int
WArraySize
private int[]
HConstants
private int[]
WArray
private byte[]
MArray
private long
bytesProcessed
private int
bytesToProcess
private byte[]
oneByte
Constructors Summary
public SHAOutputStream()
Constructs a new SHAOutputStream.


             
      
        super();
        initialize();
        reset();
    
public SHAOutputStream(byte[] state)
Constructs a new MD5OutputStream with the given initial state.

param
state The initial state of the output stream. This is what will be returned by getHash() if write() is never called.
throws
IllegalArgumentException if state.length is less than 16.

        this();

        if (state.length < HashSizeInBytes) {
            throw new IllegalArgumentException();
        }

        for (int i = 0; i < 4; i++) {
            HConstants[i] = 0;
            for (int j = 0; j < 4; j++) {
                HConstants[i] += (state[4 * i + j] & 0xFF) << 8 * (3 - j);
            }
        }
    
Methods Summary
public java.lang.Objectclone()
Returns a new instance of the same class as the receiver, whose slots have been filled in with the values in the slots of the receiver.

Classes which wish to support cloning must specify that they implement the Cloneable interface, since the native implementation checks for this.

return
a complete copy of this object
throws
CloneNotSupportedException if the component does not implement the interface Cloneable

        // Calling super takes care of primitive type slots
        SHAOutputStream result = (SHAOutputStream) super.clone();
        result.HConstants = this.HConstants.clone();
        result.WArray = this.WArray.clone();
        result.MArray = this.MArray.clone();
        result.oneByte = this.oneByte.clone();
        return result;
    
private voidcopyToInternalBuffer(byte[] buffer, int off, int len)
Copies a byte array into the receiver's internal buffer, making the adjustments as necessary and keeping the receiver in a consistent state.

param
buffer byte array representation of the bytes
param
off offset into the source buffer where to start the copying
param
len how many bytes in the source byte array to copy

        int index;
        index = off;
        for (int i = bytesToProcess; i < bytesToProcess + len; i++) {
            MArray[i] = buffer[index];
            index++;
        }
        bytesToProcess = bytesToProcess + len;
    
public int[]getHash()
Returns an int array (length = 5) with the SHA value of the bytes written to the receiver.

return
The 5 ints that form the SHA value of the bytes written to the receiver

        this.padBuffer();
        this.processBuffer();
        int[] result = HConstants.clone();
        // After the user asks for the hash value, the stream is put back to the
        // initial state
        reset();
        return result;
    
public byte[]getHashAsBytes()
Returns a byte array (length = 20) with the SHA value of the bytes written to the receiver.

return
The bytes that form the SHA value of the bytes written to the receiver

        byte[] hash = new byte[HashSizeInBytes];
        this.padBuffer();
        this.processBuffer();

        // We need to return HConstants (modified by the loop) as an array of
        // bytes. A memcopy would be the fastest.
        for (int i = 0; i < (HashSizeInBytes / 4); ++i) {
            hash[i * 4] = (byte) (HConstants[i] >>> 24 & 0xff);
            hash[i * 4 + 1] = (byte) (HConstants[i] >>> 16 & 0xff);
            hash[i * 4 + 2] = (byte) (HConstants[i] >>> 8 & 0xff);
            hash[i * 4 + 3] = (byte) (HConstants[i] & 0xff);
        }
        // After the user asks for the hash value, the stream is put back to the
        // initial state
        reset();
        return hash;
    
public byte[]getHashAsBytes(boolean pad)
Returns a byte array (length = 20) with the SHA value of the bytes written to the receiver.

return
The bytes that form the SHA value of the bytes written to the receiver

        byte[] hash = new byte[HashSizeInBytes];
        if (pad) {
            this.padBuffer();
            this.processBuffer();
        }

        // Convert HConstants to an array of bytes
        for (int i = 0; i < (HashSizeInBytes / 4); i++) {
            hash[i * 4] = (byte) (HConstants[i] >>> 24 & 0xff);
            hash[i * 4 + 1] = (byte) (HConstants[i] >>> 16 & 0xff);
            hash[i * 4 + 2] = (byte) (HConstants[i] >>> 8 & 0xff);
            hash[i * 4 + 3] = (byte) (HConstants[i] & 0xff);
        }
        // After the user asks for the hash value, the stream is put back to the
        // initial state
        reset();
        return hash;
    
private voidinitialize()
Initializes the receiver.

        HConstants = new int[HConstantsSize];
        MArray = new byte[BlockSizeInBytes];
        WArray = new int[WArraySize];
    
private voidpadBuffer()
Adds extra bytes to the bit stream as required (see the SHA specification).

        long lengthInBits;
        MArray[bytesToProcess] = (byte) 0x80;
        for (int i = bytesToProcess + 1; i < BlockSizeInBytes; i++) {
            MArray[i] = (byte) 0;
        }
        // Get length now because there might be extra padding (length in bits)
        lengthInBits = (bytesToProcess + bytesProcessed) * 8;

        // 9 extra bytes are needed: 1 for 1000... and 8 for length (long)
        if ((bytesToProcess + 9) > BlockSizeInBytes) {
            // Not enough space to append length. We need another block for
            // padding
            // Padding in this buffer only includes 1000000....
            this.processBuffer();
            // Now put 0's in all the buffer. memfill would be faster
            for (int i = 0; i < BlockSizeInBytes; i++) {
                MArray[i] = (byte) 0;
            }
        }

        for (int i = 1; i < 9; i++) {
            MArray[BlockSizeInBytes - i] = (byte) (lengthInBits & 0xff);
            lengthInBits = lengthInBits >>> 8;
        }
    
private voidprocessBuffer()
Core SHA code. Processes the receiver's buffer of bits, computing the values towards the final SHA

        int A; // A variable, from spec
        int B; // B variable, from spec
        int C; // C variable, from spec
        int D; // D variable, from spec
        int E; // E variable, from spec
        int temp; // TEMP, from spec
        int t; // t, for iteration, from spec

        for (t = 0; t <= 15; t++) { // step a, page 7 of spec. Here we convert 4
            // bytes into 1 word, 16 times
            WArray[t] = (MArray[4 * t] & 0xff) << 24
                    | ((MArray[4 * t + 1] & 0xff) << 16)
                    | ((MArray[4 * t + 2] & 0xff) << 8)
                    | (MArray[4 * t + 3] & 0xff);
        }
        for (t = 16; t <= 79; t++) { // step b, page 7 of spec
            temp = (WArray[t - 3] ^ WArray[t - 8] ^ WArray[t - 14] ^ WArray[t - 16]);
            temp = (temp << 1) | (temp >>> (32 - 1)); // element , Circular
            // Shift Left by 1
            WArray[t] = temp;
        }

        // step c, page 7 of spec
        A = HConstants[0];
        B = HConstants[1];
        C = HConstants[2];
        D = HConstants[3];
        E = HConstants[4];

        // step d, page 8 of spec
        for (t = 0; t <= 19; t++) {
            temp = (A << 5) | (A >>> (32 - 5)); // A , Circular Shift Left by 5
            temp = temp + E + WArray[t] + K0_19;
            temp = temp + ((B & C) | (~B & D));
            E = D;
            D = C;
            C = (B << 30) | (B >>> (32 - 30)); // B , Circular Shift Left by 30
            B = A;
            A = temp;
        }
        for (t = 20; t <= 39; t++) {
            temp = (A << 5) | (A >>> (32 - 5)); // A , Circular Shift Left by 5
            temp = temp + E + WArray[t] + K20_39;
            temp = temp + (B ^ C ^ D);
            E = D;
            D = C;
            C = (B << 30) | (B >>> (32 - 30)); // B , Circular Shift Left by 30
            B = A;
            A = temp;
        }
        for (t = 40; t <= 59; t++) {
            temp = (A << 5) | (A >>> (32 - 5)); // A , Circular Shift Left by 5
            temp = temp + E + WArray[t] + K40_59;
            temp = temp + ((B & C) | (B & D) | (C & D));
            E = D;
            D = C;
            C = (B << 30) | (B >>> (32 - 30)); // B , Circular Shift Left by 30
            B = A;
            A = temp;
        }
        for (t = 60; t <= 79; t++) {
            temp = (A << 5) | (A >>> (32 - 5)); // A , Circular Shift Left by 5
            temp = temp + E + WArray[t] + K60_79;
            temp = temp + (B ^ C ^ D);
            E = D;
            D = C;
            C = (B << 30) | (B >>> (32 - 30)); // B , Circular Shift Left by 30
            B = A;
            A = temp;
        }

        // step e, page 8 of spec
        HConstants[0] = HConstants[0] + A;
        HConstants[1] = HConstants[1] + B;
        HConstants[2] = HConstants[2] + C;
        HConstants[3] = HConstants[3] + D;
        HConstants[4] = HConstants[4] + E;
        // Update number of bytes actually processed
        bytesProcessed = bytesProcessed + BlockSizeInBytes;
        bytesToProcess = 0; // No pending bytes in the block

    
public voidreset()
Reset this SHAOutputStream to the state it was before any byte was written to it.

        HConstants[0] = H0;
        HConstants[1] = H1;
        HConstants[2] = H2;
        HConstants[3] = H3;
        HConstants[4] = H4;
        bytesProcessed = 0;
        bytesToProcess = 0;
    
public java.lang.StringtoString()

        return this.getClass().getName() + ':" + toStringBlock(getHashAsBytes());
    
private static java.lang.StringtoStringBlock(byte[] block)
Converts a block to a String representation.

param
block byte array representation of the bytes

        return toStringBlock(block, 0, block.length);
    
private static java.lang.StringtoStringBlock(byte[] block, int off, int len)
Converts a block to a String representation.

param
block byte array representation of the bytes
param
off offset into the block where to start the conversion
param
len how many bytes in the byte array to convert to a printable representation

        String hexdigits = "0123456789ABCDEF";
        StringBuilder buf = new StringBuilder();
        buf.append('[");
        for (int i = off; i < off + len; ++i) {
            buf.append(hexdigits.charAt((block[i] >>> 4) & 0xf));
            buf.append(hexdigits.charAt(block[i] & 0xf));
        }
        buf.append(']");
        return buf.toString();
    
public voidwrite(byte[] buffer, int off, int len)
Writes len bytes from this byte array buffer starting at offset off to the SHAOutputStream. The internal buffer used to compute SHA is updated, and the incremental computation of SHA is also performed.

param
buffer the buffer to be written
param
off offset in buffer to get bytes
param
len number of bytes in buffer to write

        int spaceLeft;
        int start;
        int bytesLeft;
        spaceLeft = BlockSizeInBytes - bytesToProcess;
        if (len < spaceLeft) { // Extra bytes are not enough to fill buffer
            this.copyToInternalBuffer(buffer, off, len);
            return;
        }
        // Extra bytes are bigger than space in buffer. Process buffer multiple
        // times
        this.copyToInternalBuffer(buffer, off, spaceLeft);
        bytesLeft = len - spaceLeft;
        this.processBuffer();
        start = off + spaceLeft;
        while (bytesLeft >= BlockSizeInBytes) {
            this.copyToInternalBuffer(buffer, start, BlockSizeInBytes);
            bytesLeft = bytesLeft - BlockSizeInBytes;
            this.processBuffer();
            start = start + BlockSizeInBytes;
        }
        if (bytesLeft > 0) {
            // Extra bytes at the end, not enough to fill buffer
            this.copyToInternalBuffer(buffer, start, bytesLeft);
        }
    
public voidwrite(int b)
Writes the specified byte b to this OutputStream. Only the low order byte of b is written.

param
b the byte to be written

        // Not thread-safe because we use a shared one-byte buffer
        oneByte[0] = (byte) b;
        write(oneByte, 0, 1);