📄 secure.java
字号:
/* Secure.java
* Component: ProperJavaRDP
*
* Revision: $Revision: 1.7 $
* Author: $Author: telliott $
* Date: $Date: 2005/09/27 14:15:39 $
*
* Copyright (c) 2005 Propero Limited
*
* Purpose: Secure layer of communication
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
* (See gpl.txt for details of the GNU General Public License.)
*
*/
package net.propero.rdp;
import java.io.*;
import java.util.*;
import java.net.*;
import java.math.*;
import org.apache.log4j.Logger;
import net.propero.rdp.crypto.*;
import net.propero.rdp.rdp5.VChannels;
public class Secure {
boolean readCert = false;
static Logger logger = Logger.getLogger(Secure.class);
private Licence licence = new Licence(this);
/* constants for the secure layer */
public static final int SEC_ENCRYPT = 0x0008;
public static final int SEC_LOGON_INFO = 0x0040;
static final int SEC_RANDOM_SIZE = 32;
static final int SEC_MODULUS_SIZE = 64;
static final int SEC_PADDING_SIZE = 8;
private static final int SEC_EXPONENT_SIZE = 4;
private static final int SEC_CLIENT_RANDOM = 0x0001;
static final int SEC_LICENCE_NEG = 0x0080;
private static final int SEC_TAG_SRV_INFO = 0x0c01;
private static final int SEC_TAG_SRV_CRYPT = 0x0c02;
private static final int SEC_TAG_SRV_3 = 0x0c03;
private static final int SEC_TAG_SRV_CHANNELS = 0x0c03;
private static final int SEC_TAG_CLI_INFO = 0xc001;
private static final int SEC_TAG_CLI_CRYPT = 0xc002;
private static final int SEC_TAG_CLI_CHANNELS = 0xc003;
private static final int SEC_TAG_CLI_4 = 0xc004;
private static final int SEC_TAG_PUBKEY = 0x0006;
private static final int SEC_TAG_KEYSIG = 0x0008;
private static final int SEC_RSA_MAGIC = 0x31415352; /* RSA1 */
private MCS McsLayer=null;
// private String hostname=null;
// private String username=null;
boolean licenceIssued = false;
private RC4 rc4_enc = null;
private RC4 rc4_dec = null;
private RC4 rc4_update = null;
private BlockMessageDigest sha1 = null;
private BlockMessageDigest md5 = null;
private int keylength = 0;
private int enc_count = 0;
private int dec_count = 0;
private byte[] sec_sign_key = null;
private byte[] sec_decrypt_key = null;
private byte[] sec_encrypt_key = null;
private byte[] sec_decrypt_update_key = null;
private byte[] sec_encrypt_update_key = null;
private byte[] sec_crypted_random=null;
private byte[] exponent = null;
private byte[] modulus = null;
private byte[] server_random = null;
private byte[] client_random = new byte[SEC_RANDOM_SIZE];
private static final byte[] pad_54 = {
54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
54, 54, 54,
54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
54, 54, 54
};
private static final byte[] pad_92 = {
92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92,
92, 92, 92, 92, 92, 92, 92,
92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92,
92, 92, 92, 92, 92, 92, 92
};
private VChannels channels;
/**
* Initialise Secure layer of communications
* @param channels Virtual channels for this connection
*/
public Secure(VChannels channels) {
this.channels = channels;
McsLayer = new MCS(channels);
Common.mcs = McsLayer;
rc4_dec = new RC4();
rc4_enc = new RC4();
rc4_update = new RC4();
sha1 = new SHA1();
md5 = new MD5();
sec_sign_key = new byte[16]; // changed from 8 - rdesktop 1.2.0
sec_decrypt_key = new byte[16];
sec_encrypt_key = new byte[16];
sec_decrypt_update_key = new byte[16]; // changed from 8 - rdesktop 1.2.0
sec_encrypt_update_key = new byte[16]; // changed from 8 - rdesktop 1.2.0
sec_crypted_random = new byte[64];
}
/**
* Connect to server
* @param host Address of server to connect to
* @param port Port to connect to
* @throws UnknownHostException
* @throws IOException
* @throws RdesktopException
* @throws SocketException
* @throws CryptoException
* @throws OrderException
*/
public void connect(InetAddress host, int port) throws UnknownHostException, IOException, RdesktopException, SocketException, CryptoException, OrderException {
if(Options.hostname==""){
InetAddress localhost = InetAddress.getLocalHost();
String name = localhost.getHostName();
StringTokenizer tok = new StringTokenizer(name, ".");
Options.hostname = tok.nextToken();
Options.hostname.trim();
}
RdpPacket_Localised mcs_data = this.sendMcsData();
McsLayer.connect(host, port, mcs_data);
this.processMcsData(mcs_data);
if (Constants.encryption) {
this.establishKey();
}
}
/**
* Connect to server on default port
* @param host Server to connect to
* @throws IOException
* @throws RdesktopException
* @throws OrderException
* @throws CryptoException
*/
public void connect(InetAddress host) throws IOException, RdesktopException, OrderException, CryptoException {
this.connect(host, Options.port);
}
/**
* Close connection
*/
public void disconnect() {
McsLayer.disconnect();
}
/**
* Construct MCS data, including channel, encryption and display options
* @return Packet populated with MCS data
*/
public RdpPacket_Localised sendMcsData() {
logger.debug("Secure.sendMcsData");
RdpPacket_Localised buffer= new RdpPacket_Localised(512);
int hostlen = 2 * (Options.hostname==null ? 0 : Options.hostname.length());
if (hostlen > 30) { hostlen=30;}
int length = 158;
if(Options.use_rdp5) length += 76 + 12 + 4;
if (Options.use_rdp5 && (channels.num_channels() > 0))
length += channels.num_channels() * 12 + 8;
buffer.setBigEndian16(5); /* unknown */
buffer.setBigEndian16(0x14);
buffer.set8(0x7c);
buffer.setBigEndian16(1);
buffer.setBigEndian16(length | 0x8000); // remaining length
buffer.setBigEndian16(8); // length?
buffer.setBigEndian16(16);
buffer.set8(0);
buffer.setLittleEndian16(0xc001);
buffer.set8(0);
buffer.setLittleEndian32(0x61637544); // "Duca" ?!
buffer.setBigEndian16(length-14 | 0x8000); // remaining length
// Client information
buffer.setLittleEndian16(SEC_TAG_CLI_INFO);
buffer.setLittleEndian16(Options.use_rdp5 ? 212 : 136); // length
buffer.setLittleEndian16(Options.use_rdp5 ? 4 : 1);
buffer.setLittleEndian16(8);
buffer.setLittleEndian16(Options.width);
buffer.setLittleEndian16(Options.height);
buffer.setLittleEndian16(0xca01);
buffer.setLittleEndian16(0xaa03);
buffer.setLittleEndian32(Options.keylayout);
buffer.setLittleEndian32(Options.use_rdp5 ? 2600 : 419); // or 0ece // client build? we are 2600 compatible :-)
/* Unicode name of client, padded to 32 bytes */
buffer.outUnicodeString(Options.hostname.toUpperCase(), hostlen);
buffer.incrementPosition(30 - hostlen);
buffer.setLittleEndian32(4);
buffer.setLittleEndian32(0);
buffer.setLittleEndian32(12);
buffer.incrementPosition(64); /* reserved? 4 + 12 doublewords */
buffer.setLittleEndian16(0xca01); // out_uint16_le(s, 0xca01);
buffer.setLittleEndian16(Options.use_rdp5 ? 1 : 0);
if(Options.use_rdp5){
buffer.setLittleEndian32(0); // out_uint32(s, 0);
buffer.set8(Options.server_bpp); // out_uint8(s, g_server_bpp);
buffer.setLittleEndian16(0x0700); // out_uint16_le(s, 0x0700);
buffer.set8(0); // out_uint8(s, 0);
buffer.setLittleEndian32(1); // out_uint32_le(s, 1);
buffer.incrementPosition(64);
buffer.setLittleEndian16(SEC_TAG_CLI_4); // out_uint16_le(s, SEC_TAG_CLI_4);
buffer.setLittleEndian16(12); // out_uint16_le(s, 12);
buffer.setLittleEndian32(Options.console_session ? 0xb : 0xd); // out_uint32_le(s, g_console_session ? 0xb : 9);
buffer.setLittleEndian32(0); // out_uint32(s, 0);
}
// Client encryption settings //
buffer.setLittleEndian16(SEC_TAG_CLI_CRYPT);
buffer.setLittleEndian16(Options.use_rdp5 ? 12 : 8); // length
//if(Options.use_rdp5) buffer.setLittleEndian32(Options.encryption ? 0x1b : 0); // 128-bit encryption supported
//else
buffer.setLittleEndian32(Options.encryption ? (Options.console_session ? 0xb : 0x3) : 0);
if(Options.use_rdp5) buffer.setLittleEndian32(0); // unknown
if (Options.use_rdp5 && (channels.num_channels() > 0))
{
logger.debug(("num_channels is " + channels.num_channels()));
buffer.setLittleEndian16(SEC_TAG_CLI_CHANNELS); // out_uint16_le(s, SEC_TAG_CLI_CHANNELS);
buffer.setLittleEndian16(channels.num_channels() * 12 + 8); // out_uint16_le(s, g_num_channels * 12 + 8); // length
buffer.setLittleEndian32(channels.num_channels()); // out_uint32_le(s, g_num_channels); // number of virtual channels
for (int i = 0; i < channels.num_channels(); i++)
{
logger.debug(("Requesting channel " + channels.channel(i).name()));
buffer.out_uint8p(channels.channel(i).name(), 8); // out_uint8a(s, g_channels[i].name, 8);
buffer.setBigEndian32(channels.channel(i).flags()); // out_uint32_be(s, g_channels[i].flags);
}
}
buffer.markEnd();
return buffer;
}
/**
* Handle MCS info from server (server info, encryption info and channel information)
* @param mcs_data Data received from server
*/
public void processMcsData(RdpPacket_Localised mcs_data) throws RdesktopException, CryptoException {
logger.debug("Secure.processMcsData");
int tag=0, len=0, length=0, nexttag=0;
mcs_data.incrementPosition(21); // header (T.124 stuff, probably)
len=mcs_data.get8();
if ((len&0x00000080)!=0) {
len=mcs_data.get8();
}
while (mcs_data.getPosition() < mcs_data.getEnd()) {
tag=mcs_data.getLittleEndian16();
length=mcs_data.getLittleEndian16();
if (length <=4) return;
nexttag=mcs_data.getPosition() + length -4;
switch(tag) {
case (Secure.SEC_TAG_SRV_INFO):
processSrvInfo(mcs_data);
break;
case (Secure.SEC_TAG_SRV_CRYPT):
this.processCryptInfo(mcs_data);
break;
case (Secure.SEC_TAG_SRV_CHANNELS):
/* FIXME: We should parse this information and
use it to map RDP5 channels to MCS
channels */
break;
default: throw new RdesktopException("Not implemented! Tag:"+tag+"not recognized!");
}
mcs_data.setPosition(nexttag);
}
}
/**
* Read server info from packet, specifically the RDP version of the server
* @param mcs_data Packet to read
*/
private void processSrvInfo(RdpPacket_Localised mcs_data) {
Options.server_rdp_version = mcs_data.getLittleEndian16(); // in_uint16_le(s, g_server_rdp_version);
logger.debug(("Server RDP version is " + Options.server_rdp_version));
if (1 == Options.server_rdp_version)
Options.use_rdp5 = false;
}
public void establishKey()throws RdesktopException, IOException, CryptoException {
int length = SEC_MODULUS_SIZE + SEC_PADDING_SIZE;
int flags = SEC_CLIENT_RANDOM;
RdpPacket_Localised buffer = this.init(flags, 76);
buffer.setLittleEndian32(length);
buffer.copyFromByteArray(this.sec_crypted_random, 0, buffer.getPosition(), SEC_MODULUS_SIZE);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -