/** * 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; } }
/** * Receive a Secure layer PDU from the MCS layer * * @return Packet representing received Secure PDU * @throws RdesktopException * @throws IOException * @throws CryptoException * @throws OrderException */ public RdpPacket_Localised receive() throws RdesktopException, IOException, CryptoException, OrderException { int sec_flags = 0; RdpPacket_Localised buffer = null; while (true) { int[] channel = new int[1]; buffer = McsLayer.receive(channel); if (buffer == null) return null; buffer.setHeader(RdpPacket.SECURE_HEADER); if (Constants.encryption || (!this.licenceIssued)) { sec_flags = buffer.getLittleEndian32(); if ((sec_flags & SEC_LICENCE_NEG) != 0) { licence.process(buffer); continue; } if ((sec_flags & SEC_ENCRYPT) != 0) { buffer.incrementPosition(8); // signature byte[] data = new byte[buffer.size() - buffer.getPosition()]; buffer.copyToByteArray(data, 0, buffer.getPosition(), data.length); byte[] packet = this.decrypt(data); buffer.copyFromByteArray(packet, 0, buffer.getPosition(), packet.length); // buffer.setStart(buffer.getPosition()); // return buffer; } } if (channel[0] != MCS.MCS_GLOBAL_CHANNEL) { channels.channel_process(buffer, channel[0]); continue; } buffer.setStart(buffer.getPosition()); return buffer; } }
/** * 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; } }