/* * Copyright (c) 1995 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Network Research * Group at Lawrence Berkeley National Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ static const char rcsid[] = "@(#) $Header: crypt-vat.cc,v 1.3 96/03/16 13:12:48 van Exp $ (LBL)"; #include "crypt.h" #include "inet.h" #include "rtp.h" extern "C" { extern void DesQuickInit(); extern int DesMethod(u_char* m, const u_char* k); extern int DesQuickFipsEncrypt(u_char* dst, const u_char* m, const u_char* src); extern int DesQuickFipsDecrypt(u_char* dst, const u_char* m, const u_char* src); } class CryptVAT : public Crypt { public: CryptVAT(); ~CryptVAT(); virtual int command(int argc, const char*const* argv); virtual int install_key(const u_int8_t* key); virtual u_char* Encrypt(const u_char* in, int& len); virtual int Decrypt(const u_char* in, int len, u_char* out); protected: int encrypt(u_int32_t* blk, const u_char* in, int len, u_char* rh); int decrypt(const u_char* in, int len, u_char* out, int rtcp); static int didinit_; u_char* wrkbuf_; u_char mkey_[128]; }; class CryptVATctrl : public CryptVAT { public: virtual u_char* Encrypt(const u_char* in, int& len); virtual int Decrypt(const u_char* in, int len, u_char* out); }; static class CryptVATMatcher : public Matcher { public: CryptVATMatcher() : Matcher("crypt") {} TclObject* match(const char* id) { if (strcmp(id, "VAT/data") == 0) return (new CryptVAT); if (strcmp(id, "VAT/ctrl") == 0) return (new CryptVATctrl); return (0); } } vat_matcher; int CryptVAT::didinit_; CryptVAT::CryptVAT() { if (didinit_ == 0) { DesQuickInit(); didinit_ = 1; } /* enough extra space for padding and RTCP 4-byte random header */ wrkbuf_ = new u_char[RTP_MTU + 8 + 4]; } CryptVAT::~CryptVAT() { delete wrkbuf_; } int CryptVAT::install_key(const u_int8_t* keystr) { /* DES key */ u_char key[8]; memset((char*)key, 0, sizeof(key)); register int i, l = strlen((const char*)keystr); for (i = 0; i < l; ++i) key[i & 7] += keystr[i]; /* make the key odd parity */ for (i = 0; i < 8; ++i) { int j = key[i]; j ^= j >> 4; j ^= j >> 2; j ^= j >> 1; if ((j & 1) == 0) { j = 0x80; while (key[i] & j) j >>= 1; key[i] |= j; } } return (DesMethod(mkey_, key)); } int CryptVAT::command(int argc, const char*const* argv) { if (argc == 3) { if (strcmp(argv[1], "key") == 0) { Tcl& tcl = Tcl::instance(); if (install_key((const u_char*)argv[2]) != 0) tcl.result("0"); else tcl.result("1"); return (TCL_OK); } } return (Crypt::command(argc, argv)); } int CryptVAT::encrypt(u_int32_t* blk, const u_char* in, int len, u_char* rh) { int pad = len & 7; if (pad != 0) { /* pad to an block (8 octet) boundary */ pad = 8 - pad; rh[1] |= 0x40; // set vat 'pad' bit } register u_int32_t* wp = (u_int32_t*)wrkbuf_; const u_char* m = mkey_; DesQuickFipsEncrypt((u_char*)wp, m, (const u_char*)blk); const u_int32_t* bp = (const u_int32_t*)in; for (int i = len >> 3; --i >= 0; ) { blk[0] = bp[0] ^ wp[0]; blk[1] = bp[1] ^ wp[1]; wp += 2; DesQuickFipsEncrypt((u_char*)wp, m, (const u_char*)blk); bp += 2; } if (pad > 0) { len += pad; blk[0] = bp[0]; blk[1] = bp[1]; u_char* cp = (u_char*)blk + 7; *cp = pad; while (--pad > 0) *--cp = 0; blk[0] ^= wp[0]; blk[1] ^= wp[1]; wp += 2; DesQuickFipsEncrypt((u_char*)wp, m, (u_char*)blk); } return (len); } int CryptVAT::decrypt(const u_char* in, int len, u_char* out, int rtcp) { register u_int32_t* wp = (u_int32_t*)out; const u_int32_t* bp = (const u_int32_t*)in; const u_char* m = mkey_; /* check that packet is an integral number of blocks */ if ((len & 7) != 0) { ++badpktlen_; return (-1); } int nblk = len >> 3; DesQuickFipsDecrypt((u_char*)wp, m, (const u_char*)bp); bp += 2; nblk -= 1; if (rtcp) { /* throw away random RTCP header */ wp[0] = wp[1]; wp += 1; len -= 4; } else wp += 2; while (--nblk >= 0) { DesQuickFipsDecrypt((u_char*)wp, m, (const u_char*)bp); wp[0] ^= bp[-2]; wp[1] ^= bp[-1]; bp += 2; wp += 2; } if ((out[1] & 0x40) != 0) { /* P bit set - trim off padding */ int pad = out[len - 1]; if (pad > 7 || pad == 0) { ++badpbit_; return (-1); } len -= pad; } return (len); } u_char* CryptVAT::Encrypt(const u_char* in, int& len) { u_int32_t blk[2]; blk[0] = *(u_int32_t*)in; blk[1] = *(u_int32_t*)(in + 4); len = encrypt(blk, in + 8, len - 8, (u_char*)blk) + 8; return (wrkbuf_); } int CryptVAT::Decrypt(const u_char* in, int len, u_char* out) { return (decrypt(in, len, out, 0)); } u_char* CryptVATctrl::Encrypt(const u_char* in, int& len) { if (len & 7) { u_char* cp = (u_char*)in + len; while (len & 7) { *cp++ = 0; ++len; } } return (CryptVAT::Encrypt(in, len)); } int CryptVATctrl::Decrypt(const u_char* in, int len, u_char* out) { return (CryptVAT::Decrypt(in, len, out)); }