public Message getNextMessage () throws IOException {
		
		// check for pending message from peek.
		if (pending != null) {
			Message msg = pending;
			pending = null;
			return msg;
		}
		
		// read incoming message from wrapped channel
		Message msg = next.getNextMessage();
		if (msg == null)
			return null;

		// get length of message
		int size = (msg.getByte() << 8) | msg.getByte();
		// check for padding (block ciphers)
		int padding = 0;
		if ((size & 0x8000) == 0)
			padding = msg.getByte();
		else
			size &= 0x7FFF;

		// extract message data.
		byte[] data = msg.getArray (size);
		
		//-------------------------------------------------------------
		// check for decryption
		//-------------------------------------------------------------
		if (decrypter != null) {
			// decrypt message
			data = decrypter.process (data);
			if (data == null)
				throw new IOException ("Decryption failed!");
			// remove padding.
			if (padding > 0)
				size -= padding;
		}
		
		//-------------------------------------------------------------
		// check for message digest
		//-------------------------------------------------------------
		if (hasher != null) {
			// check digest
			int pos = hasher.checkMessage (data, size, countIn);
			if (pos < 0)
				throw new IOException ("Hash mismatch");
			// move message to begin of buffer
			size -= pos;
			System.arraycopy (data, pos, data, 0, size);
		}

		// construct Styx message from data
		countIn++;
		Message msgIn = new Message (data, size);
		return msgIn;
	}