Skip to content

Commit 4319db5

Browse files
committed
[crypto] add platform hook for MAC frame AES-CCM* AEAD
Adds `OPENTHREAD_CONFIG_CRYPTO_PLATFORM_CCM_ENABLE` and two new platform APIs, `otPlatCryptoAesEncryptAndTag()` and `otPlatCryptoAesDecryptAndVerify()`, allowing a hardware accelerator to perform MAC frame authenticated encryption in place of the software `Crypto::AesCcm` engine.
1 parent c01cad7 commit 4319db5

12 files changed

Lines changed: 559 additions & 12 deletions

File tree

include/openthread/instance.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ extern "C" {
5252
*
5353
* @note This number versions both OpenThread platform and user APIs.
5454
*/
55-
#define OPENTHREAD_API_VERSION (602)
55+
#define OPENTHREAD_API_VERSION (603)
5656

5757
/**
5858
* @addtogroup api-instance

include/openthread/platform/crypto.h

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,61 @@ otError otPlatCryptoAesSetKey(otCryptoContext *aContext, const otCryptoKey *aKey
428428
*/
429429
otError otPlatCryptoAesEncrypt(otCryptoContext *aContext, const uint8_t *aInput, uint8_t *aOutput);
430430

431+
/**
432+
* Decrypt and verify the given AES-CCM* payload.
433+
*
434+
* @param[in] aContext AES context initialised with `otPlatCryptoAesSetKey()`.
435+
* @param[in] aNonce Nonce (13 bytes, IEEE 802.15.4 CCM* format).
436+
* @param[in] aHeader Additional authenticated data (MAC header).
437+
* @param[in] aHeaderLength Length of @p aHeader in bytes.
438+
* @param[in,out] aPayload Ciphertext on input; replaced with plaintext in place on success.
439+
* @param[in] aPayloadLength Length of @p aPayload in bytes.
440+
* @param[in] aTag MIC buffer of length @p aTagLength bytes.
441+
* @param[in] aTagLength MIC length in bytes (4, 8, or 16).
442+
*
443+
* @retval OT_ERROR_NONE Successfully decrypted and verified @p aPayload.
444+
* @retval OT_ERROR_SECURITY MIC verification failed.
445+
* @retval OT_ERROR_INVALID_ARGS @p aContext, @p aNonce, @p aPayload, or @p aTag was NULL.
446+
* @retval OT_ERROR_FAILED Other failure.
447+
*
448+
* @note This API is only used by OT core when `OPENTHREAD_CONFIG_CRYPTO_PLATFORM_CCM_ENABLE` is enabled.
449+
*/
450+
otError otPlatCryptoAesDecryptAndVerify(otCryptoContext *aContext,
451+
const uint8_t *aNonce,
452+
const void *aHeader,
453+
uint16_t aHeaderLength,
454+
void *aPayload,
455+
uint16_t aPayloadLength,
456+
const void *aTag,
457+
uint8_t aTagLength);
458+
459+
/**
460+
* Encrypt and tag the given AES-CCM* payload.
461+
*
462+
* @param[in] aContext AES context initialised with `otPlatCryptoAesSetKey()`.
463+
* @param[in] aNonce Nonce (13 bytes, IEEE 802.15.4 CCM* format).
464+
* @param[in] aHeader Additional authenticated data (MAC header).
465+
* @param[in] aHeaderLength Length of @p aHeader in bytes.
466+
* @param[in,out] aPayload Plaintext on input; replaced with ciphertext in place on success.
467+
* @param[in] aPayloadLength Length of @p aPayload in bytes.
468+
* @param[out] aTag Buffer to receive the MIC; must be at least @p aTagLength bytes.
469+
* @param[in] aTagLength MIC length in bytes (4, 8, or 16).
470+
*
471+
* @retval OT_ERROR_NONE Successfully encrypted @p aPayload and generated MIC in @p aTag.
472+
* @retval OT_ERROR_INVALID_ARGS @p aContext, @p aNonce, @p aPayload, or @p aTag was NULL.
473+
* @retval OT_ERROR_FAILED Other failure.
474+
*
475+
* @note This API is only used by OT core when `OPENTHREAD_CONFIG_CRYPTO_PLATFORM_CCM_ENABLE` is enabled.
476+
*/
477+
otError otPlatCryptoAesEncryptAndTag(otCryptoContext *aContext,
478+
const uint8_t *aNonce,
479+
const void *aHeader,
480+
uint16_t aHeaderLength,
481+
void *aPayload,
482+
uint16_t aPayloadLength,
483+
void *aTag,
484+
uint8_t aTagLength);
485+
431486
/**
432487
* Free the AES context.
433488
*

src/core/config/crypto.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,20 @@
6868
#define OPENTHREAD_CONFIG_CRYPTO_PLATFORM_ALLOCS_CONTEXT 0
6969
#endif
7070

71+
/**
72+
* @def OPENTHREAD_CONFIG_CRYPTO_PLATFORM_CCM_ENABLE
73+
*
74+
* Define to 1 to enable the platform AES-CCM* hook for MAC frame security.
75+
*
76+
* When enabled, `ProcessTransmitAesCcm()` and `ProcessReceiveAesCcm()` call
77+
* `otPlatCryptoAesEncryptAndTag()` and `otPlatCryptoAesDecryptAndVerify()` respectively,
78+
* allowing a platform to offload MAC frame AEAD to a hardware accelerator.
79+
* When disabled (default), the OpenThread core `Crypto::AesCcm` engine is used.
80+
*/
81+
#ifndef OPENTHREAD_CONFIG_CRYPTO_PLATFORM_CCM_ENABLE
82+
#define OPENTHREAD_CONFIG_CRYPTO_PLATFORM_CCM_ENABLE 0
83+
#endif
84+
7185
#if OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PLATFORM
7286

7387
/**

src/core/crypto/aes_ccm.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,5 +297,29 @@ void AesCcm::GenerateNonce(const Mac::ExtAddress &aAddress,
297297
aNonce[0] = aSecurityLevel;
298298
}
299299

300+
#if OPENTHREAD_CONFIG_CRYPTO_PLATFORM_CCM_ENABLE
301+
Error AesCcm::DecryptAndVerify(const uint8_t *aNonce,
302+
const void *aHeader,
303+
uint16_t aHeaderLength,
304+
void *aPayload,
305+
uint16_t aPayloadLength,
306+
const void *aTag,
307+
uint8_t aTagLength)
308+
{
309+
return mEcb.DecryptAndVerify(aNonce, aHeader, aHeaderLength, aPayload, aPayloadLength, aTag, aTagLength);
310+
}
311+
312+
Error AesCcm::EncryptAndTag(const uint8_t *aNonce,
313+
const void *aHeader,
314+
uint16_t aHeaderLength,
315+
void *aPayload,
316+
uint16_t aPayloadLength,
317+
void *aTag,
318+
uint8_t aTagLength)
319+
{
320+
return mEcb.EncryptAndTag(aNonce, aHeader, aHeaderLength, aPayload, aPayloadLength, aTag, aTagLength);
321+
}
322+
#endif
323+
300324
} // namespace Crypto
301325
} // namespace ot

src/core/crypto/aes_ccm.hpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,53 @@ class AesCcm
187187
uint8_t aSecurityLevel,
188188
uint8_t *aNonce);
189189

190+
#if OPENTHREAD_CONFIG_CRYPTO_PLATFORM_CCM_ENABLE
191+
/**
192+
* Decrypts and verifies the given AES-CCM* payload via the platform hook.
193+
*
194+
* @param[in] aNonce Nonce (13 bytes, IEEE 802.15.4 CCM* format).
195+
* @param[in] aHeader Additional authenticated data.
196+
* @param[in] aHeaderLength Length of @p aHeader in bytes.
197+
* @param[in,out] aPayload Ciphertext on input; replaced with plaintext in place on success.
198+
* @param[in] aPayloadLength Length of @p aPayload in bytes.
199+
* @param[in] aTag MIC buffer of length @p aTagLength bytes.
200+
* @param[in] aTagLength MIC length in bytes (4, 8, or 16).
201+
*
202+
* @retval kErrorNone Successfully decrypted and verified @p aPayload.
203+
* @retval kErrorSecurity MIC verification failed.
204+
* @retval kErrorFailed Platform operation failed.
205+
*/
206+
Error DecryptAndVerify(const uint8_t *aNonce,
207+
const void *aHeader,
208+
uint16_t aHeaderLength,
209+
void *aPayload,
210+
uint16_t aPayloadLength,
211+
const void *aTag,
212+
uint8_t aTagLength);
213+
214+
/**
215+
* Encrypts and tags the given AES-CCM* payload via the platform hook.
216+
*
217+
* @param[in] aNonce Nonce (13 bytes, IEEE 802.15.4 CCM* format).
218+
* @param[in] aHeader Additional authenticated data.
219+
* @param[in] aHeaderLength Length of @p aHeader in bytes.
220+
* @param[in,out] aPayload Plaintext on input; replaced with ciphertext in place on success.
221+
* @param[in] aPayloadLength Length of @p aPayload in bytes.
222+
* @param[out] aTag Buffer to receive the MIC; must be at least @p aTagLength bytes.
223+
* @param[in] aTagLength MIC length in bytes (4, 8, or 16).
224+
*
225+
* @retval kErrorNone Successfully encrypted @p aPayload and generated MIC in @p aTag.
226+
* @retval kErrorFailed Platform operation failed.
227+
*/
228+
Error EncryptAndTag(const uint8_t *aNonce,
229+
const void *aHeader,
230+
uint16_t aHeaderLength,
231+
void *aPayload,
232+
uint16_t aPayloadLength,
233+
void *aTag,
234+
uint8_t aTagLength);
235+
#endif
236+
190237
private:
191238
AesEcb mEcb;
192239
uint8_t mBlock[AesEcb::kBlockSize];

src/core/crypto/aes_ecb.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,32 @@ void AesEcb::Encrypt(const uint8_t aInput[kBlockSize], uint8_t aOutput[kBlockSiz
4747
SuccessOrAssert(otPlatCryptoAesEncrypt(&mContext, aInput, aOutput));
4848
}
4949

50+
#if OPENTHREAD_CONFIG_CRYPTO_PLATFORM_CCM_ENABLE
51+
Error AesEcb::DecryptAndVerify(const uint8_t *aNonce,
52+
const void *aHeader,
53+
uint16_t aHeaderLength,
54+
void *aPayload,
55+
uint16_t aPayloadLength,
56+
const void *aTag,
57+
uint8_t aTagLength)
58+
{
59+
return otPlatCryptoAesDecryptAndVerify(&mContext, aNonce, aHeader, aHeaderLength, aPayload, aPayloadLength, aTag,
60+
aTagLength);
61+
}
62+
63+
Error AesEcb::EncryptAndTag(const uint8_t *aNonce,
64+
const void *aHeader,
65+
uint16_t aHeaderLength,
66+
void *aPayload,
67+
uint16_t aPayloadLength,
68+
void *aTag,
69+
uint8_t aTagLength)
70+
{
71+
return otPlatCryptoAesEncryptAndTag(&mContext, aNonce, aHeader, aHeaderLength, aPayload, aPayloadLength, aTag,
72+
aTagLength);
73+
}
74+
#endif
75+
5076
AesEcb::~AesEcb(void) { SuccessOrAssert(otPlatCryptoAesFree(&mContext)); }
5177

5278
} // namespace Crypto

src/core/crypto/aes_ecb.hpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include <openthread/platform/crypto.h>
4040

4141
#include "common/code_utils.hpp"
42+
#include "common/error.hpp"
4243
#include "crypto/context_size.hpp"
4344
#include "crypto/storage.hpp"
4445

@@ -84,6 +85,57 @@ class AesEcb
8485
*/
8586
void Encrypt(const uint8_t aInput[kBlockSize], uint8_t aOutput[kBlockSize]);
8687

88+
#if OPENTHREAD_CONFIG_CRYPTO_PLATFORM_CCM_ENABLE
89+
/**
90+
* Decrypts and verifies the given AES-CCM* payload.
91+
*
92+
* Calls `otPlatCryptoAesDecryptAndVerify()` using the AES context set by `SetKey()`.
93+
*
94+
* @param[in] aNonce Nonce (13 bytes, IEEE 802.15.4 CCM* format).
95+
* @param[in] aHeader Additional authenticated data.
96+
* @param[in] aHeaderLength Length of @p aHeader in bytes.
97+
* @param[in,out] aPayload Ciphertext on input; replaced with plaintext in place on success.
98+
* @param[in] aPayloadLength Length of @p aPayload in bytes.
99+
* @param[in] aTag MIC buffer of length @p aTagLength bytes.
100+
* @param[in] aTagLength MIC length in bytes (4, 8, or 16).
101+
*
102+
* @retval kErrorNone Successfully decrypted and verified @p aPayload.
103+
* @retval kErrorSecurity MIC verification failed.
104+
* @retval kErrorFailed Platform operation failed.
105+
*/
106+
Error DecryptAndVerify(const uint8_t *aNonce,
107+
const void *aHeader,
108+
uint16_t aHeaderLength,
109+
void *aPayload,
110+
uint16_t aPayloadLength,
111+
const void *aTag,
112+
uint8_t aTagLength);
113+
114+
/**
115+
* Encrypts and tags the given AES-CCM* payload.
116+
*
117+
* Calls `otPlatCryptoAesEncryptAndTag()` using the AES context set by `SetKey()`.
118+
*
119+
* @param[in] aNonce Nonce (13 bytes, IEEE 802.15.4 CCM* format).
120+
* @param[in] aHeader Additional authenticated data.
121+
* @param[in] aHeaderLength Length of @p aHeader in bytes.
122+
* @param[in,out] aPayload Plaintext on input; replaced with ciphertext in place on success.
123+
* @param[in] aPayloadLength Length of @p aPayload in bytes.
124+
* @param[out] aTag Buffer to receive the MIC; must be at least @p aTagLength bytes.
125+
* @param[in] aTagLength MIC length in bytes (4, 8, or 16).
126+
*
127+
* @retval kErrorNone Successfully encrypted @p aPayload and generated MIC in @p aTag.
128+
* @retval kErrorFailed Platform operation failed.
129+
*/
130+
Error EncryptAndTag(const uint8_t *aNonce,
131+
const void *aHeader,
132+
uint16_t aHeaderLength,
133+
void *aPayload,
134+
uint16_t aPayloadLength,
135+
void *aTag,
136+
uint8_t aTagLength);
137+
#endif
138+
87139
private:
88140
ContextWith<kAesContextSize> mContext;
89141
};

src/core/crypto/crypto_platform_mbedtls.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,50 @@ OT_TOOL_WEAK otError otPlatCryptoAesFree(otCryptoContext *aContext)
152152
return error;
153153
}
154154

155+
#if OPENTHREAD_CONFIG_CRYPTO_PLATFORM_CCM_ENABLE
156+
// OPENTHREAD_CONFIG_CRYPTO_PLATFORM_CCM_ENABLE is for hardware AEAD accelerators.
157+
// Platforms enabling it must supply these symbols; there is no software fallback.
158+
OT_TOOL_WEAK otError otPlatCryptoAesDecryptAndVerify(otCryptoContext *aContext,
159+
const uint8_t *aNonce,
160+
const void *aHeader,
161+
uint16_t aHeaderLength,
162+
void *aPayload,
163+
uint16_t aPayloadLength,
164+
const void *aTag,
165+
uint8_t aTagLength)
166+
{
167+
OT_UNUSED_VARIABLE(aContext);
168+
OT_UNUSED_VARIABLE(aNonce);
169+
OT_UNUSED_VARIABLE(aHeader);
170+
OT_UNUSED_VARIABLE(aHeaderLength);
171+
OT_UNUSED_VARIABLE(aPayload);
172+
OT_UNUSED_VARIABLE(aPayloadLength);
173+
OT_UNUSED_VARIABLE(aTag);
174+
OT_UNUSED_VARIABLE(aTagLength);
175+
return kErrorFailed;
176+
}
177+
178+
OT_TOOL_WEAK otError otPlatCryptoAesEncryptAndTag(otCryptoContext *aContext,
179+
const uint8_t *aNonce,
180+
const void *aHeader,
181+
uint16_t aHeaderLength,
182+
void *aPayload,
183+
uint16_t aPayloadLength,
184+
void *aTag,
185+
uint8_t aTagLength)
186+
{
187+
OT_UNUSED_VARIABLE(aContext);
188+
OT_UNUSED_VARIABLE(aNonce);
189+
OT_UNUSED_VARIABLE(aHeader);
190+
OT_UNUSED_VARIABLE(aHeaderLength);
191+
OT_UNUSED_VARIABLE(aPayload);
192+
OT_UNUSED_VARIABLE(aPayloadLength);
193+
OT_UNUSED_VARIABLE(aTag);
194+
OT_UNUSED_VARIABLE(aTagLength);
195+
return kErrorFailed;
196+
}
197+
#endif // OPENTHREAD_CONFIG_CRYPTO_PLATFORM_CCM_ENABLE
198+
155199
#if OPENTHREAD_FTD || OPENTHREAD_MTD
156200

157201
// HMAC implementations

0 commit comments

Comments
 (0)