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 { 68b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam ParametersWithIV ivParam = (ParametersWithIV)params; 69b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam byte[] iv = ivParam.getIV(); 70b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 71b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam if (iv.length < IV.length) 72b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 73b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam // prepend the supplied IV with zeros (per FIPS PUB 81) 74b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam System.arraycopy(iv, 0, IV, IV.length - iv.length, iv.length); 75b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam for (int i = 0; i < IV.length - iv.length; i++) 76b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 77b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam IV[i] = 0; 78b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 79b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 80b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam else 81b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 82b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam System.arraycopy(iv, 0, IV, 0, IV.length); 83b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 84b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 85b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam reset(); 86b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 874c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom // if null it's an IV changed only. 884c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom if (ivParam.getParameters() != null) 894c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom { 904c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom cipher.init(true, ivParam.getParameters()); 914c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom } 92b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 93b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam else 94b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 95b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam reset(); 96b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 97b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam cipher.init(true, params); 98b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 99b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 100b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 101b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam /** 102b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * return the algorithm name and mode. 103b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * 104b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * @return the name of the underlying algorithm followed by "/OFB" 105b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * and the block size in bits 106b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam */ 107b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam public String getAlgorithmName() 108b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 109b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam return cipher.getAlgorithmName() + "/OFB" + (blockSize * 8); 110b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 111b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 112b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 113b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam /** 114b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * return the block size we are operating at (in bytes). 115b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * 116b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * @return the block size we are operating at (in bytes). 117b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam */ 118b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam public int getBlockSize() 119b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 120b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam return blockSize; 121b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 122b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 123b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam /** 124b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * Process one block of input from the array in and write it to 125b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * the out array. 126b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * 127b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * @param in the array containing the input data. 128b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * @param inOff offset into the in array the data starts at. 129b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * @param out the array the output data will be copied into. 130b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * @param outOff the offset into the out array the output will start at. 131b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * @exception DataLengthException if there isn't enough data in in, or 132b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * space in out. 133b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * @exception IllegalStateException if the cipher isn't initialised. 134b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * @return the number of bytes processed and produced. 135b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam */ 136b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam public int processBlock( 137b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam byte[] in, 138b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam int inOff, 139b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam byte[] out, 140b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam int outOff) 141b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam throws DataLengthException, IllegalStateException 142b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 143b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam if ((inOff + blockSize) > in.length) 144b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 145b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam throw new DataLengthException("input buffer too short"); 146b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 147b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 148b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam if ((outOff + blockSize) > out.length) 149b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 150b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam throw new DataLengthException("output buffer too short"); 151b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 152b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 153b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam cipher.processBlock(ofbV, 0, ofbOutV, 0); 154b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 155b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam // 156b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam // XOR the ofbV with the plaintext producing the cipher text (and 157b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam // the next input block). 158b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam // 159b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam for (int i = 0; i < blockSize; i++) 160b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 161b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam out[outOff + i] = (byte)(ofbOutV[i] ^ in[inOff + i]); 162b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 163b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 164b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam // 165b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam // change over the input block. 166b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam // 167b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam System.arraycopy(ofbV, blockSize, ofbV, 0, ofbV.length - blockSize); 168b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam System.arraycopy(ofbOutV, 0, ofbV, ofbV.length - blockSize, blockSize); 169b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 170b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam return blockSize; 171b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 172b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 173b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam /** 174b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * reset the feedback vector back to the IV and reset the underlying 175b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * cipher. 176b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam */ 177b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam public void reset() 178b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 179b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam System.arraycopy(IV, 0, ofbV, 0, IV.length); 180b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 181b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam cipher.reset(); 182b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 183b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam} 184