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