@@ -30,71 +30,118 @@ namespace chip {
30
30
namespace Protocols {
31
31
namespace SecureChannel {
32
32
33
- CHIP_ERROR CheckinMessage::GenerateCheckinMessagePayload (Crypto::Aes128KeyHandle & key, CounterType counter,
34
- const ByteSpan & appData, MutableByteSpan & output)
33
+ CHIP_ERROR CheckinMessage::GenerateCheckinMessagePayload (const Crypto::Aes128KeyHandle & aes128KeyHandle,
34
+ const Crypto::Hmac128KeyHandle & hmacKeyHandle,
35
+ const CounterType & counter, const ByteSpan & appData,
36
+ MutableByteSpan & output)
35
37
{
36
- VerifyOrReturnError (appData .size () <= sMaxAppDataSize , CHIP_ERROR_INVALID_ARGUMENT );
37
- VerifyOrReturnError (output. size () >= (appData. size () + sMinPayloadSize ), CHIP_ERROR_INVALID_ARGUMENT) ;
38
+ VerifyOrReturnError (output .size () >= (appData. size () + kMinPayloadSize ), CHIP_ERROR_BUFFER_TOO_SMALL );
39
+ size_t cursorIndex = 0 ;
38
40
39
- CHIP_ERROR err = CHIP_NO_ERROR;
40
- uint8_t * appDataStartPtr = output.data () + CHIP_CRYPTO_AEAD_NONCE_LENGTH_BYTES;
41
- Encoding::LittleEndian::Put32 (appDataStartPtr, counter);
41
+ // Generate Nonce from Key and counter value
42
+ {
43
+ MutableByteSpan nonce = output.SubSpan (0 , CHIP_CRYPTO_AEAD_NONCE_LENGTH_BYTES);
44
+ cursorIndex += nonce.size ();
42
45
43
- chip::Crypto::HMAC_sha shaHandler;
44
- uint8_t nonceWorkBuffer[CHIP_CRYPTO_HASH_LEN_BYTES] = { 0 };
46
+ Encoding::LittleEndian::BufferWriter writer (nonce);
47
+ ReturnErrorOnFailure (GenerateCheckInMessageNonce (hmacKeyHandle, counter, writer));
48
+ }
49
+
50
+ // Encrypt Counter and Application Data
51
+ {
52
+ MutableByteSpan payloadByteSpan = output.SubSpan (cursorIndex, sizeof (CounterType) + appData.size ());
53
+ cursorIndex += payloadByteSpan.size ();
45
54
46
- ReturnErrorOnFailure (shaHandler.HMAC_SHA256 (key.As <Symmetric128BitsKeyByteArray>(), sizeof (Symmetric128BitsKeyByteArray),
47
- appDataStartPtr, sizeof (CounterType), nonceWorkBuffer, CHIP_CRYPTO_HASH_LEN_BYTES));
55
+ Encoding::LittleEndian::BufferWriter payloadWriter (payloadByteSpan);
48
56
49
- static_assert (sizeof (nonceWorkBuffer) >= CHIP_CRYPTO_AEAD_NONCE_LENGTH_BYTES, " We're reading off the end of our buffer." );
50
- memcpy (output.data (), nonceWorkBuffer, CHIP_CRYPTO_AEAD_NONCE_LENGTH_BYTES);
57
+ payloadWriter.EndianPut (counter, sizeof (counter));
58
+ payloadWriter.Put (appData.data (), appData.size ());
59
+ VerifyOrReturnError (payloadWriter.Fit (), CHIP_ERROR_INTERNAL);
51
60
52
- // In place encryption to save some RAM
53
- memcpy (appDataStartPtr + sizeof (CounterType), appData. data (), appData .size () );
61
+ MutableByteSpan mic = output. SubSpan (cursorIndex, CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES);
62
+ cursorIndex += mic .size ();
54
63
55
- uint8_t * micPtr = appDataStartPtr + sizeof (CounterType) + appData. size ();
56
- ReturnErrorOnFailure ( Crypto::AES_CCM_encrypt (appDataStartPtr, sizeof (CounterType) + appData .size (), nullptr , 0 , key,
57
- output. data (), CHIP_CRYPTO_AEAD_NONCE_LENGTH_BYTES, appDataStartPtr, micPtr,
58
- CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES) );
64
+ // Validate that the cursorIndex is within the available output space
65
+ VerifyOrReturnError (cursorIndex <= output .size (), CHIP_ERROR_BUFFER_TOO_SMALL);
66
+ // Validate that the cursorIndex matchs the message length
67
+ VerifyOrReturnError (cursorIndex == appData. size () + kMinPayloadSize , CHIP_ERROR_INTERNAL );
59
68
60
- output.reduce_size (appData.size () + sMinPayloadSize );
69
+ ReturnErrorOnFailure (Crypto::AES_CCM_encrypt (payloadByteSpan.data (), payloadByteSpan.size (), nullptr , 0 , aes128KeyHandle,
70
+ output.data (), CHIP_CRYPTO_AEAD_NONCE_LENGTH_BYTES, payloadByteSpan.data (),
71
+ mic.data (), mic.size ()));
72
+ }
61
73
62
- return err;
74
+ output.reduce_size (appData.size () + kMinPayloadSize );
75
+ return CHIP_NO_ERROR;
63
76
}
64
77
65
- CHIP_ERROR CheckinMessage::ParseCheckinMessagePayload (Crypto::Aes128KeyHandle & key, ByteSpan & payload, CounterType & counter,
66
- MutableByteSpan & appData)
78
+ CHIP_ERROR CheckinMessage::ParseCheckinMessagePayload (const Crypto::Aes128KeyHandle & aes128KeyHandle,
79
+ const Crypto::Hmac128KeyHandle & hmacKeyHandle, ByteSpan & payload,
80
+ CounterType & counter, MutableByteSpan & appData)
67
81
{
68
- VerifyOrReturnError (payload.size () >= sMinPayloadSize , CHIP_ERROR_INVALID_ARGUMENT);
69
- VerifyOrReturnError (payload.size () <= (sMinPayloadSize + sMaxAppDataSize ), CHIP_ERROR_INVALID_ARGUMENT);
70
-
71
- CHIP_ERROR err = CHIP_NO_ERROR;
72
82
size_t appDataSize = GetAppDataSize (payload);
73
83
84
+ VerifyOrReturnError (payload.size () >= kMinPayloadSize , CHIP_ERROR_INVALID_MESSAGE_LENGTH);
74
85
// To prevent workbuffer usage, appData size needs to be large enough to hold both the appData and the counter
75
- VerifyOrReturnError (appData.size () >= sizeof (CounterType) + appDataSize, CHIP_ERROR_INVALID_ARGUMENT);
86
+ VerifyOrReturnError (appData.size () >= sizeof (CounterType) + appDataSize, CHIP_ERROR_BUFFER_TOO_SMALL);
87
+
88
+ // Decrypt received data
89
+ {
90
+ size_t cursorIndex = 0 ;
91
+
92
+ ByteSpan nonce = payload.SubSpan (cursorIndex, CHIP_CRYPTO_AEAD_NONCE_LENGTH_BYTES);
93
+ cursorIndex += nonce.size ();
76
94
77
- ByteSpan nonce = payload.SubSpan (0 , CHIP_CRYPTO_AEAD_NONCE_LENGTH_BYTES);
78
- ByteSpan encryptedData = payload.SubSpan (CHIP_CRYPTO_AEAD_NONCE_LENGTH_BYTES, sizeof (CounterType) + appDataSize);
79
- ByteSpan mic =
80
- payload.SubSpan (CHIP_CRYPTO_AEAD_NONCE_LENGTH_BYTES + sizeof (CounterType) + appDataSize, CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES);
95
+ ByteSpan encryptedData = payload.SubSpan (cursorIndex, sizeof (CounterType) + appDataSize);
96
+ cursorIndex += encryptedData.size ();
81
97
82
- err = Crypto::AES_CCM_decrypt (encryptedData. data (), encryptedData. size (), nullptr , 0 , mic. data (), mic. size (), key, nonce. data (),
83
- nonce .size (), appData. data () );
98
+ ByteSpan mic = payload. SubSpan (cursorIndex, CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES);
99
+ cursorIndex += mic .size ();
84
100
85
- ReturnErrorOnFailure (err);
101
+ // Return Invalid message length since the payload isn't the right size
102
+ VerifyOrReturnError (cursorIndex == payload.size (), CHIP_ERROR_INVALID_MESSAGE_LENGTH);
86
103
104
+ ReturnErrorOnFailure (Crypto::AES_CCM_decrypt (encryptedData.data (), encryptedData.size (), nullptr , 0 , mic.data (), mic.size (),
105
+ aes128KeyHandle, nonce.data (), nonce.size (), appData.data ()));
106
+ }
107
+
108
+ // Read decrypted counter and application data
87
109
counter = Encoding::LittleEndian::Get32 (appData.data ());
110
+
111
+ // TODO : Validate received nonce by calculating it with the hmacKeyHandle and received Counter value
112
+
88
113
// Shift to remove the counter from the appData
89
114
memmove (appData.data (), sizeof (CounterType) + appData.data (), appDataSize);
90
-
91
115
appData.reduce_size (appDataSize);
92
- return err;
116
+
117
+ return CHIP_NO_ERROR;
118
+ }
119
+
120
+ CHIP_ERROR CheckinMessage::GenerateCheckInMessageNonce (const Crypto::Hmac128KeyHandle & hmacKeyHandle, CounterType counter,
121
+ Encoding::LittleEndian::BufferWriter & writer)
122
+ {
123
+ VerifyOrReturnError (writer.Available () >= CHIP_CRYPTO_AEAD_NONCE_LENGTH_BYTES, CHIP_ERROR_BUFFER_TOO_SMALL);
124
+
125
+ uint8_t hashWorkBuffer[CHIP_CRYPTO_HASH_LEN_BYTES] = { 0 };
126
+ uint8_t counterBuffer[sizeof (CounterType)];
127
+
128
+ // validate that Check-In counter is a uint32_t
129
+ static_assert (sizeof (CounterType) == sizeof (uint32_t ), " Expect counter to be 32 bits for correct encoding" );
130
+ Encoding::LittleEndian::Put32 (counterBuffer, counter);
131
+
132
+ chip::Crypto::HMAC_sha shaHandler;
133
+ ReturnErrorOnFailure (
134
+ shaHandler.HMAC_SHA256 (hmacKeyHandle, counterBuffer, sizeof (CounterType), hashWorkBuffer, CHIP_CRYPTO_HASH_LEN_BYTES));
135
+
136
+ writer.Put (hashWorkBuffer, CHIP_CRYPTO_AEAD_NONCE_LENGTH_BYTES);
137
+ VerifyOrReturnError (writer.Fit (), CHIP_ERROR_BUFFER_TOO_SMALL);
138
+
139
+ return CHIP_NO_ERROR;
93
140
}
94
141
95
142
size_t CheckinMessage::GetAppDataSize (ByteSpan & payload)
96
143
{
97
- return (payload.size () <= sMinPayloadSize ) ? 0 : payload.size () - sMinPayloadSize ;
144
+ return (payload.size () <= kMinPayloadSize ) ? 0 : payload.size () - kMinPayloadSize ;
98
145
}
99
146
100
147
} // namespace SecureChannel
0 commit comments