Author Topic: [Java] Remote Control framework  (Read 5705 times)

0 Members and 1 Guest are viewing this topic.

Offline iago

  • Leader
  • Administrator
  • Hero Member
  • *****
  • Posts: 17914
  • Fnord.
    • View Profile
    • SkullSecurity
[Java] Remote Control framework
« on: June 03, 2006, 01:28:36 pm »
This isn't really a tutorial, but it's a bit of a reference.  I'll explain a little about what I did, and post the README and PROTOCOL descriptions, and a link to the code. 

I've been slowly working on a RemoteControl protocol that allows a server to communicate with multiple clients over a secure (encrypted) connection.  It uses SRP to log in, AES to encrypt packets, and all packets are HTTP-style.  In fact, a HTTP browser can communicate with a RemoteControl Server, but it obviously can't authenticate or encrypt. 

Before I post the documentation, here's a link to the source:
http://www.javaop.com/~iago/RemoteControl-1.0.tgz

If you want to be able to use it without the source, you can use the .jar file:
http://www.javaop.com/~iago/RemoteControl.jar

Or you can grab it from my CVS, with the project name RemoteControl. 

Here is the README file, which explains what this does, but not, in any detail, how it does it:
Quote
README for RemoteControl, by Ron Bowes (iago@valhallalegends.com)

This is a brief document how to write applications that make use of the RemoteControl Server and Client classes. 
To learn more about the protocol, please see the file, PROTOCOL. 


WHAT YOU CAN DO
---------------
The RemoteControl Server and Client allow an application to communicate with other pieces in a secure manner over
the Internet.  The Server portion allows any number of users to connect, ensuring that each user is authenticated
before giving access to him or her.  The Client portion connections to a single server and attempts authentication.

Upon completion of the authentication, several things are done:
 - The server has determined that the client has a valid account, and thus allows him or her access.
 - The client has determined that the server actually knows his or her password, and thus the server is a valid server.
 - The server and client share an encryption key that no eavesdropping user could possibly know.
 
Once the authentication is complete, all remaining packets are encrypted.  SRP authentication and AES encryption are
used by default, and both have no known fatal weaknesses, so data should be reasonably secure.

The necessary code is contained in a single set of packages:
 - rc.pub
 - rc.pub.exceptions
 - rc.pub.interfaces
 
Each file in those folders (in fact, all files) are heavily commented, so the purpose of each of the functions should
be fairly easy to determine.  In this document (below), I'll explain the steps to create a client and server
superficially.  For more details, please have a look at the actual functions.


EXAMPLES
--------
At the moment I have only one good example: a fake implementation of RCRS.  Although my RCRS2 program doesn't actually
server proper data, it provides a good example of how to use unauthorized and authorized commands. 

The example can be found in the rc.demo folder.  I will not provides notes on RCRS2 here; the code should be pretty self-
explanitory. 


COMMANDS
--------
Both a client and a server can send and receive commands.  Commands contain several features:
- Command name -- The name of the command, such as "CHAT" or "WRITE".
- Command path -- An arbitrary value.  Often used for a username, file path, or destination.
- Command parameters -- A series of name=value pairs representing the parameters of the command
- Data -- Any amount of binary data, as an arry of bytes.  Can contain anything or nothing. 

When a command is received, a response should always be returned.  I will explain shortly how to send commands and
responses.  A response contains several features:
- Status code -- A 3 digit number indicating the success or failure of the command.  See rc.pub.RCStatusCode.
- Status String -- Brief text containing the string "OK", or a failure string derived from the Status Code. 
- Response parameters -- Same as command parameters. 
- Data -- Same as Command Data. 

To send a command, you should:
- Implement rc.pub.interfaces.RCCommandResponse
- Call sendCommand(), which can be called from many different places. 

To receive a command, you should:
- Implement rc.pub.interfaces.RCCommandCallback
- For servers, register the command with RCServer.registerCommand() or RCPublicUser.registerCommand()
- For clients, register the command with RCClient.registerCommand()

The difference between using RCServer.registerCommand() and RCPublicUser.registerCommand() is that RCServer registers
the command for all servers instances, so all authorized users are able to use it.  RCPublicUser registers the command
only for the specific user, and is useful if you only want to grant access to certain users. 

Another useful function is registerUnauthorizedCommand().  registerUnauthorizedCommand() registers a command that users
can use whether or not they are authenticated to the server.  In other words, it can be used unencrypted by strangers. 
Be careful with unauthorized commands! 

After sending a command, either RCCommandResponse.responseReceived() or RCCommandResponse.errorReceived() will be
called.  Once it has been received, the command/response is complete.  Another command may be sent, and more than
one command may be sent in parallel.  See below for how to track multiple commands simultaneously. 

When receiving a command, RCCommandCallback.commandReceived() will be called.  When commandReceived() returns, a
response is automatically sent back.  There are several ways to modify the response:
- Call the functions in RCResponseWrite, which is passed as a parameter to commandReceived()
- Throw a RCCommandException

Tracking multiple simultaneous commands may be done with the use of command id's.  When sendCommand() is called, a
unique long value is returned.  This value can be stored and used later to associate the command with the response.


CLIENT
------
Writing a RemoteControl client is actually very simple.  I'll begin by listing the major steps, then I will outline
what exactly has to be done. 

- Write a class that either implements rc.pub.interfaces.RCClientCallback or extends
  rc.pub.interfaces.RCAbstractClientCallback.
- Create an instance of rc.pub.RCClient
- Register your callback with RCClient.registerCallback()
- Call the appropriate RCClient function (either RCClient.connect() or RCClient.createAccount()

For more actions, have a look at the RCClient class. 

Once authentication has completed successfully, the function RCClientCallback.authorizedGoodServer() will be called. 
Once that function has been called, you may send whatever commands you'd like to the server by calling
RCClient.sendCommand().  See the COMMANDS section above for more information. 


SERVER
------
Writing a RemoteContorl server is not as easy as writing the client, but it is nearly as easy.  The steps that must
be performed:

- Write a class that either implements rc.pub.interfaces.RCServerCallback or extends
  rc.pub.interfaces.RCAbstractClientCallback. 
- Create an instance of RCServer by calling RCServer.createServer(), passing it the class that implements the
  RCServerCallback
- Register the commands that you want all clients to be able to use through the RCServer instance that was returned
  by createServer()

See the RCServer class functions for more information and actions. 

When a user has completed authentication, the function RCServerCallback.userAuthorized() is called.  The RCPublicUser
instance should be stored, since it is that interface that allows the program to interface with the authenticated
user.  Whenever a command or response is receive, the RCPublicUser object is also passed, allowing you to easily check
the user. 


HACKING
-------

If you desire to play with this beyond the rc.pub folder, that's fine.  If you improve on anything, let me know, I
always like to hear from people. 

If you want information on how the protocol works, see the PROTOCOL file.  In here, I'll just explain a few things
you can do to use my code a little differently.  How well or how poorly this will work, I cannot say.  I haven't
tested any of this. 

- rc.RCSettings has many options that can be changed and tweaked.  Many changes will make the client incompatible
  with servers that don't have the same settings, but you might like other encryption or verification.

- The built-in commands can be overridden.  Information on them can be found in the PROTOCOL file, but the commands
  include LOGON, LOGON2, LOGON_ASCII, CREATE, CREATE_ASCII, CHANGE, CHANGE_ASCII, and DELETE.  My default logon
  commands use a fairly secure SRP implementation, but if you want to play with it, you can. 
 



The protocol is very simliar to HTTP.  If you want to write your own server or client (since I don't really have any servers yet, this is probably useless at the moment), here are the protocol specs:
Quote
PROTOCOL for RemoteControl, by Ron Bowes (iago@valhallalegends.com)

This file explains the protocol of the RemoteControl package.  The protocol is based largely on HTTP, SRP, and AES. 

I will begin by explaining how to encode data within a packet.  Then I will explain how both unencrypted and encrypted
packets are structured.  After explaining the structure  of the packets, I will look at the suggested parameters in the
packets.  Then I will show the built-in commands and explain how the logon works.  Since the logon is SRP-based, I'm not
going to go very deeply into how the logon works, please have a look at SRP.html for notes on the protocol.

SRP and AES encryption isn't actually required.  By sacrificing pretty much all security, a completely ASCII logon can
be achieved.  I will explain how to do so at the end, but it's a really, really bad idea. 


ENCODING DATA
-------------
Any non-standard ASCII values in a string, as well as spaces (' '), colons (':'), the plus sign ('+'), percent
sign ('%'), and endlines, should be encoded with their ASCII value.  For example, a space is %20, a endline is
%0D, etc.  Additionally, spaces can be encoded as a '+'.  Every character in a packet can be encoded, but only
characters that interfere with the normal operation are required to be encoded. 

The LOGON and LOGON2 packets require large numbers to be sent.  These numbers are encoded as 32 8-bit hex digits
separated by spaces.  For example:
 ef 5f d7 72 9b 80 e7 0b 04 1b 9f ad d2 39 17 45 a2 f6 d4 d5 df c8 84 e3 3f d4 0b 48 71 f1 de f3
Values under 16 may or may not have a leading 0, clients should handle either case. 


UNENCRYPTED PACKETS
-------------------
Unencrypted packets are modelled after HTTP packets.  In fact, the protocol is so close to HTTP that a web browser
can successfully interface with the RemoteControl. 

Each command packet contains a command name, a path, a version, a series of parameters, and, optionally, binary data. 

Here is the structure of a packet that does not contain data:

---------------------------------------------------------------
COMMAND path version
parameter: value
parameter: value
......

---------------------------------------------------------------

Here is the structure of a packet that does contain data:

---------------------------------------------------------------
COMMAND path version
parameter: value
parameter: value
content-length: x

[x bytes of data]
---------------------------------------------------------------

Responses are fairly similar to commands.  Here is a response that does not contain data:

---------------------------------------------------------------
version statuscode statusstring
parameter: value
parameter: value

---------------------------------------------------------------

Here is a response that contains data:

---------------------------------------------------------------
version statuscode statusstring
parameter: value
parameter: value
content-length: x

[x bytes of data]
---------------------------------------------------------------


That's really all there is to a command and response.  The meanings of each of the values should be obvious, but
here they are anyways:

COMMAND - The name of the command.  Defined by the program.  Some commands built-in include LOGON, LOGON2, LOGON_ASCII,
 and some others.  Should always be upper case, and the receiver should ignore case. 

path - Some arbitrary value sent along with the command.  Can be a username, file path, or anything else the programmer
 wants to send. 
 
version - A string indicating the version of the sender.  The version is echoed back by the receiver.  To differentiate
 a command from a response, check the first string; if it's the version string, then it has to be a response. 
 
parameter - The name of each parameter.  Although the programmer may decide which parameters to use and what they mean,
 some parameters are built-in.  See below for information on built-in parameters.  The receiver should ignore the case
 of all parameter names. 
 
value - The value of the parameter that it is after. 

content-length - A built-in parameter that is required for sending data along with the command/response. 

statuscode - A numeric status code.  See rc.pub.RCStatusCode for information on status codes. 

statustring - A string version of the status code.  I only included this for compatibility for HTTP. 


ENCRYPTED PACKETS
-----------------
After sending the LOGON and LOGON2 packets, all subsequent packets are encrypted.  By default, the data is encrypted
with AES using K for a key (see the LOGON section for information on how to obtain K).  Optionally (NOT by default),
packets are also compressed with GZIP.  See rc.RCSettings for encryption and compression options, but I don't
recommend changing them. 

The encryption key for AES is 128 bits.  The generated K value is 320 bits.  To solve this dilemma, I fold the K
value over, using XOR.  Bytes 1-16 are xored with bytes 17 - 32 which are xored with bytes 33 - 40:

      01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16
                       --- XOR ---
      17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
                       --- XOR ---
      33 34 35 36 37 38 39 40

An encrypted packet is in this form:

(2 bytes)      Length
(length bytes) Encrypted Data

If a packet is compressed, the compression is done before encyption, and decompression is done after decryption:

Send Data = AES(GZIP(data))
Receive Data = AES(GUNZIP(data))

The data is, of course, the regular unencrypted packet.  If LOGON_ASCII is used, then no encryption is done.  See
below for information on LOGON_ASCII. 


IMPORTANT PARAMETERS
--------------------
Some parameters that are sent with packets are important, and others are optional.  Here is a list of all built-in
packets that I use:

- nonce [required]
  The "nonce" parameter must be sent in all encrypted packets.  It is an incremental value, with "1" being sent in the
  first packet, "2", in the second, "3" in the third, and so on.  The server and client both must store their own current
  nonce and the nonce value that they're expecting to receive.  If the wrong nonce value is received, the packet should
  be ignored. 
  The nonce value is purely a security measure.  It prevents an attacker from replaying the same encrypted packet and
  causing chaos. 
 
- id [required]
  The "id" parameter must be sent in all packets, and echoed in the response.  Packet responses won't necessarily
  come back in the order they are sent.  The "id" parameter is used to track the responses and match them up to
  the sent packets.  It is important for clients and servers to always echo the "id" parameter. 
 
- content-length [required sometimes]
  The "content-length" is the length, in bytes, of the data section of a packet. 

- error [required sometimes]
  In error packets, an error parameter should be set.  The error parameter is a textual description of the error,
  provided for the user. 
 
- date [optional]
  I include the date and time of the sender in every packet. 


BUILT-IN COMMANDS
-----------------
I have written several commands that the server implements and that clients should use.  All commands listed here are
related to logging on, so details will be given below.  Provided here is a list of commands and the parameters that
are required (besides the parameters that are required for all commands).


 Command        Command Parameters   Response Parameters   Notes
 -------        ------------------   -------------------   -----
 LOGON          A                    B, s                  First logon packet, username is sent as path
 LOGON2         M1                   M2                    Second logon packet, M1 is proof
 LOGON_ASCII    Password             n/a                   Only ASCII logon packet, username is sent as path (insecure)
 CREATE         s, v                 n/a                   Create an account the most secure way
 CREATE_ASCII   Password             n/a                   Create an account using ASCII (insecure)
 CHANGE         s, v                 n/a                   Change password more securely
 CHANGE_ASCII   Password             n/a                   Change password using ASCII (insecure)
 DELETE         n/a                  n/a                   Delete own account, log out


LOGON
-----

This section will provide a brief overview of how to log on to a Remote Control server.  The logon follows the
identical LOGON procedure as Battle.net's SRP protocol.  See SRP.html for information on what the variables mean
and how the formulas work. 

a) send LOGON
   - The LOGON packet contains the username, in the path
   - The LOGON packet contains A, which is the client's public key
   - LOGON will always be successful if the username is valid
   
b) receive LOGON response
   - The LOGON response for a successful logon packet contains B, which is the server's public key
   - The LOGON response for a successful logon packet contains s, which is the salt fot the user
   
c) send LOGON2
   - The LOGON2 packet contains the M1 value, which is the client's proof
   - Server verifies the password based on M1 packet
   
d) receive LOGON2 response
   - The LOGON2 response contains M2, which is the server's proof
   - M2 should always be verified by the client

The K value, which is generated as part of SRP (see SRP.html), is used for all packets after LOGON and LOGON2.  See
ENCRYPTED PACKETS, above, for details. 


ASCII LOGON
-----------

The ASCII logon is a completely ASCII-based logon that requires no SRP implementation.  All logon packets send the
password in plaintext, and after logging on packets are NOT encrypted.  Using the ASCII method is highly insecure
and should never be used.  Unfortunately, due to the difficulty of implementing SRP in some languages, the ASCII
logon can be used. 

ASCII and SRP logons may be mixed.  On the server, the ASCII logon is basically a wrapper around the SRP logon.
As such, an account created or used with SRP can also be used with ASCII, and an account created or used with ASCII
can also be used with SRP. 

The ASCII logon is very simple:

a) send LOGON_ASCII
   - The LOGON_ASCII packet contains the username, in the path
   - The LOGON_ASCII packet contains Password, which is the client's password in plaintext
   - LOGON_ASCII will be successful if the username and password is valid

b) receive LOGON_ASCII response
   - LOGON_ASCII response contains nothing special


CONCLUSION
----------

Writing client software is fairly simple, with the proper libraries.  If not, the ASCII logon can be used without
the support of libraries.  The choice is yours: ease or security. 

Offline Chavo

  • x86
  • Hero Member
  • *****
  • Posts: 2219
  • no u
    • View Profile
    • Chavoland
Re: [Java] Remote Control framework
« Reply #1 on: June 03, 2006, 05:40:13 pm »
This would have been useful to me two weeks ago when I was trying to decifer/fix your Remote Control Plugin for JavaOp.  Instead I just wrote my own  :P

Offline iago

  • Leader
  • Administrator
  • Hero Member
  • *****
  • Posts: 17914
  • Fnord.
    • View Profile
    • SkullSecurity
Re: [Java] Remote Control framework
« Reply #2 on: June 03, 2006, 11:24:56 pm »
hah, yeah, that plugin never really worked. I didn't spend enough time on it.  That's why I wrote this completely apart, so I can use it in any of my future projects. 

If I ever get around to doing JavaOp3, this framework will definitely be the core.  That's the intention of it, but I'm going to use it for another project first, I think. 

Offline while1

  • x86
  • Hero Member
  • *****
  • Posts: 1013
    • View Profile
Re: [Java] Remote Control framework
« Reply #3 on: October 12, 2007, 09:07:17 am »
The links are dead of course... I was wondering if you still have the source lying around.

Also a question, is the source public domain or under a particular license?  Thanks.
I tend to edit my topics and replies frequently.

http://www.operationsmile.org

Offline iago

  • Leader
  • Administrator
  • Hero Member
  • *****
  • Posts: 17914
  • Fnord.
    • View Profile
    • SkullSecurity
Re: [Java] Remote Control framework
« Reply #4 on: October 12, 2007, 09:48:17 am »

Offline Joe

  • B&
  • x86
  • Hero Member
  • *****
  • Posts: 10319
  • In Soviet Russia, text read you!
    • View Profile
    • Github
Re: [Java] Remote Control framework
« Reply #5 on: October 12, 2007, 11:00:43 pm »
And since iago can't read the whole post, yes, he releases everything (exception: his lockdown code is in BSD) in public domain.
I'd personally do as Joe suggests

You might be right about that, Joe.


Offline iago

  • Leader
  • Administrator
  • Hero Member
  • *****
  • Posts: 17914
  • Fnord.
    • View Profile
    • SkullSecurity
Re: [Java] Remote Control framework
« Reply #6 on: October 12, 2007, 11:04:05 pm »
I did read the whole post, then spent 10 minutes digging up that code and uploading it. By the time I had done that, I forgot about the rest.

But yes, the code in question is public domain, use it, sell it, do whatever you want, although I appreciate getting credit for it.

Offline while1

  • x86
  • Hero Member
  • *****
  • Posts: 1013
    • View Profile
Re: [Java] Remote Control framework
« Reply #7 on: October 13, 2007, 09:11:52 pm »
Cool, thanks.
I tend to edit my topics and replies frequently.

http://www.operationsmile.org

Offline while1

  • x86
  • Hero Member
  • *****
  • Posts: 1013
    • View Profile
Re: [Java] Remote Control framework
« Reply #8 on: October 18, 2007, 08:54:52 pm »
Java 6 is sure pissing me off.

Code: [Select]
javac RCTester.java -classpath ./ -source 5

Gives me:

Code: [Select]
1. ERROR in RCTester.java (at line 1)
        import rc.commands.RCCommandCallback;
        ^^
The type Hashtable is not generic; it cannot be parameterized with arguments <String, String>

Without setting the source level to 5 I get errors telling me I need source level 5.

I'm not sure what exactly this means.  If I'm to incorporate this into a project, am I forced to use Java 5?  Last time I touched Java was back in Java 5 Update 3 or so.
« Last Edit: October 18, 2007, 08:59:27 pm by Michael »
I tend to edit my topics and replies frequently.

http://www.operationsmile.org

Offline Ender

  • x86
  • Hero Member
  • *****
  • Posts: 2390
    • View Profile
Re: [Java] Remote Control framework
« Reply #9 on: October 18, 2007, 10:27:36 pm »
But Hashtable is generic in 6.0 (in anything 5+) =\ Are you sure the source level isn't at 4 instead of 5 or 6? The java program in your path may be at 6, while your javac is at 4.

edit: omg, 777, leet.

Offline while1

  • x86
  • Hero Member
  • *****
  • Posts: 1013
    • View Profile
Re: [Java] Remote Control framework
« Reply #10 on: October 19, 2007, 01:55:44 am »
Finally figured it out, and it was basically along the lines of that.  Thanks.
I tend to edit my topics and replies frequently.

http://www.operationsmile.org