CLOUDSTACK-5344: Updated to allow rdp console to access hyper-v vm virtual framebuffer.

This commit is contained in:
Donal Lafferty 2013-11-27 14:38:51 +00:00 committed by Devdeep Singh
parent 97ede2524c
commit 48c47101aa
168 changed files with 16764 additions and 7116 deletions

44
services/console-proxy-rdp/rdpconsole/README.txt Normal file → Executable file
View File

@ -14,28 +14,38 @@
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
This project contains code for basic VNC and RDP clients.
This project contains code for basic VNC, RDP, and HyperV (RDP) clients.
VNC client can be invoked using following command:
Usage:
java common.Client vnc|rdp|hyperv OPTIONS
mvn exec:java -Dexec.mainClass="common.Client" -Dexec.args="vnc 192.168.0.101 5901 password"
Common options:
--help|-h Show this help text.
--debug-link|-DL Print debugging messages when packets are trasnferred via links.
--debug-element|-DE Print debugging messages when packets are received or sended by elements.
--debug-pipeline|-DP Print debugging messages in pipelines.
--host|-n|--host-name VALUE Name or IP address of host to connect to. Required.
--width|-W VALUE Width of canvas. Default value is "1024".
--height|-H VALUE Height of canvas. Default value is "768".
where
* vnc - name of protcol;
* 192.168.0.101 - IP of VNC server;
* 5901 - port of VNC server screen (5900+display number);
* password - VNC server password.
VNC options:
--port|-p VALUE Port of VNC display server to connect to. Calculate as 5900 + display number, e.g. 5900 for display #0, 5901 for display #1, and so on. Default value is "5901".
--password|-P VALUE Password to use. Required.
RDP options:
--ssl-implementation|-j jre|apr|bco Select SSL engine to use: JRE standard implementation, Apache Portable Runtime native library, BonuncyCastle.org implementation. Default value is "apr".
--port|-p VALUE Port of RDP server to connect to. Default value is "3389".
--domain|-D VALUE NTLM domain to login into. Default value is "Workgroup".
--user|-U VALUE User name to use. Default value is "Administrator".
--password|-P VALUE Password to use. If omitted, then login screen will be shown.
RDP client can be invoked using following command:
mvn exec:java -Dexec.mainClass="common.Client" -Dexec.args="rdp 192.168.0.101 3389 Administrator"
where
* rdp - name of protcol;
* 192.168.0.101 - IP of RDP server;
* 3389 - port of RDP server;
* Administrator - user name for loging dialog.
HyperV options:
--ssl-implementation|-j jre|apr|bco Select SSL engine to use: JRE standard implementation, Apache Portable Runtime native library, BonuncyCastle.org implementation. Default value is "apr".
--port|-p VALUE Port of HyperV server to connect to. Default value is "2179".
--instance|-i VALUE HyperV instance ID to use. Required.
--domain|-D VALUE NTLM domain to login into. Default value is "Workgroup".
--user|-U VALUE User name to use. Default value is "Administrator".
--password|-P VALUE Password to use. Required.
Limitations of VNC client:

9
services/console-proxy-rdp/rdpconsole/pom.xml Normal file → Executable file
View File

@ -61,11 +61,18 @@
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<!-- Apache Portable Runtime implementation of SSL protocol, which is compatible with broken MS RDP SSL suport.
NOTE: tomcat-native package with /usr/lib/libtcnative-1.so library is necessary for APR to work. -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>7.0.30</version>
<scope>test</scope>
</dependency>
<!-- Another implementation of SSL protocol. Does not work with broken MS RDP SSL too. -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk16</artifactId>
<version>1.46</version>
</dependency>
</dependencies>
</project>

2
services/console-proxy-rdp/rdpconsole/rdp-config.bat Normal file → Executable file
View File

@ -16,7 +16,7 @@ rem specific language governing permissions and limitations
rem under the License.
rem
rem Configure and start RDP service.
rem Configure and start RDP service. Run this script on RDP server.
rem
rem Turn off firewall

View File

@ -40,7 +40,8 @@ public class BitmapOrder extends Order {
@Override
public String toString() {
final int maxLen = 10;
return String.format("BitmapUpdateOrder [rectangles=%s]", rectangles != null ? Arrays.asList(rectangles).subList(0, Math.min(rectangles.length, maxLen)) : null);
return String.format("BitmapUpdateOrder [rectangles=%s]", rectangles != null ? Arrays.asList(rectangles).subList(0, Math.min(rectangles.length, maxLen))
: null);
}
}

View File

@ -65,8 +65,10 @@ public class BitmapRectangle {
@Override
public String toString() {
return String.format("BitmapUpdateRectangle [x=%s, y=%s, width=%s, height=%s, bitsPerPixel=%s, bitmapDataStream=%s]", x, y, width, height, colorDepth,
bitmapDataStream);
return String
.format(
"BitmapUpdateRectangle [x=%s, y=%s, width=%s, height=%s, bitsPerPixel=%s, bitmapDataStream=%s]",
x, y, width, height, colorDepth, bitmapDataStream);
}
}

View File

@ -49,7 +49,7 @@ public class BufferedImageCanvas extends Canvas {
}
public void setCanvasSize(int width, int height) {
this.offlineImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
offlineImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
graphics = offlineImage.createGraphics();
setSize(offlineImage.getWidth(), offlineImage.getHeight());

View File

@ -81,23 +81,23 @@ public class BufferedImageCopyRectAdapter extends BaseElement {
Element renderer = new BufferedImageCopyRectAdapter("renderer", canvas);
int[] pixelsBeforeCopy = new int[] {
// 0
1, 2, 3, 4,
// 1
5, 6, 7, 8,
// 2
9, 10, 11, 12,
// 3
13, 14, 15, 16};
// 0
1, 2, 3, 4,
// 1
5, 6, 7, 8,
// 2
9, 10, 11, 12,
// 3
13, 14, 15, 16};
int[] pixelsAfterCopy = new int[] {
// 0
11, 12, 3, 4,
// 1
15, 16, 7, 8,
// 2
9, 10, 11, 12,
// 3
13, 14, 15, 16};
// 0
11, 12, 3, 4,
// 1
15, 16, 7, 8,
// 2
9, 10, 11, 12,
// 3
13, 14, 15, 16};
// Initalize image
int[] data = ((DataBufferInt)canvas.getOfflineImage().getRaster().getDataBuffer()).getData();

View File

@ -82,32 +82,32 @@ public class BufferedImagePixelsAdapter extends BaseElement {
switch (dataBuf.getDataType()) {
case DataBuffer.TYPE_INT: {
case DataBuffer.TYPE_INT: {
// Convert array of bytes to array of int's
int[] intArray = buf.toIntLEArray();
// Convert array of bytes to array of int's
int[] intArray = buf.toIntLEArray();
// We chose RGB888 model, so Raster will use DataBufferInt type
DataBufferInt dataBuffer = (DataBufferInt)dataBuf;
// We chose RGB888 model, so Raster will use DataBufferInt type
DataBufferInt dataBuffer = (DataBufferInt)dataBuf;
int imageWidth = image.getWidth();
int imageHeight = image.getHeight();
int imageWidth = image.getWidth();
int imageHeight = image.getHeight();
// Paint rectangle directly on buffer, line by line
int[] imageBuffer = dataBuffer.getData();
// Paint rectangle directly on buffer, line by line
int[] imageBuffer = dataBuffer.getData();
for (int srcLine = 0, dstLine = y; srcLine < rectHeight && dstLine < imageHeight; srcLine++, dstLine++) {
try {
System.arraycopy(intArray, srcLine * rectWidth, imageBuffer, x + dstLine * imageWidth, rectWidth);
} catch (IndexOutOfBoundsException e) {
}
for (int srcLine = 0, dstLine = y; srcLine < rectHeight && dstLine < imageHeight; srcLine++, dstLine++) {
try {
System.arraycopy(intArray, srcLine * rectWidth, imageBuffer, x + dstLine * imageWidth, rectWidth);
} catch (IndexOutOfBoundsException e) {
}
break;
}
break;
}
default:
throw new RuntimeException("Unsupported data buffer in buffered image: expected data buffer of type int (DataBufferInt). Actual data buffer type: " +
dataBuf.getClass().getSimpleName());
default:
throw new RuntimeException("Unsupported data buffer in buffered image: expected data buffer of type int (DataBufferInt). Actual data buffer type: "
+ dataBuf.getClass().getSimpleName());
}
// Request update of repainted area
@ -123,13 +123,11 @@ public class BufferedImagePixelsAdapter extends BaseElement {
Element renderer = new BufferedImagePixelsAdapter("renderer", canvas);
byte[] pixels =
new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
byte[] pixels = new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1, 2, 3, 4, 5,
6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
int[] pixelsLE =
new int[] {0x04030201, 0x08070605, 0x0c0b0a09, 0x100f0e0d, 0x04030201, 0x08070605, 0x0c0b0a09, 0x100f0e0d, 0x04030201, 0x08070605, 0x0c0b0a09, 0x100f0e0d,
0x04030201, 0x08070605, 0x0c0b0a09, 0x100f0e0d};
int[] pixelsLE = new int[] {0x04030201, 0x08070605, 0x0c0b0a09, 0x100f0e0d, 0x04030201, 0x08070605, 0x0c0b0a09, 0x100f0e0d, 0x04030201, 0x08070605,
0x0c0b0a09, 0x100f0e0d, 0x04030201, 0x08070605, 0x0c0b0a09, 0x100f0e0d};
ByteBuffer buf = new ByteBuffer(pixels);
buf.putMetadata(TARGET_X, 0);

View File

@ -22,46 +22,216 @@ import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.net.InetSocketAddress;
import java.util.Arrays;
import rdpclient.RdpClient;
import streamer.Element;
import streamer.Pipeline;
import streamer.PipelineImpl;
import streamer.SocketWrapper;
import streamer.SocketWrapperImpl;
import streamer.apr.AprSocketWrapperImpl;
import streamer.bco.BcoSocketWrapperImpl;
import streamer.ssl.SSLState;
import vncclient.VncClient;
import common.opt.IntOption;
import common.opt.Option;
import common.opt.OptionParser;
import common.opt.StringEnumerationOption;
import common.opt.StringOption;
public class Client {
enum Protocol {
NONE, VNC, RDP, HYPERV
}
// Common options
private Option help = new Option() {
{
name = "--help";
alias = "-h";
description = "Show this help text.";
}
};
private Option debugLink = new Option() {
{
name = "--debug-link";
alias = "-DL";
description = "Print debugging messages when packets are trasnferred via links.";
}
};
private Option debugElement = new Option() {
{
name = "--debug-element";
alias = "-DE";
description = "Print debugging messages when packets are received or sended by elements.";
}
};
private Option debugPipeline = new Option() {
{
name = "--debug-pipeline";
alias = "-DP";
description = "Print debugging messages in pipelines.";
}
};
private StringOption hostName = new StringOption() {
{
name = "--host";
alias = "-n";
aliases = new String[] {"--host-name"};
required = true;
description = "Name or IP address of host to connect to.";
}
};
private IntOption canvasWidth = new IntOption() {
{
name = "--width";
alias = "-W";
value = 1024;
description = "Width of canvas.";
}
};
private IntOption canvasHeight = new IntOption() {
{
name = "--height";
alias = "-H";
value = 768;
description = "Height of canvas.";
}
};
// Protocol specific options
private IntOption vncPort = new IntOption() {
{
name = "--port";
alias = "-p";
value = 5901;
description = "Port of VNC display server to connect to. Calculate as 5900 + display number, e.g. 5900 for display #0, 5901 for display #1, and so on.";
}
};
private IntOption rdpPort = new IntOption() {
{
name = "--port";
alias = "-p";
value = 3389;
description = "Port of RDP server to connect to.";
}
};
private IntOption hyperVPort = new IntOption() {
{
name = "--port";
alias = "-p";
value = 2179;
description = "Port of HyperV server to connect to.";
}
};
private StringOption password = new StringOption() {
{
name = "--password";
alias = "-P";
required = true;
description = "Password to use.";
}
};
private StringOption rdpPassword = new StringOption() {
{
name = "--password";
alias = "-P";
required = false;
description = "Password to use. If omitted, then login screen will be shown.";
}
};
private StringOption userName = new StringOption() {
{
name = "--user";
alias = "-U";
value = "Administrator";
description = "User name to use.";
}
};
private StringOption domain = new StringOption() {
{
name = "--domain";
alias = "-D";
value = "Workgroup";
description = "NTLM domain to login into.";
}
};
private StringOption hyperVInstanceId = new StringOption() {
{
name = "--instance";
alias = "-i";
required = true;
description = "HyperV instance ID to use.";
}
};
private StringEnumerationOption sslImplementation = new StringEnumerationOption() {
{
name = "--ssl-implementation";
alias = "-j";
value = "apr";
choices = new String[] {"jre", "apr", "bco"};
description = "Select SSL engine to use: JRE standard implementation, Apache Portable Runtime native library, BonuncyCastle.org implementation.";
}
};
private final Option[] commonOptions = new Option[] {help, debugLink, debugElement, debugPipeline, hostName, canvasWidth, canvasHeight};
private final Option[] vncOptions = new Option[] {vncPort, password};
private final Option[] rdpOptions = new Option[] {sslImplementation, rdpPort, domain, userName, rdpPassword};
private final Option[] hyperVOptions = new Option[] {sslImplementation, hyperVPort, hyperVInstanceId, domain, userName, password};
private static Frame frame;
private static SocketWrapper socket;
private static ScrollPane scroller;
private static ScreenDescription screen;
private static BufferedImageCanvas canvas;
public static void main(String args[]) {
// System.setProperty("streamer.Link.debug", "true");
// System.setProperty("streamer.Element.debug", "true");
// System.setProperty("streamer.Pipeline.debug", "true");
private void help() {
System.out.println("Usage: \n java common.Client vnc|rdp|hyperv OPTIONS\n");
System.out.println(Option.toHelp("Common options", commonOptions));
System.out.println(Option.toHelp("VNC options", vncOptions));
System.out.println(Option.toHelp("RDP options", rdpOptions));
System.out.println(Option.toHelp("HyperV options", hyperVOptions));
}
public void runClient(String[] args) {
try {
if (args.length < 4) {
System.out.println("Usage: \n java common.Client vnc IP PORT PASSWORD\n java common.Client rdp IP PORT username\n");
System.exit(0);
}
String connectionType = args[0];
String hostname = args[1];
int port = Integer.parseInt(args[2]);
String userNameOrPassword = args[3];
Protocol protocol = parseOptions(args);
if (protocol == Protocol.NONE)
return;
// Create address from arguments
InetSocketAddress address = new InetSocketAddress(hostname, port);
System.setProperty("streamer.Link.debug", "" + debugLink.used);
System.setProperty("streamer.Element.debug", "" + debugElement.used);
System.setProperty("streamer.Pipeline.debug", "" + debugPipeline.used);
SSLState sslState = new SSLState();
// Create socket wrapper
socket = new SocketWrapper("socket");
if ("jre".equals(sslImplementation.value)) {
socket = new SocketWrapperImpl("socket", sslState);
} else if ("apr".equals(sslImplementation.value)) {
socket = new AprSocketWrapperImpl("socket", sslState);
} else if ("bco".equals(sslImplementation.value)) {
socket = new BcoSocketWrapperImpl("socket", sslState);
} else {
throw new RuntimeException("Unexpected option value: \"" + sslImplementation.value + "\". " + sslImplementation.help());
}
screen = new ScreenDescription();
canvas = new BufferedImageCanvas(1024, 768);
canvas = new BufferedImageCanvas(canvasWidth.value, canvasHeight.value);
screen.addSizeChangeListener(new SizeChangeListener() {
@Override
public void sizeChanged(int width, int height) {
@ -74,13 +244,24 @@ public class Client {
});
// Assemble pipeline
InetSocketAddress address;
Element main;
if ("vnc".equals(connectionType)) {
main = new VncClient("client", userNameOrPassword, screen, canvas);
} else if ("rdp".equals(connectionType)) {
main = new RdpClient("client", userNameOrPassword, screen, canvas);
} else {
throw new RuntimeException("Unknown connection type. Expected value: \"vnc\" or \"rdp\", actual value: \"" + connectionType + "\".");
switch (protocol) {
case VNC:
address = new InetSocketAddress(hostName.value, vncPort.value);
main = new VncClient("client", password.value, screen, canvas);
break;
case RDP:
address = new InetSocketAddress(hostName.value, rdpPort.value);
main = new RdpClient("client", hostName.value, domain.value, userName.value, rdpPassword.value, null, screen, canvas, sslState);
break;
case HYPERV:
address = new InetSocketAddress(hostName.value, hyperVPort.value);
main = new RdpClient("client", hostName.value, domain.value, userName.value, password.value, hyperVInstanceId.value, screen, canvas, sslState);
break;
default:
address = null;
main = null;
}
Pipeline pipeline = new PipelineImpl("Client");
@ -89,7 +270,7 @@ public class Client {
pipeline.validate();
frame = createVncClientMainWindow(canvas, "VNC", new WindowAdapter() {
frame = createVncClientMainWindow(canvas, protocol.toString() + " " + hostName.value, new WindowAdapter() {
@Override
public void windowClosing(WindowEvent evt) {
shutdown();
@ -108,6 +289,41 @@ public class Client {
}
}
private Protocol parseOptions(String[] args) {
String protocolName = (args.length > 0) ? args[0] : "";
Protocol protocol = Protocol.NONE;
Option[] options;
if (protocolName.equals("vnc")) {
protocol = Protocol.VNC;
options = join(commonOptions, vncOptions);
} else if (protocolName.equals("rdp")) {
protocol = Protocol.RDP;
options = join(commonOptions, rdpOptions);
} else if (protocolName.equals("hyperv")) {
protocol = Protocol.HYPERV;
options = join(commonOptions, hyperVOptions);
} else {
help();
return Protocol.NONE;
}
// Parse all options for given protocol
String[] arguments = OptionParser.parseOptions(args, 1, options);
if (arguments.length > 0) {
System.err.println("[Client] ERROR: Arguments are not allowed here. Check command syntax. Extra arguments: \"" + Arrays.toString(arguments) + "\".");
help();
return Protocol.NONE;
}
if (help.used) {
help();
return Protocol.NONE;
}
return protocol;
}
protected static void shutdown() {
if (frame != null) {
frame.setVisible(false);
@ -135,4 +351,25 @@ public class Client {
return frame;
}
/**
* Join two arrays with options and return new array.
*/
private Option[] join(Option[] a1, Option[] a2) {
// Extend first array
Option[] result = Arrays.copyOf(a1, a1.length + a2.length);
// Append second array to first
for (int i = 0, p = a1.length; i < a2.length; i++, p++)
result[p] = a2[i];
return result;
}
public static void main(String args[]) {
// *DEBUG*/System.setProperty("javax.net.debug", "ssl");
// * DEBUG */System.setProperty("javax.net.debug", "ssl:record:packet");
new Client().runClient(args);
}
}

View File

@ -56,12 +56,12 @@ public class ScreenDescription {
* Store information about server pixel format.
*/
public void setPixelFormat(int bitsPerPixel, int depth, boolean bigEndianFlag, boolean trueColorFlag, int redMax, int greenMax, int blueMax, int redShift,
int greenShift, int blueShift) {
int greenShift, int blueShift) {
this.bytesPerPixel = (bitsPerPixel + 7) / 8;
bytesPerPixel = (bitsPerPixel + 7) / 8;
this.bitsPerPixel = bitsPerPixel;
this.colorDepth = depth;
colorDepth = depth;
this.bigEndianFlag = bigEndianFlag;
this.trueColorFlag = trueColorFlag;
@ -79,23 +79,23 @@ public class ScreenDescription {
public void setPixelFormatRGBTrueColor(int bitsPerPixel) {
switch (bitsPerPixel) {
case 8:
setPixelFormat(8, 8, false, false, -1, -1, -1, -1, -1, -1);
break;
case 15:
setPixelFormat(16, 15, false, true, 31, 31, 31, 0, 5, 10);
break;
case 16:
setPixelFormat(16, 16, false, true, 31, 63, 31, 0, 5, 11);
break;
case 24:
setPixelFormat(24, 24, false, true, 255, 255, 255, 0, 8, 16);
break;
case 32:
setPixelFormat(32, 24, false, true, 255, 255, 255, 0, 8, 16);
break;
default:
throw new RuntimeException("Unknown color depth.");
case 8:
setPixelFormat(8, 8, false, false, -1, -1, -1, -1, -1, -1);
break;
case 15:
setPixelFormat(16, 15, false, true, 31, 31, 31, 0, 5, 10);
break;
case 16:
setPixelFormat(16, 16, false, true, 31, 63, 31, 0, 5, 11);
break;
case 24:
setPixelFormat(24, 24, false, true, 255, 255, 255, 0, 8, 16);
break;
case 32:
setPixelFormat(32, 24, false, true, 255, 255, 255, 0, 8, 16);
break;
default:
throw new RuntimeException("Unknown color depth.");
}
}
@ -107,8 +107,8 @@ public class ScreenDescription {
if (height <= 0 || width <= 0)
throw new RuntimeException("Incorrect framebuffer size: " + width + "x" + height + ".");
this.framebufferWidth = width;
this.framebufferHeight = height;
framebufferWidth = width;
framebufferHeight = height;
callSizeChangeListeners(width, height);
}
@ -145,16 +145,16 @@ public class ScreenDescription {
}
public boolean isRGB888_32_LE() {
return (colorDepth == 24 && bitsPerPixel == 32 && redShift == 0 && greenShift == 8 && blueShift == 16 && redMax == 255 && greenMax == 255 && blueMax == 255 &&
!bigEndianFlag && trueColorFlag);
return (colorDepth == 24 && bitsPerPixel == 32 && redShift == 0 && greenShift == 8 && blueShift == 16 && redMax == 255 && greenMax == 255 && blueMax == 255
&& !bigEndianFlag && trueColorFlag);
}
@Override
public String toString() {
return "ScreenDescription [framebufferWidth=" + framebufferWidth + ", framebufferHeight=" + framebufferHeight + ", desktopName=" + desktopName +
", bytesPerPixel=" + bytesPerPixel + ", depth=" + colorDepth + ", bitsPerPixel=" + bitsPerPixel + ", redShift=" + redShift + ", greenShift=" + greenShift +
", blueShift=" + blueShift + ", redMax=" + redMax + ", greenMax=" + greenMax + ", blueMax=" + blueMax + ", bigEndianFlag=" + bigEndianFlag +
", trueColorFlag=" + trueColorFlag + "]";
return "ScreenDescription [framebufferWidth=" + framebufferWidth + ", framebufferHeight=" + framebufferHeight + ", desktopName=" + desktopName
+ ", bytesPerPixel=" + bytesPerPixel + ", depth=" + colorDepth + ", bitsPerPixel=" + bitsPerPixel + ", redShift=" + redShift + ", greenShift=" + greenShift
+ ", blueShift=" + blueShift + ", redMax=" + redMax + ", greenMax=" + greenMax + ", blueMax=" + blueMax + ", bigEndianFlag=" + bigEndianFlag
+ ", trueColorFlag=" + trueColorFlag + "]";
}
public void addSizeChangeListener(SizeChangeListener sizeChangeListener) {

View File

@ -14,17 +14,17 @@
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package common;
package common.adapter;
import java.awt.Toolkit;
import streamer.BaseElement;
import streamer.ByteBuffer;
import streamer.Element;
import streamer.FakeSource;
import streamer.Link;
import streamer.Pipeline;
import streamer.PipelineImpl;
import streamer.debug.FakeSource;
public class AwtBellAdapter extends BaseElement {
@ -61,9 +61,9 @@ public class AwtBellAdapter extends BaseElement {
Element source = new FakeSource("source") {
{
this.incommingBufLength = 0;
this.delay = 1000;
this.numBuffers = 3;
incommingBufLength = 0;
delay = 1000;
numBuffers = 3;
}
};

View File

@ -14,13 +14,13 @@
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package common;
package common.adapter;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import rdpclient.ServerBitmapUpdate;
import rdpclient.rdp.ServerBitmapUpdate;
import streamer.BaseElement;
import streamer.ByteBuffer;
import streamer.Element;
@ -28,6 +28,12 @@ import streamer.Link;
import streamer.Order;
import streamer.Pipeline;
import streamer.PipelineImpl;
import common.BitmapOrder;
import common.BitmapRectangle;
import common.BufferedImageCanvas;
import common.CopyRectOrder;
import common.OrderType;
import common.ScreenDescription;
public class AwtCanvasAdapter extends BaseElement {
@ -54,17 +60,17 @@ public class AwtCanvasAdapter extends BaseElement {
Order order = buf.getOrder();
switch ((OrderType)order.type) {
case BITMAP_UPDATE:
handleBitmap((BitmapOrder)order, buf);
break;
case BITMAP_UPDATE:
handleBitmap((BitmapOrder)order, buf);
break;
case COPY_RECT:
handleCopyRect((CopyRectOrder)order, buf);
break;
case COPY_RECT:
handleCopyRect((CopyRectOrder)order, buf);
break;
default:
throw new RuntimeException("Order is not implemented: " + buf + ".");
// break;
default:
throw new RuntimeException("Order is not implemented: " + buf + ".");
// break;
}
buf.unref();
@ -98,33 +104,33 @@ public class AwtCanvasAdapter extends BaseElement {
BufferedImage rectImage;
switch (rectangle.colorDepth) {
case 8: {
rectImage = new BufferedImage(bufferWidth, height, BufferedImage.TYPE_BYTE_INDEXED, screen.colorMap);
WritableRaster raster = rectImage.getRaster();
raster.setDataElements(0, 0, bufferWidth, bufferHeight, rectangle.bitmapDataStream.toByteArray());
break;
}
case 15: {
rectImage = new BufferedImage(bufferWidth, height, BufferedImage.TYPE_USHORT_555_RGB);
WritableRaster raster = rectImage.getRaster();
raster.setDataElements(0, 0, bufferWidth, bufferHeight, rectangle.bitmapDataStream.toShortArray());
break;
}
case 16: {
rectImage = new BufferedImage(bufferWidth, height, BufferedImage.TYPE_USHORT_565_RGB);
WritableRaster raster = rectImage.getRaster();
raster.setDataElements(0, 0, bufferWidth, bufferHeight, rectangle.bitmapDataStream.toShortArray());
break;
}
case 24:
case 32: {
rectImage = new BufferedImage(bufferWidth, height, BufferedImage.TYPE_INT_RGB);
WritableRaster raster = rectImage.getRaster();
raster.setDataElements(0, 0, bufferWidth, bufferHeight, rectangle.bitmapDataStream.toIntLEArray());
break;
}
default:
throw new RuntimeException("Unsupported color depth: " + rectangle.colorDepth + ".");
case 8: {
rectImage = new BufferedImage(bufferWidth, height, BufferedImage.TYPE_BYTE_INDEXED, screen.colorMap);
WritableRaster raster = rectImage.getRaster();
raster.setDataElements(0, 0, bufferWidth, bufferHeight, rectangle.bitmapDataStream.toByteArray());
break;
}
case 15: {
rectImage = new BufferedImage(bufferWidth, height, BufferedImage.TYPE_USHORT_555_RGB);
WritableRaster raster = rectImage.getRaster();
raster.setDataElements(0, 0, bufferWidth, bufferHeight, rectangle.bitmapDataStream.toShortArray());
break;
}
case 16: {
rectImage = new BufferedImage(bufferWidth, height, BufferedImage.TYPE_USHORT_565_RGB);
WritableRaster raster = rectImage.getRaster();
raster.setDataElements(0, 0, bufferWidth, bufferHeight, rectangle.bitmapDataStream.toShortArray());
break;
}
case 24:
case 32: {
rectImage = new BufferedImage(bufferWidth, height, BufferedImage.TYPE_INT_RGB);
WritableRaster raster = rectImage.getRaster();
raster.setDataElements(0, 0, bufferWidth, bufferHeight, rectangle.bitmapDataStream.toIntLEArray());
break;
}
default:
throw new RuntimeException("Unsupported color depth: " + rectangle.colorDepth + ".");
}
g.setClip(x, y, width, height);
@ -143,9 +149,8 @@ public class AwtCanvasAdapter extends BaseElement {
// System.setProperty("streamer.Link.debug", "true");
// System.setProperty("streamer.Element.debug", "true");
// System.setProperty("streamer.Pipeline.debug", "true");
ByteBuffer packet =
new ByteBuffer(new byte[] {0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x10, 0x00, 0x01, 0x04, 0x0a,
0x00, 0x0c, (byte)0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
ByteBuffer packet = new ByteBuffer(new byte[] {0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x10, 0x00,
0x01, 0x04, 0x0a, 0x00, 0x0c, (byte)0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
Pipeline pipeline = new PipelineImpl("test");

View File

@ -14,7 +14,7 @@
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package common;
package common.adapter;
import java.awt.Toolkit;
import java.awt.datatransfer.StringSelection;
@ -22,10 +22,11 @@ import java.awt.datatransfer.StringSelection;
import streamer.BaseElement;
import streamer.ByteBuffer;
import streamer.Link;
import vncclient.VncMessageHandler;
public class AwtClipboardAdapter extends BaseElement {
public static final String CLIPBOARD_CONTENT = "content";
public AwtClipboardAdapter(String id) {
super(id);
declarePads();
@ -43,14 +44,14 @@ public class AwtClipboardAdapter extends BaseElement {
if (buf == null)
return;
String content = (String)buf.getMetadata(VncMessageHandler.CLIPBOARD_CONTENT);
String content = (String)buf.getMetadata(CLIPBOARD_CONTENT);
StringSelection contents = new StringSelection(content);
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(contents, null);
}
@Override
public String toString() {
return "Clipboard(" + id + ")";
return "ClipboardAdapter(" + id + ")";
}
}

View File

@ -0,0 +1,78 @@
// 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 common.asn1;
import streamer.ByteBuffer;
/**
* Any type. Don't forget to set type.
*/
public class Any extends Tag {
/**
* Raw bytes of any value.
*/
public ByteBuffer value;
public Any(String name) {
super(name);
}
@Override
public boolean isValueSet() {
return value != null;
}
@Override
public long calculateLengthOfValuePayload() {
return value.length;
}
@Override
public void writeTagValuePayload(ByteBuffer buf) {
buf.writeBytes(value);
}
@Override
public void readTagValue(ByteBuffer buf, BerType typeAndFlags) {
long length = buf.readBerLength();
value = buf.readBytes((int)length);
}
@Override
public Tag deepCopy(String suffix) {
return new Any(name + suffix).copyFrom(this);
}
@Override
public Tag copyFrom(Tag tag) {
super.copyFrom(tag);
tagType = tag.tagType;
value = new ByteBuffer(((Any)tag).value.toByteArray());
return this;
}
@Override
public boolean isTypeValid(BerType typeAndFlags, boolean explicit) {
if (explicit)
return typeAndFlags.tagClass == tagClass && typeAndFlags.constructed && typeAndFlags.typeOrTagNumber == tagNumber;
else
return true;
}
}

View File

@ -0,0 +1,83 @@
// 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 common.asn1;
public interface Asn1Constants {
/**
* Universal class type.
*/
public static final int UNIVERSAL_CLASS = 0x00;
/**
* Application class type.
*/
public static final int APPLICATION_CLASS = 0x40;
public static final int CONTEXT_CLASS = 0x80;
public static final int PRIVATE_CLASS = 0xC0;
/**
* Constructed type.
*/
public static final int CONSTRUCTED = 0x20;
/**
* Mask to extract class.
*/
public static final int CLASS_MASK = 0xC0;
/**
* Mask to extract type.
*/
public static final int TYPE_MASK = 0x1F;
public static final int EOF = 0x00;
public static final int BOOLEAN = 0x01;
/**
* Integer primitive.
*/
public static final int INTEGER = 0x02;
public static final int BIT_STRING = 0x03;
/**
* Octet string primitive.
*/
public static final int OCTET_STRING = 0x04;
public static final int NULL = 0x05;
public static final int OBJECT_ID = 0x06;
public static final int REAL = 0x09;
public static final int ENUMERATED = 0x0A;
/**
* Sequence primitive.
*/
public static final int SEQUENCE = 0x10;
public static final int SET = 0x11;
public static final int NUMERIC_STRING = 0x12;
public static final int PRINTABLE_STRING = 0x13;
public static final int TELETEX_STRING = 0x14;
public static final int VIDEOTEXT_STRING = 0x15;
public static final int IA5_STRING = 0x16;
public static final int UTCTIME = 0x17;
public static final int GENERAL_TIME = 0x18;
public static final int GRAPHIC_STRING = 0x19;
public static final int VISIBLE_STRING = 0x1A;
public static final int GENERAL_STRING = 0x1B;
public static final int EXTENDED_TYPE = 0x1F;
}

View File

@ -0,0 +1,116 @@
// 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 common.asn1;
import streamer.ByteBuffer;
/**
* Variable length integer.
*/
public class Asn1Integer extends Tag {
public Long value = null;
public Asn1Integer(String name) {
super(name);
tagType = INTEGER;
}
@Override
public void readTagValue(ByteBuffer buf, BerType typeAndFlags) {
// Type is already read by parent parser
long length = buf.readBerLength();
if (length > 8)
throw new RuntimeException("[" + this + "] ERROR: Integer value is too long: " + length + " bytes. Cannot handle integers more than 8 bytes long. Data: "
+ buf + ".");
value = buf.readSignedVarInt((int)length);
}
@Override
public Tag deepCopy(String suffix) {
return new Asn1Integer(name + suffix).copyFrom(this);
}
@Override
public Tag copyFrom(Tag tag) {
super.copyFrom(tag);
value = ((Asn1Integer)tag).value;
return this;
}
@Override
public String toString() {
return super.toString() + "= " + value;
}
@Override
public long calculateLengthOfValuePayload() {
if (value <= 0xff)
return 1;
if (value <= 0xffFF)
return 2;
if (value <= 0xffFFff)
return 3;
if (value <= 0xffFFffFFL)
return 4;
if (value <= 0xffFFffFFffL)
return 5;
if (value <= 0xffFFffFFffFFL)
return 6;
if (value <= 0xffFFffFFffFFffL)
return 7;
return 8;
}
@Override
public void writeTagValuePayload(ByteBuffer buf) {
long value = this.value.longValue();
if (value < 0xff) {
buf.writeByte((int)value);
} else if (value <= 0xffFF) {
buf.writeShort((int)value);
} else if (value <= 0xffFFff) {
buf.writeByte((int)(value >> 16));
buf.writeShort((int)value);
} else if (value <= 0xffFFffFFL) {
buf.writeInt((int)value);
} else if (value <= 0xffFFffFFffL) {
buf.writeByte((int)(value >> 32));
buf.writeInt((int)value);
} else if (value <= 0xffFFffFFffFFL) {
buf.writeShort((int)(value >> 32));
buf.writeInt((int)value);
} else if (value <= 0xffFFffFFffFFffL) {
buf.writeByte((int)(value >> (32 + 16)));
buf.writeShort((int)(value >> 32));
buf.writeInt((int)value);
} else {
buf.writeInt((int)(value >> 32));
buf.writeInt((int)value);
}
}
@Override
public boolean isValueSet() {
return value != null;
}
}

View File

@ -0,0 +1,40 @@
// 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 common.asn1;
public class BerType {
public int tagClass;
public boolean constructed;
public int typeOrTagNumber;
public BerType() {
}
public BerType(int tagClass, boolean constructed, int typeOrTagNumber) {
this.tagClass = tagClass;
this.constructed = constructed;
this.typeOrTagNumber = typeOrTagNumber;
}
@Override
public String toString() {
return "BerType [tagClass=" + Tag.tagClassToString(tagClass) + ", constructed=" + constructed + ", type or tag number="
+ Tag.tagTypeOrNumberToString(tagClass, typeOrTagNumber) + "]";
}
}

View File

@ -0,0 +1,67 @@
// 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 common.asn1;
import streamer.ByteBuffer;
public class BitString extends Tag {
/**
* Bit string value.
*/
public ByteBuffer value;
public BitString(String name) {
super(name);
tagType = BIT_STRING;
}
@Override
public boolean isValueSet() {
return value != null;
}
@Override
public long calculateLengthOfValuePayload() {
return value.length;
}
@Override
public void writeTagValuePayload(ByteBuffer buf) {
buf.writeBytes(value);
}
@Override
public void readTagValue(ByteBuffer buf, BerType typeAndFlags) {
long length = buf.readBerLength();
value = buf.readBytes((int)length);
}
@Override
public Tag deepCopy(String suffix) {
return new BitString(name + suffix).copyFrom(this);
}
@Override
public Tag copyFrom(Tag tag) {
super.copyFrom(tag);
value = new ByteBuffer(((BitString)tag).value.toByteArray());
return this;
}
}

View File

@ -0,0 +1,67 @@
// 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 common.asn1;
import streamer.ByteBuffer;
public class ObjectID extends Tag {
/**
* Raw bytes of encoded OID.
*/
public ByteBuffer value;
public ObjectID(String name) {
super(name);
tagType = OBJECT_ID;
}
@Override
public boolean isValueSet() {
return value != null;
}
@Override
public long calculateLengthOfValuePayload() {
return value.length;
}
@Override
public void writeTagValuePayload(ByteBuffer buf) {
buf.writeBytes(value);
}
@Override
public void readTagValue(ByteBuffer buf, BerType typeAndFlags) {
long length = buf.readBerLength();
value = buf.readBytes((int)length);
}
@Override
public Tag deepCopy(String suffix) {
return new ObjectID(name + suffix).copyFrom(this);
}
@Override
public Tag copyFrom(Tag tag) {
super.copyFrom(tag);
value = new ByteBuffer(((ObjectID)tag).value.toByteArray());
return this;
}
}

View File

@ -0,0 +1,80 @@
// 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 common.asn1;
import streamer.ByteBuffer;
public class OctetString extends Tag {
public ByteBuffer value = null;
public OctetString(String name) {
super(name);
tagType = OCTET_STRING;
}
@Override
public void readTagValue(ByteBuffer buf, BerType typeAndFlags) {
// Type is already read by parent parser
long length = buf.readBerLength();
if (length > buf.length)
throw new RuntimeException("BER octet string is too long: " + length + " bytes. Data: " + buf + ".");
value = buf.readBytes((int)length);
}
@Override
public Tag deepCopy(String suffix) {
return new OctetString(name + suffix).copyFrom(this);
}
@Override
public Tag copyFrom(Tag tag) {
super.copyFrom(tag);
value = ((OctetString)tag).value;
return this;
}
@Override
public String toString() {
return super.toString() + "= " + value;
}
@Override
public long calculateLengthOfValuePayload() {
if (value != null)
return value.length;
else
return 0;
}
@Override
public void writeTagValuePayload(ByteBuffer buf) {
if (value != null)
buf.writeBytes(value);
else
return;
}
@Override
public boolean isValueSet() {
return value != null;
}
}

View File

@ -0,0 +1,143 @@
// 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 common.asn1;
import java.util.Arrays;
import streamer.ByteBuffer;
/**
* One or more elements of different types.
*
* Only prefixed tags are supported.
*/
public class Sequence extends Tag {
public Tag[] tags;
public Sequence(String name) {
super(name);
tagType = SEQUENCE;
// Sequence and SequenceOf are always encoded as constructed
constructed = true;
}
@Override
public long calculateLengthOfValuePayload() {
long sum = 0;
for (Tag tag : tags) {
long tagLength = tag.calculateFullLength();
sum += tagLength;
}
return sum;
}
@Override
public void writeTagValuePayload(ByteBuffer buf) {
// Write tags
for (Tag tag : tags) {
tag.writeTag(buf);
}
}
@Override
public void readTagValue(ByteBuffer buf, BerType typeAndFlags) {
// Type is already read by parent parser
long length = buf.readBerLength();
if (length > buf.remainderLength())
throw new RuntimeException("BER sequence is too long: " + length + " bytes, while buffer remainder length is " + buf.remainderLength() + ". Data: " + buf
+ ".");
ByteBuffer value = buf.readBytes((int)length);
parseContent(value);
value.unref();
}
protected void parseContent(ByteBuffer buf) {
for (int i = 0; buf.remainderLength() > 0 && i < tags.length; i++) {
BerType typeAndFlags = readBerType(buf);
// If current tag does not match data in buffer
if (!tags[i].isTypeValid(typeAndFlags)) {
// If tag is required, then throw exception
if (!tags[i].optional) {
throw new RuntimeException("[" + this + "] ERROR: Required tag is missed: " + tags[i] + ". Unexected tag type: " + typeAndFlags + ". Data: " + buf
+ ".");
} else {
// One or more tags are omitted, so skip them
for (; i < tags.length; i++) {
if (tags[i].isTypeValid(typeAndFlags)) {
break;
}
}
if (i >= tags.length || !tags[i].isTypeValid(typeAndFlags)) {
throw new RuntimeException("[" + this + "] ERROR: No more tags to read or skip, but some data still left in buffer. Unexected tag type: "
+ typeAndFlags + ". Data: " + buf + ".");
}
}
}
tags[i].readTag(buf, typeAndFlags);
}
}
@Override
public boolean isTypeValid(BerType typeAndFlags, boolean explicit) {
if (explicit)
return typeAndFlags.tagClass == tagClass && typeAndFlags.constructed && typeAndFlags.typeOrTagNumber == tagNumber;
else
// Sequences are always encoded as "constructed" in BER.
return typeAndFlags.tagClass == UNIVERSAL_CLASS && typeAndFlags.constructed && typeAndFlags.typeOrTagNumber == SEQUENCE;
}
@Override
public Tag deepCopy(String suffix) {
return new Sequence(name + suffix).copyFrom(this);
}
@Override
public Tag copyFrom(Tag tag) {
super.copyFrom(tag);
if (tags.length != ((Sequence)tag).tags.length)
throw new RuntimeException("Incompatible sequences. This: " + this + ", another: " + tag + ".");
for (int i = 0; i < tags.length; i++) {
tags[i].copyFrom(((Sequence)tag).tags[i]);
}
return this;
}
@Override
public String toString() {
return super.toString() + "{" + Arrays.toString(tags) + " }";
}
@Override
public boolean isValueSet() {
return tags != null;
}
}

View File

@ -0,0 +1,82 @@
// 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 common.asn1;
import java.util.ArrayList;
import streamer.ByteBuffer;
/**
* Zero or more elements of same type (array).
*/
public class SequenceOf extends Sequence {
/**
* Type of this array.
*/
public Tag type;
/* Values are stored in tags[] variable inherited from Sequence. */
public SequenceOf(String name) {
super(name);
}
@Override
protected void parseContent(ByteBuffer buf) {
ArrayList<Tag> tagList = new ArrayList<Tag>();
for (int index = 0; buf.remainderLength() > 0; index++) {
// End of array is marked with two zero bytes (0x00 0x00)
if (buf.peekUnsignedByte(0) == 0x00 && buf.peekUnsignedByte(1) == 0x00) {
break;
}
Tag tag = type.deepCopy(index);
tag.readTag(buf);
tagList.add(tag);
}
tags = tagList.toArray(new Tag[tagList.size()]);
}
@Override
public Tag deepCopy(String suffix) {
return new SequenceOf(name + suffix).copyFrom(this);
}
@Override
public Tag copyFrom(Tag tag) {
super.copyFrom(tag);
// We can create shallow copy of type, because it will not be modified
type = ((SequenceOf)tag).type;
tags = new Tag[((Sequence)tag).tags.length];
for (int i = 0; i < tags.length; i++) {
tags[i] = ((Sequence)tag).tags[i].deepCopy("");
}
return this;
}
@Override
public String toString() {
return super.toString() + ": " + type;
}
}

View File

@ -0,0 +1,462 @@
// 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 common.asn1;
import streamer.ByteBuffer;
public abstract class Tag implements Asn1Constants {
/**
* Name of this tag, for debugging purposes.
*/
public String name = "";
/**
* Is this tag required or optional, for explicit tags only.
*/
public boolean optional = false;
/**
* Tag primitive (e.g. implicit boolean), or constructed (e.g. sequence, or
* explicit boolean).
*/
public boolean constructed = false;
/**
* Class of tag, when it is explicit.
*/
public int tagClass = UNIVERSAL_CLASS;
/**
* Tag number (e.g. index in sequence), when tag is explicit.
*/
public int tagNumber = -1;
/**
* Tag type (e.g. INDER), when tag is implicit.
*/
public int tagType = -1;
/**
* If tag is explicit, then it is prefixed with tag number, so it can be
* optional or used in unordered set.
*/
public boolean explicit = false;
public Tag(String name) {
this.name = name;
}
/**
* Write tag value, with or without prefix.
*/
public void writeTag(ByteBuffer buf) {
if (!isMustBeWritten())
return;
// Write prefix, when necessary
if (explicit) {
// Write tag prefix, always constructed
BerType berTagPrefix = new BerType(tagClass, true, tagNumber);
writeBerType(buf, berTagPrefix);
// Write tag prefix length
buf.writeBerLength(calculateLength());
// Write tag value
writeTagValue(buf);
} else {
// If implicit, just write tag value
writeTagValue(buf);
}
}
/**
* Must return true when value of this tag is set or tag is required, so it
* can be written, false otherwise.
*/
public boolean isMustBeWritten() {
return !optional || isValueSet();
}
/**
* Must return true when value of this tag is set or tag is required, so it
* can be written, false otherwise.
*/
public abstract boolean isValueSet();
/**
* Calculate full length of tag, including type (or prefix, when explicit).
*/
public long calculateFullLength() {
if (!isMustBeWritten())
return 0;
// Length of value, including type
long length = calculateLength();
if (!explicit) {
// Length of tag type and it length
length += calculateLengthOfTagTypeOrTagNumber(tagType) + calculateLengthOfLength(length);
} else {
// Length of tag prefix and it length
length += calculateLengthOfTagTypeOrTagNumber(tagNumber) + calculateLengthOfLength(length);
}
return length;
}
/**
* Calculate length of tag, including type when explicit, but without length
* of prefix (or type, when implicit).
*/
public long calculateLength() {
if (!isMustBeWritten())
return 0;
// Length of value
long length = calculateLengthOfValuePayload();
if (explicit) {
// Length of tag type and it length
length += calculateLengthOfTagTypeOrTagNumber(tagType) + calculateLengthOfLength(length);
}
return length;
}
/**
* Calculate length of BER length.
*/
public int calculateLengthOfLength(long length) {
if (length < 0)
throw new RuntimeException("[" + this + "] ERROR: Length of tag cannot be less than zero: " + length + ".");
if (length <= 0x7f)
return 1;
if (length <= 0xff)
return 2;
if (length <= 0xffFF)
return 3;
if (length <= 0xffFFff)
return 4;
if (length <= 0xffFFffFFL)
return 5;
if (length <= 0xffFFffFFffL)
return 6;
if (length <= 0xffFFffFFffFFL)
return 7;
if (length <= 0xffFFffFFffFFffL)
return 8;
return 9;
}
/**
* Calculate length of type to tag number. Values less than 31 are encoded
* using lower 5 bits of first byte of tag. Values larger than 31 are
* indicated by lower 5 bits set to 1 (0x1F, 31), and next bytes are contain
* value in network order, where topmost bit of byte (0x80) indicates is value
* contains more bytes, i.e. last byte of sequence has this bit set to 0.
*/
public int calculateLengthOfTagTypeOrTagNumber(int tagType) {
if (tagType >= EXTENDED_TYPE)
throw new RuntimeException("Multibyte tag types are not supported yet.");
return 1;
}
/**
* Calculate length of payload only, without tag prefix, tag type, and
* lengths.
*
* @return
*/
public abstract long calculateLengthOfValuePayload();
/**
* Write tag value only, without prefix.
*/
public void writeTagValue(ByteBuffer buf) {
// Write type
BerType valueType = new BerType(UNIVERSAL_CLASS, constructed, tagType);
writeBerType(buf, valueType);
// Write length
long lengthOfPayload = calculateLengthOfValuePayload();
buf.writeBerLength(lengthOfPayload);
// Store cursor to check is calculated length matches length of actual bytes
// written
int storedCursor = buf.cursor;
// Write value
writeTagValuePayload(buf);
// Check is calculated length matches length of actual bytes written, to catch errors early
int actualLength = buf.cursor - storedCursor;
if (actualLength != lengthOfPayload)
throw new RuntimeException("[" + this + "] ERROR: Unexpected length of data in buffer. Expected " + lengthOfPayload + " of bytes of payload, but "
+ actualLength + " bytes are written instead. Data: " + buf + ".");
}
/**
* Write tag value only, without prefix, tag type, and length.
*/
public abstract void writeTagValuePayload(ByteBuffer buf);
/**
* Read required tag, i.e. we are 100% sure that byte buffer will contain this
* tag, or exception will be thrown otherwise.
*
* @param buf
* buffer with tag data
*/
public void readTag(ByteBuffer buf) {
BerType typeAndFlags = readBerType(buf);
// * DEBUG */System.out.println("Tag, read " + typeAndFlags);
if (!isTypeValid(typeAndFlags))
throw new RuntimeException("[" + this + "] Unexpected type: " + typeAndFlags + ".");
readTag(buf, typeAndFlags);
}
/**
* Read tag when it type is already read.
*/
public void readTag(ByteBuffer buf, BerType typeAndFlags) {
if (explicit) {
long length = buf.readBerLength();
if (length > buf.length)
throw new RuntimeException("BER value is too long: " + length + " bytes. Data: " + buf + ".");
ByteBuffer value = buf.readBytes((int)length);
readTagValue(value);
value.unref();
} else {
readTagValue(buf, typeAndFlags);
}
}
/**
* Read tag value only, i.e. it prefix is already read.
*/
public void readTagValue(ByteBuffer value) {
BerType typeAndFlags = readBerType(value);
// * DEBUG */System.out.println("Tag, read value " + typeAndFlags);
if (!isTypeValid(typeAndFlags, false))
throw new RuntimeException("[" + this + "] Unexpected type: " + typeAndFlags + ".");
readTagValue(value, typeAndFlags);
}
/**
* Check are tag type and flags valid for this tag.
*/
public final boolean isTypeValid(BerType typeAndFlags) {
return isTypeValid(typeAndFlags, explicit);
}
/**
* Check are tag type and flags valid for this tag with or without tag prefix.
*
* @param explicit
* if true, then value is wrapped in tag prefix
*/
public boolean isTypeValid(BerType typeAndFlags, boolean explicit) {
if (explicit)
return typeAndFlags.tagClass == tagClass && typeAndFlags.constructed && typeAndFlags.typeOrTagNumber == tagNumber;
else
return typeAndFlags.tagClass == UNIVERSAL_CLASS && !typeAndFlags.constructed && typeAndFlags.typeOrTagNumber == tagType;
}
@Override
public String toString() {
return " \nTag [name="
+ name
+ ((constructed) ? ", constructed=" + constructed : "")
+ (", tagType=" + tagTypeOrNumberToString(UNIVERSAL_CLASS, tagType))
+ ((explicit) ? ", explicit=" + explicit + ", optional=" + optional + ", tagClass=" + tagClassToString(tagClass) + ", tagNumber="
+ tagTypeOrNumberToString(tagClass, tagNumber) : "") + "]";
}
public static final String tagTypeOrNumberToString(int tagClass, int tagTypeOrNumber) {
switch (tagClass) {
case UNIVERSAL_CLASS:
switch (tagTypeOrNumber) {
case EOF:
return "EOF";
case BOOLEAN:
return "BOOLEAN";
case INTEGER:
return "INTEGER";
case BIT_STRING:
return "BIT_STRING";
case OCTET_STRING:
return "OCTET_STRING";
case NULL:
return "NULL";
case OBJECT_ID:
return "OBJECT_ID";
case REAL:
return "REAL";
case ENUMERATED:
return "ENUMERATED";
case SEQUENCE:
return "SEQUENCE";
case SET:
return "SET";
case NUMERIC_STRING:
return "NUMERIC_STRING";
case PRINTABLE_STRING:
return "PRINTABLE_STRING";
case TELETEX_STRING:
return "TELETEX_STRING";
case VIDEOTEXT_STRING:
return "VIDEOTEXT_STRING";
case IA5_STRING:
return "IA5_STRING";
case UTCTIME:
return "UTCTIME";
case GENERAL_TIME:
return "GENERAL_TIME";
case GRAPHIC_STRING:
return "GRAPHIC_STRING";
case VISIBLE_STRING:
return "VISIBLE_STRING";
case GENERAL_STRING:
return "GENERAL_STRING";
case EXTENDED_TYPE:
return "EXTENDED_TYPE (multibyte)";
default:
return "UNKNOWN(" + tagTypeOrNumber + ")";
}
default:
return "[" + tagTypeOrNumber + "]";
}
}
public static final String tagClassToString(int tagClass) {
switch (tagClass) {
case UNIVERSAL_CLASS:
return "UNIVERSAL";
case CONTEXT_CLASS:
return "CONTEXT";
case APPLICATION_CLASS:
return "APPLICATION";
case PRIVATE_CLASS:
return "PRIVATE";
default:
return "UNKNOWN";
}
}
/**
* Read BER tag type.
*/
public BerType readBerType(ByteBuffer buf) {
int typeAndFlags = buf.readUnsignedByte();
int tagClass = typeAndFlags & CLASS_MASK;
boolean constructed = (typeAndFlags & CONSTRUCTED) != 0;
int type = typeAndFlags & TYPE_MASK;
if (type == EXTENDED_TYPE)
throw new RuntimeException("Extended tag types/numbers (31+) are not supported yet.");
return new BerType(tagClass, constructed, type);
}
/**
* Write BER tag type.
*/
public void writeBerType(ByteBuffer buf, BerType berType) {
if (berType.typeOrTagNumber >= EXTENDED_TYPE || berType.typeOrTagNumber < 0)
throw new RuntimeException("Extended tag types/numbers (31+) are not supported yet: " + berType + ".");
if ((berType.tagClass & CLASS_MASK) != berType.tagClass)
throw new RuntimeException("Value of BER tag class is out of range: " + berType.tagClass + ". Expected values: " + UNIVERSAL_CLASS + ", " + CONTEXT_CLASS
+ ", " + APPLICATION_CLASS + ", " + PRIVATE_CLASS + ".");
int typeAndFlags = berType.tagClass | ((berType.constructed) ? CONSTRUCTED : 0) | berType.typeOrTagNumber;
buf.writeByte(typeAndFlags);
}
/**
* Read tag value only, i.e. it prefix is already read, when value type is
* already read.
*
* @param buf
* buffer with tag data
*/
public abstract void readTagValue(ByteBuffer buf, BerType typeAndFlags);
/**
* Create deep copy of this tag with given suffix appended to name.
*
* @param suffix
* suffix to add to tag name, or empty string
* @return deep copy of this tag
*/
public abstract Tag deepCopy(String suffix);
/**
* Create deep copy of this tag for array or set.
*
* @param index
* index of element in array or set
* @return deep copy of this tag
*/
public Tag deepCopy(int index) {
return deepCopy("[" + index + "]");
}
/**
* Copy tag values from an other tag, except name.
*
* @return this
*/
public Tag copyFrom(Tag tag) {
constructed = tag.constructed;
explicit = tag.explicit;
optional = tag.optional;
tagClass = tag.tagClass;
tagNumber = tag.tagNumber;
return this;
}
}

View File

@ -0,0 +1,28 @@
// 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 common.opt;
public class IncrementalOption extends Option {
int value = 0;
@Override
public int parse(int position, String[] args) {
value++;
return super.parse(position, args);
}
}

View File

@ -0,0 +1,41 @@
// 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 common.opt;
public class IntOption extends Option {
public int value = 0;
@Override
public int parse(int position, String[] args) {
if (position + 1 >= args.length)
throw new NoArgumentForOptionException("Cannot find required argument for option \"" + args[position] + "\".");
value = Integer.parseInt(args[position + 1]);
return super.parse(position, args) + 1;
}
@Override
public String help() {
StringBuilder help = new StringBuilder();
help.append(join("|", name, alias, aliases)).append(" VALUE\t").append(description);
if (required)
help.append(" Required.");
else if (value != 0)
help.append(" Default value is \"").append("" + value).append("\".");
return help.toString();
}
}

View File

@ -0,0 +1,26 @@
// 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 common.opt;
public class NoArgumentForOptionException extends RuntimeException {
public NoArgumentForOptionException(String message) {
super(message);
}
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,102 @@
// 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 common.opt;
public class Option {
public String name = "";
public String alias = null;
public String aliases[] = null;
public String description = "";
public boolean used = false;
public boolean required = false;
/**
* Parse option value, if any.
*
* @param position
* position of this option in list of arguments
* @param args
* command line arguments
* @return how many arguments are consumed, at least 1
*/
public int parse(int position, String args[]) {
used = true;
return 1;
}
@Override
public String toString() {
return help();
}
/**
* Return help string for this option. Example:
*
* <pre>
* --foo|-f Foo option.
* </pre>
*/
public String help() {
return join("|", name, alias, aliases) + "\t" + description + ((required) ? " Required." : "");
}
/**
* Return string like "--foo|-f|--another-foo-alias".
*/
protected String join(String delim, String name, String alias, String aliases[]) {
// Option name is mandatory
StringBuilder sb = new StringBuilder(name.length());
sb.append(name);
// Alias is optional
if (alias != null && alias.length() > 0) {
sb.append(delim).append(alias);
}
// Other aliases are optional too
if (aliases != null) {
for (String s : aliases) {
if (s != null && s.length() > 0) {
sb.append(delim).append(s);
}
}
}
return sb.toString();
}
/**
* Return description of options in format suitable for help and usage text.
*
* @param header
* header string to print before list of options
* @param options
* list of options to print
*/
public static String toHelp(String header, Option[] options) {
StringBuffer sb = new StringBuffer();
sb.append(header).append(":\n");
for (Option option : options) {
sb.append(" ").append(option.help()).append('\n');
}
return sb.toString();
}
}

View File

@ -0,0 +1,147 @@
// 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 common.opt;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
/**
* Simple parser of GNU-like options.
*/
public class OptionParser {
public static Option helpOption() {
return new Option() {
{
name = "--help";
alias = "-h";
}
};
}
/**
* Parse options, capture values and return rest of arguments.
*
* @param args
* command line arguments to parse
* @param startFrom
* number of first argument to start parsing from
* @param options
* options to fill with values
* @return rest of command line after first non-option or "--" separator
*/
public static String[] parseOptions(String args[], int startFrom, Option options[]) {
// Convert array of options into map, where key is option name or alias
Map<String, Option> optionMap = new HashMap<String, Option>(options.length);
for (Option option : options) {
optionMap.put(option.name, option);
if (option.alias != null)
optionMap.put(option.alias, option);
if (option.aliases != null) {
for (String alias : option.aliases)
optionMap.put(alias, option);
}
}
// Parse arguments
int position = startFrom;
while (position < args.length) {
// Double dash means end of options
String optionName = args[position];
if (optionName.equals("--")) {
position++;
break;
}
Option option = optionMap.get(optionName);
// If option is not found, then this is argument, unless is starts with
// dash
if (option == null)
if (!optionName.startsWith("-"))
break;
else
throw new UnknownOptionException("Option \"" + optionName
+ "\" is unknown. If this is not an option, then use \"--\" to separate options and arguments. Known options: " + optionMap.keySet().toString());
position += option.parse(position, args);
}
// Check is required options are used on command line
for (Option option : options) {
if (option.required && !option.used)
throw new OptionRequiredException("Option \"" + option.name + "\" is required.");
}
// Return rest of arguments, which are left after options
return (position < args.length) ? Arrays.copyOfRange(args, position, args.length) : new String[] {};
}
/* Example. */
public static void main(String args[]) {
if (args.length == 0)
args = new String[] {"--help", "--foo", "fooval", "--bar", "123", "-v", "--verbose", "-v", "-a", "a1", "-aa", "a2", "-aaa", "a3", "rest", "of",
"arguments"};
StringOption foo = new StringOption() {
{
name = "--foo";
alias = "-f";
value = "fooDefault";
}
};
IntOption bar = new IntOption() {
{
name = "--bar";
alias = "-b";
value = 123;
}
};
IncrementalOption verbose = new IncrementalOption() {
{
name = "--verbose";
alias = "-v";
}
};
StringArrayOption array = new StringArrayOption() {
{
name = "--array";
alias = "-a";
aliases = new String[] {"-aa", "-aaa"};
}
};
String arguments[] = OptionParser.parseOptions(args, 0, new Option[] {helpOption(), foo, bar, verbose, array});
assertTrue(foo.value.equals("fooval"));
assertTrue(bar.value == 123);
assertTrue(verbose.value == 3);
assertTrue(Arrays.equals(array.value, new String[] {"a1", "a2", "a3"}));
assertTrue(Arrays.equals(arguments, new String[] {"rest", "of", "arguments"}));
}
public static void assertTrue(boolean result) {
if (!result)
throw new AssertionError();
}
}

View File

@ -0,0 +1,26 @@
// 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 common.opt;
public class OptionRequiredException extends RuntimeException {
public OptionRequiredException(String message) {
super(message);
}
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,38 @@
// 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 common.opt;
import java.util.Arrays;
public class StringArrayOption extends Option {
public String value[] = null;
@Override
public int parse(int position, String[] args) {
if (position + 1 >= args.length)
throw new NoArgumentForOptionException("Cannot find required argument for option \"" + args[position] + "\".");
// Append value to end of array of values
if (value == null) {
value = new String[] {args[position + 1]};
} else {
value = Arrays.copyOf(value, value.length + 1);
value[value.length - 1] = args[position + 1];
}
return super.parse(position, args) + 1;
}
}

View File

@ -0,0 +1,72 @@
// 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 common.opt;
public class StringEnumerationOption extends Option {
public String value = "";
public String choices[] = new String[] {};
@Override
public int parse(int position, String[] args) {
if (position + 1 >= args.length)
throw new NoArgumentForOptionException("Cannot find required argument for option \"" + args[position] + "\".");
value = args[position + 1];
for (String s : choices) {
if (value.equals(s))
return super.parse(position, args) + 1;
}
throw new NoArgumentForOptionException("Unexpected argument for option \"" + args[position] + "\": \"" + value + "\". Expected argument: "
+ join("|", choices) + ".");
}
@Override
public String help() {
StringBuilder help = new StringBuilder();
help.append(join("|", name, alias, aliases)).append(" ").append(join("|", choices)).append("\t").append(description);
if (required)
help.append(" Required.");
else if (value != null && value.length() > 0)
help.append(" Default value is \"").append(value).append("\".");
return help.toString();
}
/**
* Join strings in array into one large string.
*/
protected String join(String delim, String values[]) {
StringBuilder sb = new StringBuilder();
if (values != null) {
boolean first = true;
for (String s : values) {
if (s != null && s.length() > 0) {
if (first)
first = false;
else
sb.append(delim);
sb.append(s);
}
}
}
return sb.toString();
}
}

View File

@ -0,0 +1,41 @@
// 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 common.opt;
public class StringOption extends Option {
public String value = "";
@Override
public int parse(int position, String[] args) {
if (position + 1 >= args.length)
throw new NoArgumentForOptionException("Cannot find required argument for option \"" + args[position] + "\".");
value = args[position + 1];
return super.parse(position, args) + 1;
}
@Override
public String help() {
StringBuilder help = new StringBuilder();
help.append(join("|", name, alias, aliases)).append(" VALUE\t").append(description);
if (required)
help.append(" Required.");
else if (value != null && value.length() > 0)
help.append(" Default value is \"").append(value).append("\".");
return help.toString();
}
}

View File

@ -0,0 +1,27 @@
// 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 common.opt;
public class UnknownOptionException extends RuntimeException {
public UnknownOptionException(String message) {
super(message);
}
private static final long serialVersionUID = 1L;
}

View File

@ -1,350 +0,0 @@
// 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;
import java.awt.event.KeyEvent;
import streamer.BaseElement;
import streamer.ByteBuffer;
import streamer.Link;
import common.KeyOrder;
public class AwtRdpKeyboardAdapter extends BaseElement {
/**
* Absence of this flag indicates a key-down event, while its presence
* indicates a key-release event.
*/
public static final int FASTPATH_INPUT_KBDFLAGS_RELEASE = 0x01;
/**
* Keystroke message contains an extended scancode. For enhanced 101-key and
* 102-key keyboards, extended keys include the right ALT and right CTRL keys
* on the main section of the keyboard; the INS, DEL, HOME, END, PAGE UP, PAGE
* DOWN and ARROW keys in the clusters to the left of the numeric keypad; and
* the Divide ("/") and ENTER keys in the numeric keypad.
*/
public static final int FASTPATH_INPUT_KBDFLAGS_EXTENDED = 0x02;
public static final int FASTPATH_INPUT_EVENT_SCANCODE = 0;
public AwtRdpKeyboardAdapter(String id) {
super(id);
}
@Override
public void handleData(ByteBuffer buf, Link link) {
if (verbose)
System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
KeyOrder order = (KeyOrder)buf.getOrder();
buf.unref();
ByteBuffer outBuf = new ByteBuffer(2, true);
int scanCode = map_en_us(order.event);
// eventHeader (1 byte): An 8-bit, unsigned integer. The format of this
// field is the same as the eventHeader byte field described in section
// 2.2.8.1.2.2. The eventCode bitfield (3 bits in size) MUST be set to
// FASTPATH_INPUT_EVENT_SCANCODE (0). The eventFlags bitfield (5 bits in
// size) contains flags describing the keyboard event.
outBuf.writeByte((scanCode >> 8) | (FASTPATH_INPUT_EVENT_SCANCODE << 5) | ((order.pressed) ? 0 : FASTPATH_INPUT_KBDFLAGS_RELEASE));
// keyCode (1 byte): An 8-bit, unsigned integer. The scancode of the key
// which triggered the event.
outBuf.writeByte(scanCode);
// Push buffer to one pad only, so it can be modified without copying of
// data
pushDataToPad(STDOUT, outBuf);
}
/**
* Return key scan code (in lower byte) and extended flags (in second byte).
*/
private int map_en_us(KeyEvent event) {
// Also set extended key flag when necessary.
// For enhanced 101-key and 102-key keyboards, extended keys include the
// right ALT and right CTRL keys on the main section of the keyboard; the
// INS, DEL, HOME, END, PAGE UP, PAGE DOWN and ARROW keys in the clusters to
// the left of the numeric keypad; and the Divide ("/") and ENTER keys in
// the numeric keypad.
switch (event.getKeyCode()) {
// Functional keys
case KeyEvent.VK_ESCAPE:
return 1;
case KeyEvent.VK_F1:
return 59;
case KeyEvent.VK_F2:
return 60;
case KeyEvent.VK_F3:
return 61;
case KeyEvent.VK_F4:
return 62;
case KeyEvent.VK_F5:
return 63;
case KeyEvent.VK_F6:
return 64;
case KeyEvent.VK_F7:
return 65;
case KeyEvent.VK_F8:
return 66;
case KeyEvent.VK_F9:
return 67;
case KeyEvent.VK_F10:
return 68;
case KeyEvent.VK_F11:
return 87;
case KeyEvent.VK_F12:
return 88;
// Row #1
case KeyEvent.VK_BACK_QUOTE:
return 41;
case KeyEvent.VK_1:
return 2;
case KeyEvent.VK_2:
return 3;
case KeyEvent.VK_3:
return 4;
case KeyEvent.VK_4:
return 5;
case KeyEvent.VK_5:
return 6;
case KeyEvent.VK_6:
return 7;
case KeyEvent.VK_7:
return 8;
case KeyEvent.VK_8:
return 9;
case KeyEvent.VK_9:
return 10;
case KeyEvent.VK_0:
return 11;
case KeyEvent.VK_MINUS:
return 12;
case KeyEvent.VK_EQUALS:
return 13;
case KeyEvent.VK_BACK_SPACE:
return 14;
// Row #2
case KeyEvent.VK_TAB:
return 15;
case KeyEvent.VK_Q:
return 16;
case KeyEvent.VK_W:
return 17;
case KeyEvent.VK_E:
return 18;
case KeyEvent.VK_R:
return 19;
case KeyEvent.VK_T:
return 20;
case KeyEvent.VK_Y:
return 21;
case KeyEvent.VK_U:
return 22;
case KeyEvent.VK_I:
return 23;
case KeyEvent.VK_O:
return 24;
case KeyEvent.VK_P:
return 25;
case KeyEvent.VK_OPEN_BRACKET:
return 26;
case KeyEvent.VK_CLOSE_BRACKET:
return 27;
case KeyEvent.VK_ENTER:
switch (event.getKeyLocation()) {
default:
case KeyEvent.KEY_LOCATION_STANDARD:
return 28;
case KeyEvent.KEY_LOCATION_NUMPAD:
return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 28;
}
// Row #3
case KeyEvent.VK_CAPS_LOCK:
return 58;
case KeyEvent.VK_A:
return 30;
case KeyEvent.VK_S:
return 31;
case KeyEvent.VK_D:
return 32;
case KeyEvent.VK_F:
return 33;
case KeyEvent.VK_G:
return 34;
case KeyEvent.VK_H:
return 35;
case KeyEvent.VK_J:
return 36;
case KeyEvent.VK_K:
return 37;
case KeyEvent.VK_L:
return 38;
case KeyEvent.VK_SEMICOLON:
return 39;
case KeyEvent.VK_QUOTE:
return 40;
// Row #4
case KeyEvent.VK_SHIFT:
switch (event.getKeyLocation()) {
default:
case KeyEvent.KEY_LOCATION_LEFT:
return 42;
case KeyEvent.KEY_LOCATION_RIGHT:
return 54;
}
case KeyEvent.VK_BACK_SLASH:
return 43;
case KeyEvent.VK_Z:
return 44;
case KeyEvent.VK_X:
return 45;
case KeyEvent.VK_C:
return 46;
case KeyEvent.VK_V:
return 47;
case KeyEvent.VK_B:
return 48;
case KeyEvent.VK_N:
return 49;
case KeyEvent.VK_M:
return 50;
case KeyEvent.VK_COMMA:
return 51;
case KeyEvent.VK_PERIOD:
return 52;
case KeyEvent.VK_SLASH:
return 53;
//
// Bottom row
case KeyEvent.VK_CONTROL:
switch (event.getKeyLocation()) {
default:
case KeyEvent.KEY_LOCATION_LEFT:
return 29;
case KeyEvent.KEY_LOCATION_RIGHT:
return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 29;
}
case KeyEvent.VK_WINDOWS:
switch (event.getKeyLocation()) {
default:
case KeyEvent.KEY_LOCATION_LEFT:
return 91;
case KeyEvent.KEY_LOCATION_RIGHT:
return 92;
}
case KeyEvent.VK_ALT:
switch (event.getKeyLocation()) {
default:
case KeyEvent.KEY_LOCATION_LEFT:
return 56;
case KeyEvent.KEY_LOCATION_RIGHT:
return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 56;
}
case KeyEvent.VK_ALT_GRAPH:
return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 56;
case KeyEvent.VK_SPACE:
return 57;
case KeyEvent.VK_CONTEXT_MENU:
return 93;
//
// Special keys
case KeyEvent.VK_PRINTSCREEN:
return 55;
case KeyEvent.VK_SCROLL_LOCK:
return 70;
case KeyEvent.VK_PAUSE:
return 29;
// Text navigation keys
case KeyEvent.VK_INSERT:
return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 82;
case KeyEvent.VK_HOME:
return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 71;
case KeyEvent.VK_PAGE_UP:
return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 73;
case KeyEvent.VK_DELETE:
return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 83;
case KeyEvent.VK_END:
return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 79;
case KeyEvent.VK_PAGE_DOWN:
return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 81;
// Cursor keys
case KeyEvent.VK_UP:
return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 72;
case KeyEvent.VK_LEFT:
return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 75;
case KeyEvent.VK_DOWN:
return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 80;
case KeyEvent.VK_RIGHT:
return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 77;
// Keypad
case KeyEvent.VK_NUM_LOCK:
return 69;
case KeyEvent.VK_DIVIDE:
return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 53;
case KeyEvent.VK_MULTIPLY:
return 55;
case KeyEvent.VK_SUBTRACT:
return 74;
case KeyEvent.VK_ADD:
return 78;
case KeyEvent.VK_NUMPAD7:
return 71;
case KeyEvent.VK_NUMPAD8:
return 72;
case KeyEvent.VK_NUMPAD9:
return 73;
case KeyEvent.VK_NUMPAD4:
return 75;
case KeyEvent.VK_NUMPAD5:
return 76;
case KeyEvent.VK_NUMPAD6:
return 77;
case KeyEvent.VK_NUMPAD1:
return 79;
case KeyEvent.VK_NUMPAD2:
return 80;
case KeyEvent.VK_NUMPAD3:
return 81;
case KeyEvent.VK_NUMPAD0:
return 82;
case KeyEvent.VK_DECIMAL:
return 83;
default:
System.err.println("Key is not mapped: " + event + ".");
return 57; // Space
}
}
}

View File

@ -1,455 +0,0 @@
// 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;
import streamer.ByteBuffer;
import streamer.Element;
import streamer.Link;
import streamer.MockSink;
import streamer.MockSource;
import streamer.OneTimeSwitch;
import streamer.Pipeline;
import streamer.PipelineImpl;
/**
* @see http://msdn.microsoft.com/en-us/library/cc240475.aspx
*/
public class ClientInfoPDU extends OneTimeSwitch {
public static final int INFO_MOUSE = 0x1;
public static final int INFO_DISABLECTRLALTDEL = 0x2;
public static final int INFO_UNICODE = 0x10;
public static final int INFO_MAXIMIZESHELL = 0x20;
public static final int INFO_LOGONNOTIFY = 0x40;
public static final int INFO_ENABLEWINDOWSKEY = 0x100;
public static final int INFO_MOUSE_HAS_WHEEL = 0x00020000;
public static final int INFO_NOAUDIOPLAYBACK = 0x00080000;
public static final int PERF_DISABLE_WALLPAPER = 0x1;
public static final int PERF_DISABLE_FULLWINDOWDRAG = 0x2;
public static final int PERF_DISABLE_MENUANIMATIONS = 0x4;
protected byte[] userName = "".getBytes(RdpConstants.CHARSET_16);
protected byte[] password = "".getBytes(RdpConstants.CHARSET_16); // No effect
protected byte[] alternateShell = "".getBytes(RdpConstants.CHARSET_16);
protected byte[] domain = "".getBytes(RdpConstants.CHARSET_16);
protected byte[] workingDir = "".getBytes(RdpConstants.CHARSET_16);
protected byte[] clientAddress = "192.168.0.100".getBytes(RdpConstants.CHARSET_16);
protected byte[] clientDir = "C:\\Windows\\System32\\mstscax.dll".getBytes(RdpConstants.CHARSET_16);
protected String standardTimeZoneName = "EET, Standard Time";
protected String daylightTimeZoneName = "EET, Summer Time";
protected int standardTimeZoneBias = 0; /* in minutes */
protected int daylightTimeZoneBias = 60; /* in minutes */
public ClientInfoPDU(String id, String userName) {
super(id);
this.userName = userName.getBytes(RdpConstants.CHARSET_16);
}
@Override
protected void handleOneTimeData(ByteBuffer buf, Link link) {
if (buf == null)
return;
throw new RuntimeException("Unexpected packet: " + buf + ".");
}
@Override
protected void onStart() {
super.onStart();
// Length of packet
ByteBuffer buf = new ByteBuffer(1024, true);
// MCS Send Data Request PDU
buf.writeByte(0x64);
// Initiator: 0x03 + 1001 = 1004
buf.writeShort(3);
// Channel ID: 1003
buf.writeShort(1003);
// Data priority: high, segmentation: begin | end (0x40 | 0x20 | 0x10 = 0x70)
buf.writeByte(0x70);
// User data length: (variable length field)
int length = 224 + userName.length + password.length + alternateShell.length + domain.length + workingDir.length + clientAddress.length + clientDir.length;
buf.writeShort(length | 0x8000);
// Flags: SEC_INFO_PKT (0x4000)
buf.writeShort(0x4000);
// TS_SECURITY_HEADER::flagsHi - ignored
buf.writeShort(0x0000);
// Codepage: 0 (UNKNOWN, LE) (use 0x04090409 (1033,1033) for EN_US)
buf.writeIntLE(0x0000);
// Flags
buf.writeIntLE(INFO_MOUSE | INFO_DISABLECTRLALTDEL | INFO_UNICODE | INFO_MAXIMIZESHELL | INFO_LOGONNOTIFY | INFO_ENABLEWINDOWSKEY | INFO_MOUSE_HAS_WHEEL |
INFO_NOAUDIOPLAYBACK);
//
// Lengths
//
// cbDomain length: 0 bytes (LE) (NOT including size of mandatory NULL terminator)
buf.writeShortLE(domain.length);
// cbUserName length: 16 bytes (0x10, LE) (NOT including size of mandatory NULL terminator)
buf.writeShortLE(userName.length);
// cbPassword length: (LE) (NOT including size of mandatory NULL terminator)
buf.writeShortLE(password.length);
// cbAlternateShell: (LE) (NOT including size of mandatory NULL terminator)
buf.writeShortLE(alternateShell.length);
// cbWorkingDir: (LE) (NOT including size of mandatory NULL terminator)
buf.writeShortLE(workingDir.length);
//
// Values
//
// Domain: (UCS2), see cbDomain
buf.writeBytes(domain);
buf.writeShort(0);
// User name: (UCS2), see cbUserName
buf.writeBytes(userName);
buf.writeShort(0);
// Password: (UCS2), see cbPassword
buf.writeBytes(password);
buf.writeShort(0);
// Alternate shell: (UCS2), see cbAlternateShell
buf.writeBytes(alternateShell);
buf.writeShort(0);
// Working directory: (UCS2), see cbWorkingDir
buf.writeBytes(workingDir);
buf.writeShort(0);
// Client address family: 2 (AF_INET, LE)
buf.writeShortLE(2);
// cbClientAddress: ( LE) (including the size of the mandatory NULL terminator)
buf.writeShortLE(clientAddress.length + 2);
// Client address: (UCS2)
buf.writeBytes(clientAddress);
buf.writeShort(0);
// cbClientDir: 64 bytes (0x40, LE) (including the size of the mandatory NULL terminator)
buf.writeShortLE(clientDir.length + 2);
// Client directory: (UCS2)
buf.writeBytes(clientDir);
buf.writeShort(0);
//
// Client time zone:
//
// Bias: 0 minutes (LE)
buf.writeIntLE(0);
// Standard name: "EET, Standard Time" (fixed string: 64 bytes, UCS2)
buf.writeFixedString(62, standardTimeZoneName, RdpConstants.CHARSET_16);
buf.writeShort(0);
// Standard date
buf.writeBytes(new byte[] {
// wYear: 0 (LE)
(byte)0x00, (byte)0x00,
// wMonth: unknown (LE)
(byte)0x00, (byte)0x00,
// wDayOfWeek: Sunday (LE)
(byte)0x00, (byte)0x00,
// wDay: unknown (LE)
(byte)0x00, (byte)0x00,
// wHour: 0 (LE)
(byte)0x00, (byte)0x00,
// wMinute: 0 (LE)
(byte)0x00, (byte)0x00,
// wSecond: 0 (LE)
(byte)0x00, (byte)0x00,
// wMilliseconds: 0
(byte)0x00, (byte)0x00,
});
// StandardBias: 0 minutes (LE)
buf.writeIntLE(standardTimeZoneBias);
// Daylight name: "EET, Summer Time" (fixed string: 64 bytes, UCS2)
buf.writeFixedString(62, daylightTimeZoneName, RdpConstants.CHARSET_16);
buf.writeShort(0);
// Daylight date
buf.writeBytes(new byte[] {
// wYear: 0 (LE)
(byte)0x00, (byte)0x00,
// wMonth: unknown (LE)
(byte)0x00, (byte)0x00,
// wDayOfWeek: Sunday (LE)
(byte)0x00, (byte)0x00,
// wDay: unknown (LE)
(byte)0x00, (byte)0x00,
// wHour: 0 (LE)
(byte)0x00, (byte)0x00,
// wMinute: 0 (LE)
(byte)0x00, (byte)0x00,
// wSecond: 0 (LE)
(byte)0x00, (byte)0x00,
// wMilliseconds: 0
(byte)0x00, (byte)0x00,
});
// Daylight bias: 60 minutes (LE)
buf.writeIntLE(daylightTimeZoneBias);
// Client session ID: 0x00000000 (LE)
buf.writeIntLE(0);
// Performance flags: 0x7 (LE) = PERF_DISABLE_WALLPAPER (0x1), PERF_DISABLE_FULLWINDOWDRAG (0x2), PERF_DISABLE_MENUANIMATIONS (0x4)
buf.writeIntLE(PERF_DISABLE_WALLPAPER | PERF_DISABLE_FULLWINDOWDRAG | PERF_DISABLE_MENUANIMATIONS);
// cbAutoReconnectCookie: 0 bytes (LE)
buf.writeShortLE(0);
// Trim buffer to actual length of data written
buf.length = buf.cursor;
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[] {
// TPKT
(byte) 0x03, (byte) 0x00,
// TPKT length: 343 bytes
(byte) 0x01, (byte) 0x57,
// X224 Data PDU
(byte) 0x02, (byte) 0xf0, (byte) 0x80,
// MCS Send Data Request PDU
(byte) 0x64,
// Initiator: 0x03 + 1001 = 1004
(byte) 0x00, (byte) 0x03,
// Channel ID: 1003 (IO Channel)
(byte) 0x03, (byte) 0xeb,
// Data priority: high, segmentation: begin | end (0x40 | 0x20 | 0x10 = 0x70)
(byte) 0x70,
// User data length: 328 (0x148) bytes, variable length field
(byte) 0x81, (byte) 0x48,
// Flags: SEC_INFO_PKT (0x4000)
(byte) 0x40, (byte) 0x00,
// TS_SECURITY_HEADER::flagsHi - ignored
(byte) 0x00, (byte) 0x00,
// Codepage: 0 (UNKNOWN, LE) (use 0x04090409 (1033,1033) for EN_US)
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// Flags: 0xa0173 (LE), INFO_MOUSE (0x1), INFO_DISABLECTRLALTDEL (0x2), INFO_UNICODE (0x10),
// INFO_MAXIMIZESHELL (0x20), INFO_LOGONNOTIFY (0x40), INFO_ENABLEWINDOWSKEY (0x100),
// INFO_MOUSE_HAS_WHEEL (0x00020000), INFO_NOAUDIOPLAYBACK (0x00080000),
(byte) 0x73, (byte) 0x01, (byte) 0x0a, (byte) 0x00,
// Lengths
// cbDomain length: 0 bytes (LE) (NOT including size of mandatory NULL terminator)
(byte) 0x00, (byte) 0x00,
// cbUserName length: 16 bytes (0x10, LE) (NOT including size of mandatory NULL terminator)
(byte) 0x10, (byte) 0x00,
// cbPassword length: 0 bytes (LE) (NOT including size of mandatory NULL terminator)
(byte) 0x00, (byte) 0x00,
// cbAlternateShell: 0 bytes (LE) (NOT including size of mandatory NULL terminator)
(byte) 0x00, (byte) 0x00,
// cbWorkingDir: 0 bytes (LE) (NOT including size of mandatory NULL terminator)
(byte) 0x00, (byte) 0x00,
// Values
// Domain: "" (UCS2), see cbDomain
(byte) 0x00, (byte) 0x00,
// User name: "vlisivka" (UCS2), see cbUserName
(byte) 0x76, (byte) 0x00, (byte) 0x6c, (byte) 0x00, (byte) 0x69, (byte) 0x00, (byte) 0x73, (byte) 0x00,
(byte) 0x69, (byte) 0x00, (byte) 0x76, (byte) 0x00, (byte) 0x6b, (byte) 0x00, (byte) 0x61, (byte) 0x00,
(byte) 0x00, (byte) 0x00,
// Password: "" (UCS2), see cbPassword
(byte) 0x00, (byte) 0x00,
// Alternate shell: "" (UCS2), see cbAlternateShell
(byte) 0x00, (byte) 0x00,
// Working directory: "" (UCS2), see cbWorkingDir
(byte) 0x00, (byte) 0x00,
// Client address family: 2 (AF_INET, LE)
(byte) 0x02, (byte) 0x00,
// cbClientAddress = 28 bytes (0x1c, LE) (including the size of the mandatory NULL terminator)
(byte) 0x1c, (byte) 0x00,
// Client address: "192.168.0.100" (UCS2)
(byte) 0x31, (byte) 0x00, (byte) 0x39, (byte) 0x00, (byte) 0x32, (byte) 0x00, (byte) 0x2e, (byte) 0x00,
(byte) 0x31, (byte) 0x00, (byte) 0x36, (byte) 0x00, (byte) 0x38, (byte) 0x00, (byte) 0x2e, (byte) 0x00,
(byte) 0x30, (byte) 0x00, (byte) 0x2e, (byte) 0x00, (byte) 0x31, (byte) 0x00, (byte) 0x30, (byte) 0x00,
(byte) 0x30, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// cbClientDir: 64 bytes (0x40, LE) (including the size of the mandatory NULL terminator)
(byte) 0x40, (byte) 0x00,
// Client directory: "C:\Windows\System32\mstscax.dll" (UCS2)
(byte) 0x43, (byte) 0x00, (byte) 0x3a, (byte) 0x00, (byte) 0x5c, (byte) 0x00, (byte) 0x57, (byte) 0x00,
(byte) 0x69, (byte) 0x00, (byte) 0x6e, (byte) 0x00, (byte) 0x64, (byte) 0x00, (byte) 0x6f, (byte) 0x00,
(byte) 0x77, (byte) 0x00, (byte) 0x73, (byte) 0x00, (byte) 0x5c, (byte) 0x00, (byte) 0x53, (byte) 0x00,
(byte) 0x79, (byte) 0x00, (byte) 0x73, (byte) 0x00, (byte) 0x74, (byte) 0x00, (byte) 0x65, (byte) 0x00,
(byte) 0x6d, (byte) 0x00, (byte) 0x33, (byte) 0x00, (byte) 0x32, (byte) 0x00, (byte) 0x5c, (byte) 0x00,
(byte) 0x6d, (byte) 0x00, (byte) 0x73, (byte) 0x00, (byte) 0x74, (byte) 0x00, (byte) 0x73, (byte) 0x00,
(byte) 0x63, (byte) 0x00, (byte) 0x61, (byte) 0x00, (byte) 0x78, (byte) 0x00, (byte) 0x2e, (byte) 0x00,
(byte) 0x64, (byte) 0x00, (byte) 0x6c, (byte) 0x00, (byte) 0x6c, (byte) 0x00, (byte) 0x00, (byte) 0x00,
//
// Client time zone:
// Bias: 0 minutes (LE)
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// Standard name: "EET, Standard Time" (fixed string: 64 bytes, UCS2)
(byte) 0x45, (byte) 0x00, (byte) 0x45, (byte) 0x00, (byte) 0x54, (byte) 0x00, (byte) 0x2c, (byte) 0x00,
(byte) 0x20, (byte) 0x00, (byte) 0x53, (byte) 0x00, (byte) 0x74, (byte) 0x00, (byte) 0x61, (byte) 0x00,
(byte) 0x6e, (byte) 0x00, (byte) 0x64, (byte) 0x00, (byte) 0x61, (byte) 0x00, (byte) 0x72, (byte) 0x00,
(byte) 0x64, (byte) 0x00, (byte) 0x20, (byte) 0x00, (byte) 0x54, (byte) 0x00, (byte) 0x69, (byte) 0x00,
(byte) 0x6d, (byte) 0x00, (byte) 0x65, (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) 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,
//
// Standard date
// wYear: 0 (LE)
(byte) 0x00, (byte) 0x00,
// wMonth: unknown (LE)
(byte) 0x00, (byte) 0x00,
// wDayOfWeek: Sunday (LE)
(byte) 0x00, (byte) 0x00,
// wDay: unknown (LE)
(byte) 0x00, (byte) 0x00,
// wHour: 0 (LE)
(byte) 0x00, (byte) 0x00,
// wMinute: 0 (LE)
(byte) 0x00, (byte) 0x00,
// wSecond: 0 (LE)
(byte) 0x00, (byte) 0x00,
// wMilliseconds: 0
(byte) 0x00, (byte) 0x00,
// StandardBias: 0 minutes (LE)
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// Daylight name: "EET, Summer Time" (fixed string: 64 bytes, UCS2)
(byte) 0x45, (byte) 0x00, (byte) 0x45, (byte) 0x00, (byte) 0x54, (byte) 0x00, (byte) 0x2c, (byte) 0x00,
(byte) 0x20, (byte) 0x00, (byte) 0x53, (byte) 0x00, (byte) 0x75, (byte) 0x00, (byte) 0x6d, (byte) 0x00,
(byte) 0x6d, (byte) 0x00, (byte) 0x65, (byte) 0x00, (byte) 0x72, (byte) 0x00, (byte) 0x20, (byte) 0x00,
(byte) 0x54, (byte) 0x00, (byte) 0x69, (byte) 0x00, (byte) 0x6d, (byte) 0x00, (byte) 0x65, (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) 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) 0x00,
// Daylight date
// wYear: 0 (LE)
(byte) 0x00, (byte) 0x00,
// wMonth: unknown (LE)
(byte) 0x00, (byte) 0x00,
// wDayOfWeek: Sunday (LE)
(byte) 0x00, (byte) 0x00,
// wDay: unknown (LE)
(byte) 0x00, (byte) 0x00,
// wHour: 0 (LE)
(byte) 0x00, (byte) 0x00,
// wMinute: 0 (LE)
(byte) 0x00, (byte) 0x00,
// wSecond: 0 (LE)
(byte) 0x00, (byte) 0x00,
// wMilliseconds: 0
(byte) 0x00, (byte) 0x00,
// Daylight bias: 60 minutes (LE)
(byte) 0x3c, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// Client session ID: 0x00000000 (LE)
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// Performance flags: 0x7 (LE) = PERF_DISABLE_WALLPAPER (0x1), PERF_DISABLE_FULLWINDOWDRAG (0x2), PERF_DISABLE_MENUANIMATIONS (0x4)
(byte) 0x07, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// cbAutoReconnectCookie: 0 bytes (LE)
(byte) 0x00, (byte) 0x00,
};
/* @formatter:on */
MockSource source = new MockSource("source", ByteBuffer.convertByteArraysToByteBuffers(new byte[] {1, 2, 3}));
Element todo = new ClientInfoPDU("client_info", "vlisivka");
Element x224 = new ClientX224DataPdu("x224");
Element tpkt = new ClientTpkt("tpkt");
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, todo, x224, tpkt, sink, mainSink);
pipeline.link("source", "client_info", "mainSink");
pipeline.link("client_info >" + OTOUT, "x224", "tpkt", "sink");
pipeline.runMainLoop("source", STDOUT, false, false);
}
}

View File

@ -1,669 +0,0 @@
// 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;
import streamer.ByteBuffer;
import streamer.Element;
import streamer.Link;
import streamer.MockSink;
import streamer.MockSource;
import streamer.OneTimeSwitch;
import streamer.Pipeline;
import streamer.PipelineImpl;
public class ClientMCSConnectInitial extends OneTimeSwitch {
public ClientMCSConnectInitial(String id) {
super(id);
}
@Override
protected void handleOneTimeData(ByteBuffer buf, Link link) {
if (buf == null)
return;
throw new RuntimeException("Unexpected packet: " + buf + ".");
}
@Override
protected void onStart() {
super.onStart();
int length = 1024; // Large enough
ByteBuffer buf = new ByteBuffer(length, true);
/* @formatter:off */
buf.writeBytes(new byte[] {
// - T125: MCSConnect Initial
// - MCSConnectInitial: Identifier=Generic Conference Control (0.0.20.124.0.1), ConnectPDULength=254
// - ConnectInitialHeader:
(byte)0x7F, (byte)0x65,
// - AsnId: Application Constructed Tag (101)
// - HighTag:
// Class: (01......) Application (1)
// Type: (..1.....) Constructed
// TagNumber: (...11111)
// TagValueEnd: 101 (0x65)
(byte)0x82, (byte)0x01, (byte)0x6C,
// - AsnLen: Length = 364, LengthOfLength = 2
// LengthType: LengthOfLength = 2
// Length: 364 bytes
(byte)0x04, (byte)0x01, (byte)0x01,
// - CallingDomainSelector: 0x1
// - AsnOctetStringHeader:
// - AsnId: OctetString type (Universal 4)
// - LowTag:
// Class: (00......) Universal (0)
// Type: (..0.....) Primitive
// TagValue: (...00100) 4
// - AsnLen: Length = 1, LengthOfLength = 0
// Length: 1 bytes, LengthOfLength = 0
// OctetStream: 0x1
(byte)0x04, (byte)0x01, (byte)0x01,
// - CalledDomainSelector: 0x1
// - AsnOctetStringHeader:
// - AsnId: OctetString type (Universal 4)
// - LowTag:
// Class: (00......) Universal (0)
// Type: (..0.....) Primitive
// TagValue: (...00100) 4
// - AsnLen: Length = 1, LengthOfLength = 0
// Length: 1 bytes, LengthOfLength = 0
// OctetStream: 0x1
(byte)0x01, (byte)0x01, (byte)0xFF,
// - UpwardFlag: True
// - AsnBooleanHeader:
// - AsnId: Boolean type (Universal 1)
// - LowTag:
// Class: (00......) Universal (0)
// Type: (..0.....) Primitive
// TagValue: (...00001) 1
// - AsnLen: Length = 1, LengthOfLength = 0
// Length: 1 bytes, LengthOfLength = 0
// Tf: 255 (0xFF)
//
// - TargetParameters: Length = 26, LengthOfLength = 0
(byte)0x30, (byte)0x1A,
// - DomainParametersHeader: 0x1
// - AsnId: Sequence and SequenceOf types (Universal 16)
// - LowTag:
// Class: (00......) Universal (0)
// Type: (..1.....) Constructed
// TagValue: (...10000) 16
// - AsnLen: Length = 26, LengthOfLength = 0
// Length: 26 bytes, LengthOfLength = 0
(byte)0x02, (byte)0x01, (byte)0x22,
// - ChannelIds: 34
// - AsnIntegerHeader:
// - AsnId: Integer type (Universal 2)
// - LowTag:
// Class: (00......) Universal (0)
// Type: (..0.....) Primitive
// TagValue: (...00010) 2
// - AsnLen: Length = 1, LengthOfLength = 0
// Length: 1 bytes, LengthOfLength = 0
// AsnInt: 34 (0x22)
(byte)0x02, (byte)0x01, (byte)0x02,
// - UserIDs: 2
// - AsnIntegerHeader:
// - AsnId: Integer type (Universal 2)
// - LowTag:
// Class: (00......) Universal (0)
// Type: (..0.....) Primitive
// TagValue: (...00010) 2
// - AsnLen: Length = 1, LengthOfLength = 0
// Length: 1 bytes, LengthOfLength = 0
// AsnInt: 2 (0x2)
(byte)0x02, (byte)0x01, (byte)0x00,
// - TokenIds: 0
// - AsnIntegerHeader:
// - AsnId: Integer type (Universal 2)
// - LowTag:
// Class: (00......) Universal (0)
// Type: (..0.....) Primitive
// TagValue: (...00010) 2
// - AsnLen: Length = 1, LengthOfLength = 0
// Length: 1 bytes, LengthOfLength = 0
// AsnInt: 0 (0x0)
(byte)0x02, (byte)0x01, (byte)0x01,
// - NumPriorities: 1
// - AsnIntegerHeader:
// - AsnId: Integer type (Universal 2)
// - LowTag:
// Class: (00......) Universal (0)
// Type: (..0.....) Primitive
// TagValue: (...00010) 2
// - AsnLen: Length = 1, LengthOfLength = 0
// Length: 1 bytes, LengthOfLength = 0
// AsnInt: 1 (0x1)
(byte)0x02, (byte)0x01, (byte)0x00,
// - MinThroughput: 0
// - AsnIntegerHeader:
// - AsnId: Integer type (Universal 2)
// - LowTag:
// Class: (00......) Universal (0)
// Type: (..0.....) Primitive
// TagValue: (...00010) 2
// - AsnLen: Length = 1, LengthOfLength = 0
// Length: 1 bytes, LengthOfLength = 0
// AsnInt: 0 (0x0)
(byte)0x02, (byte)0x01, (byte)0x01,
// - Height: 1
// - AsnIntegerHeader:
// - AsnId: Integer type (Universal 2)
// - LowTag:
// Class: (00......) Universal (0)
// Type: (..0.....) Primitive
// TagValue: (...00010) 2
// - AsnLen: Length = 1, LengthOfLength = 0
// Length: 1 bytes, LengthOfLength = 0
// AsnInt: 1 (0x1)
(byte)0x02, (byte)0x03, (byte)0x00, (byte)0xFF, (byte)0xFF,
// - MCSPDUsize: 65535
// - AsnIntegerHeader:
// - AsnId: Integer type (Universal 2)
// - LowTag:
// Class: (00......) Universal (0)
// Type: (..0.....) Primitive
// TagValue: (...00010) 2
// - AsnLen: Length = 3, LengthOfLength = 0
// Length: 3 bytes, LengthOfLength = 0
// AsnInt: 65535 (0xFFFF)
(byte)0x02, (byte)0x01, (byte)0x02,
// - protocolVersion: 2
// - AsnIntegerHeader:
// - AsnId: Integer type (Universal 2)
// - LowTag:
// Class: (00......) Universal (0)
// Type: (..0.....) Primitive
// TagValue: (...00010) 2
// - AsnLen: Length = 1, LengthOfLength = 0
// Length: 1 bytes, LengthOfLength = 0
// AsnInt: 2 (0x2)
//
// - MinimumParameters: Length = 25, LengthOfLength = 0
(byte)0x30, (byte)0x19,
// - DomainParametersHeader: 0x1
// - AsnId: Sequence and SequenceOf types (Universal 16)
// - LowTag:
// Class: (00......) Universal (0)
// Type: (..1.....) Constructed
// TagValue: (...10000) 16
// - AsnLen: Length = 25, LengthOfLength = 0
// Length: 25 bytes, LengthOfLength = 0
(byte)0x02, (byte)0x01, (byte)0x01,
// - ChannelIds: 1
// - AsnIntegerHeader:
// - AsnId: Integer type (Universal 2)
// - LowTag:
// Class: (00......) Universal (0)
// Type: (..0.....) Primitive
// TagValue: (...00010) 2
// - AsnLen: Length = 1, LengthOfLength = 0
// Length: 1 bytes, LengthOfLength = 0
// AsnInt: 1 (0x1)
(byte)0x02, (byte)0x01, (byte)0x01,
// - UserIDs: 1
// - AsnIntegerHeader:
// - AsnId: Integer type (Universal 2)
// - LowTag:
// Class: (00......) Universal (0)
// Type: (..0.....) Primitive
// TagValue: (...00010) 2
// - AsnLen: Length = 1, LengthOfLength = 0
// Length: 1 bytes, LengthOfLength = 0
// AsnInt: 1 (0x1)
(byte)0x02, (byte)0x01, (byte)0x01,
// - TokenIds: 1
// - AsnIntegerHeader:
// - AsnId: Integer type (Universal 2)
// - LowTag:
// Class: (00......) Universal (0)
// Type: (..0.....) Primitive
// TagValue: (...00010) 2
// - AsnLen: Length = 1, LengthOfLength = 0
// Length: 1 bytes, LengthOfLength = 0
// AsnInt: 1 (0x1)
(byte)0x02, (byte)0x01, (byte)0x01,
// - NumPriorities: 1
// - AsnIntegerHeader:
// - AsnId: Integer type (Universal 2)
// - LowTag:
// Class: (00......) Universal (0)
// Type: (..0.....) Primitive
// TagValue: (...00010) 2
// - AsnLen: Length = 1, LengthOfLength = 0
// Length: 1 bytes, LengthOfLength = 0
// AsnInt: 1 (0x1)
(byte)0x02, (byte)0x01, (byte)0x00,
// - MinThroughput: 0
// - AsnIntegerHeader:
// - AsnId: Integer type (Universal 2)
// - LowTag:
// Class: (00......) Universal (0)
// Type: (..0.....) Primitive
// TagValue: (...00010) 2
// - AsnLen: Length = 1, LengthOfLength = 0
// Length: 1 bytes, LengthOfLength = 0
// AsnInt: 0 (0x0)
(byte)0x02, (byte)0x01, (byte)0x01,
// - Height: 1
// - AsnIntegerHeader:
// - AsnId: Integer type (Universal 2)
// - LowTag:
// Class: (00......) Universal (0)
// Type: (..0.....) Primitive
// TagValue: (...00010) 2
// - AsnLen: Length = 1, LengthOfLength = 0
// Length: 1 bytes, LengthOfLength = 0
// AsnInt: 1 (0x1)
(byte)0x02, (byte)0x02, (byte)0x04, (byte)0x20,
// - MCSPDUsize: 1056
// - AsnIntegerHeader:
// - AsnId: Integer type (Universal 2)
// - LowTag:
// Class: (00......) Universal (0)
// Type: (..0.....) Primitive
// TagValue: (...00010) 2
// - AsnLen: Length = 2, LengthOfLength = 0
// Length: 2 bytes, LengthOfLength = 0
// AsnInt: 1056 (0x420)
(byte)0x02, (byte)0x01, (byte)0x02,
// - protocolVersion: 2
// - AsnIntegerHeader:
// - AsnId: Integer type (Universal 2)
// - LowTag:
// Class: (00......) Universal (0)
// Type: (..0.....) Primitive
// TagValue: (...00010) 2
// - AsnLen: Length = 1, LengthOfLength = 0
// Length: 1 bytes, LengthOfLength = 0
// AsnInt: 2 (0x2)
// - MaximumParameters: Length = 31, LengthOfLength = 0
// - DomainParametersHeader: 0x1
(byte)0x30, (byte)0x1F,
// - AsnId: Sequence and SequenceOf types (Universal 16)
// - LowTag:
// Class: (00......) Universal (0)
// Type: (..1.....) Constructed
// TagValue: (...10000) 16
// - AsnLen: Length = 31, LengthOfLength = 0
// Length: 31 bytes, LengthOfLength = 0
(byte)0x02, (byte)0x03, (byte)0x00, (byte)0xFF, (byte)0xFF,
// - ChannelIds: 65535
// - AsnIntegerHeader:
// - AsnId: Integer type (Universal 2)
// - LowTag:
// Class: (00......) Universal (0)
// Type: (..0.....) Primitive
// TagValue: (...00010) 2
// - AsnLen: Length = 3, LengthOfLength = 0
// Length: 3 bytes, LengthOfLength = 0
// AsnInt: 65535 (0xFFFF)
(byte)0x02, (byte)0x02, (byte)0xFC, (byte)0x17,
// - UserIDs: 64535
// - AsnIntegerHeader:
// - AsnId: Integer type (Universal 2)
// - LowTag:
// Class: (00......) Universal (0)
// Type: (..0.....) Primitive
// TagValue: (...00010) 2
// - AsnLen: Length = 2, LengthOfLength = 0
// Length: 2 bytes, LengthOfLength = 0
// AsnInt: 64535 (0xFC17)
(byte)0x02, (byte)0x03, (byte)0x00, (byte)0xFF, (byte)0xFF,
// - TokenIds: 65535
// - AsnIntegerHeader:
// - AsnId: Integer type (Universal 2)
// - LowTag:
// Class: (00......) Universal (0)
// Type: (..0.....) Primitive
// TagValue: (...00010) 2
// - AsnLen: Length = 3, LengthOfLength = 0
// Length: 3 bytes, LengthOfLength = 0
// AsnInt: 65535 (0xFFFF)
(byte)0x02, (byte)0x01, (byte)0x01,
// - NumPriorities: 1
// - AsnIntegerHeader:
// - AsnId: Integer type (Universal 2)
// - LowTag:
// Class: (00......) Universal (0)
// Type: (..0.....) Primitive
// TagValue: (...00010) 2
// - AsnLen: Length = 1, LengthOfLength = 0
// Length: 1 bytes, LengthOfLength = 0
// AsnInt: 1 (0x1)
(byte)0x02, (byte)0x01, (byte)0x00,
// - MinThroughput: 0
// - AsnIntegerHeader:
// - AsnId: Integer type (Universal 2)
// - LowTag:
// Class: (00......) Universal (0)
// Type: (..0.....) Primitive
// TagValue: (...00010) 2
// - AsnLen: Length = 1, LengthOfLength = 0
// Length: 1 bytes, LengthOfLength = 0
// AsnInt: 0 (0x0)
(byte)0x02, (byte)0x01, (byte)0x01,
// - Height: 1
// - AsnIntegerHeader:
// - AsnId: Integer type (Universal 2)
// - LowTag:
// Class: (00......) Universal (0)
// Type: (..0.....) Primitive
// TagValue: (...00010) 2
// - AsnLen: Length = 1, LengthOfLength = 0
// Length: 1 bytes, LengthOfLength = 0
// AsnInt: 1 (0x1)
(byte)0x02, (byte)0x03, (byte)0x00, (byte)0xFF, (byte)0xFF,
// - MCSPDUsize: 65535
// - AsnIntegerHeader:
// - AsnId: Integer type (Universal 2)
// - LowTag:
// Class: (00......) Universal (0)
// Type: (..0.....) Primitive
// TagValue: (...00010) 2
// - AsnLen: Length = 3, LengthOfLength = 0
// Length: 3 bytes, LengthOfLength = 0
// AsnInt: 65535 (0xFFFF)
(byte)0x02, (byte)0x01, (byte)0x02,
// - protocolVersion: 2
// - AsnIntegerHeader:
// - AsnId: Integer type (Universal 2)
// - LowTag:
// Class: (00......) Universal (0)
// Type: (..0.....) Primitive
// TagValue: (...00010) 2
// - AsnLen: Length = 1, LengthOfLength = 0
// Length: 1 bytes, LengthOfLength = 0
// AsnInt: 2 (0x2)
// - UserData: Identifier=Generic Conference Contro (0.0.20.124.0.1), ConnectPDULength=254
// - UserDataHeader:
(byte)0x04, (byte)0x82, (byte)0x01, (byte)0x07,
// - AsnId: OctetString type (Universal 4)
// - LowTag:
// Class: (00......) Universal (0)
// Type: (..0.....) Primitive
// TagValue: (...00100) 4
// - AsnLen: Length = 263, LengthOfLength = 2
// LengthType: LengthOfLength = 2
// Length: 263 bytes
(byte)0x00, (byte)0x05, (byte)0x00, (byte)0x14, (byte)0x7C, (byte)0x00, (byte)0x01,
// - AsnBerObjectIdentifier: Generic Conference Contro (0.0.20.124.0.1)
// - AsnObjectIdentifierHeader:
// - AsnId: Reserved for use by the encoding rules (Universal 0)
// - LowTag:
// Class: (00......) Universal (0)
// Type: (..0.....) Primitive
// TagValue: (...00000) 0
// - AsnLen: Length = 5, LengthOfLength = 0
// Length: 5 bytes, LengthOfLength = 0
// First: 0 (0x0)
// Final: 20 (0x14)
// Final: 124 (0x7C)
// Final: 0 (0x0)
// Final: 1 (0x1)
(byte)0x80, (byte)0xFE,
// - ConnectPDULength: 254
// Align: No Padding
// Length: 254
(byte)0x00, (byte)0x08, (byte)0x00, (byte)0x10,
// - ConnectGCCPDU: conferenceCreateRequest
// ExtensionBit: 0 (0x0)
// - ChoiceValue: conferenceCreateRequest
// Value: (000.....) 0x0
// - conferenceCreateRequest:
// ExtensionBit: 0 (0x0)
// convenerPasswordPresent: 0 (0x0)
// passwordPresent: 0 (0x0)
// conductorPrivilegesPresent: 0 (0x0)
// conductedPrivilegesPresent: 0 (0x0)
// nonConductedPrivilegesPresent: 0 (0x0)
// conferenceDescriptionPresent: 0 (0x0)
// callerIdentifierPresent: 0 (0x0)
// userDataPresent: 1 (0x1)
// - conferenceName:
// ExtensionBit: 0 (0x0)
// textPresent: 0 (0x0)
// - numeric: 1
// - SimpleNumericString: 1
// - NumericString: 1
// - Align: No Padding
// Padding1: (0.......) 0x0
// - Length: 1
// Value: (00000000) 0x0
// - Restrictedstr: 1
// FourBits: (0001....) 0x1
// - lockedConference: False
// Value: False 0.......
// - listedConference: False
// Value: False 0.......
// - conductibleConference: False
// Value: False 0.......
// - TerminationMethod: automatic
// ExtensionBit: 0 (0x0)
// - RootIndex: 0
// Value: (0.......) 0x0
// - userData:
(byte)0x00, (byte)0x01,
// - Size: 1
// - Align: No Padding
// Padding7: (0000000.) 0x0
// Length: 1
// - UserData: 0x44756361
(byte)0xC0, (byte)0x00, (byte)0x44, (byte)0x75, (byte)0x63, (byte)0x61,
// valuePresent: 1 (0x1)
// - key: h221NonStandard "Duca"
// - ChoiceValue: h221NonStandard
// Value: (1.......) 0x1
// - h221NonStandard:
// - H221NonStandardIdentifier: length: 4
// - ConstrainedLength: 4
// Value: (00000000) 0x0
// - Align: No Padding
// Padding6: (000000..) 0x0
// Value: Binary Large Object (4 Bytes) "Duca"
// - ClientMcsConnectInitialPdu:
(byte)0x80, (byte)0xF0,
// - RDPGCCUserDataRequestLength: 240
// Align: No Padding
// Length: 240
// - TsUd: CS_CORE
(byte)0x01, (byte)0xC0, (byte)0xD8, (byte)0x00,
// - TsUdHeader: Type = CS_CORE, Length = 216
// Type: CS_CORE
// Length: 216 (0xD8)
// - TsUdCsCore:
(byte)0x04, (byte)0x00, (byte)0x08, (byte)0x00,
// Version: RDP 5.0, 5.1, 5.2, 6.0, 6.1, and 7.0
(byte)0x00, (byte)0x04,
// DesktopWidth: 1024 (0x400)
(byte)0x00, (byte)0x03,
// DesktopHeight: 768 (0x300)
(byte)0x01, (byte)0xCA,
// ColorDepth: 8 bpp
(byte)0x03, (byte)0xAA,
// SASSequence: 0xaa03, SHOULD be set to RNS_UD_SAS_DEL(0xAA03)
(byte)0x09, (byte)0x04, (byte)0x00, (byte)0x00,
// KeyboardLayout: Language: English, Location: United States
(byte)0x28, (byte)0x0A, (byte)0x00, (byte)0x00,
// ClientBuild: 2600 (0xA28)
(byte)0x61, (byte)0x00, (byte)0x70, (byte)0x00, (byte)0x6F, (byte)0x00, (byte)0x6C, (byte)0x00, (byte)0x6C, (byte)0x00, (byte)0x6F, (byte)0x00, (byte)0x33, (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)0x00, (byte)0x00, (byte)0x00,
// ClientName: apollo3
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
// KeyboardType: Undefined value: 0
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
// KeyboardSubType: 0 (0x0)
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
// KeyboardFunctionKey: 0 (0x0)
(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)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)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)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,
// ImeFileName:
(byte)0x01, (byte)0xCA,
// PostBeta2ColorDepth: 8 bpp
(byte)0x01, (byte)0x00,
// ClientProductId: 0x1, SHOULD be set to initialized to 1
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
// SerialNumber: 0x0, SHOULD be set to 0
(byte)0x10, (byte)0x00,
// HighColorDepth: 16-bit 565 RGB
(byte)0x07, (byte)0x00,
// - SupportedColorDepth: 7 (0x7)
// Support24BPP: (...............1) Support 24BPP
// Support16BPP: (..............1.) Support 16BPP
// Support15BPP: (.............1..) Support 15BPP
// Support32BPP: (............0...) Not Support 32BPP
// Reserved: (000000000000....)
(byte)0x01, (byte)0x00,
// - EarlyCapabilityFlags: 1 (0x1)
// SupportSetErrorPdu: (...............1) Indicates that the client supports the Set Error Info PDU
// Want32BppSession: (..............0.) Client is not requesting 32BPP session
// SupportStatusInfoPdu: (.............0..) Client not supports the Server Status Info PDU
// StrongAsymmetricKeys: (............0...) Not support asymmetric keys larger than 512-bits
// Unused: (...........0....)
// ValidConnection: (..........0.....) Not Indicates ConnectionType field contains valid data
// SupportMonitorLayoutPdu: (.........0......) Not Indicates that the client supports the Monitor Layout PDU
// Unused2: (000000000.......)
(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)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)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)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,
// ClientDigProductId:
(byte)0x00,
// connectionType: invalid connection type
(byte)0x00,
// pad1octet: 0 (0x0)
(byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00,
// ServerSelectedProtocols: TLS 1.0
//
// - TsUd: CS_CLUSTER
// - TsUdHeader: Type = CS_CLUSTER, Length = 12
(byte)0x04, (byte)0xC0,
// Type: CS_CLUSTER
(byte)0x0C, (byte)0x00,
// Length: 12 (0xC)
(byte)0x0D, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
// - TsUdCsCluster:
// - Flags: 13 (0xD)
// RedirectedSupported: (...............................1) Support Redirected
// SessionIDFieldValid: (..............................0.) SessionID Field not Valid
// SupportedVersion: (..........................0011..) REDIRECTION_VERSION4
// RedirectedSmartcard: (.........................0......) Not Logon with Smartcard
// Unused: (0000000000000000000000000.......)
// RedirectedSessionID: 0 (0x0)
//
// - TsUd: CS_SECURITY
// - TsUdHeader: Type = CS_SECURITY, Length = 12
(byte)0x02, (byte)0xC0,
// Type: CS_SECURITY
(byte)0x0C, (byte)0x00,
// Length: 12 (0xC)
//
// - TsUdCsSec:
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
// - EncryptionMethod:
// Support40Bit: (...............................0) Not Support
// Support128Bit: (..............................0.) Not Support 128-bit
// Reserved1: (.............................0..)
// Support56Bit: (............................0...) Not Support 56-bit
// SupportFIPS: (...........................0....) Not Support FIPS Compliant
// Reserved2: (000000000000000000000000000.....)
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
// - ExtEncryptionMethod:
// Support40Bit: (...............................0) Not Support
// Support128Bit: (..............................0.) Not Support 128-bit
// Reserved1: (.............................0..)
// Support56Bit: (............................0...) Not Support 56-bit
// SupportFIPS: (...........................0....) Not Support FIPS Compliant
// Reserved2: (000000000000000000000000000.....)
});
/* @formatter:on */
buf.length = buf.cursor;
pushDataToOTOut(buf);
switchOff();
}
/**
* Example.
*
* @see http://msdn.microsoft.com/en-us/library/cc240836.aspx
*/
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[] {
// TPKT: TPKT version = 3
(byte) 0x03, (byte) 0x00,
// TPKT: Packet length: 378 bytes
(byte) 0x01, (byte) 0x78,
// X.224: Length indicator = 2
(byte) 0x02,
// X.224: Type: Data TPDU
(byte) 0xf0,
// X.224: EOT
(byte) 0x80,
// Captured packet
(byte)0x7f, (byte)0x65, (byte)0x82, (byte)0x01, (byte)0x6c, (byte)0x04, (byte)0x01, (byte)0x01, (byte)0x04,
(byte)0x01, (byte)0x01, (byte)0x01, (byte)0x01, (byte)0xff, (byte)0x30, (byte)0x1a, (byte)0x02, (byte)0x01, (byte)0x22, (byte)0x02, (byte)0x01, (byte)0x02, (byte)0x02, (byte)0x01, (byte)0x00,
(byte)0x02, (byte)0x01, (byte)0x01, (byte)0x02, (byte)0x01, (byte)0x00, (byte)0x02, (byte)0x01, (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x00, (byte)0xff, (byte)0xff, (byte)0x02, (byte)0x01,
(byte)0x02, (byte)0x30, (byte)0x19, (byte)0x02, (byte)0x01, (byte)0x01, (byte)0x02, (byte)0x01, (byte)0x01, (byte)0x02, (byte)0x01, (byte)0x01, (byte)0x02, (byte)0x01, (byte)0x01, (byte)0x02,
(byte)0x01, (byte)0x00, (byte)0x02, (byte)0x01, (byte)0x01, (byte)0x02, (byte)0x02, (byte)0x04, (byte)0x20, (byte)0x02, (byte)0x01, (byte)0x02, (byte)0x30, (byte)0x1f, (byte)0x02, (byte)0x03,
(byte)0x00, (byte)0xff, (byte)0xff, (byte)0x02, (byte)0x02, (byte)0xfc, (byte)0x17, (byte)0x02, (byte)0x03, (byte)0x00, (byte)0xff, (byte)0xff, (byte)0x02, (byte)0x01, (byte)0x01, (byte)0x02,
(byte)0x01, (byte)0x00, (byte)0x02, (byte)0x01, (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x00, (byte)0xff, (byte)0xff, (byte)0x02, (byte)0x01, (byte)0x02, (byte)0x04, (byte)0x82, (byte)0x01,
(byte)0x07, (byte)0x00, (byte)0x05, (byte)0x00, (byte)0x14, (byte)0x7c, (byte)0x00, (byte)0x01, (byte)0x80, (byte)0xfe, (byte)0x00, (byte)0x08, (byte)0x00, (byte)0x10, (byte)0x00, (byte)0x01,
(byte)0xc0, (byte)0x00, (byte)0x44, (byte)0x75, (byte)0x63, (byte)0x61, (byte)0x80, (byte)0xf0, (byte)0x01, (byte)0xc0, (byte)0xd8, (byte)0x00, (byte)0x04, (byte)0x00, (byte)0x08, (byte)0x00,
(byte)0x00, (byte)0x04, (byte)0x00, (byte)0x03, (byte)0x01, (byte)0xca, (byte)0x03, (byte)0xaa, (byte)0x09, (byte)0x04, (byte)0x00, (byte)0x00, (byte)0x28, (byte)0x0a, (byte)0x00, (byte)0x00,
(byte)0x61, (byte)0x00, (byte)0x70, (byte)0x00, (byte)0x6f, (byte)0x00, (byte)0x6c, (byte)0x00, (byte)0x6c, (byte)0x00, (byte)0x6f, (byte)0x00, (byte)0x33, (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)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)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)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)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)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)0x01, (byte)0xca, (byte)0x01, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x10, (byte)0x00, (byte)0x07, (byte)0x00, (byte)0x01, (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)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)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)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)0x00, (byte)0x00, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x04, (byte)0xc0, (byte)0x0c, (byte)0x00, (byte)0x0d, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x02, (byte)0xc0, (byte)0x0c, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
};
/* @formatter:on */
MockSource source = new MockSource("source", ByteBuffer.convertByteArraysToByteBuffers(new byte[] {1, 2, 3}));
Element todo = new ClientMCSConnectInitial("ClientMCSConnectInitial");
Element x224 = new ClientX224DataPdu("x224");
Element tpkt = new ClientTpkt("tpkt");
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, todo, x224, tpkt, sink, mainSink);
pipeline.link("source", "ClientMCSConnectInitial", "mainSink");
pipeline.link("ClientMCSConnectInitial >" + OTOUT, "x224", "tpkt", "sink");
pipeline.runMainLoop("source", STDOUT, false, false);
}
}

View File

@ -1,49 +0,0 @@
// 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;
/**
* Try to determine packet content by it header fingerprint.
*/
public class ClientPacketSniffer extends PacketSniffer {
private static final Pair[] clientRegexps = new Pair[] {
// @formatter:off
new Pair("Client FastPath input", "04"),
new Pair("Client X224ConnectionRequest", "03 00 XX XX 27 E0"),
new Pair("Client ConnectionRequest", "03 00 XX XX XX E0"),
new Pair("Client MCConnectInitial", "03 00 XX XX 02 F0 80 7F 65"),
new Pair("Client ErectDomainRequest", "03 00 XX XX 02 F0 80 04"),
new Pair("Client AttachUserRequest", "03 00 XX XX 02 F0 80 28"),
new Pair("Client ChannelJoinRequest", "03 00 XX XX 02 F0 80 38"),
new Pair("Client Info", "03 00 XX XX 02 F0 80 64 00 03 03 EB 70 XX XX XX XX 00 00"),
new Pair("Client ConfirmActivePDU", "03 00 XX XX 02 F0 80 64 00 03 03 EB 70 XX XX XX XX 13 00"),
new Pair("Client SynchronizePDU", "03 00 XX XX 02 F0 80 64 00 03 03 EB 70 XX XX XX XX 17 00 EC 03 EA 03 XX 00 XX XX XX XX 1F"),
new Pair("Client ControlPDU", "03 00 XX XX 02 F0 80 64 00 03 03 EB 70 XX XX XX XX 17 00 EC 03 EA 03 XX 00 XX XX XX XX 14"),
new Pair("Client FontListPDU", "03 00 XX XX 02 F0 80 64 00 03 03 EB 70 XX XX XX XX 17 00 EC 03 EA 03 XX 00 XX XX XX XX 27"),
new Pair("Client BitmapCachePersistentList","03 00 XX XX 02 F0 80 64 00 03 03 EB 70 XX XX XX XX 17 00 EC 03 EA 03 XX XX XX XX XX XX 2b"),
// new Pair("Client TPKT Unknown packet", "03"),
// new Pair("Client UNKNOWN PACKET (ERROR)", ".*"),
// @formatter:on
};
public ClientPacketSniffer(String id) {
super(id, clientRegexps);
}
}

View File

@ -1,985 +0,0 @@
// 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;
import streamer.AssertingByteBuffer;
import streamer.ByteBuffer;
/**
* Based on code example from MSDN, @see
* http://msdn.microsoft.com/en-us/library/dd240593.aspx .
*/
public class RLEBitmapDecompression {
public static final int g_MaskRegularRunLength = 0x1F;
public static final int g_MaskLiteRunLength = 0x0F;
public static final int g_MaskSpecialFgBg1 = 0x03;
public static final int g_MaskSpecialFgBg2 = 0x05;
public static final int REGULAR_BG_RUN = 0x00;
public static final int REGULAR_FG_RUN = 0x01;
public static final int REGULAR_FGBG_IMAGE = 0x02;
public static final int REGULAR_COLOR_RUN = 0x03;
public static final int REGULAR_COLOR_IMAGE = 0x04;
public static final int LITE_SET_FG_FG_RUN = 0x0C;
public static final int LITE_SET_FG_FGBG_IMAGE = 0x0D;
public static final int LITE_DITHERED_RUN = 0x0E;
public static final int MEGA_MEGA_BG_RUN = 0xF0;
public static final int MEGA_MEGA_FG_RUN = 0xF1;
public static final int MEGA_MEGA_FGBG_IMAGE = 0xF2;
public static final int MEGA_MEGA_COLOR_RUN = 0xF3;
public static final int MEGA_MEGA_COLOR_IMAGE = 0xF4;
public static final int MEGA_MEGA_SET_FG_RUN = 0xF6;
public static final int MEGA_MEGA_SET_FGBG_IMAGE = 0xF7;
public static final int MEGA_MEGA_DITHERED_RUN = 0xF8;
public static final int SPECIAL_FGBG_1 = 0xF9;
public static final int SPECIAL_FGBG_2 = 0xFA;
public static final int SPECIAL_WHITE = 0xFD;
public static final int SPECIAL_BLACK = 0xFE;
/**
* Writes a pixel to the specified buffer and advance cursor by bpp.
*
* @param bpp
* bytes per pixel
*/
private static void writePixel(int bpp, ByteBuffer destBuf, int pixel) {
switch (bpp) {
case 1:
destBuf.writeByte(pixel);
break;
case 2:
destBuf.writeShortLE(pixel);
break;
case 3:
destBuf.writeByte(pixel);
destBuf.writeShortLE(pixel >> 8);
break;
case 4:
destBuf.writeIntLE(pixel);
break;
default:
throw new RuntimeException("Unsupported color depth.");
}
}
/**
* Reads a pixel from the specified buffer at given offset without changing of
* cursor.
*
* @param bpp
* bytes per pixel
* @param offset
* -rowDelta (i.e. (-width*bpp))
*/
private static int peekPixel(int bpp, ByteBuffer destBuf, int offset) {
if (offset >= 0 || (-offset) > destBuf.cursor)
throw new RuntimeException("Incorrect value for offset: offset in destination buffer must point to pixel in previous row.");
// Adjust cursor to point to pixel in previous row
int oldCursor = destBuf.cursor;
destBuf.cursor += offset;
int pixel;
switch (bpp) {
case 1:
pixel = destBuf.readUnsignedByte();
break;
case 2:
pixel = destBuf.readUnsignedShortLE();
break;
case 3:
pixel = destBuf.readUnsignedByte() | (destBuf.readUnsignedShortLE() >> 8);
break;
case 4:
pixel = destBuf.readSignedIntLE();
break;
default:
throw new RuntimeException("Unsupported color depth.");
}
destBuf.cursor = oldCursor;
return pixel;
}
/**
* Reads a pixel from the specified buffer and advance cursor by bpp value.
*
* @param bpp
* bytes per pixel
*/
private static int readPixel(int bpp, ByteBuffer srcBuf) {
int pixel;
switch (bpp) {
case 1:
pixel = srcBuf.readUnsignedByte();
break;
case 2:
pixel = srcBuf.readUnsignedShortLE();
break;
case 3:
pixel = srcBuf.readUnsignedByte() | (srcBuf.readUnsignedShortLE() >> 8);
break;
case 4:
pixel = srcBuf.readSignedIntLE();
break;
default:
throw new RuntimeException("Unsupported color depth.");
}
return pixel;
}
/**
* Returns the size of a pixel in bytes.
*/
private static int getPixelSize(int colorDepth) {
switch (colorDepth) {
case 8:
return 1;
case 15:
case 16:
return 2;
case 24:
return 3;
default:
throw new RuntimeException("Unsupported pixel color depth: " + colorDepth + " bpp.");
}
}
/**
* Reads the supplied order header & extracts the compression order code ID.
*/
private static int extractCodeId(int orderHeader) {
// Taken from FreeRDP code, bitmap.c
switch (orderHeader) {
case MEGA_MEGA_BG_RUN:
case MEGA_MEGA_FG_RUN:
case MEGA_MEGA_SET_FG_RUN:
case MEGA_MEGA_DITHERED_RUN:
case MEGA_MEGA_COLOR_RUN:
case MEGA_MEGA_FGBG_IMAGE:
case MEGA_MEGA_SET_FGBG_IMAGE:
case MEGA_MEGA_COLOR_IMAGE:
case SPECIAL_FGBG_1:
case SPECIAL_FGBG_2:
case SPECIAL_WHITE:
case SPECIAL_BLACK:
return orderHeader;
}
int code = orderHeader >> 5;
switch (code) {
case REGULAR_BG_RUN:
case REGULAR_FG_RUN:
case REGULAR_COLOR_RUN:
case REGULAR_FGBG_IMAGE:
case REGULAR_COLOR_IMAGE:
return code;
}
return orderHeader >> 4;
}
/**
* Returns a black pixel.
*/
private static int getColorBlack() {
return 0x000000;
}
/**
* Returns a white pixel.
*/
private static int getColorWhite(int colorDepth) {
if (colorDepth == 8) {
//
// Palette entry #255 holds white.
//
return 0xFF;
} else if (colorDepth == 15) {
//
// 5 bits per RGB component:
// 0111 1111 1111 1111 (binary)
//
return 0x7FFF;
} else if (colorDepth == 16) {
//
// 5 bits for red, 6 bits for green, 5 bits for green:
// 1111 1111 1111 1111 (binary)
//
return 0xFFFF;
} else if (colorDepth == 24) {
//
// 8 bits per RGB component:
// 1111 1111 1111 1111 1111 1111 (binary)
//
return 0xFFFFFF;
} else
throw new RuntimeException("Unsupported color depth.");
}
/**
* Extract the run length of a compression order.
*/
private static int extractRunLength(int code, int orderHeader, ByteBuffer srcBuf) {
switch (code) {
case REGULAR_FGBG_IMAGE: {
int runLength = orderHeader & g_MaskRegularRunLength;
if (runLength == 0)
runLength = srcBuf.readUnsignedByte() + 1;
else
runLength = runLength * 8;
return runLength;
}
case LITE_SET_FG_FGBG_IMAGE: {
int runLength = orderHeader & g_MaskLiteRunLength;
if (runLength == 0)
runLength = srcBuf.readUnsignedByte() + 1;
else
runLength = runLength * 8;
return runLength;
}
case REGULAR_BG_RUN:
case REGULAR_COLOR_IMAGE:
case REGULAR_COLOR_RUN:
case REGULAR_FG_RUN: {
int runLength = orderHeader & g_MaskRegularRunLength;
if (runLength == 0)
// An extended (MEGA) run.
runLength = srcBuf.readUnsignedByte() + 32;
return runLength;
}
case LITE_DITHERED_RUN:
case LITE_SET_FG_FG_RUN: {
int runLength = orderHeader & g_MaskLiteRunLength;
if (runLength == 0)
// An extended (MEGA) run.
runLength = srcBuf.readUnsignedByte() + 16;
return runLength;
}
case MEGA_MEGA_BG_RUN:
case MEGA_MEGA_COLOR_IMAGE:
case MEGA_MEGA_COLOR_RUN:
case MEGA_MEGA_DITHERED_RUN:
case MEGA_MEGA_FG_RUN:
case MEGA_MEGA_FGBG_IMAGE:
case MEGA_MEGA_SET_FG_RUN:
case MEGA_MEGA_SET_FGBG_IMAGE: {
return srcBuf.readUnsignedShortLE();
}
default:
return 0;
}
}
/**
* Write a foreground/background image to a destination buffer.
*/
private static void writeFgBgImage(int bpp, ByteBuffer destBuf, int rowDelta, int bitmask, int fgPel, int cBits) {
for (; cBits > 0; cBits--, bitmask >>= 1) {
int xorPixel = peekPixel(bpp, destBuf, -rowDelta);
writePixel(bpp, destBuf, ((bitmask & 0x1) > 0) ? xorPixel ^ fgPel : xorPixel);
}
}
/**
* Write a foreground/background image to a destination buffer for the first
* line of compressed data.
*/
private static void writeFirstLineFgBgImage(int bpp, ByteBuffer destBuf, int bitmask, int fgPel, int cBits) {
for (; cBits > 0; cBits--, bitmask >>= 1) {
writePixel(bpp, destBuf, ((bitmask & 0x1) > 0) ? fgPel : getColorBlack());
}
}
/**
* Decompress a RLE compressed bitmap and flip decompressed image.
*
* @param srcBuf
* source buffer containing compressed bitmap
* @param imageWidth
* width of destination image in pixels
* @param imageHeight
* height of destination image in pixels
* @param colorDepth
* bits per pixel
* @return destination image buffer
*/
public static ByteBuffer rleDecompress(ByteBuffer srcBuf, int imageWidth, int imageHeight, int colorDepth) {
int bpp = getPixelSize(colorDepth);
// Decompress image
ByteBuffer destBuf = new ByteBuffer(new byte[imageWidth * imageHeight * bpp]);
rleDecompress(srcBuf, destBuf, imageWidth, imageHeight, colorDepth);
// Flip image
return flipRawImage(destBuf, imageWidth, imageHeight, bpp);
}
/**
* Decompress a RLE compressed bitmap.
*
* @param srcBuf
* source buffer containing compressed bitmap
* @param destBuf
* destination buffer
* @param imageWidth
* width of destination image in pixels
* @param imageHeight
* height of destination image in pixels
* @param colorDepth
* bits per pixel
*/
protected static void rleDecompress(final ByteBuffer srcBuf, final ByteBuffer destBuf, final int imageWidth, final int imageHeight, final int colorDepth) {
final int bpp = getPixelSize(colorDepth);
final int rowDelta = imageWidth * bpp;
final int whitePixel = getColorWhite(colorDepth);
final int blackPixel = getColorBlack();
int fgPel = whitePixel;
boolean insertFgPel = false;
boolean firstLine = true;
if (destBuf.length != imageWidth * imageHeight * bpp)
throw new RuntimeException("Incorrect size of destination buffer. Expected size (imageWidth*imageHeight*bpp): " + (imageWidth * imageHeight * bpp) +
", actual size: " + destBuf.length + ".");
while (srcBuf.cursor < srcBuf.length) {
// Watch out for the end of the first scanline in destination buffer.
if (firstLine) {
if (destBuf.cursor >= rowDelta) {
firstLine = false;
insertFgPel = false;
}
}
// Extract the compression order code ID from the compression
// order header.
int orderHeader = srcBuf.readUnsignedByte();
int code = extractCodeId(orderHeader);
// Handle Background Run Orders.
if (code == REGULAR_BG_RUN | code == MEGA_MEGA_BG_RUN) {
int runLength = extractRunLength(code, orderHeader, srcBuf);
if (firstLine) {
if (insertFgPel) {
writePixel(bpp, destBuf, fgPel);
runLength--;
}
for (; runLength > 0; runLength--)
writePixel(bpp, destBuf, blackPixel);
} else {
if (insertFgPel) {
writePixel(bpp, destBuf, peekPixel(bpp, destBuf, -rowDelta) ^ fgPel);
runLength--;
}
// Copy pixels from previous row of destination image
for (; runLength > 0; runLength--)
writePixel(bpp, destBuf, peekPixel(bpp, destBuf, -rowDelta));
}
//
// A follow-on background run order will need a
// foreground pel inserted.
//
insertFgPel = true;
continue;
}
//
// For any of the other run-types a follow-on background run
// order does not need a foreground pel inserted.
//
insertFgPel = false;
//
// Handle Foreground Run Orders.
//
if (code == REGULAR_FG_RUN | code == MEGA_MEGA_FG_RUN | code == LITE_SET_FG_FG_RUN | code == MEGA_MEGA_SET_FG_RUN) {
int runLength = extractRunLength(code, orderHeader, srcBuf);
if (code == LITE_SET_FG_FG_RUN | code == MEGA_MEGA_SET_FG_RUN)
fgPel = readPixel(bpp, srcBuf);
if (firstLine) {
for (; runLength > 0; runLength--) {
writePixel(bpp, destBuf, fgPel);
}
} else {
for (; runLength > 0; runLength--) {
writePixel(bpp, destBuf, peekPixel(bpp, destBuf, -rowDelta) ^ fgPel);
}
}
continue;
}
//
// Handle Dithered Run Orders.
//
if (code == LITE_DITHERED_RUN | code == MEGA_MEGA_DITHERED_RUN) {
int runLength = extractRunLength(code, orderHeader, srcBuf);
int pixelA = readPixel(bpp, srcBuf);
int pixelB = readPixel(bpp, srcBuf);
for (; runLength > 0; runLength--) {
writePixel(bpp, destBuf, pixelA);
writePixel(bpp, destBuf, pixelB);
}
continue;
}
//
// Handle Color Run Orders.
//
if (code == REGULAR_COLOR_RUN | code == MEGA_MEGA_COLOR_RUN) {
int runLength = extractRunLength(code, orderHeader, srcBuf);
int pixelA = readPixel(bpp, srcBuf);
for (; runLength > 0; runLength--)
writePixel(bpp, destBuf, pixelA);
continue;
}
//
// Handle Foreground/Background Image Orders.
//
if (code == REGULAR_FGBG_IMAGE | code == MEGA_MEGA_FGBG_IMAGE | code == LITE_SET_FG_FGBG_IMAGE | code == MEGA_MEGA_SET_FGBG_IMAGE) {
int runLength = extractRunLength(code, orderHeader, srcBuf);
if (code == LITE_SET_FG_FGBG_IMAGE | code == MEGA_MEGA_SET_FGBG_IMAGE) {
fgPel = readPixel(bpp, srcBuf);
}
for (; runLength > 8; runLength -= 8) {
int bitmask = srcBuf.readUnsignedByte();
if (firstLine)
writeFirstLineFgBgImage(bpp, destBuf, bitmask, fgPel, 8);
else
writeFgBgImage(bpp, destBuf, rowDelta, bitmask, fgPel, 8);
}
if (runLength > 0) {
int bitmask = srcBuf.readUnsignedByte();
if (firstLine)
writeFirstLineFgBgImage(bpp, destBuf, bitmask, fgPel, runLength);
else
writeFgBgImage(bpp, destBuf, rowDelta, bitmask, fgPel, runLength);
}
continue;
}
//
// Handle Color Image Orders.
//
if (code == REGULAR_COLOR_IMAGE | code == MEGA_MEGA_COLOR_IMAGE) {
int runLength = extractRunLength(code, orderHeader, srcBuf);
/* DEBUG */
// Copy bytes from source to destination using writeByte(readByte())
// for (int byteCount = runLength * bpp; byteCount > 0; byteCount--) {
// destBuf.writeByte(srcBuf.readUnsignedByte());
// }
/* DEBUG */
// Copy bytes from source to destination directly using arraycopy()
int lengthInBytes = runLength * bpp;
System.arraycopy(srcBuf.data, srcBuf.offset + srcBuf.cursor, destBuf.data, destBuf.offset + destBuf.cursor, lengthInBytes);
srcBuf.cursor += lengthInBytes;
destBuf.cursor += lengthInBytes;
continue;
}
//
// Handle Special Order 1.
//
if (code == SPECIAL_FGBG_1) {
if (firstLine)
writeFirstLineFgBgImage(bpp, destBuf, g_MaskSpecialFgBg1, fgPel, 8);
else
writeFgBgImage(bpp, destBuf, rowDelta, g_MaskSpecialFgBg1, fgPel, 8);
continue;
}
//
// Handle Special Order 2.
//
if (code == SPECIAL_FGBG_2) {
if (firstLine)
writeFirstLineFgBgImage(bpp, destBuf, g_MaskSpecialFgBg2, fgPel, 8);
else
writeFgBgImage(bpp, destBuf, rowDelta, g_MaskSpecialFgBg2, fgPel, 8);
continue;
}
//
// Handle White Order.
//
if (code == SPECIAL_WHITE) {
writePixel(bpp, destBuf, whitePixel);
continue;
}
//
// Handle Black Order.
//
if (code == SPECIAL_BLACK) {
writePixel(bpp, destBuf, blackPixel);
continue;
}
throw new RuntimeException("Unknown code: " + code + ".");
}
}
/**
* Flip image in vertical direction.
*/
public static ByteBuffer flipRawImage(ByteBuffer src, int width, int height, int bpp) {
if (width * height * bpp != src.length)
throw new RuntimeException("Incorrect size of buffer. Expected size (imageWidth*imageHeight*bpp): " + (width * height * bpp) + ", actual size: " +
src.length + ".");
ByteBuffer dest = new ByteBuffer(new byte[src.length]);
int scanLine = width * bpp;
for (int i = 0; i < height; i++) {
// Copy one row
System.arraycopy(src.data, (height - i - 1) * scanLine, dest.data, i * scanLine, scanLine);
}
return dest;
}
/**
* Example.
*/
public static void main(String args[]) {
if (true) {
// 16x1@8bpp, all black
int width = 16, height = 1, depth = 8, bpp = depth / 8;
ByteBuffer src = new ByteBuffer(new byte[] {0x10});
ByteBuffer dest = new AssertingByteBuffer(new byte[width * height * bpp]);
rleDecompress(src, dest, width, height, depth);
}
if (true) {
// 16x1@16bpp, all black
int width = 16, height = 1, depth = 16, bpp = depth / 8;
ByteBuffer src = new ByteBuffer(new byte[] {0x0c, (byte)0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
ByteBuffer dest = new AssertingByteBuffer(new byte[width * height * bpp]);
rleDecompress(src, dest, width, height, depth);
}
if (true) {
// 32x32@8
int width = 32, height = 32, depth = 8, bpp = depth / 8;
ByteBuffer src =
new ByteBuffer(new byte[] {(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x80, (byte)0x00, (byte)0x06, (byte)0x06, (byte)0xed, (byte)0x06,
(byte)0x06, (byte)0x06, (byte)0xed, (byte)0x06, (byte)0x06, (byte)0x06, (byte)0xec, (byte)0x6c, (byte)0x0e, (byte)0x0e, (byte)0x44, (byte)0x0e,
(byte)0x0e, (byte)0x0e, (byte)0x13, (byte)0x06, (byte)0x06, (byte)0x06, (byte)0xed, (byte)0x06, (byte)0x06, (byte)0x06, (byte)0xed, (byte)0x06,
(byte)0x06, (byte)0x06, (byte)0x00, (byte)0x00, (byte)0xe4, (byte)0x04, (byte)0x06, (byte)0x8e, (byte)0x60, (byte)0x0e, (byte)0x60, (byte)0x8c,
(byte)0xb4, (byte)0xb5, (byte)0xdc, (byte)0xdc, (byte)0xbb, (byte)0xb4, (byte)0x8c, (byte)0x66, (byte)0x0b, (byte)0x6c, (byte)0xe4, (byte)0x04,
(byte)0x06, (byte)0x02, (byte)0x8b, (byte)0x06, (byte)0x06, (byte)0xed, (byte)0x06, (byte)0xed, (byte)0x06, (byte)0xf8, (byte)0x0e, (byte)0x66,
(byte)0xb4, (byte)0xdc, (byte)0x68, (byte)0xe2, (byte)0x97, (byte)0xdd, (byte)0xb4, (byte)0xa7, (byte)0x16, (byte)0x06, (byte)0x06, (byte)0x06,
(byte)0xed, (byte)0x06, (byte)0xed, (byte)0x06, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x06, (byte)0x04, (byte)0x06, (byte)0x00, (byte)0x06,
(byte)0x0b, (byte)0xae, (byte)0xdc, (byte)0xe9, (byte)0x6a, (byte)0xdc, (byte)0x96, (byte)0xe9, (byte)0xe9, (byte)0xb4, (byte)0x0e, (byte)0x00,
(byte)0x06, (byte)0x04, (byte)0x06, (byte)0x00, (byte)0x06, (byte)0x00, (byte)0x00, (byte)0x06, (byte)0x06, (byte)0xed, (byte)0x06, (byte)0x06,
(byte)0x0e, (byte)0xae, (byte)0xdc, (byte)0xdb, (byte)0xdb, (byte)0xd0, (byte)0x09, (byte)0x07, (byte)0xcf, (byte)0x03, (byte)0x95, (byte)0xdb,
(byte)0xdb, (byte)0xdc, (byte)0xb4, (byte)0x66, (byte)0x6c, (byte)0xed, (byte)0x06, (byte)0x06, (byte)0x06, (byte)0x00, (byte)0x00, (byte)0x04,
(byte)0x06, (byte)0x04, (byte)0x06, (byte)0x0b, (byte)0xae, (byte)0xdb, (byte)0xd4, (byte)0xd5, (byte)0x6c, (byte)0xdb, (byte)0x80, (byte)0xaf,
(byte)0xd5, (byte)0xd4, (byte)0xdb, (byte)0xb4, (byte)0x66, (byte)0x04, (byte)0x06, (byte)0x04, (byte)0x06, (byte)0x00, (byte)0x00, (byte)0xed,
(byte)0x06, (byte)0xed, (byte)0x66, (byte)0xae, (byte)0xd5, (byte)0xad, (byte)0xd4, (byte)0xd4, (byte)0xd5, (byte)0xd5, (byte)0xd5, (byte)0xdb,
(byte)0xb4, (byte)0xb4, (byte)0xb4, (byte)0xb4, (byte)0xb4, (byte)0xd5, (byte)0xd5, (byte)0xd5, (byte)0xd4, (byte)0xd4, (byte)0xad, (byte)0xd5,
(byte)0xb4, (byte)0x0e, (byte)0x06, (byte)0x06, (byte)0x06, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x06, (byte)0x60, (byte)0xa7, (byte)0xb4,
(byte)0xad, (byte)0xad, (byte)0xad, (byte)0xb3, (byte)0xb3, (byte)0xd4, (byte)0xd4, (byte)0xb3, (byte)0x8c, (byte)0xb6, (byte)0x07, (byte)0xb6,
(byte)0x8c, (byte)0xb3, (byte)0xd4, (byte)0xb3, (byte)0xb3, (byte)0xad, (byte)0xad, (byte)0xad, (byte)0xb4, (byte)0xad, (byte)0x66, (byte)0x00,
(byte)0x06, (byte)0x00, (byte)0x00, (byte)0x06, (byte)0x06, (byte)0x66, (byte)0xae, (byte)0xad, (byte)0x8b, (byte)0xad, (byte)0xad, (byte)0xad,
(byte)0xad, (byte)0xad, (byte)0xb3, (byte)0xad, (byte)0xb5, (byte)0x07, (byte)0x07, (byte)0x07, (byte)0xf0, (byte)0x8b, (byte)0xad, (byte)0xad,
(byte)0xad, (byte)0xad, (byte)0xad, (byte)0x8b, (byte)0xa7, (byte)0xae, (byte)0xa7, (byte)0x6c, (byte)0x06, (byte)0x00, (byte)0x00, (byte)0x04,
(byte)0x6c, (byte)0xa7, (byte)0xad, (byte)0xa7, (byte)0xa7, (byte)0x8b, (byte)0xad, (byte)0xad, (byte)0xad, (byte)0xad, (byte)0xad, (byte)0xad,
(byte)0xb5, (byte)0xbd, (byte)0xbd, (byte)0xbd, (byte)0xbd, (byte)0xf0, (byte)0x8b, (byte)0x8b, (byte)0xad, (byte)0x8b, (byte)0x8b, (byte)0xa7,
(byte)0xa7, (byte)0xc8, (byte)0xc8, (byte)0x60, (byte)0x06, (byte)0x00, (byte)0x00, (byte)0x06, (byte)0x66, (byte)0xc8, (byte)0xa7, (byte)0x66,
(byte)0xa7, (byte)0xa7, (byte)0x8b, (byte)0x8b, (byte)0x8b, (byte)0x8b, (byte)0xad, (byte)0x8b, (byte)0x92, (byte)0xf1, (byte)0xf1, (byte)0xf1,
(byte)0xf1, (byte)0xf2, (byte)0x07, (byte)0xa7, (byte)0xa7, (byte)0x8b, (byte)0xa7, (byte)0xa7, (byte)0x66, (byte)0x66, (byte)0xc8, (byte)0x66,
(byte)0x06, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x60, (byte)0xa7, (byte)0x66, (byte)0x66, (byte)0x66, (byte)0xa7, (byte)0xa7, (byte)0xa7,
(byte)0xa7, (byte)0x8b, (byte)0x8b, (byte)0x8b, (byte)0xa7, (byte)0xb6, (byte)0xf3, (byte)0xf3, (byte)0xf3, (byte)0xf3, (byte)0xf3, (byte)0x07,
(byte)0x66, (byte)0xa7, (byte)0xa7, (byte)0x66, (byte)0x66, (byte)0x66, (byte)0xa7, (byte)0xa7, (byte)0x6c, (byte)0x00, (byte)0x00, (byte)0x6c,
(byte)0x04, (byte)0xa7, (byte)0x60, (byte)0x6b, (byte)0x66, (byte)0x99, (byte)0xb6, (byte)0xf5, (byte)0xf5, (byte)0xf5, (byte)0xf5, (byte)0xf5,
(byte)0xef, (byte)0x66, (byte)0x66, (byte)0x66, (byte)0x66, (byte)0x66, (byte)0x66, (byte)0xa7, (byte)0x66, (byte)0x00, (byte)0x00, (byte)0x60,
(byte)0xa7, (byte)0x66, (byte)0x60, (byte)0x66, (byte)0x66, (byte)0x8c, (byte)0xf1, (byte)0x6e, (byte)0xff, (byte)0x85, (byte)0xbd, (byte)0x66,
(byte)0x66, (byte)0x66, (byte)0x60, (byte)0x05, (byte)0x87, (byte)0x13, (byte)0x04, (byte)0x66, (byte)0x66, (byte)0x66, (byte)0x66, (byte)0xf4,
(byte)0x70, (byte)0xff, (byte)0x84, (byte)0xbd, (byte)0x66, (byte)0x66, (byte)0x66, (byte)0x05, (byte)0x85, (byte)0x0b, (byte)0xa7, (byte)0xb5,
(byte)0xae, (byte)0x8c, (byte)0xd0, (byte)0x13, (byte)0xc1, (byte)0x01, (byte)0x00, (byte)0x08, (byte)0x8e, (byte)0x8c, (byte)0xae, (byte)0xb5,
(byte)0xae, (byte)0x66, (byte)0x00, (byte)0x00, (byte)0x6c, (byte)0xae, (byte)0xbc, (byte)0xb5, (byte)0xb5, (byte)0xae, (byte)0xb5, (byte)0xd0,
(byte)0x0e, (byte)0x0c, (byte)0x01, (byte)0x00, (byte)0x90, (byte)0xf2, (byte)0xae, (byte)0xae, (byte)0xb5, (byte)0xb5, (byte)0xbc, (byte)0xb5,
(byte)0x66, (byte)0x00, (byte)0x00, (byte)0x04, (byte)0xae, (byte)0x0a, (byte)0xb5, (byte)0xb5, (byte)0xb5, (byte)0x68, (byte)0xae, (byte)0x82,
(byte)0x8c, (byte)0x0a, (byte)0x05, (byte)0x8c, (byte)0xf2, (byte)0xae, (byte)0xae, (byte)0xb5, (byte)0xb5, (byte)0xb5, (byte)0xbc, (byte)0xb5,
(byte)0x6c, (byte)0x00, (byte)0x00, (byte)0x06, (byte)0x05, (byte)0x81, (byte)0xd0, (byte)0x06, (byte)0x9a, (byte)0x8c, (byte)0x0a, (byte)0xff,
(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xf2, (byte)0xae, (byte)0xae, (byte)0xd0, (byte)0xb5, (byte)0xb5, (byte)0xb5, (byte)0x0a,
(byte)0xb5, (byte)0x6c, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x8b, (byte)0x0a, (byte)0xbc, (byte)0xb5, (byte)0xb5, (byte)0xb5, (byte)0x06,
(byte)0x9b, (byte)0xb6, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xf2, (byte)0xae, (byte)0xae, (byte)0xae, (byte)0xb5,
(byte)0xb5, (byte)0xb5, (byte)0xb6, (byte)0x0a, (byte)0x8c, (byte)0x06, (byte)0x00, (byte)0x00, (byte)0x06, (byte)0x6c, (byte)0xb5, (byte)0x0a,
(byte)0xb6, (byte)0xb5, (byte)0xb5, (byte)0xb5, (byte)0x05, (byte)0x80, (byte)0x7d, (byte)0xbc, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
(byte)0xf2, (byte)0xae, (byte)0xae, (byte)0xae, (byte)0xb5, (byte)0xb5, (byte)0xb5, (byte)0xb6, (byte)0x0a, (byte)0x0a, (byte)0x8b, (byte)0x06,
(byte)0x00, (byte)0x00, (byte)0x04, (byte)0x06, (byte)0x87, (byte)0x0a, (byte)0xbc, (byte)0xb6, (byte)0xb5, (byte)0xb5, (byte)0xb5, (byte)0xd0,
(byte)0xae, (byte)0xae, (byte)0xae, (byte)0xb6, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xf2, (byte)0xd0, (byte)0xae, (byte)0xd0, (byte)0xb5,
(byte)0xb5, (byte)0xb5, (byte)0xb6, (byte)0xbc, (byte)0x1a, (byte)0xb5, (byte)0x04, (byte)0x06, (byte)0x00, (byte)0x00, (byte)0xed, (byte)0x06,
(byte)0x6e, (byte)0xb5, (byte)0x0a, (byte)0xbc, (byte)0xb6, (byte)0xb5, (byte)0xb5, (byte)0xb5, (byte)0xd0, (byte)0xd0, (byte)0xd0, (byte)0xb5,
(byte)0xf4, (byte)0xff, (byte)0xf2, (byte)0xd0, (byte)0xd0, (byte)0xd0, (byte)0xb5, (byte)0xb5, (byte)0xb5, (byte)0xb6, (byte)0xbc, (byte)0x0a,
(byte)0x0a, (byte)0x8b, (byte)0x06, (byte)0x06, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x06, (byte)0x04, (byte)0x8b, (byte)0xbc, (byte)0x1a,
(byte)0x0a, (byte)0xb6, (byte)0xb6, (byte)0xb5, (byte)0xb5, (byte)0xb5, (byte)0xb5, (byte)0xb5, (byte)0xd0, (byte)0xb5, (byte)0xb5, (byte)0xb5,
(byte)0xb5, (byte)0xb5, (byte)0xb5, (byte)0xb6, (byte)0xb6, (byte)0x0a, (byte)0xde, (byte)0x0a, (byte)0xa7, (byte)0x06, (byte)0x00, (byte)0x06,
(byte)0x00, (byte)0x00, (byte)0x06, (byte)0x06, (byte)0xed, (byte)0x06, (byte)0x8b, (byte)0xbc, (byte)0xf2, (byte)0x0a, (byte)0xb6, (byte)0xb6,
(byte)0xb6, (byte)0xb6, (byte)0xb5, (byte)0xb5, (byte)0xb5, (byte)0xb5, (byte)0xb5, (byte)0xb5, (byte)0xb6, (byte)0xb6, (byte)0xb6, (byte)0xb6,
(byte)0x0a, (byte)0xf2, (byte)0x1a, (byte)0x8c, (byte)0xec, (byte)0x06, (byte)0x06, (byte)0x06, (byte)0x00, (byte)0x00, (byte)0x04, (byte)0x06,
(byte)0x04, (byte)0x06, (byte)0x04, (byte)0xa7, (byte)0xbc, (byte)0x1a, (byte)0x0a, (byte)0x0a, (byte)0x6a, (byte)0xb6, (byte)0x96, (byte)0x0a,
(byte)0x0a, (byte)0xf2, (byte)0x0a, (byte)0x87, (byte)0x06, (byte)0x04, (byte)0x06, (byte)0x04, (byte)0x06, (byte)0x00, (byte)0x00, (byte)0x06,
(byte)0x06, (byte)0xed, (byte)0x06, (byte)0xed, (byte)0x06, (byte)0x8c, (byte)0xb6, (byte)0xf4, (byte)0xf2, (byte)0xd0, (byte)0x09, (byte)0xbc,
(byte)0x87, (byte)0x03, (byte)0x80, (byte)0x2c, (byte)0xde, (byte)0xf4, (byte)0x0a, (byte)0x8b, (byte)0x06, (byte)0x06, (byte)0xed, (byte)0x06,
(byte)0xed, (byte)0x06, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x06, (byte)0x04, (byte)0x06, (byte)0x00, (byte)0x06, (byte)0x04, (byte)0x6c,
(byte)0x87, (byte)0x0a, (byte)0xf4, (byte)0xf4, (byte)0xf2, (byte)0xde, (byte)0xbd, (byte)0xbd, (byte)0xde, (byte)0xf2, (byte)0xf4, (byte)0xf4,
(byte)0x0a, (byte)0xd0, (byte)0x04, (byte)0x06, (byte)0x00, (byte)0x06, (byte)0x04, (byte)0x06, (byte)0x00, (byte)0x06, (byte)0x00, (byte)0x00,
(byte)0x06, (byte)0x06, (byte)0xed, (byte)0x06, (byte)0x06, (byte)0x06, (byte)0xed, (byte)0x06, (byte)0x06, (byte)0x6c, (byte)0x8c, (byte)0xb5,
(byte)0xbc, (byte)0x0a, (byte)0xde, (byte)0xf2, (byte)0xbd, (byte)0x0a, (byte)0xb5, (byte)0x8c, (byte)0x6c, (byte)0x06, (byte)0xed, (byte)0x06,
(byte)0x06, (byte)0x06, (byte)0xed, (byte)0x06, (byte)0x06, (byte)0x06, (byte)0x00, (byte)0x00, (byte)0xe6, (byte)0x04, (byte)0x06, (byte)0x86,
(byte)0x04, (byte)0x6c, (byte)0x04, (byte)0x8b, (byte)0x04, (byte)0x6c, (byte)0xe6, (byte)0x04, (byte)0x06, (byte)0x82, (byte)0x00, (byte)0x00
});
ByteBuffer flippedImage =
new ByteBuffer(new byte[] {(byte)0x04, (byte)0x06, (byte)0x04, (byte)0x06, (byte)0x04, (byte)0x06, (byte)0x04, (byte)0x06, (byte)0x04, (byte)0x06,
(byte)0x04, (byte)0x06, (byte)0x04, (byte)0x6c, (byte)0x04, (byte)0x8b, (byte)0x04, (byte)0x6c, (byte)0x04, (byte)0x06, (byte)0x04, (byte)0x06,
(byte)0x04, (byte)0x06, (byte)0x04, (byte)0x06, (byte)0x04, (byte)0x06, (byte)0x04, (byte)0x06, (byte)0x00, (byte)0x00, (byte)0x06, (byte)0x06,
(byte)0xed, (byte)0x06, (byte)0x06, (byte)0x06, (byte)0xed, (byte)0x06, (byte)0x06, (byte)0x6c, (byte)0x8c, (byte)0xb5, (byte)0xbc, (byte)0x0a,
(byte)0xde, (byte)0xf2, (byte)0xbd, (byte)0x0a, (byte)0xb5, (byte)0x8c, (byte)0x6c, (byte)0x06, (byte)0xed, (byte)0x06, (byte)0x06, (byte)0x06,
(byte)0xed, (byte)0x06, (byte)0x06, (byte)0x06, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x06, (byte)0x04, (byte)0x06, (byte)0x00, (byte)0x06,
(byte)0x04, (byte)0x6c, (byte)0x87, (byte)0x0a, (byte)0xf4, (byte)0xf4, (byte)0xf2, (byte)0xde, (byte)0xbd, (byte)0xbd, (byte)0xde, (byte)0xf2,
(byte)0xf4, (byte)0xf4, (byte)0x0a, (byte)0xd0, (byte)0x04, (byte)0x06, (byte)0x00, (byte)0x06, (byte)0x04, (byte)0x06, (byte)0x00, (byte)0x06,
(byte)0x00, (byte)0x00, (byte)0x06, (byte)0x06, (byte)0xed, (byte)0x06, (byte)0xed, (byte)0x06, (byte)0x8c, (byte)0xb6, (byte)0xf4, (byte)0xf2,
(byte)0x0a, (byte)0x0a, (byte)0x0a, (byte)0xb6, (byte)0xb6, (byte)0xb6, (byte)0xb6, (byte)0x0a, (byte)0x0a, (byte)0x0a, (byte)0xde, (byte)0xf4,
(byte)0x0a, (byte)0x8b, (byte)0x06, (byte)0x06, (byte)0xed, (byte)0x06, (byte)0xed, (byte)0x06, (byte)0x00, (byte)0x00, (byte)0x04, (byte)0x06,
(byte)0x04, (byte)0x06, (byte)0x04, (byte)0xa7, (byte)0xbc, (byte)0x1a, (byte)0x0a, (byte)0x0a, (byte)0xb6, (byte)0xb6, (byte)0xb6, (byte)0xb6,
(byte)0xb6, (byte)0xb6, (byte)0xb6, (byte)0xb6, (byte)0xb6, (byte)0xb6, (byte)0x0a, (byte)0x0a, (byte)0xf2, (byte)0x0a, (byte)0x87, (byte)0x06,
(byte)0x04, (byte)0x06, (byte)0x04, (byte)0x06, (byte)0x00, (byte)0x00, (byte)0x06, (byte)0x06, (byte)0xed, (byte)0x06, (byte)0x8b, (byte)0xbc,
(byte)0xf2, (byte)0x0a, (byte)0xb6, (byte)0xb6, (byte)0xb6, (byte)0xb6, (byte)0xb5, (byte)0xb5, (byte)0xb5, (byte)0xb5, (byte)0xb5, (byte)0xb5,
(byte)0xb6, (byte)0xb6, (byte)0xb6, (byte)0xb6, (byte)0x0a, (byte)0xf2, (byte)0x1a, (byte)0x8c, (byte)0xec, (byte)0x06, (byte)0x06, (byte)0x06,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x06, (byte)0x04, (byte)0x8b, (byte)0xbc, (byte)0x1a, (byte)0x0a, (byte)0xb6, (byte)0xb6, (byte)0xb5,
(byte)0xb5, (byte)0xb5, (byte)0xb5, (byte)0xb5, (byte)0xd0, (byte)0xb5, (byte)0xb5, (byte)0xb5, (byte)0xb5, (byte)0xb5, (byte)0xb5, (byte)0xb6,
(byte)0xb6, (byte)0x0a, (byte)0xde, (byte)0x0a, (byte)0xa7, (byte)0x06, (byte)0x00, (byte)0x06, (byte)0x00, (byte)0x00, (byte)0xed, (byte)0x06,
(byte)0x6e, (byte)0xb5, (byte)0x0a, (byte)0xbc, (byte)0xb6, (byte)0xb5, (byte)0xb5, (byte)0xb5, (byte)0xd0, (byte)0xd0, (byte)0xd0, (byte)0xb5,
(byte)0xf4, (byte)0xff, (byte)0xf2, (byte)0xd0, (byte)0xd0, (byte)0xd0, (byte)0xb5, (byte)0xb5, (byte)0xb5, (byte)0xb6, (byte)0xbc, (byte)0x0a,
(byte)0x0a, (byte)0x8b, (byte)0x06, (byte)0x06, (byte)0x00, (byte)0x00, (byte)0x04, (byte)0x06, (byte)0x87, (byte)0x0a, (byte)0xbc, (byte)0xb6,
(byte)0xb5, (byte)0xb5, (byte)0xb5, (byte)0xd0, (byte)0xae, (byte)0xae, (byte)0xae, (byte)0xb6, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xf2,
(byte)0xd0, (byte)0xae, (byte)0xd0, (byte)0xb5, (byte)0xb5, (byte)0xb5, (byte)0xb6, (byte)0xbc, (byte)0x1a, (byte)0xb5, (byte)0x04, (byte)0x06,
(byte)0x00, (byte)0x00, (byte)0x06, (byte)0x6c, (byte)0xb5, (byte)0x0a, (byte)0xb6, (byte)0xb5, (byte)0xb5, (byte)0xb5, (byte)0xae, (byte)0xae,
(byte)0xae, (byte)0xae, (byte)0xae, (byte)0xbc, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xf2, (byte)0xae, (byte)0xae, (byte)0xae,
(byte)0xb5, (byte)0xb5, (byte)0xb5, (byte)0xb6, (byte)0x0a, (byte)0x0a, (byte)0x8b, (byte)0x06, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x8b,
(byte)0x0a, (byte)0xbc, (byte)0xb5, (byte)0xb5, (byte)0xb5, (byte)0xae, (byte)0xae, (byte)0xae, (byte)0xae, (byte)0xae, (byte)0xae, (byte)0xb6,
(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xf2, (byte)0xae, (byte)0xae, (byte)0xae, (byte)0xb5, (byte)0xb5, (byte)0xb5,
(byte)0xb6, (byte)0x0a, (byte)0x8c, (byte)0x06, (byte)0x00, (byte)0x00, (byte)0x06, (byte)0xae, (byte)0x0a, (byte)0xb5, (byte)0xb5, (byte)0xb5,
(byte)0xd0, (byte)0xae, (byte)0xae, (byte)0xae, (byte)0xae, (byte)0xae, (byte)0xae, (byte)0x8c, (byte)0x0a, (byte)0xff, (byte)0xff, (byte)0xff,
(byte)0xff, (byte)0xff, (byte)0xf2, (byte)0xae, (byte)0xae, (byte)0xd0, (byte)0xb5, (byte)0xb5, (byte)0xb5, (byte)0x0a, (byte)0xb5, (byte)0x6c,
(byte)0x00, (byte)0x00, (byte)0x04, (byte)0xae, (byte)0x0a, (byte)0xb5, (byte)0xb5, (byte)0xb5, (byte)0xae, (byte)0xae, (byte)0xae, (byte)0xae,
(byte)0xae, (byte)0xae, (byte)0xae, (byte)0xae, (byte)0x8c, (byte)0x0a, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xf2,
(byte)0xae, (byte)0xae, (byte)0xb5, (byte)0xb5, (byte)0xb5, (byte)0xbc, (byte)0xb5, (byte)0x6c, (byte)0x00, (byte)0x00, (byte)0x6c, (byte)0xae,
(byte)0xbc, (byte)0xb5, (byte)0xb5, (byte)0xae, (byte)0xb5, (byte)0xf3, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xf2, (byte)0xae, (byte)0xae, (byte)0xb5,
(byte)0xb5, (byte)0xbc, (byte)0xb5, (byte)0x66, (byte)0x00, (byte)0x00, (byte)0x0b, (byte)0xa7, (byte)0xb5, (byte)0xae, (byte)0x8c, (byte)0xa7,
(byte)0xf4, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xbd, (byte)0xa7, (byte)0x8c, (byte)0xae, (byte)0xb5, (byte)0xae, (byte)0x66,
(byte)0x00, (byte)0x00, (byte)0x13, (byte)0x04, (byte)0x66, (byte)0x66, (byte)0x66, (byte)0x66, (byte)0xf4, (byte)0xff, (byte)0xff, (byte)0xff,
(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
(byte)0xff, (byte)0xbd, (byte)0x66, (byte)0x66, (byte)0x66, (byte)0x66, (byte)0xa7, (byte)0x66, (byte)0x00, (byte)0x00, (byte)0x60, (byte)0xa7,
(byte)0x66, (byte)0x60, (byte)0x66, (byte)0x66, (byte)0x8c, (byte)0xf1, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xbd, (byte)0x66, (byte)0x66, (byte)0x66,
(byte)0x60, (byte)0x66, (byte)0xa7, (byte)0x66, (byte)0x00, (byte)0x00, (byte)0x6c, (byte)0x04, (byte)0xa7, (byte)0x60, (byte)0x66, (byte)0x66,
(byte)0x66, (byte)0x66, (byte)0x66, (byte)0x66, (byte)0x66, (byte)0x66, (byte)0x66, (byte)0x66, (byte)0x66, (byte)0xb6, (byte)0xf5, (byte)0xf5,
(byte)0xf5, (byte)0xf5, (byte)0xf5, (byte)0xef, (byte)0x66, (byte)0x66, (byte)0x66, (byte)0x66, (byte)0x66, (byte)0x66, (byte)0xa7, (byte)0x66,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x60, (byte)0xa7, (byte)0x66, (byte)0x66, (byte)0x66, (byte)0xa7, (byte)0xa7, (byte)0xa7, (byte)0xa7,
(byte)0x8b, (byte)0x8b, (byte)0x8b, (byte)0xa7, (byte)0xb6, (byte)0xf3, (byte)0xf3, (byte)0xf3, (byte)0xf3, (byte)0xf3, (byte)0x07, (byte)0x66,
(byte)0xa7, (byte)0xa7, (byte)0x66, (byte)0x66, (byte)0x66, (byte)0xa7, (byte)0xa7, (byte)0x6c, (byte)0x00, (byte)0x00, (byte)0x06, (byte)0x66,
(byte)0xc8, (byte)0xa7, (byte)0x66, (byte)0xa7, (byte)0xa7, (byte)0x8b, (byte)0x8b, (byte)0x8b, (byte)0x8b, (byte)0xad, (byte)0x8b, (byte)0x92,
(byte)0xf1, (byte)0xf1, (byte)0xf1, (byte)0xf1, (byte)0xf2, (byte)0x07, (byte)0xa7, (byte)0xa7, (byte)0x8b, (byte)0xa7, (byte)0xa7, (byte)0x66,
(byte)0x66, (byte)0xc8, (byte)0x66, (byte)0x06, (byte)0x00, (byte)0x00, (byte)0x04, (byte)0x6c, (byte)0xa7, (byte)0xad, (byte)0xa7, (byte)0xa7,
(byte)0x8b, (byte)0xad, (byte)0xad, (byte)0xad, (byte)0xad, (byte)0xad, (byte)0xad, (byte)0xb5, (byte)0xbd, (byte)0xbd, (byte)0xbd, (byte)0xbd,
(byte)0xf0, (byte)0x8b, (byte)0x8b, (byte)0xad, (byte)0x8b, (byte)0x8b, (byte)0xa7, (byte)0xa7, (byte)0xc8, (byte)0xc8, (byte)0x60, (byte)0x06,
(byte)0x00, (byte)0x00, (byte)0x06, (byte)0x06, (byte)0x66, (byte)0xae, (byte)0xad, (byte)0x8b, (byte)0xad, (byte)0xad, (byte)0xad, (byte)0xad,
(byte)0xad, (byte)0xb3, (byte)0xad, (byte)0xb5, (byte)0x07, (byte)0x07, (byte)0x07, (byte)0xf0, (byte)0x8b, (byte)0xad, (byte)0xad, (byte)0xad,
(byte)0xad, (byte)0xad, (byte)0x8b, (byte)0xa7, (byte)0xae, (byte)0xa7, (byte)0x6c, (byte)0x06, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x06,
(byte)0x60, (byte)0xa7, (byte)0xb4, (byte)0xad, (byte)0xad, (byte)0xad, (byte)0xb3, (byte)0xb3, (byte)0xd4, (byte)0xd4, (byte)0xb3, (byte)0x8c,
(byte)0xb6, (byte)0x07, (byte)0xb6, (byte)0x8c, (byte)0xb3, (byte)0xd4, (byte)0xb3, (byte)0xb3, (byte)0xad, (byte)0xad, (byte)0xad, (byte)0xb4,
(byte)0xad, (byte)0x66, (byte)0x00, (byte)0x06, (byte)0x00, (byte)0x00, (byte)0xed, (byte)0x06, (byte)0xed, (byte)0x66, (byte)0xae, (byte)0xd5,
(byte)0xad, (byte)0xd4, (byte)0xd4, (byte)0xd5, (byte)0xd5, (byte)0xd5, (byte)0xdb, (byte)0xb4, (byte)0xb4, (byte)0xb4, (byte)0xb4, (byte)0xb4,
(byte)0xd5, (byte)0xd5, (byte)0xd5, (byte)0xd4, (byte)0xd4, (byte)0xad, (byte)0xd5, (byte)0xb4, (byte)0x0e, (byte)0x06, (byte)0x06, (byte)0x06,
(byte)0x00, (byte)0x00, (byte)0x04, (byte)0x06, (byte)0x04, (byte)0x06, (byte)0x0b, (byte)0xae, (byte)0xdb, (byte)0xd4, (byte)0xd5, (byte)0xdb,
(byte)0xdb, (byte)0xdb, (byte)0xdb, (byte)0xdb, (byte)0xdb, (byte)0xdb, (byte)0xdb, (byte)0xdb, (byte)0xdb, (byte)0xdb, (byte)0xdb, (byte)0xd5,
(byte)0xd4, (byte)0xdb, (byte)0xb4, (byte)0x66, (byte)0x04, (byte)0x06, (byte)0x04, (byte)0x06, (byte)0x00, (byte)0x00, (byte)0x06, (byte)0x06,
(byte)0xed, (byte)0x06, (byte)0x06, (byte)0x0e, (byte)0xae, (byte)0xdc, (byte)0xdb, (byte)0xdb, (byte)0xdb, (byte)0xdb, (byte)0xdb, (byte)0xdb,
(byte)0xdc, (byte)0xdc, (byte)0xdb, (byte)0xdb, (byte)0xdb, (byte)0xdb, (byte)0xdb, (byte)0xdb, (byte)0xdc, (byte)0xb4, (byte)0x66, (byte)0x6c,
(byte)0xed, (byte)0x06, (byte)0x06, (byte)0x06, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x06, (byte)0x04, (byte)0x06, (byte)0x00, (byte)0x06,
(byte)0x0b, (byte)0xae, (byte)0xdc, (byte)0xe9, (byte)0xdc, (byte)0xdc, (byte)0xdc, (byte)0xdc, (byte)0xdc, (byte)0xdc, (byte)0xdc, (byte)0xdc,
(byte)0xdc, (byte)0xdc, (byte)0xe9, (byte)0xe9, (byte)0xb4, (byte)0x0e, (byte)0x00, (byte)0x06, (byte)0x04, (byte)0x06, (byte)0x00, (byte)0x06,
(byte)0x00, (byte)0x00, (byte)0x06, (byte)0x06, (byte)0xed, (byte)0x06, (byte)0xed, (byte)0x06, (byte)0xf8, (byte)0x0e, (byte)0x66, (byte)0xb4,
(byte)0xdc, (byte)0xe2, (byte)0xe2, (byte)0xe2, (byte)0xe2, (byte)0xe2, (byte)0xe2, (byte)0xe2, (byte)0xe2, (byte)0xdd, (byte)0xb4, (byte)0xa7,
(byte)0x16, (byte)0x06, (byte)0x06, (byte)0x06, (byte)0xed, (byte)0x06, (byte)0xed, (byte)0x06, (byte)0x00, (byte)0x00, (byte)0x04, (byte)0x06,
(byte)0x04, (byte)0x06, (byte)0x04, (byte)0x06, (byte)0x04, (byte)0x06, (byte)0x60, (byte)0x0e, (byte)0x60, (byte)0x8c, (byte)0xb4, (byte)0xb5,
(byte)0xdc, (byte)0xdc, (byte)0xbb, (byte)0xb4, (byte)0x8c, (byte)0x66, (byte)0x0b, (byte)0x6c, (byte)0x04, (byte)0x06, (byte)0x04, (byte)0x06,
(byte)0x04, (byte)0x06, (byte)0x04, (byte)0x06, (byte)0x00, (byte)0x00, (byte)0x06, (byte)0x06, (byte)0xed, (byte)0x06, (byte)0x06, (byte)0x06,
(byte)0xed, (byte)0x06, (byte)0x06, (byte)0x06, (byte)0xec, (byte)0x6c, (byte)0x0e, (byte)0x0e, (byte)0x44, (byte)0x0e, (byte)0x0e, (byte)0x0e,
(byte)0x13, (byte)0x06, (byte)0x06, (byte)0x06, (byte)0xed, (byte)0x06, (byte)0x06, (byte)0x06, (byte)0xed, (byte)0x06, (byte)0x06, (byte)0x06,
(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)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)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)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)0x00, (byte)0x00});
ByteBuffer dest = new AssertingByteBuffer(flipRawImage(flippedImage, width, height, bpp).data);
rleDecompress(src, dest, width, height, depth);
}
if (true) {
// 32x32@16
int width = 32, height = 32, depth = 16;
ByteBuffer src =
new ByteBuffer(new byte[] {(byte)0x85, (byte)0xff, (byte)0xff, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x06, (byte)0x8b, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x10, (byte)0x84, (byte)0x08,
(byte)0x42, (byte)0x08, (byte)0x42, (byte)0x10, (byte)0x84, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x06, (byte)0x84, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0xff, (byte)0xff, (byte)0x16,
(byte)0x69, (byte)0x99, (byte)0xd6, (byte)0x06, (byte)0x69, (byte)0x99, (byte)0xd6, (byte)0x04, (byte)0xcc, (byte)0x89, (byte)0x52, (byte)0x03,
(byte)0x6e, (byte)0xff, (byte)0xff, (byte)0x02, (byte)0x6e, (byte)0x08, (byte)0x42, (byte)0x01, (byte)0x70, (byte)0x08, (byte)0x42, (byte)0x71,
(byte)0xff, (byte)0xff, (byte)0xce, (byte)0x18, (byte)0xc6, (byte)0x01, (byte)0x81, (byte)0x08, (byte)0x42, (byte)0xce, (byte)0x66, (byte)0x29,
(byte)0x02, (byte)0xcd, (byte)0x89, (byte)0x52, (byte)0x03, (byte)0x88, (byte)0x10, (byte)0x84, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6,
(byte)0x99, (byte)0xd6, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xd8, (byte)0x99,
(byte)0xd6, (byte)0x03, (byte)0xf8, (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xf0, (byte)0x66, (byte)0x99, (byte)0xd6,
(byte)0x05, (byte)0x6a, (byte)0x99, (byte)0xd6, (byte)0x00, (byte)0xc4, (byte)0xcc, (byte)0x89, (byte)0x52, (byte)0x03, (byte)0x6e, (byte)0xff,
(byte)0xff, (byte)0x02, (byte)0x6e, (byte)0x08, (byte)0x42, (byte)0x01, (byte)0x70, (byte)0x08, (byte)0x42, (byte)0x71, (byte)0xff, (byte)0xff,
(byte)0xce, (byte)0x18, (byte)0xc6, (byte)0x01, (byte)0x81, (byte)0x08, (byte)0x42, (byte)0xce, (byte)0x66, (byte)0x29, (byte)0x02, (byte)0xcd,
(byte)0x89, (byte)0x52, (byte)0x03, (byte)0x00, (byte)0x04, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0xc3, (byte)0x80, (byte)0x61, (byte)0x00,
(byte)0xa5, (byte)0x80, (byte)0x40, (byte)0xec, (byte)0x52, (byte)0x00, (byte)0x5a, (byte)0x00, (byte)0x2d, (byte)0x00, (byte)0x24, (byte)0x00,
(byte)0x12, (byte)0x00, (byte)0x24, (byte)0x00, (byte)0x12, (byte)0x00, (byte)0x5a, (byte)0x00, (byte)0x2d, (byte)0x00, (byte)0xa5, (byte)0x80,
(byte)0x52, (byte)0x00, (byte)0xc3, (byte)0x80, (byte)0x61, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xcc, (byte)0x89,
(byte)0x52, (byte)0x03, (byte)0x6e, (byte)0xff, (byte)0xff, (byte)0x02, (byte)0xcb, (byte)0x18, (byte)0xc6, (byte)0x84, (byte)0x08, (byte)0x42,
(byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0xff, (byte)0xff,});
ByteBuffer dest =
new AssertingByteBuffer(new byte[] {(byte)0xff, (byte)0xff, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (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)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x10, (byte)0x84, (byte)0x08, (byte)0x42, (byte)0x08,
(byte)0x42, (byte)0x10, (byte)0x84, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (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)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (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)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x10,
(byte)0x84, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x10, (byte)0x84, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0xff, (byte)0xff, (byte)0xff,
(byte)0xff, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x10, (byte)0x84, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x10, (byte)0x84, (byte)0x10,
(byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10,
(byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10, (byte)0x84, (byte)0x99,
(byte)0xd6, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x08, (byte)0x42, (byte)0x08,
(byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08,
(byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08,
(byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0xff, (byte)0xff, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08,
(byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08,
(byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08,
(byte)0x42, (byte)0x08, (byte)0x42, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
(byte)0xff, (byte)0x10, (byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10,
(byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10,
(byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10, (byte)0x84, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x10, (byte)0x84, (byte)0x08, (byte)0x42, (byte)0x08,
(byte)0x42, (byte)0x10, (byte)0x84, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (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)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (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)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x10,
(byte)0x84, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x10, (byte)0x84, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (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)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0xff, (byte)0xff, (byte)0xff,
(byte)0xff, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (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)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x10, (byte)0x84, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x10, (byte)0x84, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x10, (byte)0x84, (byte)0x08, (byte)0x42, (byte)0x08,
(byte)0x42, (byte)0x10, (byte)0x84, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x10,
(byte)0x84, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x10, (byte)0x84, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0xff, (byte)0xff, (byte)0xff,
(byte)0xff, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x10, (byte)0x84, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x10, (byte)0x84, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x10, (byte)0x84, (byte)0x08, (byte)0x42, (byte)0x08,
(byte)0x42, (byte)0x10, (byte)0x84, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x10,
(byte)0x84, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x10, (byte)0x84, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0xff, (byte)0xff, (byte)0xff,
(byte)0xff, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x10, (byte)0x84, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x10, (byte)0x84, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x10, (byte)0x84, (byte)0x08, (byte)0x42, (byte)0x08,
(byte)0x42, (byte)0x10, (byte)0x84, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x10,
(byte)0x84, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x10, (byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10,
(byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10,
(byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10, (byte)0x84, (byte)0x99, (byte)0xd6, (byte)0xff, (byte)0xff, (byte)0xff,
(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08,
(byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08,
(byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08,
(byte)0x42, (byte)0xff, (byte)0xff, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08,
(byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08,
(byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0xff,
(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x10, (byte)0x84, (byte)0x10,
(byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10,
(byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10,
(byte)0x84, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0xff, (byte)0xff, (byte)0xff,
(byte)0xff, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x10, (byte)0x84, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x10, (byte)0x84, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x10, (byte)0x84, (byte)0x08, (byte)0x42, (byte)0x08,
(byte)0x42, (byte)0x10, (byte)0x84, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x10,
(byte)0x84, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x10, (byte)0x84, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0xff, (byte)0xff, (byte)0xff,
(byte)0xff, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x10, (byte)0x84, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x10, (byte)0x84, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x10, (byte)0x84, (byte)0x08, (byte)0x42, (byte)0x08,
(byte)0x42, (byte)0x10, (byte)0x84, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x10,
(byte)0x84, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x10, (byte)0x84, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0xff, (byte)0xff, (byte)0xff,
(byte)0xff, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x10, (byte)0x84, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x10, (byte)0x84, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x10, (byte)0x84, (byte)0x08, (byte)0x42, (byte)0x08,
(byte)0x42, (byte)0x10, (byte)0x84, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x10,
(byte)0x84, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x10, (byte)0x84, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0xff, (byte)0xff, (byte)0xff,
(byte)0xff, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x10, (byte)0x84, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x10, (byte)0x84, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99,
(byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x99, (byte)0xd6, (byte)0x10, (byte)0x84, (byte)0x08, (byte)0x42, (byte)0x08,
(byte)0x42, (byte)0x10, (byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10,
(byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10, (byte)0x84, (byte)0x10,
(byte)0x84, (byte)0x10, (byte)0x84, (byte)0x99, (byte)0xd6, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
(byte)0xff, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08,
(byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08,
(byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0x08, (byte)0x42, (byte)0xff, (byte)0xff,});
rleDecompress(src, dest, width, height, depth);
}
}
}

View File

@ -16,13 +16,50 @@
// under the License.
package rdpclient;
import java.net.InetAddress;
import java.net.UnknownHostException;
import rdpclient.adapter.AwtRdpKeyboardAdapter;
import rdpclient.adapter.AwtRdpMouseAdapter;
import rdpclient.hyperv.ClientPreConnectionBlob;
import rdpclient.ntlmssp.ClientNtlmsspNegotiate;
import rdpclient.ntlmssp.ClientNtlmsspPubKeyAuth;
import rdpclient.ntlmssp.ClientNtlmsspUserCredentials;
import rdpclient.ntlmssp.NtlmState;
import rdpclient.ntlmssp.ServerNtlmsspChallenge;
import rdpclient.ntlmssp.ServerNtlmsspPubKeyPlus1;
import rdpclient.rdp.ClientConfirmActivePDU;
import rdpclient.rdp.ClientFastPathPDU;
import rdpclient.rdp.ClientInfoPDU;
import rdpclient.rdp.ClientMCSAttachUserRequest;
import rdpclient.rdp.ClientMCSChannelJoinRequestServerMCSChannelConfirmPDUs;
import rdpclient.rdp.ClientMCSConnectInitial;
import rdpclient.rdp.ClientMCSErectDomainRequest;
import rdpclient.rdp.ClientTpkt;
import rdpclient.rdp.ClientX224ConnectionRequestPDU;
import rdpclient.rdp.ClientX224DataPDU;
import rdpclient.rdp.RdpConstants;
import rdpclient.rdp.RdpState;
import rdpclient.rdp.ServerBitmapUpdate;
import rdpclient.rdp.ServerDemandActivePDU;
import rdpclient.rdp.ServerFastPath;
import rdpclient.rdp.ServerIOChannelRouter;
import rdpclient.rdp.ServerLicenseErrorPDUValidClient;
import rdpclient.rdp.ServerMCSAttachUserConfirmPDU;
import rdpclient.rdp.ServerMCSConnectResponse;
import rdpclient.rdp.ServerMCSPDU;
import rdpclient.rdp.ServerPaletteUpdate;
import rdpclient.rdp.ServerX224ConnectionConfirmPDU;
import rdpclient.rdp.ServerX224DataPdu;
import streamer.PipelineImpl;
import streamer.Queue;
import common.AwtCanvasAdapter;
import streamer.ssl.SSLState;
import streamer.ssl.UpgradeSocketToSSL;
import common.AwtKeyEventSource;
import common.AwtMouseEventSource;
import common.BufferedImageCanvas;
import common.ScreenDescription;
import common.adapter.AwtCanvasAdapter;
public class RdpClient extends PipelineImpl {
@ -31,12 +68,32 @@ public class RdpClient extends PipelineImpl {
*/
private static final String HANDSHAKE_END = "server_valid_client";
public RdpClient(String id, String userName, ScreenDescription screen, BufferedImageCanvas canvas) {
/**
* Create new RDP or HyperV cli
*
* @param id
* id of this element
* @param userName
* user name
* @param password
* password
* @param pcb
* pre-connection blob for HyperV server or null/empty string to
* disable. Usually, HyperV VM ID, e.g.
* "39418F90-6D03-468E-B796-91C60DD6653A".
* @param screen
* screen description to fill
* @param canvas
* canvas to draw on
* @param sslState
*/
public RdpClient(String id, String serverHostName, String domain, String userName, String password, String pcb, ScreenDescription screen,
BufferedImageCanvas canvas, SSLState sslState) {
super(id);
assembleRDPPipeline(userName, screen, canvas);
assembleRDPPipeline(serverHostName, domain, userName, password, pcb, screen, canvas, sslState);
}
// /* DEBUG */
// /* DEBUG */
// @Override
// protected HashMap<String, streamer.Element> initElementMap(String id) {
// HashMap<String, streamer.Element> map = new HashMap<String, streamer.Element>();
@ -45,72 +102,195 @@ public class RdpClient extends PipelineImpl {
// return map;
// }
private void assembleRDPPipeline(String userName, ScreenDescription screen, BufferedImageCanvas canvas) {
/**
* Assemble connection sequence and main pipeline.
*
* Connection sequence for RDP w/o NLA: cookie(TPKT) SSL x224(TPKT)
* main(FastPath).
*
* Connection sequence for RDP w NLA: cookie(TPKT) SSL credssp x224(TPKT)
* main(FastPath).
*
* Connection sequence for HyperV w NLA: pcb SSL credssp cookie(TPKT)
* x224(TPKT) main(FastPath).
*/
protected void assembleRDPPipeline(String serverHostName, String domain, String userName, String password, String pcb, ScreenDescription screen,
BufferedImageCanvas canvas, SSLState sslState) {
// If preconnection blob with VM ID is specified, then we are connecting to
// HyperV server
boolean hyperv = (pcb != null && !pcb.isEmpty());
// HyperV server requires NLA (CredSSP/SPNEGO/NTLMSSP) to connect, because
// it cannot display login screen
boolean credssp = hyperv || (password != null && !password.isEmpty());
String workstation;
try {
workstation = InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException e) {
workstation = "workstation";
}
//
// Handshake chain
//
RdpState state = new RdpState();
int[] channelsToJoin = new int[] {RdpConstants.CHANNEL_RDPRDR, RdpConstants.CHANNEL_IO};
NtlmState ntlmState = new NtlmState();
int[] channelsToJoin = new int[] {RdpConstants.CHANNEL_IO,
// RdpConstants.CHANNEL_RDPRDR, // RDPRDR channel is not used in current
// version
// RdpConstants .CHANNEL_CLIPRDR // Clipboard channel is refused to join :-/
};
// Add elements
add(
// If pre-connection blob is specified, then add element to send it as
// first packet
if (hyperv) {
add(new ClientPreConnectionBlob("pcb", pcb));
}
new ClientX224ConnectionRequestPDU("client_connection_req", userName), new ServerX224ConnectionConfirmPDU("server_connection_conf"),
// If password is specified, then use CredSSP/NTLM (NTLMSSP)
int protocol = RdpConstants.RDP_NEG_REQ_PROTOCOL_SSL;
if (credssp) {
protocol = RdpConstants.RDP_NEG_REQ_PROTOCOL_HYBRID;
new UpgradeSocketToSSL("upgrade_to_ssl"),
add(
new ClientNtlmsspNegotiate("client_ntlmssp_nego", ntlmState),
new ClientMCSConnectInitial("client_initial_conference_create"), new ServerMCSConnectResponse("server_initial_conference_create"),
new ServerNtlmsspChallenge("server_ntlmssp_challenge", ntlmState),
new ClientMCSErectDomainRequest("client_erect_domain"),
new ClientNtlmsspPubKeyAuth("client_ntlmssp_auth", ntlmState, sslState, serverHostName, domain, workstation, userName, password),
new ClientMCSAttachUserRequest("client_atach_user"), new ServerMCSAttachUserConfirmPDU("server_atach_user_confirm", state),
new ServerNtlmsspPubKeyPlus1("server_ntlmssp_confirm", ntlmState),
new ClientMCSChannelJoinRequestServerMCSChannelConfirmPDUs("client_channel_join_rdprdr", channelsToJoin, state),
new ClientNtlmsspUserCredentials("client_ntlmssp_finish", ntlmState)
new ClientInfoPDU("client_info_req", userName),
);
}
new ServerLicenseErrorPDUValidClient("server_valid_client"),
add(new ClientX224ConnectionRequestPDU("client_connection_req", userName, protocol), new ServerX224ConnectionConfirmPDU("server_connection_conf"),
new UpgradeSocketToSSL("upgrade_to_ssl"),
new ServerFastPath("server_fastpath"),
new ClientMCSConnectInitial("client_initial_conference_create"), new ServerMCSConnectResponse("server_initial_conference_create"),
new ServerTpkt("server_tpkt"),
new ClientMCSErectDomainRequest("client_erect_domain"),
new ServerX224DataPdu("server_x224_data"),
new ClientMCSAttachUserRequest("client_atach_user"), new ServerMCSAttachUserConfirmPDU("server_atach_user_confirm", state),
// These TPKT and X224 wrappers are connected directly to OUT for handshake
// sequence
new ClientTpkt("client_tpkt_ot"),
new ClientMCSChannelJoinRequestServerMCSChannelConfirmPDUs("client_channel_join_rdprdr", channelsToJoin, state),
new ClientX224DataPdu("client_x224_data_ot")
new ClientInfoPDU("client_info_req", userName),
);
new ServerLicenseErrorPDUValidClient("server_valid_client"),
// Handshake sequence (via SlowPath)
link("IN",
new ServerFastPath("server_fastpath"),
"server_fastpath >tpkt", "server_tpkt",
// new ServerTpkt("server_tpkt"),
"client_connection_req", "server_connection_conf",
new ServerX224DataPdu("server_x224_data"),
"upgrade_to_ssl",
// These TPKT and X224 wrappers are connected directly to OUT for
// handshake sequence
new ClientTpkt("client_tpkt_ot"),
"client_initial_conference_create", "server_initial_conference_create",
new ClientX224DataPDU("client_x224_data_ot")
"client_erect_domain",
);
"server_x224_data",
// If HyperV VM ID is set, then insert element which will send VM ID as
// first packet of connection, before other packets
if (hyperv) {
"client_atach_user", "server_atach_user_confirm",
// HyperV: pcb SSL credssp cookie x224 main.
"client_channel_join_rdprdr",
link("IN",
"client_info_req",
// Pre Connection Blob
"pcb",
"server_valid_client"
// Main (will be used after connection seq) or tpkt (to X224)
"server_fastpath >tpkt",
);
// SSL
"upgrade_to_ssl",
// CredSSP
"client_ntlmssp_nego", "server_ntlmssp_challenge", "client_ntlmssp_auth", "server_ntlmssp_confirm", "client_ntlmssp_finish",
// Cookie
"client_connection_req", "server_connection_conf",
// X224
"client_initial_conference_create");
for (String element : new String[] {"pcb", "client_ntlmssp_nego", "server_ntlmssp_challenge", "client_ntlmssp_auth", "server_ntlmssp_confirm",
"client_ntlmssp_finish"}) {
link(element + " >otout", element + "< OUT");
}
} else {
// RDP: cookie SSL (credssp) x224 main.
link("IN",
// Main or tpkt
"server_fastpath >tpkt",
// Cookie
"client_connection_req", "server_connection_conf",
// SSL
"upgrade_to_ssl");
if (credssp) {
// SSL
link("upgrade_to_ssl",
// CredSSP
"client_ntlmssp_nego", "server_ntlmssp_challenge", "client_ntlmssp_auth", "server_ntlmssp_confirm", "client_ntlmssp_finish",
// X224
"client_initial_conference_create");
for (String element : new String[] {"client_ntlmssp_nego", "server_ntlmssp_challenge", "client_ntlmssp_auth", "server_ntlmssp_confirm",
"client_ntlmssp_finish"}) {
link(element + " >otout", element + "< OUT");
}
} else {
link(
// SSL
"upgrade_to_ssl",
// X224
"client_initial_conference_create");
}
}
link(
// X224
"client_initial_conference_create", "server_initial_conference_create",
"client_erect_domain",
"server_x224_data",
"client_atach_user", "server_atach_user_confirm",
"client_channel_join_rdprdr",
"client_info_req",
"server_valid_client"
);
// Chain for direct handshake responses (without involving of queue)
link("client_x224_data_ot", "client_tpkt_ot", "client_tpkt_ot< OUT");
@ -122,8 +302,7 @@ public class RdpClient extends PipelineImpl {
}
// Connect one time outputs to client X224 input
String x224_peers[] =
new String[] {"client_initial_conference_create", "server_initial_conference_create", "client_erect_domain", "client_atach_user",
String x224_peers[] = new String[] {"client_initial_conference_create", "server_initial_conference_create", "client_erect_domain", "client_atach_user",
"server_atach_user_confirm", "client_channel_join_rdprdr", "client_info_req", "server_valid_client"};
for (String element : x224_peers) {
link(element + " >otout", element + "< client_x224_data_ot");
@ -134,13 +313,13 @@ public class RdpClient extends PipelineImpl {
//
add(
// To transfer packets between input threads and output thread.
new Queue("queue"),
// To transfer packets between input threads and output thread.
new Queue("queue"),
// Slow path: MultiChannel Support
new ServerMCSPDU("server_mcs")
// Slow path: MultiChannel Support
new ServerMCSPDU("server_mcs")
);
);
// Last element of handshake sequence will wake up queue and and socket
// output pull loop, which will switch links, between socket output and
@ -165,38 +344,38 @@ public class RdpClient extends PipelineImpl {
// Add elements
add(
new ServerChannel1003Router("server_channel_1003", state),
new ServerIOChannelRouter("server_io_channel", state),
new ServerDemandActivePDU("server_demand_active", screen, state),
new ServerDemandActivePDU("server_demand_active", screen, state),
new ClientConfirmActivePDU("client_confirm_active", screen, state),
new ClientConfirmActivePDU("client_confirm_active", screen, state),
new ServerBitmapUpdate("server_bitmap_update"),
new ServerBitmapUpdate("server_bitmap_update"),
new AwtCanvasAdapter("canvas_adapter", canvas, screen),
new AwtCanvasAdapter("canvas_adapter", canvas, screen),
new ServerPaletteUpdate("server_palette", screen),
new ServerPaletteUpdate("server_palette", screen),
keyEventSource, new AwtRdpKeyboardAdapter("keyboard_adapter"),
keyEventSource, new AwtRdpKeyboardAdapter("keyboard_adapter"),
mouseEventSource, new AwtRdpMouseAdapter("mouse_adapter"),
mouseEventSource, new AwtRdpMouseAdapter("mouse_adapter"),
// These FastPath, TPKT, and X224 wrappers are connected to queue
new ClientTpkt("client_tpkt_queue"),
// These FastPath, TPKT, and X224 wrappers are connected to queue
new ClientTpkt("client_tpkt_queue"),
new ClientX224DataPdu("client_x224_data_queue"),
new ClientX224DataPDU("client_x224_data_queue"),
new ClientFastPathPDU("client_fastpath_queue"));
new ClientFastPathPDU("client_fastpath_queue"));
// Server packet handlers
link("server_mcs >channel_1003", "server_channel_1003");
link("server_mcs >channel_1003", "server_io_channel");
link("server_fastpath >bitmap", "fastpath< server_bitmap_update", "server_bitmap_update< canvas_adapter");
link("server_channel_1003 >bitmap", "slowpath< server_bitmap_update");
link("server_io_channel >bitmap", "slowpath< server_bitmap_update");
link("server_fastpath >palette", "fastpath< server_palette");
link("server_channel_1003 >palette", "slowpath< server_palette");
link("server_io_channel >palette", "slowpath< server_palette");
link("server_channel_1003 >demand_active", "slowpath< server_demand_active");
link("server_io_channel >demand_active", "slowpath< server_demand_active");
// link("server_demand_active >confirm_active", "client_confirm_active",
// "confirm_active< client_channel_1003");
link("server_demand_active >confirm_active", "client_confirm_active", "confirm_active< client_x224_data_queue");

View File

@ -1,533 +0,0 @@
// 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;
import streamer.BaseElement;
import streamer.ByteBuffer;
import streamer.Element;
import streamer.Link;
import streamer.MockSink;
import streamer.MockSource;
import streamer.Pipeline;
import streamer.PipelineImpl;
public class ServerChannel1003Router extends BaseElement {
/**
* Demand Active PDU.
*/
public static final int PDUTYPE_DEMANDACTIVEPDU = 0x1;
/**
* Confirm Active PDU.
*/
public static final int PDUTYPE_CONFIRMACTIVEPDU = 0x3;
/**
* Deactivate All PDU.
*/
public static final int PDUTYPE_DEACTIVATEALLPDU = 0x6;
/**
* Data PDU (actual type is revealed by the pduType2 field in the Share Data
* Header).
*/
public static final int PDUTYPE_DATAPDU = 0x7;
/**
* Enhanced Security Server Redirection PDU.
*/
public static final int PDUTYPE_SERVER_REDIR_PKT = 0xA;
protected RdpState state;
public ServerChannel1003Router(String id, RdpState state) {
super(id);
this.state = state;
}
/**
* @see http://msdn.microsoft.com/en-us/library/cc240576.aspx
*/
@Override
public void handleData(ByteBuffer buf, Link link) {
if (verbose)
System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
int length = buf.readUnsignedShortLE();
if (buf.length != length) {
// It is ServerErrorAlert-ValidClient
// Ignore it
//throw new RuntimeException("[" + this + "] ERROR: Incorrect PDU length: " + length + ", data: " + buf + ".");
}
int type = buf.readUnsignedShortLE() & 0xf;
// int sourceId = buf.readUnsignedShortLE();
buf.skipBytes(2);
switch (type) {
case PDUTYPE_DEMANDACTIVEPDU:
pushDataToPad("demand_active", buf);
break;
case PDUTYPE_CONFIRMACTIVEPDU:
throw new RuntimeException("Unexpected client CONFIRM ACTIVE PDU. Data: " + buf + ".");
case PDUTYPE_DEACTIVATEALLPDU:
// pushDataToPad("deactivate_all", buf);
/* ignore */buf.unref();
break;
case PDUTYPE_DATAPDU:
handleDataPdu(buf);
break;
case PDUTYPE_SERVER_REDIR_PKT:
// pushDataToPad("server_redir", buf);
/* ignore */buf.unref();
break;
default:
throw new RuntimeException("[" + this + "] ERROR: Unknown PDU type: " + type + ", data: " + buf + ".");
}
}
/**
* Graphics Update PDU.
*/
public static final int PDUTYPE2_UPDATE = 0x02;
/**
* Control PDU.
*/
public static final int PDUTYPE2_CONTROL = 0x14;
/**
* Pointer Update PDU.
*/
public static final int PDUTYPE2_POINTER = 0x1B;
/**
* Input Event PDU.
*/
public static final int PDUTYPE2_INPUT = 0x1C;
/**
* Synchronize PDU.
*/
public static final int PDUTYPE2_SYNCHRONIZE = 0x1F;
/**
* Refresh Rect PDU.
*/
public static final int PDUTYPE2_REFRESH_RECT = 0x21;
/**
* Play Sound PDU.
*/
public static final int PDUTYPE2_PLAY_SOUND = 0x22;
/**
* Suppress Output PDU.
*/
public static final int PDUTYPE2_SUPPRESS_OUTPUT = 0x23;
/**
* Shutdown Request PDU.
*/
public static final int PDUTYPE2_SHUTDOWN_REQUEST = 0x24;
/**
* Shutdown Request Denied PDU.
*/
public static final int PDUTYPE2_SHUTDOWN_DENIED = 0x25;
/**
* Save Session Info PDU.
*/
public static final int PDUTYPE2_SAVE_SESSION_INFO = 0x26;
/**
* Font List PDU.
*/
public static final int PDUTYPE2_FONTLIST = 0x27;
/**
* Font Map PDU.
*/
public static final int PDUTYPE2_FONTMAP = 0x28;
/**
* Set Keyboard Indicators PDU.
*/
public static final int PDUTYPE2_SET_KEYBOARD_INDICATORS = 0x29;
/**
* Persistent Key List PDU.
*/
public static final int PDUTYPE2_BITMAPCACHE_PERSISTENT_LIST = 0x2B;
/**
* Bitmap Cache Error PDU.
*/
public static final int PDUTYPE2_BITMAPCACHE_ERROR_PDU = 0x2C;
/**
* Set Keyboard IME Status PDU.
*/
public static final int PDUTYPE2_SET_KEYBOARD_IME_STATUS = 0x2D;
/**
* Offscreen Bitmap Cache Error PDU.
*/
public static final int PDUTYPE2_OFFSCRCACHE_ERROR_PDU = 0x2E;
/**
* Set Error Info PDU.
*/
public static final int PDUTYPE2_SET_ERROR_INFO_PDU = 0x2F;
/**
* DrawNineGrid Cache Error PDU.
*/
public static final int PDUTYPE2_DRAWNINEGRID_ERROR_PDU = 0x30;
/**
* GDI+ Error PDU.
*/
public static final int PDUTYPE2_DRAWGDIPLUS_ERROR_PDU = 0x31;
/**
* Auto-Reconnect Status PDU.
*/
public static final int PDUTYPE2_ARC_STATUS_PDU = 0x32;
/**
* Status Info PDU.
*/
public static final int PDUTYPE2_STATUS_INFO_PDU = 0x36;
/**
* Monitor Layout PDU.
*/
public static final int PDUTYPE2_MONITOR_LAYOUT_PDU = 0x37;
/**
* Indicates an Orders Update.
*/
public static final int UPDATETYPE_ORDERS = 0x0000;
/**
* Indicates a Bitmap Graphics Update.
*/
public static final int UPDATETYPE_BITMAP = 0x0001;
/**
* Indicates a Palette Update.
*/
public static final int UPDATETYPE_PALETTE = 0x0002;
/**
* Indicates a Synchronize Update.
*/
public static final int UPDATETYPE_SYNCHRONIZE = 0x0003;
/**
* @see http://msdn.microsoft.com/en-us/library/cc240577.aspx
*/
protected void handleDataPdu(ByteBuffer buf) {
// (4 bytes): A 32-bit, unsigned integer. Share identifier for the packet.
long shareId = buf.readUnsignedIntLE();
if (shareId != state.serverShareId)
throw new RuntimeException("Unexpected share ID: " + shareId + ".");
// buf.skipBytes(4);
// Padding.
buf.skipBytes(1);
// (1 byte): An 8-bit, unsigned integer. The stream identifier for the
// packet.
// int streamId = buf.readUnsignedByte();
buf.skipBytes(1);
// (2 bytes): A 16-bit, unsigned integer. The uncompressed length of the
// packet in bytes.
int uncompressedLength = buf.readUnsignedShortLE();
// (1 byte): An 8-bit, unsigned integer. The type of Data PDU.
int type2 = buf.readUnsignedByte();
// (1 byte): An 8-bit, unsigned integer. The compression type and flags
// specifying the data following the Share Data Header
int compressedType = buf.readUnsignedByte();
if (compressedType != 0)
throw new RuntimeException("Compression of protocol packets is not supported. Data: " + buf + ".");
// (2 bytes): A 16-bit, unsigned integer. The compressed length of the
// packet in bytes.
int compressedLength = buf.readUnsignedShortLE();
if (compressedLength != 0)
throw new RuntimeException("Compression of protocol packets is not supported. Data: " + buf + ".");
ByteBuffer data = buf.readBytes(uncompressedLength - 18);
buf.unref();
switch (type2) {
case PDUTYPE2_UPDATE: {
// (2 bytes): A 16-bit, unsigned integer. Type of the graphics update.
int updateType = data.readUnsignedShortLE();
ByteBuffer data2 = data.readBytes(data.length - data.cursor);
data.unref();
switch (updateType) {
case UPDATETYPE_ORDERS:
pushDataToPad("orders", data2);
break;
case UPDATETYPE_BITMAP:
pushDataToPad("bitmap", data2);
break;
case UPDATETYPE_PALETTE:
pushDataToPad("palette", data2);
break;
case UPDATETYPE_SYNCHRONIZE:
// Ignore
data2.unref();
break;
}
break;
}
case PDUTYPE2_CONTROL:
if (verbose)
System.out.println("[" + this + "] INFO: Packet PDUTYPE2_CONTROL ignored.");
// Ignore
data.unref();
break;
case PDUTYPE2_POINTER:
if (verbose)
System.out.println("[" + this + "] INFO: Packet PDUTYPE2_POINTER ignored.");
// Ignore
data.unref();
break;
case PDUTYPE2_INPUT:
if (verbose)
System.out.println("[" + this + "] INFO: Packet PDUTYPE2_INPUT ignored.");
// Ignore
data.unref();
break;
case PDUTYPE2_SYNCHRONIZE:
if (verbose)
System.out.println("[" + this + "] INFO: Packet PDUTYPE2_SYNCHRONIZE ignored.");
// Ignore
data.unref();
break;
case PDUTYPE2_REFRESH_RECT:
if (verbose)
System.out.println("[" + this + "] INFO: Packet PDUTYPE2_REFRESH_RECT ignored.");
// Ignore
data.unref();
break;
case PDUTYPE2_PLAY_SOUND:
if (verbose)
System.out.println("[" + this + "] INFO: Packet PDUTYPE2_PLAY_SOUND ignored.");
// Ignore
data.unref();
break;
case PDUTYPE2_SUPPRESS_OUTPUT:
if (verbose)
System.out.println("[" + this + "] INFO: Packet PDUTYPE2_SUPPRESS_OUTPUT ignored.");
// Ignore
data.unref();
break;
case PDUTYPE2_SHUTDOWN_REQUEST:
if (verbose)
System.out.println("[" + this + "] INFO: Packet PDUTYPE2_SHUTDOWN_REQUEST ignored.");
// Ignore
data.unref();
break;
case PDUTYPE2_SHUTDOWN_DENIED:
if (verbose)
System.out.println("[" + this + "] INFO: Packet PDUTYPE2_SHUTDOWN_DENIED ignored.");
// Ignore
data.unref();
break;
case PDUTYPE2_SAVE_SESSION_INFO:
if (verbose)
System.out.println("[" + this + "] INFO: Packet PDUTYPE2_SAVE_SESSION_INFO ignored.");
// Ignore
data.unref();
break;
case PDUTYPE2_FONTLIST:
if (verbose)
System.out.println("[" + this + "] INFO: Packet PDUTYPE2_FONTLIST ignored.");
// Ignore
data.unref();
break;
case PDUTYPE2_FONTMAP:
if (verbose)
System.out.println("[" + this + "] INFO: Packet PDUTYPE2_FONTMAP ignored.");
// Ignore
data.unref();
break;
case PDUTYPE2_SET_KEYBOARD_INDICATORS:
if (verbose)
System.out.println("[" + this + "] INFO: Packet PDUTYPE2_SET_KEYBOARD_INDICATORS ignored.");
// Ignore
data.unref();
break;
case PDUTYPE2_BITMAPCACHE_PERSISTENT_LIST:
if (verbose)
System.out.println("[" + this + "] INFO: Packet PDUTYPE2_BITMAPCACHE_PERSISTENT_LIST ignored.");
// Ignore
data.unref();
break;
case PDUTYPE2_BITMAPCACHE_ERROR_PDU:
if (verbose)
System.out.println("[" + this + "] INFO: Packet PDUTYPE2_BITMAPCACHE_ERROR_PDU ignored.");
// Ignore
data.unref();
break;
case PDUTYPE2_SET_KEYBOARD_IME_STATUS:
if (verbose)
System.out.println("[" + this + "] INFO: Packet PDUTYPE2_SET_KEYBOARD_IME_STATUS ignored.");
// Ignore
data.unref();
break;
case PDUTYPE2_OFFSCRCACHE_ERROR_PDU:
if (verbose)
System.out.println("[" + this + "] INFO: Packet PDUTYPE2_OFFSCRCACHE_ERROR_PDU ignored.");
// Ignore
data.unref();
break;
case PDUTYPE2_SET_ERROR_INFO_PDU:
if (verbose)
System.out.println("[" + this + "] INFO: Packet PDUTYPE2_SET_ERROR_INFO_PDU ignored.");
// Ignore
data.unref();
break;
case PDUTYPE2_DRAWNINEGRID_ERROR_PDU:
if (verbose)
System.out.println("[" + this + "] INFO: Packet PDUTYPE2_DRAWNINEGRID_ERROR_PDU ignored.");
// Ignore
data.unref();
break;
case PDUTYPE2_DRAWGDIPLUS_ERROR_PDU:
if (verbose)
System.out.println("[" + this + "] INFO: Packet PDUTYPE2_DRAWGDIPLUS_ERROR_PDU ignored.");
// Ignore
data.unref();
break;
case PDUTYPE2_ARC_STATUS_PDU:
if (verbose)
System.out.println("[" + this + "] INFO: Packet PDUTYPE2_ARC_STATUS_PDU ignored.");
// Ignore
data.unref();
break;
case PDUTYPE2_STATUS_INFO_PDU:
if (verbose)
System.out.println("[" + this + "] INFO: Packet PDUTYPE2_STATUS_INFO_PDU ignored.");
// Ignore
data.unref();
break;
case PDUTYPE2_MONITOR_LAYOUT_PDU:
if (verbose)
System.out.println("[" + this + "] INFO: Packet PDUTYPE2_MONITOR_LAYOUT_PDU ignored.");
// Ignore
data.unref();
break;
default:
throw new RuntimeException("Unknow data PDU type: " + type2 + ", data: " + 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");
byte[] packet = new byte[] {
// TPKT
(byte)0x03, (byte)0x00, // TPKT Header: TPKT version = 3
(byte)0x00, (byte)0x1B, // TPKT length: 27 bytes
// X224
(byte)0x02, // X224 Length: 2 bytes
(byte)0xF0, // X224 Type: Data
(byte)0x80, // X224 EOT
// MCS
// Type: send data indication: 26 (0x1a, top 6 bits)
(byte)0x68, // ??
(byte)0x00, (byte)0x01, // User ID: 1002 (1001+1)
(byte)0x03, (byte)0xEB, // Channel ID: 1003
(byte)0x70, // Data priority: high, segmentation: begin|end
(byte)0x0D, // Payload length: 13 bytes
// Deactivate all PDU
(byte)0x0D, (byte)0x00, // Length: 13 bytes (LE)
// - PDUType: (0x16, LE)
// Type: (............0110) TS_PDUTYPE_DEACTIVATEALLPDU
// ProtocolVersion: (000000000001....) 1
(byte)0x16, (byte)0x00,
(byte)0xEA, (byte)0x03, // PDU source: 1002 (LE)
(byte)0xEA, (byte)0x03, (byte)0x01, (byte)0x00, // ShareID = 66538
(byte)0x01, (byte)0x00, // Length if source descriptor: 1 (LE)
(byte)0x00, // Source descriptor (should be set to 0): 0
};
MockSource source = new MockSource("source", ByteBuffer.convertByteArraysToByteBuffers(packet));
RdpState rdpState = new RdpState() {
{
serverShareId = 66538;
}
};
Element channel1003 = new ServerChannel1003Router("channel_1003", rdpState);
Element mcs = new ServerMCSPDU("mcs");
Element tpkt = new ServerTpkt("tpkt");
Element x224 = new ServerX224DataPdu("x224");
Element sink = new MockSink("sink", ByteBuffer.convertByteArraysToByteBuffers(new byte[] {
// Deactivate all PDU
(byte)0x0D, (byte)0x00, // Length: 13 bytes (LE)
// - PDUType: 22 (0x16, LE)
// Type: (............0110) TS_PDUTYPE_DEACTIVATEALLPDU
// ProtocolVersion: (000000000001....) 1
(byte)0x16, (byte)0x00,
(byte)0xEA, (byte)0x03, // PDU source: 1002 (LE)
(byte)0xEA, (byte)0x03, (byte)0x01, (byte)0x00, // ShareID = 66538
(byte)0x01, (byte)0x00, // Length if source descriptor: 1 (LE)
(byte)0x00, // Source descriptor (should be set to 0): 0
}));
Pipeline pipeline = new PipelineImpl("test");
pipeline.add(source, tpkt, x224, mcs, channel1003, sink);
pipeline.link("source", "tpkt", "x224", "mcs >channel_1003", "channel_1003 >deactivate_all", "sink");
pipeline.runMainLoop("source", STDOUT, false, false);
}
}

View File

@ -1,660 +0,0 @@
// 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;
import streamer.BaseElement;
import streamer.ByteBuffer;
import streamer.Element;
import streamer.FakeSink;
import streamer.Link;
import streamer.MockSource;
import streamer.Order;
import streamer.Pipeline;
import streamer.PipelineImpl;
import common.ScreenDescription;
/**
* @see http://msdn.microsoft.com/en-us/library/cc240669.aspx
* @see http://msdn.microsoft.com/en-us/library/cc240484.aspx
*/
public class ServerDemandActivePDU extends BaseElement {
/**
* Demand Active PDU.
*/
public static final int PDUTYPE_DEMANDACTIVEPDU = 0x1;
protected RdpState state;
protected ScreenDescription screen;
public ServerDemandActivePDU(String id, ScreenDescription screen, RdpState state) {
super(id);
this.state = state;
this.screen = screen;
}
@Override
public void handleData(ByteBuffer buf, Link link) {
if (verbose)
System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
// Total length of packet
int length = buf.readSignedShortLE(); // Ignore
if (buf.length != length)
throw new RuntimeException("Incorrect length of packet. Length: " + length + ", data: " + buf + ".");
int type = buf.readSignedShortLE() & 0xf;
if (type != PDUTYPE_DEMANDACTIVEPDU)
throw new RuntimeException("Unknown PDU type. Expected type: Demand Active PDU (0x1), actual tyoe: " + type + ", data: " + buf + ".");
// TS_SHARECONTROLHEADER::pduSource = 0x03ea (1002)
int pduSource = buf.readSignedShortLE();
if (pduSource != 1002)
throw new RuntimeException("Unexepcted source of demand active PDU. Expected source: 1002, actual source: " + pduSource + ".");
// (4 bytes): A 32-bit, unsigned integer. The share identifier for the
// packet (see [T128] section 8.4.2 for more information regarding share
// IDs).
long shareId = buf.readUnsignedIntLE();
state.serverShareId = shareId;
// Ignore rest of server data because it is not used by this client.
// (2 bytes): A 16-bit, unsigned integer. The size in bytes of the
// sourceDescriptor field.
int lengthSourceDescriptor = buf.readUnsignedShortLE();
// (2 bytes): A 16-bit, unsigned integer. The combined size in bytes of the
// numberCapabilities, pad2Octets, and capabilitySets fields.
int lengthCombinedCapabilities = buf.readUnsignedShortLE();
// (variable): A variable-length array of bytes containing a source
// descriptor,
// ByteBuffer sourceDescriptor = buf.readBytes(lengthSourceDescriptor);
buf.skipBytes(lengthSourceDescriptor);
// (variable): An array of Capability Set (section 2.2.1.13.1.1.1)
// structures. The number of capability sets is specified by the
// numberCapabilities field.
handleCapabiltySets(buf.readBytes(lengthCombinedCapabilities));
// (4 bytes): A 32-bit, unsigned integer. The session identifier. This field
// is ignored by the client.
buf.skipBytes(4);
/* DEBUG */buf.assertThatBufferIsFullyRead();
buf.unref();
sendHandshakePackets();
}
/**
* General Capability Set
*/
public static final int CAPSTYPE_GENERAL = 0x0001;
/**
* Bitmap Capability Set
*/
public static final int CAPSTYPE_BITMAP = 0x0002;
/**
* Order Capability Set
*/
public static final int CAPSTYPE_ORDER = 0x0003;
/**
* Revision 1 Bitmap Cache Capability Set
*/
public static final int CAPSTYPE_BITMAPCACHE = 0x0004;
/**
* Control Capability Set
*/
public static final int CAPSTYPE_CONTROL = 0x0005;
/**
* Window Activation Capability Set
*/
public static final int CAPSTYPE_ACTIVATION = 0x0007;
/**
* Pointer Capability Set
*/
public static final int CAPSTYPE_POINTER = 0x0008;
/**
* Share Capability Set
*/
public static final int CAPSTYPE_SHARE = 0x0009;
/**
* Color Table Cache Capability Set
*/
public static final int CAPSTYPE_COLORCACHE = 0x000A;
/**
* Sound Capability Set
*/
public static final int CAPSTYPE_SOUND = 0x000C;
/**
* Input Capability Set
*/
public static final int CAPSTYPE_INPUT = 0x000D;
/**
* Font Capability Set
*/
public static final int CAPSTYPE_FONT = 0x000E;
/**
* Brush Capability Set
*/
public static final int CAPSTYPE_BRUSH = 0x000F;
/**
* Glyph Cache Capability Set
*/
public static final int CAPSTYPE_GLYPHCACHE = 0x0010;
/**
* Offscreen Bitmap Cache Capability Set
*/
public static final int CAPSTYPE_OFFSCREENCACHE = 0x0011;
/**
* Bitmap Cache Host Support Capability Set
*/
public static final int CAPSTYPE_BITMAPCACHE_HOSTSUPPORT = 0x0012;
/**
* Revision 2 Bitmap Cache Capability Set
*/
public static final int CAPSTYPE_BITMAPCACHE_REV2 = 0x0013;
/**
* Virtual Channel Capability Set
*/
public static final int CAPSTYPE_VIRTUALCHANNEL = 0x0014;
/**
* DrawNineGrid Cache Capability Set
*/
public static final int CAPSTYPE_DRAWNINEGRIDCACHE = 0x0015;
/**
* Draw GDI+ Cache Capability Set
*/
public static final int CAPSTYPE_DRAWGDIPLUS = 0x0016;
/**
* Remote Programs Capability Set
*/
public static final int CAPSTYPE_RAIL = 0x0017;
/**
* Window List Capability Set
*/
public static final int CAPSTYPE_WINDOW = 0x0018;
/**
* Desktop Composition Extension Capability Set
*/
public static final int CAPSETTYPE_COMPDESK = 0x0019;
/**
* Multifragment Update Capability Set
*/
public static final int CAPSETTYPE_MULTIFRAGMENTUPDATE = 0x001A;
/**
* Large Pointer Capability Set
*/
public static final int CAPSETTYPE_LARGE_POINTER = 0x001B;
/**
* Surface Commands Capability Set
*/
public static final int CAPSETTYPE_SURFACE_COMMANDS = 0x001C;
/**
* Bitmap Codecs Capability Set
*/
public static final int CAPSETTYPE_BITMAP_CODECS = 0x001D;
/**
* Frame Acknowledge Capability Set
*/
public static final int CAPSSETTYPE_FRAME_ACKNOWLEDGE = 0x001E;
/**
* @see http://msdn.microsoft.com/en-us/library/cc240486.aspx
*/
protected void handleCapabiltySets(ByteBuffer buf) {
// (2 bytes): A 16-bit, unsigned integer. The number of capability sets
// included in the Demand Active PDU.
int numberCapabilities = buf.readSignedShortLE();
// (2 bytes): Padding.
buf.skipBytes(2);
for (int i = 0; i < numberCapabilities; i++) {
// (2 bytes): A 16-bit, unsigned integer. The type identifier of the
// capability set.
int capabilitySetType = buf.readUnsignedShortLE();
// (2 bytes): A 16-bit, unsigned integer. The length in bytes of the
// capability data, including the size of the capabilitySetType and
// lengthCapability fields.
int lengthCapability = buf.readUnsignedShortLE();
// (variable): Capability set data which conforms to the structure of the
// type given by the capabilitySetType field.
ByteBuffer capabilityData = buf.readBytes(lengthCapability - 4);
switch (capabilitySetType) {
case CAPSTYPE_GENERAL:
break;
case CAPSTYPE_BITMAP:
handleBitmapCapabilities(capabilityData);
break;
case CAPSTYPE_ORDER:
break;
case CAPSTYPE_BITMAPCACHE:
break;
case CAPSTYPE_CONTROL:
break;
case CAPSTYPE_ACTIVATION:
break;
case CAPSTYPE_POINTER:
break;
case CAPSTYPE_SHARE:
break;
case CAPSTYPE_COLORCACHE:
break;
case CAPSTYPE_SOUND:
break;
case CAPSTYPE_INPUT:
break;
case CAPSTYPE_FONT:
break;
case CAPSTYPE_BRUSH:
break;
case CAPSTYPE_GLYPHCACHE:
break;
case CAPSTYPE_OFFSCREENCACHE:
break;
case CAPSTYPE_BITMAPCACHE_HOSTSUPPORT:
break;
case CAPSTYPE_BITMAPCACHE_REV2:
break;
case CAPSTYPE_VIRTUALCHANNEL:
break;
case CAPSTYPE_DRAWNINEGRIDCACHE:
break;
case CAPSTYPE_DRAWGDIPLUS:
break;
case CAPSTYPE_RAIL:
break;
case CAPSTYPE_WINDOW:
break;
case CAPSETTYPE_COMPDESK:
break;
case CAPSETTYPE_MULTIFRAGMENTUPDATE:
break;
case CAPSETTYPE_LARGE_POINTER:
break;
case CAPSETTYPE_SURFACE_COMMANDS:
break;
case CAPSETTYPE_BITMAP_CODECS:
break;
case CAPSSETTYPE_FRAME_ACKNOWLEDGE:
break;
default:
// Ignore
break;
}
capabilityData.unref();
}
// TODO
buf.unref();
}
/**
* @see http://msdn.microsoft.com/en-us/library/cc240554.aspx
*/
protected void handleBitmapCapabilities(ByteBuffer buf) {
// (2 bytes): A 16-bit, unsigned integer. The server MUST set this field to
// the color depth of the session, while the client SHOULD set this field to
// the color depth requested in the Client Core Data (section 2.2.1.3.2).
int preferredBitsPerPixel = buf.readUnsignedShortLE();
screen.setPixelFormatRGBTrueColor(preferredBitsPerPixel);
// receive1BitPerPixel (2 bytes): A 16-bit, unsigned integer. Indicates
// whether the client can receive 1 bpp. This field is ignored and SHOULD be
// set to TRUE (0x0001).
buf.skipBytes(2);
// receive4BitsPerPixel(2 bytes): A 16-bit, unsigned integer. Indicates
// whether the client can receive 4 bpp. This field is ignored and SHOULD be
// set to TRUE (0x0001).
buf.skipBytes(2);
// receive8BitsPerPixel (2 bytes): A 16-bit, unsigned integer. Indicates
// whether the client can receive 8 bpp. This field is ignored and SHOULD be
// set to TRUE (0x0001).
buf.skipBytes(2);
// (2 bytes): A 16-bit, unsigned integer. The width of the desktop in the
// session.
int desktopWidth = buf.readUnsignedShortLE();
// (2 bytes): A 16-bit, unsigned integer. The height of the desktop in the
// session.
int desktopHeight = buf.readUnsignedShortLE();
screen.setFramebufferSize(desktopWidth, desktopHeight);
// pad2octets (2 bytes): A 16-bit, unsigned integer. Padding. Values in this
// field MUST be ignored.
// desktopResizeFlag (2 bytes): A 16-bit, unsigned integer. Indicates
// whether resizing the desktop by using a Deactivation-Reactivation
// Sequence is supported.
// bitmapCompressionFlag (2 bytes): A 16-bit, unsigned integer. Indicates
// whether bitmap compression is supported. This field MUST be set to TRUE
// (0x0001) because support for compressed bitmaps is required for a
// connection to proceed.
// highColorFlags (1 byte): An 8-bit, unsigned integer. Client support for
// 16 bpp color modes. This field is ignored and SHOULD be set to zero.
// drawingFlags (1 byte): An 8-bit, unsigned integer. Flags describing
// support for 32 bpp bitmaps.
// multipleRectangleSupport (2 bytes): A 16-bit, unsigned integer. Indicates
// whether the use of multiple bitmap rectangles is supported in the Bitmap
// Update (section 2.2.9.1.1.3.1.2). This field MUST be set to TRUE (0x0001)
// because multiple rectangle support is required for a connection to
// proceed.
// pad2octetsB (2 bytes): A 16-bit, unsigned integer. Padding. Values in
// this field MUST be ignored.
}
/**
* Send all client requests in one hop, to simplify logic.
*/
protected void sendHandshakePackets() {
// Send reactivation sequence in bulk
pushDataToPad("confirm_active", new ByteBuffer((Order)null));
}
/**
* 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[] {
0x67, 0x01, // TS_SHARECONTROLHEADER::totalLength = 0x0167 = 359 bytes
0x11, 0x00, // TS_SHARECONTROLHEADER::pduType = 0x0011 0x0011 = 0x0010 | 0x0001 = TS_PROTOCOL_VERSION | PDUTYPE_DEMANDACTIVEPDU
(byte) 0xea, 0x03, // TS_SHARECONTROLHEADER::pduSource = 0x03ea (1002)
(byte) 0xea, 0x03, 0x01, 0x00, // TS_DEMAND_ACTIVE_PDU::shareId
0x04, 0x00, // TS_DEMAND_ACTIVE_PDU::lengthSourceDescriptor = 4 bytes
0x51, 0x01, // TS_DEMAND_ACTIVE_PDU::lengthCombinedCapabilities = 0x151 = 337 bytes
0x52, 0x44, 0x50, 0x00, // TS_DEMAND_ACTIVE_PDU::sourceDescriptor = "RDP"
0x0d, 0x00, // TS_DEMAND_ACTIVE_PDU::numberCapabilities = 13
0x00, 0x00, // TS_DEMAND_ACTIVE_PDU::pad2octets
// Share Capability Set (8 bytes)
// 0x09, 0x00, 0x08, 0x00, (byte) 0xea, 0x03, (byte) 0xdc, (byte) 0xe2,
//
0x09, 0x00, // TS_SHARE_CAPABILITYSET::capabilitySetType = CAPSTYPE_SHARE (9)
0x08, 0x00, // TS_SHARE_CAPABILITYSET::lengthCapability = 8 bytes
(byte) 0xea, 0x03, // TS_SHARE_CAPABILITYSET::nodeID = 0x03ea (1002)
(byte) 0xdc, (byte) 0xe2, // TS_SHARE_CAPABILITYSET::pad2octets
// General Capability Set (24 bytes)
// 0x01, 0x00, 0x18, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x04,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
//
0x01, 0x00, // TS_GENERAL_CAPABILITYSET::capabilitySetType = CAPSTYPE_GENERAL (1)
0x18, 0x00, // TS_GENERAL_CAPABILITYSET::lengthCapability = 24 bytes
0x01, 0x00, // TS_GENERAL_CAPABILITYSET::osMajorType = TS_OSMAJORTYPE_WINDOWS (1)
0x03, 0x00, // TS_GENERAL_CAPABILITYSET::osMinorType = TS_OSMINORTYPE_WINDOWS_NT (3)
0x00, 0x02, // TS_GENERAL_CAPABILITYSET::protocolVersion = TS_CAPS_PROTOCOLVERSION (0x0200)
0x00, 0x00, // TS_GENERAL_CAPABILITYSET::pad2octetsA
0x00, 0x00, // TS_GENERAL_CAPABILITYSET::generalCompressionTypes = 0
0x1d, 0x04, // TS_GENERAL_CAPABILITYSET::extraFlags = 0x041d = 0x0400 | 0x0010 | 0x0008 | 0x0004 | 0x0001 = NO_BITMAP_COMPRESSION_HDR | ENC_SALTED_CHECKSUM | AUTORECONNECT_SUPPORTED | LONG_CREDENTIALS_SUPPORTED | FASTPATH_OUTPUT_SUPPORTED
0x00, 0x00, // TS_GENERAL_CAPABILITYSET::updateCapabilityFlag = 0
0x00, 0x00, // TS_GENERAL_CAPABILITYSET::remoteUnshareFlag = 0
0x00, 0x00, // TS_GENERAL_CAPABILITYSET::generalCompressionLevel = 0
0x01, // TS_GENERAL_CAPABILITYSET::refreshRectSupport = TRUE
0x01, // TS_GENERAL_CAPABILITYSET::suppressOutputSupport = TRUE
// Virtual Channel Capability Set (8 bytes)
// 0x14, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, 0x00,
//
0x14, 0x00, // TS_VIRTUALCHANNEL_CAPABILITYSET::capabilitySetType = CAPSTYPE_VIRTUALCHANNEL (20)
0x08, 0x00, // TS_VIRTUALCHANNEL_CAPABILITYSET::lengthCapability = 8 bytes
0x02, 0x00, 0x00, 0x00, // TS_VIRTUALCHANNEL_CAPABILITYSET::vccaps1 = 0x00000002 = VCCAPS_COMPR_CS_8K
// DrawGdiPlus Capability Set (40 bytes)
// 0x16, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, (byte) 0xf6, 0x13, (byte) 0xf3, 0x01, 0x00, 0x00, 0x00,
// 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, (byte) 0x9c, (byte) 0xf6, 0x13, (byte) 0xf3, 0x61, (byte) 0xa6, (byte) 0x82, (byte) 0x80,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, (byte) 0x91, (byte) 0xbf,
//
0x16, 0x00, // TS_DRAW_GDIPLUS_CAPABILITYSET::capabilitySetType = CAPSTYPE_DRAWGDIPLUS (22)
0x28, 0x00, // TS_DRAW_GDIPLUS_CAPABILITYSET::lengthCapability = 40 bytes
0x00, 0x00, 0x00, 0x00, // TS_DRAW_GDIPLUS_CAPABILITYSET::drawGdiplusSupportLevel = TS_DRAW_GDIPLUS_DEFAULT (0)
0x70, (byte) 0xf6, 0x13, (byte) 0xf3, // TS_DRAW_GDIPLUS_CAPABILITYSET::GdipVersion (not initialized by server)
0x01, 0x00, 0x00, 0x00, // TS_DRAW_GDIPLUS_CAPABILITYSET::drawGdiplusCacheLevel = TS_DRAW_GDIPLUS_CACHE_LEVEL_ONE (1)
0x01, 0x00, // TS_GDIPLUS_CACHE_ENTRIES::GdipGraphicsCacheEntries (not initialized by server)
0x00, 0x00, // TS_GDIPLUS_CACHE_ENTRIES::GdipObjectBrushCacheEntries (not initialized by server)
0x18, 0x00, // TS_GDIPLUS_CACHE_ENTRIES::GdipObjectPenCacheEntries (not initialized by server)
0x00, 0x00, // TS_GDIPLUS_CACHE_ENTRIES::GdipObjectImageCacheEntries (not initialized by server)
(byte) 0x9c, (byte) 0xf6, // TS_GDIPLUS_CACHE_ENTRIES::GdipObjectImageAttributesCacheEntries (not initialized by server)
0x13, (byte) 0xf3, // TS_GDIPLUS_CACHE_CHUNK_SIZE::GdipGraphicsCacheChunkSize (not initialized by server)
0x61, (byte) 0xa6, // TS_GDIPLUS_CACHE_CHUNK_SIZE::GdipObjectBrushCacheChunkSize (not initialized by server)
(byte) 0x82, (byte) 0x80, // TS_GDIPLUS_CACHE_CHUNK_SIZE::GdipObjectPenCacheChunkSize (not initialized by server)
0x00, 0x00, // TS_GDIPLUS_CACHE_CHUNK_SIZE::GdipObjectImageAttributesCacheChunkSize (not initialized by server)
0x00, 0x00, // TS_GDIPLUS_IMAGE_CACHE_PROPERTIES::GdipObjectImageCacheChunkSize (not initialized by server)
0x00, 0x50, // TS_GDIPLUS_IMAGE_CACHE_PROPERTIES::GdipObjectImageCacheTotalSize (not initialized by server)
(byte) 0x91, (byte) 0xbf, // TS_GDIPLUS_IMAGE_CACHE_PROPERTIES::GdipObjectImageCacheMaxSize (not initialized by server)
// Font Capability Set (4 bytes)
// 0x0e, 0x00, 0x04, 0x00,
//
// Due to a bug, the TS_FONT_CAPABILITYSET capability set size is incorrectly set to 4 bytes (it must be 8 bytes). As a result of this bug, the fontSupportFlags and pad2octets fields are missing.
0x0e, 0x00, // TS_FONT_CAPABILITYSET::capabilitySetType = CAPSTYPE_FONT (14)
0x04, 0x00, // TS_FONT_CAPABILITYSET::lengthCapability = 4 bytes
// Bitmap Capability Set (28 bytes)
// 0x02, 0x00, 0x1c, 0x00, 0x18, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x05, 0x00, 0x04,
// 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
//
0x02, 0x00, // TS_BITMAP_CAPABILITYSET::capabilitySetType = CAPSTYPE_BITMAP (2)
0x1c, 0x00, // TS_BITMAP_CAPABILITYSET::lengthCapability = 28 bytes
0x18, 0x00, // TS_BITMAP_CAPABILITYSET::preferredBitsPerPixel = 24 bpp
0x01, 0x00, // TS_BITMAP_CAPABILITYSET::receive1BitPerPixel = TRUE
0x01, 0x00, // TS_BITMAP_CAPABILITYSET::receive4BitsPerPixel = TRUE
0x01, 0x00, // TS_BITMAP_CAPABILITYSET::receive8BitsPerPixel = TRUE
0x00, 0x05, // TS_BITMAP_CAPABILITYSET::desktopWidth = 1280 pixels
0x00, 0x04, // TS_BITMAP_CAPABILITYSET::desktopHeight = 1024 pixels
0x00, 0x00, // TS_BITMAP_CAPABILITYSET::pad2octets
0x01, 0x00, // TS_BITMAP_CAPABILITYSET::desktopResizeFlag = TRUE
0x01, 0x00, // TS_BITMAP_CAPABILITYSET::bitmapCompressionFlag = TRUE
0x00, // TS_BITMAP_CAPABILITYSET::highColorFlags = 0
0x00, // TS_BITMAP_CAPABILITYSET::pad1octet
0x01, 0x00, // TS_BITMAP_CAPABILITYSET::multipleRectangleSupport = TRUE
0x00, 0x00, // TS_BITMAP_CAPABILITYSET::pad2octetsB
// Order Capability Set (88 bytes)
// 0x03, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x40, 0x42, 0x0f, 0x00, 0x01, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00,
// 0x00, 0x00, 0x22, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01,
// 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01,
// 0x00, 0x00, 0x00, 0x00, (byte) 0xa1, 0x06, 0x00, 0x00, 0x40, 0x42, 0x0f, 0x00, 0x40, 0x42, 0x0f, 0x00,
// 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
//
0x03, 0x00, // TS_ORDER_CAPABILITYSET::capabilitySetType = CAPSTYPE_ORDER (3)
0x58, 0x00, // TS_ORDER_CAPABILITYSET::lengthCapability = 88 bytes
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // TS_ORDER_CAPABILITYSET::terminalDescriptor = ""
0x40, 0x42, 0x0f, 0x00, // TS_ORDER_CAPABILITYSET::pad4octetsA
0x01, 0x00, // TS_ORDER_CAPABILITYSET::desktopSaveXGranularity = 1
0x14, 0x00, // TS_ORDER_CAPABILITYSET::desktopSaveYGranularity = 20
0x00, 0x00, // TS_ORDER_CAPABILITYSET::pad2octetsA
0x01, 0x00, // TS_ORDER_CAPABILITYSET::maximumOrderLevel = ORD_LEVEL_1_ORDERS (1)
0x00, 0x00, // TS_ORDER_CAPABILITYSET::numberFonts = 0
0x22, 0x00, // TS_ORDER_CAPABILITYSET::orderFlags = 0x0022 = 0x0020 | 0x0002 = COLORINDEXSUPPORT | NEGOTIATEORDERSUPPORT
0x01, // TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_DSTBLT_INDEX] = TRUE
0x01, // TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_PATBLT_INDEX] = TRUE
0x01, // TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_SCRBLT_INDEX] = TRUE
0x01, // TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_MEMBLT_INDEX] = TRUE
0x01, // TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_MEM3BLT_INDEX] = TRUE
0x00, // TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_ATEXTOUT_INDEX] = FALSE
0x00, // TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_AEXTTEXTOUT_INDEX] = FALSE
0x01, // TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_DRAWNINEGRID_INDEX] = TRUE
0x01, // TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_LINETO_INDEX] = TRUE
0x01, // TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_MULTI_DRAWNINEGRID_INDEX] = TRUE
0x01, // TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_OPAQUERECT_INDEX] = TRUE
0x01, // TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_SAVEBITMAP_INDEX] = TRUE
0x00, // TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_WTEXTOUT_INDEX] = FALSE
0x00, // TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_MEMBLT_R2_INDEX] = FALSE
0x00, // TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_MEM3BLT_R2_INDEX] = FALSE
0x01, // TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_MULTIDSTBLT_INDEX] = TRUE
0x01, // TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_MULTIPATBLT_INDEX] = TRUE
0x01, // TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_MULTISCRBLT_INDEX] = TRUE
0x01, // TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_MULTIOPAQUERECT_INDEX] = TRUE
0x01, // TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_FAST_INDEX_INDEX] = TRUE
0x01, // TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_POLYGON_SC_INDEX] = TRUE
0x01, // TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_POLYGON_CB_INDEX] = TRUE
0x01, // TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_POLYLINE_INDEX] = TRUE
0x00, // TS_ORDER_CAPABILITYSET::orderSupport[23] = 0
0x01, // TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_FAST_GLYPH_INDEX] = TRUE
0x01, // TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_ELLIPSE_SC_INDEX] = TRUE
0x01, // TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_ELLIPSE_CB_INDEX] = TRUE
0x01, // TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_INDEX_INDEX] = TRUE
0x00, // TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_WEXTTEXTOUT_INDEX] = FALSE
0x00, // TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_WLONGTEXTOUT_INDEX] = FALSE
0x00, // TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_WLONGEXTTEXTOUT_INDEX] = FALSE
0x00, // TS_ORDER_CAPABILITYSET::orderSupport[24] = 0
(byte) 0xa1, 0x06, // TS_ORDER_CAPABILITYSET::textFlags = 0x06a1
0x00, 0x00, // TS_ORDER_CAPABILITYSET::pad2octetsB
0x40, 0x42, 0x0f, 0x00, // TS_ORDER_CAPABILITYSET::pad4octetsB
0x40, 0x42, 0x0f, 0x00, // TS_ORDER_CAPABILITYSET::desktopSaveSize = 0xf4240 = 1000000
0x01, 0x00, // TS_ORDER_CAPABILITYSET::pad2octetsC
0x00, 0x00, // TS_ORDER_CAPABILITYSET::pad2octetsD
0x00, 0x00, // TS_ORDER_CAPABILITYSET::textANSICodePage
0x00, 0x00, // TS_ORDER_CAPABILITYSET::pad2octetsE
// Color Table Cache Capability Set (8 bytes)
// 0x0a, 0x00, 0x08, 0x00, 0x06, 0x00, 0x00, 0x00,
//
0x0a, 0x00, // TS_COLORTABLECACHE_CAPABILITYSET::capabilitySetType = CAPSTYPE_COLORCACHE (10)
0x08, 0x00, // TS_COLORTABLECACHE_CAPABILITYSET::lengthCapability = 8 bytes
0x06, 0x00, // TS_COLORTABLECACHE_CAPABILITYSET::colorTableCacheSize = 6
0x00, 0x00, // TS_COLORTABLECACHE_CAPABILITYSET::pad2octets
// Bitmap Cache Host Support Capability Set (8 bytes)
// 0x12, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00,
//
0x12, 0x00, // TS_BITMAPCACHE_CAPABILITYSET_HOSTSUPPORT::capabilitySetType = CAPSTYPE_BITMAPCACHE_HOSTSUPPORT (18)
0x08, 0x00, // TS_BITMAPCACHE_CAPABILITYSET_HOSTSUPPORT::lengthCapability = 8 bytes
0x01, // TS_BITMAPCACHE_CAPABILITYSET_HOSTSUPPORT::CacheVersion = 1 (corresponds to rev. 2 capabilities)
0x00, // TS_BITMAPCACHE_CAPABILITYSET_HOSTSUPPORT::Pad1
0x00, 0x00, // TS_BITMAPCACHE_CAPABILITYSET_HOSTSUPPORT::Pad2
// Pointer Capability Set (10 bytes)
// 0x08, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x19, 0x00, 0x19, 0x00,
//
0x08, 0x00, // TS_POINTER_CAPABILITYSET::capabilitySetType = CAPSTYPE_POINTER (8)
0x0a, 0x00, // TS_POINTER_CAPABILITYSET::lengthCapability = 10 bytes
0x01, 0x00, // TS_POINTER_CAPABILITYSET::colorPointerFlag = TRUE
0x19, 0x00, // TS_POINTER_CAPABILITYSET::colorPointerCacheSize = 25
0x19, 0x00, // TS_POINTER_CAPABILITYSET::pointerCacheSize = 25
// Input Capability Set (88 bytes)
// 0x0d, 0x00, 0x58, 0x00, 0x35, 0x00, 0x00, 0x00, (byte) 0xa1, 0x06, 0x00, 0x00, 0x40, 0x42, 0x0f, 0x00,
// 0x0c, (byte) 0xf6, 0x13, (byte) 0xf3, (byte) 0x93, 0x5a, 0x37, (byte) 0xf3, 0x00, (byte) 0x90, 0x30, (byte) 0xe1, 0x34, 0x1c, 0x38, (byte) 0xf3,
// 0x40, (byte) 0xf6, 0x13, (byte) 0xf3, 0x04, 0x00, 0x00, 0x00, 0x4c, 0x54, (byte) 0xdc, (byte) 0xe2, 0x08, 0x50, (byte) 0xdc, (byte) 0xe2,
// 0x01, 0x00, 0x00, 0x00, 0x08, 0x50, (byte) 0xdc, (byte) 0xe2, 0x00, 0x00, 0x00, 0x00, 0x38, (byte) 0xf6, 0x13, (byte) 0xf3,
// 0x2e, 0x05, 0x38, (byte) 0xf3, 0x08, 0x50, (byte) 0xdc, (byte) 0xe2, 0x2c, (byte) 0xf6, 0x13, (byte) 0xf3, 0x00, 0x00, 0x00, 0x00,
// 0x08, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x19, 0x00,
//
0x0d, 0x00, // TS_INPUT_CAPABILITYSET::capabilitySetType = CAPSTYPE_INPUT (13)
0x58, 0x00, // TS_INPUT_CAPABILITYSET::lengthCapability = 88 bytes
0x35, 0x00, // TS_INPUT_CAPABILITYSET::inputFlags = 0x0035 = 0x0020 | 0x0010 | 0x0004 | 0x0001 = INPUT_FLAG_FASTPATH_INPUT2 | INPUT_FLAG_VKPACKET | INPUT_FLAG_MOUSEX | INPUT_FLAG_SCANCODES
0x00, 0x00, // TS_INPUT_CAPABILITYSET::pad2octetsA
(byte) 0xa1, 0x06, 0x00, 0x00, // TS_INPUT_CAPABILITYSET::keyboardLayout (not initialized by server)
0x40, 0x42, 0x0f, 0x00, // TS_INPUT_CAPABILITYSET::keyboardType (not initialized by server)
0x0c, (byte) 0xf6, 0x13, (byte) 0xf3, // TS_INPUT_CAPABILITYSET::keyboardSubType (not initialized by server)
(byte) 0x93, 0x5a, 0x37, (byte) 0xf3, // TS_INPUT_CAPABILITYSET::keyboardFunctionKey (not initialized by server)
// TS_INPUT_CAPABILITYSET::imeFileName (not initialized by server)
0x00, (byte) 0x90, 0x30, (byte) 0xe1, 0x34, 0x1c, 0x38, (byte) 0xf3, 0x40, (byte) 0xf6, 0x13, (byte) 0xf3, 0x04, 0x00, 0x00, 0x00,
0x4c, 0x54, (byte) 0xdc, (byte) 0xe2, 0x08, 0x50, (byte) 0xdc, (byte) 0xe2, 0x01, 0x00, 0x00, 0x00, 0x08, 0x50, (byte) 0xdc, (byte) 0xe2,
0x00, 0x00, 0x00, 0x00, 0x38, (byte) 0xf6, 0x13, (byte) 0xf3, 0x2e, 0x05, 0x38, (byte) 0xf3, 0x08, 0x50, (byte) 0xdc, (byte) 0xe2,
0x2c, (byte) 0xf6, 0x13, (byte) 0xf3, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x19, 0x00,
// RAIL Capability Set (8 bytes)
// 0x17, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
//
0x17, 0x00, // TS_RAIL_CAPABILITYSET::capabilitySetType = CAPSTYPE_RAIL (23)
0x08, 0x00, // TS_RAIL_CAPABILITYSET::lengthCapability = 8 bytes
0x00, 0x00, 0x00, 0x00, // TS_RAIL_CAPABILITYSET::railSupportLevel = TS_RAIL_LEVEL_DEFAULT (0)
// Windowing Capability Set (11 bytes)
// 0x18, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
//
0x18, 0x00, // TS_WINDOW_CAPABILITYSET::capabilitySetType = CAPSTYPE_WINDOW (24)
0x0b, 0x00, // TS_WINDOW_CAPABILITYSET::lengthCapability = 11 bytes
0x00, 0x00, 0x00, 0x00, // TS_WINDOW_CAPABILITYSET::wndSupportLevel = TS_WINDOW_LEVEL_DEFAULT (0)
0x00, // TS_WINDOW_CAPABILITYSET::nIconCaches = 0
0x00, 0x00, // TS_WINDOW_CAPABILITYSET::nIconCacheEntries = 0
// Remainder of Demand Active PDU:
0x00, 0x00, 0x00, 0x00, // TS_DEMAND_ACTIVE_PDU::sessionId = 0
};
/* @formatter:on */
RdpState rdpState = new RdpState();
ScreenDescription screenDescription = new ScreenDescription();
MockSource source = new MockSource("source", ByteBuffer.convertByteArraysToByteBuffers(packet));
Element demandActive = new ServerDemandActivePDU("demand_active", screenDescription, rdpState);
Element sink = new FakeSink("sink");
Pipeline pipeline = new PipelineImpl("test");
pipeline.add(source, demandActive, sink);
pipeline.link("source", "demand_active", "sink");
pipeline.runMainLoop("source", STDOUT, false, false);
}
}

View File

@ -1,258 +0,0 @@
// 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;
import streamer.BaseElement;
import streamer.ByteBuffer;
import streamer.Link;
/**
* @see http://msdn.microsoft.com/en-us/library/cc240621.aspx
*/
public class ServerFastPath extends BaseElement {
/**
* TPKT protocol version (first byte).
*/
public static final int PROTOCOL_TPKT = 3;
/**
* Fast path protocol version (first two bits of first byte).
*/
public static final int PROTOCOL_FASTPATH = 0;
/**
* TPKT packets will be pushed to that pad.
*/
public static final String TPKT_PAD = "tpkt";
private static final String ORDERS_PAD = "orders";
private static final String BITMAP_PAD = "bitmap";
private static final String PALETTE_PAD = "palette";
/**
* Indicates that packet contains 8 byte secure checksum at top of packet. Top
* two bits of first byte.
*/
public static final int FASTPATH_OUTPUT_SECURE_CHECKSUM = 1;
/**
* Indicates that packet contains 8 byte secure checksum at top of packet and
* packet content is encrypted. Top two bits of first byte.
*/
public static final int FASTPATH_OUTPUT_ENCRYPTED = 2;
public static final int FASTPATH_UPDATETYPE_ORDERS = 0;
public static final int FASTPATH_UPDATETYPE_BITMAP = 1;
public static final int FASTPATH_UPDATETYPE_PALETTE = 2;
public static final int FASTPATH_UPDATETYPE_SYNCHRONIZE = 3;
public static final int FASTPATH_UPDATETYPE_SURFCMDS = 4;
public static final int FASTPATH_UPDATETYPE_PTR_NULL = 5;
public static final int FASTPATH_UPDATETYPE_PTR_DEFAULT = 6;
public static final int FASTPATH_UPDATETYPE_PTR_POSITION = 8;
public static final int FASTPATH_UPDATETYPE_COLOR = 9;
public static final int FASTPATH_UPDATETYPE_CACHED = 0xa;
public static final int FASTPATH_UPDATETYPE_POINTER = 0xb;
public static final int FASTPATH_FRAGMENT_SINGLE = 0;
public static final int FASTPATH_FRAGMENT_LAST = 1;
public static final int FASTPATH_FRAGMENT_FIRST = 2;
public static final int FASTPATH_FRAGMENT_NEXT = 3;
public static final int FASTPATH_OUTPUT_COMPRESSION_USED = 2;
public ServerFastPath(String id) {
super(id);
}
@Override
public void handleData(ByteBuffer buf, Link link) {
if (buf == null)
return;
if (verbose)
System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
//* DEBUG */System.out.println(buf.toHexString(buf.length));
// We need at 4 bytes to read packet type (TPKT or FastPath) and packet
// length
if (!cap(buf, 4, UNLIMITED, link, false))
return;
int typeAndFlags = buf.readUnsignedByte();
if (typeAndFlags == PROTOCOL_TPKT) {
//
// TPKT
//
// Reserved
buf.skipBytes(1);
// Read TPKT length
int length = buf.readUnsignedShort();
if (!cap(buf, length, length, link, false))
// Wait for full packet to arrive
return;
pushDataToPad(TPKT_PAD, buf);
// TPKT is handled
return;
}
//
// FastPath
//
// Number of bytes in updateData field (including header (1+1 or 2
// bytes))
int length = buf.readVariableUnsignedShort();
// Length is the size of payload, so we need to calculate from cursor
if (!cap(buf, length, length, link, false))
// Wait for full packet to arrive
return;
int type = typeAndFlags & 0x3;
int securityFlags = (typeAndFlags >> 6) & 0x3;
// Assertions
{
if (type != PROTOCOL_FASTPATH)
throw new RuntimeException("Unknown protocol. Expected protocol: 0 (FastPath). Actual protocol: " + type + ", data: " + buf + ".");
switch (securityFlags) {
case FASTPATH_OUTPUT_SECURE_CHECKSUM:
// TODO
throw new RuntimeException("Secure checksum is not supported in FastPath packets.");
case FASTPATH_OUTPUT_ENCRYPTED:
// TODO
throw new RuntimeException("Encryption is not supported in FastPath packets.");
}
}
// TODO: optional FIPS information, when FIPS is selected
// TODO: optional data signature (checksum), when checksum or FIPS is
// selected
// Array of FastPath update fields
while (buf.cursor < buf.length) {
int updateHeader = buf.readUnsignedByte();
int size = buf.readUnsignedShortLE();
int updateCode = updateHeader & 0xf;
int fragmentation = (updateHeader >> 4) & 0x3;
int compression = (updateHeader >> 6) & 0x3;
if (verbose)
System.out.println("[" + this + "] INFO: FastPath update received. UpdateCode: " + updateCode + ", fragmentation: " + fragmentation + ", compression: " +
compression + ", size: " + size + ".");
ByteBuffer data = buf.readBytes(size);
buf.putMetadata("fragmentation", fragmentation);
buf.putMetadata("compression", compression);
switch (updateCode) {
case FASTPATH_UPDATETYPE_ORDERS:
if (verbose)
System.out.println("[" + this + "] INFO: FASTPATH_UPDATETYPE_ORDERS.");
pushDataToPad(ORDERS_PAD, data);
break;
case FASTPATH_UPDATETYPE_BITMAP:
if (verbose)
System.out.println("[" + this + "] INFO: FASTPATH_UPDATETYPE_BITMAP.");
pushDataToPad(BITMAP_PAD, data);
break;
case FASTPATH_UPDATETYPE_PALETTE:
if (verbose)
System.out.println("[" + this + "] INFO: FASTPATH_UPDATETYPE_PALETTE.");
pushDataToPad(PALETTE_PAD, data);
break;
case FASTPATH_UPDATETYPE_SYNCHRONIZE:
// @see http://msdn.microsoft.com/en-us/library/cc240625.aspx
if (verbose)
System.out.println("[" + this + "] INFO: FASTPATH_UPDATETYPE_SYNCHRONIZE.");
data.unref();
if (size != 0)
throw new RuntimeException("Size of FastPath synchronize packet must be 0. UpdateCode: " + updateCode + ", fragmentation: " + fragmentation +
", compression: " + compression + ", size: " + size + ", data: " + data + ".");
break;
case FASTPATH_UPDATETYPE_SURFCMDS:
if (verbose)
System.out.println("[" + this + "] INFO: FASTPATH_UPDATETYPE_SURFCMDS.");
break;
case FASTPATH_UPDATETYPE_PTR_NULL:
if (verbose)
System.out.println("[" + this + "] INFO: FASTPATH_UPDATETYPE_PTR_NULL.");
break;
case FASTPATH_UPDATETYPE_PTR_DEFAULT:
if (verbose)
System.out.println("[" + this + "] INFO: FASTPATH_UPDATETYPE_PTR_DEFAULT.");
break;
case FASTPATH_UPDATETYPE_PTR_POSITION:
if (verbose)
System.out.println("[" + this + "] INFO: FASTPATH_UPDATETYPE_PTR_POSITION.");
break;
case FASTPATH_UPDATETYPE_COLOR:
if (verbose)
System.out.println("[" + this + "] INFO: FASTPATH_UPDATETYPE_COLOR.");
break;
case FASTPATH_UPDATETYPE_CACHED:
if (verbose)
System.out.println("[" + this + "] INFO: FASTPATH_UPDATETYPE_CACHED.");
break;
case FASTPATH_UPDATETYPE_POINTER:
if (verbose)
System.out.println("[" + this + "] INFO: FASTPATH_UPDATETYPE_POINTER.");
break;
default:
throw new RuntimeException("Unknown FastPath update. UpdateCode: " + updateCode + ", fragmentation: " + fragmentation + ", compression: " +
compression + ", size: " + size + ", data: " + data + ".");
}
}
buf.unref();
}
}

View File

@ -1,149 +0,0 @@
// 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;
import streamer.BaseElement;
import streamer.ByteBuffer;
import streamer.Element;
import streamer.Link;
import streamer.MockSink;
import streamer.MockSource;
import streamer.Pipeline;
import streamer.PipelineImpl;
public class ServerMCSPDU extends BaseElement {
public ServerMCSPDU(String id) {
super(id);
}
@Override
public void handleData(ByteBuffer buf, Link link) {
if (verbose)
System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
byte headerByte = buf.readSignedByte();
int type = headerByte >> 2;
switch (type) {
// Expected type: send data indication: 26 (0x1a, top 6 bits, or 0x68)
case 0x1a: {
// int userId = buf.readUnsignedShort() + 1001; // User ID: 1002 (1001+1)
buf.skipBytes(2); // Ignore user ID
int channelId = buf.readUnsignedShort(); // Channel ID: 1003
int flags = buf.readSignedByte();
if ((flags & 0x30) != 0x30)
throw new RuntimeException("Fragmented MCS packets are not supported.");
int payloadLength = buf.readVariableUnsignedShort();
ByteBuffer data = buf.readBytes(payloadLength);
buf.unref();
pushDataToPad("channel_" + channelId, data);
break;
}
case 0x8: {
// Disconnection sequence.
buf.unref();
break;
}
default:
throw new RuntimeException("Unsupported MCS packet type: " + type + "(" + headerByte + "), data: " + 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");
byte[] packet = new byte[] {
// TPKT
(byte)0x03, (byte)0x00, // TPKT Header: TPKT version = 3
(byte)0x00, (byte)0x1B, // TPKT length: 27 bytes
// X224
(byte)0x02, // X224 Length: 2 bytes
(byte)0xF0, // X224 Type: Data
(byte)0x80, // X224 EOT
// MCS
// Type: send data indication: 26 (0x1a, top 6 bits)
(byte)0x68, // ??
(byte)0x00, (byte)0x01, // User ID: 1002 (1001+1)
(byte)0x03, (byte)0xEB, // Channel ID: 1003
(byte)0x70, // Data priority: high, segmentation: begin|end
(byte)0x0D, // Payload length: 13 bytes
// Deactivate all PDU
(byte)0x0D, (byte)0x00, // Length: 13 bytes (LE)
// - PDUType: 22 (0x16, LE)
// Type: (............0110) TS_PDUTYPE_DEACTIVATEALLPDU
// ProtocolVersion: (000000000001....) 1
(byte)0x16, (byte)0x00,
(byte)0xEA, (byte)0x03, // PDU source: 1002 (LE)
(byte)0xEA, (byte)0x03, (byte)0x01, (byte)0x00, // ShareID = 66538
(byte)0x01, (byte)0x00, // Length if source descriptor: 1 (LE)
(byte)0x00, // Source descriptor (should be set to 0): 0
};
MockSource source = new MockSource("source", ByteBuffer.convertByteArraysToByteBuffers(packet));
Element mcs = new ServerMCSPDU("mcs") {
{
verbose = true;
}
};
Element tpkt = new ServerTpkt("tpkt");
Element x224 = new ServerX224DataPdu("x224");
Element sink = new MockSink("sink", ByteBuffer.convertByteArraysToByteBuffers(new byte[] {
// Deactivate all PDU
(byte)0x0D, (byte)0x00, // Length: 13 bytes (LE)
// - PDUType: 22 (0x16, LE)
// Type: (............0110) TS_PDUTYPE_DEACTIVATEALLPDU
// ProtocolVersion: (000000000001....) 1
(byte)0x16, (byte)0x00,
(byte)0xEA, (byte)0x03, // PDU source: 1002 (LE)
(byte)0xEA, (byte)0x03, (byte)0x01, (byte)0x00, // ShareID = 66538
(byte)0x01, (byte)0x00, // Length if source descriptor: 1 (LE)
(byte)0x00, // Source descriptor (should be set to 0): 0
}));
Pipeline pipeline = new PipelineImpl("test");
pipeline.add(source, tpkt, x224, mcs, sink);
pipeline.link("source", "tpkt", "x224", "mcs >channel_1003", "sink");
pipeline.runMainLoop("source", STDOUT, false, false);
}
}

View File

@ -1,50 +0,0 @@
// 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;
/**
* 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 TPKT unknown packet", "03"),
// new Pair("Server FastPath update with flags or continuation", ".*"),
// @formatter:on
};
public ServerPacketSniffer(String id) {
super(id, serverRegexps);
}
}

View File

@ -0,0 +1,350 @@
// 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.adapter;
import java.awt.event.KeyEvent;
import streamer.BaseElement;
import streamer.ByteBuffer;
import streamer.Link;
import common.KeyOrder;
public class AwtRdpKeyboardAdapter extends BaseElement {
/**
* Absence of this flag indicates a key-down event, while its presence
* indicates a key-release event.
*/
public static final int FASTPATH_INPUT_KBDFLAGS_RELEASE = 0x01;
/**
* Keystroke message contains an extended scancode. For enhanced 101-key and
* 102-key keyboards, extended keys include the right ALT and right CTRL keys
* on the main section of the keyboard; the INS, DEL, HOME, END, PAGE UP, PAGE
* DOWN and ARROW keys in the clusters to the left of the numeric keypad; and
* the Divide ("/") and ENTER keys in the numeric keypad.
*/
public static final int FASTPATH_INPUT_KBDFLAGS_EXTENDED = 0x02;
public static final int FASTPATH_INPUT_EVENT_SCANCODE = 0;
public AwtRdpKeyboardAdapter(String id) {
super(id);
}
@Override
public void handleData(ByteBuffer buf, Link link) {
if (verbose)
System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
KeyOrder order = (KeyOrder)buf.getOrder();
buf.unref();
ByteBuffer outBuf = new ByteBuffer(2, true);
int scanCode = map_en_us(order.event);
// eventHeader (1 byte): An 8-bit, unsigned integer. The format of this
// field is the same as the eventHeader byte field described in section
// 2.2.8.1.2.2. The eventCode bitfield (3 bits in size) MUST be set to
// FASTPATH_INPUT_EVENT_SCANCODE (0). The eventFlags bitfield (5 bits in
// size) contains flags describing the keyboard event.
outBuf.writeByte((scanCode >> 8) | (FASTPATH_INPUT_EVENT_SCANCODE << 5) | ((order.pressed) ? 0 : FASTPATH_INPUT_KBDFLAGS_RELEASE));
// keyCode (1 byte): An 8-bit, unsigned integer. The scancode of the key
// which triggered the event.
outBuf.writeByte(scanCode);
// Push buffer to one pad only, so it can be modified without copying of
// data
pushDataToPad(STDOUT, outBuf);
}
/**
* Return key scan code (in lower byte) and extended flags (in second byte).
*/
private int map_en_us(KeyEvent event) {
// Also set extended key flag when necessary.
// For enhanced 101-key and 102-key keyboards, extended keys include the
// right ALT and right CTRL keys on the main section of the keyboard; the
// INS, DEL, HOME, END, PAGE UP, PAGE DOWN and ARROW keys in the clusters to
// the left of the numeric keypad; and the Divide ("/") and ENTER keys in
// the numeric keypad.
switch (event.getKeyCode()) {
// Functional keys
case KeyEvent.VK_ESCAPE:
return 1;
case KeyEvent.VK_F1:
return 59;
case KeyEvent.VK_F2:
return 60;
case KeyEvent.VK_F3:
return 61;
case KeyEvent.VK_F4:
return 62;
case KeyEvent.VK_F5:
return 63;
case KeyEvent.VK_F6:
return 64;
case KeyEvent.VK_F7:
return 65;
case KeyEvent.VK_F8:
return 66;
case KeyEvent.VK_F9:
return 67;
case KeyEvent.VK_F10:
return 68;
case KeyEvent.VK_F11:
return 87;
case KeyEvent.VK_F12:
return 88;
// Row #1
case KeyEvent.VK_BACK_QUOTE:
return 41;
case KeyEvent.VK_1:
return 2;
case KeyEvent.VK_2:
return 3;
case KeyEvent.VK_3:
return 4;
case KeyEvent.VK_4:
return 5;
case KeyEvent.VK_5:
return 6;
case KeyEvent.VK_6:
return 7;
case KeyEvent.VK_7:
return 8;
case KeyEvent.VK_8:
return 9;
case KeyEvent.VK_9:
return 10;
case KeyEvent.VK_0:
return 11;
case KeyEvent.VK_MINUS:
return 12;
case KeyEvent.VK_EQUALS:
return 13;
case KeyEvent.VK_BACK_SPACE:
return 14;
// Row #2
case KeyEvent.VK_TAB:
return 15;
case KeyEvent.VK_Q:
return 16;
case KeyEvent.VK_W:
return 17;
case KeyEvent.VK_E:
return 18;
case KeyEvent.VK_R:
return 19;
case KeyEvent.VK_T:
return 20;
case KeyEvent.VK_Y:
return 21;
case KeyEvent.VK_U:
return 22;
case KeyEvent.VK_I:
return 23;
case KeyEvent.VK_O:
return 24;
case KeyEvent.VK_P:
return 25;
case KeyEvent.VK_OPEN_BRACKET:
return 26;
case KeyEvent.VK_CLOSE_BRACKET:
return 27;
case KeyEvent.VK_ENTER:
switch (event.getKeyLocation()) {
default:
case KeyEvent.KEY_LOCATION_STANDARD:
return 28;
case KeyEvent.KEY_LOCATION_NUMPAD:
return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 28;
}
// Row #3
case KeyEvent.VK_CAPS_LOCK:
return 58;
case KeyEvent.VK_A:
return 30;
case KeyEvent.VK_S:
return 31;
case KeyEvent.VK_D:
return 32;
case KeyEvent.VK_F:
return 33;
case KeyEvent.VK_G:
return 34;
case KeyEvent.VK_H:
return 35;
case KeyEvent.VK_J:
return 36;
case KeyEvent.VK_K:
return 37;
case KeyEvent.VK_L:
return 38;
case KeyEvent.VK_SEMICOLON:
return 39;
case KeyEvent.VK_QUOTE:
return 40;
// Row #4
case KeyEvent.VK_SHIFT:
switch (event.getKeyLocation()) {
default:
case KeyEvent.KEY_LOCATION_LEFT:
return 42;
case KeyEvent.KEY_LOCATION_RIGHT:
return 54;
}
case KeyEvent.VK_BACK_SLASH:
return 43;
case KeyEvent.VK_Z:
return 44;
case KeyEvent.VK_X:
return 45;
case KeyEvent.VK_C:
return 46;
case KeyEvent.VK_V:
return 47;
case KeyEvent.VK_B:
return 48;
case KeyEvent.VK_N:
return 49;
case KeyEvent.VK_M:
return 50;
case KeyEvent.VK_COMMA:
return 51;
case KeyEvent.VK_PERIOD:
return 52;
case KeyEvent.VK_SLASH:
return 53;
//
// Bottom row
case KeyEvent.VK_CONTROL:
switch (event.getKeyLocation()) {
default:
case KeyEvent.KEY_LOCATION_LEFT:
return 29;
case KeyEvent.KEY_LOCATION_RIGHT:
return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 29;
}
case KeyEvent.VK_WINDOWS:
switch (event.getKeyLocation()) {
default:
case KeyEvent.KEY_LOCATION_LEFT:
return 91;
case KeyEvent.KEY_LOCATION_RIGHT:
return 92;
}
case KeyEvent.VK_ALT:
switch (event.getKeyLocation()) {
default:
case KeyEvent.KEY_LOCATION_LEFT:
return 56;
case KeyEvent.KEY_LOCATION_RIGHT:
return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 56;
}
case KeyEvent.VK_ALT_GRAPH:
return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 56;
case KeyEvent.VK_SPACE:
return 57;
case KeyEvent.VK_CONTEXT_MENU:
return 93;
//
// Special keys
case KeyEvent.VK_PRINTSCREEN:
return 55;
case KeyEvent.VK_SCROLL_LOCK:
return 70;
case KeyEvent.VK_PAUSE:
return 29;
// Text navigation keys
case KeyEvent.VK_INSERT:
return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 82;
case KeyEvent.VK_HOME:
return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 71;
case KeyEvent.VK_PAGE_UP:
return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 73;
case KeyEvent.VK_DELETE:
return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 83;
case KeyEvent.VK_END:
return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 79;
case KeyEvent.VK_PAGE_DOWN:
return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 81;
// Cursor keys
case KeyEvent.VK_UP:
return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 72;
case KeyEvent.VK_LEFT:
return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 75;
case KeyEvent.VK_DOWN:
return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 80;
case KeyEvent.VK_RIGHT:
return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 77;
// Keypad
case KeyEvent.VK_NUM_LOCK:
return 69;
case KeyEvent.VK_DIVIDE:
return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 53;
case KeyEvent.VK_MULTIPLY:
return 55;
case KeyEvent.VK_SUBTRACT:
return 74;
case KeyEvent.VK_ADD:
return 78;
case KeyEvent.VK_NUMPAD7:
return 71;
case KeyEvent.VK_NUMPAD8:
return 72;
case KeyEvent.VK_NUMPAD9:
return 73;
case KeyEvent.VK_NUMPAD4:
return 75;
case KeyEvent.VK_NUMPAD5:
return 76;
case KeyEvent.VK_NUMPAD6:
return 77;
case KeyEvent.VK_NUMPAD1:
return 79;
case KeyEvent.VK_NUMPAD2:
return 80;
case KeyEvent.VK_NUMPAD3:
return 81;
case KeyEvent.VK_NUMPAD0:
return 82;
case KeyEvent.VK_DECIMAL:
return 83;
default:
System.err.println("Key is not mapped: " + event + ".");
return 57; // Space
}
}
}

View File

@ -14,7 +14,7 @@
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package rdpclient;
package rdpclient.adapter;
import java.awt.event.InputEvent;
@ -27,58 +27,58 @@ import common.MouseOrder;
* @see http://msdn.microsoft.com/en-us/library/cc240594.aspx
*/
public class AwtRdpMouseAdapter extends BaseElement {
public static final int FASTPATH_INPUT_EVENT_MOUSE = 0x01;
public final static int FASTPATH_INPUT_EVENT_MOUSE = 0x01;
/**
* Event is a mouse wheel rotation. The only valid flags in a wheel rotation
* event are PTRFLAGS_WHEEL_NEGATIVE and the WheelRotationMask; all other
* pointer flags are ignored.
*/
public static final int PTRFLAGS_WHEEL = 0x0200;
public final static int PTRFLAGS_WHEEL = 0x0200;
/**
* Wheel rotation value (contained in the WheelRotationMask bit field) is
* negative and MUST be sign-extended before injection at the server.
*/
public static final int PTRFLAGS_WHEEL_NEGATIVE = 0x0100;
public final static int PTRFLAGS_WHEEL_NEGATIVE = 0x0100;
/**
* Bit field describing the number of rotation units the mouse wheel was
* rotated. The value is negative if the PTRFLAGS_WHEEL_NEGATIVE flag is set.
*/
public static final int WHEEL_ROTATION_MASK = 0x01FF;
public final static int WHEEL_ROTATION_MASK = 0x01FF;
/**
* Indicates that the mouse position MUST be updated to the location specified
* by the xPos and yPos fields.
*/
public static final int PTRFLAGS_MOVE = 0x0800;
public final static int PTRFLAGS_MOVE = 0x0800;
/**
* Indicates that a click event has occurred at the position specified by the
* xPos and yPos fields. The button flags indicate which button has been
* clicked and at least one of these flags MUST be set.
*/
public static final int PTRFLAGS_DOWN = 0x8000;
public final static int PTRFLAGS_DOWN = 0x8000;
/**
* Mouse button 1 (left button) was clicked or released. If the PTRFLAGS_DOWN
* flag is set, then the button was clicked, otherwise it was released.
*/
public static final int PTRFLAGS_BUTTON1 = 0x1000;
public final static int PTRFLAGS_BUTTON1 = 0x1000;
/**
* Mouse button 2 (right button) was clicked or released. If the PTRFLAGS_DOWN
* flag is set, then the button was clicked, otherwise it was released.
*/
public static final int PTRFLAGS_BUTTON2 = 0x2000;
public final static int PTRFLAGS_BUTTON2 = 0x2000;
/**
* Mouse button 3 (middle button or wheel) was clicked or released. If the
* PTRFLAGS_DOWN flag is set, then the button was clicked, otherwise it was
* released.
*/
public static final int PTRFLAGS_BUTTON3 = 0x4000;
public final static int PTRFLAGS_BUTTON3 = 0x4000;
public AwtRdpMouseAdapter(String id) {
super(id);

View File

@ -0,0 +1,143 @@
// 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.clip;
import java.util.Map;
import rdpclient.rdp.RdpConstants;
import streamer.ByteBuffer;
public class ClipboardDataFormat {
public static final String HTML_FORMAT = "HTML Format";
public static final String RTF_AS_TEXT = "RTF As Text";
public static final String RICH_TEXT_FORMAT_WITHOUT_OBJECTS = "Rich Text Format Without Objects";
public static final String RICH_TEXT_FORMAT = "Rich Text Format";
public static final int CB_FORMAT_TEXT = 0x0001;
public static final int CB_FORMAT_UNICODETEXT = 0x000D;
/**
* Supported clipboard data formats in order of preference.
*/
public static final Object[] supportedTextBasedFormats = new Object[] {
// ID's
CB_FORMAT_UNICODETEXT, CB_FORMAT_TEXT,
// Names
HTML_FORMAT,
// RTF_AS_TEXT,
// RICH_TEXT_FORMAT_WITHOUT_OBJECTS,
// RICH_TEXT_FORMAT,
};
public final int id;
public final String name;
public ClipboardDataFormat(int id, String name) {
super();
this.id = id;
this.name = name;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ClipboardDataFormat other = (ClipboardDataFormat)obj;
if (id != other.id)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
@Override
public String toString() {
return "ClipboardDataFormat [id=" + id + ", name=\"" + name + "\"" + ((id == CB_FORMAT_UNICODETEXT) ? " (Unicode text)" : "")
+ ((id == CB_FORMAT_TEXT) ? " (text)" : "") + "]";
}
public int getId() {
return id;
}
public String getName() {
return name;
}
/**
* Parse response of supported format and return it as string.
*/
public String parseServerResponseAsString(ByteBuffer buf) {
switch (id) {
case CB_FORMAT_UNICODETEXT:
return buf.readVariableWideString(RdpConstants.CHARSET_16);
case CB_FORMAT_TEXT:
return buf.readVariableString(RdpConstants.CHARSET_8);
}
if (name == null || name.length() == 0)
return null;
if (HTML_FORMAT.equals(name))
return buf.readVariableString(RdpConstants.CHARSET_8); // TODO: verify
// if (RTF_AS_TEXT.equals(name))
// return buf.readVariableString(RdpConstants.CHARSET_8); // TODO: verify
//
// if (RICH_TEXT_FORMAT_WITHOUT_OBJECTS.equals(name))
// return buf.readVariableString(RdpConstants.CHARSET_8); // TODO: verify
//
// if (RICH_TEXT_FORMAT.equals(name))
// return buf.readVariableString(RdpConstants.CHARSET_8); // TODO: verify
return null;
}
/**
* Find first (richest) text-based data format.
*
* @return text-based data format or null, when not found
*/
public static ClipboardDataFormat findBestTextFormat(Map<Object, ClipboardDataFormat> serverClipboardDataFormats) {
for (Object formatKey : ClipboardDataFormat.supportedTextBasedFormats)
if (serverClipboardDataFormats.containsKey(formatKey))
return serverClipboardDataFormats.get(formatKey);
return null;
}
}

View File

@ -0,0 +1,70 @@
// 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.clip;
import java.util.HashMap;
import java.util.Map;
public class ClipboardState {
/**
* The Long Format Name variant of the Format List PDU is supported for
* exchanging updated format names. If this flag is not set, the Short Format
* Name variant MUST be used. If this flag is set by both protocol endpoints,
* then the Long Format Name variant MUST be used.
*/
public boolean serverUseLongFormatNames = false;
public final boolean clientUseLongFormatNames = false;
/**
* File copy and paste using stream-based operations are supported using the
* File Contents Request PDU and File Contents Response PDU.
*/
public boolean serverStreamFileClipEnabled = false;
public final boolean clientStreamFileClipEnabled = false;
/**
* Indicates that any description of files to copy and paste MUST NOT include
* the source path of the files.
*/
public boolean serverFileClipNoFilePaths = false;
public final boolean clientFileClipNoFilePaths = false;
/**
* Locking and unlocking of File Stream data on the clipboard is supported
* using the Lock Clipboard Data PDU and Unlock Clipboard Data PDU.
*/
public boolean serverCanLockClipdata = false;
public final boolean clientCanLockClipdata = false;
/**
* The Monitor Ready PDU is sent from the server to the client to indicate
* that the server is initialized and ready.
*/
public boolean serverReady = false;
/**
* Set of data formats, which are supported by server for paste operation.
*/
public Map<Object, ClipboardDataFormat> serverClipboardDataFormats = new HashMap<Object, ClipboardDataFormat>(0);
/**
* Server sends clipboard data in requested format.
*/
public ClipboardDataFormat serverRequestedFormat;
}

View File

@ -0,0 +1,193 @@
// 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.clip;
import streamer.BaseElement;
import streamer.ByteBuffer;
import streamer.Link;
public class ServerClipRdrChannelRouter extends BaseElement {
/**
* Key for ASCII names message flag in payload metadata. Value is Boolean.
*/
public static final String ASCII_NAMES = "ascii_names";
/**
* Key for success/fail message flag in payload metadata. Value is Boolean.
*/
public static final String SUCCESS = "success";
/**
* Monitor Ready PDU
*/
public static final int CB_MONITOR_READY = 0x0001;
/**
* Format List PDU
*/
public static final int CB_FORMAT_LIST = 0x0002;
/**
* Format List Response PDU
*/
public static final int CB_FORMAT_LIST_RESPONSE = 0x0003;
/**
* Format Data Request PDU
*/
public static final int CB_FORMAT_DATA_REQUEST = 0x0004;
/**
* Format Data Response PDU
*/
public static final int CB_FORMAT_DATA_RESPONSE = 0x0005;
/**
* Temporary Directory PDU
*/
public static final int CB_TEMP_DIRECTORY = 0x0006;
/**
* Clipboard Capabilities PDU
*/
public static final int CB_CLIP_CAPS = 0x0007;
/**
* File Contents Request PDU
*/
public static final int CB_FILECONTENTS_REQUEST = 0x0008;
/**
* File Contents Response PDU
*/
public static final int CB_FILECONTENTS_RESPONSE = 0x0009;
/**
* Lock Clipboard Data PDU
*/
public static final int CB_LOCK_CLIPDATA = 0x000A;
/**
* Unlock Clipboard Data PDU
*/
public static final int CB_UNLOCK_CLIPDATA = 0x000B;
/**
* Used by the Format List Response PDU, Format Data Response PDU, and File
* Contents Response PDU to indicate that the associated request Format List
* PDU, Format Data Request PDU, and File Contents Request PDU were processed
* successfully.
*/
public static final int CB_RESPONSE_OK = 0x0001;
/**
* Used by the Format List Response PDU, Format Data Response PDU, and File
* Contents Response PDU to indicate that the associated Format List PDU,
* Format Data Request PDU, and File Contents Request PDU were not processed
* successfully.
*/
public static final int CB_RESPONSE_FAIL = 0x0002;
/**
* Used by the Short Format Name variant of the Format List Response PDU to
* indicate the format names are in ASCII 8.
*/
public static final int CB_ASCII_NAMES = 0x0004;
public ServerClipRdrChannelRouter(String id) {
super(id);
}
@Override
public void handleData(ByteBuffer buf, Link link) {
if (verbose)
System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
// Parse PDU header
// Example: 07 00 -> CLIPRDR_HEADER::msgType = CB_CLIP_CAPS (7)
int msgType = buf.readUnsignedShortLE();
// Example: 00 00 -> CLIPRDR_HEADER::msgFlags = 0
int msgFlags = buf.readUnsignedShortLE();
// Example: 10 00 00 00 -> CLIPRDR_HEADER::dataLen = 0x10 = 16 bytes
long dataLenLong = buf.readSignedIntLE();
if (dataLenLong > 4 * 1024 * 1024)
throw new RuntimeException("Clipboard packet is too long. Expected length: less than 4MiB. Actual length: " + dataLenLong + ".");
int dataLen = (int)dataLenLong;
ByteBuffer payload = buf.readBytes(dataLen);
// Parse message flags and store them in the payload metadata
if ((msgFlags & CB_RESPONSE_OK) == CB_RESPONSE_OK)
payload.putMetadata("success", true);
if ((msgFlags & CB_RESPONSE_FAIL) == CB_RESPONSE_FAIL)
payload.putMetadata(SUCCESS, false);
if ((msgFlags & CB_ASCII_NAMES) == CB_ASCII_NAMES)
payload.putMetadata(ASCII_NAMES, true);
// Push PDU to appropriate handler
switch (msgType) {
case CB_MONITOR_READY:
pushDataToPad("monitor_ready", payload);
break;
case CB_FORMAT_LIST:
pushDataToPad("format_list", payload);
break;
case CB_FORMAT_LIST_RESPONSE:
pushDataToPad("format_list_response", payload);
break;
case CB_FORMAT_DATA_REQUEST:
pushDataToPad("format_data_request", payload);
break;
case CB_FORMAT_DATA_RESPONSE:
pushDataToPad("format_data_response", payload);
break;
case CB_TEMP_DIRECTORY:
throw new RuntimeException("[" + this + "] ERROR: Unexpected clipboard temporary directory PDU received from server. Data: " + buf + ".");
case CB_CLIP_CAPS:
pushDataToPad("clipboard_capabilities", payload);
break;
case CB_FILECONTENTS_REQUEST:
pushDataToPad("filecontent_request", payload);
break;
case CB_FILECONTENTS_RESPONSE:
pushDataToPad("filecontent_response", payload);
break;
case CB_LOCK_CLIPDATA:
pushDataToPad("lock_clipdata", payload);
break;
case CB_UNLOCK_CLIPDATA:
pushDataToPad("unlock_clipdata", payload);
break;
default:
throw new RuntimeException("[" + this + "] ERROR: Unknown clipboard PDU message type: " + msgType + ".");
}
buf.unref();
}
/**
* Example.
*/
public static void main(String args[]) {
// TODO
}
}

View File

@ -0,0 +1,180 @@
// 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.clip;
import streamer.BaseElement;
import streamer.ByteBuffer;
import streamer.Element;
import streamer.Link;
import streamer.Pipeline;
import streamer.PipelineImpl;
import streamer.debug.MockSink;
import streamer.debug.MockSource;
public class ServerClipboardCapabilitiesPDU extends BaseElement {
/**
* General capability set.
*/
public static final int CB_CAPSTYPE_GENERAL = 0x1;
/**
* The Long Format Name variant of the Format List PDU is supported for
* exchanging updated format names. If this flag is not set, the Short Format
* Name variant MUST be used. If this flag is set by both protocol endpoints,
* then the Long Format Name variant MUST be used.
*/
public static final int CB_USE_LONG_FORMAT_NAMES = 0x00000002;
/**
* File copy and paste using stream-based operations are supported using the
* File Contents Request PDU and File Contents Response PDU.
*/
public static final int CB_STREAM_FILECLIP_ENABLED = 0x00000004;
/**
* Indicates that any description of files to copy and paste MUST NOT include
* the source path of the files.
*/
public static final int CB_FILECLIP_NO_FILE_PATHS = 0x00000008;
/**
* Locking and unlocking of File Stream data on the clipboard is supported
* using the Lock Clipboard Data PDU and Unlock Clipboard Data PDU.
*/
public static final int CB_CAN_LOCK_CLIPDATA = 0x00000010;
protected ClipboardState state;
public ServerClipboardCapabilitiesPDU(String id, ClipboardState state) {
super(id);
this.state = state;
}
@Override
public void handleData(ByteBuffer buf, Link link) {
if (verbose)
System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
// 0x01, 0x00, // CLIPRDR_CAPS::cCapabilitiesSets = 1
int cCapabilitiesSets = buf.readUnsignedShortLE();
// 0x00, 0x00, // CLIPRDR_CAPS::pad1
buf.skipBytes(2);
// Parse all capability sets
for (int capabilitySet = 0; capabilitySet < cCapabilitiesSets; capabilitySet++) {
// 0x01, 0x00, // CLIPRDR_CAPS_SET::capabilitySetType =
// CB_CAPSTYPE_GENERAL (1)
int capabilitySetType = buf.readUnsignedShortLE();
// 0x0c, 0x00, // CLIPRDR_CAPS_SET::lengthCapability = 0x0c = 12 bytes
int lengthCapability = buf.readUnsignedShortLE();
// parse capability set
switch (capabilitySetType) {
case CB_CAPSTYPE_GENERAL:
parseGeneralCapabilitySet(buf.readBytes(lengthCapability - 4));
break;
default:
// Ignore
// throw new RuntimeException("Unknown capability set type: " +
// capabilitySetType + ". Expected value: CB_CAPSTYPE_GENERAL (1).");
}
}
buf.unref();
}
protected void parseGeneralCapabilitySet(ByteBuffer buf) {
// 0x02, 0x00, 0x00, 0x00, // CLIPRDR_GENERAL_CAPABILITY::version =
// CB_CAPS_VERSION_2 (2)
// long version = buf.readUnsignedIntLE();
buf.skipBytes(4);
// 0x0e, 0x00, 0x00, 0x00, // CLIPRDR_GENERAL_CAPABILITY::capabilityFlags
// = 0x0000000e = 0x02 |0x04 |0x08 = CB_USE_LONG_FORMAT_NAMES |
// CB_STREAM_FILECLIP_ENABLED | CB_FILECLIP_NO_FILE_PATHS
int flags = buf.readSignedIntLE();
if ((flags & CB_USE_LONG_FORMAT_NAMES) == CB_USE_LONG_FORMAT_NAMES) {
state.serverUseLongFormatNames = true;
if (verbose)
System.out.println("[" + this + "] INFO: Server can use long format names for clipboard data.");
}
if ((flags & CB_STREAM_FILECLIP_ENABLED) == CB_STREAM_FILECLIP_ENABLED) {
state.serverStreamFileClipEnabled = true;
if (verbose)
System.out.println("[" + this + "] INFO: Server supports stream based file clipboard operations.");
}
if ((flags & CB_FILECLIP_NO_FILE_PATHS) == CB_FILECLIP_NO_FILE_PATHS) {
state.serverFileClipNoFilePaths = true;
if (verbose)
System.out.println("[" + this
+ "] INFO: Server Indicates that any description of files to copy and paste MUST NOT include the source path of the files.");
}
if ((flags & CB_CAN_LOCK_CLIPDATA) == CB_CAN_LOCK_CLIPDATA) {
state.serverCanLockClipdata = true;
if (verbose)
System.out.println("[" + this + "] INFO: Server can lock and unlock file streams on the clipboard.");
}
}
/**
* 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[] {
0x07, 0x00, // CLIPRDR_HEADER::msgType = CB_CLIP_CAPS (7)
0x00, 0x00, // CLIPRDR_HEADER::msgFlags = 0
0x10, 0x00, 0x00, 0x00, // CLIPRDR_HEADER::dataLen = 0x10 = 16 bytes
0x01, 0x00, // CLIPRDR_CAPS::cCapabilitiesSets = 1
0x00, 0x00, // CLIPRDR_CAPS::pad1
0x01, 0x00, // CLIPRDR_CAPS_SET::capabilitySetType = CB_CAPSTYPE_GENERAL (1)
0x0c, 0x00, // CLIPRDR_CAPS_SET::lengthCapability = 0x0c = 12 bytes
0x02, 0x00, 0x00, 0x00, // CLIPRDR_GENERAL_CAPABILITY::version = CB_CAPS_VERSION_2 (2)
0x0e, 0x00, 0x00, 0x00, // CLIPRDR_GENERAL_CAPABILITY::capabilityFlags = 0x0000000e = 0x02 |0x04 |0x08 = CB_USE_LONG_FORMAT_NAMES | CB_STREAM_FILECLIP_ENABLED | CB_FILECLIP_NO_FILE_PATHS
};
/* @formatter:on */
MockSource source = new MockSource("source", ByteBuffer.convertByteArraysToByteBuffers(packet));
Element router = new ServerClipRdrChannelRouter("router");
ClipboardState state = new ClipboardState();
Element clip_cap = new ServerClipboardCapabilitiesPDU("clip_cap", state);
Element sink = new MockSink("sink", new ByteBuffer[] {});
Pipeline pipeline = new PipelineImpl("test");
pipeline.add(source, router, clip_cap, sink);
pipeline.link("source", "router >clipboard_capabilities", "clip_cap", "sink");
pipeline.runMainLoop("source", STDOUT, false, false);
// Check state
if (!state.serverUseLongFormatNames || !state.serverStreamFileClipEnabled || !state.serverFileClipNoFilePaths || state.serverCanLockClipdata)
throw new RuntimeException("Server clipboard capabilities packet parsed incorrectly.");
}
}

View File

@ -0,0 +1,97 @@
// 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.clip;
import streamer.BaseElement;
import streamer.ByteBuffer;
import streamer.Element;
import streamer.Link;
import streamer.Pipeline;
import streamer.PipelineImpl;
import streamer.debug.MockSink;
import streamer.debug.MockSource;
import common.adapter.AwtClipboardAdapter;
public class ServerFormatDataResponsePDU extends BaseElement {
public static final String SERVER_CLIPBOARD_ADAPTER_PAD = "clipboard";
protected ClipboardState state;
public ServerFormatDataResponsePDU(String id, ClipboardState state) {
super(id);
this.state = state;
}
@Override
public void handleData(ByteBuffer buf, Link link) {
if (verbose)
System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
parseData(buf);
buf.unref();
}
protected void parseData(ByteBuffer buf) {
String content = state.serverRequestedFormat.parseServerResponseAsString(buf);
// Send response to clipboard adapter
ByteBuffer outBuf = new ByteBuffer(0);
outBuf.putMetadata(AwtClipboardAdapter.CLIPBOARD_CONTENT, content);
pushDataToPad(SERVER_CLIPBOARD_ADAPTER_PAD, outBuf);
}
/**
* 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[] {
0x05, 0x00, // CLIPRDR_HEADER::msgType = CB_FORMAT_DATA_RESPONSE (5)
0x01, 0x00, // CLIPRDR_HEADER::msgFlags = 0x0001 = CB_RESPONSE_OK
0x18, 0x00, 0x00, 0x00, // CLIPRDR_HEADER::dataLen = 0x18 = 24 bytes
0x68, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x20, 0x00, 0x77, 0x00, 0x6f, 0x00,
0x72, 0x00, 0x6c, 0x00, 0x64, 0x00, 0x00, 0x00, // CLIPRDR_FORMAT_DATA_RESPONSE::requestedFormatData: "hello world"
};
/* @formatter:on */
MockSource source = new MockSource("source", ByteBuffer.convertByteArraysToByteBuffers(packet));
Element router = new ServerClipRdrChannelRouter("router");
ClipboardState state = new ClipboardState();
state.serverRequestedFormat = new ClipboardDataFormat(ClipboardDataFormat.CB_FORMAT_UNICODETEXT, "");
Element format_data_response = new ServerFormatDataResponsePDU("format_data_response", state);
ByteBuffer clipboardAdapterPacket = new ByteBuffer(0);
clipboardAdapterPacket.putMetadata(AwtClipboardAdapter.CLIPBOARD_CONTENT, "hello world");
Element sink = new MockSink("sink", new ByteBuffer[] {clipboardAdapterPacket});
Pipeline pipeline = new PipelineImpl("test");
pipeline.add(source, router, format_data_response, sink);
pipeline.link("source", "router >format_data_response", "format_data_response >clipboard", "sink");
pipeline.runMainLoop("source", STDOUT, false, false);
}
}

View File

@ -0,0 +1,237 @@
// 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.clip;
import java.util.HashMap;
import java.util.Map;
import rdpclient.rdp.RdpConstants;
import streamer.BaseElement;
import streamer.ByteBuffer;
import streamer.Element;
import streamer.Link;
import streamer.Pipeline;
import streamer.PipelineImpl;
import streamer.debug.MockSink;
import streamer.debug.MockSource;
public class ServerFormatListPDU extends BaseElement {
protected ClipboardState state;
public ServerFormatListPDU(String id, ClipboardState state) {
super(id);
this.state = state;
}
@Override
public void handleData(ByteBuffer buf, Link link) {
if (verbose)
System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
parseFormatNames(buf);
buf.unref();
// Automatically send request for text-based data to insert it into local
// clipboard
ClipboardDataFormat textFormat = ClipboardDataFormat.findBestTextFormat(state.serverClipboardDataFormats);
if (textFormat != null) {
// Send response: OK
sendFormatListParseResponse(true);
// Request data
sendFormatDataRequest(textFormat);
} else {
// Send response: FAIL, we are not interested in this data
sendFormatListParseResponse(false);
}
}
/**
* The Format Data Request PDU is sent by the recipient of the Format List
* PDU. It is used to request the data for one of the formats that was listed
* in the Format List PDU.
*/
protected void sendFormatDataRequest(ClipboardDataFormat textFormat) {
if (verbose)
System.out.println("[" + this + "] INFO: Sending request for data in following format: " + textFormat + ".");
// Store data format to parse server response later
state.serverRequestedFormat = textFormat;
ByteBuffer buf = new ByteBuffer(12, true);
// Type
buf.writeShortLE(ServerClipRdrChannelRouter.CB_FORMAT_DATA_REQUEST);
// Message flags
buf.writeShortLE(0);
// Length
buf.writeIntLE(4);
// ID of chosen format
buf.writeIntLE(textFormat.id);
buf.trimAtCursor();
pushDataToPad(STDOUT, buf);
}
/**
* The Format List Response PDU is sent as a reply to the Format List PDU. It
* is used to indicate whether processing of the Format List PDU was
* successful.
*
* @param b
*/
protected void sendFormatListParseResponse(boolean ok) {
ByteBuffer buf = new ByteBuffer(8, true);
// Type
buf.writeShortLE(ServerClipRdrChannelRouter.CB_FORMAT_LIST_RESPONSE);
// Message flags
buf.writeShortLE((ok) ? ServerClipRdrChannelRouter.CB_RESPONSE_OK : ServerClipRdrChannelRouter.CB_RESPONSE_FAIL);
// Length
buf.writeIntLE(0);
buf.trimAtCursor();
pushDataToPad(STDOUT, buf);
}
protected void parseFormatNames(ByteBuffer buf) {
// Set will not be modified after creation, so there is no need to make it
// synchronous.
Map<Object, ClipboardDataFormat> formats = new HashMap<Object, ClipboardDataFormat>();
while (buf.cursor < buf.length) {
int id = buf.readSignedIntLE();
String name;
if (state.serverUseLongFormatNames) {
// Long format names in Unicode
name = buf.readVariableWideString(RdpConstants.CHARSET_16);
} else {
Boolean asciiNames = (Boolean)buf.getMetadata(ServerClipRdrChannelRouter.ASCII_NAMES);
if (asciiNames != null && asciiNames) {
// Short format names in ASCII
name = buf.readString(32, RdpConstants.CHARSET_8);
} else {
// Short format names in Unicode
name = buf.readString(32, RdpConstants.CHARSET_16);
}
}
// Store format in map by both ID and name (if name is not empty)
formats.put(id, new ClipboardDataFormat(id, name));
if (name.length() > 0)
formats.put(name, new ClipboardDataFormat(id, name));
}
if (verbose)
System.out.println("Server supports following formats for clipboard data: " + formats.values().toString() + ".");
state.serverClipboardDataFormats = formats;
}
/**
* 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[] {
0x02, 0x00, // CLIPRDR_HEADER::msgType = CB_FORMAT_LIST (2)
0x00, 0x00, // CLIPRDR_HEADER::msgFlags = 0
(byte) 0xe0, 0x00, 0x00, 0x00, // CLIPRDR_HEADER::dataLen = 0xe0 = 224 bytes
(byte) 0x8a, (byte) 0xc0, 0x00, 0x00, // CLIPRDR_LONG_FORMAT_NAME::formatId = 0xc08a = 49290
0x52, 0x00, 0x69, 0x00, 0x63, 0x00, 0x68, 0x00, 0x20, 0x00, 0x54, 0x00, 0x65, 0x00, 0x78, 0x00, 0x74, 0x00, 0x20, 0x00, 0x46, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x74, 0x00, 0x00, 0x00, // CLIPRDR_LONG_FORMAT_NAME::formatName = "Rich Text Format"
0x45, (byte) 0xc1, 0x00, 0x00, // CLIPRDR_LONG_FORMAT_NAME::formatId = 0xc145 = 49477
0x52, 0x00, 0x69, 0x00, 0x63, 0x00, 0x68, 0x00, 0x20, 0x00, 0x54, 0x00, 0x65, 0x00, 0x78, 0x00,
0x74, 0x00, 0x20, 0x00, 0x46, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x74, 0x00,
0x20, 0x00, 0x57, 0x00, 0x69, 0x00, 0x74, 0x00, 0x68, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x74, 0x00,
0x20, 0x00, 0x4f, 0x00, 0x62, 0x00, 0x6a, 0x00, 0x65, 0x00, 0x63, 0x00, 0x74, 0x00, 0x73, 0x00,
0x00, 0x00, // CLIPRDR_LONG_FORMAT_NAME::formatName = "Rich Text Format Without Objects"
0x43, (byte) 0xc1, 0x00, 0x00, // CLIPRDR_LONG_FORMAT_NAME::formatId = 0xc143 = 49475
0x52, 0x00, 0x54, 0x00, 0x46, 0x00, 0x20, 0x00, 0x41, 0x00, 0x73, 0x00, 0x20, 0x00, 0x54, 0x00,
0x65, 0x00, 0x78, 0x00, 0x74, 0x00, 0x00, 0x00, // CLIPRDR_LONG_FORMAT_NAME::formatName = "RTF As Text"
0x01, 0x00, 0x00, 0x00, // CLIPRDR_LONG_FORMAT_NAME::formatId = 1
0x00, 0x00, // CLIPRDR_LONG_FORMAT_NAME::formatName = ""
0x0d, 0x00, 0x00, 0x00, // CLIPRDR_LONG_FORMAT_NAME::formatId = 0x0d = 13
0x00, 0x00, // CLIPRDR_LONG_FORMAT_NAME::formatName = ""
0x04, (byte) 0xc0, 0x00, 0x00, // CLIPRDR_LONG_FORMAT_NAME::formatId = 0xc004 = 49156
0x4e, 0x00, 0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x76, 0x00, 0x65, 0x00, 0x00, 0x00, // "Native"
0x0e, (byte) 0xc0, 0x00, 0x00, // CLIPRDR_LONG_FORMAT_NAME::formatId = 0xc00e = 49166
0x4f, 0x00, 0x62, 0x00, 0x6a, 0x00, 0x65, 0x00, 0x63, 0x00, 0x74, 0x00, 0x20, 0x00, 0x44, 0x00,
0x65, 0x00, 0x73, 0x00, 0x63, 0x00, 0x72, 0x00, 0x69, 0x00, 0x70, 0x00, 0x74, 0x00, 0x6f, 0x00,
0x72, 0x00, 0x00, 0x00, // CLIPRDR_LONG_FORMAT_NAME::formatName = "Object Descriptor"
0x03, 0x00, 0x00, 0x00, // CLIPRDR_LONG_FORMAT_NAME::formatId = 3
0x00, 0x00, // CLIPRDR_LONG_FORMAT_NAME::formatName = ""
0x10, 0x00, 0x00, 0x00, // CLIPRDR_LONG_FORMAT_NAME::formatId = 16
0x00, 0x00, // CLIPRDR_LONG_FORMAT_NAME::formatName = ""
0x07, 0x00, 0x00, 0x00, // CLIPRDR_LONG_FORMAT_NAME::formatId = 7
0x00, 0x00, // CLIPRDR_LONG_FORMAT_NAME::formatName = ""
};
/* @formatter:on */
MockSource source = new MockSource("source", ByteBuffer.convertByteArraysToByteBuffers(packet));
Element router = new ServerClipRdrChannelRouter("router");
ClipboardState state = new ClipboardState();
state.serverUseLongFormatNames = true;
Element format_list = new ServerFormatListPDU("format_list", state);
Element sink = new MockSink("sink", ByteBuffer.convertByteArraysToByteBuffers(new byte[] {
// Format List Response PDU
0x03, 0x00, // CLIPRDR_HEADER::msgType = CB_FORMAT_LIST_RESPONSE (3)
0x01, 0x00, // CLIPRDR_HEADER::msgFlags = 0x0001 = CB_RESPONSE_OK
0x00, 0x00, 0x00, 0x00, // CLIPRDR_HEADER::dataLen = 0 bytes
}, new byte[] {
// Format Data Request PDU
0x04, 0x00, // CLIPRDR_HEADER::msgType = CB_FORMAT_DATA_REQUEST (4)
0x00, 0x00, // CLIPRDR_HEADER::msgFlags = 0
0x04, 0x00, 0x00, 0x00, // CLIPRDR_HEADER::dataLen = 4 bytes
0x0d, 0x00, 0x00, 0x00, // CLIPRDR_FORMAT_DATA_REQUEST::requestedFormatId
// = 0x0d
}));
Pipeline pipeline = new PipelineImpl("test");
pipeline.add(source, router, format_list, sink);
pipeline.link("source", "router >format_list", "format_list", "sink");
pipeline.runMainLoop("source", STDOUT, false, false);
// Check state
if (!(state.serverClipboardDataFormats.containsKey(49475) && state.serverClipboardDataFormats.containsKey("Rich Text Format")))
throw new RuntimeException("Server format list packet parsed incorrectly.");
}
}

View File

@ -0,0 +1,85 @@
// 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.clip;
import streamer.BaseElement;
import streamer.ByteBuffer;
import streamer.Element;
import streamer.Link;
import streamer.Pipeline;
import streamer.PipelineImpl;
import streamer.debug.MockSink;
import streamer.debug.MockSource;
public class ServerMonitorReadyPDU extends BaseElement {
protected ClipboardState state;
public ServerMonitorReadyPDU(String id, ClipboardState state) {
super(id);
this.state = state;
}
// 0x01, 0x00, // CLIPRDR_HEADER::msgType = CB_MONITOR_READY (1)
// 0x00, 0x00, // CLIPRDR_HEADER::msgFlags = 0
// 0x00, 0x00, 0x00, 0x00, // CLIPRDR_HEADER::dataLen = 0 bytes
@Override
public void handleData(ByteBuffer buf, Link link) {
if (verbose)
System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
state.serverReady = true;
buf.unref();
}
/**
* 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[] {
0x01, 0x00, // CLIPRDR_HEADER::msgType = CB_MONITOR_READY (1)
0x00, 0x00, // CLIPRDR_HEADER::msgFlags = 0
0x00, 0x00, 0x00, 0x00, // CLIPRDR_HEADER::dataLen = 0 bytes
};
/* @formatter:on */
MockSource source = new MockSource("source", ByteBuffer.convertByteArraysToByteBuffers(packet));
Element router = new ServerClipRdrChannelRouter("router");
ClipboardState state = new ClipboardState();
Element monitor_ready = new ServerMonitorReadyPDU("monitor_ready", state);
Element sink = new MockSink("sink", new ByteBuffer[] {});
Pipeline pipeline = new PipelineImpl("test");
pipeline.add(source, router, monitor_ready, sink);
pipeline.link("source", "router >monitor_ready", "monitor_ready", "sink");
pipeline.runMainLoop("source", STDOUT, false, false);
// Check state
if (!state.serverReady)
throw new RuntimeException("Server monitor ready packet parsed incorrectly.");
}
}

View File

@ -0,0 +1,51 @@
// 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 ClientPacketSniffer extends PacketSniffer {
private static final Pair[] clientRegexps = new Pair[] {
// @formatter:off
new Pair("Client FastPath input", "04"),
new Pair("Client X224ConnectionRequest", "03 00 XX XX 27 E0"),
new Pair("Client ConnectionRequest", "03 00 XX XX XX E0"),
new Pair("Client MCConnectInitial", "03 00 XX XX 02 F0 80 7F 65"),
new Pair("Client ErectDomainRequest", "03 00 XX XX 02 F0 80 04"),
new Pair("Client AttachUserRequest", "03 00 XX XX 02 F0 80 28"),
new Pair("Client ChannelJoinRequest", "03 00 XX XX 02 F0 80 38"),
new Pair("Client Info", "03 00 XX XX 02 F0 80 64 00 03 03 EB 70 XX XX XX XX 00 00"),
new Pair("Client ConfirmActivePDU", "03 00 XX XX 02 F0 80 64 00 03 03 EB 70 XX XX XX XX 13 00"),
new Pair("Client SynchronizePDU", "03 00 XX XX 02 F0 80 64 00 03 03 EB 70 XX XX XX XX 17 00 EC 03 EA 03 XX 00 XX XX XX XX 1F"),
new Pair("Client ControlPDU", "03 00 XX XX 02 F0 80 64 00 03 03 EB 70 XX XX XX XX 17 00 EC 03 EA 03 XX 00 XX XX XX XX 14"),
new Pair("Client FontListPDU", "03 00 XX XX 02 F0 80 64 00 03 03 EB 70 XX XX XX XX 17 00 EC 03 EA 03 XX 00 XX XX XX XX 27"),
new Pair("Client BitmapCachePersistentList","03 00 XX XX 02 F0 80 64 00 03 03 EB 70 XX XX XX XX 17 00 EC 03 EA 03 XX XX XX XX XX XX 2b"),
new Pair("Client CredSSP", "30"),
new Pair("Client HyperV PreConnection Blob","5E"),
new Pair("Client a TPKT packet", "03"),
new Pair("Client a Fast Path packet", "00"),
// @formatter:on
};
public ClientPacketSniffer(String id) {
super(id, clientRegexps);
}
}

View File

@ -14,7 +14,7 @@
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package rdpclient;
package rdpclient.debug;
import java.util.regex.Pattern;

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}
}

View File

@ -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 */
}
}

View File

@ -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());
}
}

View File

@ -0,0 +1,492 @@
// 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;
/**
* During NTLM authentication, each of the following flags is a possible value
* of the NegotiateFlags field of the NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, and
* AUTHENTICATE_MESSAGE, unless otherwise noted. These flags define client or
* server NTLM capabilities supported by the sender.
*
* @see http://msdn.microsoft.com/en-us/library/cc236650.aspx
*/
public class NegoFlags {
/**
* 56-bit encryption. If the client sends NTLMSSP_NEGOTIATE_SEAL or
* NTLMSSP_NEGOTIATE_SIGN with NTLMSSP_NEGOTIATE_56 to the server in the
* NEGOTIATE_MESSAGE, the server MUST return NTLMSSP_NEGOTIATE_56 to the
* client in the CHALLENGE_MESSAGE. Otherwise it is ignored. If both
* NTLMSSP_NEGOTIATE_56 and NTLMSSP_NEGOTIATE_128 are requested and supported
* by the client and server, NTLMSSP_NEGOTIATE_56 and NTLMSSP_NEGOTIATE_128
* will both be returned to the client. Clients and servers that set
* NTLMSSP_NEGOTIATE_SEAL SHOULD set NTLMSSP_NEGOTIATE_56 if it is supported.
* An alternate name for this field is
*/
public static final int NTLMSSP_NEGOTIATE_56 = 0x80000000;
/**
* Explicit key exchange. This capability SHOULD be used because it improves
* security for message integrity or confidentiality. See sections 3.2.5.1.2,
* 3.2.5.2.1, and 3.2.5.2.2 for details.
*/
public static final int NTLMSSP_NEGOTIATE_KEY_EXCH = 0x40000000;
/**
* 128-bit session key negotiation. An alternate name for this field is
* NTLMSSP_NEGOTIATE_128. If the client sends NTLMSSP_NEGOTIATE_128 to the
* server in the NEGOTIATE_MESSAGE, the server MUST return
* NTLMSSP_NEGOTIATE_128 to the client in the CHALLENGE_MESSAGE only if the
* client sets NTLMSSP_NEGOTIATE_SEAL or NTLMSSP_NEGOTIATE_SIGN. Otherwise it
* is ignored. If both NTLMSSP_NEGOTIATE_56 and NTLMSSP_NEGOTIATE_128 are
* requested and supported by the client and server, NTLMSSP_NEGOTIATE_56 and
* NTLMSSP_NEGOTIATE_128 will both be returned to the client. Clients and
* servers that set NTLMSSP_NEGOTIATE_SEAL SHOULD set NTLMSSP_NEGOTIATE_128 if
* it is supported.
*/
public static final int NTLMSSP_NEGOTIATE_128 = 0x20000000;
/**
* Protocol version number. The data corresponding to this flag is provided in
* the Version field of the NEGOTIATE_MESSAGE, the CHALLENGE_MESSAGE, and the
* AUTHENTICATE_MESSAGE.
*/
public static final int NTLMSSP_NEGOTIATE_VERSION = 0x02000000;
/**
* TargetInfo fields in the CHALLENGE_MESSAGE (section 2.2.1.2) are populated.
*/
public static final int NTLMSSP_NEGOTIATE_TARGET_INFO = 0x00800000;
/** LMOWF (section 3.3). */
public static final int NTLMSSP_REQUEST_NON_NT_SESSION_KEY = 0x00400000;
/** An identify level token. */
public static final int NTLMSSP_NEGOTIATE_IDENTIFY = 0x00100000;
/**
* NTLM v2 session security. NTLM v2 session security is a misnomer because it
* is not NTLM v2. It is NTLM v1 using the extended session security that is
* also in NTLM v2. NTLMSSP_NEGOTIATE_LM_KEY and
* NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY are mutually exclusive. If both
* NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY and NTLMSSP_NEGOTIATE_LM_KEY are
* requested, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY alone MUST be
* returned to the client. NTLM v2 authentication session key generation MUST
* be supported by both the client and the DC in order to be used, and
* extended session security signing and sealing requires support from the
* client and the server in order to be used.
*/
public static final int NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY = 0x00080000;
/**
* TargetName MUST be a server name. The data corresponding to this flag is
* provided by the server in the TargetName field of the CHALLENGE_MESSAGE. If
* this bit is set, then NTLMSSP_TARGET_TYPE_DOMAIN MUST NOT be set. This flag
* MUST be ignored in the NEGOTIATE_MESSAGE and the AUTHENTICATE_MESSAGE.
*/
public static final int NTLMSSP_TARGET_TYPE_SERVER = 0x00020000;
/**
* TargetName MUST be a domain name. The data corresponding to this flag is
* provided by the server in the TargetName field of the CHALLENGE_MESSAGE. If
* set, then NTLMSSP_TARGET_TYPE_SERVER MUST NOT be set. This flag MUST be
* ignored in the NEGOTIATE_MESSAGE and the AUTHENTICATE_MESSAGE.
*/
public static final int NTLMSSP_TARGET_TYPE_DOMAIN = 0x00010000;
/**
* Signature block on all messages. NTLMSSP_NEGOTIATE_ALWAYS_SIGN MUST be set
* in the NEGOTIATE_MESSAGE to the server and the CHALLENGE_MESSAGE to the
* client. NTLMSSP_NEGOTIATE_ALWAYS_SIGN is overridden by
* NTLMSSP_NEGOTIATE_SIGN and NTLMSSP_NEGOTIATE_SEAL, if they are supported.
*/
public static final int NTLMSSP_NEGOTIATE_ALWAYS_SIGN = 0x00008000;
/**
* Workstation field is present. If this flag is not set, the Workstation
* field MUST be ignored. If this flag is set, the length field of the
* Workstation field specifies whether the workstation name is nonempty or
* not.
*/
public static final int NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED = 0x00002000;
/**
* Domain name is provided.
*
* Sent by the client in the Type 1 message to indicate that the name of the
* domain in which the client workstation has membership is included in the
* message. This is used by the server to determine whether the client is
* eligible for local authentication.
*/
public static final int NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED = 0x00001000;
/**
* Connection SHOULD be anonymous.
*
* Sent by the client in the Type 3 message to indicate that an anonymous
* context has been established. This also affects the response fields (as
* detailed in the "Anonymous Response" section).
*/
public static final int NTLMSSP_NEGOTIATE_ANONYMOUS = 0x00000800;
/**
* Usage of the NTLM v1 session security protocol. NTLMSSP_NEGOTIATE_NTLM MUST
* be set in the NEGOTIATE_MESSAGE to the server and the CHALLENGE_MESSAGE to
* the client.
*/
public static final int NTLMSSP_NEGOTIATE_NTLM = 0x00000200;
/**
* LAN Manager (LM) session key computation. NTLMSSP_NEGOTIATE_LM_KEY and
* NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY are mutually exclusive. If both
* NTLMSSP_NEGOTIATE_LM_KEY and NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY are
* requested, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY alone MUST be
* returned to the client. NTLM v2 authentication session key generation MUST
* be supported by both the client and the DC in order to be used, and
* extended session security signing and sealing requires support from the
* client and the server to be used.
*/
public static final int NTLMSSP_NEGOTIATE_LM_KEY = 0x00000080;
/**
* Connectionless authentication. If NTLMSSP_NEGOTIATE_DATAGRAM is set, then
* NTLMSSP_NEGOTIATE_KEY_EXCH MUST always be set in the AUTHENTICATE_MESSAGE
* to the server and the CHALLENGE_MESSAGE to the client.
*/
public static final int NTLMSSP_NEGOTIATE_DATAGRAM = 0x00000040;
/**
* Session key negotiation for message confidentiality. If the client sends
* NTLMSSP_NEGOTIATE_SEAL to the server in the NEGOTIATE_MESSAGE, the server
* MUST return NTLMSSP_NEGOTIATE_SEAL to the client in the CHALLENGE_MESSAGE.
* Clients and servers that set NTLMSSP_NEGOTIATE_SEAL SHOULD always set
* NTLMSSP_NEGOTIATE_56 and NTLMSSP_NEGOTIATE_128, if they are supported.
*/
public static final int NTLMSSP_NEGOTIATE_SEAL = 0x00000020;
/**
* Session key negotiation for message signatures. If the client sends
* NTLMSSP_NEGOTIATE_SIGN to the server in the NEGOTIATE_MESSAGE, the server
* MUST return NTLMSSP_NEGOTIATE_SIGN to the client in the CHALLENGE_MESSAGE.
*/
public static final int NTLMSSP_NEGOTIATE_SIGN = 0x00000010;
/**
* TargetName field of the CHALLENGE_MESSAGE (section 2.2.1.2) MUST be
* supplied.
*/
public static final int NTLMSSP_REQUEST_TARGET = 0x00000004;
/**
* OEM character set encoding.
*
* @see NTLMSSP_NEGOTIATE_UNICODE
*/
public static final int NTLMSSP_NEGOTIATE_OEM = 0x00000002;
/**
* Unicode character set encoding.
*
* The NTLMSSP_NEGOTIATE_UNICODE(A) and NTLM_NEGOTIATE_OEM(B) bits are
* evaluated together as follows:
* <ul>
* <li>A==1: The choice of character set encoding MUST be Unicode.
*
* <li>A==0 and B==1: The choice of character set encoding MUST be OEM.
*
* <li>A==0 and B==0: The protocol MUST return SEC_E_INVALID_TOKEN.
* <ul>
* */
public static final int NTLMSSP_NEGOTIATE_UNICODE = 0x00000001;
public int value;
public NegoFlags(int value) {
this.value = value;
}
public NegoFlags() {
value = 0;
}
@Override
public String toString() {
return String.format("NegoFlags [value=0x%04x (%s)]", value, flagsToSting());
}
public String flagsToSting() {
String str = "";
if (NEGOTIATE_56())
str += "NEGOTIATE_56 ";
if (NEGOTIATE_KEY_EXCH())
str += "NEGOTIATE_KEY_EXCH ";
if (NEGOTIATE_128())
str += "NEGOTIATE_128 ";
if (NEGOTIATE_VERSION())
str += "NEGOTIATE_VERSION ";
if (NEGOTIATE_TARGET_INFO())
str += "NEGOTIATE_TARGET_INFO ";
if (REQUEST_NON_NT_SESSION_KEY())
str += "REQUEST_NON_NT_SESSION_KEY ";
if (NEGOTIATE_IDENTIFY())
str += "NEGOTIATE_IDENTIFY ";
if (NEGOTIATE_EXTENDED_SESSION_SECURITY())
str += "NEGOTIATE_EXTENDED_SESSION_SECURITY ";
if (TARGET_TYPE_SERVER())
str += "TARGET_TYPE_SERVER ";
if (TARGET_TYPE_DOMAIN())
str += "TARGET_TYPE_DOMAIN ";
if (NEGOTIATE_ALWAYS_SIGN())
str += "NEGOTIATE_ALWAYS_SIGN ";
if (NEGOTIATE_OEM_WORKSTATION_SUPPLIED())
str += "NEGOTIATE_OEM_WORKSTATION_SUPPLIED ";
if (NEGOTIATE_OEM_DOMAIN_SUPPLIED())
str += "NEGOTIATE_OEM_DOMAIN_SUPPLIED ";
if (NEGOTIATE_ANONYMOUS())
str += "NEGOTIATE_ANONYMOUS ";
if (NEGOTIATE_NTLM())
str += "NEGOTIATE_NTLM ";
if (NEGOTIATE_LM_KEY())
str += "NEGOTIATE_LM_KEY ";
if (NEGOTIATE_DATAGRAM())
str += "NEGOTIATE_DATAGRAM ";
if (NEGOTIATE_SEAL())
str += "NEGOTIATE_SEAL ";
if (NEGOTIATE_SIGN())
str += "NEGOTIATE_SIGN ";
if (REQUEST_TARGET())
str += "REQUEST_TARGET ";
if (NEGOTIATE_OEM())
str += "NEGOTIATE_OEM ";
if (NEGOTIATE_UNICODE())
str += "NEGOTIATE_UNICODE ";
return str;
}
public boolean NEGOTIATE_56() {
return ((value & NTLMSSP_NEGOTIATE_56) != 0);
}
public boolean NEGOTIATE_KEY_EXCH() {
return ((value & NTLMSSP_NEGOTIATE_KEY_EXCH) != 0);
}
public boolean NEGOTIATE_128() {
return ((value & NTLMSSP_NEGOTIATE_128) != 0);
}
public boolean NEGOTIATE_VERSION() {
return ((value & NTLMSSP_NEGOTIATE_VERSION) != 0);
}
public boolean NEGOTIATE_TARGET_INFO() {
return ((value & NTLMSSP_NEGOTIATE_TARGET_INFO) != 0);
}
public boolean REQUEST_NON_NT_SESSION_KEY() {
return ((value & NTLMSSP_REQUEST_NON_NT_SESSION_KEY) != 0);
}
public boolean NEGOTIATE_IDENTIFY() {
return ((value & NTLMSSP_NEGOTIATE_IDENTIFY) != 0);
}
public boolean NEGOTIATE_EXTENDED_SESSION_SECURITY() {
return ((value & NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY) != 0);
}
public boolean TARGET_TYPE_SERVER() {
return ((value & NTLMSSP_TARGET_TYPE_SERVER) != 0);
}
public boolean TARGET_TYPE_DOMAIN() {
return ((value & NTLMSSP_TARGET_TYPE_DOMAIN) != 0);
}
public boolean NEGOTIATE_ALWAYS_SIGN() {
return ((value & NTLMSSP_NEGOTIATE_ALWAYS_SIGN) != 0);
}
public boolean NEGOTIATE_OEM_WORKSTATION_SUPPLIED() {
return ((value & NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED) != 0);
}
public boolean NEGOTIATE_OEM_DOMAIN_SUPPLIED() {
return ((value & NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED) != 0);
}
public boolean NEGOTIATE_ANONYMOUS() {
return ((value & NTLMSSP_NEGOTIATE_ANONYMOUS) != 0);
}
public boolean NEGOTIATE_NTLM() {
return ((value & NTLMSSP_NEGOTIATE_NTLM) != 0);
}
public boolean NEGOTIATE_LM_KEY() {
return ((value & NTLMSSP_NEGOTIATE_LM_KEY) != 0);
}
public boolean NEGOTIATE_DATAGRAM() {
return ((value & NTLMSSP_NEGOTIATE_DATAGRAM) != 0);
}
public boolean NEGOTIATE_SEAL() {
return ((value & NTLMSSP_NEGOTIATE_SEAL) != 0);
}
public boolean NEGOTIATE_SIGN() {
return ((value & NTLMSSP_NEGOTIATE_SIGN) != 0);
}
public boolean REQUEST_TARGET() {
return ((value & NTLMSSP_REQUEST_TARGET) != 0);
}
public boolean NEGOTIATE_OEM() {
return ((value & NTLMSSP_NEGOTIATE_OEM) != 0);
}
public boolean NEGOTIATE_UNICODE() {
return ((value & NTLMSSP_NEGOTIATE_UNICODE) != 0);
}
public NegoFlags set_NEGOTIATE_56() {
value |= NTLMSSP_NEGOTIATE_56;
return this;
}
public NegoFlags set_NEGOTIATE_KEY_EXCH() {
value |= NTLMSSP_NEGOTIATE_KEY_EXCH;
return this;
}
public NegoFlags set_NEGOTIATE_128() {
value |= NTLMSSP_NEGOTIATE_128;
return this;
}
public NegoFlags set_NEGOTIATE_VERSION() {
value |= NTLMSSP_NEGOTIATE_VERSION;
return this;
}
public NegoFlags set_NEGOTIATE_TARGET_INFO() {
value |= NTLMSSP_NEGOTIATE_TARGET_INFO;
return this;
}
public NegoFlags set_REQUEST_NON_NT_SESSION_KEY() {
value |= NTLMSSP_REQUEST_NON_NT_SESSION_KEY;
return this;
}
public NegoFlags set_NEGOTIATE_IDENTIFY() {
value |= NTLMSSP_NEGOTIATE_IDENTIFY;
return this;
}
public NegoFlags set_NEGOTIATE_EXTENDED_SESSION_SECURITY() {
value |= NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY;
return this;
}
public NegoFlags set_TARGET_TYPE_SERVER() {
value |= NTLMSSP_TARGET_TYPE_SERVER;
return this;
}
public NegoFlags set_TARGET_TYPE_DOMAIN() {
value |= NTLMSSP_TARGET_TYPE_DOMAIN;
return this;
}
public NegoFlags set_NEGOTIATE_ALWAYS_SIGN() {
value |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
return this;
}
public NegoFlags set_NEGOTIATE_OEM_WORKSTATION_SUPPLIED() {
value |= NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED;
return this;
}
public NegoFlags set_NEGOTIATE_OEM_DOMAIN_SUPPLIED() {
value |= NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED;
return this;
}
public NegoFlags set_NEGOTIATE_ANONYMOUS() {
value |= NTLMSSP_NEGOTIATE_ANONYMOUS;
return this;
}
public NegoFlags set_NEGOTIATE_NTLM() {
value |= NTLMSSP_NEGOTIATE_NTLM;
return this;
}
public NegoFlags set_NEGOTIATE_LM_KEY() {
value |= NTLMSSP_NEGOTIATE_LM_KEY;
return this;
}
public NegoFlags set_NEGOTIATE_DATAGRAM() {
value |= NTLMSSP_NEGOTIATE_DATAGRAM;
return this;
}
public NegoFlags set_NEGOTIATE_SEAL() {
value |= NTLMSSP_NEGOTIATE_SEAL;
return this;
}
public NegoFlags set_NEGOTIATE_SIGN() {
value |= NTLMSSP_NEGOTIATE_SIGN;
return this;
}
public NegoFlags set_REQUEST_TARGET() {
value |= NTLMSSP_REQUEST_TARGET;
return this;
}
public NegoFlags set_NEGOTIATE_OEM() {
value |= NTLMSSP_NEGOTIATE_OEM;
return this;
}
public NegoFlags set_NEGOTIATE_UNICODE() {
value |= NTLMSSP_NEGOTIATE_UNICODE;
return this;
}
/**
* Example.
*/
public static void main(String args[]) {
NegoFlags flags = new NegoFlags(0xe20882b7);
System.out.println("Negotiation flags: " + flags);
}
}

View File

@ -14,14 +14,11 @@
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package rdpclient;
package rdpclient.ntlmssp;
import streamer.BaseElement;
public class NtlmCompute {
public class HandshakeEnd extends BaseElement {
public void compute_ntlm_v2_hash() {
public HandshakeEnd(String id) {
super(id);
}
}

View File

@ -0,0 +1,157 @@
// 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;
public interface NtlmConstants {
/**
* Attribute type: Indicates that this is the last AV_PAIR in the list. AvLen
* MUST be 0. This type of information MUST be present in the AV pair list.
*/
public final static int MSV_AV_EOL = 0x0000;
/**
* Attribute type: The server's NetBIOS computer name. The name MUST be in
* Unicode, and is not null-terminated. This type of information MUST be
* present in the AV_pair list.
*/
public final static int MSV_AV_NETBIOS_COMPUTER_NAME = 0x0001;
/**
* Attribute type: The server's NetBIOS domain name. The name MUST be in
* Unicode, and is not null-terminated. This type of information MUST be
* present in the AV_pair list.
*/
public final static int MSV_AV_NETBIOS_DOMAIN_NAME = 0x0002;
/**
* Attribute type: The fully qualified domain name (FQDN (1)) of the computer.
* The name MUST be in Unicode, and is not null-terminated.
*/
public final static int MSV_AV_DNS_COMPUTER_NAME = 0x0003;
/**
* Attribute type: The FQDN of the domain. The name MUST be in Unicode, and is
* not null-terminated.
*/
public final static int MSV_AV_DNS_DOMAIN_NAME = 0x0004;
/**
* Attribute type: The FQDN of the forest. The name MUST be in Unicode, and is
* not null-terminated.
*/
public final static int MSV_AV_DNS_TREE_NAME = 0x0005;
/**
* Attribute type: A 32-bit value indicating server or client configuration.
*
* <li>0x00000001: indicates to the client that the account authentication is
* constrained.
*
* <li>0x00000002: indicates that the client is providing message integrity in
* the MIC field (section 2.2.1.3) in the AUTHENTICATE_MESSAGE.
*
* <li>0x00000004: indicates that the client is providing a target SPN
* generated from an untrusted source.
**/
public final static int MSV_AV_FLAGS = 0x0006;
public static final int MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK = 0x00000002;
/**
* Attribute type: A FILETIME structure ([MS-DTYP] section 2.3.3) in
* little-endian byte order that contains the server local time.
*/
public final static int MSV_AV_TIMESTAMP = 0x0007;
/**
* Attribute type: A Single_Host_Data (section 2.2.2.2) structure. The Value
* field contains a platform-specific blob, as well as a MachineID created at
* computer startup to identify the calling machine.<15>
*/
public final static int MSV_AV_SINGLE_HOST = 0x0008;
/**
* Attribute type: The SPN of the target server. The name MUST be in Unicode
* and is not null-terminated.<16>
*/
public final static int MSV_AV_TARGET_NAME = 0x0009;
/**
* Attribute type: A channel bindings hash. The Value field contains an MD5
* hash ([RFC4121] section 4.1.1.2) of a gss_channel_bindings_struct
* ([RFC2744] section 3.11). An all-zero value of the hash is used to indicate
* absence of channel bindings.
*/
public final static int MSV_AV_CHANNEL_BINDINGS = 0x000A;
/**
* Signature of NTLMSSP blob.
*/
public static final String NTLMSSP = "NTLMSSP";
public static final String GSS_RDP_SERVICE_NAME = "TERMSRV";
/**
* NTLM message type: NEGOTIATE.
*/
public static final int NEGOTIATE = 0x00000001;
/**
* NTLM message type: CHALLENGE.
*/
public static final int CHALLENGE = 0x00000002;
/**
* NTLM message type: NTLMSSP_AUTH.
*/
public static final int NTLMSSP_AUTH = 0x00000003;
public static final String OID_SPNEGO = "1.3.6.1.5.5.2";
public static final String OID_KERBEROS5 = "1.2.840.113554.1.2.2";
public static final String OID_MSKERBEROS5 = "1.2.840.48018.1.2.2";
public static final String OID_KRB5USERTOUSER = "1.2.840.113554.1.2.2.3";
public static final String OID_NTLMSSP = "1.3.6.1.4.1.311.2.2.10";
/**
* Magic constant used in calculation of Lan Manager response.
*/
public static final String LM_MAGIC = "KGS!@#$%";
/**
* Magic constant used in generation of client signing key.
*/
public static final String CLIENT_SIGN_MAGIC = "session key to client-to-server signing key magic constant";
/**
* Magic constant used in generation of client sealing key.
*/
public static final String CLIENT_SEAL_MAGIC = "session key to client-to-server sealing key magic constant";
public static final String SERVER_SIGN_MAGIC = "session key to server-to-client signing key magic constant";
public static final String SERVER_SEAL_MAGIC = "session key to server-to-client sealing key magic constant";
/**
* In Windows XP, Windows Server 2003, Windows Vista, Windows Server 2008,
* Windows 7, Windows Server 2008 R2, Windows 8, Windows Server 2012, Windows
* 8.1, and Windows Server 2012 R2, the maximum lifetime of challenge is 36 hours.
*/
public static final int CHALLENGE_MAX_LIFETIME = 36 * 60 * 60;
}

View File

@ -0,0 +1,887 @@
// 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.util.Arrays;
import javax.crypto.Cipher;
import rdpclient.rdp.RdpConstants;
import streamer.ByteBuffer;
public class NtlmState implements NtlmConstants {
/**
* The set of configuration flags (section 2.2.2.5) that specifies the
* negotiated capabilities of the client and server for the current NTLM
* session.
*/
public NegoFlags negotiatedFlags;
/**
* Target Information extracted from Type2 server response.
*/
public byte[] serverTargetInfo;
/**
* Challenge extracted from Type2 server response.
*/
public byte[] serverChallenge;
public byte[] clientChallenge;
public byte[] keyExchangeKey;
/**
* A 128-bit (16-byte) session key used to derive ClientSigningKey,
* ClientSealingKey, ServerSealingKey, and ServerSigningKey.
*/
public byte[] exportedSessionKey;
/**
* The signing key used by the client to sign messages and used by the server
* to verify signed client messages. It is generated after the client is
* authenticated by the server and is not passed over the wire.
*/
public byte[] clientSigningKey;
/**
* The sealing key used by the client to seal messages and used by the server
* to unseal client messages. It is generated after the client is
* authenticated by the server and is not passed over the wire.
*/
public byte[] clientSealingKey;
public byte[] encryptedRandomSessionKey;
public byte[] sessionBaseKey;
public byte[] responseKeyNT;
public byte[] ntProofStr1;
public String domain;
public String user;
public String workstation;
public String password;
public String serverNetbiosDomainName;
public String serverNetbiosComputerName;
public String serverDnsDomainName;
public String serverDnsComputerName;
public String serverDnsTreeName;
public String serverTargetName;
public byte[] serverTimestamp;
public byte[] clientChallengeTimestamp;
public byte[] lmChallengeResponse;
public byte[] ntChallengeResponse;
public byte[] ntProofStr2;
public byte[] randomSessionKey;
public byte[] serverSigningKey;
public byte[] serverSealingKey;
public byte[] sendSigningKey;
public byte[] recvSigningKey;
public byte[] sendSealingKey;
public byte[] recvSealingKey;
public Cipher sendRc4Seal;
public Cipher recvRc4Seal;
public byte[] messageIntegrityCheck;
public byte[] negotiateMessage;
public byte[] challengeMessage;
public byte[] authenticateMessage;
/**
* A 4-byte sequence number.
*
* In the case of connection-oriented authentication, the SeqNum parameter
* MUST start at 0 and is incremented by one for each message sent. The
* receiver expects the first received message to have SeqNum equal to 0, and
* to be one greater for each subsequent message received. If a received
* message does not contain the expected SeqNum, an error MUST be returned to
* the receiving application, and SeqNum is not incremented.
*/
public int sendSeqNum;
public int recvSeqNum;
public byte[] authenticateTargetInfo;
public String servicePrincipalName;
private byte[] channelBindingsHash = new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
public byte[] subjectPublicKey;
public byte[] ntlm_generate_timestamp() {
clientChallengeTimestamp = serverTimestamp;
return clientChallengeTimestamp;
}
/**
* MD4(UNICODE(Password))
*/
public byte[] NTOWFv1W(String password) {
return CryptoAlgos.MD4(password.getBytes(RdpConstants.CHARSET_16));
}
public void testNTOWFv1W() {
byte[] expected = new byte[] {(byte)0x25, (byte)0xf3, (byte)0x39, (byte)0xc9, (byte)0x86, (byte)0xb5, (byte)0xc2, (byte)0x6f, (byte)0xdc,
(byte)0xab, (byte)0x91, (byte)0x34, (byte)0x93, (byte)0xa2, (byte)0x18, (byte)0x2a};
byte[] actual = NTOWFv1W("R2Preview!");
if (!Arrays.equals(expected, actual))
throw new RuntimeException("Incorrect result.\nExpected:\n" + new ByteBuffer(expected).toPlainHexString() + "\n actual:\n"
+ new ByteBuffer(actual).toPlainHexString() + ".");
}
/**
* HMAC_MD5(NTOWFv1W(Password), UNICODE(ConcatenationOf(UpperCase(User),
* Domain)))
*/
public byte[] NTOWFv2W(String password, String user, String domain) {
return CryptoAlgos.HMAC_MD5(NTOWFv1W(password), (user.toUpperCase() + domain).getBytes(RdpConstants.CHARSET_16));
}
public void testNTOWFv2W() {
byte[] expected = new byte[] {(byte)0x5f, (byte)0xcc, (byte)0x4c, (byte)0x48, (byte)0x74, (byte)0x6b, (byte)0x94, (byte)0xce, (byte)0xb7,
(byte)0xae, (byte)0xf1, (byte)0x0d, (byte)0xc9, (byte)0x11, (byte)0x22, (byte)0x8f,};
byte[] actual = NTOWFv2W("R2Preview!", "Administrator", "workgroup");
if (!Arrays.equals(expected, actual))
throw new RuntimeException("Incorrect result.\nExpected:\n" + new ByteBuffer(expected).toPlainHexString() + "\n actual:\n"
+ new ByteBuffer(actual).toPlainHexString() + ".");
}
public byte[] ntlm_compute_ntlm_v2_hash() {
return NTOWFv2W(password, user, domain);
}
public byte[] ntlm_generate_client_challenge() {
if (clientChallenge == null) {
clientChallenge = CryptoAlgos.NONCE(8);
}
return clientChallenge;
}
public byte[] ntlm_compute_lm_v2_response() {
if (lmChallengeResponse == null) {
byte[] ntlm_v2_hash = ntlm_compute_ntlm_v2_hash();
ntlm_generate_client_challenge();
byte[] challenges = CryptoAlgos.concatenationOf(serverChallenge, clientChallenge);
lmChallengeResponse = CryptoAlgos.concatenationOf(CryptoAlgos.HMAC_MD5(ntlm_v2_hash, challenges), clientChallenge);
}
return lmChallengeResponse;
}
public void testComputeLmV2Response() {
serverChallenge = new byte[] {(byte)0x34, (byte)0xe4, (byte)0x4c, (byte)0xd5, (byte)0x75, (byte)0xe3, (byte)0x43, (byte)0x0f};
clientChallenge = new byte[] {1, 2, 3, 4, 5, 6, 7, 8};
password = "R2Preview!";
user = "Administrator";
domain = "workgroup";
byte[] expected = new byte[] {(byte)0xa8, (byte)0xae, (byte)0xd7, (byte)0x46, (byte)0x06, (byte)0x32, (byte)0x02, (byte)0x35, (byte)0x1d,
(byte)0x95, (byte)0x99, (byte)0x36, (byte)0x20, (byte)0x36, (byte)0xac, (byte)0xc3, (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04,
(byte)0x05, (byte)0x06, (byte)0x07, (byte)0x08,};
byte[] actual = ntlm_compute_lm_v2_response();
if (!Arrays.equals(expected, actual))
throw new RuntimeException("Incorrect result.\nExpected:\n" + new ByteBuffer(expected).toPlainHexString() + "\n actual:\n"
+ new ByteBuffer(actual).toPlainHexString() + ".");
}
public byte[] computeNtProofStr(byte[] ntlmV2Hash, byte[] data) {
return CryptoAlgos.HMAC_MD5(ntlmV2Hash, data);
}
public void testComputeNtProofStr() {
byte[] ntlm_v2_hash = new byte[] {(byte)0x5f, (byte)0xcc, (byte)0x4c, (byte)0x48, (byte)0x74, (byte)0x6b, (byte)0x94, (byte)0xce, (byte)0xb7,
(byte)0xae, (byte)0xf1, (byte)0x0d, (byte)0xc9, (byte)0x11, (byte)0x22, (byte)0x8f,};
byte[] data = new byte[] {(byte)0x4a, (byte)0x25, (byte)0x50, (byte)0xa5, (byte)0x11, (byte)0x9b, (byte)0xd6, (byte)0x16, (byte)0x01,
(byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xa0, (byte)0xe8, (byte)0x85, (byte)0x2c,
(byte)0xe4, (byte)0xc9, (byte)0xce, (byte)0x01, (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04, (byte)0x05, (byte)0x06, (byte)0x07,
(byte)0x08, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x02, (byte)0x00, (byte)0x1e, (byte)0x00, (byte)0x57, (byte)0x00,
(byte)0x49, (byte)0x00, (byte)0x4e, (byte)0x00, (byte)0x2d, (byte)0x00, (byte)0x4c, (byte)0x00, (byte)0x4f, (byte)0x00, (byte)0x34,
(byte)0x00, (byte)0x31, (byte)0x00, (byte)0x39, (byte)0x00, (byte)0x42, (byte)0x00, (byte)0x32, (byte)0x00, (byte)0x4c, (byte)0x00,
(byte)0x53, (byte)0x00, (byte)0x52, (byte)0x00, (byte)0x30, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x1e, (byte)0x00, (byte)0x57,
(byte)0x00, (byte)0x49, (byte)0x00, (byte)0x4e, (byte)0x00, (byte)0x2d, (byte)0x00, (byte)0x4c, (byte)0x00, (byte)0x4f, (byte)0x00,
(byte)0x34, (byte)0x00, (byte)0x31, (byte)0x00, (byte)0x39, (byte)0x00, (byte)0x42, (byte)0x00, (byte)0x32, (byte)0x00, (byte)0x4c,
(byte)0x00, (byte)0x53, (byte)0x00, (byte)0x52, (byte)0x00, (byte)0x30, (byte)0x00, (byte)0x04, (byte)0x00, (byte)0x1e, (byte)0x00,
(byte)0x57, (byte)0x00, (byte)0x49, (byte)0x00, (byte)0x4e, (byte)0x00, (byte)0x2d, (byte)0x00, (byte)0x4c, (byte)0x00, (byte)0x4f,
(byte)0x00, (byte)0x34, (byte)0x00, (byte)0x31, (byte)0x00, (byte)0x39, (byte)0x00, (byte)0x42, (byte)0x00, (byte)0x32, (byte)0x00,
(byte)0x4c, (byte)0x00, (byte)0x53, (byte)0x00, (byte)0x52, (byte)0x00, (byte)0x30, (byte)0x00, (byte)0x03, (byte)0x00, (byte)0x1e,
(byte)0x00, (byte)0x57, (byte)0x00, (byte)0x49, (byte)0x00, (byte)0x4e, (byte)0x00, (byte)0x2d, (byte)0x00, (byte)0x4c, (byte)0x00,
(byte)0x4f, (byte)0x00, (byte)0x34, (byte)0x00, (byte)0x31, (byte)0x00, (byte)0x39, (byte)0x00, (byte)0x42, (byte)0x00, (byte)0x32,
(byte)0x00, (byte)0x4c, (byte)0x00, (byte)0x53, (byte)0x00, (byte)0x52, (byte)0x00, (byte)0x30, (byte)0x00, (byte)0x07, (byte)0x00,
(byte)0x08, (byte)0x00, (byte)0xa0, (byte)0xe8, (byte)0x85, (byte)0x2c, (byte)0xe4, (byte)0xc9, (byte)0xce, (byte)0x01, (byte)0x06,
(byte)0x00, (byte)0x04, (byte)0x00, (byte)0x02, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x0a, (byte)0x00, (byte)0x10, (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)0x00, (byte)0x09, (byte)0x00, (byte)0x26, (byte)0x00, (byte)0x54, (byte)0x00,
(byte)0x45, (byte)0x00, (byte)0x52, (byte)0x00, (byte)0x4d, (byte)0x00, (byte)0x53, (byte)0x00, (byte)0x52, (byte)0x00, (byte)0x56,
(byte)0x00, (byte)0x2f, (byte)0x00, (byte)0x31, (byte)0x00, (byte)0x39, (byte)0x00, (byte)0x32, (byte)0x00, (byte)0x2e, (byte)0x00,
(byte)0x31, (byte)0x00, (byte)0x36, (byte)0x00, (byte)0x38, (byte)0x00, (byte)0x2e, (byte)0x00, (byte)0x31, (byte)0x00, (byte)0x2e,
(byte)0x00, (byte)0x33, (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)0x00,};
byte[] expected = new byte[] {(byte)0x19, (byte)0x4b, (byte)0xeb, (byte)0xad, (byte)0xda, (byte)0x24, (byte)0xd5, (byte)0x96, (byte)0x85,
(byte)0x2e, (byte)0x24, (byte)0x94, (byte)0xd6, (byte)0x4a, (byte)0xb8, (byte)0x5e,};
byte[] actual = computeNtProofStr(ntlm_v2_hash, data);
if (!Arrays.equals(expected, actual))
throw new RuntimeException("Incorrect result.\nExpected:\n" + new ByteBuffer(expected).toPlainHexString() + "\n actual:\n"
+ new ByteBuffer(actual).toPlainHexString() + ".");
}
public byte[] computeSessionBaseKey(byte[] ntlmV2Hash, byte[] ntProofStr) {
return CryptoAlgos.HMAC_MD5(ntlmV2Hash, ntProofStr);
}
public void testComputeSessionBaseKey() {
byte[] ntlm_v2_hash = new byte[] {(byte)0x5f, (byte)0xcc, (byte)0x4c, (byte)0x48, (byte)0x74, (byte)0x6b, (byte)0x94, (byte)0xce, (byte)0xb7,
(byte)0xae, (byte)0xf1, (byte)0x0d, (byte)0xc9, (byte)0x11, (byte)0x22, (byte)0x8f,};
byte[] nt_proof_str = new byte[] {(byte)0x19, (byte)0x4b, (byte)0xeb, (byte)0xad, (byte)0xda, (byte)0x24, (byte)0xd5, (byte)0x96, (byte)0x85,
(byte)0x2e, (byte)0x24, (byte)0x94, (byte)0xd6, (byte)0x4a, (byte)0xb8, (byte)0x5e,};
byte[] expected = new byte[] {(byte)0x8e, (byte)0x0f, (byte)0xdd, (byte)0x12, (byte)0x4c, (byte)0x3b, (byte)0x11, (byte)0x7f, (byte)0x22,
(byte)0xb9, (byte)0x4b, (byte)0x59, (byte)0x52, (byte)0xbc, (byte)0xa7, (byte)0x18,};
byte[] actual = computeSessionBaseKey(ntlm_v2_hash, nt_proof_str);
if (!Arrays.equals(expected, actual))
throw new RuntimeException("Incorrect result.\nExpected:\n" + new ByteBuffer(expected).toPlainHexString() + "\n actual:\n"
+ new ByteBuffer(actual).toPlainHexString() + ".");
}
public String generateServicePrincipalName(String serverHostName) {
servicePrincipalName = GSS_RDP_SERVICE_NAME + "/" + serverHostName;
return servicePrincipalName;
}
public void writeAVPair(ByteBuffer buf, int avPairType, byte[] value) {
if (value != null) {
buf.writeShortLE(avPairType);
buf.writeShortLE(value.length);
buf.writeBytes(value);
}
}
public void writeAVPair(ByteBuffer buf, int avPairType, String value) {
if (value != null) {
writeAVPair(buf, avPairType, value.getBytes(RdpConstants.CHARSET_16));
}
}
public byte[] ntlm_construct_authenticate_target_info() {
ByteBuffer buf = new ByteBuffer(4096);
writeAVPair(buf, MSV_AV_NETBIOS_DOMAIN_NAME, serverNetbiosDomainName);
writeAVPair(buf, MSV_AV_NETBIOS_COMPUTER_NAME, serverNetbiosComputerName);
writeAVPair(buf, MSV_AV_DNS_DOMAIN_NAME, serverDnsDomainName);
writeAVPair(buf, MSV_AV_DNS_COMPUTER_NAME, serverDnsComputerName);
writeAVPair(buf, MSV_AV_DNS_TREE_NAME, serverDnsTreeName);
writeAVPair(buf, MSV_AV_TIMESTAMP, serverTimestamp);
byte[] flags = new byte[] {(byte)MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK, 0, 0, 0};
writeAVPair(buf, MSV_AV_FLAGS, flags);
writeAVPair(buf, MSV_AV_CHANNEL_BINDINGS, channelBindingsHash);
writeAVPair(buf, MSV_AV_TARGET_NAME, servicePrincipalName);
writeAVPair(buf, MSV_AV_EOL, "");
// DEBUG: put EOL 4 times, for compatibility with FreeRDP output
//*DEBUG*/writeAVPair(buf, MSV_AV_EOL, "");
//*DEBUG*/writeAVPair(buf, MSV_AV_EOL, "");
//*DEBUG*/writeAVPair(buf, MSV_AV_EOL, "");
buf.trimAtCursor();
authenticateTargetInfo = buf.toByteArray();
buf.unref();
return authenticateTargetInfo;
}
public void testConstructAuthenticateTargetInfo() {
serverNetbiosDomainName = "WIN-LO419B2LSR0";
serverNetbiosComputerName = "WIN-LO419B2LSR0";
serverDnsDomainName = "WIN-LO419B2LSR0";
serverDnsComputerName = "WIN-LO419B2LSR0";
serverTimestamp = new byte[] {(byte)0xa0, (byte)0xe8, (byte)0x85, (byte)0x2c, (byte)0xe4, (byte)0xc9, (byte)0xce, (byte)0x01,};
servicePrincipalName = "TERMSRV/192.168.1.3";
byte[] expected = new byte[] {(byte)0x02, (byte)0x00, (byte)0x1e, (byte)0x00, (byte)0x57, (byte)0x00, (byte)0x49, (byte)0x00, (byte)0x4e,
(byte)0x00, (byte)0x2d, (byte)0x00, (byte)0x4c, (byte)0x00, (byte)0x4f, (byte)0x00, (byte)0x34, (byte)0x00, (byte)0x31, (byte)0x00,
(byte)0x39, (byte)0x00, (byte)0x42, (byte)0x00, (byte)0x32, (byte)0x00, (byte)0x4c, (byte)0x00, (byte)0x53, (byte)0x00, (byte)0x52,
(byte)0x00, (byte)0x30, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x1e, (byte)0x00, (byte)0x57, (byte)0x00, (byte)0x49, (byte)0x00,
(byte)0x4e, (byte)0x00, (byte)0x2d, (byte)0x00, (byte)0x4c, (byte)0x00, (byte)0x4f, (byte)0x00, (byte)0x34, (byte)0x00, (byte)0x31,
(byte)0x00, (byte)0x39, (byte)0x00, (byte)0x42, (byte)0x00, (byte)0x32, (byte)0x00, (byte)0x4c, (byte)0x00, (byte)0x53, (byte)0x00,
(byte)0x52, (byte)0x00, (byte)0x30, (byte)0x00, (byte)0x04, (byte)0x00, (byte)0x1e, (byte)0x00, (byte)0x57, (byte)0x00, (byte)0x49,
(byte)0x00, (byte)0x4e, (byte)0x00, (byte)0x2d, (byte)0x00, (byte)0x4c, (byte)0x00, (byte)0x4f, (byte)0x00, (byte)0x34, (byte)0x00,
(byte)0x31, (byte)0x00, (byte)0x39, (byte)0x00, (byte)0x42, (byte)0x00, (byte)0x32, (byte)0x00, (byte)0x4c, (byte)0x00, (byte)0x53,
(byte)0x00, (byte)0x52, (byte)0x00, (byte)0x30, (byte)0x00, (byte)0x03, (byte)0x00, (byte)0x1e, (byte)0x00, (byte)0x57, (byte)0x00,
(byte)0x49, (byte)0x00, (byte)0x4e, (byte)0x00, (byte)0x2d, (byte)0x00, (byte)0x4c, (byte)0x00, (byte)0x4f, (byte)0x00, (byte)0x34,
(byte)0x00, (byte)0x31, (byte)0x00, (byte)0x39, (byte)0x00, (byte)0x42, (byte)0x00, (byte)0x32, (byte)0x00, (byte)0x4c, (byte)0x00,
(byte)0x53, (byte)0x00, (byte)0x52, (byte)0x00, (byte)0x30, (byte)0x00, (byte)0x07, (byte)0x00, (byte)0x08, (byte)0x00, (byte)0xa0,
(byte)0xe8, (byte)0x85, (byte)0x2c, (byte)0xe4, (byte)0xc9, (byte)0xce, (byte)0x01, (byte)0x06, (byte)0x00, (byte)0x04, (byte)0x00,
(byte)0x02, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x0a, (byte)0x00, (byte)0x10, (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)0x00, (byte)0x09, (byte)0x00, (byte)0x26, (byte)0x00, (byte)0x54, (byte)0x00, (byte)0x45, (byte)0x00, (byte)0x52,
(byte)0x00, (byte)0x4d, (byte)0x00, (byte)0x53, (byte)0x00, (byte)0x52, (byte)0x00, (byte)0x56, (byte)0x00, (byte)0x2f, (byte)0x00,
(byte)0x31, (byte)0x00, (byte)0x39, (byte)0x00, (byte)0x32, (byte)0x00, (byte)0x2e, (byte)0x00, (byte)0x31, (byte)0x00, (byte)0x36,
(byte)0x00, (byte)0x38, (byte)0x00, (byte)0x2e, (byte)0x00, (byte)0x31, (byte)0x00, (byte)0x2e, (byte)0x00, (byte)0x33, (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)0x00,};
byte[] actual = ntlm_construct_authenticate_target_info();
if (!Arrays.equals(expected, actual))
throw new RuntimeException("Incorrect result.\nExpected:\n" + new ByteBuffer(expected).toPlainHexString() + "\n actual:\n"
+ new ByteBuffer(actual).toPlainHexString() + ".");
}
public byte[] ntlm_compute_ntlm_v2_response() {
ByteBuffer buf = new ByteBuffer(4096);
byte[] ntlm_v2_hash = ntlm_compute_ntlm_v2_hash();
buf.writeByte(0x1); // RespType
buf.writeByte(0x1); // HighRespType
buf.writeShort(0); // reserved
buf.writeInt(0); // reserved
buf.writeBytes(clientChallengeTimestamp); // Timestamp, 8 bytes
buf.writeBytes(clientChallenge); // Client nonce, 8 bytes
buf.writeInt(0); // reserved
buf.writeBytes(authenticateTargetInfo); // Target Info block
buf.trimAtCursor();
byte[] bufBytes = buf.toByteArray();
buf.unref();
ntProofStr2 = computeNtProofStr(ntlm_v2_hash, CryptoAlgos.concatenationOf(serverChallenge, bufBytes));
ntChallengeResponse = CryptoAlgos.concatenationOf(ntProofStr2, bufBytes);
sessionBaseKey = computeSessionBaseKey(ntlm_v2_hash, ntProofStr2);
return ntChallengeResponse;
}
public void testComputeNtlmV2Response() {
serverChallenge = new byte[] {(byte)0x4a, (byte)0x25, (byte)0x50, (byte)0xa5, (byte)0x11, (byte)0x9b, (byte)0xd6, (byte)0x16,};
clientChallenge = new byte[] {1, 2, 3, 4, 5, 6, 7, 8};
password = "R2Preview!";
user = "Administrator";
domain = "workgroup";
clientChallengeTimestamp = new byte[] {(byte)0xa0, (byte)0xe8, (byte)0x85, (byte)0x2c, (byte)0xe4, (byte)0xc9, (byte)0xce, (byte)0x01,};
authenticateTargetInfo = new byte[] {(byte)0x02, (byte)0x00, (byte)0x1e, (byte)0x00, (byte)0x57, (byte)0x00, (byte)0x49, (byte)0x00, (byte)0x4e,
(byte)0x00, (byte)0x2d, (byte)0x00, (byte)0x4c, (byte)0x00, (byte)0x4f, (byte)0x00, (byte)0x34, (byte)0x00, (byte)0x31, (byte)0x00,
(byte)0x39, (byte)0x00, (byte)0x42, (byte)0x00, (byte)0x32, (byte)0x00, (byte)0x4c, (byte)0x00, (byte)0x53, (byte)0x00, (byte)0x52,
(byte)0x00, (byte)0x30, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x1e, (byte)0x00, (byte)0x57, (byte)0x00, (byte)0x49, (byte)0x00,
(byte)0x4e, (byte)0x00, (byte)0x2d, (byte)0x00, (byte)0x4c, (byte)0x00, (byte)0x4f, (byte)0x00, (byte)0x34, (byte)0x00, (byte)0x31,
(byte)0x00, (byte)0x39, (byte)0x00, (byte)0x42, (byte)0x00, (byte)0x32, (byte)0x00, (byte)0x4c, (byte)0x00, (byte)0x53, (byte)0x00,
(byte)0x52, (byte)0x00, (byte)0x30, (byte)0x00, (byte)0x04, (byte)0x00, (byte)0x1e, (byte)0x00, (byte)0x57, (byte)0x00, (byte)0x49,
(byte)0x00, (byte)0x4e, (byte)0x00, (byte)0x2d, (byte)0x00, (byte)0x4c, (byte)0x00, (byte)0x4f, (byte)0x00, (byte)0x34, (byte)0x00,
(byte)0x31, (byte)0x00, (byte)0x39, (byte)0x00, (byte)0x42, (byte)0x00, (byte)0x32, (byte)0x00, (byte)0x4c, (byte)0x00, (byte)0x53,
(byte)0x00, (byte)0x52, (byte)0x00, (byte)0x30, (byte)0x00, (byte)0x03, (byte)0x00, (byte)0x1e, (byte)0x00, (byte)0x57, (byte)0x00,
(byte)0x49, (byte)0x00, (byte)0x4e, (byte)0x00, (byte)0x2d, (byte)0x00, (byte)0x4c, (byte)0x00, (byte)0x4f, (byte)0x00, (byte)0x34,
(byte)0x00, (byte)0x31, (byte)0x00, (byte)0x39, (byte)0x00, (byte)0x42, (byte)0x00, (byte)0x32, (byte)0x00, (byte)0x4c, (byte)0x00,
(byte)0x53, (byte)0x00, (byte)0x52, (byte)0x00, (byte)0x30, (byte)0x00, (byte)0x07, (byte)0x00, (byte)0x08, (byte)0x00, (byte)0xa0,
(byte)0xe8, (byte)0x85, (byte)0x2c, (byte)0xe4, (byte)0xc9, (byte)0xce, (byte)0x01, (byte)0x06, (byte)0x00, (byte)0x04, (byte)0x00,
(byte)0x02, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x0a, (byte)0x00, (byte)0x10, (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)0x00, (byte)0x09, (byte)0x00, (byte)0x26, (byte)0x00, (byte)0x54, (byte)0x00, (byte)0x45, (byte)0x00, (byte)0x52,
(byte)0x00, (byte)0x4d, (byte)0x00, (byte)0x53, (byte)0x00, (byte)0x52, (byte)0x00, (byte)0x56, (byte)0x00, (byte)0x2f, (byte)0x00,
(byte)0x31, (byte)0x00, (byte)0x39, (byte)0x00, (byte)0x32, (byte)0x00, (byte)0x2e, (byte)0x00, (byte)0x31, (byte)0x00, (byte)0x36,
(byte)0x00, (byte)0x38, (byte)0x00, (byte)0x2e, (byte)0x00, (byte)0x31, (byte)0x00, (byte)0x2e, (byte)0x00, (byte)0x33, (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)0x00,};
byte[] expected = new byte[] {(byte)0x19, (byte)0x4b, (byte)0xeb, (byte)0xad, (byte)0xda, (byte)0x24, (byte)0xd5, (byte)0x96, (byte)0x85,
(byte)0x2e, (byte)0x24, (byte)0x94, (byte)0xd6, (byte)0x4a, (byte)0xb8, (byte)0x5e, (byte)0x01, (byte)0x01, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xa0, (byte)0xe8, (byte)0x85, (byte)0x2c, (byte)0xe4, (byte)0xc9, (byte)0xce,
(byte)0x01, (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04, (byte)0x05, (byte)0x06, (byte)0x07, (byte)0x08, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x02, (byte)0x00, (byte)0x1e, (byte)0x00, (byte)0x57, (byte)0x00, (byte)0x49, (byte)0x00, (byte)0x4e,
(byte)0x00, (byte)0x2d, (byte)0x00, (byte)0x4c, (byte)0x00, (byte)0x4f, (byte)0x00, (byte)0x34, (byte)0x00, (byte)0x31, (byte)0x00,
(byte)0x39, (byte)0x00, (byte)0x42, (byte)0x00, (byte)0x32, (byte)0x00, (byte)0x4c, (byte)0x00, (byte)0x53, (byte)0x00, (byte)0x52,
(byte)0x00, (byte)0x30, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x1e, (byte)0x00, (byte)0x57, (byte)0x00, (byte)0x49, (byte)0x00,
(byte)0x4e, (byte)0x00, (byte)0x2d, (byte)0x00, (byte)0x4c, (byte)0x00, (byte)0x4f, (byte)0x00, (byte)0x34, (byte)0x00, (byte)0x31,
(byte)0x00, (byte)0x39, (byte)0x00, (byte)0x42, (byte)0x00, (byte)0x32, (byte)0x00, (byte)0x4c, (byte)0x00, (byte)0x53, (byte)0x00,
(byte)0x52, (byte)0x00, (byte)0x30, (byte)0x00, (byte)0x04, (byte)0x00, (byte)0x1e, (byte)0x00, (byte)0x57, (byte)0x00, (byte)0x49,
(byte)0x00, (byte)0x4e, (byte)0x00, (byte)0x2d, (byte)0x00, (byte)0x4c, (byte)0x00, (byte)0x4f, (byte)0x00, (byte)0x34, (byte)0x00,
(byte)0x31, (byte)0x00, (byte)0x39, (byte)0x00, (byte)0x42, (byte)0x00, (byte)0x32, (byte)0x00, (byte)0x4c, (byte)0x00, (byte)0x53,
(byte)0x00, (byte)0x52, (byte)0x00, (byte)0x30, (byte)0x00, (byte)0x03, (byte)0x00, (byte)0x1e, (byte)0x00, (byte)0x57, (byte)0x00,
(byte)0x49, (byte)0x00, (byte)0x4e, (byte)0x00, (byte)0x2d, (byte)0x00, (byte)0x4c, (byte)0x00, (byte)0x4f, (byte)0x00, (byte)0x34,
(byte)0x00, (byte)0x31, (byte)0x00, (byte)0x39, (byte)0x00, (byte)0x42, (byte)0x00, (byte)0x32, (byte)0x00, (byte)0x4c, (byte)0x00,
(byte)0x53, (byte)0x00, (byte)0x52, (byte)0x00, (byte)0x30, (byte)0x00, (byte)0x07, (byte)0x00, (byte)0x08, (byte)0x00, (byte)0xa0,
(byte)0xe8, (byte)0x85, (byte)0x2c, (byte)0xe4, (byte)0xc9, (byte)0xce, (byte)0x01, (byte)0x06, (byte)0x00, (byte)0x04, (byte)0x00,
(byte)0x02, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x0a, (byte)0x00, (byte)0x10, (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)0x00, (byte)0x09, (byte)0x00, (byte)0x26, (byte)0x00, (byte)0x54, (byte)0x00, (byte)0x45, (byte)0x00, (byte)0x52,
(byte)0x00, (byte)0x4d, (byte)0x00, (byte)0x53, (byte)0x00, (byte)0x52, (byte)0x00, (byte)0x56, (byte)0x00, (byte)0x2f, (byte)0x00,
(byte)0x31, (byte)0x00, (byte)0x39, (byte)0x00, (byte)0x32, (byte)0x00, (byte)0x2e, (byte)0x00, (byte)0x31, (byte)0x00, (byte)0x36,
(byte)0x00, (byte)0x38, (byte)0x00, (byte)0x2e, (byte)0x00, (byte)0x31, (byte)0x00, (byte)0x2e, (byte)0x00, (byte)0x33, (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)0x00,};
byte[] actual = ntlm_compute_ntlm_v2_response();
if (!Arrays.equals(expected, actual))
throw new RuntimeException("Incorrect result.\nExpected:\n" + new ByteBuffer(expected).toPlainHexString() + "\n actual:\n"
+ new ByteBuffer(actual).toPlainHexString() + ".");
}
public byte[] ntlm_generate_key_exchange_key() {
keyExchangeKey = sessionBaseKey;
return keyExchangeKey;
}
public byte[] ntlm_generate_random_session_key() {
randomSessionKey = CryptoAlgos.NONCE(16);
return randomSessionKey;
}
public byte[] ntlm_generate_exported_session_key() {
exportedSessionKey = randomSessionKey;
return exportedSessionKey;
}
public byte[] ntlm_encrypt_random_session_key() {
encryptedRandomSessionKey = CryptoAlgos.RC4K(keyExchangeKey, randomSessionKey);
return encryptedRandomSessionKey;
}
public void testComputeEncryptedRandomSessionKey() {
keyExchangeKey = new byte[] {(byte)0x8e, (byte)0x0f, (byte)0xdd, (byte)0x12, (byte)0x4c, (byte)0x3b, (byte)0x11, (byte)0x7f, (byte)0x22,
(byte)0xb9, (byte)0x4b, (byte)0x59, (byte)0x52, (byte)0xbc, (byte)0xa7, (byte)0x18,};
randomSessionKey = new byte[] {(byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04, (byte)0x05, (byte)0x06, (byte)0x07, (byte)0x08, (byte)0x09,
(byte)0x0a, (byte)0x0b, (byte)0x0c, (byte)0x0d, (byte)0x0e, (byte)0x0f, (byte)0x10,};
byte[] expected = new byte[] {(byte)0xe4, (byte)0xe9, (byte)0xc2, (byte)0xad, (byte)0x41, (byte)0x02, (byte)0x2f, (byte)0x3c, (byte)0xf9,
(byte)0x4c, (byte)0x72, (byte)0x84, (byte)0xc5, (byte)0x2a, (byte)0x7c, (byte)0x6f,};
byte[] actual = ntlm_encrypt_random_session_key();
if (!Arrays.equals(expected, actual))
throw new RuntimeException("Incorrect result.\nExpected:\n" + new ByteBuffer(expected).toPlainHexString() + "\n actual:\n"
+ new ByteBuffer(actual).toPlainHexString() + ".");
}
public byte[] ntlm_generate_signing_key(String signMagic) {
return CryptoAlgos.MD5(CryptoAlgos.concatenationOf(exportedSessionKey, signMagic.getBytes(RdpConstants.CHARSET_8), new byte[] {0}));
}
public void testGenerateSigningKey() {
exportedSessionKey = new byte[] {(byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04, (byte)0x05, (byte)0x06, (byte)0x07, (byte)0x08, (byte)0x09,
(byte)0x0a, (byte)0x0b, (byte)0x0c, (byte)0x0d, (byte)0x0e, (byte)0x0f, (byte)0x10,};
byte[] expected = new byte[] {(byte)0xf6, (byte)0xae, (byte)0x96, (byte)0xcb, (byte)0x05, (byte)0xe2, (byte)0xab, (byte)0x54, (byte)0xf6,
(byte)0xdd, (byte)0x59, (byte)0xf3, (byte)0xc9, (byte)0xd9, (byte)0xa0, (byte)0x43,};
byte[] actual = ntlm_generate_signing_key(CLIENT_SIGN_MAGIC);
if (!Arrays.equals(expected, actual))
throw new RuntimeException("Incorrect result.\nExpected:\n" + new ByteBuffer(expected).toPlainHexString() + "\n actual:\n"
+ new ByteBuffer(actual).toPlainHexString() + ".");
}
public byte[] ntlm_generate_client_signing_key() {
clientSigningKey = ntlm_generate_signing_key(CLIENT_SIGN_MAGIC);
return clientSigningKey;
}
public void testGenerateClientSigningKey() {
exportedSessionKey = new byte[] {(byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04, (byte)0x05, (byte)0x06, (byte)0x07, (byte)0x08, (byte)0x09,
(byte)0x0a, (byte)0x0b, (byte)0x0c, (byte)0x0d, (byte)0x0e, (byte)0x0f, (byte)0x10,};
byte[] expected = new byte[] {(byte)0xf6, (byte)0xae, (byte)0x96, (byte)0xcb, (byte)0x05, (byte)0xe2, (byte)0xab, (byte)0x54, (byte)0xf6,
(byte)0xdd, (byte)0x59, (byte)0xf3, (byte)0xc9, (byte)0xd9, (byte)0xa0, (byte)0x43,};
byte[] actual = ntlm_generate_client_signing_key();
if (!Arrays.equals(expected, actual))
throw new RuntimeException("Incorrect result.\nExpected:\n" + new ByteBuffer(expected).toPlainHexString() + "\n actual:\n"
+ new ByteBuffer(actual).toPlainHexString() + ".");
}
public byte[] ntlm_generate_server_signing_key() {
serverSigningKey = ntlm_generate_signing_key(SERVER_SIGN_MAGIC);
return serverSigningKey;
}
public void testGenerateServerSigningKey() {
exportedSessionKey = new byte[] {(byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04, (byte)0x05, (byte)0x06, (byte)0x07, (byte)0x08, (byte)0x09,
(byte)0x0a, (byte)0x0b, (byte)0x0c, (byte)0x0d, (byte)0x0e, (byte)0x0f, (byte)0x10,};
byte[] expected = new byte[] {(byte)0xb6, (byte)0x58, (byte)0xc5, (byte)0x98, (byte)0x7a, (byte)0x25, (byte)0xf8, (byte)0x6e, (byte)0xd8,
(byte)0xe5, (byte)0x6c, (byte)0xe9, (byte)0x3e, (byte)0x3c, (byte)0xc0, (byte)0x88,};
byte[] actual = ntlm_generate_server_signing_key();
if (!Arrays.equals(expected, actual))
throw new RuntimeException("Incorrect result.\nExpected:\n" + new ByteBuffer(expected).toPlainHexString() + "\n actual:\n"
+ new ByteBuffer(actual).toPlainHexString() + ".");
}
public byte[] ntlm_generate_client_sealing_key() {
clientSealingKey = ntlm_generate_signing_key(CLIENT_SEAL_MAGIC);
return clientSealingKey;
}
public void testGenerateClientSealingKey() {
exportedSessionKey = new byte[] {(byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04, (byte)0x05, (byte)0x06, (byte)0x07, (byte)0x08, (byte)0x09,
(byte)0x0a, (byte)0x0b, (byte)0x0c, (byte)0x0d, (byte)0x0e, (byte)0x0f, (byte)0x10,};
byte[] expected = new byte[] {(byte)0x58, (byte)0x19, (byte)0x44, (byte)0xc2, (byte)0x7a, (byte)0xc6, (byte)0x34, (byte)0x45, (byte)0xe4,
(byte)0xb8, (byte)0x2b, (byte)0x55, (byte)0xb9, (byte)0x0b, (byte)0x1f, (byte)0xb5,};
byte[] actual = ntlm_generate_client_sealing_key();
if (!Arrays.equals(expected, actual))
throw new RuntimeException("Incorrect result.\nExpected:\n" + new ByteBuffer(expected).toPlainHexString() + "\n actual:\n"
+ new ByteBuffer(actual).toPlainHexString() + ".");
}
public byte[] ntlm_generate_server_sealing_key() {
serverSealingKey = ntlm_generate_signing_key(SERVER_SEAL_MAGIC);
return serverSealingKey;
}
public void testGenerateServerSealingKey() {
exportedSessionKey = new byte[] {(byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04, (byte)0x05, (byte)0x06, (byte)0x07, (byte)0x08, (byte)0x09,
(byte)0x0a, (byte)0x0b, (byte)0x0c, (byte)0x0d, (byte)0x0e, (byte)0x0f, (byte)0x10,};
byte[] expected = new byte[] {(byte)0x92, (byte)0x3a, (byte)0x73, (byte)0x5c, (byte)0x92, (byte)0xa7, (byte)0x04, (byte)0x34, (byte)0xbe,
(byte)0x9a, (byte)0xa2, (byte)0x9f, (byte)0xed, (byte)0xc1, (byte)0xe6, (byte)0x13,};
byte[] actual = ntlm_generate_server_sealing_key();
if (!Arrays.equals(expected, actual))
throw new RuntimeException("Incorrect result.\nExpected:\n" + new ByteBuffer(expected).toPlainHexString() + "\n actual:\n"
+ new ByteBuffer(actual).toPlainHexString() + ".");
}
public void ntlm_init_rc4_seal_states() {
ntlm_generate_client_signing_key();
ntlm_generate_server_signing_key();
ntlm_generate_client_sealing_key();
ntlm_generate_server_sealing_key();
sendSigningKey = clientSigningKey;
recvSigningKey = serverSigningKey;
sendSealingKey = clientSealingKey;
recvSealingKey = serverSealingKey;
sendRc4Seal = CryptoAlgos.initRC4(sendSealingKey);
recvRc4Seal = CryptoAlgos.initRC4(recvSealingKey);
}
public byte[] ntlm_compute_message_integrity_check() {
//* DEBUG */System.out.println("ntlm_compute_message_integrity_check: exportedSessionKey:\n" + new ByteBuffer(exportedSessionKey).dump() + "\n");
//* DEBUG */System.out.println("ntlm_compute_message_integrity_check: negotiateMessage:\n" + new ByteBuffer(negotiateMessage).dump() + "\n");
//* DEBUG */System.out.println("ntlm_compute_message_integrity_check: challengeMessage:\n" + new ByteBuffer(challengeMessage).dump() + "\n");
//* DEBUG */System.out.println("ntlm_compute_message_integrity_check: authenticateMessage:\n" + new ByteBuffer(authenticateMessage).dump() + "\n");
messageIntegrityCheck = CryptoAlgos.HMAC_MD5(exportedSessionKey, CryptoAlgos.concatenationOf(negotiateMessage, challengeMessage, authenticateMessage));
//* DEBUG */System.out.println("ntlm_compute_message_integrity_check: messageIntegrityCheck:\n" + new ByteBuffer(messageIntegrityCheck).dump() + "\n");
return messageIntegrityCheck;
}
public void testComputeMessageIntegrityCheck() {
exportedSessionKey = new byte[] {(byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04, (byte)0x05, (byte)0x06, (byte)0x07, (byte)0x08, (byte)0x09,
(byte)0x0a, (byte)0x0b, (byte)0x0c, (byte)0x0d, (byte)0x0e, (byte)0x0f, (byte)0x10,};
negotiateMessage = new byte[] {(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,};
challengeMessage = new byte[] {(byte)0x4e, (byte)0x54, (byte)0x4c, (byte)0x4d, (byte)0x53, (byte)0x53, (byte)0x50, (byte)0x00, (byte)0x02,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x1e, (byte)0x00, (byte)0x1e, (byte)0x00, (byte)0x38, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x35, (byte)0x82, (byte)0x8a, (byte)0xe2, (byte)0x4a, (byte)0x25, (byte)0x50, (byte)0xa5, (byte)0x11, (byte)0x9b, (byte)0xd6,
(byte)0x16, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x98, (byte)0x00,
(byte)0x98, (byte)0x00, (byte)0x56, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x06, (byte)0x03, (byte)0xd7, (byte)0x24, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x0f, (byte)0x57, (byte)0x00, (byte)0x49, (byte)0x00, (byte)0x4e, (byte)0x00, (byte)0x2d, (byte)0x00,
(byte)0x4c, (byte)0x00, (byte)0x4f, (byte)0x00, (byte)0x34, (byte)0x00, (byte)0x31, (byte)0x00, (byte)0x39, (byte)0x00, (byte)0x42,
(byte)0x00, (byte)0x32, (byte)0x00, (byte)0x4c, (byte)0x00, (byte)0x53, (byte)0x00, (byte)0x52, (byte)0x00, (byte)0x30, (byte)0x00,
(byte)0x02, (byte)0x00, (byte)0x1e, (byte)0x00, (byte)0x57, (byte)0x00, (byte)0x49, (byte)0x00, (byte)0x4e, (byte)0x00, (byte)0x2d,
(byte)0x00, (byte)0x4c, (byte)0x00, (byte)0x4f, (byte)0x00, (byte)0x34, (byte)0x00, (byte)0x31, (byte)0x00, (byte)0x39, (byte)0x00,
(byte)0x42, (byte)0x00, (byte)0x32, (byte)0x00, (byte)0x4c, (byte)0x00, (byte)0x53, (byte)0x00, (byte)0x52, (byte)0x00, (byte)0x30,
(byte)0x00, (byte)0x01, (byte)0x00, (byte)0x1e, (byte)0x00, (byte)0x57, (byte)0x00, (byte)0x49, (byte)0x00, (byte)0x4e, (byte)0x00,
(byte)0x2d, (byte)0x00, (byte)0x4c, (byte)0x00, (byte)0x4f, (byte)0x00, (byte)0x34, (byte)0x00, (byte)0x31, (byte)0x00, (byte)0x39,
(byte)0x00, (byte)0x42, (byte)0x00, (byte)0x32, (byte)0x00, (byte)0x4c, (byte)0x00, (byte)0x53, (byte)0x00, (byte)0x52, (byte)0x00,
(byte)0x30, (byte)0x00, (byte)0x04, (byte)0x00, (byte)0x1e, (byte)0x00, (byte)0x57, (byte)0x00, (byte)0x49, (byte)0x00, (byte)0x4e,
(byte)0x00, (byte)0x2d, (byte)0x00, (byte)0x4c, (byte)0x00, (byte)0x4f, (byte)0x00, (byte)0x34, (byte)0x00, (byte)0x31, (byte)0x00,
(byte)0x39, (byte)0x00, (byte)0x42, (byte)0x00, (byte)0x32, (byte)0x00, (byte)0x4c, (byte)0x00, (byte)0x53, (byte)0x00, (byte)0x52,
(byte)0x00, (byte)0x30, (byte)0x00, (byte)0x03, (byte)0x00, (byte)0x1e, (byte)0x00, (byte)0x57, (byte)0x00, (byte)0x49, (byte)0x00,
(byte)0x4e, (byte)0x00, (byte)0x2d, (byte)0x00, (byte)0x4c, (byte)0x00, (byte)0x4f, (byte)0x00, (byte)0x34, (byte)0x00, (byte)0x31,
(byte)0x00, (byte)0x39, (byte)0x00, (byte)0x42, (byte)0x00, (byte)0x32, (byte)0x00, (byte)0x4c, (byte)0x00, (byte)0x53, (byte)0x00,
(byte)0x52, (byte)0x00, (byte)0x30, (byte)0x00, (byte)0x07, (byte)0x00, (byte)0x08, (byte)0x00, (byte)0xa0, (byte)0xe8, (byte)0x85,
(byte)0x2c, (byte)0xe4, (byte)0xc9, (byte)0xce, (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,};
authenticateMessage = new byte[] {(byte)0x4e, (byte)0x54, (byte)0x4c, (byte)0x4d, (byte)0x53, (byte)0x53, (byte)0x50, (byte)0x00, (byte)0x03,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x18, (byte)0x00, (byte)0x18, (byte)0x00, (byte)0x90, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x16, (byte)0x01, (byte)0x16, (byte)0x01, (byte)0xa8, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x12, (byte)0x00, (byte)0x12,
(byte)0x00, (byte)0x58, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x1a, (byte)0x00, (byte)0x1a, (byte)0x00, (byte)0x6a, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x0c, (byte)0x00, (byte)0x0c, (byte)0x00, (byte)0x84, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x10,
(byte)0x00, (byte)0x10, (byte)0x00, (byte)0xbe, (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x35, (byte)0xb2, (byte)0x88, (byte)0xe2,
(byte)0x06, (byte)0x01, (byte)0xb1, (byte)0x1d, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x0f, (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)0x77, (byte)0x00, (byte)0x6f, (byte)0x00, (byte)0x72, (byte)0x00, (byte)0x6b, (byte)0x00, (byte)0x67,
(byte)0x00, (byte)0x72, (byte)0x00, (byte)0x6f, (byte)0x00, (byte)0x75, (byte)0x00, (byte)0x70, (byte)0x00, (byte)0x41, (byte)0x00,
(byte)0x64, (byte)0x00, (byte)0x6d, (byte)0x00, (byte)0x69, (byte)0x00, (byte)0x6e, (byte)0x00, (byte)0x69, (byte)0x00, (byte)0x73,
(byte)0x00, (byte)0x74, (byte)0x00, (byte)0x72, (byte)0x00, (byte)0x61, (byte)0x00, (byte)0x74, (byte)0x00, (byte)0x6f, (byte)0x00,
(byte)0x72, (byte)0x00, (byte)0x61, (byte)0x00, (byte)0x70, (byte)0x00, (byte)0x6f, (byte)0x00, (byte)0x6c, (byte)0x00, (byte)0x6c,
(byte)0x00, (byte)0x6f, (byte)0x00, (byte)0x7c, (byte)0xc0, (byte)0xfd, (byte)0x08, (byte)0xc5, (byte)0x14, (byte)0x05, (byte)0x34,
(byte)0xf3, (byte)0x12, (byte)0x9e, (byte)0x3e, (byte)0xa3, (byte)0x09, (byte)0xbc, (byte)0xc6, (byte)0x01, (byte)0x02, (byte)0x03,
(byte)0x04, (byte)0x05, (byte)0x06, (byte)0x07, (byte)0x08, (byte)0x19, (byte)0x4b, (byte)0xeb, (byte)0xad, (byte)0xda, (byte)0x24,
(byte)0xd5, (byte)0x96, (byte)0x85, (byte)0x2e, (byte)0x24, (byte)0x94, (byte)0xd6, (byte)0x4a, (byte)0xb8, (byte)0x5e, (byte)0x01,
(byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xa0, (byte)0xe8, (byte)0x85, (byte)0x2c,
(byte)0xe4, (byte)0xc9, (byte)0xce, (byte)0x01, (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04, (byte)0x05, (byte)0x06, (byte)0x07,
(byte)0x08, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x02, (byte)0x00, (byte)0x1e, (byte)0x00, (byte)0x57, (byte)0x00,
(byte)0x49, (byte)0x00, (byte)0x4e, (byte)0x00, (byte)0x2d, (byte)0x00, (byte)0x4c, (byte)0x00, (byte)0x4f, (byte)0x00, (byte)0x34,
(byte)0x00, (byte)0x31, (byte)0x00, (byte)0x39, (byte)0x00, (byte)0x42, (byte)0x00, (byte)0x32, (byte)0x00, (byte)0x4c, (byte)0x00,
(byte)0x53, (byte)0x00, (byte)0x52, (byte)0x00, (byte)0x30, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x1e, (byte)0x00, (byte)0x57,
(byte)0x00, (byte)0x49, (byte)0x00, (byte)0x4e, (byte)0x00, (byte)0x2d, (byte)0x00, (byte)0x4c, (byte)0x00, (byte)0x4f, (byte)0x00,
(byte)0x34, (byte)0x00, (byte)0x31, (byte)0x00, (byte)0x39, (byte)0x00, (byte)0x42, (byte)0x00, (byte)0x32, (byte)0x00, (byte)0x4c,
(byte)0x00, (byte)0x53, (byte)0x00, (byte)0x52, (byte)0x00, (byte)0x30, (byte)0x00, (byte)0x04, (byte)0x00, (byte)0x1e, (byte)0x00,
(byte)0x57, (byte)0x00, (byte)0x49, (byte)0x00, (byte)0x4e, (byte)0x00, (byte)0x2d, (byte)0x00, (byte)0x4c, (byte)0x00, (byte)0x4f,
(byte)0x00, (byte)0x34, (byte)0x00, (byte)0x31, (byte)0x00, (byte)0x39, (byte)0x00, (byte)0x42, (byte)0x00, (byte)0x32, (byte)0x00,
(byte)0x4c, (byte)0x00, (byte)0x53, (byte)0x00, (byte)0x52, (byte)0x00, (byte)0x30, (byte)0x00, (byte)0x03, (byte)0x00, (byte)0x1e,
(byte)0x00, (byte)0x57, (byte)0x00, (byte)0x49, (byte)0x00, (byte)0x4e, (byte)0x00, (byte)0x2d, (byte)0x00, (byte)0x4c, (byte)0x00,
(byte)0x4f, (byte)0x00, (byte)0x34, (byte)0x00, (byte)0x31, (byte)0x00, (byte)0x39, (byte)0x00, (byte)0x42, (byte)0x00, (byte)0x32,
(byte)0x00, (byte)0x4c, (byte)0x00, (byte)0x53, (byte)0x00, (byte)0x52, (byte)0x00, (byte)0x30, (byte)0x00, (byte)0x07, (byte)0x00,
(byte)0x08, (byte)0x00, (byte)0xa0, (byte)0xe8, (byte)0x85, (byte)0x2c, (byte)0xe4, (byte)0xc9, (byte)0xce, (byte)0x01, (byte)0x06,
(byte)0x00, (byte)0x04, (byte)0x00, (byte)0x02, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x0a, (byte)0x00, (byte)0x10, (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)0x00, (byte)0x09, (byte)0x00, (byte)0x26, (byte)0x00, (byte)0x54, (byte)0x00,
(byte)0x45, (byte)0x00, (byte)0x52, (byte)0x00, (byte)0x4d, (byte)0x00, (byte)0x53, (byte)0x00, (byte)0x52, (byte)0x00, (byte)0x56,
(byte)0x00, (byte)0x2f, (byte)0x00, (byte)0x31, (byte)0x00, (byte)0x39, (byte)0x00, (byte)0x32, (byte)0x00, (byte)0x2e, (byte)0x00,
(byte)0x31, (byte)0x00, (byte)0x36, (byte)0x00, (byte)0x38, (byte)0x00, (byte)0x2e, (byte)0x00, (byte)0x31, (byte)0x00, (byte)0x2e,
(byte)0x00, (byte)0x33, (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)0x00, (byte)0xe4, (byte)0xe9, (byte)0xc2,
(byte)0xad, (byte)0x41, (byte)0x02, (byte)0x2f, (byte)0x3c, (byte)0xf9, (byte)0x4c, (byte)0x72, (byte)0x84, (byte)0xc5, (byte)0x2a,
(byte)0x7c, (byte)0x6f,};
byte[] expected = new byte[] {(byte)0xd9, (byte)0xe9, (byte)0xbc, (byte)0x9b, (byte)0x6f, (byte)0xa5, (byte)0xf9, (byte)0xc8, (byte)0x70,
(byte)0x16, (byte)0x10, (byte)0x20, (byte)0xf8, (byte)0xf1, (byte)0x61, (byte)0x42,};
byte[] actual = ntlm_compute_message_integrity_check();
if (!Arrays.equals(expected, actual))
throw new RuntimeException("Incorrect result.\nExpected:\n" + new ByteBuffer(expected).toPlainHexString() + "\n actual:\n"
+ new ByteBuffer(actual).toPlainHexString() + ".");
}
public byte[] ntlm_EncryptMessage(byte[] message) {
byte[] versionBytes = new byte[] {0x01, 0x00, 0x00, 0x00}; // 0x00000001
// LE
byte[] seqNumBytes = new byte[] {(byte)(sendSeqNum & 0xff), (byte)((sendSeqNum >> 8) & 0xff), (byte)((sendSeqNum >> 16) & 0xff),
(byte)((sendSeqNum >> 24) & 0xff)};
byte[] digest = CryptoAlgos.HMAC_MD5(sendSigningKey, CryptoAlgos.concatenationOf(seqNumBytes, message));
byte[] encrypted = CryptoAlgos.RC4(sendRc4Seal, message);
// Encrypt first 8 bytes of digest only
byte[] checksum = CryptoAlgos.RC4(sendRc4Seal, Arrays.copyOf(digest, 8));
byte[] signature = CryptoAlgos.concatenationOf(versionBytes, checksum, seqNumBytes);
sendSeqNum++;
return CryptoAlgos.concatenationOf(signature, encrypted);
}
public void testNtlmEncryptMessage() {
sendSigningKey = new byte[] {(byte)0xf6, (byte)0xae, (byte)0x96, (byte)0xcb, (byte)0x05, (byte)0xe2, (byte)0xab, (byte)0x54, (byte)0xf6,
(byte)0xdd, (byte)0x59, (byte)0xf3, (byte)0xc9, (byte)0xd9, (byte)0xa0, (byte)0x43,};
sendRc4Seal = CryptoAlgos.initRC4(new byte[] {(byte)0x58, (byte)0x19, (byte)0x44, (byte)0xc2, (byte)0x7a, (byte)0xc6, (byte)0x34, (byte)0x45,
(byte)0xe4, (byte)0xb8, (byte)0x2b, (byte)0x55, (byte)0xb9, (byte)0x0b, (byte)0x1f, (byte)0xb5,});
sendSeqNum = 0;
byte[] serverPublicKey = new byte[] {(byte)0x30, (byte)0x82, (byte)0x01, (byte)0x0a, (byte)0x02, (byte)0x82, (byte)0x01, (byte)0x01, (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,};
byte[] expected = new byte[] {(byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x72, (byte)0x76, (byte)0x1e, (byte)0x57, (byte)0x49,
(byte)0xb5, (byte)0x0f, (byte)0xad, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (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,};
byte[] actual = ntlm_EncryptMessage(serverPublicKey);
if (!Arrays.equals(expected, actual))
throw new RuntimeException("Incorrect result.\nExpected:\n" + new ByteBuffer(expected).toPlainHexString() + "\n actual:\n"
+ new ByteBuffer(actual).toPlainHexString() + ".");
}
public byte[] ntlm_DecryptMessage(byte[] wrappedMssage) {
byte[] versionBytes = new byte[] {0x01, 0x00, 0x00, 0x00}; // 0x00000001
// LE
byte[] seqNumBytes = new byte[] {(byte)(recvSeqNum & 0xff), (byte)((recvSeqNum >> 8) & 0xff), (byte)((recvSeqNum >> 16) & 0xff),
(byte)((recvSeqNum >> 24) & 0xff)};
// Unwrap message
byte[] actualSignature = Arrays.copyOf(wrappedMssage, 16);
byte[] encryptedMessage = Arrays.copyOfRange(wrappedMssage, 16, wrappedMssage.length);
// Decrypt message
byte[] decryptedMessage = CryptoAlgos.RC4(recvRc4Seal, encryptedMessage);
// Compare actual signature with expected signature
byte[] digest = CryptoAlgos.HMAC_MD5(recvSigningKey, CryptoAlgos.concatenationOf(seqNumBytes, decryptedMessage));
// Encrypt first 8 bytes of digest only
byte[] checksum = CryptoAlgos.RC4(recvRc4Seal, Arrays.copyOf(digest, 8));
byte[] expectedSignature = CryptoAlgos.concatenationOf(versionBytes, checksum, seqNumBytes);
if (!Arrays.equals(expectedSignature, actualSignature))
throw new RuntimeException("Unexpected signature of message:\nExpected signature: " + new ByteBuffer(expectedSignature).toPlainHexString()
+ "\n Actual signature: " + new ByteBuffer(actualSignature).toPlainHexString());
recvSeqNum++;
return decryptedMessage;
}
public void testNtlmDecryptMessage() {
recvSigningKey = new byte[] {(byte)0xb6, (byte)0x58, (byte)0xc5, (byte)0x98, (byte)0x7a, (byte)0x25, (byte)0xf8, (byte)0x6e, (byte)0xd8,
(byte)0xe5, (byte)0x6c, (byte)0xe9, (byte)0x3e, (byte)0x3c, (byte)0xc0, (byte)0x88,};
recvRc4Seal = CryptoAlgos.initRC4(new byte[] {(byte)0x92, (byte)0x3a, (byte)0x73, (byte)0x5c, (byte)0x92, (byte)0xa7, (byte)0x04, (byte)0x34,
(byte)0xbe, (byte)0x9a, (byte)0xa2, (byte)0x9f, (byte)0xed, (byte)0xc1, (byte)0xe6, (byte)0x13,});
recvSeqNum = 0;
byte[] encryptedMessage = new byte[] {(byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x25, (byte)0xf8, (byte)0x2d, (byte)0x1e, (byte)0x4e,
(byte)0x6a, (byte)0xec, (byte)0x4f, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x03, (byte)0x12, (byte)0xdd, (byte)0xea,
(byte)0x47, (byte)0xb3, (byte)0xff, (byte)0xe1, (byte)0x66, (byte)0x08, (byte)0xf6, (byte)0x6b, (byte)0xa0, (byte)0x62, (byte)0x42,
(byte)0x67, (byte)0xbf, (byte)0x3d, (byte)0x59, (byte)0x60, (byte)0xef, (byte)0x52, (byte)0xb0, (byte)0x26, (byte)0x95, (byte)0xed,
(byte)0x84, (byte)0x48, (byte)0x44, (byte)0xbb, (byte)0x8d, (byte)0x65, (byte)0xcf, (byte)0xe4, (byte)0x8e, (byte)0x6f, (byte)0x69,
(byte)0xae, (byte)0xed, (byte)0x44, (byte)0xbb, (byte)0x49, (byte)0x1d, (byte)0x2a, (byte)0x40, (byte)0x29, (byte)0x2b, (byte)0x13,
(byte)0x42, (byte)0x1c, (byte)0xeb, (byte)0xb1, (byte)0x6c, (byte)0x8a, (byte)0x3b, (byte)0x80, (byte)0xd1, (byte)0x70, (byte)0xfd,
(byte)0xdd, (byte)0x79, (byte)0xe4, (byte)0x93, (byte)0x0b, (byte)0x47, (byte)0xbd, (byte)0x3a, (byte)0x7e, (byte)0x31, (byte)0x66,
(byte)0x4b, (byte)0x65, (byte)0x8d, (byte)0x5c, (byte)0x2a, (byte)0xcd, (byte)0xc2, (byte)0x09, (byte)0x7a, (byte)0x3b, (byte)0xb2,
(byte)0xfd, (byte)0x09, (byte)0x52, (byte)0x09, (byte)0x47, (byte)0x05, (byte)0xa4, (byte)0x6f, (byte)0x32, (byte)0xd1, (byte)0x76,
(byte)0xb2, (byte)0xd4, (byte)0x59, (byte)0xe0, (byte)0x85, (byte)0xf1, (byte)0x36, (byte)0x7d, (byte)0x76, (byte)0x50, (byte)0x21,
(byte)0x0e, (byte)0x20, (byte)0x22, (byte)0x83, (byte)0x1a, (byte)0x08, (byte)0xc0, (byte)0x85, (byte)0x5d, (byte)0x4f, (byte)0x5c,
(byte)0x77, (byte)0x68, (byte)0x32, (byte)0x95, (byte)0xa9, (byte)0xa2, (byte)0x59, (byte)0x69, (byte)0xea, (byte)0x19, (byte)0x34,
(byte)0x08, (byte)0xed, (byte)0x76, (byte)0xa3, (byte)0x58, (byte)0x37, (byte)0xf2, (byte)0x0a, (byte)0x0c, (byte)0xba, (byte)0x4d,
(byte)0xbb, (byte)0x6f, (byte)0x82, (byte)0x94, (byte)0xd3, (byte)0x87, (byte)0xde, (byte)0xc9, (byte)0x8f, (byte)0xef, (byte)0x34,
(byte)0x2d, (byte)0x8f, (byte)0xd0, (byte)0x0c, (byte)0x91, (byte)0x59, (byte)0xfd, (byte)0xea, (byte)0x6b, (byte)0xcb, (byte)0xbd,
(byte)0xa2, (byte)0x20, (byte)0xed, (byte)0xb9, (byte)0x76, (byte)0xd3, (byte)0x64, (byte)0x1b, (byte)0xb3, (byte)0x3b, (byte)0xf5,
(byte)0x9b, (byte)0x61, (byte)0xd7, (byte)0xab, (byte)0x26, (byte)0x9b, (byte)0x0d, (byte)0xa0, (byte)0xea, (byte)0xbf, (byte)0xad,
(byte)0x2c, (byte)0xad, (byte)0x63, (byte)0x65, (byte)0xc6, (byte)0x70, (byte)0xc4, (byte)0xe5, (byte)0x8d, (byte)0x40, (byte)0xaa,
(byte)0x08, (byte)0x45, (byte)0x66, (byte)0xe2, (byte)0x4d, (byte)0xc9, (byte)0x46, (byte)0x00, (byte)0x33, (byte)0x43, (byte)0xe0,
(byte)0xba, (byte)0xd6, (byte)0x80, (byte)0x29, (byte)0x21, (byte)0x5e, (byte)0xd1, (byte)0x9a, (byte)0xbc, (byte)0x44, (byte)0xfa,
(byte)0x4d, (byte)0x46, (byte)0xf9, (byte)0x25, (byte)0x80, (byte)0x40, (byte)0xb5, (byte)0x27, (byte)0xdd, (byte)0xc5, (byte)0x02,
(byte)0xf8, (byte)0xa4, (byte)0x9a, (byte)0xcb, (byte)0xcf, (byte)0x3f, (byte)0xef, (byte)0xc7, (byte)0xcd, (byte)0x71, (byte)0x45,
(byte)0xa5, (byte)0x35, (byte)0xb1, (byte)0x21, (byte)0x14, (byte)0x39, (byte)0x57, (byte)0xf8, (byte)0x0a, (byte)0x24, (byte)0x98,
(byte)0xea, (byte)0x15, (byte)0xe1, (byte)0xe3, (byte)0xcb, (byte)0x9d, (byte)0xf2, (byte)0x4e, (byte)0xef, (byte)0x89, (byte)0x97,
(byte)0xc0, (byte)0xb2, (byte)0x96, (byte)0x9a, (byte)0x1e, (byte)0xad, (byte)0xd0, (byte)0x9a, (byte)0x99, (byte)0x62, (byte)0x9f,
(byte)0x13, (byte)0x2e,};
byte[] expected = new byte[] {
// First byte is increased by 1
(byte)0x31, (byte)0x82, (byte)0x01, (byte)0x0a, (byte)0x02, (byte)0x82, (byte)0x01, (byte)0x01, (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,};
byte[] actual = ntlm_DecryptMessage(encryptedMessage);
if (!Arrays.equals(expected, actual))
throw new RuntimeException("Incorrect result.\nExpected:\n" + new ByteBuffer(expected).toPlainHexString() + "\n actual:\n"
+ new ByteBuffer(actual).toPlainHexString() + ".");
}
public static void main(String args[]) {
CryptoAlgos.callAll(new NtlmState());
}
}

View File

@ -0,0 +1,21 @@
// 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;
public class SecBuffer {
}

View File

@ -0,0 +1,293 @@
// 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.util.Arrays;
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;
/**
* @see http://msdn.microsoft.com/en-us/library/cc236642.aspx
*/
public class ServerNtlmsspChallenge extends OneTimeSwitch implements NtlmConstants {
protected NtlmState ntlmState;
public ServerNtlmsspChallenge(String id, NtlmState state) {
super(id);
ntlmState = state;
}
@Override
protected void handleOneTimeData(ByteBuffer buf, Link link) {
if (buf == null)
return;
if (verbose)
System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
// Extract server challenge, extract server flags.
// Parse TSRequest in BER format
TSRequest request = new TSRequest("TSRequest");
request.readTag(buf);
ByteBuffer negoToken = ((NegoItem)request.negoTokens.tags[0]).negoToken.value;
ntlmState.challengeMessage = negoToken.toByteArray(); // Store message for MIC calculation in AUTH message
parseNtlmChallenge(negoToken);
negoToken.unref();
buf.unref();
switchOff();
}
public void parseNtlmChallenge(ByteBuffer buf) {
// Signature: "NTLMSSP\0"
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.CHALLENGE)
throw new RuntimeException("Unexpected NTLM message type: " + messageType + ". Expected type: CHALLENGE (" + NtlmConstants.CHALLENGE + "). Data: " + buf
+ ".");
// TargetName
ntlmState.serverTargetName = readStringByDescription(buf);
// NegotiateFlags
ntlmState.negotiatedFlags = new NegoFlags(buf.readSignedIntLE());
if (verbose)
System.out.println("[" + this + "] INFO: Server negotiate flags: " + ntlmState.negotiatedFlags + ".");
// ServerChallenge
ByteBuffer challenge = buf.readBytes(8);
ntlmState.serverChallenge = challenge.toByteArray();
if (verbose)
System.out.println("[" + this + "] INFO: Server challenge: " + challenge + ".");
challenge.unref();
// Reserved/context
buf.skipBytes(8);
// TargetInfo
ByteBuffer targetInfo = readBlockByDescription(buf);
// Store raw target info block for Type3 message
ntlmState.serverTargetInfo = targetInfo.toByteArray();
// Parse target info block
parseTargetInfo(targetInfo);
targetInfo.unref();
// OS Version, NTLM revision, 8 bytes, Optional. Ignore it.
// Ignore rest of buffer with allocated blocks
buf.unref();
}
public void parseTargetInfo(ByteBuffer buf) {
// 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);
parseAttribute(data, type, length);
data.unref();
}
}
public void parseAttribute(ByteBuffer buf, int type, int length) {
switch (type) {
case MSV_AV_NETBIOS_DOMAIN_NAME:
ntlmState.serverNetbiosDomainName = buf.readString(length, RdpConstants.CHARSET_16);
break;
case MSV_AV_NETBIOS_COMPUTER_NAME:
ntlmState.serverNetbiosComputerName = buf.readString(length, RdpConstants.CHARSET_16);
break;
case MSV_AV_DNS_DOMAIN_NAME:
ntlmState.serverDnsDomainName = buf.readString(length, RdpConstants.CHARSET_16);
break;
case MSV_AV_DNS_COMPUTER_NAME:
ntlmState.serverDnsComputerName = buf.readString(length, RdpConstants.CHARSET_16);
break;
case MSV_AV_DNS_TREE_NAME:
ntlmState.serverDnsTreeName = buf.readString(length, RdpConstants.CHARSET_16);
break;
case MSV_AV_TIMESTAMP:
ByteBuffer tmp = buf.readBytes(length);
ntlmState.serverTimestamp = tmp.toByteArray();
//*DEBUG*/System.out.println("Server timestamp: "+tmp.toPlainHexString());
tmp.unref();
break;
default:
// Ignore
//throw new RuntimeException("[" + this + "] ERROR: Unknown NTLM target info attribute: " + type + ". Data: " + buf + ".");
}
}
/**
* Read NTLM wide string, by it description. Buffer offset must point to
* beginning of NTLM message signature.
*
* @param buf
* buffer with cursor pointing to description
* @return
*/
public static String readStringByDescription(ByteBuffer buf) {
ByteBuffer block = readBlockByDescription(buf);
String value = block.readString(block.length, RdpConstants.CHARSET_16);
block.unref();
return value;
}
public static ByteBuffer readBlockByDescription(ByteBuffer buf) {
int blockLength = buf.readUnsignedShortLE(); // In bytes
int allocatedSpace = buf.readUnsignedShortLE();
int offset = buf.readSignedIntLE();
if (allocatedSpace < blockLength)
blockLength = allocatedSpace;
if (offset > buf.length || offset < 0 || offset + allocatedSpace > buf.length)
throw new RuntimeException("ERROR: NTLM block is too long. Allocated space: " + allocatedSpace + ", block offset: " + offset + ", data: "
+ buf + ".");
// Move cursor to position of allocated block, starting from beginning of
// this buffer
int storedCursor = buf.cursor;
buf.cursor = offset;
// Read string
ByteBuffer value = buf.readBytes(blockLength);
// Restore cursor
buf.cursor = storedCursor;
return value;
}
/**
* 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[] {
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
0x52, (byte) 0xbe, (byte) 0x83, (byte) 0xd1, (byte) 0xf8, (byte) 0x80, 0x16, 0x6a, // 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) 0x99, 0x4f, 0x02, (byte) 0xd8, (byte) 0xf4, (byte) 0xaf, (byte) 0xce, 0x01, // TODO
// Attribute: End of list
0x00, 0x00,
0x00, 0x00,
};
/* @formatter:on */
MockSource source = new MockSource("source", ByteBuffer.convertByteArraysToByteBuffers(packet, new byte[] {1, 2, 3}));
NtlmState state = new NtlmState();
Element ntlmssp_challenge = new ServerNtlmsspChallenge("ntlmssp_challenge", state);
Element sink = new MockSink("sink", ByteBuffer.convertByteArraysToByteBuffers());
Element mainSink = new MockSink("mainSink", ByteBuffer.convertByteArraysToByteBuffers(new byte[] {1, 2, 3}));
Pipeline pipeline = new PipelineImpl("test");
pipeline.add(source, ntlmssp_challenge, sink, mainSink);
pipeline.link("source", "ntlmssp_challenge", "mainSink");
pipeline.link("ntlmssp_challenge >" + OTOUT, "sink");
pipeline.runMainLoop("source", STDOUT, false, false);
// Check state challenge
byte[] challenge = new byte[] {0x52, (byte)0xbe, (byte)0x83, (byte)0xd1, (byte)0xf8, (byte)0x80, 0x16, 0x6a};
if (state.serverChallenge == null)
throw new RuntimeException("Challenge was not extracted from server NTLMSSP Challenge packet.");
if (!Arrays.equals(challenge, state.serverChallenge))
throw new RuntimeException("Challenge was extracted from server NTLMSSP Challenge packet is not equal to expected. Actual value: "
+ state.serverChallenge + ", expected value: " + challenge + ".");
}
}

View File

@ -0,0 +1,125 @@
// 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.util.Arrays;
import rdpclient.ntlmssp.asn1.TSRequest;
import streamer.ByteBuffer;
import streamer.Element;
import streamer.Link;
import streamer.OneTimeSwitch;
public class ServerNtlmsspPubKeyPlus1 extends OneTimeSwitch implements Element {
protected NtlmState ntlmState;
public ServerNtlmsspPubKeyPlus1(String id, NtlmState ntlmState) {
super(id);
this.ntlmState = ntlmState;
}
@Override
protected void handleOneTimeData(ByteBuffer buf, Link link) {
TSRequest tsRequest = new TSRequest("TSRequest");
tsRequest.readTag(buf);
ByteBuffer encryptedPubKey = tsRequest.pubKeyAuth.value;
if (encryptedPubKey == null || encryptedPubKey.length == 0)
throw new RuntimeException("[" + this
+ "] ERROR: Unexpected message from RDP server. Expected encrypted server public key but got nothing instead. Data: " + buf);
byte[] decryptedPubKey = ntlmState.ntlm_DecryptMessage(encryptedPubKey.toByteArray());
//* DEBUG */System.out.println("Decrypted pub key:\n" + new ByteBuffer(decryptedPubKey).dump());
// Decrease first byte by 1
decryptedPubKey[0]--;
// Compare returned value with expected value
if (!Arrays.equals(decryptedPubKey, ntlmState.subjectPublicKey))
throw new RuntimeException("[" + this
+ "] ERROR: Unexpected message from RDP server. Expected encrypted server public key but an unknown response. Encryted key after decryption: "
+ new ByteBuffer(decryptedPubKey).toPlainHexString());
buf.unref();
switchOff(); // Ignore packet
}
}
/* @formatter:off */
// CredSSP header in BER format:
// 0x30, (byte) 0x82, 0x01, 0x2b, // TAG: [UNIVERSAL 16] (constructed)
// "SEQUENCE" LEN: 299 bytes
// (byte) 0xa0, 0x03, // TAG: [0] (constructed) LEN: 3 bytes
// 0x02, 0x01, 0x03, // TAG: [UNIVERSAL 2] (primitive) "INTEGER" LEN: 1 bytes,
// Version: 0x3
// (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
// ???
// 0x01, 0x00, 0x00, 0x00, // ???
// (byte) 0x98, (byte) 0xb0, 0x72, 0x48, 0x42, 0x09, (byte) 0xbd, 0x42, 0x00,
// 0x00, 0x00, //
// 0x00, (byte) 0xf6, 0x76, 0x0a, 0x40, (byte) 0xb4, 0x7b, (byte) 0xee, 0x69,
// (byte) 0xfc, (byte) 0x95, 0x2d, 0x5f, 0x6a, (byte) 0xe8, (byte) 0x87, //
// 0x4e, (byte) 0xeb, (byte) 0xae, 0x29, (byte) 0xf2, (byte) 0xde, 0x5e, 0x0a,
// 0x6e, 0x45, (byte) 0xeb, (byte) 0x95, (byte) 0xd9, 0x48, (byte) 0xfc, 0x44,
// //
// 0x7a, 0x34, (byte) 0xb4, (byte) 0xc4, (byte) 0xee, (byte) 0x93, (byte) 0xd2,
// (byte) 0xb4, (byte) 0xe5, (byte) 0xe5, (byte) 0xc1, 0x0f, (byte) 0x9e, 0x3b,
// (byte) 0xce, (byte) 0xaa, //
// 0x76, (byte) 0x9e, 0x2b, 0x33, 0x44, 0x76, 0x2f, 0x2f, (byte) 0x83, 0x34,
// 0x3c, (byte) 0xe9, (byte) 0xc2, (byte) 0xeb, 0x0e, (byte) 0xce, //
// 0x6c, (byte) 0xcd, 0x1c, (byte) 0xae, 0x74, 0x78, 0x3e, (byte) 0x8c, 0x17,
// (byte) 0xb4, 0x39, (byte) 0x9a, 0x21, (byte) 0x99, (byte) 0xde, (byte) 0xae,
// //
// 0x72, 0x23, (byte) 0x94, (byte) 0xc6, (byte) 0xe9, (byte) 0xcb, 0x48, (byte)
// 0xb1, 0x54, 0x20, 0x70, 0x70, (byte) 0xc0, 0x77, 0x10, 0x4b, //
// (byte) 0x8a, (byte) 0xe0, (byte) 0xa0, 0x6c, (byte) 0xb9, 0x65, (byte) 0xfc,
// 0x67, (byte) 0xe3, 0x3b, (byte) 0xb6, 0x46, 0x5e, (byte) 0xaf, (byte) 0xe7,
// (byte) 0x92, //
// 0x6a, (byte) 0xaf, (byte) 0x86, 0x4d, 0x74, 0x33, 0x49, 0x2a, (byte) 0xf0,
// (byte) 0xdd, 0x66, (byte) 0xce, (byte) 0xec, (byte) 0xcc, 0x6b, 0x62, //
// 0x4f, 0x35, (byte) 0xb5, 0x0f, (byte) 0x95, (byte) 0xd7, (byte) 0xf7, (byte)
// 0xf3, 0x4b, 0x59, 0x5f, 0x29, (byte) 0xc9, (byte) 0xc4, (byte) 0xdc, 0x47, //
// (byte) 0xe9, (byte) 0x8d, 0x47, (byte) 0xd2, 0x1d, 0x35, 0x43, (byte) 0xce,
// (byte) 0xff, (byte) 0xd7, 0x6b, 0x28, (byte) 0xd8, 0x06, (byte) 0xe8, (byte)
// 0xba, //
// (byte) 0xf1, 0x4d, (byte) 0xba, 0x43, (byte) 0x8e, 0x64, (byte) 0xba, (byte)
// 0xcd, (byte) 0xcb, (byte) 0xaf, 0x1a, 0x61, (byte) 0xd8, 0x11, 0x19, (byte)
// 0xf7, //
// (byte) 0xae, (byte) 0xfe, (byte) 0x94, 0x48, (byte) 0x8e, (byte) 0x9f, 0x57,
// 0x17, (byte) 0xd2, (byte) 0xa3, (byte) 0xfd, 0x79, (byte) 0xb5, (byte) 0xa3,
// 0x7d, (byte) 0xca, //
// (byte) 0xff, (byte) 0x94, (byte) 0xb5, (byte) 0xb5, 0x03, (byte) 0xf3, 0x13,
// 0x6a, 0x74, 0x7a, (byte) 0xae, (byte) 0x9d, (byte) 0xe9, 0x5c, 0x32, 0x42, //
// 0x37, (byte) 0xa6, (byte) 0xb3, (byte) 0xf5, 0x4b, (byte) 0xaa, 0x22, 0x61,
// (byte) 0xf5, 0x28, 0x5b, 0x41, 0x26, 0x32, 0x63, 0x5f, //
// 0x43, (byte) 0xfd, 0x2e, 0x44, 0x7d, (byte) 0xfb, (byte) 0xb6, 0x09, (byte)
// 0xc5, (byte) 0xc8, 0x33, (byte) 0xbe, (byte) 0x81, 0x08, (byte) 0xd4, 0x5f,
// //
// (byte) 0xad, (byte) 0xee, 0x49, 0x25, 0x62, 0x52, (byte) 0x83, (byte) 0xc1,
// 0x3e, 0x17, 0x5b, (byte) 0xea, 0x4b, (byte) 0x90, 0x62, (byte) 0xf7, //
// 0x4e, 0x28, (byte) 0xfb, (byte) 0xab, (byte) 0x9a, (byte) 0xbc, 0x5e, (byte)
// 0xd4, (byte) 0xd5, 0x56, (byte) 0xf4, 0x4a, 0x2a, 0x7e, (byte) 0xd7, //
/* @formatter:on */

View File

@ -0,0 +1,40 @@
// 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.asn1;
import common.asn1.Any;
import common.asn1.ObjectID;
import common.asn1.Sequence;
import common.asn1.Tag;
/**
* X509 SubjectPublicKeyInfo field ASN.1 description.
*/
public class AlgorithmIdentifier extends Sequence {
public ObjectID algorithm = new ObjectID("algorithm");
public Any parameters = new Any("parameters") {
{
optional = true;
}
};
public AlgorithmIdentifier(String name) {
super(name);
tags = new Tag[] {algorithm, parameters};
}
}

View File

@ -0,0 +1,64 @@
// 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.asn1;
import common.asn1.SequenceOf;
import common.asn1.Tag;
/**
* The NegoData structure contains the SPNEGO messages, as specified in
* [MS-SPNG] section 2.
*
* <pre>
* NegoData ::= SEQUENCE OF SEQUENCE {
* negoToken [0] OCTET STRING
* }
* </pre>
*
* If we write NegoItem as
*
* <pre>
* NegoItem ::= SEQUENCE {
* negoToken [0] OCTET STRING
* }
* </pre>
*
* then NegoData can be written as
*
* <pre>
* NegoData ::= SEQUENCE OF NegoItem
* </pre>
*
* <ul>
* <li>negoToken: One or more SPNEGO tokens, as specified in [MS-SPNG].
* </ul>
*
* @see http://msdn.microsoft.com/en-us/library/cc226781.aspx
*/
public class NegoData extends SequenceOf {
public NegoData(String name) {
super(name);
type = new NegoItem("NegoItem");
}
@Override
public Tag deepCopy(String suffix) {
return new NegoData(name + suffix).copyFrom(this);
}
}

View File

@ -0,0 +1,73 @@
// 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.asn1;
import common.asn1.OctetString;
import common.asn1.Sequence;
import common.asn1.Tag;
/**
* The NegoData structure contains the SPNEGO messages, as specified in
* [MS-SPNG] section 2.
*
* <pre>
* NegoData ::= SEQUENCE OF SEQUENCE {
* negoToken [0] OCTET STRING
* }
* </pre>
*
* If we write NegoItem as
*
* <pre>
* NegoItem ::= SEQUENCE {
* negoToken [0] OCTET STRING
* }
* </pre>
*
* then NegoData can be written as
*
* <pre>
* NegoData ::= SEQUENCE OF NegoItem
* </pre>
*
* <ul>
* <li>negoToken: One or more SPNEGO tokens, as specified in [MS-SPNG].
* </ul>
*
* @see http://msdn.microsoft.com/en-us/library/cc226781.aspx
*/
public class NegoItem extends Sequence {
public OctetString negoToken = new OctetString("negoToken") {
{
explicit = true;
tagClass = CONTEXT_CLASS;
tagNumber = 0;
}
};
public NegoItem(String name) {
super(name);
tags = new Tag[] {negoToken};
}
@Override
public Tag deepCopy(String suffix) {
return new NegoItem(name + suffix).copyFrom(this);
}
}

View File

@ -0,0 +1,35 @@
// 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.asn1;
import common.asn1.BitString;
import common.asn1.Sequence;
import common.asn1.Tag;
/**
* X509 SubjectPublicKeyInfo field ASN.1 description.
*/
public class SubjectPublicKeyInfo extends Sequence {
public AlgorithmIdentifier algorithm = new AlgorithmIdentifier("algorithm");
public BitString subjectPublicKey = new BitString("subjectPublicKey");
public SubjectPublicKeyInfo(String name) {
super(name);
tags = new Tag[] {algorithm, subjectPublicKey};
}
}

View File

@ -0,0 +1,62 @@
// 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.asn1;
import common.asn1.Asn1Integer;
import common.asn1.OctetString;
import common.asn1.Sequence;
import common.asn1.Tag;
/**
* <pre>
* TSCredentials ::= SEQUENCE {
* credType [0] INTEGER,
* credentials [1] OCTET STRING
* }
*
* credType:
* 1 - credentials contains a TSPasswordCreds structure that defines the user's password credentials.
* 2 - credentials contains a TSSmartCardCreds structure that defines the user's smart card credentials.
* </pre>
*/
public class TSCredentials extends Sequence {
public Asn1Integer credType = new Asn1Integer("credType") {
{
explicit = true;
tagClass = CONTEXT_CLASS;
tagNumber = 0;
}
};
public OctetString credentials = new OctetString("credentials") {
{
explicit = true;
tagClass = CONTEXT_CLASS;
tagNumber = 1;
}
};
public TSCredentials(String name) {
super(name);
tags = new Tag[] {credType, credentials};
}
@Override
public Tag deepCopy(String suffix) {
return new TSCredentials(name + suffix).copyFrom(this);
}
}

View File

@ -0,0 +1,98 @@
// 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.asn1;
import common.asn1.Asn1Integer;
import common.asn1.OctetString;
import common.asn1.Sequence;
import common.asn1.Tag;
/**
* <pre>
* TSCspDataDetail ::= SEQUENCE {
* keySpec [0] INTEGER,
* cardName [1] OCTET STRING OPTIONAL,
* readerName [2] OCTET STRING OPTIONAL,
* containerName [3] OCTET STRING OPTIONAL,
* cspName [4] OCTET STRING OPTIONAL
* }
* </pre>
* <ul>
* <li>keySpec: Defines the specification of the user's smart card.
*
* <li>cardName: Specifies the name of the smart card.
*
* <li>readerName: Specifies the name of the smart card reader.
*
* <li>containerName: Specifies the name of the certificate container.
*
* <li>cspName: Specifies the name of the CSP.
* </ul>
* @see http://msdn.microsoft.com/en-us/library/cc226785.aspx
*/
public class TSCspDataDetail extends Sequence {
public Asn1Integer keySpec = new Asn1Integer("keySpec") {
{
explicit = true;
tagClass = CONTEXT_CLASS;
tagNumber = 0;
}
};
public OctetString cardName = new OctetString("cardName") {
{
explicit = true;
tagClass = CONTEXT_CLASS;
tagNumber = 1;
optional = true;
}
};
public OctetString readerName = new OctetString("readerName") {
{
explicit = true;
tagClass = CONTEXT_CLASS;
tagNumber = 2;
optional = true;
}
};
public OctetString containerName = new OctetString("containerName") {
{
explicit = true;
tagClass = CONTEXT_CLASS;
tagNumber = 3;
optional = true;
}
};
public OctetString cspName = new OctetString("cspName") {
{
explicit = true;
tagClass = CONTEXT_CLASS;
tagNumber = 4;
optional = true;
}
};
public TSCspDataDetail(String name) {
super(name);
tags = new Tag[] {keySpec, cardName, readerName, containerName, cspName};
}
@Override
public Tag deepCopy(String suffix) {
return new TSCspDataDetail(name + suffix).copyFrom(this);
}
}

View File

@ -0,0 +1,76 @@
// 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.asn1;
import common.asn1.OctetString;
import common.asn1.Sequence;
import common.asn1.Tag;
/**
* <pre>
* TSPasswordCreds ::= SEQUENCE {
* domainName [0] OCTET STRING,
* userName [1] OCTET STRING,
* password [2] OCTET STRING
* }
* </pre>
*
* <ul>
* <li>domainName: Contains the name of the user's account domain, as defined in
* [MS-GLOS].
*
* <li>userName: Contains the user's account name.
*
* <li>Password: Contains the user's account password.
* </ul>
*
* @see http://msdn.microsoft.com/en-us/library/cc226783.aspx
*/
public class TSPasswordCreds extends Sequence {
public OctetString domainName = new OctetString("domainName") {
{
explicit = true;
tagClass = CONTEXT_CLASS;
tagNumber = 0;
}
};
public OctetString userName = new OctetString("userName") {
{
explicit = true;
tagClass = CONTEXT_CLASS;
tagNumber = 1;
}
};
public OctetString password = new OctetString("password") {
{
explicit = true;
tagClass = CONTEXT_CLASS;
tagNumber = 2;
}
};
public TSPasswordCreds(String name) {
super(name);
tags = new Tag[] {domainName, userName, password};
}
@Override
public Tag deepCopy(String suffix) {
return new TSPasswordCreds(name + suffix).copyFrom(this);
}
}

View File

@ -0,0 +1,201 @@
// 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.asn1;
import streamer.ByteBuffer;
import common.asn1.Asn1Integer;
import common.asn1.OctetString;
import common.asn1.Sequence;
import common.asn1.Tag;
/**
* The TSRequest structure is the top-most structure used by the CredSSP client
* and CredSSP server. It contains the SPNEGO messages between the client and
* server, and either the public key authentication messages that are used to
* bind to the TLS session or the client credentials that are delegated to the
* server. The TSRequest message is always sent over the TLS-encrypted channel
* between the client and server in a CredSSP Protocol exchange (see step 1 in
* section 3.1.5).
*
* <pre>
* TSRequest ::= SEQUENCE {
* version [0] INTEGER,
* negoTokens [1] NegoData OPTIONAL,
* authInfo [2] OCTET STRING OPTIONAL,
* pubKeyAuth [3] OCTET STRING OPTIONAL
* }
*
* </pre>
* <ul>
*
* <li>version: This field specifies the supported version of the CredSSP
* Protocol. This field MUST be 2. If the version is greater than 2, a version 2
* client or server treats its peer as one that is compatible with version 2 of
* the CredSSP Protocol.
*
* <li>negoTokens: A NegoData structure, as defined in section 2.2.1.1, that
* contains the SPNEGO messages that are passed between the client and server.
*
* <li>authInfo: A TSCredentials structure, as defined in section 2.2.1.2, that
* contains the user's credentials that are delegated to the server. The
* authinfo field <b>MUST be encrypted</b> under the encryption key that is
* negotiated under the SPNEGO package.
*
* <li>pubKeyAuth: This field is used to assure that the public key that is used
* by the server during the TLS handshake belongs to the target server and not
* to a "man in the middle". 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. After the
* client completes the SPNEGO phase of the CredSSP Protocol, it uses
* GSS_WrapEx() for the negotiated protocol to encrypt the server's public key.
* The pubKeyAuth field carries the message signature and then the encrypted
* public key to the server. In response, the server uses the pubKeyAuth field
* to transmit to the client a modified version of the public key (as described
* in section 3.1.5) that is encrypted under the encryption key that is
* negotiated under SPNEGO.
* </ul>
*
* @see http://msdn.microsoft.com/en-us/library/cc226780.aspx
*/
public class TSRequest extends Sequence {
public Asn1Integer version = new Asn1Integer("version") {
{
explicit = true;
tagClass = CONTEXT_CLASS;
tagNumber = 0;
}
};
public NegoData negoTokens = new NegoData("negoTokens") {
{
explicit = true;
tagClass = CONTEXT_CLASS;
tagNumber = 1;
optional = true;
}
};
public OctetString authInfo = new OctetString("authInfo") {
{
explicit = true;
tagClass = CONTEXT_CLASS;
tagNumber = 2;
optional = true;
}
};
public OctetString pubKeyAuth = new OctetString("pubKeyAuth") {
{
explicit = true;
tagClass = CONTEXT_CLASS;
tagNumber = 3;
optional = true;
}
};
public TSRequest(String name) {
super(name);
tags = new Tag[] {version, negoTokens, authInfo, pubKeyAuth};
}
@Override
public Tag deepCopy(String suffix) {
return new TSRequest(name + suffix).copyFrom(this);
}
/**
* Example.
*/
public static void main(String[] args) {
/* @formatter:off */
byte[] packet = 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 TODO
0x52, (byte) 0xbe, (byte) 0x83, (byte) 0xd1, (byte) 0xf8, (byte) 0x80, 0x16, 0x6a, // 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) 0x99, 0x4f, 0x02, (byte) 0xd8, (byte) 0xf4, (byte) 0xaf, (byte) 0xce, 0x01, // TODO
// Attribute: End of list
0x00, 0x00,
0x00, 0x00,
};
/* @formatter:on */
TSRequest request = new TSRequest("TSRequest");
// Read request from buffer
// System.out.println("Request BER tree before parsing: " + request);
ByteBuffer toReadBuf = new ByteBuffer(packet);
request.readTag(toReadBuf);
// System.out.println("Request BER tree after parsing: " + request);
// System.out.println("version value: " + request.version.value);
// System.out.println("negoToken value: " + ((NegoItem)
// request.negoTokens.tags[0]).negoToken.value);
// Write request to buffer and compare with original
ByteBuffer toWriteBuf = new ByteBuffer(packet.length + 100, true);
request.writeTag(toWriteBuf);
toWriteBuf.trimAtCursor();
if (!toReadBuf.equals(toWriteBuf))
throw new RuntimeException("Data written to buffer is not equal to data read from buffer. \nExpected: " + toReadBuf + "\nActual: " + toWriteBuf + ".");
}
}

View File

@ -0,0 +1,90 @@
// 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.asn1;
import common.asn1.OctetString;
import common.asn1.Sequence;
import common.asn1.Tag;
/**
* <pre>
* TSSmartCardCreds ::= SEQUENCE {
* pin [0] OCTET STRING,
* cspData [1] TSCspDataDetail,
* userHint [2] OCTET STRING OPTIONAL,
* domainHint [3] OCTET STRING OPTIONAL
* }
* </pre>
*
* <ul>
* <li>pin: Contains the user's smart card PIN.
*
* <li>cspData: A TSCspDataDetail structure that contains information about the
* cryptographic service provider (CSP).
*
* <li>userHint: Contains the user's account hint.
*
* <li>domainHint: Contains the user's domain name to which the user's account
* belongs. This name could be entered by the user when the user is first
* prompted for the PIN.
* </ul>
*
* @see http://msdn.microsoft.com/en-us/library/cc226784.aspx
*/
public class TSSmartCardCreds extends Sequence {
public OctetString pin = new OctetString("pin") {
{
explicit = true;
tagClass = CONTEXT_CLASS;
tagNumber = 0;
}
};
public TSCspDataDetail cspData = new TSCspDataDetail("cspData") {
{
explicit = true;
tagClass = CONTEXT_CLASS;
tagNumber = 1;
}
};
public OctetString userHint = new OctetString("userHint") {
{
explicit = true;
tagClass = CONTEXT_CLASS;
tagNumber = 2;
optional = true;
}
};
public OctetString domainHint = new OctetString("domainHint") {
{
explicit = true;
tagClass = CONTEXT_CLASS;
tagNumber = 3;
optional = true;
}
};
public TSSmartCardCreds(String name) {
super(name);
tags = new Tag[] {pin, cspData, userHint, domainHint};
}
@Override
public Tag deepCopy(String suffix) {
return new TSSmartCardCreds(name + suffix).copyFrom(this);
}
}

View File

@ -0,0 +1,71 @@
// 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.
/**
*
* CredSSP/SPNEGO/NTLMSSP implementation.
*
* CredSSP ASN.1 definition:
*
<pre>
CredSSP DEFINITIONS EXPLICIT TAGS ::=
BEGIN
TSPasswordCreds ::= SEQUENCE {
domainName [0] OCTET STRING,
userName [1] OCTET STRING,
password [2] OCTET STRING
}
TSCspDataDetail ::= SEQUENCE {
keySpec [0] INTEGER,
cardName [1] OCTET STRING OPTIONAL,
readerName [2] OCTET STRING OPTIONAL,
containerName [3] OCTET STRING OPTIONAL,
cspName [4] OCTET STRING OPTIONAL
}
TSSmartCardCreds ::= SEQUENCE {
pin [0] OCTET STRING,
cspData [1] TSCspDataDetail,
userHint [2] OCTET STRING OPTIONAL,
domainHint [3] OCTET STRING OPTIONAL
}
TSCredentials ::= SEQUENCE {
credType [0] INTEGER,
credentials [1] OCTET STRING
}
NegoData ::= SEQUENCE OF SEQUENCE {
negoToken [0] OCTET STRING
}
TSRequest ::= SEQUENCE {
version [0] INTEGER,
negoTokens [1] NegoData OPTIONAL,
authInfo [2] OCTET STRING OPTIONAL,
pubKeyAuth [3] OCTET STRING OPTIONAL
}
END
</pre>
For packet flow, @see http://msdn.microsoft.com/en-us/library/cc226794.aspx
*/
package rdpclient.ntlmssp;

View File

@ -14,7 +14,7 @@
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package rdpclient;
package rdpclient.rdp;
import streamer.BaseElement;
import streamer.ByteBuffer;

View File

@ -0,0 +1,456 @@
// 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.rdp;
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;
/**
* @see http://msdn.microsoft.com/en-us/library/cc240475.aspx
*/
public class ClientInfoPDU extends OneTimeSwitch {
public static final int INFO_MOUSE = 0x1;
public static final int INFO_DISABLECTRLALTDEL = 0x2;
public static final int INFO_UNICODE = 0x10;
public static final int INFO_MAXIMIZESHELL = 0x20;
public static final int INFO_LOGONNOTIFY = 0x40;
public static final int INFO_ENABLEWINDOWSKEY = 0x100;
public static final int INFO_MOUSE_HAS_WHEEL = 0x00020000;
public static final int INFO_NOAUDIOPLAYBACK = 0x00080000;
public static final int PERF_DISABLE_WALLPAPER = 0x1;
public static final int PERF_DISABLE_FULLWINDOWDRAG = 0x2;
public static final int PERF_DISABLE_MENUANIMATIONS = 0x4;
protected byte[] userName = "".getBytes(RdpConstants.CHARSET_16);
protected byte[] password = "".getBytes(RdpConstants.CHARSET_16); // No effect
protected byte[] alternateShell = "".getBytes(RdpConstants.CHARSET_16);
protected byte[] domain = "".getBytes(RdpConstants.CHARSET_16);
protected byte[] workingDir = "".getBytes(RdpConstants.CHARSET_16);
protected byte[] clientAddress = "192.168.0.100".getBytes(RdpConstants.CHARSET_16);
protected byte[] clientDir = "C:\\Windows\\System32\\mstscax.dll".getBytes(RdpConstants.CHARSET_16);
protected String standardTimeZoneName = "EET, Standard Time";
protected String daylightTimeZoneName = "EET, Summer Time";
protected int standardTimeZoneBias = 0; /* in minutes */
protected int daylightTimeZoneBias = 60; /* in minutes */
public ClientInfoPDU(String id, String userName) {
super(id);
this.userName = userName.getBytes(RdpConstants.CHARSET_16);
}
@Override
protected void handleOneTimeData(ByteBuffer buf, Link link) {
if (buf == null)
return;
throw new RuntimeException("Unexpected packet: " + buf + ".");
}
@Override
protected void onStart() {
super.onStart();
// Length of packet
ByteBuffer buf = new ByteBuffer(1024, true);
// MCS Send Data Request PDU
buf.writeByte(0x64);
// Initiator: 0x03 + 1001 = 1004
buf.writeShort(3);
// Channel ID: 1003
buf.writeShort(1003);
// Data priority: high, segmentation: begin | end (0x40 | 0x20 | 0x10 = 0x70)
buf.writeByte(0x70);
// User data length: (variable length field)
int length = 224 + userName.length + password.length + alternateShell.length + domain.length + workingDir.length + clientAddress.length + clientDir.length;
buf.writeShort(length | 0x8000);
// Flags: SEC_INFO_PKT (0x4000)
buf.writeShort(0x4000);
// TS_SECURITY_HEADER::flagsHi - ignored
buf.writeShort(0x0000);
// Codepage: 0 (UNKNOWN, LE) (use 0x04090409 (1033,1033) for EN_US)
buf.writeIntLE(0x0000);
// Flags
buf.writeIntLE(INFO_MOUSE | INFO_DISABLECTRLALTDEL | INFO_UNICODE |
INFO_MAXIMIZESHELL | INFO_LOGONNOTIFY | INFO_ENABLEWINDOWSKEY |
INFO_MOUSE_HAS_WHEEL | INFO_NOAUDIOPLAYBACK);
//
// Lengths
//
// cbDomain length: 0 bytes (LE) (NOT including size of mandatory NULL terminator)
buf.writeShortLE(domain.length);
// cbUserName length: 16 bytes (0x10, LE) (NOT including size of mandatory NULL terminator)
buf.writeShortLE(userName.length);
// cbPassword length: (LE) (NOT including size of mandatory NULL terminator)
buf.writeShortLE(password.length);
// cbAlternateShell: (LE) (NOT including size of mandatory NULL terminator)
buf.writeShortLE(alternateShell.length);
// cbWorkingDir: (LE) (NOT including size of mandatory NULL terminator)
buf.writeShortLE(workingDir.length);
//
// Values
//
// Domain: (UCS2), see cbDomain
buf.writeBytes(domain);
buf.writeShort(0);
// User name: (UCS2), see cbUserName
buf.writeBytes(userName);
buf.writeShort(0);
// Password: (UCS2), see cbPassword
buf.writeBytes(password);
buf.writeShort(0);
// Alternate shell: (UCS2), see cbAlternateShell
buf.writeBytes(alternateShell);
buf.writeShort(0);
// Working directory: (UCS2), see cbWorkingDir
buf.writeBytes(workingDir);
buf.writeShort(0);
// Client address family: 2 (AF_INET, LE)
buf.writeShortLE(2);
// cbClientAddress: ( LE) (including the size of the mandatory NULL terminator)
buf.writeShortLE(clientAddress.length + 2);
// Client address: (UCS2)
buf.writeBytes(clientAddress);
buf.writeShort(0);
// cbClientDir: 64 bytes (0x40, LE) (including the size of the mandatory NULL terminator)
buf.writeShortLE(clientDir.length + 2);
// Client directory: (UCS2)
buf.writeBytes(clientDir);
buf.writeShort(0);
//
// Client time zone:
//
// Bias: 0 minutes (LE)
buf.writeIntLE(0);
// Standard name: "EET, Standard Time" (fixed string: 64 bytes, UCS2)
buf.writeFixedString(62, standardTimeZoneName, RdpConstants.CHARSET_16);
buf.writeShort(0);
// Standard date
buf.writeBytes(new byte[] {
// wYear: 0 (LE)
(byte)0x00, (byte)0x00,
// wMonth: unknown (LE)
(byte)0x00, (byte)0x00,
// wDayOfWeek: Sunday (LE)
(byte)0x00, (byte)0x00,
// wDay: unknown (LE)
(byte)0x00, (byte)0x00,
// wHour: 0 (LE)
(byte)0x00, (byte)0x00,
// wMinute: 0 (LE)
(byte)0x00, (byte)0x00,
// wSecond: 0 (LE)
(byte)0x00, (byte)0x00,
// wMilliseconds: 0
(byte)0x00, (byte)0x00,
});
// StandardBias: 0 minutes (LE)
buf.writeIntLE(standardTimeZoneBias);
// Daylight name: "EET, Summer Time" (fixed string: 64 bytes, UCS2)
buf.writeFixedString(62, daylightTimeZoneName, RdpConstants.CHARSET_16);
buf.writeShort(0);
// Daylight date
buf.writeBytes(new byte[] {
// wYear: 0 (LE)
(byte)0x00, (byte)0x00,
// wMonth: unknown (LE)
(byte)0x00, (byte)0x00,
// wDayOfWeek: Sunday (LE)
(byte)0x00, (byte)0x00,
// wDay: unknown (LE)
(byte)0x00, (byte)0x00,
// wHour: 0 (LE)
(byte)0x00, (byte)0x00,
// wMinute: 0 (LE)
(byte)0x00, (byte)0x00,
// wSecond: 0 (LE)
(byte)0x00, (byte)0x00,
// wMilliseconds: 0
(byte)0x00, (byte)0x00,
});
// Daylight bias: 60 minutes (LE)
buf.writeIntLE(daylightTimeZoneBias);
// Client session ID: 0x00000000 (LE)
buf.writeIntLE(0);
// Performance flags: 0x7 (LE) = PERF_DISABLE_WALLPAPER (0x1), PERF_DISABLE_FULLWINDOWDRAG (0x2), PERF_DISABLE_MENUANIMATIONS (0x4)
buf.writeIntLE(PERF_DISABLE_WALLPAPER | PERF_DISABLE_FULLWINDOWDRAG | PERF_DISABLE_MENUANIMATIONS);
// cbAutoReconnectCookie: 0 bytes (LE)
buf.writeShortLE(0);
// 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[] {
// TPKT
(byte) 0x03, (byte) 0x00,
// TPKT length: 343 bytes
(byte) 0x01, (byte) 0x57,
// X224 Data PDU
(byte) 0x02, (byte) 0xf0, (byte) 0x80,
// MCS Send Data Request PDU
(byte) 0x64,
// Initiator: 0x03 + 1001 = 1004
(byte) 0x00, (byte) 0x03,
// Channel ID: 1003 (IO Channel)
(byte) 0x03, (byte) 0xeb,
// Data priority: high, segmentation: begin | end (0x40 | 0x20 | 0x10 = 0x70)
(byte) 0x70,
// User data length: 328 (0x148) bytes, variable length field
(byte) 0x81, (byte) 0x48,
// Flags: SEC_INFO_PKT (0x4000)
(byte) 0x40, (byte) 0x00,
// TS_SECURITY_HEADER::flagsHi - ignored
(byte) 0x00, (byte) 0x00,
// Codepage: 0 (UNKNOWN, LE) (use 0x04090409 (1033,1033) for EN_US)
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// Flags: 0xa0173 (LE), INFO_MOUSE (0x1), INFO_DISABLECTRLALTDEL (0x2), INFO_UNICODE (0x10),
// INFO_MAXIMIZESHELL (0x20), INFO_LOGONNOTIFY (0x40), INFO_ENABLEWINDOWSKEY (0x100),
// INFO_MOUSE_HAS_WHEEL (0x00020000), INFO_NOAUDIOPLAYBACK (0x00080000),
(byte) 0x73, (byte) 0x01, (byte) 0x0a, (byte) 0x00,
// Lengths
// cbDomain length: 0 bytes (LE) (NOT including size of mandatory NULL terminator)
(byte) 0x00, (byte) 0x00,
// cbUserName length: 16 bytes (0x10, LE) (NOT including size of mandatory NULL terminator)
(byte) 0x10, (byte) 0x00,
// cbPassword length: 0 bytes (LE) (NOT including size of mandatory NULL terminator)
(byte) 0x00, (byte) 0x00,
// cbAlternateShell: 0 bytes (LE) (NOT including size of mandatory NULL terminator)
(byte) 0x00, (byte) 0x00,
// cbWorkingDir: 0 bytes (LE) (NOT including size of mandatory NULL terminator)
(byte) 0x00, (byte) 0x00,
// Values
// Domain: "" (UCS2), see cbDomain
(byte) 0x00, (byte) 0x00,
// User name: "vlisivka" (UCS2), see cbUserName
(byte) 0x76, (byte) 0x00, (byte) 0x6c, (byte) 0x00, (byte) 0x69, (byte) 0x00, (byte) 0x73, (byte) 0x00,
(byte) 0x69, (byte) 0x00, (byte) 0x76, (byte) 0x00, (byte) 0x6b, (byte) 0x00, (byte) 0x61, (byte) 0x00,
(byte) 0x00, (byte) 0x00,
// Password: "" (UCS2), see cbPassword
(byte) 0x00, (byte) 0x00,
// Alternate shell: "" (UCS2), see cbAlternateShell
(byte) 0x00, (byte) 0x00,
// Working directory: "" (UCS2), see cbWorkingDir
(byte) 0x00, (byte) 0x00,
// Client address family: 2 (AF_INET, LE)
(byte) 0x02, (byte) 0x00,
// cbClientAddress = 28 bytes (0x1c, LE) (including the size of the mandatory NULL terminator)
(byte) 0x1c, (byte) 0x00,
// Client address: "192.168.0.100" (UCS2)
(byte) 0x31, (byte) 0x00, (byte) 0x39, (byte) 0x00, (byte) 0x32, (byte) 0x00, (byte) 0x2e, (byte) 0x00,
(byte) 0x31, (byte) 0x00, (byte) 0x36, (byte) 0x00, (byte) 0x38, (byte) 0x00, (byte) 0x2e, (byte) 0x00,
(byte) 0x30, (byte) 0x00, (byte) 0x2e, (byte) 0x00, (byte) 0x31, (byte) 0x00, (byte) 0x30, (byte) 0x00,
(byte) 0x30, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// cbClientDir: 64 bytes (0x40, LE) (including the size of the mandatory NULL terminator)
(byte) 0x40, (byte) 0x00,
// Client directory: "C:\Windows\System32\mstscax.dll" (UCS2)
(byte) 0x43, (byte) 0x00, (byte) 0x3a, (byte) 0x00, (byte) 0x5c, (byte) 0x00, (byte) 0x57, (byte) 0x00,
(byte) 0x69, (byte) 0x00, (byte) 0x6e, (byte) 0x00, (byte) 0x64, (byte) 0x00, (byte) 0x6f, (byte) 0x00,
(byte) 0x77, (byte) 0x00, (byte) 0x73, (byte) 0x00, (byte) 0x5c, (byte) 0x00, (byte) 0x53, (byte) 0x00,
(byte) 0x79, (byte) 0x00, (byte) 0x73, (byte) 0x00, (byte) 0x74, (byte) 0x00, (byte) 0x65, (byte) 0x00,
(byte) 0x6d, (byte) 0x00, (byte) 0x33, (byte) 0x00, (byte) 0x32, (byte) 0x00, (byte) 0x5c, (byte) 0x00,
(byte) 0x6d, (byte) 0x00, (byte) 0x73, (byte) 0x00, (byte) 0x74, (byte) 0x00, (byte) 0x73, (byte) 0x00,
(byte) 0x63, (byte) 0x00, (byte) 0x61, (byte) 0x00, (byte) 0x78, (byte) 0x00, (byte) 0x2e, (byte) 0x00,
(byte) 0x64, (byte) 0x00, (byte) 0x6c, (byte) 0x00, (byte) 0x6c, (byte) 0x00, (byte) 0x00, (byte) 0x00,
//
// Client time zone:
// Bias: 0 minutes (LE)
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// Standard name: "EET, Standard Time" (fixed string: 64 bytes, UCS2)
(byte) 0x45, (byte) 0x00, (byte) 0x45, (byte) 0x00, (byte) 0x54, (byte) 0x00, (byte) 0x2c, (byte) 0x00,
(byte) 0x20, (byte) 0x00, (byte) 0x53, (byte) 0x00, (byte) 0x74, (byte) 0x00, (byte) 0x61, (byte) 0x00,
(byte) 0x6e, (byte) 0x00, (byte) 0x64, (byte) 0x00, (byte) 0x61, (byte) 0x00, (byte) 0x72, (byte) 0x00,
(byte) 0x64, (byte) 0x00, (byte) 0x20, (byte) 0x00, (byte) 0x54, (byte) 0x00, (byte) 0x69, (byte) 0x00,
(byte) 0x6d, (byte) 0x00, (byte) 0x65, (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) 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,
//
// Standard date
// wYear: 0 (LE)
(byte) 0x00, (byte) 0x00,
// wMonth: unknown (LE)
(byte) 0x00, (byte) 0x00,
// wDayOfWeek: Sunday (LE)
(byte) 0x00, (byte) 0x00,
// wDay: unknown (LE)
(byte) 0x00, (byte) 0x00,
// wHour: 0 (LE)
(byte) 0x00, (byte) 0x00,
// wMinute: 0 (LE)
(byte) 0x00, (byte) 0x00,
// wSecond: 0 (LE)
(byte) 0x00, (byte) 0x00,
// wMilliseconds: 0
(byte) 0x00, (byte) 0x00,
// StandardBias: 0 minutes (LE)
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// Daylight name: "EET, Summer Time" (fixed string: 64 bytes, UCS2)
(byte) 0x45, (byte) 0x00, (byte) 0x45, (byte) 0x00, (byte) 0x54, (byte) 0x00, (byte) 0x2c, (byte) 0x00,
(byte) 0x20, (byte) 0x00, (byte) 0x53, (byte) 0x00, (byte) 0x75, (byte) 0x00, (byte) 0x6d, (byte) 0x00,
(byte) 0x6d, (byte) 0x00, (byte) 0x65, (byte) 0x00, (byte) 0x72, (byte) 0x00, (byte) 0x20, (byte) 0x00,
(byte) 0x54, (byte) 0x00, (byte) 0x69, (byte) 0x00, (byte) 0x6d, (byte) 0x00, (byte) 0x65, (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) 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) 0x00,
// Daylight date
// wYear: 0 (LE)
(byte) 0x00, (byte) 0x00,
// wMonth: unknown (LE)
(byte) 0x00, (byte) 0x00,
// wDayOfWeek: Sunday (LE)
(byte) 0x00, (byte) 0x00,
// wDay: unknown (LE)
(byte) 0x00, (byte) 0x00,
// wHour: 0 (LE)
(byte) 0x00, (byte) 0x00,
// wMinute: 0 (LE)
(byte) 0x00, (byte) 0x00,
// wSecond: 0 (LE)
(byte) 0x00, (byte) 0x00,
// wMilliseconds: 0
(byte) 0x00, (byte) 0x00,
// Daylight bias: 60 minutes (LE)
(byte) 0x3c, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// Client session ID: 0x00000000 (LE)
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// Performance flags: 0x7 (LE) = PERF_DISABLE_WALLPAPER (0x1), PERF_DISABLE_FULLWINDOWDRAG (0x2), PERF_DISABLE_MENUANIMATIONS (0x4)
(byte) 0x07, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// cbAutoReconnectCookie: 0 bytes (LE)
(byte) 0x00, (byte) 0x00,
};
/* @formatter:on */
MockSource source = new MockSource("source", ByteBuffer.convertByteArraysToByteBuffers(new byte[] {1, 2, 3}));
Element client_info = new ClientInfoPDU("client_info", "vlisivka");
Element x224 = new ClientX224DataPDU("x224");
Element tpkt = new ClientTpkt("tpkt");
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, client_info, x224, tpkt, sink, mainSink);
pipeline.link("source", "client_info", "mainSink");
pipeline.link("client_info >" + OTOUT, "x224", "tpkt", "sink");
pipeline.runMainLoop("source", STDOUT, false, false);
}
}

View File

@ -14,16 +14,16 @@
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package rdpclient;
package rdpclient.rdp;
import streamer.ByteBuffer;
import streamer.Element;
import streamer.Link;
import streamer.MockSink;
import streamer.MockSource;
import streamer.OneTimeSwitch;
import streamer.Pipeline;
import streamer.PipelineImpl;
import streamer.debug.MockSink;
import streamer.debug.MockSource;
/**
* @see http://msdn.microsoft.com/en-us/library/cc240684.aspx
@ -65,30 +65,30 @@ public class ClientMCSAttachUserRequest extends OneTimeSwitch {
// System.setProperty("streamer.Pipeline.debug", "true");
/* @formatter:off */
byte[] packet = new byte[] {
byte[] packet = new byte[] {
0x03, 0x00, 0x00, 0x08, // TPKT Header (length = 8 bytes)
0x02, (byte) 0xf0, (byte) 0x80, // X.224 Data TPDU
0x03, 0x00, 0x00, 0x08, // TPKT Header (length = 8 bytes)
0x02, (byte) 0xf0, (byte) 0x80, // X.224 Data TPDU
// PER encoded (ALIGNED variant of BASIC-PER) PDU contents:
0x28,
// PER encoded (ALIGNED variant of BASIC-PER) PDU contents:
0x28,
// 0x28:
// 0 - --\
// 0 - |
// 1 - | CHOICE: From DomainMCSPDU select attachUserRequest (10)
// 0 - | of type AttachUserRequest
// 1 - |
// 0 - --/
// 0 - padding
// 0 - padding
// 0x28:
// 0 - --\
// 0 - |
// 1 - | CHOICE: From DomainMCSPDU select attachUserRequest (10)
// 0 - | of type AttachUserRequest
// 1 - |
// 0 - --/
// 0 - padding
// 0 - padding
};
/* @formatter:on */
};
/* @formatter:on */
MockSource source = new MockSource("source", ByteBuffer.convertByteArraysToByteBuffers(new byte[] {1, 2, 3}));
Element todo = new ClientMCSAttachUserRequest("TODO");
Element x224 = new ClientX224DataPdu("x224");
Element x224 = new ClientX224DataPDU("x224");
Element tpkt = new ClientTpkt("tpkt");
Element sink = new MockSink("sink", ByteBuffer.convertByteArraysToByteBuffers(packet));
Element mainSink = new MockSink("mainSink", ByteBuffer.convertByteArraysToByteBuffers(new byte[] {1, 2, 3}));

View File

@ -14,16 +14,16 @@
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package rdpclient;
package rdpclient.rdp;
import streamer.ByteBuffer;
import streamer.Element;
import streamer.Link;
import streamer.MockSink;
import streamer.MockSource;
import streamer.OneTimeSwitch;
import streamer.Pipeline;
import streamer.PipelineImpl;
import streamer.debug.MockSink;
import streamer.debug.MockSource;
/**
* The MCS Channel Join Request PDUs are sent sequentially. The first PDU is
@ -60,13 +60,13 @@ public class ClientMCSChannelJoinRequestServerMCSChannelConfirmPDUs extends OneT
// int flags = typeAndFlags & 0x3;
if (type != MCS_CHANNEL_CONFIRM_PDU)
throw new RuntimeException("[" + this + "] ERROR: Incorrect type of MCS AttachUserConfirm PDU. Expected value: 15, actual value: " + type + ", data: " + buf +
".");
throw new RuntimeException("[" + this + "] ERROR: Incorrect type of MCS AttachUserConfirm PDU. Expected value: 15, actual value: " + type + ", data: " + buf + ".");
int rtSuccess = buf.readUnsignedByte() >> 4;
if (rtSuccess != 0)
throw new RuntimeException("[" + this + "] ERROR: Cannot connect to channel: request failed. Error code: " + rtSuccess + ", channel ID: " +
channels[channelRequestsSent - 1] + ", data: " + buf + ".");
throw new RuntimeException("[" + this + "] ERROR: Cannot connect to channel: request failed. Error code: " + rtSuccess + ", channel ID: "
+ channels[channelRequestsSent - 1]
+ ", data: " + buf + ".");
// Initiator and requested fields MAY be ignored, however, the channelId
// field MUST be examined. If the value of the channelId field does not
@ -84,8 +84,8 @@ public class ClientMCSChannelJoinRequestServerMCSChannelConfirmPDUs extends OneT
// Actual channel
int actualChannel = buf.readUnsignedShort();
if (actualChannel != channels[channelRequestsSent - 1])
throw new RuntimeException("Unexpeceted channeld ID returned. Expected channeld ID: " + channels[channelRequestsSent - 1] + ", actual channel ID: " +
actualChannel + ", data: " + buf + ".");
throw new RuntimeException("Unexpeceted channeld ID returned. Expected channeld ID: " + channels[channelRequestsSent - 1] + ", actual channel ID: "
+ actualChannel + ", data: " + buf + ".");
state.channelJoined(actualChannel);
@ -111,7 +111,7 @@ public class ClientMCSChannelJoinRequestServerMCSChannelConfirmPDUs extends OneT
buf.writeByte(0x38); // Channel Join request
buf.writeShort(0x03); // ChannelJoinRequest::initiator: 1004
buf.writeShort(state.serverUserChannelId - 1001); // ChannelJoinRequest::initiator: 1004
buf.writeShort(channel);
pushDataToOTOut(buf);
@ -128,86 +128,87 @@ public class ClientMCSChannelJoinRequestServerMCSChannelConfirmPDUs extends OneT
// System.setProperty("streamer.Pipeline.debug", "true");
/* @formatter:off */
byte[] clientRequestPacket = new byte[] {
0x03, 0x00, 0x00, 0x0c, // TPKT Header (length = 12 bytes)
0x02, (byte) 0xf0, (byte) 0x80, // X.224 Data TPDU
byte[] clientRequestPacket = new byte[] {
0x03, 0x00, 0x00, 0x0c, // TPKT Header (length = 12 bytes)
0x02, (byte) 0xf0, (byte) 0x80, // X.224 Data TPDU
// PER encoded (ALIGNED variant of BASIC-PER) PDU contents:
0x38, 0x00, 0x03, 0x03, (byte) 0xef,
// PER encoded (ALIGNED variant of BASIC-PER) PDU contents:
0x38, 0x00, 0x03, 0x03, (byte) 0xef,
// 0x38:
// 0 - --\
// 0 - |
// 1 - | CHOICE: From DomainMCSPDU select channelJoinRequest (14)
// 1 - | of type ChannelJoinRequest
// 1 - |
// 0 - --/
// 0 - padding
// 0 - padding
// 0x38:
// 0 - --\
// 0 - |
// 1 - | CHOICE: From DomainMCSPDU select channelJoinRequest (14)
// 1 - | of type ChannelJoinRequest
// 1 - |
// 0 - --/
// 0 - padding
// 0 - padding
// 0x00:
// 0 - --\
// 0 - |
// 0 - |
// 0 - |
// 0 - |
// 0 - |
// 0 - |
// 0 - |
// | ChannelJoinRequest::initiator = 0x03 + 1001 = 1004
// 0x03: |
// 0 - |
// 0 - |
// 0 - |
// 0 - |
// 0 - |
// 1 - |
// 1 - |
// 0 - --/
// 0x00:
// 0 - --\
// 0 - |
// 0 - |
// 0 - |
// 0 - |
// 0 - |
// 0 - |
// 0 - |
// | ChannelJoinRequest::initiator = 0x03 + 1001 = 1004
// 0x03: |
// 0 - |
// 0 - |
// 0 - |
// 0 - |
// 0 - |
// 1 - |
// 1 - |
// 0 - --/
// 0x03:
// 0 - --\
// 0 - |
// 0 - |
// 0 - |
// 0 - |
// 0 - |
// 1 - |
// 1 - |
// | ChannelJoinRequest::channelId = 0x03ef = 1007
// 0xef: |
// 1 - |
// 1 - |
// 1 - |
// 0 - |
// 1 - |
// 1 - |
// 1 - |
// 1 - --/
};
// 0x03:
// 0 - --\
// 0 - |
// 0 - |
// 0 - |
// 0 - |
// 0 - |
// 1 - |
// 1 - |
// | ChannelJoinRequest::channelId = 0x03ef = 1007
// 0xef: |
// 1 - |
// 1 - |
// 1 - |
// 0 - |
// 1 - |
// 1 - |
// 1 - |
// 1 - --/
};
byte[] serverResponsePacket = new byte[] {
// MCS Channel Confirm
(byte)0x3e,
byte[] serverResponsePacket = new byte[] {
// MCS Channel Confirm
(byte)0x3e,
// result: rt-successful (0)
(byte)0x00,
// result: rt-successful (0)
(byte)0x00,
// Initiator: 1007 (6+1001)
(byte)0x00, (byte)0x06,
// Initiator: 1007 (6+1001)
(byte)0x00, (byte)0x06,
// Requested channel
(byte)0x03, (byte)0xef,
// Requested channel
(byte)0x03, (byte)0xef,
// Actual channel
(byte)0x03, (byte)0xef,
};
/* @formatter:on */
// Actual channel
(byte)0x03, (byte)0xef,
};
/* @formatter:on */
RdpState rdpState = new RdpState();
rdpState.serverUserChannelId = 1004;
MockSource source = new MockSource("source", ByteBuffer.convertByteArraysToByteBuffers(serverResponsePacket, new byte[] {1, 2, 3}));
Element todo = new ClientMCSChannelJoinRequestServerMCSChannelConfirmPDUs("channels", new int[] {1007}, rdpState);
Element x224 = new ClientX224DataPdu("x224");
Element x224 = new ClientX224DataPDU("x224");
Element tpkt = new ClientTpkt("tpkt");
Element sink = new MockSink("sink", ByteBuffer.convertByteArraysToByteBuffers(clientRequestPacket));
Element mainSink = new MockSink("mainSink", ByteBuffer.convertByteArraysToByteBuffers(new byte[] {1, 2, 3}));

View File

@ -0,0 +1,696 @@
// 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.rdp;
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;
public class ClientMCSConnectInitial extends OneTimeSwitch {
public ClientMCSConnectInitial(String id) {
super(id);
}
@Override
protected void handleOneTimeData(ByteBuffer buf, Link link) {
if (buf == null)
return;
throw new RuntimeException("Unexpected packet: " + buf + ".");
}
@Override
protected void onStart() {
super.onStart();
int length = 1024; // Large enough
ByteBuffer buf = new ByteBuffer(length, true);
/* @formatter:off */
buf.writeBytes(new byte[] {
(byte)0x7f, (byte)0x65, (byte)0x82, (byte)0x01, (byte)0x6d, (byte)0x04, (byte)0x01, (byte)0x01, (byte)0x04, (byte)0x01, (byte)0x01, (byte)0x01, (byte)0x01, (byte)0xff, (byte)0x30, (byte)0x1a,
(byte)0x02, (byte)0x01, (byte)0x22, (byte)0x02, (byte)0x01, (byte)0x02, (byte)0x02, (byte)0x01, (byte)0x00, (byte)0x02, (byte)0x01, (byte)0x01, (byte)0x02, (byte)0x01, (byte)0x00, (byte)0x02,
(byte)0x01, (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x00, (byte)0xff, (byte)0xff, (byte)0x02, (byte)0x01, (byte)0x02, (byte)0x30, (byte)0x19, (byte)0x02, (byte)0x01, (byte)0x01, (byte)0x02,
(byte)0x01, (byte)0x01, (byte)0x02, (byte)0x01, (byte)0x01, (byte)0x02, (byte)0x01, (byte)0x01, (byte)0x02, (byte)0x01, (byte)0x00, (byte)0x02, (byte)0x01, (byte)0x01, (byte)0x02, (byte)0x02,
(byte)0x04, (byte)0x20, (byte)0x02, (byte)0x01, (byte)0x02, (byte)0x30, (byte)0x20, (byte)0x02, (byte)0x03, (byte)0x00, (byte)0xff, (byte)0xff, (byte)0x02, (byte)0x03, (byte)0x00, (byte)0xfc,
(byte)0x17, (byte)0x02, (byte)0x03, (byte)0x00, (byte)0xff, (byte)0xff, (byte)0x02, (byte)0x01, (byte)0x01, (byte)0x02, (byte)0x01, (byte)0x00, (byte)0x02, (byte)0x01, (byte)0x01, (byte)0x02,
(byte)0x03, (byte)0x00, (byte)0xff, (byte)0xff, (byte)0x02, (byte)0x01, (byte)0x02, (byte)0x04, (byte)0x82, (byte)0x01, (byte)0x07, (byte)0x00, (byte)0x05, (byte)0x00, (byte)0x14, (byte)0x7c,
(byte)0x00, (byte)0x01, (byte)0x80, (byte)0xfe, (byte)0x00, (byte)0x08, (byte)0x00, (byte)0x10, (byte)0x00, (byte)0x01, (byte)0xc0, (byte)0x00, (byte)0x44, (byte)0x75, (byte)0x63, (byte)0x61,
(byte)0x80, (byte)0xf0, (byte)0x01, (byte)0xc0, (byte)0xd8, (byte)0x00, (byte)0x04, (byte)0x00, (byte)0x08, (byte)0x00, (byte)0x00, (byte)0x04, (byte)0x00, (byte)0x03, (byte)0x01, (byte)0xca,
(byte)0x03, (byte)0xaa, (byte)0x09, (byte)0x04, (byte)0x00, (byte)0x00, (byte)0x28, (byte)0x0a, (byte)0x00, (byte)0x00, (byte)0x61, (byte)0x00, (byte)0x70, (byte)0x00, (byte)0x6f, (byte)0x00,
(byte)0x6c, (byte)0x00, (byte)0x6c, (byte)0x00, (byte)0x6f, (byte)0x00, (byte)0x2e, (byte)0x00, (byte)0x76, (byte)0x00, (byte)0x6c, (byte)0x00, (byte)0x69, (byte)0x00, (byte)0x73, (byte)0x00,
(byte)0x69, (byte)0x00, (byte)0x76, (byte)0x00, (byte)0x6b, (byte)0x00, (byte)0x61, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x04, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x0c, (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)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)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)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)0x00, (byte)0x00, (byte)0x00, (byte)0x01, (byte)0xca, (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x10, (byte)0x00,
(byte)0x07, (byte)0x00, (byte)0x21, (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)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)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)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)0x00, (byte)0x06, (byte)0x00, (byte)0x02, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x04, (byte)0xc0, (byte)0x0c, (byte)0x00, (byte)0x0d, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x02, (byte)0xc0, (byte)0x0c, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x00,
});
//
// buf.writeBytes(new byte[] {
//// - T125: MCSConnect Initial
//// - MCSConnectInitial: Identifier=Generic Conference Control (0.0.20.124.0.1), ConnectPDULength=254
//// - ConnectInitialHeader:
// (byte)0x7F, (byte)0x65,
//// - AsnId: Application Constructed Tag (101)
//// - HighTag:
//// Class: (01......) Application (1)
//// Type: (..1.....) Constructed
//// TagNumber: (...11111)
//// TagValueEnd: 101 (0x65)
// (byte)0x82, (byte)0x01, (byte)0x6C,
//// - AsnLen: Length = 364, LengthOfLength = 2
//// LengthType: LengthOfLength = 2
//// Length: 364 bytes
// (byte)0x04, (byte)0x01, (byte)0x01,
//// - CallingDomainSelector: 0x1
//// - AsnOctetStringHeader:
//// - AsnId: OctetString type (Universal 4)
//// - LowTag:
//// Class: (00......) Universal (0)
//// Type: (..0.....) Primitive
//// TagValue: (...00100) 4
//// - AsnLen: Length = 1, LengthOfLength = 0
//// Length: 1 bytes, LengthOfLength = 0
//// OctetStream: 0x1
// (byte)0x04, (byte)0x01, (byte)0x01,
//// - CalledDomainSelector: 0x1
//// - AsnOctetStringHeader:
//// - AsnId: OctetString type (Universal 4)
//// - LowTag:
//// Class: (00......) Universal (0)
//// Type: (..0.....) Primitive
//// TagValue: (...00100) 4
//// - AsnLen: Length = 1, LengthOfLength = 0
//// Length: 1 bytes, LengthOfLength = 0
//// OctetStream: 0x1
// (byte)0x01, (byte)0x01, (byte)0xFF,
//// - UpwardFlag: True
//// - AsnBooleanHeader:
//// - AsnId: Boolean type (Universal 1)
//// - LowTag:
//// Class: (00......) Universal (0)
//// Type: (..0.....) Primitive
//// TagValue: (...00001) 1
//// - AsnLen: Length = 1, LengthOfLength = 0
//// Length: 1 bytes, LengthOfLength = 0
//// Tf: 255 (0xFF)
//
////
//// - TargetParameters: Length = 26, LengthOfLength = 0
// (byte)0x30, (byte)0x1A,
//// - DomainParametersHeader: 0x1
//// - AsnId: Sequence and SequenceOf types (Universal 16)
//// - LowTag:
//// Class: (00......) Universal (0)
//// Type: (..1.....) Constructed
//// TagValue: (...10000) 16
//// - AsnLen: Length = 26, LengthOfLength = 0
//// Length: 26 bytes, LengthOfLength = 0
// (byte)0x02, (byte)0x01, (byte)0x22,
//// - ChannelIds: 34
//// - AsnIntegerHeader:
//// - AsnId: Integer type (Universal 2)
//// - LowTag:
//// Class: (00......) Universal (0)
//// Type: (..0.....) Primitive
//// TagValue: (...00010) 2
//// - AsnLen: Length = 1, LengthOfLength = 0
//// Length: 1 bytes, LengthOfLength = 0
//// AsnInt: 34 (0x22)
// (byte)0x02, (byte)0x01, (byte)0x02,
//// - UserIDs: 2
//// - AsnIntegerHeader:
//// - AsnId: Integer type (Universal 2)
//// - LowTag:
//// Class: (00......) Universal (0)
//// Type: (..0.....) Primitive
//// TagValue: (...00010) 2
//// - AsnLen: Length = 1, LengthOfLength = 0
//// Length: 1 bytes, LengthOfLength = 0
//// AsnInt: 2 (0x2)
// (byte)0x02, (byte)0x01, (byte)0x00,
//// - TokenIds: 0
//// - AsnIntegerHeader:
//// - AsnId: Integer type (Universal 2)
//// - LowTag:
//// Class: (00......) Universal (0)
//// Type: (..0.....) Primitive
//// TagValue: (...00010) 2
//// - AsnLen: Length = 1, LengthOfLength = 0
//// Length: 1 bytes, LengthOfLength = 0
//// AsnInt: 0 (0x0)
// (byte)0x02, (byte)0x01, (byte)0x01,
//// - NumPriorities: 1
//// - AsnIntegerHeader:
//// - AsnId: Integer type (Universal 2)
//// - LowTag:
//// Class: (00......) Universal (0)
//// Type: (..0.....) Primitive
//// TagValue: (...00010) 2
//// - AsnLen: Length = 1, LengthOfLength = 0
//// Length: 1 bytes, LengthOfLength = 0
//// AsnInt: 1 (0x1)
// (byte)0x02, (byte)0x01, (byte)0x00,
//// - MinThroughput: 0
//// - AsnIntegerHeader:
//// - AsnId: Integer type (Universal 2)
//// - LowTag:
//// Class: (00......) Universal (0)
//// Type: (..0.....) Primitive
//// TagValue: (...00010) 2
//// - AsnLen: Length = 1, LengthOfLength = 0
//// Length: 1 bytes, LengthOfLength = 0
//// AsnInt: 0 (0x0)
// (byte)0x02, (byte)0x01, (byte)0x01,
//// - Height: 1
//// - AsnIntegerHeader:
//// - AsnId: Integer type (Universal 2)
//// - LowTag:
//// Class: (00......) Universal (0)
//// Type: (..0.....) Primitive
//// TagValue: (...00010) 2
//// - AsnLen: Length = 1, LengthOfLength = 0
//// Length: 1 bytes, LengthOfLength = 0
//// AsnInt: 1 (0x1)
// (byte)0x02, (byte)0x03, (byte)0x00, (byte)0xFF, (byte)0xFF,
//// - MCSPDUsize: 65535
//// - AsnIntegerHeader:
//// - AsnId: Integer type (Universal 2)
//// - LowTag:
//// Class: (00......) Universal (0)
//// Type: (..0.....) Primitive
//// TagValue: (...00010) 2
//// - AsnLen: Length = 3, LengthOfLength = 0
//// Length: 3 bytes, LengthOfLength = 0
//// AsnInt: 65535 (0xFFFF)
// (byte)0x02, (byte)0x01, (byte)0x02,
//// - protocolVersion: 2
//// - AsnIntegerHeader:
//// - AsnId: Integer type (Universal 2)
//// - LowTag:
//// Class: (00......) Universal (0)
//// Type: (..0.....) Primitive
//// TagValue: (...00010) 2
//// - AsnLen: Length = 1, LengthOfLength = 0
//// Length: 1 bytes, LengthOfLength = 0
//// AsnInt: 2 (0x2)
//
////
//// - MinimumParameters: Length = 25, LengthOfLength = 0
// (byte)0x30, (byte)0x19,
//// - DomainParametersHeader: 0x1
//// - AsnId: Sequence and SequenceOf types (Universal 16)
//// - LowTag:
//// Class: (00......) Universal (0)
//// Type: (..1.....) Constructed
//// TagValue: (...10000) 16
//// - AsnLen: Length = 25, LengthOfLength = 0
//// Length: 25 bytes, LengthOfLength = 0
// (byte)0x02, (byte)0x01, (byte)0x01,
//// - ChannelIds: 1
//// - AsnIntegerHeader:
//// - AsnId: Integer type (Universal 2)
//// - LowTag:
//// Class: (00......) Universal (0)
//// Type: (..0.....) Primitive
//// TagValue: (...00010) 2
//// - AsnLen: Length = 1, LengthOfLength = 0
//// Length: 1 bytes, LengthOfLength = 0
//// AsnInt: 1 (0x1)
// (byte)0x02, (byte)0x01, (byte)0x01,
//// - UserIDs: 1
//// - AsnIntegerHeader:
//// - AsnId: Integer type (Universal 2)
//// - LowTag:
//// Class: (00......) Universal (0)
//// Type: (..0.....) Primitive
//// TagValue: (...00010) 2
//// - AsnLen: Length = 1, LengthOfLength = 0
//// Length: 1 bytes, LengthOfLength = 0
//// AsnInt: 1 (0x1)
// (byte)0x02, (byte)0x01, (byte)0x01,
//// - TokenIds: 1
//// - AsnIntegerHeader:
//// - AsnId: Integer type (Universal 2)
//// - LowTag:
//// Class: (00......) Universal (0)
//// Type: (..0.....) Primitive
//// TagValue: (...00010) 2
//// - AsnLen: Length = 1, LengthOfLength = 0
//// Length: 1 bytes, LengthOfLength = 0
//// AsnInt: 1 (0x1)
// (byte)0x02, (byte)0x01, (byte)0x01,
//// - NumPriorities: 1
//// - AsnIntegerHeader:
//// - AsnId: Integer type (Universal 2)
//// - LowTag:
//// Class: (00......) Universal (0)
//// Type: (..0.....) Primitive
//// TagValue: (...00010) 2
//// - AsnLen: Length = 1, LengthOfLength = 0
//// Length: 1 bytes, LengthOfLength = 0
//// AsnInt: 1 (0x1)
// (byte)0x02, (byte)0x01, (byte)0x00,
//// - MinThroughput: 0
//// - AsnIntegerHeader:
//// - AsnId: Integer type (Universal 2)
//// - LowTag:
//// Class: (00......) Universal (0)
//// Type: (..0.....) Primitive
//// TagValue: (...00010) 2
//// - AsnLen: Length = 1, LengthOfLength = 0
//// Length: 1 bytes, LengthOfLength = 0
//// AsnInt: 0 (0x0)
// (byte)0x02, (byte)0x01, (byte)0x01,
//// - Height: 1
//// - AsnIntegerHeader:
//// - AsnId: Integer type (Universal 2)
//// - LowTag:
//// Class: (00......) Universal (0)
//// Type: (..0.....) Primitive
//// TagValue: (...00010) 2
//// - AsnLen: Length = 1, LengthOfLength = 0
//// Length: 1 bytes, LengthOfLength = 0
//// AsnInt: 1 (0x1)
// (byte)0x02, (byte)0x02, (byte)0x04, (byte)0x20,
//// - MCSPDUsize: 1056
//// - AsnIntegerHeader:
//// - AsnId: Integer type (Universal 2)
//// - LowTag:
//// Class: (00......) Universal (0)
//// Type: (..0.....) Primitive
//// TagValue: (...00010) 2
//// - AsnLen: Length = 2, LengthOfLength = 0
//// Length: 2 bytes, LengthOfLength = 0
//// AsnInt: 1056 (0x420)
// (byte)0x02, (byte)0x01, (byte)0x02,
//// - protocolVersion: 2
//// - AsnIntegerHeader:
//// - AsnId: Integer type (Universal 2)
//// - LowTag:
//// Class: (00......) Universal (0)
//// Type: (..0.....) Primitive
//// TagValue: (...00010) 2
//// - AsnLen: Length = 1, LengthOfLength = 0
//// Length: 1 bytes, LengthOfLength = 0
//// AsnInt: 2 (0x2)
//// - MaximumParameters: Length = 31, LengthOfLength = 0
//// - DomainParametersHeader: 0x1
// (byte)0x30, (byte)0x1F,
//// - AsnId: Sequence and SequenceOf types (Universal 16)
//// - LowTag:
//// Class: (00......) Universal (0)
//// Type: (..1.....) Constructed
//// TagValue: (...10000) 16
//// - AsnLen: Length = 31, LengthOfLength = 0
//// Length: 31 bytes, LengthOfLength = 0
// (byte)0x02, (byte)0x03, (byte)0x00, (byte)0xFF, (byte)0xFF,
//// - ChannelIds: 65535
//// - AsnIntegerHeader:
//// - AsnId: Integer type (Universal 2)
//// - LowTag:
//// Class: (00......) Universal (0)
//// Type: (..0.....) Primitive
//// TagValue: (...00010) 2
//// - AsnLen: Length = 3, LengthOfLength = 0
//// Length: 3 bytes, LengthOfLength = 0
//// AsnInt: 65535 (0xFFFF)
// (byte)0x02, (byte)0x02, (byte)0xFC, (byte)0x17,
//// - UserIDs: 64535
//// - AsnIntegerHeader:
//// - AsnId: Integer type (Universal 2)
//// - LowTag:
//// Class: (00......) Universal (0)
//// Type: (..0.....) Primitive
//// TagValue: (...00010) 2
//// - AsnLen: Length = 2, LengthOfLength = 0
//// Length: 2 bytes, LengthOfLength = 0
//// AsnInt: 64535 (0xFC17)
// (byte)0x02, (byte)0x03, (byte)0x00, (byte)0xFF, (byte)0xFF,
//// - TokenIds: 65535
//// - AsnIntegerHeader:
//// - AsnId: Integer type (Universal 2)
//// - LowTag:
//// Class: (00......) Universal (0)
//// Type: (..0.....) Primitive
//// TagValue: (...00010) 2
//// - AsnLen: Length = 3, LengthOfLength = 0
//// Length: 3 bytes, LengthOfLength = 0
//// AsnInt: 65535 (0xFFFF)
// (byte)0x02, (byte)0x01, (byte)0x01,
//// - NumPriorities: 1
//// - AsnIntegerHeader:
//// - AsnId: Integer type (Universal 2)
//// - LowTag:
//// Class: (00......) Universal (0)
//// Type: (..0.....) Primitive
//// TagValue: (...00010) 2
//// - AsnLen: Length = 1, LengthOfLength = 0
//// Length: 1 bytes, LengthOfLength = 0
//// AsnInt: 1 (0x1)
// (byte)0x02, (byte)0x01, (byte)0x00,
//// - MinThroughput: 0
//// - AsnIntegerHeader:
//// - AsnId: Integer type (Universal 2)
//// - LowTag:
//// Class: (00......) Universal (0)
//// Type: (..0.....) Primitive
//// TagValue: (...00010) 2
//// - AsnLen: Length = 1, LengthOfLength = 0
//// Length: 1 bytes, LengthOfLength = 0
//// AsnInt: 0 (0x0)
// (byte)0x02, (byte)0x01, (byte)0x01,
//// - Height: 1
//// - AsnIntegerHeader:
//// - AsnId: Integer type (Universal 2)
//// - LowTag:
//// Class: (00......) Universal (0)
//// Type: (..0.....) Primitive
//// TagValue: (...00010) 2
//// - AsnLen: Length = 1, LengthOfLength = 0
//// Length: 1 bytes, LengthOfLength = 0
//// AsnInt: 1 (0x1)
// (byte)0x02, (byte)0x03, (byte)0x00, (byte)0xFF, (byte)0xFF,
//// - MCSPDUsize: 65535
//// - AsnIntegerHeader:
//// - AsnId: Integer type (Universal 2)
//// - LowTag:
//// Class: (00......) Universal (0)
//// Type: (..0.....) Primitive
//// TagValue: (...00010) 2
//// - AsnLen: Length = 3, LengthOfLength = 0
//// Length: 3 bytes, LengthOfLength = 0
//// AsnInt: 65535 (0xFFFF)
// (byte)0x02, (byte)0x01, (byte)0x02,
//// - protocolVersion: 2
//// - AsnIntegerHeader:
//// - AsnId: Integer type (Universal 2)
//// - LowTag:
//// Class: (00......) Universal (0)
//// Type: (..0.....) Primitive
//// TagValue: (...00010) 2
//// - AsnLen: Length = 1, LengthOfLength = 0
//// Length: 1 bytes, LengthOfLength = 0
//// AsnInt: 2 (0x2)
//// - UserData: Identifier=Generic Conference Control (0.0.20.124.0.1), ConnectPDULength=254
//// - UserDataHeader:
// (byte)0x04, (byte)0x82, (byte)0x01, (byte)0x07,
//// - AsnId: OctetString type (Universal 4)
//// - LowTag:
//// Class: (00......) Universal (0)
//// Type: (..0.....) Primitive
//// TagValue: (...00100) 4
//// - AsnLen: Length = 263, LengthOfLength = 2
//// LengthType: LengthOfLength = 2
//// Length: 263 bytes
// (byte)0x00, (byte)0x05, (byte)0x00, (byte)0x14, (byte)0x7C, (byte)0x00, (byte)0x01,
//// - AsnBerObjectIdentifier: Generic Conference Contro (0.0.20.124.0.1)
//// - AsnObjectIdentifierHeader:
//// - AsnId: Reserved for use by the encoding rules (Universal 0)
//// - LowTag:
//// Class: (00......) Universal (0)
//// Type: (..0.....) Primitive
//// TagValue: (...00000) 0
//// - AsnLen: Length = 5, LengthOfLength = 0
//// Length: 5 bytes, LengthOfLength = 0
//// First: 0 (0x0)
//// Final: 20 (0x14)
//// Final: 124 (0x7C)
//// Final: 0 (0x0)
//// Final: 1 (0x1)
// (byte)0x80, (byte)0xFE,
//// - ConnectPDULength: 254
//// Align: No Padding
//// Length: 254
// (byte)0x00, (byte)0x08, (byte)0x00, (byte)0x10,
//// - ConnectGCCPDU: conferenceCreateRequest
//// ExtensionBit: 0 (0x0)
//// - ChoiceValue: conferenceCreateRequest
//// Value: (000.....) 0x0
//// - conferenceCreateRequest:
//// ExtensionBit: 0 (0x0)
//// convenerPasswordPresent: 0 (0x0)
//// passwordPresent: 0 (0x0)
//// conductorPrivilegesPresent: 0 (0x0)
//// conductedPrivilegesPresent: 0 (0x0)
//// nonConductedPrivilegesPresent: 0 (0x0)
//// conferenceDescriptionPresent: 0 (0x0)
//// callerIdentifierPresent: 0 (0x0)
//// userDataPresent: 1 (0x1)
//// - conferenceName:
//// ExtensionBit: 0 (0x0)
//// textPresent: 0 (0x0)
//// - numeric: 1
//// - SimpleNumericString: 1
//// - NumericString: 1
//// - Align: No Padding
//// Padding1: (0.......) 0x0
//// - Length: 1
//// Value: (00000000) 0x0
//// - Restrictedstr: 1
//// FourBits: (0001....) 0x1
//// - lockedConference: False
//// Value: False 0.......
//// - listedConference: False
//// Value: False 0.......
//// - conductibleConference: False
//// Value: False 0.......
//// - TerminationMethod: automatic
//// ExtensionBit: 0 (0x0)
//// - RootIndex: 0
//// Value: (0.......) 0x0
//// - userData:
// (byte)0x00, (byte)0x01,
//// - Size: 1
//// - Align: No Padding
//// Padding7: (0000000.) 0x0
//// Length: 1
//// - UserData: 0x44756361
// (byte)0xC0, (byte)0x00, (byte)0x44, (byte)0x75, (byte)0x63, (byte)0x61,
//// valuePresent: 1 (0x1)
//// - key: h221NonStandard "Duca"
//// - ChoiceValue: h221NonStandard
//// Value: (1.......) 0x1
//// - h221NonStandard:
//// - H221NonStandardIdentifier: length: 4
//// - ConstrainedLength: 4
//// Value: (00000000) 0x0
//// - Align: No Padding
//// Padding6: (000000..) 0x0
//// Value: Binary Large Object (4 Bytes) "Duca"
//// - ClientMcsConnectInitialPdu:
// (byte)0x80, (byte)0xF0,
//// - RDPGCCUserDataRequestLength: 240
//// Align: No Padding
//// Length: 240
//// - TsUd: CS_CORE
// (byte)0x01, (byte)0xC0, (byte)0xD8, (byte)0x00,
//// - TsUdHeader: Type = CS_CORE, Length = 216
//// Type: CS_CORE
//// Length: 216 (0xD8)
//// - TsUdCsCore:
// (byte)0x04, (byte)0x00, (byte)0x08, (byte)0x00,
//// Version: RDP 5.0, 5.1, 5.2, 6.0, 6.1, and 7.0
// (byte)0x00, (byte)0x04,
//// DesktopWidth: 1024 (0x400)
// (byte)0x00, (byte)0x03,
//// DesktopHeight: 768 (0x300)
// (byte)0x01, (byte)0xCA,
//// ColorDepth: 8 bpp
// (byte)0x03, (byte)0xAA,
//// SASSequence: 0xaa03, SHOULD be set to RNS_UD_SAS_DEL(0xAA03)
// (byte)0x09, (byte)0x04, (byte)0x00, (byte)0x00,
//// KeyboardLayout: Language: English, Location: United States
// (byte)0x28, (byte)0x0A, (byte)0x00, (byte)0x00,
//// ClientBuild: 2600 (0xA28)
// (byte)0x61, (byte)0x00, (byte)0x70, (byte)0x00, (byte)0x6F, (byte)0x00, (byte)0x6C, (byte)0x00, (byte)0x6C, (byte)0x00, (byte)0x6F, (byte)0x00, (byte)0x33, (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)0x00, (byte)0x00, (byte)0x00,
//// ClientName: apollo3
// (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
//// KeyboardType: Undefined value: 0
// (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
//// KeyboardSubType: 0 (0x0)
// (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
//// KeyboardFunctionKey: 0 (0x0)
// (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)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)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)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,
//// ImeFileName:
// (byte)0x01, (byte)0xCA,
//// PostBeta2ColorDepth: 8 bpp
// (byte)0x01, (byte)0x00,
//// ClientProductId: 0x1, SHOULD be set to initialized to 1
// (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
//// SerialNumber: 0x0, SHOULD be set to 0
// (byte)0x10, (byte)0x00,
//// HighColorDepth: 16-bit 565 RGB
// (byte)0x07, (byte)0x00,
//// - SupportedColorDepth: 7 (0x7)
//// Support24BPP: (...............1) Support 24BPP
//// Support16BPP: (..............1.) Support 16BPP
//// Support15BPP: (.............1..) Support 15BPP
//// Support32BPP: (............0...) Not Support 32BPP
//// Reserved: (000000000000....)
// (byte)0x01, (byte)0x00,
//// - EarlyCapabilityFlags: 1 (0x1)
//// SupportSetErrorPdu: (...............1) Indicates that the client supports the Set Error Info PDU
//// Want32BppSession: (..............0.) Client is not requesting 32BPP session
//// SupportStatusInfoPdu: (.............0..) Client not supports the Server Status Info PDU
//// StrongAsymmetricKeys: (............0...) Not support asymmetric keys larger than 512-bits
//// Unused: (...........0....)
//// ValidConnection: (..........0.....) Not Indicates ConnectionType field contains valid data
//// SupportMonitorLayoutPdu: (.........0......) Not Indicates that the client supports the Monitor Layout PDU
//// Unused2: (000000000.......)
// (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)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)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)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,
//// ClientDigProductId:
//(byte)0x00,
//// connectionType: invalid connection type
//(byte)0x00,
//// pad1octet: 0 (0x0)
//(byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00,
//// ServerSelectedProtocols: TLS 1.0
////
//// - TsUd: CS_CLUSTER
//// - TsUdHeader: Type = CS_CLUSTER, Length = 12
//(byte)0x04, (byte)0xC0,
//// Type: CS_CLUSTER
//(byte)0x0C, (byte)0x00,
//// Length: 12 (0xC)
//(byte)0x0D, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
//// - TsUdCsCluster:
//// - Flags: 13 (0xD)
//// RedirectedSupported: (...............................1) Support Redirected
//// SessionIDFieldValid: (..............................0.) SessionID Field not Valid
//// SupportedVersion: (..........................0011..) REDIRECTION_VERSION4
//// RedirectedSmartcard: (.........................0......) Not Logon with Smartcard
//// Unused: (0000000000000000000000000.......)
//// RedirectedSessionID: 0 (0x0)
////
//// - TsUd: CS_SECURITY
//// - TsUdHeader: Type = CS_SECURITY, Length = 12
//(byte)0x02, (byte)0xC0,
//// Type: CS_SECURITY
//(byte)0x0C, (byte)0x00,
//// Length: 12 (0xC)
////
//// - TsUdCsSec:
//(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
//// - EncryptionMethod:
//// Support40Bit: (...............................0) Not Support
//// Support128Bit: (..............................0.) Not Support 128-bit
//// Reserved1: (.............................0..)
//// Support56Bit: (............................0...) Not Support 56-bit
//// SupportFIPS: (...........................0....) Not Support FIPS Compliant
//// Reserved2: (000000000000000000000000000.....)
//(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
//// - ExtEncryptionMethod:
//// Support40Bit: (...............................0) Not Support
//// Support128Bit: (..............................0.) Not Support 128-bit
//// Reserved1: (.............................0..)
//// Support56Bit: (............................0...) Not Support 56-bit
//// SupportFIPS: (...........................0....) Not Support FIPS Compliant
//// Reserved2: (000000000000000000000000000.....)
// });
/* @formatter:on */
buf.trimAtCursor();
pushDataToOTOut(buf);
switchOff();
}
/**
* Example.
*
* @see http://msdn.microsoft.com/en-us/library/cc240836.aspx
*/
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[] {
// TPKT: TPKT version = 3
(byte) 0x03, (byte) 0x00,
// TPKT: Packet length: 378 bytes
(byte) 0x01, (byte) 0x78,
// X.224: Length indicator = 2
(byte) 0x02,
// X.224: Type: Data TPDU
(byte) 0xf0,
// X.224: EOT
(byte) 0x80,
// Captured packet
(byte)0x7f, (byte)0x65, (byte)0x82, (byte)0x01, (byte)0x6c, (byte)0x04, (byte)0x01, (byte)0x01, (byte)0x04,
(byte)0x01, (byte)0x01, (byte)0x01, (byte)0x01, (byte)0xff, (byte)0x30, (byte)0x1a, (byte)0x02, (byte)0x01, (byte)0x22, (byte)0x02, (byte)0x01, (byte)0x02, (byte)0x02, (byte)0x01, (byte)0x00,
(byte)0x02, (byte)0x01, (byte)0x01, (byte)0x02, (byte)0x01, (byte)0x00, (byte)0x02, (byte)0x01, (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x00, (byte)0xff, (byte)0xff, (byte)0x02, (byte)0x01,
(byte)0x02, (byte)0x30, (byte)0x19, (byte)0x02, (byte)0x01, (byte)0x01, (byte)0x02, (byte)0x01, (byte)0x01, (byte)0x02, (byte)0x01, (byte)0x01, (byte)0x02, (byte)0x01, (byte)0x01, (byte)0x02,
(byte)0x01, (byte)0x00, (byte)0x02, (byte)0x01, (byte)0x01, (byte)0x02, (byte)0x02, (byte)0x04, (byte)0x20, (byte)0x02, (byte)0x01, (byte)0x02, (byte)0x30, (byte)0x1f, (byte)0x02, (byte)0x03,
(byte)0x00, (byte)0xff, (byte)0xff, (byte)0x02, (byte)0x02, (byte)0xfc, (byte)0x17, (byte)0x02, (byte)0x03, (byte)0x00, (byte)0xff, (byte)0xff, (byte)0x02, (byte)0x01, (byte)0x01, (byte)0x02,
(byte)0x01, (byte)0x00, (byte)0x02, (byte)0x01, (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x00, (byte)0xff, (byte)0xff, (byte)0x02, (byte)0x01, (byte)0x02, (byte)0x04, (byte)0x82, (byte)0x01,
(byte)0x07, (byte)0x00, (byte)0x05, (byte)0x00, (byte)0x14, (byte)0x7c, (byte)0x00, (byte)0x01, (byte)0x80, (byte)0xfe, (byte)0x00, (byte)0x08, (byte)0x00, (byte)0x10, (byte)0x00, (byte)0x01,
(byte)0xc0, (byte)0x00, (byte)0x44, (byte)0x75, (byte)0x63, (byte)0x61, (byte)0x80, (byte)0xf0, (byte)0x01, (byte)0xc0, (byte)0xd8, (byte)0x00, (byte)0x04, (byte)0x00, (byte)0x08, (byte)0x00,
(byte)0x00, (byte)0x04, (byte)0x00, (byte)0x03, (byte)0x01, (byte)0xca, (byte)0x03, (byte)0xaa, (byte)0x09, (byte)0x04, (byte)0x00, (byte)0x00, (byte)0x28, (byte)0x0a, (byte)0x00, (byte)0x00,
(byte)0x61, (byte)0x00, (byte)0x70, (byte)0x00, (byte)0x6f, (byte)0x00, (byte)0x6c, (byte)0x00, (byte)0x6c, (byte)0x00, (byte)0x6f, (byte)0x00, (byte)0x33, (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)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)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)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)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)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)0x01, (byte)0xca, (byte)0x01, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x10, (byte)0x00, (byte)0x07, (byte)0x00, (byte)0x01, (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)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)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)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)0x00, (byte)0x00, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x04, (byte)0xc0, (byte)0x0c, (byte)0x00, (byte)0x0d, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x02, (byte)0xc0, (byte)0x0c, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
};
/* @formatter:on */
MockSource source = new MockSource("source", ByteBuffer.convertByteArraysToByteBuffers(new byte[] {1, 2, 3}));
Element todo = new ClientMCSConnectInitial("ClientMCSConnectInitial");
Element x224 = new ClientX224DataPDU("x224");
Element tpkt = new ClientTpkt("tpkt");
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, todo, x224, tpkt, sink, mainSink);
pipeline.link("source", "ClientMCSConnectInitial", "mainSink");
pipeline.link("ClientMCSConnectInitial >" + OTOUT, "x224", "tpkt", "sink");
pipeline.runMainLoop("source", STDOUT, false, false);
}
}

View File

@ -14,16 +14,16 @@
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package rdpclient;
package rdpclient.rdp;
import streamer.ByteBuffer;
import streamer.Element;
import streamer.Link;
import streamer.MockSink;
import streamer.MockSource;
import streamer.OneTimeSwitch;
import streamer.Pipeline;
import streamer.PipelineImpl;
import streamer.debug.MockSink;
import streamer.debug.MockSource;
/**
* @see http://msdn.microsoft.com/en-us/library/cc240683.aspx
@ -74,71 +74,71 @@ public class ClientMCSErectDomainRequest extends OneTimeSwitch {
// System.setProperty("streamer.Pipeline.debug", "true");
/* @formatter:off */
byte[] packet = new byte[] {
byte[] packet = new byte[] {
0x03, 0x00, 0x00, 0x0c, // TPKT Header (length = 12 bytes)
0x02, (byte) 0xf0, (byte) 0x80, // X.224 Data TPDU
0x03, 0x00, 0x00, 0x0c, // TPKT Header (length = 12 bytes)
0x02, (byte) 0xf0, (byte) 0x80, // X.224 Data TPDU
// PER encoded (ALIGNED variant of BASIC-PER) PDU contents:
0x04, 0x01, 0x00, 0x01, 0x00,
// PER encoded (ALIGNED variant of BASIC-PER) PDU contents:
0x04, 0x01, 0x00, 0x01, 0x00,
// 0x04:
// 0 - --\
// 0 - |
// 0 - | CHOICE: From DomainMCSPDU select erectDomainRequest (1)
// 0 - | of type ErectDomainRequest
// 0 - |
// 1 - --/
// 0 - padding
// 0 - padding
// 0x04:
// 0 - --\
// 0 - |
// 0 - | CHOICE: From DomainMCSPDU select erectDomainRequest (1)
// 0 - | of type ErectDomainRequest
// 0 - |
// 1 - --/
// 0 - padding
// 0 - padding
// 0x01:
// 0 - --\
// 0 - |
// 0 - |
// 0 - | ErectDomainRequest::subHeight length = 1 byte
// 0 - |
// 0 - |
// 0 - |
// 1 - --/
// 0x01:
// 0 - --\
// 0 - |
// 0 - |
// 0 - | ErectDomainRequest::subHeight length = 1 byte
// 0 - |
// 0 - |
// 0 - |
// 1 - --/
// 0x00:
// 0 - --\
// 0 - |
// 0 - |
// 0 - | ErectDomainRequest::subHeight = 0
// 0 - |
// 0 - |
// 0 - |
// 0 - --/
// 0x00:
// 0 - --\
// 0 - |
// 0 - |
// 0 - | ErectDomainRequest::subHeight = 0
// 0 - |
// 0 - |
// 0 - |
// 0 - --/
// 0x01:
// 0 - --\
// 0 - |
// 0 - |
// 0 - | ErectDomainRequest::subInterval length = 1 byte
// 0 - |
// 0 - |
// 0 - |
// 1 - --/
// 0x01:
// 0 - --\
// 0 - |
// 0 - |
// 0 - | ErectDomainRequest::subInterval length = 1 byte
// 0 - |
// 0 - |
// 0 - |
// 1 - --/
// 0x00:
// 0 - --\
// 0 - |
// 0 - |
// 0 - | ErectDomainRequest::subInterval = 0
// 0 - |
// 0 - |
// 0 - |
// 0 - --/
// 0x00:
// 0 - --\
// 0 - |
// 0 - |
// 0 - | ErectDomainRequest::subInterval = 0
// 0 - |
// 0 - |
// 0 - |
// 0 - --/
};
/* @formatter:on */
};
/* @formatter:on */
MockSource source = new MockSource("source", ByteBuffer.convertByteArraysToByteBuffers(new byte[] {1, 2, 3}));
Element todo = new ClientMCSErectDomainRequest("TODO");
Element x224 = new ClientX224DataPdu("x224");
Element x224 = new ClientX224DataPDU("x224");
Element tpkt = new ClientTpkt("tpkt");
Element sink = new MockSink("sink", ByteBuffer.convertByteArraysToByteBuffers(packet));
Element mainSink = new MockSink("mainSink", ByteBuffer.convertByteArraysToByteBuffers(new byte[] {1, 2, 3}));

View File

@ -14,16 +14,16 @@
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package rdpclient;
package rdpclient.rdp;
import streamer.ByteBuffer;
import streamer.Element;
import streamer.Link;
import streamer.MockSink;
import streamer.MockSource;
import streamer.OneTimeSwitch;
import streamer.Pipeline;
import streamer.PipelineImpl;
import streamer.debug.MockSink;
import streamer.debug.MockSource;
/**
* @see http://msdn.microsoft.com/en-us/library/cc240489.aspx
@ -50,46 +50,46 @@ public class ClientSynchronizePDU extends OneTimeSwitch {
ByteBuffer buf = new ByteBuffer(length, true);
/* @formatter:off */
buf.writeBytes(new byte[] {
// MCS send data request
(byte)0x64,
// Initiator: 1004 (1001+3)
(byte)0x00, (byte)0x03,
// Channel ID: 1003 (I/O Channel)
(byte)0x03, (byte)0xeb,
// Data priority: high (0x40), segmentation: begin (0x20) | end (0x10)
(byte)0x70,
// Data length: 22 bytes (0x16, variable length field)
(byte)0x80, (byte)0x16,
buf.writeBytes(new byte[] {
// MCS send data request
(byte)0x64,
// Initiator: 1004 (1001+3)
(byte)0x00, (byte)0x03,
// Channel ID: 1003 (I/O Channel)
(byte)0x03, (byte)0xeb,
// Data priority: high (0x40), segmentation: begin (0x20) | end (0x10)
(byte)0x70,
// Data length: 22 bytes (0x16, variable length field)
(byte)0x80, (byte)0x16,
// RDP: total length: 22 bytes (LE)
(byte)0x16, (byte)0x00,
// RDP: total length: 22 bytes (LE)
(byte)0x16, (byte)0x00,
// PDU type: PDUTYPE_DATAPDU (0x7), TS_PROTOCOL_VERSION (0x10) (LE)
(byte)0x17, (byte)0x00,
// PDU type: PDUTYPE_DATAPDU (0x7), TS_PROTOCOL_VERSION (0x10) (LE)
(byte)0x17, (byte)0x00,
// PDU source: 1007 (LE)
(byte)0xec, (byte)0x03,
// Share ID: 0x000103ea (LE)
(byte)0xea, (byte)0x03, (byte)0x01, (byte)0x00,
// Padding: 1 byte
(byte)0x00,
// Stream ID: STREAM_LOW (1)
(byte)0x01,
// uncompressedLength : 8 bytes (LE)
(byte)0x08, (byte)0x00,
// pduType2 = PDUTYPE2_SYNCHRONIZE (31)
(byte)0x1f,
// generalCompressedType: 0
(byte)0x00,
// generalCompressedLength: 0 (LE?)
(byte)0x00, (byte)0x00,
// messageType: SYNCMSGTYPE_SYNC (1) (LE)
(byte)0x01, (byte)0x00,
// targetUser: 0x03ea
(byte)0xea, (byte)0x03,
});
/* @formatter:on */
// PDU source: 1007 (LE)
(byte)0xec, (byte)0x03,
// Share ID: 0x000103ea (LE)
(byte)0xea, (byte)0x03, (byte)0x01, (byte)0x00,
// Padding: 1 byte
(byte)0x00,
// Stream ID: STREAM_LOW (1)
(byte)0x01,
// uncompressedLength : 8 bytes (LE)
(byte)0x08, (byte)0x00,
// pduType2 = PDUTYPE2_SYNCHRONIZE (31)
(byte)0x1f,
// generalCompressedType: 0
(byte)0x00,
// generalCompressedLength: 0 (LE?)
(byte)0x00, (byte)0x00,
// messageType: SYNCMSGTYPE_SYNC (1) (LE)
(byte)0x01, (byte)0x00,
// targetUser: 0x03ea
(byte)0xea, (byte)0x03,
});
/* @formatter:on */
// Trim buffer to actual length of data written
buf.trimAtCursor();
@ -110,56 +110,56 @@ public class ClientSynchronizePDU extends OneTimeSwitch {
// System.setProperty("streamer.Pipeline.debug", "true");
/* @formatter:off */
byte[] packet = new byte[] {
// TPKT
(byte)0x03, (byte)0x00,
// TPKT length: 37 bytes
(byte)0x00, (byte)0x25,
// X224 Data PDU
(byte)0x02, (byte)0xf0, (byte)0x80,
byte[] packet = new byte[] {
// TPKT
(byte)0x03, (byte)0x00,
// TPKT length: 37 bytes
(byte)0x00, (byte)0x25,
// X224 Data PDU
(byte)0x02, (byte)0xf0, (byte)0x80,
// MCS send data request
(byte)0x64,
// Initiator: 1004 (1001+3)
(byte)0x00, (byte)0x03,
// Channel ID: 1003 (I/O Channel)
(byte)0x03, (byte)0xeb,
// Data priority: high (0x40), segmentation: begin (0x20) | end (0x10)
(byte)0x70,
// Data length: 22 bytes (0x16, variable length field)
(byte)0x80, (byte)0x16,
// MCS send data request
(byte)0x64,
// Initiator: 1004 (1001+3)
(byte)0x00, (byte)0x03,
// Channel ID: 1003 (I/O Channel)
(byte)0x03, (byte)0xeb,
// Data priority: high (0x40), segmentation: begin (0x20) | end (0x10)
(byte)0x70,
// Data length: 22 bytes (0x16, variable length field)
(byte)0x80, (byte)0x16,
// RDP: total length: 22 bytes (LE)
(byte)0x16, (byte)0x00,
// PDU type: PDUTYPE_DATAPDU (0x7), TS_PROTOCOL_VERSION (0x10) (LE)
(byte)0x17, (byte)0x00,
// PDU source: 1007 (LE)
(byte)0xec, (byte)0x03,
// Share ID: 0x000103ea (LE)
(byte)0xea, (byte)0x03, (byte)0x01, (byte)0x00,
// Padding: 1 byte
(byte)0x00,
// Stream ID: STREAM_LOW (1)
(byte)0x01,
// uncompressedLength : 8 bytes (LE)
(byte)0x08, (byte)0x00,
// pduType2 = PDUTYPE2_SYNCHRONIZE (31)
(byte)0x1f,
// generalCompressedType: 0
(byte)0x00,
// generalCompressedLength: 0 (LE?)
(byte)0x00, (byte)0x00,
// messageType: SYNCMSGTYPE_SYNC (1) (LE)
(byte)0x01, (byte)0x00,
// targetUser: 0x03ea
(byte)0xea, (byte)0x03,
// RDP: total length: 22 bytes (LE)
(byte)0x16, (byte)0x00,
// PDU type: PDUTYPE_DATAPDU (0x7), TS_PROTOCOL_VERSION (0x10) (LE)
(byte)0x17, (byte)0x00,
// PDU source: 1007 (LE)
(byte)0xec, (byte)0x03,
// Share ID: 0x000103ea (LE)
(byte)0xea, (byte)0x03, (byte)0x01, (byte)0x00,
// Padding: 1 byte
(byte)0x00,
// Stream ID: STREAM_LOW (1)
(byte)0x01,
// uncompressedLength : 8 bytes (LE)
(byte)0x08, (byte)0x00,
// pduType2 = PDUTYPE2_SYNCHRONIZE (31)
(byte)0x1f,
// generalCompressedType: 0
(byte)0x00,
// generalCompressedLength: 0 (LE?)
(byte)0x00, (byte)0x00,
// messageType: SYNCMSGTYPE_SYNC (1) (LE)
(byte)0x01, (byte)0x00,
// targetUser: 0x03ea
(byte)0xea, (byte)0x03,
};
/* @formatter:on */
};
/* @formatter:on */
MockSource source = new MockSource("source", ByteBuffer.convertByteArraysToByteBuffers(new byte[] {1, 2, 3}));
Element todo = new ClientSynchronizePDU("TODO");
Element x224 = new ClientX224DataPdu("x224");
Element x224 = new ClientX224DataPDU("x224");
Element tpkt = new ClientTpkt("tpkt");
Element sink = new MockSink("sink", ByteBuffer.convertByteArraysToByteBuffers(packet));
Element mainSink = new MockSink("mainSink", ByteBuffer.convertByteArraysToByteBuffers(new byte[] {1, 2, 3}));

View File

@ -14,7 +14,7 @@
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package rdpclient;
package rdpclient.rdp;
import streamer.BaseElement;
import streamer.ByteBuffer;

View File

@ -14,16 +14,16 @@
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package rdpclient;
package rdpclient.rdp;
import streamer.ByteBuffer;
import streamer.Element;
import streamer.Link;
import streamer.MockSink;
import streamer.MockSource;
import streamer.OneTimeSwitch;
import streamer.Pipeline;
import streamer.PipelineImpl;
import streamer.debug.MockSink;
import streamer.debug.MockSource;
/**
* @see http://msdn.microsoft.com/en-us/library/cc240470.aspx
@ -47,9 +47,15 @@ public class ClientX224ConnectionRequestPDU extends OneTimeSwitch {
*/
protected String userName;
public ClientX224ConnectionRequestPDU(String id, String userName) {
/**
* Protocol to use: RDP_NEG_REQ_PROTOCOL_SSL or RDP_NEG_REQ_PROTOCOL_HYBRID.
*/
protected int protocol;
public ClientX224ConnectionRequestPDU(String id, String userName, int protocol) {
super(id);
this.userName = userName;
this.protocol = protocol;
}
@Override
@ -85,7 +91,7 @@ public class ClientX224ConnectionRequestPDU extends OneTimeSwitch {
buf.writeByte(0x00);
// RDP_NEG_REQ: Requested protocols: PROTOCOL_SSL
buf.writeIntLE(RdpConstants.RDP_NEG_REQ_PROTOCOL_SSL);
buf.writeIntLE(protocol);
// Calculate length of packet and prepend it to buffer
ByteBuffer data = new ByteBuffer(5);
@ -119,29 +125,29 @@ public class ClientX224ConnectionRequestPDU extends OneTimeSwitch {
byte[] packet = new byte[] {
0x03, // TPKT Header: version = 3
0x00, // TPKT Header: Reserved = 0
0x00, // TPKT Header: Packet length - high part
0x2c, // TPKT Header: Packet length - low part (total = 44 bytes)
0x27, // X.224: Length indicator (39 bytes)
(byte)0xe0, // X.224: Type (high nibble) = 0xe = CR TPDU;
// credit (low nibble) = 0
0x00, 0x00, // X.224: Destination reference = 0
0x00, 0x00, // X.224: Source reference = 0
0x00, // X.224: Class and options = 0
0x03, // TPKT Header: version = 3
0x00, // TPKT Header: Reserved = 0
0x00, // TPKT Header: Packet length - high part
0x2c, // TPKT Header: Packet length - low part (total = 44 bytes)
0x27, // X.224: Length indicator (39 bytes)
(byte)0xe0, // X.224: Type (high nibble) = 0xe = CR TPDU;
// credit (low nibble) = 0
0x00, 0x00, // X.224: Destination reference = 0
0x00, 0x00, // X.224: Source reference = 0
0x00, // X.224: Class and options = 0
'C', 'o', 'o', 'k', 'i', 'e', ':', ' ', 'm', 's', 't', 's', 'h', 'a', 's', 'h', '=', 'e', 'l', 't', 'o', 'n', 's', // "Cookie: mstshash=eltons"
'\r', '\n', // -Cookie terminator sequence
'C', 'o', 'o', 'k', 'i', 'e', ':', ' ', 'm', 's', 't', 's', 'h', 'a', 's', 'h', '=', 'e', 'l', 't', 'o', 'n', 's', // "Cookie: mstshash=eltons"
'\r', '\n', // -Cookie terminator sequence
0x01, // RDP_NEG_REQ::type (TYPE_RDP_NEG_REQ)
0x00, // RDP_NEG_REQ::flags (0)
0x08, 0x00, // RDP_NEG_REQ::length (8 bytes)
0x01, 0x00, 0x00, 0x00 // RDP_NEG_REQ: Requested protocols
// (PROTOCOL_SSL in little endian format)
0x01, // RDP_NEG_REQ::type (TYPE_RDP_NEG_REQ)
0x00, // RDP_NEG_REQ::flags (0)
0x08, 0x00, // RDP_NEG_REQ::length (8 bytes)
0x01, 0x00, 0x00, 0x00 // RDP_NEG_REQ: Requested protocols
// (PROTOCOL_SSL in little endian format)
};
MockSource source = new MockSource("source", ByteBuffer.convertByteArraysToByteBuffers(new byte[] {1, 2, 3}));
Element cr = new ClientX224ConnectionRequestPDU("cr", cookie);
Element cr = new ClientX224ConnectionRequestPDU("cr", cookie, RdpConstants.RDP_NEG_REQ_PROTOCOL_SSL);
Element tpkt = new ClientTpkt("tpkt");
Element sink = new MockSink("sink", ByteBuffer.convertByteArraysToByteBuffers(packet));
Element mainSink = new MockSink("mainSink", ByteBuffer.convertByteArraysToByteBuffers(new byte[] {1, 2, 3}));

View File

@ -14,18 +14,18 @@
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package rdpclient;
package rdpclient.rdp;
import streamer.BaseElement;
import streamer.ByteBuffer;
import streamer.Link;
public class ClientX224DataPdu extends BaseElement {
public class ClientX224DataPDU extends BaseElement {
public static final int X224_TPDU_DATA = 0xF0;
public static final int X224_TPDU_LAST_DATA_UNIT = 0x80;
public ClientX224DataPdu(String id) {
public ClientX224DataPDU(String id) {
super(id);
}

View File

@ -14,7 +14,7 @@
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package rdpclient;
package rdpclient.rdp;
import java.nio.charset.Charset;
@ -63,8 +63,29 @@ public interface RdpConstants {
*/
public static final int RDP_NEG_REQ_TYPE_NEG_FAILURE = 3;
/**
* I/O Channel.
*/
public static final int CHANNEL_IO = 1003;
/**
* RDP channel.
*/
public static final int CHANNEL_RDPRDR = 1004;
/**
* Clipboard channel.
*/
public static final int CHANNEL_CLIPRDR = 1005;
/**
* RDP sound channel.
*/
public static final int CHANNEL_RDPSND = 1006;
/**
* User channel.
*/
public static final int CHANNEL_USER = 1007;
}

View File

@ -14,7 +14,7 @@
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package rdpclient;
package rdpclient.rdp;
import java.util.HashSet;
import java.util.Set;

Some files were not shown because too many files have changed in this diff Show More