AES GCM slow

Michael StJohns mstjohns at comcast.net
Mon Jan 27 08:46:45 PST 2014


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 at oracle.com>xuelei.fan at 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 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.openjdk.java.net/pipermail/security-dev/attachments/20140127/18da0bea/attachment.html 


More information about the security-dev mailing list