CRYPTO_REQUEST(9)
π CRYPTO_REQUEST π β symmetric cryptographic operations
so this is from the Kernel Developer's Manual, section 9 β kernel-land only, bestie, no userland shenanigans π
β¨ NAME β¨
crypto_request β symmetric cryptographic operations π
πΈ SYNOPSIS πΈ
#include <opencrypto/cryptodev.h>
struct cryptop *
crypto_clonereq(crypto_session_t cses, struct cryptop *crp, int how);
int
crypto_dispatch(struct cryptop *crp);
int
crypto_dispatch_async(struct cryptop *crp, int flags);
void
crypto_dispatch_batch(struct cryptopq *crpq, int flags);
void
crypto_destroyreq(struct cryptop *crp);
void
crypto_freereq(struct cryptop *crp);
struct cryptop *
crypto_getreq(crypto_session_t cses, int how);
void
crypto_initreq(crypto_session_t cses, int how);
void
crypto_use_buf(struct cryptop *crp, void *buf, int len);
void
crypto_use_mbuf(struct cryptop *crp, struct mbuf *m);
void
crypto_use_uio(struct cryptop *crp, struct uio *uio);
void
crypto_use_vmpage(struct cryptop *crp, vm_page_t *pages, int len,
int offset);
void
crypto_use_output_buf(struct cryptop *crp, void *buf, int len);
void
crypto_use_output_mbuf(struct cryptop *crp, struct mbuf *m);
void
crypto_use_output_uio(struct cryptop *crp, struct uio *uio);
void
crypto_use_output_vmpage(struct cryptop *crp, vm_page_t *pages, int len,
int offset);
π¦ DESCRIPTION π¦
okay so picture this: every single symmetric crypto operation happening in the kernel is described by an instance of struct cryptop, and like... it's always attached to an active session. main character + their management, yk? π
Requests can be allocated dynamically or they can use caller-supplied storage. two whole vibes:
- dynamically allocated requests β allocate them with
crypto_getreq()orcrypto_clonereq(), and free them withcrypto_freereq()once the request has completed. done and dusted π«Ά - requests using caller-supplied storage β initialize them with
crypto_initreq()at the start of each operation, and destroy them withcrypto_destroyreq()once the request has completed.
for crypto_clonereq(), crypto_getreq(), and crypto_initreq(), the cses argument is a reference to an active session. for crypto_clonereq() and crypto_getreq(), how gets passed straight to malloc(9) and should be set to either M_NOWAIT or M_WAITOK β those are your only two options, no freestyling π
crypto_clonereq() allocates a brand-new request that inherits the request inputs (think request buffers and stuff) from the original crp request. but plot twist β the new request is associated with the cses session instead of inheriting the session from crp. also, crp must not be a completed request. not even a little bit. π
once a request has been initialized, the caller should set fields in the structure to describe the request-specific parameters. any fields you're not using? leave them exactly as-is, don't touch, hands off β
crypto_dispatch(), crypto_dispatch_async(), and crypto_dispatch_batch() are the ones that pass one or more crypto requests to the driver attached to the request's session. if there are errors in the request's fields, these functions may return an error to the caller. but if errors are encountered while servicing the request, they get reported to the request's callback function (crp_callback) via crp_etype instead. two very different error pipelines, don't mix them up π
β οΈ heads up bestie: a request's callback function may be invoked before crypto_dispatch() returns. yes really. keep up.
once a request has signaled completion by invoking its callback function, it should be freed via crypto_destroyreq() or crypto_freereq(). that's the cleanup era, we love a responsible queen π
cryptographic operations include several fields to describe the request β let's get into them π
π Request Buffers π
requests can either specify a single data buffer that is modified in place (crp_buf), or separate input (crp_buf) and output (crp_obuf) buffers.
π real talk: separate input and output buffers are not supported for compression mode requests. not a thing. don't try it.
all requests must have a valid crp_buf, initialized by one of these iconic little functions:
crypto_use_buf()β uses an array oflenbytes pointed to bybufas the data buffer.crypto_use_mbuf()β uses the network memory buffermas the data buffer.crypto_use_uio()β uses the scatter/gather listuioas the data buffer.crypto_use_vmpage()β uses the array ofvm_page_tstructures as the data buffer.
and for requests that use separate input and output buffers, one of these should be used to initialize crp_obuf:
crypto_use_output_buf()β uses an array oflenbytes pointed to bybufas the output buffer.crypto_use_output_mbuf()β uses the network memory buffermas the output buffer.crypto_use_output_uio()β uses the scatter/gather listuioas the output buffer.crypto_use_output_vmpage()β uses the array ofvm_page_tstructures as the output buffer.
π Request Regions π
each request describes one or more regions in the data buffers. every region is described by an offset relative to the start of a data buffer, plus a length. some regions have a length that's the same for all requests belonging to a session β those lengths live in the session parameters of the associated session. every request must define a payload region; the other regions only show up for specific session modes. it's giving Γ la carte π
for requests with separate input and output data buffers, the AAD, IV, and payload regions are always defined as regions in the input buffer, and a separate payload output region is defined to hold the output of encryption or decryption in the output buffer. the digest region describes a region in the input data buffer for requests that verify an existing digest; for requests that compute a digest, the digest region describes a region in the output data buffer.
π and note: the only data written to the output buffer is the encryption or decryption result and any computed digest. AAD and IV regions are not copied from the input buffer into the output buffer β they're inputs only, they don't get a cameo in the output.
here's the region roster, with where each one lives:
- AAD β Buffer: Input β Embedded Additional Authenticated Data
- IV β Buffer: Input β Embedded IV or nonce
- Payload β Buffer: Input β Data to encrypt, decrypt, compress, or decompress
- Payload Output β Buffer: Output β Encrypted or decrypted data
- Digest β Buffer: Input/Output β Authentication digest, hash, or tag
and the fields that actually hold their start + length (iykyk):
- AAD β Start:
crp_aad_startβ Length:crp_aad_length - IV β Start:
crp_iv_startβ Length:csp_ivlen - Payload β Start:
crp_payload_startβ Length:crp_payload_length - Payload Output β Start:
crp_payload_output_startβ Length:crp_payload_length - Digest β Start:
crp_digest_startβ Length:csp_auth_mlen
requests are permitted to operate on only a subset of the data buffer. example: requests from IPsec operate on network packets that include headers not used as either additional authentication data (AAD) or payload data. so yes, the buffer can be bigger than the region you care about π
π₯ Request Operations π₯
every request must specify the type of operation to perform in crp_op. which operations are available depends on the session's mode. choose wisely β¨
Compression requests support these:
CRYPTO_OP_COMPRESSβ compress the data in the payload region of the data buffer.CRYPTO_OP_DECOMPRESSβ decompress the data in the payload region of the data buffer.
Cipher requests support these:
CRYPTO_OP_ENCRYPTβ encrypt the data in the payload region of the data buffer.CRYPTO_OP_DECRYPTβ decrypt the data in the payload region of the data buffer.
Digest requests support these:
CRYPTO_OP_COMPUTE_DIGESTβ calculate a digest over the payload region of the data buffer and store the result in the digest region.CRYPTO_OP_VERIFY_DIGESTβ calculate a digest over the payload region of the data buffer. compare the calculated digest to the existing digest from the digest region. if the digests match, complete the request successfully. if the digests do not match, fail the request withEBADMSG. no cap, that's the fail path π
AEAD and Encrypt-then-Authenticate requests support these:
CRYPTO_OP_ENCRYPT | CRYPTO_OP_COMPUTE_DIGESTβ encrypt the data in the payload region of the data buffer. calculate a digest over the AAD and payload regions and store the result in the data buffer. two ops, one request, she's doing both πCRYPTO_OP_DECRYPT | CRYPTO_OP_VERIFY_DIGESTβ calculate a digest over the AAD and payload regions of the data buffer. compare the calculated digest to the existing digest from the digest region. if the digests match, decrypt the payload region. if the digests do not match, fail the request withEBADMSG.
π§ Request AAD π§
AEAD and Encrypt-then-Authenticate requests may optionally include Additional Authenticated Data. AAD can either be supplied in the AAD region of the input buffer, or as a single buffer pointed to by crp_aad. either way, crp_aad_length always indicates the amount of AAD in bytes β that part never changes, she's consistent π
β Request ESN β
IPsec requests may optionally include Extended Sequence Numbers (ESN) β¨ ESN can either be supplied in crp_esn or as part of the AAD pointed to by crp_aad.
if the ESN is stored in crp_esn, CSP_F_ESN should be set in csp_flags. this use case is dedicated for encrypt and authenticate mode, since the high-order 32 bits of the sequence number are appended after the Next Header (RFC 4303). very specific, very niche, very her π
AEAD modes supply the ESN in a separate AAD buffer (see e.g. RFC 4106, Chapter 5 AAD Construction).
π Request IV and/or Nonce π
some cryptographic operations require an IV or nonce as an input. an IV may be stored either in the IV region of the data buffer, or in crp_iv. by default, the IV is assumed to be stored in the IV region. if the IV is stored in crp_iv, CRYPTO_F_IV_SEPARATE should be set in crp_flags and crp_iv_start should be left as zero. zero! not whatever leftover value, zero π
requests that store part, but not all, of the IV in the data buffer should store the partial IV in the data buffer and pass the full IV separately in crp_iv. both. at once. yes really π«Ά
π Request and Callback Scheduling π
the crypto framework provides multiple methods of scheduling the dispatch of requests to drivers, along with the processing of driver callbacks. crypto_dispatch(), crypto_dispatch_async(), and crypto_dispatch_batch() can be used to request different dispatch scheduling policies β pick the one whose vibe fits π₯
crypto_dispatch() synchronously passes the request to the driver. the driver itself may process the request synchronously or asynchronously depending on whether the driver is implemented by software or hardware β that part's on the driver, not on you π
(okay that's the scheduling tea so far β there's more where this came from, don't go anywhere πΈ)
okay so crypto_dispatch_async() is the girl who does not do "wait your turn" π
β she dispatches the request asynchronously. If your driver is inherently synchronous (like, bless it, it's trying its best), the request gets queued to a taskqueue backed by a pool of worker threads. And why would we even do that? Because it can bump up throughput by letting requests from a single producer get processed in parallel. Slay.
By default, that pool is sized to give you one thread for each CPU. Worker threads dequeue requests and hand them straight to the driver asynchronously. No cap β¨
crypto_dispatch_async() also takes a flags parameter, and the star of that show is CRYPTO_ASYNC_ORDERED, which says: completion callbacks for requests must be called in the same order the requests were dispatched. If your driver is already asynchronous, then honestly crypto_dispatch_async() behaves exactly like crypto_dispatch() β same vibe, same everything π«Ά
π crypto_dispatch_batch() β the group-chat option
crypto_dispatch_batch() lets the caller collect a whole batch of requests and submit them to the driver at the same time. This is the glow-up that lets hardware drivers optimize the scheduling of request processing and batch completion interrupts together π₯
A batch gets submitted to the driver by invoking the driver's process method on each request, and you specify CRYPTO_HINT_MORE with every request except the last one. Also, heads up: the flags parameter to crypto_dispatch_batch() is currently ignored. ignored!! π
π Callback scheduling (the chill one)
Callback function scheduling is genuinely simpler than request scheduling, bestie. Callbacks can either be invoked synchronously from crypto_done(), or they can be queued to a pool of worker threads β same deal as before, that pool is sized to give you one worker thread for each CPU by default.
β οΈ But listen: a callback function invoked synchronously from crypto_done() must follow the same restrictions placed on threaded interrupt handlers. That's not a vibe, that's a rule π§
By default, callbacks are invoked asynchronously by a worker thread. Then you've got:
CRYPTO_F_CBIMMβ if set, the callback is always invoked synchronously fromcrypto_done().CRYPTO_F_CBIFSYNCβ if set, the callback is invoked synchronously if the request was processed by a software driver, or asynchronously if the request was processed by a hardware driver. It's giving "depends on the situation" π
And the plot twist: if a request was scheduled to the taskqueue with CRYPTO_ASYNC_ORDERED, callbacks are always invoked asynchronously, ignoring CRYPTO_F_CBIMM and CRYPTO_F_CBIFSYNC entirely. Periodt. Why? Because IPsec uses this flag to make sure decrypted network packets get passed up the network stack in roughly the same order they were received. Ordered queen π
β¨ Other Request Fields β¨
In addition to the fields and flags we already enumerated above, struct cryptop also includes all of these babies:
crp_sessionβ a reference to the active session. This gets set when the request is created bycrypto_getreq()and it should not be modified. Drivers can use it to fetch driver-specific session state or session parameters πcrp_etypeβ the error status. Either zero on success, or an error if a request fails. Set by drivers prior to completing a request viacrypto_done().crp_flagsβ a bitmask of flags.crp_cipher_keyβ pointer to a request-specific encryption key. If this value is not set, the request uses the session encryption key πcrp_auth_keyβ pointer to a request-specific authentication key. If this value is not set, the request uses the session authentication key.crp_opaqueβ an opaque pointer. This lets users of the cryptographic framework store information about a request that'll be used in the callback. Cute little secret pocket πcrp_callbackβ the callback function. This must point to a callback function of typevoid (*)(struct cryptop *). The callback function should inspectcrp_etypeto figure out the status of the completed operation, and it should also arrange for the request to be freed viacrypto_freereq(). Like, don't leave it lying around, bestie π«Άcrp_olenβ used with compression and decompression requests to describe the updated length of the payload region in the data buffer.
And okay, crp_olen has lore, so:
If a compression request increases the size of the payload, then the data buffer is unmodified, the request completes successfully, and crp_olen is set to the size the compressed data would have used. Callers can compare this to the payload region length to determine if the compressed data was discarded. π
π RETURN VALUES π
crypto_dispatch()returns an error if the request contained invalid fields, or zero if the request was valid. Simple as that β¨crypto_getreq()returns a pointer to a new request structure on success, orNULLon failure. AndNULLcan only be returned ifM_NOWAITwas passed inhow. Locked in π
πΈ SEE ALSO πΈ
ipsec(4), crypto(7), crypto(9), crypto_session(9), mbuf(9), uio(9)
Go read 'em, they're all iconic in their own way π
π BUGS π
Not all drivers properly handle mixing session and per-request keys within a single session. So consumers should either use a single key for a session specified in the session parameters, or always use per-request keys. Pick a lane, bestie β don't mix π
and that's the whole page!! mwah π This one's from the Debian fam, dated May 8, 2025, and it's filed under CRYPTO_REQUEST(9) β go forth and crypto responsibly, ily πβ¨π¦
π¦ where this page comes from
- freebsd 15.1: base 15.1
- Copyright (c) 2020, Chelsio Inc
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms