/* * ecp_des.c * * Written by Archie Cobbs * Copyright (c) 1998-1999 Whistle Communications, Inc. All rights reserved. * See ``COPYRIGHT.whistle'' */ #include "ppp.h" #include "ecp.h" /* * DEFINITIONS */ #define DES_OVERHEAD 2 /* * INTERNAL FUNCTIONS */ static int DesSubtractBloat(int size); static void DesConfigure(void); static Mbuf DesEncrypt(Mbuf plain); static Mbuf DesDecrypt(Mbuf cypher); static u_char *DesBuildConfigReq(u_char *cp); static void DesDecodeConfigReq(Fsm fp, FsmOption opt, int mode); /* * GLOBAL VARIABLES */ const struct enctype gDesEncType = { "des", ECP_TY_DES, NULL, DesConfigure, DesSubtractBloat, DesEncrypt, DesDecrypt, NULL, DesBuildConfigReq, DesDecodeConfigReq, NULL, NULL, NULL, }; /* * DesConfigure() */ static void DesConfigure(void) { EcpState const ecp = &bund->ecp; DesInfo const des = &ecp->des; des_cblock key; des_check_key = FALSE; des_string_to_key(ecp->key, &key); des_set_key(&key, des->ks); des->xmit_seq = 0; des->recv_seq = 0; } /* * DesSubtractBloat() */ static int DesSubtractBloat(int size) { size -= DES_OVERHEAD; size &= ~0x7; return(size); } /* * DesEncrypt() */ Mbuf DesEncrypt(Mbuf plain) { EcpState const ecp = &bund->ecp; DesInfo const des = &ecp->des; const int plen = plength(plain); const int clen = roundup2(plen, 8); Mbuf cypher; int k; /* Get mbuf for encrypted frame */ cypher = mballoc(MB_CRYPT, DES_OVERHEAD + clen); cypher->cnt = DES_OVERHEAD + clen; /* Copy in sequence number */ MBDATA(cypher)[0] = des->xmit_seq >> 8; MBDATA(cypher)[1] = des->xmit_seq & 0xff; des->xmit_seq++; /* Copy in plaintext and encrypt it */ mbcopy(plain, MBDATA(cypher) + DES_OVERHEAD, plen); for (k = 0; k < clen; k += 8) { u_char *const block = MBDATA(cypher) + DES_OVERHEAD + k; des_cbc_encrypt(block, block, 8, des->ks, &des->xmit_ivec, TRUE); memcpy(des->xmit_ivec, block, 8); } /* Return cyphertext */ PFREE(plain); return(cypher); } /* * DesDecrypt() */ Mbuf DesDecrypt(Mbuf cypher) { EcpState const ecp = &bund->ecp; DesInfo des = &ecp->des; const int clen = plength(cypher) - DES_OVERHEAD; u_int16_t seq; Mbuf plain; int k; /* Get mbuf for plaintext */ if (clen < 8 || (clen & 0x7)) { Log(LG_ECP, ("[%s] rec'd bogus DES cypher: len=%d", bund->name, clen + DES_OVERHEAD)); return(NULL); } /* Check sequence number */ cypher = mbread(cypher, (u_char *) &seq, DES_OVERHEAD, NULL); if (seq != des->recv_seq) { Mbuf tail; /* Recover from dropped packet */ Log(LG_ECP, ("[%s] rec'd wrong seq=%u, expected %u", bund->name, seq, des->recv_seq)); tail = mbsplit(cypher, clen - 8); PFREE(cypher); tail = mbread(tail, (u_char *) &des->recv_ivec, 8, NULL); assert(!tail); des->recv_seq = seq + 1; return(NULL); } des->recv_seq++; /* Decrypt frame */ plain = mbunify(cypher); for (k = 0; k < clen; k += 8) { u_char *const block = MBDATA(plain) + k; des_cblock next_ivec; memcpy(next_ivec, block, 8); des_cbc_encrypt(block, block, 8, des->ks, &des->recv_ivec, FALSE); memcpy(des->recv_ivec, next_ivec, 8); } /* Done */ return(plain); } /* * DesBuildConfigReq() */ static u_char * DesBuildConfigReq(u_char *cp) { EcpState const ecp = &bund->ecp; DesInfo const des = &ecp->des; des_random_key(&des->recv_ivec); return(FsmConfValue(cp, ECP_TY_DES, 8, &des->recv_ivec)); } /* * DesDecodeConfigReq() */ static void DesDecodeConfigReq(Fsm fp, FsmOption opt, int mode) { DesInfo const des = &bund->ecp.des; if (opt->len != 10) { Log(LG_ECP, (" bogus length %d", opt->len)); if (mode == MODE_REQ) FsmRej(fp, opt); return; } Log(LG_ECP, (" nonce 0x%08lx%08lx", (unsigned long)ntohl(((u_int32_t *) opt->data)[0]), (unsigned long)ntohl(((u_int32_t *) opt->data)[1]))); switch (mode) { case MODE_REQ: memcpy(des->xmit_ivec, opt->data, 8); FsmAck(fp, opt); break; case MODE_NAK: break; } }