Я пытаюсь подтвердить подлинность против Atmel ATAES132 Crypto Chip из приложения C ++. Для вычисления MAC я хочу использовать библиотеку Crypto ++. Чип использует AES CCM для вычисления MAC, который сравнивается с MAC, который я должен вычислять в программном обеспечении.
Генерирование MAC описывается в таблице данных как шифрование 128-битного блока данных (B0) в режиме CBC, XOR его с использованием 128-битных данных только для аутентификации и XORing результата с помощью другого 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 состоит из следующих 128 битов:
- 1-байтовый флаг, фиксированное значение b0111 1001.
- 12-байтовый Nonce, генерируемый командой Nonce.
- 1 байт MacCount, 1 для первого поколения MAC.
- Поле длиной 2 байта, всегда 0x00 00 только для аутентификации.
- B1 — это XOR B’0 со следующими 128 битами:
- 2-байтовое поле длины, размер данных только для аутентификации.
- Только 14-байтовые данные для аутентификации.
- B’1 — это текстовый MAC, который должен быть зашифрован перед отправкой в систему.
Существует один дополнительный проход через крипто-механизм AES в режиме CTR для создания блока ключей, который используется для шифрования MAC.
Вход в крипто-движок для этого блока помечен как A0, а выход — как A’0. A’0 — это MAC, отправленный в систему в качестве выходного параметра команды Auth.
- A0 состоит из следующих 128 битов:
- 1 байт флаг — фиксированное значение b0000 0001.
- 12-байтовый Nonce — генерируется ATAES132 во время команды Nonce.
- 1 байт MacCount — один для первого поколения MAC.
- Поле счетчика 2 байта — всегда 0x00 00 для A0.
- «0» — это «XOR» с открытым текстом «MAC» («В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 приведены в описании из таблицы
Я узнал, как использовать Crypto ++ AES CCM для вычисления MAC для ATAES132.
В техническом описании описывается AES CCM, но он уже рассчитан для алгоритма CCM. Вы не можете просто вставить это в функцию CCM.
Если вы хотите использовать Crypto ++ CCM Mode для вычисления MAC, сделайте следующее:
// Compute a 12 Byte Nonce as described in the datasheet
// Get the ManufacturingID from the IC
string iv = string((const char*)nonce, sizeof(nonce));
iv.append( MACCount ); // MAC Count is part of the IV giving it a size of 13
string authOnly, empty, cipher;
authOnly.append("\x00\xEE", 2); // Manufacturing ID
authOnly.append("\x03", 1); // Opcode
authOnly.append("\x02", 1); // Outbound authentication (we receive a MAC)
authOnly.append("\x00\x01", 2); // Key ID
authOnly.append("\x00\x07", 2); // Usage
authOnly.append("\x01", 1); // Mac Flag !!!NOT MACCOUNT!!!
authOnly.append("\x00\x00\x00\x00", 4); // 4 Bytes Zero
authOnly.append("\x00", 1); // 1 Byte padding
CCM< AES, 16 >::Enryption ccm;
ccm.SetKeyWithIV(key, sizeof(key), (byte*)iv.c_str(), iv.length());
ccm.SpecifyDataLengths(authOnly.length(), empty.length(), 0); // empty is an empty string
AuthenticatedEncryptionFilter ef(ccm,
new StringSink(cipher)
);
ef.ChannelPut(AAD_CHANNEL, (byte*)authOnly.c_str(), authOnly.length());
ef.ChannelMessageEnd(AAD_CHANNEL);
ef.ChannelPut(DEFAULT_CHANNEL, (byte*)empty.c_str(), empty.length());
ef.ChannelMessageEnd(DEFAULT_CHANNEL);
string tag = cipher.substr( cipher.length() - TAG_SIZE);
Теперь у вас должен быть тот же 16-байтовый MAC, который вычислял IC.
Я не знаю, какой именно чип Atmel, но я знаю, что Crypto ++ содержит режим шифрования CCM. Ты конечно вам нужно реализовать это самостоятельно?