<html><head></head><body>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.<br>
-- <br>
Sent from my mobile device.<br><br><div class="gmail_quote">Michael StJohns <mstjohns@comcast.net> wrote:<blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">


At 09:23 AM 1/27/2014, Mark Christiaens wrote:<br />
<blockquote type="cite" class="cite" cite="">Silly me, forgot to mention that
I'm working on Ubuntu, 64 bit, 13.10.<br /><br />
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 />
Mark<br />
</blockquote><br /><br />
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 />
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 />
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 />
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 />
Mike<br /><br />
<br /><br />
<blockquote type="cite" class="cite" cite="">On Mon, Jan 27, 2014 at 3:19 PM,
Xuelei Fan
<<a href="mailto:xuelei.fan@oracle.com">xuelei.fan@oracle.com</a>>
wrote:<br />

<dl>
<dd>What's the platform are you using for the testing? Â Windows,
Linux,<br />

</dd><dd>Solaris or Mac OS? Â GCM are now only implemented in SunJCE provider.
 I<br />

</dd><dd>want to make sure the crypto provider for AES-CBC, which is
different<br />

</dd><dd>for different platforms by default, is not the major cause of
the<br />

</dd><dd>performance impact.<br /><br />

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

</dd><dd>Regards,<br />

</dd><dd>Xuelei<br /><br />

</dd><dd>On 1/27/2014 5:34 PM, Chris Hegarty wrote:<br />

</dd><dd>> Cross posting to security-dev, since the question cipher
related.<br />

</dd><dd>><br />

</dd><dd>> -Chris.<br />

</dd><dd>><br />

</dd><dd>> On 27/01/14 09:28, Mark Christiaens wrote:<br />

</dd><dd>>> I wrote Â a little test client/server setup that transfers
100 MB of data<br />

</dd><dd>>> over an SSL socket configured to use TLS 1.2 AES GCM<br />

</dd><dd>>> (TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256). Â On my i7-4770
CPU @ 3.40GHz<br />

</dd><dd>>> with OpenJDK 1.8.0-ea-b124 I get a transfer rate of around
5.2<br />

</dd><dd>>> MiB/second. Â I expected a higher speed. Â Using<br />

</dd><dd>>> TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 I reach 100 MiB/s. Â
Is this to<br />

</dd><dd>>> be expected?<br />

</dd><dd>>><br />

</dd><dd>>> For reference, here is my code:<br />

</dd><dd>>><br />

</dd><dd>>> ///// Client.java<br />

</dd><dd>>><br />

</dd><dd>>> package ssl;<br />

</dd><dd>>><br />

</dd><dd>>> import javax.net.ssl.*;<br />

</dd><dd>>> import java.io.*;<br />

</dd><dd>>> import java.util.Arrays;<br />

</dd><dd>>><br />

</dd><dd>>> public class Client {<br />

</dd><dd>>><br />

</dd><dd>>> Â  Â  Â public static void main(String[] arstring)
{<br />

</dd><dd>>> Â  Â  Â  Â  Â try {<br />

</dd><dd>>> Â  Â  Â  Â  Â  Â  Â
SSLSocketFactory sslsocketfactory = (SSLSocketFactory)<br />

</dd><dd>>> SSLSocketFactory.getDefault();<br />

</dd><dd>>> Â  Â  Â  Â  Â  Â  Â SSLSocket
sslsocket = (SSLSocket)<br />

</dd><dd>>> sslsocketfactory.createSocket("localhost",
9999);<br />

</dd><dd>>> Â  Â  Â  Â  Â  Â  Â
Helper.requireAESCipherSuites(sslsocket);<br />

</dd><dd>>> Â  Â  Â  Â  Â  Â  Â
sslsocket.setEnabledProtocols(new String[]{"TLSv1.2"});<br />

</dd><dd>>><br />

</dd><dd>>> Â  Â  Â  Â  Â  Â  Â try
(OutputStream outputstream =<br />

</dd><dd>>> sslsocket.getOutputStream()) {<br />

</dd><dd>>> Â  Â  Â  Â  Â  Â  Â 
  Â byte[] buf = new byte[Helper.BUF_SIZE];<br />

</dd><dd>>> Â  Â  Â  Â  Â  Â  Â 
  Â Arrays.fill(buf, (byte) 1);<br />

</dd><dd>>> Â  Â  Â  Â  Â  Â  Â 
  Â for (int i = 0; i < Helper.BUF_COUNT; ++i) {<br />

</dd><dd>>> Â  Â  Â  Â  Â  Â  Â 
  Â  Â  Â outputstream.write(buf);<br />

</dd><dd>>> Â  Â  Â  Â  Â  Â  Â 
  Â }<br />

</dd><dd>>><br />

</dd><dd>>> Â  Â  Â  Â  Â  Â  Â 
  Â System.out.println("Using cipher suite: " +<br />

</dd><dd>>> (sslsocket.getSession()).getCipherSuite());<br />

</dd><dd>>><br />

</dd><dd>>> Â  Â  Â  Â  Â  Â  Â 
  Â outputstream.flush();<br />

</dd><dd>>> Â  Â  Â  Â  Â  Â  Â }<br />

</dd><dd>>><br />

</dd><dd>>> Â  Â  Â  Â  Â } catch (IOException
exception) {<br />

</dd><dd>>> Â  Â  Â  Â  Â  Â  Â
exception.printStackTrace();<br />

</dd><dd>>> Â  Â  Â  Â  Â }<br />

</dd><dd>>> Â  Â  Â }<br />

</dd><dd>>> }<br />

</dd><dd>>><br />

</dd><dd>>> ///// Server.java<br />

</dd><dd>>><br />

</dd><dd>>> package ssl;<br />

</dd><dd>>><br />

</dd><dd>>> import javax.net.ssl.*;<br />

</dd><dd>>> import java.io.*;<br />

</dd><dd>>><br />

</dd><dd>>> public class Server {<br />

</dd><dd>>><br />

</dd><dd>>> Â  Â  Â public static void main(String[] arstring)
{<br />

</dd><dd>>> Â  Â  Â  Â  Â try {<br />

</dd><dd>>> Â  Â  Â  Â  Â  Â  Â
SSLServerSocketFactory sslserversocketfactory =<br />

</dd><dd>>> (SSLServerSocketFactory)
SSLServerSocketFactory.getDefault();<br />

</dd><dd>>> Â  Â  Â  Â  Â  Â  Â
SSLServerSocket sslserversocket = (SSLServerSocket)<br />

</dd><dd>>> sslserversocketfactory.createServerSocket(9999);<br />

</dd><dd>>> Â  Â  Â  Â  Â  Â  Â SSLSocket
sslsocket = (SSLSocket) sslserversocket.accept();<br />

</dd><dd>>><br />

</dd><dd>>> Â  Â  Â  Â  Â  Â  Â
InputStream inputstream = sslsocket.getInputStream();<br />

</dd><dd>>><br />

</dd><dd>>> Â  Â  Â  Â  Â  Â  Â byte[] buf
= new byte[Helper.BUF_SIZE];<br />

</dd><dd>>> Â  Â  Â  Â  Â  Â  Â long
bytesToRead = BYTES_TO_READ;<br />

</dd><dd>>><br />

</dd><dd>>> Â  Â  Â  Â  Â  Â  Â long
startTime = System.currentTimeMillis();<br />

</dd><dd>>><br />

</dd><dd>>> Â  Â  Â  Â  Â  Â  Â while
(bytesToRead > 0) {<br />

</dd><dd>>> Â  Â  Â  Â  Â  Â  Â 
  Â bytesToRead -= inputstream.read(buf);<br />

</dd><dd>>> Â  Â  Â  Â  Â  Â  Â }<br />

</dd><dd>>><br />

</dd><dd>>> Â  Â  Â  Â  Â  Â  Â long
stopTime = System.currentTimeMillis();<br />

</dd><dd>>> Â  Â  Â  Â  Â  Â  Â long
totalTimeMs = stopTime - startTime;<br />

</dd><dd>>> Â  Â  Â  Â  Â  Â  Â double
mbRead = BYTES_TO_READ / (1024.0 * 1024);<br />

</dd><dd>>> Â  Â  Â  Â  Â  Â  Â double
totalTimeSeconds = totalTimeMs / 1000.0;<br />

</dd><dd>>> Â  Â  Â  Â  Â  Â  Â double
mibPerSecond = mbRead / totalTimeSeconds;<br />

</dd><dd>>><br />

</dd><dd>>> Â  Â  Â  Â  Â  Â  Â
System.out.println("Using cipher suite: " +<br />

</dd><dd>>> (sslsocket.getSession()).getCipherSuite());<br />

</dd><dd>>> Â  Â  Â  Â  Â  Â  Â
System.out.println("Read " + mbRead + "MiB in "
+<br />

</dd><dd>>> totalTimeSeconds + "s");<br />

</dd><dd>>> Â  Â  Â  Â  Â  Â  Â
System.out.println("Bandwidth: " + mibPerSecond +
"MiB/s");<br />

</dd><dd>>><br />

</dd><dd>>> Â  Â  Â  Â  Â } catch (IOException
exception) {<br />

</dd><dd>>> Â  Â  Â  Â  Â  Â  Â
exception.printStackTrace();<br />

</dd><dd>>> Â  Â  Â  Â  Â }<br />

</dd><dd>>> Â  Â  Â }<br />

</dd><dd>>><br />

</dd><dd>>> Â  Â  Â private static final int BYTES_TO_READ =
Helper.BUF_COUNT *<br />

</dd><dd>>> Helper.BUF_SIZE;<br />

</dd><dd>>> }<br />

</dd><dd>>><br />

</dd><dd>>> ///// Helper.java<br />

</dd><dd>>><br />

</dd><dd>>> package ssl;<br />

</dd><dd>>><br />

</dd><dd>>> import java.util.*;<br />

</dd><dd>>> import java.util.regex.*;<br />

</dd><dd>>> import javax.net.ssl.*;<br />

</dd><dd>>><br />

</dd><dd>>> public class Helper {<br />

</dd><dd>>><br />

</dd><dd>>> Â  Â  Â static int BUF_SIZE = 1024 * 1024;<br />

</dd><dd>>> Â  Â  Â static int BUF_COUNT = 100;<br />

</dd><dd>>><br />

</dd><dd>>> Â  Â  Â static SSLSocket
requireAESCipherSuites(SSLSocket socket) {<br />

</dd><dd>>> Â  Â  Â  Â  Â String
supportedCipherSuites[] =<br />

</dd><dd>>> socket.getSupportedCipherSuites();<br />

</dd><dd>>><br />

</dd><dd>>> Â  Â  Â  Â  Â
System.out.println("Supported cipher suite: " +<br />

</dd><dd>>> Arrays.toString(supportedCipherSuites));<br />

</dd><dd>>><br />

</dd><dd>>> Â  Â  Â  Â  Â List<String>
selectedCipherSuites = new ArrayList<>();<br />

</dd><dd>>><br />

</dd><dd>>> // Â  Â  Â  Â String patternString =
".*";<br />

</dd><dd>>> Â  Â  Â  Â  Â String patternString =
"TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256";<br />

</dd><dd>>> // Â  Â  Â  Â String patternString =<br />

</dd><dd>>> "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256";<br />

</dd><dd>>><br />

</dd><dd>>> Â  Â  Â  Â  Â Pattern pattern =
Pattern.compile(patternString);<br />

</dd><dd>>><br />

</dd><dd>>> Â  Â  Â  Â  Â for (String cipherSuite :
supportedCipherSuites) {<br />

</dd><dd>>> Â  Â  Â  Â  Â  Â  Â Matcher
matcher = pattern.matcher(cipherSuite);<br />

</dd><dd>>> Â  Â  Â  Â  Â  Â  Â if
(matcher.find()) {<br />

</dd><dd>>> Â  Â  Â  Â  Â  Â  Â 
  Â selectedCipherSuites.add(cipherSuite);<br />

</dd><dd>>> Â  Â  Â  Â  Â  Â  Â }<br />

</dd><dd>>> Â  Â  Â  Â  Â }<br />

</dd><dd>>><br />

</dd><dd>>> Â  Â  Â  Â  Â
System.out.println("Selected cipher suites: " +<br />

</dd><dd>>> selectedCipherSuites);<br />

</dd><dd>>><br />

</dd><dd>>> Â  Â  Â  Â  Â
socket.setEnabledCipherSuites(selectedCipherSuites.toArray(new<br />

</dd><dd>>> String[0]));<br />

</dd><dd>>><br />

</dd><dd>>> Â  Â  Â  Â  Â return socket;<br />

</dd><dd>>> Â  Â  Â }<br />

</dd><dd>>> }<br />

</dd><dd>>><br /><br />

</dd></dl><br /><br />
<br />
-- <br />
Mark Christiaens<br />
Ganzeplas 23<br />
9880 Aalter<br />
09 / 325 07 40 </blockquote>
<br />

</blockquote></div></body></html>