Svc::Ccsds::AesGcmEncryptor
The Svc::Ccsds::AesGcmEncryptor component encrypts and authenticates downlink data under AES-256-GCM, per CCSDS Space Data Link Security Protocol (CCSDS 355.0-B-2). It implements Svc.Ccsds.CcsdsSdlsEncrypt toward an encryption client (typically Svc::Ccsds::CcsdsSdlsFramer via Svc::Ccsds::SdlsSaRouter) and Svc.Ccsds.SdlsKeyInterfaceClient toward a key supplier such as Svc::Ccsds::SdlsFileKeyManager. It is the security-providing alternative to Svc::Ccsds::ClearTextEncryptor, and the downlink mirror of Svc::Ccsds::AesGcmDecryptor.
Introduction
Encrypting a frame proceeds as follows:
- Receive an SA index, plaintext buffer, and frame context on
encryptIn. - Request the AES-256 key for the frame's security association via
keyGet; on failure or a wrong-sized key, reportKEY_ERROR. - Draw a fresh IV, encrypt the plaintext into a per-instance output store, authenticating the SA index and virtual channel as AES-GCM additional authenticated data (AAD).
- Emit
IV (12) | ciphertext | MAC (16)onencryptOutwith statusSUCCESS. - Return the plaintext buffer via
bufferReturnOuton every path — it is copied, not encrypted in place.
The AAD is built by Svc::Ccsds::Utils::SdlsTmAuthMask, whose layout matches the ground segment's independent implementation of the same contract. The TM primary header does not yet exist at encryption time, so the virtual channel comes from the frame context — the same field Svc::Ccsds::TmFramer reads when it builds that header downstream, so the AAD always authenticates the VC actually transmitted.
The output store is a single per-instance buffer; it must be returned on encryptReturnIn before the next frame, and a frame arriving while it is still in flight is dropped with ENCRYPTION_FAILURE and the OutputBufferBusy event rather than overwriting unsent ciphertext.
Requirements
| Name | Description | Rationale | Validation |
|---|---|---|---|
| SVC-CCSDS-AES-ENCRYPTOR-001 | On a successful request, the AesGcmEncryptor shall emit on encryptOut a buffer laid out as IV (12) | ciphertext | MAC (16), with status SUCCESS. |
The security header and trailer Svc.Ccsds.CcsdsSdlsFramer expects. |
Unit Test |
| SVC-CCSDS-AES-ENCRYPTOR-002 | The AesGcmEncryptor shall authenticate, as AES-GCM AAD, the masked TM primary header carrying the virtual channel ID together with the SA index. | CCSDS 355.0-B-2 binds a frame to its VC and SA. | Unit Test |
| SVC-CCSDS-AES-ENCRYPTOR-003 | The AesGcmEncryptor shall draw a fresh IV from the CSPRNG for every frame. | A repeated IV under one key forfeits GCM's confidentiality and authenticity. | Unit Test |
| SVC-CCSDS-AES-ENCRYPTOR-004 | The AesGcmEncryptor shall return KEY_ERROR when the key manager reports failure or supplies a key that is not AES-256 sized. |
A wrong-sized key would otherwise encrypt under unintended material. | Unit Test |
| SVC-CCSDS-AES-ENCRYPTOR-005 | The AesGcmEncryptor shall return ENCRYPTION_FAILURE when the plaintext plus IV and MAC would exceed the TM data field less the 2-byte SA index (ComCfg.TmFrameFixedSize - 6 - 2 - 2). |
A larger output would overrun the transfer frame data field in Svc.Ccsds.TmFramer. |
Unit Test |
| SVC-CCSDS-AES-ENCRYPTOR-006 | The AesGcmEncryptor shall return the incoming plaintext buffer on bufferReturnOut, unmodified. |
The plaintext belongs to its sender and is not encrypted in place. | Unit Test |
| SVC-CCSDS-AES-ENCRYPTOR-007 | The AesGcmEncryptor shall mark its output store available again when the emitted buffer arrives on encryptReturnIn. |
The store is component memory, not allocator memory. | Unit Test |
| SVC-CCSDS-AES-ENCRYPTOR-008 | The AesGcmEncryptor shall authenticate, in the AAD, the virtual channel ID carried on the frame context. | The TM primary header does not exist at encryption time; the context carries the VC that Svc::Ccsds::TmFramer will write into it. |
Unit Test |
| SVC-CCSDS-AES-ENCRYPTOR-009 | The AesGcmEncryptor shall drop a frame with ENCRYPTION_FAILURE and the OutputBufferBusy event, rather than overwrite its output store, when a previously emitted frame has not yet returned on encryptReturnIn. |
The store is a single buffer; overwriting it would let the new frame's MAC cover a silent substitution. | Unit Test |
| SVC-CCSDS-AES-ENCRYPTOR-010 | The AesGcmEncryptor shall emit on encryptOut only its own output store, and shall return the incoming plaintext on bufferReturnOut on every path, with a failed frame reporting its status against an empty buffer. |
Keeps buffer ownership unambiguous on the return path. | Unit Test |
| SVC-CCSDS-AES-ENCRYPTOR-011 | The AesGcmEncryptor shall return ENCRYPTION_FAILURE rather than emit a frame if the CSPRNG cannot supply an IV. |
Encrypting under a stale or predictable IV is worse than dropping the frame. | Inspection |
Design
The component is passive with no commands, telemetry, or parameters, and allocates no memory after construction. It composes two interfaces:
| Kind | Name | Port Type | Description |
|---|---|---|---|
| guarded input | encryptIn | Svc.Ccsds.CcsdsSdlsEncryption | Receives the SA index and plaintext buffer to encrypt. |
| output | encryptOut | Svc.Ccsds.CcsdsSdlsData | Sends the operation status and encrypted data downstream. |
| sync input | encryptReturnIn | Svc.ComDataWithContext | Receives back ownership of buffers sent on encryptOut. |
| output | bufferReturnOut | Svc.ComDataWithContext | Returns the incoming plaintext buffer for deallocation. |
| output | keyGet | Svc.Ccsds.SdlsKey | Requests the AES-256 key for the frame's security association, passing the SA index with the request. |
Events: OutputBufferBusy (WARNING_HI).
The SA index is passed on every keyGet request, but whether it selects the key is up to the connected key source. Per Svc.Ccsds.SdlsKeyInterface, an implementation keyed per SA documents which indices it serves and returns KEY_ERROR for any other, while one that ignores the index says so. The in-tree Svc.Ccsds.SdlsFileKeyManager ignores it and returns its single file key for every SA — adequate where the deployment uses one key across its SAs by design, but note that SAs sharing a key also share its IV budget (see Security Considerations).
Configuration
Compile time: none of its own. The output store is sized directly from ComCfg.TmFrameFixedSize, the project-overridable TM frame size every deployment already sets; the accepted output is bounded by the TM data field less the SA index that Svc.Ccsds.CcsdsSdlsFramer prepends.
Runtime: none. The constructor builds the EVP_CIPHER_CTX every frame reuses, which is what keeps encryptIn free of dynamic allocation, and the authenticated virtual channel arrives per frame on the frame context.
Security Considerations
Each frame is encrypted under a freshly drawn 96-bit random IV. A repeated IV under one key forfeits both confidentiality and authenticity for GCM, so this is the property the design protects most carefully: the component returns ENCRYPTION_FAILURE rather than emit a frame if the CSPRNG cannot supply one.
Random IVs of this width carry a bound. NIST SP 800-38D §8.3 limits a key to 2^32 invocations when IVs are constructed randomly, which keeps the collision probability below 2^-32. Nothing in this component counts invocations or forces a re-key, and the in-tree Svc.Ccsds.SdlsFileKeyManager serves one static key for the life of the process, so respecting the bound is a deployment responsibility. Two consequences follow:
- The budget is per key, not per SA. Where several security associations are served by the same key material — which
SdlsFileKeyManagerdoes by construction — their frame counts add up against the same 2^32. - A long-lived mission can reach it. At one downlink frame every 100 ms across a single SA, 2^32 frames is roughly 13 years of continuous transmission; a higher frame rate, or several SAs sharing a key, scales that down proportionally.
A mission that expects to approach the bound should either rotate keys through a key manager of its own, or move to the deterministic IV construction of §8.2.1 (a fixed field identifying the sender plus an invocation field that never repeats), which removes the birthday bound at the cost of requiring non-volatile invocation state.
Unit Testing
Direct tests covering the frame layout and AAD, IV freshness, both key-error paths, the output-size bound, buffer ownership, and both busy-store cases (the drop, and back-to-back frames succeeding when the buffer returns from inside encryptOut, as CcsdsSdlsFramer does on a synchronous pipeline). The AAD and ciphertext are checked against an independently built reference rather than assumed self-consistent. Requirements are traced with REQUIREMENT() macros in the test main.