/*
* This file is part of "The Java Telnet Application".
*
* (c) Matthias L. Jugel, Marcus Mei�ner 1996-2002. All Rights Reserved. The
* file was changed by Radek Polak to work as midlet in MIDP 1.0
*
* This file has been modified by Karl von Randow for MidpSSH.
*
* Please visit http://javatelnet.org/ for updates and contact.
*
* --LICENSE NOTICE-- This program is free software; you can redistribute it
* and/or modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the License,
* or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 675 Mass
* Ave, Cambridge, MA 02139, USA. --LICENSE NOTICE--
*/
package ssh.v2;
import java.io.IOException;
import ssh.SshIO;
import ssh.SshPacket;
public class SshPacket2 extends SshPacket {
private static final int PHASE_packet_length = 0;
private static final int PHASE_block = 1;
//SSH_RECEIVE_PACKET
private byte[] packet_length_array = new byte[8]; // 8 bytes
private int packet_length; // 32-bit sign int
private int padlen; // packet length 1 byte unsigned
private int position;
private int phase_packet = PHASE_packet_length;
private SshCrypto2 crypto;
public SshPacket2() {
}
public SshPacket2(SshCrypto2 _crypto) {
/* receiving packet */
crypto = _crypto;
}
public SshPacket2(byte newType) {
packet_type = newType;
}
/**
* Return the mp-int at the position offset in the data First 4 bytes are
* the number of bytes in the integer, msb first (for example, the value
* 0x00012345 would have 17 bits). The value zero has zero bits. It is
* permissible that the number of bits be larger than the real number of
* bits. The number of bits is followed by (bits + 7) / 8 bytes of binary
* data, msb first, giving the value of the integer.
*/
public byte[] getMpInt() {
return getBytes(getInt32());
}
public void putMpInt(byte[] foo) {
int i = foo.length;
if ((foo[0] & 0x80) != 0) {
i++;
putInt32(i);
putByte((byte) 0);
} else {
putInt32(i);
}
putBytes(foo);
}
public byte[] getPayLoad(SshCrypto2 xcrypt, long seqnr) throws IOException {
byte[] data = getData();
int blocksize = 8;
// crypted data is:
// packet length [ payloadlen + padlen + type + data ]
packet_length = 4 + 1 + 1;
if (data != null)
packet_length += data.length;
// pad it up to full blocksize.
// If not crypto, zeroes, otherwise random.
// (zeros because we do not want to tell the attacker the state of our
// random generator)
int padlen = blocksize - (packet_length % blocksize);
if (padlen < 4)
padlen += blocksize;
byte[] padding = new byte[padlen];
//System.out.println( "packet length is " + packet_length + ", padlen
// is " + padlen );
if (xcrypt == null)
for (int i = 0; i < padlen; i++)
padding[i] = 0;
else
for (int i = 0; i < padlen; i++)
padding[i] = SshIO.getNotZeroRandomByte();
// [ packetlength, padlength, padding, packet type, data ]
byte[] block = new byte[packet_length + padlen];
int xlen = padlen + packet_length - 4;
block[3] = (byte) (xlen & 0xff);
block[2] = (byte) ((xlen >> 8) & 0xff);
block[1] = (byte) ((xlen >> 16) & 0xff);
block[0] = (byte) ((xlen >> 24) & 0xff);
block[4] = (byte) padlen;
block[5] = getType();
System.arraycopy(data, 0, block, 6, data.length);
System.arraycopy(padding, 0, block, 6 + data.length, padlen);
/*
* byte[] md5sum; if ( xcrypt != null ) { MD5 md5 = new MD5(); byte[]
* seqint = new byte[4];
*
* seqint[0] = (byte) ( ( seqnr >> 24 ) & 0xff ); seqint[1] = (byte) ( (
* seqnr >> 16 ) & 0xff ); seqint[2] = (byte) ( ( seqnr >> 8 ) & 0xff );
* seqint[3] = (byte) ( ( seqnr ) & 0xff ); md5.update( seqint, 0, 4 );
* md5.update( block, 0, block.length ); md5sum = md5.digest(); } else {
* md5sum = new byte[0]; }
*/
byte[] mac = null;
if (xcrypt != null) {
HMACSHA1 c2smac = xcrypt.getSndHmac();
if (c2smac != null) {
c2smac.update((int) seqnr);
c2smac.update(block, 0, block.length);
mac = c2smac.doFinal();
}
}
if (xcrypt != null)
block = xcrypt.encrypt(block);
byte[] sendblock = new byte[block.length
+ (mac != null ? mac.length : 0)];
System.arraycopy(block, 0, sendblock, 0, block.length);
if (mac != null) {
System.arraycopy(mac, 0, sendblock, block.length, mac.length);
}
return sendblock;
};
private byte block[];
public int addPayload(byte buff[], int boffset, int length) {
int hmaclen = 0;
int boffsetend = boffset + length;
if (crypto != null)
hmaclen = crypto.getRcvHmac().getBlockSize();
//System.out.println( "addPayload2 " + length + " mac length " +
// hmaclen );
/*
* Note: The whole packet is encrypted, except for the MAC.
*
* (So I have to rewrite it again).
*/
while (boffset < boffsetend) {
switch (phase_packet) {
// 4 bytes
// Packet length: 32 bit unsigned integer
// gives the length of the packet, not including the length
// field
// and padding. maximum is 262144 bytes.
case PHASE_packet_length:
packet_length_array[position++] = buff[boffset++];
if (position == 8) {
/*
* HERE I AM Well, the crypto doesn't appear to be working.
* We've tested the crypto algs in Jsch so maybe we're not
* getting the right keys? or setting up the ciphers
* incorrectly?
*
*/
packet_length = (packet_length_array[3] & 0xff)
+ ((packet_length_array[2] & 0xff) << 8)
+ ((packet_length_array[1] & 0xff) << 16)
+ ((packet_length_array[0] & 0xff) << 24);
// NOW HAVE READ FIRST 8 BYTES OF PACKET, CAN DECRYPT
byte[] packet_length_array;
if (crypto != null) {
packet_length_array = crypto
.decrypt(this.packet_length_array);
} else {
packet_length_array = this.packet_length_array;
}
packet_length = (packet_length_array[3] & 0xff)
+ ((packet_length_array[2] & 0xff) << 8)
+ ((packet_length_array[1] & 0xff) << 16)
+ ((packet_length_array[0] & 0xff) << 24);
padlen = packet_length_array[4];
position = 3;
//System.out.println( "SSH2: packet length " +
// packet_length );
//System.out.println( "SSH2: padlen " + padlen );
packet_length += hmaclen; /* len(md5) */
block = new byte[packet_length - 1]; /*
* padlen already done
*/
// copy in already decrypted first 3 bytes of payload
System.arraycopy(packet_length_array, 5, block, 0, 3);
phase_packet++;
}
break; //switch (phase_packet)
//8*(packet_length/8 +1) bytes
case PHASE_block:
if (block.length > position) {
if (boffset < boffsetend) {
int amount = boffsetend - boffset;
if (amount > block.length - position)
amount = block.length - position;
System
.arraycopy(buff, boffset, block, position,
amount);
boffset += amount;
position += amount;
}
}
if (position == block.length) { //the block is complete
packet_length -= hmaclen; // packet_length is now payload
// (incl type) + padding
byte[] decryptedBlock = new byte[block.length - hmaclen - 3]; // 3
// bytes
// already
// decrypted
byte[] data;
// first 3 bytes already decrypted
System.arraycopy(block, 3, decryptedBlock, 0,
decryptedBlock.length);
if (crypto != null)
decryptedBlock = crypto.decrypt(decryptedBlock);
// Add back in first 3 bytes
byte[] dd = new byte[decryptedBlock.length + 3];
System.arraycopy(block, 0, dd, 0, 3);
System.arraycopy(decryptedBlock, 0, dd, 3,
decryptedBlock.length);
decryptedBlock = dd;
packet_type = decryptedBlock[0];
//System.err.println( "IN Packet type: " + getType() );
//System.err.println( "Packet len: " + packet_length );
//data
if (packet_length > padlen + 1 + 1) { // 1 for padding
// length, 1 for type
data = new byte[packet_length - 2 - padlen];
System.arraycopy(decryptedBlock, 1, data, 0,
data.length);
putData(data);
} else {
putData(null);
}
/* MAC! */
return boffset;
}
break;
}
}
return boffset;
}
/*
*
* private boolean checkCrc(){ byte[] crc_arrayCheck = new byte[4]; long
* crcCheck;
*
* crcCheck = SshMisc.crc32(decryptedBlock, decryptedBlock.length-4);
* crc_arrayCheck[3] = (byte) (crcCheck & 0xff); crc_arrayCheck[2] = (byte)
* ((crcCheck>>8) & 0xff); crc_arrayCheck[1] = (byte) ((crcCheck>>16) &
* 0xff); crc_arrayCheck[0] = (byte) ((crcCheck>>24) & 0xff);
*
* if(debug) { System.err.println(crc_arrayCheck[3]+" == "+crc_array[3]);
* System.err.println(crc_arrayCheck[2]+" == "+crc_array[2]);
* System.err.println(crc_arrayCheck[1]+" == "+crc_array[1]);
* System.err.println(crc_arrayCheck[0]+" == "+crc_array[0]); } if
* (crc_arrayCheck[3] != crc_array[3]) return false; if (crc_arrayCheck[2] !=
* crc_array[2]) return false; if (crc_arrayCheck[1] != crc_array[1]) return
* false; if (crc_arrayCheck[0] != crc_array[0]) return false; return true; }
*/
}