Tue, 04 Feb 2020 18:13:14 +0800
Merge
kvn@4205 | 1 | /* |
kvn@6653 | 2 | * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. |
kvn@4205 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
kvn@4205 | 4 | * |
kvn@4205 | 5 | * This code is free software; you can redistribute it and/or modify it |
kvn@4205 | 6 | * under the terms of the GNU General Public License version 2 only, as |
kvn@4205 | 7 | * published by the Free Software Foundation. |
kvn@4205 | 8 | * |
kvn@4205 | 9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
kvn@4205 | 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
kvn@4205 | 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
kvn@4205 | 12 | * version 2 for more details (a copy is included in the LICENSE file that |
kvn@4205 | 13 | * accompanied this code). |
kvn@4205 | 14 | * |
kvn@4205 | 15 | * You should have received a copy of the GNU General Public License version |
kvn@4205 | 16 | * 2 along with this work; if not, write to the Free Software Foundation, |
kvn@4205 | 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
kvn@4205 | 18 | * |
kvn@4205 | 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
kvn@4205 | 20 | * or visit www.oracle.com if you need additional information or have any |
kvn@4205 | 21 | * questions. |
kvn@4205 | 22 | * |
kvn@4205 | 23 | */ |
kvn@4205 | 24 | |
kvn@4205 | 25 | /** |
kvn@4205 | 26 | * @author Tom Deneau |
kvn@4205 | 27 | */ |
kvn@4205 | 28 | |
kvn@4205 | 29 | import javax.crypto.Cipher; |
kvn@4205 | 30 | import javax.crypto.KeyGenerator; |
kvn@4205 | 31 | import javax.crypto.SecretKey; |
ascarpino@9788 | 32 | import javax.crypto.spec.GCMParameterSpec; |
kvn@4205 | 33 | import javax.crypto.spec.IvParameterSpec; |
kvn@4205 | 34 | import javax.crypto.spec.SecretKeySpec; |
kvn@4205 | 35 | import java.security.AlgorithmParameters; |
kvn@4205 | 36 | |
kvn@4205 | 37 | import java.util.Random; |
kvn@4205 | 38 | import java.util.Arrays; |
kvn@4205 | 39 | |
kvn@4205 | 40 | abstract public class TestAESBase { |
kvn@4205 | 41 | int msgSize = Integer.getInteger("msgSize", 646); |
kvn@4205 | 42 | boolean checkOutput = Boolean.getBoolean("checkOutput"); |
kvn@4205 | 43 | boolean noReinit = Boolean.getBoolean("noReinit"); |
kvn@6653 | 44 | boolean testingMisalignment; |
kvn@6653 | 45 | private static final int ALIGN = 8; |
kvn@6653 | 46 | int encInputOffset = Integer.getInteger("encInputOffset", 0) % ALIGN; |
kvn@6653 | 47 | int encOutputOffset = Integer.getInteger("encOutputOffset", 0) % ALIGN; |
kvn@6653 | 48 | int decOutputOffset = Integer.getInteger("decOutputOffset", 0) % ALIGN; |
kvn@6653 | 49 | int lastChunkSize = Integer.getInteger("lastChunkSize", 32); |
kvn@4205 | 50 | int keySize = Integer.getInteger("keySize", 128); |
kvn@6653 | 51 | int inputLength; |
kvn@6653 | 52 | int encodeLength; |
kvn@6653 | 53 | int decodeLength; |
kvn@6653 | 54 | int decodeMsgSize; |
kvn@4205 | 55 | String algorithm = System.getProperty("algorithm", "AES"); |
kvn@4205 | 56 | String mode = System.getProperty("mode", "CBC"); |
kvn@6653 | 57 | String paddingStr = System.getProperty("paddingStr", "PKCS5Padding"); |
kvn@4205 | 58 | byte[] input; |
kvn@4205 | 59 | byte[] encode; |
kvn@4205 | 60 | byte[] expectedEncode; |
kvn@4205 | 61 | byte[] decode; |
kvn@4205 | 62 | byte[] expectedDecode; |
kvn@4205 | 63 | Random random = new Random(0); |
kvn@4205 | 64 | Cipher cipher; |
kvn@4205 | 65 | Cipher dCipher; |
ascarpino@9789 | 66 | AlgorithmParameters algParams = null; |
kvn@4205 | 67 | SecretKey key; |
ascarpino@9788 | 68 | GCMParameterSpec gcm_spec; |
ascarpino@9789 | 69 | byte[] aad = { 0x11, 0x22, 0x33, 0x44, 0x55 }; |
ascarpino@9788 | 70 | int tlen = 12; |
ascarpino@9789 | 71 | byte[] iv = new byte[16]; |
kvn@4205 | 72 | |
kvn@4205 | 73 | static int numThreads = 0; |
kvn@4205 | 74 | int threadId; |
kvn@4205 | 75 | static synchronized int getThreadId() { |
kvn@4205 | 76 | int id = numThreads; |
kvn@4205 | 77 | numThreads++; |
kvn@4205 | 78 | return id; |
kvn@4205 | 79 | } |
kvn@4205 | 80 | |
kvn@4205 | 81 | abstract public void run(); |
kvn@4205 | 82 | |
kvn@4205 | 83 | public void prepare() { |
kvn@4205 | 84 | try { |
ascarpino@9789 | 85 | System.out.println("\nalgorithm=" + algorithm + ", mode=" + mode + ", paddingStr=" + paddingStr + |
ascarpino@9789 | 86 | ", msgSize=" + msgSize + ", keySize=" + keySize + ", noReinit=" + noReinit + |
ascarpino@9789 | 87 | ", checkOutput=" + checkOutput + ", encInputOffset=" + encInputOffset + ", encOutputOffset=" + |
ascarpino@9789 | 88 | encOutputOffset + ", decOutputOffset=" + decOutputOffset + ", lastChunkSize=" +lastChunkSize ); |
kvn@6653 | 89 | |
kvn@6653 | 90 | if (encInputOffset % ALIGN != 0 || encOutputOffset % ALIGN != 0 || decOutputOffset % ALIGN !=0 ) |
kvn@6653 | 91 | testingMisalignment = true; |
kvn@4205 | 92 | |
kvn@4205 | 93 | int keyLenBytes = (keySize == 0 ? 16 : keySize/8); |
kvn@4205 | 94 | byte keyBytes[] = new byte[keyLenBytes]; |
kvn@4205 | 95 | if (keySize == 128) |
kvn@4205 | 96 | keyBytes = new byte[] {-8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7}; |
kvn@4205 | 97 | else |
kvn@4205 | 98 | random.nextBytes(keyBytes); |
kvn@4205 | 99 | |
kvn@4205 | 100 | key = new SecretKeySpec(keyBytes, algorithm); |
kvn@4205 | 101 | if (threadId == 0) { |
kvn@4205 | 102 | System.out.println("Algorithm: " + key.getAlgorithm() + "(" |
kvn@4205 | 103 | + key.getEncoded().length * 8 + "bit)"); |
kvn@4205 | 104 | } |
kvn@4205 | 105 | |
kvn@4205 | 106 | cipher = Cipher.getInstance(algorithm + "/" + mode + "/" + paddingStr, "SunJCE"); |
kvn@4205 | 107 | dCipher = Cipher.getInstance(algorithm + "/" + mode + "/" + paddingStr, "SunJCE"); |
kvn@4205 | 108 | |
ascarpino@9789 | 109 | // CBC init |
kvn@4363 | 110 | if (mode.equals("CBC")) { |
ascarpino@9789 | 111 | IvParameterSpec initVector = new IvParameterSpec(iv); |
kvn@4363 | 112 | cipher.init(Cipher.ENCRYPT_MODE, key, initVector); |
ascarpino@9789 | 113 | algParams = cipher.getParameters(); |
ascarpino@9789 | 114 | dCipher.init(Cipher.DECRYPT_MODE, key, initVector); |
ascarpino@9789 | 115 | |
ascarpino@9789 | 116 | // GCM init |
ascarpino@9788 | 117 | } else if (mode.equals("GCM")) { |
ascarpino@9789 | 118 | gcm_init(true); |
ascarpino@9789 | 119 | gcm_init(false); |
ascarpino@9789 | 120 | |
ascarpino@9789 | 121 | // ECB init |
kvn@4363 | 122 | } else { |
kvn@4363 | 123 | cipher.init(Cipher.ENCRYPT_MODE, key, algParams); |
ascarpino@9789 | 124 | dCipher.init(Cipher.DECRYPT_MODE, key, algParams); |
kvn@4363 | 125 | } |
ascarpino@9789 | 126 | |
kvn@4205 | 127 | if (threadId == 0) { |
kvn@4205 | 128 | childShowCipher(); |
kvn@4205 | 129 | } |
kvn@4205 | 130 | |
kvn@6653 | 131 | inputLength = msgSize + encInputOffset; |
kvn@6653 | 132 | if (testingMisalignment) { |
kvn@6653 | 133 | encodeLength = cipher.getOutputSize(msgSize - lastChunkSize) + encOutputOffset; |
kvn@6653 | 134 | encodeLength += cipher.getOutputSize(lastChunkSize); |
kvn@6653 | 135 | decodeLength = dCipher.getOutputSize(encodeLength - lastChunkSize) + decOutputOffset; |
kvn@6653 | 136 | decodeLength += dCipher.getOutputSize(lastChunkSize); |
kvn@6653 | 137 | } else { |
kvn@6653 | 138 | encodeLength = cipher.getOutputSize(msgSize) + encOutputOffset; |
kvn@6653 | 139 | decodeLength = dCipher.getOutputSize(encodeLength) + decOutputOffset; |
kvn@6653 | 140 | } |
kvn@6653 | 141 | |
kvn@6653 | 142 | input = new byte[inputLength]; |
kvn@6653 | 143 | for (int i=encInputOffset, j=0; i<inputLength; i++, j++) { |
kvn@6653 | 144 | input[i] = (byte) (j & 0xff); |
kvn@6653 | 145 | } |
kvn@6653 | 146 | |
kvn@4205 | 147 | // do one encode and decode in preparation |
kvn@6653 | 148 | encode = new byte[encodeLength]; |
kvn@6653 | 149 | decode = new byte[decodeLength]; |
kvn@6653 | 150 | if (testingMisalignment) { |
kvn@6653 | 151 | decodeMsgSize = cipher.update(input, encInputOffset, (msgSize - lastChunkSize), encode, encOutputOffset); |
kvn@6653 | 152 | decodeMsgSize += cipher.doFinal(input, (encInputOffset + msgSize - lastChunkSize), lastChunkSize, encode, (encOutputOffset + decodeMsgSize)); |
kvn@6653 | 153 | |
kvn@6653 | 154 | int tempSize = dCipher.update(encode, encOutputOffset, (decodeMsgSize - lastChunkSize), decode, decOutputOffset); |
kvn@6653 | 155 | dCipher.doFinal(encode, (encOutputOffset + decodeMsgSize - lastChunkSize), lastChunkSize, decode, (decOutputOffset + tempSize)); |
kvn@6653 | 156 | } else { |
kvn@6653 | 157 | decodeMsgSize = cipher.doFinal(input, encInputOffset, msgSize, encode, encOutputOffset); |
kvn@6653 | 158 | dCipher.doFinal(encode, encOutputOffset, decodeMsgSize, decode, decOutputOffset); |
kvn@6653 | 159 | } |
kvn@4205 | 160 | if (checkOutput) { |
kvn@4205 | 161 | expectedEncode = (byte[]) encode.clone(); |
kvn@4205 | 162 | expectedDecode = (byte[]) decode.clone(); |
kvn@4205 | 163 | showArray(key.getEncoded() , "key: "); |
kvn@4205 | 164 | showArray(input, "input: "); |
kvn@4205 | 165 | showArray(encode, "encode: "); |
kvn@4205 | 166 | showArray(decode, "decode: "); |
kvn@4205 | 167 | } |
kvn@4205 | 168 | } |
kvn@4205 | 169 | catch (Exception e) { |
kvn@4205 | 170 | e.printStackTrace(); |
kvn@4205 | 171 | System.exit(1); |
kvn@4205 | 172 | } |
kvn@4205 | 173 | } |
kvn@4205 | 174 | |
kvn@4205 | 175 | void showArray(byte b[], String name) { |
kvn@4205 | 176 | System.out.format("%s [%d]: ", name, b.length); |
kvn@4205 | 177 | for (int i=0; i<Math.min(b.length, 32); i++) { |
kvn@4205 | 178 | System.out.format("%02x ", b[i] & 0xff); |
kvn@4205 | 179 | } |
kvn@4205 | 180 | System.out.println(); |
kvn@4205 | 181 | } |
kvn@4205 | 182 | |
kvn@4205 | 183 | void compareArrays(byte b[], byte exp[]) { |
kvn@4205 | 184 | if (b.length != exp.length) { |
kvn@4205 | 185 | System.out.format("different lengths for actual and expected output arrays\n"); |
kvn@4205 | 186 | showArray(b, "test: "); |
kvn@4205 | 187 | showArray(exp, "exp : "); |
kvn@4205 | 188 | System.exit(1); |
kvn@4205 | 189 | } |
kvn@4205 | 190 | for (int i=0; i< exp.length; i++) { |
kvn@4205 | 191 | if (b[i] != exp[i]) { |
kvn@4205 | 192 | System.out.format("output error at index %d: got %02x, expected %02x\n", i, b[i] & 0xff, exp[i] & 0xff); |
kvn@4205 | 193 | showArray(b, "test: "); |
kvn@4205 | 194 | showArray(exp, "exp : "); |
kvn@4205 | 195 | System.exit(1); |
kvn@4205 | 196 | } |
kvn@4205 | 197 | } |
kvn@4205 | 198 | } |
kvn@4205 | 199 | |
kvn@4205 | 200 | |
kvn@4205 | 201 | void showCipher(Cipher c, String kind) { |
kvn@4205 | 202 | System.out.println(kind + " cipher provider: " + cipher.getProvider()); |
kvn@4205 | 203 | System.out.println(kind + " cipher algorithm: " + cipher.getAlgorithm()); |
kvn@4205 | 204 | } |
kvn@4205 | 205 | |
kvn@4205 | 206 | abstract void childShowCipher(); |
ascarpino@9788 | 207 | |
ascarpino@9789 | 208 | void gcm_init(boolean encrypt) throws Exception { |
ascarpino@9788 | 209 | gcm_spec = new GCMParameterSpec(tlen * 8, iv); |
ascarpino@9789 | 210 | if (encrypt) { |
ascarpino@9789 | 211 | // Get a new instance everytime because of reuse IV restrictions |
ascarpino@9789 | 212 | cipher = Cipher.getInstance(algorithm + "/" + mode + "/" + paddingStr, "SunJCE"); |
ascarpino@9789 | 213 | cipher.init(Cipher.ENCRYPT_MODE, key, gcm_spec); |
ascarpino@9789 | 214 | cipher.updateAAD(aad); |
ascarpino@9789 | 215 | } else { |
ascarpino@9789 | 216 | dCipher.init(Cipher.DECRYPT_MODE, key, gcm_spec); |
ascarpino@9789 | 217 | dCipher.updateAAD(aad); |
ascarpino@9789 | 218 | |
ascarpino@9789 | 219 | |
ascarpino@9789 | 220 | } |
ascarpino@9788 | 221 | } |
kvn@4205 | 222 | } |