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