summaryrefslogtreecommitdiffstats
path: root/bcprov/src/main/java/org/bouncycastle/crypto/signers/X931Signer.java
diff options
context:
space:
mode:
Diffstat (limited to 'bcprov/src/main/java/org/bouncycastle/crypto/signers/X931Signer.java')
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/signers/X931Signer.java269
1 files changed, 269 insertions, 0 deletions
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/signers/X931Signer.java b/bcprov/src/main/java/org/bouncycastle/crypto/signers/X931Signer.java
new file mode 100644
index 0000000..7197404
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/signers/X931Signer.java
@@ -0,0 +1,269 @@
+package org.bouncycastle.crypto.signers;
+
+import java.math.BigInteger;
+import java.util.Hashtable;
+
+import org.bouncycastle.crypto.AsymmetricBlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.CryptoException;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.Signer;
+import org.bouncycastle.crypto.SignerWithRecovery;
+import org.bouncycastle.crypto.params.RSAKeyParameters;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.BigIntegers;
+import org.bouncycastle.util.Integers;
+import org.bouncycastle.util.encoders.Hex;
+
+/**
+ * X9.31-1998 - signing using a hash.
+ * <p>
+ * The message digest hash, H, is encapsulated to form a byte string as follows
+ * <pre>
+ * EB = 06 || PS || 0xBA || H || TRAILER
+ * </pre>
+ * where PS is a string of bytes all of value 0xBB of length such that |EB|=|n|, and TRAILER is the ISO/IEC 10118 part number† for the digest. The byte string, EB, is converted to an integer value, the message representative, f.
+ */
+public class X931Signer
+ implements Signer
+{
+ static final public int TRAILER_IMPLICIT = 0xBC;
+ static final public int TRAILER_RIPEMD160 = 0x31CC;
+ static final public int TRAILER_RIPEMD128 = 0x32CC;
+ static final public int TRAILER_SHA1 = 0x33CC;
+ static final public int TRAILER_SHA256 = 0x34CC;
+ static final public int TRAILER_SHA512 = 0x35CC;
+ static final public int TRAILER_SHA384 = 0x36CC;
+ static final public int TRAILER_WHIRLPOOL = 0x37CC;
+ static final public int TRAILER_SHA224 = 0x38CC;
+
+ private static Hashtable trailerMap = new Hashtable();
+
+ static
+ {
+ trailerMap.put("RIPEMD128", Integers.valueOf(TRAILER_RIPEMD128));
+ trailerMap.put("RIPEMD160", Integers.valueOf(TRAILER_RIPEMD160));
+
+ trailerMap.put("SHA-1", Integers.valueOf(TRAILER_SHA1));
+ trailerMap.put("SHA-224", Integers.valueOf(TRAILER_SHA224));
+ trailerMap.put("SHA-256", Integers.valueOf(TRAILER_SHA256));
+ trailerMap.put("SHA-384", Integers.valueOf(TRAILER_SHA384));
+ trailerMap.put("SHA-512", Integers.valueOf(TRAILER_SHA512));
+
+ trailerMap.put("Whirlpool", Integers.valueOf(TRAILER_WHIRLPOOL));
+ }
+
+ private Digest digest;
+ private AsymmetricBlockCipher cipher;
+ private RSAKeyParameters kParam;
+
+ private int trailer;
+ private int keyBits;
+ private byte[] block;
+
+ /**
+ * Generate a signer for the with either implicit or explicit trailers
+ * for ISO9796-2.
+ *
+ * @param cipher base cipher to use for signature creation/verification
+ * @param digest digest to use.
+ * @param implicit whether or not the trailer is implicit or gives the hash.
+ */
+ public X931Signer(
+ AsymmetricBlockCipher cipher,
+ Digest digest,
+ boolean implicit)
+ {
+ this.cipher = cipher;
+ this.digest = digest;
+
+ if (implicit)
+ {
+ trailer = TRAILER_IMPLICIT;
+ }
+ else
+ {
+ Integer trailerObj = (Integer)trailerMap.get(digest.getAlgorithmName());
+
+ if (trailerObj != null)
+ {
+ trailer = trailerObj.intValue();
+ }
+ else
+ {
+ throw new IllegalArgumentException("no valid trailer for digest");
+ }
+ }
+ }
+
+ /**
+ * Constructor for a signer with an explicit digest trailer.
+ *
+ * @param cipher cipher to use.
+ * @param digest digest to sign with.
+ */
+ public X931Signer(
+ AsymmetricBlockCipher cipher,
+ Digest digest)
+ {
+ this(cipher, digest, false);
+ }
+
+ public void init(
+ boolean forSigning,
+ CipherParameters param)
+ {
+ kParam = (RSAKeyParameters)param;
+
+ cipher.init(forSigning, kParam);
+
+ keyBits = kParam.getModulus().bitLength();
+
+ block = new byte[(keyBits + 7) / 8];
+
+ reset();
+ }
+
+ /**
+ * clear possible sensitive data
+ */
+ private void clearBlock(
+ byte[] block)
+ {
+ for (int i = 0; i != block.length; i++)
+ {
+ block[i] = 0;
+ }
+ }
+
+ /**
+ * update the internal digest with the byte b
+ */
+ public void update(
+ byte b)
+ {
+ digest.update(b);
+ }
+
+ /**
+ * update the internal digest with the byte array in
+ */
+ public void update(
+ byte[] in,
+ int off,
+ int len)
+ {
+ digest.update(in, off, len);
+ }
+
+ /**
+ * reset the internal state
+ */
+ public void reset()
+ {
+ digest.reset();
+ }
+
+ /**
+ * generate a signature for the loaded message using the key we were
+ * initialised with.
+ */
+ public byte[] generateSignature()
+ throws CryptoException
+ {
+ createSignatureBlock();
+
+ BigInteger t = new BigInteger(1, cipher.processBlock(block, 0, block.length));
+ BigInteger nSubT = kParam.getModulus().subtract(t);
+
+ clearBlock(block);
+
+ BigInteger v = kParam.getModulus().shiftRight(2);
+
+ if (t.compareTo(nSubT) > 0)
+ {
+ return BigIntegers.asUnsignedByteArray((kParam.getModulus().bitLength() + 7) / 8, nSubT);
+ }
+ else
+ {
+ return BigIntegers.asUnsignedByteArray((kParam.getModulus().bitLength() + 7) / 8, t);
+ }
+ }
+
+ private void createSignatureBlock()
+ {
+ int digSize = digest.getDigestSize();
+
+ int delta;
+
+ if (trailer == TRAILER_IMPLICIT)
+ {
+ delta = block.length - digSize - 1;
+ digest.doFinal(block, delta);
+ block[block.length - 1] = (byte)TRAILER_IMPLICIT;
+ }
+ else
+ {
+ delta = block.length - digSize - 2;
+ digest.doFinal(block, delta);
+ block[block.length - 2] = (byte)(trailer >>> 8);
+ block[block.length - 1] = (byte)trailer;
+ }
+
+ block[0] = 0x6b;
+ for (int i = delta - 2; i != 0; i--)
+ {
+ block[i] = (byte)0xbb;
+ }
+ block[delta - 1] = (byte)0xba;
+ }
+
+ /**
+ * return true if the signature represents a ISO9796-2 signature
+ * for the passed in message.
+ */
+ public boolean verifySignature(
+ byte[] signature)
+ {
+ try
+ {
+ block = cipher.processBlock(signature, 0, signature.length);
+ }
+ catch (Exception e)
+ {
+ return false;
+ }
+
+ BigInteger t = new BigInteger(block);
+ BigInteger f;
+
+ if (t.mod(BigInteger.valueOf(16)).equals(BigInteger.valueOf(12)))
+ {
+ f = t;
+ }
+ else
+ {
+ t = kParam.getModulus().subtract(t);
+ if (t.mod(BigInteger.valueOf(16)).equals(BigInteger.valueOf(12)))
+ {
+ f = t;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ createSignatureBlock();
+
+ byte[] fBlock = BigIntegers.asUnsignedByteArray(block.length, f);
+
+ boolean rv = Arrays.constantTimeAreEqual(block, fBlock);
+
+ clearBlock(block);
+ clearBlock(fBlock);
+
+ return rv;
+ }
+}