diff --git a/client/src/mifare/desfire_crypto.h b/client/src/mifare/desfire_crypto.h
index 71f3acb23..346a7e50c 100644
--- a/client/src/mifare/desfire_crypto.h
+++ b/client/src/mifare/desfire_crypto.h
@@ -25,10 +25,9 @@
 #include "mifare.h" // structs
 #include "crc32.h"
 #include "crypto/libpcrypto.h"
+#include "mifare/desfirecrypto.h"
 
 
-#define MAX_CRYPTO_BLOCK_SIZE 16
-#define DESFIRE_MAX_KEY_SIZE 24
 /* Mifare DESFire EV1 Application crypto operations */
 #define APPLICATION_CRYPTO_DES    0x00
 #define APPLICATION_CRYPTO_3K3DES 0x40
@@ -75,13 +74,6 @@ typedef enum {
 /* Error code managed by the library */
 #define CRYPTO_ERROR            0x01
 
-enum DESFIRE_CRYPTOALGO {
-    T_DES = 0x00,
-    T_3DES = 0x01, //aka 2K3DES
-    T_3K3DES = 0x02,
-    T_AES = 0x03
-};
-
 int desfire_get_key_length(enum DESFIRE_CRYPTOALGO key_type);
 size_t desfire_get_key_block_length(enum DESFIRE_CRYPTOALGO key_type);
 
diff --git a/client/src/mifare/desfirecrypto.c b/client/src/mifare/desfirecrypto.c
index 55c957932..e0a886b62 100644
--- a/client/src/mifare/desfirecrypto.c
+++ b/client/src/mifare/desfirecrypto.c
@@ -24,6 +24,8 @@
 #include <string.h>
 #include <util.h>
 #include "ui.h"
+#include "aes.h"
+#include "des.h"
 #include "crc.h"
 #include "crc16.h"        // crc16 ccitt
 #include "crc32.h"
@@ -85,39 +87,152 @@ bool DesfireIsAuthenticated(DesfireContext *dctx) {
     return dctx->secureChannel != DACNone;
 }
 
-void DesfireCryptoEncDec(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool encode) {
-    uint8_t data[1024] = {0};
+static void DesfireCryptoEncDecSingleBlock(uint8_t *key, DesfireCryptoAlgorythm keyType, uint8_t *data, uint8_t *dstdata, uint8_t *ivect, bool dir_to_send, bool encode) {
+    size_t block_size = desfire_get_key_block_length(keyType);
+    uint8_t sdata[MAX_CRYPTO_BLOCK_SIZE] = {0};
+    memcpy(sdata, data, block_size);
+    if (dir_to_send) {
+        bin_xor(sdata, ivect, block_size);
+    }
 
-    switch (ctx->keyType) {
+    uint8_t edata[MAX_CRYPTO_BLOCK_SIZE] = {0};
+
+    switch (keyType) {
         case T_DES:
-            if (ctx->secureChannel == DACd40) {
-                if (encode)
-                    des_encrypt_ecb(data, srcdata, srcdatalen, ctx->key);
-                else
-                    des_decrypt_ecb(data, srcdata, srcdatalen, ctx->key);
-            }
-            if (ctx->secureChannel == DACEV1) {
-                if (encode)
-                    des_encrypt_cbc(data, srcdata, srcdatalen, ctx->key, ctx->IV);
-                else
-                    des_decrypt_cbc(data, srcdata, srcdatalen, ctx->key, ctx->IV);
-            }
-
-            if (dstdata)
-                memcpy(dstdata, data, srcdatalen);
+            if (encode)
+                des_encrypt(edata, sdata, key);
+            else
+                des_decrypt(edata, sdata, key);
             break;
         case T_3DES:
+            if (encode) {
+                mbedtls_des3_context ctx3;
+                mbedtls_des3_set2key_enc(&ctx3, key);
+                mbedtls_des3_crypt_ecb(&ctx3, sdata, edata);
+            } else {
+                mbedtls_des3_context ctx3;
+                mbedtls_des3_set2key_dec(&ctx3, key);
+                mbedtls_des3_crypt_ecb(&ctx3, sdata, edata);
+            }
             break;
         case T_3K3DES:
+            if (encode) {
+                mbedtls_des3_context ctx3;
+                mbedtls_des3_set3key_enc(&ctx3, key);
+                mbedtls_des3_crypt_ecb(&ctx3, sdata, edata);
+            } else {
+                mbedtls_des3_context ctx3;
+                mbedtls_des3_set3key_dec(&ctx3, key);
+                mbedtls_des3_crypt_ecb(&ctx3, sdata, edata);
+            }
             break;
         case T_AES:
-            if (encode)
-                aes_encode(ctx->IV, ctx->key, srcdata, data, srcdatalen);
-            else
-                aes_decode(ctx->IV, ctx->key, srcdata, data, srcdatalen);
-            if (dstdata)
-                memcpy(dstdata, data, srcdatalen);
+            if (encode) {
+                mbedtls_aes_context actx;
+                mbedtls_aes_init(&actx);
+                mbedtls_aes_setkey_enc(&actx, key, 128);
+                mbedtls_aes_crypt_ecb(&actx, MBEDTLS_AES_ENCRYPT, sdata, edata);
+                mbedtls_aes_free(&actx);
+            } else {
+                mbedtls_aes_context actx;
+                mbedtls_aes_init(&actx);
+                mbedtls_aes_setkey_dec(&actx, key, 128);
+                mbedtls_aes_crypt_ecb(&actx, MBEDTLS_AES_DECRYPT, sdata, edata);
+                mbedtls_aes_free(&actx);
+            }
             break;
     }
+
+    memcpy(dstdata, edata, block_size);
+
+    if (dir_to_send) {
+        memcpy(ivect, sdata, block_size);
+    } else {
+        memcpy(ivect, data, block_size);
+    }
+}
+
+void DesfireCryptoEncDec(DesfireContext *ctx, bool use_session_key, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool encode) {
+    uint8_t data[1024] = {0};
+    
+    if (ctx->secureChannel == DACd40)
+        memset(ctx->IV, 0, DESFIRE_MAX_CRYPTO_BLOCK_SIZE);
+        
+    size_t block_size = desfire_get_key_block_length(ctx->keyType);
+    size_t offset = 0;
+    while (offset < srcdatalen) {
+        //mifare_cypher_single_block(key, data + offset, ivect, direction, operation, block_size);
+        if (use_session_key)
+            DesfireCryptoEncDecSingleBlock(ctx->sessionKeyMAC, ctx->keyType, srcdata + offset, data, ctx->IV, encode, encode);
+        else
+            DesfireCryptoEncDecSingleBlock(ctx->key, ctx->keyType, srcdata + offset, data, ctx->IV, encode, encode);
+        offset += block_size;
+    }
+
+    if (dstdata)
+        memcpy(dstdata, data, srcdatalen);
+}
+
+static void DesfireCMACGenerateSubkeys(DesfireContext *ctx, uint8_t *sk1, uint8_t *sk2) {
+    int kbs = desfire_get_key_block_length(ctx->keyType);
+    const uint8_t R = (kbs == 8) ? 0x1B : 0x87;
+
+    uint8_t l[kbs];
+    memset(l, 0, kbs);
+
+    uint8_t ivect[kbs];
+    memset(ivect, 0, kbs);
+
+    //mifare_cypher_blocks_chained(NULL, key, ivect, l, kbs, MCD_SEND, MCO_ENCYPHER);
+    DesfireCryptoEncDec(ctx, true, l, kbs, NULL, true);
+
+    bool txor = false;
+
+    // Used to compute CMAC on complete blocks
+    memcpy(sk1, l, kbs);
+    txor = l[0] & 0x80;
+    lsl(sk1, kbs);
+    if (txor) {
+        sk1[kbs - 1] ^= R;
+    }
+
+    // Used to compute CMAC on the last block if non-complete
+    memcpy(sk2, sk1, kbs);
+    txor = sk1[0] & 0x80;
+    lsl(sk2, kbs);
+    if (txor) {
+        sk2[kbs - 1] ^= R;
+    }
+}
+
+void DesfireCryptoCMAC(DesfireContext *ctx, uint8_t *data, size_t len, uint8_t *cmac) {
+    int kbs = desfire_get_key_block_length(ctx->keyType);
+    if (kbs == 0)
+        return;
+    
+    uint8_t buffer[kbs];
+    memset(buffer, 0, kbs);
+    
+    uint8_t sk1[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0};
+    uint8_t sk2[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0};
+    DesfireCMACGenerateSubkeys(ctx, sk1, sk2);
+    
+    memcpy(buffer, data, len);
+
+    if ((!len) || (len % kbs)) {
+        buffer[len++] = 0x80;
+        while (len % kbs) {
+            buffer[len++] = 0x00;
+        }
+        bin_xor(buffer + len - kbs, sk2, kbs);
+    } else {
+        bin_xor(buffer + len - kbs, sk1, kbs);
+    }
+
+    //mifare_cypher_blocks_chained(NULL, key, ivect, buffer, len, MCD_SEND, MCO_ENCYPHER);
+    DesfireCryptoEncDec(ctx, true, buffer, len, NULL, true);
+
+    memcpy(cmac, ctx->IV, kbs);
+    
 }
 
diff --git a/client/src/mifare/desfirecrypto.h b/client/src/mifare/desfirecrypto.h
index 9fc3d61e0..236601406 100644
--- a/client/src/mifare/desfirecrypto.h
+++ b/client/src/mifare/desfirecrypto.h
@@ -22,13 +22,21 @@
 #define __DESFIRECRYPTO_H
 
 #include "common.h"
-#include "mifare/desfire_crypto.h"
 #include "mifare/mifare4.h"
 
-#define DESF_MAX_KEY_LEN        24
+#define MAX_CRYPTO_BLOCK_SIZE 16
+#define DESFIRE_MAX_CRYPTO_BLOCK_SIZE 16
+#define DESFIRE_MAX_KEY_SIZE  24
 
 #define DESFIRE_GET_ISO_STATUS(x) ( ((uint16_t)(0x91<<8)) + (uint16_t)x )
 
+enum DESFIRE_CRYPTOALGO {
+    T_DES = 0x00,
+    T_3DES = 0x01, //aka 2K3DES
+    T_3K3DES = 0x02,
+    T_AES = 0x03
+};
+
 typedef enum DESFIRE_CRYPTOALGO DesfireCryptoAlgorythm;
 
 typedef enum {
@@ -54,8 +62,8 @@ typedef enum {
 
 typedef struct DesfireContextS {
     uint8_t keyNum;
-    enum DESFIRE_CRYPTOALGO keyType;   // des/2tdea/3tdea/aes
-    uint8_t key[DESF_MAX_KEY_LEN];
+    DesfireCryptoAlgorythm keyType;   // des/2tdea/3tdea/aes
+    uint8_t key[DESFIRE_MAX_KEY_SIZE];
 
     // KDF finction
     uint8_t kdfAlgo;
@@ -66,10 +74,10 @@ typedef struct DesfireContextS {
     DesfireCommandSet cmdSet;           // native/nativeiso/iso
     DesfireCommunicationMode commMode;  // plain/mac/enc
 
-    uint8_t IV[DESF_MAX_KEY_LEN];
-    uint8_t sessionKeyMAC[DESF_MAX_KEY_LEN];
-    uint8_t sessionKeyEnc[DESF_MAX_KEY_LEN];  // look at mifare4.h - mf4Session_t
-    uint8_t lastIV[DESF_MAX_KEY_LEN];
+    uint8_t IV[DESFIRE_MAX_KEY_SIZE];
+    uint8_t sessionKeyMAC[DESFIRE_MAX_KEY_SIZE];
+    uint8_t sessionKeyEnc[DESFIRE_MAX_KEY_SIZE];  // look at mifare4.h - mf4Session_t
+    uint8_t lastIV[DESFIRE_MAX_KEY_SIZE];
     //mf4Session_t AESSession;
     uint16_t cntrTx;    // for AES
     uint16_t cntrRx;    // for AES
@@ -85,7 +93,8 @@ void DesfireSetKdf(DesfireContext *ctx, uint8_t kdfAlgo, uint8_t *kdfInput, uint
 bool DesfireIsAuthenticated(DesfireContext *dctx);
 
 
-void DesfireCryptoEncDec(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool encode);
+void DesfireCryptoEncDec(DesfireContext *ctx, bool use_session_key, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool encode);
+void DesfireCryptoCMAC(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t *cmac);
 
 
 #endif // __DESFIRECRYPTO_H
diff --git a/client/src/mifare/desfiresecurechan.c b/client/src/mifare/desfiresecurechan.c
index f7e7d22ea..51f2af365 100644
--- a/client/src/mifare/desfiresecurechan.c
+++ b/client/src/mifare/desfiresecurechan.c
@@ -40,7 +40,7 @@ static void DesfireSecureChannelEncodeD40(DesfireContext *ctx, uint8_t cmd, uint
 
             rlen = padded_data_length(srcdatalen, desfire_get_key_block_length(ctx->keyType));
             memcpy(data, srcdata, srcdatalen);
-            DesfireCryptoEncDec(ctx, data, rlen, NULL, true);
+            DesfireCryptoEncDec(ctx, true, data, rlen, NULL, true);
             memcpy(dstdata, srcdata, srcdatalen);
             memcpy(&dstdata[srcdatalen], ctx->IV, 4);
             *dstdatalen = rlen;
@@ -49,7 +49,7 @@ static void DesfireSecureChannelEncodeD40(DesfireContext *ctx, uint8_t cmd, uint
             rlen = padded_data_length(srcdatalen + 2, desfire_get_key_block_length(ctx->keyType)); // 2 - crc16
             memcpy(data, srcdata, srcdatalen);
             compute_crc(CRC_14443_A, data, srcdatalen, &data[srcdatalen], &data[srcdatalen + 1]);
-            DesfireCryptoEncDec(ctx, data, rlen, dstdata, true);
+            DesfireCryptoEncDec(ctx, true, data, rlen, dstdata, true);
             *dstdatalen = rlen;
             break;
         case DCMNone:
@@ -70,7 +70,7 @@ static void DesfireSecureChannelEncodeEV1(DesfireContext *ctx, uint8_t cmd, uint
             data[0] = cmd;
             rlen = padded_data_length(srcdatalen + 1, desfire_get_key_block_length(ctx->keyType));
             memcpy(&data[1], srcdata, srcdatalen);
-            DesfireCryptoEncDec(ctx, data, rlen, NULL, true);
+            DesfireCryptoEncDec(ctx, true, data, rlen, NULL, true);
 
             memcpy(dstdata, srcdata, srcdatalen);
             if (srcdatalen != 0 && ctx->commMode == DCMMACed) {