--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/rsa/RSASignature.java Sun Aug 17 15:54:13 2014 +0100
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.rsa;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+import java.security.*;
+import java.security.interfaces.*;
+
+import sun.security.util.*;
+import sun.security.x509.AlgorithmId;
+
+/**
+ * PKCS#1 RSA signatures with the various message digest algorithms.
+ * This file contains an abstract base class with all the logic plus
+ * a nested static class for each of the message digest algorithms
+ * (see end of the file). We support MD2, MD5, SHA-1, SHA-224, SHA-256,
+ * SHA-384, and SHA-512.
+ *
+ * @since 1.5
+ * @author Andreas Sterbenz
+ */
+public abstract class RSASignature extends SignatureSpi {
+
+ // we sign an ASN.1 SEQUENCE of AlgorithmId and digest
+ // it has the form 30:xx:30:xx:[digestOID]:05:00:04:xx:[digest]
+ // this means the encoded length is (8 + digestOID.length + digest.length)
+ private static final int baseLength = 8;
+
+ // object identifier for the message digest algorithm used
+ private final ObjectIdentifier digestOID;
+
+ // length of the encoded signature blob
+ private final int encodedLength;
+
+ // message digest implementation we use
+ private final MessageDigest md;
+ // flag indicating whether the digest is reset
+ private boolean digestReset;
+
+ // private key, if initialized for signing
+ private RSAPrivateKey privateKey;
+ // public key, if initialized for verifying
+ private RSAPublicKey publicKey;
+
+ // padding to use, set when the initSign/initVerify is called
+ private RSAPadding padding;
+
+ /**
+ * Construct a new RSASignature. Used by subclasses.
+ */
+ RSASignature(String algorithm, ObjectIdentifier digestOID, int oidLength) {
+ this.digestOID = digestOID;
+ try {
+ md = MessageDigest.getInstance(algorithm);
+ } catch (NoSuchAlgorithmException e) {
+ throw new ProviderException(e);
+ }
+ digestReset = true;
+ encodedLength = baseLength + oidLength + md.getDigestLength();
+ }
+
+ // initialize for verification. See JCA doc
+ protected void engineInitVerify(PublicKey publicKey)
+ throws InvalidKeyException {
+ RSAPublicKey rsaKey = (RSAPublicKey)RSAKeyFactory.toRSAKey(publicKey);
+ this.privateKey = null;
+ this.publicKey = rsaKey;
+ initCommon(rsaKey, null);
+ }
+
+ // initialize for signing. See JCA doc
+ protected void engineInitSign(PrivateKey privateKey)
+ throws InvalidKeyException {
+ engineInitSign(privateKey, null);
+ }
+
+ // initialize for signing. See JCA doc
+ protected void engineInitSign(PrivateKey privateKey, SecureRandom random)
+ throws InvalidKeyException {
+ RSAPrivateKey rsaKey =
+ (RSAPrivateKey)RSAKeyFactory.toRSAKey(privateKey);
+ this.privateKey = rsaKey;
+ this.publicKey = null;
+ initCommon(rsaKey, random);
+ }
+
+ /**
+ * Init code common to sign and verify.
+ */
+ private void initCommon(RSAKey rsaKey, SecureRandom random)
+ throws InvalidKeyException {
+ resetDigest();
+ int keySize = RSACore.getByteLength(rsaKey);
+ try {
+ padding = RSAPadding.getInstance
+ (RSAPadding.PAD_BLOCKTYPE_1, keySize, random);
+ } catch (InvalidAlgorithmParameterException iape) {
+ throw new InvalidKeyException(iape.getMessage());
+ }
+ int maxDataSize = padding.getMaxDataSize();
+ if (encodedLength > maxDataSize) {
+ throw new InvalidKeyException
+ ("Key is too short for this signature algorithm");
+ }
+ }
+
+ /**
+ * Reset the message digest if it is not already reset.
+ */
+ private void resetDigest() {
+ if (digestReset == false) {
+ md.reset();
+ digestReset = true;
+ }
+ }
+
+ /**
+ * Return the message digest value.
+ */
+ private byte[] getDigestValue() {
+ digestReset = true;
+ return md.digest();
+ }
+
+ // update the signature with the plaintext data. See JCA doc
+ protected void engineUpdate(byte b) throws SignatureException {
+ md.update(b);
+ digestReset = false;
+ }
+
+ // update the signature with the plaintext data. See JCA doc
+ protected void engineUpdate(byte[] b, int off, int len)
+ throws SignatureException {
+ md.update(b, off, len);
+ digestReset = false;
+ }
+
+ // update the signature with the plaintext data. See JCA doc
+ protected void engineUpdate(ByteBuffer b) {
+ md.update(b);
+ digestReset = false;
+ }
+
+ // sign the data and return the signature. See JCA doc
+ protected byte[] engineSign() throws SignatureException {
+ byte[] digest = getDigestValue();
+ try {
+ byte[] encoded = encodeSignature(digestOID, digest);
+ byte[] padded = padding.pad(encoded);
+ byte[] encrypted = RSACore.rsa(padded, privateKey);
+ return encrypted;
+ } catch (GeneralSecurityException e) {
+ throw new SignatureException("Could not sign data", e);
+ } catch (IOException e) {
+ throw new SignatureException("Could not encode data", e);
+ }
+ }
+
+ // verify the data and return the result. See JCA doc
+ protected boolean engineVerify(byte[] sigBytes) throws SignatureException {
+ if (sigBytes.length != RSACore.getByteLength(publicKey)) {
+ throw new SignatureException("Signature length not correct: got " +
+ sigBytes.length + " but was expecting " +
+ RSACore.getByteLength(publicKey));
+ }
+ byte[] digest = getDigestValue();
+ try {
+ byte[] decrypted = RSACore.rsa(sigBytes, publicKey);
+ byte[] unpadded = padding.unpad(decrypted);
+ byte[] decodedDigest = decodeSignature(digestOID, unpadded);
+ return Arrays.equals(digest, decodedDigest);
+ } catch (javax.crypto.BadPaddingException e) {
+ // occurs if the app has used the wrong RSA public key
+ // or if sigBytes is invalid
+ // return false rather than propagating the exception for
+ // compatibility/ease of use
+ return false;
+ } catch (IOException e) {
+ throw new SignatureException("Signature encoding error", e);
+ }
+ }
+
+ /**
+ * Encode the digest, return the to-be-signed data.
+ * Also used by the PKCS#11 provider.
+ */
+ public static byte[] encodeSignature(ObjectIdentifier oid, byte[] digest)
+ throws IOException {
+ DerOutputStream out = new DerOutputStream();
+ new AlgorithmId(oid).encode(out);
+ out.putOctetString(digest);
+ DerValue result =
+ new DerValue(DerValue.tag_Sequence, out.toByteArray());
+ return result.toByteArray();
+ }
+
+ /**
+ * Decode the signature data. Verify that the object identifier matches
+ * and return the message digest.
+ */
+ public static byte[] decodeSignature(ObjectIdentifier oid, byte[] signature)
+ throws IOException {
+ DerInputStream in = new DerInputStream(signature);
+ DerValue[] values = in.getSequence(2);
+ if ((values.length != 2) || (in.available() != 0)) {
+ throw new IOException("SEQUENCE length error");
+ }
+ AlgorithmId algId = AlgorithmId.parse(values[0]);
+ if (algId.getOID().equals((Object)oid) == false) {
+ throw new IOException("ObjectIdentifier mismatch: "
+ + algId.getOID());
+ }
+ if (algId.getEncodedParams() != null) {
+ throw new IOException("Unexpected AlgorithmId parameters");
+ }
+ byte[] digest = values[1].getOctetString();
+ return digest;
+ }
+
+ // set parameter, not supported. See JCA doc
+ @Deprecated
+ protected void engineSetParameter(String param, Object value)
+ throws InvalidParameterException {
+ throw new UnsupportedOperationException("setParameter() not supported");
+ }
+
+ // get parameter, not supported. See JCA doc
+ @Deprecated
+ protected Object engineGetParameter(String param)
+ throws InvalidParameterException {
+ throw new UnsupportedOperationException("getParameter() not supported");
+ }
+
+ // Nested class for MD2withRSA signatures
+ public static final class MD2withRSA extends RSASignature {
+ public MD2withRSA() {
+ super("MD2", AlgorithmId.MD2_oid, 10);
+ }
+ }
+
+ // Nested class for MD5withRSA signatures
+ public static final class MD5withRSA extends RSASignature {
+ public MD5withRSA() {
+ super("MD5", AlgorithmId.MD5_oid, 10);
+ }
+ }
+
+ // Nested class for SHA1withRSA signatures
+ public static final class SHA1withRSA extends RSASignature {
+ public SHA1withRSA() {
+ super("SHA-1", AlgorithmId.SHA_oid, 7);
+ }
+ }
+
+ // Nested class for SHA224withRSA signatures
+ public static final class SHA224withRSA extends RSASignature {
+ public SHA224withRSA() {
+ super("SHA-224", AlgorithmId.SHA224_oid, 11);
+ }
+ }
+
+ // Nested class for SHA256withRSA signatures
+ public static final class SHA256withRSA extends RSASignature {
+ public SHA256withRSA() {
+ super("SHA-256", AlgorithmId.SHA256_oid, 11);
+ }
+ }
+
+ // Nested class for SHA384withRSA signatures
+ public static final class SHA384withRSA extends RSASignature {
+ public SHA384withRSA() {
+ super("SHA-384", AlgorithmId.SHA384_oid, 11);
+ }
+ }
+
+ // Nested class for SHA512withRSA signatures
+ public static final class SHA512withRSA extends RSASignature {
+ public SHA512withRSA() {
+ super("SHA-512", AlgorithmId.SHA512_oid, 11);
+ }
+ }
+
+}