|
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 |
};
|