Monday, January 25, 2010

ISO 9797 algorithm 3

Last Friday I set out to implement ISO 9797 algorithm 3 using the OpenSSL library. I did not have the specification handy, so I decided to to the best I could with what I could find by way of examples on the net.

I came across a description of the algorithm in this 2005 thread ( This was posted in a query by someone named Christian. He also posted his keys, data and the expected answer.

H0 = 0
stages 1 to n: Hj = Enc(K, Dj XOR H{j-1})
MAC = Enc(K, Dec(K', Hn))

Francois Grieu replied with, "This is very likely ISO/IEC 9797-1, using DES as the block cipher,
padding method 2, MAC algorithm 3." He provided an answer by sharing sample code in "some near-extinct dialect".

set m0 72C29C2371CC9BDB #message
set m1 65B779B8E8D37B29
set m2 ECC154AA56A8799F
set m3 AE2F498F76ED92F2

set pd 8000000000000000 #padding

set iv 0000000000000000 #initialisation vector

set k0 7962D9ECE03D1ACD #key
set k1 4C76089DCE131543

set xx {iv} # setup
for mj in {m0} {m1} {m2} {m3} {pd} # for each block including padding
set xx `xor {xx} {mj}` # chain
set xx `des -k {k0} -c {xx}` #encrypt
set xx `des -k {k1} -d {xx}` #decrypt
set xx `des -k {k0} -c {xx}` #encrypt
echo {xx} #show result


I've implemented the same in c for the purpose of research.

#include openssl/des.h
#include memory
#include string.h

//message + padding
const unsigned char msg[40] = { 0x72, 0xC2, 0x9C, 0x23, 0x71, 0xCC, 0x9B, 0xDB,
0x65, 0xB7, 0x79, 0xB8, 0xE8, 0xD3, 0x7B, 0x29,
0xEC, 0xC1, 0x54, 0xAA, 0x56, 0xA8, 0x79, 0x9F,
0xAE, 0x2F, 0x49, 0x8F, 0x76, 0xED, 0x92, 0xF2,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

//initialization vector
unsigned char iv[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

unsigned char k0[8] = { 0x79, 0x62, 0xD9, 0xEC, 0xE0, 0x3D, 0x1A, 0xCD };
unsigned char k1[8] = { 0x4C, 0x76, 0x08, 0x9D, 0xCE, 0x13, 0x15, 0x43 };

void print_hex(const unsigned char *bs, int n) {

for (int i = 0; i < n; i++)
printf("%02x", bs[i]);

void des_ecb_crypt(unsigned char* input, unsigned char* output, int encrypt, unsigned char* key) {

des_key_schedule sched;
des_set_key((des_cblock *) key, sched);

DES_ecb_encrypt((const_DES_cblock *)input,
(const_DES_cblock *)output,

void xor_block(unsigned char* src, unsigned char* dest) {

for (int x = 0; x < 8; x++) {
src[x] = src[x] ^ dest[x];

int main(int argc, char* argv[]) {

unsigned char output[8];
unsigned char xx[8];
unsigned char block[8];
int offset = 0;

memcpy(xx, iv, 8);

// Chain and encrypt 5 8-bit blocks
for (int x = 0; x < 5; x++) {

memcpy(block, &msg[offset] , 8);

//set xx `xor {xx} {mj}` # chain
xor_block(xx, block);

//set xx `des -k {k0} -c {xx}` #encrypt
des_ecb_crypt(xx, output, DES_ENCRYPT, k0);
memcpy(xx, output, 8);

des_ecb_crypt(xx, output, DES_DECRYPT, k1);
memcpy(xx, output, 8);

des_ecb_crypt(xx, output, DES_ENCRYPT, k0);
memcpy(xx, output, 8);

print_hex(xx, 8);
return 1;


dtsign1277 said...

wonderful ..................................................

Parisa said...
This comment has been removed by the author.
Parisa said...

It works well,thanks a lot.

CPT said...
This comment has been removed by the author.