summary refs log tree commit diff
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
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
-rw-r--r--crypto/BouncyCastle.Android.csproj3
-rw-r--r--crypto/BouncyCastle.csproj3
-rw-r--r--crypto/BouncyCastle.iOS.csproj3
-rw-r--r--crypto/Readme.html23
-rw-r--r--crypto/crypto.csproj30
-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
-rw-r--r--crypto/test/UnitTests.csproj3
-rw-r--r--crypto/test/src/asn1/test/BitStringTest.cs16
-rw-r--r--crypto/test/src/crypto/test/HKDFGeneratorTest.cs310
-rw-r--r--crypto/test/src/crypto/test/Poly1305Test.cs350
-rw-r--r--crypto/test/src/crypto/test/RegressionTest.cs1
-rw-r--r--crypto/test/src/math/ec/custom/sec/test/SecP256R1FieldTest.cs181
-rw-r--r--crypto/test/src/math/ec/custom/sec/test/SecP384R1FieldTest.cs146
-rw-r--r--crypto/test/src/openpgp/test/PGPNoPrivateKeyTest.cs4
-rw-r--r--crypto/test/src/openpgp/test/RegressionTest.cs2
-rw-r--r--crypto/test/src/test/nist/NistCertPathTest.cs6
-rw-r--r--crypto/test/src/util/test/SimpleTest.cs6
59 files changed, 1751 insertions, 396 deletions
diff --git a/crypto/BouncyCastle.Android.csproj b/crypto/BouncyCastle.Android.csproj
index 0b6f376bf..13ca4f05c 100644
--- a/crypto/BouncyCastle.Android.csproj
+++ b/crypto/BouncyCastle.Android.csproj
@@ -639,6 +639,7 @@
     <Compile Include="src\crypto\engines\SerpentEngineBase.cs" />
     <Compile Include="src\crypto\engines\TnepresEngine.cs" />
     <Compile Include="src\crypto\generators\BCrypt.cs" />
+    <Compile Include="src\crypto\generators\HKDFBytesGenerator.cs" />
     <Compile Include="src\crypto\generators\OpenBsdBCrypt.cs" />
     <Compile Include="src\crypto\IAsymmetricBlockCipher.cs" />
     <Compile Include="src\crypto\IAsymmetricCipherKeyPairGenerator.cs" />
@@ -668,6 +669,7 @@
     <Compile Include="src\crypto\KeyGenerationParameters.cs" />
     <Compile Include="src\crypto\MaxBytesExceededException.cs" />
     <Compile Include="src\crypto\OutputLengthException.cs" />
+    <Compile Include="src\crypto\parameters\HKDFParameters.cs" />
     <Compile Include="src\crypto\PbeParametersGenerator.cs" />
     <Compile Include="src\crypto\prng\BasicEntropySourceProvider.cs" />
     <Compile Include="src\crypto\prng\CryptoApiEntropySourceProvider.cs" />
@@ -961,6 +963,7 @@
     <Compile Include="src\crypto\tls\CertificateStatus.cs" />
     <Compile Include="src\crypto\tls\CertificateStatusRequest.cs" />
     <Compile Include="src\crypto\tls\CertificateStatusType.cs" />
+    <Compile Include="src\crypto\tls\CertificateType.cs" />
     <Compile Include="src\crypto\tls\CertificateUrl.cs" />
     <Compile Include="src\crypto\tls\Chacha20Poly1305.cs" />
     <Compile Include="src\crypto\tls\ChangeCipherSpec.cs" />
diff --git a/crypto/BouncyCastle.csproj b/crypto/BouncyCastle.csproj
index 5f0a58ad8..f72c9c527 100644
--- a/crypto/BouncyCastle.csproj
+++ b/crypto/BouncyCastle.csproj
@@ -633,6 +633,7 @@
     <Compile Include="src\crypto\engines\SerpentEngineBase.cs" />
     <Compile Include="src\crypto\engines\TnepresEngine.cs" />
     <Compile Include="src\crypto\generators\BCrypt.cs" />
+    <Compile Include="src\crypto\generators\HKDFBytesGenerator.cs" />
     <Compile Include="src\crypto\generators\OpenBsdBCrypt.cs" />
     <Compile Include="src\crypto\IAsymmetricBlockCipher.cs" />
     <Compile Include="src\crypto\IAsymmetricCipherKeyPairGenerator.cs" />
@@ -662,6 +663,7 @@
     <Compile Include="src\crypto\KeyGenerationParameters.cs" />
     <Compile Include="src\crypto\MaxBytesExceededException.cs" />
     <Compile Include="src\crypto\OutputLengthException.cs" />
+    <Compile Include="src\crypto\parameters\HKDFParameters.cs" />
     <Compile Include="src\crypto\PbeParametersGenerator.cs" />
     <Compile Include="src\crypto\prng\BasicEntropySourceProvider.cs" />
     <Compile Include="src\crypto\prng\CryptoApiEntropySourceProvider.cs" />
@@ -955,6 +957,7 @@
     <Compile Include="src\crypto\tls\CertificateStatus.cs" />
     <Compile Include="src\crypto\tls\CertificateStatusRequest.cs" />
     <Compile Include="src\crypto\tls\CertificateStatusType.cs" />
+    <Compile Include="src\crypto\tls\CertificateType.cs" />
     <Compile Include="src\crypto\tls\CertificateUrl.cs" />
     <Compile Include="src\crypto\tls\Chacha20Poly1305.cs" />
     <Compile Include="src\crypto\tls\ChangeCipherSpec.cs" />
diff --git a/crypto/BouncyCastle.iOS.csproj b/crypto/BouncyCastle.iOS.csproj
index eeaf3bb12..b3bf7b4fa 100644
--- a/crypto/BouncyCastle.iOS.csproj
+++ b/crypto/BouncyCastle.iOS.csproj
@@ -634,6 +634,7 @@
     <Compile Include="src\crypto\engines\SerpentEngineBase.cs" />
     <Compile Include="src\crypto\engines\TnepresEngine.cs" />
     <Compile Include="src\crypto\generators\BCrypt.cs" />
+    <Compile Include="src\crypto\generators\HKDFBytesGenerator.cs" />
     <Compile Include="src\crypto\generators\OpenBsdBCrypt.cs" />
     <Compile Include="src\crypto\IAsymmetricBlockCipher.cs" />
     <Compile Include="src\crypto\IAsymmetricCipherKeyPairGenerator.cs" />
@@ -663,6 +664,7 @@
     <Compile Include="src\crypto\KeyGenerationParameters.cs" />
     <Compile Include="src\crypto\MaxBytesExceededException.cs" />
     <Compile Include="src\crypto\OutputLengthException.cs" />
+    <Compile Include="src\crypto\parameters\HKDFParameters.cs" />
     <Compile Include="src\crypto\PbeParametersGenerator.cs" />
     <Compile Include="src\crypto\prng\BasicEntropySourceProvider.cs" />
     <Compile Include="src\crypto\prng\CryptoApiEntropySourceProvider.cs" />
@@ -956,6 +958,7 @@
     <Compile Include="src\crypto\tls\CertificateStatus.cs" />
     <Compile Include="src\crypto\tls\CertificateStatusRequest.cs" />
     <Compile Include="src\crypto\tls\CertificateStatusType.cs" />
+    <Compile Include="src\crypto\tls\CertificateType.cs" />
     <Compile Include="src\crypto\tls\CertificateUrl.cs" />
     <Compile Include="src\crypto\tls\Chacha20Poly1305.cs" />
     <Compile Include="src\crypto\tls\ChangeCipherSpec.cs" />
diff --git a/crypto/Readme.html b/crypto/Readme.html
index 7af1bbaf0..b26937714 100644
--- a/crypto/Readme.html
+++ b/crypto/Readme.html
@@ -294,6 +294,27 @@ We state, where EC MQV has not otherwise been disabled or removed:
 
         <h4><a class="mozTocH4" name="mozTocId85316"></a>Release 1.8.2, Release Date TBD</h4>
 
+        <h5>Security Advisory</h5>
+        <ul>
+            <li>
+                Carry propagation bugs in the implementation of squaring for several raw math classes have been fixed (Org.BouncyCastle.Math.Raw.Nat???).
+                These classes are used by our custom elliptic curve implementations (Org.BouncyCastle.Math.Ec.Custom.**), so there was the possibility
+                of rare (in general usage) spurious calculations for elliptic curve scalar multiplications. Such errors would have been detected with
+                high probability by the output validation for our scalar multipliers. We consider these bugs to be exploitable for static ECDH with
+                long-term keys, per <a href="https://eprint.iacr.org/2011/633">"Practical realisation and elimination of an ECC-related software bug attack",
+                Brumley et.al.</a>
+            </li>
+        </ul>
+
+        <h5>IMPORTANT</h5>
+        <ul>
+            <li>
+                This release brings our Poly1305 implementation into line wih RFC 7539, which breaks backward compatibility. The essential
+                difference from 1.8.1 is that the two halves of the 32-byte Poly1305 key have swapped places. If you have persisted Poly1305
+                keys, or are interoperating with other Poly1305 implementations, you may need to account for this change when migrating to 1.8.2.
+            </li>
+        </ul>
+
         <h5>Additional Features and Functionality</h5>
         <ul>
             <li>TLS: support for ClientHello Padding Extension (RFC 7685).</li>
@@ -372,7 +393,7 @@ We state, where EC MQV has not otherwise been disabled or removed:
             <li>RFC 6637 ECDSA and ECDH support has been added to the OpenPGP API.</li>
             <li>Implementations of Threefish and Skein have been added.</li>
             <li>Implementation of the SM3 digest has been added.</li>
-            <li>Implementations of XSalsa20 and ChaCha have been added. Support for reduced round Salas20 has been added.</li>
+            <li>Implementations of XSalsa20 and ChaCha have been added. Support for reduced round Salsa20 has been added.</li>
             <li>Support has been added for RFC 6979 Deterministic DSA/ECDSA.</li>
             <li>Support for the Poly1305 MAC has been added.</li>
             <li>GCM and GMAC now support tag lengths down to 32 bits.</li>
diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj
index 6ab8faf50..6f1fdcf61 100644
--- a/crypto/crypto.csproj
+++ b/crypto/crypto.csproj
@@ -3794,6 +3794,11 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\crypto\generators\HKDFBytesGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\crypto\generators\KDF1BytesGenerator.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
@@ -4244,6 +4249,11 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\crypto\parameters\HKDFParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\crypto\parameters\IESParameters.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
@@ -4664,6 +4674,11 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\crypto\tls\CertificateType.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\crypto\tls\CertificateUrl.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
@@ -11450,6 +11465,11 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "test\src\crypto\test\HKDFGeneratorTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "test\src\crypto\test\IDEATest.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
@@ -12035,6 +12055,16 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "test\src\math\ec\custom\sec\test\SecP256R1FieldTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\math\ec\custom\sec\test\SecP384R1FieldTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "test\src\math\ec\test\AllTests.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
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; } }
diff --git a/crypto/test/UnitTests.csproj b/crypto/test/UnitTests.csproj
index d3250d89a..fe4dd9583 100644
--- a/crypto/test/UnitTests.csproj
+++ b/crypto/test/UnitTests.csproj
@@ -193,6 +193,7 @@
     <Compile Include="src\crypto\test\GcmReorderTest.cs" />
     <Compile Include="src\crypto\test\HCFamilyTest.cs" />
     <Compile Include="src\crypto\test\HCFamilyVecTest.cs" />
+    <Compile Include="src\crypto\test\HKDFGeneratorTest.cs" />
     <Compile Include="src\crypto\test\IDEATest.cs" />
     <Compile Include="src\crypto\test\ISAACTest.cs" />
     <Compile Include="src\crypto\test\ISO9796Test.cs" />
@@ -311,6 +312,8 @@
     <Compile Include="src\crypto\tls\test\TlsTestSuite.cs" />
     <Compile Include="src\crypto\tls\test\TlsTestUtilities.cs" />
     <Compile Include="src\crypto\tls\test\UnreliableDatagramTransport.cs" />
+    <Compile Include="src\math\ec\custom\sec\test\SecP256R1FieldTest.cs" />
+    <Compile Include="src\math\ec\custom\sec\test\SecP384R1FieldTest.cs" />
     <Compile Include="src\math\ec\test\AllTests.cs" />
     <Compile Include="src\math\ec\test\ECAlgorithmsTest.cs" />
     <Compile Include="src\math\ec\test\ECPointPerformanceTest.cs" />
diff --git a/crypto/test/src/asn1/test/BitStringTest.cs b/crypto/test/src/asn1/test/BitStringTest.cs
index f2ae3de97..35b7811bc 100644
--- a/crypto/test/src/asn1/test/BitStringTest.cs
+++ b/crypto/test/src/asn1/test/BitStringTest.cs
@@ -86,10 +86,26 @@ namespace Org.BouncyCastle.Asn1.Tests
                 //Fail("failed DL check");
                 Fail("failed BER check");
             }
+            IAsn1String dl = BerBitString.GetInstance(dlData);
+
+            //IsTrue("DL test failed", dl is DLBitString);
+            IsTrue("BER test failed", dl is BerBitString);
             if (!Arrays.AreEqual(derData, Asn1Object.FromByteArray(dlData).GetDerEncoded()))
             {
                 Fail("failed DER check");
             }
+            // TODO This test isn't applicable until we get the DL variants
+            //try
+            //{
+            //    DerBitString.GetInstance(dlData);
+            //    Fail("no exception");
+            //}
+            //catch (ArgumentException e)
+            //{
+            //    // ignore
+            //}
+            IAsn1String der = DerBitString.GetInstance(derData);
+            IsTrue("DER test failed", der is DerBitString);
         }
 
         public override void PerformTest()
diff --git a/crypto/test/src/crypto/test/HKDFGeneratorTest.cs b/crypto/test/src/crypto/test/HKDFGeneratorTest.cs
new file mode 100644
index 000000000..d6e2149df
--- /dev/null
+++ b/crypto/test/src/crypto/test/HKDFGeneratorTest.cs
@@ -0,0 +1,310 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /**
+     * HKDF tests - vectors from RFC 5869, + 2 more, 101 and 102
+     */
+    [TestFixture]
+    public class HkdfGeneratorTest
+        : SimpleTest
+    {
+        public HkdfGeneratorTest()
+        {
+        }
+
+        private void CompareOkm(int test, byte[] calculatedOkm, byte[] testOkm)
+        {
+            if (!AreEqual(calculatedOkm, testOkm))
+            {
+                Fail("HKDF failed generator test " + test);
+            }
+        }
+
+        public override void PerformTest()
+        {
+            {
+                // === A.1. Test Case 1 - Basic test case with SHA-256 ===
+
+                IDigest hash = new Sha256Digest();
+                byte[] ikm = Hex.Decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b");
+                byte[] salt = Hex.Decode("000102030405060708090a0b0c");
+                byte[] info = Hex.Decode("f0f1f2f3f4f5f6f7f8f9");
+                int l = 42;
+                byte[] okm = new byte[l];
+
+                HkdfParameters parameters = new HkdfParameters(ikm, salt, info);
+
+                HkdfBytesGenerator hkdf = new HkdfBytesGenerator(hash);
+                hkdf.Init(parameters);
+                hkdf.GenerateBytes(okm, 0, l);
+
+                CompareOkm(1, okm, Hex.Decode(
+                    "3cb25f25faacd57a90434f64d0362f2a" +
+                    "2d2d0a90cf1a5a4c5db02d56ecc4c5bf" +
+                    "34007208d5b887185865"));
+            }
+
+            // === A.2. Test Case 2 - Test with SHA-256 and longer inputs/outputs
+            // ===
+            {
+                IDigest hash = new Sha256Digest();
+                byte[] ikm = Hex.Decode("000102030405060708090a0b0c0d0e0f"
+                    + "101112131415161718191a1b1c1d1e1f"
+                    + "202122232425262728292a2b2c2d2e2f"
+                    + "303132333435363738393a3b3c3d3e3f"
+                    + "404142434445464748494a4b4c4d4e4f");
+                byte[] salt = Hex.Decode("606162636465666768696a6b6c6d6e6f"
+                    + "707172737475767778797a7b7c7d7e7f"
+                    + "808182838485868788898a8b8c8d8e8f"
+                    + "909192939495969798999a9b9c9d9e9f"
+                    + "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf");
+                byte[] info = Hex.Decode("b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
+                    + "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
+                    + "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
+                    + "e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
+                    + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff");
+                int l = 82;
+                byte[] okm = new byte[l];
+
+                HkdfParameters parameters = new HkdfParameters(ikm, salt, info);
+
+                HkdfBytesGenerator hkdf = new HkdfBytesGenerator(hash);
+                hkdf.Init(parameters);
+                hkdf.GenerateBytes(okm, 0, l);
+
+                CompareOkm(2, okm, Hex.Decode(
+                    "b11e398dc80327a1c8e7f78c596a4934" +
+                    "4f012eda2d4efad8a050cc4c19afa97c" +
+                    "59045a99cac7827271cb41c65e590e09" +
+                    "da3275600c2f09b8367793a9aca3db71" +
+                    "cc30c58179ec3e87c14c01d5c1f3434f" +
+                    "1d87"));
+            }
+
+            {
+                // === A.3. Test Case 3 - Test with SHA-256 and zero-length
+                // salt/info ===
+
+                // setting salt to an empty byte array means that the salt is set to
+                // HashLen zero valued bytes
+                // setting info to null generates an empty byte array as info
+                // structure
+
+                IDigest hash = new Sha256Digest();
+                byte[] ikm = Hex.Decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b");
+                byte[] salt = new byte[0];
+                byte[] info = null;
+                int l = 42;
+                byte[] okm = new byte[l];
+
+                HkdfParameters parameters = new HkdfParameters(ikm, salt, info);
+
+                HkdfBytesGenerator hkdf = new HkdfBytesGenerator(hash);
+                hkdf.Init(parameters);
+                hkdf.GenerateBytes(okm, 0, l);
+
+                CompareOkm(3, okm, Hex.Decode(
+                    "8da4e775a563c18f715f802a063c5a31" +
+                    "b8a11f5c5ee1879ec3454e5f3c738d2d" +
+                    "9d201395faa4b61a96c8"));
+            }
+
+            {
+                // === A.4. Test Case 4 - Basic test case with SHA-1 ===
+
+                IDigest hash = new Sha1Digest();
+                byte[] ikm = Hex.Decode("0b0b0b0b0b0b0b0b0b0b0b");
+                byte[] salt = Hex.Decode("000102030405060708090a0b0c");
+                byte[] info = Hex.Decode("f0f1f2f3f4f5f6f7f8f9");
+                int l = 42;
+                byte[] okm = new byte[l];
+
+                HkdfParameters parameters = new HkdfParameters(ikm, salt, info);
+
+                HkdfBytesGenerator hkdf = new HkdfBytesGenerator(hash);
+                hkdf.Init(parameters);
+                hkdf.GenerateBytes(okm, 0, l);
+
+                CompareOkm(4, okm, Hex.Decode(
+                    "085a01ea1b10f36933068b56efa5ad81" +
+                        "a4f14b822f5b091568a9cdd4f155fda2" +
+                        "c22e422478d305f3f896"));
+            }
+
+            // === A.5. Test Case 5 - Test with SHA-1 and longer inputs/outputs ===
+            {
+                IDigest hash = new Sha1Digest();
+                byte[] ikm = Hex.Decode("000102030405060708090a0b0c0d0e0f"
+                    + "101112131415161718191a1b1c1d1e1f"
+                    + "202122232425262728292a2b2c2d2e2f"
+                    + "303132333435363738393a3b3c3d3e3f"
+                    + "404142434445464748494a4b4c4d4e4f");
+                byte[] salt = Hex.Decode("606162636465666768696a6b6c6d6e6f"
+                    + "707172737475767778797a7b7c7d7e7f"
+                    + "808182838485868788898a8b8c8d8e8f"
+                    + "909192939495969798999a9b9c9d9e9f"
+                    + "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf");
+                byte[] info = Hex.Decode("b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
+                    + "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
+                    + "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
+                    + "e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
+                    + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff");
+                int l = 82;
+                byte[] okm = new byte[l];
+
+                HkdfParameters parameters = new HkdfParameters(ikm, salt, info);
+
+                HkdfBytesGenerator hkdf = new HkdfBytesGenerator(hash);
+                hkdf.Init(parameters);
+                hkdf.GenerateBytes(okm, 0, l);
+
+                CompareOkm(5, okm, Hex.Decode(
+                    "0bd770a74d1160f7c9f12cd5912a06eb" +
+                    "ff6adcae899d92191fe4305673ba2ffe" +
+                    "8fa3f1a4e5ad79f3f334b3b202b2173c" +
+                    "486ea37ce3d397ed034c7f9dfeb15c5e" +
+                    "927336d0441f4c4300e2cff0d0900b52" +
+                    "d3b4"));
+            }
+
+            {
+                // === A.6. Test Case 6 - Test with SHA-1 and zero-length salt/info
+                // ===
+
+                // setting salt to null should generate a new salt of HashLen zero
+                // valued bytes
+
+                IDigest hash = new Sha1Digest();
+                byte[] ikm = Hex.Decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b");
+                byte[] salt = null;
+                byte[] info = new byte[0];
+                int l = 42;
+                byte[] okm = new byte[l];
+
+                HkdfParameters parameters = new HkdfParameters(ikm, salt, info);
+
+                HkdfBytesGenerator hkdf = new HkdfBytesGenerator(hash);
+                hkdf.Init(parameters);
+                hkdf.GenerateBytes(okm, 0, l);
+
+                CompareOkm(6, okm, Hex.Decode(
+                    "0ac1af7002b3d761d1e55298da9d0506" +
+                    "b9ae52057220a306e07b6b87e8df21d0" +
+                    "ea00033de03984d34918"));
+            }
+
+            {
+                // === A.7. Test Case 7 - Test with SHA-1, salt not provided,
+                // zero-length info ===
+                // (salt defaults to HashLen zero octets)
+
+                // this test is identical to test 6 in all ways bar the IKM value
+
+                IDigest hash = new Sha1Digest();
+                byte[] ikm = Hex.Decode("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c");
+                byte[] salt = null;
+                byte[] info = new byte[0];
+                int l = 42;
+                byte[] okm = new byte[l];
+
+                HkdfParameters parameters = new HkdfParameters(ikm, salt, info);
+
+                HkdfBytesGenerator hkdf = new HkdfBytesGenerator(hash);
+                hkdf.Init(parameters);
+                hkdf.GenerateBytes(okm, 0, l);
+
+                CompareOkm(7, okm, Hex.Decode(
+                    "2c91117204d745f3500d636a62f64f0a" +
+                    "b3bae548aa53d423b0d1f27ebba6f5e5" +
+                    "673a081d70cce7acfc48"));
+            }
+
+            {
+                // === A.101. Additional Test Case - Test with SHA-1, skipping extract
+                // zero-length info ===
+                // (salt defaults to HashLen zero octets)
+
+                // this test is identical to test 7 in all ways bar the IKM value
+                // which is set to the PRK value
+
+                IDigest hash = new Sha1Digest();
+                byte[] ikm = Hex.Decode("2adccada18779e7c2077ad2eb19d3f3e731385dd");
+                byte[] info = new byte[0];
+                int l = 42;
+                byte[] okm = new byte[l];
+
+                HkdfParameters parameters = HkdfParameters.SkipExtractParameters(ikm, info);
+
+                HkdfBytesGenerator hkdf = new HkdfBytesGenerator(hash);
+                hkdf.Init(parameters);
+                hkdf.GenerateBytes(okm, 0, l);
+
+                CompareOkm(101, okm, Hex.Decode(
+                    "2c91117204d745f3500d636a62f64f0a" +
+                    "b3bae548aa53d423b0d1f27ebba6f5e5" +
+                    "673a081d70cce7acfc48"));
+            }
+
+            {
+                // === A.102. Additional Test Case - Test with SHA-1, maximum output ===
+                // (salt defaults to HashLen zero octets)
+
+                // this test is identical to test 7 in all ways bar the IKM value
+
+                IDigest hash = new Sha1Digest();
+                byte[] ikm = Hex.Decode("2adccada18779e7c2077ad2eb19d3f3e731385dd");
+                byte[] info = new byte[0];
+                int l = 255 * hash.GetDigestSize();
+                byte[] okm = new byte[l];
+
+                HkdfParameters parameters = HkdfParameters.SkipExtractParameters(ikm, info);
+
+                HkdfBytesGenerator hkdf = new HkdfBytesGenerator(hash);
+                hkdf.Init(parameters);
+                hkdf.GenerateBytes(okm, 0, l);
+
+                int zeros = 0;
+                for (int i = 0; i < hash.GetDigestSize(); i++)
+                {
+                    if (okm[i] == 0)
+                    {
+                        zeros++;
+                    }
+                }
+
+                if (zeros == hash.GetDigestSize())
+                {
+                    Fail("HKDF failed generator test " + 102);
+                }
+            }
+        }
+
+        public override string Name
+        {
+            get { return "HKDF"; }
+        }
+
+        public static void Main(string[] args)
+        {
+            RunTest(new HkdfGeneratorTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/Poly1305Test.cs b/crypto/test/src/crypto/test/Poly1305Test.cs
index a1513165b..17c4289aa 100644
--- a/crypto/test/src/crypto/test/Poly1305Test.cs
+++ b/crypto/test/src/crypto/test/Poly1305Test.cs
@@ -20,54 +20,7 @@ namespace Org.BouncyCastle.Crypto.Tests
 	{
 		private const int MAXLEN = 1000;
 
-		private class KeyEngine
-			: IBlockCipher
-		{
-
-			private byte[] key;
-			private int blockSize;
-
-			public KeyEngine(int blockSize)
-			{
-				this.blockSize = blockSize;
-			}
-
-			public void Init(bool forEncryption, ICipherParameters parameters)
-			{
-				if (parameters is KeyParameter)
-				{
-					this.key = ((KeyParameter)parameters).GetKey();
-				}
-			}
-
-			public bool IsPartialBlockOkay 
-			{ 
-				get { return false; } 
-			}
-
-			public string AlgorithmName
-			{
-				get { return "Key"; }
-			}
-
-			public int GetBlockSize()
-			{
-				return blockSize;
-			}
-
-			public int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
-			{
-				Array.Copy(key, 0, output, outOff, key.Length);
-				return key.Length;
-			}
-
-			public void Reset()
-			{
-			}
-
-		}
-
-		private class TestCase
+        private class TestCase
 		{
 			internal byte[] key;
 			internal byte[] nonce;
@@ -85,57 +38,54 @@ namespace Org.BouncyCastle.Crypto.Tests
 			}
 		}
 
-		private static TestCase[] CASES = {
-			// Raw Poly1305
-			// onetimeauth.c from nacl-20110221
-			new TestCase("2539121d8e234e652d651fa4c8cff880eea6a7251c1e72916d11c2cb214d3c25", null,
-			             "8e993b9f48681273c29650ba32fc76ce48332ea7164d96a4476fb8c531a1186a"
-			             + "c0dfc17c98dce87b4da7f011ec48c97271d2c20f9b928fe2270d6fb863d51738"
-			             + "b48eeee314a7cc8ab932164548e526ae90224368517acfeabd6bb3732bc0e9da"
-			             + "99832b61ca01b6de56244a9e88d5f9b37973f622a43d14a6599b1f654cb45a74e355a5",
-			             "f3ffc7703f9400e52a7dfb4b3d3305d9"),
-
-			// Poly1305-AES
-			// Loop 1 of test-poly1305aes from poly1305aes-20050218
-			new TestCase("0000000000000000000000000000000000000000000000000000000000000000",
-			             "00000000000000000000000000000000", "", "66e94bd4ef8a2c3b884cfa59ca342b2e"),
-			new TestCase("f795bd4a52e29ed713d313fa20e98dbcf795bd0a50e29e0710d3130a20e98d0c",
-			             "917cf69ebd68b2ec9b9fe9a3eadda692", "66f7", "5ca585c75e8f8f025e710cabc9a1508b"),
-			new TestCase("e69dae0aab9f91c03a325dcc9436fa903ef49901c8e11c000430d90ad45e7603",
-			             "166450152e2394835606a9d1dd2cdc8b", "66f75c0e0c7a406586", "2924f51b9c2eff5df09db61dd03a9ca1"),
-			new TestCase("85a4ea91a7de0b0d96eed0d4bf6ecf1cda4afc035087d90e503f8f0ea08c3e0d",
-			             "0b6ef7a0b8f8c738b0f8d5995415271f",
-			             "66f75c0e0c7a40658629e3392f7f8e3349a02191ffd49f39879a8d9d1d0e23ea",
-			             "3c5a13adb18d31c64cc29972030c917d"),
-			new TestCase(
-				"25eb69bac5cdf7d6bfcee4d9d5507b82ca3c6a0da0a864024ca3090628c28e0d",
-				"046772a4f0a8de92e4f0d628cdb04484",
-				"66f75c0e0c7a40658629e3392f7f8e3349a02191ffd49f39879a8d9d1d0e23ea3caa4d240bd2ab8a8c4a6bb8d3288d9de4b793f05e97646dd4d98055de",
-				"fc5fb58dc65daf19b14d1d05da1064e8"),
-
-			// Specific test cases generated from test-poly1305aes from poly1305aes-20050218 that
-			// expose Java unsigned integer problems
-			new TestCase(
-				"95cc0e44d0b79a8856afcae1bec4fe3c" + "01bcb20bfc8b6e03609ddd09f44b060f",
-				null,
-				"66f75c0e0c7a40658629e3392f7f8e3349a02191ffd49f39879a8d9d1d0e23ea3caa4d240bd2ab8a8c4a6bb8d3288d9de4b793f05e97646dd4d98055de"
-				+ "fc3e0677d956b4c62664bac15962ab15d93ccbbc03aafdbde779162ed93b55361f0f8acaa41d50ef5175927fe79ea316186516eef15001cd04d3524a55"
-				+ "e4fa3c5ca479d3aaa8a897c21807f721b6270ffc68b6889d81a116799f6aaa35d8e04c7a7dd5e6da2519e8759f54e906696f5772fee093283bcef7b930"
-				+ "aed50323bcbc8c820c67422c1e16bdc022a9c0277c9d95fef0ea4ee11e2b27276da811523c5acb80154989f8a67ee9e3fa30b73b0c1c34bf46e3464d97"
-				+ "7cd7fcd0ac3b82721080bb0d9b982ee2c77feee983d7ba35da88ce86955002940652ab63bc56fb16f994da2b01d74356509d7d1b6d7956b0e5a557757b"
-				+ "d1ced2eef8650bc5b6d426108c1518abcbd0befb6a0d5fd57a3e2dbf31458eab63df66613653d4beae73f5c40eb438fbcfdcf4a4ba46320184b9ca0da4"
-				+ "dfae77de7ccc910356caea3243f33a3c81b064b3b7cedc7435c223f664227215715980e6e0bb570d459ba80d7512dbe458c8f0f3f52d659b6e8eef19ee"
-				+ "71aea2ced85c7a42ffca6522a62db49a2a46eff72bd7f7e0883acd087183f0627f3537a4d558754ed63358e8182bee196735b361dc9bd64d5e34e1074a"
-				+ "855655d2974cc6fa1653754cf40f561d8c7dc526aab2908ec2d2b977cde1a1fb1071e32f40e049ea20f30368ba1592b4fe57fb51595d23acbdace324cd"
-				+ "d78060a17187c662368854e915402d9b52fb21e984663e41c26a109437e162cfaf071b53f77e50000a5388ff183b82ce7a1af476c416d7d204157b3633"
-				+ "b2f4ec077b699b032816997e37bceded8d4a04976fd7d0c0b029f290794c3be504c5242287ea2f831f11ed5690d92775cd6e863d7731fd4da687ebfb13"
-				+ "df4c41dc0fb8", "ae345d555eb04d6947bb95c0965237e2"),
-			new TestCase(
-				"76fb3635a2dc92a1f768163ab12f2187" + "cd07fd0ef8c0be0afcbdb30af4af0009",
-				null,
-				"f05204a74f0f88a7fa1a95b84ec3d8ffb36fcdc7723ea65dfe7cd464e86e0abf6b9d51db3220cfd8496ad6e6d36ebee8d990f9ce0d3bb7f72b7ab5b3ab0a73240d11efe772c857021ae859db4933cdde4387b471d2ce700fef4b81087f8f47c307881fd83017afcd15b8d21edf9b704677f46df97b07e5b83f87c8abd90af9b1d0f9e2710e8ebd0d4d1c6a055abea861f42368bed94d9373e909c1d3715b221c16bc524c55c31ec3eab204850bb2474a84f9917038eff9d921130951391b5c54f09b5e1de833ea2cd7d3b306740abb7096d1e173da83427da2adddd3631eda30b54dbf487f2b082e8646f07d6e0a87e97522ca38d4ace4954bf3db6dd3a93b06fa18eb56856627ed6cffcd7ae26374554ca18ab8905f26331d323fe10e6e70624c7bc07a70f06ecd804b48f8f7e75e910165e1beb554f1f0ec7949c9c8d429a206b4d5c0653102249b6098e6b45fac2a07ff0220b0b8ae8f4c6bcc0c813a7cd141fa8b398b42575fc395747c5a0257ac41d6c1f434cfbf5dfe8349f5347ef6b60e611f5d6c3cbc20ca2555274d1934325824cef4809da293ea13f181929e2af025bbd1c9abdc3af93afd4c50a2854ade3887f4d2c8c225168052c16e74d76d2dd3e9467a2c5b8e15c06ffbffa42b8536384139f07e195a8c9f70f514f31dca4eb2cf262c0dcbde53654b6250a29efe21d54e83c80e005a1cad36d5934ff01c32e4bc5fe06d03064ff4a268517df4a94c759289f323734318cfa5d859d4ce9c16e63d02dff0896976f521607638535d2ee8dd3312e1ddc80a55d34fe829ab954c1ebd54d929954770f1be9d32b4c05003c5c9e97943b6431e2afe820b1e967b19843e5985a131b1100517cdc363799104af91e2cf3f53cb8fd003653a6dd8a31a3f9d566a7124b0ffe9695bcb87c482eb60106f88198f766a40bc0f4873c23653c5f9e7a8e446f770beb8034cf01d21028ba15ccee21a8db918c4829d61c88bfa927bc5def831501796c5b401a60a6b1b433c9fb905c8cd40412fffee81ab",
-				"045be28cc52009f506bdbfabedacf0b4"),
-
+        private static TestCase[] CASES = {
+            // Raw Poly1305
+            // onetimeauth.c from nacl-20110221
+            new TestCase("eea6a7251c1e72916d11c2cb214d3c25" + "2539121d8e234e652d651fa4c8cff880", null,
+                "8e993b9f48681273c29650ba32fc76ce48332ea7164d96a4476fb8c531a1186a"
+                    + "c0dfc17c98dce87b4da7f011ec48c97271d2c20f9b928fe2270d6fb863d51738"
+                    + "b48eeee314a7cc8ab932164548e526ae90224368517acfeabd6bb3732bc0e9da"
+                    + "99832b61ca01b6de56244a9e88d5f9b37973f622a43d14a6599b1f654cb45a74e355a5",
+                "f3ffc7703f9400e52a7dfb4b3d3305d9"),
+            // Poly1305-AES
+            // Loop 1 of test-poly1305aes from poly1305aes-20050218
+            new TestCase("0000000000000000000000000000000000000000000000000000000000000000",
+                "00000000000000000000000000000000", "", "66e94bd4ef8a2c3b884cfa59ca342b2e"),
+            new TestCase("f795bd0a50e29e0710d3130a20e98d0c" + "f795bd4a52e29ed713d313fa20e98dbc",
+                "917cf69ebd68b2ec9b9fe9a3eadda692", "66f7", "5ca585c75e8f8f025e710cabc9a1508b"),
+            new TestCase("3ef49901c8e11c000430d90ad45e7603" + "e69dae0aab9f91c03a325dcc9436fa90",
+                "166450152e2394835606a9d1dd2cdc8b", "66f75c0e0c7a406586", "2924f51b9c2eff5df09db61dd03a9ca1"),
+            new TestCase("da4afc035087d90e503f8f0ea08c3e0d" + "85a4ea91a7de0b0d96eed0d4bf6ecf1c",
+                "0b6ef7a0b8f8c738b0f8d5995415271f",
+                "66f75c0e0c7a40658629e3392f7f8e3349a02191ffd49f39879a8d9d1d0e23ea",
+                "3c5a13adb18d31c64cc29972030c917d"),
+            new TestCase(
+                "ca3c6a0da0a864024ca3090628c28e0d" + "25eb69bac5cdf7d6bfcee4d9d5507b82",
+                "046772a4f0a8de92e4f0d628cdb04484",
+                "66f75c0e0c7a40658629e3392f7f8e3349a02191ffd49f39879a8d9d1d0e23ea3caa4d240bd2ab8a8c4a6bb8d3288d9de4b793f05e97646dd4d98055de",
+                "fc5fb58dc65daf19b14d1d05da1064e8"),
+            // Specific test cases generated from test-poly1305aes from poly1305aes-20050218 that
+            // expose Java unsigned integer problems
+            new TestCase(
+                "01bcb20bfc8b6e03609ddd09f44b060f" + "95cc0e44d0b79a8856afcae1bec4fe3c",
+                null,
+                "66f75c0e0c7a40658629e3392f7f8e3349a02191ffd49f39879a8d9d1d0e23ea3caa4d240bd2ab8a8c4a6bb8d3288d9de4b793f05e97646dd4d98055de"
+                    + "fc3e0677d956b4c62664bac15962ab15d93ccbbc03aafdbde779162ed93b55361f0f8acaa41d50ef5175927fe79ea316186516eef15001cd04d3524a55"
+                    + "e4fa3c5ca479d3aaa8a897c21807f721b6270ffc68b6889d81a116799f6aaa35d8e04c7a7dd5e6da2519e8759f54e906696f5772fee093283bcef7b930"
+                    + "aed50323bcbc8c820c67422c1e16bdc022a9c0277c9d95fef0ea4ee11e2b27276da811523c5acb80154989f8a67ee9e3fa30b73b0c1c34bf46e3464d97"
+                    + "7cd7fcd0ac3b82721080bb0d9b982ee2c77feee983d7ba35da88ce86955002940652ab63bc56fb16f994da2b01d74356509d7d1b6d7956b0e5a557757b"
+                    + "d1ced2eef8650bc5b6d426108c1518abcbd0befb6a0d5fd57a3e2dbf31458eab63df66613653d4beae73f5c40eb438fbcfdcf4a4ba46320184b9ca0da4"
+                    + "dfae77de7ccc910356caea3243f33a3c81b064b3b7cedc7435c223f664227215715980e6e0bb570d459ba80d7512dbe458c8f0f3f52d659b6e8eef19ee"
+                    + "71aea2ced85c7a42ffca6522a62db49a2a46eff72bd7f7e0883acd087183f0627f3537a4d558754ed63358e8182bee196735b361dc9bd64d5e34e1074a"
+                    + "855655d2974cc6fa1653754cf40f561d8c7dc526aab2908ec2d2b977cde1a1fb1071e32f40e049ea20f30368ba1592b4fe57fb51595d23acbdace324cd"
+                    + "d78060a17187c662368854e915402d9b52fb21e984663e41c26a109437e162cfaf071b53f77e50000a5388ff183b82ce7a1af476c416d7d204157b3633"
+                    + "b2f4ec077b699b032816997e37bceded8d4a04976fd7d0c0b029f290794c3be504c5242287ea2f831f11ed5690d92775cd6e863d7731fd4da687ebfb13"
+                    + "df4c41dc0fb8", "ae345d555eb04d6947bb95c0965237e2"),
+            new TestCase(
+                "cd07fd0ef8c0be0afcbdb30af4af0009" + "76fb3635a2dc92a1f768163ab12f2187",
+                null,
+                "f05204a74f0f88a7fa1a95b84ec3d8ffb36fcdc7723ea65dfe7cd464e86e0abf6b9d51db3220cfd8496ad6e6d36ebee8d990f9ce0d3bb7f72b7ab5b3ab0a73240d11efe772c857021ae859db4933cdde4387b471d2ce700fef4b81087f8f47c307881fd83017afcd15b8d21edf9b704677f46df97b07e5b83f87c8abd90af9b1d0f9e2710e8ebd0d4d1c6a055abea861f42368bed94d9373e909c1d3715b221c16bc524c55c31ec3eab204850bb2474a84f9917038eff9d921130951391b5c54f09b5e1de833ea2cd7d3b306740abb7096d1e173da83427da2adddd3631eda30b54dbf487f2b082e8646f07d6e0a87e97522ca38d4ace4954bf3db6dd3a93b06fa18eb56856627ed6cffcd7ae26374554ca18ab8905f26331d323fe10e6e70624c7bc07a70f06ecd804b48f8f7e75e910165e1beb554f1f0ec7949c9c8d429a206b4d5c0653102249b6098e6b45fac2a07ff0220b0b8ae8f4c6bcc0c813a7cd141fa8b398b42575fc395747c5a0257ac41d6c1f434cfbf5dfe8349f5347ef6b60e611f5d6c3cbc20ca2555274d1934325824cef4809da293ea13f181929e2af025bbd1c9abdc3af93afd4c50a2854ade3887f4d2c8c225168052c16e74d76d2dd3e9467a2c5b8e15c06ffbffa42b8536384139f07e195a8c9f70f514f31dca4eb2cf262c0dcbde53654b6250a29efe21d54e83c80e005a1cad36d5934ff01c32e4bc5fe06d03064ff4a268517df4a94c759289f323734318cfa5d859d4ce9c16e63d02dff0896976f521607638535d2ee8dd3312e1ddc80a55d34fe829ab954c1ebd54d929954770f1be9d32b4c05003c5c9e97943b6431e2afe820b1e967b19843e5985a131b1100517cdc363799104af91e2cf3f53cb8fd003653a6dd8a31a3f9d566a7124b0ffe9695bcb87c482eb60106f88198f766a40bc0f4873c23653c5f9e7a8e446f770beb8034cf01d21028ba15ccee21a8db918c4829d61c88bfa927bc5def831501796c5b401a60a6b1b433c9fb905c8cd40412fffee81ab",
+                "045be28cc52009f506bdbfabedacf0b4"),
 		};
 
 		public override string Name
@@ -153,6 +103,7 @@ namespace Org.BouncyCastle.Crypto.Tests
 			}
 			testSequential();
 			testReset();
+            rfc7539Test();
 		}
 
 		private void testCase(int i)
@@ -164,8 +115,8 @@ namespace Org.BouncyCastle.Crypto.Tests
 			if (tc.nonce == null)
 			{
 				// Raw Poly1305 test - don't do any transform on AES key part
-				mac = new Poly1305(new KeyEngine(16));
-				mac.Init(new ParametersWithIV(new KeyParameter(tc.key), new byte[16]));
+                mac = new Poly1305();
+                mac.Init(new KeyParameter(tc.key));
 			}
 			else
 			{
@@ -228,23 +179,33 @@ namespace Org.BouncyCastle.Crypto.Tests
 					if (len >= MAXLEN)
 						break;
 					n[0] = (byte)(n[0] ^ loop);
-					for (int i = 0; i < 16; ++i)
-						n[i] ^= output[i];
-					if (len % 2 != 0)
-						for (int i = 0; i < 16; ++i)
-							kr[i] ^= output[i];
+                    for (int i = 0; i < 16; ++i)
+                    {
+                        n[i] ^= output[i];
+                    }
+                    if (len % 2 != 0)
+                    {
+                        for (int i = 0; i < 16; ++i)
+                        {
+                            kr[i] ^= output[i];
+                        }
+                    }
 					if (len % 3 != 0)
+                    {
 						for (int i = 0; i < 16; ++i)
+                        {
 							kr[i + 16] ^= output[i];
-					Poly1305KeyGenerator.Clamp(kr);
+                        }
+                    }
+                    Poly1305KeyGenerator.Clamp(kr);
 					m[len++] ^= output[0];
 				}
 			}
 			// Output after 13 loops as generated by poly1305 ref
-			if (c != 13013 || !Arrays.AreEqual(output, Hex.Decode("c96f60a23701a5b0fd2016f58cbe4f7e")))
-			{
-				Fail("Sequential Poly1305 " + c, "c96f60a23701a5b0fd2016f58cbe4f7e", Hex.ToHexString(output));
-			}
+            if (c != 13013 || !Arrays.AreEqual(output, Hex.Decode("89824ddf0816481051f4a82731cd56d5")))
+            {
+                Fail("Sequential Poly1305 " + c, "89824ddf0816481051f4a82731cd56d5", Hex.ToHexString(output));
+            }
 		}
 
 		private void testReset()
@@ -311,7 +272,8 @@ namespace Org.BouncyCastle.Crypto.Tests
 			{
 				poly.Init(new ParametersWithIV(new KeyParameter(k), new byte[15]));
 				Fail("16 byte nonce required");
-			} catch (ArgumentException)
+			}
+            catch (ArgumentException)
 			{
 				// Expected
 			}
@@ -322,21 +284,24 @@ namespace Org.BouncyCastle.Crypto.Tests
 				Array.Copy(k, 0, k2, 0, k2.Length);
 				poly.Init(new ParametersWithIV(new KeyParameter(k2), new byte[16]));
 				Fail("32 byte key required");
-			} catch (ArgumentException)
+			}
+            catch (ArgumentException)
 			{
 				// Expected
 			}
 
+            /*
 			try
 			{
 				k[19] = (byte)0xFF;
 				poly.Init(new ParametersWithIV(new KeyParameter(k), new byte[16]));
 				Fail("UnClamped key should not be accepted.");
-			} catch (ArgumentException)
+			}
+            catch (ArgumentException)
 			{
 				// Expected
 			}
-
+            */
 		}
 
 		private void testKeyGenerator()
@@ -353,7 +318,8 @@ namespace Org.BouncyCastle.Crypto.Tests
 			try
 			{
 				Poly1305KeyGenerator.CheckKey(k);
-			} catch (ArgumentException)
+			}
+            catch (ArgumentException)
 			{
 				Fail("Poly1305 key should be Clamped on generation.");
 			}
@@ -366,17 +332,167 @@ namespace Org.BouncyCastle.Crypto.Tests
 				Fail("Poly1305 key should be Clamped on generation.");
 			}
 
+            /*
 			try
 			{
 				k2[19] = (byte)0xff;
 				Poly1305KeyGenerator.CheckKey(k2);
 				Fail("UnClamped key should fail check.");
-			} catch (ArgumentException)
+			}
+            catch (ArgumentException)
 			{
 				// Expected
 			}
+            */
 		}
 
+        public void rfc7539Test()
+        {
+            // From RFC 7539
+            byte[] keyMaterial = Hex.Decode("85d6be7857556d337f4452fe42d506a80103808afb0db2fd4abff6af4149f51b");
+            byte[] data = Hex.Decode("43727970746f677261706869 63 20 46 6f 72 75 6d 20 52 65 73 65 61 72 63 68 20 47 72 6f7570");
+            byte[] expected = Hex.Decode("a8061dc1305136c6c22b8baf0c0127a9");
+
+            CheckVector(keyMaterial, data, expected);
+
+            data = Hex.Decode("48656c6c6f20776f726c6421");
+            keyMaterial = Hex.Decode(
+                "746869732069732033322d6279746520" +
+                    "6b657920666f7220506f6c7931333035");
+
+            CheckVector(keyMaterial, data, Hex.Decode("a6f745008f81c916a20dcc74eef2b2f0"));
+
+            // A.3 #1
+            keyMaterial = Hex.Decode("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
+
+            data = Hex.Decode(
+                "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"
+                    + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"
+                    + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"
+                    + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
+
+            CheckVector(keyMaterial, data, Hex.Decode("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"));
+
+            // A.3 #2
+            keyMaterial = Hex.Decode("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0036 e5 f6 b5 c5 e0 60 70 f0 ef ca 96 22 7a 86 3e");
+
+            data = Hex.Decode(
+                "41 6e 79 20 73 75 62 6d 69 73 73 69 6f 6e 20 74"
+                    + "6f 20 74 68 65 20 49 45 54 46 20 69 6e 74 65 6e"
+                    + "64 65 64 20 62 79 20 74 68 65 20 43 6f 6e 74 72"
+                    + "69 62 75 74 6f 72 20 66 6f 72 20 70 75 62 6c 69"
+                    + "63 61 74 69 6f 6e 20 61 73 20 61 6c 6c 20 6f 72"
+                    + "20 70 61 72 74 20 6f 66 20 61 6e 20 49 45 54 46"
+                    + "20 49 6e 74 65 72 6e 65 74 2d 44 72 61 66 74 20"
+                    + "6f 72 20 52 46 43 20 61 6e 64 20 61 6e 79 20 73"
+                    + "74 61 74 65 6d 65 6e 74 20 6d 61 64 65 20 77 69"
+                    + "74 68 69 6e 20 74 68 65 20 63 6f 6e 74 65 78 74"
+                    + "20 6f 66 20 61 6e 20 49 45 54 46 20 61 63 74 69"
+                    + "76 69 74 79 20 69 73 20 63 6f 6e 73 69 64 65 72"
+                    + "65 64 20 61 6e 20 22 49 45 54 46 20 43 6f 6e 74"
+                    + "72 69 62 75 74 69 6f 6e 22 2e 20 53 75 63 68 20"
+                    + "73 74 61 74 65 6d 65 6e 74 73 20 69 6e 63 6c 75"
+                    + "64 65 20 6f 72 61 6c 20 73 74 61 74 65 6d 65 6e"
+                    + "74 73 20 69 6e 20 49 45 54 46 20 73 65 73 73 69"
+                    + "6f 6e 73 2c 20 61 73 20 77 65 6c 6c 20 61 73 20"
+                    + "77 72 69 74 74 65 6e 20 61 6e 64 20 65 6c 65 63"
+                    + "74 72 6f 6e 69 63 20 63 6f 6d 6d 75 6e 69 63 61"
+                    + "74 69 6f 6e 73 20 6d 61 64 65 20 61 74 20 61 6e"
+                    + "79 20 74 69 6d 65 20 6f 72 20 70 6c 61 63 65 2c"
+                    + "20 77 68 69 63 68 20 61 72 65 20 61 64 64 72 65"
+                    + "73 73 65 64 20 74 6f");
+
+            CheckVector(keyMaterial, data, Hex.Decode("36 e5 f6 b5 c5 e0 60 70 f0 ef ca 96 22 7a 86 3e"));
+
+            // A.3 #3
+            keyMaterial = Hex.Decode("36 e5 f6 b5 c5 e0 60 70 f0 ef ca 96 22 7a 86 3e00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
+
+            CheckVector(keyMaterial, data, Hex.Decode("f3 47 7e 7c d9 54 17 af 89 a6 b8 79 4c 31 0c f0"));
+
+            // A.3 #4
+
+            keyMaterial = Hex.Decode("1c 92 40 a5 eb 55 d3 8a f3 33 88 86 04 f6 b5 f0 47 39 17 c1 40 2b 80 09 9d ca 5c bc 20 70 75 c0");
+
+            data = Hex.Decode(
+                "27 54 77 61 73 20 62 72 69 6c 6c 69 67 2c 20 61"
+                    + "6e 64 20 74 68 65 20 73 6c 69 74 68 79 20 74 6f"
+                    + "76 65 73 0a 44 69 64 20 67 79 72 65 20 61 6e 64"
+                    + "20 67 69 6d 62 6c 65 20 69 6e 20 74 68 65 20 77"
+                    + "61 62 65 3a 0a 41 6c 6c 20 6d 69 6d 73 79 20 77"
+                    + "65 72 65 20 74 68 65 20 62 6f 72 6f 67 6f 76 65"
+                    + "73 2c 0a 41 6e 64 20 74 68 65 20 6d 6f 6d 65 20"
+                    + "72 61 74 68 73 20 6f 75 74 67 72 61 62 65 2e");
+
+            CheckVector(keyMaterial, data, Hex.Decode("45 41 66 9a 7e aa ee 61 e7 08 dc 7c bc c5 eb 62"));
+
+            // A.3 #5
+            keyMaterial = Hex.Decode("02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
+            data = Hex.Decode("FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF");
+
+            CheckVector(keyMaterial, data, Hex.Decode("03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"));
+
+            // A.3 #6
+            keyMaterial = Hex.Decode("02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF");
+            data = Hex.Decode("02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
+
+            CheckVector(keyMaterial, data, Hex.Decode("03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"));
+
+            // A.3 #7
+            keyMaterial = Hex.Decode("01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
+            data = Hex.Decode("FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FFF0 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF11 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
+
+            CheckVector(keyMaterial, data, Hex.Decode("05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"));
+
+            // A.3 #8
+            keyMaterial = Hex.Decode("01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
+            data = Hex.Decode("FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FFFB FE FE FE FE FE FE FE FE FE FE FE FE FE FE FE01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01");
+
+            CheckVector(keyMaterial, data, Hex.Decode("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"));
+
+            // A.3 #9
+            keyMaterial = Hex.Decode("02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
+            data = Hex.Decode("FD FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF");
+
+            CheckVector(keyMaterial, data, Hex.Decode("FA FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF"));
+
+            // A.3 #10
+            keyMaterial = Hex.Decode("01 00 00 00 00 00 00 00 04 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
+            data = Hex.Decode(
+                "E3 35 94 D7 50 5E 43 B9 00 00 00 00 00 00 00 00"
+                    + "33 94 D7 50 5E 43 79 CD 01 00 00 00 00 00 00 00"
+                    + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"
+                    + "01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
+
+            CheckVector(keyMaterial, data, Hex.Decode("14 00 00 00 00 00 00 00 55 00 00 00 00 00 00 00"));
+
+            // A.3 #11
+            keyMaterial = Hex.Decode("01 00 00 00 00 00 00 00 04 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
+            data = Hex.Decode(
+                "E3 35 94 D7 50 5E 43 B9 00 00 00 00 00 00 00 00"
+                    + "33 94 D7 50 5E 43 79 CD 01 00 00 00 00 00 00 00"
+                    + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
+
+            CheckVector(keyMaterial, data, Hex.Decode("13 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"));
+        }
+
+        private void CheckVector(byte[] keyMaterial, byte[] input, byte[] tag)
+        {
+            Poly1305 poly1305 = new Poly1305();
+
+            poly1305.Init(new KeyParameter(keyMaterial));
+
+            poly1305.BlockUpdate(input, 0, input.Length);
+
+            byte[] mac = new byte[poly1305.GetMacSize()];
+
+            poly1305.DoFinal(mac, 0);
+
+            if (!Arrays.AreEqual(tag, mac))
+            {
+                Fail("rfc7539", Hex.ToHexString(tag), Hex.ToHexString(mac));
+            }
+       }
+
 		public static void Main(
 			string[] args)
 		{
diff --git a/crypto/test/src/crypto/test/RegressionTest.cs b/crypto/test/src/crypto/test/RegressionTest.cs
index 3611e4e63..ba6c341d4 100644
--- a/crypto/test/src/crypto/test/RegressionTest.cs
+++ b/crypto/test/src/crypto/test/RegressionTest.cs
@@ -90,6 +90,7 @@ namespace Org.BouncyCastle.Crypto.Tests
             new Kdf1GeneratorTest(),
             new Kdf2GeneratorTest(),
             new Mgf1GeneratorTest(),
+            new HkdfGeneratorTest(),
             new DHKekGeneratorTest(),
             new ECDHKekGeneratorTest(),
             new ShortenedDigestTest(),
diff --git a/crypto/test/src/math/ec/custom/sec/test/SecP256R1FieldTest.cs b/crypto/test/src/math/ec/custom/sec/test/SecP256R1FieldTest.cs
new file mode 100644
index 000000000..374b1ecd1
--- /dev/null
+++ b/crypto/test/src/math/ec/custom/sec/test/SecP256R1FieldTest.cs
@@ -0,0 +1,181 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.Sec;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto.EC;
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec.Tests
+{
+    [TestFixture]
+    public class SecP256R1FieldTest
+    {
+        private static readonly SecureRandom Random = new SecureRandom();
+
+        private static readonly X9ECParameters DP = CustomNamedCurves
+            .GetByOid(SecObjectIdentifiers.SecP256r1);
+        private static readonly BigInteger Q = DP.Curve.Field.Characteristic;
+
+        [Test]
+        public void TestMultiply1()
+        {
+            int COUNT = 1000;
+
+            for (int i = 0; i < COUNT; ++i)
+            {
+                ECFieldElement x = GenerateMultiplyInput_Random();
+                ECFieldElement y = GenerateMultiplyInput_Random();
+
+                BigInteger X = x.ToBigInteger(), Y = y.ToBigInteger();
+                BigInteger R = X.Multiply(Y).Mod(Q);
+
+                ECFieldElement z = x.Multiply(y);
+                BigInteger Z = z.ToBigInteger();
+
+                Assert.AreEqual(R, Z);
+            }
+        }
+
+        [Test]
+        public void TestMultiply2()
+        {
+            int COUNT = 100;
+            ECFieldElement[] inputs = new ECFieldElement[COUNT];
+            BigInteger[] INPUTS = new BigInteger[COUNT];
+
+            for (int i = 0; i < inputs.Length; ++i)
+            {
+                inputs[i] = GenerateMultiplyInput_Random();
+                INPUTS[i] = inputs[i].ToBigInteger();
+            }
+
+            for (int j = 0; j < inputs.Length; ++j)
+            {
+                for (int k = 0; k < inputs.Length; ++k)
+                {
+                    BigInteger R = INPUTS[j].Multiply(INPUTS[k]).Mod(Q);
+
+                    ECFieldElement z = inputs[j].Multiply(inputs[k]);
+                    BigInteger Z = z.ToBigInteger();
+
+                    Assert.AreEqual(R, Z);
+                }
+            }
+        }
+
+        [Test]
+        public void TestSquare()
+        {
+            int COUNT = 1000;
+
+            for (int i = 0; i < COUNT; ++i)
+            {
+                ECFieldElement x = GenerateMultiplyInput_Random();
+
+                BigInteger X = x.ToBigInteger();
+                BigInteger R = X.Multiply(X).Mod(Q);
+
+                ECFieldElement z = x.Square();
+                BigInteger Z = z.ToBigInteger();
+
+                Assert.AreEqual(R, Z);
+            }
+        }
+
+        /**
+         * Test multiplication with specifically selected values that triggered a bug in the modular
+         * reduction in OpenSSL (last affected version 0.9.8g).
+         *
+         * See "Practical realisation and elimination of an ECC-related software bug attack", B. B.
+         * Brumley, M. Barbarosa, D. Page, F. Vercauteren.
+         */
+        [Test]
+        public void TestMultiply_OpenSSLBug()
+        {
+            int COUNT = 100;
+
+            for (int i = 0; i < COUNT; ++i)
+            {
+                ECFieldElement x = GenerateMultiplyInputA_OpenSSLBug();
+                ECFieldElement y = GenerateMultiplyInputB_OpenSSLBug();
+
+                BigInteger X = x.ToBigInteger(), Y = y.ToBigInteger();
+                BigInteger R = X.Multiply(Y).Mod(Q);
+
+                ECFieldElement z = x.Multiply(y);
+                BigInteger Z = z.ToBigInteger();
+
+                Assert.AreEqual(R, Z);
+            }
+        }
+
+        /**
+         * Test squaring with specifically selected values that triggered a bug in the modular reduction
+         * in OpenSSL (last affected version 0.9.8g).
+         *
+         * See "Practical realisation and elimination of an ECC-related software bug attack", B. B.
+         * Brumley, M. Barbarosa, D. Page, F. Vercauteren.
+         */
+        [Test]
+        public void TestSquare_OpenSSLBug()
+        {
+            int COUNT = 100;
+
+            for (int i = 0; i < COUNT; ++i)
+            {
+                ECFieldElement x = GenerateSquareInput_OpenSSLBug();
+
+                BigInteger X = x.ToBigInteger();
+                BigInteger R = X.Multiply(X).Mod(Q);
+
+                ECFieldElement z = x.Square();
+                BigInteger Z = z.ToBigInteger();
+
+                Assert.AreEqual(R, Z);
+            }
+        }
+
+        private ECFieldElement FE(BigInteger x)
+        {
+            return DP.Curve.FromBigInteger(x);
+        }
+
+        private ECFieldElement GenerateMultiplyInput_Random()
+        {
+            return FE(new BigInteger(DP.Curve.FieldSize + 32, Random).Mod(Q));
+        }
+
+        private ECFieldElement GenerateMultiplyInputA_OpenSSLBug()
+        {
+            uint[] x = Nat256.Create();
+            x[0] = (uint)Random.NextInt() >> 1;
+            x[4] = 3;
+            x[7] = 0xFFFFFFFF;
+
+            return FE(Nat256.ToBigInteger(x));
+        }
+
+        private ECFieldElement GenerateMultiplyInputB_OpenSSLBug()
+        {
+            uint[] x = Nat256.Create();
+            x[0] = (uint)Random.NextInt() >> 1;
+            x[3] = 1;
+            x[7] = 0xFFFFFFFF;
+
+            return FE(Nat256.ToBigInteger(x));
+        }
+
+        private ECFieldElement GenerateSquareInput_OpenSSLBug()
+        {
+            uint[] x = Nat256.Create();
+            x[0] = (uint)Random.NextInt() >> 1;
+            x[4] = 2;
+            x[7] = 0xFFFFFFFF;
+
+            return FE(Nat256.ToBigInteger(x));
+        }
+    }
+}
diff --git a/crypto/test/src/math/ec/custom/sec/test/SecP384R1FieldTest.cs b/crypto/test/src/math/ec/custom/sec/test/SecP384R1FieldTest.cs
new file mode 100644
index 000000000..86ec4894f
--- /dev/null
+++ b/crypto/test/src/math/ec/custom/sec/test/SecP384R1FieldTest.cs
@@ -0,0 +1,146 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.Sec;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto.EC;
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec.Tests
+{
+    [TestFixture]
+    public class SecP384R1FieldTest
+    {
+        private static readonly SecureRandom Random = new SecureRandom();
+
+        private static readonly X9ECParameters DP = CustomNamedCurves
+            .GetByOid(SecObjectIdentifiers.SecP384r1);
+        private static readonly BigInteger Q = DP.Curve.Field.Characteristic;
+
+        [Test]
+        public void TestMultiply1()
+        {
+            int COUNT = 1000;
+
+            for (int i = 0; i < COUNT; ++i)
+            {
+                ECFieldElement x = GenerateMultiplyInput_Random();
+                ECFieldElement y = GenerateMultiplyInput_Random();
+
+                BigInteger X = x.ToBigInteger(), Y = y.ToBigInteger();
+                BigInteger R = X.Multiply(Y).Mod(Q);
+
+                ECFieldElement z = x.Multiply(y);
+                BigInteger Z = z.ToBigInteger();
+
+                Assert.AreEqual(R, Z);
+            }
+        }
+
+        [Test]
+        public void TestMultiply2()
+        {
+            int COUNT = 100;
+            ECFieldElement[] inputs = new ECFieldElement[COUNT];
+            BigInteger[] INPUTS = new BigInteger[COUNT];
+
+            for (int i = 0; i < inputs.Length; ++i)
+            {
+                inputs[i] = GenerateMultiplyInput_Random();
+                INPUTS[i] = inputs[i].ToBigInteger();
+            }
+
+            for (int j = 0; j < inputs.Length; ++j)
+            {
+                for (int k = 0; k < inputs.Length; ++k)
+                {
+                    BigInteger R = INPUTS[j].Multiply(INPUTS[k]).Mod(Q);
+
+                    ECFieldElement z = inputs[j].Multiply(inputs[k]);
+                    BigInteger Z = z.ToBigInteger();
+
+                    Assert.AreEqual(R, Z);
+                }
+            }
+        }
+
+        [Test]
+        public void TestSquare()
+        {
+            int COUNT = 1000;
+
+            for (int i = 0; i < COUNT; ++i)
+            {
+                ECFieldElement x = GenerateMultiplyInput_Random();
+
+                BigInteger X = x.ToBigInteger();
+                BigInteger R = X.Multiply(X).Mod(Q);
+
+                ECFieldElement z = x.Square();
+                BigInteger Z = z.ToBigInteger();
+
+                Assert.AreEqual(R, Z);
+            }
+        }
+
+        [Test]
+        public void TestSquare_CarryBug()
+        {
+            int COUNT = 100;
+
+            for (int i = 0; i < COUNT; ++i)
+            {
+                ECFieldElement x = GenerateSquareInput_CarryBug();
+
+                BigInteger X = x.ToBigInteger();
+                BigInteger R = X.Multiply(X).Mod(Q);
+
+                ECFieldElement z = x.Square();
+                BigInteger Z = z.ToBigInteger();
+
+                Assert.AreEqual(R, Z);
+            }
+        }
+
+        /*
+         * Based on another example input demonstrating the carry propagation bug in Nat192.square, as
+         * reported by Joseph Friel on dev-crypto.
+         */
+        [Test]
+        public void TestSquare_CarryBug_Reported()
+        {
+            ECFieldElement x = FE(new BigInteger("2fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd", 16));
+
+            BigInteger X = x.ToBigInteger();
+            BigInteger R = X.Multiply(X).Mod(Q);
+
+            ECFieldElement z = x.Square();
+            BigInteger Z = z.ToBigInteger();
+
+            Assert.AreEqual(R, Z);
+        }
+
+        private ECFieldElement FE(BigInteger x)
+        {
+            return DP.Curve.FromBigInteger(x);
+        }
+
+        private ECFieldElement GenerateMultiplyInput_Random()
+        {
+            return FE(new BigInteger(DP.Curve.FieldSize + 32, Random).Mod(Q));
+        }
+
+        private ECFieldElement GenerateSquareInput_CarryBug()
+        {
+            uint[] x = Nat.Create(12);
+            x[0] = (uint)Random.NextInt() >> 1;
+            x[6] = 2;
+            x[10] = 0xFFFF0000;
+            x[11] = 0xFFFFFFFF;
+
+            return FE(Nat.ToBigInteger(12, x));
+        }
+    }
+}
diff --git a/crypto/test/src/openpgp/test/PGPNoPrivateKeyTest.cs b/crypto/test/src/openpgp/test/PGPNoPrivateKeyTest.cs
index edb96b149..8f702b67b 100644
--- a/crypto/test/src/openpgp/test/PGPNoPrivateKeyTest.cs
+++ b/crypto/test/src/openpgp/test/PGPNoPrivateKeyTest.cs
@@ -10,7 +10,7 @@ using Org.BouncyCastle.Utilities.Test;
 namespace Org.BouncyCastle.Bcpg.OpenPgp.Tests
 {
     [TestFixture]
-    public class PGPNoPrivateKeyTest
+    public class PgpNoPrivateKeyTest
         : SimpleTest
     {
         private static string pgpOldPass = "test";
@@ -155,7 +155,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp.Tests
         public static void Main(
             string[] args)
         {
-            RunTest(new PGPNoPrivateKeyTest());
+            RunTest(new PgpNoPrivateKeyTest());
         }
 
         [Test]
diff --git a/crypto/test/src/openpgp/test/RegressionTest.cs b/crypto/test/src/openpgp/test/RegressionTest.cs
index c784a19c8..329960bd8 100644
--- a/crypto/test/src/openpgp/test/RegressionTest.cs
+++ b/crypto/test/src/openpgp/test/RegressionTest.cs
@@ -19,7 +19,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp.Tests
             new PgpSignatureTest(),
             new PgpClearSignedSignatureTest(),
             new PgpCompressionTest(),
-            new PGPNoPrivateKeyTest(),
+            new PgpNoPrivateKeyTest(),
             new PgpECDHTest(),
             new PgpECDsaTest(),
             new PgpECMessageTest(),
diff --git a/crypto/test/src/test/nist/NistCertPathTest.cs b/crypto/test/src/test/nist/NistCertPathTest.cs
index fed98a778..6a23cac22 100644
--- a/crypto/test/src/test/nist/NistCertPathTest.cs
+++ b/crypto/test/src/test/nist/NistCertPathTest.cs
@@ -185,8 +185,10 @@ namespace Org.BouncyCastle.Tests.Nist
 				new string[] { "NegativeSerialNumberCACert", "InvalidNegativeSerialNumberTest15EE" },
 				new string[] { TRUST_ANCHOR_ROOT_CRL, "NegativeSerialNumberCACRL" },
 				0,
-				"Certificate revocation after Thu Apr 19 14:57:20",
-				"reason: keyCompromise");
+                // NOTE: Date/time part is locale-dependent
+                //"Certificate revocation after Thu Apr 19 14:57:20",
+                "Certificate revocation after",
+                "reason: keyCompromise");
 		}
 
 		//
diff --git a/crypto/test/src/util/test/SimpleTest.cs b/crypto/test/src/util/test/SimpleTest.cs
index bf6c8fb92..fea680832 100644
--- a/crypto/test/src/util/test/SimpleTest.cs
+++ b/crypto/test/src/util/test/SimpleTest.cs
@@ -27,6 +27,12 @@ namespace Org.BouncyCastle.Utilities.Test
             throw new TestFailedException(SimpleTestResult.Failed(this, message));
         }
 
+        internal void IsTrue(string message, bool value)
+        {
+            if (!value)
+                throw new TestFailedException(SimpleTestResult.Failed(this, message));
+        }
+
         internal void Fail(
             string		message,
             Exception	throwable)