I want to download a PNG from a remote web server through the tor proxy. The proxy is up and running and I can send the necessary GET and receive the OK using a tor socket. I can also receive the content. However, I don't manage to parse the content. My goal is to have a method I can pass a connected socket (preconfigured by me to use the Tor network) and get back an BufferedImage. How can I do that?
My GET request looks like the following:
PrintStream httpOut = new PrintStream(socket.getOutputStream());
httpOut.print("GET /" + path + " HTTP/1.0\r\n");
httpOut.print("Host: " + host + ":" + port + "\r\n");
httpOut.print("\r\n");
httpOut.flush();
And an example response would be:
HTTP/1.1 200 OK
Date: Mon, 23 Feb 2015 20:54:25 GMT
Server: Apache
Set-Cookie: PHPSESSID=thesessionideeee; path=/
Expires: Mon, 26 Jul 1997 05:00:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Last-Modified: Mon, 23 Feb 2015 20:54:25GMT
Cache-Control: post-check=0, pre-check=0
Content-Length: 3884
Connection: close
Content-Type: image/png
Thank you for help,
Turakar
You can check this class from http://web.mit.edu/foley/www/TinFoil/src/tinfoil/TorLib.java
that explain how to connect:
package tinfoil;
/**
* Tinfoil is an RFID Privacy and Security Enhancement library.
*
* Copyright (c) 2005 Joe Foley, MIT AutoID Labs
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
// $HeadURL: $
// $Id: $
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.InetAddress;
import java.net.Socket;
/**
* The Onion Router Java Library routines<br />
* These methods allow us to setup an anonymized TCP socket through the Tor
* network and do safe anonymized DNS lookups.<br />
* This code was written with the help of Roger Dingledine and Nick Mathewson.<br />
* The code is open-source under the MIT X11 license.
* <ul>
* <li> http://tor.eff.org
* <li><a href =
* "http://tor.eff.org/cvs/control/doc/howto.txt">http://tor.eff.org
* /cvs/control/doc/howto.txt</a>
* <li><a href =
* "http://www.mokabyte.it/2000/06/firewallutil.htm">http://www.mokabyte
* .it/2000/06/firewallutil.htm</a>
* </ul>
*
* #author Joe Foley<foley at MIT dot EDU>, MIT AutoID Labs
* #version 1.0
* <p>
*/
public class TorLib {
/**
* Default TOR Proxy port.
*/
static int proxyPort = 9050;
/**
* Default TOR Proxy hostaddr.
*/
static String proxyAddr = "localhost";
/**
* Constant tells SOCKS4/4a to connect. Use it in the <i>req</i> parameter.
*/
final static byte TOR_CONNECT = (byte) 0x01;
/**
* Constant tells TOR to do a DNS resolve. Use it in the <i>req</i>
* parameter.
*/
final static byte TOR_RESOLVE = (byte) 0xF0;
/**
* Constant indicates what SOCKS version are talking Either SOCKS4 or
* SOCKS4a
*/
final static byte SOCKS_VERSION = (byte) 0x04;
/**
* SOCKS uses Nulls as field delimiters
*/
final static byte SOCKS_DELIM = (byte) 0x00;
/**
* Setting the IP field to 0.0.0.1 causes SOCKS4a to be enabled.
*/
final static int SOCKS4A_FAKEIP = 0x01;
/**
* This method allows you to demo/access the resolver/socket generation from
* the command line. Run with "-h" to get the help menu.
*
* #param args
* Command line arguments for test main method.
*/
public static void main(final String[] args) {
String req = "-r";
String targetHostname = "tor.eff.org";
String targetDir = "index.html";
int targetPort = 80;
if ((args.length > 0) && args[0].equals("-h")) {
System.out.println("Tinfoil/TorLib - interface for using Tor from Java\n" + "By Joe Foley<foley#mit.edu>\n"
+ "Usage: java Tinfoil.TorLib <cmd> <args>\n" + "<cmd> can be: -h for help\n"
+ " -r for resolve\n" + " -w for wget\n" + "For -r, the arg is:\n"
+ " <hostname> Hostname to DNS resolve\n" + "For -w, the args are:\n"
+ " <host> <path> <optional port>\n"
+ " for example, http://tor.eff.org:80/index.html would be\n" + " tor.eff.org index.html 80\n"
+ " Since this is a demo, the default is the tor website.\n");
System.exit(2);
}
if (args.length >= 4) {
targetPort = new Integer(args[2]).intValue();
}
if (args.length >= 3) {
targetDir = args[2];
}
if (args.length >= 2) {
targetHostname = args[1];
}
if (args.length >= 1) {
req = args[0];
}
if (req.equals("-r")) {
System.out.println(TorResolve(targetHostname));
} else if (req.equals("-w")) {
try {
Socket s = TorSocket(targetHostname, targetPort);
DataInputStream is = new DataInputStream(s.getInputStream());
PrintStream out = new java.io.PrintStream(s.getOutputStream());
// Construct an HTTP request
out.print("GET /" + targetDir + " HTTP/1.0\r\n");
out.print("Host: " + targetHostname + ":" + targetPort + "\r\n");
out.print("Accept: */*\r\n");
out.print("Connection: Keep-Aliv\r\n");
out.print("Pragma: no-cache\r\n");
out.print("\r\n");
out.flush();
// this is from Java Examples In a Nutshell
final InputStreamReader from_server = new InputStreamReader(is);
char[] buffer = new char[1024];
int chars_read;
// read until stream closes
while ((chars_read = from_server.read(buffer)) != -1) {
// loop through array of chars
// change \n to local platform terminator
// this is a nieve implementation
for (int j = 0; j < chars_read; j++) {
if (buffer[j] == '\n') {
System.out.println();
} else {
System.out.print(buffer[j]);
}
}
System.out.flush();
}
s.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* This method Creates a socket, then sends the inital SOCKS request info It
* stops before reading so that other methods may differently interpret the
* results. It returns the open socket.
*
* #param targetHostname
* The hostname of the destination host.
* #param targetPort
* The port to connect to
* #param req
* SOCKS/TOR request code
* #return An open Socket that has been sent the SOCK4a init codes.
* #throws IOException
* from any Socket problems
*/
static Socket TorSocketPre(final String targetHostname, final int targetPort, final byte req) throws IOException {
Socket s;
// System.out.println("Opening connection to "+targetHostname+":"+targetPort+
// " via proxy "+proxyAddr+":"+proxyPort+" of type "+req);
s = new Socket(proxyAddr, proxyPort);
DataOutputStream os = new DataOutputStream(s.getOutputStream());
os.writeByte(SOCKS_VERSION);
os.writeByte(req);
// 2 bytes
os.writeShort(targetPort);
// 4 bytes, high byte first
os.writeInt(SOCKS4A_FAKEIP);
os.writeByte(SOCKS_DELIM);
os.writeBytes(targetHostname);
os.writeByte(SOCKS_DELIM);
return (s);
}
/**
* This method creates a socket to the target host and port using
* TorSocketPre, then reads the SOCKS information.
*
* #param targetHostname
* Hostname of destination host.
* #param targetPort
* Port on remote destination host.
* #return Fully initialized TCP Socket that tunnels to the target Host/Port
* via the Tor Proxy host/port.
* #throws IOException
* when Socket and Read/Write exceptions occur.
*/
static Socket TorSocket(final String targetHostname, final int targetPort) throws IOException {
Socket s = TorSocketPre(targetHostname, targetPort, TOR_CONNECT);
DataInputStream is = new DataInputStream(s.getInputStream());
// only the status is useful on a TOR CONNECT
byte version = is.readByte();
byte status = is.readByte();
if (status != (byte) 90) {
// failed for some reason, return useful exception
throw (new IOException(ParseSOCKSStatus(status)));
}
// System.out.println("status: "+ParseSOCKSStatus(status));
int port = is.readShort();
int ipAddr = is.readInt();
return (s);
}
/**
* This method opens a TOR socket, and does an anonymous DNS resolve through
* it. Since Tor caches things, this is a very fast lookup if we've already
* connected there The resolve does a gethostbyname() on the exit node.
*
* #param targetHostname
* String containing the hostname to look up.
* #return String representation of the IP address: "x.x.x.x"
*/
static String TorResolve(final String targetHostname) {
int targetPort = 0; // we dont need a port to resolve
try {
Socket s = TorSocketPre(targetHostname, targetPort, TOR_RESOLVE);
DataInputStream is = new DataInputStream(s.getInputStream());
byte version = is.readByte();
byte status = is.readByte();
if (status != (byte) 90) {
// failed for some reason, return useful exception
throw (new IOException(ParseSOCKSStatus(status)));
}
int port = is.readShort();
byte[] ipAddrBytes = new byte[4];
is.read(ipAddrBytes);
InetAddress ia = InetAddress.getByAddress(ipAddrBytes);
// System.out.println("Resolved into:"+ia);
is.close();
String addr = ia.toString().substring(1); // clip off the "/"
return (addr);
} catch (Exception e) {
e.printStackTrace();
}
return (null);
}
/**
* This helper method allows us to decode the SOCKS4 status codes into Human
* readible input.<br />
* Based upon info from
* http://archive.socks.permeo.com/protocol/socks4.protocol
*
* #param status
* Byte containing the status code.
* #return String human-readible representation of the error.
*/
static String ParseSOCKSStatus(final byte status) {
// func to turn the status codes into useful output
// reference
String retval;
switch (status) {
case 90:
retval = status + " Request granted.";
break;
case 91:
retval = status + " Request rejected/failed - unknown reason.";
break;
case 92:
retval = status + " Request rejected: SOCKS server cannot connect to identd on the client.";
break;
case 93:
retval = status + " Request rejected: the client program and identd report different user-ids.";
break;
default:
retval = status + " Unknown SOCKS status code.";
}
return (retval);
}
}
Related
I've been using IntelliJ to test out my SMTP Java client-server protocol. I've been testing some code on my Client java file to allow me input text.
The output i want to achieve in the end should look a little something like this:
s: 220 [my ip]
c: HELLO [my email]
s: 250 Hello [my email], pleased to meet you
c: MAIL FROM <[my email]>
s: 250 ok
c: RCPT TO: <[test email]>
s: 250 ok
c: DATA
s: 354 End data with <CR><LF>.<CR><LF>
c: Hello loan team,
c: If i don't stay, will i lose my loan?
c: .
s: 250 ok Message accepted for delivery
c: QUIT
s: 221 [my ip] closing connection
When i run my server code first, then my client code afterwards, it connects to the server but there's no output in the terminal. Even when i type something in the terminal, nothing outputs and i'm stumped if the Client code is causing problems, or the Server code is causing problems? Just to let you know that both code compiles and runs without errors.
Edit 1: I went back to the tutorial i followed and typed in the same socket ip and port and the Client code worked perfectly fine, following the tutorial. So i've denounced that the Server code is the problem. The main question is how do i alter the TCPServer code to fit the requirements of a simple SMTP server?
TCPServer.java:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.io.*;
import java.net.*;
public class TCPServer{
private ServerSocket server;
/**
* The TCPServer constructor initiate the socket
* #param ipAddress
* #param port
* #throws Exception
*/
public TCPServer(String ipAddress, int port) throws Exception {
if (ipAddress != null && !ipAddress.isEmpty())
this.server = new ServerSocket(port, 1, InetAddress.getByName(ipAddress));
else
this.server = new ServerSocket(0, 1, InetAddress.getLocalHost());
}
/**
* The listen method listen to incoming client's datagrams and requests
* #throws Exception
*/
private void listen() throws Exception {
// listen to incoming client's requests via the ServerSocket
//add your code here
String data = null;
Socket client = this.server.accept();
String clientAddress = client.getInetAddress().getHostAddress();
System.out.println("\r\nNew client connection from " + clientAddress);
// print received datagrams from client
//add your code here
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
while ( (data = in.readLine()) != null ) {
System.out.println("\r\nMessage from " + clientAddress + ": " + data);
client.sendUrgentData(1);
}
}
public InetAddress getSocketAddress() {
return this.server.getInetAddress();
}
public int getPort() {
return this.server.getLocalPort();
}
public static void main(String[] args) throws Exception {
// set the server address (IP) and port number
//add your code here
String serverIP = "192.168.1.235"; // local IP address
int port = 8088;
if (args.length > 0) {
serverIP = args[0];
port = Integer.parseInt(args[1]);
}
// call the constructor and pass the IP and port
//add your code here
TCPServer server = new TCPServer(serverIP, port);
System.out.println("\r\nRunning Server: " +
"Host=" + server.getSocketAddress().getHostAddress() +
" Port=" + server.getPort());
server.listen();
}
}
And here's ClientTester.java
import java.io.*;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;
public class ClientTester{
private Socket tcpSocket;
private InetAddress serverAddress;
private int serverPort;
private Scanner scanner;
/**
* #param serverAddress
* #param serverPort
* #throws Exception
*/
private ClientTester(InetAddress serverAddress, int serverPort) throws Exception {
this.serverAddress = serverAddress;
this.serverPort = serverPort;
//Initiate the connection with the server using Socket.
//For this, creates a stream socket and connects it to the specified port number at the specified IP address.
//add your code here
this.tcpSocket = new Socket(this.serverAddress, this.serverPort);
this.scanner = new Scanner(System.in);
}
/**
* The start method connect to the server and datagrams
* #throws IOException
*/
public static void main(String[] args) throws Exception {
// set the server address (IP) and port number
//add your code here
InetAddress serverIP = InetAddress.getByName("192.168.1.235"); // local IP address
int port = 8088;
if (args.length > 0) {
serverIP = InetAddress.getByName(args[0]);
port = Integer.parseInt(args[1]);
}
// call the constructor and pass the IP and port
//add your code here
ClientTester client = new ClientTester(serverIP, port);
// client.start();
try{
client = new ClientTester(serverIP, port);
System.out.println("\r\n Connected to Server: " + client.tcpSocket.getInetAddress());
BufferedReader stdin;
stdin = new BufferedReader (new InputStreamReader (System.in));
InputStream is = client.tcpSocket.getInputStream ();
BufferedReader sockin;
sockin = new BufferedReader (new InputStreamReader (is));
OutputStream os = client.tcpSocket.getOutputStream();
PrintWriter sockout;
sockout = new PrintWriter (os, true);
System.out.println ("S:" + sockin.readLine ());
while (true){
System.out.print ("C:");
String cmd = stdin.readLine ();
sockout.println (cmd);
String reply = sockin.readLine ();
System.out.println ("S:" + reply);
if (cmd.toLowerCase ().startsWith ("data") &&
reply.substring (0, 3).equals ("354"))
{
do
{
cmd = stdin.readLine ();
if (cmd != null && cmd.length () > 1 &&
cmd.charAt (0) == '.')
cmd = "."; // Must be no chars after . char.
sockout.println (cmd);
if (cmd.equals ("."))
break;
}
while (true);
// Read a reply string from the SMTP server program.
reply = sockin.readLine ();
// Display the first line of this reply string.
System.out.println ("S:" + reply);
continue;
}
// If the QUIT command was entered, quit.
if (cmd.toLowerCase ().startsWith ("quit"))
break;
}
}
catch (IOException e)
{
System.out.println (e.toString ());
}
finally
{
try
{
// Attempt to close the client socket.
if (client != null)
client.tcpSocket.close();
}
catch (IOException e)
{
}
}
}
}
Hopefully what i've written made somewhat sense of what problems i am encountering.
According to the documentation, before a read/write can occur, I need to send REQA followed by SELECT for anti-collision.
But I couldn't find any complete example code, code sequence performing this.
Every one starts with authenticate in onTagDiscovered, and starts reading/writing.
So my question is,
1. does Android performs its own REQA/SEL on its own under the hood?
2. If i wanted to, how do I perform REQA and SEL on my own?
I have come up with a sample code, based on the code here
try {
byte[] reqa = new byte[1];
reqa[0] = 0x26;
Log.e(TAG, "Sending REQA: " + bytesToHex(reqa));
mifareTag.transceive(reqa);
Log.e(TAG, bytesToHex(mifareTag.transceive(reqa)));
byte[] sel = new byte[9];
sel[0] = (byte) 0x93;
sel[1] = (byte) 0x70;
System.arraycopy(uid, uid.length - 4, sel, 2, 4);
sel[6] = (byte) (sel[2] ^ sel[3] ^ sel[4] ^ sel[5]);
java.util.zip.CRC32 x = new java.util.zip.CRC32();
x.update(sel);
long crc32 = x.getValue();
sel[7] = (byte) crc32;
sel[8] = (byte) (crc32 >> 8);
Log.e(TAG, "CRC: " + Long.toHexString(crc32));
Log.e(TAG, "Sending SEL: " + bytesToHex(sel));
Log.e(TAG, bytesToHex(mifareTag.transceive(sel)));
if (mifareTag.transceive(cmd) != null) {
Log.e(TAG, "NfcA Tag transcieve:auth success");
return true;
}
} catch (Exception ex) {
Log.e(TAG, "NfcA Tag transcieve:auth failed with exception !", ex);
return false;
}
But the problem is, with this code, what I'm receiving back is weird data.
10-22 11:04:13.465 30687-30734/com.mfreader E/RfidReader: Sending REQA: 26
10-22 11:04:13.492 30687-30734/com.mfreader E/RfidReader: B2007D9BD20804000215671E0D8B811D
10-22 11:04:13.492 30687-30734/com.mfreader E/RfidReader: CRC: a247ff86
10-22 11:04:13.493 30687-30734/com.mfreader E/RfidReader: Sending SEL: 93701A2E7D9BD286FF
10-22 11:04:13.519 30687-30734/com.mfreader E/RfidReader: B2007D9BD20804000215671E0D8B811D
10-22 11:04:13.602 30687-30734/com.mfreader E/RfidReader: NfcA Tag transcieve:auth failed with exception !
java.io.IOException: Transceive failed
at android.nfc.TransceiveResult.getResponseOrThrow(TransceiveResult.java:52)
at android.nfc.tech.BasicTagTechnology.transceive(BasicTagTechnology.java:151)
at android.nfc.tech.NfcA.transceive(NfcA.java:145)
The returned value is Sect#0Block#0 but the first 2 bytes replaced with B200 instead of 1A2E of the UID. And the succeeding Auth fails, which otherwise fails only intermittently (which is what i'm trying to solve)!
Not sure what i'm doing wrong, any help?
does Android performs its own REQA/SEL on its own under the hood?
Yes
If I wanted to, how do I perform REQA and SEL on my own?
/**
* Send raw NFC-A commands to the tag and receive the response.
*
* <p>Applications must not append the EoD (CRC) to the payload,
* it will be automatically calculated.
* <p>Applications must only send commands that are complete bytes,
* for example a SENS_REQ is not possible (these are used to
* manage tag polling and initialization).
*
* <p>Use {#link #getMaxTransceiveLength} to retrieve the maximum number of bytes
* that can be sent with {#link #transceive}.
*
* <p>This is an I/O operation and will block until complete. It must
* not be called from the main application thread. A blocked call will be canceled with
* {#link IOException} if {#link #close} is called from another thread.
*
* <p class="note">Requires the {#link android.Manifest.permission#NFC} permission.
*
* #param data bytes to send
* #return bytes received in response
* #throws TagLostException if the tag leaves the field
* #throws IOException if there is an I/O failure, or this operation is canceled
*/
public byte[] transceive(byte[] data) throws IOException {
return transceive(data, true);
}
You can select tag by method mifareTag.connect(), after authenticating with android methods from android docs you can write and read.
https://developer.android.com/reference/android/nfc/tech/MifareClassic
What means error 'B2' do you got it somewhere in documentation?
I want send a rest service call from Java using "GET" request.But i am getting the following error.I am able to use it in the postman but i am unable to send java application.
Exception in thread "main" java.lang.IllegalArgumentException: Key length not 128/192/256 bits.
at org.bouncycastle.crypto.engines.AESFastEngine.generateWorkingKey(Unknown Source)
at org.bouncycastle.crypto.engines.AESFastEngine.init(Unknown Source)
at org.bouncycastle.crypto.modes.CBCBlockCipher.init(Unknown Source)
at org.bouncycastle.crypto.macs.CMac.init(Unknown Source)
at com.rest.OAuth1.generateCmac(OAuth1.java:262)
at com.rest.OAuth1.generateSignature(OAuth1.java:180)
at com.rest.OAuth1.main(OAuth1.java:61)
This the my sample code
package com.rest;
// Java Libraries
import java.io.*;
import java.net.URL;
import java.net.URLEncoder;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;
import javax.net.ssl.HttpsURLConnection;
// Apache Commons Libraries used for the Nonce & Base64
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.codec.binary.Base64;
// Bouncy Castle Libraries used for CMAC encryption
import org.bouncycastle.crypto.engines.AESFastEngine;
import org.bouncycastle.crypto.macs.CMac;
import org.bouncycastle.crypto.params.KeyParameter;
/**
* Very basic sample code that demonstrates how to make an OAuth 1.0 System-to-System
* request to the LearningStudio API
*/
public class OAuth1 {
public static void main(final String[] args) throws Exception
{
// Setup the variables necessary to create the OAuth 1.0 signature and make the request
String httpMethod = "GET";
String URI = "example.com/one/oauth1/userManagement/v5/users";
//String appID = "{applicationId}";
String consumerKey = "1234567-1234-4186-1234-1234567891011!mailid#example.com";
String secret = "12345678-1234-1234-1234-12345678";
String body = "{var:val}";
String signatureMethod = "HMAC-SHA1";
byte[] requestBody = null;
HttpsURLConnection request = null;
BufferedReader in = null;
URL url = new URL(String.format("https://api.example.com%s", URI));
// Set the Nonce and Timestamp parameters
String nonce = getNonce();
String timestamp = getTimestamp();
// Set the request body if making a POST or PUT request
if ("POST".equals(httpMethod) || "PUT".equals(httpMethod))
{
requestBody = body.getBytes("UTF-8");
}
// Create the OAuth parameter name/value pair
Map<String, String> oauthParams = new LinkedHashMap<String, String>();
oauthParams.put("oauth_consumer_key", consumerKey);
//oauthParams.put("application_id", appID);
oauthParams.put("oauth_signature_method", signatureMethod);
oauthParams.put("oauth_timestamp", timestamp);
oauthParams.put("oauth_nonce", nonce);
// Get the OAuth 1.0 Signature
String signature = generateSignature(httpMethod, url, oauthParams, requestBody, secret);
System.out.println(String.format("OAuth 1.0 Signature = %s", signature));
// Add the oauth_signature parameter to the set of OAuth Parameters
oauthParams.put("oauth_signature", signature);
// Generate a string of comma delimited: keyName="URL-encoded(value)" pairs
StringBuilder sb = new StringBuilder();
String delimiter = "";
for (String keyName : oauthParams.keySet()) {
sb.append(delimiter);
String value = oauthParams.get((String) keyName);
sb.append(keyName).append("=\"").append(URLEncoder.encode(value, "UTF-8")).append("\"");
delimiter=",";
}
String urlString = url.toString();
// omit the queryString from the url
int startOfQueryString = urlString.indexOf('?');
if(startOfQueryString != -1) {
urlString = urlString.substring(0,startOfQueryString);
}
// Build the X-Authorization request header
String xauth = String.format("OAuth realm=\"%s\",%s", urlString, sb.toString());
System.out.println(String.format("X-Authorization request header = %s", xauth));
try
{
// Setup the Request
request = (HttpsURLConnection)url.openConnection();
request.setRequestMethod(httpMethod);
request.addRequestProperty("X-Authorization", xauth);
// Set the request body if making a POST or PUT request
if ("POST".equals(httpMethod) || "PUT".equals(httpMethod))
{
request.setRequestProperty("Content-Length", "" + requestBody.length);
request.setDoOutput(true);
OutputStream postStream = request.getOutputStream();
postStream.write(requestBody, 0, requestBody.length);
postStream.close();
}
// Send Request & Get Response
InputStreamReader reader = new InputStreamReader(request.getInputStream());
in = new BufferedReader(reader);
// Get the response stream
String response = in.readLine();
System.out.println(String.format("Successful Response: \r\n%s", response));
} catch (IOException e )
{
// This exception will be raised if the serve didn't return 200 - OK
System.out.print(e.getMessage());
} finally
{
if (in != null) in.close();
if (request != null) request.disconnect();
}
}
/**
* Generates a random nonce
*
* #return A unique identifier for the request
*/
private static String getNonce()
{
return RandomStringUtils.randomAlphanumeric(32);
}
/**
* Generates an integer representing the number of seconds since the unix epoch using the
* date/time the request is issued
*
* #return A timestamp for the request
*/
private static String getTimestamp()
{
return Long.toString((System.currentTimeMillis() / 1000));
}
/**
* Generates an OAuth 1.0 signature
*
* #param httpMethod The HTTP method of the request
* #param URL The request URL
* #param oauthParams The associative set of signable oAuth parameters
* #param requestBody The serialized POST/PUT message body
* #param secret Alphanumeric string used to validate the identity of the education partner (Private Key)
*
* #return A string containing the Base64-encoded signature digest
*
* #throws UnsupportedEncodingException
*/
private static String generateSignature(
String httpMethod,
URL url,
Map<String, String> oauthParams,
byte[] requestBody,
String secret
) throws UnsupportedEncodingException
{
// Ensure the HTTP Method is upper-cased
httpMethod = httpMethod.toUpperCase();
// Construct the URL-encoded OAuth parameter portion of the signature base string
String encodedParams = normalizeParams(httpMethod, url, oauthParams, requestBody);
// URL-encode the relative URL
String encodedUri = URLEncoder.encode(url.getPath(), "UTF-8");
// Build the signature base string to be signed with the Consumer Secret
String baseString = String.format("%s&%s&%s", httpMethod, encodedUri, encodedParams);
return generateCmac(secret, baseString);
}
/**
* Normalizes all OAuth signable parameters and url query parameters according to OAuth 1.0
*
* #param httpMethod The upper-cased HTTP method
* #param URL The request URL
* #param oauthParams The associative set of signable oAuth parameters
* #param requstBody The serialized POST/PUT message body
*
* #return A string containing normalized and encoded oAuth parameters
*
* #throws UnsupportedEncodingException
*/
private static String normalizeParams(
String httpMethod,
URL url,
Map<String, String> oauthParams,
byte[] requestBody
) throws UnsupportedEncodingException
{
// Sort the parameters in lexicographical order, 1st by Key then by Value
Map<String, String> kvpParams = new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER);
kvpParams.putAll(oauthParams);
// Place any query string parameters into a key value pair using equals ("=") to mark
// the key/value relationship and join each parameter with an ampersand ("&")
if (url.getQuery() != null)
{
for(String keyValue : url.getQuery().split("&"))
{
String[] p = keyValue.split("=");
kvpParams.put(p[0],p[1]);
}
}
// Include the body parameter if dealing with a POST or PUT request
if ("POST".equals(httpMethod) || "PUT".equals(httpMethod))
{
String body = Base64.encodeBase64String(requestBody).replaceAll("\r\n", "");
// url encode the body 2 times now before combining other params
body = URLEncoder.encode(body, "UTF-8");
body = URLEncoder.encode(body, "UTF-8");
kvpParams.put("body", body);
}
// separate the key and values with a "="
// separate the kvp with a "&"
StringBuilder combinedParams = new StringBuilder();
String delimiter="";
for(String key : kvpParams.keySet()) {
combinedParams.append(delimiter);
combinedParams.append(key);
combinedParams.append("=");
combinedParams.append(kvpParams.get(key));
delimiter="&";
}
// url encode the entire string again before returning
return URLEncoder.encode(combinedParams.toString(), "UTF-8");
}
/**
* Generates a Base64-encoded CMAC-AES digest
*
* #param key The secret key used to sign the data
* #param msg The data to be signed
*
* #return A CMAC-AES hash
*
* #throws UnsupportedEncodingException
*/
private static String generateCmac(String key, String msg)
throws UnsupportedEncodingException
{
byte[] keyBytes = key.getBytes("UTF-8");
byte[] data = msg.getBytes("UTF-8");
CMac macProvider = new CMac(new AESFastEngine());
macProvider.init(new KeyParameter(keyBytes));
macProvider.reset();
macProvider.update(data, 0, data.length);
byte[] output = new byte[macProvider.getMacSize()];
macProvider.doFinal(output, 0);
// Convert the CMAC to a Base64 string and remove the new line the Base64 library adds
String cmac = Base64.encodeBase64String(output).replaceAll("\r\n", "");
return cmac;
}
}
Is there any thing else which i am missing.
Also if i need to do POST request i need to add json data in the body tag directly?
EDIT: Is this really your key? maybe you changed the secret key to another size for not posting the original key here. If so check if keyBytes.length really gives you 16,24 or 32
I really digged deep now... I can't find any error in any of your code.
Your key is 256 bits long:
byte[] keyBytes = "12345678-1234-1234-1234-12345678".getBytes("UTF-8");
int bits = keyBytes.length*8;
System.out.println(bits); //gives 256
So i checked the CMac.java and they basically just copy the key with System.arraycopyso there is no error there.
They check the key in https://github.com/bcgit/bc-java/blob/master/core/src/main/java/org/bouncycastle/crypto/engines/AESFastEngine.java with
int keyLen = key.length;
if (keyLen < 16 || keyLen > 32 || (keyLen & 7) != 0)
{
throw new IllegalArgumentException("Key length not 128/192/256 bits.");
}
And since key.length is equal to 32 and 100000 & 111 is obviously 0 I really don't see anything wrong.
Please try to use a key with only 16 characters and tell us if the error still applies. Maybe you should also check if you really use the latest version of org.bouncycastle.crypto
If this doesn't help try just key.getBytes() without the charset UTF-8 for once.
I am a newbie in the javacard world. I have a wallet applet successfully running in netbeans (I can credit, debit,check-balance, verify pin etc using APDUs in the device console).
I am tasked to write a host application to communicate with this card in netbeans without using the smartcard console. From a little research, I figure that I have to import javax.smartcardio class into my host application, however, as you might know, there is very little documentation on this. Any assistance will be appreciated and of help to many of us who are finding it hard to delve into this world of smartcard programming. Below is my applet code. Pin was passed via parameters as 1122334455667788 via project properties.
package classicapplet1;
//package com.sun.javacard.samples.wallet;
import javacard.framework.*;
public class Wallet extends Applet {
// codes of CLA byte in the command APDUs
final static byte Wallet_CLA = (byte) 0xB0;
// codes of INS byte in the command APDUs
final static byte VERIFY = (byte) 0x20;
final static byte CREDIT = (byte) 0x30;
final static byte DEBIT = (byte) 0x40;
final static byte GET_BALANCE = (byte) 0x50;
// maximum wallet balance
final static short MAX_BALANCE = 10000;
// maximum transaction amount
final static byte MAX_TRANSACTION_AMOUNT = 100;
// maximum number of incorrect tries before the
// PIN is blocked
final static byte PIN_TRY_LIMIT = (byte) 0x03;
// maximum size PIN
final static byte MAX_PIN_SIZE = (byte) 0x08;
// Applet-specific status words:
final static short SW_VERIFICATION_FAILED = 0x6300;
final static short SW_PIN_VERIFICATION_REQUIRED = 0x6301;
final static short SW_INVALID_TRANSACTION_AMOUNT = 0x6A83;
final static short SW_EXCEED_MAXIMUM_BALANCE = 0x6A84;
final static short SW_NEGATIVE_BALANCE = 0x6A85;
// instance variables declaration
OwnerPIN pin;
short balance;
/**
*
* called by the JCRE to create an applet instance
*/
public static void install(byte[] bArray, short bOffset, byte bLength) {
// create a Wallet applet instance
new Wallet(bArray, bOffset, bLength);
} // end of install method
/**
*
* private constructor — called by the install method to
*
* instantiate a Wallet instance
*/
private Wallet(byte[] bArray, short bOffset, byte bLength) {
pin = new OwnerPIN(PIN_TRY_LIMIT, MAX_PIN_SIZE);
// bArray contains the PIN initialization value
pin.update(bArray, bOffset, bLength);
// register the applet instance with the JCRE
register();
} // end of the constructor
/**
*
* initialize the applet when it is selected
*/
public boolean select() {
// the applet declines to be selected
// if the pin is blocked
if (pin.getTriesRemaining() == 0)
return false;
return true;
} // end of select method
/**
*
* perform any cleanup and bookkeeping tasks before
*
* the applet is deselected
*/
public void deselect() {
// reset the pin
pin.reset();
}
/**
*
* process APDUs
*/
public void process(APDU apdu) {
// APDU object carries a byte array (buffer) to
// transfer incoming and outgoing APDU header
// and data bytes between the card and the host
// at this point, only the first five bytes
// [CLA, INS, P1, P2, P3] are available in
// the APDU buffer
byte[] buffer = apdu.getBuffer();
// return if the APDU is the applet SELECT command
if (selectingApplet())
return;
// verify the CLA byte
if (buffer[ISO7816.OFFSET_CLA] != Wallet_CLA)
ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
// check the INS byte to decide which service method to call
switch (buffer[ISO7816.OFFSET_INS]) {
case GET_BALANCE:
getBalance(apdu);
return;
case DEBIT:
debit(apdu);
return;
case CREDIT:
credit(apdu);
return;
case VERIFY:
verify(apdu);
return;
default:
ISOException.throwIt
(ISO7816.SW_INS_NOT_SUPPORTED);
}
} // end of process method
/**
*
* add money to the wallet
*/
private void credit(APDU apdu) {
// verify authentication
if (!pin.isValidated())
ISOException.throwIt(SW_PIN_VERIFICATION_REQUIRED);
byte[] buffer = apdu.getBuffer();
// get the number of bytes in the
// data field of the command APDU
byte numBytes = buffer[ISO7816.OFFSET_LC];
// recieve data
// data are read into the apdu buffer
// at the offset ISO7816.OFFSET_CDATA
byte byteRead = (byte) (apdu.setIncomingAndReceive());
// error if the number of data bytes
// read does not match the number in the Lc byte
if ((numBytes != 1) || (byteRead != 1))
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
// get the credit amount
byte creditAmount = buffer[ISO7816.OFFSET_CDATA];
// check the credit amount
if ((creditAmount > MAX_TRANSACTION_AMOUNT)
|| (creditAmount < 0))
ISOException.throwIt(SW_INVALID_TRANSACTION_AMOUNT);
// check the new balance
if ((short) (balance + creditAmount) > MAX_BALANCE)
ISOException.throwIt(SW_EXCEED_MAXIMUM_BALANCE);
// credit the amount
balance = (short) (balance + creditAmount);
return;
} // end of deposit method
/**
*
* withdraw money from the wallet
*/
private void debit(APDU apdu) {
// verify authentication
if (!pin.isValidated())
ISOException.throwIt(SW_PIN_VERIFICATION_REQUIRED);
byte[] buffer = apdu.getBuffer();
byte numBytes = (byte) (buffer[ISO7816.OFFSET_LC]);
byte byteRead = (byte) (apdu.setIncomingAndReceive());
if ((numBytes != 1) || (byteRead != 1))
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
// get debit amount
byte debitAmount = buffer[ISO7816.OFFSET_CDATA];
// check debit amount
if ((debitAmount > MAX_TRANSACTION_AMOUNT)
|| (debitAmount < 0))
ISOException.throwIt(SW_INVALID_TRANSACTION_AMOUNT);
// check the new balance
if ((short) (balance - debitAmount) < (short) 0)
ISOException.throwIt(SW_NEGATIVE_BALANCE);
balance = (short) (balance - debitAmount);
} // end of debit method
/**
*
* the method returns the wallet’s balance
*/
private void getBalance(APDU apdu) {
byte[] buffer = apdu.getBuffer();
// for(short i=0;i<buffer.length;i++)
// {
// System.out.println((byte)buffer[i]);
// }
// System.out.println((short)0);
// inform the JCRE that the applet has data to return
short le = apdu.setOutgoing();
// set the actual number of the outgoing data bytes
apdu.setOutgoingLength((byte) 2);
// write the balance into the APDU buffer at the offset 0
Util.setShort(buffer, (short) 0, balance);
// send the 2-byte balance at the offset
// 0 in the apdu buffer
apdu.sendBytes((short) 0, (short) 2);
} // end of getBalance method
/**
*
* verify the PIN
*/
private void verify(APDU apdu) {
byte[] buffer = apdu.getBuffer();
// receive the PIN data for validation.
byte byteRead = (byte) (apdu.setIncomingAndReceive());
// check pin
// the PIN data is read into the APDU buffer
// starting at the offset ISO7816.OFFSET_CDATA
// the PIN data length = byteRead
if (pin.check(buffer, ISO7816.OFFSET_CDATA, byteRead) == false)
ISOException.throwIt(SW_VERIFICATION_FAILED);
} // end of verify method
}
How the simulator works?
Netbeans uses Java Card Development kit tools to simulate Java Card. Communication with the simulator requires a little socket programming, but the JCDK provided a library for that already. It is named APDUIO. You can find it and its documentations in the JCDK.
Those ports that Netbeans assign to the simulator is 9025 (for contact) and 9026 (for contactless) by default. But you can change them simply.
How to change Java Card simulator configurations in Netbeans?
1-Go to Services tab, do a right click on Java card Runtime and then select Java Platforms:
2- Select Bundled Java Card and then click on Manage Devices:
3- There, you can change the configured ports:
How to communicate with the simulator via code?
First turn on the simulator in the Netbeans, and then run this program:
package testapduio;
import com.sun.javacard.apduio.*;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Arrays;
public class TestAPDUIO {
public static void main(String[] args) {
CadClientInterface cad;
Socket sock;
Apdu apdu = new Apdu();
apdu.command = new byte[]{(byte) 0x00, (byte) 0xa4, (byte) 0x04, (byte) 0x00, (byte) 0x00};
try {
sock = new Socket("localhost", 9025);
InputStream is = sock.getInputStream();
OutputStream os = sock.getOutputStream();
cad = CadDevice.getCadClientInstance(CadDevice.PROTOCOL_T1, is, os);
byte[] ATR = cad.powerUp();
System.out.println("Answer To Reset:\n");
System.out.println(Arrays.toString(ATR));
byte[] input = apdu.getDataIn();
byte[] output = apdu.getDataOut();
System.out.println("-----------------");
System.out.println(input);
System.out.println("\n");
System.out.println(output);
cad.exchangeApdu(apdu);
System.out.println("-----------------");
System.out.println(input);
System.out.println("\n");
System.out.println(output);
cad.powerDown();
} catch (Exception e) {
System.out.println("Exception Occurred");
}
}
}
Note that, as you see in the imports above, you need to add the apduio library from Java Card Development Kit package, to your project'c library in Netbeans.
I working on HTTP Traffic Data set which is composed of complete POST and GET request Like given below. I have written code in java that has separated each of these request and saved it as string element in array list. Now i am confused how to parse these raw HTTP request in java is there any method better than manual parsing?
GET http://localhost:8080/tienda1/imagenes/3.gif/ HTTP/1.1
User-Agent: Mozilla/5.0 (compatible; Konqueror/3.5; Linux) KHTML/3.5.8 (like Gecko)
Pragma: no-cache
Cache-control: no-cache
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Encoding: x-gzip, x-deflate, gzip, deflate
Accept-Charset: utf-8, utf-8;q=0.5, *;q=0.5
Accept-Language: en
Host: localhost:8080
Cookie: JSESSIONID=FB018FFB06011CFABD60D8E8AD58CA21
Connection: close
Here is a General Http Request Parser For all Method types (GET, POST, etc.) for your convinience:
package util.dpi.capture;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.Hashtable;
/**
* Class for HTTP request parsing as defined by RFC 2612:
*
* Request = Request-Line ; Section 5.1 (( general-header ; Section 4.5 |
* request-header ; Section 5.3 | entity-header ) CRLF) ; Section 7.1 CRLF [
* message-body ] ; Section 4.3
*
* #author izelaya
*
*/
public class HttpRequestParser {
private String _requestLine;
private Hashtable<String, String> _requestHeaders;
private StringBuffer _messagetBody;
public HttpRequestParser() {
_requestHeaders = new Hashtable<String, String>();
_messagetBody = new StringBuffer();
}
/**
* Parse and HTTP request.
*
* #param request
* String holding http request.
* #throws IOException
* If an I/O error occurs reading the input stream.
* #throws HttpFormatException
* If HTTP Request is malformed
*/
public void parseRequest(String request) throws IOException, HttpFormatException {
BufferedReader reader = new BufferedReader(new StringReader(request));
setRequestLine(reader.readLine()); // Request-Line ; Section 5.1
String header = reader.readLine();
while (header.length() > 0) {
appendHeaderParameter(header);
header = reader.readLine();
}
String bodyLine = reader.readLine();
while (bodyLine != null) {
appendMessageBody(bodyLine);
bodyLine = reader.readLine();
}
}
/**
*
* 5.1 Request-Line The Request-Line begins with a method token, followed by
* the Request-URI and the protocol version, and ending with CRLF. The
* elements are separated by SP characters. No CR or LF is allowed except in
* the final CRLF sequence.
*
* #return String with Request-Line
*/
public String getRequestLine() {
return _requestLine;
}
private void setRequestLine(String requestLine) throws HttpFormatException {
if (requestLine == null || requestLine.length() == 0) {
throw new HttpFormatException("Invalid Request-Line: " + requestLine);
}
_requestLine = requestLine;
}
private void appendHeaderParameter(String header) throws HttpFormatException {
int idx = header.indexOf(":");
if (idx == -1) {
throw new HttpFormatException("Invalid Header Parameter: " + header);
}
_requestHeaders.put(header.substring(0, idx), header.substring(idx + 1, header.length()));
}
/**
* The message-body (if any) of an HTTP message is used to carry the
* entity-body associated with the request or response. The message-body
* differs from the entity-body only when a transfer-coding has been
* applied, as indicated by the Transfer-Encoding header field (section
* 14.41).
* #return String with message-body
*/
public String getMessageBody() {
return _messagetBody.toString();
}
private void appendMessageBody(String bodyLine) {
_messagetBody.append(bodyLine).append("\r\n");
}
/**
* For list of available headers refer to sections: 4.5, 5.3, 7.1 of RFC 2616
* #param headerName Name of header
* #return String with the value of the header or null if not found.
*/
public String getHeaderParam(String headerName){
return _requestHeaders.get(headerName);
}
}
I [am] working on [an] HTTP Traffic Data set which is composed of complete POST and GET request[s]
So you want to parse a file or list that contains multiple HTTP requests. What data do you want to extract? Anyway here is a Java HTTP parsing class, which can read the method, version and URI used in the request-line, and that reads all headers into a Hashtable.
You can use that one or write one yourself if you feel like reinventing the wheel. Take a look at the RFC to see what a request looks like in order to parse it correctly:
Request = Request-Line ; Section 5.1
*(( general-header ; Section 4.5
| request-header ; Section 5.3
| entity-header ) CRLF) ; Section 7.1
CRLF
[ message-body ] ; Section 4.3
If you just want to send the raw request as it is, it's very easy, just send the actual String using a TCP socket!
Something like this:
Socket socket = new Socket(host, port);
BufferedWriter out = new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream(), "UTF8"));
for (String line : getContents(request)) {
System.out.println(line);
out.write(line + "\r\n");
}
out.write("\r\n");
out.flush();
See this blog post by JoeJag for the full code.
UPDATE
I started a project, RawHTTP to provide HTTP parsers for request, responses, headers etc... it turned out so good that it makes it quite easy to write HTTP servers and clients on top of it. Check it out if you're looking for something lowl level.