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

Packit fd8b60
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
Packit fd8b60
/* lib/crypto/builtin/enc_provider/rc4.c */
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
#include "crypto_int.h"
Packit fd8b60
Packit fd8b60
typedef struct
Packit fd8b60
{
Packit fd8b60
    unsigned int x;
Packit fd8b60
    unsigned int y;
Packit fd8b60
    unsigned char state[256];
Packit fd8b60
} ArcfourContext;
Packit fd8b60
Packit fd8b60
typedef struct {
Packit fd8b60
    int initialized;
Packit fd8b60
    ArcfourContext ctx;
Packit fd8b60
} ArcFourCipherState;
Packit fd8b60
Packit fd8b60
/* gets the next byte from the PRNG */
Packit fd8b60
#if ((__GNUC__ >= 2) )
Packit fd8b60
static __inline__ unsigned int k5_arcfour_byte(ArcfourContext *);
Packit fd8b60
#else
Packit fd8b60
static unsigned int k5_arcfour_byte(ArcfourContext *);
Packit fd8b60
#endif /* gcc inlines*/
Packit fd8b60
Packit fd8b60
/* Initializes the context and sets the key. */
Packit fd8b60
static krb5_error_code k5_arcfour_init(ArcfourContext *ctx, const unsigned char *key,
Packit fd8b60
                                       unsigned int keylen);
Packit fd8b60
Packit fd8b60
/* Encrypts/decrypts data. */
Packit fd8b60
static void k5_arcfour_crypt(ArcfourContext *ctx, unsigned char *dest,
Packit fd8b60
                             const unsigned char *src, unsigned int len);
Packit fd8b60
Packit fd8b60
static inline unsigned int k5_arcfour_byte(ArcfourContext * ctx)
Packit fd8b60
{
Packit fd8b60
    unsigned int x;
Packit fd8b60
    unsigned int y;
Packit fd8b60
    unsigned int sx, sy;
Packit fd8b60
    unsigned char *state;
Packit fd8b60
Packit fd8b60
    state = ctx->state;
Packit fd8b60
    x = (ctx->x + 1) & 0xff;
Packit fd8b60
    sx = state[x];
Packit fd8b60
    y = (sx + ctx->y) & 0xff;
Packit fd8b60
    sy = state[y];
Packit fd8b60
    ctx->x = x;
Packit fd8b60
    ctx->y = y;
Packit fd8b60
    state[y] = sx;
Packit fd8b60
    state[x] = sy;
Packit fd8b60
    return state[(sx + sy) & 0xff];
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
static void k5_arcfour_crypt(ArcfourContext *ctx, unsigned char *dest,
Packit fd8b60
                             const unsigned char *src, unsigned int len)
Packit fd8b60
{
Packit fd8b60
    unsigned int i;
Packit fd8b60
    for (i = 0; i < len; i++)
Packit fd8b60
        dest[i] = src[i] ^ k5_arcfour_byte(ctx);
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
Packit fd8b60
static krb5_error_code
Packit fd8b60
k5_arcfour_init(ArcfourContext *ctx, const unsigned char *key,
Packit fd8b60
                unsigned int key_len)
Packit fd8b60
{
Packit fd8b60
    unsigned int t, u;
Packit fd8b60
    unsigned int keyindex;
Packit fd8b60
    unsigned int stateindex;
Packit fd8b60
    unsigned char* state;
Packit fd8b60
    unsigned int counter;
Packit fd8b60
Packit fd8b60
    if (key_len != 16)
Packit fd8b60
        return KRB5_BAD_MSIZE;     /*this is probably not the correct error code
Packit fd8b60
                                     to return */
Packit fd8b60
    state = &ctx->state[0];
Packit fd8b60
    ctx->x = 0;
Packit fd8b60
    ctx->y = 0;
Packit fd8b60
    for (counter = 0; counter < 256; counter++)
Packit fd8b60
        state[counter] = counter;
Packit fd8b60
    keyindex = 0;
Packit fd8b60
    stateindex = 0;
Packit fd8b60
    for (counter = 0; counter < 256; counter++)
Packit fd8b60
    {
Packit fd8b60
        t = state[counter];
Packit fd8b60
        stateindex = (stateindex + key[keyindex] + t) & 0xff;
Packit fd8b60
        u = state[stateindex];
Packit fd8b60
        state[stateindex] = t;
Packit fd8b60
        state[counter] = u;
Packit fd8b60
        if (++keyindex >= key_len)
Packit fd8b60
            keyindex = 0;
Packit fd8b60
    }
Packit fd8b60
    return 0;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
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
    ArcfourContext *arcfour_ctx = NULL;
Packit fd8b60
    ArcFourCipherState *cipher_state = NULL;
Packit fd8b60
    krb5_error_code ret;
Packit fd8b60
    size_t i;
Packit fd8b60
Packit fd8b60
    if (key->keyblock.length != 16)
Packit fd8b60
        return KRB5_BAD_KEYSIZE;
Packit fd8b60
    if (state != NULL && (state->length != sizeof(ArcFourCipherState)))
Packit fd8b60
        return KRB5_BAD_MSIZE;
Packit fd8b60
Packit fd8b60
    if (state != NULL) {
Packit fd8b60
        cipher_state = (ArcFourCipherState *)(void *)state->data;
Packit fd8b60
        arcfour_ctx = &cipher_state->ctx;
Packit fd8b60
        if (cipher_state->initialized == 0) {
Packit fd8b60
            ret = k5_arcfour_init(arcfour_ctx, key->keyblock.contents,
Packit fd8b60
                                  key->keyblock.length);
Packit fd8b60
            if (ret != 0)
Packit fd8b60
                return ret;
Packit fd8b60
Packit fd8b60
            cipher_state->initialized = 1;
Packit fd8b60
        }
Packit fd8b60
    } else {
Packit fd8b60
        arcfour_ctx = (ArcfourContext *)malloc(sizeof(ArcfourContext));
Packit fd8b60
        if (arcfour_ctx == NULL)
Packit fd8b60
            return ENOMEM;
Packit fd8b60
Packit fd8b60
        ret = k5_arcfour_init(arcfour_ctx, key->keyblock.contents,
Packit fd8b60
                              key->keyblock.length);
Packit fd8b60
        if (ret != 0) {
Packit fd8b60
            free(arcfour_ctx);
Packit fd8b60
            return ret;
Packit fd8b60
        }
Packit fd8b60
    }
Packit fd8b60
Packit fd8b60
    for (i = 0; i < num_data; i++) {
Packit fd8b60
        krb5_crypto_iov *iov = &data[i];
Packit fd8b60
Packit fd8b60
        if (ENCRYPT_IOV(iov))
Packit fd8b60
            k5_arcfour_crypt(arcfour_ctx, (unsigned char *)iov->data.data,
Packit fd8b60
                             (const unsigned char *)iov->data.data, iov->data.length);
Packit fd8b60
    }
Packit fd8b60
Packit fd8b60
    if (state == NULL)
Packit fd8b60
        zapfree(arcfour_ctx, sizeof(ArcfourContext));
Packit fd8b60
Packit fd8b60
    return 0;
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
    /* Note that we can't actually set up the state here  because the key
Packit fd8b60
     * will change  between now and when encrypt is called
Packit fd8b60
     * because  it is data dependent.  Yeah, this has strange
Packit fd8b60
     * properties. --SDH
Packit fd8b60
     */
Packit fd8b60
    new_state->length = sizeof (ArcFourCipherState);
Packit fd8b60
    new_state->data = malloc (new_state->length);
Packit fd8b60
    if (new_state->data) {
Packit fd8b60
        memset (new_state->data, 0 , new_state->length);
Packit fd8b60
        /* That will set initialized to zero*/
Packit fd8b60
    }else {
Packit fd8b60
        return (ENOMEM);
Packit fd8b60
    }
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
    1,
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
    16, 16,
Packit fd8b60
    k5_arcfour_docrypt,
Packit fd8b60
    k5_arcfour_docrypt,
Packit fd8b60
    NULL,
Packit fd8b60
    k5_arcfour_init_state, /*xxx not implemented yet*/
Packit fd8b60
    krb5int_default_free_state
Packit fd8b60
};