summary refs log tree commit diff
path: root/crypto/src
diff options
context:
space:
mode:
authorDavid Hook <dgh@bouncycastle.org>2016-12-28 22:02:41 +1100
committerDavid Hook <dgh@bouncycastle.org>2016-12-28 22:02:41 +1100
commitd21cb9eeb630b0b81978a907c08cc88cdd650cd7 (patch)
treeadffc74ed7019ef8cf89691960ff211b88f6c3d2 /crypto/src
parentfixed head of loop to use primitive type. (diff)
parentFix carry propagation bug in Nat???.Square methods (diff)
downloadBouncyCastle.NET-ed25519-d21cb9eeb630b0b81978a907c08cc88cdd650cd7.tar.xz
Merge branch 'master' of bcgit@git.bouncycastle.org:bc-csharp.git
Diffstat (limited to 'crypto/src')
-rw-r--r--crypto/src/asn1/DerBitString.cs11
-rw-r--r--crypto/src/asn1/ocsp/CertStatus.cs2
-rw-r--r--crypto/src/crypto/agreement/ECDHBasicAgreement.cs3
-rw-r--r--crypto/src/crypto/agreement/ECDHCBasicAgreement.cs10
-rw-r--r--crypto/src/crypto/agreement/ECMqvBasicAgreement.cs10
-rw-r--r--crypto/src/crypto/generators/BCrypt.cs4
-rw-r--r--crypto/src/crypto/generators/HKDFBytesGenerator.cs153
-rw-r--r--crypto/src/crypto/generators/Pkcs12ParametersGenerator.cs2
-rw-r--r--crypto/src/crypto/generators/Pkcs5S1ParametersGenerator.cs2
-rw-r--r--crypto/src/crypto/generators/Pkcs5S2ParametersGenerator.cs2
-rw-r--r--crypto/src/crypto/generators/Poly1305KeyGenerator.cs65
-rw-r--r--crypto/src/crypto/macs/Poly1305.cs76
-rw-r--r--crypto/src/crypto/parameters/DHParameters.cs2
-rw-r--r--crypto/src/crypto/parameters/ECDomainParameters.cs19
-rw-r--r--crypto/src/crypto/parameters/HKDFParameters.cs119
-rw-r--r--crypto/src/crypto/parameters/MqvPrivateParameters.cs32
-rw-r--r--crypto/src/crypto/parameters/MqvPublicParameters.cs17
-rw-r--r--crypto/src/crypto/tls/CertificateType.cs18
-rw-r--r--crypto/src/crypto/tls/Chacha20Poly1305.cs5
-rw-r--r--crypto/src/crypto/tls/CipherSuite.cs2
-rw-r--r--crypto/src/crypto/tls/DefaultTlsCipherFactory.cs2
-rw-r--r--crypto/src/crypto/tls/DtlsClientProtocol.cs16
-rw-r--r--crypto/src/crypto/tls/DtlsRecordLayer.cs12
-rw-r--r--crypto/src/crypto/tls/DtlsServerProtocol.cs34
-rw-r--r--crypto/src/crypto/tls/EncryptionAlgorithm.cs2
-rw-r--r--crypto/src/crypto/tls/NameType.cs5
-rw-r--r--crypto/src/crypto/tls/ServerNameList.cs27
-rw-r--r--crypto/src/crypto/tls/TlsAeadCipher.cs76
-rw-r--r--crypto/src/crypto/tls/TlsDHUtilities.cs5
-rw-r--r--crypto/src/crypto/tls/TlsEccUtilities.cs5
-rw-r--r--crypto/src/crypto/tls/TlsProtocol.cs69
-rw-r--r--crypto/src/crypto/tls/TlsUtilities.cs1
-rw-r--r--crypto/src/math/ec/multiplier/WNafUtilities.cs2
-rw-r--r--crypto/src/math/raw/Nat128.cs8
-rw-r--r--crypto/src/math/raw/Nat160.cs16
-rw-r--r--crypto/src/math/raw/Nat192.cs24
-rw-r--r--crypto/src/math/raw/Nat224.cs32
-rw-r--r--crypto/src/math/raw/Nat256.cs40
-rw-r--r--crypto/src/openpgp/PgpSignature.cs25
-rw-r--r--crypto/src/security/SecureRandom.cs8
-rw-r--r--crypto/src/tsp/TimeStampRequest.cs22
-rw-r--r--crypto/src/util/zlib/ZInputStream.cs47
-rw-r--r--crypto/src/util/zlib/ZOutputStream.cs28
43 files changed, 787 insertions, 273 deletions
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 &lt;- 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 &amp; 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; } }