Decode South African (ZA) Drivers License - barcode

I am writing a solution to scan PDF417 barcode (http://en.wikipedia.org/wiki/PDF417) at the back of a South African drivers license for iOS. I can't find any documentation or specification how to decode barcode. Does anyone have a link to a specification or sample code that can decode driver license data stored in PDF417 barcode? Thanks

The data after scanning the PDF417 barcode is 720 bytes. First 4 bytes indicate the version of barcode.
Version 2 covers all currently valid licenses.
Version 1: 01 e1 02 45
Version 2: 01 9b 09 45
Next two bytes are zero (00 00).
Remaining 714 bytes form 6 blocks - 5 blocks of 128, 1 block of 74.
Different keys are used depending on version and and block size.
Version 1, 128 bytes
-----BEGIN RSA PUBLIC KEY-----
MIGXAoGBAP7S4cJ+M2MxbncxenpSxUmBOVGGvkl0dgxyUY1j4FRKSNCIszLFsMNw
x2XWXZg8H53gpCsxDMwHrncL0rYdak3M6sdXaJvcv2CEePrzEvYIfMSWw3Ys9cRl
HK7No0mfrn7bfrQOPhjrMEFw6R7VsVaqzm9DLW7KbMNYUd6MZ49nAhEAu3l//ex/
nkLJ1vebE3BZ2w==
-----END RSA PUBLIC KEY-----
Version 1, 74 bytes:
-----BEGIN RSA PUBLIC KEY-----
MGACSwD/POxrX0Djw2YUUbn8+u866wbcIynA5vTczJJ5cmcWzhW74F7tLFcRvPj1
tsj3J221xDv6owQNwBqxS5xNFvccDOXqlT8MdUxrFwIRANsFuoItmswz+rfY9Cf5
zmU=
-----END RSA PUBLIC KEY-----
Version 2, 128 bytes:
-----BEGIN RSA PUBLIC KEY-----
MIGWAoGBAMqfGO9sPz+kxaRh/qVKsZQGul7NdG1gonSS3KPXTjtcHTFfexA4MkGA
mwKeu9XeTRFgMMxX99WmyaFvNzuxSlCFI/foCkx0TZCFZjpKFHLXryxWrkG1Bl9+
+gKTvTJ4rWk1RvnxYhm3n/Rxo2NoJM/822Oo7YBZ5rmk8NuJU4HLAhAYcJLaZFTO
sYU+aRX4RmoF
-----END RSA PUBLIC KEY-----
Version 2, 74 bytes:
-----BEGIN RSA PUBLIC KEY-----
MF8CSwC0BKDfEdHKz/GhoEjU1XP5U6YsWD10klknVhpteh4rFAQlJq9wtVBUc5Dq
bsdI0w/bga20kODDahmGtASy9fae9dobZj5ZUJEw5wIQMJz+2XGf4qXiDJu0R2U4
Kw==
-----END RSA PUBLIC KEY-----
Decrypt each block separately. Decrypted with RSA ENCRYPT function using
the public key.

Based on the RSA public key, the incomplete document, and the C# open source project, I've successfully decoded the South African driving license in Python except for the image part.
Steps:
Load the RSA public key from the PEM format.
pubKey = rsa.PublicKey.load_pkcs1(pk128)
Decrypt the data decoded from PDF417:
all = bytearray()
pubKey = rsa.PublicKey.load_pkcs1(pk128)
start = 6
for i in range(5):
block = data[start: start + 128]
input = int.from_bytes(block, byteorder='big', signed=False)
output = pow(input, pubKey.e, mod=pubKey.n)
decrypted_bytes = output.to_bytes(128, byteorder='big', signed=False)
all += decrypted_bytes
start = start + 128
pubKey = rsa.PublicKey.load_pkcs1(pk74)
block = data[start: start + 74]
input = int.from_bytes(block, byteorder='big', signed=False)
output = pow(input, pubKey.e, mod=pubKey.n)
decrypted_bytes = output.to_bytes(74, byteorder='big', signed=False)
all += decrypted_bytes
Parse the data:
def parse_data(data):
index = 0
for i in range(0, len(data)):
if data[i] == 0x82:
index = i
break
# Section 1: Strings
vehicleCodes, index = readStrings(data, index + 2, 4)
print(f'Vehicle codes: {vehicleCodes}')
surname, index, delimiter = readString(data, index)
print(f'Surname: {surname}')
initials, index, delimiter = readString(data, index)
print(f'Initials: {initials}')
PrDPCode = ''
if delimiter == 0xe0:
PrDPCode, index, delimiter = readString(data, index)
print(f'PrDP Code: {PrDPCode}')
idCountryOfIssue, index, delimiter = readString(data, index)
print(f'ID Country of Issue: {idCountryOfIssue}')
licenseCountryOfIssue, index, delimiter = readString(data, index)
print(f'License Country of Issue: {licenseCountryOfIssue}')
vehicleRestrictions, index = readStrings(data, index, 4)
print(f'Vehicle Restriction: {vehicleRestrictions}')
...
You can visit https://github.com/yushulx/South-Africa-driving-license/blob/main/sadl/init.py to see the full code.
The Python package has been published to pypi.org. You can install it via pip install south-africa-driving-license.

Related

SNMP - Decode Hex String Value

This is my first question here, so hope it's correctly done.
Im trying to get some information from a ZTE C300 OLT.
The thing is when i try to get the SN of one of the ONTS I get the response in HEX-String
snmpwalk -cpublic -v2c [OLTIP] 1.3.6.1.4.1.3902.1082.500.10.2.2.5.1.2
And this is the response that I get
SNMPv2-SMI::enterprises.3902.1082.500.10.2.2.5.1.2.285278736.1 = Hex-STRING: 5A 54 45 47 C8 79 9B 27
This is the SN that i have on the OLT ZTEGC8799B27, but im trying to convert the HEX-STRING into text and i don't get that SN text.
Indeed i have a python script for SNMP and the response that i get for that OID is
{'1.3.6.1.4.1.3902.1082.500.10.2.2.5.1.2.285278736.1': "ZTEGÈy\x9b'"}
Can someone give me a hand on this?. I'm new on SNMP and this is giving me some headache.
Thanks in advace!
This is a 8 octet hex string, the first 4 octets are ASCII.
Just convert hex 2 ascii.
Indeed it was easier. The firts 4 bytes were encoded, and the other 4 is the actual serial number splitted every 2 digits. So i only need to decode the first part and concatenate the rest.
Works with OLT ZTE C320
def hex_str(str):
str = str.strip()
str = str.split(' ')
vendor_id = ''
serial = str[4:]
serial = "".join(serial)
for hex_byte in str[:4]:
vendor_id += chr(int(hex_byte, 16))
normalized_serial = vendor_id + serial
return normalized_serial
def ascii_to_hex(str):
arr = []
hex_byte = ''
for i in range(len(str)):
hex_byte += hex(ord(str[i]))
hex_byte = hex_byte.replace('0x', ' ')
hex_byte = hex_str(hex_byte)
return hex_byte
# value = f"5A 54 45 47 C8 79 9B 27 "
# value = f"49 54 42 53 8B 69 A2 45 "
# value = f"ZTEGÈy\x9b'"
value = f"ITBS2Lz/"
# value = f"ITBS2HP#"
if(len(value) == 24):
print(hex_str(value))
else:
print(ascii_to_hex(value))

Understand `openssl speed`

I ran openssl speed rsa512 and it shows me how many signs and verifies it can do in a second. Unfortunalely, the test does not say anything about the message size, which is signed. Thus I digged into the openssl sources and found the following line in the speed.c:
ret = RSA_sign(NID_md5_sha1, buf, 36, buf2, rsa_num, rsa_key[testnum]);
Looking into the function in the rsa.h, I can see the following function declaration:
int RSA_sign(int type, const unsigned char *m, unsigned int m_length,
unsigned char *sigret, unsigned int *siglen, RSA *rsa);
I guess, m is the message and m_length is the length of the message.
Am I right that the message size is 36 byte in the RSA speed test?
The same goes for ECDSA, e.g., openssl speed ecdsap256. The speed.c uses the following line:
ret = ECDSA_sign(0, buf, 20, ecdsasig, ecdsasiglen, ecdsa[testnum]);
Am I right that the message size is 20 byte in the ECDSA speed test?
My Conclusion: It's not possible to compare them, since they sign different message lengths.
Asymmetric signatures, technically, don't sign messages. They sign hashes of messages.
Their rsa512 test is doing the RSA signature padding and transformation on an SSL "MD5 and SHA1" value (which is 16 + 20 = 36 bytes). So the number it produces is how many RSA pad-and-sign (and answer-copy) operations it can do, you need to divide that by the time it takes to hash the message.
Their ecdsap256 computation is assuming that the digest was SHA-1 (20 bytes). Again, you would take this number divided by the time it takes to hash a message.
Since they both are in scale terms of the data hashing they're comparable.

mkimage doesn't add public key to .dtb file

I am trying to make a verified boot on beaglebone black by following the documentation
https://github.com/01org/edison-u-boot/blob/master/doc/uImage.FIT/beaglebone_vboot.txt
when i run the command to put public key into .dtb file
mkimage -f sign.its -K am335x-boneblack.dtb -k keys -r image.fit
I get the output
FIT description: Beaglebone black
Created: Fri Mar 24 18:47:51 2017
Image 0 (kernel#1)
Description: unavailable
Created: Fri Mar 24 18:47:51 2017
Type: Kernel Image
Compression: lzo compressed
Data Size: 8490316 Bytes = 8291.32 KiB = 8.10 MiB
Architecture: ARM
OS: Linux
Load Address: 0x80008000
Entry Point: 0x80008000
Hash algo: sha1
Hash value: 9a390ee3c02c5bddc7b191d5cbe107991522a6d7
Image 1 (fdt#1)
Description: beaglebone-black
Created: Fri Mar 24 18:47:51 2017
Type: Flat Device Tree
Compression: uncompressed
Data Size: 38894 Bytes = 37.98 KiB = 0.04 MiB
Architecture: ARM
Hash algo: sha1
Hash value: 249ca75de41f5202fae334253bd153666f60b7dc
Default Configuration: 'conf#1'
Configuration 0 (conf#1)
Description: unavailable
Kernel: kernel#1
FDT: fdt#1
But unfortunately there is no such a field like signature or rsa in my .dtb file when i read it with fdtdump.
Here is my .its file:
/dts-v1/;
/ {
description = "Beaglebone black";
#address-cells = <1>;
images {
kernel#1 {
data = /incbin/("zImage.lzo");
type = "kernel";
arch = "arm";
os = "linux";
compression = "lzo";
load = <0x80008000>;
entry = <0x80008000>;
hash#1 {
algo = "sha1";
};
};
fdt#1 {
description = "beaglebone-black";
data = /incbin/("am335x-boneblack.dtb");
type = "flat_dt";
arch = "arm";
compression = "none";
hash#1 {
algo = "sha1";
};
};
};
configurations {
default = "conf#1";
conf#1 {
kernel = "kernel#1";
fdt = "fdt#1";
signature#1 {
algo = "sha1,rsa2048";
key-name-hint = "dev";
sign-images = "fdt", "kernel";
};
};
};
};
also in keys folder i have dev.key and dev.crt files.
thanks for your answer.
Though there's no error message, mkimage does not support that function if CONFIG_FIT_SIGNATURE in U-Boot's .config is not set.
as it says in: https://lxr.missinglinkelectronics.com/#uboot/doc/uImage.FIT/signature.txt
Public Key Storage
In order to verify an image that has been signed with a public key we need to
have a trusted public key. This cannot be stored in the signed image, since
it would be easy to alter. For this implementation we choose to store the
public key in U-Boot's control FDT (using CONFIG_OF_CONTROL).
Regards, Steve

Encrypt and Decrypt AES with Golang and Ruby

I'm working on making two secure systems talk via a common encryption scheme. I picked AES as it seems a secure standard, but I'm not married to it, so long as I have two way encryption.
Here is the Go source and Ruby source simplified down to a really clear example to run from command line and see the differences. I'm outputting bytecode for easier literal comparison.
I'm using 128 bit CFB in both, and neither of them appear to have padding, any help is greatly appreciated!
You passed wrong key size in Ruby code. It should be 192. (because key.size is 24 bytes == 192 bits)
cipher = OpenSSL::Cipher::AES.new(192, :CFB)
cipher.encrypt
cipher.key = key
cipher.iv = iv
encrypted = cipher.update(input) + cipher.final()
puts "Output: [" + encrypted.bytes.join(" ") + "]"
output:
Output: [155 79 127 80 31 163 142 111 13 211 221 163 219 248]

Parsing a base64 X509 certificate in an Oracle stored procedure?

I have a certificate x509 in base 64 binary format. How can I retrieve the information about the certificate with Oracle? I have to get serial number of this certificate. Any ideas?
There is a solution on the Oracle forum : SQL to extract specific attributes from an x509 digital certificate
The code (the original is for certificates stored as CLOB, I modified it for BLOB and to return the serial number):
create or replace and compile java source named testx509src
as
import java.security.cert.*;
import java.io.*;
import java.sql.*;
import oracle.sql.BLOB;
import oracle.sql.NUMBER;
public class TestX509 {
public static NUMBER getSerialNumber(BLOB cert)
throws SQLException, IOException, CertificateException {
Connection conn = (Connection) DriverManager.getConnection("jdbc:default:connection:");
BufferedInputStream is = new BufferedInputStream(cert.getBinaryStream());
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate c = (X509Certificate) cf.generateCertificate(is);
is.close();
return new oracle.sql.NUMBER(c.getSerialNumber());
}
}
/
CREATE OR REPLACE FUNCTION CERT_getSerialNumber(cert in blob)
RETURN NUMBER
AS LANGUAGE JAVA
NAME 'TestX509.getSerialNumber(oracle.sql.BLOB) return oracle.sql.NUMBER';
/
SQL> select CERT_GetSerialNumber(cert) serial from cert_storage where id = 1;
serial
-----------------------
243435653237
After you base64-decode a certificate, you most likely get a DER-encoded ASN.1 structure of a X.509 v3 certificate (enough keywords to continue searching for an answer).
I am not aware of any PL/SQL implementation of ASN.1 parser, parsing DER-encoded content, but it is possible to learn ASN.1 structures (sequence, integer, etc.) and their binary representation in DER format, and then do the parsing in PL/SQL, byte by byte.
=> The serial number is close to the beginning of the DER-content, so you do not need to support parsing every ASN.1 element to extract the serial number.
You could have to look at X.509 certificate structure/template, explaining how a certificate is constructed from basic ASN.1 elements, then parse/extract the elements and get the info you're interested in.
More detailed description of what's in a certificate: X.509 certificate consists of some data fields like version, serial number, valid from/to dates, issuer DN (distinguished name), subject DN, subject public key, signature hash algorithm, etc. This info is then "signed" by the certificate issuer: the issuer creates a hash code (e.g. using SHA-1 algorithm) from the info mentioned above, and then encrypts it using issuer's private key (RSA encryption). Having issuer's public key and trusting the issuer, one could use the issuer's public key to decrypt the hash code encrypted by the issuer, then create a hash code from certificate details using the same algorithm, and finally compare the computed hash with the one the issuer created. If these match, it means that no one modified the details, so if issuer is trusted, the details found in the certificate can be trusted as well.
X.509 certificate begins with (data types shown to the right):
Certificate SEQUENCE
Data SEQUENCE
Version [0] { INTEGER }
Serial Number INTEGER
Each element starts with a tag byte indicating the element type, followed by the element length, followed by the element content. If the element contains fewer than 128 bytes, the length field requires only one byte to specify the content length. If it is more than 127 bytes, bit 7 of the Length field is set to 1 and bits 6 through 0 specify the number of additional bytes used to identify the content length. In case of X.509 certificate, Version is wrapped in a context-specific tag [0].
Books explaining ASN.1 can be downloaded for free from the web.
Here's an example for analysing the beginning of a certificate:
30 82 02 D7 30 82 02 40 A0 03 02 01 02 02 01 01 ...
Interpretation:
30 = Start of Certificate SEQUENCE
82 = sequence length are the following two bytes
02 D7 = sequence length 0x02D7 (Big Endian order of bytes)
30 = Start of Data SEQUENCE
82 = sequence length are the following two bytes
02 40 = sequence length 0x0240 (Big Endian order of bytes)
A0 = start of context-specific element [0]
03 = length of context-specific element [0]
02 01 02 = content of context-specific element [0] (Version INTEGER)
(02=start of Version INTEGER,
01=length of the integer,
02=Version value (zero-based, so value 02 actually means v3))
02 = Start of Serial Number INTEGER
01 = Length of Serial Number INTEGER
01 = The serial number itself
...
Of course, in your case, length of the serial number may be bigger than one byte shown here.

Resources