view dcrypt/crypto/modes/CTR.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 8c7f8fecdd75
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.modes.CTR;

import dcrypt.crypto.BlockCipher;
public import dcrypt.crypto.params.ParametersWithIV;


/** This class implements the counter (CTR/SIC/ICM) block mode,
    treating the counter as a big endian integer. */
class CTR : BlockCipher {
    private BlockCipher wrappedCipher;
    private ubyte[] iv,
                    counter,
                    counterOutput;
    private bool initialized = false;
    
    /**
     * Params:
     *     cipher = Block cipher to wrap.
     */
    this (BlockCipher cipher) {
        wrappedCipher = cipher;
    }
    
    /** Returns: The underlying cipher we are wrapping. */
    BlockCipher cipher() {
        return wrappedCipher;
    }
    
    char[] name() {
        return wrappedCipher.name~"/CTR";
    }
    
    /** 
     * Throws: dcrypt.crypto.errors.InvalidParameterError if params aren't 
     *         an instance of dcrypt.crypto.params.ParametersWithIV.
     */
    void init(bool encrypt, CipherParameters params) {
        ParametersWithIV ivParams = cast(ParametersWithIV)params;
        
        if (!ivParams)
            throw new InvalidParameterError(
                    name()~": Block mode requires IV (use ParametersWithIV)");
        if (ivParams.iv.length != blockSize)
            throw new InvalidParameterError(
                    name()~": IV must be same length as cipher block size");
                    
        wrappedCipher.init(true, ivParams.parameters);
        
        iv = ivParams.iv[0..blockSize];
        counter = new ubyte[blockSize];
        counter[] = iv;
        counterOutput = new ubyte[blockSize];
        
        initialized = true;
    }
    
    uint update(void[] input_, void[] output_) {
        if (!initialized)
            throw new NotInitializedError(
                    name()~": Block mode not initialized");
            
        ubyte[] input = cast(ubyte[]) input_,
                output = cast(ubyte[]) output_;
                
        uint len = (counter.length > input.length) ? input.length : counter.length;
        
        if (len > output.length)
            throw new ShortBufferError(name()~": Output buffer too short");
        
        // Encrypt the counter
        wrappedCipher.update(counter, counterOutput);
        
        // XOR output with plaintext to create ciphertext
        for (int i = 0; i < len; i++)
            counterOutput[i] ^= input[i];
            
        // Increment the counter
        for (int i = counter.length-1; i >= 0; i--)
            if (++counter[i]) break;

        output[0..len] = counterOutput[0..len];
        
        return len;
    }
    
    uint blockSize() {
        return wrappedCipher.blockSize;
    }
    
    void reset() {
        counter[] = iv;
        wrappedCipher.reset();
    }
}