[jitsi-dev] [libjitsi-commits] master: Prepares to use SHA-1 from OpenSSL instead of BouncyCastle. (8dd83b6)


#1

Out of curiosity: why all that JNI mess when SHA1 is available from both the JRE and BouncyCastle? Performance?

(And the OpenSSL license being considered problematic in combination with the GPL in Debian, not sure about the implications to LGPL).

Freundliche Grüsse,
Ingo Bauersachs

-- sent from my mobile

Freundliche Grüsse,
Ingo Bauersachs

-- sent from my mobile

···

Le 25.10.2014 à 00:44, "lyubomir.marinov@jitsi.org" <lyubomir.marinov@jitsi.org> a écrit :

Repository : ssh://lists.jitsi.org/libjitsi

On branch : master
Link : https://github.com/jitsi/libjitsi/compare/c07e2f4c3af0ad688c524d740c24f20c13b421ca...8dd83b679f6b44243fa9771f920a3a542fb4a78c

---------------------------------------------------------------

commit 8dd83b679f6b44243fa9771f920a3a542fb4a78c
Author: Lyubomir Marinov <lyubomir.marinov@jitsi.org>
Date: Fri Oct 24 20:43:41 2014 +0300

   Prepares to use SHA-1 from OpenSSL instead of BouncyCastle.

---------------------------------------------------------------

8dd83b679f6b44243fa9771f920a3a542fb4a78c
src/native/openssl/Digest.c | 102 +++++++
src/native/openssl/Digest.h | 77 +++++
.../jitsi/impl/neomedia/transform/srtp/AES.java | 4 +-
.../neomedia/transform/srtp/OpenSSLDigest.java | 307 ++++++++++++++++++++
.../jitsi/impl/neomedia/transform/srtp/SHA1.java | 63 +++-
5 files changed, 548 insertions(+), 5 deletions(-)

diff --git a/src/native/openssl/Digest.c b/src/native/openssl/Digest.c
new file mode 100644
index 0000000..f3b1c2e
--- /dev/null
+++ b/src/native/openssl/Digest.c
@@ -0,0 +1,102 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+
+#include "Digest.h"
+
+#include <openssl/evp.h>
+#include <stdint.h>
+
+JNIEXPORT jint JNICALL
+Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1DigestFinal_1ex
+ (JNIEnv *env, jclass clazz, jlong ctx, jbyteArray md, jint off)
+{
+ jbyte *md_ = (*env)->GetPrimitiveArrayCritical(env, md, NULL);
+ int i;
+
+ if (md_)
+ {
+ unsigned int s = 0;
+
+ i = EVP_DigestFinal_ex((EVP_MD_CTX *) (intptr_t) ctx, md_ + off, &s);
+ (*env)->ReleasePrimitiveArrayCritical(env, md, md_, 0);
+ i = i ? ((int) s) : -1;
+ }
+ else
+ {
+ i = -1;
+ }
+ return i;
+}
+
+JNIEXPORT jboolean JNICALL
+Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1DigestInit_1ex
+ (JNIEnv *env, jclass clazz, jlong ctx, jlong type, jlong impl)
+{
+ int i
+ = EVP_DigestInit_ex(
+ (EVP_MD_CTX *) (intptr_t) ctx,
+ (const EVP_MD *) (intptr_t) type,
+ (ENGINE *) (intptr_t) impl);
+
+ return i ? JNI_TRUE : JNI_FALSE;
+}
+
+JNIEXPORT jboolean JNICALL
+Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1DigestUpdate
+ (JNIEnv *env, jclass clazz, jlong ctx, jbyteArray d, jint off, jint cnt)
+{
+ jbyte *d_ = (*env)->GetPrimitiveArrayCritical(env, d, NULL);
+ jboolean b;
+
+ if (d_)
+ {
+ int i = EVP_DigestUpdate((EVP_MD_CTX *) (intptr_t) ctx, d_ + off, cnt);
+
+ (*env)->ReleasePrimitiveArrayCritical(env, d, d_, JNI_ABORT);
+ b = i ? JNI_TRUE : JNI_FALSE;
+ }
+ else
+ {
+ b = JNI_FALSE;
+ }
+ return b;
+}
+
+JNIEXPORT jint JNICALL
+Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1MD_1CTX_1block_1size
+ (JNIEnv *env, jclass clazz, jlong ctx)
+{
+ return EVP_MD_CTX_block_size((const EVP_MD_CTX *) (intptr_t) ctx);
+}
+
+JNIEXPORT jlong JNICALL
+Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1MD_1CTX_1create
+ (JNIEnv *env, jclass clazz)
+{
+ return (jlong) (intptr_t) EVP_MD_CTX_create();
+}
+
+JNIEXPORT void JNICALL
+Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1MD_1CTX_1destroy
+ (JNIEnv *env, jclass clazz, jlong ctx)
+{
+ EVP_MD_CTX_destroy((EVP_MD_CTX *) (intptr_t) ctx);
+}
+
+JNIEXPORT jint JNICALL
+Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1MD_1CTX_1size
+ (JNIEnv *env, jclass clazz, jlong ctx)
+{
+ return EVP_MD_CTX_size((const EVP_MD_CTX *) (intptr_t) ctx);
+}
+
+JNIEXPORT jlong JNICALL
+Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1sha1
+ (JNIEnv *env, jclass clazz)
+{
+ return (jlong) (intptr_t) EVP_sha1();
+}
diff --git a/src/native/openssl/Digest.h b/src/native/openssl/Digest.h
new file mode 100644
index 0000000..f79df6a
--- /dev/null
+++ b/src/native/openssl/Digest.h
@@ -0,0 +1,77 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest */
+
+#ifndef _Included_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest
+#define _Included_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest
+ * Method: EVP_DigestFinal_ex
+ * Signature: (J[BI)I
+ */
+JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1DigestFinal_1ex
+ (JNIEnv *, jclass, jlong, jbyteArray, jint);
+
+/*
+ * Class: org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest
+ * Method: EVP_DigestInit_ex
+ * Signature: (JJJ)Z
+ */
+JNIEXPORT jboolean JNICALL Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1DigestInit_1ex
+ (JNIEnv *, jclass, jlong, jlong, jlong);
+
+/*
+ * Class: org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest
+ * Method: EVP_DigestUpdate
+ * Signature: (J[BII)Z
+ */
+JNIEXPORT jboolean JNICALL Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1DigestUpdate
+ (JNIEnv *, jclass, jlong, jbyteArray, jint, jint);
+
+/*
+ * Class: org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest
+ * Method: EVP_MD_CTX_block_size
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1MD_1CTX_1block_1size
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest
+ * Method: EVP_MD_CTX_create
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1MD_1CTX_1create
+ (JNIEnv *, jclass);
+
+/*
+ * Class: org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest
+ * Method: EVP_MD_CTX_destroy
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1MD_1CTX_1destroy
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest
+ * Method: EVP_MD_CTX_size
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1MD_1CTX_1size
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest
+ * Method: EVP_sha1
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1sha1
+ (JNIEnv *, jclass);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/org/jitsi/impl/neomedia/transform/srtp/AES.java b/src/org/jitsi/impl/neomedia/transform/srtp/AES.java
index 503d815..2682bd8 100644
--- a/src/org/jitsi/impl/neomedia/transform/srtp/AES.java
+++ b/src/org/jitsi/impl/neomedia/transform/srtp/AES.java
@@ -109,8 +109,8 @@ class AES
                {
                    logger.warn(
                            "Failed to employ a java.security.Provider for an"
- + " optimized AES implementation.",
- t);
+ + " optimized AES implementation: "
+ + t.getLocalizedMessage());
                }
            }
        }
diff --git a/src/org/jitsi/impl/neomedia/transform/srtp/OpenSSLDigest.java b/src/org/jitsi/impl/neomedia/transform/srtp/OpenSSLDigest.java
new file mode 100644
index 0000000..606c96f
--- /dev/null
+++ b/src/org/jitsi/impl/neomedia/transform/srtp/OpenSSLDigest.java
@@ -0,0 +1,307 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jitsi.impl.neomedia.transform.srtp;
+
+import org.bouncycastle.crypto.*;
+
+/**
+ * Implements the interface <tt>org.bouncycastle.crypto.Digest</tt> using the
+ * OpenSSL Crypto library.
+ *
+ * @author Lyubomir Marinov
+ */
+public class OpenSSLDigest
+ implements ExtendedDigest
+{
+ private static long EVP_sha1;
+
+ /**
+ * The indicator which determines whether
+ * <tt>System.loadLibrary(String)</tt> is to be invoked in order to load the
+ * OpenSSL (Crypto) library.
+ */
+ private static boolean loadLibrary = true;
+
+ /**
+ * The algorithm of the SHA-1 cryptographic hash function/digest.
+ */
+ public static final int SHA1 = 1;
+
+ private static native int EVP_DigestFinal_ex(
+ long ctx,
+ byte[] md, int off);
+
+ private static native boolean EVP_DigestInit_ex(
+ long ctx,
+ long type,
+ long impl);
+
+ private static native boolean EVP_DigestUpdate(
+ long ctx,
+ byte[] d, int off, int cnt);
+
+ private static native int EVP_MD_CTX_block_size(long ctx);
+
+ private static native long EVP_MD_CTX_create();
+
+ private static native void EVP_MD_CTX_destroy(long ctx);
+
+ private static native int EVP_MD_CTX_size(long ctx)
+;
+ private static native long EVP_sha1();
+
+ /**
+ * The name of the algorithm implemented by this instance.
+ */
+ private final String algorithmName;
+
+ /**
+ * The size in bytes of the internal buffer the digest applies its
+ * compression function to.
+ */
+ private int byteLength;
+
+ /**
+ * The digest context of the OpenSSL (Crypto) library through which the
+ * actual algorithm implementation is invoked by this instance.
+ */
+ private long ctx;
+
+ /**
+ * The size in bytes of the digest produced by this message digest.
+ */
+ private int digestSize;
+
+ /**
+ * The OpenSSL Crypto type of the message digest implemented by this
+ * instance.
+ */
+ private final long type;
+
+ /**
+ * Initializes a new <tt>OpenSSLDigest</tt> with a specific algorithm.
+ *
+ * @param algorithm the algorithm with which to initialize the new instance
+ */
+ public OpenSSLDigest(int algorithm)
+ {
+ // Make sure the provided arguments are legal.
+ if (algorithm == SHA1)
+ this.algorithmName = "SHA-1";
+ else
+ throw new IllegalArgumentException("algorithm " + algorithm);
+
+ // Load the OpenSSL (Crypto) library if necessary.
+ synchronized (OpenSSLDigest.class)
+ {
+ if (loadLibrary)
+ {
+ try
+ {
+ System.loadLibrary("jnopenssl");
+ EVP_sha1 = EVP_sha1();
+ }
+ finally
+ {
+ loadLibrary = false;
+ }
+ }
+ }
+
+ long type;
+
+ if (algorithm == SHA1)
+ {
+ long EVP_sha1 = OpenSSLDigest.EVP_sha1;
+
+ if (EVP_sha1 == 0)
+ throw new IllegalStateException("EVP_sha1");
+ else
+ type = EVP_sha1;
+ }
+ else
+ {
+ // It must have been checked prior to loading the OpenSSL (Crypto)
+ // library but the compiler needs it to be convinced that we are not
+ // attempting to use an uninitialized variable.
+ throw new IllegalArgumentException("algorithm " + algorithm);
+ }
+ this.type = type;
+
+ long ctx = EVP_MD_CTX_create();
+
+ if (ctx == 0)
+ {
+ throw new RuntimeException("EVP_MD_CTX_create");
+ }
+ else
+ {
+ boolean ok = false;
+
+ this.ctx = ctx;
+ try
+ {
+ reset();
+ ok = true;
+ }
+ finally
+ {
+ if (!ok)
+ {
+ if (this.ctx == ctx)
+ this.ctx = 0;
+ EVP_MD_CTX_destroy(ctx);
+ }
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int doFinal(byte[] out, int off)
+ {
+ if (out == null)
+ throw new NullPointerException("out");
+ if ((off < 0) || (out.length <= off))
+ throw new ArrayIndexOutOfBoundsException(off);
+
+ long ctx = this.ctx;
+
+ if (ctx == 0)
+ {
+ throw new IllegalStateException("ctx");
+ }
+ else
+ {
+ int s = EVP_DigestFinal_ex(ctx, out, off);
+
+ if (s < 0)
+ {
+ throw new RuntimeException("EVP_DigestFinal_ex");
+ }
+ else
+ {
+ // As the javadoc on interface method specifies, the doFinal
+ // call leaves this Digest reset.
+ reset();
+ return s;
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void finalize()
+ throws Throwable
+ {
+ try
+ {
+ // Well, the destroying in the finalizer should exist as a backup
+ // anyway. There is no way to explicitly invoke the destroying at
+ // the time of this writing but it is a start.
+ long ctx = this.ctx;
+
+ if (ctx != 0)
+ {
+ this.ctx = 0;
+ EVP_MD_CTX_destroy(ctx);
+ }
+ }
+ finally
+ {
+ super.finalize();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getAlgorithmName()
+ {
+ return algorithmName;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int getByteLength()
+ {
+ return byteLength;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int getDigestSize()
+ {
+ return digestSize;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void reset()
+ {
+ long ctx = this.ctx;
+
+ if (ctx == 0)
+ {
+ throw new IllegalStateException("ctx");
+ }
+ else if (EVP_DigestInit_ex(ctx, type, /* impl */ 0))
+ {
+ byteLength = EVP_MD_CTX_block_size(ctx);
+ digestSize = EVP_MD_CTX_size(ctx);
+ }
+ else
+ {
+ throw new RuntimeException(
+ "EVP_DigestInit_ex(" + getAlgorithmName() + ")");
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void update(byte in)
+ {
+ // TODO Auto-generated method stub
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void update(byte[] in, int off, int len)
+ {
+ if (len != 0)
+ {
+ if (in == null)
+ throw new NullPointerException("in");
+ if ((off < 0) || (in.length <= off))
+ throw new ArrayIndexOutOfBoundsException(off);
+ if ((len < 0) || (in.length < off + len))
+ throw new IllegalArgumentException("len " + len);
+
+ long ctx = this.ctx;
+
+ if (ctx == 0)
+ throw new IllegalStateException("ctx");
+ else if (!EVP_DigestUpdate(ctx, in, off, len))
+ throw new RuntimeException("EVP_DigestUpdate");
+ }
+ }
+}
diff --git a/src/org/jitsi/impl/neomedia/transform/srtp/SHA1.java b/src/org/jitsi/impl/neomedia/transform/srtp/SHA1.java
index e4ac56e..9b6b112 100644
--- a/src/org/jitsi/impl/neomedia/transform/srtp/SHA1.java
+++ b/src/org/jitsi/impl/neomedia/transform/srtp/SHA1.java
@@ -8,12 +8,69 @@ package org.jitsi.impl.neomedia.transform.srtp;

import org.bouncycastle.crypto.*;
import org.bouncycastle.crypto.digests.*;
+import org.jitsi.util.*;

-class SHA1
+/**
+ * Implements a factory for a SHA-1 <tt>Digest</tt>.
+ *
+ * @author Lyubomir Marinov
+ */
+public class SHA1
{
- static Digest createDigest()
+ /**
+ * The <tt>Logger</tt> used by the <tt>SHA1</tt> class to print out debug
+ * information.
+ */
+ private static final Logger logger = Logger.getLogger(SHA1.class);
+
+ /**
+ * The indicator which determines whether the OpenSSL (Crypto) library is to
+ * be used. If <tt>true</tt>, an attempt will be made to initialize an
+ * <tt>OpenSSLDigest</tt> instance. If the attempt fails, <tt>false</tt>
+ * will be assigned in order to not repeatedly attempt the initialization
+ * which is known to have failed.
+ */
+ private static boolean useOpenSSL = true;
+
+ /**
+ * Initializes a new <tt>org.bouncycastle.crypto.Digest</tt> instance which
+ * implements the SHA-1 cryptographic hash function/digest.
+ *
+ * @return a new <tt>org.bouncycastle.crypto.Digest</tt> instance which
+ * implements the SHA-1 cryptographic hash function/digest
+ */
+ public static Digest createDigest()
    {
- // TODO Auto-generated method stub
+ if (useOpenSSL)
+ {
+ try
+ {
+ return new OpenSSLDigest(OpenSSLDigest.SHA1);
+ }
+ catch (Throwable t)
+ {
+ // If an exception is thrown once, it is very likely to be
+ // thrown multiple times.
+ useOpenSSL = false;
+
+ if (t instanceof InterruptedException)
+ {
+ Thread.currentThread().interrupt();
+ }
+ else if (t instanceof ThreadDeath)
+ {
+ throw (ThreadDeath) t;
+ }
+ else
+ {
+ logger.warn(
+ "Failed to employ OpenSSL (Crypto) for an optimized"
+ + " SHA-1 implementation: "
+ + t.getLocalizedMessage());
+ }
+ }
+ }
+
        return new SHA1Digest();
    }
}

_______________________________________________
commits mailing list
commits@jitsi.org
Unsubscribe instructions and other list options:
http://lists.jitsi.org/mailman/listinfo/commits


#2

Hey Ingo,

Yes indeed.

Currently encryption and decryption are the biggest CPU hugs in Jitsi
Videobridge so the purpose of this work (still in progress) is to see
if openssl was behaving better.

Lyubomir noticed some time ago that Google were using an OpenSSL
provider with bouncy castle on Android and that they even had a unit
test that was wired to fail if ever their OpenSSL provider performed
worse than BouncyCastle ... so we thought it was worth a try. We'll
see how this goes.

Emil

···

On Fri, Oct 24, 2014 at 8:46 PM, Ingo Bauersachs <ingo@jitsi.org> wrote:

Out of curiosity: why all that JNI mess when SHA1 is available from both the JRE and BouncyCastle? Performance?

(And the OpenSSL license being considered problematic in combination with the GPL in Debian, not sure about the implications to LGPL).

Freundliche Grüsse,
Ingo Bauersachs

-- sent from my mobile

Freundliche Grüsse,
Ingo Bauersachs

-- sent from my mobile

Le 25.10.2014 à 00:44, "lyubomir.marinov@jitsi.org" <lyubomir.marinov@jitsi.org> a écrit :

Repository : ssh://lists.jitsi.org/libjitsi

On branch : master
Link : https://github.com/jitsi/libjitsi/compare/c07e2f4c3af0ad688c524d740c24f20c13b421ca...8dd83b679f6b44243fa9771f920a3a542fb4a78c

---------------------------------------------------------------

commit 8dd83b679f6b44243fa9771f920a3a542fb4a78c
Author: Lyubomir Marinov <lyubomir.marinov@jitsi.org>
Date: Fri Oct 24 20:43:41 2014 +0300

   Prepares to use SHA-1 from OpenSSL instead of BouncyCastle.

---------------------------------------------------------------

8dd83b679f6b44243fa9771f920a3a542fb4a78c
src/native/openssl/Digest.c | 102 +++++++
src/native/openssl/Digest.h | 77 +++++
.../jitsi/impl/neomedia/transform/srtp/AES.java | 4 +-
.../neomedia/transform/srtp/OpenSSLDigest.java | 307 ++++++++++++++++++++
.../jitsi/impl/neomedia/transform/srtp/SHA1.java | 63 +++-
5 files changed, 548 insertions(+), 5 deletions(-)

diff --git a/src/native/openssl/Digest.c b/src/native/openssl/Digest.c
new file mode 100644
index 0000000..f3b1c2e
--- /dev/null
+++ b/src/native/openssl/Digest.c
@@ -0,0 +1,102 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+
+#include "Digest.h"
+
+#include <openssl/evp.h>
+#include <stdint.h>
+
+JNIEXPORT jint JNICALL
+Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1DigestFinal_1ex
+ (JNIEnv *env, jclass clazz, jlong ctx, jbyteArray md, jint off)
+{
+ jbyte *md_ = (*env)->GetPrimitiveArrayCritical(env, md, NULL);
+ int i;
+
+ if (md_)
+ {
+ unsigned int s = 0;
+
+ i = EVP_DigestFinal_ex((EVP_MD_CTX *) (intptr_t) ctx, md_ + off, &s);
+ (*env)->ReleasePrimitiveArrayCritical(env, md, md_, 0);
+ i = i ? ((int) s) : -1;
+ }
+ else
+ {
+ i = -1;
+ }
+ return i;
+}
+
+JNIEXPORT jboolean JNICALL
+Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1DigestInit_1ex
+ (JNIEnv *env, jclass clazz, jlong ctx, jlong type, jlong impl)
+{
+ int i
+ = EVP_DigestInit_ex(
+ (EVP_MD_CTX *) (intptr_t) ctx,
+ (const EVP_MD *) (intptr_t) type,
+ (ENGINE *) (intptr_t) impl);
+
+ return i ? JNI_TRUE : JNI_FALSE;
+}
+
+JNIEXPORT jboolean JNICALL
+Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1DigestUpdate
+ (JNIEnv *env, jclass clazz, jlong ctx, jbyteArray d, jint off, jint cnt)
+{
+ jbyte *d_ = (*env)->GetPrimitiveArrayCritical(env, d, NULL);
+ jboolean b;
+
+ if (d_)
+ {
+ int i = EVP_DigestUpdate((EVP_MD_CTX *) (intptr_t) ctx, d_ + off, cnt);
+
+ (*env)->ReleasePrimitiveArrayCritical(env, d, d_, JNI_ABORT);
+ b = i ? JNI_TRUE : JNI_FALSE;
+ }
+ else
+ {
+ b = JNI_FALSE;
+ }
+ return b;
+}
+
+JNIEXPORT jint JNICALL
+Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1MD_1CTX_1block_1size
+ (JNIEnv *env, jclass clazz, jlong ctx)
+{
+ return EVP_MD_CTX_block_size((const EVP_MD_CTX *) (intptr_t) ctx);
+}
+
+JNIEXPORT jlong JNICALL
+Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1MD_1CTX_1create
+ (JNIEnv *env, jclass clazz)
+{
+ return (jlong) (intptr_t) EVP_MD_CTX_create();
+}
+
+JNIEXPORT void JNICALL
+Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1MD_1CTX_1destroy
+ (JNIEnv *env, jclass clazz, jlong ctx)
+{
+ EVP_MD_CTX_destroy((EVP_MD_CTX *) (intptr_t) ctx);
+}
+
+JNIEXPORT jint JNICALL
+Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1MD_1CTX_1size
+ (JNIEnv *env, jclass clazz, jlong ctx)
+{
+ return EVP_MD_CTX_size((const EVP_MD_CTX *) (intptr_t) ctx);
+}
+
+JNIEXPORT jlong JNICALL
+Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1sha1
+ (JNIEnv *env, jclass clazz)
+{
+ return (jlong) (intptr_t) EVP_sha1();
+}
diff --git a/src/native/openssl/Digest.h b/src/native/openssl/Digest.h
new file mode 100644
index 0000000..f79df6a
--- /dev/null
+++ b/src/native/openssl/Digest.h
@@ -0,0 +1,77 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest */
+
+#ifndef _Included_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest
+#define _Included_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest
+ * Method: EVP_DigestFinal_ex
+ * Signature: (J[BI)I
+ */
+JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1DigestFinal_1ex
+ (JNIEnv *, jclass, jlong, jbyteArray, jint);
+
+/*
+ * Class: org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest
+ * Method: EVP_DigestInit_ex
+ * Signature: (JJJ)Z
+ */
+JNIEXPORT jboolean JNICALL Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1DigestInit_1ex
+ (JNIEnv *, jclass, jlong, jlong, jlong);
+
+/*
+ * Class: org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest
+ * Method: EVP_DigestUpdate
+ * Signature: (J[BII)Z
+ */
+JNIEXPORT jboolean JNICALL Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1DigestUpdate
+ (JNIEnv *, jclass, jlong, jbyteArray, jint, jint);
+
+/*
+ * Class: org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest
+ * Method: EVP_MD_CTX_block_size
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1MD_1CTX_1block_1size
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest
+ * Method: EVP_MD_CTX_create
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1MD_1CTX_1create
+ (JNIEnv *, jclass);
+
+/*
+ * Class: org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest
+ * Method: EVP_MD_CTX_destroy
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1MD_1CTX_1destroy
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest
+ * Method: EVP_MD_CTX_size
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1MD_1CTX_1size
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest
+ * Method: EVP_sha1
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1sha1
+ (JNIEnv *, jclass);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/org/jitsi/impl/neomedia/transform/srtp/AES.java b/src/org/jitsi/impl/neomedia/transform/srtp/AES.java
index 503d815..2682bd8 100644
--- a/src/org/jitsi/impl/neomedia/transform/srtp/AES.java
+++ b/src/org/jitsi/impl/neomedia/transform/srtp/AES.java
@@ -109,8 +109,8 @@ class AES
                {
                    logger.warn(
                            "Failed to employ a java.security.Provider for an"
- + " optimized AES implementation.",
- t);
+ + " optimized AES implementation: "
+ + t.getLocalizedMessage());
                }
            }
        }
diff --git a/src/org/jitsi/impl/neomedia/transform/srtp/OpenSSLDigest.java b/src/org/jitsi/impl/neomedia/transform/srtp/OpenSSLDigest.java
new file mode 100644
index 0000000..606c96f
--- /dev/null
+++ b/src/org/jitsi/impl/neomedia/transform/srtp/OpenSSLDigest.java
@@ -0,0 +1,307 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jitsi.impl.neomedia.transform.srtp;
+
+import org.bouncycastle.crypto.*;
+
+/**
+ * Implements the interface <tt>org.bouncycastle.crypto.Digest</tt> using the
+ * OpenSSL Crypto library.
+ *
+ * @author Lyubomir Marinov
+ */
+public class OpenSSLDigest
+ implements ExtendedDigest
+{
+ private static long EVP_sha1;
+
+ /**
+ * The indicator which determines whether
+ * <tt>System.loadLibrary(String)</tt> is to be invoked in order to load the
+ * OpenSSL (Crypto) library.
+ */
+ private static boolean loadLibrary = true;
+
+ /**
+ * The algorithm of the SHA-1 cryptographic hash function/digest.
+ */
+ public static final int SHA1 = 1;
+
+ private static native int EVP_DigestFinal_ex(
+ long ctx,
+ byte[] md, int off);
+
+ private static native boolean EVP_DigestInit_ex(
+ long ctx,
+ long type,
+ long impl);
+
+ private static native boolean EVP_DigestUpdate(
+ long ctx,
+ byte[] d, int off, int cnt);
+
+ private static native int EVP_MD_CTX_block_size(long ctx);
+
+ private static native long EVP_MD_CTX_create();
+
+ private static native void EVP_MD_CTX_destroy(long ctx);
+
+ private static native int EVP_MD_CTX_size(long ctx)
+;
+ private static native long EVP_sha1();
+
+ /**
+ * The name of the algorithm implemented by this instance.
+ */
+ private final String algorithmName;
+
+ /**
+ * The size in bytes of the internal buffer the digest applies its
+ * compression function to.
+ */
+ private int byteLength;
+
+ /**
+ * The digest context of the OpenSSL (Crypto) library through which the
+ * actual algorithm implementation is invoked by this instance.
+ */
+ private long ctx;
+
+ /**
+ * The size in bytes of the digest produced by this message digest.
+ */
+ private int digestSize;
+
+ /**
+ * The OpenSSL Crypto type of the message digest implemented by this
+ * instance.
+ */
+ private final long type;
+
+ /**
+ * Initializes a new <tt>OpenSSLDigest</tt> with a specific algorithm.
+ *
+ * @param algorithm the algorithm with which to initialize the new instance
+ */
+ public OpenSSLDigest(int algorithm)
+ {
+ // Make sure the provided arguments are legal.
+ if (algorithm == SHA1)
+ this.algorithmName = "SHA-1";
+ else
+ throw new IllegalArgumentException("algorithm " + algorithm);
+
+ // Load the OpenSSL (Crypto) library if necessary.
+ synchronized (OpenSSLDigest.class)
+ {
+ if (loadLibrary)
+ {
+ try
+ {
+ System.loadLibrary("jnopenssl");
+ EVP_sha1 = EVP_sha1();
+ }
+ finally
+ {
+ loadLibrary = false;
+ }
+ }
+ }
+
+ long type;
+
+ if (algorithm == SHA1)
+ {
+ long EVP_sha1 = OpenSSLDigest.EVP_sha1;
+
+ if (EVP_sha1 == 0)
+ throw new IllegalStateException("EVP_sha1");
+ else
+ type = EVP_sha1;
+ }
+ else
+ {
+ // It must have been checked prior to loading the OpenSSL (Crypto)
+ // library but the compiler needs it to be convinced that we are not
+ // attempting to use an uninitialized variable.
+ throw new IllegalArgumentException("algorithm " + algorithm);
+ }
+ this.type = type;
+
+ long ctx = EVP_MD_CTX_create();
+
+ if (ctx == 0)
+ {
+ throw new RuntimeException("EVP_MD_CTX_create");
+ }
+ else
+ {
+ boolean ok = false;
+
+ this.ctx = ctx;
+ try
+ {
+ reset();
+ ok = true;
+ }
+ finally
+ {
+ if (!ok)
+ {
+ if (this.ctx == ctx)
+ this.ctx = 0;
+ EVP_MD_CTX_destroy(ctx);
+ }
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int doFinal(byte[] out, int off)
+ {
+ if (out == null)
+ throw new NullPointerException("out");
+ if ((off < 0) || (out.length <= off))
+ throw new ArrayIndexOutOfBoundsException(off);
+
+ long ctx = this.ctx;
+
+ if (ctx == 0)
+ {
+ throw new IllegalStateException("ctx");
+ }
+ else
+ {
+ int s = EVP_DigestFinal_ex(ctx, out, off);
+
+ if (s < 0)
+ {
+ throw new RuntimeException("EVP_DigestFinal_ex");
+ }
+ else
+ {
+ // As the javadoc on interface method specifies, the doFinal
+ // call leaves this Digest reset.
+ reset();
+ return s;
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void finalize()
+ throws Throwable
+ {
+ try
+ {
+ // Well, the destroying in the finalizer should exist as a backup
+ // anyway. There is no way to explicitly invoke the destroying at
+ // the time of this writing but it is a start.
+ long ctx = this.ctx;
+
+ if (ctx != 0)
+ {
+ this.ctx = 0;
+ EVP_MD_CTX_destroy(ctx);
+ }
+ }
+ finally
+ {
+ super.finalize();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getAlgorithmName()
+ {
+ return algorithmName;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int getByteLength()
+ {
+ return byteLength;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int getDigestSize()
+ {
+ return digestSize;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void reset()
+ {
+ long ctx = this.ctx;
+
+ if (ctx == 0)
+ {
+ throw new IllegalStateException("ctx");
+ }
+ else if (EVP_DigestInit_ex(ctx, type, /* impl */ 0))
+ {
+ byteLength = EVP_MD_CTX_block_size(ctx);
+ digestSize = EVP_MD_CTX_size(ctx);
+ }
+ else
+ {
+ throw new RuntimeException(
+ "EVP_DigestInit_ex(" + getAlgorithmName() + ")");
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void update(byte in)
+ {
+ // TODO Auto-generated method stub
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void update(byte[] in, int off, int len)
+ {
+ if (len != 0)
+ {
+ if (in == null)
+ throw new NullPointerException("in");
+ if ((off < 0) || (in.length <= off))
+ throw new ArrayIndexOutOfBoundsException(off);
+ if ((len < 0) || (in.length < off + len))
+ throw new IllegalArgumentException("len " + len);
+
+ long ctx = this.ctx;
+
+ if (ctx == 0)
+ throw new IllegalStateException("ctx");
+ else if (!EVP_DigestUpdate(ctx, in, off, len))
+ throw new RuntimeException("EVP_DigestUpdate");
+ }
+ }
+}
diff --git a/src/org/jitsi/impl/neomedia/transform/srtp/SHA1.java b/src/org/jitsi/impl/neomedia/transform/srtp/SHA1.java
index e4ac56e..9b6b112 100644
--- a/src/org/jitsi/impl/neomedia/transform/srtp/SHA1.java
+++ b/src/org/jitsi/impl/neomedia/transform/srtp/SHA1.java
@@ -8,12 +8,69 @@ package org.jitsi.impl.neomedia.transform.srtp;

import org.bouncycastle.crypto.*;
import org.bouncycastle.crypto.digests.*;
+import org.jitsi.util.*;

-class SHA1
+/**
+ * Implements a factory for a SHA-1 <tt>Digest</tt>.
+ *
+ * @author Lyubomir Marinov
+ */
+public class SHA1
{
- static Digest createDigest()
+ /**
+ * The <tt>Logger</tt> used by the <tt>SHA1</tt> class to print out debug
+ * information.
+ */
+ private static final Logger logger = Logger.getLogger(SHA1.class);
+
+ /**
+ * The indicator which determines whether the OpenSSL (Crypto) library is to
+ * be used. If <tt>true</tt>, an attempt will be made to initialize an
+ * <tt>OpenSSLDigest</tt> instance. If the attempt fails, <tt>false</tt>
+ * will be assigned in order to not repeatedly attempt the initialization
+ * which is known to have failed.
+ */
+ private static boolean useOpenSSL = true;
+
+ /**
+ * Initializes a new <tt>org.bouncycastle.crypto.Digest</tt> instance which
+ * implements the SHA-1 cryptographic hash function/digest.
+ *
+ * @return a new <tt>org.bouncycastle.crypto.Digest</tt> instance which
+ * implements the SHA-1 cryptographic hash function/digest
+ */
+ public static Digest createDigest()
    {
- // TODO Auto-generated method stub
+ if (useOpenSSL)
+ {
+ try
+ {
+ return new OpenSSLDigest(OpenSSLDigest.SHA1);
+ }
+ catch (Throwable t)
+ {
+ // If an exception is thrown once, it is very likely to be
+ // thrown multiple times.
+ useOpenSSL = false;
+
+ if (t instanceof InterruptedException)
+ {
+ Thread.currentThread().interrupt();
+ }
+ else if (t instanceof ThreadDeath)
+ {
+ throw (ThreadDeath) t;
+ }
+ else
+ {
+ logger.warn(
+ "Failed to employ OpenSSL (Crypto) for an optimized"
+ + " SHA-1 implementation: "
+ + t.getLocalizedMessage());
+ }
+ }
+ }
+
        return new SHA1Digest();
    }
}

_______________________________________________
commits mailing list
commits@jitsi.org
Unsubscribe instructions and other list options:
http://lists.jitsi.org/mailman/listinfo/commits

_______________________________________________
dev mailing list
dev@jitsi.org
Unsubscribe instructions and other list options:
http://lists.jitsi.org/mailman/listinfo/dev

--
https://jitsi.org


#3

Okay, thought so. Have made comparisons with different JRE versions? One should think that the newest JREs use the crypto intrinsics of modern CPUs (SHA/AES and the JVM flag UseAESIntrinsics)...

Freundliche Grüsse,
Ingo Bauersachs

-- sent from my mobile

···

Le 25.10.2014 à 23:52, "Emil Ivov" <emcho@jitsi.org> a écrit :

Hey Ingo,

Yes indeed.

Currently encryption and decryption are the biggest CPU hugs in Jitsi
Videobridge so the purpose of this work (still in progress) is to see
if openssl was behaving better.

Lyubomir noticed some time ago that Google were using an OpenSSL
provider with bouncy castle on Android and that they even had a unit
test that was wired to fail if ever their OpenSSL provider performed
worse than BouncyCastle ... so we thought it was worth a try. We'll
see how this goes.

Emil

On Fri, Oct 24, 2014 at 8:46 PM, Ingo Bauersachs <ingo@jitsi.org> wrote:
Out of curiosity: why all that JNI mess when SHA1 is available from both the JRE and BouncyCastle? Performance?

(And the OpenSSL license being considered problematic in combination with the GPL in Debian, not sure about the implications to LGPL).

Freundliche Grüsse,
Ingo Bauersachs

-- sent from my mobile

Freundliche Grüsse,
Ingo Bauersachs

-- sent from my mobile

Le 25.10.2014 à 00:44, "lyubomir.marinov@jitsi.org" <lyubomir.marinov@jitsi.org> a écrit :

Repository : ssh://lists.jitsi.org/libjitsi

On branch : master
Link : https://github.com/jitsi/libjitsi/compare/c07e2f4c3af0ad688c524d740c24f20c13b421ca...8dd83b679f6b44243fa9771f920a3a542fb4a78c

---------------------------------------------------------------

commit 8dd83b679f6b44243fa9771f920a3a542fb4a78c
Author: Lyubomir Marinov <lyubomir.marinov@jitsi.org>
Date: Fri Oct 24 20:43:41 2014 +0300

  Prepares to use SHA-1 from OpenSSL instead of BouncyCastle.

---------------------------------------------------------------

8dd83b679f6b44243fa9771f920a3a542fb4a78c
src/native/openssl/Digest.c | 102 +++++++
src/native/openssl/Digest.h | 77 +++++
.../jitsi/impl/neomedia/transform/srtp/AES.java | 4 +-
.../neomedia/transform/srtp/OpenSSLDigest.java | 307 ++++++++++++++++++++
.../jitsi/impl/neomedia/transform/srtp/SHA1.java | 63 +++-
5 files changed, 548 insertions(+), 5 deletions(-)

diff --git a/src/native/openssl/Digest.c b/src/native/openssl/Digest.c
new file mode 100644
index 0000000..f3b1c2e
--- /dev/null
+++ b/src/native/openssl/Digest.c
@@ -0,0 +1,102 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+
+#include "Digest.h"
+
+#include <openssl/evp.h>
+#include <stdint.h>
+
+JNIEXPORT jint JNICALL
+Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1DigestFinal_1ex
+ (JNIEnv *env, jclass clazz, jlong ctx, jbyteArray md, jint off)
+{
+ jbyte *md_ = (*env)->GetPrimitiveArrayCritical(env, md, NULL);
+ int i;
+
+ if (md_)
+ {
+ unsigned int s = 0;
+
+ i = EVP_DigestFinal_ex((EVP_MD_CTX *) (intptr_t) ctx, md_ + off, &s);
+ (*env)->ReleasePrimitiveArrayCritical(env, md, md_, 0);
+ i = i ? ((int) s) : -1;
+ }
+ else
+ {
+ i = -1;
+ }
+ return i;
+}
+
+JNIEXPORT jboolean JNICALL
+Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1DigestInit_1ex
+ (JNIEnv *env, jclass clazz, jlong ctx, jlong type, jlong impl)
+{
+ int i
+ = EVP_DigestInit_ex(
+ (EVP_MD_CTX *) (intptr_t) ctx,
+ (const EVP_MD *) (intptr_t) type,
+ (ENGINE *) (intptr_t) impl);
+
+ return i ? JNI_TRUE : JNI_FALSE;
+}
+
+JNIEXPORT jboolean JNICALL
+Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1DigestUpdate
+ (JNIEnv *env, jclass clazz, jlong ctx, jbyteArray d, jint off, jint cnt)
+{
+ jbyte *d_ = (*env)->GetPrimitiveArrayCritical(env, d, NULL);
+ jboolean b;
+
+ if (d_)
+ {
+ int i = EVP_DigestUpdate((EVP_MD_CTX *) (intptr_t) ctx, d_ + off, cnt);
+
+ (*env)->ReleasePrimitiveArrayCritical(env, d, d_, JNI_ABORT);
+ b = i ? JNI_TRUE : JNI_FALSE;
+ }
+ else
+ {
+ b = JNI_FALSE;
+ }
+ return b;
+}
+
+JNIEXPORT jint JNICALL
+Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1MD_1CTX_1block_1size
+ (JNIEnv *env, jclass clazz, jlong ctx)
+{
+ return EVP_MD_CTX_block_size((const EVP_MD_CTX *) (intptr_t) ctx);
+}
+
+JNIEXPORT jlong JNICALL
+Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1MD_1CTX_1create
+ (JNIEnv *env, jclass clazz)
+{
+ return (jlong) (intptr_t) EVP_MD_CTX_create();
+}
+
+JNIEXPORT void JNICALL
+Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1MD_1CTX_1destroy
+ (JNIEnv *env, jclass clazz, jlong ctx)
+{
+ EVP_MD_CTX_destroy((EVP_MD_CTX *) (intptr_t) ctx);
+}
+
+JNIEXPORT jint JNICALL
+Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1MD_1CTX_1size
+ (JNIEnv *env, jclass clazz, jlong ctx)
+{
+ return EVP_MD_CTX_size((const EVP_MD_CTX *) (intptr_t) ctx);
+}
+
+JNIEXPORT jlong JNICALL
+Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1sha1
+ (JNIEnv *env, jclass clazz)
+{
+ return (jlong) (intptr_t) EVP_sha1();
+}
diff --git a/src/native/openssl/Digest.h b/src/native/openssl/Digest.h
new file mode 100644
index 0000000..f79df6a
--- /dev/null
+++ b/src/native/openssl/Digest.h
@@ -0,0 +1,77 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest */
+
+#ifndef _Included_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest
+#define _Included_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest
+ * Method: EVP_DigestFinal_ex
+ * Signature: (J[BI)I
+ */
+JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1DigestFinal_1ex
+ (JNIEnv *, jclass, jlong, jbyteArray, jint);
+
+/*
+ * Class: org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest
+ * Method: EVP_DigestInit_ex
+ * Signature: (JJJ)Z
+ */
+JNIEXPORT jboolean JNICALL Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1DigestInit_1ex
+ (JNIEnv *, jclass, jlong, jlong, jlong);
+
+/*
+ * Class: org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest
+ * Method: EVP_DigestUpdate
+ * Signature: (J[BII)Z
+ */
+JNIEXPORT jboolean JNICALL Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1DigestUpdate
+ (JNIEnv *, jclass, jlong, jbyteArray, jint, jint);
+
+/*
+ * Class: org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest
+ * Method: EVP_MD_CTX_block_size
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1MD_1CTX_1block_1size
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest
+ * Method: EVP_MD_CTX_create
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1MD_1CTX_1create
+ (JNIEnv *, jclass);
+
+/*
+ * Class: org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest
+ * Method: EVP_MD_CTX_destroy
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1MD_1CTX_1destroy
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest
+ * Method: EVP_MD_CTX_size
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1MD_1CTX_1size
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest
+ * Method: EVP_sha1
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1sha1
+ (JNIEnv *, jclass);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/org/jitsi/impl/neomedia/transform/srtp/AES.java b/src/org/jitsi/impl/neomedia/transform/srtp/AES.java
index 503d815..2682bd8 100644
--- a/src/org/jitsi/impl/neomedia/transform/srtp/AES.java
+++ b/src/org/jitsi/impl/neomedia/transform/srtp/AES.java
@@ -109,8 +109,8 @@ class AES
               {
                   logger.warn(
                           "Failed to employ a java.security.Provider for an"
- + " optimized AES implementation.",
- t);
+ + " optimized AES implementation: "
+ + t.getLocalizedMessage());
               }
           }
       }
diff --git a/src/org/jitsi/impl/neomedia/transform/srtp/OpenSSLDigest.java b/src/org/jitsi/impl/neomedia/transform/srtp/OpenSSLDigest.java
new file mode 100644
index 0000000..606c96f
--- /dev/null
+++ b/src/org/jitsi/impl/neomedia/transform/srtp/OpenSSLDigest.java
@@ -0,0 +1,307 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jitsi.impl.neomedia.transform.srtp;
+
+import org.bouncycastle.crypto.*;
+
+/**
+ * Implements the interface <tt>org.bouncycastle.crypto.Digest</tt> using the
+ * OpenSSL Crypto library.
+ *
+ * @author Lyubomir Marinov
+ */
+public class OpenSSLDigest
+ implements ExtendedDigest
+{
+ private static long EVP_sha1;
+
+ /**
+ * The indicator which determines whether
+ * <tt>System.loadLibrary(String)</tt> is to be invoked in order to load the
+ * OpenSSL (Crypto) library.
+ */
+ private static boolean loadLibrary = true;
+
+ /**
+ * The algorithm of the SHA-1 cryptographic hash function/digest.
+ */
+ public static final int SHA1 = 1;
+
+ private static native int EVP_DigestFinal_ex(
+ long ctx,
+ byte[] md, int off);
+
+ private static native boolean EVP_DigestInit_ex(
+ long ctx,
+ long type,
+ long impl);
+
+ private static native boolean EVP_DigestUpdate(
+ long ctx,
+ byte[] d, int off, int cnt);
+
+ private static native int EVP_MD_CTX_block_size(long ctx);
+
+ private static native long EVP_MD_CTX_create();
+
+ private static native void EVP_MD_CTX_destroy(long ctx);
+
+ private static native int EVP_MD_CTX_size(long ctx)
+;
+ private static native long EVP_sha1();
+
+ /**
+ * The name of the algorithm implemented by this instance.
+ */
+ private final String algorithmName;
+
+ /**
+ * The size in bytes of the internal buffer the digest applies its
+ * compression function to.
+ */
+ private int byteLength;
+
+ /**
+ * The digest context of the OpenSSL (Crypto) library through which the
+ * actual algorithm implementation is invoked by this instance.
+ */
+ private long ctx;
+
+ /**
+ * The size in bytes of the digest produced by this message digest.
+ */
+ private int digestSize;
+
+ /**
+ * The OpenSSL Crypto type of the message digest implemented by this
+ * instance.
+ */
+ private final long type;
+
+ /**
+ * Initializes a new <tt>OpenSSLDigest</tt> with a specific algorithm.
+ *
+ * @param algorithm the algorithm with which to initialize the new instance
+ */
+ public OpenSSLDigest(int algorithm)
+ {
+ // Make sure the provided arguments are legal.
+ if (algorithm == SHA1)
+ this.algorithmName = "SHA-1";
+ else
+ throw new IllegalArgumentException("algorithm " + algorithm);
+
+ // Load the OpenSSL (Crypto) library if necessary.
+ synchronized (OpenSSLDigest.class)
+ {
+ if (loadLibrary)
+ {
+ try
+ {
+ System.loadLibrary("jnopenssl");
+ EVP_sha1 = EVP_sha1();
+ }
+ finally
+ {
+ loadLibrary = false;
+ }
+ }
+ }
+
+ long type;
+
+ if (algorithm == SHA1)
+ {
+ long EVP_sha1 = OpenSSLDigest.EVP_sha1;
+
+ if (EVP_sha1 == 0)
+ throw new IllegalStateException("EVP_sha1");
+ else
+ type = EVP_sha1;
+ }
+ else
+ {
+ // It must have been checked prior to loading the OpenSSL (Crypto)
+ // library but the compiler needs it to be convinced that we are not
+ // attempting to use an uninitialized variable.
+ throw new IllegalArgumentException("algorithm " + algorithm);
+ }
+ this.type = type;
+
+ long ctx = EVP_MD_CTX_create();
+
+ if (ctx == 0)
+ {
+ throw new RuntimeException("EVP_MD_CTX_create");
+ }
+ else
+ {
+ boolean ok = false;
+
+ this.ctx = ctx;
+ try
+ {
+ reset();
+ ok = true;
+ }
+ finally
+ {
+ if (!ok)
+ {
+ if (this.ctx == ctx)
+ this.ctx = 0;
+ EVP_MD_CTX_destroy(ctx);
+ }
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int doFinal(byte[] out, int off)
+ {
+ if (out == null)
+ throw new NullPointerException("out");
+ if ((off < 0) || (out.length <= off))
+ throw new ArrayIndexOutOfBoundsException(off);
+
+ long ctx = this.ctx;
+
+ if (ctx == 0)
+ {
+ throw new IllegalStateException("ctx");
+ }
+ else
+ {
+ int s = EVP_DigestFinal_ex(ctx, out, off);
+
+ if (s < 0)
+ {
+ throw new RuntimeException("EVP_DigestFinal_ex");
+ }
+ else
+ {
+ // As the javadoc on interface method specifies, the doFinal
+ // call leaves this Digest reset.
+ reset();
+ return s;
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void finalize()
+ throws Throwable
+ {
+ try
+ {
+ // Well, the destroying in the finalizer should exist as a backup
+ // anyway. There is no way to explicitly invoke the destroying at
+ // the time of this writing but it is a start.
+ long ctx = this.ctx;
+
+ if (ctx != 0)
+ {
+ this.ctx = 0;
+ EVP_MD_CTX_destroy(ctx);
+ }
+ }
+ finally
+ {
+ super.finalize();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getAlgorithmName()
+ {
+ return algorithmName;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int getByteLength()
+ {
+ return byteLength;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int getDigestSize()
+ {
+ return digestSize;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void reset()
+ {
+ long ctx = this.ctx;
+
+ if (ctx == 0)
+ {
+ throw new IllegalStateException("ctx");
+ }
+ else if (EVP_DigestInit_ex(ctx, type, /* impl */ 0))
+ {
+ byteLength = EVP_MD_CTX_block_size(ctx);
+ digestSize = EVP_MD_CTX_size(ctx);
+ }
+ else
+ {
+ throw new RuntimeException(
+ "EVP_DigestInit_ex(" + getAlgorithmName() + ")");
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void update(byte in)
+ {
+ // TODO Auto-generated method stub
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void update(byte[] in, int off, int len)
+ {
+ if (len != 0)
+ {
+ if (in == null)
+ throw new NullPointerException("in");
+ if ((off < 0) || (in.length <= off))
+ throw new ArrayIndexOutOfBoundsException(off);
+ if ((len < 0) || (in.length < off + len))
+ throw new IllegalArgumentException("len " + len);
+
+ long ctx = this.ctx;
+
+ if (ctx == 0)
+ throw new IllegalStateException("ctx");
+ else if (!EVP_DigestUpdate(ctx, in, off, len))
+ throw new RuntimeException("EVP_DigestUpdate");
+ }
+ }
+}
diff --git a/src/org/jitsi/impl/neomedia/transform/srtp/SHA1.java b/src/org/jitsi/impl/neomedia/transform/srtp/SHA1.java
index e4ac56e..9b6b112 100644
--- a/src/org/jitsi/impl/neomedia/transform/srtp/SHA1.java
+++ b/src/org/jitsi/impl/neomedia/transform/srtp/SHA1.java
@@ -8,12 +8,69 @@ package org.jitsi.impl.neomedia.transform.srtp;

import org.bouncycastle.crypto.*;
import org.bouncycastle.crypto.digests.*;
+import org.jitsi.util.*;

-class SHA1
+/**
+ * Implements a factory for a SHA-1 <tt>Digest</tt>.
+ *
+ * @author Lyubomir Marinov
+ */
+public class SHA1
{
- static Digest createDigest()
+ /**
+ * The <tt>Logger</tt> used by the <tt>SHA1</tt> class to print out debug
+ * information.
+ */
+ private static final Logger logger = Logger.getLogger(SHA1.class);
+
+ /**
+ * The indicator which determines whether the OpenSSL (Crypto) library is to
+ * be used. If <tt>true</tt>, an attempt will be made to initialize an
+ * <tt>OpenSSLDigest</tt> instance. If the attempt fails, <tt>false</tt>
+ * will be assigned in order to not repeatedly attempt the initialization
+ * which is known to have failed.
+ */
+ private static boolean useOpenSSL = true;
+
+ /**
+ * Initializes a new <tt>org.bouncycastle.crypto.Digest</tt> instance which
+ * implements the SHA-1 cryptographic hash function/digest.
+ *
+ * @return a new <tt>org.bouncycastle.crypto.Digest</tt> instance which
+ * implements the SHA-1 cryptographic hash function/digest
+ */
+ public static Digest createDigest()
   {
- // TODO Auto-generated method stub
+ if (useOpenSSL)
+ {
+ try
+ {
+ return new OpenSSLDigest(OpenSSLDigest.SHA1);
+ }
+ catch (Throwable t)
+ {
+ // If an exception is thrown once, it is very likely to be
+ // thrown multiple times.
+ useOpenSSL = false;
+
+ if (t instanceof InterruptedException)
+ {
+ Thread.currentThread().interrupt();
+ }
+ else if (t instanceof ThreadDeath)
+ {
+ throw (ThreadDeath) t;
+ }
+ else
+ {
+ logger.warn(
+ "Failed to employ OpenSSL (Crypto) for an optimized"
+ + " SHA-1 implementation: "
+ + t.getLocalizedMessage());
+ }
+ }
+ }
+
       return new SHA1Digest();
   }
}

_______________________________________________
commits mailing list
commits@jitsi.org
Unsubscribe instructions and other list options:
http://lists.jitsi.org/mailman/listinfo/commits

_______________________________________________
dev mailing list
dev@jitsi.org
Unsubscribe instructions and other list options:
http://lists.jitsi.org/mailman/listinfo/dev

--
https://jitsi.org

_______________________________________________
dev mailing list
dev@jitsi.org
Unsubscribe instructions and other list options:
http://lists.jitsi.org/mailman/listinfo/dev


#4

Lyubo did run a few quick tests for the actual AES encryption bouncy
castle was performing significantly better than the native JRE8
encryption. Enabling use of hardware AES-NI seemed to performa
slightly (almost insignificantly) better than BouncyCastle. We haven't
tested enough though.

Emil

···

On Sat, Oct 25, 2014 at 7:04 PM, Ingo Bauersachs <ingo@jitsi.org> wrote:

Okay, thought so. Have made comparisons with different JRE versions? One should think that the newest JREs use the crypto intrinsics of modern CPUs (SHA/AES and the JVM flag UseAESIntrinsics)...

Freundliche Grüsse,
Ingo Bauersachs

-- sent from my mobile

Le 25.10.2014 à 23:52, "Emil Ivov" <emcho@jitsi.org> a écrit :

Hey Ingo,

Yes indeed.

Currently encryption and decryption are the biggest CPU hugs in Jitsi
Videobridge so the purpose of this work (still in progress) is to see
if openssl was behaving better.

Lyubomir noticed some time ago that Google were using an OpenSSL
provider with bouncy castle on Android and that they even had a unit
test that was wired to fail if ever their OpenSSL provider performed
worse than BouncyCastle ... so we thought it was worth a try. We'll
see how this goes.

Emil

On Fri, Oct 24, 2014 at 8:46 PM, Ingo Bauersachs <ingo@jitsi.org> wrote:
Out of curiosity: why all that JNI mess when SHA1 is available from both the JRE and BouncyCastle? Performance?

(And the OpenSSL license being considered problematic in combination with the GPL in Debian, not sure about the implications to LGPL).

Freundliche Grüsse,
Ingo Bauersachs

-- sent from my mobile

Freundliche Grüsse,
Ingo Bauersachs

-- sent from my mobile

Le 25.10.2014 à 00:44, "lyubomir.marinov@jitsi.org" <lyubomir.marinov@jitsi.org> a écrit :

Repository : ssh://lists.jitsi.org/libjitsi

On branch : master
Link : https://github.com/jitsi/libjitsi/compare/c07e2f4c3af0ad688c524d740c24f20c13b421ca...8dd83b679f6b44243fa9771f920a3a542fb4a78c

---------------------------------------------------------------

commit 8dd83b679f6b44243fa9771f920a3a542fb4a78c
Author: Lyubomir Marinov <lyubomir.marinov@jitsi.org>
Date: Fri Oct 24 20:43:41 2014 +0300

  Prepares to use SHA-1 from OpenSSL instead of BouncyCastle.

---------------------------------------------------------------

8dd83b679f6b44243fa9771f920a3a542fb4a78c
src/native/openssl/Digest.c | 102 +++++++
src/native/openssl/Digest.h | 77 +++++
.../jitsi/impl/neomedia/transform/srtp/AES.java | 4 +-
.../neomedia/transform/srtp/OpenSSLDigest.java | 307 ++++++++++++++++++++
.../jitsi/impl/neomedia/transform/srtp/SHA1.java | 63 +++-
5 files changed, 548 insertions(+), 5 deletions(-)

diff --git a/src/native/openssl/Digest.c b/src/native/openssl/Digest.c
new file mode 100644
index 0000000..f3b1c2e
--- /dev/null
+++ b/src/native/openssl/Digest.c
@@ -0,0 +1,102 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+
+#include "Digest.h"
+
+#include <openssl/evp.h>
+#include <stdint.h>
+
+JNIEXPORT jint JNICALL
+Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1DigestFinal_1ex
+ (JNIEnv *env, jclass clazz, jlong ctx, jbyteArray md, jint off)
+{
+ jbyte *md_ = (*env)->GetPrimitiveArrayCritical(env, md, NULL);
+ int i;
+
+ if (md_)
+ {
+ unsigned int s = 0;
+
+ i = EVP_DigestFinal_ex((EVP_MD_CTX *) (intptr_t) ctx, md_ + off, &s);
+ (*env)->ReleasePrimitiveArrayCritical(env, md, md_, 0);
+ i = i ? ((int) s) : -1;
+ }
+ else
+ {
+ i = -1;
+ }
+ return i;
+}
+
+JNIEXPORT jboolean JNICALL
+Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1DigestInit_1ex
+ (JNIEnv *env, jclass clazz, jlong ctx, jlong type, jlong impl)
+{
+ int i
+ = EVP_DigestInit_ex(
+ (EVP_MD_CTX *) (intptr_t) ctx,
+ (const EVP_MD *) (intptr_t) type,
+ (ENGINE *) (intptr_t) impl);
+
+ return i ? JNI_TRUE : JNI_FALSE;
+}
+
+JNIEXPORT jboolean JNICALL
+Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1DigestUpdate
+ (JNIEnv *env, jclass clazz, jlong ctx, jbyteArray d, jint off, jint cnt)
+{
+ jbyte *d_ = (*env)->GetPrimitiveArrayCritical(env, d, NULL);
+ jboolean b;
+
+ if (d_)
+ {
+ int i = EVP_DigestUpdate((EVP_MD_CTX *) (intptr_t) ctx, d_ + off, cnt);
+
+ (*env)->ReleasePrimitiveArrayCritical(env, d, d_, JNI_ABORT);
+ b = i ? JNI_TRUE : JNI_FALSE;
+ }
+ else
+ {
+ b = JNI_FALSE;
+ }
+ return b;
+}
+
+JNIEXPORT jint JNICALL
+Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1MD_1CTX_1block_1size
+ (JNIEnv *env, jclass clazz, jlong ctx)
+{
+ return EVP_MD_CTX_block_size((const EVP_MD_CTX *) (intptr_t) ctx);
+}
+
+JNIEXPORT jlong JNICALL
+Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1MD_1CTX_1create
+ (JNIEnv *env, jclass clazz)
+{
+ return (jlong) (intptr_t) EVP_MD_CTX_create();
+}
+
+JNIEXPORT void JNICALL
+Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1MD_1CTX_1destroy
+ (JNIEnv *env, jclass clazz, jlong ctx)
+{
+ EVP_MD_CTX_destroy((EVP_MD_CTX *) (intptr_t) ctx);
+}
+
+JNIEXPORT jint JNICALL
+Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1MD_1CTX_1size
+ (JNIEnv *env, jclass clazz, jlong ctx)
+{
+ return EVP_MD_CTX_size((const EVP_MD_CTX *) (intptr_t) ctx);
+}
+
+JNIEXPORT jlong JNICALL
+Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1sha1
+ (JNIEnv *env, jclass clazz)
+{
+ return (jlong) (intptr_t) EVP_sha1();
+}
diff --git a/src/native/openssl/Digest.h b/src/native/openssl/Digest.h
new file mode 100644
index 0000000..f79df6a
--- /dev/null
+++ b/src/native/openssl/Digest.h
@@ -0,0 +1,77 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest */
+
+#ifndef _Included_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest
+#define _Included_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest
+ * Method: EVP_DigestFinal_ex
+ * Signature: (J[BI)I
+ */
+JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1DigestFinal_1ex
+ (JNIEnv *, jclass, jlong, jbyteArray, jint);
+
+/*
+ * Class: org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest
+ * Method: EVP_DigestInit_ex
+ * Signature: (JJJ)Z
+ */
+JNIEXPORT jboolean JNICALL Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1DigestInit_1ex
+ (JNIEnv *, jclass, jlong, jlong, jlong);
+
+/*
+ * Class: org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest
+ * Method: EVP_DigestUpdate
+ * Signature: (J[BII)Z
+ */
+JNIEXPORT jboolean JNICALL Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1DigestUpdate
+ (JNIEnv *, jclass, jlong, jbyteArray, jint, jint);
+
+/*
+ * Class: org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest
+ * Method: EVP_MD_CTX_block_size
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1MD_1CTX_1block_1size
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest
+ * Method: EVP_MD_CTX_create
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1MD_1CTX_1create
+ (JNIEnv *, jclass);
+
+/*
+ * Class: org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest
+ * Method: EVP_MD_CTX_destroy
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1MD_1CTX_1destroy
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest
+ * Method: EVP_MD_CTX_size
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1MD_1CTX_1size
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest
+ * Method: EVP_sha1
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_org_jitsi_impl_neomedia_transform_srtp_OpenSSLDigest_EVP_1sha1
+ (JNIEnv *, jclass);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/org/jitsi/impl/neomedia/transform/srtp/AES.java b/src/org/jitsi/impl/neomedia/transform/srtp/AES.java
index 503d815..2682bd8 100644
--- a/src/org/jitsi/impl/neomedia/transform/srtp/AES.java
+++ b/src/org/jitsi/impl/neomedia/transform/srtp/AES.java
@@ -109,8 +109,8 @@ class AES
               {
                   logger.warn(
                           "Failed to employ a java.security.Provider for an"
- + " optimized AES implementation.",
- t);
+ + " optimized AES implementation: "
+ + t.getLocalizedMessage());
               }
           }
       }
diff --git a/src/org/jitsi/impl/neomedia/transform/srtp/OpenSSLDigest.java b/src/org/jitsi/impl/neomedia/transform/srtp/OpenSSLDigest.java
new file mode 100644
index 0000000..606c96f
--- /dev/null
+++ b/src/org/jitsi/impl/neomedia/transform/srtp/OpenSSLDigest.java
@@ -0,0 +1,307 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jitsi.impl.neomedia.transform.srtp;
+
+import org.bouncycastle.crypto.*;
+
+/**
+ * Implements the interface <tt>org.bouncycastle.crypto.Digest</tt> using the
+ * OpenSSL Crypto library.
+ *
+ * @author Lyubomir Marinov
+ */
+public class OpenSSLDigest
+ implements ExtendedDigest
+{
+ private static long EVP_sha1;
+
+ /**
+ * The indicator which determines whether
+ * <tt>System.loadLibrary(String)</tt> is to be invoked in order to load the
+ * OpenSSL (Crypto) library.
+ */
+ private static boolean loadLibrary = true;
+
+ /**
+ * The algorithm of the SHA-1 cryptographic hash function/digest.
+ */
+ public static final int SHA1 = 1;
+
+ private static native int EVP_DigestFinal_ex(
+ long ctx,
+ byte[] md, int off);
+
+ private static native boolean EVP_DigestInit_ex(
+ long ctx,
+ long type,
+ long impl);
+
+ private static native boolean EVP_DigestUpdate(
+ long ctx,
+ byte[] d, int off, int cnt);
+
+ private static native int EVP_MD_CTX_block_size(long ctx);
+
+ private static native long EVP_MD_CTX_create();
+
+ private static native void EVP_MD_CTX_destroy(long ctx);
+
+ private static native int EVP_MD_CTX_size(long ctx)
+;
+ private static native long EVP_sha1();
+
+ /**
+ * The name of the algorithm implemented by this instance.
+ */
+ private final String algorithmName;
+
+ /**
+ * The size in bytes of the internal buffer the digest applies its
+ * compression function to.
+ */
+ private int byteLength;
+
+ /**
+ * The digest context of the OpenSSL (Crypto) library through which the
+ * actual algorithm implementation is invoked by this instance.
+ */
+ private long ctx;
+
+ /**
+ * The size in bytes of the digest produced by this message digest.
+ */
+ private int digestSize;
+
+ /**
+ * The OpenSSL Crypto type of the message digest implemented by this
+ * instance.
+ */
+ private final long type;
+
+ /**
+ * Initializes a new <tt>OpenSSLDigest</tt> with a specific algorithm.
+ *
+ * @param algorithm the algorithm with which to initialize the new instance
+ */
+ public OpenSSLDigest(int algorithm)
+ {
+ // Make sure the provided arguments are legal.
+ if (algorithm == SHA1)
+ this.algorithmName = "SHA-1";
+ else
+ throw new IllegalArgumentException("algorithm " + algorithm);
+
+ // Load the OpenSSL (Crypto) library if necessary.
+ synchronized (OpenSSLDigest.class)
+ {
+ if (loadLibrary)
+ {
+ try
+ {
+ System.loadLibrary("jnopenssl");
+ EVP_sha1 = EVP_sha1();
+ }
+ finally
+ {
+ loadLibrary = false;
+ }
+ }
+ }
+
+ long type;
+
+ if (algorithm == SHA1)
+ {
+ long EVP_sha1 = OpenSSLDigest.EVP_sha1;
+
+ if (EVP_sha1 == 0)
+ throw new IllegalStateException("EVP_sha1");
+ else
+ type = EVP_sha1;
+ }
+ else
+ {
+ // It must have been checked prior to loading the OpenSSL (Crypto)
+ // library but the compiler needs it to be convinced that we are not
+ // attempting to use an uninitialized variable.
+ throw new IllegalArgumentException("algorithm " + algorithm);
+ }
+ this.type = type;
+
+ long ctx = EVP_MD_CTX_create();
+
+ if (ctx == 0)
+ {
+ throw new RuntimeException("EVP_MD_CTX_create");
+ }
+ else
+ {
+ boolean ok = false;
+
+ this.ctx = ctx;
+ try
+ {
+ reset();
+ ok = true;
+ }
+ finally
+ {
+ if (!ok)
+ {
+ if (this.ctx == ctx)
+ this.ctx = 0;
+ EVP_MD_CTX_destroy(ctx);
+ }
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int doFinal(byte[] out, int off)
+ {
+ if (out == null)
+ throw new NullPointerException("out");
+ if ((off < 0) || (out.length <= off))
+ throw new ArrayIndexOutOfBoundsException(off);
+
+ long ctx = this.ctx;
+
+ if (ctx == 0)
+ {
+ throw new IllegalStateException("ctx");
+ }
+ else
+ {
+ int s = EVP_DigestFinal_ex(ctx, out, off);
+
+ if (s < 0)
+ {
+ throw new RuntimeException("EVP_DigestFinal_ex");
+ }
+ else
+ {
+ // As the javadoc on interface method specifies, the doFinal
+ // call leaves this Digest reset.
+ reset();
+ return s;
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void finalize()
+ throws Throwable
+ {
+ try
+ {
+ // Well, the destroying in the finalizer should exist as a backup
+ // anyway. There is no way to explicitly invoke the destroying at
+ // the time of this writing but it is a start.
+ long ctx = this.ctx;
+
+ if (ctx != 0)
+ {
+ this.ctx = 0;
+ EVP_MD_CTX_destroy(ctx);
+ }
+ }
+ finally
+ {
+ super.finalize();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getAlgorithmName()
+ {
+ return algorithmName;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int getByteLength()
+ {
+ return byteLength;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int getDigestSize()
+ {
+ return digestSize;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void reset()
+ {
+ long ctx = this.ctx;
+
+ if (ctx == 0)
+ {
+ throw new IllegalStateException("ctx");
+ }
+ else if (EVP_DigestInit_ex(ctx, type, /* impl */ 0))
+ {
+ byteLength = EVP_MD_CTX_block_size(ctx);
+ digestSize = EVP_MD_CTX_size(ctx);
+ }
+ else
+ {
+ throw new RuntimeException(
+ "EVP_DigestInit_ex(" + getAlgorithmName() + ")");
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void update(byte in)
+ {
+ // TODO Auto-generated method stub
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void update(byte[] in, int off, int len)
+ {
+ if (len != 0)
+ {
+ if (in == null)
+ throw new NullPointerException("in");
+ if ((off < 0) || (in.length <= off))
+ throw new ArrayIndexOutOfBoundsException(off);
+ if ((len < 0) || (in.length < off + len))
+ throw new IllegalArgumentException("len " + len);
+
+ long ctx = this.ctx;
+
+ if (ctx == 0)
+ throw new IllegalStateException("ctx");
+ else if (!EVP_DigestUpdate(ctx, in, off, len))
+ throw new RuntimeException("EVP_DigestUpdate");
+ }
+ }
+}
diff --git a/src/org/jitsi/impl/neomedia/transform/srtp/SHA1.java b/src/org/jitsi/impl/neomedia/transform/srtp/SHA1.java
index e4ac56e..9b6b112 100644
--- a/src/org/jitsi/impl/neomedia/transform/srtp/SHA1.java
+++ b/src/org/jitsi/impl/neomedia/transform/srtp/SHA1.java
@@ -8,12 +8,69 @@ package org.jitsi.impl.neomedia.transform.srtp;

import org.bouncycastle.crypto.*;
import org.bouncycastle.crypto.digests.*;
+import org.jitsi.util.*;

-class SHA1
+/**
+ * Implements a factory for a SHA-1 <tt>Digest</tt>.
+ *
+ * @author Lyubomir Marinov
+ */
+public class SHA1
{
- static Digest createDigest()
+ /**
+ * The <tt>Logger</tt> used by the <tt>SHA1</tt> class to print out debug
+ * information.
+ */
+ private static final Logger logger = Logger.getLogger(SHA1.class);
+
+ /**
+ * The indicator which determines whether the OpenSSL (Crypto) library is to
+ * be used. If <tt>true</tt>, an attempt will be made to initialize an
+ * <tt>OpenSSLDigest</tt> instance. If the attempt fails, <tt>false</tt>
+ * will be assigned in order to not repeatedly attempt the initialization
+ * which is known to have failed.
+ */
+ private static boolean useOpenSSL = true;
+
+ /**
+ * Initializes a new <tt>org.bouncycastle.crypto.Digest</tt> instance which
+ * implements the SHA-1 cryptographic hash function/digest.
+ *
+ * @return a new <tt>org.bouncycastle.crypto.Digest</tt> instance which
+ * implements the SHA-1 cryptographic hash function/digest
+ */
+ public static Digest createDigest()
   {
- // TODO Auto-generated method stub
+ if (useOpenSSL)
+ {
+ try
+ {
+ return new OpenSSLDigest(OpenSSLDigest.SHA1);
+ }
+ catch (Throwable t)
+ {
+ // If an exception is thrown once, it is very likely to be
+ // thrown multiple times.
+ useOpenSSL = false;
+
+ if (t instanceof InterruptedException)
+ {
+ Thread.currentThread().interrupt();
+ }
+ else if (t instanceof ThreadDeath)
+ {
+ throw (ThreadDeath) t;
+ }
+ else
+ {
+ logger.warn(
+ "Failed to employ OpenSSL (Crypto) for an optimized"
+ + " SHA-1 implementation: "
+ + t.getLocalizedMessage());
+ }
+ }
+ }
+
       return new SHA1Digest();
   }
}

_______________________________________________
commits mailing list
commits@jitsi.org
Unsubscribe instructions and other list options:
http://lists.jitsi.org/mailman/listinfo/commits

_______________________________________________
dev mailing list
dev@jitsi.org
Unsubscribe instructions and other list options:
http://lists.jitsi.org/mailman/listinfo/dev

--
https://jitsi.org

_______________________________________________
dev mailing list
dev@jitsi.org
Unsubscribe instructions and other list options:
http://lists.jitsi.org/mailman/listinfo/dev

_______________________________________________
dev mailing list
dev@jitsi.org
Unsubscribe instructions and other list options:
http://lists.jitsi.org/mailman/listinfo/dev

--
https://jitsi.org


#5

Hello, Emil and Ingo!

Here are the ratios of the times taken by the respective hash
functions/digests on mid-2011 MacBook Air, 64-bit GNU/Linux, JRE 8u25,
OpenSSL 1.0.1j:

OpenSSL: 1
java.security.MessageDigest.getInstance("SHA-1"): 1.75-2.25
BouncyCastle: 2.5-3


#6

Here are the ratios of the times taken by the respective AES
implementations on mid-2011 MacBook Air, 64-bit GNU/Linux, JRE 8u25,
NSS 3.17.1:

BouncyCastle: 1
Sun JCE +UseAES +UseAESIntrinsics: 0.85
Sun JCE -UseAES -UseAESIntrinsics: 1.65
Sun PKCS#11/NSS +UseAES +UseAESIntrinsics: 2.25
Sun PKCS#11/NSS -UseAES -UseAESIntrinsics: 2.75


#7

Thanks, that is valuable information! I'm stunned that OpenSSL is that much faster despite all the JNI stuff...
I also stumbled ober Java's libnss bindings that come with the JVM. Have you looked at those as well? Seems to be complicated to setup though.

And something related to the design: I don't know how feasible it is, but given that Java already has an extensive factory mechanism, wouldn't make sense to create an OpenSSL provider? (Just like BC is one.)

Freundliche Grüsse,
Ingo Bauersachs

-- sent from my mobile

···

Le 27.10.2014 à 14:09, "Lyubomir Marinov" <lyubomir.marinov@jitsi.org> a écrit :

Hello, Emil and Ingo!

Here are the ratios of the times taken by the respective hash
functions/digests on mid-2011 MacBook Air, 64-bit GNU/Linux, JRE 8u25,
OpenSSL 1.0.1j:

OpenSSL: 1
java.security.MessageDigest.getInstance("SHA-1"): 1.75-2.25
BouncyCastle: 2.5-3

_______________________________________________
dev mailing list
dev@jitsi.org
Unsubscribe instructions and other list options:
http://lists.jitsi.org/mailman/listinfo/dev


#8

if possible, you may want to use sha256 instead of sha1, which is deemed dead already

···

On 27.10.2014 09:54, Lyubomir Marinov wrote:

2014-10-27 10:07 GMT+02:00 Ingo Bauersachs <ingo@jitsi.org>:

I also stumbled ober Java's libnss bindings that come with the JVM. Have you looked at those as well? Seems to be complicated to setup though.

Yes, we have the source code in
org.jitsi.impl.neomedia.transform.srtp.AES so I copied, modified and
ran it for SHA-1 as well. It's more often than not worse than
BouncyCastle but, overall, they're comparable.

And something related to the design: I don't know how feasible it is, but given that Java already has an extensive factory mechanism, wouldn't make sense to create an OpenSSL provider? (Just like BC is one.)

For both AES and SHA-1, we had multiple direct calls to respective
BouncyCastle contructors. I replaced them with the factory-like
methods/classes org.jitsi.impl.neomedia.transform.srtp.AES and
org.jitsi.impl.neomedia.transform.srtp.SHA1.

AES and SHA-1 were the major offenders in the CPU sampling profiles of
Videobridge so I replaced them with minimal and isolated changes
avoiding modifications to BouncyCastle.

Anyway, I agree that an OpenSSL provider for Java is a very good design.


#9

I definitely do support the request from Raphael!

···

ingo@jitsi.org

dev@jitsi.org

http://lists.jitsi.org/mailman/listinfo/dev


#10

I also stumbled ober Java's libnss bindings that come with the JVM. Have you looked at those as well? Seems to be complicated to setup though.

Yes, we have the source code in
org.jitsi.impl.neomedia.transform.srtp.AES so I copied, modified and
ran it for SHA-1 as well. It's more often than not worse than
BouncyCastle but, overall, they're comparable.

And something related to the design: I don't know how feasible it is, but given that Java already has an extensive factory mechanism, wouldn't make sense to create an OpenSSL provider? (Just like BC is one.)

For both AES and SHA-1, we had multiple direct calls to respective
BouncyCastle contructors. I replaced them with the factory-like
methods/classes org.jitsi.impl.neomedia.transform.srtp.AES and
org.jitsi.impl.neomedia.transform.srtp.SHA1.

AES and SHA-1 were the major offenders in the CPU sampling profiles of
Videobridge so I replaced them with minimal and isolated changes
avoiding modifications to BouncyCastle.

Anyway, I agree that an OpenSSL provider for Java is a very good design.

···

2014-10-27 10:07 GMT+02:00 Ingo Bauersachs <ingo@jitsi.org>: