[pkg-eucalyptus-commits] r25 - / openjdk-crypto openjdk-crypto/trunk openjdk-crypto/trunk/debian openjdk-crypto/trunk/src openjdk-crypto/trunk/src/main openjdk-crypto/trunk/src/main/java openjdk-crypto/trunk/src/main/java/javax openjdk-crypto/trunk/src/main/java/javax/crypto

Chris Grzegorczyk grze-guest at alioth.debian.org
Sat Mar 13 04:23:31 UTC 2010


Author: grze-guest
Date: 2010-03-13 04:23:29 +0000 (Sat, 13 Mar 2010)
New Revision: 25

Added:
   openjdk-crypto/
   openjdk-crypto/trunk/
   openjdk-crypto/trunk/debian/
   openjdk-crypto/trunk/debian/README.Debian
   openjdk-crypto/trunk/debian/build-jars
   openjdk-crypto/trunk/debian/build.xml
   openjdk-crypto/trunk/debian/changelog
   openjdk-crypto/trunk/debian/compat
   openjdk-crypto/trunk/debian/control
   openjdk-crypto/trunk/debian/copyright
   openjdk-crypto/trunk/debian/rules
   openjdk-crypto/trunk/src/
   openjdk-crypto/trunk/src/main/
   openjdk-crypto/trunk/src/main/java/
   openjdk-crypto/trunk/src/main/java/javax/
   openjdk-crypto/trunk/src/main/java/javax/crypto/
   openjdk-crypto/trunk/src/main/java/javax/crypto/BadPaddingException.java
   openjdk-crypto/trunk/src/main/java/javax/crypto/Cipher.java
   openjdk-crypto/trunk/src/main/java/javax/crypto/CipherInputStream.java
   openjdk-crypto/trunk/src/main/java/javax/crypto/CipherOutputStream.java
   openjdk-crypto/trunk/src/main/java/javax/crypto/CipherSpi.java
   openjdk-crypto/trunk/src/main/java/javax/crypto/CryptoAllPermission.java
   openjdk-crypto/trunk/src/main/java/javax/crypto/CryptoPermission.java
   openjdk-crypto/trunk/src/main/java/javax/crypto/CryptoPermissions.java
   openjdk-crypto/trunk/src/main/java/javax/crypto/CryptoPolicyParser.java
   openjdk-crypto/trunk/src/main/java/javax/crypto/EncryptedPrivateKeyInfo.java
   openjdk-crypto/trunk/src/main/java/javax/crypto/ExemptionMechanism.java
   openjdk-crypto/trunk/src/main/java/javax/crypto/ExemptionMechanismException.java
   openjdk-crypto/trunk/src/main/java/javax/crypto/ExemptionMechanismSpi.java
   openjdk-crypto/trunk/src/main/java/javax/crypto/IllegalBlockSizeException.java
   openjdk-crypto/trunk/src/main/java/javax/crypto/JceSecurity.java
   openjdk-crypto/trunk/src/main/java/javax/crypto/KeyAgreement.java
   openjdk-crypto/trunk/src/main/java/javax/crypto/KeyAgreementSpi.java
   openjdk-crypto/trunk/src/main/java/javax/crypto/KeyGenerator.java
   openjdk-crypto/trunk/src/main/java/javax/crypto/KeyGeneratorSpi.java
   openjdk-crypto/trunk/src/main/java/javax/crypto/Mac.java
   openjdk-crypto/trunk/src/main/java/javax/crypto/MacSpi.java
   openjdk-crypto/trunk/src/main/java/javax/crypto/NoSuchPaddingException.java
   openjdk-crypto/trunk/src/main/java/javax/crypto/NullCipher.java
   openjdk-crypto/trunk/src/main/java/javax/crypto/NullCipherSpi.java
   openjdk-crypto/trunk/src/main/java/javax/crypto/SealedObject.java
   openjdk-crypto/trunk/src/main/java/javax/crypto/SecretKey.java
   openjdk-crypto/trunk/src/main/java/javax/crypto/SecretKeyFactory.java
   openjdk-crypto/trunk/src/main/java/javax/crypto/SecretKeyFactorySpi.java
   openjdk-crypto/trunk/src/main/java/javax/crypto/ShortBufferException.java
   openjdk-crypto/trunk/src/main/resources/
Log:
very early stab  at openjdk-crypto package

Added: openjdk-crypto/trunk/debian/README.Debian
===================================================================
--- openjdk-crypto/trunk/debian/README.Debian	                        (rev 0)
+++ openjdk-crypto/trunk/debian/README.Debian	2010-03-13 04:23:29 UTC (rev 25)
@@ -0,0 +1,6 @@
+openjdk-crypto for Debian
+-------------------------
+
+<possible notes regarding this package - if none, delete this file>
+
+ -- Chris Grzegorczyk <grze at eucalyptus.com>  Fri, 12 Mar 2010 18:59:34 -0800

Added: openjdk-crypto/trunk/debian/build-jars
===================================================================
--- openjdk-crypto/trunk/debian/build-jars	                        (rev 0)
+++ openjdk-crypto/trunk/debian/build-jars	2010-03-13 04:23:29 UTC (rev 25)
@@ -0,0 +1,43 @@
+/usr/share/java/ant.jar
+/usr/share/java/antlr.jar
+/usr/share/java/aopalliance.jar
+/usr/share/java/asm3-commons.jar
+/usr/share/java/asm3.jar
+/usr/share/java/asm-attrs.jar
+/usr/share/java/backport-util-concurrent.jar
+/usr/share/java/bsh.jar
+/usr/share/java/catalina.jar
+/usr/share/java/cglib.jar
+/usr/share/java/commons-attributes-api.jar
+/usr/share/java/commons-beanutils.jar
+/usr/share/java/commons-cli.jar
+/usr/share/java/commons-collections3.jar
+/usr/share/java/commons-io.jar
+/usr/share/java/commons-jxpath.jar
+/usr/share/java/commons-lang.jar
+/usr/share/java/commons-logging.jar
+/usr/share/java/commons-pool.jar
+/usr/share/java/dom4j.jar
+/usr/share/java/el-api-2.1.jar
+/usr/share/java/geronimo-ejb-3.0-spec.jar
+/usr/share/java/geronimo-interceptor-3.0-spec.jar
+/usr/share/java/geronimo-j2ee-connector-1.5-spec.jar
+/usr/share/java/geronimo-jacc-1.1-spec.jar
+/usr/share/java/geronimo-jms-1.1-spec-1.1.jar
+/usr/share/java/geronimo-jms-1.1-spec.jar
+/usr/share/java/geronimo-jpa-3.0-spec.jar
+/usr/share/java/geronimo-jta-1.0.1b-spec.jar
+/usr/share/java/gnumail.jar
+/usr/share/java/groovy.jar
+/usr/share/java/jamon.jar
+/usr/share/java/javassist.jar
+/usr/share/java/jaxen.jar
+/usr/share/java/jetty.jar
+/usr/share/java/jsp-api-2.1.jar
+/usr/share/java/jug-asl.jar
+/usr/share/java/junit.jar
+/usr/share/java/log4j-1.2.jar
+/usr/share/java/proxool.jar
+/usr/share/java/servlet-api-2.5.jar
+/usr/share/java/slf4j-api.jar
+/usr/share/java/xstream.jar

Added: openjdk-crypto/trunk/debian/build.xml
===================================================================
--- openjdk-crypto/trunk/debian/build.xml	                        (rev 0)
+++ openjdk-crypto/trunk/debian/build.xml	2010-03-13 04:23:29 UTC (rev 25)
@@ -0,0 +1,42 @@
+<?xml version="1.0"?>
+
+<project name="pkg-java" default="package" basedir="..">
+
+    <property name="build.sourceDirectory" value="src/main/java"/>
+    <property name="build.resourcesDirectory" value="src/main/resources"/>
+    <property name="build.directory" value="build"/>
+    <property name="build.outputDirectory" value="${build.directory}/classes"/>
+
+    <target name="init">
+        <available property="available.resources" file="${build.resourcesDirectory}"/>
+    </target>
+
+    <target name="clean">
+        <delete dir="${build.directory}"/>
+    </target>
+
+    <target name="process-resources" depends="init" if="available.resources">
+        <mkdir dir="${build.outputDirectory}"/>
+        <copy todir="${build.outputDirectory}">
+            <fileset dir="${build.resourcesDirectory}"/>
+        </copy>
+    </target>
+
+    <target name="compile" depends="process-resources">
+        <mkdir dir="${build.outputDirectory}"/>
+        <javac
+            destdir="${build.outputDirectory}"
+            nowarn="true"
+            source="${sourceVersion}" target="${targetVersion}"
+            debug="on">
+            <src path="${build.sourceDirectory}"/>
+        </javac>
+    </target>
+
+    <target name="package" depends="compile">
+        <jar jarfile="${build.directory}/${artifactId}-${artifactVersion}.jar"
+            basedir="${build.outputDirectory}"/>
+    </target>
+
+</project>
+

Added: openjdk-crypto/trunk/debian/changelog
===================================================================
--- openjdk-crypto/trunk/debian/changelog	                        (rev 0)
+++ openjdk-crypto/trunk/debian/changelog	2010-03-13 04:23:29 UTC (rev 25)
@@ -0,0 +1,5 @@
+openjdk-crypto (1-1) unstable; urgency=low
+
+  * Initial release (Closes: #nnnn)  <nnnn is the bug number of your ITP>
+
+ -- Chris Grzegorczyk <grze at eucalyptus.com>  Fri, 12 Mar 2010 18:59:34 -0800

Added: openjdk-crypto/trunk/debian/compat
===================================================================
--- openjdk-crypto/trunk/debian/compat	                        (rev 0)
+++ openjdk-crypto/trunk/debian/compat	2010-03-13 04:23:29 UTC (rev 25)
@@ -0,0 +1 @@
+7

Added: openjdk-crypto/trunk/debian/control
===================================================================
--- openjdk-crypto/trunk/debian/control	                        (rev 0)
+++ openjdk-crypto/trunk/debian/control	2010-03-13 04:23:29 UTC (rev 25)
@@ -0,0 +1,23 @@
+Source: openjdk-crypto
+Section: java
+Priority: optional
+Maintainer: Debian Eucalyptus Maintainers <pkg-eucalyptus-maintainers at lists.alioth.debian.org>
+Uploaders:
+ Chris Grzegorczyk <grze at eucalyptus.com>,
+ Charles Plessy <plessy at debian.org>,
+ Steffen Moeller <plessy at debian.org>,
+ Graziano Obertelli <graziano at eucalyptus.com>,
+ Kyo Lee <kyo.lee at eucalyptus.com>,
+DM-Upload-Allowed: yes
+Build-Depends: ant, debhelper (>= 5), cdbs (>= 0.4.5.3)
+Build-Depends-Indep: default-jdk
+Standards-Version: 3.8.4
+Homepage: https://code.launchpad.net/~openjdk/openjdk/openjdk6
+
+Package: libopenjdk-crypto-java
+Architecture: any
+Depends: ${misc:Depends}, default-jre-headless
+Description: Simplified and unrestricted javax.crypto bootstrap library
+ Provides a simple unrestricted version of the javax.crypto package
+ which can be provided when bootstrapping the Java Virtual Machine. This
+ is needed to load, e.g., unsigned crypo SPI implementations.

Added: openjdk-crypto/trunk/debian/copyright
===================================================================
--- openjdk-crypto/trunk/debian/copyright	                        (rev 0)
+++ openjdk-crypto/trunk/debian/copyright	2010-03-13 04:23:29 UTC (rev 25)
@@ -0,0 +1,46 @@
+This package was debianized by:
+
+    Chris Grzegorczyk <grze at eucalyptus.com> on Fri, 12 Mar 2010 18:59:34 -0800
+
+Copyright:
+
+  Copyright 1997-2007 Sun Microsystems, Inc.
+
+License:
+
+JCE/Crypto code is distributed under the terms of the GNU General Public
+License with the following clarification and special 'Classpath' exception:
+
+  "CLASSPATH" EXCEPTION TO THE GPL
+
+  Certain source files distributed by Sun Microsystems, Inc.  are subject to
+  the following clarification and special exception to the GPL, but only where
+  Sun has expressly included in the particular source file's header the words
+  "Sun designates this particular file as subject to the "Classpath" exception
+  as provided by Sun in the LICENSE file that accompanied this code."
+
+   Linking this library statically or dynamically with other modules is making
+   a combined work based on this library. Thus, the terms and conditions of
+   the GNU General Public License cover the whole combination.
+
+   As a special exception, the copyright holders of this library give you
+   permission to link this library with independent modules to produce an
+   executable, regardless of the license terms of these independent modules,
+   and to copy and distribute the resulting executable under terms of your
+   choice, provided that you also meet, for each linked independent module,
+   the terms and conditions of the license of that module. An independent
+   module is a module which is not derived from or based on this library.
+   If you modify this library, you may extend this exception to your version
+   of the library, but you are not obligated to do so. If you do not wish to
+   do so, delete this exception statement from your version.
+
+ On Debian GNU/Linux system you can find a copy of the GPL in
+ `/usr/share/common-licenses/GPL-2'.
+
+The Debian packaging is:
+
+    Copyright (C) 2010 Chris Grzegorczyk <grze at eucalyptus.com>
+
+and is licensed under the BSD license, 
+see `/usr/share/common-licenses/BSD'.
+

Added: openjdk-crypto/trunk/debian/rules
===================================================================
--- openjdk-crypto/trunk/debian/rules	                        (rev 0)
+++ openjdk-crypto/trunk/debian/rules	2010-03-13 04:23:29 UTC (rev 25)
@@ -0,0 +1,18 @@
+#!/usr/bin/make -f
+
+include /usr/share/cdbs/1/rules/debhelper.mk
+include /usr/share/cdbs/1/class/ant.mk
+include /usr/share/cdbs/1/rules/simple-patchsys.mk
+
+JAVA_HOME            := /usr/lib/jvm/default-java
+REQUIRED_JVM_VERSION := 1.5
+DEB_ANT_BUILDFILE    := debian/build.xml
+DEB_ANT_ARGS         := -DartifactVersion=$(DEB_UPSTREAM_VERSION) \
+                        -DartifactId=$(DEB_SOURCE_PACKAGE) \
+                        -DsourceVersion=$(REQUIRED_JVM_VERSION) \
+                        -DtargetVersion=$(REQUIRED_JVM_VERSION)
+
+binary-post-install/lib$(DEB_SOURCE_PACKAGE)-java::
+	dh_install -plib$(DEB_SOURCE_PACKAGE)-java build/$(DEB_SOURCE_PACKAGE)-$(DEB_UPSTREAM_VERSION).jar usr/share/java
+	dh_link -plib$(DEB_SOURCE_PACKAGE)-java usr/share/java/$(DEB_SOURCE_PACKAGE)-$(DEB_UPSTREAM_VERSION).jar usr/share/java/$(DEB_SOURCE_PACKAGE).jar
+


Property changes on: openjdk-crypto/trunk/debian/rules
___________________________________________________________________
Added: svn:executable
   + *

Added: openjdk-crypto/trunk/src/main/java/javax/crypto/BadPaddingException.java
===================================================================
--- openjdk-crypto/trunk/src/main/java/javax/crypto/BadPaddingException.java	                        (rev 0)
+++ openjdk-crypto/trunk/src/main/java/javax/crypto/BadPaddingException.java	2010-03-13 04:23:29 UTC (rev 25)
@@ -0,0 +1,60 @@
+/*
+ * Copyright 1997-2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.crypto;
+
+import java.security.GeneralSecurityException;
+
+/**
+ * This exception is thrown when a particular padding mechanism is
+ * expected for the input data but the data is not padded properly.
+ *
+ * @author Gigi Ankney
+ * @since 1.4
+ */
+
+public class BadPaddingException extends GeneralSecurityException {
+
+    private static final long serialVersionUID = -5315033893984728443L;
+
+    /**
+     * Constructs a BadPaddingException with no detail
+     * message. A detail message is a String that describes this
+     * particular exception.
+     */
+    public BadPaddingException() {
+        super();
+    }
+
+    /**
+     * Constructs a BadPaddingException with the specified
+     * detail message.
+     *
+     * @param msg the detail message.
+     */
+    public BadPaddingException(String msg) {
+        super(msg);
+    }
+}

Added: openjdk-crypto/trunk/src/main/java/javax/crypto/Cipher.java
===================================================================
--- openjdk-crypto/trunk/src/main/java/javax/crypto/Cipher.java	                        (rev 0)
+++ openjdk-crypto/trunk/src/main/java/javax/crypto/Cipher.java	2010-03-13 04:23:29 UTC (rev 25)
@@ -0,0 +1,2258 @@
+/*
+ * Copyright 1997-2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.crypto;
+
+import java.util.*;
+import java.util.regex.*;
+
+import static java.util.Locale.ENGLISH;
+
+import java.security.*;
+import java.security.Provider.Service;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+
+import javax.crypto.spec.*;
+
+import java.nio.ByteBuffer;
+import java.nio.ReadOnlyBufferException;
+
+import sun.security.util.Debug;
+import sun.security.jca.*;
+import sun.security.jca.GetInstance.Instance;
+
+/**
+ * This class provides the functionality of a cryptographic cipher for
+ * encryption and decryption. It forms the core of the Java Cryptographic
+ * Extension (JCE) framework.
+ *
+ * <p>In order to create a Cipher object, the application calls the
+ * Cipher's <code>getInstance</code> method, and passes the name of the
+ * requested <i>transformation</i> to it. Optionally, the name of a provider
+ * may be specified.
+ *
+ * <p>A <i>transformation</i> is a string that describes the operation (or
+ * set of operations) to be performed on the given input, to produce some
+ * output. A transformation always includes the name of a cryptographic
+ * algorithm (e.g., <i>DES</i>), and may be followed by a feedback mode and
+ * padding scheme.
+ *
+ * <p> A transformation is of the form:<p>
+ *
+ * <ul>
+ * <li>"<i>algorithm/mode/padding</i>" or
+ * <p>
+ * <li>"<i>algorithm</i>"
+ * </ul>
+ *
+ * <P> (in the latter case,
+ * provider-specific default values for the mode and padding scheme are used).
+ * For example, the following is a valid transformation:<p>
+ *
+ * <pre>
+ *     Cipher c = Cipher.getInstance("<i>DES/CBC/PKCS5Padding</i>");
+ * </pre>
+ *
+ * Using modes such as <code>CFB</code> and <code>OFB<code>, block
+ * ciphers can encrypt data in units smaller than the cipher's actual
+ * block size.  When requesting such a mode, you may optionally specify
+ * the number of bits to be processed at a time by appending this number
+ * to the mode name as shown in the "<code>DES/CFB8/NoPadding</code>" and
+ * "<code>DES/OFB32/PKCS5Padding</code>" transformations. If no such
+ * number is specified, a provider-specific default is used. (For
+ * example, the SunJCE provider uses a default of 64 bits for DES.)
+ * Thus, block ciphers can be turned into byte-oriented stream ciphers by
+ * using an 8 bit mode such as CFB8 or OFB8.
+ *
+ * @author Jan Luehe
+ * @see KeyGenerator
+ * @see SecretKey
+ * @since 1.4
+ */
+
+public class Cipher {
+
+    private static final Debug debug =
+                        Debug.getInstance("jca", "Cipher");
+
+    /**
+     * Constant used to initialize cipher to encryption mode.
+     */
+    public static final int ENCRYPT_MODE = 1;
+
+    /**
+     * Constant used to initialize cipher to decryption mode.
+     */
+    public static final int DECRYPT_MODE = 2;
+
+    /**
+     * Constant used to initialize cipher to key-wrapping mode.
+     */
+    public static final int WRAP_MODE = 3;
+
+    /**
+     * Constant used to initialize cipher to key-unwrapping mode.
+     */
+    public static final int UNWRAP_MODE = 4;
+
+    /**
+     * Constant used to indicate the to-be-unwrapped key is a "public key".
+     */
+    public static final int PUBLIC_KEY = 1;
+
+    /**
+     * Constant used to indicate the to-be-unwrapped key is a "private key".
+     */
+    public static final int PRIVATE_KEY = 2;
+
+    /**
+     * Constant used to indicate the to-be-unwrapped key is a "secret key".
+     */
+    public static final int SECRET_KEY = 3;
+
+    // The provider
+    private Provider provider;
+
+    // The provider implementation (delegate)
+    private CipherSpi spi;
+
+    // The transformation
+    private String transformation;
+
+    // The exemption mechanism that needs to be enforced
+    private ExemptionMechanism exmech;
+
+    // Flag which indicates whether or not this cipher has been initialized
+    private boolean initialized = false;
+
+    // The operation mode - store the operation mode after the
+    // cipher has been initialized.
+    private int opmode = 0;
+
+    // The OID for the KeyUsage extension in an X.509 v3 certificate
+    private static final String KEY_USAGE_EXTENSION_OID = "2.5.29.15";
+
+    // next SPI  to try in provider selection
+    // null once provider is selected
+    private CipherSpi firstSpi;
+
+    // next service to try in provider selection
+    // null once provider is selected
+    private Service firstService;
+
+    // remaining services to try in provider selection
+    // null once provider is selected
+    private Iterator serviceIterator;
+
+    // list of transform Strings to lookup in the provider
+    private List transforms;
+
+    private final Object lock;
+
+    /**
+     * Creates a Cipher object.
+     *
+     * @param cipherSpi the delegate
+     * @param provider the provider
+     * @param transformation the transformation
+     */
+    protected Cipher(CipherSpi cipherSpi,
+                     Provider provider,
+                     String transformation) {
+        this.spi = cipherSpi;
+        this.provider = provider;
+        this.transformation = transformation;
+        this.lock = null;
+    }
+
+    /**
+     * Creates a Cipher object. Called internally and by NullCipher.
+     *
+     * @param cipherSpi the delegate
+     * @param transformation the transformation
+     */
+    Cipher(CipherSpi cipherSpi, String transformation) {
+        this.spi = cipherSpi;
+        this.transformation = transformation;
+        this.lock = null;
+    }
+
+    private Cipher(CipherSpi firstSpi, Service firstService,
+            Iterator serviceIterator, String transformation, List transforms) {
+        this.firstSpi = firstSpi;
+        this.firstService = firstService;
+        this.serviceIterator = serviceIterator;
+        this.transforms = transforms;
+        this.transformation = transformation;
+        this.lock = new Object();
+    }
+
+    private static String[] tokenizeTransformation(String transformation)
+            throws NoSuchAlgorithmException {
+        if (transformation == null) {
+            throw new NoSuchAlgorithmException("No transformation given");
+        }
+        /*
+         * array containing the components of a Cipher transformation:
+         *
+         * index 0: algorithm component (e.g., DES)
+         * index 1: feedback component (e.g., CFB)
+         * index 2: padding component (e.g., PKCS5Padding)
+         */
+        String[] parts = new String[3];
+        int count = 0;
+        StringTokenizer parser = new StringTokenizer(transformation, "/");
+        try {
+            while (parser.hasMoreTokens() && count < 3) {
+                parts[count++] = parser.nextToken().trim();
+            }
+            if (count == 0 || count == 2 || parser.hasMoreTokens()) {
+                throw new NoSuchAlgorithmException("Invalid transformation"
+                                               + " format:" +
+                                               transformation);
+            }
+        } catch (NoSuchElementException e) {
+            throw new NoSuchAlgorithmException("Invalid transformation " +
+                                           "format:" + transformation);
+        }
+        if ((parts[0] == null) || (parts[0].length() == 0)) {
+            throw new NoSuchAlgorithmException("Invalid transformation:" +
+                                   "algorithm not specified-"
+                                   + transformation);
+        }
+        return parts;
+    }
+
+    // Provider attribute name for supported chaining mode
+    private final static String ATTR_MODE = "SupportedModes";
+    // Provider attribute name for supported padding names
+    private final static String ATTR_PAD  = "SupportedPaddings";
+
+    // constants indicating whether the provider supports
+    // a given mode or padding
+    private final static int S_NO    = 0;       // does not support
+    private final static int S_MAYBE = 1;       // unable to determine
+    private final static int S_YES   = 2;       // does support
+
+    /**
+     * Nested class to deal with modes and paddings.
+     */
+    private static class Transform {
+        // transform string to lookup in the provider
+        final String transform;
+        // the mode/padding suffix in upper case. for example, if the algorithm
+        // to lookup is "DES/CBC/PKCS5Padding" suffix is "/CBC/PKCS5PADDING"
+        // if loopup is "DES", suffix is the empty string
+        // needed because aliases prevent straight transform.equals()
+        final String suffix;
+        // value to pass to setMode() or null if no such call required
+        final String mode;
+        // value to pass to setPadding() or null if no such call required
+        final String pad;
+        Transform(String alg, String suffix, String mode, String pad) {
+            this.transform = alg + suffix;
+            this.suffix = suffix.toUpperCase(Locale.ENGLISH);
+            this.mode = mode;
+            this.pad = pad;
+        }
+        // set mode and padding for the given SPI
+        void setModePadding(CipherSpi spi) throws NoSuchAlgorithmException,
+                NoSuchPaddingException {
+            if (mode != null) {
+                spi.engineSetMode(mode);
+            }
+            if (pad != null) {
+                spi.engineSetPadding(pad);
+            }
+        }
+        // check whether the given services supports the mode and
+        // padding described by this Transform
+        int supportsModePadding(Service s) {
+            int smode = supportsMode(s);
+            if (smode == S_NO) {
+                return smode;
+            }
+            int spad = supportsPadding(s);
+            // our constants are defined so that Math.min() is a tri-valued AND
+            return Math.min(smode, spad);
+        }
+
+        // separate methods for mode and padding
+        // called directly by Cipher only to throw the correct exception
+        int supportsMode(Service s) {
+            return supports(s, ATTR_MODE, mode);
+        }
+        int supportsPadding(Service s) {
+            return supports(s, ATTR_PAD, pad);
+        }
+
+        private static int supports(Service s, String attrName, String value) {
+            if (value == null) {
+                return S_YES;
+            }
+            String regexp = s.getAttribute(attrName);
+            if (regexp == null) {
+                return S_MAYBE;
+            }
+            return matches(regexp, value) ? S_YES : S_NO;
+        }
+
+        // Map<String,Pattern> for previously compiled patterns
+        // XXX use ConcurrentHashMap once available
+        private final static Map patternCache =
+            Collections.synchronizedMap(new HashMap());
+
+        private static boolean matches(String regexp, String str) {
+            Pattern pattern = (Pattern)patternCache.get(regexp);
+            if (pattern == null) {
+                pattern = Pattern.compile(regexp);
+                patternCache.put(regexp, pattern);
+            }
+            return pattern.matcher(str.toUpperCase(Locale.ENGLISH)).matches();
+        }
+
+    }
+
+    private static List getTransforms(String transformation)
+            throws NoSuchAlgorithmException {
+        String[] parts = tokenizeTransformation(transformation);
+
+        String alg = parts[0];
+        String mode = parts[1];
+        String pad = parts[2];
+        if ((mode != null) && (mode.length() == 0)) {
+            mode = null;
+        }
+        if ((pad != null) && (pad.length() == 0)) {
+            pad = null;
+        }
+
+        if ((mode == null) && (pad == null)) {
+            // DES
+            Transform tr = new Transform(alg, "", null, null);
+            return Collections.singletonList(tr);
+        } else { // if ((mode != null) && (pad != null)) {
+            // DES/CBC/PKCS5Padding
+            List list = new ArrayList(4);
+            list.add(new Transform(alg, "/" + mode + "/" + pad, null, null));
+            list.add(new Transform(alg, "/" + mode, null, pad));
+            list.add(new Transform(alg, "//" + pad, mode, null));
+            list.add(new Transform(alg, "", mode, pad));
+            return list;
+        }
+    }
+
+    // get the transform matching the specified service
+    private static Transform getTransform(Service s, List transforms) {
+        String alg = s.getAlgorithm().toUpperCase(Locale.ENGLISH);
+        for (Iterator t = transforms.iterator(); t.hasNext(); ) {
+            Transform tr = (Transform)t.next();
+            if (alg.endsWith(tr.suffix)) {
+                return tr;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns a <code>Cipher</code> object that implements the specified
+     * transformation.
+     *
+     * <p> This method traverses the list of registered security Providers,
+     * starting with the most preferred Provider.
+     * A new Cipher object encapsulating the
+     * CipherSpi implementation from the first
+     * Provider that supports the specified algorithm is returned.
+     *
+     * <p> Note that the list of registered providers may be retrieved via
+     * the {@link Security#getProviders() Security.getProviders()} method.
+     *
+     * @param transformation the name of the transformation, e.g.,
+     * <i>DES/CBC/PKCS5Padding</i>.
+     * See Appendix A in the
+     * <a href=
+     *   "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     * Java Cryptography Architecture Reference Guide</a>
+     * for information about standard transformation names.
+     *
+     * @return a cipher that implements the requested transformation.
+     *
+     * @exception NoSuchAlgorithmException if <code>transformation</code>
+     *          is null, empty, in an invalid format,
+     *          or if no Provider supports a CipherSpi implementation for the
+     *          specified algorithm.
+     *
+     * @exception NoSuchPaddingException if <code>transformation</code>
+     *          contains a padding scheme that is not available.
+     *
+     * @see java.security.Provider
+     */
+    public static final Cipher getInstance(String transformation)
+            throws NoSuchAlgorithmException, NoSuchPaddingException
+    {
+        List transforms = getTransforms(transformation);
+        List cipherServices = new ArrayList(transforms.size());
+        for (Iterator t = transforms.iterator(); t.hasNext(); ) {
+            Transform transform = (Transform)t.next();
+            cipherServices.add(new ServiceId("Cipher", transform.transform));
+        }
+        List services = GetInstance.getServices(cipherServices);
+        // make sure there is at least one service from a signed provider
+        // and that it can use the specified mode and padding
+        Iterator t = services.iterator();
+        Exception failure = null;
+        while (t.hasNext()) {
+            Service s = (Service)t.next();
+            Transform tr = getTransform(s, transforms);
+            if (tr == null) {
+                // should never happen
+                continue;
+            }
+            int canuse = tr.supportsModePadding(s);
+            if (canuse == S_NO) {
+                // does not support mode or padding we need, ignore
+                continue;
+            }
+            if (canuse == S_YES) {
+                return new Cipher(null, s, t, transformation, transforms);
+            } else { // S_MAYBE, try out if it works
+                try {
+                    CipherSpi spi = (CipherSpi)s.newInstance(null);
+                    tr.setModePadding(spi);
+                    return new Cipher(spi, s, t, transformation, transforms);
+                } catch (Exception e) {
+                    failure = e;
+                }
+            }
+        }
+        throw new NoSuchAlgorithmException
+            ("Cannot find any provider supporting " + transformation, failure);
+    }
+
+    /**
+     * Returns a <code>Cipher</code> object that implements the specified
+     * transformation.
+     *
+     * <p> A new Cipher object encapsulating the
+     * CipherSpi implementation from the specified provider
+     * is returned.  The specified provider must be registered
+     * in the security provider list.
+     *
+     * <p> Note that the list of registered providers may be retrieved via
+     * the {@link Security#getProviders() Security.getProviders()} method.
+     *
+     * @param transformation the name of the transformation,
+     * e.g., <i>DES/CBC/PKCS5Padding</i>.
+     * See Appendix A in the
+     * <a href=
+     *   "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     * Java Cryptography Architecture Reference Guide</a>
+     * for information about standard transformation names.
+     *
+     * @param provider the name of the provider.
+     *
+     * @return a cipher that implements the requested transformation.
+     *
+     * @exception NoSuchAlgorithmException if <code>transformation</code>
+     *          is null, empty, in an invalid format,
+     *          or if a CipherSpi implementation for the specified algorithm
+     *          is not available from the specified provider.
+     *
+     * @exception NoSuchProviderException if the specified provider is not
+     *          registered in the security provider list.
+     *
+     * @exception NoSuchPaddingException if <code>transformation</code>
+     *          contains a padding scheme that is not available.
+     *
+     * @exception IllegalArgumentException if the <code>provider</code>
+     *          is null or empty.
+     *
+     * @see java.security.Provider
+     */
+    public static final Cipher getInstance(String transformation,
+                                           String provider)
+            throws NoSuchAlgorithmException, NoSuchProviderException,
+            NoSuchPaddingException
+    {
+        if ((provider == null) || (provider.length() == 0)) {
+            throw new IllegalArgumentException("Missing provider");
+        }
+        Provider p = Security.getProvider(provider);
+        if (p == null) {
+            throw new NoSuchProviderException("No such provider: " +
+                                              provider);
+        }
+        return getInstance(transformation, p);
+    }
+
+    /**
+     * Returns a <code>Cipher</code> object that implements the specified
+     * transformation.
+     *
+     * <p> A new Cipher object encapsulating the
+     * CipherSpi implementation from the specified Provider
+     * object is returned.  Note that the specified Provider object
+     * does not have to be registered in the provider list.
+     *
+     * @param transformation the name of the transformation,
+     * e.g., <i>DES/CBC/PKCS5Padding</i>.
+     * See Appendix A in the
+     * <a href=
+     *   "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     * Java Cryptography Architecture Reference Guide</a>
+     * for information about standard transformation names.
+     *
+     * @param provider the provider.
+     *
+     * @return a cipher that implements the requested transformation.
+     *
+     * @exception NoSuchAlgorithmException if <code>transformation</code>
+     *          is null, empty, in an invalid format,
+     *          or if a CipherSpi implementation for the specified algorithm
+     *          is not available from the specified Provider object.
+     *
+     * @exception NoSuchPaddingException if <code>transformation</code>
+     *          contains a padding scheme that is not available.
+     *
+     * @exception IllegalArgumentException if the <code>provider</code>
+     *          is null.
+     *
+     * @see java.security.Provider
+     */
+    public static final Cipher getInstance(String transformation,
+                                           Provider provider)
+            throws NoSuchAlgorithmException, NoSuchPaddingException
+    {
+        if (provider == null) {
+            throw new IllegalArgumentException("Missing provider");
+        }
+        Exception failure = null;
+        List transforms = getTransforms(transformation);
+        String paddingError = null;
+        for (Iterator t = transforms.iterator(); t.hasNext();) {
+            Transform tr = (Transform)t.next();
+            Service s = provider.getService("Cipher", tr.transform);
+            if (s == null) {
+                continue;
+            }
+            if (tr.supportsMode(s) == S_NO) {
+                continue;
+            }
+            if (tr.supportsPadding(s) == S_NO) {
+                paddingError = tr.pad;
+                continue;
+            }
+            try {
+                CipherSpi spi = (CipherSpi)s.newInstance(null);
+                tr.setModePadding(spi);
+                Cipher cipher = new Cipher(spi, transformation);
+                cipher.provider = s.getProvider();
+                return cipher;
+            } catch (Exception e) {
+                failure = e;
+            }
+        }
+
+        // throw NoSuchPaddingException if the problem is with padding
+        if (failure instanceof NoSuchPaddingException) {
+            throw (NoSuchPaddingException)failure;
+        }
+        if (paddingError != null) {
+            throw new NoSuchPaddingException
+                ("Padding not supported: " + paddingError);
+        }
+        throw new NoSuchAlgorithmException
+                ("No such algorithm: " + transformation, failure);
+    }
+
+    // max number of debug warnings to print from chooseFirstProvider()
+    private static int warnCount = 10;
+
+    /**
+     * Choose the Spi from the first provider available. Used if
+     * delayed provider selection is not possible because init()
+     * is not the first method called.
+     */
+    void chooseFirstProvider() {
+        if (spi != null) {
+            return;
+        }
+        synchronized (lock) {
+            if (spi != null) {
+                return;
+            }
+            if (debug != null) {
+                int w = --warnCount;
+                if (w >= 0) {
+                    debug.println("Cipher.init() not first method "
+                        + "called, disabling delayed provider selection");
+                    if (w == 0) {
+                        debug.println("Further warnings of this type will "
+                            + "be suppressed");
+                    }
+                    new Exception("Call trace").printStackTrace();
+                }
+            }
+            Exception lastException = null;
+            while ((firstService != null) || serviceIterator.hasNext()) {
+                Service s;
+                CipherSpi thisSpi;
+                if (firstService != null) {
+                    s = firstService;
+                    thisSpi = firstSpi;
+                    firstService = null;
+                    firstSpi = null;
+                } else {
+                    s = (Service)serviceIterator.next();
+                    thisSpi = null;
+                }
+                Transform tr = getTransform(s, transforms);
+                if (tr == null) {
+                    // should never happen
+                    continue;
+                }
+                if (tr.supportsModePadding(s) == S_NO) {
+                    continue;
+                }
+                try {
+                    if (thisSpi == null) {
+                        Object obj = s.newInstance(null);
+                        if (obj instanceof CipherSpi == false) {
+                            continue;
+                        }
+                        thisSpi = (CipherSpi)obj;
+                    }
+                    tr.setModePadding(thisSpi);
+                    spi = thisSpi;
+                    provider = s.getProvider();
+                    // not needed any more
+                    firstService = null;
+                    serviceIterator = null;
+                    transforms = null;
+                    return;
+                } catch (Exception e) {
+                    lastException = e;
+                }
+            }
+            ProviderException e = new ProviderException
+                    ("Could not construct CipherSpi instance");
+            if (lastException != null) {
+                e.initCause(lastException);
+            }
+            throw e;
+        }
+    }
+
+    private final static int I_KEY       = 1;
+    private final static int I_PARAMSPEC = 2;
+    private final static int I_PARAMS    = 3;
+    private final static int I_CERT      = 4;
+
+    private void implInit(CipherSpi thisSpi, int type, int opmode, Key key,
+            AlgorithmParameterSpec paramSpec, AlgorithmParameters params,
+            SecureRandom random) throws InvalidKeyException,
+            InvalidAlgorithmParameterException {
+        switch (type) {
+        case I_KEY:
+            thisSpi.engineInit(opmode, key, random);
+            break;
+        case I_PARAMSPEC:
+            thisSpi.engineInit(opmode, key, paramSpec, random);
+            break;
+        case I_PARAMS:
+            thisSpi.engineInit(opmode, key, params, random);
+            break;
+        case I_CERT:
+            thisSpi.engineInit(opmode, key, random);
+            break;
+        default:
+            throw new AssertionError("Internal Cipher error: " + type);
+        }
+    }
+
+    private void chooseProvider(int initType, int opmode, Key key,
+            AlgorithmParameterSpec paramSpec,
+            AlgorithmParameters params, SecureRandom random)
+            throws InvalidKeyException, InvalidAlgorithmParameterException {
+        synchronized (lock) {
+            if (spi != null) {
+                implInit(spi, initType, opmode, key, paramSpec, params, random);
+                return;
+            }
+            Exception lastException = null;
+            while ((firstService != null) || serviceIterator.hasNext()) {
+                Service s;
+                CipherSpi thisSpi;
+                if (firstService != null) {
+                    s = firstService;
+                    thisSpi = firstSpi;
+                    firstService = null;
+                    firstSpi = null;
+                } else {
+                    s = (Service)serviceIterator.next();
+                    thisSpi = null;
+                }
+                // if provider says it does not support this key, ignore it
+                if (s.supportsParameter(key) == false) {
+                    continue;
+                }
+                Transform tr = getTransform(s, transforms);
+                if (tr == null) {
+                    // should never happen
+                    continue;
+                }
+                if (tr.supportsModePadding(s) == S_NO) {
+                    continue;
+                }
+                try {
+                    if (thisSpi == null) {
+                        thisSpi = (CipherSpi)s.newInstance(null);
+                    }
+                    tr.setModePadding(thisSpi);
+                    implInit(thisSpi, initType, opmode, key, paramSpec,
+                                                        params, random);
+                    provider = s.getProvider();
+                    this.spi = thisSpi;
+                    firstService = null;
+                    serviceIterator = null;
+                    transforms = null;
+                    return;
+                } catch (Exception e) {
+                    // NoSuchAlgorithmException from newInstance()
+                    // InvalidKeyException from init()
+                    // RuntimeException (ProviderException) from init()
+                    // SecurityException from crypto permission check
+                    if (lastException == null) {
+                        lastException = e;
+                    }
+                }
+            }
+            // no working provider found, fail
+            if (lastException instanceof InvalidKeyException) {
+                throw (InvalidKeyException)lastException;
+            }
+            if (lastException instanceof InvalidAlgorithmParameterException) {
+                throw (InvalidAlgorithmParameterException)lastException;
+            }
+            if (lastException instanceof RuntimeException) {
+                throw (RuntimeException)lastException;
+            }
+            String kName = (key != null) ? key.getClass().getName() : "(null)";
+            throw new InvalidKeyException
+                ("No installed provider supports this key: "
+                + kName, lastException);
+        }
+    }
+
+    /**
+     * Returns the provider of this <code>Cipher</code> object.
+     *
+     * @return the provider of this <code>Cipher</code> object
+     */
+    public final Provider getProvider() {
+        chooseFirstProvider();
+        return this.provider;
+    }
+
+    /**
+     * Returns the algorithm name of this <code>Cipher</code> object.
+     *
+     * <p>This is the same name that was specified in one of the
+     * <code>getInstance</code> calls that created this <code>Cipher</code>
+     * object..
+     *
+     * @return the algorithm name of this <code>Cipher</code> object.
+     */
+    public final String getAlgorithm() {
+        return this.transformation;
+    }
+
+    /**
+     * Returns the block size (in bytes).
+     *
+     * @return the block size (in bytes), or 0 if the underlying algorithm is
+     * not a block cipher
+     */
+    public final int getBlockSize() {
+        chooseFirstProvider();
+        return spi.engineGetBlockSize();
+    }
+
+    /**
+     * Returns the length in bytes that an output buffer would need to be in
+     * order to hold the result of the next <code>update</code> or
+     * <code>doFinal</code> operation, given the input length
+     * <code>inputLen</code> (in bytes).
+     *
+     * <p>This call takes into account any unprocessed (buffered) data from a
+     * previous <code>update</code> call, and padding.
+     *
+     * <p>The actual output length of the next <code>update</code> or
+     * <code>doFinal</code> call may be smaller than the length returned by
+     * this method.
+     *
+     * @param inputLen the input length (in bytes)
+     *
+     * @return the required output buffer size (in bytes)
+     *
+     * @exception IllegalStateException if this cipher is in a wrong state
+     * (e.g., has not yet been initialized)
+     */
+    public final int getOutputSize(int inputLen) {
+
+        if (!initialized && !(this instanceof NullCipher)) {
+            throw new IllegalStateException("Cipher not initialized");
+        }
+        if (inputLen < 0) {
+            throw new IllegalArgumentException("Input size must be equal " +
+                                               "to or greater than zero");
+        }
+        chooseFirstProvider();
+        return spi.engineGetOutputSize(inputLen);
+    }
+
+    /**
+     * Returns the initialization vector (IV) in a new buffer.
+     *
+     * <p>This is useful in the case where a random IV was created,
+     * or in the context of password-based encryption or
+     * decryption, where the IV is derived from a user-supplied password.
+     *
+     * @return the initialization vector in a new buffer, or null if the
+     * underlying algorithm does not use an IV, or if the IV has not yet
+     * been set.
+     */
+    public final byte[] getIV() {
+        chooseFirstProvider();
+        return spi.engineGetIV();
+    }
+
+    /**
+     * Returns the parameters used with this cipher.
+     *
+     * <p>The returned parameters may be the same that were used to initialize
+     * this cipher, or may contain a combination of default and random
+     * parameter values used by the underlying cipher implementation if this
+     * cipher requires algorithm parameters but was not initialized with any.
+     *
+     * @return the parameters used with this cipher, or null if this cipher
+     * does not use any parameters.
+     */
+    public final AlgorithmParameters getParameters() {
+        chooseFirstProvider();
+        return spi.engineGetParameters();
+    }
+
+    /**
+     * Returns the exemption mechanism object used with this cipher.
+     *
+     * @return the exemption mechanism object used with this cipher, or
+     * null if this cipher does not use any exemption mechanism.
+     */
+    public final ExemptionMechanism getExemptionMechanism() {
+        chooseFirstProvider();
+        return exmech;
+    }
+
+    // check if opmode is one of the defined constants
+    // throw InvalidParameterExeption if not
+    private static void checkOpmode(int opmode) {
+        if ((opmode < ENCRYPT_MODE) || (opmode > UNWRAP_MODE)) {
+            throw new InvalidParameterException("Invalid operation mode");
+        }
+    }
+
+    /**
+     * Initializes this cipher with a key.
+     *
+     * <p>The cipher is initialized for one of the following four operations:
+     * encryption, decryption, key wrapping or key unwrapping, depending
+     * on the value of <code>opmode</code>.
+     *
+     * <p>If this cipher requires any algorithm parameters that cannot be
+     * derived from the given <code>key</code>, the underlying cipher
+     * implementation is supposed to generate the required parameters itself
+     * (using provider-specific default or random values) if it is being
+     * initialized for encryption or key wrapping, and raise an
+     * <code>InvalidKeyException</code> if it is being
+     * initialized for decryption or key unwrapping.
+     * The generated parameters can be retrieved using
+     * {@link #getParameters() getParameters} or
+     * {@link #getIV() getIV} (if the parameter is an IV).
+     *
+     * <p>If this cipher (including its underlying feedback or padding scheme)
+     * requires any random bytes (e.g., for parameter generation), it will get
+     * them using the {@link SecureRandom <code>SecureRandom</code>}
+     * implementation of the highest-priority
+     * installed provider as the source of randomness.
+     * (If none of the installed providers supply an implementation of
+     * SecureRandom, a system-provided source of randomness will be used.)
+     *
+     * <p>Note that when a Cipher object is initialized, it loses all
+     * previously-acquired state. In other words, initializing a Cipher is
+     * equivalent to creating a new instance of that Cipher and initializing
+     * it.
+     *
+     * @param opmode the operation mode of this cipher (this is one of
+     * the following:
+     * <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,
+     * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)
+     * @param key the key
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * initializing this cipher, or if this cipher is being initialized for
+     * decryption and requires algorithm parameters that cannot be
+     * determined from the given key, or if the given key has a keysize that
+     * exceeds the maximum allowable keysize (as determined from the
+     * configured jurisdiction policy files).
+     */
+    public final void init(int opmode, Key key) throws InvalidKeyException {
+        init(opmode, key, JceSecurity.RANDOM);
+    }
+
+    /**
+     * Initializes this cipher with a key and a source of randomness.
+     *
+     * <p>The cipher is initialized for one of the following four operations:
+     * encryption, decryption, key wrapping or  key unwrapping, depending
+     * on the value of <code>opmode</code>.
+     *
+     * <p>If this cipher requires any algorithm parameters that cannot be
+     * derived from the given <code>key</code>, the underlying cipher
+     * implementation is supposed to generate the required parameters itself
+     * (using provider-specific default or random values) if it is being
+     * initialized for encryption or key wrapping, and raise an
+     * <code>InvalidKeyException</code> if it is being
+     * initialized for decryption or key unwrapping.
+     * The generated parameters can be retrieved using
+     * {@link #getParameters() getParameters} or
+     * {@link #getIV() getIV} (if the parameter is an IV).
+     *
+     * <p>If this cipher (including its underlying feedback or padding scheme)
+     * requires any random bytes (e.g., for parameter generation), it will get
+     * them from <code>random</code>.
+     *
+     * <p>Note that when a Cipher object is initialized, it loses all
+     * previously-acquired state. In other words, initializing a Cipher is
+     * equivalent to creating a new instance of that Cipher and initializing
+     * it.
+     *
+     * @param opmode the operation mode of this cipher (this is one of the
+     * following:
+     * <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,
+     * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)
+     * @param key the encryption key
+     * @param random the source of randomness
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * initializing this cipher, or if this cipher is being initialized for
+     * decryption and requires algorithm parameters that cannot be
+     * determined from the given key, or if the given key has a keysize that
+     * exceeds the maximum allowable keysize (as determined from the
+     * configured jurisdiction policy files).
+     */
+    public final void init(int opmode, Key key, SecureRandom random)
+            throws InvalidKeyException
+    {
+        initialized = false;
+        checkOpmode(opmode);
+
+        if (spi != null) {
+            spi.engineInit(opmode, key, random);
+        } else {
+            try {
+                chooseProvider(I_KEY, opmode, key, null, null, random);
+            } catch (InvalidAlgorithmParameterException e) {
+                // should never occur
+                throw new InvalidKeyException(e);
+            }
+        }
+
+        initialized = true;
+        this.opmode = opmode;
+    }
+
+    /**
+     * Initializes this cipher with a key and a set of algorithm
+     * parameters.
+     *
+     * <p>The cipher is initialized for one of the following four operations:
+     * encryption, decryption, key wrapping or  key unwrapping, depending
+     * on the value of <code>opmode</code>.
+     *
+     * <p>If this cipher requires any algorithm parameters and
+     * <code>params</code> is null, the underlying cipher implementation is
+     * supposed to generate the required parameters itself (using
+     * provider-specific default or random values) if it is being
+     * initialized for encryption or key wrapping, and raise an
+     * <code>InvalidAlgorithmParameterException</code> if it is being
+     * initialized for decryption or key unwrapping.
+     * The generated parameters can be retrieved using
+     * {@link #getParameters() getParameters} or
+     * {@link #getIV() getIV} (if the parameter is an IV).
+     *
+     * <p>If this cipher (including its underlying feedback or padding scheme)
+     * requires any random bytes (e.g., for parameter generation), it will get
+     * them using the {@link SecureRandom <code>SecureRandom</code>}
+     * implementation of the highest-priority
+     * installed provider as the source of randomness.
+     * (If none of the installed providers supply an implementation of
+     * SecureRandom, a system-provided source of randomness will be used.)
+     *
+     * <p>Note that when a Cipher object is initialized, it loses all
+     * previously-acquired state. In other words, initializing a Cipher is
+     * equivalent to creating a new instance of that Cipher and initializing
+     * it.
+     *
+     * @param opmode the operation mode of this cipher (this is one of the
+     * following:
+     * <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,
+     * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)
+     * @param key the encryption key
+     * @param params the algorithm parameters
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * initializing this cipher, or its keysize exceeds the maximum allowable
+     * keysize (as determined from the configured jurisdiction policy files).
+     * @exception InvalidAlgorithmParameterException if the given algorithm
+     * parameters are inappropriate for this cipher,
+     * or this cipher is being initialized for decryption and requires
+     * algorithm parameters and <code>params</code> is null, or the given
+     * algorithm parameters imply a cryptographic strength that would exceed
+     * the legal limits (as determined from the configured jurisdiction
+     * policy files).
+     */
+    public final void init(int opmode, Key key, AlgorithmParameterSpec params)
+            throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        init(opmode, key, params, JceSecurity.RANDOM);
+    }
+
+    /**
+     * Initializes this cipher with a key, a set of algorithm
+     * parameters, and a source of randomness.
+     *
+     * <p>The cipher is initialized for one of the following four operations:
+     * encryption, decryption, key wrapping or  key unwrapping, depending
+     * on the value of <code>opmode</code>.
+     *
+     * <p>If this cipher requires any algorithm parameters and
+     * <code>params</code> is null, the underlying cipher implementation is
+     * supposed to generate the required parameters itself (using
+     * provider-specific default or random values) if it is being
+     * initialized for encryption or key wrapping, and raise an
+     * <code>InvalidAlgorithmParameterException</code> if it is being
+     * initialized for decryption or key unwrapping.
+     * The generated parameters can be retrieved using
+     * {@link #getParameters() getParameters} or
+     * {@link #getIV() getIV} (if the parameter is an IV).
+     *
+     * <p>If this cipher (including its underlying feedback or padding scheme)
+     * requires any random bytes (e.g., for parameter generation), it will get
+     * them from <code>random</code>.
+     *
+     * <p>Note that when a Cipher object is initialized, it loses all
+     * previously-acquired state. In other words, initializing a Cipher is
+     * equivalent to creating a new instance of that Cipher and initializing
+     * it.
+     *
+     * @param opmode the operation mode of this cipher (this is one of the
+     * following:
+     * <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,
+     * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)
+     * @param key the encryption key
+     * @param params the algorithm parameters
+     * @param random the source of randomness
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * initializing this cipher, or its keysize exceeds the maximum allowable
+     * keysize (as determined from the configured jurisdiction policy files).
+     * @exception InvalidAlgorithmParameterException if the given algorithm
+     * parameters are inappropriate for this cipher,
+     * or this cipher is being initialized for decryption and requires
+     * algorithm parameters and <code>params</code> is null, or the given
+     * algorithm parameters imply a cryptographic strength that would exceed
+     * the legal limits (as determined from the configured jurisdiction
+     * policy files).
+     */
+    public final void init(int opmode, Key key, AlgorithmParameterSpec params,
+                           SecureRandom random)
+            throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        initialized = false;
+        checkOpmode(opmode);
+
+        if (spi != null) {
+            spi.engineInit(opmode, key, params, random);
+        } else {
+            chooseProvider(I_PARAMSPEC, opmode, key, params, null, random);
+        }
+
+        initialized = true;
+        this.opmode = opmode;
+    }
+
+    /**
+     * Initializes this cipher with a key and a set of algorithm
+     * parameters.
+     *
+     * <p>The cipher is initialized for one of the following four operations:
+     * encryption, decryption, key wrapping or  key unwrapping, depending
+     * on the value of <code>opmode</code>.
+     *
+     * <p>If this cipher requires any algorithm parameters and
+     * <code>params</code> is null, the underlying cipher implementation is
+     * supposed to generate the required parameters itself (using
+     * provider-specific default or random values) if it is being
+     * initialized for encryption or key wrapping, and raise an
+     * <code>InvalidAlgorithmParameterException</code> if it is being
+     * initialized for decryption or key unwrapping.
+     * The generated parameters can be retrieved using
+     * {@link #getParameters() getParameters} or
+     * {@link #getIV() getIV} (if the parameter is an IV).
+     *
+     * <p>If this cipher (including its underlying feedback or padding scheme)
+     * requires any random bytes (e.g., for parameter generation), it will get
+     * them using the {@link SecureRandom <code>SecureRandom</code>}
+     * implementation of the highest-priority
+     * installed provider as the source of randomness.
+     * (If none of the installed providers supply an implementation of
+     * SecureRandom, a system-provided source of randomness will be used.)
+     *
+     * <p>Note that when a Cipher object is initialized, it loses all
+     * previously-acquired state. In other words, initializing a Cipher is
+     * equivalent to creating a new instance of that Cipher and initializing
+     * it.
+     *
+     * @param opmode the operation mode of this cipher (this is one of the
+     * following: <code>ENCRYPT_MODE</code>,
+     * <code>DECRYPT_MODE</code>, <code>WRAP_MODE</code>
+     * or <code>UNWRAP_MODE</code>)
+     * @param key the encryption key
+     * @param params the algorithm parameters
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * initializing this cipher, or its keysize exceeds the maximum allowable
+     * keysize (as determined from the configured jurisdiction policy files).
+     * @exception InvalidAlgorithmParameterException if the given algorithm
+     * parameters are inappropriate for this cipher,
+     * or this cipher is being initialized for decryption and requires
+     * algorithm parameters and <code>params</code> is null, or the given
+     * algorithm parameters imply a cryptographic strength that would exceed
+     * the legal limits (as determined from the configured jurisdiction
+     * policy files).
+     */
+    public final void init(int opmode, Key key, AlgorithmParameters params)
+            throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        init(opmode, key, params, JceSecurity.RANDOM);
+    }
+
+    /**
+     * Initializes this cipher with a key, a set of algorithm
+     * parameters, and a source of randomness.
+     *
+     * <p>The cipher is initialized for one of the following four operations:
+     * encryption, decryption, key wrapping or  key unwrapping, depending
+     * on the value of <code>opmode</code>.
+     *
+     * <p>If this cipher requires any algorithm parameters and
+     * <code>params</code> is null, the underlying cipher implementation is
+     * supposed to generate the required parameters itself (using
+     * provider-specific default or random values) if it is being
+     * initialized for encryption or key wrapping, and raise an
+     * <code>InvalidAlgorithmParameterException</code> if it is being
+     * initialized for decryption or key unwrapping.
+     * The generated parameters can be retrieved using
+     * {@link #getParameters() getParameters} or
+     * {@link #getIV() getIV} (if the parameter is an IV).
+     *
+     * <p>If this cipher (including its underlying feedback or padding scheme)
+     * requires any random bytes (e.g., for parameter generation), it will get
+     * them from <code>random</code>.
+     *
+     * <p>Note that when a Cipher object is initialized, it loses all
+     * previously-acquired state. In other words, initializing a Cipher is
+     * equivalent to creating a new instance of that Cipher and initializing
+     * it.
+     *
+     * @param opmode the operation mode of this cipher (this is one of the
+     * following: <code>ENCRYPT_MODE</code>,
+     * <code>DECRYPT_MODE</code>, <code>WRAP_MODE</code>
+     * or <code>UNWRAP_MODE</code>)
+     * @param key the encryption key
+     * @param params the algorithm parameters
+     * @param random the source of randomness
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * initializing this cipher, or its keysize exceeds the maximum allowable
+     * keysize (as determined from the configured jurisdiction policy files).
+     * @exception InvalidAlgorithmParameterException if the given algorithm
+     * parameters are inappropriate for this cipher,
+     * or this cipher is being initialized for decryption and requires
+     * algorithm parameters and <code>params</code> is null, or the given
+     * algorithm parameters imply a cryptographic strength that would exceed
+     * the legal limits (as determined from the configured jurisdiction
+     * policy files).
+     */
+    public final void init(int opmode, Key key, AlgorithmParameters params,
+                           SecureRandom random)
+            throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        initialized = false;
+        checkOpmode(opmode);
+
+        if (spi != null) {
+            spi.engineInit(opmode, key, params, random);
+        } else {
+            chooseProvider(I_PARAMS, opmode, key, null, params, random);
+        }
+
+        initialized = true;
+        this.opmode = opmode;
+    }
+
+    /**
+     * Initializes this cipher with the public key from the given certificate.
+     * <p> The cipher is initialized for one of the following four operations:
+     * encryption, decryption, key wrapping or  key unwrapping, depending
+     * on the value of <code>opmode</code>.
+     *
+     * <p>If the certificate is of type X.509 and has a <i>key usage</i>
+     * extension field marked as critical, and the value of the <i>key usage</i>
+     * extension field implies that the public key in
+     * the certificate and its corresponding private key are not
+     * supposed to be used for the operation represented by the value
+     * of <code>opmode</code>,
+     * an <code>InvalidKeyException</code>
+     * is thrown.
+     *
+     * <p> If this cipher requires any algorithm parameters that cannot be
+     * derived from the public key in the given certificate, the underlying
+     * cipher
+     * implementation is supposed to generate the required parameters itself
+     * (using provider-specific default or ramdom values) if it is being
+     * initialized for encryption or key wrapping, and raise an <code>
+     * InvalidKeyException</code> if it is being initialized for decryption or
+     * key unwrapping.
+     * The generated parameters can be retrieved using
+     * {@link #getParameters() getParameters} or
+     * {@link #getIV() getIV} (if the parameter is an IV).
+     *
+     * <p>If this cipher (including its underlying feedback or padding scheme)
+     * requires any random bytes (e.g., for parameter generation), it will get
+     * them using the
+     * <code>SecureRandom</code>
+     * implementation of the highest-priority
+     * installed provider as the source of randomness.
+     * (If none of the installed providers supply an implementation of
+     * SecureRandom, a system-provided source of randomness will be used.)
+     *
+     * <p>Note that when a Cipher object is initialized, it loses all
+     * previously-acquired state. In other words, initializing a Cipher is
+     * equivalent to creating a new instance of that Cipher and initializing
+     * it.
+     *
+     * @param opmode the operation mode of this cipher (this is one of the
+     * following:
+     * <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,
+     * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)
+     * @param certificate the certificate
+     *
+     * @exception InvalidKeyException if the public key in the given
+     * certificate is inappropriate for initializing this cipher, or this
+     * cipher is being initialized for decryption or unwrapping keys and
+     * requires algorithm parameters that cannot be determined from the
+     * public key in the given certificate, or the keysize of the public key
+     * in the given certificate has a keysize that exceeds the maximum
+     * allowable keysize (as determined by the configured jurisdiction policy
+     * files).
+     */
+    public final void init(int opmode, Certificate certificate)
+            throws InvalidKeyException
+    {
+        init(opmode, certificate, JceSecurity.RANDOM);
+    }
+
+    /**
+     * Initializes this cipher with the public key from the given certificate
+     * and
+     * a source of randomness.
+     *
+     * <p>The cipher is initialized for one of the following four operations:
+     * encryption, decryption, key wrapping
+     * or key unwrapping, depending on
+     * the value of <code>opmode</code>.
+     *
+     * <p>If the certificate is of type X.509 and has a <i>key usage</i>
+     * extension field marked as critical, and the value of the <i>key usage</i>
+     * extension field implies that the public key in
+     * the certificate and its corresponding private key are not
+     * supposed to be used for the operation represented by the value of
+     * <code>opmode</code>,
+     * an <code>InvalidKeyException</code>
+     * is thrown.
+     *
+     * <p>If this cipher requires any algorithm parameters that cannot be
+     * derived from the public key in the given <code>certificate</code>,
+     * the underlying cipher
+     * implementation is supposed to generate the required parameters itself
+     * (using provider-specific default or random values) if it is being
+     * initialized for encryption or key wrapping, and raise an
+     * <code>InvalidKeyException</code> if it is being
+     * initialized for decryption or key unwrapping.
+     * The generated parameters can be retrieved using
+     * {@link #getParameters() getParameters} or
+     * {@link #getIV() getIV} (if the parameter is an IV).
+     *
+     * <p>If this cipher (including its underlying feedback or padding scheme)
+     * requires any random bytes (e.g., for parameter generation), it will get
+     * them from <code>random</code>.
+     *
+     * <p>Note that when a Cipher object is initialized, it loses all
+     * previously-acquired state. In other words, initializing a Cipher is
+     * equivalent to creating a new instance of that Cipher and initializing
+     * it.
+     *
+     * @param opmode the operation mode of this cipher (this is one of the
+     * following:
+     * <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,
+     * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)
+     * @param certificate the certificate
+     * @param random the source of randomness
+     *
+     * @exception InvalidKeyException if the public key in the given
+     * certificate is inappropriate for initializing this cipher, or this
+     * cipher is being initialized for decryption or unwrapping keys and
+     * requires algorithm parameters that cannot be determined from the
+     * public key in the given certificate, or the keysize of the public key
+     * in the given certificate has a keysize that exceeds the maximum
+     * allowable keysize (as determined by the configured jurisdiction policy
+     * files).
+     */
+    public final void init(int opmode, Certificate certificate,
+                           SecureRandom random)
+            throws InvalidKeyException
+    {
+        initialized = false;
+        checkOpmode(opmode);
+
+        // Check key usage if the certificate is of
+        // type X.509.
+        if (certificate instanceof java.security.cert.X509Certificate) {
+            // Check whether the cert has a key usage extension
+            // marked as a critical extension.
+            X509Certificate cert = (X509Certificate)certificate;
+            Set critSet = cert.getCriticalExtensionOIDs();
+
+            if (critSet != null && !critSet.isEmpty()
+                && critSet.contains(KEY_USAGE_EXTENSION_OID)) {
+                boolean[] keyUsageInfo = cert.getKeyUsage();
+                // keyUsageInfo[2] is for keyEncipherment;
+                // keyUsageInfo[3] is for dataEncipherment.
+                if ((keyUsageInfo != null) &&
+                    (((opmode == Cipher.ENCRYPT_MODE) &&
+                      (keyUsageInfo.length > 3) &&
+                      (keyUsageInfo[3] == false)) ||
+                     ((opmode == Cipher.WRAP_MODE) &&
+                      (keyUsageInfo.length > 2) &&
+                      (keyUsageInfo[2] == false)))) {
+                    throw new InvalidKeyException("Wrong key usage");
+                }
+            }
+        }
+
+        PublicKey publicKey =
+            (certificate==null? null:certificate.getPublicKey());
+
+        if (spi != null) {
+            spi.engineInit(opmode, publicKey, random);
+        } else {
+            try {
+                chooseProvider(I_CERT, opmode, publicKey, null, null, random);
+            } catch (InvalidAlgorithmParameterException e) {
+                // should never occur
+                throw new InvalidKeyException(e);
+            }
+        }
+
+        initialized = true;
+        this.opmode = opmode;
+    }
+
+    /**
+     * Ensures that Cipher is in a valid state for update() and doFinal()
+     * calls - should be initialized and in ENCRYPT_MODE or DECRYPT_MODE.
+     * @throws IllegalStateException if Cipher object is not in valid state.
+     */
+    private void checkCipherState() {
+        if (!(this instanceof NullCipher)) {
+            if (!initialized) {
+                throw new IllegalStateException("Cipher not initialized");
+            }
+            if ((opmode != Cipher.ENCRYPT_MODE) &&
+                (opmode != Cipher.DECRYPT_MODE)) {
+                throw new IllegalStateException("Cipher not initialized " +
+                                                "for encryption/decryption");
+            }
+        }
+    }
+
+    /**
+     * Continues a multiple-part encryption or decryption operation
+     * (depending on how this cipher was initialized), processing another data
+     * part.
+     *
+     * <p>The bytes in the <code>input</code> buffer are processed, and the
+     * result is stored in a new buffer.
+     *
+     * <p>If <code>input</code> has a length of zero, this method returns
+     * <code>null</code>.
+     *
+     * @param input the input buffer
+     *
+     * @return the new buffer with the result, or null if the underlying
+     * cipher is a block cipher and the input data is too short to result in a
+     * new block.
+     *
+     * @exception IllegalStateException if this cipher is in a wrong state
+     * (e.g., has not been initialized)
+     */
+    public final byte[] update(byte[] input) {
+        checkCipherState();
+
+        // Input sanity check
+        if (input == null) {
+            throw new IllegalArgumentException("Null input buffer");
+        }
+
+        chooseFirstProvider();
+        if (input.length == 0) {
+            return null;
+        }
+        return spi.engineUpdate(input, 0, input.length);
+    }
+
+    /**
+     * Continues a multiple-part encryption or decryption operation
+     * (depending on how this cipher was initialized), processing another data
+     * part.
+     *
+     * <p>The first <code>inputLen</code> bytes in the <code>input</code>
+     * buffer, starting at <code>inputOffset</code> inclusive, are processed,
+     * and the result is stored in a new buffer.
+     *
+     * <p>If <code>inputLen</code> is zero, this method returns
+     * <code>null</code>.
+     *
+     * @param input the input buffer
+     * @param inputOffset the offset in <code>input</code> where the input
+     * starts
+     * @param inputLen the input length
+     *
+     * @return the new buffer with the result, or null if the underlying
+     * cipher is a block cipher and the input data is too short to result in a
+     * new block.
+     *
+     * @exception IllegalStateException if this cipher is in a wrong state
+     * (e.g., has not been initialized)
+     */
+    public final byte[] update(byte[] input, int inputOffset, int inputLen) {
+        checkCipherState();
+
+        // Input sanity check
+        if (input == null || inputOffset < 0
+            || inputLen > (input.length - inputOffset) || inputLen < 0) {
+            throw new IllegalArgumentException("Bad arguments");
+        }
+
+        chooseFirstProvider();
+        if (inputLen == 0) {
+            return null;
+        }
+        return spi.engineUpdate(input, inputOffset, inputLen);
+    }
+
+    /**
+     * Continues a multiple-part encryption or decryption operation
+     * (depending on how this cipher was initialized), processing another data
+     * part.
+     *
+     * <p>The first <code>inputLen</code> bytes in the <code>input</code>
+     * buffer, starting at <code>inputOffset</code> inclusive, are processed,
+     * and the result is stored in the <code>output</code> buffer.
+     *
+     * <p>If the <code>output</code> buffer is too small to hold the result,
+     * a <code>ShortBufferException</code> is thrown. In this case, repeat this
+     * call with a larger output buffer. Use
+     * {@link #getOutputSize(int) getOutputSize} to determine how big
+     * the output buffer should be.
+     *
+     * <p>If <code>inputLen</code> is zero, this method returns
+     * a length of zero.
+     *
+     * <p>Note: this method should be copy-safe, which means the
+     * <code>input</code> and <code>output</code> buffers can reference
+     * the same byte array and no unprocessed input data is overwritten
+     * when the result is copied into the output buffer.
+     *
+     * @param input the input buffer
+     * @param inputOffset the offset in <code>input</code> where the input
+     * starts
+     * @param inputLen the input length
+     * @param output the buffer for the result
+     *
+     * @return the number of bytes stored in <code>output</code>
+     *
+     * @exception IllegalStateException if this cipher is in a wrong state
+     * (e.g., has not been initialized)
+     * @exception ShortBufferException if the given output buffer is too small
+     * to hold the result
+     */
+    public final int update(byte[] input, int inputOffset, int inputLen,
+                            byte[] output)
+            throws ShortBufferException {
+        checkCipherState();
+
+        // Input sanity check
+        if (input == null || inputOffset < 0
+            || inputLen > (input.length - inputOffset) || inputLen < 0) {
+            throw new IllegalArgumentException("Bad arguments");
+        }
+
+        chooseFirstProvider();
+        if (inputLen == 0) {
+            return 0;
+        }
+        return spi.engineUpdate(input, inputOffset, inputLen,
+                                      output, 0);
+    }
+
+    /**
+     * Continues a multiple-part encryption or decryption operation
+     * (depending on how this cipher was initialized), processing another data
+     * part.
+     *
+     * <p>The first <code>inputLen</code> bytes in the <code>input</code>
+     * buffer, starting at <code>inputOffset</code> inclusive, are processed,
+     * and the result is stored in the <code>output</code> buffer, starting at
+     * <code>outputOffset</code> inclusive.
+     *
+     * <p>If the <code>output</code> buffer is too small to hold the result,
+     * a <code>ShortBufferException</code> is thrown. In this case, repeat this
+     * call with a larger output buffer. Use
+     * {@link #getOutputSize(int) getOutputSize} to determine how big
+     * the output buffer should be.
+     *
+     * <p>If <code>inputLen</code> is zero, this method returns
+     * a length of zero.
+     *
+     * <p>Note: this method should be copy-safe, which means the
+     * <code>input</code> and <code>output</code> buffers can reference
+     * the same byte array and no unprocessed input data is overwritten
+     * when the result is copied into the output buffer.
+     *
+     * @param input the input buffer
+     * @param inputOffset the offset in <code>input</code> where the input
+     * starts
+     * @param inputLen the input length
+     * @param output the buffer for the result
+     * @param outputOffset the offset in <code>output</code> where the result
+     * is stored
+     *
+     * @return the number of bytes stored in <code>output</code>
+     *
+     * @exception IllegalStateException if this cipher is in a wrong state
+     * (e.g., has not been initialized)
+     * @exception ShortBufferException if the given output buffer is too small
+     * to hold the result
+     */
+    public final int update(byte[] input, int inputOffset, int inputLen,
+                            byte[] output, int outputOffset)
+            throws ShortBufferException {
+        checkCipherState();
+
+        // Input sanity check
+        if (input == null || inputOffset < 0
+            || inputLen > (input.length - inputOffset) || inputLen < 0
+            || outputOffset < 0) {
+            throw new IllegalArgumentException("Bad arguments");
+        }
+
+        chooseFirstProvider();
+        if (inputLen == 0) {
+            return 0;
+        }
+        return spi.engineUpdate(input, inputOffset, inputLen,
+                                      output, outputOffset);
+    }
+
+    /**
+     * Continues a multiple-part encryption or decryption operation
+     * (depending on how this cipher was initialized), processing another data
+     * part.
+     *
+     * <p>All <code>input.remaining()</code> bytes starting at
+     * <code>input.position()</code> are processed. The result is stored
+     * in the output buffer.
+     * Upon return, the input buffer's position will be equal
+     * to its limit; its limit will not have changed. The output buffer's
+     * position will have advanced by n, where n is the value returned
+     * by this method; the output buffer's limit will not have changed.
+     *
+     * <p>If <code>output.remaining()</code> bytes are insufficient to
+     * hold the result, a <code>ShortBufferException</code> is thrown.
+     * In this case, repeat this call with a larger output buffer. Use
+     * {@link #getOutputSize(int) getOutputSize} to determine how big
+     * the output buffer should be.
+     *
+     * <p>Note: this method should be copy-safe, which means the
+     * <code>input</code> and <code>output</code> buffers can reference
+     * the same block of memory and no unprocessed input data is overwritten
+     * when the result is copied into the output buffer.
+     *
+     * @param input the input ByteBuffer
+     * @param output the output ByteByffer
+     *
+     * @return the number of bytes stored in <code>output</code>
+     *
+     * @exception IllegalStateException if this cipher is in a wrong state
+     * (e.g., has not been initialized)
+     * @exception IllegalArgumentException if input and output are the
+     *   same object
+     * @exception ReadOnlyBufferException if the output buffer is read-only
+     * @exception ShortBufferException if there is insufficient space in the
+     * output buffer
+     * @since 1.5
+     */
+    public final int update(ByteBuffer input, ByteBuffer output)
+            throws ShortBufferException {
+        checkCipherState();
+
+        if ((input == null) || (output == null)) {
+            throw new IllegalArgumentException("Buffers must not be null");
+        }
+        if (input == output) {
+            throw new IllegalArgumentException("Input and output buffers must "
+                + "not be the same object, consider using buffer.duplicate()");
+        }
+        if (output.isReadOnly()) {
+            throw new ReadOnlyBufferException();
+        }
+
+        chooseFirstProvider();
+        return spi.engineUpdate(input, output);
+    }
+
+    /**
+     * Finishes a multiple-part encryption or decryption operation, depending
+     * on how this cipher was initialized.
+     *
+     * <p>Input data that may have been buffered during a previous
+     * <code>update</code> operation is processed, with padding (if requested)
+     * being applied.
+     * The result is stored in a new buffer.
+     *
+     * <p>Upon finishing, this method resets this cipher object to the state
+     * it was in when previously initialized via a call to <code>init</code>.
+     * That is, the object is reset and available to encrypt or decrypt
+     * (depending on the operation mode that was specified in the call to
+     * <code>init</code>) more data.
+     *
+     * <p>Note: if any exception is thrown, this cipher object may need to
+     * be reset before it can be used again.
+     *
+     * @return the new buffer with the result
+     *
+     * @exception IllegalStateException if this cipher is in a wrong state
+     * (e.g., has not been initialized)
+     * @exception IllegalBlockSizeException if this cipher is a block cipher,
+     * no padding has been requested (only in encryption mode), and the total
+     * input length of the data processed by this cipher is not a multiple of
+     * block size; or if this encryption algorithm is unable to
+     * process the input data provided.
+     * @exception BadPaddingException if this cipher is in decryption mode,
+     * and (un)padding has been requested, but the decrypted data is not
+     * bounded by the appropriate padding bytes
+     */
+    public final byte[] doFinal()
+            throws IllegalBlockSizeException, BadPaddingException {
+        checkCipherState();
+
+        chooseFirstProvider();
+        return spi.engineDoFinal(null, 0, 0);
+    }
+
+    /**
+     * Finishes a multiple-part encryption or decryption operation, depending
+     * on how this cipher was initialized.
+     *
+     * <p>Input data that may have been buffered during a previous
+     * <code>update</code> operation is processed, with padding (if requested)
+     * being applied.
+     * The result is stored in the <code>output</code> buffer, starting at
+     * <code>outputOffset</code> inclusive.
+     *
+     * <p>If the <code>output</code> buffer is too small to hold the result,
+     * a <code>ShortBufferException</code> is thrown. In this case, repeat this
+     * call with a larger output buffer. Use
+     * {@link #getOutputSize(int) getOutputSize} to determine how big
+     * the output buffer should be.
+     *
+     * <p>Upon finishing, this method resets this cipher object to the state
+     * it was in when previously initialized via a call to <code>init</code>.
+     * That is, the object is reset and available to encrypt or decrypt
+     * (depending on the operation mode that was specified in the call to
+     * <code>init</code>) more data.
+     *
+     * <p>Note: if any exception is thrown, this cipher object may need to
+     * be reset before it can be used again.
+     *
+     * @param output the buffer for the result
+     * @param outputOffset the offset in <code>output</code> where the result
+     * is stored
+     *
+     * @return the number of bytes stored in <code>output</code>
+     *
+     * @exception IllegalStateException if this cipher is in a wrong state
+     * (e.g., has not been initialized)
+     * @exception IllegalBlockSizeException if this cipher is a block cipher,
+     * no padding has been requested (only in encryption mode), and the total
+     * input length of the data processed by this cipher is not a multiple of
+     * block size; or if this encryption algorithm is unable to
+     * process the input data provided.
+     * @exception ShortBufferException if the given output buffer is too small
+     * to hold the result
+     * @exception BadPaddingException if this cipher is in decryption mode,
+     * and (un)padding has been requested, but the decrypted data is not
+     * bounded by the appropriate padding bytes
+     */
+    public final int doFinal(byte[] output, int outputOffset)
+            throws IllegalBlockSizeException, ShortBufferException,
+               BadPaddingException {
+        checkCipherState();
+
+        // Input sanity check
+        if ((output == null) || (outputOffset < 0)) {
+            throw new IllegalArgumentException("Bad arguments");
+        }
+
+        chooseFirstProvider();
+        return spi.engineDoFinal(null, 0, 0, output, outputOffset);
+    }
+
+    /**
+     * Encrypts or decrypts data in a single-part operation, or finishes a
+     * multiple-part operation. The data is encrypted or decrypted,
+     * depending on how this cipher was initialized.
+     *
+     * <p>The bytes in the <code>input</code> buffer, and any input bytes that
+     * may have been buffered during a previous <code>update</code> operation,
+     * are processed, with padding (if requested) being applied.
+     * The result is stored in a new buffer.
+     *
+     * <p>Upon finishing, this method resets this cipher object to the state
+     * it was in when previously initialized via a call to <code>init</code>.
+     * That is, the object is reset and available to encrypt or decrypt
+     * (depending on the operation mode that was specified in the call to
+     * <code>init</code>) more data.
+     *
+     * <p>Note: if any exception is thrown, this cipher object may need to
+     * be reset before it can be used again.
+     *
+     * @param input the input buffer
+     *
+     * @return the new buffer with the result
+     *
+     * @exception IllegalStateException if this cipher is in a wrong state
+     * (e.g., has not been initialized)
+     * @exception IllegalBlockSizeException if this cipher is a block cipher,
+     * no padding has been requested (only in encryption mode), and the total
+     * input length of the data processed by this cipher is not a multiple of
+     * block size; or if this encryption algorithm is unable to
+     * process the input data provided.
+     * @exception BadPaddingException if this cipher is in decryption mode,
+     * and (un)padding has been requested, but the decrypted data is not
+     * bounded by the appropriate padding bytes
+     */
+    public final byte[] doFinal(byte[] input)
+            throws IllegalBlockSizeException, BadPaddingException {
+        checkCipherState();
+
+        // Input sanity check
+        if (input == null) {
+            throw new IllegalArgumentException("Null input buffer");
+        }
+
+        chooseFirstProvider();
+        return spi.engineDoFinal(input, 0, input.length);
+    }
+
+    /**
+     * Encrypts or decrypts data in a single-part operation, or finishes a
+     * multiple-part operation. The data is encrypted or decrypted,
+     * depending on how this cipher was initialized.
+     *
+     * <p>The first <code>inputLen</code> bytes in the <code>input</code>
+     * buffer, starting at <code>inputOffset</code> inclusive, and any input
+     * bytes that may have been buffered during a previous <code>update</code>
+     * operation, are processed, with padding (if requested) being applied.
+     * The result is stored in a new buffer.
+     *
+     * <p>Upon finishing, this method resets this cipher object to the state
+     * it was in when previously initialized via a call to <code>init</code>.
+     * That is, the object is reset and available to encrypt or decrypt
+     * (depending on the operation mode that was specified in the call to
+     * <code>init</code>) more data.
+     *
+     * <p>Note: if any exception is thrown, this cipher object may need to
+     * be reset before it can be used again.
+     *
+     * @param input the input buffer
+     * @param inputOffset the offset in <code>input</code> where the input
+     * starts
+     * @param inputLen the input length
+     *
+     * @return the new buffer with the result
+     *
+     * @exception IllegalStateException if this cipher is in a wrong state
+     * (e.g., has not been initialized)
+     * @exception IllegalBlockSizeException if this cipher is a block cipher,
+     * no padding has been requested (only in encryption mode), and the total
+     * input length of the data processed by this cipher is not a multiple of
+     * block size; or if this encryption algorithm is unable to
+     * process the input data provided.
+     * @exception BadPaddingException if this cipher is in decryption mode,
+     * and (un)padding has been requested, but the decrypted data is not
+     * bounded by the appropriate padding bytes
+     */
+    public final byte[] doFinal(byte[] input, int inputOffset, int inputLen)
+            throws IllegalBlockSizeException, BadPaddingException {
+        checkCipherState();
+
+        // Input sanity check
+        if (input == null || inputOffset < 0
+            || inputLen > (input.length - inputOffset) || inputLen < 0) {
+            throw new IllegalArgumentException("Bad arguments");
+        }
+
+        chooseFirstProvider();
+        return spi.engineDoFinal(input, inputOffset, inputLen);
+    }
+
+    /**
+     * Encrypts or decrypts data in a single-part operation, or finishes a
+     * multiple-part operation. The data is encrypted or decrypted,
+     * depending on how this cipher was initialized.
+     *
+     * <p>The first <code>inputLen</code> bytes in the <code>input</code>
+     * buffer, starting at <code>inputOffset</code> inclusive, and any input
+     * bytes that may have been buffered during a previous <code>update</code>
+     * operation, are processed, with padding (if requested) being applied.
+     * The result is stored in the <code>output</code> buffer.
+     *
+     * <p>If the <code>output</code> buffer is too small to hold the result,
+     * a <code>ShortBufferException</code> is thrown. In this case, repeat this
+     * call with a larger output buffer. Use
+     * {@link #getOutputSize(int) getOutputSize} to determine how big
+     * the output buffer should be.
+     *
+     * <p>Upon finishing, this method resets this cipher object to the state
+     * it was in when previously initialized via a call to <code>init</code>.
+     * That is, the object is reset and available to encrypt or decrypt
+     * (depending on the operation mode that was specified in the call to
+     * <code>init</code>) more data.
+     *
+     * <p>Note: if any exception is thrown, this cipher object may need to
+     * be reset before it can be used again.
+     *
+     * <p>Note: this method should be copy-safe, which means the
+     * <code>input</code> and <code>output</code> buffers can reference
+     * the same byte array and no unprocessed input data is overwritten
+     * when the result is copied into the output buffer.
+     *
+     * @param input the input buffer
+     * @param inputOffset the offset in <code>input</code> where the input
+     * starts
+     * @param inputLen the input length
+     * @param output the buffer for the result
+     *
+     * @return the number of bytes stored in <code>output</code>
+     *
+     * @exception IllegalStateException if this cipher is in a wrong state
+     * (e.g., has not been initialized)
+     * @exception IllegalBlockSizeException if this cipher is a block cipher,
+     * no padding has been requested (only in encryption mode), and the total
+     * input length of the data processed by this cipher is not a multiple of
+     * block size; or if this encryption algorithm is unable to
+     * process the input data provided.
+     * @exception ShortBufferException if the given output buffer is too small
+     * to hold the result
+     * @exception BadPaddingException if this cipher is in decryption mode,
+     * and (un)padding has been requested, but the decrypted data is not
+     * bounded by the appropriate padding bytes
+     */
+    public final int doFinal(byte[] input, int inputOffset, int inputLen,
+                             byte[] output)
+            throws ShortBufferException, IllegalBlockSizeException,
+            BadPaddingException {
+        checkCipherState();
+
+        // Input sanity check
+        if (input == null || inputOffset < 0
+            || inputLen > (input.length - inputOffset) || inputLen < 0) {
+            throw new IllegalArgumentException("Bad arguments");
+        }
+
+        chooseFirstProvider();
+        return spi.engineDoFinal(input, inputOffset, inputLen,
+                                       output, 0);
+    }
+
+    /**
+     * Encrypts or decrypts data in a single-part operation, or finishes a
+     * multiple-part operation. The data is encrypted or decrypted,
+     * depending on how this cipher was initialized.
+     *
+     * <p>The first <code>inputLen</code> bytes in the <code>input</code>
+     * buffer, starting at <code>inputOffset</code> inclusive, and any input
+     * bytes that may have been buffered during a previous
+     * <code>update</code> operation, are processed, with padding
+     * (if requested) being applied.
+     * The result is stored in the <code>output</code> buffer, starting at
+     * <code>outputOffset</code> inclusive.
+     *
+     * <p>If the <code>output</code> buffer is too small to hold the result,
+     * a <code>ShortBufferException</code> is thrown. In this case, repeat this
+     * call with a larger output buffer. Use
+     * {@link #getOutputSize(int) getOutputSize} to determine how big
+     * the output buffer should be.
+     *
+     * <p>Upon finishing, this method resets this cipher object to the state
+     * it was in when previously initialized via a call to <code>init</code>.
+     * That is, the object is reset and available to encrypt or decrypt
+     * (depending on the operation mode that was specified in the call to
+     * <code>init</code>) more data.
+     *
+     * <p>Note: if any exception is thrown, this cipher object may need to
+     * be reset before it can be used again.
+     *
+     * <p>Note: this method should be copy-safe, which means the
+     * <code>input</code> and <code>output</code> buffers can reference
+     * the same byte array and no unprocessed input data is overwritten
+     * when the result is copied into the output buffer.
+     *
+     * @param input the input buffer
+     * @param inputOffset the offset in <code>input</code> where the input
+     * starts
+     * @param inputLen the input length
+     * @param output the buffer for the result
+     * @param outputOffset the offset in <code>output</code> where the result
+     * is stored
+     *
+     * @return the number of bytes stored in <code>output</code>
+     *
+     * @exception IllegalStateException if this cipher is in a wrong state
+     * (e.g., has not been initialized)
+     * @exception IllegalBlockSizeException if this cipher is a block cipher,
+     * no padding has been requested (only in encryption mode), and the total
+     * input length of the data processed by this cipher is not a multiple of
+     * block size; or if this encryption algorithm is unable to
+     * process the input data provided.
+     * @exception ShortBufferException if the given output buffer is too small
+     * to hold the result
+     * @exception BadPaddingException if this cipher is in decryption mode,
+     * and (un)padding has been requested, but the decrypted data is not
+     * bounded by the appropriate padding bytes
+     */
+    public final int doFinal(byte[] input, int inputOffset, int inputLen,
+                             byte[] output, int outputOffset)
+            throws ShortBufferException, IllegalBlockSizeException,
+            BadPaddingException {
+        checkCipherState();
+
+        // Input sanity check
+        if (input == null || inputOffset < 0
+            || inputLen > (input.length - inputOffset) || inputLen < 0
+            || outputOffset < 0) {
+            throw new IllegalArgumentException("Bad arguments");
+        }
+
+        chooseFirstProvider();
+        return spi.engineDoFinal(input, inputOffset, inputLen,
+                                       output, outputOffset);
+    }
+
+    /**
+     * Encrypts or decrypts data in a single-part operation, or finishes a
+     * multiple-part operation. The data is encrypted or decrypted,
+     * depending on how this cipher was initialized.
+     *
+     * <p>All <code>input.remaining()</code> bytes starting at
+     * <code>input.position()</code> are processed. The result is stored
+     * in the output buffer.
+     * Upon return, the input buffer's position will be equal
+     * to its limit; its limit will not have changed. The output buffer's
+     * position will have advanced by n, where n is the value returned
+     * by this method; the output buffer's limit will not have changed.
+     *
+     * <p>If <code>output.remaining()</code> bytes are insufficient to
+     * hold the result, a <code>ShortBufferException</code> is thrown.
+     * In this case, repeat this call with a larger output buffer. Use
+     * {@link #getOutputSize(int) getOutputSize} to determine how big
+     * the output buffer should be.
+     *
+     * <p>Upon finishing, this method resets this cipher object to the state
+     * it was in when previously initialized via a call to <code>init</code>.
+     * That is, the object is reset and available to encrypt or decrypt
+     * (depending on the operation mode that was specified in the call to
+     * <code>init</code>) more data.
+     *
+     * <p>Note: if any exception is thrown, this cipher object may need to
+     * be reset before it can be used again.
+     *
+     * <p>Note: this method should be copy-safe, which means the
+     * <code>input</code> and <code>output</code> buffers can reference
+     * the same byte array and no unprocessed input data is overwritten
+     * when the result is copied into the output buffer.
+     *
+     * @param input the input ByteBuffer
+     * @param output the output ByteBuffer
+     *
+     * @return the number of bytes stored in <code>output</code>
+     *
+     * @exception IllegalStateException if this cipher is in a wrong state
+     * (e.g., has not been initialized)
+     * @exception IllegalArgumentException if input and output are the
+     *   same object
+     * @exception ReadOnlyBufferException if the output buffer is read-only
+     * @exception IllegalBlockSizeException if this cipher is a block cipher,
+     * no padding has been requested (only in encryption mode), and the total
+     * input length of the data processed by this cipher is not a multiple of
+     * block size; or if this encryption algorithm is unable to
+     * process the input data provided.
+     * @exception ShortBufferException if there is insufficient space in the
+     * output buffer
+     * @exception BadPaddingException if this cipher is in decryption mode,
+     * and (un)padding has been requested, but the decrypted data is not
+     * bounded by the appropriate padding bytes
+     * @since 1.5
+     */
+    public final int doFinal(ByteBuffer input, ByteBuffer output)
+            throws ShortBufferException, IllegalBlockSizeException,
+            BadPaddingException {
+        checkCipherState();
+
+        if ((input == null) || (output == null)) {
+            throw new IllegalArgumentException("Buffers must not be null");
+        }
+        if (input == output) {
+            throw new IllegalArgumentException("Input and output buffers must "
+                + "not be the same object, consider using buffer.duplicate()");
+        }
+        if (output.isReadOnly()) {
+            throw new ReadOnlyBufferException();
+        }
+
+        chooseFirstProvider();
+        return spi.engineDoFinal(input, output);
+    }
+
+    /**
+     * Wrap a key.
+     *
+     * @param key the key to be wrapped.
+     *
+     * @return the wrapped key.
+     *
+     * @exception IllegalStateException if this cipher is in a wrong
+     * state (e.g., has not been initialized).
+     *
+     * @exception IllegalBlockSizeException if this cipher is a block
+     * cipher, no padding has been requested, and the length of the
+     * encoding of the key to be wrapped is not a
+     * multiple of the block size.
+     *
+     * @exception InvalidKeyException if it is impossible or unsafe to
+     * wrap the key with this cipher (e.g., a hardware protected key is
+     * being passed to a software-only cipher).
+     */
+    public final byte[] wrap(Key key)
+            throws IllegalBlockSizeException, InvalidKeyException {
+        if (!(this instanceof NullCipher)) {
+            if (!initialized) {
+                throw new IllegalStateException("Cipher not initialized");
+            }
+            if (opmode != Cipher.WRAP_MODE) {
+                throw new IllegalStateException("Cipher not initialized " +
+                                                "for wrapping keys");
+            }
+        }
+
+        chooseFirstProvider();
+        return spi.engineWrap(key);
+    }
+
+    /**
+     * Unwrap a previously wrapped key.
+     *
+     * @param wrappedKey the key to be unwrapped.
+     *
+     * @param wrappedKeyAlgorithm the algorithm associated with the wrapped
+     * key.
+     *
+     * @param wrappedKeyType the type of the wrapped key. This must be one of
+     * <code>SECRET_KEY</code>, <code>PRIVATE_KEY</code>, or
+     * <code>PUBLIC_KEY</code>.
+     *
+     * @return the unwrapped key.
+     *
+     * @exception IllegalStateException if this cipher is in a wrong state
+     * (e.g., has not been initialized).
+     *
+     * @exception NoSuchAlgorithmException if no installed providers
+     * can create keys of type <code>wrappedKeyType</code> for the
+     * <code>wrappedKeyAlgorithm</code>.
+     *
+     * @exception InvalidKeyException if <code>wrappedKey</code> does not
+     * represent a wrapped key of type <code>wrappedKeyType</code> for
+     * the <code>wrappedKeyAlgorithm</code>.
+     */
+    public final Key unwrap(byte[] wrappedKey,
+                            String wrappedKeyAlgorithm,
+                            int wrappedKeyType)
+            throws InvalidKeyException, NoSuchAlgorithmException {
+
+        if (!(this instanceof NullCipher)) {
+            if (!initialized) {
+                throw new IllegalStateException("Cipher not initialized");
+            }
+            if (opmode != Cipher.UNWRAP_MODE) {
+                throw new IllegalStateException("Cipher not initialized " +
+                                                "for unwrapping keys");
+            }
+        }
+        if ((wrappedKeyType != SECRET_KEY) &&
+            (wrappedKeyType != PRIVATE_KEY) &&
+            (wrappedKeyType != PUBLIC_KEY)) {
+            throw new InvalidParameterException("Invalid key type");
+        }
+
+        chooseFirstProvider();
+        return spi.engineUnwrap(wrappedKey,
+                                      wrappedKeyAlgorithm,
+                                      wrappedKeyType);
+    }
+
+    private AlgorithmParameterSpec getAlgorithmParameterSpec(
+                                      AlgorithmParameters params)
+            throws InvalidParameterSpecException {
+        if (params == null) {
+            return null;
+        }
+
+        String alg = params.getAlgorithm().toUpperCase(Locale.ENGLISH);
+
+        if (alg.equalsIgnoreCase("RC2")) {
+            return params.getParameterSpec(RC2ParameterSpec.class);
+        }
+
+        if (alg.equalsIgnoreCase("RC5")) {
+            return params.getParameterSpec(RC5ParameterSpec.class);
+        }
+
+        if (alg.startsWith("PBE")) {
+            return params.getParameterSpec(PBEParameterSpec.class);
+        }
+
+        if (alg.startsWith("DES")) {
+            return params.getParameterSpec(IvParameterSpec.class);
+        }
+        return null;
+    }
+
+    // Used by getMaxAllowedKeyLength and getMaxAllowedParameterSpec
+    // always returns CryptoAllPermission. Old stuff from bad old days.
+    private static CryptoPermission getConfiguredPermission(
+            String transformation) throws NullPointerException,
+            NoSuchAlgorithmException {
+        if (transformation == null) throw new NullPointerException();
+	// Called to make sure it is a valid transformation.
+        tokenizeTransformation(transformation);
+        return CryptoAllPermission.INSTANCE;
+    }
+
+    /**
+     * Returns the maximum key length for the specified transformation
+     * according to the installed JCE jurisdiction policy files. If
+     * JCE unlimited strength jurisdiction policy files are installed,
+     * Integer.MAX_VALUE will be returned.
+     * For more information on default key size in JCE jurisdiction
+     * policy files, please see Appendix E in the
+     * <a href=
+     *   "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppE">
+     * Java Cryptography Architecture Reference Guide</a>.
+     *
+     * @param transformation the cipher transformation.
+     * @return the maximum key length in bits or Integer.MAX_VALUE.
+     * @exception NullPointerException if <code>transformation</code> is null.
+     * @exception NoSuchAlgorithmException if <code>transformation</code>
+     * is not a valid transformation, i.e. in the form of "algorithm" or
+     * "algorithm/mode/padding".
+     * @since 1.5
+     */
+    public static final int getMaxAllowedKeyLength(String transformation)
+            throws NoSuchAlgorithmException {
+        CryptoPermission cp = getConfiguredPermission(transformation);
+        return cp.getMaxKeySize();
+    }
+
+    /**
+     * Returns an AlgorithmParameterSpec object which contains
+     * the maximum cipher parameter value according to the
+     * jurisdiction policy file. If JCE unlimited strength jurisdiction
+     * policy files are installed or there is no maximum limit on the
+     * parameters for the specified transformation in the policy file,
+     * null will be returned.
+     *
+     * @param transformation the cipher transformation.
+     * @return an AlgorithmParameterSpec which holds the maximum
+     * value or null.
+     * @exception NullPointerException if <code>transformation</code>
+     * is null.
+     * @exception NoSuchAlgorithmException if <code>transformation</code>
+     * is not a valid transformation, i.e. in the form of "algorithm" or
+     * "algorithm/mode/padding".
+     * @since 1.5
+     */
+    public static final AlgorithmParameterSpec getMaxAllowedParameterSpec(
+            String transformation) throws NoSuchAlgorithmException {
+        CryptoPermission cp = getConfiguredPermission(transformation);
+        return cp.getAlgorithmParameterSpec();
+    }
+}

Added: openjdk-crypto/trunk/src/main/java/javax/crypto/CipherInputStream.java
===================================================================
--- openjdk-crypto/trunk/src/main/java/javax/crypto/CipherInputStream.java	                        (rev 0)
+++ openjdk-crypto/trunk/src/main/java/javax/crypto/CipherInputStream.java	2010-03-13 04:23:29 UTC (rev 25)
@@ -0,0 +1,322 @@
+/*
+ * Copyright 1997-2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.crypto;
+
+import java.io.*;
+
+/**
+ * A CipherInputStream is composed of an InputStream and a Cipher so
+ * that read() methods return data that are read in from the
+ * underlying InputStream but have been additionally processed by the
+ * Cipher.  The Cipher must be fully initialized before being used by
+ * a CipherInputStream.
+ *
+ * <p> For example, if the Cipher is initialized for decryption, the
+ * CipherInputStream will attempt to read in data and decrypt them,
+ * before returning the decrypted data.
+ *
+ * <p> This class adheres strictly to the semantics, especially the
+ * failure semantics, of its ancestor classes
+ * java.io.FilterInputStream and java.io.InputStream.  This class has
+ * exactly those methods specified in its ancestor classes, and
+ * overrides them all.  Moreover, this class catches all exceptions
+ * that are not thrown by its ancestor classes.  In particular, the
+ * <code>skip</code> method skips, and the <code>available</code>
+ * method counts only data that have been processed by the encapsulated Cipher.
+ *
+ * <p> It is crucial for a programmer using this class not to use
+ * methods that are not defined or overriden in this class (such as a
+ * new method or constructor that is later added to one of the super
+ * classes), because the design and implementation of those methods
+ * are unlikely to have considered security impact with regard to
+ * CipherInputStream.
+ *
+ * @author  Li Gong
+ * @see     java.io.InputStream
+ * @see     java.io.FilterInputStream
+ * @see     javax.crypto.Cipher
+ * @see     javax.crypto.CipherOutputStream
+ *
+ * @since 1.4
+ */
+
+public class CipherInputStream extends FilterInputStream {
+
+    // the cipher engine to use to process stream data
+    private Cipher cipher;
+
+    // the underlying input stream
+    private InputStream input;
+
+    /* the buffer holding data that have been read in from the
+       underlying stream, but have not been processed by the cipher
+       engine. the size 512 bytes is somewhat randomly chosen */
+    private byte[] ibuffer = new byte[512];
+
+    // having reached the end of the underlying input stream
+    private boolean done = false;
+
+    /* the buffer holding data that have been processed by the cipher
+       engine, but have not been read out */
+    private byte[] obuffer;
+    // the offset pointing to the next "new" byte
+    private int ostart = 0;
+    // the offset pointing to the last "new" byte
+    private int ofinish = 0;
+
+    /**
+     * private convenience function.
+     *
+     * Entry condition: ostart = ofinish
+     *
+     * Exit condition: ostart <= ofinish
+     *
+     * return (ofinish-ostart) (we have this many bytes for you)
+     * return 0 (no data now, but could have more later)
+     * return -1 (absolutely no more data)
+     */
+    private int getMoreData() throws IOException {
+        if (done) return -1;
+        int readin = input.read(ibuffer);
+        if (readin == -1) {
+            done = true;
+            try {
+                obuffer = cipher.doFinal();
+            }
+            catch (IllegalBlockSizeException e) {obuffer = null;}
+            catch (BadPaddingException e) {obuffer = null;}
+            if (obuffer == null)
+                return -1;
+            else {
+                ostart = 0;
+                ofinish = obuffer.length;
+                return ofinish;
+            }
+        }
+        try {
+            obuffer = cipher.update(ibuffer, 0, readin);
+        } catch (IllegalStateException e) {obuffer = null;};
+        ostart = 0;
+        if (obuffer == null)
+            ofinish = 0;
+        else ofinish = obuffer.length;
+        return ofinish;
+    }
+
+    /**
+     * Constructs a CipherInputStream from an InputStream and a
+     * Cipher.
+     * <br>Note: if the specified input stream or cipher is
+     * null, a NullPointerException may be thrown later when
+     * they are used.
+     * @param is the to-be-processed input stream
+     * @param c an initialized Cipher object
+     */
+    public CipherInputStream(InputStream is, Cipher c) {
+        super(is);
+        input = is;
+        cipher = c;
+    }
+
+    /**
+     * Constructs a CipherInputStream from an InputStream without
+     * specifying a Cipher. This has the effect of constructing a
+     * CipherInputStream using a NullCipher.
+     * <br>Note: if the specified input stream is null, a
+     * NullPointerException may be thrown later when it is used.
+     * @param is the to-be-processed input stream
+     */
+    protected CipherInputStream(InputStream is) {
+        super(is);
+        input = is;
+        cipher = new NullCipher();
+    }
+
+    /**
+     * Reads the next byte of data from this input stream. The value
+     * byte is returned as an <code>int</code> in the range
+     * <code>0</code> to <code>255</code>. If no byte is available
+     * because the end of the stream has been reached, the value
+     * <code>-1</code> is returned. This method blocks until input data
+     * is available, the end of the stream is detected, or an exception
+     * is thrown.
+     * <p>
+     *
+     * @return  the next byte of data, or <code>-1</code> if the end of the
+     *          stream is reached.
+     * @exception  IOException  if an I/O error occurs.
+     * @since JCE1.2
+     */
+    public int read() throws IOException {
+        if (ostart >= ofinish) {
+            // we loop for new data as the spec says we are blocking
+            int i = 0;
+            while (i == 0) i = getMoreData();
+            if (i == -1) return -1;
+        }
+        return ((int) obuffer[ostart++] & 0xff);
+    };
+
+    /**
+     * Reads up to <code>b.length</code> bytes of data from this input
+     * stream into an array of bytes.
+     * <p>
+     * The <code>read</code> method of <code>InputStream</code> calls
+     * the <code>read</code> method of three arguments with the arguments
+     * <code>b</code>, <code>0</code>, and <code>b.length</code>.
+     *
+     * @param      b   the buffer into which the data is read.
+     * @return     the total number of bytes read into the buffer, or
+     *             <code>-1</code> is there is no more data because the end of
+     *             the stream has been reached.
+     * @exception  IOException  if an I/O error occurs.
+     * @see        java.io.InputStream#read(byte[], int, int)
+     * @since      JCE1.2
+     */
+    public int read(byte b[]) throws IOException {
+        return read(b, 0, b.length);
+    }
+
+    /**
+     * Reads up to <code>len</code> bytes of data from this input stream
+     * into an array of bytes. This method blocks until some input is
+     * available. If the first argument is <code>null,</code> up to
+     * <code>len</code> bytes are read and discarded.
+     *
+     * @param      b     the buffer into which the data is read.
+     * @param      off   the start offset in the destination array
+     *                   <code>buf</code>
+     * @param      len   the maximum number of bytes read.
+     * @return     the total number of bytes read into the buffer, or
+     *             <code>-1</code> if there is no more data because the end of
+     *             the stream has been reached.
+     * @exception  IOException  if an I/O error occurs.
+     * @see        java.io.InputStream#read()
+     * @since      JCE1.2
+     */
+    public int read(byte b[], int off, int len) throws IOException {
+        if (ostart >= ofinish) {
+            // we loop for new data as the spec says we are blocking
+            int i = 0;
+            while (i == 0) i = getMoreData();
+            if (i == -1) return -1;
+        }
+        if (len <= 0) {
+            return 0;
+        }
+        int available = ofinish - ostart;
+        if (len < available) available = len;
+        if (b != null) {
+            System.arraycopy(obuffer, ostart, b, off, available);
+        }
+        ostart = ostart + available;
+        return available;
+    }
+
+    /**
+     * Skips <code>n</code> bytes of input from the bytes that can be read
+     * from this input stream without blocking.
+     *
+     * <p>Fewer bytes than requested might be skipped.
+     * The actual number of bytes skipped is equal to <code>n</code> or
+     * the result of a call to
+     * {@link #available() <code>available</code>},
+     * whichever is smaller.
+     * If <code>n</code> is less than zero, no bytes are skipped.
+     *
+     * <p>The actual number of bytes skipped is returned.
+     *
+     * @param      n the number of bytes to be skipped.
+     * @return     the actual number of bytes skipped.
+     * @exception  IOException  if an I/O error occurs.
+     * @since JCE1.2
+     */
+    public long skip(long n) throws IOException {
+        int available = ofinish - ostart;
+        if (n > available) {
+            n = available;
+        }
+        if (n < 0) {
+            return 0;
+        }
+        ostart += n;
+        return n;
+    }
+
+    /**
+     * Returns the number of bytes that can be read from this input
+     * stream without blocking. The <code>available</code> method of
+     * <code>InputStream</code> returns <code>0</code>. This method
+     * <B>should</B> be overridden by subclasses.
+     *
+     * @return     the number of bytes that can be read from this input stream
+     *             without blocking.
+     * @exception  IOException  if an I/O error occurs.
+     * @since      JCE1.2
+     */
+    public int available() throws IOException {
+        return (ofinish - ostart);
+    }
+
+    /**
+     * Closes this input stream and releases any system resources
+     * associated with the stream.
+     * <p>
+     * The <code>close</code> method of <code>CipherInputStream</code>
+     * calls the <code>close</code> method of its underlying input
+     * stream.
+     *
+     * @exception  IOException  if an I/O error occurs.
+     * @since JCE1.2
+     */
+    public void close() throws IOException {
+        input.close();
+        try {
+            // throw away the unprocessed data
+            cipher.doFinal();
+        }
+        catch (BadPaddingException ex) {
+        }
+        catch (IllegalBlockSizeException ex) {
+        }
+        ostart = 0;
+        ofinish = 0;
+    }
+
+    /**
+     * Tests if this input stream supports the <code>mark</code>
+     * and <code>reset</code> methods, which it does not.
+     *
+     * @return  <code>false</code>, since this class does not support the
+     *          <code>mark</code> and <code>reset</code> methods.
+     * @see     java.io.InputStream#mark(int)
+     * @see     java.io.InputStream#reset()
+     * @since   JCE1.2
+     */
+    public boolean markSupported() {
+        return false;
+    }
+}

Added: openjdk-crypto/trunk/src/main/java/javax/crypto/CipherOutputStream.java
===================================================================
--- openjdk-crypto/trunk/src/main/java/javax/crypto/CipherOutputStream.java	                        (rev 0)
+++ openjdk-crypto/trunk/src/main/java/javax/crypto/CipherOutputStream.java	2010-03-13 04:23:29 UTC (rev 25)
@@ -0,0 +1,213 @@
+/*
+ * Copyright 1997-2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.crypto;
+
+import java.io.*;
+
+/**
+ * A CipherOutputStream is composed of an OutputStream and a Cipher so
+ * that write() methods first process the data before writing them out
+ * to the underlying OutputStream.  The cipher must be fully
+ * initialized before being used by a CipherOutputStream.
+ *
+ * <p> For example, if the cipher is initialized for encryption, the
+ * CipherOutputStream will attempt to encrypt data before writing out the
+ * encrypted data.
+ *
+ * <p> This class adheres strictly to the semantics, especially the
+ * failure semantics, of its ancestor classes
+ * java.io.OutputStream and java.io.FilterOutputStream.  This class
+ * has exactly those methods specified in its ancestor classes, and
+ * overrides them all.  Moreover, this class catches all exceptions
+ * that are not thrown by its ancestor classes.
+ *
+ * <p> It is crucial for a programmer using this class not to use
+ * methods that are not defined or overriden in this class (such as a
+ * new method or constructor that is later added to one of the super
+ * classes), because the design and implementation of those methods
+ * are unlikely to have considered security impact with regard to
+ * CipherOutputStream.
+ *
+ * @author  Li Gong
+ * @see     java.io.OutputStream
+ * @see     java.io.FilterOutputStream
+ * @see     javax.crypto.Cipher
+ * @see     javax.crypto.CipherInputStream
+ *
+ * @since 1.4
+ */
+
+public class CipherOutputStream extends FilterOutputStream {
+
+    // the cipher engine to use to process stream data
+    private Cipher cipher;
+
+    // the underlying output stream
+    private OutputStream output;
+
+    /* the buffer holding one byte of incoming data */
+    private byte[] ibuffer = new byte[1];
+
+    // the buffer holding data ready to be written out
+    private byte[] obuffer;
+
+    /**
+     *
+     * Constructs a CipherOutputStream from an OutputStream and a
+     * Cipher.
+     * <br>Note: if the specified output stream or cipher is
+     * null, a NullPointerException may be thrown later when
+     * they are used.
+     *
+     * @param os  the OutputStream object
+     * @param c   an initialized Cipher object
+     */
+    public CipherOutputStream(OutputStream os, Cipher c) {
+        super(os);
+        output = os;
+        cipher = c;
+    };
+
+    /**
+     * Constructs a CipherOutputStream from an OutputStream without
+     * specifying a Cipher. This has the effect of constructing a
+     * CipherOutputStream using a NullCipher.
+     * <br>Note: if the specified output stream is null, a
+     * NullPointerException may be thrown later when it is used.
+     *
+     * @param os  the OutputStream object
+     */
+    protected CipherOutputStream(OutputStream os) {
+        super(os);
+        output = os;
+        cipher = new NullCipher();
+    }
+
+    /**
+     * Writes the specified byte to this output stream.
+     *
+     * @param      b   the <code>byte</code>.
+     * @exception  IOException  if an I/O error occurs.
+     * @since      JCE1.2
+     */
+    public void write(int b) throws IOException {
+        ibuffer[0] = (byte) b;
+        obuffer = cipher.update(ibuffer, 0, 1);
+        if (obuffer != null) {
+            output.write(obuffer);
+            obuffer = null;
+        }
+    };
+
+    /**
+     * Writes <code>b.length</code> bytes from the specified byte array
+     * to this output stream.
+     * <p>
+     * The <code>write</code> method of
+     * <code>CipherOutputStream</code> calls the <code>write</code>
+     * method of three arguments with the three arguments
+     * <code>b</code>, <code>0</code>, and <code>b.length</code>.
+     *
+     * @param      b   the data.
+     * @exception  NullPointerException if <code>b</code> is null.
+     * @exception  IOException  if an I/O error occurs.
+     * @see        javax.crypto.CipherOutputStream#write(byte[], int, int)
+     * @since JCE1.2
+     */
+    public void write(byte b[]) throws IOException {
+        write(b, 0, b.length);
+    }
+
+    /**
+     * Writes <code>len</code> bytes from the specified byte array
+     * starting at offset <code>off</code> to this output stream.
+     *
+     * @param      b     the data.
+     * @param      off   the start offset in the data.
+     * @param      len   the number of bytes to write.
+     * @exception  IOException  if an I/O error occurs.
+     * @since      JCE1.2
+     */
+    public void write(byte b[], int off, int len) throws IOException {
+        obuffer = cipher.update(b, off, len);
+        if (obuffer != null) {
+            output.write(obuffer);
+            obuffer = null;
+        }
+    }
+
+    /**
+     * Flushes this output stream by forcing any buffered output bytes
+     * that have already been processed by the encapsulated cipher object
+     * to be written out.
+     *
+     * <p>Any bytes buffered by the encapsulated cipher
+     * and waiting to be processed by it will not be written out. For example,
+     * if the encapsulated cipher is a block cipher, and the total number of
+     * bytes written using one of the <code>write</code> methods is less than
+     * the cipher's block size, no bytes will be written out.
+     *
+     * @exception  IOException  if an I/O error occurs.
+     * @since      JCE1.2
+     */
+    public void flush() throws IOException {
+        if (obuffer != null) {
+            output.write(obuffer);
+            obuffer = null;
+        }
+        output.flush();
+    }
+
+    /**
+     * Closes this output stream and releases any system resources
+     * associated with this stream.
+     * <p>
+     * This method invokes the <code>doFinal</code> method of the encapsulated
+     * cipher object, which causes any bytes buffered by the encapsulated
+     * cipher to be processed. The result is written out by calling the
+     * <code>flush</code> method of this output stream.
+     * <p>
+     * This method resets the encapsulated cipher object to its initial state
+     * and calls the <code>close</code> method of the underlying output
+     * stream.
+     *
+     * @exception  IOException  if an I/O error occurs.
+     * @since      JCE1.2
+     */
+    public void close() throws IOException {
+        try {
+            obuffer = cipher.doFinal();
+        } catch (IllegalBlockSizeException e) {
+            obuffer = null;
+        } catch (BadPaddingException e) {
+            obuffer = null;
+        }
+        try {
+            flush();
+        } catch (IOException ignored) {}
+        out.close();
+    }
+}

Added: openjdk-crypto/trunk/src/main/java/javax/crypto/CipherSpi.java
===================================================================
--- openjdk-crypto/trunk/src/main/java/javax/crypto/CipherSpi.java	                        (rev 0)
+++ openjdk-crypto/trunk/src/main/java/javax/crypto/CipherSpi.java	2010-03-13 04:23:29 UTC (rev 25)
@@ -0,0 +1,895 @@
+/*
+ * Copyright 1997-2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.crypto;
+
+import java.util.StringTokenizer;
+import java.util.NoSuchElementException;
+import java.security.AlgorithmParameters;
+import java.security.Provider;
+import java.security.Key;
+import java.security.SecureRandom;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.InvalidKeyException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.ProviderException;
+import java.security.spec.AlgorithmParameterSpec;
+
+import java.nio.ByteBuffer;
+
+/**
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
+ * for the <code>Cipher</code> class.
+ * All the abstract methods in this class must be implemented by each
+ * cryptographic service provider who wishes to supply the implementation
+ * of a particular cipher algorithm.
+ *
+ * <p>In order to create an instance of <code>Cipher</code>, which
+ * encapsulates an instance of this <code>CipherSpi</code> class, an
+ * application calls one of the
+ * {@link Cipher#getInstance(java.lang.String) getInstance}
+ * factory methods of the
+ * {@link Cipher Cipher} engine class and specifies the requested
+ * <i>transformation</i>.
+ * Optionally, the application may also specify the name of a provider.
+ *
+ * <p>A <i>transformation</i> is a string that describes the operation (or
+ * set of operations) to be performed on the given input, to produce some
+ * output. A transformation always includes the name of a cryptographic
+ * algorithm (e.g., <i>DES</i>), and may be followed by a feedback mode and
+ * padding scheme.
+ *
+ * <p> A transformation is of the form:<p>
+ *
+ * <ul>
+ * <li>"<i>algorithm/mode/padding</i>" or
+ * <p>
+ * <li>"<i>algorithm</i>"
+ * </ul>
+ *
+ * <P> (in the latter case,
+ * provider-specific default values for the mode and padding scheme are used).
+ * For example, the following is a valid transformation:<p>
+ *
+ * <pre>
+ *     Cipher c = Cipher.getInstance("<i>DES/CBC/PKCS5Padding</i>");
+ * </pre>
+ *
+ * <p>A provider may supply a separate class for each combination
+ * of <i>algorithm/mode/padding</i>, or may decide to provide more generic
+ * classes representing sub-transformations corresponding to
+ * <i>algorithm</i> or <i>algorithm/mode</i> or <i>algorithm//padding</i>
+ * (note the double slashes),
+ * in which case the requested mode and/or padding are set automatically by
+ * the <code>getInstance</code> methods of <code>Cipher</code>, which invoke
+ * the {@link #engineSetMode(java.lang.String) engineSetMode} and
+ * {@link #engineSetPadding(java.lang.String) engineSetPadding}
+ * methods of the provider's subclass of <code>CipherSpi</code>.
+ *
+ * <p>A <code>Cipher</code> property in a provider master class may have one of
+ * the following formats:
+ *
+ * <ul>
+ *
+ * <li>
+ * <pre>
+ *     // provider's subclass of "CipherSpi" implements "algName" with
+ *     // pluggable mode and padding
+ *     <code>Cipher.</code><i>algName</i>
+ * </pre>
+ *
+ * <li>
+ * <pre>
+ *     // provider's subclass of "CipherSpi" implements "algName" in the
+ *     // specified "mode", with pluggable padding
+ *     <code>Cipher.</code><i>algName/mode</i>
+ * </pre>
+ *
+ * <li>
+ * <pre>
+ *     // provider's subclass of "CipherSpi" implements "algName" with the
+ *     // specified "padding", with pluggable mode
+ *     <code>Cipher.</code><i>algName//padding</i>
+ * </pre>
+ *
+ * <li>
+ * <pre>
+ *     // provider's subclass of "CipherSpi" implements "algName" with the
+ *     // specified "mode" and "padding"
+ *     <code>Cipher.</code><i>algName/mode/padding</i>
+ * </pre>
+ *
+ * </ul>
+ *
+ * <p>For example, a provider may supply a subclass of <code>CipherSpi</code>
+ * that implements <i>DES/ECB/PKCS5Padding</i>, one that implements
+ * <i>DES/CBC/PKCS5Padding</i>, one that implements
+ * <i>DES/CFB/PKCS5Padding</i>, and yet another one that implements
+ * <i>DES/OFB/PKCS5Padding</i>. That provider would have the following
+ * <code>Cipher</code> properties in its master class:<p>
+ *
+ * <ul>
+ *
+ * <li>
+ * <pre>
+ *     <code>Cipher.</code><i>DES/ECB/PKCS5Padding</i>
+ * </pre>
+ *
+ * <li>
+ * <pre>
+ *     <code>Cipher.</code><i>DES/CBC/PKCS5Padding</i>
+ * </pre>
+ *
+ * <li>
+ * <pre>
+ *     <code>Cipher.</code><i>DES/CFB/PKCS5Padding</i>
+ * </pre>
+ *
+ * <li>
+ * <pre>
+ *     <code>Cipher.</code><i>DES/OFB/PKCS5Padding</i>
+ * </pre>
+ *
+ * </ul>
+ *
+ * <p>Another provider may implement a class for each of the above modes
+ * (i.e., one class for <i>ECB</i>, one for <i>CBC</i>, one for <i>CFB</i>,
+ * and one for <i>OFB</i>), one class for <i>PKCS5Padding</i>,
+ * and a generic <i>DES</i> class that subclasses from <code>CipherSpi</code>.
+ * That provider would have the following
+ * <code>Cipher</code> properties in its master class:<p>
+ *
+ * <ul>
+ *
+ * <li>
+ * <pre>
+ *     <code>Cipher.</code><i>DES</i>
+ * </pre>
+ *
+ * </ul>
+ *
+ * <p>The <code>getInstance</code> factory method of the <code>Cipher</code>
+ * engine class follows these rules in order to instantiate a provider's
+ * implementation of <code>CipherSpi</code> for a
+ * transformation of the form "<i>algorithm</i>":
+ *
+ * <ol>
+ * <li>
+ * Check if the provider has registered a subclass of <code>CipherSpi</code>
+ * for the specified "<i>algorithm</i>".
+ * <p>If the answer is YES, instantiate this
+ * class, for whose mode and padding scheme default values (as supplied by
+ * the provider) are used.
+ * <p>If the answer is NO, throw a <code>NoSuchAlgorithmException</code>
+ * exception.
+ * </ol>
+ *
+ * <p>The <code>getInstance</code> factory method of the <code>Cipher</code>
+ * engine class follows these rules in order to instantiate a provider's
+ * implementation of <code>CipherSpi</code> for a
+ * transformation of the form "<i>algorithm/mode/padding</i>":
+ *
+ * <ol>
+ * <li>
+ * Check if the provider has registered a subclass of <code>CipherSpi</code>
+ * for the specified "<i>algorithm/mode/padding</i>" transformation.
+ * <p>If the answer is YES, instantiate it.
+ * <p>If the answer is NO, go to the next step.<p>
+ * <li>
+ * Check if the provider has registered a subclass of <code>CipherSpi</code>
+ * for the sub-transformation "<i>algorithm/mode</i>".
+ * <p>If the answer is YES, instantiate it, and call
+ * <code>engineSetPadding(<i>padding</i>)</code> on the new instance.
+ * <p>If the answer is NO, go to the next step.<p>
+ * <li>
+ * Check if the provider has registered a subclass of <code>CipherSpi</code>
+ * for the sub-transformation "<i>algorithm//padding</i>" (note the double
+ * slashes).
+ * <p>If the answer is YES, instantiate it, and call
+ * <code>engineSetMode(<i>mode</i>)</code> on the new instance.
+ * <p>If the answer is NO, go to the next step.<p>
+ * <li>
+ * Check if the provider has registered a subclass of <code>CipherSpi</code>
+ * for the sub-transformation "<i>algorithm</i>".
+ * <p>If the answer is YES, instantiate it, and call
+ * <code>engineSetMode(<i>mode</i>)</code> and
+ * <code>engineSetPadding(<i>padding</i>)</code> on the new instance.
+ * <p>If the answer is NO, throw a <code>NoSuchAlgorithmException</code>
+ * exception.
+ * </ol>
+ *
+ * @author Jan Luehe
+ * @see KeyGenerator
+ * @see SecretKey
+ * @since 1.4
+ */
+
+public abstract class CipherSpi {
+
+    /**
+     * Sets the mode of this cipher.
+     *
+     * @param mode the cipher mode
+     *
+     * @exception NoSuchAlgorithmException if the requested cipher mode does
+     * not exist
+     */
+    protected abstract void engineSetMode(String mode)
+        throws NoSuchAlgorithmException;
+
+    /**
+     * Sets the padding mechanism of this cipher.
+     *
+     * @param padding the padding mechanism
+     *
+     * @exception NoSuchPaddingException if the requested padding mechanism
+     * does not exist
+     */
+    protected abstract void engineSetPadding(String padding)
+        throws NoSuchPaddingException;
+
+    /**
+     * Returns the block size (in bytes).
+     *
+     * @return the block size (in bytes), or 0 if the underlying algorithm is
+     * not a block cipher
+     */
+    protected abstract int engineGetBlockSize();
+
+    /**
+     * Returns the length in bytes that an output buffer would
+     * need to be in order to hold the result of the next <code>update</code>
+     * or <code>doFinal</code> operation, given the input length
+     * <code>inputLen</code> (in bytes).
+     *
+     * <p>This call takes into account any unprocessed (buffered) data from a
+     * previous <code>update</code> call, and padding.
+     *
+     * <p>The actual output length of the next <code>update</code> or
+     * <code>doFinal</code> call may be smaller than the length returned by
+     * this method.
+     *
+     * @param inputLen the input length (in bytes)
+     *
+     * @return the required output buffer size (in bytes)
+     */
+    protected abstract int engineGetOutputSize(int inputLen);
+
+    /**
+     * Returns the initialization vector (IV) in a new buffer.
+     *
+     * <p> This is useful in the context of password-based encryption or
+     * decryption, where the IV is derived from a user-provided passphrase.
+     *
+     * @return the initialization vector in a new buffer, or null if the
+     * underlying algorithm does not use an IV, or if the IV has not yet
+     * been set.
+     */
+    protected abstract byte[] engineGetIV();
+
+    /**
+     * Returns the parameters used with this cipher.
+     *
+     * <p>The returned parameters may be the same that were used to initialize
+     * this cipher, or may contain a combination of default and random
+     * parameter values used by the underlying cipher implementation if this
+     * cipher requires algorithm parameters but was not initialized with any.
+     *
+     * @return the parameters used with this cipher, or null if this cipher
+     * does not use any parameters.
+     */
+    protected abstract AlgorithmParameters engineGetParameters();
+
+    /**
+     * Initializes this cipher with a key and a source
+     * of randomness.
+     *
+     * <p>The cipher is initialized for one of the following four operations:
+     * encryption, decryption, key wrapping or key unwrapping, depending on
+     * the value of <code>opmode</code>.
+     *
+     * <p>If this cipher requires any algorithm parameters that cannot be
+     * derived from the given <code>key</code>, the underlying cipher
+     * implementation is supposed to generate the required parameters itself
+     * (using provider-specific default or random values) if it is being
+     * initialized for encryption or key wrapping, and raise an
+     * <code>InvalidKeyException</code> if it is being
+     * initialized for decryption or key unwrapping.
+     * The generated parameters can be retrieved using
+     * {@link #engineGetParameters() engineGetParameters} or
+     * {@link #engineGetIV() engineGetIV} (if the parameter is an IV).
+     *
+     * <p>If this cipher (including its underlying feedback or padding scheme)
+     * requires any random bytes (e.g., for parameter generation), it will get
+     * them from <code>random</code>.
+     *
+     * <p>Note that when a Cipher object is initialized, it loses all
+     * previously-acquired state. In other words, initializing a Cipher is
+     * equivalent to creating a new instance of that Cipher and initializing
+     * it.
+     *
+     * @param opmode the operation mode of this cipher (this is one of
+     * the following:
+     * <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,
+     * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)
+     * @param key the encryption key
+     * @param random the source of randomness
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * initializing this cipher, or if this cipher is being initialized for
+     * decryption and requires algorithm parameters that cannot be
+     * determined from the given key.
+     */
+    protected abstract void engineInit(int opmode, Key key,
+                                       SecureRandom random)
+        throws InvalidKeyException;
+
+    /**
+     * Initializes this cipher with a key, a set of
+     * algorithm parameters, and a source of randomness.
+     *
+     * <p>The cipher is initialized for one of the following four operations:
+     * encryption, decryption, key wrapping or key unwrapping, depending on
+     * the value of <code>opmode</code>.
+     *
+     * <p>If this cipher requires any algorithm parameters and
+     * <code>params</code> is null, the underlying cipher implementation is
+     * supposed to generate the required parameters itself (using
+     * provider-specific default or random values) if it is being
+     * initialized for encryption or key wrapping, and raise an
+     * <code>InvalidAlgorithmParameterException</code> if it is being
+     * initialized for decryption or key unwrapping.
+     * The generated parameters can be retrieved using
+     * {@link #engineGetParameters() engineGetParameters} or
+     * {@link #engineGetIV() engineGetIV} (if the parameter is an IV).
+     *
+     * <p>If this cipher (including its underlying feedback or padding scheme)
+     * requires any random bytes (e.g., for parameter generation), it will get
+     * them from <code>random</code>.
+     *
+     * <p>Note that when a Cipher object is initialized, it loses all
+     * previously-acquired state. In other words, initializing a Cipher is
+     * equivalent to creating a new instance of that Cipher and initializing
+     * it.
+     *
+     * @param opmode the operation mode of this cipher (this is one of
+     * the following:
+     * <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,
+     * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)
+     * @param key the encryption key
+     * @param params the algorithm parameters
+     * @param random the source of randomness
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * initializing this cipher
+     * @exception InvalidAlgorithmParameterException if the given algorithm
+     * parameters are inappropriate for this cipher,
+     * or if this cipher is being initialized for decryption and requires
+     * algorithm parameters and <code>params</code> is null.
+     */
+    protected abstract void engineInit(int opmode, Key key,
+                                       AlgorithmParameterSpec params,
+                                       SecureRandom random)
+        throws InvalidKeyException, InvalidAlgorithmParameterException;
+
+    /**
+     * Initializes this cipher with a key, a set of
+     * algorithm parameters, and a source of randomness.
+     *
+     * <p>The cipher is initialized for one of the following four operations:
+     * encryption, decryption, key wrapping or key unwrapping, depending on
+     * the value of <code>opmode</code>.
+     *
+     * <p>If this cipher requires any algorithm parameters and
+     * <code>params</code> is null, the underlying cipher implementation is
+     * supposed to generate the required parameters itself (using
+     * provider-specific default or random values) if it is being
+     * initialized for encryption or key wrapping, and raise an
+     * <code>InvalidAlgorithmParameterException</code> if it is being
+     * initialized for decryption or key unwrapping.
+     * The generated parameters can be retrieved using
+     * {@link #engineGetParameters() engineGetParameters} or
+     * {@link #engineGetIV() engineGetIV} (if the parameter is an IV).
+     *
+     * <p>If this cipher (including its underlying feedback or padding scheme)
+     * requires any random bytes (e.g., for parameter generation), it will get
+     * them from <code>random</code>.
+     *
+     * <p>Note that when a Cipher object is initialized, it loses all
+     * previously-acquired state. In other words, initializing a Cipher is
+     * equivalent to creating a new instance of that Cipher and initializing
+     * it.
+     *
+     * @param opmode the operation mode of this cipher (this is one of
+     * the following:
+     * <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,
+     * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)
+     * @param key the encryption key
+     * @param params the algorithm parameters
+     * @param random the source of randomness
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * initializing this cipher
+     * @exception InvalidAlgorithmParameterException if the given algorithm
+     * parameters are inappropriate for this cipher,
+     * or if this cipher is being initialized for decryption and requires
+     * algorithm parameters and <code>params</code> is null.
+     */
+    protected abstract void engineInit(int opmode, Key key,
+                                       AlgorithmParameters params,
+                                       SecureRandom random)
+        throws InvalidKeyException, InvalidAlgorithmParameterException;
+
+    /**
+     * Continues a multiple-part encryption or decryption operation
+     * (depending on how this cipher was initialized), processing another data
+     * part.
+     *
+     * <p>The first <code>inputLen</code> bytes in the <code>input</code>
+     * buffer, starting at <code>inputOffset</code> inclusive, are processed,
+     * and the result is stored in a new buffer.
+     *
+     * @param input the input buffer
+     * @param inputOffset the offset in <code>input</code> where the input
+     * starts
+     * @param inputLen the input length
+     *
+     * @return the new buffer with the result, or null if the underlying
+     * cipher is a block cipher and the input data is too short to result in a
+     * new block.
+     */
+    protected abstract byte[] engineUpdate(byte[] input, int inputOffset,
+                                           int inputLen);
+
+    /**
+     * Continues a multiple-part encryption or decryption operation
+     * (depending on how this cipher was initialized), processing another data
+     * part.
+     *
+     * <p>The first <code>inputLen</code> bytes in the <code>input</code>
+     * buffer, starting at <code>inputOffset</code> inclusive, are processed,
+     * and the result is stored in the <code>output</code> buffer, starting at
+     * <code>outputOffset</code> inclusive.
+     *
+     * <p>If the <code>output</code> buffer is too small to hold the result,
+     * a <code>ShortBufferException</code> is thrown.
+     *
+     * @param input the input buffer
+     * @param inputOffset the offset in <code>input</code> where the input
+     * starts
+     * @param inputLen the input length
+     * @param output the buffer for the result
+     * @param outputOffset the offset in <code>output</code> where the result
+     * is stored
+     *
+     * @return the number of bytes stored in <code>output</code>
+     *
+     * @exception ShortBufferException if the given output buffer is too small
+     * to hold the result
+     */
+    protected abstract int engineUpdate(byte[] input, int inputOffset,
+                                        int inputLen, byte[] output,
+                                        int outputOffset)
+        throws ShortBufferException;
+
+    /**
+     * Continues a multiple-part encryption or decryption operation
+     * (depending on how this cipher was initialized), processing another data
+     * part.
+     *
+     * <p>All <code>input.remaining()</code> bytes starting at
+     * <code>input.position()</code> are processed. The result is stored
+     * in the output buffer.
+     * Upon return, the input buffer's position will be equal
+     * to its limit; its limit will not have changed. The output buffer's
+     * position will have advanced by n, where n is the value returned
+     * by this method; the output buffer's limit will not have changed.
+     *
+     * <p>If <code>output.remaining()</code> bytes are insufficient to
+     * hold the result, a <code>ShortBufferException</code> is thrown.
+     *
+     * <p>Subclasses should consider overriding this method if they can
+     * process ByteBuffers more efficiently than byte arrays.
+     *
+     * @param input the input ByteBuffer
+     * @param output the output ByteByffer
+     *
+     * @return the number of bytes stored in <code>output</code>
+     *
+     * @exception ShortBufferException if there is insufficient space in the
+     * output buffer
+     *
+     * @throws NullPointerException if either parameter is <CODE>null</CODE>
+     * @since 1.5
+     */
+    protected int engineUpdate(ByteBuffer input, ByteBuffer output)
+            throws ShortBufferException {
+        try {
+            return bufferCrypt(input, output, true);
+        } catch (IllegalBlockSizeException e) {
+            // never thrown for engineUpdate()
+            throw new ProviderException("Internal error in update()");
+        } catch (BadPaddingException e) {
+            // never thrown for engineUpdate()
+            throw new ProviderException("Internal error in update()");
+        }
+    }
+
+    /**
+     * Encrypts or decrypts data in a single-part operation,
+     * or finishes a multiple-part operation.
+     * The data is encrypted or decrypted, depending on how this cipher was
+     * initialized.
+     *
+     * <p>The first <code>inputLen</code> bytes in the <code>input</code>
+     * buffer, starting at <code>inputOffset</code> inclusive, and any input
+     * bytes that may have been buffered during a previous <code>update</code>
+     * operation, are processed, with padding (if requested) being applied.
+     * The result is stored in a new buffer.
+     *
+     * <p>Upon finishing, this method resets this cipher object to the state
+     * it was in when previously initialized via a call to
+     * <code>engineInit</code>.
+     * That is, the object is reset and available to encrypt or decrypt
+     * (depending on the operation mode that was specified in the call to
+     * <code>engineInit</code>) more data.
+     *
+     * <p>Note: if any exception is thrown, this cipher object may need to
+     * be reset before it can be used again.
+     *
+     * @param input the input buffer
+     * @param inputOffset the offset in <code>input</code> where the input
+     * starts
+     * @param inputLen the input length
+     *
+     * @return the new buffer with the result
+     *
+     * @exception IllegalBlockSizeException if this cipher is a block cipher,
+     * no padding has been requested (only in encryption mode), and the total
+     * input length of the data processed by this cipher is not a multiple of
+     * block size; or if this encryption algorithm is unable to
+     * process the input data provided.
+     * @exception BadPaddingException if this cipher is in decryption mode,
+     * and (un)padding has been requested, but the decrypted data is not
+     * bounded by the appropriate padding bytes
+     */
+    protected abstract byte[] engineDoFinal(byte[] input, int inputOffset,
+                                            int inputLen)
+        throws IllegalBlockSizeException, BadPaddingException;
+
+    /**
+     * Encrypts or decrypts data in a single-part operation,
+     * or finishes a multiple-part operation.
+     * The data is encrypted or decrypted, depending on how this cipher was
+     * initialized.
+     *
+     * <p>The first <code>inputLen</code> bytes in the <code>input</code>
+     * buffer, starting at <code>inputOffset</code> inclusive, and any input
+     * bytes that may have been buffered during a previous <code>update</code>
+     * operation, are processed, with padding (if requested) being applied.
+     * The result is stored in the <code>output</code> buffer, starting at
+     * <code>outputOffset</code> inclusive.
+     *
+     * <p>If the <code>output</code> buffer is too small to hold the result,
+     * a <code>ShortBufferException</code> is thrown.
+     *
+     * <p>Upon finishing, this method resets this cipher object to the state
+     * it was in when previously initialized via a call to
+     * <code>engineInit</code>.
+     * That is, the object is reset and available to encrypt or decrypt
+     * (depending on the operation mode that was specified in the call to
+     * <code>engineInit</code>) more data.
+     *
+     * <p>Note: if any exception is thrown, this cipher object may need to
+     * be reset before it can be used again.
+     *
+     * @param input the input buffer
+     * @param inputOffset the offset in <code>input</code> where the input
+     * starts
+     * @param inputLen the input length
+     * @param output the buffer for the result
+     * @param outputOffset the offset in <code>output</code> where the result
+     * is stored
+     *
+     * @return the number of bytes stored in <code>output</code>
+     *
+     * @exception IllegalBlockSizeException if this cipher is a block cipher,
+     * no padding has been requested (only in encryption mode), and the total
+     * input length of the data processed by this cipher is not a multiple of
+     * block size; or if this encryption algorithm is unable to
+     * process the input data provided.
+     * @exception ShortBufferException if the given output buffer is too small
+     * to hold the result
+     * @exception BadPaddingException if this cipher is in decryption mode,
+     * and (un)padding has been requested, but the decrypted data is not
+     * bounded by the appropriate padding bytes
+     */
+    protected abstract int engineDoFinal(byte[] input, int inputOffset,
+                                         int inputLen, byte[] output,
+                                         int outputOffset)
+        throws ShortBufferException, IllegalBlockSizeException,
+               BadPaddingException;
+
+    /**
+     * Encrypts or decrypts data in a single-part operation,
+     * or finishes a multiple-part operation.
+     * The data is encrypted or decrypted, depending on how this cipher was
+     * initialized.
+     *
+     * <p>All <code>input.remaining()</code> bytes starting at
+     * <code>input.position()</code> are processed. The result is stored
+     * in the output buffer.
+     * Upon return, the input buffer's position will be equal
+     * to its limit; its limit will not have changed. The output buffer's
+     * position will have advanced by n, where n is the value returned
+     * by this method; the output buffer's limit will not have changed.
+     *
+     * <p>If <code>output.remaining()</code> bytes are insufficient to
+     * hold the result, a <code>ShortBufferException</code> is thrown.
+     *
+     * <p>Upon finishing, this method resets this cipher object to the state
+     * it was in when previously initialized via a call to
+     * <code>engineInit</code>.
+     * That is, the object is reset and available to encrypt or decrypt
+     * (depending on the operation mode that was specified in the call to
+     * <code>engineInit</code>) more data.
+     *
+     * <p>Note: if any exception is thrown, this cipher object may need to
+     * be reset before it can be used again.
+     *
+     * <p>Subclasses should consider overriding this method if they can
+     * process ByteBuffers more efficiently than byte arrays.
+     *
+     * @param input the input ByteBuffer
+     * @param output the output ByteByffer
+     *
+     * @return the number of bytes stored in <code>output</code>
+     *
+     * @exception IllegalBlockSizeException if this cipher is a block cipher,
+     * no padding has been requested (only in encryption mode), and the total
+     * input length of the data processed by this cipher is not a multiple of
+     * block size; or if this encryption algorithm is unable to
+     * process the input data provided.
+     * @exception ShortBufferException if there is insufficient space in the
+     * output buffer
+     * @exception BadPaddingException if this cipher is in decryption mode,
+     * and (un)padding has been requested, but the decrypted data is not
+     * bounded by the appropriate padding bytes
+     *
+     * @throws NullPointerException if either parameter is <CODE>null</CODE>
+     * @since 1.5
+     */
+    protected int engineDoFinal(ByteBuffer input, ByteBuffer output)
+            throws ShortBufferException, IllegalBlockSizeException,
+            BadPaddingException {
+        return bufferCrypt(input, output, false);
+    }
+
+    // copied from sun.security.jca.JCAUtil
+    // will be changed to reference that method once that code has been
+    // integrated and promoted
+    static int getTempArraySize(int totalSize) {
+        return Math.min(4096, totalSize);
+    }
+
+    /**
+     * Implementation for encryption using ByteBuffers. Used for both
+     * engineUpdate() and engineDoFinal().
+     */
+    private int bufferCrypt(ByteBuffer input, ByteBuffer output,
+            boolean isUpdate) throws ShortBufferException,
+            IllegalBlockSizeException, BadPaddingException {
+        if ((input == null) || (output == null)) {
+            throw new NullPointerException
+                ("Input and output buffers must not be null");
+        }
+        int inPos = input.position();
+        int inLimit = input.limit();
+        int inLen = inLimit - inPos;
+        if (isUpdate && (inLen == 0)) {
+            return 0;
+        }
+        int outLenNeeded = engineGetOutputSize(inLen);
+        if (output.remaining() < outLenNeeded) {
+            throw new ShortBufferException("Need at least " + outLenNeeded
+                + " bytes of space in output buffer");
+        }
+
+        boolean a1 = input.hasArray();
+        boolean a2 = output.hasArray();
+
+        if (a1 && a2) {
+            byte[] inArray = input.array();
+            int inOfs = input.arrayOffset() + inPos;
+            byte[] outArray = output.array();
+            int outPos = output.position();
+            int outOfs = output.arrayOffset() + outPos;
+            int n;
+            if (isUpdate) {
+                n = engineUpdate(inArray, inOfs, inLen, outArray, outOfs);
+            } else {
+                n = engineDoFinal(inArray, inOfs, inLen, outArray, outOfs);
+            }
+            input.position(inLimit);
+            output.position(outPos + n);
+            return n;
+        } else if (!a1 && a2) {
+            int outPos = output.position();
+            byte[] outArray = output.array();
+            int outOfs = output.arrayOffset() + outPos;
+            byte[] inArray = new byte[getTempArraySize(inLen)];
+            int total = 0;
+            while (inLen > 0) {
+                int chunk = Math.min(inLen, inArray.length);
+                input.get(inArray, 0, chunk);
+                int n;
+                if (isUpdate || (inLen != chunk)) {
+                    n = engineUpdate(inArray, 0, chunk, outArray, outOfs);
+                } else {
+                    n = engineDoFinal(inArray, 0, chunk, outArray, outOfs);
+                }
+                total += n;
+                outOfs += n;
+                inLen -= chunk;
+            }
+            output.position(outPos + total);
+            return total;
+        } else { // output is not backed by an accessible byte[]
+            byte[] inArray;
+            int inOfs;
+            if (a1) {
+                inArray = input.array();
+                inOfs = input.arrayOffset() + inPos;
+            } else {
+                inArray = new byte[getTempArraySize(inLen)];
+                inOfs = 0;
+            }
+            byte[] outArray = new byte[getTempArraySize(outLenNeeded)];
+            int outSize = outArray.length;
+            int total = 0;
+            boolean resized = false;
+            while (inLen > 0) {
+                int chunk = Math.min(inLen, outSize);
+                if ((a1 == false) && (resized == false)) {
+                    input.get(inArray, 0, chunk);
+                    inOfs = 0;
+                }
+                try {
+                    int n;
+                    if (isUpdate || (inLen != chunk)) {
+                        n = engineUpdate(inArray, inOfs, chunk, outArray, 0);
+                    } else {
+                        n = engineDoFinal(inArray, inOfs, chunk, outArray, 0);
+                    }
+                    resized = false;
+                    inOfs += chunk;
+                    inLen -= chunk;
+                    output.put(outArray, 0, n);
+                    total += n;
+                } catch (ShortBufferException e) {
+                    if (resized) {
+                        // we just resized the output buffer, but it still
+                        // did not work. Bug in the provider, abort
+                        throw (ProviderException)new ProviderException
+                            ("Could not determine buffer size").initCause(e);
+                    }
+                    // output buffer is too small, realloc and try again
+                    resized = true;
+                    int newOut = engineGetOutputSize(chunk);
+                    outArray = new byte[newOut];
+                }
+            }
+            input.position(inLimit);
+            return total;
+        }
+    }
+
+    /**
+     * Wrap a key.
+     *
+     * <p>This concrete method has been added to this previously-defined
+     * abstract class. (For backwards compatibility, it cannot be abstract.)
+     * It may be overridden by a provider to wrap a key.
+     * Such an override is expected to throw an IllegalBlockSizeException or
+     * InvalidKeyException (under the specified circumstances),
+     * if the given key cannot be wrapped.
+     * If this method is not overridden, it always throws an
+     * UnsupportedOperationException.
+     *
+     * @param key the key to be wrapped.
+     *
+     * @return the wrapped key.
+     *
+     * @exception IllegalBlockSizeException if this cipher is a block cipher,
+     * no padding has been requested, and the length of the encoding of the
+     * key to be wrapped is not a multiple of the block size.
+     *
+     * @exception InvalidKeyException if it is impossible or unsafe to
+     * wrap the key with this cipher (e.g., a hardware protected key is
+     * being passed to a software-only cipher).
+     */
+    protected byte[] engineWrap(Key key)
+        throws IllegalBlockSizeException, InvalidKeyException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Unwrap a previously wrapped key.
+     *
+     * <p>This concrete method has been added to this previously-defined
+     * abstract class. (For backwards compatibility, it cannot be abstract.)
+     * It may be overridden by a provider to unwrap a previously wrapped key.
+     * Such an override is expected to throw an InvalidKeyException if
+     * the given wrapped key cannot be unwrapped.
+     * If this method is not overridden, it always throws an
+     * UnsupportedOperationException.
+     *
+     * @param wrappedKey the key to be unwrapped.
+     *
+     * @param wrappedKeyAlgorithm the algorithm associated with the wrapped
+     * key.
+     *
+     * @param wrappedKeyType the type of the wrapped key. This is one of
+     * <code>SECRET_KEY</code>, <code>PRIVATE_KEY</code>, or
+     * <code>PUBLIC_KEY</code>.
+     *
+     * @return the unwrapped key.
+     *
+     * @exception NoSuchAlgorithmException if no installed providers
+     * can create keys of type <code>wrappedKeyType</code> for the
+     * <code>wrappedKeyAlgorithm</code>.
+     *
+     * @exception InvalidKeyException if <code>wrappedKey</code> does not
+     * represent a wrapped key of type <code>wrappedKeyType</code> for
+     * the <code>wrappedKeyAlgorithm</code>.
+     */
+    protected Key engineUnwrap(byte[] wrappedKey,
+                               String wrappedKeyAlgorithm,
+                               int wrappedKeyType)
+        throws InvalidKeyException, NoSuchAlgorithmException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Returns the key size of the given key object in bits.
+     * <p>This concrete method has been added to this previously-defined
+     * abstract class. It throws an <code>UnsupportedOperationException</code>
+     * if it is not overridden by the provider.
+     *
+     * @param key the key object.
+     *
+     * @return the key size of the given key object.
+     *
+     * @exception InvalidKeyException if <code>key</code> is invalid.
+     */
+    protected int engineGetKeySize(Key key)
+        throws InvalidKeyException
+    {
+        throw new UnsupportedOperationException();
+    }
+}

Added: openjdk-crypto/trunk/src/main/java/javax/crypto/CryptoAllPermission.java
===================================================================
--- openjdk-crypto/trunk/src/main/java/javax/crypto/CryptoAllPermission.java	                        (rev 0)
+++ openjdk-crypto/trunk/src/main/java/javax/crypto/CryptoAllPermission.java	2010-03-13 04:23:29 UTC (rev 25)
@@ -0,0 +1,179 @@
+/*
+ * Copyright 1999-2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.crypto;
+
+import java.security.*;
+import java.util.Enumeration;
+import java.util.Vector;
+
+/**
+ * The CryptoAllPermission is a permission that implies
+ * any other crypto permissions.
+ * <p>
+ *
+ * @see java.security.Permission
+ * @see java.security.AllPermission
+ *
+ * @author Sharon Liu
+ * @since 1.4
+ */
+
+final class CryptoAllPermission extends CryptoPermission {
+
+    private static final long serialVersionUID = -5066513634293192112L;
+
+    // This class is similar to java.security.AllPermission.
+    static final String ALG_NAME = "CryptoAllPermission";
+    static final CryptoAllPermission INSTANCE =
+        new CryptoAllPermission();
+
+    private CryptoAllPermission() {
+        super(ALG_NAME);
+    }
+
+    /**
+     * Checks if the specified permission is implied by
+     * this object.
+     *
+     * @param p the permission to check against.
+     *
+     * @return true if the specified permission is an
+     * instance of CryptoPermission.
+     */
+    public boolean implies(Permission p) {
+         return (p instanceof CryptoPermission);
+    }
+
+    /**
+     * Checks two CryptoAllPermission objects for equality.
+     * Two CryptoAllPermission objects are always equal.
+     *
+     * @param obj the object to test for equality with this object.
+     *
+     * @return true if <i>obj</i> is a CryptoAllPermission object.
+     */
+    public boolean equals(Object obj) {
+        return (obj == INSTANCE);
+    }
+
+    /**
+     *
+     * Returns the hash code value for this object.
+     *
+     * @return a hash code value for this object.
+     */
+    public int hashCode() {
+        return 1;
+    }
+
+    /**
+     * Returns a new PermissionCollection object for storing
+     * CryptoAllPermission objects.
+     * <p>
+     *
+     * @return a new PermissionCollection object suitable for
+     * storing CryptoAllPermissions.
+     */
+    public PermissionCollection newPermissionCollection() {
+        return new CryptoAllPermissionCollection();
+    }
+}
+
+/**
+ * A CryptoAllPermissionCollection stores a collection
+ * of CryptoAllPermission permissions.
+ *
+ * @see java.security.Permission
+ * @see java.security.Permissions
+ * @see javax.crypto.CryptoPermission
+ *
+ * @author Sharon Liu
+ */
+final class CryptoAllPermissionCollection extends PermissionCollection
+    implements java.io.Serializable
+{
+
+    private static final long serialVersionUID = 7450076868380144072L;
+
+    // true if a CryptoAllPermission has been added
+    private boolean all_allowed;
+
+    /**
+     * Create an empty CryptoAllPermissions object.
+     */
+    CryptoAllPermissionCollection() {
+        all_allowed = false;
+    }
+
+    /**
+     * Adds a permission to the CryptoAllPermissions.
+     *
+     * @param permission the Permission object to add.
+     *
+     * @exception SecurityException - if this CryptoAllPermissionCollection
+     * object has been marked readonly
+     */
+    public void add(Permission permission)
+    {
+        if (isReadOnly())
+            throw new SecurityException("attempt to add a Permission to " +
+                                        "a readonly PermissionCollection");
+
+        if (permission != CryptoAllPermission.INSTANCE)
+            return;
+
+        all_allowed = true;
+    }
+
+    /**
+     * Check and see if this set of permissions implies the permissions
+     * expressed in "permission".
+     *
+     * @param p the Permission object to compare
+     *
+     * @return true if the given permission is implied by this
+     * CryptoAllPermissionCollection.
+     */
+    public boolean implies(Permission permission)
+    {
+        if (!(permission instanceof CryptoPermission)) {
+            return false;
+        }
+        return all_allowed;
+    }
+
+    /**
+     * Returns an enumeration of all the CryptoAllPermission
+     * objects in the  container.
+     *
+     * @return an enumeration of all the CryptoAllPermission objects.
+     */
+    public Enumeration elements() {
+        Vector v = new Vector(1);
+        if (all_allowed) v.add(CryptoAllPermission.INSTANCE);
+        return v.elements();
+    }
+}

Added: openjdk-crypto/trunk/src/main/java/javax/crypto/CryptoPermission.java
===================================================================
--- openjdk-crypto/trunk/src/main/java/javax/crypto/CryptoPermission.java	                        (rev 0)
+++ openjdk-crypto/trunk/src/main/java/javax/crypto/CryptoPermission.java	2010-03-13 04:23:29 UTC (rev 25)
@@ -0,0 +1,545 @@
+/*
+ * Copyright 1999-2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.crypto;
+
+import java.security.*;
+import java.security.spec.AlgorithmParameterSpec;
+import java.io.Serializable;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import javax.crypto.spec.*;
+
+/**
+ * The CryptoPermission class extends the
+ * java.security.Permission class. A
+ * CryptoPermission object is used to represent
+ * the ability of an application/applet to use certain
+ * algorithms with certain key sizes and other
+ * restrictions in certain environments. <p>
+ *
+ * @see java.security.Permission
+ *
+ * @author Jan Luehe
+ * @author Sharon Liu
+ * @since 1.4
+ */
+class CryptoPermission extends java.security.Permission {
+
+    private static final long serialVersionUID = 8987399626114087514L;
+
+    private String alg;
+    private int maxKeySize = Integer.MAX_VALUE; // no restriction on maxKeySize
+    private String exemptionMechanism = null;
+    private AlgorithmParameterSpec algParamSpec = null;
+    private boolean checkParam = false; // no restriction on param
+
+    static final String ALG_NAME_WILDCARD = "*";
+
+    /**
+     * Constructor that takes an algorithm name.
+     *
+     * This constructor implies that the given algorithm can be
+     * used without any restrictions.
+     *
+     * @param alg the algorithm name.
+     */
+    CryptoPermission(String alg) {
+        super(null);
+        this.alg = alg;
+    }
+
+    /**
+     * Constructor that takes an algorithm name and a maximum
+     * key size.
+     *
+     * This constructor implies that the given algorithm can be
+     * used with a key size up to <code>maxKeySize</code>.
+     *
+     * @param alg the algorithm name.
+     *
+     * @param maxKeySize the maximum allowable key size,
+     * specified in number of bits.
+     */
+    CryptoPermission(String alg, int maxKeySize) {
+        super(null);
+        this.alg = alg;
+        this.maxKeySize = maxKeySize;
+    }
+
+    /**
+     * Constructor that takes an algorithm name, a maximum
+     * key size, and an AlgorithmParameterSpec object.
+     *
+     * This constructor implies that the given algorithm can be
+     * used with a key size up to <code>maxKeySize</code>, and
+     * algorithm
+     * parameters up to the limits set in <code>algParamSpec</code>.
+     *
+     * @param alg the algorithm name.
+     *
+     * @param maxKeySize the maximum allowable key size,
+     * specified in number of bits.
+     *
+     * @param algParamSpec the limits for allowable algorithm
+     * parameters.
+     */
+    CryptoPermission(String alg,
+                     int maxKeySize,
+                     AlgorithmParameterSpec algParamSpec) {
+        super(null);
+        this.alg = alg;
+        this.maxKeySize = maxKeySize;
+        this.checkParam = true;
+        this.algParamSpec = algParamSpec;
+    }
+
+    /**
+     * Constructor that takes an algorithm name and the name of
+     * an exemption mechanism.
+     *
+     * This constructor implies that the given algorithm can be
+     * used without any key size or algorithm parameter restrictions
+     * provided that the specified exemption mechanism is enforced.
+     *
+     * @param alg the algorithm name.
+     *
+     * @param exemptionMechanism the name of the exemption mechanism.
+     */
+    CryptoPermission(String alg,
+                     String exemptionMechanism) {
+        super(null);
+        this.alg = alg;
+        this.exemptionMechanism = exemptionMechanism;
+    }
+
+    /**
+     * Constructor that takes an algorithm name, a maximum key
+     * size, and the name of an exemption mechanism.
+     *
+     * This constructor implies that the given algorithm can be
+     * used with a key size up to <code>maxKeySize</code>
+     * provided that the
+     * specified exemption mechanism is enforced.
+     *
+     * @param alg the algorithm name.
+     * @param maxKeySize the maximum allowable key size,
+     * specified in number of bits.
+     * @param exemptionMechanism the name of the exemption
+     * mechanism.
+     */
+    CryptoPermission(String alg,
+                     int maxKeySize,
+                     String exemptionMechanism) {
+        super(null);
+        this.alg = alg;
+        this.exemptionMechanism = exemptionMechanism;
+        this.maxKeySize = maxKeySize;
+    }
+
+    /**
+     * Constructor that takes an algorithm name, a maximum key
+     * size, the name of an exemption mechanism, and an
+     * AlgorithmParameterSpec object.
+     *
+     * This constructor implies that the given algorithm can be
+     * used with a key size up to <code>maxKeySize</code>
+     * and algorithm
+     * parameters up to the limits set in <code>algParamSpec</code>
+     * provided that
+     * the specified exemption mechanism is enforced.
+     *
+     * @param alg the algorithm name.
+     * @param maxKeySize the maximum allowable key size,
+     * specified in number of bits.
+     * @param algParamSpec the limit for allowable algorithm
+     *  parameter spec.
+     * @param exemptionMechanism the name of the exemption
+     * mechanism.
+     */
+    CryptoPermission(String alg,
+                     int maxKeySize,
+                     AlgorithmParameterSpec algParamSpec,
+                     String exemptionMechanism) {
+        super(null);
+        this.alg = alg;
+        this.exemptionMechanism = exemptionMechanism;
+        this.maxKeySize = maxKeySize;
+        this.checkParam = true;
+        this.algParamSpec = algParamSpec;
+    }
+
+    /**
+     * Checks if the specified permission is "implied" by
+     * this object.
+     * <p>
+     * More specifically, this method returns true if:<p>
+     * <ul>
+     * <li> <i>p</i> is an instance of CryptoPermission, and<p>
+     * <li> <i>p</i>'s algorithm name equals or (in the case of wildcards)
+     *       is implied by this permission's algorithm name, and<p>
+     * <li> <i>p</i>'s maximum allowable key size is less or
+     *       equal to this permission's maximum allowable key size, and<p>
+     * <li> <i>p</i>'s algorithm parameter spec equals or is
+     *        implied by this permission's algorithm parameter spec, and<p>
+     * <li> <i>p</i>'s exemptionMechanism equals or
+     *        is implied by this permission's
+     *        exemptionMechanism (a <code>null</code> exemption mechanism
+     *        implies any other exemption mechanism).
+     * </ul>
+     *
+     * @param p the permission to check against.
+     *
+     * @return true if the specified permission is equal to or
+     * implied by this permission, false otherwise.
+     */
+    public boolean implies(Permission p) {
+        if (!(p instanceof CryptoPermission))
+            return false;
+
+        CryptoPermission cp = (CryptoPermission)p;
+
+        if ((!alg.equalsIgnoreCase(cp.alg)) &&
+            (!alg.equalsIgnoreCase(ALG_NAME_WILDCARD))) {
+            return false;
+        }
+
+        // alg is the same as cp's alg or
+        // alg is a wildcard.
+        if (cp.maxKeySize <= this.maxKeySize) {
+            // check algParamSpec.
+            if (!impliesParameterSpec(cp.checkParam, cp.algParamSpec)) {
+                return false;
+            }
+
+            // check exemptionMechanism.
+            if (impliesExemptionMechanism(cp.exemptionMechanism)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Checks two CryptoPermission objects for equality. Checks that
+     * <code>obj</code> is a CryptoPermission, and has the same
+     * algorithm name,
+     * exemption mechanism name, maximum allowable key size and
+     * algorithm parameter spec
+     * as this object.
+     * <P>
+     * @param obj the object to test for equality with this object.
+     * @return true if <code>obj</code> is equal to this object.
+     */
+    public boolean equals(Object obj) {
+        if (obj == this)
+            return true;
+
+        if (!(obj instanceof CryptoPermission))
+            return false;
+
+        CryptoPermission that = (CryptoPermission) obj;
+
+        if (!(alg.equalsIgnoreCase(that.alg)) ||
+            (maxKeySize != that.maxKeySize)) {
+            return false;
+        }
+        if (this.checkParam != that.checkParam) {
+            return false;
+        }
+        return (equalObjects(this.exemptionMechanism,
+                             that.exemptionMechanism) &&
+                equalObjects(this.algParamSpec,
+                             that.algParamSpec));
+    }
+
+    /**
+     * Returns the hash code value for this object.
+     *
+     * @return a hash code value for this object.
+     */
+
+    public int hashCode() {
+        int retval = alg.hashCode();
+        retval ^= maxKeySize;
+        if (exemptionMechanism != null) {
+            retval ^= exemptionMechanism.hashCode();
+        }
+        if (checkParam) retval ^= 100;
+        if (algParamSpec != null) {
+            retval ^= algParamSpec.hashCode();
+        }
+        return retval;
+    }
+
+    /**
+     * There is no action defined for a CryptoPermission
+     * onject.
+     */
+    public String getActions()
+    {
+        return null;
+    }
+
+    /**
+     * Returns a new PermissionCollection object for storing
+     * CryptoPermission objects.
+     *
+     * @return a new PermissionCollection object suitable for storing
+     * CryptoPermissions.
+     */
+
+    public PermissionCollection newPermissionCollection() {
+        return new CryptoPermissionCollection();
+    }
+
+    /**
+     * Returns the algorithm name associated with
+     * this CryptoPermission object.
+     */
+    final String getAlgorithm() {
+        return alg;
+    }
+
+    /**
+     * Returns the exemption mechanism name
+     * associated with this CryptoPermission
+     * object.
+     */
+    final String getExemptionMechanism() {
+        return exemptionMechanism;
+    }
+
+    /**
+     * Returns the maximum allowable key size associated
+     * with this CryptoPermission object.
+     */
+    final int getMaxKeySize() {
+        return maxKeySize;
+    }
+
+    /**
+     * Returns true if there is a limitation on the
+     * AlgorithmParameterSpec associated with this
+     * CryptoPermission object and false if otherwise.
+     */
+    final boolean getCheckParam() {
+        return checkParam;
+    }
+
+    /**
+     * Returns the AlgorithmParameterSpec
+     * associated with this CryptoPermission
+     * object.
+     */
+    final AlgorithmParameterSpec getAlgorithmParameterSpec() {
+        return algParamSpec;
+    }
+
+    /**
+     * Returns a string describing this CryptoPermission.  The convention is to
+     * specify the class name, the algorithm name, the maximum allowable
+     * key size, and the name of the exemption mechanism, in the following
+     * format: '("ClassName" "algorithm" "keysize" "exemption_mechanism")'.
+     *
+     * @return information about this CryptoPermission.
+     */
+    public String toString() {
+        StringBuilder buf = new StringBuilder(100);
+        buf.append("(CryptoPermission " + alg + " " + maxKeySize);
+        if (algParamSpec != null) {
+            if (algParamSpec instanceof RC2ParameterSpec) {
+                buf.append(" , effective " +
+                    ((RC2ParameterSpec)algParamSpec).getEffectiveKeyBits());
+            } else if (algParamSpec instanceof RC5ParameterSpec) {
+                buf.append(" , rounds " +
+                    ((RC5ParameterSpec)algParamSpec).getRounds());
+            }
+        }
+        if (exemptionMechanism != null) { // OPTIONAL
+            buf.append(" " + exemptionMechanism);
+        }
+        buf.append(")");
+        return buf.toString();
+    }
+
+    private boolean impliesExemptionMechanism(String exemptionMechanism) {
+        if (this.exemptionMechanism == null) {
+            return true;
+        }
+
+        if (exemptionMechanism == null) {
+            return false;
+        }
+
+        if (this.exemptionMechanism.equals(exemptionMechanism)) {
+            return true;
+        }
+
+        return false;
+    }
+
+    private boolean impliesParameterSpec(boolean checkParam,
+                                         AlgorithmParameterSpec algParamSpec) {
+        if ((this.checkParam) && checkParam) {
+            if (algParamSpec == null) {
+                return true;
+            } else if (this.algParamSpec == null) {
+                return false;
+            }
+
+            if (this.algParamSpec.getClass() != algParamSpec.getClass()) {
+                return false;
+            }
+
+            if (algParamSpec instanceof RC2ParameterSpec) {
+                if (((RC2ParameterSpec)algParamSpec).getEffectiveKeyBits() <=
+                    ((RC2ParameterSpec)
+                     (this.algParamSpec)).getEffectiveKeyBits()) {
+                    return true;
+                }
+            }
+
+            if (algParamSpec instanceof RC5ParameterSpec) {
+                if (((RC5ParameterSpec)algParamSpec).getRounds() <=
+                    ((RC5ParameterSpec)this.algParamSpec).getRounds()) {
+                    return true;
+                }
+            }
+
+            if (algParamSpec instanceof PBEParameterSpec) {
+                if (((PBEParameterSpec)algParamSpec).getIterationCount() <=
+                    ((PBEParameterSpec)this.algParamSpec).getIterationCount()) {
+                    return true;
+                }
+            }
+
+            // For classes we don't know, the following
+            // may be the best try.
+            if (this.algParamSpec.equals(algParamSpec)) {
+                return true;
+            }
+            return false;
+        } else if (this.checkParam) {
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    private boolean equalObjects(Object obj1, Object obj2) {
+        if (obj1 == null) {
+            return (obj2 == null ? true : false);
+        }
+
+        return obj1.equals(obj2);
+    }
+}
+
+/**
+ * A CryptoPermissionCollection stores a set of CryptoPermission
+ * permissions.
+ *
+ * @see java.security.Permission
+ * @see java.security.Permissions
+ * @see java.security.PermissionCollection
+ *
+ * @author Sharon Liu
+ */
+final class CryptoPermissionCollection extends PermissionCollection
+implements Serializable {
+
+    private static final long serialVersionUID = -511215555898802763L;
+
+    private Vector permissions;
+
+    /**
+     * Creates an empty CryptoPermissionCollection
+     * object.
+     */
+    CryptoPermissionCollection() {
+        permissions = new Vector(3);
+    }
+
+    /**
+     * Adds a permission to the CryptoPermissionCollection.
+     *
+     * @param permission the Permission object to add.
+     *
+     * @exception SecurityException - if this CryptoPermissionCollection
+     * object has been marked <i>readOnly</i>.
+     */
+    public void add(Permission permission)
+    {
+        if (isReadOnly())
+            throw new SecurityException("attempt to add a Permission " +
+                                        "to a readonly PermissionCollection");
+
+        if (!(permission instanceof CryptoPermission))
+            return;
+
+        permissions.addElement(permission);
+    }
+
+    /**
+      * Check and see if this CryptoPermission object implies
+      * the given Permission object.
+     *
+     * @param p the Permission object to compare
+     *
+     * @return true if the given permission  is implied by this
+     * CryptoPermissionCollection, false if not.
+     */
+    public boolean implies(Permission permission) {
+        if (!(permission instanceof CryptoPermission))
+            return false;
+
+        CryptoPermission cp = (CryptoPermission)permission;
+
+        Enumeration e = permissions.elements();
+
+        while (e.hasMoreElements()) {
+            CryptoPermission x = (CryptoPermission) e.nextElement();
+            if (x.implies(cp)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns an enumeration of all the CryptoPermission objects
+     * in the container.
+     *
+     * @return an enumeration of all the CryptoPermission objects.
+     */
+
+    public Enumeration elements()
+    {
+        return permissions.elements();
+    }
+}

Added: openjdk-crypto/trunk/src/main/java/javax/crypto/CryptoPermissions.java
===================================================================
--- openjdk-crypto/trunk/src/main/java/javax/crypto/CryptoPermissions.java	                        (rev 0)
+++ openjdk-crypto/trunk/src/main/java/javax/crypto/CryptoPermissions.java	2010-03-13 04:23:29 UTC (rev 25)
@@ -0,0 +1,479 @@
+/*
+ * Copyright 1999-2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.crypto;
+
+import java.security.*;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+import java.util.NoSuchElementException;
+import java.io.Serializable;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.BufferedReader;
+import java.io.IOException;
+
+/**
+ * This class contains CryptoPermission objects, organized into
+ * PermissionCollections according to algorithm names.
+ *
+ * <p>When the <code>add</code> method is called to add a
+ * CryptoPermission, the CryptoPermission is stored in the
+ * appropriate PermissionCollection. If no such
+ * collection exists yet, the algorithm name associated with
+ * the CryptoPermission object is
+ * determined and the <code>newPermissionCollection</code> method
+ * is called on the CryptoPermission or CryptoAllPermission class to
+ * create the PermissionCollection and add it to the Permissions object.
+ *
+ * @see javax.crypto.CryptoPermission
+ * @see java.security.PermissionCollection
+ * @see java.security.Permissions
+ *
+ * @author Sharon Liu
+ * @since 1.4
+ */
+final class CryptoPermissions extends PermissionCollection
+implements Serializable {
+
+    private static final long serialVersionUID = 4946547168093391015L;
+
+    // This class is similar to java.security.Permissions
+    private Hashtable perms;
+
+    /**
+     * Creates a new CryptoPermissions object containing
+     * no CryptoPermissionCollections.
+     */
+    CryptoPermissions() {
+        perms = new Hashtable(7);
+    }
+
+    /**
+     * Populates the crypto policy from the specified
+     * InputStream into this CryptoPermissions object.
+     *
+     * @param in the InputStream to load from.
+     *
+     * @exception SecurityException if cannot load
+     * successfully.
+     */
+    void load(InputStream in)
+        throws IOException, CryptoPolicyParser.ParsingException {
+        CryptoPolicyParser parser = new CryptoPolicyParser();
+        parser.read(new BufferedReader(new InputStreamReader(in, "UTF-8")));
+
+        CryptoPermission[] parsingResult = parser.getPermissions();
+        for (int i = 0; i < parsingResult.length; i++) {
+            this.add(parsingResult[i]);
+        }
+    }
+
+    /**
+     * Returns true if this CryptoPermissions object doesn't
+     * contain any CryptoPermission objects; otherwise, returns
+     * false.
+     */
+    boolean isEmpty() {
+        return perms.isEmpty();
+    }
+
+    /**
+     * Adds a permission object to the PermissionCollection for the
+     * algorithm returned by
+     * <code>(CryptoPermission)permission.getAlgorithm()</code>.
+     *
+     * This method creates
+     * a new PermissionCollection object (and adds the permission to it)
+     * if an appropriate collection does not yet exist. <p>
+     *
+     * @param permission the Permission object to add.
+     *
+     * @exception SecurityException if this CryptoPermissions object is
+     * marked as readonly.
+     *
+     * @see isReadOnly
+     */
+    public void add(Permission permission) {
+
+        if (isReadOnly())
+            throw new SecurityException("Attempt to add a Permission " +
+                                        "to a readonly CryptoPermissions " +
+                                        "object");
+
+        if (!(permission instanceof CryptoPermission))
+            return;
+
+        CryptoPermission cryptoPerm = (CryptoPermission)permission;
+        PermissionCollection pc =
+                        getPermissionCollection(cryptoPerm);
+        pc.add(cryptoPerm);
+        String alg = cryptoPerm.getAlgorithm();
+        if (!perms.containsKey(alg)) {
+            perms.put(alg, pc);
+        }
+    }
+
+    /**
+     * Checks if this object's PermissionCollection for permissons
+     * of the specified permission's algorithm implies the specified
+     * permission. Returns true if the checking succeeded.
+     *
+     * @param permission the Permission object to check.
+     *
+     * @return true if "permission" is implied by the permissions
+     * in the PermissionCollection it belongs to, false if not.
+     *
+     */
+    public boolean implies(Permission permission) {
+        if (!(permission instanceof CryptoPermission)) {
+            return false;
+        }
+
+        CryptoPermission cryptoPerm = (CryptoPermission)permission;
+
+        PermissionCollection pc =
+            getPermissionCollection(cryptoPerm.getAlgorithm());
+        return pc.implies(cryptoPerm);
+    }
+
+    /**
+     * Returns an enumeration of all the Permission objects in all the
+     * PermissionCollections in this CryptoPermissions object.
+     *
+     * @return an enumeration of all the Permissions.
+     */
+    public Enumeration elements() {
+        // go through each Permissions in the hash table
+        // and call their elements() function.
+        return new PermissionsEnumerator(perms.elements());
+    }
+
+    /**
+     * Returns a CryptoPermissions object which
+     * represents the minimum of the specified
+     * CryptoPermissions object and this
+     * CryptoPermissions object.
+     *
+     * @param other the CryptoPermission
+     * object to compare with this object.
+     */
+    CryptoPermissions getMinimum(CryptoPermissions other) {
+        if (other == null) {
+            return null;
+        }
+
+        if (this.perms.containsKey(CryptoAllPermission.ALG_NAME)) {
+            return other;
+        }
+
+        if (other.perms.containsKey(CryptoAllPermission.ALG_NAME)) {
+            return this;
+        }
+
+        CryptoPermissions ret = new CryptoPermissions();
+
+
+        PermissionCollection thatWildcard =
+            (PermissionCollection)other.perms.get(
+                                        CryptoPermission.ALG_NAME_WILDCARD);
+        int maxKeySize = 0;
+        if (thatWildcard != null) {
+            maxKeySize = ((CryptoPermission)
+                    thatWildcard.elements().nextElement()).getMaxKeySize();
+        }
+        // For each algorithm in this CryptoPermissions,
+        // find out if there is anything we should add into
+        // ret.
+        Enumeration thisKeys = this.perms.keys();
+        while (thisKeys.hasMoreElements()) {
+            String alg = (String)thisKeys.nextElement();
+
+            PermissionCollection thisPc =
+                (PermissionCollection)this.perms.get(alg);
+            PermissionCollection thatPc =
+                (PermissionCollection)other.perms.get(alg);
+
+            CryptoPermission[] partialResult;
+
+            if (thatPc == null) {
+                if (thatWildcard == null) {
+                    // The other CryptoPermissions
+                    // doesn't allow this given
+                    // algorithm at all. Just skip this
+                    // algorithm.
+                    continue;
+                }
+                partialResult = getMinimum(maxKeySize, thisPc);
+            } else {
+                partialResult = getMinimum(thisPc, thatPc);
+            }
+
+            for (int i = 0; i < partialResult.length; i++) {
+                ret.add(partialResult[i]);
+            }
+        }
+
+        PermissionCollection thisWildcard =
+            (PermissionCollection)this.perms.get(
+                                      CryptoPermission.ALG_NAME_WILDCARD);
+
+        // If this CryptoPermissions doesn't
+        // have a wildcard, we are done.
+        if (thisWildcard == null) {
+            return ret;
+        }
+
+        // Deal with the algorithms only appear
+        // in the other CryptoPermissions.
+        maxKeySize =
+            ((CryptoPermission)
+                    thisWildcard.elements().nextElement()).getMaxKeySize();
+        Enumeration thatKeys = other.perms.keys();
+        while (thatKeys.hasMoreElements()) {
+            String alg = (String)thatKeys.nextElement();
+
+            if (this.perms.containsKey(alg)) {
+                continue;
+            }
+
+            PermissionCollection thatPc =
+                (PermissionCollection)other.perms.get(alg);
+
+            CryptoPermission[] partialResult;
+
+            partialResult = getMinimum(maxKeySize, thatPc);
+
+            for (int i = 0; i < partialResult.length; i++) {
+                ret.add(partialResult[i]);
+            }
+        }
+        return ret;
+    }
+
+    /**
+     * Get the minimum of the two given PermissionCollection
+     * <code>thisPc</code> and <code>thatPc</code>.
+     *
+     * @param thisPc the first given PermissionColloection
+     * object.
+     *
+     * @param thatPc the second given PermissionCollection
+     * object.
+     */
+    private CryptoPermission[] getMinimum(PermissionCollection thisPc,
+                                          PermissionCollection thatPc) {
+        Vector permVector = new Vector(2);
+
+        Enumeration thisPcPermissions = thisPc.elements();
+
+        // For each CryptoPermission in
+        // thisPc object, do the following:
+        // 1) if this CryptoPermission is implied
+        //     by thatPc, this CryptoPermission
+        //     should be returned, and we can
+        //     move on to check the next
+        //     CryptoPermission in thisPc.
+        // 2) otherwise, we should return
+        //     all CryptoPermissions in thatPc
+        //     which
+        //     are implied by this CryptoPermission.
+        //     Then we can move on to the
+        //     next CryptoPermission in thisPc.
+        while (thisPcPermissions.hasMoreElements()) {
+            CryptoPermission thisCp =
+                (CryptoPermission)thisPcPermissions.nextElement();
+
+            Enumeration thatPcPermissions = thatPc.elements();
+            while (thatPcPermissions.hasMoreElements()) {
+                CryptoPermission thatCp =
+                    (CryptoPermission)thatPcPermissions.nextElement();
+
+                if (thatCp.implies(thisCp)) {
+                    permVector.addElement(thisCp);
+                    break;
+                }
+                if (thisCp.implies(thatCp)) {
+                    permVector.addElement(thatCp);
+                }
+            }
+        }
+
+        CryptoPermission[] ret = new CryptoPermission[permVector.size()];
+        permVector.copyInto(ret);
+        return ret;
+    }
+
+    /**
+     * Returns all the CryptoPermission objects in the given
+     * PermissionCollection object
+     * whose maximum keysize no greater than <code>maxKeySize</code>.
+     * For all CryptoPermission objects with a maximum keysize greater
+     * than <code>maxKeySize</code>, this method constructs a
+     * corresponding CryptoPermission object whose maximum keysize is
+     * set to <code>maxKeySize</code>, and includes that in the result.
+     *
+     * @param maxKeySize the given maximum key size.
+     *
+     * @param pc the given PermissionCollection object.
+     */
+    private CryptoPermission[] getMinimum(int maxKeySize,
+                                          PermissionCollection pc) {
+        Vector permVector = new Vector(1);
+
+        Enumeration enum_ = pc.elements();
+
+        while (enum_.hasMoreElements()) {
+            CryptoPermission cp =
+                (CryptoPermission)enum_.nextElement();
+            if (cp.getMaxKeySize() <= maxKeySize) {
+                permVector.addElement(cp);
+            } else {
+                if (cp.getCheckParam()) {
+                    permVector.addElement(
+                           new CryptoPermission(cp.getAlgorithm(),
+                                                maxKeySize,
+                                                cp.getAlgorithmParameterSpec(),
+                                                cp.getExemptionMechanism()));
+                } else {
+                    permVector.addElement(
+                           new CryptoPermission(cp.getAlgorithm(),
+                                                maxKeySize,
+                                                cp.getExemptionMechanism()));
+                }
+            }
+        }
+
+        CryptoPermission[] ret = new CryptoPermission[permVector.size()];
+        permVector.copyInto(ret);
+        return ret;
+    }
+
+    /**
+     * Returns the PermissionCollection for the
+     * specified algorithm. Returns null if there
+     * isn't such a PermissionCollection.
+     *
+     * @param alg the algorithm name.
+     */
+    PermissionCollection getPermissionCollection(String alg) {
+        // If this CryptoPermissions includes CryptoAllPermission,
+        // we should return CryptoAllPermission.
+        if (perms.containsKey(CryptoAllPermission.ALG_NAME)) {
+            return
+                (PermissionCollection)(perms.get(CryptoAllPermission.ALG_NAME));
+        }
+
+        PermissionCollection pc = (PermissionCollection)perms.get(alg);
+
+        // If there isn't a PermissionCollection for
+        // the given algorithm,we should return the
+        // PermissionCollection for the wildcard
+        // if there is one.
+        if (pc == null) {
+            pc = (PermissionCollection)perms.get(
+                                       CryptoPermission.ALG_NAME_WILDCARD);
+        }
+        return pc;
+    }
+
+    /**
+     * Returns the PermissionCollection for the algorithm
+     * associated with the specified CryptoPermission
+     * object. Creates such a PermissionCollection
+     * if such a PermissionCollection does not
+     * exist yet.
+     *
+     * @param cryptoPerm the CryptoPermission object.
+     */
+    private PermissionCollection getPermissionCollection(
+                                          CryptoPermission cryptoPerm) {
+
+        String alg = cryptoPerm.getAlgorithm();
+
+        PermissionCollection pc = (PermissionCollection)perms.get(alg);
+
+        if (pc == null) {
+            pc = cryptoPerm.newPermissionCollection();
+        }
+        return pc;
+    }
+}
+
+final class PermissionsEnumerator implements Enumeration {
+
+    // all the perms
+    private Enumeration perms;
+    // the current set
+    private Enumeration permset;
+
+    PermissionsEnumerator(Enumeration e) {
+        perms = e;
+        permset = getNextEnumWithMore();
+    }
+
+    public synchronized boolean hasMoreElements() {
+        // if we enter with permissionimpl null, we know
+        // there are no more left.
+
+        if (permset == null)
+            return  false;
+
+        // try to see if there are any left in the current one
+
+        if (permset.hasMoreElements())
+            return true;
+
+        // get the next one that has something in it...
+        permset = getNextEnumWithMore();
+
+        // if it is null, we are done!
+        return (permset != null);
+    }
+
+    public synchronized Object nextElement() {
+        // hasMoreElements will update permset to the next permset
+        // with something in it...
+
+        if (hasMoreElements()) {
+            return permset.nextElement();
+        } else {
+            throw new NoSuchElementException("PermissionsEnumerator");
+        }
+
+    }
+
+    private Enumeration getNextEnumWithMore() {
+        while (perms.hasMoreElements()) {
+            PermissionCollection pc =
+                (PermissionCollection) perms.nextElement();
+            Enumeration next = pc.elements();
+            if (next.hasMoreElements())
+                return next;
+        }
+        return null;
+    }
+}

Added: openjdk-crypto/trunk/src/main/java/javax/crypto/CryptoPolicyParser.java
===================================================================
--- openjdk-crypto/trunk/src/main/java/javax/crypto/CryptoPolicyParser.java	                        (rev 0)
+++ openjdk-crypto/trunk/src/main/java/javax/crypto/CryptoPolicyParser.java	2010-03-13 04:23:29 UTC (rev 25)
@@ -0,0 +1,707 @@
+/*
+ * Copyright 1999-2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.crypto;
+
+import java.io.*;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+import java.util.StringTokenizer;
+import static java.util.Locale.ENGLISH;
+
+import java.security.GeneralSecurityException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.lang.reflect.*;
+
+/**
+ * JCE has two pairs of jurisdiction policy files: one represents U.S. export
+ * laws, and the other represents the local laws of the country where the
+ * JCE will be used.
+ *
+ * The jurisdiction policy file has the same syntax as JDK policy files except
+ * that JCE has new permission classes called javax.crypto.CryptoPermission
+ * and javax.crypto.CryptoAllPermission.
+ *
+ * The format of a permission entry in the jurisdiction policy file is:
+ *
+ *   permission <crypto permission class name>[, <algorithm name>
+ *              [[, <exemption mechanism name>][, <maxKeySize>
+ *              [, <AlgrithomParameterSpec class name>, <parameters
+ *              for constructing an AlgrithomParameterSpec object>]]]];
+ *
+ * @author Sharon Liu
+ *
+ * @see java.security.Permissions
+ * @see java.security.spec.AlgrithomParameterSpec
+ * @see javax.crypto.CryptoPermission
+ * @see javax.crypto.CryptoAllPermission
+ * @see javax.crypto.CryptoPermissions
+ * @since 1.4
+ */
+
+final class CryptoPolicyParser {
+
+    private Vector grantEntries;
+
+    // Convenience variables for parsing
+    private StreamTokenizer st;
+    private int lookahead;
+
+    /**
+     * Creates a CryptoPolicyParser object.
+     */
+    CryptoPolicyParser() {
+        grantEntries = new Vector();
+    }
+
+    /**
+     * Reads a policy configuration using a Reader object. <p>
+     *
+     * @param policy the policy Reader object.
+     *
+     * @exception ParsingException if the policy configuration
+     * contains a syntax error.
+     *
+     * @exception IOException if an error occurs while reading
+     * the policy configuration.
+     */
+
+    void read(Reader policy)
+        throws ParsingException, IOException
+    {
+        if (!(policy instanceof BufferedReader)) {
+            policy = new BufferedReader(policy);
+        }
+
+        /*
+         * Configure the stream tokenizer:
+         *      Recognize strings between "..."
+         *      Don't convert words to lowercase
+         *      Recognize both C-style and C++-style comments
+         *      Treat end-of-line as white space, not as a token
+         */
+        st = new StreamTokenizer(policy);
+
+        st.resetSyntax();
+        st.wordChars('a', 'z');
+        st.wordChars('A', 'Z');
+        st.wordChars('.', '.');
+        st.wordChars('0', '9');
+        st.wordChars('_', '_');
+        st.wordChars('$', '$');
+        st.wordChars(128 + 32, 255);
+        st.whitespaceChars(0, ' ');
+        st.commentChar('/');
+        st.quoteChar('\'');
+        st.quoteChar('"');
+        st.lowerCaseMode(false);
+        st.ordinaryChar('/');
+        st.slashSlashComments(true);
+        st.slashStarComments(true);
+        st.parseNumbers();
+
+        /*
+         * The crypto jurisdiction policy must be consistent. The
+         * following hashtable is used for checking consistency.
+         */
+        Hashtable processedPermissions = null;
+
+        /*
+         * The main parsing loop.  The loop is executed once for each entry
+         * in the policy file. The entries are delimited by semicolons. Once
+         * we've read in the information for an entry, go ahead and try to
+         * add it to the grantEntries.
+         */
+        lookahead = st.nextToken();
+        while (lookahead != StreamTokenizer.TT_EOF) {
+            if (peek("grant")) {
+                GrantEntry ge = parseGrantEntry(processedPermissions);
+                if (ge != null)
+                    grantEntries.addElement(ge);
+            } else {
+                throw new ParsingException(st.lineno(), "expected grant " +
+                                           "statement");
+            }
+            match(";");
+        }
+    }
+
+    /**
+     * parse a Grant entry
+     */
+    private GrantEntry parseGrantEntry(Hashtable processedPermissions)
+        throws ParsingException, IOException
+    {
+        GrantEntry e = new GrantEntry();
+
+        match("grant");
+        match("{");
+
+        while(!peek("}")) {
+            if (peek("Permission")) {
+                CryptoPermissionEntry pe =
+                    parsePermissionEntry(processedPermissions);
+                e.add(pe);
+                match(";");
+            } else {
+                throw new
+                    ParsingException(st.lineno(), "expected permission entry");
+            }
+        }
+        match("}");
+
+        return e;
+    }
+
+    /**
+     * parse a CryptoPermission entry
+     */
+    private CryptoPermissionEntry parsePermissionEntry(
+                                       Hashtable processedPermissions)
+        throws ParsingException, IOException
+    {
+        CryptoPermissionEntry e = new CryptoPermissionEntry();
+
+        match("Permission");
+        e.cryptoPermission = match("permission type");
+
+        if (e.cryptoPermission.equals("javax.crypto.CryptoAllPermission")) {
+            // Done with the CryptoAllPermission entry.
+            e.alg = CryptoAllPermission.ALG_NAME;
+            e.maxKeySize = Integer.MAX_VALUE;
+            return e;
+        }
+
+        // Should see the algorithm name.
+        if (peek("\"")) {
+            // Algorithm name - always convert to upper case after parsing.
+            e.alg = match("quoted string").toUpperCase(ENGLISH);
+        } else {
+            // The algorithm name can be a wildcard.
+            if (peek("*")) {
+                match("*");
+                e.alg = CryptoPermission.ALG_NAME_WILDCARD;
+            } else {
+                throw new ParsingException(st.lineno(),
+                                           "Missing the algorithm name");
+            }
+        }
+
+        peekAndMatch(",");
+
+        // May see the exemption mechanism name.
+        if (peek("\"")) {
+            // Exemption mechanism name - convert to upper case too.
+            e.exemptionMechanism = match("quoted string").toUpperCase(ENGLISH);
+        }
+
+        peekAndMatch(",");
+
+        // Check whether this entry is consistent with other permission entries
+        // that have been read.
+        if (!isConsistent(e.alg, e.exemptionMechanism, processedPermissions)) {
+            throw new ParsingException(st.lineno(), "Inconsistent policy");
+        }
+
+        // Should see the maxKeySize if not at the end of this entry yet.
+        if (peek("number")) {
+            e.maxKeySize = match();
+        } else {
+            if (peek("*")) {
+                match("*");
+                e.maxKeySize = Integer.MAX_VALUE;
+            } else {
+                if (!peek(";")) {
+                    throw new ParsingException(st.lineno(),
+                                               "Missing the maximum " +
+                                               "allowable key size");
+                } else {
+                    // At the end of this permission entry
+                    e.maxKeySize = Integer.MAX_VALUE;
+                }
+            }
+        }
+
+        peekAndMatch(",");
+
+        // May see an AlgorithmParameterSpec class name.
+        if (peek("\"")) {
+            // AlgorithmParameterSpec class name.
+            String algParamSpecClassName = match("quoted string");
+
+            Vector paramsV = new Vector(1);
+            while (peek(",")) {
+                match(",");
+                if (peek("number")) {
+                    paramsV.addElement(new Integer(match()));
+                } else {
+                    if (peek("*")) {
+                        match("*");
+                        paramsV.addElement(new Integer(Integer.MAX_VALUE));
+                    } else {
+                        throw new ParsingException(st.lineno(),
+                                                   "Expecting an integer");
+                    }
+                }
+            }
+
+            Integer[] params = new Integer[paramsV.size()];
+            paramsV.copyInto(params);
+
+            e.checkParam = true;
+            e.algParamSpec = getInstance(algParamSpecClassName, params);
+        }
+
+        return e;
+    }
+
+    private static final AlgorithmParameterSpec getInstance(String type,
+                                                            Integer[] params)
+        throws ParsingException
+    {
+        AlgorithmParameterSpec ret = null;
+
+        try {
+            Class apsClass = Class.forName(type);
+            Class[] paramClasses = new Class[params.length];
+
+            for (int i = 0; i < params.length; i++) {
+                paramClasses[i] = int.class;
+            }
+
+            Constructor c = apsClass.getConstructor(paramClasses);
+            ret = (AlgorithmParameterSpec) c.newInstance((Object[]) params);
+        } catch (Exception e) {
+            throw new ParsingException("Cannot call the constructor of " +
+                                       type + e);
+        }
+        return ret;
+    }
+
+
+    private boolean peekAndMatch(String expect)
+        throws ParsingException, IOException
+    {
+        if (peek(expect)) {
+            match(expect);
+            return true;
+        }
+        return false;
+    }
+
+    private boolean peek(String expect) {
+        boolean found = false;
+
+        switch (lookahead) {
+
+        case StreamTokenizer.TT_WORD:
+            if (expect.equalsIgnoreCase(st.sval))
+                found = true;
+            break;
+        case StreamTokenizer.TT_NUMBER:
+            if (expect.equalsIgnoreCase("number")) {
+                found = true;
+            }
+            break;
+        case ',':
+            if (expect.equals(","))
+                found = true;
+            break;
+        case '{':
+            if (expect.equals("{"))
+                found = true;
+            break;
+        case '}':
+            if (expect.equals("}"))
+                found = true;
+            break;
+        case '"':
+            if (expect.equals("\""))
+                found = true;
+            break;
+        case '*':
+            if (expect.equals("*"))
+                found = true;
+            break;
+        case ';':
+            if (expect.equals(";"))
+                found = true;
+            break;
+        default:
+            break;
+        }
+        return found;
+    }
+
+    /**
+     * Excepts to match a non-negative number.
+     */
+    private int match()
+        throws ParsingException, IOException
+    {
+        int value = -1;
+        int lineno = st.lineno();
+        String sValue = null;
+
+        switch (lookahead) {
+        case StreamTokenizer.TT_NUMBER:
+            value = (int)st.nval;
+            if (value < 0) {
+                sValue = String.valueOf(st.nval);
+            }
+            lookahead = st.nextToken();
+            break;
+        default:
+            sValue = st.sval;
+            break;
+        }
+        if (value <= 0) {
+            throw new ParsingException(lineno, "a non-negative number",
+                                       sValue);
+        }
+        return value;
+    }
+
+    private String match(String expect)
+        throws ParsingException, IOException
+    {
+        String value = null;
+
+        switch (lookahead) {
+        case StreamTokenizer.TT_NUMBER:
+            throw new ParsingException(st.lineno(), expect,
+                                       "number "+String.valueOf(st.nval));
+        case StreamTokenizer.TT_EOF:
+           throw new ParsingException("expected "+expect+", read end of file");
+        case StreamTokenizer.TT_WORD:
+            if (expect.equalsIgnoreCase(st.sval)) {
+                lookahead = st.nextToken();
+            }
+            else if (expect.equalsIgnoreCase("permission type")) {
+                value = st.sval;
+                lookahead = st.nextToken();
+            }
+            else
+                throw new ParsingException(st.lineno(), expect, st.sval);
+            break;
+        case '"':
+            if (expect.equalsIgnoreCase("quoted string")) {
+                value = st.sval;
+                lookahead = st.nextToken();
+            } else if (expect.equalsIgnoreCase("permission type")) {
+                value = st.sval;
+                lookahead = st.nextToken();
+            }
+            else
+                throw new ParsingException(st.lineno(), expect, st.sval);
+            break;
+        case ',':
+            if (expect.equals(","))
+                lookahead = st.nextToken();
+            else
+                throw new ParsingException(st.lineno(), expect, ",");
+            break;
+        case '{':
+            if (expect.equals("{"))
+                lookahead = st.nextToken();
+            else
+                throw new ParsingException(st.lineno(), expect, "{");
+            break;
+        case '}':
+            if (expect.equals("}"))
+                lookahead = st.nextToken();
+            else
+                throw new ParsingException(st.lineno(), expect, "}");
+            break;
+        case ';':
+            if (expect.equals(";"))
+                lookahead = st.nextToken();
+            else
+                throw new ParsingException(st.lineno(), expect, ";");
+            break;
+        case '*':
+            if (expect.equals("*"))
+                lookahead = st.nextToken();
+            else
+                throw new ParsingException(st.lineno(), expect, "*");
+            break;
+        default:
+            throw new ParsingException(st.lineno(), expect,
+                               new String(new char[] {(char)lookahead}));
+        }
+        return value;
+    }
+
+    CryptoPermission[] getPermissions() {
+        Vector result = new Vector();
+
+        Enumeration grantEnum = grantEntries.elements();
+        while (grantEnum.hasMoreElements()) {
+            GrantEntry ge = (GrantEntry)grantEnum.nextElement();
+            Enumeration permEnum = ge.permissionElements();
+            while (permEnum.hasMoreElements()) {
+                CryptoPermissionEntry pe =
+                    (CryptoPermissionEntry)permEnum.nextElement();
+                if (pe.cryptoPermission.equals(
+                                        "javax.crypto.CryptoAllPermission")) {
+                    result.addElement(CryptoAllPermission.INSTANCE);
+                } else {
+                    if (pe.checkParam) {
+                        result.addElement(new CryptoPermission(
+                                                pe.alg,
+                                                pe.maxKeySize,
+                                                pe.algParamSpec,
+                                                pe.exemptionMechanism));
+                    } else {
+                        result.addElement(new CryptoPermission(
+                                                pe.alg,
+                                                pe.maxKeySize,
+                                                pe.exemptionMechanism));
+                    }
+                }
+            }
+        }
+
+        CryptoPermission[] ret = new CryptoPermission[result.size()];
+        result.copyInto(ret);
+
+        return ret;
+    }
+
+    private boolean isConsistent(String alg,
+                                 String exemptionMechanism,
+                                 Hashtable processedPermissions) {
+        String thisExemptionMechanism =
+            exemptionMechanism == null ? "none" : exemptionMechanism;
+
+        if (processedPermissions == null) {
+            processedPermissions = new Hashtable();
+            Vector exemptionMechanisms = new Vector(1);
+            exemptionMechanisms.addElement(thisExemptionMechanism);
+            processedPermissions.put(alg, exemptionMechanisms);
+            return true;
+        }
+
+        if (processedPermissions.containsKey(CryptoAllPermission.ALG_NAME)) {
+            return false;
+        }
+
+        Vector exemptionMechanisms;
+
+        if (processedPermissions.containsKey(alg)) {
+            exemptionMechanisms = (Vector)processedPermissions.get(alg);
+            if (exemptionMechanisms.contains(thisExemptionMechanism)) {
+                return false;
+            }
+        } else {
+            exemptionMechanisms = new Vector(1);
+        }
+
+        exemptionMechanisms.addElement(thisExemptionMechanism);
+        processedPermissions.put(alg, exemptionMechanisms);
+        return true;
+    }
+
+    /**
+     * Each grant entry in the policy configuration file is  represented by a
+     * GrantEntry object.  <p>
+     *
+     * <p>
+     * For example, the entry
+     * <pre>
+     *      grant {
+     *       permission javax.crypto.CryptoPermission "DES", 56;
+     *      };
+     *
+     * </pre>
+     * is represented internally
+     * <pre>
+     *
+     * pe = new CryptoPermissionEntry("javax.crypto.CryptoPermission",
+     *                           "DES", 56);
+     *
+     * ge = new GrantEntry();
+     *
+     * ge.add(pe);
+     *
+     * </pre>
+     *
+     * @see java.security.Permission
+     * @see javax.crypto.CryptoPermission
+     * @see javax.crypto.CryptoPermissions
+     */
+
+    private static class GrantEntry {
+
+        private Vector permissionEntries;
+
+        GrantEntry() {
+            permissionEntries = new Vector();
+        }
+
+        void add(CryptoPermissionEntry pe)
+        {
+            permissionEntries.addElement(pe);
+        }
+
+        boolean remove(CryptoPermissionEntry pe)
+        {
+            return permissionEntries.removeElement(pe);
+        }
+
+        boolean contains(CryptoPermissionEntry pe)
+        {
+            return permissionEntries.contains(pe);
+        }
+
+        /**
+         * Enumerate all the permission entries in this GrantEntry.
+         */
+        Enumeration permissionElements(){
+            return permissionEntries.elements();
+        }
+
+    }
+
+    /**
+     * Each crypto permission entry in the policy configuration file is
+     * represented by a CryptoPermissionEntry object.  <p>
+     *
+     * <p>
+     * For example, the entry
+     * <pre>
+     *     permission javax.crypto.CryptoPermission "DES", 56;
+     * </pre>
+     * is represented internally
+     * <pre>
+     *
+     * pe = new CryptoPermissionEntry("javax.crypto.cryptoPermission",
+     *                           "DES", 56);
+     * </pre>
+     *
+     * @see java.security.Permissions
+     * @see javax.crypto.CryptoPermission
+     * @see javax.crypto.CryptoAllPermission
+     */
+
+    private static class CryptoPermissionEntry {
+
+        String cryptoPermission;
+        String alg;
+        String exemptionMechanism;
+        int maxKeySize;
+        boolean checkParam;
+        AlgorithmParameterSpec algParamSpec;
+
+        CryptoPermissionEntry() {
+            // Set default values.
+            maxKeySize = 0;
+            alg = null;
+            exemptionMechanism = null;
+            checkParam = false;
+            algParamSpec = null;
+        }
+
+        /**
+         * Calculates a hash code value for the object.  Objects
+         * which are equal will also have the same hashcode.
+         */
+        public int hashCode() {
+            int retval = cryptoPermission.hashCode();
+            if (alg != null) retval ^= alg.hashCode();
+            if (exemptionMechanism != null) {
+                retval ^= exemptionMechanism.hashCode();
+            }
+            retval ^= maxKeySize;
+            if (checkParam) retval ^= 100;
+            if (algParamSpec != null) {
+                retval ^= algParamSpec.hashCode();
+            }
+            return retval;
+        }
+
+        public boolean equals(Object obj) {
+            if (obj == this)
+                return true;
+
+            if (!(obj instanceof CryptoPermissionEntry))
+                return false;
+
+            CryptoPermissionEntry that = (CryptoPermissionEntry) obj;
+
+            if (this.cryptoPermission == null) {
+                if (that.cryptoPermission != null) return false;
+            } else {
+                if (!this.cryptoPermission.equals(
+                                                 that.cryptoPermission))
+                    return false;
+            }
+
+            if (this.alg == null) {
+                if (that.alg != null) return false;
+            } else {
+                if (!this.alg.equalsIgnoreCase(that.alg))
+                    return false;
+            }
+
+            if (!(this.maxKeySize == that.maxKeySize)) return false;
+
+            if (this.checkParam != that.checkParam) return false;
+
+            if (this.algParamSpec == null) {
+                if (that.algParamSpec != null) return false;
+            } else {
+                if (!this.algParamSpec.equals(that.algParamSpec))
+                    return false;
+            }
+
+            // everything matched -- the 2 objects are equal
+            return true;
+        }
+    }
+
+    static final class ParsingException extends GeneralSecurityException {
+
+        private static final long serialVersionUID = 7147241245566588374L;
+
+        /**
+         * Constructs a ParsingException with the specified
+         * detail message.
+         * @param msg the detail message.
+         */
+        ParsingException(String msg) {
+            super(msg);
+        }
+
+        ParsingException(int line, String msg) {
+            super("line " + line + ": " + msg);
+        }
+
+        ParsingException(int line, String expect, String actual) {
+            super("line "+line+": expected '"+expect+"', found '"+actual+"'");
+        }
+    }
+}

Added: openjdk-crypto/trunk/src/main/java/javax/crypto/EncryptedPrivateKeyInfo.java
===================================================================
--- openjdk-crypto/trunk/src/main/java/javax/crypto/EncryptedPrivateKeyInfo.java	                        (rev 0)
+++ openjdk-crypto/trunk/src/main/java/javax/crypto/EncryptedPrivateKeyInfo.java	2010-03-13 04:23:29 UTC (rev 25)
@@ -0,0 +1,448 @@
+/*
+ * Copyright 2001-2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.crypto;
+
+import java.io.*;
+import java.security.*;
+import java.security.spec.*;
+import sun.security.x509.AlgorithmId;
+import sun.security.util.DerValue;
+import sun.security.util.DerInputStream;
+import sun.security.util.DerOutputStream;
+
+/**
+ * This class implements the <code>EncryptedPrivateKeyInfo</code> type
+ * as defined in PKCS #8.
+ * <p>Its ASN.1 definition is as follows:
+ *
+ * <pre>
+ * EncryptedPrivateKeyInfo ::=  SEQUENCE {
+ *     encryptionAlgorithm   AlgorithmIdentifier,
+ *     encryptedData   OCTET STRING }
+ *
+ * AlgorithmIdentifier  ::=  SEQUENCE  {
+ *     algorithm              OBJECT IDENTIFIER,
+ *     parameters             ANY DEFINED BY algorithm OPTIONAL  }
+ * </pre>
+ *
+ * @author Valerie Peng
+ *
+ * @see java.security.spec.PKCS8EncodedKeySpec
+ *
+ * @since 1.4
+ */
+
+public class EncryptedPrivateKeyInfo {
+
+    // the "encryptionAlgorithm" field
+    private AlgorithmId algid;
+
+    // the "encryptedData" field
+    private byte[] encryptedData;
+
+    // the ASN.1 encoded contents of this class
+    private byte[] encoded = null;
+
+    /**
+     * Constructs (i.e., parses) an <code>EncryptedPrivateKeyInfo</code> from
+     * its ASN.1 encoding.
+     * @param encoded the ASN.1 encoding of this object. The contents of
+     * the array are copied to protect against subsequent modification.
+     * @exception NullPointerException if the <code>encoded</code> is null.
+     * @exception IOException if error occurs when parsing the ASN.1 encoding.
+     */
+    public EncryptedPrivateKeyInfo(byte[] encoded)
+        throws IOException {
+        if (encoded == null) {
+            throw new NullPointerException("the encoded parameter " +
+                                           "must be non-null");
+        }
+        this.encoded = (byte[])encoded.clone();
+        DerValue val = new DerValue(this.encoded);
+
+        DerValue[] seq = new DerValue[2];
+
+        seq[0] = val.data.getDerValue();
+        seq[1] = val.data.getDerValue();
+
+        if (val.data.available() != 0) {
+            throw new IOException("overrun, bytes = " + val.data.available());
+        }
+
+        this.algid = AlgorithmId.parse(seq[0]);
+        if (seq[0].data.available() != 0) {
+            throw new IOException("encryptionAlgorithm field overrun");
+        }
+
+        this.encryptedData = seq[1].getOctetString();
+        if (seq[1].data.available() != 0) {
+            throw new IOException("encryptedData field overrun");
+        }
+    }
+
+    /**
+     * Constructs an <code>EncryptedPrivateKeyInfo</code> from the
+     * encryption algorithm name and the encrypted data.
+     *
+     * <p>Note: This constructor will use null as the value of the
+     * algorithm parameters. If the encryption algorithm has
+     * parameters whose value is not null, a different constructor,
+     * e.g. EncryptedPrivateKeyInfo(AlgorithmParameters, byte[]),
+     * should be used.
+     *
+     * @param algName encryption algorithm name. See Appendix A in the
+     * <a href=
+     *   "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     * Java Cryptography Architecture Reference Guide</a>
+     * for information about standard Cipher algorithm names.
+     * @param encryptedData encrypted data. The contents of
+     * <code>encrypedData</code> are copied to protect against subsequent
+     * modification when constructing this object.
+     * @exception NullPointerException if <code>algName</code> or
+     * <code>encryptedData</code> is null.
+     * @exception IllegalArgumentException if <code>encryptedData</code>
+     * is empty, i.e. 0-length.
+     * @exception NoSuchAlgorithmException if the specified algName is
+     * not supported.
+     */
+    public EncryptedPrivateKeyInfo(String algName, byte[] encryptedData)
+        throws NoSuchAlgorithmException {
+
+        if (algName == null)
+                throw new NullPointerException("the algName parameter " +
+                                               "must be non-null");
+        this.algid = AlgorithmId.get(algName);
+
+        if (encryptedData == null) {
+            throw new NullPointerException("the encryptedData " +
+                                           "parameter must be non-null");
+        } else if (encryptedData.length == 0) {
+            throw new IllegalArgumentException("the encryptedData " +
+                                                "parameter must not be empty");
+        } else {
+            this.encryptedData = (byte[])encryptedData.clone();
+        }
+        // delay the generation of ASN.1 encoding until
+        // getEncoded() is called
+        this.encoded = null;
+    }
+
+    /**
+     * Constructs an <code>EncryptedPrivateKeyInfo</code> from the
+     * encryption algorithm parameters and the encrypted data.
+     *
+     * @param algParams the algorithm parameters for the encryption
+     * algorithm. <code>algParams.getEncoded()</code> should return
+     * the ASN.1 encoded bytes of the <code>parameters</code> field
+     * of the <code>AlgorithmIdentifer</code> component of the
+     * <code>EncryptedPrivateKeyInfo</code> type.
+     * @param encryptedData encrypted data. The contents of
+     * <code>encrypedData</code> are copied to protect against
+     * subsequent modification when constructing this object.
+     * @exception NullPointerException if <code>algParams</code> or
+     * <code>encryptedData</code> is null.
+     * @exception IllegalArgumentException if <code>encryptedData</code>
+     * is empty, i.e. 0-length.
+     * @exception NoSuchAlgorithmException if the specified algName of
+     * the specified <code>algParams</code> parameter is not supported.
+     */
+    public EncryptedPrivateKeyInfo(AlgorithmParameters algParams,
+        byte[] encryptedData) throws NoSuchAlgorithmException {
+
+        if (algParams == null) {
+            throw new NullPointerException("algParams must be non-null");
+        }
+        this.algid = AlgorithmId.get(algParams);
+
+        if (encryptedData == null) {
+            throw new NullPointerException("encryptedData must be non-null");
+        } else if (encryptedData.length == 0) {
+            throw new IllegalArgumentException("the encryptedData " +
+                                                "parameter must not be empty");
+        } else {
+            this.encryptedData = (byte[])encryptedData.clone();
+        }
+
+        // delay the generation of ASN.1 encoding until
+        // getEncoded() is called
+        this.encoded = null;
+    }
+
+
+    /**
+     * Returns the encryption algorithm.
+     * <p>Note: Standard name is returned instead of the specified one
+     * in the constructor when such mapping is available.
+     * See Appendix A in the
+     * <a href=
+     *   "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     * Java Cryptography Architecture Reference Guide</a>
+     * for information about standard Cipher algorithm names.
+     *
+     * @return the encryption algorithm name.
+     */
+    public String getAlgName() {
+        return this.algid.getName();
+    }
+
+    /**
+     * Returns the algorithm parameters used by the encryption algorithm.
+     * @return the algorithm parameters.
+     */
+    public AlgorithmParameters getAlgParameters() {
+        return this.algid.getParameters();
+    }
+
+    /**
+     * Returns the encrypted data.
+     * @return the encrypted data. Returns a new array
+     * each time this method is called.
+     */
+    public byte[] getEncryptedData() {
+        return (byte[])this.encryptedData.clone();
+    }
+
+    /**
+     * Extract the enclosed PKCS8EncodedKeySpec object from the
+     * encrypted data and return it.
+     * <br>Note: In order to successfully retrieve the enclosed
+     * PKCS8EncodedKeySpec object, <code>cipher</code> needs
+     * to be initialized to either Cipher.DECRYPT_MODE or
+     * Cipher.UNWRAP_MODE, with the same key and parameters used
+     * for generating the encrypted data.
+     *
+     * @param cipher the initialized cipher object which will be
+     * used for decrypting the encrypted data.
+     * @return the PKCS8EncodedKeySpec object.
+     * @exception NullPointerException if <code>cipher</code>
+     * is null.
+     * @exception InvalidKeySpecException if the given cipher is
+     * inappropriate for the encrypted data or the encrypted
+     * data is corrupted and cannot be decrypted.
+     */
+    public PKCS8EncodedKeySpec getKeySpec(Cipher cipher)
+        throws InvalidKeySpecException {
+        byte[] encoded = null;
+        try {
+            encoded = cipher.doFinal((byte[])encryptedData);
+            checkPKCS8Encoding(encoded);
+        } catch (GeneralSecurityException gse) {
+            InvalidKeySpecException ikse = new
+                InvalidKeySpecException(
+                    "Cannot retrieve the PKCS8EncodedKeySpec");
+            ikse.initCause(gse);
+            throw ikse;
+        } catch (IOException ioe) {
+            InvalidKeySpecException ikse = new
+                InvalidKeySpecException(
+                    "Cannot retrieve the PKCS8EncodedKeySpec");
+            ikse.initCause(ioe);
+            throw ikse;
+        } catch (IllegalStateException ise) {
+            InvalidKeySpecException ikse = new
+                InvalidKeySpecException(
+                    "Cannot retrieve the PKCS8EncodedKeySpec");
+            ikse.initCause(ise);
+            throw ikse;
+        }
+        return new PKCS8EncodedKeySpec(encoded);
+    }
+
+    private PKCS8EncodedKeySpec getKeySpecImpl(Key decryptKey,
+        Provider provider) throws NoSuchAlgorithmException,
+        InvalidKeyException {
+        byte[] encoded = null;
+        Cipher c;
+        try {
+            if (provider == null) {
+                // use the most preferred one
+                c = Cipher.getInstance(algid.getName());
+            } else {
+                c = Cipher.getInstance(algid.getName(), provider);
+            }
+            c.init(Cipher.DECRYPT_MODE, decryptKey, algid.getParameters());
+            encoded = c.doFinal(encryptedData);
+            checkPKCS8Encoding(encoded);
+        } catch (NoSuchAlgorithmException nsae) {
+            // rethrow
+            throw nsae;
+        } catch (GeneralSecurityException gse) {
+            InvalidKeyException ike = new InvalidKeyException
+                ("Cannot retrieve the PKCS8EncodedKeySpec");
+            ike.initCause(gse);
+            throw ike;
+        } catch (IOException ioe) {
+            InvalidKeyException ike = new InvalidKeyException
+                ("Cannot retrieve the PKCS8EncodedKeySpec");
+            ike.initCause(ioe);
+            throw ike;
+        }
+        return new PKCS8EncodedKeySpec(encoded);
+    }
+
+    /**
+     * Extract the enclosed PKCS8EncodedKeySpec object from the
+     * encrypted data and return it.
+     * @param decryptKey key used for decrypting the encrypted data.
+     * @return the PKCS8EncodedKeySpec object.
+     * @exception NullPointerException if <code>decryptKey</code>
+     * is null.
+     * @exception NoSuchAlgorithmException if cannot find appropriate
+     * cipher to decrypt the encrypted data.
+     * @exception InvalidKeyException if <code>decryptKey</code>
+     * cannot be used to decrypt the encrypted data or the decryption
+     * result is not a valid PKCS8KeySpec.
+     *
+     * @since 1.5
+     */
+    public PKCS8EncodedKeySpec getKeySpec(Key decryptKey)
+        throws NoSuchAlgorithmException, InvalidKeyException {
+        if (decryptKey == null) {
+            throw new NullPointerException("decryptKey is null");
+        }
+        return getKeySpecImpl(decryptKey, null);
+    }
+
+    /**
+     * Extract the enclosed PKCS8EncodedKeySpec object from the
+     * encrypted data and return it.
+     * @param decryptKey key used for decrypting the encrypted data.
+     * @param providerName the name of provider whose Cipher
+     * implementation will be used.
+     * @return the PKCS8EncodedKeySpec object.
+     * @exception NullPointerException if <code>decryptKey</code>
+     * or <code>providerName</code> is null.
+     * @exception NoSuchProviderException if no provider
+     * <code>providerName</code> is registered.
+     * @exception NoSuchAlgorithmException if cannot find appropriate
+     * cipher to decrypt the encrypted data.
+     * @exception InvalidKeyException if <code>decryptKey</code>
+     * cannot be used to decrypt the encrypted data or the decryption
+     * result is not a valid PKCS8KeySpec.
+     *
+     * @since 1.5
+     */
+    public PKCS8EncodedKeySpec getKeySpec(Key decryptKey,
+        String providerName) throws NoSuchProviderException,
+        NoSuchAlgorithmException, InvalidKeyException {
+        if (decryptKey == null) {
+            throw new NullPointerException("decryptKey is null");
+        }
+        if (providerName == null) {
+            throw new NullPointerException("provider is null");
+        }
+        Provider provider = Security.getProvider(providerName);
+        if (provider == null) {
+            throw new NoSuchProviderException("provider " +
+                providerName + " not found");
+        }
+        return getKeySpecImpl(decryptKey, provider);
+    }
+
+    /**
+     * Extract the enclosed PKCS8EncodedKeySpec object from the
+     * encrypted data and return it.
+     * @param decryptKey key used for decrypting the encrypted data.
+     * @param provider the name of provider whose Cipher implementation
+     * will be used.
+     * @return the PKCS8EncodedKeySpec object.
+     * @exception NullPointerException if <code>decryptKey</code>
+     * or <code>provider</code> is null.
+     * @exception NoSuchAlgorithmException if cannot find appropriate
+     * cipher to decrypt the encrypted data in <code>provider</code>.
+     * @exception InvalidKeyException if <code>decryptKey</code>
+     * cannot be used to decrypt the encrypted data or the decryption
+     * result is not a valid PKCS8KeySpec.
+     *
+     * @since 1.5
+     */
+    public PKCS8EncodedKeySpec getKeySpec(Key decryptKey,
+        Provider provider) throws NoSuchAlgorithmException,
+        InvalidKeyException {
+        if (decryptKey == null) {
+            throw new NullPointerException("decryptKey is null");
+        }
+        if (provider == null) {
+            throw new NullPointerException("provider is null");
+        }
+        return getKeySpecImpl(decryptKey, provider);
+    }
+
+    /**
+     * Returns the ASN.1 encoding of this object.
+     * @return the ASN.1 encoding. Returns a new array
+     * each time this method is called.
+     * @exception IOException if error occurs when constructing its
+     * ASN.1 encoding.
+     */
+    public byte[] getEncoded() throws IOException {
+        if (this.encoded == null) {
+            DerOutputStream out = new DerOutputStream();
+            DerOutputStream tmp = new DerOutputStream();
+
+            // encode encryption algorithm
+            algid.encode(tmp);
+
+            // encode encrypted data
+            tmp.putOctetString(encryptedData);
+
+            // wrap everything into a SEQUENCE
+            out.write(DerValue.tag_Sequence, tmp);
+            this.encoded = out.toByteArray();
+        }
+        return (byte[])this.encoded.clone();
+    }
+
+    private static void checkTag(DerValue val, byte tag, String valName)
+        throws IOException {
+        if (val.getTag() != tag) {
+            throw new IOException("invalid key encoding - wrong tag for " +
+                                  valName);
+        }
+    }
+
+    private static void checkPKCS8Encoding(byte[] encodedKey)
+        throws IOException {
+        DerInputStream in = new DerInputStream(encodedKey);
+        DerValue[] values = in.getSequence(3);
+
+        switch (values.length) {
+        case 4:
+            checkTag(values[3], DerValue.TAG_CONTEXT, "attributes");
+        case 3:
+            checkTag(values[0], DerValue.tag_Integer, "version");
+            DerInputStream algid = values[1].toDerInputStream();
+            algid.getOID();
+            if (algid.available() != 0) {
+                algid.getDerValue();
+            }
+            checkTag(values[2], DerValue.tag_OctetString, "privateKey");
+            break;
+        default:
+            throw new IOException("invalid key encoding");
+        }
+    }
+}

Added: openjdk-crypto/trunk/src/main/java/javax/crypto/ExemptionMechanism.java
===================================================================
--- openjdk-crypto/trunk/src/main/java/javax/crypto/ExemptionMechanism.java	                        (rev 0)
+++ openjdk-crypto/trunk/src/main/java/javax/crypto/ExemptionMechanism.java	2010-03-13 04:23:29 UTC (rev 25)
@@ -0,0 +1,486 @@
+/*
+ * Copyright 1999-2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.crypto;
+
+import java.security.AlgorithmParameters;
+import java.security.Provider;
+import java.security.Key;
+import java.security.Security;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.InvalidKeyException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.spec.AlgorithmParameterSpec;
+
+import sun.security.jca.GetInstance.Instance;
+
+/**
+ * This class provides the functionality of an exemption mechanism, examples
+ * of which are <i>key recovery</i>, <i>key weakening</i>, and
+ * <i>key escrow</i>.
+ *
+ * <p>Applications or applets that use an exemption mechanism may be granted
+ * stronger encryption capabilities than those which don't.
+ *
+ * @since 1.4
+ */
+
+public class ExemptionMechanism {
+
+    // The provider
+    private Provider provider;
+
+    // The provider implementation (delegate)
+    private ExemptionMechanismSpi exmechSpi;
+
+    // The name of the exemption mechanism.
+    private String mechanism;
+
+    // Flag which indicates whether this ExemptionMechanism
+    // result is generated successfully.
+    private boolean done = false;
+
+    // State information
+    private boolean initialized = false;
+
+    // Store away the key at init() time for later comparison.
+    private Key keyStored = null;
+
+    /**
+     * Creates a ExemptionMechanism object.
+     *
+     * @param exmechSpi the delegate
+     * @param provider the provider
+     * @param mechanism the exemption mechanism
+     */
+    protected ExemptionMechanism(ExemptionMechanismSpi exmechSpi,
+                                 Provider provider,
+                                 String mechanism) {
+        this.exmechSpi = exmechSpi;
+        this.provider = provider;
+        this.mechanism = mechanism;
+    }
+
+    /**
+     * Returns the exemption mechanism name of this
+     * <code>ExemptionMechanism</code> object.
+     *
+     * <p>This is the same name that was specified in one of the
+     * <code>getInstance</code> calls that created this
+     * <code>ExemptionMechanism</code> object.
+     *
+     * @return the exemption mechanism name of this
+     * <code>ExemptionMechanism</code> object.
+     */
+    public final String getName() {
+        return this.mechanism;
+    }
+
+    /**
+     * Returns an <code>ExemptionMechanism</code> object that implements the
+     * specified exemption mechanism algorithm.
+     *
+     * <p> This method traverses the list of registered security Providers,
+     * starting with the most preferred Provider.
+     * A new ExemptionMechanism object encapsulating the
+     * ExemptionMechanismSpi implementation from the first
+     * Provider that supports the specified algorithm is returned.
+     *
+     * <p> Note that the list of registered providers may be retrieved via
+     * the {@link Security#getProviders() Security.getProviders()} method.
+     *
+     * @param algorithm the standard name of the requested exemption
+     * mechanism.
+     * See Appendix A in the
+     * <a href=
+     *   "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     * Java Cryptography Architecture Reference Guide</a>
+     * for information about standard exemption mechanism names.
+     *
+     * @return the new <code>ExemptionMechanism</code> object.
+     *
+     * @exception NullPointerException if <code>algorithm</code>
+     *          is null.
+     *
+     * @exception NoSuchAlgorithmException if no Provider supports an
+     *          ExemptionMechanismSpi implementation for the
+     *          specified algorithm.
+     *
+     * @see java.security.Provider
+     */
+    public static final ExemptionMechanism getInstance(String algorithm)
+            throws NoSuchAlgorithmException {
+        Instance instance = JceSecurity.getInstance("ExemptionMechanism",
+                ExemptionMechanismSpi.class, algorithm);
+        return new ExemptionMechanism((ExemptionMechanismSpi)instance.impl,
+                instance.provider, algorithm);
+    }
+
+
+    /**
+     * Returns an <code>ExemptionMechanism</code> object that implements the
+     * specified exemption mechanism algorithm.
+     *
+     * <p> A new ExemptionMechanism object encapsulating the
+     * ExemptionMechanismSpi implementation from the specified provider
+     * is returned.  The specified provider must be registered
+     * in the security provider list.
+     *
+     * <p> Note that the list of registered providers may be retrieved via
+     * the {@link Security#getProviders() Security.getProviders()} method.
+
+     * @param algorithm the standard name of the requested exemption mechanism.
+     * See Appendix A in the
+     * <a href=
+     *   "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     * Java Cryptography Architecture Reference Guide</a>
+     * for information about standard exemption mechanism names.
+     *
+     * @param provider the name of the provider.
+     *
+     * @return the new <code>ExemptionMechanism</code> object.
+     *
+     * @exception NullPointerException if <code>algorithm</code>
+     *          is null.
+     *
+     * @exception NoSuchAlgorithmException if an ExemptionMechanismSpi
+     *          implementation for the specified algorithm is not
+     *          available from the specified provider.
+     *
+     * @exception NoSuchProviderException if the specified provider is not
+     *          registered in the security provider list.
+     *
+     * @exception IllegalArgumentException if the <code>provider</code>
+     *          is null or empty.
+     *
+     * @see java.security.Provider
+     */
+    public static final ExemptionMechanism getInstance(String algorithm,
+            String provider) throws NoSuchAlgorithmException,
+            NoSuchProviderException {
+        Instance instance = JceSecurity.getInstance("ExemptionMechanism",
+                ExemptionMechanismSpi.class, algorithm, provider);
+        return new ExemptionMechanism((ExemptionMechanismSpi)instance.impl,
+                instance.provider, algorithm);
+    }
+
+    /**
+     * Returns an <code>ExemptionMechanism</code> object that implements the
+     * specified exemption mechanism algorithm.
+     *
+     * <p> A new ExemptionMechanism object encapsulating the
+     * ExemptionMechanismSpi implementation from the specified Provider
+     * object is returned.  Note that the specified Provider object
+     * does not have to be registered in the provider list.
+     *
+     * @param algorithm the standard name of the requested exemption mechanism.
+     * See Appendix A in the
+     * <a href=
+     *   "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     * Java Cryptography Architecture Reference Guide</a>
+     * for information about standard exemption mechanism names.
+     *
+     * @param provider the provider.
+     *
+     * @return the new <code>ExemptionMechanism</code> object.
+     *
+     * @exception NullPointerException if <code>algorithm</code>
+     *          is null.
+     *
+     * @exception NoSuchAlgorithmException if an ExemptionMechanismSpi
+     *          implementation for the specified algorithm is not available
+     *          from the specified Provider object.
+     *
+     * @exception IllegalArgumentException if the <code>provider</code>
+     *          is null.
+     *
+     * @see java.security.Provider
+     */
+    public static final ExemptionMechanism getInstance(String algorithm,
+            Provider provider) throws NoSuchAlgorithmException {
+        Instance instance = JceSecurity.getInstance("ExemptionMechanism",
+                ExemptionMechanismSpi.class, algorithm, provider);
+        return new ExemptionMechanism((ExemptionMechanismSpi)instance.impl,
+                instance.provider, algorithm);
+    }
+
+    /**
+     * Returns the provider of this <code>ExemptionMechanism</code> object.
+     *
+     * @return the provider of this <code>ExemptionMechanism</code> object.
+     */
+    public final Provider getProvider() {
+        return this.provider;
+    }
+
+    /**
+     * Returns whether the result blob has been generated successfully by this
+     * exemption mechanism.
+     *
+     * <p>The method also makes sure that the key passed in is the same as
+     * the one this exemption mechanism used in initializing and generating
+     * phases.
+     *
+     * @param key the key the crypto is going to use.
+     *
+     * @return whether the result blob of the same key has been generated
+     * successfully by this exemption mechanism; false if <code>key</code>
+     * is null.
+     *
+     * @exception ExemptionMechanismException if problem(s) encountered
+     * while determining whether the result blob has been generated successfully
+     * by this exemption mechanism object.
+     */
+    public final boolean isCryptoAllowed(Key key)
+            throws ExemptionMechanismException {
+        boolean ret = false;
+        if (done && (key != null)) {
+            // Check if the key passed in is the same as the one
+            // this exemption mechanism used.
+            ret = keyStored.equals(key);
+        }
+        return ret;
+     }
+
+    /**
+     * Returns the length in bytes that an output buffer would need to be in
+     * order to hold the result of the next
+     * {@link #genExemptionBlob(byte[]) genExemptionBlob}
+     * operation, given the input length <code>inputLen</code> (in bytes).
+     *
+     * <p>The actual output length of the next
+     * {@link #genExemptionBlob(byte[]) genExemptionBlob}
+     * call may be smaller than the length returned by this method.
+     *
+     * @param inputLen the input length (in bytes)
+     *
+     * @return the required output buffer size (in bytes)
+     *
+     * @exception IllegalStateException if this exemption mechanism is in a
+     * wrong state (e.g., has not yet been initialized)
+     */
+    public final int getOutputSize(int inputLen) throws IllegalStateException {
+        if (!initialized) {
+            throw new IllegalStateException(
+                "ExemptionMechanism not initialized");
+        }
+        if (inputLen < 0) {
+            throw new IllegalArgumentException(
+                "Input size must be equal to " + "or greater than zero");
+        }
+        return exmechSpi.engineGetOutputSize(inputLen);
+    }
+
+    /**
+     * Initializes this exemption mechanism with a key.
+     *
+     * <p>If this exemption mechanism requires any algorithm parameters
+     * that cannot be derived from the given <code>key</code>, the
+     * underlying exemption mechanism implementation is supposed to
+     * generate the required parameters itself (using provider-specific
+     * default values); in the case that algorithm parameters must be
+     * specified by the caller, an <code>InvalidKeyException</code> is raised.
+     *
+     * @param key the key for this exemption mechanism
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * this exemption mechanism.
+     * @exception ExemptionMechanismException if problem(s) encountered in the
+     * process of initializing.
+     */
+    public final void init(Key key)
+            throws InvalidKeyException, ExemptionMechanismException {
+        done = false;
+        initialized = false;
+
+        keyStored = key;
+        exmechSpi.engineInit(key);
+        initialized = true;
+    }
+
+    /**
+     * Initializes this exemption mechanism with a key and a set of algorithm
+     * parameters.
+     *
+     * <p>If this exemption mechanism requires any algorithm parameters
+     * and <code>params</code> is null, the underlying exemption
+     * mechanism implementation is supposed to generate the required
+     * parameters itself (using provider-specific default values); in the case
+     * that algorithm parameters must be specified by the caller, an
+     * <code>InvalidAlgorithmParameterException</code> is raised.
+     *
+     * @param key the key for this exemption mechanism
+     * @param params the algorithm parameters
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * this exemption mechanism.
+     * @exception InvalidAlgorithmParameterException if the given algorithm
+     * parameters are inappropriate for this exemption mechanism.
+     * @exception ExemptionMechanismException if problem(s) encountered in the
+     * process of initializing.
+     */
+    public final void init(Key key, AlgorithmParameterSpec params)
+            throws InvalidKeyException, InvalidAlgorithmParameterException,
+            ExemptionMechanismException {
+        done = false;
+        initialized = false;
+
+        keyStored = key;
+        exmechSpi.engineInit(key, params);
+        initialized = true;
+    }
+
+    /**
+     * Initializes this exemption mechanism with a key and a set of algorithm
+     * parameters.
+     *
+     * <p>If this exemption mechanism requires any algorithm parameters
+     * and <code>params</code> is null, the underlying exemption mechanism
+     * implementation is supposed to generate the required parameters itself
+     * (using provider-specific default values); in the case that algorithm
+     * parameters must be specified by the caller, an
+     * <code>InvalidAlgorithmParameterException</code> is raised.
+     *
+     * @param key the key for this exemption mechanism
+     * @param params the algorithm parameters
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * this exemption mechanism.
+     * @exception InvalidAlgorithmParameterException if the given algorithm
+     * parameters are inappropriate for this exemption mechanism.
+     * @exception ExemptionMechanismException if problem(s) encountered in the
+     * process of initializing.
+     */
+    public final void init(Key key, AlgorithmParameters params)
+            throws InvalidKeyException, InvalidAlgorithmParameterException,
+            ExemptionMechanismException {
+        done = false;
+        initialized = false;
+
+        keyStored = key;
+        exmechSpi.engineInit(key, params);
+        initialized = true;
+    }
+
+    /**
+     * Generates the exemption mechanism key blob.
+     *
+     * @return the new buffer with the result key blob.
+     *
+     * @exception IllegalStateException if this exemption mechanism is in
+     * a wrong state (e.g., has not been initialized).
+     * @exception ExemptionMechanismException if problem(s) encountered in the
+     * process of generating.
+     */
+    public final byte[] genExemptionBlob() throws IllegalStateException,
+            ExemptionMechanismException {
+        if (!initialized) {
+            throw new IllegalStateException(
+                "ExemptionMechanism not initialized");
+        }
+        byte[] blob = exmechSpi.engineGenExemptionBlob();
+        done = true;
+        return blob;
+    }
+
+    /**
+     * Generates the exemption mechanism key blob, and stores the result in
+     * the <code>output</code> buffer.
+     *
+     * <p>If the <code>output</code> buffer is too small to hold the result,
+     * a <code>ShortBufferException</code> is thrown. In this case, repeat this
+     * call with a larger output buffer. Use
+     * {@link #getOutputSize(int) getOutputSize} to determine how big
+     * the output buffer should be.
+     *
+     * @param output the buffer for the result
+     *
+     * @return the number of bytes stored in <code>output</code>
+     *
+     * @exception IllegalStateException if this exemption mechanism is in
+     * a wrong state (e.g., has not been initialized).
+     * @exception ShortBufferException if the given output buffer is too small
+     * to hold the result.
+     * @exception ExemptionMechanismException if problem(s) encountered in the
+     * process of generating.
+     */
+    public final int genExemptionBlob(byte[] output)
+            throws IllegalStateException, ShortBufferException,
+            ExemptionMechanismException {
+        if (!initialized) {
+            throw new IllegalStateException
+            ("ExemptionMechanism not initialized");
+        }
+        int n = exmechSpi.engineGenExemptionBlob(output, 0);
+        done = true;
+        return n;
+    }
+
+    /**
+     * Generates the exemption mechanism key blob, and stores the result in
+     * the <code>output</code> buffer, starting at <code>outputOffset</code>
+     * inclusive.
+     *
+     * <p>If the <code>output</code> buffer is too small to hold the result,
+     * a <code>ShortBufferException</code> is thrown. In this case, repeat this
+     * call with a larger output buffer. Use
+     * {@link #getOutputSize(int) getOutputSize} to determine how big
+     * the output buffer should be.
+     *
+     * @param output the buffer for the result
+     * @param outputOffset the offset in <code>output</code> where the result
+     * is stored
+     *
+     * @return the number of bytes stored in <code>output</code>
+     *
+     * @exception IllegalStateException if this exemption mechanism is in
+     * a wrong state (e.g., has not been initialized).
+     * @exception ShortBufferException if the given output buffer is too small
+     * to hold the result.
+     * @exception ExemptionMechanismException if problem(s) encountered in the
+     * process of generating.
+     */
+    public final int genExemptionBlob(byte[] output, int outputOffset)
+            throws IllegalStateException, ShortBufferException,
+            ExemptionMechanismException {
+        if (!initialized) {
+            throw new IllegalStateException
+            ("ExemptionMechanism not initialized");
+        }
+        int n = exmechSpi.engineGenExemptionBlob(output, outputOffset);
+        done = true;
+        return n;
+    }
+
+    /**
+     * Ensures that the key stored away by this ExemptionMechanism
+     * object will be wiped out when there are no more references to it.
+     */
+    protected void finalize() {
+        keyStored = null;
+        // Are there anything else we could do?
+    }
+}

Added: openjdk-crypto/trunk/src/main/java/javax/crypto/ExemptionMechanismException.java
===================================================================
--- openjdk-crypto/trunk/src/main/java/javax/crypto/ExemptionMechanismException.java	                        (rev 0)
+++ openjdk-crypto/trunk/src/main/java/javax/crypto/ExemptionMechanismException.java	2010-03-13 04:23:29 UTC (rev 25)
@@ -0,0 +1,59 @@
+/*
+ * Copyright 1999-2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.crypto;
+
+import java.security.GeneralSecurityException;
+
+/**
+ * This is the generic ExemptionMechanism exception.
+ *
+ * @since 1.4
+ */
+
+public class ExemptionMechanismException extends GeneralSecurityException {
+
+    private static final long serialVersionUID = 1572699429277957109L;
+
+    /**
+     * Constructs a ExemptionMechanismException with no detailed message.
+     * (A detailed message is a String that describes this particular
+     * exception.)
+     */
+    public ExemptionMechanismException() {
+        super();
+    }
+
+    /**
+     * Constructs a ExemptionMechanismException with the specified
+     * detailed message. (A detailed message is a String that describes
+     * this particular exception.)
+     *
+     * @param msg the detailed message.
+     */
+   public ExemptionMechanismException(String msg) {
+       super(msg);
+    }
+}

Added: openjdk-crypto/trunk/src/main/java/javax/crypto/ExemptionMechanismSpi.java
===================================================================
--- openjdk-crypto/trunk/src/main/java/javax/crypto/ExemptionMechanismSpi.java	                        (rev 0)
+++ openjdk-crypto/trunk/src/main/java/javax/crypto/ExemptionMechanismSpi.java	2010-03-13 04:23:29 UTC (rev 25)
@@ -0,0 +1,170 @@
+/*
+ * Copyright 1999-2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.crypto;
+
+import java.security.Key;
+import java.security.AlgorithmParameters;
+import java.security.InvalidKeyException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
+ * for the <code>ExemptionMechanism</code> class.
+ * All the abstract methods in this class must be implemented by each
+ * cryptographic service provider who wishes to supply the implementation
+ * of a particular exemption mechanism.
+ *
+ * @author Sharon Liu
+ *
+ * @since 1.4
+ */
+
+public abstract class ExemptionMechanismSpi {
+
+    /**
+     * Returns the length in bytes that an output buffer would need to be in
+     * order to hold the result of the next
+     * {@link #engineGenExemptionBlob(byte[], int) engineGenExemptionBlob}
+     * operation, given the input length <code>inputLen</code> (in bytes).
+     *
+     * <p>The actual output length of the next
+     * {@link #engineGenExemptionBlob(byte[], int) engineGenExemptionBlob}
+     * call may be smaller than the length returned by this method.
+     *
+     * @param inputLen the input length (in bytes)
+     *
+     * @return the required output buffer size (in bytes)
+     */
+    protected abstract int engineGetOutputSize(int inputLen);
+
+    /**
+     * Initializes this exemption mechanism with a key.
+     *
+     * <p>If this exemption mechanism requires any algorithm parameters
+     * that cannot be derived from the given <code>key</code>, the underlying
+     * exemption mechanism implementation is supposed to generate the required
+     * parameters itself (using provider-specific default values); in the case
+     * that algorithm parameters must be specified by the caller, an
+     * <code>InvalidKeyException</code> is raised.
+     *
+     * @param key the key for this exemption mechanism
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * this exemption mechanism.
+     * @exception ExemptionMechanismException if problem(s) encountered in the
+     * process of initializing.
+     */
+    protected abstract void engineInit(Key key)
+    throws InvalidKeyException, ExemptionMechanismException;
+
+    /**
+     * Initializes this exemption mechanism with a key and a set of algorithm
+     * parameters.
+     *
+     * <p>If this exemption mechanism requires any algorithm parameters and
+     * <code>params</code> is null, the underlying exemption mechanism
+     * implementation is supposed to generate the required parameters
+     * itself (using provider-specific default values); in the case that
+     * algorithm parameters must be specified by the caller, an
+     * <code>InvalidAlgorithmParameterException</code> is raised.
+     *
+     * @param key the key for this exemption mechanism
+     * @param params the algorithm parameters
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * this exemption mechanism.
+     * @exception InvalidAlgorithmParameterException if the given algorithm
+     * parameters are inappropriate for this exemption mechanism.
+     * @exception ExemptionMechanismException if problem(s) encountered in the
+     * process of initializing.
+     */
+    protected abstract void engineInit(Key key, AlgorithmParameterSpec params)
+    throws InvalidKeyException, InvalidAlgorithmParameterException,
+    ExemptionMechanismException;
+
+    /**
+     * Initializes this exemption mechanism with a key and a set of algorithm
+     * parameters.
+     *
+     * <p>If this exemption mechanism requires any algorithm parameters
+     * and <code>params</code> is null, the underlying exemption mechanism
+     * implementation is supposed to generate the required parameters
+     * itself (using provider-specific default values); in the case that
+     * algorithm parameters must be specified by the caller, an
+     * <code>InvalidAlgorithmParameterException</code> is raised.
+     *
+     * @param key the key for this exemption mechanism
+     * @param params the algorithm parameters
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * this exemption mechanism.
+     * @exception InvalidAlgorithmParameterException if the given algorithm
+     * parameters are inappropriate for this exemption mechanism.
+     * @exception ExemptionMechanismException if problem(s) encountered in the
+     * process of initializing.
+     */
+    protected abstract void engineInit(Key key, AlgorithmParameters params)
+    throws InvalidKeyException, InvalidAlgorithmParameterException,
+    ExemptionMechanismException;
+
+    /**
+     * Generates the exemption mechanism key blob.
+     *
+     * @return the new buffer with the result key blob.
+     *
+     * @exception ExemptionMechanismException if problem(s) encountered in the
+     * process of generating.
+     */
+    protected abstract byte[] engineGenExemptionBlob()
+        throws ExemptionMechanismException;
+
+    /**
+     * Generates the exemption mechanism key blob, and stores the result in
+     * the <code>output</code> buffer, starting at <code>outputOffset</code>
+     * inclusive.
+     *
+     * <p>If the <code>output</code> buffer is too small to hold the result,
+     * a <code>ShortBufferException</code> is thrown. In this case, repeat this
+     * call with a larger output buffer. Use
+     * {@link #engineGetOutputSize(int) engineGetOutputSize} to determine
+     * how big the output buffer should be.
+     *
+     * @param output the buffer for the result
+     * @param outputOffset the offset in <code>output</code> where the result
+     * is stored
+     *
+     * @return the number of bytes stored in <code>output</code>
+     *
+     * @exception ShortBufferException if the given output buffer is too small
+     * to hold the result.
+     * @exception ExemptionMechanismException if problem(s) encountered in the
+     * process of generating.
+     */
+    protected abstract int engineGenExemptionBlob
+    (byte[] output, int outputOffset)
+        throws ShortBufferException, ExemptionMechanismException;
+}

Added: openjdk-crypto/trunk/src/main/java/javax/crypto/IllegalBlockSizeException.java
===================================================================
--- openjdk-crypto/trunk/src/main/java/javax/crypto/IllegalBlockSizeException.java	                        (rev 0)
+++ openjdk-crypto/trunk/src/main/java/javax/crypto/IllegalBlockSizeException.java	2010-03-13 04:23:29 UTC (rev 25)
@@ -0,0 +1,60 @@
+/*
+ * Copyright 1997-2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.crypto;
+
+/**
+ * This exception is thrown when the length of data provided to a block
+ * cipher is incorrect, i.e., does not match the block size of the cipher.
+ *
+ * @author Jan Luehe
+ *
+ * @since 1.4
+ */
+
+public class IllegalBlockSizeException
+    extends java.security.GeneralSecurityException {
+
+    private static final long serialVersionUID = -1965144811953540392L;
+
+    /**
+     * Constructs an IllegalBlockSizeException with no detail message.
+     * A detail message is a String that describes this particular
+     * exception.
+     */
+    public IllegalBlockSizeException() {
+        super();
+    }
+
+    /**
+     * Constructs an IllegalBlockSizeException with the specified
+     * detail message.
+     *
+     * @param msg the detail message.
+     */
+    public IllegalBlockSizeException(String msg) {
+        super(msg);
+    }
+}

Added: openjdk-crypto/trunk/src/main/java/javax/crypto/JceSecurity.java
===================================================================
--- openjdk-crypto/trunk/src/main/java/javax/crypto/JceSecurity.java	                        (rev 0)
+++ openjdk-crypto/trunk/src/main/java/javax/crypto/JceSecurity.java	2010-03-13 04:23:29 UTC (rev 25)
@@ -0,0 +1,92 @@
+/*
+ * Copyright 1997-2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.crypto;
+
+import java.util.*;
+import java.security.*;
+
+import java.security.Provider.Service;
+
+import sun.security.jca.*;
+import sun.security.jca.GetInstance.Instance;
+
+/**
+ * This class instantiates implementations of JCE engine classes from
+ * providers registered with the java.security.Security object.
+ *
+ * @author Jan Luehe
+ * @author Sharon Liu
+ * @since 1.4
+ */
+
+final class JceSecurity {
+
+    // Used in KeyGenerator, Cipher and KeyAgreement.
+    static final SecureRandom RANDOM = new SecureRandom();
+
+    /*
+     * Don't let anyone instantiate this.
+     */
+    private JceSecurity() {
+    }
+
+    static Instance getInstance(String type, Class clazz, String algorithm,
+            String provider) throws NoSuchAlgorithmException,
+            NoSuchProviderException {
+        Service s = GetInstance.getService(type, algorithm, provider);
+        return GetInstance.getInstance(s, clazz);
+    }
+
+    static Instance getInstance(String type, Class clazz, String algorithm,
+            Provider provider) throws NoSuchAlgorithmException {
+        Service s = GetInstance.getService(type, algorithm, provider);
+        return GetInstance.getInstance(s, clazz);
+    }
+
+    static Instance getInstance(String type, Class clazz, String algorithm)
+            throws NoSuchAlgorithmException {
+        List services = GetInstance.getServices(type, algorithm);
+        NoSuchAlgorithmException failure = null;
+        for (Iterator t = services.iterator(); t.hasNext(); ) {
+            Service s = (Service)t.next();
+            try {
+                Instance instance = GetInstance.getInstance(s, clazz);
+                return instance;
+            } catch (NoSuchAlgorithmException e) {
+                failure = e;
+            }
+        }
+        throw new NoSuchAlgorithmException("Algorithm " + algorithm
+                + " not available", failure);
+    }
+
+    // Used to return whether this provider is properly signed and
+    // can be used by JCE. These days just returns true. Still used
+    // in SecretKeyFactory, KeyGenerator, Mac and KeyAgreement.
+    static boolean canUseProvider(Provider p) {
+        return true;
+    }
+}

Added: openjdk-crypto/trunk/src/main/java/javax/crypto/KeyAgreement.java
===================================================================
--- openjdk-crypto/trunk/src/main/java/javax/crypto/KeyAgreement.java	                        (rev 0)
+++ openjdk-crypto/trunk/src/main/java/javax/crypto/KeyAgreement.java	2010-03-13 04:23:29 UTC (rev 25)
@@ -0,0 +1,625 @@
+/*
+ * Copyright 1997-2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.crypto;
+
+import java.util.*;
+
+import java.security.*;
+import java.security.Provider.Service;
+import java.security.spec.*;
+
+import sun.security.util.Debug;
+import sun.security.jca.*;
+import sun.security.jca.GetInstance.Instance;
+
+/**
+ * This class provides the functionality of a key agreement (or key
+ * exchange) protocol.
+ * <p>
+ * The keys involved in establishing a shared secret are created by one of the
+ * key generators (<code>KeyPairGenerator</code> or
+ * <code>KeyGenerator</code>), a <code>KeyFactory</code>, or as a result from
+ * an intermediate phase of the key agreement protocol.
+ *
+ * <p> For each of the correspondents in the key exchange, <code>doPhase</code>
+ * needs to be called. For example, if this key exchange is with one other
+ * party, <code>doPhase</code> needs to be called once, with the
+ * <code>lastPhase</code> flag set to <code>true</code>.
+ * If this key exchange is
+ * with two other parties, <code>doPhase</code> needs to be called twice,
+ * the first time setting the <code>lastPhase</code> flag to
+ * <code>false</code>, and the second time setting it to <code>true</code>.
+ * There may be any number of parties involved in a key exchange.
+ *
+ * @author Jan Luehe
+ *
+ * @see KeyGenerator
+ * @see SecretKey
+ * @since 1.4
+ */
+
+public class KeyAgreement {
+
+    private static final Debug debug =
+                        Debug.getInstance("jca", "KeyAgreement");
+
+    // The provider
+    private Provider provider;
+
+    // The provider implementation (delegate)
+    private KeyAgreementSpi spi;
+
+    // The name of the key agreement algorithm.
+    private final String algorithm;
+
+    // next service to try in provider selection
+    // null once provider is selected
+    private Service firstService;
+
+    // remaining services to try in provider selection
+    // null once provider is selected
+    private Iterator serviceIterator;
+
+    private final Object lock;
+
+    /**
+     * Creates a KeyAgreement object.
+     *
+     * @param keyAgreeSpi the delegate
+     * @param provider the provider
+     * @param algorithm the algorithm
+     */
+    protected KeyAgreement(KeyAgreementSpi keyAgreeSpi, Provider provider,
+                           String algorithm) {
+        this.spi = keyAgreeSpi;
+        this.provider = provider;
+        this.algorithm = algorithm;
+        lock = null;
+    }
+
+    private KeyAgreement(Service s, Iterator t, String algorithm) {
+        firstService = s;
+        serviceIterator = t;
+        this.algorithm = algorithm;
+        lock = new Object();
+    }
+
+    /**
+     * Returns the algorithm name of this <code>KeyAgreement</code> object.
+     *
+     * <p>This is the same name that was specified in one of the
+     * <code>getInstance</code> calls that created this
+     * <code>KeyAgreement</code> object.
+     *
+     * @return the algorithm name of this <code>KeyAgreement</code> object.
+     */
+    public final String getAlgorithm() {
+        return this.algorithm;
+    }
+
+    /**
+     * Returns a <code>KeyAgreement</code> object that implements the
+     * specified key agreement algorithm.
+     *
+     * <p> This method traverses the list of registered security Providers,
+     * starting with the most preferred Provider.
+     * A new KeyAgreement object encapsulating the
+     * KeyAgreementSpi implementation from the first
+     * Provider that supports the specified algorithm is returned.
+     *
+     * <p> Note that the list of registered providers may be retrieved via
+     * the {@link Security#getProviders() Security.getProviders()} method.
+     *
+     * @param algorithm the standard name of the requested key agreement
+     * algorithm.
+     * See Appendix A in the
+     * <a href=
+     *   "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     * Java Cryptography Architecture Reference Guide</a>
+     * for information about standard algorithm names.
+     *
+     * @return the new <code>KeyAgreement</code> object.
+     *
+     * @exception NullPointerException if the specified algorithm
+     *          is null.
+     *
+     * @exception NoSuchAlgorithmException if no Provider supports a
+     *          KeyAgreementSpi implementation for the
+     *          specified algorithm.
+     *
+     * @see java.security.Provider
+     */
+    public static final KeyAgreement getInstance(String algorithm)
+            throws NoSuchAlgorithmException {
+        List services = GetInstance.getServices("KeyAgreement", algorithm);
+        // make sure there is at least one service from a signed provider
+        Iterator t = services.iterator();
+        while (t.hasNext()) {
+            Service s = (Service)t.next();
+            if (JceSecurity.canUseProvider(s.getProvider()) == false) {
+                continue;
+            }
+            return new KeyAgreement(s, t, algorithm);
+        }
+        throw new NoSuchAlgorithmException
+                                ("Algorithm " + algorithm + " not available");
+    }
+
+    /**
+     * Returns a <code>KeyAgreement</code> object that implements the
+     * specified key agreement algorithm.
+     *
+     * <p> A new KeyAgreement object encapsulating the
+     * KeyAgreementSpi implementation from the specified provider
+     * is returned.  The specified provider must be registered
+     * in the security provider list.
+     *
+     * <p> Note that the list of registered providers may be retrieved via
+     * the {@link Security#getProviders() Security.getProviders()} method.
+     *
+     * @param algorithm the standard name of the requested key agreement
+     * algorithm.
+     * See Appendix A in the
+     * <a href=
+     *   "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     * Java Cryptography Architecture Reference Guide</a>
+     * for information about standard algorithm names.
+     *
+     * @param provider the name of the provider.
+     *
+     * @return the new <code>KeyAgreement</code> object.
+     *
+     * @exception NullPointerException if the specified algorithm
+     *          is null.
+     *
+     * @exception NoSuchAlgorithmException if a KeyAgreementSpi
+     *          implementation for the specified algorithm is not
+     *          available from the specified provider.
+     *
+     * @exception NoSuchProviderException if the specified provider is not
+     *          registered in the security provider list.
+     *
+     * @exception IllegalArgumentException if the <code>provider</code>
+     *          is null or empty.
+     *
+     * @see java.security.Provider
+     */
+    public static final KeyAgreement getInstance(String algorithm,
+            String provider) throws NoSuchAlgorithmException,
+            NoSuchProviderException {
+        Instance instance = JceSecurity.getInstance
+                ("KeyAgreement", KeyAgreementSpi.class, algorithm, provider);
+        return new KeyAgreement((KeyAgreementSpi)instance.impl,
+                instance.provider, algorithm);
+    }
+
+    /**
+     * Returns a <code>KeyAgreement</code> object that implements the
+     * specified key agreement algorithm.
+     *
+     * <p> A new KeyAgreement object encapsulating the
+     * KeyAgreementSpi implementation from the specified Provider
+     * object is returned.  Note that the specified Provider object
+     * does not have to be registered in the provider list.
+     *
+     * @param algorithm the standard name of the requested key agreement
+     * algorithm.
+     * See Appendix A in the
+     * <a href=
+     *   "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     * Java Cryptography Architecture Reference Guide</a>
+     * for information about standard algorithm names.
+     *
+     * @param provider the provider.
+     *
+     * @return the new <code>KeyAgreement</code> object.
+     *
+     * @exception NullPointerException if the specified algorithm
+     *          is null.
+     *
+     * @exception NoSuchAlgorithmException if a KeyAgreementSpi
+     *          implementation for the specified algorithm is not available
+     *          from the specified Provider object.
+     *
+     * @exception IllegalArgumentException if the <code>provider</code>
+     *          is null.
+     *
+     * @see java.security.Provider
+     */
+    public static final KeyAgreement getInstance(String algorithm,
+            Provider provider) throws NoSuchAlgorithmException {
+        Instance instance = JceSecurity.getInstance
+                ("KeyAgreement", KeyAgreementSpi.class, algorithm, provider);
+        return new KeyAgreement((KeyAgreementSpi)instance.impl,
+                instance.provider, algorithm);
+    }
+
+    // max number of debug warnings to print from chooseFirstProvider()
+    private static int warnCount = 10;
+
+    /**
+     * Choose the Spi from the first provider available. Used if
+     * delayed provider selection is not possible because init()
+     * is not the first method called.
+     */
+    void chooseFirstProvider() {
+        if (spi != null) {
+            return;
+        }
+        synchronized (lock) {
+            if (spi != null) {
+                return;
+            }
+            if (debug != null) {
+                int w = --warnCount;
+                if (w >= 0) {
+                    debug.println("KeyAgreement.init() not first method "
+                        + "called, disabling delayed provider selection");
+                    if (w == 0) {
+                        debug.println("Further warnings of this type will "
+                            + "be suppressed");
+                    }
+                    new Exception("Call trace").printStackTrace();
+                }
+            }
+            Exception lastException = null;
+            while ((firstService != null) || serviceIterator.hasNext()) {
+                Service s;
+                if (firstService != null) {
+                    s = firstService;
+                    firstService = null;
+                } else {
+                    s = (Service)serviceIterator.next();
+                }
+                if (JceSecurity.canUseProvider(s.getProvider()) == false) {
+                    continue;
+                }
+                try {
+                    Object obj = s.newInstance(null);
+                    if (obj instanceof KeyAgreementSpi == false) {
+                        continue;
+                    }
+                    spi = (KeyAgreementSpi)obj;
+                    provider = s.getProvider();
+                    // not needed any more
+                    firstService = null;
+                    serviceIterator = null;
+                    return;
+                } catch (Exception e) {
+                    lastException = e;
+                }
+            }
+            ProviderException e = new ProviderException
+                    ("Could not construct KeyAgreementSpi instance");
+            if (lastException != null) {
+                e.initCause(lastException);
+            }
+            throw e;
+        }
+    }
+
+    private final static int I_NO_PARAMS = 1;
+    private final static int I_PARAMS    = 2;
+
+    private void implInit(KeyAgreementSpi spi, int type, Key key,
+            AlgorithmParameterSpec params, SecureRandom random)
+            throws InvalidKeyException, InvalidAlgorithmParameterException {
+        if (type == I_NO_PARAMS) {
+            spi.engineInit(key, random);
+        } else { // I_PARAMS
+            spi.engineInit(key, params, random);
+        }
+    }
+
+    private void chooseProvider(int initType, Key key,
+            AlgorithmParameterSpec params, SecureRandom random)
+            throws InvalidKeyException, InvalidAlgorithmParameterException {
+        synchronized (lock) {
+            if (spi != null) {
+                implInit(spi, initType, key, params, random);
+                return;
+            }
+            Exception lastException = null;
+            while ((firstService != null) || serviceIterator.hasNext()) {
+                Service s;
+                if (firstService != null) {
+                    s = firstService;
+                    firstService = null;
+                } else {
+                    s = (Service)serviceIterator.next();
+                }
+                // if provider says it does not support this key, ignore it
+                if (s.supportsParameter(key) == false) {
+                    continue;
+                }
+                if (JceSecurity.canUseProvider(s.getProvider()) == false) {
+                    continue;
+                }
+                try {
+                    KeyAgreementSpi spi = (KeyAgreementSpi)s.newInstance(null);
+                    implInit(spi, initType, key, params, random);
+                    provider = s.getProvider();
+                    this.spi = spi;
+                    firstService = null;
+                    serviceIterator = null;
+                    return;
+                } catch (Exception e) {
+                    // NoSuchAlgorithmException from newInstance()
+                    // InvalidKeyException from init()
+                    // RuntimeException (ProviderException) from init()
+                    if (lastException == null) {
+                        lastException = e;
+                    }
+                }
+            }
+            // no working provider found, fail
+            if (lastException instanceof InvalidKeyException) {
+                throw (InvalidKeyException)lastException;
+            }
+            if (lastException instanceof InvalidAlgorithmParameterException) {
+                throw (InvalidAlgorithmParameterException)lastException;
+            }
+            if (lastException instanceof RuntimeException) {
+                throw (RuntimeException)lastException;
+            }
+            String kName = (key != null) ? key.getClass().getName() : "(null)";
+            throw new InvalidKeyException
+                ("No installed provider supports this key: "
+                + kName, lastException);
+        }
+    }
+
+    /**
+     * Returns the provider of this <code>KeyAgreement</code> object.
+     *
+     * @return the provider of this <code>KeyAgreement</code> object
+     */
+    public final Provider getProvider() {
+        chooseFirstProvider();
+        return this.provider;
+    }
+
+    /**
+     * Initializes this key agreement with the given key, which is required to
+     * contain all the algorithm parameters required for this key agreement.
+     *
+     * <p> If this key agreement requires any random bytes, it will get
+     * them using the
+     * {@link SecureRandom <code>SecureRandom</code>}
+     * implementation of the highest-priority
+     * installed provider as the source of randomness.
+     * (If none of the installed providers supply an implementation of
+     * SecureRandom, a system-provided source of randomness will be used.)
+     *
+     * @param key the party's private information. For example, in the case
+     * of the Diffie-Hellman key agreement, this would be the party's own
+     * Diffie-Hellman private key.
+     *
+     * @exception InvalidKeyException if the given key is
+     * inappropriate for this key agreement, e.g., is of the wrong type or
+     * has an incompatible algorithm type.
+     */
+    public final void init(Key key) throws InvalidKeyException {
+        init(key, JceSecurity.RANDOM);
+    }
+
+    /**
+     * Initializes this key agreement with the given key and source of
+     * randomness. The given key is required to contain all the algorithm
+     * parameters required for this key agreement.
+     *
+     * <p> If the key agreement algorithm requires random bytes, it gets them
+     * from the given source of randomness, <code>random</code>.
+     * However, if the underlying
+     * algorithm implementation does not require any random bytes,
+     * <code>random</code> is ignored.
+     *
+     * @param key the party's private information. For example, in the case
+     * of the Diffie-Hellman key agreement, this would be the party's own
+     * Diffie-Hellman private key.
+     * @param random the source of randomness
+     *
+     * @exception InvalidKeyException if the given key is
+     * inappropriate for this key agreement, e.g., is of the wrong type or
+     * has an incompatible algorithm type.
+     */
+    public final void init(Key key, SecureRandom random)
+            throws InvalidKeyException {
+        if (spi != null) {
+            spi.engineInit(key, random);
+        } else {
+            try {
+                chooseProvider(I_NO_PARAMS, key, null, random);
+            } catch (InvalidAlgorithmParameterException e) {
+                // should never occur
+                throw new InvalidKeyException(e);
+            }
+        }
+    }
+
+    /**
+     * Initializes this key agreement with the given key and set of
+     * algorithm parameters.
+     *
+     * <p> If this key agreement requires any random bytes, it will get
+     * them using the
+     * {@link SecureRandom <code>SecureRandom</code>}
+     * implementation of the highest-priority
+     * installed provider as the source of randomness.
+     * (If none of the installed providers supply an implementation of
+     * SecureRandom, a system-provided source of randomness will be used.)
+     *
+     * @param key the party's private information. For example, in the case
+     * of the Diffie-Hellman key agreement, this would be the party's own
+     * Diffie-Hellman private key.
+     * @param params the key agreement parameters
+     *
+     * @exception InvalidKeyException if the given key is
+     * inappropriate for this key agreement, e.g., is of the wrong type or
+     * has an incompatible algorithm type.
+     * @exception InvalidAlgorithmParameterException if the given parameters
+     * are inappropriate for this key agreement.
+     */
+    public final void init(Key key, AlgorithmParameterSpec params)
+        throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        init(key, params, JceSecurity.RANDOM);
+    }
+
+    /**
+     * Initializes this key agreement with the given key, set of
+     * algorithm parameters, and source of randomness.
+     *
+     * @param key the party's private information. For example, in the case
+     * of the Diffie-Hellman key agreement, this would be the party's own
+     * Diffie-Hellman private key.
+     * @param params the key agreement parameters
+     * @param random the source of randomness
+     *
+     * @exception InvalidKeyException if the given key is
+     * inappropriate for this key agreement, e.g., is of the wrong type or
+     * has an incompatible algorithm type.
+     * @exception InvalidAlgorithmParameterException if the given parameters
+     * are inappropriate for this key agreement.
+     */
+    public final void init(Key key, AlgorithmParameterSpec params,
+                           SecureRandom random)
+        throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        if (spi != null) {
+            spi.engineInit(key, params, random);
+        } else {
+            chooseProvider(I_PARAMS, key, params, random);
+        }
+    }
+
+    /**
+     * Executes the next phase of this key agreement with the given
+     * key that was received from one of the other parties involved in this key
+     * agreement.
+     *
+     * @param key the key for this phase. For example, in the case of
+     * Diffie-Hellman between 2 parties, this would be the other party's
+     * Diffie-Hellman public key.
+     * @param lastPhase flag which indicates whether or not this is the last
+     * phase of this key agreement.
+     *
+     * @return the (intermediate) key resulting from this phase, or null
+     * if this phase does not yield a key
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * this phase.
+     * @exception IllegalStateException if this key agreement has not been
+     * initialized.
+     */
+    public final Key doPhase(Key key, boolean lastPhase)
+        throws InvalidKeyException, IllegalStateException
+    {
+        chooseFirstProvider();
+        return spi.engineDoPhase(key, lastPhase);
+    }
+
+    /**
+     * Generates the shared secret and returns it in a new buffer.
+     *
+     * <p>This method resets this <code>KeyAgreement</code> object, so that it
+     * can be reused for further key agreements. Unless this key agreement is
+     * reinitialized with one of the <code>init</code> methods, the same
+     * private information and algorithm parameters will be used for
+     * subsequent key agreements.
+     *
+     * @return the new buffer with the shared secret
+     *
+     * @exception IllegalStateException if this key agreement has not been
+     * completed yet
+     */
+    public final byte[] generateSecret() throws IllegalStateException {
+        chooseFirstProvider();
+        return spi.engineGenerateSecret();
+    }
+
+    /**
+     * Generates the shared secret, and places it into the buffer
+     * <code>sharedSecret</code>, beginning at <code>offset</code> inclusive.
+     *
+     * <p>If the <code>sharedSecret</code> buffer is too small to hold the
+     * result, a <code>ShortBufferException</code> is thrown.
+     * In this case, this call should be repeated with a larger output buffer.
+     *
+     * <p>This method resets this <code>KeyAgreement</code> object, so that it
+     * can be reused for further key agreements. Unless this key agreement is
+     * reinitialized with one of the <code>init</code> methods, the same
+     * private information and algorithm parameters will be used for
+     * subsequent key agreements.
+     *
+     * @param sharedSecret the buffer for the shared secret
+     * @param offset the offset in <code>sharedSecret</code> where the
+     * shared secret will be stored
+     *
+     * @return the number of bytes placed into <code>sharedSecret</code>
+     *
+     * @exception IllegalStateException if this key agreement has not been
+     * completed yet
+     * @exception ShortBufferException if the given output buffer is too small
+     * to hold the secret
+     */
+    public final int generateSecret(byte[] sharedSecret, int offset)
+        throws IllegalStateException, ShortBufferException
+    {
+        chooseFirstProvider();
+        return spi.engineGenerateSecret(sharedSecret, offset);
+    }
+
+    /**
+     * Creates the shared secret and returns it as a <code>SecretKey</code>
+     * object of the specified algorithm.
+     *
+     * <p>This method resets this <code>KeyAgreement</code> object, so that it
+     * can be reused for further key agreements. Unless this key agreement is
+     * reinitialized with one of the <code>init</code> methods, the same
+     * private information and algorithm parameters will be used for
+     * subsequent key agreements.
+     *
+     * @param algorithm the requested secret-key algorithm
+     *
+     * @return the shared secret key
+     *
+     * @exception IllegalStateException if this key agreement has not been
+     * completed yet
+     * @exception NoSuchAlgorithmException if the specified secret-key
+     * algorithm is not available
+     * @exception InvalidKeyException if the shared secret-key material cannot
+     * be used to generate a secret key of the specified algorithm (e.g.,
+     * the key material is too short)
+     */
+    public final SecretKey generateSecret(String algorithm)
+        throws IllegalStateException, NoSuchAlgorithmException,
+            InvalidKeyException
+    {
+        chooseFirstProvider();
+        return spi.engineGenerateSecret(algorithm);
+    }
+}

Added: openjdk-crypto/trunk/src/main/java/javax/crypto/KeyAgreementSpi.java
===================================================================
--- openjdk-crypto/trunk/src/main/java/javax/crypto/KeyAgreementSpi.java	                        (rev 0)
+++ openjdk-crypto/trunk/src/main/java/javax/crypto/KeyAgreementSpi.java	2010-03-13 04:23:29 UTC (rev 25)
@@ -0,0 +1,204 @@
+/*
+ * Copyright 1997-2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.crypto;
+
+import java.security.*;
+import java.security.spec.*;
+
+/**
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
+ * for the <code>KeyAgreement</code> class.
+ * All the abstract methods in this class must be implemented by each
+ * cryptographic service provider who wishes to supply the implementation
+ * of a particular key agreement algorithm.
+ *
+ * <p> The keys involved in establishing a shared secret are created by one
+ * of the
+ * key generators (<code>KeyPairGenerator</code> or
+ * <code>KeyGenerator</code>), a <code>KeyFactory</code>, or as a result from
+ * an intermediate phase of the key agreement protocol
+ * ({@link #engineDoPhase(java.security.Key, boolean) engineDoPhase}).
+ *
+ * <p> For each of the correspondents in the key exchange,
+ * <code>engineDoPhase</code>
+ * needs to be called. For example, if the key exchange is with one other
+ * party, <code>engineDoPhase</code> needs to be called once, with the
+ * <code>lastPhase</code> flag set to <code>true</code>.
+ * If the key exchange is
+ * with two other parties, <code>engineDoPhase</code> needs to be called twice,
+ * the first time setting the <code>lastPhase</code> flag to
+ * <code>false</code>, and the second time setting it to <code>true</code>.
+ * There may be any number of parties involved in a key exchange.
+ *
+ * @author Jan Luehe
+ *
+ * @see KeyGenerator
+ * @see SecretKey
+ * @since 1.4
+ */
+
+public abstract class KeyAgreementSpi {
+
+    /**
+     * Initializes this key agreement with the given key and source of
+     * randomness. The given key is required to contain all the algorithm
+     * parameters required for this key agreement.
+     *
+     * <p> If the key agreement algorithm requires random bytes, it gets them
+     * from the given source of randomness, <code>random</code>.
+     * However, if the underlying
+     * algorithm implementation does not require any random bytes,
+     * <code>random</code> is ignored.
+     *
+     * @param key the party's private information. For example, in the case
+     * of the Diffie-Hellman key agreement, this would be the party's own
+     * Diffie-Hellman private key.
+     * @param random the source of randomness
+     *
+     * @exception InvalidKeyException if the given key is
+     * inappropriate for this key agreement, e.g., is of the wrong type or
+     * has an incompatible algorithm type.
+     */
+    protected abstract void engineInit(Key key, SecureRandom random)
+        throws InvalidKeyException;
+
+    /**
+     * Initializes this key agreement with the given key, set of
+     * algorithm parameters, and source of randomness.
+     *
+     * @param key the party's private information. For example, in the case
+     * of the Diffie-Hellman key agreement, this would be the party's own
+     * Diffie-Hellman private key.
+     * @param params the key agreement parameters
+     * @param random the source of randomness
+     *
+     * @exception InvalidKeyException if the given key is
+     * inappropriate for this key agreement, e.g., is of the wrong type or
+     * has an incompatible algorithm type.
+     * @exception InvalidAlgorithmParameterException if the given parameters
+     * are inappropriate for this key agreement.
+     */
+    protected abstract void engineInit(Key key, AlgorithmParameterSpec params,
+                                       SecureRandom random)
+        throws InvalidKeyException, InvalidAlgorithmParameterException;
+
+    /**
+     * Executes the next phase of this key agreement with the given
+     * key that was received from one of the other parties involved in this key
+     * agreement.
+     *
+     * @param key the key for this phase. For example, in the case of
+     * Diffie-Hellman between 2 parties, this would be the other party's
+     * Diffie-Hellman public key.
+     * @param lastPhase flag which indicates whether or not this is the last
+     * phase of this key agreement.
+     *
+     * @return the (intermediate) key resulting from this phase, or null if
+     * this phase does not yield a key
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * this phase.
+     * @exception IllegalStateException if this key agreement has not been
+     * initialized.
+     */
+    protected abstract Key engineDoPhase(Key key, boolean lastPhase)
+        throws InvalidKeyException, IllegalStateException;
+
+    /**
+     * Generates the shared secret and returns it in a new buffer.
+     *
+     * <p>This method resets this <code>KeyAgreementSpi</code> object,
+     * so that it
+     * can be reused for further key agreements. Unless this key agreement is
+     * reinitialized with one of the <code>engineInit</code> methods, the same
+     * private information and algorithm parameters will be used for
+     * subsequent key agreements.
+     *
+     * @return the new buffer with the shared secret
+     *
+     * @exception IllegalStateException if this key agreement has not been
+     * completed yet
+     */
+    protected abstract byte[] engineGenerateSecret()
+        throws IllegalStateException;
+
+    /**
+     * Generates the shared secret, and places it into the buffer
+     * <code>sharedSecret</code>, beginning at <code>offset</code> inclusive.
+     *
+     * <p>If the <code>sharedSecret</code> buffer is too small to hold the
+     * result, a <code>ShortBufferException</code> is thrown.
+     * In this case, this call should be repeated with a larger output buffer.
+     *
+     * <p>This method resets this <code>KeyAgreementSpi</code> object,
+     * so that it
+     * can be reused for further key agreements. Unless this key agreement is
+     * reinitialized with one of the <code>engineInit</code> methods, the same
+     * private information and algorithm parameters will be used for
+     * subsequent key agreements.
+     *
+     * @param sharedSecret the buffer for the shared secret
+     * @param offset the offset in <code>sharedSecret</code> where the
+     * shared secret will be stored
+     *
+     * @return the number of bytes placed into <code>sharedSecret</code>
+     *
+     * @exception IllegalStateException if this key agreement has not been
+     * completed yet
+     * @exception ShortBufferException if the given output buffer is too small
+     * to hold the secret
+     */
+    protected abstract int engineGenerateSecret(byte[] sharedSecret,
+                                                int offset)
+        throws IllegalStateException, ShortBufferException;
+
+    /**
+     * Creates the shared secret and returns it as a secret key object
+     * of the requested algorithm type.
+     *
+     * <p>This method resets this <code>KeyAgreementSpi</code> object,
+     * so that it
+     * can be reused for further key agreements. Unless this key agreement is
+     * reinitialized with one of the <code>engineInit</code> methods, the same
+     * private information and algorithm parameters will be used for
+     * subsequent key agreements.
+     *
+     * @param algorithm the requested secret key algorithm
+     *
+     * @return the shared secret key
+     *
+     * @exception IllegalStateException if this key agreement has not been
+     * completed yet
+     * @exception NoSuchAlgorithmException if the requested secret key
+     * algorithm is not available
+     * @exception InvalidKeyException if the shared secret key material cannot
+     * be used to generate a secret key of the requested algorithm type (e.g.,
+     * the key material is too short)
+     */
+    protected abstract SecretKey engineGenerateSecret(String algorithm)
+        throws IllegalStateException, NoSuchAlgorithmException,
+            InvalidKeyException;
+}

Added: openjdk-crypto/trunk/src/main/java/javax/crypto/KeyGenerator.java
===================================================================
--- openjdk-crypto/trunk/src/main/java/javax/crypto/KeyGenerator.java	                        (rev 0)
+++ openjdk-crypto/trunk/src/main/java/javax/crypto/KeyGenerator.java	2010-03-13 04:23:29 UTC (rev 25)
@@ -0,0 +1,526 @@
+/*
+ * Copyright 1997-2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.crypto;
+
+import java.util.*;
+
+import java.security.*;
+import java.security.Provider.Service;
+import java.security.spec.*;
+
+import sun.security.jca.*;
+import sun.security.jca.GetInstance.Instance;
+
+/**
+ * This class provides the functionality of a secret (symmetric) key generator.
+ *
+ * <p>Key generators are constructed using one of the <code>getInstance</code>
+ * class methods of this class.
+ *
+ * <p>KeyGenerator objects are reusable, i.e., after a key has been
+ * generated, the same KeyGenerator object can be re-used to generate further
+ * keys.
+ *
+ * <p>There are two ways to generate a key: in an algorithm-independent
+ * manner, and in an algorithm-specific manner.
+ * The only difference between the two is the initialization of the object:
+ *
+ * <ul>
+ * <li><b>Algorithm-Independent Initialization</b>
+ * <p>All key generators share the concepts of a <i>keysize</i> and a
+ * <i>source of randomness</i>.
+ * There is an
+ * {@link #init(int, java.security.SecureRandom) init}
+ * method in this KeyGenerator class that takes these two universally
+ * shared types of arguments. There is also one that takes just a
+ * <code>keysize</code> argument, and uses the SecureRandom implementation
+ * of the highest-priority installed provider as the source of randomness
+ * (or a system-provided source of randomness if none of the installed
+ * providers supply a SecureRandom implementation), and one that takes just a
+ * source of randomness.
+ *
+ * <p>Since no other parameters are specified when you call the above
+ * algorithm-independent <code>init</code> methods, it is up to the
+ * provider what to do about the algorithm-specific parameters (if any) to be
+ * associated with each of the keys.
+ * <p>
+ *
+ * <li><b>Algorithm-Specific Initialization</b>
+ * <p>For situations where a set of algorithm-specific parameters already
+ * exists, there are two
+ * {@link #init(java.security.spec.AlgorithmParameterSpec) init}
+ * methods that have an <code>AlgorithmParameterSpec</code>
+ * argument. One also has a <code>SecureRandom</code> argument, while the
+ * other uses the SecureRandom implementation
+ * of the highest-priority installed provider as the source of randomness
+ * (or a system-provided source of randomness if none of the installed
+ * providers supply a SecureRandom implementation).
+ * </ul>
+ *
+ * <p>In case the client does not explicitly initialize the KeyGenerator
+ * (via a call to an <code>init</code> method), each provider must
+ * supply (and document) a default initialization.
+ *
+ * @author Jan Luehe
+ *
+ * @see SecretKey
+ * @since 1.4
+ */
+
+public class KeyGenerator {
+
+    // see java.security.KeyPairGenerator for failover notes
+
+    private final static int I_NONE   = 1;
+    private final static int I_RANDOM = 2;
+    private final static int I_PARAMS = 3;
+    private final static int I_SIZE   = 4;
+
+    // The provider
+    private Provider provider;
+
+    // The provider implementation (delegate)
+    private volatile KeyGeneratorSpi spi;
+
+    // The algorithm
+    private final String algorithm;
+
+    private final Object lock = new Object();
+
+    private Iterator serviceIterator;
+
+    private int initType;
+    private int initKeySize;
+    private AlgorithmParameterSpec initParams;
+    private SecureRandom initRandom;
+
+    /**
+     * Creates a KeyGenerator object.
+     *
+     * @param keyGenSpi the delegate
+     * @param provider the provider
+     * @param algorithm the algorithm
+     */
+    protected KeyGenerator(KeyGeneratorSpi keyGenSpi, Provider provider,
+                           String algorithm) {
+        this.spi = keyGenSpi;
+        this.provider = provider;
+        this.algorithm = algorithm;
+    }
+
+    private KeyGenerator(String algorithm) throws NoSuchAlgorithmException {
+        this.algorithm = algorithm;
+        List list = GetInstance.getServices("KeyGenerator", algorithm);
+        serviceIterator = list.iterator();
+        initType = I_NONE;
+        // fetch and instantiate initial spi
+        if (nextSpi(null, false) == null) {
+            throw new NoSuchAlgorithmException
+                (algorithm + " KeyGenerator not available");
+        }
+    }
+
+    /**
+     * Returns the algorithm name of this <code>KeyGenerator</code> object.
+     *
+     * <p>This is the same name that was specified in one of the
+     * <code>getInstance</code> calls that created this
+     * <code>KeyGenerator</code> object.
+     *
+     * @return the algorithm name of this <code>KeyGenerator</code> object.
+     */
+    public final String getAlgorithm() {
+        return this.algorithm;
+    }
+
+    /**
+     * Returns a <code>KeyGenerator</code> object that generates secret keys
+     * for the specified algorithm.
+     *
+     * <p> This method traverses the list of registered security Providers,
+     * starting with the most preferred Provider.
+     * A new KeyGenerator object encapsulating the
+     * KeyGeneratorSpi implementation from the first
+     * Provider that supports the specified algorithm is returned.
+     *
+     * <p> Note that the list of registered providers may be retrieved via
+     * the {@link Security#getProviders() Security.getProviders()} method.
+     *
+     * @param algorithm the standard name of the requested key algorithm.
+     * See Appendix A in the
+     * <a href=
+     *   "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     * Java Cryptography Architecture Reference Guide</a>
+     * for information about standard algorithm names.
+     *
+     * @return the new <code>KeyGenerator</code> object.
+     *
+     * @exception NullPointerException if the specified algorithm is null.
+     *
+     * @exception NoSuchAlgorithmException if no Provider supports a
+     *          KeyGeneratorSpi implementation for the
+     *          specified algorithm.
+     *
+     * @see java.security.Provider
+     */
+    public static final KeyGenerator getInstance(String algorithm)
+            throws NoSuchAlgorithmException {
+        return new KeyGenerator(algorithm);
+    }
+
+    /**
+     * Returns a <code>KeyGenerator</code> object that generates secret keys
+     * for the specified algorithm.
+     *
+     * <p> A new KeyGenerator object encapsulating the
+     * KeyGeneratorSpi implementation from the specified provider
+     * is returned.  The specified provider must be registered
+     * in the security provider list.
+     *
+     * <p> Note that the list of registered providers may be retrieved via
+     * the {@link Security#getProviders() Security.getProviders()} method.
+     *
+     * @param algorithm the standard name of the requested key algorithm.
+     * See Appendix A in the
+     * <a href=
+     *   "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     * Java Cryptography Architecture Reference Guide</a>
+     * for information about standard algorithm names.
+     *
+     * @param provider the name of the provider.
+     *
+     * @return the new <code>KeyGenerator</code> object.
+     *
+     * @exception NullPointerException if the specified algorithm is null.
+     *
+     * @exception NoSuchAlgorithmException if a KeyGeneratorSpi
+     *          implementation for the specified algorithm is not
+     *          available from the specified provider.
+     *
+     * @exception NoSuchProviderException if the specified provider is not
+     *          registered in the security provider list.
+     *
+     * @exception IllegalArgumentException if the <code>provider</code>
+     *          is null or empty.
+     *
+     * @see java.security.Provider
+     */
+    public static final KeyGenerator getInstance(String algorithm,
+            String provider) throws NoSuchAlgorithmException,
+            NoSuchProviderException {
+        Instance instance = JceSecurity.getInstance("KeyGenerator",
+                KeyGeneratorSpi.class, algorithm, provider);
+        return new KeyGenerator((KeyGeneratorSpi)instance.impl,
+                instance.provider, algorithm);
+    }
+
+    /**
+     * Returns a <code>KeyGenerator</code> object that generates secret keys
+     * for the specified algorithm.
+     *
+     * <p> A new KeyGenerator object encapsulating the
+     * KeyGeneratorSpi implementation from the specified Provider
+     * object is returned.  Note that the specified Provider object
+     * does not have to be registered in the provider list.
+     *
+     * @param algorithm the standard name of the requested key algorithm.
+     * See Appendix A in the
+     * <a href=
+     *   "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     * Java Cryptography Architecture Reference Guide</a>
+     * for information about standard algorithm names.
+     *
+     * @param provider the provider.
+     *
+     * @return the new <code>KeyGenerator</code> object.
+     *
+     * @exception NullPointerException if the specified algorithm is null.
+     *
+     * @exception NoSuchAlgorithmException if a KeyGeneratorSpi
+     *          implementation for the specified algorithm is not available
+     *          from the specified Provider object.
+     *
+     * @exception IllegalArgumentException if the <code>provider</code>
+     *          is null.
+     *
+     * @see java.security.Provider
+     */
+    public static final KeyGenerator getInstance(String algorithm,
+            Provider provider) throws NoSuchAlgorithmException {
+        Instance instance = JceSecurity.getInstance("KeyGenerator",
+                KeyGeneratorSpi.class, algorithm, provider);
+        return new KeyGenerator((KeyGeneratorSpi)instance.impl,
+                instance.provider, algorithm);
+    }
+
+    /**
+     * Returns the provider of this <code>KeyGenerator</code> object.
+     *
+     * @return the provider of this <code>KeyGenerator</code> object
+     */
+    public final Provider getProvider() {
+        synchronized (lock) {
+            disableFailover();
+            return provider;
+        }
+    }
+
+    /**
+     * Update the active spi of this class and return the next
+     * implementation for failover. If no more implemenations are
+     * available, this method returns null. However, the active spi of
+     * this class is never set to null.
+     */
+    private KeyGeneratorSpi nextSpi(KeyGeneratorSpi oldSpi,
+            boolean reinit) {
+        synchronized (lock) {
+            // somebody else did a failover concurrently
+            // try that spi now
+            if ((oldSpi != null) && (oldSpi != spi)) {
+                return spi;
+            }
+            if (serviceIterator == null) {
+                return null;
+            }
+            while (serviceIterator.hasNext()) {
+                Service s = (Service)serviceIterator.next();
+                if (JceSecurity.canUseProvider(s.getProvider()) == false) {
+                    continue;
+                }
+                try {
+                    Object inst = s.newInstance(null);
+                    // ignore non-spis
+                    if (inst instanceof KeyGeneratorSpi == false) {
+                        continue;
+                    }
+                    KeyGeneratorSpi spi = (KeyGeneratorSpi)inst;
+                    if (reinit) {
+                        if (initType == I_SIZE) {
+                            spi.engineInit(initKeySize, initRandom);
+                        } else if (initType == I_PARAMS) {
+                            spi.engineInit(initParams, initRandom);
+                        } else if (initType == I_RANDOM) {
+                            spi.engineInit(initRandom);
+                        } else if (initType != I_NONE) {
+                            throw new AssertionError
+                                ("KeyGenerator initType: " + initType);
+                        }
+                    }
+                    provider = s.getProvider();
+                    this.spi = spi;
+                    return spi;
+                } catch (Exception e) {
+                    // ignore
+                }
+            }
+            disableFailover();
+            return null;
+        }
+    }
+
+    void disableFailover() {
+        serviceIterator = null;
+        initType = 0;
+        initParams = null;
+        initRandom = null;
+    }
+
+    /**
+     * Initializes this key generator.
+     *
+     * @param random the source of randomness for this generator
+     */
+    public final void init(SecureRandom random) {
+        if (serviceIterator == null) {
+            spi.engineInit(random);
+            return;
+        }
+        RuntimeException failure = null;
+        KeyGeneratorSpi mySpi = spi;
+        do {
+            try {
+                mySpi.engineInit(random);
+                initType = I_RANDOM;
+                initKeySize = 0;
+                initParams = null;
+                initRandom = random;
+                return;
+            } catch (RuntimeException e) {
+                if (failure == null) {
+                    failure = e;
+                }
+                mySpi = nextSpi(mySpi, false);
+            }
+        } while (mySpi != null);
+        throw failure;
+    }
+
+    /**
+     * Initializes this key generator with the specified parameter set.
+     *
+     * <p> If this key generator requires any random bytes, it will get them
+     * using the
+     * {@link SecureRandom <code>SecureRandom</code>}
+     * implementation of the highest-priority installed
+     * provider as the source of randomness.
+     * (If none of the installed providers supply an implementation of
+     * SecureRandom, a system-provided source of randomness will be used.)
+     *
+     * @param params the key generation parameters
+     *
+     * @exception InvalidAlgorithmParameterException if the given parameters
+     * are inappropriate for this key generator
+     */
+    public final void init(AlgorithmParameterSpec params)
+        throws InvalidAlgorithmParameterException
+    {
+        init(params, JceSecurity.RANDOM);
+    }
+
+    /**
+     * Initializes this key generator with the specified parameter
+     * set and a user-provided source of randomness.
+     *
+     * @param params the key generation parameters
+     * @param random the source of randomness for this key generator
+     *
+     * @exception InvalidAlgorithmParameterException if <code>params</code> is
+     * inappropriate for this key generator
+     */
+    public final void init(AlgorithmParameterSpec params, SecureRandom random)
+        throws InvalidAlgorithmParameterException
+    {
+        if (serviceIterator == null) {
+            spi.engineInit(params, random);
+            return;
+        }
+        Exception failure = null;
+        KeyGeneratorSpi mySpi = spi;
+        do {
+            try {
+                mySpi.engineInit(params, random);
+                initType = I_PARAMS;
+                initKeySize = 0;
+                initParams = params;
+                initRandom = random;
+                return;
+            } catch (Exception e) {
+                if (failure == null) {
+                    failure = e;
+                }
+                mySpi = nextSpi(mySpi, false);
+            }
+        } while (mySpi != null);
+        if (failure instanceof InvalidAlgorithmParameterException) {
+            throw (InvalidAlgorithmParameterException)failure;
+        }
+        if (failure instanceof RuntimeException) {
+            throw (RuntimeException)failure;
+        }
+        throw new InvalidAlgorithmParameterException("init() failed", failure);
+    }
+
+    /**
+     * Initializes this key generator for a certain keysize.
+     *
+     * <p> If this key generator requires any random bytes, it will get them
+     * using the
+     * {@link SecureRandom <code>SecureRandom</code>}
+     * implementation of the highest-priority installed
+     * provider as the source of randomness.
+     * (If none of the installed providers supply an implementation of
+     * SecureRandom, a system-provided source of randomness will be used.)
+     *
+     * @param keysize the keysize. This is an algorithm-specific metric,
+     * specified in number of bits.
+     *
+     * @exception InvalidParameterException if the keysize is wrong or not
+     * supported.
+     */
+    public final void init(int keysize) {
+        init(keysize, JceSecurity.RANDOM);
+    }
+
+    /**
+     * Initializes this key generator for a certain keysize, using a
+     * user-provided source of randomness.
+     *
+     * @param keysize the keysize. This is an algorithm-specific metric,
+     * specified in number of bits.
+     * @param random the source of randomness for this key generator
+     *
+     * @exception InvalidParameterException if the keysize is wrong or not
+     * supported.
+     */
+    public final void init(int keysize, SecureRandom random) {
+        if (serviceIterator == null) {
+            spi.engineInit(keysize, random);
+            return;
+        }
+        RuntimeException failure = null;
+        KeyGeneratorSpi mySpi = spi;
+        do {
+            try {
+                mySpi.engineInit(keysize, random);
+                initType = I_SIZE;
+                initKeySize = keysize;
+                initParams = null;
+                initRandom = random;
+                return;
+            } catch (RuntimeException e) {
+                if (failure == null) {
+                    failure = e;
+                }
+                mySpi = nextSpi(mySpi, false);
+            }
+        } while (mySpi != null);
+        throw failure;
+    }
+
+    /**
+     * Generates a secret key.
+     *
+     * @return the new key
+     */
+    public final SecretKey generateKey() {
+        if (serviceIterator == null) {
+            return spi.engineGenerateKey();
+        }
+        RuntimeException failure = null;
+        KeyGeneratorSpi mySpi = spi;
+        do {
+            try {
+                return mySpi.engineGenerateKey();
+            } catch (RuntimeException e) {
+                if (failure == null) {
+                    failure = e;
+                }
+                mySpi = nextSpi(mySpi, true);
+            }
+        } while (mySpi != null);
+        throw failure;
+   }
+}

Added: openjdk-crypto/trunk/src/main/java/javax/crypto/KeyGeneratorSpi.java
===================================================================
--- openjdk-crypto/trunk/src/main/java/javax/crypto/KeyGeneratorSpi.java	                        (rev 0)
+++ openjdk-crypto/trunk/src/main/java/javax/crypto/KeyGeneratorSpi.java	2010-03-13 04:23:29 UTC (rev 25)
@@ -0,0 +1,86 @@
+/*
+ * Copyright 1997-2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.crypto;
+
+import java.security.*;
+import java.security.spec.*;
+
+/**
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
+ * for the <code>KeyGenerator</code> class.
+ * All the abstract methods in this class must be implemented by each
+ * cryptographic service provider who wishes to supply the implementation
+ * of a key generator for a particular algorithm.
+ *
+ * @author Jan Luehe
+ *
+ * @see SecretKey
+ * @since 1.4
+ */
+
+public abstract class KeyGeneratorSpi {
+
+    /**
+     * Initializes the key generator.
+     *
+     * @param random the source of randomness for this generator
+     */
+    protected abstract void engineInit(SecureRandom random);
+
+    /**
+     * Initializes the key generator with the specified parameter
+     * set and a user-provided source of randomness.
+     *
+     * @param params the key generation parameters
+     * @param random the source of randomness for this key generator
+     *
+     * @exception InvalidAlgorithmParameterException if <code>params</code> is
+     * inappropriate for this key generator
+     */
+    protected abstract void engineInit(AlgorithmParameterSpec params,
+                                       SecureRandom random)
+        throws InvalidAlgorithmParameterException;
+
+    /**
+     * Initializes this key generator for a certain keysize, using the given
+     * source of randomness.
+     *
+     * @param keysize the keysize. This is an algorithm-specific metric,
+     * specified in number of bits.
+     * @param random the source of randomness for this key generator
+     *
+     * @exception InvalidParameterException if the keysize is wrong or not
+     * supported.
+     */
+    protected abstract void engineInit(int keysize, SecureRandom random);
+
+    /**
+     * Generates a secret key.
+     *
+     * @return the new key
+     */
+    protected abstract SecretKey engineGenerateKey();
+}

Added: openjdk-crypto/trunk/src/main/java/javax/crypto/Mac.java
===================================================================
--- openjdk-crypto/trunk/src/main/java/javax/crypto/Mac.java	                        (rev 0)
+++ openjdk-crypto/trunk/src/main/java/javax/crypto/Mac.java	2010-03-13 04:23:29 UTC (rev 25)
@@ -0,0 +1,643 @@
+/*
+ * Copyright 1998-2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.crypto;
+
+import java.util.*;
+
+import java.security.*;
+import java.security.Provider.Service;
+import java.security.spec.AlgorithmParameterSpec;
+
+import java.nio.ByteBuffer;
+
+import sun.security.util.Debug;
+import sun.security.jca.*;
+import sun.security.jca.GetInstance.Instance;
+
+/**
+ * This class provides the functionality of a "Message Authentication Code"
+ * (MAC) algorithm.
+ *
+ * <p> A MAC provides a way to check
+ * the integrity of information transmitted over or stored in an unreliable
+ * medium, based on a secret key. Typically, message
+ * authentication codes are used between two parties that share a secret
+ * key in order to validate information transmitted between these
+ * parties.
+ *
+ * <p> A MAC mechanism that is based on cryptographic hash functions is
+ * referred to as HMAC. HMAC can be used with any cryptographic hash function,
+ * e.g., MD5 or SHA-1, in combination with a secret shared key. HMAC is
+ * specified in RFC 2104.
+ *
+ * @author Jan Luehe
+ *
+ * @since 1.4
+ */
+
+public class Mac implements Cloneable {
+
+    private static final Debug debug =
+                        Debug.getInstance("jca", "Mac");
+
+    // The provider
+    private Provider provider;
+
+    // The provider implementation (delegate)
+    private MacSpi spi;
+
+    // The name of the MAC algorithm.
+    private final String algorithm;
+
+    // Has this object been initialized?
+    private boolean initialized = false;
+
+    // next service to try in provider selection
+    // null once provider is selected
+    private Service firstService;
+
+    // remaining services to try in provider selection
+    // null once provider is selected
+    private Iterator serviceIterator;
+
+    private final Object lock;
+
+    /**
+     * Creates a MAC object.
+     *
+     * @param macSpi the delegate
+     * @param provider the provider
+     * @param algorithm the algorithm
+     */
+    protected Mac(MacSpi macSpi, Provider provider, String algorithm) {
+        this.spi = macSpi;
+        this.provider = provider;
+        this.algorithm = algorithm;
+        serviceIterator = null;
+        lock = null;
+    }
+
+    private Mac(Service s, Iterator t, String algorithm) {
+        firstService = s;
+        serviceIterator = t;
+        this.algorithm = algorithm;
+        lock = new Object();
+    }
+
+    /**
+     * Returns the algorithm name of this <code>Mac</code> object.
+     *
+     * <p>This is the same name that was specified in one of the
+     * <code>getInstance</code> calls that created this
+     * <code>Mac</code> object.
+     *
+     * @return the algorithm name of this <code>Mac</code> object.
+     */
+    public final String getAlgorithm() {
+        return this.algorithm;
+    }
+
+    /**
+     * Returns a <code>Mac</code> object that implements the
+     * specified MAC algorithm.
+     *
+     * <p> This method traverses the list of registered security Providers,
+     * starting with the most preferred Provider.
+     * A new Mac object encapsulating the
+     * MacSpi implementation from the first
+     * Provider that supports the specified algorithm is returned.
+     *
+     * <p> Note that the list of registered providers may be retrieved via
+     * the {@link Security#getProviders() Security.getProviders()} method.
+     *
+     * @param algorithm the standard name of the requested MAC algorithm.
+     * See Appendix A in the <a href=
+     *   "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     * Java Cryptography Architecture Reference Guide</a>
+     * for information about standard algorithm names.
+     *
+     * @return the new <code>Mac</code> object.
+     *
+     * @exception NoSuchAlgorithmException if no Provider supports a
+     *          MacSpi implementation for the
+     *          specified algorithm.
+     *
+     * @see java.security.Provider
+     */
+    public static final Mac getInstance(String algorithm)
+            throws NoSuchAlgorithmException {
+        List services = GetInstance.getServices("Mac", algorithm);
+        // make sure there is at least one service from a signed provider
+        Iterator t = services.iterator();
+        while (t.hasNext()) {
+            Service s = (Service)t.next();
+            if (JceSecurity.canUseProvider(s.getProvider()) == false) {
+                continue;
+            }
+            return new Mac(s, t, algorithm);
+        }
+        throw new NoSuchAlgorithmException
+                                ("Algorithm " + algorithm + " not available");
+    }
+
+    /**
+     * Returns a <code>Mac</code> object that implements the
+     * specified MAC algorithm.
+     *
+     * <p> A new Mac object encapsulating the
+     * MacSpi implementation from the specified provider
+     * is returned.  The specified provider must be registered
+     * in the security provider list.
+     *
+     * <p> Note that the list of registered providers may be retrieved via
+     * the {@link Security#getProviders() Security.getProviders()} method.
+     *
+     * @param algorithm the standard name of the requested MAC algorithm.
+     * See Appendix A in the <a href=
+     *   "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     * Java Cryptography Architecture Reference Guide</a>
+     * for information about standard algorithm names.
+     *
+     * @param provider the name of the provider.
+     *
+     * @return the new <code>Mac</code> object.
+     *
+     * @exception NoSuchAlgorithmException if a MacSpi
+     *          implementation for the specified algorithm is not
+     *          available from the specified provider.
+     *
+     * @exception NoSuchProviderException if the specified provider is not
+     *          registered in the security provider list.
+     *
+     * @exception IllegalArgumentException if the <code>provider</code>
+     *          is null or empty.
+     *
+     * @see java.security.Provider
+     */
+    public static final Mac getInstance(String algorithm, String provider)
+            throws NoSuchAlgorithmException, NoSuchProviderException {
+        Instance instance = JceSecurity.getInstance
+                ("Mac", MacSpi.class, algorithm, provider);
+        return new Mac((MacSpi)instance.impl, instance.provider, algorithm);
+    }
+
+    /**
+     * Returns a <code>Mac</code> object that implements the
+     * specified MAC algorithm.
+     *
+     * <p> A new Mac object encapsulating the
+     * MacSpi implementation from the specified Provider
+     * object is returned.  Note that the specified Provider object
+     * does not have to be registered in the provider list.
+     *
+     * @param algorithm the standard name of the requested MAC algorithm.
+     * See Appendix A in the <a href=
+     *   "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     * Java Cryptography Architecture Reference Guide</a>
+     * for information about standard algorithm names.
+     *
+     * @param provider the provider.
+     *
+     * @return the new <code>Mac</code> object.
+     *
+     * @exception NoSuchAlgorithmException if a MacSpi
+     *          implementation for the specified algorithm is not available
+     *          from the specified Provider object.
+     *
+     * @exception IllegalArgumentException if the <code>provider</code>
+     *          is null.
+     *
+     * @see java.security.Provider
+     */
+    public static final Mac getInstance(String algorithm, Provider provider)
+            throws NoSuchAlgorithmException {
+        Instance instance = JceSecurity.getInstance
+                ("Mac", MacSpi.class, algorithm, provider);
+        return new Mac((MacSpi)instance.impl, instance.provider, algorithm);
+    }
+
+    // max number of debug warnings to print from chooseFirstProvider()
+    private static int warnCount = 10;
+
+    /**
+     * Choose the Spi from the first provider available. Used if
+     * delayed provider selection is not possible because init()
+     * is not the first method called.
+     */
+    void chooseFirstProvider() {
+        if ((spi != null) || (serviceIterator == null)) {
+            return;
+        }
+        synchronized (lock) {
+            if (spi != null) {
+                return;
+            }
+            if (debug != null) {
+                int w = --warnCount;
+                if (w >= 0) {
+                    debug.println("Mac.init() not first method "
+                        + "called, disabling delayed provider selection");
+                    if (w == 0) {
+                        debug.println("Further warnings of this type will "
+                            + "be suppressed");
+                    }
+                    new Exception("Call trace").printStackTrace();
+                }
+            }
+            Exception lastException = null;
+            while ((firstService != null) || serviceIterator.hasNext()) {
+                Service s;
+                if (firstService != null) {
+                    s = firstService;
+                    firstService = null;
+                } else {
+                    s = (Service)serviceIterator.next();
+                }
+                if (JceSecurity.canUseProvider(s.getProvider()) == false) {
+                    continue;
+                }
+                try {
+                    Object obj = s.newInstance(null);
+                    if (obj instanceof MacSpi == false) {
+                        continue;
+                    }
+                    spi = (MacSpi)obj;
+                    provider = s.getProvider();
+                    // not needed any more
+                    firstService = null;
+                    serviceIterator = null;
+                    return;
+                } catch (NoSuchAlgorithmException e) {
+                    lastException = e;
+                }
+            }
+            ProviderException e = new ProviderException
+                    ("Could not construct MacSpi instance");
+            if (lastException != null) {
+                e.initCause(lastException);
+            }
+            throw e;
+        }
+    }
+
+    private void chooseProvider(Key key, AlgorithmParameterSpec params)
+            throws InvalidKeyException, InvalidAlgorithmParameterException {
+        synchronized (lock) {
+            if (spi != null) {
+                spi.engineInit(key, params);
+                return;
+            }
+            Exception lastException = null;
+            while ((firstService != null) || serviceIterator.hasNext()) {
+                Service s;
+                if (firstService != null) {
+                    s = firstService;
+                    firstService = null;
+                } else {
+                    s = (Service)serviceIterator.next();
+                }
+                // if provider says it does not support this key, ignore it
+                if (s.supportsParameter(key) == false) {
+                    continue;
+                }
+                if (JceSecurity.canUseProvider(s.getProvider()) == false) {
+                    continue;
+                }
+                try {
+                    MacSpi spi = (MacSpi)s.newInstance(null);
+                    spi.engineInit(key, params);
+                    provider = s.getProvider();
+                    this.spi = spi;
+                    firstService = null;
+                    serviceIterator = null;
+                    return;
+                } catch (Exception e) {
+                    // NoSuchAlgorithmException from newInstance()
+                    // InvalidKeyException from init()
+                    // RuntimeException (ProviderException) from init()
+                    if (lastException == null) {
+                        lastException = e;
+                    }
+                }
+            }
+            // no working provider found, fail
+            if (lastException instanceof InvalidKeyException) {
+                throw (InvalidKeyException)lastException;
+            }
+            if (lastException instanceof InvalidAlgorithmParameterException) {
+                throw (InvalidAlgorithmParameterException)lastException;
+            }
+            if (lastException instanceof RuntimeException) {
+                throw (RuntimeException)lastException;
+            }
+            String kName = (key != null) ? key.getClass().getName() : "(null)";
+            throw new InvalidKeyException
+                ("No installed provider supports this key: "
+                + kName, lastException);
+        }
+    }
+
+    /**
+     * Returns the provider of this <code>Mac</code> object.
+     *
+     * @return the provider of this <code>Mac</code> object.
+     */
+    public final Provider getProvider() {
+        chooseFirstProvider();
+        return this.provider;
+    }
+
+    /**
+     * Returns the length of the MAC in bytes.
+     *
+     * @return the MAC length in bytes.
+     */
+    public final int getMacLength() {
+        chooseFirstProvider();
+        return spi.engineGetMacLength();
+    }
+
+    /**
+     * Initializes this <code>Mac</code> object with the given key.
+     *
+     * @param key the key.
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * initializing this MAC.
+     */
+    public final void init(Key key) throws InvalidKeyException {
+        try {
+            if (spi != null) {
+                spi.engineInit(key, null);
+            } else {
+                chooseProvider(key, null);
+            }
+        } catch (InvalidAlgorithmParameterException e) {
+            throw new InvalidKeyException("init() failed", e);
+        }
+        initialized = true;
+    }
+
+    /**
+     * Initializes this <code>Mac</code> object with the given key and
+     * algorithm parameters.
+     *
+     * @param key the key.
+     * @param params the algorithm parameters.
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * initializing this MAC.
+     * @exception InvalidAlgorithmParameterException if the given algorithm
+     * parameters are inappropriate for this MAC.
+     */
+    public final void init(Key key, AlgorithmParameterSpec params)
+            throws InvalidKeyException, InvalidAlgorithmParameterException {
+        if (spi != null) {
+            spi.engineInit(key, params);
+        } else {
+            chooseProvider(key, params);
+        }
+        initialized = true;
+    }
+
+    /**
+     * Processes the given byte.
+     *
+     * @param input the input byte to be processed.
+     *
+     * @exception IllegalStateException if this <code>Mac</code> has not been
+     * initialized.
+     */
+    public final void update(byte input) throws IllegalStateException {
+        chooseFirstProvider();
+        if (initialized == false) {
+            throw new IllegalStateException("MAC not initialized");
+        }
+        spi.engineUpdate(input);
+    }
+
+    /**
+     * Processes the given array of bytes.
+     *
+     * @param input the array of bytes to be processed.
+     *
+     * @exception IllegalStateException if this <code>Mac</code> has not been
+     * initialized.
+     */
+    public final void update(byte[] input) throws IllegalStateException {
+        chooseFirstProvider();
+        if (initialized == false) {
+            throw new IllegalStateException("MAC not initialized");
+        }
+        if (input != null) {
+            spi.engineUpdate(input, 0, input.length);
+        }
+    }
+
+    /**
+     * Processes the first <code>len</code> bytes in <code>input</code>,
+     * starting at <code>offset</code> inclusive.
+     *
+     * @param input the input buffer.
+     * @param offset the offset in <code>input</code> where the input starts.
+     * @param len the number of bytes to process.
+     *
+     * @exception IllegalStateException if this <code>Mac</code> has not been
+     * initialized.
+     */
+    public final void update(byte[] input, int offset, int len)
+            throws IllegalStateException {
+        chooseFirstProvider();
+        if (initialized == false) {
+            throw new IllegalStateException("MAC not initialized");
+        }
+
+        if (input != null) {
+            if ((offset < 0) || (len > (input.length - offset)) || (len < 0))
+                throw new IllegalArgumentException("Bad arguments");
+            spi.engineUpdate(input, offset, len);
+        }
+    }
+
+    /**
+     * Processes <code>input.remaining()</code> bytes in the ByteBuffer
+     * <code>input</code>, starting at <code>input.position()</code>.
+     * Upon return, the buffer's position will be equal to its limit;
+     * its limit will not have changed.
+     *
+     * @param input the ByteBuffer
+     *
+     * @exception IllegalStateException if this <code>Mac</code> has not been
+     * initialized.
+     * @since 1.5
+     */
+    public final void update(ByteBuffer input) {
+        chooseFirstProvider();
+        if (initialized == false) {
+            throw new IllegalStateException("MAC not initialized");
+        }
+        if (input == null) {
+            throw new IllegalArgumentException("Buffer must not be null");
+        }
+        spi.engineUpdate(input);
+    }
+
+    /**
+     * Finishes the MAC operation.
+     *
+     * <p>A call to this method resets this <code>Mac</code> object to the
+     * state it was in when previously initialized via a call to
+     * <code>init(Key)</code> or
+     * <code>init(Key, AlgorithmParameterSpec)</code>.
+     * That is, the object is reset and available to generate another MAC from
+     * the same key, if desired, via new calls to <code>update</code> and
+     * <code>doFinal</code>.
+     * (In order to reuse this <code>Mac</code> object with a different key,
+     * it must be reinitialized via a call to <code>init(Key)</code> or
+     * <code>init(Key, AlgorithmParameterSpec)</code>.
+     *
+     * @return the MAC result.
+     *
+     * @exception IllegalStateException if this <code>Mac</code> has not been
+     * initialized.
+     */
+    public final byte[] doFinal() throws IllegalStateException {
+        chooseFirstProvider();
+        if (initialized == false) {
+            throw new IllegalStateException("MAC not initialized");
+        }
+        byte[] mac = spi.engineDoFinal();
+        spi.engineReset();
+        return mac;
+    }
+
+    /**
+     * Finishes the MAC operation.
+     *
+     * <p>A call to this method resets this <code>Mac</code> object to the
+     * state it was in when previously initialized via a call to
+     * <code>init(Key)</code> or
+     * <code>init(Key, AlgorithmParameterSpec)</code>.
+     * That is, the object is reset and available to generate another MAC from
+     * the same key, if desired, via new calls to <code>update</code> and
+     * <code>doFinal</code>.
+     * (In order to reuse this <code>Mac</code> object with a different key,
+     * it must be reinitialized via a call to <code>init(Key)</code> or
+     * <code>init(Key, AlgorithmParameterSpec)</code>.
+     *
+     * <p>The MAC result is stored in <code>output</code>, starting at
+     * <code>outOffset</code> inclusive.
+     *
+     * @param output the buffer where the MAC result is stored
+     * @param outOffset the offset in <code>output</code> where the MAC is
+     * stored
+     *
+     * @exception ShortBufferException if the given output buffer is too small
+     * to hold the result
+     * @exception IllegalStateException if this <code>Mac</code> has not been
+     * initialized.
+     */
+    public final void doFinal(byte[] output, int outOffset)
+        throws ShortBufferException, IllegalStateException
+    {
+        chooseFirstProvider();
+        if (initialized == false) {
+            throw new IllegalStateException("MAC not initialized");
+        }
+        int macLen = getMacLength();
+        if (output == null || output.length-outOffset < macLen) {
+            throw new ShortBufferException
+                ("Cannot store MAC in output buffer");
+        }
+        byte[] mac = doFinal();
+        System.arraycopy(mac, 0, output, outOffset, macLen);
+        return;
+    }
+
+    /**
+     * Processes the given array of bytes and finishes the MAC operation.
+     *
+     * <p>A call to this method resets this <code>Mac</code> object to the
+     * state it was in when previously initialized via a call to
+     * <code>init(Key)</code> or
+     * <code>init(Key, AlgorithmParameterSpec)</code>.
+     * That is, the object is reset and available to generate another MAC from
+     * the same key, if desired, via new calls to <code>update</code> and
+     * <code>doFinal</code>.
+     * (In order to reuse this <code>Mac</code> object with a different key,
+     * it must be reinitialized via a call to <code>init(Key)</code> or
+     * <code>init(Key, AlgorithmParameterSpec)</code>.
+     *
+     * @param input data in bytes
+     * @return the MAC result.
+     *
+     * @exception IllegalStateException if this <code>Mac</code> has not been
+     * initialized.
+     */
+    public final byte[] doFinal(byte[] input) throws IllegalStateException
+    {
+        chooseFirstProvider();
+        if (initialized == false) {
+            throw new IllegalStateException("MAC not initialized");
+        }
+        update(input);
+        return doFinal();
+    }
+
+    /**
+     * Resets this <code>Mac</code> object.
+     *
+     * <p>A call to this method resets this <code>Mac</code> object to the
+     * state it was in when previously initialized via a call to
+     * <code>init(Key)</code> or
+     * <code>init(Key, AlgorithmParameterSpec)</code>.
+     * That is, the object is reset and available to generate another MAC from
+     * the same key, if desired, via new calls to <code>update</code> and
+     * <code>doFinal</code>.
+     * (In order to reuse this <code>Mac</code> object with a different key,
+     * it must be reinitialized via a call to <code>init(Key)</code> or
+     * <code>init(Key, AlgorithmParameterSpec)</code>.
+     */
+    public final void reset() {
+        chooseFirstProvider();
+        spi.engineReset();
+    }
+
+    /**
+     * Returns a clone if the provider implementation is cloneable.
+     *
+     * @return a clone if the provider implementation is cloneable.
+     *
+     * @exception CloneNotSupportedException if this is called on a
+     * delegate that does not support <code>Cloneable</code>.
+     */
+    public final Object clone() throws CloneNotSupportedException {
+        chooseFirstProvider();
+        Mac that = (Mac)super.clone();
+        that.spi = (MacSpi)this.spi.clone();
+        return that;
+    }
+}

Added: openjdk-crypto/trunk/src/main/java/javax/crypto/MacSpi.java
===================================================================
--- openjdk-crypto/trunk/src/main/java/javax/crypto/MacSpi.java	                        (rev 0)
+++ openjdk-crypto/trunk/src/main/java/javax/crypto/MacSpi.java	2010-03-13 04:23:29 UTC (rev 25)
@@ -0,0 +1,153 @@
+/*
+ * Copyright 1998-2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.crypto;
+
+import java.security.*;
+import java.security.spec.*;
+
+import java.nio.ByteBuffer;
+
+/**
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
+ * for the <code>Mac</code> class.
+ * All the abstract methods in this class must be implemented by each
+ * cryptographic service provider who wishes to supply the implementation
+ * of a particular MAC algorithm.
+ *
+ * <p> Implementations are free to implement the Cloneable interface.
+ *
+ * @author Jan Luehe
+ *
+ * @since 1.4
+ */
+
+public abstract class MacSpi {
+
+    /**
+     * Returns the length of the MAC in bytes.
+     *
+     * @return the MAC length in bytes.
+     */
+    protected abstract int engineGetMacLength();
+
+    /**
+     * Initializes the MAC with the given (secret) key and algorithm
+     * parameters.
+     *
+     * @param key the (secret) key.
+     * @param params the algorithm parameters.
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * initializing this MAC.
+     * @exception InvalidAlgorithmParameterException if the given algorithm
+     * parameters are inappropriate for this MAC.
+     */
+    protected abstract void engineInit(Key key,
+                                       AlgorithmParameterSpec params)
+        throws InvalidKeyException, InvalidAlgorithmParameterException ;
+
+    /**
+     * Processes the given byte.
+     *
+     * @param input the input byte to be processed.
+     */
+    protected abstract void engineUpdate(byte input);
+
+    /**
+     * Processes the first <code>len</code> bytes in <code>input</code>,
+     * starting at <code>offset</code> inclusive.
+     *
+     * @param input the input buffer.
+     * @param offset the offset in <code>input</code> where the input starts.
+     * @param len the number of bytes to process.
+     */
+    protected abstract void engineUpdate(byte[] input, int offset, int len);
+
+    /**
+     * Processes <code>input.remaining()</code> bytes in the ByteBuffer
+     * <code>input</code>, starting at <code>input.position()</code>.
+     * Upon return, the buffer's position will be equal to its limit;
+     * its limit will not have changed.
+     *
+     * <p>Subclasses should consider overriding this method if they can
+     * process ByteBuffers more efficiently than byte arrays.
+     *
+     * @param input the ByteBuffer
+     * @since 1.5
+     */
+    protected void engineUpdate(ByteBuffer input) {
+        if (input.hasRemaining() == false) {
+            return;
+        }
+        if (input.hasArray()) {
+            byte[] b = input.array();
+            int ofs = input.arrayOffset();
+            int pos = input.position();
+            int lim = input.limit();
+            engineUpdate(b, ofs + pos, lim - pos);
+            input.position(lim);
+        } else {
+            int len = input.remaining();
+            byte[] b = new byte[CipherSpi.getTempArraySize(len)];
+            while (len > 0) {
+                int chunk = Math.min(len, b.length);
+                input.get(b, 0, chunk);
+                engineUpdate(b, 0, chunk);
+                len -= chunk;
+            }
+        }
+    }
+
+    /**
+     * Completes the MAC computation and resets the MAC for further use,
+     * maintaining the secret key that the MAC was initialized with.
+     *
+     * @return the MAC result.
+     */
+    protected abstract byte[] engineDoFinal();
+
+    /**
+     * Resets the MAC for further use, maintaining the secret key that the
+     * MAC was initialized with.
+     */
+    protected abstract void engineReset();
+
+    /**
+     * Returns a clone if the implementation is cloneable.
+     *
+     * @return a clone if the implementation is cloneable.
+     *
+     * @exception CloneNotSupportedException if this is called
+     * on an implementation that does not support <code>Cloneable</code>.
+     */
+    public Object clone() throws CloneNotSupportedException {
+        if (this instanceof Cloneable) {
+            return super.clone();
+        } else {
+            throw new CloneNotSupportedException();
+        }
+    }
+}

Added: openjdk-crypto/trunk/src/main/java/javax/crypto/NoSuchPaddingException.java
===================================================================
--- openjdk-crypto/trunk/src/main/java/javax/crypto/NoSuchPaddingException.java	                        (rev 0)
+++ openjdk-crypto/trunk/src/main/java/javax/crypto/NoSuchPaddingException.java	2010-03-13 04:23:29 UTC (rev 25)
@@ -0,0 +1,61 @@
+/*
+ * Copyright 1997-2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.crypto;
+
+import java.security.GeneralSecurityException;
+
+/**
+ * This exception is thrown when a particular padding mechanism is
+ * requested but is not available in the environment.
+ *
+ * @author Jan Luehe
+ *
+ * @since 1.4
+ */
+
+public class NoSuchPaddingException extends GeneralSecurityException {
+
+    private static final long serialVersionUID = -4572885201200175466L;
+
+    /**
+     * Constructs a NoSuchPaddingException with no detail
+     * message. A detail message is a String that describes this
+     * particular exception.
+     */
+    public NoSuchPaddingException() {
+        super();
+    }
+
+    /**
+     * Constructs a NoSuchPaddingException with the specified
+     * detail message.
+     *
+     * @param msg the detail message.
+     */
+    public NoSuchPaddingException(String msg) {
+        super(msg);
+    }
+}

Added: openjdk-crypto/trunk/src/main/java/javax/crypto/NullCipher.java
===================================================================
--- openjdk-crypto/trunk/src/main/java/javax/crypto/NullCipher.java	                        (rev 0)
+++ openjdk-crypto/trunk/src/main/java/javax/crypto/NullCipher.java	2010-03-13 04:23:29 UTC (rev 25)
@@ -0,0 +1,44 @@
+/*
+ * Copyright 1997-2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.crypto;
+
+/**
+ * The NullCipher class is a class that provides an
+ * "identity cipher" -- one that does not tranform the plaintext.  As
+ * a consequence, the ciphertext is identical to the plaintext.  All
+ * initialization methods do nothing, while the blocksize is set to 1
+ * byte.
+ *
+ * @author  Li Gong
+ * @since 1.4
+ */
+
+public class NullCipher extends Cipher {
+
+    public NullCipher() {
+        super(new NullCipherSpi(), null);
+    }
+}

Added: openjdk-crypto/trunk/src/main/java/javax/crypto/NullCipherSpi.java
===================================================================
--- openjdk-crypto/trunk/src/main/java/javax/crypto/NullCipherSpi.java	                        (rev 0)
+++ openjdk-crypto/trunk/src/main/java/javax/crypto/NullCipherSpi.java	2010-03-13 04:23:29 UTC (rev 25)
@@ -0,0 +1,113 @@
+/*
+ * Copyright 1997-2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.crypto;
+
+import java.security.*;
+import java.security.spec.*;
+
+/**
+ * This class provides a delegate for the identity cipher - one that does not
+ * tranform the plaintext.
+ *
+ * @author  Li Gong
+ * @see Nullcipher
+ *
+ * @since 1.4
+ */
+
+final class NullCipherSpi extends CipherSpi {
+
+    /*
+     * Do not let anybody instantiate this directly (protected).
+     */
+    protected NullCipherSpi() {}
+
+    public void engineSetMode(String mode) {}
+
+    public void engineSetPadding(String padding) {}
+
+    protected int engineGetBlockSize() {
+        return 1;
+    }
+
+    protected int engineGetOutputSize(int inputLen) {
+        return inputLen;
+    }
+
+    protected byte[] engineGetIV() {
+        byte[] x = new byte[8];
+        return x;
+    }
+
+    protected AlgorithmParameters engineGetParameters() {
+        return null;
+    }
+
+    protected void engineInit(int mode, Key key, SecureRandom random) {}
+
+    protected void engineInit(int mode, Key key,
+                              AlgorithmParameterSpec params,
+                              SecureRandom random) {}
+
+    protected void engineInit(int mode, Key key,
+                              AlgorithmParameters params,
+                              SecureRandom random) {}
+
+    protected byte[] engineUpdate(byte[] input, int inputOffset,
+                                  int inputLen) {
+        if (input == null) return null;
+        byte[] x = new byte[inputLen];
+        System.arraycopy(input, inputOffset, x, 0, inputLen);
+        return x;
+    }
+
+    protected int engineUpdate(byte[] input, int inputOffset,
+                               int inputLen, byte[] output,
+                               int outputOffset) {
+        if (input == null) return 0;
+        System.arraycopy(input, inputOffset, output, outputOffset, inputLen);
+        return inputLen;
+    }
+
+    protected byte[] engineDoFinal(byte[] input, int inputOffset,
+                                   int inputLen)
+    {
+        return engineUpdate(input, inputOffset, inputLen);
+    }
+
+    protected int engineDoFinal(byte[] input, int inputOffset,
+                                int inputLen, byte[] output,
+                                int outputOffset)
+    {
+        return engineUpdate(input, inputOffset, inputLen,
+                            output, outputOffset);
+    }
+
+    protected int engineGetKeySize(Key key)
+    {
+        return 0;
+    }
+}

Added: openjdk-crypto/trunk/src/main/java/javax/crypto/SealedObject.java
===================================================================
--- openjdk-crypto/trunk/src/main/java/javax/crypto/SealedObject.java	                        (rev 0)
+++ openjdk-crypto/trunk/src/main/java/javax/crypto/SealedObject.java	2010-03-13 04:23:29 UTC (rev 25)
@@ -0,0 +1,497 @@
+/*
+ * Copyright 1997-2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.crypto;
+
+import java.io.*;
+import java.security.AlgorithmParameters;
+import java.security.Key;
+import java.security.InvalidKeyException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+
+/**
+ * This class enables a programmer to create an object and protect its
+ * confidentiality with a cryptographic algorithm.
+ *
+ * <p> Given any Serializable object, one can create a SealedObject
+ * that encapsulates the original object, in serialized
+ * format (i.e., a "deep copy"), and seals (encrypts) its serialized contents,
+ * using a cryptographic algorithm such as DES, to protect its
+ * confidentiality.  The encrypted content can later be decrypted (with
+ * the corresponding algorithm using the correct decryption key) and
+ * de-serialized, yielding the original object.
+ *
+ * <p> Note that the Cipher object must be fully initialized with the
+ * correct algorithm, key, padding scheme, etc., before being applied
+ * to a SealedObject.
+ *
+ * <p> The original object that was sealed can be recovered in two different
+ * ways: <p>
+ *
+ * <ul>
+ *
+ * <li>by using the {@link #getObject(javax.crypto.Cipher) getObject}
+ * method that takes a <code>Cipher</code> object.
+ *
+ * <p> This method requires a fully initialized <code>Cipher</code> object,
+ * initialized with the
+ * exact same algorithm, key, padding scheme, etc., that were used to seal the
+ * object.
+ *
+ * <p> This approach has the advantage that the party who unseals the
+ * sealed object does not require knowledge of the decryption key. For example,
+ * after one party has initialized the cipher object with the required
+ * decryption key, it could hand over the cipher object to
+ * another party who then unseals the sealed object.
+ *
+ * <p>
+ *
+ * <li>by using one of the
+ * {@link #getObject(java.security.Key) getObject} methods
+ * that take a <code>Key</code> object.
+ *
+ * <p> In this approach, the <code>getObject</code> method creates a cipher
+ * object for the appropriate decryption algorithm and initializes it with the
+ * given decryption key and the algorithm parameters (if any) that were stored
+ * in the sealed object.
+ *
+ * <p> This approach has the advantage that the party who
+ * unseals the object does not need to keep track of the parameters (e.g., an
+ * IV) that were used to seal the object.
+ *
+ * </ul>
+ *
+ * @author Li Gong
+ * @author Jan Luehe
+ * @see Cipher
+ * @since 1.4
+ */
+
+public class SealedObject implements Serializable {
+
+    static final long serialVersionUID = 4482838265551344752L;
+
+    /**
+     * The serialized object contents in encrypted format.
+     *
+     * @serial
+     */
+    private byte[] encryptedContent = null;
+
+    /**
+     * The algorithm that was used to seal this object.
+     *
+     * @serial
+     */
+    private String sealAlg = null;
+
+    /**
+     * The algorithm of the parameters used.
+     *
+     * @serial
+     */
+    private String paramsAlg = null;
+
+    /**
+     * The cryptographic parameters used by the sealing Cipher,
+     * encoded in the default format.
+     * <p>
+     * That is, <code>cipher.getParameters().getEncoded()</code>.
+     *
+     * @serial
+     */
+    protected byte[] encodedParams = null;
+
+    /**
+     * Constructs a SealedObject from any Serializable object.
+     *
+     * <p>The given object is serialized, and its serialized contents are
+     * encrypted using the given Cipher, which must be fully initialized.
+     *
+     * <p>Any algorithm parameters that may be used in the encryption
+     * operation are stored inside of the new <code>SealedObject</code>.
+     *
+     * @param object the object to be sealed; can be null.
+     * @param c the cipher used to seal the object.
+     *
+     * @exception NullPointerException if the given cipher is null.
+     * @exception IOException if an error occurs during serialization
+     * @exception IllegalBlockSizeException if the given cipher is a block
+     * cipher, no padding has been requested, and the total input length
+     * (i.e., the length of the serialized object contents) is not a multiple
+     * of the cipher's block size
+     */
+    public SealedObject(Serializable object, Cipher c) throws IOException,
+        IllegalBlockSizeException
+    {
+        /*
+         * Serialize the object
+         */
+
+        // creating a stream pipe-line, from a to b
+        ByteArrayOutputStream b = new ByteArrayOutputStream();
+        ObjectOutput a = new ObjectOutputStream(b);
+        byte[] content;
+        try {
+            // write and flush the object content to byte array
+            a.writeObject(object);
+            a.flush();
+            content = b.toByteArray();
+        } finally {
+            a.close();
+        }
+
+        /*
+         * Seal the object
+         */
+        try {
+            this.encryptedContent = c.doFinal(content);
+        }
+        catch (BadPaddingException ex) {
+            // if sealing is encryption only
+            // Should never happen??
+        }
+
+        // Save the parameters
+        if (c.getParameters() != null) {
+            this.encodedParams = c.getParameters().getEncoded();
+            this.paramsAlg = c.getParameters().getAlgorithm();
+        }
+
+        // Save the encryption algorithm
+        this.sealAlg = c.getAlgorithm();
+    }
+
+    /**
+     * Constructs a SealedObject object from the passed-in SealedObject.
+     *
+     * @param so a SealedObject object
+     * @exception NullPointerException if the given sealed object is null.
+     */
+    protected SealedObject(SealedObject so) {
+        this.encryptedContent = (byte[]) so.encryptedContent.clone();
+        this.sealAlg = so.sealAlg;
+        this.paramsAlg = so.paramsAlg;
+        if (so.encodedParams != null) {
+            this.encodedParams = (byte[]) so.encodedParams.clone();
+        } else {
+            this.encodedParams = null;
+        }
+    }
+
+    /**
+     * Returns the algorithm that was used to seal this object.
+     *
+     * @return the algorithm that was used to seal this object.
+     */
+    public final String getAlgorithm() {
+        return this.sealAlg;
+    }
+
+    /**
+     * Retrieves the original (encapsulated) object.
+     *
+     * <p>This method creates a cipher for the algorithm that had been used in
+     * the sealing operation.
+     * If the default provider package provides an implementation of that
+     * algorithm, an instance of Cipher containing that implementation is used.
+     * If the algorithm is not available in the default package, other
+     * packages are searched.
+     * The Cipher object is initialized for decryption, using the given
+     * <code>key</code> and the parameters (if any) that had been used in the
+     * sealing operation.
+     *
+     * <p>The encapsulated object is unsealed and de-serialized, before it is
+     * returned.
+     *
+     * @param key the key used to unseal the object.
+     *
+     * @return the original object.
+     *
+     * @exception IOException if an error occurs during de-serialiazation.
+     * @exception ClassNotFoundException if an error occurs during
+     * de-serialiazation.
+     * @exception NoSuchAlgorithmException if the algorithm to unseal the
+     * object is not available.
+     * @exception InvalidKeyException if the given key cannot be used to unseal
+     * the object (e.g., it has the wrong algorithm).
+     * @exception NullPointerException if <code>key</code> is null.
+     */
+    public final Object getObject(Key key)
+        throws IOException, ClassNotFoundException, NoSuchAlgorithmException,
+            InvalidKeyException
+    {
+        if (key == null) {
+            throw new NullPointerException("key is null");
+        }
+
+        try {
+            return unseal(key, null);
+        } catch (NoSuchProviderException nspe) {
+            // we've already caught NoSuchProviderException's and converted
+            // them into NoSuchAlgorithmException's with details about
+            // the failing algorithm
+            throw new NoSuchAlgorithmException("algorithm not found");
+        } catch (IllegalBlockSizeException ibse) {
+            throw new InvalidKeyException(ibse.getMessage());
+        } catch (BadPaddingException bpe) {
+            throw new InvalidKeyException(bpe.getMessage());
+        }
+    }
+
+    /**
+     * Retrieves the original (encapsulated) object.
+     *
+     * <p>The encapsulated object is unsealed (using the given Cipher,
+     * assuming that the Cipher is already properly initialized) and
+     * de-serialized, before it is returned.
+     *
+     * @param c the cipher used to unseal the object
+     *
+     * @return the original object.
+     *
+     * @exception NullPointerException if the given cipher is null.
+     * @exception IOException if an error occurs during de-serialiazation
+     * @exception ClassNotFoundException if an error occurs during
+     * de-serialiazation
+     * @exception IllegalBlockSizeException if the given cipher is a block
+     * cipher, no padding has been requested, and the total input length is
+     * not a multiple of the cipher's block size
+     * @exception BadPaddingException if the given cipher has been
+     * initialized for decryption, and padding has been specified, but
+     * the input data does not have proper expected padding bytes
+     */
+    public final Object getObject(Cipher c)
+        throws IOException, ClassNotFoundException, IllegalBlockSizeException,
+            BadPaddingException
+    {
+        /*
+         * Unseal the object
+         */
+        byte[] content = c.doFinal(this.encryptedContent);
+
+        /*
+         * De-serialize it
+         */
+        // creating a stream pipe-line, from b to a
+        ByteArrayInputStream b = new ByteArrayInputStream(content);
+        ObjectInput a = new extObjectInputStream(b);
+        try {
+            Object obj = a.readObject();
+            return obj;
+        } finally {
+            a.close();
+        }
+    }
+
+    /**
+     * Retrieves the original (encapsulated) object.
+     *
+     * <p>This method creates a cipher for the algorithm that had been used in
+     * the sealing operation, using an implementation of that algorithm from
+     * the given <code>provider</code>.
+     * The Cipher object is initialized for decryption, using the given
+     * <code>key</code> and the parameters (if any) that had been used in the
+     * sealing operation.
+     *
+     * <p>The encapsulated object is unsealed and de-serialized, before it is
+     * returned.
+     *
+     * @param key the key used to unseal the object.
+     * @param provider the name of the provider of the algorithm to unseal
+     * the object.
+     *
+     * @return the original object.
+     *
+     * @exception IllegalArgumentException if the given provider is null
+     * or empty.
+     * @exception IOException if an error occurs during de-serialiazation.
+     * @exception ClassNotFoundException if an error occurs during
+     * de-serialiazation.
+     * @exception NoSuchAlgorithmException if the algorithm to unseal the
+     * object is not available.
+     * @exception NoSuchProviderException if the given provider is not
+     * configured.
+     * @exception InvalidKeyException if the given key cannot be used to unseal
+     * the object (e.g., it has the wrong algorithm).
+     * @exception NullPointerException if <code>key</code> is null.
+     */
+    public final Object getObject(Key key, String provider)
+        throws IOException, ClassNotFoundException, NoSuchAlgorithmException,
+            NoSuchProviderException, InvalidKeyException
+    {
+        if (key == null) {
+            throw new NullPointerException("key is null");
+        }
+        if (provider == null || provider.length() == 0) {
+            throw new IllegalArgumentException("missing provider");
+        }
+
+        try {
+            return unseal(key, provider);
+        } catch (IllegalBlockSizeException ibse) {
+            throw new InvalidKeyException(ibse.getMessage());
+        } catch (BadPaddingException bpe) {
+            throw new InvalidKeyException(bpe.getMessage());
+        }
+    }
+
+
+    private Object unseal(Key key, String provider)
+        throws IOException, ClassNotFoundException, NoSuchAlgorithmException,
+            NoSuchProviderException, InvalidKeyException,
+            IllegalBlockSizeException, BadPaddingException
+    {
+        /*
+         * Create the parameter object.
+         */
+        AlgorithmParameters params = null;
+        if (this.encodedParams != null) {
+            try {
+                if (provider != null)
+                    params = AlgorithmParameters.getInstance(this.paramsAlg,
+                                                             provider);
+                else
+                    params = AlgorithmParameters.getInstance(this.paramsAlg);
+
+            } catch (NoSuchProviderException nspe) {
+                if (provider == null) {
+                    throw new NoSuchAlgorithmException(this.paramsAlg
+                                                       + " not found");
+                } else {
+                    throw new NoSuchProviderException(nspe.getMessage());
+                }
+            }
+            params.init(this.encodedParams);
+        }
+
+        /*
+         * Create and initialize the cipher.
+         */
+        Cipher c;
+        try {
+            if (provider != null)
+                c = Cipher.getInstance(this.sealAlg, provider);
+            else
+                c = Cipher.getInstance(this.sealAlg);
+        } catch (NoSuchPaddingException nspe) {
+            throw new NoSuchAlgorithmException("Padding that was used in "
+                                               + "sealing operation not "
+                                               + "available");
+        } catch (NoSuchProviderException nspe) {
+            if (provider == null) {
+                throw new NoSuchAlgorithmException(this.sealAlg+" not found");
+            } else {
+                throw new NoSuchProviderException(nspe.getMessage());
+            }
+        }
+
+        try {
+            if (params != null)
+                c.init(Cipher.DECRYPT_MODE, key, params);
+            else
+                c.init(Cipher.DECRYPT_MODE, key);
+        } catch (InvalidAlgorithmParameterException iape) {
+            // this should never happen, because we use the exact same
+            // parameters that were used in the sealing operation
+            throw new RuntimeException(iape.getMessage());
+        }
+
+        /*
+         * Unseal the object
+         */
+        byte[] content = c.doFinal(this.encryptedContent);
+
+        /*
+         * De-serialize it
+         */
+        // creating a stream pipe-line, from b to a
+        ByteArrayInputStream b = new ByteArrayInputStream(content);
+        ObjectInput a = new extObjectInputStream(b);
+        try {
+            Object obj = a.readObject();
+            return obj;
+        } finally {
+            a.close();
+        }
+    }
+
+    /**
+     * Restores the state of the SealedObject from a stream.
+     * @param s the object input stream.
+     * @exception NullPointerException if s is null.
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException
+    {
+        s.defaultReadObject();
+        if (encryptedContent != null)
+            encryptedContent = (byte[])encryptedContent.clone();
+        if (encodedParams != null)
+            encodedParams = (byte[])encodedParams.clone();
+    }
+}
+
+final class extObjectInputStream extends ObjectInputStream {
+
+    private static ClassLoader systemClassLoader = null;
+
+    extObjectInputStream(InputStream in)
+        throws IOException, StreamCorruptedException {
+        super(in);
+    }
+
+    protected Class resolveClass(ObjectStreamClass v)
+        throws IOException, ClassNotFoundException
+    {
+
+        try {
+            /*
+             * Calling the super.resolveClass() first
+             * will let us pick up bug fixes in the super
+             * class (e.g., 4171142).
+             */
+            return super.resolveClass(v);
+        } catch (ClassNotFoundException cnfe) {
+            /*
+             * This is a workaround for bug 4224921.
+             */
+            ClassLoader loader = Thread.currentThread().getContextClassLoader();
+            if (loader == null) {
+                if (systemClassLoader == null) {
+                    systemClassLoader = ClassLoader.getSystemClassLoader();
+                }
+                loader = systemClassLoader;
+                if (loader == null) {
+                    throw new ClassNotFoundException(v.getName());
+                }
+            }
+
+            return Class.forName(v.getName(), false, loader);
+        }
+    }
+}

Added: openjdk-crypto/trunk/src/main/java/javax/crypto/SecretKey.java
===================================================================
--- openjdk-crypto/trunk/src/main/java/javax/crypto/SecretKey.java	                        (rev 0)
+++ openjdk-crypto/trunk/src/main/java/javax/crypto/SecretKey.java	2010-03-13 04:23:29 UTC (rev 25)
@@ -0,0 +1,58 @@
+/*
+ * Copyright 1997-2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.crypto;
+
+/**
+ * A secret (symmetric) key.
+ *
+ * <p>This interface contains no methods or constants.
+ * Its only purpose is to group (and provide type safety for) secret keys.
+ *
+ * <p>Provider implementations of this interface must overwrite the
+ * <code>equals</code> and <code>hashCode</code> methods inherited from
+ * <code>java.lang.Object</code>, so that secret keys are compared based on
+ * their underlying key material and not based on reference.
+ *
+ * <p>Keys that implement this interface return the string <code>RAW</code>
+ * as their encoding format (see <code>getFormat</code>), and return the
+ * raw key bytes as the result of a <code>getEncoded</code> method call. (The
+ * <code>getFormat</code> and <code>getEncoded</code> methods are inherited
+ * from the <code>java.security.Key</code> parent interface.)
+ *
+ * @author Jan Luehe
+ *
+ * @see SecretKeyFactory
+ * @see Cipher
+ * @since 1.4
+ */
+
+public interface SecretKey extends java.security.Key {
+    /**
+     * The class fingerprint that is set to indicate serialization
+     * compatibility since J2SE 1.4.
+     */
+    static final long serialVersionUID = -4795878709595146952L;
+}

Added: openjdk-crypto/trunk/src/main/java/javax/crypto/SecretKeyFactory.java
===================================================================
--- openjdk-crypto/trunk/src/main/java/javax/crypto/SecretKeyFactory.java	                        (rev 0)
+++ openjdk-crypto/trunk/src/main/java/javax/crypto/SecretKeyFactory.java	2010-03-13 04:23:29 UTC (rev 25)
@@ -0,0 +1,415 @@
+/*
+ * Copyright 1997-2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.crypto;
+
+import java.util.*;
+
+import java.security.*;
+import java.security.Provider.Service;
+import java.security.spec.*;
+
+import sun.security.jca.*;
+import sun.security.jca.GetInstance.Instance;
+
+/**
+ * This class represents a factory for secret keys.
+ *
+ * <P> Key factories are used to convert <I>keys</I> (opaque
+ * cryptographic keys of type <code>Key</code>) into <I>key specifications</I>
+ * (transparent representations of the underlying key material), and vice
+ * versa.
+ * Secret key factories operate only on secret (symmetric) keys.
+ *
+ * <P> Key factories are bi-directional, i.e., they allow to build an opaque
+ * key object from a given key specification (key material), or to retrieve
+ * the underlying key material of a key object in a suitable format.
+ *
+ * <P> Application developers should refer to their provider's documentation
+ * to find out which key specifications are supported by the
+ * {@link #generateSecret(java.security.spec.KeySpec) generateSecret} and
+ * {@link #getKeySpec(javax.crypto.SecretKey, java.lang.Class) getKeySpec}
+ * methods.
+ * For example, the DES secret-key factory supplied by the "SunJCE" provider
+ * supports <code>DESKeySpec</code> as a transparent representation of DES
+ * keys, and that provider's secret-key factory for Triple DES keys supports
+ * <code>DESedeKeySpec</code> as a transparent representation of Triple DES
+ * keys.
+ *
+ * @author Jan Luehe
+ *
+ * @see SecretKey
+ * @see javax.crypto.spec.DESKeySpec
+ * @see javax.crypto.spec.DESedeKeySpec
+ * @see javax.crypto.spec.PBEKeySpec
+ * @since 1.4
+ */
+
+public class SecretKeyFactory {
+
+    // The provider
+    private Provider provider;
+
+    // The algorithm associated with this factory
+    private final String algorithm;
+
+    // The provider implementation (delegate)
+    private volatile SecretKeyFactorySpi spi;
+
+    // lock for mutex during provider selection
+    private final Object lock = new Object();
+
+    // remaining services to try in provider selection
+    // null once provider is selected
+    private Iterator serviceIterator;
+
+    /**
+     * Creates a SecretKeyFactory object.
+     *
+     * @param keyFacSpi the delegate
+     * @param provider the provider
+     * @param algorithm the secret-key algorithm
+     */
+    protected SecretKeyFactory(SecretKeyFactorySpi keyFacSpi,
+                               Provider provider, String algorithm) {
+        this.spi = keyFacSpi;
+        this.provider = provider;
+        this.algorithm = algorithm;
+    }
+
+    private SecretKeyFactory(String algorithm) throws NoSuchAlgorithmException {
+        this.algorithm = algorithm;
+        List list = GetInstance.getServices("SecretKeyFactory", algorithm);
+        serviceIterator = list.iterator();
+        // fetch and instantiate initial spi
+        if (nextSpi(null) == null) {
+            throw new NoSuchAlgorithmException
+                (algorithm + " SecretKeyFactory not available");
+        }
+    }
+
+    /**
+     * Returns a <code>SecretKeyFactory</code> object that converts
+     * secret keys of the specified algorithm.
+     *
+     * <p> This method traverses the list of registered security Providers,
+     * starting with the most preferred Provider.
+     * A new SecretKeyFactory object encapsulating the
+     * SecretKeyFactorySpi implementation from the first
+     * Provider that supports the specified algorithm is returned.
+     *
+     * <p> Note that the list of registered providers may be retrieved via
+     * the {@link Security#getProviders() Security.getProviders()} method.
+     *
+     * @param algorithm the standard name of the requested secret-key
+     * algorithm.
+     * See Appendix A in the <a href=
+     *   "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     * Java Cryptography Architecture Reference Guide</a>
+     * for information about standard algorithm names.
+     *
+     * @return the new <code>SecretKeyFactory</code> object.
+     *
+     * @exception NullPointerException if the specified algorithm
+     *          is null.
+     *
+     * @exception NoSuchAlgorithmException if no Provider supports a
+     *          SecretKeyFactorySpi implementation for the
+     *          specified algorithm.
+     *
+     * @see java.security.Provider
+     */
+    public static final SecretKeyFactory getInstance(String algorithm)
+            throws NoSuchAlgorithmException {
+        return new SecretKeyFactory(algorithm);
+    }
+
+    /**
+     * Returns a <code>SecretKeyFactory</code> object that converts
+     * secret keys of the specified algorithm.
+     *
+     * <p> A new SecretKeyFactory object encapsulating the
+     * SecretKeyFactorySpi implementation from the specified provider
+     * is returned.  The specified provider must be registered
+     * in the security provider list.
+     *
+     * <p> Note that the list of registered providers may be retrieved via
+     * the {@link Security#getProviders() Security.getProviders()} method.
+     *
+     * @param algorithm the standard name of the requested secret-key
+     * algorithm.
+     * See Appendix A in the <a href=
+     *   "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     * Java Cryptography Architecture Reference Guide</a>
+     * for information about standard algorithm names.
+     *
+     * @param provider the name of the provider.
+     *
+     * @return the new <code>SecretKeyFactory</code> object.
+     *
+     * @exception NoSuchAlgorithmException if a SecretKeyFactorySpi
+     *          implementation for the specified algorithm is not
+     *          available from the specified provider.
+     *
+     * @exception NullPointerException if the specified algorithm
+     *          is null.
+     *
+     * @throws NoSuchProviderException if the specified provider is not
+     *          registered in the security provider list.
+     *
+     * @exception IllegalArgumentException if the <code>provider</code>
+     *          is null or empty.
+     *
+     * @see java.security.Provider
+     */
+    public static final SecretKeyFactory getInstance(String algorithm,
+            String provider) throws NoSuchAlgorithmException,
+            NoSuchProviderException {
+        Instance instance = JceSecurity.getInstance("SecretKeyFactory",
+                SecretKeyFactorySpi.class, algorithm, provider);
+        return new SecretKeyFactory((SecretKeyFactorySpi)instance.impl,
+                instance.provider, algorithm);
+    }
+
+    /**
+     * Returns a <code>SecretKeyFactory</code> object that converts
+     * secret keys of the specified algorithm.
+     *
+     * <p> A new SecretKeyFactory object encapsulating the
+     * SecretKeyFactorySpi implementation from the specified Provider
+     * object is returned.  Note that the specified Provider object
+     * does not have to be registered in the provider list.
+     *
+     * @param algorithm the standard name of the requested secret-key
+     * algorithm.
+     * See Appendix A in the <a href=
+     *   "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     * Java Cryptography Architecture Reference Guide</a>
+     * for information about standard algorithm names.
+     *
+     * @param provider the provider.
+     *
+     * @return the new <code>SecretKeyFactory</code> object.
+     *
+     * @exception NullPointerException if the specified algorithm
+     * is null.
+     *
+     * @exception NoSuchAlgorithmException if a SecretKeyFactorySpi
+     *          implementation for the specified algorithm is not available
+     *          from the specified Provider object.
+     *
+     * @exception IllegalArgumentException if the <code>provider</code>
+     *          is null.
+     *
+     * @see java.security.Provider
+     */
+    public static final SecretKeyFactory getInstance(String algorithm,
+            Provider provider) throws NoSuchAlgorithmException {
+        Instance instance = JceSecurity.getInstance("SecretKeyFactory",
+                SecretKeyFactorySpi.class, algorithm, provider);
+        return new SecretKeyFactory((SecretKeyFactorySpi)instance.impl,
+                instance.provider, algorithm);
+    }
+
+    /**
+     * Returns the provider of this <code>SecretKeyFactory</code> object.
+     *
+     * @return the provider of this <code>SecretKeyFactory</code> object
+     */
+    public final Provider getProvider() {
+        synchronized (lock) {
+            // disable further failover after this call
+            serviceIterator = null;
+            return provider;
+        }
+    }
+
+    /**
+     * Returns the algorithm name of this <code>SecretKeyFactory</code> object.
+     *
+     * <p>This is the same name that was specified in one of the
+     * <code>getInstance</code> calls that created this
+     * <code>SecretKeyFactory</code> object.
+     *
+     * @return the algorithm name of this <code>SecretKeyFactory</code>
+     * object.
+     */
+    public final String getAlgorithm() {
+        return this.algorithm;
+    }
+
+    /**
+     * Update the active spi of this class and return the next
+     * implementation for failover. If no more implemenations are
+     * available, this method returns null. However, the active spi of
+     * this class is never set to null.
+     */
+    private SecretKeyFactorySpi nextSpi(SecretKeyFactorySpi oldSpi) {
+        synchronized (lock) {
+            // somebody else did a failover concurrently
+            // try that spi now
+            if ((oldSpi != null) && (oldSpi != spi)) {
+                return spi;
+            }
+            if (serviceIterator == null) {
+                return null;
+            }
+            while (serviceIterator.hasNext()) {
+                Service s = (Service)serviceIterator.next();
+                if (JceSecurity.canUseProvider(s.getProvider()) == false) {
+                    continue;
+                }
+                try {
+                    Object obj = s.newInstance(null);
+                    if (obj instanceof SecretKeyFactorySpi == false) {
+                        continue;
+                    }
+                    SecretKeyFactorySpi spi = (SecretKeyFactorySpi)obj;
+                    provider = s.getProvider();
+                    this.spi = spi;
+                    return spi;
+                } catch (NoSuchAlgorithmException e) {
+                    // ignore
+                }
+            }
+            serviceIterator = null;
+            return null;
+        }
+    }
+
+    /**
+     * Generates a <code>SecretKey</code> object from the provided key
+     * specification (key material).
+     *
+     * @param keySpec the specification (key material) of the secret key
+     *
+     * @return the secret key
+     *
+     * @exception InvalidKeySpecException if the given key specification
+     * is inappropriate for this secret-key factory to produce a secret key.
+     */
+    public final SecretKey generateSecret(KeySpec keySpec)
+            throws InvalidKeySpecException {
+        if (serviceIterator == null) {
+            return spi.engineGenerateSecret(keySpec);
+        }
+        Exception failure = null;
+        SecretKeyFactorySpi mySpi = spi;
+        do {
+            try {
+                return mySpi.engineGenerateSecret(keySpec);
+            } catch (Exception e) {
+                if (failure == null) {
+                    failure = e;
+                }
+                mySpi = nextSpi(mySpi);
+            }
+        } while (mySpi != null);
+        if (failure instanceof InvalidKeySpecException) {
+            throw (InvalidKeySpecException)failure;
+        }
+        throw new InvalidKeySpecException
+                ("Could not generate secret key", failure);
+    }
+
+    /**
+     * Returns a specification (key material) of the given key object
+     * in the requested format.
+     *
+     * @param key the key
+     * @param keySpec the requested format in which the key material shall be
+     * returned
+     *
+     * @return the underlying key specification (key material) in the
+     * requested format
+     *
+     * @exception InvalidKeySpecException if the requested key specification is
+     * inappropriate for the given key (e.g., the algorithms associated with
+     * <code>key</code> and <code>keySpec</code> do not match, or
+     * <code>key</code> references a key on a cryptographic hardware device
+     * whereas <code>keySpec</code> is the specification of a software-based
+     * key), or the given key cannot be dealt with
+     * (e.g., the given key has an algorithm or format not supported by this
+     * secret-key factory).
+     */
+    public final KeySpec getKeySpec(SecretKey key, Class keySpec)
+            throws InvalidKeySpecException {
+        if (serviceIterator == null) {
+            return spi.engineGetKeySpec(key, keySpec);
+        }
+        Exception failure = null;
+        SecretKeyFactorySpi mySpi = spi;
+        do {
+            try {
+                return mySpi.engineGetKeySpec(key, keySpec);
+            } catch (Exception e) {
+                if (failure == null) {
+                    failure = e;
+                }
+                mySpi = nextSpi(mySpi);
+            }
+        } while (mySpi != null);
+        if (failure instanceof InvalidKeySpecException) {
+            throw (InvalidKeySpecException)failure;
+        }
+        throw new InvalidKeySpecException
+                ("Could not get key spec", failure);
+    }
+
+    /**
+     * Translates a key object, whose provider may be unknown or potentially
+     * untrusted, into a corresponding key object of this secret-key factory.
+     *
+     * @param key the key whose provider is unknown or untrusted
+     *
+     * @return the translated key
+     *
+     * @exception InvalidKeyException if the given key cannot be processed
+     * by this secret-key factory.
+     */
+    public final SecretKey translateKey(SecretKey key)
+            throws InvalidKeyException {
+        if (serviceIterator == null) {
+            return spi.engineTranslateKey(key);
+        }
+        Exception failure = null;
+        SecretKeyFactorySpi mySpi = spi;
+        do {
+            try {
+                return mySpi.engineTranslateKey(key);
+            } catch (Exception e) {
+                if (failure == null) {
+                    failure = e;
+                }
+                mySpi = nextSpi(mySpi);
+            }
+        } while (mySpi != null);
+        if (failure instanceof InvalidKeyException) {
+            throw (InvalidKeyException)failure;
+        }
+        throw new InvalidKeyException
+                ("Could not translate key", failure);
+    }
+}

Added: openjdk-crypto/trunk/src/main/java/javax/crypto/SecretKeyFactorySpi.java
===================================================================
--- openjdk-crypto/trunk/src/main/java/javax/crypto/SecretKeyFactorySpi.java	                        (rev 0)
+++ openjdk-crypto/trunk/src/main/java/javax/crypto/SecretKeyFactorySpi.java	2010-03-13 04:23:29 UTC (rev 25)
@@ -0,0 +1,108 @@
+/*
+ * Copyright 1997-2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.crypto;
+
+import java.security.*;
+import java.security.spec.*;
+
+/**
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
+ * for the <code>SecretKeyFactory</code> class.
+ * All the abstract methods in this class must be implemented by each
+ * cryptographic service provider who wishes to supply the implementation
+ * of a secret-key factory for a particular algorithm.
+ *
+ * <P> A provider should document all the key specifications supported by its
+ * secret key factory.
+ * For example, the DES secret-key factory supplied by the "SunJCE" provider
+ * supports <code>DESKeySpec</code> as a transparent representation of DES
+ * keys, and that provider's secret-key factory for Triple DES keys supports
+ * <code>DESedeKeySpec</code> as a transparent representation of Triple DES
+ * keys.
+ *
+ * @author Jan Luehe
+ *
+ * @see SecretKey
+ * @see javax.crypto.spec.DESKeySpec
+ * @see javax.crypto.spec.DESedeKeySpec
+ * @since 1.4
+ */
+
+public abstract class SecretKeyFactorySpi {
+
+    /**
+     * Generates a <code>SecretKey</code> object from the
+     * provided key specification (key material).
+     *
+     * @param keySpec the specification (key material) of the secret key
+     *
+     * @return the secret key
+     *
+     * @exception InvalidKeySpecException if the given key specification
+     * is inappropriate for this secret-key factory to produce a secret key.
+     */
+    protected abstract SecretKey engineGenerateSecret(KeySpec keySpec)
+        throws InvalidKeySpecException;
+
+    /**
+     * Returns a specification (key material) of the given key
+     * object in the requested format.
+     *
+     * @param key the key
+     *
+     * @param keySpec the requested format in which the key material shall be
+     * returned
+     *
+     * @return the underlying key specification (key material) in the
+     * requested format
+     *
+     * @exception InvalidKeySpecException if the requested key specification is
+     * inappropriate for the given key (e.g., the algorithms associated with
+     * <code>key</code> and <code>keySpec</code> do not match, or
+     * <code>key</code> references a key on a cryptographic hardware device
+     * whereas <code>keySpec</code> is the specification of a software-based
+     * key), or the given key cannot be dealt with
+     * (e.g., the given key has an algorithm or format not supported by this
+     * secret-key factory).
+     */
+    protected abstract KeySpec engineGetKeySpec(SecretKey key, Class keySpec)
+        throws InvalidKeySpecException;
+
+    /**
+     * Translates a key object, whose provider may be unknown or
+     * potentially untrusted, into a corresponding key object of this
+     * secret-key factory.
+     *
+     * @param key the key whose provider is unknown or untrusted
+     *
+     * @return the translated key
+     *
+     * @exception InvalidKeyException if the given key cannot be processed
+     * by this secret-key factory.
+     */
+    protected abstract SecretKey engineTranslateKey(SecretKey key)
+        throws InvalidKeyException;
+}

Added: openjdk-crypto/trunk/src/main/java/javax/crypto/ShortBufferException.java
===================================================================
--- openjdk-crypto/trunk/src/main/java/javax/crypto/ShortBufferException.java	                        (rev 0)
+++ openjdk-crypto/trunk/src/main/java/javax/crypto/ShortBufferException.java	2010-03-13 04:23:29 UTC (rev 25)
@@ -0,0 +1,61 @@
+/*
+ * Copyright 1997-2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.crypto;
+
+import java.security.GeneralSecurityException;
+
+/**
+ * This exception is thrown when an output buffer provided by the user
+ * is too short to hold the operation result.
+ *
+ * @author Jan Luehe
+ *
+ * @since 1.4
+ */
+
+public class ShortBufferException extends GeneralSecurityException {
+
+    private static final long serialVersionUID = 8427718640832943747L;
+
+    /**
+     * Constructs a ShortBufferException with no detail
+     * message. A detail message is a String that describes this
+     * particular exception.
+     */
+    public ShortBufferException() {
+        super();
+    }
+
+    /**
+     * Constructs a ShortBufferException with the specified
+     * detail message.
+     *
+     * @param msg the detail message.
+     */
+    public ShortBufferException(String msg) {
+        super(msg);
+    }
+}




More information about the pkg-eucalyptus-commits mailing list