CRYPTO(9)
β¨ NAME β¨
crypto β the API for cryptographic services in the kernel π
okay so bestie, welcome to crypto(9), straight out of the Kernel Developer's Manual. this is the whole vibe of how hardware crypto drivers and their consumers talk to each other in-kernel. grab a snack, it's a long one π
πΈ SYNOPSIS πΈ
#include <opencrypto/cryptodev.h>
int32_t
crypto_get_driverid(device_t dev, size_t session_size, int flags);
int
crypto_register(uint32_t driverid, int alg, uint16_t maxoplen,
uint32_t flags);
int
crypto_kregister(uint32_t driverid, int kalg, uint32_t flags);
int
crypto_unregister(uint32_t driverid, int alg);
int
crypto_unregister_all(uint32_t driverid);
void
crypto_done(struct cryptop *crp);
void
crypto_kdone(struct cryptkop *krp);
int
crypto_find_driver(const char *match);
int
crypto_newsession(crypto_session_t *cses, struct cryptoini *cri,
int crid);
int
crypto_freesession(crypto_session_t cses);
int
crypto_dispatch(struct cryptop *crp);
int
crypto_kdispatch(struct cryptkop *krp);
int
crypto_unblock(uint32_t driverid, int what);
struct cryptop *
crypto_getreq(int num);
void
crypto_freereq(struct cryptop *crp);
and the lil constants:
#define CRYPTO_SYMQ 0x1
#define CRYPTO_ASYMQ 0x2
#define EALG_MAX_BLOCK_LEN 16
and the structs, in all their glory β¨
struct cryptoini {
int cri_alg;
int cri_klen;
int cri_mlen;
caddr_t cri_key;
uint8_t cri_iv[EALG_MAX_BLOCK_LEN];
struct cryptoini *cri_next;
};
struct cryptodesc {
int crd_skip;
int crd_len;
int crd_inject;
int crd_flags;
struct cryptoini CRD_INI;
#define crd_iv CRD_INI.cri_iv
#define crd_key CRD_INI.cri_key
#define crd_alg CRD_INI.cri_alg
#define crd_klen CRD_INI.cri_klen
struct cryptodesc *crd_next;
};
struct cryptop {
TAILQ_ENTRY(cryptop) crp_next;
crypto_session_t crp_session;
int crp_ilen;
int crp_olen;
int crp_etype;
int crp_flags;
caddr_t crp_buf;
caddr_t crp_opaque;
struct cryptodesc *crp_desc;
int (*crp_callback) (struct cryptop *);
caddr_t crp_mac;
};
struct crparam {
caddr_t crp_p;
u_int crp_nbits;
};
#define CRK_MAXPARAM 8
struct cryptkop {
TAILQ_ENTRY(cryptkop) krp_next;
u_int krp_op; /* ie. CRK_MOD_EXP or other */
u_int krp_status; /* return status */
u_short krp_iparams; /* # of input parameters */
u_short krp_oparams; /* # of output parameters */
uint32_t krp_hid;
struct crparam krp_param[CRK_MAXPARAM];
int (*krp_callback)(struct cryptkop *);
};
π¦ DESCRIPTION π¦
so crypto is this whole framework, right? it's here so drivers of cryptographic hardware can register themselves with the kernel, and then all the "consumers" out there β other kernel subsystems, plus users coming in through the /dev/crypto device β get to actually use that hardware. iconic behavior honestly π
drivers register the algorithms they support with the framework, and they hand over entry points (functions) that the framework can call to establish, use, and tear down sessions. sessions are the move because they let a particular driver (or its associated hardware) cache cryptographic info, so you're not redoing initialization on literally every single request. and consumers? they pass a set of descriptors that tell the framework (and whichever drivers are registered) which operations should be applied to the data β and yes, more than one cryptographic operation can be requested at a time. multitasking queen π
keying operations are supported too π. unlike the symmetric operators we just described, these are sessionless commands, and they perform mathematical operations using input and output parameters.
now here's the tea: since consumers might not be tied to a process at all, drivers are not allowed to sleep(9) π΄π«. same rule for the framework itself. so instead, there's a callback mechanism to let a consumer know a request is done (the consumer specifies that callback on a per-request basis). the framework calls the callback whether the request succeeded or not, and if it flopped, there's an error indication. one specific error code, EAGAIN, is the special one: it means a session handle has changed, and you can re-submit the request immediately with the new session. errors only get returned to the invoking function when there isn't enough info to even call the callback β meaning there was a fatal error while verifying the arguments. and for session initialization and teardown? no callback mechanism at all, bestie.
β οΈ note the rule: drivers may not sleep(9), and neither may the framework.
crypto_find_driver() returns the driver id of the device whose name matches match. match can be either the exact name of a device including the unit, or the driver name without a unit. in that second case, you get the id of the first device with the matching driver name. if nothing matches? you get the value -1. π
crypto_newsession() is what consumers of cryptographic services (hi, ipsec(4) stack π) call when they want to establish a new session with the framework. the cri argument points at a cryptoini structure holding all the info the driver needs to set the session up. the crid argument is either a specific driver id or a bitmask of flags:
CRYPTOCAP_F_HARDWAREβ pick hardware devicesCRYPTOCAP_F_SOFTWAREβ pick software devices
if you specify both, hardware devices get preferred over software devices. on success, the opaque session handle of the new session lands in *cses. π
the cryptoini structure that cri points to has these fields:
cri_algβ an algorithm identifier. the currently supported algorithms are:CRYPTO_AES_128_NIST_GMACCRYPTO_AES_192_NIST_GMACCRYPTO_AES_256_NIST_GMACCRYPTO_AES_CBCCRYPTO_AES_CCM_16CRYPTO_AES_CCM_CBC_MACCRYPTO_AES_ICMCRYPTO_AES_NIST_GCM_16CRYPTO_AES_NIST_GMACCRYPTO_AES_XTSCRYPTO_ARC4CRYPTO_BLAKE2BCRYPTO_BLAKE2SCRYPTO_BLF_CBCCRYPTO_CAMELLIA_CBCCRYPTO_CAST_CBCCRYPTO_CHACHA20CRYPTO_DEFLATE_COMPCRYPTO_DES_CBCCRYPTO_3DES_CBCCRYPTO_MD5CRYPTO_MD5_HMACCRYPTO_MD5_KPDKCRYPTO_NULL_HMACCRYPTO_NULL_CBCCRYPTO_POLY1305CRYPTO_RIPEMD160CRYPTO_RIPEMD160_HMACCRYPTO_SHA1CRYPTO_SHA1_HMACCRYPTO_SHA1_KPDKCRYPTO_SHA2_224CRYPTO_SHA2_224_HMACCRYPTO_SHA2_256CRYPTO_SHA2_256_HMACCRYPTO_SHA2_384CRYPTO_SHA2_384_HMACCRYPTO_SHA2_512CRYPTO_SHA2_512_HMACCRYPTO_SKIPJACK_CBC
cri_klenβ for variable-size key algorithms, the length of the key in bits.cri_mlenβ if it's non-zero, truncate the calculated hash to this many bytes.cri_keyβ the key to be used.cri_ivβ an explicit initialization vector, for when it doesn't prefix the data. this field gets ignored during initialization (crypto_newsession). and if no IV is explicitly passed (details below, keep reading π«Ά), the device driver processing the request uses a random IV.cri_nextβ pointer to anothercryptoinistructure. this is how you establish dual-algorithm sessions, like combining a cipher with a MAC. two-for-one, we love it β¨
π thecryptoinistructure and its contents will not be modified or referenced by the framework or any cryptographic drivers. so the memory associated with cri can be released as soon ascrypto_newsession()returns. no leaks, no worries.
crypto_freesession() is the one you call with the session handle that crypto_newsession() gave you, to free that session. bye bestie π
crypto_dispatch() is what you call to process a request. the various fields in the cryptop structure are:
crp_sessionβ the session handle.crp_ilenβ the total length in bytes of the buffer to be processed.crp_olenβ on return, this holds the total length of the result. for symmetric crypto operations, it'll be the same as the input length. it gets used if the framework needs to allocate a new buffer for the result (or to re-format the input).crp_callbackβ the callback routine invoked when a request is completed viacrypto_done(). that callback should go peek atcrp_etypeto figure out whether the request was successfully completed.crp_etypeβ the error type if any errors came up, or zero if the request was processed successfully. if theEAGAINerror code comes back, the session handle has changed (and the new one has been recorded in thecrp_sessionfield). the consumer should record that new session handle and use it in all subsequent requests. in this case, the request may be re-submitted immediately. the framework uses this mechanism to do session migration β moving a session from one driver to another because of availability, performance, or other considerations.
this field is only valid in the context of the callback routine specified by crp_callback. errors are returned to the invoker of crypto_process() only when there isn't enough information to call the callback routine β that is, if the pointer passed is NULL, or if no callback routine was specified.
crp_flagsβ a bitmask of flags associated with this request. the currently defined flags are:CRYPTO_F_IMBUFβ the buffer is an mbuf chain pointed to bycrp_mbuf.CRYPTO_F_IOVβ the buffer is auiostructure pointed to bycrp_uio.CRYPTO_F_BATCHβ batch operation if possible.CRYPTO_F_CBIMMβ do the callback immediately instead of doing it from a dedicated kernel thread.CRYPTO_F_DONEβ operation completed.
So the flag squad continues π β these change how your crypto request behaves:
CRYPTO_F_CBIFSYNCβ do callback immediately if the operation is synchronous (aka the driver specified theCRYPTOCAP_F_SYNCflag). No waiting, bestie. π¦CRYPTO_F_ASYNCβ try to do the crypto operation in a pool of workers if the operation is synchronous (that is, if the driver specified theCRYPTOCAP_F_SYNCflag). It aims to speed up processing by dispatching crypto operations on different processors. parallel processing slay β¨CRYPTO_F_ASYNC_KEEPORDERβ dispatch callbacks in the same order they are posted. Only relevant if theCRYPTO_F_ASYNCflag is set and if the operation is synchronous. Order matters, periodt. π
Now the rest of the cryptop fields, because yes:
crp_bufβ data buffer unlessCRYPTO_F_IMBUForCRYPTO_F_IOVis set incrp_flags. The length in bytes is set incrp_ilen.crp_mbufβ data buffer mbuf chain whenCRYPTO_F_IMBUFis set incrp_flags.crp_uioβstruct uiodata buffer whenCRYPTO_F_IOVis set incrp_flags.crp_opaqueβ cookie passed through the crypto framework untouched. It is intended for the invoking application's use. your lil secret πcrp_descβ a linked list of descriptors. Each descriptor provides information about what type of cryptographic operation should be done on the input buffer. The various fields are:crd_ivβ when the flagCRD_F_IV_EXPLICITis set, this field contains the IV.crd_keyβ when theCRD_F_KEY_EXPLICITflag is set, thecrd_keypoints to a buffer with encryption or authentication key.crd_algβ an algorithm to use. Must be the same as the one given at newsession time. No swapping mid-session. πcrd_klenβ thecrd_keykey length.crd_skipβ the offset in the input buffer where processing should start.crd_lenβ how many bytes, aftercrd_skip, should be processed.crd_injectβ specifies an offset in bytes from the beginning of the buffer. For encryption algorithms, this may be where the IV will be inserted when encrypting or where the IV may be found for decryption (subject tocrd_flags). For MAC algorithms, this is where the result of the keyed hash will be inserted.crd_flagsβ the following flags are defined:CRD_F_ENCRYPTβ for encryption algorithms, this bit is set when encryption is required (when not set, decryption is performed).CRD_F_IV_PRESENTβ for encryption, if this bit is not set the IV used to encrypt the packet will be written at the location pointed to bycrd_inject. The IV length is assumed to be equal to the blocksize of the encryption algorithm. For encryption, if this bit is set, nothing is done. For decryption, this flag has no meaning. Applications that do special βIV cookingβ, such as the half-IV mode inipsec(4), can use this flag to indicate that the IV should not be written on the packet. This flag is typically used in conjunction with theCRD_F_IV_EXPLICITflag.CRD_F_IV_EXPLICITβ this bit is set when the IV is explicitly provided by the consumer in thecrd_ivfield. Otherwise, for encryption operations the IV is provided for by the driver used to perform the operation, whereas for decryption operations the offset of the IV is provided by thecrd_injectfield. This flag is typically used when the IV is calculated βon the flyβ by the consumer, and does not precede the data.CRD_F_KEY_EXPLICITβ for encryption and authentication (MAC) algorithms, this bit is set when the key is explicitly provided by the consumer in thecrd_keyfield for the given operation. Otherwise, the key is taken at newsession time from thecri_keyfield. As calculating the key schedule may take a while, it is recommended that often used keys are given their own session. dedicated session era πCRD_F_COMPβ for compression algorithms, this bit is set when compression is required (when not set, decompression is performed).
CRD_INIβ thiscryptoinistructure will not be modified by the framework or the device drivers. Since this information accompanies every cryptographic operation request, drivers may re-initialize state on-demand (typically an expensive operation). Furthermore, the cryptographic framework may re-route requests as a result of full queues or hardware failure, as described above.crd_nextβ point to the next descriptor. Linked operations are useful in protocols such asipsec(4), where multiple cryptographic transforms may be applied on the same block of data.
crypto_getreq()allocates acryptopstructure with a linked list of numcryptodescstructures.crypto_freereq()deallocates a structurecryptopand anycryptodescstructures linked to it. Note that it is the responsibility of the callback routine to do the necessary cleanups associated with the opaque field in thecryptopstructure.crypto_kdispatch()is called to perform a keying operation. The various fields in thecryptkopstructure are:krp_opβ operation code, such asCRK_MOD_EXP.krp_statusβ return code. This errno-style variable indicates whether lower level reasons for operation failure.krp_iparamsβ number of input parameters to the specified operation. Note that each operation has a (typically hardwired) number of such parameters.krp_oparamsβ number of output parameters from the specified operation. Note that each operation has a (typically hardwired) number of such parameters.krp_kvpβ an array of kernel memory blocks containing the parameters.krp_hidβ identifier specifying which low-level driver is being used.krp_callbackβ callback called on completion of a keying operation.
π DRIVER-SIDE API π
okay bestie, so if you're writing a driver that gives the kernel cryptographic primitives, these are your ride-or-die routines: crypto_get_driverid(), crypto_get_driver_session(), crypto_register(), crypto_kregister(), crypto_unregister(), crypto_unblock(), and crypto_done(). They let you register and unregister with the kernel crypto services framework. periodt.
First things first: drivers must call crypto_get_driverid() to get a driver identifier. You pass the flags as an argument, and you have to specify one of CRYPTOCAP_F_SOFTWARE or CRYPTOCAP_F_HARDWARE. You can also specify CRYPTOCAP_F_SYNC, and honestly you should if your driver does all of its operations synchronously. The second argument is the size of your session structure. The framework will allocate appropriately sized memory, zero it, and pass it to your driver's newsession() method. iconic.
Then, for every algorithm your driver supports, call crypto_register(). The first two arguments are the driver and algorithm identifiers. The next two arguments specify the largest possible operator length (in bits, important for public key operations) and flags for this algorithm.
When you want to withdraw support for an algorithm, call crypto_unregister(). Two args: driver identifier and algorithm identifier, respectively. Classic use case: PCMCIA crypto cards being ejected will invoke this routine for all algorithms supported by the card. crypto_unregister_all() will unregister all algorithms registered by a driver and the driver will be disabled β no new sessions will be allocated on that driver, and any existing sessions will be migrated to other drivers. Same thing happens if all algorithms associated with a driver are unregistered one by one. After crypto_unregister_all() there will be no threads in either the newsession or freesession function of the driver. slay.
The calling convention for the driver-supplied routines:
int (*newsession)(device_t, crypto_session_t, struct cryptoini *);
void (*freesession)(device_t, crypto_session_t);
int (*process)(device_t, struct cryptop *, int);
int (*kprocess)(device_t, struct cryptkop *, int);
On invocation, the first argument to all routines is the device_t that was provided to crypto_get_driverid(). The second argument to newsession() is the opaque session handle for the new session. The third argument is identical to that of crypto_newsession().
Drivers get a pointer to their session memory by invoking crypto_get_driver_session() on the opaque crypto_session_t handle.
freesession() takes as arguments the opaque data value and the session handle. It should clear any context associated with the session (clear hardware registers, memory, etc.). If no resources need to be released other than the contents of session memory, the method is optional. The crypto framework will zero and release the allocated session memory (after running the freesession() method, if one exists).
process() is invoked with a request to perform crypto processing. This routine must not block or sleep. Instead, it should queue the request and return immediately, or process the request to completion. If there's an unrecoverable error, the error indication must be placed in the crp_etype field of the cryptop structure. When the request is completed, or an error is detected, process() must invoke crypto_done(). Session migration may be performed, as mentioned previously.
If you hit temporary resource exhaustion, process() may return ERESTART. In that case the crypto services will requeue the request, mark the driver as βblockedβ, and stop submitting requests for processing. Then the driver is responsible for notifying the crypto services when it is again able to process requests, through the crypto_unblock() routine. This simple flow control mechanism should only be used for short-lived resource exhaustion because it causes operations to be queued in the crypto layer. Doing so is preferable to returning an error in such cases, since that can cause network protocols to degrade performance by treating the failure much like a lost packet. no cap.
kprocess() is invoked with a request to perform crypto key processing. This routine must not block, but should queue the request and return immediately. Upon processing the request, the callback routine should be invoked. If there's an unrecoverable error, the error indication must be placed in the krp_status field of the cryptkop structure. When the request is completed, or an error is detected, kprocess() should invoke crypto_kdone(). π
π¦ RETURN VALUES π¦
crypto_register(), crypto_kregister(), crypto_unregister(), crypto_newsession(), crypto_freesession(), and crypto_unblock() return 0 on success, or an error code on failure. crypto_get_driverid() returns a non-negative value on error, and -1 on failure. crypto_getreq() returns a pointer to a cryptop structure and NULL on failure. crypto_dispatch() returns EINVAL if its argument or the callback function was NULL, and 0 otherwise. The callback is provided with an error code in case of failure, in the crp_etype field. okurrr.
π FILES π
sys/opencrypto/crypto.cβ most of the framework code
π SEE ALSO π
crypto(4), ipsec(4), crypto(7), malloc(9), sleep(9)
π HISTORY π
The cryptographic framework first appeared in OpenBSD 2.7 and was written by Angelos D. Keromytis <angelos@openbsd.org>.
π BUGS π
The framework currently assumes that all the algorithms in a crypto_newsession() operation must be available by the same driver. If that is not the case, session initialization will fail.
The framework also needs a mechanism for determining which driver is best for a specific set of algorithms associated with a session. Some type of benchmarking is in order here.
Multiple instances of the same algorithm in the same session are not supported.
mwah π this page came from Debian, dated December 17, 2019, and it's the CRYPTO(9) manual. bye bestie, go write an iconic driver! π«Ά
π¦ where this page comes from
- debian bookworm: freebsd-manpages 12.2-1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- debian trixie: freebsd-manpages 12.2-2 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- ubuntu jammy: freebsd-manpages 12.2-1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- ubuntu noble: freebsd-manpages 12.2-1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- ubuntu questing: freebsd-manpages 12.2-2
- ubuntu resolute: freebsd-manpages 12.2-2build1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- ubuntu stonking: freebsd-manpages 12.2-2build1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- Copyright (c) 2000, 2001 Angelos D. Keromytis
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms