Support for AN10922 key derivation

This commit implements [AN10922][] key diversification, as described in issue #77.

[AN10922]: https://www.nxp.com/docs/en/application-note/AN10922.pdf
This commit is contained in:
Robert Quattlebaum 2018-01-05 13:03:42 -08:00
parent 3d398dcd2f
commit 9d88c18833
15 changed files with 864 additions and 68 deletions

View file

@ -16,6 +16,7 @@ bin_PROGRAMS = felica-lite-dump \
mifare-desfire-read-ndef \ mifare-desfire-read-ndef \
mifare-desfire-write-ndef \ mifare-desfire-write-ndef \
mifare-ultralight-info \ mifare-ultralight-info \
mifare-ultralightc-diversify \
ntag-detect \ ntag-detect \
ntag-removeauth \ ntag-removeauth \
ntag-setauth \ ntag-setauth \
@ -66,6 +67,9 @@ mifare_desfire_write_ndef_LDADD = $(top_builddir)/libfreefare/libfreefare.la
mifare_ultralight_info_SOURCES = mifare-ultralight-info.c mifare_ultralight_info_SOURCES = mifare-ultralight-info.c
mifare_ultralight_info_LDADD = $(top_builddir)/libfreefare/libfreefare.la mifare_ultralight_info_LDADD = $(top_builddir)/libfreefare/libfreefare.la
mifare_ultralightc_diversify_SOURCES = mifare-ultralightc-diversify.c
mifare_ultralightc_diversify_LDADD = $(top_builddir)/libfreefare/libfreefare.la
ntag_detect_SOURCES = ntag-detect.c ntag_detect_SOURCES = ntag-detect.c
ntag_detect_LDADD = $(top_builddir)/libfreefare/libfreefare.la ntag_detect_LDADD = $(top_builddir)/libfreefare/libfreefare.la

View file

@ -59,7 +59,28 @@ main(int argc, char *argv[])
if (mifare_ultralight_connect(tag) < 0) if (mifare_ultralight_connect(tag) < 0)
errx(EXIT_FAILURE, "Error connecting to tag."); errx(EXIT_FAILURE, "Error connecting to tag.");
res = mifare_ultralightc_authenticate(tag, key); res = mifare_ultralightc_authenticate(tag, key);
printf("Authentication with default key: %s\n", res ? "fail" : "success"); if (res != 0) {
MifareDESFireKey diversified_key = NULL;
MifareKeyDeriver deriver = mifare_key_deriver_new_an10922(key, MIFARE_KEY_2K3DES);
mifare_key_deriver_begin(deriver);
mifare_key_deriver_update_uid(deriver, tag);
diversified_key = mifare_key_deriver_end(deriver);
// Disconnect and reconnect.
mifare_ultralight_disconnect(tag);
if (mifare_ultralight_connect(tag) < 0)
errx(EXIT_FAILURE, "Error connecting to tag.");
res = mifare_ultralightc_authenticate(tag, diversified_key);
printf("Authentication with default key: %s\n", res ? "fail" : "success (diversified)");
mifare_desfire_key_free(diversified_key);
mifare_key_deriver_free(deriver);
} else {
printf("Authentication with default key: success\n");
}
mifare_desfire_key_free(key); mifare_desfire_key_free(key);
mifare_ultralight_disconnect(tag); mifare_ultralight_disconnect(tag);
} }

View file

@ -0,0 +1,112 @@
#include <err.h>
#include <stdlib.h>
#include <string.h>
#include <nfc/nfc.h>
#include <freefare.h>
static int
swap_keys(FreefareTag tag, MifareDESFireKey new_key, MifareDESFireKey old_key)
{
int res;
res = mifare_ultralightc_authenticate(tag, old_key);
MifareUltralightPage data;
if (res != 0) {
mifare_ultralight_disconnect(tag);
mifare_ultralight_connect(tag);
}
return mifare_ultralightc_set_key(tag, new_key);
}
int
main(int argc, char *argv[])
{
int error = EXIT_SUCCESS;
nfc_device *device = NULL;
FreefareTag *tags = NULL;
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);
bool undiversify = (argc == 2 && strcmp("--undiversify",argv[1]) == 0);
if (argc > 2 || (argc == 2 && strcmp("--undiversify",argv[1]) != 0)) {
errx(EXIT_FAILURE, "usage: %s [--undiversify]", argv[0]);
}
nfc_connstring devices[8];
size_t device_count;
nfc_context *context;
nfc_init(&context);
if (context == NULL)
errx(EXIT_FAILURE, "Unable to init libnfc (malloc)");
device_count = nfc_list_devices(context, devices, sizeof(devices) / sizeof(*devices));
if (device_count <= 0)
errx(EXIT_FAILURE, "No NFC device found");
for (size_t d = 0; d < device_count; d++) {
if (!(device = nfc_open(context, devices[d]))) {
warnx("nfc_open() failed.");
error = EXIT_FAILURE;
continue;
}
if (!(tags = freefare_get_tags(device))) {
nfc_close(device);
errx(EXIT_FAILURE, "Error listing tags.");
}
for (int i = 0; (!error) && tags[i]; i++) {
int res;
FreefareTag tag = tags[i];
char *tag_uid = freefare_get_tag_uid(tag);
switch (freefare_get_tag_type(tag)) {
case MIFARE_ULTRALIGHT_C:
if (mifare_ultralight_connect(tag) < 0) {
errx(EXIT_FAILURE, "Error connecting to tag %s.", tag_uid);
}
break;
default:
continue;
}
if (mifare_key_deriver_begin(deriver) < 0) {
errx(EXIT_FAILURE, "Error starting key diversification");
}
if (mifare_key_deriver_update_uid(deriver, tag) < 0) {
errx(EXIT_FAILURE, "Error with key diversification");
}
if ((derived_key = mifare_key_deriver_end(deriver)) == NULL) {
errx(EXIT_FAILURE, "Error with key diversification");
}
if (undiversify) {
res = swap_keys(tag, master_key, derived_key);
} else {
res = swap_keys(tag, derived_key, master_key);
}
printf("%siversification of tag with UID %s %s.\n", undiversify?"Und":"D", tag_uid, res?"FAILED":"succeded");
mifare_desfire_key_free(derived_key);
mifare_ultralight_disconnect(tag);
free(tag_uid);
}
freefare_free_tags(tags);
nfc_close(device);
}
mifare_desfire_key_free(master_key);
mifare_key_deriver_free(deriver);
nfc_exit(context);
exit(error);
}

View file

@ -10,6 +10,7 @@ set(LIBRARY_SOURCES
mifare_desfire_crypto mifare_desfire_crypto
mifare_desfire_error mifare_desfire_error
mifare_desfire_key mifare_desfire_key
mifare_key_deriver
mifare_ultralight mifare_ultralight
ntag21x ntag21x
tlv tlv

View file

@ -12,6 +12,7 @@ libfreefare_la_SOURCES = felica.c \
mifare_desfire_crypto.c \ mifare_desfire_crypto.c \
mifare_desfire_error.c \ mifare_desfire_error.c \
mifare_desfire_key.c \ mifare_desfire_key.c \
mifare_key_deriver.c \
mad.c \ mad.c \
mifare_application.c \ mifare_application.c \
ntag21x.c \ ntag21x.c \
@ -39,6 +40,7 @@ man_MANS = freefare.3 \
mifare_desfire.3 \ mifare_desfire.3 \
mifare_desfire_aid.3 \ mifare_desfire_aid.3 \
mifare_desfire_key.3 \ mifare_desfire_key.3 \
mifare_key_deriver.3 \
mifare_ultralight.3 \ mifare_ultralight.3 \
ntag21x.3 \ ntag21x.3 \
tlv.3 tlv.3

View file

@ -469,6 +469,7 @@ int mifare_desfire_set_configuration(FreefareTag tag, bool disable_format, boo
int mifare_desfire_set_default_key(FreefareTag tag, MifareDESFireKey key); int mifare_desfire_set_default_key(FreefareTag tag, MifareDESFireKey key);
int mifare_desfire_set_ats(FreefareTag tag, uint8_t *ats); int mifare_desfire_set_ats(FreefareTag tag, uint8_t *ats);
int mifare_desfire_get_card_uid(FreefareTag tag, char **uid); int mifare_desfire_get_card_uid(FreefareTag tag, char **uid);
int mifare_desfire_get_card_uid_raw(FreefareTag tag, uint8_t uid[7]);
int mifare_desfire_get_file_ids(FreefareTag tag, uint8_t **files, size_t *count); int mifare_desfire_get_file_ids(FreefareTag tag, uint8_t **files, size_t *count);
int mifare_desfire_get_iso_file_ids(FreefareTag tag, uint16_t **files, size_t *count); int mifare_desfire_get_iso_file_ids(FreefareTag tag, uint16_t **files, size_t *count);
int mifare_desfire_get_file_settings(FreefareTag tag, uint8_t file_no, struct mifare_desfire_file_settings *settings); int mifare_desfire_get_file_settings(FreefareTag tag, uint8_t file_no, struct mifare_desfire_file_settings *settings);
@ -521,6 +522,28 @@ uint8_t *tlv_decode(const uint8_t *istream, uint8_t *type, uint16_t *size);
size_t tlv_record_length(const uint8_t *istream, size_t *field_length_size, size_t *field_value_size); size_t tlv_record_length(const uint8_t *istream, size_t *field_length_size, size_t *field_value_size);
uint8_t *tlv_append(uint8_t *a, uint8_t *b); uint8_t *tlv_append(uint8_t *a, uint8_t *b);
typedef enum mifare_key_type {
MIFARE_KEY_DES,
MIFARE_KEY_2K3DES,
MIFARE_KEY_3K3DES,
MIFARE_KEY_AES128,
MIFARE_KEY_LAST = MIFARE_KEY_AES128
} MifareKeyType;
struct mifare_key_deriver;
typedef struct mifare_key_deriver *MifareKeyDeriver;
MifareKeyDeriver mifare_key_deriver_new_an10922(MifareDESFireKey master_key, MifareKeyType output_key_type);
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);
int mifare_key_deriver_update_aid(MifareKeyDeriver deriver, MifareDESFireAID aid);
int mifare_key_deriver_update_cstr(MifareKeyDeriver deriver, const char *cstr);
MifareDESFireKey mifare_key_deriver_end(MifareKeyDeriver deriver);
int mifare_key_deriver_end_raw(MifareKeyDeriver deriver, uint8_t* diversified_bytes, size_t data_max_len);
void mifare_key_deriver_free(MifareKeyDeriver state);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif // __cplusplus #endif // __cplusplus

View file

@ -185,12 +185,7 @@ struct mifare_desfire_aid {
struct mifare_desfire_key { struct mifare_desfire_key {
uint8_t data[24]; uint8_t data[24];
enum { MifareKeyType type;
T_DES,
T_3DES,
T_3K3DES,
T_AES
} type;
DES_key_schedule ks1; DES_key_schedule ks1;
DES_key_schedule ks2; DES_key_schedule ks2;
DES_key_schedule ks3; DES_key_schedule ks3;
@ -215,6 +210,13 @@ struct mifare_desfire_tag {
uint32_t selected_application; uint32_t selected_application;
}; };
struct mifare_key_deriver {
MifareDESFireKey master_key;
MifareKeyType output_key_type;
uint8_t m[48];
int len;
};
MifareDESFireKey mifare_desfire_session_key_new(const uint8_t rnda[], const uint8_t rndb[], MifareDESFireKey authentication_key); MifareDESFireKey mifare_desfire_session_key_new(const uint8_t rnda[], const uint8_t rndb[], MifareDESFireKey authentication_key);
const char *mifare_desfire_error_lookup(uint8_t error); const char *mifare_desfire_error_lookup(uint8_t error);

View file

@ -437,14 +437,14 @@ int
mifare_desfire_authenticate(FreefareTag tag, uint8_t key_no, MifareDESFireKey key) mifare_desfire_authenticate(FreefareTag tag, uint8_t key_no, MifareDESFireKey key)
{ {
switch (key->type) { switch (key->type) {
case T_DES: case MIFARE_KEY_DES:
case T_3DES: case MIFARE_KEY_2K3DES:
return authenticate(tag, AUTHENTICATE_LEGACY, key_no, key); return authenticate(tag, AUTHENTICATE_LEGACY, key_no, key);
break; break;
case T_3K3DES: case MIFARE_KEY_3K3DES:
return authenticate(tag, AUTHENTICATE_ISO, key_no, key); return authenticate(tag, AUTHENTICATE_ISO, key_no, key);
break; break;
case T_AES: case MIFARE_KEY_AES128:
return authenticate(tag, AUTHENTICATE_AES, key_no, key); return authenticate(tag, AUTHENTICATE_AES, key_no, key);
break; break;
} }
@ -534,13 +534,13 @@ mifare_desfire_change_key(FreefareTag tag, uint8_t key_no, MifareDESFireKey new_
*/ */
if (0x000000 == MIFARE_DESFIRE(tag)->selected_application) { if (0x000000 == MIFARE_DESFIRE(tag)->selected_application) {
switch (new_key->type) { switch (new_key->type) {
case T_DES: case MIFARE_KEY_DES:
case T_3DES: case MIFARE_KEY_2K3DES:
break; break;
case T_3K3DES: case MIFARE_KEY_3K3DES:
key_no |= 0x40; key_no |= 0x40;
break; break;
case T_AES: case MIFARE_KEY_AES128:
key_no |= 0x80; key_no |= 0x80;
break; break;
} }
@ -551,12 +551,12 @@ mifare_desfire_change_key(FreefareTag tag, uint8_t key_no, MifareDESFireKey new_
int new_key_length; int new_key_length;
switch (new_key->type) { switch (new_key->type) {
case T_DES: case MIFARE_KEY_DES:
case T_3DES: case MIFARE_KEY_2K3DES:
case T_AES: case MIFARE_KEY_AES128:
new_key_length = 16; new_key_length = 16;
break; break;
case T_3K3DES: case MIFARE_KEY_3K3DES:
new_key_length = 24; new_key_length = 24;
break; break;
} }
@ -573,7 +573,7 @@ mifare_desfire_change_key(FreefareTag tag, uint8_t key_no, MifareDESFireKey new_
__cmd_n += new_key_length; __cmd_n += new_key_length;
if (new_key->type == T_AES) if (new_key->type == MIFARE_KEY_AES128)
cmd[__cmd_n++] = new_key->aes_version; cmd[__cmd_n++] = new_key->aes_version;
if ((MIFARE_DESFIRE(tag)->authenticated_key_no & 0x0f) != (key_no & 0x0f)) { if ((MIFARE_DESFIRE(tag)->authenticated_key_no & 0x0f) != (key_no & 0x0f)) {
@ -1037,12 +1037,12 @@ mifare_desfire_set_default_key(FreefareTag tag, MifareDESFireKey key)
BUFFER_APPEND(cmd, 0x01); BUFFER_APPEND(cmd, 0x01);
size_t key_data_length; size_t key_data_length;
switch (key->type) { switch (key->type) {
case T_DES: case MIFARE_KEY_DES:
case T_3DES: case MIFARE_KEY_2K3DES:
case T_AES: case MIFARE_KEY_AES128:
key_data_length = 16; key_data_length = 16;
break; break;
case T_3K3DES: case MIFARE_KEY_3K3DES:
key_data_length = 24; key_data_length = 24;
break; break;
} }
@ -1101,7 +1101,7 @@ mifare_desfire_set_ats(FreefareTag tag, uint8_t *ats)
} }
int int
mifare_desfire_get_card_uid(FreefareTag tag, char **uid) mifare_desfire_get_card_uid_raw(FreefareTag tag, uint8_t uid[])
{ {
ASSERT_ACTIVE(tag); ASSERT_ACTIVE(tag);
@ -1122,6 +1122,20 @@ mifare_desfire_get_card_uid(FreefareTag tag, char **uid)
if (!p) if (!p)
return errno = EINVAL, -1; return errno = EINVAL, -1;
memcpy(uid, p, 7);
return 0;
}
int
mifare_desfire_get_card_uid(FreefareTag tag, char **uid)
{
uint8_t p[7];
if (mifare_desfire_get_card_uid_raw(tag, p) < 0) {
return -1;
}
if (!(*uid = malloc(2 * 7 + 1))) { if (!(*uid = malloc(2 * 7 + 1))) {
return -1; return -1;
} }

View file

@ -184,12 +184,12 @@ key_block_size(const MifareDESFireKey key)
size_t block_size; size_t block_size;
switch (key->type) { switch (key->type) {
case T_DES: case MIFARE_KEY_DES:
case T_3DES: case MIFARE_KEY_2K3DES:
case T_3K3DES: case MIFARE_KEY_3K3DES:
block_size = 8; block_size = 8;
break; break;
case T_AES: case MIFARE_KEY_AES128:
block_size = 16; block_size = 16;
break; break;
} }
@ -206,12 +206,12 @@ key_macing_length(const MifareDESFireKey key)
size_t mac_length; size_t mac_length;
switch (key->type) { switch (key->type) {
case T_DES: case MIFARE_KEY_DES:
case T_3DES: case MIFARE_KEY_2K3DES:
mac_length = MAC_LENGTH; mac_length = MAC_LENGTH;
break; break;
case T_3K3DES: case MIFARE_KEY_3K3DES:
case T_AES: case MIFARE_KEY_AES128:
mac_length = CMAC_LENGTH; mac_length = CMAC_LENGTH;
break; break;
} }
@ -669,7 +669,7 @@ mifare_cypher_single_block(MifareDESFireKey key, uint8_t *data, uint8_t *ivect,
uint8_t edata[MAX_CRYPTO_BLOCK_SIZE]; uint8_t edata[MAX_CRYPTO_BLOCK_SIZE];
switch (key->type) { switch (key->type) {
case T_DES: case MIFARE_KEY_DES:
switch (operation) { switch (operation) {
case MCO_ENCYPHER: case MCO_ENCYPHER:
DES_ecb_encrypt((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_ENCRYPT); DES_ecb_encrypt((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_ENCRYPT);
@ -679,7 +679,7 @@ mifare_cypher_single_block(MifareDESFireKey key, uint8_t *data, uint8_t *ivect,
break; break;
} }
break; break;
case T_3DES: case MIFARE_KEY_2K3DES:
switch (operation) { switch (operation) {
case MCO_ENCYPHER: case MCO_ENCYPHER:
DES_ecb_encrypt((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_ENCRYPT); DES_ecb_encrypt((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_ENCRYPT);
@ -693,7 +693,7 @@ mifare_cypher_single_block(MifareDESFireKey key, uint8_t *data, uint8_t *ivect,
break; break;
} }
break; break;
case T_3K3DES: case MIFARE_KEY_3K3DES:
switch (operation) { switch (operation) {
case MCO_ENCYPHER: case MCO_ENCYPHER:
DES_ecb_encrypt((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_ENCRYPT); DES_ecb_encrypt((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_ENCRYPT);
@ -707,7 +707,7 @@ mifare_cypher_single_block(MifareDESFireKey key, uint8_t *data, uint8_t *ivect,
break; break;
} }
break; break;
case T_AES: case MIFARE_KEY_AES128:
switch (operation) { switch (operation) {
case MCO_ENCYPHER: case MCO_ENCYPHER:
AES_set_encrypt_key(key->data, 8 * 16, &k); AES_set_encrypt_key(key->data, 8 * 16, &k);

View file

@ -13,7 +13,7 @@ update_key_schedules(MifareDESFireKey key)
{ {
DES_set_key((DES_cblock *)key->data, &(key->ks1)); DES_set_key((DES_cblock *)key->data, &(key->ks1));
DES_set_key((DES_cblock *)(key->data + 8), &(key->ks2)); DES_set_key((DES_cblock *)(key->data + 8), &(key->ks2));
if (T_3K3DES == key->type) { if (MIFARE_KEY_3K3DES == key->type) {
DES_set_key((DES_cblock *)(key->data + 16), &(key->ks3)); DES_set_key((DES_cblock *)(key->data + 16), &(key->ks3));
} }
} }
@ -34,7 +34,7 @@ mifare_desfire_des_key_new_with_version(const uint8_t value[8])
MifareDESFireKey key; MifareDESFireKey key;
if ((key = malloc(sizeof(struct mifare_desfire_key)))) { if ((key = malloc(sizeof(struct mifare_desfire_key)))) {
key->type = T_DES; key->type = MIFARE_KEY_DES;
memcpy(key->data, value, 8); memcpy(key->data, value, 8);
memcpy(key->data + 8, value, 8); memcpy(key->data + 8, value, 8);
update_key_schedules(key); update_key_schedules(key);
@ -60,7 +60,7 @@ mifare_desfire_3des_key_new_with_version(const uint8_t value[16])
MifareDESFireKey key; MifareDESFireKey key;
if ((key = malloc(sizeof(struct mifare_desfire_key)))) { if ((key = malloc(sizeof(struct mifare_desfire_key)))) {
key->type = T_3DES; key->type = MIFARE_KEY_2K3DES;
memcpy(key->data, value, 16); memcpy(key->data, value, 16);
update_key_schedules(key); update_key_schedules(key);
} }
@ -83,7 +83,7 @@ mifare_desfire_3k3des_key_new_with_version(const uint8_t value[24])
MifareDESFireKey key; MifareDESFireKey key;
if ((key = malloc(sizeof(struct mifare_desfire_key)))) { if ((key = malloc(sizeof(struct mifare_desfire_key)))) {
key->type = T_3K3DES; key->type = MIFARE_KEY_3K3DES;
memcpy(key->data, value, 24); memcpy(key->data, value, 24);
update_key_schedules(key); update_key_schedules(key);
} }
@ -103,7 +103,7 @@ mifare_desfire_aes_key_new_with_version(const uint8_t value[16], uint8_t version
if ((key = malloc(sizeof(struct mifare_desfire_key)))) { if ((key = malloc(sizeof(struct mifare_desfire_key)))) {
memcpy(key->data, value, 16); memcpy(key->data, value, 16);
key->type = T_AES; key->type = MIFARE_KEY_AES128;
key->aes_version = version; key->aes_version = version;
} }
return key; return key;
@ -114,7 +114,7 @@ mifare_desfire_key_get_version(MifareDESFireKey key)
{ {
uint8_t version = 0; uint8_t version = 0;
if (key->type == T_AES) if (key->type == MIFARE_KEY_AES128)
return key->aes_version; return key->aes_version;
for (int n = 0; n < 8; n++) { for (int n = 0; n < 8; n++) {
@ -127,7 +127,7 @@ mifare_desfire_key_get_version(MifareDESFireKey key)
void void
mifare_desfire_key_set_version(MifareDESFireKey key, uint8_t version) mifare_desfire_key_set_version(MifareDESFireKey key, uint8_t version)
{ {
if (key->type == T_AES) { if (key->type == MIFARE_KEY_AES128) {
key->aes_version = version; key->aes_version = version;
return; return;
} }
@ -137,7 +137,7 @@ mifare_desfire_key_set_version(MifareDESFireKey key, uint8_t version)
key->data[n] &= 0xfe; key->data[n] &= 0xfe;
key->data[n] |= version_bit; key->data[n] |= version_bit;
switch (key->type) { switch (key->type) {
case T_DES: case MIFARE_KEY_DES:
// DESFire cards always treat DES keys as special cases of 2K3DES // DESFire cards always treat DES keys as special cases of 2K3DES
// keys. The DESFire functional specification explicitly points // keys. The DESFire functional specification explicitly points
// out that if the subkeys of a 2K3DES key are exactly identical // out that if the subkeys of a 2K3DES key are exactly identical
@ -148,7 +148,7 @@ mifare_desfire_key_set_version(MifareDESFireKey key, uint8_t version)
// next line ensure that. // next line ensure that.
key->data[n + 8] = key->data[n]; key->data[n + 8] = key->data[n];
break; break;
case T_3DES: case MIFARE_KEY_2K3DES:
// But what if we really did want the PICC to treat the key as a // But what if we really did want the PICC to treat the key as a
// real 2K3DES key, even if the actual 56 bits of the subkeys did // real 2K3DES key, even if the actual 56 bits of the subkeys did
// match? To ensure that such as case still works (largely because // match? To ensure that such as case still works (largely because
@ -175,19 +175,19 @@ mifare_desfire_session_key_new(const uint8_t rnda[], const uint8_t rndb[], Mifar
uint8_t buffer[24]; uint8_t buffer[24];
switch (authentication_key->type) { switch (authentication_key->type) {
case T_DES: case MIFARE_KEY_DES:
memcpy(buffer, rnda, 4); memcpy(buffer, rnda, 4);
memcpy(buffer + 4, rndb, 4); memcpy(buffer + 4, rndb, 4);
key = mifare_desfire_des_key_new_with_version(buffer); key = mifare_desfire_des_key_new_with_version(buffer);
break; break;
case T_3DES: case MIFARE_KEY_2K3DES:
memcpy(buffer, rnda, 4); memcpy(buffer, rnda, 4);
memcpy(buffer + 4, rndb, 4); memcpy(buffer + 4, rndb, 4);
memcpy(buffer + 8, rnda + 4, 4); memcpy(buffer + 8, rnda + 4, 4);
memcpy(buffer + 12, rndb + 4, 4); memcpy(buffer + 12, rndb + 4, 4);
key = mifare_desfire_3des_key_new_with_version(buffer); key = mifare_desfire_3des_key_new_with_version(buffer);
break; break;
case T_3K3DES: case MIFARE_KEY_3K3DES:
memcpy(buffer, rnda, 4); memcpy(buffer, rnda, 4);
memcpy(buffer + 4, rndb, 4); memcpy(buffer + 4, rndb, 4);
memcpy(buffer + 8, rnda + 6, 4); memcpy(buffer + 8, rnda + 6, 4);
@ -196,7 +196,7 @@ mifare_desfire_session_key_new(const uint8_t rnda[], const uint8_t rndb[], Mifar
memcpy(buffer + 20, rndb + 12, 4); memcpy(buffer + 20, rndb + 12, 4);
key = mifare_desfire_3k3des_key_new(buffer); key = mifare_desfire_3k3des_key_new(buffer);
break; break;
case T_AES: case MIFARE_KEY_AES128:
memcpy(buffer, rnda, 4); memcpy(buffer, rnda, 4);
memcpy(buffer + 4, rndb, 4); memcpy(buffer + 4, rndb, 4);
memcpy(buffer + 8, rnda + 12, 4); memcpy(buffer + 8, rnda + 12, 4);

View file

@ -0,0 +1,169 @@
.\" Copyright (C) 2018 Robert Quattlebaum
.\"
.\" 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 <http://www.gnu.org/licenses/>
.\"
.Dd January 4, 2018
.Dt MIFARE_KEY_DERIVER 3
.Os
.\" _ _
.\" | \ | | __ _ _ __ ___ ___
.\" | \| |/ _` | '_ ` _ \ / _ \
.\" | |\ | (_| | | | | | | __/
.\" |_| \_|\__,_|_| |_| |_|\___|
.\"
.Sh NAME
.Nm mifare_key_deriver_new_an10922 ,
.Nm mifare_key_deriver_begin ,
.Nm mifare_key_deriver_update_data ,
.Nm mifare_key_deriver_update_uid ,
.Nm mifare_key_deriver_update_aid ,
.Nm mifare_key_deriver_update_cstr ,
.Nm mifare_key_deriver_end ,
.Nm mifare_key_deriver_end_raw ,
.Nm mifare_key_deriver_free ,
.Nd Mifare Key Derivation Functions
.\" _ _ _
.\" | | (_) |__ _ __ __ _ _ __ _ _
.\" | | | | '_ \| '__/ _` | '__| | | |
.\" | |___| | |_) | | | (_| | | | |_| |
.\" |_____|_|_.__/|_| \__,_|_| \__, |
.\" |___/
.Sh LIBRARY
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"
.Ft int
.Fn mifare_key_deriver_begin "MifareKeyDeriver deriver"
.Ft int
.Fn mifare_key_deriver_update_data "MifareKeyDeriver deriver" "const uint8_t *data" "size_t len"
.Ft int
.Fn mifare_key_deriver_update_uid "MifareKeyDeriver deriver" "FreefareTag tag"
.Ft int
.Fn mifare_key_deriver_update_aid "MifareKeyDeriver deriver" "MifareDESFireAID aid"
.Ft int
.Fn mifare_key_deriver_update_cstr "MifareKeyDeriver deriver" "const char *cstr"
.Ft MifareDESFireKey
.Fn mifare_key_deriver_end "MifareKeyDeriver deriver"
.Ft int
.Fn mifare_key_deriver_end_raw "MifareKeyDeriver deriver" "uint8_t* derived_data" "size_t data_max_len"
.Ft void
.Fn mifare_key_deriver_free "MifareKeyDeriver deriver"
.\" ____ _ _ _
.\" | _ \ ___ ___ ___ _ __(_)_ __ | |_(_) ___ _ __
.\" | | | |/ _ \/ __|/ __| '__| | '_ \| __| |/ _ \| '_ \
.\" | |_| | __/\__ \ (__| | | | |_) | |_| | (_) | | | |
.\" |____/ \___||___/\___|_| |_| .__/ \__|_|\___/|_| |_|
.\" |_|
.Sh DESCRIPTION
The
.Fn mifare_key_deriver_*
family of functions allows for the diversification of Mifare DESFire keys.
.Pp
The
.Fn mifare_key_deriver_new_an10922
function alocates a new key deriver object which can be used to generate
diversified keys from
.Va master_key
in accordinance with AN10922.
.Pp
The
.Fn mifare_key_deriver_begin
function marks the start of the derivation of a new diversified key.
.Pp
The
.Fn mifare_key_deriver_update_data ,
.Fn mifare_key_deriver_update_uid ,
.Fn mifare_key_deriver_update_aid
and
.Fn mifare_key_deriver_update_cstr
functions are used to specify the information that should be used to derive
the diversified key from the master key.
.Pp
The
.Fn mifare_key_deriver_end
function marks the end of the derivation and returns the new diversified key.
It is the responsibility of the caller to to free the returned key by calling
.Fn mifare_desfire_key_free .
.Fn mifare_key_deriver_end_raw
is a variant used to directly fetch the raw bytes of the derived key.
.Pp
.\" ____ _ _
.\" | _ \ ___| |_ _ _ _ __ _ __ __ ____ _| |_ _ ___ ___
.\" | |_) / _ \ __| | | | '__| '_ \ \ \ / / _` | | | | |/ _ \/ __|
.\" | _ < __/ |_| |_| | | | | | | \ V / (_| | | |_| | __/\__ \
.\" |_| \_\___|\__|\__,_|_| |_| |_| \_/ \__,_|_|\__,_|\___||___/
.\"
.Sh RETURN VALUES
.Fn mifare_key_deriver_new_an10922
returns the allocated key deriver or
.Va NULL
on failure.
.Pp
The
.Fn mifare_key_deriver_begin ,
.Fn mifare_key_deriver_update_data ,
.Fn mifare_key_deriver_update_uid ,
.Fn mifare_key_deriver_update_aid
and
.Fn mifare_key_deriver_update_cstr
functions return
.Va 0
on success and
.Va -1
on failure.
.Pp
The
.Fn mifare_key_deriver_end
function returns the new diversified key on success and
.Va NULL
on failure. It is the responsibility of the
caller to to free the returned key by calling
.Fn mifare_desfire_key_free .
.Pp
The
.Fn mifare_key_deriver_end_raw
function returns
.Va -1
on failure. On success, it returns the number of bytes that were derived. If
.Va data_max_len
is smaller than the return value, then no bytes were written to
.Va derived_data .
.Pp
Upon failure, all methods update
.Va errno
with the appropriate error code.
.\" ____ _
.\" / ___| ___ ___ __ _| |___ ___
.\" \___ \ / _ \/ _ \ / _` | / __|/ _ \
.\" ___) | __/ __/ | (_| | \__ \ (_) |
.\" |____/ \___|\___| \__,_|_|___/\___/
.\"
.Sh SEE ALSO
.Xr mifare_desfire_key 3
.\" _ _ _
.\" / \ _ _| |_| |__ ___ _ __ ___
.\" / _ \| | | | __| '_ \ / _ \| '__/ __|
.\" / ___ \ |_| | |_| | | | (_) | | \__ \
.\" /_/ \_\__,_|\__|_| |_|\___/|_| |___/
.\"
.Sh AUTHORS
.An Robert Quattlebaum darco@deepdarc.com

View file

@ -0,0 +1,301 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <openssl/des.h>
#include <freefare.h>
#include "freefare_internal.h"
#define AN10922_DIV_AES128 0x01
#define AN10922_DIV_AES192_1 0x11
#define AN10922_DIV_AES192_2 0x12
#define AN10922_DIV_2K3DES_1 0x21
#define AN10922_DIV_2K3DES_2 0x22
#define AN10922_DIV_3K3DES_1 0x31
#define AN10922_DIV_3K3DES_2 0x32
#define AN10922_DIV_3K3DES_3 0x33
MifareKeyDeriver
mifare_key_deriver_new_an10922(MifareDESFireKey master_key, MifareKeyType output_key_type)
{
MifareKeyDeriver deriver = NULL;
const int master_key_block_size = key_block_size(master_key);
switch(output_key_type) {
case MIFARE_KEY_AES128:
if (master_key_block_size != 16) {
errno = EINVAL;
return NULL;
}
break;
case MIFARE_KEY_2K3DES:
if ((master_key_block_size != 8) && (master_key_block_size != 16)) {
errno = EINVAL;
return NULL;
}
break;
case MIFARE_KEY_3K3DES:
if (master_key_block_size != 8) {
errno = EINVAL;
return NULL;
}
break;
case MIFARE_KEY_DES:
// AN10922 doesn't define a DIV constant for
// deriving plain 56-bit DES keys.
default:
// Unsupported output key type.
errno = EINVAL;
return NULL;
}
if ((deriver = malloc(sizeof(struct mifare_key_deriver)))) {
deriver->master_key = master_key;
deriver->output_key_type = output_key_type;
cmac_generate_subkeys(deriver->master_key);
}
return deriver;
}
void
mifare_key_deriver_free(MifareKeyDeriver deriver)
{
memset(deriver, 0, sizeof(*deriver));
free(deriver);
}
int
mifare_key_deriver_begin(MifareKeyDeriver deriver)
{
memset(deriver->m, 0, sizeof(deriver->m));
// We skip byte zero for the DIV constant, which
// we will fill out in the call to end(). We also
// use len==0 as an overflow error condition.
deriver->len = 1;
return 0;
}
int
mifare_key_deriver_update_data(MifareKeyDeriver deriver, const uint8_t *data, size_t len)
{
if (deriver->len == 0) {
// Overflow from previous update call.
errno = EOVERFLOW;
return -1;
}
if (len > sizeof(deriver->m) - deriver->len) {
deriver->len = 0; // Remember that we have an error.
errno = EOVERFLOW;
return -1;
}
memcpy(deriver->m + deriver->len, data, len);
deriver->len += (int)len;
return 0;
}
int
mifare_key_deriver_update_cstr(MifareKeyDeriver deriver, const char *cstr)
{
return mifare_key_deriver_update_data(deriver, (const uint8_t*)cstr, strlen(cstr));
}
int
mifare_key_deriver_update_aid(MifareKeyDeriver deriver, MifareDESFireAID aid)
{
return mifare_key_deriver_update_data(deriver, aid->data, sizeof(aid->data));
}
int
mifare_key_deriver_update_uid(MifareKeyDeriver deriver, FreefareTag tag)
{
int ret = 0;
const uint8_t* uid_data = NULL;
uint8_t desfire_uid[7];
uint8_t uid_len = 0;
switch (tag->info.nm.nmt) {
case NMT_FELICA:
uid_data = tag->info.nti.nfi.abtId;
uid_len = 8;
break;
case NMT_ISO14443A:
uid_data = tag->info.nti.nai.abtUid;
uid_len = tag->info.nti.nai.szUidLen;
break;
case NMT_DEP:
case NMT_ISO14443B2CT:
case NMT_ISO14443B2SR:
case NMT_ISO14443B:
case NMT_ISO14443BI:
case NMT_JEWEL:
case NMT_BARCODE:
ret = -1;
errno = EINVAL;
break;
}
if ((uid_len == 4) && (freefare_get_tag_type(tag) == MIFARE_DESFIRE)) {
// DESFire card is using random UID. We need
// to explicitly get the real static UID.
if (mifare_desfire_get_card_uid_raw(tag, desfire_uid) < 0) {
ret = -1;
} else {
uid_data = desfire_uid;
}
}
if (ret >= 0) {
ret = mifare_key_deriver_update_data(deriver, uid_data, uid_len);
}
return ret;
}
static void
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);
}
static uint8_t
get_key_type_data_len(MifareKeyType type)
{
switch(type) {
case MIFARE_KEY_AES128:
case MIFARE_KEY_2K3DES:
return 16;
case MIFARE_KEY_DES:
return 8;
case MIFARE_KEY_3K3DES:
return 24;
}
// This should never happen.
return 0;
}
static uint8_t
get_key_data_len(MifareDESFireKey key)
{
return get_key_type_data_len(key->type);
}
int
mifare_key_deriver_end_raw(MifareKeyDeriver deriver, uint8_t* diversified_bytes, size_t max_len)
{
const uint8_t len = get_key_type_data_len(deriver->output_key_type);
const int master_key_block_size = key_block_size(deriver->master_key);
uint8_t data[24];
if (deriver->len == 0) {
// Overflow from previous update call.
// We must not emit a key if there was a previous error,
// otherwise bugs may go unnoticed.
errno = EOVERFLOW;
return -1;
}
if (len == 0) {
errno = EINVAL;
return -1;
}
if (max_len > len) {
max_len = len;
}
memset(data, 0, sizeof(data));
if ((master_key_block_size == 16) && (deriver->output_key_type == MIFARE_KEY_AES128)) {
deriver->m[0] = AN10922_DIV_AES128;
deriver_cmac(deriver, data);
} else if ((master_key_block_size == 16) && (deriver->output_key_type == MIFARE_KEY_2K3DES)) {
// This technically isn't defined in AN10922, but it is
// straightforward adaptation that is useful for diversifying
// MIFARE Ultralight C keys.
deriver->m[0] = AN10922_DIV_2K3DES_1;
deriver_cmac(deriver, data);
} else if ((master_key_block_size == 8) && (deriver->output_key_type == MIFARE_KEY_2K3DES)) {
deriver->m[0] = AN10922_DIV_2K3DES_1;
deriver_cmac(deriver, data + 0);
deriver->m[0] = AN10922_DIV_2K3DES_2;
deriver_cmac(deriver, data + 8);
} else if ((master_key_block_size == 8) && (deriver->output_key_type == MIFARE_KEY_3K3DES)) {
deriver->m[0] = AN10922_DIV_3K3DES_1;
deriver_cmac(deriver, data + 0);
deriver->m[0] = AN10922_DIV_3K3DES_2;
deriver_cmac(deriver, data + 8);
deriver->m[0] = AN10922_DIV_3K3DES_3;
deriver_cmac(deriver, data + 16);
} else {
// AN10922 doesn't describe how to perform this derivation.
errno = EINVAL;
return -1;
}
memcpy(diversified_bytes, data, max_len);
// Wipe key info from stack
memset(data, 0, sizeof(data));
return len;
}
MifareDESFireKey
mifare_key_deriver_end(MifareKeyDeriver deriver)
{
MifareDESFireKey ret = NULL;
uint8_t data[24];
int len = mifare_key_deriver_end_raw(deriver, data, sizeof(data));
if (len <= 0) {
return NULL;
}
switch (deriver->output_key_type) {
case MIFARE_KEY_AES128:
ret = mifare_desfire_aes_key_new_with_version(data, 0);
break;
case MIFARE_KEY_DES:
ret = mifare_desfire_des_key_new(data);
break;
case MIFARE_KEY_2K3DES:
ret = mifare_desfire_3des_key_new(data);
break;
case MIFARE_KEY_3K3DES:
ret = mifare_desfire_3k3des_key_new(data);
break;
}
// Update the key version
if (ret != NULL) {
mifare_desfire_key_set_version(ret, mifare_desfire_key_get_version(deriver->master_key));
}
// Wipe key info from stack
memset(data, 0, sizeof(data));
return ret;
}

View file

@ -340,7 +340,7 @@ mifare_ultralightc_set_key(FreefareTag tag, MifareDESFireKey key)
{ {
MifareUltralightPage data; MifareUltralightPage data;
if (key->type != T_3DES) { if (key->type != MIFARE_KEY_2K3DES) {
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }

View file

@ -24,6 +24,7 @@ cutter_unit_test_libs = \
test_mifare_desfire_des.la \ test_mifare_desfire_des.la \
test_mifare_desfire_ev1.la \ test_mifare_desfire_ev1.la \
test_mifare_desfire_key.la \ test_mifare_desfire_key.la \
test_mifare_key_deriver_an10922.la \
test_mifare_ultralight.la \ test_mifare_ultralight.la \
test_tlv.la test_tlv.la
@ -89,6 +90,9 @@ test_mifare_desfire_ev1_la_LIBADD = $(top_builddir)/libfreefare/libfreefare.la \
test_mifare_desfire_key_la_SOURCES = test_mifare_desfire_key.c test_mifare_desfire_key_la_SOURCES = test_mifare_desfire_key.c
test_mifare_desfire_key_la_LIBADD = $(top_builddir)/libfreefare/libfreefare.la test_mifare_desfire_key_la_LIBADD = $(top_builddir)/libfreefare/libfreefare.la
test_mifare_key_deriver_an10922_la_SOURCES = test_mifare_key_deriver_an10922.c
test_mifare_key_deriver_an10922_la_LIBADD = $(top_builddir)/libfreefare/libfreefare.la
test_mifare_ultralight_la_SOURCES = test_mifare_ultralight.c \ test_mifare_ultralight_la_SOURCES = test_mifare_ultralight.c \
mifare_ultralight_fixture.c \ mifare_ultralight_fixture.c \
fixture.h fixture.h

View file

@ -0,0 +1,143 @@
#include <cutter.h>
#include <freefare.h>
#include "freefare_internal.h"
void
test_mifare_key_deriver_an10922_aes128(void)
{
MifareDESFireKey key = NULL;
MifareDESFireKey derived_key = NULL;
MifareKeyDeriver deriver = NULL;
int version, ret;
// These test vectors come from NCP's AN10922, section 2.2.1
uint8_t key1_aes128_data[16] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0XEE, 0xFF };
uint8_t key1_aes128_version = 16;
uint8_t key1_aes128_derived_data[16] = { 0xA8, 0xDD, 0x63, 0xA3, 0xB8, 0x9D, 0x54, 0xB3, 0x7C, 0xA8, 0x02, 0x47, 0x3F, 0xDA, 0x91, 0x75 };
uint8_t key1_aes128_check_m[] = { 0x01, 0x04, 0x78, 0x2E, 0x21, 0x80, 0x1D, 0x80, 0x30, 0x42, 0xF5, 0x4E, 0x58, 0x50, 0x20, 0x41, 0x62, 0x75 };
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);
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\x78\x2E\x21\x80\x1D\x80");
cut_assert_equal_int(ret, 0, cut_message("mifare_key_deriver_update failed"));
ret = mifare_key_deriver_update_cstr(deriver, "\x30\x42\xF5");
cut_assert_equal_int(ret, 0, cut_message("mifare_key_deriver_update failed"));
ret = mifare_key_deriver_update_cstr(deriver, "NXP Abu");
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)
{
MifareDESFireKey key = NULL;
MifareDESFireKey derived_key = NULL;
MifareKeyDeriver deriver = NULL;
int version, ret;
// These test vectors come from NCP's AN10922, section 2.4.1
uint8_t key1_2k3des_data[16] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0XEE, 0xFF };
uint8_t key1_2k3des_derived_data[16] = { 0x16, 0xf9, 0x58, 0x7d, 0x9e, 0x89, 0x10, 0xc9, 0x6b, 0x96, 0x49, 0xd0, 0x07, 0x10, 0x7d, 0xd6 };
uint8_t key1_2k3des_check_m[] = { 0x22, 0x04, 0x78, 0x2E, 0x21, 0x80, 0x1D, 0x80, 0x30, 0x42, 0xF5, 0x4E, 0x58, 0x50, 0x20, 0x41 };
key = mifare_desfire_3des_key_new_with_version(key1_2k3des_data);
deriver = mifare_key_deriver_new_an10922(key, MIFARE_KEY_2K3DES);
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\x78\x2E\x21\x80\x1D\x80");
cut_assert_equal_int(ret, 0, cut_message("mifare_key_deriver_update failed"));
ret = mifare_key_deriver_update_cstr(deriver, "\x30\x42\xF5");
cut_assert_equal_int(ret, 0, cut_message("mifare_key_deriver_update failed"));
ret = mifare_key_deriver_update_cstr(deriver, "NXP A");
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_2k3des_check_m, sizeof(key1_2k3des_check_m), deriver->m, deriver->len, cut_message("Wrong CMAC message"));
version = mifare_desfire_key_get_version(derived_key);
cut_assert_equal_int(mifare_desfire_key_get_version(key), version, cut_message("Wrong derived key version"));
cut_assert_equal_int(derived_key->type, MIFARE_KEY_2K3DES, cut_message("Wrong derived key type"));
cut_assert_equal_memory(key1_2k3des_derived_data, sizeof(key1_2k3des_derived_data), derived_key->data, sizeof(key1_2k3des_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_3k3des(void)
{
MifareDESFireKey key = NULL;
MifareDESFireKey derived_key = NULL;
MifareKeyDeriver deriver = NULL;
int version, ret;
// These test vectors come from NCP's AN10922, section 2.5.1
uint8_t key1_3k3des_data[24] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0XEE, 0xFF, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
uint8_t key1_3k3des_derived_data[24] = { 0x2E, 0x0D, 0xD0, 0x37, 0x74, 0xD3, 0xFA, 0x9B, 0x57, 0x05, 0xAB, 0x0B, 0xDA, 0x91, 0xCA, 0x0B, 0x55, 0xB8, 0xE0, 0x7F, 0xCD, 0xBF, 0x10, 0xEC };
uint8_t key1_3k3des_check_m[] = { 0x33, 0x04, 0x78, 0x2E, 0x21, 0x80, 0x1D, 0x80, 0x30, 0x42, 0xF5, 0x4E, 0x58, 0x50 };
key = mifare_desfire_3k3des_key_new_with_version(key1_3k3des_data);
deriver = mifare_key_deriver_new_an10922(key, MIFARE_KEY_3K3DES);
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\x78\x2E\x21\x80\x1D\x80");
cut_assert_equal_int(ret, 0, cut_message("mifare_key_deriver_update failed"));
ret = mifare_key_deriver_update_cstr(deriver, "\x30\x42\xF5");
cut_assert_equal_int(ret, 0, cut_message("mifare_key_deriver_update failed"));
ret = mifare_key_deriver_update_cstr(deriver, "NXP");
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_3k3des_check_m, sizeof(key1_3k3des_check_m), deriver->m, deriver->len, cut_message("Wrong CMAC message"));
version = mifare_desfire_key_get_version(derived_key);
cut_assert_equal_int(mifare_desfire_key_get_version(key), version, cut_message("Wrong derived key version"));
cut_assert_equal_int(derived_key->type, MIFARE_KEY_3K3DES, cut_message("Wrong derived key type"));
cut_assert_equal_memory(key1_3k3des_derived_data, sizeof(key1_3k3des_derived_data), derived_key->data, sizeof(key1_3k3des_derived_data), cut_message("Wrong derived key"));
mifare_key_deriver_free(deriver);
mifare_desfire_key_free(derived_key);
mifare_desfire_key_free(key);
}