Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit abcd50ae authored by Miguel Aranda's avatar Miguel Aranda Committed by Automerger Merge Worker
Browse files

Merge "Add more conscrypt benchmarks and extend benchmark parameterization."...

Merge "Add more conscrypt benchmarks and extend benchmark parameterization." into main am: 90ef6562 am: efe56f9a

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/3140418



Change-Id: I18a5db88f3ab2d2b64bbc308f98529627969f1cf
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 5d4a89bf efe56f9a
Loading
Loading
Loading
Loading
+14 −15
Original line number Diff line number Diff line
@@ -23,6 +23,9 @@ import androidx.test.filters.LargeTest;
import org.conscrypt.TestUtils;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Cipher;
@@ -91,21 +94,17 @@ public final class CipherEncryptPerfTest {
        }
    }

    private Object[] getParams() {
        return new Object[][] {
            new Object[] {new Config(BufferType.ARRAY,
                              MyCipherFactory.CONSCRYPT,
                              Transformation.AES_CBC_PKCS5)},
            new Object[] {new Config(BufferType.ARRAY,
                              MyCipherFactory.CONSCRYPT,
                              Transformation.AES_ECB_PKCS5)},
            new Object[] {new Config(BufferType.ARRAY,
                              MyCipherFactory.CONSCRYPT,
                              Transformation.AES_GCM_NO)},
            new Object[] {new Config(BufferType.ARRAY,
                              MyCipherFactory.CONSCRYPT,
                              Transformation.AES_GCM_SIV)},
        };
    public Collection <Object[]> getParams() {
        final List<Object[]> params = new ArrayList<>();
        for (BufferType bufferType : BufferType.values()) {
            for (CipherFactory cipherFactory : MyCipherFactory.values()) {
                for (Transformation transformation : Transformation.values()) {
                  params.add(new Object[] {new Config(
                                bufferType, cipherFactory, transformation)});
                }
            }
        }
        return params;
    }

    private EncryptStrategy encryptStrategy;
+21 −11
Original line number Diff line number Diff line
@@ -30,6 +30,9 @@ import java.io.IOException;
import java.io.OutputStream;
import java.net.SocketException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
@@ -104,18 +107,25 @@ public final class ClientSocketPerfTest {
        }
    }

    private Object[] getParams() {
        return new Object[][] {
            new Object[] {new Config(
                              EndpointFactory.CONSCRYPT,
                              EndpointFactory.CONSCRYPT,
                              64,
                              "AES128-GCM",
                              ChannelType.CHANNEL,
                              PerfTestProtocol.TLSv13)},
        };
    public Collection getParams() {
        final List<Object[]> params = new ArrayList<>();
        for (EndpointFactory endpointFactory : EndpointFactory.values()) {
            for (ChannelType channelType : ChannelType.values()) {
                for (PerfTestProtocol protocol : PerfTestProtocol.values()) {
                    params.add(new Object[] {new Config(endpointFactory,
                        endpointFactory, 64, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
                        channelType, protocol)});
                    params.add(new Object[] {new Config(endpointFactory,
                        endpointFactory, 512, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
                        channelType, protocol)});
                    params.add(new Object[] {new Config(endpointFactory,
                        endpointFactory, 4096, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
                        channelType, protocol)});
                }
            }
        }
        return params;
    }


    private ClientEndpoint client;
    private ServerEndpoint server;
+68 −0
Original line number Diff line number Diff line
/*
 * Copyright 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package android.conscrypt;

import org.conscrypt.TestUtils;
import java.security.Security;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;


/**
 * Factory for {@link SSLEngine} instances.
 */
public class EngineFactory {
    public EngineFactory() {
        this(newConscryptClientContext(), newConscryptServerContext());
    }

    private EngineFactory(SSLContext clientContext, SSLContext serverContext) {
        this.clientContext = clientContext;
        this.serverContext = serverContext;
    }

    private final SSLContext clientContext;
    private final SSLContext serverContext;

    public SSLEngine newClientEngine(String cipher) {
        SSLEngine engine = initEngine(clientContext.createSSLEngine(), cipher, true);
        return engine;
    }

    public SSLEngine newServerEngine(String cipher) {
        SSLEngine engine = initEngine(serverContext.createSSLEngine(), cipher, false);
        return engine;
    }

    public void dispose(SSLEngine engine) {
        engine.closeOutbound();
    }

    private static SSLContext newConscryptClientContext() {
        return TestUtils.newClientSslContext(TestUtils.getConscryptProvider());
    }

    private static SSLContext newConscryptServerContext() {
        return TestUtils.newServerSslContext(TestUtils.getConscryptProvider());
    }

    static SSLEngine initEngine(SSLEngine engine, String cipher, boolean client) {
        engine.setEnabledProtocols(new String[]{"TLSv1.2", "TLSv1.3"});
        engine.setEnabledCipherSuites(new String[] {cipher});
        engine.setUseClientMode(client);
        return engine;
    }
}
 No newline at end of file
+207 −0
Original line number Diff line number Diff line
/*
 * Copyright 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Copyright 2017 The Netty Project
 *
 * The Netty Project licenses this file to you under the Apache License,
 * version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

package android.conscrypt;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLEngineResult;
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
import javax.net.ssl.SSLException;

import junitparams.JUnitParamsRunner;
import junitparams.Parameters;

import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;

import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

/**
 * Benchmark comparing handshake performance of various engine implementations to conscrypt.
 */
@RunWith(JUnitParamsRunner.class)
@LargeTest
public final class EngineHandshakePerfTest {
    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();

    /**
     * Provider for the test configuration
     */
    private class Config {
        BufferType a_bufferType;
        String c_cipher;
        int d_rttMillis;
        Config(BufferType bufferType,
            String cipher,
            int rttMillis) {
          a_bufferType = bufferType;
          c_cipher = cipher;
          d_rttMillis = rttMillis;
        }
        public BufferType bufferType() {
            return a_bufferType;
        }

        public String cipher() {
            return c_cipher;
        }

        public int rttMillis() {
            return d_rttMillis;
        }
    }

    public Collection getParams() {
        final List<Object[]> params = new ArrayList<>();
        for (BufferType bufferType : BufferType.values()) {
            params.add(new Object[] {new Config(bufferType,
                "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", 100)});
        }
        return params;
    }

    private static final ByteBuffer EMPTY_BUFFER = ByteBuffer.allocateDirect(0);

    private EngineFactory engineFactory = new EngineFactory();
    private String cipher;
    private int rttMillis;

    private ByteBuffer clientApplicationBuffer;
    private ByteBuffer clientPacketBuffer;
    private ByteBuffer serverApplicationBuffer;
    private ByteBuffer serverPacketBuffer;

    private void setup(Config config) throws Exception {
        cipher = config.cipher();
        rttMillis = config.rttMillis();
        BufferType bufferType = config.bufferType();

        SSLEngine clientEngine = engineFactory.newClientEngine(cipher);
        SSLEngine serverEngine = engineFactory.newServerEngine(cipher);

        // Create the application and packet buffers for both endpoints.
        clientApplicationBuffer = bufferType.newApplicationBuffer(clientEngine);
        serverApplicationBuffer = bufferType.newApplicationBuffer(serverEngine);
        clientPacketBuffer = bufferType.newPacketBuffer(clientEngine);
        serverPacketBuffer = bufferType.newPacketBuffer(serverEngine);

        engineFactory.dispose(clientEngine);
        engineFactory.dispose(serverEngine);
    }

    @Test
    @Parameters(method = "getParams")
    public void handshake(Config config) throws Exception {
        setup(config);
        SSLEngine client = engineFactory.newClientEngine(cipher);
        SSLEngine server = engineFactory.newServerEngine(cipher);
        clientApplicationBuffer.clear();
        clientPacketBuffer.clear();
        serverApplicationBuffer.clear();
        serverPacketBuffer.clear();

        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
        while (state.keepRunning()) {
            client.beginHandshake();
            server.beginHandshake();
            doHandshake(client, server);
        }

        engineFactory.dispose(client);
        engineFactory.dispose(server);
    }

    private void doHandshake(SSLEngine client, SSLEngine server) throws SSLException {

        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
        while (state.keepRunning()) {
            // Send as many client-to-server messages as possible
            doHalfHandshake(client, server, clientPacketBuffer, serverApplicationBuffer);

            if (client.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING
                    && server.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING) {
                return;
            }

            // Do the same with server-to-client messages
            doHalfHandshake(server, client, serverPacketBuffer, clientApplicationBuffer);

            if (client.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING
                    && server.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING) {
                return;
            }
        }
    }

    private void doHalfHandshake(SSLEngine sender, SSLEngine receiver,
            ByteBuffer senderPacketBuffer, ByteBuffer receiverApplicationBuffer)
            throws SSLException {
        SSLEngineResult senderResult;
        SSLEngineResult receiverResult;

        do {
            senderResult = sender.wrap(EMPTY_BUFFER, senderPacketBuffer);
            runDelegatedTasks(senderResult, sender);
            senderPacketBuffer.flip();
            receiverResult = receiver.unwrap(senderPacketBuffer, receiverApplicationBuffer);
            runDelegatedTasks(receiverResult, receiver);
            senderPacketBuffer.compact();
        } while (senderResult.getHandshakeStatus() == HandshakeStatus.NEED_WRAP);

        if (rttMillis > 0) {
            try {
                Thread.sleep(rttMillis / 2);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

    private static void runDelegatedTasks(SSLEngineResult result, SSLEngine engine) {
        if (result.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_TASK) {
            for (;;) {
                Runnable task = engine.getDelegatedTask();
                if (task == null) {
                    break;
                }
                task.run();
            }
        }
    }
}
 No newline at end of file
+221 −0
Original line number Diff line number Diff line
/*
 * Copyright 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Copyright 2017 The Netty Project
 *
 * The Netty Project licenses this file to you under the Apache License,
 * version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

package android.conscrypt;

import static org.conscrypt.TestUtils.doEngineHandshake;
import static org.conscrypt.TestUtils.newTextMessage;
import static org.junit.Assert.assertEquals;

import java.nio.ByteBuffer;
import java.util.Locale;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLEngineResult;
import javax.net.ssl.SSLException;

import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import androidx.test.filters.LargeTest;

import junitparams.JUnitParamsRunner;
import junitparams.Parameters;

import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

/**
 * Benchmark comparing performance of various engine implementations to conscrypt.
 */
@RunWith(JUnitParamsRunner.class)
@LargeTest
public final class EngineWrapPerfTest {
    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();

    /**
     * Provider for the benchmark configuration
     */
    private class Config {
        BufferType a_bufferType;
        int c_messageSize;
        String d_cipher;
        Config(BufferType bufferType,
            int messageSize,
            String cipher) {
          a_bufferType = bufferType;
          c_messageSize = messageSize;
          d_cipher = cipher;
        }
        public BufferType bufferType() {
            return a_bufferType;
        }

        public int messageSize() {
            return c_messageSize;
        }

        public String cipher() {
            return d_cipher;
        }
    }

    public Collection getParams() {
        final List<Object[]> params = new ArrayList<>();
        for (BufferType bufferType : BufferType.values()) {
            params.add(new Object[] {new Config(bufferType, 64,
                                    "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256")});
            params.add(new Object[] {new Config(bufferType, 512,
                                    "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256")});
            params.add(new Object[] {new Config(bufferType, 4096,
                                    "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256")});
        }
        return params;
    }


    private EngineFactory engineFactory = new EngineFactory();
    private String cipher;
    private SSLEngine clientEngine;
    private SSLEngine serverEngine;

    private ByteBuffer messageBuffer;
    private ByteBuffer clientApplicationBuffer;
    private ByteBuffer clientPacketBuffer;
    private ByteBuffer serverApplicationBuffer;
    private ByteBuffer serverPacketBuffer;
    private ByteBuffer preEncryptedBuffer;

    private void setup(Config config) throws Exception {
        cipher = config.cipher();
        BufferType bufferType = config.bufferType();

        clientEngine = engineFactory.newClientEngine(cipher);
        serverEngine = engineFactory.newServerEngine(cipher);

        // Create the application and packet buffers for both endpoints.
        clientApplicationBuffer = bufferType.newApplicationBuffer(clientEngine);
        serverApplicationBuffer = bufferType.newApplicationBuffer(serverEngine);
        clientPacketBuffer = bufferType.newPacketBuffer(clientEngine);
        serverPacketBuffer = bufferType.newPacketBuffer(serverEngine);

        // Generate the message to be sent from the client.
        int messageSize = config.messageSize();
        messageBuffer = bufferType.newBuffer(messageSize);
        messageBuffer.put(newTextMessage(messageSize));
        messageBuffer.flip();

        // Complete the initial TLS handshake.
        doEngineHandshake(clientEngine, serverEngine, clientApplicationBuffer, clientPacketBuffer,
                serverApplicationBuffer, serverPacketBuffer, true);

        // Populate the pre-encrypted buffer for use with the unwrap benchmark.
        preEncryptedBuffer = bufferType.newBuffer(clientEngine.getSession().getPacketBufferSize());
        doWrap(messageBuffer, preEncryptedBuffer);
        doUnwrap(preEncryptedBuffer, serverApplicationBuffer);
    }

    void teardown() {
        engineFactory.dispose(clientEngine);
        engineFactory.dispose(serverEngine);
    }

    @Test
    @Parameters(method = "getParams")
    public void wrap(Config config) throws Exception {
        setup(config);

        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
        while (state.keepRunning()) {
            // Reset the buffers.
            messageBuffer.position(0);
            clientPacketBuffer.clear();
            // Wrap the original message and create the encrypted data.
            doWrap(messageBuffer, clientPacketBuffer);

            // Lightweight comparison - just make sure the data length is correct.
            assertEquals(preEncryptedBuffer.limit(), clientPacketBuffer.limit());
        }
        teardown();
    }

    /**
     * Simple benchmark that sends a single message from client to server.
     */
    @Test
    @Parameters(method = "getParams")
    public void wrapAndUnwrap(Config config) throws Exception {
        setup(config);

        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
        while (state.keepRunning()) {
            // Reset the buffers.
            messageBuffer.position(0);
            clientPacketBuffer.clear();
            serverApplicationBuffer.clear();
            // Wrap the original message and create the encrypted data.
            doWrap(messageBuffer, clientPacketBuffer);

            // Unwrap the encrypted data and get back the original result.
            doUnwrap(clientPacketBuffer, serverApplicationBuffer);

            // Lightweight comparison - just make sure the unencrypted data length is correct.
            assertEquals(messageBuffer.limit(), serverApplicationBuffer.limit());
        }
        teardown();
    }

    private void doWrap(ByteBuffer src, ByteBuffer dst) throws SSLException {
        // Wrap the original message and create the encrypted data.
        verifyResult(src, clientEngine.wrap(src, dst));
        dst.flip();
    }

    private void doUnwrap(ByteBuffer src, ByteBuffer dst) throws SSLException {
        verifyResult(src, serverEngine.unwrap(src, dst));
        dst.flip();
    }

    private void verifyResult(ByteBuffer src, SSLEngineResult result) {
        if (result.getStatus() != SSLEngineResult.Status.OK) {
            throw new RuntimeException("Operation returned unexpected result " + result);
        }
        if (result.bytesConsumed() != src.limit()) {
            throw new RuntimeException(
                    String.format(Locale.US,
                            "Operation didn't consume all bytes. Expected %d, consumed %d.",
                            src.limit(), result.bytesConsumed()));
        }
    }
}
 No newline at end of file
Loading