/* * openssl.c * Wrapper for OpenSSL library. * * Copyright (c) 2001 Marko Kreen * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * contrib/pgcrypto/openssl.c */ #include "postgres.h" #include "px.h" #include #include #include #include #include #include /* * Max lengths we might want to handle. */ #define MAX_KEY (512/8) #define MAX_IV (128/8) /* * Compatibility with OpenSSL 0.9.6 * * It needs AES and newer DES and digest API. */ #if OPENSSL_VERSION_NUMBER >= 0x00907000L /* * Nothing needed for OpenSSL 0.9.7+ */ #include #else /* old OPENSSL */ /* * Emulate OpenSSL AES. */ #include "rijndael.c" #define AES_ENCRYPT 1 #define AES_DECRYPT 0 #define AES_KEY rijndael_ctx static int AES_set_encrypt_key(const uint8 *key, int kbits, AES_KEY *ctx) { aes_set_key(ctx, key, kbits, 1); return 0; } static int AES_set_decrypt_key(const uint8 *key, int kbits, AES_KEY *ctx) { aes_set_key(ctx, key, kbits, 0); return 0; } static void AES_ecb_encrypt(const uint8 *src, uint8 *dst, AES_KEY *ctx, int enc) { memcpy(dst, src, 16); if (enc) aes_ecb_encrypt(ctx, dst, 16); else aes_ecb_decrypt(ctx, dst, 16); } static void AES_cbc_encrypt(const uint8 *src, uint8 *dst, int len, AES_KEY *ctx, uint8 *iv, int enc) { memcpy(dst, src, len); if (enc) { aes_cbc_encrypt(ctx, iv, dst, len); memcpy(iv, dst + len - 16, 16); } else { aes_cbc_decrypt(ctx, iv, dst, len); memcpy(iv, src + len - 16, 16); } } /* * Emulate DES_* API */ #define DES_key_schedule des_key_schedule #define DES_cblock des_cblock #define DES_set_key(k, ks) \ des_set_key((k), *(ks)) #define DES_ecb_encrypt(i, o, k, e) \ des_ecb_encrypt((i), (o), *(k), (e)) #define DES_ncbc_encrypt(i, o, l, k, iv, e) \ des_ncbc_encrypt((i), (o), (l), *(k), (iv), (e)) #define DES_ecb3_encrypt(i, o, k1, k2, k3, e) \ des_ecb3_encrypt((des_cblock *)(i), (des_cblock *)(o), \ *(k1), *(k2), *(k3), (e)) #define DES_ede3_cbc_encrypt(i, o, l, k1, k2, k3, iv, e) \ des_ede3_cbc_encrypt((i), (o), \ (l), *(k1), *(k2), *(k3), (iv), (e)) /* * Emulate newer digest API. */ static void EVP_MD_CTX_init(EVP_MD_CTX *ctx) { memset(ctx, 0, sizeof(*ctx)); } static int EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx) { memset(ctx, 0, sizeof(*ctx)); return 1; } static int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *md, void *engine) { EVP_DigestInit(ctx, md); return 1; } static int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *res, unsigned int *len) { EVP_DigestFinal(ctx, res, len); return 1; } #endif /* old OpenSSL */ /* * Provide SHA2 for older OpenSSL < 0.9.8 */ #if OPENSSL_VERSION_NUMBER < 0x00908000L #include "sha2.c" #include "internal-sha2.c" typedef void (*init_f) (PX_MD *md); static int compat_find_digest(const char *name, PX_MD **res) { init_f init = NULL; if (pg_strcasecmp(name, "sha224") == 0) init = init_sha224; else if (pg_strcasecmp(name, "sha256") == 0) init = init_sha256; else if (pg_strcasecmp(name, "sha384") == 0) init = init_sha384; else if (pg_strcasecmp(name, "sha512") == 0) init = init_sha512; else return PXE_NO_HASH; *res = px_alloc(sizeof(PX_MD)); init(*res); return 0; } #else #define compat_find_digest(name, res) (PXE_NO_HASH) #endif /* * Hashes */ typedef struct OSSLDigest { const EVP_MD *algo; EVP_MD_CTX ctx; } OSSLDigest; static unsigned digest_result_size(PX_MD *h) { OSSLDigest *digest = (OSSLDigest *) h->p.ptr; return EVP_MD_CTX_size(&digest->ctx); } static unsigned digest_block_size(PX_MD *h) { OSSLDigest *digest = (OSSLDigest *) h->p.ptr; return EVP_MD_CTX_block_size(&digest->ctx); } static void digest_reset(PX_MD *h) { OSSLDigest *digest = (OSSLDigest *) h->p.ptr; EVP_DigestInit_ex(&digest->ctx, digest->algo, NULL); } static void digest_update(PX_MD *h, const uint8 *data, unsigned dlen) { OSSLDigest *digest = (OSSLDigest *) h->p.ptr; EVP_DigestUpdate(&digest->ctx, data, dlen); } static void digest_finish(PX_MD *h, uint8 *dst) { OSSLDigest *digest = (OSSLDigest *) h->p.ptr; EVP_DigestFinal_ex(&digest->ctx, dst, NULL); } static void digest_free(PX_MD *h) { OSSLDigest *digest = (OSSLDigest *) h->p.ptr; EVP_MD_CTX_cleanup(&digest->ctx); px_free(digest); px_free(h); } static int px_openssl_initialized = 0; /* PUBLIC functions */ int px_find_digest(const char *name, PX_MD **res) { const EVP_MD *md; PX_MD *h; OSSLDigest *digest; if (!px_openssl_initialized) { px_openssl_initialized = 1; OpenSSL_add_all_algorithms(); } md = EVP_get_digestbyname(name); if (md == NULL) return compat_find_digest(name, res); digest = px_alloc(sizeof(*digest)); digest->algo = md; EVP_MD_CTX_init(&digest->ctx); if (EVP_DigestInit_ex(&digest->ctx, digest->algo, NULL) == 0) return -1; h = px_alloc(sizeof(*h)); h->result_size = digest_result_size; h->block_size = digest_block_size; h->reset = digest_reset; h->update = digest_update; h->finish = digest_finish; h->free = digest_free; h->p.ptr = (void *) digest; *res = h; return 0; } /* * Ciphers * * The problem with OpenSSL is that the EVP* family * of functions does not allow enough flexibility * and forces some of the parameters (keylen, * padding) to SSL defaults. * * So need to manage ciphers ourselves. */ struct ossl_cipher { int (*init) (PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv); int (*encrypt) (PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res); int (*decrypt) (PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res); int block_size; int max_key_size; int stream_cipher; }; typedef struct { union { struct { BF_KEY key; int num; } bf; struct { DES_key_schedule key_schedule; } des; struct { DES_key_schedule k1, k2, k3; } des3; CAST_KEY cast_key; AES_KEY aes_key; } u; uint8 key[MAX_KEY]; uint8 iv[MAX_IV]; unsigned klen; unsigned init; const struct ossl_cipher *ciph; } ossldata; /* generic */ static unsigned gen_ossl_block_size(PX_Cipher *c) { ossldata *od = (ossldata *) c->ptr; return od->ciph->block_size; } static unsigned gen_ossl_key_size(PX_Cipher *c) { ossldata *od = (ossldata *) c->ptr; return od->ciph->max_key_size; } static unsigned gen_ossl_iv_size(PX_Cipher *c) { unsigned ivlen; ossldata *od = (ossldata *) c->ptr; ivlen = od->ciph->block_size; return ivlen; } static void gen_ossl_free(PX_Cipher *c) { ossldata *od = (ossldata *) c->ptr; memset(od, 0, sizeof(*od)); px_free(od); px_free(c); } /* Blowfish */ /* * Check if strong crypto is supported. Some openssl installations * support only short keys and unfortunately BF_set_key does not return any * error value. This function tests if is possible to use strong key. */ static int bf_check_supported_key_len(void) { static const uint8 key[56] = { 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87, 0x78, 0x69, 0x5a, 0x4b, 0x3c, 0x2d, 0x1e, 0x0f, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x04, 0x68, 0x91, 0x04, 0xc2, 0xfd, 0x3b, 0x2f, 0x58, 0x40, 0x23, 0x64, 0x1a, 0xba, 0x61, 0x76, 0x1f, 0x1f, 0x1f, 0x1f, 0x0e, 0x0e, 0x0e, 0x0e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; static const uint8 data[8] = {0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10}; static const uint8 res[8] = {0xc0, 0x45, 0x04, 0x01, 0x2e, 0x4e, 0x1f, 0x53}; static uint8 out[8]; BF_KEY bf_key; /* encrypt with 448bits key and verify output */ BF_set_key(&bf_key, 56, key); BF_ecb_encrypt(data, out, &bf_key, BF_ENCRYPT); if (memcmp(out, res, 8) != 0) return 0; /* Output does not match -> strong cipher is * not supported */ return 1; } static int bf_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv) { ossldata *od = c->ptr; static int bf_is_strong = -1; /* * Test if key len is supported. BF_set_key silently cut large keys and it * could be be a problem when user transfer crypted data from one server * to another. */ if (bf_is_strong == -1) bf_is_strong = bf_check_supported_key_len(); if (!bf_is_strong && klen > 16) return PXE_KEY_TOO_BIG; /* Key len is supported. We can use it. */ BF_set_key(&od->u.bf.key, klen, key); if (iv) memcpy(od->iv, iv, BF_BLOCK); else memset(od->iv, 0, BF_BLOCK); od->u.bf.num = 0; return 0; } static int bf_ecb_encrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) { unsigned bs = gen_ossl_block_size(c); unsigned i; ossldata *od = c->ptr; for (i = 0; i < dlen / bs; i++) BF_ecb_encrypt(data + i * bs, res + i * bs, &od->u.bf.key, BF_ENCRYPT); return 0; } static int bf_ecb_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) { unsigned bs = gen_ossl_block_size(c), i; ossldata *od = c->ptr; for (i = 0; i < dlen / bs; i++) BF_ecb_encrypt(data + i * bs, res + i * bs, &od->u.bf.key, BF_DECRYPT); return 0; } static int bf_cbc_encrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) { ossldata *od = c->ptr; BF_cbc_encrypt(data, res, dlen, &od->u.bf.key, od->iv, BF_ENCRYPT); return 0; } static int bf_cbc_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) { ossldata *od = c->ptr; BF_cbc_encrypt(data, res, dlen, &od->u.bf.key, od->iv, BF_DECRYPT); return 0; } static int bf_cfb64_encrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) { ossldata *od = c->ptr; BF_cfb64_encrypt(data, res, dlen, &od->u.bf.key, od->iv, &od->u.bf.num, BF_ENCRYPT); return 0; } static int bf_cfb64_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) { ossldata *od = c->ptr; BF_cfb64_encrypt(data, res, dlen, &od->u.bf.key, od->iv, &od->u.bf.num, BF_DECRYPT); return 0; } /* DES */ static int ossl_des_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv) { ossldata *od = c->ptr; DES_cblock xkey; memset(&xkey, 0, sizeof(xkey)); memcpy(&xkey, key, klen > 8 ? 8 : klen); DES_set_key(&xkey, &od->u.des.key_schedule); memset(&xkey, 0, sizeof(xkey)); if (iv) memcpy(od->iv, iv, 8); else memset(od->iv, 0, 8); return 0; } static int ossl_des_ecb_encrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) { unsigned bs = gen_ossl_block_size(c); unsigned i; ossldata *od = c->ptr; for (i = 0; i < dlen / bs; i++) DES_ecb_encrypt((DES_cblock *) (data + i * bs), (DES_cblock *) (res + i * bs), &od->u.des.key_schedule, 1); return 0; } static int ossl_des_ecb_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) { unsigned bs = gen_ossl_block_size(c); unsigned i; ossldata *od = c->ptr; for (i = 0; i < dlen / bs; i++) DES_ecb_encrypt((DES_cblock *) (data + i * bs), (DES_cblock *) (res + i * bs), &od->u.des.key_schedule, 0); return 0; } static int ossl_des_cbc_encrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) { ossldata *od = c->ptr; DES_ncbc_encrypt(data, res, dlen, &od->u.des.key_schedule, (DES_cblock *) od->iv, 1); return 0; } static int ossl_des_cbc_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) { ossldata *od = c->ptr; DES_ncbc_encrypt(data, res, dlen, &od->u.des.key_schedule, (DES_cblock *) od->iv, 0); return 0; } /* DES3 */ static int ossl_des3_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv) { ossldata *od = c->ptr; DES_cblock xkey1, xkey2, xkey3; memset(&xkey1, 0, sizeof(xkey1)); memset(&xkey2, 0, sizeof(xkey2)); memset(&xkey3, 0, sizeof(xkey3)); memcpy(&xkey1, key, klen > 8 ? 8 : klen); if (klen > 8) memcpy(&xkey2, key + 8, (klen - 8) > 8 ? 8 : (klen - 8)); if (klen > 16) memcpy(&xkey3, key + 16, (klen - 16) > 8 ? 8 : (klen - 16)); DES_set_key(&xkey1, &od->u.des3.k1); DES_set_key(&xkey2, &od->u.des3.k2); DES_set_key(&xkey3, &od->u.des3.k3); memset(&xkey1, 0, sizeof(xkey1)); memset(&xkey2, 0, sizeof(xkey2)); memset(&xkey3, 0, sizeof(xkey3)); if (iv) memcpy(od->iv, iv, 8); else memset(od->iv, 0, 8); return 0; } static int ossl_des3_ecb_encrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) { unsigned bs = gen_ossl_block_size(c); unsigned i; ossldata *od = c->ptr; for (i = 0; i < dlen / bs; i++) DES_ecb3_encrypt((void *) (data + i * bs), (void *) (res + i * bs), &od->u.des3.k1, &od->u.des3.k2, &od->u.des3.k3, 1); return 0; } static int ossl_des3_ecb_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) { unsigned bs = gen_ossl_block_size(c); unsigned i; ossldata *od = c->ptr; for (i = 0; i < dlen / bs; i++) DES_ecb3_encrypt((void *) (data + i * bs), (void *) (res + i * bs), &od->u.des3.k1, &od->u.des3.k2, &od->u.des3.k3, 0); return 0; } static int ossl_des3_cbc_encrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) { ossldata *od = c->ptr; DES_ede3_cbc_encrypt(data, res, dlen, &od->u.des3.k1, &od->u.des3.k2, &od->u.des3.k3, (DES_cblock *) od->iv, 1); return 0; } static int ossl_des3_cbc_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) { ossldata *od = c->ptr; DES_ede3_cbc_encrypt(data, res, dlen, &od->u.des3.k1, &od->u.des3.k2, &od->u.des3.k3, (DES_cblock *) od->iv, 0); return 0; } /* CAST5 */ static int ossl_cast_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv) { ossldata *od = c->ptr; unsigned bs = gen_ossl_block_size(c); CAST_set_key(&od->u.cast_key, klen, key); if (iv) memcpy(od->iv, iv, bs); else memset(od->iv, 0, bs); return 0; } static int ossl_cast_ecb_encrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) { unsigned bs = gen_ossl_block_size(c); ossldata *od = c->ptr; const uint8 *end = data + dlen - bs; for (; data <= end; data += bs, res += bs) CAST_ecb_encrypt(data, res, &od->u.cast_key, CAST_ENCRYPT); return 0; } static int ossl_cast_ecb_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) { unsigned bs = gen_ossl_block_size(c); ossldata *od = c->ptr; const uint8 *end = data + dlen - bs; for (; data <= end; data += bs, res += bs) CAST_ecb_encrypt(data, res, &od->u.cast_key, CAST_DECRYPT); return 0; } static int ossl_cast_cbc_encrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) { ossldata *od = c->ptr; CAST_cbc_encrypt(data, res, dlen, &od->u.cast_key, od->iv, CAST_ENCRYPT); return 0; } static int ossl_cast_cbc_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) { ossldata *od = c->ptr; CAST_cbc_encrypt(data, res, dlen, &od->u.cast_key, od->iv, CAST_DECRYPT); return 0; } /* AES */ static int ossl_aes_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv) { ossldata *od = c->ptr; unsigned bs = gen_ossl_block_size(c); if (klen <= 128 / 8) od->klen = 128 / 8; else if (klen <= 192 / 8) od->klen = 192 / 8; else if (klen <= 256 / 8) od->klen = 256 / 8; else return PXE_KEY_TOO_BIG; memcpy(od->key, key, klen); if (iv) memcpy(od->iv, iv, bs); else memset(od->iv, 0, bs); return 0; } static int ossl_aes_key_init(ossldata *od, int type) { int err; /* * Strong key support could be missing on some openssl installations. We * must check return value from set key function. */ if (type == AES_ENCRYPT) err = AES_set_encrypt_key(od->key, od->klen * 8, &od->u.aes_key); else err = AES_set_decrypt_key(od->key, od->klen * 8, &od->u.aes_key); if (err == 0) { od->init = 1; return 0; } od->init = 0; return PXE_KEY_TOO_BIG; } static int ossl_aes_ecb_encrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) { unsigned bs = gen_ossl_block_size(c); ossldata *od = c->ptr; const uint8 *end = data + dlen - bs; int err; if (!od->init) if ((err = ossl_aes_key_init(od, AES_ENCRYPT)) != 0) return err; for (; data <= end; data += bs, res += bs) AES_ecb_encrypt(data, res, &od->u.aes_key, AES_ENCRYPT); return 0; } static int ossl_aes_ecb_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) { unsigned bs = gen_ossl_block_size(c); ossldata *od = c->ptr; const uint8 *end = data + dlen - bs; int err; if (!od->init) if ((err = ossl_aes_key_init(od, AES_DECRYPT)) != 0) return err; for (; data <= end; data += bs, res += bs) AES_ecb_encrypt(data, res, &od->u.aes_key, AES_DECRYPT); return 0; } static int ossl_aes_cbc_encrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) { ossldata *od = c->ptr; int err; if (!od->init) if ((err = ossl_aes_key_init(od, AES_ENCRYPT)) != 0) return err; AES_cbc_encrypt(data, res, dlen, &od->u.aes_key, od->iv, AES_ENCRYPT); return 0; } static int ossl_aes_cbc_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) { ossldata *od = c->ptr; int err; if (!od->init) if ((err = ossl_aes_key_init(od, AES_DECRYPT)) != 0) return err; AES_cbc_encrypt(data, res, dlen, &od->u.aes_key, od->iv, AES_DECRYPT); return 0; } /* * aliases */ static PX_Alias ossl_aliases[] = { {"bf", "bf-cbc"}, {"blowfish", "bf-cbc"}, {"blowfish-cbc", "bf-cbc"}, {"blowfish-ecb", "bf-ecb"}, {"blowfish-cfb", "bf-cfb"}, {"des", "des-cbc"}, {"3des", "des3-cbc"}, {"3des-ecb", "des3-ecb"}, {"3des-cbc", "des3-cbc"}, {"cast5", "cast5-cbc"}, {"aes", "aes-cbc"}, {"rijndael", "aes-cbc"}, {"rijndael-cbc", "aes-cbc"}, {"rijndael-ecb", "aes-ecb"}, {NULL} }; static const struct ossl_cipher ossl_bf_cbc = { bf_init, bf_cbc_encrypt, bf_cbc_decrypt, 64 / 8, 448 / 8, 0 }; static const struct ossl_cipher ossl_bf_ecb = { bf_init, bf_ecb_encrypt, bf_ecb_decrypt, 64 / 8, 448 / 8, 0 }; static const struct ossl_cipher ossl_bf_cfb = { bf_init, bf_cfb64_encrypt, bf_cfb64_decrypt, 64 / 8, 448 / 8, 1 }; static const struct ossl_cipher ossl_des_ecb = { ossl_des_init, ossl_des_ecb_encrypt, ossl_des_ecb_decrypt, 64 / 8, 64 / 8, 0 }; static const struct ossl_cipher ossl_des_cbc = { ossl_des_init, ossl_des_cbc_encrypt, ossl_des_cbc_decrypt, 64 / 8, 64 / 8, 0 }; static const struct ossl_cipher ossl_des3_ecb = { ossl_des3_init, ossl_des3_ecb_encrypt, ossl_des3_ecb_decrypt, 64 / 8, 192 / 8, 0 }; static const struct ossl_cipher ossl_des3_cbc = { ossl_des3_init, ossl_des3_cbc_encrypt, ossl_des3_cbc_decrypt, 64 / 8, 192 / 8, 0 }; static const struct ossl_cipher ossl_cast_ecb = { ossl_cast_init, ossl_cast_ecb_encrypt, ossl_cast_ecb_decrypt, 64 / 8, 128 / 8, 0 }; static const struct ossl_cipher ossl_cast_cbc = { ossl_cast_init, ossl_cast_cbc_encrypt, ossl_cast_cbc_decrypt, 64 / 8, 128 / 8, 0 }; static const struct ossl_cipher ossl_aes_ecb = { ossl_aes_init, ossl_aes_ecb_encrypt, ossl_aes_ecb_decrypt, 128 / 8, 256 / 8, 0 }; static const struct ossl_cipher ossl_aes_cbc = { ossl_aes_init, ossl_aes_cbc_encrypt, ossl_aes_cbc_decrypt, 128 / 8, 256 / 8, 0 }; /* * Special handlers */ struct ossl_cipher_lookup { const char *name; const struct ossl_cipher *ciph; }; static const struct ossl_cipher_lookup ossl_cipher_types[] = { {"bf-cbc", &ossl_bf_cbc}, {"bf-ecb", &ossl_bf_ecb}, {"bf-cfb", &ossl_bf_cfb}, {"des-ecb", &ossl_des_ecb}, {"des-cbc", &ossl_des_cbc}, {"des3-ecb", &ossl_des3_ecb}, {"des3-cbc", &ossl_des3_cbc}, {"cast5-ecb", &ossl_cast_ecb}, {"cast5-cbc", &ossl_cast_cbc}, {"aes-ecb", &ossl_aes_ecb}, {"aes-cbc", &ossl_aes_cbc}, {NULL} }; /* PUBLIC functions */ int px_find_cipher(const char *name, PX_Cipher **res) { const struct ossl_cipher_lookup *i; PX_Cipher *c = NULL; ossldata *od; name = px_resolve_alias(ossl_aliases, name); for (i = ossl_cipher_types; i->name; i++) if (!strcmp(i->name, name)) break; if (i->name == NULL) return PXE_NO_CIPHER; od = px_alloc(sizeof(*od)); memset(od, 0, sizeof(*od)); od->ciph = i->ciph; c = px_alloc(sizeof(*c)); c->block_size = gen_ossl_block_size; c->key_size = gen_ossl_key_size; c->iv_size = gen_ossl_iv_size; c->free = gen_ossl_free; c->init = od->ciph->init; c->encrypt = od->ciph->encrypt; c->decrypt = od->ciph->decrypt; c->ptr = od; *res = c; return 0; } static int openssl_random_init = 0; /* * OpenSSL random should re-feeded occasionally. From /dev/urandom * preferably. */ static void init_openssl_rand(void) { if (RAND_get_rand_method() == NULL) RAND_set_rand_method(RAND_SSLeay()); openssl_random_init = 1; } int px_get_random_bytes(uint8 *dst, unsigned count) { int res; if (!openssl_random_init) init_openssl_rand(); res = RAND_bytes(dst, count); if (res == 1) return count; return PXE_OSSL_RAND_ERROR; } int px_get_pseudo_random_bytes(uint8 *dst, unsigned count) { int res; if (!openssl_random_init) init_openssl_rand(); res = RAND_pseudo_bytes(dst, count); if (res == 0 || res == 1) return count; return PXE_OSSL_RAND_ERROR; } int px_add_entropy(const uint8 *data, unsigned count) { /* * estimate 0 bits */ RAND_add(data, count, 0); return 0; }