diff --git a/examples/mifare-ultralight-info.c b/examples/mifare-ultralight-info.c index e9b3c494..0b4f6994 100644 --- a/examples/mifare-ultralight-info.c +++ b/examples/mifare-ultralight-info.c @@ -61,7 +61,7 @@ main(int argc, char *argv[]) res = mifare_ultralightc_authenticate(tag, key); if (res != 0) { MifareDESFireKey diversified_key = NULL; - MifareKeyDeriver deriver = mifare_key_deriver_new_an10922(key, MIFARE_KEY_2K3DES); + MifareKeyDeriver deriver = mifare_key_deriver_new_an10922(key, MIFARE_KEY_2K3DES, AN10922_FLAG_DEFAULT); mifare_key_deriver_begin(deriver); mifare_key_deriver_update_uid(deriver, tag); diff --git a/examples/mifare-ultralightc-diversify.c b/examples/mifare-ultralightc-diversify.c index 631b60b2..d78efb78 100644 --- a/examples/mifare-ultralightc-diversify.c +++ b/examples/mifare-ultralightc-diversify.c @@ -30,7 +30,7 @@ main(int argc, char *argv[]) uint8_t key1_3des_data[16] = { 0x49, 0x45, 0x4D, 0x4B, 0x41, 0x45, 0x52, 0x42, 0x21, 0x4E, 0x41, 0x43, 0x55, 0x4F, 0x59, 0x46 }; MifareDESFireKey master_key = mifare_desfire_3des_key_new(key1_3des_data); MifareDESFireKey derived_key = NULL; - MifareKeyDeriver deriver = mifare_key_deriver_new_an10922(master_key, MIFARE_KEY_2K3DES); + MifareKeyDeriver deriver = mifare_key_deriver_new_an10922(master_key, MIFARE_KEY_2K3DES, AN10922_FLAG_DEFAULT); bool undiversify = (argc == 2 && strcmp("--undiversify",argv[1]) == 0); if (argc > 2 || (argc == 2 && strcmp("--undiversify",argv[1]) != 0)) { diff --git a/libfreefare/freefare.h b/libfreefare/freefare.h index 14b85388..9e4e333b 100644 --- a/libfreefare/freefare.h +++ b/libfreefare/freefare.h @@ -540,7 +540,10 @@ typedef enum mifare_key_type { struct mifare_key_deriver; typedef struct mifare_key_deriver *MifareKeyDeriver; -MifareKeyDeriver mifare_key_deriver_new_an10922(MifareDESFireKey master_key, MifareKeyType output_key_type); +#define AN10922_FLAG_DEFAULT 0 +#define AN10922_FLAG_EMULATE_ISSUE_91 (1<<1) + +MifareKeyDeriver mifare_key_deriver_new_an10922(MifareDESFireKey master_key, MifareKeyType output_key_type, int flags); int mifare_key_deriver_begin(MifareKeyDeriver deriver); int mifare_key_deriver_update_data(MifareKeyDeriver deriver, const uint8_t *data, size_t len); int mifare_key_deriver_update_uid(MifareKeyDeriver deriver, FreefareTag tag); diff --git a/libfreefare/freefare_internal.h b/libfreefare/freefare_internal.h index 25c9f3a4..af94d50d 100644 --- a/libfreefare/freefare_internal.h +++ b/libfreefare/freefare_internal.h @@ -134,6 +134,7 @@ size_t enciphered_data_length(const FreefareTag tag, const size_t nbytes, int void cmac_generate_subkeys(MifareDESFireKey key); void cmac(const MifareDESFireKey key, uint8_t *ivect, const uint8_t *data, size_t len, uint8_t *cmac); +void cmac_an10922(const MifareDESFireKey key, uint8_t *ivect, const uint8_t *data, size_t len, uint8_t *cmac); void *assert_crypto_buffer_size(FreefareTag tag, size_t nbytes); #define MIFARE_ULTRALIGHT_PAGE_COUNT 0x10 @@ -213,8 +214,9 @@ struct mifare_desfire_tag { struct mifare_key_deriver { MifareDESFireKey master_key; MifareKeyType output_key_type; - uint8_t m[48]; + uint8_t m[32]; int len; + int flags; }; MifareDESFireKey mifare_desfire_session_key_new(const uint8_t rnda[], const uint8_t rndb[], MifareDESFireKey authentication_key); diff --git a/libfreefare/mifare_desfire_crypto.c b/libfreefare/mifare_desfire_crypto.c index 9f08da57..1d450000 100644 --- a/libfreefare/mifare_desfire_crypto.c +++ b/libfreefare/mifare_desfire_crypto.c @@ -144,6 +144,40 @@ cmac(const MifareDESFireKey key, uint8_t *ivect, const uint8_t *data, size_t len free(buffer); } +void +cmac_an10922(const MifareDESFireKey key, uint8_t *ivect, const uint8_t *data, size_t len, uint8_t *cmac) +{ + int kbs = key_block_size(key); + int buffer_len = kbs*2; + + // Contract for this function requires that the data fit in two blocks. + if (len > buffer_len) + abort(); + + uint8_t *buffer = malloc(buffer_len); + + if (!buffer) + abort(); + + memcpy(buffer, data, len); + + if (len != buffer_len) { + buffer[len++] = 0x80; + while (len != buffer_len) { + 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); + + free(buffer); +} + #define CRC32_PRESET 0xFFFFFFFF static void diff --git a/libfreefare/mifare_key_deriver.3 b/libfreefare/mifare_key_deriver.3 index 686ce5ec..bd4a98f9 100644 --- a/libfreefare/mifare_key_deriver.3 +++ b/libfreefare/mifare_key_deriver.3 @@ -50,7 +50,7 @@ Mifare card manipulation library (libfreefare, \-lfreefare) .Sh SYNOPSIS .In freefare.h .Ft MifareKeyDeriver -.Fn mifare_key_deriver_new_an10922 "MifareDESFireKey master_key" "MifareKeyType output_key_type" +.Fn mifare_key_deriver_new_an10922 "MifareDESFireKey master_key" "MifareKeyType output_key_type" "int flags" .Ft int .Fn mifare_key_deriver_begin "MifareKeyDeriver deriver" .Ft int @@ -83,7 +83,11 @@ The function alocates a new key deriver object which can be used to generate diversified keys from .Va master_key -in accordinance with AN10922. +in accordinance with AN10922 when the flags field is is set to AN10922_FLAG_DEFAULT. +When the flags field is set to AN10922_FLAG_EMULATE_ISSUE_91, the resulting key +deriver will use the non-AN10922-compliant key derivation that was originally being +used by this API. All new deployments should use AN10922_FLAG_DEFAULT. See issue #91 for +more information. .Pp The .Fn mifare_key_deriver_begin diff --git a/libfreefare/mifare_key_deriver.c b/libfreefare/mifare_key_deriver.c index d79db877..17f3842f 100644 --- a/libfreefare/mifare_key_deriver.c +++ b/libfreefare/mifare_key_deriver.c @@ -17,7 +17,7 @@ #define AN10922_DIV_3K3DES_3 0x33 MifareKeyDeriver -mifare_key_deriver_new_an10922(MifareDESFireKey master_key, MifareKeyType output_key_type) +mifare_key_deriver_new_an10922(MifareDESFireKey master_key, MifareKeyType output_key_type, int flags) { MifareKeyDeriver deriver = NULL; const int master_key_block_size = key_block_size(master_key); @@ -57,6 +57,7 @@ mifare_key_deriver_new_an10922(MifareDESFireKey master_key, MifareKeyType output deriver->master_key = master_key; deriver->output_key_type = output_key_type; cmac_generate_subkeys(deriver->master_key); + deriver->flags = flags; } return deriver; @@ -91,7 +92,7 @@ mifare_key_deriver_update_data(MifareKeyDeriver deriver, const uint8_t *data, si return -1; } - if (len > sizeof(deriver->m) - deriver->len) { + if (len > key_block_size(deriver->master_key) * 2 - deriver->len) { deriver->len = 0; // Remember that we have an error. errno = EOVERFLOW; return -1; @@ -167,7 +168,13 @@ deriver_cmac(MifareKeyDeriver deriver, uint8_t* output) { uint8_t ivect[24]; memset(ivect, 0, sizeof(ivect)); - cmac(deriver->master_key, ivect, deriver->m, deriver->len, output); + if (deriver->flags & AN10922_FLAG_EMULATE_ISSUE_91) { + // Restores the old non-AN10922-compiant derivation + // that was fixed by issue #91. + cmac(deriver->master_key, ivect, deriver->m, deriver->len, output); + } else { + cmac_an10922(deriver->master_key, ivect, deriver->m, deriver->len, output); + } } static uint8_t diff --git a/test/test_mifare_key_deriver_an10922.c b/test/test_mifare_key_deriver_an10922.c index bc4a9658..3fda5fa5 100644 --- a/test/test_mifare_key_deriver_an10922.c +++ b/test/test_mifare_key_deriver_an10922.c @@ -22,7 +22,7 @@ test_mifare_key_deriver_an10922_aes128(void) version = mifare_desfire_key_get_version(key); cut_assert_equal_int(key1_aes128_version, version, cut_message("Wrong master key version")); - deriver = mifare_key_deriver_new_an10922(key, MIFARE_KEY_AES128); + deriver = mifare_key_deriver_new_an10922(key, MIFARE_KEY_AES128, AN10922_FLAG_DEFAULT); ret = mifare_key_deriver_begin(deriver); cut_assert_equal_int(ret, 0, cut_message("mifare_key_deriver_begin failed")); @@ -52,6 +52,93 @@ test_mifare_key_deriver_an10922_aes128(void) mifare_desfire_key_free(key); } +void +test_mifare_key_deriver_an10922_aes128_short_m(void) +{ + MifareDESFireKey key = NULL; + MifareDESFireKey derived_key = NULL; + MifareKeyDeriver deriver = NULL; + int version, ret; + + // These test vectors came from AN10957, pages 13-14 + uint8_t key1_aes128_data[16] = { 0xf3, 0xf9, 0x37, 0x76, 0x98, 0x70, 0x7b, 0x68, 0x8e, 0xaf, 0x84, 0xab, 0xe3, 0x9e, 0x37, 0x91 }; + uint8_t key1_aes128_version = 16; + uint8_t key1_aes128_derived_data[16] = { 0x0b, 0xb4, 0x08, 0xba, 0xff, 0x98, 0xb6, 0xee, 0x9f, 0x2e, 0x15, 0x85, 0x77, 0x7f, 0x6a, 0x51 }; + uint8_t key1_aes128_check_m[] = { 0x01, 0x04, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed }; + + key = mifare_desfire_aes_key_new_with_version(key1_aes128_data, key1_aes128_version); + + version = mifare_desfire_key_get_version(key); + cut_assert_equal_int(key1_aes128_version, version, cut_message("Wrong master key version")); + + deriver = mifare_key_deriver_new_an10922(key, MIFARE_KEY_AES128, AN10922_FLAG_DEFAULT); + + ret = mifare_key_deriver_begin(deriver); + cut_assert_equal_int(ret, 0, cut_message("mifare_key_deriver_begin failed")); + + ret = mifare_key_deriver_update_cstr(deriver, "\x04\xde\xad\xbe\xef\xfe\xed"); + cut_assert_equal_int(ret, 0, cut_message("mifare_key_deriver_update failed")); + + derived_key = mifare_key_deriver_end(deriver); + cut_assert_not_null(derived_key, cut_message("mifare_key_deriver_end failed")); + + cut_assert_equal_memory(key1_aes128_check_m, sizeof(key1_aes128_check_m), deriver->m, deriver->len, cut_message("Wrong CMAC message")); + + version = mifare_desfire_key_get_version(derived_key); + cut_assert_equal_int(key1_aes128_version, version, cut_message("Wrong derived key version")); + + cut_assert_equal_int(derived_key->type, MIFARE_KEY_AES128, cut_message("Wrong derived key type")); + + cut_assert_equal_memory(key1_aes128_derived_data, sizeof(key1_aes128_derived_data), derived_key->data, sizeof(key1_aes128_derived_data), cut_message("Wrong derived key")); + mifare_key_deriver_free(deriver); + mifare_desfire_key_free(derived_key); + mifare_desfire_key_free(key); +} + +void +test_mifare_key_deriver_an10922_aes128_issue_91(void) +{ + MifareDESFireKey key = NULL; + MifareDESFireKey derived_key = NULL; + MifareKeyDeriver deriver = NULL; + int version, ret; + + // These test vectors came from AN10957, pages 13-14; EXCEPT that the derived + // data reflects the use of the AN10922_FLAG_EMULATE_ISSUE_91 flag. + uint8_t key1_aes128_data[16] = { 0xf3, 0xf9, 0x37, 0x76, 0x98, 0x70, 0x7b, 0x68, 0x8e, 0xaf, 0x84, 0xab, 0xe3, 0x9e, 0x37, 0x91 }; + uint8_t key1_aes128_version = 16; + uint8_t key1_aes128_derived_data[16] = { 0x72, 0x1e, 0x2c, 0x01, 0xe8, 0x1a, 0xf8, 0x5d, 0x81, 0x56, 0x33, 0x96, 0x9c, 0xea, 0x26, 0x07 }; + uint8_t key1_aes128_check_m[] = { 0x01, 0x04, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed }; + + key = mifare_desfire_aes_key_new_with_version(key1_aes128_data, key1_aes128_version); + + version = mifare_desfire_key_get_version(key); + cut_assert_equal_int(key1_aes128_version, version, cut_message("Wrong master key version")); + + deriver = mifare_key_deriver_new_an10922(key, MIFARE_KEY_AES128, AN10922_FLAG_EMULATE_ISSUE_91); + + ret = mifare_key_deriver_begin(deriver); + cut_assert_equal_int(ret, 0, cut_message("mifare_key_deriver_begin failed")); + + ret = mifare_key_deriver_update_cstr(deriver, "\x04\xde\xad\xbe\xef\xfe\xed"); + cut_assert_equal_int(ret, 0, cut_message("mifare_key_deriver_update failed")); + + derived_key = mifare_key_deriver_end(deriver); + cut_assert_not_null(derived_key, cut_message("mifare_key_deriver_end failed")); + + cut_assert_equal_memory(key1_aes128_check_m, sizeof(key1_aes128_check_m), deriver->m, deriver->len, cut_message("Wrong CMAC message")); + + version = mifare_desfire_key_get_version(derived_key); + cut_assert_equal_int(key1_aes128_version, version, cut_message("Wrong derived key version")); + + cut_assert_equal_int(derived_key->type, MIFARE_KEY_AES128, cut_message("Wrong derived key type")); + + cut_assert_equal_memory(key1_aes128_derived_data, sizeof(key1_aes128_derived_data), derived_key->data, sizeof(key1_aes128_derived_data), cut_message("Wrong derived key")); + mifare_key_deriver_free(deriver); + mifare_desfire_key_free(derived_key); + mifare_desfire_key_free(key); +} + void test_mifare_key_deriver_an10922_2k3des(void) { @@ -67,7 +154,7 @@ test_mifare_key_deriver_an10922_2k3des(void) key = mifare_desfire_3des_key_new_with_version(key1_2k3des_data); - deriver = mifare_key_deriver_new_an10922(key, MIFARE_KEY_2K3DES); + deriver = mifare_key_deriver_new_an10922(key, MIFARE_KEY_2K3DES, AN10922_FLAG_DEFAULT); ret = mifare_key_deriver_begin(deriver); cut_assert_equal_int(ret, 0, cut_message("mifare_key_deriver_begin failed")); @@ -112,7 +199,7 @@ test_mifare_key_deriver_an10922_3k3des(void) key = mifare_desfire_3k3des_key_new_with_version(key1_3k3des_data); - deriver = mifare_key_deriver_new_an10922(key, MIFARE_KEY_3K3DES); + deriver = mifare_key_deriver_new_an10922(key, MIFARE_KEY_3K3DES, AN10922_FLAG_DEFAULT); ret = mifare_key_deriver_begin(deriver); cut_assert_equal_int(ret, 0, cut_message("mifare_key_deriver_begin failed"));