org.bouncycastle.crypto.signers.X931Signer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of bcprov-ext-debug-jdk18on Show documentation
Show all versions of bcprov-ext-debug-jdk18on Show documentation
The Bouncy Castle Crypto package is a Java implementation of cryptographic algorithms. This jar contains JCE provider and lightweight API for the Bouncy Castle Cryptography APIs for Java 1.8 and later with debug enabled.
The newest version!
package org.bouncycastle.crypto.signers;
import java.math.BigInteger;
import org.bouncycastle.crypto.AsymmetricBlockCipher;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.Signer;
import org.bouncycastle.crypto.params.RSAKeyParameters;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.BigIntegers;
/**
* X9.31-1998 - signing using a hash.
*
* The message digest hash, H, is encapsulated to form a byte string as follows
*
* EB = 06 || PS || 0xBA || H || TRAILER
*
* 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
{
/** @deprecated use ISOTrailers */
static final public int TRAILER_IMPLICIT = 0xBC;
/** @deprecated use ISOTrailers */
static final public int TRAILER_RIPEMD160 = 0x31CC;
/** @deprecated use ISOTrailers */
static final public int TRAILER_RIPEMD128 = 0x32CC;
/** @deprecated use ISOTrailers */
static final public int TRAILER_SHA1 = 0x33CC;
/** @deprecated use ISOTrailers */
static final public int TRAILER_SHA256 = 0x34CC;
/** @deprecated use ISOTrailers */
static final public int TRAILER_SHA512 = 0x35CC;
/** @deprecated use ISOTrailers */
static final public int TRAILER_SHA384 = 0x36CC;
/** @deprecated use ISOTrailers */
static final public int TRAILER_WHIRLPOOL = 0x37CC;
/** @deprecated use ISOTrailers */
static final public int TRAILER_SHA224 = 0x38CC;
private Digest digest;
private AsymmetricBlockCipher cipher;
private RSAKeyParameters kParam;
private int trailer;
private int keyBits;
private byte[] block;
/**
* Generate a signer with either implicit or explicit trailers for X9.31
*
* @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 = ISOTrailers.TRAILER_IMPLICIT;
}
else
{
Integer trailerObj = ISOTrailers.getTrailer(digest);
if (trailerObj != null)
{
trailer = trailerObj.intValue();
}
else
{
throw new IllegalArgumentException("no valid trailer for digest: " + digest.getAlgorithmName());
}
}
}
/**
* 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(trailer);
BigInteger t = new BigInteger(1, cipher.processBlock(block, 0, block.length));
clearBlock(block);
t = t.min(kParam.getModulus().subtract(t));
int size = BigIntegers.getUnsignedByteLength(kParam.getModulus());
return BigIntegers.asUnsignedByteArray(size, t);
}
private void createSignatureBlock(int trailer)
{
int digSize = digest.getDigestSize();
int delta;
if (trailer == ISOTrailers.TRAILER_IMPLICIT)
{
delta = block.length - digSize - 1;
digest.doFinal(block, delta);
block[block.length - 1] = (byte)ISOTrailers.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 X9.31 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(1, block);
BigInteger f;
if ((t.intValue() & 15) == 12)
{
f = t;
}
else
{
t = kParam.getModulus().subtract(t);
if ((t.intValue() & 15) == 12)
{
f = t;
}
else
{
return false;
}
}
createSignatureBlock(trailer);
byte[] fBlock = BigIntegers.asUnsignedByteArray(block.length, f);
boolean rv = Arrays.constantTimeAreEqual(block, fBlock);
// check for old NIST tool value
if (trailer == ISOTrailers.TRAILER_SHA512_256 && !rv)
{
block[block.length - 2] = (byte)0x40; // old NIST CAVP tool value
rv = Arrays.constantTimeAreEqual(block, fBlock);
}
clearBlock(block);
clearBlock(fBlock);
return rv;
}
}