From 554fd8c5195424bdbcabf5de30fdc183aba391bd Mon Sep 17 00:00:00 2001 From: upstream source tree Date: Sun, 15 Mar 2015 20:14:05 -0400 Subject: obtained gcc-4.6.4.tar.bz2 from upstream website; verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository. --- .../gnu/java/security/sig/BaseSignature.java | 219 ++++++++++++ .../gnu/java/security/sig/ISignature.java | 160 +++++++++ .../gnu/java/security/sig/ISignatureCodec.java | 59 ++++ .../java/security/sig/SignatureCodecFactory.java | 226 +++++++++++++ .../gnu/java/security/sig/SignatureFactory.java | 101 ++++++ .../gnu/java/security/sig/dss/DSSSignature.java | 275 +++++++++++++++ .../security/sig/dss/DSSSignatureRawCodec.java | 164 +++++++++ .../security/sig/dss/DSSSignatureX509Codec.java | 193 +++++++++++ .../gnu/java/security/sig/rsa/EME_PKCS1_V1_5.java | 274 +++++++++++++++ .../gnu/java/security/sig/rsa/EMSA_PKCS1_V1_5.java | 243 ++++++++++++++ .../gnu/java/security/sig/rsa/EMSA_PSS.java | 371 +++++++++++++++++++++ .../classpath/gnu/java/security/sig/rsa/RSA.java | 324 ++++++++++++++++++ .../security/sig/rsa/RSAPKCS1V1_5Signature.java | 224 +++++++++++++ .../sig/rsa/RSAPKCS1V1_5SignatureRawCodec.java | 153 +++++++++ .../sig/rsa/RSAPKCS1V1_5SignatureX509Codec.java | 128 +++++++ .../gnu/java/security/sig/rsa/RSAPSSSignature.java | 255 ++++++++++++++ .../security/sig/rsa/RSAPSSSignatureRawCodec.java | 134 ++++++++ .../java/security/sig/rsa/RSASignatureFactory.java | 176 ++++++++++ 18 files changed, 3679 insertions(+) create mode 100644 libjava/classpath/gnu/java/security/sig/BaseSignature.java create mode 100644 libjava/classpath/gnu/java/security/sig/ISignature.java create mode 100644 libjava/classpath/gnu/java/security/sig/ISignatureCodec.java create mode 100644 libjava/classpath/gnu/java/security/sig/SignatureCodecFactory.java create mode 100644 libjava/classpath/gnu/java/security/sig/SignatureFactory.java create mode 100644 libjava/classpath/gnu/java/security/sig/dss/DSSSignature.java create mode 100644 libjava/classpath/gnu/java/security/sig/dss/DSSSignatureRawCodec.java create mode 100644 libjava/classpath/gnu/java/security/sig/dss/DSSSignatureX509Codec.java create mode 100644 libjava/classpath/gnu/java/security/sig/rsa/EME_PKCS1_V1_5.java create mode 100644 libjava/classpath/gnu/java/security/sig/rsa/EMSA_PKCS1_V1_5.java create mode 100644 libjava/classpath/gnu/java/security/sig/rsa/EMSA_PSS.java create mode 100644 libjava/classpath/gnu/java/security/sig/rsa/RSA.java create mode 100644 libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5Signature.java create mode 100644 libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureRawCodec.java create mode 100644 libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureX509Codec.java create mode 100644 libjava/classpath/gnu/java/security/sig/rsa/RSAPSSSignature.java create mode 100644 libjava/classpath/gnu/java/security/sig/rsa/RSAPSSSignatureRawCodec.java create mode 100644 libjava/classpath/gnu/java/security/sig/rsa/RSASignatureFactory.java (limited to 'libjava/classpath/gnu/java/security/sig') diff --git a/libjava/classpath/gnu/java/security/sig/BaseSignature.java b/libjava/classpath/gnu/java/security/sig/BaseSignature.java new file mode 100644 index 000000000..ef4d87f26 --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/BaseSignature.java @@ -0,0 +1,219 @@ +/* BaseSignature.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +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. */ + + +package gnu.java.security.sig; + +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.util.PRNG; + +import java.security.PrivateKey; +import java.security.PublicKey; +import java.util.Map; +import java.util.Random; + +/** + * A base abstract class to facilitate implementations of concrete Signatures. + */ +public abstract class BaseSignature + implements ISignature +{ + /** The canonical name of this signature scheme. */ + protected String schemeName; + + /** The underlying message digest instance for this signature scheme. */ + protected IMessageDigest md; + + /** The public key to use when verifying signatures. */ + protected PublicKey publicKey; + + /** The private key to use when generating signatures (signing). */ + protected PrivateKey privateKey; + + /** The optional {@link Random} instance to use. */ + private Random rnd; + + /** The optional {@link IRandom} instance to use. */ + private IRandom irnd; + + /** Our default source of randomness. */ + private PRNG prng = null; + + /** + * Trivial constructor. + * + * @param schemeName the name of this signature scheme. + * @param md the underlying instance of the message digest algorithm. + * @throws IllegalArgumentException if the designated hash instance is + * null. + */ + protected BaseSignature(String schemeName, IMessageDigest md) + { + super(); + + this.schemeName = schemeName; + if (md == null) + throw new IllegalArgumentException("Message digest MUST NOT be null"); + + this.md = md; + } + + public String name() + { + return schemeName + "-" + md.name(); + } + + public void setupVerify(Map attributes) throws IllegalArgumentException + { + setup(attributes); + // do we have a public key? + PublicKey key = (PublicKey) attributes.get(VERIFIER_KEY); + if (key != null) + setupForVerification(key); + } + + public void setupSign(Map attributes) throws IllegalArgumentException + { + setup(attributes); + // do we have a private key? + PrivateKey key = (PrivateKey) attributes.get(SIGNER_KEY); + if (key != null) + setupForSigning(key); + } + + public void update(byte b) + { + if (md == null) + throw new IllegalStateException(); + + md.update(b); + } + + public void update(byte[] b, int off, int len) + { + if (md == null) + throw new IllegalStateException(); + + md.update(b, off, len); + } + + public Object sign() + { + if (md == null || privateKey == null) + throw new IllegalStateException(); + + return generateSignature(); + } + + public boolean verify(Object sig) + { + if (md == null || publicKey == null) + throw new IllegalStateException(); + + return verifySignature(sig); + } + + public abstract Object clone(); + + protected abstract void setupForVerification(PublicKey key) + throws IllegalArgumentException; + + protected abstract void setupForSigning(PrivateKey key) + throws IllegalArgumentException; + + protected abstract Object generateSignature() throws IllegalStateException; + + protected abstract boolean verifySignature(Object signature) + throws IllegalStateException; + + /** Initialises the internal fields of this instance. */ + protected void init() + { + md.reset(); + rnd = null; + irnd = null; + publicKey = null; + privateKey = null; + } + + /** + * Fills the designated byte array with random data. + * + * @param buffer the byte array to fill with random data. + */ + protected void nextRandomBytes(byte[] buffer) + { + if (rnd != null) + rnd.nextBytes(buffer); + else if (irnd != null) + try + { + irnd.nextBytes(buffer, 0, buffer.length); + } + catch (IllegalStateException x) + { + throw new RuntimeException("nextRandomBytes(): " + x); + } + catch (LimitReachedException x) + { + throw new RuntimeException("nextRandomBytes(): " + x); + } + else + getDefaultPRNG().nextBytes(buffer); + } + + private void setup(Map attributes) + { + init(); + // do we have a Random or SecureRandom, or should we use our own? + Object obj = attributes.get(SOURCE_OF_RANDOMNESS); + if (obj instanceof Random) + rnd = (Random) obj; + else if (obj instanceof IRandom) + irnd = (IRandom) obj; + } + + private PRNG getDefaultPRNG() + { + if (prng == null) + prng = PRNG.getInstance(); + + return prng; + } +} diff --git a/libjava/classpath/gnu/java/security/sig/ISignature.java b/libjava/classpath/gnu/java/security/sig/ISignature.java new file mode 100644 index 000000000..be98f9a9b --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/ISignature.java @@ -0,0 +1,160 @@ +/* ISignature.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +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. */ + + +package gnu.java.security.sig; + +import java.util.Map; + +/** + * The visible methods of every signature-with-appendix scheme. + *

+ * The Handbook of Applied Cryptography (HAC), by A. Menezes & al. states: + * "Digital signature schemes which require the message as input to the + * verification algorithm are called digital signature schemes with appendix. + * ... They rely on cryptographic hash functions rather than customised + * redundancy functions, and are less prone to existential forgery attacks." + *

+ * References: + *

    + *
  1. Handbook of Applied + * Cryptography, Alfred J. Menezes, Paul C. van Oorschot and Scott A. + * Vanstone. Section 11.2.2 Digital signature schemes with appendix.
  2. + *
+ */ +public interface ISignature + extends Cloneable +{ + /** Property name of the verifier's public key. */ + public static final String VERIFIER_KEY = "gnu.crypto.sig.public.key"; + + /** Property name of the signer's private key. */ + public static final String SIGNER_KEY = "gnu.crypto.sig.private.key"; + + /** + * Property name of an optional {@link java.security.SecureRandom}, + * {@link java.util.Random}, or {@link gnu.java.security.prng.IRandom} + * instance to use. The default is to use a classloader singleton from + * {@link gnu.java.security.util.PRNG}. + */ + public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.sig.prng"; + + /** + * Returns the canonical name of this signature scheme. + * + * @return the canonical name of this instance. + */ + String name(); + + /** + * Initialises this instance for signature verification. + * + * @param attributes the attributes to use for setting up this instance. + * @throws IllegalArgumentException if the designated public key is not + * appropriate for this signature scheme. + * @see #SOURCE_OF_RANDOMNESS + * @see #VERIFIER_KEY + */ + void setupVerify(Map attributes) throws IllegalArgumentException; + + /** + * Initialises this instance for signature generation. + * + * @param attributes the attributes to use for setting up this instance. + * @throws IllegalArgumentException if the designated private key is not + * appropriate for this signature scheme. + * @see #SOURCE_OF_RANDOMNESS + * @see #SIGNER_KEY + */ + void setupSign(Map attributes) throws IllegalArgumentException; + + /** + * Digests one byte of a message for signing or verification purposes. + * + * @param b the message byte to digest. + * @throws IllegalStateException if this instance was not setup for signature + * generation/verification. + */ + void update(byte b) throws IllegalStateException; + + /** + * Digests a sequence of bytes from a message for signing or verification + * purposes. + * + * @param buffer the byte sequence to consider. + * @param offset the byte poisition in buffer of the first byte + * to consider. + * @param length the number of bytes in buffer starting from + * the byte at index offset to digest. + * @throws IllegalStateException if this instance was not setup for signature + * generation/verification. + */ + void update(byte[] buffer, int offset, int length) + throws IllegalStateException; + + /** + * Terminates a signature generation phase by digesting and processing the + * context of the underlying message digest algorithm instance. + * + * @return a {@link Object} representing the native output of the signature + * scheme implementation. + * @throws IllegalStateException if this instance was not setup for signature + * generation. + */ + Object sign() throws IllegalStateException; + + /** + * Terminates a signature verification phase by digesting and processing the + * context of the underlying message digest algorithm instance. + * + * @param signature a native signature object previously generated by an + * invocation of the sign() method. + * @return true iff the outpout of the verification phase + * confirms that the designated signature object has been generated + * using the corresponding public key of the recepient. + * @throws IllegalStateException if this instance was not setup for signature + * verification. + */ + boolean verify(Object signature) throws IllegalStateException; + + /** + * Returns a clone copy of this instance. + * + * @return a clone copy of this instance. + */ + Object clone(); +} diff --git a/libjava/classpath/gnu/java/security/sig/ISignatureCodec.java b/libjava/classpath/gnu/java/security/sig/ISignatureCodec.java new file mode 100644 index 000000000..f8b147361 --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/ISignatureCodec.java @@ -0,0 +1,59 @@ +/* ISignatureCodec.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +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. */ + + +package gnu.java.security.sig; + +import gnu.java.security.Registry; + +/** + * The visible methods of an object that knows how to encode and decode + * cryptographic signatures. Codecs are useful for (a) externalising signature + * output data for storage and on-the-wire transmission, as well as (b) re- + * creating their internal Java representation from external sources. + */ +public interface ISignatureCodec +{ + /** Constant identifying the Raw encoding format. */ + int RAW_FORMAT = Registry.RAW_ENCODING_ID; + + int getFormatID(); + + byte[] encodeSignature(Object signature); + + Object decodeSignature(byte[] input); +} diff --git a/libjava/classpath/gnu/java/security/sig/SignatureCodecFactory.java b/libjava/classpath/gnu/java/security/sig/SignatureCodecFactory.java new file mode 100644 index 000000000..0026ad164 --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/SignatureCodecFactory.java @@ -0,0 +1,226 @@ +/* SignatureCodecFactory.java -- Factory to instantiate Signature codecs + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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. */ + + +package gnu.java.security.sig; + +import gnu.java.security.Registry; +import gnu.java.security.hash.HashFactory; +import gnu.java.security.sig.dss.DSSSignatureRawCodec; +import gnu.java.security.sig.dss.DSSSignatureX509Codec; +import gnu.java.security.sig.rsa.RSAPKCS1V1_5SignatureRawCodec; +import gnu.java.security.sig.rsa.RSAPKCS1V1_5SignatureX509Codec; +import gnu.java.security.sig.rsa.RSAPSSSignatureRawCodec; +import gnu.java.security.util.FormatUtil; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +/** + * A Factory class to instantiate Signature codecs. + */ +public class SignatureCodecFactory +{ + private static Set names; + + /** Trivial constructor to enforce Singleton pattern. */ + private SignatureCodecFactory() + { + super(); + } + + /** + * Returns the appropriate codec given a composed signature algorithm and an + * encoding format. A composed name is formed by the concatenation of the + * canonical signature algorithm name, the forward slash character + * / and the canonical name of the encoding format. + *

+ * When the encoding format name is missing, the Raw encoding format is + * assumed. When this is the case the trailing forward slash is discarded from + * the name. + * + * @param name the case-insensitive, possibly composed, signature codec name. + * @return an instance of the signaturecodec, or null if none + * found. + */ + public static ISignatureCodec getInstance(String name) + { + if (name == null) + return null; + + name = name.trim(); + if (name.length() == 0) + return null; + + if (name.startsWith("/")) + return null; + + if (name.endsWith("/")) + return getInstance(name.substring(0, name.length() - 1), + Registry.RAW_ENCODING_ID); + + int i = name.indexOf("/"); + if (i == - 1) + return getInstance(name, Registry.RAW_ENCODING_ID); + + String sigName = name.substring(0, i); + String formatName = name.substring(i + 1); + return getInstance(sigName, formatName); + } + + /** + * Returns an instance of a signature codec given the canonical name of the + * signature algorithm, and that of the encoding format. + * + * @param name the case-insensitive signature algorithm name. + * @param format the name of the format to use when encodigng/decoding + * signatures generated by the named algorithm. + * @return an instance of the signature codec, or null if none + * found. + */ + public static ISignatureCodec getInstance(String name, String format) + { + int formatID = FormatUtil.getFormatID(format); + if (formatID == 0) + return null; + + return getInstance(name, formatID); + } + + /** + * Returns an instance of a signature codec given the canonical name of the + * signature algorithm, and the identifier of the format to use when + * encoding/decoding signatures generated by that algorithm. + * + * @param name the case-insensitive signature algorithm name. + * @param formatID the identifier of the format to use when encoding / + * decoding signatures generated by the designated algorithm. + * @return an instance of the signature codec, or null if none + * found. + */ + public static ISignatureCodec getInstance(String name, int formatID) + { + if (name == null) + return null; + + name = name.trim(); + switch (formatID) + { + case Registry.RAW_ENCODING_ID: + return getRawCodec(name); + case Registry.X509_ENCODING_ID: + return getX509Codec(name); + } + + return null; + } + + /** + * Returns a {@link Set} of supported signature codec names. + * + * @return a {@link Set} of the names of supported signature codec (Strings). + */ + public static synchronized final Set getNames() + { + if (names == null) + { + HashSet hs = new HashSet(); + hs.add(Registry.DSS_SIG + "/" + Registry.RAW_ENCODING_SHORT_NAME); + hs.add(Registry.DSS_SIG + "/" + Registry.X509_ENCODING_SORT_NAME); + Set hashNames = HashFactory.getNames(); + for (Iterator it = hashNames.iterator(); it.hasNext();) + { + String mdName = (String) it.next(); + String name = Registry.RSA_PKCS1_V1_5_SIG + "-" + mdName; + hs.add(name + "/" + Registry.RAW_ENCODING_SHORT_NAME); + hs.add(name + "/" + Registry.X509_ENCODING_SORT_NAME); + name = Registry.RSA_PSS_SIG + "-" + mdName; + hs.add(name + "/" + Registry.RAW_ENCODING_SHORT_NAME); + } + + names = Collections.unmodifiableSet(hs); + } + + return names; + } + + /** + * @param name the trimmed name of a signature algorithm. + * @return a Raw format codec for the designated signature algorithm, or + * null if none exists. + */ + private static ISignatureCodec getRawCodec(String name) + { + ISignatureCodec result = null; + if (name.equalsIgnoreCase(Registry.DSA_SIG) + || name.equalsIgnoreCase(Registry.DSS_SIG)) + result = new DSSSignatureRawCodec(); + else + { + name = name.toLowerCase(); + if (name.startsWith(Registry.RSA_PKCS1_V1_5_SIG)) + result = new RSAPKCS1V1_5SignatureRawCodec(); + else if (name.startsWith(Registry.RSA_PSS_SIG)) + result = new RSAPSSSignatureRawCodec(); + } + + return result; + } + + /** + * @param name the trimmed name of a signature algorithm. + * @return a X.509 format codec for the designated signature algorithm, or + * null if none exists. + */ + private static ISignatureCodec getX509Codec(String name) + { + ISignatureCodec result = null; + if (name.equalsIgnoreCase(Registry.DSA_SIG) + || name.equalsIgnoreCase(Registry.DSS_SIG)) + result = new DSSSignatureX509Codec(); + else + { + name = name.toLowerCase(); + if (name.startsWith(Registry.RSA_PKCS1_V1_5_SIG)) + result = new RSAPKCS1V1_5SignatureX509Codec(); + } + + return result; + } +} diff --git a/libjava/classpath/gnu/java/security/sig/SignatureFactory.java b/libjava/classpath/gnu/java/security/sig/SignatureFactory.java new file mode 100644 index 000000000..6cdaf6544 --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/SignatureFactory.java @@ -0,0 +1,101 @@ +/* SignatureFactory.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +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. */ + + +package gnu.java.security.sig; + +import gnu.java.security.Registry; +import gnu.java.security.sig.dss.DSSSignature; +import gnu.java.security.sig.rsa.RSASignatureFactory; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * A Factory to instantiate signature-with-appendix handlers. + */ +public class SignatureFactory +{ + private static Set names; + + /** Trivial constructor to enforce Singleton pattern. */ + private SignatureFactory() + { + super(); + } + + /** + * Returns an instance of a signature-with-appendix scheme given its name. + * + * @param ssa the case-insensitive signature-with-appendix scheme name. + * @return an instance of the scheme, or null if none found. + */ + public static final ISignature getInstance(String ssa) + { + if (ssa == null) + return null; + + ssa = ssa.trim(); + ssa = ssa.toLowerCase(); + ISignature result = null; + if (ssa.equalsIgnoreCase(Registry.DSA_SIG) || ssa.equals(Registry.DSS_SIG)) + result = new DSSSignature(); + else if (ssa.startsWith(Registry.RSA_SIG_PREFIX)) + result = RSASignatureFactory.getInstance(ssa); + + return result; + } + + /** + * Returns a {@link Set} of signature-with-appendix scheme names supported by + * this Factory. + * + * @return a {@link Set} of signature-with-appendix scheme names (Strings). + */ + public static synchronized final Set getNames() + { + if (names == null) + { + HashSet hs = new HashSet(); + hs.add(Registry.DSS_SIG); + hs.addAll(RSASignatureFactory.getNames()); + names = Collections.unmodifiableSet(hs); + } + return names; + } +} diff --git a/libjava/classpath/gnu/java/security/sig/dss/DSSSignature.java b/libjava/classpath/gnu/java/security/sig/dss/DSSSignature.java new file mode 100644 index 000000000..024521ba4 --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/dss/DSSSignature.java @@ -0,0 +1,275 @@ +/* DSSSignature.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +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. */ + + +package gnu.java.security.sig.dss; + +import gnu.java.security.Registry; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.hash.Sha160; +import gnu.java.security.prng.IRandom; +import gnu.java.security.sig.BaseSignature; +import gnu.java.security.sig.ISignature; + +import java.math.BigInteger; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.interfaces.DSAPrivateKey; +import java.security.interfaces.DSAPublicKey; +import java.util.HashMap; +import java.util.Map; +import java.util.Random; + +/** + * The DSS (Digital Signature Standard) algorithm makes use of the following + * parameters: + *

    + *
  1. p: A prime modulus, where + * 2L-1 < p < 2L for 512 <= L + * <= 1024 and L a multiple of 64.
  2. + *
  3. q: A prime divisor of p - 1, where 2159 + * < q < 2160.
  4. + *
  5. g: Where g = h(p-1)/q mod p, where + * h is any integer with 1 < h < p - 1 such + * that h (p-1)/q mod p > 1 (g has order + * q mod p).
  6. + *
  7. x: A randomly or pseudorandomly generated integer with 0 < x + * < q.
  8. + *
  9. y: y = gx mod p.
  10. + *
  11. k: A randomly or pseudorandomly generated integer with 0 < k + * < q.
  12. + *
+ *

+ * The integers p, q, and g can be + * public and can be common to a group of users. A user's private and public + * keys are x and y, respectively. They are + * normally fixed for a period of time. Parameters x and + * k are used for signature generation only, and must be kept + * secret. Parameter k must be regenerated for each signature. + *

+ * The signature of a message M is the pair of numbers + * r and s computed according to the equations below: + *

+ *

+ * In the above, k-1 is the multiplicative inverse of + * k, mod q; i.e., (k-1 k) mod q = + * 1 and 0 < k-1 < q. The value of SHA(M) + * is a 160-bit string output by the Secure Hash Algorithm specified in FIPS + * 180. For use in computing s, this string must be converted to + * an integer. + *

+ * As an option, one may wish to check if r == 0 or s == 0 + * . + * If either r == 0 or s == 0, a new value of + * k should be generated and the signature should be recalculated + * (it is extremely unlikely that r == 0 or s == 0 if + * signatures are generated properly). + *

+ * The signature is transmitted along with the message to the verifier. + *

+ * References: + *

    + *
  1. Digital Signature + * Standard (DSS), Federal Information Processing Standards Publication + * 186. National Institute of Standards and Technology.
  2. + *
+ */ +public class DSSSignature + extends BaseSignature +{ + /** Trivial 0-arguments constructor. */ + public DSSSignature() + { + super(Registry.DSS_SIG, new Sha160()); + } + + /** Private constructor for cloning purposes. */ + private DSSSignature(DSSSignature that) + { + this(); + + this.publicKey = that.publicKey; + this.privateKey = that.privateKey; + this.md = (IMessageDigest) that.md.clone(); + } + + public static final BigInteger[] sign(final DSAPrivateKey k, final byte[] h) + { + final DSSSignature sig = new DSSSignature(); + final Map attributes = new HashMap(); + attributes.put(ISignature.SIGNER_KEY, k); + sig.setupSign(attributes); + return sig.computeRS(h); + } + + public static final BigInteger[] sign(final DSAPrivateKey k, final byte[] h, + Random rnd) + { + final DSSSignature sig = new DSSSignature(); + final Map attributes = new HashMap(); + attributes.put(ISignature.SIGNER_KEY, k); + if (rnd != null) + attributes.put(ISignature.SOURCE_OF_RANDOMNESS, rnd); + + sig.setupSign(attributes); + return sig.computeRS(h); + } + + public static final BigInteger[] sign(final DSAPrivateKey k, final byte[] h, + IRandom irnd) + { + final DSSSignature sig = new DSSSignature(); + final Map attributes = new HashMap(); + attributes.put(ISignature.SIGNER_KEY, k); + if (irnd != null) + attributes.put(ISignature.SOURCE_OF_RANDOMNESS, irnd); + + sig.setupSign(attributes); + return sig.computeRS(h); + } + + public static final boolean verify(final DSAPublicKey k, final byte[] h, + final BigInteger[] rs) + { + final DSSSignature sig = new DSSSignature(); + final Map attributes = new HashMap(); + attributes.put(ISignature.VERIFIER_KEY, k); + sig.setupVerify(attributes); + return sig.checkRS(rs, h); + } + + public Object clone() + { + return new DSSSignature(this); + } + + protected void setupForVerification(PublicKey k) + throws IllegalArgumentException + { + if (! (k instanceof DSAPublicKey)) + throw new IllegalArgumentException(); + + this.publicKey = k; + } + + protected void setupForSigning(PrivateKey k) throws IllegalArgumentException + { + if (! (k instanceof DSAPrivateKey)) + throw new IllegalArgumentException(); + + this.privateKey = k; + } + + protected Object generateSignature() throws IllegalStateException + { + final BigInteger[] rs = computeRS(md.digest()); + return encodeSignature(rs[0], rs[1]); + } + + protected boolean verifySignature(Object sig) throws IllegalStateException + { + final BigInteger[] rs = decodeSignature(sig); + return checkRS(rs, md.digest()); + } + + /** + * Returns the output of a signature generation phase. + * + * @return an object encapsulating the DSS signature pair r and + * s. + */ + private Object encodeSignature(BigInteger r, BigInteger s) + { + return new BigInteger[] { r, s }; + } + + /** + * Returns the output of a previously generated signature object as a pair of + * {@link java.math.BigInteger}. + * + * @return the DSS signature pair r and s. + */ + private BigInteger[] decodeSignature(Object signature) + { + return (BigInteger[]) signature; + } + + private BigInteger[] computeRS(final byte[] digestBytes) + { + final BigInteger p = ((DSAPrivateKey) privateKey).getParams().getP(); + final BigInteger q = ((DSAPrivateKey) privateKey).getParams().getQ(); + final BigInteger g = ((DSAPrivateKey) privateKey).getParams().getG(); + final BigInteger x = ((DSAPrivateKey) privateKey).getX(); + final BigInteger m = new BigInteger(1, digestBytes); + BigInteger k, r, s; + final byte[] kb = new byte[20]; // we'll use 159 bits only + while (true) + { + this.nextRandomBytes(kb); + k = new BigInteger(1, kb); + k.clearBit(159); + r = g.modPow(k, p).mod(q); + if (r.equals(BigInteger.ZERO)) + continue; + + s = m.add(x.multiply(r)).multiply(k.modInverse(q)).mod(q); + if (s.equals(BigInteger.ZERO)) + continue; + + break; + } + return new BigInteger[] { r, s }; + } + + private boolean checkRS(final BigInteger[] rs, final byte[] digestBytes) + { + final BigInteger r = rs[0]; + final BigInteger s = rs[1]; + final BigInteger g = ((DSAPublicKey) publicKey).getParams().getG(); + final BigInteger p = ((DSAPublicKey) publicKey).getParams().getP(); + final BigInteger q = ((DSAPublicKey) publicKey).getParams().getQ(); + final BigInteger y = ((DSAPublicKey) publicKey).getY(); + final BigInteger w = s.modInverse(q); + final BigInteger u1 = w.multiply(new BigInteger(1, digestBytes)).mod(q); + final BigInteger u2 = r.multiply(w).mod(q); + final BigInteger v = g.modPow(u1, p).multiply(y.modPow(u2, p)).mod(p).mod(q); + return v.equals(r); + } +} diff --git a/libjava/classpath/gnu/java/security/sig/dss/DSSSignatureRawCodec.java b/libjava/classpath/gnu/java/security/sig/dss/DSSSignatureRawCodec.java new file mode 100644 index 000000000..169f84bd1 --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/dss/DSSSignatureRawCodec.java @@ -0,0 +1,164 @@ +/* DSSSignatureRawCodec.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +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. */ + + +package gnu.java.security.sig.dss; + +import gnu.java.security.Registry; +import gnu.java.security.sig.ISignatureCodec; + +import java.io.ByteArrayOutputStream; +import java.math.BigInteger; + +/** + * An object that implements the {@link ISignatureCodec} operations for the + * Raw format to use with DSS signatures. + */ +public class DSSSignatureRawCodec + implements ISignatureCodec +{ + public int getFormatID() + { + return RAW_FORMAT; + } + + /** + * Returns the encoded form of the designated DSS (Digital Signature Standard) + * signature object according to the Raw format supported by this + * library. + *

+ * The Raw format for a DSA signature, in this implementation, is a + * byte sequence consisting of the following: + *

    + *
  1. 4-byte magic consisting of the value of the literal + * {@link Registry#MAGIC_RAW_DSS_SIGNATURE},
  2. + *
  3. 1-byte version consisting of the constant: 0x01,
  4. + *
  5. 4-byte count of following bytes representing the DSS parameter + * r in internet order,
  6. + *
  7. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the DSS parameter r, + *
  8. + *
  9. 4-byte count of following bytes representing the DSS parameter + * s,
  10. + *
  11. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the DSS parameter s. + *
  12. + *
+ * + * @param signature the signature to encode, consisting of the two DSS + * parameters r and s as a + * {@link BigInteger} array. + * @return the Raw format encoding of the designated signature. + * @exception IllegalArgumentException if the designated signature is not a + * DSS (Digital Signature Standard) one. + */ + public byte[] encodeSignature(Object signature) + { + BigInteger r, s; + try + { + BigInteger[] sig = (BigInteger[]) signature; + r = sig[0]; + s = sig[1]; + } + catch (Exception x) + { + throw new IllegalArgumentException("signature"); + } + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + // magic + baos.write(Registry.MAGIC_RAW_DSS_SIGNATURE[0]); + baos.write(Registry.MAGIC_RAW_DSS_SIGNATURE[1]); + baos.write(Registry.MAGIC_RAW_DSS_SIGNATURE[2]); + baos.write(Registry.MAGIC_RAW_DSS_SIGNATURE[3]); + // version + baos.write(0x01); + // r + byte[] buffer = r.toByteArray(); + int length = buffer.length; + baos.write( length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + // s + buffer = s.toByteArray(); + length = buffer.length; + baos.write( length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + return baos.toByteArray(); + } + + public Object decodeSignature(byte[] k) + { + // magic + if (k[0] != Registry.MAGIC_RAW_DSS_SIGNATURE[0] + || k[1] != Registry.MAGIC_RAW_DSS_SIGNATURE[1] + || k[2] != Registry.MAGIC_RAW_DSS_SIGNATURE[2] + || k[3] != Registry.MAGIC_RAW_DSS_SIGNATURE[3]) + throw new IllegalArgumentException("magic"); + // version + if (k[4] != 0x01) + throw new IllegalArgumentException("version"); + + int i = 5; + int l; + byte[] buffer; + // r + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger r = new BigInteger(1, buffer); + // s + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger s = new BigInteger(1, buffer); + return new BigInteger[] { r, s }; + } +} diff --git a/libjava/classpath/gnu/java/security/sig/dss/DSSSignatureX509Codec.java b/libjava/classpath/gnu/java/security/sig/dss/DSSSignatureX509Codec.java new file mode 100644 index 000000000..d0a0188fb --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/dss/DSSSignatureX509Codec.java @@ -0,0 +1,193 @@ +/* DSSSignatureX509Codec.java -- X.509 encoder/decoder for DSS signatures + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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. */ + + +package gnu.java.security.sig.dss; + +import gnu.java.security.Registry; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; +import gnu.java.security.der.DERWriter; +import gnu.java.security.sig.ISignatureCodec; +import gnu.java.security.util.DerUtil; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.InvalidParameterException; +import java.util.ArrayList; + +/** + * An implementation of an {@link ISignatureCodec} that knows to encode and + * decode DSS signatures into the raw bytes which would constitute a DER-encoded + * form of the ASN.1 structure defined in RFC-2459, and RFC-2313 as described in + * the next paragraphs. + *

+ * Digital signatures when transmitted in an X.509 certificates are encoded + * in DER (Distinguished Encoding Rules) as a BIT STRING; i.e. + * + *

+ * Certificate ::= SEQUENCE {
+ *   tbsCertificate       TBSCertificate,
+ *   signatureAlgorithm   AlgorithmIdentifier,
+ *   signature            BIT STRING
+ * }
+ * 
+ *

+ * The output of the encoder, and the input of the decoder, of this codec are + * then the raw bytes of such a BIT STRING; i.e. not the DER-encoded + * form itself. + *

+ * RFC-2459 states that, for the Digital Signature Standard (DSS), which + * generates two MPIs, commonly called r and s, as the + * result of digitally signing a message, these two numbers will be transferred + * as the following ASN.1 structure: + * + *

+ *   Dss-Sig-Value ::= SEQUENCE {
+ *     r  INTEGER,
+ *     s  INTEGER
+ *   }
+ * 
+ *

+ * Client code that needs to build a DER BIT STRING MUST construct such + * an ASN.1 value. The following is an example of how to do this: + *

+ *

+ * ...
+ * import gnu.java.security.der.BitString;
+ * import gnu.java.security.der.DER;
+ * import gnu.java.security.der.DERValue;
+ * ...
+ * DERValue bitString = new DERValue(DER.BIT_STRING, new BitString(sigBytes));
+ * ...
+ * 
+ */ +public class DSSSignatureX509Codec + implements ISignatureCodec +{ + // implicit 0-arguments constructor + + public int getFormatID() + { + return Registry.X509_ENCODING_ID; + } + + /** + * Encodes a DSS Signature output as the signature raw bytes which can + * be used to construct an ASN.1 DER-encoded BIT STRING as defined in the + * documentation of this class. + * + * @param signature the output of the DSS signature algorithm; i.e. the value + * returned by the invocation of + * {@link gnu.java.security.sig.ISignature#sign()} method. In the + * case of a DSS signature this is an array of two MPIs called + * r and s. + * @return the raw bytes of a DSS signature which could be then used as the + * contents of a BIT STRING as per rfc-2459. + * @throws InvalidParameterException if an exception occurs during the + * marshalling process. + */ + public byte[] encodeSignature(Object signature) + { + BigInteger[] rs = (BigInteger[]) signature; + + DERValue derR = new DERValue(DER.INTEGER, rs[0]); + DERValue derS = new DERValue(DER.INTEGER, rs[1]); + + ArrayList dssSigValue = new ArrayList(2); + dssSigValue.add(derR); + dssSigValue.add(derS); + DERValue derDssSigValue = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, + dssSigValue); + byte[] result; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try + { + DERWriter.write(baos, derDssSigValue); + result = baos.toByteArray(); + } + catch (IOException x) + { + InvalidParameterException y = new InvalidParameterException(); + y.initCause(x); + throw y; + } + + return result; + } + + /** + * Decodes a signature as defined in the documentation of this class. + * + * @param input the byte array to unmarshall into a valid DSS signature + * instance; i.e. an array of two MPIs. MUST NOT be null. + * @return an array of two MPIs, r and s in this + * order, decoded from the designated input. + * @throw InvalidParameterException if an exception occurs during the + * unmarshalling process. + */ + public Object decodeSignature(byte[] input) + { + if (input == null) + throw new InvalidParameterException("Input bytes MUST NOT be null"); + + BigInteger r, s; + DERReader der = new DERReader(input); + try + { + DERValue derDssSigValue = der.read(); + DerUtil.checkIsConstructed(derDssSigValue, "Wrong Dss-Sig-Value field"); + + DERValue val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong R field"); + r = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong S field"); + s = (BigInteger) val.getValue(); + } + catch (IOException x) + { + InvalidParameterException y = new InvalidParameterException(); + y.initCause(x); + throw y; + } + + return new BigInteger[] { r, s }; + } +} diff --git a/libjava/classpath/gnu/java/security/sig/rsa/EME_PKCS1_V1_5.java b/libjava/classpath/gnu/java/security/sig/rsa/EME_PKCS1_V1_5.java new file mode 100644 index 000000000..329ca8ed6 --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/rsa/EME_PKCS1_V1_5.java @@ -0,0 +1,274 @@ +/* EME_PKCS1_V1_5.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +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. */ + + +package gnu.java.security.sig.rsa; + +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.util.PRNG; + +import java.io.ByteArrayOutputStream; +import java.security.interfaces.RSAKey; +import java.util.Random; + +/** + * An implementation of the EME-PKCS1-V1.5 encoding and decoding methods. + *

+ * EME-PKCS1-V1.5 is parameterised by the entity k which is the + * byte count of an RSA public shared modulus. + *

+ * References: + *

    + *
  1. Public-Key Cryptography + * Standards (PKCS) #1:
    + * RSA Cryptography Specifications Version 2.1.
    + * Jakob Jonsson and Burt Kaliski.
  2. + *
+ */ +public class EME_PKCS1_V1_5 +{ + private int k; + + private ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + /** Our default source of randomness. */ + private PRNG prng = PRNG.getInstance(); + + private EME_PKCS1_V1_5(final int k) + { + super(); + + this.k = k; + } + + public static final EME_PKCS1_V1_5 getInstance(final int k) + { + if (k < 0) + throw new IllegalArgumentException("k must be a positive integer"); + + return new EME_PKCS1_V1_5(k); + } + + public static final EME_PKCS1_V1_5 getInstance(final RSAKey key) + { + final int modBits = key.getModulus().bitLength(); + final int k = (modBits + 7) / 8; + return EME_PKCS1_V1_5.getInstance(k); + } + + /** + * Generates an octet string PS of length k - mLen - + * 3 consisting of pseudo-randomly generated nonzero octets. The length + * of PS will be at least eight octets. + *

+ * The method then concatenates PS, the message M, + * and other padding to form an encoded message EM of length + * k octets as: + *

+   *     EM = 0x00 || 0x02 || PS || 0x00 || M.
+   * 
+ *

+ * This method uses a default PRNG to obtain the padding bytes. + * + * @param M the message to encode. + * @return the encoded message EM. + */ + public byte[] encode(final byte[] M) + { + // a. Generate an octet string PS of length k - mLen - 3 consisting + // of pseudo-randomly generated nonzero octets. The length of PS + // will be at least eight octets. + final byte[] PS = new byte[k - M.length - 3]; + // FIXME. This should be configurable, somehow. + prng.nextBytes(PS); + int i = 0; + for (; i < PS.length; i++) + { + if (PS[i] == 0) + PS[i] = 1; + } + // b. Concatenate PS, the message M, and other padding to form an + // encoded message EM of length k octets as + // + // EM = 0x00 || 0x02 || PS || 0x00 || M. + return assembleEM(PS, M); + } + + /** + * Similar to {@link #encode(byte[])} method, except that the source of + * randomness to use for obtaining the padding bytes (an instance of + * {@link IRandom}) is given as a parameter. + * + * @param M the message to encode. + * @param irnd the {@link IRandom} instance to use as a source of randomness. + * @return the encoded message EM. + */ + public byte[] encode(final byte[] M, final IRandom irnd) + { + final byte[] PS = new byte[k - M.length - 3]; + try + { + irnd.nextBytes(PS, 0, PS.length); + int i = 0; + outer: while (true) + { + for (; i < PS.length; i++) + { + if (PS[i] == 0x00) + { + System.arraycopy(PS, i + 1, PS, i, PS.length - i - 1); + irnd.nextBytes(PS, PS.length - 1, 1); + continue outer; + } + } + break; + } + } + catch (IllegalStateException x) + { + throw new RuntimeException("encode(): " + String.valueOf(x)); + } + catch (LimitReachedException x) + { + throw new RuntimeException("encode(): " + String.valueOf(x)); + } + return assembleEM(PS, M); + } + + /** + * Similar to the {@link #encode(byte[], IRandom)} method, except that the + * source of randmoness is an instance of {@link Random}. + * + * @param M the message to encode. + * @param rnd the {@link Random} instance to use as a source of randomness. + * @return the encoded message EM. + */ + public byte[] encode(final byte[] M, final Random rnd) + { + final byte[] PS = new byte[k - M.length - 3]; + rnd.nextBytes(PS); + int i = 0; + outer: while (true) + { + for (; i < PS.length; i++) + { + if (PS[i] == 0x00) + { + System.arraycopy(PS, i + 1, PS, i, PS.length - i - 1); + PS[PS.length - 1] = (byte) rnd.nextInt(); + continue outer; + } + } + break; + } + return assembleEM(PS, M); + } + + /** + * Separate the encoded message EM into an octet string + * PS consisting of nonzero octets and a message M + * as: + *

+   *     EM = 0x00 || 0x02 || PS || 0x00 || M.
+   * 
+ *

+ * If the first octet of EM does not have hexadecimal value + * 0x00, if the second octet of EM does not + * have hexadecimal value 0x02, if there is no octet with + * hexadecimal value 0x00 to separate PS from + * M, or if the length of PS is less than + * 8 octets, output "decryption error" and stop. + * + * @param EM the designated encoded message. + * @return the decoded message M framed in the designated + * EM value. + * @throws IllegalArgumentException if the length of the designated entity + * EM is different than k (the length + * in bytes of the public shared modulus), or if any of the + * conditions described above is detected. + */ + public byte[] decode(final byte[] EM) + { + // Separate the encoded message EM into an + // octet string PS consisting of nonzero octets and a message M as + // + // EM = 0x00 || 0x02 || PS || 0x00 || M. + // + // If the first octet of EM does not have hexadecimal value 0x00, if + // the second octet of EM does not have hexadecimal value 0x02, if + // there is no octet with hexadecimal value 0x00 to separate PS from + // M, or if the length of PS is less than 8 octets, output + // "decryption error" and stop. (See the note below.) + final int emLen = EM.length; + if (emLen != k) + throw new IllegalArgumentException("decryption error"); + if (EM[0] != 0x00) + throw new IllegalArgumentException("decryption error"); + if (EM[1] != 0x02) + throw new IllegalArgumentException("decryption error"); + int i = 2; + for (; i < emLen; i++) + { + if (EM[i] == 0x00) + break; + } + if (i >= emLen || i < 11) + throw new IllegalArgumentException("decryption error"); + i++; + final byte[] result = new byte[emLen - i]; + System.arraycopy(EM, i, result, 0, result.length); + return result; + } + + private byte[] assembleEM(final byte[] PS, final byte[] M) + { + // b. Concatenate PS, the message M, and other padding to form an + // encoded message EM of length k octets as + // + // EM = 0x00 || 0x02 || PS || 0x00 || M. + baos.reset(); + baos.write(0x00); + baos.write(0x02); + baos.write(PS, 0, PS.length); + baos.write(0x00); + baos.write(M, 0, M.length); + final byte[] result = baos.toByteArray(); + baos.reset(); + return result; + } +} diff --git a/libjava/classpath/gnu/java/security/sig/rsa/EMSA_PKCS1_V1_5.java b/libjava/classpath/gnu/java/security/sig/rsa/EMSA_PKCS1_V1_5.java new file mode 100644 index 000000000..3cddab4aa --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/rsa/EMSA_PKCS1_V1_5.java @@ -0,0 +1,243 @@ +/* EMSA_PKCS1_V1_5.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +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. */ + + +package gnu.java.security.sig.rsa; + +import gnu.java.security.Registry; +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; + +import java.io.ByteArrayOutputStream; + +/** + * An implementation of the EMSA-PKCS1-V1.5 encoding scheme. + *

+ * EMSA-PKCS1-V1.5 is parameterised by the choice of hash function Hash and + * hLen which denotes the length in octets of the hash function output. + *

+ * References: + *

    + *
  1. Public-Key Cryptography + * Standards (PKCS) #1:
    + * RSA Cryptography Specifications Version 2.1.
    + * Jakob Jonsson and Burt Kaliski.
  2. + *
+ */ +public class EMSA_PKCS1_V1_5 + implements Cloneable +{ + /* Notes. + 1. For the six hash functions mentioned in Appendix B.1, the DER encoding + T of the DigestInfo value is equal to the following: + + MD2: (0x)30 20 30 0c 06 08 2a 86 48 86 f7 0d 02 02 05 00 04 10 || H + MD5: (0x)30 20 30 0c 06 08 2a 86 48 86 f7 0d 02 05 05 00 04 10 || H + SHA-1: (0x)30 21 30 09 06 05 2b 0e 03 02 1a 05 00 04 14 || H + SHA-256: (0x)30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 || H + SHA-384: (0x)30 41 30 0d 06 09 60 86 48 01 65 03 04 02 02 05 00 04 30 || H + SHA-512: (0x)30 51 30 0d 06 09 60 86 48 01 65 03 04 02 03 05 00 04 40 || H + */ + private static final byte[] MD2_PREFIX = { + (byte) 0x30, (byte) 0x20, (byte) 0x30, (byte) 0x0c, (byte) 0x06, + (byte) 0x08, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, + (byte) 0xf7, (byte) 0x0d, (byte) 0x02, (byte) 0x02, (byte) 0x05, + (byte) 0x00, (byte) 0x04, (byte) 0x10 + }; + + private static final byte[] MD5_PREFIX = { + (byte) 0x30, (byte) 0x20, (byte) 0x30, (byte) 0x0c, (byte) 0x06, + (byte) 0x08, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, + (byte) 0xf7, (byte) 0x0d, (byte) 0x02, (byte) 0x05, (byte) 0x05, + (byte) 0x00, (byte) 0x04, (byte) 0x10 + }; + + private static final byte[] SHA160_PREFIX = { + (byte) 0x30, (byte) 0x21, (byte) 0x30, (byte) 0x09, (byte) 0x06, + (byte) 0x05, (byte) 0x2b, (byte) 0x0e, (byte) 0x03, (byte) 0x02, + (byte) 0x1a, (byte) 0x05, (byte) 0x00, (byte) 0x04, (byte) 0x14 + }; + + private static final byte[] SHA256_PREFIX = { + (byte) 0x30, (byte) 0x31, (byte) 0x30, (byte) 0x0d, (byte) 0x06, + (byte) 0x09, (byte) 0x60, (byte) 0x86, (byte) 0x48, (byte) 0x01, + (byte) 0x65, (byte) 0x03, (byte) 0x04, (byte) 0x02, (byte) 0x01, + (byte) 0x05, (byte) 0x00, (byte) 0x04, (byte) 0x20 + }; + + private static final byte[] SHA384_PREFIX = { + (byte) 0x30, (byte) 0x41, (byte) 0x30, (byte) 0x0d, (byte) 0x06, + (byte) 0x09, (byte) 0x60, (byte) 0x86, (byte) 0x48, (byte) 0x01, + (byte) 0x65, (byte) 0x03, (byte) 0x04, (byte) 0x02, (byte) 0x02, + (byte) 0x05, (byte) 0x00, (byte) 0x04, (byte) 0x30 + }; + + private static final byte[] SHA512_PREFIX = { + (byte) 0x30, (byte) 0x51, (byte) 0x30, (byte) 0x0d, (byte) 0x06, + (byte) 0x09, (byte) 0x60, (byte) 0x86, (byte) 0x48, (byte) 0x01, + (byte) 0x65, (byte) 0x03, (byte) 0x04, (byte) 0x02, (byte) 0x03, + (byte) 0x05, (byte) 0x00, (byte) 0x04, (byte) 0x40 + }; + + /** The underlying hash function to use with this instance. */ + private IMessageDigest hash; + + /** The output size of the hash function in octets. */ + private int hLen; // TODO: field not used!!! investigate + + /** The DER part of DigestInfo not containing the hash value itself. */ + private byte[] prefix; + + /** + * Trivial private constructor to enforce use through Factory method. + * + * @param hash the message digest instance to use with this scheme instance. + */ + private EMSA_PKCS1_V1_5(final IMessageDigest hash) + { + super(); + + this.hash = hash; + hLen = hash.hashSize(); + final String name = hash.name(); + if (name.equals(Registry.MD2_HASH)) + prefix = MD2_PREFIX; + else if (name.equals(Registry.MD5_HASH)) + prefix = MD5_PREFIX; + else if (name.equals(Registry.SHA160_HASH)) + prefix = SHA160_PREFIX; + else if (name.equals(Registry.SHA256_HASH)) + prefix = SHA256_PREFIX; + else if (name.equals(Registry.SHA384_HASH)) + prefix = SHA384_PREFIX; + else if (name.equals(Registry.SHA512_HASH)) + prefix = SHA512_PREFIX; + else + throw new UnsupportedOperationException(); // should not happen + } + + /** + * Returns an instance of this object given a designated name of a hash + * function. + * + * @param mdName the canonical name of a hash function. + * @return an instance of this object configured for use with the designated + * options. + * @throws UnsupportedOperationException if the hash function is not + * implemented or does not have an ID listed in RFC-3447. + */ + public static final EMSA_PKCS1_V1_5 getInstance(final String mdName) + { + final IMessageDigest hash = HashFactory.getInstance(mdName); + final String name = hash.name(); + if (! (name.equals(Registry.MD2_HASH) + || name.equals(Registry.MD5_HASH) + || name.equals(Registry.SHA160_HASH) + || name.equals(Registry.SHA256_HASH) + || name.equals(Registry.SHA384_HASH) + || name.equals(Registry.SHA512_HASH))) + throw new UnsupportedOperationException("hash with no OID: " + name); + + return new EMSA_PKCS1_V1_5(hash); + } + + public Object clone() + { + return getInstance(hash.name()); + } + + /** + * Frames the hash of a message, along with an ID of the hash function in + * a DER sequence according to the specifications of EMSA-PKCS1-V1.5 as + * described in RFC-3447 (see class documentation). + * + * @param mHash the byte sequence resulting from applying the message digest + * algorithm Hash to the message M. + * @param emLen intended length in octets of the encoded message, at least + * tLen + 11, where tLen is the octet length of the + * DER encoding T of a certain value computed during the + * encoding operation. + * @return encoded message, an octet string of length emLen. + * @throws IllegalArgumentException if the message is too long, or if the + * intended encoded message length is too short. + */ + public byte[] encode(final byte[] mHash, final int emLen) + { + // 1. Apply the hash function to the message M to produce a hash value + // H: H = Hash(M). + // If the hash function outputs "message too long," output "message + // too long" and stop. + // 2. Encode the algorithm ID for the hash function and the hash value + // into an ASN.1 value of type DigestInfo (see Appendix A.2.4) with + // the Distinguished Encoding Rules (DER), where the type DigestInfo + // has the syntax + // DigestInfo ::= SEQUENCE { + // digestAlgorithm AlgorithmIdentifier, + // digest OCTET STRING + // } + // The first field identifies the hash function and the second contains + // the hash value. Let T be the DER encoding of the DigestInfo value + // (see the notes below) and let tLen be the length in octets of T. + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + baos.write(prefix, 0, prefix.length); + baos.write(mHash, 0, mHash.length); + final byte[] T = baos.toByteArray(); + final int tLen = T.length; + // 3. If emLen < tLen + 11, output "intended encoded message length too + // short" and stop. + if (emLen < tLen + 11) + throw new IllegalArgumentException("emLen too short"); + // 4. Generate an octet string PS consisting of emLen - tLen - 3 octets + // with hexadecimal value 0xff. The length of PS will be at least 8 + // octets. + final byte[] PS = new byte[emLen - tLen - 3]; + for (int i = 0; i < PS.length; i++) + PS[i] = (byte) 0xFF; + // 5. Concatenate PS, the DER encoding T, and other padding to form the + // encoded message EM as: EM = 0x00 || 0x01 || PS || 0x00 || T. + baos.reset(); + baos.write(0x00); + baos.write(0x01); + baos.write(PS, 0, PS.length); + baos.write(0x00); + baos.write(T, 0, tLen); + final byte[] result = baos.toByteArray(); + baos.reset(); + // 6. Output EM. + return result; + } +} diff --git a/libjava/classpath/gnu/java/security/sig/rsa/EMSA_PSS.java b/libjava/classpath/gnu/java/security/sig/rsa/EMSA_PSS.java new file mode 100644 index 000000000..917d96323 --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/rsa/EMSA_PSS.java @@ -0,0 +1,371 @@ +/* EMSA_PSS.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +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. */ + + +package gnu.java.security.sig.rsa; + +import gnu.java.security.Configuration; +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.util.Util; + +import java.util.Arrays; +import java.util.logging.Logger; + +/** + * An implementation of the EMSA-PSS encoding/decoding scheme. + *

+ * EMSA-PSS coincides with EMSA4 in IEEE P1363a D5 except that EMSA-PSS acts on + * octet strings and not on bit strings. In particular, the bit lengths of the + * hash and the salt must be multiples of 8 in EMSA-PSS. Moreover, EMSA4 outputs + * an integer of a desired bit length rather than an octet string. + *

+ * EMSA-PSS is parameterized by the choice of hash function Hash and mask + * generation function MGF. In this submission, MGF is based on a Hash + * definition that coincides with the corresponding definitions in IEEE Std + * 1363-2000, PKCS #1 v2.0, and the draft ANSI X9.44. In PKCS #1 v2.0 and the + * draft ANSI X9.44, the recommended hash function is SHA-1, while IEEE Std + * 1363-2000 recommends SHA-1 and RIPEMD-160. + *

+ * References: + *

    + *
  1. + * RSA-PSS Signature Scheme with Appendix, part B.
    + * Primitive specification and supporting documentation.
    + * Jakob Jonsson and Burt Kaliski.
  2. + *
+ */ +public class EMSA_PSS + implements Cloneable +{ + private static final Logger log = Logger.getLogger(EMSA_PSS.class.getName()); + + /** The underlying hash function to use with this instance. */ + private IMessageDigest hash; + + /** The output size of the hash function in octets. */ + private int hLen; + + /** + * Trivial private constructor to enforce use through Factory method. + * + * @param hash the message digest instance to use with this scheme instance. + */ + private EMSA_PSS(IMessageDigest hash) + { + super(); + + this.hash = hash; + hLen = hash.hashSize(); + } + + /** + * Returns an instance of this object given a designated name of a hash + * function. + * + * @param mdName the canonical name of a hash function. + * @return an instance of this object configured for use with the designated + * options. + */ + public static EMSA_PSS getInstance(String mdName) + { + IMessageDigest hash = HashFactory.getInstance(mdName); + return new EMSA_PSS(hash); + } + + public Object clone() + { + return getInstance(hash.name()); + } + + /** + * The encoding operation EMSA-PSS-Encode computes the hash of a message + * M using a hash function and maps the result to an encoded + * message EM of a specified length using a mask generation + * function. + * + * @param mHash the byte sequence resulting from applying the message digest + * algorithm Hash to the message M. + * @param emBits the maximal bit length of the integer OS2IP(EM), at least + * 8.hLen + 8.sLen + 9. + * @param salt the salt to use when encoding the output. + * @return the encoded message EM, an octet string of length + * emLen = CEILING(emBits / 8). + * @exception IllegalArgumentException if an exception occurs. + */ + public byte[] encode(byte[] mHash, int emBits, byte[] salt) + { + int sLen = salt.length; + // 1. If the length of M is greater than the input limitation for the hash + // function (2**61 - 1 octets for SHA-1) then output "message too long" + // and stop. + // 2. Let mHash = Hash(M), an octet string of length hLen. + if (hLen != mHash.length) + throw new IllegalArgumentException("wrong hash"); + // 3. If emBits < 8.hLen + 8.sLen + 9, output 'encoding error' and stop. + if (emBits < (8 * hLen + 8 * sLen + 9)) + throw new IllegalArgumentException("encoding error"); + int emLen = (emBits + 7) / 8; + // 4. Generate a random octet string salt of length sLen; if sLen = 0, + // then salt is the empty string. + // ...passed as argument to accomodate JCE + // 5. Let M0 = 00 00 00 00 00 00 00 00 || mHash || salt; + // M0 is an octet string of length 8 + hLen + sLen with eight initial zero + // octets. + // 6. Let H = Hash(M0), an octet string of length hLen. + byte[] H; + int i; + synchronized (hash) + { + for (i = 0; i < 8; i++) + hash.update((byte) 0x00); + + hash.update(mHash, 0, hLen); + hash.update(salt, 0, sLen); + H = hash.digest(); + } + // 7. Generate an octet string PS consisting of emLen - sLen - hLen - 2 + // zero octets. The length of PS may be 0. + // 8. Let DB = PS || 01 || salt. + byte[] DB = new byte[emLen - sLen - hLen - 2 + 1 + sLen]; + DB[emLen - sLen - hLen - 2] = 0x01; + System.arraycopy(salt, 0, DB, emLen - sLen - hLen - 1, sLen); + // 9. Let dbMask = MGF(H, emLen - hLen - 1). + byte[] dbMask = MGF(H, emLen - hLen - 1); + if (Configuration.DEBUG) + { + log.fine("dbMask (encode): " + Util.toString(dbMask)); + log.fine("DB (encode): " + Util.toString(DB)); + } + // 10. Let maskedDB = DB XOR dbMask. + for (i = 0; i < DB.length; i++) + DB[i] = (byte)(DB[i] ^ dbMask[i]); + // 11. Set the leftmost 8emLen - emBits bits of the leftmost octet in + // maskedDB to zero. + DB[0] &= (0xFF >>> (8 * emLen - emBits)); + // 12. Let EM = maskedDB || H || bc, where bc is the single octet with + // hexadecimal value 0xBC. + byte[] result = new byte[emLen]; + System.arraycopy(DB, 0, result, 0, emLen - hLen - 1); + System.arraycopy(H, 0, result, emLen - hLen - 1, hLen); + result[emLen - 1] = (byte) 0xBC; + // 13. Output EM. + return result; + } + + /** + * The decoding operation EMSA-PSS-Decode recovers the message hash from an + * encoded message EM and compares it to the hash of + * M. + * + * @param mHash the byte sequence resulting from applying the message digest + * algorithm Hash to the message M. + * @param EM the encoded message, an octet string of length + * emLen = CEILING(emBits/8). + * @param emBits the maximal bit length of the integer OS2IP(EM), at least + * 8.hLen + 8.sLen + 9. + * @param sLen the length, in octets, of the expected salt. + * @return true if the result of the verification was + * consistent with the expected reseult; and false if the + * result was inconsistent. + * @exception IllegalArgumentException if an exception occurs. + */ + public boolean decode(byte[] mHash, byte[] EM, int emBits, int sLen) + { + if (Configuration.DEBUG) + { + log.fine("mHash: " + Util.toString(mHash)); + log.fine("EM: " + Util.toString(EM)); + log.fine("emBits: " + String.valueOf(emBits)); + log.fine("sLen: " + String.valueOf(sLen)); + } + if (sLen < 0) + throw new IllegalArgumentException("sLen"); + // 1. If the length of M is greater than the input limitation for the hash + // function (2**61 ? 1 octets for SHA-1) then output 'inconsistent' and + // stop. + // 2. Let mHash = Hash(M), an octet string of length hLen. + if (hLen != mHash.length) + { + if (Configuration.DEBUG) + log.fine("hLen != mHash.length; hLen: " + String.valueOf(hLen)); + throw new IllegalArgumentException("wrong hash"); + } + // 3. If emBits < 8.hLen + 8.sLen + 9, output 'decoding error' and stop. + if (emBits < (8 * hLen + 8 * sLen + 9)) + { + if (Configuration.DEBUG) + log.fine("emBits < (8hLen + 8sLen + 9); sLen: " + + String.valueOf(sLen)); + throw new IllegalArgumentException("decoding error"); + } + int emLen = (emBits + 7) / 8; + // 4. If the rightmost octet of EM does not have hexadecimal value bc, + // output 'inconsistent' and stop. + if ((EM[EM.length - 1] & 0xFF) != 0xBC) + { + if (Configuration.DEBUG) + log.fine("EM does not end with 0xBC"); + return false; + } + // 5. Let maskedDB be the leftmost emLen ? hLen ? 1 octets of EM, and let + // H be the next hLen octets. + // 6. If the leftmost 8.emLen ? emBits bits of the leftmost octet in + // maskedDB are not all equal to zero, output 'inconsistent' and stop. + if ((EM[0] & (0xFF << (8 - (8 * emLen - emBits)))) != 0) + { + if (Configuration.DEBUG) + log.fine("Leftmost 8emLen - emBits bits of EM are not 0s"); + return false; + } + byte[] DB = new byte[emLen - hLen - 1]; + byte[] H = new byte[hLen]; + System.arraycopy(EM, 0, DB, 0, emLen - hLen - 1); + System.arraycopy(EM, emLen - hLen - 1, H, 0, hLen); + // 7. Let dbMask = MGF(H, emLen ? hLen ? 1). + byte[] dbMask = MGF(H, emLen - hLen - 1); + // 8. Let DB = maskedDB XOR dbMask. + int i; + for (i = 0; i < DB.length; i++) + DB[i] = (byte)(DB[i] ^ dbMask[i]); + // 9. Set the leftmost 8.emLen ? emBits bits of DB to zero. + DB[0] &= (0xFF >>> (8 * emLen - emBits)); + if (Configuration.DEBUG) + { + log.fine("dbMask (decode): " + Util.toString(dbMask)); + log.fine("DB (decode): " + Util.toString(DB)); + } + // 10. If the emLen -hLen -sLen -2 leftmost octets of DB are not zero or + // if the octet at position emLen -hLen -sLen -1 is not equal to 0x01, + // output 'inconsistent' and stop. + // IMPORTANT (rsn): this is an error in the specs, the index of the 0x01 + // byte should be emLen -hLen -sLen -2 and not -1! authors have been advised + for (i = 0; i < (emLen - hLen - sLen - 2); i++) + { + if (DB[i] != 0) + { + if (Configuration.DEBUG) + log.fine("DB[" + String.valueOf(i) + "] != 0x00"); + return false; + } + } + if (DB[i] != 0x01) + { // i == emLen -hLen -sLen -2 + if (Configuration.DEBUG) + log.fine("DB's byte at position (emLen -hLen -sLen -2); i.e. " + + String.valueOf(i) + " is not 0x01"); + return false; + } + // 11. Let salt be the last sLen octets of DB. + byte[] salt = new byte[sLen]; + System.arraycopy(DB, DB.length - sLen, salt, 0, sLen); + // 12. Let M0 = 00 00 00 00 00 00 00 00 || mHash || salt; + // M0 is an octet string of length 8 + hLen + sLen with eight initial + // zero octets. + // 13. Let H0 = Hash(M0), an octet string of length hLen. + byte[] H0; + synchronized (hash) + { + for (i = 0; i < 8; i++) + hash.update((byte) 0x00); + + hash.update(mHash, 0, hLen); + hash.update(salt, 0, sLen); + H0 = hash.digest(); + } + // 14. If H = H0, output 'consistent.' Otherwise, output 'inconsistent.' + return Arrays.equals(H, H0); + } + + /** + * A mask generation function takes an octet string of variable length and a + * desired output length as input, and outputs an octet string of the desired + * length. There may be restrictions on the length of the input and output + * octet strings, but such bounds are generally very large. Mask generation + * functions are deterministic; the octet string output is completely + * determined by the input octet string. The output of a mask generation + * function should be pseudorandom, that is, it should be infeasible to + * predict, given one part of the output but not the input, another part of + * the output. The provable security of RSA-PSS relies on the random nature of + * the output of the mask generation function, which in turn relies on the + * random nature of the underlying hash function. + * + * @param Z a seed. + * @param l the desired output length in octets. + * @return the mask. + * @exception IllegalArgumentException if the desired output length is too + * long. + */ + private byte[] MGF(byte[] Z, int l) + { + // 1. If l > (2**32).hLen, output 'mask too long' and stop. + if (l < 1 || (l & 0xFFFFFFFFL) > ((hLen & 0xFFFFFFFFL) << 32L)) + throw new IllegalArgumentException("mask too long"); + // 2. Let T be the empty octet string. + byte[] result = new byte[l]; + // 3. For i = 0 to CEILING(l/hLen) ? 1, do + int limit = ((l + hLen - 1) / hLen) - 1; + IMessageDigest hashZ = null; + hashZ = (IMessageDigest) hash.clone(); + hashZ.digest(); + hashZ.update(Z, 0, Z.length); + IMessageDigest hashZC = null; + byte[] t; + int sofar = 0; + int length; + for (int i = 0; i < limit; i++) + { + // 3.1 Convert i to an octet string C of length 4 with the primitive + // I2OSP: C = I2OSP(i, 4). + // 3.2 Concatenate the hash of the seed Z and C to the octet string T: + // T = T || Hash(Z || C) + hashZC = (IMessageDigest) hashZ.clone(); + hashZC.update((byte)(i >>> 24)); + hashZC.update((byte)(i >>> 16)); + hashZC.update((byte)(i >>> 8)); + hashZC.update((byte) i); + t = hashZC.digest(); + length = l - sofar; + length = (length > hLen ? hLen : length); + System.arraycopy(t, 0, result, sofar, length); + sofar += length; + } + // 4. Output the leading l octets of T as the octet string mask. + return result; + } +} diff --git a/libjava/classpath/gnu/java/security/sig/rsa/RSA.java b/libjava/classpath/gnu/java/security/sig/rsa/RSA.java new file mode 100644 index 000000000..343b2cf65 --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/rsa/RSA.java @@ -0,0 +1,324 @@ +/* RSA.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +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. */ + + +package gnu.java.security.sig.rsa; + +import gnu.java.security.Properties; +import gnu.java.security.util.PRNG; + +import java.math.BigInteger; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.interfaces.RSAPrivateCrtKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; + +/** + * Utility methods related to the RSA algorithm. + *

+ * References: + *

    + *
  1. + * RSA-PSS Signature Scheme with Appendix, part B.
    + * Primitive specification and supporting documentation.
    + * Jakob Jonsson and Burt Kaliski.
  2. + *
  3. Public-Key Cryptography + * Standards (PKCS) #1:
    + * RSA Cryptography Specifications Version 2.1.
    + * Jakob Jonsson and Burt Kaliski.
  4. + *
  5. + * Remote timing attacks are practical
    + * D. Boneh and D. Brumley.
  6. + *
+ */ +public class RSA +{ + private static final BigInteger ZERO = BigInteger.ZERO; + + private static final BigInteger ONE = BigInteger.ONE; + + /** Our default source of randomness. */ + private static final PRNG prng = PRNG.getInstance(); + + /** Trivial private constructor to enforce Singleton pattern. */ + private RSA() + { + super(); + } + + /** + * An implementation of the RSASP method: Assuming that the designated + * RSA private key is a valid one, this method computes a signature + * representative for a designated message representative signed + * by the holder of the designated RSA private key. + * + * @param K the RSA private key. + * @param m the message representative: an integer between + * 0 and n - 1, where n + * is the RSA modulus. + * @return the signature representative, an integer between + * 0 and n - 1, where n + * is the RSA modulus. + * @throws ClassCastException if K is not an RSA one. + * @throws IllegalArgumentException if m (the message + * representative) is out of range. + */ + public static final BigInteger sign(final PrivateKey K, final BigInteger m) + { + try + { + return RSADP((RSAPrivateKey) K, m); + } + catch (IllegalArgumentException x) + { + throw new IllegalArgumentException("message representative out of range"); + } + } + + /** + * An implementation of the RSAVP method: Assuming that the designated + * RSA public key is a valid one, this method computes a message + * representative for the designated signature representative + * generated by an RSA private key, for a message intended for the holder of + * the designated RSA public key. + * + * @param K the RSA public key. + * @param s the signature representative, an integer between + * 0 and n - 1, where n + * is the RSA modulus. + * @return a message representative: an integer between 0 + * and n - 1, where n is the RSA + * modulus. + * @throws ClassCastException if K is not an RSA one. + * @throws IllegalArgumentException if s (the signature + * representative) is out of range. + */ + public static final BigInteger verify(final PublicKey K, final BigInteger s) + { + try + { + return RSAEP((RSAPublicKey) K, s); + } + catch (IllegalArgumentException x) + { + throw new IllegalArgumentException("signature representative out of range"); + } + } + + /** + * An implementation of the RSAEP algorithm. + * + * @param K the recipient's RSA public key. + * @param m the message representative as an MPI. + * @return the resulting MPI --an MPI between 0 and + * n - 1 (n being the public shared + * modulus)-- that will eventually be padded with an appropriate + * framing/padding scheme. + * @throws ClassCastException if K is not an RSA one. + * @throws IllegalArgumentException if m, the message + * representative is not between 0 and + * n - 1 (n being the public shared + * modulus). + */ + public static final BigInteger encrypt(final PublicKey K, final BigInteger m) + { + try + { + return RSAEP((RSAPublicKey) K, m); + } + catch (IllegalArgumentException x) + { + throw new IllegalArgumentException("message representative out of range"); + } + } + + /** + * An implementation of the RSADP algorithm. + * + * @param K the recipient's RSA private key. + * @param c the ciphertext representative as an MPI. + * @return the message representative, an MPI between 0 and + * n - 1 (n being the shared public + * modulus). + * @throws ClassCastException if K is not an RSA one. + * @throws IllegalArgumentException if c, the ciphertext + * representative is not between 0 and + * n - 1 (n being the shared public + * modulus). + */ + public static final BigInteger decrypt(final PrivateKey K, final BigInteger c) + { + try + { + return RSADP((RSAPrivateKey) K, c); + } + catch (IllegalArgumentException x) + { + throw new IllegalArgumentException("ciphertext representative out of range"); + } + } + + /** + * Converts a multi-precision integer (MPI) s into an + * octet sequence of length k. + * + * @param s the multi-precision integer to convert. + * @param k the length of the output. + * @return the result of the transform. + * @exception IllegalArgumentException if the length in octets of meaningful + * bytes of s is greater than k. + */ + public static final byte[] I2OSP(final BigInteger s, final int k) + { + byte[] result = s.toByteArray(); + if (result.length < k) + { + final byte[] newResult = new byte[k]; + System.arraycopy(result, 0, newResult, k - result.length, result.length); + result = newResult; + } + else if (result.length > k) + { // leftmost extra bytes should all be 0 + final int limit = result.length - k; + for (int i = 0; i < limit; i++) + { + if (result[i] != 0x00) + throw new IllegalArgumentException("integer too large"); + } + final byte[] newResult = new byte[k]; + System.arraycopy(result, limit, newResult, 0, k); + result = newResult; + } + return result; + } + + private static final BigInteger RSAEP(final RSAPublicKey K, final BigInteger m) + { + // 1. If the representative m is not between 0 and n - 1, output + // "representative out of range" and stop. + final BigInteger n = K.getModulus(); + if (m.compareTo(ZERO) < 0 || m.compareTo(n.subtract(ONE)) > 0) + throw new IllegalArgumentException(); + // 2. Let c = m^e mod n. + final BigInteger e = K.getPublicExponent(); + final BigInteger result = m.modPow(e, n); + // 3. Output c. + return result; + } + + private static final BigInteger RSADP(final RSAPrivateKey K, BigInteger c) + { + // 1. If the representative c is not between 0 and n - 1, output + // "representative out of range" and stop. + final BigInteger n = K.getModulus(); + if (c.compareTo(ZERO) < 0 || c.compareTo(n.subtract(ONE)) > 0) + throw new IllegalArgumentException(); + // 2. The representative m is computed as follows. + BigInteger result; + if (! (K instanceof RSAPrivateCrtKey)) + { + // a. If the first form (n, d) of K is used, let m = c^d mod n. + final BigInteger d = K.getPrivateExponent(); + result = c.modPow(d, n); + } + else + { + // from [3] p.13 --see class docs: + // The RSA blinding operation calculates x = (r^e) * g mod n before + // decryption, where r is random, e is the RSA encryption exponent, and + // g is the ciphertext to be decrypted. x is then decrypted as normal, + // followed by division by r, i.e. (x^e) / r mod n. Since r is random, + // x is random and timing the decryption should not reveal information + // about the key. Note that r should be a new random number for every + // decryption. + final boolean rsaBlinding = Properties.doRSABlinding(); + BigInteger r = null; + BigInteger e = null; + if (rsaBlinding) + { // pre-decryption + r = newR(n); + e = ((RSAPrivateCrtKey) K).getPublicExponent(); + final BigInteger x = r.modPow(e, n).multiply(c).mod(n); + c = x; + } + // b. If the second form (p, q, dP, dQ, qInv) and (r_i, d_i, t_i) + // of K is used, proceed as follows: + final BigInteger p = ((RSAPrivateCrtKey) K).getPrimeP(); + final BigInteger q = ((RSAPrivateCrtKey) K).getPrimeQ(); + final BigInteger dP = ((RSAPrivateCrtKey) K).getPrimeExponentP(); + final BigInteger dQ = ((RSAPrivateCrtKey) K).getPrimeExponentQ(); + final BigInteger qInv = ((RSAPrivateCrtKey) K).getCrtCoefficient(); + // i. Let m_1 = c^dP mod p and m_2 = c^dQ mod q. + final BigInteger m_1 = c.modPow(dP, p); + final BigInteger m_2 = c.modPow(dQ, q); + // ii. If u > 2, let m_i = c^(d_i) mod r_i, i = 3, ..., u. + // iii. Let h = (m_1 - m_2) * qInv mod p. + final BigInteger h = m_1.subtract(m_2).multiply(qInv).mod(p); + // iv. Let m = m_2 + q * h. + result = m_2.add(q.multiply(h)); + if (rsaBlinding) // post-decryption + result = result.multiply(r.modInverse(n)).mod(n); + } + // 3. Output m + return result; + } + + /** + * Returns a random MPI with a random bit-length of the form 8b, + * where b is in the range [32..64]. + * + * @return a random MPI whose length in bytes is between 32 and 64 inclusive. + */ + private static final BigInteger newR(final BigInteger N) + { + final int upper = (N.bitLength() + 7) / 8; + final int lower = upper / 2; + final byte[] bl = new byte[1]; + int b; + do + { + prng.nextBytes(bl); + b = bl[0] & 0xFF; + } + while (b < lower || b > upper); + final byte[] buffer = new byte[b]; // 256-bit MPI + prng.nextBytes(buffer); + return new BigInteger(1, buffer); + } +} diff --git a/libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5Signature.java b/libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5Signature.java new file mode 100644 index 000000000..1420331de --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5Signature.java @@ -0,0 +1,224 @@ +/* RSAPKCS1V1_5Signature.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +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. */ + + +package gnu.java.security.sig.rsa; + +import gnu.java.security.Registry; +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.sig.BaseSignature; + +import java.math.BigInteger; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.util.Arrays; + +/** + * The RSA-PKCS1-V1.5 signature scheme is a digital signature scheme with + * appendix (SSA) combining the RSA algorithm with the EMSA-PKCS1-v1_5 encoding + * method. + *

+ * References: + *

    + *
  1. + * RSA-PSS Signature Scheme with Appendix, part B.
    + * Primitive specification and supporting documentation.
    + * Jakob Jonsson and Burt Kaliski.
  2. + *
  3. Public-Key Cryptography + * Standards (PKCS) #1:
    + * RSA Cryptography Specifications Version 2.1.
    + * Jakob Jonsson and Burt Kaliski.
  4. + *
+ */ +public class RSAPKCS1V1_5Signature + extends BaseSignature +{ + /** The underlying EMSA-PKCS1-v1.5 instance for this object. */ + private EMSA_PKCS1_V1_5 pkcs1; + + /** + * Default 0-arguments constructor. Uses SHA-1 as the default hash. + */ + public RSAPKCS1V1_5Signature() + { + this(Registry.SHA160_HASH); + } + + /** + * Constructs an instance of this object using the designated message digest + * algorithm as its underlying hash function. + * + * @param mdName the canonical name of the underlying hash function. + */ + public RSAPKCS1V1_5Signature(final String mdName) + { + this(HashFactory.getInstance(mdName)); + } + + public RSAPKCS1V1_5Signature(IMessageDigest md) + { + super(Registry.RSA_PKCS1_V1_5_SIG, md); + + pkcs1 = EMSA_PKCS1_V1_5.getInstance(md.name()); + } + + /** Private constructor for cloning purposes. */ + private RSAPKCS1V1_5Signature(final RSAPKCS1V1_5Signature that) + { + this(that.md.name()); + + this.publicKey = that.publicKey; + this.privateKey = that.privateKey; + this.md = (IMessageDigest) that.md.clone(); + this.pkcs1 = (EMSA_PKCS1_V1_5) that.pkcs1.clone(); + } + + public Object clone() + { + return new RSAPKCS1V1_5Signature(this); + } + + protected void setupForVerification(final PublicKey k) + throws IllegalArgumentException + { + if (! (k instanceof RSAPublicKey)) + throw new IllegalArgumentException(); + + publicKey = k; + } + + protected void setupForSigning(final PrivateKey k) + throws IllegalArgumentException + { + if (! (k instanceof RSAPrivateKey)) + throw new IllegalArgumentException(); + + privateKey = k; + } + + protected Object generateSignature() throws IllegalStateException + { + // 1. EMSA-PKCS1-v1_5 encoding: Apply the EMSA-PKCS1-v1_5 encoding + // operation (Section 9.2) to the message M to produce an encoded + // message EM of length k octets: + // + // EM = EMSA-PKCS1-V1_5-ENCODE (M, k). + // + // If the encoding operation outputs "message too long," output + // "message too long" and stop. If the encoding operation outputs + // "intended encoded message length too short," output "RSA modulus + // too short" and stop. + final int modBits = ((RSAPrivateKey) privateKey).getModulus().bitLength(); + final int k = (modBits + 7) / 8; + final byte[] EM = pkcs1.encode(md.digest(), k); + // 2. RSA signature: + // a. Convert the encoded message EM to an integer message epresentative + // m (see Section 4.2): m = OS2IP (EM). + final BigInteger m = new BigInteger(1, EM); + // b. Apply the RSASP1 signature primitive (Section 5.2.1) to the RSA + // private key K and the message representative m to produce an + // integer signature representative s: s = RSASP1 (K, m). + final BigInteger s = RSA.sign(privateKey, m); + // c. Convert the signature representative s to a signature S of length + // k octets (see Section 4.1): S = I2OSP (s, k). + // 3. Output the signature S. + return RSA.I2OSP(s, k); + } + + protected boolean verifySignature(final Object sig) + throws IllegalStateException + { + if (publicKey == null) + throw new IllegalStateException(); + final byte[] S = (byte[]) sig; + // 1. Length checking: If the length of the signature S is not k octets, + // output "invalid signature" and stop. + final int modBits = ((RSAPublicKey) publicKey).getModulus().bitLength(); + final int k = (modBits + 7) / 8; + if (S.length != k) + return false; + // 2. RSA verification: + // a. Convert the signature S to an integer signature representative + // s (see Section 4.2): s = OS2IP (S). + final BigInteger s = new BigInteger(1, S); + // b. Apply the RSAVP1 verification primitive (Section 5.2.2) to the + // RSA public key (n, e) and the signature representative s to + // produce an integer message representative m: + // m = RSAVP1 ((n, e), s). + // If RSAVP1 outputs "signature representative out of range," + // output "invalid signature" and stop. + final BigInteger m; + try + { + m = RSA.verify(publicKey, s); + } + catch (IllegalArgumentException x) + { + return false; + } + // c. Convert the message representative m to an encoded message EM + // of length k octets (see Section 4.1): EM = I2OSP (m, k). + // If I2OSP outputs "integer too large," output "invalid signature" + // and stop. + final byte[] EM; + try + { + EM = RSA.I2OSP(m, k); + } + catch (IllegalArgumentException x) + { + return false; + } + // 3. EMSA-PKCS1-v1_5 encoding: Apply the EMSA-PKCS1-v1_5 encoding + // operation (Section 9.2) to the message M to produce a second + // encoded message EM' of length k octets: + // EM' = EMSA-PKCS1-V1_5-ENCODE (M, k). + // If the encoding operation outputs "message too long," output + // "message too long" and stop. If the encoding operation outputs + // "intended encoded message length too short," output "RSA modulus + // too short" and stop. + final byte[] EMp = pkcs1.encode(md.digest(), k); + // 4. Compare the encoded message EM and the second encoded message EM'. + // If they are the same, output "valid signature"; otherwise, output + // "invalid signature." + return Arrays.equals(EM, EMp); + } +} diff --git a/libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureRawCodec.java b/libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureRawCodec.java new file mode 100644 index 000000000..548dc3deb --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureRawCodec.java @@ -0,0 +1,153 @@ +/* RSAPKCS1V1_5SignatureRawCodec.java -- Raw RSA PKCS1 v1.5 signature codeec + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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. */ + + +package gnu.java.security.sig.rsa; + +import java.io.ByteArrayOutputStream; + +import gnu.java.security.Registry; +import gnu.java.security.sig.ISignatureCodec; + +/** + * An object that implements the {@link ISignatureCodec} operations for the + * Raw format to use with RSA-PKCS#1 v1.5 signatures. + */ +public class RSAPKCS1V1_5SignatureRawCodec + implements ISignatureCodec +{ + public int getFormatID() + { + return RAW_FORMAT; + } + + /** + * Returns the encoded form of the designated RSA-PKCS#1 (v1.5) signature + * object according to the Raw format supported by this library. + *

+ * The Raw format for such a signature, in this implementation, is a + * byte sequence consisting of the following: + *

+ *

    + *
  1. 4-byte magic consisting of the value of the literal + * {@link Registry#MAGIC_RAW_RSA_PKCS1V1_5_SIGNATURE}, + *
  2. + *
  3. 1-byte version consisting of the constant: 0x01,
  4. + *
  5. 4-byte count of following bytes representing the RSA-PKCS#1 (v1.5) + * signature bytes in internet order,
  6. + *
  7. the RSA-PKCS#1 (v1.5) signature bytes in internet order.
  8. + *
+ * + * @param signature the signature to encode, consisting of the output of the + * sign() method of a {@link RSAPKCS1V1_5Signature} + * instance --a byte array. + * @return the Raw format encoding of the designated signature. + * @exception IllegalArgumentException if the designated signature is not an + * RSA-PKCS#1 (v1.5) one. + */ + public byte[] encodeSignature(Object signature) + { + byte[] buffer; + try + { + buffer = (byte[]) signature; + } + catch (Exception x) + { + throw new IllegalArgumentException("Signature/codec mismatch"); + } + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + // magic + baos.write(Registry.MAGIC_RAW_RSA_PKCS1V1_5_SIGNATURE[0]); + baos.write(Registry.MAGIC_RAW_RSA_PKCS1V1_5_SIGNATURE[1]); + baos.write(Registry.MAGIC_RAW_RSA_PKCS1V1_5_SIGNATURE[2]); + baos.write(Registry.MAGIC_RAW_RSA_PKCS1V1_5_SIGNATURE[3]); + + // version + baos.write(0x01); + + // signature bytes + int length = buffer.length; + baos.write( length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write( length & 0xFF); + baos.write(buffer, 0, length); + + return baos.toByteArray(); + } + + /** + * Returns the decoded object from a designated input assumed to have been + * generated by the {@link #encodeSignature(Object)} method. + * + * @param input the input bytes of a previously Raw-encoded RSA PKCS1 (v1.5) + * signature. + * @return the signature object. + * @throws IllegalArgumentException if the designated input does not start + * with the right magic characters, or if the version + * is not supported. + */ + public Object decodeSignature(byte[] input) + { + // magic + if (input[0] != Registry.MAGIC_RAW_RSA_PKCS1V1_5_SIGNATURE[0] + || input[1] != Registry.MAGIC_RAW_RSA_PKCS1V1_5_SIGNATURE[1] + || input[2] != Registry.MAGIC_RAW_RSA_PKCS1V1_5_SIGNATURE[2] + || input[3] != Registry.MAGIC_RAW_RSA_PKCS1V1_5_SIGNATURE[3]) + throw new IllegalArgumentException("Signature/codec mismatch"); + + // version + if (input[4] != 0x01) + throw new IllegalArgumentException("Wrong or unsupported format version"); + + int i = 5; + int l; + + // signature bytes + l = input[i++] << 24 + | (input[i++] & 0xFF) << 16 + | (input[i++] & 0xFF) << 8 + | (input[i++] & 0xFF); + byte[] result = new byte[l]; + System.arraycopy(input, i, result, 0, l); + + return result; + } +} diff --git a/libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureX509Codec.java b/libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureX509Codec.java new file mode 100644 index 000000000..ee8586f7d --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureX509Codec.java @@ -0,0 +1,128 @@ +/* RSAPSSSignatureX509Codec.java -- X.509 encoder/decoder for RSA signatures + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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. */ + + +package gnu.java.security.sig.rsa; + +import gnu.java.security.Registry; +import gnu.java.security.sig.ISignatureCodec; + +import java.security.InvalidParameterException; + +/** + * An implementation of an {@link ISignatureCodec} that knows to encode and + * decode RSA PKCS1 (v1.5) signatures into the raw bytes which would constitute + * a DER-encoded form of the ASN.1 structure defined in RFC-2459, and RFC-2313 + * as described in the next paragraphs. + *

+ * Digital signatures when transmitted in an X.509 certificates are encoded + * in DER (Distinguished Encoding Rules) as a BIT STRING; i.e. + * + *

+ * Certificate ::= SEQUENCE {
+ *   tbsCertificate       TBSCertificate,
+ *   signatureAlgorithm   AlgorithmIdentifier,
+ *   signature            BIT STRING
+ * }
+ * 
+ *

+ * The output of the encoder, and the input of the decoder, of this codec are + * then the raw bytes of such a BIT STRING; i.e. not the DER-encoded + * form itself. + *

+ * Our implementation of the RSA PKCS1 signature algorithm outputs a byte array + * as the result of generating a digital signature, in accordance with RFC-2313. + * As a consequence, the encoder and decoder of this codec, simply pass through + * such a byte array. + *

+ * Client code that needs to build a DER BIT STRING MUST construct such + * an ASN.1 value. The following is an example of how to do this: + *

+ *

+ * ...
+ * import gnu.java.security.der.BitString;
+ * import gnu.java.security.der.DER;
+ * import gnu.java.security.der.DERValue;
+ * ...
+ * DERValue bitString = new DERValue(DER.BIT_STRING, new BitString(sigBytes));
+ * ...
+ * 
+ */ +public class RSAPKCS1V1_5SignatureX509Codec + implements ISignatureCodec +{ + // default 0-arguments constructor + + public int getFormatID() + { + return Registry.X509_ENCODING_ID; + } + + /** + * Encodes an RSA Signature output as a signature BIT STRING as + * defined in the documentation of this class. + * + * @param signature the output of the RSA PKCS1 (v1.5) signature algorithm; + * i.e. the value returned by the invocation of + * {@link gnu.java.security.sig.ISignature#sign()} method. In the + * case of the RSA PKCS1 (v1.5) signature this is an array of bytes. + * @return the raw bytes of an RSA signature which could be then used as the + * contents of a BIT STRING as per rfc-2459. + */ + public byte[] encodeSignature(Object signature) + { + byte[] result = (byte[]) signature; + return result; + } + + /** + * Decodes a signature as defined in the documentation of this class. + * + * @param input the byte array to unmarshall into a valid RSA PKCS1 (v1.5) + * signature instance; i.e. a byte array. MUST NOT be null. + * @return an array of raw bytes decoded from the designated input. In the + * case of RSA PKCS1 (v1.5) this is the same as the input. + * @throw InvalidParameterException if the input array is null. + */ + public Object decodeSignature(byte[] input) + { + if (input == null) + throw new InvalidParameterException("Input bytes MUST NOT be null"); + + return input; + } +} diff --git a/libjava/classpath/gnu/java/security/sig/rsa/RSAPSSSignature.java b/libjava/classpath/gnu/java/security/sig/rsa/RSAPSSSignature.java new file mode 100644 index 000000000..d8f8327f1 --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/rsa/RSAPSSSignature.java @@ -0,0 +1,255 @@ +/* RSAPSSSignature.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +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. */ + + +package gnu.java.security.sig.rsa; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.sig.BaseSignature; +import gnu.java.security.util.Util; + +import java.math.BigInteger; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.util.logging.Logger; + +/** + * The RSA-PSS signature scheme is a public-key encryption scheme combining the + * RSA algorithm with the Probabilistic Signature Scheme (PSS) encoding method. + *

+ * The inventors of RSA are Ronald L. Rivest, Adi Shamir, and Leonard Adleman, + * while the inventors of the PSS encoding method are Mihir Bellare and Phillip + * Rogaway. During efforts to adopt RSA-PSS into the P1363a standards effort, + * certain adaptations to the original version of RSA-PSS were made by Mihir + * Bellare and Phillip Rogaway and also by Burt Kaliski (the editor of IEEE + * P1363a) to facilitate implementation and integration into existing protocols. + *

+ * References: + *

    + *
  1. + * RSA-PSS Signature Scheme with Appendix, part B.
    + * Primitive specification and supporting documentation.
    + * Jakob Jonsson and Burt Kaliski.
  2. + *
+ */ +public class RSAPSSSignature + extends BaseSignature +{ + private static final Logger log = Logger.getLogger(RSAPSSSignature.class.getName()); + + /** The underlying EMSA-PSS instance for this object. */ + private EMSA_PSS pss; + + /** The desired length in octets of the EMSA-PSS salt. */ + private int sLen; + + /** + * Default 0-arguments constructor. Uses SHA-1 as the default hash and a + * 0-octet salt. + */ + public RSAPSSSignature() + { + this(Registry.SHA160_HASH, 0); + } + + /** + * Constructs an instance of this object using the designated message digest + * algorithm as its underlying hash function, and having 0-octet salt. + * + * @param mdName the canonical name of the underlying hash function. + */ + public RSAPSSSignature(String mdName) + { + this(mdName, 0); + } + + /** + * Constructs an instance of this object using the designated message digest + * algorithm as its underlying hash function. + * + * @param mdName the canonical name of the underlying hash function. + * @param sLen the desired length in octets of the salt to use for encoding / + * decoding signatures. + */ + public RSAPSSSignature(String mdName, int sLen) + { + this(HashFactory.getInstance(mdName), sLen); + } + + public RSAPSSSignature(IMessageDigest md, int sLen) + { + super(Registry.RSA_PSS_SIG, md); + + pss = EMSA_PSS.getInstance(md.name()); + this.sLen = sLen; + } + + /** Private constructor for cloning purposes. */ + private RSAPSSSignature(RSAPSSSignature that) + { + this(that.md.name(), that.sLen); + + this.publicKey = that.publicKey; + this.privateKey = that.privateKey; + this.md = (IMessageDigest) that.md.clone(); + this.pss = (EMSA_PSS) that.pss.clone(); + } + + public Object clone() + { + return new RSAPSSSignature(this); + } + + protected void setupForVerification(PublicKey k) + throws IllegalArgumentException + { + if (! (k instanceof RSAPublicKey)) + throw new IllegalArgumentException(); + + publicKey = (RSAPublicKey) k; + } + + protected void setupForSigning(PrivateKey k) throws IllegalArgumentException + { + if (! (k instanceof RSAPrivateKey)) + throw new IllegalArgumentException(); + + privateKey = (RSAPrivateKey) k; + } + + protected Object generateSignature() throws IllegalStateException + { + // 1. Apply the EMSA-PSS encoding operation to the message M to produce an + // encoded message EM of length CEILING((modBits ? 1)/8) octets such + // that the bit length of the integer OS2IP(EM) is at most modBits ? 1: + // EM = EMSA-PSS-Encode(M,modBits ? 1). + // Note that the octet length of EM will be one less than k if + // modBits ? 1 is divisible by 8. If the encoding operation outputs + // 'message too long' or 'encoding error,' then output 'message too + // long' or 'encoding error' and stop. + int modBits = ((RSAPrivateKey) privateKey).getModulus().bitLength(); + byte[] salt = new byte[sLen]; + this.nextRandomBytes(salt); + byte[] EM = pss.encode(md.digest(), modBits - 1, salt); + if (Configuration.DEBUG) + log.fine("EM (sign): " + Util.toString(EM)); + // 2. Convert the encoded message EM to an integer message representative + // m (see Section 1.2.2): m = OS2IP(EM). + BigInteger m = new BigInteger(1, EM); + // 3. Apply the RSASP signature primitive to the public key K and the + // message representative m to produce an integer signature + // representative s: s = RSASP(K,m). + BigInteger s = RSA.sign(privateKey, m); + // 4. Convert the signature representative s to a signature S of length k + // octets (see Section 1.2.1): S = I2OSP(s, k). + // 5. Output the signature S. + int k = (modBits + 7) / 8; + // return encodeSignature(s, k); + return RSA.I2OSP(s, k); + } + + protected boolean verifySignature(Object sig) throws IllegalStateException + { + if (publicKey == null) + throw new IllegalStateException(); + // byte[] S = decodeSignature(sig); + byte[] S = (byte[]) sig; + // 1. If the length of the signature S is not k octets, output 'signature + // invalid' and stop. + int modBits = ((RSAPublicKey) publicKey).getModulus().bitLength(); + int k = (modBits + 7) / 8; + if (S.length != k) + return false; + // 2. Convert the signature S to an integer signature representative s: + // s = OS2IP(S). + BigInteger s = new BigInteger(1, S); + // 3. Apply the RSAVP verification primitive to the public key (n, e) and + // the signature representative s to produce an integer message + // representative m: m = RSAVP((n, e), s). + // If RSAVP outputs 'signature representative out of range,' then + // output 'signature invalid' and stop. + BigInteger m = null; + try + { + m = RSA.verify(publicKey, s); + } + catch (IllegalArgumentException x) + { + return false; + } + // 4. Convert the message representative m to an encoded message EM of + // length emLen = CEILING((modBits - 1)/8) octets, where modBits is + // equal to the bit length of the modulus: EM = I2OSP(m, emLen). + // Note that emLen will be one less than k if modBits - 1 is divisible + // by 8. If I2OSP outputs 'integer too large,' then output 'signature + // invalid' and stop. + int emBits = modBits - 1; + int emLen = (emBits + 7) / 8; + byte[] EM = m.toByteArray(); + if (Configuration.DEBUG) + log.fine("EM (verify): " + Util.toString(EM)); + if (EM.length > emLen) + return false; + else if (EM.length < emLen) + { + byte[] newEM = new byte[emLen]; + System.arraycopy(EM, 0, newEM, emLen - EM.length, EM.length); + EM = newEM; + } + // 5. Apply the EMSA-PSS decoding operation to the message M and the + // encoded message EM: Result = EMSA-PSS-Decode(M, EM, emBits). If + // Result = 'consistent,' output 'signature verified.' Otherwise, + // output 'signature invalid.' + byte[] mHash = md.digest(); + boolean result = false; + try + { + result = pss.decode(mHash, EM, emBits, sLen); + } + catch (IllegalArgumentException x) + { + result = false; + } + return result; + } +} diff --git a/libjava/classpath/gnu/java/security/sig/rsa/RSAPSSSignatureRawCodec.java b/libjava/classpath/gnu/java/security/sig/rsa/RSAPSSSignatureRawCodec.java new file mode 100644 index 000000000..b147ea3ea --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/rsa/RSAPSSSignatureRawCodec.java @@ -0,0 +1,134 @@ +/* RSAPSSSignatureRawCodec.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +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. */ + + +package gnu.java.security.sig.rsa; + +import gnu.java.security.Registry; +import gnu.java.security.sig.ISignatureCodec; + +import java.io.ByteArrayOutputStream; + +/** + * An object that implements the {@link ISignatureCodec} operations for the + * Raw format to use with RSA-PSS signatures. + */ +public class RSAPSSSignatureRawCodec + implements ISignatureCodec +{ + // implicit 0-arguments constructor + + public int getFormatID() + { + return RAW_FORMAT; + } + + /** + * Returns the encoded form of the designated RSA-PSS signature object + * according to the Raw format supported by this library. + *

+ * The Raw format for an RSA-PSS signature, in this implementation, is + * a byte sequence consisting of the following: + *

    + *
  1. 4-byte magic consisting of the value of the literal + * {@link Registry#MAGIC_RAW_RSA_PSS_SIGNATURE}, + *
  2. + *
  3. 1-byte version consisting of the constant: 0x01,
  4. + *
  5. 4-byte count of following bytes representing the RSA-PSS signature + * bytes in internet order,
  6. + *
  7. the RSA-PSS signature bytes in internet order.
  8. + *
+ * + * @param signature the signature to encode, consisting of the output of the + * sign() method of a {@link RSAPSSSignature} instance + * --a byte array. + * @return the Raw format encoding of the designated signature. + * @exception IllegalArgumentException if the designated signature is not an + * RSA-PSS one. + */ + public byte[] encodeSignature(Object signature) + { + byte[] buffer; + try + { + buffer = (byte[]) signature; + } + catch (Exception x) + { + throw new IllegalArgumentException("signature"); + } + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + // magic + baos.write(Registry.MAGIC_RAW_RSA_PSS_SIGNATURE[0]); + baos.write(Registry.MAGIC_RAW_RSA_PSS_SIGNATURE[1]); + baos.write(Registry.MAGIC_RAW_RSA_PSS_SIGNATURE[2]); + baos.write(Registry.MAGIC_RAW_RSA_PSS_SIGNATURE[3]); + // version + baos.write(0x01); + // signature bytes + int length = buffer.length; + baos.write( length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + return baos.toByteArray(); + } + + public Object decodeSignature(byte[] k) + { + // magic + if (k[0] != Registry.MAGIC_RAW_RSA_PSS_SIGNATURE[0] + || k[1] != Registry.MAGIC_RAW_RSA_PSS_SIGNATURE[1] + || k[2] != Registry.MAGIC_RAW_RSA_PSS_SIGNATURE[2] + || k[3] != Registry.MAGIC_RAW_RSA_PSS_SIGNATURE[3]) + throw new IllegalArgumentException("magic"); + // version + if (k[4] != 0x01) + throw new IllegalArgumentException("version"); + int i = 5; + int l; + // signature bytes + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + byte[] result = new byte[l]; + System.arraycopy(k, i, result, 0, l); + return result; + } +} diff --git a/libjava/classpath/gnu/java/security/sig/rsa/RSASignatureFactory.java b/libjava/classpath/gnu/java/security/sig/rsa/RSASignatureFactory.java new file mode 100644 index 000000000..ba5121b46 --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/rsa/RSASignatureFactory.java @@ -0,0 +1,176 @@ +/* RSASignatureFactory.java -- A Factory class to instantiate RSA Signatures + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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. */ + + +package gnu.java.security.sig.rsa; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import gnu.java.security.Registry; +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.sig.ISignature; + +/** + * A Factory class to instantiate RSA Signature classes. + */ +public class RSASignatureFactory +{ + private static Set names; + + /** + * Private constructor to enforce usage through Factory (class) methods. + */ + private RSASignatureFactory() + { + super(); + } + + /** + * Returns a new instance of an RSA Signature given its name. The name of an + * RSA Signature always starts with rsa-, followed by either + * pss or pkcs1_v1.5. An optional message digest + * name, to be used with the RSA signature may be specified by appending the + * hyphen chanaracter - followed by the canonical message digest + * algorithm name. When no message digest algorithm name is given, SHA-160 is + * used. + * + * @param name the composite RSA signature name. + * @return a new instance of an RSA Signature algorithm implementation. + * Returns null if the given name does not correspond to any + * supported RSA Signature encoding and message digest combination. + */ + public static final ISignature getInstance(String name) + { + if (name == null) + return null; + + name = name.trim(); + if (name.length() == 0) + return null; + + name = name.toLowerCase(); + if (! name.startsWith(Registry.RSA_SIG_PREFIX)) + return null; + + name = name.substring(Registry.RSA_SIG_PREFIX.length()).trim(); + if (name.startsWith(Registry.RSA_PSS_ENCODING)) + return getPSSSignature(name); + else if (name.startsWith(Registry.RSA_PKCS1_V1_5_ENCODING)) + return getPKCS1Signature(name); + else + return null; + } + + /** + * Returns a {@link Set} of names of RSA signatures supported by this + * Factory. + * + * @return a {@link Set} of RSA Signature algorithm names (Strings). + */ + public static synchronized final Set getNames() + { + if (names == null) + { + Set hashNames = HashFactory.getNames(); + HashSet hs = new HashSet(); + for (Iterator it = hashNames.iterator(); it.hasNext();) + { + String mdName = (String) it.next(); + hs.add(Registry.RSA_PSS_SIG + "-" + mdName); + } + + hs.add(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.MD2_HASH); + hs.add(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.MD5_HASH); + hs.add(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.SHA160_HASH); + hs.add(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.SHA256_HASH); + hs.add(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.SHA384_HASH); + hs.add(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.SHA512_HASH); + + names = Collections.unmodifiableSet(hs); + } + + return names; + } + + private static final ISignature getPSSSignature(String name) + { + name = name.substring(Registry.RSA_PSS_ENCODING.length()).trim(); + // remove the hyphen if found at the beginning + if (name.startsWith("-")) + name = name.substring(1).trim(); + + IMessageDigest md; + if (name.length() == 0) + md = HashFactory.getInstance(Registry.SHA160_HASH); + else + { + // check if there is such a hash + md = HashFactory.getInstance(name); + if (md == null) + return null; + } + + ISignature result = new RSAPSSSignature(md, 0); + return result; + } + + private static final ISignature getPKCS1Signature(String name) + { + name = name.substring(Registry.RSA_PKCS1_V1_5_ENCODING.length()).trim(); + // remove the hyphen if found at the beginning + if (name.startsWith("-")) + name = name.substring(1).trim(); + + IMessageDigest md; + if (name.length() == 0) + md = HashFactory.getInstance(Registry.SHA160_HASH); + else + { + // check if there is such a hash + md = HashFactory.getInstance(name); + if (md == null) + return null; + } + + ISignature result = new RSAPKCS1V1_5Signature(md); + return result; + } +} -- cgit v1.2.3