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