You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by de...@apache.org on 2014/01/02 08:53:15 UTC

[13/21] CLOUDSTACK-5344: Updated to allow rdp console to access hyper-v vm virtual framebuffer.

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/48c47101/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/debug/ServerPacketSniffer.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/debug/ServerPacketSniffer.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/debug/ServerPacketSniffer.java
new file mode 100755
index 0000000..a4ead0c
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/debug/ServerPacketSniffer.java
@@ -0,0 +1,49 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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 rdpclient.debug;
+
+/**
+ * Try to determine packet content by it header fingerprint.
+ */
+public class ServerPacketSniffer extends PacketSniffer {
+
+    private static final Pair[] serverRegexps = new Pair[] {
+// @formatter:off
+        new Pair("Server FastPath update",             "04"),
+        new Pair("Server X224ConnectionRequest",       "03 00 XX XX 0E D0"),
+        new Pair("Server MCSConnectResponse",          "03 00 XX XX 02 F0 80 7F 66 5A"),
+        new Pair("Server AttachUserConfirm",           "03 00 XX XX 02 F0 80 2E"),
+        new Pair("Server ChannelJoinConfirm",          "03 00 XX XX 02 F0 80 3E"),
+        new Pair("Server ErrorAlert",                  "03 00 XX XX 02 F0 80 68 00 01 03 EB 70 14 80 00"),
+        new Pair("Server DemandActivePDU",             "03 00 XX XX 02 F0 80 68 00 01 03 EB 70 XX XX XX XX 11"),
+        new Pair("Server ControlPDU",                  "03 00 XX XX 02 F0 80 68 00 01 03 EB 70 XX XX XX 17 00 EA 03 EA 03 XX 00 XX XX XX XX 14"),
+        new Pair("Server SynchronizePDU",              "03 00 XX XX 02 F0 80 68 00 01 03 EB 70 XX XX XX 17 00 EA 03 EA 03 XX 00 XX XX XX XX 1F"),
+        new Pair("Server FontMapPDU",                  "03 00 XX XX 02 F0 80 68 00 01 03 EB 70 XX XX XX 17 00 EA 03 EA 03 XX 00 XX XX XX XX 28"),
+        new Pair("Server SET_ERROR_INFO_PDU",          "03 00 XX XX 02 F0 80 68 00 01 03 EB 30 XX XX XX 17 00 00 00 EA 03 XX 00 XX XX XX XX 2F"),
+        new Pair("Server DeactivateAllPDU",            "03 00 XX XX 02 F0 80 68 00 01 03 EB 70 XX XX XX 16 00"),
+        new Pair("Server CloseConnection",             "03 00 00 09 02 F0 80 21 80"),
+        new Pair("Server CredSSP",                     "30"),
+
+        new Pair("Server a TPKT packet",               "03"),
+        new Pair("Server a FastPath packet",           "00"),
+        // @formatter:on
+    };
+
+    public ServerPacketSniffer(String id) {
+        super(id, serverRegexps);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/48c47101/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/hyperv/ClientPreConnectionBlob.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/hyperv/ClientPreConnectionBlob.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/hyperv/ClientPreConnectionBlob.java
new file mode 100755
index 0000000..05af4c0
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/hyperv/ClientPreConnectionBlob.java
@@ -0,0 +1,121 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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 rdpclient.hyperv;
+
+import rdpclient.rdp.RdpConstants;
+import streamer.ByteBuffer;
+import streamer.Element;
+import streamer.Link;
+import streamer.OneTimeSwitch;
+import streamer.Pipeline;
+import streamer.PipelineImpl;
+import streamer.debug.MockSink;
+import streamer.debug.MockSource;
+
+/**
+ * For HyperV server, client must send VM ID before any other packet.
+ */
+public class ClientPreConnectionBlob extends OneTimeSwitch {
+
+    protected String data;
+
+    public ClientPreConnectionBlob(String id, String data) {
+        super(id);
+        this.data = data;
+    }
+
+    @Override
+    protected void handleOneTimeData(ByteBuffer buf, Link link) {
+        if (buf == null)
+            return;
+
+        throw new RuntimeException("This element only sends data. This method must not be called. Unexpected packet: " + buf + ".");
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+        sendPreConnectionBlobData(data);
+    }
+
+    protected void sendPreConnectionBlobData(String data) {
+        // Length of packet
+        ByteBuffer buf = new ByteBuffer(1024, true);
+
+        // Header
+        buf.writeBytes(new byte[] {(byte)0x5e, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x02,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,});
+
+        // Length of string in wide characters + two wide \0 (LE)
+        buf.writeShortLE(data.length() + 2);
+
+        // Wide string + two wide '\0' characters
+        buf.writeString(data + "\0\0", RdpConstants.CHARSET_16);
+
+        // Trim buffer to actual length of data written
+        buf.trimAtCursor();
+
+        pushDataToOTOut(buf);
+
+        switchOff();
+    }
+
+    /**
+     * Example.
+     */
+    public static void main(String[] args) {
+        // System.setProperty("streamer.Link.debug", "true");
+        System.setProperty("streamer.Element.debug", "true");
+        // System.setProperty("streamer.Pipeline.debug", "true");
+
+        /* @formatter:off */
+        byte[] packet = new byte[] {
+                // Header
+                (byte) 0x5e, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+                // Length of string in wide characters + two wide \0 (LE)
+                (byte) 0x26, (byte) 0x00,
+
+                // Wide string
+                (byte) 0x33, (byte) 0x00, (byte) 0x39, (byte) 0x00, (byte) 0x34, (byte) 0x00, (byte) 0x31, (byte) 0x00, (byte) 0x38, (byte) 0x00, (byte) 0x46,
+                (byte) 0x00, (byte) 0x39, (byte) 0x00, (byte) 0x30, (byte) 0x00, (byte) 0x2d, (byte) 0x00, (byte) 0x36, (byte) 0x00, (byte) 0x44, (byte) 0x00,
+                (byte) 0x30, (byte) 0x00, (byte) 0x33, (byte) 0x00, (byte) 0x2d, (byte) 0x00, (byte) 0x34, (byte) 0x00, (byte) 0x36, (byte) 0x00, (byte) 0x38,
+                (byte) 0x00, (byte) 0x45, (byte) 0x00, (byte) 0x2d, (byte) 0x00, (byte) 0x42, (byte) 0x00, (byte) 0x37, (byte) 0x00, (byte) 0x39, (byte) 0x00,
+                (byte) 0x36, (byte) 0x00, (byte) 0x2d, (byte) 0x00, (byte) 0x39, (byte) 0x00, (byte) 0x31, (byte) 0x00, (byte) 0x43, (byte) 0x00, (byte) 0x36,
+                (byte) 0x00, (byte) 0x30, (byte) 0x00, (byte) 0x44, (byte) 0x00, (byte) 0x44, (byte) 0x00, (byte) 0x36, (byte) 0x00, (byte) 0x36, (byte) 0x00,
+                (byte) 0x35, (byte) 0x00, (byte) 0x33, (byte) 0x00, (byte) 0x41, (byte) 0x00,
+
+                // Two wide \0
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+        /* @formatter:on */
+
+        MockSource source = new MockSource("source", ByteBuffer.convertByteArraysToByteBuffers(new byte[] {1, 2, 3}));
+        Element pcb = new ClientPreConnectionBlob("pcb", "39418F90-6D03-468E-B796-91C60DD6653A");
+        Element sink = new MockSink("sink", ByteBuffer.convertByteArraysToByteBuffers(packet));
+        Element mainSink = new MockSink("mainSink", ByteBuffer.convertByteArraysToByteBuffers(new byte[] {1, 2, 3}));
+
+        Pipeline pipeline = new PipelineImpl("test");
+        pipeline.add(source, pcb, sink, mainSink);
+        pipeline.link("source", "pcb", "mainSink");
+        pipeline.link("pcb >" + OTOUT, "sink");
+        pipeline.runMainLoop("source", STDOUT, false, false);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/48c47101/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ntlmssp/ClientNtlmsspNegotiate.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ntlmssp/ClientNtlmsspNegotiate.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ntlmssp/ClientNtlmsspNegotiate.java
new file mode 100755
index 0000000..8bac4ab
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ntlmssp/ClientNtlmsspNegotiate.java
@@ -0,0 +1,177 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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 rdpclient.ntlmssp;
+
+import rdpclient.ntlmssp.asn1.NegoItem;
+import rdpclient.ntlmssp.asn1.TSRequest;
+import rdpclient.rdp.RdpConstants;
+import streamer.ByteBuffer;
+import streamer.Element;
+import streamer.Link;
+import streamer.OneTimeSwitch;
+import streamer.Pipeline;
+import streamer.PipelineImpl;
+import streamer.debug.MockSink;
+import streamer.debug.MockSource;
+import common.asn1.Tag;
+
+/**
+ * @see http://msdn.microsoft.com/en-us/library/cc236641.aspx
+ */
+public class ClientNtlmsspNegotiate extends OneTimeSwitch {
+
+    /**
+     * The set of client configuration flags (section 2.2.2.5) that specify the
+     * full set of capabilities of the client.
+     */
+    public NegoFlags clientConfigFlags = new NegoFlags().set_NEGOTIATE_56().set_NEGOTIATE_KEY_EXCH().set_NEGOTIATE_128().set_NEGOTIATE_VERSION()
+            .set_NEGOTIATE_EXTENDED_SESSION_SECURITY().set_NEGOTIATE_ALWAYS_SIGN().set_NEGOTIATE_NTLM().set_NEGOTIATE_LM_KEY().set_NEGOTIATE_SEAL()
+            .set_NEGOTIATE_SIGN().set_REQUEST_TARGET().set_NEGOTIATE_OEM().set_NEGOTIATE_UNICODE();
+
+    protected NtlmState ntlmState;
+
+    public ClientNtlmsspNegotiate(String id, NtlmState state) {
+        super(id);
+        ntlmState = state;
+    }
+
+    @Override
+    protected void handleOneTimeData(ByteBuffer buf, Link link) {
+        if (buf == null)
+            return;
+
+        throw new RuntimeException("Unexpected packet: " + buf + ".");
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+
+        ByteBuffer negoToken = generateNegotiateMessage();
+        ntlmState.negotiateMessage = negoToken.toByteArray(); // Store message for MIC calculation in AUTH message
+
+        // Length of packet
+        ByteBuffer buf = new ByteBuffer(1024, true);
+
+        TSRequest tsRequest = new TSRequest("TSRequest");
+        tsRequest.version.value = 2L;
+        NegoItem negoItem = new NegoItem("NegoItem");
+        negoItem.negoToken.value = negoToken;
+        tsRequest.negoTokens.tags = new Tag[] {negoItem};
+
+        tsRequest.writeTag(buf);
+
+        // Trim buffer to actual length of data written
+        buf.trimAtCursor();
+
+        pushDataToOTOut(buf);
+
+        switchOff();
+    }
+
+    private ByteBuffer generateNegotiateMessage() {
+        ByteBuffer buf = new ByteBuffer(1024);
+
+        // Signature
+        buf.writeString("NTLMSSP", RdpConstants.CHARSET_8);
+        buf.writeByte(0);
+
+        // Message type
+        buf.writeIntLE(NtlmConstants.NEGOTIATE);
+
+        buf.writeIntLE(clientConfigFlags.value); // Flags
+
+        // If the NTLMSSP_NEGOTIATE_VERSION flag is set by the client application,
+        // the Version field MUST be set to the current version (section 2.2.2.10),
+        // the DomainName field MUST be set to a zero-length string, and the
+        // Workstation field MUST be set to a zero-length string.
+
+        // Domain: ""
+        buf.writeShortLE(0); // Length
+        buf.writeShortLE(0); // Allocated space
+        buf.writeIntLE(0); // Offset
+
+        // Workstation: ""
+        buf.writeShortLE(0); // Length
+        buf.writeShortLE(0); // Allocated space
+        buf.writeIntLE(0); // Offset
+
+        // OS Version: 6.1 (Build 7601); NTLM Current Revision 15
+        buf.writeBytes(new byte[] {(byte)0x06, (byte)0x01, (byte)0xb1, (byte)0x1d, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x0f});
+
+        // Trim buffer to actual length of data written
+        buf.trimAtCursor();
+
+        return buf;
+    }
+
+    /**
+     * Example.
+     */
+    public static void main(String args[]) {
+        // System.setProperty("streamer.Link.debug", "true");
+        System.setProperty("streamer.Element.debug", "true");
+        // System.setProperty("streamer.Pipeline.debug", "true");
+
+        /* @formatter:off */
+        byte[] packet = new byte[] {
+                // CredSSP BER header:
+
+                (byte)0x30, // Sequence
+                (byte)0x37, // Length, 55 bytes
+
+                (byte)0xa0, (byte)0x03, // TAG: [0] (constructed) LEN: 3 byte
+                (byte)0x02, (byte)0x01, (byte)0x02, // Version: (int, 1 byte, 0x02)
+
+                // Sequence of sequence
+                (byte)0xa1, (byte)0x30, // TAG: [1] (constructed) LEN: 48 bytes
+                (byte)0x30, (byte)0x2e, // TAG: [UNIVERSAL 16] (constructed) "SEQUENCE" LEN: 46 bytes
+                (byte)0x30, (byte)0x2c, // TAG: [UNIVERSAL 16] (constructed) "SEQUENCE" LEN: 44 bytes
+                (byte)0xa0, (byte)0x2a, // TAG: [0] (constructed) LEN: 42 bytes
+
+
+                (byte)0x04, (byte)0x28, // TAG: [UNIVERSAL 4] (primitive) "OCTET STRING" LEN: 40 bytes
+
+                // NTLM negotiate request
+
+                (byte)0x4e, (byte)0x54, (byte)0x4c, (byte)0x4d, (byte)0x53, (byte)0x53, (byte)0x50, (byte)0x00, // "NTLMSSP\0"
+
+                (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00, // Message type: NEGOTIATE (0x1, LE)
+
+                (byte)0xb7, (byte)0x82, (byte)0x08, (byte)0xe2, // Flags: 0xe20882b7 (LE)
+
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // Domain (security buffer, 8bit, 8 bytes): length: 0x0000 (LE), allocated space: 0x0000 (LE), offset: 0x00000000 (LE)
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // Workstation  (security buffer, 8bit, 8 bytes): length: 0x0000 (LE), allocated space: 0x0000 (LE), offset: 0x00000000 (LE)
+                (byte)0x06, (byte)0x01, (byte)0xb1, (byte)0x1d, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x0f, // OS Version: 6.1 (Build 7601); NTLM Current Revision 15, 8 bytes
+
+        };
+        /* @formatter:on */
+
+        NtlmState state = new NtlmState();
+
+        MockSource source = new MockSource("source", ByteBuffer.convertByteArraysToByteBuffers(new byte[] {1, 2, 3}));
+        Element ntlmssp_negotiate = new ClientNtlmsspNegotiate("ntlmssp_negotiate", state);
+        Element sink = new MockSink("sink", ByteBuffer.convertByteArraysToByteBuffers(packet));
+        Element mainSink = new MockSink("mainSink", ByteBuffer.convertByteArraysToByteBuffers(new byte[] {1, 2, 3}));
+
+        Pipeline pipeline = new PipelineImpl("test");
+        pipeline.add(source, ntlmssp_negotiate, sink, mainSink);
+        pipeline.link("source", "ntlmssp_negotiate", "mainSink");
+        pipeline.link("ntlmssp_negotiate >" + OTOUT, "sink");
+        pipeline.runMainLoop("source", STDOUT, false, false);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/48c47101/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ntlmssp/ClientNtlmsspPubKeyAuth.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ntlmssp/ClientNtlmsspPubKeyAuth.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ntlmssp/ClientNtlmsspPubKeyAuth.java
new file mode 100755
index 0000000..ffd1630
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ntlmssp/ClientNtlmsspPubKeyAuth.java
@@ -0,0 +1,680 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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 rdpclient.ntlmssp;
+
+import java.nio.charset.Charset;
+
+import rdpclient.ntlmssp.asn1.NegoItem;
+import rdpclient.ntlmssp.asn1.SubjectPublicKeyInfo;
+import rdpclient.ntlmssp.asn1.TSRequest;
+import rdpclient.rdp.RdpConstants;
+import streamer.ByteBuffer;
+import streamer.Element;
+import streamer.Link;
+import streamer.OneTimeSwitch;
+import streamer.Pipeline;
+import streamer.PipelineImpl;
+import streamer.debug.Dumper;
+import streamer.debug.MockSink;
+import streamer.debug.MockSource;
+import streamer.ssl.SSLState;
+import common.asn1.Tag;
+
+/**
+ * @see http://msdn.microsoft.com/en-us/library/cc236643.aspx
+ */
+public class ClientNtlmsspPubKeyAuth extends OneTimeSwitch implements NtlmConstants, Dumper {
+
+    /**
+     * Offset of first byte of allocated block after NTLMSSP header and block
+     * descriptors.
+     */
+    private static final int BLOCKS_OFFSET = 88;
+
+    protected NtlmState ntlmState;
+    protected SSLState sslState;
+
+    protected String targetDomain;
+    protected String user;
+    protected String password;
+    protected String workstation;
+    protected String serverHostName;
+
+    public ClientNtlmsspPubKeyAuth(String id, NtlmState ntlmState, SSLState sslState, String serverHostName, String targetDomain, String workstation,
+            String user, String password) {
+        super(id);
+        this.ntlmState = ntlmState;
+        this.sslState = sslState;
+        this.serverHostName = serverHostName;
+        this.targetDomain = targetDomain;
+        this.workstation = workstation;
+        this.user = user;
+        this.password = password;
+    }
+
+    @Override
+    protected void handleOneTimeData(ByteBuffer buf, Link link) {
+        if (buf == null)
+            return;
+
+        throw new RuntimeException("Unexpected packet: " + buf + ".");
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+
+        /*
+         * @see
+         * http://blogs.msdn.com/b/openspecification/archive/2010/04/20/ntlm-keys
+         * -and-sundry-stuff.aspx
+         */
+        ntlmState.domain = targetDomain;
+        ntlmState.user = user;
+        ntlmState.password = password;
+        ntlmState.workstation = workstation;
+        ntlmState.generateServicePrincipalName(serverHostName);
+        ntlmState.ntlm_construct_authenticate_target_info();
+        ntlmState.ntlm_generate_timestamp();
+        ntlmState.ntlm_generate_client_challenge();
+        ntlmState.ntlm_compute_lm_v2_response();
+        ntlmState.ntlm_compute_ntlm_v2_response();
+        ntlmState.ntlm_generate_key_exchange_key();
+        ntlmState.ntlm_generate_random_session_key();
+        ntlmState.ntlm_generate_exported_session_key();
+        ntlmState.ntlm_encrypt_random_session_key();
+        ntlmState.ntlm_init_rc4_seal_states();
+
+        ByteBuffer authenticateMessage = generateAuthenticateMessage(ntlmState);
+        ByteBuffer messageSignatureAndEncryptedServerPublicKey = generateMessageSignatureAndEncryptedServerPublicKey(ntlmState);
+
+        // Length of packet
+        ByteBuffer buf = new ByteBuffer(4096, true);
+
+        TSRequest tsRequest = new TSRequest("TSRequest");
+        tsRequest.version.value = 2L;
+        NegoItem negoItem = new NegoItem("NegoItem");
+        negoItem.negoToken.value = authenticateMessage;
+
+        tsRequest.negoTokens.tags = new Tag[] {negoItem};
+
+        tsRequest.pubKeyAuth.value = messageSignatureAndEncryptedServerPublicKey;
+
+        tsRequest.writeTag(buf);
+
+        // Trim buffer to actual length of data written
+        buf.trimAtCursor();
+
+        pushDataToOTOut(buf);
+
+        switchOff();
+    }
+
+    private byte[] getServerPublicKey() {
+        // SSL certificate public key with algorithm
+        ByteBuffer subjectPublicKeyInfo = new ByteBuffer(sslState.serverCertificateSubjectPublicKeyInfo);
+
+        // Parse subjectPublicKeyInfo
+        SubjectPublicKeyInfo parser = new SubjectPublicKeyInfo("SubjectPublicKeyInfo");
+        parser.readTag(subjectPublicKeyInfo);
+
+        // Copy subjectPublicKey subfield to separate byte buffer
+        ByteBuffer subjectPublicKey = new ByteBuffer(subjectPublicKeyInfo.length);
+        parser.subjectPublicKey.writeTag(subjectPublicKey);
+
+        subjectPublicKeyInfo.unref();
+        subjectPublicKey.trimAtCursor();
+
+        // Skip tag:
+        // 03 82 01 0f (tag) 00 (padding byte)
+        subjectPublicKey.trimHeader(5);// FIXME: parse it properly
+        // * DEBUG */System.out.println("DEBUG: subjectPublicKey:\n" +
+        // subjectPublicKey.dump());
+
+        ntlmState.subjectPublicKey = subjectPublicKey.toByteArray();
+
+        return ntlmState.subjectPublicKey;
+    }
+
+    /**
+     * The client encrypts the public key it received from the server (contained
+     * in the X.509 certificate) in the TLS handshake from step 1, by using the
+     * confidentiality support of SPNEGO.
+     *
+     * The public key that is encrypted is the ASN.1-encoded SubjectPublicKey
+     * sub-field of SubjectPublicKeyInfo from the X.509 certificate, as specified
+     * in [RFC3280] section 4.1. The encrypted key is encapsulated in the
+     * pubKeyAuth field of the TSRequest structure and is sent over the TLS
+     * channel to the server.
+     */
+    private ByteBuffer generateMessageSignatureAndEncryptedServerPublicKey(NtlmState ntlmState) {
+        return new ByteBuffer(ntlmState.ntlm_EncryptMessage(getServerPublicKey()));
+    }
+
+    public static ByteBuffer generateAuthenticateMessage(NtlmState ntlmState) {
+
+        // Allocate memory for blocks from given fixed offset
+        int blocksCursor = BLOCKS_OFFSET;
+
+        ByteBuffer buf = new ByteBuffer(4096);
+
+        // Signature: "NTLMSSP\0"
+        buf.writeString(NTLMSSP, RdpConstants.CHARSET_8);
+        buf.writeByte(0);
+
+        // NTLM Message Type: NTLMSSP_AUTH (0x00000003)
+        buf.writeIntLE(NtlmConstants.NTLMSSP_AUTH);
+
+        // Although the protocol allows authentication to succeed if the client
+        // provides either LmChallengeResponse or NtChallengeResponse, Windows
+        // implementations provide both.
+
+        // LM V2 response
+        blocksCursor = writeBlock(buf, ntlmState.lmChallengeResponse, blocksCursor);
+
+        // NT v2 response
+        blocksCursor = writeBlock(buf, ntlmState.ntChallengeResponse, blocksCursor);
+
+        // DomainName
+        blocksCursor = writeStringBlock(buf, ntlmState.domain, blocksCursor, RdpConstants.CHARSET_16);
+
+        // UserName
+        blocksCursor = writeStringBlock(buf, ntlmState.user, blocksCursor, RdpConstants.CHARSET_16);
+
+        // Workstation
+        blocksCursor = writeStringBlock(buf, ntlmState.workstation, blocksCursor, RdpConstants.CHARSET_16);
+
+        // EncryptedRandomSessionKey, 16 bytes
+        blocksCursor = writeBlock(buf, ntlmState.encryptedRandomSessionKey, blocksCursor);
+
+        // NegotiateFlags (4 bytes): In connection-oriented mode, a NEGOTIATE
+        // structure that contains the set of bit flags (section 2.2.2.5) negotiated
+        // in the previous messages.
+        buf.writeIntLE(/*ntlmState.negotiatedFlags.value*/0xe288b235); // FIXME: remove hardcoded value
+
+        buf.writeBytes(generateVersion());
+
+        // If the CHALLENGE_MESSAGE TargetInfo field (section 2.2.1.2) has an
+        // MsvAvTimestamp present, the client SHOULD provide a MIC(Message Integrity
+        // Check)
+
+        int savedCursorForMIC = buf.cursor; // Save cursor position to write MIC
+        // later
+        buf.writeBytes(new byte[16]); // Write 16 zeroes
+
+        if (BLOCKS_OFFSET != buf.cursor)
+            throw new RuntimeException("BUG: Actual offset of first byte of allocated blocks is not equal hardcoded offset. Hardcoded offset: " + BLOCKS_OFFSET
+                    + ", actual offset: " + buf.cursor + ". Update hardcoded offset to match actual offset.");
+
+        buf.cursor = blocksCursor;
+        buf.trimAtCursor();
+
+        ntlmState.authenticateMessage = buf.toByteArray();
+
+        // Calculate and write MIC to reserved position
+        ntlmState.ntlm_compute_message_integrity_check();
+        buf.cursor = savedCursorForMIC;
+        buf.writeBytes(ntlmState.messageIntegrityCheck);
+        buf.rewindCursor();
+
+        return buf;
+    }
+
+    /**
+     * Write string as security buffer, using given charset, without trailing '\0'
+     * character.
+     */
+    private static int writeStringBlock(ByteBuffer buf, String string, int blocksCursor, Charset charset) {
+        return writeBlock(buf, string.getBytes(charset), blocksCursor);
+    }
+
+    /**
+     * Write block to blocks buffer and block descriptor to main buffer.
+     */
+    private static int writeBlock(ByteBuffer buf, byte[] block, int blocksCursor) {
+
+        // Write block descriptor
+
+        // Length
+        buf.writeShortLE(block.length);
+        // Allocated
+        buf.writeShortLE(block.length);
+        // Offset
+        buf.writeIntLE(blocksCursor);
+
+        // Write block to position pointed by blocksCursor instead of buf.cursor
+        int savedCursor = buf.cursor;
+        buf.cursor = blocksCursor;
+        buf.writeBytes(block);
+        blocksCursor = buf.cursor;
+        buf.cursor = savedCursor;
+
+        return blocksCursor;
+    }
+
+    /**
+     * Version (8 bytes): A VERSION structure (section 2.2.2.10) that is present
+     * only when the NTLMSSP_NEGOTIATE_VERSION flag is set in the NegotiateFlags
+     * field. This structure is used for debugging purposes only. In normal
+     * protocol messages, it is ignored and does not affect the NTLM message
+     * processing.
+     */
+    private static byte[] generateVersion() {
+        // Version (6.1, Build 7601), NTLM current revision: 15
+        return new byte[] {0x06, 0x01, (byte)0xb1, 0x1d, 0x00, 0x00, 0x00, 0x0f};
+    }
+
+    /**
+     * Example.
+     */
+    public static void main(String args[]) {
+        System.setProperty("streamer.Element.debug", "true");
+
+        /* @formatter:off */
+        //
+        // Client NEGOTIATE
+        //
+        byte[] clientNegotiatePacket = new byte[] {
+                (byte)0x30, (byte)0x37, (byte)0xa0, (byte)0x03, (byte)0x02, (byte)0x01, (byte)0x02, (byte)0xa1, (byte)0x30, (byte)0x30, (byte)0x2e, (byte)0x30, (byte)0x2c, (byte)0xa0, (byte)0x2a, (byte)0x04,
+                (byte)0x28, (byte)0x4e, (byte)0x54, (byte)0x4c, (byte)0x4d, (byte)0x53, (byte)0x53, (byte)0x50, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xb7, (byte)0x82, (byte)0x08,
+                (byte)0xe2, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x06, (byte)0x01, (byte)0xb1, (byte)0x1d, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x0f,
+        };
+
+//
+// Server CHALLENGE
+//
+        byte[] serverChallengePacket = new byte[] {
+                0x30, (byte) 0x82, 0x01, 0x02, // TAG: [UNIVERSAL 16] (constructed) "SEQUENCE" LEN: 258 bytes
+
+                (byte) 0xa0, 0x03, // TAG: [0] (constructed) LEN: 3 bytes
+                0x02, 0x01, 0x03,  // TAG: [UNIVERSAL 2] (primitive) "INTEGER" LEN: 1 bytes, Version: 0x3
+                (byte) 0xa1, (byte) 0x81, (byte) 0xfa, // TAG: [1] (constructed) LEN: 250 bytes
+                0x30, (byte) 0x81, (byte) 0xf7, // TAG: [UNIVERSAL 16] (constructed) "SEQUENCE" LEN: 247 bytes
+                0x30, (byte) 0x81, (byte) 0xf4, // TAG: [UNIVERSAL 16] (constructed) "SEQUENCE" LEN: 244 bytes
+                (byte) 0xa0, (byte) 0x81, (byte) 0xf1, // TAG: [0] (constructed) LEN: 241 bytes
+                0x04, (byte) 0x81, (byte) 0xee, // TAG: [UNIVERSAL 4] (primitive) "OCTET STRING" LEN: 238 bytes
+
+                0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, // "NTLMSSP\0"
+
+                0x02, 0x00, 0x00, 0x00, // MessageType (CHALLENGE)
+
+                0x1e, 0x00, 0x1e, 0x00, 0x38, 0x00, 0x00, 0x00, // TargetName (length: 30, allocated space: 30, offset: 56)
+                0x35, (byte) 0x82, (byte) 0x8a, (byte) 0xe2, // NegotiateFlags: NEGOTIATE_56 NEGOTIATE_KEY_EXCH NEGOTIATE_128 NEGOTIATE_VERSION NEGOTIATE_TARGET_INFO NEGOTIATE_EXTENDED_SESSION_SECURITY TARGET_TYPE_SERVER NEGOTIATE_ALWAYS_SIGN NEGOTIATE_NTLM NEGOTIATE_SEAL NEGOTIATE_SIGN REQUEST_TARGET NEGOTIATE_UNICODE
+
+                (byte)0xc1, (byte)0x4a, (byte)0xc8, (byte)0x98, (byte)0x2f, (byte)0xd1, (byte)0x93, (byte)0xd4, //  ServerChallenge
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //  Reserved
+                (byte) 0x98, 0x00, (byte) 0x98, 0x00, 0x56, 0x00, 0x00, 0x00, // TargetInfo (length: 152, allocated space: 152, offset: 86)
+                0x06, 0x03, (byte) 0xd7, 0x24, 0x00, 0x00, 0x00, 0x0f,  // Version (6.3, build 9431) , NTLM current revision: 15
+
+
+                0x57, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x2d, 0x00, 0x4c, 0x00, 0x4f, 0x00, 0x34, 0x00, 0x31, 0x00, 0x39, 0x00, 0x42, 0x00, 0x32, 0x00, 0x4c, 0x00, 0x53, 0x00, 0x52, 0x00, 0x30, 0x00,  // Target name value: "WIN-LO419B2LSR0"
+
+                // Target Info value:
+
+                // Attribute list
+
+                0x02, 0x00, // Item Type: NetBIOS domain name (0x0002, LE)
+                0x1e, 0x00, //  Item Length: 30 (LE)
+                0x57, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x2d, 0x00, 0x4c, 0x00, 0x4f, 0x00, 0x34, 0x00, 0x31, 0x00, 0x39, 0x00, 0x42, 0x00, 0x32, 0x00, 0x4c, 0x00, 0x53, 0x00, 0x52, 0x00, 0x30, 0x00, // "WIN-LO419B2LSR0"
+
+                0x01, 0x00,  //  Item Type: NetBIOS computer name (0x0001, LE)
+                0x1e, 0x00, //  Item Length: 30 (LE)
+                0x57, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x2d, 0x00, 0x4c, 0x00, 0x4f, 0x00, 0x34, 0x00, 0x31, 0x00, 0x39, 0x00, 0x42, 0x00, 0x32, 0x00, 0x4c, 0x00, 0x53, 0x00, 0x52, 0x00, 0x30, 0x00, // "WIN-LO419B2LSR0"
+
+                0x04, 0x00,  // Item Type: DNS domain name (0x0004, LE)
+                0x1e, 0x00, //  Item Length: 30 (LE)
+                0x57, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x2d, 0x00, 0x4c, 0x00, 0x4f, 0x00, 0x34, 0x00, 0x31, 0x00, 0x39, 0x00, 0x42, 0x00, 0x32, 0x00, 0x4c, 0x00, 0x53, 0x00, 0x52, 0x00, 0x30, 0x00, // "WIN-LO419B2LSR0"
+
+                0x03, 0x00,  // Item Type: DNS computer name (0x0003, LE)
+                0x1e, 0x00, //  Item Length: 30 (LE)
+                0x57, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x2d, 0x00, 0x4c, 0x00, 0x4f, 0x00, 0x34, 0x00, 0x31, 0x00, 0x39, 0x00, 0x42, 0x00, 0x32, 0x00, 0x4c, 0x00, 0x53, 0x00, 0x52, 0x00, 0x30, 0x00, // "WIN-LO419B2LSR0"
+
+                0x07, 0x00,  // Item Type: Timestamp (0x0007, LE)
+                0x08, 0x00, //  Item Length: 8 (LE)
+                (byte)0x1d, (byte)0xea, (byte)0x6b, (byte)0x60, (byte)0xf8, (byte)0xc5, (byte)0xce, (byte)0x01, // Time: Oct 10, 2013 23:36:20.056937300 EEST
+
+                // Attribute: End of list
+                0x00, 0x00,
+                0x00, 0x00,
+
+        };
+
+//
+// Client NTLMSSP_AUTH
+//
+        byte[] clientAuthPacket = new byte[] {
+                0x30, (byte) 0x82, 0x03, 0x13, //  TAG: [UNIVERSAL 16] (constructed) "SEQUENCE" LEN: 787 bytes
+
+                //
+                // TSRequest.version
+                //
+                (byte) 0xa0, 0x03, //  TAG: [0] (constructed) LEN: 3 bytes
+                0x02, 0x01, 0x02, //  TAG: [UNIVERSAL 2] (primitive) "INTEGER" LEN: 1 bytes
+
+                //
+                // TSRequest.negoData
+                //
+                (byte) 0xa1, (byte) 0x82, 0x01, (byte) 0xe4, //  TAG: [1] (constructed) LEN: 484 bytes
+                0x30, (byte) 0x82, 0x01, (byte) 0xe0, //  TAG: [UNIVERSAL 16] (constructed) "SEQUENCE" LEN: 480 bytes
+                0x30, (byte) 0x82, 0x01, (byte) 0xdc, //  TAG: [UNIVERSAL 16] (constructed) "SEQUENCE" LEN: 476 bytes
+
+                //
+                // NegoItem.negoToken
+                //
+                (byte) 0xa0, (byte) 0x82, 0x01, (byte) 0xd8, //  TAG: [0] (constructed) LEN: 472 bytes
+                0x04, (byte) 0x82, 0x01, (byte) 0xd4,  // TAG: [UNIVERSAL 4] (primitive) "OCTET STRING" LEN: 468 bytes
+
+                // NTLMSSP
+
+                0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, //  "NTLMSSP\0"
+
+                0x03, 0x00, 0x00, 0x00, //  NTLM Message Type: NTLMSSP_AUTH (0x00000003)
+                0x18, 0x00, 0x18, 0x00, (byte) 0x92, 0x00, 0x00, 0x00, //  LmChallengeResponse (length 24, allocated: 24, offset 146)
+                0x1a, 0x01, 0x1a, 0x01, (byte) 0xaa, 0x00, 0x00, 0x00, //  NtChallengeResponse (length 282, allocated: 282, offset 170)
+                0x12, 0x00, 0x12, 0x00, 0x58, 0x00, 0x00, 0x00,  // DomainName (length 18, allocated: 88, offset 88)
+                0x1a, 0x00, 0x1a, 0x00, 0x6a, 0x00, 0x00, 0x00,  // UserName (length 26, allocated:26, offset 106)
+                0x0e, 0x00, 0x0e, 0x00, (byte) 0x84, 0x00, 0x00, 0x00,  // Workstation (length 14, offset 132)
+                0x10, 0x00, 0x10, 0x00, (byte) 0xc4, 0x01, 0x00, 0x00,  // EncryptedRandomSessionKey (length 16, offset 452)
+                0x35, (byte) 0xb2, (byte) 0x88, (byte) 0xe2,   // NegotiateFlags
+                0x06, 0x01, (byte) 0xb1, 0x1d, 0x00, 0x00, 0x00, 0x0f, //  Version (6.1, Build 7601), NTLM current revision: 15
+
+                (byte)0x8c, (byte)0x69, (byte)0x53, (byte)0x1c, (byte)0xbb, (byte)0x6f, (byte)0xfb, (byte)0x9a, (byte)0x5d, (byte)0x2c, (byte)0x63, (byte)0xf2, (byte)0xc9, (byte)0x51, (byte)0xc5, (byte)0x11, // Message integrity check
+
+                0x77, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x6b, 0x00, 0x67, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x70, 0x00, // Domain name value: "Workgroup"
+
+                0x41, 0x00, 0x64, 0x00, 0x6d, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x69, 0x00, 0x73, 0x00, 0x74, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x72, 0x00,  // User name value: "Administrator"
+
+                0x61, 0x00, 0x70, 0x00, 0x6f, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x33, 0x00, //  Workstation host name value: "apollo3"
+
+                // Lan manager challenge response value
+                // Response: HMAC_MD(ResponseKeyLM, concatenate(ServerChallenge, ClientChallenge), where ResponseKeyLM=ntlmv2Hash(target, user, password)
+                (byte)0x17, (byte)0x9b, (byte)0x7d, (byte)0x7b, (byte)0x2f, (byte)0x79, (byte)0x9f, (byte)0x19, (byte)0xa0, (byte)0x4b, (byte)0x00, (byte)0xed, (byte)0x2b, (byte)0x39, (byte)0xbb, (byte)0x23,
+                // Client challenge (fixed for debugging)
+                (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04, (byte)0x05, (byte)0x06, (byte)0x07, (byte)0x08,
+
+                //
+                // NTLM challenge response value:
+                //
+
+                (byte)0x49, (byte)0xea, (byte)0x27, (byte)0x4f, (byte)0xcc, (byte)0x05, (byte)0x8b, (byte)0x79, (byte)0x20, (byte)0x0b, (byte)0x08, (byte)0x42, (byte)0xa9, (byte)0xc8, (byte)0x0e, (byte)0xc7, //  HMAC
+
+                0x01, 0x01, 0x00, 0x00, // Header: 0x00000101 (LE)
+                0x00, 0x00, 0x00, 0x00, // Reserved: 0x00000000
+                (byte)0x1d, (byte)0xea, (byte)0x6b, (byte)0x60, (byte)0xf8, (byte)0xc5, (byte)0xce, (byte)0x01, // Time: Oct 10, 2013 23:36:20.056937300 EEST
+                (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04, (byte)0x05, (byte)0x06, (byte)0x07, (byte)0x08, // Client challenge (fixed)
+                0x00, 0x00, 0x00, 0x00, //  Reserved
+
+                // Target Info value:
+
+                // Attribute list
+
+                0x02, 0x00, // Item Type: NetBIOS domain name (0x0002, LE)
+                0x1e, 0x00, //  Item Length: 30 (LE)
+                0x57, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x2d, 0x00, 0x4c, 0x00, 0x4f, 0x00, 0x34, 0x00, 0x31, 0x00, 0x39, 0x00, 0x42, 0x00, 0x32, 0x00, 0x4c, 0x00, 0x53, 0x00, 0x52, 0x00, 0x30, 0x00,  //  "WIN-LO419B2LSR0 "
+
+                0x01, 0x00,  //  Item Type: NetBIOS computer name (0x0001, LE)
+                0x1e, 0x00,  // Item Length: 30 (LE)
+                0x57, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x2d, 0x00, 0x4c, 0x00, 0x4f, 0x00, 0x34, 0x00, 0x31, 0x00, 0x39, 0x00, 0x42, 0x00, 0x32, 0x00, 0x4c, 0x00, 0x53, 0x00, 0x52, 0x00, 0x30, 0x00, //  "WIN-LO419B2LSR0 "
+
+                0x04, 0x00,  // Item Type: DNS domain name (0x0004, LE)
+                0x1e, 0x00,  // Item Length: 30 (LE)
+                0x57, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x2d, 0x00, 0x4c, 0x00, 0x4f, 0x00, 0x34, 0x00, 0x31, 0x00, 0x39, 0x00, 0x42, 0x00, 0x32, 0x00, 0x4c, 0x00, 0x53, 0x00, 0x52, 0x00, 0x30, 0x00, //  "WIN-LO419B2LSR0 "
+
+                0x03, 0x00,  // Item Type: DNS computer name (0x0003, LE)
+                0x1e, 0x00,  // Item Length: 30 (LE)
+                0x57, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x2d, 0x00, 0x4c, 0x00, 0x4f, 0x00, 0x34, 0x00, 0x31, 0x00, 0x39, 0x00, 0x42, 0x00, 0x32, 0x00, 0x4c, 0x00, 0x53, 0x00, 0x52, 0x00, 0x30, 0x00, //  "WIN-LO419B2LSR0 "
+
+                0x07, 0x00,  // Item Type: Timestamp (0x0007, LE)
+                0x08, 0x00,  // Item Length: 8 (LE)
+                (byte)0x1d, (byte)0xea, (byte)0x6b, (byte)0x60, (byte)0xf8, (byte)0xc5, (byte)0xce, (byte)0x01, // Timestamp: Oct 10, 2013 23:36:20.056937300 EEST
+
+                0x06, 0x00,  // Item Type: Flags (0x0006, LE)
+                0x04, 0x00, // Item Length: 4 (LE)
+                0x02, 0x00, 0x00, 0x00, // Flags: 0x00000002
+
+                0x0a, 0x00, // Item Type: Channel Bindings (0x000a, LE)
+                0x10, 0x00, // Item Length: 16 (LE)
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Channel Bindings: 00000000000000000000000000000000
+
+                0x09, 0x00, // Item Type: Target Name (0x0009, LE)
+                0x2a, 0x00, // Item Length: 42 (LE)
+                0x54, 0x00, 0x45, 0x00, 0x52, 0x00, 0x4d, 0x00, 0x53, 0x00, 0x52, 0x00, 0x56, 0x00, 0x2f, 0x00, 0x31, 0x00, 0x39, 0x00, 0x32, 0x00, 0x2e, 0x00, 0x31, 0x00, 0x36, 0x00, 0x38, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x2e, 0x00, 0x31, 0x00, 0x30, 0x00, 0x31, 0x00, // Target Name: "TERMSRV/192.168.0.101" (UTF-16)
+
+                // Attribute: End of list
+                0x00, 0x00,  //
+                0x00, 0x00,  //
+                // Attribute: End of list
+                0x00, 0x00,  //
+                0x00, 0x00,  //
+                // Attribute: End of list
+                0x00, 0x00,  //
+                0x00, 0x00,  //
+                // Attribute: End of list
+                0x00, 0x00,  //
+                0x00, 0x00,  //
+
+                // Session Key
+                // RC4 key (Server KeyExchangeKey or SessionBaseKey):
+                // 6e bd e3 da 83 c2 fd f1 38 a2 78 be 8c e6 75 d6
+                //
+                // RC4 data (Client nonce):
+                // 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10
+                //
+                // RC4 encrypted:
+                // 2c 24 da 10 17 cf 40 69 35 49 6f 58 e1 29 9e 79
+                (byte)0x2c, (byte)0x24, (byte)0xda, (byte)0x10, (byte)0x17, (byte)0xcf, (byte)0x40, (byte)0x69, (byte)0x35, (byte)0x49, (byte)0x6f, (byte)0x58, (byte)0xe1, (byte)0x29, (byte)0x9e, (byte)0x79,
+
+                //
+                // TSRequest.publicKey
+                //
+                (byte) 0xa3, (byte) 0x82, 0x01, 0x22, // TAG: [3] (constructed) LEN: 290 bytes
+                0x04, (byte) 0x82, 0x01, 0x1e,  // TAG: [UNIVERSAL 4] (primitive) "OCTET STRING" LEN: 286 bytes
+
+                // NTLMSSP_MESSAGE_SIGNATURE, @see http://msdn.microsoft.com/en-us/library/cc422952.aspx
+
+                // Version: 0x00000001
+                (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00,
+
+                // Checksum (8 bytes): An 8-byte array that contains the checksum for the message.
+                (byte)0x72, (byte)0x76, (byte)0x1e, (byte)0x57, (byte)0x49, (byte)0xb5, (byte)0x0f, (byte)0xad,
+
+                // seqNum of the message: 0
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+
+                // Encrypted public key
+                (byte)0x15, (byte)0xf7, (byte)0xf2, (byte)0x54, (byte)0xda, (byte)0xa9, (byte)0xe5, (byte)0xad, (byte)0x85, (byte)0x04, (byte)0x67, (byte)0x4d, (byte)0x0b, (byte)0xcb, (byte)0xf9, (byte)0xb1,
+                (byte)0xf8, (byte)0x02, (byte)0x8a, (byte)0x77, (byte)0xc2, (byte)0x63, (byte)0xab, (byte)0xd5, (byte)0x74, (byte)0x23, (byte)0x9f, (byte)0x9d, (byte)0x5d, (byte)0x1f, (byte)0xd3, (byte)0xb3,
+                (byte)0xa0, (byte)0xac, (byte)0x16, (byte)0x8a, (byte)0x4b, (byte)0x08, (byte)0xf5, (byte)0x47, (byte)0x70, (byte)0x58, (byte)0x10, (byte)0xb4, (byte)0xe7, (byte)0x87, (byte)0xb3, (byte)0x4b,
+                (byte)0xc9, (byte)0xa2, (byte)0xd5, (byte)0xd1, (byte)0xca, (byte)0x0f, (byte)0xd4, (byte)0xe3, (byte)0x8d, (byte)0x76, (byte)0x5a, (byte)0x60, (byte)0x28, (byte)0xf8, (byte)0x06, (byte)0x5d,
+                (byte)0xe4, (byte)0x7e, (byte)0x21, (byte)0xc8, (byte)0xbb, (byte)0xac, (byte)0xe5, (byte)0x79, (byte)0x85, (byte)0x30, (byte)0x9b, (byte)0x88, (byte)0x13, (byte)0x2f, (byte)0x8f, (byte)0xfc,
+                (byte)0x04, (byte)0x52, (byte)0xfe, (byte)0x87, (byte)0x94, (byte)0xcf, (byte)0xcb, (byte)0x49, (byte)0x4a, (byte)0xda, (byte)0x6f, (byte)0xdd, (byte)0xee, (byte)0x57, (byte)0xa5, (byte)0xe4,
+                (byte)0x4d, (byte)0x0e, (byte)0x5c, (byte)0x3d, (byte)0x0b, (byte)0x63, (byte)0x1f, (byte)0xf6, (byte)0x3d, (byte)0x1b, (byte)0xae, (byte)0x5a, (byte)0xf6, (byte)0x42, (byte)0x2a, (byte)0x46,
+                (byte)0xfa, (byte)0x42, (byte)0x71, (byte)0x67, (byte)0x46, (byte)0x02, (byte)0x71, (byte)0xea, (byte)0x51, (byte)0x98, (byte)0xf7, (byte)0xd4, (byte)0x43, (byte)0xbf, (byte)0x8e, (byte)0xe8,
+                (byte)0x3c, (byte)0xc8, (byte)0xfa, (byte)0x79, (byte)0x9d, (byte)0x8c, (byte)0xfc, (byte)0xc2, (byte)0x42, (byte)0xc9, (byte)0xbb, (byte)0xd0, (byte)0xab, (byte)0x81, (byte)0xc4, (byte)0x53,
+                (byte)0xfd, (byte)0x41, (byte)0xda, (byte)0xab, (byte)0x0f, (byte)0x25, (byte)0x79, (byte)0x5f, (byte)0xbd, (byte)0xa3, (byte)0x8c, (byte)0xd3, (byte)0xf5, (byte)0x1b, (byte)0xab, (byte)0x20,
+                (byte)0xd1, (byte)0xf4, (byte)0xd8, (byte)0x81, (byte)0x9c, (byte)0x18, (byte)0x4a, (byte)0xa4, (byte)0x77, (byte)0xee, (byte)0xe1, (byte)0x51, (byte)0xee, (byte)0x2a, (byte)0xc1, (byte)0x94,
+                (byte)0x37, (byte)0xc5, (byte)0x06, (byte)0x7a, (byte)0x3f, (byte)0x0f, (byte)0x25, (byte)0x5b, (byte)0x4e, (byte)0x6a, (byte)0xdc, (byte)0x0b, (byte)0x62, (byte)0x6f, (byte)0x12, (byte)0x83,
+                (byte)0x03, (byte)0xae, (byte)0x4e, (byte)0xce, (byte)0x2b, (byte)0x6e, (byte)0xd4, (byte)0xd5, (byte)0x23, (byte)0x27, (byte)0xf6, (byte)0xa6, (byte)0x38, (byte)0x67, (byte)0xec, (byte)0x95,
+                (byte)0x82, (byte)0xc6, (byte)0xba, (byte)0xd4, (byte)0xf6, (byte)0xe6, (byte)0x22, (byte)0x7d, (byte)0xb9, (byte)0xe4, (byte)0x81, (byte)0x97, (byte)0x24, (byte)0xff, (byte)0x40, (byte)0xb2,
+                (byte)0x42, (byte)0x3c, (byte)0x11, (byte)0x24, (byte)0xd0, (byte)0x3a, (byte)0x96, (byte)0xd9, (byte)0xc1, (byte)0x13, (byte)0xd6, (byte)0x62, (byte)0x45, (byte)0x21, (byte)0x60, (byte)0x5b,
+                (byte)0x7b, (byte)0x2b, (byte)0x62, (byte)0x44, (byte)0xf7, (byte)0x40, (byte)0x93, (byte)0x29, (byte)0x5b, (byte)0x44, (byte)0xb7, (byte)0xda, (byte)0x9c, (byte)0xa6, (byte)0xa9, (byte)0x3b,
+                (byte)0xe1, (byte)0x3b, (byte)0x9d, (byte)0x31, (byte)0xf2, (byte)0x21, (byte)0x53, (byte)0x0f, (byte)0xb3, (byte)0x70, (byte)0x55, (byte)0x84, (byte)0x2c, (byte)0xb4,
+        };
+
+        SSLState sslState = new SSLState();
+
+        sslState.serverCertificateSubjectPublicKeyInfo = new byte[] {
+                0x30, (byte) 0x82, 0x01, 0x22, // Sequence, length: 290 bytes
+                0x30, 0x0d, // Sequence, length: 13 bytes {
+                0x06, 0x09, // Object ID, length: 9 bytes
+                0x2a, (byte) 0x86, 0x48, (byte) 0x86, (byte) 0xf7, 0x0d, 0x01, 0x01, 0x01,
+                0x05, 0x00, // NULL, length: 0 bytes
+
+                (byte)0x03, (byte)0x82, (byte)0x01, (byte)0x0f, // Bit string, length: 271 bytes
+
+                (byte)0x00, // Pading
+                (byte)0x30, (byte)0x82, (byte)0x01, (byte)0x0a, // Sequence
+                (byte)0x02, (byte)0x82, (byte)0x01, (byte)0x01, // Integer, length: 257 bytes
+
+                (byte)0x00, (byte)0xa8, (byte)0x56,
+                (byte)0x65, (byte)0xd3, (byte)0xce, (byte)0x8a, (byte)0x54, (byte)0x4d, (byte)0x9d, (byte)0xb0,
+                (byte)0x84, (byte)0x31, (byte)0x19, (byte)0x71, (byte)0x7f, (byte)0xdd, (byte)0x42, (byte)0xfb,
+                (byte)0x2a, (byte)0x7a, (byte)0x72, (byte)0x13, (byte)0xa1, (byte)0xb9, (byte)0x72, (byte)0xbb,
+                (byte)0xd3, (byte)0x08, (byte)0xad, (byte)0x7d, (byte)0x6c, (byte)0x15, (byte)0x65, (byte)0x03,
+                (byte)0xd1, (byte)0xc4, (byte)0x54, (byte)0xc5, (byte)0x33, (byte)0x6b, (byte)0x7d, (byte)0x69,
+                (byte)0x89, (byte)0x5e, (byte)0xfe, (byte)0xe0, (byte)0x01, (byte)0xc0, (byte)0x7e, (byte)0x9b,
+                (byte)0xcb, (byte)0x5d, (byte)0x65, (byte)0x36, (byte)0xcd, (byte)0x77, (byte)0x5d, (byte)0xf3,
+                (byte)0x7a, (byte)0x5b, (byte)0x29, (byte)0x44, (byte)0x72, (byte)0xd5, (byte)0x38, (byte)0xe2,
+                (byte)0xcf, (byte)0xb1, (byte)0xc7, (byte)0x78, (byte)0x9b, (byte)0x58, (byte)0xb9, (byte)0x17,
+                (byte)0x7c, (byte)0xb7, (byte)0xd6, (byte)0xc7, (byte)0xc7, (byte)0xbf, (byte)0x90, (byte)0x4e,
+                (byte)0x7c, (byte)0x39, (byte)0x93, (byte)0xcb, (byte)0x2e, (byte)0xe0, (byte)0xc2, (byte)0x33,
+                (byte)0x2d, (byte)0xa5, (byte)0x7e, (byte)0xe0, (byte)0x7b, (byte)0xb6, (byte)0xf9, (byte)0x91,
+                (byte)0x32, (byte)0xb7, (byte)0xd4, (byte)0x85, (byte)0xb7, (byte)0x35, (byte)0x2d, (byte)0x2b,
+                (byte)0x00, (byte)0x6d, (byte)0xf8, (byte)0xea, (byte)0x8c, (byte)0x97, (byte)0x5f, (byte)0x51,
+                (byte)0x1d, (byte)0x68, (byte)0x04, (byte)0x3c, (byte)0x79, (byte)0x14, (byte)0x71, (byte)0xa7,
+                (byte)0xc7, (byte)0xd7, (byte)0x70, (byte)0x7a, (byte)0xe0, (byte)0xba, (byte)0x12, (byte)0x69,
+                (byte)0xc8, (byte)0xd3, (byte)0xd9, (byte)0x4e, (byte)0xab, (byte)0x51, (byte)0x47, (byte)0xa3,
+                (byte)0xec, (byte)0x99, (byte)0xd4, (byte)0x88, (byte)0xca, (byte)0xda, (byte)0xc2, (byte)0x7f,
+                (byte)0x79, (byte)0x4b, (byte)0x66, (byte)0xed, (byte)0x87, (byte)0xbe, (byte)0xc2, (byte)0x5f,
+                (byte)0xea, (byte)0xcf, (byte)0xe1, (byte)0xb5, (byte)0xf0, (byte)0x3d, (byte)0x9b, (byte)0xf2,
+                (byte)0x19, (byte)0xc3, (byte)0xe0, (byte)0xe1, (byte)0x7a, (byte)0x45, (byte)0x71, (byte)0x12,
+                (byte)0x3d, (byte)0x72, (byte)0x1d, (byte)0x6f, (byte)0x2b, (byte)0x1c, (byte)0x46, (byte)0x68,
+                (byte)0xc0, (byte)0x8f, (byte)0x4f, (byte)0xce, (byte)0x3a, (byte)0xc5, (byte)0xcd, (byte)0x22,
+                (byte)0x65, (byte)0x2d, (byte)0x43, (byte)0xb0, (byte)0x5c, (byte)0xdd, (byte)0x89, (byte)0xae,
+                (byte)0xbe, (byte)0x70, (byte)0x59, (byte)0x5e, (byte)0x0c, (byte)0xbd, (byte)0xf5, (byte)0x46,
+                (byte)0x82, (byte)0x1e, (byte)0xe4, (byte)0x86, (byte)0x95, (byte)0x7b, (byte)0x60, (byte)0xae,
+                (byte)0x45, (byte)0x50, (byte)0xc2, (byte)0x54, (byte)0x08, (byte)0x49, (byte)0x9a, (byte)0x9e,
+                (byte)0xfb, (byte)0xb2, (byte)0xb6, (byte)0x78, (byte)0xe5, (byte)0x2f, (byte)0x9c, (byte)0x5a,
+                (byte)0xd0, (byte)0x8a, (byte)0x03, (byte)0x77, (byte)0x68, (byte)0x30, (byte)0x93, (byte)0x78,
+                (byte)0x6d, (byte)0x90, (byte)0x6d, (byte)0x50, (byte)0xfa, (byte)0xa7, (byte)0x65, (byte)0xfe,
+                (byte)0x59, (byte)0x33, (byte)0x27, (byte)0x4e, (byte)0x4b, (byte)0xf8, (byte)0x38, (byte)0x44,
+                (byte)0x3a, (byte)0x12, (byte)0xf4, (byte)0x07, (byte)0xa0, (byte)0x8d, (byte)0x02, (byte)0x03,
+                (byte)0x01, (byte)0x00, (byte)0x01,
+        };
+        /* @formatter:on */
+
+        NtlmState ntlmState = new NtlmState();
+        MockSource source = new MockSource("source", ByteBuffer.convertByteArraysToByteBuffers(serverChallengePacket, new byte[] {1, 2, 3}));
+        Element ntlmssp_negotiate = new ClientNtlmsspNegotiate("ntlmssp_negotiate", ntlmState);
+        Element ntlmssp_challenge = new ServerNtlmsspChallenge("ntlmssp_challenge", ntlmState);
+        Element ntlmssp_auth = new ClientNtlmsspPubKeyAuth("ntlmssp_auth", ntlmState, sslState, "192.168.0.101", "workgroup", "apollo3", "Administrator",
+                "R2Preview!");
+        Element sink = new MockSink("sink", ByteBuffer.convertByteArraysToByteBuffers(clientNegotiatePacket, clientAuthPacket), (Dumper)ntlmssp_auth);
+        Element mainSink = new MockSink("mainSink", ByteBuffer.convertByteArraysToByteBuffers(new byte[] {1, 2, 3}));
+
+        Pipeline pipeline = new PipelineImpl("test");
+        pipeline.add(source, ntlmssp_negotiate, ntlmssp_challenge, ntlmssp_auth, sink, mainSink);
+        pipeline.link("source", "ntlmssp_negotiate", "ntlmssp_challenge", "ntlmssp_auth", "mainSink");
+        pipeline.link("ntlmssp_negotiate >" + OTOUT, "ntlmssp_negotiate< sink");
+        pipeline.link("ntlmssp_challenge >" + OTOUT, "ntlmssp_challenge< sink");
+        pipeline.link("ntlmssp_auth >" + OTOUT, "ntlmssp_auth< sink");
+        pipeline.runMainLoop("source", STDOUT, false, false);
+
+    }
+
+    @Override
+    public void dump(ByteBuffer buf) {
+        buf.rewindCursor();
+        TSRequest request = new TSRequest("TSRequest");
+        request.readTag(buf);
+        System.out.println("TSRequest version: " + request.version.value);
+        System.out.println("TSRequest pubKey: " + request.pubKeyAuth.value.toPlainHexString());
+
+        ByteBuffer negoToken = ((NegoItem)request.negoTokens.tags[0]).negoToken.value;
+        System.out.println("TSRequest negotoken: " + negoToken.toPlainHexString());
+        dumpNegoToken(negoToken);
+
+        negoToken.unref();
+    }
+
+    private void dumpNegoToken(ByteBuffer buf) {
+        String signature = buf.readVariableString(RdpConstants.CHARSET_8);
+        if (!signature.equals(NTLMSSP))
+            throw new RuntimeException("Unexpected NTLM message singature: \"" + signature + "\". Expected signature: \"" + NTLMSSP + "\". Data: " + buf + ".");
+
+        // MessageType (CHALLENGE)
+        int messageType = buf.readSignedIntLE();
+        if (messageType != NtlmConstants.NTLMSSP_AUTH)
+            throw new RuntimeException("Unexpected NTLM message type: " + messageType + ". Expected type: CHALLENGE (" + NtlmConstants.CHALLENGE + "). Data: " + buf
+                    + ".");
+
+        System.out.println("lmChallengeResponseFields: " + ServerNtlmsspChallenge.readBlockByDescription(buf).toPlainHexString());
+        ByteBuffer ntChallengeResponseBuf = ServerNtlmsspChallenge.readBlockByDescription(buf);
+        System.out.println("NtChallengeResponse: " + ntChallengeResponseBuf.toPlainHexString());
+        System.out.println("DomainName: " + ServerNtlmsspChallenge.readStringByDescription(buf));
+        System.out.println("UserName: " + ServerNtlmsspChallenge.readStringByDescription(buf));
+        System.out.println("Workstation: " + ServerNtlmsspChallenge.readStringByDescription(buf));
+        System.out.println("EncryptedRandomSessionKey: " + ServerNtlmsspChallenge.readBlockByDescription(buf).toPlainHexString());
+        System.out.println("NegotiateFlags: " + new NegoFlags(buf.readSignedIntLE()));
+        System.out.println("Version: " + buf.readBytes(8).toPlainHexString());
+
+        dumpNtChallengeResponse(ntChallengeResponseBuf);
+    }
+
+    private void dumpNtChallengeResponse(ByteBuffer buf) {
+        System.out.println("HMAC: " + buf.readBytes(16).toPlainHexString());
+        System.out.format("Header: 0x%08x\n", buf.readUnsignedIntLE());
+        System.out.format("Reserved: 0x%08x\n", buf.readUnsignedIntLE());
+        System.out.println("Time: " + buf.readBytes(8).toPlainHexString());
+        System.out.println("Client challenge: " + buf.readBytes(8).toPlainHexString());
+        System.out.format("Reserved: 0x%08x\n", buf.readUnsignedIntLE());
+
+        // Parse attribute list
+
+        while (buf.remainderLength() > 0) {
+            int type = buf.readUnsignedShortLE();
+            int length = buf.readUnsignedShortLE();
+
+            if (type == MSV_AV_EOL)
+                // End of list
+                break;
+
+            ByteBuffer data = buf.readBytes(length);
+            switch (type) {
+            case MSV_AV_NETBIOS_DOMAIN_NAME:
+                System.out.println("AV Netbios Domain name: " + data.readString(length, RdpConstants.CHARSET_16));
+                break;
+            case MSV_AV_NETBIOS_COMPUTER_NAME:
+                System.out.println("AV Netbios Computer name: " + data.readString(length, RdpConstants.CHARSET_16));
+                break;
+            case MSV_AV_DNS_DOMAIN_NAME:
+                System.out.println("AV DNS Domain name: " + data.readString(length, RdpConstants.CHARSET_16));
+                break;
+            case MSV_AV_DNS_COMPUTER_NAME:
+                System.out.println("AV DNS Computer name: " + data.readString(length, RdpConstants.CHARSET_16));
+                break;
+            case MSV_AV_CHANNEL_BINDINGS:
+                System.out.println("AV Channel Bindings: " + data.readBytes(length).toPlainHexString());
+                break;
+            case MSV_AV_TIMESTAMP:
+                System.out.println("AV Timestamp: " + data.readBytes(length).toPlainHexString());
+                break;
+            case MSV_AV_FLAGS:
+                System.out.println("AV Flags: " + data.readBytes(length).toPlainHexString());
+                break;
+            case MSV_AV_TARGET_NAME:
+                System.out.println("AV Target Name: " + data.readString(length, RdpConstants.CHARSET_16));
+                break;
+            default:
+                System.out.println("Unknown NTLM target info attribute: " + type + ". Data: " + data + ".");
+            }
+            data.unref();
+        }
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/48c47101/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ntlmssp/ClientNtlmsspUserCredentials.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ntlmssp/ClientNtlmsspUserCredentials.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ntlmssp/ClientNtlmsspUserCredentials.java
new file mode 100755
index 0000000..480f448
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ntlmssp/ClientNtlmsspUserCredentials.java
@@ -0,0 +1,128 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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 rdpclient.ntlmssp;
+
+import rdpclient.ntlmssp.asn1.TSCredentials;
+import rdpclient.ntlmssp.asn1.TSPasswordCreds;
+import rdpclient.ntlmssp.asn1.TSRequest;
+import rdpclient.rdp.RdpConstants;
+import streamer.ByteBuffer;
+import streamer.Element;
+import streamer.Link;
+import streamer.OneTimeSwitch;
+
+public class ClientNtlmsspUserCredentials extends OneTimeSwitch implements Element {
+
+    protected NtlmState ntlmState;
+
+    public ClientNtlmsspUserCredentials(String id, NtlmState ntlmState) {
+        super(id);
+        this.ntlmState = ntlmState;
+    }
+
+    @Override
+    protected void handleOneTimeData(ByteBuffer buf, Link link) {
+        if (buf == null)
+            return;
+
+        throw new RuntimeException("Unexpected packet: " + buf + ".");
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+
+        ByteBuffer buf = new ByteBuffer(4096, true);
+
+        TSRequest tsRequest = new TSRequest("TSRequest");
+        tsRequest.version.value = 2L;
+
+        ByteBuffer tsCredentialsBuf = generateTSCredentials();
+        tsRequest.authInfo.value = encryptTSCredentials(tsCredentialsBuf);
+        tsCredentialsBuf.unref();
+
+        tsRequest.writeTag(buf);
+
+        // Trim buffer to actual length of data written
+        buf.trimAtCursor();
+
+        pushDataToOTOut(buf);
+
+        switchOff();
+    }
+
+    private ByteBuffer encryptTSCredentials(ByteBuffer buf2) {
+        return new ByteBuffer(ntlmState.ntlm_EncryptMessage(buf2.toByteArray()));
+    }
+
+    private ByteBuffer generateTSCredentials() {
+        ByteBuffer buf = new ByteBuffer(4096);
+
+        TSCredentials tsCredentials = new TSCredentials("authInfo");
+        // 1 means that credentials field contains a TSPasswordCreds structure
+        tsCredentials.credType.value = 1L;
+
+        ByteBuffer tsPasswordCredsBuf = new ByteBuffer(4096, true);
+        TSPasswordCreds tsPasswordCreds = new TSPasswordCreds("credentials");
+        tsPasswordCreds.domainName.value = new ByteBuffer(ntlmState.domain.getBytes(RdpConstants.CHARSET_16));
+        tsPasswordCreds.userName.value = new ByteBuffer(ntlmState.user.getBytes(RdpConstants.CHARSET_16));
+        tsPasswordCreds.password.value = new ByteBuffer(ntlmState.password.getBytes(RdpConstants.CHARSET_16));
+        tsPasswordCreds.writeTag(tsPasswordCredsBuf);
+        tsPasswordCredsBuf.trimAtCursor();
+        //* DEBUG */System.out.println("TSPasswordCreds:\n" + tsPasswordCredsBuf.dump());
+
+        tsCredentials.credentials.value = tsPasswordCredsBuf;
+
+        tsCredentials.writeTag(buf);
+        tsPasswordCredsBuf.unref();
+
+        // Trim buffer to actual length of data written
+        buf.trimAtCursor();
+        //* DEBUG */System.out.println("TSCredentials:\n" + buf.dump());
+
+        return buf;
+    }
+
+    /**
+     * @param args
+     */
+    public static void main(String[] args) {
+        // TODO Auto-generated method stub
+
+        /* @formatter:off */
+        // TSCredentials
+//  30 57 // Sequence
+//  a0 03 // TAG 0
+//  02 01 01 // Integer: 1 : credentials contains a TSPasswordCreds structure
+//  a1 50 // TAG 1
+//  04 4e // OCTETSTRING
+        // TSPasswordCreds
+//  30 4c // SEQUENCE
+//  a0 14 // TAG 0
+//  04 12 // OCTETSTRING
+//  77 00 6f 00 72 00 6b 00 67 00 72 00 6f 00 75 00 70 00 // "workgroup"
+//  a1 1c // TAG 1
+//  04 1a // OCTETSTRING
+//  41 00 64 00 6d 00 69 00 6e 00 69 00 73 00 74 00 72 00 61 00 74 00 6f 00 72 00 // "Administrator"
+//  a2 16 // TAG 2
+//  04 14 //
+//  52 00 32 00 50 00 72 00 65 00 76 00 69 00 65 00 77 00 21 00 // "R2Preview!"
+        /* @formatter:on */
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/48c47101/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ntlmssp/CryptoAlgos.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ntlmssp/CryptoAlgos.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ntlmssp/CryptoAlgos.java
new file mode 100755
index 0000000..d0e72e9
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ntlmssp/CryptoAlgos.java
@@ -0,0 +1,361 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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 rdpclient.ntlmssp;
+
+import java.lang.reflect.Method;
+import java.security.Key;
+import java.security.MessageDigest;
+import java.security.SecureRandom;
+import java.util.Arrays;
+
+import javax.crypto.Cipher;
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+
+import rdpclient.rdp.RdpConstants;
+
+/**
+ * @see http://msdn.microsoft.com/en-us/library/cc236717.aspx
+ */
+public class CryptoAlgos implements NtlmConstants {
+
+    /**
+     * Indicates the left-to-right concatenation of the string parameters, from
+     * the first string to the Nnth. Any numbers are converted to strings and all
+     * numeric conversions to strings retain all digits, even nonsignificant ones.
+     * The result is a string. For example, ConcatenationOf(0x00122, "XYZ",
+     * "Client") results in the string "00122XYZClient."
+     */
+    public static String concatenationOf(String... args) {
+        StringBuffer sb = new StringBuffer();
+        for (String arg : args) {
+            sb.append(arg);
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Concatenate byte arrays.
+     */
+    public static byte[] concatenationOf(byte[]... arrays) {
+        int length = 0;
+        for (byte[] array : arrays) {
+            length += array.length;
+        }
+
+        byte[] result = new byte[length];
+        int destPos = 0;
+        for (byte[] array : arrays) {
+            System.arraycopy(array, 0, result, destPos, array.length);
+            destPos += array.length;
+        }
+
+        return result;
+    }
+
+    /** Indicates a 32-bit CRC calculated over m. */
+    public static byte[] CRC32(byte[] m) {
+        throw new RuntimeException("FATAL: Not implemented.");
+    }
+
+    /**
+     * Indicates the encryption of an 8-byte data item d with the 7-byte key k
+     * using the Data Encryption Standard (DES) algorithm in Electronic Codebook
+     * (ECB) mode. The result is 8 bytes in length ([FIPS46-2]).
+     */
+    public static byte[] DES(byte[] k, byte[] d) {
+        throw new RuntimeException("FATAL: Not implemented.");
+    }
+
+    /**
+     * Indicates the encryption of an 8-byte data item D with the 16-byte key K
+     * using the Data Encryption Standard Long (DESL) algorithm. The result is 24
+     * bytes in length. DESL(K, D) is computed as follows.
+     *
+     * <pre>
+     *   ConcatenationOf( DES(K[0..6], D),
+     *     DES(K[7..13], D), DES(
+     *       ConcatenationOf(K[14..15], Z(5)), D));
+     * </pre>
+     *
+     * Note K[] implies a key represented as a character array.
+     */
+    public static byte[] DESL(byte[] k, byte[] d) {
+        throw new RuntimeException("FATAL: Not implemented.");
+    }
+
+    /**
+     * An auxiliary function that returns an operating system version-specific
+     * value (section 2.2.2.8).
+     */
+    public static byte[] getVersion() {
+        // Version (6.1, Build 7601), NTLM current revision: 15
+        return new byte[] {0x06, 0x01, (byte)0xb1, 0x1d, 0x00, 0x00, 0x00, 0x0f};
+    }
+
+    /**
+     * Retrieve the user's LM response key from the server database (directory or
+     * local database).
+     */
+    public static byte[] LMGETKEY(byte[] u, byte[] d) {
+        throw new RuntimeException("FATAL: Not implemented.");
+    }
+
+    /** Retrieve the user's NT response key from the server database. */
+    public static byte[] NTGETKEY(byte[] u, byte[] d) {
+        throw new RuntimeException("FATAL: Not implemented.");
+    }
+
+    /**
+     * Indicates the encryption of data item m with the key k using the HMAC
+     * algorithm ([RFC2104]).
+     */
+    public static byte[] HMAC(byte[] k, byte[] m) {
+        throw new RuntimeException("FATAL: Not implemented.");
+    }
+
+    /**
+     * Indicates the computation of a 16-byte HMAC-keyed MD5 message digest of the
+     * byte string m using the key k.
+     */
+    public static byte[] HMAC_MD5(byte[] k, byte[] m) {
+        try {
+            String algorithm = "HMacMD5";
+            Mac hashMac = Mac.getInstance(algorithm);
+
+            Key secretKey = new SecretKeySpec(k, 0, k.length, algorithm);
+            hashMac.init(secretKey);
+            return hashMac.doFinal(m);
+        } catch (Exception e) {
+            throw new RuntimeException("Cannot calculate HMAC-MD5.", e);
+        }
+    }
+
+    /**
+     * Produces a key exchange key from the session base key K, LM response and
+     * server challenge SC as defined in the sections KXKEY, SIGNKEY, and SEALKEY.
+     */
+    public static byte[] KXKEY(byte[] sessionBaseKey/*K, byte[] LM, byte[] SC*/) {
+        // Key eXchange Key is server challenge
+        /* In NTLMv2, KeyExchangeKey is the 128-bit SessionBaseKey */
+        return Arrays.copyOf(sessionBaseKey, sessionBaseKey.length);
+    }
+
+    /**
+     * Computes a one-way function of the user's password to use as the response
+     * key. NTLM v1 and NTLM v2 define separate LMOWF() functions in the NTLM v1
+     * authentication and NTLM v2 authentication sections, respectively.
+     */
+    public static byte[] LMOWF() {
+        throw new RuntimeException("FATAL: Not implemented.");
+    }
+
+    /**
+     * Indicates the computation of an MD4 message digest of the null-terminated
+     * byte string m ([RFC1320]).
+     */
+    public static byte[] MD4(byte[] m) {
+        try {
+            return sun.security.provider.MD4.getInstance().digest(m);
+        } catch (Exception e) {
+            throw new RuntimeException("Cannot calculate MD5.", e);
+        }
+    }
+
+    /**
+     * Indicates the computation of an MD5 message digest of the null-terminated
+     * byte string m ([RFC1321]).
+     */
+    public static byte[] MD5(byte[] m) {
+        try {
+            return MessageDigest.getInstance("MD5").digest(m);
+        } catch (Exception e) {
+            throw new RuntimeException("Cannot calculate MD5.", e);
+        }
+    }
+
+    /**
+     * Indicates the computation of an MD5 message digest of a binary blob
+     * ([RFC4121] section 4.1.1.2).
+     */
+    public static byte[] MD5_HASH(byte[] m) {
+        try {
+            return MessageDigest.getInstance("MD5").digest(m);
+        } catch (Exception e) {
+            throw new RuntimeException("Cannot calculate MD5.", e);
+        }
+    }
+
+    /** A zero-length string. */
+    public static final String NIL = "";
+
+    /**
+     * Indicates the computation of an n-byte cryptographic-strength random
+     * number.
+     *
+     * Note The NTLM Authentication Protocol does not define the statistical
+     * properties of the random number generator. It is left to the discretion of
+     * the implementation to define the strength requirements of the NONCE(n)
+     * operation.
+     */
+    public static byte[] NONCE(int n) {
+        // Generate random nonce for LMv2 and NTv2 responses
+        byte[] nonce = new byte[n];
+        SecureRandom random = new SecureRandom();
+        random.nextBytes(nonce);
+
+        // Fixed nonce for debugging purposes
+        //* DEBUG */for (int i = 0; i < N; i++) nonce[i] = (byte) (i + 1);
+
+        return nonce;
+    }
+
+    /**
+     * Computes a one-way function of the user's password to use as the response
+     * key. NTLM v1 and NTLM v2 define separate NTOWF() functions in the NTLM v1
+     * authentication and NTLM v2 authentication sections, respectively.
+     */
+    public static byte[] NTOWF() {
+        throw new RuntimeException("FATAL: Not implemented.");
+    }
+
+    /**
+     * The RC4 Encryption Algorithm. To obtain this stream cipher that is licensed
+     * by RSA Data Security, Inc., contact this company.
+     *
+     * Indicates the encryption of data item d with the current session or message
+     * key state, using the RC4 algorithm. h is the handle to a key state
+     * structure initialized by RC4INIT.
+     */
+    public static byte[] RC4(Cipher h, byte[] d) {
+        return h.update(d);
+    }
+
+    /**
+     * Indicates the encryption of data item d with the key k using the RC4
+     * algorithm.
+     *
+     * Note The key sizes for RC4 encryption in NTLM are defined in sections
+     * KXKEY, SIGNKEY, and SEALKEY, where they are created.
+     */
+    public static byte[] RC4K(byte[] k, byte[] d) {
+        try {
+            Cipher cipher = Cipher.getInstance("RC4");
+            Key key = new SecretKeySpec(k, "RC4");
+            cipher.init(Cipher.ENCRYPT_MODE, key);
+            return cipher.doFinal(d);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Initialization of the RC4 key and handle to a key state structure for the
+     * session.
+     */
+    public static Cipher RC4Init(byte[] k) {
+        throw new RuntimeException("FATAL: Not implemented.");
+    }
+
+    /**
+     * Produces an encryption key from the session key as defined in sections
+     * KXKEY, SIGNKEY, and SEALKEY.
+     */
+    public static byte[] SEALKEY(byte[] f, byte[] k, byte[] string1) {
+        throw new RuntimeException("FATAL: Not implemented.");
+    }
+
+    /**
+     * Produces a signing key from the session key as defined in sections KXKEY,
+     * SIGNKEY, and SEALKEY.
+     */
+    public static byte[] SIGNKEY(int flag, byte[] k, byte[] string1) {
+        throw new RuntimeException("FATAL: Not implemented.");
+    }
+
+    /**
+     * Indicates the retrieval of the current time as a 64-bit value, represented
+     * as the number of 100-nanosecond ticks elapsed since midnight of January
+     * 1st, 1601 (UTC).
+     */
+    public static byte[] Currenttime() {
+        // (current time + milliseconds from 1.01.1601 to 1.01.1970) *
+        // 100-nanosecond ticks
+        long time = (System.currentTimeMillis() + 11644473600000L) * 10000;
+
+        // Convert 64bit value to byte array.
+        byte[] result = new byte[8];
+        for (int i = 0; i < 8; i++, time >>>= 8) {
+            result[i] = (byte)time;
+        }
+
+        return result;
+    }
+
+    /**
+     * Indicates the 2-byte little-endian byte order encoding of the Unicode
+     * UTF-16 representation of string. The Byte Order Mark (BOM) is not sent over
+     * the wire.
+     */
+    public static byte[] UNICODE(String string) {
+        return string.getBytes(RdpConstants.CHARSET_16);
+    }
+
+    /** Indicates the uppercase representation of string. */
+    public static String UpperCase(String string) {
+        return string.toUpperCase();
+    }
+
+    /**
+     * Indicates the creation of a byte array of length N. Each byte in the array
+     * is initialized to the value zero.
+     */
+    public static byte[] Z(int n) {
+        return new byte[n];
+    }
+
+    public static Cipher initRC4(byte[] key) {
+        try {
+            Cipher cipher = Cipher.getInstance("RC4");
+            cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "RC4"));
+            return cipher;
+        } catch (Exception e) {
+            throw new RuntimeException("Cannot initialize RC4 sealing handle with client sealing key.", e);
+        }
+    }
+
+    /**
+     * Helper method for embedded test cases.
+     */
+    public static void callAll(Object obj) {
+        Method[] methods = obj.getClass().getDeclaredMethods();
+        for (Method m : methods) {
+            if (m.getName().startsWith("test")) {
+                try {
+                    m.invoke(obj, (Object[])null);
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+    public static void main(String args[]) {
+        callAll(new CryptoAlgos());
+    }
+
+}