org.bouncycastle.crypto.modes.KXTSBlockCipher Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of bcprov-ext-debug-jdk18on Show documentation
Show all versions of bcprov-ext-debug-jdk18on Show documentation
The Bouncy Castle Crypto package is a Java implementation of cryptographic algorithms. This jar contains JCE provider and lightweight API for the Bouncy Castle Cryptography APIs for Java 1.8 and later with debug enabled.
The newest version!
package org.bouncycastle.crypto.modes;
import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.DefaultBufferedBlockCipher;
import org.bouncycastle.crypto.OutputLengthException;
import org.bouncycastle.crypto.params.ParametersWithIV;
import org.bouncycastle.util.Pack;
/**
* Implementation of DSTU7624 XTS mode
*/
public class KXTSBlockCipher
extends DefaultBufferedBlockCipher
{
/*
* Constants for GF(2^m) operations
*
* GF(2 ^ 128) -> x^128 + x^7 + x^2 + x + 1
* GF(2 ^ 256) -> x^256 + x^10 + x^5 + x^2 + 1
* GF(2 ^ 512) -> x^512 + x^8 + x^5 + x^2 + 1
*/
private static final long RED_POLY_128 = 0x0087L;
private static final long RED_POLY_256 = 0x0425L;
private static final long RED_POLY_512 = 0x0125L;
protected static long getReductionPolynomial(int blockSize)
{
switch (blockSize)
{
case 16:
return RED_POLY_128;
case 32:
return RED_POLY_256;
case 64:
return RED_POLY_512;
default:
throw new IllegalArgumentException("Only 128, 256, and 512 -bit block sizes supported");
}
}
private final int blockSize;
private final long reductionPolynomial;
private final long[] tw_init, tw_current;
private int counter;
public KXTSBlockCipher(BlockCipher cipher)
{
// super(cipher);
this.cipher = cipher;
this.blockSize = cipher.getBlockSize();
this.reductionPolynomial = getReductionPolynomial(blockSize);
this.tw_init = new long[blockSize >>> 3];
this.tw_current = new long[blockSize >>> 3];
this.counter = -1;
}
public int getOutputSize(int length)
{
return length;
}
public int getUpdateOutputSize(int len)
{
return len;
}
public void init(boolean forEncryption, CipherParameters parameters)
{
if (!(parameters instanceof ParametersWithIV))
{
throw new IllegalArgumentException("Invalid parameters passed");
}
ParametersWithIV ivParam = (ParametersWithIV)parameters;
parameters = ivParam.getParameters();
byte[] iv = ivParam.getIV();
/*
* TODO We need to check what the rule is supposed to be for IVs that aren't exactly one block.
*
* Given general little-endianness, presumably a short IV should be right-padded with zeroes.
*/
if (iv.length != blockSize)
{
throw new IllegalArgumentException("Currently only support IVs of exactly one block");
}
byte[] tweak = new byte[blockSize];
System.arraycopy(iv, 0, tweak, 0, blockSize);
cipher.init(true, parameters);
cipher.processBlock(tweak, 0, tweak, 0);
cipher.init(forEncryption, parameters);
Pack.littleEndianToLong(tweak, 0, tw_init);
System.arraycopy(tw_init, 0, tw_current, 0, tw_init.length);
counter = 0;
}
public int processByte(byte in, byte[] out, int outOff)
{
/*
* TODO This class isn't really behaving like a BufferedBlockCipher yet
*/
throw new IllegalStateException("unsupported operation");
}
public int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
{
if (input.length - inOff < len)
{
throw new DataLengthException("Input buffer too short");
}
if (output.length - inOff < len)
{
throw new OutputLengthException("Output buffer too short");
}
if (len % blockSize != 0)
{
throw new IllegalArgumentException("Partial blocks not supported");
}
for (int pos = 0; pos < len; pos += blockSize)
{
processBlocks(input, inOff + pos, output, outOff + pos);
}
return len;
}
private void processBlocks(byte[] input, int inOff, byte[] output, int outOff)
{
/*
* A somewhat arbitrary limit of 2^32 - 1 blocks
*/
if (counter == -1)
{
throw new IllegalStateException("Attempt to process too many blocks");
}
++counter;
/*
* Multiply tweak by 'alpha', which is just 2
*/
GF_double(reductionPolynomial, tw_current);
byte[] tweak = new byte[blockSize];
Pack.longToLittleEndian(tw_current, tweak, 0);
byte[] buffer = new byte[blockSize];
System.arraycopy(tweak, 0, buffer, 0, blockSize);
for (int i = 0; i < blockSize; ++i)
{
buffer[i] ^= input[inOff + i];
}
cipher.processBlock(buffer, 0, buffer, 0);
for (int i = 0; i < blockSize; ++i)
{
output[outOff + i] = (byte)(buffer[i] ^ tweak[i]);
}
}
public int doFinal(byte[] output, int outOff)
{
reset();
return 0;
}
public void reset()
{
// super.reset();
cipher.reset();
System.arraycopy(tw_init, 0, tw_current, 0, tw_init.length);
counter = 0;
}
private static void GF_double(long redPoly, long[] z)
{
long c = 0;
for (int i = 0; i < z.length; ++i)
{
long zVal = z[i];
long bit = zVal >>> 63;
z[i] = (zVal << 1) ^ c;
c = bit;
}
z[0] ^= redPoly & -c;
}
}