From 02a9861925a3077835fa80f7f3bd055b62940801 Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Sat, 17 Oct 2015 15:07:04 +0700 Subject: Fix case of JPAKE filenames --- .../src/crypto/agreement/jpake/JPAKEParticipant.cs | 455 --------------------- .../crypto/agreement/jpake/JPAKEPrimeOrderGroup.cs | 103 ----- .../agreement/jpake/JPAKEPrimeOrderGroups.cs | 108 ----- .../crypto/agreement/jpake/JPAKERound1Payload.cs | 101 ----- .../crypto/agreement/jpake/JPAKERound2Payload.cs | 72 ---- .../crypto/agreement/jpake/JPAKERound3Payload.cs | 51 --- .../src/crypto/agreement/jpake/JPakeParticipant.cs | 455 +++++++++++++++++++++ .../crypto/agreement/jpake/JPakePrimeOrderGroup.cs | 103 +++++ .../agreement/jpake/JPakePrimeOrderGroups.cs | 108 +++++ .../crypto/agreement/jpake/JPakeRound1Payload.cs | 101 +++++ .../crypto/agreement/jpake/JPakeRound2Payload.cs | 72 ++++ .../crypto/agreement/jpake/JPakeRound3Payload.cs | 51 +++ 12 files changed, 890 insertions(+), 890 deletions(-) delete mode 100755 crypto/src/crypto/agreement/jpake/JPAKEParticipant.cs delete mode 100755 crypto/src/crypto/agreement/jpake/JPAKEPrimeOrderGroup.cs delete mode 100755 crypto/src/crypto/agreement/jpake/JPAKEPrimeOrderGroups.cs delete mode 100755 crypto/src/crypto/agreement/jpake/JPAKERound1Payload.cs delete mode 100755 crypto/src/crypto/agreement/jpake/JPAKERound2Payload.cs delete mode 100755 crypto/src/crypto/agreement/jpake/JPAKERound3Payload.cs create mode 100755 crypto/src/crypto/agreement/jpake/JPakeParticipant.cs create mode 100755 crypto/src/crypto/agreement/jpake/JPakePrimeOrderGroup.cs create mode 100755 crypto/src/crypto/agreement/jpake/JPakePrimeOrderGroups.cs create mode 100755 crypto/src/crypto/agreement/jpake/JPakeRound1Payload.cs create mode 100755 crypto/src/crypto/agreement/jpake/JPakeRound2Payload.cs create mode 100755 crypto/src/crypto/agreement/jpake/JPakeRound3Payload.cs (limited to 'crypto/src') diff --git a/crypto/src/crypto/agreement/jpake/JPAKEParticipant.cs b/crypto/src/crypto/agreement/jpake/JPAKEParticipant.cs deleted file mode 100755 index f8ca2cd41..000000000 --- a/crypto/src/crypto/agreement/jpake/JPAKEParticipant.cs +++ /dev/null @@ -1,455 +0,0 @@ -using System; - -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Crypto.Digests; -using Org.BouncyCastle.Math; -using Org.BouncyCastle.Security; - -namespace Org.BouncyCastle.Crypto.Agreement.JPake -{ - /// - /// A participant in a Password Authenticated Key Exchange by Juggling (J-PAKE) exchange. - /// - /// The J-PAKE exchange is defined by Feng Hao and Peter Ryan in the paper - /// - /// "Password Authenticated Key Exchange by Juggling, 2008." - /// - /// The J-PAKE protocol is symmetric. - /// There is no notion of a client or server, but rather just two participants. - /// 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, - /// 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 - /// CreateRound2PayloadToSend() - and send the payload to 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 - /// - /// 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). - /// - /// Round 3 is an optional key confirmation process. - /// If you do not execute round 3, then there is no assurance that both participants are using the same key. - /// (i.e. if the participants used different passwords, then their session keys will differ.) - /// - /// If the round 3 validation succeeds, then the keys are guaranteed to be the same on both sides. - /// - /// The symmetric design can easily support the asymmetric cases when one party initiates the communication. - /// e.g. Sometimes the round1 payload and round2 payload may be sent in one pass. - /// Also, in some cases, the key confirmation payload can be sent together with the round2 payload. - /// These are the trivial techniques to optimize the communication. - /// - /// The key confirmation process is implemented as specified in - /// NIST SP 800-56A Revision 1, - /// Section 8.2 Unilateral Key Confirmation for Key Agreement Schemes. - /// - /// 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). - /// - public class JPakeParticipant - { - // Possible internal states. Used for state checking. - public static readonly int STATE_INITIALIZED = 0; - public static readonly int STATE_ROUND_1_CREATED = 10; - public static readonly int STATE_ROUND_1_VALIDATED = 20; - public static readonly int STATE_ROUND_2_CREATED = 30; - public static readonly int STATE_ROUND_2_VALIDATED = 40; - public static readonly int STATE_KEY_CALCULATED = 50; - public static readonly int STATE_ROUND_3_CREATED = 60; - public static readonly int STATE_ROUND_3_VALIDATED = 70; - - // Unique identifier of this participant. - // The two participants in the exchange must NOT share the same id. - private string participantId; - - // Shared secret. This only contains the secret between construction - // and the call to CalculateKeyingMaterial(). - // - // i.e. When CalculateKeyingMaterial() is called, this buffer overwritten with 0's, - // and the field is set to null. - private char[] password; - - // Digest to use during calculations. - private IDigest digest; - - // Source of secure random data. - private readonly SecureRandom random; - - private readonly BigInteger p; - private readonly BigInteger q; - private readonly BigInteger g; - - // The participantId of the other participant in this exchange. - private string partnerParticipantId; - - // Alice's x1 or Bob's x3. - private BigInteger x1; - // Alice's x2 or Bob's x4. - private BigInteger x2; - // Alice's g^x1 or Bob's g^x3. - private BigInteger gx1; - // Alice's g^x2 or Bob's g^x4. - private BigInteger gx2; - // Alice's g^x3 or Bob's g^x1. - private BigInteger gx3; - // Alice's g^x4 or Bob's g^x2. - private BigInteger gx4; - // Alice's B or Bob's A. - private BigInteger b; - - // The current state. - // See the STATE_* constants for possible values. - private int state; - - /// - /// 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. - /// - /// Throws NullReferenceException if any argument is null. Throws - /// ArgumentException if password is empty. - /// - /// Unique identifier of this participant. - /// The two participants in the exchange must NOT share the same id. - /// 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. - public JPakeParticipant(string participantId, char[] password) - : this(participantId, password, JPakePrimeOrderGroups.NIST_3072) { } - - /// - /// 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. - /// - /// Throws NullReferenceException if any argument is null. Throws - /// ArgumentException if password is empty. - /// - /// Unique identifier of this participant. - /// The two participants in the exchange must NOT share the same id. - /// 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. - /// Prime order group. See JPakePrimeOrderGroups for standard groups. - public JPakeParticipant(string participantId, char[] password, JPakePrimeOrderGroup group) - : this(participantId, password, group, new Sha256Digest(), new SecureRandom()) { } - - - /// - /// Constructor for a new JPakeParticipant. - /// - /// After construction, the State state will be STATE_INITIALIZED. - /// - /// Throws NullReferenceException if any argument is null. Throws - /// ArgumentException if password is empty. - /// - /// Unique identifier of this participant. - /// The two participants in the exchange must NOT share the same id. - /// 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. - /// Prime order group. See JPakePrimeOrderGroups for standard groups. - /// Digest to use during zero knowledge proofs and key confirmation - /// (SHA-256 or stronger preferred). - /// Source of secure random data for x1 and x2, and for the zero knowledge proofs. - public JPakeParticipant(string participantId, char[] password, JPakePrimeOrderGroup group, IDigest digest, SecureRandom 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) - { - throw new ArgumentException("Password must not be empty."); - } - - this.participantId = participantId; - - // Create a defensive copy so as to fully encapsulate the password. - // - // This array will contain the password for the lifetime of this - // participant BEFORE CalculateKeyingMaterial() is called. - // - // i.e. When CalculateKeyingMaterial() is called, the array will be cleared - // in order to remove the password from memory. - // - // The caller is responsible for clearing the original password array - // given as input to this constructor. - this.password = new char[password.Length]; - Array.Copy(password, this.password, password.Length); - - this.p = group.P; - this.q = group.Q; - this.g = group.G; - - this.digest = digest; - this.random = random; - - this.state = STATE_INITIALIZED; - } - - /// - /// Gets the current state of this participant. - /// See the STATE_* constants for possible values. - /// - public virtual int State - { - get { return state; } - } - - - /// - /// Creates and returns the payload to send to the other participant during round 1. - /// - /// After execution, the State state} will be STATE_ROUND_1_CREATED}. - /// - public virtual JPakeRound1Payload CreateRound1PayloadToSend() - { - if (this.state >= STATE_ROUND_1_CREATED) - throw new InvalidOperationException("Round 1 payload already created for " + this.participantId); - - this.x1 = JPakeUtilities.GenerateX1(q, random); - this.x2 = JPakeUtilities.GenerateX2(q, 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); - } - - /// - /// Validates the payload received from the other participant during round 1. - /// - /// Must be called prior to CreateRound2PayloadToSend(). - /// - /// After execution, the State state will be STATE_ROUND_1_VALIDATED. - /// - /// Throws CryptoException if validation fails. Throws InvalidOperationException - /// if called multiple times. - /// - 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; - this.gx4 = round1PayloadReceived.Gx2; - - BigInteger[] knowledgeProofForX3 = round1PayloadReceived.KnowledgeProofForX1; - BigInteger[] knowledgeProofForX4 = round1PayloadReceived.KnowledgeProofForX2; - - 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; - } - - /// - /// Creates and returns the payload to send to the other participant during round 2. - /// - /// 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 - /// - 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 = 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); - } - - /// - /// Validates the payload received from the other participant during round 2. - /// Note that this DOES NOT detect a non-common password. - /// The only indication of a non-common password is through derivation - /// of different keys (which can be detected explicitly by executing round 3 and round 4) - /// - /// Must be called prior to CalculateKeyingMaterial(). - /// - /// 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 - /// - 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 = JPakeUtilities.CalculateGA(p, gx3, gx1, gx2); - this.b = round2PayloadReceived.A; - BigInteger[] knowledgeProofForX4s = round2PayloadReceived.KnowledgeProofForX2s; - - 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; - } - - /// - /// 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 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 - /// share the same password, then each participant will derive a different key. - /// 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. - /// - /// The keying material will be in the range [0, p-1]. - /// - /// 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), - /// or if called multiple times. - /// - 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 = 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 = 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. - // The old objects will hang around in memory until the garbage collector destroys them. - // - // If the ephemeral private keys x1 and x2 are leaked, - // the attacker might be able to brute-force the password. - this.x1 = null; - this.x2 = null; - this.b = null; - - // Do not clear gx* yet, since those are needed by round 3. - - this.state = STATE_KEY_CALCULATED; - - return keyingMaterial; - } - - /// - /// Creates and returns the payload to send to the other participant during 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. - /// - /// The keying material as returned from CalculateKeyingMaterial(). - 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 = JPakeUtilities.CalculateMacTag( - this.participantId, - this.partnerParticipantId, - this.gx1, - this.gx2, - this.gx3, - this.gx4, - keyingMaterial, - this.digest); - - this.state = STATE_ROUND_3_CREATED; - - return new JPakeRound3Payload(participantId, macTag); - } - - /// - /// Validates the payload received from the other participant during round 3. - /// - /// See JPakeParticipant for more details on round 3. - /// - /// After execution, the State state will be STATE_ROUND_3_VALIDATED. - /// - /// Throws CryptoException if validation fails. Throws InvalidOperationException if called prior to - /// CalculateKeyingMaterial or multiple times - /// - /// The keying material as returned from CalculateKeyingMaterial(). - 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); - - JPakeUtilities.ValidateParticipantIdsDiffer(participantId, round3PayloadReceived.ParticipantId); - JPakeUtilities.ValidateParticipantIdsEqual(this.partnerParticipantId, round3PayloadReceived.ParticipantId); - - JPakeUtilities.ValidateMacTag( - this.participantId, - this.partnerParticipantId, - this.gx1, - this.gx2, - this.gx3, - this.gx4, - keyingMaterial, - this.digest, - round3PayloadReceived.MacTag); - - // Clear the rest of the fields. - this.gx1 = null; - this.gx2 = null; - this.gx3 = null; - this.gx4 = null; - - this.state = STATE_ROUND_3_VALIDATED; - } - } -} diff --git a/crypto/src/crypto/agreement/jpake/JPAKEPrimeOrderGroup.cs b/crypto/src/crypto/agreement/jpake/JPAKEPrimeOrderGroup.cs deleted file mode 100755 index 08ffe1a55..000000000 --- a/crypto/src/crypto/agreement/jpake/JPAKEPrimeOrderGroup.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System; - -using Org.BouncyCastle.Math; - -namespace Org.BouncyCastle.Crypto.Agreement.JPake -{ - /// - /// A pre-computed prime order group for use during a J-PAKE exchange. - /// - /// 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. - /// - /// NIST publishes - /// many groups that can be used for the desired level of security. - /// - public class JPakePrimeOrderGroup - { - private readonly BigInteger p; - private readonly BigInteger q; - private readonly BigInteger g; - - /// - /// Constructs a new JPakePrimeOrderGroup. - /// - /// In general, you should use one of the pre-approved groups from - /// JPakePrimeOrderGroups, rather than manually constructing one. - /// - /// The following basic checks are performed: - /// - /// p-1 must be evenly divisible by q - /// g must be in [2, p-1] - /// g^q mod p must equal 1 - /// p must be prime (within reasonably certainty) - /// q must be prime (within reasonably certainty) - /// - /// The prime checks are performed using BigInteger#isProbablePrime(int), - /// and are therefore subject to the same probability guarantees. - /// - /// These checks prevent trivial mistakes. - /// However, due to the small uncertainties if p and q are not prime, - /// advanced attacks are not prevented. - /// Use it at your own risk. - /// - /// Throws NullReferenceException if any argument is null. Throws - /// InvalidOperationException is any of the above validations fail. - /// - public JPakePrimeOrderGroup(BigInteger p, BigInteger q, BigInteger g) - : this(p, q, g, false) - { - // Don't skip the checks on user-specified groups. - } - - /// - /// 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. - /// - public JPakePrimeOrderGroup(BigInteger p, BigInteger q, BigInteger g, bool skipChecks) - { - JPakeUtilities.ValidateNotNull(p, "p"); - JPakeUtilities.ValidateNotNull(q, "q"); - JPakeUtilities.ValidateNotNull(g, "g"); - - if (!skipChecks) - { - 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.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(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; - this.q = q; - this.g = g; - } - - public virtual BigInteger P - { - get { return p; } - } - - public virtual BigInteger Q - { - get { return q; } - } - - 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 deleted file mode 100755 index 33640845a..000000000 --- a/crypto/src/crypto/agreement/jpake/JPAKEPrimeOrderGroups.cs +++ /dev/null @@ -1,108 +0,0 @@ -using Org.BouncyCastle.Math; - -namespace Org.BouncyCastle.Crypto.Agreement.JPake -{ - /// - /// Standard pre-computed prime order groups for use by J-PAKE. - /// (J-PAKE can use pre-computed prime order groups, same as DSA and Diffie-Hellman.) - ///

- /// This class contains some convenient constants for use as input for - /// constructing {@link JPAKEParticipant}s. - ///

- /// The prime order groups below are taken from Sun's JDK JavaDoc (docs/guide/security/CryptoSpec.html#AppB), - /// and from the prime order groups - /// published by NIST. - ///

- public class JPakePrimeOrderGroups - { - /// - /// 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. - /// - public static readonly JPakePrimeOrderGroup SUN_JCE_1024 = new JPakePrimeOrderGroup( - // p - new BigInteger( - "fd7f53811d75122952df4a9c2eece4e7f611b7523cef4400c31e3f80b6512669" + - "455d402251fb593d8d58fabfc5f5ba30f6cb9b556cd7813b801d346ff26660b7" + - "6b9950a5a49f9fe8047b1022c24fbba9d7feb7c61bf83b57e7c6a8a6150f04fb" + - "83f6d3c51ec3023554135a169132f675f3ae2b61d72aeff22203199dd14801c7", 16), - // q - new BigInteger("9760508f15230bccb292b982a2eb840bf0581cf5", 16), - // g - new BigInteger( - "f7e1a085d69b3ddecbbcab5c36b857b97994afbbfa3aea82f9574c0b3d078267" + - "5159578ebad4594fe67107108180b449167123e84c281613b7cf09328cc8a6e1" + - "3c167a8b547c8d28e0a3ae1e2bb3a675916ea37f0bfa213562f1fb627a01243b" + - "cca4f1bea8519089a883dfe15ae59f06928b665e807b552564014c3bfecf492a", 16), - true - ); - - /// - /// From NIST. - /// 2048-bit p, 224-bit q and 2048-bit g for 112-bit security. - /// - public static readonly JPakePrimeOrderGroup NIST_2048 = new JPakePrimeOrderGroup( - // p - new BigInteger( - "C196BA05AC29E1F9C3C72D56DFFC6154A033F1477AC88EC37F09BE6C5BB95F51" + - "C296DD20D1A28A067CCC4D4316A4BD1DCA55ED1066D438C35AEBAABF57E7DAE4" + - "28782A95ECA1C143DB701FD48533A3C18F0FE23557EA7AE619ECACC7E0B51652" + - "A8776D02A425567DED36EABD90CA33A1E8D988F0BBB92D02D1D20290113BB562" + - "CE1FC856EEB7CDD92D33EEA6F410859B179E7E789A8F75F645FAE2E136D252BF" + - "FAFF89528945C1ABE705A38DBC2D364AADE99BE0D0AAD82E5320121496DC65B3" + - "930E38047294FF877831A16D5228418DE8AB275D7D75651CEFED65F78AFC3EA7" + - "FE4D79B35F62A0402A1117599ADAC7B269A59F353CF450E6982D3B1702D9CA83", 16), - // q - new BigInteger("90EAF4D1AF0708B1B612FF35E0A2997EB9E9D263C9CE659528945C0D", 16), - // g - new BigInteger( - "A59A749A11242C58C894E9E5A91804E8FA0AC64B56288F8D47D51B1EDC4D6544" + - "4FECA0111D78F35FC9FDD4CB1F1B79A3BA9CBEE83A3F811012503C8117F98E50" + - "48B089E387AF6949BF8784EBD9EF45876F2E6A5A495BE64B6E770409494B7FEE" + - "1DBB1E4B2BC2A53D4F893D418B7159592E4FFFDF6969E91D770DAEBD0B5CB14C" + - "00AD68EC7DC1E5745EA55C706C4A1C5C88964E34D09DEB753AD418C1AD0F4FDF" + - "D049A955E5D78491C0B7A2F1575A008CCD727AB376DB6E695515B05BD412F5B8" + - "C2F4C77EE10DA48ABD53F5DD498927EE7B692BBBCDA2FB23A516C5B4533D7398" + - "0B2A3B60E384ED200AE21B40D273651AD6060C13D97FD69AA13C5611A51B9085", 16), - true - ); - - /// - /// From NIST. - /// 3072-bit p, 256-bit q and 3072-bit g for 128-bit security. - /// - public static readonly JPakePrimeOrderGroup NIST_3072 = new JPakePrimeOrderGroup( - // p - new BigInteger( - "90066455B5CFC38F9CAA4A48B4281F292C260FEEF01FD61037E56258A7795A1C" + - "7AD46076982CE6BB956936C6AB4DCFE05E6784586940CA544B9B2140E1EB523F" + - "009D20A7E7880E4E5BFA690F1B9004A27811CD9904AF70420EEFD6EA11EF7DA1" + - "29F58835FF56B89FAA637BC9AC2EFAAB903402229F491D8D3485261CD068699B" + - "6BA58A1DDBBEF6DB51E8FE34E8A78E542D7BA351C21EA8D8F1D29F5D5D159394" + - "87E27F4416B0CA632C59EFD1B1EB66511A5A0FBF615B766C5862D0BD8A3FE7A0" + - "E0DA0FB2FE1FCB19E8F9996A8EA0FCCDE538175238FC8B0EE6F29AF7F642773E" + - "BE8CD5402415A01451A840476B2FCEB0E388D30D4B376C37FE401C2A2C2F941D" + - "AD179C540C1C8CE030D460C4D983BE9AB0B20F69144C1AE13F9383EA1C08504F" + - "B0BF321503EFE43488310DD8DC77EC5B8349B8BFE97C2C560EA878DE87C11E3D" + - "597F1FEA742D73EEC7F37BE43949EF1A0D15C3F3E3FC0A8335617055AC91328E" + - "C22B50FC15B941D3D1624CD88BC25F3E941FDDC6200689581BFEC416B4B2CB73", 16), - // q - new BigInteger("CFA0478A54717B08CE64805B76E5B14249A77A4838469DF7F7DC987EFCCFB11D", 16), - // g - new BigInteger( - "5E5CBA992E0A680D885EB903AEA78E4A45A469103D448EDE3B7ACCC54D521E37" + - "F84A4BDD5B06B0970CC2D2BBB715F7B82846F9A0C393914C792E6A923E2117AB" + - "805276A975AADB5261D91673EA9AAFFEECBFA6183DFCB5D3B7332AA19275AFA1" + - "F8EC0B60FB6F66CC23AE4870791D5982AAD1AA9485FD8F4A60126FEB2CF05DB8" + - "A7F0F09B3397F3937F2E90B9E5B9C9B6EFEF642BC48351C46FB171B9BFA9EF17" + - "A961CE96C7E7A7CC3D3D03DFAD1078BA21DA425198F07D2481622BCE45969D9C" + - "4D6063D72AB7A0F08B2F49A7CC6AF335E08C4720E31476B67299E231F8BD90B3" + - "9AC3AE3BE0C6B6CACEF8289A2E2873D58E51E029CAFBD55E6841489AB66B5B4B" + - "9BA6E2F784660896AFF387D92844CCB8B69475496DE19DA2E58259B090489AC8" + - "E62363CDF82CFD8EF2A427ABCD65750B506F56DDE3B988567A88126B914D7828" + - "E2B63A6D7ED0747EC59E0E0A23CE7D8A74C1D2C2A7AFB6A29799620F00E11C33" + - "787F7DED3B30E1A22D09F1FBDA1ABBBFBF25CAE05A13F812E34563F99410E73B", 16), - true - ); - } -} diff --git a/crypto/src/crypto/agreement/jpake/JPAKERound1Payload.cs b/crypto/src/crypto/agreement/jpake/JPAKERound1Payload.cs deleted file mode 100755 index 9e4ab7a5f..000000000 --- a/crypto/src/crypto/agreement/jpake/JPAKERound1Payload.cs +++ /dev/null @@ -1,101 +0,0 @@ -using System; - -using Org.BouncyCastle.Math; - -namespace Org.BouncyCastle.Crypto.Agreement.JPake -{ - /// - /// The payload sent/received during the first round of a J-PAKE exchange. - /// - /// Each JPAKEParticipant creates and sends an instance of this payload to - /// the other. The payload to send should be created via - /// JPAKEParticipant.CreateRound1PayloadToSend(). - /// - /// Each participant must also validate the payload received from the other. - /// The received payload should be validated via - /// JPAKEParticipant.ValidateRound1PayloadReceived(JPakeRound1Payload). - /// - public class JPakeRound1Payload - { - /// - /// The id of the JPAKEParticipant who created/sent this payload. - /// - private readonly string participantId; - - /// - /// The value of g^x1 - /// - private readonly BigInteger gx1; - - /// - /// The value of g^x2 - /// - private readonly BigInteger gx2; - - /// - /// The zero knowledge proof for x1. - /// - /// This is a two element array, containing {g^v, r} for x1. - /// - private readonly BigInteger[] knowledgeProofForX1; - - /// - /// The zero knowledge proof for x2. - /// - /// This is a two element array, containing {g^v, r} for x2. - /// - private readonly BigInteger[] knowledgeProofForX2; - - public JPakeRound1Payload(string participantId, BigInteger gx1, BigInteger gx2, BigInteger[] knowledgeProofForX1, BigInteger[] 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; - this.gx2 = gx2; - this.knowledgeProofForX1 = new BigInteger[knowledgeProofForX1.Length]; - Array.Copy(knowledgeProofForX1, this.knowledgeProofForX1, knowledgeProofForX1.Length); - this.knowledgeProofForX2 = new BigInteger[knowledgeProofForX2.Length]; - Array.Copy(knowledgeProofForX2, this.knowledgeProofForX2, knowledgeProofForX2.Length); - } - - public virtual string ParticipantId - { - get { return participantId; } - } - - public virtual BigInteger Gx1 - { - get { return gx1; } - } - - public virtual BigInteger Gx2 - { - get { return gx2; } - } - - public virtual BigInteger[] KnowledgeProofForX1 - { - get - { - BigInteger[] kp = new BigInteger[knowledgeProofForX1.Length]; - Array.Copy(knowledgeProofForX1, kp, knowledgeProofForX1.Length); - return kp; - } - } - - public virtual BigInteger[] KnowledgeProofForX2 - { - get - { - BigInteger[] kp = new BigInteger[knowledgeProofForX2.Length]; - Array.Copy(knowledgeProofForX2, kp, knowledgeProofForX2.Length); - return kp; - } - } - } -} diff --git a/crypto/src/crypto/agreement/jpake/JPAKERound2Payload.cs b/crypto/src/crypto/agreement/jpake/JPAKERound2Payload.cs deleted file mode 100755 index 47962cb3f..000000000 --- a/crypto/src/crypto/agreement/jpake/JPAKERound2Payload.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System; - -using Org.BouncyCastle.Math; -using Org.BouncyCastle.Utilities; - -namespace Org.BouncyCastle.Crypto.Agreement.JPake -{ - /// - /// The payload sent/received during the second round of a J-PAKE exchange. - /// - /// Each JPAKEParticipant creates and sends an instance - /// of this payload to the other JPAKEParticipant. - /// The payload to send should be created via - /// JPAKEParticipant#createRound2PayloadToSend() - /// - /// Each JPAKEParticipant must also validate the payload - /// received from the other JPAKEParticipant. - /// The received payload should be validated via - /// JPAKEParticipant#validateRound2PayloadReceived(JPakeRound2Payload) - /// - public class JPakeRound2Payload - { - /// - /// The id of the JPAKEParticipant who created/sent this payload. - /// - private readonly string participantId; - - /// - /// The value of A, as computed during round 2. - /// - private readonly BigInteger a; - - /// - /// The zero knowledge proof for x2 * s. - /// - /// This is a two element array, containing {g^v, r} for x2 * s. - /// - private readonly BigInteger[] knowledgeProofForX2s; - - public JPakeRound2Payload(string participantId, BigInteger a, BigInteger[] knowledgeProofForX2s) - { - JPakeUtilities.ValidateNotNull(participantId, "participantId"); - JPakeUtilities.ValidateNotNull(a, "a"); - JPakeUtilities.ValidateNotNull(knowledgeProofForX2s, "knowledgeProofForX2s"); - - this.participantId = participantId; - this.a = a; - this.knowledgeProofForX2s = new BigInteger[knowledgeProofForX2s.Length]; - knowledgeProofForX2s.CopyTo(this.knowledgeProofForX2s, 0); - } - - public virtual string ParticipantId - { - get { return participantId; } - } - - public virtual BigInteger A - { - get { return a; } - } - - public virtual BigInteger[] KnowledgeProofForX2s - { - get - { - BigInteger[] kp = new BigInteger[knowledgeProofForX2s.Length]; - Array.Copy(knowledgeProofForX2s, kp, knowledgeProofForX2s.Length); - return kp; - } - } - } -} diff --git a/crypto/src/crypto/agreement/jpake/JPAKERound3Payload.cs b/crypto/src/crypto/agreement/jpake/JPAKERound3Payload.cs deleted file mode 100755 index 767702f23..000000000 --- a/crypto/src/crypto/agreement/jpake/JPAKERound3Payload.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; - -using Org.BouncyCastle.Math; - -namespace Org.BouncyCastle.Crypto.Agreement.JPake -{ - /// - /// The payload sent/received during the optional third round of a J-PAKE exchange, - /// which is for explicit key confirmation. - /// - /// Each JPAKEParticipant creates and sends an instance - /// of this payload to the other JPAKEParticipant. - /// The payload to send should be created via - /// JPAKEParticipant#createRound3PayloadToSend(BigInteger) - /// - /// Eeach JPAKEParticipant must also validate the payload - /// received from the other JPAKEParticipant. - /// The received payload should be validated via - /// JPAKEParticipant#validateRound3PayloadReceived(JPakeRound3Payload, BigInteger) - /// - public class JPakeRound3Payload - { - /// - /// The id of the {@link JPAKEParticipant} who created/sent this payload. - /// - private readonly string participantId; - - /// - /// The value of MacTag, as computed by round 3. - /// - /// See JPAKEUtil#calculateMacTag(string, string, BigInteger, BigInteger, BigInteger, BigInteger, BigInteger, org.bouncycastle.crypto.Digest) - /// - private readonly BigInteger macTag; - - public JPakeRound3Payload(string participantId, BigInteger magTag) - { - this.participantId = participantId; - this.macTag = magTag; - } - - public virtual string ParticipantId - { - get { return participantId; } - } - - public virtual BigInteger MacTag - { - get { return macTag; } - } - } -} diff --git a/crypto/src/crypto/agreement/jpake/JPakeParticipant.cs b/crypto/src/crypto/agreement/jpake/JPakeParticipant.cs new file mode 100755 index 000000000..f8ca2cd41 --- /dev/null +++ b/crypto/src/crypto/agreement/jpake/JPakeParticipant.cs @@ -0,0 +1,455 @@ +using System; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Agreement.JPake +{ + /// + /// A participant in a Password Authenticated Key Exchange by Juggling (J-PAKE) exchange. + /// + /// The J-PAKE exchange is defined by Feng Hao and Peter Ryan in the paper + /// + /// "Password Authenticated Key Exchange by Juggling, 2008." + /// + /// The J-PAKE protocol is symmetric. + /// There is no notion of a client or server, but rather just two participants. + /// 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, + /// 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 + /// CreateRound2PayloadToSend() - and send the payload to 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 + /// + /// 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). + /// + /// Round 3 is an optional key confirmation process. + /// If you do not execute round 3, then there is no assurance that both participants are using the same key. + /// (i.e. if the participants used different passwords, then their session keys will differ.) + /// + /// If the round 3 validation succeeds, then the keys are guaranteed to be the same on both sides. + /// + /// The symmetric design can easily support the asymmetric cases when one party initiates the communication. + /// e.g. Sometimes the round1 payload and round2 payload may be sent in one pass. + /// Also, in some cases, the key confirmation payload can be sent together with the round2 payload. + /// These are the trivial techniques to optimize the communication. + /// + /// The key confirmation process is implemented as specified in + /// NIST SP 800-56A Revision 1, + /// Section 8.2 Unilateral Key Confirmation for Key Agreement Schemes. + /// + /// 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). + /// + public class JPakeParticipant + { + // Possible internal states. Used for state checking. + public static readonly int STATE_INITIALIZED = 0; + public static readonly int STATE_ROUND_1_CREATED = 10; + public static readonly int STATE_ROUND_1_VALIDATED = 20; + public static readonly int STATE_ROUND_2_CREATED = 30; + public static readonly int STATE_ROUND_2_VALIDATED = 40; + public static readonly int STATE_KEY_CALCULATED = 50; + public static readonly int STATE_ROUND_3_CREATED = 60; + public static readonly int STATE_ROUND_3_VALIDATED = 70; + + // Unique identifier of this participant. + // The two participants in the exchange must NOT share the same id. + private string participantId; + + // Shared secret. This only contains the secret between construction + // and the call to CalculateKeyingMaterial(). + // + // i.e. When CalculateKeyingMaterial() is called, this buffer overwritten with 0's, + // and the field is set to null. + private char[] password; + + // Digest to use during calculations. + private IDigest digest; + + // Source of secure random data. + private readonly SecureRandom random; + + private readonly BigInteger p; + private readonly BigInteger q; + private readonly BigInteger g; + + // The participantId of the other participant in this exchange. + private string partnerParticipantId; + + // Alice's x1 or Bob's x3. + private BigInteger x1; + // Alice's x2 or Bob's x4. + private BigInteger x2; + // Alice's g^x1 or Bob's g^x3. + private BigInteger gx1; + // Alice's g^x2 or Bob's g^x4. + private BigInteger gx2; + // Alice's g^x3 or Bob's g^x1. + private BigInteger gx3; + // Alice's g^x4 or Bob's g^x2. + private BigInteger gx4; + // Alice's B or Bob's A. + private BigInteger b; + + // The current state. + // See the STATE_* constants for possible values. + private int state; + + /// + /// 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. + /// + /// Throws NullReferenceException if any argument is null. Throws + /// ArgumentException if password is empty. + /// + /// Unique identifier of this participant. + /// The two participants in the exchange must NOT share the same id. + /// 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. + public JPakeParticipant(string participantId, char[] password) + : this(participantId, password, JPakePrimeOrderGroups.NIST_3072) { } + + /// + /// 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. + /// + /// Throws NullReferenceException if any argument is null. Throws + /// ArgumentException if password is empty. + /// + /// Unique identifier of this participant. + /// The two participants in the exchange must NOT share the same id. + /// 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. + /// Prime order group. See JPakePrimeOrderGroups for standard groups. + public JPakeParticipant(string participantId, char[] password, JPakePrimeOrderGroup group) + : this(participantId, password, group, new Sha256Digest(), new SecureRandom()) { } + + + /// + /// Constructor for a new JPakeParticipant. + /// + /// After construction, the State state will be STATE_INITIALIZED. + /// + /// Throws NullReferenceException if any argument is null. Throws + /// ArgumentException if password is empty. + /// + /// Unique identifier of this participant. + /// The two participants in the exchange must NOT share the same id. + /// 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. + /// Prime order group. See JPakePrimeOrderGroups for standard groups. + /// Digest to use during zero knowledge proofs and key confirmation + /// (SHA-256 or stronger preferred). + /// Source of secure random data for x1 and x2, and for the zero knowledge proofs. + public JPakeParticipant(string participantId, char[] password, JPakePrimeOrderGroup group, IDigest digest, SecureRandom 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) + { + throw new ArgumentException("Password must not be empty."); + } + + this.participantId = participantId; + + // Create a defensive copy so as to fully encapsulate the password. + // + // This array will contain the password for the lifetime of this + // participant BEFORE CalculateKeyingMaterial() is called. + // + // i.e. When CalculateKeyingMaterial() is called, the array will be cleared + // in order to remove the password from memory. + // + // The caller is responsible for clearing the original password array + // given as input to this constructor. + this.password = new char[password.Length]; + Array.Copy(password, this.password, password.Length); + + this.p = group.P; + this.q = group.Q; + this.g = group.G; + + this.digest = digest; + this.random = random; + + this.state = STATE_INITIALIZED; + } + + /// + /// Gets the current state of this participant. + /// See the STATE_* constants for possible values. + /// + public virtual int State + { + get { return state; } + } + + + /// + /// Creates and returns the payload to send to the other participant during round 1. + /// + /// After execution, the State state} will be STATE_ROUND_1_CREATED}. + /// + public virtual JPakeRound1Payload CreateRound1PayloadToSend() + { + if (this.state >= STATE_ROUND_1_CREATED) + throw new InvalidOperationException("Round 1 payload already created for " + this.participantId); + + this.x1 = JPakeUtilities.GenerateX1(q, random); + this.x2 = JPakeUtilities.GenerateX2(q, 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); + } + + /// + /// Validates the payload received from the other participant during round 1. + /// + /// Must be called prior to CreateRound2PayloadToSend(). + /// + /// After execution, the State state will be STATE_ROUND_1_VALIDATED. + /// + /// Throws CryptoException if validation fails. Throws InvalidOperationException + /// if called multiple times. + /// + 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; + this.gx4 = round1PayloadReceived.Gx2; + + BigInteger[] knowledgeProofForX3 = round1PayloadReceived.KnowledgeProofForX1; + BigInteger[] knowledgeProofForX4 = round1PayloadReceived.KnowledgeProofForX2; + + 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; + } + + /// + /// Creates and returns the payload to send to the other participant during round 2. + /// + /// 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 + /// + 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 = 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); + } + + /// + /// Validates the payload received from the other participant during round 2. + /// Note that this DOES NOT detect a non-common password. + /// The only indication of a non-common password is through derivation + /// of different keys (which can be detected explicitly by executing round 3 and round 4) + /// + /// Must be called prior to CalculateKeyingMaterial(). + /// + /// 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 + /// + 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 = JPakeUtilities.CalculateGA(p, gx3, gx1, gx2); + this.b = round2PayloadReceived.A; + BigInteger[] knowledgeProofForX4s = round2PayloadReceived.KnowledgeProofForX2s; + + 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; + } + + /// + /// 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 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 + /// share the same password, then each participant will derive a different key. + /// 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. + /// + /// The keying material will be in the range [0, p-1]. + /// + /// 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), + /// or if called multiple times. + /// + 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 = 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 = 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. + // The old objects will hang around in memory until the garbage collector destroys them. + // + // If the ephemeral private keys x1 and x2 are leaked, + // the attacker might be able to brute-force the password. + this.x1 = null; + this.x2 = null; + this.b = null; + + // Do not clear gx* yet, since those are needed by round 3. + + this.state = STATE_KEY_CALCULATED; + + return keyingMaterial; + } + + /// + /// Creates and returns the payload to send to the other participant during 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. + /// + /// The keying material as returned from CalculateKeyingMaterial(). + 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 = JPakeUtilities.CalculateMacTag( + this.participantId, + this.partnerParticipantId, + this.gx1, + this.gx2, + this.gx3, + this.gx4, + keyingMaterial, + this.digest); + + this.state = STATE_ROUND_3_CREATED; + + return new JPakeRound3Payload(participantId, macTag); + } + + /// + /// Validates the payload received from the other participant during round 3. + /// + /// See JPakeParticipant for more details on round 3. + /// + /// After execution, the State state will be STATE_ROUND_3_VALIDATED. + /// + /// Throws CryptoException if validation fails. Throws InvalidOperationException if called prior to + /// CalculateKeyingMaterial or multiple times + /// + /// The keying material as returned from CalculateKeyingMaterial(). + 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); + + JPakeUtilities.ValidateParticipantIdsDiffer(participantId, round3PayloadReceived.ParticipantId); + JPakeUtilities.ValidateParticipantIdsEqual(this.partnerParticipantId, round3PayloadReceived.ParticipantId); + + JPakeUtilities.ValidateMacTag( + this.participantId, + this.partnerParticipantId, + this.gx1, + this.gx2, + this.gx3, + this.gx4, + keyingMaterial, + this.digest, + round3PayloadReceived.MacTag); + + // Clear the rest of the fields. + this.gx1 = null; + this.gx2 = null; + this.gx3 = null; + this.gx4 = null; + + this.state = STATE_ROUND_3_VALIDATED; + } + } +} diff --git a/crypto/src/crypto/agreement/jpake/JPakePrimeOrderGroup.cs b/crypto/src/crypto/agreement/jpake/JPakePrimeOrderGroup.cs new file mode 100755 index 000000000..08ffe1a55 --- /dev/null +++ b/crypto/src/crypto/agreement/jpake/JPakePrimeOrderGroup.cs @@ -0,0 +1,103 @@ +using System; + +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Crypto.Agreement.JPake +{ + /// + /// A pre-computed prime order group for use during a J-PAKE exchange. + /// + /// 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. + /// + /// NIST publishes + /// many groups that can be used for the desired level of security. + /// + public class JPakePrimeOrderGroup + { + private readonly BigInteger p; + private readonly BigInteger q; + private readonly BigInteger g; + + /// + /// Constructs a new JPakePrimeOrderGroup. + /// + /// In general, you should use one of the pre-approved groups from + /// JPakePrimeOrderGroups, rather than manually constructing one. + /// + /// The following basic checks are performed: + /// + /// p-1 must be evenly divisible by q + /// g must be in [2, p-1] + /// g^q mod p must equal 1 + /// p must be prime (within reasonably certainty) + /// q must be prime (within reasonably certainty) + /// + /// The prime checks are performed using BigInteger#isProbablePrime(int), + /// and are therefore subject to the same probability guarantees. + /// + /// These checks prevent trivial mistakes. + /// However, due to the small uncertainties if p and q are not prime, + /// advanced attacks are not prevented. + /// Use it at your own risk. + /// + /// Throws NullReferenceException if any argument is null. Throws + /// InvalidOperationException is any of the above validations fail. + /// + public JPakePrimeOrderGroup(BigInteger p, BigInteger q, BigInteger g) + : this(p, q, g, false) + { + // Don't skip the checks on user-specified groups. + } + + /// + /// 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. + /// + public JPakePrimeOrderGroup(BigInteger p, BigInteger q, BigInteger g, bool skipChecks) + { + JPakeUtilities.ValidateNotNull(p, "p"); + JPakeUtilities.ValidateNotNull(q, "q"); + JPakeUtilities.ValidateNotNull(g, "g"); + + if (!skipChecks) + { + 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.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(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; + this.q = q; + this.g = g; + } + + public virtual BigInteger P + { + get { return p; } + } + + public virtual BigInteger Q + { + get { return q; } + } + + 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 new file mode 100755 index 000000000..33640845a --- /dev/null +++ b/crypto/src/crypto/agreement/jpake/JPakePrimeOrderGroups.cs @@ -0,0 +1,108 @@ +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Crypto.Agreement.JPake +{ + /// + /// Standard pre-computed prime order groups for use by J-PAKE. + /// (J-PAKE can use pre-computed prime order groups, same as DSA and Diffie-Hellman.) + ///

+ /// This class contains some convenient constants for use as input for + /// constructing {@link JPAKEParticipant}s. + ///

+ /// The prime order groups below are taken from Sun's JDK JavaDoc (docs/guide/security/CryptoSpec.html#AppB), + /// and from the prime order groups + /// published by NIST. + ///

+ public class JPakePrimeOrderGroups + { + /// + /// 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. + /// + public static readonly JPakePrimeOrderGroup SUN_JCE_1024 = new JPakePrimeOrderGroup( + // p + new BigInteger( + "fd7f53811d75122952df4a9c2eece4e7f611b7523cef4400c31e3f80b6512669" + + "455d402251fb593d8d58fabfc5f5ba30f6cb9b556cd7813b801d346ff26660b7" + + "6b9950a5a49f9fe8047b1022c24fbba9d7feb7c61bf83b57e7c6a8a6150f04fb" + + "83f6d3c51ec3023554135a169132f675f3ae2b61d72aeff22203199dd14801c7", 16), + // q + new BigInteger("9760508f15230bccb292b982a2eb840bf0581cf5", 16), + // g + new BigInteger( + "f7e1a085d69b3ddecbbcab5c36b857b97994afbbfa3aea82f9574c0b3d078267" + + "5159578ebad4594fe67107108180b449167123e84c281613b7cf09328cc8a6e1" + + "3c167a8b547c8d28e0a3ae1e2bb3a675916ea37f0bfa213562f1fb627a01243b" + + "cca4f1bea8519089a883dfe15ae59f06928b665e807b552564014c3bfecf492a", 16), + true + ); + + /// + /// From NIST. + /// 2048-bit p, 224-bit q and 2048-bit g for 112-bit security. + /// + public static readonly JPakePrimeOrderGroup NIST_2048 = new JPakePrimeOrderGroup( + // p + new BigInteger( + "C196BA05AC29E1F9C3C72D56DFFC6154A033F1477AC88EC37F09BE6C5BB95F51" + + "C296DD20D1A28A067CCC4D4316A4BD1DCA55ED1066D438C35AEBAABF57E7DAE4" + + "28782A95ECA1C143DB701FD48533A3C18F0FE23557EA7AE619ECACC7E0B51652" + + "A8776D02A425567DED36EABD90CA33A1E8D988F0BBB92D02D1D20290113BB562" + + "CE1FC856EEB7CDD92D33EEA6F410859B179E7E789A8F75F645FAE2E136D252BF" + + "FAFF89528945C1ABE705A38DBC2D364AADE99BE0D0AAD82E5320121496DC65B3" + + "930E38047294FF877831A16D5228418DE8AB275D7D75651CEFED65F78AFC3EA7" + + "FE4D79B35F62A0402A1117599ADAC7B269A59F353CF450E6982D3B1702D9CA83", 16), + // q + new BigInteger("90EAF4D1AF0708B1B612FF35E0A2997EB9E9D263C9CE659528945C0D", 16), + // g + new BigInteger( + "A59A749A11242C58C894E9E5A91804E8FA0AC64B56288F8D47D51B1EDC4D6544" + + "4FECA0111D78F35FC9FDD4CB1F1B79A3BA9CBEE83A3F811012503C8117F98E50" + + "48B089E387AF6949BF8784EBD9EF45876F2E6A5A495BE64B6E770409494B7FEE" + + "1DBB1E4B2BC2A53D4F893D418B7159592E4FFFDF6969E91D770DAEBD0B5CB14C" + + "00AD68EC7DC1E5745EA55C706C4A1C5C88964E34D09DEB753AD418C1AD0F4FDF" + + "D049A955E5D78491C0B7A2F1575A008CCD727AB376DB6E695515B05BD412F5B8" + + "C2F4C77EE10DA48ABD53F5DD498927EE7B692BBBCDA2FB23A516C5B4533D7398" + + "0B2A3B60E384ED200AE21B40D273651AD6060C13D97FD69AA13C5611A51B9085", 16), + true + ); + + /// + /// From NIST. + /// 3072-bit p, 256-bit q and 3072-bit g for 128-bit security. + /// + public static readonly JPakePrimeOrderGroup NIST_3072 = new JPakePrimeOrderGroup( + // p + new BigInteger( + "90066455B5CFC38F9CAA4A48B4281F292C260FEEF01FD61037E56258A7795A1C" + + "7AD46076982CE6BB956936C6AB4DCFE05E6784586940CA544B9B2140E1EB523F" + + "009D20A7E7880E4E5BFA690F1B9004A27811CD9904AF70420EEFD6EA11EF7DA1" + + "29F58835FF56B89FAA637BC9AC2EFAAB903402229F491D8D3485261CD068699B" + + "6BA58A1DDBBEF6DB51E8FE34E8A78E542D7BA351C21EA8D8F1D29F5D5D159394" + + "87E27F4416B0CA632C59EFD1B1EB66511A5A0FBF615B766C5862D0BD8A3FE7A0" + + "E0DA0FB2FE1FCB19E8F9996A8EA0FCCDE538175238FC8B0EE6F29AF7F642773E" + + "BE8CD5402415A01451A840476B2FCEB0E388D30D4B376C37FE401C2A2C2F941D" + + "AD179C540C1C8CE030D460C4D983BE9AB0B20F69144C1AE13F9383EA1C08504F" + + "B0BF321503EFE43488310DD8DC77EC5B8349B8BFE97C2C560EA878DE87C11E3D" + + "597F1FEA742D73EEC7F37BE43949EF1A0D15C3F3E3FC0A8335617055AC91328E" + + "C22B50FC15B941D3D1624CD88BC25F3E941FDDC6200689581BFEC416B4B2CB73", 16), + // q + new BigInteger("CFA0478A54717B08CE64805B76E5B14249A77A4838469DF7F7DC987EFCCFB11D", 16), + // g + new BigInteger( + "5E5CBA992E0A680D885EB903AEA78E4A45A469103D448EDE3B7ACCC54D521E37" + + "F84A4BDD5B06B0970CC2D2BBB715F7B82846F9A0C393914C792E6A923E2117AB" + + "805276A975AADB5261D91673EA9AAFFEECBFA6183DFCB5D3B7332AA19275AFA1" + + "F8EC0B60FB6F66CC23AE4870791D5982AAD1AA9485FD8F4A60126FEB2CF05DB8" + + "A7F0F09B3397F3937F2E90B9E5B9C9B6EFEF642BC48351C46FB171B9BFA9EF17" + + "A961CE96C7E7A7CC3D3D03DFAD1078BA21DA425198F07D2481622BCE45969D9C" + + "4D6063D72AB7A0F08B2F49A7CC6AF335E08C4720E31476B67299E231F8BD90B3" + + "9AC3AE3BE0C6B6CACEF8289A2E2873D58E51E029CAFBD55E6841489AB66B5B4B" + + "9BA6E2F784660896AFF387D92844CCB8B69475496DE19DA2E58259B090489AC8" + + "E62363CDF82CFD8EF2A427ABCD65750B506F56DDE3B988567A88126B914D7828" + + "E2B63A6D7ED0747EC59E0E0A23CE7D8A74C1D2C2A7AFB6A29799620F00E11C33" + + "787F7DED3B30E1A22D09F1FBDA1ABBBFBF25CAE05A13F812E34563F99410E73B", 16), + true + ); + } +} diff --git a/crypto/src/crypto/agreement/jpake/JPakeRound1Payload.cs b/crypto/src/crypto/agreement/jpake/JPakeRound1Payload.cs new file mode 100755 index 000000000..9e4ab7a5f --- /dev/null +++ b/crypto/src/crypto/agreement/jpake/JPakeRound1Payload.cs @@ -0,0 +1,101 @@ +using System; + +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Crypto.Agreement.JPake +{ + /// + /// The payload sent/received during the first round of a J-PAKE exchange. + /// + /// Each JPAKEParticipant creates and sends an instance of this payload to + /// the other. The payload to send should be created via + /// JPAKEParticipant.CreateRound1PayloadToSend(). + /// + /// Each participant must also validate the payload received from the other. + /// The received payload should be validated via + /// JPAKEParticipant.ValidateRound1PayloadReceived(JPakeRound1Payload). + /// + public class JPakeRound1Payload + { + /// + /// The id of the JPAKEParticipant who created/sent this payload. + /// + private readonly string participantId; + + /// + /// The value of g^x1 + /// + private readonly BigInteger gx1; + + /// + /// The value of g^x2 + /// + private readonly BigInteger gx2; + + /// + /// The zero knowledge proof for x1. + /// + /// This is a two element array, containing {g^v, r} for x1. + /// + private readonly BigInteger[] knowledgeProofForX1; + + /// + /// The zero knowledge proof for x2. + /// + /// This is a two element array, containing {g^v, r} for x2. + /// + private readonly BigInteger[] knowledgeProofForX2; + + public JPakeRound1Payload(string participantId, BigInteger gx1, BigInteger gx2, BigInteger[] knowledgeProofForX1, BigInteger[] 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; + this.gx2 = gx2; + this.knowledgeProofForX1 = new BigInteger[knowledgeProofForX1.Length]; + Array.Copy(knowledgeProofForX1, this.knowledgeProofForX1, knowledgeProofForX1.Length); + this.knowledgeProofForX2 = new BigInteger[knowledgeProofForX2.Length]; + Array.Copy(knowledgeProofForX2, this.knowledgeProofForX2, knowledgeProofForX2.Length); + } + + public virtual string ParticipantId + { + get { return participantId; } + } + + public virtual BigInteger Gx1 + { + get { return gx1; } + } + + public virtual BigInteger Gx2 + { + get { return gx2; } + } + + public virtual BigInteger[] KnowledgeProofForX1 + { + get + { + BigInteger[] kp = new BigInteger[knowledgeProofForX1.Length]; + Array.Copy(knowledgeProofForX1, kp, knowledgeProofForX1.Length); + return kp; + } + } + + public virtual BigInteger[] KnowledgeProofForX2 + { + get + { + BigInteger[] kp = new BigInteger[knowledgeProofForX2.Length]; + Array.Copy(knowledgeProofForX2, kp, knowledgeProofForX2.Length); + return kp; + } + } + } +} diff --git a/crypto/src/crypto/agreement/jpake/JPakeRound2Payload.cs b/crypto/src/crypto/agreement/jpake/JPakeRound2Payload.cs new file mode 100755 index 000000000..47962cb3f --- /dev/null +++ b/crypto/src/crypto/agreement/jpake/JPakeRound2Payload.cs @@ -0,0 +1,72 @@ +using System; + +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Agreement.JPake +{ + /// + /// The payload sent/received during the second round of a J-PAKE exchange. + /// + /// Each JPAKEParticipant creates and sends an instance + /// of this payload to the other JPAKEParticipant. + /// The payload to send should be created via + /// JPAKEParticipant#createRound2PayloadToSend() + /// + /// Each JPAKEParticipant must also validate the payload + /// received from the other JPAKEParticipant. + /// The received payload should be validated via + /// JPAKEParticipant#validateRound2PayloadReceived(JPakeRound2Payload) + /// + public class JPakeRound2Payload + { + /// + /// The id of the JPAKEParticipant who created/sent this payload. + /// + private readonly string participantId; + + /// + /// The value of A, as computed during round 2. + /// + private readonly BigInteger a; + + /// + /// The zero knowledge proof for x2 * s. + /// + /// This is a two element array, containing {g^v, r} for x2 * s. + /// + private readonly BigInteger[] knowledgeProofForX2s; + + public JPakeRound2Payload(string participantId, BigInteger a, BigInteger[] knowledgeProofForX2s) + { + JPakeUtilities.ValidateNotNull(participantId, "participantId"); + JPakeUtilities.ValidateNotNull(a, "a"); + JPakeUtilities.ValidateNotNull(knowledgeProofForX2s, "knowledgeProofForX2s"); + + this.participantId = participantId; + this.a = a; + this.knowledgeProofForX2s = new BigInteger[knowledgeProofForX2s.Length]; + knowledgeProofForX2s.CopyTo(this.knowledgeProofForX2s, 0); + } + + public virtual string ParticipantId + { + get { return participantId; } + } + + public virtual BigInteger A + { + get { return a; } + } + + public virtual BigInteger[] KnowledgeProofForX2s + { + get + { + BigInteger[] kp = new BigInteger[knowledgeProofForX2s.Length]; + Array.Copy(knowledgeProofForX2s, kp, knowledgeProofForX2s.Length); + return kp; + } + } + } +} diff --git a/crypto/src/crypto/agreement/jpake/JPakeRound3Payload.cs b/crypto/src/crypto/agreement/jpake/JPakeRound3Payload.cs new file mode 100755 index 000000000..767702f23 --- /dev/null +++ b/crypto/src/crypto/agreement/jpake/JPakeRound3Payload.cs @@ -0,0 +1,51 @@ +using System; + +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Crypto.Agreement.JPake +{ + /// + /// The payload sent/received during the optional third round of a J-PAKE exchange, + /// which is for explicit key confirmation. + /// + /// Each JPAKEParticipant creates and sends an instance + /// of this payload to the other JPAKEParticipant. + /// The payload to send should be created via + /// JPAKEParticipant#createRound3PayloadToSend(BigInteger) + /// + /// Eeach JPAKEParticipant must also validate the payload + /// received from the other JPAKEParticipant. + /// The received payload should be validated via + /// JPAKEParticipant#validateRound3PayloadReceived(JPakeRound3Payload, BigInteger) + /// + public class JPakeRound3Payload + { + /// + /// The id of the {@link JPAKEParticipant} who created/sent this payload. + /// + private readonly string participantId; + + /// + /// The value of MacTag, as computed by round 3. + /// + /// See JPAKEUtil#calculateMacTag(string, string, BigInteger, BigInteger, BigInteger, BigInteger, BigInteger, org.bouncycastle.crypto.Digest) + /// + private readonly BigInteger macTag; + + public JPakeRound3Payload(string participantId, BigInteger magTag) + { + this.participantId = participantId; + this.macTag = magTag; + } + + public virtual string ParticipantId + { + get { return participantId; } + } + + public virtual BigInteger MacTag + { + get { return macTag; } + } + } +} -- cgit 1.5.1