view dcrypt/crypto/modes/CTR.d @ 0:0e08791a1418

Initial import.
author Thomas Dixon <reikon@reikon.us>
date Sun, 10 Aug 2008 14:20:17 -0400
parents
children 23c62e28b3a4
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;
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 m_cipher;
    private ubyte[] iv,
                    counter,
                    counterOutput;
    private bool initialized = false;
    
    /**
     * Params:
     *     cipher = Block cipher to wrap.
     */
    this (BlockCipher cipher) {
        m_cipher = cipher;
    }
    
    /** Returns: The underlying cipher we are wrapping. */
    BlockCipher cipher() {
        return m_cipher;
    }
    
    char[] name() {
        return m_cipher.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");
                    
        m_cipher.init(true, ivParams.parameters);
        
        iv = ivParams.iv[0..blockSize];
        counter = new ubyte[blockSize];
        counter[] = iv;
        counterOutput = new ubyte[blockSize];
        
        initialized = true;
    }
    
    uint processBlock(void[] input_, uint inOff, void[] output_, uint outOff) {
        if (!initialized)
            throw new NotInitializedError(
                    name()~": Block mode not initialized");
            
        ubyte[] input = cast(ubyte[]) input_;
        ubyte[] output = cast(ubyte[]) output_;
        
        // Encrypt the counter
        m_cipher.processBlock(counter, 0, counterOutput, 0);
        
        // XOR output with plaintext to create ciphertext
        for (int i = 0; i < counter.length; i++)
            output[outOff++] = (counterOutput[i] ^ input[inOff++]);
            
        // Increment the counter
        for (int i = counter.length-1; i >= 0; i--)
            if (++counter[i]) break;

        return counter.length;  
    }
    
    uint blockSize() {
        return m_cipher.blockSize;
    }
    
    void reset() {
        counter[] = iv;
        m_cipher.reset();
    }
}