// 
// Decompiled by Procyon v0.6.0
// 

package org.bouncycastle.crypto.examples;

import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.crypto.agreement.ecjpake.ECJPAKERound3Payload;
import org.bouncycastle.crypto.agreement.ecjpake.ECJPAKERound2Payload;
import org.bouncycastle.crypto.agreement.ecjpake.ECJPAKERound1Payload;
import org.bouncycastle.crypto.SavableDigest;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.crypto.agreement.ecjpake.ECJPAKECurve;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.agreement.ecjpake.ECJPAKEParticipant;
import java.security.SecureRandom;
import org.bouncycastle.crypto.digests.SHA256Digest;
import java.math.BigInteger;
import org.bouncycastle.crypto.agreement.ecjpake.ECJPAKECurves;

public class ECJPAKEExample
{
    public static void main(final String[] array) throws CryptoException {
        final ECJPAKECurve nist_P256 = ECJPAKECurves.NIST_P256;
        final BigInteger a = nist_P256.getA();
        final BigInteger b = nist_P256.getB();
        final ECPoint g = nist_P256.getG();
        final BigInteger h = nist_P256.getH();
        final BigInteger n = nist_P256.getN();
        final BigInteger q = nist_P256.getQ();
        final String str = "password";
        final String str2 = "password";
        System.out.println("********* Initialization **********");
        System.out.println("Public parameters for the elliptic curve over prime field:");
        System.out.println("Curve param a (" + a.bitLength() + " bits): " + a.toString(16));
        System.out.println("Curve param b (" + b.bitLength() + " bits): " + b.toString(16));
        System.out.println("Co-factor h (" + h.bitLength() + " bits): " + h.toString(16));
        System.out.println("Base point G (" + g.getEncoded(true).length + " bytes): " + new BigInteger(g.getEncoded(true)).toString(16));
        System.out.println("X coord of G (G not normalised) (" + g.getXCoord().toBigInteger().bitLength() + " bits): " + g.getXCoord().toBigInteger().toString(16));
        System.out.println("y coord of G (G not normalised) (" + g.getYCoord().toBigInteger().bitLength() + " bits): " + g.getYCoord().toBigInteger().toString(16));
        System.out.println("Order of the base point n (" + n.bitLength() + " bits): " + n.toString(16));
        System.out.println("Prime field q (" + q.bitLength() + " bits): " + q.toString(16));
        System.out.println("");
        System.out.println("(Secret passwords used by Alice and Bob: \"" + str + "\" and \"" + str2 + "\")\n");
        final SavableDigest instance = SHA256Digest.newInstance();
        final SecureRandom secureRandom = new SecureRandom();
        final ECJPAKEParticipant ecjpakeParticipant = new ECJPAKEParticipant("alice", str.toCharArray(), nist_P256, instance, secureRandom);
        final ECJPAKEParticipant ecjpakeParticipant2 = new ECJPAKEParticipant("bob", str2.toCharArray(), nist_P256, instance, secureRandom);
        final ECJPAKERound1Payload round1PayloadToSend = ecjpakeParticipant.createRound1PayloadToSend();
        final ECJPAKERound1Payload round1PayloadToSend2 = ecjpakeParticipant2.createRound1PayloadToSend();
        System.out.println("************ Round 1 **************");
        System.out.println("Alice sends to Bob: ");
        System.out.println("g^{x1}=" + new BigInteger(round1PayloadToSend.getGx1().getEncoded(true)).toString(16));
        System.out.println("g^{x2}=" + new BigInteger(round1PayloadToSend.getGx2().getEncoded(true)).toString(16));
        System.out.println("KP{x1}: {V=" + new BigInteger(round1PayloadToSend.getKnowledgeProofForX1().getV().getEncoded(true)).toString(16) + "; r=" + round1PayloadToSend.getKnowledgeProofForX1().getr().toString(16) + "}");
        System.out.println("KP{x2}: {V=" + new BigInteger(round1PayloadToSend.getKnowledgeProofForX2().getV().getEncoded(true)).toString(16) + "; r=" + round1PayloadToSend.getKnowledgeProofForX2().getr().toString(16) + "}");
        System.out.println("");
        System.out.println("Bob sends to Alice: ");
        System.out.println("g^{x3}=" + new BigInteger(round1PayloadToSend2.getGx1().getEncoded(true)).toString(16));
        System.out.println("g^{x4}=" + new BigInteger(round1PayloadToSend2.getGx2().getEncoded(true)).toString(16));
        System.out.println("KP{x3}: {V=" + new BigInteger(round1PayloadToSend2.getKnowledgeProofForX1().getV().getEncoded(true)).toString(16) + "; r=" + round1PayloadToSend2.getKnowledgeProofForX1().getr().toString(16) + "}");
        System.out.println("KP{x4}: {V=" + new BigInteger(round1PayloadToSend2.getKnowledgeProofForX2().getV().getEncoded(true)).toString(16) + "; r=" + round1PayloadToSend2.getKnowledgeProofForX2().getr().toString(16) + "}");
        System.out.println("");
        ecjpakeParticipant.validateRound1PayloadReceived(round1PayloadToSend2);
        System.out.println("Alice checks g^{x4}!=1: OK");
        System.out.println("Alice checks KP{x3}: OK");
        System.out.println("Alice checks KP{x4}: OK");
        System.out.println("");
        ecjpakeParticipant2.validateRound1PayloadReceived(round1PayloadToSend);
        System.out.println("Bob checks g^{x2}!=1: OK");
        System.out.println("Bob checks KP{x1},: OK");
        System.out.println("Bob checks KP{x2},: OK");
        System.out.println("");
        final ECJPAKERound2Payload round2PayloadToSend = ecjpakeParticipant.createRound2PayloadToSend();
        final ECJPAKERound2Payload round2PayloadToSend2 = ecjpakeParticipant2.createRound2PayloadToSend();
        System.out.println("************ Round 2 **************");
        System.out.println("Alice sends to Bob: ");
        System.out.println("A=" + new BigInteger(round2PayloadToSend.getA().getEncoded(true)).toString(16));
        System.out.println("KP{x2*s}: {V=" + new BigInteger(round2PayloadToSend.getKnowledgeProofForX2s().getV().getEncoded(true)).toString(16) + ", r=" + round2PayloadToSend.getKnowledgeProofForX2s().getr().toString(16) + "}");
        System.out.println("");
        System.out.println("Bob sends to Alice");
        System.out.println("B=" + new BigInteger(round2PayloadToSend2.getA().getEncoded(true)).toString(16));
        System.out.println("KP{x4*s}: {V=" + new BigInteger(round2PayloadToSend2.getKnowledgeProofForX2s().getV().getEncoded(true)).toString(16) + ", r=" + round2PayloadToSend2.getKnowledgeProofForX2s().getr().toString(16) + "}");
        System.out.println("");
        ecjpakeParticipant.validateRound2PayloadReceived(round2PayloadToSend2);
        System.out.println("Alice checks KP{x4*s}: OK\n");
        ecjpakeParticipant2.validateRound2PayloadReceived(round2PayloadToSend);
        System.out.println("Bob checks KP{x2*s}: OK\n");
        final BigInteger calculateKeyingMaterial = ecjpakeParticipant.calculateKeyingMaterial();
        final BigInteger calculateKeyingMaterial2 = ecjpakeParticipant2.calculateKeyingMaterial();
        System.out.println("********* After round 2 ***********");
        System.out.println("Alice computes key material \t K=" + calculateKeyingMaterial.toString(16));
        System.out.println("Bob computes key material \t K=" + calculateKeyingMaterial2.toString(16));
        System.out.println();
        deriveSessionKey(calculateKeyingMaterial);
        deriveSessionKey(calculateKeyingMaterial2);
        final ECJPAKERound3Payload round3PayloadToSend = ecjpakeParticipant.createRound3PayloadToSend(calculateKeyingMaterial);
        final ECJPAKERound3Payload round3PayloadToSend2 = ecjpakeParticipant2.createRound3PayloadToSend(calculateKeyingMaterial2);
        System.out.println("************ Round 3 **************");
        System.out.println("Alice sends to Bob: ");
        System.out.println("MacTag=" + round3PayloadToSend.getMacTag().toString(16));
        System.out.println("");
        System.out.println("Bob sends to Alice: ");
        System.out.println("MacTag=" + round3PayloadToSend2.getMacTag().toString(16));
        System.out.println("");
        ecjpakeParticipant.validateRound3PayloadReceived(round3PayloadToSend2, calculateKeyingMaterial);
        System.out.println("Alice checks MacTag: OK\n");
        ecjpakeParticipant2.validateRound3PayloadReceived(round3PayloadToSend, calculateKeyingMaterial2);
        System.out.println("Bob checks MacTag: OK\n");
        System.out.println();
        System.out.println("MacTags validated, therefore the keying material matches.");
    }
    
    private static BigInteger deriveSessionKey(final BigInteger bigInteger) {
        final SavableDigest instance = SHA256Digest.newInstance();
        final byte[] byteArray = bigInteger.toByteArray();
        final byte[] val = new byte[instance.getDigestSize()];
        instance.update(byteArray, 0, byteArray.length);
        instance.doFinal(val, 0);
        return new BigInteger(val);
    }
}
