Research, development and trades concerning the powerful Proxmark3 device.
Remember; sharing is caring. Bring something back to the community.
"Learn the tools of the trade the hard way." +Fravia
You are not logged in.
Time changes and with it the technology
Proxmark3 @ discord
Users of this forum, please be aware that information stored on this site is not private.
Pages: 1
Dear rfid enthusiasts,
I'm trying to implement full Mifare classic tag emulation inside the proxmark3 firmware.
The anticollision works perfectly, even the read requests without authentication neither encryption (mifare ultralight behavior)
I have ported the crypto1 implementation (based on Nohl paper) to the ARM code and tried to use it for authentication and ciphering.
This implementation works with the traces we can find on the forum
Initialization values
UID: c1 08 41 6a
KEY: 62 be a1 92 fa 37
Decrypted random nonces
Nt: ab cd 19 49
Nt': 6b 01 17 99
Nt'': b8 68 c4 dc
Nr: 16 05 49 0d
Mifare Classic trace, []=Encrypted
Auth(00): 60 00 f5 7b
Nt: ab cd 19 49
[Nr,Nt']: 59! d5 92 0f! 15 b9 d5! 53!
[Nt'']: a7! 9a 3f! ee!
However, with a real life reader, the authentication fails when I check the reader response (mutual 2). I suspect the parity bits to be the reason of my problem :
- In esorics 2008, the author explains that "Every 8 bits, the communication protocol sends a parity bit. It turns out that the parity is not computed over the ciphertext, at the lowest level of the protocol, but over the plaintext."
- I've added my code inside the SimulateIso14443aTag() function and at this level, I don't know the parity bit value. Hence, I'm sending the reader answer to the mutual 2 authentication function as a simple 4 bytes array, and thus the crypto1 register is not shifted with this parity bit value.
Do you think I'm on the right way ?
What do you suggest to fix the issue :
- get the parity bit from the reader answer (needs to change the GetIso14443aCommandFromReader function to send the parity bit to higher level functions)
- find a way to make crypto1 works without this parityBit (in the Krapto implementation, it is possible to recover the key from a trace without parity bits, so maybe I can do something similar)
Thank you in advance for your help
Offline
- you can't communicate with a reader without the parity bits (unless you hack on the reader)
- you can easily calculate the parity bit. you take the 8 bits you are going to send before they are encrypted, you add them all up if you get an even number your parity is 0 if you get an odd number you parity is 1 (or was it the other way round :]). after encrypting and sending the 8 bits, you send the parity bit xorred against the same keystream bit as the next bit (or was it the previous one :] ). A parity bit is a one bit checksum. which is supposed to protect against 1 bit failures. If you don't have the necessary information where you are hacking the code you can do two things. a) get the information you need there, b) hack somewhere else.
- crypto1 works regardless of the parity bits, crypto1 is just a streamcipher
- breaking the crypto is done in various situations. the situation where you emulate a tag and talk to a valid reader, gives you more than enough information that you don't need the parity bits to break it.
Offline
Hi Hat,
Thank you for your comments. As you suggest, I may have to hack the code somewhere else.
- of course, but since I'm using the code in iso14443a.c, the parity bits are calculated in the CodeIso14443aAsTag(). The answers from the reader are also of course with partiy bits but I don't see them because I use the output from GetIso14443aCommandFromReader()
- I think that I need to hack somewhere else to have crypto done on the parity bit
- In Nohl implementation, it seems that parity is used
static void crypto1_clean_mutual_2_reader(struct _crypto1_state *const state,
parity_data_t * const reader_response)
{
/* Unencrypted reader nonce */
const uint32_t reader_nonce = ARRAY_TO_UINT32(reader_response);
fprintf(stderr, "%s().%d key 0x%012llx prng 0x%08x n_R 0x%08lx\n", __func__, __LINE__, state->lfsr, state->prng, (long unsigned)reader_nonce);
/* Feed the reader nonce into the state and simultaneously encrypt it */
for(int i = 3; i >= 0; i--) { /* Same as in mifare_update_word, but with added parity */
reader_response[3 - i] = reader_response[3 - i] ^ mifare_update_byte(state, (reader_nonce >> (i * 8)) & 0xff, 0);
reader_response[3 - i] ^= mf20(state->lfsr) << 8;
}
fprintf(stderr, "%s().%d key 0x%012llx prng 0x%08x\n", __func__, __LINE__, state->lfsr, state->prng);
/* Unencrypted reader response */
const uint32_t RR = prng_next(state, 64);
UINT32_TO_ARRAY_WITH_PARITY(RR, reader_response + 4);
/* Encrypt the reader response */
crypto1_transcrypt(state, reader_response + 4, 4);
fprintf(stderr, "%s().%d key 0x%012llx prng 0x%08x a_R 0x%08lx\n", __func__, __LINE__, state->lfsr, state->prng, (long unsigned)RR);
}
Parity is not related with the streamcipher, but since parity bits are encrypted/decrypted, I think that if I don't have these parity bits, my LFSR will not be updated correctly.
- my goal is not to break the crypto but to act as a tag that can speak with a reader (with known key)
Offline
You may want to look into this example. It pretty much explains how the parity bits are generated using the crapto1 implementation.
Offline
proxhad: Why are you looking at crypto1_clean_mutual_2_reader? This function is the second step of mutual authentication when you are emulating a reader. If you want to emulate a card you need to look at crypto1_clean_mutual_2_card. Also: yes, of course, our implementation correctly transcrypts and generates all the parity bits (though I'm not sure, I think they are not checked). The data format we use is uint16_t for all the bytes where the lower 8 bits contain the actual payload byte and the 9th bit contains the parity bit (the remaining 7 bits in each 16-bit number are unused).
The macros ARRAY_TO_UINT32 and UINT32_TO_ARRAY_WITH_PARITY are used for this reason: the first converts a 4*16-bit array into a uint32_t (stripping the parity bits, since they are not used for the calculations) and the second one converts a uint32_t into an array of 4*16-bit, correctly generating the parity bits.
Offline
Pages: 1