AES GCM slow

Michael StJohns mstjohns at comcast.net
Mon Jan 27 10:16:42 PST 2014


At 12:17 PM 1/27/2014, Matthew Hall wrote:
>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.


Yup.  https://developer.mozilla.org/en-US/docs/NSS/NSS_3.14.2_release_notes

>-- 
>Sent from my mobile device.
>
>Michael StJohns <mstjohns at comcast.net> wrote:
>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/04c88c07/attachment.html 


More information about the security-dev mailing list