source: trunk/src/rijndael-alg-fst.c @ 383

Last change on this file since 383 was 383, checked in by katerina, 10 years ago

Fix for ticket #281 (warnings from clang static analyzer).

File size: 14.1 KB
Line 
1/*
2 * rijndael-alg-fst.c   v2.3   April '2000
3 *
4 * Optimised ANSI C code
5 *
6 * authors: v1.0: Antoon Bosselaers
7 *          v2.0: Vincent Rijmen
8 *          v2.3: Paulo Barreto
9 *
10 * This code is placed in the public domain.
11 */
12
13#include "config_xor.h"
14
15#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18
19#ifdef SH_ENCRYPT
20
21#include "rijndael-alg-fst.h"
22
23#include "rijndael-boxes-fst.h"
24
25int rijndaelKeySched(word8 k[MAXKC][4], word8 W[MAXROUNDS+1][4][4], int ROUNDS) {
26        /* Calculate the necessary round keys
27         * The number of calculations depends on keyBits and blockBits
28         */ 
29        int j, r, t, rconpointer = 0;
30        word8 tk[MAXKC][4] = { { 0 } }; /* init for llvm/clang analyzer */
31        int KC = ROUNDS - 6;
32        word32 tmp;
33
34        for (j = KC-1; j >= 0; j--) {
35          memmove( &(tk[j]), &(k[j]), sizeof(word32));
36        }
37        r = 0;
38        t = 0;
39
40        /* copy values into round key array */
41        for (j = 0; (j < KC) && (r < ROUNDS + 1); ) {
42                for (; (j < KC) && (t < 4); j++, t++) {
43                  memmove( &(W[r][t]), &(tk[j]), sizeof(word32));
44                }
45                if (t == 4) {
46                        r++;
47                        t = 0;
48                }
49        }
50               
51        while (r < ROUNDS + 1) { /* while not enough round key material calculated */
52                /* calculate new values */
53                tk[0][0] ^= S[tk[KC-1][1]];
54                tk[0][1] ^= S[tk[KC-1][2]];
55                tk[0][2] ^= S[tk[KC-1][3]];
56                tk[0][3] ^= S[tk[KC-1][0]];
57                tk[0][0] ^= rcon[rconpointer++];
58
59                if (KC != 8) {
60                        for (j = 1; j < KC; j++) {
61                          tmp = *((word32*)tk[j-1]);
62                          *((word32*)tk[j]) ^= tmp;
63                        }
64                } else {
65                        for (j = 1; j < KC/2; j++) {
66                          tmp = *((word32*)tk[j-1]);
67                          *((word32*)tk[j]) ^= tmp;
68                        }
69                        tk[KC/2][0] ^= S[tk[KC/2 - 1][0]];
70                        tk[KC/2][1] ^= S[tk[KC/2 - 1][1]];
71                        tk[KC/2][2] ^= S[tk[KC/2 - 1][2]];
72                        tk[KC/2][3] ^= S[tk[KC/2 - 1][3]];
73                        for (j = KC/2 + 1; j < KC; j++) {
74                                tmp = *((word32*)tk[j-1]);
75                                *((word32*)tk[j]) ^= tmp;
76                        }
77                }
78                /* copy values into round key array */
79                for (j = 0; (j < KC) && (r < ROUNDS + 1); ) {
80                        for (; (j < KC) && (t < 4); j++, t++) {
81                          memmove( &(W[r][t]), &(tk[j]), sizeof(word32));
82                        }
83                        if (t == 4) {
84                                r++;
85                                t = 0;
86                        }
87                }
88        }               
89        return 0;
90}
91
92int rijndaelKeyEncToDec(word8 W[MAXROUNDS+1][4][4], int ROUNDS) {
93        int r;
94        word8 *w;
95
96        for (r = 1; r < ROUNDS; r++) {
97                w = W[r][0];
98                *((word32*)w) =
99                          *((word32*)U1[w[0]])
100                        ^ *((word32*)U2[w[1]])
101                        ^ *((word32*)U3[w[2]])
102                        ^ *((word32*)U4[w[3]]);
103
104                w = W[r][1];
105                *((word32*)w) =
106                          *((word32*)U1[w[0]])
107                        ^ *((word32*)U2[w[1]])
108                        ^ *((word32*)U3[w[2]])
109                        ^ *((word32*)U4[w[3]]);
110
111                w = W[r][2];
112                *((word32*)w) =
113                          *((word32*)U1[w[0]])
114                        ^ *((word32*)U2[w[1]])
115                        ^ *((word32*)U3[w[2]])
116                        ^ *((word32*)U4[w[3]]);
117
118                w = W[r][3];
119                *((word32*)w) =
120                          *((word32*)U1[w[0]])
121                        ^ *((word32*)U2[w[1]])
122                        ^ *((word32*)U3[w[2]])
123                        ^ *((word32*)U4[w[3]]);
124        }
125        return 0;
126}       
127
128/**
129 * Encrypt a single block.
130 */
131int rijndaelEncrypt(word8 a[16], word8 b[16], word8 rk[MAXROUNDS+1][4][4], int ROUNDS) {
132        int r;
133        union {
134          word32 tem4[4];
135          word8  temp[4][4];
136        } tmpU;
137        tmpU.tem4[0] = tmpU.tem4[1] = tmpU.tem4[2] = tmpU.tem4[3] = 0;
138
139    tmpU.tem4[0] = *((word32*)(a   )) ^ *((word32*)rk[0][0]);
140    tmpU.tem4[1] = *((word32*)(a+ 4)) ^ *((word32*)rk[0][1]);
141    tmpU.tem4[2] = *((word32*)(a+ 8)) ^ *((word32*)rk[0][2]);
142    tmpU.tem4[3] = *((word32*)(a+12)) ^ *((word32*)rk[0][3]);
143    *((word32*)(b    )) = *((word32*)T1[tmpU.temp[0][0]])
144                                                ^ *((word32*)T2[tmpU.temp[1][1]])
145                                                ^ *((word32*)T3[tmpU.temp[2][2]]) 
146                                                ^ *((word32*)T4[tmpU.temp[3][3]]);
147    *((word32*)(b + 4)) = *((word32*)T1[tmpU.temp[1][0]])
148                                                ^ *((word32*)T2[tmpU.temp[2][1]])
149                                                ^ *((word32*)T3[tmpU.temp[3][2]]) 
150                                                ^ *((word32*)T4[tmpU.temp[0][3]]);
151    *((word32*)(b + 8)) = *((word32*)T1[tmpU.temp[2][0]])
152                                                ^ *((word32*)T2[tmpU.temp[3][1]])
153                                                ^ *((word32*)T3[tmpU.temp[0][2]]) 
154                                                ^ *((word32*)T4[tmpU.temp[1][3]]);
155    *((word32*)(b +12)) = *((word32*)T1[tmpU.temp[3][0]])
156                                                ^ *((word32*)T2[tmpU.temp[0][1]])
157                                                ^ *((word32*)T3[tmpU.temp[1][2]]) 
158                                                ^ *((word32*)T4[tmpU.temp[2][3]]);
159        for (r = 1; r < ROUNDS-1; r++) {
160                tmpU.tem4[0] = *((word32*)(b   )) ^ *((word32*)rk[r][0]);
161                tmpU.tem4[1] = *((word32*)(b+ 4)) ^ *((word32*)rk[r][1]);
162                tmpU.tem4[2] = *((word32*)(b+ 8)) ^ *((word32*)rk[r][2]);
163                tmpU.tem4[3] = *((word32*)(b+12)) ^ *((word32*)rk[r][3]);
164
165                *((word32*)(b    )) = *((word32*)T1[tmpU.temp[0][0]])
166                                                        ^ *((word32*)T2[tmpU.temp[1][1]])
167                                                        ^ *((word32*)T3[tmpU.temp[2][2]]) 
168                                                        ^ *((word32*)T4[tmpU.temp[3][3]]);
169                *((word32*)(b + 4)) = *((word32*)T1[tmpU.temp[1][0]])
170                                                        ^ *((word32*)T2[tmpU.temp[2][1]])
171                                                        ^ *((word32*)T3[tmpU.temp[3][2]]) 
172                                                        ^ *((word32*)T4[tmpU.temp[0][3]]);
173                *((word32*)(b + 8)) = *((word32*)T1[tmpU.temp[2][0]])
174                                                        ^ *((word32*)T2[tmpU.temp[3][1]])
175                                                        ^ *((word32*)T3[tmpU.temp[0][2]]) 
176                                                        ^ *((word32*)T4[tmpU.temp[1][3]]);
177                *((word32*)(b +12)) = *((word32*)T1[tmpU.temp[3][0]])
178                                                        ^ *((word32*)T2[tmpU.temp[0][1]])
179                                                        ^ *((word32*)T3[tmpU.temp[1][2]]) 
180                                                        ^ *((word32*)T4[tmpU.temp[2][3]]);
181        }
182        /* last round is special */   
183        tmpU.tem4[0] = *((word32*)(b   )) ^ *((word32*)rk[ROUNDS-1][0]);
184        tmpU.tem4[1] = *((word32*)(b+ 4)) ^ *((word32*)rk[ROUNDS-1][1]);
185        tmpU.tem4[2] = *((word32*)(b+ 8)) ^ *((word32*)rk[ROUNDS-1][2]);
186        tmpU.tem4[3] = *((word32*)(b+12)) ^ *((word32*)rk[ROUNDS-1][3]);
187        b[ 0] = T1[tmpU.temp[0][0]][1];
188        b[ 1] = T1[tmpU.temp[1][1]][1];
189        b[ 2] = T1[tmpU.temp[2][2]][1];
190        b[ 3] = T1[tmpU.temp[3][3]][1];
191        b[ 4] = T1[tmpU.temp[1][0]][1];
192        b[ 5] = T1[tmpU.temp[2][1]][1];
193        b[ 6] = T1[tmpU.temp[3][2]][1];
194        b[ 7] = T1[tmpU.temp[0][3]][1];
195        b[ 8] = T1[tmpU.temp[2][0]][1];
196        b[ 9] = T1[tmpU.temp[3][1]][1];
197        b[10] = T1[tmpU.temp[0][2]][1];
198        b[11] = T1[tmpU.temp[1][3]][1];
199        b[12] = T1[tmpU.temp[3][0]][1];
200        b[13] = T1[tmpU.temp[0][1]][1];
201        b[14] = T1[tmpU.temp[1][2]][1];
202        b[15] = T1[tmpU.temp[2][3]][1];
203        *((word32*)(b   )) ^= *((word32*)rk[ROUNDS][0]);
204        *((word32*)(b+ 4)) ^= *((word32*)rk[ROUNDS][1]);
205        *((word32*)(b+ 8)) ^= *((word32*)rk[ROUNDS][2]);
206        *((word32*)(b+12)) ^= *((word32*)rk[ROUNDS][3]);
207
208        return 0;
209}
210
211/**
212 * Decrypt a single block.
213 */
214int rijndaelDecrypt(word8 a[16], word8 b[16], word8 rk[MAXROUNDS+1][4][4], int ROUNDS) {
215        int r;
216        union {
217          word32 tem4[4];
218          word8  temp[4][4];
219        } tmpU;
220        tmpU.tem4[0] = tmpU.tem4[1] = tmpU.tem4[2] = tmpU.tem4[3] = 0;
221       
222    tmpU.tem4[0] = *((word32*)(a   )) ^ *((word32*)rk[ROUNDS][0]);
223    tmpU.tem4[1] = *((word32*)(a+ 4)) ^ *((word32*)rk[ROUNDS][1]);
224    tmpU.tem4[2] = *((word32*)(a+ 8)) ^ *((word32*)rk[ROUNDS][2]);
225    tmpU.tem4[3] = *((word32*)(a+12)) ^ *((word32*)rk[ROUNDS][3]);
226
227    *((word32*)(b   )) = *((word32*)T5[tmpU.temp[0][0]])
228           ^ *((word32*)T6[tmpU.temp[3][1]])
229           ^ *((word32*)T7[tmpU.temp[2][2]]) 
230           ^ *((word32*)T8[tmpU.temp[1][3]]);
231        *((word32*)(b+ 4)) = *((word32*)T5[tmpU.temp[1][0]])
232           ^ *((word32*)T6[tmpU.temp[0][1]])
233           ^ *((word32*)T7[tmpU.temp[3][2]]) 
234           ^ *((word32*)T8[tmpU.temp[2][3]]);
235        *((word32*)(b+ 8)) = *((word32*)T5[tmpU.temp[2][0]])
236           ^ *((word32*)T6[tmpU.temp[1][1]])
237           ^ *((word32*)T7[tmpU.temp[0][2]]) 
238           ^ *((word32*)T8[tmpU.temp[3][3]]);
239        *((word32*)(b+12)) = *((word32*)T5[tmpU.temp[3][0]])
240           ^ *((word32*)T6[tmpU.temp[2][1]])
241           ^ *((word32*)T7[tmpU.temp[1][2]]) 
242           ^ *((word32*)T8[tmpU.temp[0][3]]);
243        for (r = ROUNDS-1; r > 1; r--) {
244                tmpU.tem4[0] = *((word32*)(b   )) ^ *((word32*)rk[r][0]);
245                tmpU.tem4[1] = *((word32*)(b+ 4)) ^ *((word32*)rk[r][1]);
246                tmpU.tem4[2] = *((word32*)(b+ 8)) ^ *((word32*)rk[r][2]);
247                tmpU.tem4[3] = *((word32*)(b+12)) ^ *((word32*)rk[r][3]);
248                *((word32*)(b   )) = *((word32*)T5[tmpU.temp[0][0]])
249           ^ *((word32*)T6[tmpU.temp[3][1]])
250           ^ *((word32*)T7[tmpU.temp[2][2]]) 
251           ^ *((word32*)T8[tmpU.temp[1][3]]);
252                *((word32*)(b+ 4)) = *((word32*)T5[tmpU.temp[1][0]])
253           ^ *((word32*)T6[tmpU.temp[0][1]])
254           ^ *((word32*)T7[tmpU.temp[3][2]]) 
255           ^ *((word32*)T8[tmpU.temp[2][3]]);
256                *((word32*)(b+ 8)) = *((word32*)T5[tmpU.temp[2][0]])
257           ^ *((word32*)T6[tmpU.temp[1][1]])
258           ^ *((word32*)T7[tmpU.temp[0][2]]) 
259           ^ *((word32*)T8[tmpU.temp[3][3]]);
260                *((word32*)(b+12)) = *((word32*)T5[tmpU.temp[3][0]])
261           ^ *((word32*)T6[tmpU.temp[2][1]])
262           ^ *((word32*)T7[tmpU.temp[1][2]]) 
263           ^ *((word32*)T8[tmpU.temp[0][3]]);
264        }
265        /* last round is special */   
266        tmpU.tem4[0] = *((word32*)(b   )) ^ *((word32*)rk[1][0]);
267        tmpU.tem4[1] = *((word32*)(b+ 4)) ^ *((word32*)rk[1][1]);
268        tmpU.tem4[2] = *((word32*)(b+ 8)) ^ *((word32*)rk[1][2]);
269        tmpU.tem4[3] = *((word32*)(b+12)) ^ *((word32*)rk[1][3]);
270        b[ 0] = S5[tmpU.temp[0][0]];
271        b[ 1] = S5[tmpU.temp[3][1]];
272        b[ 2] = S5[tmpU.temp[2][2]];
273        b[ 3] = S5[tmpU.temp[1][3]];
274        b[ 4] = S5[tmpU.temp[1][0]];
275        b[ 5] = S5[tmpU.temp[0][1]];
276        b[ 6] = S5[tmpU.temp[3][2]];
277        b[ 7] = S5[tmpU.temp[2][3]];
278        b[ 8] = S5[tmpU.temp[2][0]];
279        b[ 9] = S5[tmpU.temp[1][1]];
280        b[10] = S5[tmpU.temp[0][2]];
281        b[11] = S5[tmpU.temp[3][3]];
282        b[12] = S5[tmpU.temp[3][0]];
283        b[13] = S5[tmpU.temp[2][1]];
284        b[14] = S5[tmpU.temp[1][2]];
285        b[15] = S5[tmpU.temp[0][3]];
286        *((word32*)(b   )) ^= *((word32*)rk[0][0]);
287        *((word32*)(b+ 4)) ^= *((word32*)rk[0][1]);
288        *((word32*)(b+ 8)) ^= *((word32*)rk[0][2]);
289        *((word32*)(b+12)) ^= *((word32*)rk[0][3]);
290
291        return 0;
292}
293
294#ifdef INTERMEDIATE_VALUE_KAT
295/**
296 * Encrypt only a certain number of rounds.
297 * Only used in the Intermediate Value Known Answer Test.
298 */
299int rijndaelEncryptRound(word8 a[4][4], word8 rk[MAXROUNDS+1][4][4], int ROUNDS, int rounds) {
300        int r;
301        word8 temp[4][4];
302
303        /* make number of rounds sane */
304        if (rounds > ROUNDS) {
305                rounds = ROUNDS;
306        }
307
308        *((word32*)a[0]) = *((word32*)a[0]) ^ *((word32*)rk[0][0]);
309        *((word32*)a[1]) = *((word32*)a[1]) ^ *((word32*)rk[0][1]);
310        *((word32*)a[2]) = *((word32*)a[2]) ^ *((word32*)rk[0][2]);
311        *((word32*)a[3]) = *((word32*)a[3]) ^ *((word32*)rk[0][3]);
312
313        for (r = 1; (r <= rounds) && (r < ROUNDS); r++) {
314                *((word32*)temp[0]) = *((word32*)T1[a[0][0]])
315           ^ *((word32*)T2[a[1][1]])
316           ^ *((word32*)T3[a[2][2]]) 
317           ^ *((word32*)T4[a[3][3]]);
318                *((word32*)temp[1]) = *((word32*)T1[a[1][0]])
319           ^ *((word32*)T2[a[2][1]])
320           ^ *((word32*)T3[a[3][2]]) 
321           ^ *((word32*)T4[a[0][3]]);
322                *((word32*)temp[2]) = *((word32*)T1[a[2][0]])
323           ^ *((word32*)T2[a[3][1]])
324           ^ *((word32*)T3[a[0][2]]) 
325           ^ *((word32*)T4[a[1][3]]);
326                *((word32*)temp[3]) = *((word32*)T1[a[3][0]])
327           ^ *((word32*)T2[a[0][1]])
328           ^ *((word32*)T3[a[1][2]]) 
329           ^ *((word32*)T4[a[2][3]]);
330                *((word32*)a[0]) = *((word32*)temp[0]) ^ *((word32*)rk[r][0]);
331                *((word32*)a[1]) = *((word32*)temp[1]) ^ *((word32*)rk[r][1]);
332                *((word32*)a[2]) = *((word32*)temp[2]) ^ *((word32*)rk[r][2]);
333                *((word32*)a[3]) = *((word32*)temp[3]) ^ *((word32*)rk[r][3]);
334        }
335        if (rounds == ROUNDS) {
336                /* last round is special */   
337                temp[0][0] = T1[a[0][0]][1];
338                temp[0][1] = T1[a[1][1]][1];
339                temp[0][2] = T1[a[2][2]][1]; 
340                temp[0][3] = T1[a[3][3]][1];
341                temp[1][0] = T1[a[1][0]][1];
342                temp[1][1] = T1[a[2][1]][1];
343                temp[1][2] = T1[a[3][2]][1]; 
344                temp[1][3] = T1[a[0][3]][1];
345                temp[2][0] = T1[a[2][0]][1];
346                temp[2][1] = T1[a[3][1]][1];
347                temp[2][2] = T1[a[0][2]][1]; 
348                temp[2][3] = T1[a[1][3]][1];
349                temp[3][0] = T1[a[3][0]][1];
350                temp[3][1] = T1[a[0][1]][1];
351                temp[3][2] = T1[a[1][2]][1]; 
352                temp[3][3] = T1[a[2][3]][1];
353                *((word32*)a[0]) = *((word32*)temp[0]) ^ *((word32*)rk[ROUNDS][0]);
354                *((word32*)a[1]) = *((word32*)temp[1]) ^ *((word32*)rk[ROUNDS][1]);
355                *((word32*)a[2]) = *((word32*)temp[2]) ^ *((word32*)rk[ROUNDS][2]);
356                *((word32*)a[3]) = *((word32*)temp[3]) ^ *((word32*)rk[ROUNDS][3]);
357        }
358
359        return 0;
360}   
361#endif /* INTERMEDIATE_VALUE_KAT */
362
363#ifdef INTERMEDIATE_VALUE_KAT
364/**
365 * Decrypt only a certain number of rounds.
366 * Only used in the Intermediate Value Known Answer Test.
367 * Operations rearranged such that the intermediate values
368 * of decryption correspond with the intermediate values
369 * of encryption.
370 */
371int rijndaelDecryptRound(word8 a[4][4], word8 rk[MAXROUNDS+1][4][4], int ROUNDS, int rounds) {
372        int r, i;
373        word8 temp[4], shift;
374
375        /* make number of rounds sane */
376        if (rounds > ROUNDS) {
377                rounds = ROUNDS;
378        }
379    /* first round is special: */
380        *(word32 *)a[0] ^= *(word32 *)rk[ROUNDS][0];
381        *(word32 *)a[1] ^= *(word32 *)rk[ROUNDS][1];
382        *(word32 *)a[2] ^= *(word32 *)rk[ROUNDS][2];
383        *(word32 *)a[3] ^= *(word32 *)rk[ROUNDS][3];
384        for (i = 0; i < 4; i++) {
385                a[i][0] = Si[a[i][0]];
386                a[i][1] = Si[a[i][1]];
387                a[i][2] = Si[a[i][2]];
388                a[i][3] = Si[a[i][3]];
389        }
390        for (i = 1; i < 4; i++) {
391                shift = (4 - i) & 3;
392                temp[0] = a[(0 + shift) & 3][i];
393                temp[1] = a[(1 + shift) & 3][i];
394                temp[2] = a[(2 + shift) & 3][i];
395                temp[3] = a[(3 + shift) & 3][i];
396                a[0][i] = temp[0];
397                a[1][i] = temp[1];
398                a[2][i] = temp[2];
399                a[3][i] = temp[3];
400        }
401        /* ROUNDS-1 ordinary rounds */
402        for (r = ROUNDS-1; r > rounds; r--) {
403                *(word32 *)a[0] ^= *(word32 *)rk[r][0];
404                *(word32 *)a[1] ^= *(word32 *)rk[r][1];
405                *(word32 *)a[2] ^= *(word32 *)rk[r][2];
406                *(word32 *)a[3] ^= *(word32 *)rk[r][3];
407
408                *((word32*)a[0]) =
409                          *((word32*)U1[a[0][0]])
410                        ^ *((word32*)U2[a[0][1]])
411                        ^ *((word32*)U3[a[0][2]])
412                        ^ *((word32*)U4[a[0][3]]);
413
414                *((word32*)a[1]) =
415                          *((word32*)U1[a[1][0]])
416                        ^ *((word32*)U2[a[1][1]])
417                        ^ *((word32*)U3[a[1][2]])
418                        ^ *((word32*)U4[a[1][3]]);
419
420                *((word32*)a[2]) =
421                          *((word32*)U1[a[2][0]])
422                        ^ *((word32*)U2[a[2][1]])
423                        ^ *((word32*)U3[a[2][2]])
424                        ^ *((word32*)U4[a[2][3]]);
425
426                *((word32*)a[3]) =
427                          *((word32*)U1[a[3][0]])
428                        ^ *((word32*)U2[a[3][1]])
429                        ^ *((word32*)U3[a[3][2]])
430                        ^ *((word32*)U4[a[3][3]]);
431                for (i = 0; i < 4; i++) {
432                        a[i][0] = Si[a[i][0]];
433                        a[i][1] = Si[a[i][1]];
434                        a[i][2] = Si[a[i][2]];
435                        a[i][3] = Si[a[i][3]];
436                }
437                for (i = 1; i < 4; i++) {
438                        shift = (4 - i) & 3;
439                        temp[0] = a[(0 + shift) & 3][i];
440                        temp[1] = a[(1 + shift) & 3][i];
441                        temp[2] = a[(2 + shift) & 3][i];
442                        temp[3] = a[(3 + shift) & 3][i];
443                        a[0][i] = temp[0];
444                        a[1][i] = temp[1];
445                        a[2][i] = temp[2];
446                        a[3][i] = temp[3];
447                }
448        }
449        if (rounds == 0) {
450                /* End with the extra key addition */   
451                *(word32 *)a[0] ^= *(word32 *)rk[0][0];
452                *(word32 *)a[1] ^= *(word32 *)rk[0][1];
453                *(word32 *)a[2] ^= *(word32 *)rk[0][2];
454                *(word32 *)a[3] ^= *(word32 *)rk[0][3];
455        }   
456        return 0;
457}
458#endif /* INTERMEDIATE_VALUE_KAT */
459#endif
Note: See TracBrowser for help on using the repository browser.