Skip to content
This repository has been archived by the owner on Mar 27, 2019. It is now read-only.

Commit

Permalink
First tests for encrypt cipher.
Browse files Browse the repository at this point in the history
  • Loading branch information
ezzatron committed May 28, 2014
1 parent ada73b1 commit aff7649
Show file tree
Hide file tree
Showing 3 changed files with 299 additions and 11 deletions.
54 changes: 54 additions & 0 deletions src/main/java/co/lqnt/lockbox/cipher/CipherInterface.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
import co.lqnt.lockbox.cipher.exception.OutputSizeException;
import co.lqnt.lockbox.cipher.exception.UnsupportedCipherParametersException;
import co.lqnt.lockbox.cipher.parameters.CipherParametersInterface;
import co.lqnt.lockbox.cipher.result.CipherResultInterface;
import com.google.common.base.Optional;

/**
* The interface implemented by ciphers.
Expand Down Expand Up @@ -107,6 +109,58 @@ public int process(
*/
public int finalize(final byte[] output, final int outputOffset);

/**
* Finalize the cipher output.
*
* @param input The input byte.
* @param output The space for any output that might be produced.
* @param outputOffset The offset to which the output will be copied.
*
* @return The number of bytes produced.
* @throws CipherStateException If the cipher is in an invalid state.
* @throws OutputSizeException If there isn't enough space in output.
*/
public int finalize(
final byte input,
final byte[] output,
final int outputOffset
);

/**
* Finalize the cipher output.
*
* @param input The input byte array.
* @param inputOffset The offset at which the input data starts.
* @param size The number of bytes to be read from the input array.
* @param output The space for any output that might be produced.
* @param outputOffset The offset to which the output will be copied.
*
* @return The number of bytes produced.
* @throws CipherStateException If the cipher is in an invalid state.
* @throws OutputSizeException If there isn't enough space in output.
*/
public int finalize(
final byte[] input,
final int inputOffset,
final int size,
final byte[] output,
final int outputOffset
);

/**
* Returns true if this cipher is finalized.
*
* @return True if finalized.
*/
public boolean isFinalized();

/**
* Get the result.
*
* @return The result.
*/
public Optional<CipherResultInterface> result();

/**
* Reset the cipher to its state after the last initialize() call.
*/
Expand Down
142 changes: 131 additions & 11 deletions src/main/java/co/lqnt/lockbox/cipher/EncryptCipher.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,21 @@

package co.lqnt.lockbox.cipher;

import co.lqnt.lockbox.cipher.exception.CipherFinalizedException;
import co.lqnt.lockbox.cipher.exception.CipherNotInitializedException;
import co.lqnt.lockbox.cipher.exception.CipherStateException;
import co.lqnt.lockbox.cipher.exception.OutputSizeException;
import co.lqnt.lockbox.cipher.exception.UnsupportedCipherParametersException;
import co.lqnt.lockbox.cipher.parameters.CipherParametersInterface;
import co.lqnt.lockbox.cipher.parameters.EncryptParametersInterface;
import co.lqnt.lockbox.cipher.result.CipherResultInterface;
import co.lqnt.lockbox.cipher.result.CipherResultType;
import co.lqnt.lockbox.cipher.result.factory.CipherResultFactory;
import co.lqnt.lockbox.cipher.result.factory.CipherResultFactoryInterface;
import co.lqnt.lockbox.key.KeyInterface;
import co.lqnt.lockbox.random.RandomSourceInterface;
import co.lqnt.lockbox.random.SecureRandom;
import com.google.common.base.Optional;
import com.google.common.primitives.Bytes;
import java.util.Arrays;
import org.bouncycastle.crypto.DataLengthException;
Expand All @@ -43,24 +50,28 @@ public class EncryptCipher implements CipherInterface
*/
public EncryptCipher()
{
this(SecureRandom.instance());
this(SecureRandom.instance(), CipherResultFactory.instance());
}

/**
* Create a new encrypt cipher.
*
* @param randomSource The random source to use.
* @param resultFactory The result factory to use.
*/
public EncryptCipher(final RandomSourceInterface randomSource)
{
public EncryptCipher(
final RandomSourceInterface randomSource,
final CipherResultFactoryInterface resultFactory
) {
this.randomSource = randomSource;
this.resultFactory = resultFactory;
this.cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()),
new PKCS7Padding()
);
this.blockMac = null;
this.finalMac = null;
this.isInitialized = this.isHeaderSent = false;
this.blockMac = this.finalMac = null;
this.isInitialized = this.isHeaderSent = this.isFinalized = false;
this.result = null;
}

/**
Expand All @@ -73,6 +84,16 @@ public RandomSourceInterface randomSource()
return this.randomSource;
}

/**
* Get the result factory.
*
* @return The result factory.
*/
public CipherResultFactoryInterface resultFactory()
{
return this.resultFactory;
}

/**
* Returns true if this cipher is initialized.
*
Expand Down Expand Up @@ -109,6 +130,8 @@ public void initialize(final CipherParametersInterface parameters)
throw new UnsupportedCipherParametersException(this, parameters);
}

this.isInitialized = true;

if (null == this.iv) {
this.iv = Bytes.toArray(this.randomSource().generate(16));
}
Expand Down Expand Up @@ -168,6 +191,13 @@ public void initialize(final CipherParametersInterface parameters)
*/
public int processOutputSize(final int inputSize)
{
if (!this.isInitialized) {
throw new CipherNotInitializedException(this);
}
if (this.isFinalized) {
throw new CipherFinalizedException(this);
}

int size = this.cipher.getUpdateOutputSize(inputSize) / 16 * 18;

if (size > 0 && !this.isHeaderSent) {
Expand Down Expand Up @@ -216,8 +246,11 @@ public int process(
final byte[] output,
final int outputOffset
) {
if (null == this.iv) {
throw new IllegalStateException("Cipher not initialized.");
if (!this.isInitialized) {
throw new CipherNotInitializedException(this);
}
if (this.isFinalized) {
throw new CipherFinalizedException(this);
}

int outputSize = this.processOutputSize(size);
Expand Down Expand Up @@ -264,6 +297,13 @@ public int process(
*/
public int finalOutputSize(final int inputSize)
{
if (!this.isInitialized) {
throw new CipherNotInitializedException(this);
}
if (this.isFinalized) {
throw new CipherFinalizedException(this);
}

int size = this.cipher.getOutputSize(inputSize) / 16 * 18;

if (this.isHeaderSent) {
Expand All @@ -287,8 +327,11 @@ public int finalOutputSize(final int inputSize)
*/
public int finalize(final byte[] output, final int outputOffset)
{
if (null == this.iv) {
throw new IllegalStateException("Cipher not initialized.");
if (!this.isInitialized) {
throw new CipherNotInitializedException(this);
}
if (this.isFinalized) {
throw new CipherFinalizedException(this);
}

int outputSize = this.finalOutputSize(0);
Expand All @@ -299,6 +342,8 @@ public int finalize(final byte[] output, final int outputOffset)
);
}

this.isFinalized = true;

int ciphertextOffset = outputOffset +
this.handleHeader(output, outputOffset, outputSize);

Expand Down Expand Up @@ -339,16 +384,88 @@ public int finalize(final byte[] output, final int outputOffset)
mac.length
);

this.result = this.resultFactory()
.createResult(CipherResultType.SUCCESS);

return outputSize;
}

/**
* Finalize the cipher output.
*
* @param input The input byte.
* @param output The space for any output that might be produced.
* @param outputOffset The offset to which the output will be copied.
*
* @return The number of bytes produced.
* @throws CipherStateException If the cipher is in an invalid state.
* @throws OutputSizeException If there isn't enough space in output.
*/
public int finalize(
final byte input,
final byte[] output,
final int outputOffset
) {
return this.finalize(new byte[]{input}, 0, 1, output, outputOffset);
}

/**
* Finalize the cipher output.
*
* @param input The input byte array.
* @param inputOffset The offset at which the input data starts.
* @param size The number of bytes to be read from the input array.
* @param output The space for any output that might be produced.
* @param outputOffset The offset to which the output will be copied.
*
* @return The number of bytes produced.
* @throws CipherStateException If the cipher is in an invalid state.
* @throws OutputSizeException If there isn't enough space in output.
*/
public int finalize(
final byte[] input,
final int inputOffset,
final int size,
final byte[] output,
final int outputOffset
) {
int outputSize =
this.process(input, inputOffset, size, output, outputOffset);

return outputSize + this.finalize(output, outputOffset + outputSize);
}

/**
* Returns true if this cipher is finalized.
*
* @return True if finalized.
*/
public boolean isFinalized()
{
return this.isFinalized;
}

/**
* Get the result.
*
* @return The result.
*/
public Optional<CipherResultInterface> result()
{
return Optional.fromNullable(this.result);
}

/**
* Reset the cipher to its state after the last initialize() call.
*/
public void reset()
{
this.cipher.reset();
this.isHeaderSent = false;
if (null != this.finalMac) {
this.finalMac.reset();
}
this.isHeaderSent = this.isFinalized = false;
this.result = null;
}

/**
Expand Down Expand Up @@ -414,10 +531,13 @@ private void authenticate(
}

final private RandomSourceInterface randomSource;
final private CipherResultFactoryInterface resultFactory;
final private PaddedBufferedBlockCipher cipher;
private byte[] iv;
private HMac blockMac;
private HMac finalMac;
private boolean isInitialized;
private boolean isHeaderSent;
private boolean isFinalized;
private CipherResultInterface result;
}
Loading

0 comments on commit aff7649

Please sign in to comment.