Skip to content

Commit 6765761

Browse files
committed
8308118: Avoid multiarray allocations in AESCrypt.makeSessionKey
Reviewed-by: xuelei
1 parent 97ade57 commit 6765761

File tree

2 files changed

+95
-55
lines changed

2 files changed

+95
-55
lines changed

src/java.base/share/classes/com/sun/crypto/provider/AESCrypt.java

+31-55
Original file line numberDiff line numberDiff line change
@@ -1061,37 +1061,6 @@ void init(boolean decrypting, String algorithm, byte[] key)
10611061
this.K = sessionK[(decrypting? 1:0)];
10621062
}
10631063

1064-
/**
1065-
* Expand an int[(ROUNDS+1)][4] into int[(ROUNDS+1)*4].
1066-
* For decryption round keys, need to rotate right by 4 ints.
1067-
* @param kr The round keys for encryption or decryption.
1068-
* @param decrypting True if 'kr' is for decryption and false otherwise.
1069-
*/
1070-
private static final int[] expandToSubKey(int[][] kr, boolean decrypting) {
1071-
int total = kr.length;
1072-
int[] expK = new int[total*4];
1073-
if (decrypting) {
1074-
// decrypting, rotate right by 4 ints
1075-
// i.e. i==0
1076-
for(int j=0; j<4; j++) {
1077-
expK[j] = kr[total-1][j];
1078-
}
1079-
for(int i=1; i<total; i++) {
1080-
for(int j=0; j<4; j++) {
1081-
expK[i*4 + j] = kr[i-1][j];
1082-
}
1083-
}
1084-
} else {
1085-
// encrypting, straight expansion
1086-
for(int i=0; i<total; i++) {
1087-
for(int j=0; j<4; j++) {
1088-
expK[i*4 + j] = kr[i][j];
1089-
}
1090-
}
1091-
}
1092-
return expK;
1093-
}
1094-
10951064
// check if the specified length (in bytes) is a valid keysize for AES
10961065
static boolean isKeySizeValid(int len) {
10971066
for (int aesKeysize : AES_KEYSIZES) {
@@ -1361,12 +1330,13 @@ private void makeSessionKey(byte[] k) throws InvalidKeyException {
13611330
k.length + " bytes");
13621331
}
13631332

1333+
final int BC = 4;
1334+
13641335
int ROUNDS = getRounds(k.length);
1365-
int ROUND_KEY_COUNT = (ROUNDS + 1) * 4;
1336+
int ROUND_KEY_COUNT = (ROUNDS + 1) * BC;
13661337

1367-
int BC = 4;
1368-
int[][] Ke = new int[ROUNDS + 1][4]; // encryption round keys
1369-
int[][] Kd = new int[ROUNDS + 1][4]; // decryption round keys
1338+
int[] Ke = new int[ROUND_KEY_COUNT]; // encryption round keys
1339+
int[] Kd = new int[ROUND_KEY_COUNT]; // decryption round keys
13701340

13711341
int KC = k.length/4; // keylen in 32-bit elements
13721342

@@ -1384,8 +1354,8 @@ private void makeSessionKey(byte[] k) throws InvalidKeyException {
13841354
// copy values into round key arrays
13851355
int t = 0;
13861356
for (j = 0; (j < KC) && (t < ROUND_KEY_COUNT); j++, t++) {
1387-
Ke[t / 4][t % 4] = tk[j];
1388-
Kd[ROUNDS - (t / 4)][t % 4] = tk[j];
1357+
Ke[t] = tk[j];
1358+
Kd[(ROUNDS - (t / BC))*BC + (t % BC)] = tk[j];
13891359
}
13901360
int tt, rconpointer = 0;
13911361
while (t < ROUND_KEY_COUNT) {
@@ -1409,32 +1379,35 @@ private void makeSessionKey(byte[] k) throws InvalidKeyException {
14091379
}
14101380
// copy values into round key arrays
14111381
for (j = 0; (j < KC) && (t < ROUND_KEY_COUNT); j++, t++) {
1412-
Ke[t / 4][t % 4] = tk[j];
1413-
Kd[ROUNDS - (t / 4)][t % 4] = tk[j];
1382+
Ke[t] = tk[j];
1383+
Kd[(ROUNDS - (t / BC))*BC + (t % BC)] = tk[j];
14141384
}
14151385
}
14161386
for (int r = 1; r < ROUNDS; r++) {
14171387
// inverse MixColumn where needed
14181388
for (j = 0; j < BC; j++) {
1419-
tt = Kd[r][j];
1420-
Kd[r][j] = U1[(tt >>> 24) & 0xFF] ^
1421-
U2[(tt >>> 16) & 0xFF] ^
1422-
U3[(tt >>> 8) & 0xFF] ^
1423-
U4[ tt & 0xFF];
1389+
int idx = r*BC + j;
1390+
tt = Kd[idx];
1391+
Kd[idx] = U1[(tt >>> 24) & 0xFF] ^
1392+
U2[(tt >>> 16) & 0xFF] ^
1393+
U3[(tt >>> 8) & 0xFF] ^
1394+
U4[ tt & 0xFF];
14241395
}
14251396
}
14261397

1427-
// assemble the encryption (Ke) and decryption (Kd) round keys
1428-
// and expand them into arrays of ints.
1429-
int[] expandedKe = expandToSubKey(Ke, false); // decrypting==false
1430-
int[] expandedKd = expandToSubKey(Kd, true); // decrypting==true
1398+
// For decryption round keys, need to rotate right by 4 ints.
1399+
// Do that without allocating and zeroing the small buffer.
1400+
int KdTail_0 = Kd[Kd.length - 4];
1401+
int KdTail_1 = Kd[Kd.length - 3];
1402+
int KdTail_2 = Kd[Kd.length - 2];
1403+
int KdTail_3 = Kd[Kd.length - 1];
1404+
System.arraycopy(Kd, 0, Kd, 4, Kd.length - 4);
1405+
Kd[0] = KdTail_0;
1406+
Kd[1] = KdTail_1;
1407+
Kd[2] = KdTail_2;
1408+
Kd[3] = KdTail_3;
1409+
14311410
Arrays.fill(tk, 0);
1432-
for (int[] ia: Ke) {
1433-
Arrays.fill(ia, 0);
1434-
}
1435-
for (int[] ia: Kd) {
1436-
Arrays.fill(ia, 0);
1437-
}
14381411
ROUNDS_12 = (ROUNDS>=12);
14391412
ROUNDS_14 = (ROUNDS==14);
14401413
limit = ROUNDS*4;
@@ -1444,8 +1417,11 @@ private void makeSessionKey(byte[] k) throws InvalidKeyException {
14441417
// erase the previous values in sessionK
14451418
Arrays.fill(sessionK[0], 0);
14461419
Arrays.fill(sessionK[1], 0);
1420+
} else {
1421+
sessionK = new int[2][];
14471422
}
1448-
sessionK = new int[][] { expandedKe, expandedKd };
1423+
sessionK[0] = Ke;
1424+
sessionK[1] = Kd;
14491425
}
14501426

14511427
/**
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
package org.openjdk.bench.javax.crypto;
24+
25+
import org.openjdk.jmh.annotations.*;
26+
27+
import javax.crypto.Cipher;
28+
import javax.crypto.spec.GCMParameterSpec;
29+
import javax.crypto.spec.SecretKeySpec;
30+
import java.util.Random;
31+
import java.util.concurrent.TimeUnit;
32+
33+
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
34+
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
35+
@Fork(value = 3, jvmArgsAppend = {"-Xms1g", "-Xmx1g"})
36+
@BenchmarkMode(Mode.AverageTime)
37+
@OutputTimeUnit(TimeUnit.NANOSECONDS)
38+
@State(Scope.Benchmark)
39+
public class AESReinit {
40+
41+
private Cipher cipher;
42+
private Random random;
43+
44+
byte[] key = new byte[16];
45+
byte[] iv = new byte[16];
46+
47+
@Setup
48+
public void prepare() throws Exception {
49+
random = new Random();
50+
cipher = Cipher.getInstance("AES/GCM/NoPadding");
51+
key = new byte[16];
52+
iv = new byte[16];
53+
}
54+
55+
@Benchmark
56+
public void test() throws Exception {
57+
random.nextBytes(key);
58+
random.nextBytes(iv);
59+
SecretKeySpec secretKey = new SecretKeySpec(key, "AES");
60+
GCMParameterSpec param = new GCMParameterSpec(128, iv);
61+
cipher.init(Cipher.ENCRYPT_MODE, secretKey, param);
62+
}
63+
64+
}

0 commit comments

Comments
 (0)