From: merlokk Date: Fri, 5 Jan 2018 09:57:11 +0000 (+0200) Subject: Merge branch 'master' of github.com:Proxmark/proxmark3 into travis X-Git-Tag: v3.1.0~86^2~2 X-Git-Url: http://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/commitdiff_plain/314a9b9cdd3d0e45bef3158e0a40de8568edf236?hp=58f0ae45c1f3bbe6d962aece3694c61f78475da3 Merge branch 'master' of github.com:Proxmark/proxmark3 into travis --- diff --git a/CHANGELOG.md b/CHANGELOG.md index fabd04b0..4162c638 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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] diff --git a/appveyor.yml b/appveyor.yml index eb22114e..f5ae2c70 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -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 { diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index a0fe2326..94ca52f5 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -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 diff --git a/armsrc/lfsampling.c b/armsrc/lfsampling.c index 999f56bb..084201a5 100644 --- a/armsrc/lfsampling.c +++ b/armsrc/lfsampling.c @@ -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; diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index 00fd638c..fcfd7e8f 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -694,10 +694,9 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, continue; } - // send a dummy byte as reader response in order to trigger the cards authentication timeout - uint8_t dummy_answer = 0; - ReaderTransmit(&dummy_answer, 1, NULL); - timeout = GetCountSspClk() + AUTHENTICATION_TIMEOUT; + // send a dummy response in order to trigger the cards authentication failure timeout + uint8_t dummy_answer[8] = {0}; + ReaderTransmit(dummy_answer, 8, NULL); num_nonces++; if (num_nonces % 2) { @@ -710,9 +709,6 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, i += 9; } - // wait for the card to become ready again - while(GetCountSspClk() < timeout); - } LED_C_OFF(); diff --git a/client/Makefile b/client/Makefile index 5df99de7..52a106bd 100644 --- a/client/Makefile +++ b/client/Makefile @@ -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 diff --git a/client/cmdcrc.c b/client/cmdcrc.c index 27d081b9..0ca2b8b1 100644 --- a/client/cmdcrc.c +++ b/client/cmdcrc.c @@ -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; diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 8064724c..e4b245c3 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -16,6 +16,7 @@ #include #include #include +#include #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: diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c index 60713a01..d42f7eef 100644 --- a/client/cmdhficlass.c +++ b/client/cmdhficlass.c @@ -14,6 +14,7 @@ #include #include #include +#include #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] "); + PrintAndLog("Options:"); + PrintAndLog("h Show this help"); + PrintAndLog("f 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 ] 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; } diff --git a/client/cmdhficlass.h b/client/cmdhficlass.h index 9a3adf50..456bb1c3 100644 --- a/client/cmdhficlass.h +++ b/client/cmdhficlass.h @@ -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 diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index eed6b34c..c471fdf7 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -987,6 +987,7 @@ int CmdHF14AMfChk(const char *Cmd) int i, res; int keycnt = 0; char ctmp = 0x00; + int clen = 0; char ctmp3[3] = {0x00}; uint8_t blockNo = 0; uint8_t SectorsCnt = 0; @@ -1015,32 +1016,36 @@ int CmdHF14AMfChk(const char *Cmd) blockNo = param_get8(Cmd, 0); ctmp = param_getchar(Cmd, 1); - switch (ctmp) { - case 'a': case 'A': - keyType = 0; - break; - case 'b': case 'B': - keyType = 1; - break; - case '?': - keyType = 2; - break; - default: - PrintAndLog("Key type must be A , B or ?"); - free(keyBlock); - return 1; - }; + clen = param_getlength(Cmd, 1); + if (clen == 1) { + switch (ctmp) { + case 'a': case 'A': + keyType = 0; + break; + case 'b': case 'B': + keyType = 1; + break; + case '?': + keyType = 2; + break; + default: + PrintAndLog("Key type must be A , B or ?"); + free(keyBlock); + return 1; + }; + } // transfer to emulator & create dump file ctmp = param_getchar(Cmd, 2); - if (ctmp == 't' || ctmp == 'T') transferToEml = 1; - if (ctmp == 'd' || ctmp == 'D') createDumpFile = 1; + clen = param_getlength(Cmd, 2); + if (clen == 1 && (ctmp == 't' || ctmp == 'T')) transferToEml = 1; + if (clen == 1 && (ctmp == 'd' || ctmp == 'D')) createDumpFile = 1; param3InUse = transferToEml | createDumpFile; timeout14a = 500; // fast by default // double parameters - ts, ds - int clen = param_getlength(Cmd, 2); + clen = param_getlength(Cmd, 2); if (clen == 2 || clen == 3){ param_getstr(Cmd, 2, ctmp3, sizeof(ctmp3)); ctmp = ctmp3[1]; @@ -1089,7 +1094,7 @@ int CmdHF14AMfChk(const char *Cmd) if( buf[0]=='#' ) continue; //The line start with # is comment, skip - if (!isxdigit(buf[0])){ + if (!isxdigit((unsigned char)buf[0])){ PrintAndLog("File content error. '%s' must include 12 HEX symbols",buf); continue; } @@ -1985,8 +1990,8 @@ int CmdHF14AMfCWipe(const char *Cmd) bool fillCard = false; if (strlen(Cmd) < 1 || param_getchar(Cmd, 0) == 'h') { - PrintAndLog("Usage: hf mf cwipe [card size] [w] [p]"); - PrintAndLog("sample: hf mf cwipe 1 w s"); + PrintAndLog("Usage: hf mf cwipe [card size] [w] [f]"); + PrintAndLog("sample: hf mf cwipe 1 w f"); PrintAndLog("[card size]: 0 = 320 bytes (Mifare Mini), 1 = 1K (default), 2 = 2K, 4 = 4K"); PrintAndLog("w - Wipe magic Chinese card (only works with gen:1a cards)"); PrintAndLog("f - Fill the card with default data and keys (works with gen:1a and gen:1b cards only)"); diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index 92a00bce..c5a6dd3f 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -1433,7 +1433,7 @@ int CmdT55xxBruteForce(const char *Cmd) { //The line start with # is comment, skip if( buf[0]=='#' ) continue; - if (!isxdigit(buf[0])) { + if (!isxdigit((unsigned char)buf[0])) { PrintAndLog("File content error. '%s' must include 8 HEX symbols", buf); continue; } diff --git a/client/cmdmain.c b/client/cmdmain.c index 739d68e1..ae059ea2 100644 --- a/client/cmdmain.c +++ b/client/cmdmain.c @@ -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; diff --git a/client/cmdscript.c b/client/cmdscript.c index 23163aa9..0d19f496 100644 --- a/client/cmdscript.c +++ b/client/cmdscript.c @@ -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 index 00000000..0925fbad --- /dev/null +++ b/client/emv/capk.txt @@ -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 diff --git a/client/emv/cmdemv.c b/client/emv/cmdemv.c index 3c3c1f11..c53b02af 100644 --- a/client/emv/cmdemv.c +++ b/client/emv/cmdemv.c @@ -8,7 +8,9 @@ // EMV commands //----------------------------------------------------------------------------- +#include #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} }; diff --git a/client/emv/cmdemv.h b/client/emv/cmdemv.h index 78796efa..b3f76508 100644 --- a/client/emv/cmdemv.h +++ b/client/emv/cmdemv.h @@ -15,6 +15,7 @@ #include #include #include +#include #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 index 00000000..c8ced6d4 --- /dev/null +++ b/client/emv/crypto.c @@ -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 +#endif + +#include "crypto.h" +#include "crypto_backend.h" + +#include + +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 index 00000000..940e8b2b --- /dev/null +++ b/client/emv/crypto.h @@ -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 +#include + +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 index 00000000..a815ae11 --- /dev/null +++ b/client/emv/crypto_backend.h @@ -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 +#include + +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 index 00000000..760395c4 --- /dev/null +++ b/client/emv/crypto_polarssl.c @@ -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 +#endif + +#include "crypto.h" +#include "crypto_backend.h" + +#include +#include +#include + +#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 index 00000000..b577855e --- /dev/null +++ b/client/emv/emv_pk.c @@ -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 +#endif + +/* For asprintf */ +#define _GNU_SOURCE +#include + +#include "emv_pk.h" +#include "crypto.h" +#include "proxmark3.h" + +#include +#include +#include +#include + +#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 index 00000000..e291a065 --- /dev/null +++ b/client/emv/emv_pk.h @@ -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 +#include + +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 index 00000000..7803060e --- /dev/null +++ b/client/emv/emv_pki.c @@ -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 +#endif + +#include "emv_pki.h" +#include "crypto.h" +#include "dump.h" +#include "util.h" + +#include +#include +#include +#include + +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 index 00000000..e37e3c7d --- /dev/null +++ b/client/emv/emv_pki.h @@ -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 + +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 index 00000000..d67a8705 --- /dev/null +++ b/client/emv/emv_pki_priv.c @@ -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 +#endif + +#include "emv_pki_priv.h" +#include "crypto.h" + +#include +#include +#include + +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 index 00000000..4f1639d5 --- /dev/null +++ b/client/emv/emv_pki_priv.h @@ -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 + +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 diff --git a/client/emv/emv_tags.c b/client/emv/emv_tags.c index a7c11c3e..cdd57cb5 100644 --- a/client/emv/emv_tags.c +++ b/client/emv/emv_tags.c @@ -21,6 +21,7 @@ #include "emv_tags.h" #include +#include #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; diff --git a/client/emv/emv_tags.h b/client/emv/emv_tags.h index 8dbd9e00..f6d44f01 100644 --- a/client/emv/emv_tags.h +++ b/client/emv/emv_tags.h @@ -19,6 +19,17 @@ #include "tlv.h" #include +// 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 diff --git a/client/emv/emvcore.c b/client/emv/emvcore.c index 5c737b05..08c6e3db 100644 --- a/client/emv/emvcore.c +++ b/client/emv/emvcore.c @@ -12,75 +12,96 @@ // 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 + + 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; +} diff --git a/client/emv/emvcore.h b/client/emv/emvcore.h index fdd3ab86..94be4fcf 100644 --- a/client/emv/emvcore.h +++ b/client/emv/emvcore.h @@ -20,19 +20,52 @@ #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 index 00000000..536a5862 --- /dev/null +++ b/client/emv/test/cda_test.c @@ -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 +#endif + +#include "../emv_pk.h" +#include "../crypto.h" +#include "../dump.h" +#include "../tlv.h" +#include "../emv_pki.h" + +#include +#include +#include + +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 index 00000000..1d321a26 --- /dev/null +++ b/client/emv/test/cda_test.h @@ -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 + +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 index 00000000..ff18b9da --- /dev/null +++ b/client/emv/test/crypto_test.c @@ -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 +#endif + +#include "../crypto.h" +#include "../dump.h" +#include "util_posix.h" + +#include +#include +#include + +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 index 00000000..084bc991 --- /dev/null +++ b/client/emv/test/crypto_test.h @@ -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 + +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 index 00000000..a6d06e68 --- /dev/null +++ b/client/emv/test/cryptotest.c @@ -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 index 00000000..5c6aaae2 --- /dev/null +++ b/client/emv/test/cryptotest.h @@ -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 + +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 index 00000000..afdd4e20 --- /dev/null +++ b/client/emv/test/dda_test.c @@ -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 +#endif + +#include "dda_test.h" + +#include "../emv_pk.h" +#include "../crypto.h" +#include "../dump.h" +#include "../tlv.h" +#include "../emv_pki.h" + +#include +#include +#include + +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 index 00000000..354cd7e1 --- /dev/null +++ b/client/emv/test/dda_test.h @@ -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 + +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 index 00000000..2aafcf19 --- /dev/null +++ b/client/emv/test/sda_test.c @@ -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 +#endif + +#include "../emv_pk.h" +#include "../crypto.h" +#include "../dump.h" +#include "../tlv.h" +#include "../emv_pki.h" + +#include +#include +#include + +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 index 00000000..43a4c948 --- /dev/null +++ b/client/emv/test/sda_test.h @@ -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); diff --git a/client/loclass/cipher.c b/client/loclass/cipher.c index 57bc831f..3b146b10 100644 --- a/client/loclass/cipher.c +++ b/client/loclass/cipher.c @@ -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 . * * - * ****************************************************************************/ diff --git a/client/loclass/cipher.h b/client/loclass/cipher.h index 7afdb524..632910a9 100644 --- a/client/loclass/cipher.h +++ b/client/loclass/cipher.h @@ -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 . * * - * ****************************************************************************/ diff --git a/client/loclass/cipherutils.c b/client/loclass/cipherutils.c index 9a8256bb..b5e365bf 100644 --- a/client/loclass/cipherutils.c +++ b/client/loclass/cipherutils.c @@ -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 . * * - * ****************************************************************************/ #include diff --git a/client/loclass/cipherutils.h b/client/loclass/cipherutils.h index 3cdbf5fa..56867179 100644 --- a/client/loclass/cipherutils.h +++ b/client/loclass/cipherutils.h @@ -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 . * * - * ****************************************************************************/ diff --git a/client/loclass/elite_crack.c b/client/loclass/elite_crack.c index 777efe08..fe9bf7d1 100644 --- a/client/loclass/elite_crack.c +++ b/client/loclass/elite_crack.c @@ -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 . * * - * ****************************************************************************/ #include diff --git a/client/loclass/elite_crack.h b/client/loclass/elite_crack.h index fb27355f..46791fb5 100644 --- a/client/loclass/elite_crack.h +++ b/client/loclass/elite_crack.h @@ -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 . * * - * ****************************************************************************/ diff --git a/client/loclass/fileutils.c b/client/loclass/fileutils.c index e5e5c5b0..90857e7a 100644 --- a/client/loclass/fileutils.c +++ b/client/loclass/fileutils.c @@ -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 . * * - * ****************************************************************************/ #ifndef ON_DEVICE diff --git a/client/loclass/fileutils.h b/client/loclass/fileutils.h index 10720f76..79dbe566 100644 --- a/client/loclass/fileutils.h +++ b/client/loclass/fileutils.h @@ -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 . * * - * ****************************************************************************/ #ifndef FILEUTILS_H diff --git a/client/loclass/ikeys.c b/client/loclass/ikeys.c index 8892b4a3..2a6a0010 100644 --- a/client/loclass/ikeys.c +++ b/client/loclass/ikeys.c @@ -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 . * * - * ****************************************************************************/ /** @@ -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; diff --git a/client/loclass/ikeys.h b/client/loclass/ikeys.h index 13096194..5b44d179 100644 --- a/client/loclass/ikeys.h +++ b/client/loclass/ikeys.h @@ -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 . * * - * ****************************************************************************/ #ifndef IKEYS_H diff --git a/client/loclass/main.c b/client/loclass/main.c index 95112f7d..fa9886ee 100644 --- a/client/loclass/main.c +++ b/client/loclass/main.c @@ -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 . * * - * ****************************************************************************/ diff --git a/client/obj/emv/test/.dummy b/client/obj/emv/test/.dummy new file mode 100644 index 00000000..e69de29b diff --git a/client/pm3_binlib.c b/client/pm3_binlib.c index ed46c8e8..cffbca6c 100644 --- a/client/pm3_binlib.c +++ b/client/pm3_binlib.c @@ -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*/ diff --git a/client/reveng/model.c b/client/reveng/model.c index 2d45b2fe..5a9b6580 100644 --- a/client/reveng/model.c +++ b/client/reveng/model.c @@ -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); diff --git a/client/scripting.c b/client/scripting.c index 13cb8cdf..3859fd48 100644 --- a/client/scripting.c +++ b/client/scripting.c @@ -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: diff --git a/client/ui.c b/client/ui.c index df2c3ce3..8faed6e8 100644 --- a/client/ui.c +++ b/client/ui.c @@ -9,12 +9,14 @@ // UI utilities //----------------------------------------------------------------------------- -#include +#include +#ifndef EXTERNAL_PRINTANDLOG #include #include -#include +#include #include #include +#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) { diff --git a/client/util.c b/client/util.c index 92b0e7a6..7e6b4074 100644 --- a/client/util.c +++ b/client/util.c @@ -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 diff --git a/client/util.h b/client/util.h index e9c48b03..fd7ceaff 100644 --- a/client/util.h +++ b/client/util.h @@ -12,6 +12,7 @@ #define UTIL_H__ #include +#include #include #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); diff --git a/common/polarssl/aes.h b/common/polarssl/aes.h index 946bd87d..299cb4cd 100644 --- a/common/polarssl/aes.h +++ b/common/polarssl/aes.h @@ -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 index 00000000..d22dd5c7 --- /dev/null +++ b/common/polarssl/bignum.c @@ -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 + * + * 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 + +#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 index 00000000..5eaf1a57 --- /dev/null +++ b/common/polarssl/bignum.h @@ -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 + * + * 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 +#include + +#include "polarssl_config.h" + +#ifdef _MSC_VER +#include +#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 +#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 index 00000000..1c2da136 --- /dev/null +++ b/common/polarssl/bn_mul.h @@ -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 + * + * 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 */ diff --git a/common/polarssl/des.c b/common/polarssl/des.c index 746752d7..b33deb6c 100644 --- a/common/polarssl/des.c +++ b/common/polarssl/des.c @@ -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) diff --git a/common/polarssl/polarssl_config.h b/common/polarssl/polarssl_config.h index 5bd88fc0..3d9a2f67 100644 --- a/common/polarssl/polarssl_config.h +++ b/common/polarssl/polarssl_config.h @@ -82,7 +82,7 @@ * * Comment to disable the use of assembly code. */ -#define POLARSSL_HAVE_ASM +//#define POLARSSL_HAVE_ASM /** * \def POLARSSL_HAVE_SSE2 @@ -762,7 +762,7 @@ * * 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 index 00000000..9872274b --- /dev/null +++ b/common/polarssl/rsa.c @@ -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 + * + * 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 +#include + +/* + * 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 index 00000000..f9a02202 --- /dev/null +++ b/common/polarssl/rsa.h @@ -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 + * + * 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 index 00000000..28bcd4e3 --- /dev/null +++ b/common/polarssl/sha1.c @@ -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 + * + * 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 +#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 index 00000000..01cb69b7 --- /dev/null +++ b/common/polarssl/sha1.h @@ -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 + * + * 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 + +#ifdef _MSC_VER +#include +typedef UINT32 uint32_t; +#else +#include +#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 index d20c54a4..00000000 --- a/common/sha1.c +++ /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 - -#if defined(POLARSSL_FS_IO) -#include -#endif - -#if defined(POLARSSL_SELF_TEST) -#if defined(POLARSSL_PLATFORM_C) -#include "polarssl/platform.h" -#else -#include -#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 index 056bba7e..00000000 --- a/common/sha1.h +++ /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 - -#if defined(_MSC_VER) && !defined(EFIX64) && !defined(EFI32) -#include -typedef UINT32 uint32_t; -#else -#include -#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 */