Skip to content

Commit

Permalink
CRYPTO-60: opensslCipher support GCM mode
Browse files Browse the repository at this point in the history
Closes #70 from kexianda/gcm3
  • Loading branch information
Xianda Ke authored and sundapeng committed Nov 20, 2017
1 parent de54234 commit aad8c55
Show file tree
Hide file tree
Showing 14 changed files with 1,113 additions and 110 deletions.
2 changes: 1 addition & 1 deletion Makefile.common
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ Linux-x86_64_CXX := $(CROSS_PREFIX)g++
Linux-x86_64_STRIP := $(CROSS_PREFIX)strip
Linux-x86_64_CXXFLAGS := -Ilib/inc_linux -I$(JAVA_HOME)/include -Ilib/inc_mac -O2 -fPIC -fvisibility=hidden -m64
Linux-x86_64_CFLAGS := -Ilib/inc_linux -I$(JAVA_HOME)/include -Ilib/inc_mac -O2 -fPIC -fvisibility=hidden -m64
Linux-x86_64_LINKFLAGS := -shared -static-libgcc -static-libstdc++
Linux-x86_64_LINKFLAGS := -shared -static-libgcc
Linux-x86_64_LIBNAME := libcommons-crypto.so
Linux-x86_64_COMMONS_CRYPTO_FLAGS :=

Expand Down
52 changes: 52 additions & 0 deletions src/main/java/org/apache/commons/crypto/cipher/CryptoCipher.java
Original file line number Diff line number Diff line change
Expand Up @@ -153,4 +153,56 @@ int doFinal(ByteBuffer inBuffer, ByteBuffer outBuffer)
int doFinal(byte[] input, int inputOffset, int inputLen, byte[] output,
int outputOffset) throws ShortBufferException,
IllegalBlockSizeException, BadPaddingException;

/**
* Continues a multi-part update of the Additional Authentication
* Data (AAD).
* <p>
* Calls to this method provide AAD to the cipher when operating in
* modes such as AEAD (GCM). If this cipher is operating in
* GCM mode, all AAD must be supplied before beginning
* operations on the ciphertext (via the {@code update} and
* {@code doFinal} methods).
*
* @param aad the buffer containing the Additional Authentication Data
*
* @throws IllegalArgumentException if the {@code aad}
* byte array is null
* @throws IllegalStateException if this cipher is in a wrong state
* (e.g., has not been initialized), does not accept AAD, or if
* operating in either GCM or CCM mode and one of the {@code update}
* methods has already been called for the active
* encryption/decryption operation
* @throws UnsupportedOperationException if the corresponding method
* has not been overridden by an implementation
*
*/
void updateAAD(byte[] aad)
throws IllegalArgumentException, IllegalStateException, UnsupportedOperationException;

/**
* Continues a multi-part update of the Additional Authentication
* Data (AAD).
* <p>
* Calls to this method provide AAD to the cipher when operating in
* modes such as AEAD (GCM). If this cipher is operating in
* GCM mode, all AAD must be supplied before beginning
* operations on the ciphertext (via the {@code update} and
* {@code doFinal} methods).
*
* @param aad the buffer containing the Additional Authentication Data
*
* @throws IllegalArgumentException if the {@code aad}
* byte array is null
* @throws IllegalStateException if this cipher is in a wrong state
* (e.g., has not been initialized), does not accept AAD, or if
* operating in either GCM or CCM mode and one of the {@code update}
* methods has already been called for the active
* encryption/decryption operation
* @throws UnsupportedOperationException if the corresponding method
* has not been overridden by an implementation
*
*/
void updateAAD(ByteBuffer aad)
throws IllegalArgumentException, IllegalStateException, UnsupportedOperationException;
}
56 changes: 56 additions & 0 deletions src/main/java/org/apache/commons/crypto/cipher/JceCipher.java
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,62 @@ public int doFinal(byte[] input, int inputOffset, int inputLen,
outputOffset);
}


/**
* Continues a multi-part update of the Additional Authentication
* Data (AAD).
* <p>
* Calls to this method provide AAD to the cipher when operating in
* modes such as AEAD (GCM/CCM). If this cipher is operating in
* either GCM or CCM mode, all AAD must be supplied before beginning
* operations on the ciphertext (via the {@code update} and
* {@code doFinal} methods).
*
* @param aad the buffer containing the Additional Authentication Data
*
* @throws IllegalArgumentException if the {@code aad}
* byte array is null
* @throws IllegalStateException if this cipher is in a wrong state
* (e.g., has not been initialized), does not accept AAD, or if
* operating in either GCM or CCM mode and one of the {@code update}
* methods has already been called for the active
* encryption/decryption operation
* @throws UnsupportedOperationException if JCE's implementation does not
* support such operation
*/
@Override
public void updateAAD(byte[] aad) {
cipher.updateAAD(aad);
}

/**
* Continues a multi-part update of the Additional Authentication
* Data (AAD).
* <p>
* Calls to this method provide AAD to the cipher when operating in
* modes such as AEAD (GCM/CCM). If this cipher is operating in
* either GCM or CCM mode, all AAD must be supplied before beginning
* operations on the ciphertext (via the {@code update} and
* {@code doFinal} methods).
*
* @param aad the buffer containing the Additional Authentication Data
*
* @throws IllegalArgumentException if the {@code aad}
* byte array is null
* @throws IllegalStateException if this cipher is in a wrong state
* (e.g., has not been initialized), does not accept AAD, or if
* operating in either GCM or CCM mode and one of the {@code update}
* methods has already been called for the active
* encryption/decryption operation
* @throws UnsupportedOperationException if JCE's implementation does not
* support such operation
*/
@Override
public void updateAAD(ByteBuffer aad) {
cipher.updateAAD(aad);
}


/**
* Closes Jce cipher.
*/
Expand Down
119 changes: 69 additions & 50 deletions src/main/java/org/apache/commons/crypto/cipher/OpenSsl.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
package org.apache.commons.crypto.cipher;

import java.nio.ByteBuffer;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.AlgorithmParameterSpec;
import java.util.StringTokenizer;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
Expand All @@ -34,13 +36,15 @@
*/
final class OpenSsl {

OpenSslFeedbackCipher opensslBlockCipher;

// Mode constant defined by OpenSsl JNI
public static final int ENCRYPT_MODE = 1;
public static final int DECRYPT_MODE = 0;

/** Currently only support AES/CTR/NoPadding. */
private static enum AlgorithmMode {
AES_CTR, AES_CBC;
AES_CTR, AES_CBC, AES_GCM;

/**
* Gets the mode.
Expand Down Expand Up @@ -82,10 +86,6 @@ static int get(String padding) throws NoSuchPaddingException {
}
}

private long context = 0;
private final int algorithm;
private final int padding;

private static final Throwable loadingFailureReason;

static {
Expand Down Expand Up @@ -122,9 +122,11 @@ public static Throwable getLoadingFailureReason() {
* @param padding the padding.
*/
private OpenSsl(long context, int algorithm, int padding) {
this.context = context;
this.algorithm = algorithm;
this.padding = padding;
if (algorithm == AlgorithmMode.AES_GCM.ordinal()) {
opensslBlockCipher = new OpenSslGaloisCounterMode(context, algorithm, padding);
} else {
opensslBlockCipher = new OpenSslCommonMode(context, algorithm, padding);
}
}

/**
Expand Down Expand Up @@ -210,11 +212,13 @@ private static Transform tokenizeTransformation(String transformation)
*
* @param mode {@link #ENCRYPT_MODE} or {@link #DECRYPT_MODE}
* @param key crypto key
* @param iv crypto iv
* @param params the algorithm parameters
* @throws InvalidAlgorithmParameterException if IV length is wrong
*/
public void init(int mode, byte[] key, byte[] iv) {
context = OpenSslNative
.init(context, mode, algorithm, padding, key, iv);
public void init(int mode, byte[] key, AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException {
checkState();
opensslBlockCipher.init(mode, key, params);
}

/**
Expand Down Expand Up @@ -250,12 +254,7 @@ public int update(ByteBuffer input, ByteBuffer output)
checkState();
Utils.checkArgument(input.isDirect() && output.isDirect(),
"Direct buffers are required.");
int len = OpenSslNative.update(context, input, input.position(),
input.remaining(), output, output.position(),
output.remaining());
input.position(input.limit());
output.position(output.position() + len);
return len;
return opensslBlockCipher.update(input, output);
}

/**
Expand All @@ -274,8 +273,37 @@ public int update(ByteBuffer input, ByteBuffer output)
public int update(byte[] input, int inputOffset, int inputLen,
byte[] output, int outputOffset) throws ShortBufferException {
checkState();
return OpenSslNative.updateByteArray(context, input, inputOffset,
inputLen, output, outputOffset, output.length - outputOffset);
return opensslBlockCipher.update(input, inputOffset, inputLen, output, outputOffset);
}

/**
* Encrypts or decrypts data in a single-part operation, or finishes a
* multiple-part operation.
*
* @param input the input byte array
* @param inputOffset the offset in input where the input starts
* @param inputLen the input length
* @param output the byte array for the result
* @param outputOffset the offset in output where the result is stored
* @return the number of bytes stored in output
* @throws ShortBufferException if the given output byte array is too small
* to hold the result
* @throws BadPaddingException if this cipher is in decryption mode, and
* (un)padding has been requested, but the decrypted data is not
* bounded by the appropriate padding bytes
* @throws IllegalBlockSizeException if this cipher is a block cipher, no
* padding has been requested (only in encryption mode), and the
* total input length of the data processed by this cipher is not a
* multiple of block size; or if this encryption algorithm is unable
* to process the input data provided.
*/
public int doFinal(byte[] input, int inputOffset, int inputLen,
byte[] output, int outputOffset)
throws ShortBufferException, IllegalBlockSizeException,
BadPaddingException{

checkState();
return opensslBlockCipher.doFinal(input, inputOffset, inputLen, output, outputOffset);
}

/**
Expand Down Expand Up @@ -304,6 +332,7 @@ public int update(byte[] input, int inputOffset, int inputLen,
* If any exception is thrown, this cipher object need to be reset before it
* can be used again.
*
* @param input the input ByteBuffer
* @param output the output ByteBuffer
* @return int number of bytes stored in <code>output</code>
* @throws ShortBufferException if the given output byte array is too small
Expand All @@ -317,53 +346,43 @@ public int update(byte[] input, int inputOffset, int inputLen,
* (un)padding has been requested, but the decrypted data is not
* bounded by the appropriate padding bytes
*/
public int doFinal(ByteBuffer output) throws ShortBufferException,
public int doFinal(ByteBuffer input, ByteBuffer output) throws ShortBufferException,
IllegalBlockSizeException, BadPaddingException {
checkState();
Utils.checkArgument(output.isDirect(), "Direct buffer is required.");
int len = OpenSslNative.doFinal(context, output, output.position(),
output.remaining());
output.position(output.position() + len);
return len;

return opensslBlockCipher.doFinal(input, output);
}


/**
* Encrypts or decrypts data in a single-part operation, or finishes a
* multiple-part operation.
* Continues a multi-part update of the Additional Authentication
* Data (AAD).
* <p>
* Calls to this method provide AAD to the cipher when operating in
* modes such as AEAD (GCM). If this cipher is operating in
* either GCM mode, all AAD must be supplied before beginning
* operations on the ciphertext (via the {@code update} and
* {@code doFinal} methods).
*
* @param aad the buffer containing the Additional Authentication Data
*
* @param output the byte array for the result
* @param outputOffset the offset in output where the result is stored
* @return the number of bytes stored in output
* @throws ShortBufferException if the given output byte array is too small
* to hold the result
* @throws BadPaddingException if this cipher is in decryption mode, and
* (un)padding has been requested, but the decrypted data is not
* bounded by the appropriate padding bytes
* @throws IllegalBlockSizeException if this cipher is a block cipher, no
* padding has been requested (only in encryption mode), and the
* total input length of the data processed by this cipher is not a
* multiple of block size; or if this encryption algorithm is unable
* to process the input data provided.
*/
public int doFinal(byte[] output, int outputOffset)
throws ShortBufferException, IllegalBlockSizeException,
BadPaddingException {
checkState();
return OpenSslNative.doFinalByteArray(context, output, outputOffset,
output.length - outputOffset);
public void updateAAD(byte[] aad) {
this.opensslBlockCipher.updateAAD(aad);
}


/** Forcibly clean the context. */
public void clean() {
if (context != 0) {
OpenSslNative.clean(context);
context = 0;
if (opensslBlockCipher != null) {
opensslBlockCipher.clean();
}
}

/** Checks whether context is initialized. */
private void checkState() {
Utils.checkState(context != 0);
Utils.checkState(opensslBlockCipher != null);
}

@Override
Expand Down
Loading

0 comments on commit aad8c55

Please sign in to comment.