blob: 0afafd059489336fd201e0290aa1f2c715873633 (
plain) (
tree)
|
|
package de.bwlehrpool.bwlp_guac;
import java.io.Closeable;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class VncConnection implements Closeable {
private static final Logger LOGGER = LoggerFactory.getLogger(VncConnection.class);
private final Socket sock;
private final DataOutputStream out;
private final DataInputStream in;
public VncConnection(String host, int port) throws IOException {
sock = new Socket();
sock.connect(new InetSocketAddress(host, port), 1200);
sock.setSoTimeout(1000);
out = new DataOutputStream(sock.getOutputStream());
in = new DataInputStream(sock.getInputStream());
}
/**
* @return Version string on success, null if not RFB
* @throws IOException
*/
public String handshake() throws IOException {
byte[] buffer = new byte[12];
in.readFully(buffer);
if (buffer[0] != 'R' || buffer[1] != 'F' || buffer[2] != 'B')
return null;
out.write("RFB 003.008\n".getBytes());
out.flush();
return new String(buffer).substring(4, 11);
}
public boolean tryLogin(String passwd) throws IOException {
if (passwd == null)
return false; // Paswordless not supported yet (although simpler..)
int numTypes = in.read();
if (numTypes == 0) {
LOGGER.info("VNC Server @ " + sock.getRemoteSocketAddress() + " does not support any auth methods");
printError();
return false;
}
boolean ok = false;
for (int i = 0; i < numTypes; ++i) {
if (in.read() == 2) {
ok = true;
break; // Found "VNC Authentication"
}
}
if (!ok) {
LOGGER.info("VNC Server @ " + sock.getRemoteSocketAddress() + " does not support VNC Authentication");
return false;
}
out.write(2); // Pick passwd auth
// Get challenge data
byte[] challenge = new byte[16];
int ret = in.read(challenge);
if (ret != 16) {
LOGGER.info("Didn't receive challenge from VNC server @ " + sock.getRemoteSocketAddress());
return false;
}
// pad pw to 8 bytes
byte[] pw_bytes = passwd.getBytes();
pw_bytes = Arrays.copyOf(pw_bytes, 8);
// Encrypt
Cipher des;
try {
des = Cipher.getInstance("DES/ECB/NoPadding");
des.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(reverseBits(pw_bytes), 0, pw_bytes.length, "DES"));
out.write(des.doFinal(challenge));
} catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException
| BadPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// check reply
int securityReply = in.readInt();
if (securityReply != 0) {
LOGGER.info("Security reply = " + securityReply + " for VNC server @ " + sock.getRemoteSocketAddress());
return false;
}
return true;
}
private void printError() {
try {
int len = in.readInt();
byte[] msg = new byte[len];
in.readFully(msg);
LOGGER.info(new String(msg, StandardCharsets.ISO_8859_1));
} catch (IOException e) {
// Nothing, we're already kinda handling an error, so if we can't fetch the message, ignore
}
}
@Override
public void close() throws IOException {
try {
in.close();
} catch (Exception e) {
}
try {
out.close();
} catch (Exception e) {
}
try {
sock.close();
} catch (Exception e) {
}
}
/*
*
*/
private byte[] reverseBits(byte[] b) {
byte[] result = new byte[b.length];
for (int i = 0; i < b.length; i++) {
result[i] = reverseBits(b[i]);
}
return result;
}
private byte reverseBits(byte input) {
byte result = 0x00;
for (int i = 0; i < 8; i++) {
result |= ((byte) ((input & (0x01 << i)) >>> i) << 7 - i);
}
return result;
}
}
|