blob: db916a691f497a4fc0dd7bdc40ec36b9cb61a311 [file] [log] [blame]
Bram Moolenaar40e6a712010-05-16 22:32:54 +02001/* vi:set ts=8 sts=4 sw=4:
2 *
Bram Moolenaar0bbabe82010-05-17 20:32:55 +02003 * VIM - Vi IMproved by Bram Moolenaar
Bram Moolenaar40e6a712010-05-16 22:32:54 +02004 *
Bram Moolenaar0bbabe82010-05-17 20:32:55 +02005 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 *
9 * FIPS-180-2 compliant SHA-256 implementation
Bram Moolenaar8d4eecc2012-11-20 17:19:01 +010010 * GPL by Christophe Devine, applies to older version.
Bram Moolenaar0bbabe82010-05-17 20:32:55 +020011 * Modified for md5deep, in public domain.
12 * Modified For Vim, Mohsin Ahmed, http://www.cs.albany.edu/~mosh
Bram Moolenaar8d4eecc2012-11-20 17:19:01 +010013 * Mohsin Ahmed states this work is distributed under the VIM License or GPL,
14 * at your choice.
Bram Moolenaar0bbabe82010-05-17 20:32:55 +020015 *
16 * Vim specific notes:
17 * Functions exported by this file:
18 * 1. sha256_key() hashes the password to 64 bytes char string.
19 * 2. sha2_seed() generates a random header.
20 * sha256_self_test() is implicitly called once.
Bram Moolenaar40e6a712010-05-16 22:32:54 +020021 */
22
23#include "vim.h"
24
Bram Moolenaar55debbe2010-05-23 23:34:36 +020025#if defined(FEAT_CRYPT) || defined(FEAT_PERSISTENT_UNDO)
Bram Moolenaar40e6a712010-05-16 22:32:54 +020026
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010027static void sha256_process(context_sha256_T *ctx, char_u data[64]);
Bram Moolenaar40e6a712010-05-16 22:32:54 +020028
29#define GET_UINT32(n, b, i) \
30{ \
Bram Moolenaarfa7584c2010-05-19 21:57:45 +020031 (n) = ( (UINT32_T)(b)[(i) ] << 24) \
32 | ( (UINT32_T)(b)[(i) + 1] << 16) \
33 | ( (UINT32_T)(b)[(i) + 2] << 8) \
34 | ( (UINT32_T)(b)[(i) + 3] ); \
Bram Moolenaar40e6a712010-05-16 22:32:54 +020035}
36
37#define PUT_UINT32(n,b,i) \
38{ \
39 (b)[(i) ] = (char_u)((n) >> 24); \
40 (b)[(i) + 1] = (char_u)((n) >> 16); \
41 (b)[(i) + 2] = (char_u)((n) >> 8); \
42 (b)[(i) + 3] = (char_u)((n) ); \
43}
44
Bram Moolenaar55debbe2010-05-23 23:34:36 +020045 void
Bram Moolenaar764b23c2016-01-30 21:10:09 +010046sha256_start(context_sha256_T *ctx)
Bram Moolenaar40e6a712010-05-16 22:32:54 +020047{
48 ctx->total[0] = 0;
49 ctx->total[1] = 0;
50
51 ctx->state[0] = 0x6A09E667;
52 ctx->state[1] = 0xBB67AE85;
53 ctx->state[2] = 0x3C6EF372;
54 ctx->state[3] = 0xA54FF53A;
55 ctx->state[4] = 0x510E527F;
56 ctx->state[5] = 0x9B05688C;
57 ctx->state[6] = 0x1F83D9AB;
58 ctx->state[7] = 0x5BE0CD19;
59}
60
61 static void
Bram Moolenaar764b23c2016-01-30 21:10:09 +010062sha256_process(context_sha256_T *ctx, char_u data[64])
Bram Moolenaar40e6a712010-05-16 22:32:54 +020063{
Bram Moolenaarfa7584c2010-05-19 21:57:45 +020064 UINT32_T temp1, temp2, W[64];
65 UINT32_T A, B, C, D, E, F, G, H;
Bram Moolenaar40e6a712010-05-16 22:32:54 +020066
67 GET_UINT32(W[0], data, 0);
68 GET_UINT32(W[1], data, 4);
69 GET_UINT32(W[2], data, 8);
70 GET_UINT32(W[3], data, 12);
71 GET_UINT32(W[4], data, 16);
72 GET_UINT32(W[5], data, 20);
73 GET_UINT32(W[6], data, 24);
74 GET_UINT32(W[7], data, 28);
75 GET_UINT32(W[8], data, 32);
76 GET_UINT32(W[9], data, 36);
77 GET_UINT32(W[10], data, 40);
78 GET_UINT32(W[11], data, 44);
79 GET_UINT32(W[12], data, 48);
80 GET_UINT32(W[13], data, 52);
81 GET_UINT32(W[14], data, 56);
82 GET_UINT32(W[15], data, 60);
83
84#define SHR(x, n) ((x & 0xFFFFFFFF) >> n)
85#define ROTR(x, n) (SHR(x, n) | (x << (32 - n)))
86
87#define S0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3))
88#define S1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10))
89
90#define S2(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
91#define S3(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
92
93#define F0(x, y, z) ((x & y) | (z & (x | y)))
94#define F1(x, y, z) (z ^ (x & (y ^ z)))
95
96#define R(t) \
97( \
98 W[t] = S1(W[t - 2]) + W[t - 7] + \
99 S0(W[t - 15]) + W[t - 16] \
100)
101
102#define P(a,b,c,d,e,f,g,h,x,K) \
103{ \
104 temp1 = h + S3(e) + F1(e, f, g) + K + x; \
105 temp2 = S2(a) + F0(a, b, c); \
106 d += temp1; h = temp1 + temp2; \
107}
108
109 A = ctx->state[0];
110 B = ctx->state[1];
111 C = ctx->state[2];
112 D = ctx->state[3];
113 E = ctx->state[4];
114 F = ctx->state[5];
115 G = ctx->state[6];
116 H = ctx->state[7];
117
118 P( A, B, C, D, E, F, G, H, W[ 0], 0x428A2F98);
119 P( H, A, B, C, D, E, F, G, W[ 1], 0x71374491);
120 P( G, H, A, B, C, D, E, F, W[ 2], 0xB5C0FBCF);
121 P( F, G, H, A, B, C, D, E, W[ 3], 0xE9B5DBA5);
122 P( E, F, G, H, A, B, C, D, W[ 4], 0x3956C25B);
123 P( D, E, F, G, H, A, B, C, W[ 5], 0x59F111F1);
124 P( C, D, E, F, G, H, A, B, W[ 6], 0x923F82A4);
125 P( B, C, D, E, F, G, H, A, W[ 7], 0xAB1C5ED5);
126 P( A, B, C, D, E, F, G, H, W[ 8], 0xD807AA98);
127 P( H, A, B, C, D, E, F, G, W[ 9], 0x12835B01);
128 P( G, H, A, B, C, D, E, F, W[10], 0x243185BE);
129 P( F, G, H, A, B, C, D, E, W[11], 0x550C7DC3);
130 P( E, F, G, H, A, B, C, D, W[12], 0x72BE5D74);
131 P( D, E, F, G, H, A, B, C, W[13], 0x80DEB1FE);
132 P( C, D, E, F, G, H, A, B, W[14], 0x9BDC06A7);
133 P( B, C, D, E, F, G, H, A, W[15], 0xC19BF174);
134 P( A, B, C, D, E, F, G, H, R(16), 0xE49B69C1);
135 P( H, A, B, C, D, E, F, G, R(17), 0xEFBE4786);
136 P( G, H, A, B, C, D, E, F, R(18), 0x0FC19DC6);
137 P( F, G, H, A, B, C, D, E, R(19), 0x240CA1CC);
138 P( E, F, G, H, A, B, C, D, R(20), 0x2DE92C6F);
139 P( D, E, F, G, H, A, B, C, R(21), 0x4A7484AA);
140 P( C, D, E, F, G, H, A, B, R(22), 0x5CB0A9DC);
141 P( B, C, D, E, F, G, H, A, R(23), 0x76F988DA);
142 P( A, B, C, D, E, F, G, H, R(24), 0x983E5152);
143 P( H, A, B, C, D, E, F, G, R(25), 0xA831C66D);
144 P( G, H, A, B, C, D, E, F, R(26), 0xB00327C8);
145 P( F, G, H, A, B, C, D, E, R(27), 0xBF597FC7);
146 P( E, F, G, H, A, B, C, D, R(28), 0xC6E00BF3);
147 P( D, E, F, G, H, A, B, C, R(29), 0xD5A79147);
148 P( C, D, E, F, G, H, A, B, R(30), 0x06CA6351);
149 P( B, C, D, E, F, G, H, A, R(31), 0x14292967);
150 P( A, B, C, D, E, F, G, H, R(32), 0x27B70A85);
151 P( H, A, B, C, D, E, F, G, R(33), 0x2E1B2138);
152 P( G, H, A, B, C, D, E, F, R(34), 0x4D2C6DFC);
153 P( F, G, H, A, B, C, D, E, R(35), 0x53380D13);
154 P( E, F, G, H, A, B, C, D, R(36), 0x650A7354);
155 P( D, E, F, G, H, A, B, C, R(37), 0x766A0ABB);
156 P( C, D, E, F, G, H, A, B, R(38), 0x81C2C92E);
157 P( B, C, D, E, F, G, H, A, R(39), 0x92722C85);
158 P( A, B, C, D, E, F, G, H, R(40), 0xA2BFE8A1);
159 P( H, A, B, C, D, E, F, G, R(41), 0xA81A664B);
160 P( G, H, A, B, C, D, E, F, R(42), 0xC24B8B70);
161 P( F, G, H, A, B, C, D, E, R(43), 0xC76C51A3);
162 P( E, F, G, H, A, B, C, D, R(44), 0xD192E819);
163 P( D, E, F, G, H, A, B, C, R(45), 0xD6990624);
164 P( C, D, E, F, G, H, A, B, R(46), 0xF40E3585);
165 P( B, C, D, E, F, G, H, A, R(47), 0x106AA070);
166 P( A, B, C, D, E, F, G, H, R(48), 0x19A4C116);
167 P( H, A, B, C, D, E, F, G, R(49), 0x1E376C08);
168 P( G, H, A, B, C, D, E, F, R(50), 0x2748774C);
169 P( F, G, H, A, B, C, D, E, R(51), 0x34B0BCB5);
170 P( E, F, G, H, A, B, C, D, R(52), 0x391C0CB3);
171 P( D, E, F, G, H, A, B, C, R(53), 0x4ED8AA4A);
172 P( C, D, E, F, G, H, A, B, R(54), 0x5B9CCA4F);
173 P( B, C, D, E, F, G, H, A, R(55), 0x682E6FF3);
174 P( A, B, C, D, E, F, G, H, R(56), 0x748F82EE);
175 P( H, A, B, C, D, E, F, G, R(57), 0x78A5636F);
176 P( G, H, A, B, C, D, E, F, R(58), 0x84C87814);
177 P( F, G, H, A, B, C, D, E, R(59), 0x8CC70208);
178 P( E, F, G, H, A, B, C, D, R(60), 0x90BEFFFA);
179 P( D, E, F, G, H, A, B, C, R(61), 0xA4506CEB);
180 P( C, D, E, F, G, H, A, B, R(62), 0xBEF9A3F7);
181 P( B, C, D, E, F, G, H, A, R(63), 0xC67178F2);
182
183 ctx->state[0] += A;
184 ctx->state[1] += B;
185 ctx->state[2] += C;
186 ctx->state[3] += D;
187 ctx->state[4] += E;
188 ctx->state[5] += F;
189 ctx->state[6] += G;
190 ctx->state[7] += H;
191}
192
Bram Moolenaar55debbe2010-05-23 23:34:36 +0200193 void
Bram Moolenaar764b23c2016-01-30 21:10:09 +0100194sha256_update(context_sha256_T *ctx, char_u *input, UINT32_T length)
Bram Moolenaar40e6a712010-05-16 22:32:54 +0200195{
Bram Moolenaarfa7584c2010-05-19 21:57:45 +0200196 UINT32_T left, fill;
Bram Moolenaar40e6a712010-05-16 22:32:54 +0200197
198 if (length == 0)
199 return;
200
201 left = ctx->total[0] & 0x3F;
202 fill = 64 - left;
203
204 ctx->total[0] += length;
205 ctx->total[0] &= 0xFFFFFFFF;
206
207 if (ctx->total[0] < length)
208 ctx->total[1]++;
209
210 if (left && length >= fill)
211 {
212 memcpy((void *)(ctx->buffer + left), (void *)input, fill);
213 sha256_process(ctx, ctx->buffer);
214 length -= fill;
215 input += fill;
216 left = 0;
217 }
218
219 while (length >= 64)
220 {
221 sha256_process(ctx, input);
222 length -= 64;
223 input += 64;
224 }
225
226 if (length)
227 memcpy((void *)(ctx->buffer + left), (void *)input, length);
228}
229
230static char_u sha256_padding[64] = {
231 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
232 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
233 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
234 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
235};
236
Bram Moolenaar55debbe2010-05-23 23:34:36 +0200237 void
Bram Moolenaar764b23c2016-01-30 21:10:09 +0100238sha256_finish(context_sha256_T *ctx, char_u digest[32])
Bram Moolenaar40e6a712010-05-16 22:32:54 +0200239{
Bram Moolenaarfa7584c2010-05-19 21:57:45 +0200240 UINT32_T last, padn;
241 UINT32_T high, low;
Bram Moolenaar40e6a712010-05-16 22:32:54 +0200242 char_u msglen[8];
243
244 high = (ctx->total[0] >> 29) | (ctx->total[1] << 3);
245 low = (ctx->total[0] << 3);
246
247 PUT_UINT32(high, msglen, 0);
248 PUT_UINT32(low, msglen, 4);
249
250 last = ctx->total[0] & 0x3F;
251 padn = (last < 56) ? (56 - last) : (120 - last);
252
253 sha256_update(ctx, sha256_padding, padn);
254 sha256_update(ctx, msglen, 8);
255
256 PUT_UINT32(ctx->state[0], digest, 0);
257 PUT_UINT32(ctx->state[1], digest, 4);
258 PUT_UINT32(ctx->state[2], digest, 8);
259 PUT_UINT32(ctx->state[3], digest, 12);
260 PUT_UINT32(ctx->state[4], digest, 16);
261 PUT_UINT32(ctx->state[5], digest, 20);
262 PUT_UINT32(ctx->state[6], digest, 24);
263 PUT_UINT32(ctx->state[7], digest, 28);
264}
Bram Moolenaar80794b12010-06-13 05:20:42 +0200265#endif /* FEAT_CRYPT || FEAT_PERSISTENT_UNDO */
266
267#if defined(FEAT_CRYPT) || defined(PROTO)
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100268static unsigned int get_some_time(void);
Bram Moolenaar40e6a712010-05-16 22:32:54 +0200269
Bram Moolenaar823a1652010-05-16 23:02:33 +0200270/*
Bram Moolenaar80794b12010-06-13 05:20:42 +0200271 * Returns hex digest of "buf[buf_len]" in a static array.
272 * if "salt" is not NULL also do "salt[salt_len]".
Bram Moolenaar823a1652010-05-16 23:02:33 +0200273 */
Bram Moolenaaraf9aeb92013-02-13 17:35:04 +0100274 char_u *
Bram Moolenaar764b23c2016-01-30 21:10:09 +0100275sha256_bytes(
276 char_u *buf,
277 int buf_len,
278 char_u *salt,
279 int salt_len)
Bram Moolenaar40e6a712010-05-16 22:32:54 +0200280{
281 char_u sha256sum[32];
Bram Moolenaar823a1652010-05-16 23:02:33 +0200282 static char_u hexit[65];
Bram Moolenaar40e6a712010-05-16 22:32:54 +0200283 int j;
284 context_sha256_T ctx;
285
286 sha256_self_test();
287
Bram Moolenaar55debbe2010-05-23 23:34:36 +0200288 sha256_start(&ctx);
Bram Moolenaar80794b12010-06-13 05:20:42 +0200289 sha256_update(&ctx, buf, buf_len);
290 if (salt != NULL)
291 sha256_update(&ctx, salt, salt_len);
Bram Moolenaar40e6a712010-05-16 22:32:54 +0200292 sha256_finish(&ctx, sha256sum);
293 for (j = 0; j < 32; j++)
Bram Moolenaar823a1652010-05-16 23:02:33 +0200294 sprintf((char *)hexit + j * 2, "%02x", sha256sum[j]);
Bram Moolenaar40e6a712010-05-16 22:32:54 +0200295 hexit[sizeof(hexit) - 1] = '\0';
296 return hexit;
297}
298
299/*
Bram Moolenaar823a1652010-05-16 23:02:33 +0200300 * Returns sha256(buf) as 64 hex chars in static array.
Bram Moolenaar40e6a712010-05-16 22:32:54 +0200301 */
Bram Moolenaar823a1652010-05-16 23:02:33 +0200302 char_u *
Bram Moolenaar764b23c2016-01-30 21:10:09 +0100303sha256_key(
304 char_u *buf,
305 char_u *salt,
306 int salt_len)
Bram Moolenaar40e6a712010-05-16 22:32:54 +0200307{
Bram Moolenaar40e6a712010-05-16 22:32:54 +0200308 /* No passwd means don't encrypt */
309 if (buf == NULL || *buf == NUL)
Bram Moolenaar823a1652010-05-16 23:02:33 +0200310 return (char_u *)"";
Bram Moolenaar40e6a712010-05-16 22:32:54 +0200311
Bram Moolenaar80794b12010-06-13 05:20:42 +0200312 return sha256_bytes(buf, (int)STRLEN(buf), salt, salt_len);
Bram Moolenaar40e6a712010-05-16 22:32:54 +0200313}
314
315/*
316 * These are the standard FIPS-180-2 test vectors
317 */
318
319static char *sha_self_test_msg[] = {
320 "abc",
321 "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
322 NULL
323};
324
325static char *sha_self_test_vector[] = {
326 "ba7816bf8f01cfea414140de5dae2223" \
327 "b00361a396177a9cb410ff61f20015ad",
328 "248d6a61d20638b8e5c026930c3e6039" \
329 "a33ce45964ff2167f6ecedd419db06c1",
330 "cdc76e5c9914fb9281a1c7e284d73e67" \
331 "f1809a48a497200e046d39ccc7112cd0"
332};
333
334/*
335 * Perform a test on the SHA256 algorithm.
336 * Return FAIL or OK.
337 */
338 int
Bram Moolenaar764b23c2016-01-30 21:10:09 +0100339sha256_self_test(void)
Bram Moolenaar40e6a712010-05-16 22:32:54 +0200340{
341 int i, j;
342 char output[65];
343 context_sha256_T ctx;
344 char_u buf[1000];
345 char_u sha256sum[32];
346 static int failures = 0;
Bram Moolenaar823a1652010-05-16 23:02:33 +0200347 char_u *hexit;
Bram Moolenaar40e6a712010-05-16 22:32:54 +0200348 static int sha256_self_tested = 0;
349
350 if (sha256_self_tested > 0)
351 return failures > 0 ? FAIL : OK;
352 sha256_self_tested = 1;
353
354 for (i = 0; i < 3; i++)
355 {
356 if (i < 2)
357 {
Bram Moolenaar823a1652010-05-16 23:02:33 +0200358 hexit = sha256_bytes((char_u *)sha_self_test_msg[i],
Bram Moolenaar80794b12010-06-13 05:20:42 +0200359 (int)STRLEN(sha_self_test_msg[i]),
360 NULL, 0);
Bram Moolenaar823a1652010-05-16 23:02:33 +0200361 STRCPY(output, hexit);
Bram Moolenaar40e6a712010-05-16 22:32:54 +0200362 }
363 else
364 {
Bram Moolenaar55debbe2010-05-23 23:34:36 +0200365 sha256_start(&ctx);
Bram Moolenaar7db5fc82010-05-24 11:59:29 +0200366 vim_memset(buf, 'a', 1000);
Bram Moolenaar40e6a712010-05-16 22:32:54 +0200367 for (j = 0; j < 1000; j++)
368 sha256_update(&ctx, (char_u *)buf, 1000);
369 sha256_finish(&ctx, sha256sum);
370 for (j = 0; j < 32; j++)
371 sprintf(output + j * 2, "%02x", sha256sum[j]);
372 }
373 if (memcmp(output, sha_self_test_vector[i], 64))
374 {
375 failures++;
376 output[sizeof(output) - 1] = '\0';
377 /* printf("sha256_self_test %d failed %s\n", i, output); */
378 }
379 }
380 return failures > 0 ? FAIL : OK;
381}
382
383 static unsigned int
Bram Moolenaar764b23c2016-01-30 21:10:09 +0100384get_some_time(void)
Bram Moolenaar40e6a712010-05-16 22:32:54 +0200385{
Bram Moolenaar80794b12010-06-13 05:20:42 +0200386# ifdef HAVE_GETTIMEOFDAY
Bram Moolenaar40e6a712010-05-16 22:32:54 +0200387 struct timeval tv;
388
389 /* Using usec makes it less predictable. */
390 gettimeofday(&tv, NULL);
391 return (unsigned int)(tv.tv_sec + tv.tv_usec);
Bram Moolenaar80794b12010-06-13 05:20:42 +0200392# else
Bram Moolenaar40e6a712010-05-16 22:32:54 +0200393 return (unsigned int)time(NULL);
Bram Moolenaar80794b12010-06-13 05:20:42 +0200394# endif
Bram Moolenaar40e6a712010-05-16 22:32:54 +0200395}
396
397/*
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200398 * Fill "header[header_len]" with random_data.
399 * Also "salt[salt_len]" when "salt" is not NULL.
Bram Moolenaar40e6a712010-05-16 22:32:54 +0200400 */
401 void
Bram Moolenaar764b23c2016-01-30 21:10:09 +0100402sha2_seed(
403 char_u *header,
404 int header_len,
405 char_u *salt,
406 int salt_len)
Bram Moolenaar40e6a712010-05-16 22:32:54 +0200407{
408 int i;
409 static char_u random_data[1000];
410 char_u sha256sum[32];
411 context_sha256_T ctx;
Bram Moolenaar80794b12010-06-13 05:20:42 +0200412
Bram Moolenaar40e6a712010-05-16 22:32:54 +0200413 srand(get_some_time());
414
415 for (i = 0; i < (int)sizeof(random_data) - 1; i++)
416 random_data[i] = (char_u)((get_some_time() ^ rand()) & 0xff);
Bram Moolenaar55debbe2010-05-23 23:34:36 +0200417 sha256_start(&ctx);
Bram Moolenaar40e6a712010-05-16 22:32:54 +0200418 sha256_update(&ctx, (char_u *)random_data, sizeof(random_data));
419 sha256_finish(&ctx, sha256sum);
420
Bram Moolenaar80794b12010-06-13 05:20:42 +0200421 /* put first block into header. */
Bram Moolenaar40e6a712010-05-16 22:32:54 +0200422 for (i = 0; i < header_len; i++)
423 header[i] = sha256sum[i % sizeof(sha256sum)];
Bram Moolenaar80794b12010-06-13 05:20:42 +0200424
425 /* put remaining block into salt. */
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200426 if (salt != NULL)
427 for (i = 0; i < salt_len; i++)
428 salt[i] = sha256sum[(i + header_len) % sizeof(sha256sum)];
Bram Moolenaar40e6a712010-05-16 22:32:54 +0200429}
430
Bram Moolenaar80794b12010-06-13 05:20:42 +0200431#endif /* FEAT_CRYPT */