net.schmizz.sshj.transport.Encoder Maven / Gradle / Ivy
/*
* Copyright (C)2009 - SSHJ Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.schmizz.sshj.transport;
import net.schmizz.sshj.common.LoggerFactory;
import net.schmizz.sshj.common.SSHPacket;
import net.schmizz.sshj.transport.cipher.Cipher;
import net.schmizz.sshj.transport.compression.Compression;
import net.schmizz.sshj.transport.mac.MAC;
import net.schmizz.sshj.transport.random.Random;
import org.slf4j.Logger;
import java.util.concurrent.locks.Lock;
/** Encodes packets into the SSH binary protocol per the current algorithms. */
final class Encoder
extends Converter {
private final Logger log;
private final Random prng;
private final Lock encodeLock;
Encoder(Random prng, Lock encodeLock, LoggerFactory loggerFactory) {
this.prng = prng;
this.encodeLock = encodeLock;
log = loggerFactory.getLogger(getClass());
}
private void compress(SSHPacket buffer) {
compression.compress(buffer);
}
private void putMAC(SSHPacket buffer, int startOfPacket, int endOfPadding) {
buffer.wpos(endOfPadding + mac.getBlockSize());
mac.update(seq);
mac.update(buffer.array(), startOfPacket, endOfPadding);
mac.doFinal(buffer.array(), endOfPadding);
}
/**
* Encode a buffer into the SSH binary protocol per the current algorithms.
*
* @param buffer the buffer to encode
*
* @return the sequence no. of encoded packet
*
* @throws TransportException
*/
long encode(SSHPacket buffer) {
encodeLock.lock();
try {
if (log.isTraceEnabled())
log.trace("Encoding packet #{}: {}", seq, buffer.printHex());
if (usingCompression())
compress(buffer);
final int payloadSize = buffer.available();
// Compute padding length
int padLen = -(payloadSize + 5) & cipherSize - 1;
if (padLen < cipherSize)
padLen += cipherSize;
final int startOfPacket = buffer.rpos() - 5;
final int packetLen = payloadSize + 1 + padLen;
// Put packet header
buffer.wpos(startOfPacket);
buffer.putUInt32(packetLen);
buffer.putByte((byte) padLen);
// Now wpos will mark end of padding
buffer.wpos(startOfPacket + 5 + payloadSize + padLen);
// Fill padding
prng.fill(buffer.array(), buffer.wpos() - padLen, padLen);
seq = seq + 1 & 0xffffffffL;
if (mac != null)
putMAC(buffer, startOfPacket, buffer.wpos());
cipher.update(buffer.array(), startOfPacket, 4 + packetLen);
buffer.rpos(startOfPacket); // Make ready-to-read
return seq;
} finally {
encodeLock.unlock();
}
}
@Override
void setAlgorithms(Cipher cipher, MAC mac, Compression compression) {
encodeLock.lock();
try {
super.setAlgorithms(cipher, mac, compression);
} finally {
encodeLock.unlock();
}
}
@Override
void setAuthenticated() {
encodeLock.lock();
try {
super.setAuthenticated();
} finally {
encodeLock.unlock();
}
}
@Override
Compression.Mode getCompressionType() {
return Compression.Mode.DEFLATE;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy