ECB mode added to the DES plugin
[strongswan.git] / src / libstrongswan / plugins / padlock / padlock_rng.c
1 /*
2 * Copyright (C) 2008 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 *
15 * $Id$
16 */
17
18 #include "padlock_rng.h"
19
20 typedef struct private_padlock_rng_t private_padlock_rng_t;
21 typedef enum padlock_quality_factor_t padlock_quality_factor_t;
22
23 /**
24 * Padlock RNG quality factors
25 */
26 enum padlock_quality_factor_t {
27 /* Lowest quality: Reads 8 bytes */
28 PADLOCK_QF0 = 0x00,
29 /* Medium quality: Reads 4 bytes */
30 PADLOCK_QF1 = 0x01,
31 /* Better quality: Reads 2 bytes */
32 PADLOCK_QF2 = 0x10,
33 /* Highest quality: Reads 1 byte */
34 PADLOCK_QF3 = 0x11,
35 };
36
37 /**
38 * Private data of an padlock_rng_t object.
39 */
40 struct private_padlock_rng_t {
41
42 /**
43 * Public padlock_rng_t interface.
44 */
45 padlock_rng_t public;
46
47 /**
48 * Padlock quality factor
49 */
50 padlock_quality_factor_t quality;
51 };
52
53 /**
54 * Get bytes from Padlock RNG. buf should have space for (len + 7)
55 */
56 static void rng(char *buf, int len, int quality)
57 {
58 while (len > 0)
59 {
60 int status;
61
62 /* run XSTORE until we have all bytes needed. We do not use REP, as
63 * this should not be performance critical and it's easier this way. */
64 asm volatile (
65 ".byte 0x0F,0xA7,0xC0 \n\t"
66 : "=D"(buf), "=a"(status)
67 : "d"(quality), "D"(buf));
68
69 /* bits[0..4] of status word contains the number of bytes read */
70 len -= status & 0x1F;
71 }
72 }
73
74 /**
75 * Implementation of padlock_rng_t.allocate_bytes.
76 */
77 static void allocate_bytes(private_padlock_rng_t *this, size_t bytes,
78 chunk_t *chunk)
79 {
80 chunk->len = bytes;
81 /* padlock requires some additional bytes */
82 chunk->ptr = malloc(bytes + 7);
83
84 rng(chunk->ptr, chunk->len, this->quality);
85 }
86
87 /**
88 * Implementation of padlock_rng_t.get_bytes.
89 */
90 static void get_bytes(private_padlock_rng_t *this, size_t bytes,
91 u_int8_t *buffer)
92 {
93 chunk_t chunk;
94
95 /* Padlock needs a larger buffer than "bytes", we need a new buffer */
96 allocate_bytes(this, bytes, &chunk);
97 memcpy(buffer, chunk.ptr, bytes);
98 chunk_clear(&chunk);
99 }
100
101 /**
102 * Implementation of padlock_rng_t.destroy.
103 */
104 static void destroy(private_padlock_rng_t *this)
105 {
106 free(this);
107 }
108
109 /*
110 * Described in header.
111 */
112 padlock_rng_t *padlock_rng_create(rng_quality_t quality)
113 {
114 private_padlock_rng_t *this = malloc_thing(private_padlock_rng_t);
115
116 this->public.rng.get_bytes = (void (*) (rng_t *, size_t, u_int8_t*)) get_bytes;
117 this->public.rng.allocate_bytes = (void (*) (rng_t *, size_t, chunk_t*)) allocate_bytes;
118 this->public.rng.destroy = (void (*) (rng_t *))destroy;
119
120 /* map RNG quality to Padlock quality factor */
121 switch (quality)
122 {
123 case RNG_WEAK:
124 this->quality = PADLOCK_QF0;
125 break;
126 case RNG_STRONG:
127 this->quality = PADLOCK_QF1;
128 break;
129 case RNG_REAL:
130 this->quality = PADLOCK_QF3;
131 break;
132 }
133
134 return &this->public;
135 }
136