1 /*
2 * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * Redistribution of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * Redistribution in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * Neither the name of Sun Microsystems, Inc. or the names of
16 * contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * This software is provided "AS IS," without a warranty of any kind.
20 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
21 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
22 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
23 * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
24 * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
25 * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
26 * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
27 * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
28 * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
29 * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
30 * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
31 */
32
33 #include "ipmitool/log.h"
34 #include "ipmitool/ipmi_constants.h"
35 #include "lanplus.h"
36 #include "lanplus_crypt_impl.h"
37 #include <openssl/hmac.h>
38 #include <openssl/evp.h>
39 #include <openssl/rand.h>
40 #include <openssl/err.h>
41 #include <assert.h>
42
43
44
45 /*
46 * lanplus_seed_prng
47 *
48 * Seed our PRNG with the specified number of bytes from /dev/random
49 *
50 * param bytes specifies the number of bytes to read from /dev/random
51 *
52 * returns 0 on success
53 * 1 on failure
54 */
lanplus_seed_prng(uint32_t bytes)55 int lanplus_seed_prng(uint32_t bytes)
56 {
57 if (! RAND_load_file("/dev/urandom", bytes))
58 return 1;
59 else
60 return 0;
61 }
62
63
64
65 /*
66 * lanplus_rand
67 *
68 * Generate a random number of the specified size
69 *
70 * param num_bytes [in] is the size of the random number to be
71 * generated
72 * param buffer [out] is where we will place our random number
73 *
74 * return 0 on success
75 * 1 on failure
76 */
77 int
lanplus_rand(uint8_t * buffer,uint32_t num_bytes)78 lanplus_rand(uint8_t * buffer, uint32_t num_bytes)
79 {
80 #undef IPMI_LANPLUS_FAKE_RAND
81 #ifdef IPMI_LANPLUS_FAKE_RAND
82
83 /*
84 * This code exists so that we can easily find the generated random number
85 * in the hex dumps.
86 */
87 int i;
88 for (i = 0; i < num_bytes; ++i)
89 buffer[i] = 0x70 | i;
90
91 return 0;
92 #else
93 return (! RAND_bytes(buffer, num_bytes));
94 #endif
95 }
96
97
98
99 /*
100 * lanplus_HMAC
101 *
102 * param mac specifies the algorithm to be used, currently only SHA1 is supported
103 * param key is the key used for HMAC generation
104 * param key_len is the lenght of key
105 * param d is the data to be MAC'd
106 * param n is the length of the data at d
107 * param md is the result of the HMAC algorithm
108 * param md_len is the length of md
109 *
110 * returns a pointer to md
111 */
112 uint8_t *
lanplus_HMAC(uint8_t mac,const void * key,int key_len,const uint8_t * d,int n,uint8_t * md,uint32_t * md_len)113 lanplus_HMAC(uint8_t mac,
114 const void *key,
115 int key_len,
116 const uint8_t *d,
117 int n,
118 uint8_t *md,
119 uint32_t *md_len)
120 {
121 const EVP_MD *evp_md = NULL;
122
123 if ((mac == IPMI_AUTH_RAKP_HMAC_SHA1) ||
124 (mac == IPMI_INTEGRITY_HMAC_SHA1_96))
125 evp_md = EVP_sha1();
126 else
127 {
128 lprintf(LOG_DEBUG, "Invalid mac type 0x%x in lanplus_HMAC\n", mac);
129 assert(0);
130 }
131
132 return HMAC(evp_md, key, key_len, d, n, md, (unsigned int *)md_len);
133 }
134
135
136 /*
137 * lanplus_encrypt_aes_cbc_128
138 *
139 * Encrypt with the AES CBC 128 algorithm
140 *
141 * param iv is the 16 byte initialization vector
142 * param key is the 16 byte key used by the AES algorithm
143 * param input is the data to be encrypted
144 * param input_length is the number of bytes to be encrypted. This MUST
145 * be a multiple of the block size, 16.
146 * param output is the encrypted output
147 * param bytes_written is the number of bytes written. This param is set
148 * to 0 on failure, or if 0 bytes were input.
149 */
150 void
lanplus_encrypt_aes_cbc_128(const uint8_t * iv,const uint8_t * key,const uint8_t * input,uint32_t input_length,uint8_t * output,uint32_t * bytes_written)151 lanplus_encrypt_aes_cbc_128(const uint8_t * iv,
152 const uint8_t * key,
153 const uint8_t * input,
154 uint32_t input_length,
155 uint8_t * output,
156 uint32_t * bytes_written)
157 {
158 EVP_CIPHER_CTX ctx;
159 EVP_CIPHER_CTX_init(&ctx);
160 EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key, iv);
161 EVP_CIPHER_CTX_set_padding(&ctx, 0);
162
163
164 *bytes_written = 0;
165
166 if (input_length == 0)
167 return;
168
169 if (verbose >= 5)
170 {
171 printbuf(iv, 16, "encrypting with this IV");
172 printbuf(key, 16, "encrypting with this key");
173 printbuf(input, input_length, "encrypting this data");
174 }
175
176
177 /*
178 * The default implementation adds a whole block of padding if the input
179 * data is perfectly aligned. We would like to keep that from happening.
180 * We have made a point to have our input perfectly padded.
181 */
182 assert((input_length % IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE) == 0);
183
184
185 if(!EVP_EncryptUpdate(&ctx, output, (int *)bytes_written, input, input_length))
186 {
187 /* Error */
188 *bytes_written = 0;
189 return;
190 }
191 else
192 {
193 uint32_t tmplen;
194
195 if(!EVP_EncryptFinal_ex(&ctx, output + *bytes_written, (int *)&tmplen))
196 {
197 *bytes_written = 0;
198 return; /* Error */
199 }
200 else
201 {
202 /* Success */
203 *bytes_written += tmplen;
204 EVP_CIPHER_CTX_cleanup(&ctx);
205 }
206 }
207 }
208
209
210
211 /*
212 * lanplus_decrypt_aes_cbc_128
213 *
214 * Decrypt with the AES CBC 128 algorithm
215 *
216 * param iv is the 16 byte initialization vector
217 * param key is the 16 byte key used by the AES algorithm
218 * param input is the data to be decrypted
219 * param input_length is the number of bytes to be decrypted. This MUST
220 * be a multiple of the block size, 16.
221 * param output is the decrypted output
222 * param bytes_written is the number of bytes written. This param is set
223 * to 0 on failure, or if 0 bytes were input.
224 */
225 void
lanplus_decrypt_aes_cbc_128(const uint8_t * iv,const uint8_t * key,const uint8_t * input,uint32_t input_length,uint8_t * output,uint32_t * bytes_written)226 lanplus_decrypt_aes_cbc_128(const uint8_t * iv,
227 const uint8_t * key,
228 const uint8_t * input,
229 uint32_t input_length,
230 uint8_t * output,
231 uint32_t * bytes_written)
232 {
233 EVP_CIPHER_CTX ctx;
234 EVP_CIPHER_CTX_init(&ctx);
235 EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key, iv);
236 EVP_CIPHER_CTX_set_padding(&ctx, 0);
237
238
239 if (verbose >= 5)
240 {
241 printbuf(iv, 16, "decrypting with this IV");
242 printbuf(key, 16, "decrypting with this key");
243 printbuf(input, input_length, "decrypting this data");
244 }
245
246
247 *bytes_written = 0;
248
249 if (input_length == 0)
250 return;
251
252 /*
253 * The default implementation adds a whole block of padding if the input
254 * data is perfectly aligned. We would like to keep that from happening.
255 * We have made a point to have our input perfectly padded.
256 */
257 assert((input_length % IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE) == 0);
258
259
260 if (!EVP_DecryptUpdate(&ctx, output, (int *)bytes_written, input, input_length))
261 {
262 /* Error */
263 lprintf(LOG_DEBUG, "ERROR: decrypt update failed");
264 *bytes_written = 0;
265 return;
266 }
267 else
268 {
269 uint32_t tmplen;
270
271 if (!EVP_DecryptFinal_ex(&ctx, output + *bytes_written, (int *)&tmplen))
272 {
273 char buffer[1000];
274 ERR_error_string(ERR_get_error(), buffer);
275 lprintf(LOG_DEBUG, "the ERR error %s", buffer);
276 lprintf(LOG_DEBUG, "ERROR: decrypt final failed");
277 *bytes_written = 0;
278 return; /* Error */
279 }
280 else
281 {
282 /* Success */
283 *bytes_written += tmplen;
284 EVP_CIPHER_CTX_cleanup(&ctx);
285 }
286 }
287
288 if (verbose >= 5)
289 {
290 lprintf(LOG_DEBUG, "Decrypted %d encrypted bytes", input_length);
291 printbuf(output, *bytes_written, "Decrypted this data");
292 }
293 }
294