2 * CBC: Cipher Block Chaining mode
4 * Copyright (c) 2016 Herbert Xu <herbert@gondor.apana.org.au>
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
16 #include <crypto/internal/skcipher.h>
17 #include <linux/string.h>
18 #include <linux/types.h>
20 static inline int crypto_cbc_encrypt_segment(
21 struct skcipher_walk
*walk
, struct crypto_skcipher
*tfm
,
22 void (*fn
)(struct crypto_skcipher
*, const u8
*, u8
*))
24 unsigned int bsize
= crypto_skcipher_blocksize(tfm
);
25 unsigned int nbytes
= walk
->nbytes
;
26 u8
*src
= walk
->src
.virt
.addr
;
27 u8
*dst
= walk
->dst
.virt
.addr
;
31 crypto_xor(iv
, src
, bsize
);
33 memcpy(iv
, dst
, bsize
);
37 } while ((nbytes
-= bsize
) >= bsize
);
42 static inline int crypto_cbc_encrypt_inplace(
43 struct skcipher_walk
*walk
, struct crypto_skcipher
*tfm
,
44 void (*fn
)(struct crypto_skcipher
*, const u8
*, u8
*))
46 unsigned int bsize
= crypto_skcipher_blocksize(tfm
);
47 unsigned int nbytes
= walk
->nbytes
;
48 u8
*src
= walk
->src
.virt
.addr
;
52 crypto_xor(src
, iv
, bsize
);
57 } while ((nbytes
-= bsize
) >= bsize
);
59 memcpy(walk
->iv
, iv
, bsize
);
64 static inline int crypto_cbc_encrypt_walk(struct skcipher_request
*req
,
65 void (*fn
)(struct crypto_skcipher
*,
68 struct crypto_skcipher
*tfm
= crypto_skcipher_reqtfm(req
);
69 struct skcipher_walk walk
;
72 err
= skcipher_walk_virt(&walk
, req
, false);
75 if (walk
.src
.virt
.addr
== walk
.dst
.virt
.addr
)
76 err
= crypto_cbc_encrypt_inplace(&walk
, tfm
, fn
);
78 err
= crypto_cbc_encrypt_segment(&walk
, tfm
, fn
);
79 err
= skcipher_walk_done(&walk
, err
);
85 static inline int crypto_cbc_decrypt_segment(
86 struct skcipher_walk
*walk
, struct crypto_skcipher
*tfm
,
87 void (*fn
)(struct crypto_skcipher
*, const u8
*, u8
*))
89 unsigned int bsize
= crypto_skcipher_blocksize(tfm
);
90 unsigned int nbytes
= walk
->nbytes
;
91 u8
*src
= walk
->src
.virt
.addr
;
92 u8
*dst
= walk
->dst
.virt
.addr
;
97 crypto_xor(dst
, iv
, bsize
);
102 } while ((nbytes
-= bsize
) >= bsize
);
104 memcpy(walk
->iv
, iv
, bsize
);
109 static inline int crypto_cbc_decrypt_inplace(
110 struct skcipher_walk
*walk
, struct crypto_skcipher
*tfm
,
111 void (*fn
)(struct crypto_skcipher
*, const u8
*, u8
*))
113 unsigned int bsize
= crypto_skcipher_blocksize(tfm
);
114 unsigned int nbytes
= walk
->nbytes
;
115 u8
*src
= walk
->src
.virt
.addr
;
118 /* Start of the last block. */
119 src
+= nbytes
- (nbytes
& (bsize
- 1)) - bsize
;
120 memcpy(last_iv
, src
, bsize
);
124 if ((nbytes
-= bsize
) < bsize
)
126 crypto_xor(src
, src
- bsize
, bsize
);
130 crypto_xor(src
, walk
->iv
, bsize
);
131 memcpy(walk
->iv
, last_iv
, bsize
);
136 static inline int crypto_cbc_decrypt_blocks(
137 struct skcipher_walk
*walk
, struct crypto_skcipher
*tfm
,
138 void (*fn
)(struct crypto_skcipher
*, const u8
*, u8
*))
140 if (walk
->src
.virt
.addr
== walk
->dst
.virt
.addr
)
141 return crypto_cbc_decrypt_inplace(walk
, tfm
, fn
);
143 return crypto_cbc_decrypt_segment(walk
, tfm
, fn
);
146 #endif /* _CRYPTO_CBC_H */