From f85705002ec44bc67ce0dcbbc9b50763e8dd1a74 Mon Sep 17 00:00:00 2001
From: Mandy Chung
Date: Fri, 28 Dec 2012 22:21:40 -0800
Subject: [PATCH 01/28] 8003562: Provide a CLI tool to analyze class
dependencies
Reviewed-by: jjg, alanb, ulfzibis, erikj
---
jdk/make/common/Release.gmk | 3 +++
jdk/make/docs/NON_CORE_PKGS.gmk | 2 +-
jdk/make/launchers/Makefile | 1 +
jdk/make/launchers/Makefile.launcher | 4 ++++
jdk/makefiles/CompileLaunchers.gmk | 5 +++++
jdk/makefiles/CreateJars.gmk | 1 +
jdk/makefiles/Images.gmk | 1 +
7 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/jdk/make/common/Release.gmk b/jdk/make/common/Release.gmk
index dc43ecf95ea..367eab8fa7e 100644
--- a/jdk/make/common/Release.gmk
+++ b/jdk/make/common/Release.gmk
@@ -375,6 +375,7 @@ TOOLS = \
com/sun/tools/javadoc \
com/sun/tools/javah \
com/sun/tools/javap \
+ com/sun/tools/jdeps \
com/sun/tools/corba \
com/sun/tools/internal/xjc \
com/sun/tools/internal/ws \
@@ -457,6 +458,7 @@ NOTJRETOOLS = \
javadoc$(EXE_SUFFIX) \
javah$(EXE_SUFFIX) \
javap$(EXE_SUFFIX) \
+ jdeps$(EXE_SUFFIX) \
jcmd$(EXE_SUFFIX) \
jdb$(EXE_SUFFIX) \
jps$(EXE_SUFFIX) \
@@ -564,6 +566,7 @@ $(NOT_RT_JAR_LIST): FRC
$(ECHO) "sun/tools/javac/" >> $@
$(ECHO) "com/sun/tools/classfile/" >> $@
$(ECHO) "com/sun/tools/javap/" >> $@
+ $(ECHO) "com/sun/tools/jdeps/" >> $@
$(ECHO) "sun/tools/jcmd/" >> $@
$(ECHO) "sun/tools/jconsole/" >> $@
$(ECHO) "sun/tools/jps/" >> $@
diff --git a/jdk/make/docs/NON_CORE_PKGS.gmk b/jdk/make/docs/NON_CORE_PKGS.gmk
index b299938e844..949637cfeda 100644
--- a/jdk/make/docs/NON_CORE_PKGS.gmk
+++ b/jdk/make/docs/NON_CORE_PKGS.gmk
@@ -76,7 +76,7 @@ ATTACH_PKGS = com.sun.tools.attach \
JCONSOLE_PKGS = com.sun.tools.jconsole
-TREEAPI_PKGS = com.sunsource.doctree \
+TREEAPI_PKGS = com.sun.source.doctree \
com.sun.source.tree \
com.sun.source.util
diff --git a/jdk/make/launchers/Makefile b/jdk/make/launchers/Makefile
index 3d9511408b0..be16512e478 100644
--- a/jdk/make/launchers/Makefile
+++ b/jdk/make/launchers/Makefile
@@ -63,6 +63,7 @@ $(call make-launcher, javac, com.sun.tools.javac.Main, , )
$(call make-launcher, javadoc, com.sun.tools.javadoc.Main, , )
$(call make-launcher, javah, com.sun.tools.javah.Main, , )
$(call make-launcher, javap, com.sun.tools.javap.Main, , )
+$(call make-launcher, jdeps, com.sun.tools.jdeps.Main, , )
$(call make-launcher, jcmd, sun.tools.jcmd.JCmd, , )
$(call make-launcher, jconsole, sun.tools.jconsole.JConsole, \
-J-Djconsole.showOutputViewer, )
diff --git a/jdk/make/launchers/Makefile.launcher b/jdk/make/launchers/Makefile.launcher
index 1b3e51b6de8..bb06f80f7cc 100644
--- a/jdk/make/launchers/Makefile.launcher
+++ b/jdk/make/launchers/Makefile.launcher
@@ -62,6 +62,10 @@ ifeq ($(PROGRAM),javap)
WILDCARDS=true
NEVER_ACT_AS_SERVER_CLASS_MACHINE=true
endif
+ifeq ($(PROGRAM),jdeps)
+ WILDCARDS=true
+ NEVER_ACT_AS_SERVER_CLASS_MACHINE=true
+endif
ifeq ($(PROGRAM),javah)
WILDCARDS=true
NEVER_ACT_AS_SERVER_CLASS_MACHINE=true
diff --git a/jdk/makefiles/CompileLaunchers.gmk b/jdk/makefiles/CompileLaunchers.gmk
index 102a2e7831f..f97578aa087 100644
--- a/jdk/makefiles/CompileLaunchers.gmk
+++ b/jdk/makefiles/CompileLaunchers.gmk
@@ -267,6 +267,11 @@ $(eval $(call SetupLauncher,javap,\
-DNEVER_ACT_AS_SERVER_CLASS_MACHINE \
-DJAVA_ARGS='{ "-J-ms8m"$(COMMA) "com.sun.tools.javap.Main"$(COMMA) }'))
+$(eval $(call SetupLauncher,jdeps,\
+ -DEXPAND_CLASSPATH_WILDCARDS \
+ -DNEVER_ACT_AS_SERVER_CLASS_MACHINE \
+ -DJAVA_ARGS='{ "-J-ms8m"$(COMMA) "com.sun.tools.jdeps.Main"$(COMMA) }'))
+
BUILD_LAUNCHER_jconsole_CFLAGS_windows:=-DJAVAW
BUILD_LAUNCHER_jconsole_LDFLAGS_windows:=user32.lib
diff --git a/jdk/makefiles/CreateJars.gmk b/jdk/makefiles/CreateJars.gmk
index 748aac94a2d..77269bd2b90 100644
--- a/jdk/makefiles/CreateJars.gmk
+++ b/jdk/makefiles/CreateJars.gmk
@@ -738,6 +738,7 @@ TOOLS_JAR_INCLUDES := \
com/sun/tools/javadoc \
com/sun/tools/javah \
com/sun/tools/javap \
+ com/sun/tools/jdeps \
com/sun/tools/corba \
com/sun/tools/internal/xjc \
com/sun/tools/internal/ws \
diff --git a/jdk/makefiles/Images.gmk b/jdk/makefiles/Images.gmk
index 5a85e6c37f3..8d8368dbf08 100644
--- a/jdk/makefiles/Images.gmk
+++ b/jdk/makefiles/Images.gmk
@@ -100,6 +100,7 @@ NOT_JRE_BIN_FILES := \
javadoc$(EXE_SUFFIX) \
javah$(EXE_SUFFIX) \
javap$(EXE_SUFFIX) \
+ jdeps$(EXE_SUFFIX) \
jcmd$(EXE_SUFFIX) \
jdb$(EXE_SUFFIX) \
jps$(EXE_SUFFIX) \
From c2f4000a6f8f276ce45496d7237b098a9d364861 Mon Sep 17 00:00:00 2001
From: Chris Hegarty
Date: Sat, 29 Dec 2012 11:00:15 +0000
Subject: [PATCH 02/28] 8005556: java/net/Socks/SocksV4Test.java is missing
@run tag
Reviewed-by: alanb
---
jdk/test/java/net/Socks/SocksV4Test.java | 1 +
1 file changed, 1 insertion(+)
diff --git a/jdk/test/java/net/Socks/SocksV4Test.java b/jdk/test/java/net/Socks/SocksV4Test.java
index b61d658a78a..cc0452e5ea4 100644
--- a/jdk/test/java/net/Socks/SocksV4Test.java
+++ b/jdk/test/java/net/Socks/SocksV4Test.java
@@ -26,6 +26,7 @@
* @bug 4727547
* @summary SocksSocketImpl throws NullPointerException
* @build SocksServer
+ * @run main SocksV4Test
*/
import java.net.*;
From 2fc01efdd8af2fd8aa85c18ca6c4c6b596addb77 Mon Sep 17 00:00:00 2001
From: Jim Gish
Date: Fri, 28 Dec 2012 16:56:54 -0500
Subject: [PATCH 03/28] 8005118: Javadoc styles are inconsistent
Use a common javadoc style in the String classes
Reviewed-by: darcy
---
.../java/lang/AbstractStringBuilder.java | 10 +-
jdk/src/share/classes/java/lang/String.java | 170 +++++++++---------
.../share/classes/java/lang/StringBuffer.java | 22 +--
.../classes/java/lang/StringBuilder.java | 76 ++++----
.../lang/StringIndexOutOfBoundsException.java | 10 +-
5 files changed, 147 insertions(+), 141 deletions(-)
diff --git a/jdk/src/share/classes/java/lang/AbstractStringBuilder.java b/jdk/src/share/classes/java/lang/AbstractStringBuilder.java
index fc513f55efe..03999c445a5 100644
--- a/jdk/src/share/classes/java/lang/AbstractStringBuilder.java
+++ b/jdk/src/share/classes/java/lang/AbstractStringBuilder.java
@@ -860,9 +860,9 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
* @return the specified subsequence.
*
* @throws IndexOutOfBoundsException
- * if start or end are negative,
- * if end is greater than length(),
- * or if start is greater than end
+ * if {@code start} or {@code end} are negative,
+ * if {@code end} is greater than {@code length()},
+ * or if {@code start} is greater than {@code end}
* @spec JSR-51
*/
@Override
@@ -1292,7 +1292,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
/**
* Returns the index within this string of the first occurrence of the
* specified substring, starting at the specified index. The integer
- * returned is the smallest value k for which:
+ * returned is the smallest value {@code k} for which:
*
* k >= Math.min(fromIndex, str.length()) &&
* this.toString().startsWith(str, k)
@@ -1418,7 +1418,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
public abstract String toString();
/**
- * Needed by String for the contentEquals method.
+ * Needed by {@code String} for the contentEquals method.
*/
final char[] getValue() {
return value;
diff --git a/jdk/src/share/classes/java/lang/String.java b/jdk/src/share/classes/java/lang/String.java
index d73a2f7c2e9..a9bc2f37648 100644
--- a/jdk/src/share/classes/java/lang/String.java
+++ b/jdk/src/share/classes/java/lang/String.java
@@ -615,10 +615,10 @@ public final class String
}
/**
- * Returns true if, and only if, {@link #length()} is 0.
+ * Returns {@code true} if, and only if, {@link #length()} is {@code 0}.
*
- * @return true if {@link #length()} is 0, otherwise
- * false
+ * @return {@code true} if {@link #length()} is {@code 0}, otherwise
+ * {@code false}
*
* @since 1.6
*/
@@ -1229,23 +1229,23 @@ public final class String
/**
* Tests if two string regions are equal.
*
- * A substring of this String object is compared to a substring
+ * A substring of this {@code String} object is compared to a substring
* of the argument other. The result is true if these substrings
* represent identical character sequences. The substring of this
- * String object to be compared begins at index toffset
- * and has length len. The substring of other to be compared
- * begins at index ooffset and has length len. The
- * result is false if and only if at least one of the following
+ * {@code String} object to be compared begins at index {@code toffset}
+ * and has length {@code len}. The substring of other to be compared
+ * begins at index {@code ooffset} and has length {@code len}. The
+ * result is {@code false} if and only if at least one of the following
* is true:
- *
toffset is negative.
- *
ooffset is negative.
- *
toffset+len is greater than the length of this
- * String object.
- *
ooffset+len is greater than the length of the other
+ *
{@code toffset} is negative.
+ *
{@code ooffset} is negative.
+ *
{@code toffset+len} is greater than the length of this
+ * {@code String} object.
+ *
{@code ooffset+len} is greater than the length of the other
* argument.
- *
There is some nonnegative integer k less than len
+ *
There is some nonnegative integer k less than {@code len}
* such that:
- * this.charAt(toffset+k) != other.charAt(ooffset+k)
+ * this.charAt(toffset+k) != other.charAt(ooffset+k)
*
*
* @param toffset the starting offset of the subregion in this string.
@@ -1280,28 +1280,28 @@ public final class String
/**
* Tests if two string regions are equal.
*
- * A substring of this String object is compared to a substring
- * of the argument other. The result is true if these
+ * A substring of this {@code String} object is compared to a substring
+ * of the argument {@code other}. The result is {@code true} if these
* substrings represent character sequences that are the same, ignoring
- * case if and only if ignoreCase is true. The substring of
- * this String object to be compared begins at index
- * toffset and has length len. The substring of
- * other to be compared begins at index ooffset and
- * has length len. The result is false if and only if
+ * case if and only if {@code ignoreCase} is true. The substring of
+ * this {@code String} object to be compared begins at index
+ * {@code toffset} and has length {@code len}. The substring of
+ * {@code other} to be compared begins at index {@code ooffset} and
+ * has length {@code len}. The result is {@code false} if and only if
* at least one of the following is true:
- *
toffset is negative.
- *
ooffset is negative.
- *
toffset+len is greater than the length of this
- * String object.
- *
ooffset+len is greater than the length of the other
+ *
{@code toffset} is negative.
+ *
{@code ooffset} is negative.
+ *
{@code toffset+len} is greater than the length of this
+ * {@code String} object.
+ *
{@code ooffset+len} is greater than the length of the other
* argument.
- *
ignoreCase is false and there is some nonnegative
- * integer k less than len such that:
+ *
{@code ignoreCase} is {@code false} and there is some nonnegative
+ * integer k less than {@code len} such that:
*
ignoreCase is true and there is some nonnegative
- * integer k less than len such that:
+ *
{@code ignoreCase} is {@code true} and there is some nonnegative
+ * integer k less than {@code len} such that:
*
* Character.toLowerCase(this.charAt(toffset+k)) !=
Character.toLowerCase(other.charAt(ooffset+k))
@@ -1500,12 +1500,12 @@ public final class String
* of {@code ch} in the range from 0 to 0xFFFF (inclusive),
* this is the smallest value k such that:
*
* is true. In either case, if no such character occurs in this
* string at or after position {@code fromIndex}, then
@@ -1604,12 +1604,12 @@ public final class String
* from 0 to 0xFFFF (inclusive), the index returned is the largest
* value k such that:
*
* is true. In either case, if no such character occurs in this
* string at or before position {@code fromIndex}, then
@@ -1690,7 +1690,7 @@ public final class String
*
*
The returned index is the smallest value k for which:
*
- * k >= fromIndex && this.startsWith(str, k)
+ * k >= fromIndex {@code &&} this.startsWith(str, k)
*
* If no such value of k exists, then {@code -1} is returned.
*
@@ -1799,7 +1799,7 @@ public final class String
*
*
The returned index is the largest value k for which:
*
- * k <= fromIndex && this.startsWith(str, k)
+ * k {@code <=} fromIndex {@code &&} this.startsWith(str, k)
*
* If no such value of k exists, then {@code -1} is returned.
*
@@ -2080,17 +2080,18 @@ public final class String
* href="../util/regex/Pattern.html#sum">regular expression.
*
*
An invocation of this method of the form
- * str.matches(regex) yields exactly the
+ * str{@code .matches(}regex{@code )} yields exactly the
* same result as the expression
*
- *
*
* @param regex
* the regular expression to which this string is to be matched
*
- * @return true if, and only if, this string matches the
+ * @return {@code true} if, and only if, this string matches the
* given regular expression
*
* @throws PatternSyntaxException
@@ -2124,18 +2125,20 @@ public final class String
* given replacement.
*
*
An invocation of this method of the form
- * str.replaceFirst(regex,repl)
+ * str{@code .replaceFirst(}regex{@code ,} repl{@code )}
* yields exactly the same result as the expression
*
- *
- * Note that backslashes (\) and dollar signs ($) in the
+ * Note that backslashes ({@code \}) and dollar signs ({@code $}) in the
* replacement string may cause the results to be different than if it were
* being treated as a literal replacement string; see
* {@link java.util.regex.Matcher#replaceFirst}.
@@ -2147,7 +2150,7 @@ public final class String
* @param replacement
* the string to be substituted for the first match
*
- * @return The resulting String
+ * @return The resulting {@code String}
*
* @throws PatternSyntaxException
* if the regular expression's syntax is invalid
@@ -2167,18 +2170,20 @@ public final class String
* given replacement.
*
*
An invocation of this method of the form
- * str.replaceAll(regex,repl)
+ * str{@code .replaceAll(}regex{@code ,} repl{@code )}
* yields exactly the same result as the expression
*
- *
- * Note that backslashes (\) and dollar signs ($) in the
+ * Note that backslashes ({@code \}) and dollar signs ({@code $}) in the
* replacement string may cause the results to be different than if it were
* being treated as a literal replacement string; see
* {@link java.util.regex.Matcher#replaceAll Matcher.replaceAll}.
@@ -2190,7 +2195,7 @@ public final class String
* @param replacement
* the string to be substituted for each match
*
- * @return The resulting String
+ * @return The resulting {@code String}
*
* @throws PatternSyntaxException
* if the regular expression's syntax is invalid
@@ -2234,7 +2239,7 @@ public final class String
* expression does not match any part of the input then the resulting array
* has just one element, namely this string.
*
- *
The limit parameter controls the number of times the
+ *
The {@code limit} parameter controls the number of times the
* pattern is applied and therefore affects the length of the resulting
* array. If the limit n is greater than zero then the pattern
* will be applied at most n - 1 times, the array's
@@ -2245,7 +2250,7 @@ public final class String
* the pattern will be applied as many times as possible, the array can
* have any length, and trailing empty strings will be discarded.
*
- *
The string "boo:and:foo", for example, yields the
+ *
The string {@code "boo:and:foo"}, for example, yields the
* following results with these parameters:
*
*
@@ -2256,33 +2261,34 @@ public final class String
*
*
:
*
2
- *
{ "boo", "and:foo" }
+ *
{@code { "boo", "and:foo" }}
*
:
*
5
- *
{ "boo", "and", "foo" }
+ *
{@code { "boo", "and", "foo" }}
*
:
*
-2
- *
{ "boo", "and", "foo" }
+ *
{@code { "boo", "and", "foo" }}
*
o
*
5
- *
{ "b", "", ":and:f", "", "" }
+ *
{@code { "b", "", ":and:f", "", "" }}
*
o
*
-2
- *
{ "b", "", ":and:f", "", "" }
+ *
{@code { "b", "", ":and:f", "", "" }}
*
o
*
0
- *
{ "b", "", ":and:f" }
+ *
{@code { "b", "", ":and:f" }}
*
*
*
An invocation of this method of the form
- * str.split(regex,n)
+ * str.{@code split(}regex{@code ,} n{@code )}
* yields the same result as the expression
*
*
*
*
@@ -2364,7 +2370,7 @@ public final class String
* argument of zero. Trailing empty strings are therefore not included in
* the resulting array.
*
- *
The string "boo:and:foo", for example, yields the following
+ *
The string {@code "boo:and:foo"}, for example, yields the following
* results with these expressions:
*
*
@@ -2373,9 +2379,9 @@ public final class String
*
Result
*
*
:
- *
{ "boo", "and", "foo" }
+ *
{@code { "boo", "and", "foo" }}
*
o
- *
{ "b", "", ":and:f" }
+ *
{@code { "b", "", ":and:f" }}
*
*
*
@@ -2815,7 +2821,7 @@ public final class String
* limited by the maximum dimension of a Java array as defined by
* The Java™ Virtual Machine Specification.
* The behaviour on a
- * null argument depends on the conversion.
*
* @throws java.util.IllegalFormatException
@@ -2828,7 +2834,7 @@ public final class String
* formatter class specification.
*
* @throws NullPointerException
- * If the format is null
+ * If the {@code format} is {@code null}
*
* @return A formatted string
*
@@ -2845,7 +2851,7 @@ public final class String
*
* @param l
* The {@linkplain java.util.Locale locale} to apply during
- * formatting. If l is null then no localization
+ * formatting. If {@code l} is {@code null} then no localization
* is applied.
*
* @param format
@@ -2859,7 +2865,7 @@ public final class String
* limited by the maximum dimension of a Java array as defined by
* The Java™ Virtual Machine Specification.
* The behaviour on a
- * null argument depends on the conversion.
*
* @throws java.util.IllegalFormatException
@@ -2872,7 +2878,7 @@ public final class String
* formatter class specification
*
* @throws NullPointerException
- * If the format is null
+ * If the {@code format} is {@code null}
*
* @return A formatted string
*
@@ -3143,7 +3149,7 @@ public final class String
* programmer should be aware that producing distinct integer results
* for unequal objects may improve the performance of hash tables.
*
- *
+ *
* The hash value will never be zero.
*
* @return a hash code value for this object.
diff --git a/jdk/src/share/classes/java/lang/StringBuffer.java b/jdk/src/share/classes/java/lang/StringBuffer.java
index 9fabad48d68..5d7754a0cc7 100644
--- a/jdk/src/share/classes/java/lang/StringBuffer.java
+++ b/jdk/src/share/classes/java/lang/StringBuffer.java
@@ -57,7 +57,7 @@ package java.lang;
*
* In general, if sb refers to an instance of a {@code StringBuffer},
* then {@code sb.append(x)} has the same effect as
- * {@code sb.insert(sb.length(), x)}.
+ * {@code sb.insert(sb.length(), x)}.
*
* Whenever an operation occurs involving a source sequence (such as
* appending or inserting from a source sequence), this class synchronizes
@@ -80,7 +80,7 @@ package java.lang;
*
* As of release JDK 5, this class has been supplemented with an equivalent
* class designed for use by a single thread, {@link StringBuilder}. The
- * StringBuilder class should generally be used in preference to
+ * {@code StringBuilder} class should generally be used in preference to
* this one, as it supports all of the same operations but it is faster, as
* it performs no synchronization.
*
@@ -262,17 +262,17 @@ package java.lang;
}
/**
- * Appends the specified StringBuffer to this sequence.
+ * Appends the specified {@code StringBuffer} to this sequence.
*
- * The characters of the StringBuffer argument are appended,
- * in order, to the contents of this StringBuffer, increasing the
- * length of this StringBuffer by the length of the argument.
- * If sb is null, then the four characters
- * "null" are appended to this StringBuffer.
+ * The characters of the {@code StringBuffer} argument are appended,
+ * in order, to the contents of this {@code StringBuffer}, increasing the
+ * length of this {@code StringBuffer} by the length of the argument.
+ * If {@code sb} is {@code null}, then the four characters
+ * {@code "null"} are appended to this {@code StringBuffer}.
*
* Let n be the length of the old character sequence, the one
- * contained in the StringBuffer just prior to execution of the
- * append method. Then the character at index k in
+ * contained in the {@code StringBuffer} just prior to execution of the
+ * {@code append} method. Then the character at index k in
* the new character sequence is equal to the character at index k
* in the old character sequence, if k is less than n;
* otherwise, it is equal to the character at index k-n in the
@@ -281,7 +281,7 @@ package java.lang;
* This method synchronizes on {@code this}, the destination
* object, but does not synchronize on the source ({@code sb}).
*
- * @param sb the StringBuffer to append.
+ * @param sb the {@code StringBuffer} to append.
* @return a reference to this object.
* @since 1.4
*/
diff --git a/jdk/src/share/classes/java/lang/StringBuilder.java b/jdk/src/share/classes/java/lang/StringBuilder.java
index acddd83a8a3..e9defe23f6f 100644
--- a/jdk/src/share/classes/java/lang/StringBuilder.java
+++ b/jdk/src/share/classes/java/lang/StringBuilder.java
@@ -28,39 +28,39 @@ package java.lang;
/**
* A mutable sequence of characters. This class provides an API compatible
- * with StringBuffer, but with no guarantee of synchronization.
+ * with {@code StringBuffer}, but with no guarantee of synchronization.
* This class is designed for use as a drop-in replacement for
- * StringBuffer in places where the string buffer was being
+ * {@code StringBuffer} in places where the string buffer was being
* used by a single thread (as is generally the case). Where possible,
* it is recommended that this class be used in preference to
- * StringBuffer as it will be faster under most implementations.
+ * {@code StringBuffer} as it will be faster under most implementations.
*
- *
The principal operations on a StringBuilder are the
- * append and insert methods, which are
+ *
The principal operations on a {@code StringBuilder} are the
+ * {@code append} and {@code insert} methods, which are
* overloaded so as to accept data of any type. Each effectively
* converts a given datum to a string and then appends or inserts the
* characters of that string to the string builder. The
- * append method always adds these characters at the end
- * of the builder; the insert method adds the characters at
+ * {@code append} method always adds these characters at the end
+ * of the builder; the {@code insert} method adds the characters at
* a specified point.
*
- * For example, if z refers to a string builder object
- * whose current contents are "start", then
- * the method call z.append("le") would cause the string
- * builder to contain "startle", whereas
- * z.insert(4, "le") would alter the string builder to
- * contain "starlet".
+ * For example, if {@code z} refers to a string builder object
+ * whose current contents are "{@code start}", then
+ * the method call {@code z.append("le")} would cause the string
+ * builder to contain "{@code startle}", whereas
+ * {@code z.insert(4, "le")} would alter the string builder to
+ * contain "{@code starlet}".
+ *
+ * In general, if sb refers to an instance of a {@code StringBuilder},
+ * then {@code sb.append(x)} has the same effect as
+ * {@code sb.insert(sb.length(), x)}.
*
- * In general, if sb refers to an instance of a StringBuilder,
- * then sb.append(x) has the same effect as
- * sb.insert(sb.length(), x).
- *
* Every string builder has a capacity. As long as the length of the
* character sequence contained in the string builder does not exceed
* the capacity, it is not necessary to allocate a new internal
* buffer. If the internal buffer overflows, it is automatically made larger.
*
- *
Instances of StringBuilder are not safe for
+ *
Instances of {@code StringBuilder} are not safe for
* use by multiple threads. If such synchronization is required then it is
* recommended that {@link java.lang.StringBuffer} be used.
*
@@ -87,11 +87,11 @@ public final class StringBuilder
/**
* Constructs a string builder with no characters in it and an
- * initial capacity specified by the capacity argument.
+ * initial capacity specified by the {@code capacity} argument.
*
* @param capacity the initial capacity.
- * @throws NegativeArraySizeException if the capacity
- * argument is less than 0.
+ * @throws NegativeArraySizeException if the {@code capacity}
+ * argument is less than {@code 0}.
*/
public StringBuilder(int capacity) {
super(capacity);
@@ -100,10 +100,10 @@ public final class StringBuilder
/**
* Constructs a string builder initialized to the contents of the
* specified string. The initial capacity of the string builder is
- * 16 plus the length of the string argument.
+ * {@code 16} plus the length of the string argument.
*
* @param str the initial contents of the buffer.
- * @throws NullPointerException if str is null
+ * @throws NullPointerException if {@code str} is {@code null}
*/
public StringBuilder(String str) {
super(str.length() + 16);
@@ -112,12 +112,12 @@ public final class StringBuilder
/**
* Constructs a string builder that contains the same characters
- * as the specified CharSequence. The initial capacity of
- * the string builder is 16 plus the length of the
- * CharSequence argument.
+ * as the specified {@code CharSequence}. The initial capacity of
+ * the string builder is {@code 16} plus the length of the
+ * {@code CharSequence} argument.
*
* @param seq the sequence to copy.
- * @throws NullPointerException if seq is null
+ * @throws NullPointerException if {@code seq} is {@code null}
*/
public StringBuilder(CharSequence seq) {
this(seq.length() + 16);
@@ -136,22 +136,22 @@ public final class StringBuilder
}
/**
- * Appends the specified StringBuffer to this sequence.
+ * Appends the specified {@code StringBuffer} to this sequence.
*
- * The characters of the StringBuffer argument are appended,
+ * The characters of the {@code StringBuffer} argument are appended,
* in order, to this sequence, increasing the
* length of this sequence by the length of the argument.
- * If sb is null, then the four characters
- * "null" are appended to this sequence.
+ * If {@code sb} is {@code null}, then the four characters
+ * {@code "null"} are appended to this sequence.
*
* Let n be the length of this character sequence just prior to
- * execution of the append method. Then the character at index
+ * execution of the {@code append} method. Then the character at index
* k in the new character sequence is equal to the character at
* index k in the old character sequence, if k is less than
* n; otherwise, it is equal to the character at index k-n
- * in the argument sb.
+ * in the argument {@code sb}.
*
- * @param sb the StringBuffer to append.
+ * @param sb the {@code StringBuffer} to append.
* @return a reference to this object.
*/
public StringBuilder append(StringBuffer sb) {
@@ -418,13 +418,13 @@ public final class StringBuilder
}
/**
- * Save the state of the StringBuilder instance to a stream
+ * Save the state of the {@code StringBuilder} instance to a stream
* (that is, serialize it).
*
* @serialData the number of characters currently stored in the string
- * builder (int), followed by the characters in the
- * string builder (char[]). The length of the
- * char array may be greater than the number of
+ * builder ({@code int}), followed by the characters in the
+ * string builder ({@code char[]}). The length of the
+ * {@code char} array may be greater than the number of
* characters currently stored in the string builder, in which
* case extra characters are ignored.
*/
diff --git a/jdk/src/share/classes/java/lang/StringIndexOutOfBoundsException.java b/jdk/src/share/classes/java/lang/StringIndexOutOfBoundsException.java
index 7067e29a88c..c3aa9b7a2df 100644
--- a/jdk/src/share/classes/java/lang/StringIndexOutOfBoundsException.java
+++ b/jdk/src/share/classes/java/lang/StringIndexOutOfBoundsException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 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
@@ -26,7 +26,7 @@
package java.lang;
/**
- * Thrown by String methods to indicate that an index
+ * Thrown by {@code String} methods to indicate that an index
* is either negative or greater than the size of the string. For
* some methods such as the charAt method, this exception also is
* thrown when the index is equal to the size of the string.
@@ -40,7 +40,7 @@ class StringIndexOutOfBoundsException extends IndexOutOfBoundsException {
private static final long serialVersionUID = -6762910422159637258L;
/**
- * Constructs a StringIndexOutOfBoundsException with no
+ * Constructs a {@code StringIndexOutOfBoundsException} with no
* detail message.
*
* @since JDK1.0.
@@ -50,7 +50,7 @@ class StringIndexOutOfBoundsException extends IndexOutOfBoundsException {
}
/**
- * Constructs a StringIndexOutOfBoundsException with
+ * Constructs a {@code StringIndexOutOfBoundsException} with
* the specified detail message.
*
* @param s the detail message.
@@ -60,7 +60,7 @@ class StringIndexOutOfBoundsException extends IndexOutOfBoundsException {
}
/**
- * Constructs a new StringIndexOutOfBoundsException
+ * Constructs a new {@code StringIndexOutOfBoundsException}
* class with an argument indicating the illegal index.
*
* @param index the illegal index.
From 87ea670a650ef3e29f5b1272d6ce06373b898ead Mon Sep 17 00:00:00 2001
From: Mandy Chung
Date: Fri, 28 Dec 2012 22:20:53 -0800
Subject: [PATCH 04/28] 8003562: Provide a CLI tool to analyze class
dependencies
Reviewed-by: jjg, alanb, ulfzibis, erikj
---
common/bin/compare_exceptions.sh.incl | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/common/bin/compare_exceptions.sh.incl b/common/bin/compare_exceptions.sh.incl
index 0127e9a4eb3..607e5fd4563 100644
--- a/common/bin/compare_exceptions.sh.incl
+++ b/common/bin/compare_exceptions.sh.incl
@@ -80,6 +80,7 @@ ACCEPTED_BIN_DIFF="
./bin/javadoc
./bin/javah
./bin/javap
+./bin/jdeps
./bin/jcmd
./bin/jconsole
./bin/jdb
@@ -167,6 +168,7 @@ ACCEPTED_BIN_DIFF="
./bin/javadoc
./bin/javah
./bin/javap
+./bin/jdeps
./bin/jcmd
./bin/jconsole
./bin/jdb
@@ -309,6 +311,7 @@ ACCEPTED_SMALL_SIZE_DIFF="
./bin/javadoc
./bin/javah
./bin/javap
+./bin/jdeps
./bin/javaws
./bin/jcmd
./bin/jconsole
@@ -449,6 +452,7 @@ ACCEPTED_SMALL_SIZE_DIFF="
./bin/amd64/javadoc
./bin/amd64/javah
./bin/amd64/javap
+./bin/amd64/jdeps
./bin/amd64/jcmd
./bin/amd64/jconsole
./bin/amd64/jdb
@@ -606,6 +610,7 @@ ACCEPTED_SMALL_SIZE_DIFF="
./bin/javadoc
./bin/javah
./bin/javap
+./bin/jdeps
./bin/javaws
./bin/jcmd
./bin/jconsole
@@ -751,6 +756,7 @@ ACCEPTED_SMALL_SIZE_DIFF="
./bin/sparcv9/javadoc
./bin/sparcv9/javah
./bin/sparcv9/javap
+./bin/sparcv9/jdeps
./bin/sparcv9/jcmd
./bin/sparcv9/jconsole
./bin/sparcv9/jdb
@@ -826,6 +832,7 @@ ACCEPTED_SMALL_SIZE_DIFF="
./bin/javadoc.exe
./bin/javah.exe
./bin/javap.exe
+./bin/jdeps.exe
./bin/javaw.exe
./bin/jcmd.exe
./bin/jconsole.exe
@@ -910,6 +917,7 @@ ACCEPTED_BIN_DIFF="
./bin/javadoc
./bin/javah
./bin/javap
+./bin/jdeps
./bin/jcmd
./bin/jconsole
./bin/jdb
From 83223ad4acfd5e7e963f2830456bf13e5835cc59 Mon Sep 17 00:00:00 2001
From: Chris Hegarty
Date: Thu, 3 Jan 2013 10:00:55 +0000
Subject: [PATCH 05/28] 8005634: tools/launcher/VersionCheck.java fails version
check on jdeps
Add jdeps to the list of tools that do not support '-version'
Reviewed-by: mchung
---
jdk/test/tools/launcher/VersionCheck.java | 1 +
1 file changed, 1 insertion(+)
diff --git a/jdk/test/tools/launcher/VersionCheck.java b/jdk/test/tools/launcher/VersionCheck.java
index d8018214181..c30ef424011 100644
--- a/jdk/test/tools/launcher/VersionCheck.java
+++ b/jdk/test/tools/launcher/VersionCheck.java
@@ -68,6 +68,7 @@ public class VersionCheck extends TestHelper {
"jcmd",
"jconsole",
"jcontrol",
+ "jdeps",
"jinfo",
"jmap",
"jps",
From 6061c09cab10db4ba809a8e7d140188c9c382ce7 Mon Sep 17 00:00:00 2001
From: Chris Hegarty
Date: Fri, 4 Jan 2013 11:18:00 +0000
Subject: [PATCH 06/28] 8005659: Add tools/pack200/AttributeTests.java to
exclude list (ProblemList.txt) until pack200 updated to support method
parameters
Reviewed-by: mchung, ksrini
---
jdk/test/ProblemList.txt | 3 +++
1 file changed, 3 insertions(+)
diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt
index ec698c7ef5d..e8bd6328599 100644
--- a/jdk/test/ProblemList.txt
+++ b/jdk/test/ProblemList.txt
@@ -324,6 +324,9 @@ tools/pack200/Pack200Test.java generic-all
# 7150569
tools/launcher/UnicodeTest.java macosx-all
+# 8005252
+tools/pack200/AttributeTests.java generic-all
+
############################################################################
# jdk_jdi
From c994d9bc0e6bfa2a730f71be8fcafd708537a240 Mon Sep 17 00:00:00 2001
From: Chris Hegarty
Date: Fri, 4 Jan 2013 11:34:17 +0000
Subject: [PATCH 07/28] 8005638: Less secure Authentication schemes should work
when more secure schemes are not available
Reviewed-by: alanb
---
.../sun/net/www/protocol/http/AuthenticationHeader.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/jdk/src/share/classes/sun/net/www/protocol/http/AuthenticationHeader.java b/jdk/src/share/classes/sun/net/www/protocol/http/AuthenticationHeader.java
index 390898292f0..41f55998973 100644
--- a/jdk/src/share/classes/sun/net/www/protocol/http/AuthenticationHeader.java
+++ b/jdk/src/share/classes/sun/net/www/protocol/http/AuthenticationHeader.java
@@ -206,7 +206,8 @@ public class AuthenticationHeader {
if(v == null) {
if ((v=schemes.get ("digest")) == null) {
- if (((v=schemes.get("ntlm"))==null)) {
+ if (!NTLMAuthenticationProxy.supported
+ || ((v=schemes.get("ntlm"))==null)) {
v = schemes.get ("basic");
}
}
From 6ae79cff82bca3ab44651139dbcfced307c3f0e0 Mon Sep 17 00:00:00 2001
From: Amy Lu
Date: Fri, 4 Jan 2013 16:10:14 -0800
Subject: [PATCH 08/28] 8005683: ProblemList.txt updates (01/2013)
Reviewed-by: mchung, alanb
---
jdk/test/ProblemList.txt | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt
index e8bd6328599..d2387317b5d 100644
--- a/jdk/test/ProblemList.txt
+++ b/jdk/test/ProblemList.txt
@@ -122,9 +122,6 @@
# jdk_lang
-# 7194607
-java/lang/instrument/VerifyLocalVariableTableOnRetransformTest.sh generic-all
-
# 6944188
java/lang/management/ThreadMXBean/ThreadStateTest.java generic-all
@@ -148,6 +145,9 @@ java/lang/management/MemoryMXBean/LowMemoryTest2.sh generic-all
# 6959636
javax/management/loading/LibraryLoader/LibraryLoaderTest.java windows-all
+# 8005472
+com/sun/jmx/remote/NotificationMarshalVersions/TestSerializationMismatch.sh windows-all
+
############################################################################
# jdk_math
From f4c27e0ba1f1d5adf09a9c50e0c61ef1f0adcccb Mon Sep 17 00:00:00 2001
From: Chris Hegarty
Date: Sat, 5 Jan 2013 17:06:54 +0000
Subject: [PATCH 09/28] 8005709: Add at since tags to new FJP
getCommonPoolParallelism and commonPool
Reviewed-by: dl
---
jdk/src/share/classes/java/util/concurrent/ForkJoinPool.java | 2 ++
1 file changed, 2 insertions(+)
diff --git a/jdk/src/share/classes/java/util/concurrent/ForkJoinPool.java b/jdk/src/share/classes/java/util/concurrent/ForkJoinPool.java
index a8940a3ddee..86bb3b59ebc 100644
--- a/jdk/src/share/classes/java/util/concurrent/ForkJoinPool.java
+++ b/jdk/src/share/classes/java/util/concurrent/ForkJoinPool.java
@@ -2611,6 +2611,7 @@ public class ForkJoinPool extends AbstractExecutorService {
* {@link #shutdown} or {@link #shutdownNow}.
*
* @return the common pool instance
+ * @since 1.8
*/
public static ForkJoinPool commonPool() {
// assert commonPool != null : "static init error";
@@ -2793,6 +2794,7 @@ public class ForkJoinPool extends AbstractExecutorService {
* Returns the targeted parallelism level of the common pool.
*
* @return the targeted parallelism level of the common pool
+ * @since 1.8
*/
public static int getCommonPoolParallelism() {
return commonPoolParallelism;
From 1381be8b23a373dfeb479102ba47b6c65ad30de0 Mon Sep 17 00:00:00 2001
From: David Dehaven
Date: Mon, 7 Jan 2013 09:58:48 -0800
Subject: [PATCH 10/28] 8004547: Extend JavaFX launcher support to allow full
JavaFX launch feature set
Reviewed-by: mchung, kcr, ksrini
---
.../classes/sun/launcher/LauncherHelper.java | 131 ++++++++-----
.../launcher/resources/launcher.properties | 3 +
jdk/test/tools/launcher/FXLauncherTest.java | 172 ++++++++++++++----
3 files changed, 231 insertions(+), 75 deletions(-)
diff --git a/jdk/src/share/classes/sun/launcher/LauncherHelper.java b/jdk/src/share/classes/sun/launcher/LauncherHelper.java
index 3b899bcca4d..2fc42a6962b 100644
--- a/jdk/src/share/classes/sun/launcher/LauncherHelper.java
+++ b/jdk/src/share/classes/sun/launcher/LauncherHelper.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2013, 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
@@ -409,6 +409,15 @@ public enum LauncherHelper {
if (mainValue == null) {
abort(null, "java.launcher.jar.error3", jarname);
}
+ /*
+ * Hand off to FXHelper if it detects a JavaFX application
+ * This must be done after ensuring a Main-Class entry
+ * exists to enforce compliance with the jar specification
+ */
+ if (mainAttrs.containsKey(
+ new Attributes.Name(FXHelper.JAVAFX_APPLICATION_MARKER))) {
+ return FXHelper.class.getName();
+ }
return mainValue.trim();
} catch (IOException ioe) {
abort(ioe, "java.launcher.jar.error1", jarname);
@@ -483,26 +492,23 @@ public enum LauncherHelper {
} catch (NoClassDefFoundError | ClassNotFoundException cnfe) {
abort(cnfe, "java.launcher.cls.error1", cn);
}
- // set to mainClass, FXHelper may return something else
+ // set to mainClass
appClass = mainClass;
- Method m = getMainMethod(mainClass);
- if (m != null) {
- // this will abort if main method has the wrong signature
- validateMainMethod(m);
- return mainClass;
+ /*
+ * Check if FXHelper can launch it using the FX launcher. In an FX app,
+ * the main class may or may not have a main method, so do this before
+ * validating the main class.
+ */
+ if (mainClass.equals(FXHelper.class) ||
+ FXHelper.doesExtendFXApplication(mainClass)) {
+ // Will abort() if there are problems with the FX runtime
+ FXHelper.setFXLaunchParameters(what, mode);
+ return FXHelper.class;
}
- // Check if FXHelper can launch it using the FX launcher
- Class> fxClass = FXHelper.getFXMainClass(mainClass);
- if (fxClass != null) {
- return fxClass;
- }
-
- // not an FX application either, abort with an error
- abort(null, "java.launcher.cls.error4", mainClass.getName(),
- FXHelper.JAVAFX_APPLICATION_CLASS_NAME);
- return null; // avoid compiler error...
+ validateMainClass(mainClass);
+ return mainClass;
}
/*
@@ -515,16 +521,18 @@ public enum LauncherHelper {
return appClass;
}
- // Check for main method or return null if not found
- static Method getMainMethod(Class> clazz) {
+ // Check the existence and signature of main and abort if incorrect
+ static void validateMainClass(Class> mainClass) {
+ Method mainMethod;
try {
- return clazz.getMethod("main", String[].class);
- } catch (NoSuchMethodException nsme) {}
- return null;
- }
+ mainMethod = mainClass.getMethod("main", String[].class);
+ } catch (NoSuchMethodException nsme) {
+ // invalid main or not FX application, abort with an error
+ abort(null, "java.launcher.cls.error4", mainClass.getName(),
+ FXHelper.JAVAFX_APPLICATION_CLASS_NAME);
+ return; // Avoid compiler issues
+ }
- // Check the signature of main and abort if it's incorrect
- static void validateMainMethod(Method mainMethod) {
/*
* getMethod (above) will choose the correct method, based
* on its name and parameter type, however, we still have to
@@ -644,41 +652,78 @@ public enum LauncherHelper {
}
static final class FXHelper {
+ // Marker entry in jar manifest that designates a JavaFX application jar
+ private static final String JAVAFX_APPLICATION_MARKER =
+ "JavaFX-Application-Class";
private static final String JAVAFX_APPLICATION_CLASS_NAME =
"javafx.application.Application";
private static final String JAVAFX_LAUNCHER_CLASS_NAME =
"com.sun.javafx.application.LauncherImpl";
+ /*
+ * The launch method used to invoke the JavaFX launcher. These must
+ * match the strings used in the launchApplication method.
+ *
+ * Command line JavaFX-App-Class Launch mode FX Launch mode
+ * java -cp fxapp.jar FXClass N/A LM_CLASS "LM_CLASS"
+ * java -cp somedir FXClass N/A LM_CLASS "LM_CLASS"
+ * java -jar fxapp.jar Present LM_JAR "LM_JAR"
+ * java -jar fxapp.jar Not Present LM_JAR "LM_JAR"
+ */
+ private static final String JAVAFX_LAUNCH_MODE_CLASS = "LM_CLASS";
+ private static final String JAVAFX_LAUNCH_MODE_JAR = "LM_JAR";
+
/*
* FX application launcher and launch method, so we can launch
* applications with no main method.
*/
+ private static String fxLaunchName = null;
+ private static String fxLaunchMode = null;
+
private static Class> fxLauncherClass = null;
private static Method fxLauncherMethod = null;
/*
- * We can assume that the class does NOT have a main method or it would
- * have been handled already. We do, however, need to check if the class
- * extends Application and the launcher is available and abort with an
- * error if it's not.
+ * Set the launch params according to what was passed to LauncherHelper
+ * so we can use the same launch mode for FX. Abort if there is any
+ * issue with loading the FX runtime or with the launcher method.
*/
- private static Class> getFXMainClass(Class> mainClass) {
- // Check if mainClass extends Application
- if (!doesExtendFXApplication(mainClass)) {
- return null;
- }
-
+ private static void setFXLaunchParameters(String what, int mode) {
// Check for the FX launcher classes
try {
fxLauncherClass = scloader.loadClass(JAVAFX_LAUNCHER_CLASS_NAME);
+ /*
+ * signature must be:
+ * public static void launchApplication(String launchName,
+ * String launchMode, String[] args);
+ */
fxLauncherMethod = fxLauncherClass.getMethod("launchApplication",
- Class.class, String[].class);
+ String.class, String.class, String[].class);
+
+ // verify launcher signature as we do when validating the main method
+ int mod = fxLauncherMethod.getModifiers();
+ if (!Modifier.isStatic(mod)) {
+ abort(null, "java.launcher.javafx.error1");
+ }
+ if (fxLauncherMethod.getReturnType() != java.lang.Void.TYPE) {
+ abort(null, "java.launcher.javafx.error1");
+ }
} catch (ClassNotFoundException | NoSuchMethodException ex) {
abort(ex, "java.launcher.cls.error5", ex);
}
- // That's all, return this class so we can launch later
- return FXHelper.class;
+ fxLaunchName = what;
+ switch (mode) {
+ case LM_CLASS:
+ fxLaunchMode = JAVAFX_LAUNCH_MODE_CLASS;
+ break;
+ case LM_JAR:
+ fxLaunchMode = JAVAFX_LAUNCH_MODE_JAR;
+ break;
+ default:
+ // should not have gotten this far...
+ throw new InternalError(mode + ": Unknown launch mode");
+ }
}
/*
@@ -696,11 +741,15 @@ public enum LauncherHelper {
return false;
}
- // preloader ?
public static void main(String... args) throws Exception {
+ if (fxLauncherMethod == null
+ || fxLaunchMode == null
+ || fxLaunchName == null) {
+ throw new RuntimeException("Invalid JavaFX launch parameters");
+ }
// launch appClass via fxLauncherMethod
- fxLauncherMethod.invoke(null, new Object[] {appClass, args});
+ fxLauncherMethod.invoke(null,
+ new Object[] {fxLaunchName, fxLaunchMode, args});
}
}
}
-
diff --git a/jdk/src/share/classes/sun/launcher/resources/launcher.properties b/jdk/src/share/classes/sun/launcher/resources/launcher.properties
index bfa05181784..8fbefacf8da 100644
--- a/jdk/src/share/classes/sun/launcher/resources/launcher.properties
+++ b/jdk/src/share/classes/sun/launcher/resources/launcher.properties
@@ -140,3 +140,6 @@ java.launcher.jar.error1=\
java.launcher.jar.error2=manifest not found in {0}
java.launcher.jar.error3=no main manifest attribute, in {0}
java.launcher.init.error=initialization error
+java.launcher.javafx.error1=\
+ Error: The JavaFX launchApplication method has the wrong signature, it\n\
+ must be declared static and return a value of type void
diff --git a/jdk/test/tools/launcher/FXLauncherTest.java b/jdk/test/tools/launcher/FXLauncherTest.java
index 9b58c0846c0..1ed251bad19 100644
--- a/jdk/test/tools/launcher/FXLauncherTest.java
+++ b/jdk/test/tools/launcher/FXLauncherTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, 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
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 8001533
+ * @bug 8001533 8004547
* @summary Test launching FX application with java -jar
* Test uses main method and blank main method, a jfx app class and an incorrest
* jfx app class, a main-class for the manifest, a bogus one and none.
@@ -47,6 +47,8 @@ public class FXLauncherTest extends TestHelper {
/* standard main class can be used as java main for fx app class */
static final String StdMainClass = "helloworld.HelloWorld";
+ static final String ExtMainClass = "helloworld.ExtHello";
+ static final String NonFXMainClass = "helloworld.HelloJava";
static int testcount = 0;
/* a main method and a blank. */
@@ -107,9 +109,7 @@ public class FXLauncherTest extends TestHelper {
}
/*
- * Create class to extend fx java file for test application
- * TODO: make test to create java file and this extension of the java file
- * and jar them together an run app via this java class.
+ * Create class that extends HelloWorld instead of Application
*/
static void createExtJavaFile(String mainmethod) {
try {
@@ -125,16 +125,48 @@ public class FXLauncherTest extends TestHelper {
compile("-cp", ".", "-d", ".", mainClass + JAVA_FILE_EXT);
} catch (java.io.IOException ioe) {
ioe.printStackTrace();
- throw new RuntimeException("Failed creating HelloWorld.");
+ throw new RuntimeException("Failed creating ExtHello.");
+ }
+ }
+
+ /*
+ * Create non-JavaFX class for testing if jfxrt.jar is being loaded
+ * when it shouldn't be
+ */
+ static void createNonFXJavaFile() {
+ try {
+ String mainClass = "HelloJava";
+ List contents = new ArrayList<>();
+ contents.add("package helloworld;");
+ contents.add("public class HelloJava {");
+ contents.add(" public static void main(String[] args) {");
+ contents.add(" for(String aa : args)");
+ contents.add(" System.out.println(\"arg: \" + aa);" );
+ contents.add(" }");
+ contents.add("}");
+ // Create and compile java source.
+ MainJavaFile = new File(mainClass + JAVA_FILE_EXT);
+ createFile(MainJavaFile, contents);
+ compile("-cp", ".", "-d", ".", mainClass + JAVA_FILE_EXT);
+ } catch (java.io.IOException ioe) {
+ ioe.printStackTrace();
+ throw new RuntimeException("Failed creating HelloJava.");
}
}
// Create manifest for test fx application
- static List createManifestContents(String mainclassentry) {
+ static List createManifestContents(String mainClassEntry, String fxMainEntry) {
List mcontents = new ArrayList<>();
mcontents.add("Manifest-Version: 1.0");
mcontents.add("Created-By: FXLauncherTest");
- mcontents.add("Main-Class: " + mainclassentry);
+ if (mainClassEntry != null) {
+ mcontents.add("Main-Class: " + mainClassEntry);
+ System.out.println("Main-Class: " + mainClassEntry);
+ }
+ if (fxMainEntry != null) {
+ mcontents.add("JavaFX-Application-Class: " + fxMainEntry);
+ System.out.println("JavaFX-Application-Class: " + fxMainEntry);
+ }
return mcontents;
}
@@ -175,31 +207,41 @@ public class FXLauncherTest extends TestHelper {
/*
* Set Main-Class and iterate main_methods.
- * Try launching with both -jar and -cp methods.
+ * Try launching with both -jar and -cp methods, with and without FX main
+ * class manifest entry.
* All cases should run.
+ *
+ * See sun.launcher.LauncherHelper$FXHelper for more details on how JavaFX
+ * applications are launched.
*/
@Test
static void testBasicFXApp() throws Exception {
- testBasicFXApp(true);
- testBasicFXApp(false);
+ testBasicFXApp(true, false); // -cp, no JAC
+ testBasicFXApp(false, true); // -jar, with JAC
+ testBasicFXApp(false, false); // -jar, no JAC
}
- static void testBasicFXApp(boolean useCP) throws Exception {
+ static void testBasicFXApp(boolean useCP, boolean setFXMainClass) throws Exception {
String testname = "testBasicFXApp";
+ if (useCP) {
+ testname = testname.concat("_useCP");
+ }
+ String fxMC = StdMainClass;
+ if (!setFXMainClass) {
+ testname = testname.concat("_noJAC");
+ fxMC = null;
+ }
for (String mm : MAIN_METHODS) {
testcount++;
line();
- System.out.println("test# " + testcount +
- "- Main method: " + mm +
- "; MF main class: " + StdMainClass);
+ System.out.println("test# " + testcount + "- Main method: " + mm);
createJavaFile(mm);
- createFile(ManifestFile, createManifestContents(StdMainClass));
+ createFile(ManifestFile, createManifestContents(StdMainClass, fxMC));
createJar(FXtestJar, ManifestFile);
String sTestJar = FXtestJar.getAbsolutePath();
TestResult tr;
if (useCP) {
tr = doExec(javaCmd, "-cp", sTestJar, StdMainClass, APP_PARMS[0], APP_PARMS[1]);
- testname = testname.concat("_useCP");
} else {
tr = doExec(javaCmd, "-jar", sTestJar, APP_PARMS[0], APP_PARMS[1]);
}
@@ -224,26 +266,33 @@ public class FXLauncherTest extends TestHelper {
*/
@Test
static void testExtendFXApp() throws Exception {
- testExtendFXApp(true);
- testExtendFXApp(false);
+ testExtendFXApp(true, false); // -cp, no JAC
+ testExtendFXApp(false, true); // -jar, with JAC
+ testExtendFXApp(false, false); // -jar, no JAC
}
- static void testExtendFXApp(boolean useCP) throws Exception {
+ static void testExtendFXApp(boolean useCP, boolean setFXMainClass) throws Exception {
String testname = "testExtendFXApp";
+ if (useCP) {
+ testname = testname.concat("_useCP");
+ }
+ String fxMC = ExtMainClass;
+ if (!setFXMainClass) {
+ testname = testname.concat("_noJAC");
+ fxMC = null;
+ }
for (String mm : MAIN_METHODS) {
testcount++;
line();
- System.out.println("test# " + testcount +
- "- Main method: " + mm + "; MF main class: " + StdMainClass);
+ System.out.println("test# " + testcount + "- Main method: " + mm);
createJavaFile(mm);
createExtJavaFile(mm);
- createFile(ManifestFile, createManifestContents(StdMainClass));
+ createFile(ManifestFile, createManifestContents(ExtMainClass, fxMC));
createJar(FXtestJar, ManifestFile);
String sTestJar = FXtestJar.getAbsolutePath();
TestResult tr;
if (useCP) {
- tr = doExec(javaCmd, "-cp", sTestJar, StdMainClass, APP_PARMS[0], APP_PARMS[1]);
- testname = testname.concat("_useCP");
+ tr = doExec(javaCmd, "-cp", sTestJar, ExtMainClass, APP_PARMS[0], APP_PARMS[1]);
} else {
tr = doExec(javaCmd, "-jar", sTestJar, APP_PARMS[0], APP_PARMS[1]);
}
@@ -256,27 +305,82 @@ public class FXLauncherTest extends TestHelper {
}
}
}
- checkStatus(tr, testname, testcount, StdMainClass);
+ checkStatus(tr, testname, testcount, ExtMainClass);
}
}
+ /*
+ * Ensure we can NOT launch a FX app jar with no Main-Class manifest entry
+ */
+ @Test
+ static void testMissingMC() throws Exception {
+ String testname = "testMissingMC";
+ testcount++;
+ line();
+ System.out.println("test# " + testcount + ": abort on missing Main-Class");
+ createJavaFile(" "); // no main() needed
+ createFile(ManifestFile, createManifestContents(null, StdMainClass)); // No MC, but supply JAC
+ createJar(FXtestJar, ManifestFile);
+ String sTestJar = FXtestJar.getAbsolutePath();
+ TestResult tr = doExec(javaCmd, "-jar", sTestJar, APP_PARMS[0], APP_PARMS[1]);
+ tr.checkNegative(); // should abort if no Main-Class
+ if (tr.testStatus) {
+ if (!tr.contains("no main manifest attribute")) {
+ System.err.println("ERROR: launcher did not abort properly");
+ }
+ } else {
+ System.err.println("ERROR: jar executed with no Main-Class!");
+ }
+ checkStatus(tr, testname, testcount, StdMainClass);
+ }
+
/*
* test to ensure that we don't load any extraneous fx jars when
* launching a standard java application
+ * Test both -cp and -jar methods since they use different code paths.
+ * Neither case should cause jfxrt.jar to be loaded.
*/
@Test
- static void testExtraneousJars()throws Exception {
+ static void testExtraneousJars() throws Exception {
+ testExtraneousJars(true);
+ testExtraneousJars(false);
+ }
+
+ static void testExtraneousJars(boolean useCP) throws Exception {
String testname = "testExtraneousJars";
+ if (useCP) {
+ testname = testname.concat("_useCP");
+ }
testcount++;
line();
- System.out.println("test# " + testcount);
- TestResult tr = doExec(javacCmd, "-J-verbose:class", "-version");
- if (!tr.notContains("jfxrt.jar")) {
- System.out.println("testing for extraneous jfxrt jar");
- System.out.println(tr);
- throw new Exception("jfxrt.jar is being loaded by javac!!!");
+ System.out.println("test# " + testcount
+ + ": test for erroneous jfxrt.jar loading");
+ createNonFXJavaFile();
+ createFile(ManifestFile, createManifestContents(NonFXMainClass, null));
+ createJar(FXtestJar, ManifestFile);
+ String sTestJar = FXtestJar.getAbsolutePath();
+ TestResult tr;
+
+ if (useCP) {
+ tr = doExec(javaCmd, "-verbose:class", "-cp", sTestJar, NonFXMainClass, APP_PARMS[0], APP_PARMS[1]);
+ } else {
+ tr = doExec(javaCmd, "-verbose:class", "-jar", sTestJar, APP_PARMS[0], APP_PARMS[1]);
}
- checkStatus(tr, testname, testcount, StdMainClass);
+ tr.checkPositive();
+ if (tr.testStatus) {
+ if (!tr.notContains("jfxrt.jar")) {
+ System.out.println("testing for extraneous jfxrt jar");
+ System.out.println(tr);
+ throw new Exception("jfxrt.jar is being loaded, it should not be!");
+ }
+ for (String p : APP_PARMS) {
+ if (!tr.contains(p)) {
+ System.err.println("ERROR: Did not find "
+ + p + " in output!");
+ }
+ }
+ }
+ checkStatus(tr, testname, testcount, NonFXMainClass);
}
public static void main(String... args) throws Exception {
From 96c54994396b1f7ab483268e8c3b8d68a3d40d6b Mon Sep 17 00:00:00 2001
From: Valerie Peng
Date: Mon, 7 Jan 2013 11:11:54 -0800
Subject: [PATCH 11/28] 6996769: support AEAD cipher
Added implementation for GCM mode under AES cipher
Reviewed-by: weijun
---
.../com/sun/crypto/provider/AESCipher.java | 93 +++-
.../com/sun/crypto/provider/CipherCore.java | 445 +++++++++++-----
.../crypto/provider/CipherTextStealing.java | 14 +-
.../sun/crypto/provider/FeedbackCipher.java | 46 +-
.../sun/crypto/provider/GCMParameters.java | 146 +++++
.../classes/com/sun/crypto/provider/GCTR.java | 144 +++++
.../com/sun/crypto/provider/GHASH.java | 178 +++++++
.../crypto/provider/GaloisCounterMode.java | 501 ++++++++++++++++++
.../com/sun/crypto/provider/SunJCE.java | 17 +-
.../share/classes/javax/crypto/Cipher.java | 23 +-
.../javax/crypto/spec/GCMParameterSpec.java | 4 +-
.../provider/Cipher/AES/Test4512524.java | 17 +-
.../provider/Cipher/AES/Test4512704.java | 23 +-
.../provider/Cipher/AES/Test4517355.java | 44 +-
.../provider/Cipher/AES/Test4626070.java | 20 +-
.../Cipher/AES/TestGCMKeyAndIvCheck.java | 178 +++++++
.../provider/Cipher/AES/TestKATForGCM.java | 314 +++++++++++
jdk/test/javax/crypto/Cipher/GCMAPI.java | 8 +-
18 files changed, 2010 insertions(+), 205 deletions(-)
create mode 100644 jdk/src/share/classes/com/sun/crypto/provider/GCMParameters.java
create mode 100644 jdk/src/share/classes/com/sun/crypto/provider/GCTR.java
create mode 100644 jdk/src/share/classes/com/sun/crypto/provider/GHASH.java
create mode 100644 jdk/src/share/classes/com/sun/crypto/provider/GaloisCounterMode.java
create mode 100644 jdk/test/com/sun/crypto/provider/Cipher/AES/TestGCMKeyAndIvCheck.java
create mode 100644 jdk/test/com/sun/crypto/provider/Cipher/AES/TestKATForGCM.java
diff --git a/jdk/src/share/classes/com/sun/crypto/provider/AESCipher.java b/jdk/src/share/classes/com/sun/crypto/provider/AESCipher.java
index 0ae68957c43..32cb3e39d3d 100644
--- a/jdk/src/share/classes/com/sun/crypto/provider/AESCipher.java
+++ b/jdk/src/share/classes/com/sun/crypto/provider/AESCipher.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2013, 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,6 +30,7 @@ import java.security.spec.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import javax.crypto.BadPaddingException;
+import java.nio.ByteBuffer;
/**
* This class implements the AES algorithm in its various modes
@@ -127,6 +128,21 @@ abstract class AESCipher extends CipherSpi {
super(32, "CFB", "NOPADDING");
}
}
+ public static final class AES128_GCM_NoPadding extends OidImpl {
+ public AES128_GCM_NoPadding() {
+ super(16, "GCM", "NOPADDING");
+ }
+ }
+ public static final class AES192_GCM_NoPadding extends OidImpl {
+ public AES192_GCM_NoPadding() {
+ super(24, "GCM", "NOPADDING");
+ }
+ }
+ public static final class AES256_GCM_NoPadding extends OidImpl {
+ public AES256_GCM_NoPadding() {
+ super(32, "GCM", "NOPADDING");
+ }
+ }
// utility method used by AESCipher and AESWrapCipher
static final void checkKeySize(Key key, int fixedKeySize)
@@ -531,4 +547,79 @@ abstract class AESCipher extends CipherSpi {
return core.unwrap(wrappedKey, wrappedKeyAlgorithm,
wrappedKeyType);
}
+
+ /**
+ * Continues a multi-part update of the Additional Authentication
+ * Data (AAD), using a subset of the provided buffer.
+ *
+ * Calls to this method provide AAD to the cipher when operating in
+ * modes such as AEAD (GCM/CCM). If this cipher is operating in
+ * either GCM or CCM mode, all AAD must be supplied before beginning
+ * operations on the ciphertext (via the {@code update} and {@code
+ * doFinal} methods).
+ *
+ * @param src the buffer containing the AAD
+ * @param offset the offset in {@code src} where the AAD input starts
+ * @param len the number of AAD bytes
+ *
+ * @throws IllegalStateException if this cipher is in a wrong state
+ * (e.g., has not been initialized), does not accept AAD, or if
+ * operating in either GCM or CCM mode and one of the {@code update}
+ * methods has already been called for the active
+ * encryption/decryption operation
+ * @throws UnsupportedOperationException if this method
+ * has not been overridden by an implementation
+ *
+ * @since 1.8
+ */
+ @Override
+ protected void engineUpdateAAD(byte[] src, int offset, int len) {
+ core.updateAAD(src, offset, len);
+ }
+
+ /**
+ * Continues a multi-part update of the Additional Authentication
+ * Data (AAD).
+ *
+ * Calls to this method provide AAD to the cipher when operating in
+ * modes such as AEAD (GCM/CCM). If this cipher is operating in
+ * either GCM or CCM mode, all AAD must be supplied before beginning
+ * operations on the ciphertext (via the {@code update} and {@code
+ * doFinal} methods).
+ *
+ * All {@code src.remaining()} bytes starting at
+ * {@code src.position()} are processed.
+ * Upon return, the input buffer's position will be equal
+ * to its limit; its limit will not have changed.
+ *
+ * @param src the buffer containing the AAD
+ *
+ * @throws IllegalStateException if this cipher is in a wrong state
+ * (e.g., has not been initialized), does not accept AAD, or if
+ * operating in either GCM or CCM mode and one of the {@code update}
+ * methods has already been called for the active
+ * encryption/decryption operation
+ * @throws UnsupportedOperationException if this method
+ * has not been overridden by an implementation
+ *
+ * @since 1.8
+ */
+ @Override
+ protected void engineUpdateAAD(ByteBuffer src) {
+ if (src != null) {
+ int aadLen = src.limit() - src.position();
+ if (aadLen != 0) {
+ if (src.hasArray()) {
+ int aadOfs = src.arrayOffset() + src.position();
+ core.updateAAD(src.array(), aadOfs, aadLen);
+ src.position(src.limit());
+ } else {
+ byte[] aad = new byte[aadLen];
+ src.get(aad);
+ core.updateAAD(aad, 0, aadLen);
+ }
+ }
+ }
+ }
}
+
diff --git a/jdk/src/share/classes/com/sun/crypto/provider/CipherCore.java b/jdk/src/share/classes/com/sun/crypto/provider/CipherCore.java
index eb30879b0b9..5c47e7f1f72 100644
--- a/jdk/src/share/classes/com/sun/crypto/provider/CipherCore.java
+++ b/jdk/src/share/classes/com/sun/crypto/provider/CipherCore.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2013, 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
@@ -25,6 +25,7 @@
package com.sun.crypto.provider;
+import java.util.Arrays;
import java.util.Locale;
import java.security.*;
@@ -59,7 +60,7 @@ final class CipherCore {
private byte[] buffer = null;
/*
- * internal buffer
+ * block size of cipher in bytes
*/
private int blockSize = 0;
@@ -76,10 +77,12 @@ final class CipherCore {
/*
* minimum number of bytes in the buffer required for
* FeedbackCipher.encryptFinal()/decryptFinal() call.
- * update() must buffer this many bytes before before starting
+ * update() must buffer this many bytes before starting
* to encrypt/decrypt data.
- * currently, only CTS mode has a non-zero value due to its special
- * handling on the last two blocks (the last one may be incomplete).
+ * currently, only the following cases have non-zero values:
+ * 1) CTS mode - due to its special handling on the last two blocks
+ * (the last one may be incomplete).
+ * 2) GCM mode + decryption - due to its trailing tag bytes
*/
private int minBytes = 0;
@@ -121,6 +124,24 @@ final class CipherCore {
private static final int PCBC_MODE = 4;
private static final int CTR_MODE = 5;
private static final int CTS_MODE = 6;
+ private static final int GCM_MODE = 7;
+
+ /*
+ * variables used for performing the GCM (key+iv) uniqueness check.
+ * To use GCM mode safely, the cipher object must be re-initialized
+ * with a different combination of key + iv values for each
+ * encryption operation. However, checking all past key + iv values
+ * isn't feasible. Thus, we only do a per-instance check of the
+ * key + iv values used in previous encryption.
+ * For decryption operations, no checking is necessary.
+ * NOTE: this key+iv check have to be done inside CipherCore class
+ * since CipherCore class buffers potential tag bytes in GCM mode
+ * and may not call GaloisCounterMode when there isn't sufficient
+ * input to process.
+ */
+ private boolean requireReinit = false;
+ private byte[] lastEncKey = null;
+ private byte[] lastEncIv = null;
/**
* Creates an instance of CipherCore with default ECB mode and
@@ -149,7 +170,7 @@ final class CipherCore {
* @param mode the cipher mode
*
* @exception NoSuchAlgorithmException if the requested cipher mode does
- * not exist
+ * not exist for this cipher
*/
void setMode(String mode) throws NoSuchAlgorithmException {
if (mode == null)
@@ -165,30 +186,34 @@ final class CipherCore {
if (modeUpperCase.equals("CBC")) {
cipherMode = CBC_MODE;
cipher = new CipherBlockChaining(rawImpl);
- }
- else if (modeUpperCase.equals("CTS")) {
+ } else if (modeUpperCase.equals("CTS")) {
cipherMode = CTS_MODE;
cipher = new CipherTextStealing(rawImpl);
minBytes = blockSize+1;
padding = null;
- }
- else if (modeUpperCase.equals("CTR")) {
+ } else if (modeUpperCase.equals("CTR")) {
cipherMode = CTR_MODE;
cipher = new CounterMode(rawImpl);
unitBytes = 1;
padding = null;
- }
- else if (modeUpperCase.startsWith("CFB")) {
+ } else if (modeUpperCase.startsWith("GCM")) {
+ // can only be used for block ciphers w/ 128-bit block size
+ if (blockSize != 16) {
+ throw new NoSuchAlgorithmException
+ ("GCM mode can only be used for AES cipher");
+ }
+ cipherMode = GCM_MODE;
+ cipher = new GaloisCounterMode(rawImpl);
+ padding = null;
+ } else if (modeUpperCase.startsWith("CFB")) {
cipherMode = CFB_MODE;
unitBytes = getNumOfUnit(mode, "CFB".length(), blockSize);
cipher = new CipherFeedback(rawImpl, unitBytes);
- }
- else if (modeUpperCase.startsWith("OFB")) {
+ } else if (modeUpperCase.startsWith("OFB")) {
cipherMode = OFB_MODE;
unitBytes = getNumOfUnit(mode, "OFB".length(), blockSize);
cipher = new OutputFeedback(rawImpl, unitBytes);
- }
- else if (modeUpperCase.equals("PCBC")) {
+ } else if (modeUpperCase.equals("PCBC")) {
cipherMode = PCBC_MODE;
cipher = new PCBC(rawImpl);
}
@@ -219,6 +244,7 @@ final class CipherCore {
return result;
}
+
/**
* Sets the padding mechanism of this cipher.
*
@@ -242,11 +268,27 @@ final class CipherCore {
+ " not implemented");
}
if ((padding != null) &&
- ((cipherMode == CTR_MODE) || (cipherMode == CTS_MODE))) {
+ ((cipherMode == CTR_MODE) || (cipherMode == CTS_MODE)
+ || (cipherMode == GCM_MODE))) {
padding = null;
- throw new NoSuchPaddingException
- ((cipherMode == CTR_MODE? "CTR":"CTS") +
- " mode must be used with NoPadding");
+ String modeStr = null;
+ switch (cipherMode) {
+ case CTR_MODE:
+ modeStr = "CTR";
+ break;
+ case GCM_MODE:
+ modeStr = "GCM";
+ break;
+ case CTS_MODE:
+ modeStr = "CTS";
+ break;
+ default:
+ // should never happen
+ }
+ if (modeStr != null) {
+ throw new NoSuchPaddingException
+ (modeStr + " mode must be used with NoPadding");
+ }
}
}
@@ -257,7 +299,7 @@ final class CipherCore {
* inputLen (in bytes).
*
*
This call takes into account any unprocessed (buffered) data from a
- * previous update call, and padding.
+ * previous update call, padding, and AEAD tagging.
*
*
The actual output length of the next update or
* doFinal call may be smaller than the length returned by
@@ -270,23 +312,60 @@ final class CipherCore {
int getOutputSize(int inputLen) {
int totalLen = buffered + inputLen;
- if (padding == null)
- return totalLen;
+ // GCM: this call may be for either update() or doFinal(), so have to
+ // return the larger value of both
+ // Encryption: based on doFinal value: inputLen + tag
+ // Decryption: based on update value: inputLen
+ if (!decrypting && (cipherMode == GCM_MODE)) {
+ return (totalLen + ((GaloisCounterMode) cipher).getTagLen());
+ }
- if (decrypting)
+ if (padding == null) {
return totalLen;
+ }
+
+ if (decrypting) {
+ return totalLen;
+ }
if (unitBytes != blockSize) {
- if (totalLen < diffBlocksize)
+ if (totalLen < diffBlocksize) {
return diffBlocksize;
- else
+ } else {
return (totalLen + blockSize -
((totalLen - diffBlocksize) % blockSize));
+ }
} else {
return totalLen + padding.padLength(totalLen);
}
}
+ private int getOutputSizeByOperation(int inputLen, boolean isDoFinal) {
+ int totalLen = 0;
+ switch (cipherMode) {
+ case GCM_MODE:
+ totalLen = buffered + inputLen;
+ if (isDoFinal) {
+ int tagLen = ((GaloisCounterMode) cipher).getTagLen();
+ if (decrypting) {
+ // need to get the actual value from cipher??
+ // deduct tagLen
+ totalLen -= tagLen;
+ } else {
+ totalLen += tagLen;
+ }
+ }
+ if (totalLen < 0) {
+ totalLen = 0;
+ }
+ break;
+ default:
+ totalLen = getOutputSize(inputLen);
+ break;
+ }
+ return totalLen;
+ }
+
/**
* Returns the initialization vector (IV) in a new buffer.
*
@@ -318,34 +397,49 @@ final class CipherCore {
* does not use any parameters.
*/
AlgorithmParameters getParameters(String algName) {
+ if (cipherMode == ECB_MODE) {
+ return null;
+ }
AlgorithmParameters params = null;
- if (cipherMode == ECB_MODE) return null;
+ AlgorithmParameterSpec spec;
byte[] iv = getIV();
- if (iv != null) {
- AlgorithmParameterSpec ivSpec;
- if (algName.equals("RC2")) {
- RC2Crypt rawImpl = (RC2Crypt) cipher.getEmbeddedCipher();
- ivSpec = new RC2ParameterSpec(rawImpl.getEffectiveKeyBits(),
- iv);
+ if (iv == null) {
+ // generate spec using default value
+ if (cipherMode == GCM_MODE) {
+ iv = new byte[GaloisCounterMode.DEFAULT_IV_LEN];
} else {
- ivSpec = new IvParameterSpec(iv);
- }
- try {
- params = AlgorithmParameters.getInstance(algName, "SunJCE");
- } catch (NoSuchAlgorithmException nsae) {
- // should never happen
- throw new RuntimeException("Cannot find " + algName +
- " AlgorithmParameters implementation in SunJCE provider");
- } catch (NoSuchProviderException nspe) {
- // should never happen
- throw new RuntimeException("Cannot find SunJCE provider");
- }
- try {
- params.init(ivSpec);
- } catch (InvalidParameterSpecException ipse) {
- // should never happen
- throw new RuntimeException("IvParameterSpec not supported");
+ iv = new byte[blockSize];
}
+ SunJCE.RANDOM.nextBytes(iv);
+ }
+ if (cipherMode == GCM_MODE) {
+ algName = "GCM";
+ spec = new GCMParameterSpec
+ (((GaloisCounterMode) cipher).getTagLen()*8, iv);
+ } else {
+ if (algName.equals("RC2")) {
+ RC2Crypt rawImpl = (RC2Crypt) cipher.getEmbeddedCipher();
+ spec = new RC2ParameterSpec
+ (rawImpl.getEffectiveKeyBits(), iv);
+ } else {
+ spec = new IvParameterSpec(iv);
+ }
+ }
+ try {
+ params = AlgorithmParameters.getInstance(algName, "SunJCE");
+ } catch (NoSuchAlgorithmException nsae) {
+ // should never happen
+ throw new RuntimeException("Cannot find " + algName +
+ " AlgorithmParameters implementation in SunJCE provider");
+ } catch (NoSuchProviderException nspe) {
+ // should never happen
+ throw new RuntimeException("Cannot find SunJCE provider");
+ }
+ try {
+ params.init(spec);
+ } catch (InvalidParameterSpecException ipse) {
+ // should never happen
+ throw new RuntimeException(spec.getClass() + " not supported");
}
return params;
}
@@ -420,44 +514,63 @@ final class CipherCore {
|| (opmode == Cipher.UNWRAP_MODE);
byte[] keyBytes = getKeyBytes(key);
-
- byte[] ivBytes;
- if (params == null) {
- ivBytes = null;
- } else if (params instanceof IvParameterSpec) {
- ivBytes = ((IvParameterSpec)params).getIV();
- if ((ivBytes == null) || (ivBytes.length != blockSize)) {
- throw new InvalidAlgorithmParameterException
- ("Wrong IV length: must be " + blockSize +
- " bytes long");
+ int tagLen = -1;
+ byte[] ivBytes = null;
+ if (params != null) {
+ if (cipherMode == GCM_MODE) {
+ if (params instanceof GCMParameterSpec) {
+ tagLen = ((GCMParameterSpec)params).getTLen();
+ if (tagLen < 96 || tagLen > 128 || ((tagLen & 0x07) != 0)) {
+ throw new InvalidAlgorithmParameterException
+ ("Unsupported TLen value; must be one of " +
+ "{128, 120, 112, 104, 96}");
+ }
+ tagLen = tagLen >> 3;
+ ivBytes = ((GCMParameterSpec)params).getIV();
+ } else {
+ throw new InvalidAlgorithmParameterException
+ ("Unsupported parameter: " + params);
+ }
+ } else {
+ if (params instanceof IvParameterSpec) {
+ ivBytes = ((IvParameterSpec)params).getIV();
+ if ((ivBytes == null) || (ivBytes.length != blockSize)) {
+ throw new InvalidAlgorithmParameterException
+ ("Wrong IV length: must be " + blockSize +
+ " bytes long");
+ }
+ } else if (params instanceof RC2ParameterSpec) {
+ ivBytes = ((RC2ParameterSpec)params).getIV();
+ if ((ivBytes != null) && (ivBytes.length != blockSize)) {
+ throw new InvalidAlgorithmParameterException
+ ("Wrong IV length: must be " + blockSize +
+ " bytes long");
+ }
+ } else {
+ throw new InvalidAlgorithmParameterException
+ ("Unsupported parameter: " + params);
+ }
}
- } else if (params instanceof RC2ParameterSpec) {
- ivBytes = ((RC2ParameterSpec)params).getIV();
- if ((ivBytes != null) && (ivBytes.length != blockSize)) {
- throw new InvalidAlgorithmParameterException
- ("Wrong IV length: must be " + blockSize +
- " bytes long");
- }
- } else {
- throw new InvalidAlgorithmParameterException("Wrong parameter "
- + "type: IV "
- + "expected");
}
-
if (cipherMode == ECB_MODE) {
if (ivBytes != null) {
throw new InvalidAlgorithmParameterException
("ECB mode cannot use IV");
}
- } else if (ivBytes == null) {
+ } else if (ivBytes == null) {
if (decrypting) {
throw new InvalidAlgorithmParameterException("Parameters "
+ "missing");
}
+
if (random == null) {
random = SunJCE.RANDOM;
}
- ivBytes = new byte[blockSize];
+ if (cipherMode == GCM_MODE) {
+ ivBytes = new byte[GaloisCounterMode.DEFAULT_IV_LEN];
+ } else {
+ ivBytes = new byte[blockSize];
+ }
random.nextBytes(ivBytes);
}
@@ -466,23 +579,57 @@ final class CipherCore {
String algorithm = key.getAlgorithm();
- cipher.init(decrypting, algorithm, keyBytes, ivBytes);
+ // GCM mode needs additional handling
+ if (cipherMode == GCM_MODE) {
+ if(tagLen == -1) {
+ tagLen = GaloisCounterMode.DEFAULT_TAG_LEN;
+ }
+ if (decrypting) {
+ minBytes = tagLen;
+ } else {
+ // check key+iv for encryption in GCM mode
+ requireReinit =
+ Arrays.equals(ivBytes, lastEncIv) &&
+ Arrays.equals(keyBytes, lastEncKey);
+ if (requireReinit) {
+ throw new InvalidAlgorithmParameterException
+ ("Cannot reuse iv for GCM encryption");
+ }
+ lastEncIv = ivBytes;
+ lastEncKey = keyBytes;
+ }
+ ((GaloisCounterMode) cipher).init
+ (decrypting, algorithm, keyBytes, ivBytes, tagLen);
+ } else {
+ cipher.init(decrypting, algorithm, keyBytes, ivBytes);
+ }
+ // skip checking key+iv from now on until after doFinal()
+ requireReinit = false;
}
void init(int opmode, Key key, AlgorithmParameters params,
SecureRandom random)
throws InvalidKeyException, InvalidAlgorithmParameterException {
- IvParameterSpec ivSpec = null;
+ AlgorithmParameterSpec spec = null;
+ String paramType = null;
if (params != null) {
try {
- ivSpec = params.getParameterSpec(IvParameterSpec.class);
+ if (cipherMode == GCM_MODE) {
+ paramType = "GCM";
+ spec = params.getParameterSpec(GCMParameterSpec.class);
+ } else {
+ // NOTE: RC2 parameters are always handled through
+ // init(..., AlgorithmParameterSpec,...) method, so
+ // we can assume IvParameterSpec type here.
+ paramType = "IV";
+ spec = params.getParameterSpec(IvParameterSpec.class);
+ }
} catch (InvalidParameterSpecException ipse) {
- throw new InvalidAlgorithmParameterException("Wrong parameter "
- + "type: IV "
- + "expected");
+ throw new InvalidAlgorithmParameterException
+ ("Wrong parameter type: " + paramType + " expected");
}
}
- init(opmode, key, ivSpec, random);
+ init(opmode, key, spec, random);
}
/**
@@ -504,6 +651,7 @@ final class CipherCore {
return keyBytes;
}
+
/**
* Continues a multiple-part encryption or decryption operation
* (depending on how this cipher was initialized), processing another data
@@ -524,22 +672,25 @@ final class CipherCore {
* (e.g., has not been initialized)
*/
byte[] update(byte[] input, int inputOffset, int inputLen) {
+ if (requireReinit) {
+ throw new IllegalStateException
+ ("Must use either different key or iv for GCM encryption");
+ }
+
byte[] output = null;
- byte[] out = null;
try {
- output = new byte[getOutputSize(inputLen)];
+ output = new byte[getOutputSizeByOperation(inputLen, false)];
int len = update(input, inputOffset, inputLen, output,
0);
if (len == output.length) {
- out = output;
+ return output;
} else {
- out = new byte[len];
- System.arraycopy(output, 0, out, 0, len);
+ return Arrays.copyOf(output, len);
}
} catch (ShortBufferException e) {
- // never thrown
+ // should never happen
+ throw new ProviderException("Unexpected exception", e);
}
- return out;
}
/**
@@ -567,6 +718,11 @@ final class CipherCore {
*/
int update(byte[] input, int inputOffset, int inputLen, byte[] output,
int outputOffset) throws ShortBufferException {
+ if (requireReinit) {
+ throw new IllegalStateException
+ ("Must use either different key or iv for GCM encryption");
+ }
+
// figure out how much can be sent to crypto function
int len = buffered + inputLen - minBytes;
if (padding != null && decrypting) {
@@ -582,6 +738,7 @@ final class CipherCore {
+ "(at least) " + len
+ " bytes long");
}
+
if (len != 0) {
// there is some work to do
byte[] in = new byte[len];
@@ -600,7 +757,6 @@ final class CipherCore {
System.arraycopy(input, inputOffset, in,
bufferedConsumed, inputConsumed);
}
-
if (decrypting) {
cipher.decrypt(in, 0, len, output, outputOffset);
} else {
@@ -611,11 +767,12 @@ final class CipherCore {
// the total input length a multiple of blocksize when
// padding is applied
if (unitBytes != blockSize) {
- if (len < diffBlocksize)
+ if (len < diffBlocksize) {
diffBlocksize -= len;
- else
+ } else {
diffBlocksize = blockSize -
((len - diffBlocksize) % blockSize);
+ }
}
inputLen -= inputConsumed;
@@ -669,21 +826,18 @@ final class CipherCore {
byte[] doFinal(byte[] input, int inputOffset, int inputLen)
throws IllegalBlockSizeException, BadPaddingException {
byte[] output = null;
- byte[] out = null;
try {
- output = new byte[getOutputSize(inputLen)];
+ output = new byte[getOutputSizeByOperation(inputLen, true)];
int len = doFinal(input, inputOffset, inputLen, output, 0);
if (len < output.length) {
- out = new byte[len];
- if (len != 0)
- System.arraycopy(output, 0, out, 0, len);
+ return Arrays.copyOf(output, len);
} else {
- out = output;
+ return output;
}
} catch (ShortBufferException e) {
// never thrown
+ throw new ProviderException("Unexpected exception", e);
}
- return out;
}
/**
@@ -726,6 +880,10 @@ final class CipherCore {
int outputOffset)
throws IllegalBlockSizeException, ShortBufferException,
BadPaddingException {
+ if (requireReinit) {
+ throw new IllegalStateException
+ ("Must use either different key or iv for GCM encryption");
+ }
// calculate the total input length
int totalLen = buffered + inputLen;
@@ -752,8 +910,9 @@ final class CipherCore {
}
// if encrypting and padding not null, add padding
- if (!decrypting && padding != null)
+ if (!decrypting && padding != null) {
paddedLen += paddingLen;
+ }
// check output buffer capacity.
// if we are decrypting with padding applied, we can perform this
@@ -763,8 +922,8 @@ final class CipherCore {
throw new ShortBufferException("Output buffer is null");
}
int outputCapacity = output.length - outputOffset;
- if (((!decrypting) || (padding == null)) &&
- (outputCapacity < paddedLen) ||
+
+ if (((!decrypting) && (outputCapacity < paddedLen)) ||
(decrypting && (outputCapacity < (paddedLen - blockSize)))) {
throw new ShortBufferException("Output buffer too short: "
+ outputCapacity + " bytes given, "
@@ -812,6 +971,7 @@ final class CipherCore {
}
totalLen = padStart;
}
+
if ((output.length - outputOffset) < totalLen) {
// restore so users can retry with a larger buffer
cipher.restore();
@@ -824,8 +984,13 @@ final class CipherCore {
output[outputOffset + i] = outWithPadding[i];
}
} else { // encrypting
- totalLen = finalNoPadding(finalBuf, finalOffset, output,
- outputOffset, paddedLen);
+ try {
+ totalLen = finalNoPadding(finalBuf, finalOffset, output,
+ outputOffset, paddedLen);
+ } finally {
+ // reset after doFinal() for GCM encryption
+ requireReinit = (cipherMode == GCM_MODE);
+ }
}
buffered = 0;
@@ -836,33 +1001,33 @@ final class CipherCore {
return totalLen;
}
- private int finalNoPadding(byte[] in, int inOff, byte[] out, int outOff,
+ private int finalNoPadding(byte[] in, int inOfs, byte[] out, int outOfs,
int len)
- throws IllegalBlockSizeException
- {
- if (in == null || len == 0)
+ throws IllegalBlockSizeException, AEADBadTagException {
+
+ if ((cipherMode != GCM_MODE) && (in == null || len == 0)) {
return 0;
-
- if ((cipherMode != CFB_MODE) && (cipherMode != OFB_MODE)
- && ((len % unitBytes) != 0) && (cipherMode != CTS_MODE)) {
- if (padding != null) {
- throw new IllegalBlockSizeException
- ("Input length (with padding) not multiple of " +
- unitBytes + " bytes");
- } else {
- throw new IllegalBlockSizeException
- ("Input length not multiple of " + unitBytes
- + " bytes");
- }
}
-
+ if ((cipherMode != CFB_MODE) && (cipherMode != OFB_MODE) &&
+ (cipherMode != GCM_MODE) &&
+ ((len % unitBytes) != 0) && (cipherMode != CTS_MODE)) {
+ if (padding != null) {
+ throw new IllegalBlockSizeException
+ ("Input length (with padding) not multiple of " +
+ unitBytes + " bytes");
+ } else {
+ throw new IllegalBlockSizeException
+ ("Input length not multiple of " + unitBytes
+ + " bytes");
+ }
+ }
+ int outLen = 0;
if (decrypting) {
- cipher.decryptFinal(in, inOff, len, out, outOff);
+ outLen = cipher.decryptFinal(in, inOfs, len, out, outOfs);
} else {
- cipher.encryptFinal(in, inOff, len, out, outOff);
+ outLen = cipher.encryptFinal(in, inOfs, len, out, outOfs);
}
-
- return len;
+ return outLen;
}
// Note: Wrap() and Unwrap() are the same in
@@ -939,4 +1104,36 @@ final class CipherCore {
return ConstructKeys.constructKey(encodedKey, wrappedKeyAlgorithm,
wrappedKeyType);
}
+
+ /**
+ * Continues a multi-part update of the Additional Authentication
+ * Data (AAD), using a subset of the provided buffer.
+ *
+ * Calls to this method provide AAD to the cipher when operating in
+ * modes such as AEAD (GCM/CCM). If this cipher is operating in
+ * either GCM or CCM mode, all AAD must be supplied before beginning
+ * operations on the ciphertext (via the {@code update} and {@code
+ * doFinal} methods).
+ *
+ * @param src the buffer containing the AAD
+ * @param offset the offset in {@code src} where the AAD input starts
+ * @param len the number of AAD bytes
+ *
+ * @throws IllegalStateException if this cipher is in a wrong state
+ * (e.g., has not been initialized), does not accept AAD, or if
+ * operating in either GCM or CCM mode and one of the {@code update}
+ * methods has already been called for the active
+ * encryption/decryption operation
+ * @throws UnsupportedOperationException if this method
+ * has not been overridden by an implementation
+ *
+ * @since 1.8
+ */
+ void updateAAD(byte[] src, int offset, int len) {
+ if (requireReinit) {
+ throw new IllegalStateException
+ ("Must use either different key or iv for GCM encryption");
+ }
+ cipher.updateAAD(src, offset, len);
+ }
}
diff --git a/jdk/src/share/classes/com/sun/crypto/provider/CipherTextStealing.java b/jdk/src/share/classes/com/sun/crypto/provider/CipherTextStealing.java
index ef77d3e5360..630f8707fde 100644
--- a/jdk/src/share/classes/com/sun/crypto/provider/CipherTextStealing.java
+++ b/jdk/src/share/classes/com/sun/crypto/provider/CipherTextStealing.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2013, 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
@@ -83,9 +83,10 @@ final class CipherTextStealing extends CipherBlockChaining {
* @param plainLen the length of the input data
* @param cipher the buffer for the result
* @param cipherOffset the offset in cipher
+ * @return the number of bytes placed into cipher
*/
- void encryptFinal(byte[] plain, int plainOffset, int plainLen,
- byte[] cipher, int cipherOffset)
+ int encryptFinal(byte[] plain, int plainOffset, int plainLen,
+ byte[] cipher, int cipherOffset)
throws IllegalBlockSizeException {
if (plainLen < blockSize) {
@@ -134,6 +135,7 @@ final class CipherTextStealing extends CipherBlockChaining {
embeddedCipher.encryptBlock(tmp2, 0, cipher, cipherOffset);
}
}
+ return plainLen;
}
/**
@@ -158,9 +160,10 @@ final class CipherTextStealing extends CipherBlockChaining {
* @param cipherLen the length of the input data
* @param plain the buffer for the result
* @param plainOffset the offset in plain
+ * @return the number of bytes placed into plain
*/
- void decryptFinal(byte[] cipher, int cipherOffset, int cipherLen,
- byte[] plain, int plainOffset)
+ int decryptFinal(byte[] cipher, int cipherOffset, int cipherLen,
+ byte[] plain, int plainOffset)
throws IllegalBlockSizeException {
if (cipherLen < blockSize) {
throw new IllegalBlockSizeException("input is too short!");
@@ -211,5 +214,6 @@ final class CipherTextStealing extends CipherBlockChaining {
}
}
}
+ return cipherLen;
}
}
diff --git a/jdk/src/share/classes/com/sun/crypto/provider/FeedbackCipher.java b/jdk/src/share/classes/com/sun/crypto/provider/FeedbackCipher.java
index 34b83ae928b..c27332457f3 100644
--- a/jdk/src/share/classes/com/sun/crypto/provider/FeedbackCipher.java
+++ b/jdk/src/share/classes/com/sun/crypto/provider/FeedbackCipher.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, 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
@@ -26,7 +26,7 @@
package com.sun.crypto.provider;
import java.security.InvalidKeyException;
-import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.*;
/**
* This class represents a block cipher in one of its modes. It wraps
@@ -150,11 +150,13 @@ abstract class FeedbackCipher {
* @param plainLen the length of the input data
* @param cipher the buffer for the encryption result
* @param cipherOffset the offset in cipher
+ * @return the number of bytes placed into cipher
*/
- void encryptFinal(byte[] plain, int plainOffset, int plainLen,
- byte[] cipher, int cipherOffset)
+ int encryptFinal(byte[] plain, int plainOffset, int plainLen,
+ byte[] cipher, int cipherOffset)
throws IllegalBlockSizeException {
encrypt(plain, plainOffset, plainLen, cipher, cipherOffset);
+ return plainLen;
}
/**
* Performs decryption operation.
@@ -190,10 +192,40 @@ abstract class FeedbackCipher {
* @param cipherLen the length of the input data
* @param plain the buffer for the decryption result
* @param plainOffset the offset in plain
+ * @return the number of bytes placed into plain
*/
- void decryptFinal(byte[] cipher, int cipherOffset, int cipherLen,
- byte[] plain, int plainOffset)
- throws IllegalBlockSizeException {
+ int decryptFinal(byte[] cipher, int cipherOffset, int cipherLen,
+ byte[] plain, int plainOffset)
+ throws IllegalBlockSizeException, AEADBadTagException {
decrypt(cipher, cipherOffset, cipherLen, plain, plainOffset);
+ return cipherLen;
}
+
+ /**
+ * Continues a multi-part update of the Additional Authentication
+ * Data (AAD), using a subset of the provided buffer. If this
+ * cipher is operating in either GCM or CCM mode, all AAD must be
+ * supplied before beginning operations on the ciphertext (via the
+ * {@code update} and {@code doFinal} methods).
+ *
+ * NOTE: Given most modes do not accept AAD, default impl for this
+ * method throws IllegalStateException.
+ *
+ * @param src the buffer containing the AAD
+ * @param offset the offset in {@code src} where the AAD input starts
+ * @param len the number of AAD bytes
+ *
+ * @throws IllegalStateException if this cipher is in a wrong state
+ * (e.g., has not been initialized), does not accept AAD, or if
+ * operating in either GCM or CCM mode and one of the {@code update}
+ * methods has already been called for the active
+ * encryption/decryption operation
+ * @throws UnsupportedOperationException if this method
+ * has not been overridden by an implementation
+ *
+ * @since 1.8
+ */
+ void updateAAD(byte[] src, int offset, int len) {
+ throw new IllegalStateException("No AAD accepted");
+ }
}
diff --git a/jdk/src/share/classes/com/sun/crypto/provider/GCMParameters.java b/jdk/src/share/classes/com/sun/crypto/provider/GCMParameters.java
new file mode 100644
index 00000000000..4ae729204a6
--- /dev/null
+++ b/jdk/src/share/classes/com/sun/crypto/provider/GCMParameters.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2013, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.crypto.provider;
+
+import java.io.IOException;
+import java.security.AlgorithmParametersSpi;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import javax.crypto.spec.GCMParameterSpec;
+import sun.misc.HexDumpEncoder;
+import sun.security.util.*;
+
+/**
+ * This class implements the parameter set used with
+ * GCM encryption, which is defined in RFC 5084 as follows:
+ *
+ *
+ *
+ * @author Valerie Peng
+ * @since 1.8
+ */
+public final class GCMParameters extends AlgorithmParametersSpi {
+
+ // the iv
+ private byte[] iv;
+ // the tag length in bytes
+ private int tLen;
+
+ public GCMParameters() {}
+
+ protected void engineInit(AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException {
+
+ if (!(paramSpec instanceof GCMParameterSpec)) {
+ throw new InvalidParameterSpecException
+ ("Inappropriate parameter specification");
+ }
+ GCMParameterSpec gps = (GCMParameterSpec) paramSpec;
+ // need to convert from bits to bytes for ASN.1 encoding
+ this.tLen = gps.getTLen()/8;
+ this.iv = gps.getIV();
+ }
+
+ protected void engineInit(byte[] encoded) throws IOException {
+ DerValue val = new DerValue(encoded);
+ // check if IV or params
+ if (val.tag == DerValue.tag_Sequence) {
+ byte[] iv = val.data.getOctetString();
+ int tLen;
+ if (val.data.available() != 0) {
+ tLen = val.data.getInteger();
+ if (tLen < 12 || tLen > 16 ) {
+ throw new IOException
+ ("GCM parameter parsing error: unsupported tag len: " +
+ tLen);
+ }
+ if (val.data.available() != 0) {
+ throw new IOException
+ ("GCM parameter parsing error: extra data");
+ }
+ } else {
+ tLen = 12;
+ }
+ this.iv = iv.clone();
+ this.tLen = tLen;
+ } else {
+ throw new IOException("GCM parameter parsing error: no SEQ tag");
+ }
+ }
+
+ protected void engineInit(byte[] encoded, String decodingMethod)
+ throws IOException {
+ engineInit(encoded);
+ }
+
+ protected
+ T engineGetParameterSpec(Class paramSpec)
+ throws InvalidParameterSpecException {
+
+ if (GCMParameterSpec.class.isAssignableFrom(paramSpec)) {
+ return paramSpec.cast(new GCMParameterSpec(tLen * 8, iv));
+ } else {
+ throw new InvalidParameterSpecException
+ ("Inappropriate parameter specification");
+ }
+ }
+
+ protected byte[] engineGetEncoded() throws IOException {
+ DerOutputStream out = new DerOutputStream();
+ DerOutputStream bytes = new DerOutputStream();
+
+ bytes.putOctetString(iv);
+ bytes.putInteger(tLen);
+ out.write(DerValue.tag_Sequence, bytes);
+ return out.toByteArray();
+ }
+
+ protected byte[] engineGetEncoded(String encodingMethod)
+ throws IOException {
+ return engineGetEncoded();
+ }
+
+ /*
+ * Returns a formatted string describing the parameters.
+ */
+ protected String engineToString() {
+ String LINE_SEP = System.getProperty("line.separator");
+ HexDumpEncoder encoder = new HexDumpEncoder();
+ StringBuilder sb
+ = new StringBuilder(LINE_SEP + " iv:" + LINE_SEP + "["
+ + encoder.encodeBuffer(iv) + "]");
+
+ sb.append(LINE_SEP + "tLen(bits):" + LINE_SEP + tLen*8 + LINE_SEP);
+ return sb.toString();
+ }
+}
diff --git a/jdk/src/share/classes/com/sun/crypto/provider/GCTR.java b/jdk/src/share/classes/com/sun/crypto/provider/GCTR.java
new file mode 100644
index 00000000000..74d3555cc58
--- /dev/null
+++ b/jdk/src/share/classes/com/sun/crypto/provider/GCTR.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2013, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright IBM Corp. 2013
+ */
+
+package com.sun.crypto.provider;
+
+import java.security.*;
+import javax.crypto.*;
+import static com.sun.crypto.provider.AESConstants.AES_BLOCK_SIZE;
+
+/**
+ * This class represents the GCTR function defined in NIST 800-38D
+ * under section 6.5. It needs to be constructed w/ an initialized
+ * cipher object, and initial counter block(ICB). Given an input X
+ * of arbitrary length, it processes and returns an output which has
+ * the same length as X.
+ *
+ *
This function is used in the implementation of GCM mode.
+ *
+ * @since 1.8
+ */
+final class GCTR {
+
+ // these fields should not change after the object has been constructed
+ private final SymmetricCipher aes;
+ private final byte[] icb;
+
+ // the current counter value
+ private byte[] counter;
+
+ // needed for save/restore calls
+ private byte[] counterSave;
+
+ // NOTE: cipher should already be initialized
+ GCTR(SymmetricCipher cipher, byte[] initialCounterBlk) {
+ this.aes = cipher;
+ this.icb = initialCounterBlk;
+ this.counter = icb.clone();
+ }
+
+ // input must be multiples of 128-bit blocks when calling update
+ int update(byte[] in, int inOfs, int inLen, byte[] out, int outOfs) {
+ if (inLen - inOfs > in.length) {
+ throw new RuntimeException("input length out of bound");
+ }
+ if (inLen < 0 || inLen % AES_BLOCK_SIZE != 0) {
+ throw new RuntimeException("input length unsupported");
+ }
+ if (out.length - outOfs < inLen) {
+ throw new RuntimeException("output buffer too small");
+ }
+
+ byte[] encryptedCntr = new byte[AES_BLOCK_SIZE];
+
+ int numOfCompleteBlocks = inLen / AES_BLOCK_SIZE;
+ for (int i = 0; i < numOfCompleteBlocks; i++) {
+ aes.encryptBlock(counter, 0, encryptedCntr, 0);
+ for (int n = 0; n < AES_BLOCK_SIZE; n++) {
+ int index = (i * AES_BLOCK_SIZE + n);
+ out[outOfs + index] =
+ (byte) ((in[inOfs + index] ^ encryptedCntr[n]));
+ }
+ GaloisCounterMode.increment32(counter);
+ }
+ return inLen;
+ }
+
+ // input can be arbitrary size when calling doFinal
+ protected int doFinal(byte[] in, int inOfs, int inLen, byte[] out,
+ int outOfs) throws IllegalBlockSizeException {
+ try {
+ if (inLen < 0) {
+ throw new IllegalBlockSizeException("Negative input size!");
+ } else if (inLen > 0) {
+ int lastBlockSize = inLen % AES_BLOCK_SIZE;
+ // process the complete blocks first
+ update(in, inOfs, inLen - lastBlockSize, out, outOfs);
+ if (lastBlockSize != 0) {
+ // do the last partial block
+ byte[] encryptedCntr = new byte[AES_BLOCK_SIZE];
+ aes.encryptBlock(counter, 0, encryptedCntr, 0);
+
+ int processed = inLen - lastBlockSize;
+ for (int n = 0; n < lastBlockSize; n++) {
+ out[outOfs + processed + n] =
+ (byte) ((in[inOfs + processed + n] ^
+ encryptedCntr[n]));
+ }
+ }
+ }
+ } finally {
+ reset();
+ }
+ return inLen;
+ }
+
+ /**
+ * Resets the current counter to its initial value.
+ * This is used after the doFinal() is called so this object can be
+ * reused w/o explicit re-initialization.
+ */
+ void reset() {
+ System.arraycopy(icb, 0, counter, 0, icb.length);
+ }
+
+ /**
+ * Save the current content of this object.
+ */
+ void save() {
+ this.counterSave = this.counter.clone();
+ }
+
+ /**
+ * Restores the content of this object to the previous saved one.
+ */
+ void restore() {
+ this.counter = this.counterSave;
+ }
+}
diff --git a/jdk/src/share/classes/com/sun/crypto/provider/GHASH.java b/jdk/src/share/classes/com/sun/crypto/provider/GHASH.java
new file mode 100644
index 00000000000..8b0ba28e898
--- /dev/null
+++ b/jdk/src/share/classes/com/sun/crypto/provider/GHASH.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2013, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * (C) Copyright IBM Corp. 2013
+ */
+
+package com.sun.crypto.provider;
+
+import java.util.Arrays;
+import java.security.*;
+import static com.sun.crypto.provider.AESConstants.AES_BLOCK_SIZE;
+
+/**
+ * This class represents the GHASH function defined in NIST 800-38D
+ * under section 6.4. It needs to be constructed w/ a hash subkey, i.e.
+ * block H. Given input of 128-bit blocks, it will process and output
+ * a 128-bit block.
+ *
+ *
This function is used in the implementation of GCM mode.
+ *
+ * @since 1.8
+ */
+final class GHASH {
+
+ private static final byte P128 = (byte) 0xe1; //reduction polynomial
+
+ private static boolean getBit(byte[] b, int pos) {
+ int p = pos / 8;
+ pos %= 8;
+ int i = (b[p] >>> (7 - pos)) & 1;
+ return i != 0;
+ }
+
+ private static void shift(byte[] b) {
+ byte temp, temp2;
+ temp2 = 0;
+ for (int i = 0; i < b.length; i++) {
+ temp = (byte) ((b[i] & 0x01) << 7);
+ b[i] = (byte) ((b[i] & 0xff) >>> 1);
+ b[i] = (byte) (b[i] | temp2);
+ temp2 = temp;
+ }
+ }
+
+ // Given block X and Y, returns the muliplication of X * Y
+ private static byte[] blockMult(byte[] x, byte[] y) {
+ if (x.length != AES_BLOCK_SIZE || y.length != AES_BLOCK_SIZE) {
+ throw new RuntimeException("illegal input sizes");
+ }
+ byte[] z = new byte[AES_BLOCK_SIZE];
+ byte[] v = y.clone();
+ // calculate Z1-Z127 and V1-V127
+ for (int i = 0; i < 127; i++) {
+ // Zi+1 = Zi if bit i of x is 0
+ if (getBit(x, i)) {
+ for (int n = 0; n < z.length; n++) {
+ z[n] ^= v[n];
+ }
+ }
+ boolean lastBitOfV = getBit(v, 127);
+ shift(v);
+ if (lastBitOfV) v[0] ^= P128;
+ }
+ // calculate Z128
+ if (getBit(x, 127)) {
+ for (int n = 0; n < z.length; n++) {
+ z[n] ^= v[n];
+ }
+ }
+ return z;
+ }
+
+ // hash subkey H; should not change after the object has been constructed
+ private final byte[] subkeyH;
+
+ // buffer for storing hash
+ private byte[] state;
+
+ // variables for save/restore calls
+ private byte[] stateSave = null;
+
+ /**
+ * Initializes the cipher in the specified mode with the given key
+ * and iv.
+ *
+ * @param subkeyH the hash subkey
+ *
+ * @exception ProviderException if the given key is inappropriate for
+ * initializing this digest
+ */
+ GHASH(byte[] subkeyH) throws ProviderException {
+ if ((subkeyH == null) || subkeyH.length != AES_BLOCK_SIZE) {
+ throw new ProviderException("Internal error");
+ }
+ this.subkeyH = subkeyH;
+ this.state = new byte[AES_BLOCK_SIZE];
+ }
+
+ /**
+ * Resets the GHASH object to its original state, i.e. blank w/
+ * the same subkey H. Used after digest() is called and to re-use
+ * this object for different data w/ the same H.
+ */
+ void reset() {
+ Arrays.fill(state, (byte) 0);
+ }
+
+ /**
+ * Save the current snapshot of this GHASH object.
+ */
+ void save() {
+ stateSave = state.clone();
+ }
+
+ /**
+ * Restores this object using the saved snapshot.
+ */
+ void restore() {
+ state = stateSave;
+ }
+
+ private void processBlock(byte[] data, int ofs) {
+ if (data.length - ofs < AES_BLOCK_SIZE) {
+ throw new RuntimeException("need complete block");
+ }
+ for (int n = 0; n < state.length; n++) {
+ state[n] ^= data[ofs + n];
+ }
+ state = blockMult(state, subkeyH);
+ }
+
+ void update(byte[] in) {
+ update(in, 0, in.length);
+ }
+
+ void update(byte[] in, int inOfs, int inLen) {
+ if (inLen - inOfs > in.length) {
+ throw new RuntimeException("input length out of bound");
+ }
+ if (inLen % AES_BLOCK_SIZE != 0) {
+ throw new RuntimeException("input length unsupported");
+ }
+
+ for (int i = inOfs; i < (inOfs + inLen); i += AES_BLOCK_SIZE) {
+ processBlock(in, i);
+ }
+ }
+
+ byte[] digest() {
+ try {
+ return state.clone();
+ } finally {
+ reset();
+ }
+ }
+}
diff --git a/jdk/src/share/classes/com/sun/crypto/provider/GaloisCounterMode.java b/jdk/src/share/classes/com/sun/crypto/provider/GaloisCounterMode.java
new file mode 100644
index 00000000000..a2c6cfd82ef
--- /dev/null
+++ b/jdk/src/share/classes/com/sun/crypto/provider/GaloisCounterMode.java
@@ -0,0 +1,501 @@
+/*
+ * Copyright (c) 2013, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.S
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.crypto.provider;
+
+import java.util.Arrays;
+import java.io.*;
+import java.security.*;
+import javax.crypto.*;
+import static com.sun.crypto.provider.AESConstants.AES_BLOCK_SIZE;
+
+/**
+ * This class represents ciphers in GaloisCounter (GCM) mode.
+ *
+ *
This mode currently should only be used w/ AES cipher.
+ * Although no checking is done here, caller should only
+ * pass AES Cipher to the constructor.
+ *
+ *
NOTE: This class does not deal with buffering or padding.
+ *
+ * @since 1.8
+ */
+final class GaloisCounterMode extends FeedbackCipher {
+
+ static int DEFAULT_TAG_LEN = AES_BLOCK_SIZE;
+ static int DEFAULT_IV_LEN = 12; // in bytes
+
+ // buffer for AAD data; if null, meaning update has been called
+ private ByteArrayOutputStream aadBuffer = new ByteArrayOutputStream();
+ private int sizeOfAAD = 0;
+
+ // in bytes; need to convert to bits (default value 128) when needed
+ private int tagLenBytes = DEFAULT_TAG_LEN;
+
+ // these following 2 fields can only be initialized after init() is
+ // called, e.g. after cipher key k is set, and STAY UNCHANGED
+ private byte[] subkeyH = null;
+ private byte[] preCounterBlock = null;
+
+ private GCTR gctrPAndC = null;
+ private GHASH ghashAllToS = null;
+
+ // length of total data, i.e. len(C)
+ private int processed = 0;
+
+ // additional variables for save/restore calls
+ private byte[] aadBufferSave = null;
+ private int sizeOfAADSave = 0;
+ private int processedSave = 0;
+
+ // value must be 16-byte long; used by GCTR and GHASH as well
+ static void increment32(byte[] value) {
+ if (value.length != AES_BLOCK_SIZE) {
+ throw new RuntimeException("Unexpected counter block length");
+ }
+ // start from last byte and only go over 4 bytes, i.e. total 32 bits
+ int n = value.length - 1;
+ while ((n >= value.length - 4) && (++value[n] == 0)) {
+ n--;
+ }
+ }
+
+ // ivLen in bits
+ private static byte[] getLengthBlock(int ivLen) {
+ byte[] out = new byte[AES_BLOCK_SIZE];
+ out[12] = (byte)(ivLen >>> 24);
+ out[13] = (byte)(ivLen >>> 16);
+ out[14] = (byte)(ivLen >>> 8);
+ out[15] = (byte)ivLen;
+ return out;
+ }
+
+ // aLen and cLen both in bits
+ private static byte[] getLengthBlock(int aLen, int cLen) {
+ byte[] out = new byte[AES_BLOCK_SIZE];
+ out[4] = (byte)(aLen >>> 24);
+ out[5] = (byte)(aLen >>> 16);
+ out[6] = (byte)(aLen >>> 8);
+ out[7] = (byte)aLen;
+ out[12] = (byte)(cLen >>> 24);
+ out[13] = (byte)(cLen >>> 16);
+ out[14] = (byte)(cLen >>> 8);
+ out[15] = (byte)cLen;
+ return out;
+ }
+
+ private static byte[] expandToOneBlock(byte[] in, int inOfs, int len) {
+ if (len > AES_BLOCK_SIZE) {
+ throw new ProviderException("input " + len + " too long");
+ }
+ if (len == AES_BLOCK_SIZE && inOfs == 0) {
+ return in;
+ } else {
+ byte[] paddedIn = new byte[AES_BLOCK_SIZE];
+ System.arraycopy(in, inOfs, paddedIn, 0, len);
+ return paddedIn;
+ }
+ }
+
+ private static byte[] getJ0(byte[] iv, byte[] subkeyH) {
+ byte[] j0;
+ if (iv.length == 12) { // 96 bits
+ j0 = expandToOneBlock(iv, 0, iv.length);
+ j0[AES_BLOCK_SIZE - 1] = 1;
+ } else {
+ GHASH g = new GHASH(subkeyH);
+ int lastLen = iv.length % AES_BLOCK_SIZE;
+ if (lastLen != 0) {
+ g.update(iv, 0, iv.length - lastLen);
+ byte[] padded =
+ expandToOneBlock(iv, iv.length - lastLen, lastLen);
+ g.update(padded);
+ } else {
+ g.update(iv);
+ }
+ byte[] lengthBlock = getLengthBlock(iv.length*8);
+ g.update(lengthBlock);
+ j0 = g.digest();
+ }
+ return j0;
+ }
+
+ GaloisCounterMode(SymmetricCipher embeddedCipher) {
+ super(embeddedCipher);
+ aadBuffer = new ByteArrayOutputStream();
+ }
+
+ /**
+ * Gets the name of the feedback mechanism
+ *
+ * @return the name of the feedback mechanism
+ */
+ String getFeedback() {
+ return "GCM";
+ }
+
+ /**
+ * Resets the cipher object to its original state.
+ * This is used when doFinal is called in the Cipher class, so that the
+ * cipher can be reused (with its original key and iv).
+ */
+ void reset() {
+ if (aadBuffer == null) {
+ aadBuffer = new ByteArrayOutputStream();
+ } else {
+ aadBuffer.reset();
+ }
+ if (gctrPAndC != null) gctrPAndC.reset();
+ if (ghashAllToS != null) ghashAllToS.reset();
+ processed = 0;
+ sizeOfAAD = 0;
+ }
+
+ /**
+ * Save the current content of this cipher.
+ */
+ void save() {
+ processedSave = processed;
+ sizeOfAADSave = sizeOfAAD;
+ aadBufferSave =
+ ((aadBuffer == null || aadBuffer.size() == 0)?
+ null : aadBuffer.toByteArray());
+ if (gctrPAndC != null) gctrPAndC.save();
+ if (ghashAllToS != null) ghashAllToS.save();
+ }
+
+ /**
+ * Restores the content of this cipher to the previous saved one.
+ */
+ void restore() {
+ processed = processedSave;
+ sizeOfAAD = sizeOfAADSave;
+ if (aadBuffer != null) {
+ aadBuffer.reset();
+ if (aadBufferSave != null) {
+ aadBuffer.write(aadBufferSave, 0, aadBufferSave.length);
+ }
+ }
+ if (gctrPAndC != null) gctrPAndC.restore();
+ if (ghashAllToS != null) ghashAllToS.restore();
+ }
+
+ /**
+ * Initializes the cipher in the specified mode with the given key
+ * and iv.
+ *
+ * @param decrypting flag indicating encryption or decryption
+ * @param algorithm the algorithm name
+ * @param key the key
+ * @param iv the iv
+ * @param tagLenBytes the length of tag in bytes
+ *
+ * @exception InvalidKeyException if the given key is inappropriate for
+ * initializing this cipher
+ */
+ void init(boolean decrypting, String algorithm, byte[] key, byte[] iv)
+ throws InvalidKeyException {
+ init(decrypting, algorithm, key, iv, DEFAULT_TAG_LEN);
+ }
+
+ /**
+ * Initializes the cipher in the specified mode with the given key
+ * and iv.
+ *
+ * @param decrypting flag indicating encryption or decryption
+ * @param algorithm the algorithm name
+ * @param key the key
+ * @param iv the iv
+ * @param tagLenBytes the length of tag in bytes
+ *
+ * @exception InvalidKeyException if the given key is inappropriate for
+ * initializing this cipher
+ */
+ void init(boolean decrypting, String algorithm, byte[] keyValue,
+ byte[] ivValue, int tagLenBytes)
+ throws InvalidKeyException {
+ if (keyValue == null || ivValue == null) {
+ throw new InvalidKeyException("Internal error");
+ }
+
+ // always encrypt mode for embedded cipher
+ this.embeddedCipher.init(false, algorithm, keyValue);
+ this.subkeyH = new byte[AES_BLOCK_SIZE];
+ this.embeddedCipher.encryptBlock(new byte[AES_BLOCK_SIZE], 0,
+ this.subkeyH, 0);
+
+ this.iv = ivValue.clone();
+ preCounterBlock = getJ0(iv, subkeyH);
+ byte[] j0Plus1 = preCounterBlock.clone();
+ increment32(j0Plus1);
+ gctrPAndC = new GCTR(embeddedCipher, j0Plus1);
+ ghashAllToS = new GHASH(subkeyH);
+
+ this.tagLenBytes = tagLenBytes;
+ if (aadBuffer == null) {
+ aadBuffer = new ByteArrayOutputStream();
+ } else {
+ aadBuffer.reset();
+ }
+ processed = 0;
+ sizeOfAAD = 0;
+ }
+
+ /**
+ * Continues a multi-part update of the Additional Authentication
+ * Data (AAD), using a subset of the provided buffer. If this
+ * cipher is operating in either GCM or CCM mode, all AAD must be
+ * supplied before beginning operations on the ciphertext (via the
+ * {@code update} and {@code doFinal} methods).
+ *
+ * NOTE: Given most modes do not accept AAD, default impl for this
+ * method throws IllegalStateException.
+ *
+ * @param src the buffer containing the AAD
+ * @param offset the offset in {@code src} where the AAD input starts
+ * @param len the number of AAD bytes
+ *
+ * @throws IllegalStateException if this cipher is in a wrong state
+ * (e.g., has not been initialized), does not accept AAD, or if
+ * operating in either GCM or CCM mode and one of the {@code update}
+ * methods has already been called for the active
+ * encryption/decryption operation
+ * @throws UnsupportedOperationException if this method
+ * has not been overridden by an implementation
+ *
+ * @since 1.8
+ */
+ void updateAAD(byte[] src, int offset, int len) {
+ if (aadBuffer != null) {
+ aadBuffer.write(src, offset, len);
+ } else {
+ // update has already been called
+ throw new IllegalStateException
+ ("Update has been called; no more AAD data");
+ }
+ }
+
+ // Feed the AAD data to GHASH, pad if necessary
+ void processAAD() {
+ if (aadBuffer != null) {
+ byte[] aad = aadBuffer.toByteArray();
+ sizeOfAAD = aad.length;
+ aadBuffer = null;
+
+ int lastLen = aad.length % AES_BLOCK_SIZE;
+ if (lastLen != 0) {
+ ghashAllToS.update(aad, 0, aad.length - lastLen);
+ byte[] padded = expandToOneBlock(aad, aad.length - lastLen,
+ lastLen);
+ ghashAllToS.update(padded);
+ } else {
+ ghashAllToS.update(aad);
+ }
+ }
+ }
+
+ // Utility to process the last block; used by encryptFinal and decryptFinal
+ void doLastBlock(byte[] in, int inOfs, int len, byte[] out, int outOfs,
+ boolean isEncrypt) throws IllegalBlockSizeException {
+ // process data in 'in'
+ gctrPAndC.doFinal(in, inOfs, len, out, outOfs);
+ processed += len;
+
+ byte[] ct;
+ int ctOfs;
+ if (isEncrypt) {
+ ct = out;
+ ctOfs = outOfs;
+ } else {
+ ct = in;
+ ctOfs = inOfs;
+ }
+ int lastLen = len % AES_BLOCK_SIZE;
+ if (lastLen != 0) {
+ ghashAllToS.update(ct, ctOfs, len - lastLen);
+ byte[] padded =
+ expandToOneBlock(ct, (ctOfs + len - lastLen), lastLen);
+ ghashAllToS.update(padded);
+ } else {
+ ghashAllToS.update(ct, ctOfs, len);
+ }
+ }
+
+
+ /**
+ * Performs encryption operation.
+ *
+ *
The input plain text in, starting at inOff
+ * and ending at (inOff + len - 1), is encrypted. The result
+ * is stored in out, starting at outOfs.
+ *
+ *
It is the application's responsibility to make sure that
+ * len is a multiple of the embedded cipher's block size,
+ * otherwise, a ProviderException will be thrown.
+ *
+ *
It is also the application's responsibility to make sure that
+ * init has been called before this method is called.
+ * (This check is omitted here, to avoid double checking.)
+ *
+ * @param in the buffer with the input data to be encrypted
+ * @param inOfs the offset in in
+ * @param len the length of the input data
+ * @param out the buffer for the result
+ * @param outOfs the offset in out
+ */
+ void encrypt(byte[] in, int inOfs, int len, byte[] out, int outOfs) {
+ processAAD();
+ if (len > 0) {
+ gctrPAndC.update(in, inOfs, len, out, outOfs);
+ processed += len;
+ ghashAllToS.update(out, outOfs, len);
+ }
+ }
+
+ /**
+ * Performs encryption operation for the last time.
+ *
+ *
NOTE: len may not be multiple of the embedded
+ * cipher's block size for this call.
+ *
+ * @param in the input buffer with the data to be encrypted
+ * @param inOfs the offset in in
+ * @param len the length of the input data
+ * @param out the buffer for the encryption result
+ * @param outOfs the offset in out
+ * @return the number of bytes placed into the out buffer
+ */
+ int encryptFinal(byte[] in, int inOfs, int len, byte[] out, int outOfs)
+ throws IllegalBlockSizeException {
+ if (out.length - outOfs < (len + tagLenBytes)) {
+ throw new RuntimeException("Output buffer too small");
+ }
+
+ processAAD();
+ if (len > 0) {
+ //ByteUtil.dumpArray(Arrays.copyOfRange(in, inOfs, inOfs + len));
+ doLastBlock(in, inOfs, len, out, outOfs, true);
+ }
+
+ byte[] lengthBlock = getLengthBlock(sizeOfAAD*8, processed*8);
+ ghashAllToS.update(lengthBlock);
+ byte[] s = ghashAllToS.digest();
+ byte[] sOut = new byte[s.length];
+ GCTR gctrForSToTag = new GCTR(embeddedCipher, this.preCounterBlock);
+ gctrForSToTag.doFinal(s, 0, s.length, sOut, 0);
+
+ System.arraycopy(sOut, 0, out, (outOfs + len), tagLenBytes);
+ return (len + tagLenBytes);
+ }
+
+ /**
+ * Performs decryption operation.
+ *
+ *
The input cipher text in, starting at
+ * inOfs and ending at (inOfs + len - 1),
+ * is decrypted. The result is stored in out, starting at
+ * outOfs.
+ *
+ *
It is the application's responsibility to make sure that
+ * len is a multiple of the embedded cipher's block
+ * size, as any excess bytes are ignored.
+ *
+ *
It is also the application's responsibility to make sure that
+ * init has been called before this method is called.
+ * (This check is omitted here, to avoid double checking.)
+ *
+ * @param in the buffer with the input data to be decrypted
+ * @param inOfs the offset in in
+ * @param len the length of the input data
+ * @param out the buffer for the result
+ * @param outOfs the offset in out
+ */
+ void decrypt(byte[] in, int inOfs, int len, byte[] out, int outOfs) {
+ processAAD();
+
+ if (len > 0) { // must be at least AES_BLOCK_SIZE bytes long
+ gctrPAndC.update(in, inOfs, len, out, outOfs);
+ processed += len;
+ ghashAllToS.update(in, inOfs, len);
+ }
+ }
+
+ /**
+ * Performs decryption operation for the last time.
+ *
+ *
NOTE: For cipher feedback modes which does not perform
+ * special handling for the last few blocks, this is essentially
+ * the same as encrypt(...). Given most modes do
+ * not do special handling, the default impl for this method is
+ * to simply call decrypt(...).
+ *
+ * @param in the input buffer with the data to be decrypted
+ * @param inOfs the offset in cipher
+ * @param len the length of the input data
+ * @param out the buffer for the decryption result
+ * @param outOfs the offset in plain
+ * @return the number of bytes placed into the out buffer
+ */
+ int decryptFinal(byte[] in, int inOfs, int len,
+ byte[] out, int outOfs)
+ throws IllegalBlockSizeException, AEADBadTagException {
+ if (len < tagLenBytes) {
+ throw new RuntimeException("Input buffer too short - need tag");
+ }
+ if (out.length - outOfs < (len - tagLenBytes)) {
+ throw new RuntimeException("Output buffer too small");
+ }
+ processAAD();
+
+ int processedOld = processed;
+ byte[] tag = new byte[tagLenBytes];
+ // get the trailing tag bytes from 'in'
+ System.arraycopy(in, inOfs + len - tagLenBytes, tag, 0, tagLenBytes);
+ len -= tagLenBytes;
+
+ if (len > 0) {
+ doLastBlock(in, inOfs, len, out, outOfs, false);
+ }
+
+ byte[] lengthBlock = getLengthBlock(sizeOfAAD*8, processed*8);
+ ghashAllToS.update(lengthBlock);
+
+ byte[] s = ghashAllToS.digest();
+ byte[] sOut = new byte[s.length];
+ GCTR gctrForSToTag = new GCTR(embeddedCipher, this.preCounterBlock);
+ gctrForSToTag.doFinal(s, 0, s.length, sOut, 0);
+ for (int i = 0; i < tagLenBytes; i++) {
+ if (tag[i] != sOut[i]) {
+ throw new AEADBadTagException("Tag mismatch!");
+ }
+ }
+ return len;
+ }
+
+ // return tag length in bytes
+ int getTagLen() {
+ return this.tagLenBytes;
+ }
+}
diff --git a/jdk/src/share/classes/com/sun/crypto/provider/SunJCE.java b/jdk/src/share/classes/com/sun/crypto/provider/SunJCE.java
index 3edac42c6ba..9128495e40a 100644
--- a/jdk/src/share/classes/com/sun/crypto/provider/SunJCE.java
+++ b/jdk/src/share/classes/com/sun/crypto/provider/SunJCE.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, 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
@@ -57,6 +57,7 @@ import java.security.SecureRandom;
* - ARCFOUR (RC4 compatible)
*
* - Cipher modes ECB, CBC, CFB, OFB, PCBC, CTR, and CTS for all block ciphers
+ * and mode GCM for AES cipher
*
* - Cipher padding ISO10126Padding for non-PKCS#5 block ciphers and
* NoPadding and PKCS5Padding for all block ciphers
@@ -100,7 +101,7 @@ public final class SunJCE extends Provider {
"|CFB8|CFB16|CFB24|CFB32|CFB40|CFB48|CFB56|CFB64" +
"|OFB8|OFB16|OFB24|OFB32|OFB40|OFB48|OFB56|OFB64";
final String BLOCK_MODES128 = BLOCK_MODES +
- "|CFB72|CFB80|CFB88|CFB96|CFB104|CFB112|CFB120|CFB128" +
+ "|GCM|CFB72|CFB80|CFB88|CFB96|CFB104|CFB112|CFB120|CFB128" +
"|OFB72|OFB80|OFB88|OFB96|OFB104|OFB112|OFB120|OFB128";
final String BLOCK_PADS = "NOPADDING|PKCS5PADDING|ISO10126PADDING";
@@ -258,6 +259,9 @@ public final class SunJCE extends Provider {
put("Cipher.AES_128/CFB/NoPadding", "com.sun.crypto.provider.AESCipher$AES128_CFB_NoPadding");
put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.4", "AES_128/CFB/NoPadding");
put("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.4", "AES_128/CFB/NoPadding");
+ put("Cipher.AES_128/GCM/NoPadding", "com.sun.crypto.provider.AESCipher$AES128_GCM_NoPadding");
+ put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.6", "AES_128/GCM/NoPadding");
+ put("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.6", "AES_128/GCM/NoPadding");
put("Cipher.AES_192/ECB/NoPadding", "com.sun.crypto.provider.AESCipher$AES192_ECB_NoPadding");
put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.21", "AES_192/ECB/NoPadding");
@@ -271,7 +275,9 @@ public final class SunJCE extends Provider {
put("Cipher.AES_192/CFB/NoPadding", "com.sun.crypto.provider.AESCipher$AES192_CFB_NoPadding");
put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.24", "AES_192/CFB/NoPadding");
put("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.24", "AES_192/CFB/NoPadding");
-
+ put("Cipher.AES_192/GCM/NoPadding", "com.sun.crypto.provider.AESCipher$AES192_GCM_NoPadding");
+ put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.26", "AES_192/GCM/NoPadding");
+ put("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.26", "AES_192/GCM/NoPadding");
put("Cipher.AES_256/ECB/NoPadding", "com.sun.crypto.provider.AESCipher$AES256_ECB_NoPadding");
put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.41", "AES_256/ECB/NoPadding");
@@ -285,6 +291,9 @@ public final class SunJCE extends Provider {
put("Cipher.AES_256/CFB/NoPadding", "com.sun.crypto.provider.AESCipher$AES256_CFB_NoPadding");
put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.44", "AES_256/CFB/NoPadding");
put("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.44", "AES_256/CFB/NoPadding");
+ put("Cipher.AES_256/GCM/NoPadding", "com.sun.crypto.provider.AESCipher$AES256_GCM_NoPadding");
+ put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.46", "AES_256/GCM/NoPadding");
+ put("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.46", "AES_256/GCM/NoPadding");
put("Cipher.AESWrap", "com.sun.crypto.provider.AESWrapCipher$General");
put("Cipher.AESWrap SupportedModes", "ECB");
@@ -509,6 +518,8 @@ public final class SunJCE extends Provider {
put("AlgorithmParameters.AES",
"com.sun.crypto.provider.AESParameters");
put("Alg.Alias.AlgorithmParameters.Rijndael", "AES");
+ put("AlgorithmParameters.GCM",
+ "com.sun.crypto.provider.GCMParameters");
put("AlgorithmParameters.RC2",
diff --git a/jdk/src/share/classes/javax/crypto/Cipher.java b/jdk/src/share/classes/javax/crypto/Cipher.java
index 408d9b91172..bdbe2bcd98e 100644
--- a/jdk/src/share/classes/javax/crypto/Cipher.java
+++ b/jdk/src/share/classes/javax/crypto/Cipher.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, 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
@@ -104,17 +104,30 @@ import sun.security.jca.*;
* must be supplied to GCM/CCM implementations (via the {@code
* updateAAD} methods) before the ciphertext is processed (via
* the {@code update} and {@code doFinal} methods).
- *
+ *
+ * Note that GCM mode has a uniqueness requirement on IVs used in
+ * encryption with a given key. When IVs are repeated for GCM
+ * encryption, such usages are subject to forgery attacks. Thus, after
+ * each encryption operation using GCM mode, callers should re-initialize
+ * the cipher objects with GCM parameters which has a different IV value.
*
- * GCMParameterSpec s = new GCMParameterSpec(...);
+ * GCMParameterSpec s = ...;
* cipher.init(..., s);
*
- * // If the GCMParameterSpec is needed again
- * cipher.getParameters().getParameterSpec(GCMParameterSpec.class));
+ * // If the GCM parameters were generated by the provider, it can
+ * // be retrieved by:
+ * // cipher.getParameters().getParameterSpec(GCMParameterSpec.class);
*
* cipher.updateAAD(...); // AAD
* cipher.update(...); // Multi-part update
* cipher.doFinal(...); // conclusion of operation
+ *
+ * // Use a different IV value for every encryption
+ * byte[] newIv = ...;
+ * s = new GCMParameterSpec(s.getTLen(), newIv);
+ * cipher.init(..., s);
+ * ...
+ *
*
* Every implementation of the Java platform is required to support
* the following standard Cipher transformations with the keysizes
diff --git a/jdk/src/share/classes/javax/crypto/spec/GCMParameterSpec.java b/jdk/src/share/classes/javax/crypto/spec/GCMParameterSpec.java
index 01cb1cc7028..403205a298e 100644
--- a/jdk/src/share/classes/javax/crypto/spec/GCMParameterSpec.java
+++ b/jdk/src/share/classes/javax/crypto/spec/GCMParameterSpec.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2013, 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
@@ -43,7 +43,7 @@ import java.security.spec.AlgorithmParameterSpec;
* (Additional Authenticated Data (AAD), Keys, block ciphers,
* plain/ciphertext and authentication tags) are handled in the {@code
* Cipher} class.
-