/// <summary> /// Creates a round 1 (zero-knowledge proof) DTO to send to the partner participant. /// </summary> public ECJpakeRound1 CreateRound1ToSend() { Contract.Requires(ProtocolState < State.Round1Created, "Round 1 payload already created."); BigInteger x1 = BigInteger.CreateRandomInRange(BigInteger.One, _domain.N.Subtract(BigInteger.One), EntropySupply); _x2 = BigInteger.CreateRandomInRange(BigInteger.One, _domain.N.Subtract(BigInteger.One), EntropySupply); _gx1 = BasePointMultiplier.Multiply(_domain.G, x1); _gx2 = BasePointMultiplier.Multiply(_domain.G, _x2); ECPoint V1, V2; BigInteger r1, r2; CreateZeroKnowledgeProof(_domain.G, x1, _gx1, ParticipantId, out V1, out r1); CreateZeroKnowledgeProof(_domain.G, _x2, _gx2, ParticipantId, out V2, out r2); var dto = new ECJpakeRound1 { ParticipantId = ParticipantId, GX1 = _gx1.GetEncoded(), X1V = V1.GetEncoded(), X1R = r1.ToByteArray(), GX2 = _gx2.GetEncoded(), X2V = V2.GetEncoded(), X2R = r2.ToByteArray() }; ProtocolState = State.Round1Created; return(dto); }
/// <summary> /// Validates the round 1 (zero-knowledge proof) DTO received from the partner participant. /// </summary> /// <param name="round1Received">Round 1 DTO received from partner participant.</param> public void ValidateRound1Received(ECJpakeRound1 round1Received) { Contract.Requires <InvalidOperationException>(ProtocolState < State.Round1Validated, "Validation already attempted for round 1 payload."); Contract.Requires <ConfigurationInvalidException>(String.IsNullOrEmpty(round1Received.ParticipantId) == false, "Partner participant ID in round 1 DTO received is null or empty."); PartnerParticipantId = round1Received.ParticipantId; _gx3 = _domain.Curve.DecodePoint(round1Received.GX1); _gx4 = _domain.Curve.DecodePoint(round1Received.GX2); ECPoint X3V = _domain.Curve.DecodePoint(round1Received.X1V); var X3R = new BigInteger(round1Received.X1R); ECPoint X4V = _domain.Curve.DecodePoint(round1Received.X2V); var X4R = new BigInteger(round1Received.X2R); if (ZeroKnowledgeProofValid(_domain.G, _gx3, X3V, X3R, PartnerParticipantId) == false || ZeroKnowledgeProofValid(_domain.G, _gx4, X4V, X4R, PartnerParticipantId) == false) { throw new CryptoException("Verification of zero-knowledge proof in round 1 failed."); } ProtocolState = State.Round1Validated; }
/// <summary> /// Restores the state of an incomplete J-PAKE session, /// given private keys and DTO objects created/received from that session. /// </summary> /// <param name="x2">Private key.</param> /// <param name="round1Created">Round 1 created/sent.</param> /// <param name="round1Received">Round 1 received.</param> /// <param name="round2Created">Round 2 created/sent.</param> /// <param name="round2Received">Round 2 received.</param> /// <param name="round3Created">Round 3 created/sent.</param> public void RestoreState(byte[] x2, ECJpakeRound1 round1Created, ECJpakeRound1 round1Received = null, ECJpakeRound2 round2Created = null, ECJpakeRound2 round2Received = null, JpakeRound3 round3Created = null) { Contract.Requires(ProtocolState == State.Initialised, "Cannot restore state of already-active protocol session!"); Contract.Requires(round1Created != null); _gx1 = _domain.Curve.DecodePoint(round1Created.GX1); _gx2 = _domain.Curve.DecodePoint(round1Created.GX2); ProtocolState = State.Round1Created; if (round1Received != null) { if (String.IsNullOrEmpty(round1Received.ParticipantId)) { throw new ArgumentException("Partner participant ID in round 1 received is null or empty."); } PartnerParticipantId = round1Received.ParticipantId; _gx3 = _domain.Curve.DecodePoint(round1Received.GX1); _gx4 = _domain.Curve.DecodePoint(round1Received.GX2); ProtocolState = State.Round1Validated; } else { return; } if (round2Created != null) { ProtocolState = State.Round2Created; } else { return; } if (round2Received != null) { if (PartnerParticipantId.Equals(round2Received.ParticipantId, StringComparison.Ordinal) == false) { throw new ArgumentException("Partner participant ID of round 2 does not match value from round 1."); } _b = _domain.Curve.DecodePoint(round2Received.A); ProtocolState = State.Round2Validated; } else { return; } if (round3Created != null) { // Keying material has been calculated _b = _domain.Curve.DecodePoint(round2Received.A); ProtocolState = State.Round3Created; } else { if (x2.IsNullOrZeroLength()) { throw new ArgumentException("Session cannot be resumed without private key x2Export. Aborting."); } } }