1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 * CBC: Cipher Block Chaining mode
5 * Copyright (c) 2016 Herbert Xu <herbert@gondor.apana.org.au>
11 #include <crypto/internal/skcipher.h>
12 #include <linux/string.h>
13 #include <linux/types.h>
15 static inline int crypto_cbc_encrypt_segment(
16 struct skcipher_walk
*walk
, struct crypto_skcipher
*tfm
,
17 void (*fn
)(struct crypto_skcipher
*, const u8
*, u8
*))
19 unsigned int bsize
= crypto_skcipher_blocksize(tfm
);
20 unsigned int nbytes
= walk
->nbytes
;
21 u8
*src
= walk
->src
.virt
.addr
;
22 u8
*dst
= walk
->dst
.virt
.addr
;
26 crypto_xor(iv
, src
, bsize
);
28 memcpy(iv
, dst
, bsize
);
32 } while ((nbytes
-= bsize
) >= bsize
);
37 static inline int crypto_cbc_encrypt_inplace(
38 struct skcipher_walk
*walk
, struct crypto_skcipher
*tfm
,
39 void (*fn
)(struct crypto_skcipher
*, const u8
*, u8
*))
41 unsigned int bsize
= crypto_skcipher_blocksize(tfm
);
42 unsigned int nbytes
= walk
->nbytes
;
43 u8
*src
= walk
->src
.virt
.addr
;
47 crypto_xor(src
, iv
, bsize
);
52 } while ((nbytes
-= bsize
) >= bsize
);
54 memcpy(walk
->iv
, iv
, bsize
);
59 static inline int crypto_cbc_encrypt_walk(struct skcipher_request
*req
,
60 void (*fn
)(struct crypto_skcipher
*,
63 struct crypto_skcipher
*tfm
= crypto_skcipher_reqtfm(req
);
64 struct skcipher_walk walk
;
67 err
= skcipher_walk_virt(&walk
, req
, false);
70 if (walk
.src
.virt
.addr
== walk
.dst
.virt
.addr
)
71 err
= crypto_cbc_encrypt_inplace(&walk
, tfm
, fn
);
73 err
= crypto_cbc_encrypt_segment(&walk
, tfm
, fn
);
74 err
= skcipher_walk_done(&walk
, err
);
80 static inline int crypto_cbc_decrypt_segment(
81 struct skcipher_walk
*walk
, struct crypto_skcipher
*tfm
,
82 void (*fn
)(struct crypto_skcipher
*, const u8
*, u8
*))
84 unsigned int bsize
= crypto_skcipher_blocksize(tfm
);
85 unsigned int nbytes
= walk
->nbytes
;
86 u8
*src
= walk
->src
.virt
.addr
;
87 u8
*dst
= walk
->dst
.virt
.addr
;
92 crypto_xor(dst
, iv
, bsize
);
97 } while ((nbytes
-= bsize
) >= bsize
);
99 memcpy(walk
->iv
, iv
, bsize
);
104 static inline int crypto_cbc_decrypt_inplace(
105 struct skcipher_walk
*walk
, struct crypto_skcipher
*tfm
,
106 void (*fn
)(struct crypto_skcipher
*, const u8
*, u8
*))
108 unsigned int bsize
= crypto_skcipher_blocksize(tfm
);
109 unsigned int nbytes
= walk
->nbytes
;
110 u8
*src
= walk
->src
.virt
.addr
;
111 u8 last_iv
[MAX_CIPHER_BLOCKSIZE
];
113 /* Start of the last block. */
114 src
+= nbytes
- (nbytes
& (bsize
- 1)) - bsize
;
115 memcpy(last_iv
, src
, bsize
);
119 if ((nbytes
-= bsize
) < bsize
)
121 crypto_xor(src
, src
- bsize
, bsize
);
125 crypto_xor(src
, walk
->iv
, bsize
);
126 memcpy(walk
->iv
, last_iv
, bsize
);
131 static inline int crypto_cbc_decrypt_blocks(
132 struct skcipher_walk
*walk
, struct crypto_skcipher
*tfm
,
133 void (*fn
)(struct crypto_skcipher
*, const u8
*, u8
*))
135 if (walk
->src
.virt
.addr
== walk
->dst
.virt
.addr
)
136 return crypto_cbc_decrypt_inplace(walk
, tfm
, fn
);
138 return crypto_cbc_decrypt_segment(walk
, tfm
, fn
);
141 #endif /* _CRYPTO_CBC_H */