]>
Commit | Line | Data |
---|---|---|
049359d6 JH |
1 | /** |
2 | * AMCC SoC PPC4xx Crypto Driver | |
3 | * | |
4 | * Copyright (c) 2008 Applied Micro Circuits Corporation. | |
5 | * All rights reserved. James Hsiao <[email protected]> | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License as published by | |
9 | * the Free Software Foundation; either version 2 of the License, or | |
10 | * (at your option) any later version. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | * GNU General Public License for more details. | |
16 | * | |
17 | * This file implements the Linux crypto algorithms. | |
18 | */ | |
19 | ||
20 | #include <linux/kernel.h> | |
21 | #include <linux/interrupt.h> | |
22 | #include <linux/spinlock_types.h> | |
23 | #include <linux/scatterlist.h> | |
24 | #include <linux/crypto.h> | |
25 | #include <linux/hash.h> | |
26 | #include <crypto/internal/hash.h> | |
27 | #include <linux/dma-mapping.h> | |
28 | #include <crypto/algapi.h> | |
29 | #include <crypto/aes.h> | |
30 | #include <crypto/sha.h> | |
31 | #include "crypto4xx_reg_def.h" | |
32 | #include "crypto4xx_sa.h" | |
33 | #include "crypto4xx_core.h" | |
34 | ||
3a4eac79 JH |
35 | static void set_dynamic_sa_command_0(struct dynamic_sa_ctl *sa, u32 save_h, |
36 | u32 save_iv, u32 ld_h, u32 ld_iv, | |
37 | u32 hdr_proc, u32 h, u32 c, u32 pad_type, | |
38 | u32 op_grp, u32 op, u32 dir) | |
049359d6 JH |
39 | { |
40 | sa->sa_command_0.w = 0; | |
41 | sa->sa_command_0.bf.save_hash_state = save_h; | |
42 | sa->sa_command_0.bf.save_iv = save_iv; | |
43 | sa->sa_command_0.bf.load_hash_state = ld_h; | |
44 | sa->sa_command_0.bf.load_iv = ld_iv; | |
45 | sa->sa_command_0.bf.hdr_proc = hdr_proc; | |
46 | sa->sa_command_0.bf.hash_alg = h; | |
47 | sa->sa_command_0.bf.cipher_alg = c; | |
48 | sa->sa_command_0.bf.pad_type = pad_type & 3; | |
49 | sa->sa_command_0.bf.extend_pad = pad_type >> 2; | |
50 | sa->sa_command_0.bf.op_group = op_grp; | |
51 | sa->sa_command_0.bf.opcode = op; | |
52 | sa->sa_command_0.bf.dir = dir; | |
53 | } | |
54 | ||
3a4eac79 JH |
55 | static void set_dynamic_sa_command_1(struct dynamic_sa_ctl *sa, u32 cm, |
56 | u32 hmac_mc, u32 cfb, u32 esn, | |
57 | u32 sn_mask, u32 mute, u32 cp_pad, | |
58 | u32 cp_pay, u32 cp_hdr) | |
049359d6 JH |
59 | { |
60 | sa->sa_command_1.w = 0; | |
61 | sa->sa_command_1.bf.crypto_mode31 = (cm & 4) >> 2; | |
62 | sa->sa_command_1.bf.crypto_mode9_8 = cm & 3; | |
63 | sa->sa_command_1.bf.feedback_mode = cfb, | |
64 | sa->sa_command_1.bf.sa_rev = 1; | |
65 | sa->sa_command_1.bf.extended_seq_num = esn; | |
66 | sa->sa_command_1.bf.seq_num_mask = sn_mask; | |
67 | sa->sa_command_1.bf.mutable_bit_proc = mute; | |
68 | sa->sa_command_1.bf.copy_pad = cp_pad; | |
69 | sa->sa_command_1.bf.copy_payload = cp_pay; | |
70 | sa->sa_command_1.bf.copy_hdr = cp_hdr; | |
71 | } | |
72 | ||
73 | int crypto4xx_encrypt(struct ablkcipher_request *req) | |
74 | { | |
75 | struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm); | |
76 | ||
77 | ctx->direction = DIR_OUTBOUND; | |
78 | ctx->hash_final = 0; | |
79 | ctx->is_hash = 0; | |
80 | ctx->pd_ctl = 0x1; | |
81 | ||
82 | return crypto4xx_build_pd(&req->base, ctx, req->src, req->dst, | |
83 | req->nbytes, req->info, | |
84 | get_dynamic_sa_iv_size(ctx)); | |
85 | } | |
86 | ||
87 | int crypto4xx_decrypt(struct ablkcipher_request *req) | |
88 | { | |
89 | struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm); | |
90 | ||
91 | ctx->direction = DIR_INBOUND; | |
92 | ctx->hash_final = 0; | |
93 | ctx->is_hash = 0; | |
94 | ctx->pd_ctl = 1; | |
95 | ||
96 | return crypto4xx_build_pd(&req->base, ctx, req->src, req->dst, | |
97 | req->nbytes, req->info, | |
98 | get_dynamic_sa_iv_size(ctx)); | |
99 | } | |
100 | ||
101 | /** | |
102 | * AES Functions | |
103 | */ | |
104 | static int crypto4xx_setkey_aes(struct crypto_ablkcipher *cipher, | |
105 | const u8 *key, | |
106 | unsigned int keylen, | |
107 | unsigned char cm, | |
108 | u8 fb) | |
109 | { | |
110 | struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher); | |
111 | struct crypto4xx_ctx *ctx = crypto_tfm_ctx(tfm); | |
112 | struct dynamic_sa_ctl *sa; | |
113 | int rc; | |
114 | ||
115 | if (keylen != AES_KEYSIZE_256 && | |
116 | keylen != AES_KEYSIZE_192 && keylen != AES_KEYSIZE_128) { | |
117 | crypto_ablkcipher_set_flags(cipher, | |
118 | CRYPTO_TFM_RES_BAD_KEY_LEN); | |
119 | return -EINVAL; | |
120 | } | |
121 | ||
122 | /* Create SA */ | |
123 | if (ctx->sa_in_dma_addr || ctx->sa_out_dma_addr) | |
124 | crypto4xx_free_sa(ctx); | |
125 | ||
126 | rc = crypto4xx_alloc_sa(ctx, SA_AES128_LEN + (keylen-16) / 4); | |
127 | if (rc) | |
128 | return rc; | |
129 | ||
130 | if (ctx->state_record_dma_addr == 0) { | |
131 | rc = crypto4xx_alloc_state_record(ctx); | |
132 | if (rc) { | |
133 | crypto4xx_free_sa(ctx); | |
134 | return rc; | |
135 | } | |
136 | } | |
137 | /* Setup SA */ | |
138 | sa = (struct dynamic_sa_ctl *) ctx->sa_in; | |
139 | ctx->hash_final = 0; | |
140 | ||
141 | set_dynamic_sa_command_0(sa, SA_NOT_SAVE_HASH, SA_NOT_SAVE_IV, | |
142 | SA_LOAD_HASH_FROM_SA, SA_LOAD_IV_FROM_STATE, | |
143 | SA_NO_HEADER_PROC, SA_HASH_ALG_NULL, | |
144 | SA_CIPHER_ALG_AES, SA_PAD_TYPE_ZERO, | |
145 | SA_OP_GROUP_BASIC, SA_OPCODE_DECRYPT, | |
146 | DIR_INBOUND); | |
147 | ||
148 | set_dynamic_sa_command_1(sa, cm, SA_HASH_MODE_HASH, | |
149 | fb, SA_EXTENDED_SN_OFF, | |
150 | SA_SEQ_MASK_OFF, SA_MC_ENABLE, | |
151 | SA_NOT_COPY_PAD, SA_NOT_COPY_PAYLOAD, | |
152 | SA_NOT_COPY_HDR); | |
153 | crypto4xx_memcpy_le(ctx->sa_in + get_dynamic_sa_offset_key_field(ctx), | |
154 | key, keylen); | |
155 | sa->sa_contents = SA_AES_CONTENTS | (keylen << 2); | |
156 | sa->sa_command_1.bf.key_len = keylen >> 3; | |
157 | ctx->is_hash = 0; | |
158 | ctx->direction = DIR_INBOUND; | |
159 | memcpy(ctx->sa_in + get_dynamic_sa_offset_state_ptr_field(ctx), | |
160 | (void *)&ctx->state_record_dma_addr, 4); | |
161 | ctx->offset_to_sr_ptr = get_dynamic_sa_offset_state_ptr_field(ctx); | |
162 | ||
163 | memcpy(ctx->sa_out, ctx->sa_in, ctx->sa_len * 4); | |
164 | sa = (struct dynamic_sa_ctl *) ctx->sa_out; | |
165 | sa->sa_command_0.bf.dir = DIR_OUTBOUND; | |
166 | ||
167 | return 0; | |
168 | } | |
169 | ||
170 | int crypto4xx_setkey_aes_cbc(struct crypto_ablkcipher *cipher, | |
171 | const u8 *key, unsigned int keylen) | |
172 | { | |
173 | return crypto4xx_setkey_aes(cipher, key, keylen, CRYPTO_MODE_CBC, | |
174 | CRYPTO_FEEDBACK_MODE_NO_FB); | |
175 | } | |
176 | ||
177 | /** | |
178 | * HASH SHA1 Functions | |
179 | */ | |
180 | static int crypto4xx_hash_alg_init(struct crypto_tfm *tfm, | |
181 | unsigned int sa_len, | |
182 | unsigned char ha, | |
183 | unsigned char hm) | |
184 | { | |
185 | struct crypto_alg *alg = tfm->__crt_alg; | |
186 | struct crypto4xx_alg *my_alg = crypto_alg_to_crypto4xx_alg(alg); | |
187 | struct crypto4xx_ctx *ctx = crypto_tfm_ctx(tfm); | |
188 | struct dynamic_sa_ctl *sa; | |
189 | struct dynamic_sa_hash160 *sa_in; | |
190 | int rc; | |
191 | ||
192 | ctx->dev = my_alg->dev; | |
193 | ctx->is_hash = 1; | |
194 | ctx->hash_final = 0; | |
195 | ||
196 | /* Create SA */ | |
197 | if (ctx->sa_in_dma_addr || ctx->sa_out_dma_addr) | |
198 | crypto4xx_free_sa(ctx); | |
199 | ||
200 | rc = crypto4xx_alloc_sa(ctx, sa_len); | |
201 | if (rc) | |
202 | return rc; | |
203 | ||
204 | if (ctx->state_record_dma_addr == 0) { | |
205 | crypto4xx_alloc_state_record(ctx); | |
206 | if (!ctx->state_record_dma_addr) { | |
207 | crypto4xx_free_sa(ctx); | |
208 | return -ENOMEM; | |
209 | } | |
210 | } | |
211 | ||
6b1679f4 HX |
212 | crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), |
213 | sizeof(struct crypto4xx_ctx)); | |
049359d6 JH |
214 | sa = (struct dynamic_sa_ctl *) ctx->sa_in; |
215 | set_dynamic_sa_command_0(sa, SA_SAVE_HASH, SA_NOT_SAVE_IV, | |
216 | SA_NOT_LOAD_HASH, SA_LOAD_IV_FROM_SA, | |
217 | SA_NO_HEADER_PROC, ha, SA_CIPHER_ALG_NULL, | |
218 | SA_PAD_TYPE_ZERO, SA_OP_GROUP_BASIC, | |
219 | SA_OPCODE_HASH, DIR_INBOUND); | |
220 | set_dynamic_sa_command_1(sa, 0, SA_HASH_MODE_HASH, | |
221 | CRYPTO_FEEDBACK_MODE_NO_FB, SA_EXTENDED_SN_OFF, | |
222 | SA_SEQ_MASK_OFF, SA_MC_ENABLE, | |
223 | SA_NOT_COPY_PAD, SA_NOT_COPY_PAYLOAD, | |
224 | SA_NOT_COPY_HDR); | |
225 | ctx->direction = DIR_INBOUND; | |
226 | sa->sa_contents = SA_HASH160_CONTENTS; | |
227 | sa_in = (struct dynamic_sa_hash160 *) ctx->sa_in; | |
228 | /* Need to zero hash digest in SA */ | |
229 | memset(sa_in->inner_digest, 0, sizeof(sa_in->inner_digest)); | |
230 | memset(sa_in->outer_digest, 0, sizeof(sa_in->outer_digest)); | |
231 | sa_in->state_ptr = ctx->state_record_dma_addr; | |
232 | ctx->offset_to_sr_ptr = get_dynamic_sa_offset_state_ptr_field(ctx); | |
233 | ||
234 | return 0; | |
235 | } | |
236 | ||
237 | int crypto4xx_hash_init(struct ahash_request *req) | |
238 | { | |
239 | struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm); | |
240 | int ds; | |
241 | struct dynamic_sa_ctl *sa; | |
242 | ||
243 | sa = (struct dynamic_sa_ctl *) ctx->sa_in; | |
244 | ds = crypto_ahash_digestsize( | |
245 | __crypto_ahash_cast(req->base.tfm)); | |
246 | sa->sa_command_0.bf.digest_len = ds >> 2; | |
247 | sa->sa_command_0.bf.load_hash_state = SA_LOAD_HASH_FROM_SA; | |
248 | ctx->is_hash = 1; | |
249 | ctx->direction = DIR_INBOUND; | |
250 | ||
251 | return 0; | |
252 | } | |
253 | ||
254 | int crypto4xx_hash_update(struct ahash_request *req) | |
255 | { | |
256 | struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm); | |
257 | ||
258 | ctx->is_hash = 1; | |
259 | ctx->hash_final = 0; | |
260 | ctx->pd_ctl = 0x11; | |
261 | ctx->direction = DIR_INBOUND; | |
262 | ||
263 | return crypto4xx_build_pd(&req->base, ctx, req->src, | |
264 | (struct scatterlist *) req->result, | |
265 | req->nbytes, NULL, 0); | |
266 | } | |
267 | ||
268 | int crypto4xx_hash_final(struct ahash_request *req) | |
269 | { | |
270 | return 0; | |
271 | } | |
272 | ||
273 | int crypto4xx_hash_digest(struct ahash_request *req) | |
274 | { | |
275 | struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm); | |
276 | ||
277 | ctx->hash_final = 1; | |
278 | ctx->pd_ctl = 0x11; | |
279 | ctx->direction = DIR_INBOUND; | |
280 | ||
281 | return crypto4xx_build_pd(&req->base, ctx, req->src, | |
282 | (struct scatterlist *) req->result, | |
283 | req->nbytes, NULL, 0); | |
284 | } | |
285 | ||
286 | /** | |
287 | * SHA1 Algorithm | |
288 | */ | |
289 | int crypto4xx_sha1_alg_init(struct crypto_tfm *tfm) | |
290 | { | |
291 | return crypto4xx_hash_alg_init(tfm, SA_HASH160_LEN, SA_HASH_ALG_SHA1, | |
292 | SA_HASH_MODE_HASH); | |
293 | } | |
294 | ||
295 |