Monthly Archives: August 2013

Wrote an EAN13 barcode program

I decided to write a barcode generator in Java “for no apparent reason”, that can currently generator EAN13 barcodes. It’s available here in this post, but if you want the latest code then I suggest you check it out on github.

Github repo:
https://github.com/jra89/barcode

Usage:

[code]
java -jar barcode.jar numbers path barwidth barheight
[/code]

Example:

[code]
java -jar barcode.jar 999990000020 /home/user/Desktop/EAN_IMG.png 2 60
[/code]

Main.java

[code lang=”java”]
package barcode;

public class Main
{
public static void main(String[] args)
{
String code;
String path;
int barWidth;
int barHeight;

if(args.length <= 1)
{
System.out.println("Not enough parameters");
}

try
{
code = args[0];
}
catch(NullPointerException e)
{
code = "9999900000207";
}

try
{
path = args[1];
}
catch(NullPointerException e)
{
path = "/tmp/barcode.png";
}

try
{
barWidth = Integer.parseInt(args[2]);
}
catch(NullPointerException e)
{
barWidth = 1;
}

try
{
barHeight = Integer.parseInt(args[3]);
}
catch(NullPointerException e)
{
barHeight = 100;
}

Ean13 ean = new Ean13(code, path, barWidth, barHeight);
ean.createBarcodePNG();

}
}
[/code]

Ean13.java

[code lang=”java”]
package barcode;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;

public class Ean13
{
/**
* -=Structure=-
*
* Fist, First Six, Last Six
* LGR = 012
* 0 LLLLLL RRRRRR
* 1 LLGLGG RRRRRR
* 2 LLGGLG RRRRRR
* 3 LLGGGL RRRRRR
* 4 LGLLGG RRRRRR
* 5 LGGLLG RRRRRR
* 6 LGGGLL RRRRRR
* 7 LGLGLG RRRRRR
* 8 LGLGGL RRRRRR
* 9 LGGLGL RRRRRR
*
* -=Encodings=-
*
* Digit L-code G-code R-code
* 0 0001101 0100111 1110010
* 1 0011001 0110011 1100110
* 2 0010011 0011011 1101100
* 3 0111101 0100001 1000010
* 4 0100011 0011101 1011100
* 5 0110001 0111001 1001110
* 6 0101111 0000101 1010000
* 7 0111011 0010001 1000100
* 8 0110111 0001001 1001000
* 9 0001011 0010111 1110100
**/

private String code;
private String path;
private BufferedImage bi;
private Graphics2D ig2;
private int barPos;
private int barPosBin;
private int imgPixelPos;
private int barWidth;
private int barHeight;
private int imgWidth;
private int imgHeight;
private int[][] barcodeBinary;

private int[][] firstSix = {
{0,0,0,0,0,0}, //LLLLLL
{0,0,1,0,1,1}, //LLGLGG
{0,0,1,1,0,1}, //LLGGLG
{0,0,1,1,1,0}, //LLGGGL
{0,1,0,0,1,1}, //LGLLGG
{0,1,1,0,0,1}, //LGGLLG
{0,1,1,1,0,0}, //LGGGLL
{0,1,0,1,0,1}, //LGLGLG
{0,1,0,1,1,0}, //LGLGGL
{0,1,1,0,1,0} //LGGLGL
};

private int[] lastSix = {2, 2, 2, 2, 2, 2};

private int[][][] encodings = {
{
{0,0,0,1,1,0,1},
{0,1,0,0,1,1,1},
{1,1,1,0,0,1,0}
},
{
{0,0,1,1,0,0,1},
{0,1,1,0,0,1,1},
{1,1,0,0,1,1,0}
},
{
{0,0,1,0,0,1,1},
{0,0,1,1,0,1,1},
{1,1,0,1,1,0,0}
},
{
{0,1,1,1,1,0,1},
{0,1,0,0,0,0,1},
{1,0,0,0,0,1,0}
},
{
{0,1,0,0,0,1,1},
{0,0,1,1,1,0,1},
{1,0,1,1,1,0,0}
},
{
{0,1,1,0,0,0,1},
{0,1,1,1,0,0,1},
{1,0,0,1,1,1,0}
},
{
{0,1,0,1,1,1,1},
{0,0,0,0,1,0,1},
{1,0,1,0,0,0,0}
},
{
{0,1,1,1,0,1,1},
{0,0,1,0,0,0,1},
{1,0,0,0,1,0,0}
},
{
{0,1,1,0,1,1,1},
{0,0,0,1,0,0,1},
{1,0,0,1,0,0,0}
},
{
{0,0,0,1,0,1,1},
{0,0,1,0,1,1,1},
{1,1,1,0,1,0,0}
}
};

Ean13(String code, String path,int barWidth, int barHeight)
{
this.code = code;
this.path = path;
this.barPos = 12;
this.barPosBin = 7;
this.imgPixelPos = 0;
this.barcodeBinary = new int[barPos][barPosBin];
this.barWidth = barWidth;
this.barHeight = barHeight;
this.imgWidth = ((12*7) + (2*9) + (2*3) + (1*5)) * this.barWidth;
this.imgHeight = this.barHeight;
}

public void createBarcodePNG()
{
this.code += Integer.toString(calculateControlDigit(this.code));
generateBinaryMap();
generateBarcodePNG();
}

private void generateBinaryMap()
{
int first = Integer.parseInt(String.valueOf(this.code.charAt(0)));

//i = 1, first digit is not welcome to the bar
for(int i = 1; i < 13; ++i)
{
int current = Integer.parseInt(String.valueOf(this.code.charAt(i)));

if(i < 7)
this.barcodeBinary[i-1] = this.encodings[current][this.firstSix[first][i-1]];
else
this.barcodeBinary[i-1] = this.encodings[current][this.lastSix[i-7]];
}
}

private void generateBarcodePNG()
{
try {
// TYPE_INT_ARGB specifies the image format: 8-bit RGBA packed
// into integer pixels
bi = new BufferedImage(this.imgWidth, this.imgHeight, BufferedImage.TYPE_INT_ARGB);
ig2 = bi.createGraphics();

ig2.setPaint(Color.white);
ig2.fillRect ( 0, 0, bi.getWidth(), bi.getHeight() );

//Draw quiet zone
drawSpecial(0);

//Draw lead
drawSpecial(1);

//Draw first group
drawGroup(1);

//Draw separator
drawSpecial(2);

//Draw second group
drawGroup(2);

//Draw lead
drawSpecial(1);

//Draw quiet zone
drawSpecial(0);

ImageIO.write(bi, "PNG", new File(path));

} catch (IOException ie) {
ie.printStackTrace();
}
}

private void drawGroup(int groupPart)
{
int i = 0, length = 0;
if(groupPart == 1)
{
i = 0;
length = (this.barcodeBinary.length/2);
}
else if(groupPart == 2)
{
i = 6;
length = this.barcodeBinary.length;
}

for(; i < length; ++i)
{
for(int n = 0; n < this.barcodeBinary[i].length; ++n)
{
if(this.barcodeBinary[i][n] == 0)
{
ig2.setPaint(Color.white);
ig2.setStroke(new BasicStroke(this.barWidth));
}
else
{
ig2.setPaint(Color.black);
ig2.setStroke(new BasicStroke(this.barWidth));
}

int pos = this.imgPixelPos;
ig2.drawLine(pos,0,pos,this.barHeight);
this.imgPixelPos += this.barWidth;
}
}
}

private void drawSpecial(int type)
{

/*
Special Symbol Pattern
Quite Zone 000000000
Lead / Trailer 101
Separator 01010
*/

int[] quiteZone = {0,0,0,0,0,0,0,0,0};
int[] leadtrail = {1,0,1};
int[] separator = {0,1,0,1,0};
int binaryArrLength = 0;
int[] arr;

if(type == 0)
{
binaryArrLength = quiteZone.length;
arr = quiteZone;
}
else if(type == 1)
{
binaryArrLength = leadtrail.length;
arr = leadtrail;
}
else
{
binaryArrLength = separator.length;
arr = separator;
}

for(int n = 0; n < binaryArrLength; ++n)
{
if(arr[n] == 0)
ig2.setPaint(Color.white);
else
ig2.setPaint(Color.black);

int pos = this.imgPixelPos;
ig2.drawLine(pos,0,pos,this.barHeight);
this.imgPixelPos += this.barWidth;
}
}

public int calculateControlDigit(String ean)
{
int sum = 0;
for(int i = 0; i < 12; ++i)
{
int val = charToInt(ean.charAt(i));
if((i+1)%2 == 0)
sum += val*3;
else
sum += val*1;
}

return (10 – (sum % 10));
}

private int charToInt(char c)
{
return Integer.parseInt(String.valueOf(c));
}
}
[/code]

Reverse vending machines, wrapping it up

Ok so I thought it would be a good idea to wrap things up around this project now. I’ve been doing a lot more work on it now, perfecting the scripts and so on. I even wrote my own barcode program in Java (for fun), and bought a receipt printer so that I could perfect my proof-of-concept receipt.

I also got a new reply from Tomra about my questions, and it seems that they have been forwarding my email around in their company, and then forgot to remove their subject line when finally sending me an answer. And thus the subject was something like “A lot of spam from the same customer” … cute. But the answer I got was the same as usual, as in “We have a solution that has been working for a long time now that we believe in, so we can’t tell you more about it. Thank you for your interest”. Of course I understand their view on this, as it is a very expensive piece of machinery and not something they will just openly expose everything about to random people like me. I haven’t been able to find a store with this security yet, although I got a receipt a few days ago that indicates something unusual, so if I get the time for it, I might actually check that out as well, just for fun, and to see if there actually is some security.

The kind of security that I can imagine that they have, is some sort of control number on the receipt that is stored in a database and then removed from the database when the receipt is scanned by the cashier (I have seen some receipts with an expiration date of 2 months and such, which would indicate something like that). Of course this security will hold pretty ok, except if the store has one of those self checkouts, where the customer scans all the receipts themselves, since then you can try to have a bunch of receipts with you and try every time you shop, and if you are lucky there will be a matching receipt in the database (of course this will be extremely hard since the control number and amount of money on the receipt will probably have to match, and thus making this pretty meaningless to attempt).

My solution is actually similar to theirs, with the control number and everything, except that I have two approaches.
The first method is to do it like they probably have, as in having a control number and then have the machine add it to a database that the cash machines check when scanning the receipt.
But instead of using an EAN code, the receipt would have a QR code (which can store a lot more data than an EAN code can) that contains PGP encrypted data. The machine would have the public key and the cash machine would have the private one, and the data stored would be the amount of money and a control number.

The second solution is one where the machine does not have any contact to a database or any kind of network at all.
The receipt would still have a QR code with almost the same encrypted data, but it would also have the date when it was created, so that when it is scanned, it is added to the database then, instead of being removed at the time of scanning, and if the date has passed the expiration, it will not be added and be counted as invalid, and if it’s valid, it will be added and then kept for the time it is valid, and then removed by the system. This way the machine wont have to be connected all the time.

Anyway enough about that, so I actually bought 2 printers, one being an Epson TM-T88IV, and the second one a Star TSP100 ECO. I had a lot of trouble with the Epson one at first, so I bought the Star one since I read some pretty good reviews about it, and then it turned out that I had configured the Epson wrongly (I discovered this when I was playing around with the Star one, so I guess it was worth it in a way).

I will fix the Epson one a bit, clean it, add a driver DVD, make a short manual and add a cable for it (didn’t get a cable when I bought it).
And when I finish fixing it, I will try to sell it for a bit more than what I got it for (it was in bad shape when I got it, but it’s mostly fixed now).

The Star one that you can see below, was in really neat condition and works very well, so I will keep it for future projects.

2013-08-20 18.20.41

So with this I printed out some example receipts first, to try the quality.

2013-08-20 18.29.31

And then with my new barcode program and the updates that I made to the scripts, I could finally print a very good looking and authentic “fake” receipt! 🙂
As you can see on the fake one to the left, the barcode is a bit smaller, and this is due to me being a little bit lazy now at the end (The barcode program isn’t 100% finished yet, but I will fix it more later so that it can make the barcode a bit wider, but I don’t have much time for it right now).

2013-08-20 18.20.12

I tried to scan the barcode on the fake one as well, just to make sure that it worked.

2013-08-20 18.17.57

As you can see, the real one to the right is a bit old and the color is about to go away, but the strength of the color would be about the same as the fake one.
Do note that the “ink” and paper of the fake one, is the same as the real one, so it would be very hard to tell them apart in the store.
And with just a little bit more work, you could make them exactly identical, but I think I have made my point now, so I wont go into that.

Hint: http://blog.alcor.se/index.php/2013/08/20/wrote-an-ean13-barcode-program/

Using Java to connect with SSLSocket, trusting all certificates

So I wanted to make a little test client that would connect to a web server via SSL.
The problem is that in this experiment I don’t really care about the security, so I want the client to accept all certificates, even self signed ones and very old ones.
Credits to my good friend Maboroshi who helped me find the final solution that solved the last problem with the invalid certs.

So the first thing I did was to write the following.
This is a safe code that does NOT accept invalid certificates of any kind.

SAFE
[code lang=”java”]
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import java.io.*;
import java.net.Socket;

public class test {
public static void main(String[] arstring) {
try {
//Connect without SSL
Socket clientSocket = new Socket("google.com", 80);
DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream());
BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));

outToServer.writeBytes("GET / HTTP/1.1\nHost: google.com\n\n");
System.out.println("No SSL – " + inFromServer.readLine());
clientSocket.close();

//Connect with SSL
SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket("google.com", 443);

DataOutputStream outToServerSSL = new DataOutputStream(sslsocket.getOutputStream());
BufferedReader inFromServerSSL = new BufferedReader(new InputStreamReader(sslsocket.getInputStream()));

outToServerSSL.writeBytes("GET / HTTP/1.1\nHost: google.com\n\n");
System.out.println("SSL – " + inFromServerSSL.readLine());

} catch (Exception exception) {
exception.printStackTrace();
}
}
}
[/code]

The problem with the above code for me, was that when connecting to a server with an invalid certificate, I got the following error.

Exception in thread “main” javax.net.ssl.SSLHandshakeException:
sun.security.validator.ValidatorException: PKIX path building failed:
sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(Unknown Source)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source)

Thus, that solution wont cut it!
I needed something else, so I tried to write some code that would accept all certs as well.
Please note that ALL of the code from here on is UNSAFE, and should NOT be used in a production environment.


Reference to solution

UNSAFE
[code lang=”java”]
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509TrustManager;
import java.io.*;
import java.net.Socket;
import javax.net.ssl.TrustManager;
import java.security.cert.X509Certificate;

public class ssl {
public static void main(String[] arstring) {

try {
//Connect without SSL
Socket clientSocket = new Socket("google.com", 80);
DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream());
BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));

outToServer.writeBytes("GET / HTTP/1.1\nHost: google.com\n\n");
System.out.println("No SSL – " + inFromServer.readLine());
clientSocket.close();

//Connect with SSL
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}

@Override
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}

@Override
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}
};

// Install the all-trusting trust manager
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());

SSLSocketFactory sslsocketfactory = sc.getSocketFactory();
SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket("google.com", 443);

DataOutputStream outToServerSSL = new DataOutputStream(sslsocket.getOutputStream());
BufferedReader inFromServerSSL = new BufferedReader(new InputStreamReader(sslsocket.getInputStream()));

outToServerSSL.writeBytes("GET / HTTP/1.1\nHost: google.com\n\n");
System.out.println("SSL – " + inFromServerSSL.readLine());

} catch (Exception exception) {
exception.printStackTrace();
}
}
}
[/code]

But, now this gives me a different error because this invalid certificate is broken/old!

javax.net.ssl.SSLProtocolException: no more data allowed for version 1 certificate
at sun.security.ssl.HandshakeMessage$CertificateMsg.(HandshakeMessage.java:431)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:153)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:609)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:545)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:963)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1208)
at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:674)
at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:119)
at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:133)
at java.io.DataOutputStream.writeBytes(DataOutputStream.java:276)
at ssl.main(ssl.java:93)
Caused by: java.security.cert.CertificateParsingException: no more data allowed for version 1 certificate
at sun.security.x509.X509CertInfo.parse(X509CertInfo.java:710)
at sun.security.x509.X509CertInfo.(X509CertInfo.java:169)
at sun.security.x509.X509CertImpl.parse(X509CertImpl.java:1751)
at sun.security.x509.X509CertImpl.(X509CertImpl.java:196)
at sun.security.provider.X509Factory.engineGenerateCertificate(X509Factory.java:107)
at java.security.cert.CertificateFactory.generateCertificate(CertificateFactory.java:322)
at sun.security.ssl.HandshakeMessage$CertificateMsg.(HandshakeMessage.java:429)
… 10 more

Ok, so this is where it got tricky to solve.
I googled around for some time but I couldn’t really find a solution (since usually this is not the kind of thing you want to do).

But then a friend of mine (Maboroshi), pointed me to this site

Which brought me to this final solution.
The only real change here was to use the BouncyCastle provider

[code lang=”java”]
Security.insertProviderAt(new BouncyCastleProvider(), 1);
[/code]

Which can be found HERE

Another requirement that I came to think about, is that this change requires Java 6 since Java 7 doesn’t support MD2. There is a solution if you are running Java 7 though.

Just open this file

[code]
JDK_HOME/jre/lib/security/java.security
[/code]

And comment out the following line

[code]
jdk.certpath.disabledAlgorithms=MD2
[/code]

That should do the trick.
Solution was found HERE

UNSAFE
[code lang=”java”]
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509TrustManager;
import java.io.*;
import java.net.Socket;
import javax.net.ssl.TrustManager;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.security.cert.X509Certificate;
import java.security.Security;

public class ssl {
public static void main(String[] arstring) {
Security.insertProviderAt(new BouncyCastleProvider(), 1);

try {
//Connect without SSL

Socket clientSocket = new Socket("google.com", 80);
DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream());
BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));

outToServer.writeBytes("GET / HTTP/1.1\nHost: google.com\n\n");
System.out.println("No SSL – " + inFromServer.readLine());
clientSocket.close();

//Connect with SSL

// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() {
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}

@Override
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}

@Override
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}
};

// Install the all-trusting trust manager
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());

SSLSocketFactory sslsocketfactory = sc.getSocketFactory();
SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket("google.com", 443);

DataOutputStream outToServerSSL = new DataOutputStream(sslsocket.getOutputStream());
BufferedReader inFromServerSSL = new BufferedReader(new InputStreamReader(sslsocket.getInputStream()));

outToServerSSL.writeBytes("GET / HTTP/1.1\nHost: google.com\n\n");
System.out.println("SSL – " + inFromServerSSL.readLine());

} catch (Exception exception) {
exception.printStackTrace();
}
}
}
[/code]

Now I got the output I wanted 🙂

No SSL – HTTP/1.1 200 OK
SSL – HTTP/1.1 200 OK