c++ - AtmelATAES132 Mac一代

标签 c++ encryption aes crypto++ atmel

我正在尝试根据 Atmel ATAES132 进行身份验证来自 C++ 应用程序的加密芯片。要计算 MAC,我想使用 Crypto++ 库。该芯片使用 AES CCM 计算 MAC,并将其与我必须在软件中计算的 MAC 进行比较。

MAC 生成在数据表中描述为使用 CBC 模式加密 128 位数据 block (B0),将其与 128 位仅身份验证数据进行异或,并将结果与​​另一个使用 AES CTR 模式加密的 128 位数据 block (A0) 进行异或。

我正在做的是:

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 进行身份验证尝试失败。 我在第一个 CBC 加密中使用了零填充 IV,因为我知道 CCM 就像 CBC-MAC,具有零 IV 和 CTR 加密。

如果有使用 ATAES132 经验的人可以指出正确的方向,我将非常感激。

编辑

这是数据表中描述 CCM 过程的方式。

The following example shows how the integrity MAC is calculated for an authentication operation requiring up to 14 bytes of authenticate-only data. This operation involves three passes through the AES crypto engine; all three using the same key. If there are more than 14 bytes of authenticate-only data, then another pass through the AES crypto engine is required.

There are two passes through the AES crypto engine in CBC mode to create the cleartext MAC. The inputs to the crypto engine for those blocks are labeled B0 and B1, and the outputs are B’0 and B’1, respectively.

  • B0 is composed of the following 128 bits:
    • 1 byte flag, a fixed value of b0111 1001.
    • 12 byte Nonce, as generated by the Nonce command.
    • 1 byte MacCount, 1 for first MAC generation.
    • 2 byte length field, always 0x00 00 for authentication only.
  • B1 is the XOR of B’0 with the following 128 bits:
    • 2 byte length field, size of authenticate-only data.
    • 14 byte data to be authenticated only.
  • B’1 is the cleartext MAC, which must be encrypted before being sent to the system.

There is one additional pass through the AES crypto engine in CTR mode to create the key block that is used to encrypt the MAC. The input to the crypto engine for this block is labeled A0 and the output is A’0. A’0 is the MAC sent to the system as the output parameter of the Auth command.

  • A0 is composed of the following 128 bits:
    • 1 byte flag – fixed value of b0000 0001.
    • 12 byte Nonce – as generated by ATAES132 during Nonce command.
    • 1 byte MacCount – one for first MAC generation.
    • 2 byte counter field – always 0x00 00 for A0.
  • A’0 is XOR’d with the cleartext MAC (B’1) and sent to the system.

这是我试过的代码

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 来计算 ATAES132 的 MAC。 数据表中描述的是 AES CCM,但已经针对 CCM 算法进行了计算。您不能将其直接放入 CCM 函数中。

如果您想使用 Crypto++ CCM 模式计算 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);

现在您应该拥有与 IC 计算出的相同的 16 字节 MAC。

关于c++ - AtmelATAES132 Mac一代,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24803099/

相关文章:

java - 为什么解密后的数据与使用java加密的原始数据不同?

c++ - ZXing 库 : Errors in iOS: private field 'cached_y_' is not used

c# - 处理 CryptoStream 还是处理底层 Stream?

.htaccess - 从 http 重定向到 https 是否有加密

c++ - 错误 : AES Encryption key: invalid conversion from ‘char*’ to ‘unsigned char’

node.js - nodejs加密解密有什么问题?

c++ - 纠错码

c++ - 我忘了这个叫什么了?

c++ - 损坏的双链表 : 0x0804d0c0 (C++)?

c# - BouncyCaSTLe C# PublicKey 不同于 GnuPG