view dcrypt/crypto/prngs/PRNGFromHash.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 2b4bccdc8387
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.prngs.PRNGFromHash;

import dcrypt.crypto.PRNG;
import dcrypt.crypto.Hash;

/** Creates a PRNG from a hash function. */
class PRNGFromHash : PRNG
{
    private
    {
        const uint COUNTER_SIZE = 32;
        
        Hash hash;
        ubyte[] counter,
                seed,
                state;
        uint index;
    }
    
    string name()
    {
        if (hash is null)
            throw new NotInitializedError(name()~": PRNG not initialized");
        
        return hash.name~"PRNG";
    }
    
    this(Hash hash)
    {
        if (hash is null)
            throw new InvalidParameterError(
                name()~": Invalid parameter passed to constructor.");
                
        this.hash = hash;
        this.hash.reset();
        
        counter = new ubyte[COUNTER_SIZE];
        seed = new ubyte[this.hash.digestSize];
        state = new ubyte[this.hash.digestSize];
        
        index = this.hash.digestSize; // to force updating of the state
    }
    
    void addEntropy(ubyte[] input)
    {
        if (!_initialized)
        {
            hash.update(input);
            seed = hash.digest();
            _initialized = true;
        } else
            throw new NotSupportedError(name()~": state is immutable once initialized");
    }
    
    uint read(ubyte[] output)
    {
        if (!_initialized)
            throw new NotInitializedError(name()~": PRNG not initialized");
        
        for (uint i = 0; i < output.length; i++)
        {
            if (index == state.length)
            {
                hash.update(seed);
                hash.update(counter);
                state = hash.digest();
                
                // Increment the counter
                for (uint j = COUNTER_SIZE-1; j >= 0; j--)
                    if (++counter[j]) break;
                
                index = 0;
            }
            output[i] = state[index++];
        }
        
        return output.length;
    }
}