org.testifyproject.bouncycastle.crypto.signers.X931Signer Maven / Gradle / Ivy
The newest version!
package org.testifyproject.bouncycastle.crypto.signers;
import java.math.BigInteger;
import java.util.Hashtable;
import org.testifyproject.bouncycastle.crypto.AsymmetricBlockCipher;
import org.testifyproject.bouncycastle.crypto.CipherParameters;
import org.testifyproject.bouncycastle.crypto.CryptoException;
import org.testifyproject.bouncycastle.crypto.Digest;
import org.testifyproject.bouncycastle.crypto.InvalidCipherTextException;
import org.testifyproject.bouncycastle.crypto.Signer;
import org.testifyproject.bouncycastle.crypto.SignerWithRecovery;
import org.testifyproject.bouncycastle.crypto.params.RSAKeyParameters;
import org.testifyproject.bouncycastle.util.Arrays;
import org.testifyproject.bouncycastle.util.BigIntegers;
import org.testifyproject.bouncycastle.util.Integers;
import org.testifyproject.bouncycastle.util.encoders.Hex;
/**
* 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
{
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.org.testifyproject.testifyprojectpareTo(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;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy