private static byte[] CalculateMac(byte[] key, byte[] nonce, byte[] data, byte[] associatedData, int signatureLength) { byte[] messageToAuthenticate = BuildB0Block(nonce, true, signatureLength, data.Length); if (associatedData.Length > 0) { if (associatedData.Length >= 65280) { throw new NotSupportedException("Associated data length of 65280 or more is not supported"); } byte[] associatedDataLength = BigEndianConverter.GetBytes((ushort)associatedData.Length); messageToAuthenticate = ByteUtils.Concatenate(messageToAuthenticate, associatedDataLength); messageToAuthenticate = ByteUtils.Concatenate(messageToAuthenticate, associatedData); int associatedDataPaddingLength = (16 - (messageToAuthenticate.Length % 16)) % 16; messageToAuthenticate = ByteUtils.Concatenate(messageToAuthenticate, new byte[associatedDataPaddingLength]); } messageToAuthenticate = ByteUtils.Concatenate(messageToAuthenticate, data); int dataPaddingLength = (16 - (messageToAuthenticate.Length % 16)) % 16; messageToAuthenticate = ByteUtils.Concatenate(messageToAuthenticate, new byte[dataPaddingLength]); byte[] encrypted = AesEncrypt(key, new byte[16], messageToAuthenticate, CipherMode.CBC); return(ByteReader.ReadBytes(encrypted, messageToAuthenticate.Length - 16, signatureLength)); }
public static byte[] CalculateAesCmac(byte[] key, byte[] data) { // SubKey generation // step 1, AES-128 with key K is applied to an all-zero input block. byte[] L = AESEncrypt(key, new byte[16], new byte[16]); // step 2, K1 is derived through the following operation: byte[] FirstSubkey = Rol(L); //If the most significant bit of L is equal to 0, K1 is the left-shift of L by 1 bit. if ((L[0] & 0x80) == 0x80) { FirstSubkey[15] ^= 0x87; // Otherwise, K1 is the exclusive-OR of const_Rb and the left-shift of L by 1 bit. } // step 3, K2 is derived through the following operation: byte[] SecondSubkey = Rol(FirstSubkey); // If the most significant bit of K1 is equal to 0, K2 is the left-shift of K1 by 1 bit. if ((FirstSubkey[0] & 0x80) == 0x80) { SecondSubkey[15] ^= 0x87; // Otherwise, K2 is the exclusive-OR of const_Rb and the left-shift of K1 by 1 bit. } // MAC computing if (((data.Length != 0) && (data.Length % 16 == 0)) == true) { // If the size of the input message block is equal to a positive multiple of the block size (namely, 128 bits), // the last block shall be exclusive-OR'ed with K1 before processing for (int j = 0; j < FirstSubkey.Length; j++) { data[data.Length - 16 + j] ^= FirstSubkey[j]; } } else { // Otherwise, the last block shall be padded with 10^i byte[] padding = new byte[16 - data.Length % 16]; padding[0] = 0x80; data = ByteUtils.Concatenate(data, padding); // and exclusive-OR'ed with K2 for (int j = 0; j < SecondSubkey.Length; j++) { data[data.Length - 16 + j] ^= SecondSubkey[j]; } } // The result of the previous process will be the input of the last encryption. byte[] encResult = AESEncrypt(key, new byte[16], data); byte[] HashValue = new byte[16]; Array.Copy(encResult, encResult.Length - HashValue.Length, HashValue, 0, HashValue.Length); return(HashValue); }