view dcrypt/crypto/Hash.d @ 10:cd376996cdb3

Renamed SymmetricCipher back to Cipher (we don't support any other kind atm, I'll deal with it when we do.). Added BlockCipherWrapper for the encryption of arbitrary streams with or without padding. Removed hashByName, and replaced it with createHash. Re-did the high-level API, and filled out Crypto. Added cipher creation via createCipher. Added dsk to the CONTRIBUTORS file for helping with the design of the high-level API.
author Thomas Dixon <reikon@reikon.us>
date Wed, 20 Aug 2008 20:08:07 -0400
parents cff9960a019c
children 8c7f8fecdd75
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.Util;

/** 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.
     */
    void update(void[] input_) {
        ubyte[] input = cast(ubyte[]) input_;
        foreach (ubyte i; input) {
            bytes++;
            buffer[index++] = i;
            if (index == blockSize) {
                transform(buffer);
                index = 0;
            }   
        }
            
    }
    
    /** 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 ofr 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 Util.ubytesToHex(digest());
    }
    
    /** Reset hash to initial state. */
    void reset() {
        bytes = index = 0;
    }
}