From 839a8d3bc6bc285d55d61d3cea0253d4ae2c9cca Mon Sep 17 00:00:00 2001 From: kellyzly Date: Mon, 25 Dec 2017 13:07:40 +0800 Subject: [PATCH 1/2] add support to GCM --- .../crypto/stream/CryptoInputStream.java | 46 ++++++++++++++--- .../crypto/stream/CryptoOutputStream.java | 3 +- .../crypto/stream/input/ChannelInput.java | 17 +++++++ .../crypto/cipher/AbstractCipherTest.java | 1 + .../jna/CbcNoPaddingCipherJnaStreamTest.java | 4 ++ .../CbcPkcs5PaddingCipherJnaStreamTest.java | 4 ++ .../crypto/jna/CtrCryptoJnaStreamTest.java | 4 +- .../jna/CtrNoPaddingCipherJnaStreamTest.java | 3 ++ .../stream/AbstractCipherStreamTest.java | 15 +++--- .../stream/CbcNoPaddingCipherStreamTest.java | 3 ++ .../CbcPkcs5PaddingCipherStreamTest.java | 3 ++ .../crypto/stream/CtrCryptoStreamTest.java | 3 ++ .../stream/CtrNoPaddingCipherStreamTest.java | 2 + .../stream/GcmNoPaddingCipherStreamTest.java | 51 +++++++++++++++++++ 14 files changed, 142 insertions(+), 17 deletions(-) create mode 100644 src/test/java/org/apache/commons/crypto/stream/GcmNoPaddingCipherStreamTest.java diff --git a/src/main/java/org/apache/commons/crypto/stream/CryptoInputStream.java b/src/main/java/org/apache/commons/crypto/stream/CryptoInputStream.java index a7f76229b..87c81cf5c 100644 --- a/src/main/java/org/apache/commons/crypto/stream/CryptoInputStream.java +++ b/src/main/java/org/apache/commons/crypto/stream/CryptoInputStream.java @@ -31,6 +31,7 @@ import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.ShortBufferException; +import javax.crypto.spec.GCMParameterSpec; import javax.crypto.spec.IvParameterSpec; import org.apache.commons.crypto.Crypto; @@ -174,6 +175,22 @@ protected CryptoInputStream(ReadableByteChannel in, CryptoCipher cipher, this(new ChannelInput(in), cipher, bufferSize, key, params); } + /** + * Constructs a {@link CryptoInputStream}. + * + * @param in the ReadableByteChannel instance. + * @param cipher the cipher instance. + * @param bufferSize the bufferSize. + * @param key crypto key for the cipher. + * @param params the algorithm parameters. + * @throws IOException if an I/O error occurs. + */ + protected CryptoInputStream(ReadableByteChannel in, CryptoCipher cipher, + int bufferSize, Key key, AlgorithmParameterSpec params,int dateSize) + throws IOException { + this(new ChannelInput(in,dateSize), cipher, bufferSize, key, params); + } + /** * Constructs a {@link CryptoInputStream}. * @@ -192,15 +209,16 @@ protected CryptoInputStream(Input input, CryptoCipher cipher, int bufferSize, this.key = key; this.params = params; - if (!(params instanceof IvParameterSpec)) { - // other AlgorithmParameterSpec such as GCMParameterSpec is not - // supported now. + if (params instanceof IvParameterSpec){ + outBuffer = ByteBuffer.allocateDirect(this.bufferSize + + cipher.getBlockSize()); + }else if (params instanceof GCMParameterSpec){ + outBuffer = ByteBuffer.allocateDirect(input.available()); + }else { throw new IOException("Illegal parameters"); } inBuffer = ByteBuffer.allocateDirect(this.bufferSize); - outBuffer = ByteBuffer.allocateDirect(this.bufferSize - + cipher.getBlockSize()); outBuffer.limit(0); initCipher(); @@ -412,7 +430,7 @@ public int read(ByteBuffer dst) throws IOException { // Decrypt more data // we loop for new data int nd = 0; - while (nd == 0) { + while (nd == 0 && !finalDone) { nd = decryptMore(); } @@ -511,6 +529,8 @@ protected int decryptMore() throws IOException { } int n = input.read(inBuffer); + + //if it is used of gmac ,it must dofinal though decryptFinal if (n < 0) { // The stream is end, finalize the cipher stream decryptFinal(); @@ -523,10 +543,20 @@ protected int decryptMore() throws IOException { // End of the stream return -1; - } else if (n == 0) { + } else if (n == 0 && !(params instanceof GCMParameterSpec)) { // No data is read, but the stream is not end yet return 0; - } else { + } else if (n < bufferSize && (params instanceof GCMParameterSpec)){ + decryptFinal(); + // Satisfy the read with the remaining + int remaining = outBuffer.remaining(); + if (remaining > 0) { + return remaining; + } + + // End of the stream + return -1; + }else { decrypt(); return outBuffer.remaining(); } diff --git a/src/main/java/org/apache/commons/crypto/stream/CryptoOutputStream.java b/src/main/java/org/apache/commons/crypto/stream/CryptoOutputStream.java index 424671344..3eadfa713 100644 --- a/src/main/java/org/apache/commons/crypto/stream/CryptoOutputStream.java +++ b/src/main/java/org/apache/commons/crypto/stream/CryptoOutputStream.java @@ -31,6 +31,7 @@ import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.ShortBufferException; +import javax.crypto.spec.GCMParameterSpec; import javax.crypto.spec.IvParameterSpec; import org.apache.commons.crypto.cipher.CryptoCipher; @@ -177,7 +178,7 @@ protected CryptoOutputStream(Output output, CryptoCipher cipher, this.key = key; this.params = params; - if (!(params instanceof IvParameterSpec)) { + if (!(params instanceof IvParameterSpec) && !(params instanceof GCMParameterSpec)) { // other AlgorithmParameterSpec such as GCMParameterSpec is not // supported now. throw new IOException("Illegal parameters"); diff --git a/src/main/java/org/apache/commons/crypto/stream/input/ChannelInput.java b/src/main/java/org/apache/commons/crypto/stream/input/ChannelInput.java index d85dba17d..e0fcf1fc1 100644 --- a/src/main/java/org/apache/commons/crypto/stream/input/ChannelInput.java +++ b/src/main/java/org/apache/commons/crypto/stream/input/ChannelInput.java @@ -31,6 +31,7 @@ public class ChannelInput implements Input { private ByteBuffer buf; private final ReadableByteChannel channel; + private int channelSize = 0; /** * Constructs the @@ -42,6 +43,18 @@ public ChannelInput(ReadableByteChannel channel) { this.channel = channel; } + /** + * Constructs the + * {@link org.apache.commons.crypto.stream.input.ChannelInput}. + * + * @param channel the ReadableByteChannel object. + * @param channelSize using it to adjust gcm + */ + public ChannelInput(ReadableByteChannel channel,int channelSize) { + this.channel = channel; + this.channelSize = channelSize; + } + /** * Overrides the * {@link org.apache.commons.crypto.stream.input.Input#read(ByteBuffer)}. @@ -99,6 +112,7 @@ public long skip(long n) throws IOException { * single read or skip of this many bytes will not block, but may read or * skip fewer bytes. * + * @author Li,Gongyi * @return an estimate of the number of bytes that can be read (or skipped * over) from this input stream without blocking or {@code 0} when * it reaches the end of the input stream. @@ -106,6 +120,9 @@ public long skip(long n) throws IOException { */ @Override public int available() throws IOException { + if (channelSize != 0){ + return channelSize; + } return 0; } diff --git a/src/test/java/org/apache/commons/crypto/cipher/AbstractCipherTest.java b/src/test/java/org/apache/commons/crypto/cipher/AbstractCipherTest.java index 2e6d0be5f..b721d0ff9 100644 --- a/src/test/java/org/apache/commons/crypto/cipher/AbstractCipherTest.java +++ b/src/test/java/org/apache/commons/crypto/cipher/AbstractCipherTest.java @@ -22,6 +22,7 @@ import java.nio.ByteBuffer; import java.security.GeneralSecurityException; import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; import java.util.Properties; import java.util.Random; diff --git a/src/test/java/org/apache/commons/crypto/jna/CbcNoPaddingCipherJnaStreamTest.java b/src/test/java/org/apache/commons/crypto/jna/CbcNoPaddingCipherJnaStreamTest.java index 98c17e17a..4eb9aca8f 100644 --- a/src/test/java/org/apache/commons/crypto/jna/CbcNoPaddingCipherJnaStreamTest.java +++ b/src/test/java/org/apache/commons/crypto/jna/CbcNoPaddingCipherJnaStreamTest.java @@ -17,12 +17,16 @@ */ package org.apache.commons.crypto.jna; +import javax.crypto.spec.IvParameterSpec; import java.io.IOException; +import java.security.spec.AlgorithmParameterSpec; public class CbcNoPaddingCipherJnaStreamTest extends AbstractCipherJnaStreamTest { @Override public void setUp() throws IOException { transformation = "AES/CBC/NoPadding"; + super.algorithmParameterSpec = new IvParameterSpec(iv); } + } diff --git a/src/test/java/org/apache/commons/crypto/jna/CbcPkcs5PaddingCipherJnaStreamTest.java b/src/test/java/org/apache/commons/crypto/jna/CbcPkcs5PaddingCipherJnaStreamTest.java index 8ebc0811c..3ac313b12 100644 --- a/src/test/java/org/apache/commons/crypto/jna/CbcPkcs5PaddingCipherJnaStreamTest.java +++ b/src/test/java/org/apache/commons/crypto/jna/CbcPkcs5PaddingCipherJnaStreamTest.java @@ -17,13 +17,17 @@ */ package org.apache.commons.crypto.jna; +import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.IvParameterSpec; import java.io.IOException; +import java.security.spec.AlgorithmParameterSpec; public class CbcPkcs5PaddingCipherJnaStreamTest extends AbstractCipherJnaStreamTest { @Override public void setUp() throws IOException { transformation = "AES/CBC/PKCS5Padding"; + algorithmParameterSpec = new IvParameterSpec(iv); } } diff --git a/src/test/java/org/apache/commons/crypto/jna/CtrCryptoJnaStreamTest.java b/src/test/java/org/apache/commons/crypto/jna/CtrCryptoJnaStreamTest.java index 6cb39df1b..9fb457e81 100644 --- a/src/test/java/org/apache/commons/crypto/jna/CtrCryptoJnaStreamTest.java +++ b/src/test/java/org/apache/commons/crypto/jna/CtrCryptoJnaStreamTest.java @@ -17,14 +17,16 @@ */ package org.apache.commons.crypto.jna; +import javax.crypto.spec.IvParameterSpec; import java.io.IOException; +import java.security.spec.AlgorithmParameterSpec; public class CtrCryptoJnaStreamTest extends AbstractCipherJnaStreamTest { @Override public void setUp() throws IOException { transformation = "AES/CTR/NoPadding"; + algorithmParameterSpec = new IvParameterSpec(iv); } - } diff --git a/src/test/java/org/apache/commons/crypto/jna/CtrNoPaddingCipherJnaStreamTest.java b/src/test/java/org/apache/commons/crypto/jna/CtrNoPaddingCipherJnaStreamTest.java index d615a65b8..4023c8c3c 100644 --- a/src/test/java/org/apache/commons/crypto/jna/CtrNoPaddingCipherJnaStreamTest.java +++ b/src/test/java/org/apache/commons/crypto/jna/CtrNoPaddingCipherJnaStreamTest.java @@ -17,13 +17,16 @@ */ package org.apache.commons.crypto.jna; +import javax.crypto.spec.IvParameterSpec; import java.io.IOException; +import java.security.spec.AlgorithmParameterSpec; public class CtrNoPaddingCipherJnaStreamTest extends AbstractCipherJnaStreamTest { @Override public void setUp() throws IOException { transformation = "AES/CTR/NoPadding"; + algorithmParameterSpec = new IvParameterSpec(iv); } } diff --git a/src/test/java/org/apache/commons/crypto/stream/AbstractCipherStreamTest.java b/src/test/java/org/apache/commons/crypto/stream/AbstractCipherStreamTest.java index e5873704e..6d62faf54 100644 --- a/src/test/java/org/apache/commons/crypto/stream/AbstractCipherStreamTest.java +++ b/src/test/java/org/apache/commons/crypto/stream/AbstractCipherStreamTest.java @@ -28,6 +28,8 @@ import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.util.Arrays; import java.util.Properties; import java.util.Random; import javax.crypto.spec.IvParameterSpec; @@ -52,6 +54,7 @@ public abstract class AbstractCipherStreamTest { protected int count = 10000; protected static int defaultBufferSize = 8192; protected static int smallBufferSize = 1024; + protected AlgorithmParameterSpec algorithmParameterSpec; protected String transformation; @@ -72,7 +75,6 @@ public void before() throws IOException { public void testSkip() throws Exception { doSkipTest(AbstractCipherTest.JCE_CIPHER_CLASSNAME, false); doSkipTest(AbstractCipherTest.OPENSSL_CIPHER_CLASSNAME, false); - doSkipTest(AbstractCipherTest.JCE_CIPHER_CLASSNAME, true); doSkipTest(AbstractCipherTest.OPENSSL_CIPHER_CLASSNAME, true); } @@ -82,7 +84,6 @@ public void testSkip() throws Exception { public void testByteBufferRead() throws Exception { doByteBufferRead(AbstractCipherTest.JCE_CIPHER_CLASSNAME, false); doByteBufferRead(AbstractCipherTest.OPENSSL_CIPHER_CLASSNAME, false); - doByteBufferRead(AbstractCipherTest.JCE_CIPHER_CLASSNAME, true); doByteBufferRead(AbstractCipherTest.OPENSSL_CIPHER_CLASSNAME, true); } @@ -263,7 +264,7 @@ private void prepareData() throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); try (OutputStream out = new CryptoOutputStream(baos, cipher, defaultBufferSize, new SecretKeySpec(key, "AES"), - new IvParameterSpec(iv))) { + algorithmParameterSpec)) { out.write(data); out.flush(); } @@ -276,10 +277,10 @@ protected CryptoInputStream getCryptoInputStream(ByteArrayInputStream bais, if (withChannel) { return new CryptoInputStream(Channels.newChannel(bais), cipher, bufferSize, new SecretKeySpec(key, "AES"), - new IvParameterSpec(iv)); + algorithmParameterSpec); } return new CryptoInputStream(bais, cipher, bufferSize, - new SecretKeySpec(key, "AES"), new IvParameterSpec(iv)); + new SecretKeySpec(key, "AES"), algorithmParameterSpec); } protected CryptoOutputStream getCryptoOutputStream( @@ -288,10 +289,10 @@ protected CryptoOutputStream getCryptoOutputStream( if (withChannel) { return new CryptoOutputStream(Channels.newChannel(baos), cipher, bufferSize, new SecretKeySpec(key, "AES"), - new IvParameterSpec(iv)); + algorithmParameterSpec); } return new CryptoOutputStream(baos, cipher, bufferSize, - new SecretKeySpec(key, "AES"), new IvParameterSpec(iv)); + new SecretKeySpec(key, "AES"), algorithmParameterSpec); } private int readAll(InputStream in, byte[] b, int offset, int len) diff --git a/src/test/java/org/apache/commons/crypto/stream/CbcNoPaddingCipherStreamTest.java b/src/test/java/org/apache/commons/crypto/stream/CbcNoPaddingCipherStreamTest.java index d5a0de799..14b5877d7 100644 --- a/src/test/java/org/apache/commons/crypto/stream/CbcNoPaddingCipherStreamTest.java +++ b/src/test/java/org/apache/commons/crypto/stream/CbcNoPaddingCipherStreamTest.java @@ -17,13 +17,16 @@ */ package org.apache.commons.crypto.stream; +import javax.crypto.spec.IvParameterSpec; import java.io.IOException; +import java.security.spec.AlgorithmParameterSpec; public class CbcNoPaddingCipherStreamTest extends AbstractCipherStreamTest { @Override public void setUp() throws IOException { transformation = "AES/CBC/NoPadding"; + algorithmParameterSpec = new IvParameterSpec(super.iv); } } diff --git a/src/test/java/org/apache/commons/crypto/stream/CbcPkcs5PaddingCipherStreamTest.java b/src/test/java/org/apache/commons/crypto/stream/CbcPkcs5PaddingCipherStreamTest.java index ebe3f608a..888a9e57c 100644 --- a/src/test/java/org/apache/commons/crypto/stream/CbcPkcs5PaddingCipherStreamTest.java +++ b/src/test/java/org/apache/commons/crypto/stream/CbcPkcs5PaddingCipherStreamTest.java @@ -17,6 +17,8 @@ */ package org.apache.commons.crypto.stream; +import javax.crypto.spec.IvParameterSpec; +import javax.swing.plaf.SeparatorUI; import java.io.IOException; public class CbcPkcs5PaddingCipherStreamTest extends AbstractCipherStreamTest { @@ -24,5 +26,6 @@ public class CbcPkcs5PaddingCipherStreamTest extends AbstractCipherStreamTest { @Override public void setUp() throws IOException { transformation = "AES/CBC/PKCS5Padding"; + algorithmParameterSpec = new IvParameterSpec(super.iv); } } diff --git a/src/test/java/org/apache/commons/crypto/stream/CtrCryptoStreamTest.java b/src/test/java/org/apache/commons/crypto/stream/CtrCryptoStreamTest.java index 7b9c12b1b..240b45a7a 100644 --- a/src/test/java/org/apache/commons/crypto/stream/CtrCryptoStreamTest.java +++ b/src/test/java/org/apache/commons/crypto/stream/CtrCryptoStreamTest.java @@ -24,11 +24,14 @@ import org.apache.commons.crypto.cipher.CryptoCipher; +import javax.crypto.spec.IvParameterSpec; + public class CtrCryptoStreamTest extends AbstractCipherStreamTest { @Override public void setUp() throws IOException { transformation = "AES/CTR/NoPadding"; + algorithmParameterSpec = new IvParameterSpec(super.iv); } @Override diff --git a/src/test/java/org/apache/commons/crypto/stream/CtrNoPaddingCipherStreamTest.java b/src/test/java/org/apache/commons/crypto/stream/CtrNoPaddingCipherStreamTest.java index 376a56b64..6c5128db5 100644 --- a/src/test/java/org/apache/commons/crypto/stream/CtrNoPaddingCipherStreamTest.java +++ b/src/test/java/org/apache/commons/crypto/stream/CtrNoPaddingCipherStreamTest.java @@ -17,6 +17,7 @@ */ package org.apache.commons.crypto.stream; +import javax.crypto.spec.IvParameterSpec; import java.io.IOException; public class CtrNoPaddingCipherStreamTest extends AbstractCipherStreamTest { @@ -24,6 +25,7 @@ public class CtrNoPaddingCipherStreamTest extends AbstractCipherStreamTest { @Override public void setUp() throws IOException { transformation = "AES/CTR/NoPadding"; + algorithmParameterSpec = new IvParameterSpec(super.iv); } } diff --git a/src/test/java/org/apache/commons/crypto/stream/GcmNoPaddingCipherStreamTest.java b/src/test/java/org/apache/commons/crypto/stream/GcmNoPaddingCipherStreamTest.java new file mode 100644 index 000000000..2500de3d7 --- /dev/null +++ b/src/test/java/org/apache/commons/crypto/stream/GcmNoPaddingCipherStreamTest.java @@ -0,0 +1,51 @@ +package org.apache.commons.crypto.stream; + +import org.apache.commons.crypto.cipher.CryptoCipher; + +import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.channels.Channel; +import java.nio.channels.Channels; +import java.security.spec.AlgorithmParameterSpec; + +public class GcmNoPaddingCipherStreamTest extends AbstractCipherStreamTest{ + + private int tLen ; + + @Override + public void setUp() throws IOException { + transformation = "AES/GCM/NoPadding"; + tLen = 128; //the verification bit is 16 bytes. + algorithmParameterSpec = new GCMParameterSpec(tLen,super.iv,0,12); + } + + protected CryptoInputStream getCryptoInputStream(ByteArrayInputStream bais, + CryptoCipher cipher, int bufferSize, byte[] iv, boolean withChannel) + throws IOException { + if (withChannel) { + return new CryptoInputStream(Channels.newChannel(bais), cipher, + bufferSize, new SecretKeySpec(key, "AES"), + super.algorithmParameterSpec,bais.available()); + } + return new CryptoInputStream(bais, cipher, bufferSize, + new SecretKeySpec(key, "AES"), super.algorithmParameterSpec); + } + + protected CryptoOutputStream getCryptoOutputStream( + ByteArrayOutputStream baos, CryptoCipher cipher, int bufferSize, + byte[] iv, boolean withChannel) throws IOException { + if (withChannel) { + return new CryptoOutputStream(Channels.newChannel(baos), cipher, + bufferSize, new SecretKeySpec(key, "AES"), + super.algorithmParameterSpec); + } + return new CryptoOutputStream(baos, cipher, bufferSize, + new SecretKeySpec(key, "AES"), super.algorithmParameterSpec); + } + +} From f5aaaa690d499cd724c30d18791b0d57a7fe679e Mon Sep 17 00:00:00 2001 From: kellyzly Date: Mon, 25 Dec 2017 16:14:35 +0800 Subject: [PATCH 2/2] support to gcm --- .../java/org/apache/commons/crypto/stream/input/Input.java | 1 + .../org/apache/commons/crypto/stream/input/StreamInput.java | 2 ++ .../commons/crypto/jna/AbstractCipherJnaStreamTest.java | 4 +++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/apache/commons/crypto/stream/input/Input.java b/src/main/java/org/apache/commons/crypto/stream/input/Input.java index fff7e1dfb..8ccf2949a 100644 --- a/src/main/java/org/apache/commons/crypto/stream/input/Input.java +++ b/src/main/java/org/apache/commons/crypto/stream/input/Input.java @@ -134,4 +134,5 @@ int read(long position, byte[] buffer, int offset, int length) * @throws IOException if an I/O error occurs. */ void close() throws IOException; + } diff --git a/src/main/java/org/apache/commons/crypto/stream/input/StreamInput.java b/src/main/java/org/apache/commons/crypto/stream/input/StreamInput.java index cbbcb9ac0..4d24dd96a 100644 --- a/src/main/java/org/apache/commons/crypto/stream/input/StreamInput.java +++ b/src/main/java/org/apache/commons/crypto/stream/input/StreamInput.java @@ -17,6 +17,7 @@ */ package org.apache.commons.crypto.stream.input; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; @@ -157,4 +158,5 @@ public void seek(long position) throws IOException { public void close() throws IOException { in.close(); } + } diff --git a/src/test/java/org/apache/commons/crypto/jna/AbstractCipherJnaStreamTest.java b/src/test/java/org/apache/commons/crypto/jna/AbstractCipherJnaStreamTest.java index 5770a3f11..f9efbbc11 100644 --- a/src/test/java/org/apache/commons/crypto/jna/AbstractCipherJnaStreamTest.java +++ b/src/test/java/org/apache/commons/crypto/jna/AbstractCipherJnaStreamTest.java @@ -18,6 +18,8 @@ package org.apache.commons.crypto.jna; import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.security.spec.AlgorithmParameterSpec; import org.apache.commons.crypto.cipher.AbstractCipherTest; import org.apache.commons.crypto.stream.AbstractCipherStreamTest; @@ -30,7 +32,7 @@ public abstract class AbstractCipherJnaStreamTest extends AbstractCipherStreamTe private static final String CIPHER_OPENSSL_JNA = OpenSslJna.getCipherClass().getName(); @Before - public void init() { + public void init() throws IOException{ Assume.assumeTrue(OpenSslJna.isEnabled()); }