mirror of
https://github.com/Proxmark/proxmark3.git
synced 2025-07-06 13:11:18 -07:00
The new handler accepts multiple formats of the same length. Because of this, the existing pack/unpack commands are unsupported and have been removed and replaced with 'lf hid encode' and 'lf hid decode'. The decode command will test a packed Prox ID against all programmed formats and return results for all matching formats. The encode command takes the parameter of format name instead of bit length (as per the old pack command). Additionally, an 'lf hid write' command has been added as a single-command combination of encode and clone. To support easier addition of new formats, a library for handling card fields has been added. This will allow direct access to the card bits, to linear fields, and to non-linear (jumping) fields in a single line of code without having to resort to managing bit positions or masks on the underlying data. A number of new formats have been added as working examples of the new support functions.
172 lines
No EOL
5.6 KiB
C
172 lines
No EOL
5.6 KiB
C
//-----------------------------------------------------------------------------
|
|
// Copyright (C) 2018 grauerfuchs
|
|
//
|
|
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
|
// at your option, any later version. See the LICENSE.txt file for the text of
|
|
// the license.
|
|
//-----------------------------------------------------------------------------
|
|
// HID card format packing/unpacking support functions
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include "hidcardformatutils.h"
|
|
#include "ui.h"
|
|
|
|
bool get_bit_by_position(/* in */hidproxmessage_t* data, /* in */uint8_t pos){
|
|
if (pos >= data->Length) return false;
|
|
pos = (data->Length - pos) - 1; // invert ordering; Indexing goes from 0 to 1. Subtract 1 for weight of bit.
|
|
bool result = false;
|
|
if (pos > 95)
|
|
result = false;
|
|
else if (pos > 63)
|
|
result = (data->top >> (pos - 64)) & 1;
|
|
else if (pos > 31)
|
|
result = (data->mid >> (pos - 32)) & 1;
|
|
else
|
|
result = (data->bot >> pos) & 1;
|
|
return result;
|
|
}
|
|
bool set_bit_by_position(/* inout */hidproxmessage_t* data, /* in */bool value, /* in */uint8_t pos){
|
|
if (pos >= data->Length) return false;
|
|
pos = (data->Length - pos) - 1; // invert ordering; Indexing goes from 0 to 1. Subtract 1 for weight of bit.
|
|
if (pos > 95) {
|
|
return false;
|
|
} else if (pos > 63) {
|
|
if (value)
|
|
data->top |= (1 << (pos - 64));
|
|
else
|
|
data->top &= ~(1 << (pos - 64));
|
|
return true;
|
|
} else if (pos > 31) {
|
|
if (value)
|
|
data->mid |= (1 << (pos - 32));
|
|
else
|
|
data->mid &= ~(1 << (pos - 32));
|
|
return true;
|
|
} else {
|
|
if (value)
|
|
data->bot |= (1 << pos);
|
|
else
|
|
data->bot &= ~(1 << pos);
|
|
return true;
|
|
}
|
|
}
|
|
/**
|
|
* Safeguard the data by doing a manual deep copy
|
|
*
|
|
* At the time of the initial writing, the struct does not contain pointers. That doesn't
|
|
* mean it won't eventually contain one, however. To prevent memory leaks and erroneous
|
|
* aliasing, perform the copy function manually instead. Hence, this function.
|
|
*
|
|
* If the definition of the hid_proxmessage struct changes, this function must also
|
|
* be updated to match.
|
|
*/
|
|
void proxmessage_datacopy(/*in*/hidproxmessage_t* src, /*out*/hidproxmessage_t* dest){
|
|
dest->bot = src->bot;
|
|
dest->mid = src->mid;
|
|
dest->top = src->top;
|
|
dest->Length = src->Length;
|
|
}
|
|
/**
|
|
*
|
|
* Yes, this is horribly inefficient for linear data.
|
|
* The current code is a temporary measure to have a working function in place
|
|
* until all the bugs shaken from the block/chunk version of the code.
|
|
*
|
|
*/
|
|
uint64_t get_linear_field(/* in */hidproxmessage_t* data, uint8_t firstBit, uint8_t length){
|
|
uint64_t result = 0;
|
|
for (uint8_t i = 0; i < length; i++ ) {
|
|
result = (result << 1) | get_bit_by_position(data, firstBit + i);
|
|
}
|
|
return result;
|
|
}
|
|
bool set_linear_field(/* inout */hidproxmessage_t* data, uint64_t value, uint8_t firstBit, uint8_t length){
|
|
hidproxmessage_t tmpdata;
|
|
proxmessage_datacopy(data, &tmpdata);
|
|
bool result = true;
|
|
for (int i = 0; i < length; i++){
|
|
result &= set_bit_by_position(&tmpdata, (value >> ((length - i) - 1)) & 1, firstBit + i);
|
|
}
|
|
if (result) proxmessage_datacopy(&tmpdata, data);
|
|
return result;
|
|
}
|
|
|
|
uint64_t get_nonlinear_field(/* in */hidproxmessage_t* data, uint8_t numBits, uint8_t* bits){
|
|
uint64_t result = 0;
|
|
for (int i = 0; i < numBits; i++){
|
|
result = (result << 1) | (get_bit_by_position(data, *(bits+i)) & 1);
|
|
}
|
|
return result;
|
|
}
|
|
bool set_nonlinear_field(/* inout */hidproxmessage_t* data, uint64_t value, uint8_t numBits, uint8_t* bits){
|
|
hidproxmessage_t tmpdata;
|
|
proxmessage_datacopy(data, &tmpdata);
|
|
bool result = true;
|
|
for (int i = 0; i < numBits; i++){
|
|
result &= set_bit_by_position(&tmpdata, (value >> ((numBits - i) - 1)) & 1, *(bits + i));
|
|
}
|
|
if (result) proxmessage_datacopy(&tmpdata, data);
|
|
return result;
|
|
}
|
|
|
|
uint8_t get_length_from_header(/* inout */hidproxmessage_t* data) {
|
|
uint8_t len = 0;
|
|
|
|
uint32_t hFmt; // for calculating card length
|
|
if ((data->top & 0x000FFFFF) > 0) { // > 64 bits
|
|
hFmt = data->top & 0x000FFFFF;
|
|
len = 64;
|
|
} else if ((data->mid & 0xFFFFFFC0) > 0) { // < 63-38 bits
|
|
hFmt = data->mid & 0xFFFFFFC0;
|
|
len = 32;
|
|
} else if ((data->mid & 0x00000020) == 0) { // 37 bits
|
|
hFmt = 0;
|
|
len = 37;
|
|
} else if ((data->mid & 0x0000001F) > 0){ // 36-32 bits
|
|
hFmt = data->mid & 0x0000001F;
|
|
len = 32;
|
|
} else { // <32 bits
|
|
hFmt = data->bot;
|
|
len = 0;
|
|
}
|
|
|
|
while (hFmt > 1) {
|
|
hFmt >>= 1;
|
|
len++;
|
|
}
|
|
return len;
|
|
}
|
|
|
|
hidproxmessage_t initialize_proxmessage_object(uint32_t top, uint32_t mid, uint32_t bot){
|
|
struct hidproxmessage_s result;
|
|
memset(&result, 0, sizeof(hidproxmessage_t));
|
|
result.top = top;
|
|
result.mid = mid;
|
|
result.bot = bot;
|
|
result.Length = get_length_from_header(&result);
|
|
return result;
|
|
}
|
|
bool add_HID_header(/* inout */hidproxmessage_t* data){
|
|
if (data->Length > 84 || data->Length == 0) return false; // Invalid value
|
|
|
|
if (data->Length >= 64){
|
|
data->top |= 1 << (data->Length - 64); // leading 1: start bit
|
|
data->top |= 0x09e00000; // Extended-length header
|
|
} else if (data->Length > 37){
|
|
data->mid |= 1 << (data->Length - 32); // leading 1: start bit
|
|
data->top |= 0x09e00000; // Extended-length header
|
|
} else if (data->Length == 37){
|
|
// No header bits added to 37-bit cards
|
|
} else if (data->Length >= 32){
|
|
data->mid |= 0x20; // Bit 37; standard header
|
|
data->mid |= 1 << (data->Length - 32); // leading 1: start bit
|
|
} else {
|
|
data->mid |= 0x20; // Bit 37; standard header
|
|
data->bot |= 1 << data->Length; // leading 1: start bit
|
|
}
|
|
return true;
|
|
} |