RNGs' get_bytes and allocate_bytes return boolean
[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
16 #include "padlock_rng.h"
17
18 typedef struct private_padlock_rng_t private_padlock_rng_t;
19 typedef enum padlock_quality_factor_t padlock_quality_factor_t;
20
21 /**
22 * Padlock RNG quality factors
23 */
24 enum padlock_quality_factor_t {
25 /* Lowest quality: Reads 8 bytes */
26 PADLOCK_QF0 = 0x00,
27 /* Medium quality: Reads 4 bytes */
28 PADLOCK_QF1 = 0x01,
29 /* Better quality: Reads 2 bytes */
30 PADLOCK_QF2 = 0x10,
31 /* Highest quality: Reads 1 byte */
32 PADLOCK_QF3 = 0x11,
33 };
34
35 /**
36 * Private data of an padlock_rng_t object.
37 */
38 struct private_padlock_rng_t {
39
40 /**
41 * Public padlock_rng_t interface.
42 */
43 padlock_rng_t public;
44
45 /**
46 * Padlock quality factor
47 */
48 padlock_quality_factor_t quality;
49 };
50
51 /**
52 * Get bytes from Padlock RNG. buf should have space for (len + 7)
53 */
54 static void rng(char *buf, int len, int quality)
55 {
56 while (len > 0)
57 {
58 int status;
59
60 /* run XSTORE until we have all bytes needed. We do not use REP, as
61 * this should not be performance critical and it's easier this way. */
62 asm volatile (
63 ".byte 0x0F,0xA7,0xC0 \n\t"
64 : "=D"(buf), "=a"(status)
65 : "d"(quality), "D"(buf));
66
67 /* bits[0..4] of status word contains the number of bytes read */
68 len -= status & 0x1F;
69 }
70 }
71
72 METHOD(rng_t, allocate_bytes, bool,
73 private_padlock_rng_t *this, size_t bytes, chunk_t *chunk)
74 {
75 chunk->len = bytes;
76 /* padlock requires some additional bytes */
77 chunk->ptr = malloc(bytes + 7);
78
79 rng(chunk->ptr, chunk->len, this->quality);
80 return TRUE;
81 }
82
83 METHOD(rng_t, get_bytes, bool,
84 private_padlock_rng_t *this, size_t bytes, u_int8_t *buffer)
85 {
86 chunk_t chunk;
87
88 /* Padlock needs a larger buffer than "bytes", we need a new buffer */
89 allocate_bytes(this, bytes, &chunk);
90 memcpy(buffer, chunk.ptr, bytes);
91 chunk_clear(&chunk);
92 return TRUE;
93 }
94
95 METHOD(rng_t, destroy, void,
96 private_padlock_rng_t *this)
97 {
98 free(this);
99 }
100
101 /*
102 * Described in header.
103 */
104 padlock_rng_t *padlock_rng_create(rng_quality_t quality)
105 {
106 private_padlock_rng_t *this;
107
108 INIT(this,
109 .public = {
110 .rng = {
111 .get_bytes = _get_bytes,
112 .allocate_bytes = _allocate_bytes,
113 .destroy = _destroy,
114 },
115 },
116 );
117
118 /* map RNG quality to Padlock quality factor */
119 switch (quality)
120 {
121 case RNG_WEAK:
122 this->quality = PADLOCK_QF0;
123 break;
124 case RNG_STRONG:
125 this->quality = PADLOCK_QF1;
126 break;
127 case RNG_TRUE:
128 this->quality = PADLOCK_QF3;
129 break;
130 default:
131 free(this);
132 return NULL;
133 }
134 return &this->public;
135 }
136