Documentation / crypto / devel-algos.rst


Based on kernel version 5.11. Page generated on 2021-02-15 21:59 EST.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
Developing Cipher Algorithms
============================

Registering And Unregistering Transformation
--------------------------------------------

There are three distinct types of registration functions in the Crypto
API. One is used to register a generic cryptographic transformation,
while the other two are specific to HASH transformations and
COMPRESSion. We will discuss the latter two in a separate chapter, here
we will only look at the generic ones.

Before discussing the register functions, the data structure to be
filled with each, struct crypto_alg, must be considered -- see below
for a description of this data structure.

The generic registration functions can be found in
include/linux/crypto.h and their definition can be seen below. The
former function registers a single transformation, while the latter
works on an array of transformation descriptions. The latter is useful
when registering transformations in bulk, for example when a driver
implements multiple transformations.

::

       int crypto_register_alg(struct crypto_alg *alg);
       int crypto_register_algs(struct crypto_alg *algs, int count);


The counterparts to those functions are listed below.

::

       void crypto_unregister_alg(struct crypto_alg *alg);
       void crypto_unregister_algs(struct crypto_alg *algs, int count);


The registration functions return 0 on success, or a negative errno
value on failure.  crypto_register_algs() succeeds only if it
successfully registered all the given algorithms; if it fails partway
through, then any changes are rolled back.

The unregistration functions always succeed, so they don't have a
return value.  Don't try to unregister algorithms that aren't
currently registered.

Single-Block Symmetric Ciphers [CIPHER]
---------------------------------------

Example of transformations: aes, serpent, ...

This section describes the simplest of all transformation
implementations, that being the CIPHER type used for symmetric ciphers.
The CIPHER type is used for transformations which operate on exactly one
block at a time and there are no dependencies between blocks at all.

Registration specifics
~~~~~~~~~~~~~~~~~~~~~~

The registration of [CIPHER] algorithm is specific in that struct
crypto_alg field .cra_type is empty. The .cra_u.cipher has to be
filled in with proper callbacks to implement this transformation.

See struct cipher_alg below.

Cipher Definition With struct cipher_alg
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Struct cipher_alg defines a single block cipher.

Here are schematics of how these functions are called when operated from
other part of the kernel. Note that the .cia_setkey() call might happen
before or after any of these schematics happen, but must not happen
during any of these are in-flight.

::

             KEY ---.    PLAINTEXT ---.
                    v                 v
              .cia_setkey() -> .cia_encrypt()
                                      |
                                      '-----> CIPHERTEXT


Please note that a pattern where .cia_setkey() is called multiple times
is also valid:

::


      KEY1 --.    PLAINTEXT1 --.         KEY2 --.    PLAINTEXT2 --.
             v                 v                v                 v
       .cia_setkey() -> .cia_encrypt() -> .cia_setkey() -> .cia_encrypt()
                               |                                  |
                               '---> CIPHERTEXT1                  '---> CIPHERTEXT2


Multi-Block Ciphers
-------------------

Example of transformations: cbc(aes), chacha20, ...

This section describes the multi-block cipher transformation
implementations. The multi-block ciphers are used for transformations
which operate on scatterlists of data supplied to the transformation
functions. They output the result into a scatterlist of data as well.

Registration Specifics
~~~~~~~~~~~~~~~~~~~~~~

The registration of multi-block cipher algorithms is one of the most
standard procedures throughout the crypto API.

Note, if a cipher implementation requires a proper alignment of data,
the caller should use the functions of crypto_skcipher_alignmask() to
identify a memory alignment mask. The kernel crypto API is able to
process requests that are unaligned. This implies, however, additional
overhead as the kernel crypto API needs to perform the realignment of
the data which may imply moving of data.

Cipher Definition With struct skcipher_alg
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Struct skcipher_alg defines a multi-block cipher, or more generally, a
length-preserving symmetric cipher algorithm.

Scatterlist handling
~~~~~~~~~~~~~~~~~~~~

Some drivers will want to use the Generic ScatterWalk in case the
hardware needs to be fed separate chunks of the scatterlist which
contains the plaintext and will contain the ciphertext. Please refer
to the ScatterWalk interface offered by the Linux kernel scatter /
gather list implementation.

Hashing [HASH]
--------------

Example of transformations: crc32, md5, sha1, sha256,...

Registering And Unregistering The Transformation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

There are multiple ways to register a HASH transformation, depending on
whether the transformation is synchronous [SHASH] or asynchronous
[AHASH] and the amount of HASH transformations we are registering. You
can find the prototypes defined in include/crypto/internal/hash.h:

::

       int crypto_register_ahash(struct ahash_alg *alg);

       int crypto_register_shash(struct shash_alg *alg);
       int crypto_register_shashes(struct shash_alg *algs, int count);


The respective counterparts for unregistering the HASH transformation
are as follows:

::

       void crypto_unregister_ahash(struct ahash_alg *alg);

       void crypto_unregister_shash(struct shash_alg *alg);
       void crypto_unregister_shashes(struct shash_alg *algs, int count);


Cipher Definition With struct shash_alg and ahash_alg
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Here are schematics of how these functions are called when operated from
other part of the kernel. Note that the .setkey() call might happen
before or after any of these schematics happen, but must not happen
during any of these are in-flight. Please note that calling .init()
followed immediately by .finish() is also a perfectly valid
transformation.

::

       I)   DATA -----------.
                            v
             .init() -> .update() -> .final()      ! .update() might not be called
                         ^    |         |            at all in this scenario.
                         '----'         '---> HASH

       II)  DATA -----------.-----------.
                            v           v
             .init() -> .update() -> .finup()      ! .update() may not be called
                         ^    |         |            at all in this scenario.
                         '----'         '---> HASH

       III) DATA -----------.
                            v
                        .digest()                  ! The entire process is handled
                            |                        by the .digest() call.
                            '---------------> HASH


Here is a schematic of how the .export()/.import() functions are called
when used from another part of the kernel.

::

       KEY--.                 DATA--.
            v                       v                  ! .update() may not be called
        .setkey() -> .init() -> .update() -> .export()   at all in this scenario.
                                 ^     |         |
                                 '-----'         '--> PARTIAL_HASH

       ----------- other transformations happen here -----------

       PARTIAL_HASH--.   DATA1--.
                     v          v
                 .import -> .update() -> .final()     ! .update() may not be called
                             ^    |         |           at all in this scenario.
                             '----'         '--> HASH1

       PARTIAL_HASH--.   DATA2-.
                     v         v
                 .import -> .finup()
                               |
                               '---------------> HASH2

Note that it is perfectly legal to "abandon" a request object:
- call .init() and then (as many times) .update()
- _not_ call any of .final(), .finup() or .export() at any point in future

In other words implementations should mind the resource allocation and clean-up.
No resources related to request objects should remain allocated after a call
to .init() or .update(), since there might be no chance to free them.


Specifics Of Asynchronous HASH Transformation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Some of the drivers will want to use the Generic ScatterWalk in case the
implementation needs to be fed separate chunks of the scatterlist which
contains the input data. The buffer containing the resulting hash will
always be properly aligned to .cra_alignmask so there is no need to
worry about this.