1b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallampackage org.bouncycastle.crypto.modes; 2b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 3b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport org.bouncycastle.crypto.BlockCipher; 4b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport org.bouncycastle.crypto.CipherParameters; 5b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport org.bouncycastle.crypto.DataLengthException; 6b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport org.bouncycastle.crypto.params.ParametersWithIV; 7b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 8b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam/** 9b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * implements a Output-FeedBack (OFB) mode on top of a simple cipher. 10b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam */ 11b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallampublic class OFBBlockCipher 12b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam implements BlockCipher 13b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam{ 14b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam private byte[] IV; 15b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam private byte[] ofbV; 16b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam private byte[] ofbOutV; 17b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 18b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam private final int blockSize; 19b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam private final BlockCipher cipher; 20b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 21b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam /** 22b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * Basic constructor. 23b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * 24b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * @param cipher the block cipher to be used as the basis of the 25b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * feedback mode. 26b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * @param blockSize the block size in bits (note: a multiple of 8) 27b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam */ 28b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam public OFBBlockCipher( 29b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam BlockCipher cipher, 30b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam int blockSize) 31b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 32b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam this.cipher = cipher; 33b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam this.blockSize = blockSize / 8; 34b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 35b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam this.IV = new byte[cipher.getBlockSize()]; 36b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam this.ofbV = new byte[cipher.getBlockSize()]; 37b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam this.ofbOutV = new byte[cipher.getBlockSize()]; 38b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 39b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 40b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam /** 41b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * return the underlying block cipher that we are wrapping. 42b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * 43b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * @return the underlying block cipher that we are wrapping. 44b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam */ 45b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam public BlockCipher getUnderlyingCipher() 46b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 47b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam return cipher; 48b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 49b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 50b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam /** 51b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * Initialise the cipher and, possibly, the initialisation vector (IV). 52b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * If an IV isn't passed as part of the parameter, the IV will be all zeros. 53b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * An IV which is too short is handled in FIPS compliant fashion. 54b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * 55b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * @param encrypting if true the cipher is initialised for 56b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * encryption, if false for decryption. 57b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * @param params the key and other data required by the cipher. 58b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * @exception IllegalArgumentException if the params argument is 59b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * inappropriate. 60b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam */ 61b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam public void init( 62b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam boolean encrypting, //ignored by this OFB mode 63b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam CipherParameters params) 64b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam throws IllegalArgumentException 65b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 66b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam if (params instanceof ParametersWithIV) 67b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 6870c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom ParametersWithIV ivParam = (ParametersWithIV)params; 6970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom byte[] iv = ivParam.getIV(); 70b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 7170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom if (iv.length < IV.length) 7270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom { 7370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom // prepend the supplied IV with zeros (per FIPS PUB 81) 7470c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom System.arraycopy(iv, 0, IV, IV.length - iv.length, iv.length); 7570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom for (int i = 0; i < IV.length - iv.length; i++) 76b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 7770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom IV[i] = 0; 78b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 7970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom } 8070c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom else 8170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom { 8270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom System.arraycopy(iv, 0, IV, 0, IV.length); 8370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom } 84b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 8570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom reset(); 86b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 8770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom // if null it's an IV changed only. 8870c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom if (ivParam.getParameters() != null) 8970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom { 9070c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom cipher.init(true, ivParam.getParameters()); 9170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom } 92b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 93b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam else 94b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 9570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom reset(); 96b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 9770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom // if it's null, key is to be reused. 9870c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom if (params != null) 9970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom { 100b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam cipher.init(true, params); 10170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom } 102b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 103b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 104b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 105b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam /** 106b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * return the algorithm name and mode. 107b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * 108b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * @return the name of the underlying algorithm followed by "/OFB" 109b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * and the block size in bits 110b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam */ 111b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam public String getAlgorithmName() 112b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 113b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam return cipher.getAlgorithmName() + "/OFB" + (blockSize * 8); 114b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 115b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 116b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 117b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam /** 118b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * return the block size we are operating at (in bytes). 119b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * 120b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * @return the block size we are operating at (in bytes). 121b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam */ 122b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam public int getBlockSize() 123b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 124b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam return blockSize; 125b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 126b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 127b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam /** 128b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * Process one block of input from the array in and write it to 129b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * the out array. 130b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * 131b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * @param in the array containing the input data. 132b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * @param inOff offset into the in array the data starts at. 133b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * @param out the array the output data will be copied into. 134b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * @param outOff the offset into the out array the output will start at. 135b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * @exception DataLengthException if there isn't enough data in in, or 136b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * space in out. 137b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * @exception IllegalStateException if the cipher isn't initialised. 138b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * @return the number of bytes processed and produced. 139b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam */ 140b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam public int processBlock( 141b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam byte[] in, 142b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam int inOff, 143b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam byte[] out, 144b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam int outOff) 145b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam throws DataLengthException, IllegalStateException 146b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 147b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam if ((inOff + blockSize) > in.length) 148b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 149b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam throw new DataLengthException("input buffer too short"); 150b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 151b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 152b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam if ((outOff + blockSize) > out.length) 153b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 154b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam throw new DataLengthException("output buffer too short"); 155b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 156b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 157b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam cipher.processBlock(ofbV, 0, ofbOutV, 0); 158b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 159b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam // 160b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam // XOR the ofbV with the plaintext producing the cipher text (and 161b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam // the next input block). 162b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam // 163b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam for (int i = 0; i < blockSize; i++) 164b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 165b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam out[outOff + i] = (byte)(ofbOutV[i] ^ in[inOff + i]); 166b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 167b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 168b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam // 169b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam // change over the input block. 170b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam // 171b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam System.arraycopy(ofbV, blockSize, ofbV, 0, ofbV.length - blockSize); 172b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam System.arraycopy(ofbOutV, 0, ofbV, ofbV.length - blockSize, blockSize); 173b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 174b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam return blockSize; 175b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 176b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 177b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam /** 178b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * reset the feedback vector back to the IV and reset the underlying 179b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * cipher. 180b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam */ 181b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam public void reset() 182b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 183b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam System.arraycopy(IV, 0, ofbV, 0, IV.length); 184b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 185b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam cipher.reset(); 186b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 187b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam} 188