in sshd-core/src/main/java/org/apache/sshd/common/session/helpers/AbstractSession.java [1440:1540]
protected Buffer encode(Buffer buffer) throws IOException {
try {
// Check that the packet has some free space for the header
int curPos = buffer.rpos();
int cmd = buffer.rawByte(curPos) & 0xFF; // usually the 1st byte is an SSH opcode
Buffer nb = preProcessEncodeBuffer(cmd, buffer);
if (nb != buffer) {
buffer = nb;
curPos = buffer.rpos();
int newCmd = buffer.rawByte(curPos) & 0xFF;
if (cmd != newCmd) {
log.warn("encode({}) - command changed from {}[{}] to {}[{}] by pre-processor",
this, cmd, SshConstants.getCommandMessageName(cmd),
newCmd, SshConstants.getCommandMessageName(newCmd));
cmd = newCmd;
}
}
// Grab the length of the packet (excluding the 5 header bytes)
int len = buffer.available();
if (log.isDebugEnabled()) {
log.debug("encode({}) packet #{} sending command={}[{}] len={}",
this, seqo, cmd, SshConstants.getCommandMessageName(cmd), len);
}
int off = curPos - SshConstants.SSH_PACKET_HEADER_LEN;
// Debug log the packet
boolean traceEnabled = log.isTraceEnabled();
if (traceEnabled) {
buffer.dumpHex(getSimplifiedLogger(), Level.FINEST,
"encode(" + this + ") packet #" + seqo, this);
}
// Compress the packet if needed
if ((outCompression != null)
&& outCompression.isCompressionExecuted()
&& (isAuthenticated() || (!outCompression.isDelayed()))) {
int oldLen = len;
outCompression.compress(buffer);
len = buffer.available();
if (traceEnabled) {
log.trace("encode({}) packet #{} command={}[{}] compressed {} -> {}",
this, seqo, cmd, SshConstants.getCommandMessageName(cmd), oldLen, len);
}
}
// Compute padding length
boolean etmMode = outMac != null && outMac.isEncryptThenMac();
int authSize = outCipher != null ? outCipher.getAuthenticationTagSize() : 0;
boolean authMode = authSize > 0;
int oldLen = len;
int pad = calculatePadLength(len, outCipherSize, etmMode || authMode);
len += Byte.BYTES + pad;
if (traceEnabled) {
log.trace("encode({}) packet #{} command={}[{}] len={}, pad={}, mac={}",
this, seqo, cmd, SshConstants.getCommandMessageName(cmd), len, pad, outMac);
}
// Write 5 header bytes
buffer.wpos(off);
buffer.putUInt(len);
buffer.putByte((byte) pad);
// Make sure enough room for padding and then fill it
buffer.wpos(off + oldLen + SshConstants.SSH_PACKET_HEADER_LEN + pad);
synchronized (random) {
random.fill(buffer.array(), buffer.wpos() - pad, pad);
}
if (authMode) {
int wpos = buffer.wpos();
buffer.wpos(wpos + authSize);
aeadOutgoingBuffer(buffer, off, len);
} else if (etmMode) {
// Do not encrypt the length field
encryptOutgoingBuffer(buffer, off + Integer.BYTES, len);
appendOutgoingMac(buffer, off, len);
} else {
appendOutgoingMac(buffer, off, len);
encryptOutgoingBuffer(buffer, off, len + Integer.BYTES);
}
// Increment packet id
seqo = (seqo + 1L) & 0x0ffffffffL;
// Update counters used to track re-keying
outPacketsCount.incrementAndGet();
outBytesCount.addAndGet(len);
// Make buffer ready to be read
buffer.rpos(off);
return buffer;
} catch (IOException e) {
throw e;
} catch (Exception e) {
throw new SshException(e);
}
}