Imported GNU Classpath 0.90
Imported GNU Classpath 0.90
* scripts/makemake.tcl: Set gnu/java/awt/peer/swing to ignore.
* gnu/classpath/jdwp/VMFrame.java (SIZE): New constant.
* java/lang/VMCompiler.java: Use gnu.java.security.hash.MD5.
* java/lang/Math.java: New override file.
* java/lang/Character.java: Merged from Classpath.
(start, end): Now 'int's.
(canonicalName): New field.
(CANONICAL_NAME, NO_SPACES_NAME, CONSTANT_NAME): New constants.
(UnicodeBlock): Added argument.
(of): New overload.
(forName): New method.
Updated unicode blocks.
(sets): Updated.
* sources.am: Regenerated.
* Makefile.in: Likewise.
From-SVN: r111942
This commit is contained in:
@@ -0,0 +1,261 @@
|
||||
/* 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;
|
||||
|
||||
/**
|
||||
* <p>A base abstract class to facilitate implementations of concrete
|
||||
* Signatures.</p>
|
||||
*/
|
||||
public abstract class BaseSignature implements ISignature
|
||||
{
|
||||
|
||||
// Constants and variables
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/** 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;
|
||||
|
||||
// Constructor(s)
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 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
|
||||
* <code>null</code>.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
// Class methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// Instance methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// gnu.crypto.sig.ISignature interface implementation ----------------------
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// abstract methods to be implemented by concrete subclasses ---------------
|
||||
|
||||
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;
|
||||
|
||||
// Other instance methods --------------------------------------------------
|
||||
|
||||
/** Initialises the internal fields of this instance. */
|
||||
protected void init()
|
||||
{
|
||||
md.reset();
|
||||
rnd = null;
|
||||
irnd = null;
|
||||
publicKey = null;
|
||||
privateKey = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Fills the designated byte array with random data.</p>
|
||||
*
|
||||
* @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(): "
|
||||
+ String.valueOf(x));
|
||||
}
|
||||
catch (LimitReachedException x)
|
||||
{
|
||||
throw new RuntimeException("nextRandomBytes(): "
|
||||
+ String.valueOf(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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
/* 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;
|
||||
|
||||
/**
|
||||
* <p>The visible methods of every signature-with-appendix scheme.</p>
|
||||
*
|
||||
* <p>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 <i>digital signature schemes with
|
||||
* appendix</i>. ... They rely on cryptographic hash functions rather than
|
||||
* customised redundancy functions, and are less prone to existential forgery
|
||||
* attacks."</p>
|
||||
*
|
||||
* <p>References:</p>
|
||||
* <ol>
|
||||
* <li><a href="http://www.cacr.math.uwaterloo.ca/hac/">Handbook of Applied
|
||||
* Cryptography</a>, Alfred J. Menezes, Paul C. van Oorschot and Scott A.
|
||||
* Vanstone. Section 11.2.2 Digital signature schemes with appendix.</li>
|
||||
* </ol>
|
||||
*
|
||||
* @version $Revision: 1.1 $
|
||||
*/
|
||||
public interface ISignature extends Cloneable
|
||||
{
|
||||
|
||||
// Constants
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/** 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.crypto.prng.IRandom} instance to
|
||||
* use. The default is to use a classloader singleton from
|
||||
* {@link gnu.crypto.util.PRNG}.
|
||||
*/
|
||||
public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.sig.prng";
|
||||
|
||||
// Methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* <p>Returns the canonical name of this signature scheme.</p>
|
||||
*
|
||||
* @return the canonical name of this instance.
|
||||
*/
|
||||
String name();
|
||||
|
||||
/**
|
||||
* <p>Initialises this instance for signature verification.</p>
|
||||
*
|
||||
* @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;
|
||||
|
||||
/**
|
||||
* <p>Initialises this instance for signature generation.</p>
|
||||
*
|
||||
* @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;
|
||||
|
||||
/**
|
||||
* <p>Digests one byte of a message for signing or verification purposes.</p>
|
||||
*
|
||||
* @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;
|
||||
|
||||
/**
|
||||
* <p>Digests a sequence of bytes from a message for signing or verification
|
||||
* purposes.</p>
|
||||
*
|
||||
* @param buffer the byte sequence to consider.
|
||||
* @param offset the byte poisition in <code>buffer</code> of the first byte
|
||||
* to consider.
|
||||
* @param length the number of bytes in <code>buffer</code> starting from the
|
||||
* byte at index <code>offset</code> to digest.
|
||||
* @throws IllegalStateException if this instance was not setup for
|
||||
* signature generation/verification.
|
||||
*/
|
||||
void update(byte[] buffer, int offset, int length)
|
||||
throws IllegalStateException;
|
||||
|
||||
/**
|
||||
* <p>Terminates a signature generation phase by digesting and processing the
|
||||
* context of the underlying message digest algorithm instance.</p>
|
||||
*
|
||||
* @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;
|
||||
|
||||
/**
|
||||
* <p>Terminates a signature verification phase by digesting and processing
|
||||
* the context of the underlying message digest algorithm instance.</p>
|
||||
*
|
||||
* @param signature a native signature object previously generated by an
|
||||
* invocation of the <code>sign()</code> method.
|
||||
* @return <code>true</code> 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;
|
||||
|
||||
/**
|
||||
* <p>Returns a clone copy of this instance.</p>
|
||||
*
|
||||
* @return a clone copy of this instance.
|
||||
*/
|
||||
Object clone();
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/* 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;
|
||||
|
||||
/**
|
||||
* <p>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.</p>
|
||||
*
|
||||
* @version $Revision: 1.1 $
|
||||
*/
|
||||
public interface ISignatureCodec
|
||||
{
|
||||
|
||||
// Constants
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/** Constant identifying the <i>Raw</i> encoding format. */
|
||||
int RAW_FORMAT = Registry.RAW_ENCODING_ID;
|
||||
|
||||
// Method(s)
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
int getFormatID();
|
||||
|
||||
byte[] encodeSignature(Object signature);
|
||||
|
||||
Object decodeSignature(byte[] input);
|
||||
}
|
||||
@@ -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 <i>Factory</i> 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
|
||||
* <code>/</code> and the canonical name of the encoding format.
|
||||
* <p>
|
||||
* 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 <code>null</code> 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 <code>null</code> 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 <code>null</code> 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
|
||||
* <code>null</code> 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
|
||||
* <code>null</code> 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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/* 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;
|
||||
|
||||
// Constructor(s)
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/** Trivial constructor to enforce Singleton pattern. */
|
||||
private SignatureFactory()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
// Class methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 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 <code>null</code> 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 <i>Factory</i>.
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,347 @@
|
||||
/* 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;
|
||||
|
||||
/**
|
||||
* <p>The DSS (Digital Signature Standard) algorithm makes use of the following
|
||||
* parameters:</p>
|
||||
*
|
||||
* <ol>
|
||||
* <li>p: A prime modulus, where <code>2<sup>L-1</sup> < p < 2<sup>L</sup>
|
||||
* </code> for <code>512 <= L <= 1024</code> and <code>L</code> a
|
||||
* multiple of <code>64</code>.</li>
|
||||
* <li>q: A prime divisor of <code>p - 1</code>, where <code>2<sup>159</sup>
|
||||
* < q < 2<sup>160</sup></code>.</li>
|
||||
* <li>g: Where <code>g = h<sup>(p-1)</sup>/q mod p</code>, where
|
||||
* <code>h</code> is any integer with <code>1 < h < p - 1</code> such
|
||||
* that <code>h<sup> (p-1)</sup>/q mod p > 1</code> (<code>g</code> has order
|
||||
* <code>q mod p</code>).</li>
|
||||
* <li>x: A randomly or pseudorandomly generated integer with <code>0 < x
|
||||
* < q</code>.</li>
|
||||
* <li>y: <code>y = g<sup>x</sup> mod p</code>.</li>
|
||||
* <li>k: A randomly or pseudorandomly generated integer with <code>0 < k
|
||||
* < q</code>.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p>The integers <code>p</code>, <code>q</code>, and <code>g</code> can be
|
||||
* public and can be common to a group of users. A user's private and public
|
||||
* keys are <code>x</code> and <code>y</code>, respectively. They are normally
|
||||
* fixed for a period of time. Parameters <code>x</code> and <code>k</code> are
|
||||
* used for signature generation only, and must be kept secret. Parameter
|
||||
* <code>k</code> must be regenerated for each signature.</p>
|
||||
*
|
||||
* <p>The signature of a message <code>M</code> is the pair of numbers <code>r</code>
|
||||
* and <code>s</code> computed according to the equations below:</p>
|
||||
*
|
||||
* <ul>
|
||||
* <li><code>r = (g<sup>k</sup> mod p) mod q</code> and</li>
|
||||
* <li><code>s = (k<sup>-1</sup>(SHA(M) + xr)) mod q</code>.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>In the above, <code>k<sup>-1</sup></code> is the multiplicative inverse of
|
||||
* <code>k</code>, <code>mod q</code>; i.e., <code>(k<sup>-1</sup> k) mod q = 1
|
||||
* </code> and <code>0 < k-1 < q</code>. The value of <code>SHA(M)</code>
|
||||
* is a 160-bit string output by the Secure Hash Algorithm specified in FIPS 180.
|
||||
* For use in computing <code>s</code>, this string must be converted to an
|
||||
* integer.</p>
|
||||
*
|
||||
* <p>As an option, one may wish to check if <code>r == 0</code> or <code>s == 0
|
||||
* </code>. If either <code>r == 0</code> or <code>s == 0</code>, a new value
|
||||
* of <code>k</code> should be generated and the signature should be
|
||||
* recalculated (it is extremely unlikely that <code>r == 0</code> or <code>s ==
|
||||
* 0</code> if signatures are generated properly).</p>
|
||||
*
|
||||
* <p>The signature is transmitted along with the message to the verifier.</p>
|
||||
*
|
||||
* <p>References:</p>
|
||||
* <ol>
|
||||
* <li><a href="http://www.itl.nist.gov/fipspubs/fip186.htm">Digital
|
||||
* Signature Standard (DSS)</a>, Federal Information Processing Standards
|
||||
* Publication 186. National Institute of Standards and Technology.</li>
|
||||
* </ol>
|
||||
*
|
||||
* @version $Revision: 1.1 $
|
||||
*/
|
||||
public class DSSSignature extends BaseSignature
|
||||
{
|
||||
|
||||
// Constants and variables
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// Constructor(s)
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/** 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();
|
||||
}
|
||||
|
||||
// Class methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// Implementation of abstract methods in superclass
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
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
|
||||
{
|
||||
// BigInteger p = ((DSAPrivateKey) privateKey).getParams().getP();
|
||||
// BigInteger q = ((DSAPrivateKey) privateKey).getParams().getQ();
|
||||
// BigInteger g = ((DSAPrivateKey) privateKey).getParams().getG();
|
||||
// BigInteger x = ((DSAPrivateKey) privateKey).getX();
|
||||
// BigInteger m = new BigInteger(1, md.digest());
|
||||
// BigInteger k, r, s;
|
||||
//
|
||||
// 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;
|
||||
// }
|
||||
final BigInteger[] rs = computeRS(md.digest());
|
||||
|
||||
// return encodeSignature(r, s);
|
||||
return encodeSignature(rs[0], rs[1]);
|
||||
}
|
||||
|
||||
protected boolean verifySignature(Object sig) throws IllegalStateException
|
||||
{
|
||||
final BigInteger[] rs = decodeSignature(sig);
|
||||
// BigInteger r = rs[0];
|
||||
// BigInteger s = rs[1];
|
||||
//
|
||||
// BigInteger g = ((DSAPublicKey) publicKey).getParams().getG();
|
||||
// BigInteger p = ((DSAPublicKey) publicKey).getParams().getP();
|
||||
// BigInteger q = ((DSAPublicKey) publicKey).getParams().getQ();
|
||||
// BigInteger y = ((DSAPublicKey) publicKey).getY();
|
||||
// BigInteger w = s.modInverse(q);
|
||||
//
|
||||
// byte bytes[] = md.digest();
|
||||
// BigInteger u1 = w.multiply(new BigInteger(1, bytes)).mod(q);
|
||||
// BigInteger u2 = r.multiply(w).mod(q);
|
||||
//
|
||||
// BigInteger v = g.modPow(u1, p).multiply(y.modPow(u2, p)).mod(p).mod(q);
|
||||
// return v.equals(r);
|
||||
return checkRS(rs, md.digest());
|
||||
}
|
||||
|
||||
// Other instance methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the output of a signature generation phase.<p>
|
||||
*
|
||||
* @return an object encapsulating the DSS signature pair <code>r</code> and
|
||||
* <code>s</code>.
|
||||
*/
|
||||
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}.<p>
|
||||
*
|
||||
* @return the DSS signature pair <code>r</code> and <code>s</code>.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
/* 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;
|
||||
|
||||
/**
|
||||
* <p>An object that implements the {@link ISignatureCodec} operations for the
|
||||
* <i>Raw</i> format to use with DSS signatures.</p>
|
||||
*
|
||||
* @version $Revision: 1.1 $
|
||||
*/
|
||||
public class DSSSignatureRawCodec implements ISignatureCodec
|
||||
{
|
||||
|
||||
// Constants and variables
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// Constructor(s)
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// implicit 0-arguments constructor
|
||||
|
||||
// Class methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// Instance methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// gnu.crypto.sig.ISignatureCodec interface implementation -----------------
|
||||
|
||||
public int getFormatID()
|
||||
{
|
||||
return RAW_FORMAT;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns the encoded form of the designated DSS (Digital Signature
|
||||
* Standard) signature object according to the <i>Raw</i> format supported by
|
||||
* this library.</p>
|
||||
*
|
||||
* <p>The <i>Raw</i> format for a DSA signature, in this implementation, is a
|
||||
* byte sequence consisting of the following:</p>
|
||||
*
|
||||
* <ol>
|
||||
* <li>4-byte magic consisting of the value of the literal
|
||||
* {@link Registry#MAGIC_RAW_DSS_SIGNATURE},</li>
|
||||
* <li>1-byte version consisting of the constant: 0x01,</li>
|
||||
* <li>4-byte count of following bytes representing the DSS parameter
|
||||
* <code>r</code> in internet order,</li>
|
||||
* <li>n-bytes representation of a {@link BigInteger} obtained by invoking
|
||||
* the <code>toByteArray()</code> method on the DSS parameter <code>r</code>,</li>
|
||||
* <li>4-byte count of following bytes representing the DSS parameter
|
||||
* <code>s</code>,</li>
|
||||
* <li>n-bytes representation of a {@link BigInteger} obtained by invoking
|
||||
* the <code>toByteArray()</code> method on the DSS parameter <code>s</code>.</li>
|
||||
* </ol>
|
||||
*
|
||||
* @param signature the signature to encode, consisting of the two DSS
|
||||
* parameters <code>r</code> and <code>s</code> as a {@link java.math.BigInteger}
|
||||
* array.
|
||||
* @return the <i>Raw</i> 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("key");
|
||||
}
|
||||
|
||||
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 };
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
* <p>
|
||||
* Digital signatures when transmitted in an X.509 certificates are encoded
|
||||
* in DER (Distinguished Encoding Rules) as a BIT STRING; i.e.
|
||||
*
|
||||
* <pre>
|
||||
* Certificate ::= SEQUENCE {
|
||||
* tbsCertificate TBSCertificate,
|
||||
* signatureAlgorithm AlgorithmIdentifier,
|
||||
* signature BIT STRING
|
||||
* }
|
||||
* </pre>
|
||||
* <p>
|
||||
* The output of the encoder, and the input of the decoder, of this codec are
|
||||
* then the <i>raw</i> bytes of such a BIT STRING; i.e. not the DER-encoded
|
||||
* form itself.
|
||||
* <p>
|
||||
* RFC-2459 states that, for the Digital Signature Standard (DSS), which
|
||||
* generates two MPIs, commonly called <code>r</code> and <code>s</code>, as the
|
||||
* result of digitally signing a message, these two numbers will be transferred
|
||||
* as the following ASN.1 structure:
|
||||
*
|
||||
* <pre>
|
||||
* Dss-Sig-Value ::= SEQUENCE {
|
||||
* r INTEGER,
|
||||
* s INTEGER
|
||||
* }
|
||||
* </pre>
|
||||
* <p>
|
||||
* Client code that needs to build a DER BIT STRING <b>MUST</b> construct such
|
||||
* an ASN.1 value. The following is an example of how to do this:
|
||||
* <p>
|
||||
* <pre>
|
||||
* ...
|
||||
* 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));
|
||||
* ...
|
||||
* </pre>
|
||||
*/
|
||||
public class DSSSignatureX509Codec
|
||||
implements ISignatureCodec
|
||||
{
|
||||
// implicit 0-arguments constructor
|
||||
|
||||
public int getFormatID()
|
||||
{
|
||||
return Registry.X509_ENCODING_ID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a DSS Signature output as the <i>signature</i> 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
|
||||
* <code>r</code> and <code>s</code>.
|
||||
* @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 <i>signature</i> 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, <code>r</code> and <code>s</code> in this
|
||||
* order, decoded from the designated <code>input</code>.
|
||||
* @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 };
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,306 @@
|
||||
/* 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;
|
||||
|
||||
/**
|
||||
* <p>An implementation of the EME-PKCS1-V1.5 encoding and decoding methods.</p>
|
||||
*
|
||||
* <p>EME-PKCS1-V1.5 is parameterised by the entity <code>k</code> which is the
|
||||
* byte count of an RSA public shared modulus.</p>
|
||||
*
|
||||
* <p>References:</p>
|
||||
* <ol>
|
||||
* <li><a href="http://www.ietf.org/rfc/rfc3447.txt">Public-Key Cryptography
|
||||
* Standards (PKCS) #1:</a><br>
|
||||
* RSA Cryptography Specifications Version 2.1.<br>
|
||||
* Jakob Jonsson and Burt Kaliski.</li>
|
||||
* </ol>
|
||||
*/
|
||||
public class EME_PKCS1_V1_5
|
||||
{
|
||||
|
||||
// Constants and variables
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
private int k;
|
||||
|
||||
private ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
|
||||
/** Our default source of randomness. */
|
||||
private PRNG prng = PRNG.getInstance();
|
||||
|
||||
// Constructor(s)
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
private EME_PKCS1_V1_5(final int k)
|
||||
{
|
||||
super();
|
||||
|
||||
this.k = k;
|
||||
}
|
||||
|
||||
// Class methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// Instance methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* <p>Generates an octet string <code>PS</code> of length <code>k - mLen -
|
||||
* 3</code> consisting of pseudo-randomly generated nonzero octets. The
|
||||
* length of <code>PS</code> will be at least eight octets.</p>
|
||||
*
|
||||
* <p>The method then concatenates <code>PS</code>, the message <code>M</code>,
|
||||
* and other padding to form an encoded message <code>EM</code> of length
|
||||
* <code>k</code> octets as:</p>
|
||||
*
|
||||
* <pre>
|
||||
* EM = 0x00 || 0x02 || PS || 0x00 || M.
|
||||
* </pre>
|
||||
*
|
||||
* <p>This method uses a default PRNG to obtain the padding bytes.</p>
|
||||
*
|
||||
* @param M the message to encode.
|
||||
* @return the encoded message <code>EM</code>.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>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.</p>
|
||||
*
|
||||
* @param M the message to encode.
|
||||
* @param irnd the {@link IRandom} instance to use as a source of randomness.
|
||||
* @return the encoded message <code>EM</code>.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>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 <code>EM</code>.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Separate the encoded message <code>EM</code> into an octet string
|
||||
* <code>PS</code> consisting of nonzero octets and a message <code>M</code>
|
||||
* as:</p>
|
||||
*
|
||||
* <pre>
|
||||
* EM = 0x00 || 0x02 || PS || 0x00 || M.
|
||||
* </pre>
|
||||
*
|
||||
* <p>If the first octet of <code>EM</code> does not have hexadecimal value
|
||||
* <code>0x00</code>, if the second octet of <code>EM</code> does not have
|
||||
* hexadecimal value <code>0x02</code>, if there is no octet with hexadecimal
|
||||
* value <code>0x00</code> to separate <code>PS</code> from <code>M</code>,
|
||||
* or if the length of <code>PS</code> is less than <code>8</code> octets,
|
||||
* output "decryption error" and stop.</p>
|
||||
|
||||
* @param EM the designated encoded message.
|
||||
* @return the decoded message <code>M</code> framed in the designated
|
||||
* <code>EM</code> value.
|
||||
* @throws IllegalArgumentException if the length of the designated entity
|
||||
* <code>EM</code> is different than <code>k</code> (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;
|
||||
}
|
||||
|
||||
// helper methods ----------------------------------------------------------
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,299 @@
|
||||
/* 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;
|
||||
|
||||
/**
|
||||
* <p>An implementation of the EMSA-PKCS1-V1.5 encoding scheme.</p>
|
||||
*
|
||||
* <p>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.</p>
|
||||
*
|
||||
* <p>References:</p>
|
||||
* <ol>
|
||||
* <li><a href="http://www.ietf.org/rfc/rfc3447.txt">Public-Key Cryptography
|
||||
* Standards (PKCS) #1:</a><br>
|
||||
* RSA Cryptography Specifications Version 2.1.<br>
|
||||
* Jakob Jonsson and Burt Kaliski.</li>
|
||||
* </ol>
|
||||
*
|
||||
* @version $Revision: 1.2 $
|
||||
*/
|
||||
public class EMSA_PKCS1_V1_5 implements Cloneable
|
||||
{
|
||||
|
||||
// Constants and variables
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/* 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;
|
||||
|
||||
// Constructor(s)
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* <p>Trivial private constructor to enforce use through Factory method.</p>
|
||||
*
|
||||
* @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
|
||||
}
|
||||
}
|
||||
|
||||
// Class methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* <p>Returns an instance of this object given a designated name of a hash
|
||||
* function.</p>
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
|
||||
// Instance methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// Cloneable interface implementation --------------------------------------
|
||||
|
||||
public Object clone()
|
||||
{
|
||||
return getInstance(hash.name());
|
||||
}
|
||||
|
||||
// own methods -------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* <p>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).</p>
|
||||
*
|
||||
* @param mHash the byte sequence resulting from applying the message digest
|
||||
* algorithm Hash to the message <i>M</i>.
|
||||
* @param emLen intended length in octets of the encoded message, at least
|
||||
* <code>tLen + 11</code>, where <code>tLen</code> is the octet length of the
|
||||
* DER encoding <code>T</code> of a certain value computed during the
|
||||
* encoding operation.
|
||||
* @return encoded message, an octet string of length <code>emLen</code>.
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,432 @@
|
||||
/* 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.hash.HashFactory;
|
||||
import gnu.java.security.hash.IMessageDigest;
|
||||
import gnu.java.security.util.Util;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* <p>An implementation of the EMSA-PSS encoding/decoding scheme.</p>
|
||||
*
|
||||
* <p>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.</p>
|
||||
*
|
||||
* <p>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.</p>
|
||||
*
|
||||
* <p>References:</p>
|
||||
* <ol>
|
||||
* <li><a href="http://www.cosic.esat.kuleuven.ac.be/nessie/workshop/submissions/rsa-pss.zip">
|
||||
* RSA-PSS Signature Scheme with Appendix, part B.</a><br>
|
||||
* Primitive specification and supporting documentation.<br>
|
||||
* Jakob Jonsson and Burt Kaliski.</li>
|
||||
* </ol>
|
||||
*
|
||||
* @version $Revision: 1.1 $
|
||||
*/
|
||||
public class EMSA_PSS implements Cloneable
|
||||
{
|
||||
|
||||
// Debugging methods and variables
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
private static final String NAME = "emsa-pss";
|
||||
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private static final int debuglevel = 5;
|
||||
|
||||
private static final PrintWriter err = new PrintWriter(System.out, true);
|
||||
|
||||
private static void debug(String s)
|
||||
{
|
||||
err.println(">>> " + NAME + ": " + s);
|
||||
}
|
||||
|
||||
// Constants and variables
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/** The underlying hash function to use with this instance. */
|
||||
private IMessageDigest hash;
|
||||
|
||||
/** The output size of the hash function in octets. */
|
||||
private int hLen;
|
||||
|
||||
// Constructor(s)
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* <p>Trivial private constructor to enforce use through Factory method.</p>
|
||||
*
|
||||
* @param hash the message digest instance to use with this scheme instance.
|
||||
*/
|
||||
private EMSA_PSS(IMessageDigest hash)
|
||||
{
|
||||
super();
|
||||
|
||||
this.hash = hash;
|
||||
hLen = hash.hashSize();
|
||||
}
|
||||
|
||||
// Class methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* <p>Returns an instance of this object given a designated name of a hash
|
||||
* function.</p>
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
|
||||
// Instance methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// Cloneable interface implementation --------------------------------------
|
||||
|
||||
public Object clone()
|
||||
{
|
||||
return getInstance(hash.name());
|
||||
}
|
||||
|
||||
// own methods -------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* <p>The encoding operation EMSA-PSS-Encode computes the hash of a message
|
||||
* <code>M</code> using a hash function and maps the result to an encoded
|
||||
* message <code>EM</code> of a specified length using a mask generation
|
||||
* function.</p>
|
||||
*
|
||||
* @param mHash the byte sequence resulting from applying the message digest
|
||||
* algorithm Hash to the message <i>M</i>.
|
||||
* @param emBits the maximal bit length of the integer OS2IP(EM), at least
|
||||
* <code>8.hLen + 8.sLen + 9</code>.
|
||||
* @param salt the salt to use when encoding the output.
|
||||
* @return the encoded message <code>EM</code>, an octet string of length
|
||||
* <code>emLen = CEILING(emBits / 8)</code>.
|
||||
* @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 (DEBUG && debuglevel > 8)
|
||||
{
|
||||
debug("dbMask (encode): " + Util.toString(dbMask));
|
||||
debug("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;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>The decoding operation EMSA-PSS-Decode recovers the message hash from
|
||||
* an encoded message <code>EM</code> and compares it to the hash of
|
||||
* <code>M</code>.</p>
|
||||
*
|
||||
* @param mHash the byte sequence resulting from applying the message digest
|
||||
* algorithm Hash to the message <i>M</i>.
|
||||
* @param EM the <i>encoded message</i>, an octet string of length
|
||||
* <code>emLen = CEILING(emBits/8).
|
||||
* @param emBits the maximal bit length of the integer OS2IP(EM), at least
|
||||
* <code>8.hLen + 8.sLen + 9</code>.
|
||||
* @param sLen the length, in octets, of the expected salt.
|
||||
* @return <code>true</code> if the result of the verification was
|
||||
* <i>consistent</i> with the expected reseult; and <code>false</code> if the
|
||||
* result was <i>inconsistent</i>.
|
||||
* @exception IllegalArgumentException if an exception occurs.
|
||||
*/
|
||||
public boolean decode(byte[] mHash, byte[] EM, int emBits, int sLen)
|
||||
{
|
||||
if (DEBUG && debuglevel > 8)
|
||||
{
|
||||
debug("mHash: " + Util.toString(mHash));
|
||||
debug("EM: " + Util.toString(EM));
|
||||
debug("emBits: " + String.valueOf(emBits));
|
||||
debug("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 (DEBUG && debuglevel > 8)
|
||||
{
|
||||
debug("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 (DEBUG && debuglevel > 8)
|
||||
{
|
||||
debug("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 (DEBUG && debuglevel > 8)
|
||||
{
|
||||
debug("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 (DEBUG && debuglevel > 8)
|
||||
{
|
||||
debug("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 (DEBUG && debuglevel > 8)
|
||||
{
|
||||
debug("dbMask (decode): " + Util.toString(dbMask));
|
||||
debug("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 (DEBUG && debuglevel > 8)
|
||||
{
|
||||
debug("DB[" + String.valueOf(i) + "] != 0x00");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (DB[i] != 0x01)
|
||||
{ // i == emLen -hLen -sLen -2
|
||||
if (DEBUG && debuglevel > 8)
|
||||
{
|
||||
debug("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);
|
||||
}
|
||||
|
||||
// helper methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* <p>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.</p>
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,356 @@
|
||||
/* 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;
|
||||
|
||||
/**
|
||||
* <p>Utility methods related to the RSA algorithm.</p>
|
||||
*
|
||||
* <p>References:</p>
|
||||
* <ol>
|
||||
* <li><a href="http://www.cosic.esat.kuleuven.ac.be/nessie/workshop/submissions/rsa-pss.zip">
|
||||
* RSA-PSS Signature Scheme with Appendix, part B.</a><br>
|
||||
* Primitive specification and supporting documentation.<br>
|
||||
* Jakob Jonsson and Burt Kaliski.</li>
|
||||
*
|
||||
* <li><a href="http://www.ietf.org/rfc/rfc3447.txt">Public-Key Cryptography
|
||||
* Standards (PKCS) #1:</a><br>
|
||||
* RSA Cryptography Specifications Version 2.1.<br>
|
||||
* Jakob Jonsson and Burt Kaliski.</li>
|
||||
*
|
||||
* <li><a href="http://crypto.stanford.edu/~dabo/abstracts/ssl-timing.html">
|
||||
* Remote timing attacks are practical</a><br>
|
||||
* D. Boneh and D. Brumley.</li>
|
||||
* </ol>
|
||||
*/
|
||||
public class RSA
|
||||
{
|
||||
|
||||
// Constants and variables
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
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();
|
||||
|
||||
// Constructor(s)
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/** Trivial private constructor to enforce Singleton pattern. */
|
||||
private RSA()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
// Class methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// Signature and verification methods --------------------------------------
|
||||
|
||||
/**
|
||||
* <p>An implementation of the <b>RSASP</b> method: Assuming that the
|
||||
* designated RSA private key is a valid one, this method computes a
|
||||
* <i>signature representative</i> for a designated <i>message
|
||||
* representative</i> signed by the holder of the designated RSA private
|
||||
* key.<p>
|
||||
*
|
||||
* @param K the RSA private key.
|
||||
* @param m the <i>message representative</i>: an integer between
|
||||
* <code>0</code> and <code>n - 1</code>, where <code>n</code> is the RSA
|
||||
* <i>modulus</i>.
|
||||
* @return the <i>signature representative</i>, an integer between
|
||||
* <code>0</code> and <code>n - 1</code>, where <code>n</code> is the RSA
|
||||
* <i>modulus</i>.
|
||||
* @throws ClassCastException if <code>K</code> is not an RSA one.
|
||||
* @throws IllegalArgumentException if <code>m</code> (the <i>message
|
||||
* representative</i>) 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");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>An implementation of the <b>RSAVP</b> method: Assuming that the
|
||||
* designated RSA public key is a valid one, this method computes a
|
||||
* <i>message representative</i> for the designated <i>signature
|
||||
* representative</i> generated by an RSA private key, for a message
|
||||
* intended for the holder of the designated RSA public key.</p>
|
||||
*
|
||||
* @param K the RSA public key.
|
||||
* @param s the <i>signature representative</i>, an integer between
|
||||
* <code>0</code> and <code>n - 1</code>, where <code>n</code> is the RSA
|
||||
* <i>modulus</i>.
|
||||
* @return a <i>message representative</i>: an integer between <code>0</code>
|
||||
* and <code>n - 1</code>, where <code>n</code> is the RSA <i>modulus</i>.
|
||||
* @throws ClassCastException if <code>K</code> is not an RSA one.
|
||||
* @throws IllegalArgumentException if <code>s</code> (the <i>signature
|
||||
* representative</i>) 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");
|
||||
}
|
||||
}
|
||||
|
||||
// Encryption and decryption methods ---------------------------------------
|
||||
|
||||
/**
|
||||
* <p>An implementation of the <code>RSAEP</code> algorithm.</p>
|
||||
*
|
||||
* @param K the recipient's RSA public key.
|
||||
* @param m the message representative as an MPI.
|
||||
* @return the resulting MPI --an MPI between <code>0</code> and
|
||||
* <code>n - 1</code> (<code>n</code> being the public shared modulus)-- that
|
||||
* will eventually be padded with an appropriate framing/padding scheme.
|
||||
* @throws ClassCastException if <code>K</code> is not an RSA one.
|
||||
* @throws IllegalArgumentException if <code>m</code>, the message
|
||||
* representative is not between <code>0</code> and <code>n - 1</code>
|
||||
* (<code>n</code> 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");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>An implementation of the <code>RSADP</code> algorithm.</p>
|
||||
*
|
||||
* @param K the recipient's RSA private key.
|
||||
* @param c the ciphertext representative as an MPI.
|
||||
* @return the message representative, an MPI between <code>0</code> and
|
||||
* <code>n - 1</code> (<code>n</code> being the shared public modulus).
|
||||
* @throws ClassCastException if <code>K</code> is not an RSA one.
|
||||
* @throws IllegalArgumentException if <code>c</code>, the ciphertext
|
||||
* representative is not between <code>0</code> and <code>n - 1</code>
|
||||
* (<code>n</code> 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");
|
||||
}
|
||||
}
|
||||
|
||||
// Conversion methods ------------------------------------------------------
|
||||
|
||||
/**
|
||||
* <p>Converts a <i>multi-precision integer</i> (MPI) <code>s</code> into an
|
||||
* octet sequence of length <code>k</code>.</p>
|
||||
*
|
||||
* @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 <code>s</code> is greater than <code>k</code>.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
// helper methods ----------------------------------------------------------
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns a random MPI with a random bit-length of the form <code>8b</code>,
|
||||
* where <code>b</code> is in the range <code>[32..64]</code>.</p>
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
/* 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;
|
||||
|
||||
/**
|
||||
* <p>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.</p>
|
||||
*
|
||||
* <p>References:</p>
|
||||
* <ol>
|
||||
* <li><a href="http://www.cosic.esat.kuleuven.ac.be/nessie/workshop/submissions/rsa-pss.zip">
|
||||
* RSA-PSS Signature Scheme with Appendix, part B.</a><br>
|
||||
* Primitive specification and supporting documentation.<br>
|
||||
* Jakob Jonsson and Burt Kaliski.</li>
|
||||
*
|
||||
* <li><a href="http://www.ietf.org/rfc/rfc3447.txt">Public-Key Cryptography
|
||||
* Standards (PKCS) #1:</a><br>
|
||||
* RSA Cryptography Specifications Version 2.1.<br>
|
||||
* Jakob Jonsson and Burt Kaliski.</li>
|
||||
* </ol>
|
||||
*
|
||||
* @version $Revision: 1.2 $
|
||||
*/
|
||||
public class RSAPKCS1V1_5Signature extends BaseSignature
|
||||
{
|
||||
|
||||
// Constants and variables
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/** The underlying EMSA-PKCS1-v1.5 instance for this object. */
|
||||
private EMSA_PKCS1_V1_5 pkcs1;
|
||||
|
||||
// Constructor(s)
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Default 0-arguments constructor. Uses SHA-1 as the default hash.
|
||||
*/
|
||||
public RSAPKCS1V1_5Signature()
|
||||
{
|
||||
this(Registry.SHA160_HASH);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Constructs an instance of this object using the designated message
|
||||
* digest algorithm as its underlying hash function.</p>
|
||||
*
|
||||
* @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();
|
||||
}
|
||||
|
||||
// Class methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// Instance methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// Implementation of abstract methods in superclass ------------------------
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
* <i>Raw</i> 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 <i>Raw</i> format supported by this library.
|
||||
* <p>
|
||||
* The <i>Raw</i> format for such a signature, in this implementation, is a
|
||||
* byte sequence consisting of the following:
|
||||
* <p>
|
||||
* <ol>
|
||||
* <li>4-byte magic consisting of the value of the literal
|
||||
* {@link Registry#MAGIC_RAW_RSA_PKCS1V1_5_SIGNATURE},
|
||||
* <li>
|
||||
* <li>1-byte version consisting of the constant: 0x01,</li>
|
||||
* <li>4-byte count of following bytes representing the RSA-PKCS#1 (v1.5)
|
||||
* signature bytes in internet order,</li>
|
||||
* <li>the RSA-PKCS#1 (v1.5) signature bytes in internet order.</li>
|
||||
* </ol>
|
||||
*
|
||||
* @param signature the signature to encode, consisting of the output of the
|
||||
* <code>sign()</code> method of a {@link RSAPKCS1V1_5Signature}
|
||||
* instance --a byte array.
|
||||
* @return the <i>Raw</i> 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 <i>magic</i> characters, or if the <i>version</i>
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
* <p>
|
||||
* Digital signatures when transmitted in an X.509 certificates are encoded
|
||||
* in DER (Distinguished Encoding Rules) as a BIT STRING; i.e.
|
||||
*
|
||||
* <pre>
|
||||
* Certificate ::= SEQUENCE {
|
||||
* tbsCertificate TBSCertificate,
|
||||
* signatureAlgorithm AlgorithmIdentifier,
|
||||
* signature BIT STRING
|
||||
* }
|
||||
* </pre>
|
||||
* <p>
|
||||
* The output of the encoder, and the input of the decoder, of this codec are
|
||||
* then the <i>raw</i> bytes of such a BIT STRING; i.e. not the DER-encoded
|
||||
* form itself.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* Client code that needs to build a DER BIT STRING <b>MUST</b> construct such
|
||||
* an ASN.1 value. The following is an example of how to do this:
|
||||
* <p>
|
||||
* <pre>
|
||||
* ...
|
||||
* 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));
|
||||
* ...
|
||||
* </pre>
|
||||
*/
|
||||
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 <i>signature</i> 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 <i>signature</i> 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 <code>input</code> array is null.
|
||||
*/
|
||||
public Object decodeSignature(byte[] input)
|
||||
{
|
||||
if (input == null)
|
||||
throw new InvalidParameterException("Input bytes MUST NOT be null");
|
||||
|
||||
return input;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,348 @@
|
||||
/* 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.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.io.PrintWriter;
|
||||
import java.math.BigInteger;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
|
||||
/**
|
||||
* <p>The RSA-PSS signature scheme is a public-key encryption scheme combining
|
||||
* the RSA algorithm with the Probabilistic Signature Scheme (PSS) encoding
|
||||
* method.</p>
|
||||
*
|
||||
* <p>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.</p>
|
||||
*
|
||||
* <p>References:</pr>
|
||||
* <ol>
|
||||
* <li><a href="http://www.cosic.esat.kuleuven.ac.be/nessie/workshop/submissions/rsa-pss.zip">
|
||||
* RSA-PSS Signature Scheme with Appendix, part B.</a><br>
|
||||
* Primitive specification and supporting documentation.<br>
|
||||
* Jakob Jonsson and Burt Kaliski.</li>
|
||||
* </ol>
|
||||
*
|
||||
* @version $Revision: 1.2 $
|
||||
*/
|
||||
public class RSAPSSSignature extends BaseSignature
|
||||
{
|
||||
|
||||
// Debugging methods and variables
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
private static final String NAME = "rsa-pss";
|
||||
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private static final int debuglevel = 1;
|
||||
|
||||
private static final PrintWriter err = new PrintWriter(System.out, true);
|
||||
|
||||
private static void debug(String s)
|
||||
{
|
||||
err.println(">>> " + NAME + ": " + s);
|
||||
}
|
||||
|
||||
// Constants and variables
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/** 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;
|
||||
|
||||
// Constructor(s)
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Default 0-arguments constructor. Uses SHA-1 as the default hash and a
|
||||
* 0-octet <i>salt</i>.
|
||||
*/
|
||||
public RSAPSSSignature()
|
||||
{
|
||||
this(Registry.SHA160_HASH, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Constructs an instance of this object using the designated message
|
||||
* digest algorithm as its underlying hash function, and having 0-octet
|
||||
* <i>salt</i>.</p>
|
||||
*
|
||||
* @param mdName the canonical name of the underlying hash function.
|
||||
*/
|
||||
public RSAPSSSignature(String mdName)
|
||||
{
|
||||
this(mdName, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Constructs an instance of this object using the designated message
|
||||
* digest algorithm as its underlying hash function.</p>
|
||||
*
|
||||
* @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();
|
||||
}
|
||||
|
||||
// Class methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// Instance methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// Implementation of abstract methods in superclass ------------------------
|
||||
|
||||
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 (DEBUG && debuglevel > 8)
|
||||
{
|
||||
debug("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 (DEBUG && debuglevel > 8)
|
||||
{
|
||||
debug("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;
|
||||
}
|
||||
|
||||
// Other instance methods --------------------------------------------------
|
||||
|
||||
/**
|
||||
* Converts the <i>signature representative</i> <code>s</code> to a signature
|
||||
* <code>S</code> of length <code>k</code> octets; i.e.
|
||||
* <code>S = I2OSP(s, k)</code>, where <code>k = CEILING(modBits/8)</code>.
|
||||
*
|
||||
* @param s the <i>signature representative</i>.
|
||||
* @param k the length of the output.
|
||||
* @return the signature as an octet sequence.
|
||||
* @exception IllegalArgumentException if the length in octets of meaningful
|
||||
* bytes of <code>s</code> is greater than <code>k</code>, implying that
|
||||
* <code>s</code> is not less than the RSA <i>modulus</i>.
|
||||
*/
|
||||
// private Object encodeSignature(BigInteger s, int k) {
|
||||
// if (DEBUG && debuglevel > 8) {
|
||||
// debug("s.bitLength(): "+String.valueOf(s.bitLength()));
|
||||
// debug("k: "+String.valueOf(k));
|
||||
// }
|
||||
// byte[] result = s.toByteArray();
|
||||
// if (DEBUG && debuglevel > 8) {
|
||||
// debug("s: "+Util.toString(result));
|
||||
// debug("s (bytes): "+String.valueOf(result.length));
|
||||
// }
|
||||
// if (result.length < k) {
|
||||
// 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
|
||||
// int limit = result.length - k;
|
||||
// for (int i = 0; i < limit; i++) {
|
||||
// if (result[i] != 0x00) {
|
||||
// throw new IllegalArgumentException("integer too large");
|
||||
// }
|
||||
// }
|
||||
// byte[] newResult = new byte[k];
|
||||
// System.arraycopy(result, limit, newResult, 0, k);
|
||||
// result = newResult;
|
||||
// }
|
||||
// return result;
|
||||
// }
|
||||
/**
|
||||
* Returns the output of a previously generated signature object as an octet
|
||||
* sequence.<p>
|
||||
*
|
||||
* @return the octet sequence <code>S</code>.
|
||||
*/
|
||||
// private byte[] decodeSignature(Object signature) {
|
||||
// return (byte[]) signature;
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
/* 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;
|
||||
|
||||
/**
|
||||
* <p>An object that implements the {@link gnu.crypto.sig.ISignatureCodec}
|
||||
* operations for the <i>Raw</i> format to use with RSA-PSS signatures.</p>
|
||||
*
|
||||
* @version $Revision: 1.1 $
|
||||
*/
|
||||
public class RSAPSSSignatureRawCodec implements ISignatureCodec
|
||||
{
|
||||
|
||||
// Constants and variables
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// Constructor(s)
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// implicit 0-arguments constructor
|
||||
|
||||
// Class methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// gnu.crypto.keys.IKeyPairCodec interface implementation
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
public int getFormatID()
|
||||
{
|
||||
return RAW_FORMAT;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns the encoded form of the designated RSA-PSS signature object
|
||||
* according to the <i>Raw</i> format supported by this library.</p>
|
||||
*
|
||||
* <p>The <i>Raw</i> format for an RSA-PSS signature, in this implementation,
|
||||
* is a byte sequence consisting of the following:</p>
|
||||
*
|
||||
* <ol>
|
||||
* <li>4-byte magic consisting of the value of the literal
|
||||
* {@link Registry#MAGIC_RAW_RSA_PSS_SIGNATURE},<li>
|
||||
* <li>1-byte version consisting of the constant: 0x01,</li>
|
||||
* <li>4-byte count of following bytes representing the RSA-PSS signature
|
||||
* bytes in internet order,</li>
|
||||
* <li>the RSA-PSS signature bytes in internet order.</li>
|
||||
* </ol>
|
||||
*
|
||||
* @param signature the signature to encode, consisting of the output of the
|
||||
* <code>sign()</code> method of a {@link RSAPSSSignature} instance --a byte
|
||||
* array.
|
||||
* @return the <i>Raw</i> 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("key");
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -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 <code>rsa-</code>, followed by either
|
||||
* <code>pss</code> or <code>pkcs1_v1.5</code>. An optional message digest
|
||||
* name, to be used with the RSA signature may be specified by appending the
|
||||
* hyphen chanaracter <code>-</code> 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 <code>null</code> 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 <i>RSA</i> signatures supported by this
|
||||
* <i>Factory</i>.
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user