This is an automated email from the ASF dual-hosted git repository.

vanzin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-crypto.git


The following commit(s) were added to refs/heads/master by this push:
     new 2875340  OpenSSL 1.1.0 updates with backward compatibility for OpenSSL 
1.0.2 and 1.0.1 (#92)
2875340 is described below

commit 2875340ca3f9f5b19cd14939d9c0fbba500687f1
Author: aremily <arem...@users.noreply.github.com>
AuthorDate: Tue Feb 19 13:40:39 2019 -0500

    OpenSSL 1.1.0 updates with backward compatibility for OpenSSL 1.0.2 and 
1.0.1 (#92)
---
 Makefile.common                                    |   6 +-
 .../java/org/apache/commons/crypto/Crypto.java     |   8 +-
 .../apache/commons/crypto/OpenSslInfoNative.java   |  19 +-
 ...nSslNativeJna.java => OpenSsl10XNativeJna.java} | 180 ++++----
 ...nSslNativeJna.java => OpenSsl11XNativeJna.java} | 212 ++++-----
 .../org/apache/commons/crypto/jna/OpenSslJna.java  |  10 +
 .../commons/crypto/jna/OpenSslJnaCryptoRandom.java |   2 +-
 .../commons/crypto/jna/OpenSslNativeJna.java       | 477 ++++++++++-----------
 .../org/apache/commons/crypto/OpenSslInfoNative.c  |  83 ++--
 .../apache/commons/crypto/cipher/OpenSslNative.c   | 163 +++----
 .../commons/crypto/org_apache_commons_crypto.h     |  22 +
 .../crypto/random/OpenSslCryptoRandomNative.c      |  86 ++--
 .../commons/crypto/jna/OpenSslNativeJnaTest.java   |   2 +-
 13 files changed, 638 insertions(+), 632 deletions(-)

diff --git a/Makefile.common b/Makefile.common
index 96a53b8..f5ce5b7 100644
--- a/Makefile.common
+++ b/Makefile.common
@@ -179,10 +179,10 @@ Mac-x86_LIBNAME   := libcommons-crypto.jnilib
 Mac-x86_COMMONS_CRYPTO_FLAGS  :=
 
 Mac-x86_64_CC        := gcc -arch $(OS_ARCH)
-Mac-x86_64_CXX       := g++ -arch $(OS_ARCH)
+Mac-x86_64_CXX       := gcc -arch $(OS_ARCH)
 Mac-x86_64_STRIP     := strip -x
-Mac-x86_64_CFLAGS    := -Ilib/inc_mac -I$(JAVA_HOME)/include -O2 -fPIC 
-mmacosx-version-min=10.5 -fvisibility=hidden -I/usr/local/include 
-I/usr/local/opt/openssl/include
-Mac-x86_64_CXXFLAGS  := -Ilib/inc_mac -I$(JAVA_HOME)/include -O2 -fPIC 
-mmacosx-version-min=10.5 -fvisibility=hidden -I/usr/local/include 
-I/usr/local/opt/openssl/include
+Mac-x86_64_CFLAGS    := -Ilib/inc_mac -I$(JAVA_HOME)/include -O2 -fPIC 
-mmacosx-version-min=10.7 -fvisibility=hidden -I/usr/local/include 
-I/usr/local/opt/openssl/include
+Mac-x86_64_CXXFLAGS  := -Ilib/inc_mac -I$(JAVA_HOME)/include -O2 -fPIC 
-mmacosx-version-min=10.7 -fvisibility=hidden -I/usr/local/include 
-I/usr/local/opt/openssl/include
 Mac-x86_64_LINKFLAGS := -dynamiclib -L/usr/local/lib
 Mac-x86_64_LIBNAME   := libcommons-crypto.jnilib
 Mac-x86_64_COMMONS_CRYPTO_FLAGS  :=
diff --git a/src/main/java/org/apache/commons/crypto/Crypto.java 
b/src/main/java/org/apache/commons/crypto/Crypto.java
index 48069f4..b6fc886 100644
--- a/src/main/java/org/apache/commons/crypto/Crypto.java
+++ b/src/main/java/org/apache/commons/crypto/Crypto.java
@@ -132,8 +132,8 @@ public final class Crypto {
             System.out.println("Native code loaded OK " + 
OpenSslInfoNative.NativeVersion());
             System.out.println("Native Name " + 
OpenSslInfoNative.NativeName());
             System.out.println("Native Built " + 
OpenSslInfoNative.NativeTimeStamp());
-            System.out.println("OpenSSL library loaded OK, version: 0x" + 
Long.toHexString(OpenSslInfoNative.SSLeay()));
-            System.out.println(OpenSslInfoNative.SSLeayVersion(0));
+            System.out.println("OpenSSL library loaded OK, version: 0x" + 
Long.toHexString(OpenSslInfoNative.OpenSSL()));
+            System.out.println("OpenSSL library info " + 
OpenSslInfoNative.OpenSSLVersion(0));
             {
                 Properties props = new Properties();
                 props.setProperty(CryptoRandomFactory.CLASSES_KEY, 
CryptoRandomFactory.RandomProvider.OPENSSL.getClassName());
@@ -146,9 +146,9 @@ public final class Crypto {
                 CryptoCipherFactory.getCryptoCipher("AES/CTR/NoPadding", 
props);
                 System.out.println("Cipher instance created OK");
             }
-            System.out.println("Additional SSLeay_version(n) details:");
+            System.out.println("Additional OpenSSL_version(n) details:");
             for(int j=1;j<6;j++) {
-                System.out.println(j+": "+ OpenSslInfoNative.SSLeayVersion(j));
+                System.out.println(j+": "+ 
OpenSslInfoNative.OpenSSLVersion(j));
             }
         } else {
             System.out.println("Native load failed: " + getLoadingError());    
        
diff --git a/src/main/java/org/apache/commons/crypto/OpenSslInfoNative.java 
b/src/main/java/org/apache/commons/crypto/OpenSslInfoNative.java
index 8ca2fde..85a3687 100644
--- a/src/main/java/org/apache/commons/crypto/OpenSslInfoNative.java
+++ b/src/main/java/org/apache/commons/crypto/OpenSslInfoNative.java
@@ -18,7 +18,7 @@
 package org.apache.commons.crypto;
 
 /**
- * JNI interface of {@see CryptoRandom} implementation for OpenSSL.
+ * JNI interface of {@link CryptoRandom} implementation for OpenSSL.
  * The native method in this class is defined in 
  * OpenSslCryptoRandomNative.h (generated at build time by javah)
  * and implemented in the file
@@ -26,6 +26,9 @@ package org.apache.commons.crypto;
  */
 class OpenSslInfoNative {
 
+    public static final long VERSION_1_0_2X = 0x10002000;
+    public static final long VERSION_1_1_0X = 0x10100000;
+
     /**
      * Makes the constructor private.
      */
@@ -46,16 +49,18 @@ class OpenSslInfoNative {
      * @return timestamp of native
      */
     public static native String NativeTimeStamp();
-
+    
+    
     /**
-     * @return the value of SSLEAY_VERSION_NUMBER.
+     * @return the value of OPENSSL_VERSION_NUMBER.
      */
-    public static native long SSLeay();
-
+    public static native long OpenSSL();
+    
     /**
-     * Returns SSLeay_version according the version type.
+     * Returns OpenSSL_version according the version type.
+     * 
      * @param type The version type
      * @return The text variant of the version number and the release date.
      */
-    public static native String SSLeayVersion(int type);
+    public static native String OpenSSLVersion(int type);
 }
diff --git a/src/main/java/org/apache/commons/crypto/jna/OpenSslNativeJna.java 
b/src/main/java/org/apache/commons/crypto/jna/OpenSsl10XNativeJna.java
similarity index 69%
copy from src/main/java/org/apache/commons/crypto/jna/OpenSslNativeJna.java
copy to src/main/java/org/apache/commons/crypto/jna/OpenSsl10XNativeJna.java
index 099c049..ed050b2 100644
--- a/src/main/java/org/apache/commons/crypto/jna/OpenSslNativeJna.java
+++ b/src/main/java/org/apache/commons/crypto/jna/OpenSsl10XNativeJna.java
@@ -24,12 +24,7 @@ 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;
+class OpenSsl10XNativeJna {
 
     static final boolean INIT_OK;
 
@@ -40,7 +35,6 @@ class OpenSslNativeJna {
         Throwable thrown = null;
         try {
             Native.register("crypto");
-            ERR_load_crypto_strings();
             ok = true;
         } catch (Exception e) {
             thrown = e;
@@ -52,19 +46,18 @@ class OpenSslNativeJna {
         }
     }
 
-    //misc
     /**
-     * @return OPENSSL_VERSION_NUMBER which is a numeric release version
-     * * identifier
+     * @return OPENSSL_VERSION_NUMBER which is a numeric release version 
identifier
      */
     public static native NativeLong SSLeay();
 
     /**
      * Retrieves version/build information about OpenSSL library.
      *
-     * @param type type can be SSLEAY_VERSION, SSLEAY_CFLAGS, 
SSLEAY_BUILT_ON...
-     * @return A pointer to a constant string describing the version of the
-     * OpenSSL library or giving information about the library build.
+     * @param type
+     *            type can be SSLEAY_VERSION, SSLEAY_CFLAGS, SSLEAY_BUILT_ON...
+     * @return A pointer to a constant string describing the version of the 
OpenSSL library or
+     *         giving information about the library build.
      */
     public static native String SSLeay_version(int type);
 
@@ -74,45 +67,45 @@ class OpenSslNativeJna {
     public static native void ERR_load_crypto_strings();
 
     /**
-     * @return the earliest error code from the thread's error queue without
-     * modifying it.
+     * @return the earliest error code from the thread's error queue without 
modifying it.
      */
     public static native NativeLong ERR_peek_error();
 
-
-
     /**
      * Generates a human-readable string representing the error code e.
+     * 
      * @see 
<a>https://www.openssl.org/docs/manmaster/crypto/ERR_error_string.html</a>
      *
-     * @param err the error code
-     * @param null_ buf is NULL, the error string is placed in a static buffer
+     * @param err
+     *            the error code
+     * @param null_
+     *            buf is NULL, the error string is placed in a static buffer
      * @return the human-readable error messages.
      */
     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);
 
-    //en-/decryption
     /**
      * Creates a cipher context.
      *
-     * @return a pointer to a newly created EVP_CIPHER_CTX for success and
-     * NULL for failure.
+     * @return a pointer to a newly created EVP_CIPHER_CTX for success and 
NULL for failure.
      */
     public static native PointerByReference EVP_CIPHER_CTX_new();
 
-
     /**
      * EVP_CIPHER_CTX_init() remains as an alias for EVP_CIPHER_CTX_reset
-     * @param p cipher context
+     * 
+     * @param p
+     *            cipher context
      */
     public static native void EVP_CIPHER_CTX_init(PointerByReference p);
 
     /**
      * Enables or disables padding
-     * @param c cipher context
-     * @param pad If the pad parameter is zero then no padding is performed
+     * 
+     * @param c
+     *            cipher context
+     * @param pad
+     *            If the pad parameter is zero then no padding is performed
      * @return always returns 1
      */
     public static native int EVP_CIPHER_CTX_set_padding(PointerByReference c, 
int pad);
@@ -149,70 +142,96 @@ class OpenSslNativeJna {
 
     /**
      * Init a cipher.
-     * @param ctx cipher context
-     * @param cipher evp cipher instance
-     * @param impl engine
-     * @param key key
-     * @param iv iv
-     * @param enc 1 for encryption, 0 for decryption
+     * 
+     * @param ctx
+     *            cipher context
+     * @param cipher
+     *            evp cipher instance
+     * @param impl
+     *            engine
+     * @param key
+     *            key
+     * @param iv
+     *            iv
+     * @param enc
+     *            1 for encryption, 0 for decryption
      * @return 1 for success and 0 for failure.
      */
-    public static native int EVP_CipherInit_ex(PointerByReference ctx, 
PointerByReference cipher, PointerByReference impl, byte key[], byte iv[], int 
enc);
-
+    public static native int EVP_CipherInit_ex(PointerByReference ctx, 
PointerByReference cipher,
+            PointerByReference impl, byte key[], byte iv[], int enc);
 
     /**
      * Continues a multiple-part encryption/decryption operation.
      *
-     * @param ctx cipher context
-     * @param bout output byte buffer
-     * @param outl output length
-     * @param in input byte buffer
-     * @param inl input length
+     * @param ctx
+     *            cipher context
+     * @param bout
+     *            output byte buffer
+     * @param outl
+     *            output length
+     * @param in
+     *            input byte buffer
+     * @param inl
+     *            input length
      * @return 1 for success and 0 for failure.
      */
-    public static native int EVP_CipherUpdate(PointerByReference ctx, 
ByteBuffer bout, int[] outl, ByteBuffer in, int inl);
+    public static native int EVP_CipherUpdate(PointerByReference ctx, 
ByteBuffer bout, int[] outl,
+            ByteBuffer in, int inl);
 
     /**
      * Finishes a multiple-part operation.
      *
-     * @param ctx cipher context
-     * @param bout output byte buffer
-     * @param outl output length
+     * @param ctx
+     *            cipher context
+     * @param bout
+     *            output byte buffer
+     * @param outl
+     *            output length
      * @return 1 for success and 0 for failure.
      */
-    public static native int EVP_CipherFinal_ex(PointerByReference ctx, 
ByteBuffer bout, int[] outl);
+    public static native int EVP_CipherFinal_ex(PointerByReference ctx, 
ByteBuffer bout,
+            int[] outl);
 
     /**
-     * Clears all information from a cipher context and free up any allocated
-     * memory associate with it, including ctx itself.
-     * @param c openssl evp cipher
+     * Clears all information from a cipher context and free up any allocated 
memory associate with
+     * it, including ctx itself.
+     * 
+     * @param c
+     *            openssl evp cipher
      */
     public static native void EVP_CIPHER_CTX_free(PointerByReference c);
 
     /**
-     * Clears all information from a cipher context and free up any allocated
-     * * memory associate with it.
-     * @param c openssl evp cipher
+     * Clears all information from a cipher context and free up any allocated 
* memory associate
+     * with it.
+     * 
+     * @param c
+     *            openssl evp cipher
      */
     public static native void EVP_CIPHER_CTX_cleanup(PointerByReference c);
 
-    //Random generator
+    // Random generator
     /**
      * OpenSSL uses for random number generation
+     * 
      * @return pointers to the respective methods
      */
     public static native PointerByReference RAND_get_rand_method();
 
     /**
      * OpenSSL uses for random number generation.
+     * 
      * @return pointers to the respective methods
      */
     public static native PointerByReference RAND_SSLeay();
 
     /**
      * Generates random data
-     * @param buf the bytes for generated random.
-     * @param num buffer length
+     * 
+     * @param buf
+     *            the bytes for generated random.
+     * @param num
+     *            buffer length
      * @return 1 on success, 0 otherwise.
      */
     public static native int RAND_bytes(ByteBuffer buf, int num);
@@ -220,42 +239,54 @@ class OpenSslNativeJna {
     /**
      * Releases all functional references.
      *
-     * @param e engine reference.
+     * @param e
+     *            engine reference.
      * @return 0 on success, 1 otherwise.
      */
     public static native int ENGINE_finish(PointerByReference e);
 
     /**
      * Frees the structural reference
-     * @param e engine reference.
+     * 
+     * @param e
+     *            engine reference.
      * @return 0 on success, 1 otherwise.
      */
     public static native int ENGINE_free(PointerByReference e);
 
     /**
      * Cleanups before program exit, it will avoid memory leaks.
+     * 
      * @return 0 on success, 1 otherwise.
      */
     public static native int ENGINE_cleanup();
 
     /**
      * Obtains a functional reference from an existing structural reference.
-     * @param e engine reference
-     * @return zero if the ENGINE was not already operational and couldn't be 
successfully initialised
+     * 
+     * @param e
+     *            engine reference
+     * @return zero if the ENGINE was not already operational and couldn't be 
successfully
+     *         initialised
      */
     public static native int ENGINE_init(PointerByReference e);
 
     /**
      * Sets the engine as the default for random number generation.
-     * @param e  engine reference
-     * @param flags ENGINE_METHOD_RAND
+     * 
+     * @param e
+     *            engine reference
+     * @param flags
+     *            ENGINE_METHOD_RAND
      * @return zero if failed.
      */
     public static native int ENGINE_set_default(PointerByReference e, int 
flags);
 
     /**
      * Gets engine by id
-     * @param id engine id
+     * 
+     * @param id
+     *            engine id
      * @return engine instance
      */
     public static native PointerByReference ENGINE_by_id(String id);
@@ -264,27 +295,4 @@ class OpenSslNativeJna {
      * Initializes the engine.
      */
     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
+}
diff --git a/src/main/java/org/apache/commons/crypto/jna/OpenSslNativeJna.java 
b/src/main/java/org/apache/commons/crypto/jna/OpenSsl11XNativeJna.java
similarity index 58%
copy from src/main/java/org/apache/commons/crypto/jna/OpenSslNativeJna.java
copy to src/main/java/org/apache/commons/crypto/jna/OpenSsl11XNativeJna.java
index 099c049..b9c4c0e 100644
--- a/src/main/java/org/apache/commons/crypto/jna/OpenSslNativeJna.java
+++ b/src/main/java/org/apache/commons/crypto/jna/OpenSsl11XNativeJna.java
@@ -24,12 +24,7 @@ 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;
+class OpenSsl11XNativeJna {
 
     static final boolean INIT_OK;
 
@@ -40,7 +35,6 @@ class OpenSslNativeJna {
         Throwable thrown = null;
         try {
             Native.register("crypto");
-            ERR_load_crypto_strings();
             ok = true;
         } catch (Exception e) {
             thrown = e;
@@ -52,67 +46,38 @@ class OpenSslNativeJna {
         }
     }
 
-    //misc
-    /**
-     * @return OPENSSL_VERSION_NUMBER which is a numeric release version
-     * * identifier
-     */
-    public static native NativeLong SSLeay();
-
-    /**
-     * Retrieves version/build information about OpenSSL library.
-     *
-     * @param type type can be SSLEAY_VERSION, SSLEAY_CFLAGS, 
SSLEAY_BUILT_ON...
-     * @return A pointer to a constant string describing the version of the
-     * OpenSSL library or giving information about the library build.
-     */
-    public static native String SSLeay_version(int type);
-
     /**
-     * Registers the error strings for all libcrypto functions.
-     */
-    public static native void ERR_load_crypto_strings();
-
-    /**
-     * @return the earliest error code from the thread's error queue without
-     * modifying it.
+     * @return the earliest error code from the thread's error queue without 
modifying it.
      */
     public static native NativeLong ERR_peek_error();
 
-
-
     /**
      * Generates a human-readable string representing the error code e.
+     * 
      * @see 
<a>https://www.openssl.org/docs/manmaster/crypto/ERR_error_string.html</a>
      *
-     * @param err the error code
-     * @param null_ buf is NULL, the error string is placed in a static buffer
+     * @param err
+     *            the error code
+     * @param null_
+     *            buf is NULL, the error string is placed in a static buffer
      * @return the human-readable error messages.
      */
     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);
 
-    //en-/decryption
     /**
      * Creates a cipher context.
      *
-     * @return a pointer to a newly created EVP_CIPHER_CTX for success and
-     * NULL for failure.
+     * @return a pointer to a newly created EVP_CIPHER_CTX for success and 
NULL for failure.
      */
     public static native PointerByReference EVP_CIPHER_CTX_new();
 
-
-    /**
-     * EVP_CIPHER_CTX_init() remains as an alias for EVP_CIPHER_CTX_reset
-     * @param p cipher context
-     */
-    public static native void EVP_CIPHER_CTX_init(PointerByReference p);
-
     /**
      * Enables or disables padding
-     * @param c cipher context
-     * @param pad If the pad parameter is zero then no padding is performed
+     * 
+     * @param c
+     *            cipher context
+     * @param pad
+     *            If the pad parameter is zero then no padding is performed
      * @return always returns 1
      */
     public static native int EVP_CIPHER_CTX_set_padding(PointerByReference c, 
int pad);
@@ -149,70 +114,88 @@ class OpenSslNativeJna {
 
     /**
      * Init a cipher.
-     * @param ctx cipher context
-     * @param cipher evp cipher instance
-     * @param impl engine
-     * @param key key
-     * @param iv iv
-     * @param enc 1 for encryption, 0 for decryption
+     * 
+     * @param ctx
+     *            cipher context
+     * @param cipher
+     *            evp cipher instance
+     * @param impl
+     *            engine
+     * @param key
+     *            key
+     * @param iv
+     *            iv
+     * @param enc
+     *            1 for encryption, 0 for decryption
      * @return 1 for success and 0 for failure.
      */
-    public static native int EVP_CipherInit_ex(PointerByReference ctx, 
PointerByReference cipher, PointerByReference impl, byte key[], byte iv[], int 
enc);
-
+    public static native int EVP_CipherInit_ex(PointerByReference ctx, 
PointerByReference cipher,
+            PointerByReference impl, byte key[], byte iv[], int enc);
 
     /**
      * Continues a multiple-part encryption/decryption operation.
      *
-     * @param ctx cipher context
-     * @param bout output byte buffer
-     * @param outl output length
-     * @param in input byte buffer
-     * @param inl input length
+     * @param ctx
+     *            cipher context
+     * @param bout
+     *            output byte buffer
+     * @param outl
+     *            output length
+     * @param in
+     *            input byte buffer
+     * @param inl
+     *            input length
      * @return 1 for success and 0 for failure.
      */
-    public static native int EVP_CipherUpdate(PointerByReference ctx, 
ByteBuffer bout, int[] outl, ByteBuffer in, int inl);
+    public static native int EVP_CipherUpdate(PointerByReference ctx, 
ByteBuffer bout, int[] outl,
+            ByteBuffer in, int inl);
 
     /**
      * Finishes a multiple-part operation.
      *
-     * @param ctx cipher context
-     * @param bout output byte buffer
-     * @param outl output length
+     * @param ctx
+     *            cipher context
+     * @param bout
+     *            output byte buffer
+     * @param outl
+     *            output length
      * @return 1 for success and 0 for failure.
      */
-    public static native int EVP_CipherFinal_ex(PointerByReference ctx, 
ByteBuffer bout, int[] outl);
+    public static native int EVP_CipherFinal_ex(PointerByReference ctx, 
ByteBuffer bout,
+            int[] outl);
 
     /**
-     * Clears all information from a cipher context and free up any allocated
-     * memory associate with it, including ctx itself.
-     * @param c openssl evp cipher
+     * Clears all information from a cipher context and free up any allocated 
memory associate with
+     * it, including ctx itself.
+     * 
+     * @param c
+     *            openssl evp cipher
      */
     public static native void EVP_CIPHER_CTX_free(PointerByReference c);
 
     /**
-     * Clears all information from a cipher context and free up any allocated
-     * * memory associate with it.
-     * @param c openssl evp cipher
+     * Clears all information from a cipher context and free up any allocated 
* memory associate
+     * with it.
+     * 
+     * @param c
+     *            openssl evp cipher
      */
-    public static native void EVP_CIPHER_CTX_cleanup(PointerByReference c);
 
-    //Random generator
+    // Random generator
     /**
      * OpenSSL uses for random number generation
+     * 
      * @return pointers to the respective methods
      */
     public static native PointerByReference RAND_get_rand_method();
 
     /**
-     * OpenSSL uses for random number generation.
-     * @return pointers to the respective methods
-     */
-    public static native PointerByReference RAND_SSLeay();
-
-    /**
      * Generates random data
-     * @param buf the bytes for generated random.
-     * @param num buffer length
+     * 
+     * @param buf
+     *            the bytes for generated random.
+     * @param num
+     *            buffer length
      * @return 1 on success, 0 otherwise.
      */
     public static native int RAND_bytes(ByteBuffer buf, int num);
@@ -220,71 +203,58 @@ class OpenSslNativeJna {
     /**
      * Releases all functional references.
      *
-     * @param e engine reference.
+     * @param e
+     *            engine reference.
      * @return 0 on success, 1 otherwise.
      */
     public static native int ENGINE_finish(PointerByReference e);
 
     /**
      * Frees the structural reference
-     * @param e engine reference.
+     * 
+     * @param e
+     *            engine reference.
      * @return 0 on success, 1 otherwise.
      */
     public static native int ENGINE_free(PointerByReference e);
 
     /**
-     * Cleanups before program exit, it will avoid memory leaks.
-     * @return 0 on success, 1 otherwise.
-     */
-    public static native int ENGINE_cleanup();
-
-    /**
      * Obtains a functional reference from an existing structural reference.
-     * @param e engine reference
-     * @return zero if the ENGINE was not already operational and couldn't be 
successfully initialised
+     * 
+     * @param e
+     *            engine reference
+     * @return zero if the ENGINE was not already operational and couldn't be 
successfully
+     *         initialised
      */
     public static native int ENGINE_init(PointerByReference e);
 
     /**
      * Sets the engine as the default for random number generation.
-     * @param e  engine reference
-     * @param flags ENGINE_METHOD_RAND
+     * 
+     * @param e
+     *            engine reference
+     * @param flags
+     *            ENGINE_METHOD_RAND
      * @return zero if failed.
      */
     public static native int ENGINE_set_default(PointerByReference e, int 
flags);
 
     /**
      * Gets engine by id
-     * @param id engine id
+     * 
+     * @param id
+     *            engine id
      * @return engine instance
      */
     public static native PointerByReference ENGINE_by_id(String id);
 
     /**
-     * Initializes the engine.
+     * Retrieves version/build information about OpenSSL library.
+     *
+     * @param type
+     *            type can be OPENSSL_VERSION, OPENSSL_CFLAGS, 
OPENSSL_BUILT_ON...
+     * @return A pointer to a constant string describing the version of the 
OpenSSL library or
+     *         giving information about the library build.
      */
-    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
+    public static native String OpenSSL_version(int type);
+}
diff --git a/src/main/java/org/apache/commons/crypto/jna/OpenSslJna.java 
b/src/main/java/org/apache/commons/crypto/jna/OpenSslJna.java
index 14b9d34..da66c5c 100644
--- a/src/main/java/org/apache/commons/crypto/jna/OpenSslJna.java
+++ b/src/main/java/org/apache/commons/crypto/jna/OpenSslJna.java
@@ -53,4 +53,14 @@ public final class OpenSslJna {
         return OpenSslNativeJna.INIT_ERROR;
     }
 
+    /**
+     * Retrieves version/build information about OpenSSL library.
+     *
+     * @param type type can be OPENSSL_VERSION, OPENSSL_CFLAGS, 
OPENSSL_BUILT_ON...
+     * @return A pointer to a constant string describing the version of the
+     * OpenSSL library or giving information about the library build.
+     */
+    static String OpenSSLVersion(int type) {
+         return OpenSslNativeJna.OpenSSLVersion(type);
+    }
 }
diff --git 
a/src/main/java/org/apache/commons/crypto/jna/OpenSslJnaCryptoRandom.java 
b/src/main/java/org/apache/commons/crypto/jna/OpenSslJnaCryptoRandom.java
index b3f4c4f..823637d 100644
--- a/src/main/java/org/apache/commons/crypto/jna/OpenSslJnaCryptoRandom.java
+++ b/src/main/java/org/apache/commons/crypto/jna/OpenSslJnaCryptoRandom.java
@@ -106,7 +106,7 @@ class OpenSslJnaCryptoRandom extends Random implements 
CryptoRandom {
                 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);
diff --git a/src/main/java/org/apache/commons/crypto/jna/OpenSslNativeJna.java 
b/src/main/java/org/apache/commons/crypto/jna/OpenSslNativeJna.java
index 099c049..26507d7 100644
--- a/src/main/java/org/apache/commons/crypto/jna/OpenSslNativeJna.java
+++ b/src/main/java/org/apache/commons/crypto/jna/OpenSslNativeJna.java
@@ -20,7 +20,8 @@ package org.apache.commons.crypto.jna;
 
 import java.nio.ByteBuffer;
 
-import com.sun.jna.Native;
+import com.sun.jna.Function;
+import com.sun.jna.NativeLibrary;
 import com.sun.jna.NativeLong;
 import com.sun.jna.ptr.PointerByReference;
 
@@ -35,256 +36,252 @@ class OpenSslNativeJna {
 
     static final Throwable INIT_ERROR;
 
+    public static final long VERSION;
+    public static final long VERSION_1_0_X = 0x10000000;
+    public static final long VERSION_1_1_X = 0x10100000;
+
     static {
-        boolean ok = false;
-        Throwable thrown = null;
+        NativeLibrary crypto = NativeLibrary.getInstance("crypto");
+        Function version = null;
         try {
-            Native.register("crypto");
-            ERR_load_crypto_strings();
-            ok = true;
-        } catch (Exception e) {
-            thrown = e;
+            version = crypto.getFunction("SSLeay");
         } catch (UnsatisfiedLinkError e) {
-            thrown = e;
-        } finally {
-            INIT_OK = ok;
-            INIT_ERROR = thrown;
+            // Swallow the Error.
+        }
+
+        if (version == null) {
+            VERSION = VERSION_1_1_X;
+        } else {
+            VERSION = VERSION_1_0_X;
+        }
+
+        if (VERSION == VERSION_1_1_X) {
+            INIT_OK = OpenSsl11XNativeJna.INIT_OK;
+        } else {
+            INIT_OK = OpenSsl10XNativeJna.INIT_OK;
+        }
+
+        if (INIT_OK) {
+            INIT_ERROR = null;
+        } else if (VERSION == VERSION_1_1_X) {
+            INIT_ERROR = OpenSsl11XNativeJna.INIT_ERROR;
+        } else {
+            INIT_ERROR = OpenSsl10XNativeJna.INIT_ERROR;
+        }
+    }
+
+    public static PointerByReference ENGINE_by_id(String string) {
+        if (VERSION == VERSION_1_1_X) {
+            return OpenSsl11XNativeJna.ENGINE_by_id(string);
+        } else {
+            return OpenSsl10XNativeJna.ENGINE_by_id(string);
         }
     }
 
-    //misc
-    /**
-     * @return OPENSSL_VERSION_NUMBER which is a numeric release version
-     * * identifier
-     */
-    public static native NativeLong SSLeay();
-
-    /**
-     * Retrieves version/build information about OpenSSL library.
-     *
-     * @param type type can be SSLEAY_VERSION, SSLEAY_CFLAGS, 
SSLEAY_BUILT_ON...
-     * @return A pointer to a constant string describing the version of the
-     * OpenSSL library or giving information about the library build.
-     */
-    public static native String SSLeay_version(int type);
-
-    /**
-     * Registers the error strings for all libcrypto functions.
-     */
-    public static native void ERR_load_crypto_strings();
-
-    /**
-     * @return the earliest error code from the thread's error queue without
-     * modifying it.
-     */
-    public static native NativeLong ERR_peek_error();
-
-
-
-    /**
-     * Generates a human-readable string representing the error code e.
-     * @see 
<a>https://www.openssl.org/docs/manmaster/crypto/ERR_error_string.html</a>
-     *
-     * @param err the error code
-     * @param null_ buf is NULL, the error string is placed in a static buffer
-     * @return the human-readable error messages.
-     */
-    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);
-
-    //en-/decryption
-    /**
-     * Creates a cipher context.
-     *
-     * @return a pointer to a newly created EVP_CIPHER_CTX for success and
-     * NULL for failure.
-     */
-    public static native PointerByReference EVP_CIPHER_CTX_new();
-
-
-    /**
-     * EVP_CIPHER_CTX_init() remains as an alias for EVP_CIPHER_CTX_reset
-     * @param p cipher context
-     */
-    public static native void EVP_CIPHER_CTX_init(PointerByReference p);
-
-    /**
-     * Enables or disables padding
-     * @param c cipher context
-     * @param pad If the pad parameter is zero then no padding is performed
-     * @return always returns 1
-     */
-    public static native int EVP_CIPHER_CTX_set_padding(PointerByReference c, 
int pad);
-
-    /**
-     * @return an openssl AES evp cipher instance with a 128-bit key CBC mode
-     */
-    public static native PointerByReference EVP_aes_128_cbc();
-
-    /**
-     * @return an openssl AES evp cipher instance with a 128-bit key CTR mode
-     */
-    public static native PointerByReference EVP_aes_128_ctr();
-
-    /**
-     * @return an openssl AES evp cipher instance with a 192-bit key CBC mode
-     */
-    public static native PointerByReference EVP_aes_192_cbc();
-
-    /**
-     * @return an openssl AES evp cipher instance with a 192-bit key CTR mode
-     */
-    public static native PointerByReference EVP_aes_192_ctr();
-
-    /**
-     * @return an openssl AES evp cipher instance with a 256-bit key CBC mode
-     */
-    public static native PointerByReference EVP_aes_256_cbc();
-
-    /**
-     * @return an openssl AES evp cipher instance with a 256-bit key CTR mode
-     */
-    public static native PointerByReference EVP_aes_256_ctr();
-
-    /**
-     * Init a cipher.
-     * @param ctx cipher context
-     * @param cipher evp cipher instance
-     * @param impl engine
-     * @param key key
-     * @param iv iv
-     * @param enc 1 for encryption, 0 for decryption
-     * @return 1 for success and 0 for failure.
-     */
-    public static native int EVP_CipherInit_ex(PointerByReference ctx, 
PointerByReference cipher, PointerByReference impl, byte key[], byte iv[], int 
enc);
-
-
-    /**
-     * Continues a multiple-part encryption/decryption operation.
-     *
-     * @param ctx cipher context
-     * @param bout output byte buffer
-     * @param outl output length
-     * @param in input byte buffer
-     * @param inl input length
-     * @return 1 for success and 0 for failure.
-     */
-    public static native int EVP_CipherUpdate(PointerByReference ctx, 
ByteBuffer bout, int[] outl, ByteBuffer in, int inl);
-
-    /**
-     * Finishes a multiple-part operation.
-     *
-     * @param ctx cipher context
-     * @param bout output byte buffer
-     * @param outl output length
-     * @return 1 for success and 0 for failure.
-     */
-    public static native int EVP_CipherFinal_ex(PointerByReference ctx, 
ByteBuffer bout, int[] outl);
-
-    /**
-     * Clears all information from a cipher context and free up any allocated
-     * memory associate with it, including ctx itself.
-     * @param c openssl evp cipher
-     */
-    public static native void EVP_CIPHER_CTX_free(PointerByReference c);
-
-    /**
-     * Clears all information from a cipher context and free up any allocated
-     * * memory associate with it.
-     * @param c openssl evp cipher
-     */
-    public static native void EVP_CIPHER_CTX_cleanup(PointerByReference c);
-
-    //Random generator
-    /**
-     * OpenSSL uses for random number generation
-     * @return pointers to the respective methods
-     */
-    public static native PointerByReference RAND_get_rand_method();
-
-    /**
-     * OpenSSL uses for random number generation.
-     * @return pointers to the respective methods
-     */
-    public static native PointerByReference RAND_SSLeay();
-
-    /**
-     * Generates random data
-     * @param buf the bytes for generated random.
-     * @param num buffer length
-     * @return 1 on success, 0 otherwise.
-     */
-    public static native int RAND_bytes(ByteBuffer buf, int num);
-
-    /**
-     * Releases all functional references.
-     *
-     * @param e engine reference.
-     * @return 0 on success, 1 otherwise.
-     */
-    public static native int ENGINE_finish(PointerByReference e);
-
-    /**
-     * Frees the structural reference
-     * @param e engine reference.
-     * @return 0 on success, 1 otherwise.
-     */
-    public static native int ENGINE_free(PointerByReference e);
-
-    /**
-     * Cleanups before program exit, it will avoid memory leaks.
-     * @return 0 on success, 1 otherwise.
-     */
-    public static native int ENGINE_cleanup();
-
-    /**
-     * Obtains a functional reference from an existing structural reference.
-     * @param e engine reference
-     * @return zero if the ENGINE was not already operational and couldn't be 
successfully initialised
-     */
-    public static native int ENGINE_init(PointerByReference e);
-
-    /**
-     * Sets the engine as the default for random number generation.
-     * @param e  engine reference
-     * @param flags ENGINE_METHOD_RAND
-     * @return zero if failed.
-     */
-    public static native int ENGINE_set_default(PointerByReference e, int 
flags);
-
-    /**
-     * Gets engine by id
-     * @param id engine id
-     * @return engine instance
-     */
-    public static native PointerByReference ENGINE_by_id(String id);
-
-    /**
-     * Initializes the engine.
-     */
-    public static native void ENGINE_load_rdrand();
-
-    //TODO callback multithreading
-    /*public interface Id_function_cb extends Callback {
-        long invoke ();
+    public static void ENGINE_finish(PointerByReference rdrandEngine) {
+        if (VERSION == VERSION_1_1_X) {
+            OpenSsl11XNativeJna.ENGINE_finish(rdrandEngine);
+        } else {
+            OpenSsl10XNativeJna.ENGINE_finish(rdrandEngine);
+        }
+    }
+
+    public static void ENGINE_free(PointerByReference rdrandEngine) {
+        if (VERSION == VERSION_1_1_X) {
+            OpenSsl11XNativeJna.ENGINE_free(rdrandEngine);
+        } else {
+            OpenSsl10XNativeJna.ENGINE_free(rdrandEngine);
+        }
+    }
+
+    public static int ENGINE_init(PointerByReference rdrandEngine) {
+        if (VERSION == VERSION_1_1_X) {
+            return OpenSsl11XNativeJna.ENGINE_init(rdrandEngine);
+        } else {
+            return OpenSsl10XNativeJna.ENGINE_init(rdrandEngine);
+        }
     }
 
-    public interface Locking_function_cb extends Callback {
-        void invoke(int mode, int n, String file, int line);
+    public static int ENGINE_set_default(PointerByReference rdrandEngine, int 
eNGINE_METHOD_RAND) {
+        if (VERSION == VERSION_1_1_X) {
+            return OpenSsl11XNativeJna.ENGINE_set_default(rdrandEngine, 
eNGINE_METHOD_RAND);
+        } else {
+            return OpenSsl10XNativeJna.ENGINE_set_default(rdrandEngine, 
eNGINE_METHOD_RAND);
+        }
     }
 
-    public static final Id_function_cb default_id_function = new 
Id_function_cb() {
+    public static String ERR_error_string(NativeLong err, Object object) {
+        if (VERSION == VERSION_1_1_X) {
+            return OpenSsl11XNativeJna.ERR_error_string(err, null);
+        } else {
+            return OpenSsl10XNativeJna.ERR_error_string(err, null);
+        }
+    }
 
-        @Override
-        public long invoke() {
-            //id always positive
-            long id = Thread.currentThread().getId();
-            return id;
+    public static NativeLong ERR_peek_error() {
+        if (VERSION == VERSION_1_1_X) {
+            return OpenSsl11XNativeJna.ERR_peek_error();
+        } else {
+            return OpenSsl10XNativeJna.ERR_peek_error();
         }
-    };
+    }
+
+    public static PointerByReference EVP_aes_128_cbc() {
+        if (VERSION == VERSION_1_1_X) {
+            return OpenSsl11XNativeJna.EVP_aes_128_cbc();
+        } else {
+            return OpenSsl10XNativeJna.EVP_aes_128_cbc();
+        }
+    }
+
+    public static PointerByReference EVP_aes_128_ctr() {
+        if (VERSION == VERSION_1_1_X) {
+            return OpenSsl11XNativeJna.EVP_aes_128_ctr();
+        } else {
+            return OpenSsl10XNativeJna.EVP_aes_128_ctr();
+        }
+    }
+
+    public static PointerByReference EVP_aes_192_cbc() {
+        if (VERSION == VERSION_1_1_X) {
+            return OpenSsl11XNativeJna.EVP_aes_192_cbc();
+        } else {
+            return OpenSsl10XNativeJna.EVP_aes_192_cbc();
+        }
+    }
+
+    public static PointerByReference EVP_aes_192_ctr() {
+        if (VERSION == VERSION_1_1_X) {
+            return OpenSsl11XNativeJna.EVP_aes_192_ctr();
+        } else {
+            return OpenSsl10XNativeJna.EVP_aes_192_ctr();
+        }
+    }
+
+    public static PointerByReference EVP_aes_256_cbc() {
+        if (VERSION == VERSION_1_1_X) {
+            return OpenSsl11XNativeJna.EVP_aes_256_cbc();
+        } else {
+            return OpenSsl10XNativeJna.EVP_aes_256_cbc();
+        }
+    }
+
+    public static PointerByReference EVP_aes_256_ctr() {
+        if (VERSION == VERSION_1_1_X) {
+            return OpenSsl11XNativeJna.EVP_aes_256_ctr();
+        } else {
+            return OpenSsl10XNativeJna.EVP_aes_256_ctr();
+        }
+    }
 
-    int CRYPTO_num_locks();
-    void CRYPTO_set_id_callback(Id_function_cb id_function);
-    void CRYPTO_set_locking_callback(Locking_function_cb locking_function);*/
+    public static void EVP_CIPHER_CTX_free(PointerByReference context) {
+        if (VERSION == VERSION_1_1_X) {
+            OpenSsl11XNativeJna.EVP_CIPHER_CTX_free(context);
+        } else {
+            OpenSsl10XNativeJna.EVP_CIPHER_CTX_free(context);
+        }
+    }
+
+    public static PointerByReference EVP_CIPHER_CTX_new() {
+        if (VERSION == VERSION_1_1_X) {
+            return OpenSsl11XNativeJna.EVP_CIPHER_CTX_new();
+        } else {
+            return OpenSsl10XNativeJna.EVP_CIPHER_CTX_new();
+        }
+    }
+
+    public static void EVP_CIPHER_CTX_set_padding(PointerByReference context, 
int padding) {
+        if (VERSION == VERSION_1_1_X) {
+            OpenSsl11XNativeJna.EVP_CIPHER_CTX_set_padding(context, padding);
+        } else {
+            OpenSsl10XNativeJna.EVP_CIPHER_CTX_set_padding(context, padding);
+        }
+    }
+
+    public static int EVP_CipherFinal_ex(PointerByReference context, 
ByteBuffer outBuffer,
+            int[] outlen) {
+        if (VERSION == VERSION_1_1_X) {
+            return OpenSsl11XNativeJna.EVP_CipherFinal_ex(context, outBuffer, 
outlen);
+        } else {
+            return OpenSsl10XNativeJna.EVP_CipherFinal_ex(context, outBuffer, 
outlen);
+        }
+    }
+
+    public static int EVP_CipherInit_ex(PointerByReference context, 
PointerByReference algo,
+            Object object, byte[] encoded, byte[] iv, int cipherMode) {
+        if (VERSION == VERSION_1_1_X) {
+            return OpenSsl11XNativeJna.EVP_CipherInit_ex(context, algo, null, 
encoded, iv,
+                    cipherMode);
+        } else {
+            return OpenSsl10XNativeJna.EVP_CipherInit_ex(context, algo, null, 
encoded, iv,
+                    cipherMode);
+        }
+    }
+
+    public static int EVP_CipherUpdate(PointerByReference context, ByteBuffer 
outBuffer,
+            int[] outlen, ByteBuffer inBuffer, int remaining) {
+        if (VERSION == VERSION_1_1_X) {
+            return OpenSsl11XNativeJna.EVP_CipherUpdate(context, outBuffer, 
outlen, inBuffer,
+                    remaining);
+        } else {
+            return OpenSsl10XNativeJna.EVP_CipherUpdate(context, outBuffer, 
outlen, inBuffer,
+                    remaining);
+        }
+    }
+
+    public static int RAND_bytes(ByteBuffer buf, int length) {
+        if (VERSION == VERSION_1_1_X) {
+            return OpenSsl11XNativeJna.RAND_bytes(buf, length);
+        } else {
+            return OpenSsl10XNativeJna.RAND_bytes(buf, length);
+        }
+    }
+
+    public static PointerByReference RAND_get_rand_method() {
+        if (VERSION == VERSION_1_1_X) {
+            return OpenSsl11XNativeJna.RAND_get_rand_method();
+        } else {
+            return OpenSsl10XNativeJna.RAND_get_rand_method();
+        }
+    }
+
+    public static PointerByReference RAND_SSLeay() {
+        if (VERSION == VERSION_1_1_X) {
+            return null;
+        } else {
+            return OpenSsl10XNativeJna.RAND_SSLeay();
+        }
+    }
+
+    public static String OpenSSLVersion(int i) {
+        if (VERSION == VERSION_1_1_X) {
+            return OpenSsl11XNativeJna.OpenSSL_version(i);
+        } else {
+            return OpenSsl10XNativeJna.SSLeay_version(i);
+        }
+    }
+
+    public static void ENGINE_load_rdrand() {
+        if (VERSION == VERSION_1_1_X) {
+            return;
+        } else {
+            OpenSsl10XNativeJna.ENGINE_load_rdrand();
+        }
+    }
+
+    public static void ENGINE_cleanup() {
+        if (VERSION == VERSION_1_1_X) {
+            return;
+        } else {
+            OpenSsl10XNativeJna.ENGINE_cleanup();
+        }
+    }
+
+    public static void EVP_CIPHER_CTX_cleanup(PointerByReference context) {
+        if (VERSION == VERSION_1_1_X) {
+            return;
+        } else {
+            OpenSsl10XNativeJna.EVP_CIPHER_CTX_cleanup(context);
+        }
+    }
 }
\ No newline at end of file
diff --git a/src/main/native/org/apache/commons/crypto/OpenSslInfoNative.c 
b/src/main/native/org/apache/commons/crypto/OpenSslInfoNative.c
index bb71638..937fc28 100644
--- a/src/main/native/org/apache/commons/crypto/OpenSslInfoNative.c
+++ b/src/main/native/org/apache/commons/crypto/OpenSslInfoNative.c
@@ -39,38 +39,20 @@
 #include "OpenSslInfoNative.h"
 
 #ifdef UNIX
-static unsigned long (*dlsym_SSLeay) (void);
-static char * (*dlsym_SSLeay_version) (int);
+static unsigned long (*dlsym_OpenSSL_version_num) (void);
+static const char * (*dlsym_OpenSSL_version) (int);
 static void *openssl;
 #endif
 
 #ifdef WINDOWS
-typedef unsigned long (__cdecl *__dlsym_SSLeay) (void);
-static __dlsym_SSLeay dlsym_SSLeay;
-typedef char * (__cdecl *__dlsym_SSLeay_version) (int);
-static __dlsym_SSLeay dlsym_SSLeay;
-static __dlsym_SSLeay_version dlsym_SSLeay_version;
+typedef unsigned long (__cdecl *__dlsym_OpenSSL) (void);
+static __dlsym_OpenSSL dlsym_OpenSSL;
+typedef char * (__cdecl *__dlsym_OpenSSL_version) (int);
+static __dlsym_OpenSSL dlsym_OpenSSL;
+static __dlsym_OpenSSL_version dlsym_OpenSSL_version;
 HMODULE openssl;
 #endif
 
-#ifdef UNIX
-static void get_methods(JNIEnv *env, void *openssl)
-#endif
-#ifdef WINDOWS
-static void get_methods(JNIEnv *env, HMODULE openssl)
-#endif
-{
-#ifdef UNIX
-  dlerror();  // Clear any existing error
-  LOAD_DYNAMIC_SYMBOL(dlsym_SSLeay, env, openssl, "SSLeay");
-  LOAD_DYNAMIC_SYMBOL(dlsym_SSLeay_version, env, openssl, "SSLeay_version");
-#endif
-
-#ifdef WINDOWS
-  LOAD_DYNAMIC_SYMBOL(__dlsym_SSLeay, dlsym_SSLeay, env, openssl, "SSLeay");
-  LOAD_DYNAMIC_SYMBOL(__dlsym_SSLeay_version, dlsym_SSLeay_version, env, 
openssl, "SSLeay_version");
-#endif
-}
 static int load_library(JNIEnv *env)
 {
     char msg[100];
@@ -94,30 +76,12 @@ static int load_library(JNIEnv *env)
     THROW(env, "java/lang/UnsatisfiedLinkError", msg);
     return 0;
   }
-  get_methods(env, openssl);
+#ifdef UNIX
+  LOAD_OPENSSL_VERSION_FUNCTION(dlsym_OpenSSL_version_num, env, openssl);
+#endif
   return 1;
 }
 
-JNIEXPORT jstring JNICALL 
Java_org_apache_commons_crypto_OpenSslInfoNative_SSLeayVersion
-    (JNIEnv *env, jclass clazz, jint type)
-{
-    if (!load_library(env)) {
-        return NULL;
-    }
-
-    jstring answer = (*env)->NewStringUTF(env,dlsym_SSLeay_version(type));
-    return answer;
-}
-
-JNIEXPORT jlong JNICALL Java_org_apache_commons_crypto_OpenSslInfoNative_SSLeay
-    (JNIEnv *env, jobject object)
-{
-    if (!load_library(env)) {
-        return 0;
-    }
-    return dlsym_SSLeay();
-}
-
 JNIEXPORT jstring JNICALL 
Java_org_apache_commons_crypto_OpenSslInfoNative_NativeVersion
     (JNIEnv *env, jobject object)
 {
@@ -135,3 +99,30 @@ JNIEXPORT jstring JNICALL 
Java_org_apache_commons_crypto_OpenSslInfoNative_Nativ
 {
     return (*env)->NewStringUTF(env, PROJECT_NAME);
 }
+
+JNIEXPORT jlong JNICALL 
Java_org_apache_commons_crypto_OpenSslInfoNative_OpenSSL
+  (JNIEnv *env, jclass clazz)
+{
+    if (!load_library(env)) {
+        return 0;
+    }
+    jlong version_num = (jlong)dlsym_OpenSSL_version_num();
+    return version_num;
+}
+
+JNIEXPORT jstring JNICALL 
Java_org_apache_commons_crypto_OpenSslInfoNative_OpenSSLVersion
+  (JNIEnv *env, jclass clazz, jint type)
+{
+    if (!load_library(env)) {
+        return NULL;
+    }
+    if (dlsym_OpenSSL_version_num() > VERSION_1_1_X) {
+       dlsym_OpenSSL_version = do_dlsym(env, openssl, "OpenSSL_version");
+    } else {
+       dlsym_OpenSSL_version = do_dlsym(env, openssl, "SSLeay_version");
+    }
+    jstring answer = (*env)->NewStringUTF(env,dlsym_OpenSSL_version(type));
+    return answer;
+}
+
+
diff --git a/src/main/native/org/apache/commons/crypto/cipher/OpenSslNative.c 
b/src/main/native/org/apache/commons/crypto/cipher/OpenSslNative.c
index ec9c945..25b4a06 100644
--- a/src/main/native/org/apache/commons/crypto/cipher/OpenSslNative.c
+++ b/src/main/native/org/apache/commons/crypto/cipher/OpenSslNative.c
@@ -32,9 +32,12 @@
 #ifdef UNIX
 static EVP_CIPHER_CTX * (*dlsym_EVP_CIPHER_CTX_new)(void);
 static void (*dlsym_EVP_CIPHER_CTX_free)(EVP_CIPHER_CTX *);
-static void (*dlsym_EVP_CIPHER_CTX_init)(EVP_CIPHER_CTX *);
 static int (*dlsym_EVP_CIPHER_CTX_set_padding)(EVP_CIPHER_CTX *, int);
 static int (*dlsym_EVP_CIPHER_CTX_ctrl)(EVP_CIPHER_CTX *, int, int, void *);
+static int (*dlsym_EVP_CIPHER_CTX_block_size)(EVP_CIPHER_CTX *);
+static EVP_CIPHER * (*dlsym_EVP_CIPHER_CTX_cipher)(EVP_CIPHER_CTX *);
+static unsigned long (*dlsym_EVP_CIPHER_flags)(const EVP_CIPHER *);
+static int (*dlsym_EVP_CIPHER_CTX_test_flags)(const EVP_CIPHER_CTX *, int);
 static int (*dlsym_EVP_CipherInit_ex)(EVP_CIPHER_CTX *, const EVP_CIPHER *,  \
            ENGINE *, const unsigned char *, const unsigned char *, int);
 static int (*dlsym_EVP_CipherUpdate)(EVP_CIPHER_CTX *, unsigned char *,  \
@@ -49,12 +52,13 @@ static EVP_CIPHER * (*dlsym_EVP_aes_128_cbc)(void);
 static EVP_CIPHER * (*dlsym_EVP_aes_256_gcm)(void);
 static EVP_CIPHER * (*dlsym_EVP_aes_192_gcm)(void);
 static EVP_CIPHER * (*dlsym_EVP_aes_128_gcm)(void);
+static void *openssl;
 #endif
 
 #ifdef WINDOWS
 typedef EVP_CIPHER_CTX * (__cdecl *__dlsym_EVP_CIPHER_CTX_new)(void);
 typedef void (__cdecl *__dlsym_EVP_CIPHER_CTX_free)(EVP_CIPHER_CTX *);
-typedef void (__cdecl *__dlsym_EVP_CIPHER_CTX_init)(EVP_CIPHER_CTX *);
+typedef int (__cdecl *__dlsym_EVP_CIPHER_CTX_reset)(EVP_CIPHER_CTX *);
 typedef int (__cdecl *__dlsym_EVP_CIPHER_CTX_set_padding)(EVP_CIPHER_CTX *, 
int);
 typedef int (__cdecl *__dlsym_EVP_CIPHER_CTX_ctrl)(EVP_CIPHER_CTX *, int, int, 
void *);
 typedef int (__cdecl *__dlsym_EVP_CipherInit_ex)(EVP_CIPHER_CTX *,  \
@@ -75,7 +79,7 @@ typedef EVP_CIPHER * (__cdecl *__dlsym_EVP_aes_192_gcm)(void);
 typedef EVP_CIPHER * (__cdecl *__dlsym_EVP_aes_128_gcm)(void);
 static __dlsym_EVP_CIPHER_CTX_new dlsym_EVP_CIPHER_CTX_new;
 static __dlsym_EVP_CIPHER_CTX_free dlsym_EVP_CIPHER_CTX_free;
-static __dlsym_EVP_CIPHER_CTX_init dlsym_EVP_CIPHER_CTX_init;
+static __dlsym_EVP_CIPHER_CTX_reset dlsym_EVP_CIPHER_CTX_reset;
 static __dlsym_EVP_CIPHER_CTX_set_padding dlsym_EVP_CIPHER_CTX_set_padding;
 static __dlsym_EVP_CIPHER_CTX_ctrl dlsym_EVP_CIPHER_CTX_ctrl;
 static __dlsym_EVP_CipherInit_ex dlsym_EVP_CipherInit_ex;
@@ -93,7 +97,7 @@ static __dlsym_EVP_aes_128_gcm dlsym_EVP_aes_128_gcm;
 #endif
 
 #ifdef UNIX
-static void loadAes(JNIEnv *env, void *openssl)
+static void loadAes(JNIEnv *env)
 #endif
 
 #ifdef WINDOWS
@@ -139,7 +143,7 @@ JNIEXPORT void JNICALL 
Java_org_apache_commons_crypto_cipher_OpenSslNative_initI
 {
   char msg[1000];
 #ifdef UNIX
-  void *openssl = dlopen(COMMONS_CRYPTO_OPENSSL_LIBRARY, RTLD_LAZY | 
RTLD_GLOBAL);
+  openssl = dlopen(COMMONS_CRYPTO_OPENSSL_LIBRARY, RTLD_LAZY | RTLD_GLOBAL);
 #endif
 
 #ifdef WINDOWS
@@ -161,22 +165,17 @@ JNIEXPORT void JNICALL 
Java_org_apache_commons_crypto_cipher_OpenSslNative_initI
 
 #ifdef UNIX
   dlerror();  // Clear any existing error
-  LOAD_DYNAMIC_SYMBOL(dlsym_EVP_CIPHER_CTX_new, env, openssl,  \
-                      "EVP_CIPHER_CTX_new");
-  LOAD_DYNAMIC_SYMBOL(dlsym_EVP_CIPHER_CTX_free, env, openssl,  \
-                      "EVP_CIPHER_CTX_free");
-  LOAD_DYNAMIC_SYMBOL(dlsym_EVP_CIPHER_CTX_init, env, openssl,  \
-                      "EVP_CIPHER_CTX_init");
-  LOAD_DYNAMIC_SYMBOL(dlsym_EVP_CIPHER_CTX_set_padding, env, openssl,  \
-                      "EVP_CIPHER_CTX_set_padding");
-  LOAD_DYNAMIC_SYMBOL(dlsym_EVP_CIPHER_CTX_ctrl, env, openssl,  \
-                      "EVP_CIPHER_CTX_ctrl");
-  LOAD_DYNAMIC_SYMBOL(dlsym_EVP_CipherInit_ex, env, openssl,  \
-                      "EVP_CipherInit_ex");
-  LOAD_DYNAMIC_SYMBOL(dlsym_EVP_CipherUpdate, env, openssl,  \
-                      "EVP_CipherUpdate");
-  LOAD_DYNAMIC_SYMBOL(dlsym_EVP_CipherFinal_ex, env, openssl,  \
-                      "EVP_CipherFinal_ex");
+  LOAD_DYNAMIC_SYMBOL(dlsym_EVP_CIPHER_CTX_new, env, openssl, 
"EVP_CIPHER_CTX_new");
+  LOAD_DYNAMIC_SYMBOL(dlsym_EVP_CIPHER_CTX_free, env, openssl, 
"EVP_CIPHER_CTX_free");
+  LOAD_DYNAMIC_SYMBOL(dlsym_EVP_CIPHER_CTX_set_padding, env, openssl, 
"EVP_CIPHER_CTX_set_padding");
+  LOAD_DYNAMIC_SYMBOL(dlsym_EVP_CIPHER_CTX_ctrl, env, openssl, 
"EVP_CIPHER_CTX_ctrl");
+  LOAD_DYNAMIC_SYMBOL(dlsym_EVP_CIPHER_CTX_block_size, env, openssl, 
"EVP_CIPHER_CTX_block_size");
+  LOAD_DYNAMIC_SYMBOL(dlsym_EVP_CIPHER_CTX_cipher, env, openssl, 
"EVP_CIPHER_CTX_cipher");
+  LOAD_DYNAMIC_SYMBOL(dlsym_EVP_CIPHER_flags, env, openssl, 
"EVP_CIPHER_flags");
+  LOAD_DYNAMIC_SYMBOL(dlsym_EVP_CIPHER_CTX_test_flags, env, openssl, 
"EVP_CIPHER_CTX_test_flags");
+  LOAD_DYNAMIC_SYMBOL(dlsym_EVP_CipherInit_ex, env, openssl, 
"EVP_CipherInit_ex");
+  LOAD_DYNAMIC_SYMBOL(dlsym_EVP_CipherUpdate, env, openssl, 
"EVP_CipherUpdate");
+  LOAD_DYNAMIC_SYMBOL(dlsym_EVP_CipherFinal_ex, env, openssl, 
"EVP_CipherFinal_ex");
 #endif
 
 #ifdef WINDOWS
@@ -184,8 +183,9 @@ JNIEXPORT void JNICALL 
Java_org_apache_commons_crypto_cipher_OpenSslNative_initI
                       env, openssl, "EVP_CIPHER_CTX_new");
   LOAD_DYNAMIC_SYMBOL(__dlsym_EVP_CIPHER_CTX_free, dlsym_EVP_CIPHER_CTX_free,  
\
                       env, openssl, "EVP_CIPHER_CTX_free");
-  LOAD_DYNAMIC_SYMBOL(__dlsym_EVP_CIPHER_CTX_init, dlsym_EVP_CIPHER_CTX_init,  
\
-                      env, openssl, "EVP_CIPHER_CTX_init");
+  LOAD_DYNAMIC_SYMBOL(__dlsym_EVP_CIPHER_CTX_reset,  \
+                      dlsym_EVP_CIPHER_CTX_reset, env,
+                      openssl, "EVP_CIPHER_CTX_reset");
   LOAD_DYNAMIC_SYMBOL(__dlsym_EVP_CIPHER_CTX_set_padding,  \
                       dlsym_EVP_CIPHER_CTX_set_padding, env,  \
                       openssl, "EVP_CIPHER_CTX_set_padding");
@@ -197,7 +197,7 @@ JNIEXPORT void JNICALL 
Java_org_apache_commons_crypto_cipher_OpenSslNative_initI
                       env, openssl, "EVP_CipherFinal_ex");
 #endif
 
-  loadAes(env, openssl);
+  loadAes(env);
   jthrowable jthr = (*env)->ExceptionOccurred(env);
   if (jthr) {
     (*env)->DeleteLocalRef(env, jthr);
@@ -209,9 +209,14 @@ JNIEXPORT void JNICALL 
Java_org_apache_commons_crypto_cipher_OpenSslNative_initI
 
 typedef struct EVP_CTX_Wrapper {
   int initialized;
+  int encrypt; // ENCRYPT_MODE or DECRYPT_MODE
   EVP_CIPHER_CTX *ctx;
 } EVP_CTX_Wrapper;
 
+static int check_update_max_output_len(EVP_CTX_Wrapper *wrapper, int 
input_len, int max_output_len);
+static int check_doFinal_max_output_len(JNIEnv *env, EVP_CIPHER_CTX *context, 
int max_output_len);
+static int is_bad_tag(EVP_CTX_Wrapper *wrapper);
+
 #define CTX_WRAPPER(addr) ((EVP_CTX_Wrapper *)(ptrdiff_t) addr)
 
 static EVP_CTX_Wrapper * new_context_wrapper(JNIEnv *env) {
@@ -412,6 +417,7 @@ JNIEXPORT jlong JNICALL 
Java_org_apache_commons_crypto_cipher_OpenSslNative_init
   }
 
   // everything is OK,
+  wrapper->encrypt = mode;
   wrapper->initialized = 1;
 
 cleanup:
@@ -428,31 +434,6 @@ cleanup:
   return JLONG(wrapper);
 }
 
-// https://www.openssl.org/docs/crypto/EVP_EncryptInit.html
-static int check_update_max_output_len(EVP_CIPHER_CTX *context, int input_len,
-    int max_output_len)
-{
-  if (context->flags & EVP_CIPH_NO_PADDING) {
-    if (max_output_len >= input_len) {
-      return 1;
-    }
-    return 0;
-  } else {
-    int b = context->cipher->block_size;
-    if (context->encrypt) {
-      if (max_output_len >= input_len + b - 1) {
-        return 1;
-      }
-    } else {
-      if (max_output_len >= input_len + b) {
-        return 1;
-      }
-    }
-
-    return 0;
-  }
-}
-
 JNIEXPORT jint JNICALL 
Java_org_apache_commons_crypto_cipher_OpenSslNative_update
     (JNIEnv *env, jclass clazz, jlong ctx, jobject input, jint input_offset,
     jint input_len, jobject output, jint output_offset, jint max_output_len)
@@ -462,7 +443,7 @@ JNIEXPORT jint JNICALL 
Java_org_apache_commons_crypto_cipher_OpenSslNative_updat
     return 0;
   }
 
-  if (!check_update_max_output_len(context, input_len, max_output_len)) {
+  if (!check_update_max_output_len(CTX_WRAPPER(ctx), input_len, 
max_output_len)) {
     THROW(env, "javax/crypto/ShortBufferException",  \
         "Output buffer is not sufficient.");
     return 0;
@@ -495,10 +476,8 @@ JNIEXPORT jint JNICALL 
Java_org_apache_commons_crypto_cipher_OpenSslNative_updat
   }
 
   // when provide AAD to EVP cipher, output is NULL.
-  if (output != NULL
-        && !check_update_max_output_len(context, input_len, max_output_len)) {
-    THROW(env, "javax/crypto/ShortBufferException",  \
-        "Output buffer is not sufficient.");
+  if (output != NULL && !check_update_max_output_len(CTX_WRAPPER(ctx), 
input_len, max_output_len)) {
+    THROW(env, "javax/crypto/ShortBufferException", "Output buffer is not 
sufficient.");
     return 0;
   }
 
@@ -544,7 +523,7 @@ JNIEXPORT jint JNICALL 
Java_org_apache_commons_crypto_cipher_OpenSslNative_updat
     return 0;
   }
 
-  if (!check_update_max_output_len(context, input_len, max_output_len)) {
+  if (!check_update_max_output_len(CTX_WRAPPER(ctx), input_len, 
max_output_len)) {
     THROW(env, "javax/crypto/ShortBufferException",  \
         "Output buffer is not sufficient.");
     return 0;
@@ -572,23 +551,6 @@ cleanup:
   return output_len;
 }
 
-
-// https://www.openssl.org/docs/crypto/EVP_EncryptInit.html
-static int check_doFinal_max_output_len(EVP_CIPHER_CTX *context,
-    int max_output_len)
-{
-  if (context->flags & EVP_CIPH_NO_PADDING) {
-    return 1;
-  } else {
-    int b = context->cipher->block_size;
-    if (max_output_len >= b) {
-      return 1;
-    }
-
-    return 0;
-  }
-}
-
 JNIEXPORT jint JNICALL 
Java_org_apache_commons_crypto_cipher_OpenSslNative_doFinal
     (JNIEnv *env, jclass clazz, jlong ctx, jobject output, jint offset,
     jint max_output_len)
@@ -598,7 +560,7 @@ JNIEXPORT jint JNICALL 
Java_org_apache_commons_crypto_cipher_OpenSslNative_doFin
     return 0;
   }
 
-  if (!check_doFinal_max_output_len(context, max_output_len)) {
+  if (!check_doFinal_max_output_len(env, context, max_output_len)) {
     THROW(env, "javax/crypto/ShortBufferException",  \
         "Output buffer is not sufficient.");
     return 0;
@@ -613,8 +575,7 @@ JNIEXPORT jint JNICALL 
Java_org_apache_commons_crypto_cipher_OpenSslNative_doFin
   int output_len = 0;
   if (!dlsym_EVP_CipherFinal_ex(context, output_bytes, &output_len)) {
     // validate tag in GCM mode when decrypt
-    if ((context->cipher->flags & EVP_CIPH_MODE) == EVP_CIPH_GCM_MODE
-        && context->encrypt == DECRYPT_MODE) {
+    if (is_bad_tag(CTX_WRAPPER(ctx))) {
       THROW(env, "javax/crypto/AEADBadTagException", "Tag mismatch!");
     } else {
       THROW(env, "java/lang/InternalError", "Error in EVP_CipherFinal_ex.");
@@ -633,7 +594,7 @@ JNIEXPORT jint JNICALL 
Java_org_apache_commons_crypto_cipher_OpenSslNative_doFin
     return 0;
   }
 
-  if (!check_doFinal_max_output_len(context, max_output_len)) {
+  if (!check_doFinal_max_output_len(env, context, max_output_len)) {
     THROW(env, "javax/crypto/ShortBufferException",  \
         "Output buffer is not sufficient.");
     return 0;
@@ -651,8 +612,7 @@ JNIEXPORT jint JNICALL 
Java_org_apache_commons_crypto_cipher_OpenSslNative_doFin
 
   if (rc == 0) {
     // validate tag in GCM mode when decrypt
-    if ((context->cipher->flags & EVP_CIPH_MODE) == EVP_CIPH_GCM_MODE
-      && context->encrypt == DECRYPT_MODE) {
+    if (is_bad_tag(CTX_WRAPPER(ctx))) {
     THROW(env, "javax/crypto/AEADBadTagException", "Tag mismatch!");
     } else {
     THROW(env, "java/lang/InternalError", "Error in EVP_CipherFinal_ex.");
@@ -716,3 +676,50 @@ JNIEXPORT void JNICALL 
Java_org_apache_commons_crypto_cipher_OpenSslNative_clean
   EVP_CTX_Wrapper *wrapper = CTX_WRAPPER(ctx);
   free_context_wrapper(wrapper);
 }
+
+static int check_update_max_output_len(EVP_CTX_Wrapper *wrapper, int 
input_len, int max_output_len)
+{
+  if (dlsym_EVP_CIPHER_CTX_test_flags(wrapper->ctx, EVP_CIPH_NO_PADDING) == 
EVP_CIPH_NO_PADDING) {
+    if (max_output_len >= input_len) {
+      return 1;
+    }
+    return 0;
+  } else {
+    int b = dlsym_EVP_CIPHER_CTX_block_size(wrapper->ctx);
+    if (wrapper->encrypt) {
+      if (max_output_len >= input_len + b - 1) {
+        return 1;
+      }
+    } else {
+      if (max_output_len >= input_len + b) {
+        return 1;
+      }
+    }
+    return 0;
+  }
+}
+
+static int check_doFinal_max_output_len(JNIEnv *env, EVP_CIPHER_CTX *context, 
int max_output_len)
+{
+  if (dlsym_EVP_CIPHER_CTX_test_flags(context, EVP_CIPH_NO_PADDING) == 
EVP_CIPH_NO_PADDING) {
+    return 1;
+  } else {
+    int b = dlsym_EVP_CIPHER_CTX_block_size(context);
+    if (max_output_len >= b) {
+      return 1;
+    }
+    return 0;
+  }
+}
+
+static int is_bad_tag(EVP_CTX_Wrapper *wrapper)
+{
+  EVP_CIPHER* ciph = dlsym_EVP_CIPHER_CTX_cipher(wrapper->ctx);
+  unsigned long flags = dlsym_EVP_CIPHER_flags(ciph);
+  if ((flags & EVP_CIPH_MODE) == EVP_CIPH_GCM_MODE && wrapper->encrypt == 
DECRYPT_MODE) {
+    return 1;
+  }
+  return 0;
+}
+
+
diff --git 
a/src/main/native/org/apache/commons/crypto/org_apache_commons_crypto.h 
b/src/main/native/org/apache/commons/crypto/org_apache_commons_crypto.h
index b980b77..d0b43ef 100644
--- a/src/main/native/org/apache/commons/crypto/org_apache_commons_crypto.h
+++ b/src/main/native/org/apache/commons/crypto/org_apache_commons_crypto.h
@@ -94,11 +94,30 @@ void *do_dlsym(JNIEnv *env, void *handle, const char 
*symbol) {
   return func_ptr;
 }
 
+static __attribute__ ((unused))
+void *do_version_dlsym(JNIEnv *env, void *handle) {
+  if (!env || !handle) {
+    THROW(env, "java/lang/InternalError", NULL);
+      return NULL;
+  }
+  void *func_ptr = dlsym(handle, "OpenSSL_version_num");
+  if (func_ptr == NULL) {
+    func_ptr = dlsym(handle, "SSLeay");
+  }
+  return func_ptr;
+}
+
 /* A helper macro to dlsym the requisite dynamic symbol and bail-out on error. 
*/
 #define LOAD_DYNAMIC_SYMBOL(func_ptr, env, handle, symbol) \
   if ((func_ptr = do_dlsym(env, handle, symbol)) == NULL) { \
     return; \
   }
+
+/* A macro to dlsym the appropriate OpenSSL version number function. */
+#define LOAD_OPENSSL_VERSION_FUNCTION(func_ptr, env, handle) \
+  if ((func_ptr = do_version_dlsym(env, handle)) == NULL) { \
+    THROW(env, "java/lang/Error", NULL); \
+  }
 #endif
 // Unix part end
 
@@ -195,6 +214,7 @@ static FARPROC WINAPI do_dlsym(JNIEnv *env, HMODULE handle, 
LPCSTR symbol) {
 #include <openssl/aes.h>
 #include <openssl/evp.h>
 #include <openssl/err.h>
+#include <openssl/opensslv.h>
 
 /**
  * A helper macro to convert the java 'context-handle'
@@ -224,6 +244,8 @@ static FARPROC WINAPI do_dlsym(JNIEnv *env, HMODULE handle, 
LPCSTR symbol) {
 #define NOPADDING 0
 #define PKCS5PADDING 1
 
+#define VERSION_1_0_X 0x10000000
+#define VERSION_1_1_X 0x10100000
 
 #endif
 
diff --git 
a/src/main/native/org/apache/commons/crypto/random/OpenSslCryptoRandomNative.c 
b/src/main/native/org/apache/commons/crypto/random/OpenSslCryptoRandomNative.c
index 56668cb..9f6078d 100644
--- 
a/src/main/native/org/apache/commons/crypto/random/OpenSslCryptoRandomNative.c
+++ 
b/src/main/native/org/apache/commons/crypto/random/OpenSslCryptoRandomNative.c
@@ -43,60 +43,51 @@
 #ifdef UNIX
 static void * (*dlsym_CRYPTO_malloc) (int, const char *, int);
 static void (*dlsym_CRYPTO_free) (void *);
-static int (*dlsym_CRYPTO_num_locks) (void);
-static void (*dlsym_CRYPTO_set_locking_callback) (void (*)());
-static void (*dlsym_CRYPTO_set_id_callback) (unsigned long (*)());
-static void (*dlsym_ENGINE_load_rdrand) (void);
 static ENGINE * (*dlsym_ENGINE_by_id) (const char *);
 static int (*dlsym_ENGINE_init) (ENGINE *);
 static int (*dlsym_ENGINE_set_default) (ENGINE *, unsigned int);
 static int (*dlsym_ENGINE_finish) (ENGINE *);
 static int (*dlsym_ENGINE_free) (ENGINE *);
-static void (*dlsym_ENGINE_cleanup) (void);
 static int (*dlsym_RAND_bytes) (unsigned char *, int);
 static unsigned long (*dlsym_ERR_get_error) (void);
+static unsigned long (*dlsym_OpenSSL_version_num)(void);
+static void *openssl;
 #endif
 
 #ifdef WINDOWS
 typedef void * (__cdecl *__dlsym_CRYPTO_malloc) (int, const char *, int);
 typedef void (__cdecl *__dlsym_CRYPTO_free) (void *);
-typedef int (__cdecl *__dlsym_CRYPTO_num_locks) (void);
-typedef void (__cdecl *__dlsym_CRYPTO_set_locking_callback)  \
-              (void (*)(int, int, char *, int));
-typedef void (__cdecl *__dlsym_ENGINE_load_rdrand) (void);
 typedef ENGINE * (__cdecl *__dlsym_ENGINE_by_id) (const char *);
 typedef int (__cdecl *__dlsym_ENGINE_init) (ENGINE *);
 typedef int (__cdecl *__dlsym_ENGINE_set_default) (ENGINE *, unsigned int);
 typedef int (__cdecl *__dlsym_ENGINE_finish) (ENGINE *);
 typedef int (__cdecl *__dlsym_ENGINE_free) (ENGINE *);
-typedef void (__cdecl *__dlsym_ENGINE_cleanup) (void);
 typedef int (__cdecl *__dlsym_RAND_bytes) (unsigned char *, int);
 typedef unsigned long (__cdecl *__dlsym_ERR_get_error) (void);
 static __dlsym_CRYPTO_malloc dlsym_CRYPTO_malloc;
 static __dlsym_CRYPTO_free dlsym_CRYPTO_free;
-static __dlsym_CRYPTO_num_locks dlsym_CRYPTO_num_locks;
-static __dlsym_CRYPTO_set_locking_callback dlsym_CRYPTO_set_locking_callback;
-static __dlsym_ENGINE_load_rdrand dlsym_ENGINE_load_rdrand;
 static __dlsym_ENGINE_by_id dlsym_ENGINE_by_id;
 static __dlsym_ENGINE_init dlsym_ENGINE_init;
 static __dlsym_ENGINE_set_default dlsym_ENGINE_set_default;
 static __dlsym_ENGINE_finish dlsym_ENGINE_finish;
 static __dlsym_ENGINE_free dlsym_ENGINE_free;
-static __dlsym_ENGINE_cleanup dlsym_ENGINE_cleanup;
 static __dlsym_RAND_bytes dlsym_RAND_bytes;
 static __dlsym_ERR_get_error dlsym_ERR_get_error;
 #endif
 
-static ENGINE * openssl_rand_init(void);
-static void openssl_rand_clean(ENGINE *eng, int clean_locks);
+static ENGINE * openssl_rand_init(JNIEnv *env);
+static void openssl_rand_clean(JNIEnv *env, ENGINE *eng, int clean_locks);
 static int openssl_rand_bytes(unsigned char *buf, int num);
+static void pthreads_locking_callback(int mode, int type, char *file, int 
line);
+static unsigned long pthreads_thread_id(void);
+static pthread_mutex_t *lock_cs;
 
 JNIEXPORT void JNICALL 
Java_org_apache_commons_crypto_random_OpenSslCryptoRandomNative_initSR
     (JNIEnv *env, jclass clazz)
 {
   char msg[1000];
 #ifdef UNIX
-  void *openssl = dlopen(COMMONS_CRYPTO_OPENSSL_LIBRARY, RTLD_LAZY | 
RTLD_GLOBAL);
+  openssl = dlopen(COMMONS_CRYPTO_OPENSSL_LIBRARY, RTLD_LAZY | RTLD_GLOBAL);
 #endif
 
 #ifdef WINDOWS
@@ -120,22 +111,15 @@ JNIEXPORT void JNICALL 
Java_org_apache_commons_crypto_random_OpenSslCryptoRandom
   dlerror();  // Clear any existing error
   LOAD_DYNAMIC_SYMBOL(dlsym_CRYPTO_malloc, env, openssl, "CRYPTO_malloc");
   LOAD_DYNAMIC_SYMBOL(dlsym_CRYPTO_free, env, openssl, "CRYPTO_free");
-  LOAD_DYNAMIC_SYMBOL(dlsym_CRYPTO_num_locks, env, openssl, 
"CRYPTO_num_locks");
-  LOAD_DYNAMIC_SYMBOL(dlsym_CRYPTO_set_locking_callback,  \
-                      env, openssl, "CRYPTO_set_locking_callback");
-  LOAD_DYNAMIC_SYMBOL(dlsym_CRYPTO_set_id_callback, env,  \
-                      openssl, "CRYPTO_set_id_callback");
-  LOAD_DYNAMIC_SYMBOL(dlsym_ENGINE_load_rdrand, env,  \
-                      openssl, "ENGINE_load_rdrand");
   LOAD_DYNAMIC_SYMBOL(dlsym_ENGINE_by_id, env, openssl, "ENGINE_by_id");
   LOAD_DYNAMIC_SYMBOL(dlsym_ENGINE_init, env, openssl, "ENGINE_init");
   LOAD_DYNAMIC_SYMBOL(dlsym_ENGINE_set_default, env,  \
                       openssl, "ENGINE_set_default");
   LOAD_DYNAMIC_SYMBOL(dlsym_ENGINE_finish, env, openssl, "ENGINE_finish");
   LOAD_DYNAMIC_SYMBOL(dlsym_ENGINE_free, env, openssl, "ENGINE_free");
-  LOAD_DYNAMIC_SYMBOL(dlsym_ENGINE_cleanup, env, openssl, "ENGINE_cleanup");
   LOAD_DYNAMIC_SYMBOL(dlsym_RAND_bytes, env, openssl, "RAND_bytes");
   LOAD_DYNAMIC_SYMBOL(dlsym_ERR_get_error, env, openssl, "ERR_get_error");
+  LOAD_OPENSSL_VERSION_FUNCTION(dlsym_OpenSSL_version_num, env, openssl);
 #endif
 
 #ifdef WINDOWS
@@ -143,13 +127,6 @@ JNIEXPORT void JNICALL 
Java_org_apache_commons_crypto_random_OpenSslCryptoRandom
                       env, openssl, "CRYPTO_malloc");
   LOAD_DYNAMIC_SYMBOL(__dlsym_CRYPTO_free, dlsym_CRYPTO_free,  \
                       env, openssl, "CRYPTO_free");
-  LOAD_DYNAMIC_SYMBOL(__dlsym_CRYPTO_num_locks, dlsym_CRYPTO_num_locks,  \
-                      env, openssl, "CRYPTO_num_locks");
-  LOAD_DYNAMIC_SYMBOL(__dlsym_CRYPTO_set_locking_callback,  \
-                      dlsym_CRYPTO_set_locking_callback,  \
-                      env, openssl, "CRYPTO_set_locking_callback");
-  LOAD_DYNAMIC_SYMBOL(__dlsym_ENGINE_load_rdrand, dlsym_ENGINE_load_rdrand,  \
-                      env, openssl, "ENGINE_load_rdrand");
   LOAD_DYNAMIC_SYMBOL(__dlsym_ENGINE_by_id, dlsym_ENGINE_by_id,  \
                       env, openssl, "ENGINE_by_id");
   LOAD_DYNAMIC_SYMBOL(__dlsym_ENGINE_init, dlsym_ENGINE_init,  \
@@ -160,15 +137,13 @@ JNIEXPORT void JNICALL 
Java_org_apache_commons_crypto_random_OpenSslCryptoRandom
                       env, openssl, "ENGINE_finish");
   LOAD_DYNAMIC_SYMBOL(__dlsym_ENGINE_free, dlsym_ENGINE_free,  \
                       env, openssl, "ENGINE_free");
-  LOAD_DYNAMIC_SYMBOL(__dlsym_ENGINE_cleanup, dlsym_ENGINE_cleanup,  \
-                      env, openssl, "ENGINE_cleanup");
   LOAD_DYNAMIC_SYMBOL(__dlsym_RAND_bytes, dlsym_RAND_bytes,  \
                       env, openssl, "RAND_bytes");
   LOAD_DYNAMIC_SYMBOL(__dlsym_ERR_get_error, dlsym_ERR_get_error,  \
                       env, openssl, "ERR_get_error");
 #endif
 
-  openssl_rand_init();
+  openssl_rand_init(env);
 }
 
 JNIEXPORT jboolean JNICALL 
Java_org_apache_commons_crypto_random_OpenSslCryptoRandomNative_nextRandBytes___3B
@@ -246,9 +221,11 @@ static void pthreads_locking_callback(int mode, int type, 
char *file, int line);
 static unsigned long pthreads_thread_id(void);
 static pthread_mutex_t *lock_cs;
 
-static void locks_setup(void)
+static void locks_setup(JNIEnv *env)
 {
   int i;
+  static int (*dlsym_CRYPTO_num_locks) (void);
+  dlsym_CRYPTO_num_locks = do_dlsym(env, openssl, "CRYPTO_num_locks");
   lock_cs = dlsym_CRYPTO_malloc(dlsym_CRYPTO_num_locks() *  \
       sizeof(pthread_mutex_t), __FILE__, __LINE__);
 
@@ -256,13 +233,22 @@ static void locks_setup(void)
     pthread_mutex_init(&(lock_cs[i]), NULL);
   }
 
+  static void (*dlsym_CRYPTO_set_id_callback) (unsigned long (*)());
+  dlsym_CRYPTO_set_id_callback = do_dlsym(env, openssl, 
"CRYPTO_set_id_callback");
+  static void (*dlsym_CRYPTO_set_locking_callback) (void (*)());
+  dlsym_CRYPTO_set_locking_callback = do_dlsym(env, openssl, 
"CRYPTO_set_locking_callback");
+
   dlsym_CRYPTO_set_id_callback((unsigned long (*)())pthreads_thread_id);
   dlsym_CRYPTO_set_locking_callback((void (*)())pthreads_locking_callback);
 }
 
-static void locks_cleanup(void)
+static void locks_cleanup(JNIEnv *env)
 {
   int i;
+  static int (*dlsym_CRYPTO_num_locks) (void);
+  dlsym_CRYPTO_num_locks = do_dlsym(env, openssl, "CRYPTO_num_locks");
+  static void (*dlsym_CRYPTO_set_locking_callback) (void (*)());
+  dlsym_CRYPTO_set_locking_callback = do_dlsym(env, openssl, 
"CRYPTO_set_locking_callback");
   dlsym_CRYPTO_set_locking_callback(NULL);
 
   for (i = 0; i < dlsym_CRYPTO_num_locks(); i++) {
@@ -294,11 +280,15 @@ static unsigned long pthreads_thread_id(void)
  * If using an Intel chipset with RDRAND, the high-performance hardware
  * random number generator will be used.
  */
-static ENGINE * openssl_rand_init(void)
+static ENGINE * openssl_rand_init(JNIEnv *env)
 {
-  locks_setup();
+  if (dlsym_OpenSSL_version_num() < VERSION_1_1_X) {
+    locks_setup(env);
+    static void (*dlsym_ENGINE_load_rdrand) (void);
+    dlsym_ENGINE_load_rdrand = do_dlsym(env, openssl, "ENGINE_load_rdrand");
+    dlsym_ENGINE_load_rdrand();
+  }
 
-  dlsym_ENGINE_load_rdrand();
   ENGINE *eng = dlsym_ENGINE_by_id("rdrand");
 
   int ret = -1;
@@ -321,22 +311,28 @@ static ENGINE * openssl_rand_init(void)
   } while(0);
 
   if (ret == -1) {
-    openssl_rand_clean(eng, 0);
+    openssl_rand_clean(env, eng, 0);
   }
 
   return eng;
 }
 
-static void openssl_rand_clean(ENGINE *eng, int clean_locks)
+static void openssl_rand_clean(JNIEnv *env, ENGINE *eng, int clean_locks)
 {
   if (NULL != eng) {
     dlsym_ENGINE_finish(eng);
     dlsym_ENGINE_free(eng);
   }
 
-  dlsym_ENGINE_cleanup();
-  if (clean_locks) {
-    locks_cleanup();
+  if (dlsym_OpenSSL_version_num() < VERSION_1_1_X) {
+    static void (*dlsym_ENGINE_cleanup) (void);
+    if((dlsym_ENGINE_cleanup = do_dlsym(env, openssl, "ENGINE_cleanup")) == 
NULL) {
+       THROW(env, "java/lang/UnsatisfiedLinkError", "ENGINE_cleanup");
+    }
+    dlsym_ENGINE_cleanup();
+    if (clean_locks) {
+      locks_cleanup(env);
+    }
   }
 }
 
diff --git 
a/src/test/java/org/apache/commons/crypto/jna/OpenSslNativeJnaTest.java 
b/src/test/java/org/apache/commons/crypto/jna/OpenSslNativeJnaTest.java
index 28b3381..4857aea 100644
--- a/src/test/java/org/apache/commons/crypto/jna/OpenSslNativeJnaTest.java
+++ b/src/test/java/org/apache/commons/crypto/jna/OpenSslNativeJnaTest.java
@@ -25,7 +25,7 @@ public class OpenSslNativeJnaTest {
     @Test
     public void test() {
         if (OpenSslJna.isEnabled()) {
-            System.out.println("** INFO: JNA is using: " + 
OpenSslNativeJna.SSLeay_version(0));
+            System.out.println("** INFO: JNA is using: " + 
OpenSslJna.OpenSSLVersion(0));
         } else {
             System.out.println("** WARN: JNA could not be enabled: " + 
OpenSslJna.initialisationError().getMessage());
         }

Reply via email to