diff options
author | Sebastian Siewior <sebastian@breakpoint.cc> | 2007-11-08 08:25:04 -0500 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2008-01-10 16:16:10 -0500 |
commit | 81190b321548bb0bf2d6e1f172695275b0fd1363 (patch) | |
tree | 00948bc67bf8cd450595988c4f96a5f9749ee157 /arch | |
parent | 96e82e4551d38e0863b366a7b61185bc4a9946cc (diff) |
[CRYPTO] aes-x86-64: Remove setkey
The setkey() function can be shared with the generic algorithm.
Signed-off-by: Sebastian Siewior <sebastian@breakpoint.cc>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/crypto/aes-x86_64-asm_64.S | 68 | ||||
-rw-r--r-- | arch/x86/crypto/aes_64.c | 282 |
2 files changed, 37 insertions, 313 deletions
diff --git a/arch/x86/crypto/aes-x86_64-asm_64.S b/arch/x86/crypto/aes-x86_64-asm_64.S index 26b40de4d0b0..a120f526c3df 100644 --- a/arch/x86/crypto/aes-x86_64-asm_64.S +++ b/arch/x86/crypto/aes-x86_64-asm_64.S | |||
@@ -8,10 +8,10 @@ | |||
8 | * including this sentence is retained in full. | 8 | * including this sentence is retained in full. |
9 | */ | 9 | */ |
10 | 10 | ||
11 | .extern aes_ft_tab | 11 | .extern crypto_ft_tab |
12 | .extern aes_it_tab | 12 | .extern crypto_it_tab |
13 | .extern aes_fl_tab | 13 | .extern crypto_fl_tab |
14 | .extern aes_il_tab | 14 | .extern crypto_il_tab |
15 | 15 | ||
16 | .text | 16 | .text |
17 | 17 | ||
@@ -56,13 +56,13 @@ | |||
56 | .align 8; \ | 56 | .align 8; \ |
57 | FUNC: movq r1,r2; \ | 57 | FUNC: movq r1,r2; \ |
58 | movq r3,r4; \ | 58 | movq r3,r4; \ |
59 | leaq BASE+KEY+52(r8),r9; \ | 59 | leaq BASE+KEY+48+4(r8),r9; \ |
60 | movq r10,r11; \ | 60 | movq r10,r11; \ |
61 | movl (r7),r5 ## E; \ | 61 | movl (r7),r5 ## E; \ |
62 | movl 4(r7),r1 ## E; \ | 62 | movl 4(r7),r1 ## E; \ |
63 | movl 8(r7),r6 ## E; \ | 63 | movl 8(r7),r6 ## E; \ |
64 | movl 12(r7),r7 ## E; \ | 64 | movl 12(r7),r7 ## E; \ |
65 | movl BASE(r8),r10 ## E; \ | 65 | movl BASE+0(r8),r10 ## E; \ |
66 | xorl -48(r9),r5 ## E; \ | 66 | xorl -48(r9),r5 ## E; \ |
67 | xorl -44(r9),r1 ## E; \ | 67 | xorl -44(r9),r1 ## E; \ |
68 | xorl -40(r9),r6 ## E; \ | 68 | xorl -40(r9),r6 ## E; \ |
@@ -154,37 +154,37 @@ FUNC: movq r1,r2; \ | |||
154 | /* void aes_enc_blk(stuct crypto_tfm *tfm, u8 *out, const u8 *in) */ | 154 | /* void aes_enc_blk(stuct crypto_tfm *tfm, u8 *out, const u8 *in) */ |
155 | 155 | ||
156 | entry(aes_enc_blk,0,enc128,enc192) | 156 | entry(aes_enc_blk,0,enc128,enc192) |
157 | encrypt_round(aes_ft_tab,-96) | 157 | encrypt_round(crypto_ft_tab,-96) |
158 | encrypt_round(aes_ft_tab,-80) | 158 | encrypt_round(crypto_ft_tab,-80) |
159 | enc192: encrypt_round(aes_ft_tab,-64) | 159 | enc192: encrypt_round(crypto_ft_tab,-64) |
160 | encrypt_round(aes_ft_tab,-48) | 160 | encrypt_round(crypto_ft_tab,-48) |
161 | enc128: encrypt_round(aes_ft_tab,-32) | 161 | enc128: encrypt_round(crypto_ft_tab,-32) |
162 | encrypt_round(aes_ft_tab,-16) | 162 | encrypt_round(crypto_ft_tab,-16) |
163 | encrypt_round(aes_ft_tab, 0) | 163 | encrypt_round(crypto_ft_tab, 0) |
164 | encrypt_round(aes_ft_tab, 16) | 164 | encrypt_round(crypto_ft_tab, 16) |
165 | encrypt_round(aes_ft_tab, 32) | 165 | encrypt_round(crypto_ft_tab, 32) |
166 | encrypt_round(aes_ft_tab, 48) | 166 | encrypt_round(crypto_ft_tab, 48) |
167 | encrypt_round(aes_ft_tab, 64) | 167 | encrypt_round(crypto_ft_tab, 64) |
168 | encrypt_round(aes_ft_tab, 80) | 168 | encrypt_round(crypto_ft_tab, 80) |
169 | encrypt_round(aes_ft_tab, 96) | 169 | encrypt_round(crypto_ft_tab, 96) |
170 | encrypt_final(aes_fl_tab,112) | 170 | encrypt_final(crypto_fl_tab,112) |
171 | return | 171 | return |
172 | 172 | ||
173 | /* void aes_dec_blk(struct crypto_tfm *tfm, u8 *out, const u8 *in) */ | 173 | /* void aes_dec_blk(struct crypto_tfm *tfm, u8 *out, const u8 *in) */ |
174 | 174 | ||
175 | entry(aes_dec_blk,240,dec128,dec192) | 175 | entry(aes_dec_blk,240,dec128,dec192) |
176 | decrypt_round(aes_it_tab,-96) | 176 | decrypt_round(crypto_it_tab,-96) |
177 | decrypt_round(aes_it_tab,-80) | 177 | decrypt_round(crypto_it_tab,-80) |
178 | dec192: decrypt_round(aes_it_tab,-64) | 178 | dec192: decrypt_round(crypto_it_tab,-64) |
179 | decrypt_round(aes_it_tab,-48) | 179 | decrypt_round(crypto_it_tab,-48) |
180 | dec128: decrypt_round(aes_it_tab,-32) | 180 | dec128: decrypt_round(crypto_it_tab,-32) |
181 | decrypt_round(aes_it_tab,-16) | 181 | decrypt_round(crypto_it_tab,-16) |
182 | decrypt_round(aes_it_tab, 0) | 182 | decrypt_round(crypto_it_tab, 0) |
183 | decrypt_round(aes_it_tab, 16) | 183 | decrypt_round(crypto_it_tab, 16) |
184 | decrypt_round(aes_it_tab, 32) | 184 | decrypt_round(crypto_it_tab, 32) |
185 | decrypt_round(aes_it_tab, 48) | 185 | decrypt_round(crypto_it_tab, 48) |
186 | decrypt_round(aes_it_tab, 64) | 186 | decrypt_round(crypto_it_tab, 64) |
187 | decrypt_round(aes_it_tab, 80) | 187 | decrypt_round(crypto_it_tab, 80) |
188 | decrypt_round(aes_it_tab, 96) | 188 | decrypt_round(crypto_it_tab, 96) |
189 | decrypt_final(aes_il_tab,112) | 189 | decrypt_final(crypto_il_tab,112) |
190 | return | 190 | return |
diff --git a/arch/x86/crypto/aes_64.c b/arch/x86/crypto/aes_64.c index 0b38a4cd2ce1..d7a41a97dd3f 100644 --- a/arch/x86/crypto/aes_64.c +++ b/arch/x86/crypto/aes_64.c | |||
@@ -1,284 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * Cryptographic API. | 2 | * Glue Code for AES Cipher Algorithm |
3 | * | 3 | * |
4 | * AES Cipher Algorithm. | ||
5 | * | ||
6 | * Based on Brian Gladman's code. | ||
7 | * | ||
8 | * Linux developers: | ||
9 | * Alexander Kjeldaas <astor@fast.no> | ||
10 | * Herbert Valerio Riedel <hvr@hvrlab.org> | ||
11 | * Kyle McMartin <kyle@debian.org> | ||
12 | * Adam J. Richter <adam@yggdrasil.com> (conversion to 2.5 API). | ||
13 | * Andreas Steinmetz <ast@domdv.de> (adapted to x86_64 assembler) | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or modify | ||
16 | * it under the terms of the GNU General Public License as published by | ||
17 | * the Free Software Foundation; either version 2 of the License, or | ||
18 | * (at your option) any later version. | ||
19 | * | ||
20 | * --------------------------------------------------------------------------- | ||
21 | * Copyright (c) 2002, Dr Brian Gladman <brg@gladman.me.uk>, Worcester, UK. | ||
22 | * All rights reserved. | ||
23 | * | ||
24 | * LICENSE TERMS | ||
25 | * | ||
26 | * The free distribution and use of this software in both source and binary | ||
27 | * form is allowed (with or without changes) provided that: | ||
28 | * | ||
29 | * 1. distributions of this source code include the above copyright | ||
30 | * notice, this list of conditions and the following disclaimer; | ||
31 | * | ||
32 | * 2. distributions in binary form include the above copyright | ||
33 | * notice, this list of conditions and the following disclaimer | ||
34 | * in the documentation and/or other associated materials; | ||
35 | * | ||
36 | * 3. the copyright holder's name is not used to endorse products | ||
37 | * built using this software without specific written permission. | ||
38 | * | ||
39 | * ALTERNATIVELY, provided that this notice is retained in full, this product | ||
40 | * may be distributed under the terms of the GNU General Public License (GPL), | ||
41 | * in which case the provisions of the GPL apply INSTEAD OF those given above. | ||
42 | * | ||
43 | * DISCLAIMER | ||
44 | * | ||
45 | * This software is provided 'as is' with no explicit or implied warranties | ||
46 | * in respect of its properties, including, but not limited to, correctness | ||
47 | * and/or fitness for purpose. | ||
48 | * --------------------------------------------------------------------------- | ||
49 | */ | 4 | */ |
50 | 5 | ||
51 | /* Some changes from the Gladman version: | ||
52 | s/RIJNDAEL(e_key)/E_KEY/g | ||
53 | s/RIJNDAEL(d_key)/D_KEY/g | ||
54 | */ | ||
55 | |||
56 | #include <asm/byteorder.h> | ||
57 | #include <crypto/aes.h> | 6 | #include <crypto/aes.h> |
58 | #include <linux/bitops.h> | ||
59 | #include <linux/crypto.h> | ||
60 | #include <linux/errno.h> | ||
61 | #include <linux/init.h> | ||
62 | #include <linux/module.h> | ||
63 | #include <linux/types.h> | ||
64 | |||
65 | /* | ||
66 | * #define byte(x, nr) ((unsigned char)((x) >> (nr*8))) | ||
67 | */ | ||
68 | static inline u8 byte(const u32 x, const unsigned n) | ||
69 | { | ||
70 | return x >> (n << 3); | ||
71 | } | ||
72 | |||
73 | struct aes_ctx | ||
74 | { | ||
75 | u32 key_length; | ||
76 | u32 buf[120]; | ||
77 | }; | ||
78 | |||
79 | #define E_KEY (&ctx->buf[0]) | ||
80 | #define D_KEY (&ctx->buf[60]) | ||
81 | |||
82 | static u8 pow_tab[256] __initdata; | ||
83 | static u8 log_tab[256] __initdata; | ||
84 | static u8 sbx_tab[256] __initdata; | ||
85 | static u8 isb_tab[256] __initdata; | ||
86 | static u32 rco_tab[10]; | ||
87 | u32 aes_ft_tab[4][256]; | ||
88 | u32 aes_it_tab[4][256]; | ||
89 | |||
90 | u32 aes_fl_tab[4][256]; | ||
91 | u32 aes_il_tab[4][256]; | ||
92 | |||
93 | static inline u8 f_mult(u8 a, u8 b) | ||
94 | { | ||
95 | u8 aa = log_tab[a], cc = aa + log_tab[b]; | ||
96 | |||
97 | return pow_tab[cc + (cc < aa ? 1 : 0)]; | ||
98 | } | ||
99 | |||
100 | #define ff_mult(a, b) (a && b ? f_mult(a, b) : 0) | ||
101 | |||
102 | #define ls_box(x) \ | ||
103 | (aes_fl_tab[0][byte(x, 0)] ^ \ | ||
104 | aes_fl_tab[1][byte(x, 1)] ^ \ | ||
105 | aes_fl_tab[2][byte(x, 2)] ^ \ | ||
106 | aes_fl_tab[3][byte(x, 3)]) | ||
107 | |||
108 | static void __init gen_tabs(void) | ||
109 | { | ||
110 | u32 i, t; | ||
111 | u8 p, q; | ||
112 | |||
113 | /* log and power tables for GF(2**8) finite field with | ||
114 | 0x011b as modular polynomial - the simplest primitive | ||
115 | root is 0x03, used here to generate the tables */ | ||
116 | |||
117 | for (i = 0, p = 1; i < 256; ++i) { | ||
118 | pow_tab[i] = (u8)p; | ||
119 | log_tab[p] = (u8)i; | ||
120 | |||
121 | p ^= (p << 1) ^ (p & 0x80 ? 0x01b : 0); | ||
122 | } | ||
123 | |||
124 | log_tab[1] = 0; | ||
125 | |||
126 | for (i = 0, p = 1; i < 10; ++i) { | ||
127 | rco_tab[i] = p; | ||
128 | |||
129 | p = (p << 1) ^ (p & 0x80 ? 0x01b : 0); | ||
130 | } | ||
131 | |||
132 | for (i = 0; i < 256; ++i) { | ||
133 | p = (i ? pow_tab[255 - log_tab[i]] : 0); | ||
134 | q = ((p >> 7) | (p << 1)) ^ ((p >> 6) | (p << 2)); | ||
135 | p ^= 0x63 ^ q ^ ((q >> 6) | (q << 2)); | ||
136 | sbx_tab[i] = p; | ||
137 | isb_tab[p] = (u8)i; | ||
138 | } | ||
139 | |||
140 | for (i = 0; i < 256; ++i) { | ||
141 | p = sbx_tab[i]; | ||
142 | |||
143 | t = p; | ||
144 | aes_fl_tab[0][i] = t; | ||
145 | aes_fl_tab[1][i] = rol32(t, 8); | ||
146 | aes_fl_tab[2][i] = rol32(t, 16); | ||
147 | aes_fl_tab[3][i] = rol32(t, 24); | ||
148 | |||
149 | t = ((u32)ff_mult(2, p)) | | ||
150 | ((u32)p << 8) | | ||
151 | ((u32)p << 16) | ((u32)ff_mult(3, p) << 24); | ||
152 | |||
153 | aes_ft_tab[0][i] = t; | ||
154 | aes_ft_tab[1][i] = rol32(t, 8); | ||
155 | aes_ft_tab[2][i] = rol32(t, 16); | ||
156 | aes_ft_tab[3][i] = rol32(t, 24); | ||
157 | |||
158 | p = isb_tab[i]; | ||
159 | |||
160 | t = p; | ||
161 | aes_il_tab[0][i] = t; | ||
162 | aes_il_tab[1][i] = rol32(t, 8); | ||
163 | aes_il_tab[2][i] = rol32(t, 16); | ||
164 | aes_il_tab[3][i] = rol32(t, 24); | ||
165 | |||
166 | t = ((u32)ff_mult(14, p)) | | ||
167 | ((u32)ff_mult(9, p) << 8) | | ||
168 | ((u32)ff_mult(13, p) << 16) | | ||
169 | ((u32)ff_mult(11, p) << 24); | ||
170 | |||
171 | aes_it_tab[0][i] = t; | ||
172 | aes_it_tab[1][i] = rol32(t, 8); | ||
173 | aes_it_tab[2][i] = rol32(t, 16); | ||
174 | aes_it_tab[3][i] = rol32(t, 24); | ||
175 | } | ||
176 | } | ||
177 | |||
178 | #define star_x(x) (((x) & 0x7f7f7f7f) << 1) ^ ((((x) & 0x80808080) >> 7) * 0x1b) | ||
179 | |||
180 | #define imix_col(y, x) \ | ||
181 | u = star_x(x); \ | ||
182 | v = star_x(u); \ | ||
183 | w = star_x(v); \ | ||
184 | t = w ^ (x); \ | ||
185 | (y) = u ^ v ^ w; \ | ||
186 | (y) ^= ror32(u ^ t, 8) ^ \ | ||
187 | ror32(v ^ t, 16) ^ \ | ||
188 | ror32(t, 24) | ||
189 | |||
190 | /* initialise the key schedule from the user supplied key */ | ||
191 | |||
192 | #define loop4(i) \ | ||
193 | { \ | ||
194 | t = ror32(t, 8); t = ls_box(t) ^ rco_tab[i]; \ | ||
195 | t ^= E_KEY[4 * i]; E_KEY[4 * i + 4] = t; \ | ||
196 | t ^= E_KEY[4 * i + 1]; E_KEY[4 * i + 5] = t; \ | ||
197 | t ^= E_KEY[4 * i + 2]; E_KEY[4 * i + 6] = t; \ | ||
198 | t ^= E_KEY[4 * i + 3]; E_KEY[4 * i + 7] = t; \ | ||
199 | } | ||
200 | |||
201 | #define loop6(i) \ | ||
202 | { \ | ||
203 | t = ror32(t, 8); t = ls_box(t) ^ rco_tab[i]; \ | ||
204 | t ^= E_KEY[6 * i]; E_KEY[6 * i + 6] = t; \ | ||
205 | t ^= E_KEY[6 * i + 1]; E_KEY[6 * i + 7] = t; \ | ||
206 | t ^= E_KEY[6 * i + 2]; E_KEY[6 * i + 8] = t; \ | ||
207 | t ^= E_KEY[6 * i + 3]; E_KEY[6 * i + 9] = t; \ | ||
208 | t ^= E_KEY[6 * i + 4]; E_KEY[6 * i + 10] = t; \ | ||
209 | t ^= E_KEY[6 * i + 5]; E_KEY[6 * i + 11] = t; \ | ||
210 | } | ||
211 | |||
212 | #define loop8(i) \ | ||
213 | { \ | ||
214 | t = ror32(t, 8); ; t = ls_box(t) ^ rco_tab[i]; \ | ||
215 | t ^= E_KEY[8 * i]; E_KEY[8 * i + 8] = t; \ | ||
216 | t ^= E_KEY[8 * i + 1]; E_KEY[8 * i + 9] = t; \ | ||
217 | t ^= E_KEY[8 * i + 2]; E_KEY[8 * i + 10] = t; \ | ||
218 | t ^= E_KEY[8 * i + 3]; E_KEY[8 * i + 11] = t; \ | ||
219 | t = E_KEY[8 * i + 4] ^ ls_box(t); \ | ||
220 | E_KEY[8 * i + 12] = t; \ | ||
221 | t ^= E_KEY[8 * i + 5]; E_KEY[8 * i + 13] = t; \ | ||
222 | t ^= E_KEY[8 * i + 6]; E_KEY[8 * i + 14] = t; \ | ||
223 | t ^= E_KEY[8 * i + 7]; E_KEY[8 * i + 15] = t; \ | ||
224 | } | ||
225 | |||
226 | static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, | ||
227 | unsigned int key_len) | ||
228 | { | ||
229 | struct aes_ctx *ctx = crypto_tfm_ctx(tfm); | ||
230 | const __le32 *key = (const __le32 *)in_key; | ||
231 | u32 *flags = &tfm->crt_flags; | ||
232 | u32 i, j, t, u, v, w; | ||
233 | |||
234 | if (key_len % 8) { | ||
235 | *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; | ||
236 | return -EINVAL; | ||
237 | } | ||
238 | |||
239 | ctx->key_length = key_len; | ||
240 | |||
241 | D_KEY[key_len + 24] = E_KEY[0] = le32_to_cpu(key[0]); | ||
242 | D_KEY[key_len + 25] = E_KEY[1] = le32_to_cpu(key[1]); | ||
243 | D_KEY[key_len + 26] = E_KEY[2] = le32_to_cpu(key[2]); | ||
244 | D_KEY[key_len + 27] = E_KEY[3] = le32_to_cpu(key[3]); | ||
245 | |||
246 | switch (key_len) { | ||
247 | case 16: | ||
248 | t = E_KEY[3]; | ||
249 | for (i = 0; i < 10; ++i) | ||
250 | loop4(i); | ||
251 | break; | ||
252 | |||
253 | case 24: | ||
254 | E_KEY[4] = le32_to_cpu(key[4]); | ||
255 | t = E_KEY[5] = le32_to_cpu(key[5]); | ||
256 | for (i = 0; i < 8; ++i) | ||
257 | loop6 (i); | ||
258 | break; | ||
259 | |||
260 | case 32: | ||
261 | E_KEY[4] = le32_to_cpu(key[4]); | ||
262 | E_KEY[5] = le32_to_cpu(key[5]); | ||
263 | E_KEY[6] = le32_to_cpu(key[6]); | ||
264 | t = E_KEY[7] = le32_to_cpu(key[7]); | ||
265 | for (i = 0; i < 7; ++i) | ||
266 | loop8(i); | ||
267 | break; | ||
268 | } | ||
269 | |||
270 | D_KEY[0] = E_KEY[key_len + 24]; | ||
271 | D_KEY[1] = E_KEY[key_len + 25]; | ||
272 | D_KEY[2] = E_KEY[key_len + 26]; | ||
273 | D_KEY[3] = E_KEY[key_len + 27]; | ||
274 | |||
275 | for (i = 4; i < key_len + 24; ++i) { | ||
276 | j = key_len + 24 - (i & ~3) + (i & 3); | ||
277 | imix_col(D_KEY[j], E_KEY[i]); | ||
278 | } | ||
279 | |||
280 | return 0; | ||
281 | } | ||
282 | 7 | ||
283 | asmlinkage void aes_enc_blk(struct crypto_tfm *tfm, u8 *out, const u8 *in); | 8 | asmlinkage void aes_enc_blk(struct crypto_tfm *tfm, u8 *out, const u8 *in); |
284 | asmlinkage void aes_dec_blk(struct crypto_tfm *tfm, u8 *out, const u8 *in); | 9 | asmlinkage void aes_dec_blk(struct crypto_tfm *tfm, u8 *out, const u8 *in); |
@@ -299,14 +24,14 @@ static struct crypto_alg aes_alg = { | |||
299 | .cra_priority = 200, | 24 | .cra_priority = 200, |
300 | .cra_flags = CRYPTO_ALG_TYPE_CIPHER, | 25 | .cra_flags = CRYPTO_ALG_TYPE_CIPHER, |
301 | .cra_blocksize = AES_BLOCK_SIZE, | 26 | .cra_blocksize = AES_BLOCK_SIZE, |
302 | .cra_ctxsize = sizeof(struct aes_ctx), | 27 | .cra_ctxsize = sizeof(struct crypto_aes_ctx), |
303 | .cra_module = THIS_MODULE, | 28 | .cra_module = THIS_MODULE, |
304 | .cra_list = LIST_HEAD_INIT(aes_alg.cra_list), | 29 | .cra_list = LIST_HEAD_INIT(aes_alg.cra_list), |
305 | .cra_u = { | 30 | .cra_u = { |
306 | .cipher = { | 31 | .cipher = { |
307 | .cia_min_keysize = AES_MIN_KEY_SIZE, | 32 | .cia_min_keysize = AES_MIN_KEY_SIZE, |
308 | .cia_max_keysize = AES_MAX_KEY_SIZE, | 33 | .cia_max_keysize = AES_MAX_KEY_SIZE, |
309 | .cia_setkey = aes_set_key, | 34 | .cia_setkey = crypto_aes_set_key, |
310 | .cia_encrypt = aes_encrypt, | 35 | .cia_encrypt = aes_encrypt, |
311 | .cia_decrypt = aes_decrypt | 36 | .cia_decrypt = aes_decrypt |
312 | } | 37 | } |
@@ -315,7 +40,6 @@ static struct crypto_alg aes_alg = { | |||
315 | 40 | ||
316 | static int __init aes_init(void) | 41 | static int __init aes_init(void) |
317 | { | 42 | { |
318 | gen_tabs(); | ||
319 | return crypto_register_alg(&aes_alg); | 43 | return crypto_register_alg(&aes_alg); |
320 | } | 44 | } |
321 | 45 | ||