#include "nfs_gss_crypto.h"
void
krb5_nfold(unsigned int inbits, const unsigned char *in, unsigned int outbits,
unsigned char *out)
{
int a,b,c,lcm;
int byte, i, msbit;
inbits >>= 3;
outbits >>= 3;
a = outbits;
b = inbits;
while(b != 0) {
c = b;
b = a%b;
a = c;
}
lcm = outbits*inbits/a;
memset(out, 0, outbits);
byte = 0;
for (i=lcm-1; i>=0; i--) {
msbit = (
((inbits<<3)-1)
+(((inbits<<3)+13)*(i/inbits))
+((inbits-(i%inbits))<<3)
)%(inbits<<3);
byte += (((in[((inbits-1)-(msbit>>3))%inbits]<<8)|
(in[((inbits)-(msbit>>3))%inbits]))
>>((msbit&7)+1))&0xff;
byte += out[i%outbits];
out[i%outbits] = byte&0xff;
#if 0
printf("msbit[%d] = %d\tbyte = %02x\tsum = %03x\n", i, msbit,
(((in[((inbits-1)-(msbit>>3))%inbits]<<8)|
(in[((inbits)-(msbit>>3))%inbits]))
>>((msbit&7)+1))&0xff, byte);
#endif
byte >>= 8;
#if 0
printf("carry=%d\n", byte);
#endif
}
if (byte) {
for (i=outbits-1; i>=0; i--) {
byte += out[i];
out[i] = byte&0xff;
byte >>= 8;
}
}
}
void
des3_make_key(const unsigned char randombits[21], des_cblock key[3])
{
int i;
for (i = 0; i < 3; i++) {
memcpy(&key[i], &randombits[i*7], 7);
key[i][7] = (((key[i][0] & 1) << 1) |
((key[i][1] & 1) << 2) |
((key[i][2] & 1) << 3) |
((key[i][3] & 1) << 4) |
((key[i][4] & 1) << 5) |
((key[i][5] & 1) << 6) |
((key[i][6] & 1) << 7));
des_fixup_key_parity(&key[i]);
}
}
int
des3_key_sched(des_cblock key[3], des_key_schedule sched[3])
{
int i;
int rc = 0;
for (i = 0; i < 3; i++)
rc |= des_key_sched(&key[i], sched[i]);
return (rc);
}
void
des3_cbc_encrypt(des_cblock *input, des_cblock *output, int32_t length,
des_key_schedule schedule[3], des_cblock *ivec, des_cblock *retvec, int encrypt)
{
register DES_LONG tin0,tin1;
register DES_LONG tout0,tout1,xor0,xor1;
register unsigned char *in,*out,*retval;
register int32_t l=length;
DES_LONG tin[2];
unsigned char *iv;
tin0 = tin1 = 0;
in=(unsigned char *)input;
out=(unsigned char *)output;
retval=(unsigned char *)retvec;
iv=(unsigned char *)ivec;
if (encrypt) {
c2l(iv,tout0);
c2l(iv,tout1);
for (l-=8; l>=0; l-=8) {
c2l(in,tin0);
c2l(in,tin1);
tin0^=tout0; tin[0]=tin0;
tin1^=tout1; tin[1]=tin1;
des_encrypt3((DES_LONG *)tin,schedule[0], schedule[1], schedule[2]);
tout0=tin[0]; l2c(tout0,out);
tout1=tin[1]; l2c(tout1,out);
}
if (l != -8) {
c2ln(in,tin0,tin1,l+8);
tin0^=tout0; tin[0]=tin0;
tin1^=tout1; tin[1]=tin1;
des_encrypt3((DES_LONG *)tin,schedule[0], schedule[1], schedule[2]);
tout0=tin[0]; l2c(tout0,out);
tout1=tin[1]; l2c(tout1,out);
}
if (retval) {
l2c(tout0,retval);
l2c(tout1,retval);
}
} else {
c2l(iv,xor0);
c2l(iv,xor1);
for (l-=8; l>=0; l-=8) {
c2l(in,tin0); tin[0]=tin0;
c2l(in,tin1); tin[1]=tin1;
des_decrypt3((DES_LONG *)tin,schedule[0],schedule[1],schedule[2]);
tout0=tin[0]^xor0;
tout1=tin[1]^xor1;
l2c(tout0,out);
l2c(tout1,out);
xor0=tin0;
xor1=tin1;
}
if (l != -8) {
c2l(in,tin0); tin[0]=tin0;
c2l(in,tin1); tin[1]=tin1;
des_decrypt3((DES_LONG *)tin,schedule[0],schedule[1],schedule[2]);
tout0=tin[0]^xor0;
tout1=tin[1]^xor1;
l2cn(tout0,tout1,out,l+8);
}
if (retval) {
l2c(tin0,retval);
l2c(tin1,retval);
}
}
tin0=tin1=tout0=tout1=xor0=xor1=0;
tin[0]=tin[1]=0;
}
int
des3_derive_key(des_cblock inkey[3], des_cblock outkey[3],
const unsigned char *constant, int clen)
{
des_cblock inblock, outblock, ivec;
des_key_schedule sched[3];
unsigned char rawkey[21];
size_t n, keybytes = sizeof(rawkey);
if (clen == sizeof(des_cblock)) {
memcpy(inblock, constant, clen);
} else {
krb5_nfold(clen*8, constant, sizeof(des_cblock)*8, inblock);
}
bzero(ivec, sizeof(ivec));
des3_key_sched(inkey, sched);
for (n = 0; n < sizeof(rawkey); n += sizeof(des_cblock)) {
des3_cbc_encrypt(&inblock, &outblock, sizeof(outblock), sched, &ivec, NULL, 1);
if ((keybytes - n) <= sizeof (des_cblock)) {
memcpy(rawkey+n, outblock, (keybytes - n));
break;
}
memcpy(rawkey+n, outblock, sizeof(des_cblock));
memcpy(inblock, outblock, sizeof(des_cblock));
}
des3_make_key(rawkey, outkey);
bzero(inblock, sizeof (des_cblock));
bzero(outblock, sizeof (des_cblock));
bzero(rawkey, keybytes);
bzero(sched, sizeof (sched));
return(0);
}
void
HMAC_SHA1_DES3KD_Init(HMAC_SHA1_DES3KD_CTX *ctx, des_cblock key[3], int derive)
{
unsigned char ipad[64];
size_t i, j;
SHA1Init(&ctx->sha1_ctx);
if (derive)
des3_derive_key(key, ctx->dk, KEY_USAGE_DES3_SIGN, KEY_USAGE_LEN);
else
memcpy(ctx->dk, key, 3*sizeof(des_cblock));
memset(ipad, 0x36, sizeof(ipad));
for (i = 0; i < 3; i++)
for (j = 0; j < sizeof(des_cblock); j++)
ipad[j + i * sizeof(des_cblock)] ^= ctx->dk[i][j];
SHA1Update(&ctx->sha1_ctx, ipad, sizeof(ipad));
}
void
HMAC_SHA1_DES3KD_Update(HMAC_SHA1_DES3KD_CTX *ctx, void *data, size_t len)
{
SHA1Update(&ctx->sha1_ctx, data, len);
}
void
HMAC_SHA1_DES3KD_Final(void *digest, HMAC_SHA1_DES3KD_CTX *ctx)
{
unsigned char opad[64];
size_t i, j;
SHA1Final(digest, &ctx->sha1_ctx);
memset(opad, 0x5c, sizeof(opad));
for (i = 0; i < 3; i++)
for (j = 0; j < sizeof(des_cblock); j++)
opad[j + i * sizeof(des_cblock)] ^= ctx->dk[i][j];
SHA1Init(&ctx->sha1_ctx);
SHA1Update(&ctx->sha1_ctx, opad, sizeof(opad));
SHA1Update(&ctx->sha1_ctx, digest, SHA1_RESULTLEN);
SHA1Final(digest, &ctx->sha1_ctx);
}
DES_LONG
des_cbc_cksum(des_cblock *input, des_cblock *output,
int32_t length, des_key_schedule schedule, des_cblock *ivec)
{
register DES_LONG tout0,tout1,tin0,tin1;
register int32_t l=length;
DES_LONG tin[2];
unsigned char *in,*out,*iv;
in=(unsigned char *)input;
out=(unsigned char *)output;
iv=(unsigned char *)ivec;
c2l(iv,tout0);
c2l(iv,tout1);
for (; l>0; l-=8) {
if (l >= 8) {
c2l(in,tin0);
c2l(in,tin1);
} else
c2ln(in,tin0,tin1,l);
tin0^=tout0; tin[0]=tin0;
tin1^=tout1; tin[1]=tin1;
des_encrypt1((DES_LONG *)tin,schedule,DES_ENCRYPT);
tout0=tin[0];
tout1=tin[1];
}
if (out != NULL) {
l2c(tout0,out);
l2c(tout1,out);
}
tout0=tin0=tin1=tin[0]=tin[1]=0;
return(tout1);
}
void
des_cbc_encrypt(des_cblock *input, des_cblock *output, int32_t length,
des_key_schedule schedule, des_cblock *ivec, des_cblock *retvec, int encrypt)
{
register DES_LONG tin0,tin1;
register DES_LONG tout0,tout1,xor0,xor1;
register unsigned char *in,*out,*retval;
register int32_t l=length;
DES_LONG tin[2];
unsigned char *iv;
tin0 = tin1 = 0;
in=(unsigned char *)input;
out=(unsigned char *)output;
retval=(unsigned char *)retvec;
iv=(unsigned char *)ivec;
if (encrypt) {
c2l(iv,tout0);
c2l(iv,tout1);
for (l-=8; l>=0; l-=8) {
c2l(in,tin0);
c2l(in,tin1);
tin0^=tout0; tin[0]=tin0;
tin1^=tout1; tin[1]=tin1;
des_encrypt1((DES_LONG *)tin,schedule,DES_ENCRYPT);
tout0=tin[0]; l2c(tout0,out);
tout1=tin[1]; l2c(tout1,out);
}
if (l != -8) {
c2ln(in,tin0,tin1,l+8);
tin0^=tout0; tin[0]=tin0;
tin1^=tout1; tin[1]=tin1;
des_encrypt1((DES_LONG *)tin,schedule,DES_ENCRYPT);
tout0=tin[0]; l2c(tout0,out);
tout1=tin[1]; l2c(tout1,out);
}
if (retval) {
l2c(tout0,retval);
l2c(tout1,retval);
}
} else {
c2l(iv,xor0);
c2l(iv,xor1);
for (l-=8; l>=0; l-=8) {
c2l(in,tin0); tin[0]=tin0;
c2l(in,tin1); tin[1]=tin1;
des_encrypt1((DES_LONG *)tin,schedule,DES_DECRYPT);
tout0=tin[0]^xor0;
tout1=tin[1]^xor1;
l2c(tout0,out);
l2c(tout1,out);
xor0=tin0;
xor1=tin1;
}
if (l != -8) {
c2l(in,tin0); tin[0]=tin0;
c2l(in,tin1); tin[1]=tin1;
des_encrypt1((DES_LONG *)tin,schedule,DES_DECRYPT);
tout0=tin[0]^xor0;
tout1=tin[1]^xor1;
l2cn(tout0,tout1,out,l+8);
}
if (retval) {
l2c(tin0,retval);
l2c(tin1,retval);
}
}
tin0=tin1=tout0=tout1=xor0=xor1=0;
tin[0]=tin[1]=0;
}
void MD5_DESCBC_Init(MD5_DESCBC_CTX *ctx, des_key_schedule *sched)
{
MD5Init(&ctx->md5_ctx);
ctx->sched = sched;
}
void MD5_DESCBC_Update(MD5_DESCBC_CTX *ctx, void *data, size_t len)
{
MD5Update(&ctx->md5_ctx, data, len);
}
void MD5_DESCBC_Final(void *digest, MD5_DESCBC_CTX *ctx)
{
des_cblock iv0;
unsigned char md5_digest[MD5_DIGEST_LENGTH];
MD5Final(md5_digest, &ctx->md5_ctx);
bzero(iv0, sizeof (iv0));
(void) des_cbc_cksum((des_cblock *) md5_digest, (des_cblock *)digest,
sizeof (md5_digest), *ctx->sched, &iv0);
}