From f38a152863a5eb289acb169c5a38b4b77e87956e Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 11 Sep 2014 23:23:46 +0200 Subject: [PATCH] First check in. --- armsrc/LCD.c | 2 +- armsrc/Makefile | 15 +- armsrc/aes.c | 1168 ++++++++++++++++++++++++++++++++++ armsrc/aes.h | 30 + armsrc/appmain.c | 88 +-- armsrc/apps.h | 73 ++- armsrc/des.c | 383 +++++++++++ armsrc/des.h | 107 ++++ armsrc/desfire_crypto.c | 642 +++++++++++++++++++ armsrc/desfire_crypto.h | 15 + armsrc/desfire_key.c | 158 +++++ armsrc/desfire_key.h | 10 + armsrc/epa.c | 2 +- armsrc/fpgaloader.c | 3 +- armsrc/hitag2.c | 4 +- armsrc/iclass.c | 315 ++++++++- armsrc/iso14443.c | 4 +- armsrc/iso14443a.c | 34 +- armsrc/iso14443a.h | 3 +- armsrc/iso15693.c | 10 +- armsrc/legicrf.c | 6 +- armsrc/lfops.c | 82 ++- armsrc/mifarecmd.c | 94 ++- armsrc/mifarecmd.h | 7 +- armsrc/mifaredesfire.c | 568 +++++++++++++++++ armsrc/mifaredesfire.h | 16 + armsrc/mifaresniff.h | 6 +- armsrc/mifareutil.c | 91 ++- armsrc/mifareutil.h | 3 + armsrc/start.c | 2 +- armsrc/string.c | 5 + armsrc/string.h | 4 + armsrc/util.c | 42 +- armsrc/util.h | 6 +- client/Makefile | 24 +- client/cmdhf.c | 6 + client/cmdhf14a.c | 194 +++--- client/cmdhf14b.c | 3 +- client/cmdhf15.c | 2 +- client/cmdhfdes.c | 69 ++ client/cmdhfdes.h | 27 + client/cmdhfepa.c | 2 +- client/cmdhficlass.c | 306 +++++++-- client/cmdhficlass.h | 2 +- client/cmdhflegic.c | 1 - client/cmdhfmf.c | 151 ++++- client/cmdhfmf.h | 7 +- client/cmdhfmfdes.c | 436 +++++++++++++ client/cmdhfmfdes.h | 20 + client/cmdhfmfu.c | 1159 +++++++++++++++++++++++++++++++++ client/cmdhfmfu.h | 16 + client/cmdhw.c | 1 - client/cmdlf.c | 1 - client/cmdlfem4x.c | 91 ++- client/cmdlfhid.c | 1 - client/cmdlfhitag.c | 5 +- client/cmdlfio.c | 1 - client/cmdlfpcf7931.c | 1 - client/cmdlft55xx.c | 103 ++- client/cmdlfti.c | 1 - client/cmdmain.c | 2 +- client/cmdmain.h | 2 +- client/data.c | 1 - client/flash.c | 3 +- client/flasher.c | 2 +- client/loclass/cipher.c | 255 ++++++++ client/loclass/cipher.h | 31 + client/loclass/cipherutils.c | 273 ++++++++ client/loclass/cipherutils.h | 59 ++ client/loclass/des.c | 1014 +++++++++++++++++++++++++++++ client/loclass/des.h | 256 ++++++++ client/loclass/elite_crack.c | 656 +++++++++++++++++++ client/loclass/elite_crack.h | 108 ++++ client/loclass/fileutils.c | 65 ++ client/loclass/fileutils.h | 24 + client/loclass/ikeys.c | 878 +++++++++++++++++++++++++ client/loclass/ikeys.h | 32 + client/loclass/main.c | 96 +++ client/mifarehost.h | 1 - client/proxmark3.c | 38 -- client/proxmark3.h | 2 +- client/ui.c | 192 ++++++ client/ui.h | 4 + client/util.c | 34 + client/util.h | 3 + common/Makefile.common | 4 +- common/cmd.c | 2 +- common/cmd.h | 4 +- {include => common}/crc.h | 0 common/crc32.c | 35 + common/crc32.h | 15 + common/desfire.h | 177 ++++++ common/iso14443crc.c | 2 +- common/iso14443crc.h | 2 +- common/iso15693tools.c | 31 +- common/iso15693tools.h | 1 + common/legic_prng.c | 2 +- common/usb_cdc.c | 2 +- common/usb_cdc.h | 2 +- include/crc.h.old | 48 ++ include/mifare.h | 2 +- include/proxmark3.h | 3 +- include/usb_cmd.h | 17 + 103 files changed, 10522 insertions(+), 486 deletions(-) create mode 100644 armsrc/aes.c create mode 100644 armsrc/aes.h create mode 100644 armsrc/des.c create mode 100644 armsrc/des.h create mode 100644 armsrc/desfire_crypto.c create mode 100644 armsrc/desfire_crypto.h create mode 100644 armsrc/desfire_key.c create mode 100644 armsrc/desfire_key.h create mode 100644 armsrc/mifaredesfire.c create mode 100644 armsrc/mifaredesfire.h create mode 100644 client/cmdhfdes.c create mode 100644 client/cmdhfdes.h create mode 100644 client/cmdhfmfdes.c create mode 100644 client/cmdhfmfdes.h create mode 100644 client/cmdhfmfu.c create mode 100644 client/cmdhfmfu.h create mode 100644 client/loclass/cipher.c create mode 100644 client/loclass/cipher.h create mode 100644 client/loclass/cipherutils.c create mode 100644 client/loclass/cipherutils.h create mode 100644 client/loclass/des.c create mode 100644 client/loclass/des.h create mode 100644 client/loclass/elite_crack.c create mode 100644 client/loclass/elite_crack.h create mode 100644 client/loclass/fileutils.c create mode 100644 client/loclass/fileutils.h create mode 100644 client/loclass/ikeys.c create mode 100644 client/loclass/ikeys.h create mode 100644 client/loclass/main.c rename {include => common}/crc.h (100%) create mode 100644 common/crc32.c create mode 100644 common/crc32.h create mode 100644 common/desfire.h create mode 100644 include/crc.h.old diff --git a/armsrc/LCD.c b/armsrc/LCD.c index 65d64ac9..87be5e3a 100644 --- a/armsrc/LCD.c +++ b/armsrc/LCD.c @@ -6,7 +6,7 @@ // LCD code //----------------------------------------------------------------------------- -#include "proxmark3.h" +#include "../include/proxmark3.h" #include "apps.h" #include "LCD.h" #include "fonts.h" diff --git a/armsrc/Makefile b/armsrc/Makefile index e10c1001..ea19491a 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -10,7 +10,7 @@ APP_INCLUDES = apps.h #remove one of the following defines and comment out the relevant line #in the next section to remove that particular feature from compilation -APP_CFLAGS = -DWITH_LF -DWITH_ISO15693 -DWITH_ISO14443a -DWITH_ISO14443b -DWITH_ICLASS -DWITH_LEGICRF -DWITH_HITAG +APP_CFLAGS = -DWITH_LF -DWITH_ISO15693 -DWITH_ISO14443a -DWITH_ISO14443b -DWITH_ICLASS -DWITH_LEGICRF -DWITH_HITAG -DWITH_CRC -fno-strict-aliasing #-DWITH_LCD #SRC_LCD = fonts.c LCD.c @@ -18,13 +18,15 @@ SRC_LF = lfops.c hitag2.c SRC_ISO15693 = iso15693.c iso15693tools.c SRC_ISO14443a = epa.c iso14443a.c mifareutil.c mifarecmd.c mifaresniff.c SRC_ISO14443b = iso14443.c -SRC_CRAPTO1 = crapto1.c crypto1.c +SRC_CRAPTO1 = crapto1.c crypto1.c des.c aes.c +SRC_CRC = iso14443crc.c crc.c crc16.c crc32.c THUMBSRC = start.c \ $(SRC_LCD) \ $(SRC_ISO15693) \ $(SRC_LF) \ - appmain.c printf.c \ + appmain.c \ + printf.c \ util.c \ string.c \ usb_cdc.c \ @@ -33,14 +35,15 @@ THUMBSRC = start.c \ # These are to be compiled in ARM mode ARMSRC = fpgaloader.c \ legicrf.c \ - iso14443crc.c \ - crc16.c \ $(SRC_ISO14443a) \ $(SRC_ISO14443b) \ $(SRC_CRAPTO1) \ + $(SRC_CRC) \ legic_prng.c \ iclass.c \ - crc.c + mifaredesfire.c \ + desfire_crypto.c \ + desfire_key.c # stdint.h provided locally until GCC 4.5 becomes C99 compliant APP_CFLAGS += -I. diff --git a/armsrc/aes.c b/armsrc/aes.c new file mode 100644 index 00000000..3df006bb --- /dev/null +++ b/armsrc/aes.c @@ -0,0 +1,1168 @@ +#include "stdio.h" +#include "aes.h" + +static const unsigned int Te0[256] = { + 0xc66363a5UL, 0xf87c7c84UL, 0xee777799UL, 0xf67b7b8dUL, + 0xfff2f20dUL, 0xd66b6bbdUL, 0xde6f6fb1UL, 0x91c5c554UL, + 0x60303050UL, 0x02010103UL, 0xce6767a9UL, 0x562b2b7dUL, + 0xe7fefe19UL, 0xb5d7d762UL, 0x4dababe6UL, 0xec76769aUL, + 0x8fcaca45UL, 0x1f82829dUL, 0x89c9c940UL, 0xfa7d7d87UL, + 0xeffafa15UL, 0xb25959ebUL, 0x8e4747c9UL, 0xfbf0f00bUL, + 0x41adadecUL, 0xb3d4d467UL, 0x5fa2a2fdUL, 0x45afafeaUL, + 0x239c9cbfUL, 0x53a4a4f7UL, 0xe4727296UL, 0x9bc0c05bUL, + 0x75b7b7c2UL, 0xe1fdfd1cUL, 0x3d9393aeUL, 0x4c26266aUL, + 0x6c36365aUL, 0x7e3f3f41UL, 0xf5f7f702UL, 0x83cccc4fUL, + 0x6834345cUL, 0x51a5a5f4UL, 0xd1e5e534UL, 0xf9f1f108UL, + 0xe2717193UL, 0xabd8d873UL, 0x62313153UL, 0x2a15153fUL, + 0x0804040cUL, 0x95c7c752UL, 0x46232365UL, 0x9dc3c35eUL, + 0x30181828UL, 0x379696a1UL, 0x0a05050fUL, 0x2f9a9ab5UL, + 0x0e070709UL, 0x24121236UL, 0x1b80809bUL, 0xdfe2e23dUL, + 0xcdebeb26UL, 0x4e272769UL, 0x7fb2b2cdUL, 0xea75759fUL, + 0x1209091bUL, 0x1d83839eUL, 0x582c2c74UL, 0x341a1a2eUL, + 0x361b1b2dUL, 0xdc6e6eb2UL, 0xb45a5aeeUL, 0x5ba0a0fbUL, + 0xa45252f6UL, 0x763b3b4dUL, 0xb7d6d661UL, 0x7db3b3ceUL, + 0x5229297bUL, 0xdde3e33eUL, 0x5e2f2f71UL, 0x13848497UL, + 0xa65353f5UL, 0xb9d1d168UL, 0x00000000UL, 0xc1eded2cUL, + 0x40202060UL, 0xe3fcfc1fUL, 0x79b1b1c8UL, 0xb65b5bedUL, + 0xd46a6abeUL, 0x8dcbcb46UL, 0x67bebed9UL, 0x7239394bUL, + 0x944a4adeUL, 0x984c4cd4UL, 0xb05858e8UL, 0x85cfcf4aUL, + 0xbbd0d06bUL, 0xc5efef2aUL, 0x4faaaae5UL, 0xedfbfb16UL, + 0x864343c5UL, 0x9a4d4dd7UL, 0x66333355UL, 0x11858594UL, + 0x8a4545cfUL, 0xe9f9f910UL, 0x04020206UL, 0xfe7f7f81UL, + 0xa05050f0UL, 0x783c3c44UL, 0x259f9fbaUL, 0x4ba8a8e3UL, + 0xa25151f3UL, 0x5da3a3feUL, 0x804040c0UL, 0x058f8f8aUL, + 0x3f9292adUL, 0x219d9dbcUL, 0x70383848UL, 0xf1f5f504UL, + 0x63bcbcdfUL, 0x77b6b6c1UL, 0xafdada75UL, 0x42212163UL, + 0x20101030UL, 0xe5ffff1aUL, 0xfdf3f30eUL, 0xbfd2d26dUL, + 0x81cdcd4cUL, 0x180c0c14UL, 0x26131335UL, 0xc3ecec2fUL, + 0xbe5f5fe1UL, 0x359797a2UL, 0x884444ccUL, 0x2e171739UL, + 0x93c4c457UL, 0x55a7a7f2UL, 0xfc7e7e82UL, 0x7a3d3d47UL, + 0xc86464acUL, 0xba5d5de7UL, 0x3219192bUL, 0xe6737395UL, + 0xc06060a0UL, 0x19818198UL, 0x9e4f4fd1UL, 0xa3dcdc7fUL, + 0x44222266UL, 0x542a2a7eUL, 0x3b9090abUL, 0x0b888883UL, + 0x8c4646caUL, 0xc7eeee29UL, 0x6bb8b8d3UL, 0x2814143cUL, + 0xa7dede79UL, 0xbc5e5ee2UL, 0x160b0b1dUL, 0xaddbdb76UL, + 0xdbe0e03bUL, 0x64323256UL, 0x743a3a4eUL, 0x140a0a1eUL, + 0x924949dbUL, 0x0c06060aUL, 0x4824246cUL, 0xb85c5ce4UL, + 0x9fc2c25dUL, 0xbdd3d36eUL, 0x43acacefUL, 0xc46262a6UL, + 0x399191a8UL, 0x319595a4UL, 0xd3e4e437UL, 0xf279798bUL, + 0xd5e7e732UL, 0x8bc8c843UL, 0x6e373759UL, 0xda6d6db7UL, + 0x018d8d8cUL, 0xb1d5d564UL, 0x9c4e4ed2UL, 0x49a9a9e0UL, + 0xd86c6cb4UL, 0xac5656faUL, 0xf3f4f407UL, 0xcfeaea25UL, + 0xca6565afUL, 0xf47a7a8eUL, 0x47aeaee9UL, 0x10080818UL, + 0x6fbabad5UL, 0xf0787888UL, 0x4a25256fUL, 0x5c2e2e72UL, + 0x381c1c24UL, 0x57a6a6f1UL, 0x73b4b4c7UL, 0x97c6c651UL, + 0xcbe8e823UL, 0xa1dddd7cUL, 0xe874749cUL, 0x3e1f1f21UL, + 0x964b4bddUL, 0x61bdbddcUL, 0x0d8b8b86UL, 0x0f8a8a85UL, + 0xe0707090UL, 0x7c3e3e42UL, 0x71b5b5c4UL, 0xcc6666aaUL, + 0x904848d8UL, 0x06030305UL, 0xf7f6f601UL, 0x1c0e0e12UL, + 0xc26161a3UL, 0x6a35355fUL, 0xae5757f9UL, 0x69b9b9d0UL, + 0x17868691UL, 0x99c1c158UL, 0x3a1d1d27UL, 0x279e9eb9UL, + 0xd9e1e138UL, 0xebf8f813UL, 0x2b9898b3UL, 0x22111133UL, + 0xd26969bbUL, 0xa9d9d970UL, 0x078e8e89UL, 0x339494a7UL, + 0x2d9b9bb6UL, 0x3c1e1e22UL, 0x15878792UL, 0xc9e9e920UL, + 0x87cece49UL, 0xaa5555ffUL, 0x50282878UL, 0xa5dfdf7aUL, + 0x038c8c8fUL, 0x59a1a1f8UL, 0x09898980UL, 0x1a0d0d17UL, + 0x65bfbfdaUL, 0xd7e6e631UL, 0x844242c6UL, 0xd06868b8UL, + 0x824141c3UL, 0x299999b0UL, 0x5a2d2d77UL, 0x1e0f0f11UL, + 0x7bb0b0cbUL, 0xa85454fcUL, 0x6dbbbbd6UL, 0x2c16163aUL, +}; +static const unsigned int Te1[256] = { + 0xa5c66363UL, 0x84f87c7cUL, 0x99ee7777UL, 0x8df67b7bUL, + 0x0dfff2f2UL, 0xbdd66b6bUL, 0xb1de6f6fUL, 0x5491c5c5UL, + 0x50603030UL, 0x03020101UL, 0xa9ce6767UL, 0x7d562b2bUL, + 0x19e7fefeUL, 0x62b5d7d7UL, 0xe64dababUL, 0x9aec7676UL, + 0x458fcacaUL, 0x9d1f8282UL, 0x4089c9c9UL, 0x87fa7d7dUL, + 0x15effafaUL, 0xebb25959UL, 0xc98e4747UL, 0x0bfbf0f0UL, + 0xec41adadUL, 0x67b3d4d4UL, 0xfd5fa2a2UL, 0xea45afafUL, + 0xbf239c9cUL, 0xf753a4a4UL, 0x96e47272UL, 0x5b9bc0c0UL, + 0xc275b7b7UL, 0x1ce1fdfdUL, 0xae3d9393UL, 0x6a4c2626UL, + 0x5a6c3636UL, 0x417e3f3fUL, 0x02f5f7f7UL, 0x4f83ccccUL, + 0x5c683434UL, 0xf451a5a5UL, 0x34d1e5e5UL, 0x08f9f1f1UL, + 0x93e27171UL, 0x73abd8d8UL, 0x53623131UL, 0x3f2a1515UL, + 0x0c080404UL, 0x5295c7c7UL, 0x65462323UL, 0x5e9dc3c3UL, + 0x28301818UL, 0xa1379696UL, 0x0f0a0505UL, 0xb52f9a9aUL, + 0x090e0707UL, 0x36241212UL, 0x9b1b8080UL, 0x3ddfe2e2UL, + 0x26cdebebUL, 0x694e2727UL, 0xcd7fb2b2UL, 0x9fea7575UL, + 0x1b120909UL, 0x9e1d8383UL, 0x74582c2cUL, 0x2e341a1aUL, + 0x2d361b1bUL, 0xb2dc6e6eUL, 0xeeb45a5aUL, 0xfb5ba0a0UL, + 0xf6a45252UL, 0x4d763b3bUL, 0x61b7d6d6UL, 0xce7db3b3UL, + 0x7b522929UL, 0x3edde3e3UL, 0x715e2f2fUL, 0x97138484UL, + 0xf5a65353UL, 0x68b9d1d1UL, 0x00000000UL, 0x2cc1ededUL, + 0x60402020UL, 0x1fe3fcfcUL, 0xc879b1b1UL, 0xedb65b5bUL, + 0xbed46a6aUL, 0x468dcbcbUL, 0xd967bebeUL, 0x4b723939UL, + 0xde944a4aUL, 0xd4984c4cUL, 0xe8b05858UL, 0x4a85cfcfUL, + 0x6bbbd0d0UL, 0x2ac5efefUL, 0xe54faaaaUL, 0x16edfbfbUL, + 0xc5864343UL, 0xd79a4d4dUL, 0x55663333UL, 0x94118585UL, + 0xcf8a4545UL, 0x10e9f9f9UL, 0x06040202UL, 0x81fe7f7fUL, + 0xf0a05050UL, 0x44783c3cUL, 0xba259f9fUL, 0xe34ba8a8UL, + 0xf3a25151UL, 0xfe5da3a3UL, 0xc0804040UL, 0x8a058f8fUL, + 0xad3f9292UL, 0xbc219d9dUL, 0x48703838UL, 0x04f1f5f5UL, + 0xdf63bcbcUL, 0xc177b6b6UL, 0x75afdadaUL, 0x63422121UL, + 0x30201010UL, 0x1ae5ffffUL, 0x0efdf3f3UL, 0x6dbfd2d2UL, + 0x4c81cdcdUL, 0x14180c0cUL, 0x35261313UL, 0x2fc3ececUL, + 0xe1be5f5fUL, 0xa2359797UL, 0xcc884444UL, 0x392e1717UL, + 0x5793c4c4UL, 0xf255a7a7UL, 0x82fc7e7eUL, 0x477a3d3dUL, + 0xacc86464UL, 0xe7ba5d5dUL, 0x2b321919UL, 0x95e67373UL, + 0xa0c06060UL, 0x98198181UL, 0xd19e4f4fUL, 0x7fa3dcdcUL, + 0x66442222UL, 0x7e542a2aUL, 0xab3b9090UL, 0x830b8888UL, + 0xca8c4646UL, 0x29c7eeeeUL, 0xd36bb8b8UL, 0x3c281414UL, + 0x79a7dedeUL, 0xe2bc5e5eUL, 0x1d160b0bUL, 0x76addbdbUL, + 0x3bdbe0e0UL, 0x56643232UL, 0x4e743a3aUL, 0x1e140a0aUL, + 0xdb924949UL, 0x0a0c0606UL, 0x6c482424UL, 0xe4b85c5cUL, + 0x5d9fc2c2UL, 0x6ebdd3d3UL, 0xef43acacUL, 0xa6c46262UL, + 0xa8399191UL, 0xa4319595UL, 0x37d3e4e4UL, 0x8bf27979UL, + 0x32d5e7e7UL, 0x438bc8c8UL, 0x596e3737UL, 0xb7da6d6dUL, + 0x8c018d8dUL, 0x64b1d5d5UL, 0xd29c4e4eUL, 0xe049a9a9UL, + 0xb4d86c6cUL, 0xfaac5656UL, 0x07f3f4f4UL, 0x25cfeaeaUL, + 0xafca6565UL, 0x8ef47a7aUL, 0xe947aeaeUL, 0x18100808UL, + 0xd56fbabaUL, 0x88f07878UL, 0x6f4a2525UL, 0x725c2e2eUL, + 0x24381c1cUL, 0xf157a6a6UL, 0xc773b4b4UL, 0x5197c6c6UL, + 0x23cbe8e8UL, 0x7ca1ddddUL, 0x9ce87474UL, 0x213e1f1fUL, + 0xdd964b4bUL, 0xdc61bdbdUL, 0x860d8b8bUL, 0x850f8a8aUL, + 0x90e07070UL, 0x427c3e3eUL, 0xc471b5b5UL, 0xaacc6666UL, + 0xd8904848UL, 0x05060303UL, 0x01f7f6f6UL, 0x121c0e0eUL, + 0xa3c26161UL, 0x5f6a3535UL, 0xf9ae5757UL, 0xd069b9b9UL, + 0x91178686UL, 0x5899c1c1UL, 0x273a1d1dUL, 0xb9279e9eUL, + 0x38d9e1e1UL, 0x13ebf8f8UL, 0xb32b9898UL, 0x33221111UL, + 0xbbd26969UL, 0x70a9d9d9UL, 0x89078e8eUL, 0xa7339494UL, + 0xb62d9b9bUL, 0x223c1e1eUL, 0x92158787UL, 0x20c9e9e9UL, + 0x4987ceceUL, 0xffaa5555UL, 0x78502828UL, 0x7aa5dfdfUL, + 0x8f038c8cUL, 0xf859a1a1UL, 0x80098989UL, 0x171a0d0dUL, + 0xda65bfbfUL, 0x31d7e6e6UL, 0xc6844242UL, 0xb8d06868UL, + 0xc3824141UL, 0xb0299999UL, 0x775a2d2dUL, 0x111e0f0fUL, + 0xcb7bb0b0UL, 0xfca85454UL, 0xd66dbbbbUL, 0x3a2c1616UL, +}; +static const unsigned int Te2[256] = { + 0x63a5c663UL, 0x7c84f87cUL, 0x7799ee77UL, 0x7b8df67bUL, + 0xf20dfff2UL, 0x6bbdd66bUL, 0x6fb1de6fUL, 0xc55491c5UL, + 0x30506030UL, 0x01030201UL, 0x67a9ce67UL, 0x2b7d562bUL, + 0xfe19e7feUL, 0xd762b5d7UL, 0xabe64dabUL, 0x769aec76UL, + 0xca458fcaUL, 0x829d1f82UL, 0xc94089c9UL, 0x7d87fa7dUL, + 0xfa15effaUL, 0x59ebb259UL, 0x47c98e47UL, 0xf00bfbf0UL, + 0xadec41adUL, 0xd467b3d4UL, 0xa2fd5fa2UL, 0xafea45afUL, + 0x9cbf239cUL, 0xa4f753a4UL, 0x7296e472UL, 0xc05b9bc0UL, + 0xb7c275b7UL, 0xfd1ce1fdUL, 0x93ae3d93UL, 0x266a4c26UL, + 0x365a6c36UL, 0x3f417e3fUL, 0xf702f5f7UL, 0xcc4f83ccUL, + 0x345c6834UL, 0xa5f451a5UL, 0xe534d1e5UL, 0xf108f9f1UL, + 0x7193e271UL, 0xd873abd8UL, 0x31536231UL, 0x153f2a15UL, + 0x040c0804UL, 0xc75295c7UL, 0x23654623UL, 0xc35e9dc3UL, + 0x18283018UL, 0x96a13796UL, 0x050f0a05UL, 0x9ab52f9aUL, + 0x07090e07UL, 0x12362412UL, 0x809b1b80UL, 0xe23ddfe2UL, + 0xeb26cdebUL, 0x27694e27UL, 0xb2cd7fb2UL, 0x759fea75UL, + 0x091b1209UL, 0x839e1d83UL, 0x2c74582cUL, 0x1a2e341aUL, + 0x1b2d361bUL, 0x6eb2dc6eUL, 0x5aeeb45aUL, 0xa0fb5ba0UL, + 0x52f6a452UL, 0x3b4d763bUL, 0xd661b7d6UL, 0xb3ce7db3UL, + 0x297b5229UL, 0xe33edde3UL, 0x2f715e2fUL, 0x84971384UL, + 0x53f5a653UL, 0xd168b9d1UL, 0x00000000UL, 0xed2cc1edUL, + 0x20604020UL, 0xfc1fe3fcUL, 0xb1c879b1UL, 0x5bedb65bUL, + 0x6abed46aUL, 0xcb468dcbUL, 0xbed967beUL, 0x394b7239UL, + 0x4ade944aUL, 0x4cd4984cUL, 0x58e8b058UL, 0xcf4a85cfUL, + 0xd06bbbd0UL, 0xef2ac5efUL, 0xaae54faaUL, 0xfb16edfbUL, + 0x43c58643UL, 0x4dd79a4dUL, 0x33556633UL, 0x85941185UL, + 0x45cf8a45UL, 0xf910e9f9UL, 0x02060402UL, 0x7f81fe7fUL, + 0x50f0a050UL, 0x3c44783cUL, 0x9fba259fUL, 0xa8e34ba8UL, + 0x51f3a251UL, 0xa3fe5da3UL, 0x40c08040UL, 0x8f8a058fUL, + 0x92ad3f92UL, 0x9dbc219dUL, 0x38487038UL, 0xf504f1f5UL, + 0xbcdf63bcUL, 0xb6c177b6UL, 0xda75afdaUL, 0x21634221UL, + 0x10302010UL, 0xff1ae5ffUL, 0xf30efdf3UL, 0xd26dbfd2UL, + 0xcd4c81cdUL, 0x0c14180cUL, 0x13352613UL, 0xec2fc3ecUL, + 0x5fe1be5fUL, 0x97a23597UL, 0x44cc8844UL, 0x17392e17UL, + 0xc45793c4UL, 0xa7f255a7UL, 0x7e82fc7eUL, 0x3d477a3dUL, + 0x64acc864UL, 0x5de7ba5dUL, 0x192b3219UL, 0x7395e673UL, + 0x60a0c060UL, 0x81981981UL, 0x4fd19e4fUL, 0xdc7fa3dcUL, + 0x22664422UL, 0x2a7e542aUL, 0x90ab3b90UL, 0x88830b88UL, + 0x46ca8c46UL, 0xee29c7eeUL, 0xb8d36bb8UL, 0x143c2814UL, + 0xde79a7deUL, 0x5ee2bc5eUL, 0x0b1d160bUL, 0xdb76addbUL, + 0xe03bdbe0UL, 0x32566432UL, 0x3a4e743aUL, 0x0a1e140aUL, + 0x49db9249UL, 0x060a0c06UL, 0x246c4824UL, 0x5ce4b85cUL, + 0xc25d9fc2UL, 0xd36ebdd3UL, 0xacef43acUL, 0x62a6c462UL, + 0x91a83991UL, 0x95a43195UL, 0xe437d3e4UL, 0x798bf279UL, + 0xe732d5e7UL, 0xc8438bc8UL, 0x37596e37UL, 0x6db7da6dUL, + 0x8d8c018dUL, 0xd564b1d5UL, 0x4ed29c4eUL, 0xa9e049a9UL, + 0x6cb4d86cUL, 0x56faac56UL, 0xf407f3f4UL, 0xea25cfeaUL, + 0x65afca65UL, 0x7a8ef47aUL, 0xaee947aeUL, 0x08181008UL, + 0xbad56fbaUL, 0x7888f078UL, 0x256f4a25UL, 0x2e725c2eUL, + 0x1c24381cUL, 0xa6f157a6UL, 0xb4c773b4UL, 0xc65197c6UL, + 0xe823cbe8UL, 0xdd7ca1ddUL, 0x749ce874UL, 0x1f213e1fUL, + 0x4bdd964bUL, 0xbddc61bdUL, 0x8b860d8bUL, 0x8a850f8aUL, + 0x7090e070UL, 0x3e427c3eUL, 0xb5c471b5UL, 0x66aacc66UL, + 0x48d89048UL, 0x03050603UL, 0xf601f7f6UL, 0x0e121c0eUL, + 0x61a3c261UL, 0x355f6a35UL, 0x57f9ae57UL, 0xb9d069b9UL, + 0x86911786UL, 0xc15899c1UL, 0x1d273a1dUL, 0x9eb9279eUL, + 0xe138d9e1UL, 0xf813ebf8UL, 0x98b32b98UL, 0x11332211UL, + 0x69bbd269UL, 0xd970a9d9UL, 0x8e89078eUL, 0x94a73394UL, + 0x9bb62d9bUL, 0x1e223c1eUL, 0x87921587UL, 0xe920c9e9UL, + 0xce4987ceUL, 0x55ffaa55UL, 0x28785028UL, 0xdf7aa5dfUL, + 0x8c8f038cUL, 0xa1f859a1UL, 0x89800989UL, 0x0d171a0dUL, + 0xbfda65bfUL, 0xe631d7e6UL, 0x42c68442UL, 0x68b8d068UL, + 0x41c38241UL, 0x99b02999UL, 0x2d775a2dUL, 0x0f111e0fUL, + 0xb0cb7bb0UL, 0x54fca854UL, 0xbbd66dbbUL, 0x163a2c16UL, +}; +static const unsigned int Te3[256] = { + 0x6363a5c6UL, 0x7c7c84f8UL, 0x777799eeUL, 0x7b7b8df6UL, + 0xf2f20dffUL, 0x6b6bbdd6UL, 0x6f6fb1deUL, 0xc5c55491UL, + 0x30305060UL, 0x01010302UL, 0x6767a9ceUL, 0x2b2b7d56UL, + 0xfefe19e7UL, 0xd7d762b5UL, 0xababe64dUL, 0x76769aecUL, + 0xcaca458fUL, 0x82829d1fUL, 0xc9c94089UL, 0x7d7d87faUL, + 0xfafa15efUL, 0x5959ebb2UL, 0x4747c98eUL, 0xf0f00bfbUL, + 0xadadec41UL, 0xd4d467b3UL, 0xa2a2fd5fUL, 0xafafea45UL, + 0x9c9cbf23UL, 0xa4a4f753UL, 0x727296e4UL, 0xc0c05b9bUL, + 0xb7b7c275UL, 0xfdfd1ce1UL, 0x9393ae3dUL, 0x26266a4cUL, + 0x36365a6cUL, 0x3f3f417eUL, 0xf7f702f5UL, 0xcccc4f83UL, + 0x34345c68UL, 0xa5a5f451UL, 0xe5e534d1UL, 0xf1f108f9UL, + 0x717193e2UL, 0xd8d873abUL, 0x31315362UL, 0x15153f2aUL, + 0x04040c08UL, 0xc7c75295UL, 0x23236546UL, 0xc3c35e9dUL, + 0x18182830UL, 0x9696a137UL, 0x05050f0aUL, 0x9a9ab52fUL, + 0x0707090eUL, 0x12123624UL, 0x80809b1bUL, 0xe2e23ddfUL, + 0xebeb26cdUL, 0x2727694eUL, 0xb2b2cd7fUL, 0x75759feaUL, + 0x09091b12UL, 0x83839e1dUL, 0x2c2c7458UL, 0x1a1a2e34UL, + 0x1b1b2d36UL, 0x6e6eb2dcUL, 0x5a5aeeb4UL, 0xa0a0fb5bUL, + 0x5252f6a4UL, 0x3b3b4d76UL, 0xd6d661b7UL, 0xb3b3ce7dUL, + 0x29297b52UL, 0xe3e33eddUL, 0x2f2f715eUL, 0x84849713UL, + 0x5353f5a6UL, 0xd1d168b9UL, 0x00000000UL, 0xeded2cc1UL, + 0x20206040UL, 0xfcfc1fe3UL, 0xb1b1c879UL, 0x5b5bedb6UL, + 0x6a6abed4UL, 0xcbcb468dUL, 0xbebed967UL, 0x39394b72UL, + 0x4a4ade94UL, 0x4c4cd498UL, 0x5858e8b0UL, 0xcfcf4a85UL, + 0xd0d06bbbUL, 0xefef2ac5UL, 0xaaaae54fUL, 0xfbfb16edUL, + 0x4343c586UL, 0x4d4dd79aUL, 0x33335566UL, 0x85859411UL, + 0x4545cf8aUL, 0xf9f910e9UL, 0x02020604UL, 0x7f7f81feUL, + 0x5050f0a0UL, 0x3c3c4478UL, 0x9f9fba25UL, 0xa8a8e34bUL, + 0x5151f3a2UL, 0xa3a3fe5dUL, 0x4040c080UL, 0x8f8f8a05UL, + 0x9292ad3fUL, 0x9d9dbc21UL, 0x38384870UL, 0xf5f504f1UL, + 0xbcbcdf63UL, 0xb6b6c177UL, 0xdada75afUL, 0x21216342UL, + 0x10103020UL, 0xffff1ae5UL, 0xf3f30efdUL, 0xd2d26dbfUL, + 0xcdcd4c81UL, 0x0c0c1418UL, 0x13133526UL, 0xecec2fc3UL, + 0x5f5fe1beUL, 0x9797a235UL, 0x4444cc88UL, 0x1717392eUL, + 0xc4c45793UL, 0xa7a7f255UL, 0x7e7e82fcUL, 0x3d3d477aUL, + 0x6464acc8UL, 0x5d5de7baUL, 0x19192b32UL, 0x737395e6UL, + 0x6060a0c0UL, 0x81819819UL, 0x4f4fd19eUL, 0xdcdc7fa3UL, + 0x22226644UL, 0x2a2a7e54UL, 0x9090ab3bUL, 0x8888830bUL, + 0x4646ca8cUL, 0xeeee29c7UL, 0xb8b8d36bUL, 0x14143c28UL, + 0xdede79a7UL, 0x5e5ee2bcUL, 0x0b0b1d16UL, 0xdbdb76adUL, + 0xe0e03bdbUL, 0x32325664UL, 0x3a3a4e74UL, 0x0a0a1e14UL, + 0x4949db92UL, 0x06060a0cUL, 0x24246c48UL, 0x5c5ce4b8UL, + 0xc2c25d9fUL, 0xd3d36ebdUL, 0xacacef43UL, 0x6262a6c4UL, + 0x9191a839UL, 0x9595a431UL, 0xe4e437d3UL, 0x79798bf2UL, + 0xe7e732d5UL, 0xc8c8438bUL, 0x3737596eUL, 0x6d6db7daUL, + 0x8d8d8c01UL, 0xd5d564b1UL, 0x4e4ed29cUL, 0xa9a9e049UL, + 0x6c6cb4d8UL, 0x5656faacUL, 0xf4f407f3UL, 0xeaea25cfUL, + 0x6565afcaUL, 0x7a7a8ef4UL, 0xaeaee947UL, 0x08081810UL, + 0xbabad56fUL, 0x787888f0UL, 0x25256f4aUL, 0x2e2e725cUL, + 0x1c1c2438UL, 0xa6a6f157UL, 0xb4b4c773UL, 0xc6c65197UL, + 0xe8e823cbUL, 0xdddd7ca1UL, 0x74749ce8UL, 0x1f1f213eUL, + 0x4b4bdd96UL, 0xbdbddc61UL, 0x8b8b860dUL, 0x8a8a850fUL, + 0x707090e0UL, 0x3e3e427cUL, 0xb5b5c471UL, 0x6666aaccUL, + 0x4848d890UL, 0x03030506UL, 0xf6f601f7UL, 0x0e0e121cUL, + 0x6161a3c2UL, 0x35355f6aUL, 0x5757f9aeUL, 0xb9b9d069UL, + 0x86869117UL, 0xc1c15899UL, 0x1d1d273aUL, 0x9e9eb927UL, + 0xe1e138d9UL, 0xf8f813ebUL, 0x9898b32bUL, 0x11113322UL, + 0x6969bbd2UL, 0xd9d970a9UL, 0x8e8e8907UL, 0x9494a733UL, + 0x9b9bb62dUL, 0x1e1e223cUL, 0x87879215UL, 0xe9e920c9UL, + 0xcece4987UL, 0x5555ffaaUL, 0x28287850UL, 0xdfdf7aa5UL, + 0x8c8c8f03UL, 0xa1a1f859UL, 0x89898009UL, 0x0d0d171aUL, + 0xbfbfda65UL, 0xe6e631d7UL, 0x4242c684UL, 0x6868b8d0UL, + 0x4141c382UL, 0x9999b029UL, 0x2d2d775aUL, 0x0f0f111eUL, + 0xb0b0cb7bUL, 0x5454fca8UL, 0xbbbbd66dUL, 0x16163a2cUL, +}; +static const unsigned int Te4[256] = { + 0x63636363UL, 0x7c7c7c7cUL, 0x77777777UL, 0x7b7b7b7bUL, + 0xf2f2f2f2UL, 0x6b6b6b6bUL, 0x6f6f6f6fUL, 0xc5c5c5c5UL, + 0x30303030UL, 0x01010101UL, 0x67676767UL, 0x2b2b2b2bUL, + 0xfefefefeUL, 0xd7d7d7d7UL, 0xababababUL, 0x76767676UL, + 0xcacacacaUL, 0x82828282UL, 0xc9c9c9c9UL, 0x7d7d7d7dUL, + 0xfafafafaUL, 0x59595959UL, 0x47474747UL, 0xf0f0f0f0UL, + 0xadadadadUL, 0xd4d4d4d4UL, 0xa2a2a2a2UL, 0xafafafafUL, + 0x9c9c9c9cUL, 0xa4a4a4a4UL, 0x72727272UL, 0xc0c0c0c0UL, + 0xb7b7b7b7UL, 0xfdfdfdfdUL, 0x93939393UL, 0x26262626UL, + 0x36363636UL, 0x3f3f3f3fUL, 0xf7f7f7f7UL, 0xccccccccUL, + 0x34343434UL, 0xa5a5a5a5UL, 0xe5e5e5e5UL, 0xf1f1f1f1UL, + 0x71717171UL, 0xd8d8d8d8UL, 0x31313131UL, 0x15151515UL, + 0x04040404UL, 0xc7c7c7c7UL, 0x23232323UL, 0xc3c3c3c3UL, + 0x18181818UL, 0x96969696UL, 0x05050505UL, 0x9a9a9a9aUL, + 0x07070707UL, 0x12121212UL, 0x80808080UL, 0xe2e2e2e2UL, + 0xebebebebUL, 0x27272727UL, 0xb2b2b2b2UL, 0x75757575UL, + 0x09090909UL, 0x83838383UL, 0x2c2c2c2cUL, 0x1a1a1a1aUL, + 0x1b1b1b1bUL, 0x6e6e6e6eUL, 0x5a5a5a5aUL, 0xa0a0a0a0UL, + 0x52525252UL, 0x3b3b3b3bUL, 0xd6d6d6d6UL, 0xb3b3b3b3UL, + 0x29292929UL, 0xe3e3e3e3UL, 0x2f2f2f2fUL, 0x84848484UL, + 0x53535353UL, 0xd1d1d1d1UL, 0x00000000UL, 0xededededUL, + 0x20202020UL, 0xfcfcfcfcUL, 0xb1b1b1b1UL, 0x5b5b5b5bUL, + 0x6a6a6a6aUL, 0xcbcbcbcbUL, 0xbebebebeUL, 0x39393939UL, + 0x4a4a4a4aUL, 0x4c4c4c4cUL, 0x58585858UL, 0xcfcfcfcfUL, + 0xd0d0d0d0UL, 0xefefefefUL, 0xaaaaaaaaUL, 0xfbfbfbfbUL, + 0x43434343UL, 0x4d4d4d4dUL, 0x33333333UL, 0x85858585UL, + 0x45454545UL, 0xf9f9f9f9UL, 0x02020202UL, 0x7f7f7f7fUL, + 0x50505050UL, 0x3c3c3c3cUL, 0x9f9f9f9fUL, 0xa8a8a8a8UL, + 0x51515151UL, 0xa3a3a3a3UL, 0x40404040UL, 0x8f8f8f8fUL, + 0x92929292UL, 0x9d9d9d9dUL, 0x38383838UL, 0xf5f5f5f5UL, + 0xbcbcbcbcUL, 0xb6b6b6b6UL, 0xdadadadaUL, 0x21212121UL, + 0x10101010UL, 0xffffffffUL, 0xf3f3f3f3UL, 0xd2d2d2d2UL, + 0xcdcdcdcdUL, 0x0c0c0c0cUL, 0x13131313UL, 0xececececUL, + 0x5f5f5f5fUL, 0x97979797UL, 0x44444444UL, 0x17171717UL, + 0xc4c4c4c4UL, 0xa7a7a7a7UL, 0x7e7e7e7eUL, 0x3d3d3d3dUL, + 0x64646464UL, 0x5d5d5d5dUL, 0x19191919UL, 0x73737373UL, + 0x60606060UL, 0x81818181UL, 0x4f4f4f4fUL, 0xdcdcdcdcUL, + 0x22222222UL, 0x2a2a2a2aUL, 0x90909090UL, 0x88888888UL, + 0x46464646UL, 0xeeeeeeeeUL, 0xb8b8b8b8UL, 0x14141414UL, + 0xdedededeUL, 0x5e5e5e5eUL, 0x0b0b0b0bUL, 0xdbdbdbdbUL, + 0xe0e0e0e0UL, 0x32323232UL, 0x3a3a3a3aUL, 0x0a0a0a0aUL, + 0x49494949UL, 0x06060606UL, 0x24242424UL, 0x5c5c5c5cUL, + 0xc2c2c2c2UL, 0xd3d3d3d3UL, 0xacacacacUL, 0x62626262UL, + 0x91919191UL, 0x95959595UL, 0xe4e4e4e4UL, 0x79797979UL, + 0xe7e7e7e7UL, 0xc8c8c8c8UL, 0x37373737UL, 0x6d6d6d6dUL, + 0x8d8d8d8dUL, 0xd5d5d5d5UL, 0x4e4e4e4eUL, 0xa9a9a9a9UL, + 0x6c6c6c6cUL, 0x56565656UL, 0xf4f4f4f4UL, 0xeaeaeaeaUL, + 0x65656565UL, 0x7a7a7a7aUL, 0xaeaeaeaeUL, 0x08080808UL, + 0xbabababaUL, 0x78787878UL, 0x25252525UL, 0x2e2e2e2eUL, + 0x1c1c1c1cUL, 0xa6a6a6a6UL, 0xb4b4b4b4UL, 0xc6c6c6c6UL, + 0xe8e8e8e8UL, 0xddddddddUL, 0x74747474UL, 0x1f1f1f1fUL, + 0x4b4b4b4bUL, 0xbdbdbdbdUL, 0x8b8b8b8bUL, 0x8a8a8a8aUL, + 0x70707070UL, 0x3e3e3e3eUL, 0xb5b5b5b5UL, 0x66666666UL, + 0x48484848UL, 0x03030303UL, 0xf6f6f6f6UL, 0x0e0e0e0eUL, + 0x61616161UL, 0x35353535UL, 0x57575757UL, 0xb9b9b9b9UL, + 0x86868686UL, 0xc1c1c1c1UL, 0x1d1d1d1dUL, 0x9e9e9e9eUL, + 0xe1e1e1e1UL, 0xf8f8f8f8UL, 0x98989898UL, 0x11111111UL, + 0x69696969UL, 0xd9d9d9d9UL, 0x8e8e8e8eUL, 0x94949494UL, + 0x9b9b9b9bUL, 0x1e1e1e1eUL, 0x87878787UL, 0xe9e9e9e9UL, + 0xcecececeUL, 0x55555555UL, 0x28282828UL, 0xdfdfdfdfUL, + 0x8c8c8c8cUL, 0xa1a1a1a1UL, 0x89898989UL, 0x0d0d0d0dUL, + 0xbfbfbfbfUL, 0xe6e6e6e6UL, 0x42424242UL, 0x68686868UL, + 0x41414141UL, 0x99999999UL, 0x2d2d2d2dUL, 0x0f0f0f0fUL, + 0xb0b0b0b0UL, 0x54545454UL, 0xbbbbbbbbUL, 0x16161616UL, +}; +static const unsigned int Td0[256] = { + 0x51f4a750UL, 0x7e416553UL, 0x1a17a4c3UL, 0x3a275e96UL, + 0x3bab6bcbUL, 0x1f9d45f1UL, 0xacfa58abUL, 0x4be30393UL, + 0x2030fa55UL, 0xad766df6UL, 0x88cc7691UL, 0xf5024c25UL, + 0x4fe5d7fcUL, 0xc52acbd7UL, 0x26354480UL, 0xb562a38fUL, + 0xdeb15a49UL, 0x25ba1b67UL, 0x45ea0e98UL, 0x5dfec0e1UL, + 0xc32f7502UL, 0x814cf012UL, 0x8d4697a3UL, 0x6bd3f9c6UL, + 0x038f5fe7UL, 0x15929c95UL, 0xbf6d7aebUL, 0x955259daUL, + 0xd4be832dUL, 0x587421d3UL, 0x49e06929UL, 0x8ec9c844UL, + 0x75c2896aUL, 0xf48e7978UL, 0x99583e6bUL, 0x27b971ddUL, + 0xbee14fb6UL, 0xf088ad17UL, 0xc920ac66UL, 0x7dce3ab4UL, + 0x63df4a18UL, 0xe51a3182UL, 0x97513360UL, 0x62537f45UL, + 0xb16477e0UL, 0xbb6bae84UL, 0xfe81a01cUL, 0xf9082b94UL, + 0x70486858UL, 0x8f45fd19UL, 0x94de6c87UL, 0x527bf8b7UL, + 0xab73d323UL, 0x724b02e2UL, 0xe31f8f57UL, 0x6655ab2aUL, + 0xb2eb2807UL, 0x2fb5c203UL, 0x86c57b9aUL, 0xd33708a5UL, + 0x302887f2UL, 0x23bfa5b2UL, 0x02036abaUL, 0xed16825cUL, + 0x8acf1c2bUL, 0xa779b492UL, 0xf307f2f0UL, 0x4e69e2a1UL, + 0x65daf4cdUL, 0x0605bed5UL, 0xd134621fUL, 0xc4a6fe8aUL, + 0x342e539dUL, 0xa2f355a0UL, 0x058ae132UL, 0xa4f6eb75UL, + 0x0b83ec39UL, 0x4060efaaUL, 0x5e719f06UL, 0xbd6e1051UL, + 0x3e218af9UL, 0x96dd063dUL, 0xdd3e05aeUL, 0x4de6bd46UL, + 0x91548db5UL, 0x71c45d05UL, 0x0406d46fUL, 0x605015ffUL, + 0x1998fb24UL, 0xd6bde997UL, 0x894043ccUL, 0x67d99e77UL, + 0xb0e842bdUL, 0x07898b88UL, 0xe7195b38UL, 0x79c8eedbUL, + 0xa17c0a47UL, 0x7c420fe9UL, 0xf8841ec9UL, 0x00000000UL, + 0x09808683UL, 0x322bed48UL, 0x1e1170acUL, 0x6c5a724eUL, + 0xfd0efffbUL, 0x0f853856UL, 0x3daed51eUL, 0x362d3927UL, + 0x0a0fd964UL, 0x685ca621UL, 0x9b5b54d1UL, 0x24362e3aUL, + 0x0c0a67b1UL, 0x9357e70fUL, 0xb4ee96d2UL, 0x1b9b919eUL, + 0x80c0c54fUL, 0x61dc20a2UL, 0x5a774b69UL, 0x1c121a16UL, + 0xe293ba0aUL, 0xc0a02ae5UL, 0x3c22e043UL, 0x121b171dUL, + 0x0e090d0bUL, 0xf28bc7adUL, 0x2db6a8b9UL, 0x141ea9c8UL, + 0x57f11985UL, 0xaf75074cUL, 0xee99ddbbUL, 0xa37f60fdUL, + 0xf701269fUL, 0x5c72f5bcUL, 0x44663bc5UL, 0x5bfb7e34UL, + 0x8b432976UL, 0xcb23c6dcUL, 0xb6edfc68UL, 0xb8e4f163UL, + 0xd731dccaUL, 0x42638510UL, 0x13972240UL, 0x84c61120UL, + 0x854a247dUL, 0xd2bb3df8UL, 0xaef93211UL, 0xc729a16dUL, + 0x1d9e2f4bUL, 0xdcb230f3UL, 0x0d8652ecUL, 0x77c1e3d0UL, + 0x2bb3166cUL, 0xa970b999UL, 0x119448faUL, 0x47e96422UL, + 0xa8fc8cc4UL, 0xa0f03f1aUL, 0x567d2cd8UL, 0x223390efUL, + 0x87494ec7UL, 0xd938d1c1UL, 0x8ccaa2feUL, 0x98d40b36UL, + 0xa6f581cfUL, 0xa57ade28UL, 0xdab78e26UL, 0x3fadbfa4UL, + 0x2c3a9de4UL, 0x5078920dUL, 0x6a5fcc9bUL, 0x547e4662UL, + 0xf68d13c2UL, 0x90d8b8e8UL, 0x2e39f75eUL, 0x82c3aff5UL, + 0x9f5d80beUL, 0x69d0937cUL, 0x6fd52da9UL, 0xcf2512b3UL, + 0xc8ac993bUL, 0x10187da7UL, 0xe89c636eUL, 0xdb3bbb7bUL, + 0xcd267809UL, 0x6e5918f4UL, 0xec9ab701UL, 0x834f9aa8UL, + 0xe6956e65UL, 0xaaffe67eUL, 0x21bccf08UL, 0xef15e8e6UL, + 0xbae79bd9UL, 0x4a6f36ceUL, 0xea9f09d4UL, 0x29b07cd6UL, + 0x31a4b2afUL, 0x2a3f2331UL, 0xc6a59430UL, 0x35a266c0UL, + 0x744ebc37UL, 0xfc82caa6UL, 0xe090d0b0UL, 0x33a7d815UL, + 0xf104984aUL, 0x41ecdaf7UL, 0x7fcd500eUL, 0x1791f62fUL, + 0x764dd68dUL, 0x43efb04dUL, 0xccaa4d54UL, 0xe49604dfUL, + 0x9ed1b5e3UL, 0x4c6a881bUL, 0xc12c1fb8UL, 0x4665517fUL, + 0x9d5eea04UL, 0x018c355dUL, 0xfa877473UL, 0xfb0b412eUL, + 0xb3671d5aUL, 0x92dbd252UL, 0xe9105633UL, 0x6dd64713UL, + 0x9ad7618cUL, 0x37a10c7aUL, 0x59f8148eUL, 0xeb133c89UL, + 0xcea927eeUL, 0xb761c935UL, 0xe11ce5edUL, 0x7a47b13cUL, + 0x9cd2df59UL, 0x55f2733fUL, 0x1814ce79UL, 0x73c737bfUL, + 0x53f7cdeaUL, 0x5ffdaa5bUL, 0xdf3d6f14UL, 0x7844db86UL, + 0xcaaff381UL, 0xb968c43eUL, 0x3824342cUL, 0xc2a3405fUL, + 0x161dc372UL, 0xbce2250cUL, 0x283c498bUL, 0xff0d9541UL, + 0x39a80171UL, 0x080cb3deUL, 0xd8b4e49cUL, 0x6456c190UL, + 0x7bcb8461UL, 0xd532b670UL, 0x486c5c74UL, 0xd0b85742UL, +}; +static const unsigned int Td1[256] = { + 0x5051f4a7UL, 0x537e4165UL, 0xc31a17a4UL, 0x963a275eUL, + 0xcb3bab6bUL, 0xf11f9d45UL, 0xabacfa58UL, 0x934be303UL, + 0x552030faUL, 0xf6ad766dUL, 0x9188cc76UL, 0x25f5024cUL, + 0xfc4fe5d7UL, 0xd7c52acbUL, 0x80263544UL, 0x8fb562a3UL, + 0x49deb15aUL, 0x6725ba1bUL, 0x9845ea0eUL, 0xe15dfec0UL, + 0x02c32f75UL, 0x12814cf0UL, 0xa38d4697UL, 0xc66bd3f9UL, + 0xe7038f5fUL, 0x9515929cUL, 0xebbf6d7aUL, 0xda955259UL, + 0x2dd4be83UL, 0xd3587421UL, 0x2949e069UL, 0x448ec9c8UL, + 0x6a75c289UL, 0x78f48e79UL, 0x6b99583eUL, 0xdd27b971UL, + 0xb6bee14fUL, 0x17f088adUL, 0x66c920acUL, 0xb47dce3aUL, + 0x1863df4aUL, 0x82e51a31UL, 0x60975133UL, 0x4562537fUL, + 0xe0b16477UL, 0x84bb6baeUL, 0x1cfe81a0UL, 0x94f9082bUL, + 0x58704868UL, 0x198f45fdUL, 0x8794de6cUL, 0xb7527bf8UL, + 0x23ab73d3UL, 0xe2724b02UL, 0x57e31f8fUL, 0x2a6655abUL, + 0x07b2eb28UL, 0x032fb5c2UL, 0x9a86c57bUL, 0xa5d33708UL, + 0xf2302887UL, 0xb223bfa5UL, 0xba02036aUL, 0x5ced1682UL, + 0x2b8acf1cUL, 0x92a779b4UL, 0xf0f307f2UL, 0xa14e69e2UL, + 0xcd65daf4UL, 0xd50605beUL, 0x1fd13462UL, 0x8ac4a6feUL, + 0x9d342e53UL, 0xa0a2f355UL, 0x32058ae1UL, 0x75a4f6ebUL, + 0x390b83ecUL, 0xaa4060efUL, 0x065e719fUL, 0x51bd6e10UL, + 0xf93e218aUL, 0x3d96dd06UL, 0xaedd3e05UL, 0x464de6bdUL, + 0xb591548dUL, 0x0571c45dUL, 0x6f0406d4UL, 0xff605015UL, + 0x241998fbUL, 0x97d6bde9UL, 0xcc894043UL, 0x7767d99eUL, + 0xbdb0e842UL, 0x8807898bUL, 0x38e7195bUL, 0xdb79c8eeUL, + 0x47a17c0aUL, 0xe97c420fUL, 0xc9f8841eUL, 0x00000000UL, + 0x83098086UL, 0x48322bedUL, 0xac1e1170UL, 0x4e6c5a72UL, + 0xfbfd0effUL, 0x560f8538UL, 0x1e3daed5UL, 0x27362d39UL, + 0x640a0fd9UL, 0x21685ca6UL, 0xd19b5b54UL, 0x3a24362eUL, + 0xb10c0a67UL, 0x0f9357e7UL, 0xd2b4ee96UL, 0x9e1b9b91UL, + 0x4f80c0c5UL, 0xa261dc20UL, 0x695a774bUL, 0x161c121aUL, + 0x0ae293baUL, 0xe5c0a02aUL, 0x433c22e0UL, 0x1d121b17UL, + 0x0b0e090dUL, 0xadf28bc7UL, 0xb92db6a8UL, 0xc8141ea9UL, + 0x8557f119UL, 0x4caf7507UL, 0xbbee99ddUL, 0xfda37f60UL, + 0x9ff70126UL, 0xbc5c72f5UL, 0xc544663bUL, 0x345bfb7eUL, + 0x768b4329UL, 0xdccb23c6UL, 0x68b6edfcUL, 0x63b8e4f1UL, + 0xcad731dcUL, 0x10426385UL, 0x40139722UL, 0x2084c611UL, + 0x7d854a24UL, 0xf8d2bb3dUL, 0x11aef932UL, 0x6dc729a1UL, + 0x4b1d9e2fUL, 0xf3dcb230UL, 0xec0d8652UL, 0xd077c1e3UL, + 0x6c2bb316UL, 0x99a970b9UL, 0xfa119448UL, 0x2247e964UL, + 0xc4a8fc8cUL, 0x1aa0f03fUL, 0xd8567d2cUL, 0xef223390UL, + 0xc787494eUL, 0xc1d938d1UL, 0xfe8ccaa2UL, 0x3698d40bUL, + 0xcfa6f581UL, 0x28a57adeUL, 0x26dab78eUL, 0xa43fadbfUL, + 0xe42c3a9dUL, 0x0d507892UL, 0x9b6a5fccUL, 0x62547e46UL, + 0xc2f68d13UL, 0xe890d8b8UL, 0x5e2e39f7UL, 0xf582c3afUL, + 0xbe9f5d80UL, 0x7c69d093UL, 0xa96fd52dUL, 0xb3cf2512UL, + 0x3bc8ac99UL, 0xa710187dUL, 0x6ee89c63UL, 0x7bdb3bbbUL, + 0x09cd2678UL, 0xf46e5918UL, 0x01ec9ab7UL, 0xa8834f9aUL, + 0x65e6956eUL, 0x7eaaffe6UL, 0x0821bccfUL, 0xe6ef15e8UL, + 0xd9bae79bUL, 0xce4a6f36UL, 0xd4ea9f09UL, 0xd629b07cUL, + 0xaf31a4b2UL, 0x312a3f23UL, 0x30c6a594UL, 0xc035a266UL, + 0x37744ebcUL, 0xa6fc82caUL, 0xb0e090d0UL, 0x1533a7d8UL, + 0x4af10498UL, 0xf741ecdaUL, 0x0e7fcd50UL, 0x2f1791f6UL, + 0x8d764dd6UL, 0x4d43efb0UL, 0x54ccaa4dUL, 0xdfe49604UL, + 0xe39ed1b5UL, 0x1b4c6a88UL, 0xb8c12c1fUL, 0x7f466551UL, + 0x049d5eeaUL, 0x5d018c35UL, 0x73fa8774UL, 0x2efb0b41UL, + 0x5ab3671dUL, 0x5292dbd2UL, 0x33e91056UL, 0x136dd647UL, + 0x8c9ad761UL, 0x7a37a10cUL, 0x8e59f814UL, 0x89eb133cUL, + 0xeecea927UL, 0x35b761c9UL, 0xede11ce5UL, 0x3c7a47b1UL, + 0x599cd2dfUL, 0x3f55f273UL, 0x791814ceUL, 0xbf73c737UL, + 0xea53f7cdUL, 0x5b5ffdaaUL, 0x14df3d6fUL, 0x867844dbUL, + 0x81caaff3UL, 0x3eb968c4UL, 0x2c382434UL, 0x5fc2a340UL, + 0x72161dc3UL, 0x0cbce225UL, 0x8b283c49UL, 0x41ff0d95UL, + 0x7139a801UL, 0xde080cb3UL, 0x9cd8b4e4UL, 0x906456c1UL, + 0x617bcb84UL, 0x70d532b6UL, 0x74486c5cUL, 0x42d0b857UL, +}; +static const unsigned int Td2[256] = { + 0xa75051f4UL, 0x65537e41UL, 0xa4c31a17UL, 0x5e963a27UL, + 0x6bcb3babUL, 0x45f11f9dUL, 0x58abacfaUL, 0x03934be3UL, + 0xfa552030UL, 0x6df6ad76UL, 0x769188ccUL, 0x4c25f502UL, + 0xd7fc4fe5UL, 0xcbd7c52aUL, 0x44802635UL, 0xa38fb562UL, + 0x5a49deb1UL, 0x1b6725baUL, 0x0e9845eaUL, 0xc0e15dfeUL, + 0x7502c32fUL, 0xf012814cUL, 0x97a38d46UL, 0xf9c66bd3UL, + 0x5fe7038fUL, 0x9c951592UL, 0x7aebbf6dUL, 0x59da9552UL, + 0x832dd4beUL, 0x21d35874UL, 0x692949e0UL, 0xc8448ec9UL, + 0x896a75c2UL, 0x7978f48eUL, 0x3e6b9958UL, 0x71dd27b9UL, + 0x4fb6bee1UL, 0xad17f088UL, 0xac66c920UL, 0x3ab47dceUL, + 0x4a1863dfUL, 0x3182e51aUL, 0x33609751UL, 0x7f456253UL, + 0x77e0b164UL, 0xae84bb6bUL, 0xa01cfe81UL, 0x2b94f908UL, + 0x68587048UL, 0xfd198f45UL, 0x6c8794deUL, 0xf8b7527bUL, + 0xd323ab73UL, 0x02e2724bUL, 0x8f57e31fUL, 0xab2a6655UL, + 0x2807b2ebUL, 0xc2032fb5UL, 0x7b9a86c5UL, 0x08a5d337UL, + 0x87f23028UL, 0xa5b223bfUL, 0x6aba0203UL, 0x825ced16UL, + 0x1c2b8acfUL, 0xb492a779UL, 0xf2f0f307UL, 0xe2a14e69UL, + 0xf4cd65daUL, 0xbed50605UL, 0x621fd134UL, 0xfe8ac4a6UL, + 0x539d342eUL, 0x55a0a2f3UL, 0xe132058aUL, 0xeb75a4f6UL, + 0xec390b83UL, 0xefaa4060UL, 0x9f065e71UL, 0x1051bd6eUL, + 0x8af93e21UL, 0x063d96ddUL, 0x05aedd3eUL, 0xbd464de6UL, + 0x8db59154UL, 0x5d0571c4UL, 0xd46f0406UL, 0x15ff6050UL, + 0xfb241998UL, 0xe997d6bdUL, 0x43cc8940UL, 0x9e7767d9UL, + 0x42bdb0e8UL, 0x8b880789UL, 0x5b38e719UL, 0xeedb79c8UL, + 0x0a47a17cUL, 0x0fe97c42UL, 0x1ec9f884UL, 0x00000000UL, + 0x86830980UL, 0xed48322bUL, 0x70ac1e11UL, 0x724e6c5aUL, + 0xfffbfd0eUL, 0x38560f85UL, 0xd51e3daeUL, 0x3927362dUL, + 0xd9640a0fUL, 0xa621685cUL, 0x54d19b5bUL, 0x2e3a2436UL, + 0x67b10c0aUL, 0xe70f9357UL, 0x96d2b4eeUL, 0x919e1b9bUL, + 0xc54f80c0UL, 0x20a261dcUL, 0x4b695a77UL, 0x1a161c12UL, + 0xba0ae293UL, 0x2ae5c0a0UL, 0xe0433c22UL, 0x171d121bUL, + 0x0d0b0e09UL, 0xc7adf28bUL, 0xa8b92db6UL, 0xa9c8141eUL, + 0x198557f1UL, 0x074caf75UL, 0xddbbee99UL, 0x60fda37fUL, + 0x269ff701UL, 0xf5bc5c72UL, 0x3bc54466UL, 0x7e345bfbUL, + 0x29768b43UL, 0xc6dccb23UL, 0xfc68b6edUL, 0xf163b8e4UL, + 0xdccad731UL, 0x85104263UL, 0x22401397UL, 0x112084c6UL, + 0x247d854aUL, 0x3df8d2bbUL, 0x3211aef9UL, 0xa16dc729UL, + 0x2f4b1d9eUL, 0x30f3dcb2UL, 0x52ec0d86UL, 0xe3d077c1UL, + 0x166c2bb3UL, 0xb999a970UL, 0x48fa1194UL, 0x642247e9UL, + 0x8cc4a8fcUL, 0x3f1aa0f0UL, 0x2cd8567dUL, 0x90ef2233UL, + 0x4ec78749UL, 0xd1c1d938UL, 0xa2fe8ccaUL, 0x0b3698d4UL, + 0x81cfa6f5UL, 0xde28a57aUL, 0x8e26dab7UL, 0xbfa43fadUL, + 0x9de42c3aUL, 0x920d5078UL, 0xcc9b6a5fUL, 0x4662547eUL, + 0x13c2f68dUL, 0xb8e890d8UL, 0xf75e2e39UL, 0xaff582c3UL, + 0x80be9f5dUL, 0x937c69d0UL, 0x2da96fd5UL, 0x12b3cf25UL, + 0x993bc8acUL, 0x7da71018UL, 0x636ee89cUL, 0xbb7bdb3bUL, + 0x7809cd26UL, 0x18f46e59UL, 0xb701ec9aUL, 0x9aa8834fUL, + 0x6e65e695UL, 0xe67eaaffUL, 0xcf0821bcUL, 0xe8e6ef15UL, + 0x9bd9bae7UL, 0x36ce4a6fUL, 0x09d4ea9fUL, 0x7cd629b0UL, + 0xb2af31a4UL, 0x23312a3fUL, 0x9430c6a5UL, 0x66c035a2UL, + 0xbc37744eUL, 0xcaa6fc82UL, 0xd0b0e090UL, 0xd81533a7UL, + 0x984af104UL, 0xdaf741ecUL, 0x500e7fcdUL, 0xf62f1791UL, + 0xd68d764dUL, 0xb04d43efUL, 0x4d54ccaaUL, 0x04dfe496UL, + 0xb5e39ed1UL, 0x881b4c6aUL, 0x1fb8c12cUL, 0x517f4665UL, + 0xea049d5eUL, 0x355d018cUL, 0x7473fa87UL, 0x412efb0bUL, + 0x1d5ab367UL, 0xd25292dbUL, 0x5633e910UL, 0x47136dd6UL, + 0x618c9ad7UL, 0x0c7a37a1UL, 0x148e59f8UL, 0x3c89eb13UL, + 0x27eecea9UL, 0xc935b761UL, 0xe5ede11cUL, 0xb13c7a47UL, + 0xdf599cd2UL, 0x733f55f2UL, 0xce791814UL, 0x37bf73c7UL, + 0xcdea53f7UL, 0xaa5b5ffdUL, 0x6f14df3dUL, 0xdb867844UL, + 0xf381caafUL, 0xc43eb968UL, 0x342c3824UL, 0x405fc2a3UL, + 0xc372161dUL, 0x250cbce2UL, 0x498b283cUL, 0x9541ff0dUL, + 0x017139a8UL, 0xb3de080cUL, 0xe49cd8b4UL, 0xc1906456UL, + 0x84617bcbUL, 0xb670d532UL, 0x5c74486cUL, 0x5742d0b8UL, +}; +static const unsigned int Td3[256] = { + 0xf4a75051UL, 0x4165537eUL, 0x17a4c31aUL, 0x275e963aUL, + 0xab6bcb3bUL, 0x9d45f11fUL, 0xfa58abacUL, 0xe303934bUL, + 0x30fa5520UL, 0x766df6adUL, 0xcc769188UL, 0x024c25f5UL, + 0xe5d7fc4fUL, 0x2acbd7c5UL, 0x35448026UL, 0x62a38fb5UL, + 0xb15a49deUL, 0xba1b6725UL, 0xea0e9845UL, 0xfec0e15dUL, + 0x2f7502c3UL, 0x4cf01281UL, 0x4697a38dUL, 0xd3f9c66bUL, + 0x8f5fe703UL, 0x929c9515UL, 0x6d7aebbfUL, 0x5259da95UL, + 0xbe832dd4UL, 0x7421d358UL, 0xe0692949UL, 0xc9c8448eUL, + 0xc2896a75UL, 0x8e7978f4UL, 0x583e6b99UL, 0xb971dd27UL, + 0xe14fb6beUL, 0x88ad17f0UL, 0x20ac66c9UL, 0xce3ab47dUL, + 0xdf4a1863UL, 0x1a3182e5UL, 0x51336097UL, 0x537f4562UL, + 0x6477e0b1UL, 0x6bae84bbUL, 0x81a01cfeUL, 0x082b94f9UL, + 0x48685870UL, 0x45fd198fUL, 0xde6c8794UL, 0x7bf8b752UL, + 0x73d323abUL, 0x4b02e272UL, 0x1f8f57e3UL, 0x55ab2a66UL, + 0xeb2807b2UL, 0xb5c2032fUL, 0xc57b9a86UL, 0x3708a5d3UL, + 0x2887f230UL, 0xbfa5b223UL, 0x036aba02UL, 0x16825cedUL, + 0xcf1c2b8aUL, 0x79b492a7UL, 0x07f2f0f3UL, 0x69e2a14eUL, + 0xdaf4cd65UL, 0x05bed506UL, 0x34621fd1UL, 0xa6fe8ac4UL, + 0x2e539d34UL, 0xf355a0a2UL, 0x8ae13205UL, 0xf6eb75a4UL, + 0x83ec390bUL, 0x60efaa40UL, 0x719f065eUL, 0x6e1051bdUL, + 0x218af93eUL, 0xdd063d96UL, 0x3e05aeddUL, 0xe6bd464dUL, + 0x548db591UL, 0xc45d0571UL, 0x06d46f04UL, 0x5015ff60UL, + 0x98fb2419UL, 0xbde997d6UL, 0x4043cc89UL, 0xd99e7767UL, + 0xe842bdb0UL, 0x898b8807UL, 0x195b38e7UL, 0xc8eedb79UL, + 0x7c0a47a1UL, 0x420fe97cUL, 0x841ec9f8UL, 0x00000000UL, + 0x80868309UL, 0x2bed4832UL, 0x1170ac1eUL, 0x5a724e6cUL, + 0x0efffbfdUL, 0x8538560fUL, 0xaed51e3dUL, 0x2d392736UL, + 0x0fd9640aUL, 0x5ca62168UL, 0x5b54d19bUL, 0x362e3a24UL, + 0x0a67b10cUL, 0x57e70f93UL, 0xee96d2b4UL, 0x9b919e1bUL, + 0xc0c54f80UL, 0xdc20a261UL, 0x774b695aUL, 0x121a161cUL, + 0x93ba0ae2UL, 0xa02ae5c0UL, 0x22e0433cUL, 0x1b171d12UL, + 0x090d0b0eUL, 0x8bc7adf2UL, 0xb6a8b92dUL, 0x1ea9c814UL, + 0xf1198557UL, 0x75074cafUL, 0x99ddbbeeUL, 0x7f60fda3UL, + 0x01269ff7UL, 0x72f5bc5cUL, 0x663bc544UL, 0xfb7e345bUL, + 0x4329768bUL, 0x23c6dccbUL, 0xedfc68b6UL, 0xe4f163b8UL, + 0x31dccad7UL, 0x63851042UL, 0x97224013UL, 0xc6112084UL, + 0x4a247d85UL, 0xbb3df8d2UL, 0xf93211aeUL, 0x29a16dc7UL, + 0x9e2f4b1dUL, 0xb230f3dcUL, 0x8652ec0dUL, 0xc1e3d077UL, + 0xb3166c2bUL, 0x70b999a9UL, 0x9448fa11UL, 0xe9642247UL, + 0xfc8cc4a8UL, 0xf03f1aa0UL, 0x7d2cd856UL, 0x3390ef22UL, + 0x494ec787UL, 0x38d1c1d9UL, 0xcaa2fe8cUL, 0xd40b3698UL, + 0xf581cfa6UL, 0x7ade28a5UL, 0xb78e26daUL, 0xadbfa43fUL, + 0x3a9de42cUL, 0x78920d50UL, 0x5fcc9b6aUL, 0x7e466254UL, + 0x8d13c2f6UL, 0xd8b8e890UL, 0x39f75e2eUL, 0xc3aff582UL, + 0x5d80be9fUL, 0xd0937c69UL, 0xd52da96fUL, 0x2512b3cfUL, + 0xac993bc8UL, 0x187da710UL, 0x9c636ee8UL, 0x3bbb7bdbUL, + 0x267809cdUL, 0x5918f46eUL, 0x9ab701ecUL, 0x4f9aa883UL, + 0x956e65e6UL, 0xffe67eaaUL, 0xbccf0821UL, 0x15e8e6efUL, + 0xe79bd9baUL, 0x6f36ce4aUL, 0x9f09d4eaUL, 0xb07cd629UL, + 0xa4b2af31UL, 0x3f23312aUL, 0xa59430c6UL, 0xa266c035UL, + 0x4ebc3774UL, 0x82caa6fcUL, 0x90d0b0e0UL, 0xa7d81533UL, + 0x04984af1UL, 0xecdaf741UL, 0xcd500e7fUL, 0x91f62f17UL, + 0x4dd68d76UL, 0xefb04d43UL, 0xaa4d54ccUL, 0x9604dfe4UL, + 0xd1b5e39eUL, 0x6a881b4cUL, 0x2c1fb8c1UL, 0x65517f46UL, + 0x5eea049dUL, 0x8c355d01UL, 0x877473faUL, 0x0b412efbUL, + 0x671d5ab3UL, 0xdbd25292UL, 0x105633e9UL, 0xd647136dUL, + 0xd7618c9aUL, 0xa10c7a37UL, 0xf8148e59UL, 0x133c89ebUL, + 0xa927eeceUL, 0x61c935b7UL, 0x1ce5ede1UL, 0x47b13c7aUL, + 0xd2df599cUL, 0xf2733f55UL, 0x14ce7918UL, 0xc737bf73UL, + 0xf7cdea53UL, 0xfdaa5b5fUL, 0x3d6f14dfUL, 0x44db8678UL, + 0xaff381caUL, 0x68c43eb9UL, 0x24342c38UL, 0xa3405fc2UL, + 0x1dc37216UL, 0xe2250cbcUL, 0x3c498b28UL, 0x0d9541ffUL, + 0xa8017139UL, 0x0cb3de08UL, 0xb4e49cd8UL, 0x56c19064UL, + 0xcb84617bUL, 0x32b670d5UL, 0x6c5c7448UL, 0xb85742d0UL, +}; +static const unsigned int Td4[256] = { + 0x52525252UL, 0x09090909UL, 0x6a6a6a6aUL, 0xd5d5d5d5UL, + 0x30303030UL, 0x36363636UL, 0xa5a5a5a5UL, 0x38383838UL, + 0xbfbfbfbfUL, 0x40404040UL, 0xa3a3a3a3UL, 0x9e9e9e9eUL, + 0x81818181UL, 0xf3f3f3f3UL, 0xd7d7d7d7UL, 0xfbfbfbfbUL, + 0x7c7c7c7cUL, 0xe3e3e3e3UL, 0x39393939UL, 0x82828282UL, + 0x9b9b9b9bUL, 0x2f2f2f2fUL, 0xffffffffUL, 0x87878787UL, + 0x34343434UL, 0x8e8e8e8eUL, 0x43434343UL, 0x44444444UL, + 0xc4c4c4c4UL, 0xdedededeUL, 0xe9e9e9e9UL, 0xcbcbcbcbUL, + 0x54545454UL, 0x7b7b7b7bUL, 0x94949494UL, 0x32323232UL, + 0xa6a6a6a6UL, 0xc2c2c2c2UL, 0x23232323UL, 0x3d3d3d3dUL, + 0xeeeeeeeeUL, 0x4c4c4c4cUL, 0x95959595UL, 0x0b0b0b0bUL, + 0x42424242UL, 0xfafafafaUL, 0xc3c3c3c3UL, 0x4e4e4e4eUL, + 0x08080808UL, 0x2e2e2e2eUL, 0xa1a1a1a1UL, 0x66666666UL, + 0x28282828UL, 0xd9d9d9d9UL, 0x24242424UL, 0xb2b2b2b2UL, + 0x76767676UL, 0x5b5b5b5bUL, 0xa2a2a2a2UL, 0x49494949UL, + 0x6d6d6d6dUL, 0x8b8b8b8bUL, 0xd1d1d1d1UL, 0x25252525UL, + 0x72727272UL, 0xf8f8f8f8UL, 0xf6f6f6f6UL, 0x64646464UL, + 0x86868686UL, 0x68686868UL, 0x98989898UL, 0x16161616UL, + 0xd4d4d4d4UL, 0xa4a4a4a4UL, 0x5c5c5c5cUL, 0xccccccccUL, + 0x5d5d5d5dUL, 0x65656565UL, 0xb6b6b6b6UL, 0x92929292UL, + 0x6c6c6c6cUL, 0x70707070UL, 0x48484848UL, 0x50505050UL, + 0xfdfdfdfdUL, 0xededededUL, 0xb9b9b9b9UL, 0xdadadadaUL, + 0x5e5e5e5eUL, 0x15151515UL, 0x46464646UL, 0x57575757UL, + 0xa7a7a7a7UL, 0x8d8d8d8dUL, 0x9d9d9d9dUL, 0x84848484UL, + 0x90909090UL, 0xd8d8d8d8UL, 0xababababUL, 0x00000000UL, + 0x8c8c8c8cUL, 0xbcbcbcbcUL, 0xd3d3d3d3UL, 0x0a0a0a0aUL, + 0xf7f7f7f7UL, 0xe4e4e4e4UL, 0x58585858UL, 0x05050505UL, + 0xb8b8b8b8UL, 0xb3b3b3b3UL, 0x45454545UL, 0x06060606UL, + 0xd0d0d0d0UL, 0x2c2c2c2cUL, 0x1e1e1e1eUL, 0x8f8f8f8fUL, + 0xcacacacaUL, 0x3f3f3f3fUL, 0x0f0f0f0fUL, 0x02020202UL, + 0xc1c1c1c1UL, 0xafafafafUL, 0xbdbdbdbdUL, 0x03030303UL, + 0x01010101UL, 0x13131313UL, 0x8a8a8a8aUL, 0x6b6b6b6bUL, + 0x3a3a3a3aUL, 0x91919191UL, 0x11111111UL, 0x41414141UL, + 0x4f4f4f4fUL, 0x67676767UL, 0xdcdcdcdcUL, 0xeaeaeaeaUL, + 0x97979797UL, 0xf2f2f2f2UL, 0xcfcfcfcfUL, 0xcecececeUL, + 0xf0f0f0f0UL, 0xb4b4b4b4UL, 0xe6e6e6e6UL, 0x73737373UL, + 0x96969696UL, 0xacacacacUL, 0x74747474UL, 0x22222222UL, + 0xe7e7e7e7UL, 0xadadadadUL, 0x35353535UL, 0x85858585UL, + 0xe2e2e2e2UL, 0xf9f9f9f9UL, 0x37373737UL, 0xe8e8e8e8UL, + 0x1c1c1c1cUL, 0x75757575UL, 0xdfdfdfdfUL, 0x6e6e6e6eUL, + 0x47474747UL, 0xf1f1f1f1UL, 0x1a1a1a1aUL, 0x71717171UL, + 0x1d1d1d1dUL, 0x29292929UL, 0xc5c5c5c5UL, 0x89898989UL, + 0x6f6f6f6fUL, 0xb7b7b7b7UL, 0x62626262UL, 0x0e0e0e0eUL, + 0xaaaaaaaaUL, 0x18181818UL, 0xbebebebeUL, 0x1b1b1b1bUL, + 0xfcfcfcfcUL, 0x56565656UL, 0x3e3e3e3eUL, 0x4b4b4b4bUL, + 0xc6c6c6c6UL, 0xd2d2d2d2UL, 0x79797979UL, 0x20202020UL, + 0x9a9a9a9aUL, 0xdbdbdbdbUL, 0xc0c0c0c0UL, 0xfefefefeUL, + 0x78787878UL, 0xcdcdcdcdUL, 0x5a5a5a5aUL, 0xf4f4f4f4UL, + 0x1f1f1f1fUL, 0xddddddddUL, 0xa8a8a8a8UL, 0x33333333UL, + 0x88888888UL, 0x07070707UL, 0xc7c7c7c7UL, 0x31313131UL, + 0xb1b1b1b1UL, 0x12121212UL, 0x10101010UL, 0x59595959UL, + 0x27272727UL, 0x80808080UL, 0xececececUL, 0x5f5f5f5fUL, + 0x60606060UL, 0x51515151UL, 0x7f7f7f7fUL, 0xa9a9a9a9UL, + 0x19191919UL, 0xb5b5b5b5UL, 0x4a4a4a4aUL, 0x0d0d0d0dUL, + 0x2d2d2d2dUL, 0xe5e5e5e5UL, 0x7a7a7a7aUL, 0x9f9f9f9fUL, + 0x93939393UL, 0xc9c9c9c9UL, 0x9c9c9c9cUL, 0xefefefefUL, + 0xa0a0a0a0UL, 0xe0e0e0e0UL, 0x3b3b3b3bUL, 0x4d4d4d4dUL, + 0xaeaeaeaeUL, 0x2a2a2a2aUL, 0xf5f5f5f5UL, 0xb0b0b0b0UL, + 0xc8c8c8c8UL, 0xebebebebUL, 0xbbbbbbbbUL, 0x3c3c3c3cUL, + 0x83838383UL, 0x53535353UL, 0x99999999UL, 0x61616161UL, + 0x17171717UL, 0x2b2b2b2bUL, 0x04040404UL, 0x7e7e7e7eUL, + 0xbabababaUL, 0x77777777UL, 0xd6d6d6d6UL, 0x26262626UL, + 0xe1e1e1e1UL, 0x69696969UL, 0x14141414UL, 0x63636363UL, + 0x55555555UL, 0x21212121UL, 0x0c0c0c0cUL, 0x7d7d7d7dUL, +}; +static const unsigned int rcon[] = { + 0x01000000UL, 0x02000000UL, 0x04000000UL, 0x08000000UL, + 0x10000000UL, 0x20000000UL, 0x40000000UL, 0x80000000UL, + 0x1B000000UL, 0x36000000UL, +}; + +#define GETU32(pt) (((unsigned int)(pt)[0] << 24) ^ \ + ((unsigned int)(pt)[1] << 16) ^ \ + ((unsigned int)(pt)[2] << 8) ^ \ + ((unsigned int)(pt)[3])) + +#define PUTU32(ct, st) { (ct)[0] = (unsigned char)((st) >> 24); \ + (ct)[1] = (unsigned char)((st) >> 16); \ + (ct)[2] = (unsigned char)((st) >> 8); \ + (ct)[3] = (unsigned char)(st); } + +/* +* Expand the cipher key into the encryption key schedule and return the +* number of rounds for the given cipher key size. +*/ +int aes_setkey_enc(unsigned int rk[], const unsigned char cipherKey[], int keyBytes) +{ + int i = 0; + unsigned int temp; + + rk[0] = GETU32(cipherKey ); + rk[1] = GETU32(cipherKey + 4); + rk[2] = GETU32(cipherKey + 8); + rk[3] = GETU32(cipherKey + 12); + if (keyBytes == 16) { // 128 bits + for (;;) { + temp = rk[3]; + rk[4] = rk[0] ^ + (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te4[(temp ) & 0xff] & 0x0000ff00) ^ + (Te4[(temp >> 24) ] & 0x000000ff) ^ + rcon[i]; + rk[5] = rk[1] ^ rk[4]; + rk[6] = rk[2] ^ rk[5]; + rk[7] = rk[3] ^ rk[6]; + if (++i == 10) { + return 10; + } + rk += 4; + } + } + rk[4] = GETU32(cipherKey + 16); + rk[5] = GETU32(cipherKey + 20); + if (keyBytes == 24) { // 192 bits + for (;;) { + temp = rk[ 5]; + rk[ 6] = rk[ 0] ^ + (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te4[(temp ) & 0xff] & 0x0000ff00) ^ + (Te4[(temp >> 24) ] & 0x000000ff) ^ + rcon[i]; + rk[ 7] = rk[ 1] ^ rk[ 6]; + rk[ 8] = rk[ 2] ^ rk[ 7]; + rk[ 9] = rk[ 3] ^ rk[ 8]; + if (++i == 8) { + return 12; + } + rk[10] = rk[ 4] ^ rk[ 9]; + rk[11] = rk[ 5] ^ rk[10]; + rk += 6; + } + } + rk[6] = GETU32(cipherKey + 24); + rk[7] = GETU32(cipherKey + 28); + if (keyBytes == 32) { // 256 bits + for (;;) { + temp = rk[ 7]; + rk[ 8] = rk[ 0] ^ + (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te4[(temp ) & 0xff] & 0x0000ff00) ^ + (Te4[(temp >> 24) ] & 0x000000ff) ^ + rcon[i]; + rk[ 9] = rk[ 1] ^ rk[ 8]; + rk[10] = rk[ 2] ^ rk[ 9]; + rk[11] = rk[ 3] ^ rk[10]; + if (++i == 7) { + return 14; + } + temp = rk[11]; + rk[12] = rk[ 4] ^ + (Te4[(temp >> 24) ] & 0xff000000) ^ + (Te4[(temp >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(temp >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(temp ) & 0xff] & 0x000000ff); + rk[13] = rk[ 5] ^ rk[12]; + rk[14] = rk[ 6] ^ rk[13]; + rk[15] = rk[ 7] ^ rk[14]; + + rk += 8; + } + } + return 0; +} + +/* +* Expand the cipher key into encryption and decryption key schedule and +* return the number of rounds for the given cipher key size. +*/ +int AesGenKeySched(unsigned int rk[], unsigned int rrk[], const unsigned char cipherKey[], int keyBytes) +{ + int Nr, i; + + // expand the cipher key + Nr = aes_setkey_enc(rk, cipherKey, keyBytes); + // invert the order of the first round keys + rrk += Nr * 4; + rrk[0] = rk[0]; + rrk[1] = rk[1]; + rrk[2] = rk[2]; + rrk[3] = rk[3]; + + /* + * apply the inverse MixColumn transform to all round keys but the first + * and the last + */ + for (i = 1; i < Nr; i++) { + rrk -= 4; + rk += 4; + rrk[0] = + Td0[Te4[(rk[0] >> 24) ] & 0xff] ^ + Td1[Te4[(rk[0] >> 16) & 0xff] & 0xff] ^ + Td2[Te4[(rk[0] >> 8) & 0xff] & 0xff] ^ + Td3[Te4[(rk[0] ) & 0xff] & 0xff]; + rrk[1] = + Td0[Te4[(rk[1] >> 24) ] & 0xff] ^ + Td1[Te4[(rk[1] >> 16) & 0xff] & 0xff] ^ + Td2[Te4[(rk[1] >> 8) & 0xff] & 0xff] ^ + Td3[Te4[(rk[1] ) & 0xff] & 0xff]; + rrk[2] = + Td0[Te4[(rk[2] >> 24) ] & 0xff] ^ + Td1[Te4[(rk[2] >> 16) & 0xff] & 0xff] ^ + Td2[Te4[(rk[2] >> 8) & 0xff] & 0xff] ^ + Td3[Te4[(rk[2] ) & 0xff] & 0xff]; + rrk[3] = + Td0[Te4[(rk[3] >> 24) ] & 0xff] ^ + Td1[Te4[(rk[3] >> 16) & 0xff] & 0xff] ^ + Td2[Te4[(rk[3] >> 8) & 0xff] & 0xff] ^ + Td3[Te4[(rk[3] ) & 0xff] & 0xff]; + } + // invert the order of the last round keys + rrk -= 4; + rk += 4; + rrk[0] = rk[0]; + rrk[1] = rk[1]; + rrk[2] = rk[2]; + rrk[3] = rk[3]; + + return Nr; +} + +/* +* Encrypt the plain text into cipher +*/ +void AesEncBlk(AesCtx *pCtx, const unsigned char pt[], unsigned char ct[]) +{ + unsigned int s0, s1, s2, s3, t0, t1, t2, t3, *iv; + const unsigned int *rk; + int r; + + rk = pCtx->Ek; + iv = pCtx->Iv; + /* + * map byte array block to cipher state + * and add initial round key: + */ + s0 = GETU32(pt ) ^ rk[0]; + s1 = GETU32(pt + 4) ^ rk[1]; + s2 = GETU32(pt + 8) ^ rk[2]; + s3 = GETU32(pt + 12) ^ rk[3]; + if (pCtx->Mode) { + s0 = s0 ^ iv[0]; + s1 = s1 ^ iv[1]; + s2 = s2 ^ iv[2]; + s3 = s3 ^ iv[3]; + } + /* + * Nr - 1 full rounds: + */ + r = pCtx->Nr >> 1; + for (;;) { + t0 = + Te0[(s0 >> 24) ] ^ + Te1[(s1 >> 16) & 0xff] ^ + Te2[(s2 >> 8) & 0xff] ^ + Te3[(s3 ) & 0xff] ^ + rk[4]; + t1 = + Te0[(s1 >> 24) ] ^ + Te1[(s2 >> 16) & 0xff] ^ + Te2[(s3 >> 8) & 0xff] ^ + Te3[(s0 ) & 0xff] ^ + rk[5]; + t2 = + Te0[(s2 >> 24) ] ^ + Te1[(s3 >> 16) & 0xff] ^ + Te2[(s0 >> 8) & 0xff] ^ + Te3[(s1 ) & 0xff] ^ + rk[6]; + t3 = + Te0[(s3 >> 24) ] ^ + Te1[(s0 >> 16) & 0xff] ^ + Te2[(s1 >> 8) & 0xff] ^ + Te3[(s2 ) & 0xff] ^ + rk[7]; + + rk += 8; + if (--r == 0) { + break; + } + + s0 = + Te0[(t0 >> 24) ] ^ + Te1[(t1 >> 16) & 0xff] ^ + Te2[(t2 >> 8) & 0xff] ^ + Te3[(t3 ) & 0xff] ^ + rk[0]; + s1 = + Te0[(t1 >> 24) ] ^ + Te1[(t2 >> 16) & 0xff] ^ + Te2[(t3 >> 8) & 0xff] ^ + Te3[(t0 ) & 0xff] ^ + rk[1]; + s2 = + Te0[(t2 >> 24) ] ^ + Te1[(t3 >> 16) & 0xff] ^ + Te2[(t0 >> 8) & 0xff] ^ + Te3[(t1 ) & 0xff] ^ + rk[2]; + s3 = + Te0[(t3 >> 24) ] ^ + Te1[(t0 >> 16) & 0xff] ^ + Te2[(t1 >> 8) & 0xff] ^ + Te3[(t2 ) & 0xff] ^ + rk[3]; + } + /* + * apply last round and + * map cipher state to byte array block: + */ + s0 = + (Te4[(t0 >> 24) ] & 0xff000000) ^ + (Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(t2 >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(t3 ) & 0xff] & 0x000000ff) ^ + rk[0]; + PUTU32(ct , s0); + s1 = + (Te4[(t1 >> 24) ] & 0xff000000) ^ + (Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(t0 ) & 0xff] & 0x000000ff) ^ + rk[1]; + PUTU32(ct + 4, s1); + s2 = + (Te4[(t2 >> 24) ] & 0xff000000) ^ + (Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(t1 ) & 0xff] & 0x000000ff) ^ + rk[2]; + PUTU32(ct + 8, s2); + s3 = + (Te4[(t3 >> 24) ] & 0xff000000) ^ + (Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(t2 ) & 0xff] & 0x000000ff) ^ + rk[3]; + PUTU32(ct + 12, s3); + + if (pCtx->Mode) { + iv[0] = s0; + iv[1] = s1; + iv[2] = s2; + iv[3] = s3; + } +} + +/* +* Decrypt the cipher into plain text +*/ +void AesDecBlk(AesCtx *pCtx, const unsigned char ct[], unsigned char pt[]) +{ + unsigned int s0, s1, s2, s3, t0, t1, t2, t3, v0, v1, v2, v3, *iv; + const unsigned int *rk; + int r; + + rk = pCtx->Dk; + iv = pCtx->Iv; + /* + * map byte array block to cipher state + * and add initial round key: + */ + v0 = GETU32(ct ); s0 = v0 ^ rk[0]; + v1 = GETU32(ct + 4); s1 = v1 ^ rk[1]; + v2 = GETU32(ct + 8); s2 = v2 ^ rk[2]; + v3 = GETU32(ct + 12); s3 = v3 ^ rk[3]; + /* + * Nr - 1 full rounds: + */ + r = pCtx->Nr >> 1; + for (;;) { + t0 = + Td0[(s0 >> 24) ] ^ + Td1[(s3 >> 16) & 0xff] ^ + Td2[(s2 >> 8) & 0xff] ^ + Td3[(s1 ) & 0xff] ^ + rk[4]; + t1 = + Td0[(s1 >> 24) ] ^ + Td1[(s0 >> 16) & 0xff] ^ + Td2[(s3 >> 8) & 0xff] ^ + Td3[(s2 ) & 0xff] ^ + rk[5]; + t2 = + Td0[(s2 >> 24) ] ^ + Td1[(s1 >> 16) & 0xff] ^ + Td2[(s0 >> 8) & 0xff] ^ + Td3[(s3 ) & 0xff] ^ + rk[6]; + t3 = + Td0[(s3 >> 24) ] ^ + Td1[(s2 >> 16) & 0xff] ^ + Td2[(s1 >> 8) & 0xff] ^ + Td3[(s0 ) & 0xff] ^ + rk[7]; + + rk += 8; + if (--r == 0) { + break; + } + + s0 = + Td0[(t0 >> 24) ] ^ + Td1[(t3 >> 16) & 0xff] ^ + Td2[(t2 >> 8) & 0xff] ^ + Td3[(t1 ) & 0xff] ^ + rk[0]; + s1 = + Td0[(t1 >> 24) ] ^ + Td1[(t0 >> 16) & 0xff] ^ + Td2[(t3 >> 8) & 0xff] ^ + Td3[(t2 ) & 0xff] ^ + rk[1]; + s2 = + Td0[(t2 >> 24) ] ^ + Td1[(t1 >> 16) & 0xff] ^ + Td2[(t0 >> 8) & 0xff] ^ + Td3[(t3 ) & 0xff] ^ + rk[2]; + s3 = + Td0[(t3 >> 24) ] ^ + Td1[(t2 >> 16) & 0xff] ^ + Td2[(t1 >> 8) & 0xff] ^ + Td3[(t0 ) & 0xff] ^ + rk[3]; + } + /* + * apply last round and + * map cipher state to byte array block: + */ + s0 = + (Td4[(t0 >> 24) ] & 0xff000000) ^ + (Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t2 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t1 ) & 0xff] & 0x000000ff) ^ + rk[0]; + s1 = + (Td4[(t1 >> 24) ] & 0xff000000) ^ + (Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t2 ) & 0xff] & 0x000000ff) ^ + rk[1]; + s2 = + (Td4[(t2 >> 24) ] & 0xff000000) ^ + (Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t3 ) & 0xff] & 0x000000ff) ^ + rk[2]; + s3 = + (Td4[(t3 >> 24) ] & 0xff000000) ^ + (Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t0 ) & 0xff] & 0x000000ff) ^ + rk[3]; + + if (pCtx->Mode) { + s0 = s0 ^ iv[0]; iv[0] = v0; + s1 = s1 ^ iv[1]; iv[1] = v1; + s2 = s2 ^ iv[2]; iv[2] = v2; + s3 = s3 ^ iv[3]; iv[3] = v3; + } + + PUTU32(pt , s0); + PUTU32(pt + 4, s1); + PUTU32(pt + 8, s2); + PUTU32(pt + 12, s3); +} + +////////////////////////////////////////////////////////////////////////////// +// API functions // +////////////////////////////////////////////////////////////////////////////// + +/* +* initialize AES context +*/ +int AesCtxIni(AesCtx *pCtx, unsigned char *pIV, unsigned char *pKey, unsigned int KeyLen, unsigned char Mode) +{ + if (pKey == 0 || pCtx == 0 || (KeyLen != KEY128 && KeyLen != KEY192 && KeyLen != KEY256)) + return -1; + + // generate key schedule + pCtx->Nr = AesGenKeySched(pCtx->Ek, pCtx->Dk, pKey, KeyLen); + + // initialize IV + if (pIV != 0) { + pCtx->Iv[0] = GETU32(pIV ); + pCtx->Iv[1] = GETU32(pIV + 4 ); + pCtx->Iv[2] = GETU32(pIV + 8 ); + pCtx->Iv[3] = GETU32(pIV + 12); + } + + // mode + pCtx->Mode = Mode; + + return 0; +} + +/* +* Encrypt plain text +*/ +int AesEncrypt(AesCtx *pCtx, unsigned char *pData, unsigned char *pCipher, unsigned int DataLen) +{ + int i; + + if (pData == 0 || pCipher == 0 || pCtx == 0 || (DataLen & 0xf) != 0) + return -1; + + for (i = 0; i < DataLen; i += BLOCKSZ) { + // encrypt block by block + AesEncBlk(pCtx, pData, pCipher); + pCipher += BLOCKSZ; + pData += BLOCKSZ; + } + return DataLen; +} + +/* +* Decrypt cipher +*/ +int AesDecrypt(AesCtx *pCtx, unsigned char *pCipher, unsigned char *pData, unsigned int CipherLen) +{ + int i; + + if (pData == 0 || pCipher == 0 || pCtx == 0 || (CipherLen & 0xf) != 0) + return -1; + + for (i = 0; i < CipherLen; i += BLOCKSZ) { + // decrypt block by block + AesDecBlk(pCtx, pCipher, pData); + pCipher += BLOCKSZ; + pData += BLOCKSZ; + } + return CipherLen; +} + +////////////////////////////////////////////////////////////////////////////// +// Sample main program // +////////////////////////////////////////////////////////////////////////////// + +#ifndef EMBEDDED +int main() +{ + AesCtx ctx; + unsigned char iv[] = "INI VECTINI VECT"; + unsigned char key[] = "This is a sample AESKey"; + unsigned char databuf[] = "Data : AES Test"; // must be in multiple of 16 + + // initialize context and encrypt data at one end + + if( AesCtxIni(&ctx, iv, key, KEY128, CBC) < 0) + printf("init error\n"); + + if (AesEncrypt(&ctx, databuf, databuf, sizeof databuf) < 0) + printf("error in encryption\n"); + + // initialize context and decrypt cipher at other end + + if( AesCtxIni(&ctx, iv, key, KEY128, CBC) < 0) + printf("init error\n"); + + if (AesDecrypt(&ctx, databuf, databuf, sizeof databuf) < 0) + printf("error in decryption\n"); + + printf("%s\n", databuf); + + return 0; +} +#endif \ No newline at end of file diff --git a/armsrc/aes.h b/armsrc/aes.h new file mode 100644 index 00000000..85944873 --- /dev/null +++ b/armsrc/aes.h @@ -0,0 +1,30 @@ +/* +* AES Cryptographic Algorithm Header File. Include this header file in +* your source which uses these given APIs. (This source is kept under +* public domain) +*/ + +// AES context structure +typedef struct { + unsigned int Ek[60]; + unsigned int Dk[60]; + unsigned int Iv[4]; + unsigned char Nr; + unsigned char Mode; +} AesCtx; + +// key length in bytes +#define KEY128 16 +#define KEY192 24 +#define KEY256 32 +// block size in bytes +#define BLOCKSZ 16 +// mode +#define EBC 0 +#define CBC 1 + +// AES API function prototype + +int AesCtxIni(AesCtx *pCtx, unsigned char *pIV, unsigned char *pKey, unsigned int KeyLen, unsigned char Mode); +int AesEncrypt(AesCtx *pCtx, unsigned char *pData, unsigned char *pCipher, unsigned int DataLen); +int AesDecrypt(AesCtx *pCtx, unsigned char *pCipher, unsigned char *pData, unsigned int CipherLen); \ No newline at end of file diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 2061f6b3..6f8b0150 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -10,10 +10,10 @@ // executes. //----------------------------------------------------------------------------- -#include "usb_cdc.h" -#include "cmd.h" +#include "../common/usb_cdc.h" +#include "../common/cmd.h" -#include "proxmark3.h" +#include "../include/proxmark3.h" #include "apps.h" #include "util.h" #include "printf.h" @@ -22,7 +22,7 @@ #include #include "legicrf.h" -#include +#include "../include/hitag2.h" #ifdef WITH_LCD #include "LCD.h" @@ -81,40 +81,12 @@ void DbpString(char *str) { byte_t len = strlen(str); cmd_send(CMD_DEBUG_PRINT_STRING,len,0,0,(byte_t*)str,len); -// /* this holds up stuff unless we're connected to usb */ -// if (!UsbConnected()) -// return; -// -// UsbCommand c; -// c.cmd = CMD_DEBUG_PRINT_STRING; -// c.arg[0] = strlen(str); -// if(c.arg[0] > sizeof(c.d.asBytes)) { -// c.arg[0] = sizeof(c.d.asBytes); -// } -// memcpy(c.d.asBytes, str, c.arg[0]); -// -// UsbSendPacket((uint8_t *)&c, sizeof(c)); -// // TODO fix USB so stupid things like this aren't req'd -// SpinDelay(50); } #if 0 void DbpIntegers(int x1, int x2, int x3) { cmd_send(CMD_DEBUG_PRINT_INTEGERS,x1,x2,x3,0,0); -// /* this holds up stuff unless we're connected to usb */ -// if (!UsbConnected()) -// return; -// -// UsbCommand c; -// c.cmd = CMD_DEBUG_PRINT_INTEGERS; -// c.arg[0] = x1; -// c.arg[1] = x2; -// c.arg[2] = x3; -// -// UsbSendPacket((uint8_t *)&c, sizeof(c)); -// // XXX -// SpinDelay(50); } #endif @@ -199,8 +171,6 @@ void MeasureAntennaTuning(void) int i, adcval = 0, peak = 0, peakv = 0, peakf = 0; //ptr = 0 int vLf125 = 0, vLf134 = 0, vHf = 0; // in mV -// UsbCommand c; - LED_B_ON(); DbpString("Measuring antenna characteristics, please wait..."); memset(dest,0,sizeof(FREE_BUFFER_SIZE)); @@ -692,7 +662,6 @@ void UsbPacketReceived(uint8_t *packet, int len) case CMD_PCF7931_READ: // Read PCF7931 tag ReadPCF7931(); cmd_send(CMD_ACK,0,0,0,0,0); -// UsbSendPacket((uint8_t*)&ack, sizeof(ack)); break; case CMD_EM4X_READ_WORD: EM4xReadWord(c->arg[1], c->arg[2],c->d.asBytes[0]); @@ -800,8 +769,17 @@ void UsbPacketReceived(uint8_t *packet, int len) case CMD_MIFAREU_READBL: MifareUReadBlock(c->arg[0],c->d.asBytes); break; + case CMD_MIFAREUC_AUTH1: + MifareUC_Auth1(c->arg[0],c->d.asBytes); + break; + case CMD_MIFAREUC_AUTH2: + MifareUC_Auth2(c->arg[0],c->d.asBytes); + break; case CMD_MIFAREU_READCARD: - MifareUReadCard(c->arg[0],c->d.asBytes); + MifareUReadCard(c->arg[0],c->arg[1],c->d.asBytes); + break; + case CMD_MIFAREUC_READCARD: + MifareUReadCard(c->arg[0],c->arg[1],c->d.asBytes); break; case CMD_MIFARE_READSC: MifareReadSector(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); @@ -854,6 +832,24 @@ void UsbPacketReceived(uint8_t *packet, int len) case CMD_MIFARE_SNIFFER: SniffMifare(c->arg[0]); break; + + // mifare desfire + case CMD_MIFARE_DESFIRE_READBL: + break; + case CMD_MIFARE_DESFIRE_WRITEBL: + break; + case CMD_MIFARE_DESFIRE_AUTH1: + MifareDES_Auth1(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); + break; + case CMD_MIFARE_DESFIRE_AUTH2: + MifareDES_Auth2(c->arg[0],c->d.asBytes); + break; + // case CMD_MIFARE_DES_READER: + // ReaderMifareDES(c->arg[0], c->arg[1], c->d.asBytes); + break; + case CMD_MIFARE_DESFIRE_INFO: + MifareDesfireGetInformation(); + break; #endif #ifdef WITH_ICLASS @@ -867,6 +863,9 @@ void UsbPacketReceived(uint8_t *packet, int len) case CMD_READER_ICLASS: ReaderIClass(c->arg[0]); break; + case CMD_READER_ICLASS_REPLAY: + ReaderIClass_Replay(c->arg[0], c->d.asBytes); + break; #endif case CMD_SIMULATE_TAG_HF_LISTEN: @@ -896,18 +895,6 @@ void UsbPacketReceived(uint8_t *packet, int len) break; case CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K: -// UsbCommand n; -// if(c->cmd == CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K) { -// n.cmd = CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K; -// } else { -// n.cmd = CMD_DOWNLOADED_RAW_BITS_TI_TYPE; -// } -// n.arg[0] = c->arg[0]; - // memcpy(n.d.asBytes, BigBuf+c->arg[0], 48); // 12*sizeof(uint32_t) - // LED_B_ON(); - // usb_write((uint8_t *)&n, sizeof(n)); - // UsbSendPacket((uint8_t *)&n, sizeof(n)); - // LED_B_OFF(); LED_B_ON(); for(size_t i=0; iarg[1]; i += USB_CMD_DATA_SIZE) { @@ -923,7 +910,6 @@ void UsbPacketReceived(uint8_t *packet, int len) uint8_t *b = (uint8_t *)BigBuf; memcpy(b+c->arg[0], c->d.asBytes, 48); //Dbprintf("copied 48 bytes to %i",b+c->arg[0]); -// UsbSendPacket((uint8_t*)&ack, sizeof(ack)); cmd_send(CMD_ACK,0,0,0,0,0); break; } @@ -981,7 +967,6 @@ void UsbPacketReceived(uint8_t *packet, int len) case CMD_DEVICE_INFO: { uint32_t dev_info = DEVICE_INFO_FLAG_OSIMAGE_PRESENT | DEVICE_INFO_FLAG_CURRENT_MODE_OS; if(common_area.flags.bootrom_present) dev_info |= DEVICE_INFO_FLAG_BOOTROM_PRESENT; -// UsbSendPacket((uint8_t*)&c, sizeof(c)); cmd_send(CMD_DEVICE_INFO,dev_info,0,0,0,0); break; } @@ -1010,7 +995,6 @@ void __attribute__((noreturn)) AppMain(void) // Init USB device` usb_enable(); -// UsbStart(); // The FPGA gets its clock from us from PCK0 output, so set that up. AT91C_BASE_PIOA->PIO_BSR = GPIO_PCK0; @@ -1046,8 +1030,6 @@ void __attribute__((noreturn)) AppMain(void) UsbPacketReceived(rx,rx_len); } } -// UsbPoll(FALSE); - WDT_HIT(); #ifdef WITH_LF diff --git a/armsrc/apps.h b/armsrc/apps.h index 1ef0e472..7c389e7c 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -14,9 +14,27 @@ #include #include -#include "common.h" -#include "hitag2.h" -#include "mifare.h" +#include + +#include +#include +#include + + +#include "../include/common.h" +#include "../include/hitag2.h" +#include "../include/mifare.h" + +//#include +//#include + +//#include "des.h" +//#include "aes.h" +#include "../common/desfire.h" +#include "../common/crc32.h" +//#include "desfire_crypto.h" +//#include "desfire_key.h" + // The large multi-purpose buffer, typically used to hold A/D samples, // maybe processed in some way. @@ -172,7 +190,9 @@ void ReaderMifare(bool first_try); int32_t dist_nt(uint32_t nt1, uint32_t nt2); void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *data); void MifareUReadBlock(uint8_t arg0,uint8_t *datain); -void MifareUReadCard(uint8_t arg0,uint8_t *datain); +void MifareUC_Auth1(uint8_t arg0, uint8_t *datain); +void MifareUC_Auth2(uint32_t arg0, uint8_t *datain); +void MifareUReadCard(uint8_t arg0,int Pages,uint8_t *datain); void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain); void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain); void MifareUWriteBlock(uint8_t arg0,uint8_t *datain); @@ -188,6 +208,47 @@ void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); // Work with "magic Chinese" card void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); +// mifaredesfire.h +void MifareDesfireGetInformation(); +void MifareDES_Auth1(uint8_t arg0,uint8_t arg1,uint8_t arg2, uint8_t *datain); +void MifareDES_Auth2(uint32_t arg0, uint8_t *datain); +int mifare_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData); +void ReaderMifareDES(uint32_t param, uint32_t param2, uint8_t * datain); +int SendDesfireCommand(enum DESFIRE_CMD desfire_cmd, uint8_t *dataout, uint8_t fromscratch); +uint8_t* CreateAPDU( uint8_t *datain, size_t len); +void OnSuccess(); +void OnError(); + +// desfire_key.h +desfirekey_t Desfire_des_key_new (const uint8_t value[8]); +desfirekey_t Desfire_3des_key_new (const uint8_t value[16]); +desfirekey_t Desfire_des_key_new_with_version (const uint8_t value[8]); +desfirekey_t Desfire_3des_key_new_with_version (const uint8_t value[16]); +desfirekey_t Desfire_3k3des_key_new (const uint8_t value[24]); +desfirekey_t Desfire_3k3des_key_new_with_version (const uint8_t value[24]); +desfirekey_t Desfire_aes_key_new (const uint8_t value[16]); +desfirekey_t Desfire_aes_key_new_with_version (const uint8_t value[16], uint8_t version); +uint8_t Desfire_key_get_version (desfirekey_t key); +void Desfire_key_set_version (desfirekey_t key, uint8_t version); +desfirekey_t Desfire_session_key_new (const uint8_t rnda[], const uint8_t rndb[], desfirekey_t authkey); + +// desfire_crypto.h +void *mifare_cryto_preprocess_data (desfiretag_t tag, void *data, size_t *nbytes, off_t offset, int communication_settings); +void *mifare_cryto_postprocess_data (desfiretag_t tag, void *data, ssize_t *nbytes, int communication_settings); +void mifare_cypher_single_block (desfirekey_t key, uint8_t *data, uint8_t *ivect, MifareCryptoDirection direction, MifareCryptoOperation operation, size_t block_size); +void mifare_cypher_blocks_chained (desfiretag_t tag, desfirekey_t key, uint8_t *ivect, uint8_t *data, size_t data_size, MifareCryptoDirection direction, MifareCryptoOperation operation); +size_t key_block_size (const desfirekey_t key); +size_t padded_data_length (const size_t nbytes, const size_t block_size); +size_t maced_data_length (const desfirekey_t key, const size_t nbytes); +size_t enciphered_data_length (const desfiretag_t tag, const size_t nbytes, int communication_settings); +void cmac_generate_subkeys (desfirekey_t key); +void cmac (const desfirekey_t key, uint8_t *ivect, const uint8_t *data, size_t len, uint8_t *cmac); + + + + + + /// iso15693.h void RecordRawAdcSamplesIso15693(void); void AcquireRawAdcSamplesIso15693(void); @@ -201,7 +262,9 @@ void SetDebugIso15693(uint32_t flag); void RAMFUNC SnoopIClass(void); void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); void ReaderIClass(uint8_t arg0); -//int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived); +void ReaderIClass_Replay(uint8_t arg0,uint8_t *MAC); +void IClass_iso14443A_GetPublic(uint8_t arg0); + // hitag2.h void SnoopHitag(uint32_t type); void SimulateHitagTag(bool tag_mem_supplied, byte_t* data); diff --git a/armsrc/des.c b/armsrc/des.c new file mode 100644 index 00000000..0a27503e --- /dev/null +++ b/armsrc/des.c @@ -0,0 +1,383 @@ +/* des.c */ +/* + This file is part of the ARM-Crypto-Lib. + Copyright (C) 2006-2010 Daniel Otte (daniel.otte@rub.de) + + 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 3 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, see . +*/ +/** + * \file des.c + * \author Daniel Otte + * \email daniel.otte@rub.de + * \date 2007-06-16 + * \brief DES and EDE-DES implementation + * \license GPLv3 or later + * + */ +#include +#include + +const uint8_t sbox[256] = { + /* S-box 1 */ + 0xE4, 0xD1, 0x2F, 0xB8, 0x3A, 0x6C, 0x59, 0x07, + 0x0F, 0x74, 0xE2, 0xD1, 0xA6, 0xCB, 0x95, 0x38, + 0x41, 0xE8, 0xD6, 0x2B, 0xFC, 0x97, 0x3A, 0x50, + 0xFC, 0x82, 0x49, 0x17, 0x5B, 0x3E, 0xA0, 0x6D, + /* S-box 2 */ + 0xF1, 0x8E, 0x6B, 0x34, 0x97, 0x2D, 0xC0, 0x5A, + 0x3D, 0x47, 0xF2, 0x8E, 0xC0, 0x1A, 0x69, 0xB5, + 0x0E, 0x7B, 0xA4, 0xD1, 0x58, 0xC6, 0x93, 0x2F, + 0xD8, 0xA1, 0x3F, 0x42, 0xB6, 0x7C, 0x05, 0xE9, + /* S-box 3 */ + 0xA0, 0x9E, 0x63, 0xF5, 0x1D, 0xC7, 0xB4, 0x28, + 0xD7, 0x09, 0x34, 0x6A, 0x28, 0x5E, 0xCB, 0xF1, + 0xD6, 0x49, 0x8F, 0x30, 0xB1, 0x2C, 0x5A, 0xE7, + 0x1A, 0xD0, 0x69, 0x87, 0x4F, 0xE3, 0xB5, 0x2C, + /* S-box 4 */ + 0x7D, 0xE3, 0x06, 0x9A, 0x12, 0x85, 0xBC, 0x4F, + 0xD8, 0xB5, 0x6F, 0x03, 0x47, 0x2C, 0x1A, 0xE9, + 0xA6, 0x90, 0xCB, 0x7D, 0xF1, 0x3E, 0x52, 0x84, + 0x3F, 0x06, 0xA1, 0xD8, 0x94, 0x5B, 0xC7, 0x2E, + /* S-box 5 */ + 0x2C, 0x41, 0x7A, 0xB6, 0x85, 0x3F, 0xD0, 0xE9, + 0xEB, 0x2C, 0x47, 0xD1, 0x50, 0xFA, 0x39, 0x86, + 0x42, 0x1B, 0xAD, 0x78, 0xF9, 0xC5, 0x63, 0x0E, + 0xB8, 0xC7, 0x1E, 0x2D, 0x6F, 0x09, 0xA4, 0x53, + /* S-box 6 */ + 0xC1, 0xAF, 0x92, 0x68, 0x0D, 0x34, 0xE7, 0x5B, + 0xAF, 0x42, 0x7C, 0x95, 0x61, 0xDE, 0x0B, 0x38, + 0x9E, 0xF5, 0x28, 0xC3, 0x70, 0x4A, 0x1D, 0xB6, + 0x43, 0x2C, 0x95, 0xFA, 0xBE, 0x17, 0x60, 0x8D, + /* S-box 7 */ + 0x4B, 0x2E, 0xF0, 0x8D, 0x3C, 0x97, 0x5A, 0x61, + 0xD0, 0xB7, 0x49, 0x1A, 0xE3, 0x5C, 0x2F, 0x86, + 0x14, 0xBD, 0xC3, 0x7E, 0xAF, 0x68, 0x05, 0x92, + 0x6B, 0xD8, 0x14, 0xA7, 0x95, 0x0F, 0xE2, 0x3C, + /* S-box 8 */ + 0xD2, 0x84, 0x6F, 0xB1, 0xA9, 0x3E, 0x50, 0xC7, + 0x1F, 0xD8, 0xA3, 0x74, 0xC5, 0x6B, 0x0E, 0x92, + 0x7B, 0x41, 0x9C, 0xE2, 0x06, 0xAD, 0xF3, 0x58, + 0x21, 0xE7, 0x4A, 0x8D, 0xFC, 0x90, 0x35, 0x6B +}; + +const uint8_t e_permtab[] ={ + 4, 6, /* 4 bytes in 6 bytes out*/ + 32, 1, 2, 3, 4, 5, + 4, 5, 6, 7, 8, 9, + 8, 9, 10, 11, 12, 13, + 12, 13, 14, 15, 16, 17, + 16, 17, 18, 19, 20, 21, + 20, 21, 22, 23, 24, 25, + 24, 25, 26, 27, 28, 29, + 28, 29, 30, 31, 32, 1 +}; + +const uint8_t p_permtab[] ={ + 4, 4, /* 32 bit -> 32 bit */ + 16, 7, 20, 21, + 29, 12, 28, 17, + 1, 15, 23, 26, + 5, 18, 31, 10, + 2, 8, 24, 14, + 32, 27, 3, 9, + 19, 13, 30, 6, + 22, 11, 4, 25 +}; + +const uint8_t ip_permtab[] ={ + 8, 8, /* 64 bit -> 64 bit */ + 58, 50, 42, 34, 26, 18, 10, 2, + 60, 52, 44, 36, 28, 20, 12, 4, + 62, 54, 46, 38, 30, 22, 14, 6, + 64, 56, 48, 40, 32, 24, 16, 8, + 57, 49, 41, 33, 25, 17, 9, 1, + 59, 51, 43, 35, 27, 19, 11, 3, + 61, 53, 45, 37, 29, 21, 13, 5, + 63, 55, 47, 39, 31, 23, 15, 7 +}; + +const uint8_t inv_ip_permtab[] ={ + 8, 8, /* 64 bit -> 64 bit */ + 40, 8, 48, 16, 56, 24, 64, 32, + 39, 7, 47, 15, 55, 23, 63, 31, + 38, 6, 46, 14, 54, 22, 62, 30, + 37, 5, 45, 13, 53, 21, 61, 29, + 36, 4, 44, 12, 52, 20, 60, 28, + 35, 3, 43, 11, 51, 19, 59, 27, + 34, 2, 42, 10, 50, 18, 58, 26, + 33, 1, 41, 9, 49, 17, 57, 25 +}; + +const uint8_t pc1_permtab[] ={ + 8, 7, /* 64 bit -> 56 bit*/ + 57, 49, 41, 33, 25, 17, 9, + 1, 58, 50, 42, 34, 26, 18, + 10, 2, 59, 51, 43, 35, 27, + 19, 11, 3, 60, 52, 44, 36, + 63, 55, 47, 39, 31, 23, 15, + 7, 62, 54, 46, 38, 30, 22, + 14, 6, 61, 53, 45, 37, 29, + 21, 13, 5, 28, 20, 12, 4 +}; + +const uint8_t pc2_permtab[] ={ + 7, 6, /* 56 bit -> 48 bit */ + 14, 17, 11, 24, 1, 5, + 3, 28, 15, 6, 21, 10, + 23, 19, 12, 4, 26, 8, + 16, 7, 27, 20, 13, 2, + 41, 52, 31, 37, 47, 55, + 30, 40, 51, 45, 33, 48, + 44, 49, 39, 56, 34, 53, + 46, 42, 50, 36, 29, 32 +}; + +const uint8_t splitin6bitword_permtab[] = { + 8, 8, /* 64 bit -> 64 bit */ + 64, 64, 1, 6, 2, 3, 4, 5, + 64, 64, 7, 12, 8, 9, 10, 11, + 64, 64, 13, 18, 14, 15, 16, 17, + 64, 64, 19, 24, 20, 21, 22, 23, + 64, 64, 25, 30, 26, 27, 28, 29, + 64, 64, 31, 36, 32, 33, 34, 35, + 64, 64, 37, 42, 38, 39, 40, 41, + 64, 64, 43, 48, 44, 45, 46, 47 +}; + +const uint8_t shiftkey_permtab[] = { + 7, 7, /* 56 bit -> 56 bit */ + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 1, + 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 29 +}; + +const uint8_t shiftkeyinv_permtab[] = { + 7, 7, + 28, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, + 56, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55 +}; + +/* +1 0 +1 0 +2 1 +2 1 +2 1 +2 1 +2 1 +2 1 +---- +1 0 +2 1 +2 1 +2 1 +2 1 +2 1 +2 1 +1 0 +*/ +#define ROTTABLE 0x7EFC +#define ROTTABLE_INV 0x3F7E +/******************************************************************************/ + +void permute(const uint8_t *ptable, const uint8_t *in, uint8_t *out){ + uint8_t ob; /* in-bytes and out-bytes */ + uint8_t byte, bit; /* counter for bit and byte */ + ob = ptable[1]; + ptable = &(ptable[2]); + for(byte=0; byte>(x%8)) ){ + t|=0x01; + } + } + out[byte]=t; + } +} + +/******************************************************************************/ + +void changeendian32(uint32_t * a){ + *a = (*a & 0x000000FF) << 24 | + (*a & 0x0000FF00) << 8 | + (*a & 0x00FF0000) >> 8 | + (*a & 0xFF000000) >> 24; +} + +/******************************************************************************/ +static inline +void shiftkey(uint8_t *key){ + uint8_t k[7]; + memcpy(k, key, 7); + permute((uint8_t*)shiftkey_permtab, k, key); +} + +/******************************************************************************/ +static inline +void shiftkey_inv(uint8_t *key){ + uint8_t k[7]; + memcpy(k, key, 7); + permute((uint8_t*)shiftkeyinv_permtab, k, key); + +} + +/******************************************************************************/ +static inline +uint64_t splitin6bitwords(uint64_t a){ + uint64_t ret=0; + a &= 0x0000ffffffffffffLL; + permute((uint8_t*)splitin6bitword_permtab, (uint8_t*)&a, (uint8_t*)&ret); + return ret; +} + +/******************************************************************************/ + +static inline +uint8_t substitute(uint8_t a, uint8_t * sbp){ + uint8_t x; + x = sbp[a>>1]; + x = (a&1)?x&0x0F:x>>4; + return x; + +} + +/******************************************************************************/ + +uint32_t des_f(uint32_t r, uint8_t* kr){ + uint8_t i; + uint32_t t=0,ret; + uint64_t data; + uint8_t *sbp; /* sboxpointer */ + permute((uint8_t*)e_permtab, (uint8_t*)&r, (uint8_t*)&data); + for(i=0; i<7; ++i) + ((uint8_t*)&data)[i] ^= kr[i]; + + /* Sbox substitution */ + data = splitin6bitwords(data); + sbp=(uint8_t*)sbox; + for(i=0; i<8; ++i){ + uint8_t x; + x = substitute(((uint8_t*)&data)[i], sbp); + t<<=4; + t |= x; + sbp += 32; + } + changeendian32(&t); + + permute((uint8_t*)p_permtab,(uint8_t*)&t, (uint8_t*)&ret); + + return ret; +} + +/******************************************************************************/ + +void des_enc(void* out, const void* in, const void* key){ +#define R *((uint32_t*)&(data[4])) +#define L *((uint32_t*)&(data[0])) + + uint8_t data[8],kr[6],k[7]; + uint8_t i; + + permute((uint8_t*)ip_permtab, (uint8_t*)in, data); + permute((uint8_t*)pc1_permtab, (const uint8_t*)key, k); + for(i=0; i<8; ++i){ + shiftkey(k); + if(ROTTABLE&((1<<((i<<1)+0))) ) + shiftkey(k); + permute((uint8_t*)pc2_permtab, k, kr); + L ^= des_f(R, kr); + + shiftkey(k); + if(ROTTABLE&((1<<((i<<1)+1))) ) + shiftkey(k); + permute((uint8_t*)pc2_permtab, k, kr); + R ^= des_f(L, kr); + + } + /* L <-> R*/ + R ^= L; + L ^= R; + R ^= L; + + permute((uint8_t*)inv_ip_permtab, data, (uint8_t*)out); +} + +/******************************************************************************/ + +void des_dec(void* out, const void* in, const uint8_t* key){ +#define R *((uint32_t*)&(data[4])) +#define L *((uint32_t*)&(data[0])) + + uint8_t data[8],kr[6],k[7]; + int8_t i; + permute((uint8_t*)ip_permtab, (uint8_t*)in, data); + permute((uint8_t*)pc1_permtab, (const uint8_t*)key, k); + for(i=7; i>=0; --i){ + + permute((uint8_t*)pc2_permtab, k, kr); + L ^= des_f(R, kr); + shiftkey_inv(k); + if(ROTTABLE&((1<<((i<<1)+1))) ){ + shiftkey_inv(k); + } + + permute((uint8_t*)pc2_permtab, k, kr); + R ^= des_f(L, kr); + shiftkey_inv(k); + if(ROTTABLE&((1<<((i<<1)+0))) ){ + shiftkey_inv(k); + } + + } + /* L <-> R*/ + R ^= L; + L ^= R; + R ^= L; + + permute((uint8_t*)inv_ip_permtab, data, (uint8_t*)out); +} + +/******************************************************************************/ + +void tdes_enc(void* out, void* in, const void* key){ + des_enc(out, in, (uint8_t*)key + 0); + des_dec(out, out, (uint8_t*)key + 8); + des_enc(out, out, (uint8_t*)key +16); +} + +/******************************************************************************/ + +void tdes_dec(void* out, void* in, const uint8_t* key){ + des_dec(out, in, (uint8_t*)key +16); + des_enc(out, out, (uint8_t*)key + 8); + des_dec(out, out, (uint8_t*)key + 0); +} + +/******************************************************************************/ + + diff --git a/armsrc/des.h b/armsrc/des.h new file mode 100644 index 00000000..652886fd --- /dev/null +++ b/armsrc/des.h @@ -0,0 +1,107 @@ +/* des.h */ +/* + This file is part of the ARM-Crypto-Lib. + Copyright (C) 2008 Daniel Otte (daniel.otte@rub.de) + + 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 3 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, see . +*/ +/** + * \file des.h + * \author Daniel Otte + * \date 2007-06-16 + * \brief des and tdes declarations + * \license GPLv3 or later + * + */ +#ifndef DES_H_ +#define DES_H_ + +/* the FIPS 46-3 (1999-10-25) name for triple DES is triple data encryption algorithm so TDEA. + * Also we only implement the three key mode */ + +/** \def tdea_enc + * \brief defining an alias for void tdes_enc(void* out, const void* in, const void* key) + */ + +/** \def tdea_dec + * \brief defining an alias for void tdes_dec(void* out, const void* in, const void* key) + */ + +#define tdea_enc tdes_enc +#define tdea_dec tdes_dec + +/** \fn void des_enc(void* out, const void* in, const void* key) + * \brief encrypt a block with DES + * + * This function encrypts a block of 64 bits (8 bytes) with the DES algorithm. + * Key expansion is done automatically. The key is 64 bits long, but note that + * only 56 bits are used (the LSB of each byte is dropped). The input and output + * blocks may overlap. + * + * \param out pointer to the block (64 bit = 8 byte) where the ciphertext is written to + * \param in pointer to the block (64 bit = 8 byte) where the plaintext is read from + * \param key pointer to the key (64 bit = 8 byte) + */ +void des_enc(void* out, const void* in, const void* key); + +/** \fn void des_dec(void* out, const void* in, const void* key) + * \brief decrypt a block with DES + * + * This function decrypts a block of 64 bits (8 bytes) with the DES algorithm. + * Key expansion is done automatically. The key is 64 bits long, but note that + * only 56 bits are used (the LSB of each byte is dropped). The input and output + * blocks may overlap. + * + * \param out pointer to the block (64 bit = 8 byte) where the plaintext is written to + * \param in pointer to the block (64 bit = 8 byte) where the ciphertext is read from + * \param key pointer to the key (64 bit = 8 byte) + */ +void des_dec(void* out, const void* in, const void* key); + +/** \fn void tdes_enc(void* out, const void* in, const void* key) + * \brief encrypt a block with Tripple-DES + * + * This function encrypts a block of 64 bits (8 bytes) with the Tripple-DES (EDE) + * algorithm. Key expansion is done automatically. The key is 192 bits long, but + * note that only 178 bits are used (the LSB of each byte is dropped). The input + * and output blocks may overlap. + * + * \param out pointer to the block (64 bit = 8 byte) where the ciphertext is written to + * \param in pointer to the block (64 bit = 8 byte) where the plaintext is read from + * \param key pointer to the key (192 bit = 24 byte) + */ +void tdes_enc(void* out, const void* in, const void* key); + +/** \fn void tdes_dec(void* out, const void* in, const void* key) + * \brief decrypt a block with Tripple-DES + * + * This function decrypts a block of 64 bits (8 bytes) with the Tripple-DES (EDE) + * algorithm. Key expansion is done automatically. The key is 192 bits long, but + * note that only 178 bits are used (the LSB of each byte is dropped). The input + * and output blocks may overlap. + * + * \param out pointer to the block (64 bit = 8 byte) where the plaintext is written to + * \param in pointer to the block (64 bit = 8 byte) where the ciphertext is read from + * \param key pointer to the key (192 bit = 24 byte) + */ + void tdes_dec(void* out, const void* in, const void* key); + +#endif /*DES_H_*/ + +// Copied from des.h in desfire imp. +typedef unsigned long DES_KS[16][2]; /* Single-key DES key schedule */ +typedef unsigned long DES3_KS[48][2]; /* Triple-DES key schedule */ + + +extern int Asmversion; /* 1 if we're linked with an asm version, 0 if C */ diff --git a/armsrc/desfire_crypto.c b/armsrc/desfire_crypto.c new file mode 100644 index 00000000..b77ad8ef --- /dev/null +++ b/armsrc/desfire_crypto.c @@ -0,0 +1,642 @@ +/*- + * Copyright (C) 2010, Romain Tartiere. + * + * This program 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 3 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 Lesser General Public License + * along with this program. If not, see + * + * $Id$ + */ + +/* + * This implementation was written based on information provided by the + * following documents: + * + * NIST Special Publication 800-38B + * Recommendation for Block Cipher Modes of Operation: The CMAC Mode for Authentication + * May 2005 + */ +#include "desfire_crypto.h" + +static void xor (const uint8_t *ivect, uint8_t *data, const size_t len); + +static size_t key_macing_length (desfirekey_t key); + +static void xor (const uint8_t *ivect, uint8_t *data, const size_t len) { + for (size_t i = 0; i < len; i++) { + data[i] ^= ivect[i]; + } +} + +void cmac_generate_subkeys ( desfirekey_t key) { + int kbs = key_block_size (key); + const uint8_t R = (kbs == 8) ? 0x1B : 0x87; + + uint8_t l[kbs]; + memset (l, 0, kbs); + + uint8_t ivect[kbs]; + memset (ivect, 0, kbs); + + mifare_cypher_blocks_chained (NULL, key, ivect, l, kbs, MCD_RECEIVE, MCO_ENCYPHER); + + bool xor = false; + + // Used to compute CMAC on complete blocks + memcpy (key->cmac_sk1, l, kbs); + xor = l[0] & 0x80; + lsl (key->cmac_sk1, kbs); + if (xor) + key->cmac_sk1[kbs-1] ^= R; + + // Used to compute CMAC on the last block if non-complete + memcpy (key->cmac_sk2, key->cmac_sk1, kbs); + xor = key->cmac_sk1[0] & 0x80; + lsl (key->cmac_sk2, kbs); + if (xor) + key->cmac_sk2[kbs-1] ^= R; +} + +void cmac (const desfirekey_t key, uint8_t *ivect, const uint8_t *data, size_t len, uint8_t *cmac) { + int kbs = key_block_size (key); + uint8_t *buffer = malloc (padded_data_length (len, kbs)); + + memcpy (buffer, data, len); + + if ((!len) || (len % kbs)) { + buffer[len++] = 0x80; + while (len % kbs) { + buffer[len++] = 0x00; + } + xor (key->cmac_sk2, buffer + len - kbs, kbs); + } else { + xor (key->cmac_sk1, buffer + len - kbs, kbs); + } + + mifare_cypher_blocks_chained (NULL, key, ivect, buffer, len, MCD_SEND, MCO_ENCYPHER); + + memcpy (cmac, ivect, kbs); +} + +size_t key_block_size (const desfirekey_t key) { + size_t block_size = 8; + + switch (key->type) { + case T_DES: + case T_3DES: + case T_3K3DES: + block_size = 8; + break; + case T_AES: + block_size = 16; + break; + } + + return block_size; +} + +/* + * Size of MACing produced with the key. + */ +static size_t key_macing_length (const desfirekey_t key) { + size_t mac_length = MAC_LENGTH; + + switch (key->type) { + case T_DES: + case T_3DES: + mac_length = MAC_LENGTH; + break; + case T_3K3DES: + case T_AES: + mac_length = CMAC_LENGTH; + break; + } + + return mac_length; +} + +/* + * Size required to store nbytes of data in a buffer of size n*block_size. + */ +size_t padded_data_length (const size_t nbytes, const size_t block_size) { + if ((!nbytes) || (nbytes % block_size)) + return ((nbytes / block_size) + 1) * block_size; + else + return nbytes; +} + +/* + * Buffer size required to MAC nbytes of data + */ +size_t maced_data_length (const desfirekey_t key, const size_t nbytes) { + return nbytes + key_macing_length (key); +} +/* + * Buffer size required to encipher nbytes of data and a two bytes CRC. + */ +size_t enciphered_data_length (const desfiretag_t tag, const size_t nbytes, int communication_settings) { + size_t crc_length = 0; + if (!(communication_settings & NO_CRC)) { + switch (DESFIRE(tag)->authentication_scheme) { + case AS_LEGACY: + crc_length = 2; + break; + case AS_NEW: + crc_length = 4; + break; + } + } + + size_t block_size = DESFIRE(tag)->session_key ? key_block_size (DESFIRE(tag)->session_key) : 1; + + return padded_data_length (nbytes + crc_length, block_size); +} + +void* mifare_cryto_preprocess_data (desfiretag_t tag, void *data, size_t *nbytes, off_t offset, int communication_settings) { + uint8_t *res = data; + uint8_t mac[4]; + size_t edl; + bool append_mac = true; + desfirekey_t key = DESFIRE(tag)->session_key; + + if (!key) + return data; + + switch (communication_settings & MDCM_MASK) { + case MDCM_PLAIN: + if (AS_LEGACY == DESFIRE(tag)->authentication_scheme) + break; + + /* + * When using new authentication methods, PLAIN data transmission from + * the PICC to the PCD are CMACed, so we have to maintain the + * cryptographic initialisation vector up-to-date to check data + * integrity later. + * + * The only difference with CMACed data transmission is that the CMAC + * is not apended to the data send by the PCD to the PICC. + */ + + append_mac = false; + + /* pass through */ + case MDCM_MACED: + switch (DESFIRE(tag)->authentication_scheme) { + case AS_LEGACY: + if (!(communication_settings & MAC_COMMAND)) + break; + + /* pass through */ + edl = padded_data_length (*nbytes - offset, key_block_size (DESFIRE(tag)->session_key)) + offset; + + // Fill in the crypto buffer with data ... + memcpy (res, data, *nbytes); + // ... and 0 padding + memset (res + *nbytes, 0, edl - *nbytes); + + mifare_cypher_blocks_chained (tag, NULL, NULL, res + offset, edl - offset, MCD_SEND, MCO_ENCYPHER); + + memcpy (mac, res + edl - 8, 4); + + // Copy again provided data (was overwritten by mifare_cypher_blocks_chained) + memcpy (res, data, *nbytes); + + if (!(communication_settings & MAC_COMMAND)) + break; + // Append MAC + size_t bla = maced_data_length (DESFIRE(tag)->session_key, *nbytes - offset) + offset; + bla++; + + memcpy (res + *nbytes, mac, 4); + + *nbytes += 4; + break; + case AS_NEW: + if (!(communication_settings & CMAC_COMMAND)) + break; + cmac (key, DESFIRE (tag)->ivect, res, *nbytes, DESFIRE (tag)->cmac); + + if (append_mac) { + maced_data_length (key, *nbytes); + + memcpy (res, data, *nbytes); + memcpy (res + *nbytes, DESFIRE (tag)->cmac, CMAC_LENGTH); + *nbytes += CMAC_LENGTH; + } + break; + } + + break; + case MDCM_ENCIPHERED: + /* |<-------------- data -------------->| + * |<--- offset -->| | + * +---------------+--------------------+-----+---------+ + * | CMD + HEADERS | DATA TO BE SECURED | CRC | PADDING | + * +---------------+--------------------+-----+---------+ ---------------- + * | |<~~~~v~~~~~~~~~~~~~>| ^ | | (DES / 3DES) + * | | `---- crc16() ----' | | + * | | | ^ | | ----- *or* ----- + * |<~~~~~~~~~~~~~~~~~~~~v~~~~~~~~~~~~~>| ^ | | (3K3DES / AES) + * | `---- crc32() ----' | | + * | | ---- *then* ---- + * |<---------------------------------->| + * encypher()/decypher() + */ + + if (!(communication_settings & ENC_COMMAND)) + break; + edl = enciphered_data_length (tag, *nbytes - offset, communication_settings) + offset; + + // Fill in the crypto buffer with data ... + memcpy (res, data, *nbytes); + if (!(communication_settings & NO_CRC)) { + // ... CRC ... + switch (DESFIRE (tag)->authentication_scheme) { + case AS_LEGACY: + AppendCrc14443a(res + offset, *nbytes - offset); + *nbytes += 2; + break; + case AS_NEW: + crc32_append (res, *nbytes); + *nbytes += 4; + break; + } + } + // ... and padding + memset (res + *nbytes, 0, edl - *nbytes); + + *nbytes = edl; + + mifare_cypher_blocks_chained (tag, NULL, NULL, res + offset, *nbytes - offset, MCD_SEND, (AS_NEW == DESFIRE(tag)->authentication_scheme) ? MCO_ENCYPHER : MCO_DECYPHER); + break; + default: + + *nbytes = -1; + res = NULL; + break; + } + + return res; + +} + +void* mifare_cryto_postprocess_data (desfiretag_t tag, void *data, ssize_t *nbytes, int communication_settings) +{ + void *res = data; + size_t edl; + void *edata = NULL; + uint8_t first_cmac_byte = 0x00; + + desfirekey_t key = DESFIRE(tag)->session_key; + + if (!key) + return data; + + // Return directly if we just have a status code. + if (1 == *nbytes) + return res; + + switch (communication_settings & MDCM_MASK) { + case MDCM_PLAIN: + + if (AS_LEGACY == DESFIRE(tag)->authentication_scheme) + break; + + /* pass through */ + case MDCM_MACED: + switch (DESFIRE (tag)->authentication_scheme) { + case AS_LEGACY: + if (communication_settings & MAC_VERIFY) { + *nbytes -= key_macing_length (key); + if (*nbytes <= 0) { + *nbytes = -1; + res = NULL; +#ifdef WITH_DEBUG + printf ("No room for MAC!"); +#endif + break; + } + + edl = enciphered_data_length (tag, *nbytes - 1, communication_settings); + edata = malloc (edl); + + memcpy (edata, data, *nbytes - 1); + memset ((uint8_t *)edata + *nbytes - 1, 0, edl - *nbytes + 1); + + mifare_cypher_blocks_chained (tag, NULL, NULL, edata, edl, MCD_SEND, MCO_ENCYPHER); + + if (0 != memcmp ((uint8_t *)data + *nbytes - 1, (uint8_t *)edata + edl - 8, 4)) { +#ifdef WITH_DEBUG + printf ("MACing not verified"); + hexdump ((uint8_t *)data + *nbytes - 1, key_macing_length (key), "Expect ", 0); + hexdump ((uint8_t *)edata + edl - 8, key_macing_length (key), "Actual ", 0); +#endif + DESFIRE (tag)->last_pcd_error = CRYPTO_ERROR; + *nbytes = -1; + res = NULL; + } + } + break; + case AS_NEW: + if (!(communication_settings & CMAC_COMMAND)) + break; + if (communication_settings & CMAC_VERIFY) { + if (*nbytes < 9) { + *nbytes = -1; + res = NULL; + break; + } + first_cmac_byte = ((uint8_t *)data)[*nbytes - 9]; + ((uint8_t *)data)[*nbytes - 9] = ((uint8_t *)data)[*nbytes-1]; + } + + int n = (communication_settings & CMAC_VERIFY) ? 8 : 0; + cmac (key, DESFIRE (tag)->ivect, ((uint8_t *)data), *nbytes - n, DESFIRE (tag)->cmac); + + if (communication_settings & CMAC_VERIFY) { + ((uint8_t *)data)[*nbytes - 9] = first_cmac_byte; + if (0 != memcmp (DESFIRE (tag)->cmac, (uint8_t *)data + *nbytes - 9, 8)) { +#ifdef WITH_DEBUG + printf ("CMAC NOT verified :-("); + hexdump ((uint8_t *)data + *nbytes - 9, 8, "Expect ", 0); + hexdump (DESFIRE (tag)->cmac, 8, "Actual ", 0); +#endif + DESFIRE (tag)->last_pcd_error = CRYPTO_ERROR; + *nbytes = -1; + res = NULL; + } else { + *nbytes -= 8; + } + } + break; + } + + free (edata); + + break; + case MDCM_ENCIPHERED: + (*nbytes)--; + bool verified = false; + int crc_pos = 0x00; + int end_crc_pos = 0x00; + uint8_t x; + + /* + * AS_LEGACY: + * ,-----------------+-------------------------------+--------+ + * \ BLOCK n-1 | BLOCK n | STATUS | + * / PAYLOAD | CRC0 | CRC1 | 0x80? | 0x000000000000 | 0x9100 | + * `-----------------+-------------------------------+--------+ + * + * <------------ DATA ------------> + * FRAME = PAYLOAD + CRC(PAYLOAD) + PADDING + * + * AS_NEW: + * ,-------------------------------+-----------------------------------------------+--------+ + * \ BLOCK n-1 | BLOCK n | STATUS | + * / PAYLOAD | CRC0 | CRC1 | CRC2 | CRC3 | 0x80? | 0x0000000000000000000000000000 | 0x9100 | + * `-------------------------------+-----------------------------------------------+--------+ + * <----------------------------------- DATA ------------------------------------->| + * + * <----------------- DATA ----------------> + * FRAME = PAYLOAD + CRC(PAYLOAD + STATUS) + PADDING + STATUS + * `------------------' + */ + + mifare_cypher_blocks_chained (tag, NULL, NULL, res, *nbytes, MCD_RECEIVE, MCO_DECYPHER); + + /* + * Look for the CRC and ensure it is followed by NULL padding. We + * can't start by the end because the CRC is supposed to be 0 when + * verified, and accumulating 0's in it should not change it. + */ + switch (DESFIRE (tag)->authentication_scheme) { + case AS_LEGACY: + crc_pos = *nbytes - 8 - 1; // The CRC can be over two blocks + if (crc_pos < 0) { + /* Single block */ + crc_pos = 0; + } + break; + case AS_NEW: + /* Move status between payload and CRC */ + res = DESFIRE (tag)->crypto_buffer; + memcpy (res, data, *nbytes); + + crc_pos = (*nbytes) - 16 - 3; + if (crc_pos < 0) { + /* Single block */ + crc_pos = 0; + } + memcpy ((uint8_t *)res + crc_pos + 1, (uint8_t *)res + crc_pos, *nbytes - crc_pos); + ((uint8_t *)res)[crc_pos] = 0x00; + crc_pos++; + *nbytes += 1; + break; + } + + do { + uint16_t crc16 =0x00; + uint32_t crc; + switch (DESFIRE (tag)->authentication_scheme) { + case AS_LEGACY: + end_crc_pos = crc_pos + 2; + AppendCrc14443a (res, end_crc_pos); + + // + + + crc = crc16; + break; + case AS_NEW: + end_crc_pos = crc_pos + 4; + crc32 (res, end_crc_pos, (uint8_t *)&crc); + break; + } + if (!crc) { + verified = true; + for (int n = end_crc_pos; n < *nbytes - 1; n++) { + uint8_t byte = ((uint8_t *)res)[n]; + if (!( (0x00 == byte) || ((0x80 == byte) && (n == end_crc_pos)) )) + verified = false; + } + } + if (verified) { + *nbytes = crc_pos; + switch (DESFIRE (tag)->authentication_scheme) { + case AS_LEGACY: + ((uint8_t *)data)[(*nbytes)++] = 0x00; + break; + case AS_NEW: + /* The status byte was already before the CRC */ + break; + } + } else { + switch (DESFIRE (tag)->authentication_scheme) { + case AS_LEGACY: + break; + case AS_NEW: + x = ((uint8_t *)res)[crc_pos - 1]; + ((uint8_t *)res)[crc_pos - 1] = ((uint8_t *)res)[crc_pos]; + ((uint8_t *)res)[crc_pos] = x; + break; + } + crc_pos++; + } + } while (!verified && (end_crc_pos < *nbytes)); + + if (!verified) { +#ifdef WITH_DEBUG + /* FIXME In some configurations, the file is transmitted PLAIN */ + Dbprintf("CRC not verified in decyphered stream"); +#endif + DESFIRE (tag)->last_pcd_error = CRYPTO_ERROR; + *nbytes = -1; + res = NULL; + } + + break; + default: + Dbprintf("Unknown communication settings"); + *nbytes = -1; + res = NULL; + break; + + } + return res; +} + + +void mifare_cypher_single_block (desfirekey_t key, uint8_t *data, uint8_t *ivect, MifareCryptoDirection direction, MifareCryptoOperation operation, size_t block_size) +{ + uint8_t ovect[MAX_CRYPTO_BLOCK_SIZE]; + + if (direction == MCD_SEND) { + xor (ivect, data, block_size); + } else { + memcpy (ovect, data, block_size); + } + + uint8_t edata[MAX_CRYPTO_BLOCK_SIZE]; + + switch (key->type) { + case T_DES: + switch (operation) { + case MCO_ENCYPHER: + //DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_ENCRYPT); + des_enc(edata, data, key->data); + break; + case MCO_DECYPHER: + //DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_DECRYPT); + des_dec(edata, data, key->data); + break; + } + break; + case T_3DES: + switch (operation) { + case MCO_ENCYPHER: + // DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_ENCRYPT); + // DES_ecb_encrypt ((DES_cblock *) edata, (DES_cblock *) data, &(key->ks2), DES_DECRYPT); + // DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_ENCRYPT); + tdes_enc(edata,data, key->data); + break; + case MCO_DECYPHER: + // DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_DECRYPT); + // DES_ecb_encrypt ((DES_cblock *) edata, (DES_cblock *) data, &(key->ks2), DES_ENCRYPT); + // DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_DECRYPT); + tdes_dec(data, edata, key->data); + break; + } + break; + case T_3K3DES: + switch (operation) { + case MCO_ENCYPHER: + tdes_enc(edata,data, key->data); + // DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_ENCRYPT); + // DES_ecb_encrypt ((DES_cblock *) edata, (DES_cblock *) data, &(key->ks2), DES_DECRYPT); + // DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks3), DES_ENCRYPT); + break; + case MCO_DECYPHER: + tdes_dec(data, edata, key->data); + // DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks3), DES_DECRYPT); + // DES_ecb_encrypt ((DES_cblock *) edata, (DES_cblock *) data, &(key->ks2), DES_ENCRYPT); + // DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_DECRYPT); + break; + } + break; + case T_AES: + switch (operation) + { + case MCO_ENCYPHER: + { + AesCtx ctx; + AesCtxIni(&ctx, ivect, key->data, KEY128,CBC); + AesEncrypt(&ctx, data, edata, sizeof(data) ); + break; + } + case MCO_DECYPHER: + { + AesCtx ctx; + AesCtxIni(&ctx, ivect, key->data, KEY128,CBC); + AesDecrypt(&ctx, edata, data, sizeof(edata)); + break; + } + } + break; + } + + memcpy (data, edata, block_size); + + if (direction == MCD_SEND) { + memcpy (ivect, data, block_size); + } else { + xor (ivect, data, block_size); + memcpy (ivect, ovect, block_size); + } +} + +/* + * This function performs all CBC cyphering / deciphering. + * + * The tag argument may be NULL, in which case both key and ivect shall be set. + * When using the tag session_key and ivect for processing data, these + * arguments should be set to NULL. + * + * Because the tag may contain additional data, one may need to call this + * function with tag, key and ivect defined. + */ +void mifare_cypher_blocks_chained (desfiretag_t tag, desfirekey_t key, uint8_t *ivect, uint8_t *data, size_t data_size, MifareCryptoDirection direction, MifareCryptoOperation operation) { + size_t block_size; + + if (tag) { + if (!key) + key = DESFIRE (tag)->session_key; + if (!ivect) + ivect = DESFIRE (tag)->ivect; + + switch (DESFIRE (tag)->authentication_scheme) { + case AS_LEGACY: + memset (ivect, 0, MAX_CRYPTO_BLOCK_SIZE); + break; + case AS_NEW: + break; + } + } + + block_size = key_block_size (key); + + size_t offset = 0; + while (offset < data_size) { + mifare_cypher_single_block (key, data + offset, ivect, direction, operation, block_size); + offset += block_size; + } +} \ No newline at end of file diff --git a/armsrc/desfire_crypto.h b/armsrc/desfire_crypto.h new file mode 100644 index 00000000..d580ccc8 --- /dev/null +++ b/armsrc/desfire_crypto.h @@ -0,0 +1,15 @@ +#ifndef __DESFIRE_CRYPTO_H +#define __DESFIRE_CRYPTO_H + +#include +#include +#include +#include "printf.h" + +#include "iso14443a.h" +#include "../common/desfire.h" +#include "des.h" +//#include "aes.h" + + +#endif diff --git a/armsrc/desfire_key.c b/armsrc/desfire_key.c new file mode 100644 index 00000000..b829013e --- /dev/null +++ b/armsrc/desfire_key.c @@ -0,0 +1,158 @@ +/*- + * Copyright (C) 2010, Romain Tartiere. + * + * This program 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 3 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 Lesser General Public License + * along with this program. If not, see + * + * $Id$ + */ + + #include "desfire_key.h" + +static inline void update_key_schedules (desfirekey_t key); + +static inline void update_key_schedules (desfirekey_t key) { + // DES_set_key ((DES_cblock *)key->data, &(key->ks1)); + // DES_set_key ((DES_cblock *)(key->data + 8), &(key->ks2)); + // if (T_3K3DES == key->type) { + // DES_set_key ((DES_cblock *)(key->data + 16), &(key->ks3)); + // } +} + +desfirekey_t Desfire_des_key_new (const uint8_t value[8]) { + uint8_t data[8]; + memcpy (data, value, 8); + for (int n=0; n < 8; n++) + data[n] &= 0xfe; + return Desfire_des_key_new_with_version (data); +} + +desfirekey_t Desfire_des_key_new_with_version (const uint8_t value[8]) { + desfirekey_t key = NULL; + key->type = T_DES; + memcpy (key->data, value, 8); + memcpy (key->data+8, value, 8); + update_key_schedules (key); + return key; +} + +desfirekey_t Desfire_3des_key_new (const uint8_t value[16]) { + uint8_t data[16]; + memcpy (data, value, 16); + for (int n=0; n < 8; n++) + data[n] &= 0xfe; + for (int n=8; n < 16; n++) + data[n] |= 0x01; + return Desfire_3des_key_new_with_version (data); +} + +desfirekey_t Desfire_3des_key_new_with_version (const uint8_t value[16]) { + desfirekey_t key = NULL; + key->type = T_3DES; + memcpy (key->data, value, 16); + update_key_schedules (key); + return key; +} + +desfirekey_t Desfire_3k3des_key_new (const uint8_t value[24]) { + uint8_t data[24]; + memcpy (data, value, 24); + for (int n=0; n < 8; n++) + data[n] &= 0xfe; + return Desfire_3k3des_key_new_with_version (data); +} + +desfirekey_t Desfire_3k3des_key_new_with_version (const uint8_t value[24]) { + desfirekey_t key = NULL; + key->type = T_3K3DES; + memcpy (key->data, value, 24); + update_key_schedules (key); + return key; +} + +desfirekey_t Desfire_aes_key_new (const uint8_t value[16]) { + return Desfire_aes_key_new_with_version (value, 0); +} + +desfirekey_t Desfire_aes_key_new_with_version (const uint8_t value[16], uint8_t version) { + desfirekey_t key = NULL; + memcpy (key->data, value, 16); + key->type = T_AES; + key->aes_version = version; + return key; +} + +uint8_t Desfire_key_get_version (desfirekey_t key) { + uint8_t version = 0; + + for (int n = 0; n < 8; n++) { + version |= ((key->data[n] & 1) << (7 - n)); + } + + return version; +} + +void Desfire_key_set_version (desfirekey_t key, uint8_t version) +{ + for (int n = 0; n < 8; n++) { + uint8_t version_bit = ((version & (1 << (7-n))) >> (7-n)); + key->data[n] &= 0xfe; + key->data[n] |= version_bit; + if (key->type == T_DES) { + key->data[n+8] = key->data[n]; + } else { + // Write ~version to avoid turning a 3DES key into a DES key + key->data[n+8] &= 0xfe; + key->data[n+8] |= ~version_bit; + } + } +} + +desfirekey_t Desfire_session_key_new (const uint8_t rnda[], const uint8_t rndb[], desfirekey_t authkey) { + + desfirekey_t key = NULL; + + uint8_t buffer[24]; + + switch (authkey->type) { + case T_DES: + memcpy (buffer, rnda, 4); + memcpy (buffer+4, rndb, 4); + key = Desfire_des_key_new_with_version (buffer); + break; + case T_3DES: + memcpy (buffer, rnda, 4); + memcpy (buffer+4, rndb, 4); + memcpy (buffer+8, rnda+4, 4); + memcpy (buffer+12, rndb+4, 4); + key = Desfire_3des_key_new_with_version (buffer); + break; + case T_3K3DES: + memcpy (buffer, rnda, 4); + memcpy (buffer+4, rndb, 4); + memcpy (buffer+8, rnda+6, 4); + memcpy (buffer+12, rndb+6, 4); + memcpy (buffer+16, rnda+12, 4); + memcpy (buffer+20, rndb+12, 4); + key = Desfire_3k3des_key_new (buffer); + break; + case T_AES: + memcpy (buffer, rnda, 4); + memcpy (buffer+4, rndb, 4); + memcpy (buffer+8, rnda+12, 4); + memcpy (buffer+12, rndb+12, 4); + key = Desfire_aes_key_new (buffer); + break; + } + return key; +} \ No newline at end of file diff --git a/armsrc/desfire_key.h b/armsrc/desfire_key.h new file mode 100644 index 00000000..ae1249b4 --- /dev/null +++ b/armsrc/desfire_key.h @@ -0,0 +1,10 @@ +#ifndef __DESFIRE_KEY_H +#define __DESFIRE_KEY_H + +#include +#include +#include + +#include "iso14443a.h" +#include "../common/desfire.h" +#endif \ No newline at end of file diff --git a/armsrc/epa.c b/armsrc/epa.c index b0ae5e0d..565019ce 100644 --- a/armsrc/epa.c +++ b/armsrc/epa.c @@ -13,7 +13,7 @@ #include "iso14443a.h" #include "epa.h" -#include "cmd.h" +#include "../common/cmd.h" // Protocol and Parameter Selection Request // use regular (1x) speed in both directions diff --git a/armsrc/fpgaloader.c b/armsrc/fpgaloader.c index 077b378a..32e0500e 100644 --- a/armsrc/fpgaloader.c +++ b/armsrc/fpgaloader.c @@ -9,7 +9,8 @@ // Routines to load the FPGA image, and then to configure the FPGA's major // mode once it is configured. //----------------------------------------------------------------------------- -#include "proxmark3.h" + +#include "../include/proxmark3.h" #include "apps.h" #include "util.h" #include "string.h" diff --git a/armsrc/hitag2.c b/armsrc/hitag2.c index 9181a62e..7d6668eb 100644 --- a/armsrc/hitag2.c +++ b/armsrc/hitag2.c @@ -16,10 +16,10 @@ // (c) 2012 Roel Verdult //----------------------------------------------------------------------------- -#include "proxmark3.h" +#include "../include/proxmark3.h" #include "apps.h" #include "util.h" -#include "hitag2.h" +#include "../include/hitag2.h" #include "string.h" static bool bQuiet; diff --git a/armsrc/iclass.c b/armsrc/iclass.c index d5cd366d..f71607d2 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -36,15 +36,18 @@ // //----------------------------------------------------------------------------- -#include "proxmark3.h" +#include "../include/proxmark3.h" #include "apps.h" #include "util.h" #include "string.h" #include "common.h" +#include "cmd.h" // Needed for CRC in emulation mode; // same construction as in ISO 14443; // different initial value (CRC_ICLASS) -#include "iso14443crc.h" +#include "../common/iso14443crc.h" +#include "../common/iso15693tools.h" + static int timeout = 4096; @@ -1167,12 +1170,11 @@ int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived, uint8_t *reader } else if(receivedCmd[0] == 0x05) { // Reader random and reader MAC!!! // Do not respond - // We do not know what to answer, so lets keep quit + // We do not know what to answer, so lets keep quiet resp = resp1; respLen = 0; //order = 5; respdata = NULL; respsize = 0; if (breakAfterMacReceived){ - // TODO, actually return this to the caller instead of just // dbprintf:ing ... Dbprintf("CSN: %02x %02x %02x %02x %02x %02x %02x %02x",csn[0],csn[1],csn[2],csn[3],csn[4],csn[5],csn[6],csn[7]); Dbprintf("RDR: (len=%02d): %02x %02x %02x %02x %02x %02x %02x %02x %02x",len, @@ -1465,15 +1467,252 @@ int ReaderReceiveIClass(uint8_t* receivedAnswer) return Demod.len; } +void setupIclassReader() +{ + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + // Reset trace buffer + iso14a_set_tracing(TRUE); + iso14a_clear_trace(); + + // Setup SSC + FpgaSetupSsc(); + // Start from off (no field generated) + // Signal field is off with the appropriate LED + LED_D_OFF(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(200); + + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + + // Now give it time to spin up. + // Signal field is on with the appropriate LED + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); + SpinDelay(200); + LED_A_ON(); + +} + // Reader iClass Anticollission void ReaderIClass(uint8_t arg0) { uint8_t act_all[] = { 0x0a }; uint8_t identify[] = { 0x0c }; uint8_t select[] = { 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + uint8_t readcheck_cc[]= { 0x88, 0x02 }; + + uint8_t card_data[24]={0}; + uint8_t last_csn[8]={0}; uint8_t* resp = (((uint8_t *)BigBuf) + 3560); // was 3560 - tied to other size changes - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + int read_status= 0; + bool abort_after_read = arg0 & FLAG_ICLASS_READER_ONLY_ONCE; + + setupIclassReader(); + + size_t datasize = 0; + while(!BUTTON_PRESS()) + { + WDT_HIT(); + + // Send act_all + ReaderTransmitIClass(act_all, 1); + // Card present? + if(ReaderReceiveIClass(resp)) { + + ReaderTransmitIClass(identify, 1); + + if(ReaderReceiveIClass(resp) == 10) { + //Copy the Anti-collision CSN to our select-packet + memcpy(&select[1],resp,8); + //Dbprintf("Anti-collision CSN: %02x %02x %02x %02x %02x %02x %02x %02x",resp[0], resp[1], resp[2], + // resp[3], resp[4], resp[5], + // resp[6], resp[7]); + //Select the card + ReaderTransmitIClass(select, sizeof(select)); + + if(ReaderReceiveIClass(resp) == 10) { + //Save CSN in response data + memcpy(card_data,resp,8); + datasize += 8; + //Flag that we got to at least stage 1, read CSN + read_status = 1; + + // Card selected + //Dbprintf("Readcheck on Sector 2"); + ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc)); + if(ReaderReceiveIClass(resp) == 8) { + //Save CC (e-purse) in response data + memcpy(card_data+8,resp,8); + datasize += 8; + //Got both + read_status = 2; + } + + LED_B_ON(); + //Send back to client, but don't bother if we already sent this + if(memcmp(last_csn, card_data, 8) != 0) + cmd_send(CMD_ACK,read_status,0,0,card_data,datasize); + + //Save that we already sent this.... + if(read_status == 2) + memcpy(last_csn, card_data, 8); + + LED_B_OFF(); + + if(abort_after_read) break; + } + } + } + + if(traceLen > TRACE_SIZE) { + DbpString("Trace full"); + break; + } + } + LED_A_OFF(); +} + +void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) { + uint8_t act_all[] = { 0x0a }; + uint8_t identify[] = { 0x0c }; + uint8_t select[] = { 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + uint8_t readcheck_cc[]= { 0x88, 0x02 }; + uint8_t check[] = { 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + uint8_t read[] = { 0x0c, 0x00, 0x00, 0x00 }; + + uint16_t crc = 0; + uint8_t cardsize=0; + bool read_success=false; + uint8_t mem=0; + + static struct memory_t{ + int k16; + int book; + int k2; + int lockauth; + int keyaccess; + } memory; + + uint8_t* resp = (((uint8_t *)BigBuf) + 3560); // was 3560 - tied to other size changes + + setupIclassReader(); + + + for(int i=0;i<1;i++) { + + if(traceLen > TRACE_SIZE) { + DbpString("Trace full"); + break; + } + + if (BUTTON_PRESS()) break; + + // Send act_all + ReaderTransmitIClass(act_all, 1); + // Card present? + if(ReaderReceiveIClass(resp)) { + ReaderTransmitIClass(identify, 1); + if(ReaderReceiveIClass(resp) == 10) { + // Select card + memcpy(&select[1],resp,8); + ReaderTransmitIClass(select, sizeof(select)); + + if(ReaderReceiveIClass(resp) == 10) { + Dbprintf(" Selected CSN: %02x %02x %02x %02x %02x %02x %02x %02x", + resp[0], resp[1], resp[2], + resp[3], resp[4], resp[5], + resp[6], resp[7]); + } + // Card selected + Dbprintf("Readcheck on Sector 2"); + ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc)); + if(ReaderReceiveIClass(resp) == 8) { + Dbprintf(" CC: %02x %02x %02x %02x %02x %02x %02x %02x", + resp[0], resp[1], resp[2], + resp[3], resp[4], resp[5], + resp[6], resp[7]); + }else return; + Dbprintf("Authenticate"); + //for now replay captured auth (as cc not updated) + memcpy(check+5,MAC,4); + //Dbprintf(" AA: %02x %02x %02x %02x", + // check[5], check[6], check[7],check[8]); + ReaderTransmitIClass(check, sizeof(check)); + if(ReaderReceiveIClass(resp) == 4) { + Dbprintf(" AR: %02x %02x %02x %02x", + resp[0], resp[1], resp[2],resp[3]); + }else { + Dbprintf("Error: Authentication Fail!"); + return; + } + Dbprintf("Dump Contents"); + //first get configuration block + read_success=false; + read[1]=1; + uint8_t *blockno=&read[1]; + crc = iclass_crc16((char *)blockno,1); + read[2] = crc >> 8; + read[3] = crc & 0xff; + while(!read_success){ + ReaderTransmitIClass(read, sizeof(read)); + if(ReaderReceiveIClass(resp) == 10) { + read_success=true; + mem=resp[5]; + memory.k16= (mem & 0x80); + memory.book= (mem & 0x20); + memory.k2= (mem & 0x8); + memory.lockauth= (mem & 0x2); + memory.keyaccess= (mem & 0x1); + + } + } + if (memory.k16){ + cardsize=255; + }else cardsize=32; + //then loop around remaining blocks + for(uint8_t j=0; j> 8; + read[3] = crc & 0xff; + while(!read_success){ + ReaderTransmitIClass(read, sizeof(read)); + if(ReaderReceiveIClass(resp) == 10) { + read_success=true; + Dbprintf(" %02x: %02x %02x %02x %02x %02x %02x %02x %02x", + j, resp[0], resp[1], resp[2], + resp[3], resp[4], resp[5], + resp[6], resp[7]); + } + } + } + } + } + WDT_HIT(); + } + + LED_A_OFF(); +} + +//2. Create Read method (cut-down from above) based off responses from 1. +// Since we have the MAC could continue to use replay function. +//3. Create Write method +/* +void IClass_iso14443A_write(uint8_t arg0, uint8_t blockNo, uint8_t *data, uint8_t *MAC) { + uint8_t act_all[] = { 0x0a }; + uint8_t identify[] = { 0x0c }; + uint8_t select[] = { 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + uint8_t readcheck_cc[]= { 0x88, 0x02 }; + uint8_t check[] = { 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + uint8_t read[] = { 0x0c, 0x00, 0x00, 0x00 }; + uint8_t write[] = { 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + uint16_t crc = 0; + + uint8_t* resp = (((uint8_t *)BigBuf) + 3560); // was 3560 - tied to other size changes // Reset trace buffer memset(trace, 0x44, RECV_CMD_OFFSET); @@ -1496,7 +1735,7 @@ void ReaderIClass(uint8_t arg0) { LED_A_ON(); - for(;;) { + for(int i=0;i<1;i++) { if(traceLen > TRACE_SIZE) { DbpString("Trace full"); @@ -1521,13 +1760,67 @@ void ReaderIClass(uint8_t arg0) { resp[3], resp[4], resp[5], resp[6], resp[7]); } - // Card selected, whats next... ;-) - } + // Card selected + Dbprintf("Readcheck on Sector 2"); + ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc)); + if(ReaderReceiveIClass(resp) == 8) { + Dbprintf(" CC: %02x %02x %02x %02x %02x %02x %02x %02x", + resp[0], resp[1], resp[2], + resp[3], resp[4], resp[5], + resp[6], resp[7]); + }else return; + Dbprintf("Authenticate"); + //for now replay captured auth (as cc not updated) + memcpy(check+5,MAC,4); + Dbprintf(" AA: %02x %02x %02x %02x", + check[5], check[6], check[7],check[8]); + ReaderTransmitIClass(check, sizeof(check)); + if(ReaderReceiveIClass(resp) == 4) { + Dbprintf(" AR: %02x %02x %02x %02x", + resp[0], resp[1], resp[2],resp[3]); + }else { + Dbprintf("Error: Authentication Fail!"); + return; + } + Dbprintf("Write Block"); + + //read configuration for max block number + read_success=false; + read[1]=1; + uint8_t *blockno=&read[1]; + crc = iclass_crc16((char *)blockno,1); + read[2] = crc >> 8; + read[3] = crc & 0xff; + while(!read_success){ + ReaderTransmitIClass(read, sizeof(read)); + if(ReaderReceiveIClass(resp) == 10) { + read_success=true; + mem=resp[5]; + memory.k16= (mem & 0x80); + memory.book= (mem & 0x20); + memory.k2= (mem & 0x8); + memory.lockauth= (mem & 0x2); + memory.keyaccess= (mem & 0x1); + + } + } + if (memory.k16){ + cardsize=255; + }else cardsize=32; + //check card_size + + memcpy(write+1,blockNo,1); + memcpy(write+2,data,8); + memcpy(write+10,mac,4); + while(!send_success){ + ReaderTransmitIClass(write, sizeof(write)); + if(ReaderReceiveIClass(resp) == 10) { + write_success=true; + } + }// } WDT_HIT(); } LED_A_OFF(); -} - - +}*/ diff --git a/armsrc/iso14443.c b/armsrc/iso14443.c index 7a445bcb..bc7b9b16 100644 --- a/armsrc/iso14443.c +++ b/armsrc/iso14443.c @@ -10,12 +10,12 @@ // supported. //----------------------------------------------------------------------------- -#include "proxmark3.h" +#include "../include/proxmark3.h" #include "apps.h" #include "util.h" #include "string.h" -#include "iso14443crc.h" +#include "../common/iso14443crc.h" //static void GetSamplesFor14443(int weTx, int n); diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 9a80a177..0cd9053b 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -10,13 +10,12 @@ // Routines to support ISO 14443 type A. //----------------------------------------------------------------------------- -#include "proxmark3.h" +#include "../include/proxmark3.h" #include "apps.h" #include "util.h" #include "string.h" -#include "cmd.h" - -#include "iso14443crc.h" +#include "../common/cmd.h" +#include "../common/iso14443crc.h" #include "iso14443a.h" #include "crapto1.h" #include "mifareutil.h" @@ -1616,6 +1615,13 @@ int ReaderReceive(uint8_t* receivedAnswer) return ReaderReceiveOffset(receivedAnswer, 0); } +int ReaderReceiveDesfiresAuthTiming(uint8_t *receivedAnswer, uint32_t *elapsedTime) +{ + int len = ReaderReceiveOffset(receivedAnswer, 0); + *elapsedTime = (Demod.endTime*16 - DELAY_AIR2ARM_AS_READER) - (Demod.startTime*16 - DELAY_AIR2ARM_AS_READER); + return len; +} + int ReaderReceivePar(uint8_t *receivedAnswer, uint32_t *parptr) { if (!GetIso14443aAnswerFromTag(receivedAnswer,0,160)) return FALSE; @@ -1787,7 +1793,7 @@ void iso14443a_setup(uint8_t fpga_minor_mode) { DemodReset(); UartReset(); NextTransferTime = 2*DELAY_ARM2AIR_AS_READER; - iso14a_set_timeout(1050); // 10ms default + iso14a_set_timeout(1050); // 10ms default 10*105 = } int iso14_apdu(uint8_t * cmd, size_t cmd_len, void * data) { @@ -1825,8 +1831,8 @@ void ReaderIso14443a(UsbCommand *c) { iso14a_command_t param = c->arg[0]; uint8_t *cmd = c->d.asBytes; - size_t len = c->arg[1]; - size_t lenbits = c->arg[2]; + size_t len = c->arg[1] & 0xFFFF; + size_t lenbits = c->arg[1] >> 16; uint32_t arg0 = 0; byte_t buf[USB_CMD_DATA_SIZE]; @@ -1862,9 +1868,10 @@ void ReaderIso14443a(UsbCommand *c) if(param & ISO14A_APPEND_CRC) { AppendCrc14443a(cmd,len); len += 2; - if (lenbits) lenbits += 16; + lenbits += 16; } if(lenbits>0) { + ReaderTransmitBitsPar(cmd,lenbits,GetParity(cmd,lenbits/8), NULL); } else { ReaderTransmit(cmd,len, NULL); @@ -2206,12 +2213,9 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * if (MF_DBGLEVEL >= 1) { if (!_7BUID) { - Dbprintf("4B UID: %02x%02x%02x%02x", - rUIDBCC1[0], rUIDBCC1[1], rUIDBCC1[2], rUIDBCC1[3]); + Dbprintf("4B UID: %02x%02x%02x%02x",rUIDBCC1[0] , rUIDBCC1[1] , rUIDBCC1[2] , rUIDBCC1[3]); } else { - Dbprintf("7B UID: (%02x)%02x%02x%02x%02x%02x%02x%02x", - rUIDBCC1[0], rUIDBCC1[1], rUIDBCC1[2], rUIDBCC1[3], - rUIDBCC2[0], rUIDBCC2[1] ,rUIDBCC2[2], rUIDBCC2[3]); + Dbprintf("7B UID: (%02x)%02x%02x%02x%02x%02x%02x%02x",rUIDBCC1[0] , rUIDBCC1[1] , rUIDBCC1[2] , rUIDBCC1[3],rUIDBCC2[0],rUIDBCC2[1] ,rUIDBCC2[2] , rUIDBCC2[3]); } } @@ -2321,9 +2325,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * // test if auth OK if (cardRr != prng_successor(nonce, 64)){ - if (MF_DBGLEVEL >= 2) Dbprintf("AUTH FAILED for sector %d with key %c. cardRr=%08x, succ=%08x", - cardAUTHSC, cardAUTHKEY == 0 ? 'A' : 'B', - cardRr, prng_successor(nonce, 64)); + if (MF_DBGLEVEL >= 2) Dbprintf("AUTH FAILED. cardRr=%08x, succ=%08x",cardRr, prng_successor(nonce, 64)); // Shouldn't we respond anything here? // Right now, we don't nack or anything, which causes the // reader to do a WUPA after a while. /Martin diff --git a/armsrc/iso14443a.h b/armsrc/iso14443a.h index 6d18515f..af650a9e 100644 --- a/armsrc/iso14443a.h +++ b/armsrc/iso14443a.h @@ -12,7 +12,7 @@ #ifndef __ISO14443A_H #define __ISO14443A_H -#include "common.h" +#include "../include/common.h" #include "mifaresniff.h" // mifare reader over DMA buffer (SnoopIso14443a())!!! @@ -84,6 +84,7 @@ extern void ReaderTransmitBitsPar(uint8_t *frame, int bits, uint32_t par, uint32 extern void ReaderTransmitPar(uint8_t *frame, int len, uint32_t par, uint32_t *timing); extern int ReaderReceive(uint8_t *receivedAnswer); extern int ReaderReceivePar(uint8_t *receivedAnswer, uint32_t *parptr); +extern int ReaderReceiveDesfiresAuthTiming(uint8_t *receivedAnswer, uint32_t *elapsedTime); extern void iso14443a_setup(uint8_t fpga_minor_mode); extern int iso14_apdu(uint8_t *cmd, size_t cmd_len, void *data); diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index ed7beb6f..39d9effb 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -58,12 +58,12 @@ // *) document all the functions -#include "proxmark3.h" +#include "../include/proxmark3.h" #include "util.h" #include "apps.h" #include "string.h" -#include "iso15693tools.h" -#include "cmd.h" +#include "../common/iso15693tools.h" +#include "../common/cmd.h" #define arraylen(x) (sizeof(x)/sizeof((x)[0])) @@ -1275,12 +1275,8 @@ void DirectTag15693Command(uint32_t datalen,uint32_t speed, uint32_t recv, uint8 recvlen=SendDataTag(data,datalen,1,speed,(recv?&recvbuf:NULL)); if (recv) { -// n.cmd=/* CMD_ISO_15693_COMMAND_DONE */ CMD_ACK; -// n.arg[0]=recvlen>48?48:recvlen; -// memcpy(n.d.asBytes, recvbuf, 48); LED_B_ON(); cmd_send(CMD_ACK,recvlen>48?48:recvlen,0,0,recvbuf,48); -// UsbSendPacket((uint8_t *)&n, sizeof(n)); LED_B_OFF(); if (DEBUG) { diff --git a/armsrc/legicrf.c b/armsrc/legicrf.c index 3fbdf5cb..0e63ef5e 100644 --- a/armsrc/legicrf.c +++ b/armsrc/legicrf.c @@ -8,14 +8,14 @@ // LEGIC RF simulation code //----------------------------------------------------------------------------- -#include "proxmark3.h" +#include "../include/proxmark3.h" #include "apps.h" #include "util.h" #include "string.h" #include "legicrf.h" -#include "legic_prng.h" -#include "crc.h" +#include "../include/legic_prng.h" +#include "../common/crc.h" static struct legic_frame { int bits; diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 6b131c26..11fc8c50 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -8,12 +8,14 @@ // Also routines for raw mode reading/simulating of LF waveform //----------------------------------------------------------------------------- -#include "proxmark3.h" +#include "../include/proxmark3.h" #include "apps.h" #include "util.h" -#include "hitag2.h" -#include "crc16.h" +#include "../include/hitag2.h" +#include "../common/crc16.h" #include "string.h" +#include "crapto1.h" +#include "mifareutil.h" void LFSetupFPGAForADC(int divisor, bool lf_field) { @@ -1146,6 +1148,15 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) #define WRITE_0 144 // 192 #define WRITE_1 400 // 432 for T55x7; 448 for E5550 +// VALUES TAKEN FROM EM4x function: SendForward +// START_GAP = 440; //(55*8) +// WRITE_GAP = 128; //(16*8) +// WRITE_1 = 256 32*8; //32 cycles at 125Khz (8us each) 1 +// //These timings work for 4469/4269/4305 (with the 55*8 above) +// WRITE_0 = 23*8 , 9*8 SpinDelayUs(23*8); // (8us each) 0 + + + // Write one bit to card void T55xxWriteBit(int bit) { @@ -1207,13 +1218,15 @@ void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t PwdMod // Read one card block in page 0 void T55xxReadBlock(uint32_t Block, uint32_t Pwd, uint8_t PwdMode) { - uint8_t *dest = (uint8_t *)BigBuf; - int m=0, i=0; + uint8_t *dest = mifare_get_bigbufptr(); + uint16_t bufferlength = 16000; + uint32_t i = 0; + + // Clear destination buffer before sending the command 0x80 = average. + memset(dest, 0x80, bufferlength); FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - m = sizeof(BigBuf); - // Clear destination buffer before sending the command - memset(dest, 128, m); + // Connect the A/D to the peak-detected low-frequency path. SetAdcMuxFor(GPIO_MUXSEL_LOPKD); // Now set up the SSC to get the ADC samples that are now streaming at us. @@ -1254,31 +1267,33 @@ void T55xxReadBlock(uint32_t Block, uint32_t Pwd, uint8_t PwdMode) for(;;) { if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { AT91C_BASE_SSC->SSC_THR = 0x43; + LED_D_ON(); } if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - // we don't care about actual value, only if it's more or less than a - // threshold essentially we capture zero crossings for later analysis - // if(dest[i] < 127) dest[i] = 0; else dest[i] = 1; - i++; - if (i >= m) break; + LED_D_OFF(); + ++i; + if (i > bufferlength) break; } } + + cmd_send(CMD_ACK,0,0,0,0,0); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off LED_D_OFF(); - DbpString("DONE!"); } // Read card traceability data (page 1) void T55xxReadTrace(void){ - uint8_t *dest = (uint8_t *)BigBuf; - int m=0, i=0; + uint8_t *dest = mifare_get_bigbufptr(); + uint16_t bufferlength = 16000; + int i=0; + + // Clear destination buffer before sending the command 0x80 = average + memset(dest, 0x80, bufferlength); FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - m = sizeof(BigBuf); - // Clear destination buffer before sending the command - memset(dest, 128, m); + // Connect the A/D to the peak-detected low-frequency path. SetAdcMuxFor(GPIO_MUXSEL_LOPKD); // Now set up the SSC to get the ADC samples that are now streaming at us. @@ -1309,17 +1324,20 @@ void T55xxReadTrace(void){ for(;;) { if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { AT91C_BASE_SSC->SSC_THR = 0x43; + LED_D_ON(); } if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - i++; - if (i >= m) break; + LED_D_OFF(); + ++i; + if (i >= bufferlength) break; } } + cmd_send(CMD_ACK,0,0,0,0,0); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off LED_D_OFF(); - DbpString("DONE!"); } /*-------------- Cloning routines -----------*/ @@ -1763,7 +1781,6 @@ int IsBlock1PCF7931(uint8_t *Block) { return 0; } - #define ALLOC 16 void ReadPCF7931() { @@ -2023,6 +2040,7 @@ void SendForward(uint8_t fwd_bit_count) { } } + void EM4xLogin(uint32_t Password) { uint8_t fwd_bit_count; @@ -2040,9 +2058,14 @@ void EM4xLogin(uint32_t Password) { void EM4xReadWord(uint8_t Address, uint32_t Pwd, uint8_t PwdMode) { + uint8_t *dest = mifare_get_bigbufptr(); + uint16_t bufferlength = 16000; + uint32_t i = 0; + + // Clear destination buffer before sending the command 0x80 = average. + memset(dest, 0x80, bufferlength); + uint8_t fwd_bit_count; - uint8_t *dest = (uint8_t *)BigBuf; - int m=0, i=0; //If password mode do login if (PwdMode == 1) EM4xLogin(Pwd); @@ -2051,9 +2074,6 @@ void EM4xReadWord(uint8_t Address, uint32_t Pwd, uint8_t PwdMode) { fwd_bit_count = Prepare_Cmd( FWD_CMD_READ ); fwd_bit_count += Prepare_Addr( Address ); - m = sizeof(BigBuf); - // Clear destination buffer before sending the command - memset(dest, 128, m); // Connect the A/D to the peak-detected low-frequency path. SetAdcMuxFor(GPIO_MUXSEL_LOPKD); // Now set up the SSC to get the ADC samples that are now streaming at us. @@ -2069,10 +2089,12 @@ void EM4xReadWord(uint8_t Address, uint32_t Pwd, uint8_t PwdMode) { } if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - i++; - if (i >= m) break; + ++i; + if (i >= bufferlength) break; } } + + cmd_send(CMD_ACK,0,0,0,0,0); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off LED_D_OFF(); } diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index 6be5b383..ff853a57 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -2,6 +2,9 @@ // Merlok - June 2011, 2012 // Gerhard de Koning Gans - May 2008 // Hagen Fritsch - June 2010 +// Midnitesnake - Dec 2013 +// Andy Davies - Apr 2014 +// Iceman - May 2014 // // 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 @@ -12,9 +15,12 @@ #include "mifarecmd.h" #include "apps.h" +#include "util.h" +#include "desfire.h" +#include "../common/crc.h" //----------------------------------------------------------------------------- -// Select, Authenticate, Read a MIFARE tag. +// Select, Authenticaate, Read an MIFARE tag. // read block //----------------------------------------------------------------------------- void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) @@ -78,7 +84,72 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); +} + +void MifareUC_Auth1(uint8_t arg0, uint8_t *datain){ + // variables + byte_t isOK = 0; + byte_t dataoutbuf[16]; + uint8_t uid[10]; + uint32_t cuid; + + // clear trace + iso14a_clear_trace(); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + + + if(!iso14443a_select_card(uid, NULL, &cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card, something went wrong before auth"); + }; + + + + + if(mifare_ultra_auth1(cuid, dataoutbuf)){ + if (MF_DBGLEVEL >= 1) Dbprintf("Authentication part1: Fail."); + } + + isOK=1; + if (MF_DBGLEVEL >= 2) DbpString("AUTH 1 FINISHED"); + + LED_B_ON(); + cmd_send(CMD_ACK,isOK,cuid,0,dataoutbuf,11); + LED_B_OFF(); + + // Thats it... + LEDsoff(); +} +void MifareUC_Auth2(uint32_t arg0, uint8_t *datain){ + // params + uint32_t cuid = arg0; + uint8_t key[16]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + // variables + byte_t isOK = 0; + byte_t dataoutbuf[16]; + + memcpy(key, datain, 16); + + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + + if(mifare_ultra_auth2(cuid, key, dataoutbuf)){ + if (MF_DBGLEVEL >= 1) Dbprintf("Authentication part2: Fail..."); + } + isOK=1; + if (MF_DBGLEVEL >= 2) DbpString("AUTH 2 FINISHED"); + + LED_B_ON(); + cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,11); + LED_B_OFF(); + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); } void MifareUReadBlock(uint8_t arg0,uint8_t *datain) @@ -129,7 +200,6 @@ void MifareUReadBlock(uint8_t arg0,uint8_t *datain) LEDsoff(); } - //----------------------------------------------------------------------------- // Select, Authenticate, Read a MIFARE tag. // read sector (data = 4 x 16 bytes = 64 bytes, or 16 x 16 bytes = 256 bytes) @@ -198,15 +268,15 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) LEDsoff(); } - -void MifareUReadCard(uint8_t arg0, uint8_t *datain) +void MifareUReadCard(uint8_t arg0, int arg1, uint8_t *datain) { // params uint8_t sectorNo = arg0; - + int Pages=arg1; + int count_Pages=0; // variables byte_t isOK = 0; - byte_t dataoutbuf[16 * 4]; + byte_t dataoutbuf[44 * 4]; uint8_t uid[10]; uint32_t cuid; @@ -218,16 +288,18 @@ void MifareUReadCard(uint8_t arg0, uint8_t *datain) LED_A_ON(); LED_B_OFF(); LED_C_OFF(); - + Dbprintf("Pages %d",Pages); while (true) { if(!iso14443a_select_card(uid, NULL, &cuid)) { if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); break; }; - for(int sec=0;sec<16;sec++){ + for(int sec=0;sec= 1) Dbprintf("Read block %d error",sec); break; + }else{ + count_Pages++; }; } if(mifare_ultra_halt(cuid)) { @@ -238,11 +310,13 @@ void MifareUReadCard(uint8_t arg0, uint8_t *datain) isOK = 1; break; } - + Dbprintf("Pages read %d",count_Pages); if (MF_DBGLEVEL >= 2) DbpString("READ CARD FINISHED"); LED_B_ON(); - cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,64); + if (Pages==16) cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,64); + if (Pages==44 && count_Pages==16) cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,64); + if (Pages==44 && count_Pages>16) cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,176); LED_B_OFF(); // Thats it... diff --git a/armsrc/mifarecmd.h b/armsrc/mifarecmd.h index 3c00a343..2c5a7e3f 100644 --- a/armsrc/mifarecmd.h +++ b/armsrc/mifarecmd.h @@ -13,16 +13,15 @@ #ifndef __MIFARECMD_H #define __MIFARECMD_H -#include "proxmark3.h" +#include "../include/proxmark3.h" #include "apps.h" #include "util.h" #include "string.h" -#include "iso14443crc.h" +#include "../common/iso14443crc.h" #include "iso14443a.h" #include "crapto1.h" #include "mifareutil.h" -#include "common.h" - +#include "../include/common.h" #endif \ No newline at end of file diff --git a/armsrc/mifaredesfire.c b/armsrc/mifaredesfire.c new file mode 100644 index 00000000..d3b04fb0 --- /dev/null +++ b/armsrc/mifaredesfire.c @@ -0,0 +1,568 @@ +#include "mifaredesfire.h" + +#define MAX_APPLICATION_COUNT 28 +#define MAX_FILE_COUNT 16 +#define MAX_FRAME_SIZE 60 +#define NOT_YET_AUTHENTICATED 255 +#define FRAME_PAYLOAD_SIZE (MAX_FRAME_SIZE - 5) + +//static uint8_t __msg[MAX_FRAME_SIZE] = { 0x0A, 0x00, 0x00, /* ..., */ 0x00 }; +/* PCB CID CMD PAYLOAD */ +//static uint8_t __res[MAX_FRAME_SIZE]; + +void MifareDesfireGetInformation(){ + + + uint8_t len = 0; + uint8_t resp[RECV_RES_SIZE]; + uint8_t dataout[RECV_CMD_SIZE]; + byte_t buf[RECV_RES_SIZE]; + + memset(resp,0,sizeof(resp)); + memset(dataout,0, sizeof(dataout)); + memset(buf,0,sizeof(buf)); + + /* + 1 = PCB 1 + 2 = cid 2 + 3 = desfire command 3 + 4-5 = crc 4 key + 5-6 crc + + PCB == 0x0A because sending CID byte. + CID == 0x00 first card? + + */ + uint8_t cmd1[] = {0x0a,0x00,GET_VERSION, 0x00, 0x00 }; + uint8_t cmd2[] = {0x0a,0x00,GET_KEY_VERSION, 0x00, 0x00, 0x00 }; + + iso14a_clear_trace(); + iso14a_set_tracing(TRUE); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + // card select - information + iso14a_card_select_t *card = (iso14a_card_select_t*)buf; + byte_t isOK = iso14443a_select_card(NULL, card, NULL); + if (isOK != 1) { + if (MF_DBGLEVEL >= 1) { + Dbprintf("Can't select card"); + } + OnError(); + return; + } + + + memcpy(dataout,card->uid,7); + + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + + // GET INFORMATION + AppendCrc14443a(cmd1, 3); + ReaderTransmit(cmd1, sizeof(cmd1), NULL); + len = ReaderReceive(resp); + if ( resp[2] != ADDITIONAL_FRAME) { + print_result("ERROR <--: ", resp, len); + OnError(); + return; + } + + memcpy(dataout+7,resp+3,7); + + // ADDITION_FRAME 1 + ++cmd1[0]; + cmd1[2] = ADDITIONAL_FRAME; + AppendCrc14443a(cmd1, 3); + ReaderTransmit(cmd1, sizeof(cmd1), NULL); + len = ReaderReceive(resp); + + if ( resp[2] != ADDITIONAL_FRAME) { + print_result("ERROR <--: ", resp, len); + OnError(); + return; + } + memcpy(dataout+7+7,resp+3,7); + + // ADDITION_FRAME 2 + --cmd1[0]; + AppendCrc14443a(cmd1, 3); + ReaderTransmit(cmd1, sizeof(cmd1), NULL); + len = ReaderReceive(resp); + if ( resp[2] != OPERATION_OK) { + print_result("ERROR <--: ", resp, len); + OnError(); + return; + } + + memcpy(dataout+7+7+7,resp+3,14); + + // GET MASTER KEYSETTINGS + cmd1[2] = GET_KEY_SETTINGS; + AppendCrc14443a(cmd1, 3); + ReaderTransmit(cmd1, sizeof(cmd1), NULL); + len = ReaderReceive(resp); + if (len){ + memcpy(dataout+7+7+7+14,resp+3,2); + } + + + // GET MASTER KEY VERSION + AppendCrc14443a(cmd2, 4); + ReaderTransmit(cmd2, sizeof(cmd2), NULL); + len = ReaderReceive(resp); + if (len){ + memcpy(dataout+7+7+7+14+2,resp+3,1); + } + + // GET FREE MEMORY + cmd1[2] = GET_FREE_MEMORY; + AppendCrc14443a(cmd1, 3); + ReaderTransmit(cmd1, sizeof(cmd1), NULL); + len = ReaderReceive(resp); + if (len){ + memcpy(dataout+7+7+7+14+2+1,resp+3,3); + } + + cmd_send(CMD_ACK,1,0,0,dataout,sizeof(dataout)); + OnSuccess(); +} + +void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno, uint8_t *datain){ + + uint8_t null_key_data[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + uint8_t new_key_data[8] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 }; + int res; + + MifareDESFireKey default_key = mifare_desfire_des_key_new_with_version (null_key_data); + + res = mifare_desfire_select_application (tags[i], aid); + if (res < 0) { + freefare_perror (tags[i], "mifare_desfire_select_application"); + error = EXIT_FAILURE; + break; + } + + return; + // pcb cid cmd key crc1 cr2 + //uint8_t cmd2[] = {0x02,0x00,GET_KEY_VERSION, 0x00, 0x00, 0x00 }; + + //uint8_t* bigbuffer = mifare_get_bigbufptr(); + byte_t isOK = 1; + uint8_t resp[256]; + uint8_t key[24]; + uint8_t IV[16]; + + // första byten håller keylength. + uint8_t keylen = datain[0]; + memcpy(key, datain+1, keylen); + + if (MF_DBGLEVEL >= 1) { + + Dbprintf("MODE: %d", mode); + Dbprintf("ALGO: %d", algo); + Dbprintf("KEYNO: %d", keyno); + Dbprintf("KEYLEN: %d", keylen); + + print_result("KEY", key, keylen); + } + + // card select - information + byte_t buf[USB_CMD_DATA_SIZE]; + iso14a_card_select_t *card = (iso14a_card_select_t*)buf; + + // test of DES on ARM side. + /* + if ( mode == 1){ + uint8_t IV[8]; + uint8_t plain[16]; + uint8_t encData[16]; + + uint8_t tmpData[8]; + uint8_t tmpPlain[8]; + + memset(IV, 0, 8); + memset(tmpData, 0 ,8); + memset(tmpPlain,0 ,8); + memcpy(key, datain, 8); + memcpy(plain, datain+30, 16); + + for(uint8_t i=0; i< sizeof(plain); i=i+8 ){ + + memcpy(tmpPlain, plain+i, 8); + des_enc( &tmpData, &tmpPlain, &key); + memcpy(encData+i, tmpData, 8); + } + } +*/ + + iso14a_clear_trace(); + + iso14a_set_tracing(TRUE); + + // power up the field + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + // select the card + isOK = iso14443a_select_card(resp, card, NULL); + if (isOK != 1) { + if (MF_DBGLEVEL >= 1) { + Dbprintf("CAN'T SELECT CARD, SOMETHING WENT WRONG BEFORE AUTH"); + } + OnError(); + return; + } + + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + + // 3 olika sätt att authenticera. AUTH (CRC16) , AUTH_ISO (CRC32) , AUTH_AES (CRC32) + // 4 olika crypto algo DES, 3DES, 3K3DES, AES + // 3 olika kommunikations sätt, PLAIN,MAC,CRYPTO + + // des, nyckel 0, + switch (mode){ + case 1: + // if ( SendDesfireCommand(AUTHENTICATE, &keyno, resp) > 0 ){ + // // fick nonce från kortet + // } + break; + case 2: + //SendDesfireCommand(AUTHENTICATE_ISO, &keyno, resp); + break; + case 3:{ + AesCtx ctx; + if ( AesCtxIni(&ctx, IV, key, KEY128, CBC) < 0 ){ + if (MF_DBGLEVEL >= 1) { + Dbprintf("AES context failed to init"); + } + OnError(); + return; + } + uint8_t real_cmd[6]; + real_cmd[0] = 0x90; + real_cmd[1] = 0x02; + real_cmd[2] = AUTHENTICATE_AES; + real_cmd[3] = keyno; + + AppendCrc14443a(real_cmd, 2); + ReaderTransmit(real_cmd, sizeof(real_cmd), NULL); + + int len = ReaderReceive(resp); + if(!len) { + OnError(); + return; + } + + print_result("RX:", resp, len); + + enum DESFIRE_STATUS status = resp[1]; + if ( status != ADDITIONAL_FRAME) { + OnError(); + return; + } + + // tags enc nonce + uint8_t encRndB[16]; + uint8_t decRndB[16]; + uint8_t nonce[16]; + uint8_t both[32]; + uint8_t encBoth[32]; + + memset(nonce, 0, 16); + memcpy( encRndB, resp+2, 16); + + // dekryptera tagnonce. + AesDecrypt(&ctx, encRndB, decRndB, 16); + + rol(decRndB,16); + + memcpy(both, nonce,16); + memcpy(both+16, decRndB ,16 ); + + AesEncrypt(&ctx, both, encBoth, 32 ); + + uint8_t real_cmd_A[36]; + real_cmd_A[0] = 0x03; + real_cmd_A[1] = ADDITIONAL_FRAME; + + memcpy(real_cmd_A+2, encBoth, sizeof(encBoth) ); + AppendCrc14443a(real_cmd_A, sizeof(real_cmd_A)); + ReaderTransmit(real_cmd_A, sizeof(real_cmd_A), NULL); + + len = ReaderReceive(resp); + + print_result("Auth1a ", resp, 36); + + status = resp[1]; + if ( status != OPERATION_OK) { + Dbprintf("Cmd Error: %02x Len: %d", status,len); + OnError(); + return; + } + + break; + } + + } + + OnSuccess(resp); +} + + +// desfire_cmd = enum DESFIRE_CMD in desfire.h +// cmd = pointer to +// dataout = point to array for response data. +int SendDesfireCommand(enum DESFIRE_CMD desfire_cmd,uint8_t *dataout, uint8_t fromscratch){ + + uint8_t resp[80]; + uint8_t len; + + if ( fromscratch){ + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + + // power up the field + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + // select the card + iso14443a_select_card(NULL, NULL, NULL); + } + + // 3 olika ISO sätt att skicka data till DESFIRE (direkt, inkapslat, inkapslat ISO) + uint8_t real_cmd[4]; + real_cmd[0] = 0x02; + real_cmd[1] = desfire_cmd; + AppendCrc14443a(real_cmd, 2); + ReaderTransmit(real_cmd, sizeof(real_cmd), NULL); + len = ReaderReceive(resp); + if(!len) + return -1; //DATA LINK ERROR + + if ( fromscratch){ + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + } + + enum DESFIRE_STATUS status = resp[1]; + //1 bytes iso, 1 byte status, in the end: 2 bytes crc + if ( status == OPERATION_OK || status == ADDITIONAL_FRAME) { + memcpy(dataout, resp+2, 2); + return len; + } + else { + Dbprintf("unexpected desfire response: %X (to %X)", status, desfire_cmd); + return -status; + } +} + + // crc_update(&desfire_crc32, 0, 1); /* CMD_WRITE */ + // crc_update(&desfire_crc32, addr, addr_sz); + // crc_update(&desfire_crc32, byte, 8); + // uint32_t crc = crc_finish(&desfire_crc32); + + + /* Version + + //uint8_t versionCmd1[] = {0x02, 0x60}; + //uint8_t versionCmd2[] = {0x03, 0xaf}; + //uint8_t versionCmd3[] = {0x02, 0xaf}; + + // AUTH 1 - CMD: 0x02, 0x0A, 0x00 = Auth + // 0x02 = status byte för simpla svar?!? + // 0x0a = krypto typ + // 0x00 = key nr + //uint8_t initAuthCmdDES[] = {0x02, 0x0a, 0x00}; // DES + //uint8_t initAuthCmd3DES[] = {0x02, 0x1a, 0x00}; // 3DES + //uint8_t initAuthCmdAES[] = {0x02, 0xaa, 0x00}; // AES + // auth 1 - answer command + // 0x03 = status byte för komplexa typer? + // 0xaf = additional frame + // LEN = 1+1+32+2 = 36 + //uint8_t answerAuthCmd[34] = {0x03, 0xaf}; + + // Lägg till CRC + //AppendCrc14443a(versionCmd1,sizeof(versionCmd1)); +*/ + + // Sending commands + /*ReaderTransmit(versionCmd1,sizeof(versionCmd1)+2, NULL); + len = ReaderReceive(buffer); + print_result("Get Version 3", buffer, 9); + */ + + // for( int i = 0; i < 8; i++){ + // // Auth 1 - Request authentication + // ReaderTransmit(initAuthCmdAES,sizeof(initAuthCmdAES)+2, NULL); + // //len = ReaderReceive(buffer); + + // // 0xAE = authentication error + // if (buffer[1] == 0xae) { + // Dbprintf("Cmd Error: %02x", buffer[1]); + // OnError(); + // return; + // } + + // // tags enc nonce + // memcpy(encRndB, buffer+2, 16); + + // // dekryptera svaret från tag. + // AesDecrypt(&ctx, encRndB, decRndB, 16); + + // rol8(decRndB,16); + // memcpy(RndARndB, RndA,16); + // memcpy(RndARndB+16, decRndB ,16 ); + + // AesEncrypt(&ctx, RndARndB, encRndARndB, 32 ); + + // memcpy(answerAuthCmd+2, encRndARndB, 32); + // AppendCrc14443a(answerAuthCmd,sizeof(answerAuthCmd)); + + // ReaderTransmit(answerAuthCmd,sizeof(answerAuthCmd)+2, NULL); + + // len = ReaderReceive(buffer); + + // print_result("Auth1a ", buffer, 8); + // Dbprintf("Rx len: %02x", len); + + // if (buffer[1] == 0xCA) { + // Dbprintf("Cmd Error: %02x Len: %d", buffer[1],len); + // cmd_send(CMD_ACK,0,0,0,0,0); + // key[1] = i; + // AesCtxIni(&ctx, iv, key, KEY128, CBC); + // } + // } + + //des_dec(decRndB, encRndB, key); + + //Do crypto magic + /* + DES_ede2_cbc_encrypt(e_RndB,RndB,sizeof(e_RndB),&ks1,&ks2,&iv,0); + memcpy(RndARndB,RndA,8); + memcpy(RndARndB+8,RndB,8); + PrintAndLog(" RA+B:%s",sprint_hex(RndARndB, 16)); + DES_ede2_cbc_encrypt(RndARndB,RndARndB,sizeof(RndARndB),&ks1,&ks2,&e_RndB,1); + PrintAndLog("enc(RA+B):%s",sprint_hex(RndARndB, 16)); + */ + + +int mifare_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData){ + + uint8_t* buffer = mifare_get_bigbufptr(); + uint8_t dcmd[19]; + + dcmd[0] = 0xAF; + memcpy(dcmd+1,key,16); + AppendCrc14443a(dcmd, 17); + + + ReaderTransmit(dcmd, sizeof(dcmd), NULL); + int len = ReaderReceive(buffer); + if(!len) { + if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Card timeout."); + len = ReaderReceive(buffer); + } + + if(len==1) { + if (MF_DBGLEVEL >= 1) { + Dbprintf("NAK - Authentication failed."); + Dbprintf("Cmd Error: %02x", buffer[0]); + } + return 1; + } + + if (len == 11){ + if (MF_DBGLEVEL >= 1) { + Dbprintf("Auth2 Resp: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + buffer[0],buffer[1],buffer[2],buffer[3],buffer[4], + buffer[5],buffer[6],buffer[7],buffer[8],buffer[9], + buffer[10]); + } + return 0; + } + return 1; +} + +void MifareDES_Auth2(uint32_t arg0, uint8_t *datain){ + + return; + uint32_t cuid = arg0; + uint8_t key[16]; + + byte_t isOK = 0; + byte_t dataoutbuf[16]; + + memset(key, 0, 16); + memcpy(key, datain, 16); + + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + + if(mifare_des_auth2(cuid, key, dataoutbuf)){ + if (MF_DBGLEVEL >= 1) Dbprintf("Authentication part2: Fail..."); + } + isOK=1; + if (MF_DBGLEVEL >= 2) DbpString("AUTH 2 FINISHED"); + + LED_B_ON(); + cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,11); + LED_B_OFF(); + + // Thats it... + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); +} + +// CreateAPDU +uint8_t* CreateAPDU( uint8_t *datain, size_t len){ + + len = MIN(len, USB_CMD_DATA_SIZE); + + uint8_t tmpcmd[len]; + uint8_t *cmd = tmpcmd; + memset(cmd, 0, len); + cmd[0] = 0x0a; + cmd[1] = 0x00; + + memcpy(cmd, datain,len); + AppendCrc14443a(cmd, len+2); + return cmd; +} + +void SelectCard(){ + + uint8_t resp[RECV_RES_SIZE]; + byte_t buf[RECV_RES_SIZE]; + + memset(resp,0,sizeof(resp)); + memset(buf,0,sizeof(buf)); + + iso14a_clear_trace(); + iso14a_set_tracing(TRUE); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + // card select - information + iso14a_card_select_t *card = (iso14a_card_select_t*)buf; + byte_t isOK = iso14443a_select_card(NULL, card, NULL); + if (isOK != 1) { + if (MF_DBGLEVEL >= 1) { + Dbprintf("Can't select card"); + } + OnError(); + return; + } +} + +void OnSuccess(){ + // Deselect card by sending a s-block. the crc is precalced for speed + uint8_t cmd[] = {0xc2,0xe0,0xb4}; + ReaderTransmit(cmd, sizeof(cmd), NULL); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); +} + +void OnError(){ + cmd_send(CMD_ACK,0,0,0,0,0); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); +} diff --git a/armsrc/mifaredesfire.h b/armsrc/mifaredesfire.h new file mode 100644 index 00000000..5d490e2e --- /dev/null +++ b/armsrc/mifaredesfire.h @@ -0,0 +1,16 @@ +#ifndef __MIFAREDESFIRE_H +#define __MIFAREDESFIRE_H + +#include "../include/proxmark3.h" +#include "apps.h" +#include "util.h" +#include "string.h" + +#include "../common/iso14443crc.h" +#include "iso14443a.h" +#include "crapto1.h" +#include "mifareutil.h" +#include "../include/common.h" + + +#endif diff --git a/armsrc/mifaresniff.h b/armsrc/mifaresniff.h index 1065fa61..3ee64f35 100644 --- a/armsrc/mifaresniff.h +++ b/armsrc/mifaresniff.h @@ -11,16 +11,16 @@ #ifndef __MIFARESNIFF_H #define __MIFARESNIFF_H -#include "proxmark3.h" +#include "../include/proxmark3.h" #include "apps.h" #include "util.h" #include "string.h" -#include "iso14443crc.h" +#include "../common/iso14443crc.h" #include "iso14443a.h" #include "crapto1.h" #include "mifareutil.h" -#include "common.h" +#include "../include/common.h" #define SNF_INIT 0 #define SNF_NO_FIELD 1 diff --git a/armsrc/mifareutil.c b/armsrc/mifareutil.c index 0b93db8f..537720df 100644 --- a/armsrc/mifareutil.c +++ b/armsrc/mifareutil.c @@ -9,12 +9,12 @@ // Work with mifare cards. //----------------------------------------------------------------------------- -#include "proxmark3.h" +#include "../include/proxmark3.h" #include "apps.h" #include "util.h" #include "string.h" -#include "iso14443crc.h" +#include "../common/iso14443crc.h" #include "iso14443a.h" #include "crapto1.h" #include "mifareutil.h" @@ -84,26 +84,36 @@ int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, int mifare_sendcmd_short_special(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t* data, uint8_t* answer, uint8_t *timing) { - uint8_t dcmd[8];//, ecmd[4]; - //uint32_t par=0; - + uint8_t dcmd[8]; dcmd[0] = cmd; - dcmd[1] = data[0]; - dcmd[2] = data[1]; - dcmd[3] = data[2]; - dcmd[4] = data[3]; - dcmd[5] = data[4]; + memcpy(dcmd+1,data,5); AppendCrc14443a(dcmd, 6); - //Dbprintf("Data command: %02x", dcmd[0]); - //Dbprintf("Data R: %02x %02x %02x %02x %02x %02x %02x", dcmd[1],dcmd[2],dcmd[3],dcmd[4],dcmd[5],dcmd[6],dcmd[7]); - - //memcpy(ecmd, dcmd, sizeof(dcmd)); ReaderTransmit(dcmd, sizeof(dcmd), NULL); int len = ReaderReceive(answer); - if(!len) - { + if(!len) { if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Card timeout."); return 2; + } + return len; +} + +int mifare_sendcmd_short_mfucauth(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t* data, uint8_t* answer, uint32_t *timing) +{ + uint8_t dcmd[19]; + int len; + dcmd[0] = cmd; + memcpy(dcmd+1,data,16); + AppendCrc14443a(dcmd, 17); + + ReaderTransmit(dcmd, sizeof(dcmd), timing); + len = ReaderReceive(answer); + if(!len) { + if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Card timeout."); + len = ReaderReceive(answer); + } + if(len==1) { + if (MF_DBGLEVEL >= 1) Dbprintf("NAK - Authentication failed."); + return 1; } return len; } @@ -280,6 +290,55 @@ int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blo memcpy(blockData, receivedAnswer, 16); return 0; +} + +int mifare_ultra_auth1(uint32_t uid, uint8_t *blockData){ + // variables + int len; + + uint8_t* receivedAnswer = mifare_get_bigbufptr(); + + // command MIFARE_CLASSIC_READBLOCK + len = mifare_sendcmd_short(NULL, 1, 0x1A, 0x00, receivedAnswer,NULL); + if (len == 1) { + if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); + return 1; + } + if (len == 11) { + if (MF_DBGLEVEL >= 1) Dbprintf("Auth1 Resp: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + receivedAnswer[0],receivedAnswer[1],receivedAnswer[2],receivedAnswer[3],receivedAnswer[4], + receivedAnswer[5],receivedAnswer[6],receivedAnswer[7],receivedAnswer[8],receivedAnswer[9], + receivedAnswer[10]); + memcpy(blockData, receivedAnswer, 11); + return 0; + } + //else something went wrong??? + return 1; +} + +int mifare_ultra_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData){ + // variables + int len; + + uint8_t* receivedAnswer = mifare_get_bigbufptr(); + + + // command MIFARE_CLASSIC_READBLOCK + len = mifare_sendcmd_short_mfucauth(NULL, 1, 0xAF, key, receivedAnswer,NULL); + if (len == 1) { + if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); + return 1; + } + if (len == 11){ + if (MF_DBGLEVEL >= 1) Dbprintf("Auth2 Resp: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + receivedAnswer[0],receivedAnswer[1],receivedAnswer[2],receivedAnswer[3],receivedAnswer[4], + receivedAnswer[5],receivedAnswer[6],receivedAnswer[7],receivedAnswer[8],receivedAnswer[9], + receivedAnswer[10]); + memcpy(blockData, receivedAnswer, 11); + return 0; + } + //something went wrong? + return 1; } int mifare_ultra_readblock(uint32_t uid, uint8_t blockNo, uint8_t *blockData) diff --git a/armsrc/mifareutil.h b/armsrc/mifareutil.h index 8708d3dd..f9d74384 100644 --- a/armsrc/mifareutil.h +++ b/armsrc/mifareutil.h @@ -56,6 +56,7 @@ extern int MF_DBGLEVEL; uint8_t* mifare_get_bigbufptr(void); int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer, uint32_t *timing); int mifare_sendcmd_short_special(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t *data, uint8_t* amswer, uint8_t *timing); +int mifare_sendcmd_short_mfucauth(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t *data, uint8_t* amswer, uint32_t *timing); int mifare_sendcmd_shortex(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer, uint32_t * parptr, uint32_t *timing); int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, \ @@ -63,6 +64,8 @@ int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, \ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, \ uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint64_t isNested, uint32_t * ntptr, uint32_t *timing); int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData); +int mifare_ultra_auth1(uint32_t cuid, uint8_t *blockData); +int mifare_ultra_auth2(uint32_t cuid, uint8_t *key, uint8_t *blockData); int mifare_ultra_readblock(uint32_t uid, uint8_t blockNo, uint8_t *blockData); int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData); int mifare_ultra_writeblock(uint32_t uid, uint8_t blockNo, uint8_t *blockData); diff --git a/armsrc/start.c b/armsrc/start.c index d7332bda..3f5dc676 100644 --- a/armsrc/start.c +++ b/armsrc/start.c @@ -9,7 +9,7 @@ // with the linker script. //----------------------------------------------------------------------------- -#include "proxmark3.h" +#include "../include/proxmark3.h" #include "apps.h" extern char __data_start__, __data_src_start__, __data_end__, __bss_start__, __bss_end__; diff --git a/armsrc/string.c b/armsrc/string.c index cc71276c..945a4cf6 100644 --- a/armsrc/string.c +++ b/armsrc/string.c @@ -48,6 +48,11 @@ int memcmp(const void *av, const void *bv, int len) return 0; } +void memxor(uint8_t * dest, uint8_t * src, size_t len) { + for( ; len > 0; len--,dest++,src++) + *dest ^= *src; +} + int strlen(const char *str) { int l = 0; diff --git a/armsrc/string.h b/armsrc/string.h index 46ee218d..1067b91f 100644 --- a/armsrc/string.h +++ b/armsrc/string.h @@ -12,10 +12,14 @@ #ifndef __STRING_H #define __STRING_H +#include +#include + int strlen(const char *str); void *memcpy(void *dest, const void *src, int len); void *memset(void *dest, int c, int len); int memcmp(const void *av, const void *bv, int len); +void memxor(uint8_t * dest, uint8_t * src, size_t len); char *strncat(char *dest, const char *src, unsigned int n); char *strcat(char *dest, const char *src); void strreverse(char s[]); diff --git a/armsrc/util.c b/armsrc/util.c index 2d3aab9c..f20e4b42 100644 --- a/armsrc/util.c +++ b/armsrc/util.c @@ -8,11 +8,31 @@ // Utility functions used in many places, not specific to any piece of code. //----------------------------------------------------------------------------- -#include "proxmark3.h" +#include "../include/proxmark3.h" #include "util.h" #include "string.h" #include "apps.h" + + +void print_result(char *name, uint8_t *buf, size_t len) { + uint8_t *p = buf; + + if ( len % 16 == 0 ) { + for(; p-buf < len; p += 16) + Dbprintf("[%s:%02x/%02x] %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", + name, + p-buf, + len, + p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15] + ); + } + else { + for(; p-buf < len; p += 8) + Dbprintf("[%s:%02x/%02x] %02x %02x %02x %02x %02x %02x %02x %02x", name, p-buf, len, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); + } +} + size_t nbytes(size_t nbits) { return (nbits/8)+((nbits%8)>0); } @@ -45,6 +65,26 @@ uint64_t bytes_to_num(uint8_t* src, size_t len) return num; } +// RotateLeft - Ultralight, Desfire +void rol(uint8_t *data, const size_t len){ + uint8_t first = data[0]; + for (size_t i = 0; i < len-1; i++) { + data[i] = data[i+1]; + } + data[len-1] = first; +} +void lsl (uint8_t *data, size_t len) { + for (size_t n = 0; n < len - 1; n++) { + data[n] = (data[n] << 1) | (data[n+1] >> 7); + } + data[len - 1] <<= 1; +} + +int32_t le24toh (uint8_t data[3]) +{ + return (data[2] << 16) | (data[1] << 8) | data[0]; +} + void LEDsoff() { LED_A_OFF(); diff --git a/armsrc/util.h b/armsrc/util.h index e8b9cdff..c6503395 100644 --- a/armsrc/util.h +++ b/armsrc/util.h @@ -13,7 +13,7 @@ #include #include -#include +#include "../include/common.h" #define BYTEx(x, n) (((x) >> (n * 8)) & 0xff ) @@ -27,10 +27,14 @@ #define BUTTON_DOUBLE_CLICK -2 #define BUTTON_ERROR -99 +void print_result(char *name, uint8_t *buf, size_t len); size_t nbytes(size_t nbits); uint32_t SwapBits(uint32_t value, int nrbits); void num_to_bytes(uint64_t n, size_t len, uint8_t* dest); uint64_t bytes_to_num(uint8_t* src, size_t len); +void rol(uint8_t *data, const size_t len); +void lsl (uint8_t *data, size_t len); +int32_t le24toh (uint8_t data[3]); void SpinDelay(int ms); void SpinDelayUs(int us); diff --git a/client/Makefile b/client/Makefile index e4a3580b..026db798 100644 --- a/client/Makefile +++ b/client/Makefile @@ -13,23 +13,16 @@ CXX=g++ VPATH = ../common OBJDIR = obj -LDLIBS = -L/opt/local/lib -L/usr/local/lib -lreadline -lpthread ../liblua/liblua.a +LDLIBS = -L/mingw/lib -L/opt/local/lib -L/usr/local/lib ../liblua/liblua.a -lreadline -lpthread -lcrypto -lgdi32 LDFLAGS = $(COMMON_FLAGS) -CFLAGS = -std=c99 -I. -I../include -I../common -I/opt/local/include -I../liblua -Wall $(COMMON_FLAGS) -g -O4 +CFLAGS = -std=c99 -I. -I../include -I../common -I/mingw/include -I/opt/local/include -I../liblua -Wall $(COMMON_FLAGS) -g -O4 $(ICE_FLAGS) LUAPLATFORM = generic ifneq (,$(findstring MINGW,$(platform))) -CXXFLAGS = -I$(QTDIR)/include -I$(QTDIR)/include/QtCore -I$(QTDIR)/include/QtGui -QTLDLIBS = -L$(QTDIR)/lib -lQtCore4 -lQtGui4 +CXXFLAGS = -I$(QTDIR)/include -I$(QTDIR)/include/QtCore -I$(QTDIR)/include/QtGui -I$(QTDIR)/include/QtWidgets +QTLDLIBS = -L$(QTDIR)/lib -lQt5Core -lQt5Gui -lQt5Widgets MOC = $(QTDIR)/bin/moc LUAPLATFORM = mingw -else ifeq ($(platform),Darwin) -#CXXFLAGS = -I/Library/Frameworks/QtGui.framework/Versions/Current/Headers -I/Library/Frameworks/QtCore.framework/Versions/Current/Headers -#QTLDLIBS = -framework QtGui -framework QtCore -CXXFLAGS = -I$(QTDIR)/include -I$(QTDIR)/include/QtCore -I$(QTDIR)/include/QtGui -QTLDLIBS = -F/opt/local/Library/Frameworks -framework QtGui -framework QtCore -MOC = moc -LUAPLATFORM = macosx else CXXFLAGS = $(shell pkg-config --cflags QtCore QtGui 2>/dev/null) -Wall -O4 QTLDLIBS = $(shell pkg-config --libs QtCore QtGui 2>/dev/null) @@ -58,6 +51,12 @@ CORESRCS = uart.c \ CMDSRCS = nonce2key/crapto1.c\ nonce2key/crypto1.c\ nonce2key/nonce2key.c\ + loclass/cipher.c \ + loclass/cipherutils.c \ + loclass/des.c \ + loclass/ikeys.c \ + loclass/elite_crack.c\ + loclass/fileutils.c\ mifarehost.c\ crc16.c \ iso14443crc.c \ @@ -74,6 +73,9 @@ CMDSRCS = nonce2key/crapto1.c\ cmdhflegic.c \ cmdhficlass.c \ cmdhfmf.c \ + cmdhfmfu.c \ + cmdhfmfdes.c \ + cmdhfdes.c \ cmdhw.c \ cmdlf.c \ cmdlfhid.c \ diff --git a/client/cmdhf.c b/client/cmdhf.c index d955fc83..dda0a669 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -22,6 +22,9 @@ #include "cmdhflegic.h" #include "cmdhficlass.h" #include "cmdhfmf.h" +#include "cmdhfmfu.h" +#include "cmdhfmfdes.h" +#include "cmdhfdes.h" static int CmdHelp(const char *Cmd); @@ -42,6 +45,9 @@ static command_t CommandTable[] = {"legic", CmdHFLegic, 0, "{ LEGIC RFIDs... }"}, {"iclass", CmdHFiClass, 1, "{ ICLASS RFIDs... }"}, {"mf", CmdHFMF, 1, "{ MIFARE RFIDs... }"}, + {"mfu", CmdHFMFUltra, 1, "{ MIFARE Ultralight RFIDs... }"}, + {"mfdes", CmdHFMFDes, 1, "{ MIFARE Desfire RFIDs... }"}, + {"des", CmdHFDES, 0, "{ MIFARE DESfire}"}, {"tune", CmdHFTune, 0, "Continuously measure HF antenna tuning"}, {NULL, NULL, 0, NULL} }; diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 39bdcf40..bd19cee4 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -14,15 +14,15 @@ #include #include #include "util.h" -#include "iso14443crc.h" +#include "../common/iso14443crc.h" #include "data.h" #include "proxmark3.h" #include "ui.h" #include "cmdparser.h" #include "cmdhf14a.h" -#include "common.h" +#include "../include/common.h" #include "cmdmain.h" -#include "mifare.h" +#include "../include/mifare.h" static int CmdHelp(const char *Cmd); static void waitCmd(uint8_t iLen); @@ -183,27 +183,24 @@ void iso14a_set_timeout(uint32_t timeout) { int CmdHF14AReader(const char *Cmd) { - UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0}}; + UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT, 0, 0}}; SendCommand(&c); UsbCommand resp; WaitForResponse(CMD_ACK,&resp); - iso14a_card_select_t card; - memcpy(&card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t)); + iso14a_card_select_t *card = (iso14a_card_select_t *)resp.d.asBytes; - uint64_t select_status = resp.arg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS - - if(select_status == 0) { + if(resp.arg[0] == 0) { PrintAndLog("iso14443a card select failed"); return 0; } - PrintAndLog("ATQA : %02x %02x", card.atqa[1], card.atqa[0]); - PrintAndLog(" UID : %s", sprint_hex(card.uid, card.uidlen)); - PrintAndLog(" SAK : %02x [%d]", card.sak, resp.arg[0]); + PrintAndLog("ATQA : %02x %02x", card->atqa[0], card->atqa[1]); + PrintAndLog(" UID : %s", sprint_hex(card->uid, card->uidlen)); + PrintAndLog(" SAK : %02x [%d]", card->sak, resp.arg[0]); - switch (card.sak) { + switch (card->sak) { case 0x00: PrintAndLog("TYPE : NXP MIFARE Ultralight | Ultralight C"); break; case 0x04: PrintAndLog("TYPE : NXP MIFARE (various !DESFire !DESFire EV1)"); break; case 0x08: PrintAndLog("TYPE : NXP MIFARE CLASSIC 1k | Plus 2k SL1"); break; @@ -219,107 +216,67 @@ int CmdHF14AReader(const char *Cmd) case 0x98: PrintAndLog("TYPE : Gemplus MPCOS"); break; default: ; } - - - // try to request ATS even if tag claims not to support it - if (select_status == 2) { - uint8_t rats[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0 - c.arg[0] = ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT; - c.arg[1] = 2; - c.arg[2] = 0; - memcpy(c.d.asBytes, rats, 2); - SendCommand(&c); - WaitForResponse(CMD_ACK,&resp); - - memcpy(&card.ats, resp.d.asBytes, resp.arg[0]); - card.ats_len = resp.arg[0]; // note: ats_len includes CRC Bytes - } - - // disconnect - c.arg[0] = 0; - c.arg[1] = 0; - c.arg[2] = 0; - SendCommand(&c); - - - if(card.ats_len >= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes + if(resp.arg[0] == 1) { bool ta1 = 0, tb1 = 0, tc1 = 0; int pos; - if (select_status == 2) { - PrintAndLog("SAK incorrectly claims that card doesn't support RATS"); + PrintAndLog(" ATS : %s", sprint_hex(card->ats, card->ats_len)); + if (card->ats_len > 0) { + PrintAndLog(" - TL : length is %d bytes", card->ats[0]); } - PrintAndLog(" ATS : %s", sprint_hex(card.ats, card.ats_len)); - PrintAndLog(" - TL : length is %d bytes", card.ats[0]); - if (card.ats[0] != card.ats_len - 2) { - PrintAndLog("ATS may be corrupted. Length of ATS (%d bytes incl. 2 Bytes CRC) doesn't match TL", card.ats_len); - } - - if (card.ats[0] > 1) { // there is a format byte (T0) - ta1 = (card.ats[1] & 0x10) == 0x10; - tb1 = (card.ats[1] & 0x20) == 0x20; - tc1 = (card.ats[1] & 0x40) == 0x40; - int16_t fsci = card.ats[1] & 0x0f; + if (card->ats_len > 1) { + ta1 = (card->ats[1] & 0x10) == 0x10; + tb1 = (card->ats[1] & 0x20) == 0x20; + tc1 = (card->ats[1] & 0x40) == 0x40; PrintAndLog(" - T0 : TA1 is%s present, TB1 is%s present, " - "TC1 is%s present, FSCI is %d (FSC = %ld)", + "TC1 is%s present, FSCI is %d", (ta1 ? "" : " NOT"), (tb1 ? "" : " NOT"), (tc1 ? "" : " NOT"), - fsci, - fsci < 5 ? (fsci - 2) * 8 : - fsci < 8 ? (fsci - 3) * 32 : - fsci == 8 ? 256 : - -1 - ); + (card->ats[1] & 0x0f)); } pos = 2; - if (ta1) { + if (ta1 && card->ats_len > pos) { char dr[16], ds[16]; dr[0] = ds[0] = '\0'; - if (card.ats[pos] & 0x10) strcat(ds, "2, "); - if (card.ats[pos] & 0x20) strcat(ds, "4, "); - if (card.ats[pos] & 0x40) strcat(ds, "8, "); - if (card.ats[pos] & 0x01) strcat(dr, "2, "); - if (card.ats[pos] & 0x02) strcat(dr, "4, "); - if (card.ats[pos] & 0x04) strcat(dr, "8, "); + if (card->ats[pos] & 0x10) strcat(ds, "2, "); + if (card->ats[pos] & 0x20) strcat(ds, "4, "); + if (card->ats[pos] & 0x40) strcat(ds, "8, "); + if (card->ats[pos] & 0x01) strcat(dr, "2, "); + if (card->ats[pos] & 0x02) strcat(dr, "4, "); + if (card->ats[pos] & 0x04) strcat(dr, "8, "); if (strlen(ds) != 0) ds[strlen(ds) - 2] = '\0'; if (strlen(dr) != 0) dr[strlen(dr) - 2] = '\0'; PrintAndLog(" - TA1 : different divisors are%s supported, " "DR: [%s], DS: [%s]", - (card.ats[pos] & 0x80 ? " NOT" : ""), dr, ds); + (card->ats[pos] & 0x80 ? " NOT" : ""), dr, ds); pos++; } - if (tb1) { - uint32_t sfgi = card.ats[pos] & 0x0F; - uint32_t fwi = card.ats[pos] >> 4; - PrintAndLog(" - TB1 : SFGI = %d (SFGT = %s%ld/fc), FWI = %d (FWT = %ld/fc)", - (sfgi), - sfgi ? "" : "(not needed) ", - sfgi ? (1 << 12) << sfgi : 0, - fwi, - (1 << 12) << fwi - ); + if (tb1 && card->ats_len > pos) { + PrintAndLog(" - TB1 : SFGI = %d, FWI = %d", + (card->ats[pos] & 0x08), + (card->ats[pos] & 0x80) >> 4); pos++; } - if (tc1) { + if (tc1 && card->ats_len > pos) { PrintAndLog(" - TC1 : NAD is%s supported, CID is%s supported", - (card.ats[pos] & 0x01) ? "" : " NOT", - (card.ats[pos] & 0x02) ? "" : " NOT"); + (card->ats[pos] & 0x01) ? "" : " NOT", + (card->ats[pos] & 0x02) ? "" : " NOT"); pos++; } - if (card.ats[0] > pos) { + if (card->ats_len > pos) { char *tip = ""; - if (card.ats[0] - pos >= 7) { - if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) { + if (card->ats_len - pos > 7) { + if (memcmp(card->ats + pos, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) { tip = "-> MIFARE Plus X 2K or 4K"; - } else if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) { + } else if (memcmp(card->ats + pos, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) { tip = "-> MIFARE Plus S 2K or 4K"; } } - PrintAndLog(" - HB : %s%s", sprint_hex(card.ats + pos, card.ats[0] - pos), tip); - if (card.ats[pos] == 0xC1) { + PrintAndLog(" - HB : %s%s", sprint_hex(card->ats + pos, card->ats_len - pos - 2), tip); + if (card->ats[pos] == 0xC1) { PrintAndLog(" c1 -> Mifare or (multiple) virtual cards of various type"); PrintAndLog(" %02x -> Length is %d bytes", - card.ats[pos + 1], card.ats[pos + 1]); - switch (card.ats[pos + 2] & 0xf0) { + card->ats[pos + 1], card->ats[pos + 1]); + switch (card->ats[pos + 2] & 0xf0) { case 0x10: PrintAndLog(" 1x -> MIFARE DESFire"); break; @@ -327,7 +284,7 @@ int CmdHF14AReader(const char *Cmd) PrintAndLog(" 2x -> MIFARE Plus"); break; } - switch (card.ats[pos + 2] & 0x0f) { + switch (card->ats[pos + 2] & 0x0f) { case 0x00: PrintAndLog(" x0 -> <1 kByte"); break; @@ -344,7 +301,7 @@ int CmdHF14AReader(const char *Cmd) PrintAndLog(" x0 -> 8 kByte"); break; } - switch (card.ats[pos + 3] & 0xf0) { + switch (card->ats[pos + 3] & 0xf0) { case 0x00: PrintAndLog(" 0x -> Engineering sample"); break; @@ -352,7 +309,7 @@ int CmdHF14AReader(const char *Cmd) PrintAndLog(" 2x -> Released"); break; } - switch (card.ats[pos + 3] & 0x0f) { + switch (card->ats[pos + 3] & 0x0f) { case 0x00: PrintAndLog(" x0 -> Generation 1"); break; @@ -363,7 +320,7 @@ int CmdHF14AReader(const char *Cmd) PrintAndLog(" x2 -> Generation 3"); break; } - switch (card.ats[pos + 4] & 0x0f) { + switch (card->ats[pos + 4] & 0x0f) { case 0x00: PrintAndLog(" x0 -> Only VCSL supported"); break; @@ -377,10 +334,10 @@ int CmdHF14AReader(const char *Cmd) } } } else { - PrintAndLog("proprietary non iso14443-4 card found, RATS not supported"); + PrintAndLog("proprietary non iso14443a-4 card found, RATS not supported"); } - return select_status; + return resp.arg[0]; } // Collect ISO14443 Type A UIDs @@ -402,17 +359,20 @@ int CmdHF14ACUIDs(const char *Cmd) UsbCommand resp; WaitForResponse(CMD_ACK,&resp); - iso14a_card_select_t *card = (iso14a_card_select_t *) resp.d.asBytes; + uint8_t *uid = resp.d.asBytes; + iso14a_card_select_t *card = (iso14a_card_select_t *)(uid + 12); // check if command failed if (resp.arg[0] == 0) { PrintAndLog("Card select failed."); } else { - char uid_string[20]; - for (uint16_t i = 0; i < card->uidlen; i++) { - sprintf(&uid_string[2*i], "%02X", card->uid[i]); + // check if UID is 4 bytes + if ((card->atqa[1] & 0xC0) == 0) { + PrintAndLog("%02X%02X%02X%02X", + *uid, *(uid + 1), *(uid + 2), *(uid + 3)); + } else { + PrintAndLog("UID longer than 4 bytes"); } - PrintAndLog("%s", uid_string); } } PrintAndLog("End: %u", time(NULL)); @@ -466,10 +426,6 @@ int CmdHF14ASim(const char *Cmd) // At lease save the mandatory first part of the UID c.arg[0] = long_uid & 0xffffffff; - - // At lease save the mandatory first part of the UID - c.arg[0] = long_uid & 0xffffffff; - if (c.arg[1] == 0) { PrintAndLog("Emulating ISO/IEC 14443 type A tag with UID %01d %08x %08x",c.arg[0],c.arg[1],c.arg[2]); } @@ -537,19 +493,22 @@ int CmdHF14ACmdRaw(const char *cmd) { uint8_t active=0; uint8_t active_select=0; uint16_t numbits=0; + uint16_t timeout=0; + uint8_t bTimeout=0; char buf[5]=""; int i=0; - uint8_t data[100]; + uint8_t data[USB_CMD_DATA_SIZE]; unsigned int datalen=0, temp; if (strlen(cmd)<2) { - PrintAndLog("Usage: hf 14a raw [-r] [-c] [-p] [-f] [-b] <0A 0B 0C ... hex>"); + PrintAndLog("Usage: hf 14a raw [-r] [-c] [-p] [-f] [-b] [-t] <0A 0B 0C ... hex>"); PrintAndLog(" -r do not read response"); PrintAndLog(" -c calculate and append CRC"); PrintAndLog(" -p leave the signal field ON after receive"); PrintAndLog(" -a active signal field ON without select"); PrintAndLog(" -s active signal field ON with select"); PrintAndLog(" -b number of bits to send. Useful for send partial byte"); + PrintAndLog(" -t timeout"); return 0; } @@ -582,6 +541,14 @@ int CmdHF14ACmdRaw(const char *cmd) { while(cmd[i]!=' ' && cmd[i]!='\0') { i++; } i-=2; break; + case 't': + bTimeout=1; + sscanf(cmd+i+2,"%d",&temp); + timeout = temp & 0xFFFF; + i+=3; + while(cmd[i]!=' ' && cmd[i]!='\0') { i++; } + i+=2; + break; default: PrintAndLog("Invalid option"); return 0; @@ -599,15 +566,19 @@ int CmdHF14ACmdRaw(const char *cmd) { if (strlen(buf)>=2) { sscanf(buf,"%x",&temp); data[datalen]=(uint8_t)(temp & 0xff); - datalen++; *buf=0; + if (++datalen>sizeof(data)){ + if (crc) + PrintAndLog("Buffer is full, we can't add CRC to your data"); + break; + } } continue; } PrintAndLog("Invalid char on input"); return 0; } - if(crc && datalen>0) + if(crc && datalen>0 && datalenMAX_TIMEOUT) { + c.arg[2] = MAX_TIMEOUT; + PrintAndLog("Set timeout to 624 ms. The max we can wait for response"); + } + } if(power) c.arg[0] |= ISO14A_NO_DISCONNECT; if(datalen>0) c.arg[0] |= ISO14A_RAW; - c.arg[1] = datalen; - c.arg[2] = numbits; + // Max buffer is USB_CMD_DATA_SIZE + c.arg[1] = (datalen & 0xFFFF) | (numbits << 16); memcpy(c.d.asBytes,data,datalen); SendCommand(&c); diff --git a/client/cmdhf14b.c b/client/cmdhf14b.c index c42d54c5..25a452e6 100644 --- a/client/cmdhf14b.c +++ b/client/cmdhf14b.c @@ -13,8 +13,7 @@ #include #include #include -#include "iso14443crc.h" -//#include "proxusb.h" +#include "../common/iso14443crc.h" #include "proxmark3.h" #include "data.h" #include "graph.h" diff --git a/client/cmdhf15.c b/client/cmdhf15.c index cc61d289..195560ed 100644 --- a/client/cmdhf15.c +++ b/client/cmdhf15.c @@ -33,7 +33,7 @@ #include "ui.h" #include "cmdparser.h" #include "cmdhf15.h" -#include "iso15693tools.h" +#include "../common/iso15693tools.h" #include "cmdmain.h" #define FrameSOF Iso15693FrameSOF diff --git a/client/cmdhfdes.c b/client/cmdhfdes.c new file mode 100644 index 00000000..1876e5c1 --- /dev/null +++ b/client/cmdhfdes.c @@ -0,0 +1,69 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2012 nuit +// +// 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. +//----------------------------------------------------------------------------- +// High frequency MIFARE DESfire commands +//----------------------------------------------------------------------------- + +#include "cmdhfdes.h" +#include "proxmark3.h" +#include "cmdmain.h" + +static int CmdHelp(const char *Cmd); + +int CmdHFDESReader(const char *Cmd) +{ + UsbCommand c ={CMD_MIFARE_DES_READER, {3, 0x60, 0}}; + SendCommand(&c); + + UsbCommand resp; + WaitForResponseTimeout(CMD_ACK,&resp,2000); + return 0; +} + +int CmdHFDESDbg(const char *Cmd) +{ + int dbgMode = param_get32ex(Cmd, 0, 0, 10); + if (dbgMode > 4) { + PrintAndLog("Max debud mode parameter is 4 \n"); + } + + if (strlen(Cmd) < 1 || !param_getchar(Cmd, 0) || dbgMode > 4) { + PrintAndLog("Usage: hf des dbg "); + PrintAndLog(" 0 - no debug messages"); + PrintAndLog(" 1 - error messages"); + PrintAndLog(" 2 - all messages"); + PrintAndLog(" 4 - extended debug mode"); + return 0; + } + + UsbCommand c = {CMD_MIFARE_SET_DBGMODE, {dbgMode, 0, 0}}; + SendCommand(&c); + + return 0; +} + +static command_t CommandTable[] = +{ + {"help", CmdHelp, 1, "This help"}, + {"dbg", CmdHFDESDbg, 0, "Set default debug mode"}, + {"reader", CmdHFDESReader, 0, "Reader"}, + {NULL, NULL, 0, NULL} +}; + +int CmdHFDES(const char *Cmd) +{ + //flush + WaitForResponseTimeout(CMD_ACK,NULL,100); + CmdsParse(CommandTable, Cmd); + return 0; +} + +int CmdHelp(const char *Cmd) +{ + CmdsHelp(CommandTable); + return 0; +} diff --git a/client/cmdhfdes.h b/client/cmdhfdes.h new file mode 100644 index 00000000..e51797cb --- /dev/null +++ b/client/cmdhfdes.h @@ -0,0 +1,27 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2012 nuit +// +// 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. +//----------------------------------------------------------------------------- +// High frequency MIFARE DESfire commands +//----------------------------------------------------------------------------- + +#ifndef CMDHFDES_H__ +#define CMDHFDES_H__ + +#include +#include +#include +#include +#include "proxmark3.h" +#include "data.h" +#include "ui.h" +#include "cmdparser.h" +#include "common.h" +#include "util.h" +int CmdHFDES(const char *Cmd); +int CmdHFDESReader(const char *Cmd); +int CmdHFDESDbg(const char *Cmd); +#endif diff --git a/client/cmdhfepa.c b/client/cmdhfepa.c index 8a36d6ae..92e61c68 100644 --- a/client/cmdhfepa.c +++ b/client/cmdhfepa.c @@ -13,7 +13,7 @@ #include "proxmark3.h" #include "ui.h" #include "cmdparser.h" -#include "common.h" +#include "../include/common.h" #include "cmdmain.h" #include "sleep.h" #include "cmdhfepa.h" diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c index b8e1e098..e32664f5 100644 --- a/client/cmdhficlass.c +++ b/client/cmdhficlass.c @@ -1,6 +1,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 2010 iZsh , Hagen Fritsch // Copyright (C) 2011 Gerhard de Koning Gans +// Copyright (C) 2014 Midnitesnake & Andy Davies & Martin Holst Swende // // 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 @@ -15,14 +16,19 @@ #include #include "iso14443crc.h" // Can also be used for iClass, using 0xE012 as CRC-type #include "data.h" -//#include "proxusb.h" #include "proxmark3.h" #include "ui.h" #include "cmdparser.h" #include "cmdhficlass.h" -#include "common.h" +#include "../include/common.h" #include "util.h" #include "cmdmain.h" +#include "loclass/des.h" +#include "loclass/cipherutils.h" +#include "loclass/cipher.h" +#include "loclass/ikeys.h" +#include "loclass/elite_crack.h" +#include "loclass/fileutils.h" static int CmdHelp(const char *Cmd); @@ -290,11 +296,6 @@ int CmdHFiClassListOld(const char *Cmd) return 0; } -/*void iso14a_set_timeout(uint32_t timeout) { - UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_SET_TIMEOUT, 0, timeout}}; - SendCommand(&c); -}*/ - int CmdHFiClassSnoop(const char *Cmd) { UsbCommand c = {CMD_SNOOP_ICLASS}; @@ -393,37 +394,255 @@ int CmdHFiClassSim(const char *Cmd) memcpy(c.d.asBytes, CSN, 8); SendCommand(&c); } + return 0; } int CmdHFiClassReader(const char *Cmd) +{ + UsbCommand c = {CMD_READER_ICLASS, {0}}; + SendCommand(&c); + UsbCommand resp; + while(!ukbhit()){ + if (WaitForResponseTimeout(CMD_ACK,&resp,4500)) { + uint8_t isOK = resp.arg[0] & 0xff; + uint8_t * data = resp.d.asBytes; + + PrintAndLog("isOk:%02x", isOK); + + if(isOK > 0) + { + PrintAndLog("CSN: %s",sprint_hex(data,8)); + } + if(isOK >= 1) + { + PrintAndLog("CC: %s",sprint_hex(data+8,8)); + }else{ + PrintAndLog("No CC obtained"); + } + } else { + PrintAndLog("Command execute timeout"); + } + } + + return 0; +} + +int CmdHFiClassReader_Replay(const char *Cmd) { uint8_t readerType = 0; + uint8_t MAC[4]={0x00, 0x00, 0x00, 0x00}; if (strlen(Cmd)<1) { - PrintAndLog("Usage: hf iclass reader "); - PrintAndLog(" sample: hf iclass reader 0"); + PrintAndLog("Usage: hf iclass replay "); + PrintAndLog(" sample: hf iclass replay 00112233"); return 0; } - readerType = param_get8(Cmd, 0); - PrintAndLog("--readertype:%02x", readerType); + if (param_gethex(Cmd, 0, MAC, 8)) { + PrintAndLog("MAC must include 8 HEX symbols"); + return 1; + } + + UsbCommand c = {CMD_READER_ICLASS_REPLAY, {readerType}}; + memcpy(c.d.asBytes, MAC, 4); + SendCommand(&c); + + return 0; +} + +int CmdHFiClassReader_Dump(const char *Cmd) +{ + uint8_t readerType = 0; + uint8_t MAC[4]={0x00,0x00,0x00,0x00}; + uint8_t KEY[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + uint8_t CSN[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + uint8_t CCNR[12]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + //uint8_t CC_temp[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + uint8_t div_key[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + uint8_t keytable[128] = {0}; + int elite = 0; + uint8_t *used_key; + int i; + if (strlen(Cmd)<1) + { + PrintAndLog("Usage: hf iclass dump [e]"); + PrintAndLog(" Key - A 16 byte master key"); + PrintAndLog(" e - If 'e' is specified, the key is interpreted as the 16 byte"); + PrintAndLog(" Custom Key (KCus), which can be obtained via reader-attack"); + PrintAndLog(" See 'hf iclass sim 2'. This key should be on iclass-format"); + PrintAndLog(" sample: hf iclass dump 0011223344556677"); + + + return 0; + } + + if (param_gethex(Cmd, 0, KEY, 16)) { + PrintAndLog("KEY must include 16 HEX symbols"); + return 1; + } + + if (param_getchar(Cmd, 1) == 'e') + { + PrintAndLog("Elite switch on"); + elite = 1; + + //calc h2 + hash2(KEY, keytable); + printarr_human_readable("keytable", keytable, 128); + + } + + + UsbCommand c = {CMD_READER_ICLASS, {0}}; + c.arg[0] = FLAG_ICLASS_READER_ONLY_ONCE; - UsbCommand c = {CMD_READER_ICLASS, {readerType}}; - //memcpy(c.d.asBytes, CSN, 8); SendCommand(&c); + + UsbCommand resp; + + if (WaitForResponseTimeout(CMD_ACK,&resp,4500)) { + uint8_t isOK = resp.arg[0] & 0xff; + uint8_t * data = resp.d.asBytes; + + memcpy(CSN,data,8); + memcpy(CCNR,data+8,8); + + PrintAndLog("isOk:%02x", isOK); + + if(isOK > 0) + { + PrintAndLog("CSN: %s",sprint_hex(CSN,8)); + } + if(isOK > 1) + { + if(elite) + { + uint8_t key_sel[8] = {0}; + uint8_t key_sel_p[8] = { 0 }; + //Get the key index (hash1) + uint8_t key_index[8] = {0}; + + hash1(CSN, key_index); + printvar("hash1", key_index,8); + for(i = 0; i < 8 ; i++) + key_sel[i] = keytable[key_index[i]] & 0xFF; + printvar("k_sel", key_sel,8); + //Permute from iclass format to standard format + permutekey_rev(key_sel,key_sel_p); + used_key = key_sel_p; + }else{ + //Perhaps this should also be permuted to std format? + // Something like the code below? I have no std system + // to test this with /Martin + + //uint8_t key_sel_p[8] = { 0 }; + //permutekey_rev(KEY,key_sel_p); + //used_key = key_sel_p; + + used_key = KEY; + + } + printvar("Used key",used_key,8); + diversifyKey(CSN,used_key, div_key); + printvar("Div key", div_key, 8); + printvar("CC_NR:",CCNR,12); + doMAC(CCNR,12,div_key, MAC); + printvar("MAC", MAC, 4); + + UsbCommand d = {CMD_READER_ICLASS_REPLAY, {readerType}}; + memcpy(d.d.asBytes, MAC, 4); + SendCommand(&d); + + }else{ + PrintAndLog("Failed to obtain CC! Aborting"); + } + } else { + PrintAndLog("Command execute timeout"); + } + + return 0; +} - /*UsbCommand * resp = WaitForResponseTimeout(CMD_ACK, 1500); - if (resp != NULL) { - uint8_t isOK = resp->arg[0] & 0xff; +int CmdHFiClass_iso14443A_write(const char *Cmd) +{ + uint8_t readerType = 0; + uint8_t MAC[4]={0x00,0x00,0x00,0x00}; + uint8_t KEY[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + uint8_t CSN[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + uint8_t CCNR[12]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + uint8_t div_key[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + + uint8_t blockNo=0; + uint8_t bldata[8]={0}; + + if (strlen(Cmd)<3) + { + PrintAndLog("Usage: hf iclass write "); + PrintAndLog(" sample: hf iclass write 0011223344556677 10 AAAAAAAAAAAAAAAA"); + return 0; + } + + if (param_gethex(Cmd, 0, KEY, 16)) + { + PrintAndLog("KEY must include 16 HEX symbols"); + return 1; + } + + blockNo = param_get8(Cmd, 1); + if (blockNo>32) + { + PrintAndLog("Error: Maximum number of blocks is 32 for iClass 2K Cards!"); + return 1; + } + if (param_gethex(Cmd, 2, bldata, 8)) + { + PrintAndLog("Block data must include 8 HEX symbols"); + return 1; + } + + UsbCommand c = {CMD_ICLASS_ISO14443A_WRITE, {0}}; + SendCommand(&c); + UsbCommand resp; + + if (WaitForResponseTimeout(CMD_ACK,&resp,4500)) { + uint8_t isOK = resp.arg[0] & 0xff; + uint8_t * data = resp.d.asBytes; + + memcpy(CSN,data,8); + memcpy(CCNR,data+8,8); + PrintAndLog("DEBUG: %s",sprint_hex(CSN,8)); + PrintAndLog("DEBUG: %s",sprint_hex(CCNR,8)); PrintAndLog("isOk:%02x", isOK); } else { PrintAndLog("Command execute timeout"); - }*/ + } + + diversifyKey(CSN,KEY, div_key); + + PrintAndLog("Div Key: %s",sprint_hex(div_key,8)); + doMAC(CCNR, 12,div_key, MAC); + + UsbCommand c2 = {CMD_ICLASS_ISO14443A_WRITE, {readerType,blockNo}}; + memcpy(c2.d.asBytes, bldata, 8); + memcpy(c2.d.asBytes+8, MAC, 4); + SendCommand(&c2); + + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + uint8_t isOK = resp.arg[0] & 0xff; + uint8_t * data = resp.d.asBytes; + if (isOK) + PrintAndLog("isOk:%02x data:%s", isOK, sprint_hex(data, 4)); + else + PrintAndLog("isOk:%02x", isOK); + } else { + PrintAndLog("Command execute timeout"); + } return 0; } + static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, @@ -431,6 +650,9 @@ static command_t CommandTable[] = {"snoop", CmdHFiClassSnoop, 0, "Eavesdrop iClass communication"}, {"sim", CmdHFiClassSim, 0, "Simulate iClass tag"}, {"reader", CmdHFiClassReader, 0, "Read an iClass tag"}, + {"replay", CmdHFiClassReader_Replay, 0, "Read an iClass tag via Reply Attack"}, + {"dump", CmdHFiClassReader_Dump, 0, "Authenticate and Dump iClass tag"}, + {"write", CmdHFiClass_iso14443A_write, 0, "Authenticate and Write iClass block"}, {NULL, NULL, 0, NULL} }; @@ -443,55 +665,5 @@ int CmdHFiClass(const char *Cmd) int CmdHelp(const char *Cmd) { CmdsHelp(CommandTable); - return 0; -} - -/** - * @brief checks if a file exists - * @param filename - * @return - */ -int fileExists(const char *filename) { - struct stat st; - int result = stat(filename, &st); - return result == 0; -} -/** - * @brief Utility function to save data to a file. This method takes a preferred name, but if that - * file already exists, it tries with another name until it finds something suitable. - * E.g. dumpdata-15.txt - * @param preferredName - * @param suffix the file suffix. Leave out the ".". - * @param data The binary data to write to the file - * @param datalen the length of the data - * @return 0 for ok, 1 for failz - */ -int saveFile(const char *preferredName, const char *suffix, const void* data, size_t datalen) -{ - FILE *f = fopen(preferredName, "wb"); - int size = sizeof(char) * (strlen(preferredName)+strlen(suffix)+5); - char * fileName = malloc(size); - - memset(fileName,0,size); - int num = 1; - sprintf(fileName,"%s.%s", preferredName, suffix); - while(fileExists(fileName)) - { - sprintf(fileName,"%s-%d.%s", preferredName, num, suffix); - num++; - } - /* We should have a valid filename now, e.g. dumpdata-3.bin */ - - /*Opening file for writing in binary mode*/ - FILE *fileHandle=fopen(fileName,"wb"); - if(!f) { - PrintAndLog("Failed to write to file '%s'", fileName); - return 0; - } - fwrite(data, 1, datalen, fileHandle); - fclose(fileHandle); - PrintAndLog("Saved data to '%s'", fileName); - - free(fileName); return 0; } diff --git a/client/cmdhficlass.h b/client/cmdhficlass.h index 98c79e4b..e4048eb1 100644 --- a/client/cmdhficlass.h +++ b/client/cmdhficlass.h @@ -18,6 +18,6 @@ int CmdHFiClassSnoop(const char *Cmd); int CmdHFiClassSim(const char *Cmd); int CmdHFiClassList(const char *Cmd); int CmdHFiClassReader(const char *Cmd); -int saveFile(const char *preferredName, const char *suffix, const void* data, size_t datalen); +int CmdHFiClassReader_Replay(const char *Cmd); #endif diff --git a/client/cmdhflegic.c b/client/cmdhflegic.c index 8366b09b..340fd2b0 100644 --- a/client/cmdhflegic.c +++ b/client/cmdhflegic.c @@ -10,7 +10,6 @@ #include #include -//#include "proxusb.h" #include "proxmark3.h" #include "data.h" #include "ui.h" diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index eb3b4bf1..37c6fe94 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -7,7 +7,7 @@ //----------------------------------------------------------------------------- // High frequency MIFARE commands //----------------------------------------------------------------------------- - +#include "../include/mifare.h" #include "cmdhfmf.h" static int CmdHelp(const char *Cmd); @@ -140,6 +140,7 @@ int CmdHF14AMfWrBl(const char *Cmd) return 0; } +/* dublett finns i CMDHFMFU.C int CmdHF14AMfUWrBl(const char *Cmd) { uint8_t blockNo = 0; @@ -249,8 +250,7 @@ int CmdHF14AMfUWrBl(const char *Cmd) } return 0; } - - +*/ int CmdHF14AMfRdBl(const char *Cmd) { uint8_t blockNo = 0; @@ -299,6 +299,7 @@ int CmdHF14AMfRdBl(const char *Cmd) return 0; } +/* dublett finns i CMDHFMFU.C int CmdHF14AMfURdBl(const char *Cmd) { uint8_t blockNo = 0; @@ -330,8 +331,9 @@ int CmdHF14AMfURdBl(const char *Cmd) return 0; } +*/ - +/* dublett finns i CMDHFMFU.C int CmdHF14AMfURdCard(const char *Cmd) { int i; @@ -422,7 +424,7 @@ int CmdHF14AMfURdCard(const char *Cmd) } return 0; } - +*/ int CmdHF14AMfRdSc(const char *Cmd) { @@ -516,7 +518,16 @@ int CmdHF14AMfDump(const char *Cmd) UsbCommand resp; + int size = GetCardSize(); char cmdp = param_getchar(Cmd, 0); + + PrintAndLog("Got %d",size); + + return; + + if ( size > -1) + cmdp = (char)48+size; + switch (cmdp) { case '0' : numSectors = 5; break; case '1' : @@ -545,8 +556,7 @@ int CmdHF14AMfDump(const char *Cmd) return 1; } - // Read key file - + // Read keys A from file for (sectorNo=0; sectorNo where num is: +// -1 unidentified +// 0 - MINI (320bytes) +// 1 - 1K +// 2 - 2K +// 4 - 4K +int GetCardSize() +{ + UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT, 0, 0}}; + SendCommand(&c); + + UsbCommand resp; + WaitForResponse(CMD_ACK,&resp); + + if(resp.arg[0] == 0) { + PrintAndLog("iso14443a card select failed"); + return -1; + } + + iso14a_card_select_t *card = (iso14a_card_select_t *)resp.d.asBytes; + + PrintAndLog("Trying to detect card size."); + + uint16_t atqa = 0; + uint8_t sak = 0; + atqa = (card->atqa[1] & 0xff) << 8; + atqa += card->atqa[0] & 0xff; + sak = card->sak; + + // https://code.google.com/p/libnfc/source/browse/libnfc/target-subr.c + + PrintAndLog("found ATAQ: %04X SAK: %02X", atqa, sak); + + + // NXP MIFARE Mini 0.3k + if ( (atqa && 0xff0f == 0x0004) && (sak == 0x09) ) return 0; + + // MIFARE Classic 1K + if ( (atqa && 0xff0f == 0x0004) && (sak == 0x08) ) return 1; + + // MIFARE Classik 4K + if ( (atqa && 0xff0f == 0x0002) && (sak == 0x18) ) return 4; + + // SmartMX with MIFARE 1K emulation + if ( (atqa && 0xf0ff == 0x0004) ) return 1; + + // SmartMX with MIFARE 4K emulation + if ( (atqa && 0xf0ff == 0x0002) ) return 4; + + // Infineon MIFARE CLASSIC 1K + if ( (atqa && 0xffff == 0x0004) && (sak == 0x88) ) return 1; + + // MFC 4K emulated by Nokia 6212 Classic + if ( (atqa && 0xffff == 0x0002) && (sak == 0x38) ) return 4; + + // MFC 4K emulated by Nokia 6131 NFC + if ( (atqa && 0xffff == 0x0008) && (sak == 0x38) ) return 4; + + // MIFARE Plus (4 Byte UID or 4 Byte RID) + // MIFARE Plus (7 Byte UID) + if ( + (atqa && 0xffff == 0x0002) || + (atqa && 0xffff == 0x0004) || + (atqa && 0xffff == 0x0042) || + (atqa && 0xffff == 0x0044) + ) + { + switch(sak){ + case 0x08: + case 0x10: + //case 0x20: + return 2; + break; + case 0x11: + case 0x18: + //case 0x20: + return 4; + break; + } + } + + return -1; +} + + + + static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, {"dbg", CmdHF14AMfDbg, 0, "Set default debug mode"}, {"rdbl", CmdHF14AMfRdBl, 0, "Read MIFARE classic block"}, - {"urdbl", CmdHF14AMfURdBl, 0, "Read MIFARE Ultralight block"}, - {"urdcard", CmdHF14AMfURdCard, 0,"Read MIFARE Ultralight Card"}, - {"uwrbl", CmdHF14AMfUWrBl, 0,"Write MIFARE Ultralight block"}, + //{"urdbl", CmdHF14AMfURdBl, 0, "Read MIFARE Ultralight block"}, + //{"urdcard", CmdHF14AMfURdCard, 0,"Read MIFARE Ultralight Card"}, + //{"uwrbl", CmdHF14AMfUWrBl, 0,"Write MIFARE Ultralight block"}, {"rdsc", CmdHF14AMfRdSc, 0, "Read MIFARE classic sector"}, {"dump", CmdHF14AMfDump, 0, "Dump MIFARE classic tag to binary file"}, {"restore", CmdHF14AMfRestore, 0, "Restore MIFARE classic binary file to BLANK tag"}, diff --git a/client/cmdhfmf.h b/client/cmdhfmf.h index 62e856ad..45ba7cb1 100644 --- a/client/cmdhfmf.h +++ b/client/cmdhfmf.h @@ -16,12 +16,11 @@ #include #include #include "proxmark3.h" -#include "iso14443crc.h" +#include "../common/iso14443crc.h" #include "data.h" -//#include "proxusb.h" #include "ui.h" #include "cmdparser.h" -#include "common.h" +#include "../include/common.h" #include "util.h" #include "mifarehost.h" @@ -54,5 +53,5 @@ int CmdHF14AMfCGetBlk(const char* cmd); int CmdHF14AMfCGetSc(const char* cmd); int CmdHF14AMfCLoad(const char* cmd); int CmdHF14AMfCSave(const char* cmd); - +int GetCardSize(); #endif diff --git a/client/cmdhfmfdes.c b/client/cmdhfmfdes.c new file mode 100644 index 00000000..93a972f4 --- /dev/null +++ b/client/cmdhfmfdes.c @@ -0,0 +1,436 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2014 Iceman +// +// 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. +//----------------------------------------------------------------------------- +// High frequency MIFARE Desfire commands +//----------------------------------------------------------------------------- + +#include +#include +#include +#include +#include +#include "cmdmain.h" +#include "proxmark3.h" +#include "../include/common.h" +#include "../include/mifare.h" +#include "../common/iso14443crc.h" +#include "data.h" +#include "ui.h" +#include "cmdparser.h" +#include "util.h" +#include "cmdhfmfdes.h" + + +uint8_t key_zero_data[16] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; +uint8_t key_defa_data[16] = { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f }; +uint8_t key_ones_data[16] = { 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01 }; + + +static int CmdHelp(const char *Cmd); +static void xor(unsigned char * dst, unsigned char * src, size_t len); +static int32_t le24toh (uint8_t data[3]); + + +int CmdHF14ADesWb(const char *Cmd) +{ +/* uint8_t blockNo = 0; + uint8_t keyType = 0; + uint8_t key[6] = {0, 0, 0, 0, 0, 0}; + uint8_t bldata[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + char cmdp = 0x00; + + if (strlen(Cmd)<3) { + PrintAndLog("Usage: hf mf wrbl "); + PrintAndLog(" sample: hf mf wrbl 0 A FFFFFFFFFFFF 000102030405060708090A0B0C0D0E0F"); + return 0; + } + + blockNo = param_get8(Cmd, 0); + cmdp = param_getchar(Cmd, 1); + if (cmdp == 0x00) { + PrintAndLog("Key type must be A or B"); + return 1; + } + if (cmdp != 'A' && cmdp != 'a') keyType = 1; + if (param_gethex(Cmd, 2, key, 12)) { + PrintAndLog("Key must include 12 HEX symbols"); + return 1; + } + if (param_gethex(Cmd, 3, bldata, 32)) { + PrintAndLog("Block data must include 32 HEX symbols"); + return 1; + } + PrintAndLog("--block no:%02x key type:%02x key:%s", blockNo, keyType, sprint_hex(key, 6)); + PrintAndLog("--data: %s", sprint_hex(bldata, 16)); + + UsbCommand c = {CMD_MIFARE_WRITEBL, {blockNo, keyType, 0}}; + memcpy(c.d.asBytes, key, 6); + memcpy(c.d.asBytes + 10, bldata, 16); + SendCommand(&c); + + UsbCommand resp; + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + uint8_t isOK = resp.arg[0] & 0xff; + PrintAndLog("isOk:%02x", isOK); + } else { + PrintAndLog("Command execute timeout"); + } + */ + return 0; +} + +int CmdHF14ADesRb(const char *Cmd) +{ + // uint8_t blockNo = 0; + // uint8_t keyType = 0; + // uint8_t key[6] = {0, 0, 0, 0, 0, 0}; + + // char cmdp = 0x00; + + + // if (strlen(Cmd)<3) { + // PrintAndLog("Usage: hf mf rdbl "); + // PrintAndLog(" sample: hf mf rdbl 0 A FFFFFFFFFFFF "); + // return 0; + // } + + // blockNo = param_get8(Cmd, 0); + // cmdp = param_getchar(Cmd, 1); + // if (cmdp == 0x00) { + // PrintAndLog("Key type must be A or B"); + // return 1; + // } + // if (cmdp != 'A' && cmdp != 'a') keyType = 1; + // if (param_gethex(Cmd, 2, key, 12)) { + // PrintAndLog("Key must include 12 HEX symbols"); + // return 1; + // } + // PrintAndLog("--block no:%02x key type:%02x key:%s ", blockNo, keyType, sprint_hex(key, 6)); + + // UsbCommand c = {CMD_MIFARE_READBL, {blockNo, keyType, 0}}; + // memcpy(c.d.asBytes, key, 6); + // SendCommand(&c); + + // UsbCommand resp; + // if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + // uint8_t isOK = resp.arg[0] & 0xff; + // uint8_t * data = resp.d.asBytes; + + // if (isOK) + // PrintAndLog("isOk:%02x data:%s", isOK, sprint_hex(data, 16)); + // else + // PrintAndLog("isOk:%02x", isOK); + // } else { + // PrintAndLog("Command execute timeout"); + // } + + return 0; +} + +int CmdHF14ADesInfo(const char *Cmd){ + + UsbCommand c = {CMD_MIFARE_DESFIRE_INFO, { 0x00 }}; + + SendCommand(&c); + UsbCommand resp; + + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + uint8_t isOK = resp.arg[0] & 0xff; + PrintAndLog("isOk:%02x", isOK); + } else { + PrintAndLog("Command execute timeout"); + return 0; + } + + PrintAndLog("---Desfire Information---------------------------------------"); + PrintAndLog("-------------------------------------------------------------"); + PrintAndLog(" UID : %s",sprint_hex(resp.d.asBytes, 7)); + PrintAndLog(" Batch number : %s",sprint_hex(resp.d.asBytes+28,5)); + PrintAndLog(" Production date : week %02x, 20%02x",resp.d.asBytes[33], resp.d.asBytes[34]); + PrintAndLog("-------------------------------------------------------------"); + PrintAndLog(" Hardware Information"); + PrintAndLog(" Vendor Id : %s", GetVendorStr(resp.d.asBytes[7])); + PrintAndLog(" Type : 0x%02X",resp.d.asBytes[8]); + PrintAndLog(" Subtype : 0x%02X",resp.d.asBytes[9]); + PrintAndLog(" Version : %d.%d",resp.d.asBytes[10], resp.d.asBytes[11]); + PrintAndLog(" Storage size : %s",GetCardSizeStr(resp.d.asBytes[12])); + PrintAndLog(" Protocol : %s",GetProtocolStr(resp.d.asBytes[13])); + PrintAndLog("-------------------------------------------------------------"); + PrintAndLog(" Software Information"); + PrintAndLog(" Vendor Id : %s",GetVendorStr(resp.d.asBytes[14])); + PrintAndLog(" Type : 0x%02X",resp.d.asBytes[15]); + PrintAndLog(" Subtype : 0x%02X",resp.d.asBytes[16]); + PrintAndLog(" Version : %d.%d",resp.d.asBytes[17], resp.d.asBytes[18]); + PrintAndLog(" storage size : %s", GetCardSizeStr(resp.d.asBytes[19])); + PrintAndLog(" Protocol : %s", GetProtocolStr(resp.d.asBytes[20])); + PrintAndLog("-------------------------------------------------------------"); + + PrintAndLog(" Master Key settings"); + if ( resp.d.asBytes[35] & (1 << 3 ) ) + PrintAndLog(" 0x08 Configuration changeable;"); + else + PrintAndLog(" 0x08 Configuration NOT changeable;"); + + if ( resp.d.asBytes[35] & (1 << 2 ) ) + PrintAndLog(" 0x04 PICC Master Key not required for create / delete;"); + else + PrintAndLog(" 0x04 PICC Master Key required for create / delete;"); + + if ( resp.d.asBytes[35] & (1 << 1 ) ) + PrintAndLog(" 0x02 Free directory list access without PICC Master Key;"); + else + PrintAndLog(" 0x02 Directory list access with PICC Master Key;"); + + if ( resp.d.asBytes[35] & (1 << 0 ) ) + PrintAndLog(" 0x01 Allow changing the Master Key;"); + else + PrintAndLog(" 0x01 Master Key is not changeable anymore;"); + + PrintAndLog(""); + PrintAndLog(" Max number of keys : %d", resp.d.asBytes[36]); + PrintAndLog(" Master key Version : %d (0x%02x)", resp.d.asBytes[37], resp.d.asBytes[37]); + PrintAndLog("-------------------------------------------------------------"); + + uint8_t tmp[3]; + memcpy(tmp, resp.d.asBytes+38,3); + + PrintAndLog(" Free memory on card : %d bytes", le24toh( tmp )); + PrintAndLog("-------------------------------------------------------------"); + /* + Card Master key (CMK) 0x00 on AID = 00 00 00 (card level) + 0x1 + + Application Master Key (AMK) 0x00 on AID != 00 00 00 + Application keys (APK) = 0x01-0x0D + Application free = 0x0E + Application never = 0x0F + + ACCESS RIGHTS: + keys 0,1,2,3 C + keys 4,5,6,7 RW + keys 8,9,10,11 W + keys 12,13,14,15 R + + KEY Versioning. + Se GetKeyVersion (samma nyckel kan ha olika versionen?) + + Session key: + 16 : RndA(byte0-byte3) + RndB(byte0-byte3) + RndA(byte4-byte7) + RndB(byte4-byte7) + 8 : RndA(byte0-byte3) + RndB(byte0-byte3) + + AES 16 : RndA(byte0-byte3) + RndB(byte0-byte3) + RndA(byte12-byte15) + RndB(byte12-byte15) + */ + + PrintAndLog(" RX :%s",sprint_hex(resp.d.asBytes, 40)); + return 1; +} + +char * GetVendorStr( uint8_t id){ + static char buf[30]; + char *retStr = buf; + + if ( id == 0x04 ) + sprintf(retStr, "0x%02X (NXP)",id); + else + sprintf(retStr,"0x%02X (Unknown)",id); + return buf; +} + +/* + The 7 MSBits (= n) code the storage size itself based on 2^n, + the LSBit is set to '0' if the size is exactly 2^n + and set to '1' if the storage size is between 2^n and 2^(n+1). + For this version of DESFire the 7 MSBits are set to 0x0C (2^12 = 4096) and the LSBit is '0'. +*/ +char * GetCardSizeStr( uint8_t fsize ){ + + static char buf[30]; + char *retStr = buf; + + uint16_t usize = 1 << ((fsize >>1) + 1); + uint16_t lsize = 1 << (fsize >>1); + + // is LSB set? + if ( fsize & (1 << 0 ) ) + sprintf(retStr, "0x%02X (%d - %d bytes)",fsize, usize, lsize); + else + sprintf(retStr, "0x%02X (%d bytes)", fsize, lsize); + return buf; +} + +char * GetProtocolStr(uint8_t id){ + + static char buf[30]; + char *retStr = buf; + + if ( id == 0x05) + sprintf(retStr,"0x%02X (ISO 14443-3, 14443-4)", id); + else + sprintf(retStr,"0x%02X", id); + return buf; +} + +int CmdHF14ADesEnumApplications(const char *Cmd){ + return 1; +} + +int CmdHF14ADesNonces(const char *Cmd){ + return 1; +} + +// +// MIAFRE DesFire Authentication +// +#define BUFSIZE 64 +int CmdHF14ADesAuth(const char *Cmd){ + + // NR DESC KEYLENGHT + // ------------------------ + // 1 = DES 8 + // 2 = 3DES 16 + // 3 = 3K 3DES 24 + // 4 = AES 16 + + // AUTHENTICTION MODES: + // 1 Normal + // 2 ISO + // 3 AES + + uint8_t keylength = 8; + //unsigned char testinput[] = { 0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff,0x00}; + unsigned char key[24]; // = { 0x75,0x28,0x78,0x39,0x74,0x93,0xCB,0x70}; + + if (strlen(Cmd)<3) { + PrintAndLog("Usage: hf mfdes auth <1|2|3> <1|2|3|4> "); + PrintAndLog(" AUTH modes 1 = normal, 2 = iso, 3 = aes"); + PrintAndLog(" Crypto: 1 = DES 2 = 3DES 3 = 3K3DES 4 = AES"); + PrintAndLog(" keynumber"); + PrintAndLog(" sample: hf mfdes auth 1 1 0 11223344"); + return 0; + } + uint8_t cmdAuthMode = param_get8(Cmd,0); + uint8_t cmdAuthAlgo = param_get8(Cmd,1); + uint8_t cmdKeyNo = param_get8(Cmd,2); + + switch (cmdAuthMode) + { + case 1: + if ( cmdAuthAlgo != 1 && cmdAuthAlgo != 2) { + PrintAndLog("Crypto algo not valid for the auth mode"); + return 1; + } + break; + case 2: + if ( cmdAuthAlgo != 1 && cmdAuthAlgo != 2 && cmdAuthAlgo != 3) { + PrintAndLog("Crypto algo not valid for the auth mode"); + return 1; + } + break; + case 3: + if ( cmdAuthAlgo != 4) { + PrintAndLog("Crypto algo not valid for the auth mode"); + return 1; + } + break; + default: + PrintAndLog("Wrong Auth mode"); + return 1; + break; + } + + switch (cmdAuthAlgo){ + case 2: + keylength = 16; + PrintAndLog("3DES selected"); + break; + case 3: + keylength = 24; + PrintAndLog("3 key 3DES selected"); + break; + case 4: + keylength = 16; + PrintAndLog("AES selected"); + break; + default: + cmdAuthAlgo = 1; + keylength = 8; + PrintAndLog("DES selected"); + break; + } + + // key + if (param_gethex(Cmd, 3, key, keylength*2)) { + PrintAndLog("Key must include %d HEX symbols", keylength); + return 1; + } + // algo, nyckellängd, + UsbCommand c = {CMD_MIFARE_DESFIRE_AUTH1, { cmdAuthMode, cmdAuthAlgo, cmdKeyNo }}; + + c.d.asBytes[0] = keylength; + memcpy(c.d.asBytes+1, key, keylength); + //memcpy(c.d.asBytes + 30, testinput, keylength); + + SendCommand(&c); + UsbCommand resp; + + if (WaitForResponseTimeout(CMD_ACK,&resp,3000)) { + uint8_t isOK = resp.arg[0] & 0xff; + PrintAndLog("isOk:%02x", isOK); + + } else { + PrintAndLog("Command execute timeout"); + return 0; + } + + uint8_t * data= resp.d.asBytes; + + // PrintAndLog("-------------------------------------------------------------"); + PrintAndLog(" Key :%s",sprint_hex(key, keylength)); + // PrintAndLog(" Plain :%s",sprint_hex(testinput, keylength)); + PrintAndLog(" Encoded :%s",sprint_hex(data, keylength)); + PrintAndLog("-------------------------------------------------------------"); + //PrintAndLog(" Expected :B5 21 9E E8 1A A7 49 9D 21 96 68 7E 13 97 38 56"); + + return 1; +} + + +static void xor(unsigned char * dst, unsigned char * src, size_t len) { + for( ; len > 0; len--,dst++,src++) + *dst ^= *src; +} + +static int32_t le24toh (uint8_t data[3]) { + return (data[2] << 16) | (data[1] << 8) | data[0]; +} + +static command_t CommandTable[] = +{ + {"help", CmdHelp, 1, "This help"}, + {"auth", CmdHF14ADesAuth, 0, "Tries a MIFARE DesFire Authentication"}, + {"rb", CmdHF14ADesRb, 0, "Read MIFARE DesFire block"}, + {"wb", CmdHF14ADesWb, 0, "write MIFARE DesFire block"}, + {"info", CmdHF14ADesInfo, 0, "Get MIFARE DesFire information"}, + {"enum", CmdHF14ADesEnumApplications,0, "Tries enumerate all applications"}, + {"nonce", CmdHF14ADesNonces, 0, " Collect n>0 nonces"}, + {NULL, NULL, 0, NULL} +}; + +int CmdHFMFDes(const char *Cmd) +{ + // flush + WaitForResponseTimeout(CMD_ACK,NULL,100); + CmdsParse(CommandTable, Cmd); + return 0; +} + +int CmdHelp(const char *Cmd) +{ + CmdsHelp(CommandTable); + return 0; +} diff --git a/client/cmdhfmfdes.h b/client/cmdhfmfdes.h new file mode 100644 index 00000000..5a4997e5 --- /dev/null +++ b/client/cmdhfmfdes.h @@ -0,0 +1,20 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2014 Iceman +// +// 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. +//----------------------------------------------------------------------------- +// High frequency MIFARE Desfire commands +//----------------------------------------------------------------------------- + +int CmdHFMFDes(const char *Cmd); +int CmdHF14ADesAuth(const char* cmd); +int CmdHF14ADesRb(const char* cmd); +int CmdHF14ADesWb(const char* cmd); +int CmdHF14ADesInfo(const char *Cmd); +int CmdHF14ADesEnumApplications(const char *Cmd); +int CmdHF14ADesNonces(const char *Cmd); +char * GetCardSizeStr( uint8_t fsize ); +char * GetVendorStr( uint8_t id); +char * GetProtocolStr(uint8_t id); diff --git a/client/cmdhfmfu.c b/client/cmdhfmfu.c new file mode 100644 index 00000000..3b9f2e6d --- /dev/null +++ b/client/cmdhfmfu.c @@ -0,0 +1,1159 @@ +//----------------------------------------------------------------------------- +// Ultralight Code (c) 2013,2014 Midnitesnake & Andy Davies of Pentura +// +// 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. +//----------------------------------------------------------------------------- +// High frequency MIFARE ULTRALIGHT (C) commands +//----------------------------------------------------------------------------- +#include +#include "cmdhfmf.h" + +uint8_t MAX_ULTRA_BLOCKS= 0x0f; +uint8_t MAX_ULTRAC_BLOCKS= 0x2c; +uint8_t key1_blnk_data[16] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; +uint8_t key2_defa_data[16] = { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f }; +uint8_t key3_3des_data[16] = { 0x49,0x45,0x4D,0x4B,0x41,0x45,0x52,0x42,0x21,0x4E,0x41,0x43,0x55,0x4F,0x59,0x46 }; +uint8_t key4_nfc_data[16] = { 0x42,0x52,0x45,0x41,0x4b,0x4d,0x45,0x49,0x46,0x59,0x4f,0x55,0x43,0x41,0x4e,0x21 }; +uint8_t key5_ones_data[16] = { 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01 }; + +static int CmdHelp(const char *Cmd); + +// +// Mifare Ultralight Write Single Block +// +int CmdHF14AMfUWrBl(const char *Cmd){ + uint8_t blockNo = 0; + bool chinese_card=0; + uint8_t bldata[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + UsbCommand resp; + + if (strlen(Cmd)<3) { + PrintAndLog("Usage: hf mfu uwrbl [w]"); + PrintAndLog(" sample: hf mfu uwrbl 0 01020304"); + return 0; + } + blockNo = param_get8(Cmd, 0); + if (blockNo>MAX_ULTRA_BLOCKS){ + PrintAndLog("Error: Maximum number of blocks is 15 for Ultralight Cards!"); + return 1; + } + if (param_gethex(Cmd, 1, bldata, 8)) { + PrintAndLog("Block data must include 8 HEX symbols"); + return 1; + } + if (strchr(Cmd,'w') != 0) { + chinese_card=1; + } + switch(blockNo){ + case 0: + if (!chinese_card){ + PrintAndLog("Access Denied"); + }else{ + PrintAndLog("--specialblock no:%02x", blockNo); + PrintAndLog("--data: %s", sprint_hex(bldata, 4)); + UsbCommand d = {CMD_MIFAREU_WRITEBL, {blockNo}}; + memcpy(d.d.asBytes,bldata, 4); + SendCommand(&d); + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + uint8_t isOK = resp.arg[0] & 0xff; + PrintAndLog("isOk:%02x", isOK); + } else { + PrintAndLog("Command execute timeout"); + } + } + break; + case 1: + if (!chinese_card){ + PrintAndLog("Access Denied"); + }else{ + PrintAndLog("--specialblock no:%02x", blockNo); + PrintAndLog("--data: %s", sprint_hex(bldata, 4)); + UsbCommand d = {CMD_MIFAREU_WRITEBL, {blockNo}}; + memcpy(d.d.asBytes,bldata, 4); + SendCommand(&d); + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + uint8_t isOK = resp.arg[0] & 0xff; + PrintAndLog("isOk:%02x", isOK); + } else { + PrintAndLog("Command execute timeout"); + } + } + break; + case 2: + if (!chinese_card){ + PrintAndLog("Access Denied"); + }else{ + PrintAndLog("--specialblock no:%02x", blockNo); + PrintAndLog("--data: %s", sprint_hex(bldata, 4)); + UsbCommand c = {CMD_MIFAREU_WRITEBL, {blockNo}}; + memcpy(c.d.asBytes, bldata, 4); + SendCommand(&c); + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + uint8_t isOK = resp.arg[0] & 0xff; + PrintAndLog("isOk:%02x", isOK); + } else { + PrintAndLog("Command execute timeout"); + } + } + break; + case 3: + PrintAndLog("--specialblock no:%02x", blockNo); + PrintAndLog("--data: %s", sprint_hex(bldata, 4)); + UsbCommand d = {CMD_MIFAREU_WRITEBL, {blockNo}}; + memcpy(d.d.asBytes,bldata, 4); + SendCommand(&d); + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + uint8_t isOK = resp.arg[0] & 0xff; + PrintAndLog("isOk:%02x", isOK); + } else { + PrintAndLog("Command execute timeout"); + } + break; + default: + PrintAndLog("--block no:%02x", blockNo); + PrintAndLog("--data: %s", sprint_hex(bldata, 4)); + UsbCommand e = {CMD_MIFAREU_WRITEBL, {blockNo}}; + memcpy(e.d.asBytes,bldata, 4); + SendCommand(&e); + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + uint8_t isOK = resp.arg[0] & 0xff; + PrintAndLog("isOk:%02x", isOK); + } else { + PrintAndLog("Command execute timeout"); + } + break; + } + return 0; +} + +// +// Mifare Ultralight Read Single Block +// +int CmdHF14AMfURdBl(const char *Cmd){ + + uint8_t blockNo = 0; + + if (strlen(Cmd)<1) { + PrintAndLog("Usage: hf mfu urdbl "); + PrintAndLog(" sample: hfu mfu urdbl 0"); + return 0; + } + + blockNo = param_get8(Cmd, 0); + // if (blockNo>MAX_ULTRA_BLOCKS){ + // PrintAndLog("Error: Maximum number of blocks is 15 for Ultralight Cards!"); + // return 1; + // } + PrintAndLog("--block no:%02x", (int)blockNo); + UsbCommand c = {CMD_MIFAREU_READBL, {blockNo}}; + SendCommand(&c); + + UsbCommand resp; + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + uint8_t isOK = resp.arg[0] & 0xff; + uint8_t * data = resp.d.asBytes; + + if (isOK) + PrintAndLog("isOk:%02x data:%s", isOK, sprint_hex(data, 4)); + else + PrintAndLog("isOk:%02x", isOK); + } else { + PrintAndLog("Command execute timeout"); + } + return 0; +} + +// +// Mifare Ultralight Read (Dump) Card Contents +// +int CmdHF14AMfURdCard(const char *Cmd){ + int i; + uint8_t BlockNo = 0; + int Pages=16; + uint8_t *lockbytes_t=NULL; + uint8_t lockbytes[2]={0,0}; + bool bit[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + bool dump=false; + uint8_t datatemp[5]={0,0,0,0,0}; + + uint8_t isOK = 0; + uint8_t * data = NULL; + FILE *fout = NULL; + + if (strchr(Cmd,'x') != 0){ + dump=true; + if ((fout = fopen("dump_ultralight_data.bin","wb")) == NULL) { + PrintAndLog("Could not create file name dumpdata.bin"); + return 1; + } + PrintAndLog("Dumping Ultralight Card Data..."); + } + PrintAndLog("Attempting to Read Ultralight... "); + UsbCommand c = {CMD_MIFAREU_READCARD, {BlockNo, Pages}}; + SendCommand(&c); + UsbCommand resp; + + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + isOK = resp.arg[0] & 0xff; + data = resp.d.asBytes; + PrintAndLog("isOk:%02x", isOK); + if (isOK) { + + // UID + memcpy( datatemp, data,3); + memcpy( datatemp+3, data+4, 4); + PrintAndLog(" UID :%s ", sprint_hex(datatemp, 7)); + // BBC + // CT (cascade tag byte) 0x88 xor SN0 xor SN1 xor SN2 + int crc0 = 0x88 ^ data[0] ^ data[1] ^data[2]; + if ( data[3] == crc0 ) { + PrintAndLog(" BCC0 :%02x - Ok", data[3]); + } + else{ + PrintAndLog(" BCC0 :%02x - crc should be %02x", data[3], crc0); + } + + int crc1 = data[4] ^ data[5] ^ data[6] ^data[7]; + if ( data[8] == crc1 ){ + PrintAndLog(" BCC1 :%02x - Ok", data[8]); + } + else{ + PrintAndLog(" BCC1 :%02x - crc should be %02x", data[8], crc1 ); + } + + PrintAndLog(" Internal :%s ", sprint_hex(data + 9, 1)); + + memcpy(datatemp, data+10, 2); + PrintAndLog(" Lock :%s - %s", sprint_hex(datatemp, 2),printBits( 2, &datatemp) ); + + PrintAndLog(" OneTimePad :%s ", sprint_hex(data + 3*4, 4)); + PrintAndLog(""); + + for (i = 0; i < Pages; i++) { + switch(i){ + case 2: + //process lock bytes + lockbytes_t=data+(i*4); + lockbytes[0]=lockbytes_t[2]; + lockbytes[1]=lockbytes_t[3]; + for(int j=0; j<16; j++){ + bit[j]=lockbytes[j/8] & ( 1 <<(7-j%8)); + } + PrintAndLog("Block %02x:%s ", i,sprint_hex(data + i * 4, 4)); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 3: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[4]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 4: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[3]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 5: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[2]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 6: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[1]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 7: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[0]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 8: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[15]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 9: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[14]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 10: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[13]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 11: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[12]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 12: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[11]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 13: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[10]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 14: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[9]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 15: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[8]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + default: + PrintAndLog("Block %02x:%s ", i,sprint_hex(data + i * 4, 4)); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + } + } + } + } else { + PrintAndLog("Command1 execute timeout"); + } + if (dump) fclose(fout); + return 0; +} + +int CmdHF14AMfUDump(const char *Cmd){ + int i; + uint8_t BlockNo = 0; + int Pages=16; + uint8_t *lockbytes_t=NULL; + uint8_t lockbytes[2]={0,0}; + bool bit[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + bool dump=false; + uint8_t datatemp[5]={0,0,0,0,0}; + + uint8_t isOK = 0; + uint8_t * data = NULL; + FILE *fout; + + dump=true; + if ((fout = fopen("dump_ultralight_data.bin","wb")) == NULL) { + PrintAndLog("Could not create file name dumpdata.bin"); + return 1; + } + PrintAndLog("Dumping Ultralight Card Data..."); + + PrintAndLog("Attempting to Read Ultralight... "); + UsbCommand c = {CMD_MIFAREU_READCARD, {BlockNo,Pages}}; + SendCommand(&c); + UsbCommand resp; + + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + isOK = resp.arg[0] & 0xff; + data = resp.d.asBytes; + PrintAndLog("isOk:%02x", isOK); + if (isOK) + for (i = 0; i < Pages; i++) { + switch(i){ + case 2: + //process lock bytes + lockbytes_t=data+(i*4); + lockbytes[0]=lockbytes_t[2]; + lockbytes[1]=lockbytes_t[3]; + for(int j=0; j<16; j++){ + bit[j]=lockbytes[j/8] & ( 1 <<(7-j%8)); + } + PrintAndLog("Block %02x:%s ", i,sprint_hex(data + i * 4, 4)); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 3: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[4]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 4: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[3]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 5: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[2]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 6: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[1]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 7: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[0]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 8: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[15]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 9: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[14]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 10: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[13]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 11: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[12]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 12: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[11]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 13: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[10]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 14: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[9]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 15: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[8]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + default: + PrintAndLog("Block %02x:%s ", i,sprint_hex(data + i * 4, 4)); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + } + } + } else { + PrintAndLog("Command1 execute timeout"); + } + if (dump) fclose(fout); + return 0; +} + +// Needed to Authenticate to Ultralight C tags +void rol (uint8_t *data, const size_t len){ + uint8_t first = data[0]; + for (size_t i = 0; i < len-1; i++) { + data[i] = data[i+1]; + } + data[len-1] = first; +} + +//------------------------------------------------------------------------------- +// Ultralight C Methods +//------------------------------------------------------------------------------- + +// +// Ultralight C Authentication Demo {currently uses hard-coded key} +// +int CmdHF14AMfucAuth(const char *Cmd){ + + uint8_t blockNo = 0, keyNo=0; + uint8_t e_RndB[8]; + uint32_t cuid=0; + unsigned char RndARndB[16]; + uint8_t key[16]; + DES_cblock RndA, RndB; + DES_cblock iv={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + DES_key_schedule ks1,ks2; + DES_cblock key1,key2; + + if (strlen(Cmd)<1) { + PrintAndLog("Usage: hf mfu auth k "); + PrintAndLog(" sample: hf mfu auth k 0"); + return 0; + } + + //Change key to user defined one + if (strchr(Cmd,'k') != 0){ + //choose a key + keyNo = param_get8(Cmd, 1); + switch(keyNo){ + case 0: + memcpy(key,key1_blnk_data,16); + break; + case 1: + memcpy(key,key2_defa_data,16); + break; + case 2: + memcpy(key,key4_nfc_data,16); + break; + case 3: + memcpy(key,key5_ones_data,16); + break; + default: + memcpy(key,key3_3des_data,16); + break; + } + }else{ + memcpy(key,key3_3des_data,16); + } + memcpy(key1,key,8); + memcpy(key2,key+8,8); + DES_set_key((DES_cblock *)key1,&ks1); + DES_set_key((DES_cblock *)key2,&ks2); + + //Auth1 + UsbCommand c = {CMD_MIFAREUC_AUTH1, {blockNo}}; + SendCommand(&c); + UsbCommand resp; + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + uint8_t isOK = resp.arg[0] & 0xff; + cuid = resp.arg[1]; + uint8_t * data= resp.d.asBytes; + + if (isOK){ + PrintAndLog("enc(RndB):%s", sprint_hex(data+1, 8)); + memcpy(e_RndB,data+1,8); + } + } else { + PrintAndLog("Command execute timeout"); + } + + //Do crypto magic + DES_random_key(&RndA); + DES_ede2_cbc_encrypt(e_RndB,RndB,sizeof(e_RndB),&ks1,&ks2,&iv,0); + PrintAndLog(" RndB:%s",sprint_hex(RndB, 8)); + PrintAndLog(" RndA:%s",sprint_hex(RndA, 8)); + rol(RndB,8); + memcpy(RndARndB,RndA,8); + memcpy(RndARndB+8,RndB,8); + PrintAndLog(" RA+B:%s",sprint_hex(RndARndB, 16)); + DES_ede2_cbc_encrypt(RndARndB,RndARndB,sizeof(RndARndB),&ks1,&ks2,&e_RndB,1); + PrintAndLog("enc(RA+B):%s",sprint_hex(RndARndB, 16)); + + //Auth2 + UsbCommand d = {CMD_MIFAREUC_AUTH2, {cuid}}; + memcpy(d.d.asBytes,RndARndB, 16); + SendCommand(&d); + + UsbCommand respb; + if (WaitForResponseTimeout(CMD_ACK,&respb,1500)) { + uint8_t isOK = respb.arg[0] & 0xff; + uint8_t * data2= respb.d.asBytes; + + if (isOK){ + PrintAndLog("enc(RndA'):%s", sprint_hex(data2+1, 8)); + } + + } else { + PrintAndLog("Command execute timeout"); + } + return 1; +} + +// +// Ultralight C Read Single Block +// +int CmdHF14AMfUCRdBl(const char *Cmd) +{ + + uint8_t blockNo = 0; + + if (strlen(Cmd)<1) { + PrintAndLog("Usage: hf mfu ucrdbl "); + PrintAndLog(" sample: hf mfu ucrdbl 0"); + return 0; + } + + blockNo = param_get8(Cmd, 0); + if (blockNo>MAX_ULTRAC_BLOCKS){ + PrintAndLog("Error: Maximum number of readable blocks is 44 for Ultralight Cards!"); + return 1; + } + PrintAndLog("--block no:%02x", (int)blockNo); + + //Read Block + UsbCommand e = {CMD_MIFAREU_READBL, {blockNo}}; + SendCommand(&e); + UsbCommand resp_c; + if (WaitForResponseTimeout(CMD_ACK,&resp_c,1500)) { + uint8_t isOK = resp_c.arg[0] & 0xff; + uint8_t * data = resp_c.d.asBytes; + if (isOK) + PrintAndLog("isOk:%02x data:%s", isOK, sprint_hex(data, 4)); + else + PrintAndLog("isOk:%02x", isOK); + } else { + PrintAndLog("Command execute timeout"); + } + return 0; +} + +// +// Ultralight C Read (or Dump) Card Contents +// +int CmdHF14AMfUCRdCard(const char *Cmd){ + int i; + uint8_t BlockNo = 0; + int Pages=44; + uint8_t *lockbytes_t=NULL; + uint8_t lockbytes[2]={0,0}; + uint8_t *lockbytes_t2=NULL; + uint8_t lockbytes2[2]={0,0}; + bool bit[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + bool bit2[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + bool dump=false; + uint8_t datatemp[5]={0,0,0,0,0}; + + uint8_t isOK = 0; + uint8_t * data = NULL; + FILE *fout = NULL; + + if (strchr(Cmd,'x') != 0){ + dump=true; + if ((fout = fopen("dump_ultralightc_data.bin","wb")) == NULL) { + PrintAndLog("Could not create file name dumpdata.bin"); + return 1; + } + PrintAndLog("Dumping Ultralight C Card Data..."); + } + PrintAndLog("Attempting to Read Ultralight C... "); + UsbCommand c = {CMD_MIFAREUC_READCARD, {BlockNo, Pages}}; + SendCommand(&c); + UsbCommand resp; + + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + isOK = resp.arg[0] & 0xff; + data = resp.d.asBytes; + //Pages=sizeof(data)/sizeof(data[0]); + PrintAndLog("isOk:%02x", isOK); + if (isOK) + for (i = 0; i < Pages; i++) { + switch(i){ + case 2: + //process lock bytes + lockbytes_t=data+(i*4); + lockbytes[0]=lockbytes_t[2]; + lockbytes[1]=lockbytes_t[3]; + for(int j=0; j<16; j++){ + bit[j]=lockbytes[j/8] & ( 1 <<(7-j%8)); + } + //might as well read bottom lockbytes too + lockbytes_t2=data+(40*4); + lockbytes2[0]=lockbytes_t2[2]; + lockbytes2[1]=lockbytes_t2[3]; + for(int j=0; j<16; j++){ + bit2[j]=lockbytes2[j/8] & ( 1 <<(7-j%8)); + } + PrintAndLog("Block %02x:%s ", i,sprint_hex(data + i * 4, 4)); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 3: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[4]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 4: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[3]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 5: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[2]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 6: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[1]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 7: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[0]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 8: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[15]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 9: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[14]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 10: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[13]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 11: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[12]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 12: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[11]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 13: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[10]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 14: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[9]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 15: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[8]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 16: + case 17: + case 18: + case 19: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[6]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 20: + case 21: + case 22: + case 23: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[5]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 24: + case 25: + case 26: + case 27: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[4]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 28: + case 29: + case 30: + case 31: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[2]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 32: + case 33: + case 34: + case 35: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[1]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 36: + case 37: + case 38: + case 39: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[0]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 40: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[12]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 41: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[11]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 42: + //auth0 + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[10]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 43: + //auth1 + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[9]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + default: + PrintAndLog("Block %02x:%s ", i,sprint_hex(data + i * 4, 4)); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + } + } + + } else { + PrintAndLog("Command1 execute timeout"); + } + if (dump) fclose(fout); + return 0; +} + +// +// Ultralight C Dump Card Contents to file +// +int CmdHF14AMfUCDump(const char *Cmd){ + int i; + uint8_t BlockNo = 0; + int Pages=44; + uint8_t *lockbytes_t=NULL; + uint8_t lockbytes[2]={0,0}; + uint8_t *lockbytes_t2=NULL; + uint8_t lockbytes2[2]={0,0}; + bool bit[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + bool bit2[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + bool dump=false; + uint8_t datatemp[5]={0,0,0,0,0}; + + uint8_t isOK = 0; + uint8_t * data = NULL; + FILE *fout; + + dump=true; + if ((fout = fopen("dump_ultralightc_data.bin","wb")) == NULL) { + PrintAndLog("Could not create file name dumpdata.bin"); + return 1; + } + PrintAndLog("Dumping Ultralight C Card Data..."); + PrintAndLog("Attempting to Read Ultralight C... "); + UsbCommand c = {CMD_MIFAREU_READCARD, {BlockNo,Pages}}; + SendCommand(&c); + UsbCommand resp; + + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + isOK = resp.arg[0] & 0xff; + data = resp.d.asBytes; + PrintAndLog("isOk:%02x", isOK); + if (isOK) + for (i = 0; i < Pages; i++) { + switch(i){ + case 2: + //process lock bytes + lockbytes_t=data+(i*4); + lockbytes[0]=lockbytes_t[2]; + lockbytes[1]=lockbytes_t[3]; + for(int j=0; j<16; j++){ + bit[j]=lockbytes[j/8] & ( 1 <<(7-j%8)); + + } + //might as well read bottom lockbytes too + lockbytes_t2=data+(40*4); + lockbytes2[0]=lockbytes_t2[2]; + lockbytes2[1]=lockbytes_t2[3]; + for(int j=0; j<16; j++){ + bit2[j]=lockbytes2[j/8] & ( 1 <<(7-j%8)); + } + + PrintAndLog("Block %02x:%s ", i,sprint_hex(data + i * 4, 4)); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 3: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[4]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 4: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[3]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 5: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[2]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 6: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[1]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 7: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[0]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 8: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[15]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 9: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[14]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 10: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[13]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 11: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[12]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 12: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[11]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 13: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[10]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 14: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[9]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 15: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[8]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 16: + case 17: + case 18: + case 19: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[6]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 20: + case 21: + case 22: + case 23: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[5]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 24: + case 25: + case 26: + case 27: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[4]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 28: + case 29: + case 30: + case 31: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[2]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 32: + case 33: + case 34: + case 35: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[1]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 36: + case 37: + case 38: + case 39: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[0]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 40: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[12]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 41: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[11]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 42: + //auth0 + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[10]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 43: + //auth1 + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[9]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + default: + PrintAndLog("Block %02x:%s ", i,sprint_hex(data + i * 4, 4)); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + } + } + + } else { + PrintAndLog("Command1 execute timeout"); + } + if (dump) fclose(fout); + return 0; +} + +// +// Mifare Ultralight C Write Single Block +// +int CmdHF14AMfUCWrBl(const char *Cmd){ + + uint8_t blockNo = 0; + bool chinese_card=0; + uint8_t bldata[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + UsbCommand resp; + + if (strlen(Cmd)<3) { + PrintAndLog("Usage: hf mfu ucwrbl [w]"); + PrintAndLog(" sample: hf mfu uwrbl 0 01020304"); + return 0; + } + blockNo = param_get8(Cmd, 0); + if (blockNo>(MAX_ULTRAC_BLOCKS+4)){ + PrintAndLog("Error: Maximum number of blocks is 47 for Ultralight Cards!"); + return 1; + } + if (param_gethex(Cmd, 1, bldata, 8)) { + PrintAndLog("Block data must include 8 HEX symbols"); + return 1; + } + if (strchr(Cmd,'w') != 0) { + chinese_card=1; + } + switch(blockNo){ + case 0: + if (!chinese_card){ + PrintAndLog("Access Denied"); + }else{ + PrintAndLog("--specialblock no:%02x", blockNo); + PrintAndLog("--data: %s", sprint_hex(bldata, 4)); + UsbCommand d = {CMD_MIFAREU_WRITEBL, {blockNo}}; + memcpy(d.d.asBytes,bldata, 4); + SendCommand(&d); + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + uint8_t isOK = resp.arg[0] & 0xff; + PrintAndLog("isOk:%02x", isOK); + } else { + PrintAndLog("Command execute timeout"); + } + } + break; + case 1: + if (!chinese_card){ + PrintAndLog("Access Denied"); + }else{ + PrintAndLog("--specialblock no:%02x", blockNo); + PrintAndLog("--data: %s", sprint_hex(bldata, 4)); + UsbCommand d = {CMD_MIFAREU_WRITEBL, {blockNo}}; + memcpy(d.d.asBytes,bldata, 4); + SendCommand(&d); + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + uint8_t isOK = resp.arg[0] & 0xff; + PrintAndLog("isOk:%02x", isOK); + } else { + PrintAndLog("Command execute timeout"); + } + } + break; + case 2: + if (!chinese_card){ + PrintAndLog("Access Denied"); + }else{ + PrintAndLog("--specialblock no:%02x", blockNo); + PrintAndLog("--data: %s", sprint_hex(bldata, 4)); + UsbCommand c = {CMD_MIFAREU_WRITEBL, {blockNo}}; + memcpy(c.d.asBytes, bldata, 4); + SendCommand(&c); + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + uint8_t isOK = resp.arg[0] & 0xff; + PrintAndLog("isOk:%02x", isOK); + } else { + PrintAndLog("Command execute timeout"); + } + } + break; + case 3: + PrintAndLog("--specialblock no:%02x", blockNo); + PrintAndLog("--data: %s", sprint_hex(bldata, 4)); + UsbCommand d = {CMD_MIFAREU_WRITEBL, {blockNo}}; + memcpy(d.d.asBytes,bldata, 4); + SendCommand(&d); + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + uint8_t isOK = resp.arg[0] & 0xff; + PrintAndLog("isOk:%02x", isOK); + } else { + PrintAndLog("Command execute timeout"); + } + break; + default: + PrintAndLog("--block no:%02x", blockNo); + PrintAndLog("--data: %s", sprint_hex(bldata, 4)); + UsbCommand e = {CMD_MIFAREU_WRITEBL, {blockNo}}; + memcpy(e.d.asBytes,bldata, 4); + SendCommand(&e); + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + uint8_t isOK = resp.arg[0] & 0xff; + PrintAndLog("isOk:%02x", isOK); + } else { + PrintAndLog("Command execute timeout"); + } + break; + } + return 0; +} + +//------------------------------------ +// Menu Stuff +//------------------------------------ +static command_t CommandTable[] = +{ + {"help", CmdHelp, 1,"This help"}, + {"dbg", CmdHF14AMfDbg, 0,"Set default debug mode"}, + {"urdbl", CmdHF14AMfURdBl, 0,"Read MIFARE Ultralight block"}, + {"urdcard", CmdHF14AMfURdCard, 0,"Read MIFARE Ultralight Card"}, + {"udump", CmdHF14AMfUDump, 0,"Dump MIFARE Ultralight tag to binary file"}, + {"uwrbl", CmdHF14AMfUWrBl, 0,"Write MIFARE Ultralight block"}, + {"ucrdbl", CmdHF14AMfUCRdBl, 0,"Read MIFARE Ultralight C block"}, + {"ucrdcard",CmdHF14AMfUCRdCard, 0,"Read MIFARE Ultralight C Card"}, + {"ucdump", CmdHF14AMfUCDump, 0,"Dump MIFARE Ultralight C tag to binary file"}, + {"ucwrbl", CmdHF14AMfUCWrBl, 0,"Write MIFARE Ultralight C block"}, + {"auth", CmdHF14AMfucAuth, 0,"Ultralight C Authentication"}, + {NULL, NULL, 0, NULL} +}; + +int CmdHFMFUltra(const char *Cmd){ + // flush + WaitForResponseTimeout(CMD_ACK,NULL,100); + CmdsParse(CommandTable, Cmd); + return 0; +} + +int CmdHelp(const char *Cmd){ + CmdsHelp(CommandTable); + return 0; +} \ No newline at end of file diff --git a/client/cmdhfmfu.h b/client/cmdhfmfu.h new file mode 100644 index 00000000..20f25d1d --- /dev/null +++ b/client/cmdhfmfu.h @@ -0,0 +1,16 @@ +#include "cmdhfmf.h" + +//standard ultralight +int CmdHF14AMfUWrBl(const char *Cmd); +int CmdHF14AMfURdBl(const char *Cmd); +int CmdHF14AMfURdCard(const char *Cmd); +int CmdHF14AMfUDump(const char *Cmd); +//Crypto Cards +int CmdHF14AMfUCRdBl(const char *Cmd); +int CmdHF14AMfUCRdCard(const char *Cmd); +int CmdHF14AMfUCDump(const char *Cmd); +int CmdHF14AMfucAuth(const char *Cmd); +void rol (uint8_t *data, const size_t len); + +//general stuff +int CmdHFMFUltra(const char *Cmd); diff --git a/client/cmdhw.c b/client/cmdhw.c index 4f0f3e38..a526fe86 100644 --- a/client/cmdhw.c +++ b/client/cmdhw.c @@ -13,7 +13,6 @@ #include #include #include "ui.h" -//#include "proxusb.h" #include "proxmark3.h" #include "cmdparser.h" #include "cmdhw.h" diff --git a/client/cmdlf.c b/client/cmdlf.c index 22aa1e05..71d87f16 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -12,7 +12,6 @@ #include #include #include -//#include "proxusb.h" #include "proxmark3.h" #include "data.h" #include "graph.h" diff --git a/client/cmdlfem4x.c b/client/cmdlfem4x.c index a7312d21..be31e1ea 100644 --- a/client/cmdlfem4x.c +++ b/client/cmdlfem4x.c @@ -11,14 +11,18 @@ #include #include #include -//#include "proxusb.h" #include "proxmark3.h" #include "ui.h" #include "graph.h" +#include "cmdmain.h" #include "cmdparser.h" #include "cmddata.h" #include "cmdlf.h" #include "cmdlfem4x.h" +#include "util.h" +#include "data.h" + +char *global_em410xId; static int CmdHelp(const char *Cmd); @@ -139,6 +143,8 @@ retest: PrintAndLog("EM410x Tag ID: %s", id); PrintAndLog("Unique Tag ID: %s", id2); + global_em410xId = id; + /* Stop any loops */ return 1; } @@ -167,8 +173,9 @@ retest: } /* if we've already retested after flipping bits, return */ - if (retested++) + if (retested++){ return 0; + } /* if this didn't work, try flipping bits */ for (i = 0; i < bit2idx; i++) @@ -252,6 +259,7 @@ int CmdEM410xSim(const char *Cmd) int CmdEM410xWatch(const char *Cmd) { int read_h = (*Cmd == 'h'); + //char k; do { CmdLFRead(read_h ? "h" : ""); @@ -264,7 +272,22 @@ int CmdEM410xWatch(const char *Cmd) // Changed by martin, 4000 x 4 = 16000, // see http://www.proxmark.org/forum/viewtopic.php?pid=7235#p7235 CmdSamples("16000"); + } while ( + !CmdEM410xRead("") + ); + return 0; +} + +int CmdEM410xWatchnSpoof(const char *Cmd) +{ + int read_h = (*Cmd == 'h'); + do + { + CmdLFRead(read_h ? "h" : ""); + CmdSamples("16000"); } while ( ! CmdEM410xRead("")); + PrintAndLog("# Replaying : %s",global_em410xId); + CmdEM410xSim(global_em410xId); return 0; } @@ -482,12 +505,12 @@ int CmdEM410xWrite(const char *Cmd) int CmdReadWord(const char *Cmd) { - int Word = 16; //default to invalid word + int Word = -1; //default to invalid word UsbCommand c; sscanf(Cmd, "%d", &Word); - if (Word > 15) { + if ( (Word > 15) | (Word < 0) ) { PrintAndLog("Word must be between 0 and 15"); return 1; } @@ -500,18 +523,37 @@ int CmdReadWord(const char *Cmd) c.arg[1] = Word; c.arg[2] = 0; SendCommand(&c); + WaitForResponse(CMD_ACK, NULL); + + size_t bytelength = 4096; + uint8_t data[bytelength]; + memset(data, 0x00, bytelength); + + GetFromBigBuf(data,bytelength,3560); //3560 -- should be offset.. + WaitForResponseTimeout(CMD_ACK,NULL, 1500); + + for (int j = 0; j < bytelength; j++) { + GraphBuffer[j] = ((int)data[j]) - 128; + } + GraphTraceLen = bytelength; + RepaintGraphWindow(); + + manchester_decode(data, bytelength); + + free(data); + return 0; } int CmdReadWordPWD(const char *Cmd) { - int Word = 16; //default to invalid word + int Word = -1; //default to invalid word int Password = 0xFFFFFFFF; //default to blank password UsbCommand c; sscanf(Cmd, "%d %x", &Word, &Password); - if (Word > 15) { + if ( (Word > 15) | (Word < 0) ) { PrintAndLog("Word must be between 0 and 15"); return 1; } @@ -524,6 +566,24 @@ int CmdReadWordPWD(const char *Cmd) c.arg[1] = Word; c.arg[2] = Password; SendCommand(&c); + WaitForResponse(CMD_ACK, NULL); + + size_t bytelength = 4096; + uint8_t data[bytelength]; + memset(data, 0x00, bytelength); + + GetFromBigBuf(data,bytelength,3560); //3560 -- should be offset.. + WaitForResponseTimeout(CMD_ACK,NULL, 1500); + + for (int j = 0; j < bytelength; j++) { + GraphBuffer[j] = ((int)data[j]) - 128; + } + GraphTraceLen = bytelength; + RepaintGraphWindow(); + + manchester_decode(data, bytelength); + + free(data); return 0; } @@ -581,15 +641,16 @@ int CmdWriteWordPWD(const char *Cmd) static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, - {"em410xread", CmdEM410xRead, 1, "[clock rate] -- Extract ID from EM410x tag"}, - {"em410xsim", CmdEM410xSim, 0, " -- Simulate EM410x tag"}, - {"em410xwatch", CmdEM410xWatch, 0, "['h'] -- Watches for EM410x 125/134 kHz tags (option 'h' for 134)"}, - {"em410xwrite", CmdEM410xWrite, 1, " <'0' T5555> <'1' T55x7> [clock rate] -- Write EM410x UID to T5555(Q5) or T55x7 tag, optionally setting clock rate"}, - {"em4x50read", CmdEM4x50Read, 1, "Extract data from EM4x50 tag"}, - {"readword", CmdReadWord, 1, " -- Read EM4xxx word data"}, - {"readwordPWD", CmdReadWordPWD, 1, " -- Read EM4xxx word data in password mode"}, - {"writeword", CmdWriteWord, 1, " -- Write EM4xxx word data"}, - {"writewordPWD", CmdWriteWordPWD, 1, " -- Write EM4xxx word data in password mode"}, + {"410read", CmdEM410xRead, 1, "[clock rate] -- Extract ID from EM410x tag"}, + {"410sim", CmdEM410xSim, 0, " -- Simulate EM410x tag"}, + {"410watch", CmdEM410xWatch, 0, "['h'] -- Watches for EM410x 125/134 kHz tags (option 'h' for 134)"}, + {"410spoof", CmdEM410xWatchnSpoof, 0, "['h'] --- Watches for EM410x 125/134 kHz tags, and replays them. (option 'h' for 134)" }, + {"410write", CmdEM410xWrite, 1, " <'0' T5555> <'1' T55x7> [clock rate] -- Write EM410x UID to T5555(Q5) or T55x7 tag, optionally setting clock rate"}, + {"4xread", CmdEM4x50Read, 1, "Extract data from EM4x50 tag"}, + {"rd", CmdReadWord, 1, " -- Read EM4xxx word data"}, + {"rdpwd", CmdReadWordPWD, 1, " -- Read EM4xxx word data in password mode "}, + {"wr", CmdWriteWord, 1, " -- Write EM4xxx word data"}, + {"wrpwd", CmdWriteWordPWD, 1, " -- Write EM4xxx word data in password mode"}, {NULL, NULL, 0, NULL} }; diff --git a/client/cmdlfhid.c b/client/cmdlfhid.c index dd413d2e..9dd11f18 100644 --- a/client/cmdlfhid.c +++ b/client/cmdlfhid.c @@ -10,7 +10,6 @@ #include #include -//#include "proxusb.h" #include "proxmark3.h" #include "ui.h" #include "graph.h" diff --git a/client/cmdlfhitag.c b/client/cmdlfhitag.c index af61bd36..038ec887 100644 --- a/client/cmdlfhitag.c +++ b/client/cmdlfhitag.c @@ -12,13 +12,12 @@ #include #include #include "data.h" -//#include "proxusb.h" #include "proxmark3.h" #include "ui.h" #include "cmdparser.h" -#include "common.h" +#include "../include/common.h" #include "util.h" -#include "hitag2.h" +#include "../include/hitag2.h" #include "sleep.h" #include "cmdmain.h" diff --git a/client/cmdlfio.c b/client/cmdlfio.c index a3d79b2b..d7d36bc1 100644 --- a/client/cmdlfio.c +++ b/client/cmdlfio.c @@ -3,7 +3,6 @@ #include #include #include -//#include "proxusb.h" #include "proxmark3.h" #include "data.h" #include "graph.h" diff --git a/client/cmdlfpcf7931.c b/client/cmdlfpcf7931.c index 13917146..0d8fb93d 100644 --- a/client/cmdlfpcf7931.c +++ b/client/cmdlfpcf7931.c @@ -10,7 +10,6 @@ #include #include -//#include "proxusb.h" #include "proxmark3.h" #include "ui.h" #include "graph.h" diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index 9783370c..5a464ddb 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -10,55 +10,88 @@ #include #include #include -//#include "proxusb.h" #include "proxmark3.h" #include "ui.h" #include "graph.h" +#include "cmdmain.h" #include "cmdparser.h" #include "cmddata.h" #include "cmdlf.h" #include "cmdlft55xx.h" +#include "util.h" +#include "data.h" +#define LF_TRACE_BUFF_SIZE 16000 static int CmdHelp(const char *Cmd); int CmdReadBlk(const char *Cmd) { - int Block = 8; //default to invalid block + //default to invalid block + int Block = -1; UsbCommand c; sscanf(Cmd, "%d", &Block); - if (Block > 7) { + if ((Block > 7) | (Block < 0)) { PrintAndLog("Block must be between 0 and 7"); return 1; } - PrintAndLog("Reading block %d", Block); + PrintAndLog(" Reading page 0 block : %d", Block); + // this command fills up BigBuff + // c.cmd = CMD_T55XX_READ_BLOCK; - c.d.asBytes[0] = 0x0; //Normal mode + c.d.asBytes[0] = 0x00; c.arg[0] = 0; c.arg[1] = Block; c.arg[2] = 0; SendCommand(&c); + WaitForResponse(CMD_ACK, NULL); + + uint8_t data[LF_TRACE_BUFF_SIZE]; + memset(data, 0x00, LF_TRACE_BUFF_SIZE); + + GetFromBigBuf(data,LF_TRACE_BUFF_SIZE,3560); //3560 -- should be offset.. + WaitForResponseTimeout(CMD_ACK,NULL, 1500); + + for (int j = 0; j < LF_TRACE_BUFF_SIZE; j++) { + GraphBuffer[j] = ((int)data[j]) - 128; + } + GraphTraceLen = LF_TRACE_BUFF_SIZE; + + // BiDirectional + CmdDirectionalThreshold("70 -60"); + + // Askdemod + Cmdaskdemod("1"); + + uint8_t bits[1000]; + uint8_t * bitstream = bits; + uint8_t len = 0; + len = manchester_decode(data, LF_TRACE_BUFF_SIZE, bitstream); + if ( len > 0 ) + PrintPaddedManchester(bitstream, len, 32); + return 0; } + int CmdReadBlkPWD(const char *Cmd) { - int Block = 8; //default to invalid block + int Block = -1; //default to invalid block int Password = 0xFFFFFFFF; //default to blank Block 7 UsbCommand c; sscanf(Cmd, "%d %x", &Block, &Password); - if (Block > 7) { + if ((Block > 7) | (Block < 0)) { PrintAndLog("Block must be between 0 and 7"); return 1; } - PrintAndLog("Reading block %d with password %08X", Block, Password); + PrintAndLog("Reading page 0 block %d pwd %08X", Block, Password); c.cmd = CMD_T55XX_READ_BLOCK; c.d.asBytes[0] = 0x1; //Password mode @@ -66,9 +99,35 @@ int CmdReadBlkPWD(const char *Cmd) c.arg[1] = Block; c.arg[2] = Password; SendCommand(&c); + WaitForResponse(CMD_ACK, NULL); + + uint8_t data[LF_TRACE_BUFF_SIZE]; + memset(data, 0x00, LF_TRACE_BUFF_SIZE); + + GetFromBigBuf(data,LF_TRACE_BUFF_SIZE,3560); //3560 -- should be offset.. + WaitForResponseTimeout(CMD_ACK,NULL, 1500); + + for (int j = 0; j < LF_TRACE_BUFF_SIZE; j++) { + GraphBuffer[j] = ((int)data[j]) - 128; + } + GraphTraceLen = LF_TRACE_BUFF_SIZE; + + // BiDirectional + CmdDirectionalThreshold("70 -60"); + + // Askdemod + Cmdaskdemod("1"); + + uint8_t bits[1000]; + uint8_t len = 0; + len = manchester_decode(data, LF_TRACE_BUFF_SIZE, bits); + if ( len > 0 ) + PrintPaddedManchester(bits, len, 32); + return 0; } + int CmdWriteBlk(const char *Cmd) { int Block = 8; //default to invalid block @@ -120,11 +179,35 @@ int CmdWriteBlkPWD(const char *Cmd) int CmdReadTrace(const char *Cmd) { - - PrintAndLog("Reading traceability data"); + PrintAndLog(" Reading page 1 - tracedata"); UsbCommand c = {CMD_T55XX_READ_TRACE, {0, 0, 0}}; SendCommand(&c); + WaitForResponse(CMD_ACK, NULL); + + uint8_t data[LF_TRACE_BUFF_SIZE]; + memset(data, 0x00, LF_TRACE_BUFF_SIZE); + + GetFromBigBuf(data,LF_TRACE_BUFF_SIZE,3560); //3560 -- should be offset.. + WaitForResponseTimeout(CMD_ACK,NULL, 1500); + + for (int j = 0; j < LF_TRACE_BUFF_SIZE; j++) { + GraphBuffer[j] = ((int)data[j]) - 128; + } + GraphTraceLen = LF_TRACE_BUFF_SIZE; + + // BiDirectional + CmdDirectionalThreshold("70 -60"); + + // Askdemod + Cmdaskdemod("1"); + + uint8_t bits[512]; + uint8_t len = 0; + len = manchester_decode(data,LF_TRACE_BUFF_SIZE,bits); + if ( len > 0 ) + PrintPaddedManchester(bits, len, 64); + return 0; } diff --git a/client/cmdlfti.c b/client/cmdlfti.c index 26128e2f..cb5fcd79 100644 --- a/client/cmdlfti.c +++ b/client/cmdlfti.c @@ -11,7 +11,6 @@ #include #include #include "crc16.h" -//#include "proxusb.h" #include "proxmark3.h" #include "data.h" #include "ui.h" diff --git a/client/cmdmain.c b/client/cmdmain.c index fa358fac..c56aaa63 100644 --- a/client/cmdmain.c +++ b/client/cmdmain.c @@ -16,7 +16,7 @@ #include "cmdparser.h" #include "proxmark3.h" #include "data.h" -#include "usb_cmd.h" +#include "../include/usb_cmd.h" #include "ui.h" #include "cmdhf.h" #include "cmddata.h" diff --git a/client/cmdmain.h b/client/cmdmain.h index 0cf2b35d..5e4ee73a 100644 --- a/client/cmdmain.h +++ b/client/cmdmain.h @@ -11,7 +11,7 @@ #ifndef CMDMAIN_H__ #define CMDMAIN_H__ -#include "usb_cmd.h" +#include "../include/usb_cmd.h" #include "cmdparser.h" void UsbCommandReceived(UsbCommand *UC); void CommandReceived(char *Cmd); diff --git a/client/data.c b/client/data.c index 51134d48..72acf8a6 100644 --- a/client/data.c +++ b/client/data.c @@ -12,7 +12,6 @@ #include #include "data.h" #include "ui.h" -//#include "proxusb.h" #include "proxmark3.h" #include "cmdmain.h" diff --git a/client/flash.c b/client/flash.c index 3a0a1cda..60c04adc 100644 --- a/client/flash.c +++ b/client/flash.c @@ -13,11 +13,10 @@ #include #include "proxmark3.h" #include "sleep.h" -//#include "proxusb.h" #include "flash.h" #include "elf.h" #include "proxendian.h" -#include "usb_cmd.h" +#include "../include/usb_cmd.h" void SendCommand(UsbCommand* txcmd); void ReceiveCommand(UsbCommand* rxcmd); diff --git a/client/flasher.c b/client/flasher.c index 2a24ba8f..1390d817 100644 --- a/client/flasher.c +++ b/client/flasher.c @@ -13,7 +13,7 @@ #include "proxmark3.h" #include "flash.h" #include "uart.h" -#include "usb_cmd.h" +#include "../include/usb_cmd.h" #ifdef _WIN32 # define unlink(x) diff --git a/client/loclass/cipher.c b/client/loclass/cipher.c new file mode 100644 index 00000000..8b1a523d --- /dev/null +++ b/client/loclass/cipher.c @@ -0,0 +1,255 @@ +/***************************************************************************** + * This file is part of iClassCipher. It is a reconstructon of the cipher engine + * used in iClass, and RFID techology. + * + * The implementation is based on the work performed by + * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and + * Milosch Meriac in the paper "Dismantling IClass". + * + * Copyright (C) 2014 Martin Holst Swende + * + * 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. + * + * This file 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 IClassCipher. If not, see . + ****************************************************************************/ + +#include "cipher.h" +#include "cipherutils.h" +#include +#include +#include +#include +#include +#include +#include "fileutils.h" +uint8_t keytable[] = { 0,0,0,0,0,0,0,0}; + +/** +* Definition 1 (Cipher state). A cipher state of iClass s is an element of F 40/2 +* consisting of the following four components: +* 1. the left register l = (l 0 . . . l 7 ) ∈ F 8/2 ; +* 2. the right register r = (r 0 . . . r 7 ) ∈ F 8/2 ; +* 3. the top register t = (t 0 . . . t 15 ) ∈ F 16/2 . +* 4. the bottom register b = (b 0 . . . b 7 ) ∈ F 8/2 . +**/ +typedef struct { + uint8_t l; + uint8_t r; + uint8_t b; + uint16_t t; +} State; + +/** +* Definition 2. The feedback function for the top register T : F 16/2 → F 2 +* is defined as +* T (x 0 x 1 . . . . . . x 15 ) = x 0 ⊕ x 1 ⊕ x 5 ⊕ x 7 ⊕ x 10 ⊕ x 11 ⊕ x 14 ⊕ x 15 . +**/ +bool T(State state) +{ + bool x0 = state.t & 0x8000; + bool x1 = state.t & 0x4000; + bool x5 = state.t & 0x0400; + bool x7 = state.t & 0x0100; + bool x10 = state.t & 0x0020; + bool x11 = state.t & 0x0010; + bool x14 = state.t & 0x0002; + bool x15 = state.t & 0x0001; + return x0 ^ x1 ^ x5 ^ x7 ^ x10 ^ x11 ^ x14 ^ x15; +} +/** +* Similarly, the feedback function for the bottom register B : F 8/2 → F 2 is defined as +* B(x 0 x 1 . . . x 7 ) = x 1 ⊕ x 2 ⊕ x 3 ⊕ x 7 . +**/ +bool B(State state) +{ + bool x1 = state.b & 0x40; + bool x2 = state.b & 0x20; + bool x3 = state.b & 0x10; + bool x7 = state.b & 0x01; + + return x1 ^ x2 ^ x3 ^ x7; + +} + + +/** +* Definition 3 (Selection function). The selection function select : F 2 × F 2 × +* F 8/2 → F 3/2 is defined as select(x, y, r) = z 0 z 1 z 2 where +* z 0 = (r 0 ∧ r 2 ) ⊕ (r 1 ∧ r 3 ) ⊕ (r 2 ∨ r 4 ) +* z 1 = (r 0 ∨ r 2 ) ⊕ (r 5 ∨ r 7 ) ⊕ r 1 ⊕ r 6 ⊕ x ⊕ y +* z 2 = (r 3 ∧ r 5 ) ⊕ (r 4 ∧ r 6 ) ⊕ r 7 ⊕ x +**/ +uint8_t _select(bool x, bool y, uint8_t r) +{ + bool r0 = r >> 7 & 0x1; + bool r1 = r >> 6 & 0x1; + bool r2 = r >> 5 & 0x1; + bool r3 = r >> 4 & 0x1; + bool r4 = r >> 3 & 0x1; + bool r5 = r >> 2 & 0x1; + bool r6 = r >> 1 & 0x1; + bool r7 = r & 0x1; + + bool z0 = (r0 & r2) ^ (r1 & ~r3) ^ (r2 | r4); + bool z1 = (r0 | r2) ^ ( r5 | r7) ^ r1 ^ r6 ^ x ^ y; + bool z2 = (r3 & ~r5) ^ (r4 & r6 ) ^ r7 ^ x; + + // The three bitz z0.. z1 are packed into a uint8_t: + // 00000ZZZ + //Return value is a uint8_t + uint8_t retval = 0; + retval |= (z0 << 2) & 4; + retval |= (z1 << 1) & 2; + retval |= z2 & 1; + + // Return value 0 <= retval <= 7 + return retval; +} + +/** +* Definition 4 (Successor state). Let s = l, r, t, b be a cipher state, k ∈ (F 82 ) 8 +* be a key and y ∈ F 2 be the input bit. Then, the successor cipher state s ′ = +* l ′ , r ′ , t ′ , b ′ is defined as +* t ′ := (T (t) ⊕ r 0 ⊕ r 4 )t 0 . . . t 14 l ′ := (k [select(T (t),y,r)] ⊕ b ′ ) ⊞ l ⊞ r +* b ′ := (B(b) ⊕ r 7 )b 0 . . . b 6 r ′ := (k [select(T (t),y,r)] ⊕ b ′ ) ⊞ l +* +* @param s - state +* @param k - array containing 8 bytes +**/ +State successor(uint8_t* k, State s, bool y) +{ + bool r0 = s.r >> 7 & 0x1; + bool r4 = s.r >> 3 & 0x1; + bool r7 = s.r & 0x1; + + State successor = {0,0,0,0}; + + successor.t = s.t >> 1; + successor.t |= (T(s) ^ r0 ^ r4) << 15; + + successor.b = s.b >> 1; + successor.b |= (B(s) ^ r7) << 7; + + bool Tt = T(s); + + successor.l = ((k[_select(Tt,y,s.r)] ^ successor.b) + s.l+s.r ) & 0xFF; + successor.r = ((k[_select(Tt,y,s.r)] ^ successor.b) + s.l ) & 0xFF; + + return successor; +} +/** +* We define the successor function suc which takes a key k ∈ (F 82 ) 8 , a state s and +* an input y ∈ F 2 and outputs the successor state s ′ . We overload the function suc +* to multiple bit input x ∈ F n 2 which we define as +* @param k - array containing 8 bytes +**/ +State suc(uint8_t* k,State s, BitstreamIn *bitstream) +{ + if(bitsLeft(bitstream) == 0) + { + return s; + } + bool lastbit = tailBit(bitstream); + return successor(k,suc(k,s,bitstream), lastbit); +} + +/** +* Definition 5 (Output). Define the function output which takes an internal +* state s =< l, r, t, b > and returns the bit r 5 . We also define the function output +* on multiple bits input which takes a key k, a state s and an input x ∈ F n 2 as +* output(k, s, Ç«) = Ç« +* output(k, s, x 0 . . . x n ) = output(s) · output(k, s ′ , x 1 . . . x n ) +* where s ′ = suc(k, s, x 0 ). +**/ +void output(uint8_t* k,State s, BitstreamIn* in, BitstreamOut* out) +{ + if(bitsLeft(in) == 0) + { + return; + } + pushBit(out,(s.r >> 2) & 1); + //Remove first bit + uint8_t x0 = headBit(in); + State ss = successor(k,s,x0); + output(k,ss,in, out); +} + +/** +* Definition 6 (Initial state). Define the function init which takes as input a +* key k ∈ (F 82 ) 8 and outputs the initial cipher state s =< l, r, t, b > +**/ + +State init(uint8_t* k) +{ + State s = { + ((k[0] ^ 0x4c) + 0xEC) & 0xFF,// l + ((k[0] ^ 0x4c) + 0x21) & 0xFF,// r + 0x4c, // b + 0xE012 // t + }; + return s; +} +void MAC(uint8_t* k, BitstreamIn input, BitstreamOut out) +{ + uint8_t zeroes_32[] = {0,0,0,0}; + BitstreamIn input_32_zeroes = {zeroes_32,sizeof(zeroes_32)*8,0}; + State initState = suc(k,init(k),&input); + output(k,initState,&input_32_zeroes,&out); +} + +void doMAC(uint8_t *cc_nr_p, int length, uint8_t *div_key_p, uint8_t mac[4]) +{ + uint8_t *cc_nr; + uint8_t div_key[8]; + cc_nr=(uint8_t*)malloc(length+1); + memcpy(cc_nr,cc_nr_p,length); + memcpy(div_key,div_key_p,8); + + reverse_arraybytes(cc_nr,length); + BitstreamIn bitstream = {cc_nr,length * 8,0}; + uint8_t dest []= {0,0,0,0,0,0,0,0}; + BitstreamOut out = { dest, sizeof(dest)*8, 0 }; + MAC(div_key,bitstream, out); + //The output MAC must also be reversed + reverse_arraybytes(dest, sizeof(dest)); + memcpy(mac,dest,4); + //printf("Calculated_MAC\t%02x%02x%02x%02x\n", dest[0],dest[1],dest[2],dest[3]); + free(cc_nr); + return; +} + +int testMAC() +{ + prnlog("[+] Testing MAC calculation..."); + + //From the "dismantling.IClass" paper: + uint8_t cc_nr[] = {0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0,0,0,0}; + //From the paper + uint8_t div_key[8] = {0xE0,0x33,0xCA,0x41,0x9A,0xEE,0x43,0xF9}; + uint8_t correct_MAC[4] = {0x1d,0x49,0xC9,0xDA}; + + uint8_t calculated_mac[4] = {0}; + doMAC(cc_nr, 12,div_key, calculated_mac); + + if(memcmp(calculated_mac, correct_MAC,4) == 0) + { + prnlog("[+] MAC calculation OK!"); + + }else + { + prnlog("[+] FAILED: MAC calculation failed:"); + printarr(" Calculated_MAC", calculated_mac, 4); + printarr(" Correct_MAC ", correct_MAC, 4); + return 1; +} + + return 0; +} diff --git a/client/loclass/cipher.h b/client/loclass/cipher.h new file mode 100644 index 00000000..4bfbe0b7 --- /dev/null +++ b/client/loclass/cipher.h @@ -0,0 +1,31 @@ +/***************************************************************************** + * This file is part of iClassCipher. It is a reconstructon of the cipher engine + * used in iClass, and RFID techology. + * + * The implementation is based on the work performed by + * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and + * Milosch Meriac in the paper "Dismantling IClass". + * + * Copyright (C) 2014 Martin Holst Swende + * + * 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. + * + * This file 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 IClassCipher. If not, see . + ****************************************************************************/ + +#ifndef CIPHER_H +#define CIPHER_H +#include + +void doMAC(uint8_t *cc_nr_p, int length, uint8_t *div_key_p, uint8_t mac[4]); +int testMAC(); + +#endif // CIPHER_H diff --git a/client/loclass/cipherutils.c b/client/loclass/cipherutils.c new file mode 100644 index 00000000..1e08cf10 --- /dev/null +++ b/client/loclass/cipherutils.c @@ -0,0 +1,273 @@ +/***************************************************************************** + * This file is part of iClassCipher. It is a reconstructon of the cipher engine + * used in iClass, and RFID techology. + * + * The implementation is based on the work performed by + * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and + * Milosch Meriac in the paper "Dismantling IClass". + * + * Copyright (C) 2014 Martin Holst Swende + * + * 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. + * + * This file 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 IClassCipher. If not, see . + ****************************************************************************/ + +#include +#include +#include +#include "fileutils.h" +#include "cipherutils.h" +/** + * + * @brief Return and remove the first bit (x0) in the stream : + * @param stream + * @return + */ +bool headBit( BitstreamIn *stream) +{ + int bytepos = stream->position >> 3; // divide by 8 + int bitpos = (stream->position++) & 7; // mask out 00000111 + return (*(stream->buffer + bytepos) >> (7-bitpos)) & 1; +} +/** + * @brief Return and remove the last bit (xn) in the stream: + * @param stream + * @return + */ +bool tailBit( BitstreamIn *stream) +{ + int bitpos = stream->numbits -1 - (stream->position++); + + int bytepos= bitpos >> 3; + bitpos &= 7; + return (*(stream->buffer + bytepos) >> (7-bitpos)) & 1; +} +/** + * @brief Pushes bit onto the stream + * @param stream + * @param bit + */ +void pushBit( BitstreamOut* stream, bool bit) +{ + int bytepos = stream->position >> 3; // divide by 8 + int bitpos = stream->position & 7; + *(stream->buffer+bytepos) |= (bit & 1) << (7 - bitpos); + stream->position++; + stream->numbits++; +} + +/** + * @brief Pushes the lower six bits onto the stream + * as b0 b1 b2 b3 b4 b5 b6 + * @param stream + * @param bits + */ +void push6bits( BitstreamOut* stream, uint8_t bits) +{ + pushBit(stream, bits & 0x20); + pushBit(stream, bits & 0x10); + pushBit(stream, bits & 0x08); + pushBit(stream, bits & 0x04); + pushBit(stream, bits & 0x02); + pushBit(stream, bits & 0x01); +} + +/** + * @brief bitsLeft + * @param stream + * @return number of bits left in stream + */ +int bitsLeft( BitstreamIn *stream) +{ + return stream->numbits - stream->position; +} +/** + * @brief numBits + * @param stream + * @return Number of bits stored in stream + */ +int numBits(BitstreamOut *stream) +{ + return stream->numbits; +} + +void x_num_to_bytes(uint64_t n, size_t len, uint8_t* dest) +{ + while (len--) { + dest[len] = (uint8_t) n; + n >>= 8; + } +} + +uint64_t x_bytes_to_num(uint8_t* src, size_t len) +{ + uint64_t num = 0; + while (len--) + { + num = (num << 8) | (*src); + src++; + } + return num; +} +uint8_t reversebytes(uint8_t b) { + b = (b & 0xF0) >> 4 | (b & 0x0F) << 4; + b = (b & 0xCC) >> 2 | (b & 0x33) << 2; + b = (b & 0xAA) >> 1 | (b & 0x55) << 1; + return b; +} +void reverse_arraybytes(uint8_t* arr, size_t len) +{ + uint8_t i; + for( i =0; i< len ; i++) + { + arr[i] = reversebytes(arr[i]); + } +} +void reverse_arraycopy(uint8_t* arr, uint8_t* dest, size_t len) +{ + uint8_t i; + for( i =0; i< len ; i++) + { + dest[i] = reversebytes(arr[i]); + } +} + +void printarr(char * name, uint8_t* arr, int len) +{ + int cx; + size_t outsize = 40+strlen(name)+len*5; + char* output = malloc(outsize); + memset(output, 0,outsize); + + int i ; + cx = snprintf(output,outsize, "uint8_t %s[] = {", name); + for(i =0 ; i< len ; i++) + { + cx += snprintf(output+cx,outsize-cx,"0x%02x,",*(arr+i));//5 bytes per byte + } + cx += snprintf(output+cx,outsize-cx,"};"); + prnlog(output); +} + +void printvar(char * name, uint8_t* arr, int len) +{ + int cx; + size_t outsize = 40+strlen(name)+len*2; + char* output = malloc(outsize); + memset(output, 0,outsize); + + int i ; + cx = snprintf(output,outsize,"%s = ", name); + for(i =0 ; i< len ; i++) + { + cx += snprintf(output+cx,outsize-cx,"%02x",*(arr+i));//2 bytes per byte + } + + prnlog(output); +} + +void printarr_human_readable(char * title, uint8_t* arr, int len) +{ + int cx; + size_t outsize = 100+strlen(title)+len*4; + char* output = malloc(outsize); + memset(output, 0,outsize); + + + int i; + cx = snprintf(output,outsize, "\n\t%s\n", title); + for(i =0 ; i< len ; i++) + { + if(i % 16 == 0) + cx += snprintf(output+cx,outsize-cx,"\n%02x| ", i ); + cx += snprintf(output+cx,outsize-cx, "%02x ",*(arr+i)); + } + prnlog(output); +} + +//----------------------------- +// Code for testing below +//----------------------------- + + +int testBitStream() +{ + uint8_t input [] = {0xDE,0xAD,0xBE,0xEF,0xDE,0xAD,0xBE,0xEF}; + uint8_t output [] = {0,0,0,0,0,0,0,0}; + BitstreamIn in = { input, sizeof(input) * 8,0}; + BitstreamOut out ={ output, 0,0} + ; + while(bitsLeft(&in) > 0) + { + pushBit(&out, headBit(&in)); + //printf("Bits left: %d\n", bitsLeft(&in)); + //printf("Bits out: %d\n", numBits(&out)); + } + if(memcmp(input, output, sizeof(input)) == 0) + { + prnlog(" Bitstream test 1 ok"); + }else + { + prnlog(" Bitstream test 1 failed"); + uint8_t i; + for(i = 0 ; i < sizeof(input) ; i++) + { + prnlog(" IN %02x, OUT %02x", input[i], output[i]); + } + return 1; + } + return 0; +} + +int testReversedBitstream() +{ + uint8_t input [] = {0xDE,0xAD,0xBE,0xEF,0xDE,0xAD,0xBE,0xEF}; + uint8_t reverse [] = {0,0,0,0,0,0,0,0}; + uint8_t output [] = {0,0,0,0,0,0,0,0}; + BitstreamIn in = { input, sizeof(input) * 8,0}; + BitstreamOut out ={ output, 0,0}; + BitstreamIn reversed_in ={ reverse, sizeof(input)*8,0}; + BitstreamOut reversed_out ={ reverse,0 ,0}; + + while(bitsLeft(&in) > 0) + { + pushBit(&reversed_out, tailBit(&in)); + } + while(bitsLeft(&reversed_in) > 0) + { + pushBit(&out, tailBit(&reversed_in)); + } + if(memcmp(input, output, sizeof(input)) == 0) + { + prnlog(" Bitstream test 2 ok"); + }else + { + prnlog(" Bitstream test 2 failed"); + uint8_t i; + for(i = 0 ; i < sizeof(input) ; i++) + { + prnlog(" IN %02x, MIDDLE: %02x, OUT %02x", input[i],reverse[i], output[i]); + } + return 1; + } + return 0; +} + + +int testCipherUtils(void) +{ + prnlog("[+] Testing some internals..."); + int retval = 0; + retval |= testBitStream(); + retval |= testReversedBitstream(); + return retval; +} diff --git a/client/loclass/cipherutils.h b/client/loclass/cipherutils.h new file mode 100644 index 00000000..acf96115 --- /dev/null +++ b/client/loclass/cipherutils.h @@ -0,0 +1,59 @@ +/***************************************************************************** + * This file is part of iClassCipher. It is a reconstructon of the cipher engine + * used in iClass, and RFID techology. + * + * The implementation is based on the work performed by + * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and + * Milosch Meriac in the paper "Dismantling IClass". + * + * Copyright (C) 2014 Martin Holst Swende + * + * 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. + * + * This file 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 IClassCipher. If not, see . + ****************************************************************************/ + +#ifndef CIPHERUTILS_H +#define CIPHERUTILS_H +#include +#include +#include + +typedef struct { + uint8_t * buffer; + uint8_t numbits; + uint8_t position; +} BitstreamIn; + +typedef struct { + uint8_t * buffer; + uint8_t numbits; + uint8_t position; +}BitstreamOut; + +bool headBit( BitstreamIn *stream); +bool tailBit( BitstreamIn *stream); +void pushBit( BitstreamOut *stream, bool bit); +int bitsLeft( BitstreamIn *stream); + +int testCipherUtils(void); +int testMAC(); +void push6bits( BitstreamOut* stream, uint8_t bits); +void EncryptDES(bool key[56], bool outBlk[64], bool inBlk[64], int verbose) ; +void x_num_to_bytes(uint64_t n, size_t len, uint8_t* dest); +uint64_t x_bytes_to_num(uint8_t* src, size_t len); +uint8_t reversebytes(uint8_t b); +void reverse_arraybytes(uint8_t* arr, size_t len); +void reverse_arraycopy(uint8_t* arr, uint8_t* dest, size_t len); +void printarr(char * name, uint8_t* arr, int len); +void printvar(char * name, uint8_t* arr, int len); +void printarr_human_readable(char * title, uint8_t* arr, int len); +#endif // CIPHERUTILS_H diff --git a/client/loclass/des.c b/client/loclass/des.c new file mode 100644 index 00000000..746752d7 --- /dev/null +++ b/client/loclass/des.c @@ -0,0 +1,1014 @@ +/* + * FIPS-46-3 compliant Triple-DES implementation + * + * Copyright (C) 2006-2014, 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. + */ +/* + * DES, on which TDES is based, was originally designed by Horst Feistel + * at IBM in 1974, and was adopted as a standard by NIST (formerly NBS). + * + * http://csrc.nist.gov/publications/fips/fips46-3/fips46-3.pdf + */ + +//#include "polarssl/config.h" +#define POLARSSL_DES_C + +#if defined(POLARSSL_DES_C) + +#include "des.h" + +#if defined(POLARSSL_PLATFORM_C) +#include "polarssl/platform.h" +#else +#define polarssl_printf printf +#endif + +#if !defined(POLARSSL_DES_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 + +/* + * Expanded DES S-boxes + */ +static const uint32_t SB1[64] = +{ + 0x01010400, 0x00000000, 0x00010000, 0x01010404, + 0x01010004, 0x00010404, 0x00000004, 0x00010000, + 0x00000400, 0x01010400, 0x01010404, 0x00000400, + 0x01000404, 0x01010004, 0x01000000, 0x00000004, + 0x00000404, 0x01000400, 0x01000400, 0x00010400, + 0x00010400, 0x01010000, 0x01010000, 0x01000404, + 0x00010004, 0x01000004, 0x01000004, 0x00010004, + 0x00000000, 0x00000404, 0x00010404, 0x01000000, + 0x00010000, 0x01010404, 0x00000004, 0x01010000, + 0x01010400, 0x01000000, 0x01000000, 0x00000400, + 0x01010004, 0x00010000, 0x00010400, 0x01000004, + 0x00000400, 0x00000004, 0x01000404, 0x00010404, + 0x01010404, 0x00010004, 0x01010000, 0x01000404, + 0x01000004, 0x00000404, 0x00010404, 0x01010400, + 0x00000404, 0x01000400, 0x01000400, 0x00000000, + 0x00010004, 0x00010400, 0x00000000, 0x01010004 +}; + +static const uint32_t SB2[64] = +{ + 0x80108020, 0x80008000, 0x00008000, 0x00108020, + 0x00100000, 0x00000020, 0x80100020, 0x80008020, + 0x80000020, 0x80108020, 0x80108000, 0x80000000, + 0x80008000, 0x00100000, 0x00000020, 0x80100020, + 0x00108000, 0x00100020, 0x80008020, 0x00000000, + 0x80000000, 0x00008000, 0x00108020, 0x80100000, + 0x00100020, 0x80000020, 0x00000000, 0x00108000, + 0x00008020, 0x80108000, 0x80100000, 0x00008020, + 0x00000000, 0x00108020, 0x80100020, 0x00100000, + 0x80008020, 0x80100000, 0x80108000, 0x00008000, + 0x80100000, 0x80008000, 0x00000020, 0x80108020, + 0x00108020, 0x00000020, 0x00008000, 0x80000000, + 0x00008020, 0x80108000, 0x00100000, 0x80000020, + 0x00100020, 0x80008020, 0x80000020, 0x00100020, + 0x00108000, 0x00000000, 0x80008000, 0x00008020, + 0x80000000, 0x80100020, 0x80108020, 0x00108000 +}; + +static const uint32_t SB3[64] = +{ + 0x00000208, 0x08020200, 0x00000000, 0x08020008, + 0x08000200, 0x00000000, 0x00020208, 0x08000200, + 0x00020008, 0x08000008, 0x08000008, 0x00020000, + 0x08020208, 0x00020008, 0x08020000, 0x00000208, + 0x08000000, 0x00000008, 0x08020200, 0x00000200, + 0x00020200, 0x08020000, 0x08020008, 0x00020208, + 0x08000208, 0x00020200, 0x00020000, 0x08000208, + 0x00000008, 0x08020208, 0x00000200, 0x08000000, + 0x08020200, 0x08000000, 0x00020008, 0x00000208, + 0x00020000, 0x08020200, 0x08000200, 0x00000000, + 0x00000200, 0x00020008, 0x08020208, 0x08000200, + 0x08000008, 0x00000200, 0x00000000, 0x08020008, + 0x08000208, 0x00020000, 0x08000000, 0x08020208, + 0x00000008, 0x00020208, 0x00020200, 0x08000008, + 0x08020000, 0x08000208, 0x00000208, 0x08020000, + 0x00020208, 0x00000008, 0x08020008, 0x00020200 +}; + +static const uint32_t SB4[64] = +{ + 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802080, 0x00800081, 0x00800001, 0x00002001, + 0x00000000, 0x00802000, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00800080, 0x00800001, + 0x00000001, 0x00002000, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002001, 0x00002080, + 0x00800081, 0x00000001, 0x00002080, 0x00800080, + 0x00002000, 0x00802080, 0x00802081, 0x00000081, + 0x00800080, 0x00800001, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00000000, 0x00802000, + 0x00002080, 0x00800080, 0x00800081, 0x00000001, + 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802081, 0x00000081, 0x00000001, 0x00002000, + 0x00800001, 0x00002001, 0x00802080, 0x00800081, + 0x00002001, 0x00002080, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002000, 0x00802080 +}; + +static const uint32_t SB5[64] = +{ + 0x00000100, 0x02080100, 0x02080000, 0x42000100, + 0x00080000, 0x00000100, 0x40000000, 0x02080000, + 0x40080100, 0x00080000, 0x02000100, 0x40080100, + 0x42000100, 0x42080000, 0x00080100, 0x40000000, + 0x02000000, 0x40080000, 0x40080000, 0x00000000, + 0x40000100, 0x42080100, 0x42080100, 0x02000100, + 0x42080000, 0x40000100, 0x00000000, 0x42000000, + 0x02080100, 0x02000000, 0x42000000, 0x00080100, + 0x00080000, 0x42000100, 0x00000100, 0x02000000, + 0x40000000, 0x02080000, 0x42000100, 0x40080100, + 0x02000100, 0x40000000, 0x42080000, 0x02080100, + 0x40080100, 0x00000100, 0x02000000, 0x42080000, + 0x42080100, 0x00080100, 0x42000000, 0x42080100, + 0x02080000, 0x00000000, 0x40080000, 0x42000000, + 0x00080100, 0x02000100, 0x40000100, 0x00080000, + 0x00000000, 0x40080000, 0x02080100, 0x40000100 +}; + +static const uint32_t SB6[64] = +{ + 0x20000010, 0x20400000, 0x00004000, 0x20404010, + 0x20400000, 0x00000010, 0x20404010, 0x00400000, + 0x20004000, 0x00404010, 0x00400000, 0x20000010, + 0x00400010, 0x20004000, 0x20000000, 0x00004010, + 0x00000000, 0x00400010, 0x20004010, 0x00004000, + 0x00404000, 0x20004010, 0x00000010, 0x20400010, + 0x20400010, 0x00000000, 0x00404010, 0x20404000, + 0x00004010, 0x00404000, 0x20404000, 0x20000000, + 0x20004000, 0x00000010, 0x20400010, 0x00404000, + 0x20404010, 0x00400000, 0x00004010, 0x20000010, + 0x00400000, 0x20004000, 0x20000000, 0x00004010, + 0x20000010, 0x20404010, 0x00404000, 0x20400000, + 0x00404010, 0x20404000, 0x00000000, 0x20400010, + 0x00000010, 0x00004000, 0x20400000, 0x00404010, + 0x00004000, 0x00400010, 0x20004010, 0x00000000, + 0x20404000, 0x20000000, 0x00400010, 0x20004010 +}; + +static const uint32_t SB7[64] = +{ + 0x00200000, 0x04200002, 0x04000802, 0x00000000, + 0x00000800, 0x04000802, 0x00200802, 0x04200800, + 0x04200802, 0x00200000, 0x00000000, 0x04000002, + 0x00000002, 0x04000000, 0x04200002, 0x00000802, + 0x04000800, 0x00200802, 0x00200002, 0x04000800, + 0x04000002, 0x04200000, 0x04200800, 0x00200002, + 0x04200000, 0x00000800, 0x00000802, 0x04200802, + 0x00200800, 0x00000002, 0x04000000, 0x00200800, + 0x04000000, 0x00200800, 0x00200000, 0x04000802, + 0x04000802, 0x04200002, 0x04200002, 0x00000002, + 0x00200002, 0x04000000, 0x04000800, 0x00200000, + 0x04200800, 0x00000802, 0x00200802, 0x04200800, + 0x00000802, 0x04000002, 0x04200802, 0x04200000, + 0x00200800, 0x00000000, 0x00000002, 0x04200802, + 0x00000000, 0x00200802, 0x04200000, 0x00000800, + 0x04000002, 0x04000800, 0x00000800, 0x00200002 +}; + +static const uint32_t SB8[64] = +{ + 0x10001040, 0x00001000, 0x00040000, 0x10041040, + 0x10000000, 0x10001040, 0x00000040, 0x10000000, + 0x00040040, 0x10040000, 0x10041040, 0x00041000, + 0x10041000, 0x00041040, 0x00001000, 0x00000040, + 0x10040000, 0x10000040, 0x10001000, 0x00001040, + 0x00041000, 0x00040040, 0x10040040, 0x10041000, + 0x00001040, 0x00000000, 0x00000000, 0x10040040, + 0x10000040, 0x10001000, 0x00041040, 0x00040000, + 0x00041040, 0x00040000, 0x10041000, 0x00001000, + 0x00000040, 0x10040040, 0x00001000, 0x00041040, + 0x10001000, 0x00000040, 0x10000040, 0x10040000, + 0x10040040, 0x10000000, 0x00040000, 0x10001040, + 0x00000000, 0x10041040, 0x00040040, 0x10000040, + 0x10040000, 0x10001000, 0x10001040, 0x00000000, + 0x10041040, 0x00041000, 0x00041000, 0x00001040, + 0x00001040, 0x00040040, 0x10000000, 0x10041000 +}; + +/* + * PC1: left and right halves bit-swap + */ +static const uint32_t LHs[16] = +{ + 0x00000000, 0x00000001, 0x00000100, 0x00000101, + 0x00010000, 0x00010001, 0x00010100, 0x00010101, + 0x01000000, 0x01000001, 0x01000100, 0x01000101, + 0x01010000, 0x01010001, 0x01010100, 0x01010101 +}; + +static const uint32_t RHs[16] = +{ + 0x00000000, 0x01000000, 0x00010000, 0x01010000, + 0x00000100, 0x01000100, 0x00010100, 0x01010100, + 0x00000001, 0x01000001, 0x00010001, 0x01010001, + 0x00000101, 0x01000101, 0x00010101, 0x01010101, +}; + +/* + * Initial Permutation macro + */ +#define DES_IP(X,Y) \ +{ \ + T = ((X >> 4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T << 4); \ + T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16); \ + T = ((Y >> 2) ^ X) & 0x33333333; X ^= T; Y ^= (T << 2); \ + T = ((Y >> 8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T << 8); \ + Y = ((Y << 1) | (Y >> 31)) & 0xFFFFFFFF; \ + T = (X ^ Y) & 0xAAAAAAAA; Y ^= T; X ^= T; \ + X = ((X << 1) | (X >> 31)) & 0xFFFFFFFF; \ +} + +/* + * Final Permutation macro + */ +#define DES_FP(X,Y) \ +{ \ + X = ((X << 31) | (X >> 1)) & 0xFFFFFFFF; \ + T = (X ^ Y) & 0xAAAAAAAA; X ^= T; Y ^= T; \ + Y = ((Y << 31) | (Y >> 1)) & 0xFFFFFFFF; \ + T = ((Y >> 8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T << 8); \ + T = ((Y >> 2) ^ X) & 0x33333333; X ^= T; Y ^= (T << 2); \ + T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16); \ + T = ((X >> 4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T << 4); \ +} + +/* + * DES round macro + */ +#define DES_ROUND(X,Y) \ +{ \ + T = *SK++ ^ X; \ + Y ^= SB8[ (T ) & 0x3F ] ^ \ + SB6[ (T >> 8) & 0x3F ] ^ \ + SB4[ (T >> 16) & 0x3F ] ^ \ + SB2[ (T >> 24) & 0x3F ]; \ + \ + T = *SK++ ^ ((X << 28) | (X >> 4)); \ + Y ^= SB7[ (T ) & 0x3F ] ^ \ + SB5[ (T >> 8) & 0x3F ] ^ \ + SB3[ (T >> 16) & 0x3F ] ^ \ + SB1[ (T >> 24) & 0x3F ]; \ +} + +#define SWAP(a,b) { uint32_t t = a; a = b; b = t; t = 0; } + +static const unsigned char odd_parity_table[128] = { 1, 2, 4, 7, 8, + 11, 13, 14, 16, 19, 21, 22, 25, 26, 28, 31, 32, 35, 37, 38, 41, 42, 44, + 47, 49, 50, 52, 55, 56, 59, 61, 62, 64, 67, 69, 70, 73, 74, 76, 79, 81, + 82, 84, 87, 88, 91, 93, 94, 97, 98, 100, 103, 104, 107, 109, 110, 112, + 115, 117, 118, 121, 122, 124, 127, 128, 131, 133, 134, 137, 138, 140, + 143, 145, 146, 148, 151, 152, 155, 157, 158, 161, 162, 164, 167, 168, + 171, 173, 174, 176, 179, 181, 182, 185, 186, 188, 191, 193, 194, 196, + 199, 200, 203, 205, 206, 208, 211, 213, 214, 217, 218, 220, 223, 224, + 227, 229, 230, 233, 234, 236, 239, 241, 242, 244, 247, 248, 251, 253, + 254 }; + +void des_key_set_parity( unsigned char key[DES_KEY_SIZE] ) +{ + int i; + + for( i = 0; i < DES_KEY_SIZE; i++ ) + key[i] = odd_parity_table[key[i] / 2]; +} + +/* + * Check the given key's parity, returns 1 on failure, 0 on SUCCESS + */ +int des_key_check_key_parity( const unsigned char key[DES_KEY_SIZE] ) +{ + int i; + + for( i = 0; i < DES_KEY_SIZE; i++ ) + if ( key[i] != odd_parity_table[key[i] / 2] ) + return( 1 ); + + return( 0 ); +} + +/* + * Table of weak and semi-weak keys + * + * Source: http://en.wikipedia.org/wiki/Weak_key + * + * Weak: + * Alternating ones + zeros (0x0101010101010101) + * Alternating 'F' + 'E' (0xFEFEFEFEFEFEFEFE) + * '0xE0E0E0E0F1F1F1F1' + * '0x1F1F1F1F0E0E0E0E' + * + * Semi-weak: + * 0x011F011F010E010E and 0x1F011F010E010E01 + * 0x01E001E001F101F1 and 0xE001E001F101F101 + * 0x01FE01FE01FE01FE and 0xFE01FE01FE01FE01 + * 0x1FE01FE00EF10EF1 and 0xE01FE01FF10EF10E + * 0x1FFE1FFE0EFE0EFE and 0xFE1FFE1FFE0EFE0E + * 0xE0FEE0FEF1FEF1FE and 0xFEE0FEE0FEF1FEF1 + * + */ + +#define WEAK_KEY_COUNT 16 + +static const unsigned char weak_key_table[WEAK_KEY_COUNT][DES_KEY_SIZE] = +{ + { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, + { 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE }, + { 0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x0E, 0x0E, 0x0E }, + { 0xE0, 0xE0, 0xE0, 0xE0, 0xF1, 0xF1, 0xF1, 0xF1 }, + + { 0x01, 0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E }, + { 0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E, 0x01 }, + { 0x01, 0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1 }, + { 0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1, 0x01 }, + { 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE }, + { 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01 }, + { 0x1F, 0xE0, 0x1F, 0xE0, 0x0E, 0xF1, 0x0E, 0xF1 }, + { 0xE0, 0x1F, 0xE0, 0x1F, 0xF1, 0x0E, 0xF1, 0x0E }, + { 0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E, 0xFE }, + { 0xFE, 0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E }, + { 0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1, 0xFE }, + { 0xFE, 0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1 } +}; + +int des_key_check_weak( const unsigned char key[DES_KEY_SIZE] ) +{ + int i; + + for( i = 0; i < WEAK_KEY_COUNT; i++ ) + if( memcmp( weak_key_table[i], key, DES_KEY_SIZE) == 0) + return( 1 ); + + return( 0 ); +} + +static void des_setkey( uint32_t SK[32], const unsigned char key[DES_KEY_SIZE] ) +{ + int i; + uint32_t X, Y, T; + + GET_UINT32_BE( X, key, 0 ); + GET_UINT32_BE( Y, key, 4 ); + + /* + * Permuted Choice 1 + */ + T = ((Y >> 4) ^ X) & 0x0F0F0F0F; X ^= T; Y ^= (T << 4); + T = ((Y ) ^ X) & 0x10101010; X ^= T; Y ^= (T ); + + X = (LHs[ (X ) & 0xF] << 3) | (LHs[ (X >> 8) & 0xF ] << 2) + | (LHs[ (X >> 16) & 0xF] << 1) | (LHs[ (X >> 24) & 0xF ] ) + | (LHs[ (X >> 5) & 0xF] << 7) | (LHs[ (X >> 13) & 0xF ] << 6) + | (LHs[ (X >> 21) & 0xF] << 5) | (LHs[ (X >> 29) & 0xF ] << 4); + + Y = (RHs[ (Y >> 1) & 0xF] << 3) | (RHs[ (Y >> 9) & 0xF ] << 2) + | (RHs[ (Y >> 17) & 0xF] << 1) | (RHs[ (Y >> 25) & 0xF ] ) + | (RHs[ (Y >> 4) & 0xF] << 7) | (RHs[ (Y >> 12) & 0xF ] << 6) + | (RHs[ (Y >> 20) & 0xF] << 5) | (RHs[ (Y >> 28) & 0xF ] << 4); + + X &= 0x0FFFFFFF; + Y &= 0x0FFFFFFF; + + /* + * calculate subkeys + */ + for( i = 0; i < 16; i++ ) + { + if( i < 2 || i == 8 || i == 15 ) + { + X = ((X << 1) | (X >> 27)) & 0x0FFFFFFF; + Y = ((Y << 1) | (Y >> 27)) & 0x0FFFFFFF; + } + else + { + X = ((X << 2) | (X >> 26)) & 0x0FFFFFFF; + Y = ((Y << 2) | (Y >> 26)) & 0x0FFFFFFF; + } + + *SK++ = ((X << 4) & 0x24000000) | ((X << 28) & 0x10000000) + | ((X << 14) & 0x08000000) | ((X << 18) & 0x02080000) + | ((X << 6) & 0x01000000) | ((X << 9) & 0x00200000) + | ((X >> 1) & 0x00100000) | ((X << 10) & 0x00040000) + | ((X << 2) & 0x00020000) | ((X >> 10) & 0x00010000) + | ((Y >> 13) & 0x00002000) | ((Y >> 4) & 0x00001000) + | ((Y << 6) & 0x00000800) | ((Y >> 1) & 0x00000400) + | ((Y >> 14) & 0x00000200) | ((Y ) & 0x00000100) + | ((Y >> 5) & 0x00000020) | ((Y >> 10) & 0x00000010) + | ((Y >> 3) & 0x00000008) | ((Y >> 18) & 0x00000004) + | ((Y >> 26) & 0x00000002) | ((Y >> 24) & 0x00000001); + + *SK++ = ((X << 15) & 0x20000000) | ((X << 17) & 0x10000000) + | ((X << 10) & 0x08000000) | ((X << 22) & 0x04000000) + | ((X >> 2) & 0x02000000) | ((X << 1) & 0x01000000) + | ((X << 16) & 0x00200000) | ((X << 11) & 0x00100000) + | ((X << 3) & 0x00080000) | ((X >> 6) & 0x00040000) + | ((X << 15) & 0x00020000) | ((X >> 4) & 0x00010000) + | ((Y >> 2) & 0x00002000) | ((Y << 8) & 0x00001000) + | ((Y >> 14) & 0x00000808) | ((Y >> 9) & 0x00000400) + | ((Y ) & 0x00000200) | ((Y << 7) & 0x00000100) + | ((Y >> 7) & 0x00000020) | ((Y >> 3) & 0x00000011) + | ((Y << 2) & 0x00000004) | ((Y >> 21) & 0x00000002); + } +} + +/* + * DES key schedule (56-bit, encryption) + */ +int des_setkey_enc( des_context *ctx, const unsigned char key[DES_KEY_SIZE] ) +{ + des_setkey( ctx->sk, key ); + + return( 0 ); +} + +/* + * DES key schedule (56-bit, decryption) + */ +int des_setkey_dec( des_context *ctx, const unsigned char key[DES_KEY_SIZE] ) +{ + int i; + + des_setkey( ctx->sk, key ); + + for( i = 0; i < 16; i += 2 ) + { + SWAP( ctx->sk[i ], ctx->sk[30 - i] ); + SWAP( ctx->sk[i + 1], ctx->sk[31 - i] ); + } + + return( 0 ); +} + +static void des3_set2key( uint32_t esk[96], + uint32_t dsk[96], + const unsigned char key[DES_KEY_SIZE*2] ) +{ + int i; + + des_setkey( esk, key ); + des_setkey( dsk + 32, key + 8 ); + + for( i = 0; i < 32; i += 2 ) + { + dsk[i ] = esk[30 - i]; + dsk[i + 1] = esk[31 - i]; + + esk[i + 32] = dsk[62 - i]; + esk[i + 33] = dsk[63 - i]; + + esk[i + 64] = esk[i ]; + esk[i + 65] = esk[i + 1]; + + dsk[i + 64] = dsk[i ]; + dsk[i + 65] = dsk[i + 1]; + } +} + +/* + * Triple-DES key schedule (112-bit, encryption) + */ +int des3_set2key_enc( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 2] ) +{ + uint32_t sk[96]; + + des3_set2key( ctx->sk, sk, key ); + memset( sk, 0, sizeof( sk ) ); + + return( 0 ); +} + +/* + * Triple-DES key schedule (112-bit, decryption) + */ +int des3_set2key_dec( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 2] ) +{ + uint32_t sk[96]; + + des3_set2key( sk, ctx->sk, key ); + memset( sk, 0, sizeof( sk ) ); + + return( 0 ); +} + +static void des3_set3key( uint32_t esk[96], + uint32_t dsk[96], + const unsigned char key[24] ) +{ + int i; + + des_setkey( esk, key ); + des_setkey( dsk + 32, key + 8 ); + des_setkey( esk + 64, key + 16 ); + + for( i = 0; i < 32; i += 2 ) + { + dsk[i ] = esk[94 - i]; + dsk[i + 1] = esk[95 - i]; + + esk[i + 32] = dsk[62 - i]; + esk[i + 33] = dsk[63 - i]; + + dsk[i + 64] = esk[30 - i]; + dsk[i + 65] = esk[31 - i]; + } +} + +/* + * Triple-DES key schedule (168-bit, encryption) + */ +int des3_set3key_enc( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 3] ) +{ + uint32_t sk[96]; + + des3_set3key( ctx->sk, sk, key ); + memset( sk, 0, sizeof( sk ) ); + + return( 0 ); +} + +/* + * Triple-DES key schedule (168-bit, decryption) + */ +int des3_set3key_dec( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 3] ) +{ + uint32_t sk[96]; + + des3_set3key( sk, ctx->sk, key ); + memset( sk, 0, sizeof( sk ) ); + + return( 0 ); +} + +/* + * DES-ECB block encryption/decryption + */ +int des_crypt_ecb( des_context *ctx, + const unsigned char input[8], + unsigned char output[8] ) +{ + int i; + uint32_t X, Y, T, *SK; + + SK = ctx->sk; + + GET_UINT32_BE( X, input, 0 ); + GET_UINT32_BE( Y, input, 4 ); + + DES_IP( X, Y ); + + for( i = 0; i < 8; i++ ) + { + DES_ROUND( Y, X ); + DES_ROUND( X, Y ); + } + + DES_FP( Y, X ); + + PUT_UINT32_BE( Y, output, 0 ); + PUT_UINT32_BE( X, output, 4 ); + + return( 0 ); +} + +#if defined(POLARSSL_CIPHER_MODE_CBC) +/* + * DES-CBC buffer encryption/decryption + */ +int des_crypt_cbc( des_context *ctx, + int mode, + size_t length, + unsigned char iv[8], + const unsigned char *input, + unsigned char *output ) +{ + int i; + unsigned char temp[8]; + + if( length % 8 ) + return( POLARSSL_ERR_DES_INVALID_INPUT_LENGTH ); + + if( mode == DES_ENCRYPT ) + { + while( length > 0 ) + { + for( i = 0; i < 8; i++ ) + output[i] = (unsigned char)( input[i] ^ iv[i] ); + + des_crypt_ecb( ctx, output, output ); + memcpy( iv, output, 8 ); + + input += 8; + output += 8; + length -= 8; + } + } + else /* DES_DECRYPT */ + { + while( length > 0 ) + { + memcpy( temp, input, 8 ); + des_crypt_ecb( ctx, input, output ); + + for( i = 0; i < 8; i++ ) + output[i] = (unsigned char)( output[i] ^ iv[i] ); + + memcpy( iv, temp, 8 ); + + input += 8; + output += 8; + length -= 8; + } + } + + return( 0 ); +} +#endif /* POLARSSL_CIPHER_MODE_CBC */ + +/* + * 3DES-ECB block encryption/decryption + */ +int des3_crypt_ecb( des3_context *ctx, + const unsigned char input[8], + unsigned char output[8] ) +{ + int i; + uint32_t X, Y, T, *SK; + + SK = ctx->sk; + + GET_UINT32_BE( X, input, 0 ); + GET_UINT32_BE( Y, input, 4 ); + + DES_IP( X, Y ); + + for( i = 0; i < 8; i++ ) + { + DES_ROUND( Y, X ); + DES_ROUND( X, Y ); + } + + for( i = 0; i < 8; i++ ) + { + DES_ROUND( X, Y ); + DES_ROUND( Y, X ); + } + + for( i = 0; i < 8; i++ ) + { + DES_ROUND( Y, X ); + DES_ROUND( X, Y ); + } + + DES_FP( Y, X ); + + PUT_UINT32_BE( Y, output, 0 ); + PUT_UINT32_BE( X, output, 4 ); + + return( 0 ); +} + +#if defined(POLARSSL_CIPHER_MODE_CBC) +/* + * 3DES-CBC buffer encryption/decryption + */ +int des3_crypt_cbc( des3_context *ctx, + int mode, + size_t length, + unsigned char iv[8], + const unsigned char *input, + unsigned char *output ) +{ + int i; + unsigned char temp[8]; + + if( length % 8 ) + return( POLARSSL_ERR_DES_INVALID_INPUT_LENGTH ); + + if( mode == DES_ENCRYPT ) + { + while( length > 0 ) + { + for( i = 0; i < 8; i++ ) + output[i] = (unsigned char)( input[i] ^ iv[i] ); + + des3_crypt_ecb( ctx, output, output ); + memcpy( iv, output, 8 ); + + input += 8; + output += 8; + length -= 8; + } + } + else /* DES_DECRYPT */ + { + while( length > 0 ) + { + memcpy( temp, input, 8 ); + des3_crypt_ecb( ctx, input, output ); + + for( i = 0; i < 8; i++ ) + output[i] = (unsigned char)( output[i] ^ iv[i] ); + + memcpy( iv, temp, 8 ); + + input += 8; + output += 8; + length -= 8; + } + } + + return( 0 ); +} +#endif /* POLARSSL_CIPHER_MODE_CBC */ + +#endif /* !POLARSSL_DES_ALT */ + +#if defined(POLARSSL_SELF_TEST) + +#include + +/* + * DES and 3DES test vectors from: + * + * http://csrc.nist.gov/groups/STM/cavp/documents/des/tripledes-vectors.zip + */ +static const unsigned char des3_test_keys[24] = +{ + 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, + 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, + 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23 +}; + +static const unsigned char des3_test_buf[8] = +{ + 0x4E, 0x6F, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74 +}; + +static const unsigned char des3_test_ecb_dec[3][8] = +{ + { 0xCD, 0xD6, 0x4F, 0x2F, 0x94, 0x27, 0xC1, 0x5D }, + { 0x69, 0x96, 0xC8, 0xFA, 0x47, 0xA2, 0xAB, 0xEB }, + { 0x83, 0x25, 0x39, 0x76, 0x44, 0x09, 0x1A, 0x0A } +}; + +static const unsigned char des3_test_ecb_enc[3][8] = +{ + { 0x6A, 0x2A, 0x19, 0xF4, 0x1E, 0xCA, 0x85, 0x4B }, + { 0x03, 0xE6, 0x9F, 0x5B, 0xFA, 0x58, 0xEB, 0x42 }, + { 0xDD, 0x17, 0xE8, 0xB8, 0xB4, 0x37, 0xD2, 0x32 } +}; + +#if defined(POLARSSL_CIPHER_MODE_CBC) +static const unsigned char des3_test_iv[8] = +{ + 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF, +}; + +static const unsigned char des3_test_cbc_dec[3][8] = +{ + { 0x12, 0x9F, 0x40, 0xB9, 0xD2, 0x00, 0x56, 0xB3 }, + { 0x47, 0x0E, 0xFC, 0x9A, 0x6B, 0x8E, 0xE3, 0x93 }, + { 0xC5, 0xCE, 0xCF, 0x63, 0xEC, 0xEC, 0x51, 0x4C } +}; + +static const unsigned char des3_test_cbc_enc[3][8] = +{ + { 0x54, 0xF1, 0x5A, 0xF6, 0xEB, 0xE3, 0xA4, 0xB4 }, + { 0x35, 0x76, 0x11, 0x56, 0x5F, 0xA1, 0x8E, 0x4D }, + { 0xCB, 0x19, 0x1F, 0x85, 0xD1, 0xED, 0x84, 0x39 } +}; +#endif /* POLARSSL_CIPHER_MODE_CBC */ + +/* + * Checkup routine + */ +int des_self_test( int verbose ) +{ + int i, j, u, v; + des_context ctx; + des3_context ctx3; + unsigned char key[24]; + unsigned char buf[8]; +#if defined(POLARSSL_CIPHER_MODE_CBC) + unsigned char prv[8]; + unsigned char iv[8]; +#endif + + memset( key, 0, 24 ); + + /* + * ECB mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + v = i & 1; + + if( verbose != 0 ) + polarssl_printf( " DES%c-ECB-%3d (%s): ", + ( u == 0 ) ? ' ' : '3', 56 + u * 56, + ( v == DES_DECRYPT ) ? "dec" : "enc" ); + + memcpy( buf, des3_test_buf, 8 ); + + switch( i ) + { + case 0: + des_setkey_dec( &ctx, des3_test_keys ); + break; + + case 1: + des_setkey_enc( &ctx, des3_test_keys ); + break; + + case 2: + des3_set2key_dec( &ctx3, des3_test_keys ); + break; + + case 3: + des3_set2key_enc( &ctx3, des3_test_keys ); + break; + + case 4: + des3_set3key_dec( &ctx3, des3_test_keys ); + break; + + case 5: + des3_set3key_enc( &ctx3, des3_test_keys ); + break; + + default: + return( 1 ); + } + + for( j = 0; j < 10000; j++ ) + { + if( u == 0 ) + des_crypt_ecb( &ctx, buf, buf ); + else + des3_crypt_ecb( &ctx3, buf, buf ); + } + + if( ( v == DES_DECRYPT && + memcmp( buf, des3_test_ecb_dec[u], 8 ) != 0 ) || + ( v != DES_DECRYPT && + memcmp( buf, des3_test_ecb_enc[u], 8 ) != 0 ) ) + { + if( verbose != 0 ) + polarssl_printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + polarssl_printf( "passed\n" ); + } + + if( verbose != 0 ) + polarssl_printf( "\n" ); + +#if defined(POLARSSL_CIPHER_MODE_CBC) + /* + * CBC mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + v = i & 1; + + if( verbose != 0 ) + polarssl_printf( " DES%c-CBC-%3d (%s): ", + ( u == 0 ) ? ' ' : '3', 56 + u * 56, + ( v == DES_DECRYPT ) ? "dec" : "enc" ); + + memcpy( iv, des3_test_iv, 8 ); + memcpy( prv, des3_test_iv, 8 ); + memcpy( buf, des3_test_buf, 8 ); + + switch( i ) + { + case 0: + des_setkey_dec( &ctx, des3_test_keys ); + break; + + case 1: + des_setkey_enc( &ctx, des3_test_keys ); + break; + + case 2: + des3_set2key_dec( &ctx3, des3_test_keys ); + break; + + case 3: + des3_set2key_enc( &ctx3, des3_test_keys ); + break; + + case 4: + des3_set3key_dec( &ctx3, des3_test_keys ); + break; + + case 5: + des3_set3key_enc( &ctx3, des3_test_keys ); + break; + + default: + return( 1 ); + } + + if( v == DES_DECRYPT ) + { + for( j = 0; j < 10000; j++ ) + { + if( u == 0 ) + des_crypt_cbc( &ctx, v, 8, iv, buf, buf ); + else + des3_crypt_cbc( &ctx3, v, 8, iv, buf, buf ); + } + } + else + { + for( j = 0; j < 10000; j++ ) + { + unsigned char tmp[8]; + + if( u == 0 ) + des_crypt_cbc( &ctx, v, 8, iv, buf, buf ); + else + des3_crypt_cbc( &ctx3, v, 8, iv, buf, buf ); + + memcpy( tmp, prv, 8 ); + memcpy( prv, buf, 8 ); + memcpy( buf, tmp, 8 ); + } + + memcpy( buf, prv, 8 ); + } + + if( ( v == DES_DECRYPT && + memcmp( buf, des3_test_cbc_dec[u], 8 ) != 0 ) || + ( v != DES_DECRYPT && + memcmp( buf, des3_test_cbc_enc[u], 8 ) != 0 ) ) + { + if( verbose != 0 ) + polarssl_printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + polarssl_printf( "passed\n" ); + } +#endif /* POLARSSL_CIPHER_MODE_CBC */ + + if( verbose != 0 ) + polarssl_printf( "\n" ); + + return( 0 ); +} + +#endif + +#endif diff --git a/client/loclass/des.h b/client/loclass/des.h new file mode 100644 index 00000000..907d56b1 --- /dev/null +++ b/client/loclass/des.h @@ -0,0 +1,256 @@ +/** + * \file des.h + * + * \brief DES block cipher + * + * 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_DES_H +#define POLARSSL_DES_H + +//#include "config.h" + +#include + +#if defined(_MSC_VER) && !defined(EFIX64) && !defined(EFI32) +#include +typedef UINT32 uint32_t; +#else +#include +#endif + +#define DES_ENCRYPT 1 +#define DES_DECRYPT 0 + +#define POLARSSL_ERR_DES_INVALID_INPUT_LENGTH -0x0032 /**< The data input has an invalid length. */ + +#define DES_KEY_SIZE 8 + +#if !defined(POLARSSL_DES_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief DES context structure + */ +typedef struct +{ + int mode; /*!< encrypt/decrypt */ + uint32_t sk[32]; /*!< DES subkeys */ +} +des_context; + +/** + * \brief Triple-DES context structure + */ +typedef struct +{ + int mode; /*!< encrypt/decrypt */ + uint32_t sk[96]; /*!< 3DES subkeys */ +} +des3_context; + +/** + * \brief Set key parity on the given key to odd. + * + * DES keys are 56 bits long, but each byte is padded with + * a parity bit to allow verification. + * + * \param key 8-byte secret key + */ +void des_key_set_parity( unsigned char key[DES_KEY_SIZE] ); + +/** + * \brief Check that key parity on the given key is odd. + * + * DES keys are 56 bits long, but each byte is padded with + * a parity bit to allow verification. + * + * \param key 8-byte secret key + * + * \return 0 is parity was ok, 1 if parity was not correct. + */ +int des_key_check_key_parity( const unsigned char key[DES_KEY_SIZE] ); + +/** + * \brief Check that key is not a weak or semi-weak DES key + * + * \param key 8-byte secret key + * + * \return 0 if no weak key was found, 1 if a weak key was identified. + */ +int des_key_check_weak( const unsigned char key[DES_KEY_SIZE] ); + +/** + * \brief DES key schedule (56-bit, encryption) + * + * \param ctx DES context to be initialized + * \param key 8-byte secret key + * + * \return 0 + */ +int des_setkey_enc( des_context *ctx, const unsigned char key[DES_KEY_SIZE] ); + +/** + * \brief DES key schedule (56-bit, decryption) + * + * \param ctx DES context to be initialized + * \param key 8-byte secret key + * + * \return 0 + */ +int des_setkey_dec( des_context *ctx, const unsigned char key[DES_KEY_SIZE] ); + +/** + * \brief Triple-DES key schedule (112-bit, encryption) + * + * \param ctx 3DES context to be initialized + * \param key 16-byte secret key + * + * \return 0 + */ +int des3_set2key_enc( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 2] ); + +/** + * \brief Triple-DES key schedule (112-bit, decryption) + * + * \param ctx 3DES context to be initialized + * \param key 16-byte secret key + * + * \return 0 + */ +int des3_set2key_dec( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 2] ); + +/** + * \brief Triple-DES key schedule (168-bit, encryption) + * + * \param ctx 3DES context to be initialized + * \param key 24-byte secret key + * + * \return 0 + */ +int des3_set3key_enc( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 3] ); + +/** + * \brief Triple-DES key schedule (168-bit, decryption) + * + * \param ctx 3DES context to be initialized + * \param key 24-byte secret key + * + * \return 0 + */ +int des3_set3key_dec( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 3] ); + +/** + * \brief DES-ECB block encryption/decryption + * + * \param ctx DES context + * \param input 64-bit input block + * \param output 64-bit output block + * + * \return 0 if successful + */ +int des_crypt_ecb( des_context *ctx, + const unsigned char input[8], + unsigned char output[8] ); + +#if defined(POLARSSL_CIPHER_MODE_CBC) +/** + * \brief DES-CBC buffer encryption/decryption + * + * \param ctx DES context + * \param mode DES_ENCRYPT or DES_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + */ +int des_crypt_cbc( des_context *ctx, + int mode, + size_t length, + unsigned char iv[8], + const unsigned char *input, + unsigned char *output ); +#endif /* POLARSSL_CIPHER_MODE_CBC */ + +/** + * \brief 3DES-ECB block encryption/decryption + * + * \param ctx 3DES context + * \param input 64-bit input block + * \param output 64-bit output block + * + * \return 0 if successful + */ +int des3_crypt_ecb( des3_context *ctx, + const unsigned char input[8], + unsigned char output[8] ); + +#if defined(POLARSSL_CIPHER_MODE_CBC) +/** + * \brief 3DES-CBC buffer encryption/decryption + * + * \param ctx 3DES context + * \param mode DES_ENCRYPT or DES_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful, or POLARSSL_ERR_DES_INVALID_INPUT_LENGTH + */ +int des3_crypt_cbc( des3_context *ctx, + int mode, + size_t length, + unsigned char iv[8], + const unsigned char *input, + unsigned char *output ); +#endif /* POLARSSL_CIPHER_MODE_CBC */ + +#ifdef __cplusplus +} +#endif + +#else /* POLARSSL_DES_ALT */ +#include "des_alt.h" +#endif /* POLARSSL_DES_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int des_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* des.h */ diff --git a/client/loclass/elite_crack.c b/client/loclass/elite_crack.c new file mode 100644 index 00000000..1a464b6c --- /dev/null +++ b/client/loclass/elite_crack.c @@ -0,0 +1,656 @@ +#include +#include +#include +#include +#include +#include "cipherutils.h" +#include "cipher.h" +#include "ikeys.h" +#include "elite_crack.h" +#include "fileutils.h" +#include "des.h" + +/** + * @brief Permutes a key from standard NIST format to Iclass specific format + * from http://www.proxmark.org/forum/viewtopic.php?pid=11220#p11220 + * + * If you permute [6c 8d 44 f9 2a 2d 01 bf] you get [8a 0d b9 88 bb a7 90 ea] as shown below. + * + * 1 0 1 1 1 1 1 1 bf + * 0 0 0 0 0 0 0 1 01 + * 0 0 1 0 1 1 0 1 2d + * 0 0 1 0 1 0 1 0 2a + * 1 1 1 1 1 0 0 1 f9 + * 0 1 0 0 0 1 0 0 44 + * 1 0 0 0 1 1 0 1 8d + * 0 1 1 0 1 1 0 0 6c + * + * 8 0 b 8 b a 9 e + * a d 9 8 b 7 0 a + * + * @param key + * @param dest + */ +void permutekey(uint8_t key[8], uint8_t dest[8]) +{ + + int i; + for(i = 0 ; i < 8 ; i++) + { + dest[i] = (((key[7] & (0x80 >> i)) >> (7-i)) << 7) | + (((key[6] & (0x80 >> i)) >> (7-i)) << 6) | + (((key[5] & (0x80 >> i)) >> (7-i)) << 5) | + (((key[4] & (0x80 >> i)) >> (7-i)) << 4) | + (((key[3] & (0x80 >> i)) >> (7-i)) << 3) | + (((key[2] & (0x80 >> i)) >> (7-i)) << 2) | + (((key[1] & (0x80 >> i)) >> (7-i)) << 1) | + (((key[0] & (0x80 >> i)) >> (7-i)) << 0); + } + + return; +} +/** + * Permutes a key from iclass specific format to NIST format + * @brief permutekey_rev + * @param key + * @param dest + */ +void permutekey_rev(uint8_t key[8], uint8_t dest[8]) +{ + int i; + for(i = 0 ; i < 8 ; i++) + { + dest[7-i] = (((key[0] & (0x80 >> i)) >> (7-i)) << 7) | + (((key[1] & (0x80 >> i)) >> (7-i)) << 6) | + (((key[2] & (0x80 >> i)) >> (7-i)) << 5) | + (((key[3] & (0x80 >> i)) >> (7-i)) << 4) | + (((key[4] & (0x80 >> i)) >> (7-i)) << 3) | + (((key[5] & (0x80 >> i)) >> (7-i)) << 2) | + (((key[6] & (0x80 >> i)) >> (7-i)) << 1) | + (((key[7] & (0x80 >> i)) >> (7-i)) << 0); + } +} + +/** + * Helper function for hash1 + * @brief rr + * @param val + * @return + */ +uint8_t rr(uint8_t val) +{ + return val >> 1 | (( val & 1) << 7); +} +/** + * Helper function for hash1 + * @brief rl + * @param val + * @return + */ +uint8_t rl(uint8_t val) +{ + return val << 1 | (( val & 0x80) >> 7); +} +/** + * Helper function for hash1 + * @brief swap + * @param val + * @return + */ +uint8_t swap(uint8_t val) +{ + return ((val >> 4) & 0xFF) | ((val &0xFF) << 4); +} + +/** + * Hash1 takes CSN as input, and determines what bytes in the keytable will be used + * when constructing the K_sel. + * @param csn the CSN used + * @param k output + */ +void hash1(uint8_t csn[] , uint8_t k[]) +{ + k[0] = csn[0]^csn[1]^csn[2]^csn[3]^csn[4]^csn[5]^csn[6]^csn[7]; + k[1] = csn[0]+csn[1]+csn[2]+csn[3]+csn[4]+csn[5]+csn[6]+csn[7]; + k[2] = rr(swap( csn[2]+k[1] )); + k[3] = rr(swap( csn[3]+k[0] )); + k[4] = ~rr(swap( csn[4]+k[2] ))+1; + k[5] = ~rr(swap( csn[5]+k[3] ))+1; + k[6] = rr( csn[6]+(k[4]^0x3c) ); + k[7] = rl( csn[7]+(k[5]^0xc3) ); + int i; + for(i = 7; i >=0; i--) + k[i] = k[i] & 0x7F; +} +/** +Definition 14. Define the rotate key function rk : (F 82 ) 8 × N → (F 82 ) 8 as +rk(x [0] . . . x [7] , 0) = x [0] . . . x [7] +rk(x [0] . . . x [7] , n + 1) = rk(rl(x [0] ) . . . rl(x [7] ), n) +**/ +void rk(uint8_t *key, uint8_t n, uint8_t *outp_key) +{ + + memcpy(outp_key, key, 8); + + uint8_t j; + + while(n-- > 0) + for(j=0; j < 8 ; j++) + outp_key[j] = rl(outp_key[j]); + + return; +} + +static des_context ctx_enc = {DES_ENCRYPT,{0}}; +static des_context ctx_dec = {DES_DECRYPT,{0}}; + +void desdecrypt_iclass(uint8_t *iclass_key, uint8_t *input, uint8_t *output) +{ + uint8_t key_std_format[8] = {0}; + permutekey_rev(iclass_key, key_std_format); + des_setkey_dec( &ctx_dec, key_std_format); + des_crypt_ecb(&ctx_dec,input,output); +} +void desencrypt_iclass(uint8_t *iclass_key, uint8_t *input, uint8_t *output) +{ + uint8_t key_std_format[8] = {0}; + permutekey_rev(iclass_key, key_std_format); + des_setkey_enc( &ctx_enc, key_std_format); + des_crypt_ecb(&ctx_enc,input,output); +} + +/** + * @brief Insert uint8_t[8] custom master key to calculate hash2 and return key_select. + * @param key unpermuted custom key + * @param hash1 hash1 + * @param key_sel output key_sel=h[hash1[i]] + */ +void hash2(uint8_t *key64, uint8_t *outp_keytable) +{ + /** + *Expected: + * High Security Key Table + +00 F1 35 59 A1 0D 5A 26 7F 18 60 0B 96 8A C0 25 C1 +10 BF A1 3B B0 FF 85 28 75 F2 1F C6 8F 0E 74 8F 21 +20 14 7A 55 16 C8 A9 7D B3 13 0C 5D C9 31 8D A9 B2 +30 A3 56 83 0F 55 7E DE 45 71 21 D2 6D C1 57 1C 9C +40 78 2F 64 51 42 7B 64 30 FA 26 51 76 D3 E0 FB B6 +50 31 9F BF 2F 7E 4F 94 B4 BD 4F 75 91 E3 1B EB 42 +60 3F 88 6F B8 6C 2C 93 0D 69 2C D5 20 3C C1 61 95 +70 43 08 A0 2F FE B3 26 D7 98 0B 34 7B 47 70 A0 AB + +**** The 64-bit HS Custom Key Value = 5B7C62C491C11B39 ******/ + uint8_t key64_negated[8] = {0}; + uint8_t z[8][8]={{0},{0}}; + uint8_t temp_output[8]={0}; + //calculate complement of key + int i; + for(i=0;i<8;i++) + key64_negated[i]= ~key64[i]; + + // Once again, key is on iclass-format + desencrypt_iclass(key64, key64_negated, z[0]); + + prnlog("\nHigh security custom key (Kcus):"); + printvar("z0 ", z[0],8); + + uint8_t y[8][8]={{0},{0}}; + + // y[0]=DES_dec(z[0],~key) + // Once again, key is on iclass-format + desdecrypt_iclass(z[0], key64_negated, y[0]); + printvar("y0 ", y[0],8); + + for(i=1; i<8; i++) + { + + // z [i] = DES dec (rk(K cus , i), z [i−1] ) + rk(key64, i, temp_output); + //y [i] = DES enc (rk(K cus , i), y [i−1] ) + + desdecrypt_iclass(temp_output,z[i-1], z[i]); + desencrypt_iclass(temp_output,y[i-1], y[i]); + + } + if(outp_keytable != NULL) + { + for(i = 0 ; i < 8 ; i++) + { + memcpy(outp_keytable+i*16,y[i],8); + memcpy(outp_keytable+8+i*16,z[i],8); + } + }else + { + printarr_human_readable("hash2", outp_keytable,128); + } +} + +/** + * @brief Reads data from the iclass-reader-attack dump file. + * @param dump, data from a iclass reader attack dump. The format of the dumpdata is expected to be as follows: + * <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC><8 byte HASH1><1 byte NUM_BYTES_TO_RECOVER><3 bytes BYTES_TO_RECOVER> + * .. N times... + * + * So the first attack, with 3 bytes to recover would be : ... 03000145 + * And a later attack, with 1 byte to recover (byte 0x5)would be : ...01050000 + * And an attack, with 2 bytes to recover (byte 0x5 and byte 0x07 )would be : ...02050700 + * + * @param cc_nr an array to store cc_nr into (12 bytes) + * @param csn an arracy ot store CSN into (8 bytes) + * @param received_mac an array to store MAC into (4 bytes) + * @param i the number to read. Should be less than 127, or something is wrong... + * @return + */ +int _readFromDump(uint8_t dump[], dumpdata* item, uint8_t i) +{ + size_t itemsize = sizeof(dumpdata); + //dumpdata item = {0}; + memcpy(item,dump+i*itemsize, itemsize); + if(true) + { + printvar("csn", item->csn,8); + printvar("cc_nr", item->cc_nr,12); + printvar("mac", item->mac,4); + } + return 0; +} + +static uint32_t startvalue = 0; +/** + * @brief Performs brute force attack against a dump-data item, containing csn, cc_nr and mac. + *This method calculates the hash1 for the CSN, and determines what bytes need to be bruteforced + *on the fly. If it finds that more than three bytes need to be bruteforced, it aborts. + *It updates the keytable with the findings, also using the upper half of the 16-bit ints + *to signal if the particular byte has been cracked or not. + * + * @param dump The dumpdata from iclass reader attack. + * @param keytable where to write found values. + * @return + */ +int bruteforceItem(dumpdata item, uint16_t keytable[]) +{ + int errors = 0; + uint8_t key_sel_p[8] = { 0 }; + uint8_t div_key[8] = {0}; + int found = false; + uint8_t key_sel[8] = {0}; + uint8_t calculated_MAC[4] = { 0 }; + + //Get the key index (hash1) + uint8_t key_index[8] = {0}; + hash1(item.csn, key_index); + + + /* + * Determine which bytes to retrieve. A hash is typically + * 01010000454501 + * We go through that hash, and in the corresponding keytable, we put markers + * on what state that particular index is: + * - CRACKED (this has already been cracked) + * - BEING_CRACKED (this is being bruteforced now) + * - CRACK_FAILED (self-explaining...) + * + * The markers are placed in the high area of the 16 bit key-table. + * Only the lower eight bits correspond to the (hopefully cracked) key-value. + **/ + uint8_t bytes_to_recover[3] = {0}; + uint8_t numbytes_to_recover = 0 ; + int i; + for(i =0 ; i < 8 ; i++) + { + if(keytable[key_index[i]] & (CRACKED | BEING_CRACKED)) continue; + bytes_to_recover[numbytes_to_recover++] = key_index[i]; + keytable[key_index[i]] |= BEING_CRACKED; + + if(numbytes_to_recover > 3) + { + prnlog("The CSN requires > 3 byte bruteforce, not supported"); + printvar("CSN", item.csn,8); + printvar("HASH1", key_index,8); + + //Before we exit, reset the 'BEING_CRACKED' to zero + keytable[bytes_to_recover[0]] &= ~BEING_CRACKED; + keytable[bytes_to_recover[1]] &= ~BEING_CRACKED; + keytable[bytes_to_recover[2]] &= ~BEING_CRACKED; + + return 1; + } + } + + /* + *A uint32 has room for 4 bytes, we'll only need 24 of those bits to bruteforce up to three bytes, + */ + uint32_t brute = startvalue; + /* + Determine where to stop the bruteforce. A 1-byte attack stops after 256 tries, + (when brute reaches 0x100). And so on... + bytes_to_recover = 1 --> endmask = 0x0000100 + bytes_to_recover = 2 --> endmask = 0x0010000 + bytes_to_recover = 3 --> endmask = 0x1000000 + */ + + uint32_t endmask = 1 << 8*numbytes_to_recover; + + for(i =0 ; i < numbytes_to_recover && numbytes_to_recover > 1; i++) + prnlog("Bruteforcing byte %d", bytes_to_recover[i]); + + while(!found && !(brute & endmask)) + { + + //Update the keytable with the brute-values + for(i =0 ; i < numbytes_to_recover; i++) + { + keytable[bytes_to_recover[i]] &= 0xFF00; + keytable[bytes_to_recover[i]] |= (brute >> (i*8) & 0xFF); + } + + // Piece together the key + key_sel[0] = keytable[key_index[0]] & 0xFF;key_sel[1] = keytable[key_index[1]] & 0xFF; + key_sel[2] = keytable[key_index[2]] & 0xFF;key_sel[3] = keytable[key_index[3]] & 0xFF; + key_sel[4] = keytable[key_index[4]] & 0xFF;key_sel[5] = keytable[key_index[5]] & 0xFF; + key_sel[6] = keytable[key_index[6]] & 0xFF;key_sel[7] = keytable[key_index[7]] & 0xFF; + + //Permute from iclass format to standard format + permutekey_rev(key_sel,key_sel_p); + //Diversify + diversifyKey(item.csn, key_sel_p, div_key); + //Calc mac + doMAC(item.cc_nr,12, div_key,calculated_MAC); + + if(memcmp(calculated_MAC, item.mac, 4) == 0) + { + for(i =0 ; i < numbytes_to_recover; i++) + prnlog("=> %d: 0x%02x", bytes_to_recover[i],0xFF & keytable[bytes_to_recover[i]]); + found = true; + break; + } + brute++; + if((brute & 0xFFFF) == 0) + { + printf("%d",(brute >> 16) & 0xFF); + fflush(stdout); + } + } + if(! found) + { + prnlog("Failed to recover %d bytes using the following CSN",numbytes_to_recover); + printvar("CSN",item.csn,8); + errors++; + //Before we exit, reset the 'BEING_CRACKED' to zero + for(i =0 ; i < numbytes_to_recover; i++) + { + keytable[bytes_to_recover[i]] &= 0xFF; + keytable[bytes_to_recover[i]] |= CRACK_FAILED; + } + + }else + { + for(i =0 ; i < numbytes_to_recover; i++) + { + keytable[bytes_to_recover[i]] &= 0xFF; + keytable[bytes_to_recover[i]] |= CRACKED; + } + + } + return errors; +} + + +/** + * From dismantling iclass-paper: + * Assume that an adversary somehow learns the first 16 bytes of hash2(K_cus ), i.e., y [0] and z [0] . + * Then he can simply recover the master custom key K_cus by computing + * K_cus = ~DES(z[0] , y[0] ) . + * + * Furthermore, the adversary is able to verify that he has the correct K cus by + * checking whether z [0] = DES enc (K_cus , ~K_cus ). + * @param keytable an array (128 bytes) of hash2(kcus) + * @param master_key where to put the master key + * @return 0 for ok, 1 for failz + */ +int calculateMasterKey(uint8_t first16bytes[], uint64_t master_key[] ) +{ + des_context ctx_e = {DES_ENCRYPT,{0}}; + + uint8_t z_0[8] = {0}; + uint8_t y_0[8] = {0}; + uint8_t z_0_rev[8] = {0}; + uint8_t key64[8] = {0}; + uint8_t key64_negated[8] = {0}; + uint8_t result[8] = {0}; + + // y_0 and z_0 are the first 16 bytes of the keytable + memcpy(y_0,first16bytes,8); + memcpy(z_0,first16bytes+8,8); + + // Our DES-implementation uses the standard NIST + // format for keys, thus must translate from iclass + // format to NIST-format + permutekey_rev(z_0, z_0_rev); + + // ~K_cus = DESenc(z[0], y[0]) + des_setkey_enc( &ctx_e, z_0_rev ); + des_crypt_ecb(&ctx_e, y_0, key64_negated); + + int i; + for(i = 0; i < 8 ; i++) + { + key64[i] = ~key64_negated[i]; + } + + // Can we verify that the key is correct? + // Once again, key is on iclass-format + uint8_t key64_stdformat[8] = {0}; + permutekey_rev(key64, key64_stdformat); + + des_setkey_enc( &ctx_e, key64_stdformat ); + des_crypt_ecb(&ctx_e, key64_negated, result); + prnlog("\nHigh security custom key (Kcus):"); + printvar("Std format ", key64_stdformat,8); + printvar("Iclass format", key64,8); + + if(master_key != NULL) + memcpy(master_key, key64, 8); + + if(memcmp(z_0,result,4) != 0) + { + prnlog("Failed to verify calculated master key (k_cus)! Something is wrong."); + return 1; + }else{ + prnlog("Key verified ok!\n"); + } + return 0; +} +/** + * @brief Same as bruteforcefile, but uses a an array of dumpdata instead + * @param dump + * @param dumpsize + * @param keytable + * @return + */ +int bruteforceDump(uint8_t dump[], size_t dumpsize, uint16_t keytable[]) +{ + uint8_t i; + int errors = 0; + size_t itemsize = sizeof(dumpdata); + clock_t t1 = clock(); + + dumpdata* attack = (dumpdata* ) malloc(itemsize); + + for(i = 0 ; i * itemsize < dumpsize ; i++ ) + { + memcpy(attack,dump+i*itemsize, itemsize); + errors += bruteforceItem(*attack, keytable); + } + free(attack); + clock_t t2 = clock(); + float diff = (((float)t2 - (float)t1) / CLOCKS_PER_SEC ); + prnlog("\nPerformed full crack in %f seconds",diff); + + // Pick out the first 16 bytes of the keytable. + // The keytable is now in 16-bit ints, where the upper 8 bits + // indicate crack-status. Those must be discarded for the + // master key calculation + uint8_t first16bytes[16] = {0}; + + for(i = 0 ; i < 16 ; i++) + { + first16bytes[i] = keytable[i] & 0xFF; + if(!(keytable[i] & CRACKED)) + { + prnlog("Error, we are missing byte %d, custom key calculation will fail...", i); + } + } + errors += calculateMasterKey(first16bytes, NULL); + return errors; +} +/** + * Perform a bruteforce against a file which has been saved by pm3 + * + * @brief bruteforceFile + * @param filename + * @return + */ +int bruteforceFile(const char *filename, uint16_t keytable[]) +{ + + FILE *f = fopen(filename, "rb"); + if(!f) { + prnlog("Failed to read from file '%s'", filename); + return 1; + } + + fseek(f, 0, SEEK_END); + long fsize = ftell(f); + fseek(f, 0, SEEK_SET); + + uint8_t *dump = malloc(fsize); + size_t bytes_read = fread(dump, fsize, 1, f); + + fclose(f); + if (bytes_read < fsize) + { + prnlog("Error, could only read %d bytes (should be %d)",bytes_read, fsize ); + } + return bruteforceDump(dump,fsize,keytable); +} +/** + * + * @brief Same as above, if you don't care about the returned keytable (results only printed on screen) + * @param filename + * @return + */ +int bruteforceFileNoKeys(const char *filename) +{ + uint16_t keytable[128] = {0}; + return bruteforceFile(filename, keytable); +} + +// --------------------------------------------------------------------------------- +// ALL CODE BELOW THIS LINE IS PURELY TESTING +// --------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- +// TEST CODE BELOW +// ---------------------------------------------------------------------------- + +int _testBruteforce() +{ + int errors = 0; + if(true){ + // First test + prnlog("[+] Testing crack from dumpfile..."); + + /** + Expected values for the dumpfile: + High Security Key Table + + 00 F1 35 59 A1 0D 5A 26 7F 18 60 0B 96 8A C0 25 C1 + 10 BF A1 3B B0 FF 85 28 75 F2 1F C6 8F 0E 74 8F 21 + 20 14 7A 55 16 C8 A9 7D B3 13 0C 5D C9 31 8D A9 B2 + 30 A3 56 83 0F 55 7E DE 45 71 21 D2 6D C1 57 1C 9C + 40 78 2F 64 51 42 7B 64 30 FA 26 51 76 D3 E0 FB B6 + 50 31 9F BF 2F 7E 4F 94 B4 BD 4F 75 91 E3 1B EB 42 + 60 3F 88 6F B8 6C 2C 93 0D 69 2C D5 20 3C C1 61 95 + 70 43 08 A0 2F FE B3 26 D7 98 0B 34 7B 47 70 A0 AB + + **** The 64-bit HS Custom Key Value = 5B7C62C491C11B39 **** + **/ + uint16_t keytable[128] = {0}; + //save some time... + startvalue = 0x7B0000; + errors |= bruteforceFile("iclass_dump.bin",keytable); + } + return errors; +} + +int _test_iclass_key_permutation() +{ + uint8_t testcase[8] = {0x6c,0x8d,0x44,0xf9,0x2a,0x2d,0x01,0xbf}; + uint8_t testcase_output[8] = {0}; + uint8_t testcase_output_correct[8] = {0x8a,0x0d,0xb9,0x88,0xbb,0xa7,0x90,0xea}; + uint8_t testcase_output_rev[8] = {0}; + permutekey(testcase, testcase_output); + permutekey_rev(testcase_output, testcase_output_rev); + + + if(memcmp(testcase_output, testcase_output_correct,8) != 0) + { + prnlog("Error with iclass key permute!"); + printarr("testcase_output", testcase_output, 8); + printarr("testcase_output_correct", testcase_output_correct, 8); + return 1; + + } + if(memcmp(testcase, testcase_output_rev, 8) != 0) + { + prnlog("Error with reverse iclass key permute"); + printarr("testcase", testcase, 8); + printarr("testcase_output_rev", testcase_output_rev, 8); + return 1; + } + + prnlog("[+] Iclass key permutation OK!"); + return 0; +} + +int testElite() +{ + prnlog("[+] Testing iClass Elite functinality..."); + prnlog("[+] Testing hash2"); + uint8_t k_cus[8] = {0x5B,0x7C,0x62,0xC4,0x91,0xC1,0x1B,0x39}; + + /** + *Expected: + * High Security Key Table + +00 F1 35 59 A1 0D 5A 26 7F 18 60 0B 96 8A C0 25 C1 +10 BF A1 3B B0 FF 85 28 75 F2 1F C6 8F 0E 74 8F 21 +20 14 7A 55 16 C8 A9 7D B3 13 0C 5D C9 31 8D A9 B2 +30 A3 56 83 0F 55 7E DE 45 71 21 D2 6D C1 57 1C 9C +40 78 2F 64 51 42 7B 64 30 FA 26 51 76 D3 E0 FB B6 +50 31 9F BF 2F 7E 4F 94 B4 BD 4F 75 91 E3 1B EB 42 +60 3F 88 6F B8 6C 2C 93 0D 69 2C D5 20 3C C1 61 95 +70 43 08 A0 2F FE B3 26 D7 98 0B 34 7B 47 70 A0 AB + + + +**** The 64-bit HS Custom Key Value = 5B7C62C491C11B39 **** + */ + uint8_t keytable[128] = {0}; + hash2(k_cus, keytable); + printarr_human_readable("Hash2", keytable, 128); + if(keytable[3] == 0xA1 && keytable[0x30] == 0xA3 && keytable[0x6F] == 0x95) + { + prnlog("[+] Hash2 looks fine..."); + } + + prnlog("[+] Testing key diversification ..."); + + int errors = 0 ; + errors +=_test_iclass_key_permutation(); + errors += _testBruteforce(); + return errors; + +} + diff --git a/client/loclass/elite_crack.h b/client/loclass/elite_crack.h new file mode 100644 index 00000000..21004e59 --- /dev/null +++ b/client/loclass/elite_crack.h @@ -0,0 +1,108 @@ +#ifndef ELITE_CRACK_H +#define ELITE_CRACK_H +void permutekey(uint8_t key[8], uint8_t dest[8]); +/** + * Permutes a key from iclass specific format to NIST format + * @brief permutekey_rev + * @param key + * @param dest + */ +void permutekey_rev(uint8_t key[8], uint8_t dest[8]); +//Crack status, see below +#define CRACKED 0x0100 +#define BEING_CRACKED 0x0200 +#define CRACK_FAILED 0x0400 + +/** + * Perform a bruteforce against a file which has been saved by pm3 + * + * @brief bruteforceFile + * @param filename + * @param keytable an arrah (128 x 16 bit ints). This is where the keydata is stored. + * OBS! the upper part of the 16 bits store crack-status, + * @return + */ +int bruteforceFile(const char *filename, uint16_t keytable[]); +/** + * + * @brief Same as above, if you don't care about the returned keytable (results only printed on screen) + * @param filename + * @return + */ +int bruteforceFileNoKeys(const char *filename); +/** + * @brief Same as bruteforcefile, but uses a an array of dumpdata instead + * @param dump + * @param dumpsize + * @param keytable + * @return + */ +int bruteforceDump(uint8_t dump[], size_t dumpsize, uint16_t keytable[]); + +/** + This is how we expect each 'entry' in a dumpfile to look +**/ +typedef struct { + uint8_t csn[8]; + uint8_t cc_nr[12]; + uint8_t mac[4]; + +}dumpdata; + +/** + * @brief Performs brute force attack against a dump-data item, containing csn, cc_nr and mac. + *This method calculates the hash1 for the CSN, and determines what bytes need to be bruteforced + *on the fly. If it finds that more than three bytes need to be bruteforced, it aborts. + *It updates the keytable with the findings, also using the upper half of the 16-bit ints + *to signal if the particular byte has been cracked or not. + * + * @param dump The dumpdata from iclass reader attack. + * @param keytable where to write found values. + * @return + */ +int bruteforceItem(dumpdata item, uint16_t keytable[]); +/** + * Hash1 takes CSN as input, and determines what bytes in the keytable will be used + * when constructing the K_sel. + * @param csn the CSN used + * @param k output + */ +void hash1(uint8_t csn[] , uint8_t k[]); +void hash2(uint8_t *key64, uint8_t *outp_keytable); +/** + * From dismantling iclass-paper: + * Assume that an adversary somehow learns the first 16 bytes of hash2(K_cus ), i.e., y [0] and z [0] . + * Then he can simply recover the master custom key K_cus by computing + * K_cus = ~DES(z[0] , y[0] ) . + * + * Furthermore, the adversary is able to verify that he has the correct K cus by + * checking whether z [0] = DES enc (K_cus , ~K_cus ). + * @param keytable an array (128 bytes) of hash2(kcus) + * @param master_key where to put the master key + * @return 0 for ok, 1 for failz + */ +int calculateMasterKey(uint8_t first16bytes[], uint64_t master_key[] ); + +/** + * @brief Test function + * @return + */ +int testElite(); + +/** + Here are some pretty optimal values that can be used to recover necessary data in only + eight auth attempts. +// CSN HASH1 Bytes recovered // +{ {0x00,0x0B,0x0F,0xFF,0xF7,0xFF,0x12,0xE0} , {0x01,0x01,0x00,0x00,0x45,0x01,0x45,0x45 } ,{0,1 }}, +{ {0x00,0x13,0x94,0x7e,0x76,0xff,0x12,0xe0} , {0x02,0x0c,0x01,0x00,0x45,0x01,0x45,0x45} , {2,12}}, +{ {0x2a,0x99,0xac,0x79,0xec,0xff,0x12,0xe0} , {0x07,0x45,0x0b,0x00,0x45,0x01,0x45,0x45} , {7,11}}, +{ {0x17,0x12,0x01,0xfd,0xf7,0xff,0x12,0xe0} , {0x03,0x0f,0x00,0x00,0x45,0x01,0x45,0x45} , {3,15}}, +{ {0xcd,0x56,0x01,0x7c,0x6f,0xff,0x12,0xe0} , {0x04,0x00,0x08,0x00,0x45,0x01,0x45,0x45} , {4,8}}, +{ {0x4b,0x5e,0x0b,0x72,0xef,0xff,0x12,0xe0} , {0x0e,0x06,0x08,0x00,0x45,0x01,0x45,0x45} , {6,14}}, +{ {0x00,0x73,0xd8,0x75,0x58,0xff,0x12,0xe0} , {0x0b,0x09,0x0f,0x00,0x45,0x01,0x05,0x45} , {9,5}}, +{ {0x0c,0x90,0x32,0xf3,0x5d,0xff,0x12,0xe0} , {0x0d,0x0f,0x0a,0x00,0x45,0x01,0x05,0x45} , {10,13}}, + +**/ + + +#endif diff --git a/client/loclass/fileutils.c b/client/loclass/fileutils.c new file mode 100644 index 00000000..08b81ec0 --- /dev/null +++ b/client/loclass/fileutils.c @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include +#include "fileutils.h" +#include "ui.h" +/** + * @brief checks if a file exists + * @param filename + * @return + */ +int fileExists(const char *filename) { + struct _stat st; + int result = stat(filename, &st); + return result == 0; +} + +int saveFile(const char *preferredName, const char *suffix, const void* data, size_t datalen) +{ + int size = sizeof(char) * (strlen(preferredName)+strlen(suffix)+5); + char * fileName = malloc(size); + + memset(fileName,0,size); + int num = 1; + sprintf(fileName,"%s.%s", preferredName, suffix); + while(fileExists(fileName)) + { + sprintf(fileName,"%s-%d.%s", preferredName, num, suffix); + num++; + } + /* We should have a valid filename now, e.g. dumpdata-3.bin */ + + /*Opening file for writing in binary mode*/ + FILE *fileHandle=fopen(fileName,"wb"); + if(!fileHandle) { + prnlog("Failed to write to file '%s'", fileName); + return 1; + } + fwrite(data, 1, datalen, fileHandle); + fclose(fileHandle); + prnlog("Saved data to '%s'", fileName); + free(fileName); + + return 0; +} + +/** + * Utility function to print to console. This is used consistently within the library instead + * of printf, but it actually only calls printf (and adds a linebreak). + * The reason to have this method is to + * make it simple to plug this library into proxmark, which has this function already to + * write also to a logfile. When doing so, just delete this function. + * @param fmt + */ +void prnlog(char *fmt, ...) +{ + + va_list args; + va_start(args,fmt); + PrintAndLog(fmt, args); + //vprintf(fmt,args); + va_end(args); + //printf("\n"); +} diff --git a/client/loclass/fileutils.h b/client/loclass/fileutils.h new file mode 100644 index 00000000..a0f5a799 --- /dev/null +++ b/client/loclass/fileutils.h @@ -0,0 +1,24 @@ +#ifndef FILEUTILS_H +#define FILEUTILS_H +/** + * @brief Utility function to save data to a file. This method takes a preferred name, but if that + * file already exists, it tries with another name until it finds something suitable. + * E.g. dumpdata-15.txt + * @param preferredName + * @param suffix the file suffix. Leave out the ".". + * @param data The binary data to write to the file + * @param datalen the length of the data + * @return 0 for ok, 1 for failz + */ +int saveFile(const char *preferredName, const char *suffix, const void* data, size_t datalen); + + +/** + * Utility function to print to console. This is used consistently within the library instead + * of printf, but it actually only calls printf. The reason to have this method is to + *make it simple to plug this library into proxmark, which has this function already to + * write also to a logfile. When doing so, just point this function to use PrintAndLog + * @param fmt + */ +void prnlog(char *fmt, ...); +#endif // FILEUTILS_H diff --git a/client/loclass/ikeys.c b/client/loclass/ikeys.c new file mode 100644 index 00000000..cd2b72ee --- /dev/null +++ b/client/loclass/ikeys.c @@ -0,0 +1,878 @@ +/***************************************************************************** + * This file is part of iClassCipher. It is a reconstructon of the cipher engine + * used in iClass, and RFID techology. + * + * The implementation is based on the work performed by + * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and + * Milosch Meriac in the paper "Dismantling IClass". + * + * This is a reference implementation of iclass key diversification. I'm sure it can be + * optimized heavily. It is written for ease of understanding and correctness, please take it + * and tweak it and make a super fast version instead, using this for testing and verification. + + * Copyright (C) 2014 Martin Holst Swende + * + * 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. + * + * This file 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 IClassCipher. If not, see . + ****************************************************************************/ +/** + + +From "Dismantling iclass": + This section describes in detail the built-in key diversification algorithm of iClass. + Besides the obvious purpose of deriving a card key from a master key, this + algorithm intends to circumvent weaknesses in the cipher by preventing the + usage of certain ‘weak’ keys. In order to compute a diversified key, the iClass + reader first encrypts the card identity id with the master key K, using single + DES. The resulting ciphertext is then input to a function called hash0 which + outputs the diversified key k. + + k = hash0(DES enc (id, K)) + + Here the DES encryption of id with master key K outputs a cryptogram c + of 64 bits. These 64 bits are divided as c = x, y, z [0] , . . . , z [7] ∈ F 82 × F 82 × (F 62 ) 8 + which is used as input to the hash0 function. This function introduces some + obfuscation by performing a number of permutations, complement and modulo + operations, see Figure 2.5. Besides that, it checks for and removes patterns like + similar key bytes, which could produce a strong bias in the cipher. Finally, the + output of hash0 is the diversified card key k = k [0] , . . . , k [7] ∈ (F 82 ) 8 . + + +**/ + + +#include +#include +#include +#include +#include +#include "fileutils.h" +#include "cipherutils.h" +#include "des.h" + +uint8_t pi[35] = {0x0F,0x17,0x1B,0x1D,0x1E,0x27,0x2B,0x2D,0x2E,0x33,0x35,0x39,0x36,0x3A,0x3C,0x47,0x4B,0x4D,0x4E,0x53,0x55,0x56,0x59,0x5A,0x5C,0x63,0x65,0x66,0x69,0x6A,0x6C,0x71,0x72,0x74,0x78}; + +static des_context ctx_enc = {DES_ENCRYPT,{0}}; +static des_context ctx_dec = {DES_DECRYPT,{0}}; + +static int debug_print = 0; + +/** + * @brief The key diversification algorithm uses 6-bit bytes. + * This implementation uses 64 bit uint to pack seven of them into one + * variable. When they are there, they are placed as follows: + * XXXX XXXX N0 .... N7, occupying the lsat 48 bits. + * + * This function picks out one from such a collection + * @param all + * @param n bitnumber + * @return + */ +uint8_t getSixBitByte(uint64_t c, int n) +{ + return (c >> (42-6*n)) & 0x3F; +} + +/** + * @brief Puts back a six-bit 'byte' into a uint64_t. + * @param c buffer + * @param z the value to place there + * @param n bitnumber. + */ +void pushbackSixBitByte(uint64_t *c, uint8_t z, int n) +{ + //0x XXXX YYYY ZZZZ ZZZZ ZZZZ + // ^z0 ^z7 + //z0: 1111 1100 0000 0000 + + uint64_t masked = z & 0x3F; + uint64_t eraser = 0x3F; + masked <<= 42-6*n; + eraser <<= 42-6*n; + + //masked <<= 6*n; + //eraser <<= 6*n; + + eraser = ~eraser; + (*c) &= eraser; + (*c) |= masked; + +} +/** + * @brief Swaps the z-values. + * If the input value has format XYZ0Z1...Z7, the output will have the format + * XYZ7Z6...Z0 instead + * @param c + * @return + */ +uint64_t swapZvalues(uint64_t c) +{ + uint64_t newz = 0; + pushbackSixBitByte(&newz, getSixBitByte(c,0),7); + pushbackSixBitByte(&newz, getSixBitByte(c,1),6); + pushbackSixBitByte(&newz, getSixBitByte(c,2),5); + pushbackSixBitByte(&newz, getSixBitByte(c,3),4); + pushbackSixBitByte(&newz, getSixBitByte(c,4),3); + pushbackSixBitByte(&newz, getSixBitByte(c,5),2); + pushbackSixBitByte(&newz, getSixBitByte(c,6),1); + pushbackSixBitByte(&newz, getSixBitByte(c,7),0); + newz |= (c & 0xFFFF000000000000); + return newz; +} + +/** +* @return 4 six-bit bytes chunked into a uint64_t,as 00..00a0a1a2a3 +*/ +uint64_t ck(int i, int j, uint64_t z) +{ + + if(i == 1 && j == -1) + { + // ck(1, −1, z [0] . . . z [3] ) = z [0] . . . z [3] + return z; + + }else if( j == -1) + { + // ck(i, −1, z [0] . . . z [3] ) = ck(i − 1, i − 2, z [0] . . . z [3] ) + return ck(i-1,i-2, z); + } + + if(getSixBitByte(z,i) == getSixBitByte(z,j)) + { + + //ck(i, j − 1, z [0] . . . z [i] ← j . . . z [3] ) + uint64_t newz = 0; + int c; + for(c = 0; c < 4 ;c++) + { + uint8_t val = getSixBitByte(z,c); + if(c == i) + { + pushbackSixBitByte(&newz, j, c); + }else + { + pushbackSixBitByte(&newz, val, c); + } + } + return ck(i,j-1,newz); + }else + { + return ck(i,j-1,z); + } +} +/** + + Definition 8. + Let the function check : (F 62 ) 8 → (F 62 ) 8 be defined as + check(z [0] . . . z [7] ) = ck(3, 2, z [0] . . . z [3] ) · ck(3, 2, z [4] . . . z [7] ) + + where ck : N × N × (F 62 ) 4 → (F 62 ) 4 is defined as + + ck(1, −1, z [0] . . . z [3] ) = z [0] . . . z [3] + ck(i, −1, z [0] . . . z [3] ) = ck(i − 1, i − 2, z [0] . . . z [3] ) + ck(i, j, z [0] . . . z [3] ) = + ck(i, j − 1, z [0] . . . z [i] ← j . . . z [3] ), if z [i] = z [j] ; + ck(i, j − 1, z [0] . . . z [3] ), otherwise + + otherwise. +**/ + +uint64_t check(uint64_t z) +{ + //These 64 bits are divided as c = x, y, z [0] , . . . , z [7] + + // ck(3, 2, z [0] . . . z [3] ) + uint64_t ck1 = ck(3,2, z ); + + // ck(3, 2, z [4] . . . z [7] ) + uint64_t ck2 = ck(3,2, z << 24); + + //The ck function will place the values + // in the middle of z. + ck1 &= 0x00000000FFFFFF000000; + ck2 &= 0x00000000FFFFFF000000; + + return ck1 | ck2 >> 24; + +} + +void permute(BitstreamIn *p_in, uint64_t z,int l,int r, BitstreamOut* out) +{ + if(bitsLeft(p_in) == 0) + { + return; + } + bool pn = tailBit(p_in); + if( pn ) // pn = 1 + { + uint8_t zl = getSixBitByte(z,l); + + push6bits(out, zl+1); + permute(p_in, z, l+1,r, out); + }else // otherwise + { + uint8_t zr = getSixBitByte(z,r); + + push6bits(out, zr); + permute(p_in,z,l,r+1,out); + } +} +void printbegin() +{ + if(debug_print <2) + return ; + + prnlog(" | x| y|z0|z1|z2|z3|z4|z5|z6|z7|"); +} + +void printState(char* desc, uint64_t c) +{ + if(debug_print < 2) + return ; + + printf("%s : ", desc); + uint8_t x = (c & 0xFF00000000000000 ) >> 56; + uint8_t y = (c & 0x00FF000000000000 ) >> 48; + printf(" %02x %02x", x,y); + int i ; + for(i =0 ; i < 8 ; i++) + { + printf(" %02x", getSixBitByte(c,i)); + } + printf("\n"); +} + +/** + * @brief + *Definition 11. Let the function hash0 : F 82 × F 82 × (F 62 ) 8 → (F 82 ) 8 be defined as + * hash0(x, y, z [0] . . . z [7] ) = k [0] . . . k [7] where + * z'[i] = (z[i] mod (63-i)) + i i = 0...3 + * z'[i+4] = (z[i+4] mod (64-i)) + i i = 0...3 + * ẑ = check(z'); + * @param c + * @param k this is where the diversified key is put (should be 8 bytes) + * @return + */ +void hash0(uint64_t c, uint8_t k[8]) +{ + c = swapZvalues(c); + + printbegin(); + printState("origin",c); + //These 64 bits are divided as c = x, y, z [0] , . . . , z [7] + // x = 8 bits + // y = 8 bits + // z0-z7 6 bits each : 48 bits + uint8_t x = (c & 0xFF00000000000000 ) >> 56; + uint8_t y = (c & 0x00FF000000000000 ) >> 48; + int n; + uint8_t zn, zn4, _zn, _zn4; + uint64_t zP = 0; + + for(n = 0; n < 4 ; n++) + { + zn = getSixBitByte(c,n); + + zn4 = getSixBitByte(c,n+4); + + _zn = (zn % (63-n)) + n; + _zn4 = (zn4 % (64-n)) + n; + + + pushbackSixBitByte(&zP, _zn,n); + pushbackSixBitByte(&zP, _zn4,n+4); + + } + printState("0|0|z'",zP); + + uint64_t zCaret = check(zP); + printState("0|0|z^",zP); + + + uint8_t p = pi[x % 35]; + + if(x & 1) //Check if x7 is 1 + { + p = ~p; + } + + if(debug_print >= 2) prnlog("p:%02x", p); + + BitstreamIn p_in = { &p, 8,0 }; + uint8_t outbuffer[] = {0,0,0,0,0,0,0,0}; + BitstreamOut out = {outbuffer,0,0}; + permute(&p_in,zCaret,0,4,&out);//returns 48 bits? or 6 8-bytes + + //Out is now a buffer containing six-bit bytes, should be 48 bits + // if all went well + //Shift z-values down onto the lower segment + + uint64_t zTilde = x_bytes_to_num(outbuffer,8); + + zTilde >>= 16; + + printState("0|0|z~", zTilde); + + int i; + int zerocounter =0 ; + for(i =0 ; i < 8 ; i++) + { + + // the key on index i is first a bit from y + // then six bits from z, + // then a bit from p + + // Init with zeroes + k[i] = 0; + // First, place yi leftmost in k + //k[i] |= (y << i) & 0x80 ; + + // First, place y(7-i) leftmost in k + k[i] |= (y << (7-i)) & 0x80 ; + + + + uint8_t zTilde_i = getSixBitByte(zTilde, i); + // zTildeI is now on the form 00XXXXXX + // with one leftshift, it'll be + // 0XXXXXX0 + // So after leftshift, we can OR it into k + // However, when doing complement, we need to + // again MASK 0XXXXXX0 (0x7E) + zTilde_i <<= 1; + + //Finally, add bit from p or p-mod + //Shift bit i into rightmost location (mask only after complement) + uint8_t p_i = p >> i & 0x1; + + if( k[i] )// yi = 1 + { + //printf("k[%d] +1\n", i); + k[i] |= ~zTilde_i & 0x7E; + k[i] |= p_i & 1; + k[i] += 1; + + }else // otherwise + { + k[i] |= zTilde_i & 0x7E; + k[i] |= (~p_i) & 1; + } + if((k[i] & 1 )== 0) + { + zerocounter ++; + } + } +} +/** + * @brief Performs Elite-class key diversification + * @param csn + * @param key + * @param div_key + */ +void diversifyKey(uint8_t csn[8], uint8_t key[8], uint8_t div_key[8]) +{ + + // Prepare the DES key + des_setkey_enc( &ctx_enc, key); + + uint8_t crypted_csn[8] = {0}; + + // Calculate DES(CSN, KEY) + des_crypt_ecb(&ctx_enc,csn, crypted_csn); + + //Calculate HASH0(DES)) + uint64_t crypt_csn = x_bytes_to_num(crypted_csn, 8); + //uint64_t crypted_csn_swapped = swapZvalues(crypt_csn); + + hash0(crypt_csn,div_key); +} + + + + + +void testPermute() +{ + + uint64_t x = 0; + pushbackSixBitByte(&x,0x00,0); + pushbackSixBitByte(&x,0x01,1); + pushbackSixBitByte(&x,0x02,2); + pushbackSixBitByte(&x,0x03,3); + pushbackSixBitByte(&x,0x04,4); + pushbackSixBitByte(&x,0x05,5); + pushbackSixBitByte(&x,0x06,6); + pushbackSixBitByte(&x,0x07,7); + + uint8_t mres[8] = { getSixBitByte(x, 0), + getSixBitByte(x, 1), + getSixBitByte(x, 2), + getSixBitByte(x, 3), + getSixBitByte(x, 4), + getSixBitByte(x, 5), + getSixBitByte(x, 6), + getSixBitByte(x, 7)}; + printarr("input_perm", mres,8); + + uint8_t p = ~pi[0]; + BitstreamIn p_in = { &p, 8,0 }; + uint8_t outbuffer[] = {0,0,0,0,0,0,0,0}; + BitstreamOut out = {outbuffer,0,0}; + + permute(&p_in, x,0,4, &out); + + uint64_t permuted = x_bytes_to_num(outbuffer,8); + //printf("zTilde 0x%"PRIX64"\n", zTilde); + permuted >>= 16; + + uint8_t res[8] = { getSixBitByte(permuted, 0), + getSixBitByte(permuted, 1), + getSixBitByte(permuted, 2), + getSixBitByte(permuted, 3), + getSixBitByte(permuted, 4), + getSixBitByte(permuted, 5), + getSixBitByte(permuted, 6), + getSixBitByte(permuted, 7)}; + printarr("permuted", res, 8); +} + +//These testcases are +//{ UID , TEMP_KEY, DIV_KEY} using the specific key +typedef struct +{ + uint8_t uid[8]; + uint8_t t_key[8]; + uint8_t div_key[8]; +} Testcase; + + +int testDES(Testcase testcase, des_context ctx_enc, des_context ctx_dec) +{ + uint8_t des_encrypted_csn[8] = {0}; + uint8_t decrypted[8] = {0}; + uint8_t div_key[8] = {0}; + int retval = des_crypt_ecb(&ctx_enc,testcase.uid,des_encrypted_csn); + retval |= des_crypt_ecb(&ctx_dec,des_encrypted_csn,decrypted); + + if(memcmp(testcase.uid,decrypted,8) != 0) + { + //Decryption fail + prnlog("Encryption <-> Decryption FAIL"); + printarr("Input", testcase.uid, 8); + printarr("Decrypted", decrypted, 8); + retval = 1; + } + + if(memcmp(des_encrypted_csn,testcase.t_key,8) != 0) + { + //Encryption fail + prnlog("Encryption != Expected result"); + printarr("Output", des_encrypted_csn, 8); + printarr("Expected", testcase.t_key, 8); + retval = 1; + } + uint64_t crypted_csn = x_bytes_to_num(des_encrypted_csn,8); + hash0(crypted_csn, div_key); + + if(memcmp(div_key, testcase.div_key ,8) != 0) + { + //Key diversification fail + prnlog("Div key != expected result"); + printarr(" csn ", testcase.uid,8); + printarr("{csn} ", des_encrypted_csn,8); + printarr("hash0 ", div_key, 8); + printarr("Expected", testcase.div_key, 8); + retval = 1; + + } + return retval; +} +bool des_getParityBitFromKey(uint8_t key) +{//The top 7 bits is used + bool parity = ((key & 0x80) >> 7) + ^ ((key & 0x40) >> 6) ^ ((key & 0x20) >> 5) + ^ ((key & 0x10) >> 4) ^ ((key & 0x08) >> 3) + ^ ((key & 0x04) >> 2) ^ ((key & 0x02) >> 1); + return !parity; +} + + +void des_checkParity(uint8_t* key) +{ + int i; + int fails =0; + for(i =0 ; i < 8 ; i++) + { + bool parity = des_getParityBitFromKey(key[i]); + if(parity != (key[i] & 0x1)) + { + fails++; + prnlog("[+] parity1 fail, byte %d [%02x] was %d, should be %d",i,key[i],(key[i] & 0x1),parity); + } + } + if(fails) + { + prnlog("[+] parity fails: %d", fails); + }else + { + prnlog("[+] Key syntax is with parity bits inside each byte"); + } +} + +Testcase testcases[] ={ + + {{0x8B,0xAC,0x60,0x1F,0x53,0xB8,0xED,0x11},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x05,0x07}}, + {{0xAE,0x51,0xE5,0x62,0xE7,0x9A,0x99,0x39},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01},{0x04,0x02,0x06,0x08,0x01,0x03,0x05,0x07}}, + {{0x9B,0x21,0xE4,0x31,0x6A,0x00,0x29,0x62},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02},{0x06,0x04,0x02,0x08,0x01,0x03,0x05,0x07}}, + {{0x65,0x24,0x0C,0x41,0x4F,0xC2,0x21,0x93},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04},{0x0A,0x04,0x06,0x08,0x01,0x03,0x05,0x07}}, + {{0x7F,0xEB,0xAE,0x93,0xE5,0x30,0x08,0xBD},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08},{0x12,0x04,0x06,0x08,0x01,0x03,0x05,0x07}}, + {{0x49,0x7B,0x70,0x74,0x9B,0x35,0x1B,0x83},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10},{0x22,0x04,0x06,0x08,0x01,0x03,0x05,0x07}}, + {{0x02,0x3C,0x15,0x6B,0xED,0xA5,0x64,0x6C},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20},{0x42,0x04,0x06,0x08,0x01,0x03,0x05,0x07}}, + {{0xE8,0x37,0xE0,0xE2,0xC6,0x45,0x24,0xF3},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40},{0x02,0x06,0x04,0x08,0x01,0x03,0x05,0x07}}, + {{0xAB,0xBD,0x30,0x05,0x29,0xC8,0xF7,0x12},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80},{0x02,0x08,0x06,0x04,0x01,0x03,0x05,0x07}}, + {{0x17,0xE8,0x97,0xF0,0x99,0xB6,0x79,0x31},{0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00},{0x02,0x0C,0x06,0x08,0x01,0x03,0x05,0x07}}, + {{0x49,0xA4,0xF0,0x8F,0x5F,0x96,0x83,0x16},{0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00},{0x02,0x14,0x06,0x08,0x01,0x03,0x05,0x07}}, + {{0x60,0xF5,0x7E,0x54,0xAA,0x41,0x83,0xD4},{0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00},{0x02,0x24,0x06,0x08,0x01,0x03,0x05,0x07}}, + {{0x1D,0xF6,0x3B,0x6B,0x85,0x55,0xF0,0x4B},{0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00},{0x02,0x44,0x06,0x08,0x01,0x03,0x05,0x07}}, + {{0x1F,0xDC,0x95,0x1A,0xEA,0x6B,0x4B,0xB4},{0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00},{0x02,0x04,0x08,0x06,0x01,0x03,0x05,0x07}}, + {{0xEC,0x93,0x72,0xF0,0x3B,0xA9,0xF5,0x0B},{0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00},{0x02,0x04,0x0A,0x08,0x01,0x03,0x05,0x07}}, + {{0xDE,0x57,0x5C,0xBE,0x2D,0x55,0x03,0x12},{0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00},{0x02,0x04,0x0E,0x08,0x01,0x03,0x05,0x07}}, + {{0x1E,0xD2,0xB5,0xCE,0x90,0xC9,0xC1,0xCC},{0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00},{0x02,0x04,0x16,0x08,0x01,0x03,0x05,0x07}}, + {{0xD8,0x65,0x96,0x4E,0xE7,0x74,0x99,0xB8},{0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00},{0x02,0x04,0x26,0x08,0x01,0x03,0x05,0x07}}, + {{0xE3,0x7A,0x29,0x83,0x31,0xD5,0x3A,0x54},{0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00},{0x02,0x04,0x46,0x08,0x01,0x03,0x05,0x07}}, + {{0x3A,0xB5,0x1A,0x34,0x34,0x25,0x12,0xF0},{0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00},{0x02,0x04,0x06,0x0A,0x01,0x03,0x05,0x07}}, + {{0xF2,0x88,0xEE,0x6F,0x70,0x6F,0xC2,0x52},{0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00},{0x02,0x04,0x06,0x0C,0x01,0x03,0x05,0x07}}, + {{0x76,0xEF,0xEB,0x80,0x52,0x43,0x83,0x57},{0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00},{0x02,0x04,0x06,0x10,0x01,0x03,0x05,0x07}}, + {{0x1C,0x09,0x8E,0x3B,0x23,0x23,0x52,0xB5},{0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00},{0x02,0x04,0x06,0x18,0x01,0x03,0x05,0x07}}, + {{0xA9,0x13,0xA2,0xBE,0xCF,0x1A,0xC4,0x9A},{0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00},{0x02,0x04,0x06,0x28,0x01,0x03,0x05,0x07}}, + {{0x25,0x56,0x4B,0xB0,0xC8,0x2A,0xD4,0x27},{0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00},{0x02,0x04,0x06,0x48,0x01,0x03,0x05,0x07}}, + {{0xB1,0x04,0x57,0x3F,0xA7,0x16,0x62,0xD4},{0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x03,0x01,0x05,0x07}}, + {{0x45,0x46,0xED,0xCC,0xE7,0xD3,0x8E,0xA3},{0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x05,0x03,0x01,0x07}}, + {{0x22,0x6D,0xB5,0x35,0xE0,0x5A,0xE0,0x90},{0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x09,0x03,0x05,0x07}}, + {{0xB8,0xF5,0xE5,0x44,0xC5,0x98,0x4A,0xBD},{0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x11,0x03,0x05,0x07}}, + {{0xAC,0x78,0x0A,0x23,0x9E,0xF6,0xBC,0xA0},{0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x21,0x03,0x05,0x07}}, + {{0x46,0x6B,0x2D,0x70,0x41,0x17,0xBF,0x3D},{0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x41,0x03,0x05,0x07}}, + {{0x64,0x44,0x24,0x71,0xA2,0x56,0xDF,0xB5},{0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x05,0x03,0x07}}, + {{0xC4,0x00,0x52,0x24,0xA2,0xD6,0x16,0x7A},{0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x07,0x05,0x03}}, + {{0xD8,0x4A,0x80,0x1E,0x95,0x5B,0x70,0xC4},{0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x0B,0x05,0x07}}, + {{0x08,0x56,0x6E,0xB5,0x64,0xD6,0x47,0x4E},{0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x13,0x05,0x07}}, + {{0x41,0x6F,0xBA,0xA4,0xEB,0xAE,0xA0,0x55},{0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x23,0x05,0x07}}, + {{0x62,0x9D,0xDE,0x72,0x84,0x4A,0x53,0xD5},{0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x43,0x05,0x07}}, + {{0x39,0xD3,0x2B,0x66,0xB8,0x08,0x40,0x2E},{0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x07,0x05}}, + {{0xAF,0x67,0xA9,0x18,0x57,0x21,0xAF,0x8D},{0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x09,0x07}}, + {{0x34,0xBC,0x9D,0xBC,0xC4,0xC2,0x3B,0xC8},{0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x0D,0x07}}, + {{0xB6,0x50,0xF9,0x81,0xF6,0xBF,0x90,0x3C},{0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x15,0x07}}, + {{0x71,0x41,0x93,0xA1,0x59,0x81,0xA5,0x52},{0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x25,0x07}}, + {{0x6B,0x00,0xBD,0x74,0x1C,0x3C,0xE0,0x1A},{0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x45,0x07}}, + {{0x76,0xFD,0x0B,0xD0,0x41,0xD2,0x82,0x5D},{0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x05,0x09}}, + {{0xC6,0x3A,0x1C,0x25,0x63,0x5A,0x2F,0x0E},{0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x05,0x0B}}, + {{0xD9,0x0E,0xD7,0x30,0xE2,0xAD,0xA9,0x87},{0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x05,0x0F}}, + {{0x6B,0x81,0xC6,0xD1,0x05,0x09,0x87,0x1E},{0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x05,0x17}}, + {{0xB4,0xA7,0x1E,0x02,0x54,0x37,0x43,0x35},{0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x05,0x27}}, + {{0x45,0x14,0x7C,0x7F,0xE0,0xDE,0x09,0x65},{0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x05,0x47}}, + {{0x78,0xB0,0xF5,0x20,0x8B,0x7D,0xF3,0xDD},{0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00},{0xFE,0x04,0x06,0x08,0x01,0x03,0x05,0x07}}, + {{0x88,0xB3,0x3C,0xE1,0xF7,0x87,0x42,0xA1},{0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0xFC,0x06,0x08,0x01,0x03,0x05,0x07}}, + {{0x11,0x2F,0xB2,0xF7,0xE2,0xB2,0x4F,0x6E},{0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0xFA,0x08,0x01,0x03,0x05,0x07}}, + {{0x25,0x56,0x4E,0xC6,0xEB,0x2D,0x74,0x5B},{0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0xF8,0x01,0x03,0x05,0x07}}, + {{0x7E,0x98,0x37,0xF9,0x80,0x8F,0x09,0x82},{0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0xFF,0x03,0x05,0x07}}, + {{0xF9,0xB5,0x62,0x3B,0xD8,0x7B,0x3C,0x3F},{0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0xFD,0x05,0x07}}, + {{0x29,0xC5,0x2B,0xFA,0xD1,0xFC,0x5C,0xC7},{0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0xFB,0x07}}, + {{0xC1,0xA3,0x09,0x71,0xBD,0x8E,0xAF,0x2F},{0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x05,0xF9}}, + {{0xB6,0xDD,0xD1,0xAD,0xAA,0x15,0x6F,0x29},{0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x01,0x03,0x05,0x02,0x07,0x04,0x06,0x08}}, + {{0x65,0x34,0x03,0x19,0x17,0xB3,0xA3,0x96},{0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x01,0x06,0x08,0x03,0x05,0x07}}, + {{0xF9,0x38,0x43,0x56,0x52,0xE5,0xB1,0xA9},{0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x01,0x02,0x04,0x06,0x08,0x03,0x05,0x07}}, + + {{0xA4,0xA0,0xAF,0xDA,0x48,0xB0,0xA1,0x10},{0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x01,0x02,0x04,0x06,0x03,0x08,0x05,0x07}}, + {{0x55,0x15,0x8A,0x0D,0x48,0x29,0x01,0xD8},{0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x01,0x06,0x03,0x05,0x08,0x07}}, + {{0xC4,0x81,0x96,0x7D,0xA3,0xB7,0x73,0x50},{0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x01,0x02,0x03,0x05,0x04,0x06,0x08,0x07}}, + {{0x36,0x73,0xDF,0xC1,0x1B,0x98,0xA8,0x1D},{0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x01,0x02,0x03,0x04,0x05,0x06,0x08,0x07}}, + {{0xCE,0xE0,0xB3,0x1B,0x41,0xEB,0x15,0x12},{0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x01,0x02,0x03,0x04,0x06,0x05,0x08,0x07}}, + {{0},{0},{0}} +}; + + +int testKeyDiversificationWithMasterkeyTestcases() +{ + + int error = 0; + int i; + + uint8_t empty[8]={0}; + prnlog("[+} Testing encryption/decryption"); + + for (i = 0; memcmp(testcases+i,empty,8) ; i++) { + error += testDES(testcases[i],ctx_enc, ctx_dec); + } + if(error) + { + prnlog("[+] %d errors occurred (%d testcases)", error, i); + }else + { + prnlog("[+] Hashing seems to work (%d testcases)", i); + } + return error; +} + + +void print64bits(char*name, uint64_t val) +{ + printf("%s%08x%08x\n",name,(uint32_t) (val >> 32) ,(uint32_t) (val & 0xFFFFFFFF)); +} + +uint64_t testCryptedCSN(uint64_t crypted_csn, uint64_t expected) +{ + int retval = 0; + uint8_t result[8] = {0}; + if(debug_print) prnlog("debug_print %d", debug_print); + if(debug_print) print64bits(" {csn} ", crypted_csn ); + + uint64_t crypted_csn_swapped = swapZvalues(crypted_csn); + + if(debug_print) print64bits(" {csn-revz} ", crypted_csn_swapped); + + hash0(crypted_csn, result); + uint64_t resultbyte = x_bytes_to_num(result,8 ); + if(debug_print) print64bits(" hash0 " , resultbyte ); + + if(resultbyte != expected ) + { + + if(debug_print) { + prnlog("\n[+] FAIL!"); + print64bits(" expected " , expected ); + } + retval = 1; + + }else + { + if(debug_print) prnlog(" [OK]"); + } + return retval; +} + +int testDES2(uint64_t csn, uint64_t expected) +{ + uint8_t result[8] = {0}; + uint8_t input[8] = {0}; + + print64bits(" csn ", csn); + x_num_to_bytes(csn, 8,input); + + des_crypt_ecb(&ctx_enc,input, result); + + uint64_t crypt_csn = x_bytes_to_num(result, 8); + print64bits(" {csn} ", crypt_csn ); + print64bits(" expected ", expected ); + + if( expected == crypt_csn ) + { + prnlog("[+] OK"); + return 0; + }else + { + return 1; + } +} + +/** + * These testcases come from http://www.proxmark.org/forum/viewtopic.php?pid=10977#p10977 + * @brief doTestsWithKnownInputs + * @return + */ +int doTestsWithKnownInputs() +{ + + // KSel from http://www.proxmark.org/forum/viewtopic.php?pid=10977#p10977 + int errors = 0; + prnlog("[+] Testing DES encryption"); +// uint8_t key[8] = {0x6c,0x8d,0x44,0xf9,0x2a,0x2d,0x01,0xbf}; + prnlog("[+] Testing foo"); + uint8_t key[8] = {0x6c,0x8d,0x44,0xf9,0x2a,0x2d,0x01,0xbf}; + + des_setkey_enc( &ctx_enc, key); + testDES2(0xbbbbaaaabbbbeeee,0xd6ad3ca619659e6b); + + prnlog("[+] Testing hashing algorithm"); + + errors += testCryptedCSN(0x0102030405060708,0x0bdd6512073c460a); + errors += testCryptedCSN(0x1020304050607080,0x0208211405f3381f); + errors += testCryptedCSN(0x1122334455667788,0x2bee256d40ac1f3a); + errors += testCryptedCSN(0xabcdabcdabcdabcd,0xa91c9ec66f7da592); + errors += testCryptedCSN(0xbcdabcdabcdabcda,0x79ca5796a474e19b); + errors += testCryptedCSN(0xcdabcdabcdabcdab,0xa8901b9f7ec76da4); + errors += testCryptedCSN(0xdabcdabcdabcdabc,0x357aa8e0979a5b8d); + errors += testCryptedCSN(0x21ba6565071f9299,0x34e80f88d5cf39ea); + errors += testCryptedCSN(0x14e2adfc5bb7e134,0x6ac90c6508bd9ea3); + + if(errors) + { + prnlog("[+] %d errors occurred (9 testcases)", errors); + }else + { + prnlog("[+] Hashing seems to work (9 testcases)" ); + } + return errors; +} + +int readKeyFile(uint8_t key[8]) +{ + + FILE *f; + + f = fopen("iclass_key.bin", "rb"); + if (f) + { + if(fread(key, sizeof(key), 1, f) == 1) return 0; + } + return 1; + +} + + +int doKeyTests(uint8_t debuglevel) +{ + debug_print = debuglevel; + + prnlog("[+] Checking if the master key is present (iclass_key.bin)..."); + uint8_t key[8] = {0}; + if(readKeyFile(key)) + { + prnlog("[+] Master key not present, will not be able to do all testcases"); + }else + { + + //Test if it's the right key... + uint8_t i; + uint8_t j = 0; + for(i =0 ; i < sizeof(key) ; i++) + j += key[i]; + + if(j != 185) + { + prnlog("[+] A key was loaded, but it does not seem to be the correct one. Aborting these tests"); + }else + { + prnlog("[+] Key present"); + + prnlog("[+] Checking key parity..."); + des_checkParity(key); + des_setkey_enc( &ctx_enc, key); + des_setkey_dec( &ctx_dec, key); + // Test hashing functions + prnlog("[+] The following tests require the correct 8-byte master key"); + testKeyDiversificationWithMasterkeyTestcases(); + } + } + prnlog("[+] Testing key diversification with non-sensitive keys..."); + doTestsWithKnownInputs(); + return 0; +} + +/** + +void checkParity2(uint8_t* key) +{ + + uint8_t stored_parity = key[7]; + printf("Parity byte: 0x%02x\n", stored_parity); + int i; + int byte; + int fails =0; + BitstreamIn bits = {key, 56, 0}; + + bool parity = 0; + + for(i =0 ; i < 56; i++) + { + + if ( i > 0 && i % 7 == 0) + { + parity = !parity; + bool pbit = stored_parity & (0x80 >> (byte)); + if(parity != pbit) + { + printf("parity2 fail byte %d, should be %d, was %d\n", (i / 7), parity, pbit); + fails++; + } + parity =0 ; + byte = i / 7; + } + parity = parity ^ headBit(&bits); + } + if(fails) + { + printf("parity2 fails: %d\n", fails); + }else + { + printf("Key syntax is with parity bits grouped in the last byte!\n"); + } +} +void modifyKey_put_parity_last(uint8_t * key, uint8_t* output) +{ + uint8_t paritybits = 0; + bool parity =0; + BitstreamOut out = { output, 0,0}; + unsigned int bbyte, bbit; + for(bbyte=0; bbyte <8 ; bbyte++ ) + { + for(bbit =0 ; bbit< 7 ; bbit++) + { + bool bit = *(key+bbyte) & (1 << (7-bbit)); + pushBit(&out,bit); + parity ^= bit; + } + bool paritybit = *(key+bbyte) & 1; + paritybits |= paritybit << (7-bbyte); + parity = 0; + + } + output[7] = paritybits; + printf("Parity byte: %02x\n", paritybits); +} + + * @brief Modifies a key with parity bits last, so that it is formed with parity + * bits inside each byte + * @param key + * @param output + +void modifyKey_put_parity_allover(uint8_t * key, uint8_t* output) +{ + bool parity =0; + BitstreamOut out = { output, 0,0}; + BitstreamIn in = {key, 0,0}; + unsigned int bbyte, bbit; + for(bbit =0 ; bbit < 56 ; bbit++) + { + + if( bbit > 0 && bbit % 7 == 0) + { + pushBit(&out,!parity); + parity = 0; + } + bool bit = headBit(&in); + pushBit(&out,bit ); + parity ^= bit; + + } + pushBit(&out, !parity); + + + if( des_key_check_key_parity(output)) + { + printf("modifyKey_put_parity_allover fail, DES key invalid parity!"); + } + +} + +*/ + + diff --git a/client/loclass/ikeys.h b/client/loclass/ikeys.h new file mode 100644 index 00000000..629fa75b --- /dev/null +++ b/client/loclass/ikeys.h @@ -0,0 +1,32 @@ +#ifndef IKEYS_H +#define IKEYS_H + + +/** + * @brief + *Definition 11. Let the function hash0 : F 82 × F 82 × (F 62 ) 8 ? (F 82 ) 8 be defined as + * hash0(x, y, z [0] . . . z [7] ) = k [0] . . . k [7] where + * z'[i] = (z[i] mod (63-i)) + i i = 0...3 + * z'[i+4] = (z[i+4] mod (64-i)) + i i = 0...3 + * ? = check(z'); + * @param c + * @param k this is where the diversified key is put (should be 8 bytes) + * @return + */ +void hash0(uint64_t c, uint8_t k[8]); +int doKeyTests(uint8_t debuglevel); +/** + * @brief Performs Elite-class key diversification + * @param csn + * @param key + * @param div_key + */ + +void diversifyKey(uint8_t csn[8], uint8_t key[8], uint8_t div_key[8]); +/** + * @brief Permutes a key from standard NIST format to Iclass specific format + * @param key + * @param dest + */ + +#endif // IKEYS_H diff --git a/client/loclass/main.c b/client/loclass/main.c new file mode 100644 index 00000000..42019072 --- /dev/null +++ b/client/loclass/main.c @@ -0,0 +1,96 @@ +/***************************************************************************** + * This file is part of iClassCipher. It is a reconstructon of the cipher engine + * used in iClass, and RFID techology. + * + * The implementation is based on the work performed by + * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and + * Milosch Meriac in the paper "Dismantling IClass". + * + * Copyright (C) 2014 Martin Holst Swende + * + * 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. + * + * This file 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 IClassCipher. If not, see . + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include "cipherutils.h" +#include "cipher.h" +#include "ikeys.h" +#include "fileutils.h" +#include "elite_crack.h" + +int unitTests() +{ + int errors = testCipherUtils(); + errors += testMAC(); + errors += doKeyTests(0); + errors += testElite(); + return errors; +} +int showHelp() +{ + prnlog("Usage: iclazz [options]"); + prnlog("Options:"); + prnlog("-t Perform self-test"); + prnlog("-h Show this help"); + prnlog("-f Bruteforce iclass dumpfile"); + prnlog(" An iclass dumpfile is assumed to consist of an arbitrary number of malicious CSNs, and their protocol responses"); + prnlog(" The the binary format of the file is expected to be as follows: "); + prnlog(" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>"); + prnlog(" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>"); + prnlog(" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>"); + prnlog(" ... totalling N*24 bytes"); + prnlog(" Check iclass_dump.bin for an example"); + + return 0; +} + +int main (int argc, char **argv) +{ + prnlog("IClass Cipher version 1.2, Copyright (C) 2014 Martin Holst Swende\n"); + prnlog("Comes with ABSOLUTELY NO WARRANTY"); + prnlog("This is free software, and you are welcome to use, abuse and repackage, please keep the credits\n"); + char *fileName = NULL; + int c; + while ((c = getopt (argc, argv, "thf:")) != -1) + switch (c) + { + case 't': + return unitTests(); + case 'h': + return showHelp(); + case 'f': + fileName = optarg; + return bruteforceFileNoKeys(fileName); + case '?': + if (optopt == 'f') + fprintf (stderr, "Option -%c requires an argument.\n", optopt); + else if (isprint (optopt)) + fprintf (stderr, "Unknown option `-%c'.\n", optopt); + else + fprintf (stderr, + "Unknown option character `\\x%x'.\n", + optopt); + return 1; + //default: + //showHelp(); + } + showHelp(); + return 0; +} + diff --git a/client/mifarehost.h b/client/mifarehost.h index 5de082ce..f21b9139 100644 --- a/client/mifarehost.h +++ b/client/mifarehost.h @@ -15,7 +15,6 @@ #include "cmdmain.h" #include "ui.h" #include "data.h" -//#include "proxusb.h" #include "util.h" #include "nonce2key/nonce2key.h" #include "nonce2key/crapto1.h" diff --git a/client/proxmark3.c b/client/proxmark3.c index 528cae34..a9819b54 100644 --- a/client/proxmark3.c +++ b/client/proxmark3.c @@ -62,21 +62,6 @@ struct main_loop_arg { char *script_cmds_file; }; -//static void *usb_receiver(void *targ) { -// struct receiver_arg *arg = (struct receiver_arg*)targ; -// UsbCommand cmdbuf; -// -// while (arg->run) { -// if (ReceiveCommandPoll(&cmdbuf)) { -// UsbCommandReceived(&cmdbuf); -// fflush(NULL); -// } -// } -// -// pthread_exit(NULL); -// return NULL; -//} - byte_t rx[0x1000000]; byte_t* prx = rx; @@ -207,14 +192,6 @@ static void *main_loop(void *targ) { return NULL; } -//static void dumpHelp(char *parent, ...) -//{ -// printf("## %s\n\n", parent); -// CommandReceived(parent); -// -// printf("\n"); -//} - static void dumpAllHelp(int markdown) { printf("\n%sProxmark3 command dump%s\n\n",markdown?"# ":"",markdown?"":"\n======================"); @@ -254,17 +231,6 @@ int main(int argc, char* argv[]) { }; pthread_t main_loop_t; -/* - usb_init(); - if (!OpenProxmark(1)) { - fprintf(stderr,"PROXMARK3: NOT FOUND!\n"); - marg.usb_present = 0; - offline = 1; - } else { - marg.usb_present = 1; - offline = 0; - } -*/ sp = uart_open(argv[1]); if (sp == INVALID_SERIAL_PORT) { @@ -305,10 +271,6 @@ int main(int argc, char* argv[]) { pthread_join(main_loop_t, NULL); -// if (marg.usb_present == 1) { -// CloseProxmark(); -// } - // Clean up the port uart_close(sp); diff --git a/client/proxmark3.h b/client/proxmark3.h index 8236bfe7..a634fd68 100644 --- a/client/proxmark3.h +++ b/client/proxmark3.h @@ -20,7 +20,7 @@ #include "usb_cmd.h" -#define PROXPROMPT "proxmark3> " +#define PROXPROMPT "pm3 --> " void SendCommand(UsbCommand *c); diff --git a/client/ui.c b/client/ui.c index c0d01bc3..6486d524 100644 --- a/client/ui.c +++ b/client/ui.c @@ -90,3 +90,195 @@ void SetLogFilename(char *fn) { logfilename = fn; } + + +uint8_t manchester_decode(const uint8_t * data, const size_t len, uint8_t * dataout){ + + size_t bytelength = len; + + uint8_t bitStream[bytelength]; + memset(bitStream, 0x00, bytelength); + + int clock,high, low, bit, hithigh, hitlow, first, bit2idx, lastpeak; + int i,invert, lastval; + int bitidx = 0; + int lc = 0; + int warnings = 0; + high = 1; + low = bit = bit2idx = lastpeak = invert = lastval = hithigh = hitlow = first = 0; + clock = 0xFFFF; + + /* Detect high and lows */ + for (i = 0; i < bytelength; i++) { + if (data[i] > high) + high = data[i]; + else if (data[i] < low) + low = data[i]; + } + + /* get clock */ + int j=0; + for (i = 1; i < bytelength; i++) { + /* if this is the beginning of a peak */ + j = i-1; + if ( data[j] != data[i] && + data[i] == high) + { + /* find lowest difference between peaks */ + if (lastpeak && i - lastpeak < clock) + clock = i - lastpeak; + lastpeak = i; + } + } + + int tolerance = clock/4; + PrintAndLog(" Detected clock: %d",clock); + + /* Detect first transition */ + /* Lo-Hi (arbitrary) */ + /* skip to the first high */ + for (i= 0; i < bytelength; i++) + if (data[i] == high) + break; + + /* now look for the first low */ + for (; i < bytelength; i++) { + if (data[i] == low) { + lastval = i; + break; + } + } + + /* If we're not working with 1/0s, demod based off clock */ + if (high != 1) + { + bit = 0; /* We assume the 1st bit is zero, it may not be + * the case: this routine (I think) has an init problem. + * Ed. + */ + for (; i < (int)(bytelength / clock); i++) + { + hithigh = 0; + hitlow = 0; + first = 1; + + /* Find out if we hit both high and low peaks */ + for (j = 0; j < clock; j++) + { + if (data[(i * clock) + j] == high) + hithigh = 1; + else if (data[(i * clock) + j] == low) + hitlow = 1; + + /* it doesn't count if it's the first part of our read + because it's really just trailing from the last sequence */ + if (first && (hithigh || hitlow)) + hithigh = hitlow = 0; + else + first = 0; + + if (hithigh && hitlow) + break; + } + + /* If we didn't hit both high and low peaks, we had a bit transition */ + if (!hithigh || !hitlow) + bit ^= 1; + + bitStream[bit2idx++] = bit ^ invert; + } + } + /* standard 1/0 bitstream */ + else { + /* Then detect duration between 2 successive transitions */ + for (bitidx = 1; i < bytelength; i++) { + + if (data[i-1] != data[i]) { + lc = i-lastval; + lastval = i; + + // Error check: if bitidx becomes too large, we do not + // have a Manchester encoded bitstream or the clock is really + // wrong! + if (bitidx > (bytelength*2/clock+8) ) { + PrintAndLog("Error: the clock you gave is probably wrong, aborting."); + return 0; + } + // Then switch depending on lc length: + // Tolerance is 1/4 of clock rate (arbitrary) + if (abs(lc-clock/2) < tolerance) { + // Short pulse : either "1" or "0" + bitStream[bitidx++] = data[i-1]; + } else if (abs(lc-clock) < tolerance) { + // Long pulse: either "11" or "00" + bitStream[bitidx++] = data[i-1]; + bitStream[bitidx++] = data[i-1]; + } else { + // Error + warnings++; + PrintAndLog("Warning: Manchester decode error for pulse width detection."); + if (warnings > 10) { + PrintAndLog("Error: too many detection errors, aborting."); + return 0; + } + } + } + } + } + // At this stage, we now have a bitstream of "01" ("1") or "10" ("0"), parse it into final decoded bitstream + // Actually, we overwrite BitStream with the new decoded bitstream, we just need to be careful + // to stop output at the final bitidx2 value, not bitidx + for (i = 0; i < bitidx; i += 2) { + if ((bitStream[i] == 0) && (bitStream[i+1] == 1)) { + bitStream[bit2idx++] = 1 ^ invert; + } + else if ((bitStream[i] == 1) && (bitStream[i+1] == 0)) { + bitStream[bit2idx++] = 0 ^ invert; + } + else { + // We cannot end up in this state, this means we are unsynchronized, + // move up 1 bit: + i++; + warnings++; + PrintAndLog("Unsynchronized, resync..."); + if (warnings > 10) { + PrintAndLog("Error: too many decode errors, aborting."); + return 0; + } + } + } + + // PrintAndLog(" Manchester decoded bitstream : %d bits", (bit2idx-16)); + // uint8_t mod = (bit2idx-16) % blocksize; + // uint8_t div = (bit2idx-16) / blocksize; + + // // Now output the bitstream to the scrollback by line of 16 bits + // for (i = 0; i < div*blocksize; i+=blocksize) { + // PrintAndLog(" %s", sprint_bin(bitStream+i,blocksize) ); + // } + // if ( mod > 0 ){ + // PrintAndLog(" %s", sprint_bin(bitStream+i, mod) ); + // } + + if ( bit2idx > 0 ) + memcpy(dataout, bitStream, bit2idx); + + free(bitStream); + return bit2idx; +} + +void PrintPaddedManchester( uint8_t* bitStream, size_t len, size_t blocksize){ + + PrintAndLog(" Manchester decoded bitstream : %d bits", len); + + uint8_t mod = len % blocksize; + uint8_t div = len / blocksize; + int i; + // Now output the bitstream to the scrollback by line of 16 bits + for (i = 0; i < div*blocksize; i+=blocksize) { + PrintAndLog(" %s", sprint_bin(bitStream+i,blocksize) ); + } + if ( mod > 0 ){ + PrintAndLog(" %s", sprint_bin(bitStream+i, mod) ); + } +} diff --git a/client/ui.h b/client/ui.h index a45799d5..2f2ed189 100644 --- a/client/ui.h +++ b/client/ui.h @@ -11,6 +11,8 @@ #ifndef UI_H__ #define UI_H__ +#include "util.h" + void ShowGui(void); void HideGraphWindow(void); void ShowGraphWindow(void); @@ -23,4 +25,6 @@ extern int PlotGridX, PlotGridY, PlotGridXdefault, PlotGridYdefault; extern int offline; extern int flushAfterWrite; //buzzy +uint8_t manchester_decode(const uint8_t * data, const size_t len, uint8_t * dataout); +void PrintPaddedManchester( uint8_t * bitStream, size_t len, size_t blocksize); #endif diff --git a/client/util.c b/client/util.c index 15e911a1..1ebfebea 100644 --- a/client/util.c +++ b/client/util.c @@ -13,6 +13,7 @@ #ifndef _WIN32 #include #include + int ukbhit(void) { int cnt = 0; @@ -112,6 +113,17 @@ char * sprint_hex(const uint8_t * data, const size_t len) { return buf; } +char * sprint_bin(const uint8_t * data, const size_t len) { + static char buf[1024]; + char * tmp = buf; + size_t i; + + for (i=0; i < len && i < 1024; i++, tmp++) + sprintf(tmp, "%u", data[i]); + + return buf; +} + void num_to_bytes(uint64_t n, size_t len, uint8_t* dest) { while (len--) { @@ -131,6 +143,28 @@ uint64_t bytes_to_num(uint8_t* src, size_t len) return num; } +//assumes little endian +char * printBits(size_t const size, void const * const ptr) +{ + unsigned char *b = (unsigned char*) ptr; + unsigned char byte; + static char buf[1024]; + char * tmp = buf; + int i, j; + + for (i=size-1;i>=0;i--) + { + for (j=7;j>=0;j--) + { + byte = b[i] & (1<>= j; + sprintf(tmp, "%u", byte); + tmp++; + } + } + return buf; +} + // ------------------------------------------------------------------------- // string parameters lib // ------------------------------------------------------------------------- diff --git a/client/util.h b/client/util.h index ce8876ed..2677ab84 100644 --- a/client/util.h +++ b/client/util.h @@ -33,9 +33,11 @@ void FillFileNameByUID(char *fileName, uint8_t * uid, char *ext, int byteCount); void print_hex(const uint8_t * data, const size_t len); char * sprint_hex(const uint8_t * data, const size_t len); +char * sprint_bin(const uint8_t * data, const size_t len); void num_to_bytes(uint64_t n, size_t len, uint8_t* dest); uint64_t bytes_to_num(uint8_t* src, size_t len); +char * printBits(size_t const size, void const * const ptr); char param_getchar(const char *line, int paramnum); uint8_t param_get8(const char *line, int paramnum); @@ -45,3 +47,4 @@ uint64_t param_get64ex(const char *line, int paramnum, int deflt, int base); int param_gethex(const char *line, int paramnum, uint8_t * data, int hexcnt); int param_getstr(const char *line, int paramnum, char * str); + diff --git a/common/Makefile.common b/common/Makefile.common index 2befd456..2b2bb2fb 100644 --- a/common/Makefile.common +++ b/common/Makefile.common @@ -54,7 +54,8 @@ DELETE=del /q MOVE=ren COPY=copy PATHSEP=\\# -FLASH_TOOL=winsrc\\prox.exe +#FLASH_TOOL=winsrc\\prox.exe +FLASH_TOOL=winsrc\\flash.exe DETECTED_OS=Windows endif @@ -67,6 +68,7 @@ INCLUDES = ../include/proxmark3.h ../include/at91sam7s512.h ../include/config_gp CFLAGS = -c $(INCLUDE) -Wall -Werror -pedantic -std=c99 $(APP_CFLAGS) -Os LDFLAGS = -nostartfiles -nodefaultlibs -Wl,-gc-sections -n + LIBS = -lgcc THUMBOBJ = $(patsubst %.c,$(OBJDIR)/%.o,$(THUMBSRC)) diff --git a/common/cmd.c b/common/cmd.c index 49d9d942..dae3a8da 100644 --- a/common/cmd.c +++ b/common/cmd.c @@ -32,7 +32,7 @@ #include "cmd.h" #include "string.h" -#include "proxmark3.h" +#include "../include/proxmark3.h" //static UsbCommand txcmd; diff --git a/common/cmd.h b/common/cmd.h index b330a219..35885de4 100644 --- a/common/cmd.h +++ b/common/cmd.h @@ -33,8 +33,8 @@ #ifndef _PROXMARK_CMD_H_ #define _PROXMARK_CMD_H_ -#include -#include +#include "../include/common.h" +#include "../include/usb_cmd.h" #include "usb_cdc.h" bool cmd_receive(UsbCommand* cmd); diff --git a/include/crc.h b/common/crc.h similarity index 100% rename from include/crc.h rename to common/crc.h diff --git a/common/crc32.c b/common/crc32.c new file mode 100644 index 00000000..69d770f4 --- /dev/null +++ b/common/crc32.c @@ -0,0 +1,35 @@ +#include +#include +#include "crc32.h" + +#define htole32(x) (x) +#define CRC32_PRESET 0xFFFFFFFF + + +static void crc32_byte (uint32_t *crc, const uint8_t value); + +static void crc32_byte (uint32_t *crc, const uint8_t value) { + /* x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 1 */ + const uint32_t poly = 0xEDB88320; + + *crc ^= value; + for (int current_bit = 7; current_bit >= 0; current_bit--) { + int bit_out = (*crc) & 0x00000001; + *crc >>= 1; + if (bit_out) + *crc ^= poly; + } +} + +void crc32 (const uint8_t *data, const size_t len, uint8_t *crc) { + uint32_t desfire_crc = CRC32_PRESET; + for (size_t i = 0; i < len; i++) { + crc32_byte (&desfire_crc, data[i]); + } + + *((uint32_t *)(crc)) = htole32 (desfire_crc); +} + +void crc32_append (uint8_t *data, const size_t len) { + crc32 (data, len, data + len); +} diff --git a/common/crc32.h b/common/crc32.h new file mode 100644 index 00000000..0dd2a328 --- /dev/null +++ b/common/crc32.h @@ -0,0 +1,15 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- +// CRC32 +//----------------------------------------------------------------------------- + +#ifndef __CRC32_H +#define __CRC32_H + +void crc32 (const uint8_t *data, const size_t len, uint8_t *crc); +void crc32_append (uint8_t *data, const size_t len); + +#endif diff --git a/common/desfire.h b/common/desfire.h new file mode 100644 index 00000000..912ca9ff --- /dev/null +++ b/common/desfire.h @@ -0,0 +1,177 @@ +#ifndef __DESFIRE_H +#define __DESFIRE_H + +#include "aes.h" +#define DESFIRE(tag) ((struct desfire_tag *) tag) +#define DESFIRE_KEY(key) ((struct desfire_key *) key) + +#define MAX_CRYPTO_BLOCK_SIZE 16 +/* Mifare DESFire EV1 Application crypto operations */ +#define APPLICATION_CRYPTO_DES 0x00 +#define APPLICATION_CRYPTO_3K3DES 0x40 +#define APPLICATION_CRYPTO_AES 0x80 + +#define MAC_LENGTH 4 +#define CMAC_LENGTH 8 + +typedef enum { + MCD_SEND, + MCD_RECEIVE +} MifareCryptoDirection; + +typedef enum { + MCO_ENCYPHER, + MCO_DECYPHER +} MifareCryptoOperation; + +#define MDCM_MASK 0x000F + +#define CMAC_NONE 0 + +// Data send to the PICC is used to update the CMAC +#define CMAC_COMMAND 0x010 +// Data received from the PICC is used to update the CMAC +#define CMAC_VERIFY 0x020 + +// MAC the command (when MDCM_MACED) +#define MAC_COMMAND 0x100 +// The command returns a MAC to verify (when MDCM_MACED) +#define MAC_VERIFY 0x200 + +#define ENC_COMMAND 0x1000 +#define NO_CRC 0x2000 + +#define MAC_MASK 0x0F0 +#define CMAC_MACK 0xF00 + +/* Communication mode */ +#define MDCM_PLAIN 0x00 +#define MDCM_MACED 0x01 +#define MDCM_ENCIPHERED 0x03 + +/* Error code managed by the library */ +#define CRYPTO_ERROR 0x01 + + +enum DESFIRE_AUTH_SCHEME { + AS_LEGACY, + AS_NEW +}; + +enum DESFIRE_CRYPTOALGO { + T_DES = 0x00, + T_3DES = 0x01, + T_3K3DES = 0x02, + T_AES = 0x03 +}; + +struct desfire_key { + + enum DESFIRE_CRYPTOALGO type; + uint8_t data[24]; + // DES_key_schedule ks1; + // DES_key_schedule ks2; + // DES_key_schedule ks3; + AesCtx aes_ks; + uint8_t cmac_sk1[24]; + uint8_t cmac_sk2[24]; + uint8_t aes_version; +}; + +typedef struct desfire_key *desfirekey_t; + +struct desfire_tag { + iso14a_card_select_t info; + int active; + uint8_t last_picc_error; + uint8_t last_internal_error; + uint8_t last_pcd_error; + desfirekey_t session_key; + enum DESFIRE_AUTH_SCHEME authentication_scheme; + uint8_t authenticated_key_no; + + uint8_t ivect[MAX_CRYPTO_BLOCK_SIZE]; + uint8_t cmac[16]; + uint8_t *crypto_buffer; + size_t crypto_buffer_size; + uint32_t selected_application; +}; +typedef struct desfire_tag *desfiretag_t; + + +/* File types */ +enum DESFIRE_FILE_TYPES { + MDFT_STANDARD_DATA_FILE = 0x00, + MDFT_BACKUP_DATA_FILE = 0x01, + MDFT_VALUE_FILE_WITH_BACKUP = 0x02, + MDFT_LINEAR_RECORD_FILE_WITH_BACKUP = 0x03, + MDFT_CYCLIC_RECORD_FILE_WITH_BACKUP = 0x04 +}; + + + +enum DESFIRE_STATUS { + OPERATION_OK = 0x00, + NO_CHANGES = 0x0c, + OUT_OF_EEPROM_ERROR = 0x0e, + ILLEGAL_COMMAND_CODE = 0x1c, + INTEGRITY_ERROR = 0x1e, + NO_SUCH_KEY = 0x40, + LENGTH_ERROR = 0x7e, + PERMISSION_DENIED = 0x9d, + PARAMETER_ERROR = 0x9e, + APPLICATION_NOT_FOUND = 0xa0, + APPL_INTEGRITY_ERROR = 0xa1, + AUTHENTICATION_ERROR = 0xae, + ADDITIONAL_FRAME = 0xaf, + BOUNDARY_ERROR = 0xbe, + PICC_INTEGRITY_ERROR = 0xc1, + COMMAND_ABORTED = 0xca, + PICC_DISABLED_ERROR = 0xcd, + COUNT_ERROR = 0xce, + DUPLICATE_ERROR = 0xde, + EEPROM_ERROR = 0xee, + FILE_NOT_FOUND = 0xf0, + FILE_INTEGRITY_ERROR = 0xf1 +}; + +enum DESFIRE_CMD { + CREATE_APPLICATION = 0xca, + DELETE_APPLICATION = 0xda, + GET_APPLICATION_IDS = 0x6a, + SELECT_APPLICATION = 0x5a, + FORMAT_PICC = 0xfc, + GET_VERSION = 0x60, + READ_DATA = 0xbd, + WRITE_DATA = 0x3d, + GET_VALUE = 0x6c, + CREDIT = 0x0c, + DEBIT = 0xdc, + LIMITED_CREDIT = 0x1c, + WRITE_RECORD = 0x3b, + READ_RECORDS = 0xbb, + CLEAR_RECORD_FILE = 0xeb, + COMMIT_TRANSACTION = 0xc7, + ABORT_TRANSACTION = 0xa7, + GET_FREE_MEMORY = 0x6e, + GET_FILE_IDS = 0x6f, + GET_FILE_SETTINGS = 0xf5, + CHANGE_FILE_SETTINGS = 0x5f, + CREATE_STD_DATA_FILE = 0xcd, + CREATE_BACKUP_DATA_FILE = 0xcb, + CREATE_VALUE_FILE = 0xcc, + CREATE_LINEAR_RECORD_FILE = 0xc1, + CREATE_CYCLIC_RECORD_FILE = 0xc0, + DELETE_FILE = 0xdf, + AUTHENTICATE = 0x0a, // AUTHENTICATE_NATIVE + AUTHENTICATE_ISO = 0x1a, // AUTHENTICATE_STANDARD + AUTHENTICATE_AES = 0xaa, + CHANGE_KEY_SETTINGS = 0x54, + GET_KEY_SETTINGS = 0x45, + CHANGE_KEY = 0xc4, + GET_KEY_VERSION = 0x64, + AUTHENTICATION_FRAME = 0xAF +}; + +#endif + diff --git a/common/iso14443crc.c b/common/iso14443crc.c index a6def1a9..851546ae 100644 --- a/common/iso14443crc.c +++ b/common/iso14443crc.c @@ -6,7 +6,7 @@ // ISO14443 CRC calculation code. //----------------------------------------------------------------------------- -#include "iso14443crc.h" +#include "../common/iso14443crc.h" static unsigned short UpdateCrc14443(unsigned char ch, unsigned short *lpwCrc) { diff --git a/common/iso14443crc.h b/common/iso14443crc.h index 87347714..80941116 100644 --- a/common/iso14443crc.h +++ b/common/iso14443crc.h @@ -8,7 +8,7 @@ #ifndef __ISO14443CRC_H #define __ISO14443CRC_H -#include "common.h" +#include "../include/common.h" //----------------------------------------------------------------------------- // Routines to compute the CRCs (two different flavours, just for confusion) diff --git a/common/iso15693tools.c b/common/iso15693tools.c index add0ba69..964059ce 100644 --- a/common/iso15693tools.c +++ b/common/iso15693tools.c @@ -7,11 +7,14 @@ //----------------------------------------------------------------------------- -#include "proxmark3.h" +#include "../include/proxmark3.h" #include #include //#include "iso15693tools.h" +#define POLY 0x8408 + + // The CRC as described in ISO 15693-Part 3-Annex C // v buffer with data // n length @@ -63,5 +66,31 @@ char* Iso15693sprintUID(char *target,uint8_t *uid) { return target; } +unsigned short iclass_crc16(char *data_p, unsigned short length) +{ + unsigned char i; + unsigned int data; + unsigned int crc = 0xffff; + + if (length == 0) + return (~crc); + + do + { + for (i=0, data=(unsigned int)0xff & *data_p++; + i < 8; + i++, data >>= 1) + { + if ((crc & 0x0001) ^ (data & 0x0001)) + crc = (crc >> 1) ^ POLY; + else crc >>= 1; + } + } while (--length); + crc = ~crc; + data = crc; + crc = (crc << 8) | (data >> 8 & 0xff); + crc = crc ^ 0xBC3; + return (crc); +} diff --git a/common/iso15693tools.h b/common/iso15693tools.h index c831fec4..ec63728f 100644 --- a/common/iso15693tools.h +++ b/common/iso15693tools.h @@ -70,6 +70,7 @@ uint16_t Iso15693Crc(uint8_t *v, int n); int Iso15693AddCrc(uint8_t *req, int n); char* Iso15693sprintUID(char *target,uint8_t *uid); +unsigned short iclass_crc16(char *data_p, unsigned short length); //----------------------------------------------------------------------------- // Map a sequence of octets (~layer 2 command) into the set of bits to feed diff --git a/common/legic_prng.c b/common/legic_prng.c index 4f3b1ffe..322429ad 100644 --- a/common/legic_prng.c +++ b/common/legic_prng.c @@ -6,7 +6,7 @@ // LEFIC's obfuscation function //----------------------------------------------------------------------------- -#include "legic_prng.h" +#include "../include/legic_prng.h" struct lfsr { uint8_t a; diff --git a/common/usb_cdc.c b/common/usb_cdc.c index e2787fb6..097d9a4e 100644 --- a/common/usb_cdc.c +++ b/common/usb_cdc.c @@ -33,7 +33,7 @@ */ #include "usb_cdc.h" -#include "config_gpio.h" +#include "../include/config_gpio.h" #define MIN(a, b) (((a) < (b)) ? (a) : (b)) #define MAX(a, b) (((a) > (b)) ? (a) : (b)) diff --git a/common/usb_cdc.h b/common/usb_cdc.h index d7b9c2e5..b6489937 100644 --- a/common/usb_cdc.h +++ b/common/usb_cdc.h @@ -35,7 +35,7 @@ #ifndef _USB_CDC_H_ #define _USB_CDC_H_ -#include +#include "../include/common.h" void usb_disable(); void usb_enable(); diff --git a/include/crc.h.old b/include/crc.h.old new file mode 100644 index 00000000..8e68f3b3 --- /dev/null +++ b/include/crc.h.old @@ -0,0 +1,48 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- +// Generic CRC calculation code. +//----------------------------------------------------------------------------- + +#ifndef __CRC_H +#define __CRC_H + +#include + +typedef struct crc { + uint32_t state; + int order; + uint32_t polynom; + uint32_t initial_value; + uint32_t final_xor; + uint32_t mask; +} crc_t; + +/* Initialize a crc structure. order is the order of the polynom, e.g. 32 for a CRC-32 + * polynom is the CRC polynom. initial_value is the initial value of a clean state. + * final_xor is XORed onto the state before returning it from crc_result(). */ +extern void crc_init(crc_t *crc, int order, uint32_t polynom, uint32_t initial_value, uint32_t final_xor); + +/* Update the crc state. data is the data of length data_width bits (only the the + * data_width lower-most bits are used). + */ +extern void crc_update(crc_t *crc, uint32_t data, int data_width); + +/* Clean the crc state, e.g. reset it to initial_value */ +extern void crc_clear(crc_t *crc); + +/* Get the result of the crc calculation */ +extern uint32_t crc_finish(crc_t *crc); + +/* Static initialization of a crc structure */ +#define CRC_INITIALIZER(_order, _polynom, _initial_value, _final_xor) { \ + .state = ((_initial_value) & ((1L<<(_order))-1)), \ + .order = (_order), \ + .polynom = (_polynom), \ + .initial_value = (_initial_value), \ + .final_xor = (_final_xor), \ + .mask = ((1L<<(_order))-1) } + +#endif /* __CRC_H */ diff --git a/include/mifare.h b/include/mifare.h index e2b7a7c5..403132ac 100644 --- a/include/mifare.h +++ b/include/mifare.h @@ -11,7 +11,7 @@ #ifndef _MIFARE_H_ #define _MIFARE_H_ -#include "common.h" +#include "../include/common.h" //----------------------------------------------------------------------------- // ISO 14443A diff --git a/include/proxmark3.h b/include/proxmark3.h index 8c9417da..b3530c64 100644 --- a/include/proxmark3.h +++ b/include/proxmark3.h @@ -14,6 +14,7 @@ // Might as well have the hardware-specific defines everywhere. #include "at91sam7s512.h" #include "config_gpio.h" +#include "usb_cmd.h" #define WDT_HIT() AT91C_BASE_WDTC->WDTC_WDCR = 0xa5000001 @@ -67,8 +68,6 @@ #define TRUE 1 #define FALSE 0 -#include - //#define PACKED __attribute__((__packed__)) #define LED_A_ON() HIGH(GPIO_LED_A) diff --git a/include/usb_cmd.h b/include/usb_cmd.h index 4b1fc2b6..23555ab4 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -117,6 +117,8 @@ typedef struct { #define CMD_SNOOP_ICLASS 0x0392 #define CMD_SIMULATE_TAG_ICLASS 0x0393 #define CMD_READER_ICLASS 0x0394 +#define CMD_READER_ICLASS_REPLAY 0x0395 +#define CMD_ICLASS_ISO14443A_WRITE 0x0397 // For measurements of the antenna tuning #define CMD_MEASURE_ANTENNA_TUNING 0x0400 @@ -151,6 +153,19 @@ typedef struct { #define CMD_MIFARE_CHKKEYS 0x0623 #define CMD_MIFARE_SNIFFER 0x0630 +//ultralightC +#define CMD_MIFAREUC_AUTH1 0x0724 +#define CMD_MIFAREUC_AUTH2 0x0725 +#define CMD_MIFAREUC_READCARD 0x0726 + + +// mifare desfire +#define CMD_MIFARE_DESFIRE_READBL 0x0728 +#define CMD_MIFARE_DESFIRE_WRITEBL 0x0729 +#define CMD_MIFARE_DESFIRE_AUTH1 0x072a +#define CMD_MIFARE_DESFIRE_AUTH2 0x072b +#define CMD_MIFARE_DES_READER 0x072c +#define CMD_MIFARE_DESFIRE_INFO 0x072d #define CMD_UNKNOWN 0xFFFF @@ -162,6 +177,8 @@ typedef struct { #define FLAG_NR_AR_ATTACK 0x08 +//Iclass reader flags +#define FLAG_ICLASS_READER_ONLY_ONCE 0x01 // CMD_DEVICE_INFO response packet has flags in arg[0], flag definitions: /* Whether a bootloader that understands the common_area is present */ -- 2.39.5