#include "k5-int.h"
#include "arcfour-int.h"
#include "enc_provider.h"
#if ((__GNUC__ >= 2) )
static __inline__ unsigned int k5_arcfour_byte(ArcfourContext *);
#else
static unsigned int k5_arcfour_byte(ArcfourContext *);
#endif
static krb5_error_code k5_arcfour_init(ArcfourContext *ctx, const unsigned char *key,
unsigned int keylen);
static void k5_arcfour_crypt(ArcfourContext *ctx, unsigned char *dest,
const unsigned char *src, unsigned int len);
static krb5_error_code
k5_arcfour_docrypt(const krb5_keyblock *, const krb5_data *,
const krb5_data *, krb5_data *);
static krb5_error_code
k5_arcfour_make_key(const krb5_data *, krb5_keyblock *);
static const unsigned char arcfour_weakkey1[] = {0x00, 0x00, 0xfd};
static const unsigned char arcfour_weakkey2[] = {0x03, 0xfd, 0xfc};
static const krb5_data arcfour_weakkeys[] = {
{KV5M_DATA, sizeof (arcfour_weakkey1),
(char * ) arcfour_weakkey1},
{KV5M_DATA, sizeof (arcfour_weakkey2),
(char * ) arcfour_weakkey2},
{KV5M_DATA, 0, 0}
};
#if ((__GNUC__ >= 2) )
static __inline__ unsigned int k5_arcfour_byte(ArcfourContext * ctx)
#else
static unsigned int k5_arcfour_byte(ArcfourContext * ctx)
#endif
{
unsigned int x;
unsigned int y;
unsigned int sx, sy;
unsigned char *state;
state = ctx->state;
x = (ctx->x + 1) & 0xff;
sx = state[x];
y = (sx + ctx->y) & 0xff;
sy = state[y];
ctx->x = x;
ctx->y = y;
state[y] = sx;
state[x] = sy;
return state[(sx + sy) & 0xff];
}
static void k5_arcfour_crypt(ArcfourContext *ctx, unsigned char *dest,
const unsigned char *src, unsigned int len)
{
unsigned int i;
for (i = 0; i < len; i++)
dest[i] = src[i] ^ k5_arcfour_byte(ctx);
}
static krb5_error_code
k5_arcfour_init(ArcfourContext *ctx, const unsigned char *key,
unsigned int key_len)
{
unsigned int t, u;
unsigned int keyindex;
unsigned int stateindex;
unsigned char* state;
unsigned int counter;
if (key_len != 16)
return KRB5_BAD_MSIZE;
for(counter=0;arcfour_weakkeys[counter].length >0; counter++)
if (memcmp(key, arcfour_weakkeys[counter].data,
arcfour_weakkeys[counter].length) == 0)
return KRB5DES_WEAK_KEY;
state = &ctx->state[0];
ctx->x = 0;
ctx->y = 0;
for (counter = 0; counter < 256; counter++)
state[counter] = counter;
keyindex = 0;
stateindex = 0;
for (counter = 0; counter < 256; counter++)
{
t = state[counter];
stateindex = (stateindex + key[keyindex] + t) & 0xff;
u = state[stateindex];
state[stateindex] = t;
state[counter] = u;
if (++keyindex >= key_len)
keyindex = 0;
}
return 0;
}
static krb5_error_code
k5_arcfour_docrypt(const krb5_keyblock *key, const krb5_data *state,
const krb5_data *input, krb5_data *output)
{
ArcfourContext *arcfour_ctx;
ArcFourCipherState *cipher_state;
int ret;
if (key->length != 16)
return(KRB5_BAD_KEYSIZE);
if (state && (state->length != sizeof (ArcFourCipherState)))
return(KRB5_BAD_MSIZE);
if (input->length != output->length)
return(KRB5_BAD_MSIZE);
if (state) {
cipher_state = (ArcFourCipherState *) state->data;
arcfour_ctx=&cipher_state->ctx;
if (cipher_state->initialized == 0) {
if ((ret=k5_arcfour_init(arcfour_ctx, key->contents, key->length))) {
return ret;
}
cipher_state->initialized = 1;
}
k5_arcfour_crypt(arcfour_ctx, (unsigned char *) output->data, (const unsigned char *) input->data, input->length);
}
else {
arcfour_ctx=malloc(sizeof (ArcfourContext));
if (arcfour_ctx == NULL)
return ENOMEM;
if ((ret=k5_arcfour_init(arcfour_ctx, key->contents, key->length))) {
free(arcfour_ctx);
return (ret);
}
k5_arcfour_crypt(arcfour_ctx, (unsigned char * ) output->data,
(const unsigned char * ) input->data, input->length);
memset(arcfour_ctx, 0, sizeof (ArcfourContext));
free(arcfour_ctx);
}
return 0;
}
static krb5_error_code
k5_arcfour_make_key(const krb5_data *randombits, krb5_keyblock *key)
{
if (key->length != 16)
return(KRB5_BAD_KEYSIZE);
if (randombits->length != 16)
return(KRB5_CRYPTO_INTERNAL);
key->magic = KV5M_KEYBLOCK;
key->length = 16;
memcpy(key->contents, randombits->data, randombits->length);
return(0);
}
static krb5_error_code
k5_arcfour_init_state (const krb5_keyblock *key,
krb5_keyusage keyusage, krb5_data *new_state)
{
new_state->length = sizeof (ArcFourCipherState);
new_state->data = malloc (new_state->length);
if (new_state->data) {
memset (new_state->data, 0 , new_state->length);
}else {
return (ENOMEM);
}
return 0;
}
const struct krb5_enc_provider krb5int_enc_arcfour = {
1,
16, 16,
k5_arcfour_docrypt,
k5_arcfour_docrypt,
k5_arcfour_make_key,
k5_arcfour_init_state,
krb5int_default_free_state
};