view dcrypt/crypto/Hash.d @ 28:ad687db713a4

Further reworked the code for hash padding. Replaced all instances of 'char[]' with 'string' and removed a few 'const' modifiers as per Glenn Haecker's patch for D2 compatibility. Updated CONTRIBUTORS file.
author Thomas Dixon <reikon@reikon.us>
date Sun, 10 May 2009 22:38:48 -0400
parents 8b5eaf3c2979
children b9ba770b8f16
line wrap: on
line source

/**
 * This file is part of the dcrypt project.
 *
 * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved.
 * License:   MIT
 * Authors:   Thomas Dixon
 */

module dcrypt.crypto.Hash;

public import dcrypt.misc.ByteConverter;
public import dcrypt.misc.Bitwise;

/** Base class for all cryptographic hash functions */
class Hash
{
    private const enum
    {
        MODE_MD=0, // MDx, RipeMD, etc
        MODE_SHA,
        MODE_TIGER
    }
    
    protected
    {
        ubyte[] buffer;
        ulong bytes;
        uint index;
    }
        
    this (void[] input_=null)
    {
        buffer = new ubyte[blockSize];
        ubyte[] input = cast(ubyte[]) input_;
        if (input)
            update(input);
    }
    
    /** Returns: The block size of the hash function in bytes. */
    abstract uint blockSize();
    
    /** Returns: The output size of the hash function in bytes. */
    abstract uint digestSize();
    
    /** Returns: The name of the algorithm we're implementing. */
    abstract string name();
    
    /** Returns: A copy of this hash object. */
    abstract Hash copy();

    /**
     * Introduce data into the hash function.
     * 
     * Params:
     *     input_ = Data to be processed.
     *     
     * Returns: Self
     */
    Hash update(void[] input_)
    {
        ubyte[] input = cast(ubyte[]) input_;
        foreach (ubyte i; input)
        {
            bytes++;
            buffer[index++] = i;
            if (index == blockSize)
            {
                transform(buffer);
                index = 0;
            }   
        }
        
        return this;
    }
    
    /** Hash function's internal transformation. */
    protected abstract void transform(ubyte[] input);
    
    /** 
     * Pad message in the respective manner.
     * 
     * Params:
     *     mode = Mode constant dictating in which manner
     *            to pad the message.
     */
    protected void padMessage(uint mode)
    {
        ulong bits = bytes << 3;
        
        // Add the pad marker
        buffer[index++] = ((mode == MODE_TIGER) ? 0x01 : 0x80);
        if (index == blockSize)
        {
            transform(buffer);
            index = 0;
        }
        
        // Pad with null bytes
        while ((index & (blockSize - 1)) != (blockSize - (blockSize >> 3)))
        {
            buffer[index++] = 0;
            
            if (index == blockSize)
            {
                transform(buffer);
                index = 0;
            }
        }
        
        // Length padding
        for (int i = 0; i < blockSize; i+=8, bits>>=8) // little endian
                buffer[index++] = bits;
                                
        if (mode == MODE_SHA)
            buffer[(buffer.length-(blockSize >> 3))..buffer.length].reverse; // big endian

        transform(buffer);
        index = 0;
    }
    
    /**
     * Process all data, pad and finalize. This method will
     * reset the digest to its original state for subsequent use.
     * 
     * Returns: Binary representation of the hash in bytes.
     */
    abstract ubyte[] digest();
    
    /**
     * Same as digest() but returns hash value in hex.
     * 
     * Returns: Representation of the final hash value in hex.
     */
    string hexDigest()
    {
        return ByteConverter.hexEncode(digest());
    }
    
    /** Reset hash to initial state. */
    void reset()
    {
        bytes = index = 0;
    }
}