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 +0300Prepares 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