Esempio n. 1
0
        /// <summary>
        ///     Validates the round 2 (zero-knowledge proof) DTO received from the partner participant.
        /// </summary>
        /// <param name="round2Received">Round 2 DTO received form partner participant.</param>
        /// <exception cref="InvalidOperationException">
        ///     Prior round (1) has not been completed yet, or method may have been called more than once.
        /// </exception>
        /// <exception cref="CryptoException">
        ///     Verification of zero-knowledge proof failed. Possible attempted impersonation, e.g. MiTM.
        /// </exception>
        public void ValidateRound2Received(ECJpakeRound2 round2Received)
        {
            Contract.Requires <InvalidOperationException>(ProtocolState < State.Round2Validated,
                                                          "Validation already attempted for round 2 payload.");
            Contract.Requires <InvalidOperationException>(ProtocolState > State.Round1Validated,
                                                          "Round 1 payload must be validated prior to validating round 2 payload.");

            Contract.Requires <ConfigurationInvalidException>(String.IsNullOrEmpty(round2Received.ParticipantId) == false,
                                                              "Partner participant ID in round 2 DTO received is null or empty.");
            Contract.Requires <CryptoException>(PartnerParticipantId.Equals(round2Received.ParticipantId, StringComparison.Ordinal),
                                                "Partner participant ID of round 2 DTO does not match value from round 1.");

            ECPoint X4sV = _domain.Curve.DecodePoint(round2Received.X2sV);
            var     X4sR = new BigInteger(round2Received.X2sR);

            _b = _domain.Curve.DecodePoint(round2Received.A);
            // Calculate GB : GX1 + GX3 + GX4 symmetrically
            ECPoint GB = _gx3.Add(_gx1).Add(_gx2);

            if (ZeroKnowledgeProofValid(GB, _b, X4sV, X4sR, PartnerParticipantId) == false)
            {
                throw new CryptoException("Round 2 validation failed. Possible impersonation attempt.");
            }

            ProtocolState = State.Round2Validated;
        }
Esempio n. 2
0
        /// <summary>
        ///     Validates the round 3 (key confirmation) DTO received from the partner participant.
        /// </summary>
        /// <param name="round3Received">Round 3 DTO received from partner participant.</param>
        /// <param name="keyingMaterial">Shared secret to be derived further before use as a key (e.g. by a KDF).</param>
        /// <exception cref="InvalidOperationException">
        ///     Key calculation and/or prior rounds (1 and 2) have not been completed yet, or
        ///     method may have been called more than once.
        /// </exception>
        /// <exception cref="CryptoException">
        ///     Key confirmation failed - partner participant derived a different key. The passphrase used differs.
        ///     Possible attempted impersonation / MiTM.
        /// </exception>
        public void ValidateRound3Received(JpakeRound3 round3Received, out byte[] keyingMaterial)
        {
            Contract.Requires <InvalidOperationException>(ProtocolState < State.Round3Validated,
                                                          "Validation already attempted for round 3 payload.");
//            Contract.Requires<InvalidOperationException>(ProtocolState > State.KeyCalculated,
//                "Keying material must be calculated validated prior to validating round 3.");
            Contract.Requires <InvalidOperationException>(ProtocolState > State.Round2Validated,
                                                          "Round 2 must be validated prior to validating round 3.");

            Contract.Requires <ConfigurationInvalidException>(String.IsNullOrEmpty(round3Received.ParticipantId) == false,
                                                              "Partner participant ID in round 3 DTO received is null or empty.");
            Contract.Requires <CryptoException>(PartnerParticipantId.Equals(round3Received.ParticipantId, StringComparison.Ordinal),
                                                "Partner participant ID of round 3 DTO does not match value from prior rounds (1 and 2).");

            var receivedTag = new BigInteger(round3Received.VerifiedOutput);

            if (_keyingMaterial == null)
            {
                CalculateKeyingMaterialInternal();
            }

            BigInteger expectedTag = CalculateMacTag(PartnerParticipantId, ParticipantId,
                                                     _gx3, _gx4, _gx1, _gx2, _keyingMaterial);

            byte[] expectedMacTagBytes = expectedTag.ToByteArrayUnsigned();
            byte[] receivedMacTagBytes = receivedTag.ToByteArrayUnsigned();

            if (expectedMacTagBytes.SequenceEqual_ConstantTime(receivedMacTagBytes) == false)
            {
                throw new CryptoException("Key confirmation failed - partner MAC tag failed to match expected value.");
            }

            // Return the confirmed key to the participant
            keyingMaterial = _keyingMaterial.ToByteArrayUnsigned();

            // Clear sensitive state
            _keyingMaterial = null;
            _passwordBytes  = null;
            _macTag         = null;
            _x2             = null;
            _gx1            = null;
            _gx2            = null;
            _gx3            = null;
            _gx4            = null;

            ProtocolState = State.Round3Validated;
        }
Esempio n. 3
0
        /// <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.");
                }
            }
        }