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