|
Packit Service |
ed0f68 |
/*
|
|
Packit Service |
ed0f68 |
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
|
|
Packit Service |
ed0f68 |
*
|
|
Packit Service |
ed0f68 |
* Redistribution and use in source and binary forms, with or without
|
|
Packit Service |
ed0f68 |
* modification, are permitted provided that the following conditions
|
|
Packit Service |
ed0f68 |
* are met:
|
|
Packit Service |
ed0f68 |
*
|
|
Packit Service |
ed0f68 |
* Redistribution of source code must retain the above copyright
|
|
Packit Service |
ed0f68 |
* notice, this list of conditions and the following disclaimer.
|
|
Packit Service |
ed0f68 |
*
|
|
Packit Service |
ed0f68 |
* Redistribution in binary form must reproduce the above copyright
|
|
Packit Service |
ed0f68 |
* notice, this list of conditions and the following disclaimer in the
|
|
Packit Service |
ed0f68 |
* documentation and/or other materials provided with the distribution.
|
|
Packit Service |
ed0f68 |
*
|
|
Packit Service |
ed0f68 |
* Neither the name of Sun Microsystems, Inc. or the names of
|
|
Packit Service |
ed0f68 |
* contributors may be used to endorse or promote products derived
|
|
Packit Service |
ed0f68 |
* from this software without specific prior written permission.
|
|
Packit Service |
ed0f68 |
*
|
|
Packit Service |
ed0f68 |
* This software is provided "AS IS," without a warranty of any kind.
|
|
Packit Service |
ed0f68 |
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
|
|
Packit Service |
ed0f68 |
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
|
|
Packit Service |
ed0f68 |
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
|
|
Packit Service |
ed0f68 |
* SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
|
|
Packit Service |
ed0f68 |
* FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
|
|
Packit Service |
ed0f68 |
* OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
|
|
Packit Service |
ed0f68 |
* SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
|
|
Packit Service |
ed0f68 |
* OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
|
|
Packit Service |
ed0f68 |
* PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
|
|
Packit Service |
ed0f68 |
* LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
|
|
Packit Service |
ed0f68 |
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
|
Packit Service |
ed0f68 |
*/
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
#include "ipmitool/log.h"
|
|
Packit Service |
ed0f68 |
#include "ipmitool/ipmi_constants.h"
|
|
Packit Service |
ed0f68 |
#include "lanplus.h"
|
|
Packit Service |
ed0f68 |
#include "lanplus_crypt_impl.h"
|
|
Packit Service |
ed0f68 |
#include <openssl/hmac.h>
|
|
Packit Service |
ed0f68 |
#include <openssl/evp.h>
|
|
Packit Service |
ed0f68 |
#include <openssl/rand.h>
|
|
Packit Service |
ed0f68 |
#include <openssl/err.h>
|
|
Packit Service |
ed0f68 |
#include <assert.h>
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
/*
|
|
Packit Service |
ed0f68 |
* lanplus_seed_prng
|
|
Packit Service |
ed0f68 |
*
|
|
Packit Service |
ed0f68 |
* Seed our PRNG with the specified number of bytes from /dev/random
|
|
Packit Service |
ed0f68 |
*
|
|
Packit Service |
ed0f68 |
* param bytes specifies the number of bytes to read from /dev/random
|
|
Packit Service |
ed0f68 |
*
|
|
Packit Service |
ed0f68 |
* returns 0 on success
|
|
Packit Service |
ed0f68 |
* 1 on failure
|
|
Packit Service |
ed0f68 |
*/
|
|
Packit Service |
ed0f68 |
int lanplus_seed_prng(uint32_t bytes)
|
|
Packit Service |
ed0f68 |
{
|
|
Packit Service |
ed0f68 |
if (! RAND_load_file("/dev/urandom", bytes))
|
|
Packit Service |
ed0f68 |
return 1;
|
|
Packit Service |
ed0f68 |
else
|
|
Packit Service |
ed0f68 |
return 0;
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
/*
|
|
Packit Service |
ed0f68 |
* lanplus_rand
|
|
Packit Service |
ed0f68 |
*
|
|
Packit Service |
ed0f68 |
* Generate a random number of the specified size
|
|
Packit Service |
ed0f68 |
*
|
|
Packit Service |
ed0f68 |
* param num_bytes [in] is the size of the random number to be
|
|
Packit Service |
ed0f68 |
* generated
|
|
Packit Service |
ed0f68 |
* param buffer [out] is where we will place our random number
|
|
Packit Service |
ed0f68 |
*
|
|
Packit Service |
ed0f68 |
* return 0 on success
|
|
Packit Service |
ed0f68 |
* 1 on failure
|
|
Packit Service |
ed0f68 |
*/
|
|
Packit Service |
ed0f68 |
int
|
|
Packit Service |
ed0f68 |
lanplus_rand(uint8_t * buffer, uint32_t num_bytes)
|
|
Packit Service |
ed0f68 |
{
|
|
Packit Service |
ed0f68 |
#undef IPMI_LANPLUS_FAKE_RAND
|
|
Packit Service |
ed0f68 |
#ifdef IPMI_LANPLUS_FAKE_RAND
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
/*
|
|
Packit Service |
ed0f68 |
* This code exists so that we can easily find the generated random number
|
|
Packit Service |
ed0f68 |
* in the hex dumps.
|
|
Packit Service |
ed0f68 |
*/
|
|
Packit Service |
ed0f68 |
int i;
|
|
Packit Service |
ed0f68 |
for (i = 0; i < num_bytes; ++i)
|
|
Packit Service |
ed0f68 |
buffer[i] = 0x70 | i;
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
return 0;
|
|
Packit Service |
ed0f68 |
#else
|
|
Packit Service |
ed0f68 |
return (! RAND_bytes(buffer, num_bytes));
|
|
Packit Service |
ed0f68 |
#endif
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
/*
|
|
Packit Service |
ed0f68 |
* lanplus_HMAC
|
|
Packit Service |
ed0f68 |
*
|
|
Packit Service |
ed0f68 |
* param mac specifies the algorithm to be used, currently SHA1, SHA256 and MD5
|
|
Packit Service |
ed0f68 |
* are supported
|
|
Packit Service |
ed0f68 |
* param key is the key used for HMAC generation
|
|
Packit Service |
ed0f68 |
* param key_len is the lenght of key
|
|
Packit Service |
ed0f68 |
* param d is the data to be MAC'd
|
|
Packit Service |
ed0f68 |
* param n is the length of the data at d
|
|
Packit Service |
ed0f68 |
* param md is the result of the HMAC algorithm
|
|
Packit Service |
ed0f68 |
* param md_len is the length of md
|
|
Packit Service |
ed0f68 |
*
|
|
Packit Service |
ed0f68 |
* returns a pointer to md
|
|
Packit Service |
ed0f68 |
*/
|
|
Packit Service |
ed0f68 |
uint8_t *
|
|
Packit Service |
ed0f68 |
lanplus_HMAC(uint8_t mac,
|
|
Packit Service |
ed0f68 |
const void *key,
|
|
Packit Service |
ed0f68 |
int key_len,
|
|
Packit Service |
ed0f68 |
const uint8_t *d,
|
|
Packit Service |
ed0f68 |
int n,
|
|
Packit Service |
ed0f68 |
uint8_t *md,
|
|
Packit Service |
ed0f68 |
uint32_t *md_len)
|
|
Packit Service |
ed0f68 |
{
|
|
Packit Service |
ed0f68 |
const EVP_MD *evp_md = NULL;
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
if ((mac == IPMI_AUTH_RAKP_HMAC_SHA1) ||
|
|
Packit Service |
ed0f68 |
(mac == IPMI_INTEGRITY_HMAC_SHA1_96))
|
|
Packit Service |
ed0f68 |
evp_md = EVP_sha1();
|
|
Packit Service |
ed0f68 |
else if ((mac == IPMI_AUTH_RAKP_HMAC_MD5) ||
|
|
Packit Service |
ed0f68 |
(mac == IPMI_INTEGRITY_HMAC_MD5_128))
|
|
Packit Service |
ed0f68 |
evp_md = EVP_md5();
|
|
Packit Service |
ed0f68 |
#ifdef HAVE_CRYPTO_SHA256
|
|
Packit Service |
ed0f68 |
else if ((mac == IPMI_AUTH_RAKP_HMAC_SHA256) ||
|
|
Packit Service |
ed0f68 |
(mac == IPMI_INTEGRITY_HMAC_SHA256_128))
|
|
Packit Service |
ed0f68 |
evp_md = EVP_sha256();
|
|
Packit Service |
ed0f68 |
#endif /* HAVE_CRYPTO_SHA256 */
|
|
Packit Service |
ed0f68 |
else
|
|
Packit Service |
ed0f68 |
{
|
|
Packit Service |
ed0f68 |
lprintf(LOG_DEBUG, "Invalid mac type 0x%x in lanplus_HMAC\n", mac);
|
|
Packit Service |
ed0f68 |
assert(0);
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
return HMAC(evp_md, key, key_len, d, n, md, (unsigned int *)md_len);
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
/*
|
|
Packit Service |
ed0f68 |
* lanplus_encrypt_aes_cbc_128
|
|
Packit Service |
ed0f68 |
*
|
|
Packit Service |
ed0f68 |
* Encrypt with the AES CBC 128 algorithm
|
|
Packit Service |
ed0f68 |
*
|
|
Packit Service |
ed0f68 |
* param iv is the 16 byte initialization vector
|
|
Packit Service |
ed0f68 |
* param key is the 16 byte key used by the AES algorithm
|
|
Packit Service |
ed0f68 |
* param input is the data to be encrypted
|
|
Packit Service |
ed0f68 |
* param input_length is the number of bytes to be encrypted. This MUST
|
|
Packit Service |
ed0f68 |
* be a multiple of the block size, 16.
|
|
Packit Service |
ed0f68 |
* param output is the encrypted output
|
|
Packit Service |
ed0f68 |
* param bytes_written is the number of bytes written. This param is set
|
|
Packit Service |
ed0f68 |
* to 0 on failure, or if 0 bytes were input.
|
|
Packit Service |
ed0f68 |
*/
|
|
Packit Service |
ed0f68 |
void
|
|
Packit Service |
ed0f68 |
lanplus_encrypt_aes_cbc_128(const uint8_t * iv,
|
|
Packit Service |
ed0f68 |
const uint8_t * key,
|
|
Packit Service |
ed0f68 |
const uint8_t * input,
|
|
Packit Service |
ed0f68 |
uint32_t input_length,
|
|
Packit Service |
ed0f68 |
uint8_t * output,
|
|
Packit Service |
ed0f68 |
uint32_t * bytes_written)
|
|
Packit Service |
ed0f68 |
{
|
|
Packit Service |
e61e3e |
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
|
|
Packit Service |
e61e3e |
EVP_CIPHER_CTX_init(ctx);
|
|
Packit Service |
e61e3e |
EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv);
|
|
Packit Service |
e61e3e |
EVP_CIPHER_CTX_set_padding(ctx, 0);
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
*bytes_written = 0;
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
if (input_length == 0)
|
|
Packit Service |
ed0f68 |
return;
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
if (verbose >= 5)
|
|
Packit Service |
ed0f68 |
{
|
|
Packit Service |
ed0f68 |
printbuf(iv, 16, "encrypting with this IV");
|
|
Packit Service |
ed0f68 |
printbuf(key, 16, "encrypting with this key");
|
|
Packit Service |
ed0f68 |
printbuf(input, input_length, "encrypting this data");
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
/*
|
|
Packit Service |
ed0f68 |
* The default implementation adds a whole block of padding if the input
|
|
Packit Service |
ed0f68 |
* data is perfectly aligned. We would like to keep that from happening.
|
|
Packit Service |
ed0f68 |
* We have made a point to have our input perfectly padded.
|
|
Packit Service |
ed0f68 |
*/
|
|
Packit Service |
ed0f68 |
assert((input_length % IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE) == 0);
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
e61e3e |
if(!EVP_EncryptUpdate(ctx, output, (int *)bytes_written, input, input_length))
|
|
Packit Service |
ed0f68 |
{
|
|
Packit Service |
ed0f68 |
/* Error */
|
|
Packit Service |
ed0f68 |
*bytes_written = 0;
|
|
Packit Service |
ed0f68 |
return;
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
else
|
|
Packit Service |
ed0f68 |
{
|
|
Packit Service |
ed0f68 |
uint32_t tmplen;
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
e61e3e |
if(!EVP_EncryptFinal_ex(ctx, output + *bytes_written, (int *)&tmplen))
|
|
Packit Service |
ed0f68 |
{
|
|
Packit Service |
ed0f68 |
*bytes_written = 0;
|
|
Packit Service |
ed0f68 |
return; /* Error */
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
else
|
|
Packit Service |
ed0f68 |
{
|
|
Packit Service |
ed0f68 |
/* Success */
|
|
Packit Service |
ed0f68 |
*bytes_written += tmplen;
|
|
Packit Service |
e61e3e |
EVP_CIPHER_CTX_cleanup(ctx);
|
|
Packit Service |
e61e3e |
EVP_CIPHER_CTX_free(ctx);
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
/*
|
|
Packit Service |
ed0f68 |
* lanplus_decrypt_aes_cbc_128
|
|
Packit Service |
ed0f68 |
*
|
|
Packit Service |
ed0f68 |
* Decrypt with the AES CBC 128 algorithm
|
|
Packit Service |
ed0f68 |
*
|
|
Packit Service |
ed0f68 |
* param iv is the 16 byte initialization vector
|
|
Packit Service |
ed0f68 |
* param key is the 16 byte key used by the AES algorithm
|
|
Packit Service |
ed0f68 |
* param input is the data to be decrypted
|
|
Packit Service |
ed0f68 |
* param input_length is the number of bytes to be decrypted. This MUST
|
|
Packit Service |
ed0f68 |
* be a multiple of the block size, 16.
|
|
Packit Service |
ed0f68 |
* param output is the decrypted output
|
|
Packit Service |
ed0f68 |
* param bytes_written is the number of bytes written. This param is set
|
|
Packit Service |
ed0f68 |
* to 0 on failure, or if 0 bytes were input.
|
|
Packit Service |
ed0f68 |
*/
|
|
Packit Service |
ed0f68 |
void
|
|
Packit Service |
ed0f68 |
lanplus_decrypt_aes_cbc_128(const uint8_t * iv,
|
|
Packit Service |
ed0f68 |
const uint8_t * key,
|
|
Packit Service |
ed0f68 |
const uint8_t * input,
|
|
Packit Service |
ed0f68 |
uint32_t input_length,
|
|
Packit Service |
ed0f68 |
uint8_t * output,
|
|
Packit Service |
ed0f68 |
uint32_t * bytes_written)
|
|
Packit Service |
ed0f68 |
{
|
|
Packit Service |
e61e3e |
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
|
|
Packit Service |
e61e3e |
EVP_CIPHER_CTX_init(ctx);
|
|
Packit Service |
e61e3e |
EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv);
|
|
Packit Service |
e61e3e |
EVP_CIPHER_CTX_set_padding(ctx, 0);
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
if (verbose >= 5)
|
|
Packit Service |
ed0f68 |
{
|
|
Packit Service |
ed0f68 |
printbuf(iv, 16, "decrypting with this IV");
|
|
Packit Service |
ed0f68 |
printbuf(key, 16, "decrypting with this key");
|
|
Packit Service |
ed0f68 |
printbuf(input, input_length, "decrypting this data");
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
*bytes_written = 0;
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
if (input_length == 0)
|
|
Packit Service |
ed0f68 |
return;
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
/*
|
|
Packit Service |
ed0f68 |
* The default implementation adds a whole block of padding if the input
|
|
Packit Service |
ed0f68 |
* data is perfectly aligned. We would like to keep that from happening.
|
|
Packit Service |
ed0f68 |
* We have made a point to have our input perfectly padded.
|
|
Packit Service |
ed0f68 |
*/
|
|
Packit Service |
ed0f68 |
assert((input_length % IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE) == 0);
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
e61e3e |
if (!EVP_DecryptUpdate(ctx, output, (int *)bytes_written, input, input_length))
|
|
Packit Service |
ed0f68 |
{
|
|
Packit Service |
ed0f68 |
/* Error */
|
|
Packit Service |
ed0f68 |
lprintf(LOG_DEBUG, "ERROR: decrypt update failed");
|
|
Packit Service |
ed0f68 |
*bytes_written = 0;
|
|
Packit Service |
ed0f68 |
return;
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
else
|
|
Packit Service |
ed0f68 |
{
|
|
Packit Service |
ed0f68 |
uint32_t tmplen;
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
e61e3e |
if (!EVP_DecryptFinal_ex(ctx, output + *bytes_written, (int *)&tmplen))
|
|
Packit Service |
ed0f68 |
{
|
|
Packit Service |
ed0f68 |
char buffer[1000];
|
|
Packit Service |
ed0f68 |
ERR_error_string(ERR_get_error(), buffer);
|
|
Packit Service |
ed0f68 |
lprintf(LOG_DEBUG, "the ERR error %s", buffer);
|
|
Packit Service |
ed0f68 |
lprintf(LOG_DEBUG, "ERROR: decrypt final failed");
|
|
Packit Service |
ed0f68 |
*bytes_written = 0;
|
|
Packit Service |
ed0f68 |
return; /* Error */
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
else
|
|
Packit Service |
ed0f68 |
{
|
|
Packit Service |
ed0f68 |
/* Success */
|
|
Packit Service |
ed0f68 |
*bytes_written += tmplen;
|
|
Packit Service |
e61e3e |
EVP_CIPHER_CTX_cleanup(ctx);
|
|
Packit Service |
e61e3e |
EVP_CIPHER_CTX_free(ctx);
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
if (verbose >= 5)
|
|
Packit Service |
ed0f68 |
{
|
|
Packit Service |
ed0f68 |
lprintf(LOG_DEBUG, "Decrypted %d encrypted bytes", input_length);
|
|
Packit Service |
ed0f68 |
printbuf(output, *bytes_written, "Decrypted this data");
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
}
|