view dcrypt/crypto/Hash.d @ 23:4589f8c5eb3c

Replaced dcrypt.crypto.Util with dcrypt.misc.Bitwise and dcrypt.misc.ByteConverter. Altered all dependent files to reflect changes.
author Thomas Dixon <reikon@reikon.us>
date Sat, 14 Feb 2009 19:58:20 -0500
parents 5ce3012f1def
children 8b5eaf3c2979
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 char[] 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
        if (index >= (blockSize-(blockSize >> 3)))
            update(new ubyte[blockSize-index]);
        update(new ubyte[(blockSize-ulong.sizeof)-index]);
        
        // Length padding
        ubyte[] length = new ubyte[ulong.sizeof];
        for (int i = 0, j = 0; i < 64; i+=8) // little endian
                length[j++] = bits >> i;
        if (mode == MODE_SHA)
            length.reverse; // big endian
        update(length);
    }
    
    /**
     * 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.
     */
    char[] hexDigest() {
        return ByteConverter.hexEncode(digest());
    }
    
    /** Reset hash to initial state. */
    void reset() {
        bytes = index = 0;
    }
}