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