mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 05:43:48 -07:00
Refactored communication encryption
This commit is contained in:
parent
eb29e1a17e
commit
ad875a8c01
1 changed files with 71 additions and 53 deletions
|
@ -28,6 +28,7 @@
|
||||||
#include "crypto/libpcrypto.h" // aes_decode
|
#include "crypto/libpcrypto.h" // aes_decode
|
||||||
#include "cmac.h"
|
#include "cmac.h"
|
||||||
#include "cmdhf14a.h"
|
#include "cmdhf14a.h"
|
||||||
|
#include "ui.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "crc32.h"
|
#include "crc32.h"
|
||||||
|
|
||||||
|
@ -213,6 +214,10 @@ static int ntag424_calc_file_settings_size(const ntag424_file_settings_t *settin
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ntag424_calc_file_write_settings_size(const ntag424_file_settings_t *settings) {
|
||||||
|
return ntag424_calc_file_settings_size(settings) - 4;
|
||||||
|
}
|
||||||
|
|
||||||
static int ntag424_read_file_settings(uint8_t fileno, ntag424_file_settings_t *settings_out) {
|
static int ntag424_read_file_settings(uint8_t fileno, ntag424_file_settings_t *settings_out) {
|
||||||
const size_t RESPONSE_LENGTH = sizeof(ntag424_file_settings_t) + 2;
|
const size_t RESPONSE_LENGTH = sizeof(ntag424_file_settings_t) + 2;
|
||||||
uint8_t cmd[] = { 0x90, 0xF5, 0x00, 0x00, 0x01, fileno, 0x00};
|
uint8_t cmd[] = { 0x90, 0xF5, 0x00, 0x00, 0x01, fileno, 0x00};
|
||||||
|
@ -280,8 +285,52 @@ static void ntag424_calc_mac(ntag424_session_keys_t *session_keys, uint8_t comma
|
||||||
free(mac_input);
|
free(mac_input);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write file settings is done with full communication mode. This can probably be broken out
|
static int ntag424_comm_full_encrypt_apdu(const uint8_t *apdu_in, uint8_t *apdu_out, int *apdu_out_size, ntag424_session_keys_t *session_keys)
|
||||||
// and used for read/write of file when full communication mode is needed.
|
{
|
||||||
|
#define MAC_SIZE 8
|
||||||
|
#define APDU_HEADER_SIZE 5
|
||||||
|
#define APDU_OVERHEAD (APDU_HEADER_SIZE + 1)
|
||||||
|
|
||||||
|
// ------- Calculate IV
|
||||||
|
uint8_t ivc[16];
|
||||||
|
ntag424_calc_iv(session_keys, ivc);
|
||||||
|
|
||||||
|
|
||||||
|
// ------- Copy apdu header
|
||||||
|
size_t size = apdu_in[4];
|
||||||
|
memcpy(apdu_out, apdu_in, 6);
|
||||||
|
|
||||||
|
size_t encrypt_data_size = size - 1;
|
||||||
|
size_t padded_data_size = encrypt_data_size + 16 - (encrypt_data_size % 16); // pad up to 16 byte blocks
|
||||||
|
uint8_t temp_buffer[256] = {0};
|
||||||
|
|
||||||
|
int apdu_final_size = APDU_OVERHEAD + padded_data_size + 8 + 1; // + MAC and CmdHdr
|
||||||
|
if(*apdu_out_size < apdu_final_size)
|
||||||
|
{
|
||||||
|
PrintAndLogEx(ERR, "APDU out buffer not large enough");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
*apdu_out_size = apdu_final_size;
|
||||||
|
|
||||||
|
// ------ Pad data
|
||||||
|
memcpy(temp_buffer, &apdu_in[APDU_HEADER_SIZE + 1], encrypt_data_size); // We encrypt everything except the CmdHdr
|
||||||
|
temp_buffer[encrypt_data_size] = 0x80;
|
||||||
|
|
||||||
|
// ------ Encrypt it
|
||||||
|
memcpy(apdu_out, apdu_in, 4);
|
||||||
|
aes_encode(ivc, session_keys->encryption, temp_buffer, &apdu_out[6], padded_data_size);
|
||||||
|
|
||||||
|
// ------ Add MAC
|
||||||
|
ntag424_calc_mac(session_keys, apdu_in[1], apdu_in[5], &apdu_out[6], padded_data_size, &apdu_out[APDU_HEADER_SIZE + padded_data_size + 1]);
|
||||||
|
|
||||||
|
apdu_out[4] = (uint8_t)(padded_data_size+8+1); // Set size to CmdHdr + padded data + MAC
|
||||||
|
apdu_out[APDU_HEADER_SIZE + padded_data_size + 8 + 1] = 0; // Le
|
||||||
|
|
||||||
|
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static int ntag424_write_file_settings(uint8_t fileno, ntag424_file_settings_t *settings, ntag424_session_keys_t *session_keys) {
|
static int ntag424_write_file_settings(uint8_t fileno, ntag424_file_settings_t *settings, ntag424_session_keys_t *session_keys) {
|
||||||
|
|
||||||
// ------- Convert file settings to the format for writing
|
// ------- Convert file settings to the format for writing
|
||||||
|
@ -292,51 +341,29 @@ static int ntag424_write_file_settings(uint8_t fileno, ntag424_file_settings_t *
|
||||||
.optional_sdm_settings = settings->optional_sdm_settings,
|
.optional_sdm_settings = settings->optional_sdm_settings,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// ------- Calculate IV
|
|
||||||
uint8_t ivc[16];
|
|
||||||
ntag424_calc_iv(session_keys, ivc);
|
|
||||||
|
|
||||||
// ------- Encrypt file settings
|
|
||||||
uint8_t padded_cmddata_buffer[256] = {0};
|
|
||||||
uint8_t encrypted_cmddata[256] = {0};
|
|
||||||
size_t settings_size = ntag424_calc_file_settings_size(settings) - 4; // This is weird, but since the write settings are the same as
|
|
||||||
// the settings read out, but minus file type and file size, we subtract 4 here.
|
|
||||||
|
|
||||||
size_t total_size = settings_size + 16 - (settings_size % 16); // pad up to 16 byte blocks
|
|
||||||
memcpy(padded_cmddata_buffer, (void*)&write_settings, settings_size);
|
|
||||||
if(total_size > settings_size) {
|
|
||||||
padded_cmddata_buffer[settings_size] = 0x80;
|
|
||||||
}
|
|
||||||
aes_encode(ivc, session_keys->encryption, padded_cmddata_buffer, encrypted_cmddata, total_size);
|
|
||||||
|
|
||||||
// ------- Calculate MAC
|
|
||||||
uint8_t mact[8];
|
|
||||||
ntag424_calc_mac(session_keys, 0x5f, fileno, encrypted_cmddata, total_size, mact);
|
|
||||||
|
|
||||||
// ------- Assemble the actual command
|
// ------- Assemble the actual command
|
||||||
uint8_t lc = 1 + total_size + 8; // CmdHeader + size + mac*/
|
size_t settings_size = ntag424_calc_file_write_settings_size(settings);
|
||||||
|
uint8_t lc = 1 + settings_size; // CmdHeader + size */
|
||||||
|
|
||||||
uint8_t cmd_header[] = {
|
uint8_t cmd_header[] = {
|
||||||
0x90, 0x5f, 0x00, 0x00,
|
0x90, 0x5f, 0x00, 0x00,
|
||||||
lc,
|
lc,
|
||||||
fileno
|
fileno
|
||||||
};
|
};
|
||||||
|
|
||||||
uint8_t cmd[256] = {0};
|
uint8_t cmd[256] = {0};
|
||||||
|
|
||||||
memcpy(cmd, cmd_header, sizeof(cmd_header));
|
memcpy(cmd, cmd_header, sizeof(cmd_header));
|
||||||
memcpy(&cmd[sizeof(cmd_header)], encrypted_cmddata, total_size);
|
memcpy(&cmd[sizeof(cmd_header)], (void*)&write_settings, settings_size);
|
||||||
memcpy(&cmd[sizeof(cmd_header) + total_size], mact, sizeof(mact));
|
cmd[sizeof(cmd_header) + settings_size] = 0x00;
|
||||||
cmd[sizeof(cmd_header) + total_size + sizeof(mact)] = 0x00;
|
|
||||||
|
|
||||||
size_t apdu_size = sizeof(cmd_header) + total_size + sizeof(mact) + 1;
|
uint8_t apdu_out[256] = {0};
|
||||||
|
int apdu_out_size = 256;
|
||||||
|
ntag424_comm_full_encrypt_apdu(cmd, apdu_out, &apdu_out_size, session_keys);
|
||||||
|
|
||||||
// ------- Actually send the APDU
|
// ------- Actually send the APDU
|
||||||
const size_t RESPONSE_LENGTH = 8 + 2;
|
const size_t RESPONSE_LENGTH = 8 + 2;
|
||||||
int outlen;
|
int outlen;
|
||||||
uint8_t resp[RESPONSE_LENGTH];
|
uint8_t resp[RESPONSE_LENGTH];
|
||||||
int res = ExchangeAPDU14a(cmd, apdu_size, false, true, resp, RESPONSE_LENGTH, &outlen);
|
int res = ExchangeAPDU14a(apdu_out, apdu_out_size, false, true, resp, RESPONSE_LENGTH, &outlen);
|
||||||
if(res != PM3_SUCCESS)
|
if(res != PM3_SUCCESS)
|
||||||
{
|
{
|
||||||
PrintAndLogEx(ERR, "Failed to send apdu");
|
PrintAndLogEx(ERR, "Failed to send apdu");
|
||||||
|
@ -355,7 +382,6 @@ static int ntag424_write_file_settings(uint8_t fileno, ntag424_file_settings_t *
|
||||||
}
|
}
|
||||||
|
|
||||||
session_keys->command_counter++; // Should this be incremented only on success?
|
session_keys->command_counter++; // Should this be incremented only on success?
|
||||||
|
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -682,49 +708,42 @@ static int ntag424_change_key(uint8_t keyno, uint8_t *new_key, uint8_t *old_key,
|
||||||
memcpy(key, new_key, 16);
|
memcpy(key, new_key, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------- Calculate IV
|
|
||||||
uint8_t ive[16];
|
|
||||||
ntag424_calc_iv(session_keys, ive);
|
|
||||||
|
|
||||||
// ------- Calculate KeyData
|
// ------- Calculate KeyData
|
||||||
uint8_t keydata[32] = {0};
|
uint8_t keydata[32] = {0};
|
||||||
memcpy(keydata, key, 16);
|
memcpy(keydata, key, 16);
|
||||||
keydata[16] = version;
|
keydata[16] = version;
|
||||||
|
int key_data_len;
|
||||||
if(keyno != 0)
|
if(keyno != 0)
|
||||||
{
|
{
|
||||||
memcpy(&keydata[17], crc, 4);
|
memcpy(&keydata[17], crc, 4);
|
||||||
keydata[21] = 0x80;
|
keydata[21] = 0x80;
|
||||||
|
key_data_len = 16 + 4 + 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
keydata[17] = 0x80;
|
keydata[17] = 0x80;
|
||||||
|
key_data_len = 16 + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t enc_keydata[32] = {0};
|
|
||||||
aes_encode(ive, session_keys->encryption, keydata, enc_keydata, 32);
|
|
||||||
|
|
||||||
// -------- Calculate MAC
|
|
||||||
uint8_t mact[8];
|
|
||||||
ntag424_calc_mac(session_keys, 0xC4, keyno, enc_keydata, 32, mact);
|
|
||||||
|
|
||||||
// ------- Assemble APDU
|
// ------- Assemble APDU
|
||||||
uint8_t cmd_header[] = {
|
uint8_t cmd_header[] = {
|
||||||
0x90, 0xC4, 0x00, 0x00, 0x29, keyno
|
0x90, 0xC4, 0x00, 0x00, key_data_len+1, keyno
|
||||||
};
|
};
|
||||||
|
|
||||||
uint8_t cmd[512] = {0};
|
uint8_t cmd[512] = {0};
|
||||||
memcpy(cmd, cmd_header, sizeof(cmd_header));
|
memcpy(cmd, cmd_header, sizeof(cmd_header));
|
||||||
memcpy(&cmd[sizeof(cmd_header)], enc_keydata, 32);
|
memcpy(&cmd[sizeof(cmd_header)], keydata, key_data_len);
|
||||||
memcpy(&cmd[sizeof(cmd_header) + 32], mact, 8);
|
|
||||||
int apdu_size = sizeof(cmd_header) + 32 + 8 + 1;
|
uint8_t apdu_out[256];
|
||||||
|
int apdu_out_size = 256;
|
||||||
|
ntag424_comm_full_encrypt_apdu(cmd, apdu_out, &apdu_out_size, session_keys);
|
||||||
|
|
||||||
|
|
||||||
// ------- Actually send the APDU
|
// ------- Actually send the APDU
|
||||||
const size_t RESPONSE_LENGTH = 8 + 2;
|
const size_t RESPONSE_LENGTH = 8 + 2;
|
||||||
int outlen;
|
int outlen;
|
||||||
uint8_t resp[RESPONSE_LENGTH];
|
uint8_t resp[RESPONSE_LENGTH];
|
||||||
int res = ExchangeAPDU14a(cmd, apdu_size, false, true, resp, RESPONSE_LENGTH, &outlen);
|
int res = ExchangeAPDU14a(apdu_out, apdu_out_size, false, true, resp, RESPONSE_LENGTH, &outlen);
|
||||||
if(res != PM3_SUCCESS)
|
if(res != PM3_SUCCESS)
|
||||||
{
|
{
|
||||||
PrintAndLogEx(ERR, "Failed to send apdu");
|
PrintAndLogEx(ERR, "Failed to send apdu");
|
||||||
|
@ -738,7 +757,7 @@ static int ntag424_change_key(uint8_t keyno, uint8_t *new_key, uint8_t *old_key,
|
||||||
|
|
||||||
if(resp[outlen-2] != 0x91 || resp[outlen-1] != 0x00)
|
if(resp[outlen-2] != 0x91 || resp[outlen-1] != 0x00)
|
||||||
{
|
{
|
||||||
PrintAndLogEx(ERR, "Failed to get file settings");
|
PrintAndLogEx(ERR, "Error when changing key. Wrong old key?");
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -761,7 +780,6 @@ static int CmdHF_ntag424_info(const char *Cmd) {
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "not implemented yet");
|
PrintAndLogEx(INFO, "not implemented yet");
|
||||||
PrintAndLogEx(INFO, "Feel free to contribute!");
|
PrintAndLogEx(INFO, "Feel free to contribute!");
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue