/** * Takes a byte array containing serialized and concatenated MPIs and converts it to an array of * MPIs. The buffer is assumed to consist of a 4-byte int containing the number of MPIs in the * array, followed by {size, data} pairs for each MPI. * * @throws OTRException */ public static MPI[] unserializeMPIArray(byte[] buffer) throws OTRException { InBuf ibuf = new InBuf(buffer); int count = (int) ibuf.readUInt(); if (count <= 0) throw new OTRException("Invalid count"); MPI[] mpis = new MPI[count]; for (int i = 0; i < count; i++) { mpis[i] = MPI.readMPI(ibuf); } return mpis; }
/** Hash one or two MPIs. To hash only one MPI, b may be set to NULL. */ public static MPI hash(int version, MPI a, MPI b, Provider prov) throws OTRException { int totalsize = 1 + 4 + a.getLength(); if (b != null) { totalsize += 4 + b.getLength(); } byte[] buf = new byte[totalsize]; OutBuf obuf = new OutBuf(buf); obuf.writeByte((byte) version); obuf.writeUInt(a.getLength()); a.writeRaw(obuf); if (b != null) { obuf.writeUInt(b.getLength()); b.writeRaw(obuf); } byte[] out = obuf.getBytes(); SHA256 sha = prov.getSHA256(); byte[] digest = sha.hash(out); return new MPI(digest); }
void goEncrypted(OTRCallbacks callback) throws OTRException { // See if we're talking to ourselves byte[] theiry = auth.their_pub.serialize(); byte[] their_trim = new byte[theiry.length - 4]; System.arraycopy(theiry, 4, their_trim, 0, their_trim.length); byte[] oury = auth.our_dh.getPublicKey().serialize(); byte[] our_trim = new byte[oury.length - 4]; System.arraycopy(oury, 4, our_trim, 0, our_trim.length); if (prov.compareMPI(new MPI(their_trim), new MPI(our_trim)) == 0) { // Yes, we are. callback.handleMsgEvent(OTRCallbacks.OTRL_MSGEVENT_MSG_REFLECTED, this, null); throw new OTRException("Message reflected"); } // Find the fingerprint FingerPrint found_print = this.findFingerPrint(auth.their_fingerprint, true, callback); /* Is this a new session or just a refresh of an existing one? */ if (this.msgState.getCurState() == MsgState.ST_ENCRYPTED && Util.arrayEquals(this.activeFingerprint.fingerPrint, found_print.fingerPrint) && this.our_keyid - 1 == this.auth.our_keyid && prov.compareMPI( MPI.readMPI(new InBuf(this.our_old_dh_key.getPublicKey().serialize())), MPI.readMPI(new InBuf(this.auth.our_dh.getPublicKey().serialize()))) == 0 && ((this.their_keyid > 0 && this.their_keyid == auth.their_keyid && prov.compareMPI( MPI.readMPI(new InBuf(this.their_y.serialize())), MPI.readMPI(new InBuf(this.auth.their_pub.serialize()))) == 0) || (this.their_keyid > 1 && this.their_keyid - 1 == this.auth.their_keyid && this.their_old_y != null && prov.compareMPI( MPI.readMPI(new InBuf(this.their_y.serialize())), MPI.readMPI(new InBuf(this.auth.their_pub.serialize()))) == 0))) { /* This is just a refresh of the existing session. */ callback.stillSecure(this, auth.initiated); ignore_message = 1; return; } // Copy the information from the auth into the context System.arraycopy(auth.secure_session_id, 0, this.sessionId, 0, 20); this.sessionid_len = auth.sessionid_len; // Copy the keys this.their_keyid = auth.their_keyid; this.their_y = auth.their_pub; this.their_old_y = null; if (our_keyid - 1 != auth.our_keyid) { this.our_old_dh_key = auth.our_dh; this.our_dh_key = prov.getDHKeyPairGenerator().generateKeyPair(); this.our_keyid = auth.our_keyid + 1; } // Create the session keys from the DH keys this.sesskeys[0][0] = new DHSesskeys(prov); this.sesskeys[1][0] = new DHSesskeys(prov); this.sesskeys[0][0].computeSession(this.our_dh_key, this.their_y); this.sesskeys[1][0].computeSession(this.our_old_dh_key, this.their_y); this.generation++; this.activeFingerprint = found_print; int oldstate = msgState.getCurState(); msgState.processEvent(MsgState.EVT_AUTHENTICATED); callback.updateContextList(); if (oldstate == MsgState.ST_ENCRYPTED && Util.arrayEquals(this.activeFingerprint.fingerPrint, found_print.fingerPrint)) { callback.stillSecure(this, this.auth.initiated); } else { callback.goneSecure(this); } this.gone_encrypted = 1; }