@Override public void initialize(Direction direction, SymmetricKey key) { this.key = key.getKey(); if (initialized()) { CipherParameters params = new KeyParameter(this.key); aesEngine.init(direction == Direction.ENCRYPT, params); } }
/** * We have received {@link PacketTypes#ACK} packet. Need to stop retransmitting of ack-ed packet. * @param packet received {@link Packet} */ private void onReceiveAck(Packet packet) throws EncryptionError, SymmetricKey.AuthenticationFailed { report(logLabel, ()->"received ack from " + packet.senderNodeId, VerboseLevel.DETAILED); Session session = getOrCreateSession(packet.senderNodeId); if (session != null) { if (session.state.get() == Session.STATE_EXCHANGING) { Integer ackPacketId = Boss.load(new SymmetricKey(session.sessionKey.getKey()).etaDecrypt(packet.payload)); session.removePacketFromRetransmitMap(ackPacketId); } } }
if (sessionReader.sessionKey != null) { try { byte[] decrypted = new SymmetricKey(sessionReader.sessionKey.getKey()).etaDecrypt(encryptedPayload); if (decrypted.length > 2) { byte[] payload = new byte[decrypted.length - 2];
/** * All packets data ({@link Packet#payload}) of type {@link PacketTypes#DATA} * must be encrypted with sessionKey ({@link SymmetricKey}). * This method implements encryption procedure for it. * @param sessionKey key for encryption * @param payload data to encrypt * @return encrypted data, ready for sending to network */ private byte[] preparePayloadForSession(SymmetricKey sessionKey, byte[] payload) { try { byte[] payloadWithRandomChunk = new byte[payload.length + 2]; System.arraycopy(payload, 0, payloadWithRandomChunk, 0, payload.length); System.arraycopy(Bytes.random(2).toArray(), 0, payloadWithRandomChunk, payload.length, 2); byte[] encryptedPayload = new SymmetricKey(sessionKey.getKey()).etaEncrypt(payloadWithRandomChunk); byte[] crc32 = new Crc32().digest(encryptedPayload); byte[] dataToSend = new byte[encryptedPayload.length + crc32.length]; System.arraycopy(encryptedPayload, 0, dataToSend, 0, encryptedPayload.length); System.arraycopy(crc32, 0, dataToSend, encryptedPayload.length, crc32.length); return dataToSend; } catch (EncryptionError e) { callErrorCallbacks("(preparePayloadForSession) EncryptionError: " + e); return payload; } }
/** * Each adapter will try to send blocks until have got special {@link Packet} with type {@link PacketTypes#ACK}, * that means receiver have got block. So when we got packet and all is ok - call this method. * @param sessionReader is {@link SessionReader} in which sending is. * @param packetId is id of packet we have got. */ private void sendAck(SessionReader sessionReader, Integer packetId) throws EncryptionError { report(logLabel, ()->"send ack to "+sessionReader.remoteNodeInfo.getNumber(), VerboseLevel.DETAILED); Packet packet = new Packet(0, myNodeInfo.getNumber(), sessionReader.remoteNodeInfo.getNumber(), PacketTypes.ACK, new SymmetricKey(sessionReader.sessionKey.getKey()).etaEncrypt(Boss.pack(packetId))); sendPacket(sessionReader.remoteNodeInfo, packet); }
/** * ACK packets are used only for respond to DATA packets. Retransmission of handshake's packet types stops on each * next handshake step. But last step need to be ACK-ed. For this used {@link PacketTypes#SESSION_ACK} packet. * @param session is {@link Session} in which sending is. * @throws EncryptionError */ private void sendSessionAck(Session session) throws EncryptionError { report(logLabel, ()->"send session_ack to "+session.remoteNodeInfo.getNumber(), VerboseLevel.BASE); Packet packet = new Packet(0, myNodeInfo.getNumber(), session.remoteNodeInfo.getNumber(), PacketTypes.SESSION_ACK, new SymmetricKey(session.sessionKey.getKey()).etaEncrypt(Do.randomBytes(32))); sendPacket(session.remoteNodeInfo, packet); }
@Test public void deriveKey() throws Exception { KeyInfo h1 = new KeyInfo(KeyInfo.PRF.HMAC_SHA256, 4096, null, null); KeyInfo h2 = new KeyInfo(h1.pack()); assertArrayEquals(h1.getSalt(), h2.getSalt()); assertArrayEquals("attesta".getBytes(), h2.getSalt()); SymmetricKey k = h1.derivePassword("elegance"); byte[] k1 = PBKDF2.derive(Sha256.class, "elegance", "attesta".getBytes(), 4096, 32); assertArrayEquals(k1, k.getKey()); assertEquals(h1, k.info()); }
/** * Someone who sent {@link PacketTypes#HELLO} typed {@link Packet}, * send us new KEY_REQ typed {@link Packet} - if all is ok we send session keys to. * SESSION's payload is more than 512 bytes, so used two parts here. * From now we ready to data exchange. * @param sessionReader is {@link SessionReader} in which sending is. */ private void sendSessionKey(SessionReader sessionReader) throws EncryptionError { report(logLabel, ()->"send session_key to "+sessionReader.remoteNodeInfo.getNumber(), VerboseLevel.BASE); List data = Arrays.asList(sessionReader.sessionKey.getKey(), sessionReader.remoteNonce); byte[] packed = Boss.pack(data); byte[] encrypted = new PublicKey(sessionReader.remoteNodeInfo.getPublicKey().pack()).encrypt(packed); byte[] sign = new PrivateKey(ownPrivateKey.pack()).sign(encrypted, HashType.SHA512); Packet packet1 = new Packet(getNextPacketId(), myNodeInfo.getNumber(), sessionReader.remoteNodeInfo.getNumber(), PacketTypes.SESSION_PART1, encrypted); Packet packet2 = new Packet(getNextPacketId(), myNodeInfo.getNumber(), sessionReader.remoteNodeInfo.getNumber(), PacketTypes.SESSION_PART2, sign); sendPacket(sessionReader.remoteNodeInfo, packet1); sendPacket(sessionReader.remoteNodeInfo, packet2); sessionReader.addPacketToRetransmitMap(packet1.packetId, packet1, encrypted); sessionReader.addPacketToRetransmitMap(packet2.packetId, packet2, sign); }