3d805df9db0ab8d9ce5afbcca42aec978116add1
[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, void,
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 }
81
82 METHOD(rng_t, get_bytes, void,
83 private_padlock_rng_t *this, size_t bytes, u_int8_t *buffer)
84 {
85 chunk_t chunk;
86
87 /* Padlock needs a larger buffer than "bytes", we need a new buffer */
88 allocate_bytes(this, bytes, &chunk);
89 memcpy(buffer, chunk.ptr, bytes);
90 chunk_clear(&chunk);
91 }
92
93 METHOD(rng_t, destroy, void,
94 private_padlock_rng_t *this)
95 {
96 free(this);
97 }
98
99 /*
100 * Described in header.
101 */
102 padlock_rng_t *padlock_rng_create(rng_quality_t quality)
103 {
104 private_padlock_rng_t *this;
105
106 INIT(this,
107 .public = {
108 .rng = {
109 .get_bytes = _get_bytes,
110 .allocate_bytes = _allocate_bytes,
111 .destroy = _destroy,
112 },
113 },
114 );
115
116 /* map RNG quality to Padlock quality factor */
117 switch (quality)
118 {
119 case RNG_WEAK:
120 this->quality = PADLOCK_QF0;
121 break;
122 case RNG_STRONG:
123 this->quality = PADLOCK_QF1;
124 break;
125 case RNG_TRUE:
126 this->quality = PADLOCK_QF3;
127 break;
128 default:
129 free(this);
130 return NULL;
131 }
132 return &this->public;
133 }
134