diff options
Diffstat (limited to 'core/src/main')
12 files changed, 432 insertions, 113 deletions
diff --git a/core/src/main/java/org/bouncycastle/crypto/digests/SHA512tDigest.java b/core/src/main/java/org/bouncycastle/crypto/digests/SHA512tDigest.java index 9abf73b4..d5848b17 100644 --- a/core/src/main/java/org/bouncycastle/crypto/digests/SHA512tDigest.java +++ b/core/src/main/java/org/bouncycastle/crypto/digests/SHA512tDigest.java @@ -10,7 +10,7 @@ import org.bouncycastle.util.Pack; public class SHA512tDigest extends LongDigest { - private final int digestLength; + private int digestLength; // non-final due to old flow analyser. private long H1t, H2t, H3t, H4t, H5t, H6t, H7t, H8t; diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/CramerShoupCoreEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/CramerShoupCoreEngine.java index 5fcfff9b..4c0db1b5 100644 --- a/core/src/main/java/org/bouncycastle/crypto/engines/CramerShoupCoreEngine.java +++ b/core/src/main/java/org/bouncycastle/crypto/engines/CramerShoupCoreEngine.java @@ -299,10 +299,9 @@ public class CramerShoupCoreEngine /** * CS exception for wrong cipher-texts */ - public class CramerShoupCiphertextException + public static class CramerShoupCiphertextException extends Exception { - private static final long serialVersionUID = -6360977166495345076L; public CramerShoupCiphertextException(String msg) diff --git a/core/src/main/java/org/bouncycastle/crypto/generators/CramerShoupParametersGenerator.java b/core/src/main/java/org/bouncycastle/crypto/generators/CramerShoupParametersGenerator.java index 704b1de4..4788a8ca 100644 --- a/core/src/main/java/org/bouncycastle/crypto/generators/CramerShoupParametersGenerator.java +++ b/core/src/main/java/org/bouncycastle/crypto/generators/CramerShoupParametersGenerator.java @@ -8,105 +8,116 @@ import org.bouncycastle.crypto.params.CramerShoupParameters; import org.bouncycastle.crypto.params.DHParameters; import org.bouncycastle.util.BigIntegers; -public class CramerShoupParametersGenerator { - - private int size; - private int certainty; - private SecureRandom random; - - /** - * Initialise the parameters generator. - * - * @param size - * bit length for the prime p - * @param certainty - * a measure of the uncertainty that the caller is willing to tolerate: - * the probability that the generated modulus is prime exceeds (1 - 1/2^certainty). - * The execution time of this method is proportional to the value of this parameter. - * @param random - * a source of randomness - */ - public void init(int size, int certainty, SecureRandom random) { - this.size = size; - this.certainty = certainty; - this.random = random; - } - - /** - * which generates the p and g values from the given parameters, returning - * the CramerShoupParameters object. - * <p> - * Note: can take a while... - */ - public CramerShoupParameters generateParameters() { - // - // find a safe prime p where p = 2*q + 1, where p and q are prime. - // - BigInteger[] safePrimes = ParametersHelper.generateSafePrimes(size, certainty, random); +public class CramerShoupParametersGenerator +{ + private static final BigInteger ONE = BigInteger.valueOf(1); + + private int size; + private int certainty; + private SecureRandom random; + + /** + * Initialise the parameters generator. + * + * @param size bit length for the prime p + * @param certainty a measure of the uncertainty that the caller is willing to tolerate: + * the probability that the generated modulus is prime exceeds (1 - 1/2^certainty). + * The execution time of this method is proportional to the value of this parameter. + * @param random a source of randomness + */ + public void init(int size, int certainty, SecureRandom random) + { + this.size = size; + this.certainty = certainty; + this.random = random; + } + + /** + * which generates the p and g values from the given parameters, returning + * the CramerShoupParameters object. + * <p/> + * Note: can take a while... + */ + public CramerShoupParameters generateParameters() + { + // + // find a safe prime p where p = 2*q + 1, where p and q are prime. + // + BigInteger[] safePrimes = ParametersHelper.generateSafePrimes(size, certainty, random); // BigInteger p = safePrimes[0]; - BigInteger q = safePrimes[1]; - BigInteger g1 = ParametersHelper.selectGenerator(q, random); - BigInteger g2 = ParametersHelper.selectGenerator(q, random); - while(g1.equals(g2)){ - g2 = ParametersHelper.selectGenerator(q, random); - } - - return new CramerShoupParameters(q, g1, g2, new SHA256Digest()); - } - - public CramerShoupParameters generateParameters(DHParameters dhParams){ - BigInteger p = dhParams.getP(); - BigInteger g1 = dhParams.getG(); - - // now we just need a second generator - BigInteger g2 = ParametersHelper.selectGenerator(p, random); - while(g1.equals(g2)){ - g2 = ParametersHelper.selectGenerator(p, random); - } - - return new CramerShoupParameters(p, g1, g2, new SHA256Digest()); - } - - private static class ParametersHelper { - - private static final BigInteger TWO = BigInteger.valueOf(2); - - /* - * Finds a pair of prime BigInteger's {p, q: p = 2q + 1} - * - * (see: Handbook of Applied Cryptography 4.86) - */ - static BigInteger[] generateSafePrimes(int size, int certainty, SecureRandom random) { - BigInteger p, q; - int qLength = size - 1; - - for (;;) { - q = new BigInteger(qLength, 2, random); - p = q.shiftLeft(1).add(BigInteger.ONE); - if (p.isProbablePrime(certainty) && (certainty <= 2 || q.isProbablePrime(certainty))) { - break; - } - } - - return new BigInteger[] { p, q }; - } - - static BigInteger selectGenerator(BigInteger p, SecureRandom random) { - BigInteger pMinusTwo = p.subtract(TWO); - BigInteger g; + BigInteger q = safePrimes[1]; + BigInteger g1 = ParametersHelper.selectGenerator(q, random); + BigInteger g2 = ParametersHelper.selectGenerator(q, random); + while (g1.equals(g2)) + { + g2 = ParametersHelper.selectGenerator(q, random); + } + + return new CramerShoupParameters(q, g1, g2, new SHA256Digest()); + } + + public CramerShoupParameters generateParameters(DHParameters dhParams) + { + BigInteger p = dhParams.getP(); + BigInteger g1 = dhParams.getG(); + + // now we just need a second generator + BigInteger g2 = ParametersHelper.selectGenerator(p, random); + while (g1.equals(g2)) + { + g2 = ParametersHelper.selectGenerator(p, random); + } + + return new CramerShoupParameters(p, g1, g2, new SHA256Digest()); + } + + private static class ParametersHelper + { + + private static final BigInteger TWO = BigInteger.valueOf(2); + + /* + * Finds a pair of prime BigInteger's {p, q: p = 2q + 1} + * + * (see: Handbook of Applied Cryptography 4.86) + */ + static BigInteger[] generateSafePrimes(int size, int certainty, SecureRandom random) + { + BigInteger p, q; + int qLength = size - 1; + + for (; ; ) + { + q = new BigInteger(qLength, 2, random); + p = q.shiftLeft(1).add(ONE); + if (p.isProbablePrime(certainty) && (certainty <= 2 || q.isProbablePrime(certainty))) + { + break; + } + } + + return new BigInteger[]{p, q}; + } + + static BigInteger selectGenerator(BigInteger p, SecureRandom random) + { + BigInteger pMinusTwo = p.subtract(TWO); + BigInteger g; /* - * RFC 2631 2.2.1.2 (and see: Handbook of Applied Cryptography 4.81) + * RFC 2631 2.2.1.2 (and see: Handbook of Applied Cryptography 4.81) */ - do { - BigInteger h = BigIntegers.createRandomInRange(TWO, pMinusTwo, random); + do + { + BigInteger h = BigIntegers.createRandomInRange(TWO, pMinusTwo, random); - g = h.modPow(TWO, p); - } while (g.equals(BigInteger.ONE)); + g = h.modPow(TWO, p); + } + while (g.equals(ONE)); - return g; - } - } + return g; + } + } } diff --git a/core/src/main/java/org/bouncycastle/crypto/io/CipherInputStream.java b/core/src/main/java/org/bouncycastle/crypto/io/CipherInputStream.java index 8d5b99b2..b06d1f53 100644 --- a/core/src/main/java/org/bouncycastle/crypto/io/CipherInputStream.java +++ b/core/src/main/java/org/bouncycastle/crypto/io/CipherInputStream.java @@ -25,8 +25,8 @@ public class CipherInputStream { private static final int INPUT_BUF_SIZE = 2048; - private final SkippingCipher skippingCipher; - private final byte[] inBuf; + private SkippingCipher skippingCipher; + private byte[] inBuf; private BufferedBlockCipher bufferedBlockCipher; private StreamCipher streamCipher; diff --git a/core/src/main/java/org/bouncycastle/crypto/params/ECNamedDomainParameters.java b/core/src/main/java/org/bouncycastle/crypto/params/ECNamedDomainParameters.java index 6350806f..5b694bec 100644 --- a/core/src/main/java/org/bouncycastle/crypto/params/ECNamedDomainParameters.java +++ b/core/src/main/java/org/bouncycastle/crypto/params/ECNamedDomainParameters.java @@ -9,7 +9,7 @@ import org.bouncycastle.math.ec.ECPoint; public class ECNamedDomainParameters extends ECDomainParameters { - private final ASN1ObjectIdentifier name; + private ASN1ObjectIdentifier name; public ECNamedDomainParameters(ASN1ObjectIdentifier name, ECCurve curve, ECPoint G, BigInteger n) { diff --git a/core/src/main/java/org/bouncycastle/crypto/params/KDFCounterParameters.java b/core/src/main/java/org/bouncycastle/crypto/params/KDFCounterParameters.java index 8ff637da..29d8b369 100644 --- a/core/src/main/java/org/bouncycastle/crypto/params/KDFCounterParameters.java +++ b/core/src/main/java/org/bouncycastle/crypto/params/KDFCounterParameters.java @@ -34,10 +34,10 @@ public final class KDFCounterParameters implements DerivationParameters { - private final byte[] ki; - private final byte[] fixedInputDataCounterPrefix; - private final byte[] fixedInputDataCounterSuffix; - private final int r; + private byte[] ki; + private byte[] fixedInputDataCounterPrefix; + private byte[] fixedInputDataCounterSuffix; + private int r; /** * Base constructor - suffix fixed input data only. diff --git a/core/src/main/java/org/bouncycastle/crypto/signers/DSTU4145Signer.java b/core/src/main/java/org/bouncycastle/crypto/signers/DSTU4145Signer.java index d0b893a6..bceb8220 100644 --- a/core/src/main/java/org/bouncycastle/crypto/signers/DSTU4145Signer.java +++ b/core/src/main/java/org/bouncycastle/crypto/signers/DSTU4145Signer.java @@ -163,7 +163,7 @@ public class DSTU4145Signer { if (x.bitLength() > bitLength) { - x = x.mod(BigInteger.ONE.shiftLeft(bitLength)); + x = x.mod(ONE.shiftLeft(bitLength)); } return x; } diff --git a/core/src/main/java/org/bouncycastle/math/ec/tools/DiscoverEndomorphisms.java b/core/src/main/java/org/bouncycastle/math/ec/tools/DiscoverEndomorphisms.java index 4292da31..4ee2de60 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/tools/DiscoverEndomorphisms.java +++ b/core/src/main/java/org/bouncycastle/math/ec/tools/DiscoverEndomorphisms.java @@ -213,7 +213,7 @@ public class DiscoverEndomorphisms BigInteger s0 = ECConstants.ONE, s1 = ECConstants.ZERO; BigInteger t0 = ECConstants.ZERO, t1 = ECConstants.ONE; - while (r1.compareTo(BigInteger.ONE) > 0) + while (r1.compareTo(ECConstants.ONE) > 0) { BigInteger[] qr = r0.divideAndRemainder(r1); BigInteger q = qr[0], r2 = qr[1]; diff --git a/core/src/main/jdk1.1/java/security/cert/X509CertSelector.java b/core/src/main/jdk1.1/java/security/cert/X509CertSelector.java index d5c783a6..0ac127f6 100644 --- a/core/src/main/jdk1.1/java/security/cert/X509CertSelector.java +++ b/core/src/main/jdk1.1/java/security/cert/X509CertSelector.java @@ -26,6 +26,7 @@ import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.ASN1GeneralizedTime; import org.bouncycastle.asn1.DERGeneralizedTime; import org.bouncycastle.asn1.DEROutputStream; import org.bouncycastle.asn1.util.ASN1Dump; @@ -2148,7 +2149,7 @@ public class X509CertSelector implements CertSelector // TODO fix this, Sequence contains tagged objects ASN1Sequence derObject = (ASN1Sequence)derInputStream .readObject(); - DERGeneralizedTime derDate = DERGeneralizedTime + ASN1GeneralizedTime derDate = DERGeneralizedTime .getInstance(derObject.getObjectAt(0)); SimpleDateFormat dateF = new SimpleDateFormat( "yyyyMMddHHmmssZ"); diff --git a/core/src/main/jdk1.1/java/util/Collections.java b/core/src/main/jdk1.1/java/util/Collections.java index 1b7f2e93..efde29b3 100644 --- a/core/src/main/jdk1.1/java/util/Collections.java +++ b/core/src/main/jdk1.1/java/util/Collections.java @@ -4,7 +4,8 @@ import java.io.Serializable; public class Collections { - public static List EMPTY_LIST = new ArrayList(); + public static final List EMPTY_LIST = unmodifiableList(new ArrayList()); + public static final Set EMPTY_SET = unmodifiableSet(new HashSet()); private Collections() { diff --git a/core/src/main/jdk1.1/org/bouncycastle/crypto/encodings/PKCS1Encoding.java b/core/src/main/jdk1.1/org/bouncycastle/crypto/encodings/PKCS1Encoding.java index e4a8750f..76051c3f 100644 --- a/core/src/main/jdk1.1/org/bouncycastle/crypto/encodings/PKCS1Encoding.java +++ b/core/src/main/jdk1.1/org/bouncycastle/crypto/encodings/PKCS1Encoding.java @@ -1,13 +1,13 @@ package org.bouncycastle.crypto.encodings; +import java.security.SecureRandom; + import org.bouncycastle.crypto.AsymmetricBlockCipher; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.crypto.params.ParametersWithRandom; -import java.security.SecureRandom; - /** * this does your basic PKCS 1 v1.5 padding - whether or not you should be using this * depends on your application - see PKCS1 Version 2 for details. @@ -32,6 +32,8 @@ public class PKCS1Encoding private boolean forEncryption; private boolean forPrivateKey; private boolean useStrictLength; + private int pLen = -1; + private byte[] fallback = null; /** * Basic constructor. @@ -44,11 +46,48 @@ public class PKCS1Encoding this.useStrictLength = useStrict(); } + /** + * Constructor for decryption with a fixed plaintext length. + * + * @param cipher The cipher to use for cryptographic operation. + * @param pLen Length of the expected plaintext. + */ + public PKCS1Encoding( + AsymmetricBlockCipher cipher, + int pLen) + { + this.engine = cipher; + this.useStrictLength = useStrict(); + this.pLen = pLen; + } + + /** + * Constructor for decryption with a fixed plaintext length and a fallback + * value that is returned, if the padding is incorrect. + * + * @param cipher + * The cipher to use for cryptographic operation. + * @param fallback + * The fallback value, we don't to a arraycopy here. + */ + public PKCS1Encoding( + AsymmetricBlockCipher cipher, + byte[] fallback) + { + this.engine = cipher; + this.useStrictLength = useStrict(); + this.fallback = fallback; + this.pLen = fallback.length; + } + + + // // for J2ME compatibility // private boolean useStrict() { + // required if security manager has been installed. String strict = System.getProperty(STRICT_LENGTH_ENABLED_PROPERTY); return strict == null || strict.equals("true"); @@ -174,6 +213,121 @@ public class PKCS1Encoding return engine.processBlock(block, 0, block.length); } + + /** + * Checks if the argument is a correctly PKCS#1.5 encoded Plaintext + * for encryption. + * + * @param encoded The Plaintext. + * @param pLen Expected length of the plaintext. + * @return Either 0, if the encoding is correct, or -1, if it is incorrect. + */ + private static int checkPkcs1Encoding(byte[] encoded, int pLen) { + int correct = 0; + /* + * Check if the first two bytes are 0 2 + */ + correct |= (encoded[0] ^ 2); + + /* + * Now the padding check, check for no 0 byte in the padding + */ + int plen = encoded.length - ( + pLen /* Lenght of the PMS */ + + 1 /* Final 0-byte before PMS */ + ); + + for (int i = 1; i < plen; i++) { + int tmp = encoded[i]; + tmp |= tmp >> 1; + tmp |= tmp >> 2; + tmp |= tmp >> 4; + correct |= (tmp & 1) - 1; + } + + /* + * Make sure the padding ends with a 0 byte. + */ + correct |= encoded[encoded.length - (pLen +1)]; + + /* + * Return 0 or 1, depending on the result. + */ + correct |= correct >> 1; + correct |= correct >> 2; + correct |= correct >> 4; + return ~((correct & 1) - 1); + } + + + /** + * Decode PKCS#1.5 encoding, and return a random value if the padding is not correct. + * + * @param in The encrypted block. + * @param inOff Offset in the encrypted block. + * @param inLen Length of the encrypted block. + * //@param pLen Length of the desired output. + * @return The plaintext without padding, or a random value if the padding was incorrect. + * + * @throws InvalidCipherTextException + */ + private byte[] decodeBlockOrRandom(byte[] in, int inOff, int inLen) + throws InvalidCipherTextException + { + if (!forPrivateKey) + { + throw new InvalidCipherTextException("sorry, this method is only for decryption, not for signing"); + } + + byte[] block = engine.processBlock(in, inOff, inLen); + byte[] random = null; + if (this.fallback == null) + { + random = new byte[this.pLen]; + this.random.nextBytes(random); + } + else + { + random = fallback; + } + + /* + * TODO: This is a potential dangerous side channel. However, you can + * fix this by changing the RSA engine in a way, that it will always + * return blocks of the same length and prepend them with 0 bytes if + * needed. + */ + if (block.length < getOutputBlockSize()) + { + throw new InvalidCipherTextException("block truncated"); + } + + /* + * TODO: Potential side channel. Fix it by making the engine always + * return blocks of the correct length. + */ + if (useStrictLength && block.length != engine.getOutputBlockSize()) + { + throw new InvalidCipherTextException("block incorrect size"); + } + + /* + * Check the padding. + */ + int correct = PKCS1Encoding.checkPkcs1Encoding(block, this.pLen); + + /* + * Now, to a constant time constant memory copy of the decrypted value + * or the random value, depending on the validity of the padding. + */ + byte[] result = new byte[this.pLen]; + for (int i = 0; i < this.pLen; i++) + { + result[i] = (byte)((block[i + (block.length - pLen)] & (~correct)) | (random[i] & correct)); + } + + return result; + } /** * @exception InvalidCipherTextException if the decrypted block is not in PKCS1 format. @@ -184,7 +338,15 @@ public class PKCS1Encoding int inLen) throws InvalidCipherTextException { - byte[] block = engine.processBlock(in, inOff, inLen); + /* + * If the length of the expected plaintext is known, we use a constant-time decryption. + * If the decryption fails, we return a random value. + */ + if (this.pLen != -1) { + return this.decodeBlockOrRandom(in, inOff, inLen); + } + + byte[] block = engine.processBlock(in, inOff, inLen); if (block.length < getOutputBlockSize()) { @@ -192,10 +354,20 @@ public class PKCS1Encoding } byte type = block[0]; - - if (type != 1 && type != 2) + + if (forPrivateKey) { - throw new InvalidCipherTextException("unknown block type"); + if (type != 2) + { + throw new InvalidCipherTextException("unknown block type"); + } + } + else + { + if (type != 1) + { + throw new InvalidCipherTextException("unknown block type"); + } } if (useStrictLength && block.length != engine.getOutputBlockSize()) diff --git a/core/src/main/jdk1.1/org/bouncycastle/crypto/tls/AbstractTlsContext.java b/core/src/main/jdk1.1/org/bouncycastle/crypto/tls/AbstractTlsContext.java new file mode 100644 index 00000000..b8153b06 --- /dev/null +++ b/core/src/main/jdk1.1/org/bouncycastle/crypto/tls/AbstractTlsContext.java @@ -0,0 +1,135 @@ +package org.bouncycastle.crypto.tls; + +import java.security.SecureRandom; + +import org.bouncycastle.crypto.prng.DigestRandomGenerator; +import org.bouncycastle.crypto.prng.RandomGenerator; +import org.bouncycastle.util.Times; + +abstract class AbstractTlsContext + implements TlsContext +{ + private static long counter = Times.nanoTime(); + + private synchronized static long nextCounterValue() + { + return ++counter; + } + + private RandomGenerator nonceRandom; + private SecureRandom secureRandom; + private SecurityParameters securityParameters; + + private ProtocolVersion clientVersion = null; + private ProtocolVersion serverVersion = null; + private TlsSession session = null; + private Object userObject = null; + + AbstractTlsContext(SecureRandom secureRandom, SecurityParameters securityParameters) + { + secureRandom.setSeed(nextCounterValue()); + secureRandom.setSeed(Times.nanoTime()); + + this.nonceRandom = new DigestRandomGenerator(TlsUtils.createHash(HashAlgorithm.sha256)); + byte[] nonceSeed = new byte[32]; + secureRandom.nextBytes(nonceSeed); + this.nonceRandom.addSeedMaterial(nonceSeed); + + this.secureRandom = secureRandom; + this.securityParameters = securityParameters; + } + + public RandomGenerator getNonceRandomGenerator() + { + return nonceRandom; + } + + public SecureRandom getSecureRandom() + { + return secureRandom; + } + + public SecurityParameters getSecurityParameters() + { + return securityParameters; + } + + public ProtocolVersion getClientVersion() + { + return clientVersion; + } + + void setClientVersion(ProtocolVersion clientVersion) + { + this.clientVersion = clientVersion; + } + + public ProtocolVersion getServerVersion() + { + return serverVersion; + } + + void setServerVersion(ProtocolVersion serverVersion) + { + this.serverVersion = serverVersion; + } + + public TlsSession getResumableSession() + { + return session; + } + + void setResumableSession(TlsSession session) + { + this.session = session; + } + + public Object getUserObject() + { + return userObject; + } + + public void setUserObject(Object userObject) + { + this.userObject = userObject; + } + + public byte[] exportKeyingMaterial(String asciiLabel, byte[] context_value, int length) + { + if (context_value != null && !TlsUtils.isValidUint16(context_value.length)) + { + throw new IllegalArgumentException("'context_value' must have length less than 2^16 (or be null)"); + } + + SecurityParameters sp = getSecurityParameters(); + byte[] cr = sp.getClientRandom(), sr = sp.getServerRandom(); + + int seedLength = cr.length + sr.length; + if (context_value != null) + { + seedLength += (2 + context_value.length); + } + + byte[] seed = new byte[seedLength]; + int seedPos = 0; + + System.arraycopy(cr, 0, seed, seedPos, cr.length); + seedPos += cr.length; + System.arraycopy(sr, 0, seed, seedPos, sr.length); + seedPos += sr.length; + if (context_value != null) + { + TlsUtils.writeUint16(context_value.length, seed, seedPos); + seedPos += 2; + System.arraycopy(context_value, 0, seed, seedPos, context_value.length); + seedPos += context_value.length; + } + + if (seedPos != seedLength) + { + throw new IllegalStateException("error in calculation of seed for export"); + } + + return TlsUtils.PRF(this, sp.getMasterSecret(), asciiLabel, seed, length); + } +} |