OSDN Git Service

rm *.user file
[tortoisegit/TortoiseGitJp.git] / src / TortoisePlink / SSHRAND.C
1 /*\r
2  * cryptographic random number generator for PuTTY's ssh client\r
3  */\r
4 \r
5 #include "putty.h"\r
6 #include "ssh.h"\r
7 \r
8 /* Collect environmental noise every 5 minutes */\r
9 #define NOISE_REGULAR_INTERVAL (5*60*TICKSPERSEC)\r
10 \r
11 void noise_get_heavy(void (*func) (void *, int));\r
12 void noise_get_light(void (*func) (void *, int));\r
13 \r
14 /*\r
15  * `pool' itself is a pool of random data which we actually use: we\r
16  * return bytes from `pool', at position `poolpos', until `poolpos'\r
17  * reaches the end of the pool. At this point we generate more\r
18  * random data, by adding noise, stirring well, and resetting\r
19  * `poolpos' to point to just past the beginning of the pool (not\r
20  * _the_ beginning, since otherwise we'd give away the whole\r
21  * contents of our pool, and attackers would just have to guess the\r
22  * next lot of noise).\r
23  *\r
24  * `incomingb' buffers acquired noise data, until it gets full, at\r
25  * which point the acquired noise is SHA'ed into `incoming' and\r
26  * `incomingb' is cleared. The noise in `incoming' is used as part\r
27  * of the noise for each stirring of the pool, in addition to local\r
28  * time, process listings, and other such stuff.\r
29  */\r
30 \r
31 #define HASHINPUT 64                   /* 64 bytes SHA input */\r
32 #define HASHSIZE 20                    /* 160 bits SHA output */\r
33 #define POOLSIZE 1200                  /* size of random pool */\r
34 \r
35 struct RandPool {\r
36     unsigned char pool[POOLSIZE];\r
37     int poolpos;\r
38 \r
39     unsigned char incoming[HASHSIZE];\r
40 \r
41     unsigned char incomingb[HASHINPUT];\r
42     int incomingpos;\r
43 \r
44     int stir_pending;\r
45 };\r
46 \r
47 static struct RandPool pool;\r
48 int random_active = 0;\r
49 long next_noise_collection;\r
50 \r
51 static void random_stir(void)\r
52 {\r
53     word32 block[HASHINPUT / sizeof(word32)];\r
54     word32 digest[HASHSIZE / sizeof(word32)];\r
55     int i, j, k;\r
56 \r
57     /*\r
58      * noise_get_light will call random_add_noise, which may call\r
59      * back to here. Prevent recursive stirs.\r
60      */\r
61     if (pool.stir_pending)\r
62         return;\r
63     pool.stir_pending = TRUE;\r
64 \r
65     noise_get_light(random_add_noise);\r
66 \r
67     SHATransform((word32 *) pool.incoming, (word32 *) pool.incomingb);\r
68     pool.incomingpos = 0;\r
69 \r
70     /*\r
71      * Chunks of this code are blatantly endianness-dependent, but\r
72      * as it's all random bits anyway, WHO CARES?\r
73      */\r
74     memcpy(digest, pool.incoming, sizeof(digest));\r
75 \r
76     /*\r
77      * Make two passes over the pool.\r
78      */\r
79     for (i = 0; i < 2; i++) {\r
80 \r
81         /*\r
82          * We operate SHA in CFB mode, repeatedly adding the same\r
83          * block of data to the digest. But we're also fiddling\r
84          * with the digest-so-far, so this shouldn't be Bad or\r
85          * anything.\r
86          */\r
87         memcpy(block, pool.pool, sizeof(block));\r
88 \r
89         /*\r
90          * Each pass processes the pool backwards in blocks of\r
91          * HASHSIZE, just so that in general we get the output of\r
92          * SHA before the corresponding input, in the hope that\r
93          * things will be that much less predictable that way\r
94          * round, when we subsequently return bytes ...\r
95          */\r
96         for (j = POOLSIZE; (j -= HASHSIZE) >= 0;) {\r
97             /*\r
98              * XOR the bit of the pool we're processing into the\r
99              * digest.\r
100              */\r
101 \r
102             for (k = 0; k < sizeof(digest) / sizeof(*digest); k++)\r
103                 digest[k] ^= ((word32 *) (pool.pool + j))[k];\r
104 \r
105             /*\r
106              * Munge our unrevealed first block of the pool into\r
107              * it.\r
108              */\r
109             SHATransform(digest, block);\r
110 \r
111             /*\r
112              * Stick the result back into the pool.\r
113              */\r
114 \r
115             for (k = 0; k < sizeof(digest) / sizeof(*digest); k++)\r
116                 ((word32 *) (pool.pool + j))[k] = digest[k];\r
117         }\r
118     }\r
119 \r
120     /*\r
121      * Might as well save this value back into `incoming', just so\r
122      * there'll be some extra bizarreness there.\r
123      */\r
124     SHATransform(digest, block);\r
125     memcpy(pool.incoming, digest, sizeof(digest));\r
126 \r
127     pool.poolpos = sizeof(pool.incoming);\r
128 \r
129     pool.stir_pending = FALSE;\r
130 }\r
131 \r
132 void random_add_noise(void *noise, int length)\r
133 {\r
134     unsigned char *p = noise;\r
135     int i;\r
136 \r
137     if (!random_active)\r
138         return;\r
139 \r
140     /*\r
141      * This function processes HASHINPUT bytes into only HASHSIZE\r
142      * bytes, so _if_ we were getting incredibly high entropy\r
143      * sources then we would be throwing away valuable stuff.\r
144      */\r
145     while (length >= (HASHINPUT - pool.incomingpos)) {\r
146         memcpy(pool.incomingb + pool.incomingpos, p,\r
147                HASHINPUT - pool.incomingpos);\r
148         p += HASHINPUT - pool.incomingpos;\r
149         length -= HASHINPUT - pool.incomingpos;\r
150         SHATransform((word32 *) pool.incoming, (word32 *) pool.incomingb);\r
151         for (i = 0; i < HASHSIZE; i++) {\r
152             pool.pool[pool.poolpos++] ^= pool.incomingb[i];\r
153             if (pool.poolpos >= POOLSIZE)\r
154                 pool.poolpos = 0;\r
155         }\r
156         if (pool.poolpos < HASHSIZE)\r
157             random_stir();\r
158 \r
159         pool.incomingpos = 0;\r
160     }\r
161 \r
162     memcpy(pool.incomingb + pool.incomingpos, p, length);\r
163     pool.incomingpos += length;\r
164 }\r
165 \r
166 void random_add_heavynoise(void *noise, int length)\r
167 {\r
168     unsigned char *p = noise;\r
169     int i;\r
170 \r
171     while (length >= POOLSIZE) {\r
172         for (i = 0; i < POOLSIZE; i++)\r
173             pool.pool[i] ^= *p++;\r
174         random_stir();\r
175         length -= POOLSIZE;\r
176     }\r
177 \r
178     for (i = 0; i < length; i++)\r
179         pool.pool[i] ^= *p++;\r
180     random_stir();\r
181 }\r
182 \r
183 static void random_add_heavynoise_bitbybit(void *noise, int length)\r
184 {\r
185     unsigned char *p = noise;\r
186     int i;\r
187 \r
188     while (length >= POOLSIZE - pool.poolpos) {\r
189         for (i = 0; i < POOLSIZE - pool.poolpos; i++)\r
190             pool.pool[pool.poolpos + i] ^= *p++;\r
191         random_stir();\r
192         length -= POOLSIZE - pool.poolpos;\r
193         pool.poolpos = 0;\r
194     }\r
195 \r
196     for (i = 0; i < length; i++)\r
197         pool.pool[i] ^= *p++;\r
198     pool.poolpos = i;\r
199 }\r
200 \r
201 static void random_timer(void *ctx, long now)\r
202 {\r
203     if (random_active > 0 && now - next_noise_collection >= 0) {\r
204         noise_regular();\r
205         next_noise_collection =\r
206             schedule_timer(NOISE_REGULAR_INTERVAL, random_timer, &pool);\r
207     }\r
208 }\r
209 \r
210 void random_ref(void)\r
211 {\r
212     if (!random_active) {\r
213         memset(&pool, 0, sizeof(pool));    /* just to start with */\r
214 \r
215         noise_get_heavy(random_add_heavynoise_bitbybit);\r
216         random_stir();\r
217 \r
218         next_noise_collection =\r
219             schedule_timer(NOISE_REGULAR_INTERVAL, random_timer, &pool);\r
220     }\r
221 \r
222     random_active++;\r
223 }\r
224 \r
225 void random_unref(void)\r
226 {\r
227     random_active--;\r
228 }\r
229 \r
230 int random_byte(void)\r
231 {\r
232     if (pool.poolpos >= POOLSIZE)\r
233         random_stir();\r
234 \r
235     return pool.pool[pool.poolpos++];\r
236 }\r
237 \r
238 void random_get_savedata(void **data, int *len)\r
239 {\r
240     void *buf = snewn(POOLSIZE / 2, char);\r
241     random_stir();\r
242     memcpy(buf, pool.pool + pool.poolpos, POOLSIZE / 2);\r
243     *len = POOLSIZE / 2;\r
244     *data = buf;\r
245     random_stir();\r
246 }\r