diff --git a/crypto/src/asn1/DerBitString.cs b/crypto/src/asn1/DerBitString.cs
index a3c2cee01..26adc575b 100644
--- a/crypto/src/asn1/DerBitString.cs
+++ b/crypto/src/asn1/DerBitString.cs
@@ -28,6 +28,17 @@ namespace Org.BouncyCastle.Asn1
{
return (DerBitString) obj;
}
+ if (obj is byte[])
+ {
+ try
+ {
+ return (DerBitString)FromByteArray((byte[])obj);
+ }
+ catch (Exception e)
+ {
+ throw new ArgumentException("encoding error in GetInstance: " + e.ToString());
+ }
+ }
throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(obj));
}
diff --git a/crypto/src/asn1/ocsp/CertStatus.cs b/crypto/src/asn1/ocsp/CertStatus.cs
index b524364c9..7dd99b844 100644
--- a/crypto/src/asn1/ocsp/CertStatus.cs
+++ b/crypto/src/asn1/ocsp/CertStatus.cs
@@ -48,6 +48,8 @@ namespace Org.BouncyCastle.Asn1.Ocsp
case 2:
value = DerNull.Instance;
break;
+ default:
+ throw new ArgumentException("Unknown tag encountered: " + choice.TagNo);
}
}
diff --git a/crypto/src/crypto/agreement/ECDHBasicAgreement.cs b/crypto/src/crypto/agreement/ECDHBasicAgreement.cs
index c33f16f78..ca7b3fa3f 100644
--- a/crypto/src/crypto/agreement/ECDHBasicAgreement.cs
+++ b/crypto/src/crypto/agreement/ECDHBasicAgreement.cs
@@ -46,6 +46,9 @@ namespace Org.BouncyCastle.Crypto.Agreement
ICipherParameters pubKey)
{
ECPublicKeyParameters pub = (ECPublicKeyParameters) pubKey;
+ if (!pub.Parameters.Equals(privKey.Parameters))
+ throw new InvalidOperationException("ECDH public key has wrong domain parameters");
+
ECPoint P = pub.Q.Multiply(privKey.D).Normalize();
if (P.IsInfinity)
diff --git a/crypto/src/crypto/agreement/ECDHCBasicAgreement.cs b/crypto/src/crypto/agreement/ECDHCBasicAgreement.cs
index 89be7061e..1c9ae45f9 100644
--- a/crypto/src/crypto/agreement/ECDHCBasicAgreement.cs
+++ b/crypto/src/crypto/agreement/ECDHCBasicAgreement.cs
@@ -29,7 +29,7 @@ namespace Org.BouncyCastle.Crypto.Agreement
public class ECDHCBasicAgreement
: IBasicAgreement
{
- private ECPrivateKeyParameters key;
+ private ECPrivateKeyParameters privKey;
public virtual void Init(
ICipherParameters parameters)
@@ -39,12 +39,12 @@ namespace Org.BouncyCastle.Crypto.Agreement
parameters = ((ParametersWithRandom) parameters).Parameters;
}
- this.key = (ECPrivateKeyParameters)parameters;
+ this.privKey = (ECPrivateKeyParameters)parameters;
}
public virtual int GetFieldSize()
{
- return (key.Parameters.Curve.FieldSize + 7) / 8;
+ return (privKey.Parameters.Curve.FieldSize + 7) / 8;
}
public virtual BigInteger CalculateAgreement(
@@ -52,8 +52,10 @@ namespace Org.BouncyCastle.Crypto.Agreement
{
ECPublicKeyParameters pub = (ECPublicKeyParameters) pubKey;
ECDomainParameters parameters = pub.Parameters;
+ if (!parameters.Equals(privKey.Parameters))
+ throw new InvalidOperationException("ECDHC public key has wrong domain parameters");
- BigInteger hd = parameters.H.Multiply(key.D).Mod(parameters.N);
+ BigInteger hd = parameters.H.Multiply(privKey.D).Mod(parameters.N);
ECPoint P = pub.Q.Multiply(hd).Normalize();
diff --git a/crypto/src/crypto/agreement/ECMqvBasicAgreement.cs b/crypto/src/crypto/agreement/ECMqvBasicAgreement.cs
index f55ae46af..8d5cebb13 100644
--- a/crypto/src/crypto/agreement/ECMqvBasicAgreement.cs
+++ b/crypto/src/crypto/agreement/ECMqvBasicAgreement.cs
@@ -34,8 +34,12 @@ namespace Org.BouncyCastle.Crypto.Agreement
MqvPublicParameters pubParams = (MqvPublicParameters)pubKey;
ECPrivateKeyParameters staticPrivateKey = privParams.StaticPrivateKey;
+ ECDomainParameters parameters = staticPrivateKey.Parameters;
- ECPoint agreement = CalculateMqvAgreement(staticPrivateKey.Parameters, staticPrivateKey,
+ if (!parameters.Equals(pubParams.StaticPublicKey.Parameters))
+ throw new InvalidOperationException("ECMQV public key components have wrong domain parameters");
+
+ ECPoint agreement = CalculateMqvAgreement(parameters, staticPrivateKey,
privParams.EphemeralPrivateKey, privParams.EphemeralPublicKey,
pubParams.StaticPublicKey, pubParams.EphemeralPublicKey).Normalize();
@@ -61,8 +65,8 @@ namespace Org.BouncyCastle.Crypto.Agreement
ECCurve curve = parameters.Curve;
ECPoint[] points = new ECPoint[]{
- // The Q2U public key is optional
- ECAlgorithms.ImportPoint(curve, Q2U == null ? parameters.G.Multiply(d2U.D) : Q2U.Q),
+ // The Q2U public key is optional - but will be calculated for us if it wasn't present
+ ECAlgorithms.ImportPoint(curve, Q2U.Q),
ECAlgorithms.ImportPoint(curve, Q1V.Q),
ECAlgorithms.ImportPoint(curve, Q2V.Q)
};
diff --git a/crypto/src/crypto/generators/BCrypt.cs b/crypto/src/crypto/generators/BCrypt.cs
index b21a8671f..af8029a1b 100644
--- a/crypto/src/crypto/generators/BCrypt.cs
+++ b/crypto/src/crypto/generators/BCrypt.cs
@@ -14,8 +14,8 @@ namespace Org.BouncyCastle.Crypto.Generators
* "A Future-Adaptable Password Scheme" of Niels Provos and David Mazières,
* see: https://www.usenix.org/legacy/events/usenix99/provos/provos_html/node1.html.
* In contrast to the paper, the order of key setup and salt setup is reversed:
- * state <- ExpandKey(state, 0, key)
- * state <- ExpandKey(state, 0, salt)
+ * state <- ExpandKey(state, 0, key)
+ * state %lt;- ExpandKey(state, 0, salt)
* This corresponds to the OpenBSD reference implementation of Bcrypt.
* </p><p>
* Note:
diff --git a/crypto/src/crypto/generators/HKDFBytesGenerator.cs b/crypto/src/crypto/generators/HKDFBytesGenerator.cs
new file mode 100644
index 000000000..c2e667c95
--- /dev/null
+++ b/crypto/src/crypto/generators/HKDFBytesGenerator.cs
@@ -0,0 +1,153 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * HMAC-based Extract-and-Expand Key Derivation Function (HKDF) implemented
+ * according to IETF RFC 5869, May 2010 as specified by H. Krawczyk, IBM
+ * Research & P. Eronen, Nokia. It uses a HMac internally to compute de OKM
+ * (output keying material) and is likely to have better security properties
+ * than KDF's based on just a hash function.
+ */
+ public class HkdfBytesGenerator
+ : IDerivationFunction
+ {
+ private HMac hMacHash;
+ private int hashLen;
+
+ private byte[] info;
+ private byte[] currentT;
+
+ private int generatedBytes;
+
+ /**
+ * Creates a HKDFBytesGenerator based on the given hash function.
+ *
+ * @param hash the digest to be used as the source of generatedBytes bytes
+ */
+ public HkdfBytesGenerator(IDigest hash)
+ {
+ this.hMacHash = new HMac(hash);
+ this.hashLen = hash.GetDigestSize();
+ }
+
+ public virtual void Init(IDerivationParameters parameters)
+ {
+ if (!(parameters is HkdfParameters))
+ throw new ArgumentException("HKDF parameters required for HkdfBytesGenerator", "parameters");
+
+ HkdfParameters hkdfParameters = (HkdfParameters)parameters;
+ if (hkdfParameters.SkipExtract)
+ {
+ // use IKM directly as PRK
+ hMacHash.Init(new KeyParameter(hkdfParameters.GetIkm()));
+ }
+ else
+ {
+ hMacHash.Init(Extract(hkdfParameters.GetSalt(), hkdfParameters.GetIkm()));
+ }
+
+ info = hkdfParameters.GetInfo();
+
+ generatedBytes = 0;
+ currentT = new byte[hashLen];
+ }
+
+ /**
+ * Performs the extract part of the key derivation function.
+ *
+ * @param salt the salt to use
+ * @param ikm the input keying material
+ * @return the PRK as KeyParameter
+ */
+ private KeyParameter Extract(byte[] salt, byte[] ikm)
+ {
+ hMacHash.Init(new KeyParameter(ikm));
+ if (salt == null)
+ {
+ // TODO check if hashLen is indeed same as HMAC size
+ hMacHash.Init(new KeyParameter(new byte[hashLen]));
+ }
+ else
+ {
+ hMacHash.Init(new KeyParameter(salt));
+ }
+
+ hMacHash.BlockUpdate(ikm, 0, ikm.Length);
+
+ byte[] prk = new byte[hashLen];
+ hMacHash.DoFinal(prk, 0);
+ return new KeyParameter(prk);
+ }
+
+ /**
+ * Performs the expand part of the key derivation function, using currentT
+ * as input and output buffer.
+ *
+ * @throws DataLengthException if the total number of bytes generated is larger than the one
+ * specified by RFC 5869 (255 * HashLen)
+ */
+ private void ExpandNext()
+ {
+ int n = generatedBytes / hashLen + 1;
+ if (n >= 256)
+ {
+ throw new DataLengthException(
+ "HKDF cannot generate more than 255 blocks of HashLen size");
+ }
+ // special case for T(0): T(0) is empty, so no update
+ if (generatedBytes != 0)
+ {
+ hMacHash.BlockUpdate(currentT, 0, hashLen);
+ }
+ hMacHash.BlockUpdate(info, 0, info.Length);
+ hMacHash.Update((byte)n);
+ hMacHash.DoFinal(currentT, 0);
+ }
+
+ public virtual IDigest Digest
+ {
+ get { return hMacHash.GetUnderlyingDigest(); }
+ }
+
+ public virtual int GenerateBytes(byte[] output, int outOff, int len)
+ {
+ if (generatedBytes + len > 255 * hashLen)
+ {
+ throw new DataLengthException(
+ "HKDF may only be used for 255 * HashLen bytes of output");
+ }
+
+ if (generatedBytes % hashLen == 0)
+ {
+ ExpandNext();
+ }
+
+ // copy what is left in the currentT (1..hash
+ int toGenerate = len;
+ int posInT = generatedBytes % hashLen;
+ int leftInT = hashLen - generatedBytes % hashLen;
+ int toCopy = System.Math.Min(leftInT, toGenerate);
+ Array.Copy(currentT, posInT, output, outOff, toCopy);
+ generatedBytes += toCopy;
+ toGenerate -= toCopy;
+ outOff += toCopy;
+
+ while (toGenerate > 0)
+ {
+ ExpandNext();
+ toCopy = System.Math.Min(hashLen, toGenerate);
+ Array.Copy(currentT, 0, output, outOff, toCopy);
+ generatedBytes += toCopy;
+ toGenerate -= toCopy;
+ outOff += toCopy;
+ }
+
+ return len;
+ }
+ }
+}
diff --git a/crypto/src/crypto/generators/Pkcs12ParametersGenerator.cs b/crypto/src/crypto/generators/Pkcs12ParametersGenerator.cs
index cbbfd1b3b..85543a038 100644
--- a/crypto/src/crypto/generators/Pkcs12ParametersGenerator.cs
+++ b/crypto/src/crypto/generators/Pkcs12ParametersGenerator.cs
@@ -163,7 +163,6 @@ namespace Org.BouncyCastle.Crypto.Generators
* @param keySize the size of the key we want (in bits)
* @return a KeyParameter object.
*/
- [Obsolete("Use version with 'algorithm' parameter")]
public override ICipherParameters GenerateDerivedParameters(
int keySize)
{
@@ -194,7 +193,6 @@ namespace Org.BouncyCastle.Crypto.Generators
* @param ivSize the size of the iv we want (in bits)
* @return a ParametersWithIV object.
*/
- [Obsolete("Use version with 'algorithm' parameter")]
public override ICipherParameters GenerateDerivedParameters(
int keySize,
int ivSize)
diff --git a/crypto/src/crypto/generators/Pkcs5S1ParametersGenerator.cs b/crypto/src/crypto/generators/Pkcs5S1ParametersGenerator.cs
index 8586e1ca9..9b39a5f42 100644
--- a/crypto/src/crypto/generators/Pkcs5S1ParametersGenerator.cs
+++ b/crypto/src/crypto/generators/Pkcs5S1ParametersGenerator.cs
@@ -62,7 +62,6 @@ namespace Org.BouncyCastle.Crypto.Generators
* @return a KeyParameter object.
* @exception ArgumentException if the key length larger than the base hash size.
*/
- [Obsolete("Use version with 'algorithm' parameter")]
public override ICipherParameters GenerateDerivedParameters(
int keySize)
{
@@ -96,7 +95,6 @@ namespace Org.BouncyCastle.Crypto.Generators
* @return a ParametersWithIV object.
* @exception ArgumentException if keySize + ivSize is larger than the base hash size.
*/
- [Obsolete("Use version with 'algorithm' parameter")]
public override ICipherParameters GenerateDerivedParameters(
int keySize,
int ivSize)
diff --git a/crypto/src/crypto/generators/Pkcs5S2ParametersGenerator.cs b/crypto/src/crypto/generators/Pkcs5S2ParametersGenerator.cs
index 10352abbc..0b0caa057 100644
--- a/crypto/src/crypto/generators/Pkcs5S2ParametersGenerator.cs
+++ b/crypto/src/crypto/generators/Pkcs5S2ParametersGenerator.cs
@@ -106,7 +106,6 @@ namespace Org.BouncyCastle.Crypto.Generators
* @param keySize the size of the key we want (in bits)
* @return a KeyParameter object.
*/
- [Obsolete("Use version with 'algorithm' parameter")]
public override ICipherParameters GenerateDerivedParameters(
int keySize)
{
@@ -133,7 +132,6 @@ namespace Org.BouncyCastle.Crypto.Generators
* @param ivSize the size of the iv we want (in bits)
* @return a ParametersWithIV object.
*/
- [Obsolete("Use version with 'algorithm' parameter")]
public override ICipherParameters GenerateDerivedParameters(
int keySize,
int ivSize)
diff --git a/crypto/src/crypto/generators/Poly1305KeyGenerator.cs b/crypto/src/crypto/generators/Poly1305KeyGenerator.cs
index d05af0add..cdb24bfa0 100644
--- a/crypto/src/crypto/generators/Poly1305KeyGenerator.cs
+++ b/crypto/src/crypto/generators/Poly1305KeyGenerator.cs
@@ -66,51 +66,25 @@ namespace Org.BouncyCastle.Crypto.Generators
* Key is k[0] ... k[15], r[0] ... r[15] as per poly1305_aes_clamp in ref impl.
*/
if (key.Length != 32)
- {
throw new ArgumentException("Poly1305 key must be 256 bits.");
- }
- /*
+ /*
* r[3], r[7], r[11], r[15] have top four bits clear (i.e., are {0, 1, . . . , 15})
*/
- key[19] &= R_MASK_HIGH_4;
- key[23] &= R_MASK_HIGH_4;
- key[27] &= R_MASK_HIGH_4;
- key[31] &= R_MASK_HIGH_4;
+ key[3] &= R_MASK_HIGH_4;
+ key[7] &= R_MASK_HIGH_4;
+ key[11] &= R_MASK_HIGH_4;
+ key[15] &= R_MASK_HIGH_4;
/*
* r[4], r[8], r[12] have bottom two bits clear (i.e., are in {0, 4, 8, . . . , 252}).
*/
- key[20] &= R_MASK_LOW_2;
- key[24] &= R_MASK_LOW_2;
- key[28] &= R_MASK_LOW_2;
+ key[4] &= R_MASK_LOW_2;
+ key[8] &= R_MASK_LOW_2;
+ key[12] &= R_MASK_LOW_2;
}
- internal static void Clamp(byte[] key, int keyOff)
- {
- /*
- * Key is k[0] ... k[15], r[0] ... r[15] as per poly1305_aes_clamp in ref impl.
- */
- if (key.Length - 32 < keyOff)
- throw new ArgumentException("Poly1305 key must be 256 bits.");
-
- /*
- * r[3], r[7], r[11], r[15] have top four bits clear (i.e., are {0, 1, . . . , 15})
- */
- key[keyOff + 19] &= R_MASK_HIGH_4;
- key[keyOff + 23] &= R_MASK_HIGH_4;
- key[keyOff + 27] &= R_MASK_HIGH_4;
- key[keyOff + 31] &= R_MASK_HIGH_4;
-
- /*
- * r[4], r[8], r[12] have bottom two bits clear (i.e., are in {0, 4, 8, . . . , 252}).
- */
- key[keyOff + 20] &= R_MASK_LOW_2;
- key[keyOff + 24] &= R_MASK_LOW_2;
- key[keyOff + 28] &= R_MASK_LOW_2;
- }
-
- /// <summary>
+ /// <summary>
/// Checks a 32 byte key for compliance with the Poly1305 key requirements, e.g.
/// <code>k[0] ... k[15], r[0] ... r[15]</code> with the required bits in <code>r</code> cleared
/// as per <see cref="Clamp(byte[])"/>.
@@ -121,27 +95,22 @@ namespace Org.BouncyCastle.Crypto.Generators
public static void CheckKey(byte[] key)
{
if (key.Length != 32)
- {
throw new ArgumentException("Poly1305 key must be 256 bits.");
- }
- checkMask(key[19], R_MASK_HIGH_4);
- checkMask(key[23], R_MASK_HIGH_4);
- checkMask(key[27], R_MASK_HIGH_4);
- checkMask(key[31], R_MASK_HIGH_4);
+ CheckMask(key[3], R_MASK_HIGH_4);
+ CheckMask(key[7], R_MASK_HIGH_4);
+ CheckMask(key[11], R_MASK_HIGH_4);
+ CheckMask(key[15], R_MASK_HIGH_4);
- checkMask(key[20], R_MASK_LOW_2);
- checkMask(key[24], R_MASK_LOW_2);
- checkMask(key[28], R_MASK_LOW_2);
+ CheckMask(key[4], R_MASK_LOW_2);
+ CheckMask(key[8], R_MASK_LOW_2);
+ CheckMask(key[12], R_MASK_LOW_2);
}
- private static void checkMask(byte b, byte mask)
+ private static void CheckMask(byte b, byte mask)
{
if ((b & (~mask)) != 0)
- {
throw new ArgumentException("Invalid format for r portion of Poly1305 key.");
- }
}
-
}
}
\ No newline at end of file
diff --git a/crypto/src/crypto/macs/Poly1305.cs b/crypto/src/crypto/macs/Poly1305.cs
index 1a951ca04..0f66ccccc 100644
--- a/crypto/src/crypto/macs/Poly1305.cs
+++ b/crypto/src/crypto/macs/Poly1305.cs
@@ -23,7 +23,7 @@ namespace Org.BouncyCastle.Crypto.Macs
public class Poly1305
: IMac
{
- private const int BLOCK_SIZE = 16;
+ private const int BlockSize = 16;
private readonly IBlockCipher cipher;
@@ -43,7 +43,7 @@ namespace Org.BouncyCastle.Crypto.Macs
// Accumulating state
/** Current block of buffered input */
- private byte[] currentBlock = new byte[BLOCK_SIZE];
+ private byte[] currentBlock = new byte[BlockSize];
/** Current offset in input buffer */
private int currentBlockOffset = 0;
@@ -64,7 +64,7 @@ namespace Org.BouncyCastle.Crypto.Macs
*/
public Poly1305(IBlockCipher cipher)
{
- if (cipher.GetBlockSize() != BLOCK_SIZE)
+ if (cipher.GetBlockSize() != BlockSize)
{
throw new ArgumentException("Poly1305 requires a 128 bit block cipher.");
}
@@ -102,22 +102,24 @@ namespace Org.BouncyCastle.Crypto.Macs
private void SetKey(byte[] key, byte[] nonce)
{
- if (cipher != null && (nonce == null || nonce.Length != BLOCK_SIZE))
- throw new ArgumentException("Poly1305 requires a 128 bit IV.");
+ if (key.Length != 32)
+ throw new ArgumentException("Poly1305 key must be 256 bits.");
- Poly1305KeyGenerator.CheckKey(key);
+ if (cipher != null && (nonce == null || nonce.Length != BlockSize))
+ throw new ArgumentException("Poly1305 requires a 128 bit IV.");
- // Extract r portion of key
- uint t0 = Pack.LE_To_UInt32(key, BLOCK_SIZE + 0);
- uint t1 = Pack.LE_To_UInt32(key, BLOCK_SIZE + 4);
- uint t2 = Pack.LE_To_UInt32(key, BLOCK_SIZE + 8);
- uint t3 = Pack.LE_To_UInt32(key, BLOCK_SIZE + 12);
+ // Extract r portion of key (and "clamp" the values)
+ uint t0 = Pack.LE_To_UInt32(key, 0);
+ uint t1 = Pack.LE_To_UInt32(key, 4);
+ uint t2 = Pack.LE_To_UInt32(key, 8);
+ uint t3 = Pack.LE_To_UInt32(key, 12);
- r0 = t0 & 0x3ffffff; t0 >>= 26; t0 |= t1 << 6;
- r1 = t0 & 0x3ffff03; t1 >>= 20; t1 |= t2 << 12;
- r2 = t1 & 0x3ffc0ff; t2 >>= 14; t2 |= t3 << 18;
- r3 = t2 & 0x3f03fff; t3 >>= 8;
- r4 = t3 & 0x00fffff;
+ // NOTE: The masks perform the key "clamping" implicitly
+ r0 = t0 & 0x03FFFFFFU;
+ r1 = ((t0 >> 26) | (t1 << 6)) & 0x03FFFF03U;
+ r2 = ((t1 >> 20) | (t2 << 12)) & 0x03FFC0FFU;
+ r3 = ((t2 >> 14) | (t3 << 18)) & 0x03F03FFFU;
+ r4 = (t3 >> 8) & 0x000FFFFFU;
// Precompute multipliers
s1 = r1 * 5;
@@ -126,22 +128,27 @@ namespace Org.BouncyCastle.Crypto.Macs
s4 = r4 * 5;
byte[] kBytes;
+ int kOff;
+
if (cipher == null)
{
kBytes = key;
+ kOff = BlockSize;
}
else
{
// Compute encrypted nonce
- kBytes = new byte[BLOCK_SIZE];
- cipher.Init(true, new KeyParameter(key, 0, BLOCK_SIZE));
+ kBytes = new byte[BlockSize];
+ kOff = 0;
+
+ cipher.Init(true, new KeyParameter(key, BlockSize, BlockSize));
cipher.ProcessBlock(nonce, 0, kBytes, 0);
}
- k0 = Pack.LE_To_UInt32(kBytes, 0);
- k1 = Pack.LE_To_UInt32(kBytes, 4);
- k2 = Pack.LE_To_UInt32(kBytes, 8);
- k3 = Pack.LE_To_UInt32(kBytes, 12);
+ k0 = Pack.LE_To_UInt32(kBytes, kOff + 0);
+ k1 = Pack.LE_To_UInt32(kBytes, kOff + 4);
+ k2 = Pack.LE_To_UInt32(kBytes, kOff + 8);
+ k3 = Pack.LE_To_UInt32(kBytes, kOff + 12);
}
public string AlgorithmName
@@ -151,7 +158,7 @@ namespace Org.BouncyCastle.Crypto.Macs
public int GetMacSize()
{
- return BLOCK_SIZE;
+ return BlockSize;
}
public void Update(byte input)
@@ -165,13 +172,13 @@ namespace Org.BouncyCastle.Crypto.Macs
int copied = 0;
while (len > copied)
{
- if (currentBlockOffset == BLOCK_SIZE)
+ if (currentBlockOffset == BlockSize)
{
- processBlock();
+ ProcessBlock();
currentBlockOffset = 0;
}
- int toCopy = System.Math.Min((len - copied), BLOCK_SIZE - currentBlockOffset);
+ int toCopy = System.Math.Min((len - copied), BlockSize - currentBlockOffset);
Array.Copy(input, copied + inOff, currentBlock, currentBlockOffset, toCopy);
copied += toCopy;
currentBlockOffset += toCopy;
@@ -179,12 +186,12 @@ namespace Org.BouncyCastle.Crypto.Macs
}
- private void processBlock()
+ private void ProcessBlock()
{
- if (currentBlockOffset < BLOCK_SIZE)
+ if (currentBlockOffset < BlockSize)
{
currentBlock[currentBlockOffset] = 1;
- for (int i = currentBlockOffset + 1; i < BLOCK_SIZE; i++)
+ for (int i = currentBlockOffset + 1; i < BlockSize; i++)
{
currentBlock[i] = 0;
}
@@ -201,7 +208,7 @@ namespace Org.BouncyCastle.Crypto.Macs
h3 += (uint)((((t3 << 32) | t2) >> 14) & 0x3ffffff);
h4 += (uint)(t3 >> 8);
- if (currentBlockOffset == BLOCK_SIZE)
+ if (currentBlockOffset == BlockSize)
{
h4 += (1 << 24);
}
@@ -223,15 +230,12 @@ namespace Org.BouncyCastle.Crypto.Macs
public int DoFinal(byte[] output, int outOff)
{
- if (outOff + BLOCK_SIZE > output.Length)
- {
- throw new DataLengthException("Output buffer is too short.");
- }
+ Check.DataLength(output, outOff, BlockSize, "Output buffer is too short.");
if (currentBlockOffset > 0)
{
// Process padded block
- processBlock();
+ ProcessBlock();
}
ulong f0, f1, f2, f3;
@@ -273,7 +277,7 @@ namespace Org.BouncyCastle.Crypto.Macs
Pack.UInt32_To_LE((uint)f3, output, outOff + 12);
Reset();
- return BLOCK_SIZE;
+ return BlockSize;
}
public void Reset()
diff --git a/crypto/src/crypto/parameters/DHParameters.cs b/crypto/src/crypto/parameters/DHParameters.cs
index 4258df5c5..bdea12432 100644
--- a/crypto/src/crypto/parameters/DHParameters.cs
+++ b/crypto/src/crypto/parameters/DHParameters.cs
@@ -162,7 +162,7 @@ namespace Org.BouncyCastle.Crypto.Parameters
return Equals(other);
}
- protected bool Equals(
+ protected virtual bool Equals(
DHParameters other)
{
return p.Equals(other.p)
diff --git a/crypto/src/crypto/parameters/ECDomainParameters.cs b/crypto/src/crypto/parameters/ECDomainParameters.cs
index 619971a6c..732fbdfa4 100644
--- a/crypto/src/crypto/parameters/ECDomainParameters.cs
+++ b/crypto/src/crypto/parameters/ECDomainParameters.cs
@@ -93,24 +93,25 @@ namespace Org.BouncyCastle.Crypto.Parameters
return Equals(other);
}
- protected bool Equals(
+ protected virtual bool Equals(
ECDomainParameters other)
{
return curve.Equals(other.curve)
&& g.Equals(other.g)
&& n.Equals(other.n)
- && h.Equals(other.h)
- && Arrays.AreEqual(seed, other.seed);
+ && h.Equals(other.h);
}
public override int GetHashCode()
{
- return curve.GetHashCode()
- ^ g.GetHashCode()
- ^ n.GetHashCode()
- ^ h.GetHashCode()
- ^ Arrays.GetHashCode(seed);
+ int hc = curve.GetHashCode();
+ hc *= 37;
+ hc ^= g.GetHashCode();
+ hc *= 37;
+ hc ^= n.GetHashCode();
+ hc *= 37;
+ hc ^= h.GetHashCode();
+ return hc;
}
}
-
}
diff --git a/crypto/src/crypto/parameters/HKDFParameters.cs b/crypto/src/crypto/parameters/HKDFParameters.cs
new file mode 100644
index 000000000..6d1465e4c
--- /dev/null
+++ b/crypto/src/crypto/parameters/HKDFParameters.cs
@@ -0,0 +1,119 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ /**
+ * Parameter class for the HkdfBytesGenerator class.
+ */
+ public class HkdfParameters
+ : IDerivationParameters
+ {
+ private readonly byte[] ikm;
+ private readonly bool skipExpand;
+ private readonly byte[] salt;
+ private readonly byte[] info;
+
+ private HkdfParameters(byte[] ikm, bool skip, byte[] salt, byte[] info)
+ {
+ if (ikm == null)
+ throw new ArgumentNullException("ikm");
+
+ this.ikm = Arrays.Clone(ikm);
+ this.skipExpand = skip;
+
+ if (salt == null || salt.Length == 0)
+ {
+ this.salt = null;
+ }
+ else
+ {
+ this.salt = Arrays.Clone(salt);
+ }
+
+ if (info == null)
+ {
+ this.info = new byte[0];
+ }
+ else
+ {
+ this.info = Arrays.Clone(info);
+ }
+ }
+
+ /**
+ * Generates parameters for HKDF, specifying both the optional salt and
+ * optional info. Step 1: Extract won't be skipped.
+ *
+ * @param ikm the input keying material or seed
+ * @param salt the salt to use, may be null for a salt for hashLen zeros
+ * @param info the info to use, may be null for an info field of zero bytes
+ */
+ public HkdfParameters(byte[] ikm, byte[] salt, byte[] info)
+ : this(ikm, false, salt, info)
+ {
+ }
+
+ /**
+ * Factory method that makes the HKDF skip the extract part of the key
+ * derivation function.
+ *
+ * @param ikm the input keying material or seed, directly used for step 2:
+ * Expand
+ * @param info the info to use, may be null for an info field of zero bytes
+ * @return HKDFParameters that makes the implementation skip step 1
+ */
+ public static HkdfParameters SkipExtractParameters(byte[] ikm, byte[] info)
+ {
+ return new HkdfParameters(ikm, true, null, info);
+ }
+
+ public static HkdfParameters DefaultParameters(byte[] ikm)
+ {
+ return new HkdfParameters(ikm, false, null, null);
+ }
+
+ /**
+ * Returns the input keying material or seed.
+ *
+ * @return the keying material
+ */
+ public virtual byte[] GetIkm()
+ {
+ return Arrays.Clone(ikm);
+ }
+
+ /**
+ * Returns if step 1: extract has to be skipped or not
+ *
+ * @return true for skipping, false for no skipping of step 1
+ */
+ public virtual bool SkipExtract
+ {
+ get { return skipExpand; }
+ }
+
+ /**
+ * Returns the salt, or null if the salt should be generated as a byte array
+ * of HashLen zeros.
+ *
+ * @return the salt, or null
+ */
+ public virtual byte[] GetSalt()
+ {
+ return Arrays.Clone(salt);
+ }
+
+ /**
+ * Returns the info field, which may be empty (null is converted to empty).
+ *
+ * @return the info field, never null
+ */
+ public virtual byte[] GetInfo()
+ {
+ return Arrays.Clone(info);
+ }
+ }
+}
diff --git a/crypto/src/crypto/parameters/MqvPrivateParameters.cs b/crypto/src/crypto/parameters/MqvPrivateParameters.cs
index 4bf33e347..9159cac12 100644
--- a/crypto/src/crypto/parameters/MqvPrivateParameters.cs
+++ b/crypto/src/crypto/parameters/MqvPrivateParameters.cs
@@ -21,22 +21,42 @@ namespace Org.BouncyCastle.Crypto.Parameters
ECPrivateKeyParameters ephemeralPrivateKey,
ECPublicKeyParameters ephemeralPublicKey)
{
- this.staticPrivateKey = staticPrivateKey;
- this.ephemeralPrivateKey = ephemeralPrivateKey;
- this.ephemeralPublicKey = ephemeralPublicKey;
+ if (staticPrivateKey == null)
+ throw new ArgumentNullException("staticPrivateKey");
+ if (ephemeralPrivateKey == null)
+ throw new ArgumentNullException("ephemeralPrivateKey");
+
+ ECDomainParameters parameters = staticPrivateKey.Parameters;
+ if (!parameters.Equals(ephemeralPrivateKey.Parameters))
+ throw new ArgumentException("Static and ephemeral private keys have different domain parameters");
+
+ if (ephemeralPublicKey == null)
+ {
+ ephemeralPublicKey = new ECPublicKeyParameters(
+ parameters.G.Multiply(ephemeralPrivateKey.D),
+ parameters);
+ }
+ else if (!parameters.Equals(ephemeralPublicKey.Parameters))
+ {
+ throw new ArgumentException("Ephemeral public key has different domain parameters");
+ }
+
+ this.staticPrivateKey = staticPrivateKey;
+ this.ephemeralPrivateKey = ephemeralPrivateKey;
+ this.ephemeralPublicKey = ephemeralPublicKey;
}
- public ECPrivateKeyParameters StaticPrivateKey
+ public virtual ECPrivateKeyParameters StaticPrivateKey
{
get { return staticPrivateKey; }
}
- public ECPrivateKeyParameters EphemeralPrivateKey
+ public virtual ECPrivateKeyParameters EphemeralPrivateKey
{
get { return ephemeralPrivateKey; }
}
- public ECPublicKeyParameters EphemeralPublicKey
+ public virtual ECPublicKeyParameters EphemeralPublicKey
{
get { return ephemeralPublicKey; }
}
diff --git a/crypto/src/crypto/parameters/MqvPublicParameters.cs b/crypto/src/crypto/parameters/MqvPublicParameters.cs
index a0e273ac4..239afa321 100644
--- a/crypto/src/crypto/parameters/MqvPublicParameters.cs
+++ b/crypto/src/crypto/parameters/MqvPublicParameters.cs
@@ -8,20 +8,27 @@ namespace Org.BouncyCastle.Crypto.Parameters
private readonly ECPublicKeyParameters staticPublicKey;
private readonly ECPublicKeyParameters ephemeralPublicKey;
- public MqvPublicParameters(
+ public MqvPublicParameters(
ECPublicKeyParameters staticPublicKey,
ECPublicKeyParameters ephemeralPublicKey)
{
- this.staticPublicKey = staticPublicKey;
+ if (staticPublicKey == null)
+ throw new ArgumentNullException("staticPublicKey");
+ if (ephemeralPublicKey == null)
+ throw new ArgumentNullException("ephemeralPublicKey");
+ if (!staticPublicKey.Parameters.Equals(ephemeralPublicKey.Parameters))
+ throw new ArgumentException("Static and ephemeral public keys have different domain parameters");
+
+ this.staticPublicKey = staticPublicKey;
this.ephemeralPublicKey = ephemeralPublicKey;
- }
+ }
- public ECPublicKeyParameters StaticPublicKey
+ public virtual ECPublicKeyParameters StaticPublicKey
{
get { return staticPublicKey; }
}
- public ECPublicKeyParameters EphemeralPublicKey
+ public virtual ECPublicKeyParameters EphemeralPublicKey
{
get { return ephemeralPublicKey; }
}
diff --git a/crypto/src/crypto/tls/CertificateType.cs b/crypto/src/crypto/tls/CertificateType.cs
new file mode 100644
index 000000000..47ec05c80
--- /dev/null
+++ b/crypto/src/crypto/tls/CertificateType.cs
@@ -0,0 +1,18 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /**
+ * RFC 6091
+ */
+ public class CertificateType
+ {
+ public const byte X509 = 0;
+ public const byte OpenPGP = 1;
+
+ /*
+ * RFC 7250
+ */
+ public const byte RawPublicKey = 2;
+ }
+}
diff --git a/crypto/src/crypto/tls/Chacha20Poly1305.cs b/crypto/src/crypto/tls/Chacha20Poly1305.cs
index 817e64b25..8687803b4 100644
--- a/crypto/src/crypto/tls/Chacha20Poly1305.cs
+++ b/crypto/src/crypto/tls/Chacha20Poly1305.cs
@@ -145,10 +145,7 @@ namespace Org.BouncyCastle.Crypto.Tls
byte[] firstBlock = new byte[64];
cipher.ProcessBytes(firstBlock, 0, firstBlock.Length, firstBlock, 0);
- // NOTE: The BC implementation puts 'r' after 'k'
- Array.Copy(firstBlock, 0, firstBlock, 32, 16);
- Poly1305KeyGenerator.Clamp(firstBlock, 16);
- KeyParameter macKey = new KeyParameter(firstBlock, 16, 32);
+ KeyParameter macKey = new KeyParameter(firstBlock, 0, 32);
Arrays.Fill(firstBlock, (byte)0);
return macKey;
}
diff --git a/crypto/src/crypto/tls/CipherSuite.cs b/crypto/src/crypto/tls/CipherSuite.cs
index 265174341..679a8be85 100644
--- a/crypto/src/crypto/tls/CipherSuite.cs
+++ b/crypto/src/crypto/tls/CipherSuite.cs
@@ -347,7 +347,7 @@ namespace Org.BouncyCastle.Crypto.Tls
public const int DRAFT_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256 = 0xCCAE;
/*
- * draft-zauner-tls-aes-ocb-03 (code points TBD)
+ * draft-zauner-tls-aes-ocb-04 (code points TBD)
*/
public const int DRAFT_TLS_DHE_RSA_WITH_AES_128_OCB = 0xFF00;
public const int DRAFT_TLS_DHE_RSA_WITH_AES_256_OCB = 0xFF01;
diff --git a/crypto/src/crypto/tls/DefaultTlsCipherFactory.cs b/crypto/src/crypto/tls/DefaultTlsCipherFactory.cs
index 1e03ec3a8..af0ec126a 100644
--- a/crypto/src/crypto/tls/DefaultTlsCipherFactory.cs
+++ b/crypto/src/crypto/tls/DefaultTlsCipherFactory.cs
@@ -107,7 +107,7 @@ namespace Org.BouncyCastle.Crypto.Tls
protected virtual TlsAeadCipher CreateCipher_Aes_Ocb(TlsContext context, int cipherKeySize, int macSize)
{
return new TlsAeadCipher(context, CreateAeadBlockCipher_Aes_Ocb(),
- CreateAeadBlockCipher_Aes_Ocb(), cipherKeySize, macSize, TlsAeadCipher.NONCE_DRAFT_ZAUNER_TLS_AES_OCB);
+ CreateAeadBlockCipher_Aes_Ocb(), cipherKeySize, macSize, TlsAeadCipher.NONCE_DRAFT_CHACHA20_POLY1305);
}
/// <exception cref="IOException"></exception>
diff --git a/crypto/src/crypto/tls/DtlsClientProtocol.cs b/crypto/src/crypto/tls/DtlsClientProtocol.cs
index abb402077..90430d772 100644
--- a/crypto/src/crypto/tls/DtlsClientProtocol.cs
+++ b/crypto/src/crypto/tls/DtlsClientProtocol.cs
@@ -53,19 +53,29 @@ namespace Org.BouncyCastle.Crypto.Tls
}
catch (TlsFatalAlert fatalAlert)
{
- recordLayer.Fail(fatalAlert.AlertDescription);
+ AbortClientHandshake(state, recordLayer, fatalAlert.AlertDescription);
throw fatalAlert;
}
catch (IOException e)
{
- recordLayer.Fail(AlertDescription.internal_error);
+ AbortClientHandshake(state, recordLayer, AlertDescription.internal_error);
throw e;
}
catch (Exception e)
{
- recordLayer.Fail(AlertDescription.internal_error);
+ AbortClientHandshake(state, recordLayer, AlertDescription.internal_error);
throw new TlsFatalAlert(AlertDescription.internal_error, e);
}
+ finally
+ {
+ securityParameters.Clear();
+ }
+ }
+
+ internal virtual void AbortClientHandshake(ClientHandshakeState state, DtlsRecordLayer recordLayer, byte alertDescription)
+ {
+ recordLayer.Fail(alertDescription);
+ InvalidateSession(state);
}
internal virtual DtlsTransport ClientHandshake(ClientHandshakeState state, DtlsRecordLayer recordLayer)
diff --git a/crypto/src/crypto/tls/DtlsRecordLayer.cs b/crypto/src/crypto/tls/DtlsRecordLayer.cs
index 6796f4cbb..4a781b5b5 100644
--- a/crypto/src/crypto/tls/DtlsRecordLayer.cs
+++ b/crypto/src/crypto/tls/DtlsRecordLayer.cs
@@ -237,7 +237,7 @@ namespace Org.BouncyCastle.Crypto.Tls
if (alertLevel == AlertLevel.fatal)
{
- Fail(alertDescription);
+ Failed();
throw new TlsFatalAlert(alertDescription);
}
@@ -375,6 +375,16 @@ namespace Org.BouncyCastle.Crypto.Tls
}
}
+ internal virtual void Failed()
+ {
+ if (!mClosed)
+ {
+ mFailed = true;
+
+ CloseTransport();
+ }
+ }
+
internal virtual void Fail(byte alertDescription)
{
if (!mClosed)
diff --git a/crypto/src/crypto/tls/DtlsServerProtocol.cs b/crypto/src/crypto/tls/DtlsServerProtocol.cs
index d05af193c..fbf33045b 100644
--- a/crypto/src/crypto/tls/DtlsServerProtocol.cs
+++ b/crypto/src/crypto/tls/DtlsServerProtocol.cs
@@ -54,19 +54,29 @@ namespace Org.BouncyCastle.Crypto.Tls
}
catch (TlsFatalAlert fatalAlert)
{
- recordLayer.Fail(fatalAlert.AlertDescription);
+ AbortServerHandshake(state, recordLayer, fatalAlert.AlertDescription);
throw fatalAlert;
}
catch (IOException e)
{
- recordLayer.Fail(AlertDescription.internal_error);
+ AbortServerHandshake(state, recordLayer, AlertDescription.internal_error);
throw e;
}
catch (Exception e)
{
- recordLayer.Fail(AlertDescription.internal_error);
+ AbortServerHandshake(state, recordLayer, AlertDescription.internal_error);
throw new TlsFatalAlert(AlertDescription.internal_error, e);
}
+ finally
+ {
+ securityParameters.Clear();
+ }
+ }
+
+ internal virtual void AbortServerHandshake(ServerHandshakeState state, DtlsRecordLayer recordLayer, byte alertDescription)
+ {
+ recordLayer.Fail(alertDescription);
+ InvalidateSession(state);
}
internal virtual DtlsTransport ServerHandshake(ServerHandshakeState state, DtlsRecordLayer recordLayer)
@@ -263,6 +273,21 @@ namespace Org.BouncyCastle.Crypto.Tls
return new DtlsTransport(recordLayer);
}
+ protected virtual void InvalidateSession(ServerHandshakeState state)
+ {
+ if (state.sessionParameters != null)
+ {
+ state.sessionParameters.Clear();
+ state.sessionParameters = null;
+ }
+
+ if (state.tlsSession != null)
+ {
+ state.tlsSession.Invalidate();
+ state.tlsSession = null;
+ }
+ }
+
protected virtual byte[] GenerateCertificateRequest(ServerHandshakeState state, CertificateRequest certificateRequest)
{
MemoryStream buf = new MemoryStream();
@@ -650,6 +675,9 @@ namespace Org.BouncyCastle.Crypto.Tls
{
internal TlsServer server = null;
internal TlsServerContextImpl serverContext = null;
+ internal TlsSession tlsSession = null;
+ internal SessionParameters sessionParameters = null;
+ internal SessionParameters.Builder sessionParametersBuilder = null;
internal int[] offeredCipherSuites = null;
internal byte[] offeredCompressionMethods = null;
internal IDictionary clientExtensions = null;
diff --git a/crypto/src/crypto/tls/EncryptionAlgorithm.cs b/crypto/src/crypto/tls/EncryptionAlgorithm.cs
index 04c1733cb..96037ed20 100644
--- a/crypto/src/crypto/tls/EncryptionAlgorithm.cs
+++ b/crypto/src/crypto/tls/EncryptionAlgorithm.cs
@@ -62,7 +62,7 @@ namespace Org.BouncyCastle.Crypto.Tls
[Obsolete] public const int AEAD_CHACHA20_POLY1305 = CHACHA20_POLY1305;
/*
- * draft-zauner-tls-aes-ocb-03
+ * draft-zauner-tls-aes-ocb-04
*/
public const int AES_128_OCB_TAGLEN96 = 103;
public const int AES_256_OCB_TAGLEN96 = 104;
diff --git a/crypto/src/crypto/tls/NameType.cs b/crypto/src/crypto/tls/NameType.cs
index 25f6046fc..782164215 100644
--- a/crypto/src/crypto/tls/NameType.cs
+++ b/crypto/src/crypto/tls/NameType.cs
@@ -8,5 +8,10 @@ namespace Org.BouncyCastle.Crypto.Tls
* RFC 3546 3.1.
*/
public const byte host_name = 0;
+
+ public static bool IsValid(byte nameType)
+ {
+ return nameType == host_name;
+ }
}
}
diff --git a/crypto/src/crypto/tls/ServerNameList.cs b/crypto/src/crypto/tls/ServerNameList.cs
index 13da79bf6..5b5b90e58 100644
--- a/crypto/src/crypto/tls/ServerNameList.cs
+++ b/crypto/src/crypto/tls/ServerNameList.cs
@@ -15,8 +15,8 @@ namespace Org.BouncyCastle.Crypto.Tls
*/
public ServerNameList(IList serverNameList)
{
- if (serverNameList == null || serverNameList.Count < 1)
- throw new ArgumentException("must not be null or empty", "serverNameList");
+ if (serverNameList == null)
+ throw new ArgumentNullException("serverNameList");
this.mServerNameList = serverNameList;
}
@@ -40,8 +40,13 @@ namespace Org.BouncyCastle.Crypto.Tls
{
MemoryStream buf = new MemoryStream();
+ byte[] nameTypesSeen = TlsUtilities.EmptyBytes;
foreach (ServerName entry in ServerNames)
{
+ nameTypesSeen = CheckNameType(nameTypesSeen, entry.NameType);
+ if (nameTypesSeen == null)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
entry.Encode(buf);
}
@@ -68,14 +73,32 @@ namespace Org.BouncyCastle.Crypto.Tls
MemoryStream buf = new MemoryStream(data, false);
+ byte[] nameTypesSeen = TlsUtilities.EmptyBytes;
IList server_name_list = Platform.CreateArrayList();
while (buf.Position < buf.Length)
{
ServerName entry = ServerName.Parse(buf);
+
+ nameTypesSeen = CheckNameType(nameTypesSeen, entry.NameType);
+ if (nameTypesSeen == null)
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
server_name_list.Add(entry);
}
return new ServerNameList(server_name_list);
}
+
+ private static byte[] CheckNameType(byte[] nameTypesSeen, byte nameType)
+ {
+ /*
+ * RFC 6066 3. The ServerNameList MUST NOT contain more than one name of the same
+ * name_type.
+ */
+ if (!NameType.IsValid(nameType) || Arrays.Contains(nameTypesSeen, nameType))
+ return null;
+
+ return Arrays.Append(nameTypesSeen, nameType);
+ }
}
}
diff --git a/crypto/src/crypto/tls/TlsAeadCipher.cs b/crypto/src/crypto/tls/TlsAeadCipher.cs
index bff719db1..cc0575cf0 100644
--- a/crypto/src/crypto/tls/TlsAeadCipher.cs
+++ b/crypto/src/crypto/tls/TlsAeadCipher.cs
@@ -10,8 +10,14 @@ namespace Org.BouncyCastle.Crypto.Tls
public class TlsAeadCipher
: TlsCipher
{
+ // TODO[draft-zauner-tls-aes-ocb-04] Apply data volume limit described in section 8.4
+
public const int NONCE_RFC5288 = 1;
- internal const int NONCE_DRAFT_ZAUNER_TLS_AES_OCB = 2;
+
+ /*
+ * draft-zauner-tls-aes-ocb-04 specifies the nonce construction from draft-ietf-tls-chacha20-poly1305-04
+ */
+ internal const int NONCE_DRAFT_CHACHA20_POLY1305 = 2;
protected readonly TlsContext context;
protected readonly int macSize;
@@ -23,6 +29,8 @@ namespace Org.BouncyCastle.Crypto.Tls
protected readonly byte[] encryptImplicitNonce, decryptImplicitNonce;
+ protected readonly int nonceMode;
+
/// <exception cref="IOException"></exception>
public TlsAeadCipher(TlsContext context, IAeadBlockCipher clientWriteCipher, IAeadBlockCipher serverWriteCipher,
int cipherKeySize, int macSize)
@@ -37,12 +45,19 @@ namespace Org.BouncyCastle.Crypto.Tls
if (!TlsUtilities.IsTlsV12(context))
throw new TlsFatalAlert(AlertDescription.internal_error);
+ this.nonceMode = nonceMode;
+
+ // TODO SecurityParameters.fixed_iv_length
+ int fixed_iv_length;
+
switch (nonceMode)
{
case NONCE_RFC5288:
+ fixed_iv_length = 4;
this.record_iv_length = 8;
break;
- case NONCE_DRAFT_ZAUNER_TLS_AES_OCB:
+ case NONCE_DRAFT_CHACHA20_POLY1305:
+ fixed_iv_length = 12;
this.record_iv_length = 0;
break;
default:
@@ -52,9 +67,6 @@ namespace Org.BouncyCastle.Crypto.Tls
this.context = context;
this.macSize = macSize;
- // TODO SecurityParameters.fixed_iv_length
- int fixed_iv_length = 4;
-
int key_block_size = (2 * cipherKeySize) + (2 * fixed_iv_length);
byte[] key_block = TlsUtilities.CalculateKeyBlock(context, key_block_size);
@@ -93,7 +105,7 @@ namespace Org.BouncyCastle.Crypto.Tls
decryptKey = server_write_key;
}
- byte[] dummyNonce = new byte[fixed_iv_length + 8];
+ byte[] dummyNonce = new byte[fixed_iv_length + record_iv_length];
this.encryptCipher.Init(true, new AeadParameters(encryptKey, 8 * macSize, dummyNonce));
this.decryptCipher.Init(false, new AeadParameters(decryptKey, 8 * macSize, dummyNonce));
@@ -108,16 +120,25 @@ namespace Org.BouncyCastle.Crypto.Tls
/// <exception cref="IOException"></exception>
public virtual byte[] EncodePlaintext(long seqNo, byte type, byte[] plaintext, int offset, int len)
{
- byte[] nonce = new byte[this.encryptImplicitNonce.Length + 8];
- Array.Copy(encryptImplicitNonce, 0, nonce, 0, encryptImplicitNonce.Length);
+ byte[] nonce = new byte[encryptImplicitNonce.Length + record_iv_length];
- /*
- * RFC 5288/6655: The nonce_explicit MAY be the 64-bit sequence number.
- * draft-zauner-tls-aes-ocb-03: uses the sequence number (not included in message).
- *
- * (May need review for other AEAD ciphers).
- */
- TlsUtilities.WriteUint64(seqNo, nonce, encryptImplicitNonce.Length);
+ switch (nonceMode)
+ {
+ case NONCE_RFC5288:
+ Array.Copy(encryptImplicitNonce, 0, nonce, 0, encryptImplicitNonce.Length);
+ // RFC 5288/6655: The nonce_explicit MAY be the 64-bit sequence number.
+ TlsUtilities.WriteUint64(seqNo, nonce, encryptImplicitNonce.Length);
+ break;
+ case NONCE_DRAFT_CHACHA20_POLY1305:
+ TlsUtilities.WriteUint64(seqNo, nonce, nonce.Length - 8);
+ for (int i = 0; i < encryptImplicitNonce.Length; ++i)
+ {
+ nonce[i] ^= encryptImplicitNonce[i];
+ }
+ break;
+ default:
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
int plaintextOffset = offset;
int plaintextLength = len;
@@ -159,16 +180,23 @@ namespace Org.BouncyCastle.Crypto.Tls
if (GetPlaintextLimit(len) < 0)
throw new TlsFatalAlert(AlertDescription.decode_error);
- byte[] nonce = new byte[this.decryptImplicitNonce.Length + 8];
- Array.Copy(decryptImplicitNonce, 0, nonce, 0, decryptImplicitNonce.Length);
- //Array.Copy(ciphertext, offset, nonce, decryptImplicitNonce.Length, nonce_explicit_length);
- if (record_iv_length == 0)
- {
- TlsUtilities.WriteUint64(seqNo, nonce, decryptImplicitNonce.Length);
- }
- else
+ byte[] nonce = new byte[decryptImplicitNonce.Length + record_iv_length];
+
+ switch (nonceMode)
{
- Array.Copy(ciphertext, offset, nonce, nonce.Length - record_iv_length, record_iv_length);
+ case NONCE_RFC5288:
+ Array.Copy(decryptImplicitNonce, 0, nonce, 0, decryptImplicitNonce.Length);
+ Array.Copy(ciphertext, offset, nonce, nonce.Length - record_iv_length, record_iv_length);
+ break;
+ case NONCE_DRAFT_CHACHA20_POLY1305:
+ TlsUtilities.WriteUint64(seqNo, nonce, nonce.Length - 8);
+ for (int i = 0; i < decryptImplicitNonce.Length; ++i)
+ {
+ nonce[i] ^= decryptImplicitNonce[i];
+ }
+ break;
+ default:
+ throw new TlsFatalAlert(AlertDescription.internal_error);
}
int ciphertextOffset = offset + record_iv_length;
diff --git a/crypto/src/crypto/tls/TlsDHUtilities.cs b/crypto/src/crypto/tls/TlsDHUtilities.cs
index f94163c6a..7a44670fd 100644
--- a/crypto/src/crypto/tls/TlsDHUtilities.cs
+++ b/crypto/src/crypto/tls/TlsDHUtilities.cs
@@ -375,7 +375,7 @@ namespace Org.BouncyCastle.Crypto.Tls
case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
/*
- * draft-zauner-tls-aes-ocb-03
+ * draft-zauner-tls-aes-ocb-04
*/
case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_AES_128_OCB:
case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_AES_256_OCB:
@@ -391,7 +391,8 @@ namespace Org.BouncyCastle.Crypto.Tls
public static bool AreCompatibleParameters(DHParameters a, DHParameters b)
{
- return a.P.Equals(b.P) && a.G.Equals(b.G);
+ return a.P.Equals(b.P) && a.G.Equals(b.G)
+ && (a.Q == null || b.Q == null || a.Q.Equals(b.Q));
}
public static byte[] CalculateDHBasicAgreement(DHPublicKeyParameters publicKey,
diff --git a/crypto/src/crypto/tls/TlsEccUtilities.cs b/crypto/src/crypto/tls/TlsEccUtilities.cs
index 5a4c2b60e..a5c8fa910 100644
--- a/crypto/src/crypto/tls/TlsEccUtilities.cs
+++ b/crypto/src/crypto/tls/TlsEccUtilities.cs
@@ -261,7 +261,7 @@ namespace Org.BouncyCastle.Crypto.Tls
case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
/*
- * draft-zauner-tls-aes-ocb-03
+ * draft-zauner-tls-aes-ocb-04
*/
case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_128_OCB:
case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_256_OCB:
@@ -279,8 +279,7 @@ namespace Org.BouncyCastle.Crypto.Tls
public static bool AreOnSameCurve(ECDomainParameters a, ECDomainParameters b)
{
- // TODO Move to ECDomainParameters.Equals() or other utility method?
- return a.Curve.Equals(b.Curve) && a.G.Equals(b.G) && a.N.Equals(b.N) && a.H.Equals(b.H);
+ return a != null && a.Equals(b);
}
public static bool IsSupportedNamedCurve(int namedCurve)
diff --git a/crypto/src/crypto/tls/TlsProtocol.cs b/crypto/src/crypto/tls/TlsProtocol.cs
index df1c50f02..6d5c93f40 100644
--- a/crypto/src/crypto/tls/TlsProtocol.cs
+++ b/crypto/src/crypto/tls/TlsProtocol.cs
@@ -34,6 +34,13 @@ namespace Org.BouncyCastle.Crypto.Tls
protected const short CS_END = 16;
/*
+ * Different modes to handle the known IV weakness
+ */
+ protected const short ADS_MODE_1_Nsub1 = 0; // 1/n-1 record splitting
+ protected const short ADS_MODE_0_N = 1; // 0/n record splitting
+ protected const short ADS_MODE_0_N_FIRSTONLY = 2; // 0/n record splitting on first data fragment only
+
+ /*
* Queues for data from some protocols.
*/
private ByteQueue mApplicationDataQueue = new ByteQueue();
@@ -52,7 +59,8 @@ namespace Org.BouncyCastle.Crypto.Tls
private volatile bool mClosed = false;
private volatile bool mFailedWithError = false;
private volatile bool mAppDataReady = false;
- private volatile bool mSplitApplicationDataRecords = true;
+ private volatile bool mAppDataSplitEnabled = true;
+ private volatile int mAppDataSplitMode = ADS_MODE_1_Nsub1;
private byte[] mExpectedVerifyData = null;
protected TlsSession mTlsSession = null;
@@ -175,7 +183,7 @@ namespace Org.BouncyCastle.Crypto.Tls
{
this.mRecordStream.FinaliseHandshake();
- this.mSplitApplicationDataRecords = !TlsUtilities.IsTlsV11(Context);
+ this.mAppDataSplitEnabled = !TlsUtilities.IsTlsV11(Context);
/*
* If this was an initial handshake, we are now ready to send and receive application data.
@@ -556,16 +564,29 @@ namespace Org.BouncyCastle.Crypto.Tls
* NOTE: Actually, implementations appear to have settled on 1/n-1 record splitting.
*/
- if (this.mSplitApplicationDataRecords)
+ if (this.mAppDataSplitEnabled)
{
/*
* Protect against known IV attack!
*
* DO NOT REMOVE THIS CODE, EXCEPT YOU KNOW EXACTLY WHAT YOU ARE DOING HERE.
*/
- SafeWriteRecord(ContentType.application_data, buf, offset, 1);
- ++offset;
- --len;
+ switch (mAppDataSplitMode)
+ {
+ case ADS_MODE_0_N:
+ SafeWriteRecord(ContentType.application_data, TlsUtilities.EmptyBytes, 0, 0);
+ break;
+ case ADS_MODE_0_N_FIRSTONLY:
+ this.mAppDataSplitEnabled = false;
+ SafeWriteRecord(ContentType.application_data, TlsUtilities.EmptyBytes, 0, 0);
+ break;
+ case ADS_MODE_1_Nsub1:
+ default:
+ SafeWriteRecord(ContentType.application_data, buf, offset, 1);
+ ++offset;
+ --len;
+ break;
+ }
}
if (len > 0)
@@ -579,6 +600,14 @@ namespace Org.BouncyCastle.Crypto.Tls
}
}
+ protected virtual void SetAppDataSplitMode(int appDataSplitMode)
+ {
+ if (appDataSplitMode < ADS_MODE_1_Nsub1 || appDataSplitMode > ADS_MODE_0_N_FIRSTONLY)
+ throw new ArgumentException("Illegal appDataSplitMode mode: " + appDataSplitMode, "appDataSplitMode");
+
+ this.mAppDataSplitMode = appDataSplitMode;
+ }
+
protected virtual void WriteHandshakeMessage(byte[] buf, int off, int len)
{
while (len > 0)
@@ -1086,20 +1115,32 @@ namespace Org.BouncyCastle.Crypto.Tls
{
MemoryStream buf = new MemoryStream();
- foreach (int extension_type in extensions.Keys)
- {
- byte[] extension_data = (byte[])extensions[extension_type];
-
- TlsUtilities.CheckUint16(extension_type);
- TlsUtilities.WriteUint16(extension_type, buf);
- TlsUtilities.WriteOpaque16(extension_data, buf);
- }
+ /*
+ * NOTE: There are reports of servers that don't accept a zero-length extension as the last
+ * one, so we write out any zero-length ones first as a best-effort workaround.
+ */
+ WriteSelectedExtensions(buf, extensions, true);
+ WriteSelectedExtensions(buf, extensions, false);
byte[] extBytes = buf.ToArray();
TlsUtilities.WriteOpaque16(extBytes, output);
}
+ protected internal static void WriteSelectedExtensions(Stream output, IDictionary extensions, bool selectEmpty)
+ {
+ foreach (int extension_type in extensions.Keys)
+ {
+ byte[] extension_data = (byte[])extensions[extension_type];
+ if (selectEmpty == (extension_data.Length == 0))
+ {
+ TlsUtilities.CheckUint16(extension_type);
+ TlsUtilities.WriteUint16(extension_type, output);
+ TlsUtilities.WriteOpaque16(extension_data, output);
+ }
+ }
+ }
+
protected internal static void WriteSupplementalData(Stream output, IList supplementalData)
{
MemoryStream buf = new MemoryStream();
diff --git a/crypto/src/crypto/tls/TlsUtilities.cs b/crypto/src/crypto/tls/TlsUtilities.cs
index 25908d163..d51a8ff48 100644
--- a/crypto/src/crypto/tls/TlsUtilities.cs
+++ b/crypto/src/crypto/tls/TlsUtilities.cs
@@ -1246,6 +1246,7 @@ namespace Org.BouncyCastle.Crypto.Tls
case EncryptionAlgorithm.SEED_CBC:
return CipherType.block;
+ case EncryptionAlgorithm.NULL:
case EncryptionAlgorithm.RC4_40:
case EncryptionAlgorithm.RC4_128:
return CipherType.stream;
diff --git a/crypto/src/math/ec/multiplier/WNafUtilities.cs b/crypto/src/math/ec/multiplier/WNafUtilities.cs
index 5491297d7..7d565dfbd 100644
--- a/crypto/src/math/ec/multiplier/WNafUtilities.cs
+++ b/crypto/src/math/ec/multiplier/WNafUtilities.cs
@@ -423,7 +423,7 @@ namespace Org.BouncyCastle.Math.EC.Multiplier
* 1) additions do not use the curve's A, B coefficients.
* 2) no special cases (i.e. Q +/- Q) when calculating 1P, 3P, 5P, ...
*/
- if (ECAlgorithms.IsFpCurve(c) && c.FieldSize >= 64)
+ if (!twiceP.IsInfinity && ECAlgorithms.IsFpCurve(c) && c.FieldSize >= 64)
{
switch (c.CoordinateSystem)
{
diff --git a/crypto/src/math/raw/Nat128.cs b/crypto/src/math/raw/Nat128.cs
index 819c52062..1d3b64d32 100644
--- a/crypto/src/math/raw/Nat128.cs
+++ b/crypto/src/math/raw/Nat128.cs
@@ -626,8 +626,8 @@ namespace Org.BouncyCastle.Math.Raw
}
ulong x_3 = x[3];
- ulong zz_5 = zz[5];
- ulong zz_6 = zz[6];
+ ulong zz_5 = zz[5] + (zz_4 >> 32); zz_4 &= M;
+ ulong zz_6 = zz[6] + (zz_5 >> 32); zz_5 &= M;
{
zz_3 += x_3 * x_0;
w = (uint)zz_3;
@@ -702,8 +702,8 @@ namespace Org.BouncyCastle.Math.Raw
}
ulong x_3 = x[xOff + 3];
- ulong zz_5 = zz[zzOff + 5];
- ulong zz_6 = zz[zzOff + 6];
+ ulong zz_5 = zz[zzOff + 5] + (zz_4 >> 32); zz_4 &= M;
+ ulong zz_6 = zz[zzOff + 6] + (zz_5 >> 32); zz_5 &= M;
{
zz_3 += x_3 * x_0;
w = (uint)zz_3;
diff --git a/crypto/src/math/raw/Nat160.cs b/crypto/src/math/raw/Nat160.cs
index 153ac0a43..1fd00e576 100644
--- a/crypto/src/math/raw/Nat160.cs
+++ b/crypto/src/math/raw/Nat160.cs
@@ -604,8 +604,8 @@ namespace Org.BouncyCastle.Math.Raw
}
ulong x_3 = x[3];
- ulong zz_5 = zz[5];
- ulong zz_6 = zz[6];
+ ulong zz_5 = zz[5] + (zz_4 >> 32); zz_4 &= M;
+ ulong zz_6 = zz[6] + (zz_5 >> 32); zz_5 &= M;
{
zz_3 += x_3 * x_0;
w = (uint)zz_3;
@@ -619,8 +619,8 @@ namespace Org.BouncyCastle.Math.Raw
}
ulong x_4 = x[4];
- ulong zz_7 = zz[7];
- ulong zz_8 = zz[8];
+ ulong zz_7 = zz[7] + (zz_6 >> 32); zz_6 &= M;
+ ulong zz_8 = zz[8] + (zz_7 >> 32); zz_7 &= M;
{
zz_4 += x_4 * x_0;
w = (uint)zz_4;
@@ -699,8 +699,8 @@ namespace Org.BouncyCastle.Math.Raw
}
ulong x_3 = x[xOff + 3];
- ulong zz_5 = zz[zzOff + 5];
- ulong zz_6 = zz[zzOff + 6];
+ ulong zz_5 = zz[zzOff + 5] + (zz_4 >> 32); zz_4 &= M;
+ ulong zz_6 = zz[zzOff + 6] + (zz_5 >> 32); zz_5 &= M;
{
zz_3 += x_3 * x_0;
w = (uint)zz_3;
@@ -714,8 +714,8 @@ namespace Org.BouncyCastle.Math.Raw
}
ulong x_4 = x[xOff + 4];
- ulong zz_7 = zz[zzOff + 7];
- ulong zz_8 = zz[zzOff + 8];
+ ulong zz_7 = zz[zzOff + 7] + (zz_6 >> 32); zz_6 &= M;
+ ulong zz_8 = zz[zzOff + 8] + (zz_7 >> 32); zz_7 &= M;
{
zz_4 += x_4 * x_0;
w = (uint)zz_4;
diff --git a/crypto/src/math/raw/Nat192.cs b/crypto/src/math/raw/Nat192.cs
index 4797609ee..3099bafab 100644
--- a/crypto/src/math/raw/Nat192.cs
+++ b/crypto/src/math/raw/Nat192.cs
@@ -706,8 +706,8 @@ namespace Org.BouncyCastle.Math.Raw
}
ulong x_3 = x[3];
- ulong zz_5 = zz[5];
- ulong zz_6 = zz[6];
+ ulong zz_5 = zz[5] + (zz_4 >> 32); zz_4 &= M;
+ ulong zz_6 = zz[6] + (zz_5 >> 32); zz_5 &= M;
{
zz_3 += x_3 * x_0;
w = (uint)zz_3;
@@ -721,8 +721,8 @@ namespace Org.BouncyCastle.Math.Raw
}
ulong x_4 = x[4];
- ulong zz_7 = zz[7];
- ulong zz_8 = zz[8];
+ ulong zz_7 = zz[7] + (zz_6 >> 32); zz_6 &= M;
+ ulong zz_8 = zz[8] + (zz_7 >> 32); zz_7 &= M;
{
zz_4 += x_4 * x_0;
w = (uint)zz_4;
@@ -738,8 +738,8 @@ namespace Org.BouncyCastle.Math.Raw
}
ulong x_5 = x[5];
- ulong zz_9 = zz[9];
- ulong zz_10 = zz[10];
+ ulong zz_9 = zz[9] + (zz_8 >> 32); zz_8 &= M;
+ ulong zz_10 = zz[10] + (zz_9 >> 32); zz_9 &= M;
{
zz_5 += x_5 * x_0;
w = (uint)zz_5;
@@ -822,8 +822,8 @@ namespace Org.BouncyCastle.Math.Raw
}
ulong x_3 = x[xOff + 3];
- ulong zz_5 = zz[zzOff + 5];
- ulong zz_6 = zz[zzOff + 6];
+ ulong zz_5 = zz[zzOff + 5] + (zz_4 >> 32); zz_4 &= M;
+ ulong zz_6 = zz[zzOff + 6] + (zz_5 >> 32); zz_5 &= M;
{
zz_3 += x_3 * x_0;
w = (uint)zz_3;
@@ -837,8 +837,8 @@ namespace Org.BouncyCastle.Math.Raw
}
ulong x_4 = x[xOff + 4];
- ulong zz_7 = zz[zzOff + 7];
- ulong zz_8 = zz[zzOff + 8];
+ ulong zz_7 = zz[zzOff + 7] + (zz_6 >> 32); zz_6 &= M;
+ ulong zz_8 = zz[zzOff + 8] + (zz_7 >> 32); zz_7 &= M;
{
zz_4 += x_4 * x_0;
w = (uint)zz_4;
@@ -854,8 +854,8 @@ namespace Org.BouncyCastle.Math.Raw
}
ulong x_5 = x[xOff + 5];
- ulong zz_9 = zz[zzOff + 9];
- ulong zz_10 = zz[zzOff + 10];
+ ulong zz_9 = zz[zzOff + 9] + (zz_8 >> 32); zz_8 &= M;
+ ulong zz_10 = zz[zzOff + 10] + (zz_9 >> 32); zz_9 &= M;
{
zz_5 += x_5 * x_0;
w = (uint)zz_5;
diff --git a/crypto/src/math/raw/Nat224.cs b/crypto/src/math/raw/Nat224.cs
index 940e930ac..978caf265 100644
--- a/crypto/src/math/raw/Nat224.cs
+++ b/crypto/src/math/raw/Nat224.cs
@@ -786,8 +786,8 @@ namespace Org.BouncyCastle.Math.Raw
}
ulong x_3 = x[3];
- ulong zz_5 = zz[5];
- ulong zz_6 = zz[6];
+ ulong zz_5 = zz[5] + (zz_4 >> 32); zz_4 &= M;
+ ulong zz_6 = zz[6] + (zz_5 >> 32); zz_5 &= M;
{
zz_3 += x_3 * x_0;
w = (uint)zz_3;
@@ -801,8 +801,8 @@ namespace Org.BouncyCastle.Math.Raw
}
ulong x_4 = x[4];
- ulong zz_7 = zz[7];
- ulong zz_8 = zz[8];
+ ulong zz_7 = zz[7] + (zz_6 >> 32); zz_6 &= M;
+ ulong zz_8 = zz[8] + (zz_7 >> 32); zz_7 &= M;
{
zz_4 += x_4 * x_0;
w = (uint)zz_4;
@@ -818,8 +818,8 @@ namespace Org.BouncyCastle.Math.Raw
}
ulong x_5 = x[5];
- ulong zz_9 = zz[9];
- ulong zz_10 = zz[10];
+ ulong zz_9 = zz[9] + (zz_8 >> 32); zz_8 &= M;
+ ulong zz_10 = zz[10] + (zz_9 >> 32); zz_9 &= M;
{
zz_5 += x_5 * x_0;
w = (uint)zz_5;
@@ -837,8 +837,8 @@ namespace Org.BouncyCastle.Math.Raw
}
ulong x_6 = x[6];
- ulong zz_11 = zz[11];
- ulong zz_12 = zz[12];
+ ulong zz_11 = zz[11] + (zz_10 >> 32); zz_10 &= M;
+ ulong zz_12 = zz[12] + (zz_11 >> 32); zz_11 &= M;
{
zz_6 += x_6 * x_0;
w = (uint)zz_6;
@@ -925,8 +925,8 @@ namespace Org.BouncyCastle.Math.Raw
}
ulong x_3 = x[xOff + 3];
- ulong zz_5 = zz[zzOff + 5];
- ulong zz_6 = zz[zzOff + 6];
+ ulong zz_5 = zz[zzOff + 5] + (zz_4 >> 32); zz_4 &= M;
+ ulong zz_6 = zz[zzOff + 6] + (zz_5 >> 32); zz_5 &= M;
{
zz_3 += x_3 * x_0;
w = (uint)zz_3;
@@ -940,8 +940,8 @@ namespace Org.BouncyCastle.Math.Raw
}
ulong x_4 = x[xOff + 4];
- ulong zz_7 = zz[zzOff + 7];
- ulong zz_8 = zz[zzOff + 8];
+ ulong zz_7 = zz[zzOff + 7] + (zz_6 >> 32); zz_6 &= M;
+ ulong zz_8 = zz[zzOff + 8] + (zz_7 >> 32); zz_7 &= M;
{
zz_4 += x_4 * x_0;
w = (uint)zz_4;
@@ -957,8 +957,8 @@ namespace Org.BouncyCastle.Math.Raw
}
ulong x_5 = x[xOff + 5];
- ulong zz_9 = zz[zzOff + 9];
- ulong zz_10 = zz[zzOff + 10];
+ ulong zz_9 = zz[zzOff + 9] + (zz_8 >> 32); zz_8 &= M;
+ ulong zz_10 = zz[zzOff + 10] + (zz_9 >> 32); zz_9 &= M;
{
zz_5 += x_5 * x_0;
w = (uint)zz_5;
@@ -976,8 +976,8 @@ namespace Org.BouncyCastle.Math.Raw
}
ulong x_6 = x[xOff + 6];
- ulong zz_11 = zz[zzOff + 11];
- ulong zz_12 = zz[zzOff + 12];
+ ulong zz_11 = zz[zzOff + 11] + (zz_10 >> 32); zz_10 &= M;
+ ulong zz_12 = zz[zzOff + 12] + (zz_11 >> 32); zz_11 &= M;
{
zz_6 += x_6 * x_0;
w = (uint)zz_6;
diff --git a/crypto/src/math/raw/Nat256.cs b/crypto/src/math/raw/Nat256.cs
index 19455031a..09c751a5a 100644
--- a/crypto/src/math/raw/Nat256.cs
+++ b/crypto/src/math/raw/Nat256.cs
@@ -917,8 +917,8 @@ namespace Org.BouncyCastle.Math.Raw
}
ulong x_3 = x[3];
- ulong zz_5 = zz[5];
- ulong zz_6 = zz[6];
+ ulong zz_5 = zz[5] + (zz_4 >> 32); zz_4 &= M;
+ ulong zz_6 = zz[6] + (zz_5 >> 32); zz_5 &= M;
{
zz_3 += x_3 * x_0;
w = (uint)zz_3;
@@ -932,8 +932,8 @@ namespace Org.BouncyCastle.Math.Raw
}
ulong x_4 = x[4];
- ulong zz_7 = zz[7];
- ulong zz_8 = zz[8];
+ ulong zz_7 = zz[7] + (zz_6 >> 32); zz_6 &= M;
+ ulong zz_8 = zz[8] + (zz_7 >> 32); zz_7 &= M;
{
zz_4 += x_4 * x_0;
w = (uint)zz_4;
@@ -949,8 +949,8 @@ namespace Org.BouncyCastle.Math.Raw
}
ulong x_5 = x[5];
- ulong zz_9 = zz[9];
- ulong zz_10 = zz[10];
+ ulong zz_9 = zz[9] + (zz_8 >> 32); zz_8 &= M;
+ ulong zz_10 = zz[10] + (zz_9 >> 32); zz_9 &= M;
{
zz_5 += x_5 * x_0;
w = (uint)zz_5;
@@ -968,8 +968,8 @@ namespace Org.BouncyCastle.Math.Raw
}
ulong x_6 = x[6];
- ulong zz_11 = zz[11];
- ulong zz_12 = zz[12];
+ ulong zz_11 = zz[11] + (zz_10 >> 32); zz_10 &= M;
+ ulong zz_12 = zz[12] + (zz_11 >> 32); zz_11 &= M;
{
zz_6 += x_6 * x_0;
w = (uint)zz_6;
@@ -989,8 +989,8 @@ namespace Org.BouncyCastle.Math.Raw
}
ulong x_7 = x[7];
- ulong zz_13 = zz[13];
- ulong zz_14 = zz[14];
+ ulong zz_13 = zz[13] + (zz_12 >> 32); zz_12 &= M;
+ ulong zz_14 = zz[14] + (zz_13 >> 32); zz_13 &= M;
{
zz_7 += x_7 * x_0;
w = (uint)zz_7;
@@ -1081,8 +1081,8 @@ namespace Org.BouncyCastle.Math.Raw
}
ulong x_3 = x[xOff + 3];
- ulong zz_5 = zz[zzOff + 5];
- ulong zz_6 = zz[zzOff + 6];
+ ulong zz_5 = zz[zzOff + 5] + (zz_4 >> 32); zz_4 &= M;
+ ulong zz_6 = zz[zzOff + 6] + (zz_5 >> 32); zz_5 &= M;
{
zz_3 += x_3 * x_0;
w = (uint)zz_3;
@@ -1096,8 +1096,8 @@ namespace Org.BouncyCastle.Math.Raw
}
ulong x_4 = x[xOff + 4];
- ulong zz_7 = zz[zzOff + 7];
- ulong zz_8 = zz[zzOff + 8];
+ ulong zz_7 = zz[zzOff + 7] + (zz_6 >> 32); zz_6 &= M;
+ ulong zz_8 = zz[zzOff + 8] + (zz_7 >> 32); zz_7 &= M;
{
zz_4 += x_4 * x_0;
w = (uint)zz_4;
@@ -1113,8 +1113,8 @@ namespace Org.BouncyCastle.Math.Raw
}
ulong x_5 = x[xOff + 5];
- ulong zz_9 = zz[zzOff + 9];
- ulong zz_10 = zz[zzOff + 10];
+ ulong zz_9 = zz[zzOff + 9] + (zz_8 >> 32); zz_8 &= M;
+ ulong zz_10 = zz[zzOff + 10] + (zz_9 >> 32); zz_9 &= M;
{
zz_5 += x_5 * x_0;
w = (uint)zz_5;
@@ -1132,8 +1132,8 @@ namespace Org.BouncyCastle.Math.Raw
}
ulong x_6 = x[xOff + 6];
- ulong zz_11 = zz[zzOff + 11];
- ulong zz_12 = zz[zzOff + 12];
+ ulong zz_11 = zz[zzOff + 11] + (zz_10 >> 32); zz_10 &= M;
+ ulong zz_12 = zz[zzOff + 12] + (zz_11 >> 32); zz_11 &= M;
{
zz_6 += x_6 * x_0;
w = (uint)zz_6;
@@ -1153,8 +1153,8 @@ namespace Org.BouncyCastle.Math.Raw
}
ulong x_7 = x[xOff + 7];
- ulong zz_13 = zz[zzOff + 13];
- ulong zz_14 = zz[zzOff + 14];
+ ulong zz_13 = zz[zzOff + 13] + (zz_12 >> 32); zz_12 &= M;
+ ulong zz_14 = zz[zzOff + 14] + (zz_13 >> 32); zz_13 &= M;
{
zz_7 += x_7 * x_0;
w = (uint)zz_7;
diff --git a/crypto/src/openpgp/PgpSignature.cs b/crypto/src/openpgp/PgpSignature.cs
index 3bb6f2f0e..c8c541bef 100644
--- a/crypto/src/openpgp/PgpSignature.cs
+++ b/crypto/src/openpgp/PgpSignature.cs
@@ -84,6 +84,12 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
get { return sigPck.HashAlgorithm; }
}
+ /// <summary>Return true if this signature represents a certification.</summary>
+ public bool IsCertification()
+ {
+ return IsCertification(SignatureType);
+ }
+
public void InitVerify(
PgpPublicKey pubKey)
{
@@ -418,5 +424,24 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
throw new PgpException("exception preparing key.", e);
}
}
+
+ /// <summary>
+ /// Return true if the passed in signature type represents a certification, false if the signature type is not.
+ /// </summary>
+ /// <param name="signatureType"></param>
+ /// <returns>true if signatureType is a certification, false otherwise.</returns>
+ public static bool IsCertification(int signatureType)
+ {
+ switch (signatureType)
+ {
+ case DefaultCertification:
+ case NoCertification:
+ case CasualCertification:
+ case PositiveCertification:
+ return true;
+ default:
+ return false;
+ }
+ }
}
}
diff --git a/crypto/src/security/SecureRandom.cs b/crypto/src/security/SecureRandom.cs
index cb831acc2..bd639a336 100644
--- a/crypto/src/security/SecureRandom.cs
+++ b/crypto/src/security/SecureRandom.cs
@@ -170,6 +170,7 @@ namespace Org.BouncyCastle.Security
public override int Next(int maxValue)
{
+
if (maxValue < 2)
{
if (maxValue < 0)
@@ -178,13 +179,16 @@ namespace Org.BouncyCastle.Security
return 0;
}
+ int bits;
+
// Test whether maxValue is a power of 2
if ((maxValue & (maxValue - 1)) == 0)
{
- return NextInt() & (maxValue - 1);
+ bits = NextInt() & int.MaxValue;
+ return (int)(((long)bits * maxValue) >> 31);
}
- int bits, result;
+ int result;
do
{
bits = NextInt() & int.MaxValue;
diff --git a/crypto/src/tsp/TimeStampRequest.cs b/crypto/src/tsp/TimeStampRequest.cs
index f54d33e04..0b41adef7 100644
--- a/crypto/src/tsp/TimeStampRequest.cs
+++ b/crypto/src/tsp/TimeStampRequest.cs
@@ -130,34 +130,24 @@ namespace Org.BouncyCastle.Tsp
IList extensions)
{
if (!algorithms.Contains(this.MessageImprintAlgOid))
- {
- throw new TspValidationException("request contains unknown algorithm.", PkiFailureInfo.BadAlg);
- }
+ throw new TspValidationException("request contains unknown algorithm", PkiFailureInfo.BadAlg);
- if (policies != null && this.ReqPolicy != null && !policies.Contains(this.ReqPolicy))
- {
- throw new TspValidationException("request contains unknown policy.", PkiFailureInfo.UnacceptedPolicy);
- }
+ if (policies != null && this.ReqPolicy != null && !policies.Contains(this.ReqPolicy))
+ throw new TspValidationException("request contains unknown policy", PkiFailureInfo.UnacceptedPolicy);
- if (this.Extensions != null && extensions != null)
+ if (this.Extensions != null && extensions != null)
{
foreach (DerObjectIdentifier oid in this.Extensions.ExtensionOids)
{
if (!extensions.Contains(oid.Id))
- {
- throw new TspValidationException("request contains unknown extension.",
- PkiFailureInfo.UnacceptedExtension);
- }
+ throw new TspValidationException("request contains unknown extension", PkiFailureInfo.UnacceptedExtension);
}
}
int digestLength = TspUtil.GetDigestLength(this.MessageImprintAlgOid);
if (digestLength != this.GetMessageImprintDigest().Length)
- {
- throw new TspValidationException("imprint digest the wrong length.",
- PkiFailureInfo.BadDataFormat);
- }
+ throw new TspValidationException("imprint digest the wrong length", PkiFailureInfo.BadDataFormat);
}
/**
diff --git a/crypto/src/util/zlib/ZInputStream.cs b/crypto/src/util/zlib/ZInputStream.cs
index 4b7351555..434fe95c8 100644
--- a/crypto/src/util/zlib/ZInputStream.cs
+++ b/crypto/src/util/zlib/ZInputStream.cs
@@ -42,9 +42,16 @@ namespace Org.BouncyCastle.Utilities.Zlib
public class ZInputStream
: Stream
{
- private const int BufferSize = 512;
+ private static ZStream GetDefaultZStream(bool nowrap)
+ {
+ ZStream z = new ZStream();
+ z.inflateInit(nowrap);
+ return z;
+ }
+
+ private const int BufferSize = 512;
- protected ZStream z = new ZStream();
+ protected ZStream z;
protected int flushLevel = JZlib.Z_NO_FLUSH;
// TODO Allow custom buf
protected byte[] buf = new byte[BufferSize];
@@ -62,24 +69,46 @@ namespace Org.BouncyCastle.Utilities.Zlib
}
public ZInputStream(Stream input, bool nowrap)
+ : this(input, GetDefaultZStream(nowrap))
+ {
+ }
+
+ public ZInputStream(Stream input, ZStream z)
+ : base()
{
Debug.Assert(input.CanRead);
- this.input = input;
- this.z.inflateInit(nowrap);
- this.compress = false;
- this.z.next_in = buf;
+ if (z == null)
+ {
+ z = new ZStream();
+ }
+
+ if (z.istate == null && z.dstate == null)
+ {
+ z.inflateInit();
+ }
+
+ this.input = input;
+ this.compress = (z.istate == null);
+ this.z = z;
+ this.z.next_in = buf;
this.z.next_in_index = 0;
this.z.avail_in = 0;
}
- public ZInputStream(Stream input, int level)
+ public ZInputStream(Stream input, int level)
+ : this(input, level, false)
+ {
+ }
+
+ public ZInputStream(Stream input, int level, bool nowrap)
{
Debug.Assert(input.CanRead);
this.input = input;
- this.z.deflateInit(level);
- this.compress = true;
+ this.compress = true;
+ this.z = new ZStream();
+ this.z.deflateInit(level, nowrap);
this.z.next_in = buf;
this.z.next_in_index = 0;
this.z.avail_in = 0;
diff --git a/crypto/src/util/zlib/ZOutputStream.cs b/crypto/src/util/zlib/ZOutputStream.cs
index d9f005f69..1633b2d8f 100644
--- a/crypto/src/util/zlib/ZOutputStream.cs
+++ b/crypto/src/util/zlib/ZOutputStream.cs
@@ -42,7 +42,14 @@ namespace Org.BouncyCastle.Utilities.Zlib
public class ZOutputStream
: Stream
{
- private const int BufferSize = 512;
+ private static ZStream GetDefaultZStream(bool nowrap)
+ {
+ ZStream z = new ZStream();
+ z.inflateInit(nowrap);
+ return z;
+ }
+
+ private const int BufferSize = 512;
protected ZStream z;
protected int flushLevel = JZlib.Z_NO_FLUSH;
@@ -55,9 +62,14 @@ namespace Org.BouncyCastle.Utilities.Zlib
protected bool closed;
public ZOutputStream(Stream output)
- : this(output, null)
- {
- }
+ : this(output, false)
+ {
+ }
+
+ public ZOutputStream(Stream output, bool nowrap)
+ : this(output, GetDefaultZStream(nowrap))
+ {
+ }
public ZOutputStream(Stream output, ZStream z)
: base()
@@ -67,12 +79,16 @@ namespace Org.BouncyCastle.Utilities.Zlib
if (z == null)
{
z = new ZStream();
+ }
+
+ if (z.istate == null && z.dstate == null)
+ {
z.inflateInit();
}
this.output = output;
+ this.compress = (z.istate == null);
this.z = z;
- this.compress = false;
}
public ZOutputStream(Stream output, int level)
@@ -86,9 +102,9 @@ namespace Org.BouncyCastle.Utilities.Zlib
Debug.Assert(output.CanWrite);
this.output = output;
+ this.compress = true;
this.z = new ZStream();
this.z.deflateInit(level, nowrap);
- this.compress = true;
}
public sealed override bool CanRead { get { return false; } }
|