Oddtale – Writing with strangers

So to take a break in my writing, I decided to start a new project. It was first supposed to be an Easter project, but it turned out to take a lot more time than I first thought. It’s a game called “Oddtale” where anyone can register with their name and email (no password needed, yet) and write a chapter in the current story. Authors are picked at random from the current pool of registered users, and the one who gets picked can write as little or as much (there are limitations, but they are big enough to write an okay chapter) as they want. Each author, except the first one, gets a hint from the previous chapter, to make things a little easier.

One story has ten chapters, and when the current story finishes, it gets automatically published on the site for everyone to view. A few hours later, the next story starts and people can join and write on that one as well. I’m planning more advanced features like private/public writing groups for people who don’t want to wait to get picked in the main one, as well as more advanced writing tools like a wysiwyg editor with the support for bbcode tags. There are more features planned, but these two are the biggest ones that are currently in the works. I wont publish a new version for a while though as I want to see if the main idea with the site in its current state, can draw any attention. The game is pretty pointless if no one wants to play.

The address for the game is: https://oddtale.net/ (REMOVED)

Oh, and we also have a mascot (who you will see a lot more of if the game gets an active player base). The mascot was made by Nicole (Bunnico) on Fiverr.

Having some fun with reverse vending machines – part 2

Alright, so I managed to get a few more receipts!

I got 1 receipt from the same store as before, and 1 receipt from another store (with the same machine, from the looks of it at least).
We can start with the receipt from the new store as I’m not going to go very deep into that at the moment.

I recycled one can in that store, and the EAN code on the receipt was

9 801104 699975

From this we can’t really get much info more than it’s one of the following parts that are important to identify at first (since we got 1 SEK from that can)

9 801104 699975
or
9 801104 699975

Another important thing to note, is the maker and model of the machines.

The first store that I went to, uses a “Tomra T-83 HCpIII”, while the new store I went to today uses a “Tomra T-83 HCpII”.
On the Tomra website they only advertise a “Tomra T-83 HCp”, so the III and II might be a yearly model or a firmware version (since they are not visible on the machine, only on the receipt), but I’ll see if I can dig out some more information about that.

Tomra T-83 HCp website
Tomra T-83 HCp PDF

tomra-t-83hcp_p1

So the first “light” conclusion we can draw here today, is that

1: The receipts can’t be used across stores, even if they are using the same machines.
Although the exact mechanism behind this is still unknown, I have some theories:

  • The store can decide the structure of the EAN code themselves
  • The manufacturer decides the structure per customer (meaning that it could be the same structure in the same chain of stores, although I have to confirm this later)
  • The structure of the EAN depends on the Firmware version (or that II and III model numbers which I have yet to figure out what they more exactly) – friend suggested this one

Now, putting that aside for now (since I only have one receipt anyway, and I want to finish figuring out the first store before I go with another one, although I don’t really see much point in that just yet, other than figuring out if any of the above theories are correct).

Like I mentioned before, I have a new receipt from the first store (the main one in this project).
And it looks like this:

7 cans – 1 SEK each
1 bottle – 2 SEK

And the EAN code is:

9 999900 000900

I suggested in the first blog post about this project, that it could be 907 (although I had taken 900 into consideration, I actually didn’t think it would be that since it felt the least logical to me, but hey, what the heck). So now that we know this, we now have the following list of codes (If you haven’t figured it out yet, the ones in bold are the ones I have so far):

0108
0207
0306
0405
0504
0603
0702
0801
0900
1006
2003

Now that we know all this, we’ll make another assumption.
Since we know 10 and 20, it should probably look something like this

0108
0207
0306
0405
0504
0603
0702
0801
0900
1006
1105
1204
1303
1402
1501
1600
1706
1805
1904
2003

I don’t understand why they would skip number 7 here, but the only way I can see that 20 gets number 3 as a control code is this way.
So my current assumption is that they simply use 0-8 as control numbers for 1 digit values, and 0-6 for 2 digit values.
It doesn’t feel right, and I feel that there’s more to it, but I need more data to draw any other conclusion at the moment.

But just to play around with the thought of this being the case, I made a small Perl script to print the numbers as they might look like.
The problem is here, that I don’t know what happens when the number reaches a new length in digits (like when it goes from 99 to 100), if it ignores the fact that it’s a new one and continues until the control digit reaches 0, or if it stops even if the control digit for 99 is still at 1, and then just resets to 4 right away. But I will assume the later, and then try to get a receipt for 100.

#!/usr/bin/perl
use warnings;
use strict;

my $cont = 8;
my $len = 1;
for(my $i = 1; $i <= 110; ++$i, --$cont)
{
        if($cont < 0 || $len < length($i))
        {
                $len = length($i);
                $cont = 10 - (length($i) * 2);
        }

        print $i . '0' . $cont . "n";
}

To be continued!

Butterflylabs Single SC 60GH/s miner arrived

So, finally I got my bitcoin miner that I ordered on the 1st of February 2013.
I’m hoping that I will be able to make some profit out of it, but it’s mostly for fun, so even if I don’t, I’m still happy to just play around.

Anyway, so the first thing I did was to unpack the miner and just generally check it out before I plug it in, just to make sure that I don’t miss anything, like an important manual or such.
I could only find one thing, which was a switch between 110V and 220V, which felt pretty important since I live in Europe, so I made sure it was set to 220V.

Not much more than that, so I plugged it into the computer for a test run, and then plugged in the power to the miner, suddenly the power unit for the miner literally exploded into fire and smoke. Shocked and angry at the sight of what is currently happening before my eyes, I quickly unplugged everything and carried the PSU in the cables (carried it at the end of the cable as to not get burned from the fire, although rather small fire, it was mostly smoke) to the bathroom, where I threw it in the bathtub and showered it with water.

So, at that moment a lot of thoughts where running through my mind, one being “fuck” and another one being “maybe the miner is still intact!”.
The apartment smelled like shit from all the smoke, so I opened a window and went back to the miner to see what I could do.

A thing I noticed about the PSU that was comfortably placed in the bathtub, was that the little switched I flipped before, had fallen into the unit, and was no longer visible.
So I’m thinking that the switch being broken might have been the reason for the incident, but meh, I prefer to use my own PSU anyway, so it doesn’t matter much, except for the fact that my apartment almost got threatened there for a second.

Now, I’ve read about the miner a lot on the Butterflylabs forum before I got it, to see what other people where experiencing when they got it, and a lot of them did not get a power unit with the package, and thus had to get their own. So a normal PSU for any computer works, as long as it’s around 550W (actually I tried a 550W but it didn’t work, so not sure about that one, but it’s what I have read) and has two PCIe cables that can be used for the miner.

The PSU in my server is modular, so I went and fetched two PCIe cables from the “dungeon” and plugged it in.
And voila, it started!

So, this doesn’t say much actually, since there still might be damaged parts in it from the little explosion before, so I needed to check that first.
And a quick check at least showed me that the machine detected the miner.

cats@Teresa:~$ lsusb | grep -i ft
Bus 001 Device 002: ID 0403:6014 Future Technology Devices International, Ltd FT232H Single HS USB-UART/FIFO IC

cats@Teresa:~$ dmesg | tail
[ 1317.675589] ftdi_sio 1-6:1.0: device disconnected
[ 1317.677817] ftdi_sio 1-6:1.0: FTDI USB Serial Device converter detected
[ 1317.677859] usb 1-6: Detected FT232H
[ 1317.677863] usb 1-6: Number of endpoints 2
[ 1317.677867] usb 1-6: Endpoint 1 MaxPacketSize 512
[ 1317.677870] usb 1-6: Endpoint 2 MaxPacketSize 512
[ 1317.677873] usb 1-6: Setting MaxPacketSize 512
[ 1317.678303] usb 1-6: FTDI USB Serial Device converter now attached to ttyUSB0
[ 1318.061040] ftdi_sio ttyUSB0: FTDI USB Serial Device converter now disconnected from ttyUSB0
[ 1318.061062] ftdi_sio 1-6:1.0: device disconnected

So from here I had some other trouble with the server, which eventually forced me to reinstall the whole damn machine, but that’s another story.
Now I could try to run cgminer and see if it worked with the bitcoin.cz pool.

./cgminer -o http://stratum.bitcoin.cz:port -u worked.worker -p password

And the output was rather promising 🙂

cgminer version 3.5.0 – Started: [2013-10-05 16:21:03]
——————————————————————————–
(5s):59.06G (avg):58.55Gh/s | A:509454 R:3336 HW:13534 WU:798.0/m
ST: 2 SS: 0 NB: 108 LW: 533339 GF: 0 RF: 0
Connected to stratum.bitcoin.cz diff 51 with stratum as user xxx.xxxx
Block: 000cfd2757615868… Diff:149M Started: [03:06:39] Best share: 347K
——————————————————————————–
[P]ool management [G]PU management [S]ettings [D]isplay options [Q]uit
GPU 0: | OFF /5.592Mh/s | A: 3 R: 0 HW: 0 WU: 0.1/m I: 6
BAS 0: max 69C 3.26V | 58.61G/58.55Gh/s | A:509604 R:3336 HW:13535 WU:798.0/m
——————————————————————————–

So now the miner is nicely placed on the balcony (Not an open balcony, so I’m not worried about placing it there).
And since it’s fall now and winter will come soon, the temperature out there will be just right.

References:

https://forums.butterflylabs.com/showwiki.php?title=Tutorials:ASIC+Mining+on+Ubuntu+and+other+Linux+distros&redirect=no

https://forums.butterflylabs.com/jalapeno-single-sc-support/5158-been-mining-few-hours-let-me-confirm-if-all-ok.html


https://mining.bitcoin.cz

https://en.bitcoin.it/wiki/CGMiner

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:

java -jar barcode.jar numbers path barwidth barheight

Example:

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

Main.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();

	}
}

Ean13.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));
	}
}

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: https://alcor.se/2013/08/20/wrote-an-ean13-barcode-program/

Confronting the store about the problem

This is a continuation of THIS post

I went down to one of the stores today that I used in my research, to tell them about my research, the problem and so on.
I asked for the store manager, and told him about it, and then I asked if he was okay with me testing if the receipt actually worked in the scanner at the checkout.

He seemed a bit skeptical at first, but eventually he told me to follow him to the checkout, and then he asked a cashier to take the receipt and use it as if it was a normal purchase (You can scan the receipt when you are scanning your products, and the machine will deduct the amount it says on the receipt).

The receipt worked, and a few SEK (Swedish crowns) was deducted from the price (Success o/).
After this I told them that they could keep the fake receipt to do with as they wished, like destroying it or something, but they decided to keep it intact and put up a warning sign in the store for the people who work there to keep a lookout for this kind of receipt (even though it would be close to impossible to tell them apart with a few adjustments and a proper receipt printer).

I also asked them if I could use them as a reference when contacting the company that makes these machines, which they approved of.
I didn’t get the approval on paper though, and I even forgot to take any pictures from the machine in the store when it had scanned the fake receipt, but you’ll just have to believe me 🙂

All in all this turned out pretty nicely, and I will make a few more changes to the receipt template and then generator script to make it a bit more complete, and then I will make a small proof-of-concept for my solution to the problem, and then send it to Tomra that makes the machines. After all that I will consider this little project done most likely, if nothing else comes up.

The next project in line after this one that I will be blogging about, is how to break the encryption on public transport cards that use the MIFARE Classic 1K standard (using already built tools, as the encryption was broken a few years ago), and then make copies of the card, as well as altering the data on them (like how much money they have on the card).

Bottom line here is, I’m happy they didn’t call the cops 🙂

girl-anime-happy

Continuation: https://alcor.se/2013/08/20/reverse-vending-machines-wrapping-it-up/

Having fun with reverse vending machines

I have a bad habit of breaking things on purpose, just to see what would happen if I do.
And in this case, I was recycling some bottles a few weeks ago, and I happened to take a quick look at the EAN code on the receipts that I got from the machine.

receipt1

From the pictures we can immediately come to two conclusions

1: The 7 digits (read from left to right) are probably the same on all the receipts from the same machine.

2: The third digit (read from right to left) is the amount of money on the receipt

Now, these receipts are usually given to the cashier.
When given to the cashier, she/he scans them and makes sure that they’re valid and then proceeds to give you the money or takes the money off from your purchase.
The cashier then draws a line over the EAN codes of the receipts and keeps them, so that it can’t be used again.

From that behavior, and from what we saw before on the receipts, we can draw another conclusion

3: The receipt is not unique, and could be scanned as many times as we want (We could make copies of it for example)

The receipts seem to vary a bit between machines/stores (gonna check if I can find some more info on that).
But for now I’ll focus on the Tomra T-83 HCpIII that this store has.

Tomra T-83 HCp website
Tomra T-83 HCp PDF

tomra-t-83hcp_p1

Now, if you create fake receipts with a normal printer, it would probably be discovered by the cashier, since the receipts use a special kind of paper and ink.
Although those printers + paper aren’t very hard to come by, so that wouldn’t be too hard to solve.

Epson TM-T88IV

tmt88iv

But, let’s put that aside and assume that you can’t go via the cashier (My goal here is not to create fake receipts and earn a bunch of money, so going via the cashier and getting cash would be pointless here). In the store where I am conducting these little experiments, there’s a “self checkout” area, where you can draw your membership card, scan everything yourself and then pay with a credit or debit card (They have random checks at times to make sure that people aren’t cheating). Next to the machine where you scan the EAN codes of the products that you are buying, there’s a small machine where you can put in different notes (with EAN codes) with offers on (buy 2 get 70% of on the third blabla etc), but you can also put in your receipts there and it will scan it, verify it and then draw the amount of your purchase.

A few things that should be noted here are;

4: The paper with the different offers and the recycling receipts, are on different kind of papers with different ink and quality, which makes me think that there aren’t many (if any) restrictions on the size and quality of the paper and EAN code, as long as it’s readable. Thus, even if I wanted to print it on normal A4 paper that I have in my printer at home, it would probably work.

5: The company that makes this EAN code reader is not the same one that makes the reverse vending machine for recycling the cans.

6: When the paper is inserted into the EAN code reader, if the EAN is valid, the machine keeps the paper. This further confirms point 3 that the code could probably be scanned several times if we wanted (which makes me think of a few fun things we could do with those “Weekly offers” papers that we get sometimes when shopping there, but that’s for another blog entry).

Now that we know all this, we need to do a few things!

* We need to analyze the receipts and figure out what the numbers are (to make templates later)

* We need to gather info on the machines that are used in this experiment (EAN barcode printers and scanners)

* Write a program that can generate these receipts from a template (Might as well do it while I’m at it)

So these are the two receipts that I have right now

Store: ICA Kvantum (Malmborgs Mobilia Malmö)
Machine: Tomra T-83 HCpIII
EAN Code: 9 999900 000702

Store: ICA Kvantum (Malmborgs Mobilia Malmö)
Machine: Tomra T-83 HCpIII
EAN Code: 9 999900 001006

These receipts use the EAN-13 standard, and since we already concluded that the first part of the code is the same on all these receipts,
we’ll just focus on the last part of the code, the 001006 and 000702.
According to the EAN-13 standard, the last digit is always the “check digit” or “checksum”, which is calculated like this:

References:
http://en.wikipedia.org/wiki/ISBN#ISBN-13_check_digit_calculation
http://en.wikipedia.org/wiki/EAN-13

9*1 + 9*3 + 9*1 + 9*3 + 9*1 + 0*3 + 0*1 + 0*3 + 0*1 + 0*3 + 7*1 + 0*3
=
9 + 27 + 9 + 27 + 9 + 7 = 88
=>
88/10 = 8,8
(take the rest)
10 - 8 = 2
The check digit is 2

So now that we know what the check digit is and how to calculate it, let’s focus on the rest of the numbers that we have left, which is the 001006 and 000702.
If we remove the check digit, we have this

00100
00070

And since we had one receipt on 10 SEK and one with 7 SEK, this one is pretty easy to guess, that on the first one, the “10” part is the 10 SEK, and on the second one the “7” is the 7 SEK.
So from this we can conclude that reading it from left to right, we have a digit for thousand, hundred, ten, ones and a decimal (Under 1 SEK is öre, but we don’t have that as a part of our currency any longer in Sweden, so I’ll just call it decimal for now).

So now that we know all this, we can actually create a fake receipt with just about any value we want (that fits in the EAN code of course).
To try this out and see how close to the original we can get without just putting a receipt in a machine and making copies, I have created a template in LaTex where one can just insert the right values in the template, and then convert it to a picture or PDF and print it to get the finished receipt.
The template can be seen below.

Template in LaTeX:

documentclass[12pt]{article}
usepackage{lmodern}
usepackage[utf8]{inputenc}
usepackage[paperwidth=57mm,paperheight=113mm,margin=3mm]{geometry}
%usepackage{geometry}
usepackage{graphicx}
usepackage{setspace}
usepackage{color}
%usepackage{ean13}
usepackage{soul}
geometry{verbose}
makeatletter

title{ICA Kvantum T-83HCp Receipt Template}
date{today}
makeatother

begin{document}
%begin{minipage}[t]{57mm}
centering{includegraphics{STORE_LOGO_IMG}}
pagecolor{white}
vspace{1mm}

textsf{textbf{Large TITLE_PART_1}}textsf{Large {} }
{Large {} {} {} }textsf{Large {} }textsf{textbf{Large TITLE_PART_2}}{Large }

%Large space between title and total
vspace{20mm}

%Total amount of money
centering
colorbox{black}{hspace{linewidth}hspace{HSPACEfboxsep}color{white}textbf{Large TOTAL_MONEY}{Large }}{Large par}

%Tiny space between total and ean
vspace{1mm}
centering
%EAN image
includegraphics{EAN_IMG}

%Space plus ean numbers under ean
begin{spacing}{0.5}
textsf{textbf{textsc{small EAN_NUM}}}{small par}
end{spacing}

%Space between ean and bottle/can amount
vspace{4mm}

%Amount of bottles/cans
textsf{textbf{footnotesize COUNT_BOTTLE flaskor/burkar áhfill{}AMOUNT_PER_BOTTLE}}{footnotesize par}
textsf{textbf{footnotesize rule[0.5ex]{1columnwidth}{1pt}}}{footnotesize par}

begin{spacing}{0.8}
textsf{textbf{footnotesize MODEL_NAME}}{footnotesize par}
textsf{textbf{footnotesize SERIAL_NUMBER}}{footnotesize par}
textsf{textbf{footnotesize TIME DATE}}
end{spacing}
%end{minipage}
end{document}

Generator script:

gen.sh (For safety reasons, the barcode script is not included)

#!/bin/bash

# This is a generator script for the ICA Malmborgs template
# I have left out some important parts, to protect the store in question
# Usage:
# bash gen.sh total_money

# Copy template to a temporary location
cp receipt.tex /tmp/receipt.tmp.tex

#Set path, bar width and height
path="EAN_IMG.png"
barwidth=1
barheight=60

# Set the numbers for the EAN
first=9
left=999900
right=$(bash right.sh $1)

# Decide the control digit
control=$(bash control.sh $first $left $right)
echo $control

# Set hspace (it needs to differe depending on the input value)
hspace=$(bash hspace.sh $1)

# Create the barcode here named EAN_IMG.png
# You will have to figure out for yourself how to do that though
# And write the barcode script yourself
# <insert barcode call here>

# Get time and date values
time_var=$(date +%H:%M)
date_var=$(date +%d-$(echo $(date +%b) | tr '[:lower:]' '[:upper:]')-%Y)

# Replace placeholders in template
sed -i 's/STORE_LOGO_IMG/STORE_LOGO_IMG.jpg/g' /tmp/receipt.tmp.tex
sed -i 's/TITLE_PART_1/Malmborgs/g' /tmp/receipt.tmp.tex
sed -i 's/TITLE_PART_2/Mobilia/g' /tmp/receipt.tmp.tex
sed -i "s/HSPACE/$hspace/g" /tmp/receipt.tmp.tex
sed -i "s/TOTAL_MONEY/$1.00/g" /tmp/receipt.tmp.tex
sed -i 's/EAN_IMG/EAN_IMG.png/g' /tmp/receipt.tmp.tex
sed -i "s/EAN_NUM/$first \hspace{1mm} \so{$left} \hspace{1mm} \so{$right$control}/g" /tmp/receipt.tmp.tex
sed -i 's/COUNT_BOTTLE/7/g' /tmp/receipt.tmp.tex
sed -i 's/AMOUNT_PER_BOTTLE/1.00/g' /tmp/receipt.tmp.tex
sed -i 's/MODEL_NAME/Tomra 83 HCp3/g' /tmp/receipt.tmp.tex
sed -i 's/SERIAL_NUMBER/606657-90199310-01456-00/g' /tmp/receipt.tmp.tex
sed -i "s/TIME/$time_var/g" /tmp/receipt.tmp.tex
sed -i "s/DATE/$date_var/g" /tmp/receipt.tmp.tex

# Create PDF and PNG
pdflatex /tmp/receipt.tmp.tex receipt.tmp.pdf
convert receipt.tmp.pdf receipt.png

# remove temp files
rm /tmp/receipt.tmp.tex
rm EAN_IMG.png

 

hspace.sh – This one sets the hspace value (template design related)

#!/bin/bash

val=$1
hspace="-12"

#There's probably a better way to do this
if  [[ ${#val} = 1 ]] ; then
   hspace="-12"
elif  [[ ${#val} = 2 ]] ; then
   hspace="-15"
elif [[ ${#val} = 3 ]] ; then
   hspace="-20"
elif [[ ${#val} = 4 ]] ; then
   hspace="-25"
fi

echo $hspace

 

control.sh – This one calculates the control digit

#!/bin/bash

var=$1$2$3
echo $var
vartwo=0

for i in {0..11}
do
    tmp=${var:$i:1}

    if [ $(($(($i+1))%2)) -eq 0 ] ; then
        vartwo=$(($vartwo+$(($tmp*3))))
    else
        vartwo=$(($vartwo+$(($tmp*1))))
    fi
done

vartwo=$(($vartwo%10))
vartwo=$((10-$vartwo))
echo $vartwo

 

right.sh – This one calculates the right part of the EAN number

#!/bin/bash

val=$1
right=0

#There's probably a better way to do this
if  [[ ${#val} = 1 ]] ; then
   right="000${val}0"
elif  [[ ${#val} = 2 ]] ; then
   right="00${val}0"
elif [[ ${#val} = 3 ]] ; then
   right="0${val}0"
elif [[ ${#val} = 4 ]] ; then
   right="${val}0"
fi

echo $right

 

Usage:
The easiest way to use it would be to simply run the gen.sh script. As it is right now the script will probably fail, since the pictures are missing, which I will not provide right now. But when it works, it will output a pdf and a png with the receipt. An easier way to generate them will be made together with a colleague of mine, although this will probably not be release to the public, and only presented to the company that I have targeted in this little research.

bash gen.sh sek

 

Requirements

The soul LaTeX package
The lmodern fonts for LaTeX

Result:

The EAN code has been made a bit smaller now so that it can’t be scanned in the stores.
receipt

This concludes my research for now on this topic.
I have a solution for this problem that I will write about in another post later.

Click HERE for part 2