You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by se...@apache.org on 2016/06/28 12:35:34 UTC
commons-crypto git commit: CRYPTO-63 Add JNA binding
Repository: commons-crypto
Updated Branches:
refs/heads/master 2a585651d -> b6006e563
CRYPTO-63 Add JNA binding
Adapted from PR https://github.com/apache/commons-crypto/pull/47
Made classes package-protected
TODO benchmarking
Project: http://git-wip-us.apache.org/repos/asf/commons-crypto/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-crypto/commit/b6006e56
Tree: http://git-wip-us.apache.org/repos/asf/commons-crypto/tree/b6006e56
Diff: http://git-wip-us.apache.org/repos/asf/commons-crypto/diff/b6006e56
Branch: refs/heads/master
Commit: b6006e563f63c745c964a87fae459200ae24573b
Parents: 2a58565
Author: Sebb <se...@apache.org>
Authored: Tue Jun 28 13:35:30 2016 +0100
Committer: Sebb <se...@apache.org>
Committed: Tue Jun 28 13:35:30 2016 +0100
----------------------------------------------------------------------
pom.xml | 6 +
.../commons/crypto/jna/OpensslJnaCipher.java | 331 +++++++++++++++++++
.../crypto/jna/OpensslJnaCryptoRandom.java | 190 +++++++++++
.../commons/crypto/jna/OpensslNativeJna.java | 99 ++++++
.../apache/commons/crypto/jna/package-info.java | 22 ++
.../crypto/cipher/AbstractCipherTest.java | 11 +-
.../crypto/jna/OpensslJnaCipherTest.java | 35 ++
.../crypto/jna/OpensslJnaCryptoRandomTest.java | 47 +++
.../crypto/stream/AbstractCipherStreamTest.java | 13 +
.../stream/PositionedCryptoInputStreamTest.java | 1 +
10 files changed, 753 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/b6006e56/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 6b55286..a549564 100644
--- a/pom.xml
+++ b/pom.xml
@@ -189,6 +189,7 @@ The following provides more details on the included cryptographic software:
<commons.release.version>1.0.0</commons.release.version>
<commons.release.desc>(Requires Java ${maven.compiler.target} or later)</commons.release.desc>
<commons.rc.version>RC1</commons.rc.version>
+ <jna.version>4.2.2</jna.version>
<!-- properties not related to versioning -->
<commons.jira.id>CRYPTO</commons.jira.id>
@@ -535,5 +536,10 @@ The following provides more details on the included cryptographic software:
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>net.java.dev.jna</groupId>
+ <artifactId>jna</artifactId>
+ <version>${jna.version}</version>
+ </dependency>
</dependencies>
</project>
http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/b6006e56/src/main/java/org/apache/commons/crypto/jna/OpensslJnaCipher.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/jna/OpensslJnaCipher.java b/src/main/java/org/apache/commons/crypto/jna/OpensslJnaCipher.java
new file mode 100644
index 0000000..c3ac372
--- /dev/null
+++ b/src/main/java/org/apache/commons/crypto/jna/OpensslJnaCipher.java
@@ -0,0 +1,331 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.crypto.jna;
+
+import java.nio.ByteBuffer;
+import java.security.GeneralSecurityException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Properties;
+import java.util.StringTokenizer;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.IvParameterSpec;
+
+import org.apache.commons.crypto.cipher.CryptoCipher;
+import org.apache.commons.crypto.utils.Utils;
+
+import com.sun.jna.NativeLong;
+import com.sun.jna.ptr.PointerByReference;
+
+/**
+ * Implements the CryptoCipher using JNA into OpenSSL.
+ */
+public class OpensslJnaCipher implements CryptoCipher {
+
+ private final static int AES_BLOCK_SIZE = 16;
+
+ private PointerByReference algo;
+ private final PointerByReference context;
+ private final AlgorithmMode algMode;
+ private final int padding;
+ private final String transformation;
+
+ /**
+ * Constructs a {@link CryptoCipher} using JNA into OpenSSL
+ *
+ * @param props properties for OpenSSL cipher
+ * @param transformation transformation for OpenSSL cipher
+ * @throws GeneralSecurityException if OpenSSL cipher initialize failed
+ */
+ public OpensslJnaCipher(Properties props, String transformation)
+ throws GeneralSecurityException {
+ this.transformation = transformation;
+ Transform transform = tokenizeTransformation(transformation);
+ algMode = AlgorithmMode.get(transform.algorithm, transform.mode);
+
+ if(algMode != AlgorithmMode.AES_CBC && algMode != AlgorithmMode.AES_CTR) {
+ throw new GeneralSecurityException("unknown algorithm "+transform.algorithm + "_" + transform.mode);
+ }
+
+ padding = Padding.get(transform.padding);
+ context = OpensslNativeJna.EVP_CIPHER_CTX_new();
+
+ }
+
+ /**
+ * Initializes the cipher with mode, key and iv.
+ *
+ * @param mode {@link #ENCRYPT_MODE} or {@link #DECRYPT_MODE}
+ * @param key crypto key for the cipher
+ * @param params the algorithm parameters
+ * @throws InvalidKeyException If key length is invalid
+ * @throws InvalidAlgorithmParameterException if IV length is wrong
+ */
+ @Override
+ public void init(int mode, Key key, AlgorithmParameterSpec params)
+ throws InvalidKeyException, InvalidAlgorithmParameterException {
+ Utils.checkNotNull(key);
+ Utils.checkNotNull(params);
+ int cipherMode = OpensslNativeJna.OOSL_JNA_DECRYPT_MODE;
+ if (mode == Cipher.ENCRYPT_MODE) {
+ cipherMode = OpensslNativeJna.OOSL_JNA_ENCRYPT_MODE;
+ }
+ byte[] iv;
+ if (params instanceof IvParameterSpec) {
+ iv = ((IvParameterSpec) params).getIV();
+ } else {
+ // other AlgorithmParameterSpec such as GCMParameterSpec is not
+ // supported now.
+ throw new InvalidAlgorithmParameterException("Illegal parameters");
+ }
+
+ if(algMode == AlgorithmMode.AES_CBC) {
+ switch(key.getEncoded().length) {
+ case 16: algo = OpensslNativeJna.EVP_aes_128_cbc(); break;
+ case 24: algo = OpensslNativeJna.EVP_aes_192_cbc(); break;
+ case 32: algo = OpensslNativeJna.EVP_aes_256_cbc(); break;
+ default: throw new InvalidKeyException("keysize unsupported ("+key.getEncoded().length+")");
+ }
+
+ } else {
+ switch(key.getEncoded().length) {
+ case 16: algo = OpensslNativeJna.EVP_aes_128_ctr(); break;
+ case 24: algo = OpensslNativeJna.EVP_aes_192_ctr(); break;
+ case 32: algo = OpensslNativeJna.EVP_aes_256_ctr(); break;
+ default: throw new InvalidKeyException("keysize unsupported ("+key.getEncoded().length+")");
+ }
+ }
+
+ int retVal = OpensslNativeJna.EVP_CipherInit_ex(context, algo, null, key.getEncoded(), iv, cipherMode);
+ throwOnError(retVal);
+ OpensslNativeJna.EVP_CIPHER_CTX_set_padding(context, padding);
+ }
+
+ /**
+ * Continues a multiple-part encryption/decryption operation. The data is
+ * encrypted or decrypted, depending on how this cipher was initialized.
+ *
+ * @param inBuffer the input ByteBuffer
+ * @param outBuffer the output ByteBuffer
+ * @return int number of bytes stored in <code>output</code>
+ * @throws ShortBufferException if there is insufficient space in the output
+ * buffer
+ */
+ @Override
+ public int update(ByteBuffer inBuffer, ByteBuffer outBuffer)
+ throws ShortBufferException {
+ int[] outlen = new int[1];
+ int retVal = OpensslNativeJna.EVP_CipherUpdate(context, outBuffer, outlen, inBuffer, inBuffer.remaining());
+ throwOnError(retVal);
+ int len = outlen[0];
+ inBuffer.position(inBuffer.limit());
+ outBuffer.position(outBuffer.position() + len);
+ return len;
+ }
+
+ /**
+ * Continues a multiple-part encryption/decryption operation. The data is
+ * encrypted or decrypted, depending on how this cipher was initialized.
+ *
+ * @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 there is insufficient space in the output
+ * byte array
+ */
+ @Override
+ public int update(byte[] input, int inputOffset, int inputLen,
+ byte[] output, int outputOffset) throws ShortBufferException {
+ ByteBuffer outputBuf = ByteBuffer.wrap(output, outputOffset, output.length-outputOffset);
+ ByteBuffer inputBuf = ByteBuffer.wrap(input, inputOffset, inputLen);
+ return update(inputBuf, outputBuf);
+ }
+ /**
+ * Encrypts or decrypts data in a single-part operation, or finishes a
+ * multiple-part operation. The data is encrypted or decrypted, depending on
+ * how this cipher was initialized.
+ *
+ * @param inBuffer the input ByteBuffer
+ * @param outBuffer the output ByteBuffer
+ * @return int number of bytes stored in <code>output</code>
+ * @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.
+ * @throws ShortBufferException if the given output buffer is too small to
+ * hold the result
+ */
+ @Override
+ public int doFinal(ByteBuffer inBuffer, ByteBuffer outBuffer)
+ throws ShortBufferException, IllegalBlockSizeException,
+ BadPaddingException {
+ int uptLen = update(inBuffer, outBuffer);
+ int[] outlen = new int[1];
+ int retVal = OpensslNativeJna.EVP_CipherFinal_ex(context, outBuffer, outlen);
+ throwOnError(retVal);
+ int len = uptLen + outlen[0];
+ outBuffer.position(outBuffer.position() + outlen[0]);
+ return len;
+ }
+
+ /**
+ * 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.
+ */
+ @Override
+ public int doFinal(byte[] input, int inputOffset, int inputLen,
+ byte[] output, int outputOffset) throws ShortBufferException,
+ IllegalBlockSizeException, BadPaddingException {
+ ByteBuffer outputBuf = ByteBuffer.wrap(output, outputOffset, output.length-outputOffset);
+ ByteBuffer inputBuf = ByteBuffer.wrap(input, inputOffset, inputLen);
+ return doFinal(inputBuf, outputBuf);
+ }
+
+ /**
+ * Closes the OpenSSL cipher. Clean the Openssl native context.
+ */
+ @Override
+ public void close() {
+ if(context != null) {
+ OpensslNativeJna.EVP_CIPHER_CTX_cleanup(context);
+ OpensslNativeJna.EVP_CIPHER_CTX_free(context);
+ }
+ }
+
+ private void throwOnError(int retVal) {
+ if(retVal != 1) {
+ NativeLong err = OpensslNativeJna.ERR_peek_error();
+ String errdesc = OpensslNativeJna.ERR_error_string(err, null);
+
+ if(context != null) {
+ OpensslNativeJna.EVP_CIPHER_CTX_cleanup(context);
+ }
+ throw new RuntimeException("return code "+retVal+" from openssl. Err code is "+err+": "+errdesc);
+ }
+ }
+
+ //TODO DUPLICATED CODE, needs cleanup
+ /** Nested class for algorithm, mode and padding. */
+ private static class Transform {
+ final String algorithm;
+ final String mode;
+ final String padding;
+
+ public Transform(String algorithm, String mode, String padding) {
+ this.algorithm = algorithm;
+ this.mode = mode;
+ this.padding = padding;
+ }
+ }
+
+ private static Transform tokenizeTransformation(String transformation)
+ throws NoSuchAlgorithmException {
+ if (transformation == null) {
+ throw new NoSuchAlgorithmException("No transformation given.");
+ }
+
+ /*
+ * Array containing the components of a Cipher transformation: index 0:
+ * algorithm (e.g., AES) index 1: mode (e.g., CTR) index 2: padding
+ * (e.g., NoPadding)
+ */
+ String[] parts = new String[3];
+ int count = 0;
+ StringTokenizer parser = new StringTokenizer(transformation, "/");
+ while (parser.hasMoreTokens() && count < 3) {
+ parts[count++] = parser.nextToken().trim();
+ }
+ if (count != 3 || parser.hasMoreTokens()) {
+ throw new NoSuchAlgorithmException(
+ "Invalid transformation format: " + transformation);
+ }
+ return new Transform(parts[0], parts[1], parts[2]);
+ }
+
+ /** Currently only support AES/CTR/NoPadding. */
+ private static enum AlgorithmMode {
+ AES_CTR, AES_CBC;
+
+ static AlgorithmMode get(String algorithm, String mode)
+ throws NoSuchAlgorithmException {
+ try {
+ return AlgorithmMode.valueOf(algorithm + "_" + mode);
+ } catch (Exception e) {
+ throw new NoSuchAlgorithmException(
+ "Doesn't support algorithm: " + algorithm
+ + " and mode: " + mode);
+ }
+ }
+ }
+
+ private static enum Padding {
+ NoPadding, PKCS5Padding;
+
+ static int get(String padding) throws NoSuchPaddingException {
+ try {
+ return Padding.valueOf(padding).ordinal();
+ } catch (Exception e) {
+ throw new NoSuchPaddingException("Doesn't support padding: "
+ + padding);
+ }
+ }
+ }
+
+ @Override
+ public int getBlockSize() {
+ return AES_BLOCK_SIZE;
+ }
+
+ @Override
+ public String getAlgorithm() {
+ return transformation;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/b6006e56/src/main/java/org/apache/commons/crypto/jna/OpensslJnaCryptoRandom.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/jna/OpensslJnaCryptoRandom.java b/src/main/java/org/apache/commons/crypto/jna/OpensslJnaCryptoRandom.java
new file mode 100644
index 0000000..7915d86
--- /dev/null
+++ b/src/main/java/org/apache/commons/crypto/jna/OpensslJnaCryptoRandom.java
@@ -0,0 +1,190 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.crypto.jna;
+
+import java.nio.ByteBuffer;
+import java.security.NoSuchAlgorithmException;
+import java.util.Properties;
+import java.util.Random;
+
+import org.apache.commons.crypto.random.CryptoRandom;
+import org.apache.commons.crypto.utils.Utils;
+
+import com.sun.jna.NativeLong;
+import com.sun.jna.ptr.PointerByReference;
+
+/**
+ * <p>
+ * OpenSSL secure random using JNA. This implementation is thread-safe.
+ * </p>
+ *
+ * <p>
+ * If using an Intel chipset with RDRAND, the high-performance hardware random
+ * number generator will be used and it's much faster than SecureRandom. If
+ * RDRAND is unavailable, default OpenSSL secure random generator will be used.
+ * It's still faster and can generate strong random bytes.
+ * </p>
+ *
+ * @see <a href="https://wiki.openssl.org/index.php/Random_Numbers">
+ * https://wiki.openssl.org/index.php/Random_Numbers</a>
+ * @see <a href="http://en.wikipedia.org/wiki/RdRand">
+ * http://en.wikipedia.org/wiki/RdRand</a>
+ */
+class OpensslJnaCryptoRandom extends Random implements CryptoRandom {
+ private static final long serialVersionUID = -7128193502768749585L;
+ private final boolean rdrandEnabled;
+ private PointerByReference rdrandEngine;
+
+ /**
+ * Constructs a {@link OpensslJnaCryptoRandom}.
+ *
+ * @param props the configuration properties (not used)
+ * @throws NoSuchAlgorithmException if no Provider supports a
+ * SecureRandomSpi implementation for the specified algorithm.
+ */
+ public OpensslJnaCryptoRandom(Properties props)
+ throws NoSuchAlgorithmException {
+
+ boolean rdrandLoaded = false;
+ try {
+ OpensslNativeJna.ENGINE_load_rdrand();
+ rdrandEngine = OpensslNativeJna.ENGINE_by_id("rdrand");
+ int ENGINE_METHOD_RAND = 0x0008;
+ if(rdrandEngine != null) {
+ int rc = OpensslNativeJna.ENGINE_init(rdrandEngine);
+
+ if(rc != 0) {
+ int rc2 = OpensslNativeJna.ENGINE_set_default(rdrandEngine, ENGINE_METHOD_RAND);
+ if(rc2 != 0) {
+ rdrandLoaded = true;
+ }
+ }
+ }
+
+ } catch (Exception e) {
+ throw new NoSuchAlgorithmException();
+ }
+
+ rdrandEnabled = rdrandLoaded;
+
+ if(!rdrandLoaded) {
+ closeRdrandEngine();
+ }
+ }
+
+ /**
+ * Generates a user-specified number of random bytes. It's thread-safe.
+ *
+ * @param bytes the array to be filled in with random bytes.
+ */
+ @Override
+ public void nextBytes(byte[] bytes) {
+
+ synchronized (OpensslJnaCryptoRandom.class) {
+ //this method is synchronized for now
+ //to support multithreading https://wiki.openssl.org/index.php/Manual:Threads(3) needs to be done
+
+ if(rdrandEnabled && OpensslNativeJna.RAND_get_rand_method().equals(OpensslNativeJna.RAND_SSLeay())) {
+ close();
+ throw new RuntimeException("rdrand should be used but default is detected");
+ }
+
+ ByteBuffer buf = ByteBuffer.allocateDirect(bytes.length);
+ int retVal = OpensslNativeJna.RAND_bytes(buf, bytes.length);
+ throwOnError(retVal);
+ buf.rewind();
+ buf.get(bytes,0, bytes.length);
+ }
+ }
+
+ /**
+ * Overrides {@link OpensslJnaCryptoRandom}. For {@link OpensslJnaCryptoRandom},
+ * we don't need to set seed.
+ *
+ * @param seed the initial seed.
+ */
+ @Override
+ public void setSeed(long seed) {
+ // Self-seeding.
+ }
+
+ /**
+ * Overrides Random#next(). Generates an integer containing the
+ * user-specified number of random bits(right justified, with leading
+ * zeros).
+ *
+ * @param numBits number of random bits to be generated, where 0
+ * {@literal <=} <code>numBits</code> {@literal <=} 32.
+ * @return int an <code>int</code> containing the user-specified number of
+ * random bits (right justified, with leading zeros).
+ */
+ @Override
+ final protected int next(int numBits) {
+ Utils.checkArgument(numBits >= 0 && numBits <= 32);
+ int numBytes = (numBits + 7) / 8;
+ byte b[] = new byte[numBytes];
+ int next = 0;
+
+ nextBytes(b);
+ for (int i = 0; i < numBytes; i++) {
+ next = (next << 8) + (b[i] & 0xFF);
+ }
+
+ return next >>> (numBytes * 8 - numBits);
+ }
+
+ /**
+ * Overrides {@link java.lang.AutoCloseable#close()}. Closes openssl context
+ * if native enabled.
+ */
+ @Override
+ public void close() {
+ closeRdrandEngine();
+ OpensslNativeJna.ENGINE_cleanup();
+
+ //cleanup locks
+ //OpensslNativeJna.CRYPTO_set_locking_callback(null);
+ //LOCK.unlock();
+ }
+
+ private void closeRdrandEngine() {
+
+ if(rdrandEngine != null) {
+ OpensslNativeJna.ENGINE_finish(rdrandEngine);
+ OpensslNativeJna.ENGINE_free(rdrandEngine);
+ }
+ }
+
+ /**
+ * Checks if rdrand engine is used to retrieve random bytes
+ *
+ * @return true if rdrand is used, false if default engine is used
+ */
+ public boolean isRdrandEnabled() {
+ return rdrandEnabled;
+ }
+
+ private void throwOnError(int retVal) {
+ if(retVal != 1) {
+ NativeLong err = OpensslNativeJna.ERR_peek_error();
+ String errdesc = OpensslNativeJna.ERR_error_string(err, null);
+ close();
+ throw new RuntimeException("return code "+retVal+" from openssl. Err code is "+err+": "+errdesc);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/b6006e56/src/main/java/org/apache/commons/crypto/jna/OpensslNativeJna.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/jna/OpensslNativeJna.java b/src/main/java/org/apache/commons/crypto/jna/OpensslNativeJna.java
new file mode 100644
index 0000000..5ffa25b
--- /dev/null
+++ b/src/main/java/org/apache/commons/crypto/jna/OpensslNativeJna.java
@@ -0,0 +1,99 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.crypto.jna;
+
+import java.nio.ByteBuffer;
+
+import com.sun.jna.Native;
+import com.sun.jna.NativeLong;
+import com.sun.jna.ptr.PointerByReference;
+
+class OpensslNativeJna {
+
+ static final int OPENSSL_INIT_ENGINE_RDRAND = 0x00000200;
+
+ static final int OOSL_JNA_ENCRYPT_MODE = 1;
+ static final int OOSL_JNA_DECRYPT_MODE = 0;
+
+ static {
+ Native.register("crypto");
+ ERR_load_crypto_strings();
+ }
+
+ //misc
+ public static native NativeLong SSLeay();
+ public static native String SSLeay_version(int type);
+ public static native void ERR_load_crypto_strings();
+ public static native NativeLong ERR_peek_error();
+ public static native String ERR_error_string(NativeLong err, char[] null_);
+ //String ERR_lib_error_string(NativeLong err);
+ //String ERR_func_error_string(NativeLong err);
+ //String ERR_reason_error_string(NativeLong err);
+
+ //en-/decryption
+ public static native PointerByReference EVP_CIPHER_CTX_new();
+ public static native void EVP_CIPHER_CTX_init(PointerByReference p);
+ public static native int EVP_CIPHER_CTX_set_padding(PointerByReference c, int pad);
+ public static native PointerByReference EVP_aes_128_cbc();
+ public static native PointerByReference EVP_aes_128_ctr();
+ public static native PointerByReference EVP_aes_192_cbc();
+ public static native PointerByReference EVP_aes_192_ctr();
+ public static native PointerByReference EVP_aes_256_cbc();
+ public static native PointerByReference EVP_aes_256_ctr();
+ public static native int EVP_CipherInit_ex(PointerByReference ctx, PointerByReference cipher, PointerByReference impl, byte key[], byte iv[], int enc);
+ public static native int EVP_CipherUpdate(PointerByReference ctx, ByteBuffer bout, int[] outl, ByteBuffer in, int inl);
+ public static native int EVP_CipherFinal_ex(PointerByReference ctx, ByteBuffer bout, int[] outl);
+ public static native void EVP_CIPHER_CTX_free(PointerByReference c);
+ public static native void EVP_CIPHER_CTX_cleanup(PointerByReference c);
+
+ //Random generator
+ public static native PointerByReference RAND_get_rand_method();
+ public static native PointerByReference RAND_SSLeay();
+ public static native int RAND_bytes(ByteBuffer buf, int num);
+ public static native int ENGINE_finish(PointerByReference e);
+ public static native int ENGINE_free(PointerByReference e);
+ public static native int ENGINE_cleanup();
+ public static native int ENGINE_init(PointerByReference e);
+ public static native int ENGINE_set_default(PointerByReference e, int flags);
+ public static native PointerByReference ENGINE_by_id(String id);
+ public static native void ENGINE_load_rdrand();
+
+ //TODO callback multithreading
+ /*public interface Id_function_cb extends Callback {
+ long invoke ();
+ }
+
+ public interface Locking_function_cb extends Callback {
+ void invoke(int mode, int n, String file, int line);
+ }
+
+ public static final Id_function_cb default_id_function = new Id_function_cb() {
+
+ @Override
+ public long invoke() {
+ //id always positive
+ long id = Thread.currentThread().getId();
+ return id;
+ }
+ };
+
+ int CRYPTO_num_locks();
+ void CRYPTO_set_id_callback(Id_function_cb id_function);
+ void CRYPTO_set_locking_callback(Locking_function_cb locking_function);*/
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/b6006e56/src/main/java/org/apache/commons/crypto/jna/package-info.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/crypto/jna/package-info.java b/src/main/java/org/apache/commons/crypto/jna/package-info.java
new file mode 100644
index 0000000..9254491
--- /dev/null
+++ b/src/main/java/org/apache/commons/crypto/jna/package-info.java
@@ -0,0 +1,22 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * JNA classes
+ */
+package org.apache.commons.crypto.jna;
+
http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/b6006e56/src/test/java/org/apache/commons/crypto/cipher/AbstractCipherTest.java
----------------------------------------------------------------------
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 aa95db0..2f79335 100644
--- a/src/test/java/org/apache/commons/crypto/cipher/AbstractCipherTest.java
+++ b/src/test/java/org/apache/commons/crypto/cipher/AbstractCipherTest.java
@@ -17,6 +17,8 @@
*/
package org.apache.commons.crypto.cipher;
+import static org.junit.Assert.assertNotNull;
+
import java.nio.ByteBuffer;
import java.security.GeneralSecurityException;
import java.security.SecureRandom;
@@ -29,6 +31,7 @@ import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import org.apache.commons.crypto.conf.ConfigurationKeys;
+import org.apache.commons.crypto.jna.OpensslJnaCipher;
import org.apache.commons.crypto.utils.ReflectionUtils;
import org.apache.commons.crypto.utils.Utils;
import org.junit.Assert;
@@ -41,12 +44,15 @@ public abstract class AbstractCipherTest {
public static final String JCE_CIPHER_CLASSNAME = JceCipher.class.getName();
+ public static final String OPENSSLJNA_CIPHER_CLASSNAME = OpensslJnaCipher.class.getName();
+
// data
public static final int BYTEBUFFER_SIZE = 1000;
+
public String[] cipherTests = null;
Properties props = null;
- String cipherClass = null;
- String[] transformations = null;
+ protected String cipherClass = null;
+ protected String[] transformations = null;
// cipher
static final byte[] KEY = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
@@ -72,6 +78,7 @@ public abstract class AbstractCipherTest {
for (String tran : transformations) {
/** uses the small data set in {@link TestData} */
cipherTests = TestData.getTestData(tran);
+ assertNotNull(tran, cipherTests);
for (int i = 0; i != cipherTests.length; i += 5) {
byte[] key = DatatypeConverter
.parseHexBinary(cipherTests[i + 1]);
http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/b6006e56/src/test/java/org/apache/commons/crypto/jna/OpensslJnaCipherTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/crypto/jna/OpensslJnaCipherTest.java b/src/test/java/org/apache/commons/crypto/jna/OpensslJnaCipherTest.java
new file mode 100644
index 0000000..8416484
--- /dev/null
+++ b/src/test/java/org/apache/commons/crypto/jna/OpensslJnaCipherTest.java
@@ -0,0 +1,35 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.crypto.jna;
+
+import org.apache.commons.crypto.cipher.AbstractCipherTest;
+import org.apache.commons.crypto.jna.OpensslJnaCipher;
+
+public class OpensslJnaCipherTest extends AbstractCipherTest {
+
+ @Override
+ public void init() {
+ transformations = new String[] {
+ "AES/CBC/NoPadding",
+ "AES/CBC/PKCS5Padding",
+ "AES/CTR/NoPadding"
+ };
+ cipherClass = OpensslJnaCipher.class.getName();
+ }
+}
http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/b6006e56/src/test/java/org/apache/commons/crypto/jna/OpensslJnaCryptoRandomTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/crypto/jna/OpensslJnaCryptoRandomTest.java b/src/test/java/org/apache/commons/crypto/jna/OpensslJnaCryptoRandomTest.java
new file mode 100644
index 0000000..455bc28
--- /dev/null
+++ b/src/test/java/org/apache/commons/crypto/jna/OpensslJnaCryptoRandomTest.java
@@ -0,0 +1,47 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.crypto.jna;
+
+import java.security.GeneralSecurityException;
+import java.util.Properties;
+
+import org.apache.commons.crypto.conf.ConfigurationKeys;
+import org.apache.commons.crypto.jna.OpensslJnaCryptoRandom;
+import org.apache.commons.crypto.random.AbstractRandomTest;
+import org.apache.commons.crypto.random.CryptoRandom;
+import org.apache.commons.crypto.random.CryptoRandomFactory;
+
+import static junit.framework.Assert.fail;
+
+public class OpensslJnaCryptoRandomTest extends AbstractRandomTest {
+
+ @Override
+ public CryptoRandom getCryptoRandom() throws GeneralSecurityException {
+ Properties props = new Properties();
+ props.setProperty(
+ ConfigurationKeys.SECURE_RANDOM_CLASSES_KEY,
+ OpensslJnaCryptoRandom.class.getName());
+ CryptoRandom random = CryptoRandomFactory.getCryptoRandom(props);
+ if (!(random instanceof OpensslJnaCryptoRandom)) {
+ fail("The CryptoRandom should be: "
+ + OpensslJnaCryptoRandom.class.getName());
+ }
+ return random;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/b6006e56/src/test/java/org/apache/commons/crypto/stream/AbstractCipherStreamTest.java
----------------------------------------------------------------------
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 34274e4..25b8e95 100644
--- a/src/test/java/org/apache/commons/crypto/stream/AbstractCipherStreamTest.java
+++ b/src/test/java/org/apache/commons/crypto/stream/AbstractCipherStreamTest.java
@@ -71,9 +71,11 @@ public abstract class AbstractCipherStreamTest {
public void testSkip() throws Exception {
doSkipTest(AbstractCipherTest.JCE_CIPHER_CLASSNAME, false);
doSkipTest(AbstractCipherTest.OPENSSL_CIPHER_CLASSNAME, false);
+ doSkipTest(AbstractCipherTest.OPENSSLJNA_CIPHER_CLASSNAME, false);
doSkipTest(AbstractCipherTest.JCE_CIPHER_CLASSNAME, true);
doSkipTest(AbstractCipherTest.OPENSSL_CIPHER_CLASSNAME, true);
+ doSkipTest(AbstractCipherTest.OPENSSLJNA_CIPHER_CLASSNAME, true);
}
/** Test byte buffer read with different buffer size. */
@@ -81,9 +83,11 @@ public abstract class AbstractCipherStreamTest {
public void testByteBufferRead() throws Exception {
doByteBufferRead(AbstractCipherTest.JCE_CIPHER_CLASSNAME, false);
doByteBufferRead(AbstractCipherTest.OPENSSL_CIPHER_CLASSNAME, false);
+ doByteBufferRead(AbstractCipherTest.OPENSSLJNA_CIPHER_CLASSNAME, false);
doByteBufferRead(AbstractCipherTest.JCE_CIPHER_CLASSNAME, true);
doByteBufferRead(AbstractCipherTest.OPENSSL_CIPHER_CLASSNAME, true);
+ doByteBufferRead(AbstractCipherTest.OPENSSLJNA_CIPHER_CLASSNAME, true);
}
/** Test byte buffer write. */
@@ -92,9 +96,11 @@ public abstract class AbstractCipherStreamTest {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
doByteBufferWrite(AbstractCipherTest.JCE_CIPHER_CLASSNAME, baos, false);
doByteBufferWrite(AbstractCipherTest.OPENSSL_CIPHER_CLASSNAME, baos, false);
+ doByteBufferWrite(AbstractCipherTest.OPENSSLJNA_CIPHER_CLASSNAME, baos, false);
doByteBufferWrite(AbstractCipherTest.JCE_CIPHER_CLASSNAME, baos, true);
doByteBufferWrite(AbstractCipherTest.OPENSSL_CIPHER_CLASSNAME, baos, true);
+ doByteBufferWrite(AbstractCipherTest.OPENSSLJNA_CIPHER_CLASSNAME, baos, true);
}
private void doSkipTest(String cipherClass, boolean withChannel)
@@ -308,18 +314,25 @@ public abstract class AbstractCipherStreamTest {
public void testReadWrite() throws Exception {
doReadWriteTest(0, AbstractCipherTest.JCE_CIPHER_CLASSNAME, AbstractCipherTest.JCE_CIPHER_CLASSNAME, iv);
doReadWriteTest(0, AbstractCipherTest.OPENSSL_CIPHER_CLASSNAME, AbstractCipherTest.OPENSSL_CIPHER_CLASSNAME, iv);
+ doReadWriteTest(0, AbstractCipherTest.OPENSSLJNA_CIPHER_CLASSNAME, AbstractCipherTest.OPENSSLJNA_CIPHER_CLASSNAME, iv);
doReadWriteTest(count, AbstractCipherTest.JCE_CIPHER_CLASSNAME, AbstractCipherTest.JCE_CIPHER_CLASSNAME, iv);
doReadWriteTest(count, AbstractCipherTest.OPENSSL_CIPHER_CLASSNAME, AbstractCipherTest.OPENSSL_CIPHER_CLASSNAME, iv);
+ doReadWriteTest(count, AbstractCipherTest.OPENSSLJNA_CIPHER_CLASSNAME, AbstractCipherTest.OPENSSLJNA_CIPHER_CLASSNAME, iv);
doReadWriteTest(count, AbstractCipherTest.JCE_CIPHER_CLASSNAME, AbstractCipherTest.OPENSSL_CIPHER_CLASSNAME, iv);
+ doReadWriteTest(count, AbstractCipherTest.JCE_CIPHER_CLASSNAME, AbstractCipherTest.OPENSSLJNA_CIPHER_CLASSNAME, iv);
doReadWriteTest(count, AbstractCipherTest.OPENSSL_CIPHER_CLASSNAME, AbstractCipherTest.JCE_CIPHER_CLASSNAME, iv);
+ doReadWriteTest(count, AbstractCipherTest.OPENSSLJNA_CIPHER_CLASSNAME, AbstractCipherTest.JCE_CIPHER_CLASSNAME, iv);
// Overflow test, IV: xx xx xx xx xx xx xx xx ff ff ff ff ff ff ff ff
for (int i = 0; i < 8; i++) {
iv[8 + i] = (byte) 0xff;
}
doReadWriteTest(count, AbstractCipherTest.JCE_CIPHER_CLASSNAME, AbstractCipherTest.JCE_CIPHER_CLASSNAME, iv);
doReadWriteTest(count, AbstractCipherTest.OPENSSL_CIPHER_CLASSNAME, AbstractCipherTest.OPENSSL_CIPHER_CLASSNAME, iv);
+ doReadWriteTest(count, AbstractCipherTest.OPENSSLJNA_CIPHER_CLASSNAME, AbstractCipherTest.OPENSSLJNA_CIPHER_CLASSNAME, iv);
doReadWriteTest(count, AbstractCipherTest.JCE_CIPHER_CLASSNAME, AbstractCipherTest.OPENSSL_CIPHER_CLASSNAME, iv);
+ doReadWriteTest(count, AbstractCipherTest.JCE_CIPHER_CLASSNAME, AbstractCipherTest.OPENSSLJNA_CIPHER_CLASSNAME, iv);
doReadWriteTest(count, AbstractCipherTest.OPENSSL_CIPHER_CLASSNAME, AbstractCipherTest.JCE_CIPHER_CLASSNAME, iv);
+ doReadWriteTest(count, AbstractCipherTest.OPENSSLJNA_CIPHER_CLASSNAME, AbstractCipherTest.JCE_CIPHER_CLASSNAME, iv);
}
private void doReadWriteTest(int count, String encCipherClass,
http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/b6006e56/src/test/java/org/apache/commons/crypto/stream/PositionedCryptoInputStreamTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/crypto/stream/PositionedCryptoInputStreamTest.java b/src/test/java/org/apache/commons/crypto/stream/PositionedCryptoInputStreamTest.java
index 758c095..1e39edb 100644
--- a/src/test/java/org/apache/commons/crypto/stream/PositionedCryptoInputStreamTest.java
+++ b/src/test/java/org/apache/commons/crypto/stream/PositionedCryptoInputStreamTest.java
@@ -97,6 +97,7 @@ public class PositionedCryptoInputStreamTest {
public void doTest() throws Exception {
testCipher(AbstractCipherTest.JCE_CIPHER_CLASSNAME);
testCipher(AbstractCipherTest.OPENSSL_CIPHER_CLASSNAME);
+ testCipher(AbstractCipherTest.OPENSSLJNA_CIPHER_CLASSNAME);
}
private void testCipher(String cipherClass) throws Exception {