[prev in list] [next in list] [prev in thread] [next in thread]
List: openjdk-net-dev
Subject: Re: AES GCM slow
From: Michael StJohns <mstjohns () comcast ! net>
Date: 2014-01-27 16:46:45
Message-ID: 20140127164647.B073F64D3 () mail ! openjdk ! java ! net
[Download RAW message or body]
At 09:23 AM 1/27/2014, Mark Christiaens wrote:
> Silly me, forgot to mention that I'm working on Ubuntu, 64 bit, 13.10.
>
> 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.
> Mark
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.
The more recent intel processors have a set of instructions that substantially \
improve this performance - http://en.wikipedia.org/wiki/CLMUL_instruction_set - 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.
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.
Also see http://software.intel.com/en-us/articles/intel-aes-ni-performance-testing-on-linuxjava-stack
Mike
> On Mon, Jan 27, 2014 at 3:19 PM, Xuelei Fan \
> <<mailto:xuelei.fan@oracle.com>xuelei.fan@oracle.com> wrote: What's the platform \
> are you using for the testing? Windows, Linux, Solaris or Mac OS? GCM are now \
> only implemented in SunJCE provider. I want to make sure the crypto provider for \
> AES-CBC, which is different for different platforms by default, is not the major \
> cause of the performance impact.
>
> Thanks for the performance measure.
>
> Regards,
> Xuelei
>
> On 1/27/2014 5:34 PM, Chris Hegarty wrote:
> > Cross posting to security-dev, since the question cipher related.
> >
> > -Chris.
> >
> > On 27/01/14 09:28, Mark Christiaens wrote:
> > > I wrote a little test client/server setup that transfers 100 MB of data
> > > over an SSL socket configured to use TLS 1.2 AES GCM
> > > (TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256). On my i7-4770 CPU @ 3.40GHz
> > > with OpenJDK 1.8.0-ea-b124 I get a transfer rate of around 5.2
> > > MiB/second. I expected a higher speed. Using
> > > TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 I reach 100 MiB/s. Is this to
> > > be expected?
> > >
> > > For reference, here is my code:
> > >
> > > ///// Client.java
> > >
> > > package ssl;
> > >
> > > import javax.net.ssl.*;
> > > import java.io.*;
> > > import java.util.Arrays;
> > >
> > > public class Client {
> > >
> > > public static void main(String[] arstring) {
> > > try {
> > > SSLSocketFactory sslsocketfactory = (SSLSocketFactory)
> > > SSLSocketFactory.getDefault();
> > > SSLSocket sslsocket = (SSLSocket)
> > > sslsocketfactory.createSocket("localhost", 9999);
> > > Helper.requireAESCipherSuites(sslsocket);
> > > sslsocket.setEnabledProtocols(new String[]{"TLSv1.2"});
> > >
> > > try (OutputStream outputstream =
> > > sslsocket.getOutputStream()) {
> > > byte[] buf = new byte[Helper.BUF_SIZE];
> > > Arrays.fill(buf, (byte) 1);
> > > for (int i = 0; i < Helper.BUF_COUNT; ++i) {
> > > outputstream.write(buf);
> > > }
> > >
> > > System.out.println("Using cipher suite: " +
> > > (sslsocket.getSession()).getCipherSuite());
> > >
> > > outputstream.flush();
> > > }
> > >
> > > } catch (IOException exception) {
> > > exception.printStackTrace();
> > > }
> > > }
> > > }
> > >
> > > ///// Server.java
> > >
> > > package ssl;
> > >
> > > import javax.net.ssl.*;
> > > import java.io.*;
> > >
> > > public class Server {
> > >
> > > public static void main(String[] arstring) {
> > > try {
> > > SSLServerSocketFactory sslserversocketfactory =
> > > (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
> > > SSLServerSocket sslserversocket = (SSLServerSocket)
> > > sslserversocketfactory.createServerSocket(9999);
> > > SSLSocket sslsocket = (SSLSocket) sslserversocket.accept();
> > >
> > > InputStream inputstream = sslsocket.getInputStream();
> > >
> > > byte[] buf = new byte[Helper.BUF_SIZE];
> > > long bytesToRead = BYTES_TO_READ;
> > >
> > > long startTime = System.currentTimeMillis();
> > >
> > > while (bytesToRead > 0) {
> > > bytesToRead -= inputstream.read(buf);
> > > }
> > >
> > > long stopTime = System.currentTimeMillis();
> > > long totalTimeMs = stopTime - startTime;
> > > double mbRead = BYTES_TO_READ / (1024.0 * 1024);
> > > double totalTimeSeconds = totalTimeMs / 1000.0;
> > > double mibPerSecond = mbRead / totalTimeSeconds;
> > >
> > > System.out.println("Using cipher suite: " +
> > > (sslsocket.getSession()).getCipherSuite());
> > > System.out.println("Read " + mbRead + "MiB in " +
> > > totalTimeSeconds + "s");
> > > System.out.println("Bandwidth: " + mibPerSecond + "MiB/s");
> > >
> > > } catch (IOException exception) {
> > > exception.printStackTrace();
> > > }
> > > }
> > >
> > > private static final int BYTES_TO_READ = Helper.BUF_COUNT *
> > > Helper.BUF_SIZE;
> > > }
> > >
> > > ///// Helper.java
> > >
> > > package ssl;
> > >
> > > import java.util.*;
> > > import java.util.regex.*;
> > > import javax.net.ssl.*;
> > >
> > > public class Helper {
> > >
> > > static int BUF_SIZE = 1024 * 1024;
> > > static int BUF_COUNT = 100;
> > >
> > > static SSLSocket requireAESCipherSuites(SSLSocket socket) {
> > > String supportedCipherSuites[] =
> > > socket.getSupportedCipherSuites();
> > >
> > > System.out.println("Supported cipher suite: " +
> > > Arrays.toString(supportedCipherSuites));
> > >
> > > List<String> selectedCipherSuites = new ArrayList<>();
> > >
> > > // String patternString = ".*";
> > > String patternString = "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256";
> > > // String patternString =
> > > "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256";
> > >
> > > Pattern pattern = Pattern.compile(patternString);
> > >
> > > for (String cipherSuite : supportedCipherSuites) {
> > > Matcher matcher = pattern.matcher(cipherSuite);
> > > if (matcher.find()) {
> > > selectedCipherSuites.add(cipherSuite);
> > > }
> > > }
> > >
> > > System.out.println("Selected cipher suites: " +
> > > selectedCipherSuites);
> > >
> > > socket.setEnabledCipherSuites(selectedCipherSuites.toArray(new
> > > String[0]));
> > >
> > > return socket;
> > > }
> > > }
> > >
>
>
>
>
> --
> Mark Christiaens
> Ganzeplas 23
> 9880 Aalter
> 09 / 325 07 40
[Attachment #3 (text/html)]
<html>
<body>
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>Solaris or Mac OS? GCM are now only implemented in SunJCE provider.
I<br>
<dd>want to make sure the crypto provider for AES-CBC, which is
different<br>
<dd>for different platforms by default, is not the major cause of
the<br>
<dd>performance impact.<br><br>
<dd>Thanks for the performance measure.<br><br>
<dd>Regards,<br>
<dd>Xuelei<br><br>
<dd>On 1/27/2014 5:34 PM, Chris Hegarty wrote:<br>
<dd>> Cross posting to security-dev, since the question cipher
related.<br>
<dd>><br>
<dd>> -Chris.<br>
<dd>><br>
<dd>> On 27/01/14 09:28, Mark Christiaens wrote:<br>
<dd>>> I wrote a little test client/server setup that transfers
100 MB of data<br>
<dd>>> over an SSL socket configured to use TLS 1.2 AES GCM<br>
<dd>>> (TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256). On my i7-4770
CPU @ 3.40GHz<br>
<dd>>> with OpenJDK 1.8.0-ea-b124 I get a transfer rate of around
5.2<br>
<dd>>> MiB/second. I expected a higher speed. Using<br>
<dd>>> TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 I reach 100 MiB/s.
Is this to<br>
<dd>>> be expected?<br>
<dd>>><br>
<dd>>> For reference, here is my code:<br>
<dd>>><br>
<dd>>> ///// Client.java<br>
<dd>>><br>
<dd>>> package ssl;<br>
<dd>>><br>
<dd>>> import javax.net.ssl.*;<br>
<dd>>> import java.io.*;<br>
<dd>>> import java.util.Arrays;<br>
<dd>>><br>
<dd>>> public class Client {<br>
<dd>>><br>
<dd>>> public static void main(String[] arstring)
{<br>
<dd>>> try {<br>
<dd>>>
SSLSocketFactory sslsocketfactory = (SSLSocketFactory)<br>
<dd>>> SSLSocketFactory.getDefault();<br>
<dd>>> SSLSocket
sslsocket = (SSLSocket)<br>
<dd>>> sslsocketfactory.createSocket("localhost",
9999);<br>
<dd>>>
Helper.requireAESCipherSuites(sslsocket);<br>
<dd>>>
sslsocket.setEnabledProtocols(new String[]{"TLSv1.2"});<br>
<dd>>><br>
<dd>>> try
(OutputStream outputstream =<br>
<dd>>> sslsocket.getOutputStream()) {<br>
<dd>>>
byte[] buf = new byte[Helper.BUF_SIZE];<br>
<dd>>>
Arrays.fill(buf, (byte) 1);<br>
<dd>>>
for (int i = 0; i < Helper.BUF_COUNT; ++i) {<br>
<dd>>>
outputstream.write(buf);<br>
<dd>>>
}<br>
<dd>>><br>
<dd>>>
System.out.println("Using cipher suite: " +<br>
<dd>>> (sslsocket.getSession()).getCipherSuite());<br>
<dd>>><br>
<dd>>>
outputstream.flush();<br>
<dd>>> }<br>
<dd>>><br>
<dd>>> } catch (IOException
exception) {<br>
<dd>>>
exception.printStackTrace();<br>
<dd>>> }<br>
<dd>>> }<br>
<dd>>> }<br>
<dd>>><br>
<dd>>> ///// Server.java<br>
<dd>>><br>
<dd>>> package ssl;<br>
<dd>>><br>
<dd>>> import javax.net.ssl.*;<br>
<dd>>> import java.io.*;<br>
<dd>>><br>
<dd>>> public class Server {<br>
<dd>>><br>
<dd>>> public static void main(String[] arstring)
{<br>
<dd>>> try {<br>
<dd>>>
SSLServerSocketFactory sslserversocketfactory =<br>
<dd>>> (SSLServerSocketFactory)
SSLServerSocketFactory.getDefault();<br>
<dd>>>
SSLServerSocket sslserversocket = (SSLServerSocket)<br>
<dd>>> sslserversocketfactory.createServerSocket(9999);<br>
<dd>>> SSLSocket
sslsocket = (SSLSocket) sslserversocket.accept();<br>
<dd>>><br>
<dd>>>
InputStream inputstream = sslsocket.getInputStream();<br>
<dd>>><br>
<dd>>> byte[] buf
= new byte[Helper.BUF_SIZE];<br>
<dd>>> long
bytesToRead = BYTES_TO_READ;<br>
<dd>>><br>
<dd>>> long
startTime = System.currentTimeMillis();<br>
<dd>>><br>
<dd>>> while
(bytesToRead > 0) {<br>
<dd>>>
bytesToRead -= inputstream.read(buf);<br>
<dd>>> }<br>
<dd>>><br>
<dd>>> long
stopTime = System.currentTimeMillis();<br>
<dd>>> long
totalTimeMs = stopTime - startTime;<br>
<dd>>> double
mbRead = BYTES_TO_READ / (1024.0 * 1024);<br>
<dd>>> double
totalTimeSeconds = totalTimeMs / 1000.0;<br>
<dd>>> double
mibPerSecond = mbRead / totalTimeSeconds;<br>
<dd>>><br>
<dd>>>
System.out.println("Using cipher suite: " +<br>
<dd>>> (sslsocket.getSession()).getCipherSuite());<br>
<dd>>>
System.out.println("Read " + mbRead + "MiB in "
+<br>
<dd>>> totalTimeSeconds + "s");<br>
<dd>>>
System.out.println("Bandwidth: " + mibPerSecond +
"MiB/s");<br>
<dd>>><br>
<dd>>> } catch (IOException
exception) {<br>
<dd>>>
exception.printStackTrace();<br>
<dd>>> }<br>
<dd>>> }<br>
<dd>>><br>
<dd>>> private static final int BYTES_TO_READ =
Helper.BUF_COUNT *<br>
<dd>>> Helper.BUF_SIZE;<br>
<dd>>> }<br>
<dd>>><br>
<dd>>> ///// Helper.java<br>
<dd>>><br>
<dd>>> package ssl;<br>
<dd>>><br>
<dd>>> import java.util.*;<br>
<dd>>> import java.util.regex.*;<br>
<dd>>> import javax.net.ssl.*;<br>
<dd>>><br>
<dd>>> public class Helper {<br>
<dd>>><br>
<dd>>> static int BUF_SIZE = 1024 * 1024;<br>
<dd>>> static int BUF_COUNT = 100;<br>
<dd>>><br>
<dd>>> static SSLSocket
requireAESCipherSuites(SSLSocket socket) {<br>
<dd>>> String
supportedCipherSuites[] =<br>
<dd>>> socket.getSupportedCipherSuites();<br>
<dd>>><br>
<dd>>>
System.out.println("Supported cipher suite: " +<br>
<dd>>> Arrays.toString(supportedCipherSuites));<br>
<dd>>><br>
<dd>>> List<String>
selectedCipherSuites = new ArrayList<>();<br>
<dd>>><br>
<dd>>> // String patternString =
".*";<br>
<dd>>> String patternString =
"TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256";<br>
<dd>>> // String patternString =<br>
<dd>>> "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256";<br>
<dd>>><br>
<dd>>> Pattern pattern =
Pattern.compile(patternString);<br>
<dd>>><br>
<dd>>> for (String cipherSuite :
supportedCipherSuites) {<br>
<dd>>> Matcher
matcher = pattern.matcher(cipherSuite);<br>
<dd>>> if
(matcher.find()) {<br>
<dd>>>
selectedCipherSuites.add(cipherSuite);<br>
<dd>>> }<br>
<dd>>> }<br>
<dd>>><br>
<dd>>>
System.out.println("Selected cipher suites: " +<br>
<dd>>> selectedCipherSuites);<br>
<dd>>><br>
<dd>>>
socket.setEnabledCipherSuites(selectedCipherSuites.toArray(new<br>
<dd>>> String[0]));<br>
<dd>>><br>
<dd>>> return socket;<br>
<dd>>> }<br>
<dd>>> }<br>
<dd>>><br><br>
</dl><br><br>
<br>
-- <br>
Mark Christiaens<br>
Ganzeplas 23<br>
9880 Aalter<br>
09 / 325 07 40 </blockquote></body>
<br>
</html>
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic