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