1 // SPDX-License-Identifier: GPL-2.0-only
3 * AES XTS routines supporting VMX In-core instructions on Power 8
5 * Copyright (C) 2015 International Business Machines Inc.
7 * Author: Leonidas S. Barbosa <leosilva@linux.vnet.ibm.com>
11 #include <asm/switch_to.h>
12 #include <crypto/aes.h>
13 #include <crypto/internal/simd.h>
14 #include <crypto/internal/skcipher.h>
15 #include <crypto/xts.h>
17 #include "aesp8-ppc.h"
19 struct p8_aes_xts_ctx
{
20 struct crypto_skcipher
*fallback
;
21 struct aes_key enc_key
;
22 struct aes_key dec_key
;
23 struct aes_key tweak_key
;
26 static int p8_aes_xts_init(struct crypto_skcipher
*tfm
)
28 struct p8_aes_xts_ctx
*ctx
= crypto_skcipher_ctx(tfm
);
29 struct crypto_skcipher
*fallback
;
31 fallback
= crypto_alloc_skcipher("xts(aes)", 0,
32 CRYPTO_ALG_NEED_FALLBACK
|
34 if (IS_ERR(fallback
)) {
35 pr_err("Failed to allocate xts(aes) fallback: %ld\n",
37 return PTR_ERR(fallback
);
40 crypto_skcipher_set_reqsize(tfm
, sizeof(struct skcipher_request
) +
41 crypto_skcipher_reqsize(fallback
));
42 ctx
->fallback
= fallback
;
46 static void p8_aes_xts_exit(struct crypto_skcipher
*tfm
)
48 struct p8_aes_xts_ctx
*ctx
= crypto_skcipher_ctx(tfm
);
50 crypto_free_skcipher(ctx
->fallback
);
53 static int p8_aes_xts_setkey(struct crypto_skcipher
*tfm
, const u8
*key
,
56 struct p8_aes_xts_ctx
*ctx
= crypto_skcipher_ctx(tfm
);
59 ret
= xts_verify_key(tfm
, key
, keylen
);
66 ret
= aes_p8_set_encrypt_key(key
+ keylen
/2, (keylen
/2) * 8, &ctx
->tweak_key
);
67 ret
|= aes_p8_set_encrypt_key(key
, (keylen
/2) * 8, &ctx
->enc_key
);
68 ret
|= aes_p8_set_decrypt_key(key
, (keylen
/2) * 8, &ctx
->dec_key
);
73 ret
|= crypto_skcipher_setkey(ctx
->fallback
, key
, keylen
);
75 return ret
? -EINVAL
: 0;
78 static int p8_aes_xts_crypt(struct skcipher_request
*req
, int enc
)
80 struct crypto_skcipher
*tfm
= crypto_skcipher_reqtfm(req
);
81 const struct p8_aes_xts_ctx
*ctx
= crypto_skcipher_ctx(tfm
);
82 struct skcipher_walk walk
;
84 u8 tweak
[AES_BLOCK_SIZE
];
87 if (req
->cryptlen
< AES_BLOCK_SIZE
)
90 if (!crypto_simd_usable() || (req
->cryptlen
% XTS_BLOCK_SIZE
) != 0) {
91 struct skcipher_request
*subreq
= skcipher_request_ctx(req
);
94 skcipher_request_set_tfm(subreq
, ctx
->fallback
);
95 return enc
? crypto_skcipher_encrypt(subreq
) :
96 crypto_skcipher_decrypt(subreq
);
99 ret
= skcipher_walk_virt(&walk
, req
, false);
107 aes_p8_encrypt(walk
.iv
, tweak
, &ctx
->tweak_key
);
109 disable_kernel_vsx();
113 while ((nbytes
= walk
.nbytes
) != 0) {
118 aes_p8_xts_encrypt(walk
.src
.virt
.addr
,
120 round_down(nbytes
, AES_BLOCK_SIZE
),
121 &ctx
->enc_key
, NULL
, tweak
);
123 aes_p8_xts_decrypt(walk
.src
.virt
.addr
,
125 round_down(nbytes
, AES_BLOCK_SIZE
),
126 &ctx
->dec_key
, NULL
, tweak
);
127 disable_kernel_vsx();
131 ret
= skcipher_walk_done(&walk
, nbytes
% AES_BLOCK_SIZE
);
136 static int p8_aes_xts_encrypt(struct skcipher_request
*req
)
138 return p8_aes_xts_crypt(req
, 1);
141 static int p8_aes_xts_decrypt(struct skcipher_request
*req
)
143 return p8_aes_xts_crypt(req
, 0);
146 struct skcipher_alg p8_aes_xts_alg
= {
147 .base
.cra_name
= "xts(aes)",
148 .base
.cra_driver_name
= "p8_aes_xts",
149 .base
.cra_module
= THIS_MODULE
,
150 .base
.cra_priority
= 2000,
151 .base
.cra_flags
= CRYPTO_ALG_NEED_FALLBACK
,
152 .base
.cra_blocksize
= AES_BLOCK_SIZE
,
153 .base
.cra_ctxsize
= sizeof(struct p8_aes_xts_ctx
),
154 .setkey
= p8_aes_xts_setkey
,
155 .encrypt
= p8_aes_xts_encrypt
,
156 .decrypt
= p8_aes_xts_decrypt
,
157 .init
= p8_aes_xts_init
,
158 .exit
= p8_aes_xts_exit
,
159 .min_keysize
= 2 * AES_MIN_KEY_SIZE
,
160 .max_keysize
= 2 * AES_MAX_KEY_SIZE
,
161 .ivsize
= AES_BLOCK_SIZE
,