Decode Drivers Licence Barcode

There are many companies out there. I admire your resolve, but honestly, it is highly unlikely you will ever figure out how to render the image.

If you're interested in using a reliable off the shelf solution, drop me a mail on [email protected]
 
First I used the following code

private byte[] HexToByteArray(string hex)
{
return Enumerable.Range(0, hex.Length)
.Where(x => x % 2 == 0)
.Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
.ToArray();
}

To take the hex to a byte array, the byte array should then be a length of 720 bytes.

Then I used the code sweettoe provided (skip 6 then take 128 bytes).

So in the end my code looks like the following

Code:
using System;
using System.IO;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Math;

namespace Drivers
{
    class MainClass
    {
        private static byte[] GetPaddedValue (BigInteger value, int length)
        {
            byte[] result = value.ToByteArrayUnsigned();
            byte[] padded = new byte[length];
            Buffer.BlockCopy (result, 0, padded, (length - result.Length), result.Length);
            return padded;
        }

        private byte[] HexToByteArray(string hex)
        {
            return Enumerable.Range(0, hex.Length)
                             .Where(x => x % 2 == 0)
                             .Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
                             .ToArray();
        }

        private static byte[] EncryptValue (byte[] rgb, BigInteger e, BigInteger n, int size) 
        {
            BigInteger input = new BigInteger (rgb);
            BigInteger output = input.ModPow (e, n);
            byte[] result = GetPaddedValue (output, size);
            return result;
        }

        public static void Main (string[] args)
        {
            string longKey = @"-----BEGIN RSA PUBLIC KEY-----
MIGWAoGBAMqfGO9sPz+kxaRh/qVKsZQGul7NdG1gonSS3KPXTjtcHTFfexA4MkGA
mwKeu9XeTRFgMMxX99WmyaFvNzuxSlCFI/foCkx0TZCFZjpKFHLXryxWrkG1Bl9+
+gKTvTJ4rWk1RvnxYhm3n/Rxo2NoJM/822Oo7YBZ5rmk8NuJU4HLAhAYcJLaZFTO
sYU+aRX4RmoF
-----END RSA PUBLIC KEY-----";

            string input = "019b0945000060e9a27a1e475f89af17cb3a5ae86bd91152d22fbca1f462ba8bd39e9341bb26ad82e3ab1b4e68069247b75286edb64fed476c1a444bba7ffeca8ac9ddcf629ac582a865b8eefec682f33de40e68a6fc08265df86ad058376db56e4a9d2a2da285d11f408493fb4706abc346632a156b517c87b58372a3afda8be11dbae4a8f5a3d1881559ce0c69acd026770fd9e75c28c4abd0b2796e70eca894d8546bd8456bdcd9af0aa112f78b56523471b46805ae844a66108ba2f12a28180e5ddded48436239eae212c6193d351201e6a24613d2482ddae552bf7e21729246667a9cd5c730ba4b80736586f5f90894b1017fcea7b299cd6241a266c4b7b28b704de1f0266025358d134686e1cac2ba9af74ea16b9524f4fca20792d2618beec8499dbab596f5a56531f26462c996dad5e1278400a5266c5b5aed2dd3cae135821148bdfd3d564ac127c90d3a125031cb263e63879dfdd10725dc80225a700e5d259a5a1d2340d7bd2d3fecc9b078e1726661e2c51b945b56d762fa3067f2b926dd2707a74e1535abf1a7ee09b0ec40689cd3b3b9995dfdda9b5f33482f1441afa48304a68b24b942464d0334d4b20c17a6f09d5db119257212f7b2d48860e22c64924dc53c03557624a020b175ef47553946ce2e60c3f2ba95865d73b2d440c2fd3eb3c9850447c249c869444dbc103d8197c5556355e6c46455b61aa0b176bcc73290b532726d4339bb35b144fecf5c5d4c5e90aef23fc9c9375ae7206f9ea5a22255365f7e0728e3360cb78562c805a4f9a2b4a674eb5af30b598b98b16227a223505e2e013e426296e8f3d1ff03d6506fa431162438afabbc4e8b9626e8821d6bd264ff9d35a2df90e2be27e0297c162a0a6bbc937f349d31413484b52ca27255b2263abde2793cb946387685de9662777cdf6808a18c3a25759ed4e6ab6410f7881b655421be87e3f3df100062f12ae806059ca3e11248557080a64e4ec6e0a46697cae4c5c5197e3defdc"
            
            using (var reader = new StringReader(longKey))
            {
                var pem = new PemReader(reader);
                var o = (RsaKeyParameters)pem.ReadObject();

                var br = new BinaryReader (HexToByteArray(input));

                br.ReadBytes (6);
                byte[] data = br.ReadBytes (128);

                var decrypted = EncryptValue (data, o.Exponent, o.Modulus, 128);
                string base64 = Convert.ToBase64String (decrypted);
                string ascii = Encoding.ASCII.GetString(decrypted);
                Console.WriteLine ("As base64: " + base64);
                Console.WriteLine ("As ASCII: " + ascii );
            } 


        }
    }
}


At this point I am stuck at decoding the decrypted content

Have a look at the following link

https://github.com/ugommirikwe/sa-license-decoder

Hope it helps. I have done all the decryption, going to do the extraction now using the above as a sample.
 
Has anybody got this to work?

I used the C# code provided in this thread to get the base64 string and when I use the github sa-license-decoder all the fields are empty.

Here is my code:

private static byte[] GetPaddedValue(BigInteger value, int length)
{
byte[] result = value.ToByteArrayUnsigned();
byte[] padded = new byte[length];
Buffer.BlockCopy(result, 0, padded, (length - result.Length), result.Length);
return padded;
}


private static byte[] HexToByteArray(string hex)
{
return Enumerable.Range(0, hex.Length)
.Where(x => x % 2 == 0)
.Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
.ToArray();
}


private static byte[] EncryptValue(byte[] rgb, BigInteger e, BigInteger n, int size)
{
BigInteger input = new BigInteger(rgb);
BigInteger output = input.ModPow(e, n);
byte[] result = GetPaddedValue(output, size);
return result;
}


public static void Main(string[] args)
{
string longKey = @"-----BEGIN RSA PUBLIC KEY-----
MIGWAoGBAMqfGO9sPz+kxaRh/qVKsZQGul7NdG1gonSS3KPXTjtcHTFfexA4MkGA
mwKeu9XeTRFgMMxX99WmyaFvNzuxSlCFI/foCkx0TZCFZjpKFHLXryxWrkG1Bl9+
+gKTvTJ4rWk1RvnxYhm3n/Rxo2NoJM/822Oo7YBZ5rmk8NuJU4HLAhAYcJLaZFTO
sYU+aRX4RmoF
-----END RSA PUBLIC KEY-----";


string input = "019b09450000..."; //Took the rest out due to security reasons


using (var reader = new StringReader(longKey))
{
var pem = new PemReader(reader);
var o = (RsaKeyParameters)pem.ReadObject();


var bytes = HexToByteArray(input);

byte[] newArray = new byte[128];
Array.Copy(bytes, 6, newArray, 0, 128); // Remove first 6 bytes, take next 128 bytes


var decrypted = EncryptValue(newArray, o.Exponent, o.Modulus, 128);
string base64 = Convert.ToBase64String(decrypted);
string ascii = Encoding.ASCII.GetString(decrypted);
Console.WriteLine("As base64: " + base64);
Console.WriteLine("As ASCII: " + ascii);
}
}


PS: This line var br = new BinaryReader(HexToByteArray(input)); gives an error Cannot convert byte[] to stream. So I made a slight change to remove the first 6 bytes and then take only the next 128 bytes.
 
Last edited:
Has anybody got this to work?

I used the C# code provided in this thread to get the base64 string and when I use the github sa-license-decoder all the fields are empty.

Here are my code:

private static byte[] GetPaddedValue(BigInteger value, int length)
{
byte[] result = value.ToByteArrayUnsigned();
byte[] padded = new byte[length];
Buffer.BlockCopy(result, 0, padded, (length - result.Length), result.Length);
return padded;
}

private static byte[] HexToByteArray(string hex)
{
return Enumerable.Range(0, hex.Length)
.Where(x => x % 2 == 0)
.Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
.ToArray();
}

private static byte[] EncryptValue(byte[] rgb, BigInteger e, BigInteger n, int size)
{
BigInteger input = new BigInteger(rgb);
BigInteger output = input.ModPow(e, n);
byte[] result = GetPaddedValue(output, size);
return result;
}

public static void Main(string[] args)
{
string longKey = @"-----BEGIN RSA PUBLIC KEY-----
MIGWAoGBAMqfGO9sPz+kxaRh/qVKsZQGul7NdG1gonSS3KPXTjtcHTFfexA4MkGA
mwKeu9XeTRFgMMxX99WmyaFvNzuxSlCFI/foCkx0TZCFZjpKFHLXryxWrkG1Bl9+
+gKTvTJ4rWk1RvnxYhm3n/Rxo2NoJM/822Oo7YBZ5rmk8NuJU4HLAhAYcJLaZFTO
sYU+aRX4RmoF
-----END RSA PUBLIC KEY-----";

string input = "019b09450000..."; //Took the rest out due to security reasons


using (var reader = new StringReader(longKey))
{
var pem = new PemReader(reader);
var o = (RsaKeyParameters)pem.ReadObject();

var bytes = HexToByteArray(input);

byte[] newArray = new byte[128];
Array.Copy(bytes, 6, newArray, 0, 128); // Remove first 6 bytes, take next 128 bytes

var decrypted = EncryptValue(newArray, o.Exponent, o.Modulus, 128);
string base64 = Convert.ToBase64String(decrypted);
string ascii = Encoding.ASCII.GetString(decrypted);
Console.WriteLine("As base64: " + base64);
Console.WriteLine("As ASCII: " + ascii);
}
}


PS: This line var br = new BinaryReader(HexToByteArray(input)); gives an error Cannot convert byte[] to stream. So I made a slight change to remove the first 6 bytes and then take only the next 128 bytes.

That javascript library doesn't work. I'm sure we've spoken before, but anyways, pm me for a commercial solution
 
I developed a SADL Decoder for the .net platform... decodes all versions of the SADL and returns all information including the greyscale image
 
got it working. I have a fully functional Library for the .net framework that returns all data including the photo
PM me if you are interested
 
I have a requirement to capture the data from the drivers barcode.
My requirement is to simply read the information from the scanned barcode for a security checkpoint "clock-in" / "clock-out" system.
I have been asked to do this in a web browser client side.

My problem is that when scanning the barcode into a textarea on a webpage, everything goes completely "wonky" due to the browser thinking the there have been some CNTL+key or SHIFT+key combinations pressed.

The scanner works very well in that is can read almost any barcode you throw at it. If I have notepad open, I can scan almost anything, but as soon as I go browser based, the issues explained above arise.

Does anybody perhaps have a javascript/jquery function that will allow me to simply filter out the "nonsense" and allow me to capture the remaining information.
 
Has anyone perhaps managed to implement the above c# code in Java that can be used in Android development? I have done a shortcut wrapper for a PDF barcode scanner that can be used in B4X (compiled the Java code into a jar file). It scans the PDF on my drivers license and I can extract the hex string. But have had no luck to convert the above c# sample code for decryption to Java.
 
Off topic to the coding thread there, but I've noticed an ugly trend where gated communities on a public road was starting to enforce license scanning and storage of this information, preventing access (to public roads) if the information is not provided.

This is probably illegal and even worse, some security companies are storing this information in contradiction of the POPI Act. (private or public). Capturing people's PCI in the name of security is not a valid legal reason under the POPI Act, you have to store that information for a legal reason. (FICA as an example, or RICA)

More info here is needed, JPSA made a nice summary of the issue.
http://blog.jp-sa.org/post/do-you-have-to-present-your-driving-licence-to-a-security-guard
 
I want to jump into the fray here to see if we can get the barcode decrypted. There must be a proper way/algorithm that we can implement in java/c#/javascript or whatever. If stupid scanning devices can read all the barcode versions, I'm sure we can figure it out.

Did anyone come right with the C# version? Decoding the image?
 
Hi Ben,

Can you please assist me with code for decoding the Drivers License barcode. We currently using C# coding standards.
Do you have the Library available?

Thanks
[email protected]
 
Sadl decryptor

Hi Ben, I am interested. Please PM me with your solution. I'd love to play with it

Hi, apologies for the late reply... Was a bit swamped the past week.

I have a rest api available at the moment but could provide a server bound library if i have to. I developed this solution to run on windows. It is a blend between c# an c++ .

How would you like to proceed?
 
A scan app I installed from the Microsoft Store reads the text info on the SA identity card. But the driver's license scan produces gibberish, as expected in light of above discussion.
 
This page is very interesting.

https://github.com/ugommirikwe/sa-license-decoder/blob/master/SPEC.md

I am some way down the road with this in Java. Got the RSA decryption sorted out And can see some of the info after Base64 conversion. Can also see the info in the nibbels after looking at the page in the above link.

Still some work to do and then of course have to search for the image in one / more of the blocks.
 
Hi,

Does anyone know off an app that can scan both License Disk as well as Drivers License. Its only used for verification purposes - so I am not worried to decrypt. I only need to make a comparison between two scans.

In simple terms - Scan Drivers License (first time) save whatever data it produces (can be gibberish), then scan it the second time and compare the two scans. If the gibberish is the same as first scan it passes, otherwise fails the check.

Thx

W
 
Hi,

Does anyone know off an app that can scan both License Disk as well as Drivers License. Its only used for verification purposes - so I am not worried to decrypt. I only need to make a comparison between two scans.

In simple terms - Scan Drivers License (first time) save whatever data it produces (can be gibberish), then scan it the second time and compare the two scans. If the gibberish is the same as first scan it passes, otherwise fails the check.

Thx

W
I can do it for Android
 
got it working. I have a fully functional Library for the .net framework that returns all data including the photo
PM me if you are interested

Hi Ben

I would love to see how this works in c#.
All i need is License number, Id and Names.

Thanks
Thomas
 
I have a requirement to capture the data from the drivers barcode.
My requirement is to simply read the information from the scanned barcode for a security checkpoint "clock-in" / "clock-out" system.
I have been asked to do this in a web browser client side.

My problem is that when scanning the barcode into a textarea on a webpage, everything goes completely "wonky" due to the browser thinking the there have been some CNTL+key or SHIFT+key combinations pressed.

The scanner works very well in that is can read almost any barcode you throw at it. If I have notepad open, I can scan almost anything, but as soon as I go browser based, the issues explained above arise.

Does anybody perhaps have a javascript/jquery function that will allow me to simply filter out the "nonsense" and allow me to capture the remaining information.
Pm me for assistance with this. Got i working using a honeywell barcode scanner
 
Top
Sign up to the MyBroadband newsletter
X