[crypto] introduce AesCcm::Nonce for IEEE 802.15.4 nonce (#13208)

This commit introduces the `AesCcm::Nonce` class to represent the IEEE
802.15.4 nonce byte sequence, replacing the previous `GenerateNonce()`
method which operated on a raw byte array.

Replacing `uint8_t *` buffers and `kNonceSize` with a dedicated, packed
`Nonce` class makes the code cleaner and prevents potential buffer size
mismatches at call sites. The new class provides an `InitFrom()` method
to safely initialize the nonce from an extended address, frame counter,
and security level.

All callers in `Mac` (frame transmission and reception) and `Mle`
(message security) have been updated to use the new `Nonce` class.
This commit is contained in:
Abtin Keshavarzian
2026-06-08 14:21:27 -07:00
committed by GitHub
parent 260f44f2d3
commit 9b180d4c09
4 changed files with 70 additions and 59 deletions
+12 -11
View File
@@ -40,6 +40,11 @@
namespace ot {
namespace Crypto {
//---------------------------------------------------------------------------------------------------------------------
// AesCcm
static_assert(sizeof(AesCcm::Nonce) == 13, "Nonce format is not valid");
void AesCcm::SetKey(const uint8_t *aKey, uint16_t aKeyLength)
{
Key cryptoKey;
@@ -283,18 +288,14 @@ void AesCcm::Finalize(void *aTag)
}
}
void AesCcm::GenerateNonce(const Mac::ExtAddress &aAddress,
uint32_t aFrameCounter,
uint8_t aSecurityLevel,
uint8_t *aNonce)
//---------------------------------------------------------------------------------------------------------------------
// AesCcm::Nonce
void AesCcm::Nonce::InitFrom(const Mac::ExtAddress &aExtAddress, uint32_t aFrameCounter, uint8_t aSecurityLevel)
{
memcpy(aNonce, aAddress.m8, sizeof(Mac::ExtAddress));
aNonce += sizeof(Mac::ExtAddress);
BigEndian::WriteUint32(aFrameCounter, aNonce);
aNonce += sizeof(uint32_t);
aNonce[0] = aSecurityLevel;
mExtAddress = aExtAddress;
mFrameCounter = BigEndian::HostSwap32(aFrameCounter);
mSecurityLevel = aSecurityLevel;
}
} // namespace Crypto
+24 -14
View File
@@ -63,7 +63,6 @@ class AesCcm
public:
static constexpr uint8_t kMinTagLength = 4; ///< Minimum tag length (in bytes).
static constexpr uint8_t kMaxTagLength = AesEcb::kBlockSize; ///< Maximum tag length (in bytes).
static constexpr uint8_t kNonceSize = 13; ///< Size of IEEE 802.15.4 Nonce (in bytes).
/**
* Type represent the encryption vs decryption mode.
@@ -74,6 +73,30 @@ public:
kDecrypt, // Decryption mode.
};
/**
* Represents an IEEE 802.15.4 nonce byte sequence.
*/
OT_TOOL_PACKED_BEGIN
class Nonce : public Clearable<Nonce>
{
public:
/**
* Initializes the nonce from a given extended address, frame counter, and security level.
*
* @param[in] aExtAddress An extended address.
* @param[in] aFrameCounter A frame counter.
* @param[in] aSecurityLevel A security level.
*/
void InitFrom(const Mac::ExtAddress &aExtAddress, uint32_t aFrameCounter, uint8_t aSecurityLevel);
private:
Mac::ExtAddress mExtAddress;
uint32_t mFrameCounter;
uint8_t mSecurityLevel;
} OT_TOOL_PACKED_END;
static_assert(sizeof(Nonce) == 13, "Nonce format is not valid");
/**
* Sets the key.
*
@@ -174,19 +197,6 @@ public:
*/
void Finalize(void *aTag);
/**
* Generates IEEE 802.15.4 nonce byte sequence.
*
* @param[in] aAddress An extended address.
* @param[in] aFrameCounter A frame counter.
* @param[in] aSecurityLevel A security level.
* @param[out] aNonce A buffer (with `kNonceSize` bytes) to place the generated nonce.
*/
static void GenerateNonce(const Mac::ExtAddress &aAddress,
uint32_t aFrameCounter,
uint8_t aSecurityLevel,
uint8_t *aNonce);
private:
AesEcb mEcb;
uint8_t mBlock[AesEcb::kBlockSize];
+23 -23
View File
@@ -1375,23 +1375,23 @@ void TxFrame::CopyFrom(const TxFrame &aFromFrame)
void TxFrame::ProcessTransmitAesCcm(const ExtAddress &aExtAddress)
{
#if OPENTHREAD_FTD || OPENTHREAD_MTD || OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_SECURITY_ENABLE
uint32_t frameCounter = 0;
uint8_t securityLevel;
uint8_t nonce[Crypto::AesCcm::kNonceSize];
uint8_t tagLength;
Crypto::AesCcm aesCcm;
uint32_t frameCounter = 0;
uint8_t securityLevel;
uint8_t tagLength;
Crypto::AesCcm aesCcm;
Crypto::AesCcm::Nonce nonce;
VerifyOrExit(GetSecurityEnabled());
SuccessOrExit(GetSecurityLevel(securityLevel));
SuccessOrExit(GetFrameCounter(frameCounter));
Crypto::AesCcm::GenerateNonce(aExtAddress, frameCounter, securityLevel, nonce);
nonce.InitFrom(aExtAddress, frameCounter, securityLevel);
aesCcm.SetKey(GetAesKey());
tagLength = GetFooterLength() - GetFcsSize();
aesCcm.Init(GetHeaderLength(), GetPayloadLength(), tagLength, nonce, sizeof(nonce));
aesCcm.Init(GetHeaderLength(), GetPayloadLength(), tagLength, &nonce, sizeof(nonce));
aesCcm.Header(GetHeader(), GetHeaderLength());
aesCcm.Payload(GetPayload(), GetPayload(), GetPayloadLength(), Crypto::AesCcm::kEncrypt);
aesCcm.Finalize(GetFooter());
@@ -1408,23 +1408,23 @@ exit:
#if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT && OPENTHREAD_CONFIG_MAC_SOFTWARE_RETX_SECURITY_ENABLE
void TxFrame::DecryptTransmitAesCcm(const ExtAddress &aExtAddress)
{
uint32_t frameCounter = 0;
uint8_t securityLevel;
uint8_t nonce[Crypto::AesCcm::kNonceSize];
uint8_t tagLength;
Crypto::AesCcm aesCcm;
uint32_t frameCounter = 0;
uint8_t securityLevel;
uint8_t tagLength;
Crypto::AesCcm aesCcm;
Crypto::AesCcm::Nonce nonce;
VerifyOrExit(GetSecurityEnabled() && IsSecurityProcessed());
SuccessOrExit(GetSecurityLevel(securityLevel));
SuccessOrExit(GetFrameCounter(frameCounter));
Crypto::AesCcm::GenerateNonce(aExtAddress, frameCounter, securityLevel, nonce);
nonce.InitFrom(aExtAddress, frameCounter, securityLevel);
aesCcm.SetKey(GetAesKey());
tagLength = GetFooterLength() - GetFcsSize();
aesCcm.Init(GetHeaderLength(), GetPayloadLength(), tagLength, nonce, sizeof(nonce));
aesCcm.Init(GetHeaderLength(), GetPayloadLength(), tagLength, &nonce, sizeof(nonce));
aesCcm.Header(GetHeader(), GetHeaderLength());
aesCcm.Payload(GetPayload(), GetPayload(), GetPayloadLength(), Crypto::AesCcm::kDecrypt);
// Note: We skip aesCcm.Finalize() checking because we are only decrypting back to plaintext,
@@ -1624,25 +1624,25 @@ exit:
Error RxFrame::ProcessReceiveAesCcm(const ExtAddress &aExtAddress, const KeyMaterial &aMacKey)
{
#if OPENTHREAD_FTD || OPENTHREAD_MTD
Error error = kErrorSecurity;
uint32_t frameCounter = 0;
uint8_t securityLevel;
uint8_t nonce[Crypto::AesCcm::kNonceSize];
uint8_t tag[kMaxMicSize];
uint8_t tagLength;
Crypto::AesCcm aesCcm;
Error error = kErrorSecurity;
uint32_t frameCounter = 0;
uint8_t securityLevel;
uint8_t tag[kMaxMicSize];
uint8_t tagLength;
Crypto::AesCcm aesCcm;
Crypto::AesCcm::Nonce nonce;
VerifyOrExit(GetSecurityEnabled(), error = kErrorNone);
SuccessOrExit(GetSecurityLevel(securityLevel));
SuccessOrExit(GetFrameCounter(frameCounter));
Crypto::AesCcm::GenerateNonce(aExtAddress, frameCounter, securityLevel, nonce);
nonce.InitFrom(aExtAddress, frameCounter, securityLevel);
aesCcm.SetKey(aMacKey);
tagLength = GetFooterLength() - GetFcsSize();
aesCcm.Init(GetHeaderLength(), GetPayloadLength(), tagLength, nonce, sizeof(nonce));
aesCcm.Init(GetHeaderLength(), GetPayloadLength(), tagLength, &nonce, sizeof(nonce));
aesCcm.Header(GetHeader(), GetHeaderLength());
#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
aesCcm.Payload(GetPayload(), GetPayload(), GetPayloadLength(), Crypto::AesCcm::kDecrypt);
+11 -11
View File
@@ -1520,15 +1520,15 @@ Error Mle::ProcessMessageSecurity(Crypto::AesCcm::Mode aMode,
// `kErrorNone` message encrypted and tag appended to message.
// `kErrorNoBufs` could not grow the message to append the tag.
Error error = kErrorNone;
Crypto::AesCcm aesCcm;
uint8_t nonce[Crypto::AesCcm::kNonceSize];
uint8_t tag[kMleSecurityTagSize];
Mac::ExtAddress extAddress;
uint32_t keySequence;
uint16_t payloadLength = aMessage.GetLength() - aCmdOffset;
const Ip6::Address *senderAddress = &aMessageInfo.GetSockAddr();
const Ip6::Address *receiverAddress = &aMessageInfo.GetPeerAddr();
Error error = kErrorNone;
Crypto::AesCcm aesCcm;
Crypto::AesCcm::Nonce nonce;
uint8_t tag[kMleSecurityTagSize];
Mac::ExtAddress extAddress;
uint32_t keySequence;
uint16_t payloadLength = aMessage.GetLength() - aCmdOffset;
const Ip6::Address *senderAddress = &aMessageInfo.GetSockAddr();
const Ip6::Address *receiverAddress = &aMessageInfo.GetPeerAddr();
switch (aMode)
{
@@ -1548,7 +1548,7 @@ Error Mle::ProcessMessageSecurity(Crypto::AesCcm::Mode aMode,
}
extAddress.SetFromIid(senderAddress->GetIid());
Crypto::AesCcm::GenerateNonce(extAddress, aHeader.GetFrameCounter(), Mac::Frame::kSecurityEncMic32, nonce);
nonce.InitFrom(extAddress, aHeader.GetFrameCounter(), Mac::Frame::kSecurityEncMic32);
keySequence = aHeader.GetKeyId();
@@ -1557,7 +1557,7 @@ Error Mle::ProcessMessageSecurity(Crypto::AesCcm::Mode aMode,
: Get<KeyManager>().GetTemporaryMleKey(keySequence));
aesCcm.Init(sizeof(Ip6::Address) + sizeof(Ip6::Address) + sizeof(SecurityHeader), payloadLength,
kMleSecurityTagSize, nonce, sizeof(nonce));
kMleSecurityTagSize, &nonce, sizeof(nonce));
aesCcm.Header(*senderAddress);
aesCcm.Header(*receiverAddress);