/** * Read in a public key from a provided Secure layer PDU, and store in this.exponent and * this.modulus * * @param data Secure layer PDU containing key data * @return True if key successfully read * @throws RdesktopException */ public boolean parsePublicKey(RdpPacket_Localised data) throws RdesktopException { int magic = 0, modulus_length = 0; magic = data.getLittleEndian32(); if (magic != SEC_RSA_MAGIC) { throw new RdesktopException("Wrong magic! Expected" + SEC_RSA_MAGIC + "got:" + magic); } modulus_length = data.getLittleEndian32() - SEC_PADDING_SIZE; if (modulus_length < 64 || modulus_length > SEC_MAX_MODULUS_SIZE) { throw new RdesktopException( "Bad server public key size (" + (modulus_length * 8) + " bites)"); } data.incrementPosition(8); // unknown modulus bits this.exponent = new byte[SEC_EXPONENT_SIZE]; data.copyToByteArray(this.exponent, 0, data.getPosition(), SEC_EXPONENT_SIZE); data.incrementPosition(SEC_EXPONENT_SIZE); this.modulus = new byte[modulus_length]; data.copyToByteArray(this.modulus, 0, data.getPosition(), modulus_length); data.incrementPosition(modulus_length); data.incrementPosition(SEC_PADDING_SIZE); this.server_public_key_len = modulus_length; if (data.getPosition() <= data.getEnd()) { return true; } else { return false; } }
/** * Prepare data as a Secure PDU and pass down to the MCS layer * * @param sec_data Data to send * @param flags Encryption flags * @param channel Channel over which to send data * @throws RdesktopException * @throws IOException * @throws CryptoException */ public void send_to_channel(RdpPacket_Localised sec_data, int flags, int channel) throws RdesktopException, IOException, CryptoException { int datalength = 0; byte[] signature = null; byte[] data; byte[] buffer; sec_data.setPosition(sec_data.getHeader(RdpPacket.SECURE_HEADER)); if (this.licenceIssued == false || (flags & SEC_ENCRYPT) != 0) { sec_data.setLittleEndian32(flags); } if (Options.debug_hexdump) { int length = sec_data.getEnd() - sec_data.getPosition(); byte[] packet = new byte[length]; sec_data.copyToByteArray( packet, 0, sec_data.getPosition(), sec_data.getEnd() - sec_data.getPosition()); System.out.println("Sending packet:"); System.out.println(net.propero.rdp.tools.HexDump.dumpHexString(packet)); } if ((flags & SEC_ENCRYPT) != 0) { flags &= ~SEC_ENCRYPT; datalength = sec_data.getEnd() - sec_data.getPosition() - 8; data = new byte[datalength]; buffer = null; sec_data.copyToByteArray(data, 0, sec_data.getPosition() + 8, datalength); signature = this.sign(this.sec_sign_key, 8, this.keylength, data, datalength); buffer = this.encrypt(data, datalength); sec_data.copyFromByteArray(signature, 0, sec_data.getPosition(), 8); sec_data.copyFromByteArray(buffer, 0, sec_data.getPosition() + 8, datalength); } // McsLayer.send(sec_data); McsLayer.send_to_channel(sec_data, channel); }
/** * 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 encryption information from a Secure layer PDU, obtaining and storing level of encryption * and any keys received * * @param data Packet to read encryption information from * @return Size of RC4 key * @throws RdesktopException */ public int parseCryptInfo(RdpPacket_Localised data) throws RdesktopException { logger.debug("Secure.parseCryptInfo"); int encryption_level = 0, random_length = 0, RSA_info_length = 0; int tag = 0, length = 0; int next_tag = 0, end = 0; int rc4_key_size = 0; rc4_key_size = data.getLittleEndian32(); // 1 = 40-Bit 2 = 128 Bit encryption_level = data.getLittleEndian32(); // 1 = low, 2 = medium, // 3 = high if (encryption_level == 0) { // no encryption return 0; } random_length = data.getLittleEndian32(); RSA_info_length = data.getLittleEndian32(); if (random_length != SEC_RANDOM_SIZE) { throw new RdesktopException( "Wrong Size of Random! Got" + random_length + "expected" + SEC_RANDOM_SIZE); } this.server_random = new byte[random_length]; data.copyToByteArray(this.server_random, 0, data.getPosition(), random_length); data.incrementPosition(random_length); end = data.getPosition() + RSA_info_length; if (end > data.getEnd()) { logger.debug("Reached end of crypt info prematurely "); return 0; } // data.incrementPosition(12); // unknown bytes int flags = data.getLittleEndian32(); // in_uint32_le(s, flags); // 1 // = RDP4-style, 0x80000002 = // X.509 logger.debug("Flags = 0x" + Integer.toHexString(flags)); if ((flags & 1) != 0) { logger.debug(("We're going for the RDP4-style encryption")); data.incrementPosition(8); // in_uint8s(s, 8); // unknown while (data.getPosition() < data.getEnd()) { tag = data.getLittleEndian16(); length = data.getLittleEndian16(); next_tag = data.getPosition() + length; switch (tag) { case (Secure.SEC_TAG_PUBKEY): if (!parsePublicKey(data)) { return 0; } break; case (Secure.SEC_TAG_KEYSIG): // Microsoft issued a key but we don't care break; default: throw new RdesktopException("Unimplemented decrypt tag " + tag); } data.setPosition(next_tag); } if (data.getPosition() == data.getEnd()) { return rc4_key_size; } else { logger.warn("End not reached!"); return 0; } } else { logger.debug(("We're going for the RDP5-style encryption")); // data.incrementPosition(4); // number of certificates int num_certs = data.getLittleEndian32(); int cacert_len = data.getLittleEndian32(); data.incrementPosition(cacert_len); int cert_len = data.getLittleEndian32(); data.incrementPosition(cert_len); readCert = true; return rc4_key_size; } }