public void testIORevealSignature() throws Exception { int protocolVersion = 1; byte[] xEncrypted = new byte[] {1, 2, 3, 4}; byte[] xEncryptedMAC = new byte[SerializationConstants.TYPE_LEN_MAC]; for (int i = 0; i < xEncryptedMAC.length; i++) xEncryptedMAC[i] = (byte) i; byte[] revealedKey = new byte[] {1, 2, 3, 4}; RevealSignatureMessage source = new RevealSignatureMessage(protocolVersion, xEncrypted, xEncryptedMAC, revealedKey); String base64 = SerializationUtils.toString(source); RevealSignatureMessage result = (RevealSignatureMessage) SerializationUtils.toMessage(base64); assertTrue(source.equals(result)); }
private void handleRevealSignatureMessage(RevealSignatureMessage m) throws OtrException { Session session = getSession(); SessionID sessionID = session.getSessionID(); logger.finest( sessionID.getLocalUserId() + " received a reveal signature message from " + sessionID.getRemoteUserId() + " throught " + sessionID.getProtocolName() + "."); if (!session.getSessionPolicy().getAllowV2()) { logger.finest("Policy does not allow OTRv2, ignoring message."); return; } switch (this.getAuthenticationState()) { case AWAITING_REVEALSIG: // Use the received value of r to decrypt the value of gx // received // in the D-H Commit Message, and verify the hash therein. // Decrypt // the encrypted signature, and verify the signature and the // MACs. // If everything checks out: // * Reply with a Signature Message. // * Transition authstate to AUTHSTATE_NONE. // * Transition msgstate to MSGSTATE_ENCRYPTED. // * TODO If there is a recent stored message, encrypt it and // send // it as a Data Message. OtrCryptoEngine otrCryptoEngine = new OtrCryptoEngineImpl(); // Uses r to decrypt the value of gx sent earlier byte[] remoteDHPublicKeyDecrypted = otrCryptoEngine.aesDecrypt(m.revealedKey, null, this.getRemoteDHPublicKeyEncrypted()); // Verifies that HASH(gx) matches the value sent earlier byte[] remoteDHPublicKeyHash = otrCryptoEngine.sha256Hash(remoteDHPublicKeyDecrypted); if (!Arrays.equals(remoteDHPublicKeyHash, this.getRemoteDHPublicKeyHash())) { logger.finest("Hashes don't match, ignoring message."); return; } // Verifies that Bob's gx is a legal value (2 <= gx <= // modulus-2) BigInteger remoteDHPublicKeyMpi; try { remoteDHPublicKeyMpi = SerializationUtils.readMpi(remoteDHPublicKeyDecrypted); } catch (IOException e) { throw new OtrException(e); } this.setRemoteDHPublicKey(otrCryptoEngine.getDHPublicKey(remoteDHPublicKeyMpi)); // Verify received Data. if (!m.verify(this.getM2())) { logger.finest("Signature MACs are not equal, ignoring message."); return; } // Decrypt X. byte[] remoteXDecrypted = m.decrypt(this.getC()); SignatureX remoteX; try { remoteX = SerializationUtils.toMysteriousX(remoteXDecrypted); } catch (IOException e) { throw new OtrException(e); } // Compute signature. PublicKey remoteLongTermPublicKey = remoteX.longTermPublicKey; SignatureM remoteM = new SignatureM( this.getRemoteDHPublicKey(), (DHPublicKey) this.getLocalDHKeyPair().getPublic(), remoteLongTermPublicKey, remoteX.dhKeyID); // Verify signature. byte[] signature; try { signature = otrCryptoEngine.sha256Hmac(SerializationUtils.toByteArray(remoteM), this.getM1()); } catch (IOException e) { throw new OtrException(e); } if (!otrCryptoEngine.verify(signature, remoteLongTermPublicKey, remoteX.signature)) { session.showWarning("Bad revealed signature"); logger.finest("Signature verification failed."); return; } logger.finest("Signature verification succeeded."); this.setAuthenticationState(AuthContext.NONE); this.setIsSecure(true); this.setRemoteLongTermPublicKey(remoteLongTermPublicKey); getSession().injectMessage(messageFactory.getSignatureMessage()); break; default: logger.finest("Ignoring message."); break; } }