]>
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 <jhsiao@amcc.com> | |
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 | ||
35 | void set_dynamic_sa_command_0(struct dynamic_sa_ctl *sa, u32 save_h, | |
36 | u32 save_iv, u32 ld_h, u32 ld_iv, u32 hdr_proc, | |
37 | u32 h, u32 c, u32 pad_type, u32 op_grp, u32 op, | |
38 | u32 dir) | |
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 | ||
55 | void set_dynamic_sa_command_1(struct dynamic_sa_ctl *sa, u32 cm, u32 hmac_mc, | |
56 | u32 cfb, u32 esn, u32 sn_mask, u32 mute, | |
57 | u32 cp_pad, u32 cp_pay, u32 cp_hdr) | |
58 | { | |
59 | sa->sa_command_1.w = 0; | |
60 | sa->sa_command_1.bf.crypto_mode31 = (cm & 4) >> 2; | |
61 | sa->sa_command_1.bf.crypto_mode9_8 = cm & 3; | |
62 | sa->sa_command_1.bf.feedback_mode = cfb, | |
63 | sa->sa_command_1.bf.sa_rev = 1; | |
64 | sa->sa_command_1.bf.extended_seq_num = esn; | |
65 | sa->sa_command_1.bf.seq_num_mask = sn_mask; | |
66 | sa->sa_command_1.bf.mutable_bit_proc = mute; | |
67 | sa->sa_command_1.bf.copy_pad = cp_pad; | |
68 | sa->sa_command_1.bf.copy_payload = cp_pay; | |
69 | sa->sa_command_1.bf.copy_hdr = cp_hdr; | |
70 | } | |
71 | ||
72 | int crypto4xx_encrypt(struct ablkcipher_request *req) | |
73 | { | |
74 | struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm); | |
75 | ||
76 | ctx->direction = DIR_OUTBOUND; | |
77 | ctx->hash_final = 0; | |
78 | ctx->is_hash = 0; | |
79 | ctx->pd_ctl = 0x1; | |
80 | ||
81 | return crypto4xx_build_pd(&req->base, ctx, req->src, req->dst, | |
82 | req->nbytes, req->info, | |
83 | get_dynamic_sa_iv_size(ctx)); | |
84 | } | |
85 | ||
86 | int crypto4xx_decrypt(struct ablkcipher_request *req) | |
87 | { | |
88 | struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm); | |
89 | ||
90 | ctx->direction = DIR_INBOUND; | |
91 | ctx->hash_final = 0; | |
92 | ctx->is_hash = 0; | |
93 | ctx->pd_ctl = 1; | |
94 | ||
95 | return crypto4xx_build_pd(&req->base, ctx, req->src, req->dst, | |
96 | req->nbytes, req->info, | |
97 | get_dynamic_sa_iv_size(ctx)); | |
98 | } | |
99 | ||
100 | /** | |
101 | * AES Functions | |
102 | */ | |
103 | static int crypto4xx_setkey_aes(struct crypto_ablkcipher *cipher, | |
104 | const u8 *key, | |
105 | unsigned int keylen, | |
106 | unsigned char cm, | |
107 | u8 fb) | |
108 | { | |
109 | struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher); | |
110 | struct crypto4xx_ctx *ctx = crypto_tfm_ctx(tfm); | |
111 | struct dynamic_sa_ctl *sa; | |
112 | int rc; | |
113 | ||
114 | if (keylen != AES_KEYSIZE_256 && | |
115 | keylen != AES_KEYSIZE_192 && keylen != AES_KEYSIZE_128) { | |
116 | crypto_ablkcipher_set_flags(cipher, | |
117 | CRYPTO_TFM_RES_BAD_KEY_LEN); | |
118 | return -EINVAL; | |
119 | } | |
120 | ||
121 | /* Create SA */ | |
122 | if (ctx->sa_in_dma_addr || ctx->sa_out_dma_addr) | |
123 | crypto4xx_free_sa(ctx); | |
124 | ||
125 | rc = crypto4xx_alloc_sa(ctx, SA_AES128_LEN + (keylen-16) / 4); | |
126 | if (rc) | |
127 | return rc; | |
128 | ||
129 | if (ctx->state_record_dma_addr == 0) { | |
130 | rc = crypto4xx_alloc_state_record(ctx); | |
131 | if (rc) { | |
132 | crypto4xx_free_sa(ctx); | |
133 | return rc; | |
134 | } | |
135 | } | |
136 | /* Setup SA */ | |
137 | sa = (struct dynamic_sa_ctl *) ctx->sa_in; | |
138 | ctx->hash_final = 0; | |
139 | ||
140 | set_dynamic_sa_command_0(sa, SA_NOT_SAVE_HASH, SA_NOT_SAVE_IV, | |
141 | SA_LOAD_HASH_FROM_SA, SA_LOAD_IV_FROM_STATE, | |
142 | SA_NO_HEADER_PROC, SA_HASH_ALG_NULL, | |
143 | SA_CIPHER_ALG_AES, SA_PAD_TYPE_ZERO, | |
144 | SA_OP_GROUP_BASIC, SA_OPCODE_DECRYPT, | |
145 | DIR_INBOUND); | |
146 | ||
147 | set_dynamic_sa_command_1(sa, cm, SA_HASH_MODE_HASH, | |
148 | fb, SA_EXTENDED_SN_OFF, | |
149 | SA_SEQ_MASK_OFF, SA_MC_ENABLE, | |
150 | SA_NOT_COPY_PAD, SA_NOT_COPY_PAYLOAD, | |
151 | SA_NOT_COPY_HDR); | |
152 | crypto4xx_memcpy_le(ctx->sa_in + get_dynamic_sa_offset_key_field(ctx), | |
153 | key, keylen); | |
154 | sa->sa_contents = SA_AES_CONTENTS | (keylen << 2); | |
155 | sa->sa_command_1.bf.key_len = keylen >> 3; | |
156 | ctx->is_hash = 0; | |
157 | ctx->direction = DIR_INBOUND; | |
158 | memcpy(ctx->sa_in + get_dynamic_sa_offset_state_ptr_field(ctx), | |
159 | (void *)&ctx->state_record_dma_addr, 4); | |
160 | ctx->offset_to_sr_ptr = get_dynamic_sa_offset_state_ptr_field(ctx); | |
161 | ||
162 | memcpy(ctx->sa_out, ctx->sa_in, ctx->sa_len * 4); | |
163 | sa = (struct dynamic_sa_ctl *) ctx->sa_out; | |
164 | sa->sa_command_0.bf.dir = DIR_OUTBOUND; | |
165 | ||
166 | return 0; | |
167 | } | |
168 | ||
169 | int crypto4xx_setkey_aes_cbc(struct crypto_ablkcipher *cipher, | |
170 | const u8 *key, unsigned int keylen) | |
171 | { | |
172 | return crypto4xx_setkey_aes(cipher, key, keylen, CRYPTO_MODE_CBC, | |
173 | CRYPTO_FEEDBACK_MODE_NO_FB); | |
174 | } | |
175 | ||
176 | /** | |
177 | * HASH SHA1 Functions | |
178 | */ | |
179 | static int crypto4xx_hash_alg_init(struct crypto_tfm *tfm, | |
180 | unsigned int sa_len, | |
181 | unsigned char ha, | |
182 | unsigned char hm) | |
183 | { | |
184 | struct crypto_alg *alg = tfm->__crt_alg; | |
185 | struct crypto4xx_alg *my_alg = crypto_alg_to_crypto4xx_alg(alg); | |
186 | struct crypto4xx_ctx *ctx = crypto_tfm_ctx(tfm); | |
187 | struct dynamic_sa_ctl *sa; | |
188 | struct dynamic_sa_hash160 *sa_in; | |
189 | int rc; | |
190 | ||
191 | ctx->dev = my_alg->dev; | |
192 | ctx->is_hash = 1; | |
193 | ctx->hash_final = 0; | |
194 | ||
195 | /* Create SA */ | |
196 | if (ctx->sa_in_dma_addr || ctx->sa_out_dma_addr) | |
197 | crypto4xx_free_sa(ctx); | |
198 | ||
199 | rc = crypto4xx_alloc_sa(ctx, sa_len); | |
200 | if (rc) | |
201 | return rc; | |
202 | ||
203 | if (ctx->state_record_dma_addr == 0) { | |
204 | crypto4xx_alloc_state_record(ctx); | |
205 | if (!ctx->state_record_dma_addr) { | |
206 | crypto4xx_free_sa(ctx); | |
207 | return -ENOMEM; | |
208 | } | |
209 | } | |
210 | ||
6b1679f4 HX |
211 | crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), |
212 | sizeof(struct crypto4xx_ctx)); | |
049359d6 JH |
213 | sa = (struct dynamic_sa_ctl *) ctx->sa_in; |
214 | set_dynamic_sa_command_0(sa, SA_SAVE_HASH, SA_NOT_SAVE_IV, | |
215 | SA_NOT_LOAD_HASH, SA_LOAD_IV_FROM_SA, | |
216 | SA_NO_HEADER_PROC, ha, SA_CIPHER_ALG_NULL, | |
217 | SA_PAD_TYPE_ZERO, SA_OP_GROUP_BASIC, | |
218 | SA_OPCODE_HASH, DIR_INBOUND); | |
219 | set_dynamic_sa_command_1(sa, 0, SA_HASH_MODE_HASH, | |
220 | CRYPTO_FEEDBACK_MODE_NO_FB, SA_EXTENDED_SN_OFF, | |
221 | SA_SEQ_MASK_OFF, SA_MC_ENABLE, | |
222 | SA_NOT_COPY_PAD, SA_NOT_COPY_PAYLOAD, | |
223 | SA_NOT_COPY_HDR); | |
224 | ctx->direction = DIR_INBOUND; | |
225 | sa->sa_contents = SA_HASH160_CONTENTS; | |
226 | sa_in = (struct dynamic_sa_hash160 *) ctx->sa_in; | |
227 | /* Need to zero hash digest in SA */ | |
228 | memset(sa_in->inner_digest, 0, sizeof(sa_in->inner_digest)); | |
229 | memset(sa_in->outer_digest, 0, sizeof(sa_in->outer_digest)); | |
230 | sa_in->state_ptr = ctx->state_record_dma_addr; | |
231 | ctx->offset_to_sr_ptr = get_dynamic_sa_offset_state_ptr_field(ctx); | |
232 | ||
233 | return 0; | |
234 | } | |
235 | ||
236 | int crypto4xx_hash_init(struct ahash_request *req) | |
237 | { | |
238 | struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm); | |
239 | int ds; | |
240 | struct dynamic_sa_ctl *sa; | |
241 | ||
242 | sa = (struct dynamic_sa_ctl *) ctx->sa_in; | |
243 | ds = crypto_ahash_digestsize( | |
244 | __crypto_ahash_cast(req->base.tfm)); | |
245 | sa->sa_command_0.bf.digest_len = ds >> 2; | |
246 | sa->sa_command_0.bf.load_hash_state = SA_LOAD_HASH_FROM_SA; | |
247 | ctx->is_hash = 1; | |
248 | ctx->direction = DIR_INBOUND; | |
249 | ||
250 | return 0; | |
251 | } | |
252 | ||
253 | int crypto4xx_hash_update(struct ahash_request *req) | |
254 | { | |
255 | struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm); | |
256 | ||
257 | ctx->is_hash = 1; | |
258 | ctx->hash_final = 0; | |
259 | ctx->pd_ctl = 0x11; | |
260 | ctx->direction = DIR_INBOUND; | |
261 | ||
262 | return crypto4xx_build_pd(&req->base, ctx, req->src, | |
263 | (struct scatterlist *) req->result, | |
264 | req->nbytes, NULL, 0); | |
265 | } | |
266 | ||
267 | int crypto4xx_hash_final(struct ahash_request *req) | |
268 | { | |
269 | return 0; | |
270 | } | |
271 | ||
272 | int crypto4xx_hash_digest(struct ahash_request *req) | |
273 | { | |
274 | struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm); | |
275 | ||
276 | ctx->hash_final = 1; | |
277 | ctx->pd_ctl = 0x11; | |
278 | ctx->direction = DIR_INBOUND; | |
279 | ||
280 | return crypto4xx_build_pd(&req->base, ctx, req->src, | |
281 | (struct scatterlist *) req->result, | |
282 | req->nbytes, NULL, 0); | |
283 | } | |
284 | ||
285 | /** | |
286 | * SHA1 Algorithm | |
287 | */ | |
288 | int crypto4xx_sha1_alg_init(struct crypto_tfm *tfm) | |
289 | { | |
290 | return crypto4xx_hash_alg_init(tfm, SA_HASH160_LEN, SA_HASH_ALG_SHA1, | |
291 | SA_HASH_MODE_HASH); | |
292 | } | |
293 | ||
294 |