Skip to content

Commit 4050b6b

Browse files
committed
V 1.1
1 parent af04a46 commit 4050b6b

File tree

6 files changed

+174
-32
lines changed

6 files changed

+174
-32
lines changed

.idea/.name

Lines changed: 0 additions & 1 deletion
This file was deleted.

CMakeLists.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
cmake_minimum_required(VERSION 3.25)
2-
project(DesfireCMAC)
2+
project(DesfireCrypto)
33

44
set(CMAKE_CXX_STANDARD 17)
55

6-
add_executable(DesfireCMAC
6+
add_executable(DesfireCrypto
77

88
# INCLUDE
99
include/aes/AES.cpp
1010
include/aes/AES.h
11-
include/cmac/CMAC.cpp
12-
include/cmac/CMAC.h
11+
include/desfire_crypto/DesfireCrypto.cpp
12+
include/desfire_crypto/DesfireCrypto.h
1313

1414
# MAIN
1515
src/main.cpp

README.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# DesfireCrypto
2+
3+
DesfireCrypto is a C++ class that provides cryptographic functionalities for DESFire cards. It includes encryption, decryption, initialization of the Cipher-based Message Authentication Code (CMAC), and other utility functions.
4+
5+
## Functions
6+
7+
### generateSubkeys
8+
```cpp
9+
void generateSubkeys();
10+
```
11+
This function generates key0, key1, and key2 for DESFire. It performs the following steps:
12+
1. Generate key0, key1, and key2.
13+
2. Encrypt 16 bytes of 0x00 with the key.
14+
3. Left shift key0 by 1 bit and store it in key1.
15+
4. If the Most Significant Bit (MSB) of key0 is 0x80, then key1 = (key0 << 1) ^ 0x87.
16+
5. Left shift key1 by 1 bit and store it in key2.
17+
6. If the MSB of key1 is 0x80, then key2 = (key1 << 1) ^ 0x87.
18+
19+
### setIv
20+
```cpp
21+
void setIv(const vector<uint8_t> &_iv);
22+
```
23+
This function sets the Initialization Vector (IV) for encryption and decryption. The IV is obtained during authentication.
24+
25+
### encryptAes
26+
```cpp
27+
vector<uint8_t> encryptAes(vector<uint8_t> &data, const vector<uint8_t> &key, const vector<uint8_t> &iv);
28+
```
29+
This function encrypts the provided data using AES-128 algorithm. It takes the data, encryption key, and IV as inputs and returns the encrypted data as a vector of bytes.
30+
31+
### decryptAes
32+
```cpp
33+
vector<uint8_t> decryptAes(vector<uint8_t> &data, const vector<uint8_t> &key, const vector<uint8_t> &iv);
34+
```
35+
This function decrypts the provided data using AES-128 algorithm. It takes the data, decryption key, and IV as inputs and returns the decrypted data as a vector of bytes.
36+
37+
### initCMAC
38+
```cpp
39+
void initCMAC(const vector<uint8_t> &_key, const vector<uint8_t> &_iv);
40+
```
41+
This function initializes the Cipher-based Message Authentication Code (CMAC) with the provided key and IV. It is called during the authentication process.
42+
43+
### getCMAC
44+
```cpp
45+
vector<uint8_t> getCMAC(const vector<uint8_t> &_data);
46+
```
47+
This function calculates the CMAC for the provided data. It performs the following steps:
48+
1. Checks if padding is required (`isPaddingRequired = dataLen % AES_BLOCK_SIZE != 0`).
49+
2. Calculates the number of blocks (`numberOfBlocks = isPaddingRequired ? dataLen / AES_BLOCK_SIZE + 1 : dataLen / AES_BLOCK_SIZE`).
50+
3. Splits the data into blocks, each of size 16 bytes (for AES).
51+
4. If padding is required, adds padding to the last block (`lastBlock.push_back(0x80); lastBlock.resize(AES_BLOCK_SIZE, 0x00);`).
52+
5. If `isPaddingRequired` is true, XORs the last block with key2; otherwise, XORs it with key1.
53+
6. For each block, XORs it with the previous IV obtained in the last process (`xorVec(blocks[i], iv, blocks[i]);`).
54+
7. Encrypts the XORed block with AES-128 using the key and IV (`aes.EncryptCBC(blocks[i], key, iv);`). The IV used for encryption should be all zeros.
55+
8. Updates the IV with the encrypted block.
56+
9. Returns the last block of the IV as DesfireCrypto, as only the first 8

include/cmac/CMAC.cpp renamed to include/desfire_crypto/DesfireCrypto.cpp

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,30 @@
1-
#include "CMAC.h"
1+
#include "DesfireCrypto.h"
22

3-
void CMAC::initCMAC(const vector<uint8_t>& _key, const vector<uint8_t>& _iv) {
3+
void DesfireCrypto::initCMAC(const vector<uint8_t>& _key, const vector<uint8_t>& _iv) {
44
aes = AES(AESKeyLength::AES_128);
55
key = _key;
66
iv = _iv;
7-
generateSubkeys();
87
}
98

10-
void CMAC::generateSubkeys() {
9+
void DesfireCrypto::generateSubkeys() {
1110

1211
vector<uint8_t> zero(16, 0x00);
13-
vector<unsigned char> key0 = aes.EncryptCBC(zero, key, zero);
12+
vector<unsigned char> key0 = encryptAes(zero, key, zero);
1413

1514
leftShift(key0, key1);
1615
if (key0[0] & 0x80) key1[key1.size() - 1] ^= 0x87U;
1716

1817
leftShift(key1, key2);
1918
if (key1[0] & 0x80) key2[key2.size() - 1] ^= 0x87U;
2019

20+
vecPrint("key0", key0);
21+
vecPrint("key1", key1);
22+
vecPrint("key2", key2);
23+
2124
}
2225

23-
vector<uint8_t> CMAC::getCMAC(const vector<uint8_t>& data) {
26+
vector<uint8_t> DesfireCrypto::getCMAC(const vector<uint8_t>& data) {
27+
2428
const int AES_BLOCK_SIZE = 16;
2529
bool isPaddingRequired = (data.size() % AES_BLOCK_SIZE != 0);
2630
int numberOfBlocks = isPaddingRequired ? data.size() / AES_BLOCK_SIZE + 1 : data.size() / AES_BLOCK_SIZE;
@@ -52,12 +56,24 @@ vector<uint8_t> CMAC::getCMAC(const vector<uint8_t>& data) {
5256
vector<unsigned char> temp = blocks[offset];
5357
vector<unsigned char> xorTemp(AES_BLOCK_SIZE, 0x00);
5458
xorVec(iv, temp, xorTemp);
55-
temp = aes.EncryptCBC(xorTemp, key, tempIv);
59+
temp = encryptAes(xorTemp, key, tempIv);
5660
iv = temp;
5761
offset += AES_BLOCK_SIZE;
5862
}
5963

6064
cmac = {iv.begin(), iv.begin() + AES_BLOCK_SIZE / 2};
6165

6266
return cmac;
63-
}
67+
}
68+
69+
void DesfireCrypto::setIv(const vector<uint8_t> &_iv) {
70+
iv = _iv;
71+
}
72+
73+
vector<uint8_t> DesfireCrypto::encryptAes(vector<uint8_t> &data, const vector<uint8_t> &_key, const vector<uint8_t> &_iv) {
74+
return aes.EncryptCBC(data, _key, _iv);
75+
}
76+
77+
vector<uint8_t> DesfireCrypto::decryptAes(vector<uint8_t> &data, const vector<uint8_t> &_key, const vector<uint8_t> &_iv) {
78+
return aes.DecryptCBC(data, _key, _iv);
79+
}

include/cmac/CMAC.h renamed to include/desfire_crypto/DesfireCrypto.h

Lines changed: 81 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,12 @@
44

55
using namespace std;
66

7-
class CMAC {
7+
#define CRC32_POLY 0x04C11DB7
8+
#define CRC32_POLY_REV 0xEDB88320
9+
#define CRC32_NUMBYTES 4
10+
#define CRC32_NUMBITS (8 * CRC32_NUMBYTES)
11+
12+
class DesfireCrypto {
813

914
private:
1015
AES aes;
@@ -13,6 +18,8 @@ class CMAC {
1318
vector<uint8_t> key2;
1419
vector<uint8_t> iv;
1520

21+
public:
22+
1623
/**
1724
* @name generateSubkeys
1825
* @details 1. Generate key0, key1, key2
@@ -25,7 +32,29 @@ class CMAC {
2532
*/
2633
void generateSubkeys();
2734

28-
public:
35+
/**
36+
* @name setKey
37+
* @details Set IV
38+
* @param _iv = Session obtained during authentication
39+
* @return void
40+
*/
41+
void setIv(const vector<uint8_t> &_iv);
42+
43+
/**
44+
* @name encryptAes
45+
* @details Encrypt data using AES-128
46+
* @param data = Data to be encrypted
47+
* @return Encrypted data
48+
*/
49+
vector<uint8_t> encryptAes(vector<uint8_t> &data, const vector<uint8_t> &key, const vector<uint8_t> &iv);
50+
51+
/**
52+
* @name decryptAes
53+
* @details Decrypt data using AES-128
54+
* @param data = Data to be decrypted
55+
* @return Decrypted data
56+
*/
57+
vector<uint8_t> decryptAes(vector<uint8_t> &data, const vector<uint8_t> &key, const vector<uint8_t> &iv);
2958

3059
/**
3160
* @name initCMAC
@@ -35,7 +64,7 @@ class CMAC {
3564
* @param _iv = IV obtained during authentication
3665
* @return void
3766
*/
38-
void initCMAC(const vector<uint8_t>& _key, const vector<uint8_t>& _iv);
67+
void initCMAC(const vector<uint8_t> &_key, const vector<uint8_t> &_iv);
3968

4069
/**
4170
* @name getCMAC
@@ -47,11 +76,11 @@ class CMAC {
4776
* @details 6. For each block, xor with previous IV obtain in last process. [ xorVec(blocks[i], iv, blocks[i]); ]
4877
* @details 7. Encrypt xor'ed block with AES-128 [ aes.EncryptCBC(blocks[i], key, iv); ] iv used for encryption should be all zero's
4978
* @details 8. Update iv with encrypted block
50-
* @details 9. Return last block of iv as CMAC only first 8 bytes are required
79+
* @details 9. Return last block of iv as DesfireCrypto only first 8 bytes are required
5180
* @param _data
52-
* @return cmac.
81+
* @return desfire_crypto.
5382
*/
54-
vector<uint8_t> getCMAC(const vector<uint8_t>& _data);
83+
vector<uint8_t> getCMAC(const vector<uint8_t> &_data);
5584

5685
/**
5786
* @name leftShift
@@ -61,7 +90,7 @@ class CMAC {
6190
* @param outputBuffer = Output buffer
6291
* @return void
6392
*/
64-
static void leftShift(const vector<uint8_t>& inputBuffer, vector<uint8_t>& outputBuffer) {
93+
static void leftShift(const vector<uint8_t> &inputBuffer, vector<uint8_t> &outputBuffer) {
6594
outputBuffer.clear();
6695
outputBuffer.resize(inputBuffer.size());
6796
uint8_t overflow = 0;
@@ -79,9 +108,9 @@ class CMAC {
79108
* @param data = Vector to be printed
80109
* @return void
81110
*/
82-
static void vecPrint(const string& message, const vector<unsigned char>& data) {
111+
static void vecPrint(const string &message, const vector<unsigned char> &data) {
83112
cout << message << " -> \t\t";
84-
for (unsigned char i : data) {
113+
for (unsigned char i: data) {
85114
printf("%02X", i);
86115
}
87116
cout << " | " << data.size() << endl;
@@ -95,7 +124,7 @@ class CMAC {
95124
* @param vector2 = Second vector
96125
* @param result = Resultant vector
97126
*/
98-
static void xorVec(const vector<uint8_t>& vector1, const vector<uint8_t>& vector2, vector<uint8_t>& result) {
127+
static void xorVec(const vector<uint8_t> &vector1, const vector<uint8_t> &vector2, vector<uint8_t> &result) {
99128
size_t size = min(vector1.size(), vector2.size());
100129
result.clear();
101130
result.reserve(size);
@@ -104,4 +133,46 @@ class CMAC {
104133
}
105134
}
106135

136+
/**
137+
* @name Crc32
138+
* @brief Generate a CRC checksum of width 32 for the given data array.
139+
* @param data Pointer to the data block.
140+
* @param len Length of the data block.
141+
* @param result Pointer to the CRC checksum array, in big endian format [modified].
142+
* @return void
143+
* @details Operation:
144+
* - Load the register with 0 bits.
145+
* - For each byte in the data block:
146+
* - Shift the register left by 8 bits, reading the next byte into the register.
147+
* - For each bit in the current byte (from MSB to LSB):
148+
* - If the MSB of the register is 1, perform an XOR operation with the polynomial (0x04C11DB7).
149+
* - Shift the register left by 1 bit.
150+
* - The register now contains the CRC checksum, which is stored in the result array in big endian format.
151+
*/
152+
static void crc32(uint8_t *data, size_t len, uint8_t *crc) {
153+
154+
uint32_t reg = 0;
155+
int current_bit;
156+
uint8_t current_byte;
157+
int byte;
158+
uint8_t popped_bit;
159+
160+
len += CRC32_NUMBYTES;
161+
162+
while (len--) {
163+
current_byte = *data++;
164+
for (current_bit = 8; current_bit > 0; current_bit--) {
165+
popped_bit = reg >> (CRC32_NUMBITS - 1);
166+
reg = (reg << 1) | ((len < CRC32_NUMBYTES) ? 0 : (current_byte >> 7));
167+
current_byte <<= 1;
168+
if (popped_bit) reg ^= CRC32_POLY;
169+
}
170+
}
171+
172+
for (byte = 0; byte < CRC32_NUMBYTES; byte++) {
173+
crc[byte] = reg >> (8 * (CRC32_NUMBYTES - 1 - byte)) & 0xFF;
174+
}
175+
176+
}
177+
107178
};

src/main.cpp

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
#include <iostream>
2-
#include "../include/cmac/CMAC.h"
2+
#include "../include/desfire_crypto/DesfireCrypto.h"
33

44
int main() {
55

6-
CMAC cmac;
6+
DesfireCrypto desfireCrypto;
77

8-
vector<unsigned char> key = {0x22, 0x7E, 0xAC, 0x50, 0x8F, 0xB2, 0xD1, 0x30, 0xE0, 0x45, 0x19, 0x88, 0xD5, 0x1F, 0x8D, 0xD0};
9-
vector<unsigned char> iv = {0xB9, 0x87, 0x07, 0x4D, 0x3F, 0x60, 0xEE, 0xF6, 0xC1, 0x80, 0x34, 0x55, 0x1A, 0xA7, 0x9E, 0x09};
10-
vector<unsigned char> message = {0xBD, 0x02, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00};
8+
vector<unsigned char> key = {0x32, 0x01, 0x9B, 0xE4, 0xBC, 0x09, 0xA5, 0x20, 0x7A, 0xC7, 0xC6, 0x38, 0x65, 0xC2, 0x02, 0xA4, };
9+
vector<unsigned char> iv = vector<unsigned char>(16, 0x00);
10+
vector<unsigned char> message = {0x6C, 0x00};
1111

12-
cmac.initCMAC(key, iv);
13-
//cmac.getCMAC(message);
12+
desfireCrypto.initCMAC(key, iv);
13+
desfireCrypto.generateSubkeys();
1414

15-
cout << "CMAC: ";
16-
for (auto &i : cmac.getCMAC(message)) {
15+
cout << "DesfireCrypto: ";
16+
for (auto &i : desfireCrypto.getCMAC(message)) {
1717
cout << hex << uppercase << (int) i << " ";
1818
}
1919

0 commit comments

Comments
 (0)