diff options
author | Sergio Giro <sgiro@google.com> | 2016-02-01 18:52:42 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2016-02-01 18:52:42 +0000 |
commit | 9218edabd1ef9852bc2f13115dcadc81b442dd6c (patch) | |
tree | 8229ff72c8cbb06f49dce3a8382930919fa6fc2b /bcprov/src/main/java/org/bouncycastle/crypto/signers/X931Signer.java | |
parent | 9b30eb05e5be69d51881a0d1b31e503e97acd784 (diff) | |
parent | 397d32894b89b506dc318e0f83446187c9b76ebe (diff) | |
download | android_external_bouncycastle-9218edabd1ef9852bc2f13115dcadc81b442dd6c.tar.gz android_external_bouncycastle-9218edabd1ef9852bc2f13115dcadc81b442dd6c.tar.bz2 android_external_bouncycastle-9218edabd1ef9852bc2f13115dcadc81b442dd6c.zip |
Merge "Merge remote-tracking branch 'aosp/upstream-master' into merge-152-from-upstream"
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.java | 269 |
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; + } +} |