summary refs log tree commit diff
path: root/crypto/src
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2015-10-17 14:35:17 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2015-10-17 14:35:17 +0700
commit2bb4400d228fd41191bc7aac4f1529c9c02a4e83 (patch)
treeecb69c6bdf10787751f5543864917a02bd91dfcc /crypto/src
parentMerge branch 'master' of https://github.com/avanpo/bc-csharp into avanpo-master (diff)
downloadBouncyCastle.NET-ed25519-2bb4400d228fd41191bc7aac4f1529c9c02a4e83.tar.xz
Various JPAKE changes to fit existing code conventions
- Update project file with new entries
- Tests moved to crypto/agreement/test
Diffstat (limited to 'crypto/src')
-rwxr-xr-xcrypto/src/crypto/agreement/jpake/JPAKEParticipant.cs162
-rwxr-xr-xcrypto/src/crypto/agreement/jpake/JPAKEPrimeOrderGroup.cs45
-rwxr-xr-xcrypto/src/crypto/agreement/jpake/JPAKEPrimeOrderGroups.cs10
-rwxr-xr-xcrypto/src/crypto/agreement/jpake/JPAKERound1Payload.cs28
-rwxr-xr-xcrypto/src/crypto/agreement/jpake/JPAKERound2Payload.cs20
-rwxr-xr-xcrypto/src/crypto/agreement/jpake/JPAKERound3Payload.cs12
-rw-r--r--[-rwxr-xr-x]crypto/src/crypto/agreement/jpake/JPakeUtilities.cs (renamed from crypto/src/crypto/agreement/jpake/JPAKEUtil.cs)125
7 files changed, 178 insertions, 224 deletions
diff --git a/crypto/src/crypto/agreement/jpake/JPAKEParticipant.cs b/crypto/src/crypto/agreement/jpake/JPAKEParticipant.cs
index 0874f3d83..f8ca2cd41 100755
--- a/crypto/src/crypto/agreement/jpake/JPAKEParticipant.cs
+++ b/crypto/src/crypto/agreement/jpake/JPAKEParticipant.cs
@@ -5,7 +5,7 @@ using Org.BouncyCastle.Crypto.Digests;
 using Org.BouncyCastle.Math;
 using Org.BouncyCastle.Security;
 
-namespace Org.BouncyCastle.Crypto.Agreement.Jpake
+namespace Org.BouncyCastle.Crypto.Agreement.JPake
 {
     /// <summary>
     /// A participant in a Password Authenticated Key Exchange by Juggling (J-PAKE) exchange.
@@ -16,20 +16,20 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
     ///
     /// The J-PAKE protocol is symmetric.
     /// There is no notion of a <i>client</i> or <i>server</i>, but rather just two <i>participants</i>.
-    /// An instance of JPAKEParticipant represents one participant, and
+    /// An instance of JPakeParticipant represents one participant, and
     /// is the primary interface for executing the exchange.
     ///
-    /// To execute an exchange, construct a JPAKEParticipant on each end,
+    /// To execute an exchange, construct a JPakeParticipant on each end,
     /// and call the following 7 methods
     /// (once and only once, in the given order, for each participant, sending messages between them as described):
     ///
     /// CreateRound1PayloadToSend() - and send the payload to the other participant
-    /// ValidateRound1PayloadReceived(JPAKERound1Payload) - use the payload received from the other participant
+    /// ValidateRound1PayloadReceived(JPakeRound1Payload) - use the payload received from the other participant
     /// CreateRound2PayloadToSend() - and send the payload to the other participant
-    /// ValidateRound2PayloadReceived(JPAKERound2Payload) - use the payload received from the other participant
+    /// ValidateRound2PayloadReceived(JPakeRound2Payload) - use the payload received from the other participant
     /// CalculateKeyingMaterial()
     /// CreateRound3PayloadToSend(BigInteger) - and send the payload to the other participant
-    /// ValidateRound3PayloadReceived(JPAKERound3Payload, BigInteger) - use the payload received from the other participant
+    /// ValidateRound3PayloadReceived(JPakeRound3Payload, BigInteger) - use the payload received from the other participant
     ///
     /// Each side should derive a session key from the keying material returned by CalculateKeyingMaterial().
     /// The caller is responsible for deriving the session key using a secure key derivation function (KDF).
@@ -51,9 +51,9 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
     ///
     /// This class is stateful and NOT threadsafe.
     /// Each instance should only be used for ONE complete J-PAKE exchange
-    /// (i.e. a new JPAKEParticipant should be constructed for each new J-PAKE exchange).
+    /// (i.e. a new JPakeParticipant should be constructed for each new J-PAKE exchange).
     /// </summary>
-    public class JPAKEParticipant
+    public class JPakeParticipant
     {
         // Possible internal states.  Used for state checking.
         public static readonly int STATE_INITIALIZED = 0;
@@ -109,8 +109,8 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
         private int state;
 
         /// <summary>
-        /// Convenience constructor for a new JPAKEParticipant that uses
-        /// the JPAKEPrimeOrderGroups#NIST_3072 prime order group,
+        /// Convenience constructor for a new JPakeParticipant that uses
+        /// the JPakePrimeOrderGroups#NIST_3072 prime order group,
         /// a SHA-256 digest, and a default SecureRandom implementation.
         ///
         /// After construction, the State state will be STATE_INITIALIZED.
@@ -123,11 +123,11 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
         /// <param name="password">Shared secret.
         ///      A defensive copy of this array is made (and cleared once CalculateKeyingMaterial() is called).
         ///      Caller should clear the input password as soon as possible.</param>
-        public JPAKEParticipant(string participantId, char[] password)
-            : this(participantId, password, JPAKEPrimeOrderGroups.NIST_3072) { }
+        public JPakeParticipant(string participantId, char[] password)
+            : this(participantId, password, JPakePrimeOrderGroups.NIST_3072) { }
 
         /// <summary>
-        /// Convenience constructor for a new JPAKEParticipant that uses
+        /// Convenience constructor for a new JPakeParticipant that uses
         /// a SHA-256 digest, and a default SecureRandom implementation.
         ///
         /// After construction, the State state will be STATE_INITIALIZED.
@@ -140,13 +140,13 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
         /// <param name="password">Shared secret.
         ///      A defensive copy of this array is made (and cleared once CalculateKeyingMaterial() is called).
         ///      Caller should clear the input password as soon as possible.</param>
-        /// <param name="group">Prime order group. See JPAKEPrimeOrderGroups for standard groups.</param>
-        public JPAKEParticipant(string participantId, char[] password, JPAKEPrimeOrderGroup group)
+        /// <param name="group">Prime order group. See JPakePrimeOrderGroups for standard groups.</param>
+        public JPakeParticipant(string participantId, char[] password, JPakePrimeOrderGroup group)
             : this(participantId, password, group, new Sha256Digest(), new SecureRandom()) { }
 
 
         /// <summary>
-        /// Constructor for a new JPAKEParticipant.
+        /// Constructor for a new JPakeParticipant.
         ///
         /// After construction, the State state will be STATE_INITIALIZED.
         /// 
@@ -158,17 +158,17 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
         /// <param name="password">Shared secret.
         ///      A defensive copy of this array is made (and cleared once CalculateKeyingMaterial() is called).
         ///      Caller should clear the input password as soon as possible.</param>
-        /// <param name="group">Prime order group. See JPAKEPrimeOrderGroups for standard groups.</param>
+        /// <param name="group">Prime order group. See JPakePrimeOrderGroups for standard groups.</param>
         /// <param name="digest">Digest to use during zero knowledge proofs and key confirmation
         ///     (SHA-256 or stronger preferred).</param>
         /// <param name="random">Source of secure random data for x1 and x2, and for the zero knowledge proofs.</param>
-        public JPAKEParticipant(string participantId, char[] password, JPAKEPrimeOrderGroup group, IDigest digest, SecureRandom random)
+        public JPakeParticipant(string participantId, char[] password, JPakePrimeOrderGroup group, IDigest digest, SecureRandom random)
         {
-            JPAKEUtil.ValidateNotNull(participantId, "participantId");
-            JPAKEUtil.ValidateNotNull(password, "password");
-            JPAKEUtil.ValidateNotNull(group, "p");
-            JPAKEUtil.ValidateNotNull(digest, "digest");
-            JPAKEUtil.ValidateNotNull(random, "random");
+            JPakeUtilities.ValidateNotNull(participantId, "participantId");
+            JPakeUtilities.ValidateNotNull(password, "password");
+            JPakeUtilities.ValidateNotNull(group, "p");
+            JPakeUtilities.ValidateNotNull(digest, "digest");
+            JPakeUtilities.ValidateNotNull(random, "random");
 
             if (password.Length == 0)
             {
@@ -204,7 +204,7 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
         /// Gets the current state of this participant.
         /// See the <tt>STATE_*</tt> constants for possible values.
         /// </summary>
-        public int State
+        public virtual int State
         {
             get { return state; }
         }
@@ -215,24 +215,22 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
         ///
         /// After execution, the State state} will be STATE_ROUND_1_CREATED}.
         /// </summary>
-        public JPAKERound1Payload CreateRound1PayloadToSend()
+        public virtual JPakeRound1Payload CreateRound1PayloadToSend()
         {
             if (this.state >= STATE_ROUND_1_CREATED)
-            {
                 throw new InvalidOperationException("Round 1 payload already created for " + this.participantId);
-            }
 
-            this.x1 = JPAKEUtil.GenerateX1(q, random);
-            this.x2 = JPAKEUtil.GenerateX2(q, random);
+            this.x1 = JPakeUtilities.GenerateX1(q, random);
+            this.x2 = JPakeUtilities.GenerateX2(q, random);
 
-            this.gx1 = JPAKEUtil.CalculateGx(p, g, x1);
-            this.gx2 = JPAKEUtil.CalculateGx(p, g, x2);
-            BigInteger[] knowledgeProofForX1 = JPAKEUtil.CalculateZeroKnowledgeProof(p, q, g, gx1, x1, participantId, digest, random);
-            BigInteger[] knowledgeProofForX2 = JPAKEUtil.CalculateZeroKnowledgeProof(p, q, g, gx2, x2, participantId, digest, random);
+            this.gx1 = JPakeUtilities.CalculateGx(p, g, x1);
+            this.gx2 = JPakeUtilities.CalculateGx(p, g, x2);
+            BigInteger[] knowledgeProofForX1 = JPakeUtilities.CalculateZeroKnowledgeProof(p, q, g, gx1, x1, participantId, digest, random);
+            BigInteger[] knowledgeProofForX2 = JPakeUtilities.CalculateZeroKnowledgeProof(p, q, g, gx2, x2, participantId, digest, random);
 
             this.state = STATE_ROUND_1_CREATED;
 
-            return new JPAKERound1Payload(participantId, gx1, gx2, knowledgeProofForX1, knowledgeProofForX2);
+            return new JPakeRound1Payload(participantId, gx1, gx2, knowledgeProofForX1, knowledgeProofForX2);
         }
 
         /// <summary>
@@ -245,12 +243,10 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
         /// Throws CryptoException if validation fails. Throws InvalidOperationException
         /// if called multiple times.
         /// </summary>
-        public void ValidateRound1PayloadReceived(JPAKERound1Payload round1PayloadReceived)
+        public virtual void ValidateRound1PayloadReceived(JPakeRound1Payload round1PayloadReceived)
         {
             if (this.state >= STATE_ROUND_1_VALIDATED)
-            {
                 throw new InvalidOperationException("Validation already attempted for round 1 payload for " + this.participantId);
-            }
 
             this.partnerParticipantId = round1PayloadReceived.ParticipantId;
             this.gx3 = round1PayloadReceived.Gx1;
@@ -259,42 +255,38 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
             BigInteger[] knowledgeProofForX3 = round1PayloadReceived.KnowledgeProofForX1;
             BigInteger[] knowledgeProofForX4 = round1PayloadReceived.KnowledgeProofForX2;
 
-            JPAKEUtil.ValidateParticipantIdsDiffer(participantId, round1PayloadReceived.ParticipantId);
-            JPAKEUtil.ValidateGx4(gx4);
-            JPAKEUtil.ValidateZeroKnowledgeProof(p, q, g, gx3, knowledgeProofForX3, round1PayloadReceived.ParticipantId, digest);
-            JPAKEUtil.ValidateZeroKnowledgeProof(p, q, g, gx4, knowledgeProofForX4, round1PayloadReceived.ParticipantId, digest); 
+            JPakeUtilities.ValidateParticipantIdsDiffer(participantId, round1PayloadReceived.ParticipantId);
+            JPakeUtilities.ValidateGx4(gx4);
+            JPakeUtilities.ValidateZeroKnowledgeProof(p, q, g, gx3, knowledgeProofForX3, round1PayloadReceived.ParticipantId, digest);
+            JPakeUtilities.ValidateZeroKnowledgeProof(p, q, g, gx4, knowledgeProofForX4, round1PayloadReceived.ParticipantId, digest); 
             this.state = STATE_ROUND_1_VALIDATED;
         }
 
         /// <summary>
         /// Creates and returns the payload to send to the other participant during round 2.
         ///
-        /// ValidateRound1PayloadReceived(JPAKERound1Payload) must be called prior to this method.
+        /// ValidateRound1PayloadReceived(JPakeRound1Payload) must be called prior to this method.
         ///
         /// After execution, the State state will be  STATE_ROUND_2_CREATED.
         ///
-        /// Throws InvalidOperationException if called prior to ValidateRound1PayloadReceived(JPAKERound1Payload), or multiple times
+        /// Throws InvalidOperationException if called prior to ValidateRound1PayloadReceived(JPakeRound1Payload), or multiple times
         /// </summary>
-        public JPAKERound2Payload CreateRound2PayloadToSend()
+        public virtual JPakeRound2Payload CreateRound2PayloadToSend()
         {
             if (this.state >= STATE_ROUND_2_CREATED)
-            {
                 throw new InvalidOperationException("Round 2 payload already created for " + this.participantId);
-            }
             if (this.state < STATE_ROUND_1_VALIDATED)
-            {
                 throw new InvalidOperationException("Round 1 payload must be validated prior to creating round 2 payload for " + this.participantId);
-            }
 
-            BigInteger gA = JPAKEUtil.CalculateGA(p, gx1, gx3, gx4);
-            BigInteger s = JPAKEUtil.CalculateS(password);
-            BigInteger x2s = JPAKEUtil.CalculateX2s(q, x2, s);
-            BigInteger A = JPAKEUtil.CalculateA(p, q, gA, x2s);
-            BigInteger[] knowledgeProofForX2s = JPAKEUtil.CalculateZeroKnowledgeProof(p, q, gA, A, x2s, participantId, digest, random);
+            BigInteger gA = JPakeUtilities.CalculateGA(p, gx1, gx3, gx4);
+            BigInteger s = JPakeUtilities.CalculateS(password);
+            BigInteger x2s = JPakeUtilities.CalculateX2s(q, x2, s);
+            BigInteger A = JPakeUtilities.CalculateA(p, q, gA, x2s);
+            BigInteger[] knowledgeProofForX2s = JPakeUtilities.CalculateZeroKnowledgeProof(p, q, gA, A, x2s, participantId, digest, random);
 
             this.state = STATE_ROUND_2_CREATED;
 
-            return new JPAKERound2Payload(participantId, A, knowledgeProofForX2s);
+            return new JPakeRound2Payload(participantId, A, knowledgeProofForX2s);
         }
 
         /// <summary>
@@ -308,27 +300,23 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
         /// After execution, the State state will be STATE_ROUND_2_VALIDATED.
         ///
         /// Throws CryptoException if validation fails. Throws
-        /// InvalidOperationException if called prior to ValidateRound1PayloadReceived(JPAKERound1Payload), or multiple times
+        /// InvalidOperationException if called prior to ValidateRound1PayloadReceived(JPakeRound1Payload), or multiple times
         /// </summary>
-        public void ValidateRound2PayloadReceived(JPAKERound2Payload round2PayloadReceived)
+        public virtual void ValidateRound2PayloadReceived(JPakeRound2Payload round2PayloadReceived)
         {
             if (this.state >= STATE_ROUND_2_VALIDATED)
-            {
                 throw new InvalidOperationException("Validation already attempted for round 2 payload for " + this.participantId);
-            }
             if (this.state < STATE_ROUND_1_VALIDATED)
-            {
                 throw new InvalidOperationException("Round 1 payload must be validated prior to validation round 2 payload for " + this.participantId);
-            }
 
-            BigInteger gB = JPAKEUtil.CalculateGA(p, gx3, gx1, gx2);
+            BigInteger gB = JPakeUtilities.CalculateGA(p, gx3, gx1, gx2);
             this.b = round2PayloadReceived.A;
             BigInteger[] knowledgeProofForX4s = round2PayloadReceived.KnowledgeProofForX2s;
 
-            JPAKEUtil.ValidateParticipantIdsDiffer(participantId, round2PayloadReceived.ParticipantId);
-            JPAKEUtil.ValidateParticipantIdsEqual(this.partnerParticipantId, round2PayloadReceived.ParticipantId);
-            JPAKEUtil.ValidateGa(gB);
-            JPAKEUtil.ValidateZeroKnowledgeProof(p, q, gB, b, knowledgeProofForX4s, round2PayloadReceived.ParticipantId, digest);
+            JPakeUtilities.ValidateParticipantIdsDiffer(participantId, round2PayloadReceived.ParticipantId);
+            JPakeUtilities.ValidateParticipantIdsEqual(this.partnerParticipantId, round2PayloadReceived.ParticipantId);
+            JPakeUtilities.ValidateGa(gB);
+            JPakeUtilities.ValidateZeroKnowledgeProof(p, q, gB, b, knowledgeProofForX4s, round2PayloadReceived.ParticipantId, digest);
 
             this.state = STATE_ROUND_2_VALIDATED;
         }
@@ -336,7 +324,7 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
         /// <summary>
         /// Calculates and returns the key material.
         /// A session key must be derived from this key material using a secure key derivation function (KDF).
-        /// The KDF used to derive the key is handled externally (i.e. not by JPAKEParticipant).
+        /// The KDF used to derive the key is handled externally (i.e. not by JPakeParticipant).
         ///
         /// The keying material will be identical for each participant if and only if
         /// each participant's password is the same.  i.e. If the participants do not
@@ -344,39 +332,35 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
         /// Therefore, if you immediately start using a key derived from
         /// the keying material, then you must handle detection of incorrect keys.
         /// If you want to handle this detection explicitly, you can optionally perform
-        /// rounds 3 and 4.  See JPAKEParticipant for details on how to execute
+        /// rounds 3 and 4.  See JPakeParticipant for details on how to execute
         /// rounds 3 and 4.
         ///
         /// The keying material will be in the range <tt>[0, p-1]</tt>.
         ///
-        /// ValidateRound2PayloadReceived(JPAKERound2Payload) must be called prior to this method.
+        /// ValidateRound2PayloadReceived(JPakeRound2Payload) must be called prior to this method.
         /// 
         /// As a side effect, the internal password array is cleared, since it is no longer needed.
         ///
         /// After execution, the State state will be STATE_KEY_CALCULATED.
         ///
-        /// Throws InvalidOperationException if called prior to ValidateRound2PayloadReceived(JPAKERound2Payload),
+        /// Throws InvalidOperationException if called prior to ValidateRound2PayloadReceived(JPakeRound2Payload),
         /// or if called multiple times.
         /// </summary>
-        public BigInteger CalculateKeyingMaterial()
+        public virtual BigInteger CalculateKeyingMaterial()
         {
             if (this.state >= STATE_KEY_CALCULATED)
-            {
                 throw new InvalidOperationException("Key already calculated for " + participantId);
-            }
             if (this.state < STATE_ROUND_2_VALIDATED)
-            {
                 throw new InvalidOperationException("Round 2 payload must be validated prior to creating key for " + participantId);
-            }
 
-            BigInteger s = JPAKEUtil.CalculateS(password);
+            BigInteger s = JPakeUtilities.CalculateS(password);
 
             // Clear the password array from memory, since we don't need it anymore.
             // Also set the field to null as a flag to indicate that the key has already been calculated.
             Array.Clear(password, 0, password.Length);
             this.password = null;
 
-            BigInteger keyingMaterial = JPAKEUtil.CalculateKeyingMaterial(p, q, gx4, x2, s, b);
+            BigInteger keyingMaterial = JPakeUtilities.CalculateKeyingMaterial(p, q, gx4, x2, s, b);
 
             // Clear the ephemeral private key fields as well.
             // Note that we're relying on the garbage collector to do its job to clean these up.
@@ -398,25 +382,21 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
         /// <summary>
         /// Creates and returns the payload to send to the other participant during round 3.
         ///
-        /// See JPAKEParticipant for more details on round 3.
+        /// See JPakeParticipant for more details on round 3.
         ///
         /// After execution, the State state} will be  STATE_ROUND_3_CREATED.
         /// Throws InvalidOperationException if called prior to CalculateKeyingMaterial, or multiple
         /// times.
         /// </summary>
         /// <param name="keyingMaterial">The keying material as returned from CalculateKeyingMaterial().</param> 
-        public JPAKERound3Payload CreateRound3PayloadToSend(BigInteger keyingMaterial)
+        public virtual JPakeRound3Payload CreateRound3PayloadToSend(BigInteger keyingMaterial)
         {
             if (this.state >= STATE_ROUND_3_CREATED)
-            {
                 throw new InvalidOperationException("Round 3 payload already created for " + this.participantId);
-            }
             if (this.state < STATE_KEY_CALCULATED)
-            {
                 throw new InvalidOperationException("Keying material must be calculated prior to creating round 3 payload for " + this.participantId);
-            }
 
-            BigInteger macTag = JPAKEUtil.CalculateMacTag(
+            BigInteger macTag = JPakeUtilities.CalculateMacTag(
                 this.participantId,
                 this.partnerParticipantId,
                 this.gx1,
@@ -428,13 +408,13 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
 
             this.state = STATE_ROUND_3_CREATED;
 
-            return new JPAKERound3Payload(participantId, macTag);
+            return new JPakeRound3Payload(participantId, macTag);
         }
 
         /// <summary>
         /// Validates the payload received from the other participant during round 3.
         ///
-        /// See JPAKEParticipant for more details on round 3.
+        /// See JPakeParticipant for more details on round 3.
         ///
         /// After execution, the State state will be STATE_ROUND_3_VALIDATED.
         /// 
@@ -442,21 +422,17 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
         /// CalculateKeyingMaterial or multiple times
         /// </summary>
         /// <param name="keyingMaterial">The keying material as returned from CalculateKeyingMaterial().</param> 
-        public void ValidateRound3PayloadReceived(JPAKERound3Payload round3PayloadReceived, BigInteger keyingMaterial)
+        public virtual void ValidateRound3PayloadReceived(JPakeRound3Payload round3PayloadReceived, BigInteger keyingMaterial)
         {
             if (this.state >= STATE_ROUND_3_VALIDATED)
-            {
                 throw new InvalidOperationException("Validation already attempted for round 3 payload for " + this.participantId);
-            }
             if (this.state < STATE_KEY_CALCULATED)
-            {
                 throw new InvalidOperationException("Keying material must be calculated prior to validating round 3 payload for " + this.participantId);
-            }
 
-            JPAKEUtil.ValidateParticipantIdsDiffer(participantId, round3PayloadReceived.ParticipantId);
-            JPAKEUtil.ValidateParticipantIdsEqual(this.partnerParticipantId, round3PayloadReceived.ParticipantId);
+            JPakeUtilities.ValidateParticipantIdsDiffer(participantId, round3PayloadReceived.ParticipantId);
+            JPakeUtilities.ValidateParticipantIdsEqual(this.partnerParticipantId, round3PayloadReceived.ParticipantId);
 
-            JPAKEUtil.ValidateMacTag(
+            JPakeUtilities.ValidateMacTag(
                 this.participantId,
                 this.partnerParticipantId,
                 this.gx1,
diff --git a/crypto/src/crypto/agreement/jpake/JPAKEPrimeOrderGroup.cs b/crypto/src/crypto/agreement/jpake/JPAKEPrimeOrderGroup.cs
index 3a142f713..08ffe1a55 100755
--- a/crypto/src/crypto/agreement/jpake/JPAKEPrimeOrderGroup.cs
+++ b/crypto/src/crypto/agreement/jpake/JPAKEPrimeOrderGroup.cs
@@ -2,7 +2,7 @@
 
 using Org.BouncyCastle.Math;
 
-namespace Org.BouncyCastle.Crypto.Agreement.Jpake
+namespace Org.BouncyCastle.Crypto.Agreement.JPake
 {
     /// <summary>
     /// A pre-computed prime order group for use during a J-PAKE exchange.
@@ -10,22 +10,22 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
     /// Typically a Schnorr group is used.  In general, J-PAKE can use any prime order group
     /// that is suitable for public key cryptography, including elliptic curve cryptography.
     ///
-    /// See JPAKEPrimeOrderGroups for convenient standard groups.
+    /// See JPakePrimeOrderGroups for convenient standard groups.
     ///
     /// NIST <a href="http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/DSA2_All.pdf">publishes</a>
     /// many groups that can be used for the desired level of security.
     /// </summary>
-    public class JPAKEPrimeOrderGroup
+    public class JPakePrimeOrderGroup
     {
         private readonly BigInteger p;
         private readonly BigInteger q;
         private readonly BigInteger g;
 
         /// <summary>
-        /// Constructs a new JPAKEPrimeOrderGroup.
+        /// Constructs a new JPakePrimeOrderGroup.
         ///
         /// In general, you should use one of the pre-approved groups from
-        /// JPAKEPrimeOrderGroups, rather than manually constructing one.
+        /// JPakePrimeOrderGroups, rather than manually constructing one.
         ///
         /// The following basic checks are performed:
         ///
@@ -46,47 +46,38 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
         /// Throws NullReferenceException if any argument is null. Throws
         /// InvalidOperationException is any of the above validations fail.
         /// </summary>
-        public JPAKEPrimeOrderGroup(BigInteger p, BigInteger q, BigInteger g)
+        public JPakePrimeOrderGroup(BigInteger p, BigInteger q, BigInteger g)
             : this(p, q, g, false)
         {
              // Don't skip the checks on user-specified groups.
         }
 
         /// <summary>
-        /// Constructor used by the pre-approved groups in JPAKEPrimeOrderGroups.
+        /// Constructor used by the pre-approved groups in JPakePrimeOrderGroups.
         /// These pre-approved groups can avoid the expensive checks.
         /// User-specified groups should not use this constructor.
         /// </summary>
-        public JPAKEPrimeOrderGroup(BigInteger p, BigInteger q, BigInteger g, bool skipChecks)
+        public JPakePrimeOrderGroup(BigInteger p, BigInteger q, BigInteger g, bool skipChecks)
         {
-            JPAKEUtil.ValidateNotNull(p, "p");
-            JPAKEUtil.ValidateNotNull(q, "q");
-            JPAKEUtil.ValidateNotNull(g, "g");
+            JPakeUtilities.ValidateNotNull(p, "p");
+            JPakeUtilities.ValidateNotNull(q, "q");
+            JPakeUtilities.ValidateNotNull(g, "g");
 
             if (!skipChecks)
             {
-                if (!p.Subtract(JPAKEUtil.ONE).Mod(q).Equals(JPAKEUtil.ZERO))
-                {
+                if (!p.Subtract(JPakeUtilities.One).Mod(q).Equals(JPakeUtilities.Zero))
                     throw new ArgumentException("p-1 must be evenly divisible by q");
-                }
-                if (g.CompareTo(BigInteger.ValueOf(2)) == -1 || g.CompareTo(p.Subtract(JPAKEUtil.ONE)) == 1)
-                {
+                if (g.CompareTo(BigInteger.Two) == -1 || g.CompareTo(p.Subtract(JPakeUtilities.One)) == 1)
                     throw new ArgumentException("g must be in [2, p-1]");
-                }
-                if (!g.ModPow(q, p).Equals(JPAKEUtil.ONE))
-                {
+                if (!g.ModPow(q, p).Equals(JPakeUtilities.One))
                     throw new ArgumentException("g^q mod p must equal 1");
-                }
+
                 // Note these checks do not guarantee that p and q are prime.
                 // We just have reasonable certainty that they are prime.
                 if (!p.IsProbablePrime(20))
-                {
                     throw new ArgumentException("p must be prime");
-                }
                 if (!q.IsProbablePrime(20))
-                {
                     throw new ArgumentException("q must be prime");
-                }
             }
 
             this.p = p;
@@ -94,17 +85,17 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
             this.g = g;
         }
 
-        public BigInteger P
+        public virtual BigInteger P
         {
             get { return p; }
         }
 
-        public BigInteger Q
+        public virtual BigInteger Q
         {
             get { return q; }
         }
 
-        public BigInteger G
+        public virtual BigInteger G
         {
             get { return g; }
         }
diff --git a/crypto/src/crypto/agreement/jpake/JPAKEPrimeOrderGroups.cs b/crypto/src/crypto/agreement/jpake/JPAKEPrimeOrderGroups.cs
index aeaff6f72..33640845a 100755
--- a/crypto/src/crypto/agreement/jpake/JPAKEPrimeOrderGroups.cs
+++ b/crypto/src/crypto/agreement/jpake/JPAKEPrimeOrderGroups.cs
@@ -1,6 +1,6 @@
 using Org.BouncyCastle.Math;
 
-namespace Org.BouncyCastle.Crypto.Agreement.Jpake
+namespace Org.BouncyCastle.Crypto.Agreement.JPake
 {
     /// <summary>
     /// Standard pre-computed prime order groups for use by J-PAKE.
@@ -13,13 +13,13 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
     /// and from the prime order groups
     /// <a href="http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/DSA2_All.pdf">published by NIST</a>.
     /// </summary>
-    public class JPAKEPrimeOrderGroups
+    public class JPakePrimeOrderGroups
     {
         /// <summary>
         /// From Sun's JDK JavaDoc (docs/guide/security/CryptoSpec.html#AppB)
         /// 1024-bit p, 160-bit q and 1024-bit g for 80-bit security.
         /// </summary>
-        public static readonly JPAKEPrimeOrderGroup SUN_JCE_1024 = new JPAKEPrimeOrderGroup(
+        public static readonly JPakePrimeOrderGroup SUN_JCE_1024 = new JPakePrimeOrderGroup(
             // p
             new BigInteger(
                 "fd7f53811d75122952df4a9c2eece4e7f611b7523cef4400c31e3f80b6512669" +
@@ -41,7 +41,7 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
         /// From NIST.
         /// 2048-bit p, 224-bit q and 2048-bit g for 112-bit security.
         /// </summary>
-        public static readonly JPAKEPrimeOrderGroup NIST_2048 = new JPAKEPrimeOrderGroup(
+        public static readonly JPakePrimeOrderGroup NIST_2048 = new JPakePrimeOrderGroup(
             // p
             new BigInteger(
                 "C196BA05AC29E1F9C3C72D56DFFC6154A033F1477AC88EC37F09BE6C5BB95F51" +
@@ -71,7 +71,7 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
         /// From NIST.
         /// 3072-bit p, 256-bit q and 3072-bit g for 128-bit security.
         /// </summary>
-        public static readonly JPAKEPrimeOrderGroup NIST_3072 = new JPAKEPrimeOrderGroup(
+        public static readonly JPakePrimeOrderGroup NIST_3072 = new JPakePrimeOrderGroup(
             // p
             new BigInteger(
                 "90066455B5CFC38F9CAA4A48B4281F292C260FEEF01FD61037E56258A7795A1C" +
diff --git a/crypto/src/crypto/agreement/jpake/JPAKERound1Payload.cs b/crypto/src/crypto/agreement/jpake/JPAKERound1Payload.cs
index 7b638dabd..9e4ab7a5f 100755
--- a/crypto/src/crypto/agreement/jpake/JPAKERound1Payload.cs
+++ b/crypto/src/crypto/agreement/jpake/JPAKERound1Payload.cs
@@ -2,7 +2,7 @@
 
 using Org.BouncyCastle.Math;
 
-namespace Org.BouncyCastle.Crypto.Agreement.Jpake
+namespace Org.BouncyCastle.Crypto.Agreement.JPake
 {
     /// <summary>
     /// The payload sent/received during the first round of a J-PAKE exchange.
@@ -13,9 +13,9 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
     /// 
     /// Each participant must also validate the payload received from the other.
     /// The received payload should be validated via 
-    /// JPAKEParticipant.ValidateRound1PayloadReceived(JPAKERound1Payload).
+    /// JPAKEParticipant.ValidateRound1PayloadReceived(JPakeRound1Payload).
     /// </summary>
-    public class JPAKERound1Payload
+    public class JPakeRound1Payload
     {
         /// <summary>
         /// The id of the JPAKEParticipant who created/sent this payload.
@@ -46,13 +46,13 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
         /// </summary>
         private readonly BigInteger[] knowledgeProofForX2;
 
-        public JPAKERound1Payload(string participantId, BigInteger gx1, BigInteger gx2, BigInteger[] knowledgeProofForX1, BigInteger[] knowledgeProofForX2)
+        public JPakeRound1Payload(string participantId, BigInteger gx1, BigInteger gx2, BigInteger[] knowledgeProofForX1, BigInteger[] knowledgeProofForX2)
         {
-            JPAKEUtil.ValidateNotNull(participantId, "participantId");
-            JPAKEUtil.ValidateNotNull(gx1, "gx1");
-            JPAKEUtil.ValidateNotNull(gx2, "gx2");
-            JPAKEUtil.ValidateNotNull(knowledgeProofForX1, "knowledgeProofForX1");
-            JPAKEUtil.ValidateNotNull(knowledgeProofForX2, "knowledgeProofForX2");
+            JPakeUtilities.ValidateNotNull(participantId, "participantId");
+            JPakeUtilities.ValidateNotNull(gx1, "gx1");
+            JPakeUtilities.ValidateNotNull(gx2, "gx2");
+            JPakeUtilities.ValidateNotNull(knowledgeProofForX1, "knowledgeProofForX1");
+            JPakeUtilities.ValidateNotNull(knowledgeProofForX2, "knowledgeProofForX2");
 
             this.participantId = participantId;
             this.gx1 = gx1;
@@ -63,22 +63,22 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
             Array.Copy(knowledgeProofForX2, this.knowledgeProofForX2, knowledgeProofForX2.Length);
         }
 
-        public string ParticipantId
+        public virtual string ParticipantId
         {
             get { return participantId; }
         }
 
-        public BigInteger Gx1
+        public virtual BigInteger Gx1
         {
             get { return gx1; }
         }
 
-        public BigInteger Gx2
+        public virtual BigInteger Gx2
         {
             get { return gx2; }
         }
 
-        public BigInteger[] KnowledgeProofForX1
+        public virtual BigInteger[] KnowledgeProofForX1
         {
             get
             {
@@ -88,7 +88,7 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
             }
         }
 
-        public BigInteger[] KnowledgeProofForX2
+        public virtual BigInteger[] KnowledgeProofForX2
         {
             get
             {
diff --git a/crypto/src/crypto/agreement/jpake/JPAKERound2Payload.cs b/crypto/src/crypto/agreement/jpake/JPAKERound2Payload.cs
index cf1a8575e..47962cb3f 100755
--- a/crypto/src/crypto/agreement/jpake/JPAKERound2Payload.cs
+++ b/crypto/src/crypto/agreement/jpake/JPAKERound2Payload.cs
@@ -3,7 +3,7 @@
 using Org.BouncyCastle.Math;
 using Org.BouncyCastle.Utilities;
 
-namespace Org.BouncyCastle.Crypto.Agreement.Jpake
+namespace Org.BouncyCastle.Crypto.Agreement.JPake
 {
     /// <summary>
     /// The payload sent/received during the second round of a J-PAKE exchange.
@@ -16,9 +16,9 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
     /// Each JPAKEParticipant must also validate the payload
     /// received from the other JPAKEParticipant.
     /// The received payload should be validated via
-    /// JPAKEParticipant#validateRound2PayloadReceived(JPAKERound2Payload)
+    /// JPAKEParticipant#validateRound2PayloadReceived(JPakeRound2Payload)
     /// </summary>
-    public class JPAKERound2Payload
+    public class JPakeRound2Payload
     {
         /// <summary>
         /// The id of the JPAKEParticipant who created/sent this payload.
@@ -37,11 +37,11 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
         /// </summary>
         private readonly BigInteger[] knowledgeProofForX2s;
 
-        public JPAKERound2Payload(string participantId, BigInteger a, BigInteger[] knowledgeProofForX2s)
+        public JPakeRound2Payload(string participantId, BigInteger a, BigInteger[] knowledgeProofForX2s)
         {
-            JPAKEUtil.ValidateNotNull(participantId, "participantId");
-            JPAKEUtil.ValidateNotNull(a, "a");
-            JPAKEUtil.ValidateNotNull(knowledgeProofForX2s, "knowledgeProofForX2s");
+            JPakeUtilities.ValidateNotNull(participantId, "participantId");
+            JPakeUtilities.ValidateNotNull(a, "a");
+            JPakeUtilities.ValidateNotNull(knowledgeProofForX2s, "knowledgeProofForX2s");
 
             this.participantId = participantId;
             this.a = a;
@@ -49,17 +49,17 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
             knowledgeProofForX2s.CopyTo(this.knowledgeProofForX2s, 0);
         }
 
-        public string ParticipantId
+        public virtual string ParticipantId
         {
             get { return participantId; }
         }
 
-        public BigInteger A
+        public virtual BigInteger A
         {
             get { return a; }
         }
 
-        public BigInteger[] KnowledgeProofForX2s
+        public virtual BigInteger[] KnowledgeProofForX2s
         {
             get
             {
diff --git a/crypto/src/crypto/agreement/jpake/JPAKERound3Payload.cs b/crypto/src/crypto/agreement/jpake/JPAKERound3Payload.cs
index 95e0f24ce..767702f23 100755
--- a/crypto/src/crypto/agreement/jpake/JPAKERound3Payload.cs
+++ b/crypto/src/crypto/agreement/jpake/JPAKERound3Payload.cs
@@ -2,7 +2,7 @@
 
 using Org.BouncyCastle.Math;
 
-namespace Org.BouncyCastle.Crypto.Agreement.Jpake
+namespace Org.BouncyCastle.Crypto.Agreement.JPake
 {
     /// <summary>
     /// The payload sent/received during the optional third round of a J-PAKE exchange,
@@ -16,9 +16,9 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
     /// Eeach JPAKEParticipant must also validate the payload
     /// received from the other JPAKEParticipant.
     /// The received payload should be validated via
-    /// JPAKEParticipant#validateRound3PayloadReceived(JPAKERound3Payload, BigInteger)
+    /// JPAKEParticipant#validateRound3PayloadReceived(JPakeRound3Payload, BigInteger)
     /// </summary>
-    public class JPAKERound3Payload
+    public class JPakeRound3Payload
     {
         /// <summary>
         /// The id of the {@link JPAKEParticipant} who created/sent this payload.
@@ -32,18 +32,18 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
         /// </summary>
         private readonly BigInteger macTag;
 
-        public JPAKERound3Payload(string participantId, BigInteger magTag)
+        public JPakeRound3Payload(string participantId, BigInteger magTag)
         {
             this.participantId = participantId;
             this.macTag = magTag;
         }
 
-        public string ParticipantId
+        public virtual string ParticipantId
         {
             get { return participantId; }
         }
 
-        public BigInteger MacTag
+        public virtual BigInteger MacTag
         {
             get { return macTag; }
         }
diff --git a/crypto/src/crypto/agreement/jpake/JPAKEUtil.cs b/crypto/src/crypto/agreement/jpake/JPakeUtilities.cs
index 34f8c2685..eaf8af676 100755..100644
--- a/crypto/src/crypto/agreement/jpake/JPAKEUtil.cs
+++ b/crypto/src/crypto/agreement/jpake/JPakeUtilities.cs
@@ -4,25 +4,26 @@ using System.Text;
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Crypto.Macs;
 using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
 using Org.BouncyCastle.Math;
 using Org.BouncyCastle.Security;
 using Org.BouncyCastle.Utilities;
 
-namespace Org.BouncyCastle.Crypto.Agreement.Jpake
+namespace Org.BouncyCastle.Crypto.Agreement.JPake
 {
     /// <summary>
     /// Primitives needed for a J-PAKE exchange.
     /// 
     /// The recommended way to perform a J-PAKE exchange is by using
     /// two JPAKEParticipants.  Internally, those participants
-    /// call these primitive operations in JPAKEUtil.
+    /// call these primitive operations in JPakeUtilities.
     /// 
     /// The primitives, however, can be used without a JPAKEParticipant if needed.
     /// </summary>
-    public class JPAKEUtil
+    public abstract class JPakeUtilities
     {
-        public static BigInteger ZERO = BigInteger.ValueOf(0);
-        public static BigInteger ONE = BigInteger.ValueOf(1);
+        public static readonly BigInteger Zero = BigInteger.Zero;
+        public static readonly BigInteger One = BigInteger.One;
 
         /// <summary>
         /// Return a value that can be used as x1 or x3 during round 1.
@@ -30,8 +31,8 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
         /// </summary>
         public static BigInteger GenerateX1(BigInteger q, SecureRandom random)
         {
-            BigInteger min = ZERO;
-            BigInteger max = q.Subtract(ONE);
+            BigInteger min = Zero;
+            BigInteger max = q.Subtract(One);
             return BigIntegers.CreateRandomInRange(min, max, random);
         }
 
@@ -41,8 +42,8 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
         /// </summary>
         public static BigInteger GenerateX2(BigInteger q, SecureRandom random)
         {
-            BigInteger min = ONE;
-            BigInteger max = q.Subtract(ONE);
+            BigInteger min = One;
+            BigInteger max = q.Subtract(One);
             return BigIntegers.CreateRandomInRange(min, max, random);
         }
 
@@ -52,7 +53,7 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
         /// </summary>
         public static BigInteger CalculateS(char[] password)
         {
-            return new BigInteger(Strings.ToUtf8ByteArray(password));
+            return new BigInteger(Encoding.UTF8.GetBytes(password));
         }
 
         /// <summary>
@@ -96,20 +97,19 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
         public static BigInteger[] CalculateZeroKnowledgeProof(BigInteger p, BigInteger q, BigInteger g,
             BigInteger gx, BigInteger x, string participantId, IDigest digest, SecureRandom random)
         {
-            BigInteger[] zeroKnowledgeProof = new BigInteger[2];
-
             /* Generate a random v, and compute g^v */
-            BigInteger vMin = ZERO;
-            BigInteger vMax = q.Subtract(ONE);
+            BigInteger vMin = Zero;
+            BigInteger vMax = q.Subtract(One);
             BigInteger v = BigIntegers.CreateRandomInRange(vMin, vMax, random);
 
             BigInteger gv = g.ModPow(v, p);
             BigInteger h = CalculateHashForZeroKnowledgeProof(g, gv, gx, participantId, digest); // h
 
-            zeroKnowledgeProof[0] = gv;
-            zeroKnowledgeProof[1] = v.Subtract(x.Multiply(h)).Mod(q); // r = v-x*h
-
-            return zeroKnowledgeProof;
+            return new BigInteger[]
+            {
+                gv,
+                v.Subtract(x.Multiply(h)).Mod(q) // r = v-x*h
+            };
         }
 
         private static BigInteger CalculateHashForZeroKnowledgeProof(BigInteger g, BigInteger gr, BigInteger gx,
@@ -125,8 +125,7 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
 
             UpdateDigestIncludingSize(digest, participantId);
 
-            byte[] output = new byte[digest.GetDigestSize()];
-            digest.DoFinal(output, 0);
+            byte[] output = DigestUtilities.DoFinal(digest);
 
             return new BigInteger(output);
         }
@@ -137,10 +136,8 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
         /// </summary>
         public static void ValidateGx4(BigInteger gx4)
         {
-            if (gx4.Equals(ONE))
-            {
+            if (gx4.Equals(One))
                 throw new CryptoException("g^x validation failed.  g^x should not be 1.");
-            }
         }
 
         /// <summary>
@@ -155,10 +152,8 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
         /// </summary>
         public static void ValidateGa(BigInteger ga)
         {
-            if (ga.Equals(ONE))
-            {
+            if (ga.Equals(One))
                 throw new CryptoException("ga is equal to 1.  It should not be.  The chances of this happening are on the order of 2^160 for a 160-bit q.  Try again.");
-            }
         }
 
         /// <summary>
@@ -176,9 +171,9 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
             BigInteger r = zeroKnowledgeProof[1];
 
             BigInteger h = CalculateHashForZeroKnowledgeProof(g, gv, gx, participantId, digest);
-            if (!(gx.CompareTo(ZERO) == 1 && // g^x > 0
+            if (!(gx.CompareTo(Zero) == 1 && // g^x > 0
                 gx.CompareTo(p) == -1 && // g^x < p
-                gx.ModPow(q, p).CompareTo(ONE) == 0 && // g^x^q mod q = 1
+                gx.ModPow(q, p).CompareTo(One) == 0 && // g^x^q mod q = 1
                 /*
                  * Below, I took a straightforward way to compute g^r * g^x^h,
                  * which needs 2 exp. Using a simultaneous computation technique
@@ -245,12 +240,10 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
         /// </summary>
         /// <param name="obj">object in question</param>
         /// <param name="description">name of the object (to be used in exception message)</param>
-        public static void ValidateNotNull(Object obj, string description)
+        public static void ValidateNotNull(object obj, string description)
         {
             if (obj == null)
-            {
-                throw new NullReferenceException(description + " must not be null");
-            }
+                throw new ArgumentNullException(description);
         }
 
         /// <summary>
@@ -275,8 +268,8 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
             byte[] macKey = CalculateMacKey(keyingMaterial, digest);
 
             HMac mac = new HMac(digest);
-            byte[] macOutput = new byte[mac.GetMacSize()];
             mac.Init(new KeyParameter(macKey));
+            Arrays.Fill(macKey, (byte)0);
 
             /*
              * MacData = "KC_1_U" || participantId_Alice || participantId_Bob || gx1 || gx2 || gx3 || gx4.
@@ -289,9 +282,7 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
             UpdateMac(mac, gx3);
             UpdateMac(mac, gx4);
 
-            mac.DoFinal(macOutput, 0);
-
-            Arrays.Fill(macKey, (byte)0);
+            byte[] macOutput = MacUtilities.DoFinal(mac);
 
             return new BigInteger(macOutput);
         }
@@ -311,10 +302,7 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
              */
             UpdateDigest(digest, "JPAKE_KC");
 
-            byte[] output = new byte[digest.GetDigestSize()];
-            digest.DoFinal(output, 0);
-
-            return output;
+            return DigestUtilities.DoFinal(digest);
         }
 
         /// <summary>
@@ -348,57 +336,56 @@ namespace Org.BouncyCastle.Crypto.Agreement.Jpake
 
         private static void UpdateDigest(IDigest digest, BigInteger bigInteger)
         {
-            byte[] byteArray = BigIntegers.AsUnsignedByteArray(bigInteger);
-            digest.BlockUpdate(byteArray, 0, byteArray.Length);
-            Arrays.Fill(byteArray, (byte)0);
+            UpdateDigest(digest, BigIntegers.AsUnsignedByteArray(bigInteger));
         }
 
-        private static void UpdateDigestIncludingSize(IDigest digest, BigInteger bigInteger)
+        private static void UpdateDigest(IDigest digest, string str)
         {
-            byte[] byteArray = BigIntegers.AsUnsignedByteArray(bigInteger);
-            digest.BlockUpdate(IntToByteArray(byteArray.Length), 0, 4);
-            digest.BlockUpdate(byteArray, 0, byteArray.Length);
-            Arrays.Fill(byteArray, (byte)0);
+            UpdateDigest(digest, Encoding.UTF8.GetBytes(str));
         }
 
-        private static void UpdateDigest(IDigest digest, string str)
+        private static void UpdateDigest(IDigest digest, byte[] bytes)
         {
-            byte[] byteArray = Encoding.UTF8.GetBytes(str);
-            digest.BlockUpdate(byteArray, 0, byteArray.Length);
-            Arrays.Fill(byteArray, (byte)0);
+            digest.BlockUpdate(bytes, 0, bytes.Length);
+            Arrays.Fill(bytes, (byte)0);
+        }
+
+        private static void UpdateDigestIncludingSize(IDigest digest, BigInteger bigInteger)
+        {
+            UpdateDigestIncludingSize(digest, BigIntegers.AsUnsignedByteArray(bigInteger));
         }
 
         private static void UpdateDigestIncludingSize(IDigest digest, string str)
         {
-            byte[] byteArray = Encoding.UTF8.GetBytes(str);
-            digest.BlockUpdate(IntToByteArray(byteArray.Length), 0, 4);
-            digest.BlockUpdate(byteArray, 0, byteArray.Length);
-            Arrays.Fill(byteArray, (byte)0);
+            UpdateDigestIncludingSize(digest, Encoding.UTF8.GetBytes(str));
+        }
+
+        private static void UpdateDigestIncludingSize(IDigest digest, byte[] bytes)
+        {
+            digest.BlockUpdate(IntToByteArray(bytes.Length), 0, 4);
+            digest.BlockUpdate(bytes, 0, bytes.Length);
+            Arrays.Fill(bytes, (byte)0);
         }
 
         private static void UpdateMac(IMac mac, BigInteger bigInteger)
         {
-            byte[] byteArray = BigIntegers.AsUnsignedByteArray(bigInteger);
-            mac.BlockUpdate(byteArray, 0, byteArray.Length);
-            Arrays.Fill(byteArray, (byte)0);
+            UpdateMac(mac, BigIntegers.AsUnsignedByteArray(bigInteger));
         }
 
         private static void UpdateMac(IMac mac, string str)
         {
-            byte[] byteArray = Encoding.UTF8.GetBytes(str);
-            mac.BlockUpdate(byteArray, 0, byteArray.Length);
-            Arrays.Fill(byteArray, (byte)0);
+            UpdateMac(mac, Encoding.UTF8.GetBytes(str));
         }
 
-        private static byte[] IntToByteArray(int value)
+        private static void UpdateMac(IMac mac, byte[] bytes)
         {
-            return new byte[]{
-                (byte)((uint)value >> 24),
-                (byte)((uint)value >> 16),
-                (byte)((uint)value >> 8),
-                (byte)value
-            };
+            mac.BlockUpdate(bytes, 0, bytes.Length);
+            Arrays.Fill(bytes, (byte)0);
         }
 
+        private static byte[] IntToByteArray(int value)
+        {
+            return Pack.UInt32_To_BE((uint)value);
+        }
     }
 }