Blame src/lib/crypto/openssl/enc_provider/rc4.c

Packit fd8b60
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
Packit fd8b60
/* lib/crypto/openssl/enc_provider/rc4.c */
Packit fd8b60
/*
Packit fd8b60
 * Copyright (C) 2009 by the Massachusetts Institute of Technology.
Packit fd8b60
 * All rights reserved.
Packit fd8b60
 *
Packit fd8b60
 * Export of this software from the United States of America may
Packit fd8b60
 *   require a specific license from the United States Government.
Packit fd8b60
 *   It is the responsibility of any person or organization contemplating
Packit fd8b60
 *   export to obtain such a license before exporting.
Packit fd8b60
 *
Packit fd8b60
 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
Packit fd8b60
 * distribute this software and its documentation for any purpose and
Packit fd8b60
 * without fee is hereby granted, provided that the above copyright
Packit fd8b60
 * notice appear in all copies and that both that copyright notice and
Packit fd8b60
 * this permission notice appear in supporting documentation, and that
Packit fd8b60
 * the name of M.I.T. not be used in advertising or publicity pertaining
Packit fd8b60
 * to distribution of the software without specific, written prior
Packit fd8b60
 * permission.  Furthermore if you modify this software you must label
Packit fd8b60
 * your software as modified software and not distribute it in such a
Packit fd8b60
 * fashion that it might be confused with the original M.I.T. software.
Packit fd8b60
 * M.I.T. makes no representations about the suitability of
Packit fd8b60
 * this software for any purpose.  It is provided "as is" without express
Packit fd8b60
 * or implied warranty.
Packit fd8b60
 */
Packit fd8b60
Packit fd8b60
/*
Packit fd8b60
 * Copyright (c) 2000 by Computer Science Laboratory,
Packit fd8b60
 *                       Rensselaer Polytechnic Institute
Packit fd8b60
 *
Packit fd8b60
 * #include STD_DISCLAIMER
Packit fd8b60
 */
Packit fd8b60
Packit fd8b60
Packit fd8b60
#include "crypto_int.h"
Packit fd8b60
#include <openssl/evp.h>
Packit fd8b60
Packit fd8b60
/*
Packit fd8b60
 * The loopback field is a pointer to the structure.  If the application copies
Packit fd8b60
 * the state (not a valid operation, but one which happens to works with some
Packit fd8b60
 * other enc providers), we can detect it via the loopback field and return a
Packit fd8b60
 * sane error code.
Packit fd8b60
 */
Packit fd8b60
struct arcfour_state {
Packit fd8b60
    struct arcfour_state *loopback;
Packit fd8b60
    EVP_CIPHER_CTX *ctx;
Packit fd8b60
};
Packit fd8b60
Packit fd8b60
#define RC4_KEY_SIZE 16
Packit fd8b60
#define RC4_BLOCK_SIZE 1
Packit fd8b60
Packit fd8b60
/* Interface layer to krb5 crypto layer */
Packit fd8b60
Packit fd8b60
/* The workhorse of the arcfour system,
Packit fd8b60
 * this impliments the cipher
Packit fd8b60
 */
Packit fd8b60
Packit fd8b60
/* In-place IOV crypto */
Packit fd8b60
static krb5_error_code
Packit fd8b60
k5_arcfour_docrypt(krb5_key key, const krb5_data *state, krb5_crypto_iov *data,
Packit fd8b60
                   size_t num_data)
Packit fd8b60
{
Packit fd8b60
    size_t i;
Packit fd8b60
    int ret = 1, tmp_len = 0;
Packit fd8b60
    krb5_crypto_iov *iov     = NULL;
Packit fd8b60
    EVP_CIPHER_CTX *ctx = NULL;
Packit fd8b60
    struct arcfour_state *arcstate;
Packit fd8b60
Packit fd8b60
    arcstate = (state != NULL) ? (void *)state->data : NULL;
Packit fd8b60
    if (arcstate != NULL) {
Packit fd8b60
        ctx = arcstate->ctx;
Packit fd8b60
        if (arcstate->loopback != arcstate)
Packit fd8b60
            return KRB5_CRYPTO_INTERNAL;
Packit fd8b60
    }
Packit fd8b60
Packit fd8b60
    if (ctx == NULL) {
Packit fd8b60
        ctx = EVP_CIPHER_CTX_new();
Packit fd8b60
        if (ctx == NULL)
Packit fd8b60
            return ENOMEM;
Packit fd8b60
Packit fd8b60
        ret = EVP_EncryptInit_ex(ctx, EVP_rc4(), NULL, key->keyblock.contents,
Packit fd8b60
                                 NULL);
Packit fd8b60
        if (!ret) {
Packit fd8b60
            EVP_CIPHER_CTX_free(ctx);
Packit fd8b60
            return KRB5_CRYPTO_INTERNAL;
Packit fd8b60
        }
Packit fd8b60
Packit fd8b60
        if (arcstate != NULL)
Packit fd8b60
            arcstate->ctx = ctx;
Packit fd8b60
    }
Packit fd8b60
Packit fd8b60
    for (i = 0; i < num_data; i++) {
Packit fd8b60
        iov = &data[i];
Packit fd8b60
        if (ENCRYPT_IOV(iov)) {
Packit fd8b60
            ret = EVP_EncryptUpdate(ctx,
Packit fd8b60
                                    (unsigned char *) iov->data.data, &tmp_len,
Packit fd8b60
                                    (unsigned char *) iov->data.data,
Packit fd8b60
                                    iov->data.length);
Packit fd8b60
            if (!ret)
Packit fd8b60
                break;
Packit fd8b60
        }
Packit fd8b60
    }
Packit fd8b60
Packit fd8b60
    if (arcstate == NULL)
Packit fd8b60
        EVP_CIPHER_CTX_free(ctx);
Packit fd8b60
Packit fd8b60
    if (!ret)
Packit fd8b60
        return KRB5_CRYPTO_INTERNAL;
Packit fd8b60
Packit fd8b60
    return 0;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
static void
Packit fd8b60
k5_arcfour_free_state(krb5_data *state)
Packit fd8b60
{
Packit Service e737ee
    struct arcfour_state *arcstate = (void *)state->data;
Packit fd8b60
Packit fd8b60
    EVP_CIPHER_CTX_free(arcstate->ctx);
Packit fd8b60
    free(arcstate);
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
static krb5_error_code
Packit fd8b60
k5_arcfour_init_state(const krb5_keyblock *key,
Packit fd8b60
                      krb5_keyusage keyusage, krb5_data *new_state)
Packit fd8b60
{
Packit fd8b60
    struct arcfour_state *arcstate;
Packit fd8b60
Packit fd8b60
    /*
Packit fd8b60
     * The cipher state here is a saved pointer to a struct arcfour_state
Packit fd8b60
     * object, rather than a flat byte array as in most enc providers.  The
Packit fd8b60
     * object includes a loopback pointer to detect if if the caller made a
Packit fd8b60
     * copy of the krb5_data value or otherwise assumed it was a simple byte
Packit fd8b60
     * array.  When we cast the data pointer back, we need to go through void *
Packit fd8b60
     * to avoid increased alignment warnings.
Packit fd8b60
     */
Packit fd8b60
Packit fd8b60
    /* Create a state structure with an uninitialized context. */
Packit fd8b60
    arcstate = calloc(1, sizeof(*arcstate));
Packit fd8b60
    if (arcstate == NULL)
Packit fd8b60
        return ENOMEM;
Packit fd8b60
    arcstate->loopback = arcstate;
Packit fd8b60
    arcstate->ctx = NULL;
Packit fd8b60
    new_state->data = (char *) arcstate;
Packit fd8b60
    new_state->length = sizeof(*arcstate);
Packit fd8b60
    return 0;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
/* Since the arcfour cipher is identical going forwards and backwards,
Packit fd8b60
   we just call "docrypt" directly
Packit fd8b60
*/
Packit fd8b60
const struct krb5_enc_provider krb5int_enc_arcfour = {
Packit fd8b60
    /* This seems to work... although I am not sure what the
Packit fd8b60
       implications are in other places in the kerberos library */
Packit fd8b60
    RC4_BLOCK_SIZE,
Packit fd8b60
    /* Keysize is arbitrary in arcfour, but the constraints of the
Packit fd8b60
       system, and to attempt to work with the MSFT system forces us
Packit fd8b60
       to 16byte/128bit.  Since there is no parity in the key, the
Packit fd8b60
       byte and length are the same.  */
Packit fd8b60
    RC4_KEY_SIZE, RC4_KEY_SIZE,
Packit fd8b60
    k5_arcfour_docrypt,
Packit fd8b60
    k5_arcfour_docrypt,
Packit fd8b60
    NULL,
Packit fd8b60
    k5_arcfour_init_state,
Packit fd8b60
    k5_arcfour_free_state
Packit fd8b60
};