]> git.zerfleddert.de Git - proxmark3-svn/commitdiff
Merge branch 'master' of github.com:Proxmark/proxmark3 into travis
authormerlokk <olegmsn@gmail.com>
Fri, 5 Jan 2018 09:57:11 +0000 (11:57 +0200)
committermerlokk <olegmsn@gmail.com>
Fri, 5 Jan 2018 09:57:11 +0000 (11:57 +0200)
71 files changed:
CHANGELOG.md
appveyor.yml
armsrc/iso14443a.c
armsrc/lfsampling.c
armsrc/mifarecmd.c
client/Makefile
client/cmdcrc.c
client/cmdhf14a.c
client/cmdhficlass.c
client/cmdhficlass.h
client/cmdhfmf.c
client/cmdlft55xx.c
client/cmdmain.c
client/cmdscript.c
client/emv/capk.txt [new file with mode: 0644]
client/emv/cmdemv.c
client/emv/cmdemv.h
client/emv/crypto.c [new file with mode: 0644]
client/emv/crypto.h [new file with mode: 0644]
client/emv/crypto_backend.h [new file with mode: 0644]
client/emv/crypto_polarssl.c [new file with mode: 0644]
client/emv/emv_pk.c [new file with mode: 0644]
client/emv/emv_pk.h [new file with mode: 0644]
client/emv/emv_pki.c [new file with mode: 0644]
client/emv/emv_pki.h [new file with mode: 0644]
client/emv/emv_pki_priv.c [new file with mode: 0644]
client/emv/emv_pki_priv.h [new file with mode: 0644]
client/emv/emv_tags.c
client/emv/emv_tags.h
client/emv/emvcore.c
client/emv/emvcore.h
client/emv/test/cda_test.c [new file with mode: 0644]
client/emv/test/cda_test.h [new file with mode: 0644]
client/emv/test/crypto_test.c [new file with mode: 0644]
client/emv/test/crypto_test.h [new file with mode: 0644]
client/emv/test/cryptotest.c [new file with mode: 0644]
client/emv/test/cryptotest.h [new file with mode: 0644]
client/emv/test/dda_test.c [new file with mode: 0644]
client/emv/test/dda_test.h [new file with mode: 0644]
client/emv/test/sda_test.c [new file with mode: 0644]
client/emv/test/sda_test.h [new file with mode: 0644]
client/loclass/cipher.c
client/loclass/cipher.h
client/loclass/cipherutils.c
client/loclass/cipherutils.h
client/loclass/elite_crack.c
client/loclass/elite_crack.h
client/loclass/fileutils.c
client/loclass/fileutils.h
client/loclass/ikeys.c
client/loclass/ikeys.h
client/loclass/main.c
client/obj/emv/test/.dummy [new file with mode: 0644]
client/pm3_binlib.c
client/reveng/model.c
client/scripting.c
client/ui.c
client/util.c
client/util.h
common/polarssl/aes.h
common/polarssl/bignum.c [new file with mode: 0644]
common/polarssl/bignum.h [new file with mode: 0644]
common/polarssl/bn_mul.h [new file with mode: 0644]
common/polarssl/des.c
common/polarssl/polarssl_config.h
common/polarssl/rsa.c [new file with mode: 0644]
common/polarssl/rsa.h [new file with mode: 0644]
common/polarssl/sha1.c [new file with mode: 0644]
common/polarssl/sha1.h [new file with mode: 0644]
common/sha1.c [deleted file]
common/sha1.h [deleted file]

index fabd04b0d4b1cad8c7bb01f774006de729f0f20d..4162c638d30e5d196700dda0c3f1dfbeee5effba 100644 (file)
@@ -42,6 +42,10 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
 - Added `hf emv` group of commands (Merlok)
 - Added `hf emv search` `hf emv pse` - commands for selection of EMV application (Merlok)
 - Added `hf emv select` - command for select EMV application (Merlok)
+- Added `hf emv exec` - command for execute EMV transaction (Merlok)
+- Added to `hf emv exec` MSD path for VISA and Mastercard and some other compatible EMV cards (Merlok)
+- Added to `hf emv exec` SDA, DDA, fast DDA, CDA calculations for VISA and Mastercard and some other compatible EMV cards (Merlok)
+- Added `hf emv test` - crypto tests for DES, AES, SHA, RSA, SDA, DDA, CDA and some other crypto functions (Merlok)
 
 ## [3.0.1][2017-06-08]
 
index eb22114e7afd28ce45e9aebc357b9b1fe648268a..f5ae2c70a0390f3918c76f96a62bc6c664f31c74 100644 (file)
@@ -232,8 +232,8 @@ test_script:
     #--- end Job
 
       [bool]$res=$false
-      # Wait 40 sec timeout for Job
-      if(Wait-Job $Job -Timeout 40){
+      # Wait 120 sec timeout for Job
+      if(Wait-Job $Job -Timeout 120){
         $Results = $Job | Receive-Job
         if($Results -like "true"){
           $res=$true
@@ -278,6 +278,11 @@ test_script:
     ExecTest "hf mf hardnested" "hf mf hardnested" {bash -lc "cd ~/client;proxmark3 comx -c 'hf mf hardnested t 1 000000000000'"} "found:"
 
 
+    #proxmark crypto tests
+
+    ExecTest "hf emv test" "hf emv test" {bash -lc "cd ~/client;proxmark3 comx -c 'hf emv test'"} "Tests ?OK"
+
+
     if ($global:TestsPassed) {
       Write-Host "Tests [ OK ]" -ForegroundColor Green
     } else {
index a0fe232671e86418eda924b0c52857e58a03bb7e..94ca52f542e242de6816f04e4970dd7fdda5e986 100644 (file)
@@ -189,13 +189,14 @@ void iso14a_set_trigger(bool enable) {
 
 
 void iso14a_set_timeout(uint32_t timeout) {
-       iso14a_timeout = timeout - (DELAY_AIR2ARM_AS_READER + DELAY_ARM2AIR_AS_READER)/(16*8);
+       // adjust timeout by FPGA delays and 2 additional ssp_frames to detect SOF
+       iso14a_timeout = timeout + (DELAY_AIR2ARM_AS_READER + DELAY_ARM2AIR_AS_READER)/(16*8) + 2;
        if(MF_DBGLEVEL >= 3) Dbprintf("ISO14443A Timeout set to %ld (%dms)", timeout, timeout / 106);
 }
 
 
 uint32_t iso14a_get_timeout(void) {
-       return iso14a_timeout + (DELAY_AIR2ARM_AS_READER + DELAY_ARM2AIR_AS_READER)/(16*8);
+       return iso14a_timeout - (DELAY_AIR2ARM_AS_READER + DELAY_ARM2AIR_AS_READER)/(16*8) - 2;
 }
 
 //-----------------------------------------------------------------------------
@@ -1955,9 +1956,9 @@ int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data) {
        } else{
                // S-Block WTX 
                while((data_bytes[0] & 0xF2) == 0xF2) {
-                       uint32_t save_iso14a_timeout = iso14a_timeout;
+                       uint32_t save_iso14a_timeout = iso14a_get_timeout();
                        // temporarily increase timeout
-                       iso14a_timeout = MAX((data_bytes[1] & 0x3f) * iso14a_timeout, MAX_ISO14A_TIMEOUT);
+                       iso14a_set_timeout(MAX((data_bytes[1] & 0x3f) * save_iso14a_timeout, MAX_ISO14A_TIMEOUT));
                        // Transmit WTX back 
                        // byte1 - WTXM [1..59]. command FWT=FWT*WTXM
                        data_bytes[1] = data_bytes[1] & 0x3f; // 2 high bits mandatory set to 0b
@@ -1969,7 +1970,7 @@ int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data) {
                        len = ReaderReceive(data, parity);
                        data_bytes = data;
                        // restore timeout
-                       iso14a_timeout = save_iso14a_timeout;
+                       iso14a_set_timeout(save_iso14a_timeout);
                }
 
                // if we received an I- or R(ACK)-Block with a block number equal to the
index 999f56bb0ed7458abfd86a0ad3b843b924525bf7..084201a5a52c25825615896b1d8cd84ca29eecbf 100644 (file)
@@ -153,8 +153,10 @@ uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averag
                        LED_D_OFF();
                        // threshold either high or low values 128 = center 0.  if trigger = 178 
                        if ((trigger_threshold > 0) && (sample < (trigger_threshold+128)) && (sample > (128-trigger_threshold))) { // 
-                               if (cancel_after > 0) cancel_counter++;
-                               if (cancel_after == cancel_counter) break;
+                               if (cancel_after > 0) {
+                                       cancel_counter++;
+                                       if (cancel_after == cancel_counter) break;
+                               }
                                continue;
                        }
                        trigger_threshold = 0;
index 00fd638c4daf7743a0be32669426e77acec81923..fcfd7e8fddb80f9c1bac092def66cd5fbb1d23c0 100644 (file)
@@ -694,10 +694,9 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags,
                        continue;\r
                }\r
 \r
-               // send a dummy byte as reader response in order to trigger the cards authentication timeout\r
-               uint8_t dummy_answer = 0;\r
-               ReaderTransmit(&dummy_answer, 1, NULL);\r
-               timeout = GetCountSspClk() + AUTHENTICATION_TIMEOUT;\r
+               // send a dummy response in order to trigger the cards authentication failure timeout\r
+               uint8_t dummy_answer[8] = {0};\r
+               ReaderTransmit(dummy_answer, 8, NULL);\r
 \r
                num_nonces++;\r
                if (num_nonces % 2) {\r
@@ -710,9 +709,6 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags,
                        i += 9;\r
                }\r
 \r
-               // wait for the card to become ready again\r
-               while(GetCountSspClk() < timeout);\r
-\r
        }\r
 \r
        LED_C_OFF();\r
index 5df99de775ad6da7cfb8cf41eeea4ab58553a09c..52a106bd454d9ebe55f08e9d5939ae53cd97f2a1 100644 (file)
@@ -20,7 +20,7 @@ OBJDIR = obj
 LDLIBS = -L/opt/local/lib -L/usr/local/lib -lreadline -lpthread -lm
 LUALIB = ../liblua/liblua.a
 LDFLAGS = $(ENV_LDFLAGS)
-CFLAGS = $(ENV_CFLAGS) -std=c99 -D_ISOC99_SOURCE -I. -I../include -I../common -I../zlib -I../uart -I/opt/local/include -I../liblua -Wall -g -O3
+CFLAGS = $(ENV_CFLAGS) -std=c99 -D_ISOC99_SOURCE -I. -I../include -I../common -I../common/polarssl -I../zlib -I../uart -I/opt/local/include -I../liblua -Wall -g -O3
 CXXFLAGS = -I../include -Wall -O3
 
 LUAPLATFORM = generic
@@ -88,6 +88,9 @@ CMDSRCS =     crapto1/crapto1.c\
                        crapto1/crypto1.c\
                        polarssl/des.c \
                        polarssl/aes.c\
+                       polarssl/bignum.c\
+                       polarssl/rsa.c\
+                       polarssl/sha1.c\
                        mfkey.c\
                        loclass/cipher.c \
                        loclass/cipherutils.c \
@@ -107,12 +110,22 @@ CMDSRCS =         crapto1/crapto1.c\
                        ui.c \
                        cmddata.c \
                        lfdemod.c \
+                       emv/crypto_polarssl.c\
+                       emv/crypto.c\
+                       emv/emv_pk.c\
+                       emv/emv_pki.c\
+                       emv/emv_pki_priv.c\
+                       emv/test/cryptotest.c\
                        emv/apduinfo.c\
                        emv/dump.c\
                        emv/tlv.c\
                        emv/emv_tags.c\
                        emv/dol.c\
                        emv/emvcore.c\
+                       emv/test/crypto_test.c\
+                       emv/test/sda_test.c\
+                       emv/test/dda_test.c\
+                       emv/test/cda_test.c\
                        emv/cmdemv.c\
                        cmdhf.c \
                        cmdhf14a.c \
@@ -157,7 +170,6 @@ CMDSRCS =   crapto1/crapto1.c\
                        pm3_binlib.c\
                        pm3_bitlib.c\
                        protocols.c\
-                       sha1.c\
                        cmdcrc.c\
                        reveng/reveng.c\
                        reveng/cli.c\
@@ -192,14 +204,7 @@ MULTIARCHOBJS = $(MULTIARCHSRCS:%.c=$(OBJDIR)/%_NOSIMD.o) \
                        $(MULTIARCHSRCS:%.c=$(OBJDIR)/%_AVX.o) \
                        $(MULTIARCHSRCS:%.c=$(OBJDIR)/%_AVX2.o)
 
-GCC_VERSION := $(shell gcc --version | awk '/gcc/{print $$NF;}' | sed -e 's/\.\([0-9][0-9]\)/\1/g' -e 's/\.\([0-9]\)/0\1/g' -e 's/^[0-9]\{3,4\}$$/&00/')
-CLANG_VERSION := $(shell gcc --version | awk '/Apple LLVM version/{print $$4;}' | sed -e 's/\.\([0-9][0-9]\)/\1/g' -e 's/\.\([0-9]\)/0\1/g' -e 's/^[0-9]\{3,4\}$$/&00/')
-ifneq ($(CLANG_VERSION), )
-       SUPPORTS_AVX512 :=  $(shell [ $(CLANG_VERSION) -ge 80000 ] && echo "True" )
-endif
-ifneq ($(GCC_VERSION), )
-       SUPPORTS_AVX512 :=  $(shell [ $(GCC_VERSION) -ge 40900 ] && echo "True" )
-endif
+SUPPORTS_AVX512 :=  $(shell echo | gcc -E -mavx512f - > /dev/null 2>&1 && echo "True" )
 HARD_SWITCH_NOSIMD = -mno-mmx -mno-sse2 -mno-avx -mno-avx2
 HARD_SWITCH_MMX = -mmmx -mno-sse2 -mno-avx -mno-avx2
 HARD_SWITCH_SSE2 = -mmmx -msse2 -mno-avx -mno-avx2
index 27d081b911de0c459206092d40473020d4002b17..0ca2b8b1e00d816223d991f49d23978dc8f10739 100644 (file)
@@ -40,14 +40,14 @@ int split(char *str, char *arr[MAX_ARGS]){
        int wordCnt = 0;
 
        while(1){
-               while(isspace(str[beginIndex])){
+               while(isspace((unsigned char)str[beginIndex])){
                        ++beginIndex;
                }
                if(str[beginIndex] == '\0') {
                        break;
                }
                endIndex = beginIndex;
-               while (str[endIndex] && !isspace(str[endIndex])){
+               while (str[endIndex] && !isspace((unsigned char)str[endIndex])){
                        ++endIndex;
                }
                int len = endIndex - beginIndex;
index 8064724cc3185a66b2e86f0c38c4bb8baaf9646c..e4b245c36e0a8e0c1802063268ca8481fd44bb77 100644 (file)
@@ -16,6 +16,7 @@
 #include <inttypes.h>
 #include <string.h>
 #include <unistd.h>
+#include <ctype.h>
 #include "util.h"
 #include "util_posix.h"
 #include "iso14443crc.h"
@@ -764,7 +765,7 @@ int CmdHF14AAPDU(const char *cmd) {
                                        return 1;
                        }
                        
-               if (isxdigit(c)) {
+               if (isxdigit((unsigned char)c)) {
                        // len = data + PCB(1b) + CRC(2b)
                        switch(param_gethex_to_eol(cmd, cmdp, data, sizeof(data) - 1 - 2, &datalen)) {
                        case 1:
index 60713a01fad681a0129367a2bda4ff45d07ae17a..d42f7eef6badf6d3d53dd21de7d81ec1f50e2e3b 100644 (file)
@@ -14,6 +14,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/stat.h>
+#include <ctype.h>
 #include "iso14443crc.h" // Can also be used for iClass, using 0xE012 as CRC-type
 #include "data.h"
 #include "proxmark3.h"
@@ -32,6 +33,7 @@
 #include "protocols.h"
 #include "usb_cmd.h"
 #include "cmdhfmfu.h"
+#include "util_posix.h"
 
 static int CmdHelp(const char *Cmd);
 
@@ -51,6 +53,20 @@ typedef struct iclass_block {
     uint8_t d[8];
 } iclass_block_t;
 
+int usage_hf_iclass_chk(void) {
+       PrintAndLog("Checkkeys loads a dictionary text file with 8byte hex keys to test authenticating against a iClass tag");  
+       PrintAndLog("Usage: hf iclass chk [h|e|r] <f  (*.dic)>");
+       PrintAndLog("Options:");
+       PrintAndLog("h             Show this help");
+       PrintAndLog("f <filename>  Dictionary file with default iclass keys");
+       PrintAndLog("      e             target Elite / High security key scheme");
+       PrintAndLog("      r             interpret dictionary file as raw (diversified keys)");
+       PrintAndLog("Samples:");
+       PrintAndLog("            hf iclass chk f default_iclass_keys.dic");     
+       PrintAndLog("            hf iclass chk f default_iclass_keys.dic e");   
+       return 0;
+}
+
 int xorbits_8(uint8_t val) {
        uint8_t res = val ^ (val >> 1); //1st pass
        res = res ^ (res >> 1);                 // 2nd pass
@@ -531,7 +547,7 @@ static bool select_and_auth(uint8_t *KEY, uint8_t *MAC, uint8_t *div_key, bool u
                memcpy(div_key, KEY, 8);
        else
                HFiClassCalcDivKey(CSN, KEY, div_key, elite);
-       PrintAndLog("Authing with %s: %02x%02x%02x%02x%02x%02x%02x%02x", rawkey ? "raw key" : "diversified key", div_key[0],div_key[1],div_key[2],div_key[3],div_key[4],div_key[5],div_key[6],div_key[7]);
+        if (verbose) PrintAndLog("Authing with %s: %02x%02x%02x%02x%02x%02x%02x%02x", rawkey ? "raw key" : "diversified key", div_key[0],div_key[1],div_key[2],div_key[3],div_key[4],div_key[5],div_key[6],div_key[7]);
 
        doMAC(CCNR, div_key, MAC);
        UsbCommand resp;
@@ -541,12 +557,12 @@ static bool select_and_auth(uint8_t *KEY, uint8_t *MAC, uint8_t *div_key, bool u
        SendCommand(&d);
        if (!WaitForResponseTimeout(CMD_ACK,&resp,4500))
        {
-               PrintAndLog("Auth Command execute timeout");
+               if (verbose) PrintAndLog("Auth Command execute timeout");
                return false;
        }
        uint8_t isOK = resp.arg[0] & 0xff;
        if (!isOK) {
-               PrintAndLog("Authentication error");
+               if (verbose) PrintAndLog("Authentication error");
                return false;
        }
        return true;
@@ -1699,10 +1715,152 @@ int CmdHFiClassManageKeys(const char *Cmd) {
        return 0;
 }
 
+int CmdHFiClassCheckKeys(const char *Cmd) {
+
+       uint8_t mac[4] = {0x00,0x00,0x00,0x00};
+       uint8_t key[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+       uint8_t div_key[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+
+       // elite key,  raw key, standard key
+       bool use_elite = false;
+       bool use_raw = false;   
+       bool found_debit = false;
+       bool found_credit = false;      
+       bool errors = false;
+       uint8_t cmdp = 0x00;
+       FILE * f;
+       char filename[FILE_PATH_SIZE] = {0};
+       uint8_t fileNameLen = 0;
+       char buf[17];
+       uint8_t *keyBlock = NULL, *p;
+       int keyitems = 0, keycnt = 0;
+
+       while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
+               switch (param_getchar(Cmd, cmdp)) {
+               case 'h':
+               case 'H':
+                       return usage_hf_iclass_chk();
+               case 'f':
+               case 'F':
+                       fileNameLen = param_getstr(Cmd, cmdp+1, filename, sizeof(filename)); 
+                       if (fileNameLen < 1) {
+                               PrintAndLog("No filename found after f");
+                               errors = true;
+                       }
+                       cmdp += 2;
+                       break;
+               case 'e':
+               case 'E':
+                       use_elite = true;
+                       cmdp++;
+                       break;
+               case 'r':
+               case 'R':
+                       use_raw = true;
+                       cmdp++;
+                       break;
+               default:
+                       PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd, cmdp));
+                       errors = true;
+                       break;
+               }
+       }
+       if (errors) return usage_hf_iclass_chk();       
+                       
+       if ( !(f = fopen( filename , "r")) ) {
+               PrintAndLog("File: %s: not found or locked.", filename);
+               return 1;
+       }
+
+       while( fgets(buf, sizeof(buf), f) ){
+               if (strlen(buf) < 16 || buf[15] == '\n')
+                       continue;
+       
+               while (fgetc(f) != '\n' && !feof(f)) ;  //goto next line
+               
+               if( buf[0]=='#' ) continue;     //The line start with # is comment, skip
+
+               if (!isxdigit(buf[0])){
+                       PrintAndLog("File content error. '%s' must include 16 HEX symbols",buf);
+                       continue;
+               }
+               
+               buf[16] = 0;
+
+               p = realloc(keyBlock, 8 * (keyitems += 64));
+               if (!p) {
+                       PrintAndLog("Cannot allocate memory for default keys");
+                       free(keyBlock);
+                       fclose(f);
+                       return 2;
+               }
+               keyBlock = p;
+
+               memset(keyBlock + 8 * keycnt, 0, 8);
+               num_to_bytes(strtoull(buf, NULL, 16), 8, keyBlock + 8 * keycnt);
+
+               //PrintAndLog("check key[%2d] %016" PRIx64, keycnt, bytes_to_num(keyBlock + 8*keycnt, 8));
+               keycnt++;
+               memset(buf, 0, sizeof(buf));
+       }
+       fclose(f);
+       PrintAndLog("Loaded %2d keys from %s", keycnt, filename);
+       
+       // time
+       uint64_t t1 = msclock();
+                               
+       for (uint32_t c = 0; c < keycnt; c += 1) {
+                       printf("."); fflush(stdout);                    
+                       if (ukbhit()) {
+                               int gc = getchar(); (void)gc;
+                               printf("\naborted via keyboard!\n");
+                               break;
+                       }
+                       
+                       memcpy(key, keyBlock + 8 * c , 8); 
+
+                       // debit key. try twice
+                       for (int foo = 0; foo < 2 && !found_debit; foo++) {
+                               if (!select_and_auth(key, mac, div_key, false, use_elite, use_raw, false))
+                                       continue;
+
+                               // key found.
+                               PrintAndLog("\n--------------------------------------------------------");
+                       PrintAndLog("   Found AA1 debit key\t\t[%s]", sprint_hex(key, 8));
+                               found_debit = true;
+                       }
+                       
+                       // credit key. try twice
+                       for (int foo = 0; foo < 2 && !found_credit; foo++) {
+                               if (!select_and_auth(key, mac, div_key, true, use_elite, use_raw, false))
+                                       continue;
+                               
+                               // key found
+                               PrintAndLog("\n--------------------------------------------------------");
+                               PrintAndLog("   Found AA2 credit key\t\t[%s]", sprint_hex(key, 8));
+                               found_credit = true;
+                       }
+                       
+                       // both keys found.
+                       if ( found_debit && found_credit )
+                               break;
+       }
+
+       t1 = msclock() - t1;
+
+       PrintAndLog("\nTime in iclass checkkeys: %.0f seconds\n", (float)t1/1000.0);
+       
+       DropField();
+       free(keyBlock);
+       PrintAndLog("");
+       return 0;
+}
+
 static command_t CommandTable[] = 
 {
        {"help",        CmdHelp,                        1,      "This help"},
        {"calcnewkey",  CmdHFiClassCalcNewKey,          1,      "[options..] Calc Diversified keys (blocks 3 & 4) to write new keys"},
+       {"chk",         CmdHFiClassCheckKeys,           0,      "            Check keys"},      
        {"clone",       CmdHFiClassCloneTag,            0,      "[options..] Authenticate and Clone from iClass bin file"},
        {"decrypt",     CmdHFiClassDecrypt,             1,      "[f <fname>] Decrypt tagdump" },
        {"dump",        CmdHFiClassReader_Dump,         0,      "[options..] Authenticate and Dump iClass tag's AA1"},
@@ -1723,6 +1881,7 @@ static command_t CommandTable[] =
 
 int CmdHFiClass(const char *Cmd)
 {
+       clearCommandBuffer();   
        CmdsParse(CommandTable, Cmd);
        return 0;
 }
index 9a3adf504b93ef59d322d62bb1cd9a6c3c13f7f7..456bb1c3803b2d3e7451812bb5fb61451e77e57c 100644 (file)
@@ -34,6 +34,7 @@ int CmdHFiClassSnoop(const char *Cmd);
 int CmdHFiClassSim(const char *Cmd);
 int CmdHFiClassWriteKeyFile(const char *Cmd);
 int CmdHFiClass_WriteBlock(const char *Cmd);
+int CmdHFiClassCheckKeys(const char *Cmd);
 void printIclassDumpContents(uint8_t *iclass_dump, uint8_t startblock, uint8_t endblock, size_t filesize);
 void HFiClassCalcDivKey(uint8_t        *CSN, uint8_t   *KEY, uint8_t *div_key, bool elite);
 #endif
index eed6b34c64af26e3d027e19564bec7d0757683a2..c471fdf73186f5b50d54193a45ff4f9e4b0175a3 100644 (file)
@@ -987,6 +987,7 @@ int CmdHF14AMfChk(const char *Cmd)
        int i, res;\r
        int     keycnt = 0;\r
        char ctmp       = 0x00;\r
+       int clen = 0;\r
        char ctmp3[3]   = {0x00};\r
        uint8_t blockNo = 0;\r
        uint8_t SectorsCnt = 0;\r
@@ -1015,32 +1016,36 @@ int CmdHF14AMfChk(const char *Cmd)
                blockNo = param_get8(Cmd, 0);\r
 \r
        ctmp = param_getchar(Cmd, 1);\r
-       switch (ctmp) {\r
-       case 'a': case 'A':\r
-               keyType = 0;\r
-               break;\r
-       case 'b': case 'B':\r
-               keyType = 1;\r
-               break;\r
-       case '?':\r
-               keyType = 2;\r
-               break;\r
-       default:\r
-               PrintAndLog("Key type must be A , B or ?");\r
-               free(keyBlock);\r
-               return 1;\r
-       };\r
+       clen = param_getlength(Cmd, 1);\r
+       if (clen == 1) {\r
+               switch (ctmp) {\r
+               case 'a': case 'A':\r
+                       keyType = 0;\r
+                       break;\r
+               case 'b': case 'B':\r
+                       keyType = 1;\r
+                       break;\r
+               case '?':\r
+                       keyType = 2;\r
+                       break;\r
+               default:\r
+                       PrintAndLog("Key type must be A , B or ?");\r
+                       free(keyBlock);\r
+                       return 1;\r
+               };\r
+       }\r
 \r
        // transfer to emulator & create dump file\r
        ctmp = param_getchar(Cmd, 2);\r
-       if (ctmp == 't' || ctmp == 'T') transferToEml = 1;\r
-       if (ctmp == 'd' || ctmp == 'D') createDumpFile = 1;\r
+       clen = param_getlength(Cmd, 2);\r
+       if (clen == 1 && (ctmp == 't' || ctmp == 'T')) transferToEml = 1;\r
+       if (clen == 1 && (ctmp == 'd' || ctmp == 'D')) createDumpFile = 1;\r
        \r
        param3InUse = transferToEml | createDumpFile;\r
        \r
        timeout14a = 500; // fast by default\r
        // double parameters - ts, ds\r
-       int clen = param_getlength(Cmd, 2);\r
+       clen = param_getlength(Cmd, 2);\r
        if (clen == 2 || clen == 3){\r
                param_getstr(Cmd, 2, ctmp3, sizeof(ctmp3));\r
                ctmp = ctmp3[1];\r
@@ -1089,7 +1094,7 @@ int CmdHF14AMfChk(const char *Cmd)
 \r
                                        if( buf[0]=='#' ) continue;     //The line start with # is comment, skip\r
 \r
-                                       if (!isxdigit(buf[0])){\r
+                                       if (!isxdigit((unsigned char)buf[0])){\r
                                                PrintAndLog("File content error. '%s' must include 12 HEX symbols",buf);\r
                                                continue;\r
                                        }\r
@@ -1985,8 +1990,8 @@ int CmdHF14AMfCWipe(const char *Cmd)
        bool fillCard = false;\r
        \r
        if (strlen(Cmd) < 1 || param_getchar(Cmd, 0) == 'h') {\r
-               PrintAndLog("Usage:  hf mf cwipe [card size] [w] [p]");\r
-               PrintAndLog("sample:  hf mf cwipe 1 w s");\r
+               PrintAndLog("Usage:  hf mf cwipe [card size] [w] [f]");\r
+               PrintAndLog("sample:  hf mf cwipe 1 w f");\r
                PrintAndLog("[card size]: 0 = 320 bytes (Mifare Mini), 1 = 1K (default), 2 = 2K, 4 = 4K");\r
                PrintAndLog("w - Wipe magic Chinese card (only works with gen:1a cards)");\r
                PrintAndLog("f - Fill the card with default data and keys (works with gen:1a and gen:1b cards only)");\r
index 92a00bce5820f7e63dd4675c12ac1ec118f2567a..c5a6dd3f64623ed304c2487b50ae0238dedb7602 100644 (file)
@@ -1433,7 +1433,7 @@ int CmdT55xxBruteForce(const char *Cmd) {
                        //The line start with # is comment, skip\r
                        if( buf[0]=='#' ) continue;\r
 \r
-                       if (!isxdigit(buf[0])) {\r
+                       if (!isxdigit((unsigned char)buf[0])) {\r
                                PrintAndLog("File content error. '%s' must include 8 HEX symbols", buf);\r
                                continue;\r
                        }\r
index 739d68e1cbc0beb609f0d858dae78a3ad1438b95..ae059ea281de276c3df004bb1f270cca703a4293 100644 (file)
@@ -172,7 +172,7 @@ bool WaitForResponseTimeoutW(uint32_t cmd, UsbCommand* response, size_t ms_timeo
                if (msclock() - start_time > 2000 && show_warning) {
                        PrintAndLog("Waiting for a response from the proxmark...");
                        PrintAndLog("Don't forget to cancel its operation first by pressing on the button");
-                       break;
+                       show_warning = false;
                }
        }
        return false;
index 23163aa98f128918b153c80a8ef26930519ca98c..0d19f49697a4f47304eb4edc338a31be93ed7e9a 100644 (file)
@@ -76,8 +76,11 @@ int CmdList(const char *Cmd)
 {
     DIR *dp;
     struct dirent *ep;
-       char script_directory_path[strlen(get_my_executable_directory()) + strlen(LUA_SCRIPTS_DIRECTORY) + 1];
-       strcpy(script_directory_path, get_my_executable_directory());
+       char const * exedir = get_my_executable_directory();
+       if (exedir == NULL)
+           return 0;
+       char script_directory_path[strlen(exedir) + strlen(LUA_SCRIPTS_DIRECTORY) + 1];
+       strcpy(script_directory_path, exedir);
        strcat(script_directory_path, LUA_SCRIPTS_DIRECTORY);
     dp = opendir(script_directory_path);
 
diff --git a/client/emv/capk.txt b/client/emv/capk.txt
new file mode 100644 (file)
index 0000000..0925fba
--- /dev/null
@@ -0,0 +1,32 @@
+a0:00:00:00:03 01 091231 rsa 03 c6:96:03:42:13:d7:d8:54:69:84:57:9d:1d:0f:0e:a5:19:cf:f8:de:ff:c4:29:35:4c:f3:a8:71:a6:f7:18:3f:12:28:da:5c:74:70:c0:55:38:71:00:cb:93:5a:71:2c:4e:28:64:df:5d:64:ba:93:fe:7e:63:e7:1f:25:b1:e5:f5:29:85:75:eb:e1:c6:3a:a6:17:70:69:17:91:1d:c2:a7:5a:c2:8b:25:1c:7e:f4:0f:23:65:91:24:90:b9:39:bc:a2:12:4a:30:a2:8f:54:40:2c:34:ae:ca:33:1a:b6:7e:1e:79:b2:85:dd:57:71:b5:d9:ff:79:ea:63:0b:75 sha1 d3:4a:6a:77:60:11:c7:e7:ce:3a:ec:5f:03:ad:2f:8c:fc:55:03:cc
+a0:00:00:00:03 07 171231 rsa 03 a8:9f:25:a5:6f:a6:da:25:8c:8c:a8:b4:04:27:d9:27:b4:a1:eb:4d:7e:a3:26:bb:b1:2f:97:de:d7:0a:e5:e4:48:0f:c9:c5:e8:a9:72:17:71:10:a1:cc:31:8d:06:d2:f8:f5:c4:84:4a:c5:fa:79:a4:dc:47:0b:b1:1e:d6:35:69:9c:17:08:1b:90:f1:b9:84:f1:2e:92:c1:c5:29:27:6d:8a:f8:ec:7f:28:49:20:97:d8:cd:5b:ec:ea:16:fe:40:88:f6:cf:ab:4a:1b:42:32:8a:1b:99:6f:92:78:b0:b7:e3:31:1c:a5:ef:85:6c:2f:88:84:74:b8:36:12:a8:2e:4e:00:d0:cd:40:69:a6:78:31:40:43:3d:50:72:5f sha1 b4:bc:56:cc:4e:88:32:49:32:cb:c6:43:d6:89:8f:6f:e5:93:b1:72
+a0:00:00:00:03 08 221231 rsa 03 d9:fd:6e:d7:5d:51:d0:e3:06:64:bd:15:70:23:ea:a1:ff:a8:71:e4:da:65:67:2b:86:3d:25:5e:81:e1:37:a5:1d:e4:f7:2b:cc:9e:44:ac:e1:21:27:f8:7e:26:3d:3a:f9:dd:9c:f3:5c:a4:a7:b0:1e:90:70:00:ba:85:d2:49:54:c2:fc:a3:07:48:25:dd:d4:c0:c8:f1:86:cb:02:0f:68:3e:02:f2:de:ad:39:69:13:3f:06:f7:84:51:66:ac:eb:57:ca:0f:c2:60:34:45:46:98:11:d2:93:bf:ef:ba:fa:b5:76:31:b3:dd:91:e7:96:bf:85:0a:25:01:2f:1a:e3:8f:05:aa:5c:4d:6d:03:b1:dc:2e:56:86:12:78:59:38:bb:c9:b3:cd:3a:91:0c:1d:a5:5a:5a:92:18:ac:e0:f7:a2:12:87:75:26:82:f1:58:32:a6:78:d6:e1:ed:0b sha1 20:d2:13:12:69:55:de:20:5a:dc:2f:d2:82:2b:d2:2d:e2:1c:f9:a8
+a0:00:00:00:03 09 221231 rsa 03 9d:91:22:48:de:0a:4e:39:c1:a7:dd:e3:f6:d2:58:89:92:c1:a4:09:5a:fb:d1:82:4d:1b:a7:48:47:f2:bc:49:26:d2:ef:d9:04:b4:b5:49:54:cd:18:9a:54:c5:d1:17:96:54:f8:f9:b0:d2:ab:5f:03:57:eb:64:2f:ed:a9:5d:39:12:c6:57:69:45:fa:b8:97:e7:06:2c:aa:44:a4:aa:06:b8:fe:6e:3d:ba:18:af:6a:e3:73:8e:30:42:9e:e9:be:03:42:7c:9d:64:f6:95:fa:8c:ab:4b:fe:37:68:53:ea:34:ad:1d:76:bf:ca:d1:59:08:c0:77:ff:e6:dc:55:21:ec:ef:5d:27:8a:96:e2:6f:57:35:9f:fa:ed:a1:94:34:b9:37:f1:ad:99:9d:c5:c4:1e:b1:19:35:b4:4c:18:10:0e:85:7f:43:1a:4a:5a:6b:b6:51:14:f1:74:c2:d7:b5:9f:df:23:7d:6b:b1:dd:09:16:e6:44:d7:09:de:d5:64:81:47:7c:75:d9:5c:dd:68:25:46:15:f7:74:0e:c0:7f:33:0a:c5:d6:7b:cd:75:bf:23:d2:8a:14:08:26:c0:26:db:de:97:1a:37:cd:3e:f9:b8:df:64:4a:c3:85:01:05:01:ef:c6:50:9d:7a:41 sha1 1f:f8:0a:40:17:3f:52:d7:d2:7e:0f:26:a1:46:a1:c8:cc:b2:90:46
+a0:00:00:00:03 95 000000 rsa 03 be:9e:1f:a5:e9:a8:03:85:29:99:c4:ab:43:2d:b2:86:00:dc:d9:da:b7:6d:fa:aa:47:35:5a:0f:e3:7b:15:08:ac:6b:f3:88:60:d3:c6:c2:e5:b1:2a:3c:aa:f2:a7:00:5a:72:41:eb:aa:77:71:11:2c:74:cf:9a:06:34:65:2f:bc:a0:e5:98:0c:54:a6:47:61:ea:10:1a:11:4e:0f:0b:55:72:ad:d5:7d:01:0b:7c:9c:88:7e:10:4c:a4:ee:12:72:da:66:d9:97:b9:a9:0b:5a:6d:62:4a:b6:c5:7e:73:c8:f9:19:00:0e:b5:f6:84:89:8e:f8:c3:db:ef:b3:30:c6:26:60:be:d8:8e:a7:8e:90:9a:ff:05:f6:da:62:7b sha1 ee:15:11:ce:c7:10:20:a9:b9:04:43:b3:7b:1d:5f:6e:70:30:30:f6
+a0:00:00:00:03 92 000000 rsa 03 99:6a:f5:6f:56:91:87:d0:92:93:c1:48:10:45:0e:d8:ee:33:57:39:7b:18:a2:45:8e:fa:a9:2d:a3:b6:df:65:14:ec:06:01:95:31:8f:d4:3b:e9:b8:f0:cc:66:9e:3f:84:40:57:cb:dd:f8:bd:a1:91:bb:64:47:3b:c8:dc:9a:73:0d:b8:f6:b4:ed:e3:92:41:86:ff:d9:b8:c7:73:57:89:c2:3a:36:ba:0b:8a:f6:53:72:eb:57:ea:5d:89:e7:d1:4e:9c:7b:6b:55:74:60:f1:08:85:da:16:ac:92:3f:15:af:37:58:f0:f0:3e:bd:3c:5c:2c:94:9c:ba:30:6d:b4:4e:6a:2c:07:6c:5f:67:e2:81:d7:ef:56:78:5d:c4:d7:59:45:e4:91:f0:19:18:80:0a:9e:2d:c6:6f:60:08:05:66:ce:0d:af:8d:17:ea:d4:6a:d8:e3:0a:24:7c:9f sha1 42:9c:95:4a:38:59:ce:f9:12:95:f6:63:c9:63:e5:82:ed:6e:b2:53
+a0:00:00:00:03 94 000000 rsa 03 ac:d2:b1:23:02:ee:64:4f:3f:83:5a:bd:1f:c7:a6:f6:2c:ce:48:ff:ec:62:2a:a8:ef:06:2b:ef:6f:b8:ba:8b:c6:8b:bf:6a:b5:87:0e:ed:57:9b:c3:97:3e:12:13:03:d3:48:41:a7:96:d6:dc:bc:41:db:f9:e5:2c:46:09:79:5c:0c:cf:7e:e8:6f:a1:d5:cb:04:10:71:ed:2c:51:d2:20:2f:63:f1:15:6c:58:a9:2d:38:bc:60:bd:f4:24:e1:77:6e:2b:c9:64:80:78:a0:3b:36:fb:55:43:75:fc:53:d5:7c:73:f5:16:0e:a5:9f:3a:fc:53:98:ec:7b:67:75:8d:65:c9:bf:f7:82:8b:6b:82:d4:be:12:4a:41:6a:b7:30:19:14:31:1e:a4:62:c1:9f:77:1f:31:b3:b5:73:36:00:0d:ff:73:2d:3b:83:de:07:05:2d:73:03:54:d2:97:be:c7:28:71:dc:cf:0e:19:3f:17:1a:ba:27:ee:46:4c:6a:97:69:09:43:d5:9b:da:bb:2a:27:eb:71:ce:eb:da:fa:11:76:04:64:78:fd:62:fe:c4:52:d5:ca:39:32:96:53:0a:a3:f4:19:27:ad:fe:43:4a:2d:f2:ae:30:54:f8:84:06:57:a2:6e:0f:c6:17 sha1 c4:a3:c4:3c:cf:87:32:7d:13:6b:80:41:60:e4:7d:43:b6:0e:6e:0f
+a0:00:00:00:04 03 000000 rsa 03 c2:49:07:47:fe:17:eb:05:84:c8:8d:47:b1:60:27:04:15:0a:dc:88:c5:b9:98:bd:59:ce:04:3e:de:bf:0f:fe:e3:09:3a:c7:95:6a:d3:b6:ad:45:54:c6:de:19:a1:78:d6:da:29:5b:e1:5d:52:20:64:5e:3c:81:31:66:6f:a4:be:5b:84:fe:13:1e:a4:4b:03:93:07:63:8b:9e:74:a8:c4:25:64:f8:92:a6:4d:f1:cb:15:71:2b:73:6e:33:74:f1:bb:b6:81:93:71:60:2d:89:70:e9:7b:90:07:93:c7:c2:a8:9a:4a:16:49:a5:9b:e6:80:57:4d:d0:b6:01:45 sha1 5a:dd:f2:1d:09:27:86:61:14:11:79:cb:ef:f2:72:ea:38:4b:13:bb
+a0:00:00:00:04 04 000000 rsa 03 a6:da:42:83:87:a5:02:d7:dd:fb:7a:74:d3:f4:12:be:76:26:27:19:7b:25:43:5b:7a:81:71:6a:70:01:57:dd:d0:6f:7c:c9:9d:6c:a2:8c:24:70:52:7e:2c:03:61:6b:9c:59:21:73:57:c2:67:4f:58:3b:3b:a5:c7:dc:f2:83:86:92:d0:23:e3:56:24:20:b4:61:5c:43:9c:a9:7c:44:dc:9a:24:9c:fc:e7:b3:bf:b2:2f:68:22:8c:3a:f1:33:29:aa:4a:61:3c:f8:dd:85:35:02:37:3d:62:e4:9a:b2:56:d2:bc:17:12:0e:54:ae:dc:ed:6d:96:a4:28:7a:cc:5c:04:67:7d:4a:5a:32:0d:b8:be:e2:f7:75:e5:fe:c5 sha1 38:1a:03:5d:a5:8b:48:2e:e2:af:75:f4:c3:f2:ca:46:9b:a4:aa:6c
+a0:00:00:00:04 05 000000 rsa 03 b8:04:8a:bc:30:c9:0d:97:63:36:54:3e:3f:d7:09:1c:8f:e4:80:0d:f8:20:ed:55:e7:e9:48:13:ed:00:55:5b:57:3f:ec:a3:d8:4a:f6:13:1a:65:1d:66:cf:f4:28:4f:b1:3b:63:5e:dd:0e:e4:01:76:d8:bf:04:b7:fd:1c:7b:ac:f9:ac:73:27:df:aa:8a:a7:2d:10:db:3b:8e:70:b2:dd:d8:11:cb:41:96:52:5e:a3:86:ac:c3:3c:0d:9d:45:75:91:64:69:c4:e4:f5:3e:8e:1c:91:2c:c6:18:cb:22:dd:e7:c3:56:8e:90:02:2e:6b:ba:77:02:02:e4:52:2a:2d:d6:23:d1:80:e2:15:bd:1d:15:07:fe:3d:c9:0c:a3:10:d2:7b:3e:fc:cd:8f:83:de:30:52:ca:d1:e4:89:38:c6:8d:09:5a:ac:91:b5:f3:7e:28:bb:49:ec:7e:d5:97 sha1 eb:fa:0d:5d:06:d8:ce:70:2d:a3:ea:e8:90:70:1d:45:e2:74:c8:45
+a0:00:00:00:04 06 000000 rsa 03 cb:26:fc:83:0b:43:78:5b:2b:ce:37:c8:1e:d3:34:62:2f:96:22:f4:c8:9a:ae:64:10:46:b2:35:34:33:88:3f:30:7f:b7:c9:74:16:2d:a7:2f:7a:4e:c7:5d:9d:65:73:36:86:5b:8d:30:23:d3:d6:45:66:76:25:c9:a0:7a:6b:7a:13:7c:f0:c6:41:98:ae:38:fc:23:80:06:fb:26:03:f4:1f:4f:3b:b9:da:13:47:27:0f:2f:5d:8c:60:6e:42:09:58:c5:f7:d5:0a:71:de:30:14:2f:70:de:46:88:89:b5:e3:a0:86:95:b9:38:a5:0f:c9:80:39:3a:9c:bc:e4:4a:d2:d6:4f:63:0b:b3:3a:d3:f5:f5:fd:49:5d:31:f3:78:18:c1:d9:40:71:34:2e:07:f1:be:c2:19:4f:60:35:ba:5d:ed:39:36:50:0e:b8:2d:fd:a6:e8:af:b6:55:b1:ef:3d:0d:7e:bf:86:b6:6d:d9:f2:9f:6b:1d:32:4f:e8:b2:6c:e3:8a:b2:01:3d:d1:3f:61:1e:7a:59:4d:67:5c:44:32:35:0e:a2:44:cc:34:f3:87:3c:ba:06:59:29:87:a1:d7:e8:52:ad:c2:2e:f5:a2:ee:28:13:20:31:e4:8f:74:03:7e:3b:34:ab:74:7f sha1 f9:10:a1:50:4d:5f:fb:79:3d:94:f3:b5:00:76:5e:1a:bc:ad:72:d9
+a0:00:00:00:04 00 000000 rsa 03 9c:6b:e5:ad:b1:0b:4b:e3:dc:e2:09:9b:4b:21:06:72:b8:96:56:eb:a0:91:20:4f:61:3e:cc:62:3b:ed:c9:c6:d7:7b:66:0e:8b:ae:ea:7f:7c:e3:0f:1b:15:38:79:a4:e3:64:59:34:3d:1f:e4:7a:cd:bd:41:fc:d7:10:03:0c:2b:a1:d9:46:15:97:98:2c:6e:1b:dd:08:55:4b:72:6f:5e:ff:79:13:ce:59:e7:9e:35:72:95:c3:21:e2:6d:0b:8b:e2:70:a9:44:23:45:c7:53:e2:aa:2a:cf:c9:d3:08:50:60:2f:e6:ca:c0:0c:6d:df:6b:8d:9d:9b:48:79:b2:82:6b:04:2a:07:f0:e5:ae:52:6a:3d:3c:4d:22:c7:2b:9e:aa:52:ee:d8:89:38:66:f8:66:38:7a:c0:5a:13:99 sha1 ec:0a:59:d3:5d:19:f0:31:e9:e8:cb:ec:56:db:80:e2:2b:1d:e1:30
+a0:00:00:00:04 02 000000 rsa 03 a9:9a:6d:3e:07:18:89:ed:9e:3a:0c:39:1c:69:b0:b8:04:fc:16:0b:2b:4b:dd:57:0c:92:dd:5a:0f:45:f5:3e:86:21:f7:c9:6c:40:22:42:66:73:5e:1e:e1:b3:c0:62:38:ae:35:04:63:20:fd:8e:81:f8:ce:b3:f8:b4:c9:7b:94:09:30:a3:ac:5e:79:00:86:da:d4:1a:6a:4f:51:17:ba:1c:e2:43:8a:51:ac:05:3e:b0:02:ae:d8:66:d2:c4:58:fd:73:35:90:21:a1:20:29:a0:c0:43:04:5c:11:66:4f:e0:21:9e:c6:3c:10:bf:21:55:bb:27:84:60:9a:10:64:21:d4:51:63:79:97:38:c1:c3:09:09:bb:6c:6f:e5:2b:bb:76:39:7b:97:40:ce:06:4a:61:3f:f8:41:11:85:f0:88:42:a4:23:ea:d2:0e:df:fb:ff:1c:d6:c3:fe:0c:98:21:47:91:99:c2:6d:85:72:cc:8a:ff:f0:87:a9:c3 sha1 33:40:8b:96:c8:14:74:2a:d7:35:36:c7:2f:09:26:e4:47:1e:8e:47
+a0:00:00:00:04 05 000000 rsa 03 a1:f5:e1:c9:bd:86:50:bd:43:ab:6e:e5:6b:89:1e:f7:45:9c:0a:24:fa:84:f9:12:7d:1a:6c:79:d4:93:0f:6d:b1:85:2e:25:10:f1:8b:61:cd:35:4d:b8:3a:35:6b:d1:90:b8:8a:b8:df:04:28:4d:02:a4:20:4a:7b:6c:b7:c5:55:19:77:a9:b3:63:79:ca:3d:e1:a0:8e:69:f3:01:c9:5c:c1:c2:05:06:95:92:75:f4:17:23:dd:5d:29:25:29:05:79:e5:a9:5b:0d:f6:32:3f:c8:e9:27:3d:6f:84:91:98:c4:99:62:09:16:6d:9b:fc:97:3c:36:1c:c8:26:e1 sha1 53:d0:49:03:b4:96:f5:95:44:a8:43:09:af:16:92:51:f2:89:68:74
+a0:00:00:00:04 ef 000000 rsa 03 a1:91:cb:87:47:3f:29:34:9b:5d:60:a8:8b:3e:ae:e0:97:3a:a6:f1:a0:82:f3:58:d8:49:fd:df:f9:c0:91:f8:99:ed:a9:79:2c:af:09:ef:28:f5:d2:24:04:b8:8a:22:93:ee:bb:c1:94:9c:43:be:a4:d6:0c:fd:87:9a:15:39:54:4e:09:e0:f0:9f:60:f0:65:b2:bf:2a:13:ec:c7:05:f3:d4:68:b9:d3:3a:e7:7a:d9:d3:f1:9c:a4:0f:23:dc:f5:eb:7c:04:dc:8f:69:eb:a5:65:b1:eb:cb:46:86:cd:27:47:85:53:0f:f6:f6:e9:ee:43:aa:43:fd:b0:2c:e0:0d:ae:c1:5c:7b:8f:d6:a9:b3:94:ba:ba:41:9d:3f:6d:c8:5e:16:56:9b:e8:e7:69:89:68:8e:fe:a2:df:22:ff:7d:35:c0:43:33:8d:ea:a9:82:a0:2b:86:6d:e5:32:85:19:eb:bc:d6:f0:3c:dd:68:66:73:84:7f:84:db:65:1a:b8:6c:28:cf:14:62:56:2c:57:7b:85:35:64:a2:90:c8:55:6d:81:85:31:26:8d:25:cc:98:a4:cc:6a:0b:df:ff:da:2d:cc:a3:a9:4c:99:85:59:e3:07:fd:df:91:50:06:d9:a9:87:b0:7d:da:eb:3b sha1 21:76:6e:bb:0e:e1:22:af:b6:5d:78:45:b7:3d:b4:6b:ab:65:42:7a
+a0:00:00:00:04 f1 000000 rsa 03 a0:dc:f4:bd:e1:9c:35:46:b4:b6:f0:41:4d:17:4d:de:29:4a:ab:bb:82:8c:5a:83:4d:73:aa:e2:7c:99:b0:b0:53:a9:02:78:00:72:39:b6:45:9f:f0:bb:cd:7b:4b:9c:6c:50:ac:02:ce:91:36:8d:a1:bd:21:aa:ea:db:c6:53:47:33:7d:89:b6:8f:5c:99:a0:9d:05:be:02:dd:1f:8c:5b:a2:0e:2f:13:fb:2a:27:c4:1d:3f:85:ca:d5:cf:66:68:e7:58:51:ec:66:ed:bf:98:85:1f:d4:e4:2c:44:c1:d5:9f:59:84:70:3b:27:d5:b9:f2:1b:8f:a0:d9:32:79:fb:bf:69:e0:90:64:29:09:c9:ea:27:f8:98:95:95:41:aa:67:57:f5:f6:24:10:4f:6e:1d:3a:95:32:f2:a6:e5:15:15:ae:ad:1b:43:b3:d7:83:50:88:a2:fa:fa:7b:e7 sha1 d8:e6:8d:a1:67:ab:5a:85:d8:c3:d5:5e:cb:9b:05:17:a1:a5:b4:bb
+a0:00:00:00:04 f3 000000 rsa 03 98:f0:c7:70:f2:38:64:c2:e7:66:df:02:d1:e8:33:df:f4:ff:e9:2d:69:6e:16:42:f0:a8:8c:56:94:c6:47:9d:16:db:15:37:bf:e2:9e:4f:dc:6e:6e:8a:fd:1b:0e:b7:ea:01:24:72:3c:33:31:79:bf:19:e9:3f:10:65:8b:2f:77:6e:82:9e:87:da:ed:a9:c9:4a:8b:33:82:19:9a:35:0c:07:79:77:c9:7a:ff:08:fd:11:31:0a:c9:50:a7:2c:3c:a5:00:2e:f5:13:fc:cc:28:6e:64:6e:3c:53:87:53:5d:50:95:14:b3:b3:26:e1:23:4f:9c:b4:8c:36:dd:d4:4b:41:6d:23:65:40:34:a6:6f:40:3b:a5:11:c5:ef:a3 sha1 a6:9a:c7:60:3d:af:56:6e:97:2d:ed:c2:cb:43:3e:07:e8:b0:1a:9a
+a0:00:00:00:04 f5 000000 rsa 01:00:01 a6:e6:fb:72:17:95:06:f8:60:cc:ca:8c:27:f9:9c:ec:d9:4c:7d:4f:31:91:d3:03:bb:ee:37:48:1c:7a:a1:5f:23:3b:a7:55:e9:e4:37:63:45:a9:a6:7e:79:94:bd:c1:c6:80:bb:35:22:d8:c9:3e:b0:cc:c9:1a:d3:1a:d4:50:da:30:d3:37:66:2d:19:ac:03:e2:b4:ef:5f:6e:c1:82:82:d4:91:e1:97:67:d7:b2:45:42:df:de:ff:6f:62:18:55:03:53:20:69:bb:b3:69:e3:bb:9f:b1:9a:c6:f1:c3:0b:97:d2:49:ee:e7:64:e0:ba:c9:7f:25:c8:73:d9:73:95:3e:51:53:a4:20:64:bb:fa:bf:d0:6a:4b:b4:86:86:0b:f6:63:74:06:c9:fc:36:81:3a:4a:75:f7:5c:31:cc:a9:f6:9f:8d:e5:9a:de:ce:f6:bd:e7:e0:78:00:fc:be:03:5d:31:76:af:84:73:e2:3e:9a:a3:df:ee:22:11:96:d1:14:83:02:67:7c:72:0c:fe:25:44:a0:3d:b5:53:e7:f1:b8:42:7b:a1:cc:72:b0:f2:9b:12:df:ef:4c:08:1d:07:6d:35:3e:71:88:0a:ad:ff:38:63:52:af:0a:b7:b2:8e:d4:9e:1e:67:2d:11:f9 sha1 c2:23:98:04:c8:09:81:70:be:52:d6:d5:d4:15:9e:81:ce:84:66:bf
+a0:00:00:00:04 f6 000000 rsa 03 a2:5a:6b:d7:83:a5:ef:6b:8f:b6:f8:30:55:c2:60:f5:f9:9e:a1:66:78:f3:b9:05:3e:0f:64:98:e8:2c:3f:5d:1e:8c:38:f1:35:88:01:7e:2b:12:b3:d8:ff:6f:50:16:7f:46:44:29:10:72:9e:9e:4d:1b:37:39:e5:06:7c:0a:c7:a1:f4:48:7e:35:f6:75:bc:16:e2:33:31:51:65:cb:14:2b:fd:b2:5e:30:1a:63:2a:54:a3:37:1e:ba:b6:57:2d:ee:ba:f3:70:f3:37:f0:57:ee:73:b4:ae:46:d1:a8:bc:4d:a8:53:ec:3c:c1:2c:8c:bc:2d:a1:83:22:d6:85:30:c7:0b:22:bd:ac:35:1d:d3:60:68:ae:32:1e:11:ab:f2:64:f4:d3:56:9b:b7:12:14:54:50:05:55:8d:e2:60:83:c7:35:db:77:63:68:17:2f:e8:c2:f5:c8:5e:8b:5b:89:0c:c6:82:91:1d:2d:e7:1f:a6:26:b8:81:7f:cc:c0:89:22:b7:03:86:9f:3b:ae:ac:14:59:d7:7c:d8:53:76:bc:36:18:2f:42:38:31:4d:6c:42:12:fb:dd:7f:23:d3 sha1 50:29:09:ed:54:5e:3c:8d:bd:00:ea:58:2d:06:17:fe:e9:f6:f6:84
+a0:00:00:00:04 f7 000000 rsa 01:00:01 94:ea:62:f6:d5:83:20:e3:54:c0:22:ad:dc:f0:55:9d:8c:f2:06:cd:92:e8:69:56:49:05:ce:21:d7:20:f9:71:b7:ae:a3:74:83:0e:be:17:57:11:5a:85:e0:88:d4:1c:6b:77:cf:5e:c8:21:f3:0b:1d:89:04:17:bf:2f:a3:1e:59:08:de:d5:fa:67:7f:8c:7b:18:4a:d0:90:28:fd:de:96:b6:a6:10:98:50:aa:80:01:75:ea:bc:db:bb:68:4a:96:c2:eb:63:79:df:ea:08:d3:2f:e2:33:1f:e1:03:23:3a:d5:8d:cd:b1:e6:e0:77:cb:9f:24:ea:ec:5c:25:af sha1 ee:b0:dd:9b:24:77:be:e3:20:9a:91:4c:db:a9:4c:1c:4a:9b:de:d9
+a0:00:00:00:04 f8 000000 rsa 03 a1:f5:e1:c9:bd:86:50:bd:43:ab:6e:e5:6b:89:1e:f7:45:9c:0a:24:fa:84:f9:12:7d:1a:6c:79:d4:93:0f:6d:b1:85:2e:25:10:f1:8b:61:cd:35:4d:b8:3a:35:6b:d1:90:b8:8a:b8:df:04:28:4d:02:a4:20:4a:7b:6c:b7:c5:55:19:77:a9:b3:63:79:ca:3d:e1:a0:8e:69:f3:01:c9:5c:c1:c2:05:06:95:92:75:f4:17:23:dd:5d:29:25:29:05:79:e5:a9:5b:0d:f6:32:3f:c8:e9:27:3d:6f:84:91:98:c4:99:62:09:16:6d:9b:fc:97:3c:36:1c:c8:26:e1 sha1 f0:6e:cc:6d:2a:ae:bf:25:9b:7e:75:5a:38:d9:a9:b2:4e:2f:f3:dd
+a0:00:00:00:04 f9 000000 rsa 03 a9:9a:6d:3e:07:18:89:ed:9e:3a:0c:39:1c:69:b0:b8:04:fc:16:0b:2b:4b:dd:57:0c:92:dd:5a:0f:45:f5:3e:86:21:f7:c9:6c:40:22:42:66:73:5e:1e:e1:b3:c0:62:38:ae:35:04:63:20:fd:8e:81:f8:ce:b3:f8:b4:c9:7b:94:09:30:a3:ac:5e:79:00:86:da:d4:1a:6a:4f:51:17:ba:1c:e2:43:8a:51:ac:05:3e:b0:02:ae:d8:66:d2:c4:58:fd:73:35:90:21:a1:20:29:a0:c0:43:04:5c:11:66:4f:e0:21:9e:c6:3c:10:bf:21:55:bb:27:84:60:9a:10:64:21:d4:51:63:79:97:38:c1:c3:09:09:bb:6c:6f:e5:2b:bb:76:39:7b:97:40:ce:06:4a:61:3f:f8:41:11:85:f0:88:42:a4:23:ea:d2:0e:df:fb:ff:1c:d6:c3:fe:0c:98:21:47:91:99:c2:6d:85:72:cc:8a:ff:f0:87:a9:c3 sha1 33:67:12:dc:c2:85:54:80:9c:6a:a9:b0:23:58:de:6f:75:51:64:db
+a0:00:00:00:04 fa 000000 rsa 03 a9:0f:cd:55:aa:2d:5d:99:63:e3:5e:d0:f4:40:17:76:99:83:2f:49:c6:ba:b1:5c:da:e5:79:4b:e9:3f:93:4d:44:62:d5:d1:27:62:e4:8c:38:ba:83:d8:44:5d:ea:a7:41:95:a3:01:a1:02:b2:f1:14:ea:da:0d:18:0e:e5:e7:a5:c7:3e:0c:4e:11:f6:7a:43:dd:ab:5d:55:68:3b:14:74:cc:06:27:f4:4b:8d:30:88:a4:92:ff:aa:da:d4:f4:24:22:d0:e7:01:35:36:c3:c4:9a:d3:d0:fa:e9:64:59:b0:f6:b1:b6:05:65:38:a3:d6:d4:46:40:f9:44:67:b1:08:86:7d:ec:40:fa:ae:cd:74:0c:00:e2:b7:a8:85:2d sha1 5b:ed:40:68:d9:6e:a1:6d:2d:77:e0:3d:60:36:fc:7a:16:0e:a9:9c
+b0:12:34:56:78 00 000000 rsa 03 9c:6b:e5:ad:b1:0b:4b:e3:dc:e2:09:9b:4b:21:06:72:b8:96:56:eb:a0:91:20:4f:61:3e:cc:62:3b:ed:c9:c6:d7:7b:66:0e:8b:ae:ea:7f:7c:e3:0f:1b:15:38:79:a4:e3:64:59:34:3d:1f:e4:7a:cd:bd:41:fc:d7:10:03:0c:2b:a1:d9:46:15:97:98:2c:6e:1b:dd:08:55:4b:72:6f:5e:ff:79:13:ce:59:e7:9e:35:72:95:c3:21:e2:6d:0b:8b:e2:70:a9:44:23:45:c7:53:e2:aa:2a:cf:c9:d3:08:50:60:2f:e6:ca:c0:0c:6d:df:6b:8d:9d:9b:48:79:b2:82:6b:04:2a:07:f0:e5:ae:52:6a:3d:3c:4d:22:c7:2b:9e:aa:52:ee:d8:89:38:66:f8:66:38:7a:c0:5a:13:99 sha1 5d:29:70:e6:46:75:72:7e:60:46:07:65:a8:db:75:34:2a:e1:47:83
+b0:12:34:56:78 02 000000 rsa 03 a9:9a:6d:3e:07:18:89:ed:9e:3a:0c:39:1c:69:b0:b8:04:fc:16:0b:2b:4b:dd:57:0c:92:dd:5a:0f:45:f5:3e:86:21:f7:c9:6c:40:22:42:66:73:5e:1e:e1:b3:c0:62:38:ae:35:04:63:20:fd:8e:81:f8:ce:b3:f8:b4:c9:7b:94:09:30:a3:ac:5e:79:00:86:da:d4:1a:6a:4f:51:17:ba:1c:e2:43:8a:51:ac:05:3e:b0:02:ae:d8:66:d2:c4:58:fd:73:35:90:21:a1:20:29:a0:c0:43:04:5c:11:66:4f:e0:21:9e:c6:3c:10:bf:21:55:bb:27:84:60:9a:10:64:21:d4:51:63:79:97:38:c1:c3:09:09:bb:6c:6f:e5:2b:bb:76:39:7b:97:40:ce:06:4a:61:3f:f8:41:11:85:f0:88:42:a4:23:ea:d2:0e:df:fb:ff:1c:d6:c3:fe:0c:98:21:47:91:99:c2:6d:85:72:cc:8a:ff:f0:87:a9:c3 sha1 29:4b:e2:02:39:ab:15:24:5a:63:be:a4:6c:c6:c1:75:a2:55:62:d1
+b0:12:34:56:78 05 000000 rsa 03 a1:f5:e1:c9:bd:86:50:bd:43:ab:6e:e5:6b:89:1e:f7:45:9c:0a:24:fa:84:f9:12:7d:1a:6c:79:d4:93:0f:6d:b1:85:2e:25:10:f1:8b:61:cd:35:4d:b8:3a:35:6b:d1:90:b8:8a:b8:df:04:28:4d:02:a4:20:4a:7b:6c:b7:c5:55:19:77:a9:b3:63:79:ca:3d:e1:a0:8e:69:f3:01:c9:5c:c1:c2:05:06:95:92:75:f4:17:23:dd:5d:29:25:29:05:79:e5:a9:5b:0d:f6:32:3f:c8:e9:27:3d:6f:84:91:98:c4:99:62:09:16:6d:9b:fc:97:3c:36:1c:c8:26:e1 sha1 b9:a1:d6:5c:af:e0:6b:05:4e:dd:7e:a8:25:97:ab:85:f1:30:e6:63
+b0:12:34:56:78 f3 000000 rsa 01:00:01 94:ea:62:f6:d5:83:20:e3:54:c0:22:ad:dc:f0:55:9d:8c:f2:06:cd:92:e8:69:56:49:05:ce:21:d7:20:f9:71:b7:ae:a3:74:83:0e:be:17:57:11:5a:85:e0:88:d4:1c:6b:77:cf:5e:c8:21:f3:0b:1d:89:04:17:bf:2f:a3:1e:59:08:de:d5:fa:67:7f:8c:7b:18:4a:d0:90:28:fd:de:96:b6:a6:10:98:50:aa:80:01:75:ea:bc:db:bb:68:4a:96:c2:eb:63:79:df:ea:08:d3:2f:e2:33:1f:e1:03:23:3a:d5:8d:cd:b1:e6:e0:77:cb:9f:24:ea:ec:5c:25:af sha1 56:94:b0:d2:78:48:18:14:a0:5e:12:b5:58:ce:c1:23:48:65:aa:5d
+b0:12:34:56:78 f5 000000 rsa 03 a2:5a:6b:d7:83:a5:ef:6b:8f:b6:f8:30:55:c2:60:f5:f9:9e:a1:66:78:f3:b9:05:3e:0f:64:98:e8:2c:3f:5d:1e:8c:38:f1:35:88:01:7e:2b:12:b3:d8:ff:6f:50:16:7f:46:44:29:10:72:9e:9e:4d:1b:37:39:e5:06:7c:0a:c7:a1:f4:48:7e:35:f6:75:bc:16:e2:33:31:51:65:cb:14:2b:fd:b2:5e:30:1a:63:2a:54:a3:37:1e:ba:b6:57:2d:ee:ba:f3:70:f3:37:f0:57:ee:73:b4:ae:46:d1:a8:bc:4d:a8:53:ec:3c:c1:2c:8c:bc:2d:a1:83:22:d6:85:30:c7:0b:22:bd:ac:35:1d:d3:60:68:ae:32:1e:11:ab:f2:64:f4:d3:56:9b:b7:12:14:54:50:05:55:8d:e2:60:83:c7:35:db:77:63:68:17:2f:e8:c2:f5:c8:5e:8b:5b:89:0c:c6:82:91:1d:2d:e7:1f:a6:26:b8:81:7f:cc:c0:89:22:b7:03:86:9f:3b:ae:ac:14:59:d7:7c:d8:53:76:bc:36:18:2f:42:38:31:4d:6c:42:12:fb:dd:7f:23:d3 sha1 f7:5e:88:02:85:5c:9b:14:02:7e:51:73:45:71:7e:5c:36:35:b9:1b
+b0:12:34:56:78 f6 000000 rsa 03 a1:f5:e1:c9:bd:86:50:bd:43:ab:6e:e5:6b:89:1e:f7:45:9c:0a:24:fa:84:f9:12:7d:1a:6c:79:d4:93:0f:6d:b1:85:2e:25:10:f1:8b:61:cd:35:4d:b8:3a:35:6b:d1:90:b8:8a:b8:df:04:28:4d:02:a4:20:4a:7b:6c:b7:c5:55:19:77:a9:b3:63:79:ca:3d:e1:a0:8e:69:f3:01:c9:5c:c1:c2:05:06:95:92:75:f4:17:23:dd:5d:29:25:29:05:79:e5:a9:5b:0d:f6:32:3f:c8:e9:27:3d:6f:84:91:98:c4:99:62:09:16:6d:9b:fc:97:3c:36:1c:c8:26:e1 sha1 e9:40:6b:65:10:c1:43:ab:1e:9b:9d:79:a3:c1:df:f8:90:9a:34:7c
+b0:12:34:56:78 f7 000000 rsa 03 98:f0:c7:70:f2:38:64:c2:e7:66:df:02:d1:e8:33:df:f4:ff:e9:2d:69:6e:16:42:f0:a8:8c:56:94:c6:47:9d:16:db:15:37:bf:e2:9e:4f:dc:6e:6e:8a:fd:1b:0e:b7:ea:01:24:72:3c:33:31:79:bf:19:e9:3f:10:65:8b:2f:77:6e:82:9e:87:da:ed:a9:c9:4a:8b:33:82:19:9a:35:0c:07:79:77:c9:7a:ff:08:fd:11:31:0a:c9:50:a7:2c:3c:a5:00:2e:f5:13:fc:cc:28:6e:64:6e:3c:53:87:53:5d:50:95:14:b3:b3:26:e1:23:4f:9c:b4:8c:36:dd:d4:4b:41:6d:23:65:40:34:a6:6f:40:3b:a5:11:c5:ef:a3 sha1 f7:81:13:e8:60:f0:30:a8:72:92:3f:ce:93:e3:38:1c:77:a4:2a:30
+b0:12:34:56:78 f8 000000 rsa 03 a9:9a:6d:3e:07:18:89:ed:9e:3a:0c:39:1c:69:b0:b8:04:fc:16:0b:2b:4b:dd:57:0c:92:dd:5a:0f:45:f5:3e:86:21:f7:c9:6c:40:22:42:66:73:5e:1e:e1:b3:c0:62:38:ae:35:04:63:20:fd:8e:81:f8:ce:b3:f8:b4:c9:7b:94:09:30:a3:ac:5e:79:00:86:da:d4:1a:6a:4f:51:17:ba:1c:e2:43:8a:51:ac:05:3e:b0:02:ae:d8:66:d2:c4:58:fd:73:35:90:21:a1:20:29:a0:c0:43:04:5c:11:66:4f:e0:21:9e:c6:3c:10:bf:21:55:bb:27:84:60:9a:10:64:21:d4:51:63:79:97:38:c1:c3:09:09:bb:6c:6f:e5:2b:bb:76:39:7b:97:40:ce:06:4a:61:3f:f8:41:11:85:f0:88:42:a4:23:ea:d2:0e:df:fb:ff:1c:d6:c3:fe:0c:98:21:47:91:99:c2:6d:85:72:cc:8a:ff:f0:87:a9:c3 sha1 66:46:9c:88:e7:dc:11:15:29:c7:d3:79:d7:93:8c:8d:f3:e4:c2:5e
+b0:12:34:56:78 f9 000000 rsa 01:00:01 a6:e6:fb:72:17:95:06:f8:60:cc:ca:8c:27:f9:9c:ec:d9:4c:7d:4f:31:91:d3:03:bb:ee:37:48:1c:7a:a1:5f:23:3b:a7:55:e9:e4:37:63:45:a9:a6:7e:79:94:bd:c1:c6:80:bb:35:22:d8:c9:3e:b0:cc:c9:1a:d3:1a:d4:50:da:30:d3:37:66:2d:19:ac:03:e2:b4:ef:5f:6e:c1:82:82:d4:91:e1:97:67:d7:b2:45:42:df:de:ff:6f:62:18:55:03:53:20:69:bb:b3:69:e3:bb:9f:b1:9a:c6:f1:c3:0b:97:d2:49:ee:e7:64:e0:ba:c9:7f:25:c8:73:d9:73:95:3e:51:53:a4:20:64:bb:fa:bf:d0:6a:4b:b4:86:86:0b:f6:63:74:06:c9:fc:36:81:3a:4a:75:f7:5c:31:cc:a9:f6:9f:8d:e5:9a:de:ce:f6:bd:e7:e0:78:00:fc:be:03:5d:31:76:af:84:73:e2:3e:9a:a3:df:ee:22:11:96:d1:14:83:02:67:7c:72:0c:fe:25:44:a0:3d:b5:53:e7:f1:b8:42:7b:a1:cc:72:b0:f2:9b:12:df:ef:4c:08:1d:07:6d:35:3e:71:88:0a:ad:ff:38:63:52:af:0a:b7:b2:8e:d4:9e:1e:67:2d:11:f9 sha1 ae:ac:a4:54:80:c8:83:4c:b0:be:bd:cc:57:0b:7b:2b:74:bb:4b:79
index 3c3c1f1129b86509c89c877398b22e737e9c451a..c53b02af1a1dd1e4e58225a0f2dc905332e312ae 100644 (file)
@@ -8,7 +8,9 @@
 // EMV commands
 //-----------------------------------------------------------------------------
 
+#include <ctype.h>
 #include "cmdemv.h"
+#include "test/cryptotest.h"
 
 int UsageCmdHFEMVSelect(void) {
        PrintAndLog("HELP :  Executes select applet command:\n");
@@ -68,7 +70,7 @@ int CmdHFEMVSelect(const char *cmd) {
                                        return 1;
                }
 
-               if (isxdigit(c)) {
+               if (isxdigit((unsigned char)c)) {
                        switch(param_gethex_to_eol(cmd, cmdp, data, sizeof(data), &datalen)) {
                        case 1:
                                PrintAndLog("Invalid HEX value.");
@@ -277,34 +279,48 @@ int CmdHFEMVPPSE(const char *cmd) {
 
 int UsageCmdHFEMVExec(void) {
        PrintAndLog("HELP :  Executes EMV contactless transaction:\n");
-       PrintAndLog("Usage:  hf emv exec [-s][-a][-t]\n");
+       PrintAndLog("Usage:  hf emv exec [-s][-a][-t][-f][-v][-c][-x][-g]\n");
        PrintAndLog("  Options:");
        PrintAndLog("  -s       : select card");
        PrintAndLog("  -a       : show APDU reqests and responses\n");
        PrintAndLog("  -t       : TLV decode results\n");
        PrintAndLog("  -f       : force search AID. Search AID instead of execute PPSE.\n");
+       PrintAndLog("  -v       : transaction type - qVSDC or M/Chip.\n");
+       PrintAndLog("  -c       : transaction type - qVSDC or M/Chip plus CDA (SDAD generation).\n");
+       PrintAndLog("  -x       : transaction type - VSDC. For test only. Not a standart behavior.\n");
+       PrintAndLog("  -g       : VISA. generate AC from GPO\n");
+       PrintAndLog("By default : transaction type - MSD.\n");
        PrintAndLog("Samples:");
-       PrintAndLog(" hf emv pse -s -> select card");
-       PrintAndLog(" hf emv pse -s -t -a -> select card, show responses in TLV, show APDU");
+       PrintAndLog(" hf emv exec -s -a -t -> execute MSD transaction");
+       PrintAndLog(" hf emv exec -s -a -t -c -> execute CDA transaction");
        return 0;
 }
 
 #define TLV_ADD(tag, value)( tlvdb_add(tlvRoot, tlvdb_fixed(tag, sizeof(value) - 1, (const unsigned char *)value)) )
+#define dreturn(n) {free(pdol_data_tlv);tlvdb_free(tlvSelect);tlvdb_free(tlvRoot);DropField();return n;}
 
 int CmdHFEMVExec(const char *cmd) {
        bool activateField = false;
        bool showAPDU = false;
        bool decodeTLV = false;
        bool forceSearch = false;
+       enum TransactionType TrType = TT_MSD;
+       bool GenACGPO = false;
 
        uint8_t buf[APDU_RES_LEN] = {0};
        size_t len = 0;
        uint16_t sw = 0;
        uint8_t AID[APDU_AID_LEN] = {0};
        size_t AIDlen = 0;
+       uint8_t ODAiList[4096];
+       size_t ODAiListLen = 0;
        
        int res;
        
+       struct tlvdb *tlvSelect = NULL;
+       struct tlvdb *tlvRoot = NULL;
+       struct tlv *pdol_data_tlv = NULL;
+
        if (strlen(cmd) < 1) {
                UsageCmdHFEMVExec();
                return 0;
@@ -317,7 +333,7 @@ int CmdHFEMVExec(const char *cmd) {
                        switch (param_getchar_indx(cmd, 1, cmdp)) {
                                case 'h':
                                case 'H':
-                                       UsageCmdHFEMVPPSE();
+                                       UsageCmdHFEMVExec();
                                        return 0;
                                case 's':
                                case 'S':
@@ -335,6 +351,22 @@ int CmdHFEMVExec(const char *cmd) {
                                case 'F':
                                        forceSearch = true;
                                        break;
+                               case 'x':
+                               case 'X':
+                                       TrType = TT_VSDC;
+                                       break;
+                               case 'v':
+                               case 'V':
+                                       TrType = TT_QVSDCMCHIP;
+                                       break;
+                               case 'c':
+                               case 'C':
+                                       TrType = TT_CDA;
+                                       break;
+                               case 'g':
+                               case 'G':
+                                       GenACGPO = true;
+                                       break;
                                default:
                                        PrintAndLog("Unknown parameter '%c'", param_getchar_indx(cmd, 1, cmdp));
                                        return 1;
@@ -344,7 +376,6 @@ int CmdHFEMVExec(const char *cmd) {
 
        
        // init applets list tree
-       struct tlvdb *tlvSelect = NULL;
        const char *al = "Applets list";
        tlvSelect = tlvdb_fixed(1, strlen(al), (const unsigned char *)al);
 
@@ -368,8 +399,7 @@ int CmdHFEMVExec(const char *cmd) {
                PrintAndLog("\n* Search AID in list.");
                SetAPDULogging(false);
                if (EMVSearch(activateField, true, decodeTLV, tlvSelect)) {
-                       tlvdb_free(tlvSelect);
-                       return 2;
+                       dreturn(2);
                }
 
                // check search and select application id
@@ -378,14 +408,13 @@ int CmdHFEMVExec(const char *cmd) {
        }
        
        // Init TLV tree
-       struct tlvdb *tlvRoot = NULL;
        const char *alr = "Root terminal TLV tree";
        tlvRoot = tlvdb_fixed(1, strlen(alr), (const unsigned char *)alr);
        
        // check if we found EMV application on card
        if (!AIDlen) {
                PrintAndLog("Can't select AID. EMV AID not found");
-               return 2;
+               dreturn(2);
        }
        
        // Select
@@ -395,20 +424,40 @@ int CmdHFEMVExec(const char *cmd) {
        
        if (res) {      
                PrintAndLog("Can't select AID (%d). Exit...", res);
-               return 3;
+               dreturn(3);
        }
        
        if (decodeTLV)
                TLVPrintFromBuffer(buf, len);
        PrintAndLog("* Selected.");
        
-PrintAndLog("-----BREAK.");
-return 0;
        PrintAndLog("\n* Init transaction parameters.");
 
     //9F66:(Terminal Transaction Qualifiers (TTQ)) len:4
-       TLV_ADD(0x9F66, "\x26\x00\x00\x00"); // E6
-    //9F02:(Amount, Authorised (Numeric)) len:6
+       char *qVSDC = "\x26\x00\x00\x00";
+       if (GenACGPO) {
+               qVSDC = "\x26\x80\x00\x00";
+       }
+       switch(TrType) {
+               case TT_MSD:
+                       TLV_ADD(0x9F66, "\x86\x00\x00\x00"); // MSD
+                       break;
+               // not standard for contactless. just for test.
+               case TT_VSDC:  
+                       TLV_ADD(0x9F66, "\x46\x00\x00\x00"); // VSDC
+                       break;
+               case TT_QVSDCMCHIP:
+                       TLV_ADD(0x9F66, qVSDC); // qVSDC
+                       break;
+               case TT_CDA:
+                       TLV_ADD(0x9F66, qVSDC); // qVSDC (VISA CDA not enabled)
+                       break;
+               default:
+                       TLV_ADD(0x9F66, "\x26\x00\x00\x00"); // qVSDC
+                       break;
+       }
+       
+    //9F02:(Amount, authorized (Numeric)) len:6
        TLV_ADD(0x9F02, "\x00\x00\x00\x00\x01\x00");
     //9F1A:(Terminal Country Code) len:2
        TLV_ADD(0x9F1A, "ru");
@@ -421,53 +470,82 @@ return 0;
        TLV_ADD(0x9C,   "\x00");
        // 9F37 Unpredictable Number len:4
        TLV_ADD(0x9F37, "\x01\x02\x03\x04");
+       // 9F6A Unpredictable Number (MSD for UDOL) len:4
+       TLV_ADD(0x9F6A, "\x01\x02\x03\x04");
 
-       TLVPrintFromTLV(tlvRoot);
+       TLVPrintFromTLV(tlvRoot); // TODO delete!!!
        
        PrintAndLog("\n* Calc PDOL.");
-       struct tlv *pdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x9f38, NULL), tlvRoot, 0x83);
+       pdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x9f38, NULL), tlvRoot, 0x83);
        if (!pdol_data_tlv){
                PrintAndLog("ERROR: can't create PDOL TLV.");
-               return 4;
+               dreturn(4);
        }
        
        size_t pdol_data_tlv_data_len;
        unsigned char *pdol_data_tlv_data = tlv_encode(pdol_data_tlv, &pdol_data_tlv_data_len);
        if (!pdol_data_tlv_data) {
                PrintAndLog("ERROR: can't create PDOL data.");
-               return 4;
+               dreturn(4);
        }
        PrintAndLog("PDOL data[%d]: %s", pdol_data_tlv_data_len, sprint_hex(pdol_data_tlv_data, pdol_data_tlv_data_len));
 
-//PrintAndLog("-----BREAK.");
-//return 0;
        PrintAndLog("\n* GPO.");
        res = EMVGPO(true, pdol_data_tlv_data, pdol_data_tlv_data_len, buf, sizeof(buf), &len, &sw, tlvRoot);
        
-       free(pdol_data_tlv);
+       free(pdol_data_tlv_data);
+       //free(pdol_data_tlv); --- free on exit.
        
        if (res) {      
                PrintAndLog("GPO error(%d): %4x. Exit...", res, sw);
-               return 5;
+               dreturn(5);
        }
 
        // process response template format 1 [id:80  2b AIP + x4b AFL] and format 2 [id:77 TLV]
        if (buf[0] == 0x80) {
-               
-               
-               
                if (decodeTLV){
                        PrintAndLog("GPO response format1:");
                        TLVPrintFromBuffer(buf, len);
                }
-       } else {
-               
-               
                
+               if (len < 4 || (len - 4) % 4) {
+                       PrintAndLog("ERROR: GPO response format1 parsing error. length=%d", len);
+               } else {
+                       // AIP
+                       struct tlvdb * f1AIP = tlvdb_fixed(0x82, 2, buf + 2);
+                       tlvdb_add(tlvRoot, f1AIP);
+                       if (decodeTLV){
+                               PrintAndLog("\n* * Decode response format 1 (0x80) AIP and AFL:");
+                               TLVPrintFromTLV(f1AIP);
+                       }
+
+                       // AFL
+                       struct tlvdb * f1AFL = tlvdb_fixed(0x94, len - 4, buf + 2 + 2);
+                       tlvdb_add(tlvRoot, f1AFL);
+                       if (decodeTLV)
+                               TLVPrintFromTLV(f1AFL);
+               }               
+       } else {
                if (decodeTLV)
                        TLVPrintFromBuffer(buf, len);
        }
        
+       // extract PAN from track2
+       {
+               const struct tlv *track2 = tlvdb_get(tlvRoot, 0x57, NULL);
+               if (!tlvdb_get(tlvRoot, 0x5a, NULL) && track2 && track2->len >= 8) {
+                       struct tlvdb *pan = GetPANFromTrack2(track2);
+                       if (pan) {
+                               tlvdb_add(tlvRoot, pan); 
+                               
+                               const struct tlv *pantlv = tlvdb_get(tlvRoot, 0x5a, NULL);      
+                               PrintAndLog("\n* * Extracted PAN from track2: %s", sprint_hex(pantlv->value, pantlv->len));
+                       } else {
+                               PrintAndLog("\n* * WARNING: Can't extract PAN from track2.");
+                       }
+               }
+       }
+       
        PrintAndLog("\n* Read records from AFL.");
        const struct tlv *AFL = tlvdb_get(tlvRoot, 0x94, NULL);
        if (!AFL || !AFL->len) {
@@ -506,9 +584,23 @@ return 0;
                                        PrintAndLog("");
                                }
                                
+                               // Build Input list for Offline Data Authentication
+                               // EMV 4.3 book3 10.3, page 96
                                if (SFIoffline) {
-                                       // here will be offline records storing...
-                                       // dont foget: if (sfi < 11)
+                                       if (SFI < 11) {
+                                               const unsigned char *abuf = buf;
+                                               size_t elmlen = len;
+                                               struct tlv e;
+                                               if (tlv_parse_tl(&abuf, &elmlen, &e)) {
+                                                       memcpy(&ODAiList[ODAiListLen], &buf[len - elmlen], elmlen);
+                                                       ODAiListLen += elmlen;
+                                               } else {
+                                                       PrintAndLog("ERROR SFI[%02x]. Creating input list for Offline Data Authentication error.", SFI);
+                                               }
+                                       } else {
+                                               memcpy(&ODAiList[ODAiListLen], buf, len);
+                                               ODAiListLen += len;
+                                       }
                                }
                        }
                }
@@ -516,13 +608,218 @@ return 0;
                break;
        }       
        
-       // additional contacless EMV commands (fDDA, CDA, external authenticate)
+       // copy Input list for Offline Data Authentication
+       if (ODAiListLen) {
+               struct tlvdb *oda = tlvdb_fixed(0x21, ODAiListLen, ODAiList); // not a standard tag
+               tlvdb_add(tlvRoot, oda); 
+               PrintAndLog("* Input list for Offline Data Authentication added to TLV. len=%d \n", ODAiListLen);
+       }
+       
+       // get AIP
+       const struct tlv *AIPtlv = tlvdb_get(tlvRoot, 0x82, NULL);      
+       uint16_t AIP = AIPtlv->value[0] + AIPtlv->value[1] * 0x100;
+       PrintAndLog("* * AIP=%04x", AIP);
+
+       // SDA
+       if (AIP & 0x0040) {
+               PrintAndLog("\n* SDA");
+               trSDA(tlvRoot);
+       }
+
+       // DDA
+       if (AIP & 0x0020) {
+               PrintAndLog("\n* DDA");
+               trDDA(decodeTLV, tlvRoot);
+       }       
        
+       // transaction check
+       
+       // qVSDC
+       if (TrType == TT_QVSDCMCHIP|| TrType == TT_CDA){
+               // 9F26: Application Cryptogram
+               const struct tlv *AC = tlvdb_get(tlvRoot, 0x9F26, NULL);
+               if (AC) {
+                       PrintAndLog("\n--> qVSDC transaction.");
+                       PrintAndLog("* AC path");
+                       
+                       // 9F36: Application Transaction Counter (ATC)
+                       const struct tlv *ATC = tlvdb_get(tlvRoot, 0x9F36, NULL);
+                       if (ATC) {
+                       
+                               // 9F10: Issuer Application Data - optional
+                               const struct tlv *IAD = tlvdb_get(tlvRoot, 0x9F10, NULL);
+
+                               // print AC data
+                               PrintAndLog("ATC: %s", sprint_hex(ATC->value, ATC->len));
+                               PrintAndLog("AC: %s", sprint_hex(AC->value, AC->len));
+                               if (IAD){
+                                       PrintAndLog("IAD: %s", sprint_hex(IAD->value, IAD->len));
+                                       
+                                       if (IAD->len >= IAD->value[0] + 1) {
+                                               PrintAndLog("\tKey index:  0x%02x", IAD->value[1]);
+                                               PrintAndLog("\tCrypto ver: 0x%02x(%03d)", IAD->value[2], IAD->value[2]);
+                                               PrintAndLog("\tCVR:", sprint_hex(&IAD->value[3], IAD->value[0] - 2));
+                                               struct tlvdb * cvr = tlvdb_fixed(0x20, IAD->value[0] - 2, &IAD->value[3]);
+                                               TLVPrintFromTLVLev(cvr, 1);
+                                       }
+                               } else {
+                                       PrintAndLog("WARNING: IAD not found.");
+                               }
+                               
+                       } else {
+                               PrintAndLog("ERROR AC: Application Transaction Counter (ATC) not found.");
+                       }
+               }
+       }
        
+       // Mastercard M/CHIP
+       if (GetCardPSVendor(AID, AIDlen) == CV_MASTERCARD && (TrType == TT_QVSDCMCHIP || TrType == TT_CDA)){
+               const struct tlv *CDOL1 = tlvdb_get(tlvRoot, 0x8c, NULL);
+               if (CDOL1 && GetCardPSVendor(AID, AIDlen) == CV_MASTERCARD) { // and m/chip transaction flag
+                       PrintAndLog("\n--> Mastercard M/Chip transaction.");
+
+                       PrintAndLog("* * Generate challenge");
+                       res = EMVGenerateChallenge(true, buf, sizeof(buf), &len, &sw, tlvRoot);
+                       if (res) {
+                               PrintAndLog("ERROR GetChallenge. APDU error %4x", sw);
+                               dreturn(6);
+                       }
+                       if (len < 4) {
+                               PrintAndLog("ERROR GetChallenge. Wrong challenge length %d", len);
+                               dreturn(6);
+                       }
+                       
+                       // ICC Dynamic Number
+                       struct tlvdb * ICCDynN = tlvdb_fixed(0x9f4c, len, buf);
+                       tlvdb_add(tlvRoot, ICCDynN);
+                       if (decodeTLV){
+                               PrintAndLog("\n* * ICC Dynamic Number:");
+                               TLVPrintFromTLV(ICCDynN);
+                       }
+                       
+                       PrintAndLog("* * Calc CDOL1");
+                       struct tlv *cdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x8c, NULL), tlvRoot, 0x01); // 0x01 - dummy tag
+                       if (!cdol_data_tlv){
+                               PrintAndLog("ERROR: can't create CDOL1 TLV.");
+                               dreturn(6);
+                       }
+                       PrintAndLog("CDOL1 data[%d]: %s", cdol_data_tlv->len, sprint_hex(cdol_data_tlv->value, cdol_data_tlv->len));
+                       
+                       PrintAndLog("* * AC1");
+                       // EMVAC_TC + EMVAC_CDAREQ --- to get SDAD
+                       res = EMVAC(true, (TrType == TT_CDA) ? EMVAC_TC + EMVAC_CDAREQ : EMVAC_TC, (uint8_t *)cdol_data_tlv->value, cdol_data_tlv->len, buf, sizeof(buf), &len, &sw, tlvRoot);
+                       
+                       if (res) {      
+                               PrintAndLog("AC1 error(%d): %4x. Exit...", res, sw);
+                               dreturn(7);
+                       }
+                       
+                       if (decodeTLV)
+                               TLVPrintFromBuffer(buf, len);
+                       
+                       // CDA
+                       PrintAndLog("\n* CDA:");
+                       struct tlvdb *ac_tlv = tlvdb_parse_multi(buf, len);
+                       res = trCDA(tlvRoot, ac_tlv, pdol_data_tlv, cdol_data_tlv);
+                       if (res) {      
+                               PrintAndLog("CDA error (%d)", res);
+                       }
+                       free(ac_tlv);
+                       free(cdol_data_tlv);
+                       
+                       PrintAndLog("\n* M/Chip transaction result:");
+                       // 9F27: Cryptogram Information Data (CID)
+                       const struct tlv *CID = tlvdb_get(tlvRoot, 0x9F27, NULL);
+                       if (CID) {
+                               emv_tag_dump(CID, stdout, 0);
+                               PrintAndLog("------------------------------");
+                               if (CID->len > 0) {
+                                       switch(CID->value[0] & EMVAC_AC_MASK){
+                                               case EMVAC_AAC:
+                                                       PrintAndLog("Transaction DECLINED.");
+                                                       break;
+                                               case EMVAC_TC:
+                                                       PrintAndLog("Transaction approved OFFLINE.");
+                                                       break;
+                                               case EMVAC_ARQC:
+                                                       PrintAndLog("Transaction approved ONLINE.");
+                                                       break;
+                                               default:
+                                                       PrintAndLog("ERROR: CID transaction code error %2x", CID->value[0] & EMVAC_AC_MASK);
+                                                       break;
+                                       }
+                               } else {
+                                       PrintAndLog("ERROR: Wrong CID length %d", CID->len);
+                               }
+                       } else {
+                               PrintAndLog("ERROR: CID(9F27) not found.");
+                       }
+               
+               }
+       }
+               
+       // MSD
+       if (AIP & 0x8000 && TrType == TT_MSD) { 
+               PrintAndLog("\n--> MSD transaction.");
+               
+               PrintAndLog("* MSD dCVV path. Check dCVV");
+
+               const struct tlv *track2 = tlvdb_get(tlvRoot, 0x57, NULL);
+               if (track2) {
+                       PrintAndLog("Track2: %s", sprint_hex(track2->value, track2->len));
+
+                       struct tlvdb *dCVV = GetdCVVRawFromTrack2(track2);
+                       PrintAndLog("dCVV raw data:");
+                       TLVPrintFromTLV(dCVV);
+                       
+                       if (GetCardPSVendor(AID, AIDlen) == CV_MASTERCARD) {
+                               PrintAndLog("\n* Mastercard calculate UDOL");
+
+                               // UDOL (9F69)
+                               const struct tlv *UDOL = tlvdb_get(tlvRoot, 0x9F69, NULL);
+                               // UDOL(9F69) default: 9F6A (Unpredictable number) 4 bytes
+                               const struct tlv defUDOL = {
+                                       .tag = 0x01,
+                                       .len = 3,
+                                       .value = (uint8_t *)"\x9f\x6a\x04",
+                               };
+                               if (!UDOL)
+                                       PrintAndLog("Use default UDOL.");
+
+                               struct tlv *udol_data_tlv = dol_process(UDOL ? UDOL : &defUDOL, tlvRoot, 0x01); // 0x01 - dummy tag
+                               if (!udol_data_tlv){
+                                       PrintAndLog("ERROR: can't create UDOL TLV.");
+                                       dreturn(8);
+                               }
+
+                               PrintAndLog("UDOL data[%d]: %s", udol_data_tlv->len, sprint_hex(udol_data_tlv->value, udol_data_tlv->len));
+                               
+                               PrintAndLog("\n* Mastercard compute cryptographic checksum(UDOL)");
+                               
+                               res = MSCComputeCryptoChecksum(true, (uint8_t *)udol_data_tlv->value, udol_data_tlv->len, buf, sizeof(buf), &len, &sw, tlvRoot);
+                               if (res) {
+                                       PrintAndLog("ERROR Compute Crypto Checksum. APDU error %4x", sw);
+                                       free(udol_data_tlv);
+                                       dreturn(9);
+                               }
+                               
+                               if (decodeTLV) {
+                                       TLVPrintFromBuffer(buf, len);
+                                       PrintAndLog("");
+                               }
+                               free(udol_data_tlv);
+
+                       }
+               } else {
+                       PrintAndLog("ERROR MSD: Track2 data not found.");
+               }
+       }
+
        // DropField
        DropField();
        
        // Destroy TLV's
+       free(pdol_data_tlv);
        tlvdb_free(tlvSelect);
        tlvdb_free(tlvRoot);
 
@@ -531,6 +828,10 @@ return 0;
        return 0;
 }
 
+int CmdHFEMVTest(const char *cmd) {
+       return ExecuteCryptoTests(true);
+}
+
 int CmdHelp(const char *Cmd);
 static command_t CommandTable[] =  {
        {"help",        CmdHelp,                1,      "This help"},
@@ -538,6 +839,7 @@ static command_t CommandTable[] =  {
        {"pse",         CmdHFEMVPPSE,   0,      "Execute PPSE. It selects 2PAY.SYS.DDF01 or 1PAY.SYS.DDF01 directory."},
        {"search",      CmdHFEMVSearch, 0,      "Try to select all applets from applets list and print installed applets."},
        {"select",      CmdHFEMVSelect, 0,      "Select applet."},
+       {"test",        CmdHFEMVTest,   0,      "Crypto logic test."},
        {NULL, NULL, 0, NULL}
 };
 
index 78796efab65d4ba5b231a022316675a6636e2f98..b3f76508a85e9ef1ea8c7dc3ab324a8550f1276c 100644 (file)
@@ -15,6 +15,7 @@
 #include <stdlib.h>
 #include <inttypes.h>
 #include <string.h>
+#include <ctype.h>
 #include "proxmark3.h"
 #include "ui.h"
 #include "cmdparser.h"
diff --git a/client/emv/crypto.c b/client/emv/crypto.c
new file mode 100644 (file)
index 0000000..c8ced6d
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * libopenemv - a library to work with EMV family of smart cards
+ * Copyright (C) 2015 Dmitry Eremin-Solenikov
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "crypto.h"
+#include "crypto_backend.h"
+
+#include <string.h>
+
+static struct crypto_backend *crypto_backend;
+
+static bool crypto_init(void)
+{
+       if (crypto_backend)
+               return true;
+
+       crypto_backend = crypto_polarssl_init(); 
+
+       if (!crypto_backend)
+               return false;
+
+       return true;
+}
+
+struct crypto_hash *crypto_hash_open(enum crypto_algo_hash hash)
+{
+       struct crypto_hash *ch;
+
+       if (!crypto_init())
+               return NULL;
+
+       ch = crypto_backend->hash_open(hash);
+       if (ch)
+               ch->algo = hash;
+
+       return ch;
+}
+
+void crypto_hash_close(struct crypto_hash *ch)
+{
+       ch->close(ch);
+}
+
+void crypto_hash_write(struct crypto_hash *ch, const unsigned char *buf, size_t len)
+{
+       ch->write(ch, buf, len);
+}
+
+unsigned char *crypto_hash_read(struct crypto_hash *ch)
+{
+       return ch->read(ch);
+}
+
+size_t crypto_hash_get_size(const struct crypto_hash *ch)
+{
+       return ch->get_size(ch);
+}
+
+struct crypto_pk *crypto_pk_open(enum crypto_algo_pk pk, ...)
+{
+       struct crypto_pk *cp;
+       va_list vl;
+
+       if (!crypto_init())
+               return NULL;
+
+       va_start(vl, pk);
+       cp = crypto_backend->pk_open(pk, vl);
+       va_end(vl);
+
+       if (cp)
+               cp->algo = pk;
+
+       return cp;
+}
+
+struct crypto_pk *crypto_pk_open_priv(enum crypto_algo_pk pk, ...)
+{
+       struct crypto_pk *cp;
+       va_list vl;
+
+       if (!crypto_init())
+               return NULL;
+
+       if (!crypto_backend->pk_open_priv)
+               return NULL;
+
+       va_start(vl, pk);
+       cp = crypto_backend->pk_open_priv(pk, vl);
+       va_end(vl);
+
+       if (cp)
+               cp->algo = pk;
+
+       return cp;
+}
+
+struct crypto_pk *crypto_pk_genkey(enum crypto_algo_pk pk, ...)
+{
+       struct crypto_pk *cp;
+       va_list vl;
+
+       if (!crypto_init())
+               return NULL;
+
+       if (!crypto_backend->pk_genkey)
+               return NULL;
+
+       va_start(vl, pk);
+       cp = crypto_backend->pk_genkey(pk, vl);
+       va_end(vl);
+
+       if (cp)
+               cp->algo = pk;
+
+       return cp;
+}
+
+void crypto_pk_close(struct crypto_pk *cp)
+{
+       cp->close(cp);
+}
+
+unsigned char *crypto_pk_encrypt(const struct crypto_pk *cp, const unsigned char *buf, size_t len, size_t *clen)
+{
+       return cp->encrypt(cp, buf, len, clen);
+}
+
+unsigned char *crypto_pk_decrypt(const struct crypto_pk *cp, const unsigned char *buf, size_t len, size_t *clen)
+{
+       if (!cp->decrypt) {
+               *clen = 0;
+
+               return NULL;
+       }
+
+       return cp->decrypt(cp, buf, len, clen);
+}
+
+enum crypto_algo_pk crypto_pk_get_algo(const struct crypto_pk *cp)
+{
+       if (!cp)
+               return PK_INVALID;
+
+       return cp->algo;
+}
+
+size_t crypto_pk_get_nbits(const struct crypto_pk *cp)
+{
+       if (!cp->get_nbits)
+               return 0;
+
+       return cp->get_nbits(cp);
+}
+
+unsigned char *crypto_pk_get_parameter(const struct crypto_pk *cp, unsigned param, size_t *plen)
+{
+       *plen = 0;
+
+       if (!cp->get_parameter)
+               return NULL;
+
+       return cp->get_parameter(cp, param, plen);
+}
diff --git a/client/emv/crypto.h b/client/emv/crypto.h
new file mode 100644 (file)
index 0000000..940e8b2
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * libopenemv - a library to work with EMV family of smart cards
+ * Copyright (C) 2015 Dmitry Eremin-Solenikov
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifndef CRYPTO_H
+#define CRYPTO_H
+
+#include <stdbool.h>
+#include <stddef.h>
+
+enum crypto_algo_hash {
+       HASH_INVALID,
+       HASH_SHA_1,
+};
+
+struct crypto_hash *crypto_hash_open(enum crypto_algo_hash hash);
+void crypto_hash_close(struct crypto_hash *ch);
+void crypto_hash_write(struct crypto_hash *ch, const unsigned char *buf, size_t len);
+unsigned char *crypto_hash_read(struct crypto_hash *ch);
+size_t crypto_hash_get_size(const struct crypto_hash *ch);
+
+enum crypto_algo_pk {
+       PK_INVALID,
+       PK_RSA,
+};
+
+struct crypto_pk *crypto_pk_open(enum crypto_algo_pk pk, ...);
+struct crypto_pk *crypto_pk_open_priv(enum crypto_algo_pk pk, ...);
+struct crypto_pk *crypto_pk_genkey(enum crypto_algo_pk pk, ...);
+void crypto_pk_close(struct crypto_pk *cp);
+unsigned char *crypto_pk_encrypt(const struct crypto_pk *cp, const unsigned char *buf, size_t len, size_t *clen);
+unsigned char *crypto_pk_decrypt(const struct crypto_pk *cp, const unsigned char *buf, size_t len, size_t *clen);
+enum crypto_algo_pk crypto_pk_get_algo(const struct crypto_pk *cp);
+size_t crypto_pk_get_nbits(const struct crypto_pk *cp);
+unsigned char *crypto_pk_get_parameter(const struct crypto_pk *cp, unsigned param, size_t *plen);
+
+#endif
diff --git a/client/emv/crypto_backend.h b/client/emv/crypto_backend.h
new file mode 100644 (file)
index 0000000..a815ae1
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * libopenemv - a library to work with EMV family of smart cards
+ * Copyright (C) 2015 Dmitry Eremin-Solenikov
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifndef CRYPTO_BACKEND_H
+#define CRYPTO_BACKEND_H
+
+#include "crypto.h"
+
+#include <stddef.h>
+#include <stdarg.h>
+
+struct crypto_hash {
+       enum crypto_algo_hash algo;
+       void (*write)(struct crypto_hash *ch, const unsigned char *buf, size_t len);
+       unsigned char *(*read)(struct crypto_hash *ch);
+       void (*close)(struct crypto_hash *ch);
+       size_t (*get_size)(const struct crypto_hash *ch);
+};
+
+struct crypto_pk {
+       enum crypto_algo_pk algo;
+       unsigned char *(*encrypt)(const struct crypto_pk *cp, const unsigned char *buf, size_t len, size_t *clen);
+       unsigned char *(*decrypt)(const struct crypto_pk *cp, const unsigned char *buf, size_t len, size_t *clen);
+       unsigned char *(*get_parameter)(const struct crypto_pk *cp, unsigned param, size_t *plen);
+       size_t (*get_nbits)(const struct crypto_pk *cp);
+       void (*close)(struct crypto_pk *cp);
+};
+
+struct crypto_backend {
+       struct crypto_hash *(*hash_open)(enum crypto_algo_hash hash);
+       struct crypto_pk *(*pk_open)(enum crypto_algo_pk pk, va_list vl);
+       struct crypto_pk *(*pk_open_priv)(enum crypto_algo_pk pk, va_list vl);
+       struct crypto_pk *(*pk_genkey)(enum crypto_algo_pk pk, va_list vl);
+};
+
+struct crypto_backend *crypto_polarssl_init(void);
+
+#endif
diff --git a/client/emv/crypto_polarssl.c b/client/emv/crypto_polarssl.c
new file mode 100644 (file)
index 0000000..760395c
--- /dev/null
@@ -0,0 +1,351 @@
+/*
+ * libopenemv - a library to work with EMV family of smart cards
+ * Copyright (C) 2015 Dmitry Eremin-Solenikov
+ * Copyright (C) 2017 Merlok
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "crypto.h"
+#include "crypto_backend.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "rsa.h"
+#include "sha1.h"
+
+struct crypto_hash_polarssl {
+       struct crypto_hash ch;
+       sha1_context ctx;
+};
+
+static void crypto_hash_polarssl_close(struct crypto_hash *_ch)
+{
+       struct crypto_hash_polarssl *ch = (struct crypto_hash_polarssl *)_ch;
+
+       free(ch);
+}
+
+static void crypto_hash_polarssl_write(struct crypto_hash *_ch, const unsigned char *buf, size_t len)
+{
+       struct crypto_hash_polarssl *ch = (struct crypto_hash_polarssl *)_ch;
+
+       sha1_update(&(ch->ctx), buf, len);
+}
+
+static unsigned char *crypto_hash_polarssl_read(struct crypto_hash *_ch)
+{
+       struct crypto_hash_polarssl *ch = (struct crypto_hash_polarssl *)_ch;
+
+       static unsigned char sha1sum[20];
+       sha1_finish(&(ch->ctx), sha1sum);
+       return sha1sum;
+}
+
+static size_t crypto_hash_polarssl_get_size(const struct crypto_hash *ch)
+{
+       if (ch->algo == HASH_SHA_1)
+               return 20;
+       else
+               return 0;
+}
+
+static struct crypto_hash *crypto_hash_polarssl_open(enum crypto_algo_hash hash)
+{
+       if (hash != HASH_SHA_1)
+               return NULL;
+
+       struct crypto_hash_polarssl *ch = malloc(sizeof(*ch));
+
+       sha1_starts(&(ch->ctx));
+
+       ch->ch.write = crypto_hash_polarssl_write;
+       ch->ch.read = crypto_hash_polarssl_read;
+       ch->ch.close = crypto_hash_polarssl_close;
+       ch->ch.get_size = crypto_hash_polarssl_get_size;
+
+       return &ch->ch;
+}
+
+struct crypto_pk_polarssl {
+       struct crypto_pk cp;
+       rsa_context ctx;
+};
+
+static struct crypto_pk *crypto_pk_polarssl_open_rsa(va_list vl)
+{
+       struct crypto_pk_polarssl *cp = malloc(sizeof(*cp));
+       memset(cp, 0x00, sizeof(*cp));
+
+       char *mod = va_arg(vl, char *);  // N
+       int modlen = va_arg(vl, size_t);
+       char *exp = va_arg(vl, char *);  // E
+       int explen = va_arg(vl, size_t);
+
+       rsa_init(&cp->ctx, RSA_PKCS_V15, 0);
+       
+       cp->ctx.len = modlen; // size(N) in bytes
+       mpi_read_binary(&cp->ctx.N, (const unsigned char *)mod, modlen);
+       mpi_read_binary(&cp->ctx.E, (const unsigned char *)exp, explen);
+       
+       int res = rsa_check_pubkey(&cp->ctx);
+       if(res != 0) {
+               fprintf(stderr, "PolarSSL public key error res=%x exp=%d mod=%d.\n", res * -1, explen, modlen);
+
+               return NULL;
+       }
+
+       return &cp->cp;
+}
+
+static struct crypto_pk *crypto_pk_polarssl_open_priv_rsa(va_list vl)
+{
+       struct crypto_pk_polarssl *cp = malloc(sizeof(*cp));
+       memset(cp, 0x00, sizeof(*cp));
+       char *mod = va_arg(vl, char *);
+       int modlen = va_arg(vl, size_t);
+       char *exp = va_arg(vl, char *);
+       int explen = va_arg(vl, size_t);
+       char *d = va_arg(vl, char *);
+       int dlen = va_arg(vl, size_t);
+       char *p = va_arg(vl, char *);
+       int plen = va_arg(vl, size_t);
+       char *q = va_arg(vl, char *);
+       int qlen = va_arg(vl, size_t);
+       char *dp = va_arg(vl, char *);
+       int dplen = va_arg(vl, size_t);
+       char *dq = va_arg(vl, char *);
+       int dqlen = va_arg(vl, size_t);
+       // calc QP via Q and P
+//     char *inv = va_arg(vl, char *);
+//     int invlen = va_arg(vl, size_t);        
+       
+       rsa_init(&cp->ctx, RSA_PKCS_V15, 0);
+       
+       cp->ctx.len = modlen; // size(N) in bytes
+       mpi_read_binary(&cp->ctx.N,  (const unsigned char *)mod, modlen);
+       mpi_read_binary(&cp->ctx.E,  (const unsigned char *)exp, explen);
+
+       mpi_read_binary(&cp->ctx.D,  (const unsigned char *)d, dlen);
+       mpi_read_binary(&cp->ctx.P,  (const unsigned char *)p, plen);
+       mpi_read_binary(&cp->ctx.Q,  (const unsigned char *)q, qlen);
+       mpi_read_binary(&cp->ctx.DP, (const unsigned char *)dp, dplen);
+       mpi_read_binary(&cp->ctx.DQ, (const unsigned char *)dq, dqlen);
+       mpi_inv_mod(&cp->ctx.QP, &cp->ctx.Q, &cp->ctx.P);
+       
+       int res = rsa_check_privkey(&cp->ctx);
+       if(res != 0) {
+               fprintf(stderr, "PolarSSL private key error res=%x exp=%d mod=%d.\n", res * -1, explen, modlen);
+               return NULL;
+       }
+
+       return &cp->cp;
+}
+
+static int myrand(void *rng_state, unsigned char *output, size_t len) {
+    size_t i;
+
+    if(rng_state != NULL)
+        rng_state = NULL;
+
+    for( i = 0; i < len; ++i )
+        output[i] = rand();
+    
+    return 0;
+}
+
+
+static struct crypto_pk *crypto_pk_polarssl_genkey_rsa(va_list vl)
+{
+       struct crypto_pk_polarssl *cp = malloc(sizeof(*cp));
+       memset(cp, 0x00, sizeof(*cp));
+       
+       int transient = va_arg(vl, int);
+       unsigned int nbits = va_arg(vl, unsigned int);
+       unsigned int exp = va_arg(vl, unsigned int);
+
+       if (transient) {
+       }
+       
+       int res = rsa_gen_key(&cp->ctx, &myrand, NULL, nbits, exp);
+       if (res) {
+               fprintf(stderr, "PolarSSL private key generation error res=%x exp=%d nbits=%d.\n", res * -1, exp, nbits);
+               return NULL;
+       }
+       
+       return &cp->cp;
+}
+
+static void crypto_pk_polarssl_close(struct crypto_pk *_cp)
+{
+       struct crypto_pk_polarssl *cp = (struct crypto_pk_polarssl *)_cp;
+
+       rsa_free(&cp->ctx);
+       free(cp);
+}
+
+static unsigned char *crypto_pk_polarssl_encrypt(const struct crypto_pk *_cp, const unsigned char *buf, size_t len, size_t *clen)
+{
+       struct crypto_pk_polarssl *cp = (struct crypto_pk_polarssl *)_cp;
+       int res;
+       unsigned char *result;
+       
+       *clen = 0;
+       size_t keylen = mpi_size(&cp->ctx.N);
+
+       result = malloc(keylen);
+       if (!result) {
+               printf("RSA encrypt failed. Can't allocate result memory.\n");
+               return NULL;
+       }
+
+       res = rsa_public(&cp->ctx, buf, result);
+       if(res) {
+               printf("RSA encrypt failed. Error: %x data len: %d key len: %d\n", res * -1, len, keylen);
+               return NULL;
+       }
+       
+       *clen = keylen;
+       
+       return result;
+}
+
+static unsigned char *crypto_pk_polarssl_decrypt(const struct crypto_pk *_cp, const unsigned char *buf, size_t len, size_t *clen)
+{
+       struct crypto_pk_polarssl *cp = (struct crypto_pk_polarssl *)_cp;
+       int res;
+       unsigned char *result;
+       
+       *clen = 0;
+       size_t keylen = mpi_size(&cp->ctx.N);
+
+       result = malloc(keylen);
+       if (!result) {
+               printf("RSA encrypt failed. Can't allocate result memory.\n");
+               return NULL;
+       }
+
+       res = rsa_private(&cp->ctx, buf, result); // CHECK???
+       if(res) {
+               printf("RSA decrypt failed. Error: %x data len: %d key len: %d\n", res * -1, len, keylen);
+               return NULL;
+       }
+       
+       *clen = keylen;
+       
+       return result;
+}
+
+static size_t crypto_pk_polarssl_get_nbits(const struct crypto_pk *_cp)
+{
+       struct crypto_pk_polarssl *cp = (struct crypto_pk_polarssl *)_cp;
+
+       return cp->ctx.len * 8;
+return 0;
+}
+
+static unsigned char *crypto_pk_polarssl_get_parameter(const struct crypto_pk *_cp, unsigned param, size_t *plen)
+{
+       struct crypto_pk_polarssl *cp = (struct crypto_pk_polarssl *)_cp;
+       unsigned char *result = NULL;
+       switch(param){
+               // mod
+               case 0:
+                       *plen = mpi_size(&cp->ctx.N);
+                       result = malloc(*plen);
+                       memset(result, 0x00, *plen);
+                       mpi_write_binary(&cp->ctx.N, result, *plen);
+                       break;
+               // exp
+               case 1:
+                       *plen = mpi_size(&cp->ctx.E);
+                       result = malloc(*plen);
+                       memset(result, 0x00, *plen);
+                       mpi_write_binary(&cp->ctx.E, result, *plen);
+                       break;
+               default:
+                       printf("Error get parameter. Param=%d", param);
+                       break;
+       }
+       
+       return result;
+}
+
+static struct crypto_pk *crypto_pk_polarssl_open(enum crypto_algo_pk pk, va_list vl)
+{
+       struct crypto_pk *cp;
+
+       if (pk == PK_RSA)
+               cp = crypto_pk_polarssl_open_rsa(vl);
+       else
+               return NULL;
+
+       cp->close = crypto_pk_polarssl_close;
+       cp->encrypt = crypto_pk_polarssl_encrypt;
+       cp->get_parameter = crypto_pk_polarssl_get_parameter;
+       cp->get_nbits = crypto_pk_polarssl_get_nbits;
+
+       return cp;
+}
+
+static struct crypto_pk *crypto_pk_polarssl_open_priv(enum crypto_algo_pk pk, va_list vl)
+{
+       struct crypto_pk *cp;
+
+       if (pk == PK_RSA)
+               cp = crypto_pk_polarssl_open_priv_rsa(vl);
+       else
+               return NULL;
+
+       cp->close = crypto_pk_polarssl_close;
+       cp->encrypt = crypto_pk_polarssl_encrypt;
+       cp->decrypt = crypto_pk_polarssl_decrypt;
+       cp->get_parameter = crypto_pk_polarssl_get_parameter;
+       cp->get_nbits = crypto_pk_polarssl_get_nbits;
+
+       return cp;
+}
+
+static struct crypto_pk *crypto_pk_polarssl_genkey(enum crypto_algo_pk pk, va_list vl)
+{
+       struct crypto_pk *cp;
+
+       if (pk == PK_RSA)
+               cp = crypto_pk_polarssl_genkey_rsa(vl);
+       else
+               return NULL;
+
+       cp->close = crypto_pk_polarssl_close;
+       cp->encrypt = crypto_pk_polarssl_encrypt;
+       cp->decrypt = crypto_pk_polarssl_decrypt;
+       cp->get_parameter = crypto_pk_polarssl_get_parameter;
+       cp->get_nbits = crypto_pk_polarssl_get_nbits;
+
+       return cp;
+}
+
+static struct crypto_backend crypto_polarssl_backend = {
+       .hash_open = crypto_hash_polarssl_open,
+       .pk_open = crypto_pk_polarssl_open,
+       .pk_open_priv = crypto_pk_polarssl_open_priv,
+       .pk_genkey = crypto_pk_polarssl_genkey,
+};
+
+struct crypto_backend *crypto_polarssl_init(void)
+{
+       return &crypto_polarssl_backend;
+}
diff --git a/client/emv/emv_pk.c b/client/emv/emv_pk.c
new file mode 100644 (file)
index 0000000..b577855
--- /dev/null
@@ -0,0 +1,524 @@
+/*
+ * libopenemv - a library to work with EMV family of smart cards
+ * Copyright (C) 2012, 2015 Dmitry Eremin-Solenikov
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* For asprintf */
+#define _GNU_SOURCE
+#include <stdio.h>
+
+#include "emv_pk.h"
+#include "crypto.h"
+#include "proxmark3.h"
+
+#include <stdbool.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#define BCD(c) (((c) >= '0' && (c) <= '9') ? ((c) - '0') : \
+               -1)
+
+#define HEX(c) (((c) >= '0' && (c) <= '9') ? ((c) - '0') : \
+               ((c) >= 'A' && (c) <= 'F') ? ((c) - 'A' + 10) : \
+               ((c) >= 'a' && (c) <= 'f') ? ((c) - 'a' + 10) : \
+               -1)
+
+#define TOHEX(v) ((v) < 10 ? (v) + '0' : (v) - 10 + 'a')
+
+static ssize_t emv_pk_read_bin(char *buf, unsigned char *bin, size_t size, size_t *read)
+{
+       size_t left = size;
+       char *p = buf;
+       while (*p && *p == ' ')
+               p++;
+
+       while (left > 0) {
+               int c1, c2;
+               c1 = HEX(*p);
+               if (c1 == -1)
+                       return -(p - buf);
+               p++;
+               c2 = HEX(*p);
+               if (c2 == -1)
+                       return -(p - buf);
+               p++;
+               *bin = (c1 * 16 + c2);
+               bin ++;
+               left --;
+               if (*p == ':')
+                       p++;
+               else if (read) {
+                       *read = (size - left);
+                       break;
+               } else if (left == 0)
+                       break;
+               else
+                       return -(p - buf);
+       }
+
+       while (*p && *p == ' ')
+               p++;
+
+       p--;
+
+       return (p - buf);
+}
+
+static ssize_t emv_pk_read_ymv(char *buf, unsigned *ymv)
+{
+       int i;
+       unsigned char temp[3];
+       char *p = buf;
+
+       *ymv = 0;
+
+       while (*p && *p == ' ')
+               p++;
+
+       for (i = 0; i < 3; i++) {
+               int c1, c2;
+               c1 = BCD(*p);
+               if (c1 == -1)
+                       return -(p - buf);
+               p++;
+               c2 = BCD(*p);
+               if (c2 == -1)
+                       return -(p - buf);
+               p++;
+               temp[i] = (c1 * 16 + c2);
+       }
+
+       while (*p && *p == ' ')
+               p++;
+
+       p--;
+
+       if (temp[1] > 0x12 || temp[2] > 0x31)
+               return -(p - buf);
+
+       *ymv = (temp[0] * 0x10000 + temp[1] * 0x100 + temp[2]);
+
+       return (p - buf);
+}
+
+static ssize_t emv_pk_read_string(char *buf, char *str, size_t size)
+{
+       char *p = buf;
+       while (*p && *p == ' ')
+               p++;
+
+       while (size > 1) {
+               if (*p == ' ')
+                       break;
+               else if (*p < 0x20 || *p >= 0x7f)
+                       return -(p - buf);
+               *str = *p;
+               p++;
+               str ++;
+               size --;
+       }
+
+       *str = 0;
+
+       while (*p && *p == ' ')
+               p++;
+
+       p--;
+
+       return (p - buf);
+}
+
+
+struct emv_pk *emv_pk_parse_pk(char *buf)
+{
+       struct emv_pk *r = calloc(1, sizeof(*r));
+       ssize_t l;
+       char temp[10];
+
+       l = emv_pk_read_bin(buf, r->rid, 5, NULL);
+       if (l <= 0)
+               goto out;
+       buf += l;
+
+       l = emv_pk_read_bin(buf, &r->index, 1, NULL);
+       if (l <= 0)
+               goto out;
+       buf += l;
+
+       l = emv_pk_read_ymv(buf, &r->expire);
+       if (l <= 0)
+               goto out;
+       buf += l;
+
+       l = emv_pk_read_string(buf, temp, sizeof(temp));
+       if (l <= 0)
+               goto out;
+       buf += l;
+
+       if (!strcmp(temp, "rsa"))
+               r->pk_algo = PK_RSA;
+       else
+               goto out;
+
+       l = emv_pk_read_bin(buf, r->exp, sizeof(r->exp), &r->elen);
+       if (l <= 0)
+               goto out;
+       buf += l;
+
+       r->modulus = malloc(2048/8);
+       l = emv_pk_read_bin(buf, r->modulus, 2048/8, &r->mlen);
+       if (l <= 0)
+               goto out2;
+       buf += l;
+
+       l = emv_pk_read_string(buf, temp, sizeof(temp));
+       if (l <= 0)
+               goto out2;
+       buf += l;
+
+       if (!strcmp(temp, "sha1"))
+               r->hash_algo = HASH_SHA_1;
+       else
+               goto out2;
+
+       l = emv_pk_read_bin(buf, r->hash, 20, NULL);
+       if (l <= 0)
+               goto out2;
+
+       return r;
+
+out2:
+       free(r->modulus);
+out:
+       free(r);
+       return NULL;
+}
+
+static size_t emv_pk_write_bin(char *out, size_t outlen, const unsigned char *buf, size_t len)
+{
+       int i;
+       size_t pos = 0;
+
+       if (len == 0)
+               return 0;
+       if (outlen < len * 3)
+               return 0;
+
+       out[pos++] = TOHEX(buf[0] >> 4);
+       out[pos++] = TOHEX(buf[0] & 0xf);
+       for (i = 1; i < len; i++) {
+               out[pos++] = ':';
+               out[pos++] = TOHEX(buf[i] >> 4);
+               out[pos++] = TOHEX(buf[i] & 0xf);
+       }
+       out[pos++] = ' ';
+
+       return pos;
+}
+
+static size_t emv_pk_write_str(char *out, size_t outlen, const char *str)
+{
+       size_t len = strlen(str);
+
+       if (len == 0)
+               return 0;
+       if (outlen < len)
+               return 0;
+
+       memcpy(out, str, len);
+
+       return len;
+}
+
+char *emv_pk_dump_pk(const struct emv_pk *pk)
+{
+       size_t outsize = 1024; /* should be enough */
+       char *out = malloc(outsize); /* should be enough */
+       size_t outpos = 0;
+       size_t rc;
+
+       if (!out)
+               return NULL;
+
+       rc = emv_pk_write_bin(out + outpos, outsize - outpos, pk->rid, 5);
+       if (rc == 0)
+               goto err;
+       outpos += rc;
+
+       rc = emv_pk_write_bin(out + outpos, outsize - outpos, &pk->index, 1);
+       if (rc == 0)
+               goto err;
+       outpos += rc;
+
+       if (outpos + 7 > outsize)
+               goto err;
+       out[outpos++] = TOHEX((pk->expire >> 20) & 0xf);
+       out[outpos++] = TOHEX((pk->expire >> 16) & 0xf);
+       out[outpos++] = TOHEX((pk->expire >> 12) & 0xf);
+       out[outpos++] = TOHEX((pk->expire >> 8 ) & 0xf);
+       out[outpos++] = TOHEX((pk->expire >> 4 ) & 0xf);
+       out[outpos++] = TOHEX((pk->expire >> 0 ) & 0xf);
+       out[outpos++] = ' ';
+
+       if (pk->pk_algo == PK_RSA) {
+               rc = emv_pk_write_str(out + outpos, outsize - outpos, "rsa");
+               if (rc == 0)
+                       goto err;
+               outpos += rc;
+               out[outpos++] = ' ';
+       } else {
+               if (outpos + 4 > outsize)
+                       goto err;
+               out[outpos++] = '?';
+               out[outpos++] = '?';
+               out[outpos++] = TOHEX(pk->pk_algo >> 4);
+               out[outpos++] = TOHEX(pk->pk_algo & 0xf);
+       }
+
+       rc = emv_pk_write_bin(out + outpos, outsize - outpos, pk->exp, pk->elen);
+       if (rc == 0)
+               goto err;
+       outpos += rc;
+
+       rc = emv_pk_write_bin(out + outpos, outsize - outpos, pk->modulus, pk->mlen);
+       if (rc == 0)
+               goto err;
+       outpos += rc;
+
+       if (pk->hash_algo == HASH_SHA_1) {
+               rc = emv_pk_write_str(out + outpos, outsize - outpos, "sha1");
+               if (rc == 0)
+                       goto err;
+               outpos += rc;
+               out[outpos++] = ' ';
+       } else {
+               if (outpos + 4 > outsize)
+                       goto err;
+               out[outpos++] = '?';
+               out[outpos++] = '?';
+               out[outpos++] = TOHEX(pk->pk_algo >> 4);
+               out[outpos++] = TOHEX(pk->pk_algo & 0xf);
+       }
+
+
+       rc = emv_pk_write_bin(out + outpos, outsize - outpos, pk->hash, 20);
+       if (rc == 0)
+               goto err;
+       outpos += rc;
+
+       out[outpos-1] = '\0';
+
+       return out;
+
+err:
+       free(out);
+       return NULL;
+}
+
+bool emv_pk_verify(const struct emv_pk *pk)
+{
+       struct crypto_hash *ch = crypto_hash_open(pk->hash_algo);
+       if (!ch)
+               return false;
+
+       crypto_hash_write(ch, pk->rid, sizeof(pk->rid));
+       crypto_hash_write(ch, &pk->index, 1);
+       crypto_hash_write(ch, pk->modulus, pk->mlen);
+       crypto_hash_write(ch, pk->exp, pk->elen);
+
+       unsigned char *h = crypto_hash_read(ch);
+       if (!h) {
+               crypto_hash_close(ch);
+               return false;
+       }
+
+       size_t hsize = crypto_hash_get_size(ch);
+       bool r = hsize && !memcmp(h, pk->hash, hsize) ? true : false;
+
+       crypto_hash_close(ch);
+
+       return r;
+}
+
+struct emv_pk *emv_pk_new(size_t modlen, size_t explen)
+{
+       struct emv_pk *pk;
+
+       /* Not supported ATM */
+       if (explen > 3)
+               return NULL;
+
+       pk = calloc(1, sizeof(*pk));
+       if (!pk)
+               return NULL;
+
+       pk->mlen = modlen;
+       pk->elen = explen;
+
+       pk->modulus = calloc(modlen, 1);
+       if (!pk->modulus) {
+               free(pk);
+               pk = NULL;
+       }
+
+       return pk;
+}
+
+void emv_pk_free(struct emv_pk *pk)
+{
+       if (!pk)
+               return;
+
+       free(pk->modulus);
+       free(pk);
+}
+
+static struct emv_pk *emv_pk_get_ca_pk_from_file(const char *fname,
+               const unsigned char *rid,
+               unsigned char idx)
+{
+       if  (!fname)
+               return NULL;
+
+       FILE *f = fopen(fname, "r");
+       if (!f) {
+               perror("fopen");
+               return NULL;
+       }
+
+       while (!feof(f)) {
+               char buf[2048];
+               if (fgets(buf, sizeof(buf), f) == NULL)
+                       break;
+
+               struct emv_pk *pk = emv_pk_parse_pk(buf);
+               if (!pk)
+                       continue;
+               if (memcmp(pk->rid, rid, 5) || pk->index != idx) {
+                       emv_pk_free(pk);
+                       continue;
+               }
+
+               fclose(f);
+
+               return pk;
+       }
+
+       fclose(f);
+
+       return NULL;
+}
+
+char *emv_pk_get_ca_pk_file(const char *dirname, const unsigned char *rid, unsigned char idx)
+{
+       if (!dirname)
+               dirname = ".";//openemv_config_get_str("capk.dir", NULL);
+
+       if (!dirname)
+               return NULL;
+
+       char *filename;
+       int ret = asprintf(&filename, "%s/%02hhx%02hhx%02hhx%02hhx%02hhx_%02hhx.0",
+                       dirname,
+                       rid[0],
+                       rid[1],
+                       rid[2],
+                       rid[3],
+                       rid[4],
+                       idx);
+
+       if (ret <= 0)
+               return NULL;
+
+       return filename;
+}
+
+char *emv_pk_get_ca_pk_rid_file(const char *dirname, const unsigned char *rid)
+{
+       if (!dirname)
+               dirname = "."; //openemv_config_get_str("capk.dir", NULL);
+
+       if (!dirname)
+               return NULL;
+
+       char *filename;
+       int ret = asprintf(&filename, "%s/%02hhx%02hhx%02hhx%02hhx%02hhx.pks",
+                       dirname,
+                       rid[0],
+                       rid[1],
+                       rid[2],
+                       rid[3],
+                       rid[4]);
+
+       if (ret <= 0)
+               return NULL;
+
+       return filename;
+}
+
+struct emv_pk *emv_pk_get_ca_pk(const unsigned char *rid, unsigned char idx)
+{
+       struct emv_pk *pk = NULL;
+
+/*     if (!pk) {
+               char *fname = emv_pk_get_ca_pk_file(NULL, rid, idx);
+               if (fname) {
+                       pk = emv_pk_get_ca_pk_from_file(fname, rid, idx);
+                       free(fname);
+               }
+       }
+
+       if (!pk) {
+               char *fname = emv_pk_get_ca_pk_rid_file(NULL, rid);
+               if (fname) {
+                       pk = emv_pk_get_ca_pk_from_file(fname, rid, idx);
+                       free(fname);
+               }
+       }
+*/
+       if (!pk) {
+               const char *relfname = "emv/capk.txt"; 
+
+               char fname[strlen(get_my_executable_directory()) + strlen(relfname) + 1];
+               strcpy(fname, get_my_executable_directory());
+               strcat(fname, relfname);
+
+               pk = emv_pk_get_ca_pk_from_file(fname, rid, idx);
+       }
+       if (!pk)
+               return NULL;
+
+       printf("Verifying CA PK for %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx %zd bits...",
+                               pk->rid[0],
+                               pk->rid[1],
+                               pk->rid[2],
+                               pk->rid[3],
+                               pk->rid[4],
+                               pk->index,
+                               pk->mlen * 8);
+       if (emv_pk_verify(pk)) {
+               printf("OK\n");
+
+               return pk;
+       }
+
+       printf("Failed!\n");
+       emv_pk_free(pk);
+
+       return NULL;
+}
diff --git a/client/emv/emv_pk.h b/client/emv/emv_pk.h
new file mode 100644 (file)
index 0000000..e291a06
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * libopenemv - a library to work with EMV family of smart cards
+ * Copyright (C) 2015 Dmitry Eremin-Solenikov
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifndef EMV_PK_H
+#define EMV_PK_H
+
+#include <stdbool.h>
+#include <stddef.h>
+
+struct emv_pk {
+       unsigned char rid[5];
+       unsigned char index;
+       unsigned char serial[3];
+       unsigned char pan[10];
+       unsigned char hash_algo;
+       unsigned char pk_algo;
+       unsigned char hash[20];
+       unsigned char exp[3];
+       size_t elen;
+       size_t mlen;
+       unsigned char *modulus;
+       unsigned int expire;
+};
+
+#define EXPIRE(yy, mm, dd)     0x ## yy ## mm ## dd
+
+struct emv_pk *emv_pk_parse_pk(char *buf);
+struct emv_pk *emv_pk_new(size_t modlen, size_t explen);
+void emv_pk_free(struct emv_pk *pk);
+char *emv_pk_dump_pk(const struct emv_pk *pk);
+bool emv_pk_verify(const struct emv_pk *pk);
+
+char *emv_pk_get_ca_pk_file(const char *dirname, const unsigned char *rid, unsigned char idx);
+char *emv_pk_get_ca_pk_rid_file(const char *dirname, const unsigned char *rid);
+struct emv_pk *emv_pk_get_ca_pk(const unsigned char *rid, unsigned char idx);
+#endif
diff --git a/client/emv/emv_pki.c b/client/emv/emv_pki.c
new file mode 100644 (file)
index 0000000..7803060
--- /dev/null
@@ -0,0 +1,511 @@
+/*
+ * libopenemv - a library to work with EMV family of smart cards
+ * Copyright (C) 2015 Dmitry Eremin-Solenikov
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "emv_pki.h"
+#include "crypto.h"
+#include "dump.h"
+#include "util.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+static const unsigned char empty_tlv_value[] = {};
+static const struct tlv empty_tlv = {.tag = 0x0, .len = 0, .value = empty_tlv_value};
+
+static size_t emv_pki_hash_psn[256] = { 0, 0, 11, 2, 17, 2, };
+
+static unsigned char *emv_pki_decode_message(const struct emv_pk *enc_pk,
+               uint8_t msgtype,
+               size_t *len,
+               const struct tlv *cert_tlv,
+               ... /* A list of tlv pointers, end with NULL */
+               )
+{
+       struct crypto_pk *kcp;
+       unsigned char *data;
+       size_t data_len;
+       va_list vl;
+
+       if (!enc_pk)
+               return NULL;
+
+       if (!cert_tlv) {
+               printf("ERROR: Can't find certificate\n");
+               return NULL;
+       }
+
+       if (cert_tlv->len != enc_pk->mlen) {
+               printf("ERROR: Certificate length (%d) not equal key length (%d)\n", cert_tlv->len, enc_pk->mlen);
+               return NULL;
+       }
+       kcp = crypto_pk_open(enc_pk->pk_algo,
+                       enc_pk->modulus, enc_pk->mlen,
+                       enc_pk->exp, enc_pk->elen);
+       if (!kcp)
+               return NULL;
+
+       data = crypto_pk_encrypt(kcp, cert_tlv->value, cert_tlv->len, &data_len);
+       crypto_pk_close(kcp);
+
+/*     if (true){
+               printf("Recovered data:\n");
+               dump_buffer(data, data_len, stdout, 0);
+       }*/
+       
+       if (data[data_len-1] != 0xbc || data[0] != 0x6a || data[1] != msgtype) {
+               printf("ERROR: Certificate format\n");
+               free(data);
+               return NULL;
+       }
+
+       size_t hash_pos = emv_pki_hash_psn[msgtype];
+       if (hash_pos == 0 || hash_pos > data_len){
+               printf("ERROR: Cant get hash position in the certificate\n");
+               free(data);
+               return NULL;
+       }
+
+       struct crypto_hash *ch;
+       ch = crypto_hash_open(data[hash_pos]);
+       if (!ch) {
+               printf("ERROR: Cant do hash\n");
+               free(data);
+               return NULL;
+       }
+
+       size_t hash_len = crypto_hash_get_size(ch);
+       crypto_hash_write(ch, data + 1, data_len - 2 - hash_len);
+
+       va_start(vl, cert_tlv);
+       while (true) {
+               const struct tlv *add_tlv = va_arg(vl, const struct tlv *);
+               if (!add_tlv)
+                       break;
+
+               crypto_hash_write(ch, add_tlv->value, add_tlv->len);
+       }
+       va_end(vl);
+
+       if (memcmp(data + data_len - 1 - hash_len, crypto_hash_read(ch), hash_len)) {
+               printf("ERROR: Calculated wrong hash\n");
+               printf("decoded:    %s\n",sprint_hex(data + data_len - 1 - hash_len, hash_len));
+               printf("calculated: %s\n",sprint_hex(crypto_hash_read(ch), hash_len));
+               crypto_hash_close(ch);
+               free(data);
+               return NULL;
+       }
+
+       crypto_hash_close(ch);
+
+       *len = data_len - hash_len - 1;
+
+       return data;
+}
+
+static unsigned emv_cn_length(const struct tlv *tlv)
+{
+       int i;
+
+       for (i = 0; i < tlv->len; i++) {
+               unsigned char c = tlv->value[i];
+
+               if (c >> 4 == 0xf)
+                       return 2 * i;
+
+               if ((c & 0xf) == 0xf)
+                       return 2 * i + 1;
+       }
+
+       return 2 * tlv->len;
+}
+
+static unsigned char emv_cn_get(const struct tlv *tlv, unsigned pos)
+{
+       if (pos > tlv->len * 2)
+               return 0xf;
+
+       unsigned char c = tlv->value[pos / 2];
+
+       if (pos % 2)
+               return c & 0xf;
+       else
+               return c >> 4;
+}
+
+static struct emv_pk *emv_pki_decode_key_ex(const struct emv_pk *enc_pk,
+               unsigned char msgtype,
+               const struct tlv *pan_tlv,
+               const struct tlv *cert_tlv,
+               const struct tlv *exp_tlv,
+               const struct tlv *rem_tlv,
+               const struct tlv *add_tlv,
+               bool showData
+               )
+{
+       size_t pan_length;
+       unsigned char *data;
+       size_t data_len;
+       size_t pk_len;
+
+       if (!cert_tlv || !exp_tlv || !pan_tlv)
+               return NULL;
+
+       if (!rem_tlv)
+               rem_tlv = &empty_tlv;
+
+       if (msgtype == 2)
+               pan_length = 4;
+       else if (msgtype == 4)
+               pan_length = 10;
+       else {
+               printf("ERROR: Message type must be 2 or 4\n");
+               return NULL;
+       }
+
+       data = emv_pki_decode_message(enc_pk, msgtype, &data_len,
+                       cert_tlv,
+                       rem_tlv,
+                       exp_tlv,
+                       add_tlv,
+                       NULL);
+       if (!data || data_len < 11 + pan_length) {
+               printf("ERROR: Can't decode message\n");
+               return NULL;
+       }
+
+       if (showData){ 
+               printf("Recovered data:\n");
+               dump_buffer(data, data_len, stdout, 0);
+       }
+
+       /* Perform the rest of checks here */
+
+       struct tlv pan2_tlv = {
+               .tag = 0x5a,
+               .len = pan_length,
+               .value = &data[2],
+       };
+       unsigned pan_len = emv_cn_length(pan_tlv);
+       unsigned pan2_len = emv_cn_length(&pan2_tlv);
+
+       if (((msgtype == 2) && (pan2_len < 4 || pan2_len > pan_len)) ||
+           ((msgtype == 4) && (pan2_len != pan_len))) {
+               printf("ERROR: Invalid PAN lengths\n");
+               free(data);
+
+               return NULL;
+       }
+
+       unsigned i;
+       for (i = 0; i < pan2_len; i++)
+               if (emv_cn_get(pan_tlv, i) != emv_cn_get(&pan2_tlv, i)) {
+                       printf("ERROR: PAN data mismatch\n");
+                       printf("tlv  pan=%s\n", sprint_hex(pan_tlv->value, pan_tlv->len));
+                       printf("cert pan=%s\n", sprint_hex(pan2_tlv.value, pan2_tlv.len));
+                       free(data);
+
+                       return NULL;
+               }
+
+       pk_len = data[9 + pan_length];
+       if (pk_len > data_len - 11 - pan_length + rem_tlv->len) {
+               printf("ERROR: Invalid pk length\n");
+               free(data);
+               return NULL;
+       }
+
+       if (exp_tlv->len != data[10 + pan_length]) {
+               free(data);
+               return NULL;
+       }
+
+       struct emv_pk *pk = emv_pk_new(pk_len, exp_tlv->len);
+
+       memcpy(pk->rid, enc_pk->rid, 5);
+       pk->index = enc_pk->index;
+
+       pk->hash_algo = data[7 + pan_length];
+       pk->pk_algo = data[8 + pan_length];
+       pk->expire = (data[3 + pan_length] << 16) | (data[2 + pan_length] << 8) | 0x31;
+       memcpy(pk->serial, data + 4 + pan_length, 3);
+       memcpy(pk->pan, data + 2, pan_length);
+       memset(pk->pan + pan_length, 0xff, 10 - pan_length);
+
+       memcpy(pk->modulus, data + 11 + pan_length,
+                       pk_len < data_len - (11 + pan_length) ?
+                       pk_len :
+                       data_len - (11 + pan_length));
+       memcpy(pk->modulus + data_len - (11 + pan_length), rem_tlv->value, rem_tlv->len);
+       memcpy(pk->exp, exp_tlv->value, exp_tlv->len);
+
+       free(data);
+
+       return pk;
+}
+
+static struct emv_pk *emv_pki_decode_key(const struct emv_pk *enc_pk,
+               unsigned char msgtype,
+               const struct tlv *pan_tlv,
+               const struct tlv *cert_tlv,
+               const struct tlv *exp_tlv,
+               const struct tlv *rem_tlv,
+               const struct tlv *add_tlv
+               ) {
+       return emv_pki_decode_key_ex(enc_pk, msgtype, pan_tlv, cert_tlv, exp_tlv, rem_tlv, add_tlv, false);
+}
+
+struct emv_pk *emv_pki_recover_issuer_cert(const struct emv_pk *pk, struct tlvdb *db)
+{
+       return emv_pki_decode_key(pk, 2,
+                       tlvdb_get(db, 0x5a, NULL),
+                       tlvdb_get(db, 0x90, NULL),
+                       tlvdb_get(db, 0x9f32, NULL),
+                       tlvdb_get(db, 0x92, NULL),
+                       NULL);
+}
+
+struct emv_pk *emv_pki_recover_icc_cert(const struct emv_pk *pk, struct tlvdb *db, const struct tlv *sda_tlv)
+{
+       return emv_pki_decode_key(pk, 4,
+                       tlvdb_get(db, 0x5a, NULL),
+                       tlvdb_get(db, 0x9f46, NULL),
+                       tlvdb_get(db, 0x9f47, NULL),
+                       tlvdb_get(db, 0x9f48, NULL),
+                       sda_tlv);
+}
+
+struct emv_pk *emv_pki_recover_icc_pe_cert(const struct emv_pk *pk, struct tlvdb *db)
+{
+       return emv_pki_decode_key(pk, 4,
+                       tlvdb_get(db, 0x5a, NULL),
+                       tlvdb_get(db, 0x9f2d, NULL),
+                       tlvdb_get(db, 0x9f2e, NULL),
+                       tlvdb_get(db, 0x9f2f, NULL),
+                       NULL);
+}
+
+struct tlvdb *emv_pki_recover_dac_ex(const struct emv_pk *enc_pk, const struct tlvdb *db, const struct tlv *sda_tlv, bool showData)
+{
+       size_t data_len;
+       unsigned char *data = emv_pki_decode_message(enc_pk, 3, &data_len,
+                       tlvdb_get(db, 0x93, NULL),
+                       sda_tlv,
+                       NULL);
+
+       if (!data || data_len < 5)
+               return NULL;
+
+       if (showData){
+               printf("Recovered data:\n");
+               dump_buffer(data, data_len, stdout, 0);
+       }
+
+       struct tlvdb *dac_db = tlvdb_fixed(0x9f45, 2, data+3);
+
+       free(data);
+
+       return dac_db;
+}
+struct tlvdb *emv_pki_recover_dac(const struct emv_pk *enc_pk, const struct tlvdb *db, const struct tlv *sda_tlv) {
+       return emv_pki_recover_dac_ex(enc_pk, db, sda_tlv, false);
+}
+
+struct tlvdb *emv_pki_recover_idn(const struct emv_pk *enc_pk, const struct tlvdb *db, const struct tlv *dyn_tlv) {
+       return emv_pki_recover_idn_ex(enc_pk, db, dyn_tlv, false);
+}
+
+struct tlvdb *emv_pki_recover_idn_ex(const struct emv_pk *enc_pk, const struct tlvdb *db, const struct tlv *dyn_tlv, bool showData)
+{
+       size_t data_len;
+       unsigned char *data = emv_pki_decode_message(enc_pk, 5, &data_len,
+                       tlvdb_get(db, 0x9f4b, NULL),
+                       dyn_tlv,
+                       NULL);
+
+       if (!data || data_len < 3)
+               return NULL;
+
+       if (data[3] < 2 || data[3] > data_len - 3) {
+               free(data);
+               return NULL;
+       }
+
+       if (showData){
+               printf("Recovered data:\n");
+               dump_buffer(data, data_len, stdout, 0);
+       }
+
+       size_t idn_len = data[4];
+       if (idn_len > data[3] - 1) {
+               free(data);
+               return NULL;
+       }
+
+       // 9f4c ICC Dynamic Number
+       struct tlvdb *idn_db = tlvdb_fixed(0x9f4c, idn_len, data + 5);
+       
+       free(data);
+
+       return idn_db;
+}
+
+struct tlvdb *emv_pki_recover_atc_ex(const struct emv_pk *enc_pk, const struct tlvdb *db, bool showData)
+{
+       size_t data_len;
+       unsigned char *data = emv_pki_decode_message(enc_pk, 5, &data_len,
+                       tlvdb_get(db, 0x9f4b, NULL),
+                       tlvdb_get(db, 0x9f37, NULL),
+                       tlvdb_get(db, 0x9f02, NULL),
+                       tlvdb_get(db, 0x5f2a, NULL),
+                       tlvdb_get(db, 0x9f69, NULL),
+                       NULL);
+
+       if (!data || data_len < 3)
+               return NULL;
+
+       if (data[3] < 2 || data[3] > data_len - 3) {
+               free(data);
+               return NULL;
+       }
+
+       if (showData){
+               printf("Recovered data:\n");
+               dump_buffer(data, data_len, stdout, 0);
+       }
+
+       size_t idn_len = data[4];
+       if (idn_len > data[3] - 1) {
+               free(data);
+               return NULL;
+       }
+
+       // 9f36 Application Transaction Counter (ATC)
+       struct tlvdb *atc_db = tlvdb_fixed(0x9f36, idn_len, data + 5);
+       
+       free(data);
+
+       return atc_db;
+}
+
+static bool tlv_hash(void *data, const struct tlv *tlv, int level, bool is_leaf)
+{
+       struct crypto_hash *ch = data;
+       size_t tag_len;
+       unsigned char *tag;
+
+       if (tlv_is_constructed(tlv))
+               return true;
+
+       if (tlv->tag == 0x9f4b)
+               return true;
+
+       tag = tlv_encode(tlv, &tag_len);
+       crypto_hash_write(ch, tag, tag_len);
+       free(tag);
+
+       return true;
+}
+
+struct tlvdb *emv_pki_perform_cda(const struct emv_pk *enc_pk, const struct tlvdb *db,
+               const struct tlvdb *this_db,
+               const struct tlv *pdol_data_tlv,
+               const struct tlv *crm1_tlv,
+               const struct tlv *crm2_tlv)
+{
+       return emv_pki_perform_cda_ex(enc_pk, db, this_db, pdol_data_tlv, crm1_tlv, crm2_tlv, false);
+}
+struct tlvdb *emv_pki_perform_cda_ex(const struct emv_pk *enc_pk, const struct tlvdb *db,
+               const struct tlvdb *this_db,     // AC TLV result
+               const struct tlv *pdol_data_tlv, // PDOL
+               const struct tlv *crm1_tlv,      // CDOL1
+               const struct tlv *crm2_tlv,      // CDOL2
+               bool showData)
+{
+       const struct tlv *un_tlv = tlvdb_get(db, 0x9f37, NULL);
+       const struct tlv *cid_tlv = tlvdb_get(this_db, 0x9f27, NULL);
+
+       if (!un_tlv || !cid_tlv)
+               return NULL;
+
+       size_t data_len = 0;
+       unsigned char *data = emv_pki_decode_message(enc_pk, 5, &data_len,
+                       tlvdb_get(this_db, 0x9f4b, NULL),
+                       un_tlv,
+                       NULL);
+       if (!data || data_len < 3) {
+               printf("ERROR: can't decode message. len %d\n", data_len);
+               return NULL;
+       }
+
+       if (showData){
+               printf("Recovered data:\n");
+               dump_buffer(data, data_len, stdout, 0);
+       }
+
+       if (data[3] < 30 || data[3] > data_len - 4) {
+               printf("ERROR: Invalid data length\n");
+               free(data);
+               return NULL;
+       }
+
+       if (!cid_tlv || cid_tlv->len != 1 || cid_tlv->value[0] != data[5 + data[4]]) {
+               printf("ERROR: CID mismatch\n");
+               free(data);
+               return NULL;
+       }
+
+       struct crypto_hash *ch;
+       ch = crypto_hash_open(enc_pk->hash_algo);
+       if (!ch) {
+               printf("ERROR: can't create hash\n");
+               free(data);
+               return NULL;
+       }
+
+       if (pdol_data_tlv)
+               crypto_hash_write(ch, pdol_data_tlv->value, pdol_data_tlv->len);
+       if (crm1_tlv)
+               crypto_hash_write(ch, crm1_tlv->value, crm1_tlv->len);
+       if (crm2_tlv)
+               crypto_hash_write(ch, crm2_tlv->value, crm2_tlv->len);
+
+       tlvdb_visit(this_db, tlv_hash, ch, 0);
+
+       if (memcmp(data + 5 + data[4] + 1 + 8, crypto_hash_read(ch), 20)) {
+               printf("ERROR: calculated hash error\n");
+               crypto_hash_close(ch);
+               free(data);
+               return NULL;
+       }
+       crypto_hash_close(ch);
+
+       size_t idn_len = data[4];
+       if (idn_len > data[3] - 1) {
+               printf("ERROR: Invalid IDN length\n");
+               free(data);
+               return NULL;
+       }
+
+       struct tlvdb *idn_db = tlvdb_fixed(0x9f4c, idn_len, data + 5);
+       free(data);
+
+       return idn_db;
+}
diff --git a/client/emv/emv_pki.h b/client/emv/emv_pki.h
new file mode 100644 (file)
index 0000000..e37e3c7
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * libopenemv - a library to work with EMV family of smart cards
+ * Copyright (C) 2015 Dmitry Eremin-Solenikov
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifndef EMV_PKI_H
+#define EMV_PKI_H
+
+#include "emv_pk.h"
+#include "tlv.h"
+
+#include <stddef.h>
+
+struct emv_pk *emv_pki_recover_issuer_cert(const struct emv_pk *pk, struct tlvdb *db);
+struct emv_pk *emv_pki_recover_icc_cert(const struct emv_pk *pk, struct tlvdb *db, const struct tlv *sda_tlv);
+struct emv_pk *emv_pki_recover_icc_pe_cert(const struct emv_pk *pk, struct tlvdb *db);
+
+struct tlvdb *emv_pki_recover_dac(const struct emv_pk *pk, const struct tlvdb *db, const struct tlv *sda_tlv);
+struct tlvdb *emv_pki_recover_dac_ex(const struct emv_pk *pk, const struct tlvdb *db, const struct tlv *sda_tlv, bool showData);
+struct tlvdb *emv_pki_recover_idn(const struct emv_pk *pk, const struct tlvdb *db, const struct tlv *dyn_tlv);
+struct tlvdb *emv_pki_recover_idn_ex(const struct emv_pk *pk, const struct tlvdb *db, const struct tlv *dyn_tlv, bool showData);
+struct tlvdb *emv_pki_recover_atc_ex(const struct emv_pk *enc_pk, const struct tlvdb *db, bool showData);
+struct tlvdb *emv_pki_perform_cda(const struct emv_pk *enc_pk, const struct tlvdb *db,
+               const struct tlvdb *this_db,
+               const struct tlv *pdol_data_tlv,
+               const struct tlv *crm1_tlv,
+               const struct tlv *crm2_tlv);
+struct tlvdb *emv_pki_perform_cda_ex(const struct emv_pk *enc_pk, const struct tlvdb *db,
+               const struct tlvdb *this_db,
+               const struct tlv *pdol_data_tlv,
+               const struct tlv *crm1_tlv,
+               const struct tlv *crm2_tlv,
+               bool showData);
+
+#endif
diff --git a/client/emv/emv_pki_priv.c b/client/emv/emv_pki_priv.c
new file mode 100644 (file)
index 0000000..d67a870
--- /dev/null
@@ -0,0 +1,283 @@
+/*
+ * libopenemv - a library to work with EMV family of smart cards
+ * Copyright (C) 2015 Dmitry Eremin-Solenikov
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "emv_pki_priv.h"
+#include "crypto.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+struct emv_pk *emv_pki_make_ca(const struct crypto_pk *cp,
+               const unsigned char *rid, unsigned char index,
+               unsigned int expire, enum crypto_algo_hash hash_algo)
+{
+       size_t modlen, explen;
+       unsigned char *mod, *exp;
+
+       if (!rid)
+               return NULL;
+
+       mod = crypto_pk_get_parameter(cp, 0, &modlen);
+       exp = crypto_pk_get_parameter(cp, 1, &explen);
+
+       if (!mod || !modlen || !exp || !explen) {
+               free(mod);
+               free(exp);
+
+               return NULL;
+       }
+
+       struct emv_pk *pk = emv_pk_new(modlen, explen);
+       memcpy(pk->rid, rid, 5);
+       pk->index = index;
+       pk->expire = expire;
+       pk->pk_algo = crypto_pk_get_algo(cp);
+       pk->hash_algo = hash_algo;
+       memcpy(pk->modulus, mod, modlen);
+       memcpy(pk->exp, exp, explen);
+
+       free(mod);
+       free(exp);
+
+       struct crypto_hash *ch = crypto_hash_open(pk->hash_algo);
+       if (!ch) {
+               emv_pk_free(pk);
+               return false;
+       }
+
+       crypto_hash_write(ch, pk->rid, sizeof(pk->rid));
+       crypto_hash_write(ch, &pk->index, 1);
+       crypto_hash_write(ch, pk->modulus, pk->mlen);
+       crypto_hash_write(ch, pk->exp, pk->elen);
+
+       unsigned char *h = crypto_hash_read(ch);
+       if (!h) {
+               crypto_hash_close(ch);
+               emv_pk_free(pk);
+
+               return NULL;
+       }
+
+       memcpy(pk->hash, h, crypto_hash_get_size(ch));
+       crypto_hash_close(ch);
+
+       return pk;
+}
+
+static struct tlvdb *emv_pki_sign_message(const struct crypto_pk *cp,
+               tlv_tag_t cert_tag, tlv_tag_t rem_tag,
+               const unsigned char *msg, size_t msg_len,
+               ... /* A list of tlv pointers, end with NULL */
+               )
+{
+       size_t tmp_len = (crypto_pk_get_nbits(cp) + 7) / 8;
+       unsigned char *tmp = malloc(tmp_len);
+       if (!tmp)
+               return NULL;
+
+       // XXX
+       struct crypto_hash *ch = crypto_hash_open(HASH_SHA_1);
+       if (!ch) {
+               free(tmp);
+
+               return NULL;
+       }
+
+       tmp[0] = 0x6a;
+       tmp[tmp_len - 1] = 0xbc;
+
+       const unsigned char *rem;
+       size_t rem_len;
+       size_t hash_len = crypto_hash_get_size(ch);
+       size_t part_len = tmp_len - 2 - hash_len;
+       if (part_len < msg_len) {
+               memcpy(tmp + 1, msg, part_len);
+               rem = msg + part_len;
+               rem_len = msg_len - part_len;
+       } else {
+               memcpy(tmp + 1, msg, msg_len);
+               memset(tmp + 1 + msg_len, 0xbb, part_len - msg_len);
+               rem = NULL;
+               rem_len = 0;
+       }
+       crypto_hash_write(ch, tmp + 1, part_len);
+       crypto_hash_write(ch, rem, rem_len);
+
+       va_list vl;
+       va_start(vl, msg_len);
+       while (true) {
+               const struct tlv *add_tlv = va_arg(vl, const struct tlv *);
+               if (!add_tlv)
+                       break;
+
+               crypto_hash_write(ch, add_tlv->value, add_tlv->len);
+       }
+       va_end(vl);
+
+       unsigned char *h = crypto_hash_read(ch);
+       if (!h) {
+               crypto_hash_close(ch);
+               free(tmp);
+
+               return NULL;
+       }
+
+       memcpy(tmp + 1 + part_len, h, hash_len);
+       crypto_hash_close(ch);
+
+       size_t cert_len;
+       unsigned char *cert = crypto_pk_decrypt(cp, tmp, tmp_len, &cert_len);
+       free(tmp);
+
+       if (!cert)
+               return NULL;
+
+       struct tlvdb *db = tlvdb_fixed(cert_tag, cert_len, cert);
+       free(cert);
+       if (!db)
+               return NULL;
+
+       if (rem) {
+               struct tlvdb *rdb = tlvdb_fixed(rem_tag, rem_len, rem);
+               if (!rdb) {
+                       tlvdb_free(db);
+
+                       return NULL;
+               }
+               tlvdb_add(db, rdb);
+       }
+
+       return db;
+}
+
+static struct tlvdb *emv_pki_sign_key(const struct crypto_pk *cp,
+               struct emv_pk *ipk,
+               unsigned char msgtype,
+               size_t pan_len,
+               tlv_tag_t cert_tag,
+               tlv_tag_t exp_tag,
+               tlv_tag_t rem_tag,
+               const struct tlv *add_tlv
+               )
+{
+       unsigned pos = 0;
+       unsigned char *msg = malloc(1 + pan_len + 2 + 3 + 1 + 1 + 1 + 1 + ipk->mlen);
+
+       if (!msg)
+               return NULL;
+
+       msg[pos++] = msgtype;
+       memcpy(msg + pos, ipk->pan, pan_len); pos += pan_len;
+       msg[pos++] = (ipk->expire >> 8) & 0xff;
+       msg[pos++] = (ipk->expire >> 16) & 0xff;
+       memcpy(msg + pos, ipk->serial, 3); pos += 3;
+       msg[pos++] = ipk->hash_algo;
+       msg[pos++] = ipk->pk_algo;
+       msg[pos++] = ipk->mlen;
+       msg[pos++] = ipk->elen;
+       memcpy(msg + pos, ipk->modulus, ipk->mlen);
+       pos += ipk->mlen;
+
+       struct tlvdb *exp_db = tlvdb_fixed(exp_tag, ipk->elen, ipk->exp);
+       if (!exp_db) {
+               free(msg);
+
+               return NULL;
+       }
+
+       struct tlvdb *db = emv_pki_sign_message(cp,
+                       cert_tag, rem_tag,
+                       msg, pos,
+                       tlvdb_get(exp_db, exp_tag, NULL),
+                       add_tlv,
+                       NULL);
+       free(msg);
+       if (!db)
+               return NULL;
+
+       tlvdb_add(db, exp_db);
+
+       return db;
+}
+
+struct tlvdb *emv_pki_sign_issuer_cert(const struct crypto_pk *cp, struct emv_pk *issuer_pk)
+{
+       return emv_pki_sign_key(cp, issuer_pk, 2, 4, 0x90, 0x9f32, 0x92, NULL);
+}
+
+struct tlvdb *emv_pki_sign_icc_cert(const struct crypto_pk *cp, struct emv_pk *icc_pk, const struct tlv *sda_tlv)
+{
+       return emv_pki_sign_key(cp, icc_pk, 4, 10, 0x9f46, 0x9f47, 0x9f48, sda_tlv);
+}
+
+struct tlvdb *emv_pki_sign_icc_pe_cert(const struct crypto_pk *cp, struct emv_pk *icc_pe_pk)
+{
+       return emv_pki_sign_key(cp, icc_pe_pk, 4, 10, 0x9f2d, 0x9f2e, 0x9f2f, NULL);
+}
+
+struct tlvdb *emv_pki_sign_dac(const struct crypto_pk *cp, const struct tlv *dac_tlv, const struct tlv *sda_tlv)
+{
+       unsigned pos = 0;
+       unsigned char *msg = malloc(1+1+dac_tlv->len);
+
+       if (!msg)
+               return NULL;
+
+       msg[pos++] = 3;
+       msg[pos++] = HASH_SHA_1;
+       memcpy(msg+pos, dac_tlv->value, dac_tlv->len);
+       pos += dac_tlv->len;
+
+       struct tlvdb *db = emv_pki_sign_message(cp,
+                       0x93, 0,
+                       msg, pos,
+                       sda_tlv,
+                       NULL);
+
+       free(msg);
+
+       return db;
+}
+
+struct tlvdb *emv_pki_sign_idn(const struct crypto_pk *cp, const struct tlv *idn_tlv, const struct tlv *dyn_tlv)
+{
+       unsigned pos = 0;
+       unsigned char *msg = malloc(1+1+1+1+idn_tlv->len);
+
+       if (!msg)
+               return NULL;
+
+       msg[pos++] = 5;
+       msg[pos++] = HASH_SHA_1;
+       msg[pos++] = idn_tlv->len + 1;
+       msg[pos++] = idn_tlv->len;
+       memcpy(msg+pos, idn_tlv->value, idn_tlv->len);
+       pos += idn_tlv->len;
+
+       struct tlvdb *db = emv_pki_sign_message(cp,
+                       0x9f4b, 0,
+                       msg, pos,
+                       dyn_tlv,
+                       NULL);
+
+       free(msg);
+
+       return db;
+}
diff --git a/client/emv/emv_pki_priv.h b/client/emv/emv_pki_priv.h
new file mode 100644 (file)
index 0000000..4f1639d
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * libopenemv - a library to work with EMV family of smart cards
+ * Copyright (C) 2015 Dmitry Eremin-Solenikov
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifndef EMV_PKI_PRIV_H
+#define EMV_PKI_PRIV_H
+
+#include "crypto.h"
+#include "emv_pk.h"
+#include "tlv.h"
+
+#include <stddef.h>
+
+struct emv_pk *emv_pki_make_ca(const struct crypto_pk *cp,
+               const unsigned char *rid, unsigned char index,
+               unsigned int expire, enum crypto_algo_hash hash_algo);
+struct tlvdb *emv_pki_sign_issuer_cert(const struct crypto_pk *cp, struct emv_pk *issuer_pk);
+struct tlvdb *emv_pki_sign_icc_cert(const struct crypto_pk *cp, struct emv_pk *icc_pk, const struct tlv *sda_tlv);
+struct tlvdb *emv_pki_sign_icc_pe_cert(const struct crypto_pk *cp, struct emv_pk *icc_pe_pk);
+
+struct tlvdb *emv_pki_sign_dac(const struct crypto_pk *cp, const struct tlv *dac_tlv, const struct tlv *sda_tlv);
+struct tlvdb *emv_pki_sign_idn(const struct crypto_pk *cp, const struct tlv *idn_tlv, const struct tlv *dyn_tlv);
+
+#endif
index a7c11c3e768d3d98a35d23f04063882a3f8400b4..cdd57cb519486a7fba431794dc449e9b9a298e28 100644 (file)
@@ -21,6 +21,7 @@
 #include "emv_tags.h"
 
 #include <stdlib.h>
+#include <string.h>
 
 #define PRINT_INDENT(level)    {for (int i = 0; i < (level); i++) fprintf(f, "\t");}
 
@@ -33,6 +34,8 @@ enum emv_tag_t {
        EMV_TAG_STRING,
        EMV_TAG_NUMERIC,
        EMV_TAG_YYMMDD,
+       EMV_TAG_CVR,
+       EMV_TAG_CID,
 };
 
 struct emv_tag {
@@ -57,7 +60,7 @@ static const struct emv_tag_bit EMV_AIP[] = {
        { EMV_BIT(1, 4), "Terminal risk management is to be performed" },
        { EMV_BIT(1, 3), "Issuer authentication is supported" },
        { EMV_BIT(1, 2), "Reserved for use by the EMV Contactless Specifications" },
-       { EMV_BIT(1, 1), "CDA supported" },
+       { EMV_BIT(1, 1), "CDA supported (Combined Dynamic Data Authentication / Application Cryptogram Generation)" },
        { EMV_BIT(2, 8), "MSD is supported (Magnetic Stripe Data)" },
        { EMV_BIT(2, 7), "Reserved for use by the EMV Contactless Specifications" },
        { EMV_BIT(2, 6), "Reserved for use by the EMV Contactless Specifications" },
@@ -144,12 +147,39 @@ static const struct emv_tag_bit EMV_TTQ[] = {
        EMV_BIT_FINISH,
 };
 
+static const struct emv_tag_bit EMV_CVR[] = {
+       // mask 0F 0F F0 0F
+       { EMV_BIT(1, 4), "CDA Performed" },
+       { EMV_BIT(1, 3), "Offline DDA Performed" },
+       { EMV_BIT(1, 2), "Issuer Authentication Not Performed" },
+       { EMV_BIT(1, 1), "Issuer Authentication performed and Failed" },
+       { EMV_BIT(2, 4), "Offline PIN Verification Performed" },
+       { EMV_BIT(2, 3), "Offline PIN Verification Performed and PIN Not Successfully Verified" },
+       { EMV_BIT(2, 2), "PIN Try Limit Exceeded" },
+       { EMV_BIT(2, 1), "Last Online Transaction Not Completed" },
+       { EMV_BIT(3, 8), "Lower Offline Transaction Count Limit Exceeded" },
+       { EMV_BIT(3, 7), "Upper Offline Transaction Count Limit Exceeded" },
+       { EMV_BIT(3, 6), "Lower Cumulative Offline Amount Limit Exceeded" },
+       { EMV_BIT(3, 5), "Upper Cumulative Offline Amount Limit Exceeded" },
+       { EMV_BIT(4, 4), "Issuer script processing failed on last transaction" },
+       { EMV_BIT(4, 3), "Offline data authentication failed on previous transaction and transaction declined offline" },
+       { EMV_BIT(4, 2), "Go Online on Next Transaction Was Set" },
+       { EMV_BIT(4, 1), "Unable to go Online" },
+       EMV_BIT_FINISH,
+};
+
 // All Data Elements by Tags used in TLV structure (according to the EMV 4.2 Standard )
 // https://www.eftlab.co.uk/index.php/site-map/knowledge-base/145-emv-nfc-tags
 // http://dexterous-programmer.blogspot.in/2012/05/emv-tags.html
 static const struct emv_tag emv_tags[] = {
+       // internal
        { 0x00  , "Unknown ???" },
        { 0x01  , "", EMV_TAG_STRING }, // string for headers
+       { 0x02  , "Raw data", }, // data
+       { 0x20  , "Cardholder Verification Results (CVR)", EMV_TAG_CVR }, // not standard!
+       { 0x21  , "Input list for Offline Data Authentication" }, // not standard! data for "Offline Data Authentication" come from "read records" command. (EMV book3 10.3)
+
+       // EMV
        { 0x41  , "Country code and national data" },
        { 0x42  , "Issuer Identification Number (IIN)" },
        { 0x4f  , "Application Dedicated File (ADF) Name" },
@@ -193,6 +223,7 @@ static const struct emv_tag emv_tags[] = {
        { 0x9f06, "Application Identifier (AID), Terminal. ISO 7816-5" },
        { 0x9f07, "Application Usage Control", EMV_TAG_BITMASK, &EMV_AUC },
        { 0x9f08, "Application Version Number" },
+       { 0x9f0a, "Application Selection Registered Proprietary Data" }, // https://blog.ul-ts.com/posts/electronic-card-identifier-one-more-step-for-mif-compliance/
        { 0x9f0d, "Issuer Action Code - Default", EMV_TAG_BITMASK, &EMV_TVR },
        { 0x9f0e, "Issuer Action Code - Denial", EMV_TAG_BITMASK, &EMV_TVR },
        { 0x9f0f, "Issuer Action Code - Online", EMV_TAG_BITMASK, &EMV_TVR },
@@ -205,7 +236,7 @@ static const struct emv_tag emv_tags[] = {
        { 0x9f1f, "Track 1 Discretionary Data", EMV_TAG_STRING },
        { 0x9f21, "Transaction Time" },
        { 0x9f26, "Application Cryptogram" },
-       { 0x9f27, "Cryptogram Information Data" },
+       { 0x9f27, "Cryptogram Information Data", EMV_TAG_CID },
        { 0x9f2a, "Kernel Identifier" },
        { 0x9f2d, "ICC PIN Encipherment Public Key Certificate" },
        { 0x9f2e, "ICC PIN Encipherment Public Key Exponent" },
@@ -228,18 +259,22 @@ static const struct emv_tag emv_tags[] = {
        { 0x9f4c, "ICC Dynamic Number" },
        { 0x9f4d, "Log Entry" },
        { 0x9f4f, "Log Format", EMV_TAG_DOL },
+       { 0x9f60, "CVC3 (Track1)" },
+       { 0x9f61, "CVC3 (Track2)" },
        { 0x9f62, "PCVC3(Track1)" },
        { 0x9f63, "PUNATC(Track1)" },
        { 0x9f64, "NATC(Track1)" },
        { 0x9f65, "PCVC3(Track2)" },
        { 0x9f66, "PUNATC(Track2) / Terminal Transaction Qualifiers (TTQ)", EMV_TAG_BITMASK, &EMV_TTQ },
        { 0x9f67, "NATC(Track2) / MSD Offset" },
+       { 0x9f68, "Cardholder verification method list (PayPass)" },
        { 0x9f69, "Card Authentication Related Data" },
        { 0x9f6a, "Unpredictable Number", EMV_TAG_NUMERIC },
        { 0x9f6b, "Track 2 Data" },
        { 0x9f6c, "Card Transaction Qualifiers (CTQ)", EMV_TAG_BITMASK, &EMV_CTQ },
        { 0xa5  , "File Control Information (FCI) Proprietary Template" },
        { 0xbf0c, "File Control Information (FCI) Issuer Discretionary Data" },
+       { 0xdf20, "Issuer Proprietary Bitmap (IPB)" },
 };
 
 static int emv_sort_tag(tlv_tag_t tag)
@@ -375,6 +410,116 @@ static uint32_t emv_get_binary(const unsigned char *S)
        return (S[0] << 24) | (S[1] << 16) | (S[2] << 8) | (S[3] << 0);
 }
 
+// https://github.com/binaryfoo/emv-bertlv/blob/master/src/main/resources/fields/visa-cvr.txt
+static void emv_tag_dump_cvr(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level) {
+       if (!tlv || tlv->len < 1) {
+               PRINT_INDENT(level);
+               fprintf(f, "\tINVALID!\n");
+               return;
+       }
+       
+       if (tlv->len != tlv->value[0] + 1) {
+               PRINT_INDENT(level);
+               fprintf(f, "\tINVALID length!\n");
+               return;
+       }
+       
+       if (tlv->len >= 2) {
+               // AC1
+               PRINT_INDENT(level);
+               if ((tlv->value[1] & 0xC0) == 0x00)     fprintf(f, "\tAC1: AAC (Transaction declined)\n");
+               if ((tlv->value[1] & 0xC0) == 0x40)     fprintf(f, "\tAC1: TC (Transaction approved)\n");
+               if ((tlv->value[1] & 0xC0) == 0x80)     fprintf(f, "\tAC1: ARQC (Online authorisation requested)\n");
+               if ((tlv->value[1] & 0xC0) == 0xC0)     fprintf(f, "\tAC1: RFU\n");
+               // AC2
+               PRINT_INDENT(level);
+               if ((tlv->value[1] & 0x30) == 0x00)     fprintf(f, "\tAC2: AAC (Transaction declined)\n");
+               if ((tlv->value[1] & 0x30) == 0x10)     fprintf(f, "\tAC2: TC (Transaction approved)\n");
+               if ((tlv->value[1] & 0x30) == 0x20)     fprintf(f, "\tAC2: not requested (ARQC)\n");
+               if ((tlv->value[1] & 0x30) == 0x30)     fprintf(f, "\tAC2: RFU\n");
+       }
+       if (tlv->len >= 3 && (tlv->value[2] >> 4)) {
+               PRINT_INDENT(level);
+               fprintf(f, "\tPIN try: %x\n", tlv->value[2] >> 4);
+       }
+       if (tlv->len >= 4 && (tlv->value[3] & 0x0F)) {
+               PRINT_INDENT(level);
+               fprintf(f, "\tIssuer discretionary bits: %x\n", tlv->value[3] & 0x0F);
+       }
+       if (tlv->len >= 5 && (tlv->value[4] >> 4)) {
+               PRINT_INDENT(level);
+               fprintf(f, "\tSuccessfully processed issuer script commands: %x\n", tlv->value[4] >> 4);
+       }
+       
+       // mask 0F 0F F0 0F
+       uint8_t data[20] = {0};
+       memcpy(data, &tlv->value[1], tlv->len - 1);
+       data[0] &= 0x0F;
+       data[1] &= 0x0F;
+       data[2] &= 0xF0;
+       data[3] &= 0x0F;
+       const struct tlv bit_tlv = {
+               .tag = tlv->tag,
+               .len = tlv->len - 1,
+               .value = data,
+       };
+       const struct emv_tag bit_tag = {
+               .tag = tag->tag,
+               .name = tag->name,
+               .type = EMV_TAG_BITMASK,
+               .data = EMV_CVR,
+       };
+       
+       if (data[0] || data[1] || data[2] || data[3])
+               emv_tag_dump_bitmask(&bit_tlv, &bit_tag, f, level);
+       
+       return;
+}
+
+// EMV Book 3
+static void emv_tag_dump_cid(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level) {
+       if (!tlv || tlv->len < 1) {
+               PRINT_INDENT(level);
+               fprintf(f, "\tINVALID!\n");
+               return;
+       }
+       
+       PRINT_INDENT(level);
+       if ((tlv->value[0] & EMVAC_AC_MASK) == EMVAC_AAC)               fprintf(f, "\tAC1: AAC (Transaction declined)\n");
+       if ((tlv->value[0] & EMVAC_AC_MASK) == EMVAC_TC)                fprintf(f, "\tAC1: TC (Transaction approved)\n");
+       if ((tlv->value[0] & EMVAC_AC_MASK) == EMVAC_ARQC)              fprintf(f, "\tAC1: ARQC (Online authorisation requested)\n");
+       if ((tlv->value[0] & EMVAC_AC_MASK) == EMVAC_AC_MASK)   fprintf(f, "\tAC1: RFU\n");
+
+       if (tlv->value[0] & EMVCID_ADVICE) {
+               PRINT_INDENT(level);
+               fprintf(f, "\tAdvice required!\n");
+       }
+
+       if (tlv->value[0] & EMVCID_REASON_MASK) {
+               PRINT_INDENT(level);
+               fprintf(f, "\tReason/advice/referral code: ");
+               switch((tlv->value[0] & EMVCID_REASON_MASK)) {
+                       case 0:
+                               fprintf(f, "No information given\n");
+                               break;
+                       case 1:
+                               fprintf(f, "Service not allowed\n");
+                               break;
+                       case 2:
+                               fprintf(f, "PIN Try Limit exceeded\n");
+                               break;
+                       case 3:
+                               fprintf(f, "Issuer authentication failed\n");
+                               break;
+                       default:
+                               fprintf(f, "\tRFU: %2x\n", (tlv->value[0] & EMVCID_REASON_MASK));
+                               break;
+               }
+       }
+
+       return;
+}
+
 static void emv_tag_dump_cvm_list(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level)
 {
        uint32_t X, Y;
@@ -528,6 +673,14 @@ bool emv_tag_dump(const struct tlv *tlv, FILE *f, int level)
        case EMV_TAG_YYMMDD:
                emv_tag_dump_yymmdd(tlv, tag, f, level);
                break;
+       case EMV_TAG_CVR:
+               fprintf(f, "\n");
+               emv_tag_dump_cvr(tlv, tag, f, level);
+               break;
+       case EMV_TAG_CID:
+               fprintf(f, "\n");
+               emv_tag_dump_cid(tlv, tag, f, level);
+               break;
        };
 
        return true;
index 8dbd9e00a92cb29e1266260dde1ca8835f8466a6..f6d44f0150c989c5b71b1650a026997b5df0fa4b 100644 (file)
 #include "tlv.h"
 #include <stdio.h>
 
+// AC
+# define EMVAC_AC_MASK   0xC0
+# define EMVAC_AAC       0x00
+# define EMVAC_TC        0x40
+# define EMVAC_ARQC      0x80
+# define EMVAC_CDAREQ    0x10
+
+// CID
+# define EMVCID_ADVICE       0x08
+# define EMVCID_REASON_MASK  0x07
+
 bool emv_tag_dump(const struct tlv *tlv, FILE *f, int level);
 
 #endif
index 5c737b056a0543d6a05b95eb01ade1caa6c60319..08c6e3dbb53f5d57421897a35475ea9e0bb2a60f 100644 (file)
 
 // Got from here. Thanks)
 // https://eftlab.co.uk/index.php/site-map/knowledge-base/211-emv-aid-rid-pix
-const char *PSElist [] = { 
+static const char *PSElist [] = { 
        "325041592E5359532E4444463031", // 2PAY.SYS.DDF01 - Visa Proximity Payment System Environment - PPSE
        "315041592E5359532E4444463031"  // 1PAY.SYS.DDF01 - Visa Payment System Environment - PSE
 };
-const size_t PSElistLen = sizeof(PSElist)/sizeof(char*);
+//static const size_t PSElistLen = sizeof(PSElist)/sizeof(char*);
 
-const char *AIDlist [] = { 
+typedef struct {
+       enum CardPSVendor vendor;
+       const char* aid;
+} TAIDList;
+
+static const TAIDList AIDlist [] = { 
        // Visa International
-       "A00000000305076010",   // VISA ELO Credit      
-       "A0000000031010",               // VISA Debit/Credit (Classic)  
-       "A0000000031010",               // ddddddddddddddddddddddddddddddddddddddddddddddddddddddddd    
-       "A000000003101001",             // VISA Credit  
-       "A000000003101002",             // VISA Debit   
-       "A0000000032010",               // VISA Electron
-       "A0000000032020",               // VISA 
-       "A0000000033010",               // VISA Interlink       
-       "A0000000034010",               // VISA Specific        
-       "A0000000035010",               // VISA Specific        
-       "A0000000036010",               // Domestic Visa Cash Stored Value      
-       "A0000000036020",               // International Visa Cash Stored Value 
-       "A0000000038002",               // VISA Auth, VisaRemAuthen EMV-CAP (DPA)       
-       "A0000000038010",               // VISA Plus    
-       "A0000000039010",               // VISA Loyalty 
-       "A000000003999910",             // VISA Proprietary ATM 
+       { CV_VISA,      "A00000000305076010"},                  // VISA ELO Credit      
+       { CV_VISA,      "A0000000031010" },                             // VISA Debit/Credit (Classic)  
+       { CV_VISA,      "A000000003101001" },                   // VISA Credit  
+       { CV_VISA,      "A000000003101002" },                   // VISA Debit   
+       { CV_VISA,      "A0000000032010" },                             // VISA Electron
+       { CV_VISA,      "A0000000032020" },                             // VISA 
+       { CV_VISA,      "A0000000033010" },                             // VISA Interlink       
+       { CV_VISA,      "A0000000034010" },                             // VISA Specific        
+       { CV_VISA,      "A0000000035010" },                             // VISA Specific        
+       { CV_VISA,      "A0000000036010" },                             // Domestic Visa Cash Stored Value      
+       { CV_VISA,      "A0000000036020" },                             // International Visa Cash Stored Value 
+       { CV_VISA,      "A0000000038002" },                             // VISA Auth, VisaRemAuthen EMV-CAP (DPA)       
+       { CV_VISA,      "A0000000038010" },                             // VISA Plus    
+       { CV_VISA,      "A0000000039010" },                             // VISA Loyalty 
+       { CV_VISA,      "A000000003999910" },                   // VISA Proprietary ATM 
        // Visa USA
-       "A000000098",                   // Debit Card
-       "A0000000980848",               // Debit Card
+       { CV_VISA,      "A000000098" },                                 // Debit Card
+       { CV_VISA,      "A0000000980848" },                             // Debit Card
        // Mastercard International
-       "A00000000401",                 // MasterCard PayPass   
-       "A0000000041010",               // MasterCard Credit
-       "A00000000410101213",   // MasterCard Credit
-       "A00000000410101215",   // MasterCard Credit
-       "A0000000042010",               // MasterCard Specific
-       "A0000000043010",               // MasterCard Specific
-       "A0000000043060",               // Maestro (Debit)
-       "A000000004306001",             // Maestro (Debit)
-       "A0000000044010",               // MasterCard Specific
-       "A0000000045010",               // MasterCard Specific
-       "A0000000046000",               // Cirrus
-       "A0000000048002",               // SecureCode Auth EMV-CAP
-       "A0000000049999",               // MasterCard PayPass   
+       { CV_MASTERCARD, "A00000000401" },                      // MasterCard PayPass   
+       { CV_MASTERCARD, "A0000000041010" },            // MasterCard Credit
+       { CV_MASTERCARD, "A00000000410101213" },        // MasterCard Credit
+       { CV_MASTERCARD, "A00000000410101215" },        // MasterCard Credit
+       { CV_MASTERCARD, "A0000000042010" },            // MasterCard Specific
+       { CV_MASTERCARD, "A0000000043010" },            // MasterCard Specific
+       { CV_MASTERCARD, "A0000000043060" },            // Maestro (Debit)
+       { CV_MASTERCARD, "A000000004306001" },          // Maestro (Debit)
+       { CV_MASTERCARD, "A0000000044010" },            // MasterCard Specific
+       { CV_MASTERCARD, "A0000000045010" },            // MasterCard Specific
+       { CV_MASTERCARD, "A0000000046000" },            // Cirrus
+       { CV_MASTERCARD, "A0000000048002" },            // SecureCode Auth EMV-CAP
+       { CV_MASTERCARD, "A0000000049999" },            // MasterCard PayPass   
        // American Express
-       "A000000025",
-       "A0000000250000",
-       "A00000002501",
-       "A000000025010402",
-       "A000000025010701",
-       "A000000025010801",
+       { CV_AMERICANEXPRESS, "A000000025" },
+       { CV_AMERICANEXPRESS, "A0000000250000" },
+       { CV_AMERICANEXPRESS, "A00000002501" },
+       { CV_AMERICANEXPRESS, "A000000025010402" },
+       { CV_AMERICANEXPRESS, "A000000025010701" },
+       { CV_AMERICANEXPRESS, "A000000025010801" },
        // Groupement des Cartes Bancaires "CB"
-       "A0000000421010",               // Cartes Bancaire EMV Card     
-       "A0000000422010",               
-       "A0000000423010",               
-       "A0000000424010",               
-       "A0000000425010",               
+       { CV_CB, "A0000000421010" },                            // Cartes Bancaire EMV Card     
+       { CV_CB, "A0000000422010" },            
+       { CV_CB, "A0000000423010" },            
+       { CV_CB, "A0000000424010" },            
+       { CV_CB, "A0000000425010" },            
        // JCB CO., LTD.
-       "A00000006510",                 // JCB  
-       "A0000000651010",               // JCB J Smart Credit   
-       "A0000001544442",               // Banricompras Debito - Banrisul - Banco do Estado do Rio Grande do SUL - S.A.
-       "F0000000030001",               // BRADESCO
-       "A0000005241010",               // RuPay - RuPay
-       "D5780000021010"                // Bankaxept - Bankaxept        
+       { CV_JCB, "A00000006510" },                                     // JCB  
+       { CV_JCB, "A0000000651010" },                           // JCB J Smart Credit   
+       // Other
+       { CV_OTHER, "A0000001544442" },                         // Banricompras Debito - Banrisul - Banco do Estado do Rio Grande do SUL - S.A.
+       { CV_OTHER, "F0000000030001" },                         // BRADESCO
+       { CV_OTHER, "A0000005241010" },                         // RuPay - RuPay
+       { CV_OTHER, "D5780000021010" }                          // Bankaxept - Bankaxept
 };
-const size_t AIDlistLen = sizeof(AIDlist)/sizeof(char*);
+static const size_t AIDlistLen = sizeof(AIDlist)/sizeof(TAIDList);
 
 static bool APDULogging = false;
 void SetAPDULogging(bool logging) {
        APDULogging = logging;
 }
 
+enum CardPSVendor GetCardPSVendor(uint8_t * AID, size_t AIDlen) {
+       char buf[100] = {0};
+       if (AIDlen < 1)
+               return CV_NA;
+
+       hex_to_buffer((uint8_t *)buf, AID, AIDlen, sizeof(buf) - 1, 0, 0, true);
+
+       for(int i = 0; i < AIDlistLen; i ++) {
+               if (strncmp(AIDlist[i].aid, buf, strlen(AIDlist[i].aid)) == 0){
+                       return AIDlist[i].vendor;
+               }
+       }       
+       
+       return CV_NA;
+}
+
 static bool print_cb(void *data, const struct tlv *tlv, int level, bool is_leaf) {
        emv_tag_dump(tlv, stdout, level);
        if (is_leaf) {
@@ -103,11 +124,15 @@ void TLVPrintFromBuffer(uint8_t *data, int datalen) {
        }
 }
 
-void TLVPrintFromTLV(struct tlvdb *tlv) {
+void TLVPrintFromTLVLev(struct tlvdb *tlv, int level) {
        if (!tlv) 
                return;
        
-       tlvdb_visit(tlv, print_cb, NULL, 0);
+       tlvdb_visit(tlv, print_cb, NULL, level);
+}
+
+void TLVPrintFromTLV(struct tlvdb *tlv) {
+       TLVPrintFromTLVLev(tlv, 0);
 }
 
 void TLVPrintAIDlistFromSelectTLV(struct tlvdb *tlv) {
@@ -136,41 +161,94 @@ void TLVPrintAIDlistFromSelectTLV(struct tlvdb *tlv) {
        PrintAndLog("|------------------|--------|-------------------------|");
 }
 
+struct tlvdb *GetPANFromTrack2(const struct tlv *track2) {
+       char track2Hex[200] = {0};
+       uint8_t PAN[100] = {0};
+       int PANlen = 0;
+       char *tmp = track2Hex;
 
-int EMVSelect(bool ActivateField, bool LeaveFieldON, uint8_t *AID, size_t AIDLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
+       if (!track2)
+               return NULL;
+
+       for (int i = 0; i < track2->len; ++i, tmp += 2)
+               sprintf(tmp, "%02x", (unsigned int)track2->value[i]);
+       
+       int posD = strchr(track2Hex, 'd') - track2Hex;
+       if (posD < 1)
+               return NULL;
+       
+       track2Hex[posD] = 0;
+       if (strlen(track2Hex) % 2) {
+               track2Hex[posD] = 'F';
+               track2Hex[posD + 1] = '\0';
+       }
+       
+       param_gethex_to_eol(track2Hex, 0, PAN, sizeof(PAN), &PANlen);
+       
+  return tlvdb_fixed(0x5a, PANlen, PAN);
+}
+
+struct tlvdb *GetdCVVRawFromTrack2(const struct tlv *track2) {
+       char track2Hex[200] = {0};
+       char dCVVHex[100] = {0};
+       uint8_t dCVV[100] = {0};
+       int dCVVlen = 0;
+       const int PINlen = 5; // must calculated from 9F67 MSD Offset but i have not seen this tag)
+       char *tmp = track2Hex;
+       
+       if (!track2)
+               return NULL;
+       
+       for (int i = 0; i < track2->len; ++i, tmp += 2)
+               sprintf(tmp, "%02x", (unsigned int)track2->value[i]);
+       
+       int posD = strchr(track2Hex, 'd') - track2Hex;
+       if (posD < 1)
+               return NULL;
+
+       memset(dCVVHex, '0', 32);
+       // ATC
+       memcpy(dCVVHex + 0, track2Hex + posD + PINlen + 11, 4);
+       // PAN 5 hex
+       memcpy(dCVVHex + 4, track2Hex, 5);
+       // expire date
+       memcpy(dCVVHex + 9, track2Hex + posD + 1, 4);
+       // service code
+       memcpy(dCVVHex + 13, track2Hex + posD + 5, 3);
+       
+       param_gethex_to_eol(dCVVHex, 0, dCVV, sizeof(dCVV), &dCVVlen);
+       
+  return tlvdb_fixed(0x02, dCVVlen, dCVV);
+}
+
+int EMVExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
        uint8_t data[APDU_RES_LEN] = {0};
+
        *ResultLen = 0;
        if (sw) *sw = 0;
        uint16_t isw = 0;
        
-       // select APDU
-       data[0] = 0x00;
-       data[1] = 0xA4;
-       data[2] = 0x04;
-       data[3] = 0x00;
-       data[4] = AIDLen;
-       memcpy(&data[5], AID, AIDLen);
-       
        if (ActivateField)
                DropField();
        
-       if (APDULogging)
-               PrintAndLog(">>>> %s", sprint_hex(data, AIDLen + 6));
-
-       int res = ExchangeAPDU14a(data, AIDLen + 6, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen);
+       // COMPUTE APDU
+       memcpy(data, &apdu, 5);
+       if (apdu.data)
+               memcpy(&data[5], apdu.data, apdu.Lc);
        
        if (APDULogging)
-               PrintAndLog("<<<< %s", sprint_hex(Result, *ResultLen));
+               PrintAndLog(">>>> %s", sprint_hex(data, 6 + apdu.Lc));
+
+       // 6 byes + data = INS + CLA + P1 + P2 + Lc + <data = Nc> + Le
+       int res = ExchangeAPDU14a(data, 6 + apdu.Lc, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen);
        
        if (res) {
                return res;
        }
-       
-       if (*ResultLen < 2) {
-               PrintAndLog("SELECT ERROR: returned %d bytes", *ResultLen);
-               return 5;
-       }
-       
+
+       if (APDULogging)
+               PrintAndLog("<<<< %s", sprint_hex(Result, *ResultLen));
+
        *ResultLen -= 2;
        isw = Result[*ResultLen] * 0x0100 + Result[*ResultLen + 1];
        if (sw)
@@ -178,7 +256,7 @@ int EMVSelect(bool ActivateField, bool LeaveFieldON, uint8_t *AID, size_t AIDLen
 
        if (isw != 0x9000) {
                if (APDULogging)
-                       PrintAndLog("SELECT ERROR: [%4X] %s", isw, GetAPDUCodeDescription(*sw >> 8, *sw & 0xff));
+                       PrintAndLog("APDU(%02x%02x) ERROR: [%4X] %s", apdu.CLA, apdu.INS, isw, GetAPDUCodeDescription(*sw >> 8, *sw & 0xff));
                return 5;
        }
 
@@ -191,6 +269,14 @@ int EMVSelect(bool ActivateField, bool LeaveFieldON, uint8_t *AID, size_t AIDLen
        return 0;
 }
 
+int EMVExchange(bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
+       return EMVExchangeEx(false, LeaveFieldON, apdu, Result, MaxResultLen, ResultLen, sw, tlv);
+}
+
+int EMVSelect(bool ActivateField, bool LeaveFieldON, uint8_t *AID, size_t AIDLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
+       return EMVExchangeEx(ActivateField, LeaveFieldON, (sAPDU){0x00, 0xa4, 0x04, 0x00, AIDLen, AID}, Result, MaxResultLen, ResultLen, sw, tlv);
+}
+
 int EMVSelectPSE(bool ActivateField, bool LeaveFieldON, uint8_t PSENum, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) {
        uint8_t buf[APDU_AID_LEN] = {0};
        *ResultLen = 0;
@@ -291,7 +377,7 @@ int EMVSearch(bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvd
        int res = 0;
        int retrycnt = 0;
        for(int i = 0; i < AIDlistLen; i ++) {
-               param_gethex_to_eol(AIDlist[i], 0, aidbuf, sizeof(aidbuf), &aidlen);
+               param_gethex_to_eol(AIDlist[i].aid, 0, aidbuf, sizeof(aidbuf), &aidlen);
                res = EMVSelect((i == 0) ? ActivateField : false, (i == AIDlistLen - 1) ? LeaveFieldON : true, aidbuf, aidlen, data, sizeof(data), &datalen, &sw, tlv);
                // retry if error and not returned sw error
                if (res && res != 5) {
@@ -305,7 +391,7 @@ int EMVSearch(bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvd
                                }
                                
                                retrycnt = 0;
-                               PrintAndLog("Retry failed [%s]. Skiped...", AIDlist[i]);
+                               PrintAndLog("Retry failed [%s]. Skiped...", AIDlist[i].aid);
                        }
                        continue;
                }
@@ -315,7 +401,7 @@ int EMVSearch(bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvd
                        continue;
                
                if (decodeTLV){
-                       PrintAndLog("%s:", AIDlist[i]);
+                       PrintAndLog("%s:", AIDlist[i].aid);
                        TLVPrintFromBuffer(data, datalen);
                }
        }
@@ -324,7 +410,7 @@ int EMVSearch(bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvd
 }
 
 int EMVSelectApplication(struct tlvdb *tlv, uint8_t *AID, size_t *AIDlen) {
-       // needs to check priority. 0x00 - highest
+       // check priority. 0x00 - highest
        int prio = 0xffff;
        
        *AIDlen = 0;
@@ -363,101 +449,393 @@ int EMVSelectApplication(struct tlvdb *tlv, uint8_t *AID, size_t *AIDlen) {
 }
 
 int EMVGPO(bool LeaveFieldON, uint8_t *PDOL, size_t PDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
-       uint8_t data[APDU_RES_LEN] = {0};
-       *ResultLen = 0;
-       if (sw) *sw = 0;
-       uint16_t isw = 0;
-       
-       // GPO APDU
-       data[0] = 0x80;
-       data[1] = 0xA8;
-       data[2] = 0x00;
-       data[3] = 0x00;
-       data[4] = PDOLLen;
-       if (PDOL)
-               memcpy(&data[5], PDOL, PDOLLen);
-       
-       
-       if (APDULogging)
-               PrintAndLog(">>>> %s", sprint_hex(data, PDOLLen + 5));
+       return EMVExchange(LeaveFieldON, (sAPDU){0x80, 0xa8, 0x00, 0x00, PDOLLen, PDOL}, Result, MaxResultLen, ResultLen, sw, tlv);
+}
 
-       int res = ExchangeAPDU14a(data, PDOLLen + 5, false, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen);
-       
-       if (APDULogging)
-               PrintAndLog("<<<< %s", sprint_hex(Result, *ResultLen));
-       
-       if (res) {
-               return res;
+int EMVReadRecord(bool LeaveFieldON, uint8_t SFI, uint8_t SFIrec, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
+       return EMVExchange(LeaveFieldON, (sAPDU){0x00, 0xb2, SFIrec, (SFI << 3) | 0x04, 0, NULL}, Result, MaxResultLen, ResultLen, sw, tlv);
+}
+
+int EMVAC(bool LeaveFieldON, uint8_t RefControl, uint8_t *CDOL, size_t CDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
+       return EMVExchange(LeaveFieldON, (sAPDU){0x80, 0xae, RefControl, 0x00, CDOLLen, CDOL}, Result, MaxResultLen, ResultLen, sw, tlv);
+}
+
+int EMVGenerateChallenge(bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
+       return EMVExchange(LeaveFieldON, (sAPDU){0x00, 0x84, 0x00, 0x00, 0x00, NULL}, Result, MaxResultLen, ResultLen, sw, tlv);
+}
+
+int EMVInternalAuthenticate(bool LeaveFieldON, uint8_t *DDOL, size_t DDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
+       return EMVExchange(LeaveFieldON, (sAPDU){0x00, 0x88, 0x00, 0x00, DDOLLen, DDOL}, Result, MaxResultLen, ResultLen, sw, tlv);
+}
+
+int MSCComputeCryptoChecksum(bool LeaveFieldON, uint8_t *UDOL, uint8_t UDOLlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
+       return EMVExchange(LeaveFieldON, (sAPDU){0x80, 0x2a, 0x8e, 0x80, UDOLlen, UDOL}, Result, MaxResultLen, ResultLen, sw, tlv);
+}
+
+// Authentication 
+static struct emv_pk *get_ca_pk(struct tlvdb *db) {
+       const struct tlv *df_tlv = tlvdb_get(db, 0x84, NULL);
+       const struct tlv *caidx_tlv = tlvdb_get(db, 0x8f, NULL);
+
+       if (!df_tlv || !caidx_tlv || df_tlv->len < 6 || caidx_tlv->len != 1)
+               return NULL;
+
+       PrintAndLog("CA public key index 0x%0x", caidx_tlv->value[0]);
+       return emv_pk_get_ca_pk(df_tlv->value, caidx_tlv->value[0]);
+}
+
+int trSDA(struct tlvdb *tlv) {
+
+       struct emv_pk *pk = get_ca_pk(tlv);
+       if (!pk) {
+               PrintAndLog("ERROR: Key not found. Exit.");
+               return 2;
        }
        
-       if (*ResultLen < 2) {
-               PrintAndLog("GPO ERROR: returned %d bytes", *ResultLen);
-               return 5;
+       struct emv_pk *issuer_pk = emv_pki_recover_issuer_cert(pk, tlv);
+       if (!issuer_pk) {
+               emv_pk_free(pk);
+               PrintAndLog("ERROR: Issuer certificate not found. Exit.");
+               return 2;
        }
-       
-       *ResultLen -= 2;
-       isw = Result[*ResultLen] * 0x0100 + Result[*ResultLen + 1];
-       if (sw)
-               *sw = isw;
 
-       if (isw != 0x9000) {
-               if (APDULogging)
-                       PrintAndLog("GPO ERROR: [%4X] %s", isw, GetAPDUCodeDescription(*sw >> 8, *sw & 0xff));
-               return 5;
+       PrintAndLog("Issuer PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx",
+               issuer_pk->rid[0],
+               issuer_pk->rid[1],
+               issuer_pk->rid[2],
+               issuer_pk->rid[3],
+               issuer_pk->rid[4],
+               issuer_pk->index,
+               issuer_pk->serial[0],
+               issuer_pk->serial[1],
+               issuer_pk->serial[2]
+               );
+
+       const struct tlv *sda_tlv = tlvdb_get(tlv, 0x21, NULL);
+       if (!sda_tlv || sda_tlv->len < 1) {
+               emv_pk_free(issuer_pk);
+               emv_pk_free(pk);
+               PrintAndLog("ERROR: Can't find input list for Offline Data Authentication. Exit.");
+               return 3;
        }
-
-       // add to tlv tree
-       if (tlv) {
-               struct tlvdb *t = tlvdb_parse_multi(Result, *ResultLen);
-               tlvdb_add(tlv, t);
+       
+       struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv);
+       if (dac_db) {
+               const struct tlv *dac_tlv = tlvdb_get(dac_db, 0x9f45, NULL);
+               PrintAndLog("SDA verified OK. (%02hhx:%02hhx)\n", dac_tlv->value[0], dac_tlv->value[1]);
+               tlvdb_add(tlv, dac_db);
+       } else {
+               emv_pk_free(issuer_pk);
+               emv_pk_free(pk);
+               PrintAndLog("ERROR: SSAD verify error");
+               return 4;
        }
        
+       emv_pk_free(issuer_pk);
+       emv_pk_free(pk);
        return 0;
 }
 
-int EMVReadRecord(bool LeaveFieldON, uint8_t SFI, uint8_t SFIrec, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
-       uint8_t data[10] = {0};
-       *ResultLen = 0;
-       if (sw) *sw = 0;
-       uint16_t isw = 0;
-       
-       // read record APDU
-       data[0] = 0x00;
-       data[1] = 0xb2;
-       data[2] = SFIrec;
-       data[3] = (SFI << 3) | 0x04;
-       data[4] = 0;
-       
-       if (APDULogging)
-               PrintAndLog(">>>> %s", sprint_hex(data, 5));
+static const unsigned char default_ddol_value[] = {0x9f, 0x37, 0x04};
+static struct tlv default_ddol_tlv = {.tag = 0x9f49, .len = 3, .value = default_ddol_value };
 
-       int res = ExchangeAPDU14a(data, 5, false, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen);
-       
-       if (APDULogging)
-               PrintAndLog("<<<< %s", sprint_hex(Result, *ResultLen));
-       
-       if (res) {
-               return res;
+int trDDA(bool decodeTLV, struct tlvdb *tlv) {
+       uint8_t buf[APDU_RES_LEN] = {0};
+       size_t len = 0;
+       uint16_t sw = 0;
+
+       struct emv_pk *pk = get_ca_pk(tlv);
+       if (!pk) {
+               PrintAndLog("ERROR: Key not found. Exit.");
+               return 2;
        }
 
-       *ResultLen -= 2;
-       isw = Result[*ResultLen] * 0x0100 + Result[*ResultLen + 1];
-       if (sw)
-               *sw = isw;
+       const struct tlv *sda_tlv = tlvdb_get(tlv, 0x21, NULL);
+       if (!sda_tlv || sda_tlv->len < 1) {
+               emv_pk_free(pk);
+               PrintAndLog("ERROR: Can't find input list for Offline Data Authentication. Exit.");
+               return 3;
+       }
 
-       if (isw != 0x9000) {
-               if (APDULogging)
-                       PrintAndLog("Read record ERROR: [%4X] %s", isw, GetAPDUCodeDescription(*sw >> 8, *sw & 0xff));
-               return 5;
+       struct emv_pk *issuer_pk = emv_pki_recover_issuer_cert(pk, tlv);
+       if (!issuer_pk) {
+               emv_pk_free(pk);
+               PrintAndLog("ERROR: Issuer certificate not found. Exit.");
+               return 2;
+       }
+       printf("Issuer PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n",
+                       issuer_pk->rid[0],
+                       issuer_pk->rid[1],
+                       issuer_pk->rid[2],
+                       issuer_pk->rid[3],
+                       issuer_pk->rid[4],
+                       issuer_pk->index,
+                       issuer_pk->serial[0],
+                       issuer_pk->serial[1],
+                       issuer_pk->serial[2]
+                       );
+                               
+       struct emv_pk *icc_pk = emv_pki_recover_icc_cert(issuer_pk, tlv, sda_tlv);
+       if (!icc_pk) {
+               emv_pk_free(pk);
+               emv_pk_free(issuer_pk);
+               PrintAndLog("ERROR: ICC setrificate not found. Exit.");
+               return 2;
+       }
+       printf("ICC PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n",
+                       icc_pk->rid[0],
+                       icc_pk->rid[1],
+                       icc_pk->rid[2],
+                       icc_pk->rid[3],
+                       icc_pk->rid[4],
+                       icc_pk->index,
+                       icc_pk->serial[0],
+                       icc_pk->serial[1],
+                       icc_pk->serial[2]
+                       );
+
+       struct emv_pk *icc_pe_pk = emv_pki_recover_icc_pe_cert(issuer_pk, tlv);
+       if (!icc_pe_pk) {
+               PrintAndLog("WARNING: ICC PE PK recover error. ");
+       } else {
+               printf("ICC PE PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n",
+                               icc_pe_pk->rid[0],
+                               icc_pe_pk->rid[1],
+                               icc_pe_pk->rid[2],
+                               icc_pe_pk->rid[3],
+                               icc_pe_pk->rid[4],
+                               icc_pe_pk->index,
+                               icc_pe_pk->serial[0],
+                               icc_pe_pk->serial[1],
+                               icc_pe_pk->serial[2]
+                               );
        }
 
-       // add to tlv tree
-       if (tlv) {
-               struct tlvdb *t = tlvdb_parse_multi(Result, *ResultLen);
-               tlvdb_add(tlv, t);
+       // 9F4B: Signed Dynamic Application Data
+       const struct tlv *sdad_tlv = tlvdb_get(tlv, 0x9f4b, NULL);
+       // DDA with internal authenticate OR fDDA with filled 0x9F4B tag (GPO result)
+       // EMV kernel3 v2.4, contactless book C-3, C.1., page 147
+       if (sdad_tlv) {
+               PrintAndLog("\n* * Got Signed Dynamic Application Data (9F4B) form GPO. Maybe fDDA...");
+
+               const struct tlvdb *atc_db = emv_pki_recover_atc_ex(icc_pk, tlv, true);
+               if (!atc_db) {
+                       PrintAndLog("ERROR: Can't recover IDN (ICC Dynamic Number)");
+                       emv_pk_free(pk);
+                       emv_pk_free(issuer_pk);
+                       emv_pk_free(icc_pk);
+                       return 8;
+               }
+
+               // 9f36 Application Transaction Counter (ATC)
+               const struct tlv *atc_tlv = tlvdb_get(atc_db, 0x9f36, NULL);
+               if(atc_tlv) {
+                       PrintAndLog("\nATC (Application Transaction Counter) [%zu] %s", atc_tlv->len, sprint_hex_inrow(atc_tlv->value, atc_tlv->len));
+                       
+                       const struct tlv *core_atc_tlv = tlvdb_get(tlv, 0x9f36, NULL);
+                       if(tlv_equal(core_atc_tlv, atc_tlv)) {
+                               PrintAndLog("ATC check OK.");
+                               PrintAndLog("fDDA (fast DDA) verified OK.");
+                       } else {
+                               PrintAndLog("ERROR: fDDA verified, but ATC in the certificate and ATC in the record not the same.");
+                       }
+               } else {
+                       PrintAndLog("\nERROR: fDDA (fast DDA) verify error");
+                       emv_pk_free(pk);
+                       emv_pk_free(issuer_pk);
+                       emv_pk_free(icc_pk);
+                       return 9;
+               }
+       } else {
+               struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv);
+               if (dac_db) {
+                       const struct tlv *dac_tlv = tlvdb_get(dac_db, 0x9f45, NULL);
+                       printf("SDA verified OK. (%02hhx:%02hhx)\n", dac_tlv->value[0], dac_tlv->value[1]);
+                       tlvdb_add(tlv, dac_db);
+               } else {
+                       PrintAndLog("ERROR: SSAD verify error");
+                       emv_pk_free(pk);
+                       emv_pk_free(issuer_pk);
+                       emv_pk_free(icc_pk);
+                       return 4;
+               }
+               
+               PrintAndLog("\n* Calc DDOL");
+               const struct tlv *ddol_tlv = tlvdb_get(tlv, 0x9f49, NULL);
+               if (!ddol_tlv) {
+                       ddol_tlv = &default_ddol_tlv;
+                       PrintAndLog("DDOL [9f49] not found. Using default DDOL");
+               }
+
+               struct tlv *ddol_data_tlv = dol_process(ddol_tlv, tlv, 0);
+               if (!ddol_data_tlv) {
+                       PrintAndLog("ERROR: Can't create DDOL TLV");
+                       emv_pk_free(pk);
+                       emv_pk_free(issuer_pk);
+                       emv_pk_free(icc_pk);
+                       return 5;
+               }
+
+               PrintAndLog("DDOL data[%d]: %s", ddol_data_tlv->len, sprint_hex(ddol_data_tlv->value, ddol_data_tlv->len));
+
+               PrintAndLog("\n* Internal Authenticate");
+               int res = EMVInternalAuthenticate(true, (uint8_t *)ddol_data_tlv->value, ddol_data_tlv->len, buf, sizeof(buf), &len, &sw, NULL);
+               if (res) {      
+                       PrintAndLog("Internal Authenticate error(%d): %4x. Exit...", res, sw);
+                       free(ddol_data_tlv);
+                       emv_pk_free(pk);
+                       emv_pk_free(issuer_pk);
+                       emv_pk_free(icc_pk);
+                       return 6;
+               }
+
+               struct tlvdb *dda_db = NULL;
+               if (buf[0] == 0x80) {
+                       if (len < 3 ) {
+                               PrintAndLog("ERROR: Internal Authenticate format1 parsing error. length=%d", len);
+                       } else {
+                               // 9f4b Signed Dynamic Application Data
+                               dda_db = tlvdb_fixed(0x9f4b, len - 2, buf + 2);
+                               tlvdb_add(tlv, dda_db);
+                               if (decodeTLV){
+                                       PrintAndLog("* * Decode response format 1:");
+                                       TLVPrintFromTLV(dda_db);
+                               }
+                       }
+               } else {
+                       dda_db = tlvdb_parse_multi(buf, len);
+                       if(!dda_db) {
+                               PrintAndLog("ERROR: Can't parse Internal Authenticate result as TLV");
+                               free(ddol_data_tlv);
+                               emv_pk_free(pk);
+                               emv_pk_free(issuer_pk);
+                               emv_pk_free(icc_pk);
+                               return 7;
+                       }
+                       tlvdb_add(tlv, dda_db);
+                       
+                       if (decodeTLV)
+                               TLVPrintFromTLV(dda_db);
+               }
+
+               struct tlvdb *idn_db = emv_pki_recover_idn_ex(icc_pk, dda_db, ddol_data_tlv, true);
+               free(ddol_data_tlv);
+               if (!idn_db) {
+                       PrintAndLog("ERROR: Can't recover IDN (ICC Dynamic Number)");
+                       tlvdb_free(dda_db);
+                       emv_pk_free(pk);
+                       emv_pk_free(issuer_pk);
+                       emv_pk_free(icc_pk);
+                       return 8;
+               }
+               tlvdb_free(dda_db);
+
+               // 9f4c ICC Dynamic Number
+               const struct tlv *idn_tlv = tlvdb_get(idn_db, 0x9f4c, NULL);
+               if(idn_tlv) {
+                       PrintAndLog("\nIDN (ICC Dynamic Number) [%zu] %s", idn_tlv->len, sprint_hex_inrow(idn_tlv->value, idn_tlv->len));
+                       PrintAndLog("DDA verified OK.");
+                       tlvdb_add(tlv, idn_db);
+                       tlvdb_free(idn_db);
+               } else {
+                       PrintAndLog("\nERROR: DDA verify error");
+                       tlvdb_free(idn_db);
+
+                       emv_pk_free(pk);
+                       emv_pk_free(issuer_pk);
+                       emv_pk_free(icc_pk);
+                       return 9;
+               }
        }
        
+       emv_pk_free(pk);
+       emv_pk_free(issuer_pk);
+       emv_pk_free(icc_pk);
        return 0;
 }
 
+int trCDA(struct tlvdb *tlv, struct tlvdb *ac_tlv, struct tlv *pdol_data_tlv, struct tlv *ac_data_tlv) {
 
+       struct emv_pk *pk = get_ca_pk(tlv);
+       if (!pk) {
+               PrintAndLog("ERROR: Key not found. Exit.");
+               return 2;
+       }
+
+       const struct tlv *sda_tlv = tlvdb_get(tlv, 0x21, NULL);
+       if (!sda_tlv || sda_tlv->len < 1) {
+               PrintAndLog("ERROR: Can't find input list for Offline Data Authentication. Exit.");
+               emv_pk_free(pk);
+               return 3;
+       }
+
+       struct emv_pk *issuer_pk = emv_pki_recover_issuer_cert(pk, tlv);
+       if (!issuer_pk) {
+               PrintAndLog("ERROR: Issuer certificate not found. Exit.");
+               emv_pk_free(pk);
+               return 2;
+       }
+       printf("Issuer PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n",
+                       issuer_pk->rid[0],
+                       issuer_pk->rid[1],
+                       issuer_pk->rid[2],
+                       issuer_pk->rid[3],
+                       issuer_pk->rid[4],
+                       issuer_pk->index,
+                       issuer_pk->serial[0],
+                       issuer_pk->serial[1],
+                       issuer_pk->serial[2]
+                       );
+                               
+       struct emv_pk *icc_pk = emv_pki_recover_icc_cert(issuer_pk, tlv, sda_tlv);
+       if (!icc_pk) {
+               PrintAndLog("ERROR: ICC setrificate not found. Exit.");
+               emv_pk_free(pk);
+               emv_pk_free(issuer_pk);
+               return 2;
+       }
+       printf("ICC PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n",
+                       icc_pk->rid[0],
+                       icc_pk->rid[1],
+                       icc_pk->rid[2],
+                       icc_pk->rid[3],
+                       icc_pk->rid[4],
+                       icc_pk->index,
+                       icc_pk->serial[0],
+                       icc_pk->serial[1],
+                       icc_pk->serial[2]
+                       );
+
+       struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv);
+       if (dac_db) {
+               const struct tlv *dac_tlv = tlvdb_get(dac_db, 0x9f45, NULL);
+               PrintAndLog("SSAD verified OK. (%02hhx:%02hhx)", dac_tlv->value[0], dac_tlv->value[1]);
+               tlvdb_add(tlv, dac_db);
+       } else {
+               PrintAndLog("ERROR: SSAD verify error");
+               emv_pk_free(pk);
+               emv_pk_free(issuer_pk);
+               emv_pk_free(icc_pk);
+               return 4;
+       }
+       
+       PrintAndLog("\n* * Check Signed Dynamic Application Data (SDAD)");
+       struct tlvdb *idn_db = emv_pki_perform_cda_ex(icc_pk, tlv, ac_tlv,
+                       pdol_data_tlv, // pdol
+                       ac_data_tlv,   // cdol1
+                       NULL,          // cdol2 
+                       true);
+       if (idn_db) {
+               const struct tlv *idn_tlv = tlvdb_get(idn_db, 0x9f4c, NULL);
+               PrintAndLog("\nIDN (ICC Dynamic Number) [%zu] %s", idn_tlv->len, sprint_hex_inrow(idn_tlv->value, idn_tlv->len));
+               PrintAndLog("CDA verified OK.");
+               tlvdb_add(tlv, idn_db);
+       } else {
+               PrintAndLog("\nERROR: CDA verify error");
+       }
+
+       emv_pk_free(pk);
+       emv_pk_free(issuer_pk);
+       emv_pk_free(icc_pk);
+       return 0;
+}
index fdd3ab868762ae9148d524a4053921376cf6a6c2..94be4fcf36b8949fc1bd641448f4ff3e689594b8 100644 (file)
 #include "common.h"
 #include "ui.h"
 #include "cmdhf14a.h"
-#include "emv/apduinfo.h"
-#include "emv/tlv.h"
-#include "emv/dol.h"
-#include "emv/dump.h"
-#include "emv/emv_tags.h"
+#include "apduinfo.h"
+#include "tlv.h"
+#include "dol.h"
+#include "dump.h"
+#include "emv_tags.h"
+#include "emv_pk.h"
+#include "emv_pki.h"
 
 #define APDU_RES_LEN 260
 #define APDU_AID_LEN 50
 
+enum TransactionType {
+       TT_MSD,
+       TT_VSDC,        // not standart for contactless!!!!
+       TT_QVSDCMCHIP,
+       TT_CDA,
+};
+
+typedef struct {
+       uint8_t CLA;
+       uint8_t INS;
+       uint8_t P1;
+       uint8_t P2;
+       uint8_t Lc;
+       uint8_t *data;
+} sAPDU;
+
+enum CardPSVendor {
+       CV_NA,
+       CV_VISA,
+       CV_MASTERCARD,
+       CV_AMERICANEXPRESS,
+       CV_JCB,
+       CV_CB,
+       CV_OTHER,
+};
+extern enum CardPSVendor GetCardPSVendor(uint8_t * AID, size_t AIDlen);
+
 extern void TLVPrintFromBuffer(uint8_t *data, int datalen);
 extern void TLVPrintFromTLV(struct tlvdb *tlv);
+extern void TLVPrintFromTLVLev(struct tlvdb *tlv, int level);
 extern void TLVPrintAIDlistFromSelectTLV(struct tlvdb *tlv);
 
+extern struct tlvdb *GetPANFromTrack2(const struct tlv *track2);
+extern struct tlvdb *GetdCVVRawFromTrack2(const struct tlv *track2);
+
 extern void SetAPDULogging(bool logging);
 
 // search application
@@ -45,6 +78,17 @@ extern int EMVSelectApplication(struct tlvdb *tlv, uint8_t *AID, size_t *AIDlen)
 // Get Processing Options
 extern int EMVGPO(bool LeaveFieldON, uint8_t *PDOL, size_t PDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
 extern int EMVReadRecord(bool LeaveFieldON, uint8_t SFI, uint8_t SFIrec, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
+// AC
+extern int EMVGenerateChallenge(bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
+extern int EMVAC(bool LeaveFieldON, uint8_t RefControl, uint8_t *CDOL, size_t CDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
+// DDA
+extern int EMVInternalAuthenticate(bool LeaveFieldON, uint8_t *DDOL, size_t DDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
+// Mastercard
+int MSCComputeCryptoChecksum(bool LeaveFieldON, uint8_t *UDOL, uint8_t UDOLlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
+// Auth
+extern int trSDA(struct tlvdb *tlv);
+extern int trDDA(bool decodeTLV, struct tlvdb *tlv);
+extern int trCDA(struct tlvdb *tlv, struct tlvdb *ac_tlv, struct tlv *pdol_data_tlv, struct tlv *ac_data_tlv);
 
 #endif
 
diff --git a/client/emv/test/cda_test.c b/client/emv/test/cda_test.c
new file mode 100644 (file)
index 0000000..536a586
--- /dev/null
@@ -0,0 +1,442 @@
+/*
+ * emv-tools - a set of tools to work with EMV family of smart cards
+ * Copyright (C) 2012, 2015 Dmitry Eremin-Solenikov
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "../emv_pk.h"
+#include "../crypto.h"
+#include "../dump.h"
+#include "../tlv.h"
+#include "../emv_pki.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+struct emv_pk c_mchip_05 = {
+       .rid = { 0xa0, 0x00, 0x00, 0x00, 0x04, },
+       .index = 5,
+       .hash_algo = HASH_SHA_1,
+       .pk_algo = PK_RSA,
+       .hash = {
+               0xeb, 0xfa, 0x0d, 0x5d,
+               0x06, 0xd8, 0xce, 0x70,
+               0x2d, 0xa3, 0xea, 0xe8,
+               0x90, 0x70, 0x1d, 0x45,
+               0xe2, 0x74, 0xc8, 0x45, },
+       .exp = { 0x03, },
+       .elen = 1,
+       .mlen = 1408 / 8,
+       .modulus = (unsigned char[]){
+               0xb8, 0x04, 0x8a, 0xbc, 0x30, 0xc9, 0x0d, 0x97, 0x63, 0x36, 0x54, 0x3e, 0x3f, 0xd7, 0x09, 0x1c,
+               0x8f, 0xe4, 0x80, 0x0d, 0xf8, 0x20, 0xed, 0x55, 0xe7, 0xe9, 0x48, 0x13, 0xed, 0x00, 0x55, 0x5b,
+               0x57, 0x3f, 0xec, 0xa3, 0xd8, 0x4a, 0xf6, 0x13, 0x1a, 0x65, 0x1d, 0x66, 0xcf, 0xf4, 0x28, 0x4f,
+               0xb1, 0x3b, 0x63, 0x5e, 0xdd, 0x0e, 0xe4, 0x01, 0x76, 0xd8, 0xbf, 0x04, 0xb7, 0xfd, 0x1c, 0x7b,
+               0xac, 0xf9, 0xac, 0x73, 0x27, 0xdf, 0xaa, 0x8a, 0xa7, 0x2d, 0x10, 0xdb, 0x3b, 0x8e, 0x70, 0xb2,
+               0xdd, 0xd8, 0x11, 0xcb, 0x41, 0x96, 0x52, 0x5e, 0xa3, 0x86, 0xac, 0xc3, 0x3c, 0x0d, 0x9d, 0x45,
+               0x75, 0x91, 0x64, 0x69, 0xc4, 0xe4, 0xf5, 0x3e, 0x8e, 0x1c, 0x91, 0x2c, 0xc6, 0x18, 0xcb, 0x22,
+               0xdd, 0xe7, 0xc3, 0x56, 0x8e, 0x90, 0x02, 0x2e, 0x6b, 0xba, 0x77, 0x02, 0x02, 0xe4, 0x52, 0x2a,
+               0x2d, 0xd6, 0x23, 0xd1, 0x80, 0xe2, 0x15, 0xbd, 0x1d, 0x15, 0x07, 0xfe, 0x3d, 0xc9, 0x0c, 0xa3,
+               0x10, 0xd2, 0x7b, 0x3e, 0xfc, 0xcd, 0x8f, 0x83, 0xde, 0x30, 0x52, 0xca, 0xd1, 0xe4, 0x89, 0x38,
+               0xc6, 0x8d, 0x09, 0x5a, 0xac, 0x91, 0xb5, 0xf3, 0x7e, 0x28, 0xbb, 0x49, 0xec, 0x7e, 0xd5, 0x97,
+       },
+};
+
+const unsigned char c_issuer_cert[] = {
+               0x17, 0x14, 0x28, 0x4f, 0x76, 0x3b, 0x85, 0x86, 0xee, 0x6d, 0x31, 0x99, 0x51, 0xf7, 0xe6, 0x3f,
+               0xa2, 0x50, 0x76, 0xe5, 0x0d, 0xc9, 0xd3, 0x20, 0x0b, 0xa9, 0x98, 0xd3, 0xa0, 0x52, 0xad, 0xba,
+               0x9a, 0xb6, 0x9a, 0xc6, 0xad, 0x6a, 0xdd, 0x3c, 0xe0, 0x9f, 0x02, 0x78, 0xf4, 0x07, 0x4e, 0xc4,
+               0xee, 0x9b, 0x1d, 0x22, 0x68, 0xa3, 0xe9, 0x53, 0x57, 0x5e, 0x45, 0x4e, 0x50, 0xcd, 0x86, 0x0b,
+               0xf4, 0x24, 0xc5, 0x1c, 0x59, 0x77, 0x12, 0xd2, 0xaa, 0x05, 0x70, 0x89, 0xdd, 0x86, 0x73, 0xe5,
+               0x1b, 0x1e, 0x1d, 0x71, 0x88, 0x03, 0x48, 0x92, 0x07, 0x7a, 0xc1, 0x8a, 0x6a, 0xe2, 0x34, 0x88,
+               0xbe, 0xa9, 0xdf, 0x3b, 0x1a, 0x83, 0xf2, 0xc0, 0x80, 0x0c, 0xd7, 0xc5, 0xcd, 0xf2, 0xfd, 0xe0,
+               0x49, 0x6f, 0x7b, 0xc3, 0x9f, 0xb4, 0xbf, 0x36, 0x32, 0x99, 0xbf, 0xa6, 0x37, 0xb2, 0xec, 0x33,
+               0xc5, 0x07, 0xe3, 0x68, 0x21, 0xee, 0xc2, 0x07, 0x5f, 0x0e, 0x42, 0x0d, 0x38, 0xa1, 0xc9, 0xf3,
+               0x12, 0x72, 0x61, 0xba, 0x31, 0x6c, 0x98, 0x76, 0x74, 0xfa, 0xdb, 0x20, 0xea, 0x7f, 0xeb, 0x75,
+               0xee, 0x45, 0x5d, 0x12, 0x14, 0x6e, 0xa6, 0xf0, 0x2e, 0x8b, 0x01, 0xec, 0x2f, 0xa7, 0xa1, 0x15,
+};
+
+const unsigned char c_issuer_rem[] = {
+               0x6e, 0x63, 0xb7, 0xbc, 0x70, 0xab, 0xdd, 0x09, 0x34, 0x1b, 0x34, 0xc0, 0x32, 0x86, 0xba, 0x9b,
+               0xd8, 0x3b, 0xa7, 0x93, 0x6c, 0x5b, 0x77, 0x98, 0xfb, 0x22, 0xc5, 0xe5, 0x3f, 0xf2, 0x40, 0xa2,
+               0x6d, 0xbd, 0x64, 0x15,
+};
+
+const unsigned char c_issuer_exp[] = {
+               0x03,
+};
+
+const unsigned char c_icc_cert[] = {
+               0xa4, 0x2f, 0xbe, 0xb1, 0x56, 0xb9, 0x8d, 0xcb, 0x05, 0x54, 0xda, 0x06, 0x2a, 0xdc, 0xa5, 0x30,
+               0x9a, 0x91, 0xf0, 0x4f, 0xa2, 0xc7, 0xbd, 0x71, 0x02, 0xa8, 0xd7, 0x3f, 0x16, 0xa3, 0xcf, 0xad,
+               0xe8, 0xaa, 0xdf, 0x4f, 0x3f, 0xe2, 0xa2, 0x12, 0x5c, 0xcd, 0xd7, 0x7c, 0x6b, 0x9f, 0x78, 0xb5,
+               0xb4, 0x37, 0x1c, 0xe0, 0x80, 0x57, 0x25, 0xb0, 0xf9, 0xc0, 0x27, 0xaf, 0x14, 0x7d, 0x91, 0xe1,
+               0xff, 0xdb, 0x20, 0x1e, 0x9c, 0x17, 0x0c, 0xe7, 0x77, 0x05, 0x3a, 0x17, 0x2a, 0xd5, 0x26, 0xdc,
+               0xaf, 0xd3, 0x38, 0x95, 0xe1, 0xa9, 0x47, 0x30, 0x5c, 0x5b, 0x16, 0x7f, 0x2e, 0x7c, 0x6f, 0x99,
+               0x15, 0x81, 0xa6, 0x52, 0xee, 0x47, 0x31, 0x54, 0x76, 0x0c, 0x2e, 0xd7, 0x74, 0x21, 0x4e, 0x50,
+               0xdf, 0xec, 0xdd, 0x4c, 0xf2, 0x94, 0xc9, 0x74, 0xb8, 0x9e, 0xbc, 0xa2, 0x5b, 0x5a, 0xb3, 0xc0,
+               0xbe, 0xb5, 0x0d, 0xfa, 0xf7, 0x82, 0xaf, 0xde, 0x14, 0x33, 0xd9, 0x0c, 0xa2, 0xa8, 0x9d, 0x65,
+               0x1e, 0x75, 0xd6, 0x7e, 0xbc, 0x7c, 0x3e, 0x36, 0xf5, 0xa1, 0x65, 0xee, 0x61, 0x32, 0x61, 0x29,
+               0x39, 0xc1, 0xec, 0xd3, 0x99, 0xe4, 0x60, 0x74, 0xb9, 0x96, 0xd9, 0x3a, 0x88, 0xe0, 0x1e, 0x0a,
+};
+
+const unsigned char c_icc_exp[] = {
+               0x03,
+};
+
+const unsigned char c_sdad_cr[] = {
+       0x1c, 0x00, 0x9f, 0xc4, 0x86, 0x79, 0x15, 0x7d, 0xbf, 0xf4, 0x5f, 0x65, 0xd3, 0x3f, 0xf7, 0x8d,
+       0x4f, 0xcb, 0xf0, 0xcf, 0x5e, 0xa4, 0x20, 0x8d, 0x10, 0x7a, 0xe9, 0x5a, 0xa3, 0x8c, 0x54, 0x6d,
+       0x0e, 0x5a, 0x18, 0xb8, 0x74, 0x03, 0xa1, 0x2b, 0xd4, 0x47, 0xa8, 0xbb, 0xfc, 0x1e, 0x49, 0xce,
+       0x0b, 0x2e, 0x25, 0x13, 0x89, 0x20, 0x57, 0x03, 0xc9, 0xbb, 0x1a, 0x88, 0xcc, 0x79, 0xf1, 0xdd,
+       0xc2, 0xf9, 0x84, 0x1e, 0xad, 0xf0, 0x7c, 0xe0, 0x7b, 0x62, 0x51, 0x1d, 0xdc, 0x93, 0xdf, 0x59,
+       0xf2, 0x8f, 0x0e, 0x91, 0xf9, 0x23, 0x32, 0xd2, 0x9c, 0xde, 0xf2, 0xbc, 0xcb, 0x10, 0x08, 0x85,
+       0x05, 0x00, 0xef, 0x3e, 0x47, 0x0a, 0x4c, 0xb1, 0x8c, 0xd9, 0x1a, 0xa5, 0xc1, 0xa1, 0x08, 0xf3,
+
+};
+
+const unsigned char c_ssd1[] = {
+       0x5f, 0x25, 0x03, 0x14, 0x05, 0x01, 0x5f, 0x24, 0x03, 0x15, 0x06, 0x30, 0x5a, 0x08, 0x52, 0x85,
+       0x88, 0x12, 0x54, 0x34, 0x56, 0x53, 0x5f, 0x34, 0x01, 0x01, 0x8e, 0x0c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x1e, 0x03, 0x1f, 0x03, 0x9f, 0x07, 0x02, 0xff, 0x00, 0x9f, 0x0d, 0x05,
+       0xbc, 0x50, 0xbc, 0x00, 0x00, 0x9f, 0x0e, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x0f, 0x05,
+       0xbc, 0x70, 0xbc, 0x98, 0x00, 0x9f, 0x4a, 0x01, 0x82, 0x5f, 0x28, 0x02, 0x06, 0x43, 0x8c, 0x21,
+       0x9f, 0x02, 0x06, 0x9f, 0x03, 0x06, 0x9f, 0x1a, 0x02, 0x95, 0x05, 0x5f, 0x2a, 0x02, 0x9a, 0x03,
+       0x9c, 0x01, 0x9f, 0x37, 0x04, 0x9f, 0x35, 0x01, 0x9f, 0x45, 0x02, 0x9f, 0x4c, 0x08, 0x9f, 0x34,
+       0x03, 0x8d, 0x0c, 0x91, 0x0a, 0x8a, 0x02, 0x95, 0x05, 0x9f, 0x37, 0x04, 0x9f, 0x4c, 0x08,
+       0x39, 0x00,
+};
+static const struct tlv ssd1_tlv = {
+       .len = sizeof(c_ssd1),
+       .value = c_ssd1,
+};
+
+const unsigned char c_pan[] = {
+       0x52, 0x85, 0x88, 0x12, 0x54, 0x34, 0x56, 0x53,
+};
+
+const unsigned char c_dd1[] = {
+       0x12, 0x34, 0x57, 0x79,
+};
+
+const unsigned char c_dd2[] = {
+       0x9f, 0x27, 0x01, 0x40, 0x9f, 0x36, 0x02, 0x00, 0x10, 0x9f, 0x10, 0x12, 0x00, 0x10, 0x90, 0x40,
+       0x01, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+};
+
+const unsigned char c_crm1[] = {
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x43, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x06, 0x43, 0x14, 0x09, 0x25, 0x50, 0x12, 0x34, 0x57, 0x79, 0x23, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x03, 0x00,
+};
+static const struct tlv crm1_tlv = {
+       .len = sizeof(c_crm1),
+       .value = c_crm1,
+};
+
+static int cda_test_raw(bool verbose)
+{
+       const struct emv_pk *pk = &c_mchip_05;
+
+       struct crypto_pk *kcp = crypto_pk_open(PK_RSA,
+                       pk->modulus, pk->mlen,
+                       pk->exp, pk->elen);
+       if (!kcp)
+               return 1;
+
+       unsigned char *ipk_data;
+       size_t ipk_data_len;
+       ipk_data = crypto_pk_encrypt(kcp, c_issuer_cert, sizeof(c_issuer_cert), &ipk_data_len);
+       crypto_pk_close(kcp);
+
+       if (!ipk_data)
+               return 1;
+
+       if (verbose) {
+               printf("issuer cert:\n");
+               dump_buffer(ipk_data, ipk_data_len, stdout, 0);
+       }
+
+       size_t ipk_pk_len = ipk_data[13];
+       unsigned char *ipk_pk = malloc(ipk_pk_len);
+       memcpy(ipk_pk, ipk_data + 15, ipk_data_len - 36);
+       memcpy(ipk_pk + ipk_data_len - 36, c_issuer_rem, sizeof(c_issuer_rem));
+
+       struct crypto_hash *ch;
+       ch = crypto_hash_open(HASH_SHA_1);
+       if (!ch) {
+               free(ipk_pk);
+               free(ipk_data);
+               return 1;
+       }
+
+       crypto_hash_write(ch, ipk_data + 1, 14);
+       crypto_hash_write(ch, ipk_pk, ipk_pk_len);
+       crypto_hash_write(ch, c_issuer_exp, sizeof(c_issuer_exp));
+
+       unsigned char *h = crypto_hash_read(ch);
+       if (!h) {
+               crypto_hash_close(ch);
+               free(ipk_pk);
+               free(ipk_data);
+               return 1;
+       }
+
+       if (verbose) {
+               printf("crypto hash:\n");
+               dump_buffer(h, 20, stdout, 0);
+       }
+
+       if (memcmp(ipk_data + ipk_data_len - 21, h, 20)) {
+               crypto_hash_close(ch);
+               free(ipk_pk);
+               free(ipk_data);
+               return 1;
+       }
+
+       crypto_hash_close(ch);
+       free(ipk_data);
+
+       struct crypto_pk *ikcp = crypto_pk_open(PK_RSA, ipk_pk, (int) ipk_pk_len,
+                       c_issuer_exp, (int) sizeof(c_issuer_exp));
+       free(ipk_pk);
+       if (!ikcp)
+               return 1;
+
+       unsigned char *iccpk_data;
+       size_t iccpk_data_len;
+       iccpk_data = crypto_pk_encrypt(ikcp, c_icc_cert, sizeof(c_icc_cert), &iccpk_data_len);
+       crypto_pk_close(ikcp);
+
+       if (!iccpk_data)
+               return 1;
+
+       if (verbose) {
+               printf("icc cert:\n");
+               dump_buffer(iccpk_data, iccpk_data_len, stdout, 0);
+       }
+
+       size_t iccpk_pk_len = iccpk_data[19];
+       unsigned char *iccpk_pk = malloc(iccpk_pk_len);
+       memcpy(iccpk_pk, iccpk_data + 21, /*iccpk_data_len - 36*/iccpk_pk_len);
+       /*memcpy(iccpk_pk + iccpk_data_len - 36, icc_rem, sizeof(icc_rem));*/
+
+       ch = crypto_hash_open(HASH_SHA_1);
+       if (!ch) {
+               free(iccpk_pk);
+               free(iccpk_data);
+               return 1;
+       }
+
+       crypto_hash_write(ch, iccpk_data + 1, iccpk_data_len - 22);
+       crypto_hash_write(ch, c_icc_exp, sizeof(c_icc_exp));
+       crypto_hash_write(ch, c_ssd1, sizeof(c_ssd1));
+
+       h = crypto_hash_read(ch);
+       if (!h) {
+               crypto_hash_close(ch);
+               free(iccpk_pk);
+               free(iccpk_data);
+               return 1;
+       }
+
+       if (verbose) {
+               printf("crypto hash1.1:\n");
+               dump_buffer(h, 20, stdout, 0);
+       }
+
+       if (memcmp(iccpk_data + iccpk_data_len - 21, h, 20)) {
+               crypto_hash_close(ch);
+               free(iccpk_pk);
+               free(iccpk_data);
+               return 1;
+       }
+
+       crypto_hash_close(ch);
+       free(iccpk_data);
+
+       struct crypto_pk *icckcp = crypto_pk_open(PK_RSA, iccpk_pk, (int) iccpk_pk_len,
+                       c_issuer_exp, (int) sizeof(c_issuer_exp));
+       free(iccpk_pk);
+       if (!icckcp)
+               return 1;
+
+       size_t sdad_len;
+       unsigned char *sdad = crypto_pk_encrypt(icckcp, c_sdad_cr, sizeof(c_sdad_cr), &sdad_len);
+       crypto_pk_close(icckcp);
+       if (!sdad)
+               return 1;
+
+       if (verbose) {
+               printf("SDAD:\n");
+               dump_buffer(sdad, sdad_len, stdout, 0);
+       }
+
+       ch = crypto_hash_open(HASH_SHA_1);
+       if (!ch) {
+               free(sdad);
+               return 1;
+       }
+
+       crypto_hash_write(ch, sdad + 1, sdad_len - 22);
+       crypto_hash_write(ch, c_dd1, sizeof(c_dd1));
+
+       unsigned char *h2 = crypto_hash_read(ch);
+       if (!h2) {
+               crypto_hash_close(ch);
+               free(sdad);
+               return 1;
+       }
+
+       if (verbose) {
+               printf("crypto hash2:\n");
+               dump_buffer(h2, 20, stdout, 0);
+       }
+
+       crypto_hash_close(ch);
+
+       ch =  crypto_hash_open(HASH_SHA_1);
+       if (!ch) {
+               free(sdad);
+               return 1;
+       }
+
+       crypto_hash_write(ch, c_crm1, sizeof(c_crm1));
+       crypto_hash_write(ch, c_dd2, sizeof(c_dd2));
+
+       h = crypto_hash_read(ch);
+       if (!h) {
+               crypto_hash_close(ch);
+               free(sdad);
+               return 1;
+       }
+
+       if (verbose) {
+               printf("crypto hash2.1:\n");
+               dump_buffer(h, 20, stdout, 0);
+       }
+
+       if (memcmp(sdad + 5 + 8 + 1 + 8, h, 20)) {
+               crypto_hash_close(ch);
+               free(sdad);
+               return 1;
+       }
+
+       crypto_hash_close(ch);
+
+       free(sdad);
+
+       return 0;
+}
+
+static int cda_test_pk(bool verbose)
+{
+       const struct emv_pk *pk = &c_mchip_05;
+       struct tlvdb *db;
+
+       db = tlvdb_external(0x90, sizeof(c_issuer_cert), c_issuer_cert);
+       tlvdb_add(db, tlvdb_external(0x9f32, sizeof(c_issuer_exp), c_issuer_exp));
+       tlvdb_add(db, tlvdb_external(0x92, sizeof(c_issuer_rem), c_issuer_rem));
+       tlvdb_add(db, tlvdb_external(0x5a, sizeof(c_pan), c_pan));
+
+       struct emv_pk *ipk = emv_pki_recover_issuer_cert(pk, db);
+       if (!ipk) {
+               fprintf(stderr, "Could not recover Issuer certificate!\n");
+               tlvdb_free(db);
+               return 2;
+       }
+
+       tlvdb_add(db, tlvdb_external(0x9f46, sizeof(c_icc_cert), c_icc_cert));
+       tlvdb_add(db, tlvdb_external(0x9f47, sizeof(c_icc_exp), c_icc_exp));
+       /*tlvdb_add(db, tlvdb_external(0x9f48, sizeof(issuer_rem), issuer_rem));*/
+
+       struct emv_pk *iccpk = emv_pki_recover_icc_cert(ipk, db, &ssd1_tlv);
+       if (!iccpk) {
+               fprintf(stderr, "Could not recover ICC certificate!\n");
+               emv_pk_free(ipk);
+               tlvdb_free(db);
+               return 2;
+       }
+
+       tlvdb_add(db, tlvdb_fixed(0x9f37, sizeof(c_dd1), c_dd1));
+
+       struct tlvdb *cda_db;
+       cda_db = tlvdb_fixed(0x9f27, 1, (unsigned char[]){ 0x40 });
+       tlvdb_add(cda_db, tlvdb_fixed(0x9f36, 2, (unsigned char[]) { 0x00, 0x10 }));
+       tlvdb_add(cda_db, tlvdb_external(0x9f4b, sizeof(c_sdad_cr), c_sdad_cr));
+       tlvdb_add(cda_db, tlvdb_fixed(0x9f10, 0x12,
+                       (unsigned char[]) { 0x00, 0x10, 0x90, 0x40, 0x01, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff}));
+
+       struct tlvdb *idndb = emv_pki_perform_cda(iccpk, db, cda_db,
+                       NULL,
+                       &crm1_tlv,
+                       NULL);
+       if (!idndb) {
+               fprintf(stderr, "Could not recover IDN!\n");
+               tlvdb_free(cda_db);
+               emv_pk_free(iccpk);
+               emv_pk_free(ipk);
+               tlvdb_free(db);
+               return 2;
+       }
+
+       const struct tlv *idn = tlvdb_get(idndb, 0x9f4c, NULL);
+       if (!idn) {
+               fprintf(stderr, "IDN not found!\n");
+               tlvdb_free(idndb);
+               tlvdb_free(cda_db);
+               emv_pk_free(iccpk);
+               emv_pk_free(ipk);
+               tlvdb_free(db);
+               return 2;
+       }
+
+       if (verbose) {
+               printf("IDN:\n");
+               dump_buffer(idn->value, idn->len, stdout, 0);
+       }
+
+       tlvdb_free(idndb);
+       tlvdb_free(cda_db);
+       emv_pk_free(iccpk);
+       emv_pk_free(ipk);
+       tlvdb_free(db);
+
+       return 0;
+}
+
+int exec_cda_test(bool verbose)
+{
+       int ret;
+       fprintf(stdout, "\n");
+       
+       ret = cda_test_raw(verbose);
+       if (ret) {
+               fprintf(stderr, "CDA raw test: failed\n");
+               return ret;
+       }
+       fprintf(stdout, "CDA raw test: passed\n");
+
+       ret = cda_test_pk(verbose);
+       if (ret) {
+               fprintf(stderr, "CDA test pk: failed\n");
+               return ret;
+       }
+       fprintf(stdout, "CDA test pk: passed\n");
+
+       return 0;
+}
diff --git a/client/emv/test/cda_test.h b/client/emv/test/cda_test.h
new file mode 100644 (file)
index 0000000..1d321a2
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * emv-tools - a set of tools to work with EMV family of smart cards
+ * Copyright (C) 2012, 2015 Dmitry Eremin-Solenikov
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#include <stdbool.h> 
+extern int exec_cda_test(bool verbose);
diff --git a/client/emv/test/crypto_test.c b/client/emv/test/crypto_test.c
new file mode 100644 (file)
index 0000000..ff18b9d
--- /dev/null
@@ -0,0 +1,327 @@
+/*
+ * emv-tools - a set of tools to work with EMV family of smart cards
+ * Copyright (C) 2015 Dmitry Eremin-Solenikov
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "../crypto.h"
+#include "../dump.h"
+#include "util_posix.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+static int test_genkey(unsigned int keylength, unsigned char *msg, size_t msg_len, bool verbose)
+{
+       int ret = 1;
+       size_t tmp_len, tmp2_len;
+       unsigned char *tmp, *tmp2;
+       struct crypto_pk *pk;
+
+       printf("Testing key length %u ", keylength);
+       uint64_t ms = msclock();
+
+       pk = crypto_pk_genkey(PK_RSA, 1, keylength, 3);
+       if (!pk) {
+               fprintf(stderr, "ERROR: key generation error.\n");
+               goto out;
+       }
+
+       tmp_len = crypto_pk_get_nbits(pk);
+       if (tmp_len != keylength) {
+               fprintf(stderr, "ERROR: crypto_pk_get_nbits.\n");
+               goto close;
+       }
+
+       tmp = crypto_pk_decrypt(pk, msg, msg_len, &tmp_len);
+       if (!tmp) {
+               fprintf(stderr, "ERROR: crypto_pk_decrypt.\n");
+               goto close;
+       }
+
+       tmp2 = crypto_pk_encrypt(pk, tmp, tmp_len, &tmp2_len);
+       if (!tmp2) {
+               fprintf(stderr, "ERROR: crypto_pk_encrypt.\n");
+               goto free_tmp;
+       }
+
+       if (tmp2_len == msg_len && !memcmp(tmp2, msg, tmp2_len)) {
+               ret = 0;
+       } else {
+               fprintf(stderr, "ERROR: encrypt-decrypt sequence length or data error.\n");
+       }
+
+       free(tmp2);
+       printf("passed. (%"PRIu64" ms) \n", msclock() - ms);
+free_tmp:
+       free(tmp);
+close:
+       crypto_pk_close(pk);
+
+out:
+       return ret;
+}
+
+static unsigned char message[4096 / 8] =
+       "aaaaaaaaaaaaaaaabbbbbbbbbbbbbbbb"
+       "ccccccccccccccccdddddddddddddddd"
+       "eeeeeeeeeeeeeeeeffffffffffffffff"
+       "gggggggggggggggghhhhhhhhhhhhhhhh"
+       "iiiiiiiiiiiiiiiijjjjjjjjjjjjjjjj"
+       "kkkkkkkkkkkkkkkkllllllllllllllll"
+       "mmmmmmmmmmmmmmmmnnnnnnnnnnnnnnnn"
+       "oooooooooooooooopppppppppppppppp"
+       "qqqqqqqqqqqqqqqqrrrrrrrrrrrrrrrr"
+       "sssssssssssssssstttttttttttttttt"
+       "uuuuuuuuuuuuuuuuvvvvvvvvvvvvvvvv"
+       "wwwwwwwwwwwwwwwwxxxxxxxxxxxxxxxx"
+       "yyyyyyyyyyyyyyyyzzzzzzzzzzzzzzzz"
+       "aaaaaaaaaaaaaaaabbbbbbbbbbbbbbbb"
+       "ccccccccccccccccdddddddddddddddd"
+       "eeeeeeeeeeeeeeeeffffffffffffffff"
+       ;
+
+static unsigned char pk_N[] = {
+       0xdb, 0x12, 0xe4, 0xf1, 0x8d, 0x43, 0x74, 0xf0, 0xec, 0x38, 0xdc, 0xfb, 0xf9, 0x20, 0x75, 0x6d,
+       0x05, 0xf4, 0x36, 0xc2, 0x21, 0xac, 0x34, 0x0d, 0x16, 0xc5, 0x23, 0xcb, 0xfc, 0x9a, 0x8a, 0xd1,
+       0xe0, 0xbd, 0xda, 0xe5, 0x77, 0xd5, 0xaf, 0x65, 0x8d, 0x6b, 0x62, 0x5c, 0xcd, 0x89, 0x06, 0x8d,
+       0x11, 0x19, 0x6b, 0x0e, 0x3e, 0xe2, 0x80, 0x45, 0xf6, 0x44, 0x55, 0x21, 0x9c, 0x86, 0x90, 0x00,
+       0xa8, 0xaf, 0x8c, 0x94, 0xde, 0x3f, 0xe8, 0x56, 0x52, 0xfe, 0xee, 0xa5, 0x36, 0x72, 0x07, 0xf2,
+       0xcf, 0x8e, 0xf0, 0xbd, 0xff, 0x36, 0xd5, 0xf2, 0xad, 0x74, 0x1d, 0x17, 0xd0, 0xb7, 0x93, 0xe2,
+       0x2c, 0x8d, 0x3f, 0xb6, 0x7c, 0x65, 0x19, 0x9f, 0xa7, 0x80, 0x1f, 0x9f, 0xe5, 0x2f, 0x2d, 0x75,
+       0xc9, 0xc2, 0xe9, 0x70, 0xfa, 0x1e, 0x5a, 0xc6, 0xa3, 0x82, 0xd1, 0x29, 0x5a, 0x60, 0xce, 0x1f,
+       0x40, 0x2e, 0xfc, 0x2a, 0x5e, 0xde, 0xc9, 0x67, 0xfc, 0x45, 0x18, 0xce, 0xf2, 0x83, 0x94, 0x53,
+       0xd6, 0x4f, 0x2e, 0xc5, 0x2d, 0xa1, 0xa5, 0x7a, 0x63, 0x26, 0x70, 0xcb, 0x76, 0xfc, 0xb5, 0x8d,
+       0x0f, 0x88, 0x4c, 0x07, 0xba, 0xfa, 0x8b, 0xbc, 0xa0, 0xea, 0xea, 0x0a, 0xe6, 0xa5, 0x44, 0xa5,
+       0x0d, 0x12, 0x66, 0x2b, 0xf7, 0xc4, 0x76, 0xa3, 0x82, 0xa6, 0x2b, 0xb2, 0x5a, 0x27, 0xcd, 0x11,
+       0xd2, 0x9d, 0x42, 0x86, 0x8c, 0x82, 0xc8, 0xe1, 0xff, 0x7d, 0xf1, 0xd9, 0xd9, 0xa1, 0xf3, 0x3d,
+       0xc3, 0x12, 0x4e, 0x47, 0xc8, 0xa2, 0xcd, 0x72, 0x5a, 0x18, 0xea, 0x89, 0x5c, 0x73, 0x28, 0x52,
+       0xf8, 0xdb, 0x70, 0xdc, 0x92, 0xc9, 0xb7, 0x98, 0x10, 0x94, 0x79, 0xdc, 0x9e, 0x12, 0x6c, 0x14,
+       0x78, 0xf9, 0x5a, 0xad, 0x00, 0x98, 0xc8, 0x17, 0x79, 0x8a, 0xed, 0xe7, 0xc3, 0xd3, 0xa7, 0x8b,
+};
+
+static unsigned char pk_E[] = {
+       0x01, 0x00, 0x01,
+};
+
+static unsigned char pk_D[] = {
+       0x01, 0x17, 0xd4, 0x0a, 0x9c, 0x80, 0xd4, 0xa9, 0x8b, 0x14, 0x31, 0x8e, 0x14, 0x4d, 0x24, 0x28,
+       0xda, 0x19, 0xc0, 0xd8, 0x31, 0x20, 0xd1, 0xd5, 0xaa, 0xe2, 0x6a, 0xee, 0x4e, 0xa1, 0x5a, 0xc5,
+       0xf7, 0x50, 0x1b, 0x32, 0x7f, 0xe9, 0x92, 0x09, 0x78, 0xae, 0x2b, 0x7c, 0x79, 0x0e, 0x10, 0xf9,
+       0x4d, 0x37, 0x8a, 0x40, 0x34, 0xf2, 0x1e, 0x5f, 0xba, 0xfd, 0xd6, 0x4a, 0xe7, 0xa4, 0x08, 0x3d,
+       0xe8, 0x99, 0x8f, 0xa3, 0x02, 0x84, 0xe1, 0x1c, 0xe5, 0x27, 0x1e, 0x7b, 0xb6, 0x8c, 0xd5, 0x1b,
+       0x52, 0x0b, 0xcd, 0x89, 0xb5, 0x27, 0x49, 0xe3, 0xff, 0x17, 0x90, 0x39, 0x99, 0x32, 0x01, 0x4b,
+       0xe4, 0x9b, 0x03, 0xd1, 0x5e, 0x47, 0x86, 0xdc, 0x34, 0x12, 0xc0, 0x95, 0xa4, 0xa8, 0x1a, 0x9a,
+       0xf6, 0xd9, 0xc1, 0x1e, 0x6e, 0x31, 0x0e, 0x94, 0xe5, 0x25, 0xf6, 0xf3, 0x34, 0xdf, 0x3c, 0xc8,
+       0x0a, 0xc5, 0x8c, 0x00, 0x5c, 0x59, 0x55, 0x06, 0xd1, 0x39, 0x84, 0x35, 0x96, 0x40, 0xe8, 0xb2,
+       0xf7, 0x13, 0x83, 0x37, 0xe1, 0xe2, 0x79, 0x41, 0x90, 0x2a, 0xc3, 0x71, 0xc5, 0xcf, 0xf0, 0xaa,
+       0x01, 0x2f, 0x48, 0x9c, 0x3f, 0x29, 0x7b, 0xb7, 0x5c, 0xef, 0x25, 0xde, 0x34, 0x23, 0x81, 0x7a,
+       0x4c, 0x3a, 0x9b, 0xe4, 0xa7, 0x44, 0x73, 0xbf, 0xf7, 0x39, 0x43, 0xa4, 0x39, 0xa0, 0x1b, 0xf7,
+       0x4f, 0x5f, 0x14, 0x49, 0x32, 0x0e, 0x66, 0xd0, 0x29, 0xb5, 0x80, 0xe0, 0xba, 0x3b, 0x88, 0x2b,
+       0x14, 0xa4, 0x26, 0x00, 0x2f, 0x50, 0x20, 0x4e, 0xfa, 0xc2, 0x44, 0x72, 0x72, 0x6c, 0x2a, 0x77,
+       0x85, 0x20, 0xe0, 0x1d, 0x95, 0x6a, 0x66, 0xe7, 0xb8, 0xca, 0x5b, 0xc9, 0xc3, 0xf3, 0x39, 0xef,
+       0xd7, 0xd5, 0x45, 0xb6, 0x3e, 0x19, 0xea, 0x7c, 0x56, 0x20, 0x1b, 0x95, 0x86, 0x2e, 0xc7, 0x51,
+};
+
+static unsigned char pk_P[] = {
+       0xf5, 0x93, 0x0f, 0x76, 0x00, 0xab, 0x37, 0x01, 0xb9, 0x52, 0xb6, 0x82, 0xf9, 0xf5, 0xae, 0x29,
+       0x8f, 0xd5, 0x08, 0xbc, 0xf7, 0x9f, 0x84, 0xb6, 0x4c, 0x94, 0xb5, 0xfc, 0xfe, 0xe1, 0xcd, 0x6a,
+       0xf4, 0x9c, 0xa7, 0x33, 0xdb, 0xd8, 0xc8, 0xc1, 0xc0, 0x8d, 0x65, 0xed, 0x29, 0x99, 0x6c, 0x5c,
+       0xbe, 0x08, 0xac, 0x04, 0xe4, 0x3a, 0x18, 0xe2, 0x0f, 0x70, 0x26, 0x70, 0x9b, 0x71, 0xfc, 0x9f,
+       0x22, 0xea, 0x90, 0x3b, 0xc2, 0xa5, 0x16, 0x7a, 0xcd, 0x04, 0x3e, 0xa6, 0x37, 0x49, 0xa7, 0xee,
+       0xaa, 0xe4, 0x9d, 0xaa, 0x9b, 0xb0, 0xe2, 0x6a, 0x9d, 0x1e, 0xcd, 0x83, 0x4e, 0xd8, 0x59, 0x6d,
+       0x03, 0xd5, 0x4c, 0x5e, 0xc5, 0x22, 0x10, 0xb7, 0xcc, 0x0c, 0x90, 0x76, 0x05, 0x21, 0xe7, 0x77,
+       0x5c, 0x88, 0x5f, 0xd0, 0x5f, 0x9e, 0x2e, 0x49, 0x56, 0xf4, 0x2b, 0xa9, 0x99, 0x57, 0x74, 0x19,
+};
+
+static unsigned char pk_Q[] = {
+       0xe4, 0x5f, 0xd2, 0x28, 0xbd, 0xf3, 0xdd, 0x70, 0x3d, 0xfd, 0x01, 0x23, 0xae, 0x93, 0x6a, 0x91,
+       0xca, 0x68, 0xb1, 0xdb, 0x81, 0xab, 0x1e, 0x63, 0x76, 0x9b, 0x6d, 0xaa, 0x41, 0x87, 0x5a, 0x79,
+       0xe7, 0xce, 0xd6, 0x84, 0x32, 0x53, 0xf5, 0xfc, 0xb7, 0x41, 0x7c, 0xcb, 0x88, 0x09, 0xcb, 0xe9,
+       0x07, 0x16, 0x28, 0x55, 0x23, 0xe5, 0xf2, 0xf5, 0x23, 0xf5, 0xee, 0x2b, 0x9d, 0x91, 0x56, 0xc6,
+       0x30, 0x91, 0x4d, 0x16, 0x11, 0x6c, 0x48, 0x45, 0xe8, 0x5d, 0x0e, 0x9e, 0x04, 0xc8, 0xb6, 0xdd,
+       0xba, 0x0d, 0xdf, 0x53, 0x56, 0xfa, 0x0b, 0x0b, 0x99, 0x8d, 0xea, 0x5c, 0x45, 0x7d, 0xed, 0xad,
+       0x1f, 0xc5, 0xc1, 0x7d, 0x63, 0x31, 0xf8, 0x32, 0xb5, 0x33, 0xb0, 0xef, 0xce, 0x2e, 0x74, 0x1e,
+       0x77, 0x2a, 0x18, 0x35, 0x3d, 0x6e, 0x01, 0xba, 0xde, 0x21, 0x8e, 0x14, 0x12, 0xc3, 0x0d, 0x43,
+};
+
+static unsigned char pk_dP[] = {
+       0x5a, 0xc8, 0xf7, 0x1a, 0x44, 0xbd, 0x07, 0x24, 0xd8, 0x02, 0x3f, 0xfe, 0xc3, 0xb1, 0x93, 0xa5,
+       0x41, 0xcb, 0x1b, 0xe3, 0xe0, 0x17, 0x54, 0xd4, 0xa0, 0x13, 0x0a, 0x04, 0x71, 0xa5, 0xc0, 0x6f,
+       0x1d, 0xe7, 0x1b, 0xd9, 0x0c, 0x19, 0x64, 0x7e, 0x5c, 0x54, 0xe9, 0xad, 0x77, 0x87, 0x84, 0x8b,
+       0xf4, 0xa4, 0xf8, 0x13, 0x06, 0xdc, 0x83, 0x7e, 0x6e, 0xfe, 0xa2, 0xf7, 0x56, 0x40, 0x19, 0x88,
+       0x2b, 0x3c, 0x53, 0xfe, 0x03, 0xc3, 0x4c, 0x40, 0x31, 0xb2, 0xb4, 0x06, 0x76, 0xc2, 0x00, 0x17,
+       0x37, 0x8e, 0x34, 0xcb, 0x71, 0xab, 0x3e, 0xc8, 0xf3, 0x35, 0x03, 0xfc, 0xdb, 0x15, 0x18, 0x5a,
+       0x38, 0xe4, 0x8d, 0xcb, 0x2b, 0x4d, 0xa0, 0xa8, 0x92, 0x02, 0xc3, 0x15, 0x1e, 0x68, 0x9e, 0x4d,
+       0x7e, 0x23, 0xdc, 0x68, 0x08, 0x31, 0x4e, 0x23, 0x46, 0xc6, 0x15, 0xae, 0x29, 0x46, 0x2f, 0x61,
+};
+
+static unsigned char pk_dQ[] = {
+       0x33, 0x61, 0x9f, 0xae, 0x0c, 0xf6, 0xc6, 0x16, 0x8f, 0xcb, 0xd1, 0xaa, 0xce, 0x87, 0x5a, 0x4d,
+       0xcc, 0xe5, 0x7b, 0x46, 0xb0, 0xc8, 0xe8, 0x40, 0x66, 0x9a, 0x17, 0xb5, 0x5b, 0xa2, 0xf1, 0x67,
+       0x46, 0x11, 0x52, 0x50, 0x51, 0xe6, 0x74, 0x0c, 0xd4, 0xca, 0x46, 0x22, 0xa0, 0xcb, 0xdb, 0x75,
+       0xe5, 0x63, 0x45, 0xd5, 0xca, 0x0a, 0xdd, 0x7b, 0xec, 0x08, 0x53, 0xfa, 0xba, 0x2b, 0xce, 0x03,
+       0x2f, 0x40, 0x31, 0xc0, 0xca, 0x50, 0xbb, 0x7e, 0x07, 0x06, 0x90, 0xd8, 0x5a, 0xa9, 0x32, 0x03,
+       0x76, 0xed, 0xd2, 0x16, 0x35, 0x16, 0x72, 0xcf, 0xbc, 0x4f, 0xa2, 0xaf, 0xf9, 0xee, 0x98, 0x40,
+       0x00, 0x4b, 0x04, 0xfa, 0x8a, 0x0b, 0xdf, 0x14, 0xc1, 0x92, 0x0c, 0xb8, 0x17, 0x82, 0x7a, 0x1b,
+       0xb4, 0xa1, 0xe2, 0xea, 0x6f, 0x94, 0xc5, 0x8c, 0xde, 0x97, 0x5c, 0x19, 0x06, 0x13, 0x9e, 0x73,
+};
+
+static unsigned char pk_I[] = {
+       0x75, 0x40, 0xc6, 0x02, 0x7e, 0x4f, 0xad, 0xdb, 0x95, 0xac, 0x07, 0x8d, 0x80, 0xb6, 0x80, 0x02,
+       0x06, 0xdd, 0xb8, 0x5d, 0x92, 0x65, 0x69, 0x26, 0x86, 0x61, 0x6c, 0x87, 0x4e, 0xe5, 0x03, 0x68,
+       0xc6, 0x10, 0x15, 0x8c, 0x43, 0x3a, 0x45, 0x63, 0x48, 0xb7, 0x8a, 0x8c, 0xa2, 0x2b, 0x34, 0xb6,
+       0x83, 0xfe, 0xa8, 0x10, 0xa5, 0x74, 0xa5, 0xa9, 0x52, 0x42, 0x1f, 0xa0, 0x80, 0x6a, 0xc5, 0x35,
+       0xe8, 0xb8, 0xc2, 0xa0, 0x3f, 0x49, 0x18, 0xcf, 0x0e, 0x54, 0x3c, 0x70, 0x11, 0x11, 0xd3, 0x85,
+       0x8c, 0xb2, 0xe5, 0x74, 0xdf, 0x98, 0xea, 0x6c, 0xc0, 0x5f, 0x7f, 0xff, 0x69, 0xbf, 0x08, 0x8d,
+       0x1b, 0xc4, 0x90, 0xcc, 0xa4, 0xcd, 0xcc, 0x34, 0x58, 0xe5, 0x91, 0x53, 0x3a, 0xd5, 0x39, 0xf4,
+       0xd4, 0x42, 0xc9, 0x17, 0xb2, 0x2c, 0x92, 0x12, 0x37, 0x1b, 0xd3, 0xc5, 0x79, 0xd2, 0x65, 0x61,
+};
+
+static int test_pk(bool verbose)
+{
+       int ret = 1;
+       size_t tmp_len, tmp2_len;
+       unsigned char *tmp, *tmp2;
+       struct crypto_pk *pubk, *privk;
+       unsigned char *msg = message;
+       size_t msg_len = sizeof(pk_N);
+
+       printf("Testing public keys interfaces\n");
+
+       pubk = crypto_pk_open(PK_RSA,
+                       pk_N, sizeof(pk_N),
+                       pk_E, sizeof(pk_E));
+       if (!pubk) {
+               fprintf(stderr, "ERROR: open public key.\n");
+               return 1;
+       }
+
+       tmp_len = crypto_pk_get_nbits(pubk);
+       if (tmp_len != sizeof(pk_N) * 8) {
+               fprintf(stderr, "ERROR: crypto_pk_get_nbits mismatch.\n");
+               goto close_pub;
+       }
+
+       tmp = crypto_pk_get_parameter(pubk, 0, &tmp_len);
+       if (tmp_len != sizeof(pk_N) || memcmp(tmp, pk_N, tmp_len)) {
+               fprintf(stderr, "ERROR: crypto_pk_get_parameter(0) Modulus. param len %d len %d\n", tmp_len, sizeof(pk_N));
+               free(tmp);
+               goto close_pub;
+       }
+       free(tmp);
+
+       tmp = crypto_pk_get_parameter(pubk, 1, &tmp_len);
+       if (tmp_len != sizeof(pk_E) || memcmp(tmp, pk_E, tmp_len)) {
+               fprintf(stderr, "ERROR: crypto_pk_get_parameter(1) Exponent.\n");
+               free(tmp);
+               goto close_pub;
+       }
+       free(tmp);
+
+       privk = crypto_pk_open_priv(PK_RSA,
+                       pk_N, sizeof(pk_N),
+                       pk_E, sizeof(pk_E),
+                       pk_D, sizeof(pk_D),
+                       pk_P, sizeof(pk_P),
+                       pk_Q, sizeof(pk_Q),
+                       pk_dP, sizeof(pk_dP),
+                       pk_dQ, sizeof(pk_dQ),
+                       pk_I, sizeof(pk_I));
+       if (!privk) {
+               fprintf(stderr, "ERROR: open private key.\n");
+               goto close_pub;
+       }
+
+
+       tmp_len = crypto_pk_get_nbits(privk);
+       if (tmp_len != sizeof(pk_N) * 8) {
+               fprintf(stderr, "ERROR: crypto_pk_get_nbits mismatch.\n");
+               goto close_pub;
+       }
+
+       tmp = crypto_pk_get_parameter(privk, 0, &tmp_len);
+       if (tmp_len != sizeof(pk_N) || memcmp(tmp, pk_N, tmp_len)) {
+               fprintf(stderr, "ERROR: crypto_pk_get_parameter(0) Modulus. param len %d len %d\n", tmp_len, sizeof(pk_N));
+               free(tmp);
+               goto close;
+       }
+       free(tmp);
+
+       tmp = crypto_pk_get_parameter(privk, 1, &tmp_len);
+       if (tmp_len != sizeof(pk_E) || memcmp(tmp, pk_E, tmp_len)) {
+               fprintf(stderr, "ERROR: crypto_pk_get_parameter(1) Exponent.\n");
+               free(tmp);
+               goto close;
+       }
+       free(tmp);
+
+       tmp = crypto_pk_decrypt(privk, msg, msg_len, &tmp_len);
+       if (!tmp) {
+               fprintf(stderr, "ERROR: crypto_pk_decrypt.\n");
+               goto close;
+       }
+
+       tmp2 = crypto_pk_encrypt(pubk, tmp, tmp_len, &tmp2_len);
+       if (!tmp2) {
+               fprintf(stderr, "ERROR: crypto_pk_encrypt.\n");
+               goto free_tmp;
+       }
+
+       if (tmp2_len == msg_len && !memcmp(tmp2, msg, tmp2_len)) {
+               ret = 0;
+       } else {
+               fprintf(stderr, "ERROR: encrypt-decrypt sequence length or data error.\n");
+       }
+
+       free(tmp2);
+free_tmp:
+       free(tmp);
+
+close:
+       crypto_pk_close(privk);
+close_pub:
+       crypto_pk_close(pubk);
+
+       return ret;
+}
+
+int exec_crypto_test(bool verbose)
+{
+       unsigned int keylengths[] = {1024, 1152, 1408, 1984, 2048, 3072, 4096};
+       int i;
+       int ret;
+       fprintf(stdout, "\n");
+
+       ret = test_pk(verbose);
+       if (ret) {
+               fprintf(stderr, "Crypto raw test: failed\n");
+               return ret;
+       }
+       fprintf(stdout, "Crypto raw test: passed\n\n");
+
+       for (i = 0; i < sizeof(keylengths) / sizeof(keylengths[0]); i++) {
+               unsigned int kl = keylengths[i];
+               ret = test_genkey(kl, message, kl / 8, verbose);
+               if (ret) {
+                       fprintf(stderr, "Crypto generate key[%d] test: failed\n", kl);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
diff --git a/client/emv/test/crypto_test.h b/client/emv/test/crypto_test.h
new file mode 100644 (file)
index 0000000..084bc99
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * emv-tools - a set of tools to work with EMV family of smart cards
+ * Copyright (C) 2015 Dmitry Eremin-Solenikov
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+ #include <stdbool.h>
+
+extern int exec_crypto_test(bool verbose);
diff --git a/client/emv/test/cryptotest.c b/client/emv/test/cryptotest.c
new file mode 100644 (file)
index 0000000..a6d06e6
--- /dev/null
@@ -0,0 +1,65 @@
+//-----------------------------------------------------------------------------
+// Copyright (C) 2017 Merlok
+//
+// This code is licensed to you under the terms of the GNU GPL, version 2 or,
+// at your option, any later version. See the LICENSE.txt file for the text of
+// the license.
+//-----------------------------------------------------------------------------
+// Crypto algorithms testing
+//-----------------------------------------------------------------------------
+
+#include "cryptotest.h"
+#include "util.h"
+#include "ui.h"
+
+#include "bignum.h"
+#include "aes.h"
+#include "des.h"
+#include "rsa.h"
+#include "sha1.h"
+
+#include "crypto_test.h"
+#include "sda_test.h"
+#include "dda_test.h"
+#include "cda_test.h"
+
+int ExecuteCryptoTests(bool verbose) {
+       int res;
+       bool TestFail = false;
+       
+       res = mpi_self_test(verbose);
+       if (res) TestFail = true;
+       
+       res = aes_self_test(verbose);
+       if (res) TestFail = true;
+       
+       res = des_self_test(verbose);
+       if (res) TestFail = true;
+       
+       res = sha1_self_test(verbose);
+       if (res) TestFail = true;
+       
+       res = rsa_self_test(verbose);
+       if (res) TestFail = true;
+       
+       res = exec_sda_test(verbose);
+       if (res) TestFail = true;
+
+       res = exec_dda_test(verbose);
+       if (res) TestFail = true;
+       
+       res = exec_cda_test(verbose);
+       if (res) TestFail = true;
+
+       res = exec_crypto_test(verbose);
+       if (res) TestFail = true;
+
+       PrintAndLog("\n--------------------------");
+       if (TestFail)
+               PrintAndLog("Test(s) [ERROR].");
+       else
+               PrintAndLog("Tests [OK].");
+       
+       return TestFail;
+}
+
diff --git a/client/emv/test/cryptotest.h b/client/emv/test/cryptotest.h
new file mode 100644 (file)
index 0000000..5c6aaae
--- /dev/null
@@ -0,0 +1,13 @@
+//-----------------------------------------------------------------------------
+// Copyright (C) 2017 Merlok
+//
+// This code is licensed to you under the terms of the GNU GPL, version 2 or,
+// at your option, any later version. See the LICENSE.txt file for the text of
+// the license.
+//-----------------------------------------------------------------------------
+// Crypto algorithms testing
+//-----------------------------------------------------------------------------
+
+#include <stdbool.h>
+
+extern int ExecuteCryptoTests(bool verbose);
diff --git a/client/emv/test/dda_test.c b/client/emv/test/dda_test.c
new file mode 100644 (file)
index 0000000..afdd4e2
--- /dev/null
@@ -0,0 +1,390 @@
+/*
+ * emv-tools - a set of tools to work with EMV family of smart cards
+ * Copyright (C) 2012, 2015 Dmitry Eremin-Solenikov
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "dda_test.h"
+
+#include "../emv_pk.h"
+#include "../crypto.h"
+#include "../dump.h"
+#include "../tlv.h"
+#include "../emv_pki.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+struct emv_pk mchip_05 = {
+       .rid = { 0xa0, 0x00, 0x00, 0x00, 0x04, },
+       .index = 5,
+       .hash_algo = HASH_SHA_1,
+       .pk_algo = PK_RSA,
+       .hash = {
+               0xeb, 0xfa, 0x0d, 0x5d,
+               0x06, 0xd8, 0xce, 0x70,
+               0x2d, 0xa3, 0xea, 0xe8,
+               0x90, 0x70, 0x1d, 0x45,
+               0xe2, 0x74, 0xc8, 0x45, },
+       .exp = { 0x03, },
+       .elen = 1,
+       .mlen = 1408 / 8,
+       .modulus = (unsigned char[]){
+               0xb8, 0x04, 0x8a, 0xbc, 0x30, 0xc9, 0x0d, 0x97, 0x63, 0x36, 0x54, 0x3e, 0x3f, 0xd7, 0x09, 0x1c,
+               0x8f, 0xe4, 0x80, 0x0d, 0xf8, 0x20, 0xed, 0x55, 0xe7, 0xe9, 0x48, 0x13, 0xed, 0x00, 0x55, 0x5b,
+               0x57, 0x3f, 0xec, 0xa3, 0xd8, 0x4a, 0xf6, 0x13, 0x1a, 0x65, 0x1d, 0x66, 0xcf, 0xf4, 0x28, 0x4f,
+               0xb1, 0x3b, 0x63, 0x5e, 0xdd, 0x0e, 0xe4, 0x01, 0x76, 0xd8, 0xbf, 0x04, 0xb7, 0xfd, 0x1c, 0x7b,
+               0xac, 0xf9, 0xac, 0x73, 0x27, 0xdf, 0xaa, 0x8a, 0xa7, 0x2d, 0x10, 0xdb, 0x3b, 0x8e, 0x70, 0xb2,
+               0xdd, 0xd8, 0x11, 0xcb, 0x41, 0x96, 0x52, 0x5e, 0xa3, 0x86, 0xac, 0xc3, 0x3c, 0x0d, 0x9d, 0x45,
+               0x75, 0x91, 0x64, 0x69, 0xc4, 0xe4, 0xf5, 0x3e, 0x8e, 0x1c, 0x91, 0x2c, 0xc6, 0x18, 0xcb, 0x22,
+               0xdd, 0xe7, 0xc3, 0x56, 0x8e, 0x90, 0x02, 0x2e, 0x6b, 0xba, 0x77, 0x02, 0x02, 0xe4, 0x52, 0x2a,
+               0x2d, 0xd6, 0x23, 0xd1, 0x80, 0xe2, 0x15, 0xbd, 0x1d, 0x15, 0x07, 0xfe, 0x3d, 0xc9, 0x0c, 0xa3,
+               0x10, 0xd2, 0x7b, 0x3e, 0xfc, 0xcd, 0x8f, 0x83, 0xde, 0x30, 0x52, 0xca, 0xd1, 0xe4, 0x89, 0x38,
+               0xc6, 0x8d, 0x09, 0x5a, 0xac, 0x91, 0xb5, 0xf3, 0x7e, 0x28, 0xbb, 0x49, 0xec, 0x7e, 0xd5, 0x97,
+       },
+};
+
+const unsigned char d_issuer_cert[] = {
+               0x17, 0x14, 0x28, 0x4f, 0x76, 0x3b, 0x85, 0x86, 0xee, 0x6d, 0x31, 0x99, 0x51, 0xf7, 0xe6, 0x3f,
+               0xa2, 0x50, 0x76, 0xe5, 0x0d, 0xc9, 0xd3, 0x20, 0x0b, 0xa9, 0x98, 0xd3, 0xa0, 0x52, 0xad, 0xba,
+               0x9a, 0xb6, 0x9a, 0xc6, 0xad, 0x6a, 0xdd, 0x3c, 0xe0, 0x9f, 0x02, 0x78, 0xf4, 0x07, 0x4e, 0xc4,
+               0xee, 0x9b, 0x1d, 0x22, 0x68, 0xa3, 0xe9, 0x53, 0x57, 0x5e, 0x45, 0x4e, 0x50, 0xcd, 0x86, 0x0b,
+               0xf4, 0x24, 0xc5, 0x1c, 0x59, 0x77, 0x12, 0xd2, 0xaa, 0x05, 0x70, 0x89, 0xdd, 0x86, 0x73, 0xe5,
+               0x1b, 0x1e, 0x1d, 0x71, 0x88, 0x03, 0x48, 0x92, 0x07, 0x7a, 0xc1, 0x8a, 0x6a, 0xe2, 0x34, 0x88,
+               0xbe, 0xa9, 0xdf, 0x3b, 0x1a, 0x83, 0xf2, 0xc0, 0x80, 0x0c, 0xd7, 0xc5, 0xcd, 0xf2, 0xfd, 0xe0,
+               0x49, 0x6f, 0x7b, 0xc3, 0x9f, 0xb4, 0xbf, 0x36, 0x32, 0x99, 0xbf, 0xa6, 0x37, 0xb2, 0xec, 0x33,
+               0xc5, 0x07, 0xe3, 0x68, 0x21, 0xee, 0xc2, 0x07, 0x5f, 0x0e, 0x42, 0x0d, 0x38, 0xa1, 0xc9, 0xf3,
+               0x12, 0x72, 0x61, 0xba, 0x31, 0x6c, 0x98, 0x76, 0x74, 0xfa, 0xdb, 0x20, 0xea, 0x7f, 0xeb, 0x75,
+               0xee, 0x45, 0x5d, 0x12, 0x14, 0x6e, 0xa6, 0xf0, 0x2e, 0x8b, 0x01, 0xec, 0x2f, 0xa7, 0xa1, 0x15,
+};
+
+const unsigned char d_issuer_rem[] = {
+               0x6e, 0x63, 0xb7, 0xbc, 0x70, 0xab, 0xdd, 0x09, 0x34, 0x1b, 0x34, 0xc0, 0x32, 0x86, 0xba, 0x9b,
+               0xd8, 0x3b, 0xa7, 0x93, 0x6c, 0x5b, 0x77, 0x98, 0xfb, 0x22, 0xc5, 0xe5, 0x3f, 0xf2, 0x40, 0xa2,
+               0x6d, 0xbd, 0x64, 0x15,
+};
+
+const unsigned char d_issuer_exp[] = {
+               0x03,
+};
+
+const unsigned char d_icc_cert[] = {
+               0xa4, 0x2f, 0xbe, 0xb1, 0x56, 0xb9, 0x8d, 0xcb, 0x05, 0x54, 0xda, 0x06, 0x2a, 0xdc, 0xa5, 0x30,
+               0x9a, 0x91, 0xf0, 0x4f, 0xa2, 0xc7, 0xbd, 0x71, 0x02, 0xa8, 0xd7, 0x3f, 0x16, 0xa3, 0xcf, 0xad,
+               0xe8, 0xaa, 0xdf, 0x4f, 0x3f, 0xe2, 0xa2, 0x12, 0x5c, 0xcd, 0xd7, 0x7c, 0x6b, 0x9f, 0x78, 0xb5,
+               0xb4, 0x37, 0x1c, 0xe0, 0x80, 0x57, 0x25, 0xb0, 0xf9, 0xc0, 0x27, 0xaf, 0x14, 0x7d, 0x91, 0xe1,
+               0xff, 0xdb, 0x20, 0x1e, 0x9c, 0x17, 0x0c, 0xe7, 0x77, 0x05, 0x3a, 0x17, 0x2a, 0xd5, 0x26, 0xdc,
+               0xaf, 0xd3, 0x38, 0x95, 0xe1, 0xa9, 0x47, 0x30, 0x5c, 0x5b, 0x16, 0x7f, 0x2e, 0x7c, 0x6f, 0x99,
+               0x15, 0x81, 0xa6, 0x52, 0xee, 0x47, 0x31, 0x54, 0x76, 0x0c, 0x2e, 0xd7, 0x74, 0x21, 0x4e, 0x50,
+               0xdf, 0xec, 0xdd, 0x4c, 0xf2, 0x94, 0xc9, 0x74, 0xb8, 0x9e, 0xbc, 0xa2, 0x5b, 0x5a, 0xb3, 0xc0,
+               0xbe, 0xb5, 0x0d, 0xfa, 0xf7, 0x82, 0xaf, 0xde, 0x14, 0x33, 0xd9, 0x0c, 0xa2, 0xa8, 0x9d, 0x65,
+               0x1e, 0x75, 0xd6, 0x7e, 0xbc, 0x7c, 0x3e, 0x36, 0xf5, 0xa1, 0x65, 0xee, 0x61, 0x32, 0x61, 0x29,
+               0x39, 0xc1, 0xec, 0xd3, 0x99, 0xe4, 0x60, 0x74, 0xb9, 0x96, 0xd9, 0x3a, 0x88, 0xe0, 0x1e, 0x0a,
+};
+
+const unsigned char d_icc_exp[] = {
+               0x03,
+};
+
+const unsigned char d_sdad_cr[] = {
+       0x3d, 0x87, 0xf3, 0x10, 0x56, 0x10, 0x2d, 0x25, 0x12, 0xcf, 0xde, 0x30, 0x90, 0x06, 0x27, 0xc1,
+       0x26, 0x3a, 0x76, 0xd1, 0xda, 0xa8, 0x21, 0xf5, 0x08, 0x31, 0xe6, 0x06, 0xc5, 0x45, 0x44, 0xc2,
+       0x58, 0x13, 0x1e, 0xae, 0xbe, 0x87, 0x4d, 0xcb, 0x1a, 0x28, 0xcf, 0x82, 0xd3, 0xff, 0x91, 0x11,
+       0x82, 0x60, 0xbc, 0x91, 0x11, 0x37, 0x11, 0xd3, 0xb2, 0x89, 0xfa, 0x41, 0xbe, 0x69, 0xc7, 0xa7,
+       0xb5, 0xc7, 0x83, 0xe6, 0xf8, 0xf9, 0x7f, 0xce, 0x13, 0xf0, 0x8b, 0x13, 0xfa, 0x44, 0x18, 0x3e,
+       0x37, 0x18, 0xce, 0xbf, 0x0c, 0x41, 0x47, 0x3d, 0x2b, 0x0f, 0xf4, 0xde, 0x44, 0xb6, 0xa0, 0x2d,
+       0x75, 0xad, 0xb6, 0xd4, 0x96, 0x23, 0x93, 0xff, 0xdf, 0x4e, 0x69, 0x02, 0x6c, 0xdf, 0x38, 0xff,
+};
+
+const unsigned char d_ssd1[] = {
+       0x5f, 0x25, 0x03, 0x14, 0x05, 0x01, 0x5f, 0x24, 0x03, 0x15, 0x06, 0x30, 0x5a, 0x08, 0x52, 0x85,
+       0x88, 0x12, 0x54, 0x34, 0x56, 0x53, 0x5f, 0x34, 0x01, 0x01, 0x8e, 0x0c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x1e, 0x03, 0x1f, 0x03, 0x9f, 0x07, 0x02, 0xff, 0x00, 0x9f, 0x0d, 0x05,
+       0xbc, 0x50, 0xbc, 0x00, 0x00, 0x9f, 0x0e, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x0f, 0x05,
+       0xbc, 0x70, 0xbc, 0x98, 0x00, 0x9f, 0x4a, 0x01, 0x82, 0x5f, 0x28, 0x02, 0x06, 0x43, 0x8c, 0x21,
+       0x9f, 0x02, 0x06, 0x9f, 0x03, 0x06, 0x9f, 0x1a, 0x02, 0x95, 0x05, 0x5f, 0x2a, 0x02, 0x9a, 0x03,
+       0x9c, 0x01, 0x9f, 0x37, 0x04, 0x9f, 0x35, 0x01, 0x9f, 0x45, 0x02, 0x9f, 0x4c, 0x08, 0x9f, 0x34,
+       0x03, 0x8d, 0x0c, 0x91, 0x0a, 0x8a, 0x02, 0x95, 0x05, 0x9f, 0x37, 0x04, 0x9f, 0x4c, 0x08,
+       0x39, 0x00,
+};
+static const struct tlv ssd1_tlv = {
+       .len = sizeof(d_ssd1),
+       .value = d_ssd1,
+};
+
+const unsigned char d_pan[] = {
+       0x52, 0x85, 0x88, 0x12, 0x54, 0x34, 0x56, 0x53,
+};
+
+const unsigned char d_dd1[] = {
+       0x00, 0x00, 0x00, 0x00,
+};
+static const struct tlv dd1_tlv = {
+       .len = sizeof(d_dd1),
+       .value = d_dd1,
+};
+
+static int dda_test_raw(bool verbose)
+{
+       const struct emv_pk *pk = &mchip_05;
+
+       struct crypto_pk *kcp = crypto_pk_open(PK_RSA,
+                       pk->modulus, pk->mlen,
+                       pk->exp, pk->elen);
+       if (!kcp)
+               return 1;
+
+       unsigned char *ipk_data;
+       size_t ipk_data_len;
+       ipk_data = crypto_pk_encrypt(kcp, d_issuer_cert, sizeof(d_issuer_cert), &ipk_data_len);
+       crypto_pk_close(kcp);
+
+       if (!ipk_data)
+               return 1;
+
+       if (verbose) {
+               printf("issuer cert:\n");
+               dump_buffer(ipk_data, ipk_data_len, stdout, 0);
+       }
+
+       size_t ipk_pk_len = ipk_data[13];
+       unsigned char *ipk_pk = malloc(ipk_pk_len);
+       memcpy(ipk_pk, ipk_data + 15, ipk_data_len - 36);
+       memcpy(ipk_pk + ipk_data_len - 36, d_issuer_rem, sizeof(d_issuer_rem));
+
+       struct crypto_hash *ch;
+       ch = crypto_hash_open(HASH_SHA_1);
+       if (!ch) {
+               free(ipk_pk);
+               free(ipk_data);
+               return 1;
+       }
+
+       crypto_hash_write(ch, ipk_data + 1, 14);
+       crypto_hash_write(ch, ipk_pk, ipk_pk_len);
+       crypto_hash_write(ch, d_issuer_exp, sizeof(d_issuer_exp));
+
+       unsigned char *h = crypto_hash_read(ch);
+       if (!h) {
+               crypto_hash_close(ch);
+               free(ipk_pk);
+               free(ipk_data);
+               return 1;
+       }
+
+       if (verbose) {
+               printf("crypto hash:\n");
+               dump_buffer(h, 20, stdout, 0);
+       }
+
+       if (memcmp(ipk_data + ipk_data_len - 21, h, 20)) {
+               crypto_hash_close(ch);
+               free(ipk_pk);
+               free(ipk_data);
+               return 1;
+       }
+
+       crypto_hash_close(ch);
+       free(ipk_data);
+
+       struct crypto_pk *ikcp = crypto_pk_open(PK_RSA, ipk_pk, (int) ipk_pk_len,
+                       d_issuer_exp, (int) sizeof(d_issuer_exp));
+       free(ipk_pk);
+       if (!ikcp)
+               return 1;
+
+       unsigned char *iccpk_data;
+       size_t iccpk_data_len;
+       iccpk_data = crypto_pk_encrypt(ikcp, d_icc_cert, sizeof(d_icc_cert), &iccpk_data_len);
+       crypto_pk_close(ikcp);
+
+       if (!iccpk_data)
+               return 1;
+
+       if (verbose) {
+               printf("icc cert:\n");
+               dump_buffer(iccpk_data, iccpk_data_len, stdout, 0);
+       }
+
+       size_t iccpk_pk_len = iccpk_data[19];
+       unsigned char *iccpk_pk = malloc(iccpk_pk_len);
+       memcpy(iccpk_pk, iccpk_data + 21, /*iccpk_data_len - 36*/iccpk_pk_len);
+       /*memcpy(iccpk_pk + iccpk_data_len - 36, icc_rem, sizeof(icc_rem));*/
+
+       ch = crypto_hash_open(HASH_SHA_1);
+       if (!ch) {
+               free(iccpk_pk);
+               free(iccpk_data);
+               return 1;
+       }
+
+       crypto_hash_write(ch, iccpk_data + 1, iccpk_data_len - 22);
+       crypto_hash_write(ch, d_icc_exp, sizeof(d_icc_exp));
+       crypto_hash_write(ch, d_ssd1, sizeof(d_ssd1));
+
+       h = crypto_hash_read(ch);
+       if (!h) {
+               crypto_hash_close(ch);
+               free(iccpk_pk);
+               free(iccpk_data);
+               return 1;
+       }
+
+       if (verbose) {
+               printf("crypto hash1.1:\n");
+               dump_buffer(h, 20, stdout, 0);
+       }
+
+       if (memcmp(iccpk_data + iccpk_data_len - 21, h, 20)) {
+               crypto_hash_close(ch);
+               free(iccpk_pk);
+               free(iccpk_data);
+               return 1;
+       }
+
+       crypto_hash_close(ch);
+       free(iccpk_data);
+
+       struct crypto_pk *icckcp = crypto_pk_open(PK_RSA, iccpk_pk, (int) iccpk_pk_len,
+                       d_issuer_exp, (int) sizeof(d_issuer_exp));
+       free(iccpk_pk);
+       if (!icckcp)
+               return 1;
+
+       size_t sdad_len;
+       unsigned char *sdad = crypto_pk_encrypt(icckcp, d_sdad_cr, sizeof(d_sdad_cr), &sdad_len);
+       crypto_pk_close(icckcp);
+       if (!sdad)
+               return 1;
+
+       if (verbose) {
+               printf("sdad:\n");
+               dump_buffer(sdad, sdad_len, stdout, 0);
+       }
+
+       ch = crypto_hash_open(HASH_SHA_1);
+       if (!ch) {
+               free(sdad);
+               return 1;
+       }
+
+       crypto_hash_write(ch, sdad + 1, sdad_len - 22);
+       crypto_hash_write(ch, d_dd1, sizeof(d_dd1));
+
+       unsigned char *h2 = crypto_hash_read(ch);
+       if (!h2) {
+               crypto_hash_close(ch);
+               free(sdad);
+               return 1;
+       }
+
+       if (verbose) {
+               printf("crypto hash2:\n");
+               dump_buffer(h2, 20, stdout, 0);
+       }
+
+       crypto_hash_close(ch);
+
+       free(sdad);
+
+       return 0;
+}
+
+static int dda_test_pk(bool verbose)
+{
+       const struct emv_pk *pk = &mchip_05;
+       struct tlvdb *db;
+
+       db = tlvdb_external(0x90, sizeof(d_issuer_cert), d_issuer_cert);
+       tlvdb_add(db, tlvdb_external(0x9f32, sizeof(d_issuer_exp), d_issuer_exp));
+       tlvdb_add(db, tlvdb_external(0x92, sizeof(d_issuer_rem), d_issuer_rem));
+       tlvdb_add(db, tlvdb_external(0x5a, sizeof(d_pan), d_pan));
+
+       struct emv_pk *ipk = emv_pki_recover_issuer_cert(pk, db);
+       if (!ipk) {
+               fprintf(stderr, "Could not recover Issuer certificate!\n");
+               tlvdb_free(db);
+               return 2;
+       }
+
+       tlvdb_add(db, tlvdb_external(0x9f46, sizeof(d_icc_cert), d_icc_cert));
+       tlvdb_add(db, tlvdb_external(0x9f47, sizeof(d_icc_exp), d_icc_exp));
+       /*tlvdb_add(db, tlvdb_external(0x9f48, sizeof(d_issuer_rem), d_issuer_rem));*/
+
+       struct emv_pk *iccpk = emv_pki_recover_icc_cert(ipk, db, &ssd1_tlv);
+       if (!iccpk) {
+               fprintf(stderr, "Could not recover ICC certificate!\n");
+               emv_pk_free(ipk);
+               tlvdb_free(db);
+               return 2;
+       }
+
+       tlvdb_add(db, tlvdb_external(0x9f4b, sizeof(d_sdad_cr), d_sdad_cr));
+
+       struct tlvdb *idndb = emv_pki_recover_idn(iccpk, db, &dd1_tlv);
+       if (!idndb) {
+               fprintf(stderr, "Could not recover IDN!\n");
+               emv_pk_free(iccpk);
+               emv_pk_free(ipk);
+               tlvdb_free(db);
+               return 2;
+       }
+
+       const struct tlv *idn = tlvdb_get(idndb, 0x9f4c, NULL);
+       if (!idn) {
+               fprintf(stderr, "IDN not found!\n");
+               tlvdb_free(idndb);
+               emv_pk_free(iccpk);
+               emv_pk_free(ipk);
+               tlvdb_free(db);
+               return 2;
+       }
+
+       if (verbose) {
+               printf("IDN:\n");
+               dump_buffer(idn->value, idn->len, stdout, 0);
+       }
+
+       tlvdb_free(idndb);
+       emv_pk_free(iccpk);
+       emv_pk_free(ipk);
+       tlvdb_free(db);
+
+       return 0;
+}
+
+int exec_dda_test(bool verbose)
+{
+       int ret;
+       fprintf(stdout, "\n");
+
+       ret = dda_test_raw(verbose);
+       if (ret) {
+               fprintf(stderr, "DDA raw test: failed\n");
+               return ret;
+       }
+       fprintf(stdout, "DDA raw test: passed\n");
+
+       ret = dda_test_pk(verbose);
+       if (ret) {
+               fprintf(stderr, "DDA test pk: failed\n");
+               return ret;
+       }
+       fprintf(stdout, "DDA test pk: passed\n");
+
+       return 0;
+}
diff --git a/client/emv/test/dda_test.h b/client/emv/test/dda_test.h
new file mode 100644 (file)
index 0000000..354cd7e
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * emv-tools - a set of tools to work with EMV family of smart cards
+ * Copyright (C) 2012, 2015 Dmitry Eremin-Solenikov
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#include <stdbool.h> 
+extern int exec_dda_test(bool verbose);
diff --git a/client/emv/test/sda_test.c b/client/emv/test/sda_test.c
new file mode 100644 (file)
index 0000000..2aafcf1
--- /dev/null
@@ -0,0 +1,277 @@
+/*
+ * emv-tools - a set of tools to work with EMV family of smart cards
+ * Copyright (C) 2012, 2015 Dmitry Eremin-Solenikov
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "../emv_pk.h"
+#include "../crypto.h"
+#include "../dump.h"
+#include "../tlv.h"
+#include "../emv_pki.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+struct emv_pk vsdc_01 = {
+       .rid = { 0xa0, 0x00, 0x00, 0x00, 0x03, },
+       .index = 1,
+       .hash_algo = HASH_SHA_1,
+       .pk_algo = PK_RSA,
+       .hash = {
+               0xd3, 0x4a, 0x6a, 0x77,
+               0x60, 0x11, 0xc7, 0xe7,
+               0xce, 0x3a, 0xec, 0x5f,
+               0x03, 0xad, 0x2f, 0x8c,
+               0xfc, 0x55, 0x03, 0xcc, },
+       .exp = { 0x03, },
+       .elen = 1,
+       .mlen = 1024 / 8,
+       .modulus = (unsigned char[]){
+               0xc6, 0x96, 0x03, 0x42, 0x13, 0xd7, 0xd8, 0x54, 0x69, 0x84, 0x57, 0x9d, 0x1d, 0x0f, 0x0e, 0xa5,
+               0x19, 0xcf, 0xf8, 0xde, 0xff, 0xc4, 0x29, 0x35, 0x4c, 0xf3, 0xa8, 0x71, 0xa6, 0xf7, 0x18, 0x3f,
+               0x12, 0x28, 0xda, 0x5c, 0x74, 0x70, 0xc0, 0x55, 0x38, 0x71, 0x00, 0xcb, 0x93, 0x5a, 0x71, 0x2c,
+               0x4e, 0x28, 0x64, 0xdf, 0x5d, 0x64, 0xba, 0x93, 0xfe, 0x7e, 0x63, 0xe7, 0x1f, 0x25, 0xb1, 0xe5,
+               0xf5, 0x29, 0x85, 0x75, 0xeb, 0xe1, 0xc6, 0x3a, 0xa6, 0x17, 0x70, 0x69, 0x17, 0x91, 0x1d, 0xc2,
+               0xa7, 0x5a, 0xc2, 0x8b, 0x25, 0x1c, 0x7e, 0xf4, 0x0f, 0x23, 0x65, 0x91, 0x24, 0x90, 0xb9, 0x39,
+               0xbc, 0xa2, 0x12, 0x4a, 0x30, 0xa2, 0x8f, 0x54, 0x40, 0x2c, 0x34, 0xae, 0xca, 0x33, 0x1a, 0xb6,
+               0x7e, 0x1e, 0x79, 0xb2, 0x85, 0xdd, 0x57, 0x71, 0xb5, 0xd9, 0xff, 0x79, 0xea, 0x63, 0x0b, 0x75,
+       },
+};
+
+const unsigned char issuer_cert[] = {
+               0x3c, 0x5f, 0xea, 0xd4, 0xdd, 0x7b, 0xca, 0x44, 0xf9, 0x3e, 0x90, 0xc4, 0x4f, 0x76, 0xed, 0xe5,
+               0x4a, 0x32, 0x88, 0xec, 0xdc, 0x78, 0x46, 0x9f, 0xcb, 0x12, 0x25, 0xc0, 0x3b, 0x2c, 0x04, 0xf2,
+               0xc2, 0xf4, 0x12, 0x28, 0x1a, 0x08, 0x22, 0xdf, 0x14, 0x64, 0x92, 0x30, 0x98, 0x9f, 0xb1, 0x49,
+               0x40, 0x70, 0xda, 0xf8, 0xc9, 0x53, 0x4a, 0x78, 0x81, 0x96, 0x01, 0x48, 0x61, 0x6a, 0xce, 0x58,
+               0x17, 0x88, 0x12, 0x0d, 0x35, 0x06, 0xac, 0xe4, 0xce, 0xe5, 0x64, 0xfb, 0x27, 0xee, 0x53, 0x34,
+               0x1c, 0x22, 0xf0, 0xb4, 0x5b, 0x31, 0x87, 0x3d, 0x05, 0xde, 0x54, 0x5e, 0xfe, 0x33, 0xbc, 0xd2,
+               0x9b, 0x21, 0x85, 0xd0, 0x35, 0xa8, 0x06, 0xad, 0x08, 0xc6, 0x97, 0x6f, 0x35, 0x05, 0xa1, 0x99,
+               0x99, 0x93, 0x0c, 0xa8, 0xa0, 0x3e, 0xfa, 0x32, 0x1c, 0x48, 0x60, 0x61, 0xf7, 0xdc, 0xec, 0x9f,
+};
+
+const unsigned char issuer_rem[] = {
+               0x1e, 0xbc, 0xa3, 0x0f, 0x00, 0xce, 0x59, 0x62, 0xa8, 0xc6, 0xe1, 0x30, 0x54, 0x4b, 0x82, 0x89,
+               0x1b, 0x23, 0x6c, 0x65, 0xde, 0x29, 0x31, 0x7f, 0x36, 0x47, 0x35, 0xde, 0xe6, 0x3f, 0x65, 0x98,
+               0x97, 0x58, 0x35, 0xd5
+};
+
+const unsigned char issuer_exp[] = {
+               0x03,
+};
+
+const unsigned char ssad_cr[] = {
+               0x99, 0xa5, 0x58, 0xb6, 0x2b, 0x67, 0x4a, 0xa5, 0xe7, 0xd2, 0xa5, 0x7e, 0x5e, 0xf6, 0xa6, 0xf2,
+               0x25, 0x8e, 0x5d, 0xa0, 0x52, 0xd0, 0x5b, 0x54, 0xe5, 0xc1, 0x15, 0xff, 0x1c, 0xec, 0xf9, 0x4a,
+               0xa2, 0xdf, 0x8f, 0x39, 0xa0, 0x1d, 0x71, 0xc6, 0x19, 0xeb, 0x81, 0x9d, 0xa5, 0x2e, 0xf3, 0x81,
+               0xe8, 0x49, 0x79, 0x58, 0x6a, 0xea, 0x78, 0x55, 0xff, 0xbe, 0xf4, 0x0a, 0xa3, 0xa7, 0x1c, 0xd3,
+               0xb0, 0x4c, 0xfd, 0xf2, 0x70, 0xae, 0xc8, 0x15, 0x8a, 0x27, 0x97, 0xf2, 0x4f, 0xd6, 0x13, 0xb7,
+               0x48, 0x13, 0x46, 0x61, 0x13, 0x5c, 0xd2, 0x90, 0xe4, 0x5b, 0x04, 0xa8, 0xe0, 0xcc, 0xc7, 0x11,
+               0xae, 0x04, 0x2f, 0x15, 0x9e, 0x73, 0xc8, 0x9c, 0x2a, 0x7e, 0x65, 0xa4, 0xc2, 0xfd, 0x1d, 0x61,
+               0x06, 0x02, 0x4a, 0xa2, 0x71, 0x30, 0xb0, 0xec, 0xec, 0x02, 0x38, 0xf9, 0x16, 0x59, 0xde, 0x96,
+};
+
+const unsigned char ssd1[] = {
+       0x5f, 0x24, 0x03, 0x08, 0x12, 0x31, 0x5a, 0x08, 0x42, 0x76, 0x55, 0x00, 0x13, 0x23, 0x45, 0x99, 0x5f, 0x34, 0x01, 0x01, 0x9f, 0x07, 0x02, 0xff, 0x00, 0x9f, 0x0d, 0x05, 0xd0, 0x40, 0xac, 0xa8, 0x00, 0x9f, 0x0e, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00, 0x9f, 0x0f, 0x05, 0xd0, 0x68, 0xbc, 0xf8, 0x00,
+       0x5c, 0x00,
+};
+static const struct tlv ssd1_tlv = {
+       .len = sizeof(ssd1),
+       .value = ssd1,
+};
+
+const unsigned char pan[] = {
+       0x42, 0x76, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static int sda_test_raw(bool verbose)
+{
+       const struct emv_pk *pk = &vsdc_01;
+
+       struct crypto_pk *kcp = crypto_pk_open(PK_RSA,
+                       pk->modulus, pk->mlen,
+                       pk->exp, pk->elen);
+       if (!kcp)
+               return 1;
+
+       unsigned char *ipk_data;
+       size_t ipk_data_len;
+       ipk_data = crypto_pk_encrypt(kcp, issuer_cert, sizeof(issuer_cert), &ipk_data_len);
+       crypto_pk_close(kcp);
+
+       if (!ipk_data)
+               return 1;
+
+       if (verbose) {
+               printf("issuer cert:\n");
+               dump_buffer(ipk_data, ipk_data_len, stdout, 0);
+       }
+
+       size_t ipk_pk_len = ipk_data[13];
+       unsigned char *ipk_pk = malloc(ipk_pk_len);
+       memcpy(ipk_pk, ipk_data + 15, ipk_data_len - 36);
+       memcpy(ipk_pk + ipk_data_len - 36, issuer_rem, sizeof(issuer_rem));
+
+       struct crypto_hash *ch;
+       ch = crypto_hash_open(HASH_SHA_1);
+       if (!ch) {
+               free(ipk_pk);
+               free(ipk_data);
+               return 1;
+       }
+
+       crypto_hash_write(ch, ipk_data + 1, 14);
+       crypto_hash_write(ch, ipk_pk, ipk_pk_len);
+       crypto_hash_write(ch, issuer_exp, sizeof(issuer_exp));
+
+       unsigned char *h = crypto_hash_read(ch);
+       if (!h) {
+               crypto_hash_close(ch);
+               free(ipk_pk);
+               free(ipk_data);
+               return 1;
+       }
+
+       if (verbose) {
+               printf("crypto hash:\n");
+               dump_buffer(h, 20, stdout, 0);
+       }
+
+       if (memcmp(ipk_data + ipk_data_len - 21, h, 20)) {
+               crypto_hash_close(ch);
+               free(ipk_pk);
+               free(ipk_data);
+               return 1;
+       }
+
+       crypto_hash_close(ch);
+       free(ipk_data);
+
+       struct crypto_pk *ikcp = crypto_pk_open(PK_RSA, ipk_pk, (int) ipk_pk_len,
+                       issuer_exp, (int) sizeof(issuer_exp));
+       free(ipk_pk);
+       if (!ikcp)
+               return 1;
+
+       size_t ssad_len;
+       unsigned char *ssad = crypto_pk_encrypt(ikcp, ssad_cr, sizeof(ssad_cr), &ssad_len);
+       crypto_pk_close(ikcp);
+       if (!ssad)
+               return 1;
+
+       if (verbose) {
+               printf("ssad:\n");
+               dump_buffer(ssad, ssad_len, stdout, 0);
+       }
+
+       ch = crypto_hash_open(HASH_SHA_1);
+       if (!ch) {
+               free(ssad);
+               return 1;
+       }
+
+       crypto_hash_write(ch, ssad + 1, ssad_len - 22);
+       crypto_hash_write(ch, ssd1, sizeof(ssd1));
+
+       unsigned char *h2 = crypto_hash_read(ch);
+       if (!h2) {
+               crypto_hash_close(ch);
+               free(ssad);
+               return 1;
+       }
+
+       if (verbose) {
+               printf("crypto hash2:\n");
+               dump_buffer(h2, 20, stdout, 0);
+       }
+
+       crypto_hash_close(ch);
+
+       free(ssad);
+
+       return 0;
+}
+
+static int sda_test_pk(bool verbose)
+{
+       const struct emv_pk *pk = &vsdc_01;
+       struct tlvdb *db;
+
+       db = tlvdb_external(0x90, sizeof(issuer_cert), issuer_cert);
+       tlvdb_add(db, tlvdb_external(0x9f32, sizeof(issuer_exp), issuer_exp));
+       tlvdb_add(db, tlvdb_external(0x92, sizeof(issuer_rem), issuer_rem));
+       tlvdb_add(db, tlvdb_external(0x5a, sizeof(pan), pan));
+
+       struct emv_pk *ipk = emv_pki_recover_issuer_cert(pk, db);
+       if (!ipk) {
+               fprintf(stderr, "Could not recover Issuer certificate!\n");
+               tlvdb_free(db);
+               return 2;
+       }
+
+       tlvdb_add(db, tlvdb_external(0x93, sizeof(ssad_cr), ssad_cr));
+
+       struct tlvdb *dacdb = emv_pki_recover_dac(ipk, db, &ssd1_tlv);
+       if (!dacdb) {
+               fprintf(stderr, "Could not recover DAC!\n");
+               emv_pk_free(ipk);
+               tlvdb_free(db);
+               return 2;
+       }
+
+       const struct tlv *dac = tlvdb_get(dacdb, 0x9f45, NULL);
+       if (!dac) {
+               fprintf(stderr, "DAC not found!\n");
+               tlvdb_free(dacdb);
+               emv_pk_free(ipk);
+               tlvdb_free(db);
+               return 2;
+       }
+
+       if (verbose) {
+               printf("dac:\n");
+               dump_buffer(dac->value, dac->len, stdout, 0);
+       }
+
+       tlvdb_free(dacdb);
+       emv_pk_free(ipk);
+       tlvdb_free(db);
+
+       return 0;
+}
+
+int exec_sda_test(bool verbose)
+{
+       int ret;
+       fprintf(stdout, "\n");
+
+       ret = sda_test_raw(verbose);
+       if (ret) {
+               fprintf(stderr, "SDA raw test: failed\n");
+               return ret;
+       }
+       fprintf(stdout, "SDA raw test: passed\n");
+
+       ret = sda_test_pk(verbose);
+       if (ret) {
+               fprintf(stderr, "SDA test pk: failed\n");
+               return ret;
+       }
+       fprintf(stdout, "SDA test pk: passed\n");
+
+       return 0;
+}
diff --git a/client/emv/test/sda_test.h b/client/emv/test/sda_test.h
new file mode 100644 (file)
index 0000000..43a4c94
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * emv-tools - a set of tools to work with EMV family of smart cards
+ * Copyright (C) 2012, 2015 Dmitry Eremin-Solenikov
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+extern int exec_sda_test(bool verbose);
index 57bc831fe1f97dda82c3c8fa9a940f77721ec0ea..3b146b109b520fc05eec44c4d06aaffdfdee2205 100644 (file)
@@ -22,7 +22,7 @@
  *
  * This is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
+ * by the Free Software Foundation, or, at your option, any later version. 
  *
  * This file is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -33,7 +33,6 @@
  * along with loclass.  If not, see <http://www.gnu.org/licenses/>.
  * 
  * 
- * 
  ****************************************************************************/
 
 
index 7afdb524cc4393273b5bd3e1af1c84c05f246bee..632910a98f55594aafcb289a81e8334bcfdcb551 100644 (file)
@@ -22,7 +22,7 @@
  *
  * This is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
+ * by the Free Software Foundation, or, at your option, any later version. 
  *
  * This file is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -33,7 +33,6 @@
  * along with loclass.  If not, see <http://www.gnu.org/licenses/>.
  * 
  * 
- * 
  ****************************************************************************/
 
 
index 9a8256bb38a700990fe6bddf4701116cdbaeac40..b5e365bf45780c34e1911f185080ba85d6b08739 100644 (file)
@@ -22,7 +22,7 @@
  *
  * This is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
+ * by the Free Software Foundation, or, at your option, any later version. 
  *
  * This file is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -33,7 +33,6 @@
  * along with loclass.  If not, see <http://www.gnu.org/licenses/>.
  * 
  * 
- * 
  ****************************************************************************/
 
 #include <stdint.h>
index 3cdbf5fa71305e4c7ebdb363ed01de1a637e8c47..568671791c9fff3eadc1560cdf6b95a4830c42e0 100644 (file)
@@ -22,7 +22,7 @@
  *
  * This is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
+ * by the Free Software Foundation, or, at your option, any later version. 
  *
  * This file is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -33,7 +33,6 @@
  * along with loclass.  If not, see <http://www.gnu.org/licenses/>.
  * 
  * 
- * 
  ****************************************************************************/
 
 
index 777efe08b95839a953675164c1ea89caf750550a..fe9bf7d1342ef0fb453a99c8548172e7a1dcdb66 100644 (file)
@@ -22,7 +22,7 @@
  *
  * This is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
+ * by the Free Software Foundation, or, at your option, any later version. 
  *
  * This file is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -33,7 +33,6 @@
  * along with loclass.  If not, see <http://www.gnu.org/licenses/>.
  * 
  * 
- * 
  ****************************************************************************/
 
 #include <stdint.h>
index fb27355fd7a1f5dbe6e4cf63e825ca3590f64469..46791fb5d302ecfb1a39ca49117e499a2ce6f746 100644 (file)
@@ -22,7 +22,7 @@
  *
  * This is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
+ * by the Free Software Foundation, or, at your option, any later version. 
  *
  * This file is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -33,7 +33,6 @@
  * along with loclass.  If not, see <http://www.gnu.org/licenses/>.
  * 
  * 
- * 
  ****************************************************************************/
 
 
index e5e5c5b0569270c422c53e83078d738a64f9e106..90857e7aaf96de7776a7f3ad7bd5c67b26696776 100644 (file)
@@ -22,7 +22,7 @@
  *
  * This is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
+ * by the Free Software Foundation, or, at your option, any later version. 
  *
  * This file is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -33,7 +33,6 @@
  * along with loclass.  If not, see <http://www.gnu.org/licenses/>.
  * 
  * 
- * 
  ****************************************************************************/
 #ifndef ON_DEVICE
 
index 10720f76d1e50b903d1acc0469a5d3af14f9bb0e..79dbe5660568f13a61a5b0f3f4d3b7114da46955 100644 (file)
@@ -22,7 +22,7 @@
  *
  * This is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
+ * by the Free Software Foundation, or, at your option, any later version. 
  *
  * This file is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -33,7 +33,6 @@
  * along with loclass.  If not, see <http://www.gnu.org/licenses/>.
  * 
  * 
- * 
  ****************************************************************************/
 
 #ifndef FILEUTILS_H
index 8892b4a35296d7b2aa2000a921eca5bd04a64e2d..2a6a00109297c72afe47de08426814f37a510f7e 100644 (file)
@@ -22,7 +22,7 @@
  *
  * This is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
+ * by the Free Software Foundation, or, at your option, any later version. 
  *
  * This file is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -33,7 +33,6 @@
  * along with loclass.  If not, see <http://www.gnu.org/licenses/>.
  * 
  * 
- * 
  ****************************************************************************/
 
 /**
@@ -740,18 +739,16 @@ int readKeyFile(uint8_t key[8])
        FILE *f;
        int retval = 1;
        f = fopen("iclass_key.bin", "rb");
-       if (f)
-       {
-               if(fread(key, sizeof(uint8_t), 8, f) == 1) 
-               {
-                       retval = 0;     
-               }
-               fclose(f);
+       if (!f)
+               return retval;
+       
+       if (fread(key, sizeof(uint8_t), 8, f) == 8) {
+               retval = 0;
        }
+       fclose(f);      
        return retval;
 }
 
-
 int doKeyTests(uint8_t debuglevel)
 {
        debug_print = debuglevel;
index 13096194d46b6bbbbc7e06108d434f0aea7da691..5b44d1796a7cd6f044bc074731360edd6053351e 100644 (file)
@@ -22,7 +22,7 @@
  *
  * This is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
+ * by the Free Software Foundation, or, at your option, any later version. 
  *
  * This file is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -33,7 +33,6 @@
  * along with loclass.  If not, see <http://www.gnu.org/licenses/>.
  * 
  * 
- * 
  ****************************************************************************/
 
 #ifndef IKEYS_H
index 95112f7decafe7a79f05c2651d7dd9b2aa848216..fa9886ee9e9251bd685bba25439db60d0d2346e9 100644 (file)
@@ -22,7 +22,7 @@
  *
  * This is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
+ * by the Free Software Foundation, or, at your option, any later version. 
  *
  * This file is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -33,7 +33,6 @@
  * along with loclass.  If not, see <http://www.gnu.org/licenses/>.
  * 
  * 
- * 
  ****************************************************************************/
 
 
diff --git a/client/obj/emv/test/.dummy b/client/obj/emv/test/.dummy
new file mode 100644 (file)
index 0000000..e69de29
index ed46c8e805d76debb2c247a700c9d381878a0d13..cffbca6cd3995f18dae85b5ec1be5236bd8086a2 100644 (file)
@@ -306,7 +306,7 @@ static int l_pack(lua_State *L)             /** pack(f,...) */
         sbyte = 0;
         odd = 0;
       }
-    } else if (isspace(a[ii])) {
+    } else if (isspace((unsigned char)a[ii])) {
       /* ignore */
     } else {
       /* err ... ignore too*/
index 2d45b2fe1f9b29ebaf779bd1a532f504df4a628b..5a9b6580449dd20a7343f1e1e1c3e52ee4e28996 100644 (file)
@@ -596,7 +596,7 @@ mbynam(model_t *dest, const char *key) {
                uerror("cannot allocate memory for comparison string");
        akey.name = uptr = ukey;
        do
-               *uptr++ = toupper(*key);
+               *uptr++ = toupper((unsigned char)*key);
        while(*key++);
 
        aptr = bsearch(&akey, aliases, NALIASES, sizeof(struct malias), (int (*)(const void *, const void *)) &acmp);
index 13cb8cdfcb1c998fdb09a773c8904a8262e4f74a..3859fd4863ce35fbc4942c5e326568a651ce403c 100644 (file)
@@ -23,8 +23,8 @@
 #include "iso14443crc.h"
 #include "../common/crc16.h"
 #include "../common/crc64.h"
-#include "../common/sha1.h"
-#include "polarssl/aes.h"
+#include "../common/polarssl/sha1.h"
+#include "../common/polarssl/aes.h"
 #include "cmdcrc.h"
 /**
  * The following params expected:
index df2c3ce3c6a6909cb99317f34770853c40992f13..8faed6e86cae50f34849dcd4b53b8337cfb03528 100644 (file)
@@ -9,12 +9,14 @@
 // UI utilities
 //-----------------------------------------------------------------------------
 
-#include <stdarg.h>
+#include <stdbool.h>
+#ifndef EXTERNAL_PRINTANDLOG
 #include <stdlib.h>
 #include <stdio.h>
-#include <stdbool.h>
+#include <stdarg.h>
 #include <readline/readline.h>
 #include <pthread.h>
+#endif
 
 #include "ui.h"
 
@@ -26,10 +28,12 @@ int GridOffset = 0;
 bool GridLocked = false;
 bool showDemod = true;
 
-extern pthread_mutex_t print_lock;
-
 static char *logfilename = "proxmark3.log";
 
+#ifndef EXTERNAL_PRINTANDLOG
+// Declared in proxmark3.c
+extern pthread_mutex_t print_lock;
+
 void PrintAndLog(char *fmt, ...)
 {
        char *saved_line;
@@ -94,7 +98,7 @@ void PrintAndLog(char *fmt, ...)
        //release lock
        pthread_mutex_unlock(&print_lock);  
 }
-
+#endif
 
 void SetLogFilename(char *fn)
 {
index 92b0e7a6ab22dadd8160252f6364734b8c7a870d..7e6b40742c1a7fa2ecb596481e30dae8f9e290ac 100644 (file)
@@ -111,6 +111,31 @@ void FillFileNameByUID(char *fileName, uint8_t * uid, char *ext, int byteCount)
        sprintf(fnameptr, "%s", ext); 
 }
 
+void hex_to_buffer(const uint8_t *buf, const uint8_t *hex_data, const size_t hex_len, const size_t hex_max_len, 
+       const size_t min_str_len, const size_t spaces_between, bool uppercase) {
+               
+       char *tmp = (char *)buf;
+       size_t i;
+
+       int maxLen = ( hex_len > hex_max_len) ? hex_max_len : hex_len;
+
+       for (i = 0; i < maxLen; ++i, tmp += 2 + spaces_between) {
+               sprintf(tmp, (uppercase) ? "%02X" : "%02x", (unsigned int) hex_data[i]); 
+               
+               for (int j = 0; j < spaces_between; j++)
+                       sprintf(tmp + 2 + j, " ");
+       }
+       
+       i *= (2 + spaces_between);
+       int minStrLen = min_str_len > i ? min_str_len : 0;
+       if (minStrLen > hex_max_len)
+               minStrLen = hex_max_len;
+       for(; i < minStrLen; i++, tmp += 1) 
+               sprintf(tmp, " ");
+
+       return;
+}
+
 // printing and converting functions
 
 void print_hex(const uint8_t * data, const size_t len)
@@ -141,33 +166,17 @@ void print_hex_break(const uint8_t *data, const size_t len, uint8_t breaks) {
 }
 
 char *sprint_hex(const uint8_t *data, const size_t len) {
+       static char buf[1025] = {0};
        
-       int maxLen = ( len > 1024/3) ? 1024/3 : len;
-       static char buf[1024];
-       memset(buf, 0x00, 1024);
-       char *tmp = buf;
-       size_t i;
-
-       for (i=0; i < maxLen; ++i, tmp += 3)
-               sprintf(tmp, "%02x ", (unsigned int) data[i]);
+       hex_to_buffer((uint8_t *)buf, data, len, sizeof(buf) - 1, 0, 1, false);
 
        return buf;
 }
 
 char *sprint_hex_inrow_ex(const uint8_t *data, const size_t len, const size_t min_str_len) {
-       
-       int maxLen = ( len > 1024/2) ? 1024/2 : len;
-       static char buf[1024] = {0};
-       char *tmp = buf;
-       size_t i;
+       static char buf[1025] = {0};
 
-       for (i = 0; i < maxLen; ++i, tmp += 2)
-               sprintf(tmp, "%02x", (unsigned int) data[i]);
-       
-       i *= 2;
-       int minStrLen = min_str_len > i ? min_str_len : 0;
-       for(; i < minStrLen; i++, tmp += 1) 
-               sprintf(tmp, " ");
+       hex_to_buffer((uint8_t *)buf, data, len, sizeof(buf) - 1, min_str_len, 0, false);
 
        return buf;
 }
@@ -487,7 +496,7 @@ int param_gethex(const char *line, int paramnum, uint8_t * data, int hexcnt)
                return 1;
 
        for(i = 0; i < hexcnt; i += 2) {
-               if (!(isxdigit(line[bg + i]) && isxdigit(line[bg + i + 1])) )   return 1;
+               if (!(isxdigit((unsigned char)line[bg + i]) && isxdigit((unsigned char)line[bg + i + 1])) )     return 1;
                
                sscanf((char[]){line[bg + i], line[bg + i + 1], 0}, "%X", &temp);
                data[i / 2] = temp & 0xff;
@@ -509,7 +518,7 @@ int param_gethex_ex(const char *line, int paramnum, uint8_t * data, int *hexcnt)
                return 1;
 
        for(i = 0; i < *hexcnt; i += 2) {
-               if (!(isxdigit(line[bg + i]) && isxdigit(line[bg + i + 1])) )   return 1;
+               if (!(isxdigit((unsigned char)line[bg + i]) && isxdigit((unsigned char)line[bg + i + 1])) )     return 1;
                
                sscanf((char[]){line[bg + i], line[bg + i + 1], 0}, "%X", &temp);
                data[i / 2] = temp & 0xff;
@@ -534,7 +543,7 @@ int param_gethex_to_eol(const char *line, int paramnum, uint8_t * data, int maxd
                        continue;
                }
                
-               if (isxdigit(line[indx])) {
+               if (isxdigit((unsigned char)line[indx])) {
                        buf[strlen(buf) + 1] = 0x00;
                        buf[strlen(buf)] = line[indx];
                } else {
@@ -611,7 +620,7 @@ int hextobinarray(char *target, char *source)
         else if (x >= 'A' && x <= 'F')
             x -= 'A' - 10;
         else {
-               printf("Discovered unknown character %c %d at idx %d of %s\n", x, x, source - start, start);
+               printf("Discovered unknown character %c %d at idx %tu of %s\n", x, x, source - start, start);
             return 0;
         }
         // output
index e9c48b0353bbc27e3c7f0cccaf38fd81f7d9228d..fd7ceafffb6de7685328405fa479cc2163810c16 100644 (file)
@@ -12,6 +12,7 @@
 #define UTIL_H__
 
 #include <stdint.h>
+#include <stdbool.h>
 #include <stddef.h>
 
 #ifndef ROTR
@@ -35,6 +36,9 @@ extern void AddLogUint64(char *fileName, char *extData, const uint64_t data);
 extern void AddLogCurrentDT(char *fileName);
 extern void FillFileNameByUID(char *fileName, uint8_t * uid, char *ext, int byteCount);
 
+extern void hex_to_buffer(const uint8_t *buf, const uint8_t *hex_data, const size_t hex_len, 
+       const size_t hex_max_len, const size_t min_str_len, const size_t spaces_between, bool uppercase);
+
 extern void print_hex(const uint8_t * data, const size_t len);
 extern char *sprint_hex(const uint8_t * data, const size_t len);
 extern char *sprint_hex_inrow(const uint8_t *data, const size_t len);
index 946bd87d92c0fb43e0290540892a5354c79fcaea..299cb4cdfe3d02b89641eceea2404e78e22e8585 100644 (file)
@@ -125,7 +125,6 @@ int aes_crypt_ecb( aes_context *ctx,
                     int mode,
                     const unsigned char input[16],
                     unsigned char output[16] );
-
 #if defined(POLARSSL_CIPHER_MODE_CBC)
 /**
  * \brief          AES-CBC buffer encryption/decryption
diff --git a/common/polarssl/bignum.c b/common/polarssl/bignum.c
new file mode 100644 (file)
index 0000000..d22dd5c
--- /dev/null
@@ -0,0 +1,2143 @@
+/*
+ *  Multi-precision integer library
+ *
+ *  Copyright (C) 2006-2010, Brainspark B.V.
+ *
+ *  This file is part of PolarSSL (http://www.polarssl.org)
+ *  Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
+ *
+ *  All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+/*
+ *  This MPI implementation is based on:
+ *
+ *  http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf
+ *  http://www.stillhq.com/extracted/gnupg-api/mpi/
+ *  http://math.libtomcrypt.com/files/tommath.pdf
+ */
+
+#include "polarssl_config.h"
+
+#if defined(POLARSSL_BIGNUM_C)
+
+#include "bignum.h"
+#include "bn_mul.h"
+
+#include <stdlib.h>
+
+#define ciL    (sizeof(t_uint))         /* chars in limb  */
+#define biL    (ciL << 3)               /* bits  in limb  */
+#define biH    (ciL << 2)               /* half limb size */
+
+/*
+ * Convert between bits/chars and number of limbs
+ */
+#define BITS_TO_LIMBS(i)  (((i) + biL - 1) / biL)
+#define CHARS_TO_LIMBS(i) (((i) + ciL - 1) / ciL)
+
+/*
+ * Initialize one MPI
+ */
+void mpi_init( mpi *X )
+{
+    if( X == NULL )
+        return;
+
+    X->s = 1;
+    X->n = 0;
+    X->p = NULL;
+}
+
+/*
+ * Unallocate one MPI
+ */
+void mpi_free( mpi *X )
+{
+    if( X == NULL )
+        return;
+
+    if( X->p != NULL )
+    {
+        memset( X->p, 0, X->n * ciL );
+        free( X->p );
+    }
+
+    X->s = 1;
+    X->n = 0;
+    X->p = NULL;
+}
+
+/*
+ * Enlarge to the specified number of limbs
+ */
+int mpi_grow( mpi *X, size_t nblimbs )
+{
+    t_uint *p;
+
+    if( nblimbs > POLARSSL_MPI_MAX_LIMBS )
+        return( POLARSSL_ERR_MPI_MALLOC_FAILED );
+
+    if( X->n < nblimbs )
+    {
+        if( ( p = (t_uint *) malloc( nblimbs * ciL ) ) == NULL )
+            return( POLARSSL_ERR_MPI_MALLOC_FAILED );
+
+        memset( p, 0, nblimbs * ciL );
+
+        if( X->p != NULL )
+        {
+            memcpy( p, X->p, X->n * ciL );
+            memset( X->p, 0, X->n * ciL );
+            free( X->p );
+        }
+
+        X->n = nblimbs;
+        X->p = p;
+    }
+
+    return( 0 );
+}
+
+/*
+ * Copy the contents of Y into X
+ */
+int mpi_copy( mpi *X, const mpi *Y )
+{
+    int ret;
+    size_t i;
+
+    if( X == Y )
+        return( 0 );
+
+    for( i = Y->n - 1; i > 0; i-- )
+        if( Y->p[i] != 0 )
+            break;
+    i++;
+
+    X->s = Y->s;
+
+    MPI_CHK( mpi_grow( X, i ) );
+
+    memset( X->p, 0, X->n * ciL );
+    memcpy( X->p, Y->p, i * ciL );
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Swap the contents of X and Y
+ */
+void mpi_swap( mpi *X, mpi *Y )
+{
+    mpi T;
+
+    memcpy( &T,  X, sizeof( mpi ) );
+    memcpy(  X,  Y, sizeof( mpi ) );
+    memcpy(  Y, &T, sizeof( mpi ) );
+}
+
+/*
+ * Set value from integer
+ */
+int mpi_lset( mpi *X, t_sint z )
+{
+    int ret;
+
+    MPI_CHK( mpi_grow( X, 1 ) );
+    memset( X->p, 0, X->n * ciL );
+
+    X->p[0] = ( z < 0 ) ? -z : z;
+    X->s    = ( z < 0 ) ? -1 : 1;
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Get a specific bit
+ */
+int mpi_get_bit( const mpi *X, size_t pos )
+{
+    if( X->n * biL <= pos )
+        return( 0 );
+
+    return ( X->p[pos / biL] >> ( pos % biL ) ) & 0x01;
+}
+
+/*
+ * Set a bit to a specific value of 0 or 1
+ */
+int mpi_set_bit( mpi *X, size_t pos, unsigned char val )
+{
+    int ret = 0;
+    size_t off = pos / biL;
+    size_t idx = pos % biL;
+
+    if( val != 0 && val != 1 )
+        return POLARSSL_ERR_MPI_BAD_INPUT_DATA;
+        
+    if( X->n * biL <= pos )
+    {
+        if( val == 0 )
+            return ( 0 );
+
+        MPI_CHK( mpi_grow( X, off + 1 ) );
+    }
+
+    X->p[off] = ( X->p[off] & ~( 0x01 << idx ) ) | ( val << idx );
+
+cleanup:
+    
+    return( ret );
+}
+
+/*
+ * Return the number of least significant bits
+ */
+size_t mpi_lsb( const mpi *X )
+{
+    size_t i, j, count = 0;
+
+    for( i = 0; i < X->n; i++ )
+        for( j = 0; j < biL; j++, count++ )
+            if( ( ( X->p[i] >> j ) & 1 ) != 0 )
+                return( count );
+
+    return( 0 );
+}
+
+/*
+ * Return the number of most significant bits
+ */
+size_t mpi_msb( const mpi *X )
+{
+    size_t i, j;
+
+    for( i = X->n - 1; i > 0; i-- )
+        if( X->p[i] != 0 )
+            break;
+
+    for( j = biL; j > 0; j-- )
+        if( ( ( X->p[i] >> ( j - 1 ) ) & 1 ) != 0 )
+            break;
+
+    return( ( i * biL ) + j );
+}
+
+/*
+ * Return the total size in bytes
+ */
+size_t mpi_size( const mpi *X )
+{
+    return( ( mpi_msb( X ) + 7 ) >> 3 );
+}
+
+/*
+ * Convert an ASCII character to digit value
+ */
+static int mpi_get_digit( t_uint *d, int radix, char c )
+{
+    *d = 255;
+
+    if( c >= 0x30 && c <= 0x39 ) *d = c - 0x30;
+    if( c >= 0x41 && c <= 0x46 ) *d = c - 0x37;
+    if( c >= 0x61 && c <= 0x66 ) *d = c - 0x57;
+
+    if( *d >= (t_uint) radix )
+        return( POLARSSL_ERR_MPI_INVALID_CHARACTER );
+
+    return( 0 );
+}
+
+/*
+ * Import from an ASCII string
+ */
+int mpi_read_string( mpi *X, int radix, const char *s )
+{
+    int ret;
+    size_t i, j, slen, n;
+    t_uint d;
+    mpi T;
+
+    if( radix < 2 || radix > 16 )
+        return( POLARSSL_ERR_MPI_BAD_INPUT_DATA );
+
+    mpi_init( &T );
+
+    slen = strlen( s );
+
+    if( radix == 16 )
+    {
+        n = BITS_TO_LIMBS( slen << 2 );
+
+        MPI_CHK( mpi_grow( X, n ) );
+        MPI_CHK( mpi_lset( X, 0 ) );
+
+        for( i = slen, j = 0; i > 0; i--, j++ )
+        {
+            if( i == 1 && s[i - 1] == '-' )
+            {
+                X->s = -1;
+                break;
+            }
+
+            MPI_CHK( mpi_get_digit( &d, radix, s[i - 1] ) );
+            X->p[j / (2 * ciL)] |= d << ( (j % (2 * ciL)) << 2 );
+        }
+    }
+    else
+    {
+        MPI_CHK( mpi_lset( X, 0 ) );
+
+        for( i = 0; i < slen; i++ )
+        {
+            if( i == 0 && s[i] == '-' )
+            {
+                X->s = -1;
+                continue;
+            }
+
+            MPI_CHK( mpi_get_digit( &d, radix, s[i] ) );
+            MPI_CHK( mpi_mul_int( &T, X, radix ) );
+
+            if( X->s == 1 )
+            {
+                MPI_CHK( mpi_add_int( X, &T, d ) );
+            }
+            else
+            {
+                MPI_CHK( mpi_sub_int( X, &T, d ) );
+            }
+        }
+    }
+
+cleanup:
+
+    mpi_free( &T );
+
+    return( ret );
+}
+
+/*
+ * Helper to write the digits high-order first
+ */
+static int mpi_write_hlp( mpi *X, int radix, char **p )
+{
+    int ret;
+    t_uint r;
+
+    if( radix < 2 || radix > 16 )
+        return( POLARSSL_ERR_MPI_BAD_INPUT_DATA );
+
+    MPI_CHK( mpi_mod_int( &r, X, radix ) );
+    MPI_CHK( mpi_div_int( X, NULL, X, radix ) );
+
+    if( mpi_cmp_int( X, 0 ) != 0 )
+        MPI_CHK( mpi_write_hlp( X, radix, p ) );
+
+    if( r < 10 )
+        *(*p)++ = (char)( r + 0x30 );
+    else
+        *(*p)++ = (char)( r + 0x37 );
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Export into an ASCII string
+ */
+int mpi_write_string( const mpi *X, int radix, char *s, size_t *slen )
+{
+    int ret = 0;
+    size_t n;
+    char *p;
+    mpi T;
+
+    if( radix < 2 || radix > 16 )
+        return( POLARSSL_ERR_MPI_BAD_INPUT_DATA );
+
+    n = mpi_msb( X );
+    if( radix >=  4 ) n >>= 1;
+    if( radix >= 16 ) n >>= 1;
+    n += 3;
+
+    if( *slen < n )
+    {
+        *slen = n;
+        return( POLARSSL_ERR_MPI_BUFFER_TOO_SMALL );
+    }
+
+    p = s;
+    mpi_init( &T );
+
+    if( X->s == -1 )
+        *p++ = '-';
+
+    if( radix == 16 )
+    {
+        int c;
+        size_t i, j, k;
+
+        for( i = X->n, k = 0; i > 0; i-- )
+        {
+            for( j = ciL; j > 0; j-- )
+            {
+                c = ( X->p[i - 1] >> ( ( j - 1 ) << 3) ) & 0xFF;
+
+                if( c == 0 && k == 0 && ( i + j + 3 ) != 0 )
+                    continue;
+
+                *(p++) = "0123456789ABCDEF" [c / 16];
+                *(p++) = "0123456789ABCDEF" [c % 16];
+                k = 1;
+            }
+        }
+    }
+    else
+    {
+        MPI_CHK( mpi_copy( &T, X ) );
+
+        if( T.s == -1 )
+            T.s = 1;
+
+        MPI_CHK( mpi_write_hlp( &T, radix, &p ) );
+    }
+
+    *p++ = '\0';
+    *slen = p - s;
+
+cleanup:
+
+    mpi_free( &T );
+
+    return( ret );
+}
+
+#if defined(POLARSSL_FS_IO)
+/*
+ * Read X from an opened file
+ */
+int mpi_read_file( mpi *X, int radix, FILE *fin )
+{
+    t_uint d;
+    size_t slen;
+    char *p;
+    /*
+     * Buffer should have space for (short) label and decimal formatted MPI,
+     * newline characters and '\0'
+     */
+    char s[ POLARSSL_MPI_RW_BUFFER_SIZE ];
+
+    memset( s, 0, sizeof( s ) );
+    if( fgets( s, sizeof( s ) - 1, fin ) == NULL )
+        return( POLARSSL_ERR_MPI_FILE_IO_ERROR );
+
+    slen = strlen( s );
+    if( slen == sizeof( s ) - 2 )
+        return( POLARSSL_ERR_MPI_BUFFER_TOO_SMALL );
+
+    if( s[slen - 1] == '\n' ) { slen--; s[slen] = '\0'; }
+    if( s[slen - 1] == '\r' ) { slen--; s[slen] = '\0'; }
+
+    p = s + slen;
+    while( --p >= s )
+        if( mpi_get_digit( &d, radix, *p ) != 0 )
+            break;
+
+    return( mpi_read_string( X, radix, p + 1 ) );
+}
+
+/*
+ * Write X into an opened file (or stdout if fout == NULL)
+ */
+int mpi_write_file( const char *p, const mpi *X, int radix, FILE *fout )
+{
+    int ret;
+    size_t n, slen, plen;
+    /*
+     * Buffer should have space for (short) label and decimal formatted MPI,
+     * newline characters and '\0'
+     */
+    char s[ POLARSSL_MPI_RW_BUFFER_SIZE ];
+
+    n = sizeof( s );
+    memset( s, 0, n );
+    n -= 2;
+
+    MPI_CHK( mpi_write_string( X, radix, s, (size_t *) &n ) );
+
+    if( p == NULL ) p = "";
+
+    plen = strlen( p );
+    slen = strlen( s );
+    s[slen++] = '\r';
+    s[slen++] = '\n';
+
+    if( fout != NULL )
+    {
+        if( fwrite( p, 1, plen, fout ) != plen ||
+            fwrite( s, 1, slen, fout ) != slen )
+            return( POLARSSL_ERR_MPI_FILE_IO_ERROR );
+    }
+    else
+        printf( "%s%s", p, s );
+
+cleanup:
+
+    return( ret );
+}
+#endif /* POLARSSL_FS_IO */
+
+/*
+ * Import X from unsigned binary data, big endian
+ */
+int mpi_read_binary( mpi *X, const unsigned char *buf, size_t buflen )
+{
+    int ret;
+    size_t i, j, n;
+
+    for( n = 0; n < buflen; n++ )
+        if( buf[n] != 0 )
+            break;
+
+    MPI_CHK( mpi_grow( X, CHARS_TO_LIMBS( buflen - n ) ) );
+    MPI_CHK( mpi_lset( X, 0 ) );
+
+    for( i = buflen, j = 0; i > n; i--, j++ )
+        X->p[j / ciL] |= ((t_uint) buf[i - 1]) << ((j % ciL) << 3);
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Export X into unsigned binary data, big endian
+ */
+int mpi_write_binary( const mpi *X, unsigned char *buf, size_t buflen )
+{
+    size_t i, j, n;
+
+    n = mpi_size( X );
+
+    if( buflen < n )
+        return( POLARSSL_ERR_MPI_BUFFER_TOO_SMALL );
+
+    memset( buf, 0, buflen );
+
+    for( i = buflen - 1, j = 0; n > 0; i--, j++, n-- )
+        buf[i] = (unsigned char)( X->p[j / ciL] >> ((j % ciL) << 3) );
+
+    return( 0 );
+}
+
+/*
+ * Left-shift: X <<= count
+ */
+int mpi_shift_l( mpi *X, size_t count )
+{
+    int ret;
+    size_t i, v0, t1;
+    t_uint r0 = 0, r1;
+
+    v0 = count / (biL    );
+    t1 = count & (biL - 1);
+
+    i = mpi_msb( X ) + count;
+
+    if( X->n * biL < i )
+        MPI_CHK( mpi_grow( X, BITS_TO_LIMBS( i ) ) );
+
+    ret = 0;
+
+    /*
+     * shift by count / limb_size
+     */
+    if( v0 > 0 )
+    {
+        for( i = X->n; i > v0; i-- )
+            X->p[i - 1] = X->p[i - v0 - 1];
+
+        for( ; i > 0; i-- )
+            X->p[i - 1] = 0;
+    }
+
+    /*
+     * shift by count % limb_size
+     */
+    if( t1 > 0 )
+    {
+        for( i = v0; i < X->n; i++ )
+        {
+            r1 = X->p[i] >> (biL - t1);
+            X->p[i] <<= t1;
+            X->p[i] |= r0;
+            r0 = r1;
+        }
+    }
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Right-shift: X >>= count
+ */
+int mpi_shift_r( mpi *X, size_t count )
+{
+    size_t i, v0, v1;
+    t_uint r0 = 0, r1;
+
+    v0 = count /  biL;
+    v1 = count & (biL - 1);
+
+    if( v0 > X->n || ( v0 == X->n && v1 > 0 ) )
+        return mpi_lset( X, 0 );
+
+    /*
+     * shift by count / limb_size
+     */
+    if( v0 > 0 )
+    {
+        for( i = 0; i < X->n - v0; i++ )
+            X->p[i] = X->p[i + v0];
+
+        for( ; i < X->n; i++ )
+            X->p[i] = 0;
+    }
+
+    /*
+     * shift by count % limb_size
+     */
+    if( v1 > 0 )
+    {
+        for( i = X->n; i > 0; i-- )
+        {
+            r1 = X->p[i - 1] << (biL - v1);
+            X->p[i - 1] >>= v1;
+            X->p[i - 1] |= r0;
+            r0 = r1;
+        }
+    }
+
+    return( 0 );
+}
+
+/*
+ * Compare unsigned values
+ */
+int mpi_cmp_abs( const mpi *X, const mpi *Y )
+{
+    size_t i, j;
+
+    for( i = X->n; i > 0; i-- )
+        if( X->p[i - 1] != 0 )
+            break;
+
+    for( j = Y->n; j > 0; j-- )
+        if( Y->p[j - 1] != 0 )
+            break;
+
+    if( i == 0 && j == 0 )
+        return( 0 );
+
+    if( i > j ) return(  1 );
+    if( j > i ) return( -1 );
+
+    for( ; i > 0; i-- )
+    {
+        if( X->p[i - 1] > Y->p[i - 1] ) return(  1 );
+        if( X->p[i - 1] < Y->p[i - 1] ) return( -1 );
+    }
+
+    return( 0 );
+}
+
+/*
+ * Compare signed values
+ */
+int mpi_cmp_mpi( const mpi *X, const mpi *Y )
+{
+    size_t i, j;
+
+    for( i = X->n; i > 0; i-- )
+        if( X->p[i - 1] != 0 )
+            break;
+
+    for( j = Y->n; j > 0; j-- )
+        if( Y->p[j - 1] != 0 )
+            break;
+
+    if( i == 0 && j == 0 )
+        return( 0 );
+
+    if( i > j ) return(  X->s );
+    if( j > i ) return( -Y->s );
+
+    if( X->s > 0 && Y->s < 0 ) return(  1 );
+    if( Y->s > 0 && X->s < 0 ) return( -1 );
+
+    for( ; i > 0; i-- )
+    {
+        if( X->p[i - 1] > Y->p[i - 1] ) return(  X->s );
+        if( X->p[i - 1] < Y->p[i - 1] ) return( -X->s );
+    }
+
+    return( 0 );
+}
+
+/*
+ * Compare signed values
+ */
+int mpi_cmp_int( const mpi *X, t_sint z )
+{
+    mpi Y;
+    t_uint p[1];
+
+    *p  = ( z < 0 ) ? -z : z;
+    Y.s = ( z < 0 ) ? -1 : 1;
+    Y.n = 1;
+    Y.p = p;
+
+    return( mpi_cmp_mpi( X, &Y ) );
+}
+
+/*
+ * Unsigned addition: X = |A| + |B|  (HAC 14.7)
+ */
+int mpi_add_abs( mpi *X, const mpi *A, const mpi *B )
+{
+    int ret;
+    size_t i, j;
+    t_uint *o, *p, c;
+
+    if( X == B )
+    {
+        const mpi *T = A; A = X; B = T;
+    }
+
+    if( X != A )
+        MPI_CHK( mpi_copy( X, A ) );
+   
+    /*
+     * X should always be positive as a result of unsigned additions.
+     */
+    X->s = 1;
+
+    for( j = B->n; j > 0; j-- )
+        if( B->p[j - 1] != 0 )
+            break;
+
+    MPI_CHK( mpi_grow( X, j ) );
+
+    o = B->p; p = X->p; c = 0;
+
+    for( i = 0; i < j; i++, o++, p++ )
+    {
+        *p +=  c; c  = ( *p <  c );
+        *p += *o; c += ( *p < *o );
+    }
+
+    while( c != 0 )
+    {
+        if( i >= X->n )
+        {
+            MPI_CHK( mpi_grow( X, i + 1 ) );
+            p = X->p + i;
+        }
+
+        *p += c; c = ( *p < c ); i++; p++;
+    }
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Helper for mpi substraction
+ */
+static void mpi_sub_hlp( size_t n, t_uint *s, t_uint *d )
+{
+    size_t i;
+    t_uint c, z;
+
+    for( i = c = 0; i < n; i++, s++, d++ )
+    {
+        z = ( *d <  c );     *d -=  c;
+        c = ( *d < *s ) + z; *d -= *s;
+    }
+
+    while( c != 0 )
+    {
+        z = ( *d < c ); *d -= c;
+        c = z; i++; d++;
+    }
+}
+
+/*
+ * Unsigned substraction: X = |A| - |B|  (HAC 14.9)
+ */
+int mpi_sub_abs( mpi *X, const mpi *A, const mpi *B )
+{
+    mpi TB;
+    int ret;
+    size_t n;
+
+    if( mpi_cmp_abs( A, B ) < 0 )
+        return( POLARSSL_ERR_MPI_NEGATIVE_VALUE );
+
+    mpi_init( &TB );
+
+    if( X == B )
+    {
+        MPI_CHK( mpi_copy( &TB, B ) );
+        B = &TB;
+    }
+
+    if( X != A )
+        MPI_CHK( mpi_copy( X, A ) );
+
+    /*
+     * X should always be positive as a result of unsigned substractions.
+     */
+    X->s = 1;
+
+    ret = 0;
+
+    for( n = B->n; n > 0; n-- )
+        if( B->p[n - 1] != 0 )
+            break;
+
+    mpi_sub_hlp( n, B->p, X->p );
+
+cleanup:
+
+    mpi_free( &TB );
+
+    return( ret );
+}
+
+/*
+ * Signed addition: X = A + B
+ */
+int mpi_add_mpi( mpi *X, const mpi *A, const mpi *B )
+{
+    int ret, s = A->s;
+
+    if( A->s * B->s < 0 )
+    {
+        if( mpi_cmp_abs( A, B ) >= 0 )
+        {
+            MPI_CHK( mpi_sub_abs( X, A, B ) );
+            X->s =  s;
+        }
+        else
+        {
+            MPI_CHK( mpi_sub_abs( X, B, A ) );
+            X->s = -s;
+        }
+    }
+    else
+    {
+        MPI_CHK( mpi_add_abs( X, A, B ) );
+        X->s = s;
+    }
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Signed substraction: X = A - B
+ */
+int mpi_sub_mpi( mpi *X, const mpi *A, const mpi *B )
+{
+    int ret, s = A->s;
+
+    if( A->s * B->s > 0 )
+    {
+        if( mpi_cmp_abs( A, B ) >= 0 )
+        {
+            MPI_CHK( mpi_sub_abs( X, A, B ) );
+            X->s =  s;
+        }
+        else
+        {
+            MPI_CHK( mpi_sub_abs( X, B, A ) );
+            X->s = -s;
+        }
+    }
+    else
+    {
+        MPI_CHK( mpi_add_abs( X, A, B ) );
+        X->s = s;
+    }
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Signed addition: X = A + b
+ */
+int mpi_add_int( mpi *X, const mpi *A, t_sint b )
+{
+    mpi _B;
+    t_uint p[1];
+
+    p[0] = ( b < 0 ) ? -b : b;
+    _B.s = ( b < 0 ) ? -1 : 1;
+    _B.n = 1;
+    _B.p = p;
+
+    return( mpi_add_mpi( X, A, &_B ) );
+}
+
+/*
+ * Signed substraction: X = A - b
+ */
+int mpi_sub_int( mpi *X, const mpi *A, t_sint b )
+{
+    mpi _B;
+    t_uint p[1];
+
+    p[0] = ( b < 0 ) ? -b : b;
+    _B.s = ( b < 0 ) ? -1 : 1;
+    _B.n = 1;
+    _B.p = p;
+
+    return( mpi_sub_mpi( X, A, &_B ) );
+}
+
+/*
+ * Helper for mpi multiplication
+ */
+static
+#if defined(__APPLE__) && defined(__arm__)
+/*
+ * Apple LLVM version 4.2 (clang-425.0.24) (based on LLVM 3.2svn)
+ * appears to need this to prevent bad ARM code generation at -O3.
+ */
+__attribute__ ((noinline))
+#endif
+void mpi_mul_hlp( size_t i, t_uint *s, t_uint *d, t_uint b )
+{
+    t_uint c = 0, t = 0;
+
+#if defined(MULADDC_HUIT)
+    for( ; i >= 8; i -= 8 )
+    {
+        MULADDC_INIT
+        MULADDC_HUIT
+        MULADDC_STOP
+    }
+
+    for( ; i > 0; i-- )
+    {
+        MULADDC_INIT
+        MULADDC_CORE
+        MULADDC_STOP
+    }
+#else
+    for( ; i >= 16; i -= 16 )
+    {
+        MULADDC_INIT
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_CORE   MULADDC_CORE
+
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_STOP
+    }
+
+    for( ; i >= 8; i -= 8 )
+    {
+        MULADDC_INIT
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_CORE   MULADDC_CORE
+
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_STOP
+    }
+
+    for( ; i > 0; i-- )
+    {
+        MULADDC_INIT
+        MULADDC_CORE
+        MULADDC_STOP
+    }
+#endif
+
+    t++;
+
+    do {
+        *d += c; c = ( *d < c ); d++;
+    }
+    while( c != 0 );
+}
+
+/*
+ * Baseline multiplication: X = A * B  (HAC 14.12)
+ */
+int mpi_mul_mpi( mpi *X, const mpi *A, const mpi *B )
+{
+    int ret;
+    size_t i, j;
+    mpi TA, TB;
+
+    mpi_init( &TA ); mpi_init( &TB );
+
+    if( X == A ) { MPI_CHK( mpi_copy( &TA, A ) ); A = &TA; }
+    if( X == B ) { MPI_CHK( mpi_copy( &TB, B ) ); B = &TB; }
+
+    for( i = A->n; i > 0; i-- )
+        if( A->p[i - 1] != 0 )
+            break;
+
+    for( j = B->n; j > 0; j-- )
+        if( B->p[j - 1] != 0 )
+            break;
+
+    MPI_CHK( mpi_grow( X, i + j ) );
+    MPI_CHK( mpi_lset( X, 0 ) );
+
+    for( i++; j > 0; j-- )
+        mpi_mul_hlp( i - 1, A->p, X->p + j - 1, B->p[j - 1] );
+
+    X->s = A->s * B->s;
+
+cleanup:
+
+    mpi_free( &TB ); mpi_free( &TA );
+
+    return( ret );
+}
+
+/*
+ * Baseline multiplication: X = A * b
+ */
+int mpi_mul_int( mpi *X, const mpi *A, t_sint b )
+{
+    mpi _B;
+    t_uint p[1];
+
+    _B.s = 1;
+    _B.n = 1;
+    _B.p = p;
+    p[0] = b;
+
+    return( mpi_mul_mpi( X, A, &_B ) );
+}
+
+/*
+ * Division by mpi: A = Q * B + R  (HAC 14.20)
+ */
+int mpi_div_mpi( mpi *Q, mpi *R, const mpi *A, const mpi *B )
+{
+    int ret;
+    size_t i, n, t, k;
+    mpi X, Y, Z, T1, T2;
+
+    if( mpi_cmp_int( B, 0 ) == 0 )
+        return( POLARSSL_ERR_MPI_DIVISION_BY_ZERO );
+
+    mpi_init( &X ); mpi_init( &Y ); mpi_init( &Z );
+    mpi_init( &T1 ); mpi_init( &T2 );
+
+    if( mpi_cmp_abs( A, B ) < 0 )
+    {
+        if( Q != NULL ) MPI_CHK( mpi_lset( Q, 0 ) );
+        if( R != NULL ) MPI_CHK( mpi_copy( R, A ) );
+        return( 0 );
+    }
+
+    MPI_CHK( mpi_copy( &X, A ) );
+    MPI_CHK( mpi_copy( &Y, B ) );
+    X.s = Y.s = 1;
+
+    MPI_CHK( mpi_grow( &Z, A->n + 2 ) );
+    MPI_CHK( mpi_lset( &Z,  0 ) );
+    MPI_CHK( mpi_grow( &T1, 2 ) );
+    MPI_CHK( mpi_grow( &T2, 3 ) );
+
+    k = mpi_msb( &Y ) % biL;
+    if( k < biL - 1 )
+    {
+        k = biL - 1 - k;
+        MPI_CHK( mpi_shift_l( &X, k ) );
+        MPI_CHK( mpi_shift_l( &Y, k ) );
+    }
+    else k = 0;
+
+    n = X.n - 1;
+    t = Y.n - 1;
+    MPI_CHK( mpi_shift_l( &Y, biL * (n - t) ) );
+
+    while( mpi_cmp_mpi( &X, &Y ) >= 0 )
+    {
+        Z.p[n - t]++;
+        mpi_sub_mpi( &X, &X, &Y );
+    }
+    mpi_shift_r( &Y, biL * (n - t) );
+
+    for( i = n; i > t ; i-- )
+    {
+        if( X.p[i] >= Y.p[t] )
+            Z.p[i - t - 1] = ~0;
+        else
+        {
+#if defined(POLARSSL_HAVE_UDBL)
+            t_udbl r;
+
+            r  = (t_udbl) X.p[i] << biL;
+            r |= (t_udbl) X.p[i - 1];
+            r /= Y.p[t];
+            if( r > ((t_udbl) 1 << biL) - 1)
+                r = ((t_udbl) 1 << biL) - 1;
+
+            Z.p[i - t - 1] = (t_uint) r;
+#else
+            /*
+             * __udiv_qrnnd_c, from gmp/longlong.h
+             */
+            t_uint q0, q1, r0, r1;
+            t_uint d0, d1, d, m;
+
+            d  = Y.p[t];
+            d0 = ( d << biH ) >> biH;
+            d1 = ( d >> biH );
+
+            q1 = X.p[i] / d1;
+            r1 = X.p[i] - d1 * q1;
+            r1 <<= biH;
+            r1 |= ( X.p[i - 1] >> biH );
+
+            m = q1 * d0;
+            if( r1 < m )
+            {
+                q1--, r1 += d;
+                while( r1 >= d && r1 < m )
+                    q1--, r1 += d;
+            }
+            r1 -= m;
+
+            q0 = r1 / d1;
+            r0 = r1 - d1 * q0;
+            r0 <<= biH;
+            r0 |= ( X.p[i - 1] << biH ) >> biH;
+
+            m = q0 * d0;
+            if( r0 < m )
+            {
+                q0--, r0 += d;
+                while( r0 >= d && r0 < m )
+                    q0--, r0 += d;
+            }
+            r0 -= m;
+
+            Z.p[i - t - 1] = ( q1 << biH ) | q0;
+#endif
+        }
+
+        Z.p[i - t - 1]++;
+        do
+        {
+            Z.p[i - t - 1]--;
+
+            MPI_CHK( mpi_lset( &T1, 0 ) );
+            T1.p[0] = (t < 1) ? 0 : Y.p[t - 1];
+            T1.p[1] = Y.p[t];
+            MPI_CHK( mpi_mul_int( &T1, &T1, Z.p[i - t - 1] ) );
+
+            MPI_CHK( mpi_lset( &T2, 0 ) );
+            T2.p[0] = (i < 2) ? 0 : X.p[i - 2];
+            T2.p[1] = (i < 1) ? 0 : X.p[i - 1];
+            T2.p[2] = X.p[i];
+        }
+        while( mpi_cmp_mpi( &T1, &T2 ) > 0 );
+
+        MPI_CHK( mpi_mul_int( &T1, &Y, Z.p[i - t - 1] ) );
+        MPI_CHK( mpi_shift_l( &T1,  biL * (i - t - 1) ) );
+        MPI_CHK( mpi_sub_mpi( &X, &X, &T1 ) );
+
+        if( mpi_cmp_int( &X, 0 ) < 0 )
+        {
+            MPI_CHK( mpi_copy( &T1, &Y ) );
+            MPI_CHK( mpi_shift_l( &T1, biL * (i - t - 1) ) );
+            MPI_CHK( mpi_add_mpi( &X, &X, &T1 ) );
+            Z.p[i - t - 1]--;
+        }
+    }
+
+    if( Q != NULL )
+    {
+        mpi_copy( Q, &Z );
+        Q->s = A->s * B->s;
+    }
+
+    if( R != NULL )
+    {
+        mpi_shift_r( &X, k );
+        X.s = A->s;
+        mpi_copy( R, &X );
+
+        if( mpi_cmp_int( R, 0 ) == 0 )
+            R->s = 1;
+    }
+
+cleanup:
+
+    mpi_free( &X ); mpi_free( &Y ); mpi_free( &Z );
+    mpi_free( &T1 ); mpi_free( &T2 );
+
+    return( ret );
+}
+
+/*
+ * Division by int: A = Q * b + R
+ */
+int mpi_div_int( mpi *Q, mpi *R, const mpi *A, t_sint b )
+{
+    mpi _B;
+    t_uint p[1];
+
+    p[0] = ( b < 0 ) ? -b : b;
+    _B.s = ( b < 0 ) ? -1 : 1;
+    _B.n = 1;
+    _B.p = p;
+
+    return( mpi_div_mpi( Q, R, A, &_B ) );
+}
+
+/*
+ * Modulo: R = A mod B
+ */
+int mpi_mod_mpi( mpi *R, const mpi *A, const mpi *B )
+{
+    int ret;
+
+    if( mpi_cmp_int( B, 0 ) < 0 )
+        return POLARSSL_ERR_MPI_NEGATIVE_VALUE;
+
+    MPI_CHK( mpi_div_mpi( NULL, R, A, B ) );
+
+    while( mpi_cmp_int( R, 0 ) < 0 )
+      MPI_CHK( mpi_add_mpi( R, R, B ) );
+
+    while( mpi_cmp_mpi( R, B ) >= 0 )
+      MPI_CHK( mpi_sub_mpi( R, R, B ) );
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Modulo: r = A mod b
+ */
+int mpi_mod_int( t_uint *r, const mpi *A, t_sint b )
+{
+    size_t i;
+    t_uint x, y, z;
+
+    if( b == 0 )
+        return( POLARSSL_ERR_MPI_DIVISION_BY_ZERO );
+
+    if( b < 0 )
+        return POLARSSL_ERR_MPI_NEGATIVE_VALUE;
+
+    /*
+     * handle trivial cases
+     */
+    if( b == 1 )
+    {
+        *r = 0;
+        return( 0 );
+    }
+
+    if( b == 2 )
+    {
+        *r = A->p[0] & 1;
+        return( 0 );
+    }
+
+    /*
+     * general case
+     */
+    for( i = A->n, y = 0; i > 0; i-- )
+    {
+        x  = A->p[i - 1];
+        y  = ( y << biH ) | ( x >> biH );
+        z  = y / b;
+        y -= z * b;
+
+        x <<= biH;
+        y  = ( y << biH ) | ( x >> biH );
+        z  = y / b;
+        y -= z * b;
+    }
+
+    /*
+     * If A is negative, then the current y represents a negative value.
+     * Flipping it to the positive side.
+     */
+    if( A->s < 0 && y != 0 )
+        y = b - y;
+
+    *r = y;
+
+    return( 0 );
+}
+
+/*
+ * Fast Montgomery initialization (thanks to Tom St Denis)
+ */
+static void mpi_montg_init( t_uint *mm, const mpi *N )
+{
+    t_uint x, m0 = N->p[0];
+
+    x  = m0;
+    x += ( ( m0 + 2 ) & 4 ) << 1;
+    x *= ( 2 - ( m0 * x ) );
+
+    if( biL >= 16 ) x *= ( 2 - ( m0 * x ) );
+    if( biL >= 32 ) x *= ( 2 - ( m0 * x ) );
+    if( biL >= 64 ) x *= ( 2 - ( m0 * x ) );
+
+    *mm = ~x + 1;
+}
+
+/*
+ * Montgomery multiplication: A = A * B * R^-1 mod N  (HAC 14.36)
+ */
+static void mpi_montmul( mpi *A, const mpi *B, const mpi *N, t_uint mm, const mpi *T )
+{
+    size_t i, n, m;
+    t_uint u0, u1, *d;
+
+    memset( T->p, 0, T->n * ciL );
+
+    d = T->p;
+    n = N->n;
+    m = ( B->n < n ) ? B->n : n;
+
+    for( i = 0; i < n; i++ )
+    {
+        /*
+         * T = (T + u0*B + u1*N) / 2^biL
+         */
+        u0 = A->p[i];
+        u1 = ( d[0] + u0 * B->p[0] ) * mm;
+
+        mpi_mul_hlp( m, B->p, d, u0 );
+        mpi_mul_hlp( n, N->p, d, u1 );
+
+        *d++ = u0; d[n + 1] = 0;
+    }
+
+    memcpy( A->p, d, (n + 1) * ciL );
+
+    if( mpi_cmp_abs( A, N ) >= 0 )
+        mpi_sub_hlp( n, N->p, A->p );
+    else
+        /* prevent timing attacks */
+        mpi_sub_hlp( n, A->p, T->p );
+}
+
+/*
+ * Montgomery reduction: A = A * R^-1 mod N
+ */
+static void mpi_montred( mpi *A, const mpi *N, t_uint mm, const mpi *T )
+{
+    t_uint z = 1;
+    mpi U;
+
+    U.n = U.s = (int) z;
+    U.p = &z;
+
+    mpi_montmul( A, &U, N, mm, T );
+}
+
+/*
+ * Sliding-window exponentiation: X = A^E mod N  (HAC 14.85)
+ */
+int mpi_exp_mod( mpi *X, const mpi *A, const mpi *E, const mpi *N, mpi *_RR )
+{
+    int ret;
+    size_t wbits, wsize, one = 1;
+    size_t i, j, nblimbs;
+    size_t bufsize, nbits;
+    t_uint ei, mm, state;
+    mpi RR, T, W[ 2 << POLARSSL_MPI_WINDOW_SIZE ], Apos;
+    int neg;
+
+    if( mpi_cmp_int( N, 0 ) < 0 || ( N->p[0] & 1 ) == 0 )
+        return( POLARSSL_ERR_MPI_BAD_INPUT_DATA );
+
+    if( mpi_cmp_int( E, 0 ) < 0 )
+        return( POLARSSL_ERR_MPI_BAD_INPUT_DATA );
+
+    /*
+     * Init temps and window size
+     */
+    mpi_montg_init( &mm, N );
+    mpi_init( &RR ); mpi_init( &T );
+    memset( W, 0, sizeof( W ) );
+
+    i = mpi_msb( E );
+
+    wsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 :
+            ( i >  79 ) ? 4 : ( i >  23 ) ? 3 : 1;
+
+    if( wsize > POLARSSL_MPI_WINDOW_SIZE )
+        wsize = POLARSSL_MPI_WINDOW_SIZE;
+
+    j = N->n + 1;
+    MPI_CHK( mpi_grow( X, j ) );
+    MPI_CHK( mpi_grow( &W[1],  j ) );
+    MPI_CHK( mpi_grow( &T, j * 2 ) );
+
+    /*
+     * Compensate for negative A (and correct at the end)
+     */
+    neg = ( A->s == -1 );
+
+    mpi_init( &Apos );
+    if( neg )
+    {
+        MPI_CHK( mpi_copy( &Apos, A ) );
+        Apos.s = 1;
+        A = &Apos;
+    }
+
+    /*
+     * If 1st call, pre-compute R^2 mod N
+     */
+    if( _RR == NULL || _RR->p == NULL )
+    {
+        MPI_CHK( mpi_lset( &RR, 1 ) );
+        MPI_CHK( mpi_shift_l( &RR, N->n * 2 * biL ) );
+        MPI_CHK( mpi_mod_mpi( &RR, &RR, N ) );
+
+        if( _RR != NULL )
+            memcpy( _RR, &RR, sizeof( mpi ) );
+    }
+    else
+        memcpy( &RR, _RR, sizeof( mpi ) );
+
+    /*
+     * W[1] = A * R^2 * R^-1 mod N = A * R mod N
+     */
+    if( mpi_cmp_mpi( A, N ) >= 0 )
+        mpi_mod_mpi( &W[1], A, N );
+    else   mpi_copy( &W[1], A );
+
+    mpi_montmul( &W[1], &RR, N, mm, &T );
+
+    /*
+     * X = R^2 * R^-1 mod N = R mod N
+     */
+    MPI_CHK( mpi_copy( X, &RR ) );
+    mpi_montred( X, N, mm, &T );
+
+    if( wsize > 1 )
+    {
+        /*
+         * W[1 << (wsize - 1)] = W[1] ^ (wsize - 1)
+         */
+        j =  one << (wsize - 1);
+
+        MPI_CHK( mpi_grow( &W[j], N->n + 1 ) );
+        MPI_CHK( mpi_copy( &W[j], &W[1]    ) );
+
+        for( i = 0; i < wsize - 1; i++ )
+            mpi_montmul( &W[j], &W[j], N, mm, &T );
+    
+        /*
+         * W[i] = W[i - 1] * W[1]
+         */
+        for( i = j + 1; i < (one << wsize); i++ )
+        {
+            MPI_CHK( mpi_grow( &W[i], N->n + 1 ) );
+            MPI_CHK( mpi_copy( &W[i], &W[i - 1] ) );
+
+            mpi_montmul( &W[i], &W[1], N, mm, &T );
+        }
+    }
+
+    nblimbs = E->n;
+    bufsize = 0;
+    nbits   = 0;
+    wbits   = 0;
+    state   = 0;
+
+    while( 1 )
+    {
+        if( bufsize == 0 )
+        {
+            if( nblimbs-- == 0 )
+                break;
+
+            bufsize = sizeof( t_uint ) << 3;
+        }
+
+        bufsize--;
+
+        ei = (E->p[nblimbs] >> bufsize) & 1;
+
+        /*
+         * skip leading 0s
+         */
+        if( ei == 0 && state == 0 )
+            continue;
+
+        if( ei == 0 && state == 1 )
+        {
+            /*
+             * out of window, square X
+             */
+            mpi_montmul( X, X, N, mm, &T );
+            continue;
+        }
+
+        /*
+         * add ei to current window
+         */
+        state = 2;
+
+        nbits++;
+        wbits |= (ei << (wsize - nbits));
+
+        if( nbits == wsize )
+        {
+            /*
+             * X = X^wsize R^-1 mod N
+             */
+            for( i = 0; i < wsize; i++ )
+                mpi_montmul( X, X, N, mm, &T );
+
+            /*
+             * X = X * W[wbits] R^-1 mod N
+             */
+            mpi_montmul( X, &W[wbits], N, mm, &T );
+
+            state--;
+            nbits = 0;
+            wbits = 0;
+        }
+    }
+
+    /*
+     * process the remaining bits
+     */
+    for( i = 0; i < nbits; i++ )
+    {
+        mpi_montmul( X, X, N, mm, &T );
+
+        wbits <<= 1;
+
+        if( (wbits & (one << wsize)) != 0 )
+            mpi_montmul( X, &W[1], N, mm, &T );
+    }
+
+    /*
+     * X = A^E * R * R^-1 mod N = A^E mod N
+     */
+    mpi_montred( X, N, mm, &T );
+
+    if( neg )
+    {
+        X->s = -1;
+        mpi_add_mpi( X, N, X );
+    }
+
+cleanup:
+
+    for( i = (one << (wsize - 1)); i < (one << wsize); i++ )
+        mpi_free( &W[i] );
+
+    mpi_free( &W[1] ); mpi_free( &T ); mpi_free( &Apos );
+
+    if( _RR == NULL )
+        mpi_free( &RR );
+
+    return( ret );
+}
+
+/*
+ * Greatest common divisor: G = gcd(A, B)  (HAC 14.54)
+ */
+int mpi_gcd( mpi *G, const mpi *A, const mpi *B )
+{
+    int ret;
+    size_t lz, lzt;
+    mpi TG, TA, TB;
+
+    mpi_init( &TG ); mpi_init( &TA ); mpi_init( &TB );
+
+    MPI_CHK( mpi_copy( &TA, A ) );
+    MPI_CHK( mpi_copy( &TB, B ) );
+
+    lz = mpi_lsb( &TA );
+    lzt = mpi_lsb( &TB );
+
+    if ( lzt < lz )
+        lz = lzt;
+
+    MPI_CHK( mpi_shift_r( &TA, lz ) );
+    MPI_CHK( mpi_shift_r( &TB, lz ) );
+
+    TA.s = TB.s = 1;
+
+    while( mpi_cmp_int( &TA, 0 ) != 0 )
+    {
+        MPI_CHK( mpi_shift_r( &TA, mpi_lsb( &TA ) ) );
+        MPI_CHK( mpi_shift_r( &TB, mpi_lsb( &TB ) ) );
+
+        if( mpi_cmp_mpi( &TA, &TB ) >= 0 )
+        {
+            MPI_CHK( mpi_sub_abs( &TA, &TA, &TB ) );
+            MPI_CHK( mpi_shift_r( &TA, 1 ) );
+        }
+        else
+        {
+            MPI_CHK( mpi_sub_abs( &TB, &TB, &TA ) );
+            MPI_CHK( mpi_shift_r( &TB, 1 ) );
+        }
+    }
+
+    MPI_CHK( mpi_shift_l( &TB, lz ) );
+    MPI_CHK( mpi_copy( G, &TB ) );
+
+cleanup:
+
+    mpi_free( &TG ); mpi_free( &TA ); mpi_free( &TB );
+
+    return( ret );
+}
+
+int mpi_fill_random( mpi *X, size_t size,
+                     int (*f_rng)(void *, unsigned char *, size_t),
+                     void *p_rng )
+{
+    int ret;
+
+    MPI_CHK( mpi_grow( X, CHARS_TO_LIMBS( size ) ) );
+    MPI_CHK( mpi_lset( X, 0 ) );
+
+    MPI_CHK( f_rng( p_rng, (unsigned char *) X->p, size ) );
+
+cleanup:
+    return( ret );
+}
+
+/*
+ * Modular inverse: X = A^-1 mod N  (HAC 14.61 / 14.64)
+ */
+int mpi_inv_mod( mpi *X, const mpi *A, const mpi *N )
+{
+    int ret;
+    mpi G, TA, TU, U1, U2, TB, TV, V1, V2;
+
+    if( mpi_cmp_int( N, 0 ) <= 0 )
+        return( POLARSSL_ERR_MPI_BAD_INPUT_DATA );
+
+    mpi_init( &TA ); mpi_init( &TU ); mpi_init( &U1 ); mpi_init( &U2 );
+    mpi_init( &G ); mpi_init( &TB ); mpi_init( &TV );
+    mpi_init( &V1 ); mpi_init( &V2 );
+
+    MPI_CHK( mpi_gcd( &G, A, N ) );
+
+    if( mpi_cmp_int( &G, 1 ) != 0 )
+    {
+        ret = POLARSSL_ERR_MPI_NOT_ACCEPTABLE;
+        goto cleanup;
+    }
+
+    MPI_CHK( mpi_mod_mpi( &TA, A, N ) );
+    MPI_CHK( mpi_copy( &TU, &TA ) );
+    MPI_CHK( mpi_copy( &TB, N ) );
+    MPI_CHK( mpi_copy( &TV, N ) );
+
+    MPI_CHK( mpi_lset( &U1, 1 ) );
+    MPI_CHK( mpi_lset( &U2, 0 ) );
+    MPI_CHK( mpi_lset( &V1, 0 ) );
+    MPI_CHK( mpi_lset( &V2, 1 ) );
+
+    do
+    {
+        while( ( TU.p[0] & 1 ) == 0 )
+        {
+            MPI_CHK( mpi_shift_r( &TU, 1 ) );
+
+            if( ( U1.p[0] & 1 ) != 0 || ( U2.p[0] & 1 ) != 0 )
+            {
+                MPI_CHK( mpi_add_mpi( &U1, &U1, &TB ) );
+                MPI_CHK( mpi_sub_mpi( &U2, &U2, &TA ) );
+            }
+
+            MPI_CHK( mpi_shift_r( &U1, 1 ) );
+            MPI_CHK( mpi_shift_r( &U2, 1 ) );
+        }
+
+        while( ( TV.p[0] & 1 ) == 0 )
+        {
+            MPI_CHK( mpi_shift_r( &TV, 1 ) );
+
+            if( ( V1.p[0] & 1 ) != 0 || ( V2.p[0] & 1 ) != 0 )
+            {
+                MPI_CHK( mpi_add_mpi( &V1, &V1, &TB ) );
+                MPI_CHK( mpi_sub_mpi( &V2, &V2, &TA ) );
+            }
+
+            MPI_CHK( mpi_shift_r( &V1, 1 ) );
+            MPI_CHK( mpi_shift_r( &V2, 1 ) );
+        }
+
+        if( mpi_cmp_mpi( &TU, &TV ) >= 0 )
+        {
+            MPI_CHK( mpi_sub_mpi( &TU, &TU, &TV ) );
+            MPI_CHK( mpi_sub_mpi( &U1, &U1, &V1 ) );
+            MPI_CHK( mpi_sub_mpi( &U2, &U2, &V2 ) );
+        }
+        else
+        {
+            MPI_CHK( mpi_sub_mpi( &TV, &TV, &TU ) );
+            MPI_CHK( mpi_sub_mpi( &V1, &V1, &U1 ) );
+            MPI_CHK( mpi_sub_mpi( &V2, &V2, &U2 ) );
+        }
+    }
+    while( mpi_cmp_int( &TU, 0 ) != 0 );
+
+    while( mpi_cmp_int( &V1, 0 ) < 0 )
+        MPI_CHK( mpi_add_mpi( &V1, &V1, N ) );
+
+    while( mpi_cmp_mpi( &V1, N ) >= 0 )
+        MPI_CHK( mpi_sub_mpi( &V1, &V1, N ) );
+
+    MPI_CHK( mpi_copy( X, &V1 ) );
+
+cleanup:
+
+    mpi_free( &TA ); mpi_free( &TU ); mpi_free( &U1 ); mpi_free( &U2 );
+    mpi_free( &G ); mpi_free( &TB ); mpi_free( &TV );
+    mpi_free( &V1 ); mpi_free( &V2 );
+
+    return( ret );
+}
+
+#if defined(POLARSSL_GENPRIME)
+
+static const int small_prime[] =
+{
+        3,    5,    7,   11,   13,   17,   19,   23,
+       29,   31,   37,   41,   43,   47,   53,   59,
+       61,   67,   71,   73,   79,   83,   89,   97,
+      101,  103,  107,  109,  113,  127,  131,  137,
+      139,  149,  151,  157,  163,  167,  173,  179,
+      181,  191,  193,  197,  199,  211,  223,  227,
+      229,  233,  239,  241,  251,  257,  263,  269,
+      271,  277,  281,  283,  293,  307,  311,  313,
+      317,  331,  337,  347,  349,  353,  359,  367,
+      373,  379,  383,  389,  397,  401,  409,  419,
+      421,  431,  433,  439,  443,  449,  457,  461,
+      463,  467,  479,  487,  491,  499,  503,  509,
+      521,  523,  541,  547,  557,  563,  569,  571,
+      577,  587,  593,  599,  601,  607,  613,  617,
+      619,  631,  641,  643,  647,  653,  659,  661,
+      673,  677,  683,  691,  701,  709,  719,  727,
+      733,  739,  743,  751,  757,  761,  769,  773,
+      787,  797,  809,  811,  821,  823,  827,  829,
+      839,  853,  857,  859,  863,  877,  881,  883,
+      887,  907,  911,  919,  929,  937,  941,  947,
+      953,  967,  971,  977,  983,  991,  997, -103
+};
+
+/*
+ * Miller-Rabin primality test  (HAC 4.24)
+ */
+int mpi_is_prime( mpi *X,
+                  int (*f_rng)(void *, unsigned char *, size_t),
+                  void *p_rng )
+{
+    int ret, xs;
+    size_t i, j, n, s;
+    mpi W, R, T, A, RR;
+
+    if( mpi_cmp_int( X, 0 ) == 0 ||
+        mpi_cmp_int( X, 1 ) == 0 )
+        return( POLARSSL_ERR_MPI_NOT_ACCEPTABLE );
+
+    if( mpi_cmp_int( X, 2 ) == 0 )
+        return( 0 );
+
+    mpi_init( &W ); mpi_init( &R ); mpi_init( &T ); mpi_init( &A );
+    mpi_init( &RR );
+
+    xs = X->s; X->s = 1;
+
+    /*
+     * test trivial factors first
+     */
+    if( ( X->p[0] & 1 ) == 0 )
+        return( POLARSSL_ERR_MPI_NOT_ACCEPTABLE );
+
+    for( i = 0; small_prime[i] > 0; i++ )
+    {
+        t_uint r;
+
+        if( mpi_cmp_int( X, small_prime[i] ) <= 0 )
+            return( 0 );
+
+        MPI_CHK( mpi_mod_int( &r, X, small_prime[i] ) );
+
+        if( r == 0 )
+            return( POLARSSL_ERR_MPI_NOT_ACCEPTABLE );
+    }
+
+    /*
+     * W = |X| - 1
+     * R = W >> lsb( W )
+     */
+    MPI_CHK( mpi_sub_int( &W, X, 1 ) );
+    s = mpi_lsb( &W );
+    MPI_CHK( mpi_copy( &R, &W ) );
+    MPI_CHK( mpi_shift_r( &R, s ) );
+
+    i = mpi_msb( X );
+    /*
+     * HAC, table 4.4
+     */
+    n = ( ( i >= 1300 ) ?  2 : ( i >=  850 ) ?  3 :
+          ( i >=  650 ) ?  4 : ( i >=  350 ) ?  8 :
+          ( i >=  250 ) ? 12 : ( i >=  150 ) ? 18 : 27 );
+
+    for( i = 0; i < n; i++ )
+    {
+        /*
+         * pick a random A, 1 < A < |X| - 1
+         */
+        MPI_CHK( mpi_fill_random( &A, X->n * ciL, f_rng, p_rng ) );
+
+        if( mpi_cmp_mpi( &A, &W ) >= 0 )
+        {
+            j = mpi_msb( &A ) - mpi_msb( &W );
+            MPI_CHK( mpi_shift_r( &A, j + 1 ) );
+        }
+        A.p[0] |= 3;
+
+        /*
+         * A = A^R mod |X|
+         */
+        MPI_CHK( mpi_exp_mod( &A, &A, &R, X, &RR ) );
+
+        if( mpi_cmp_mpi( &A, &W ) == 0 ||
+            mpi_cmp_int( &A,  1 ) == 0 )
+            continue;
+
+        j = 1;
+        while( j < s && mpi_cmp_mpi( &A, &W ) != 0 )
+        {
+            /*
+             * A = A * A mod |X|
+             */
+            MPI_CHK( mpi_mul_mpi( &T, &A, &A ) );
+            MPI_CHK( mpi_mod_mpi( &A, &T, X  ) );
+
+            if( mpi_cmp_int( &A, 1 ) == 0 )
+                break;
+
+            j++;
+        }
+
+        /*
+         * not prime if A != |X| - 1 or A == 1
+         */
+        if( mpi_cmp_mpi( &A, &W ) != 0 ||
+            mpi_cmp_int( &A,  1 ) == 0 )
+        {
+            ret = POLARSSL_ERR_MPI_NOT_ACCEPTABLE;
+            break;
+        }
+    }
+
+cleanup:
+
+    X->s = xs;
+
+    mpi_free( &W ); mpi_free( &R ); mpi_free( &T ); mpi_free( &A );
+    mpi_free( &RR );
+
+    return( ret );
+}
+
+/*
+ * Prime number generation
+ */
+int mpi_gen_prime( mpi *X, size_t nbits, int dh_flag,
+                   int (*f_rng)(void *, unsigned char *, size_t),
+                   void *p_rng )
+{
+    int ret;
+    size_t k, n;
+    mpi Y;
+
+    if( nbits < 3 || nbits > POLARSSL_MPI_MAX_BITS )
+        return( POLARSSL_ERR_MPI_BAD_INPUT_DATA );
+
+    mpi_init( &Y );
+
+    n = BITS_TO_LIMBS( nbits );
+
+    MPI_CHK( mpi_fill_random( X, n * ciL, f_rng, p_rng ) );
+
+    k = mpi_msb( X );
+    if( k < nbits ) MPI_CHK( mpi_shift_l( X, nbits - k ) );
+    if( k > nbits ) MPI_CHK( mpi_shift_r( X, k - nbits ) );
+
+    X->p[0] |= 3;
+
+    if( dh_flag == 0 )
+    {
+        while( ( ret = mpi_is_prime( X, f_rng, p_rng ) ) != 0 )
+        {
+            if( ret != POLARSSL_ERR_MPI_NOT_ACCEPTABLE )
+                goto cleanup;
+
+            MPI_CHK( mpi_add_int( X, X, 2 ) );
+        }
+    }
+    else
+    {
+        MPI_CHK( mpi_sub_int( &Y, X, 1 ) );
+        MPI_CHK( mpi_shift_r( &Y, 1 ) );
+
+        while( 1 )
+        {
+            if( ( ret = mpi_is_prime( X, f_rng, p_rng ) ) == 0 )
+            {
+                if( ( ret = mpi_is_prime( &Y, f_rng, p_rng ) ) == 0 )
+                    break;
+
+                if( ret != POLARSSL_ERR_MPI_NOT_ACCEPTABLE )
+                    goto cleanup;
+            }
+
+            if( ret != POLARSSL_ERR_MPI_NOT_ACCEPTABLE )
+                goto cleanup;
+
+            MPI_CHK( mpi_add_int( &Y, X, 1 ) );
+            MPI_CHK( mpi_add_int(  X, X, 2 ) );
+            MPI_CHK( mpi_shift_r( &Y, 1 ) );
+        }
+    }
+
+cleanup:
+
+    mpi_free( &Y );
+
+    return( ret );
+}
+
+#endif
+
+#if defined(POLARSSL_SELF_TEST)
+
+#define GCD_PAIR_COUNT  3
+
+static const int gcd_pairs[GCD_PAIR_COUNT][3] =
+{
+    { 693, 609, 21 },
+    { 1764, 868, 28 },
+    { 768454923, 542167814, 1 }
+};
+
+/*
+ * Checkup routine
+ */
+int mpi_self_test( int verbose )
+{
+    int ret, i;
+    mpi A, E, N, X, Y, U, V;
+
+    mpi_init( &A ); mpi_init( &E ); mpi_init( &N ); mpi_init( &X );
+    mpi_init( &Y ); mpi_init( &U ); mpi_init( &V );
+
+    MPI_CHK( mpi_read_string( &A, 16,
+        "EFE021C2645FD1DC586E69184AF4A31E" \
+        "D5F53E93B5F123FA41680867BA110131" \
+        "944FE7952E2517337780CB0DB80E61AA" \
+        "E7C8DDC6C5C6AADEB34EB38A2F40D5E6" ) );
+
+    MPI_CHK( mpi_read_string( &E, 16,
+        "B2E7EFD37075B9F03FF989C7C5051C20" \
+        "34D2A323810251127E7BF8625A4F49A5" \
+        "F3E27F4DA8BD59C47D6DAABA4C8127BD" \
+        "5B5C25763222FEFCCFC38B832366C29E" ) );
+
+    MPI_CHK( mpi_read_string( &N, 16,
+        "0066A198186C18C10B2F5ED9B522752A" \
+        "9830B69916E535C8F047518A889A43A5" \
+        "94B6BED27A168D31D4A52F88925AA8F5" ) );
+
+    MPI_CHK( mpi_mul_mpi( &X, &A, &N ) );
+
+    MPI_CHK( mpi_read_string( &U, 16,
+        "602AB7ECA597A3D6B56FF9829A5E8B85" \
+        "9E857EA95A03512E2BAE7391688D264A" \
+        "A5663B0341DB9CCFD2C4C5F421FEC814" \
+        "8001B72E848A38CAE1C65F78E56ABDEF" \
+        "E12D3C039B8A02D6BE593F0BBBDA56F1" \
+        "ECF677152EF804370C1A305CAF3B5BF1" \
+        "30879B56C61DE584A0F53A2447A51E" ) );
+
+    if( verbose != 0 )
+        printf( "  MPI test #1 (mul_mpi): " );
+
+    if( mpi_cmp_mpi( &X, &U ) != 0 )
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( 1 );
+    }
+
+    if( verbose != 0 )
+        printf( "passed\n" );
+
+    MPI_CHK( mpi_div_mpi( &X, &Y, &A, &N ) );
+
+    MPI_CHK( mpi_read_string( &U, 16,
+        "256567336059E52CAE22925474705F39A94" ) );
+
+    MPI_CHK( mpi_read_string( &V, 16,
+        "6613F26162223DF488E9CD48CC132C7A" \
+        "0AC93C701B001B092E4E5B9F73BCD27B" \
+        "9EE50D0657C77F374E903CDFA4C642" ) );
+
+    if( verbose != 0 )
+        printf( "  MPI test #2 (div_mpi): " );
+
+    if( mpi_cmp_mpi( &X, &U ) != 0 ||
+        mpi_cmp_mpi( &Y, &V ) != 0 )
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( 1 );
+    }
+
+    if( verbose != 0 )
+        printf( "passed\n" );
+
+    MPI_CHK( mpi_exp_mod( &X, &A, &E, &N, NULL ) );
+
+    MPI_CHK( mpi_read_string( &U, 16,
+        "36E139AEA55215609D2816998ED020BB" \
+        "BD96C37890F65171D948E9BC7CBAA4D9" \
+        "325D24D6A3C12710F10A09FA08AB87" ) );
+
+    if( verbose != 0 )
+        printf( "  MPI test #3 (exp_mod): " );
+
+    if( mpi_cmp_mpi( &X, &U ) != 0 )
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( 1 );
+    }
+
+    if( verbose != 0 )
+        printf( "passed\n" );
+
+#if defined(POLARSSL_GENPRIME)
+    MPI_CHK( mpi_inv_mod( &X, &A, &N ) );
+
+    MPI_CHK( mpi_read_string( &U, 16,
+        "003A0AAEDD7E784FC07D8F9EC6E3BFD5" \
+        "C3DBA76456363A10869622EAC2DD84EC" \
+        "C5B8A74DAC4D09E03B5E0BE779F2DF61" ) );
+
+    if( verbose != 0 )
+        printf( "  MPI test #4 (inv_mod): " );
+
+    if( mpi_cmp_mpi( &X, &U ) != 0 )
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( 1 );
+    }
+
+    if( verbose != 0 )
+        printf( "passed\n" );
+#endif
+
+    if( verbose != 0 )
+        printf( "  MPI test #5 (simple gcd): " );
+
+    for ( i = 0; i < GCD_PAIR_COUNT; i++)
+    {
+        MPI_CHK( mpi_lset( &X, gcd_pairs[i][0] ) );
+        MPI_CHK( mpi_lset( &Y, gcd_pairs[i][1] ) );
+
+           MPI_CHK( mpi_gcd( &A, &X, &Y ) );
+
+           if( mpi_cmp_int( &A, gcd_pairs[i][2] ) != 0 )
+           {
+                   if( verbose != 0 )
+                           printf( "failed at %d\n", i );
+
+                   return( 1 );
+           }
+    }
+
+    if( verbose != 0 )
+        printf( "passed\n" );
+
+cleanup:
+
+    if( ret != 0 && verbose != 0 )
+        printf( "Unexpected error, return code = %08X\n", ret );
+
+    mpi_free( &A ); mpi_free( &E ); mpi_free( &N ); mpi_free( &X );
+    mpi_free( &Y ); mpi_free( &U ); mpi_free( &V );
+
+    if( verbose != 0 )
+        printf( "\n" );
+
+    return( ret );
+}
+
+#endif
+
+#endif
diff --git a/common/polarssl/bignum.h b/common/polarssl/bignum.h
new file mode 100644 (file)
index 0000000..5eaf1a5
--- /dev/null
@@ -0,0 +1,685 @@
+/**
+ * \file bignum.h
+ *
+ * \brief  Multi-precision integer library
+ *
+ *  Copyright (C) 2006-2013, Brainspark B.V.
+ *
+ *  This file is part of PolarSSL (http://www.polarssl.org)
+ *  Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
+ *
+ *  All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef POLARSSL_BIGNUM_H
+#define POLARSSL_BIGNUM_H
+
+#include <stdio.h>
+#include <string.h>
+
+#include "polarssl_config.h"
+
+#ifdef _MSC_VER
+#include <basetsd.h>
+#if (_MSC_VER <= 1200)
+typedef   signed short  int16_t;
+typedef unsigned short uint16_t;
+#else
+typedef  INT16  int16_t;
+typedef UINT16 uint16_t;
+#endif
+typedef  INT32  int32_t;
+typedef  INT64  int64_t;
+typedef UINT32 uint32_t;
+typedef UINT64 uint64_t;
+#else
+#include <inttypes.h>
+#endif
+
+#define POLARSSL_ERR_MPI_FILE_IO_ERROR                     -0x0002  /**< An error occurred while reading from or writing to a file. */
+#define POLARSSL_ERR_MPI_BAD_INPUT_DATA                    -0x0004  /**< Bad input parameters to function. */
+#define POLARSSL_ERR_MPI_INVALID_CHARACTER                 -0x0006  /**< There is an invalid character in the digit string. */
+#define POLARSSL_ERR_MPI_BUFFER_TOO_SMALL                  -0x0008  /**< The buffer is too small to write to. */
+#define POLARSSL_ERR_MPI_NEGATIVE_VALUE                    -0x000A  /**< The input arguments are negative or result in illegal output. */
+#define POLARSSL_ERR_MPI_DIVISION_BY_ZERO                  -0x000C  /**< The input argument for division is zero, which is not allowed. */
+#define POLARSSL_ERR_MPI_NOT_ACCEPTABLE                    -0x000E  /**< The input arguments are not acceptable. */
+#define POLARSSL_ERR_MPI_MALLOC_FAILED                     -0x0010  /**< Memory allocation failed. */
+
+#define MPI_CHK(f) if( ( ret = f ) != 0 ) goto cleanup
+
+/*
+ * Maximum size MPIs are allowed to grow to in number of limbs.
+ */
+#define POLARSSL_MPI_MAX_LIMBS                             10000
+
+#if !defined(POLARSSL_CONFIG_OPTIONS)
+/*
+ * Maximum window size used for modular exponentiation. Default: 6
+ * Minimum value: 1. Maximum value: 6.
+ *
+ * Result is an array of ( 2 << POLARSSL_MPI_WINDOW_SIZE ) MPIs used
+ * for the sliding window calculation. (So 64 by default)
+ *
+ * Reduction in size, reduces speed.
+ */
+#define POLARSSL_MPI_WINDOW_SIZE                           6        /**< Maximum windows size used. */
+
+/*
+ * Maximum size of MPIs allowed in bits and bytes for user-MPIs.
+ * ( Default: 512 bytes => 4096 bits, Maximum tested: 2048 bytes => 16384 bits )
+ *
+ * Note: Calculations can results temporarily in larger MPIs. So the number
+ * of limbs required (POLARSSL_MPI_MAX_LIMBS) is higher.
+ */
+#define POLARSSL_MPI_MAX_SIZE                              512      /**< Maximum number of bytes for usable MPIs. */
+
+#endif /* !POLARSSL_CONFIG_OPTIONS */
+
+#define POLARSSL_MPI_MAX_BITS                              ( 8 * POLARSSL_MPI_MAX_SIZE )    /**< Maximum number of bits for usable MPIs. */
+
+/*
+ * When reading from files with mpi_read_file() and writing to files with
+ * mpi_write_file() the buffer should have space
+ * for a (short) label, the MPI (in the provided radix), the newline
+ * characters and the '\0'.
+ *
+ * By default we assume at least a 10 char label, a minimum radix of 10
+ * (decimal) and a maximum of 4096 bit numbers (1234 decimal chars).
+ * Autosized at compile time for at least a 10 char label, a minimum radix
+ * of 10 (decimal) for a number of POLARSSL_MPI_MAX_BITS size.
+ *
+ * This used to be statically sized to 1250 for a maximum of 4096 bit
+ * numbers (1234 decimal chars).
+ *
+ * Calculate using the formula:
+ *  POLARSSL_MPI_RW_BUFFER_SIZE = ceil(POLARSSL_MPI_MAX_BITS / ln(10) * ln(2)) +
+ *                                LabelSize + 6
+ */
+#define POLARSSL_MPI_MAX_BITS_SCALE100          ( 100 * POLARSSL_MPI_MAX_BITS )
+#define LN_2_DIV_LN_10_SCALE100                 332
+#define POLARSSL_MPI_RW_BUFFER_SIZE             ( ((POLARSSL_MPI_MAX_BITS_SCALE100 + LN_2_DIV_LN_10_SCALE100 - 1) / LN_2_DIV_LN_10_SCALE100) + 10 + 6 )
+
+/*
+ * Define the base integer type, architecture-wise
+ */
+#if defined(POLARSSL_HAVE_INT8)
+typedef   signed char  t_sint;
+typedef unsigned char  t_uint;
+typedef uint16_t       t_udbl;
+#define POLARSSL_HAVE_UDBL
+#else
+#if defined(POLARSSL_HAVE_INT16)
+typedef  int16_t t_sint;
+typedef uint16_t t_uint;
+typedef uint32_t t_udbl;
+#define POLARSSL_HAVE_UDBL
+#else
+  #if ( defined(_MSC_VER) && defined(_M_AMD64) )
+    typedef  int64_t t_sint;
+    typedef uint64_t t_uint;
+  #else
+    #if ( defined(__GNUC__) && (                          \
+          defined(__amd64__) || defined(__x86_64__)    || \
+          defined(__ppc64__) || defined(__powerpc64__) || \
+          defined(__ia64__)  || defined(__alpha__)     || \
+          (defined(__sparc__) && defined(__arch64__))  || \
+          defined(__s390x__) ) )
+       typedef  int64_t t_sint;
+       typedef uint64_t t_uint;
+       typedef unsigned int t_udbl __attribute__((mode(TI)));
+       #define POLARSSL_HAVE_UDBL
+    #else
+       typedef  int32_t t_sint;
+       typedef uint32_t t_uint;
+       #if ( defined(_MSC_VER) && defined(_M_IX86) )
+         typedef uint64_t t_udbl;
+         #define POLARSSL_HAVE_UDBL
+       #else
+         #if defined( POLARSSL_HAVE_LONGLONG )
+           typedef unsigned long long t_udbl;
+           #define POLARSSL_HAVE_UDBL
+         #endif
+       #endif
+    #endif
+  #endif
+#endif /* POLARSSL_HAVE_INT16 */
+#endif /* POLARSSL_HAVE_INT8  */
+
+/**
+ * \brief          MPI structure
+ */
+typedef struct
+{
+    int s;              /*!<  integer sign      */
+    size_t n;           /*!<  total # of limbs  */
+    t_uint *p;          /*!<  pointer to limbs  */
+}
+mpi;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief           Initialize one MPI
+ *
+ * \param X         One MPI to initialize.
+ */
+void mpi_init( mpi *X );
+
+/**
+ * \brief          Unallocate one MPI
+ *
+ * \param X        One MPI to unallocate.
+ */
+void mpi_free( mpi *X );
+
+/**
+ * \brief          Enlarge to the specified number of limbs
+ *
+ * \param X        MPI to grow
+ * \param nblimbs  The target number of limbs
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
+ */
+int mpi_grow( mpi *X, size_t nblimbs );
+
+/**
+ * \brief          Copy the contents of Y into X
+ *
+ * \param X        Destination MPI
+ * \param Y        Source MPI
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
+ */
+int mpi_copy( mpi *X, const mpi *Y );
+
+/**
+ * \brief          Swap the contents of X and Y
+ *
+ * \param X        First MPI value
+ * \param Y        Second MPI value
+ */
+void mpi_swap( mpi *X, mpi *Y );
+
+/**
+ * \brief          Set value from integer
+ *
+ * \param X        MPI to set
+ * \param z        Value to use
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
+ */
+int mpi_lset( mpi *X, t_sint z );
+
+/**
+ * \brief          Get a specific bit from X
+ *
+ * \param X        MPI to use
+ * \param pos      Zero-based index of the bit in X
+ *
+ * \return         Either a 0 or a 1
+ */
+int mpi_get_bit( const mpi *X, size_t pos );
+
+/**
+ * \brief          Set a bit of X to a specific value of 0 or 1
+ *
+ * \note           Will grow X if necessary to set a bit to 1 in a not yet
+ *                 existing limb. Will not grow if bit should be set to 0
+ *
+ * \param X        MPI to use
+ * \param pos      Zero-based index of the bit in X
+ * \param val      The value to set the bit to (0 or 1)
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed,
+ *                 POLARSSL_ERR_MPI_BAD_INPUT_DATA if val is not 0 or 1
+ */
+int mpi_set_bit( mpi *X, size_t pos, unsigned char val );
+
+/**
+ * \brief          Return the number of zero-bits before the least significant
+ *                 '1' bit
+ *
+ * Note: Thus also the zero-based index of the least significant '1' bit
+ *
+ * \param X        MPI to use
+ */
+size_t mpi_lsb( const mpi *X );
+
+/**
+ * \brief          Return the number of bits up to and including the most
+ *                 significant '1' bit'
+ *
+ * Note: Thus also the one-based index of the most significant '1' bit
+ *
+ * \param X        MPI to use
+ */
+size_t mpi_msb( const mpi *X );
+
+/**
+ * \brief          Return the total size in bytes
+ *
+ * \param X        MPI to use
+ */
+size_t mpi_size( const mpi *X );
+
+/**
+ * \brief          Import from an ASCII string
+ *
+ * \param X        Destination MPI
+ * \param radix    Input numeric base
+ * \param s        Null-terminated string buffer
+ *
+ * \return         0 if successful, or a POLARSSL_ERR_MPI_XXX error code
+ */
+int mpi_read_string( mpi *X, int radix, const char *s );
+
+/**
+ * \brief          Export into an ASCII string
+ *
+ * \param X        Source MPI
+ * \param radix    Output numeric base
+ * \param s        String buffer
+ * \param slen     String buffer size
+ *
+ * \return         0 if successful, or a POLARSSL_ERR_MPI_XXX error code.
+ *                 *slen is always updated to reflect the amount
+ *                 of data that has (or would have) been written.
+ *
+ * \note           Call this function with *slen = 0 to obtain the
+ *                 minimum required buffer size in *slen.
+ */
+int mpi_write_string( const mpi *X, int radix, char *s, size_t *slen );
+
+#if defined(POLARSSL_FS_IO)
+/**
+ * \brief          Read X from an opened file
+ *
+ * \param X        Destination MPI
+ * \param radix    Input numeric base
+ * \param fin      Input file handle
+ *
+ * \return         0 if successful, POLARSSL_ERR_MPI_BUFFER_TOO_SMALL if
+ *                 the file read buffer is too small or a
+ *                 POLARSSL_ERR_MPI_XXX error code
+ */
+int mpi_read_file( mpi *X, int radix, FILE *fin );
+
+/**
+ * \brief          Write X into an opened file, or stdout if fout is NULL
+ *
+ * \param p        Prefix, can be NULL
+ * \param X        Source MPI
+ * \param radix    Output numeric base
+ * \param fout     Output file handle (can be NULL)
+ *
+ * \return         0 if successful, or a POLARSSL_ERR_MPI_XXX error code
+ *
+ * \note           Set fout == NULL to print X on the console.
+ */
+int mpi_write_file( const char *p, const mpi *X, int radix, FILE *fout );
+#endif /* POLARSSL_FS_IO */
+
+/**
+ * \brief          Import X from unsigned binary data, big endian
+ *
+ * \param X        Destination MPI
+ * \param buf      Input buffer
+ * \param buflen   Input buffer size
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
+ */
+int mpi_read_binary( mpi *X, const unsigned char *buf, size_t buflen );
+
+/**
+ * \brief          Export X into unsigned binary data, big endian
+ *
+ * \param X        Source MPI
+ * \param buf      Output buffer
+ * \param buflen   Output buffer size
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_BUFFER_TOO_SMALL if buf isn't large enough
+ */
+int mpi_write_binary( const mpi *X, unsigned char *buf, size_t buflen );
+
+/**
+ * \brief          Left-shift: X <<= count
+ *
+ * \param X        MPI to shift
+ * \param count    Amount to shift
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
+ */
+int mpi_shift_l( mpi *X, size_t count );
+
+/**
+ * \brief          Right-shift: X >>= count
+ *
+ * \param X        MPI to shift
+ * \param count    Amount to shift
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
+ */
+int mpi_shift_r( mpi *X, size_t count );
+
+/**
+ * \brief          Compare unsigned values
+ *
+ * \param X        Left-hand MPI
+ * \param Y        Right-hand MPI
+ *
+ * \return         1 if |X| is greater than |Y|,
+ *                -1 if |X| is lesser  than |Y| or
+ *                 0 if |X| is equal to |Y|
+ */
+int mpi_cmp_abs( const mpi *X, const mpi *Y );
+
+/**
+ * \brief          Compare signed values
+ *
+ * \param X        Left-hand MPI
+ * \param Y        Right-hand MPI
+ *
+ * \return         1 if X is greater than Y,
+ *                -1 if X is lesser  than Y or
+ *                 0 if X is equal to Y
+ */
+int mpi_cmp_mpi( const mpi *X, const mpi *Y );
+
+/**
+ * \brief          Compare signed values
+ *
+ * \param X        Left-hand MPI
+ * \param z        The integer value to compare to
+ *
+ * \return         1 if X is greater than z,
+ *                -1 if X is lesser  than z or
+ *                 0 if X is equal to z
+ */
+int mpi_cmp_int( const mpi *X, t_sint z );
+
+/**
+ * \brief          Unsigned addition: X = |A| + |B|
+ *
+ * \param X        Destination MPI
+ * \param A        Left-hand MPI
+ * \param B        Right-hand MPI
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
+ */
+int mpi_add_abs( mpi *X, const mpi *A, const mpi *B );
+
+/**
+ * \brief          Unsigned substraction: X = |A| - |B|
+ *
+ * \param X        Destination MPI
+ * \param A        Left-hand MPI
+ * \param B        Right-hand MPI
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_NEGATIVE_VALUE if B is greater than A
+ */
+int mpi_sub_abs( mpi *X, const mpi *A, const mpi *B );
+
+/**
+ * \brief          Signed addition: X = A + B
+ *
+ * \param X        Destination MPI
+ * \param A        Left-hand MPI
+ * \param B        Right-hand MPI
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
+ */
+int mpi_add_mpi( mpi *X, const mpi *A, const mpi *B );
+
+/**
+ * \brief          Signed substraction: X = A - B
+ *
+ * \param X        Destination MPI
+ * \param A        Left-hand MPI
+ * \param B        Right-hand MPI
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
+ */
+int mpi_sub_mpi( mpi *X, const mpi *A, const mpi *B );
+
+/**
+ * \brief          Signed addition: X = A + b
+ *
+ * \param X        Destination MPI
+ * \param A        Left-hand MPI
+ * \param b        The integer value to add
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
+ */
+int mpi_add_int( mpi *X, const mpi *A, t_sint b );
+
+/**
+ * \brief          Signed substraction: X = A - b
+ *
+ * \param X        Destination MPI
+ * \param A        Left-hand MPI
+ * \param b        The integer value to subtract
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
+ */
+int mpi_sub_int( mpi *X, const mpi *A, t_sint b );
+
+/**
+ * \brief          Baseline multiplication: X = A * B
+ *
+ * \param X        Destination MPI
+ * \param A        Left-hand MPI
+ * \param B        Right-hand MPI
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
+ */
+int mpi_mul_mpi( mpi *X, const mpi *A, const mpi *B );
+
+/**
+ * \brief          Baseline multiplication: X = A * b
+ *                 Note: b is an unsigned integer type, thus
+ *                 Negative values of b are ignored.
+ *
+ * \param X        Destination MPI
+ * \param A        Left-hand MPI
+ * \param b        The integer value to multiply with
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
+ */
+int mpi_mul_int( mpi *X, const mpi *A, t_sint b );
+
+/**
+ * \brief          Division by mpi: A = Q * B + R
+ *
+ * \param Q        Destination MPI for the quotient
+ * \param R        Destination MPI for the rest value
+ * \param A        Left-hand MPI
+ * \param B        Right-hand MPI
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed,
+ *                 POLARSSL_ERR_MPI_DIVISION_BY_ZERO if B == 0
+ *
+ * \note           Either Q or R can be NULL.
+ */
+int mpi_div_mpi( mpi *Q, mpi *R, const mpi *A, const mpi *B );
+
+/**
+ * \brief          Division by int: A = Q * b + R
+ *
+ * \param Q        Destination MPI for the quotient
+ * \param R        Destination MPI for the rest value
+ * \param A        Left-hand MPI
+ * \param b        Integer to divide by
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed,
+ *                 POLARSSL_ERR_MPI_DIVISION_BY_ZERO if b == 0
+ *
+ * \note           Either Q or R can be NULL.
+ */
+int mpi_div_int( mpi *Q, mpi *R, const mpi *A, t_sint b );
+
+/**
+ * \brief          Modulo: R = A mod B
+ *
+ * \param R        Destination MPI for the rest value
+ * \param A        Left-hand MPI
+ * \param B        Right-hand MPI
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed,
+ *                 POLARSSL_ERR_MPI_DIVISION_BY_ZERO if B == 0,
+ *                 POLARSSL_ERR_MPI_NEGATIVE_VALUE if B < 0
+ */
+int mpi_mod_mpi( mpi *R, const mpi *A, const mpi *B );
+
+/**
+ * \brief          Modulo: r = A mod b
+ *
+ * \param r        Destination t_uint
+ * \param A        Left-hand MPI
+ * \param b        Integer to divide by
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed,
+ *                 POLARSSL_ERR_MPI_DIVISION_BY_ZERO if b == 0,
+ *                 POLARSSL_ERR_MPI_NEGATIVE_VALUE if b < 0
+ */
+int mpi_mod_int( t_uint *r, const mpi *A, t_sint b );
+
+/**
+ * \brief          Sliding-window exponentiation: X = A^E mod N
+ *
+ * \param X        Destination MPI 
+ * \param A        Left-hand MPI
+ * \param E        Exponent MPI
+ * \param N        Modular MPI
+ * \param _RR      Speed-up MPI used for recalculations
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed,
+ *                 POLARSSL_ERR_MPI_BAD_INPUT_DATA if N is negative or even or if
+ *                 E is negative
+ *
+ * \note           _RR is used to avoid re-computing R*R mod N across
+ *                 multiple calls, which speeds up things a bit. It can
+ *                 be set to NULL if the extra performance is unneeded.
+ */
+int mpi_exp_mod( mpi *X, const mpi *A, const mpi *E, const mpi *N, mpi *_RR );
+
+/**
+ * \brief          Fill an MPI X with size bytes of random
+ *
+ * \param X        Destination MPI
+ * \param size     Size in bytes
+ * \param f_rng    RNG function
+ * \param p_rng    RNG parameter
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
+ */
+int mpi_fill_random( mpi *X, size_t size,
+                     int (*f_rng)(void *, unsigned char *, size_t),
+                     void *p_rng );
+
+/**
+ * \brief          Greatest common divisor: G = gcd(A, B)
+ *
+ * \param G        Destination MPI
+ * \param A        Left-hand MPI
+ * \param B        Right-hand MPI
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
+ */
+int mpi_gcd( mpi *G, const mpi *A, const mpi *B );
+
+/**
+ * \brief          Modular inverse: X = A^-1 mod N
+ *
+ * \param X        Destination MPI
+ * \param A        Left-hand MPI
+ * \param N        Right-hand MPI
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed,
+ *                 POLARSSL_ERR_MPI_BAD_INPUT_DATA if N is negative or nil
+                   POLARSSL_ERR_MPI_NOT_ACCEPTABLE if A has no inverse mod N
+ */
+int mpi_inv_mod( mpi *X, const mpi *A, const mpi *N );
+
+/**
+ * \brief          Miller-Rabin primality test
+ *
+ * \param X        MPI to check
+ * \param f_rng    RNG function
+ * \param p_rng    RNG parameter
+ *
+ * \return         0 if successful (probably prime),
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed,
+ *                 POLARSSL_ERR_MPI_NOT_ACCEPTABLE if X is not prime
+ */
+int mpi_is_prime( mpi *X,
+                  int (*f_rng)(void *, unsigned char *, size_t),
+                  void *p_rng );
+
+/**
+ * \brief          Prime number generation
+ *
+ * \param X        Destination MPI
+ * \param nbits    Required size of X in bits ( 3 <= nbits <= POLARSSL_MPI_MAX_BITS )
+ * \param dh_flag  If 1, then (X-1)/2 will be prime too
+ * \param f_rng    RNG function
+ * \param p_rng    RNG parameter
+ *
+ * \return         0 if successful (probably prime),
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed,
+ *                 POLARSSL_ERR_MPI_BAD_INPUT_DATA if nbits is < 3
+ */
+int mpi_gen_prime( mpi *X, size_t nbits, int dh_flag,
+                   int (*f_rng)(void *, unsigned char *, size_t),
+                   void *p_rng );
+
+/**
+ * \brief          Checkup routine
+ *
+ * \return         0 if successful, or 1 if the test failed
+ */
+int mpi_self_test( int verbose );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* bignum.h */
diff --git a/common/polarssl/bn_mul.h b/common/polarssl/bn_mul.h
new file mode 100644 (file)
index 0000000..1c2da13
--- /dev/null
@@ -0,0 +1,864 @@
+/**
+ * \file bn_mul.h
+ *
+ * \brief  Multi-precision integer library
+ *
+ *  Copyright (C) 2006-2010, Brainspark B.V.
+ *
+ *  This file is part of PolarSSL (http://www.polarssl.org)
+ *  Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
+ *
+ *  All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+/*
+ *      Multiply source vector [s] with b, add result
+ *       to destination vector [d] and set carry c.
+ *
+ *      Currently supports:
+ *
+ *         . IA-32 (386+)         . AMD64 / EM64T
+ *         . IA-32 (SSE2)         . Motorola 68000
+ *         . PowerPC, 32-bit      . MicroBlaze
+ *         . PowerPC, 64-bit      . TriCore
+ *         . SPARC v8             . ARM v3+
+ *         . Alpha                . MIPS32
+ *         . C, longlong          . C, generic
+ */
+#ifndef POLARSSL_BN_MUL_H
+#define POLARSSL_BN_MUL_H
+
+#include "bignum.h"
+
+#if defined(POLARSSL_HAVE_ASM)
+
+#if defined(__GNUC__)
+#if defined(__i386__)
+
+#define MULADDC_INIT                \
+    asm( "                          \
+        movl   %%ebx, %0;           \
+        movl   %5, %%esi;           \
+        movl   %6, %%edi;           \
+        movl   %7, %%ecx;           \
+        movl   %8, %%ebx;           \
+        "
+
+#define MULADDC_CORE                \
+        "                           \
+        lodsl;                      \
+        mull   %%ebx;               \
+        addl   %%ecx,   %%eax;      \
+        adcl   $0,      %%edx;      \
+        addl   (%%edi), %%eax;      \
+        adcl   $0,      %%edx;      \
+        movl   %%edx,   %%ecx;      \
+        stosl;                      \
+        "
+
+#if defined(POLARSSL_HAVE_SSE2)
+
+#define MULADDC_HUIT                    \
+        "                               \
+        movd     %%ecx,     %%mm1;      \
+        movd     %%ebx,     %%mm0;      \
+        movd     (%%edi),   %%mm3;      \
+        paddq    %%mm3,     %%mm1;      \
+        movd     (%%esi),   %%mm2;      \
+        pmuludq  %%mm0,     %%mm2;      \
+        movd     4(%%esi),  %%mm4;      \
+        pmuludq  %%mm0,     %%mm4;      \
+        movd     8(%%esi),  %%mm6;      \
+        pmuludq  %%mm0,     %%mm6;      \
+        movd     12(%%esi), %%mm7;      \
+        pmuludq  %%mm0,     %%mm7;      \
+        paddq    %%mm2,     %%mm1;      \
+        movd     4(%%edi),  %%mm3;      \
+        paddq    %%mm4,     %%mm3;      \
+        movd     8(%%edi),  %%mm5;      \
+        paddq    %%mm6,     %%mm5;      \
+        movd     12(%%edi), %%mm4;      \
+        paddq    %%mm4,     %%mm7;      \
+        movd     %%mm1,     (%%edi);    \
+        movd     16(%%esi), %%mm2;      \
+        pmuludq  %%mm0,     %%mm2;      \
+        psrlq    $32,       %%mm1;      \
+        movd     20(%%esi), %%mm4;      \
+        pmuludq  %%mm0,     %%mm4;      \
+        paddq    %%mm3,     %%mm1;      \
+        movd     24(%%esi), %%mm6;      \
+        pmuludq  %%mm0,     %%mm6;      \
+        movd     %%mm1,     4(%%edi);   \
+        psrlq    $32,       %%mm1;      \
+        movd     28(%%esi), %%mm3;      \
+        pmuludq  %%mm0,     %%mm3;      \
+        paddq    %%mm5,     %%mm1;      \
+        movd     16(%%edi), %%mm5;      \
+        paddq    %%mm5,     %%mm2;      \
+        movd     %%mm1,     8(%%edi);   \
+        psrlq    $32,       %%mm1;      \
+        paddq    %%mm7,     %%mm1;      \
+        movd     20(%%edi), %%mm5;      \
+        paddq    %%mm5,     %%mm4;      \
+        movd     %%mm1,     12(%%edi);  \
+        psrlq    $32,       %%mm1;      \
+        paddq    %%mm2,     %%mm1;      \
+        movd     24(%%edi), %%mm5;      \
+        paddq    %%mm5,     %%mm6;      \
+        movd     %%mm1,     16(%%edi);  \
+        psrlq    $32,       %%mm1;      \
+        paddq    %%mm4,     %%mm1;      \
+        movd     28(%%edi), %%mm5;      \
+        paddq    %%mm5,     %%mm3;      \
+        movd     %%mm1,     20(%%edi);  \
+        psrlq    $32,       %%mm1;      \
+        paddq    %%mm6,     %%mm1;      \
+        movd     %%mm1,     24(%%edi);  \
+        psrlq    $32,       %%mm1;      \
+        paddq    %%mm3,     %%mm1;      \
+        movd     %%mm1,     28(%%edi);  \
+        addl     $32,       %%edi;      \
+        addl     $32,       %%esi;      \
+        psrlq    $32,       %%mm1;      \
+        movd     %%mm1,     %%ecx;      \
+        "
+
+#define MULADDC_STOP            \
+        "                       \
+        emms;                   \
+        movl   %4, %%ebx;       \
+        movl   %%ecx, %1;       \
+        movl   %%edi, %2;       \
+        movl   %%esi, %3;       \
+        "                       \
+        : "=m" (t), "=m" (c), "=m" (d), "=m" (s)        \
+        : "m" (t), "m" (s), "m" (d), "m" (c), "m" (b)   \
+        : "eax", "ecx", "edx", "esi", "edi"             \
+    );
+
+#else
+
+#define MULADDC_STOP            \
+        "                       \
+        movl   %4, %%ebx;       \
+        movl   %%ecx, %1;       \
+        movl   %%edi, %2;       \
+        movl   %%esi, %3;       \
+        "                       \
+        : "=m" (t), "=m" (c), "=m" (d), "=m" (s)        \
+        : "m" (t), "m" (s), "m" (d), "m" (c), "m" (b)   \
+        : "eax", "ecx", "edx", "esi", "edi"             \
+    );
+#endif /* SSE2 */
+#endif /* i386 */
+
+#if defined(__amd64__) || defined (__x86_64__)
+
+#define MULADDC_INIT                            \
+    asm( "movq   %0, %%rsi      " :: "m" (s));  \
+    asm( "movq   %0, %%rdi      " :: "m" (d));  \
+    asm( "movq   %0, %%rcx      " :: "m" (c));  \
+    asm( "movq   %0, %%rbx      " :: "m" (b));  \
+    asm( "xorq   %r8, %r8       " );
+
+#define MULADDC_CORE                            \
+    asm( "movq  (%rsi),%rax     " );            \
+    asm( "mulq   %rbx           " );            \
+    asm( "addq   $8,   %rsi     " );            \
+    asm( "addq   %rcx, %rax     " );            \
+    asm( "movq   %r8,  %rcx     " );            \
+    asm( "adcq   $0,   %rdx     " );            \
+    asm( "nop                   " );            \
+    asm( "addq   %rax, (%rdi)   " );            \
+    asm( "adcq   %rdx, %rcx     " );            \
+    asm( "addq   $8,   %rdi     " );
+
+#define MULADDC_STOP                            \
+    asm( "movq   %%rcx, %0      " : "=m" (c));  \
+    asm( "movq   %%rdi, %0      " : "=m" (d));  \
+    asm( "movq   %%rsi, %0      " : "=m" (s) :: \
+    "rax", "rcx", "rdx", "rbx", "rsi", "rdi", "r8" );
+
+#endif /* AMD64 */
+
+#if defined(__mc68020__) || defined(__mcpu32__)
+
+#define MULADDC_INIT                            \
+    asm( "movl   %0, %%a2       " :: "m" (s));  \
+    asm( "movl   %0, %%a3       " :: "m" (d));  \
+    asm( "movl   %0, %%d3       " :: "m" (c));  \
+    asm( "movl   %0, %%d2       " :: "m" (b));  \
+    asm( "moveq  #0, %d0        " );
+
+#define MULADDC_CORE                            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d4:%d1   " );            \
+    asm( "addl   %d3, %d1       " );            \
+    asm( "addxl  %d0, %d4       " );            \
+    asm( "moveq  #0,  %d3       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "addxl  %d4, %d3       " );
+
+#define MULADDC_STOP                            \
+    asm( "movl   %%d3, %0       " : "=m" (c));  \
+    asm( "movl   %%a3, %0       " : "=m" (d));  \
+    asm( "movl   %%a2, %0       " : "=m" (s) :: \
+    "d0", "d1", "d2", "d3", "d4", "a2", "a3" );
+
+#define MULADDC_HUIT                            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d4:%d1   " );            \
+    asm( "addxl  %d3, %d1       " );            \
+    asm( "addxl  %d0, %d4       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d3:%d1   " );            \
+    asm( "addxl  %d4, %d1       " );            \
+    asm( "addxl  %d0, %d3       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d4:%d1   " );            \
+    asm( "addxl  %d3, %d1       " );            \
+    asm( "addxl  %d0, %d4       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d3:%d1   " );            \
+    asm( "addxl  %d4, %d1       " );            \
+    asm( "addxl  %d0, %d3       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d4:%d1   " );            \
+    asm( "addxl  %d3, %d1       " );            \
+    asm( "addxl  %d0, %d4       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d3:%d1   " );            \
+    asm( "addxl  %d4, %d1       " );            \
+    asm( "addxl  %d0, %d3       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d4:%d1   " );            \
+    asm( "addxl  %d3, %d1       " );            \
+    asm( "addxl  %d0, %d4       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d3:%d1   " );            \
+    asm( "addxl  %d4, %d1       " );            \
+    asm( "addxl  %d0, %d3       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "addxl  %d0, %d3       " );
+
+#endif /* MC68000 */
+
+#if defined(__powerpc__)   || defined(__ppc__)
+#if defined(__powerpc64__) || defined(__ppc64__)
+
+#if defined(__MACH__) && defined(__APPLE__)
+
+#define MULADDC_INIT                            \
+    asm( "ld     r3, %0         " :: "m" (s));  \
+    asm( "ld     r4, %0         " :: "m" (d));  \
+    asm( "ld     r5, %0         " :: "m" (c));  \
+    asm( "ld     r6, %0         " :: "m" (b));  \
+    asm( "addi   r3, r3, -8     " );            \
+    asm( "addi   r4, r4, -8     " );            \
+    asm( "addic  r5, r5,  0     " );
+
+#define MULADDC_CORE                            \
+    asm( "ldu    r7, 8(r3)      " );            \
+    asm( "mulld  r8, r7, r6     " );            \
+    asm( "mulhdu r9, r7, r6     " );            \
+    asm( "adde   r8, r8, r5     " );            \
+    asm( "ld     r7, 8(r4)      " );            \
+    asm( "addze  r5, r9         " );            \
+    asm( "addc   r8, r8, r7     " );            \
+    asm( "stdu   r8, 8(r4)      " );
+
+#define MULADDC_STOP                            \
+    asm( "addze  r5, r5         " );            \
+    asm( "addi   r4, r4, 8      " );            \
+    asm( "addi   r3, r3, 8      " );            \
+    asm( "std    r5, %0         " : "=m" (c));  \
+    asm( "std    r4, %0         " : "=m" (d));  \
+    asm( "std    r3, %0         " : "=m" (s) :: \
+    "r3", "r4", "r5", "r6", "r7", "r8", "r9" );
+
+#else
+
+#define MULADDC_INIT                            \
+    asm( "ld     %%r3, %0       " :: "m" (s));  \
+    asm( "ld     %%r4, %0       " :: "m" (d));  \
+    asm( "ld     %%r5, %0       " :: "m" (c));  \
+    asm( "ld     %%r6, %0       " :: "m" (b));  \
+    asm( "addi   %r3, %r3, -8   " );            \
+    asm( "addi   %r4, %r4, -8   " );            \
+    asm( "addic  %r5, %r5,  0   " );
+
+#define MULADDC_CORE                            \
+    asm( "ldu    %r7, 8(%r3)    " );            \
+    asm( "mulld  %r8, %r7, %r6  " );            \
+    asm( "mulhdu %r9, %r7, %r6  " );            \
+    asm( "adde   %r8, %r8, %r5  " );            \
+    asm( "ld     %r7, 8(%r4)    " );            \
+    asm( "addze  %r5, %r9       " );            \
+    asm( "addc   %r8, %r8, %r7  " );            \
+    asm( "stdu   %r8, 8(%r4)    " );
+
+#define MULADDC_STOP                            \
+    asm( "addze  %r5, %r5       " );            \
+    asm( "addi   %r4, %r4, 8    " );            \
+    asm( "addi   %r3, %r3, 8    " );            \
+    asm( "std    %%r5, %0       " : "=m" (c));  \
+    asm( "std    %%r4, %0       " : "=m" (d));  \
+    asm( "std    %%r3, %0       " : "=m" (s) :: \
+    "r3", "r4", "r5", "r6", "r7", "r8", "r9" );
+
+#endif
+
+#else /* PPC32 */
+
+#if defined(__MACH__) && defined(__APPLE__)
+
+#define MULADDC_INIT                            \
+    asm( "lwz    r3, %0         " :: "m" (s));  \
+    asm( "lwz    r4, %0         " :: "m" (d));  \
+    asm( "lwz    r5, %0         " :: "m" (c));  \
+    asm( "lwz    r6, %0         " :: "m" (b));  \
+    asm( "addi   r3, r3, -4     " );            \
+    asm( "addi   r4, r4, -4     " );            \
+    asm( "addic  r5, r5,  0     " );
+
+#define MULADDC_CORE                            \
+    asm( "lwzu   r7, 4(r3)      " );            \
+    asm( "mullw  r8, r7, r6     " );            \
+    asm( "mulhwu r9, r7, r6     " );            \
+    asm( "adde   r8, r8, r5     " );            \
+    asm( "lwz    r7, 4(r4)      " );            \
+    asm( "addze  r5, r9         " );            \
+    asm( "addc   r8, r8, r7     " );            \
+    asm( "stwu   r8, 4(r4)      " );
+
+#define MULADDC_STOP                            \
+    asm( "addze  r5, r5         " );            \
+    asm( "addi   r4, r4, 4      " );            \
+    asm( "addi   r3, r3, 4      " );            \
+    asm( "stw    r5, %0         " : "=m" (c));  \
+    asm( "stw    r4, %0         " : "=m" (d));  \
+    asm( "stw    r3, %0         " : "=m" (s) :: \
+    "r3", "r4", "r5", "r6", "r7", "r8", "r9" );
+
+#else
+
+#define MULADDC_INIT                            \
+    asm( "lwz    %%r3, %0       " :: "m" (s));  \
+    asm( "lwz    %%r4, %0       " :: "m" (d));  \
+    asm( "lwz    %%r5, %0       " :: "m" (c));  \
+    asm( "lwz    %%r6, %0       " :: "m" (b));  \
+    asm( "addi   %r3, %r3, -4   " );            \
+    asm( "addi   %r4, %r4, -4   " );            \
+    asm( "addic  %r5, %r5,  0   " );
+
+#define MULADDC_CORE                            \
+    asm( "lwzu   %r7, 4(%r3)    " );            \
+    asm( "mullw  %r8, %r7, %r6  " );            \
+    asm( "mulhwu %r9, %r7, %r6  " );            \
+    asm( "adde   %r8, %r8, %r5  " );            \
+    asm( "lwz    %r7, 4(%r4)    " );            \
+    asm( "addze  %r5, %r9       " );            \
+    asm( "addc   %r8, %r8, %r7  " );            \
+    asm( "stwu   %r8, 4(%r4)    " );
+
+#define MULADDC_STOP                            \
+    asm( "addze  %r5, %r5       " );            \
+    asm( "addi   %r4, %r4, 4    " );            \
+    asm( "addi   %r3, %r3, 4    " );            \
+    asm( "stw    %%r5, %0       " : "=m" (c));  \
+    asm( "stw    %%r4, %0       " : "=m" (d));  \
+    asm( "stw    %%r3, %0       " : "=m" (s) :: \
+    "r3", "r4", "r5", "r6", "r7", "r8", "r9" );
+
+#endif
+
+#endif /* PPC32 */
+#endif /* PPC64 */
+
+#if defined(__sparc__) && defined(__sparc64__)
+
+#define MULADDC_INIT                            \
+    asm(                                        \
+         "                                      \
+                ldx     %3, %%o0;               \
+                ldx     %4, %%o1;               \
+                ld      %5, %%o2;               \
+                ld      %6, %%o3;               \
+         "
+
+#define MULADDC_CORE                            \
+         "                                      \
+                ld      [%%o0], %%o4;           \
+                inc     4, %%o0;                \
+                ld      [%%o1], %%o5;           \
+                umul    %%o3, %%o4, %%o4;       \
+                addcc   %%o4, %%o2, %%o4;       \
+                rd      %%y, %%g1;              \
+                addx    %%g1, 0, %%g1;          \
+                addcc   %%o4, %%o5, %%o4;       \
+                st      %%o4, [%%o1];           \
+                addx    %%g1, 0, %%o2;          \
+                inc     4, %%o1;                \
+        "
+
+#define MULADDC_STOP                            \
+        "                                       \
+                st      %%o2, %0;               \
+                stx     %%o1, %1;               \
+                stx     %%o0, %2;               \
+        "                                       \
+        : "=m" (c), "=m" (d), "=m" (s)          \
+        : "m" (s), "m" (d), "m" (c), "m" (b)    \
+        : "g1", "o0", "o1", "o2", "o3", "o4",   \
+          "o5"                                  \
+        );
+#endif /* SPARCv9 */
+
+#if defined(__sparc__) && !defined(__sparc64__)
+
+#define MULADDC_INIT                            \
+    asm(                                        \
+         "                                      \
+                ld      %3, %%o0;               \
+                ld      %4, %%o1;               \
+                ld      %5, %%o2;               \
+                ld      %6, %%o3;               \
+         "
+
+#define MULADDC_CORE                            \
+         "                                      \
+                ld      [%%o0], %%o4;           \
+                inc     4, %%o0;                \
+                ld      [%%o1], %%o5;           \
+                umul    %%o3, %%o4, %%o4;       \
+                addcc   %%o4, %%o2, %%o4;       \
+                rd      %%y, %%g1;              \
+                addx    %%g1, 0, %%g1;          \
+                addcc   %%o4, %%o5, %%o4;       \
+                st      %%o4, [%%o1];           \
+                addx    %%g1, 0, %%o2;          \
+                inc     4, %%o1;                \
+        "
+
+#define MULADDC_STOP                            \
+        "                                       \
+                st      %%o2, %0;               \
+                st      %%o1, %1;               \
+                st      %%o0, %2;               \
+        "                                       \
+        : "=m" (c), "=m" (d), "=m" (s)          \
+        : "m" (s), "m" (d), "m" (c), "m" (b)    \
+        : "g1", "o0", "o1", "o2", "o3", "o4",   \
+          "o5"                                  \
+        );
+
+#endif /* SPARCv8 */
+
+#if defined(__microblaze__) || defined(microblaze)
+
+#define MULADDC_INIT                            \
+    asm( "lwi   r3,   %0        " :: "m" (s));  \
+    asm( "lwi   r4,   %0        " :: "m" (d));  \
+    asm( "lwi   r5,   %0        " :: "m" (c));  \
+    asm( "lwi   r6,   %0        " :: "m" (b));  \
+    asm( "andi  r7,   r6, 0xffff" );            \
+    asm( "bsrli r6,   r6, 16    " );
+
+#define MULADDC_CORE                            \
+    asm( "lhui  r8,   r3,   0   " );            \
+    asm( "addi  r3,   r3,   2   " );            \
+    asm( "lhui  r9,   r3,   0   " );            \
+    asm( "addi  r3,   r3,   2   " );            \
+    asm( "mul   r10,  r9,  r6   " );            \
+    asm( "mul   r11,  r8,  r7   " );            \
+    asm( "mul   r12,  r9,  r7   " );            \
+    asm( "mul   r13,  r8,  r6   " );            \
+    asm( "bsrli  r8, r10,  16   " );            \
+    asm( "bsrli  r9, r11,  16   " );            \
+    asm( "add   r13, r13,  r8   " );            \
+    asm( "add   r13, r13,  r9   " );            \
+    asm( "bslli r10, r10,  16   " );            \
+    asm( "bslli r11, r11,  16   " );            \
+    asm( "add   r12, r12, r10   " );            \
+    asm( "addc  r13, r13,  r0   " );            \
+    asm( "add   r12, r12, r11   " );            \
+    asm( "addc  r13, r13,  r0   " );            \
+    asm( "lwi   r10,  r4,   0   " );            \
+    asm( "add   r12, r12, r10   " );            \
+    asm( "addc  r13, r13,  r0   " );            \
+    asm( "add   r12, r12,  r5   " );            \
+    asm( "addc   r5, r13,  r0   " );            \
+    asm( "swi   r12,  r4,   0   " );            \
+    asm( "addi   r4,  r4,   4   " );
+
+#define MULADDC_STOP                            \
+    asm( "swi   r5,   %0        " : "=m" (c));  \
+    asm( "swi   r4,   %0        " : "=m" (d));  \
+    asm( "swi   r3,   %0        " : "=m" (s) :: \
+     "r3", "r4" , "r5" , "r6" , "r7" , "r8" ,   \
+     "r9", "r10", "r11", "r12", "r13" );
+
+#endif /* MicroBlaze */
+
+#if defined(__tricore__)
+
+#define MULADDC_INIT                            \
+    asm( "ld.a   %%a2, %0       " :: "m" (s));  \
+    asm( "ld.a   %%a3, %0       " :: "m" (d));  \
+    asm( "ld.w   %%d4, %0       " :: "m" (c));  \
+    asm( "ld.w   %%d1, %0       " :: "m" (b));  \
+    asm( "xor    %d5, %d5       " );
+
+#define MULADDC_CORE                            \
+    asm( "ld.w   %d0,   [%a2+]      " );        \
+    asm( "madd.u %e2, %e4, %d0, %d1 " );        \
+    asm( "ld.w   %d0,   [%a3]       " );        \
+    asm( "addx   %d2,    %d2,  %d0  " );        \
+    asm( "addc   %d3,    %d3,    0  " );        \
+    asm( "mov    %d4,    %d3        " );        \
+    asm( "st.w  [%a3+],  %d2        " );
+
+#define MULADDC_STOP                            \
+    asm( "st.w   %0, %%d4       " : "=m" (c));  \
+    asm( "st.a   %0, %%a3       " : "=m" (d));  \
+    asm( "st.a   %0, %%a2       " : "=m" (s) :: \
+    "d0", "d1", "e2", "d4", "a2", "a3" );
+
+#endif /* TriCore */
+
+#if defined(__arm__)
+
+#if defined(__thumb__) && !defined(__thumb2__)
+
+#define MULADDC_INIT                            \
+    asm(                                        \
+         "                                      \
+            ldr    r0, %3;                      \
+            ldr    r1, %4;                      \
+            ldr    r2, %5;                      \
+            ldr    r3, %6;                      \
+            lsr    r7, r3, #16;                 \
+            mov    r9, r7;                      \
+            lsl    r7, r3, #16;                 \
+            lsr    r7, r7, #16;                 \
+            mov    r8, r7;                      \
+         "
+
+#define MULADDC_CORE                            \
+         "                                      \
+            ldmia  r0!, {r6};                   \
+            lsr    r7, r6, #16;                 \
+            lsl    r6, r6, #16;                 \
+            lsr    r6, r6, #16;                 \
+            mov    r4, r8;                      \
+            mul    r4, r6;                      \
+            mov    r3, r9;                      \
+            mul    r6, r3;                      \
+            mov    r5, r9;                      \
+            mul    r5, r7;                      \
+            mov    r3, r8;                      \
+            mul    r7, r3;                      \
+            lsr    r3, r6, #16;                 \
+            add    r5, r5, r3;                  \
+            lsr    r3, r7, #16;                 \
+            add    r5, r5, r3;                  \
+            add    r4, r4, r2;                  \
+            mov    r2, #0;                      \
+            adc    r5, r2;                      \
+            lsl    r3, r6, #16;                 \
+            add    r4, r4, r3;                  \
+            adc    r5, r2;                      \
+            lsl    r3, r7, #16;                 \
+            add    r4, r4, r3;                  \
+            adc    r5, r2;                      \
+            ldr    r3, [r1];                    \
+            add    r4, r4, r3;                  \
+            adc    r2, r5;                      \
+            stmia  r1!, {r4};                   \
+         "
+
+#define MULADDC_STOP                            \
+         "                                      \
+            str    r2, %0;                      \
+            str    r1, %1;                      \
+            str    r0, %2;                      \
+         "                                      \
+         : "=m" (c),  "=m" (d), "=m" (s)        \
+         : "m" (s), "m" (d), "m" (c), "m" (b)   \
+         : "r0", "r1", "r2", "r3", "r4", "r5",  \
+           "r6", "r7", "r8", "r9", "cc"         \
+         );
+
+#else
+
+#define MULADDC_INIT                            \
+    asm(                                        \
+         "                                     \
+            ldr    r0, %3;                      \
+            ldr    r1, %4;                      \
+            ldr    r2, %5;                      \
+            ldr    r3, %6;                      \
+         "
+
+#define MULADDC_CORE                            \
+         "                                      \
+            ldr    r4, [r0], #4;                \
+            mov    r5, #0;                      \
+            ldr    r6, [r1];                    \
+            umlal  r2, r5, r3, r4;              \
+            adds   r7, r6, r2;                  \
+            adc    r2, r5, #0;                  \
+            str    r7, [r1], #4;                \
+         "
+
+#define MULADDC_STOP                            \
+         "                                      \
+            str    r2, %0;                      \
+            str    r1, %1;                      \
+            str    r0, %2;                      \
+         "                                      \
+         : "=m" (c),  "=m" (d), "=m" (s)        \
+         : "m" (s), "m" (d), "m" (c), "m" (b)   \
+         : "r0", "r1", "r2", "r3", "r4", "r5",  \
+           "r6", "r7", "cc"                     \
+         );
+
+#endif /* Thumb */
+
+#endif /* ARMv3 */
+
+#if defined(__alpha__)
+
+#define MULADDC_INIT                            \
+    asm( "ldq    $1, %0         " :: "m" (s));  \
+    asm( "ldq    $2, %0         " :: "m" (d));  \
+    asm( "ldq    $3, %0         " :: "m" (c));  \
+    asm( "ldq    $4, %0         " :: "m" (b));
+
+#define MULADDC_CORE                            \
+    asm( "ldq    $6,  0($1)     " );            \
+    asm( "addq   $1,  8, $1     " );            \
+    asm( "mulq   $6, $4, $7     " );            \
+    asm( "umulh  $6, $4, $6     " );            \
+    asm( "addq   $7, $3, $7     " );            \
+    asm( "cmpult $7, $3, $3     " );            \
+    asm( "ldq    $5,  0($2)     " );            \
+    asm( "addq   $7, $5, $7     " );            \
+    asm( "cmpult $7, $5, $5     " );            \
+    asm( "stq    $7,  0($2)     " );            \
+    asm( "addq   $2,  8, $2     " );            \
+    asm( "addq   $6, $3, $3     " );            \
+    asm( "addq   $5, $3, $3     " );
+
+#define MULADDC_STOP                            \
+    asm( "stq    $3, %0         " : "=m" (c));  \
+    asm( "stq    $2, %0         " : "=m" (d));  \
+    asm( "stq    $1, %0         " : "=m" (s) :: \
+    "$1", "$2", "$3", "$4", "$5", "$6", "$7" );
+
+#endif /* Alpha */
+
+#if defined(__mips__)
+
+#define MULADDC_INIT                            \
+    asm( "lw     $10, %0        " :: "m" (s));  \
+    asm( "lw     $11, %0        " :: "m" (d));  \
+    asm( "lw     $12, %0        " :: "m" (c));  \
+    asm( "lw     $13, %0        " :: "m" (b));
+
+#define MULADDC_CORE                            \
+    asm( "lw     $14, 0($10)    " );            \
+    asm( "multu  $13, $14       " );            \
+    asm( "addi   $10, $10, 4    " );            \
+    asm( "mflo   $14            " );            \
+    asm( "mfhi   $9             " );            \
+    asm( "addu   $14, $12, $14  " );            \
+    asm( "lw     $15, 0($11)    " );            \
+    asm( "sltu   $12, $14, $12  " );            \
+    asm( "addu   $15, $14, $15  " );            \
+    asm( "sltu   $14, $15, $14  " );            \
+    asm( "addu   $12, $12, $9   " );            \
+    asm( "sw     $15, 0($11)    " );            \
+    asm( "addu   $12, $12, $14  " );            \
+    asm( "addi   $11, $11, 4    " );
+
+#define MULADDC_STOP                            \
+    asm( "sw     $12, %0        " : "=m" (c));  \
+    asm( "sw     $11, %0        " : "=m" (d));  \
+    asm( "sw     $10, %0        " : "=m" (s) :: \
+    "$9", "$10", "$11", "$12", "$13", "$14", "$15" );
+
+#endif /* MIPS */
+#endif /* GNUC */
+
+#if (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
+
+#define MULADDC_INIT                            \
+    __asm   mov     esi, s                      \
+    __asm   mov     edi, d                      \
+    __asm   mov     ecx, c                      \
+    __asm   mov     ebx, b
+
+#define MULADDC_CORE                            \
+    __asm   lodsd                               \
+    __asm   mul     ebx                         \
+    __asm   add     eax, ecx                    \
+    __asm   adc     edx, 0                      \
+    __asm   add     eax, [edi]                  \
+    __asm   adc     edx, 0                      \
+    __asm   mov     ecx, edx                    \
+    __asm   stosd
+
+#if defined(POLARSSL_HAVE_SSE2)
+
+#define EMIT __asm _emit
+
+#define MULADDC_HUIT                            \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0xC9             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0xC3             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x1F             \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCB             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x16             \
+    EMIT 0x0F  EMIT 0xF4  EMIT 0xD0             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x66  EMIT 0x04  \
+    EMIT 0x0F  EMIT 0xF4  EMIT 0xE0             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x76  EMIT 0x08  \
+    EMIT 0x0F  EMIT 0xF4  EMIT 0xF0             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x7E  EMIT 0x0C  \
+    EMIT 0x0F  EMIT 0xF4  EMIT 0xF8             \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCA             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x5F  EMIT 0x04  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xDC             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x6F  EMIT 0x08  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xEE             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x67  EMIT 0x0C  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xFC             \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0x0F             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x56  EMIT 0x10  \
+    EMIT 0x0F  EMIT 0xF4  EMIT 0xD0             \
+    EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x66  EMIT 0x14  \
+    EMIT 0x0F  EMIT 0xF4  EMIT 0xE0             \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCB             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x76  EMIT 0x18  \
+    EMIT 0x0F  EMIT 0xF4  EMIT 0xF0             \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x04  \
+    EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x5E  EMIT 0x1C  \
+    EMIT 0x0F  EMIT 0xF4  EMIT 0xD8             \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCD             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x6F  EMIT 0x10  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xD5             \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x08  \
+    EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCF             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x6F  EMIT 0x14  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xE5             \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x0C  \
+    EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCA             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x6F  EMIT 0x18  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xF5             \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x10  \
+    EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCC             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x6F  EMIT 0x1C  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xDD             \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x14  \
+    EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCE             \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x18  \
+    EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCB             \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x1C  \
+    EMIT 0x83  EMIT 0xC7  EMIT 0x20             \
+    EMIT 0x83  EMIT 0xC6  EMIT 0x20             \
+    EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0xC9
+
+#define MULADDC_STOP                            \
+    EMIT 0x0F  EMIT 0x77                        \
+    __asm   mov     c, ecx                      \
+    __asm   mov     d, edi                      \
+    __asm   mov     s, esi                      \
+
+#else
+
+#define MULADDC_STOP                            \
+    __asm   mov     c, ecx                      \
+    __asm   mov     d, edi                      \
+    __asm   mov     s, esi                      \
+
+#endif /* SSE2 */
+#endif /* MSVC */
+
+#endif /* POLARSSL_HAVE_ASM */
+
+#if !defined(MULADDC_CORE)
+#if defined(POLARSSL_HAVE_UDBL)
+
+#define MULADDC_INIT                    \
+{                                       \
+    t_udbl r;                           \
+    t_uint r0, r1;
+
+#define MULADDC_CORE                    \
+    r   = *(s++) * (t_udbl) b;          \
+    r0  = r;                            \
+    r1  = r >> biL;                     \
+    r0 += c;  r1 += (r0 <  c);          \
+    r0 += *d; r1 += (r0 < *d);          \
+    c = r1; *(d++) = r0;
+
+#define MULADDC_STOP                    \
+}
+
+#else
+#define MULADDC_INIT                    \
+{                                       \
+    t_uint s0, s1, b0, b1;              \
+    t_uint r0, r1, rx, ry;              \
+    b0 = ( b << biH ) >> biH;           \
+    b1 = ( b >> biH );
+
+#define MULADDC_CORE                    \
+    s0 = ( *s << biH ) >> biH;          \
+    s1 = ( *s >> biH ); s++;            \
+    rx = s0 * b1; r0 = s0 * b0;         \
+    ry = s1 * b0; r1 = s1 * b1;         \
+    r1 += ( rx >> biH );                \
+    r1 += ( ry >> biH );                \
+    rx <<= biH; ry <<= biH;             \
+    r0 += rx; r1 += (r0 < rx);          \
+    r0 += ry; r1 += (r0 < ry);          \
+    r0 +=  c; r1 += (r0 <  c);          \
+    r0 += *d; r1 += (r0 < *d);          \
+    c = r1; *(d++) = r0;
+
+#define MULADDC_STOP                    \
+}
+
+#endif /* C (generic)  */
+#endif /* C (longlong) */
+
+#endif /* bn_mul.h */
index 746752d7ebd00292e0e2ef4ab9a0ae6d4c1e1a2c..b33deb6c6f4a9895d210bd866ab7c333d01340ec 100644 (file)
@@ -29,7 +29,7 @@
  *  http://csrc.nist.gov/publications/fips/fips46-3/fips46-3.pdf
  */
 
-//#include "polarssl/config.h"
+#include "polarssl_config.h"
 #define POLARSSL_DES_C
 
 #if defined(POLARSSL_DES_C)
index 5bd88fc07561ac8f58343ec82bb0499259c72118..3d9a2f67d31fbebaa9aa17a0f445cd760aa194b7 100644 (file)
@@ -82,7 +82,7 @@
  *
  * Comment to disable the use of assembly code.
  */
-#define POLARSSL_HAVE_ASM
+//#define POLARSSL_HAVE_ASM
 
 /**
  * \def POLARSSL_HAVE_SSE2
  *
  * This enables support for RSAES-OAEP and RSASSA-PSS operations.
  */
-#define POLARSSL_PKCS1_V21
+//#define POLARSSL_PKCS1_V21
 
 /**
  * \def POLARSSL_RSA_NO_CRT
diff --git a/common/polarssl/rsa.c b/common/polarssl/rsa.c
new file mode 100644 (file)
index 0000000..9872274
--- /dev/null
@@ -0,0 +1,1466 @@
+/*
+ *  The RSA public-key cryptosystem
+ *
+ *  Copyright (C) 2006-2011, Brainspark B.V.
+ *
+ *  This file is part of PolarSSL (http://www.polarssl.org)
+ *  Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
+ *
+ *  All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+/*
+ *  RSA was designed by Ron Rivest, Adi Shamir and Len Adleman.
+ *
+ *  http://theory.lcs.mit.edu/~rivest/rsapaper.pdf
+ *  http://www.cacr.math.uwaterloo.ca/hac/about/chap8.pdf
+ */
+
+#include "polarssl_config.h"
+
+#if defined(POLARSSL_RSA_C)
+
+#include "rsa.h"
+
+#if defined(POLARSSL_PKCS1_V21)
+#include "md.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+
+/*
+ * Initialize an RSA context
+ */
+void rsa_init( rsa_context *ctx,
+               int padding,
+               int hash_id )
+{
+    memset( ctx, 0, sizeof( rsa_context ) );
+
+    ctx->padding = padding;
+    ctx->hash_id = hash_id;
+}
+
+#if defined(POLARSSL_GENPRIME)
+
+/*
+ * Generate an RSA keypair
+ */
+int rsa_gen_key( rsa_context *ctx,
+                 int (*f_rng)(void *, unsigned char *, size_t),
+                 void *p_rng,
+                 unsigned int nbits, int exponent )
+{
+    int ret;
+    mpi P1, Q1, H, G;
+
+    if( f_rng == NULL || nbits < 128 || exponent < 3 )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    mpi_init( &P1 ); mpi_init( &Q1 ); mpi_init( &H ); mpi_init( &G );
+
+    /*
+     * find primes P and Q with Q < P so that:
+     * GCD( E, (P-1)*(Q-1) ) == 1
+     */
+    MPI_CHK( mpi_lset( &ctx->E, exponent ) );
+
+    do
+    {
+        MPI_CHK( mpi_gen_prime( &ctx->P, ( nbits + 1 ) >> 1, 0, 
+                                f_rng, p_rng ) );
+
+        MPI_CHK( mpi_gen_prime( &ctx->Q, ( nbits + 1 ) >> 1, 0,
+                                f_rng, p_rng ) );
+
+        if( mpi_cmp_mpi( &ctx->P, &ctx->Q ) < 0 )
+            mpi_swap( &ctx->P, &ctx->Q );
+
+        if( mpi_cmp_mpi( &ctx->P, &ctx->Q ) == 0 )
+            continue;
+
+        MPI_CHK( mpi_mul_mpi( &ctx->N, &ctx->P, &ctx->Q ) );
+        if( mpi_msb( &ctx->N ) != nbits )
+            continue;
+
+        MPI_CHK( mpi_sub_int( &P1, &ctx->P, 1 ) );
+        MPI_CHK( mpi_sub_int( &Q1, &ctx->Q, 1 ) );
+        MPI_CHK( mpi_mul_mpi( &H, &P1, &Q1 ) );
+        MPI_CHK( mpi_gcd( &G, &ctx->E, &H  ) );
+    }
+    while( mpi_cmp_int( &G, 1 ) != 0 );
+
+    /*
+     * D  = E^-1 mod ((P-1)*(Q-1))
+     * DP = D mod (P - 1)
+     * DQ = D mod (Q - 1)
+     * QP = Q^-1 mod P
+     */
+    MPI_CHK( mpi_inv_mod( &ctx->D , &ctx->E, &H  ) );
+    MPI_CHK( mpi_mod_mpi( &ctx->DP, &ctx->D, &P1 ) );
+    MPI_CHK( mpi_mod_mpi( &ctx->DQ, &ctx->D, &Q1 ) );
+    MPI_CHK( mpi_inv_mod( &ctx->QP, &ctx->Q, &ctx->P ) );
+
+    ctx->len = ( mpi_msb( &ctx->N ) + 7 ) >> 3;
+
+cleanup:
+
+    mpi_free( &P1 ); mpi_free( &Q1 ); mpi_free( &H ); mpi_free( &G );
+
+    if( ret != 0 )
+    {
+        rsa_free( ctx );
+        return( POLARSSL_ERR_RSA_KEY_GEN_FAILED + ret );
+    }
+
+    return( 0 );   
+}
+
+#endif
+
+/*
+ * Check a public RSA key
+ */
+int rsa_check_pubkey( const rsa_context *ctx )
+{
+    if( !ctx->N.p || !ctx->E.p )
+        return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED );
+
+    if( ( ctx->N.p[0] & 1 ) == 0 || 
+        ( ctx->E.p[0] & 1 ) == 0 )
+        return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED );
+
+    if( mpi_msb( &ctx->N ) < 128 ||
+        mpi_msb( &ctx->N ) > POLARSSL_MPI_MAX_BITS )
+        return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED );
+
+    if( mpi_msb( &ctx->E ) < 2 ||
+        mpi_msb( &ctx->E ) > 64 )
+        return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED );
+
+    return( 0 );
+}
+
+/*
+ * Check a private RSA key
+ */
+int rsa_check_privkey( const rsa_context *ctx )
+{
+    int ret;
+    mpi PQ, DE, P1, Q1, H, I, G, G2, L1, L2, DP, DQ, QP;
+
+    if( ( ret = rsa_check_pubkey( ctx ) ) != 0 )
+        return( ret );
+
+    if( !ctx->P.p || !ctx->Q.p || !ctx->D.p )
+        return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED );
+
+    mpi_init( &PQ ); mpi_init( &DE ); mpi_init( &P1 ); mpi_init( &Q1 );
+    mpi_init( &H  ); mpi_init( &I  ); mpi_init( &G  ); mpi_init( &G2 );
+    mpi_init( &L1 ); mpi_init( &L2 ); mpi_init( &DP ); mpi_init( &DQ );
+    mpi_init( &QP );
+
+    MPI_CHK( mpi_mul_mpi( &PQ, &ctx->P, &ctx->Q ) );
+    MPI_CHK( mpi_mul_mpi( &DE, &ctx->D, &ctx->E ) );
+    MPI_CHK( mpi_sub_int( &P1, &ctx->P, 1 ) );
+    MPI_CHK( mpi_sub_int( &Q1, &ctx->Q, 1 ) );
+    MPI_CHK( mpi_mul_mpi( &H, &P1, &Q1 ) );
+    MPI_CHK( mpi_gcd( &G, &ctx->E, &H  ) );
+
+    MPI_CHK( mpi_gcd( &G2, &P1, &Q1 ) );
+    MPI_CHK( mpi_div_mpi( &L1, &L2, &H, &G2 ) );  
+    MPI_CHK( mpi_mod_mpi( &I, &DE, &L1  ) );
+
+    MPI_CHK( mpi_mod_mpi( &DP, &ctx->D, &P1 ) );
+    MPI_CHK( mpi_mod_mpi( &DQ, &ctx->D, &Q1 ) );
+    MPI_CHK( mpi_inv_mod( &QP, &ctx->Q, &ctx->P ) );
+    /*
+     * Check for a valid PKCS1v2 private key
+     */
+    if( mpi_cmp_mpi( &PQ, &ctx->N ) != 0 ||
+        mpi_cmp_mpi( &DP, &ctx->DP ) != 0 ||
+        mpi_cmp_mpi( &DQ, &ctx->DQ ) != 0 ||
+        mpi_cmp_mpi( &QP, &ctx->QP ) != 0 ||
+        mpi_cmp_int( &L2, 0 ) != 0 ||
+        mpi_cmp_int( &I, 1 ) != 0 ||
+        mpi_cmp_int( &G, 1 ) != 0 )
+    {
+        ret = POLARSSL_ERR_RSA_KEY_CHECK_FAILED;
+    }
+    
+cleanup:
+    mpi_free( &PQ ); mpi_free( &DE ); mpi_free( &P1 ); mpi_free( &Q1 );
+    mpi_free( &H  ); mpi_free( &I  ); mpi_free( &G  ); mpi_free( &G2 );
+    mpi_free( &L1 ); mpi_free( &L2 ); mpi_free( &DP ); mpi_free( &DQ );
+    mpi_free( &QP );
+
+    if( ret == POLARSSL_ERR_RSA_KEY_CHECK_FAILED )
+        return( ret );
+
+    if( ret != 0 )
+        return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED + ret );
+
+    return( 0 );
+}
+
+/*
+ * Do an RSA public key operation
+ */
+int rsa_public( rsa_context *ctx,
+                const unsigned char *input,
+                unsigned char *output )
+{
+    int ret;
+    size_t olen;
+    mpi T;
+
+    mpi_init( &T );
+
+    MPI_CHK( mpi_read_binary( &T, input, ctx->len ) );
+
+    if( mpi_cmp_mpi( &T, &ctx->N ) >= 0 )
+    {
+        mpi_free( &T );
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+    }
+
+    olen = ctx->len;
+    MPI_CHK( mpi_exp_mod( &T, &T, &ctx->E, &ctx->N, &ctx->RN ) );
+    MPI_CHK( mpi_write_binary( &T, output, olen ) );
+
+cleanup:
+
+    mpi_free( &T );
+
+    if( ret != 0 )
+        return( POLARSSL_ERR_RSA_PUBLIC_FAILED + ret );
+
+    return( 0 );
+}
+
+/*
+ * Do an RSA private key operation
+ */
+int rsa_private( rsa_context *ctx,
+                 const unsigned char *input,
+                 unsigned char *output )
+{
+    int ret;
+    size_t olen;
+    mpi T, T1, T2;
+
+    mpi_init( &T ); mpi_init( &T1 ); mpi_init( &T2 );
+
+    MPI_CHK( mpi_read_binary( &T, input, ctx->len ) );
+
+    if( mpi_cmp_mpi( &T, &ctx->N ) >= 0 )
+    {
+        mpi_free( &T );
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+    }
+
+#if defined(POLARSSL_RSA_NO_CRT)
+    MPI_CHK( mpi_exp_mod( &T, &T, &ctx->D, &ctx->N, &ctx->RN ) );
+#else
+    /*
+     * faster decryption using the CRT
+     *
+     * T1 = input ^ dP mod P
+     * T2 = input ^ dQ mod Q
+     */
+    MPI_CHK( mpi_exp_mod( &T1, &T, &ctx->DP, &ctx->P, &ctx->RP ) );
+    MPI_CHK( mpi_exp_mod( &T2, &T, &ctx->DQ, &ctx->Q, &ctx->RQ ) );
+
+    /*
+     * T = (T1 - T2) * (Q^-1 mod P) mod P
+     */
+    MPI_CHK( mpi_sub_mpi( &T, &T1, &T2 ) );
+    MPI_CHK( mpi_mul_mpi( &T1, &T, &ctx->QP ) );
+    MPI_CHK( mpi_mod_mpi( &T, &T1, &ctx->P ) );
+
+    /*
+     * output = T2 + T * Q
+     */
+    MPI_CHK( mpi_mul_mpi( &T1, &T, &ctx->Q ) );
+    MPI_CHK( mpi_add_mpi( &T, &T2, &T1 ) );
+#endif
+
+    olen = ctx->len;
+    MPI_CHK( mpi_write_binary( &T, output, olen ) );
+
+cleanup:
+
+    mpi_free( &T ); mpi_free( &T1 ); mpi_free( &T2 );
+
+    if( ret != 0 )
+        return( POLARSSL_ERR_RSA_PRIVATE_FAILED + ret );
+
+    return( 0 );
+}
+
+#if defined(POLARSSL_PKCS1_V21)
+/**
+ * Generate and apply the MGF1 operation (from PKCS#1 v2.1) to a buffer.
+ *
+ * \param dst       buffer to mask
+ * \param dlen      length of destination buffer
+ * \param src       source of the mask generation
+ * \param slen      length of the source buffer
+ * \param md_ctx    message digest context to use
+ */
+static void mgf_mask( unsigned char *dst, size_t dlen, unsigned char *src, size_t slen,  
+                       md_context_t *md_ctx )
+{
+    unsigned char mask[POLARSSL_MD_MAX_SIZE];
+    unsigned char counter[4];
+    unsigned char *p;
+    unsigned int hlen;
+    size_t i, use_len;
+
+    memset( mask, 0, POLARSSL_MD_MAX_SIZE );
+    memset( counter, 0, 4 );
+
+    hlen = md_ctx->md_info->size;
+
+    // Generate and apply dbMask
+    //
+    p = dst;
+
+    while( dlen > 0 )
+    {
+        use_len = hlen;
+        if( dlen < hlen )
+            use_len = dlen;
+
+        md_starts( md_ctx );
+        md_update( md_ctx, src, slen );
+        md_update( md_ctx, counter, 4 );
+        md_finish( md_ctx, mask );
+
+        for( i = 0; i < use_len; ++i )
+            *p++ ^= mask[i];
+
+        counter[3]++;
+
+        dlen -= use_len;
+    }
+}
+#endif
+
+#if defined(POLARSSL_PKCS1_V21)
+/*
+ * Implementation of the PKCS#1 v2.1 RSAES-OAEP-ENCRYPT function
+ */
+int rsa_rsaes_oaep_encrypt( rsa_context *ctx,
+                            int (*f_rng)(void *, unsigned char *, size_t),
+                            void *p_rng,
+                            int mode,
+                            const unsigned char *label, size_t label_len,
+                            size_t ilen,
+                            const unsigned char *input,
+                            unsigned char *output )
+{
+    size_t olen;
+    int ret;
+    unsigned char *p = output;
+    unsigned int hlen;
+    const md_info_t *md_info;
+    md_context_t md_ctx;
+
+    if( ctx->padding != RSA_PKCS_V21 || f_rng == NULL )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    md_info = md_info_from_type( ctx->hash_id );
+
+    if( md_info == NULL )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    olen = ctx->len;
+    hlen = md_get_size( md_info );
+
+    if( olen < ilen + 2 * hlen + 2 || f_rng == NULL )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    memset( output, 0, olen );
+
+    *p++ = 0;
+
+    // Generate a random octet string seed
+    //
+    if( ( ret = f_rng( p_rng, p, hlen ) ) != 0 )
+        return( POLARSSL_ERR_RSA_RNG_FAILED + ret );
+
+    p += hlen;
+
+    // Construct DB
+    //
+    md( md_info, label, label_len, p );
+    p += hlen;
+    p += olen - 2 * hlen - 2 - ilen;
+    *p++ = 1;
+    memcpy( p, input, ilen );
+
+    md_init_ctx( &md_ctx, md_info );
+
+    // maskedDB: Apply dbMask to DB
+    //
+    mgf_mask( output + hlen + 1, olen - hlen - 1, output + 1, hlen,
+               &md_ctx );
+
+    // maskedSeed: Apply seedMask to seed
+    //
+    mgf_mask( output + 1, hlen, output + hlen + 1, olen - hlen - 1,
+               &md_ctx );
+
+    md_free_ctx( &md_ctx );
+
+    return( ( mode == RSA_PUBLIC )
+            ? rsa_public(  ctx, output, output )
+            : rsa_private( ctx, output, output ) );
+}
+#endif /* POLARSSL_PKCS1_V21 */
+
+/*
+ * Implementation of the PKCS#1 v2.1 RSAES-PKCS1-V1_5-ENCRYPT function
+ */
+int rsa_rsaes_pkcs1_v15_encrypt( rsa_context *ctx,
+                                 int (*f_rng)(void *, unsigned char *, size_t),
+                                 void *p_rng,
+                                 int mode, size_t ilen,
+                                 const unsigned char *input,
+                                 unsigned char *output )
+{
+    size_t nb_pad, olen;
+    int ret;
+    unsigned char *p = output;
+
+    if( ctx->padding != RSA_PKCS_V15 || f_rng == NULL )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    olen = ctx->len;
+
+    if( olen < ilen + 11 )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    nb_pad = olen - 3 - ilen;
+
+    *p++ = 0;
+    if( mode == RSA_PUBLIC )
+    {
+        *p++ = RSA_CRYPT;
+
+        while( nb_pad-- > 0 )
+        {
+            int rng_dl = 100;
+
+            do {
+                ret = f_rng( p_rng, p, 1 );
+            } while( *p == 0 && --rng_dl && ret == 0 );
+
+            // Check if RNG failed to generate data
+            //
+            if( rng_dl == 0 || ret != 0)
+                return POLARSSL_ERR_RSA_RNG_FAILED + ret;
+
+            p++;
+        }
+    }
+    else
+    {
+        *p++ = RSA_SIGN;
+
+        while( nb_pad-- > 0 )
+            *p++ = 0xFF;
+    }
+
+    *p++ = 0;
+    memcpy( p, input, ilen );
+
+    return( ( mode == RSA_PUBLIC )
+            ? rsa_public(  ctx, output, output )
+            : rsa_private( ctx, output, output ) );
+}
+
+/*
+ * Add the message padding, then do an RSA operation
+ */
+int rsa_pkcs1_encrypt( rsa_context *ctx,
+                       int (*f_rng)(void *, unsigned char *, size_t),
+                       void *p_rng,
+                       int mode, size_t ilen,
+                       const unsigned char *input,
+                       unsigned char *output )
+{
+    switch( ctx->padding )
+    {
+        case RSA_PKCS_V15:
+            return rsa_rsaes_pkcs1_v15_encrypt( ctx, f_rng, p_rng, mode, ilen,
+                                                input, output );
+
+#if defined(POLARSSL_PKCS1_V21)
+        case RSA_PKCS_V21:
+            return rsa_rsaes_oaep_encrypt( ctx, f_rng, p_rng, mode, NULL, 0,
+                                           ilen, input, output );
+#endif
+
+        default:
+            return( POLARSSL_ERR_RSA_INVALID_PADDING );
+    }
+}
+
+#if defined(POLARSSL_PKCS1_V21)
+/*
+ * Implementation of the PKCS#1 v2.1 RSAES-OAEP-DECRYPT function
+ */
+int rsa_rsaes_oaep_decrypt( rsa_context *ctx,
+                            int mode, 
+                            const unsigned char *label, size_t label_len,
+                            size_t *olen,
+                            const unsigned char *input,
+                            unsigned char *output,
+                            size_t output_max_len )
+{
+    int ret;
+    size_t ilen;
+    unsigned char *p;
+    unsigned char buf[POLARSSL_MPI_MAX_SIZE];
+    unsigned char lhash[POLARSSL_MD_MAX_SIZE];
+    unsigned int hlen;
+    const md_info_t *md_info;
+    md_context_t md_ctx;
+
+    if( ctx->padding != RSA_PKCS_V21 )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    ilen = ctx->len;
+
+    if( ilen < 16 || ilen > sizeof( buf ) )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    ret = ( mode == RSA_PUBLIC )
+          ? rsa_public(  ctx, input, buf )
+          : rsa_private( ctx, input, buf );
+
+    if( ret != 0 )
+        return( ret );
+
+    p = buf;
+
+    if( *p++ != 0 )
+        return( POLARSSL_ERR_RSA_INVALID_PADDING );
+
+    md_info = md_info_from_type( ctx->hash_id );
+    if( md_info == NULL )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    hlen = md_get_size( md_info );
+
+    md_init_ctx( &md_ctx, md_info );
+
+    // Generate lHash
+    //
+    md( md_info, label, label_len, lhash );
+
+    // seed: Apply seedMask to maskedSeed
+    //
+    mgf_mask( buf + 1, hlen, buf + hlen + 1, ilen - hlen - 1,
+               &md_ctx );
+
+    // DB: Apply dbMask to maskedDB
+    //
+    mgf_mask( buf + hlen + 1, ilen - hlen - 1, buf + 1, hlen,
+               &md_ctx );
+
+    p += hlen;
+    md_free_ctx( &md_ctx );
+
+    // Check validity
+    //
+    if( memcmp( lhash, p, hlen ) != 0 )
+        return( POLARSSL_ERR_RSA_INVALID_PADDING );
+
+    p += hlen;
+
+    while( *p == 0 && p < buf + ilen )
+        p++;
+
+    if( p == buf + ilen )
+        return( POLARSSL_ERR_RSA_INVALID_PADDING );
+
+    if( *p++ != 0x01 )
+        return( POLARSSL_ERR_RSA_INVALID_PADDING );
+
+    if (ilen - (p - buf) > output_max_len)
+        return( POLARSSL_ERR_RSA_OUTPUT_TOO_LARGE );
+
+    *olen = ilen - (p - buf);
+    memcpy( output, p, *olen );
+
+    return( 0 );
+}
+#endif /* POLARSSL_PKCS1_V21 */
+
+/*
+ * Implementation of the PKCS#1 v2.1 RSAES-PKCS1-V1_5-DECRYPT function
+ */
+int rsa_rsaes_pkcs1_v15_decrypt( rsa_context *ctx,
+                                 int mode, size_t *olen,
+                                 const unsigned char *input,
+                                 unsigned char *output,
+                                 size_t output_max_len)
+{
+    int ret, correct = 1;
+    size_t ilen, pad_count = 0;
+    unsigned char *p, *q;
+    unsigned char bt;
+    unsigned char buf[POLARSSL_MPI_MAX_SIZE];
+
+    if( ctx->padding != RSA_PKCS_V15 )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    ilen = ctx->len;
+
+    if( ilen < 16 || ilen > sizeof( buf ) )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    ret = ( mode == RSA_PUBLIC )
+          ? rsa_public(  ctx, input, buf )
+          : rsa_private( ctx, input, buf );
+
+    if( ret != 0 )
+        return( ret );
+
+    p = buf;
+
+    if( *p++ != 0 )
+        correct = 0;
+
+    bt = *p++;
+    if( ( bt != RSA_CRYPT && mode == RSA_PRIVATE ) ||
+        ( bt != RSA_SIGN && mode == RSA_PUBLIC ) )
+    {
+        correct = 0;
+    }
+
+    if( bt == RSA_CRYPT )
+    {
+        while( *p != 0 && p < buf + ilen - 1 )
+            pad_count += ( *p++ != 0 );
+
+        correct &= ( *p == 0 && p < buf + ilen - 1 );
+
+        q = p;
+
+        // Also pass over all other bytes to reduce timing differences
+        //
+        while ( q < buf + ilen - 1 )
+            pad_count += ( *q++ != 0 );
+
+        // Prevent compiler optimization of pad_count
+        //
+        correct |= pad_count & 0x100000; /* Always 0 unless 1M bit keys */
+        p++;
+    }
+    else
+    {
+        while( *p == 0xFF && p < buf + ilen - 1 )
+            pad_count += ( *p++ == 0xFF );
+
+        correct &= ( *p == 0 && p < buf + ilen - 1 );
+
+        q = p;
+
+        // Also pass over all other bytes to reduce timing differences
+        //
+        while ( q < buf + ilen - 1 )
+            pad_count += ( *q++ != 0 );
+
+        // Prevent compiler optimization of pad_count
+        //
+        correct |= pad_count & 0x100000; /* Always 0 unless 1M bit keys */
+        p++;
+    }
+
+    if( correct == 0 )
+        return( POLARSSL_ERR_RSA_INVALID_PADDING );
+
+    if (ilen - (p - buf) > output_max_len)
+        return( POLARSSL_ERR_RSA_OUTPUT_TOO_LARGE );
+
+    *olen = ilen - (p - buf);
+    memcpy( output, p, *olen );
+
+    return( 0 );
+}
+
+/*
+ * Do an RSA operation, then remove the message padding
+ */
+int rsa_pkcs1_decrypt( rsa_context *ctx,
+                       int mode, size_t *olen,
+                       const unsigned char *input,
+                       unsigned char *output,
+                       size_t output_max_len)
+{
+    switch( ctx->padding )
+    {
+        case RSA_PKCS_V15:
+            return rsa_rsaes_pkcs1_v15_decrypt( ctx, mode, olen, input, output,
+                                                output_max_len );
+
+#if defined(POLARSSL_PKCS1_V21)
+        case RSA_PKCS_V21:
+            return rsa_rsaes_oaep_decrypt( ctx, mode, NULL, 0, olen, input,
+                                           output, output_max_len );
+#endif
+
+        default:
+            return( POLARSSL_ERR_RSA_INVALID_PADDING );
+    }
+}
+
+#if defined(POLARSSL_PKCS1_V21)
+/*
+ * Implementation of the PKCS#1 v2.1 RSASSA-PSS-SIGN function
+ */
+int rsa_rsassa_pss_sign( rsa_context *ctx,
+                         int (*f_rng)(void *, unsigned char *, size_t),
+                         void *p_rng,
+                         int mode,
+                         int hash_id,
+                         unsigned int hashlen,
+                         const unsigned char *hash,
+                         unsigned char *sig )
+{
+    size_t olen;
+    unsigned char *p = sig;
+    unsigned char salt[POLARSSL_MD_MAX_SIZE];
+    unsigned int slen, hlen, offset = 0;
+    int ret;
+    size_t msb;
+    const md_info_t *md_info;
+    md_context_t md_ctx;
+
+    if( ctx->padding != RSA_PKCS_V21 || f_rng == NULL )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    olen = ctx->len;
+
+    switch( hash_id )
+    {
+        case SIG_RSA_MD2:
+        case SIG_RSA_MD4:
+        case SIG_RSA_MD5:
+            hashlen = 16;
+            break;
+
+        case SIG_RSA_SHA1:
+            hashlen = 20;
+            break;
+
+        case SIG_RSA_SHA224:
+            hashlen = 28;
+            break;
+
+        case SIG_RSA_SHA256:
+            hashlen = 32;
+            break;
+
+        case SIG_RSA_SHA384:
+            hashlen = 48;
+            break;
+
+        case SIG_RSA_SHA512:
+            hashlen = 64;
+            break;
+
+        default:
+            return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+    }
+
+    md_info = md_info_from_type( ctx->hash_id );
+    if( md_info == NULL )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    hlen = md_get_size( md_info );
+    slen = hlen;
+
+    if( olen < hlen + slen + 2 )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    memset( sig, 0, olen );
+
+    msb = mpi_msb( &ctx->N ) - 1;
+
+    // Generate salt of length slen
+    //
+    if( ( ret = f_rng( p_rng, salt, slen ) ) != 0 )
+        return( POLARSSL_ERR_RSA_RNG_FAILED + ret );
+
+    // Note: EMSA-PSS encoding is over the length of N - 1 bits
+    //
+    msb = mpi_msb( &ctx->N ) - 1;
+    p += olen - hlen * 2 - 2;
+    *p++ = 0x01;
+    memcpy( p, salt, slen );
+    p += slen;
+
+    md_init_ctx( &md_ctx, md_info );
+
+    // Generate H = Hash( M' )
+    //
+    md_starts( &md_ctx );
+    md_update( &md_ctx, p, 8 );
+    md_update( &md_ctx, hash, hashlen );
+    md_update( &md_ctx, salt, slen );
+    md_finish( &md_ctx, p );
+
+    // Compensate for boundary condition when applying mask
+    //
+    if( msb % 8 == 0 )
+        offset = 1;
+
+    // maskedDB: Apply dbMask to DB
+    //
+    mgf_mask( sig + offset, olen - hlen - 1 - offset, p, hlen, &md_ctx );
+
+    md_free_ctx( &md_ctx );
+
+    msb = mpi_msb( &ctx->N ) - 1;
+    sig[0] &= 0xFF >> ( olen * 8 - msb );
+
+    p += hlen;
+    *p++ = 0xBC;
+
+    return( ( mode == RSA_PUBLIC )
+            ? rsa_public(  ctx, sig, sig )
+            : rsa_private( ctx, sig, sig ) );
+}
+#endif /* POLARSSL_PKCS1_V21 */
+
+/*
+ * Implementation of the PKCS#1 v2.1 RSASSA-PKCS1-V1_5-SIGN function
+ */
+/*
+ * Do an RSA operation to sign the message digest
+ */
+int rsa_rsassa_pkcs1_v15_sign( rsa_context *ctx,
+                               int mode,
+                               int hash_id,
+                               unsigned int hashlen,
+                               const unsigned char *hash,
+                               unsigned char *sig )
+{
+    size_t nb_pad, olen;
+    unsigned char *p = sig;
+
+    if( ctx->padding != RSA_PKCS_V15 )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    olen = ctx->len;
+
+    switch( hash_id )
+    {
+        case SIG_RSA_RAW:
+            nb_pad = olen - 3 - hashlen;
+            break;
+
+        case SIG_RSA_MD2:
+        case SIG_RSA_MD4:
+        case SIG_RSA_MD5:
+            nb_pad = olen - 3 - 34;
+            break;
+
+        case SIG_RSA_SHA1:
+            nb_pad = olen - 3 - 35;
+            break;
+
+        case SIG_RSA_SHA224:
+            nb_pad = olen - 3 - 47;
+            break;
+
+        case SIG_RSA_SHA256:
+            nb_pad = olen - 3 - 51;
+            break;
+
+        case SIG_RSA_SHA384:
+            nb_pad = olen - 3 - 67;
+            break;
+
+        case SIG_RSA_SHA512:
+            nb_pad = olen - 3 - 83;
+            break;
+
+
+        default:
+            return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+    }
+
+    if( ( nb_pad < 8 ) || ( nb_pad > olen ) )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    *p++ = 0;
+    *p++ = RSA_SIGN;
+    memset( p, 0xFF, nb_pad );
+    p += nb_pad;
+    *p++ = 0;
+
+    switch( hash_id )
+    {
+        case SIG_RSA_RAW:
+            memcpy( p, hash, hashlen );
+            break;
+
+        case SIG_RSA_MD2:
+            memcpy( p, ASN1_HASH_MDX, 18 );
+            memcpy( p + 18, hash, 16 );
+            p[13] = 2; break;
+
+        case SIG_RSA_MD4:
+            memcpy( p, ASN1_HASH_MDX, 18 );
+            memcpy( p + 18, hash, 16 );
+            p[13] = 4; break;
+
+        case SIG_RSA_MD5:
+            memcpy( p, ASN1_HASH_MDX, 18 );
+            memcpy( p + 18, hash, 16 );
+            p[13] = 5; break;
+
+        case SIG_RSA_SHA1:
+            memcpy( p, ASN1_HASH_SHA1, 15 );
+            memcpy( p + 15, hash, 20 );
+            break;
+
+        case SIG_RSA_SHA224:
+            memcpy( p, ASN1_HASH_SHA2X, 19 );
+            memcpy( p + 19, hash, 28 );
+            p[1] += 28; p[14] = 4; p[18] += 28; break;
+
+        case SIG_RSA_SHA256:
+            memcpy( p, ASN1_HASH_SHA2X, 19 );
+            memcpy( p + 19, hash, 32 );
+            p[1] += 32; p[14] = 1; p[18] += 32; break;
+
+        case SIG_RSA_SHA384:
+            memcpy( p, ASN1_HASH_SHA2X, 19 );
+            memcpy( p + 19, hash, 48 );
+            p[1] += 48; p[14] = 2; p[18] += 48; break;
+
+        case SIG_RSA_SHA512:
+            memcpy( p, ASN1_HASH_SHA2X, 19 );
+            memcpy( p + 19, hash, 64 );
+            p[1] += 64; p[14] = 3; p[18] += 64; break;
+
+        default:
+            return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+    }
+
+    return( ( mode == RSA_PUBLIC )
+            ? rsa_public(  ctx, sig, sig )
+            : rsa_private( ctx, sig, sig ) );
+}
+
+/*
+ * Do an RSA operation to sign the message digest
+ */
+int rsa_pkcs1_sign( rsa_context *ctx,
+                    int (*f_rng)(void *, unsigned char *, size_t),
+                    void *p_rng,
+                    int mode,
+                    int hash_id,
+                    unsigned int hashlen,
+                    const unsigned char *hash,
+                    unsigned char *sig )
+{
+    switch( ctx->padding )
+    {
+        case RSA_PKCS_V15:
+            return rsa_rsassa_pkcs1_v15_sign( ctx, mode, hash_id,
+                                              hashlen, hash, sig );
+
+#if defined(POLARSSL_PKCS1_V21)
+        case RSA_PKCS_V21:
+            return rsa_rsassa_pss_sign( ctx, f_rng, p_rng, mode, hash_id,
+                                        hashlen, hash, sig );
+#endif
+
+        default:
+            return( POLARSSL_ERR_RSA_INVALID_PADDING );
+    }
+}
+
+#if defined(POLARSSL_PKCS1_V21)
+/*
+ * Implementation of the PKCS#1 v2.1 RSASSA-PSS-VERIFY function
+ */
+int rsa_rsassa_pss_verify( rsa_context *ctx,
+                           int mode,
+                           int hash_id,
+                           unsigned int hashlen,
+                           const unsigned char *hash,
+                           unsigned char *sig )
+{
+    int ret;
+    size_t siglen;
+    unsigned char *p;
+    unsigned char buf[POLARSSL_MPI_MAX_SIZE];
+    unsigned char result[POLARSSL_MD_MAX_SIZE];
+    unsigned char zeros[8];
+    unsigned int hlen;
+    size_t slen, msb;
+    const md_info_t *md_info;
+    md_context_t md_ctx;
+
+    if( ctx->padding != RSA_PKCS_V21 )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    siglen = ctx->len;
+
+    if( siglen < 16 || siglen > sizeof( buf ) )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    ret = ( mode == RSA_PUBLIC )
+          ? rsa_public(  ctx, sig, buf )
+          : rsa_private( ctx, sig, buf );
+
+    if( ret != 0 )
+        return( ret );
+
+    p = buf;
+
+    if( buf[siglen - 1] != 0xBC )
+        return( POLARSSL_ERR_RSA_INVALID_PADDING );
+
+    switch( hash_id )
+    {
+        case SIG_RSA_MD2:
+        case SIG_RSA_MD4:
+        case SIG_RSA_MD5:
+            hashlen = 16;
+            break;
+
+        case SIG_RSA_SHA1:
+            hashlen = 20;
+            break;
+
+        case SIG_RSA_SHA224:
+            hashlen = 28;
+            break;
+
+        case SIG_RSA_SHA256:
+            hashlen = 32;
+            break;
+
+        case SIG_RSA_SHA384:
+            hashlen = 48;
+            break;
+
+        case SIG_RSA_SHA512:
+            hashlen = 64;
+            break;
+
+        default:
+            return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+    }
+
+    md_info = md_info_from_type( ctx->hash_id );
+    if( md_info == NULL )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    hlen = md_get_size( md_info );
+    slen = siglen - hlen - 1;
+
+    memset( zeros, 0, 8 );
+
+    // Note: EMSA-PSS verification is over the length of N - 1 bits
+    //
+    msb = mpi_msb( &ctx->N ) - 1;
+
+    // Compensate for boundary condition when applying mask
+    //
+    if( msb % 8 == 0 )
+    {
+        p++;
+        siglen -= 1;
+    }
+    if( buf[0] >> ( 8 - siglen * 8 + msb ) )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    md_init_ctx( &md_ctx, md_info );
+
+    mgf_mask( p, siglen - hlen - 1, p + siglen - hlen - 1, hlen, &md_ctx );
+
+    buf[0] &= 0xFF >> ( siglen * 8 - msb );
+
+    while( *p == 0 && p < buf + siglen )
+        p++;
+
+    if( p == buf + siglen ||
+        *p++ != 0x01 )
+    {
+        md_free_ctx( &md_ctx );
+        return( POLARSSL_ERR_RSA_INVALID_PADDING );
+    }
+
+    slen -= p - buf;
+
+    // Generate H = Hash( M' )
+    //
+    md_starts( &md_ctx );
+    md_update( &md_ctx, zeros, 8 );
+    md_update( &md_ctx, hash, hashlen );
+    md_update( &md_ctx, p, slen );
+    md_finish( &md_ctx, result );
+
+    md_free_ctx( &md_ctx );
+
+    if( memcmp( p + slen, result, hlen ) == 0 )
+        return( 0 );
+    else
+        return( POLARSSL_ERR_RSA_VERIFY_FAILED );
+}
+#endif /* POLARSSL_PKCS1_V21 */
+
+/*
+ * Implementation of the PKCS#1 v2.1 RSASSA-PKCS1-v1_5-VERIFY function
+ */
+int rsa_rsassa_pkcs1_v15_verify( rsa_context *ctx,
+                                 int mode,
+                                 int hash_id,
+                                 unsigned int hashlen,
+                                 const unsigned char *hash,
+                                 unsigned char *sig )
+{
+    int ret;
+    size_t len, siglen;
+    unsigned char *p, c;
+    unsigned char buf[POLARSSL_MPI_MAX_SIZE];
+
+    if( ctx->padding != RSA_PKCS_V15 )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    siglen = ctx->len;
+
+    if( siglen < 16 || siglen > sizeof( buf ) )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    ret = ( mode == RSA_PUBLIC )
+          ? rsa_public(  ctx, sig, buf )
+          : rsa_private( ctx, sig, buf );
+
+    if( ret != 0 )
+        return( ret );
+
+    p = buf;
+
+    if( *p++ != 0 || *p++ != RSA_SIGN )
+        return( POLARSSL_ERR_RSA_INVALID_PADDING );
+
+    while( *p != 0 )
+    {
+        if( p >= buf + siglen - 1 || *p != 0xFF )
+            return( POLARSSL_ERR_RSA_INVALID_PADDING );
+        p++;
+    }
+    p++;
+
+    len = siglen - ( p - buf );
+
+    if( len == 33 && hash_id == SIG_RSA_SHA1 )
+    {
+        if( memcmp( p, ASN1_HASH_SHA1_ALT, 13 ) == 0 &&
+                memcmp( p + 13, hash, 20 ) == 0 )
+            return( 0 );
+        else
+            return( POLARSSL_ERR_RSA_VERIFY_FAILED );
+    }
+    if( len == 34 )
+    {
+        c = p[13];
+        p[13] = 0;
+
+        if( memcmp( p, ASN1_HASH_MDX, 18 ) != 0 )
+            return( POLARSSL_ERR_RSA_VERIFY_FAILED );
+
+        if( ( c == 2 && hash_id == SIG_RSA_MD2 ) ||
+                ( c == 4 && hash_id == SIG_RSA_MD4 ) ||
+                ( c == 5 && hash_id == SIG_RSA_MD5 ) )
+        {
+            if( memcmp( p + 18, hash, 16 ) == 0 )
+                return( 0 );
+            else
+                return( POLARSSL_ERR_RSA_VERIFY_FAILED );
+        }
+    }
+
+    if( len == 35 && hash_id == SIG_RSA_SHA1 )
+    {
+        if( memcmp( p, ASN1_HASH_SHA1, 15 ) == 0 &&
+                memcmp( p + 15, hash, 20 ) == 0 )
+            return( 0 );
+        else
+            return( POLARSSL_ERR_RSA_VERIFY_FAILED );
+    }
+    if( ( len == 19 + 28 && p[14] == 4 && hash_id == SIG_RSA_SHA224 ) ||
+            ( len == 19 + 32 && p[14] == 1 && hash_id == SIG_RSA_SHA256 ) ||
+            ( len == 19 + 48 && p[14] == 2 && hash_id == SIG_RSA_SHA384 ) ||
+            ( len == 19 + 64 && p[14] == 3 && hash_id == SIG_RSA_SHA512 ) )
+    {
+        c = p[1] - 17;
+        p[1] = 17;
+        p[14] = 0;
+
+        if( p[18] == c &&
+                memcmp( p, ASN1_HASH_SHA2X, 18 ) == 0 &&
+                memcmp( p + 19, hash, c ) == 0 )
+            return( 0 );
+        else
+            return( POLARSSL_ERR_RSA_VERIFY_FAILED );
+    }
+
+    if( len == hashlen && hash_id == SIG_RSA_RAW )
+    {
+        if( memcmp( p, hash, hashlen ) == 0 )
+            return( 0 );
+        else
+            return( POLARSSL_ERR_RSA_VERIFY_FAILED );
+    }
+
+    return( POLARSSL_ERR_RSA_INVALID_PADDING );
+}
+
+/*
+ * Do an RSA operation and check the message digest
+ */
+int rsa_pkcs1_verify( rsa_context *ctx,
+                      int mode,
+                      int hash_id,
+                      unsigned int hashlen,
+                      const unsigned char *hash,
+                      unsigned char *sig )
+{
+    switch( ctx->padding )
+    {
+        case RSA_PKCS_V15:
+            return rsa_rsassa_pkcs1_v15_verify( ctx, mode, hash_id,
+                                                hashlen, hash, sig );
+
+#if defined(POLARSSL_PKCS1_V21)
+        case RSA_PKCS_V21:
+            return rsa_rsassa_pss_verify( ctx, mode, hash_id,
+                                          hashlen, hash, sig );
+#endif
+
+        default:
+            return( POLARSSL_ERR_RSA_INVALID_PADDING );
+    }
+}
+
+/*
+ * Free the components of an RSA key
+ */
+void rsa_free( rsa_context *ctx )
+{
+    mpi_free( &ctx->RQ ); mpi_free( &ctx->RP ); mpi_free( &ctx->RN );
+    mpi_free( &ctx->QP ); mpi_free( &ctx->DQ ); mpi_free( &ctx->DP );
+    mpi_free( &ctx->Q  ); mpi_free( &ctx->P  ); mpi_free( &ctx->D );
+    mpi_free( &ctx->E  ); mpi_free( &ctx->N  );
+}
+
+#if defined(POLARSSL_SELF_TEST)
+
+#include "polarssl/sha1.h"
+
+/*
+ * Example RSA-1024 keypair, for test purposes
+ */
+#define KEY_LEN 128
+
+#define RSA_N   "9292758453063D803DD603D5E777D788" \
+                "8ED1D5BF35786190FA2F23EBC0848AEA" \
+                "DDA92CA6C3D80B32C4D109BE0F36D6AE" \
+                "7130B9CED7ACDF54CFC7555AC14EEBAB" \
+                "93A89813FBF3C4F8066D2D800F7C38A8" \
+                "1AE31942917403FF4946B0A83D3D3E05" \
+                "EE57C6F5F5606FB5D4BC6CD34EE0801A" \
+                "5E94BB77B07507233A0BC7BAC8F90F79"
+
+#define RSA_E   "10001"
+
+#define RSA_D   "24BF6185468786FDD303083D25E64EFC" \
+                "66CA472BC44D253102F8B4A9D3BFA750" \
+                "91386C0077937FE33FA3252D28855837" \
+                "AE1B484A8A9A45F7EE8C0C634F99E8CD" \
+                "DF79C5CE07EE72C7F123142198164234" \
+                "CABB724CF78B8173B9F880FC86322407" \
+                "AF1FEDFDDE2BEB674CA15F3E81A1521E" \
+                "071513A1E85B5DFA031F21ECAE91A34D"
+
+#define RSA_P   "C36D0EB7FCD285223CFB5AABA5BDA3D8" \
+                "2C01CAD19EA484A87EA4377637E75500" \
+                "FCB2005C5C7DD6EC4AC023CDA285D796" \
+                "C3D9E75E1EFC42488BB4F1D13AC30A57"
+
+#define RSA_Q   "C000DF51A7C77AE8D7C7370C1FF55B69" \
+                "E211C2B9E5DB1ED0BF61D0D9899620F4" \
+                "910E4168387E3C30AA1E00C339A79508" \
+                "8452DD96A9A5EA5D9DCA68DA636032AF"
+
+#define RSA_DP  "C1ACF567564274FB07A0BBAD5D26E298" \
+                "3C94D22288ACD763FD8E5600ED4A702D" \
+                "F84198A5F06C2E72236AE490C93F07F8" \
+                "3CC559CD27BC2D1CA488811730BB5725"
+
+#define RSA_DQ  "4959CBF6F8FEF750AEE6977C155579C7" \
+                "D8AAEA56749EA28623272E4F7D0592AF" \
+                "7C1F1313CAC9471B5C523BFE592F517B" \
+                "407A1BD76C164B93DA2D32A383E58357"
+
+#define RSA_QP  "9AE7FBC99546432DF71896FC239EADAE" \
+                "F38D18D2B2F0E2DD275AA977E2BF4411" \
+                "F5A3B2A5D33605AEBBCCBA7FEB9F2D2F" \
+                "A74206CEC169D74BF5A8C50D6F48EA08"
+
+#define PT_LEN  24
+#define RSA_PT  "\xAA\xBB\xCC\x03\x02\x01\x00\xFF\xFF\xFF\xFF\xFF" \
+                "\x11\x22\x33\x0A\x0B\x0C\xCC\xDD\xDD\xDD\xDD\xDD"
+
+static int myrand( void *rng_state, unsigned char *output, size_t len )
+{
+    size_t i;
+
+    if( rng_state != NULL )
+        rng_state  = NULL;
+
+    for( i = 0; i < len; ++i )
+        output[i] = rand();
+    
+    return( 0 );
+}
+
+/*
+ * Checkup routine
+ */
+int rsa_self_test( int verbose )
+{
+    size_t len;
+    rsa_context rsa;
+    unsigned char rsa_plaintext[PT_LEN];
+    unsigned char rsa_decrypted[PT_LEN];
+    unsigned char rsa_ciphertext[KEY_LEN];
+#if defined(POLARSSL_SHA1_C)
+    unsigned char sha1sum[20];
+#endif
+
+    rsa_init( &rsa, RSA_PKCS_V15, 0 );
+
+    rsa.len = KEY_LEN;
+    mpi_read_string( &rsa.N , 16, RSA_N  );
+    mpi_read_string( &rsa.E , 16, RSA_E  );
+    mpi_read_string( &rsa.D , 16, RSA_D  );
+    mpi_read_string( &rsa.P , 16, RSA_P  );
+    mpi_read_string( &rsa.Q , 16, RSA_Q  );
+    mpi_read_string( &rsa.DP, 16, RSA_DP );
+    mpi_read_string( &rsa.DQ, 16, RSA_DQ );
+    mpi_read_string( &rsa.QP, 16, RSA_QP );
+
+    if( verbose != 0 )
+        printf( "  RSA key validation: " );
+
+    if( rsa_check_pubkey(  &rsa ) != 0 ||
+        rsa_check_privkey( &rsa ) != 0 )
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( 1 );
+    }
+
+    if( verbose != 0 )
+        printf( "passed\n  PKCS#1 encryption : " );
+
+    memcpy( rsa_plaintext, RSA_PT, PT_LEN );
+
+    if( rsa_pkcs1_encrypt( &rsa, &myrand, NULL, RSA_PUBLIC, PT_LEN,
+                           rsa_plaintext, rsa_ciphertext ) != 0 )
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( 1 );
+    }
+
+    if( verbose != 0 )
+        printf( "passed\n  PKCS#1 decryption : " );
+
+    if( rsa_pkcs1_decrypt( &rsa, RSA_PRIVATE, &len,
+                           rsa_ciphertext, rsa_decrypted,
+                           sizeof(rsa_decrypted) ) != 0 )
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( 1 );
+    }
+
+    if( memcmp( rsa_decrypted, rsa_plaintext, len ) != 0 )
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( 1 );
+    }
+
+#if defined(POLARSSL_SHA1_C)
+    if( verbose != 0 )
+        printf( "passed\n  PKCS#1 data sign  : " );
+
+    sha1( rsa_plaintext, PT_LEN, sha1sum );
+
+    if( rsa_pkcs1_sign( &rsa, NULL, NULL, RSA_PRIVATE, SIG_RSA_SHA1, 20,
+                        sha1sum, rsa_ciphertext ) != 0 )
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( 1 );
+    }
+
+    if( verbose != 0 )
+        printf( "passed\n  PKCS#1 sig. verify: " );
+
+    if( rsa_pkcs1_verify( &rsa, RSA_PUBLIC, SIG_RSA_SHA1, 20,
+                          sha1sum, rsa_ciphertext ) != 0 )
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( 1 );
+    }
+
+    if( verbose != 0 )
+        printf( "passed\n\n" );
+#endif /* POLARSSL_SHA1_C */
+
+    rsa_free( &rsa );
+
+    return( 0 );
+}
+
+#endif
+
+#endif
diff --git a/common/polarssl/rsa.h b/common/polarssl/rsa.h
new file mode 100644 (file)
index 0000000..f9a0220
--- /dev/null
@@ -0,0 +1,597 @@
+/**
+ * \file rsa.h
+ *
+ * \brief The RSA public-key cryptosystem
+ *
+ *  Copyright (C) 2006-2010, Brainspark B.V.
+ *
+ *  This file is part of PolarSSL (http://www.polarssl.org)
+ *  Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
+ *
+ *  All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef POLARSSL_RSA_H
+#define POLARSSL_RSA_H
+
+#include "bignum.h"
+
+/*
+ * RSA Error codes
+ */
+#define POLARSSL_ERR_RSA_BAD_INPUT_DATA                    -0x4080  /**< Bad input parameters to function. */
+#define POLARSSL_ERR_RSA_INVALID_PADDING                   -0x4100  /**< Input data contains invalid padding and is rejected. */
+#define POLARSSL_ERR_RSA_KEY_GEN_FAILED                    -0x4180  /**< Something failed during generation of a key. */
+#define POLARSSL_ERR_RSA_KEY_CHECK_FAILED                  -0x4200  /**< Key failed to pass the libraries validity check. */
+#define POLARSSL_ERR_RSA_PUBLIC_FAILED                     -0x4280  /**< The public key operation failed. */
+#define POLARSSL_ERR_RSA_PRIVATE_FAILED                    -0x4300  /**< The private key operation failed. */
+#define POLARSSL_ERR_RSA_VERIFY_FAILED                     -0x4380  /**< The PKCS#1 verification failed. */
+#define POLARSSL_ERR_RSA_OUTPUT_TOO_LARGE                  -0x4400  /**< The output buffer for decryption is not large enough. */
+#define POLARSSL_ERR_RSA_RNG_FAILED                        -0x4480  /**< The random generator failed to generate non-zeros. */
+
+/*
+ * PKCS#1 constants
+ */
+#define SIG_RSA_RAW     0
+#define SIG_RSA_MD2     2
+#define SIG_RSA_MD4     3
+#define SIG_RSA_MD5     4
+#define SIG_RSA_SHA1    5
+#define SIG_RSA_SHA224 14
+#define SIG_RSA_SHA256 11
+#define SIG_RSA_SHA384 12
+#define SIG_RSA_SHA512 13
+
+#define RSA_PUBLIC      0
+#define RSA_PRIVATE     1
+
+#define RSA_PKCS_V15    0
+#define RSA_PKCS_V21    1
+
+#define RSA_SIGN        1
+#define RSA_CRYPT       2
+
+#define ASN1_STR_CONSTRUCTED_SEQUENCE   "\x30"
+#define ASN1_STR_NULL                   "\x05"
+#define ASN1_STR_OID                    "\x06"
+#define ASN1_STR_OCTET_STRING           "\x04"
+
+#define OID_DIGEST_ALG_MDX              "\x2A\x86\x48\x86\xF7\x0D\x02\x00"
+#define OID_HASH_ALG_SHA1               "\x2b\x0e\x03\x02\x1a"
+#define OID_HASH_ALG_SHA2X              "\x60\x86\x48\x01\x65\x03\x04\x02\x00"
+
+#define OID_ISO_MEMBER_BODIES           "\x2a"
+#define OID_ISO_IDENTIFIED_ORG          "\x2b"
+
+/*
+ * ISO Member bodies OID parts
+ */
+#define OID_COUNTRY_US                  "\x86\x48"
+#define OID_RSA_DATA_SECURITY           "\x86\xf7\x0d"
+
+/*
+ * ISO Identified organization OID parts
+ */
+#define OID_OIW_SECSIG_SHA1             "\x0e\x03\x02\x1a"
+
+/*
+ * DigestInfo ::= SEQUENCE {
+ *   digestAlgorithm DigestAlgorithmIdentifier,
+ *   digest Digest }
+ *
+ * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
+ *
+ * Digest ::= OCTET STRING
+ */
+#define ASN1_HASH_MDX                           \
+(                                               \
+    ASN1_STR_CONSTRUCTED_SEQUENCE "\x20"        \
+      ASN1_STR_CONSTRUCTED_SEQUENCE "\x0C"      \
+        ASN1_STR_OID "\x08"                     \
+      OID_DIGEST_ALG_MDX                        \
+    ASN1_STR_NULL "\x00"                        \
+      ASN1_STR_OCTET_STRING "\x10"              \
+)
+
+#define ASN1_HASH_SHA1                          \
+    ASN1_STR_CONSTRUCTED_SEQUENCE "\x21"        \
+      ASN1_STR_CONSTRUCTED_SEQUENCE "\x09"      \
+        ASN1_STR_OID "\x05"                     \
+      OID_HASH_ALG_SHA1                         \
+        ASN1_STR_NULL "\x00"                    \
+      ASN1_STR_OCTET_STRING "\x14"
+
+#define ASN1_HASH_SHA1_ALT                      \
+    ASN1_STR_CONSTRUCTED_SEQUENCE "\x1F"        \
+      ASN1_STR_CONSTRUCTED_SEQUENCE "\x07"      \
+        ASN1_STR_OID "\x05"                     \
+      OID_HASH_ALG_SHA1                         \
+      ASN1_STR_OCTET_STRING "\x14"
+
+#define ASN1_HASH_SHA2X                         \
+    ASN1_STR_CONSTRUCTED_SEQUENCE "\x11"        \
+      ASN1_STR_CONSTRUCTED_SEQUENCE "\x0d"      \
+        ASN1_STR_OID "\x09"                     \
+      OID_HASH_ALG_SHA2X                        \
+        ASN1_STR_NULL "\x00"                    \
+      ASN1_STR_OCTET_STRING "\x00"
+
+/**
+ * \brief          RSA context structure
+ */
+typedef struct
+{
+    int ver;                    /*!<  always 0          */
+    size_t len;                 /*!<  size(N) in chars  */
+
+    mpi N;                      /*!<  public modulus    */
+    mpi E;                      /*!<  public exponent   */
+
+    mpi D;                      /*!<  private exponent  */
+    mpi P;                      /*!<  1st prime factor  */
+    mpi Q;                      /*!<  2nd prime factor  */
+    mpi DP;                     /*!<  D % (P - 1)       */
+    mpi DQ;                     /*!<  D % (Q - 1)       */
+    mpi QP;                     /*!<  1 / (Q % P)       */
+
+    mpi RN;                     /*!<  cached R^2 mod N  */
+    mpi RP;                     /*!<  cached R^2 mod P  */
+    mpi RQ;                     /*!<  cached R^2 mod Q  */
+
+    int padding;                /*!<  RSA_PKCS_V15 for 1.5 padding and
+                                      RSA_PKCS_v21 for OAEP/PSS         */
+    int hash_id;                /*!<  Hash identifier of md_type_t as
+                                      specified in the md.h header file
+                                      for the EME-OAEP and EMSA-PSS
+                                      encoding                          */
+}
+rsa_context;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief          Initialize an RSA context
+ *
+ *                 Note: Set padding to RSA_PKCS_V21 for the RSAES-OAEP
+ *                 encryption scheme and the RSASSA-PSS signature scheme.
+ *
+ * \param ctx      RSA context to be initialized
+ * \param padding  RSA_PKCS_V15 or RSA_PKCS_V21
+ * \param hash_id  RSA_PKCS_V21 hash identifier
+ *
+ * \note           The hash_id parameter is actually ignored
+ *                 when using RSA_PKCS_V15 padding.
+ */
+void rsa_init( rsa_context *ctx,
+               int padding,
+               int hash_id);
+
+/**
+ * \brief          Generate an RSA keypair
+ *
+ * \param ctx      RSA context that will hold the key
+ * \param f_rng    RNG function
+ * \param p_rng    RNG parameter
+ * \param nbits    size of the public key in bits
+ * \param exponent public exponent (e.g., 65537)
+ *
+ * \note           rsa_init() must be called beforehand to setup
+ *                 the RSA context.
+ *
+ * \return         0 if successful, or an POLARSSL_ERR_RSA_XXX error code
+ */
+int rsa_gen_key( rsa_context *ctx,
+                 int (*f_rng)(void *, unsigned char *, size_t),
+                 void *p_rng,
+                 unsigned int nbits, int exponent );
+
+/**
+ * \brief          Check a public RSA key
+ *
+ * \param ctx      RSA context to be checked
+ *
+ * \return         0 if successful, or an POLARSSL_ERR_RSA_XXX error code
+ */
+int rsa_check_pubkey( const rsa_context *ctx );
+
+/**
+ * \brief          Check a private RSA key
+ *
+ * \param ctx      RSA context to be checked
+ *
+ * \return         0 if successful, or an POLARSSL_ERR_RSA_XXX error code
+ */
+int rsa_check_privkey( const rsa_context *ctx );
+
+/**
+ * \brief          Do an RSA public key operation
+ *
+ * \param ctx      RSA context
+ * \param input    input buffer
+ * \param output   output buffer
+ *
+ * \return         0 if successful, or an POLARSSL_ERR_RSA_XXX error code
+ *
+ * \note           This function does NOT take care of message
+ *                 padding. Also, be sure to set input[0] = 0 or assure that
+ *                 input is smaller than N.
+ *
+ * \note           The input and output buffers must be large
+ *                 enough (eg. 128 bytes if RSA-1024 is used).
+ */
+int rsa_public( rsa_context *ctx,
+                const unsigned char *input,
+                unsigned char *output );
+
+/**
+ * \brief          Do an RSA private key operation
+ *
+ * \param ctx      RSA context
+ * \param input    input buffer
+ * \param output   output buffer
+ *
+ * \return         0 if successful, or an POLARSSL_ERR_RSA_XXX error code
+ *
+ * \note           The input and output buffers must be large
+ *                 enough (eg. 128 bytes if RSA-1024 is used).
+ */
+int rsa_private( rsa_context *ctx,
+                 const unsigned char *input,
+                 unsigned char *output );
+
+/**
+ * \brief          Generic wrapper to perform a PKCS#1 encryption using the
+ *                 mode from the context. Add the message padding, then do an
+ *                 RSA operation.
+ *
+ * \param ctx      RSA context
+ * \param f_rng    RNG function (Needed for padding and PKCS#1 v2.1 encoding)
+ * \param p_rng    RNG parameter
+ * \param mode     RSA_PUBLIC or RSA_PRIVATE
+ * \param ilen     contains the plaintext length
+ * \param input    buffer holding the data to be encrypted
+ * \param output   buffer that will hold the ciphertext
+ *
+ * \return         0 if successful, or an POLARSSL_ERR_RSA_XXX error code
+ *
+ * \note           The output buffer must be as large as the size
+ *                 of ctx->N (eg. 128 bytes if RSA-1024 is used).
+ */
+int rsa_pkcs1_encrypt( rsa_context *ctx,
+                       int (*f_rng)(void *, unsigned char *, size_t),
+                       void *p_rng,
+                       int mode, size_t ilen,
+                       const unsigned char *input,
+                       unsigned char *output );
+
+/**
+ * \brief          Perform a PKCS#1 v1.5 encryption (RSAES-PKCS1-v1_5-ENCRYPT)
+ *
+ * \param ctx      RSA context
+ * \param f_rng    RNG function (Needed for padding)
+ * \param p_rng    RNG parameter
+ * \param mode     RSA_PUBLIC or RSA_PRIVATE
+ * \param ilen     contains the plaintext length
+ * \param input    buffer holding the data to be encrypted
+ * \param output   buffer that will hold the ciphertext
+ *
+ * \return         0 if successful, or an POLARSSL_ERR_RSA_XXX error code
+ *
+ * \note           The output buffer must be as large as the size
+ *                 of ctx->N (eg. 128 bytes if RSA-1024 is used).
+ */
+int rsa_rsaes_pkcs1_v15_encrypt( rsa_context *ctx,
+                                 int (*f_rng)(void *, unsigned char *, size_t),
+                                 void *p_rng,
+                                 int mode, size_t ilen,
+                                 const unsigned char *input,
+                                 unsigned char *output );
+
+/**
+ * \brief          Perform a PKCS#1 v2.1 OAEP encryption (RSAES-OAEP-ENCRYPT)
+ *
+ * \param ctx      RSA context
+ * \param f_rng    RNG function (Needed for padding and PKCS#1 v2.1 encoding)
+ * \param p_rng    RNG parameter
+ * \param mode     RSA_PUBLIC or RSA_PRIVATE
+ * \param label    buffer holding the custom label to use
+ * \param label_len contains the label length
+ * \param ilen     contains the plaintext length
+ * \param input    buffer holding the data to be encrypted
+ * \param output   buffer that will hold the ciphertext
+ *
+ * \return         0 if successful, or an POLARSSL_ERR_RSA_XXX error code
+ *
+ * \note           The output buffer must be as large as the size
+ *                 of ctx->N (eg. 128 bytes if RSA-1024 is used).
+ */
+int rsa_rsaes_oaep_encrypt( rsa_context *ctx,
+                            int (*f_rng)(void *, unsigned char *, size_t),
+                            void *p_rng,
+                            int mode,
+                            const unsigned char *label, size_t label_len,
+                            size_t ilen,
+                            const unsigned char *input,
+                            unsigned char *output );
+
+/**
+ * \brief          Generic wrapper to perform a PKCS#1 decryption using the
+ *                 mode from the context. Do an RSA operation, then remove
+ *                 the message padding
+ *
+ * \param ctx      RSA context
+ * \param mode     RSA_PUBLIC or RSA_PRIVATE
+ * \param olen     will contain the plaintext length
+ * \param input    buffer holding the encrypted data
+ * \param output   buffer that will hold the plaintext
+ * \param output_max_len    maximum length of the output buffer
+ *
+ * \return         0 if successful, or an POLARSSL_ERR_RSA_XXX error code
+ *
+ * \note           The output buffer must be as large as the size
+ *                 of ctx->N (eg. 128 bytes if RSA-1024 is used) otherwise
+ *                 an error is thrown.
+ */
+int rsa_pkcs1_decrypt( rsa_context *ctx,
+                       int mode, size_t *olen,
+                       const unsigned char *input,
+                       unsigned char *output,
+                       size_t output_max_len );
+
+/**
+ * \brief          Perform a PKCS#1 v1.5 decryption (RSAES-PKCS1-v1_5-DECRYPT)
+ *
+ * \param ctx      RSA context
+ * \param mode     RSA_PUBLIC or RSA_PRIVATE
+ * \param olen     will contain the plaintext length
+ * \param input    buffer holding the encrypted data
+ * \param output   buffer that will hold the plaintext
+ * \param output_max_len    maximum length of the output buffer
+ *
+ * \return         0 if successful, or an POLARSSL_ERR_RSA_XXX error code
+ *
+ * \note           The output buffer must be as large as the size
+ *                 of ctx->N (eg. 128 bytes if RSA-1024 is used) otherwise
+ *                 an error is thrown.
+ */
+int rsa_rsaes_pkcs1_v15_decrypt( rsa_context *ctx,
+                                 int mode, size_t *olen,
+                                 const unsigned char *input,
+                                 unsigned char *output,
+                                 size_t output_max_len );
+
+/**
+ * \brief          Perform a PKCS#1 v2.1 OAEP decryption (RSAES-OAEP-DECRYPT)
+ *
+ * \param ctx      RSA context
+ * \param mode     RSA_PUBLIC or RSA_PRIVATE
+ * \param label    buffer holding the custom label to use
+ * \param label_len contains the label length
+ * \param olen     will contain the plaintext length
+ * \param input    buffer holding the encrypted data
+ * \param output   buffer that will hold the plaintext
+ * \param output_max_len    maximum length of the output buffer
+ *
+ * \return         0 if successful, or an POLARSSL_ERR_RSA_XXX error code
+ *
+ * \note           The output buffer must be as large as the size
+ *                 of ctx->N (eg. 128 bytes if RSA-1024 is used) otherwise
+ *                 an error is thrown.
+ */
+int rsa_rsaes_oaep_decrypt( rsa_context *ctx,
+                            int mode,
+                            const unsigned char *label, size_t label_len,
+                            size_t *olen,
+                            const unsigned char *input,
+                            unsigned char *output,
+                            size_t output_max_len );
+
+/**
+ * \brief          Generic wrapper to perform a PKCS#1 signature using the
+ *                 mode from the context. Do a private RSA operation to sign
+ *                 a message digest
+ *
+ * \param ctx      RSA context
+ * \param f_rng    RNG function (Needed for PKCS#1 v2.1 encoding)
+ * \param p_rng    RNG parameter
+ * \param mode     RSA_PUBLIC or RSA_PRIVATE
+ * \param hash_id  SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512}
+ * \param hashlen  message digest length (for SIG_RSA_RAW only)
+ * \param hash     buffer holding the message digest
+ * \param sig      buffer that will hold the ciphertext
+ *
+ * \return         0 if the signing operation was successful,
+ *                 or an POLARSSL_ERR_RSA_XXX error code
+ *
+ * \note           The "sig" buffer must be as large as the size
+ *                 of ctx->N (eg. 128 bytes if RSA-1024 is used).
+ *
+ * \note           In case of PKCS#1 v2.1 encoding keep in mind that
+ *                 the hash_id in the RSA context is the one used for the
+ *                 encoding. hash_id in the function call is the type of hash
+ *                 that is encoded. According to RFC 3447 it is advised to
+ *                 keep both hashes the same.
+ */
+int rsa_pkcs1_sign( rsa_context *ctx,
+                    int (*f_rng)(void *, unsigned char *, size_t),
+                    void *p_rng,
+                    int mode,
+                    int hash_id,
+                    unsigned int hashlen,
+                    const unsigned char *hash,
+                    unsigned char *sig );
+
+/**
+ * \brief          Perform a PKCS#1 v1.5 signature (RSASSA-PKCS1-v1_5-SIGN)
+ *
+ * \param ctx      RSA context
+ * \param mode     RSA_PUBLIC or RSA_PRIVATE
+ * \param hash_id  SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512}
+ * \param hashlen  message digest length (for SIG_RSA_RAW only)
+ * \param hash     buffer holding the message digest
+ * \param sig      buffer that will hold the ciphertext
+ *
+ * \return         0 if the signing operation was successful,
+ *                 or an POLARSSL_ERR_RSA_XXX error code
+ *
+ * \note           The "sig" buffer must be as large as the size
+ *                 of ctx->N (eg. 128 bytes if RSA-1024 is used).
+ */
+int rsa_rsassa_pkcs1_v15_sign( rsa_context *ctx,
+                               int mode,
+                               int hash_id,
+                               unsigned int hashlen,
+                               const unsigned char *hash,
+                               unsigned char *sig );
+
+/**
+ * \brief          Perform a PKCS#1 v2.1 PSS signature (RSASSA-PSS-SIGN)
+ *
+ * \param ctx      RSA context
+ * \param f_rng    RNG function (Needed for PKCS#1 v2.1 encoding)
+ * \param p_rng    RNG parameter
+ * \param mode     RSA_PUBLIC or RSA_PRIVATE
+ * \param hash_id  SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512}
+ * \param hashlen  message digest length (for SIG_RSA_RAW only)
+ * \param hash     buffer holding the message digest
+ * \param sig      buffer that will hold the ciphertext
+ *
+ * \return         0 if the signing operation was successful,
+ *                 or an POLARSSL_ERR_RSA_XXX error code
+ *
+ * \note           The "sig" buffer must be as large as the size
+ *                 of ctx->N (eg. 128 bytes if RSA-1024 is used).
+ *
+ * \note           In case of PKCS#1 v2.1 encoding keep in mind that
+ *                 the hash_id in the RSA context is the one used for the
+ *                 encoding. hash_id in the function call is the type of hash
+ *                 that is encoded. According to RFC 3447 it is advised to
+ *                 keep both hashes the same.
+ */
+int rsa_rsassa_pss_sign( rsa_context *ctx,
+                         int (*f_rng)(void *, unsigned char *, size_t),
+                         void *p_rng,
+                         int mode,
+                         int hash_id,
+                         unsigned int hashlen,
+                         const unsigned char *hash,
+                         unsigned char *sig );
+
+/**
+ * \brief          Generic wrapper to perform a PKCS#1 verification using the
+ *                 mode from the context. Do a public RSA operation and check
+ *                 the message digest
+ *
+ * \param ctx      points to an RSA public key
+ * \param mode     RSA_PUBLIC or RSA_PRIVATE
+ * \param hash_id  SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512}
+ * \param hashlen  message digest length (for SIG_RSA_RAW only)
+ * \param hash     buffer holding the message digest
+ * \param sig      buffer holding the ciphertext
+ *
+ * \return         0 if the verify operation was successful,
+ *                 or an POLARSSL_ERR_RSA_XXX error code
+ *
+ * \note           The "sig" buffer must be as large as the size
+ *                 of ctx->N (eg. 128 bytes if RSA-1024 is used).
+ *
+ * \note           In case of PKCS#1 v2.1 encoding keep in mind that
+ *                 the hash_id in the RSA context is the one used for the
+ *                 verification. hash_id in the function call is the type of hash
+ *                 that is verified. According to RFC 3447 it is advised to
+ *                 keep both hashes the same.
+ */
+int rsa_pkcs1_verify( rsa_context *ctx,
+                      int mode,
+                      int hash_id,
+                      unsigned int hashlen,
+                      const unsigned char *hash,
+                      unsigned char *sig );
+
+/**
+ * \brief          Perform a PKCS#1 v1.5 verification (RSASSA-PKCS1-v1_5-VERIFY)
+ *
+ * \param ctx      points to an RSA public key
+ * \param mode     RSA_PUBLIC or RSA_PRIVATE
+ * \param hash_id  SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512}
+ * \param hashlen  message digest length (for SIG_RSA_RAW only)
+ * \param hash     buffer holding the message digest
+ * \param sig      buffer holding the ciphertext
+ *
+ * \return         0 if the verify operation was successful,
+ *                 or an POLARSSL_ERR_RSA_XXX error code
+ *
+ * \note           The "sig" buffer must be as large as the size
+ *                 of ctx->N (eg. 128 bytes if RSA-1024 is used).
+ */
+int rsa_rsassa_pkcs1_v15_verify( rsa_context *ctx,
+                                 int mode,
+                                 int hash_id,
+                                 unsigned int hashlen,
+                                 const unsigned char *hash,
+                                 unsigned char *sig );
+
+/**
+ * \brief          Perform a PKCS#1 v2.1 PSS verification (RSASSA-PSS-VERIFY)
+ * \brief          Do a public RSA and check the message digest
+ *
+ * \param ctx      points to an RSA public key
+ * \param mode     RSA_PUBLIC or RSA_PRIVATE
+ * \param hash_id  SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512}
+ * \param hashlen  message digest length (for SIG_RSA_RAW only)
+ * \param hash     buffer holding the message digest
+ * \param sig      buffer holding the ciphertext
+ *
+ * \return         0 if the verify operation was successful,
+ *                 or an POLARSSL_ERR_RSA_XXX error code
+ *
+ * \note           The "sig" buffer must be as large as the size
+ *                 of ctx->N (eg. 128 bytes if RSA-1024 is used).
+ *
+ * \note           In case of PKCS#1 v2.1 encoding keep in mind that
+ *                 the hash_id in the RSA context is the one used for the
+ *                 verification. hash_id in the function call is the type of hash
+ *                 that is verified. According to RFC 3447 it is advised to
+ *                 keep both hashes the same.
+ */
+int rsa_rsassa_pss_verify( rsa_context *ctx,
+                           int mode,
+                           int hash_id,
+                           unsigned int hashlen,
+                           const unsigned char *hash,
+                           unsigned char *sig );
+
+/**
+ * \brief          Free the components of an RSA key
+ *
+ * \param ctx      RSA Context to free
+ */
+void rsa_free( rsa_context *ctx );
+
+/**
+ * \brief          Checkup routine
+ *
+ * \return         0 if successful, or 1 if the test failed
+ */
+int rsa_self_test( int verbose );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* rsa.h */
diff --git a/common/polarssl/sha1.c b/common/polarssl/sha1.c
new file mode 100644 (file)
index 0000000..28bcd4e
--- /dev/null
@@ -0,0 +1,624 @@
+/*
+ *  FIPS-180-1 compliant SHA-1 implementation
+ *
+ *  Copyright (C) 2006-2013, Brainspark B.V.
+ *
+ *  This file is part of PolarSSL (http://www.polarssl.org)
+ *  Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
+ *
+ *  All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+/*
+ *  The SHA-1 standard was published by NIST in 1993.
+ *
+ *  http://www.itl.nist.gov/fipspubs/fip180-1.htm
+ */
+
+#include "polarssl_config.h"
+
+#if defined(POLARSSL_SHA1_C)
+
+#include "sha1.h"
+
+#if defined(POLARSSL_FS_IO) || defined(POLARSSL_SELF_TEST)
+#include <stdio.h>
+#endif
+
+#if !defined(POLARSSL_SHA1_ALT)
+
+/*
+ * 32-bit integer manipulation macros (big endian)
+ */
+#ifndef GET_UINT32_BE
+#define GET_UINT32_BE(n,b,i)                            \
+{                                                       \
+    (n) = ( (uint32_t) (b)[(i)    ] << 24 )             \
+        | ( (uint32_t) (b)[(i) + 1] << 16 )             \
+        | ( (uint32_t) (b)[(i) + 2] <<  8 )             \
+        | ( (uint32_t) (b)[(i) + 3]       );            \
+}
+#endif
+
+#ifndef PUT_UINT32_BE
+#define PUT_UINT32_BE(n,b,i)                            \
+{                                                       \
+    (b)[(i)    ] = (unsigned char) ( (n) >> 24 );       \
+    (b)[(i) + 1] = (unsigned char) ( (n) >> 16 );       \
+    (b)[(i) + 2] = (unsigned char) ( (n) >>  8 );       \
+    (b)[(i) + 3] = (unsigned char) ( (n)       );       \
+}
+#endif
+
+/*
+ * SHA-1 context setup
+ */
+void sha1_starts( sha1_context *ctx )
+{
+    ctx->total[0] = 0;
+    ctx->total[1] = 0;
+
+    ctx->state[0] = 0x67452301;
+    ctx->state[1] = 0xEFCDAB89;
+    ctx->state[2] = 0x98BADCFE;
+    ctx->state[3] = 0x10325476;
+    ctx->state[4] = 0xC3D2E1F0;
+}
+
+void sha1_process( sha1_context *ctx, const unsigned char data[64] )
+{
+    uint32_t temp, W[16], A, B, C, D, E;
+
+    GET_UINT32_BE( W[ 0], data,  0 );
+    GET_UINT32_BE( W[ 1], data,  4 );
+    GET_UINT32_BE( W[ 2], data,  8 );
+    GET_UINT32_BE( W[ 3], data, 12 );
+    GET_UINT32_BE( W[ 4], data, 16 );
+    GET_UINT32_BE( W[ 5], data, 20 );
+    GET_UINT32_BE( W[ 6], data, 24 );
+    GET_UINT32_BE( W[ 7], data, 28 );
+    GET_UINT32_BE( W[ 8], data, 32 );
+    GET_UINT32_BE( W[ 9], data, 36 );
+    GET_UINT32_BE( W[10], data, 40 );
+    GET_UINT32_BE( W[11], data, 44 );
+    GET_UINT32_BE( W[12], data, 48 );
+    GET_UINT32_BE( W[13], data, 52 );
+    GET_UINT32_BE( W[14], data, 56 );
+    GET_UINT32_BE( W[15], data, 60 );
+
+#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
+
+#define R(t)                                            \
+(                                                       \
+    temp = W[(t -  3) & 0x0F] ^ W[(t - 8) & 0x0F] ^     \
+           W[(t - 14) & 0x0F] ^ W[ t      & 0x0F],      \
+    ( W[t & 0x0F] = S(temp,1) )                         \
+)
+
+#define P(a,b,c,d,e,x)                                  \
+{                                                       \
+    e += S(a,5) + F(b,c,d) + K + x; b = S(b,30);        \
+}
+
+    A = ctx->state[0];
+    B = ctx->state[1];
+    C = ctx->state[2];
+    D = ctx->state[3];
+    E = ctx->state[4];
+
+#define F(x,y,z) (z ^ (x & (y ^ z)))
+#define K 0x5A827999
+
+    P( A, B, C, D, E, W[0]  );
+    P( E, A, B, C, D, W[1]  );
+    P( D, E, A, B, C, W[2]  );
+    P( C, D, E, A, B, W[3]  );
+    P( B, C, D, E, A, W[4]  );
+    P( A, B, C, D, E, W[5]  );
+    P( E, A, B, C, D, W[6]  );
+    P( D, E, A, B, C, W[7]  );
+    P( C, D, E, A, B, W[8]  );
+    P( B, C, D, E, A, W[9]  );
+    P( A, B, C, D, E, W[10] );
+    P( E, A, B, C, D, W[11] );
+    P( D, E, A, B, C, W[12] );
+    P( C, D, E, A, B, W[13] );
+    P( B, C, D, E, A, W[14] );
+    P( A, B, C, D, E, W[15] );
+    P( E, A, B, C, D, R(16) );
+    P( D, E, A, B, C, R(17) );
+    P( C, D, E, A, B, R(18) );
+    P( B, C, D, E, A, R(19) );
+
+#undef K
+#undef F
+
+#define F(x,y,z) (x ^ y ^ z)
+#define K 0x6ED9EBA1
+
+    P( A, B, C, D, E, R(20) );
+    P( E, A, B, C, D, R(21) );
+    P( D, E, A, B, C, R(22) );
+    P( C, D, E, A, B, R(23) );
+    P( B, C, D, E, A, R(24) );
+    P( A, B, C, D, E, R(25) );
+    P( E, A, B, C, D, R(26) );
+    P( D, E, A, B, C, R(27) );
+    P( C, D, E, A, B, R(28) );
+    P( B, C, D, E, A, R(29) );
+    P( A, B, C, D, E, R(30) );
+    P( E, A, B, C, D, R(31) );
+    P( D, E, A, B, C, R(32) );
+    P( C, D, E, A, B, R(33) );
+    P( B, C, D, E, A, R(34) );
+    P( A, B, C, D, E, R(35) );
+    P( E, A, B, C, D, R(36) );
+    P( D, E, A, B, C, R(37) );
+    P( C, D, E, A, B, R(38) );
+    P( B, C, D, E, A, R(39) );
+
+#undef K
+#undef F
+
+#define F(x,y,z) ((x & y) | (z & (x | y)))
+#define K 0x8F1BBCDC
+
+    P( A, B, C, D, E, R(40) );
+    P( E, A, B, C, D, R(41) );
+    P( D, E, A, B, C, R(42) );
+    P( C, D, E, A, B, R(43) );
+    P( B, C, D, E, A, R(44) );
+    P( A, B, C, D, E, R(45) );
+    P( E, A, B, C, D, R(46) );
+    P( D, E, A, B, C, R(47) );
+    P( C, D, E, A, B, R(48) );
+    P( B, C, D, E, A, R(49) );
+    P( A, B, C, D, E, R(50) );
+    P( E, A, B, C, D, R(51) );
+    P( D, E, A, B, C, R(52) );
+    P( C, D, E, A, B, R(53) );
+    P( B, C, D, E, A, R(54) );
+    P( A, B, C, D, E, R(55) );
+    P( E, A, B, C, D, R(56) );
+    P( D, E, A, B, C, R(57) );
+    P( C, D, E, A, B, R(58) );
+    P( B, C, D, E, A, R(59) );
+
+#undef K
+#undef F
+
+#define F(x,y,z) (x ^ y ^ z)
+#define K 0xCA62C1D6
+
+    P( A, B, C, D, E, R(60) );
+    P( E, A, B, C, D, R(61) );
+    P( D, E, A, B, C, R(62) );
+    P( C, D, E, A, B, R(63) );
+    P( B, C, D, E, A, R(64) );
+    P( A, B, C, D, E, R(65) );
+    P( E, A, B, C, D, R(66) );
+    P( D, E, A, B, C, R(67) );
+    P( C, D, E, A, B, R(68) );
+    P( B, C, D, E, A, R(69) );
+    P( A, B, C, D, E, R(70) );
+    P( E, A, B, C, D, R(71) );
+    P( D, E, A, B, C, R(72) );
+    P( C, D, E, A, B, R(73) );
+    P( B, C, D, E, A, R(74) );
+    P( A, B, C, D, E, R(75) );
+    P( E, A, B, C, D, R(76) );
+    P( D, E, A, B, C, R(77) );
+    P( C, D, E, A, B, R(78) );
+    P( B, C, D, E, A, R(79) );
+
+#undef K
+#undef F
+
+    ctx->state[0] += A;
+    ctx->state[1] += B;
+    ctx->state[2] += C;
+    ctx->state[3] += D;
+    ctx->state[4] += E;
+}
+
+/*
+ * SHA-1 process buffer
+ */
+void sha1_update( sha1_context *ctx, const unsigned char *input, size_t ilen )
+{
+    size_t fill;
+    uint32_t left;
+
+    if( ilen <= 0 )
+        return;
+
+    left = ctx->total[0] & 0x3F;
+    fill = 64 - left;
+
+    ctx->total[0] += (uint32_t) ilen;
+    ctx->total[0] &= 0xFFFFFFFF;
+
+    if( ctx->total[0] < (uint32_t) ilen )
+        ctx->total[1]++;
+
+    if( left && ilen >= fill )
+    {
+        memcpy( (void *) (ctx->buffer + left), input, fill );
+        sha1_process( ctx, ctx->buffer );
+        input += fill;
+        ilen  -= fill;
+        left = 0;
+    }
+
+    while( ilen >= 64 )
+    {
+        sha1_process( ctx, input );
+        input += 64;
+        ilen  -= 64;
+    }
+
+    if( ilen > 0 )
+        memcpy( (void *) (ctx->buffer + left), input, ilen );
+}
+
+static const unsigned char sha1_padding[64] =
+{
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/*
+ * SHA-1 final digest
+ */
+void sha1_finish( sha1_context *ctx, unsigned char output[20] )
+{
+    uint32_t last, padn;
+    uint32_t high, low;
+    unsigned char msglen[8];
+
+    high = ( ctx->total[0] >> 29 )
+         | ( ctx->total[1] <<  3 );
+    low  = ( ctx->total[0] <<  3 );
+
+    PUT_UINT32_BE( high, msglen, 0 );
+    PUT_UINT32_BE( low,  msglen, 4 );
+
+    last = ctx->total[0] & 0x3F;
+    padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
+
+    sha1_update( ctx, sha1_padding, padn );
+    sha1_update( ctx, msglen, 8 );
+
+    PUT_UINT32_BE( ctx->state[0], output,  0 );
+    PUT_UINT32_BE( ctx->state[1], output,  4 );
+    PUT_UINT32_BE( ctx->state[2], output,  8 );
+    PUT_UINT32_BE( ctx->state[3], output, 12 );
+    PUT_UINT32_BE( ctx->state[4], output, 16 );
+}
+
+#endif /* !POLARSSL_SHA1_ALT */
+
+/*
+ * output = SHA-1( input buffer )
+ */
+void sha1( const unsigned char *input, size_t ilen, unsigned char output[20] )
+{
+    sha1_context ctx;
+
+    sha1_starts( &ctx );
+    sha1_update( &ctx, input, ilen );
+    sha1_finish( &ctx, output );
+
+    memset( &ctx, 0, sizeof( sha1_context ) );
+}
+
+#if defined(POLARSSL_FS_IO)
+/*
+ * output = SHA-1( file contents )
+ */
+int sha1_file( const char *path, unsigned char output[20] )
+{
+    FILE *f;
+    size_t n;
+    sha1_context ctx;
+    unsigned char buf[1024];
+
+    if( ( f = fopen( path, "rb" ) ) == NULL )
+        return( POLARSSL_ERR_SHA1_FILE_IO_ERROR );
+
+    sha1_starts( &ctx );
+
+    while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 )
+        sha1_update( &ctx, buf, n );
+
+    sha1_finish( &ctx, output );
+
+    memset( &ctx, 0, sizeof( sha1_context ) );
+
+    if( ferror( f ) != 0 )
+    {
+        fclose( f );
+        return( POLARSSL_ERR_SHA1_FILE_IO_ERROR );
+    }
+
+    fclose( f );
+    return( 0 );
+}
+#endif /* POLARSSL_FS_IO */
+
+/*
+ * SHA-1 HMAC context setup
+ */
+void sha1_hmac_starts( sha1_context *ctx, const unsigned char *key, size_t keylen )
+{
+    size_t i;
+    unsigned char sum[20];
+
+    if( keylen > 64 )
+    {
+        sha1( key, keylen, sum );
+        keylen = 20;
+        key = sum;
+    }
+
+    memset( ctx->ipad, 0x36, 64 );
+    memset( ctx->opad, 0x5C, 64 );
+
+    for( i = 0; i < keylen; i++ )
+    {
+        ctx->ipad[i] = (unsigned char)( ctx->ipad[i] ^ key[i] );
+        ctx->opad[i] = (unsigned char)( ctx->opad[i] ^ key[i] );
+    }
+
+    sha1_starts( ctx );
+    sha1_update( ctx, ctx->ipad, 64 );
+
+    memset( sum, 0, sizeof( sum ) );
+}
+
+/*
+ * SHA-1 HMAC process buffer
+ */
+void sha1_hmac_update( sha1_context *ctx, const unsigned char *input, size_t ilen )
+{
+    sha1_update( ctx, input, ilen );
+}
+
+/*
+ * SHA-1 HMAC final digest
+ */
+void sha1_hmac_finish( sha1_context *ctx, unsigned char output[20] )
+{
+    unsigned char tmpbuf[20];
+
+    sha1_finish( ctx, tmpbuf );
+    sha1_starts( ctx );
+    sha1_update( ctx, ctx->opad, 64 );
+    sha1_update( ctx, tmpbuf, 20 );
+    sha1_finish( ctx, output );
+
+    memset( tmpbuf, 0, sizeof( tmpbuf ) );
+}
+
+/*
+ * SHA1 HMAC context reset
+ */
+void sha1_hmac_reset( sha1_context *ctx )
+{
+    sha1_starts( ctx );
+    sha1_update( ctx, ctx->ipad, 64 );
+}
+
+/*
+ * output = HMAC-SHA-1( hmac key, input buffer )
+ */
+void sha1_hmac( const unsigned char *key, size_t keylen,
+                const unsigned char *input, size_t ilen,
+                unsigned char output[20] )
+{
+    sha1_context ctx;
+
+    sha1_hmac_starts( &ctx, key, keylen );
+    sha1_hmac_update( &ctx, input, ilen );
+    sha1_hmac_finish( &ctx, output );
+
+    memset( &ctx, 0, sizeof( sha1_context ) );
+}
+
+#if defined(POLARSSL_SELF_TEST)
+/*
+ * FIPS-180-1 test vectors
+ */
+static unsigned char sha1_test_buf[3][57] = 
+{
+    { "abc" },
+    { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" },
+    { "" }
+};
+
+static const int sha1_test_buflen[3] =
+{
+    3, 56, 1000
+};
+
+static const unsigned char sha1_test_sum[3][20] =
+{
+    { 0xA9, 0x99, 0x3E, 0x36, 0x47, 0x06, 0x81, 0x6A, 0xBA, 0x3E,
+      0x25, 0x71, 0x78, 0x50, 0xC2, 0x6C, 0x9C, 0xD0, 0xD8, 0x9D },
+    { 0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E, 0xBA, 0xAE,
+      0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5, 0xE5, 0x46, 0x70, 0xF1 },
+    { 0x34, 0xAA, 0x97, 0x3C, 0xD4, 0xC4, 0xDA, 0xA4, 0xF6, 0x1E,
+      0xEB, 0x2B, 0xDB, 0xAD, 0x27, 0x31, 0x65, 0x34, 0x01, 0x6F }
+};
+
+/*
+ * RFC 2202 test vectors
+ */
+static unsigned char sha1_hmac_test_key[7][26] =
+{
+    { "\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B"
+      "\x0B\x0B\x0B\x0B" },
+    { "Jefe" },
+    { "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+      "\xAA\xAA\xAA\xAA" },
+    { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10"
+      "\x11\x12\x13\x14\x15\x16\x17\x18\x19" },
+    { "\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C"
+      "\x0C\x0C\x0C\x0C" },
+    { "" }, /* 0xAA 80 times */
+    { "" }
+};
+
+static const int sha1_hmac_test_keylen[7] =
+{
+    20, 4, 20, 25, 20, 80, 80
+};
+
+static unsigned char sha1_hmac_test_buf[7][74] =
+{
+    { "Hi There" },
+    { "what do ya want for nothing?" },
+    { "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+      "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+      "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+      "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+      "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" },
+    { "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+      "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+      "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+      "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+      "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" },
+    { "Test With Truncation" },
+    { "Test Using Larger Than Block-Size Key - Hash Key First" },
+    { "Test Using Larger Than Block-Size Key and Larger"
+      " Than One Block-Size Data" }
+};
+
+static const int sha1_hmac_test_buflen[7] =
+{
+    8, 28, 50, 50, 20, 54, 73
+};
+
+static const unsigned char sha1_hmac_test_sum[7][20] =
+{
+    { 0xB6, 0x17, 0x31, 0x86, 0x55, 0x05, 0x72, 0x64, 0xE2, 0x8B,
+      0xC0, 0xB6, 0xFB, 0x37, 0x8C, 0x8E, 0xF1, 0x46, 0xBE, 0x00 },
+    { 0xEF, 0xFC, 0xDF, 0x6A, 0xE5, 0xEB, 0x2F, 0xA2, 0xD2, 0x74,
+      0x16, 0xD5, 0xF1, 0x84, 0xDF, 0x9C, 0x25, 0x9A, 0x7C, 0x79 },
+    { 0x12, 0x5D, 0x73, 0x42, 0xB9, 0xAC, 0x11, 0xCD, 0x91, 0xA3,
+      0x9A, 0xF4, 0x8A, 0xA1, 0x7B, 0x4F, 0x63, 0xF1, 0x75, 0xD3 },
+    { 0x4C, 0x90, 0x07, 0xF4, 0x02, 0x62, 0x50, 0xC6, 0xBC, 0x84,
+      0x14, 0xF9, 0xBF, 0x50, 0xC8, 0x6C, 0x2D, 0x72, 0x35, 0xDA },
+    { 0x4C, 0x1A, 0x03, 0x42, 0x4B, 0x55, 0xE0, 0x7F, 0xE7, 0xF2,
+      0x7B, 0xE1 },
+    { 0xAA, 0x4A, 0xE5, 0xE1, 0x52, 0x72, 0xD0, 0x0E, 0x95, 0x70,
+      0x56, 0x37, 0xCE, 0x8A, 0x3B, 0x55, 0xED, 0x40, 0x21, 0x12 },
+    { 0xE8, 0xE9, 0x9D, 0x0F, 0x45, 0x23, 0x7D, 0x78, 0x6D, 0x6B,
+      0xBA, 0xA7, 0x96, 0x5C, 0x78, 0x08, 0xBB, 0xFF, 0x1A, 0x91 }
+};
+
+/*
+ * Checkup routine
+ */
+int sha1_self_test( int verbose )
+{
+    int i, j, buflen;
+    unsigned char buf[1024];
+    unsigned char sha1sum[20];
+    sha1_context ctx;
+
+    /*
+     * SHA-1
+     */
+    for( i = 0; i < 3; i++ )
+    {
+        if( verbose != 0 )
+            printf( "  SHA-1 test #%d: ", i + 1 );
+
+        sha1_starts( &ctx );
+
+        if( i == 2 )
+        {
+            memset( buf, 'a', buflen = 1000 );
+
+            for( j = 0; j < 1000; j++ )
+                sha1_update( &ctx, buf, buflen );
+        }
+        else
+            sha1_update( &ctx, sha1_test_buf[i],
+                               sha1_test_buflen[i] );
+
+        sha1_finish( &ctx, sha1sum );
+
+        if( memcmp( sha1sum, sha1_test_sum[i], 20 ) != 0 )
+        {
+            if( verbose != 0 )
+                printf( "failed\n" );
+
+            return( 1 );
+        }
+
+        if( verbose != 0 )
+            printf( "passed\n" );
+    }
+
+    if( verbose != 0 )
+        printf( "\n" );
+
+    for( i = 0; i < 7; i++ )
+    {
+        if( verbose != 0 )
+            printf( "  HMAC-SHA-1 test #%d: ", i + 1 );
+
+        if( i == 5 || i == 6 )
+        {
+            memset( buf, '\xAA', buflen = 80 );
+            sha1_hmac_starts( &ctx, buf, buflen );
+        }
+        else
+            sha1_hmac_starts( &ctx, sha1_hmac_test_key[i],
+                                    sha1_hmac_test_keylen[i] );
+
+        sha1_hmac_update( &ctx, sha1_hmac_test_buf[i],
+                                sha1_hmac_test_buflen[i] );
+
+        sha1_hmac_finish( &ctx, sha1sum );
+
+        buflen = ( i == 4 ) ? 12 : 20;
+
+        if( memcmp( sha1sum, sha1_hmac_test_sum[i], buflen ) != 0 )
+        {
+            if( verbose != 0 )
+                printf( "failed\n" );
+
+            return( 1 );
+        }
+
+        if( verbose != 0 )
+            printf( "passed\n" );
+    }
+
+    if( verbose != 0 )
+        printf( "\n" );
+
+    return( 0 );
+}
+
+#endif
+
+#endif
diff --git a/common/polarssl/sha1.h b/common/polarssl/sha1.h
new file mode 100644 (file)
index 0000000..01cb69b
--- /dev/null
@@ -0,0 +1,180 @@
+/**
+ * \file sha1.h
+ *
+ * \brief SHA-1 cryptographic hash function
+ *
+ *  Copyright (C) 2006-2013, Brainspark B.V.
+ *
+ *  This file is part of PolarSSL (http://www.polarssl.org)
+ *  Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
+ *
+ *  All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef POLARSSL_SHA1_H
+#define POLARSSL_SHA1_H
+
+#include "polarssl_config.h"
+
+#include <string.h>
+
+#ifdef _MSC_VER
+#include <basetsd.h>
+typedef UINT32 uint32_t;
+#else
+#include <inttypes.h>
+#endif
+
+#define POLARSSL_ERR_SHA1_FILE_IO_ERROR                -0x0076  /**< Read/write error in file. */
+
+#if !defined(POLARSSL_SHA1_ALT)
+// Regular implementation
+//
+
+/**
+ * \brief          SHA-1 context structure
+ */
+typedef struct
+{
+    uint32_t total[2];          /*!< number of bytes processed  */
+    uint32_t state[5];          /*!< intermediate digest state  */
+    unsigned char buffer[64];   /*!< data block being processed */
+
+    unsigned char ipad[64];     /*!< HMAC: inner padding        */
+    unsigned char opad[64];     /*!< HMAC: outer padding        */
+}
+sha1_context;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief          SHA-1 context setup
+ *
+ * \param ctx      context to be initialized
+ */
+void sha1_starts( sha1_context *ctx );
+
+/**
+ * \brief          SHA-1 process buffer
+ *
+ * \param ctx      SHA-1 context
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ */
+void sha1_update( sha1_context *ctx, const unsigned char *input, size_t ilen );
+
+/**
+ * \brief          SHA-1 final digest
+ *
+ * \param ctx      SHA-1 context
+ * \param output   SHA-1 checksum result
+ */
+void sha1_finish( sha1_context *ctx, unsigned char output[20] );
+
+/* Internal use */
+void sha1_process( sha1_context *ctx, const unsigned char data[64] );
+
+#ifdef __cplusplus
+}
+#endif
+
+#else  /* POLARSSL_SHA1_ALT */
+#include "sha1_alt.h"
+#endif /* POLARSSL_SHA1_ALT */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief          Output = SHA-1( input buffer )
+ *
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ * \param output   SHA-1 checksum result
+ */
+void sha1( const unsigned char *input, size_t ilen, unsigned char output[20] );
+
+/**
+ * \brief          Output = SHA-1( file contents )
+ *
+ * \param path     input file name
+ * \param output   SHA-1 checksum result
+ *
+ * \return         0 if successful, or POLARSSL_ERR_SHA1_FILE_IO_ERROR
+ */
+int sha1_file( const char *path, unsigned char output[20] );
+
+/**
+ * \brief          SHA-1 HMAC context setup
+ *
+ * \param ctx      HMAC context to be initialized
+ * \param key      HMAC secret key
+ * \param keylen   length of the HMAC key
+ */
+void sha1_hmac_starts( sha1_context *ctx, const unsigned char *key, size_t keylen );
+
+/**
+ * \brief          SHA-1 HMAC process buffer
+ *
+ * \param ctx      HMAC context
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ */
+void sha1_hmac_update( sha1_context *ctx, const unsigned char *input, size_t ilen );
+
+/**
+ * \brief          SHA-1 HMAC final digest
+ *
+ * \param ctx      HMAC context
+ * \param output   SHA-1 HMAC checksum result
+ */
+void sha1_hmac_finish( sha1_context *ctx, unsigned char output[20] );
+
+/**
+ * \brief          SHA-1 HMAC context reset
+ *
+ * \param ctx      HMAC context to be reset
+ */
+void sha1_hmac_reset( sha1_context *ctx );
+
+/**
+ * \brief          Output = HMAC-SHA-1( hmac key, input buffer )
+ *
+ * \param key      HMAC secret key
+ * \param keylen   length of the HMAC key
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ * \param output   HMAC-SHA-1 result
+ */
+void sha1_hmac( const unsigned char *key, size_t keylen,
+                const unsigned char *input, size_t ilen,
+                unsigned char output[20] );
+
+/**
+ * \brief          Checkup routine
+ *
+ * \return         0 if successful, or 1 if the test failed
+ */
+int sha1_self_test( int verbose );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* sha1.h */
diff --git a/common/sha1.c b/common/sha1.c
deleted file mode 100644 (file)
index d20c54a..0000000
+++ /dev/null
@@ -1,665 +0,0 @@
-/*
- *  FIPS-180-1 compliant SHA-1 implementation
- *
- *  Copyright (C) 2006-2014, ARM Limited, All Rights Reserved
- *  This file is part of mbed TLS (https://tls.mbed.org)
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-/*
- *  The SHA-1 standard was published by NIST in 1993.
- *
- *  http://www.itl.nist.gov/fipspubs/fip180-1.htm
- */
-
-#if !defined(POLARSSL_CONFIG_FILE)
-//#include "polarssl/config.h"
-#define POLARSSL_SHA1_C
-
-#else
-#include POLARSSL_CONFIG_FILE
-#endif
-
-#if defined(POLARSSL_SHA1_C)
-
-#include "sha1.h"
-
-#include <string.h>
-
-#if defined(POLARSSL_FS_IO)
-#include <stdio.h>
-#endif
-
-#if defined(POLARSSL_SELF_TEST)
-#if defined(POLARSSL_PLATFORM_C)
-#include "polarssl/platform.h"
-#else
-#include <stdio.h>
-#define polarssl_printf printf
-#endif /* POLARSSL_PLATFORM_C */
-#endif /* POLARSSL_SELF_TEST */
-
-/* Implementation that should never be optimized out by the compiler */
-static void polarssl_zeroize( void *v, size_t n ) {
-    volatile unsigned char *p = v; while( n-- ) *p++ = 0;
-}
-
-#if !defined(POLARSSL_SHA1_ALT)
-
-/*
- * 32-bit integer manipulation macros (big endian)
- */
-#ifndef GET_UINT32_BE
-#define GET_UINT32_BE(n,b,i)                            \
-{                                                       \
-    (n) = ( (uint32_t) (b)[(i)    ] << 24 )             \
-        | ( (uint32_t) (b)[(i) + 1] << 16 )             \
-        | ( (uint32_t) (b)[(i) + 2] <<  8 )             \
-        | ( (uint32_t) (b)[(i) + 3]       );            \
-}
-#endif
-
-#ifndef PUT_UINT32_BE
-#define PUT_UINT32_BE(n,b,i)                            \
-{                                                       \
-    (b)[(i)    ] = (unsigned char) ( (n) >> 24 );       \
-    (b)[(i) + 1] = (unsigned char) ( (n) >> 16 );       \
-    (b)[(i) + 2] = (unsigned char) ( (n) >>  8 );       \
-    (b)[(i) + 3] = (unsigned char) ( (n)       );       \
-}
-#endif
-
-void sha1_init( sha1_context *ctx )
-{
-    memset( ctx, 0, sizeof( sha1_context ) );
-}
-
-void sha1_free( sha1_context *ctx )
-{
-    if( ctx == NULL )
-        return;
-
-    polarssl_zeroize( ctx, sizeof( sha1_context ) );
-}
-
-/*
- * SHA-1 context setup
- */
-void sha1_starts( sha1_context *ctx )
-{
-    ctx->total[0] = 0;
-    ctx->total[1] = 0;
-
-    ctx->state[0] = 0x67452301;
-    ctx->state[1] = 0xEFCDAB89;
-    ctx->state[2] = 0x98BADCFE;
-    ctx->state[3] = 0x10325476;
-    ctx->state[4] = 0xC3D2E1F0;
-}
-
-void sha1_process( sha1_context *ctx, const unsigned char data[64] )
-{
-    uint32_t temp, W[16], A, B, C, D, E;
-
-    GET_UINT32_BE( W[ 0], data,  0 );
-    GET_UINT32_BE( W[ 1], data,  4 );
-    GET_UINT32_BE( W[ 2], data,  8 );
-    GET_UINT32_BE( W[ 3], data, 12 );
-    GET_UINT32_BE( W[ 4], data, 16 );
-    GET_UINT32_BE( W[ 5], data, 20 );
-    GET_UINT32_BE( W[ 6], data, 24 );
-    GET_UINT32_BE( W[ 7], data, 28 );
-    GET_UINT32_BE( W[ 8], data, 32 );
-    GET_UINT32_BE( W[ 9], data, 36 );
-    GET_UINT32_BE( W[10], data, 40 );
-    GET_UINT32_BE( W[11], data, 44 );
-    GET_UINT32_BE( W[12], data, 48 );
-    GET_UINT32_BE( W[13], data, 52 );
-    GET_UINT32_BE( W[14], data, 56 );
-    GET_UINT32_BE( W[15], data, 60 );
-
-#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
-
-#define R(t)                                            \
-(                                                       \
-    temp = W[( t -  3 ) & 0x0F] ^ W[( t - 8 ) & 0x0F] ^ \
-           W[( t - 14 ) & 0x0F] ^ W[  t       & 0x0F],  \
-    ( W[t & 0x0F] = S(temp,1) )                         \
-)
-
-#define P(a,b,c,d,e,x)                                  \
-{                                                       \
-    e += S(a,5) + F(b,c,d) + K + x; b = S(b,30);        \
-}
-
-    A = ctx->state[0];
-    B = ctx->state[1];
-    C = ctx->state[2];
-    D = ctx->state[3];
-    E = ctx->state[4];
-
-#define F(x,y,z) (z ^ (x & (y ^ z)))
-#define K 0x5A827999
-
-    P( A, B, C, D, E, W[0]  );
-    P( E, A, B, C, D, W[1]  );
-    P( D, E, A, B, C, W[2]  );
-    P( C, D, E, A, B, W[3]  );
-    P( B, C, D, E, A, W[4]  );
-    P( A, B, C, D, E, W[5]  );
-    P( E, A, B, C, D, W[6]  );
-    P( D, E, A, B, C, W[7]  );
-    P( C, D, E, A, B, W[8]  );
-    P( B, C, D, E, A, W[9]  );
-    P( A, B, C, D, E, W[10] );
-    P( E, A, B, C, D, W[11] );
-    P( D, E, A, B, C, W[12] );
-    P( C, D, E, A, B, W[13] );
-    P( B, C, D, E, A, W[14] );
-    P( A, B, C, D, E, W[15] );
-    P( E, A, B, C, D, R(16) );
-    P( D, E, A, B, C, R(17) );
-    P( C, D, E, A, B, R(18) );
-    P( B, C, D, E, A, R(19) );
-
-#undef K
-#undef F
-
-#define F(x,y,z) (x ^ y ^ z)
-#define K 0x6ED9EBA1
-
-    P( A, B, C, D, E, R(20) );
-    P( E, A, B, C, D, R(21) );
-    P( D, E, A, B, C, R(22) );
-    P( C, D, E, A, B, R(23) );
-    P( B, C, D, E, A, R(24) );
-    P( A, B, C, D, E, R(25) );
-    P( E, A, B, C, D, R(26) );
-    P( D, E, A, B, C, R(27) );
-    P( C, D, E, A, B, R(28) );
-    P( B, C, D, E, A, R(29) );
-    P( A, B, C, D, E, R(30) );
-    P( E, A, B, C, D, R(31) );
-    P( D, E, A, B, C, R(32) );
-    P( C, D, E, A, B, R(33) );
-    P( B, C, D, E, A, R(34) );
-    P( A, B, C, D, E, R(35) );
-    P( E, A, B, C, D, R(36) );
-    P( D, E, A, B, C, R(37) );
-    P( C, D, E, A, B, R(38) );
-    P( B, C, D, E, A, R(39) );
-
-#undef K
-#undef F
-
-#define F(x,y,z) ((x & y) | (z & (x | y)))
-#define K 0x8F1BBCDC
-
-    P( A, B, C, D, E, R(40) );
-    P( E, A, B, C, D, R(41) );
-    P( D, E, A, B, C, R(42) );
-    P( C, D, E, A, B, R(43) );
-    P( B, C, D, E, A, R(44) );
-    P( A, B, C, D, E, R(45) );
-    P( E, A, B, C, D, R(46) );
-    P( D, E, A, B, C, R(47) );
-    P( C, D, E, A, B, R(48) );
-    P( B, C, D, E, A, R(49) );
-    P( A, B, C, D, E, R(50) );
-    P( E, A, B, C, D, R(51) );
-    P( D, E, A, B, C, R(52) );
-    P( C, D, E, A, B, R(53) );
-    P( B, C, D, E, A, R(54) );
-    P( A, B, C, D, E, R(55) );
-    P( E, A, B, C, D, R(56) );
-    P( D, E, A, B, C, R(57) );
-    P( C, D, E, A, B, R(58) );
-    P( B, C, D, E, A, R(59) );
-
-#undef K
-#undef F
-
-#define F(x,y,z) (x ^ y ^ z)
-#define K 0xCA62C1D6
-
-    P( A, B, C, D, E, R(60) );
-    P( E, A, B, C, D, R(61) );
-    P( D, E, A, B, C, R(62) );
-    P( C, D, E, A, B, R(63) );
-    P( B, C, D, E, A, R(64) );
-    P( A, B, C, D, E, R(65) );
-    P( E, A, B, C, D, R(66) );
-    P( D, E, A, B, C, R(67) );
-    P( C, D, E, A, B, R(68) );
-    P( B, C, D, E, A, R(69) );
-    P( A, B, C, D, E, R(70) );
-    P( E, A, B, C, D, R(71) );
-    P( D, E, A, B, C, R(72) );
-    P( C, D, E, A, B, R(73) );
-    P( B, C, D, E, A, R(74) );
-    P( A, B, C, D, E, R(75) );
-    P( E, A, B, C, D, R(76) );
-    P( D, E, A, B, C, R(77) );
-    P( C, D, E, A, B, R(78) );
-    P( B, C, D, E, A, R(79) );
-
-#undef K
-#undef F
-
-    ctx->state[0] += A;
-    ctx->state[1] += B;
-    ctx->state[2] += C;
-    ctx->state[3] += D;
-    ctx->state[4] += E;
-}
-
-/*
- * SHA-1 process buffer
- */
-void sha1_update( sha1_context *ctx, const unsigned char *input, size_t ilen )
-{
-    size_t fill;
-    uint32_t left;
-
-    if( ilen == 0 )
-        return;
-
-    left = ctx->total[0] & 0x3F;
-    fill = 64 - left;
-
-    ctx->total[0] += (uint32_t) ilen;
-    ctx->total[0] &= 0xFFFFFFFF;
-
-    if( ctx->total[0] < (uint32_t) ilen )
-        ctx->total[1]++;
-
-    if( left && ilen >= fill )
-    {
-        memcpy( (void *) (ctx->buffer + left), input, fill );
-        sha1_process( ctx, ctx->buffer );
-        input += fill;
-        ilen  -= fill;
-        left = 0;
-    }
-
-    while( ilen >= 64 )
-    {
-        sha1_process( ctx, input );
-        input += 64;
-        ilen  -= 64;
-    }
-
-    if( ilen > 0 )
-        memcpy( (void *) (ctx->buffer + left), input, ilen );
-}
-
-static const unsigned char sha1_padding[64] =
-{
- 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-
-/*
- * SHA-1 final digest
- */
-void sha1_finish( sha1_context *ctx, unsigned char output[20] )
-{
-    uint32_t last, padn;
-    uint32_t high, low;
-    unsigned char msglen[8];
-
-    high = ( ctx->total[0] >> 29 )
-         | ( ctx->total[1] <<  3 );
-    low  = ( ctx->total[0] <<  3 );
-
-    PUT_UINT32_BE( high, msglen, 0 );
-    PUT_UINT32_BE( low,  msglen, 4 );
-
-    last = ctx->total[0] & 0x3F;
-    padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
-
-    sha1_update( ctx, sha1_padding, padn );
-    sha1_update( ctx, msglen, 8 );
-
-    PUT_UINT32_BE( ctx->state[0], output,  0 );
-    PUT_UINT32_BE( ctx->state[1], output,  4 );
-    PUT_UINT32_BE( ctx->state[2], output,  8 );
-    PUT_UINT32_BE( ctx->state[3], output, 12 );
-    PUT_UINT32_BE( ctx->state[4], output, 16 );
-}
-
-#endif /* !POLARSSL_SHA1_ALT */
-
-/*
- * output = SHA-1( input buffer )
- */
-void sha1( const unsigned char *input, size_t ilen, unsigned char output[20] )
-{
-    sha1_context ctx;
-
-    sha1_init( &ctx );
-    sha1_starts( &ctx );
-    sha1_update( &ctx, input, ilen );
-    sha1_finish( &ctx, output );
-    sha1_free( &ctx );
-}
-
-#if defined(POLARSSL_FS_IO)
-/*
- * output = SHA-1( file contents )
- */
-int sha1_file( const char *path, unsigned char output[20] )
-{
-    FILE *f;
-    size_t n;
-    sha1_context ctx;
-    unsigned char buf[1024];
-
-    if( ( f = fopen( path, "rb" ) ) == NULL )
-        return( POLARSSL_ERR_SHA1_FILE_IO_ERROR );
-
-    sha1_init( &ctx );
-    sha1_starts( &ctx );
-
-    while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 )
-        sha1_update( &ctx, buf, n );
-
-    sha1_finish( &ctx, output );
-    sha1_free( &ctx );
-
-    if( ferror( f ) != 0 )
-    {
-        fclose( f );
-        return( POLARSSL_ERR_SHA1_FILE_IO_ERROR );
-    }
-
-    fclose( f );
-    return( 0 );
-}
-#endif /* POLARSSL_FS_IO */
-
-/*
- * SHA-1 HMAC context setup
- */
-void sha1_hmac_starts( sha1_context *ctx, const unsigned char *key,
-                       size_t keylen )
-{
-    size_t i;
-    unsigned char sum[20];
-
-    if( keylen > 64 )
-    {
-        sha1( key, keylen, sum );
-        keylen = 20;
-        key = sum;
-    }
-
-    memset( ctx->ipad, 0x36, 64 );
-    memset( ctx->opad, 0x5C, 64 );
-
-    for( i = 0; i < keylen; i++ )
-    {
-        ctx->ipad[i] = (unsigned char)( ctx->ipad[i] ^ key[i] );
-        ctx->opad[i] = (unsigned char)( ctx->opad[i] ^ key[i] );
-    }
-
-    sha1_starts( ctx );
-    sha1_update( ctx, ctx->ipad, 64 );
-
-    polarssl_zeroize( sum, sizeof( sum ) );
-}
-
-/*
- * SHA-1 HMAC process buffer
- */
-void sha1_hmac_update( sha1_context *ctx, const unsigned char *input,
-                       size_t ilen )
-{
-    sha1_update( ctx, input, ilen );
-}
-
-/*
- * SHA-1 HMAC final digest
- */
-void sha1_hmac_finish( sha1_context *ctx, unsigned char output[20] )
-{
-    unsigned char tmpbuf[20];
-
-    sha1_finish( ctx, tmpbuf );
-    sha1_starts( ctx );
-    sha1_update( ctx, ctx->opad, 64 );
-    sha1_update( ctx, tmpbuf, 20 );
-    sha1_finish( ctx, output );
-
-    polarssl_zeroize( tmpbuf, sizeof( tmpbuf ) );
-}
-
-/*
- * SHA1 HMAC context reset
- */
-void sha1_hmac_reset( sha1_context *ctx )
-{
-    sha1_starts( ctx );
-    sha1_update( ctx, ctx->ipad, 64 );
-}
-
-/*
- * output = HMAC-SHA-1( hmac key, input buffer )
- */
-void sha1_hmac( const unsigned char *key, size_t keylen,
-                const unsigned char *input, size_t ilen,
-                unsigned char output[20] )
-{
-    sha1_context ctx;
-
-    sha1_init( &ctx );
-    sha1_hmac_starts( &ctx, key, keylen );
-    sha1_hmac_update( &ctx, input, ilen );
-    sha1_hmac_finish( &ctx, output );
-    sha1_free( &ctx );
-}
-
-#if defined(POLARSSL_SELF_TEST)
-/*
- * FIPS-180-1 test vectors
- */
-static const unsigned char sha1_test_buf[3][57] =
-{
-    { "abc" },
-    { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" },
-    { "" }
-};
-
-static const int sha1_test_buflen[3] =
-{
-    3, 56, 1000
-};
-
-static const unsigned char sha1_test_sum[3][20] =
-{
-    { 0xA9, 0x99, 0x3E, 0x36, 0x47, 0x06, 0x81, 0x6A, 0xBA, 0x3E,
-      0x25, 0x71, 0x78, 0x50, 0xC2, 0x6C, 0x9C, 0xD0, 0xD8, 0x9D },
-    { 0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E, 0xBA, 0xAE,
-      0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5, 0xE5, 0x46, 0x70, 0xF1 },
-    { 0x34, 0xAA, 0x97, 0x3C, 0xD4, 0xC4, 0xDA, 0xA4, 0xF6, 0x1E,
-      0xEB, 0x2B, 0xDB, 0xAD, 0x27, 0x31, 0x65, 0x34, 0x01, 0x6F }
-};
-
-/*
- * RFC 2202 test vectors
- */
-static const unsigned char sha1_hmac_test_key[7][26] =
-{
-    { "\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B"
-      "\x0B\x0B\x0B\x0B" },
-    { "Jefe" },
-    { "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
-      "\xAA\xAA\xAA\xAA" },
-    { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10"
-      "\x11\x12\x13\x14\x15\x16\x17\x18\x19" },
-    { "\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C"
-      "\x0C\x0C\x0C\x0C" },
-    { "" }, /* 0xAA 80 times */
-    { "" }
-};
-
-static const int sha1_hmac_test_keylen[7] =
-{
-    20, 4, 20, 25, 20, 80, 80
-};
-
-static const unsigned char sha1_hmac_test_buf[7][74] =
-{
-    { "Hi There" },
-    { "what do ya want for nothing?" },
-    { "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
-      "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
-      "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
-      "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
-      "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" },
-    { "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
-      "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
-      "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
-      "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
-      "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" },
-    { "Test With Truncation" },
-    { "Test Using Larger Than Block-Size Key - Hash Key First" },
-    { "Test Using Larger Than Block-Size Key and Larger"
-      " Than One Block-Size Data" }
-};
-
-static const int sha1_hmac_test_buflen[7] =
-{
-    8, 28, 50, 50, 20, 54, 73
-};
-
-static const unsigned char sha1_hmac_test_sum[7][20] =
-{
-    { 0xB6, 0x17, 0x31, 0x86, 0x55, 0x05, 0x72, 0x64, 0xE2, 0x8B,
-      0xC0, 0xB6, 0xFB, 0x37, 0x8C, 0x8E, 0xF1, 0x46, 0xBE, 0x00 },
-    { 0xEF, 0xFC, 0xDF, 0x6A, 0xE5, 0xEB, 0x2F, 0xA2, 0xD2, 0x74,
-      0x16, 0xD5, 0xF1, 0x84, 0xDF, 0x9C, 0x25, 0x9A, 0x7C, 0x79 },
-    { 0x12, 0x5D, 0x73, 0x42, 0xB9, 0xAC, 0x11, 0xCD, 0x91, 0xA3,
-      0x9A, 0xF4, 0x8A, 0xA1, 0x7B, 0x4F, 0x63, 0xF1, 0x75, 0xD3 },
-    { 0x4C, 0x90, 0x07, 0xF4, 0x02, 0x62, 0x50, 0xC6, 0xBC, 0x84,
-      0x14, 0xF9, 0xBF, 0x50, 0xC8, 0x6C, 0x2D, 0x72, 0x35, 0xDA },
-    { 0x4C, 0x1A, 0x03, 0x42, 0x4B, 0x55, 0xE0, 0x7F, 0xE7, 0xF2,
-      0x7B, 0xE1 },
-    { 0xAA, 0x4A, 0xE5, 0xE1, 0x52, 0x72, 0xD0, 0x0E, 0x95, 0x70,
-      0x56, 0x37, 0xCE, 0x8A, 0x3B, 0x55, 0xED, 0x40, 0x21, 0x12 },
-    { 0xE8, 0xE9, 0x9D, 0x0F, 0x45, 0x23, 0x7D, 0x78, 0x6D, 0x6B,
-      0xBA, 0xA7, 0x96, 0x5C, 0x78, 0x08, 0xBB, 0xFF, 0x1A, 0x91 }
-};
-
-/*
- * Checkup routine
- */
-int sha1_self_test( int verbose )
-{
-    int i, j, buflen, ret = 0;
-    unsigned char buf[1024];
-    unsigned char sha1sum[20];
-    sha1_context ctx;
-
-    sha1_init( &ctx );
-
-    /*
-     * SHA-1
-     */
-    for( i = 0; i < 3; i++ )
-    {
-        if( verbose != 0 )
-            polarssl_printf( "  SHA-1 test #%d: ", i + 1 );
-
-        sha1_starts( &ctx );
-
-        if( i == 2 )
-        {
-            memset( buf, 'a', buflen = 1000 );
-
-            for( j = 0; j < 1000; j++ )
-                sha1_update( &ctx, buf, buflen );
-        }
-        else
-            sha1_update( &ctx, sha1_test_buf[i],
-                               sha1_test_buflen[i] );
-
-        sha1_finish( &ctx, sha1sum );
-
-        if( memcmp( sha1sum, sha1_test_sum[i], 20 ) != 0 )
-        {
-            if( verbose != 0 )
-                polarssl_printf( "failed\n" );
-
-            ret = 1;
-            goto exit;
-        }
-
-        if( verbose != 0 )
-            polarssl_printf( "passed\n" );
-    }
-
-    if( verbose != 0 )
-        polarssl_printf( "\n" );
-
-    for( i = 0; i < 7; i++ )
-    {
-        if( verbose != 0 )
-            polarssl_printf( "  HMAC-SHA-1 test #%d: ", i + 1 );
-
-        if( i == 5 || i == 6 )
-        {
-            memset( buf, 0xAA, buflen = 80 );
-            sha1_hmac_starts( &ctx, buf, buflen );
-        }
-        else
-            sha1_hmac_starts( &ctx, sha1_hmac_test_key[i],
-                                    sha1_hmac_test_keylen[i] );
-
-        sha1_hmac_update( &ctx, sha1_hmac_test_buf[i],
-                                sha1_hmac_test_buflen[i] );
-
-        sha1_hmac_finish( &ctx, sha1sum );
-
-        buflen = ( i == 4 ) ? 12 : 20;
-
-        if( memcmp( sha1sum, sha1_hmac_test_sum[i], buflen ) != 0 )
-        {
-            if( verbose != 0 )
-                polarssl_printf( "failed\n" );
-
-            ret = 1;
-            goto exit;
-        }
-
-        if( verbose != 0 )
-            polarssl_printf( "passed\n" );
-    }
-
-    if( verbose != 0 )
-        polarssl_printf( "\n" );
-
-exit:
-    sha1_free( &ctx );
-
-    return( ret );
-}
-
-#endif /* POLARSSL_SELF_TEST */
-
-#endif /* POLARSSL_SHA1_C */
-
diff --git a/common/sha1.h b/common/sha1.h
deleted file mode 100644 (file)
index 056bba7..0000000
+++ /dev/null
@@ -1,213 +0,0 @@
-/**
- * \file sha1.h
- *
- * \brief SHA-1 cryptographic hash function
- *
- *  Copyright (C) 2006-2014, ARM Limited, All Rights Reserved
- *
- *  This file is part of mbed TLS (https://tls.mbed.org)
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#ifndef POLARSSL_SHA1_H
-#define POLARSSL_SHA1_H
-
-#if !defined(POLARSSL_CONFIG_FILE)
-//#include "config.h"
-/**
- * \def POLARSSL_SHA1_C
- *
- * Enable the SHA1 cryptographic hash algorithm.
- *
- * Module:  library/sha1.c
- * Caller:  library/md.c
- *          library/ssl_cli.c
- *          library/ssl_srv.c
- *          library/ssl_tls.c
- *          library/x509write_crt.c
- *
- * This module is required for SSL/TLS and SHA1-signed certificates.
- */
-#define POLARSSL_SHA1_C
-
-#else
-#include POLARSSL_CONFIG_FILE
-#endif
-
-#include <stddef.h>
-
-#if defined(_MSC_VER) && !defined(EFIX64) && !defined(EFI32)
-#include <basetsd.h>
-typedef UINT32 uint32_t;
-#else
-#include <inttypes.h>
-#endif
-
-#define POLARSSL_ERR_SHA1_FILE_IO_ERROR                -0x0076  /**< Read/write error in file. */
-
-#if !defined(POLARSSL_SHA1_ALT)
-// Regular implementation
-//
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * \brief          SHA-1 context structure
- */
-typedef struct
-{
-    uint32_t total[2];          /*!< number of bytes processed  */
-    uint32_t state[5];          /*!< intermediate digest state  */
-    unsigned char buffer[64];   /*!< data block being processed */
-
-    unsigned char ipad[64];     /*!< HMAC: inner padding        */
-    unsigned char opad[64];     /*!< HMAC: outer padding        */
-}
-sha1_context;
-
-/**
- * \brief          Initialize SHA-1 context
- *
- * \param ctx      SHA-1 context to be initialized
- */
-void sha1_init( sha1_context *ctx );
-
-/**
- * \brief          Clear SHA-1 context
- *
- * \param ctx      SHA-1 context to be cleared
- */
-void sha1_free( sha1_context *ctx );
-
-/**
- * \brief          SHA-1 context setup
- *
- * \param ctx      context to be initialized
- */
-void sha1_starts( sha1_context *ctx );
-
-/**
- * \brief          SHA-1 process buffer
- *
- * \param ctx      SHA-1 context
- * \param input    buffer holding the  data
- * \param ilen     length of the input data
- */
-void sha1_update( sha1_context *ctx, const unsigned char *input, size_t ilen );
-
-/**
- * \brief          SHA-1 final digest
- *
- * \param ctx      SHA-1 context
- * \param output   SHA-1 checksum result
- */
-void sha1_finish( sha1_context *ctx, unsigned char output[20] );
-
-/* Internal use */
-void sha1_process( sha1_context *ctx, const unsigned char data[64] );
-
-#ifdef __cplusplus
-}
-#endif
-
-#else  /* POLARSSL_SHA1_ALT */
-#include "sha1_alt.h"
-#endif /* POLARSSL_SHA1_ALT */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * \brief          Output = SHA-1( input buffer )
- *
- * \param input    buffer holding the  data
- * \param ilen     length of the input data
- * \param output   SHA-1 checksum result
- */
-void sha1( const unsigned char *input, size_t ilen, unsigned char output[20] );
-
-/**
- * \brief          Output = SHA-1( file contents )
- *
- * \param path     input file name
- * \param output   SHA-1 checksum result
- *
- * \return         0 if successful, or POLARSSL_ERR_SHA1_FILE_IO_ERROR
- */
-int sha1_file( const char *path, unsigned char output[20] );
-
-/**
- * \brief          SHA-1 HMAC context setup
- *
- * \param ctx      HMAC context to be initialized
- * \param key      HMAC secret key
- * \param keylen   length of the HMAC key
- */
-void sha1_hmac_starts( sha1_context *ctx, const unsigned char *key,
-                       size_t keylen );
-
-/**
- * \brief          SHA-1 HMAC process buffer
- *
- * \param ctx      HMAC context
- * \param input    buffer holding the  data
- * \param ilen     length of the input data
- */
-void sha1_hmac_update( sha1_context *ctx, const unsigned char *input,
-                       size_t ilen );
-
-/**
- * \brief          SHA-1 HMAC final digest
- *
- * \param ctx      HMAC context
- * \param output   SHA-1 HMAC checksum result
- */
-void sha1_hmac_finish( sha1_context *ctx, unsigned char output[20] );
-
-/**
- * \brief          SHA-1 HMAC context reset
- *
- * \param ctx      HMAC context to be reset
- */
-void sha1_hmac_reset( sha1_context *ctx );
-
-/**
- * \brief          Output = HMAC-SHA-1( hmac key, input buffer )
- *
- * \param key      HMAC secret key
- * \param keylen   length of the HMAC key
- * \param input    buffer holding the  data
- * \param ilen     length of the input data
- * \param output   HMAC-SHA-1 result
- */
-void sha1_hmac( const unsigned char *key, size_t keylen,
-                const unsigned char *input, size_t ilen,
-                unsigned char output[20] );
-
-/**
- * \brief          Checkup routine
- *
- * \return         0 if successful, or 1 if the test failed
- */
-int sha1_self_test( int verbose );
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* sha1.h */
Impressum, Datenschutz