• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.14.38 API Reference
  • KDE Home
  • Contact Us
 

KIO

  • kio
  • misc
  • kntlm
des.cpp
Go to the documentation of this file.
1/*
2 * Sofware DES functions
3 *
4 * Copyright 1988-1991 Phil Karn <karn@ka9q.net>
5 * Copyright 2003 Nikos Mavroyanopoulos <nmav@hellug.gr>
6 *
7 * Taken from libmcrypt (http://mcrypt.hellug.gr/lib/index.html).
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21 * MA 02110-1301 USA
22 */
23
24/* Sofware DES functions
25 * written 12 Dec 1986 by Phil Karn, KA9Q; large sections adapted from
26 * the 1977 public-domain program by Jim Gillogly
27 * Modified for additional speed - 6 December 1988 Phil Karn
28 * Modified for parameterized key schedules - Jan 1991 Phil Karn
29 * Callers now allocate a key schedule as follows:
30 * kn = (char (*)[8])malloc(sizeof(char) * 8 * 16);
31 * or
32 * char kn[16][8];
33 */
34
35/* modified in order to use the libmcrypt API by Nikos Mavroyanopoulos
36 * All modifications are placed under the license of libmcrypt.
37 */
38
39
40#include "des.h"
41
42#include <string.h>
43#include <QtCore/qendian.h>
44
45static void permute_ip (unsigned char *inblock, DES_KEY * key, unsigned char *outblock);
46static void permute_fp (unsigned char *inblock, DES_KEY * key, unsigned char *outblock);
47static void perminit_ip (DES_KEY * key);
48static void spinit (DES_KEY * key);
49static void perminit_fp (DES_KEY * key);
50static quint32 f (DES_KEY * key, quint32 r, char *subkey);
51
52
53/* Tables defined in the Data Encryption Standard documents */
54
55/* initial permutation IP */
56static const char ip[] = {
57 58, 50, 42, 34, 26, 18, 10, 2,
58 60, 52, 44, 36, 28, 20, 12, 4,
59 62, 54, 46, 38, 30, 22, 14, 6,
60 64, 56, 48, 40, 32, 24, 16, 8,
61 57, 49, 41, 33, 25, 17, 9, 1,
62 59, 51, 43, 35, 27, 19, 11, 3,
63 61, 53, 45, 37, 29, 21, 13, 5,
64 63, 55, 47, 39, 31, 23, 15, 7
65};
66
67/* final permutation IP^-1 */
68static const char fp[] = {
69 40, 8, 48, 16, 56, 24, 64, 32,
70 39, 7, 47, 15, 55, 23, 63, 31,
71 38, 6, 46, 14, 54, 22, 62, 30,
72 37, 5, 45, 13, 53, 21, 61, 29,
73 36, 4, 44, 12, 52, 20, 60, 28,
74 35, 3, 43, 11, 51, 19, 59, 27,
75 34, 2, 42, 10, 50, 18, 58, 26,
76 33, 1, 41, 9, 49, 17, 57, 25
77};
78
79/* expansion operation matrix
80 * This is for reference only; it is unused in the code
81 * as the f() function performs it implicitly for speed
82 */
83#ifdef notdef
84static const char ei[] = {
85 32, 1, 2, 3, 4, 5,
86 4, 5, 6, 7, 8, 9,
87 8, 9, 10, 11, 12, 13,
88 12, 13, 14, 15, 16, 17,
89 16, 17, 18, 19, 20, 21,
90 20, 21, 22, 23, 24, 25,
91 24, 25, 26, 27, 28, 29,
92 28, 29, 30, 31, 32, 1
93};
94#endif
95
96/* permuted choice table (key) */
97static const char pc1[] = {
98 57, 49, 41, 33, 25, 17, 9,
99 1, 58, 50, 42, 34, 26, 18,
100 10, 2, 59, 51, 43, 35, 27,
101 19, 11, 3, 60, 52, 44, 36,
102
103 63, 55, 47, 39, 31, 23, 15,
104 7, 62, 54, 46, 38, 30, 22,
105 14, 6, 61, 53, 45, 37, 29,
106 21, 13, 5, 28, 20, 12, 4
107};
108
109/* number left rotations of pc1 */
110static const char totrot[] = {
111 1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28
112};
113
114/* permuted choice key (table) */
115static const char pc2[] = {
116 14, 17, 11, 24, 1, 5,
117 3, 28, 15, 6, 21, 10,
118 23, 19, 12, 4, 26, 8,
119 16, 7, 27, 20, 13, 2,
120 41, 52, 31, 37, 47, 55,
121 30, 40, 51, 45, 33, 48,
122 44, 49, 39, 56, 34, 53,
123 46, 42, 50, 36, 29, 32
124};
125
126/* The (in)famous S-boxes */
127static const char si[8][64] = {
128 /* S1 */
129 {14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
130 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
131 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
132 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13},
133
134 /* S2 */
135 {15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
136 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
137 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
138 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9},
139
140 /* S3 */
141 {10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
142 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
143 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
144 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12},
145
146 /* S4 */
147 {7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
148 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
149 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
150 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14},
151
152 /* S5 */
153 {2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
154 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
155 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
156 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3},
157
158 /* S6 */
159 {12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
160 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
161 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
162 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13},
163
164 /* S7 */
165 {4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
166 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
167 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
168 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12},
169
170 /* S8 */
171 {13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
172 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
173 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
174 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11},
175
176};
177
178/* 32-bit permutation function P used on the output of the S-boxes */
179static const char p32i[] = {
180 16, 7, 20, 21,
181 29, 12, 28, 17,
182 1, 15, 23, 26,
183 5, 18, 31, 10,
184 2, 8, 24, 14,
185 32, 27, 3, 9,
186 19, 13, 30, 6,
187 22, 11, 4, 25
188};
189
190/* End of DES-defined tables */
191
192/* Lookup tables initialized once only at startup by desinit() */
193
194/* bit 0 is left-most in byte */
195static const int bytebit[] = {
196 0200, 0100, 040, 020, 010, 04, 02, 01
197};
198
199static const int nibblebit[] = {
200 010, 04, 02, 01
201};
202
203/* Allocate space and initialize DES lookup arrays
204 * mode == 0: standard Data Encryption Algorithm
205 */
206static int
207desinit (DES_KEY * key)
208{
209
210 spinit (key);
211 perminit_ip (key);
212 perminit_fp (key);
213
214 return 0;
215}
216
217
218/* Set key (initialize key schedule array) */
219int
220ntlm_des_set_key (DES_KEY * dkey, char *user_key, int /*len*/)
221{
222 char pc1m[56]; /* place to modify pc1 into */
223 char pcr[56]; /* place to rotate pc1 into */
224 int i, j, l;
225 int m;
226
227 memset(dkey, 0, sizeof (DES_KEY));
228 desinit (dkey);
229
230 /* Clear key schedule */
231
232
233 for (j = 0; j < 56; ++j)
234 { /* convert pc1 to bits of key */
235 l = pc1[j] - 1; /* integer bit location */
236 m = l & 07; /* find bit */
237 pc1m[j] = (user_key[l >> 3] & /* find which key byte l is in */
238 bytebit[m]) /* and which bit of that byte */
239 ? 1 : 0; /* and store 1-bit result */
240
241 }
242 for (i = 0; i < 16; ++i)
243 { /* key chunk for each iteration */
244 for (j = 0; j < 56; ++j) /* rotate pc1 the right amount */
245 pcr[j] = pc1m[(l = j + totrot[i]) < (j < 28 ? 28 : 56) ? l : l - 28];
246 /* rotate left and right halves independently */
247 for (j = 0; j < 48; ++j)
248 { /* select bits individually */
249 /* check bit that goes to kn[j] */
250 if (pcr[pc2[j] - 1])
251 {
252 /* mask it in if it's there */
253 l = j % 6;
254 dkey->kn[i][j / 6] |= bytebit[l] >> 2;
255 }
256 }
257 }
258 return 0;
259}
260
261/* In-place encryption of 64-bit block */
262static void
263ntlm_des_encrypt (DES_KEY * key, unsigned char *block)
264{
265 quint32 left, right;
266 char *knp;
267 quint32 work[2]; /* Working data storage */
268
269 permute_ip (block, key, (unsigned char *) work); /* Initial Permutation */
270 left = qFromBigEndian(work[0]);
271 right = qFromBigEndian(work[1]);
272
273 /* Do the 16 rounds.
274 * The rounds are numbered from 0 to 15. On even rounds
275 * the right half is fed to f() and the result exclusive-ORs
276 * the left half; on odd rounds the reverse is done.
277 */
278 knp = &key->kn[0][0];
279 left ^= f (key, right, knp);
280 knp += 8;
281 right ^= f (key, left, knp);
282 knp += 8;
283 left ^= f (key, right, knp);
284 knp += 8;
285 right ^= f (key, left, knp);
286 knp += 8;
287 left ^= f (key, right, knp);
288 knp += 8;
289 right ^= f (key, left, knp);
290 knp += 8;
291 left ^= f (key, right, knp);
292 knp += 8;
293 right ^= f (key, left, knp);
294 knp += 8;
295 left ^= f (key, right, knp);
296 knp += 8;
297 right ^= f (key, left, knp);
298 knp += 8;
299 left ^= f (key, right, knp);
300 knp += 8;
301 right ^= f (key, left, knp);
302 knp += 8;
303 left ^= f (key, right, knp);
304 knp += 8;
305 right ^= f (key, left, knp);
306 knp += 8;
307 left ^= f (key, right, knp);
308 knp += 8;
309 right ^= f (key, left, knp);
310
311 /* Left/right half swap, plus byte swap if little-endian */
312 work[1] = qToBigEndian( left );
313 work[0] = qToBigEndian( right );
314
315 permute_fp ((unsigned char *) work, key, block); /* Inverse initial permutation */
316}
317
318/* Permute inblock with perm */
319static void
320permute_ip (unsigned char *inblock, DES_KEY * key, unsigned char *outblock)
321{
322 unsigned char *ib, *ob; /* ptr to input or output block */
323 char *p, *q;
324 int j;
325
326 /* Clear output block */
327 memset(outblock, 0, 8);
328
329 ib = inblock;
330 for (j = 0; j < 16; j += 2, ++ib)
331 { /* for each input nibble */
332 ob = outblock;
333 p = key->iperm[j][(*ib >> 4) & 0xf];
334 q = key->iperm[j + 1][*ib & 0xf];
335 /* and each output byte, OR the masks together */
336 *ob++ |= *p++ | *q++;
337 *ob++ |= *p++ | *q++;
338 *ob++ |= *p++ | *q++;
339 *ob++ |= *p++ | *q++;
340 *ob++ |= *p++ | *q++;
341 *ob++ |= *p++ | *q++;
342 *ob++ |= *p++ | *q++;
343 *ob++ |= *p++ | *q++;
344 }
345}
346
347/* Permute inblock with perm */
348static void
349permute_fp (unsigned char *inblock, DES_KEY * key, unsigned char *outblock)
350{
351 unsigned char *ib, *ob; /* ptr to input or output block */
352 char *p, *q;
353 int j;
354
355 /* Clear output block */
356 memset(outblock, 0, 8);
357
358 ib = inblock;
359 for (j = 0; j < 16; j += 2, ++ib)
360 { /* for each input nibble */
361 ob = outblock;
362 p = key->fperm[j][(*ib >> 4) & 0xf];
363 q = key->fperm[j + 1][*ib & 0xf];
364 /* and each output byte, OR the masks together */
365 *ob++ |= *p++ | *q++;
366 *ob++ |= *p++ | *q++;
367 *ob++ |= *p++ | *q++;
368 *ob++ |= *p++ | *q++;
369 *ob++ |= *p++ | *q++;
370 *ob++ |= *p++ | *q++;
371 *ob++ |= *p++ | *q++;
372 *ob++ |= *p++ | *q++;
373 }
374}
375
376/* The nonlinear function f(r,k), the heart of DES */
377static quint32
378f (DES_KEY * key, quint32 r, char *subkey)
379{
380 quint32 *spp;
381 quint32 rval, rt;
382 int er;
383
384#ifdef TRACE
385 printf ("f(%08lx, %02x %02x %02x %02x %02x %02x %02x %02x) = ",
386 r,
387 subkey[0], subkey[1], subkey[2],
388 subkey[3], subkey[4], subkey[5], subkey[6], subkey[7]);
389#endif
390 /* Run E(R) ^ K through the combined S & P boxes.
391 * This code takes advantage of a convenient regularity in
392 * E, namely that each group of 6 bits in E(R) feeding
393 * a single S-box is a contiguous segment of R.
394 */
395 subkey += 7;
396
397 /* Compute E(R) for each block of 6 bits, and run thru boxes */
398 er = ((int) r << 1) | ((r & 0x80000000) ? 1 : 0);
399 spp = &key->sp[7][0];
400 rval = spp[(er ^ *subkey--) & 0x3f];
401 spp -= 64;
402 rt = (quint32) r >> 3;
403 rval |= spp[((int) rt ^ *subkey--) & 0x3f];
404 spp -= 64;
405 rt >>= 4;
406 rval |= spp[((int) rt ^ *subkey--) & 0x3f];
407 spp -= 64;
408 rt >>= 4;
409 rval |= spp[((int) rt ^ *subkey--) & 0x3f];
410 spp -= 64;
411 rt >>= 4;
412 rval |= spp[((int) rt ^ *subkey--) & 0x3f];
413 spp -= 64;
414 rt >>= 4;
415 rval |= spp[((int) rt ^ *subkey--) & 0x3f];
416 spp -= 64;
417 rt >>= 4;
418 rval |= spp[((int) rt ^ *subkey--) & 0x3f];
419 spp -= 64;
420 rt >>= 4;
421 rt |= (r & 1) << 5;
422 rval |= spp[((int) rt ^ *subkey) & 0x3f];
423#ifdef TRACE
424 printf (" %08lx\n", rval);
425#endif
426 return rval;
427}
428
429/* initialize a perm array */
430static void
431perminit_ip (DES_KEY * key)
432{
433 int l, j, k;
434 int i, m;
435
436 /* Clear the permutation array */
437 memset(key->iperm, 0, 16 * 16 * 8);
438
439 for (i = 0; i < 16; ++i) /* each input nibble position */
440 for (j = 0; j < 16; ++j) /* each possible input nibble */
441 for (k = 0; k < 64; ++k)
442 { /* each output bit position */
443 l = ip[k] - 1; /* where does this bit come from */
444 if ((l >> 2) != i) /* does it come from input posn? */
445 continue; /* if not, bit k is 0 */
446 if (!(j & nibblebit[l & 3]))
447 continue; /* any such bit in input? */
448 m = k & 07; /* which bit is this in the byte */
449 key->iperm[i][j][k >> 3] |= bytebit[m];
450 }
451}
452
453static void
454perminit_fp (DES_KEY * key)
455{
456 int l, j, k;
457 int i, m;
458
459 /* Clear the permutation array */
460 memset(key->fperm, 0, 16 * 16 * 8);
461
462 for (i = 0; i < 16; ++i) /* each input nibble position */
463 for (j = 0; j < 16; ++j) /* each possible input nibble */
464 for (k = 0; k < 64; ++k)
465 { /* each output bit position */
466 l = fp[k] - 1; /* where does this bit come from */
467 if ((l >> 2) != i) /* does it come from input posn? */
468 continue; /* if not, bit k is 0 */
469 if (!(j & nibblebit[l & 3]))
470 continue; /* any such bit in input? */
471 m = k & 07; /* which bit is this in the byte */
472 key->fperm[i][j][k >> 3] |= bytebit[m];
473 }
474}
475
476/* Initialize the lookup table for the combined S and P boxes */
477static void
478spinit (DES_KEY * key)
479{
480 char pbox[32];
481 int p, i, s, j, rowcol;
482 quint32 val;
483
484 /* Compute pbox, the inverse of p32i.
485 * This is easier to work with
486 */
487 for (p = 0; p < 32; ++p)
488 {
489 for (i = 0; i < 32; ++i)
490 {
491 if (p32i[i] - 1 == p)
492 {
493 pbox[p] = i;
494 break;
495 }
496 }
497 }
498 for (s = 0; s < 8; ++s)
499 { /* For each S-box */
500 for (i = 0; i < 64; ++i)
501 { /* For each possible input */
502 val = 0;
503 /* The row number is formed from the first and last
504 * bits; the column number is from the middle 4
505 */
506 rowcol = (i & 32) | ((i & 1) ? 16 : 0) | ((i >> 1) & 0xf);
507 for (j = 0; j < 4; j++)
508 { /* For each output bit */
509 if (si[s][rowcol] & (8 >> j))
510 {
511 val |= 1L << (31 - pbox[4 * s + j]);
512 }
513 }
514 key->sp[s][i] = val;
515 }
516 }
517}
518
519int
520ntlm_des_ecb_encrypt (const void *plaintext, int len, DES_KEY * akey,
521 unsigned char output[8])
522{
523 int j;
524 const unsigned char *plain = (const unsigned char *) plaintext;
525
526 for (j = 0; j < len / 8; ++j)
527 {
528 memcpy (&output[j * 8], &plain[j * 8], 8);
529 ntlm_des_encrypt (akey, &output[j * 8]);
530 }
531
532 if (j == 0 && len != 0)
533 return -1; /* no blocks were encrypted */
534 return 0;
535}
f
static quint32 f(DES_KEY *key, quint32 r, char *subkey)
Definition: des.cpp:378
desinit
static int desinit(DES_KEY *key)
Definition: des.cpp:207
nibblebit
static const int nibblebit[]
Definition: des.cpp:199
ntlm_des_encrypt
static void ntlm_des_encrypt(DES_KEY *key, unsigned char *block)
Definition: des.cpp:263
perminit_ip
static void perminit_ip(DES_KEY *key)
Definition: des.cpp:431
fp
static const char fp[]
Definition: des.cpp:68
si
static const char si[8][64]
Definition: des.cpp:127
perminit_fp
static void perminit_fp(DES_KEY *key)
Definition: des.cpp:454
permute_ip
static void permute_ip(unsigned char *inblock, DES_KEY *key, unsigned char *outblock)
Definition: des.cpp:320
bytebit
static const int bytebit[]
Definition: des.cpp:195
ip
static const char ip[]
Definition: des.cpp:56
permute_fp
static void permute_fp(unsigned char *inblock, DES_KEY *key, unsigned char *outblock)
Definition: des.cpp:349
pc1
static const char pc1[]
Definition: des.cpp:97
ntlm_des_ecb_encrypt
int ntlm_des_ecb_encrypt(const void *plaintext, int len, DES_KEY *akey, unsigned char output[8])
Definition: des.cpp:520
pc2
static const char pc2[]
Definition: des.cpp:115
ntlm_des_set_key
int ntlm_des_set_key(DES_KEY *dkey, char *user_key, int)
Definition: des.cpp:220
totrot
static const char totrot[]
Definition: des.cpp:110
spinit
static void spinit(DES_KEY *key)
Definition: des.cpp:478
p32i
static const char p32i[]
Definition: des.cpp:179
des.h
output
void output(QList< Action > actions, QHash< QString, QString > domain)
des_key
Definition: des.h:30
des_key::fperm
char fperm[16][16][8]
Definition: des.h:34
des_key::sp
quint32 sp[8][64]
Definition: des.h:32
des_key::iperm
char iperm[16][16][8]
Definition: des.h:33
des_key::kn
char kn[16][8]
Definition: des.h:31
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KIO

Skip menu "KIO"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs-4.14.38 API Reference

Skip menu "kdelibs-4.14.38 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal