1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package org.conscrypt; 18 19 import java.nio.ByteBuffer; 20 import java.security.Key; 21 import javax.crypto.Cipher; 22 23 /** 24 * Benchmark for comparing cipher encrypt performance. 25 */ 26 public final class CipherEncryptBenchmark { 27 public enum BufferType { 28 ARRAY, 29 HEAP_HEAP, 30 HEAP_DIRECT, 31 DIRECT_DIRECT, 32 DIRECT_HEAP 33 } 34 35 /** 36 * Provider for the benchmark configuration 37 */ 38 interface Config { bufferType()39 BufferType bufferType(); cipherFactory()40 CipherFactory cipherFactory(); transformation()41 Transformation transformation(); 42 } 43 44 private final EncryptStrategy encryptStrategy; 45 CipherEncryptBenchmark(Config config)46 CipherEncryptBenchmark(Config config) throws Exception { 47 switch (config.bufferType()) { 48 case ARRAY: 49 encryptStrategy = new ArrayStrategy(config); 50 break; 51 default: 52 encryptStrategy = new ByteBufferStrategy(config); 53 break; 54 } 55 } 56 encrypt()57 int encrypt() throws Exception { 58 return encryptStrategy.encrypt(); 59 } 60 61 private static abstract class EncryptStrategy { 62 private final Key key; 63 final Cipher cipher; 64 final int outputSize; 65 EncryptStrategy(Config config)66 EncryptStrategy(Config config) throws Exception { 67 Transformation tx = config.transformation(); 68 key = tx.newEncryptKey(); 69 cipher = config.cipherFactory().newCipher(tx.toFormattedString()); 70 initCipher(); 71 72 int messageSize = messageSize(tx.toFormattedString()); 73 outputSize = cipher.getOutputSize(messageSize); 74 } 75 initCipher()76 final void initCipher() throws Exception { 77 cipher.init(Cipher.ENCRYPT_MODE, key); 78 } 79 messageSize(String transformation)80 final int messageSize(String transformation) throws Exception { 81 Cipher conscryptCipher = Cipher.getInstance(transformation, TestUtils.getConscryptProvider()); 82 conscryptCipher.init(Cipher.ENCRYPT_MODE, key); 83 return conscryptCipher.getBlockSize() > 0 ? conscryptCipher.getBlockSize() : 128; 84 } 85 newMessage()86 final byte[] newMessage() { 87 return TestUtils.newTextMessage(cipher.getBlockSize()); 88 } 89 encrypt()90 abstract int encrypt() throws Exception; 91 } 92 93 private static final class ArrayStrategy extends EncryptStrategy { 94 private final byte[] plainBytes; 95 private final byte[] cipherBytes; 96 ArrayStrategy(Config config)97 ArrayStrategy(Config config) throws Exception { 98 super(config); 99 100 plainBytes = newMessage(); 101 cipherBytes = new byte[outputSize]; 102 } 103 104 @Override encrypt()105 int encrypt() throws Exception { 106 initCipher(); 107 return cipher.doFinal(plainBytes, 0, plainBytes.length, cipherBytes, 0); 108 } 109 } 110 111 private static final class ByteBufferStrategy extends EncryptStrategy { 112 private final ByteBuffer input; 113 private final ByteBuffer output; 114 ByteBufferStrategy(Config config)115 ByteBufferStrategy(Config config) throws Exception { 116 super(config); 117 118 switch (config.bufferType()) { 119 case HEAP_HEAP: 120 input = ByteBuffer.wrap(newMessage()); 121 output = ByteBuffer.allocate(outputSize); 122 break; 123 case HEAP_DIRECT: 124 input = ByteBuffer.wrap(newMessage()); 125 output = ByteBuffer.allocateDirect(outputSize); 126 break; 127 case DIRECT_DIRECT: 128 input = toDirect(newMessage()); 129 output = ByteBuffer.allocateDirect(outputSize); 130 break; 131 case DIRECT_HEAP: 132 input = toDirect(newMessage()); 133 output = ByteBuffer.allocate(outputSize); 134 break; 135 default: { 136 throw new IllegalStateException( 137 "Unexpected buffertype: " + config.bufferType()); 138 } 139 } 140 } 141 142 @Override encrypt()143 int encrypt() throws Exception { 144 initCipher(); 145 input.position(0); 146 output.clear(); 147 return cipher.doFinal(input, output); 148 } 149 toDirect(byte[] data)150 private static ByteBuffer toDirect(byte[] data) { 151 ByteBuffer buffer = ByteBuffer.allocateDirect(data.length); 152 buffer.put(data); 153 buffer.flip(); 154 return buffer; 155 } 156 } 157 } 158