--- a/jdk/src/share/classes/com/sun/crypto/provider/AESCrypt.java Fri Aug 10 12:48:22 2012 -0700
+++ b/jdk/src/share/classes/com/sun/crypto/provider/AESCrypt.java Fri Aug 10 14:00:08 2012 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -37,6 +37,7 @@
package com.sun.crypto.provider;
import java.security.InvalidKeyException;
+import java.util.Arrays;
/**
* Rijndael --pronounced Reindaal-- is a symmetric cipher with a 128-bit
@@ -54,7 +55,12 @@
private Object[] sessionK = null;
private int[] K = null;
- /** (ROUNDS-1) * 4 */
+ /** Cipher encryption/decryption key */
+ // skip re-generating Session and Sub keys if the cipher key is
+ // the same
+ private byte[] lastKey = null;
+
+ /** ROUNDS * 4 */
private int limit = 0;
AESCrypt() {
@@ -82,41 +88,45 @@
key.length + " bytes");
}
- // generate session key and reset sub key.
- sessionK = makeKey(key);
- setSubKey(decrypting);
- }
-
- private void setSubKey(boolean decrypting) {
- int[][] Kd = (int[][]) sessionK[decrypting ? 1 : 0];
- int rounds = Kd.length;
- this.K = new int[rounds*4];
- for(int i=0; i<rounds; i++) {
- for(int j=0; j<4; j++) {
- K[i*4 + j] = Kd[i][j];
- }
+ if (!Arrays.equals(key, lastKey)) {
+ // re-generate session key 'sessionK' when cipher key changes
+ makeSessionKey(key);
+ lastKey = key.clone(); // save cipher key
}
+ // set sub key to the corresponding session Key
+ this.K = (int[]) sessionK[(decrypting? 1:0)];
+ }
+
+ /**
+ * Expand an int[(ROUNDS+1)][4] into int[(ROUNDS+1)*4].
+ * For decryption round keys, need to rotate right by 4 ints.
+ * @param kr The round keys for encryption or decryption.
+ * @param decrypting True if 'kr' is for decryption and false otherwise.
+ */
+ private static final int[] expandToSubKey(int[][] kr, boolean decrypting) {
+ int total = kr.length;
+ int[] expK = new int[total*4];
if (decrypting) {
- int j0 = K[K.length-4];
- int j1 = K[K.length-3];
- int j2 = K[K.length-2];
- int j3 = K[K.length-1];
-
- for (int i=this.K.length-1; i>3; i--) {
- this.K[i] = this.K[i-4];
+ // decrypting, rotate right by 4 ints
+ // i.e. i==0
+ for(int j=0; j<4; j++) {
+ expK[j] = kr[total-1][j];
}
- K[0] = j0;
- K[1] = j1;
- K[2] = j2;
- K[3] = j3;
+ for(int i=1; i<total; i++) {
+ for(int j=0; j<4; j++) {
+ expK[i*4 + j] = kr[i-1][j];
+ }
+ }
+ } else {
+ // encrypting, straight expansion
+ for(int i=0; i<total; i++) {
+ for(int j=0; j<4; j++) {
+ expK[i*4 + j] = kr[i][j];
+ }
+ }
}
-
- ROUNDS_12 = (rounds>=13);
- ROUNDS_14 = (rounds==15);
-
- rounds--;
- limit=rounds*4;
+ return expK;
}
private static int[]
@@ -566,10 +576,10 @@
/**
* Expand a user-supplied key material into a session key.
*
- * @param key The 128/192/256-bit user-key to use.
+ * @param k The 128/192/256-bit cipher key to use.
* @exception InvalidKeyException If the key is invalid.
*/
- private static Object[] makeKey(byte[] k) throws InvalidKeyException {
+ private void makeSessionKey(byte[] k) throws InvalidKeyException {
if (k == null) {
throw new InvalidKeyException("Empty key");
}
@@ -639,10 +649,18 @@
U4[ tt & 0xFF];
}
}
- // assemble the encryption (Ke) and decryption (Kd) round keys into
- // one sessionKey object
- Object[] result = new Object[] {Ke, Kd};
- return result;
+
+ // assemble the encryption (Ke) and decryption (Kd) round keys
+ // and expand them into arrays of ints.
+ int[] expandedKe = expandToSubKey(Ke, false); // decrypting==false
+ int[] expandedKd = expandToSubKey(Kd, true); // decrypting==true
+
+ ROUNDS_12 = (ROUNDS>=12);
+ ROUNDS_14 = (ROUNDS==14);
+ limit = ROUNDS*4;
+
+ // store the expanded sub keys into 'sessionK'
+ sessionK = new Object[] { expandedKe, expandedKd };
}
--- a/jdk/src/share/classes/javax/crypto/CryptoPermissions.java Fri Aug 10 12:48:22 2012 -0700
+++ b/jdk/src/share/classes/javax/crypto/CryptoPermissions.java Fri Aug 10 14:00:08 2012 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -30,10 +30,16 @@
import java.util.Hashtable;
import java.util.Vector;
import java.util.NoSuchElementException;
+import java.util.concurrent.ConcurrentHashMap;
import java.io.Serializable;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;
+import java.io.ObjectStreamField;
+import java.io.ObjectInputStream;
+import java.io.ObjectInputStream.GetField;
+import java.io.ObjectOutputStream;
+import java.io.ObjectOutputStream.PutField;
import java.io.IOException;
/**
@@ -61,15 +67,24 @@
private static final long serialVersionUID = 4946547168093391015L;
- // This class is similar to java.security.Permissions
- private Hashtable<String, PermissionCollection> perms;
+ /**
+ * @serialField perms java.util.Hashtable
+ */
+ private static final ObjectStreamField[] serialPersistentFields = {
+ new ObjectStreamField("perms", Hashtable.class),
+ };
+
+ // Switched from Hashtable to ConcurrentHashMap to improve scalability.
+ // To maintain serialization compatibility, this field is made transient
+ // and custom readObject/writeObject methods are used.
+ private transient ConcurrentHashMap<String,PermissionCollection> perms;
/**
* Creates a new CryptoPermissions object containing
* no CryptoPermissionCollections.
*/
CryptoPermissions() {
- perms = new Hashtable<String, PermissionCollection>(7);
+ perms = new ConcurrentHashMap<>(7);
}
/**
@@ -132,9 +147,7 @@
getPermissionCollection(cryptoPerm);
pc.add(cryptoPerm);
String alg = cryptoPerm.getAlgorithm();
- if (!perms.containsKey(alg)) {
- perms.put(alg, pc);
- }
+ perms.putIfAbsent(alg, pc);
}
/**
@@ -377,18 +390,17 @@
PermissionCollection getPermissionCollection(String alg) {
// If this CryptoPermissions includes CryptoAllPermission,
// we should return CryptoAllPermission.
- if (perms.containsKey(CryptoAllPermission.ALG_NAME)) {
- return perms.get(CryptoAllPermission.ALG_NAME);
- }
-
- PermissionCollection pc = perms.get(alg);
+ PermissionCollection pc = perms.get(CryptoAllPermission.ALG_NAME);
+ if (pc == null) {
+ pc = perms.get(alg);
- // If there isn't a PermissionCollection for
- // the given algorithm,we should return the
- // PermissionCollection for the wildcard
- // if there is one.
- if (pc == null) {
- pc = perms.get(CryptoPermission.ALG_NAME_WILDCARD);
+ // If there isn't a PermissionCollection for
+ // the given algorithm,we should return the
+ // PermissionCollection for the wildcard
+ // if there is one.
+ if (pc == null) {
+ pc = perms.get(CryptoPermission.ALG_NAME_WILDCARD);
+ }
}
return pc;
}
@@ -414,6 +426,28 @@
}
return pc;
}
+
+ private void readObject(ObjectInputStream s)
+ throws IOException, ClassNotFoundException {
+ ObjectInputStream.GetField fields = s.readFields();
+ @SuppressWarnings("unchecked")
+ Hashtable<String,PermissionCollection> permTable =
+ (Hashtable<String,PermissionCollection>)
+ (fields.get("perms", null));
+ if (permTable != null) {
+ perms = new ConcurrentHashMap<>(permTable);
+ } else {
+ perms = new ConcurrentHashMap<>();
+ }
+ }
+
+ private void writeObject(ObjectOutputStream s) throws IOException {
+ Hashtable<String,PermissionCollection> permTable =
+ new Hashtable<>(perms);
+ ObjectOutputStream.PutField fields = s.putFields();
+ fields.put("perms", permTable);
+ s.writeFields();
+ }
}
final class PermissionsEnumerator implements Enumeration<Permission> {
@@ -456,7 +490,6 @@
} else {
throw new NoSuchElementException("PermissionsEnumerator");
}
-
}
private Enumeration<Permission> getNextEnumWithMore() {
--- a/jdk/src/share/classes/javax/crypto/JceSecurityManager.java Fri Aug 10 12:48:22 2012 -0700
+++ b/jdk/src/share/classes/javax/crypto/JceSecurityManager.java Fri Aug 10 14:00:08 2012 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -28,6 +28,8 @@
import java.security.*;
import java.net.*;
import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
/**
* The JCE security manager.
@@ -51,8 +53,10 @@
private static final CryptoAllPermission allPerm;
private static final Vector<Class<?>> TrustedCallersCache =
new Vector<>(2);
- private static final Map<URL, CryptoPermissions> exemptCache =
- new HashMap<>();
+ private static final ConcurrentMap<URL,CryptoPermissions> exemptCache =
+ new ConcurrentHashMap<>();
+ private static final CryptoPermissions CACHE_NULL_MARK =
+ new CryptoPermissions();
// singleton instance
static final JceSecurityManager INSTANCE;
@@ -117,17 +121,19 @@
return defaultPerm;
}
- CryptoPermissions appPerms;
- synchronized (this.getClass()) {
- if (exemptCache.containsKey(callerCodeBase)) {
+ CryptoPermissions appPerms = exemptCache.get(callerCodeBase);
+ if (appPerms == null) {
+ // no match found in cache
+ synchronized (this.getClass()) {
appPerms = exemptCache.get(callerCodeBase);
- } else {
- appPerms = getAppPermissions(callerCodeBase);
- exemptCache.put(callerCodeBase, appPerms);
+ if (appPerms == null) {
+ appPerms = getAppPermissions(callerCodeBase);
+ exemptCache.putIfAbsent(callerCodeBase,
+ (appPerms == null? CACHE_NULL_MARK:appPerms));
+ }
}
}
-
- if (appPerms == null) {
+ if (appPerms == null || appPerms == CACHE_NULL_MARK) {
return defaultPerm;
}