From 21f7aaed7416729c12a58777c75b886ed40be8ef Mon Sep 17 00:00:00 2001 From: Valerie Peng Date: Fri, 10 Aug 2012 13:08:23 -0700 Subject: [PATCH 1/3] 7107613: scalability bloker in javax.crypto.CryptoPermissions Changed the type of field "perms" from Hashtable to ConcurrentHashMap. Reviewed-by: weijun, xuelei --- .../javax/crypto/CryptoPermissions.java | 71 ++++++++++++++----- 1 file changed, 52 insertions(+), 19 deletions(-) diff --git a/jdk/src/share/classes/javax/crypto/CryptoPermissions.java b/jdk/src/share/classes/javax/crypto/CryptoPermissions.java index 50c76b95fc6..d2edf8e0985 100644 --- a/jdk/src/share/classes/javax/crypto/CryptoPermissions.java +++ b/jdk/src/share/classes/javax/crypto/CryptoPermissions.java @@ -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.Enumeration; 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 @@ implements Serializable { private static final long serialVersionUID = 4946547168093391015L; - // This class is similar to java.security.Permissions - private Hashtable 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 perms; /** * Creates a new CryptoPermissions object containing * no CryptoPermissionCollections. */ CryptoPermissions() { - perms = new Hashtable(7); + perms = new ConcurrentHashMap<>(7); } /** @@ -132,9 +147,7 @@ implements Serializable { 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 @@ implements Serializable { 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); - - // If there isn't a PermissionCollection for - // the given algorithm,we should return the - // PermissionCollection for the wildcard - // if there is one. + PermissionCollection pc = perms.get(CryptoAllPermission.ALG_NAME); if (pc == null) { - pc = perms.get(CryptoPermission.ALG_NAME_WILDCARD); + 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); + } } return pc; } @@ -414,6 +426,28 @@ implements Serializable { } return pc; } + + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException { + ObjectInputStream.GetField fields = s.readFields(); + @SuppressWarnings("unchecked") + Hashtable permTable = + (Hashtable) + (fields.get("perms", null)); + if (permTable != null) { + perms = new ConcurrentHashMap<>(permTable); + } else { + perms = new ConcurrentHashMap<>(); + } + } + + private void writeObject(ObjectOutputStream s) throws IOException { + Hashtable permTable = + new Hashtable<>(perms); + ObjectOutputStream.PutField fields = s.putFields(); + fields.put("perms", permTable); + s.writeFields(); + } } final class PermissionsEnumerator implements Enumeration { @@ -456,7 +490,6 @@ final class PermissionsEnumerator implements Enumeration { } else { throw new NoSuchElementException("PermissionsEnumerator"); } - } private Enumeration getNextEnumWithMore() { From 919dca60245abae8474861f0223ac3d72c219590 Mon Sep 17 00:00:00 2001 From: Valerie Peng Date: Fri, 10 Aug 2012 13:08:59 -0700 Subject: [PATCH 2/3] 7107616: scalability bloker in javax.crypto.JceSecurityManager Changed the type of field "exemptCache" from HashMap to ConcurrentHashMap. Reviewed-by: weijun, xuelei --- .../javax/crypto/JceSecurityManager.java | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/jdk/src/share/classes/javax/crypto/JceSecurityManager.java b/jdk/src/share/classes/javax/crypto/JceSecurityManager.java index c05a200806c..d4818acc897 100644 --- a/jdk/src/share/classes/javax/crypto/JceSecurityManager.java +++ b/jdk/src/share/classes/javax/crypto/JceSecurityManager.java @@ -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 @@ package javax.crypto; 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 @@ final class JceSecurityManager extends SecurityManager { private static final CryptoAllPermission allPerm; private static final Vector> TrustedCallersCache = new Vector<>(2); - private static final Map exemptCache = - new HashMap<>(); + private static final ConcurrentMap exemptCache = + new ConcurrentHashMap<>(); + private static final CryptoPermissions CACHE_NULL_MARK = + new CryptoPermissions(); // singleton instance static final JceSecurityManager INSTANCE; @@ -117,17 +121,19 @@ final class JceSecurityManager extends SecurityManager { 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; } From a44a57d7b6732e6a92526102b0d2abc608f68a1a Mon Sep 17 00:00:00 2001 From: Valerie Peng Date: Fri, 10 Aug 2012 13:10:35 -0700 Subject: [PATCH 3/3] 7185471: Avoid key expansion when AES cipher is re-init w/ the same key Saved the last cipher key value and skip key expansion if key value is the same. Reviewed-by: weijun, xuelei --- .../com/sun/crypto/provider/AESCrypt.java | 94 +++++++++++-------- 1 file changed, 56 insertions(+), 38 deletions(-) diff --git a/jdk/src/share/classes/com/sun/crypto/provider/AESCrypt.java b/jdk/src/share/classes/com/sun/crypto/provider/AESCrypt.java index 6f46e158875..02cc426e34b 100644 --- a/jdk/src/share/classes/com/sun/crypto/provider/AESCrypt.java +++ b/jdk/src/share/classes/com/sun/crypto/provider/AESCrypt.java @@ -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 @@ final class AESCrypt extends SymmetricCipher implements AESConstants 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 @@ final class AESCrypt extends SymmetricCipher implements AESConstants key.length + " bytes"); } - // generate session key and reset sub key. - sessionK = makeKey(key); - setSubKey(decrypting); + 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)]; } - 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; i3; 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]; + } + for(int i=1; i=13); - ROUNDS_14 = (rounds==15); - - rounds--; - limit=rounds*4; + return expK; } private static int[] @@ -566,10 +576,10 @@ final class AESCrypt extends SymmetricCipher implements AESConstants /** * 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 @@ final class AESCrypt extends SymmetricCipher implements AESConstants 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 }; }