<html>
<body>
At 12:17 PM 1/27/2014, Matthew Hall wrote:<br>
<blockquote type=cite class=cite cite="">I have often had good luck
accelerating such operations using the PKCS #11 provider with a recent
copy of libnss to get the native crypto. And the things needed for this
are built into Java already.</blockquote><br><br>
Yup. 
<a href="https://developer.mozilla.org/en-US/docs/NSS/NSS_3.14.2_release_notes" eudora="autourl">
https://developer.mozilla.org/en-US/docs/NSS/NSS_3.14.2_release_notes<br>
<br>
</a><blockquote type=cite class=cite cite="">-- <br>
Sent from my mobile device.<br><br>
Michael StJohns <mstjohns@comcast.net> wrote:<br>

<dl>
<dd>At 09:23 AM 1/27/2014, Mark Christiaens wrote:<br>
<blockquote type=cite class=cite cite="">
<dd>Silly me, forgot to mention that I'm working on Ubuntu, 64 bit,
13.10.<br><br>

<dd>So, AES-CBC seems to be reasonably fast (100 MiB/s) but AES-GCM is
slow (5.2 MiB/s). Â I'm particularly curious about the GCM one because I
get the impression that OpenSSL should be able to reach in the GB/s for
AES-GCM encryption/authentication. <br><br>

<dd>Mark</blockquote><br><br>

<dd>GCM uses a GF2 multiply as part of the integrity calculation. 
That operation is pretty expensive.  My guess is that if the code
was profiled, you'd find a lot of time being spent in
com.sun.crypto.provider.GHASH.<br><br>

<dd>The more recent intel processors have a set of instructions that
substantially improve this performance -
<a href="http://en.wikipedia.org/wiki/CLMUL_instruction_set" eudora="autourl">
http://en.wikipedia.org/wiki/CLMUL_instruction_set</a> - but the code in
the standard provider is all pure java and doesn't take advantage of this
as far as I can tell.  I believe that the more recent versions of
OpenSSL *have* been updated to take advantage of the new instructions
which explains their performance.<br><br>

<dd>The same processors generally also support an AES instruction set so
if someone were to build a native version of this it might be useful to
also replace/augment the default AES block cipher
implementation.<br><br>

<dd>Also see
<a href="http://software.intel.com/en-us/articles/intel-aes-ni-performance-testing-on-linuxjava-stack" eudora="autourl">
http://software.intel.com/en-us/articles/intel-aes-ni-performance-testing-on-linuxjava-stack</a>
 <br><br>

<dd>Mike<br><br>
<br><br>
<blockquote type=cite class=cite cite="">
<dd>On Mon, Jan 27, 2014 at 3:19 PM, Xuelei Fan
<<a href="mailto:xuelei.fan@oracle.com">xuelei.fan@oracle.com</a>>
wrote:
<dl>
<dd>What's the platform are you using for the testing? Â Windows,
Linux,
<dd>Solaris or Mac OS? Â GCM are now only implemented in SunJCE
provider. Â I
<dd>want to make sure the crypto provider for AES-CBC, which is
different
<dd>for different platforms by default, is not the major cause of the
<dd>performance impact.<br>

<dd>Thanks for the performance measure.<br>

<dd>Regards,
<dd>Xuelei<br>

<dd>On 1/27/2014 5:34 PM, Chris Hegarty wrote:
<dd>> Cross posting to security-dev, since the question cipher
related.
<dd>>
<dd>> -Chris.
<dd>>
<dd>> On 27/01/14 09:28, Mark Christiaens wrote:
<dd>>> I wrote Â a little test client/server setup that transfers
100 MB of data
<dd>>> over an SSL socket configured to use TLS 1.2 AES GCM
<dd>>> (TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256). Â On my i7-4770
CPU @ 3.40GHz
<dd>>> with OpenJDK 1.8.0-ea-b124 I get a transfer rate of around
5.2
<dd>>> MiB/second. Â I expected a higher speed. Â Using
<dd>>> TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 I reach 100 MiB/s.
 Is this to
<dd>>> be expected?
<dd>>>
<dd>>> For reference, here is my code:
<dd>>>
<dd>>> ///// Client.java
<dd>>>
<dd>>> package ssl;
<dd>>>
<dd>>> import javax.net.ssl.*;
<dd>>> import java.io.*;
<dd>>> import java.util.Arrays;
<dd>>>
<dd>>> public class Client {
<dd>>>
<dd>>> Â  Â  Â public static void main(String[]
arstring) {
<dd>>> Â  Â  Â  Â  Â try {
<dd>>> Â  Â  Â  Â  Â  Â  Â
SSLSocketFactory sslsocketfactory = (SSLSocketFactory)
<dd>>> SSLSocketFactory.getDefault();
<dd>>> Â  Â  Â  Â  Â  Â  Â
SSLSocket sslsocket = (SSLSocket)
<dd>>> sslsocketfactory.createSocket("localhost", 9999);
<dd>>> Â  Â  Â  Â  Â  Â  Â
Helper.requireAESCipherSuites(sslsocket);
<dd>>> Â  Â  Â  Â  Â  Â  Â
sslsocket.setEnabledProtocols(new String[]{"TLSv1.2"});
<dd>>>
<dd>>> Â  Â  Â  Â  Â  Â  Â try
(OutputStream outputstream =
<dd>>> sslsocket.getOutputStream()) {
<dd>>> Â  Â  Â  Â  Â  Â 
  Â  Â byte[] buf = new byte[Helper.BUF_SIZE];
<dd>>> Â  Â  Â  Â  Â  Â 
  Â  Â Arrays.fill(buf, (byte) 1);
<dd>>> Â  Â  Â  Â  Â  Â 
  Â  Â for (int i = 0; i < Helper.BUF_COUNT; ++i) {
<dd>>> Â  Â  Â  Â  Â  Â 
  Â  Â  Â  Â outputstream.write(buf);
<dd>>> Â  Â  Â  Â  Â  Â 
  Â  Â }
<dd>>>
<dd>>> Â  Â  Â  Â  Â  Â 
  Â  Â System.out.println("Using cipher suite: "
+
<dd>>> (sslsocket.getSession()).getCipherSuite());
<dd>>>
<dd>>> Â  Â  Â  Â  Â  Â 
  Â  Â outputstream.flush();
<dd>>> Â  Â  Â  Â  Â  Â  Â }
<dd>>>
<dd>>> Â  Â  Â  Â  Â } catch (IOException
exception) {
<dd>>> Â  Â  Â  Â  Â  Â  Â
exception.printStackTrace();
<dd>>> Â  Â  Â  Â  Â }
<dd>>> Â  Â  Â }
<dd>>> }
<dd>>>
<dd>>> ///// Server.java
<dd>>>
<dd>>> package ssl;
<dd>>>
<dd>>> import javax.net.ssl.*;
<dd>>> import java.io.*;
<dd>>>
<dd>>> public class Server {
<dd>>>
<dd>>> Â  Â  Â public static void main(String[]
arstring) {
<dd>>> Â  Â  Â  Â  Â try {
<dd>>> Â  Â  Â  Â  Â  Â  Â
SSLServerSocketFactory sslserversocketfactory =
<dd>>> (SSLServerSocketFactory)
SSLServerSocketFactory.getDefault();
<dd>>> Â  Â  Â  Â  Â  Â  Â
SSLServerSocket sslserversocket = (SSLServerSocket)
<dd>>> sslserversocketfactory.createServerSocket(9999);
<dd>>> Â  Â  Â  Â  Â  Â  Â
SSLSocket sslsocket = (SSLSocket) sslserversocket.accept();
<dd>>>
<dd>>> Â  Â  Â  Â  Â  Â  Â
InputStream inputstream = sslsocket.getInputStream();
<dd>>>
<dd>>> Â  Â  Â  Â  Â  Â  Â
byte[] buf = new byte[Helper.BUF_SIZE];
<dd>>> Â  Â  Â  Â  Â  Â  Â
long bytesToRead = BYTES_TO_READ;
<dd>>>
<dd>>> Â  Â  Â  Â  Â  Â  Â
long startTime = System.currentTimeMillis();
<dd>>>
<dd>>> Â  Â  Â  Â  Â  Â  Â
while (bytesToRead > 0) {
<dd>>> Â  Â  Â  Â  Â  Â 
  Â  Â bytesToRead -= inputstream.read(buf);
<dd>>> Â  Â  Â  Â  Â  Â  Â }
<dd>>>
<dd>>> Â  Â  Â  Â  Â  Â  Â
long stopTime = System.currentTimeMillis();
<dd>>> Â  Â  Â  Â  Â  Â  Â
long totalTimeMs = stopTime - startTime;
<dd>>> Â  Â  Â  Â  Â  Â  Â
double mbRead = BYTES_TO_READ / (1024.0 * 1024);
<dd>>> Â  Â  Â  Â  Â  Â  Â
double totalTimeSeconds = totalTimeMs / 1000.0;
<dd>>> Â  Â  Â  Â  Â  Â  Â
double mibPerSecond = mbRead / totalTimeSeconds;
<dd>>>
<dd>>> Â  Â  Â  Â  Â  Â  Â
System.out.println("Using cipher suite: " +
<dd>>> (sslsocket.getSession()).getCipherSuite());
<dd>>> Â  Â  Â  Â  Â  Â  Â
System.out.println("Read " + mbRead + "MiB in " +
<dd>>> totalTimeSeconds + "s");
<dd>>> Â  Â  Â  Â  Â  Â  Â
System.out.println("Bandwidth: " + mibPerSecond +
"MiB/s");
<dd>>>
<dd>>> Â  Â  Â  Â  Â } catch (IOException
exception) {
<dd>>> Â  Â  Â  Â  Â  Â  Â
exception.printStackTrace();
<dd>>> Â  Â  Â  Â  Â }
<dd>>> Â  Â  Â }
<dd>>>
<dd>>> Â  Â  Â private static final int BYTES_TO_READ
= Helper.BUF_COUNT *
<dd>>> Helper.BUF_SIZE;
<dd>>> }
<dd>>>
<dd>>> ///// Helper.java
<dd>>>
<dd>>> package ssl;
<dd>>>
<dd>>> import java.util.*;
<dd>>> import java.util.regex.*;
<dd>>> import javax.net.ssl.*;
<dd>>>
<dd>>> public class Helper {
<dd>>>
<dd>>> Â  Â  Â static int BUF_SIZE = 1024 * 1024;
<dd>>> Â  Â  Â static int BUF_COUNT = 100;
<dd>>>
<dd>>> Â  Â  Â static SSLSocket
requireAESCipherSuites(SSLSocket socket) {
<dd>>> Â  Â  Â  Â  Â String
supportedCipherSuites[] =
<dd>>> socket.getSupportedCipherSuites();
<dd>>>
<dd>>> Â  Â  Â  Â  Â
System.out.println("Supported cipher suite: " +
<dd>>> Arrays.toString(supportedCipherSuites));
<dd>>>
<dd>>> Â  Â  Â  Â  Â List<String>
selectedCipherSuites = new ArrayList<>();
<dd>>>
<dd>>> // Â  Â  Â  Â String patternString =
".*";
<dd>>> Â  Â  Â  Â  Â String patternString
= "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256";
<dd>>> // Â  Â  Â  Â String patternString =
<dd>>> "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256";
<dd>>>
<dd>>> Â  Â  Â  Â  Â Pattern pattern =
Pattern.compile(patternString);
<dd>>>
<dd>>> Â  Â  Â  Â  Â for (String
cipherSuite : supportedCipherSuites) {
<dd>>> Â  Â  Â  Â  Â  Â  Â
Matcher matcher = pattern.matcher(cipherSuite);
<dd>>> Â  Â  Â  Â  Â  Â  Â if
(matcher.find()) {
<dd>>> Â  Â  Â  Â  Â  Â 
  Â  Â selectedCipherSuites.add(cipherSuite);
<dd>>> Â  Â  Â  Â  Â  Â  Â }
<dd>>> Â  Â  Â  Â  Â }
<dd>>>
<dd>>> Â  Â  Â  Â  Â
System.out.println("Selected cipher suites: " +
<dd>>> selectedCipherSuites);
<dd>>>
<dd>>> Â  Â  Â  Â  Â
socket.setEnabledCipherSuites(selectedCipherSuites.toArray(new
<dd>>> String[0]));
<dd>>>
<dd>>> Â  Â  Â  Â  Â return socket;
<dd>>> Â  Â  Â }
<dd>>> }
<dd>>><br><br>
</dl><br><br>
<br>

<dd>-- <br>

<dd>Mark Christiaens<br>

<dd>Ganzeplas 23<br>

<dd>9880 Aalter<br>

<dd>09 / 325 07 40 </blockquote>
</dl></blockquote></body>
<br>
</html>