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:
parent
3d398dcd2f
commit
9d88c18833
15 changed files with 864 additions and 68 deletions
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
112
examples/mifare-ultralightc-diversify.c
Normal file
112
examples/mifare-ultralightc-diversify.c
Normal 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);
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
169
libfreefare/mifare_key_deriver.3
Normal file
169
libfreefare/mifare_key_deriver.3
Normal 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
|
301
libfreefare/mifare_key_deriver.c
Normal file
301
libfreefare/mifare_key_deriver.c
Normal 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;
|
||||||
|
}
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
143
test/test_mifare_key_deriver_an10922.c
Normal file
143
test/test_mifare_key_deriver_an10922.c
Normal 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);
|
||||||
|
}
|
Loading…
Reference in a new issue