1/*
2 * Copyright (c) 2006-2011 Christian Plattner. All rights reserved.
3 * Please refer to the LICENSE.txt for licensing details.
4 */
5package ch.ethz.ssh2.crypto.cipher;
6
7/**
8 * CBCMode.
9 *
10 * @author Christian Plattner
11 * @version 2.50, 03/15/10
12 */
13public class CBCMode implements BlockCipher
14{
15	BlockCipher tc;
16	int blockSize;
17	boolean doEncrypt;
18
19	byte[] cbc_vector;
20	byte[] tmp_vector;
21
22	public void init(boolean forEncryption, byte[] key)
23	{
24	}
25
26	public CBCMode(BlockCipher tc, byte[] iv, boolean doEncrypt)
27			throws IllegalArgumentException
28	{
29		this.tc = tc;
30		this.blockSize = tc.getBlockSize();
31		this.doEncrypt = doEncrypt;
32
33		if (this.blockSize != iv.length)
34			throw new IllegalArgumentException("IV must be " + blockSize
35					+ " bytes long! (currently " + iv.length + ")");
36
37		this.cbc_vector = new byte[blockSize];
38		this.tmp_vector = new byte[blockSize];
39		System.arraycopy(iv, 0, cbc_vector, 0, blockSize);
40	}
41
42	public int getBlockSize()
43	{
44		return blockSize;
45	}
46
47	private void encryptBlock(byte[] src, int srcoff, byte[] dst, int dstoff)
48	{
49		for (int i = 0; i < blockSize; i++)
50			cbc_vector[i] ^= src[srcoff + i];
51
52		tc.transformBlock(cbc_vector, 0, dst, dstoff);
53
54		System.arraycopy(dst, dstoff, cbc_vector, 0, blockSize);
55	}
56
57	private void decryptBlock(byte[] src, int srcoff, byte[] dst, int dstoff)
58	{
59		/* Assume the worst, src and dst are overlapping... */
60
61		System.arraycopy(src, srcoff, tmp_vector, 0, blockSize);
62
63		tc.transformBlock(src, srcoff, dst, dstoff);
64
65		for (int i = 0; i < blockSize; i++)
66			dst[dstoff + i] ^= cbc_vector[i];
67
68		/* ...that is why we need a tmp buffer. */
69
70		byte[] swap = cbc_vector;
71		cbc_vector = tmp_vector;
72		tmp_vector = swap;
73	}
74
75	public void transformBlock(byte[] src, int srcoff, byte[] dst, int dstoff)
76	{
77		if (doEncrypt)
78			encryptBlock(src, srcoff, dst, dstoff);
79		else
80			decryptBlock(src, srcoff, dst, dstoff);
81	}
82}
83