//*
//* CFB (Cipher Feedback) Stream
//*

//*
//* Initializes a CFB Stream with a cipher algorithm and an initial vector
//*
function CFBStream( _block_cipher, _init_vector ) {
    this.bc = _block_cipher;
    this.iv = _init_vector.slice( 0 );

    var ii;
    for ( ii=this.iv.length; ii < this.bc.BLOCKSIZE; ++ii ) {
	this.iv[ ii ] = 0x00be;
    }
};

//*
//* Encrypt an input string updating the initial vector as we go
//*
CFBStream.prototype.encrypt = function( _input ) {
    var out = [ ];
    var ii  = 0;
    for ( ii=0; ii < _input.length; /*done*/ ) {
	var eiv = this.bc.encrypt_block( this.iv );
	var jj;
	for ( jj=0; ii < _input.length && jj < this.bc.BLOCKSIZE; ++jj ) {
	    var pp = _input.charAt( ii ).charCodeAt(0);
	    var ee = ( pp ^ eiv[ jj ] ) & 0x00FF;
	    out[ ii ] = String.fromCharCode( ee );
	    this.iv[ jj ] = ee;
	    ++ii;
	}
    }

    return out.join('');
};

//*
//* Decrypt an input string updating the initial vector as we go.
//*
//* Note: The only difference between encrypt and decrypt is what
//* we use to update the initial vector.
//*
CFBStream.prototype.decrypt = function( _input ) {
    var out = [ ];
    var ii  = 0;
    for ( ii=0; ii < _input.length; /*done*/ ) {
	var eiv = this.bc.encrypt_block( this.iv );
	var jj;
	for ( jj=0; ii < _input.length && jj < this.bc.BLOCKSIZE; ++jj ) {
	    var cc = _input.charAt( ii ).charCodeAt(0);
	    var dd = ( cc ^ eiv[ jj ] ) & 0x00FF;
	    out[ ii ] = String.fromCharCode( dd );
	    this.iv[ jj ] = cc;
	    ++ii;
	}
    }

    return out.join('');
};

