/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.gecko.sync.jpake.stage; import java.io.UnsupportedEncodingException; import java.math.BigInteger; import java.security.NoSuchAlgorithmException; import org.mozilla.gecko.sync.ExtendedJSONObject; import org.mozilla.gecko.sync.Logger; import org.mozilla.gecko.sync.NonObjectJSONException; import org.mozilla.gecko.sync.jpake.BigIntegerHelper; import org.mozilla.gecko.sync.jpake.Gx3OrGx4IsZeroOrOneException; import org.mozilla.gecko.sync.jpake.IncorrectZkpException; import org.mozilla.gecko.sync.jpake.JPakeClient; import org.mozilla.gecko.sync.jpake.JPakeCrypto; import org.mozilla.gecko.sync.jpake.JPakeJson; import org.mozilla.gecko.sync.jpake.Zkp; import org.mozilla.gecko.sync.setup.Constants; public class ComputeStepTwoStage extends JPakeStage { @Override public void execute(JPakeClient jClient) { Logger.debug(LOG_TAG, "Computing round 2."); // Check incoming message sender. if (!jClient.jIncoming.get(Constants.JSON_KEY_TYPE).equals(jClient.theirSignerId + "1")) { Logger.error(LOG_TAG, "Invalid round 1 message: " + jClient.jIncoming.toJSONString()); jClient.abort(Constants.JPAKE_ERROR_WRONGMESSAGE); return; } // Check incoming message fields. ExtendedJSONObject iPayload; try { iPayload = jClient.jIncoming.getObject(Constants.JSON_KEY_PAYLOAD); } catch (NonObjectJSONException e) { Logger.error(LOG_TAG, "JSON object exception.", e); jClient.abort(Constants.JPAKE_ERROR_INVALID); return; } if (iPayload == null) { Logger.error(LOG_TAG, "Invalid round 1 message: " + jClient.jIncoming.toJSONString()); jClient.abort(Constants.JPAKE_ERROR_WRONGMESSAGE); return; } ExtendedJSONObject zkpPayload3; ExtendedJSONObject zkpPayload4; try { zkpPayload3 = iPayload.getObject(Constants.ZKP_KEY_ZKP_X1); zkpPayload4 = iPayload.getObject(Constants.ZKP_KEY_ZKP_X2); } catch (NonObjectJSONException e1) { jClient.abort(Constants.JPAKE_ERROR_INVALID); return; } if (zkpPayload3 == null || zkpPayload4 == null) { Logger.error(LOG_TAG, "Invalid round 1 zkpPayload message"); jClient.abort(Constants.JPAKE_ERROR_WRONGMESSAGE); return; } if (!jClient.theirSignerId.equals(zkpPayload3.get(Constants.ZKP_KEY_ID)) || !jClient.theirSignerId.equals(zkpPayload4.get(Constants.ZKP_KEY_ID))) { Logger.error(LOG_TAG, "Invalid round 1 zkpPayload message"); jClient.abort(Constants.JPAKE_ERROR_WRONGMESSAGE); return; } // Extract message fields. jClient.jParty.gx3 = new BigInteger((String) iPayload.get(Constants.ZKP_KEY_GX1), 16); jClient.jParty.gx4 = new BigInteger((String) iPayload.get(Constants.ZKP_KEY_GX2), 16); // Extract ZKPs. String zkp3_gr = (String) zkpPayload3.get(Constants.ZKP_KEY_GR); String zkp3_b = (String) zkpPayload3.get(Constants.ZKP_KEY_B); String zkp3_id = (String) zkpPayload3.get(Constants.ZKP_KEY_ID); String zkp4_gr = (String) zkpPayload4.get(Constants.ZKP_KEY_GR); String zkp4_b = (String) zkpPayload4.get(Constants.ZKP_KEY_B); String zkp4_id = (String) zkpPayload4.get(Constants.ZKP_KEY_ID); jClient.jParty.zkp3 = new Zkp(new BigInteger(zkp3_gr, 16), new BigInteger(zkp3_b, 16), zkp3_id); jClient.jParty.zkp4 = new Zkp(new BigInteger(zkp4_gr, 16), new BigInteger(zkp4_b, 16), zkp4_id); // J-PAKE round 2. try { JPakeCrypto.round2(JPakeClient.secretAsBigInteger(jClient.secret), jClient.jParty, jClient.numGen); } catch (Gx3OrGx4IsZeroOrOneException e) { Logger.error(LOG_TAG, "gx3 and gx4 cannot equal 0 or 1."); jClient.abort(Constants.JPAKE_ERROR_INTERNAL); return; } catch (IncorrectZkpException e) { Logger.error(LOG_TAG, "ZKP mismatch"); jClient.abort(Constants.JPAKE_ERROR_WRONGMESSAGE); return; } catch (NoSuchAlgorithmException e) { Logger.error(LOG_TAG, "NoSuchAlgorithmException", e); jClient.abort(Constants.JPAKE_ERROR_INTERNAL); return; } catch (UnsupportedEncodingException e) { Logger.error(LOG_TAG, "UnsupportedEncodingException", e); jClient.abort(Constants.JPAKE_ERROR_INTERNAL); return; } // Make outgoing payload. Zkp zkpA = jClient.jParty.thisZkpA; ExtendedJSONObject oPayload = new ExtendedJSONObject(); ExtendedJSONObject jZkpA = JPakeJson.makeJZkp(zkpA.gr, zkpA.b, zkpA.id); oPayload.put(Constants.ZKP_KEY_A, BigIntegerHelper.toEvenLengthHex(jClient.jParty.thisA)); oPayload.put(Constants.ZKP_KEY_ZKP_A, jZkpA); // Make outgoing message. jClient.jOutgoing = new ExtendedJSONObject(); jClient.jOutgoing.put(Constants.JSON_KEY_TYPE, jClient.mySignerId + "2"); jClient.jOutgoing.put(Constants.JSON_KEY_VERSION, JPakeClient.KEYEXCHANGE_VERSION); jClient.jOutgoing.put(Constants.JSON_KEY_PAYLOAD, oPayload); jClient.runNextStage(); } }