Я пытаюсь пройти аутентификацию с помощью криптографического чипа Atmel ATAES132 из приложения C++. Для вычисления MAC я хочу использовать библиотеку Crypto++. Чип использует AES CCM для вычисления MAC, который сравнивается с MAC, который я должен вычислить в программном обеспечении.
Генерация MAC описана в таблице данных как шифрование 128-битного блока данных (B0) в режиме CBC, операция XOR с 128-битными данными только для аутентификации и операция XOR результата с другим 128-битным блоком данных (A0), зашифрованным в режиме AES CTR.
Я делаю следующее:
string macB0string;
macB0string.append("\x79", 1);
macB0string.append(nonceString);
macB0string.append("\x01\x00\x00", 3);
// Authentication Only Data
byte aa[] = {
0x00, 0x0E, 0x00, 0xEE, 0x03, 0x01, 0x00, 0x01, 0x00, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00
};
string input, output;
input.append(macB0string);
byte zeroIV[16];
memset(zeroIV, 0, sizeof(zeroIV));
CBC_Mode< AES >::Encryption cbc;
cbc.SetKeyWithIV(key, sizeof(key), zeroIV);
StringSource(input, true,
new StreamTransformationFilter(cbc,
new StringSink(output),
StreamTransformationFilter::NO_PADDING
)
);
// Encrypt aa with same key and previous computed cipher as IV
// This is our cleartext MAC
CBC_Mode< AES >::Encryption cbc2;
cbc2.SetKeyWithIV(key, sizeof(key), (byte*)output.c_str());
string output2;
StringSource(string((const char*)aa, sizeof(aa)), true,
new StreamTransformationFilter(cbc2,
new StringSink(output2),
StreamTransformationFilter::NO_PADDING
)
);
string macA0;
macA0.append("\0x01", 1);
macA0.append(nonceString);
macA0.append("\0x01\0x00\x00", 3);
// Encrypt cleartext MAC
CTR_Mode< AES >::Encryption ctr;
ctr.SetKeyWithIV(key, sizeof(key), (byte*)macA0.c_str());
string MAC;
StringSource(output2, true,
new StreamTransformationFilter(ctr,
new StringSink(MAC)
)
);
Это именно то, что объясняется в таблице данных на странице 112. Но попытка аутентификации с помощью сгенерированного MAC-адреса не удалась. Я использовал нулевой IV в первом шифровании CBC, потому что понял, что CCM похож на CBC-MAC с нулевым IV плюс шифрование CTR.
Если кто-то, имеющий опыт работы с ATAES132, может указать мне правильное направление, что происходит не так, я был бы очень признателен.
ИЗМЕНИТЬ
Вот как процесс CCM описан в техническом описании.
В следующем примере показано, как вычисляется MAC-адрес целостности для операции аутентификации, требующей до 14 байт данных только для аутентификации. Эта операция включает в себя три прохода через криптографический механизм AES; все три с использованием одного и того же ключа. Если имеется более 14 байт данных только для аутентификации, требуется еще один проход через механизм шифрования AES.
Существует два прохода через механизм шифрования AES в режиме CBC для создания открытого MAC-адреса. Входы в криптомеханизм для этих блоков помечены как B0 и B1, а выходы — как B’0 и B’1 соответственно.
- B0 is composed of the following 128 bits:
- 1 byte flag, a fixed value of b0111 1001.
- 12-байтовый одноразовый номер, сгенерированный командой Nonce.
- 1 байт MacCount, 1 для первого поколения MAC.
- Поле длиной 2 байта, всегда 0x00 00 только для аутентификации.
- B1 is the XOR of B’0 with the following 128 bits:
- 2 byte length field, size of authenticate-only data.
- Только 14-байтовые данные для аутентификации.
- B’1 — это открытый MAC-адрес, который необходимо зашифровать перед отправкой в систему.
Существует один дополнительный проход через механизм шифрования AES в режиме CTR для создания блока ключей, который используется для шифрования MAC. Вход в криптографический механизм для этого блока помечен как A0, а выход — A’0. A’0 — это MAC-адрес, отправленный в систему в качестве выходного параметра команды Auth.
- A0 is composed of the following 128 bits:
- 1 byte flag – fixed value of b0000 0001.
- 12-байтовый одноразовый номер — сгенерированный ATAES132 во время команды Nonce.
- 1 байт MacCount – один для первого поколения MAC.
- 2-байтовое поле счетчика — всегда 0x00 00 для A0.
- A’0 подвергается операции XOR с открытым текстом MAC (B’1) и отправляется в систему.
И это код, который я пробовал
byte key[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
0x0C, 0x0D, 0x0E, 0x0F
}; // Testkey Set in Chip as KeyID 1
byte nonce[] = {
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11
};
byte crc[2];
string nonceCommand;
nonceCommand.append("\x01", 1); // Opcode
nonceCommand.append("\x00", 1); // Mode: 00 = Set Nonce
nonceCommand.append("\x00\x00\x00\x00", 4); // 4 Bytes Zero
nonceCommand.append( string((const char*)nonce, sizeof(nonce)) );
char count = nonceCommand.length() + 3; // length + 1byte count and 2bytes
// crc
nonceCommand.insert(0, &count, 1);
CalcCRC(nonceCommand.length(), (byte*)nonceCommand.c_str(), crc);
nonceCommand.append( string((const char*)crc, sizeof(crc)) );
// SNIP
// Send SetNonceCommand and read response
// SNIP
string B0;
B0.append("\x79", 1); // FixedValue
B0.append( string((const char*)nonce, sizeof(nonce)) );
B0.append("\x01", 1); // MAC Count, 1 for first generation
B0.append("\x00\x00", 2); // 2 byte length field
string AA;
AA.append("\x00\xEE", 2); // Manufacturing ID
AA.append("\x03", 1); // Opcode
AA.append("\x02", 1); // Outbound authentication (we receive a MAC)
AA.append("\x00\x01", 2); // Key ID
AA.append("\x00\x07", 2); // Usage
AA.append("\x01", 1); // Mac Flag (1 for first generation)
AA.append("\x00\x00\x00\x00", 4); // 4 Bytes Zero
AA.append("\x00", 1); // 1 Byte padding
count = AA.length();
AA.insert(0, &count, 1);
AA.insert(0, "\x00", 1);
// CCM
const int TAG_SIZE = 16;
CCM< AES, TAG_SIZE >::Encryption ccm;
ccm.SetKeyWithIV(key, sizeof(key), nonce, sizeof(nonce));
ccm.SpecifyDataLengths(AA.length(), B0.length(), 0);
string cipher;
AuthenticatedEncryptionFilter ef(ccm,
new StringSink(cipher)
);
ef.ChannelPut(AAD_CHANNEL, (byte*)AA.c_str(), AA.length());
ef.ChannelMessageEnd(AAD_CHANNEL);
ef.ChannelPut(DEFAULT_CHANNEL, (byte*)B0.c_str(), B0.length());
ef.ChannelMessageEnd(DEFAULT_CHANNEL);
string enc = cipher.substr(0, cipher.length() - TAG_SIZE);
string tag = cipher.substr(cipher.length() - TAG_SIZE);
// Get Outbound MAC from IC
string authCommand;
authCommand.append("\x03", 1); // Opcode
authCommand.append("\x02", 1); // Mode Outbound only
authCommand.append("\x00\x01", 2); // KeyID
authCommand.append("\x00\x07", 2); // Usage
count = authCommand.length() + 3;
authCommand.insert(0, &count, 1);
CalcCRC(authCommand.length(), (byte*)authCommand.c_str(), crc);
authCommand.append( string((const char*)crc, sizeof(crc)) );
// SNIP
// Send Outbound Authentication Command to IC and receive response
// SNIP
Это приводит к
enc: 96 01 a1 0d ef 1e 5f f6 5f 9d 91 7e 80 25 71 a4
tag: 71 2b a3 6a 7c 35 49 63 46 4c 58 0e a9 4a 2c 5e
Но IC отправляет аутентификационный MAC-адрес
ea c1 fd 60 9f 93 89 87 63 8f 9a df ee 17 85 bb
Я не совсем понимаю, какие правильные входные параметры для режима CCM даются в описании из даташита