Hi Roel.
I've hard coded data from your trace and I feed them into receive buffer (Rx).
Here you are the adopted Nethemba's code:
#define KEY_1 0xffffffffffffULL
#define ODD_PARITY(i) (( (i) ^ (i)>>1 ^ (i)>>2 ^ (i)>>3 ^ \
(i)>>4 ^ (i)>>5 ^ (i)>>6 ^ (i)>>7 ^ 1) & 0x01)
int mf_enhanced_auth(void) {
struct Crypto1State* pcs;
struct Crypto1State* revstate;
struct Crypto1State* revstate_start;
uint64_t lfsr;
uint8_t Nr[4] = { 0x00,0x00,0x00,0x00 }; // Reader nonce
uint8_t Auth[4] = { 0x00, 0x00, 0x00, 0x00 };
uint8_t AuthEnc[4] = { 0x00, 0x00, 0x00, 0x00 };
uint8_t AuthEncPar[8] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
uint8_t ArEnc[8] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
uint8_t ArEncPar[8] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
uint8_t Rx[25]; // Tag response
uint8_t RxPar[25]; // Tag response
uint32_t RxLen;
uint32_t Nt, NtLast, NtProbe, NtEnc, Ks1;
int i, m;
// values from Roel's trace
uint32_t uid = 0x9c599b32;
uint32_t card_challenge = 0x82a4166c;
uint32_t reader_challenge = 0xEFEA1CDA;
uint32_t card_response = 0x5cadf439;
// Prepare AUTH command
Auth[0] = 0x60;
ComputeCrc((char*)Auth, 2, &Auth[2], &Auth[3]);
// Request plain tag-nonce
num_to_bytes(card_challenge, 4, Rx);
// Save the tag nonce (Nt)
Nt = card_challenge;
// Init the cipher with key {0..47} bits
pcs = crypto1_create(KEY_1);
// Load (plain) uid^nt into the cipher {48..79} bits
crypto1_word(pcs, bytes_to_num(Rx, 4) ^ uid, 0);
num_to_bytes(reader_challenge, 4, Nr);
// Generate (encrypted) nr+parity by loading it into the cipher
for (i = 0; i < 4; i++) {
// Load in, and encrypt the reader nonce (Nr)
ArEnc[i] = crypto1_byte(pcs, Nr[i], 0) ^ Nr[i];
ArEncPar[i] = filter(pcs->odd) ^ ODD_PARITY(Nr[i]);
}
// Skip 32 bits in the pseudo random generator
Nt = prng_successor(Nt, 32);
// Generate reader-answer from tag-nonce
for (i = 4; i < 8; i++) {
// Get the next random byte
Nt = prng_successor(Nt, 8);
// Encrypt the reader-answer (Nt' = suc2(Nt))
ArEnc[i] = crypto1_byte(pcs, 0x00, 0) ^ (Nt&0xff);
ArEncPar[i] = filter(pcs->odd) ^ ODD_PARITY(Nt);
}
num_to_bytes(card_response, 4, Rx);
// Decrypt the tag answer and verify that suc3(Nt) is At
Nt = prng_successor(Nt, 32);
if (!((crypto1_word(pcs, 0x00, 0) ^ bytes_to_num(Rx, 4)) == (Nt&0xFFFFFFFF))) {
fprintf(stderr, "[At] is not Suc3(Nt), something is wrong, exiting..\n");
exit(1);
}
// If we are in "Get Distances" mode
{
{
// Encrypt Auth command with the current keystream
for (i = 0; i < 4; i++) {
AuthEnc[i] = crypto1_byte(pcs,0x00,0) ^ Auth[i];
// Encrypt the parity bits with the 4 plaintext bytes
AuthEncPar[i] = filter(pcs->odd) ^ ODD_PARITY(Auth[i]);
}
// Sending the encrypted Auth command
// Decrypt the encrypted auth
pcs = crypto1_create(KEY_1); //0xffffffffffff
num_to_bytes(0x5a920d85, 4, Rx); //encrypted Nt (from trace)
NtLast = bytes_to_num(Rx, 4) ^ crypto1_word(pcs, bytes_to_num(Rx, 4) ^ uid, 1);
num_to_bytes(0xEF60E26F, 4, Nr); //reader's Nr (from trace)
// Again, prepare and send {At}
for (i = 0; i < 4; i++) {
ArEnc[i] = crypto1_byte(pcs, Nr[i], 0) ^ Nr[i];
ArEncPar[i] = filter(pcs->odd) ^ ODD_PARITY(Nr[i]);
}
Nt = prng_successor(NtLast, 32);
for (i = 4; i < 8; i++) {
Nt = prng_successor(Nt, 8);
ArEnc[i] = crypto1_byte(pcs, 0x00, 0) ^ (Nt&0xFF);
ArEncPar[i] = filter(pcs->odd) ^ ODD_PARITY(Nt);
}
num_to_bytes(0xca7e0b63, 4, Rx); // Nt'' from trace
Nt = prng_successor(Nt, 32);
if (!((crypto1_word(pcs, 0x00, 0) ^ bytes_to_num(Rx, 4)) == (Nt&0xFFFFFFFF))) {
fprintf(stderr, "[At] is not Suc3(Nt), something is wrong, exiting..\n");
exit(1);
}
} // Next auth probe
} // The end of Get Distances mode
crypto1_destroy(pcs);
return 0;
}
void num_to_bytes(uint64_t n, uint32_t len, uint8_t* dest) {
while (len--) {
dest[len] = (uint8_t) n;
n >>= 8;
}
}
uint64_t bytes_to_num(uint8_t* src, uint32_t len) {
uint64_t num = 0;
while (len--)
{
num = (num << 8) | (*src);
src++;
}
return num;
}
unsigned short UpdateCrc(unsigned char ch, unsigned short *lpwCrc)
{
ch = (ch^(unsigned char)((*lpwCrc) & 0x00FF));
ch = (ch^(ch<<4));
*lpwCrc = (*lpwCrc >> 8)^((unsigned short)ch << 8)^((unsigned short)ch<<3)^((unsigned short)ch>>4);
return(*lpwCrc);
}
void ComputeCrc(char *Data, int Length, BYTE *TransmitFirst, BYTE *TransmitSecond)
{
unsigned char chBlock;
unsigned short wCrc;
wCrc = 0x6363; /* ITU-V.41 */
do {
chBlock = *Data++;
UpdateCrc(chBlock, &wCrc);
} while (--Length);
*TransmitFirst = (BYTE) (wCrc & 0xFF);
*TransmitSecond = (BYTE) ((wCrc >> 8) & 0xFF);
return;
}