+bool hitag2_crypto(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) {
+ // Reset the transmission frame length
+ *txlen = 0;
+
+ if(bCrypto) {
+ hitag2_cipher_transcrypt(&cipher_state,rx,rxlen/8,rxlen%8);
+ }
+
+ // Try to find out which command was send by selecting on length (in bits)
+ switch (rxlen) {
+ // No answer, try to resurrect
+ case 0: {
+ // Stop if there is no answer while we are in crypto mode (after sending NrAr)
+ if (bCrypto) {
+ DbpString("Authentication failed!");
+ return false;
+ }
+ *txlen = 5;
+ memcpy(tx,"\xc0",nbytes(*txlen));
+ } break;
+
+ // Received UID, crypto tag answer
+ case 32: {
+ if (!bCrypto) {
+ uint64_t ui64key = key[0] | ((uint64_t)key[1]) << 8 | ((uint64_t)key[2]) << 16 | ((uint64_t)key[3]) << 24 | ((uint64_t)key[4]) << 32 | ((uint64_t)key[5]) << 40;
+ uint32_t ui32uid = rx[0] | ((uint32_t)rx[1]) << 8 | ((uint32_t)rx[2]) << 16 | ((uint32_t)rx[3]) << 24;
+ cipher_state = _hitag2_init(rev64(ui64key), rev32(ui32uid), 0);
+ memset(tx,0x00,4);
+ memset(tx+4,0xff,4);
+ hitag2_cipher_transcrypt(&cipher_state,tx+4,4,0);
+ *txlen = 64;
+ bCrypto = true;
+ bAuthenticating = true;
+ } else {
+ // Check if we received answer tag (at)
+ if (bAuthenticating) {
+ bAuthenticating = false;
+ } else {
+ // Store the received block
+ memcpy(tag.sectors[blocknr],rx,4);
+ blocknr++;
+ }
+ if (blocknr > 7) {
+ DbpString("Read succesful!");
+ // We are done... for now
+ return false;
+ }
+ *txlen = 10;
+ tx[0] = 0xc0 | (blocknr << 3) | ((blocknr^7) >> 2);
+ tx[1] = ((blocknr^7) << 6);
+ }
+ } break;
+
+ // Unexpected response
+ default: {
+ Dbprintf("Uknown frame length: %d",rxlen);
+ return false;
+ } break;
+ }
+
+
+ if(bCrypto) {
+ // We have to return now to avoid double encryption
+ if (!bAuthenticating) {
+ hitag2_cipher_transcrypt(&cipher_state,tx,*txlen/8,*txlen%8);
+ }
+ }
+
+ return true;
+}
+
+