├── contrib ├── .gitignore ├── rijndael-alg-fst.h ├── cmac.h ├── umac.h ├── ocb.h ├── win_port.h └── cmac.c ├── lib ├── .gitignore └── libtcpcrypt.sym ├── util ├── .gitignore ├── README.markdown ├── tcnetstat.man.md ├── tcnetstat.man ├── tcnetstat.c └── tcs.c ├── src ├── .gitignore ├── resource.h ├── util.h ├── res.rc ├── priv.h ├── tcpcrypt_version.h.in ├── util.c ├── test.h ├── checksum.h ├── tcpcrypt_strings.h ├── inc.h ├── tcpcryptd.exe.manifest ├── tcpcrypt_ctl.h ├── profile.h ├── tcpcrypt_divert.h ├── crypto.c ├── pf.conf ├── crypto_hkdf.c ├── crypto_reg.c ├── freebsd.c ├── tcpcryptd.h ├── crypto_umac.c ├── mingw.c ├── crypto_hmac.c ├── tcpcryptd.man.md ├── iptables.sh ├── tcpcryptd.man ├── crypto_rsa.c ├── crypto_ecdhe.c ├── crypto.h ├── crypto_dummy.c ├── test.c ├── checksum.c ├── crypto_aes.c ├── profile.c ├── linux.c └── unix.c ├── launchers ├── TcpcryptLauncher │ ├── TcpcryptLauncher.xcodeproj │ │ ├── .gitignore │ │ └── project.xcworkspace │ │ │ └── contents.xcworkspacedata │ ├── TcpcryptLauncher.icns │ ├── en.lproj │ │ ├── InfoPlist.strings │ │ └── Credits.rtf │ ├── TcpcryptLauncher_Prefix.pch │ ├── main.m │ ├── Classes │ │ ├── TcpcryptLauncherAppDelegate.h │ │ ├── TCTcpcryptController.h │ │ ├── TcpcryptLauncherAppDelegate.m │ │ └── TCTcpcryptController.m │ ├── makepkg.sh │ ├── TcpcryptLauncher-Info.plist │ └── tcpcryptd_wrapper.c ├── winlauncher │ ├── main.ico │ ├── off.ico │ ├── on.ico │ ├── Bitmaps │ │ ├── dlgbmp.bmp │ │ └── bannrbmp.bmp │ ├── signmsi.bat │ ├── signexe.bat │ ├── sign.sh │ ├── resource.h │ ├── tcpcrypt.exe.manifest │ ├── Makefile │ ├── res.rc │ └── tcpcrypt.c ├── README └── freebsd │ ├── README │ └── tcpcryptd ├── doc └── tcpcrypt-iptables.png ├── tests ├── .gitignore ├── hmac.at ├── atlocal.in ├── testsuite.at ├── version.at └── hmac.c ├── win └── priv.c ├── bootstrap.sh ├── .dir-locals.el ├── .gitignore ├── shared ├── socket_address.h └── socket_address.c ├── unix ├── priv.c └── linux │ └── priv.c ├── INSTALL-MacOSX.markdown ├── LICENSE ├── include └── tcpcrypt │ └── tcpcrypt.h ├── INSTALL-FreeBSD.markdown ├── INSTALL-Linux.markdown ├── INSTALL-Windows.markdown ├── README.markdown ├── launch_tcpcryptd.sh ├── Makefile.am └── configure.ac /contrib/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.d 3 | -------------------------------------------------------------------------------- /lib/.gitignore: -------------------------------------------------------------------------------- 1 | *.d 2 | *.o 3 | .*.swp 4 | *.so 5 | *.a 6 | -------------------------------------------------------------------------------- /util/.gitignore: -------------------------------------------------------------------------------- 1 | *.d 2 | *.o 3 | .*.swp 4 | tcnetstat 5 | tcs 6 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | *.d 2 | *.o 3 | .*.swp 4 | core 5 | tcpcryptd 6 | tcpcrypt_version.h 7 | -------------------------------------------------------------------------------- /launchers/TcpcryptLauncher/TcpcryptLauncher.xcodeproj/.gitignore: -------------------------------------------------------------------------------- 1 | *.pbxuser 2 | xcuserdata 3 | 4 | -------------------------------------------------------------------------------- /doc/tcpcrypt-iptables.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scslab/tcpcrypt/master/doc/tcpcrypt-iptables.png -------------------------------------------------------------------------------- /launchers/winlauncher/main.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scslab/tcpcrypt/master/launchers/winlauncher/main.ico -------------------------------------------------------------------------------- /launchers/winlauncher/off.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scslab/tcpcrypt/master/launchers/winlauncher/off.ico -------------------------------------------------------------------------------- /launchers/winlauncher/on.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scslab/tcpcrypt/master/launchers/winlauncher/on.ico -------------------------------------------------------------------------------- /lib/libtcpcrypt.sym: -------------------------------------------------------------------------------- 1 | tcpcrypt_getsessid 2 | tcpcrypt_getsockopt 3 | tcpcrypt_setparam 4 | tcpcrypt_setsockopt 5 | -------------------------------------------------------------------------------- /src/resource.h: -------------------------------------------------------------------------------- 1 | #define MANIFEST_RESOURCE_ID 1 2 | -------------------------------------------------------------------------------- /tests/.gitignore: -------------------------------------------------------------------------------- 1 | atconfig 2 | atlocal 3 | package.m4 4 | testsuite 5 | testsuite.log 6 | testsuite.dir 7 | hmac 8 | -------------------------------------------------------------------------------- /tests/hmac.at: -------------------------------------------------------------------------------- 1 | AT_SETUP([HMAC]) 2 | 3 | AT_CHECK([hmac], 4 | [0], 5 | [OK 6 | ]) 7 | 8 | AT_CLEANUP 9 | -------------------------------------------------------------------------------- /launchers/winlauncher/Bitmaps/dlgbmp.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scslab/tcpcrypt/master/launchers/winlauncher/Bitmaps/dlgbmp.bmp -------------------------------------------------------------------------------- /tests/atlocal.in: -------------------------------------------------------------------------------- 1 | # configuration data specifically for testing # 2 | 3 | PATH=@abs_top_srcdir@/src:@abs_top_srcdir@/tests:$PATH 4 | -------------------------------------------------------------------------------- /launchers/winlauncher/Bitmaps/bannrbmp.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scslab/tcpcrypt/master/launchers/winlauncher/Bitmaps/bannrbmp.bmp -------------------------------------------------------------------------------- /launchers/TcpcryptLauncher/TcpcryptLauncher.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scslab/tcpcrypt/master/launchers/TcpcryptLauncher/TcpcryptLauncher.icns -------------------------------------------------------------------------------- /src/util.h: -------------------------------------------------------------------------------- 1 | #ifndef __TCPCRYPT_UTIL_H__ 2 | #define __TCPCRYPT_UTIL_H__ 3 | 4 | extern void *xmalloc(size_t sz); 5 | 6 | #endif /* __TCPCRYPT_UTIL_H__ */ 7 | -------------------------------------------------------------------------------- /win/priv.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void drop_privs(const char *dir, const char *name) 4 | { 5 | fprintf(stderr, "WARNING: Cannot drop privileges!"); 6 | } 7 | -------------------------------------------------------------------------------- /launchers/TcpcryptLauncher/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | NSHumanReadableCopyright = "© __MyCompanyName__, 2010"; 4 | -------------------------------------------------------------------------------- /src/res.rc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "resource.h" 5 | 6 | MANIFEST_RESOURCE_ID RT_MANIFEST "tcpcryptd.exe.manifest" 7 | -------------------------------------------------------------------------------- /launchers/winlauncher/signmsi.bat: -------------------------------------------------------------------------------- 1 | signtool sign /v /ac c:\certs\MSCV-VSClass3.cer /s my /n "Stanford University" /t http://timestamp.verisign.com/scripts/timestamp.dll tcpcrypt.msi 2 | -------------------------------------------------------------------------------- /bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | autoreconf --force --install --verbose 4 | 5 | #glibtoolize --force 6 | #aclocal 7 | #autoheader 8 | #automake --force-missing --add-missing 9 | #autoconf 10 | -------------------------------------------------------------------------------- /src/priv.h: -------------------------------------------------------------------------------- 1 | #ifndef __TCPCRYPT_PRIV_H__ 2 | #define __TCPCRYPT_PRIV_H__ 3 | 4 | extern void drop_privs(const char *dir, const char *name); 5 | extern void linux_drop_privs(uid_t uid); 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /src/tcpcrypt_version.h.in: -------------------------------------------------------------------------------- 1 | #ifndef __SRC_TCPCRYPT_VERSION_H__ 2 | #define __SRC_TCPCRYPT_VERSION_H__ 3 | 4 | #define TCPCRYPT_VERSION "@PACKAGE_VERSION@" 5 | 6 | #endif /* __SRC_TCPCRYPT_VERSION_H__ */ 7 | -------------------------------------------------------------------------------- /src/util.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "inc.h" 4 | 5 | void *xmalloc(size_t sz) 6 | { 7 | void *r = malloc(sz); 8 | 9 | if (!r) 10 | err(1, "malloc()"); 11 | 12 | return r; 13 | } 14 | 15 | -------------------------------------------------------------------------------- /launchers/README: -------------------------------------------------------------------------------- 1 | 2 | This directory contains utilities, provided by various contributors, 3 | that configure firewall rules and launch tcpcryptd. 4 | 5 | Consider them if launch_tcpcryptd.sh does not meet your needs. 6 | 7 | -------------------------------------------------------------------------------- /launchers/TcpcryptLauncher/TcpcryptLauncher_Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'TcpcryptLauncher' target in the 'TcpcryptLauncher' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #endif 8 | 9 | -------------------------------------------------------------------------------- /.dir-locals.el: -------------------------------------------------------------------------------- 1 | ;; emacs local configuration settings for tcpcrypt source 2 | ;; surmised by dkg on 2014-08-15 3 | 4 | ((c-mode 5 | (indent-tabs-mode . t) 6 | (tab-width . 8) 7 | (c-file-style . "linux")) 8 | (nil 9 | (fill-column . 70)) 10 | ) 11 | -------------------------------------------------------------------------------- /launchers/TcpcryptLauncher/TcpcryptLauncher.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /launchers/winlauncher/signexe.bat: -------------------------------------------------------------------------------- 1 | signtool sign /v /ac c:\certs\MSCV-VSClass3.cer /s my /n "Stanford University" /t http://timestamp.verisign.com/scripts/timestamp.dll tcpcrypt32.exe tcpcrypt64.exe ..\..\user\tcpcrypt\tcpcryptd.exe ..\..\user\util\tcnetstat.exe 2 | -------------------------------------------------------------------------------- /launchers/freebsd/README: -------------------------------------------------------------------------------- 1 | FreeBSD rc start script 2 | Provided by Richard Carback 3 | 4 | Instructions: 5 | * Install the included "tcpcryptd" file to /usr/local/etc/rc.d/tcpcryptd 6 | * Add the following to /etc/rc.conf to enable the script: tcpcryptd_enable="YES" 7 | -------------------------------------------------------------------------------- /tests/testsuite.at: -------------------------------------------------------------------------------- 1 | # Process this file with autom4te to create testsuite. -*- Autotest -*- 2 | 3 | # Test suite for tcpcrypt 4 | m4_include([tests/package.m4]) 5 | 6 | AT_INIT 7 | 8 | AT_TESTED([tcpcryptd]) 9 | 10 | m4_include([tests/version.at]) 11 | m4_include([tests/hmac.at]) 12 | -------------------------------------------------------------------------------- /src/test.h: -------------------------------------------------------------------------------- 1 | #ifndef __TCPCRYPT_TEST_H__ 2 | #define __TCPCRYPT_TEST_H__ 3 | 4 | extern void test_sym_throughput(void); 5 | extern void test_mac_throughput(void); 6 | extern void test_dropper(void); 7 | extern void print_packet(struct ip *ip, struct tcphdr *tcp, int flags, 8 | struct tc *tc); 9 | 10 | #endif /* __TCPCRYPT_TEST_H__ */ 11 | -------------------------------------------------------------------------------- /launchers/TcpcryptLauncher/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // TcpcryptLauncher 4 | // 5 | // Created by Samuel Quinn Slack on 8/17/10. 6 | // Copyright (c) 2010 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | 10 | #import 11 | 12 | int main(int argc, char *argv[]) 13 | { 14 | 15 | return NSApplicationMain(argc, (const char **) argv); 16 | 17 | } 18 | 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .*.swp 2 | *~ 3 | *.so 4 | *.[oa] 5 | *.lo 6 | *.la 7 | .deps 8 | .libs 9 | Makefile 10 | aclocal.m4 11 | config.log 12 | config.status 13 | config.h 14 | config.log 15 | autom4te.cache 16 | stamp-h1 17 | libtool 18 | autoscan.log 19 | configure.scan 20 | Makefile.in 21 | m4/* 22 | config/* 23 | config.h.in 24 | configure 25 | .dirstamp 26 | tcpcrypt-*.tar.gz 27 | tcpcrypt-*.tar.xz 28 | -------------------------------------------------------------------------------- /launchers/TcpcryptLauncher/en.lproj/Credits.rtf: -------------------------------------------------------------------------------- 1 | {\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf320 2 | {\fonttbl\f0\fswiss\fcharset0 Helvetica;} 3 | {\colortbl;\red255\green255\blue255;} 4 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural 5 | 6 | \f0\b\fs24 \cf0 Tcpcrypt\ 7 | {\field{\*\fldinst{HYPERLINK "http://tcpcrypt.org"}}{\fldrslt 8 | \b0 http://tcpcrypt.org}}} -------------------------------------------------------------------------------- /src/checksum.h: -------------------------------------------------------------------------------- 1 | #ifndef __TCPCRYPT_CHECKSUM_H__ 2 | #define __TCPCRYPT_CHECKSUM_H__ 3 | 4 | extern void checksum_packet(struct tc *tc, struct ip *ip, 5 | struct tcphdr *tcp); 6 | extern void checksum_ip(struct ip *ip); 7 | extern void checksum_tcp(struct tc *tc, struct ip *ip, struct tcphdr *tcp); 8 | extern uint16_t checksum(void *data, int len); 9 | 10 | #endif /* __TCPCRYPT_CHECKSUM_H__ */ 11 | -------------------------------------------------------------------------------- /tests/version.at: -------------------------------------------------------------------------------- 1 | AT_SETUP([tcpcryptd version]) 2 | 3 | AT_CHECK([tcpcryptd -V], 4 | [0], 5 | [AT_PACKAGE_NAME version AT_PACKAGE_VERSION 6 | ], 7 | [], 8 | [], 9 | [ 10 | echo '==============================================================' 11 | echo 'WARNING: Not using the expected version, *all* checks dubious...' 12 | echo '==============================================================' 13 | ]) 14 | 15 | AT_CLEANUP 16 | -------------------------------------------------------------------------------- /launchers/TcpcryptLauncher/Classes/TcpcryptLauncherAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // TcpcryptLauncherAppDelegate.h 3 | // TcpcryptLauncher 4 | // 5 | // Created by Samuel Quinn Slack on 8/17/10. 6 | // Copyright (c) 2010 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | 10 | @interface TcpcryptLauncherAppDelegate : NSObject { 11 | 12 | NSWindow *window; 13 | } 14 | 15 | @property (assign) IBOutlet NSWindow *window; 16 | 17 | @end 18 | 19 | -------------------------------------------------------------------------------- /src/tcpcrypt_strings.h: -------------------------------------------------------------------------------- 1 | #ifndef __TCPCRYPT_TCPCRYPT_STRINGS_H__ 2 | #define __TCPCRYPT_TCPCRYPT_STRINGS_H__ 3 | 4 | static char *REQS[] = { 5 | "GET /check HTTP/1.0\r\n" 6 | "Host: check.tcpcrypt.org\r\n" 7 | "\r\n", 8 | 9 | "MORTEasldkfjasldkfjaslkfjaslfkjasdlfkjas", 10 | 11 | "GHGHHGHGHGHREHEHGEHRGHERHGHERG", 12 | }; 13 | 14 | static char *TEST_REPLY = "HTTP/1.0 200 OK\r\n" 15 | "\r\n"; 16 | 17 | #endif /* __TCPCRYPT_TCPCRYPT_STRINGS_H__ */ 18 | -------------------------------------------------------------------------------- /launchers/TcpcryptLauncher/makepkg.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DIR=$1 4 | 5 | VER=$(awk -F , '/AC_INIT/ {print $2}' ../../configure.ac | tr -d '[] ') 6 | 7 | echo Version $VER 8 | 9 | pkgbuild --root $DIR --identifier org.tcpcrypt.TcpcryptLauncher \ 10 | --version $VER --install-location /Applications tcpcrypt.pkg 11 | 12 | productsign --sign 'Developer ID Installer' tcpcrypt.pkg tcpcrypt-signed.pkg 13 | spctl --asses --type install tcpcrypt-signed.pkg 14 | mv tcpcrypt-signed.pkg tcpcrypt.pkg 15 | -------------------------------------------------------------------------------- /launchers/winlauncher/sign.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sign() { 4 | echo Signing $1 5 | osslsigncode sign \ 6 | -pkcs12 cert.p12 \ 7 | -askpass \ 8 | -h sha1 \ 9 | -n tcpcrypt \ 10 | -i http://tcpcrypt.org/ \ 11 | -t http://timestamp.verisign.com/scripts/timstamp.dll \ 12 | -in $1 -out $1-signed 13 | mv $1-signed $1 14 | } 15 | 16 | BINS=(tcpcrypt.exe ../../src/.libs/tcpcryptd.exe ../../util/.libs/tcnetstat.exe) 17 | for i in ${BINS[@]} ; do 18 | sign $i 19 | done 20 | 21 | make tcpcrypt.msi 22 | 23 | sign tcpcrypt.msi 24 | -------------------------------------------------------------------------------- /src/inc.h: -------------------------------------------------------------------------------- 1 | #ifndef __WIN32__ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #define __FAVOR_BSD 12 | #include 13 | #include 14 | #include 15 | #else /* __WIN32__ */ 16 | #include 17 | #include 18 | #include 19 | #include "contrib/win_port.h" 20 | #endif /* ! __WIN32__ */ 21 | -------------------------------------------------------------------------------- /launchers/TcpcryptLauncher/Classes/TCTcpcryptController.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | 4 | @interface TCTcpcryptController : NSObject { 5 | NSString* _wrapperPath; 6 | NSString* _tcpcryptdPath; 7 | NSTask* _daemon; 8 | NSPipe* _pipe; 9 | 10 | IBOutlet NSButton* _startButton; 11 | IBOutlet NSButton* _stopButton; 12 | IBOutlet NSTextField* _statusLabel; 13 | IBOutlet NSButton* _testButton; 14 | } 15 | 16 | - (IBAction)startDaemon:(id)sender; 17 | - (IBAction)stopDaemon:(id)sender; 18 | - (IBAction)openTestPage:(id)sender; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /launchers/winlauncher/resource.h: -------------------------------------------------------------------------------- 1 | #ifndef IDC_STATIC 2 | #define IDC_STATIC (-1) 3 | #endif 4 | 5 | #define IDD_DIALOG1 100 6 | #define IDC_BUTTON2 1000 7 | #define IDC_EDIT1 1002 8 | #define IDC_BUTTON1 1003 9 | #define IDC_EDIT2 1004 10 | #define IDI_MAIN 1010 11 | #define IDI_ON 1011 12 | #define IDI_OFF 1012 13 | 14 | #define MANIFEST_RESOURCE_ID 1 15 | -------------------------------------------------------------------------------- /src/tcpcryptd.exe.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | tcpcryptd 9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /launchers/winlauncher/tcpcrypt.exe.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | tcpcrypt 9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /util/README.markdown: -------------------------------------------------------------------------------- 1 | Tcpcrypt netstat 2 | ================ 3 | 4 | The `util/tcnetstat` program lists active tcpcrypt connections and their 5 | session IDs. 6 | 7 | With two HTTP connections open, the output looks like: 8 | 9 | $ test/tcnetstat -N 10 | Using 1 implementation 11 | Local address Foreign address SID 12 | 128.12.13.14:59539 171.66.3.211:80 E0C4FA717D0B3C51E4E2A8EC70CA34ADFC91A260 13 | 128.12.13.14:59540 171.66.3.211:80 EA22A7B8A9994AB151A865C5F5AC1309DD674D6C 14 | 15 | There is currently a limit of approximately 100 active connections that can be 16 | displayed by tcnetstat. This will be fixed soon and does not affect tcpcryptd. 17 | 18 | -------------------------------------------------------------------------------- /src/tcpcrypt_ctl.h: -------------------------------------------------------------------------------- 1 | #ifndef __TCPCRYPT_TCPCRYPT_CTL_H__ 2 | #define __TCPCRYPT_TCPCRYPT_CTL_H__ 3 | 4 | #include "inc.h" 5 | 6 | #define TCC_IN 0x00000001 7 | #define TCC_SET 0x00000002 8 | 9 | struct tc_netstat { 10 | struct in_addr tn_sip; 11 | uint16_t tn_sport; 12 | struct in_addr tn_dip; 13 | uint16_t tn_dport; 14 | uint16_t tn_len; 15 | uint8_t tn_sid[0]; 16 | }; 17 | 18 | struct tcpcrypt_ctl { 19 | uint32_t tcc_seq; 20 | struct in_addr tcc_src; 21 | uint16_t tcc_sport; 22 | struct in_addr tcc_dst; 23 | uint16_t tcc_dport; 24 | uint32_t tcc_flags; 25 | uint32_t tcc_err; 26 | uint32_t tcc_opt; 27 | uint32_t tcc_dlen; 28 | uint8_t tcc_data[0]; 29 | }; 30 | 31 | #endif /* __TCPCRYPT_TCPCRYPT_CTL_H__ */ 32 | -------------------------------------------------------------------------------- /launchers/TcpcryptLauncher/Classes/TcpcryptLauncherAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // TcpcryptLauncherAppDelegate.m 3 | // TcpcryptLauncher 4 | // 5 | // Created by Samuel Quinn Slack on 8/17/10. 6 | // Copyright (c) 2010 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | 10 | #import "TcpcryptLauncherAppDelegate.h" 11 | 12 | #include "../../../src/tcpcrypt_version.h" 13 | 14 | @implementation TcpcryptLauncherAppDelegate 15 | 16 | @synthesize window; 17 | 18 | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { 19 | NSString* title = [NSString stringWithFormat:@"tcpcrypt v%s" , 20 | TCPCRYPT_VERSION]; 21 | 22 | [title autorelease]; 23 | [[self window] setTitle:title]; 24 | // Insert code here to initialize your application 25 | } 26 | 27 | @end 28 | 29 | -------------------------------------------------------------------------------- /src/profile.h: -------------------------------------------------------------------------------- 1 | #ifndef __TCPCRYPT_PROFILE_H__ 2 | #define __TCPCRYPT_PROFILE_H__ 3 | 4 | typedef unsigned int (*speed_cb)(float sample, unsigned int curavg); 5 | 6 | enum { 7 | PROFILE_DISCARD = 1, 8 | PROFILE_ENABLE, 9 | PROFILE_TIME_SOURCE, 10 | }; 11 | 12 | enum { 13 | TIME_SOURCE_TSC = 0, 14 | TIME_SOURCE_GETTIMEOFDAY, 15 | }; 16 | 17 | extern void speed_start(speed_cb cb); 18 | extern void speed_add(unsigned int sample); 19 | extern void profile_print(void); 20 | extern void profile_add(int verb, char *desc); 21 | extern void sample_add(unsigned int sample); 22 | extern void profile_end(void); 23 | extern void profile_setopt(int opt, int val); 24 | extern int time_diff(struct timeval *past, struct timeval *now); 25 | extern uint64_t get_tsc(void); 26 | 27 | #endif /* __TCPCRYPT_PROFILE_H__ */ 28 | -------------------------------------------------------------------------------- /launchers/winlauncher/Makefile: -------------------------------------------------------------------------------- 1 | CC = $(PREFIX)gcc 2 | CXX = $(PREFIX)g++ 3 | 4 | WIX ?= wine $(HOME)/.wine/drive_c/Program\ Files\ \(x86\)/Windows\ Installer\ XML\ v3/bin/ 5 | CANDLE = $(WIX)candle 6 | LIGHT = $(WIX)light 7 | 8 | NAME = tcpcrypt.exe 9 | CFLAGS = -Wall -g -I. -MD 10 | CXXFLAGS = $(CFLAGS) 11 | LDFLAGS = -lgdi32 -lsetupapi -lws2_32 -lole32 -luuid \ 12 | -Wl,-subsystem,windows 13 | 14 | OBJS = tcpcrypt.o res.o 15 | 16 | all: $(NAME) 17 | 18 | res.o: res.rc resource.h tcpcrypt.exe.manifest 19 | $(PREFIX)windres $(<) $(@) 20 | 21 | $(NAME): $(OBJS) 22 | $(CC) $(CFLAGS) -o $(@) $(OBJS) $(LDFLAGS) 23 | 24 | tcpcrypt.wixobj: tcpcrypt.wxs tcpcrypt.exe 25 | $(CANDLE) tcpcrypt.wxs 26 | 27 | tcpcrypt.msi: tcpcrypt.wixobj 28 | $(LIGHT) -sval tcpcrypt.wixobj 29 | 30 | clean: 31 | rm -f *.o $(NAME) *.d 32 | 33 | -include *.d 34 | -------------------------------------------------------------------------------- /util/tcnetstat.man.md: -------------------------------------------------------------------------------- 1 | % tcnetstat(8) 2 | % 3 | 4 | # NAME 5 | 6 | __tcnetstat__ - Print information about network connections protected by tcpcrypt 7 | 8 | # SYNOPSIS 9 | 10 | __tcnetstat__ 11 | 12 | # DESCRIPTION 13 | 14 | The __tcnetstat__ utility prints the _session id_ of each TCP connection that 15 | is currently being protected by the _tcpcrypt_ protocol. 16 | 17 | # OPTIONS 18 | 19 | Where the _tcpcrypt_ protocol is implemented by the __tcpcryptd__ daemon, 20 | this utility communicates with the daemon via a "control socket", configurable 21 | with __-u__ _socket_address_. If _socket_address_ begins with "/", it is 22 | interpreted as a filesystem path pointing to a unix-domain socket; if it is 23 | of the form ":_port_", it is interpreted as the internet address localhost:_port_. 24 | 25 | # SEE ALSO 26 | 27 | __tcpcryptd__(8), [http://tcpcrypt.org/](http://tcpcrypt.org/) 28 | 29 | -------------------------------------------------------------------------------- /util/tcnetstat.man: -------------------------------------------------------------------------------- 1 | .TH "tcnetstat" "8" "" "" "" 2 | .SH NAME 3 | .PP 4 | \f[B]tcnetstat\f[] \- Print information about network connections 5 | protected by tcpcrypt 6 | .SH SYNOPSIS 7 | .PP 8 | \f[B]tcnetstat\f[] 9 | .SH DESCRIPTION 10 | .PP 11 | The \f[B]tcnetstat\f[] utility prints the \f[I]session id\f[] of each 12 | TCP connection that is currently being protected by the 13 | \f[I]tcpcrypt\f[] protocol. 14 | .SH OPTIONS 15 | .PP 16 | Where the \f[I]tcpcrypt\f[] protocol is implemented by the 17 | \f[B]tcpcryptd\f[] daemon, this utility communicates with the daemon via 18 | a "control socket", configurable with \f[B]\-u\f[] 19 | \f[I]socket_address\f[]. 20 | If \f[I]socket_address\f[] begins with "/", it is interpreted as a 21 | filesystem path pointing to a unix\-domain socket; if it is of the form 22 | ":\f[I]port\f[]", it is interpreted as the internet address 23 | localhost:\f[I]port\f[]. 24 | .SH SEE ALSO 25 | .PP 26 | \f[B]tcpcryptd\f[](8), 27 | -------------------------------------------------------------------------------- /src/tcpcrypt_divert.h: -------------------------------------------------------------------------------- 1 | #ifndef __TCPCRYPT_DIVERT_H__ 2 | #define __TCPCRYPT_DIVERT_H__ 3 | 4 | #define INJECT_TOS 0x22 5 | 6 | enum { 7 | DIVERT_ACCEPT = 0, 8 | DIVERT_DROP, 9 | DIVERT_MODIFY, 10 | }; 11 | 12 | #define DF_IN 0x1 13 | 14 | typedef int (*divert_cb)(void *data, int len, int flags); 15 | 16 | struct divert { 17 | int (*open)(int port, divert_cb cb); 18 | void (*next_packet)(int s); 19 | void (*close)(void); 20 | void (*inject)(void *data, int len); 21 | void (*cycle)(void); 22 | int (*orig_dest)(struct sockaddr_in *out, struct ip *ip, int *flags); 23 | }; 24 | 25 | extern struct divert *divert_get(void); 26 | extern struct divert *_divert; 27 | 28 | extern void raw_inject(void *data, int len); 29 | extern void raw_open(void); 30 | extern struct divert *divert_get_pcap(void); 31 | 32 | extern void win_dont_rdr(int s); 33 | extern uint32_t win_local_ip(void); 34 | extern void win_handshake_complete(int s); 35 | 36 | #endif /* __TCPCRYPT_DIVERT_H__ */ 37 | -------------------------------------------------------------------------------- /shared/socket_address.h: -------------------------------------------------------------------------------- 1 | #ifndef __TCPCRYPT_SOCKET_ADDRESS_H__ 2 | #define __TCPCRYPT_SOCKET_ADDRESS_H__ 3 | 4 | #include "inc.h" 5 | 6 | union sockaddr_any { 7 | struct sockaddr sa; 8 | struct sockaddr_in in; 9 | #ifndef __WIN32__ 10 | struct sockaddr_un un; 11 | #endif 12 | }; 13 | 14 | struct socket_address { 15 | socklen_t addr_len; 16 | union sockaddr_any addr; 17 | }; 18 | 19 | #define SOCKET_ADDRESS_NULL { 0, {} } 20 | 21 | #define SOCKET_ADDRESS_ANY { (socklen_t) sizeof(union sockaddr_any), {} } 22 | 23 | extern int socket_address_is_null(const struct socket_address *sa); 24 | 25 | extern void socket_address_clear(struct socket_address *sa); 26 | 27 | extern const char *socket_address_pathname(const struct socket_address *sa); 28 | 29 | extern int socket_address_pretty(char *name, size_t size, 30 | const struct socket_address *sa); 31 | 32 | extern int resolve_socket_address_local(const char *descr, 33 | struct socket_address *sa, 34 | char *error, int error_len); 35 | 36 | #endif /* __TCPCRYPT_SOCKET_ADDRESS_H__ */ 37 | -------------------------------------------------------------------------------- /unix/priv.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "priv.h" 10 | 11 | void drop_privs(const char *dir, const char *name) 12 | { 13 | struct passwd *pwd = NULL; 14 | uid_t uid = (uid_t)(-1); 15 | gid_t gid; 16 | 17 | if (name) { 18 | errno = 0; 19 | pwd = getpwnam(name); 20 | if (pwd == NULL) 21 | (errno ? err : errx)(1, "Can't find user '%s'", name); 22 | uid = pwd->pw_uid; 23 | gid = pwd->pw_gid; 24 | 25 | if (setgid(gid) < 0) 26 | err(1, "setgid(%ld)", (long) gid); 27 | 28 | if (initgroups(name, gid) < 0) 29 | err(1, "initgroups(\"%s\", %ld)", 30 | name, (long) gid); 31 | } 32 | 33 | if (dir) { 34 | if (chroot(dir) < 0) 35 | err(1, "Could not chroot to %s", dir); 36 | if (chdir("/") < 0) 37 | err(1, "Could not chdir to root of jail"); 38 | } 39 | 40 | if (name) { 41 | #if defined(__linux__) 42 | linux_drop_privs(uid); 43 | #else 44 | if (setuid(uid) != 0) 45 | err(1, "setuid(%ld)", (long) uid); 46 | #endif 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /launchers/TcpcryptLauncher/TcpcryptLauncher-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleIdentifier 6 | org.tcpcrypt.${PRODUCT_NAME:rfc1034identifier} 7 | CFBundleDevelopmentRegion 8 | English 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIconFile 12 | TcpcryptLauncher 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleSignature 20 | ???? 21 | CFBundleShortVersionString 22 | 1.0 23 | LSMinimumSystemVersion 24 | ${MACOSX_DEPLOYMENT_TARGET} 25 | CFBundleVersion 26 | 1 27 | NSMainNibFile 28 | MainMenu 29 | NSPrincipalClass 30 | NSApplication 31 | 32 | 33 | -------------------------------------------------------------------------------- /unix/linux/priv.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "priv.h" 8 | 9 | void linux_drop_privs(uid_t uid) 10 | { 11 | cap_t caps = cap_init(); 12 | int num = 2; 13 | 14 | cap_value_t capList[] = { CAP_NET_ADMIN, CAP_SETUID }; 15 | 16 | cap_set_flag(caps, CAP_EFFECTIVE, num, capList, CAP_SET); 17 | cap_set_flag(caps, CAP_INHERITABLE, num, capList, CAP_SET); 18 | cap_set_flag(caps, CAP_PERMITTED, num, capList, CAP_SET); 19 | 20 | if (cap_set_proc(caps)) 21 | err(1, "cap_set_flag()"); 22 | 23 | if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) 24 | err(1, "prctl()"); 25 | 26 | cap_free(caps); 27 | 28 | if (setuid(uid) < 0) 29 | err(1, "setuid(%ld)", (long) uid); 30 | 31 | caps = cap_init(); 32 | num = 1; 33 | 34 | cap_set_flag(caps, CAP_EFFECTIVE, num, capList, CAP_SET); 35 | cap_set_flag(caps, CAP_INHERITABLE, num, capList, CAP_SET); 36 | cap_set_flag(caps, CAP_PERMITTED, num, capList, CAP_SET); 37 | 38 | if (cap_set_proc(caps)) 39 | err(1, "cap_set_proc()"); 40 | 41 | cap_free(caps); 42 | 43 | /* XXX this really sucks. The guy can screw with our net =( */ 44 | } 45 | -------------------------------------------------------------------------------- /src/crypto.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "inc.h" 10 | #include "util.h" 11 | #include "tcpcrypt_ctl.h" 12 | #include "tcpcrypt.h" 13 | #include "tcpcryptd.h" 14 | #include "crypto.h" 15 | 16 | static struct cipher_list _ciphers; 17 | 18 | struct cipher_list *crypt_cipher_list(void) 19 | { 20 | return _ciphers.c_next; 21 | } 22 | 23 | struct crypt *crypt_init(int sz) 24 | { 25 | struct crypt *c = xmalloc(sizeof(*c)); 26 | memset(c, 0, sizeof(*c)); 27 | 28 | if (sz) { 29 | c->c_priv = xmalloc(sz); 30 | memset(c->c_priv, 0, sz); 31 | } 32 | 33 | return c; 34 | } 35 | 36 | void crypt_register(int type, uint8_t id, crypt_ctr ctr) 37 | { 38 | struct cipher_list *c = xmalloc(sizeof(*c)); 39 | 40 | c->c_type = type; 41 | c->c_id = id; 42 | c->c_ctr = ctr; 43 | c->c_next = _ciphers.c_next; 44 | _ciphers.c_next = c; 45 | } 46 | 47 | struct cipher_list *crypt_find_cipher(int type, unsigned int id) 48 | { 49 | struct cipher_list *c = _ciphers.c_next; 50 | 51 | while (c) { 52 | if (c->c_type == type && c->c_id == id) 53 | return c; 54 | 55 | c = c->c_next; 56 | } 57 | 58 | return NULL; 59 | } 60 | -------------------------------------------------------------------------------- /INSTALL-MacOSX.markdown: -------------------------------------------------------------------------------- 1 | Installing tcpcrypt on Mac OS X 2 | =============================== 3 | 4 | Using the Mac OS X GUI wrapper 5 | ------------------------------ 6 | 7 | If you don't want to compile your own tcpcrypt, you can use the Mac OS X GUI 8 | wrapper, which includes the binary and is available at 9 | [http://tcpcrypt.org/download.php](http://tcpcrypt.org/download.php). 10 | 11 | Compiling 12 | --------- 13 | 14 | Tcpcrypt does not depend on non-standard libs on Mac OS X, so just run: 15 | 16 | cd tcpcrypt/user 17 | ./bootstrap.sh 18 | ./configure 19 | make 20 | 21 | Optional: running `make install` will install `libtcpcrypt` and tcpcrypt 22 | headers, for building apps that use tcpcrypt's session ID. 23 | 24 | Running 25 | ------- 26 | 27 | The launch script (in tcpcrypt/user) starts tcpcryptd and sets up your firewall 28 | to send port 80 and 7777 packets through tcpcrypt: 29 | 30 | ./launch_tcpcryptd.sh 31 | 32 | With tcpcryptd running, open 33 | [http://tcpcrypt.org/test.php](http://tcpcrypt.org/test.php) to try it out. 34 | 35 | More info 36 | ---------- 37 | 38 | See the included `README.markdown` file for more ways to try out tcpcrypt and 39 | for troubleshooting help. 40 | 41 | See `INSTALL-FreeBSD` for firewall setup instructions. (FreeBSD and Mac OS X use 42 | the same firewall, `ipfw`.) 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2009 Tcpcrypt. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are 4 | permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this list of 7 | conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, this list 10 | of conditions and the following disclaimer in the documentation and/or other 11 | materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY TCPCRYPT AND ITS CONTRIBUTORS "AS IS" AND ANY EXPRESS 14 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 15 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 16 | TCPCRYPT OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 17 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 18 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 19 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 20 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 21 | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 22 | DAMAGE. 23 | -------------------------------------------------------------------------------- /include/tcpcrypt/tcpcrypt.h: -------------------------------------------------------------------------------- 1 | #ifndef __TCPCRYPT_TCPCRYPT_H__ 2 | #define __TCPCRYPT_TCPCRYPT_H__ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #pragma GCC visibility push(default) 7 | #endif 8 | 9 | #ifndef __WIN32__ 10 | #include 11 | #include 12 | #else 13 | #include 14 | #include /* TODO: needed? */ 15 | #endif 16 | 17 | #define TCPCRYPT_SID_MAXLEN 32 18 | 19 | /* tcpcrypt get/setsockopt optnames */ 20 | enum { 21 | TCP_CRYPT_ENABLE = 0, 22 | TCP_CRYPT_CMODE, 23 | TCP_CRYPT_SESSID, 24 | TCP_CRYPT_RSA_KEY = 3, 25 | 26 | TCP_CRYPT_APP_SUPPORT = 15, 27 | 28 | /* non standard options */ 29 | TCP_CRYPT_RESET = 100, 30 | TCP_CRYPT_NOCACHE, 31 | TCP_CRYPT_NETSTAT, 32 | }; 33 | 34 | enum { 35 | TCPCRYPT_PARAM_CTLPATH = 0, 36 | }; 37 | 38 | extern void tcpcrypt_setparam(int param, void *val); 39 | 40 | extern int tcpcrypt_getsockopt(int s, int level, int optname, void *optval, 41 | socklen_t *optlen); 42 | extern int tcpcrypt_setsockopt(int s, int level, int optname, 43 | const void *optval, socklen_t optlen); 44 | 45 | extern char *tcpcrypt_getsessid(char *remote_ip, uint16_t remote_port, 46 | char *local_ip, uint16_t local_port); 47 | 48 | #ifdef __cplusplus 49 | } 50 | #pragma GCC visibility pop 51 | #endif 52 | 53 | 54 | #endif // __TCPCRYPT_TCPCRYPT_H__ 55 | -------------------------------------------------------------------------------- /launchers/winlauncher/res.rc: -------------------------------------------------------------------------------- 1 | // Generated by ResEdit 1.5.4 2 | // Copyright (C) 2006-2010 3 | // http://www.resedit.net 4 | 5 | #include 6 | #include 7 | #include 8 | #include "resource.h" 9 | 10 | 11 | 12 | 13 | // 14 | // Dialog resources 15 | // 16 | LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL 17 | IDD_DIALOG1 DIALOG 0, 0, 495, 115 18 | STYLE DS_3DLOOK | DS_CENTER | DS_MODALFRAME | DS_SHELLFONT | WS_CAPTION | WS_VISIBLE | WS_GROUP | WS_POPUP | WS_SYSMENU 19 | CAPTION "tcpcrypt" 20 | FONT 8, "Ms Shell Dlg" 21 | { 22 | PUSHBUTTON "Start", IDOK, 9, 7, 51, 15 23 | PUSHBUTTON "Netstat", IDCANCEL, 65, 7, 54, 14 24 | EDITTEXT IDC_EDIT1, 9, 37, 478, 76, ES_AUTOHSCROLL | ES_MULTILINE | ES_READONLY 25 | PUSHBUTTON "Exit", IDC_BUTTON1, 196, 7, 48, 15 26 | EDITTEXT IDC_EDIT2, 9, 23, 123, 12, NOT WS_BORDER | ES_AUTOHSCROLL | ES_READONLY 27 | PUSHBUTTON "Enter hall of fame", IDC_BUTTON2, 124, 7, 67, 14 28 | } 29 | 30 | 31 | 32 | // 33 | // Icon resources 34 | // 35 | LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL 36 | IDI_MAIN ICON "main.ico" 37 | 38 | 39 | LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL 40 | IDI_OFF ICON "off.ico" 41 | 42 | 43 | LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL 44 | IDI_ON ICON "on.ico" 45 | 46 | MANIFEST_RESOURCE_ID RT_MANIFEST "tcpcrypt.exe.manifest" 47 | -------------------------------------------------------------------------------- /src/pf.conf: -------------------------------------------------------------------------------- 1 | pr=80 2 | 3 | rdr log proto tcp from any to any port $pr tagged "tcpcrypt" -> 127.0.0.1 port 65530 4 | rdr log proto tcp from any to any port $pr tagged "tcpcryptin" -> 127.0.0.1 port 65530 5 | 6 | # Blackhole all SYNs so we can control them. 7 | block in log on en0 proto tcp from any to any port $pr flags S/SA no state 8 | pass out log on en0 route-to lo0 proto tcp from any port 65530 to any flags SA/SA no state 9 | 10 | # Redirect incoming traffic 11 | pass in log on en0 route-to en0 proto tcp from any to any port $pr flags A/SA tag "tcpcryptin" no state 12 | 13 | block in log on en1 proto tcp from any to any port $pr flags S/SA no state 14 | pass out log on en1 route-to lo0 proto tcp from any port 65530 to any flags SA/SA no state 15 | pass in log on en1 route-to en1 proto tcp from any to any port $pr flags A/SA tag "tcpcryptin" no state 16 | 17 | # Redirect outgoing traffic 18 | pass out log route-to lo0 proto tcp to any port $pr user != tcpcryptd tag "tcpcrypt" 19 | 20 | # Delay redirect SYN so we can accept connection only if peer is listening 21 | pass in quick log on lo0 proto tcp to any port 65530 tos 0x22 no state 22 | block in log on lo0 proto tcp to any port 65530 ! tagged "tcpcryptin" 23 | 24 | # blackhole SYN and ACK in 3-way handshake, but let the ones we generate through 25 | pass out quick log proto tcp to any port $pr tos 0x22 no state 26 | pass out log route-to lo0 proto tcp to any port $pr tos 0x4 user = tcpcryptd no state 27 | -------------------------------------------------------------------------------- /launchers/freebsd/tcpcryptd: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # $FreeBSD$ 4 | # 5 | # PROVIDE: tcpcryptd 6 | # REQUIRE: ipfw networking 7 | # KEYWORD: shutdown 8 | # 9 | # Add the following lines to /etc/rc.conf.local or /etc/rc.conf 10 | # to enable this service: 11 | # 12 | # tcpcryptd_enable (bool): Set to NO by default. 13 | # Set it to YES to enable tcpcryptd. 14 | # 15 | 16 | . /etc/rc.subr 17 | 18 | name="tcpcryptd" 19 | rcvar=`set_rcvar` 20 | DIVERT_PORT=666 21 | PORT=80 22 | PORT2=7777 23 | 24 | command="/usr/local/bin/${name}" 25 | command_args="-p $DIVERT_PORT" 26 | 27 | pidfile="/var/run/${name}.pid" 28 | 29 | : ${tcpcryptd_enable="NO"} 30 | 31 | required_files="" 32 | 33 | sig_reload="USR1" 34 | 35 | start_precmd="${name}_prestart" 36 | start_cmd="${name}_start" 37 | stop_postcmd="${name}_poststop" 38 | 39 | extra_commands="" 40 | 41 | tcpcryptd_prestart() 42 | { 43 | echo Tcpcrypting port 80 and local traffic on port 7777... 44 | ipfw 02 add divert $DIVERT_PORT tcp from any to any $PORT 45 | ipfw 03 add divert $DIVERT_PORT tcp from any $PORT to any 46 | ipfw 04 add divert $DIVERT_PORT tcp from any to any $PORT2 via lo0 47 | ipfw 05 add divert $DIVERT_PORT tcp from any $PORT2 to any via lo0 48 | return 0 49 | } 50 | 51 | tcpcryptd_start() 52 | { 53 | LD_LIBRARY_PATH=lib/ $command $command_args & 54 | echo $! > $pidfile 55 | return 0 56 | } 57 | 58 | tcpcryptd_poststop() 59 | { 60 | echo Removing ipfw rules and quitting tcpcryptd... 61 | ipfw delete 02 03 04 05 62 | return 0 63 | } 64 | 65 | load_rc_config $name 66 | run_rc_command "$1" 67 | -------------------------------------------------------------------------------- /INSTALL-FreeBSD.markdown: -------------------------------------------------------------------------------- 1 | Installing tcpcrypt on FreeBSD 2 | ============================== 3 | 4 | Dependencies 5 | ------------ 6 | 7 | Enable `ipfw` and divert sockets, if you haven't already (reboot required): 8 | 9 | echo 'firewall_enable="YES"' >> /etc/rc.conf 10 | echo 'firewall_type="open"' >> /etc/rc.conf 11 | echo 'ipfw_load="YES"' >> /boot/loader.conf 12 | echo 'ipdivert_load="YES"' >> /boot/loader.conf 13 | reboot 14 | 15 | Tcpcrypt also requires OpenSSL >= 0.9.8, which is provided by the 16 | `security/openssl` port. 17 | 18 | 19 | Compiling 20 | --------- 21 | 22 | cd tcpcrypt 23 | ./bootstrap.sh 24 | ./configure 25 | make 26 | 27 | Optional: running `make install` will install `libtcpcrypt` and tcpcrypt 28 | headers, for building apps that use tcpcrypt's session ID. 29 | 30 | Running 31 | ------- 32 | 33 | The launch script starts tcpcryptd and sets up your firewall 34 | to send port 80 and 7777 packets through tcpcrypt: 35 | 36 | ./launch_tcpcryptd.sh 37 | 38 | With tcpcryptd running, open 39 | [http://tcpcrypt.org/test.php](http://tcpcrypt.org/test.php) to try it out. 40 | 41 | See `launchers/freebsd` for a FreeBSD rc script that loads tcpcryptd on system startup. 42 | 43 | More info 44 | ---------- 45 | 46 | See the included `README.markdown` file for more ways to try out tcpcrypt and 47 | for troubleshooting help. 48 | 49 | 50 | Firewall setup 51 | ============== 52 | 53 | The included `launch_tcpcryptd.sh` script sets up reasonable firewall rules, but for more complex setups, add your own `divert` rules. 54 | 55 | For example, this will divert all TCP packets to tcpcryptd (on divert port 666), and it will be rule #1. 56 | 57 | ipfw 01 add divert 666 tcp from any to any 58 | 59 | It's important that tcpcrypt divert rules are high on the list since tcpcryptd 60 | modifies the packet quite a lot, including sequence numbers, so other items 61 | (e.g., natd) may get confused if tcpcryptd doesn't do its magic first. 62 | 63 | -------------------------------------------------------------------------------- /util/tcnetstat.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "src/tcpcrypt.h" 8 | #include "src/tcpcrypt_ctl.h" 9 | #include "src/inc.h" 10 | 11 | int open_socket() 12 | { 13 | int s; 14 | struct sockaddr_in s_in; 15 | #ifdef __WIN32__ 16 | WSADATA wsadata; 17 | if (WSAStartup(MAKEWORD(1,1), &wsadata) == SOCKET_ERROR) 18 | errx(1, "WSAStartup()"); 19 | #endif 20 | 21 | memset(&s_in, 0, sizeof(s_in)); 22 | s_in.sin_family = PF_INET; 23 | s_in.sin_port = 0; 24 | s_in.sin_addr.s_addr = INADDR_ANY; 25 | 26 | s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); 27 | if (s == -1) 28 | err(1, "socket()"); 29 | 30 | if (bind(s, (struct sockaddr*) &s_in, sizeof(s_in)) == -1) 31 | err(1, "bind()"); 32 | 33 | return s; 34 | } 35 | 36 | static void do_netstat(void) 37 | { 38 | unsigned char buf[2048]; 39 | unsigned int len = sizeof(buf); 40 | int s, sl, i; 41 | struct tc_netstat *n = (struct tc_netstat*) buf; 42 | char src[64]; 43 | char dst[64]; 44 | 45 | s = open_socket(); 46 | if (tcpcrypt_getsockopt(s, IPPROTO_TCP, TCP_CRYPT_NETSTAT, buf, &len) == -1) 47 | err(1, "tcpcrypt_getsockopt()"); 48 | 49 | printf("Local address\t\tForeign address\t\tSID\n"); 50 | 51 | while (len > sizeof(*n)) { 52 | sl = ntohs(n->tn_len); 53 | 54 | assert(len >= sizeof(*n) + sl); 55 | 56 | sprintf(src, "%s:%d", inet_ntoa(n->tn_sip), ntohs(n->tn_sport)); 57 | sprintf(dst, "%s:%d", inet_ntoa(n->tn_dip), ntohs(n->tn_dport)); 58 | printf("%-21s\t%-21s\t", src, dst); 59 | 60 | for (i = 0; i < sl; i++) 61 | printf("%.2X", n->tn_sid[i]); 62 | 63 | printf("\n"); 64 | 65 | sl += sizeof(*n); 66 | n = (struct tc_netstat*) ((unsigned long) n + sl); 67 | len -= sl; 68 | } 69 | assert(len == 0); 70 | } 71 | 72 | int main(int argc, char **argv) 73 | { 74 | if (argc >= 3 && !strcmp(argv[1], "-u")) { 75 | tcpcrypt_setparam(TCPCRYPT_PARAM_CTLPATH, argv[2]); 76 | } 77 | do_netstat(); 78 | return 0; 79 | } 80 | -------------------------------------------------------------------------------- /contrib/rijndael-alg-fst.h: -------------------------------------------------------------------------------- 1 | /** 2 | * rijndael-alg-fst.h 3 | * 4 | * @version 3.0 (December 2000) 5 | * 6 | * Optimised ANSI C code for the Rijndael cipher (now AES) 7 | * 8 | * @author Vincent Rijmen 9 | * @author Antoon Bosselaers 10 | * @author Paulo Barreto 11 | * 12 | * This code is hereby placed in the public domain. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS 15 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 21 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 23 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 24 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | #ifndef __RIJNDAEL_ALG_FST_H 27 | #define __RIJNDAEL_ALG_FST_H 28 | 29 | #define MAXKC (256/32) 30 | #define MAXKB (256/8) 31 | #define MAXNR 14 32 | 33 | typedef unsigned char u8; 34 | typedef unsigned short u16; 35 | typedef unsigned int u32; 36 | 37 | int rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits); 38 | int rijndaelKeySetupDec(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits); 39 | void rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 pt[16], u8 ct[16]); 40 | void rijndaelDecrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 ct[16], u8 pt[16]); 41 | 42 | #ifdef INTERMEDIATE_VALUE_KAT 43 | void rijndaelEncryptRound(const u32 rk[/*4*(Nr + 1)*/], int Nr, u8 block[16], int rounds); 44 | void rijndaelDecryptRound(const u32 rk[/*4*(Nr + 1)*/], int Nr, u8 block[16], int rounds); 45 | #endif /* INTERMEDIATE_VALUE_KAT */ 46 | 47 | #endif /* __RIJNDAEL_ALG_FST_H */ 48 | -------------------------------------------------------------------------------- /src/crypto_hkdf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "inc.h" 11 | #include "tcpcrypt_ctl.h" 12 | #include "tcpcrypt.h" 13 | #include "tcpcryptd.h" 14 | #include "crypto.h" 15 | #include "profile.h" 16 | 17 | #define MAC_LEN 32 18 | 19 | struct hkdf_priv { 20 | struct crypt *hk_hmac; 21 | }; 22 | 23 | static void hkdf_destroy(struct crypt *c) 24 | { 25 | struct hkdf_priv *hk = crypt_priv(c); 26 | 27 | if (!hk) 28 | return; 29 | 30 | crypt_destroy(hk->hk_hmac); 31 | free(hk); 32 | free(c); 33 | } 34 | 35 | static int hkdf_set_key(struct crypt *c, void *data, int len) 36 | { 37 | struct hkdf_priv *hk = crypt_priv(c); 38 | 39 | crypt_set_key(hk->hk_hmac, data, len); 40 | 41 | return 0; 42 | } 43 | 44 | static void hkdf_extract(struct crypt *c, struct iovec *iov, int num, 45 | void *out, int *outlen) 46 | { 47 | struct hkdf_priv *hk = crypt_priv(c); 48 | 49 | crypt_mac(hk->hk_hmac, iov, num, out, outlen); 50 | } 51 | 52 | static void hkdf_expand(struct crypt *c, void *tag, int taglen, void *out, 53 | int len) 54 | { 55 | struct hkdf_priv *hk = crypt_priv(c); 56 | unsigned char *p = out; 57 | uint8_t ctr = 1; 58 | struct iovec iov[2]; 59 | int outlen = MAC_LEN; 60 | 61 | iov[0].iov_base = tag; 62 | iov[0].iov_len = taglen; 63 | 64 | iov[1].iov_base = &ctr; 65 | iov[1].iov_len = sizeof(ctr); 66 | 67 | while (len >= MAC_LEN) { 68 | crypt_mac(hk->hk_hmac, iov, sizeof(iov) / sizeof(*iov), 69 | p, &outlen); 70 | 71 | ctr++; 72 | 73 | assert(outlen == MAC_LEN); 74 | assert(ctr != 0); 75 | 76 | p += MAC_LEN; 77 | len -= MAC_LEN; 78 | } 79 | 80 | if (len) { 81 | assert(!"implement remainder"); 82 | abort(); 83 | } 84 | } 85 | 86 | struct crypt *crypt_HKDF_SHA256_new(void) 87 | { 88 | struct hkdf_priv *hk; 89 | struct crypt *c; 90 | 91 | c = crypt_init(sizeof(*hk)); 92 | c->c_destroy = hkdf_destroy; 93 | c->c_set_key = hkdf_set_key; 94 | c->c_extract = hkdf_extract; 95 | c->c_expand = hkdf_expand; 96 | 97 | hk = crypt_priv(c); 98 | hk->hk_hmac = crypt_HMAC_SHA256_new(); 99 | 100 | return c; 101 | } 102 | -------------------------------------------------------------------------------- /src/crypto_reg.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "inc.h" 11 | #include "util.h" 12 | #include "tcpcrypt_ctl.h" 13 | #include "tcpcrypt.h" 14 | #include "tcpcryptd.h" 15 | #include "crypto.h" 16 | #include "profile.h" 17 | 18 | static struct crypt_pub *ECDHE_HKDF_new(struct crypt*(*ctr)(void), int klen) 19 | { 20 | struct crypt_pub *cp = xmalloc(sizeof(*cp)); 21 | 22 | memset(cp, 0, sizeof(*cp)); 23 | 24 | cp->cp_hkdf = crypt_HKDF_SHA256_new(); 25 | cp->cp_pub = ctr(); 26 | cp->cp_n_c = 32; 27 | cp->cp_n_s = 32; 28 | cp->cp_k_len = 32; 29 | cp->cp_max_key = (4096 / 8); 30 | cp->cp_cipher_len = cp->cp_n_s + klen; 31 | cp->cp_key_agreement = 1; 32 | 33 | return cp; 34 | } 35 | 36 | static struct crypt_pub *ECDHE256_HKDF_new(void) 37 | { 38 | return ECDHE_HKDF_new(crypt_ECDHE256_new, 65 + 2); 39 | } 40 | 41 | static struct crypt_pub *ECDHE521_HKDF_new(void) 42 | { 43 | return ECDHE_HKDF_new(crypt_ECDHE521_new, 133 + 2); 44 | } 45 | 46 | static struct crypt_sym *AES_GCM_new(struct crypt*(*ctr)(void), int mlen, 47 | int klen) 48 | { 49 | struct crypt_sym *cs = xmalloc(sizeof(*cs)); 50 | 51 | memset(cs, 0, sizeof(*cs)); 52 | 53 | cs->cs_cipher = ctr(); 54 | cs->cs_mac = ctr(); 55 | cs->cs_ack_mac = ctr(); 56 | cs->cs_mac_len = mlen; 57 | cs->cs_key_len = klen; 58 | 59 | return cs; 60 | } 61 | 62 | static struct crypt_sym *AES128_GCM_new(void) 63 | { 64 | return AES_GCM_new(crypt_AES128_new, 16, 128 / 8); 65 | } 66 | 67 | static struct crypt_sym *AES256_GCM_new(void) 68 | { 69 | return AES_GCM_new(crypt_AES256_new, 16, 256 / 8); 70 | } 71 | 72 | static void register_pub(uint8_t id, struct crypt_pub *(*ctr)(void)) 73 | { 74 | crypt_register(TYPE_PKEY, id, (crypt_ctr) ctr); 75 | } 76 | 77 | static void register_sym(uint8_t id, struct crypt_sym *(*ctr)(void)) 78 | { 79 | crypt_register(TYPE_SYM, id, (crypt_ctr) ctr); 80 | } 81 | 82 | static void __register_ciphers(void) __attribute__ ((constructor)); 83 | 84 | static void __register_ciphers(void) 85 | { 86 | register_pub(TC_CIPHER_ECDHE_P256, ECDHE256_HKDF_new); 87 | register_pub(TC_CIPHER_ECDHE_P521, ECDHE521_HKDF_new); 88 | 89 | register_sym(TC_AES128_GCM, AES128_GCM_new); 90 | register_sym(TC_AES256_GCM, AES256_GCM_new); 91 | } 92 | -------------------------------------------------------------------------------- /src/freebsd.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "tcpcrypt_divert.h" 13 | #include "tcpcryptd.h" 14 | 15 | static int _s; 16 | static divert_cb _cb; 17 | 18 | static int bsd_open(int port, divert_cb cb) 19 | { 20 | struct sockaddr_in s_in; 21 | 22 | memset(&s_in, 0, sizeof(s_in)); 23 | 24 | s_in.sin_family = PF_INET; 25 | s_in.sin_port = htons(port); 26 | 27 | if ((_s = socket(PF_INET, SOCK_RAW, IPPROTO_DIVERT)) == -1) 28 | err(1, "socket()"); 29 | 30 | if (bind(_s, (struct sockaddr*) &s_in, sizeof(s_in)) == -1) 31 | err(1, "bind()"); 32 | 33 | _cb = cb; 34 | 35 | xprintf(XP_DEFAULT, "Divert packets using ipfw add divert %d\n", port); 36 | 37 | raw_open(); 38 | 39 | return _s; 40 | } 41 | 42 | static void bsd_close(void) 43 | { 44 | close(_s); 45 | } 46 | 47 | static void bsd_next_packet(int s) 48 | { 49 | unsigned char buf[2048]; 50 | struct sockaddr_in s_in; 51 | socklen_t len = sizeof(s_in); 52 | int rc; 53 | int verdict; 54 | int flags = 0; 55 | 56 | rc = recvfrom(_s, buf, sizeof(buf), 0, (struct sockaddr*) &s_in, &len); 57 | if (rc == -1) 58 | err(1, "recvfrom()"); 59 | 60 | if (rc == 0) 61 | errx(1, "EOF"); 62 | 63 | if (s_in.sin_addr.s_addr != INADDR_ANY) 64 | flags |= DF_IN; 65 | 66 | verdict = _cb(buf, rc, flags); 67 | 68 | switch (verdict) { 69 | case DIVERT_MODIFY: 70 | rc = ntohs(((struct ip*) buf)->ip_len); 71 | /* fallthrough */ 72 | case DIVERT_ACCEPT: 73 | flags = sendto(_s, buf, rc, 0, (struct sockaddr*) &s_in, len); 74 | if (flags == -1) 75 | err(1, "sendto()"); 76 | 77 | if (flags != rc) 78 | errx(1, "sent %d/%d", flags, rc); 79 | break; 80 | 81 | case DIVERT_DROP: 82 | break; 83 | 84 | default: 85 | abort(); 86 | break; 87 | } 88 | } 89 | 90 | struct divert *divert_get(void) 91 | { 92 | static struct divert _divert_bsd = { 93 | .open = bsd_open, 94 | .next_packet = bsd_next_packet, 95 | .close = bsd_close, 96 | .inject = raw_inject, 97 | }; 98 | 99 | if (_conf.cf_rdr) 100 | return divert_get_pcap(); 101 | 102 | return &_divert_bsd; 103 | } 104 | -------------------------------------------------------------------------------- /src/tcpcryptd.h: -------------------------------------------------------------------------------- 1 | #ifndef __TCPCRYPT_TCPCRYPTD_H__ 2 | #define __TCPCRYPT_TCPCRYPTD_H__ 3 | 4 | #define REDIRECT_PORT 65530 5 | 6 | #define MAX_PARAM 12 7 | 8 | enum { 9 | XP_ALWAYS = 0, 10 | XP_DEFAULT, 11 | XP_DEBUG, 12 | XP_NOISY, 13 | }; 14 | 15 | enum { 16 | TEST_CRYPT = 0, 17 | TEST_TCP, 18 | }; 19 | 20 | enum { 21 | TEST_STATE_START = 0, 22 | TEST_STATE_CONNECTING, 23 | TEST_STATE_REQ_SENT, 24 | TEST_SUCCESS, 25 | TEST_STATE_DONE, 26 | }; 27 | 28 | enum { 29 | TEST_ERR_TIMEOUT = 666, 30 | TEST_ERR_DISCONNECT = 667, 31 | TEST_ERR_BADINPUT = 668, 32 | TEST_ERR_UNEXPECTED_CRYPT = 669, 33 | TEST_ERR_NO_CRYPT = 670, 34 | }; 35 | 36 | struct params { 37 | char *p_params[MAX_PARAM]; 38 | int p_paramc; 39 | }; 40 | 41 | struct conf { 42 | int cf_divert; 43 | int cf_verbose; 44 | int cf_disable; 45 | const char *cf_ctl; 46 | int cf_nocache; 47 | int cf_accept; 48 | int cf_modify; 49 | int cf_dummy; 50 | int cf_profile; 51 | int cf_test; 52 | int cf_debug; 53 | struct params cf_test_params; 54 | struct params cf_divert_params; 55 | int cf_nat; 56 | int cf_cipher; 57 | int cf_mac; 58 | int cf_rsa_client_hack; 59 | int cf_disable_timers; 60 | int cf_disable_network_test; 61 | int cf_rdr; 62 | const char *cf_test_server; 63 | const char *cf_random_path; 64 | const char *cf_jail_dir; 65 | const char *cf_jail_user; 66 | }; 67 | 68 | struct fd; 69 | typedef void (*fd_cb)(struct fd *fd); 70 | 71 | enum { 72 | FDS_IDLE = 0, 73 | FDS_READ, 74 | FDS_WRITE, 75 | FDS_DEAD 76 | }; 77 | 78 | struct fd { 79 | int fd_fd; 80 | fd_cb fd_cb; 81 | int fd_state; 82 | void *fd_priv; 83 | struct fd *fd_next; 84 | }; 85 | 86 | extern struct conf _conf; 87 | 88 | typedef void (*timer_cb)(void *a); 89 | typedef int (*packet_hook)(int rc, void *packet, int len, int flags); 90 | 91 | extern void *add_timer(unsigned int usec, timer_cb cb, void *arg); 92 | extern struct fd *add_fd(int fd, fd_cb cb); 93 | extern void clear_timer(void *timer); 94 | extern void xprintf(int level, char *fmt, ...); 95 | extern void hexdump(void *p, int len); 96 | extern void errssl(int x, char *fmt, ...); 97 | extern void set_time(struct timeval *tv); 98 | extern void tcpcryptd(void); 99 | extern void set_packet_hook(int post, packet_hook hook); 100 | extern char *driver_param(int x); 101 | extern char *test_param(int x); 102 | extern void set_nonblocking(int x); 103 | 104 | extern uint64_t xbe64toh(uint64_t x); 105 | extern uint64_t xhtobe64(uint64_t x); 106 | 107 | #endif /* __TCPCRYPT_TCPCRYPTD_H__ */ 108 | -------------------------------------------------------------------------------- /INSTALL-Linux.markdown: -------------------------------------------------------------------------------- 1 | Installing tcpcrypt on Linux 2 | ============================ 3 | 4 | Tcpcrypt has 2 separate Linux implementations: kernel and userland. These 5 | instructions cover only the userland tcpcrypt, which is easier to set up. 6 | 7 | 8 | Dependencies 9 | ============ 10 | 11 | * OpenSSL >= 0.9.8 12 | * libnfnetlink >= 0.0.40 13 | * libnetfilter_queue >= 0.0.16 14 | * libnetfilter_conntrack >= 1.0.1 15 | * libcap 16 | * Kernel divert socket support (NFQUEUE) 17 | 18 | 19 | Ubuntu and Debian package dependencies 20 | -------------------------------------- 21 | apt-get install iptables libcap-dev libssl-dev \ 22 | libnfnetlink-dev \ 23 | libnetfilter-queue-dev \ 24 | libnetfilter-conntrack-dev 25 | 26 | 27 | Arch Linux package dependencies 28 | ------------------------------- 29 | 30 | pacman -S --needed \ 31 | base-devel \ 32 | iptables \ 33 | openssl \ 34 | libnfnetlink \ 35 | libnetfilter_queue \ 36 | libcap \ 37 | libnetfilter_queue \ 38 | libnetfilter_conntrack 39 | 40 | 41 | Kernel divert sockets (NFQUEUE) 42 | ------------------------------- 43 | 44 | Installing your distribution's libnfnetfilter_queue package most likely handles 45 | this for you. If not, then you need to enable the following in `make 46 | menuconfig`: 47 | 48 | * Networking -> Networking options -> Network packet filtering framework (Netfilter) and the following suboptions 49 | * Core Netfilter Configuration -> Netfilter NFQUEUE over NFNETLINK interface 50 | * Core Netfilter Configuration -> Netfilter Xtables support -> "NFQUEUE" target Support 51 | 52 | The `.config` options for these are: 53 | 54 | CONFIG_NETFILTER_NETLINK 55 | CONFIG_NETFILTER_NETLINK_QUEUE 56 | CONFIG_NETFILTER_XT_TARGET_NFQUEUE 57 | 58 | 59 | Compiling 60 | --------- 61 | 62 | Run: 63 | 64 | cd tcpcrypt 65 | ./bootstrap.sh 66 | ./configure 67 | make 68 | 69 | Optional: running `make install` will install `libtcpcrypt` and tcpcrypt 70 | headers, for building apps that use tcpcrypt's session ID. 71 | 72 | 73 | Try it out 74 | ---------- 75 | 76 | See the included `README.markdown` file for ways to try out tcpcrypt. 77 | 78 | 79 | Reported issues 80 | --------------- 81 | 82 | Tcpcrypt is incompatible with ECN (explicit congestion notification, RFC 3168). To disable ECN (if you know what you're doing), run `sudo sysctl net.ipv4.tcp_ecn=0`. Reported by jech at https://github.com/sorbo/tcpcrypt/issues/7. 83 | 84 | 85 | iptables firewall setup 86 | ======================= 87 | 88 | The included `launch_tcpcryptd.sh` script adds iptable rules to divert all TCP 89 | traffic port 80 to tcpcryptd. See src/iptables.sh for details. 90 | -------------------------------------------------------------------------------- /src/crypto_umac.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "contrib/umac.h" 10 | #include "inc.h" 11 | #include "tcpcrypt_ctl.h" 12 | #include "tcpcrypt.h" 13 | #include "tcpcryptd.h" 14 | #include "crypto.h" 15 | #include "profile.h" 16 | 17 | #if 0 18 | #define MAC_SIZE 8 19 | 20 | static struct tc_scipher _umac_spec = 21 | { 0x0 }; 22 | 23 | static struct crypt_prop _umac_prop = { 24 | .cp_ivlen = 0, 25 | .cp_ivmode = IVMODE_NONE, 26 | .cp_maclen = MAC_SIZE, 27 | .cp_cipherlen = 0, 28 | .cp_preference = -1, 29 | }; 30 | 31 | struct umac_priv { 32 | umac_ctx_t hp_ctx; 33 | }; 34 | 35 | static void umac_init(struct tc *tc) 36 | { 37 | struct umac_priv *hp; 38 | 39 | hp = crypto_priv_init(tc, sizeof(*hp)); 40 | } 41 | 42 | static void umac_finish(struct tc *tc) 43 | { 44 | struct umac_priv *hp = crypto_priv(tc); 45 | 46 | if (!hp) 47 | return; 48 | 49 | if (hp->hp_ctx) 50 | umac_delete(hp->hp_ctx); 51 | 52 | free(hp); 53 | } 54 | 55 | static void umac_mac(struct tc *tc, struct iovec *iov, int num, void *iv, 56 | void *out, int *outlen) 57 | { 58 | struct umac_priv *hp = crypto_priv(tc); 59 | char nonce[8]; 60 | 61 | if (*outlen < MAC_SIZE) { 62 | *outlen = MAC_SIZE; 63 | return; 64 | } 65 | 66 | memset(nonce, 0, sizeof(nonce)); 67 | 68 | umac_reset(hp->hp_ctx); 69 | while (num--) { 70 | umac_update(hp->hp_ctx, iov->iov_base, iov->iov_len); 71 | iov++; 72 | } 73 | 74 | umac_final(hp->hp_ctx, out, nonce); 75 | *outlen = MAC_SIZE; 76 | } 77 | 78 | static void *umac_spec(void) 79 | { 80 | return &_umac_spec; 81 | } 82 | 83 | static int umac_type(void) 84 | { 85 | return TYPE_MAC; 86 | } 87 | 88 | static int umac_set_key(struct tc *tc, void *key, int len) 89 | { 90 | struct umac_priv *hp = crypto_priv(tc); 91 | 92 | if (hp->hp_ctx) 93 | umac_delete(hp->hp_ctx); 94 | 95 | hp->hp_ctx = umac_new(key); 96 | assert(hp->hp_ctx); 97 | 98 | return 0; 99 | } 100 | 101 | static struct crypt_prop *umac_prop(struct tc *tc) 102 | { 103 | return &_umac_prop; 104 | } 105 | 106 | struct crypt_ops _umac_ops = { 107 | .co_init = umac_init, 108 | .co_finish = umac_finish, 109 | .co_mac = umac_mac, 110 | .co_spec = umac_spec, 111 | .co_type = umac_type, 112 | .co_set_key = umac_set_key, 113 | .co_crypt_prop = umac_prop, 114 | }; 115 | 116 | static void __umac_init(void) __attribute__ ((constructor)); 117 | 118 | static void __umac_init(void) 119 | { 120 | // crypto_register(&_umac_ops); 121 | } 122 | #endif 123 | -------------------------------------------------------------------------------- /src/mingw.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "inc.h" 9 | #include "tcpcrypt_divert.h" 10 | #include "tcpcryptd.h" 11 | 12 | #include 13 | 14 | #define MAC_SIZE 14 15 | 16 | static HANDLE _h; 17 | 18 | static WINAPI DWORD reader(void *arg) 19 | { 20 | int s; 21 | struct sockaddr_in s_in; 22 | UINT r; 23 | unsigned char buf[2048]; 24 | 25 | // XXX: the DIVERT_ADDRESS is stored in the ethhdr. 26 | PDIVERT_ADDRESS addr = (PDIVERT_ADDRESS)buf; 27 | 28 | if ((s = socket(PF_INET, SOCK_DGRAM, 0)) == -1) 29 | err(1, "socket()"); 30 | 31 | memset(&s_in, 0, sizeof(s_in)); 32 | 33 | s_in.sin_family = PF_INET; 34 | s_in.sin_addr.s_addr = inet_addr("127.0.0.1"); 35 | s_in.sin_port = htons(619); 36 | 37 | while (1) { 38 | memset(buf, 0, MAC_SIZE); 39 | if (!DivertRecv(_h, buf + MAC_SIZE, sizeof(buf) - MAC_SIZE, 40 | addr, &r)) 41 | err(1, "DivertRead()"); 42 | 43 | if (sendto(s, (void*) buf, r + MAC_SIZE, 0, 44 | (struct sockaddr*) &s_in, sizeof(s_in)) != 45 | r + MAC_SIZE) 46 | err(1, "sendto()"); 47 | } 48 | 49 | return 0; 50 | } 51 | 52 | int do_divert_open(void) 53 | { 54 | // XXX i know this is lame 55 | struct sockaddr_in s_in; 56 | int s; 57 | 58 | s = socket(PF_INET, SOCK_DGRAM, 0); 59 | if (s == -1) 60 | err(1, "socket()"); 61 | 62 | memset(&s_in, 0, sizeof(s_in)); 63 | s_in.sin_family = PF_INET; 64 | s_in.sin_addr.s_addr = inet_addr("127.0.0.1"); 65 | s_in.sin_port = htons(619); 66 | 67 | if (bind(s, (struct sockaddr*) &s_in, sizeof(s_in)) == -1) 68 | err(1, "bind(divert)"); 69 | 70 | // XXX: Currently TCP port 80 only... 71 | _h = DivertOpen( 72 | "ip and " 73 | "((outbound and tcp.DstPort == 80) or " 74 | " (inbound and tcp.SrcPort == 80) or " 75 | " (outbound and tcp.SrcPort == 65530)" 76 | ") and " 77 | "ip.DstAddr != 127.0.0.1 and " 78 | "ip.SrcAddr != 127.0.0.1", 79 | WINDIVERT_LAYER_NETWORK, 0, 0); 80 | 81 | if (_h == INVALID_HANDLE_VALUE) 82 | err(1, "DivertOpen()"); 83 | 84 | if (!CreateThread(NULL, 0, reader, NULL, 0, NULL)) 85 | err(1, "CreateThread()"); 86 | 87 | return s; 88 | } 89 | 90 | void do_divert_close(int s) 91 | { 92 | DivertClose(_h); 93 | } 94 | 95 | int do_divert_read(int s, void *buf, int len) 96 | { 97 | return recv(s, buf, len, 0); 98 | } 99 | 100 | int do_divert_write(int s, void *buf, int len) 101 | { 102 | UINT r; 103 | PDIVERT_ADDRESS addr = (PDIVERT_ADDRESS)buf; 104 | 105 | if (len <= MAC_SIZE) 106 | return -1; 107 | 108 | buf += MAC_SIZE; 109 | len -= MAC_SIZE; 110 | 111 | if (!DivertSend(_h, buf, len, addr, &r)) 112 | return -1; 113 | 114 | return r + MAC_SIZE; 115 | } 116 | 117 | -------------------------------------------------------------------------------- /src/crypto_hmac.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "inc.h" 10 | #include "tcpcrypt_ctl.h" 11 | #include "tcpcrypt.h" 12 | #include "tcpcryptd.h" 13 | #include "crypto.h" 14 | #include "profile.h" 15 | 16 | #define MAC_SIZE 32 17 | 18 | struct hmac_priv { 19 | HMAC_CTX *hp_ctx; 20 | int hp_fresh; 21 | }; 22 | 23 | #if OPENSSL_VERSION_NUMBER < 0x10100000L 24 | 25 | static HMAC_CTX *HMAC_CTX_new(void) 26 | { 27 | HMAC_CTX *ctx = OPENSSL_malloc(sizeof(HMAC_CTX)); 28 | 29 | if (ctx != NULL) 30 | HMAC_CTX_init(ctx); 31 | return ctx; 32 | } 33 | 34 | static void HMAC_CTX_free(HMAC_CTX *ctx) 35 | { 36 | if (ctx != NULL) { 37 | HMAC_CTX_cleanup(ctx); 38 | OPENSSL_free(ctx); 39 | } 40 | } 41 | 42 | #endif 43 | 44 | static void hmac_destroy(struct crypt *c) 45 | { 46 | struct hmac_priv *hp = crypt_priv(c); 47 | 48 | if (!hp) 49 | errx(1, "hmac_destroy: null priv"); 50 | 51 | HMAC_CTX_free(hp->hp_ctx); 52 | free(hp); 53 | free(c); 54 | } 55 | 56 | static void hmac_mac(struct crypt *c, const struct iovec *iov, int num, 57 | void *out, int *outlen) 58 | { 59 | struct hmac_priv *hp = crypt_priv(c); 60 | void *o = out; 61 | unsigned int olen = MAC_SIZE; 62 | 63 | profile_add(3, "hmac_mac in"); 64 | 65 | if (!hp->hp_fresh) { 66 | if (HMAC_Init_ex(hp->hp_ctx, NULL, 0, NULL, NULL) != 1) 67 | errx(1, "HMAC_Init_ex"); 68 | } 69 | else 70 | hp->hp_fresh = 0; 71 | 72 | while (num--) { 73 | if (HMAC_Update(hp->hp_ctx, iov->iov_base, iov->iov_len) != 1) 74 | errx(1, "HMAC_Update"); 75 | profile_add(3, "hmac_mac update"); 76 | iov++; 77 | } 78 | 79 | if (*outlen < MAC_SIZE) 80 | o = alloca(MAC_SIZE); 81 | 82 | if (HMAC_Final(hp->hp_ctx, o, &olen) != 1) 83 | errx(1, "HMAC_Final"); 84 | profile_add(3, "hmac_mac final"); 85 | 86 | if (*outlen < MAC_SIZE) 87 | memcpy(out, o, *outlen); 88 | else 89 | *outlen = olen; 90 | } 91 | 92 | static int hmac_set_key(struct crypt *c, void *key, int len) 93 | { 94 | struct hmac_priv *hp = crypt_priv(c); 95 | 96 | if (HMAC_Init_ex(hp->hp_ctx, key, len, NULL, NULL) != 1) 97 | errx(1, "HMAC_Init_ex"); 98 | 99 | hp->hp_fresh = 1; 100 | 101 | return 0; 102 | } 103 | 104 | struct crypt *crypt_HMAC_SHA256_new(void) 105 | { 106 | struct hmac_priv *hp; 107 | struct crypt *c; 108 | 109 | c = crypt_init(sizeof(*hp)); 110 | c->c_destroy = hmac_destroy; 111 | c->c_set_key = hmac_set_key; 112 | c->c_mac = hmac_mac; 113 | 114 | hp = crypt_priv(c); 115 | 116 | hp->hp_ctx = HMAC_CTX_new(); 117 | if (!hp->hp_ctx) 118 | errx(1, "HMAC_CTX_new"); 119 | 120 | if (HMAC_Init_ex(hp->hp_ctx, "a", 1, EVP_sha256(), NULL) != 1) 121 | errx(1, "HMAC_Init_ex"); 122 | 123 | return c; 124 | } 125 | -------------------------------------------------------------------------------- /INSTALL-Windows.markdown: -------------------------------------------------------------------------------- 1 | Installing tcpcrypt on Windows 2 | ============================== 3 | 4 | Compiling 5 | ========= 6 | 7 | Only cross-compiling for Windows on Linux (using mingw) is supported right now. You can almost certainly compile the Windows version on Windows itself, but we haven't done that yet (if you have, contact us). 8 | 9 | Using mingw, run the following commands to cross-compile tcpcrypt for Windows 10 | on a Linux host. 11 | 12 | cd tcpcrypt 13 | ./bootstrap.sh 14 | ./configure CFLAGS="-mwin32 -D__WIN32__ -I/home/sqs/src/mingw/OpenSSL-Win32/include" LDFLAGS=" -L/home/sqs/src/mingw/OpenSSL-Win32/ " --host=i586-mingw32msvc 15 | make 16 | 17 | Replace `` with the path to OpenSSL compiled for 18 | Windows. You can download binaries from 19 | [http://www.slproweb.com/products/Win32OpenSSL.html](http://www.slproweb.com/products/Win32OpenSSL.html) 20 | (use the 'Win32 OpenSSL v1.0.0a' link) and run the installer with Wine. Then 21 | rename `libeay32.dll` to `libcrypto.dll` in the root OpenSSL folder (that you 22 | just installed into). There's almost certainly a cleaner way to do this, but 23 | this is the quickest way. 24 | 25 | tcpcrypt depends on WinDivert: 26 | 27 | http://reqrypt.org/windivert.html 28 | 29 | You'll have to supply paths to header files and WinDivert.dll when compiling 30 | (modify CFLAGS and LDFLAGS as above). 31 | 32 | Optional: running `make install` will install `libtcpcrypt` and tcpcrypt 33 | headers, for building apps that use tcpcrypt's session ID. 34 | 35 | 36 | Installing 37 | ========== 38 | 39 | The Windows implementation of tcpcrypt has two components: the third-party kernel divert 40 | socket driver and the userland daemon. 41 | 42 | Installing the kernel divert socket driver 43 | ------------------------------------------ 44 | 45 | http://reqrypt.org/windivert.html 46 | 47 | Just place WinDivert32.sys and WinDirver64.sys in the directory of tcpcrypt. 48 | 49 | Getting the userland daemon 50 | --------------------------- 51 | 52 | If you followed the compilation steps above, you're done. Otherwise, download 53 | the pre-compiled tcpcryptd binary for Windows at 54 | [http://tcpcrypt.org/](http://tcpcrypt.org/). If you will use the launch script 55 | (below), move this file to tcpcrypt/user/tcpcrypt/tcpcryptd.exe, which is where 56 | the launch script expects it. 57 | 58 | Or you can just download the precompiled Windows GUI version at the link above. 59 | 60 | Running 61 | ======= 62 | 63 | After installing the divert socket driver, run the tcpcryptd daemon with the 64 | following command: 65 | 66 | ./launch_tcpcryptd.sh 67 | 68 | By default, this script tells tcpcryptd to use the first network interface 69 | listed in `ipconfig /all`. If you want to use a different interface, run 70 | tcpcryptd manually: 71 | 72 | tcpcrypt/tcpcryptd -x 0a:1b:2c:3d:4f:6a 73 | 74 | 75 | Test drive 76 | ========== 77 | 78 | Once tcpcryptd is running, see README.markdown for ways to try it out. 79 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | Tcpcrypt 2 | ======== 3 | 4 | Tcpcrypt is a protocol that attempts to encrypt (almost) all of your network 5 | traffic. Unlike other security mechanisms, Tcpcrypt works out of the box: it 6 | requires no configuration, no changes to applications, and your network 7 | connections will continue to work even if the remote end does not support 8 | Tcpcrypt, in which case connections will gracefully fall back to standard 9 | clear-text TCP. 10 | 11 | Tcpcrypt supports Linux, Mac OS X, Windows, and FreeBSD. 12 | 13 | For more information, see [tcpcrypt.org](http://tcpcrypt.org). 14 | 15 | Installing tcpcrypt 16 | ------------------- 17 | 18 | git clone git://github.com/scslab/tcpcrypt.git 19 | cd tcpcrypt 20 | ./bootstrap.sh 21 | ./configure 22 | make 23 | sudo ./launch_tcpcryptd.sh 24 | 25 | The launch script starts tcpcryptd and adds firewall rules to divert all TCP 26 | traffic on port 80 to tcpcryptd. When the script exits (on Ctrl-C or `kill`), 27 | it restores your firewall config to its former state -- *no permanent changes 28 | are made*. 29 | 30 | On Linux, you must first install libnfnetlink, libnetfilter_queue, and libcap. 31 | 32 | Optional: running `make install` will install `libtcpcrypt` and tcpcrypt 33 | headers, for building apps that use tcpcrypt's session ID. 34 | 35 | Try it out 36 | ---------- 37 | 38 | Go to [http://tcpcrypt.org/test.php](http://tcpcrypt.org/test.php) with 39 | tcpcryptd running. If tcpcrypt is working, you'll be able to join the 40 | tcpcrypt Hall of Fame and your tcpcrypt session ID will be displayed at the 41 | bottom of the page. 42 | 43 | Now let's examine the packets going over the wire by starting tcpdump and then 44 | reloading the URL above. 45 | 46 | sudo tcpdump -X -s0 host tcpcrypt.org 47 | 48 | Compare this tcpdump output, which appears encrypted (or at least unreadable), 49 | with the cleartext packets you would see without tcpcryptd running. 50 | 51 | Troubleshooting 52 | --------------- 53 | 54 | If it's not working, the most likely causes are the following. 55 | 56 | * Your browser already had an open, non-tcpcrypted TCP connection to 57 | tcpcrypt.org before you ran the launch script. Quit and reopen your 58 | browser, wait 30 seconds, or use a different browser to retrieve the 59 | tcpcrypt.org URL. 60 | 61 | * There's a conflict with your existing firewall rules. See the 62 | firewall setup section in the install guide for your platform. 63 | 64 | Visit [http://wiki.github.com/scslab/tcpcrypt/troubleshooting](http://wiki.github.com/scslab/tcpcrypt/troubleshooting) if you're still 65 | unable to make it work. 66 | 67 | 68 | More info 69 | --------- 70 | 71 | The `INSTALL-*` files have more detailed installation and firewall setup instructions. See [tcpcrypt.org](http://tcpcrypt.org) for general info, including the [protocol specification](http://tcpcrypt.org/docs.php) and the [tcpcrypt paper, "The case for ubiquitous transport-level encryption"](http://tcpcrypt.org/tcpcrypt.pdf), presented at USENIX Security 2010. 72 | 73 | The code repository lives at [http://github.com/scslab/tcpcrypt](http://github.com/scslab/tcpcrypt). 74 | -------------------------------------------------------------------------------- /contrib/cmac.h: -------------------------------------------------------------------------------- 1 | /* crypto/cmac/cmac.h */ 2 | /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL 3 | * project. 4 | */ 5 | /* ==================================================================== 6 | * Copyright (c) 2010 The OpenSSL Project. All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 15 | * 2. Redistributions in binary form must reproduce the above copyright 16 | * notice, this list of conditions and the following disclaimer in 17 | * the documentation and/or other materials provided with the 18 | * distribution. 19 | * 20 | * 3. All advertising materials mentioning features or use of this 21 | * software must display the following acknowledgment: 22 | * "This product includes software developed by the OpenSSL Project 23 | * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 24 | * 25 | * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 26 | * endorse or promote products derived from this software without 27 | * prior written permission. For written permission, please contact 28 | * licensing@OpenSSL.org. 29 | * 30 | * 5. Products derived from this software may not be called "OpenSSL" 31 | * nor may "OpenSSL" appear in their names without prior written 32 | * permission of the OpenSSL Project. 33 | * 34 | * 6. Redistributions of any form whatsoever must retain the following 35 | * acknowledgment: 36 | * "This product includes software developed by the OpenSSL Project 37 | * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 38 | * 39 | * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 40 | * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 41 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 42 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 43 | * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 44 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 45 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 46 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 47 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 48 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 49 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 50 | * OF THE POSSIBILITY OF SUCH DAMAGE. 51 | * ==================================================================== 52 | */ 53 | 54 | 55 | #ifndef HEADER_CMAC_H 56 | #define HEADER_CMAC_H 57 | 58 | #ifdef __cplusplus 59 | extern "C" { 60 | #endif 61 | 62 | #include 63 | 64 | /* Opaque */ 65 | typedef struct CMAC_CTX_st CMAC_CTX; 66 | 67 | CMAC_CTX *CMAC_CTX_new(void); 68 | void CMAC_CTX_cleanup(CMAC_CTX *ctx); 69 | void CMAC_CTX_free(CMAC_CTX *ctx); 70 | EVP_CIPHER_CTX *CMAC_CTX_get0_cipher_ctx(CMAC_CTX *ctx); 71 | 72 | int CMAC_Init(CMAC_CTX *ctx, const void *key, size_t keylen, 73 | const EVP_CIPHER *cipher, ENGINE *impl); 74 | int CMAC_Update(CMAC_CTX *ctx, const void *data, size_t dlen); 75 | int CMAC_Final(CMAC_CTX *ctx, unsigned char *out, size_t *poutlen); 76 | int CMAC_resume(CMAC_CTX *ctx); 77 | 78 | #ifdef __cplusplus 79 | } 80 | #endif 81 | #endif 82 | -------------------------------------------------------------------------------- /src/tcpcryptd.man.md: -------------------------------------------------------------------------------- 1 | % tcpcryptd(8) 2 | % 3 | 4 | # NAME 5 | 6 | __tcpcryptd__ - Implement the tcpcrypt protocol by transparently modifying network I/O 7 | 8 | # SYNOPSIS 9 | 10 | __tcpcryptd__ [_options_] 11 | 12 | # OPTIONS 13 | 14 | A list of all options is produced by: 15 | 16 | > __tcpcryptd -h__ 17 | 18 | Configuration of packet-diversion rules allows the system administrator to 19 | control which TCP connections are protected by __tcpcryptd__. 20 | The daemon receives packets for transformation via a "divert port", 21 | configurable with __-p__ _port_. 22 | 23 | The daemon communicates with user programs via a "control socket", configurable 24 | with __-u__ _socket_address_. If _socket_address_ begins with "/", it is 25 | interpreted as a filesystem path pointing to a unix-domain socket; if it is 26 | of the form ":_port_", it is interpreted as the internet address localhost:_port_. 27 | 28 | Verbosity may be increased with multiple __-v__ options. 29 | 30 | A "phone-home" test will be performed at daemon startup to confirm end-to-end 31 | functionality of the implementation (by default, with the authors' server), but 32 | may be redirected to another test-server with __-s__ _hostname_ or disabled 33 | completely with __-f__. 34 | 35 | 36 | 37 | # DESCRIPTION 38 | 39 | The __tcpcryptd__ daemon transforms TCP segments via a kernel "divert" port in 40 | order to implement "opportunistic encryption" according to the _tcpcrypt_ 41 | protocol. 42 | 43 | For a peer that signals in the connection handshake that it has support for the 44 | _tcpcrypt_ protocol, ephemeral keys are exchanged and used to protect the 45 | confidentiality and integrity of the connection's application data. (The 46 | protocol protects the integrity of parts of the TCP header as well.) When a 47 | peer does not indicate support for the protocol, the daemon will pass the 48 | remainder of the connection unperturbed (and thus unprotected). 49 | 50 | Application software need not be modified to take advantage of this facility, 51 | which provides confidentiality in the face of passive network attackers (those 52 | who cannot modify network data in transit). But in order to protect 53 | communication from active attackers, the application must intentionally 54 | authenticate the connection as described below. 55 | 56 | ## Authentication 57 | 58 | The _tcpcrypt_ protocol does not itself protect communications against "active 59 | attackers", that is, those who are able to modify network packets in transit. 60 | Such an attacker may perform a "man in the middle" attack that allows 61 | her to behave as the endpoint of the encrypted connection and thus compromise 62 | its security. 63 | 64 | However, applications aware of _tcpcrypt_ may authenticate the connection in 65 | whatever manner they choose, aided by an identifier for the connection that is 66 | derived from the protocol and made available by __tcpcryptd__: 67 | 68 | A _session id_ is derived from the ephemeral keys used to encrypt each 69 | connection protected by _tcpcrypt_. This identifier is (probabalistically) 70 | unique over all connections, is not secret, and may be extracted by 71 | applications via the user library __libtcpcrypt__. Session ids for all active 72 | connections may also be listed with the netstat-like utility __tcnetstat__(8). 73 | 74 | Connection peers may ensure they are communicating securely with each other 75 | (enjoying confidentiality and integrity in the face of active network 76 | attackers) by confirming that the _tcpcrypt_ session ids derived at each end 77 | are identical. For example, they may bind the session id together with a 78 | shared secret such as a password, sign it with public keys, use a voice 79 | connection to speak a fingerprint of it, or simply record it for later 80 | confirmation. 81 | 82 | # SEE ALSO 83 | 84 | __tcnetstat__(8), [http://tcpcrypt.org/](http://tcpcrypt.org/) 85 | 86 | -------------------------------------------------------------------------------- /src/iptables.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # determine which operation is requested (Append or Delete) 4 | if [ "$1" = "start" -o -z "$1" ]; then 5 | # during startup, bail early if any of these commands fails 6 | set -e 7 | OP="-A" 8 | elif [ "$1" = "stop" -o "$1" = "-f" ] ; then 9 | OP="-D" 10 | else 11 | echo "Expected \"start\" or \"stop\" as first argument" >&2 12 | exit 1 13 | fi 14 | 15 | # determine which ports should be tcpcrypt-enabled 16 | if [ -z "$ONLY_PORTS" -a -z "$OMIT_PORTS" ] ; then 17 | echo "Expected either OMIT_PORTS or ONLY_PORTS environment variables to be set" >&2 18 | exit 1 19 | fi 20 | if [ -n "$ONLY_PORTS" -a -n "$OMIT_PORTS" ] ; then 21 | echo "Expected only one of OMIT_PORTS or ONLY_PORTS environment variables to be set" >&2 22 | exit 1 23 | fi 24 | if [ -n "$OMIT_PORTS" ] ; then 25 | PORT_TEST=! 26 | PORTS="$OMIT_PORTS" 27 | fi 28 | if [ -n "$ONLY_PORTS" ] ; then 29 | PORT_TEST= 30 | PORTS="$ONLY_PORTS" 31 | fi 32 | 33 | # more necessary configuration 34 | if [ -z "$DAEMON_USER" ] ; then 35 | echo "Expected DAEMON_USER environment variable to be set" >&2 36 | exit 1 37 | fi 38 | if [ -z "$DIVERT_PORT" ] ; then 39 | echo "Expected DIVERT_PORT environment variable to be set" >&2 40 | exit 1 41 | fi 42 | 43 | # some shorthand to make rules more concise 44 | from_enabled_port="-m multiport $PORT_TEST --source-ports $PORTS" 45 | to_enabled_port="-m multiport $PORT_TEST --destination-ports $PORTS" 46 | NFQUEUE="NFQUEUE --queue-num $DIVERT_PORT" 47 | REDIRECT_PORT="65530" 48 | REDIRECT="REDIRECT --to-port $REDIRECT_PORT" 49 | INJECT_TOS="0x22" 50 | HANDSHAKE_TOS="0x04" 51 | 52 | filter="$ECHO iptables -t filter $OP" 53 | 54 | # Injection from daemon: Accept 55 | $filter INPUT -i lo -p tcp --dport $REDIRECT_PORT \ 56 | -m tos --tos $INJECT_TOS \ 57 | -j ACCEPT 58 | 59 | # SYN redirected to daemon: 60 | # Queue for daemon to initiate proxy connection with original destination 61 | $filter INPUT -p tcp \! -s 127.0.0.1 --dport $REDIRECT_PORT --tcp-flags ALL SYN \ 62 | -j $NFQUEUE 63 | 64 | # SYN+ACK on proxy connection: 65 | # Queue for daemon to complete original handshake 66 | $filter INPUT -p tcp $from_enabled_port --tcp-flags ALL SYN,ACK \ 67 | -j $NFQUEUE 68 | 69 | 70 | # Handshake packet of proxy connection from daemon: 71 | # Queue for daemon to set tcp options via DIVERT_MODIFY 72 | $filter OUTPUT -p tcp $to_enabled_port \ 73 | -m tos --tos $HANDSHAKE_TOS \ 74 | -m owner --uid-owner $DAEMON_USER \ 75 | -j $NFQUEUE 76 | 77 | # SYN+ACK on redirected connection: 78 | # Queue for daemon to delay handshake until proxy connection succeeds 79 | $filter OUTPUT -p tcp --sport $REDIRECT_PORT --tcp-flags ALL SYN,ACK \ 80 | -j $NFQUEUE 81 | 82 | 83 | nat="$ECHO iptables -t nat $OP" 84 | 85 | # Inbound connection for enabled ports: 86 | # Redirect to daemon (at localhost:$REDIRECT_PORT) for encryption 87 | # 88 | # (The nat module will now translate addresses in both directions, 89 | # for the lifetime of this connection.) 90 | $nat PREROUTING -p tcp $to_enabled_port \ 91 | -j $REDIRECT 92 | 93 | 94 | # Proxy connection from daemon to enabled port: Accept 95 | $nat OUTPUT -p tcp $to_enabled_port \ 96 | -m owner --uid-owner $DAEMON_USER \ 97 | -j ACCEPT 98 | 99 | # Outbound connections to enabled ports on remote hosts: 100 | # Redirect to daemon (at localhost port $REDIRECT_PORT) for encryption 101 | # 102 | # (The nat module will now translate addresses in both directions, 103 | # for the lifetime of this connection.) 104 | $nat OUTPUT \! -o lo -p tcp $to_enabled_port \ 105 | -j $REDIRECT 106 | 107 | 108 | mangle="$ECHO iptables -t mangle $OP" 109 | 110 | # Packets leaving the machine with bookkeeping mark: Remove mark 111 | $mangle POSTROUTING -m tos --tos $HANDSHAKE_TOS \ 112 | -j TOS --set-tos 0x00 113 | -------------------------------------------------------------------------------- /src/tcpcryptd.man: -------------------------------------------------------------------------------- 1 | .TH "tcpcryptd" "8" "" "" "" 2 | .SH NAME 3 | .PP 4 | \f[B]tcpcryptd\f[] \- Implement the tcpcrypt protocol by transparently 5 | modifying network I/O 6 | .SH SYNOPSIS 7 | .PP 8 | \f[B]tcpcryptd\f[] [\f[I]options\f[]] 9 | .SH OPTIONS 10 | .PP 11 | A list of all options is produced by: 12 | .RS 13 | .PP 14 | \f[B]tcpcryptd \-h\f[] 15 | .RE 16 | .PP 17 | Configuration of packet\-diversion rules allows the system administrator 18 | to control which TCP connections are protected by \f[B]tcpcryptd\f[]. 19 | The daemon receives packets for transformation via a "divert port", 20 | configurable with \f[B]\-p\f[] \f[I]port\f[]. 21 | .PP 22 | The daemon communicates with user programs via a "control socket", 23 | configurable with \f[B]\-u\f[] \f[I]socket_address\f[]. 24 | If \f[I]socket_address\f[] begins with "/", it is interpreted as a 25 | filesystem path pointing to a unix\-domain socket; if it is of the form 26 | ":\f[I]port\f[]", it is interpreted as the internet address 27 | localhost:\f[I]port\f[]. 28 | .PP 29 | Verbosity may be increased with multiple \f[B]\-v\f[] options. 30 | .PP 31 | A "phone\-home" test will be performed at daemon startup to confirm 32 | end\-to\-end functionality of the implementation (by default, with the 33 | authors\[aq] server), but may be redirected to another test\-server with 34 | \f[B]\-s\f[] \f[I]hostname\f[] or disabled completely with \f[B]\-f\f[]. 35 | .SH DESCRIPTION 36 | .PP 37 | The \f[B]tcpcryptd\f[] daemon transforms TCP segments via a kernel 38 | "divert" port in order to implement "opportunistic encryption" according 39 | to the \f[I]tcpcrypt\f[] protocol. 40 | .PP 41 | For a peer that signals in the connection handshake that it has support 42 | for the \f[I]tcpcrypt\f[] protocol, ephemeral keys are exchanged and 43 | used to protect the confidentiality and integrity of the 44 | connection\[aq]s application data. 45 | (The protocol protects the integrity of parts of the TCP header as 46 | well.) When a peer does not indicate support for the protocol, the 47 | daemon will pass the remainder of the connection unperturbed (and thus 48 | unprotected). 49 | .PP 50 | Application software need not be modified to take advantage of this 51 | facility, which provides confidentiality in the face of passive network 52 | attackers (those who cannot modify network data in transit). 53 | But in order to protect communication from active attackers, the 54 | application must intentionally authenticate the connection as described 55 | below. 56 | .SS Authentication 57 | .PP 58 | The \f[I]tcpcrypt\f[] protocol does not itself protect communications 59 | against "active attackers", that is, those who are able to modify 60 | network packets in transit. 61 | Such an attacker may perform a "man in the middle" attack that allows 62 | her to behave as the endpoint of the encrypted connection and thus 63 | compromise its security. 64 | .PP 65 | However, applications aware of \f[I]tcpcrypt\f[] may authenticate the 66 | connection in whatever manner they choose, aided by an identifier for 67 | the connection that is derived from the protocol and made available by 68 | \f[B]tcpcryptd\f[]: 69 | .PP 70 | A \f[I]session id\f[] is derived from the ephemeral keys used to encrypt 71 | each connection protected by \f[I]tcpcrypt\f[]. 72 | This identifier is (probabalistically) unique over all connections, is 73 | not secret, and may be extracted by applications via the user library 74 | \f[B]libtcpcrypt\f[]. 75 | Session ids for all active connections may also be listed with the 76 | netstat\-like utility \f[B]tcnetstat\f[](8). 77 | .PP 78 | Connection peers may ensure they are communicating securely with each 79 | other (enjoying confidentiality and integrity in the face of active 80 | network attackers) by confirming that the \f[I]tcpcrypt\f[] session ids 81 | derived at each end are identical. 82 | For example, they may bind the session id together with a shared secret 83 | such as a password, sign it with public keys, use a voice connection to 84 | speak a fingerprint of it, or simply record it for later confirmation. 85 | .SH SEE ALSO 86 | .PP 87 | \f[B]tcnetstat\f[](8), 88 | -------------------------------------------------------------------------------- /src/crypto_rsa.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "inc.h" 12 | #include "util.h" 13 | #include "tcpcrypt_ctl.h" 14 | #include "tcpcrypt.h" 15 | #include "tcpcryptd.h" 16 | #include "crypto.h" 17 | #include "profile.h" 18 | 19 | #define KEYLEN 4096 20 | #define LENM (KEYLEN / 8) 21 | #define RSA_EXPONENT 3 22 | 23 | struct key { 24 | RSA *k_rsa; 25 | int k_len; 26 | int k_blen; 27 | void *k_bin; 28 | }; 29 | 30 | static struct state { 31 | struct key s_key; 32 | } _state; 33 | 34 | struct rsa_priv { 35 | struct key *r_key; 36 | RSA *r_rsa; 37 | }; 38 | 39 | static RSA* generate_key(int bits) 40 | { 41 | RSA* r; 42 | 43 | xprintf(XP_DEFAULT, "Generating RSA key: %d bits\n", bits); 44 | r = RSA_generate_key(bits, RSA_EXPONENT, NULL, NULL); 45 | if (!r) 46 | errssl(1, "RSA_generate_key()"); 47 | 48 | return r; 49 | } 50 | 51 | static void generate_keys(void) 52 | { 53 | struct key *k = &_state.s_key; 54 | 55 | xprintf(XP_DEFAULT, "Generating RSA key\n"); 56 | 57 | if (k->k_rsa) { 58 | RSA_free(k->k_rsa); 59 | free(k->k_bin); 60 | } 61 | 62 | k->k_len = KEYLEN; 63 | k->k_rsa = generate_key(k->k_len); 64 | k->k_blen = BN_num_bytes(k->k_rsa->n); 65 | k->k_bin = xmalloc(k->k_blen); 66 | BN_bn2bin(k->k_rsa->n, k->k_bin); 67 | 68 | xprintf(XP_DEFAULT, "Done generating RSA key\n"); 69 | } 70 | 71 | static struct key *get_key(void) 72 | { 73 | return &_state.s_key; 74 | } 75 | 76 | static void rsa_destroy(struct crypt *c) 77 | { 78 | struct rsa_priv *tp = crypt_priv(c); 79 | 80 | if (!tp) 81 | return; 82 | 83 | if (tp->r_rsa) { 84 | tp->r_rsa->e = NULL; 85 | RSA_free(tp->r_rsa); 86 | } 87 | 88 | free(tp); 89 | free(c); 90 | } 91 | 92 | static int rsa_encrypt(struct crypt *c, void *iv, void *data, int len) 93 | { 94 | struct rsa_priv *tp = crypt_priv(c); 95 | int sz = RSA_size(tp->r_rsa); 96 | void *out = alloca(sz); 97 | 98 | profile_add(1, "pre pkey encrypt"); 99 | 100 | if (RSA_public_encrypt(len, data, out, tp->r_rsa, 101 | RSA_PKCS1_OAEP_PADDING) == -1) 102 | errssl(1, "RSA_public_encrypt()"); 103 | 104 | profile_add(1, "post pkey encrypt"); 105 | 106 | memcpy(data, out, sz); 107 | 108 | return sz; 109 | } 110 | 111 | static int rsa_decrypt(struct crypt *c, void *iv, void *data, int len) 112 | { 113 | struct rsa_priv *tp = crypt_priv(c); 114 | void *out = alloca(len); 115 | int rc; 116 | 117 | if (_conf.cf_rsa_client_hack) 118 | assert(!"not implemented"); 119 | 120 | profile_add(1, "pre pkey decrypt"); 121 | 122 | rc = RSA_private_decrypt(len, data, out, tp->r_key->k_rsa, 123 | RSA_PKCS1_OAEP_PADDING); 124 | if (rc == -1) 125 | errssl(1, "RSA_private_decrypt()"); 126 | 127 | profile_add(1, "post pkey decrypt"); 128 | 129 | memcpy(data, out, rc); 130 | 131 | return rc; 132 | } 133 | 134 | static int rsa_get_key(struct crypt *c, void **out) 135 | { 136 | struct rsa_priv *tp = crypt_priv(c); 137 | struct key *k; 138 | 139 | k = tp->r_key = get_key(); 140 | *out = k->k_bin; 141 | 142 | return k->k_blen; 143 | } 144 | 145 | static int rsa_set_key(struct crypt *c, void *key, int len) 146 | { 147 | struct rsa_priv *tp = crypt_priv(c); 148 | BIGNUM *pub; 149 | int plen; 150 | RSA* r; 151 | 152 | tp->r_rsa = r = RSA_new(); 153 | if (!r) 154 | return -1; 155 | 156 | r->n = pub = BN_bin2bn(key, len, NULL); 157 | if (!pub) 158 | return -1; 159 | 160 | plen = BN_num_bits(pub); 161 | if (plen % LENM) 162 | return -1; 163 | 164 | r->e = get_key()->k_rsa->e; 165 | 166 | return 0; 167 | } 168 | 169 | struct crypt *crypt_RSA_new(void) 170 | { 171 | struct rsa_priv *r; 172 | struct crypt *c; 173 | static int init = 0; 174 | 175 | c = crypt_init(sizeof(*r)); 176 | c->c_destroy = rsa_destroy; 177 | c->c_set_key = rsa_set_key; 178 | c->c_get_key = rsa_get_key; 179 | c->c_encrypt = rsa_encrypt; 180 | c->c_decrypt = rsa_decrypt; 181 | 182 | r = crypt_priv(c); 183 | 184 | /* XXX have tcpcrypt call this and renew keys */ 185 | if (!init) { 186 | generate_keys(); 187 | init = 1; 188 | } 189 | 190 | return c; 191 | } 192 | -------------------------------------------------------------------------------- /src/crypto_ecdhe.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "inc.h" 15 | #include "util.h" 16 | #include "tcpcrypt_ctl.h" 17 | #include "tcpcrypt.h" 18 | #include "tcpcryptd.h" 19 | #include "crypto.h" 20 | #include "profile.h" 21 | 22 | struct ecdhe_priv { 23 | EC_KEY *ec_key; 24 | EC_KEY *ec_peer; 25 | void *ec_bin; 26 | int ec_bin_len; 27 | int ec_nid; 28 | }; 29 | 30 | static int set_peer_key(struct crypt *c, void *key, int len) 31 | { 32 | struct ecdhe_priv *p = crypt_priv(c); 33 | EC_KEY *k; 34 | uint16_t *klen = key; 35 | const unsigned char *kk = (unsigned char*) (klen + 1); 36 | 37 | if (len < sizeof(*klen)) 38 | return -1; 39 | 40 | if (ntohs(*klen) != len) 41 | return -1; 42 | 43 | len -= sizeof(*klen); 44 | 45 | k = EC_KEY_new_by_curve_name(p->ec_nid); 46 | assert(k); 47 | 48 | k = o2i_ECPublicKey(&k, &kk, len); 49 | if (!k) 50 | return -1; 51 | 52 | p->ec_peer = k; 53 | 54 | return 0; 55 | } 56 | 57 | static void ecdhe_destroy(struct crypt *c) 58 | { 59 | struct ecdhe_priv *tp = crypt_priv(c); 60 | 61 | if (!tp) 62 | return; 63 | 64 | if (tp->ec_key) 65 | EC_KEY_free(tp->ec_key); 66 | 67 | if (tp->ec_peer) 68 | EC_KEY_free(tp->ec_peer); 69 | 70 | if (tp->ec_bin) 71 | free(tp->ec_bin); 72 | 73 | free(tp); 74 | free(c); 75 | } 76 | 77 | static int ecdhe_compute_key(struct crypt *c, void *out) 78 | { 79 | struct ecdhe_priv *ec = crypt_priv(c); 80 | 81 | return ECDH_compute_key(out, 1024, 82 | EC_KEY_get0_public_key(ec->ec_peer), 83 | ec->ec_key, NULL); 84 | } 85 | 86 | /* XXX - factor out in tcpcrypt.c? call this kxs? */ 87 | static int ecdhe_encrypt(struct crypt *c, void *iv, void *data, int len) 88 | { 89 | struct ecdhe_priv *tp = crypt_priv(c); 90 | unsigned char *p = data; 91 | 92 | p += len; 93 | 94 | memcpy(p, tp->ec_bin, tp->ec_bin_len); 95 | 96 | p += tp->ec_bin_len; 97 | 98 | return (unsigned long) p - (unsigned long) data; 99 | } 100 | 101 | /* XXX same as above */ 102 | static int ecdhe_decrypt(struct crypt *c, void *iv, void *data, int len) 103 | { 104 | unsigned char *p = data; 105 | int nonce_len = 32; 106 | 107 | p += nonce_len; 108 | 109 | len -= (unsigned long) p - (unsigned long) data; 110 | if (len <= 0) 111 | return -1; 112 | 113 | if (set_peer_key(c, p, len) == -1) 114 | return -1; 115 | 116 | return ecdhe_compute_key(c, data); 117 | } 118 | 119 | static int ecdhe_get_key(struct crypt *c, void **out) 120 | { 121 | struct ecdhe_priv *p = crypt_priv(c); 122 | 123 | *out = p->ec_bin; 124 | 125 | return p->ec_bin_len; 126 | } 127 | 128 | static int ecdhe_set_key(struct crypt *c, void *key, int len) 129 | { 130 | return set_peer_key(c, key, len); 131 | } 132 | 133 | static struct crypt *crypt_ECDHE_new(int nid) 134 | { 135 | struct ecdhe_priv *r; 136 | struct crypt *c; 137 | unsigned char *p; 138 | uint16_t *len; 139 | 140 | c = crypt_init(sizeof(*r)); 141 | c->c_destroy = ecdhe_destroy; 142 | c->c_get_key = ecdhe_get_key; 143 | c->c_set_key = ecdhe_set_key; 144 | c->c_encrypt = ecdhe_encrypt; 145 | c->c_decrypt = ecdhe_decrypt; 146 | c->c_compute_key = ecdhe_compute_key; 147 | 148 | r = crypt_priv(c); 149 | 150 | r->ec_nid = nid; 151 | 152 | if (!(r->ec_key = EC_KEY_new_by_curve_name(r->ec_nid))) 153 | errx(1, "unknown curve nid %d", nid); 154 | 155 | if (EC_KEY_generate_key(r->ec_key) != 1) 156 | errx(1, "EC_KEY_generate_key()"); 157 | 158 | r->ec_bin_len = i2o_ECPublicKey(r->ec_key, NULL); 159 | assert(r->ec_bin_len > 0); 160 | 161 | /* prefix it with length */ 162 | r->ec_bin_len += sizeof(*len); 163 | len = r->ec_bin = xmalloc(r->ec_bin_len); 164 | 165 | *len++ = htons(r->ec_bin_len); 166 | 167 | p = (unsigned char*) len; 168 | i2o_ECPublicKey(r->ec_key, &p); 169 | 170 | return c; 171 | } 172 | 173 | struct crypt *crypt_ECDHE256_new(void) 174 | { 175 | return crypt_ECDHE_new(NID_X9_62_prime256v1); 176 | } 177 | 178 | struct crypt *crypt_ECDHE521_new(void) 179 | { 180 | return crypt_ECDHE_new(NID_secp521r1); 181 | } 182 | -------------------------------------------------------------------------------- /launchers/TcpcryptLauncher/Classes/TCTcpcryptController.m: -------------------------------------------------------------------------------- 1 | #import "TCTcpcryptController.h" 2 | #include 3 | #include 4 | #include 5 | 6 | @interface TCTcpcryptController () 7 | - (BOOL)daemonIsRunning; 8 | - (NSString *)daemonStatus; 9 | - (void)refreshDaemonStatus; 10 | - (void)checkPermissions; 11 | @end 12 | 13 | @implementation TCTcpcryptController 14 | 15 | //////////////////////////////////////////////////////////////////////////////////////// 16 | #pragma mark NSObject 17 | 18 | - (id)init { 19 | if ((self = [super init])) { 20 | _wrapperPath = [[[NSBundle mainBundle] pathForResource:@"tcpcryptd_wrapper" ofType:@""] retain]; 21 | _tcpcryptdPath = [[[NSBundle mainBundle] pathForResource:@"tcpcryptd" ofType:@""] retain]; 22 | } 23 | return self; 24 | } 25 | 26 | - (void)dealloc { 27 | [self stopDaemon:nil]; 28 | [_wrapperPath release]; 29 | [_tcpcryptdPath release]; 30 | [super dealloc]; 31 | } 32 | 33 | #pragma mark NSWindowDelegate 34 | 35 | - (void)windowWillClose:(NSNotification *)notification { 36 | [self stopDaemon:nil]; 37 | [[NSApplication sharedApplication] terminate:nil]; 38 | } 39 | 40 | #pragma mark - 41 | 42 | - (void)fixPermissionsForFile:(NSString *)path_ setUIDRoot:(BOOL)setUIDRoot { 43 | int fd, ret; 44 | mode_t mode; 45 | struct stat st; 46 | const char *path = [path_ cStringUsingEncoding:NSUTF8StringEncoding]; 47 | AuthorizationRef authRef; 48 | OSStatus status; 49 | 50 | fd = open(path, O_NOFOLLOW); 51 | NSAssert(fd != -1, @"open(%s)", path); 52 | 53 | ret = fstat(fd, &st); 54 | NSAssert(ret != -1, @"fstat(%s)", path); 55 | 56 | // chmod 57 | mode = 0755 | S_IFREG; 58 | if (setUIDRoot) mode = mode | S_ISUID; 59 | if (st.st_mode != mode) { 60 | NSLog(@"%@ is 0%o, will set to 0%o", path_, st.st_mode, mode); 61 | if (st.st_uid == 0) { 62 | NSLog(@"lost perms but kept root ownership of %@", path_); 63 | } 64 | ret = fchmod(fd, mode); 65 | NSAssert(ret != -1, @"fchmod()"); 66 | } 67 | 68 | // chown root 69 | if (st.st_uid != 0) { 70 | const char *args[] = {"root", path, NULL}; 71 | status = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, 72 | kAuthorizationFlagDefaults, &authRef); 73 | status = AuthorizationExecuteWithPrivileges(authRef, "/usr/sbin/chown", kAuthorizationFlagDefaults, 74 | (char *const *)args, NULL); 75 | NSAssert(status != -1, @"chown"); 76 | } 77 | 78 | close(fd); 79 | } 80 | 81 | - (void)checkPermissions { 82 | [self fixPermissionsForFile:_wrapperPath setUIDRoot:YES]; 83 | [self fixPermissionsForFile:_tcpcryptdPath setUIDRoot:NO]; 84 | } 85 | 86 | - (IBAction)startDaemon:(id)sender { 87 | NSLog(@"starting tcpcryptd..."); 88 | NSAssert(![self daemonIsRunning], @"tcpcryptd already started"); 89 | 90 | [self checkPermissions]; 91 | usleep(50000); /* file perms weren't getting set? */ 92 | _daemon = [[NSTask launchedTaskWithLaunchPath:_wrapperPath 93 | arguments:[NSArray arrayWithObject:@"start"]] retain]; 94 | NSLog(@"started tcpcryptd, pid %u", [_daemon processIdentifier]); 95 | NSAssert([self daemonIsRunning], @"failed to start tcpcryptd"); 96 | [self refreshDaemonStatus]; 97 | } 98 | 99 | - (IBAction)stopDaemon:(id)sender { 100 | NSLog(@"stopping tcpcryptd..."); 101 | 102 | NSTask *stopper = [NSTask launchedTaskWithLaunchPath:_wrapperPath 103 | arguments:[NSArray arrayWithObject:@"stop"]]; 104 | 105 | [stopper waitUntilExit]; 106 | NSLog(@"stopped tcpcryptd"); 107 | NSAssert(![self daemonIsRunning], @"failed to stop tcpcryptd"); 108 | if (_daemon) { 109 | [_daemon release]; 110 | _daemon = nil; 111 | } 112 | [self refreshDaemonStatus]; 113 | } 114 | 115 | - (BOOL)daemonIsRunning { 116 | return _daemon && [_daemon isRunning]; 117 | } 118 | 119 | - (NSString *)daemonStatus { 120 | return [self daemonIsRunning] ? @"Tcpcrypt is running on ports 80 (http) and 7777." : 121 | @"Tcpcrypt is off."; 122 | } 123 | 124 | - (void)refreshDaemonStatus { 125 | [_startButton setHidden:[self daemonIsRunning]]; 126 | [_stopButton setHidden:![self daemonIsRunning]]; 127 | [_testButton setHidden:![self daemonIsRunning]]; 128 | [_statusLabel setStringValue:[self daemonStatus]]; 129 | } 130 | 131 | - (IBAction)openTestPage:(id)sender { 132 | [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://tcpcrypt.org/fame.php"]]; 133 | } 134 | 135 | @end 136 | -------------------------------------------------------------------------------- /launchers/TcpcryptLauncher/tcpcryptd_wrapper.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | void setup_ipfw_rules(); 13 | void run_tcpcryptd(char *); 14 | void stop_tcpcryptd(); 15 | void teardown_ipfw_rules(); 16 | 17 | static const char *pidfile = "/private/tmp/tcpcrypt.pid"; 18 | 19 | static char work_dir[4096]; 20 | 21 | void setup_ipfw_rules() { 22 | char pf[4096]; 23 | char *ipfw_cmds[] = { 24 | "mkdir -p /var/run/tcpcryptd", 25 | "dscl . create /Users/tcpcryptd UniqueID 666", 26 | "dscl . create /Users/tcpcryptd PrimaryGroupID 666", 27 | pf, 28 | NULL 29 | }; 30 | int i; 31 | 32 | snprintf(pf, sizeof(pf), "pfctl -Fa -e -f %s/pf.conf", work_dir); 33 | 34 | printf("Setting up ipfw rules...\n"); 35 | for (i = 0; ipfw_cmds[i] != NULL; ++i) { 36 | if (system(ipfw_cmds[i])) 37 | err(1, "%s", ipfw_cmds[i]); 38 | } 39 | } 40 | 41 | void run_tcpcryptd(char *my_argv0) { 42 | int fd; 43 | FILE *file; 44 | struct stat st; 45 | char tcpcryptd[4096]; 46 | 47 | /* stop tcpcryptd if it's running */ 48 | stop_tcpcryptd(); 49 | 50 | /* save pid */ 51 | fd = open(pidfile, O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW, 0600); 52 | if (fd == -1) 53 | err(1, "open()"); 54 | if (fstat(fd, &st) == -1) 55 | err(1, "fstat()"); 56 | if (!(st.st_mode & S_IFREG)) 57 | errx(1, "pidfile not regular file"); 58 | if (fchmod(fd, 0600) == -1) 59 | err(1, "fchmod()"); 60 | if (fchown(fd, 0, 0) == -1) 61 | err(1, "fchown()"); 62 | if (!(file = fdopen(fd, "w"))) 63 | err(1, "fdopen()"); 64 | if (fprintf(file, "%d", getpid()) < 1) 65 | err(1, "fprintf()"); 66 | if (fclose(file)) 67 | err(1, "fclose()"); 68 | 69 | snprintf(tcpcryptd, sizeof(tcpcryptd), "%s/tcpcryptd", work_dir); 70 | 71 | printf("Starting tcpcryptd...\n"); 72 | if (execl(tcpcryptd, "tcpcryptd", "-e", "-u", ":65531", NULL) == -1) 73 | err(1, "execve()"); 74 | } 75 | 76 | void stop_tcpcryptd() { 77 | struct stat st; 78 | int fd; 79 | FILE *file; 80 | pid_t tcpcryptd_pid; 81 | 82 | fd = open(pidfile, O_RDONLY | O_NOFOLLOW); 83 | if (fd == -1) { 84 | if (errno == ENOENT) { 85 | return; 86 | } else { 87 | err(1, "open()"); 88 | } 89 | } 90 | 91 | if (fstat(fd, &st) == -1) 92 | err(1, "fstat()"); 93 | 94 | /* check pidfile perms/attrs are safe */ 95 | int regfile = st.st_mode & S_IFREG; 96 | int rootowned = st.st_uid == 0 && st.st_gid == 0; 97 | int othernorw = (st.st_mode & (S_IRWXG | S_IRWXO)) == 0; 98 | if (!regfile || !rootowned || !othernorw) 99 | errx(1, "bad perms/attrs on pidfile"); 100 | 101 | /* unlink pidfile */ 102 | if (fchmod(fd, 0600) == -1) 103 | err(1, "fchmod()"); 104 | if (fchown(fd, 0, 0) == -1) 105 | err(1, "fchown()"); 106 | if (unlink(pidfile) == -1) 107 | err(1, "unlink()"); 108 | 109 | if (!(file = fdopen(fd, "r"))) 110 | err(1, "fdopen()"); 111 | if (fscanf(file, "%d", &tcpcryptd_pid) != 1) 112 | errx(1, "fscanf: no pid"); 113 | 114 | if (tcpcryptd_pid <= 0) 115 | errx(1, "invalid pid %d", tcpcryptd_pid); 116 | 117 | if (kill(tcpcryptd_pid, SIGTERM) == -1) 118 | err(1, "kill(%d)", tcpcryptd_pid); 119 | 120 | if (fclose(file) != 0) 121 | err(1, "fclose()"); 122 | } 123 | 124 | void teardown_ipfw_rules() { 125 | static char *cmd = "pfctl -d"; 126 | 127 | printf("Restoring ipfw to previous configuration..."); 128 | if (system(cmd)) 129 | warn("ipfw warning: %s", cmd); 130 | printf("OK\n"); 131 | } 132 | 133 | int main(int argc, char **argv) { 134 | static char *start = "start", *stop = "stop"; 135 | char *action = argv[1]; 136 | char *p; 137 | 138 | snprintf(work_dir, sizeof(work_dir), "%s", argv[0]); 139 | p = strrchr(work_dir, '/'); 140 | if (p) 141 | *p = 0; 142 | 143 | printf("Work dir: [%s]\n", work_dir); 144 | 145 | if (setuid(0) != 0) { 146 | printf("must be root\n"); 147 | exit(1); 148 | } 149 | 150 | if (strncmp(action, start, strlen(start)) == 0) { 151 | setup_ipfw_rules(); 152 | run_tcpcryptd(argv[0]); 153 | } else if (strncmp(action, stop, strlen(stop)) == 0) { 154 | teardown_ipfw_rules(); 155 | stop_tcpcryptd(); 156 | } else { 157 | printf("usage: %s start|stop\n", argv[0]); 158 | exit(1); 159 | } 160 | 161 | return 0; 162 | } 163 | -------------------------------------------------------------------------------- /src/crypto.h: -------------------------------------------------------------------------------- 1 | #ifndef __TCPCRYPT_CRYPTO_H__ 2 | #define __TCPCRYPT_CRYPTO_H__ 3 | 4 | typedef void *(*crypt_ctr)(void); 5 | 6 | enum { 7 | TYPE_PKEY = 0, 8 | TYPE_SYM, 9 | }; 10 | 11 | struct cipher_list { 12 | uint8_t c_id; 13 | int c_type; 14 | crypt_ctr c_ctr; 15 | struct cipher_list *c_next; 16 | }; 17 | 18 | extern struct cipher_list *crypt_cipher_list(void); 19 | 20 | /* low-level interface */ 21 | 22 | struct crypt { 23 | void *c_priv; 24 | void (*c_destroy)(struct crypt *c); 25 | int (*c_set_key)(struct crypt *c, void *key, int len); 26 | int (*c_get_key)(struct crypt *c, void **out); 27 | void (*c_mac)(struct crypt *, const struct iovec *iov, int num, void *out, 28 | int *outlen); 29 | void (*c_extract)(struct crypt *c, struct iovec *iov, int num, 30 | void *out, int *outlen); 31 | void (*c_expand)(struct crypt *c, void *tag, int taglen, 32 | void *out, int outlen); 33 | int (*c_encrypt)(struct crypt *c, void *iv, void *data, int len); 34 | int (*c_decrypt)(struct crypt *c, void *iv, void *data, int len); 35 | int (*c_aead_encrypt)(struct crypt *c, void *iv, void *aad, 36 | int aadlen, void *data, int dlen, void *tag); 37 | int (*c_aead_decrypt)(struct crypt *c, void *iv, void *aad, 38 | int aadlen, void *data, int dlen, void *tag); 39 | int (*c_compute_key)(struct crypt *c, void *out); 40 | }; 41 | 42 | extern struct crypt *crypt_HMAC_SHA256_new(void); 43 | extern struct crypt *crypt_HKDF_SHA256_new(void); 44 | extern struct crypt *crypt_AES128_new(void); 45 | extern struct crypt *crypt_AES256_new(void); 46 | extern struct crypt *crypt_RSA_new(void); 47 | extern struct crypt *crypt_ECDHE256_new(void); 48 | extern struct crypt *crypt_ECDHE521_new(void); 49 | 50 | extern struct crypt *crypt_init(int sz); 51 | extern void crypt_register(int type, uint8_t id, crypt_ctr ctr); 52 | extern struct cipher_list *crypt_find_cipher(int type, unsigned int id); 53 | 54 | static inline void crypt_destroy(struct crypt *c) 55 | { 56 | c->c_destroy(c); 57 | } 58 | 59 | static inline int crypt_set_key(struct crypt *c, void *key, int len) 60 | { 61 | return c->c_set_key(c, key, len); 62 | } 63 | 64 | static inline int crypt_get_key(struct crypt *c, void **out) 65 | { 66 | return c->c_get_key(c, out); 67 | } 68 | 69 | static inline void crypt_mac(struct crypt *c, struct iovec *iov, int num, 70 | void *out, int *outlen) 71 | { 72 | c->c_mac(c, iov, num, out, outlen); 73 | } 74 | 75 | static inline void *crypt_priv(struct crypt *c) 76 | { 77 | return c->c_priv; 78 | } 79 | 80 | static inline void crypt_extract(struct crypt *c, struct iovec *iov, int num, 81 | void *out, int *outlen) 82 | { 83 | c->c_extract(c, iov, num, out, outlen); 84 | } 85 | 86 | static inline void crypt_expand(struct crypt *c, void *tag, int taglen, 87 | void *out, int outlen) 88 | { 89 | c->c_expand(c, tag, taglen, out, outlen); 90 | } 91 | 92 | static inline int crypt_encrypt(struct crypt *c, void *iv, void *data, int len) 93 | { 94 | return c->c_encrypt(c, iv, data, len); 95 | } 96 | 97 | static inline int crypt_decrypt(struct crypt *c, void *iv, void *data, int len) 98 | { 99 | return c->c_decrypt(c, iv, data, len); 100 | } 101 | 102 | static inline int crypt_compute_key(struct crypt *c, void *out) 103 | { 104 | return c->c_compute_key(c, out); 105 | } 106 | 107 | static inline void *crypt_new(crypt_ctr ctr) 108 | { 109 | crypt_ctr *r = ctr(); 110 | 111 | *r = ctr; 112 | 113 | return r; 114 | } 115 | 116 | /* pub crypto */ 117 | 118 | struct crypt_pub { 119 | crypt_ctr cp_ctr; /* must be first */ 120 | struct crypt *cp_hkdf; 121 | struct crypt *cp_pub; 122 | int cp_n_c; 123 | int cp_n_s; 124 | int cp_k_len; 125 | int cp_min_key; 126 | int cp_max_key; 127 | int cp_cipher_len; 128 | int cp_key_agreement; 129 | }; 130 | 131 | static inline void crypt_pub_destroy(struct crypt_pub *cp) 132 | { 133 | crypt_destroy(cp->cp_hkdf); 134 | crypt_destroy(cp->cp_pub); 135 | free(cp); 136 | } 137 | 138 | /* sym crypto */ 139 | 140 | struct crypt_sym { 141 | crypt_ctr cs_ctr; /* must be first */ 142 | struct crypt *cs_cipher; 143 | struct crypt *cs_mac; 144 | struct crypt *cs_ack_mac; 145 | int cs_mac_len; 146 | int cs_key_len; 147 | int cs_iv_len; 148 | }; 149 | 150 | static inline void crypt_sym_destroy(struct crypt_sym *cs) 151 | { 152 | crypt_destroy(cs->cs_cipher); 153 | crypt_destroy(cs->cs_mac); 154 | crypt_destroy(cs->cs_ack_mac); 155 | free(cs); 156 | } 157 | 158 | #endif /* __TCPCRYPT_CRYPTO_H__ */ 159 | -------------------------------------------------------------------------------- /launch_tcpcryptd.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | BASE=`dirname $0` 4 | TCPCRYPTD=$BASE/src/tcpcryptd 5 | DIVERT_PORT=666 6 | PIDFILE=/var/run/tcpcrypt.pid 7 | JAIL_DIR=/var/run/tcpcryptd 8 | DAEMON_USER=tcpcryptd 9 | 10 | OSNAME=`uname -s` 11 | 12 | if [ "$OSNAME" = "Linux" ] 13 | then 14 | # set either ONLY_PORTS or OMIT_PORTS, in a manner acceptable to the 15 | # "multiport" extension. see iptables-extensions(8) 16 | 17 | # EITHER enable specific ports: 18 | # ONLY_PORTS="80,7777" 19 | 20 | # OR exclude already-encrypted services: 21 | OMIT_PORTS="22,261,443,563,614,636,684,695,989,990,992:995" 22 | else 23 | # for ipfw users: 24 | PORT=${1:-80} 25 | PORT2=${2:-7777} 26 | fi 27 | 28 | start_tcpcryptd() { 29 | LD_LIBRARY_PATH=lib/ $TCPCRYPTD \ 30 | -U $DAEMON_USER \ 31 | -J $JAIL_DIR \ 32 | -p $DIVERT_PORT \ 33 | -e \ 34 | -f \ 35 | $OPTS & 36 | echo $! > $PIDFILE 37 | wait $! 38 | } 39 | 40 | init_jail() { 41 | if [ ! -d "$JAIL_DIR" ] 42 | then 43 | echo "Creating jail directory $JAIL_DIR" 44 | (umask 077 && mkdir $JAIL_DIR) 45 | fi 46 | 47 | id $DAEMON_USER >/dev/null 2>&1 48 | if [ $? -ne 0 ] 49 | then 50 | echo "Creating user and group '$DAEMON_USER'" 51 | 52 | if [ "$OSNAME" = "Darwin" ] ; then 53 | dscl . create /Users/tcpcryptd UniqueID 666 54 | dscl . create /Users/tcpcryptd PrimaryGroupID 666 55 | else 56 | useradd -s /usr/bin/nologin -d / -M -U $DAEMON_USER 57 | fi 58 | fi 59 | } 60 | 61 | ee() { 62 | echo $* 63 | eval $* 64 | } 65 | 66 | set_iptables() { 67 | export DAEMON_USER DIVERT_PORT ONLY_PORTS OMIT_PORTS 68 | $BASE/src/iptables.sh start 69 | if [ $? -ne 0 ] 70 | then 71 | echo "Couldn't set iptables" >&2 72 | exit 1 73 | fi 74 | } 75 | 76 | unset_iptables() { 77 | echo Removing iptables rules and quitting tcpcryptd... 78 | 79 | export DAEMON_USER DIVERT_PORT ONLY_PORTS OMIT_PORTS 80 | $BASE/src/iptables.sh stop 81 | 82 | exit 83 | } 84 | 85 | bsd_set_ipfw() { 86 | if [ "$OSNAME" = "Darwin" ] ; then 87 | pfctl -Fa -e -f $BASE/src/pf.conf 88 | return 89 | fi 90 | 91 | echo Tcpcrypting port 80 and 7777... 92 | ipfw 02 add divert $DIVERT_PORT tcp from any to any $PORT 93 | ipfw 03 add divert $DIVERT_PORT tcp from any $PORT to any 94 | ipfw 04 add divert $DIVERT_PORT tcp from any to any $PORT2 95 | ipfw 05 add divert $DIVERT_PORT tcp from any $PORT2 to any 96 | } 97 | 98 | bsd_unset_ipfw() { 99 | echo Removing ipfw rules and quitting tcpcryptd... 100 | 101 | if [ "$OSNAME" = "Darwin" ] ; then 102 | pfctl -Fa -d 103 | return 104 | fi 105 | 106 | ipfw delete 02 03 04 05 107 | exit 108 | } 109 | 110 | win_start_tcpcryptd() { 111 | MAC_ADDR=`ipconfig /all | grep 'Physical Address'| head -n 1 | sed 's/\s*Physical Address\(\. \)*: \(.*\)/\2/' | sed 's/-/:/g'` 112 | echo Using MAC address $MAC_ADDR... 113 | LD_LIBRARY_PATH=lib/ $TCPCRYPTD $OPTS -p $DIVERT_PORT -x $MAC_ADDR & 114 | echo $! > $PIDFILE 115 | wait $! 116 | } 117 | 118 | check_root() { 119 | if [ `whoami` != "root" ] 120 | then 121 | echo "must be root" 122 | exit 1 123 | fi 124 | } 125 | 126 | check_ssh() { 127 | if [ -n "$SSH_CONNECTION" ] 128 | then 129 | read -p 'Command may disrupt existing ssh connections. Proceed? [y/N] ' C 130 | if [ "$C" != "y" ] 131 | then 132 | exit 1 133 | fi 134 | fi 135 | } 136 | 137 | check_existing_tcpcryptd() { 138 | P=`ps axo pid,comm | grep tcpcryptd` 139 | if [ $? -eq 0 ] 140 | then 141 | read -p "tcpcryptd already running with pid $P. Proceed? [y/N] " C 142 | if [ "$C" != "y" ] 143 | then 144 | exit 1 145 | fi 146 | fi 147 | } 148 | 149 | 150 | #check_ssh 151 | 152 | case "$OSNAME" in 153 | Linux) 154 | check_existing_tcpcryptd 155 | check_root 156 | init_jail 157 | set_iptables 158 | trap unset_iptables 2 # trap SIGINT to remove iptables rules before exit 159 | start_tcpcryptd 160 | unset_iptables 161 | ;; 162 | FreeBSD|Darwin) 163 | check_existing_tcpcryptd 164 | check_root 165 | init_jail 166 | bsd_set_ipfw 167 | trap bsd_unset_ipfw 2 168 | start_tcpcryptd 169 | bsd_unset_ipfw 170 | ;; 171 | [Cc][Yy][Gg][Ww][Ii][Nn]*) 172 | win_start_tcpcryptd 173 | ;; 174 | esac 175 | 176 | -------------------------------------------------------------------------------- /src/crypto_dummy.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "inc.h" 9 | #include "tcpcrypt_ctl.h" 10 | #include "tcpcrypt.h" 11 | #include "tcpcryptd.h" 12 | #include "crypto.h" 13 | 14 | #if 0 15 | #define MAC_SIZE 20 16 | 17 | static struct tc_cipher_spec _dummy_pkey_spec = 18 | { 0, TC_DUMMY }; 19 | 20 | static struct crypt_prop _dummy_pkey_prop = 21 | { 0, IVMODE_NONE, MAC_SIZE, 256 }; 22 | 23 | static struct tc_scipher _dummy_mac_spec = 24 | { TC_DUMMY }; 25 | 26 | static struct tc_scipher _dummy_sym_spec = 27 | { TC_DUMMY }; 28 | 29 | static void dummy_init(struct tc *tc) 30 | { 31 | } 32 | 33 | static void dummy_finish(struct tc *tc) 34 | { 35 | } 36 | 37 | static void dummy_mac(struct tc *tc, struct iovec *iov, int num, void *iv, 38 | void *out, int *outlen) 39 | { 40 | if (*outlen >= MAC_SIZE) 41 | memset(out, 0, MAC_SIZE); 42 | 43 | *outlen = MAC_SIZE; 44 | } 45 | 46 | static uint32_t *get_len(void *data) 47 | { 48 | uint32_t* x = (uint32_t*) ((unsigned long) data 49 | + _dummy_pkey_prop.cp_cipherlen); 50 | 51 | return --x; 52 | } 53 | 54 | static void dummy_pkey_encrypt(struct tc *tc, void *iv, void *data, int len) 55 | { 56 | uint32_t *l = get_len(data); 57 | 58 | assert(len + 4 <= _dummy_pkey_prop.cp_cipherlen); 59 | 60 | *l = htonl(len); 61 | } 62 | 63 | static int dummy_pkey_decrypt(struct tc *tc, void *iv, void *data, int len) 64 | { 65 | uint32_t *l = get_len(data); 66 | 67 | assert(len == _dummy_pkey_prop.cp_cipherlen); 68 | 69 | return htonl(*l); 70 | } 71 | 72 | static void dummy_encrypt(struct tc *tc, void *iv, void *data, int len) 73 | { 74 | } 75 | 76 | static int dummy_decrypt(struct tc *tc, void *iv, void *data, int len) 77 | { 78 | return len; 79 | } 80 | 81 | static int dummy_get_key(struct tc *tc, void **out) 82 | { 83 | static int len = 128; 84 | static void *key; 85 | 86 | if (!key) 87 | key = xmalloc(len); 88 | 89 | *out = key; 90 | 91 | return len; 92 | } 93 | 94 | static void *dummy_pkey_spec(void) 95 | { 96 | return &_dummy_pkey_spec; 97 | } 98 | 99 | static int dummy_pkey_type(void) 100 | { 101 | return TYPE_PKEY; 102 | } 103 | 104 | static int dummy_set_key(struct tc *tc, void *key, int len) 105 | { 106 | return 4; 107 | } 108 | 109 | static void dummy_mac_set_key(struct tc *tc, void *key, int len) 110 | { 111 | } 112 | 113 | struct crypt_prop *dummy_pkey_prop(struct tc *tc) 114 | { 115 | return &_dummy_pkey_prop; 116 | } 117 | 118 | static int dummy_mac_type(void) 119 | { 120 | return TYPE_MAC; 121 | } 122 | 123 | static int dummy_sym_type(void) 124 | { 125 | return TYPE_SYM; 126 | } 127 | 128 | static void *dummy_mac_spec(void) 129 | { 130 | return &_dummy_mac_spec; 131 | } 132 | 133 | static void *dummy_sym_spec(void) 134 | { 135 | return &_dummy_sym_spec; 136 | } 137 | 138 | static void dummy_next_iv(struct tc *tc, void *out, int *outlen) 139 | { 140 | assert(*outlen == 0); 141 | 142 | *outlen = 0; 143 | } 144 | 145 | static struct crypt_ops _dummy_pkey = { 146 | .co_init = dummy_init, 147 | .co_finish = dummy_finish, 148 | .co_encrypt = dummy_pkey_encrypt, 149 | .co_decrypt = dummy_pkey_decrypt, 150 | .co_get_key = dummy_get_key, 151 | .co_spec = dummy_pkey_spec, 152 | .co_type = dummy_pkey_type, 153 | .co_set_key = dummy_set_key, 154 | .co_mac_set_key = dummy_mac_set_key, 155 | .co_mac = dummy_mac, 156 | .co_crypt_prop = dummy_pkey_prop, 157 | }; 158 | 159 | static struct crypt_ops _dummy_sym = { 160 | .co_init = dummy_init, 161 | .co_finish = dummy_finish, 162 | .co_encrypt = dummy_encrypt, 163 | .co_decrypt = dummy_decrypt, 164 | .co_spec = dummy_sym_spec, 165 | .co_type = dummy_sym_type, 166 | .co_set_key = dummy_set_key, 167 | .co_next_iv = dummy_next_iv, 168 | }; 169 | 170 | static struct crypt_ops _dummy_mac = { 171 | .co_init = dummy_init, 172 | .co_finish = dummy_finish, 173 | .co_mac = dummy_mac, 174 | .co_spec = dummy_mac_spec, 175 | .co_type = dummy_mac_type, 176 | .co_set_key = dummy_set_key, 177 | }; 178 | 179 | static void __dummy_init(void) __attribute__ ((constructor)); 180 | 181 | static void __dummy_init(void) 182 | { 183 | crypto_register(&_dummy_pkey); 184 | crypto_register(&_dummy_sym); 185 | if (0) crypto_register(&_dummy_mac); 186 | } 187 | #endif 188 | -------------------------------------------------------------------------------- /contrib/umac.h: -------------------------------------------------------------------------------- 1 | /* ----------------------------------------------------------------------- 2 | * 3 | * umac.h -- C Implementation UMAC Message Authentication 4 | * 5 | * Version 0.90 of draft-krovetz-umac-03.txt -- 2004 October 6 | * 7 | * For a full description of UMAC message authentication see the UMAC 8 | * world-wide-web page at http://www.cs.ucdavis.edu/~rogaway/umac 9 | * Please report bugs and suggestions to the UMAC webpage. 10 | * 11 | * Copyright (c) 1999-2004 Ted Krovetz 12 | * 13 | * Permission to use, copy, modify, and distribute this software and 14 | * its documentation for any purpose and with or without fee, is hereby 15 | * granted provided that the above copyright notice appears in all copies 16 | * and in supporting documentation, and that the name of the copyright 17 | * holder not be used in advertising or publicity pertaining to 18 | * distribution of the software without specific, written prior permission. 19 | * 20 | * Comments should be directed to Ted Krovetz (tdk@acm.org) 21 | * 22 | * ---------------------------------------------------------------------- */ 23 | 24 | /* ////////////////////// IMPORTANT NOTES ///////////////////////////////// 25 | * 26 | * 1) This version does not work properly on messages larger than 16MB 27 | * 28 | * 2) If you set the switch to use SSE2, then all data must be 16-byte 29 | * aligned 30 | * 31 | * 3) When calling the function umac(), it is assumed that msg is in 32 | * a writable buffer of length divisible by 32 bytes. The message itself 33 | * does not have to fill the entire buffer, but bytes beyond msg may be 34 | * zeroed. 35 | * 36 | * 4) Two free AES implementations are supported by this implementation of 37 | * UMAC. Paulo Barreto's version is in the public domain and can be found 38 | * at http://www.esat.kuleuven.ac.be/~rijmen/rijndael/ (search for 39 | * "Barreto"). The only two files needed are rijndael-alg-fst.c and 40 | * rijndael-alg-fst.h. 41 | * Brian Gladman's version is distributed with GNU Public lisence 42 | * and can be found at http://fp.gladman.plus.com/AES/index.htm. It 43 | * includes a fast IA-32 assembly version. 44 | * 45 | /////////////////////////////////////////////////////////////////////// */ 46 | 47 | 48 | #ifdef __cplusplus 49 | extern "C" { 50 | #endif 51 | 52 | typedef struct umac_ctx *umac_ctx_t; 53 | 54 | umac_ctx_t umac_new(char key[]); 55 | /* Dynamically allocate a umac_ctx struct, initialize variables, 56 | * generate subkeys from key. 57 | */ 58 | 59 | int umac_reset(umac_ctx_t ctx); 60 | /* Reset a umac_ctx to begin authenicating a new message */ 61 | 62 | int umac_update(umac_ctx_t ctx, char *input, long len); 63 | /* Incorporate len bytes pointed to by input into context ctx */ 64 | 65 | int umac_final(umac_ctx_t ctx, char tag[], char nonce[8]); 66 | /* Incorporate any pending data and the ctr value, and return tag. 67 | * This function returns error code if ctr < 0. 68 | */ 69 | 70 | int umac_delete(umac_ctx_t ctx); 71 | /* Deallocate the context structure */ 72 | 73 | int umac(umac_ctx_t ctx, char *input, 74 | long len, char tag[], 75 | char nonce[8]); 76 | /* All-in-one implementation of the functions Reset, Update and Final */ 77 | 78 | 79 | /* uhash.h */ 80 | 81 | 82 | typedef struct uhash_ctx *uhash_ctx_t; 83 | /* The uhash_ctx structure is defined by the implementation of the */ 84 | /* UHASH functions. */ 85 | 86 | uhash_ctx_t uhash_alloc(char key[16]); 87 | /* Dynamically allocate a uhash_ctx struct and generate subkeys using */ 88 | /* the kdf and kdf_key passed in. If kdf_key_len is 0 then RC6 is */ 89 | /* used to generate key with a fixed key. If kdf_key_len > 0 but kdf */ 90 | /* is NULL then the first 16 bytes pointed at by kdf_key is used as a */ 91 | /* key for an RC6 based KDF. */ 92 | 93 | int uhash_free(uhash_ctx_t ctx); 94 | 95 | int uhash_set_params(uhash_ctx_t ctx, 96 | void *params); 97 | 98 | int uhash_reset(uhash_ctx_t ctx); 99 | 100 | int uhash_update(uhash_ctx_t ctx, 101 | char *input, 102 | long len); 103 | 104 | int uhash_final(uhash_ctx_t ctx, 105 | char ouput[]); 106 | 107 | int uhash(uhash_ctx_t ctx, 108 | char *input, 109 | long len, 110 | char output[]); 111 | 112 | #ifdef __cplusplus 113 | } 114 | #endif 115 | -------------------------------------------------------------------------------- /shared/socket_address.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "inc.h" 9 | #include "socket_address.h" 10 | 11 | int socket_address_is_null(const struct socket_address *sa) 12 | { 13 | return sa->addr_len == 0; 14 | } 15 | 16 | void socket_address_clear(struct socket_address *sa) 17 | { 18 | sa->addr_len = 0; 19 | } 20 | 21 | int socket_address_pretty(char *name, size_t size, const struct socket_address *sa) 22 | { 23 | size_t n = 0; 24 | 25 | if (sa->addr_len == 0) { 26 | n = snprintf(name, size, ""); 27 | } 28 | else { 29 | switch (sa->addr.sa.sa_family) { 30 | #ifndef __WIN32__ 31 | case AF_UNIX: 32 | { 33 | size_t path_len = sa->addr_len - sizeof(sa_family_t) - 1; 34 | if (path_len == 0) { 35 | n = snprintf(name, size, ""); 36 | } 37 | else if (sa->addr.un.sun_path[0] == '\0') { 38 | n = snprintf(name, size, ""); 39 | } 40 | else { 41 | n = path_len; 42 | if (n > size) 43 | n = size; 44 | strncpy(name, sa->addr.un.sun_path, n); 45 | if (n < size) 46 | name[n++] = '\0'; 47 | } 48 | break; 49 | } 50 | #endif /* __WIN32__ */ 51 | case AF_INET: 52 | n = snprintf(name, size, "%s:%d", 53 | inet_ntoa(sa->addr.in.sin_addr), 54 | (int) ntohs(sa->addr.in.sin_port)); 55 | break; 56 | default: 57 | n = snprintf(name, size, ""); 58 | } 59 | } 60 | 61 | return n; 62 | } 63 | 64 | const char *socket_address_pathname(const struct socket_address *sa) 65 | { 66 | if (socket_address_is_null(sa)) 67 | return NULL; 68 | 69 | #ifndef __WIN32__ 70 | if (sa->addr.sa.sa_family == AF_UNIX 71 | && sa->addr_len > 0 72 | && sa->addr.un.sun_path[0] == '/') 73 | return sa->addr.un.sun_path; 74 | #endif 75 | 76 | return NULL; 77 | } 78 | 79 | int resolve_socket_address_local(const char *descr, struct socket_address *sa, 80 | char *error, int error_len) 81 | { 82 | #define errx(...) \ 83 | { \ 84 | if (error) \ 85 | snprintf(error, error_len, __VA_ARGS__); \ 86 | return -1; \ 87 | } 88 | #define err(...) \ 89 | { \ 90 | if (error) { \ 91 | int n = snprintf(error, error_len, __VA_ARGS__); \ 92 | n += snprintf(error + n, error_len - n, ": "); \ 93 | strerror_r(errno, error + n, error_len - n); \ 94 | } \ 95 | return -1; \ 96 | }\ 97 | 98 | 99 | if (descr == NULL || descr[0] == '\0') 100 | errx("empty description"); 101 | 102 | #if 0 103 | /* not tested */ 104 | 105 | /* file descriptor */ 106 | if (descr[0] == '&') { 107 | int s, r; 108 | const char *fd_str = &descr[1]; 109 | 110 | s = atoi(fd_str); 111 | if (s <= 0) 112 | errx("couldn't parse file-descriptor number from '%s'", 113 | fd_str); 114 | 115 | r = getsockname(s, &sa->addr.sa, &sa->addr_len); 116 | if (r != 0) 117 | err("getsockname"); 118 | return 0; 119 | } 120 | #endif 121 | 122 | #ifndef __WIN32__ 123 | /* path to a unix-domain socket */ 124 | if (descr[0] == '/') { 125 | size_t path_len; 126 | struct sockaddr_un *sun = &sa->addr.un; 127 | 128 | path_len = strlen(descr); 129 | if (path_len + 1 > sizeof(sun->sun_path)) 130 | errx("unix-domain path too long"); 131 | memset(sun, 0, sizeof(*sun)); 132 | sun->sun_family = AF_UNIX; 133 | memcpy(&sun->sun_path, descr, path_len); 134 | 135 | sa->addr_len = offsetof(struct sockaddr_un, sun_path) 136 | + path_len + 1; 137 | return 0; 138 | } 139 | 140 | /* abstract unix-domain socket (linux) */ 141 | if (descr[0] == '@') { 142 | const char *name; 143 | size_t len; 144 | struct sockaddr_un *sun = &sa->addr.un; 145 | 146 | name = &descr[1]; 147 | /* include trailing null for readability */ 148 | len = strlen(name) + 1; 149 | 150 | if (len + 1 > sizeof(sun->sun_path)) 151 | errx("unix-domain path too long"); 152 | memset(sun, 0, sizeof(*sun)); 153 | sun->sun_family = AF_UNIX; 154 | sun->sun_path[0] = '\0'; 155 | memcpy(&sun->sun_path[1], name, len); 156 | 157 | /* length includes leading null, the text, and trailing null */ 158 | sa->addr_len = offsetof(struct sockaddr_un, sun_path) 159 | + 1 + len + 1; 160 | return 0; 161 | } 162 | #endif /* ! __WIN32__ */ 163 | 164 | /* port number at localhost */ 165 | if (descr[0] == ':') { 166 | unsigned long port; 167 | const char *port_str = &descr[1]; 168 | char *d = NULL; 169 | 170 | errno = 0; 171 | port = strtoul(port_str, &d, 10); 172 | if (d && *d == '\0' && !errno && port == (uint16_t) port) 173 | { 174 | struct sockaddr_in *sin = &sa->addr.in; 175 | 176 | memset(sin, 0, sizeof(*sin)); 177 | sin->sin_family = AF_INET; 178 | sin->sin_addr.s_addr = inet_addr("127.0.0.1"); 179 | sin->sin_port = htons((uint16_t) port); 180 | 181 | sa->addr_len = sizeof(*sin); 182 | return 0; 183 | } 184 | else { 185 | errx("couldn't parse port number from '%s'", port_str); 186 | } 187 | } 188 | 189 | errx("couldn't understand socket description"); 190 | return -1; 191 | } 192 | -------------------------------------------------------------------------------- /tests/hmac.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "inc.h" 5 | #include "crypto.h" 6 | 7 | 8 | 9 | struct testcase { 10 | const char* name; 11 | const struct iovec key; 12 | const struct iovec data; 13 | const struct iovec answer; 14 | }; 15 | 16 | /* Test cases from RFC 4231 (https://tools.ietf.org/html/rfc4231) */ 17 | static const struct testcase tests[] = { 18 | { "RFC 4231 Test Case 1", 19 | {"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" 20 | "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", 20}, 21 | { "Hi There", 8}, 22 | {"\xb0\x34\x4c\x61\xd8\xdb\x38\x53\x5c\xa8\xaf\xce\xaf\x0b\xf1\x2b" 23 | "\x88\x1d\xc2\x00\xc9\x83\x3d\xa7\x26\xe9\x37\x6c\x2e\x32\xcf\xf7", 32} 24 | }, 25 | { "RFC 4231 Test Case 2", 26 | {"Jefe", 4}, 27 | {"what do ya want for nothing?", 28}, 28 | {"\x5b\xdc\xc1\x46\xbf\x60\x75\x4e\x6a\x04\x24\x26\x08\x95\x75\xc7" 29 | "\x5a\x00\x3f\x08\x9d\x27\x39\x83\x9d\xec\x58\xb9\x64\xec\x38\x43", 32} 30 | }, 31 | { "RFC 4231 Test Case 3", 32 | {"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" 33 | "\xaa\xaa\xaa\xaa", 20}, 34 | {"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd" 35 | "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd" 36 | "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd" 37 | "\xdd\xdd", 50}, 38 | {"\x77\x3e\xa9\x1e\x36\x80\x0e\x46\x85\x4d\xb8\xeb\xd0\x91\x81\xa7" 39 | "\x29\x59\x09\x8b\x3e\xf8\xc1\x22\xd9\x63\x55\x14\xce\xd5\x65\xfe", 32} 40 | }, 41 | { "RFC 4231 Test Case 4", 42 | {"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10" 43 | "\x11\x12\x13\x14\x15\x16\x17\x18\x19", 25}, 44 | {"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" 45 | "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" 46 | "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" 47 | "\xcd\xcd", 50}, 48 | {"\x82\x55\x8a\x38\x9a\x44\x3c\x0e\xa4\xcc\x81\x98\x99\xf2\x08\x3a" 49 | "\x85\xf0\xfa\xa3\xe5\x78\xf8\x07\x7a\x2e\x3f\xf4\x67\x29\x66\x5b", 32} 50 | }, 51 | { "RFC 4231 Test Case 5", 52 | {"\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c" 53 | "\x0c\x0c\x0c\x0c", 20}, 54 | {"Test With Truncation", 20}, 55 | {"\xa3\xb6\x16\x74\x73\x10\x0e\xe0\x6e\x0c\x79\x6c\x29\x55\x55\x2b", 16} 56 | }, 57 | { "RFC 4231 Test Case 6", 58 | {"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" 59 | "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" 60 | "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" 61 | "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" 62 | "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" 63 | "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" 64 | "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" 65 | "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" 66 | "\xaa\xaa\xaa\xaa\xaa\xaa", 131}, 67 | {"Test Using Larger Than Block-Size Key - Hash Key First", 54}, 68 | {"\x60\xe4\x31\x59\x1e\xe0\xb6\x7f\x0d\x8a\x26\xaa\xcb\xf5\xb7\x7f" 69 | "\x8e\x0b\xc6\x21\x37\x28\xc5\x14\x05\x46\x04\x0f\x0e\xe3\x7f\x54", 32} 70 | }, 71 | { "RFC 4231 Test Case 7", 72 | {"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" 73 | "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" 74 | "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" 75 | "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" 76 | "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" 77 | "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" 78 | "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" 79 | "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" 80 | "\xaa\xaa\xaa\xaa\xaa\xaa", 131}, 81 | {"This is a test using a larger than block-size key and a larger " 82 | "than block-size data. The key needs to be hashed before being " 83 | "used by the HMAC algorithm.", 152}, 84 | {"\x9b\x09\xff\xa7\x1b\x94\x2f\xcb\x27\x63\x5f\xbc\xd5\xb0\xe9\x44" 85 | "\xbf\xdc\x63\x64\x4f\x07\x13\x93\x8a\x7f\x51\x53\x5c\x3a\x35\xe2", 32} 86 | } 87 | }; 88 | int main() { 89 | struct crypt* c = NULL; 90 | int failures = 0; 91 | char mac[32]; 92 | int maclen; 93 | int ix; 94 | int ret; 95 | 96 | c = crypt_HMAC_SHA256_new(); 97 | for (ix = 0; ix < sizeof(tests)/sizeof(tests[0]); ix++) { 98 | ret = c->c_set_key(c, tests[ix].key.iov_base, tests[ix].key.iov_len); 99 | if (ret) { 100 | printf("%s: failed to set key (return: %d)\n", tests[ix].name, ret); 101 | failures++; 102 | } 103 | maclen = sizeof(mac); 104 | c->c_mac(c, &(tests[ix].data), 1, mac, &maclen); 105 | if (maclen != sizeof(mac)) { 106 | printf("%s: wrong HMAC output length %d\n", tests[ix].name, maclen); 107 | failures++; 108 | } 109 | if (memcmp(tests[ix].answer.iov_base, mac, tests[ix].answer.iov_len) != 0) { 110 | printf("%s: MAC did not match\n", tests[ix].name); 111 | failures++; 112 | } 113 | }; 114 | c->c_destroy(c); 115 | if (!failures) { 116 | printf("OK\n"); 117 | return 0; 118 | } 119 | return 1; 120 | } 121 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | ACLOCAL_AMFLAGS = -I m4 2 | 3 | bin_PROGRAMS = src/tcpcryptd util/tcnetstat 4 | if !OS_MINGW 5 | bin_PROGRAMS += util/tcs 6 | endif 7 | 8 | dist_man8_MANS = src/tcpcryptd.man util/tcnetstat.man 9 | lib_LTLIBRARIES = lib/libtcpcrypt.la 10 | TESTSUITE = tests/testsuite 11 | TESTSUITEFLAGS = --directory tests 12 | EXTRA_DIST = \ 13 | launch_tcpcryptd.sh \ 14 | src/tcpcrypt_version.h \ 15 | src/tcpcryptd.man.md util/tcnetstat.man.md \ 16 | tests/package.m4 tests/atlocal.in \ 17 | tests/testsuite.at tests/version.at tests/hmac.at \ 18 | $(TESTSUITE) 19 | 20 | if MAINTAINER_MODE 21 | SUFFIXES = .man.md .man 22 | .man.md.man: 23 | pandoc -s -w man $^ -o $@ 24 | endif 25 | 26 | TCPCRYPT_SRC = $(srcdir)/src 27 | TCPCRYPT_INCLUDE = $(srcdir)/include 28 | 29 | AM_CFLAGS = -I$(TCPCRYPT_SRC) -I$(TCPCRYPT_INCLUDE) 30 | 31 | # include generated headers like tcpcrypt_version.h 32 | AM_CFLAGS += -I$(builddir)/src 33 | 34 | PRIV_SOURCES = src/priv.h 35 | PRIV_LDADD = 36 | if OS_MINGW 37 | PRIV_SOURCES += win/priv.c 38 | else 39 | PRIV_SOURCES += unix/priv.c 40 | if OS_LINUX 41 | PRIV_SOURCES += unix/linux/priv.c 42 | PRIV_LDADD += -lcap 43 | endif 44 | endif 45 | 46 | # lib_libtcpcrypt 47 | 48 | lib_libtcpcrypt_ladir = $(includedir)/tcpcrypt 49 | lib_libtcpcrypt_la_HEADERS = include/tcpcrypt/tcpcrypt.h 50 | lib_libtcpcrypt_la_SOURCES = \ 51 | lib/sockopt.c \ 52 | shared/socket_address.c shared/socket_address.h \ 53 | src/tcpcrypt_ctl.h \ 54 | lib/libtcpcrypt.sym 55 | 56 | TCPCRYPT_LIBRARY_VERSION = 0:0:0 57 | lib_libtcpcrypt_la_LDFLAGS = \ 58 | -version-info $(TCPCRYPT_LIBRARY_VERSION) \ 59 | -export-symbols $(top_srcdir)/lib/libtcpcrypt.sym 60 | 61 | if OS_MINGW 62 | lib_libtcpcrypt_la_LIBADD = -lws2_32 63 | endif 64 | 65 | 66 | # util_tcnetstat 67 | 68 | util_tcnetstat_SOURCES = \ 69 | util/tcnetstat.c \ 70 | include/tcpcrypt/tcpcrypt.h \ 71 | shared/socket_address.c shared/socket_address.h \ 72 | lib/libtcpcrypt.la 73 | 74 | util_tcnetstat_LDADD = lib/libtcpcrypt.la 75 | if OS_MINGW 76 | util_tcnetstat_LDADD += -lwsock32 -liphlpapi 77 | endif 78 | 79 | util_tcnetstat_CFLAGS = $(AM_CFLAGS) 80 | 81 | # util_tcs 82 | 83 | util_tcs_SOURCES = util/tcs.c \ 84 | shared/socket_address.c shared/socket_address.h \ 85 | $(PRIV_SOURCES) 86 | 87 | util_tcs_LDADD = lib/libtcpcrypt.la $(PRIV_LDADD) 88 | 89 | util_tcs_CFLAGS = $(AM_CFLAGS) 90 | 91 | # src_tcpcryptd 92 | 93 | src_tcpcryptd_SOURCES = \ 94 | src/tcpcryptd.c src/tcpcrypt.c src/crypto.c src/crypto_aes.c \ 95 | src/crypto_hmac.c src/crypto_dummy.c src/profile.c src/checksum.c src/test.c \ 96 | src/crypto_hkdf.c \ 97 | src/crypto_reg.c src/crypto_ecdhe.c \ 98 | src/inc.h src/tcpcrypt_ctl.h src/tcpcrypt_divert.h src/tcpcrypt.h src/tcpcryptd.h \ 99 | src/profile.h src/checksum.h src/test.h src/crypto.h src/tcpcrypt_strings.h \ 100 | src/util.c src/util.h \ 101 | src/tcpcrypt_version.h \ 102 | shared/socket_address.c shared/socket_address.h \ 103 | $(PRIV_SOURCES) 104 | 105 | src_tcpcryptd_LDADD = @tcpcryptd_LDADD@ @crypto_LDADD@ 106 | 107 | if OS_BSD 108 | src_tcpcryptd_SOURCES += src/freebsd.c 109 | endif 110 | 111 | if OS_LINUX 112 | src_tcpcryptd_SOURCES += src/linux.c 113 | endif 114 | 115 | if OS_MINGW 116 | src_tcpcryptd_SOURCES += src/mingw.c src/res.rc src/cygwin.c contrib/win_port.h 117 | src_tcpcryptd_LDADD += -lwsock32 -liphlpapi -lWinDivert 118 | else 119 | src_tcpcryptd_SOURCES += src/unix.c 120 | endif 121 | 122 | if !NO_ASM 123 | src_tcpcryptd_SOURCES += src/checksum_32.S 124 | endif 125 | 126 | src_tcpcryptd_CFLAGS = $(AM_CFLAGS) 127 | 128 | # tests/ 129 | 130 | tests/package.m4: $(top_srcdir)/configure.ac 131 | { \ 132 | echo '# Signature of the current package.' && \ 133 | echo 'm4_define([AT_PACKAGE_NAME], [$(PACKAGE_NAME)])' && \ 134 | echo 'm4_define([AT_PACKAGE_TARNAME], [$(PACKAGE_TARNAME)])' && \ 135 | echo 'm4_define([AT_PACKAGE_VERSION], [$(PACKAGE_VERSION)])' && \ 136 | echo 'm4_define([AT_PACKAGE_STRING], [$(PACKAGE_STRING)])' && \ 137 | echo 'm4_define([AT_PACKAGE_BUGREPORT], [$(PACKAGE_BUGREPORT)])'; \ 138 | echo 'm4_define([AT_PACKAGE_URL], [$(PACKAGE_URL)])'; \ 139 | } >$@ 140 | 141 | tests/atconfig: config.status 142 | ./config.status $@ 143 | 144 | ALL_TESTS = tests/version.at tests/hmac.at 145 | 146 | RUN_TESTSUITE = $(SHELL) $(srcdir)/tests/testsuite $(TESTSUITEFLAGS) 147 | 148 | check-local: tests/atconfig tests/atlocal $(TESTSUITE) 149 | $(RUN_TESTSUITE) AUTOTEST_PATH='tests:src:util' 150 | 151 | installcheck-local: tests/atconfig tests/atlocal $(TESTSUITE) 152 | $(RUN_TESTSUITE) AUTOTEST_PATH='tests:$(bindir)' 153 | 154 | clean-local: 155 | test ! -f '$(TESTSUITE)' || $(RUN_TESTSUITE) --clean 156 | rm -f '$(TESTSUITE)' 157 | rm -f tests/testsuite.log 158 | rm -f tests/atconfig 159 | 160 | AUTOM4TE = $(SHELL) $(srcdir)/config/missing --run autom4te 161 | AUTOTEST = $(AUTOM4TE) --language=autotest 162 | $(TESTSUITE): tests/testsuite.at tests/package.m4 $(ALL_TESTS) 163 | $(AUTOTEST) -I '$(srcdir)' -o $@.tmp $@.at 164 | mv $@.tmp $@ 165 | 166 | ## test programs: 167 | 168 | ## all tests against crypto elements should include these: 169 | cryptosources = \ 170 | src/inc.h \ 171 | src/crypto.h \ 172 | src/profile.h \ 173 | src/crypto.c \ 174 | src/profile.c \ 175 | src/util.c 176 | 177 | check_PROGRAMS = tests/hmac 178 | 179 | tests_hmac_SOURCES = tests/hmac.c \ 180 | src/crypto_hmac.c \ 181 | $(cryptosources) 182 | 183 | tests_hmac_LDADD = @crypto_LDADD@ 184 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # -*- Autoconf -*- 2 | 3 | AC_PREREQ([2.65]) 4 | AC_INIT([tcpcrypt], [0.5], [tcpcrypt-users@lists.stanford.edu], [tcpcrypt], [http://tcpcrypt.org]) 5 | AC_CONFIG_SRCDIR([src/tcpcryptd.c]) 6 | AC_CONFIG_HEADERS([config.h]) 7 | AC_CONFIG_AUX_DIR(config) 8 | AC_CONFIG_MACRO_DIR([m4]) 9 | 10 | AM_INIT_AUTOMAKE([1.9 foreign dist-xz -Wall subdir-objects]) 11 | AM_MAINTAINER_MODE([disable]) 12 | 13 | AC_ARG_VAR([DIVERT_PORT], [Default divert port for tcpcryptd]) 14 | if test -n "$DIVERT_PORT"; then 15 | AC_DEFINE_UNQUOTED([TCPCRYPTD_DIVERT_PORT], [$DIVERT_PORT], [Default divert port for tcpcryptd]) 16 | else 17 | AC_DEFINE([TCPCRYPTD_DIVERT_PORT], 666, [Default divert port for tcpcryptd]) 18 | fi 19 | 20 | AC_ARG_VAR([CONTROL_SOCKET], 21 | [Default local control socket for tcpcryptd: unix-domain path or localhost port-number]) 22 | if test -n "$CONTROL_SOCKET"; then 23 | AC_DEFINE_UNQUOTED([TCPCRYPTD_CONTROL_SOCKET], [$CONTROL_SOCKET], 24 | [Default local control socket for tcpcryptd: unix-domain path or localhost port-number]) 25 | else 26 | AC_DEFINE([TCPCRYPTD_CONTROL_SOCKET], "/var/run/tcpcryptd.control", 27 | [Default local control socket for tcpcryptd: unix-domain path or localhost port-number]) 28 | fi 29 | 30 | AC_ARG_VAR([JAIL_DIR], [Default jail directory for tcpcryptd]) 31 | if test -n "$JAIL_DIR"; then 32 | AC_DEFINE_UNQUOTED([TCPCRYPTD_JAIL_DIR], ["$JAIL_DIR"], [Default jail directory for tcpcryptd]) 33 | else 34 | AC_DEFINE([TCPCRYPTD_JAIL_DIR], ["/var/run/tcpcryptd"], [Default jail directory for tcpcryptd]) 35 | fi 36 | 37 | AC_ARG_VAR([JAIL_USER], [Default jail username for tcpcryptd]) 38 | if test -n "$JAIL_USER"; then 39 | AC_DEFINE_UNQUOTED([TCPCRYPTD_JAIL_USER], ["$JAIL_USER"], [Default jail username for tcpcryptd]) 40 | else 41 | AC_DEFINE([TCPCRYPTD_JAIL_USER], ["tcpcryptd"], [Default jail username for tcpcryptd]) 42 | fi 43 | 44 | AC_ARG_VAR([TEST_SERVER], [Default network test server for tcpcryptd]) 45 | if test -n "$TEST_SERVER"; then 46 | AC_DEFINE_UNQUOTED([TCPCRYPTD_TEST_SERVER], ["$TEST_SERVER"], [Default network test server for tcpcryptd]) 47 | else 48 | AC_DEFINE([TCPCRYPTD_TEST_SERVER], ["check.tcpcrypt.org"], [Default network test server for tcpcryptd]) 49 | fi 50 | 51 | # Checks for programs. 52 | AC_PROG_CC 53 | AC_PROG_LN_S 54 | AM_PROG_AR 55 | LT_INIT 56 | AM_PROG_AS 57 | 58 | # Check platform 59 | AC_CANONICAL_HOST 60 | AC_MSG_CHECKING(OS) 61 | if [ echo $host_os | grep linux ]; then 62 | os_linux=1 63 | else 64 | os_linux=0 65 | fi 66 | AM_CONDITIONAL(OS_LINUX, [test "$os_linux" -eq 1]) 67 | AM_CONDITIONAL(OS_BSD, [echo $host_os | grep -E 'darwin|freebsd']) 68 | AM_CONDITIONAL(OS_MINGW, [echo $host_os | grep mingw]) 69 | 70 | AS_IF([test "$os_linux" -eq 1], 71 | [AC_DEFINE([OS_LINUX], 1, [Define to 1 if compiling for a Linux system])], 72 | [AC_DEFINE([OS_LINUX], 0, [Define to 1 if compiling for a Linux system])]) 73 | 74 | CFLAGS="$CFLAGS -Wall -Wno-deprecated-declarations" 75 | 76 | # DEBUG 77 | AC_ARG_ENABLE(debug, 78 | AS_HELP_STRING([--enable-debug], 79 | [enable tracing and debugging flags for all components]), 80 | [enable_debug="$enableval"], 81 | []) 82 | if test "${enable_debug}" = yes; then 83 | CXXFLAGS="$CXXFLAGS -DDEBUG -g" 84 | CFLAGS="$CFLAGS -DDEBUG -g" 85 | 86 | AC_SUBST(CXXFLAGS) 87 | AC_SUBST(CFLAGS) 88 | fi 89 | 90 | # ASM 91 | AC_MSG_CHECKING(whether to use asm checksum routine) 92 | AC_ARG_ENABLE(asm, 93 | AS_HELP_STRING([--enable-asm], 94 | [use asm checksum routine]), 95 | [enable_asm="$enableval"], 96 | [enable_asm="no"]) 97 | if test "${enable_asm}" = yes; then 98 | AC_MSG_RESULT(yes) 99 | else 100 | AC_MSG_RESULT(no) 101 | AC_DEFINE(NO_ASM, 1, [No asm?]) 102 | fi 103 | AM_CONDITIONAL(NO_ASM, test x$enable_asm = xno) 104 | 105 | AM_CONDITIONAL(HAVE_NI, false) 106 | 107 | # libs 108 | AC_CHECK_LIB([cap], [cap_set_flag], [tcpcryptd_LDADD="-lcap $tcpcryptd_LDADD"]) 109 | AC_CHECK_LIB([crypto], [EVP_OpenInit], [crypto_LDADD="-lcrypto"]) 110 | 111 | AC_CHECK_LIB([netfilter_queue], [nfq_open], [tcpcryptd_LDADD="-lnetfilter_queue $tcpcryptd_LDADD"]) 112 | AC_CHECK_LIB([netfilter_conntrack], [nfct_open], [tcpcryptd_LDADD="-lnetfilter_conntrack $tcpcryptd_LDADD"]) 113 | AC_CHECK_LIB([nfnetlink], [nfnl_rcvbufsiz], [tcpcryptd_LDADD="-lnfnetlink $tcpcryptd_LDADD"]) 114 | AC_CHECK_LIB([pcap], [pcap_open_live], [tcpcryptd_LDADD="-lpcap $tcpcryptd_LDADD"]) 115 | AC_CHECK_LIB([pthread], [pthread_create]) 116 | AC_CHECK_LIB([wsock32], [bind]) # TODO: find symbol name 117 | AC_CHECK_LIB([iphlpapi], [GetAdaptersInfo]) # TODO: find symbol name 118 | AC_SUBST([tcpcryptd_LDADD]) 119 | AC_SUBST([crypto_LDADD]) 120 | 121 | # Checks for header files. 122 | AC_CHECK_HEADERS([arpa/inet.h fcntl.h limits.h netinet/in.h stddef.h stdint.h stdlib.h string.h strings.h sys/socket.h sys/time.h unistd.h]) 123 | 124 | # Checks for typedefs, structures, and compiler characteristics. 125 | AC_C_INLINE 126 | AC_TYPE_MODE_T 127 | AC_TYPE_SIZE_T 128 | AC_TYPE_SSIZE_T 129 | AC_TYPE_UINT16_T 130 | AC_TYPE_UINT32_T 131 | AC_TYPE_UINT64_T 132 | AC_TYPE_UINT8_T 133 | AC_CHECK_TYPES([ptrdiff_t]) 134 | 135 | # testing 136 | AC_CONFIG_TESTDIR([tests], [.]) 137 | AC_CONFIG_FILES([tests/atlocal]) 138 | 139 | # Checks for library functions. 140 | AC_FUNC_ALLOCA 141 | AC_FUNC_FORK 142 | AC_FUNC_MALLOC 143 | AC_CHECK_FUNCS([bzero clock_gettime gettimeofday inet_ntoa memmove memset select socket strchr strdup strtoul]) 144 | 145 | AC_CONFIG_FILES([Makefile src/tcpcrypt_version.h]) 146 | AC_OUTPUT 147 | -------------------------------------------------------------------------------- /src/test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "inc.h" 8 | #include "tcpcrypt_ctl.h" 9 | #include "tcpcrypt.h" 10 | #include "tcpcryptd.h" 11 | #include "crypto.h" 12 | #include "profile.h" 13 | #include "tcpcrypt_divert.h" 14 | #include "test.h" 15 | 16 | static struct state { 17 | int s_dlen; 18 | int s_drop_packet_num; 19 | int s_drop_times; 20 | int s_drop_hook; 21 | } _state; 22 | 23 | static struct crypt *setup_cipher(int type, int id, int mac) 24 | { 25 | struct cipher_list *c; 26 | int klen = 20; 27 | void *key; 28 | struct crypt_sym *cs; 29 | struct crypt *ci; 30 | 31 | c = crypt_find_cipher(type, id); 32 | if (!c) 33 | errx(1, "Can't find cipher %d (type %d)", id, type); 34 | 35 | cs = crypt_new(c->c_ctr); 36 | 37 | if (mac) 38 | ci = cs->cs_mac; 39 | else 40 | ci = cs->cs_cipher; 41 | 42 | key = alloca(klen); 43 | assert(key); 44 | 45 | memset(key, 0, klen); 46 | 47 | crypt_set_key(ci, key, klen); 48 | 49 | /* XXX cs is leaked */ 50 | 51 | return ci; 52 | } 53 | 54 | static unsigned int cipher_throughput(float sample, unsigned int avg) 55 | { 56 | unsigned int ops; 57 | unsigned int bits; 58 | 59 | ops = (unsigned int) (sample * 1000.0 * 1000.0); 60 | bits = (unsigned int) (sample * (float) _state.s_dlen * 8.0); 61 | 62 | printf("%u ops / sec (%u Mbit/s) [avg %u]\n", ops, bits, avg); 63 | 64 | return ops; 65 | } 66 | 67 | void test_sym_throughput(void) 68 | { 69 | struct crypt *c; 70 | int id = TC_AES128_GCM; 71 | uint64_t iv = 0; 72 | int dlen = 1420; 73 | void *data; 74 | 75 | c = setup_cipher(TYPE_SYM, id, 0); 76 | data = alloca(dlen); 77 | _state.s_dlen = dlen; 78 | memset(data, 0, dlen); 79 | 80 | printf("Encrypting %d bytes of data\n", dlen); 81 | 82 | speed_start(cipher_throughput); 83 | 84 | while (1) { 85 | crypt_encrypt(c, &iv, data, dlen); 86 | speed_add(1); 87 | } 88 | 89 | crypt_destroy(c); 90 | } 91 | 92 | static int get_test_param(int idx, int def) 93 | { 94 | char *p = test_param(idx); 95 | 96 | if (!p) 97 | return def; 98 | 99 | return atoi(p); 100 | } 101 | 102 | void test_mac_throughput(void) 103 | { 104 | struct crypt *c; 105 | int id = TC_HMAC_SHA1_128; 106 | int len = get_test_param(0, 8); 107 | int num = get_test_param(1, 1); 108 | struct iovec *iov; 109 | int i; 110 | unsigned char out[1024]; 111 | int outlen = sizeof(out); 112 | 113 | c = setup_cipher(TYPE_SYM, id, 1); 114 | 115 | iov = alloca(sizeof(*iov) * num); 116 | 117 | for (i = 0; i < num; i++) { 118 | iov[i].iov_len = len; 119 | iov[i].iov_base = alloca(iov[i].iov_len); 120 | memset(iov[i].iov_base, 0, iov[i].iov_len); 121 | } 122 | 123 | printf("MACing %d iovecs of %d bytes each\n", num, len); 124 | 125 | speed_start(cipher_throughput); 126 | 127 | while (1) { 128 | crypt_mac(c, iov, num, out, &outlen); 129 | speed_add(1); 130 | } 131 | 132 | crypt_destroy(c); 133 | } 134 | 135 | void print_packet(struct ip *ip, struct tcphdr *tcp, int flags, struct tc *tc) 136 | { 137 | char src[16]; 138 | char flagz[16]; 139 | int i = 0; 140 | int level = XP_NOISY; 141 | 142 | if (_conf.cf_verbose < level) 143 | return; 144 | 145 | if (tcp->th_flags & TH_SYN) 146 | flagz[i++] = 'S'; 147 | 148 | if (tcp->th_flags & TH_ACK) 149 | flagz[i++] = 'A'; 150 | 151 | if (tcp->th_flags & TH_RST) 152 | flagz[i++] = 'R'; 153 | 154 | if (tcp->th_flags & TH_FIN) 155 | flagz[i++] = 'F'; 156 | 157 | flagz[i] = 0; 158 | 159 | strcpy(src, inet_ntoa(ip->ip_src)); 160 | xprintf(level, "%s:%d->%s:%d %d %s [%s] tc %p\n", 161 | src, 162 | ntohs(tcp->th_sport), 163 | inet_ntoa(ip->ip_dst), 164 | ntohs(tcp->th_dport), 165 | ntohs(ip->ip_len), 166 | flagz, 167 | flags & DF_IN ? "in" : "out", 168 | tc); 169 | } 170 | 171 | static int dropper(int rc, void *packet, int len, int flags) 172 | { 173 | if (_state.s_drop_packet_num != 1) { 174 | _state.s_drop_packet_num--; 175 | return rc; 176 | } 177 | 178 | if (_state.s_drop_times != 0) { 179 | struct ip *ip = packet; 180 | struct tcphdr *tcp; 181 | 182 | tcp = (struct tcphdr *) ((unsigned long) ip + (ip->ip_hl << 2)); 183 | 184 | xprintf(XP_NOISY, "Dropping: "); 185 | print_packet(ip, tcp, flags, NULL); 186 | 187 | _state.s_drop_packet_num--; 188 | 189 | return DIVERT_DROP; 190 | } 191 | 192 | return rc; 193 | } 194 | 195 | static int dropper_pre(int rc, void *packet, int len, int flags) 196 | { 197 | if (flags & DF_IN) 198 | return dropper(rc, packet, len, flags); 199 | 200 | return rc; 201 | } 202 | 203 | static int dropper_post(int rc, void *packet, int len, int flags) 204 | { 205 | if (flags & DF_IN) 206 | return rc; 207 | 208 | return dropper(rc, packet, len, flags); 209 | } 210 | 211 | void test_dropper(void) 212 | { 213 | _state.s_drop_packet_num = get_test_param(0, 0); 214 | _state.s_drop_times = get_test_param(1, 1); 215 | _state.s_drop_hook = get_test_param(2, -1); 216 | 217 | if (_state.s_drop_packet_num <= 0) 218 | errx(1, "Need a packet number parameter. 1 is first."); 219 | 220 | switch (_state.s_drop_hook) { 221 | case -1: 222 | set_packet_hook(0, dropper_pre); 223 | set_packet_hook(1, dropper_post); 224 | break; 225 | 226 | default: 227 | set_packet_hook(_state.s_drop_hook, dropper); 228 | break; 229 | } 230 | 231 | tcpcryptd(); 232 | } 233 | -------------------------------------------------------------------------------- /src/checksum.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "inc.h" 8 | #include "tcpcrypt_ctl.h" 9 | #include "tcpcrypt.h" 10 | #include "tcpcryptd.h" 11 | #include "checksum.h" 12 | #include "config.h" 13 | 14 | typedef __signed__ char __s8; 15 | typedef unsigned char __u8; 16 | 17 | typedef __signed__ short __s16; 18 | typedef unsigned short __u16; 19 | 20 | typedef __signed__ int __s32; 21 | typedef unsigned int __u32; 22 | 23 | typedef __u16 __sum16; 24 | typedef __u32 __wsum; 25 | 26 | typedef __u32 u32; 27 | typedef u32 __be32; 28 | 29 | # define __force 30 | 31 | extern unsigned int csum_partial(const unsigned char * buff, int len, 32 | unsigned int sum); 33 | 34 | #ifdef NO_ASM 35 | static int _use_linux = 0; 36 | 37 | unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum) 38 | { 39 | abort(); 40 | } 41 | #else 42 | static int _use_linux = 1; 43 | #endif /* ! NO_ASM */ 44 | 45 | struct tcp_ph { 46 | struct in_addr ph_src; 47 | struct in_addr ph_dst; 48 | uint8_t ph_zero; 49 | uint8_t ph_proto; 50 | uint16_t ph_len; 51 | }; 52 | 53 | 54 | static unsigned short in_cksum(struct tcp_ph *ph, unsigned short *ptr, 55 | int nbytes, int s) 56 | { 57 | register long sum; 58 | u_short oddbyte; 59 | register u_short answer; 60 | 61 | sum = s; 62 | 63 | if (ph) { 64 | unsigned short *p = (unsigned short*) ph; 65 | int i; 66 | 67 | for (i = 0; i < sizeof(*ph) >> 1; i++) 68 | sum += *p++; 69 | } 70 | 71 | while (nbytes > 1) 72 | { 73 | sum += *ptr++; 74 | nbytes -= 2; 75 | } 76 | 77 | if (nbytes == 1) 78 | { 79 | oddbyte = 0; 80 | *((u_char *) & oddbyte) = *(u_char *) ptr; 81 | sum += oddbyte; 82 | } 83 | 84 | sum = (sum >> 16) + (sum & 0xffff); 85 | sum += (sum >> 16); 86 | answer = ~sum; 87 | return (answer); 88 | } 89 | 90 | static void checksum_ip_generic(struct ip *ip) 91 | { 92 | ip->ip_sum = 0; 93 | ip->ip_sum = in_cksum(NULL, (unsigned short*) ip, sizeof(*ip), 0); 94 | } 95 | 96 | static void checksum_tcp_generic(struct ip *ip, struct tcphdr *tcp, int sum) 97 | { 98 | struct tcp_ph ph; 99 | int len; 100 | 101 | len = ntohs(ip->ip_len) - (ip->ip_hl << 2); 102 | 103 | ph.ph_src = ip->ip_src; 104 | ph.ph_dst = ip->ip_dst; 105 | ph.ph_zero = 0; 106 | ph.ph_proto = ip->ip_p; 107 | ph.ph_len = htons(len); 108 | 109 | if (sum != 0) 110 | len = tcp->th_off << 2; 111 | 112 | tcp->th_sum = 0; 113 | tcp->th_sum = in_cksum(&ph, (unsigned short*) tcp, len, sum); 114 | } 115 | 116 | static inline __sum16 csum_fold(__wsum sum) 117 | { 118 | asm("addl %1, %0 ;\n" 119 | "adcl $0xffff, %0 ;\n" 120 | : "=r" (sum) 121 | : "r" ((__force u32)sum << 16), 122 | "0" ((__force u32)sum & 0xffff0000)); 123 | return (__force __sum16)(~(__force u32)sum >> 16); 124 | } 125 | 126 | static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr, 127 | unsigned short len, 128 | unsigned short proto, 129 | __wsum sum) 130 | { 131 | asm("addl %1, %0 ;\n" 132 | "adcl %2, %0 ;\n" 133 | "adcl %3, %0 ;\n" 134 | "adcl $0, %0 ;\n" 135 | : "=r" (sum) 136 | : "g" (daddr), "g"(saddr), 137 | "g" ((len + proto) << 8), "0" (sum)); 138 | return sum; 139 | } 140 | 141 | /* 142 | * computes the checksum of the TCP/UDP pseudo-header 143 | * returns a 16-bit checksum, already complemented 144 | */ 145 | static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr, 146 | unsigned short len, 147 | unsigned short proto, 148 | __wsum sum) 149 | { 150 | return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum)); 151 | } 152 | 153 | static void checksum_tcp_linux(struct tc *tc, struct ip *ip, struct tcphdr *tcp) 154 | { 155 | int len = ntohs(ip->ip_len) - (ip->ip_hl << 2); 156 | int p; 157 | int sum = tc->tc_csum; 158 | 159 | tcp->th_sum = 0; 160 | 161 | if (sum) { 162 | sum = (sum >> 16) + (sum & 0xffff); 163 | sum += (sum >> 16); 164 | sum &= 0xffff; 165 | 166 | p = csum_partial((unsigned char*) tcp, tcp->th_off << 2, sum); 167 | } else 168 | p = csum_partial((unsigned char*) tcp, len, 0); 169 | 170 | tcp->th_sum = csum_tcpudp_magic(ip->ip_src.s_addr, 171 | ip->ip_dst.s_addr, 172 | len, 173 | IPPROTO_TCP, 174 | p); 175 | } 176 | 177 | void checksum_tcp(struct tc *tc, struct ip *ip, struct tcphdr *tcp) 178 | { 179 | if (tc && _use_linux) 180 | checksum_tcp_linux(tc, ip, tcp); 181 | else 182 | checksum_tcp_generic(ip, tcp, 0); 183 | } 184 | 185 | static inline __sum16 ip_compute_csum(const void *buff, int len) 186 | { 187 | return csum_fold(csum_partial(buff, len, 0)); 188 | } 189 | 190 | static void checksum_ip_linux(struct ip *ip) 191 | { 192 | ip->ip_sum = 0; 193 | ip->ip_sum = ip_compute_csum(ip, ip->ip_hl << 2); 194 | } 195 | 196 | void checksum_ip(struct ip *ip) 197 | { 198 | if (_use_linux) 199 | checksum_ip_linux(ip); 200 | else 201 | checksum_ip_generic(ip); 202 | } 203 | 204 | uint16_t checksum(void *data, int len) 205 | { 206 | if (_use_linux) 207 | return ip_compute_csum(data, len); 208 | else 209 | return in_cksum(NULL, data, len, 0); 210 | } 211 | -------------------------------------------------------------------------------- /contrib/ocb.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ocb.h 3 | * 4 | * Author: Ted Krovetz (tdk@acm.org) 5 | * History: 1 April 2000 - first release (TK) - version 0.9 6 | * 7 | * OCB-AES-n reference code based on NIST submission "OCB Mode" 8 | * (dated 1 April 2000), submitted by Phillip Rogaway, with 9 | * auxiliary submitters Mihir Bellare, John Black, and Ted Krovetz. 10 | * 11 | * This code is freely available, and may be modified as desired. 12 | * Please retain the authorship and change history. 13 | * Note that OCB mode itself is patent pending. 14 | * 15 | * This code is NOT optimized for speed; it is only 16 | * designed to clarify the algorithm and to provide a point 17 | * of comparison for other implementations. 18 | * 19 | * Limitiations: Assumes a 4-byte integer and pointers are 20 | * 32-bit aligned. Acts on a byte string of less than 2^{36} - 16 bytes. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 23 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 24 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE 26 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 29 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 30 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 32 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | */ 34 | 35 | #ifndef __OCB__H 36 | #define __OCB__H 37 | 38 | #ifndef AES_KEY_BITLEN 39 | #define AES_KEY_BITLEN 128 /* Must be 128, 192, 256 */ 40 | #endif 41 | 42 | #if ((AES_KEY_BITLEN != 128) && \ 43 | (AES_KEY_BITLEN != 192) && \ 44 | (AES_KEY_BITLEN != 256)) 45 | #error Bad -- AES_KEY_BITLEN must be one of 128, 192 or 256!! 46 | #endif 47 | 48 | /* Opaque forward declaration of key structure */ 49 | typedef struct _keystruct keystruct; 50 | 51 | /* 52 | * "ocb_aes_init" optionally creates an ocb keystructure in memory 53 | * and then initializes it using the supplied "enc_key". "tag_len" 54 | * specifies the length of tags that will subsequently be generated 55 | * and verified. If "key" is NULL a new structure will be created, but 56 | * if "key" is non-NULL, then it is assumed that it points to a previously 57 | * allocated structure, and that structure is initialized. "ocb_aes_init" 58 | * returns a pointer to the initialized structure, or NULL if an error 59 | * occurred. 60 | */ 61 | keystruct * /* Init'd keystruct or NULL */ 62 | ocb_aes_init(void *enc_key, /* AES key */ 63 | unsigned tag_len, /* Length of tags to be used */ 64 | keystruct *key); /* OCB key structure. NULL means */ 65 | /* Allocate/init new, non-NULL */ 66 | /* means init existing structure */ 67 | 68 | /* "ocb_done deallocates a key structure and returns NULL */ 69 | keystruct * 70 | ocb_done(keystruct *key); 71 | 72 | /* 73 | * "ocb_aes_encrypt takes a key structure, four buffers and a length 74 | * parameter as input. "pt_len" bytes that are pointed to by "pt" are 75 | * encrypted and written to the buffer pointed to by "ct". A tag of length 76 | * "tag_len" (set in ocb_aes_init) is written to the "tag" buffer. "nonce" 77 | * must be a 16-byte buffer which changes for each new message being 78 | * encrypted. "ocb_aes_encrypt" always returns a value of 1. 79 | */ 80 | void 81 | ocb_aes_encrypt(keystruct *key, /* Initialized key struct */ 82 | void *nonce, /* 16-byte nonce */ 83 | void *pt, /* Buffer for (incoming) plaintext */ 84 | unsigned pt_len, /* Byte length of pt */ 85 | void *ct, /* Buffer for (outgoing) ciphertext */ 86 | void *tag); /* Buffer for generated tag */ 87 | 88 | 89 | /* 90 | * "ocb_aes_decrypt takes a key structure, four buffers and a length 91 | * parameter as input. "ct_len" bytes that are pointed to by "ct" are 92 | * decrypted and written to the buffer pointed to by "pt". A tag of length 93 | * "tag_len" (set in ocb_aes_init) is read from the "tag" buffer. "nonce" 94 | * must be a 16-byte buffer which changes for each new message being 95 | * encrypted. "ocb_aes_decrypt" returns 0 if the supplied 96 | * tag is not correct for the supplied message, otherwise 1 is returned if 97 | * the tag is correct. 98 | */ 99 | int /* Returns 0 iff tag is incorrect */ 100 | ocb_aes_decrypt(keystruct *key, /* Initialized key struct */ 101 | void *nonce, /* 16-byte nonce */ 102 | void *ct, /* Buffer for (incoming) ciphertext */ 103 | unsigned ct_len, /* Byte length of ct */ 104 | void *pt, /* Buffer for (outgoing) plaintext */ 105 | void *tag); /* Tag to be verified */ 106 | 107 | 108 | 109 | 110 | void 111 | pmac_aes (keystruct *key, /* Initialized key struct */ 112 | void *in, /* Buffer for (incoming) message */ 113 | unsigned in_len, /* Byte length of message */ 114 | void *tag); /* 16-byte buffer for generated tag */ 115 | 116 | #endif /* __OCB__H */ 117 | -------------------------------------------------------------------------------- /contrib/win_port.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1982, 1986, 1993 3 | * The Regents of the University of California. All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 4. Neither the name of the University nor the names of its contributors 14 | * may be used to endorse or promote products derived from this software 15 | * without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 | * SUCH DAMAGE. 28 | * 29 | * @(#)tcp.h 8.1 (Berkeley) 6/10/93 30 | */ 31 | 32 | #ifndef WIN_PORT_H 33 | #define WIN_PORT_H 34 | 35 | #include 36 | 37 | #define __LITTLE_ENDIAN 666 38 | #define __BYTE_ORDER 666 39 | 40 | typedef int socklen_t; 41 | 42 | typedef unsigned int u_int32_t; 43 | typedef unsigned short u_int16_t; 44 | typedef unsigned char u_int8_t; 45 | 46 | typedef unsigned int in_addr_t; 47 | 48 | struct msghdr 49 | { 50 | void *msg_name; /* Address to send to/receive from. */ 51 | socklen_t msg_namelen; /* Length of address data. */ 52 | 53 | struct iovec *msg_iov; /* Vector of data to send/receive into. */ 54 | size_t msg_iovlen; /* Number of elements in the vector. */ 55 | 56 | void *msg_control; /* Ancillary data (eg BSD filedesc passing). */ 57 | size_t msg_controllen; /* Ancillary data buffer length. 58 | !! The type should be socklen_t but the 59 | definition of the kernel is incompatible 60 | with this. */ 61 | 62 | int msg_flags; /* Flags on received message. */ 63 | }; 64 | 65 | typedef u_int32_t tcp_seq; 66 | /* 67 | * TCP header. 68 | * Per RFC 793, September, 1981. 69 | */ 70 | struct tcphdr 71 | { 72 | u_int16_t th_sport; /* source port */ 73 | u_int16_t th_dport; /* destination port */ 74 | tcp_seq th_seq; /* sequence number */ 75 | tcp_seq th_ack; /* acknowledgement number */ 76 | # if __BYTE_ORDER == __LITTLE_ENDIAN 77 | u_int8_t th_x2:4; /* (unused) */ 78 | u_int8_t th_off:4; /* data offset */ 79 | # endif 80 | # if __BYTE_ORDER == __BIG_ENDIAN 81 | u_int8_t th_off:4; /* data offset */ 82 | u_int8_t th_x2:4; /* (unused) */ 83 | # endif 84 | u_int8_t th_flags; 85 | # define TH_FIN 0x01 86 | # define TH_SYN 0x02 87 | # define TH_RST 0x04 88 | # define TH_PUSH 0x08 89 | # define TH_ACK 0x10 90 | # define TH_URG 0x20 91 | u_int16_t th_win; /* window */ 92 | u_int16_t th_sum; /* checksum */ 93 | u_int16_t th_urp; /* urgent pointer */ 94 | } __attribute__ ((gcc_struct)); 95 | 96 | # define TCPOPT_EOL 0 97 | # define TCPOPT_NOP 1 98 | # define TCPOPT_MAXSEG 2 99 | # define TCPOLEN_MAXSEG 4 100 | # define TCPOPT_WINDOW 3 101 | # define TCPOLEN_WINDOW 3 102 | # define TCPOPT_SACK_PERMITTED 4 /* Experimental */ 103 | # define TCPOLEN_SACK_PERMITTED 2 104 | # define TCPOPT_SACK 5 /* Experimental */ 105 | # define TCPOPT_TIMESTAMP 8 106 | # define TCPOLEN_TIMESTAMP 10 107 | # define TCPOLEN_TSTAMP_APPA (TCPOLEN_TIMESTAMP+2) /* appendix A */ 108 | 109 | # define TCPOPT_TSTAMP_HDR \ 110 | (TCPOPT_NOP<<24|TCPOPT_NOP<<16|TCPOPT_TIMESTAMP<<8|TCPOLEN_TIMESTAMP) 111 | 112 | struct ip 113 | { 114 | #if __BYTE_ORDER == __LITTLE_ENDIAN 115 | unsigned int ip_hl:4; /* header length */ 116 | unsigned int ip_v:4; /* version */ 117 | #endif 118 | #if __BYTE_ORDER == __BIG_ENDIAN 119 | unsigned int ip_v:4; /* version */ 120 | unsigned int ip_hl:4; /* header length */ 121 | #endif 122 | u_int8_t ip_tos; /* type of service */ 123 | u_short ip_len; /* total length */ 124 | u_short ip_id; /* identification */ 125 | u_short ip_off; /* fragment offset field */ 126 | #define IP_RF 0x8000 /* reserved fragment flag */ 127 | #define IP_DF 0x4000 /* dont fragment flag */ 128 | #define IP_MF 0x2000 /* more fragments flag */ 129 | #define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ 130 | u_int8_t ip_ttl; /* time to live */ 131 | u_int8_t ip_p; /* protocol */ 132 | u_short ip_sum; /* checksum */ 133 | struct in_addr ip_src, ip_dst; /* source and dest address */ 134 | } __attribute__ ((gcc_struct)); 135 | 136 | #define IPTOS_RELIABILITY 0x04 137 | 138 | typedef unsigned short int sa_family_t; 139 | 140 | struct iovec 141 | { 142 | void *iov_base; /* Pointer to data. */ 143 | size_t iov_len; /* Length of data. */ 144 | }; 145 | 146 | static void warnx(const char *fmt, ...) 147 | { 148 | va_list ap; 149 | 150 | va_start(ap, fmt); 151 | vprintf(fmt, ap); 152 | va_end(ap); 153 | 154 | printf("\n"); 155 | } 156 | 157 | static void errx(int eval, const char *fmt, ...) 158 | { 159 | va_list ap; 160 | 161 | va_start(ap, fmt); 162 | vprintf(fmt, ap); 163 | va_end(ap); 164 | 165 | printf("\n"); 166 | 167 | exit(eval); 168 | } 169 | 170 | static void warn(const char *fmt, ...) 171 | { 172 | va_list ap; 173 | 174 | va_start(ap, fmt); 175 | vprintf(fmt, ap); 176 | va_end(ap); 177 | 178 | printf(": "); 179 | perror(""); 180 | printf("\n"); 181 | } 182 | 183 | static void err(int eval, const char *fmt, ...) 184 | { 185 | va_list ap; 186 | 187 | va_start(ap, fmt); 188 | vprintf(fmt, ap); 189 | va_end(ap); 190 | 191 | printf(": "); 192 | perror(""); 193 | printf("\n"); 194 | 195 | exit(eval); 196 | } 197 | 198 | #endif // WIN_PORT_H 199 | -------------------------------------------------------------------------------- /src/crypto_aes.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "inc.h" 11 | #include "tcpcrypt_ctl.h" 12 | #include "tcpcrypt.h" 13 | #include "tcpcryptd.h" 14 | #include "crypto.h" 15 | #include "profile.h" 16 | 17 | #define BLEN 16 18 | 19 | struct aes_priv { 20 | EVP_CIPHER_CTX *ap_ctx; 21 | uint8_t ap_key[1024]; 22 | int ap_key_len; 23 | }; 24 | 25 | /* XXX move CTR / ASM mode outside of AES-specific implementation */ 26 | static void do_aes(struct crypt *c, void *iv, void *data, int len, int enc) 27 | { 28 | struct aes_priv *ap = crypt_priv(c); 29 | int blen; 30 | uint8_t *blocks; 31 | uint64_t ctr; 32 | uint64_t inc = xhtobe64(1); 33 | int rem, drem; 34 | uint64_t *ctrp; 35 | int i; 36 | uint32_t *pb, *pd; 37 | uint8_t *pb2, *pd2; 38 | uint16_t* csum = data; 39 | 40 | profile_add(3, "do_aes in"); 41 | assert(len); 42 | 43 | /* figure out counter value and remainder (use of previous block) */ 44 | ctr = xbe64toh(*((uint64_t*) iv)); 45 | rem = ctr & 0xf; 46 | ctr &= ~0xf; 47 | xhtobe64(ctr); 48 | 49 | /* figure out how many blocks we need */ 50 | blen = (len & ~0xf); 51 | if (rem) 52 | blen += BLEN; 53 | 54 | drem = len & 0xf; 55 | if (drem && ((drem > (16 - rem)) || !rem)) 56 | blen += BLEN; 57 | 58 | blocks = alloca(blen); 59 | assert(blocks); 60 | 61 | profile_add(3, "do_aes setup"); 62 | 63 | /* fill blocks with counter values */ 64 | ctrp = (uint64_t*) blocks; 65 | for (i = 0; i < (blen >> 4); i++) { 66 | *ctrp++ = 0; 67 | *ctrp++ = ctr; 68 | ctr += inc; 69 | } 70 | 71 | profile_add(3, "do_aes fill blocks"); 72 | 73 | /* do AES */ 74 | i = blen; 75 | if (!EVP_EncryptUpdate(ap->ap_ctx, blocks, &i, blocks, blen)) 76 | errssl(1, "EVP_EncryptUpdate()"); 77 | 78 | assert(i == blen); 79 | 80 | profile_add(3, "do_aes AES"); 81 | 82 | /* XOR data (and checksum) */ 83 | pb = (uint32_t*) &blocks[rem]; 84 | pd = (uint32_t*) data; 85 | while (len >= 4) { 86 | *pd++ ^= *pb++; 87 | len -= 4; 88 | 89 | // tc->tc_csum += *csum++; 90 | // tc->tc_csum += *csum++; 91 | } 92 | 93 | profile_add(3, "do_aes XOR words"); 94 | 95 | /* XOR any remainder (< 4 bytes) */ 96 | i = 0; /* unsummed */ 97 | pb2 = (uint8_t*) pb; 98 | pd2 = (uint8_t*) pd; 99 | while (len > 0) { 100 | *pd2++ ^= *pb2++; 101 | len--; 102 | 103 | if (i == 1) { 104 | // tc->tc_csum += *csum++; 105 | i = 0; 106 | } else 107 | i++; 108 | } 109 | 110 | profile_add(3, "do_aes XOR remainder"); 111 | 112 | assert(pb2 - blocks <= blen); 113 | assert(blen - (pb2 - blocks) < 16); /* efficiency */ 114 | 115 | /* sum odd byte */ 116 | if (i) { 117 | i = 0; 118 | *((uint8_t*) &i) = *((uint8_t*) csum); 119 | // tc->tc_csum += i; 120 | } 121 | } 122 | 123 | static int aes_encrypt(struct crypt *c, void *iv, void *data, int len) 124 | { 125 | do_aes(c, iv, data, len, 1); 126 | 127 | return len; 128 | } 129 | 130 | static int aes_decrypt(struct crypt *c, void *iv, void *data, int len) 131 | { 132 | do_aes(c, iv, data, len, 0); 133 | 134 | return len; 135 | } 136 | 137 | static int aes_set_key(struct crypt *c, void *key, int len) 138 | { 139 | struct aes_priv *ap = crypt_priv(c); 140 | 141 | assert(len <= sizeof(ap->ap_key)); 142 | 143 | memcpy(ap->ap_key, key, len); 144 | ap->ap_key_len = len; 145 | 146 | return 0; 147 | } 148 | 149 | static void aes_ack_mac(struct crypt *c, const struct iovec *iov, int num, void *out, 150 | int *outlen) 151 | { 152 | struct aes_priv *ap = crypt_priv(c); 153 | unsigned char block[BLEN]; 154 | 155 | assert(num == 1); 156 | assert(iov->iov_len <= sizeof(block)); 157 | 158 | memset(block, 0, sizeof(block)); 159 | memcpy(block, iov->iov_base, iov->iov_len); 160 | 161 | if (!EVP_EncryptUpdate(ap->ap_ctx, out, outlen, block, sizeof(block))) 162 | errssl(1, "EVP_EncryptUpdate()"); 163 | } 164 | 165 | static void aes_destroy(struct crypt *c) 166 | { 167 | struct aes_priv *p = crypt_priv(c); 168 | 169 | EVP_CIPHER_CTX_free(p->ap_ctx); 170 | 171 | free(p); 172 | free(c); 173 | } 174 | 175 | static int aes_aead_encrypt(struct crypt *c, void *iv, void *aad, int aadlen, 176 | void *data, int dlen, void *tag) 177 | { 178 | struct aes_priv *p = crypt_priv(c); 179 | int len = aadlen; 180 | 181 | if (EVP_EncryptInit_ex(p->ap_ctx, NULL, NULL, p->ap_key, iv) != 1) 182 | errx(1, "EVP_EncryptInit_ex()"); 183 | 184 | if (EVP_EncryptUpdate(p->ap_ctx, NULL, &len, aad, aadlen) != 1) 185 | errx(1, "EVP_EncryptUpdate()"); 186 | 187 | assert(len == aadlen); 188 | 189 | len = dlen; 190 | 191 | if (EVP_EncryptUpdate(p->ap_ctx, data, &len, data, dlen) != 1) 192 | errx(1, "EVP_EncryptUpdate()"); 193 | 194 | assert(len == dlen); 195 | 196 | len = 0; 197 | if (EVP_EncryptFinal_ex(p->ap_ctx, data + dlen, &len) != 1) 198 | errx(1, "EVP_EncryptFinal_ex()"); 199 | 200 | assert(len == 0); 201 | 202 | if (EVP_CIPHER_CTX_ctrl(p->ap_ctx, EVP_CTRL_GCM_GET_TAG, 16, tag) != 1) 203 | errx(1, "EVP_CTRL_GCM_GET_TAG"); 204 | 205 | return dlen; 206 | } 207 | 208 | static int aes_aead_decrypt(struct crypt *c, void *iv, void *aad, int aadlen, 209 | void *data, int dlen, void *tag) 210 | { 211 | struct aes_priv *p = crypt_priv(c); 212 | int len = aadlen; 213 | 214 | if (EVP_DecryptInit_ex(p->ap_ctx, NULL, NULL, p->ap_key, iv) != 1) 215 | errx(1, "EVP_EncryptInit_ex()"); 216 | 217 | if (EVP_DecryptUpdate(p->ap_ctx, NULL, &len, aad, aadlen) != 1) 218 | errx(1, "EVP_EncryptUpdate()"); 219 | 220 | assert(len == aadlen); 221 | 222 | len = dlen; 223 | 224 | if (EVP_DecryptUpdate(p->ap_ctx, data, &len, data, dlen) != 1) 225 | errx(1, "EVP_EncryptUpdate()"); 226 | 227 | assert(len == dlen); 228 | 229 | if (EVP_CIPHER_CTX_ctrl(p->ap_ctx, EVP_CTRL_GCM_SET_TAG, 16, tag) != 1) 230 | errx(1, "EVP_CTRL_GCM_GET_TAG"); 231 | 232 | len = 0; 233 | if (EVP_DecryptFinal_ex(p->ap_ctx, data + dlen, &len) <= 0) 234 | return -1; 235 | 236 | return dlen; 237 | } 238 | 239 | static struct crypt *crypt_AES_new(const EVP_CIPHER *evp) 240 | { 241 | struct aes_priv *p; 242 | struct crypt *c; 243 | 244 | c = crypt_init(sizeof(*p)); 245 | c->c_destroy = aes_destroy; 246 | c->c_set_key = aes_set_key; 247 | c->c_mac = aes_ack_mac; 248 | c->c_encrypt = aes_encrypt; 249 | c->c_decrypt = aes_decrypt; 250 | c->c_aead_encrypt = aes_aead_encrypt; 251 | c->c_aead_decrypt = aes_aead_decrypt; 252 | 253 | p = crypt_priv(c); 254 | 255 | p->ap_ctx = EVP_CIPHER_CTX_new(); 256 | if (!p->ap_ctx) 257 | errx(1, "EVP_CIPHER_CTX_new()"); 258 | 259 | if (EVP_EncryptInit_ex(p->ap_ctx, evp, NULL, NULL, NULL) != 1) 260 | errx(1, "EVP_EncryptInit_ex()"); 261 | 262 | if (EVP_CIPHER_CTX_ctrl(p->ap_ctx, EVP_CTRL_GCM_SET_IVLEN, 8, NULL) 263 | != 1) { 264 | errx(1, "EVP_CTRL_GCM_SET_IVLEN"); 265 | } 266 | 267 | return c; 268 | } 269 | 270 | struct crypt *crypt_AES128_new(void) 271 | { 272 | return crypt_AES_new(EVP_aes_128_gcm()); 273 | } 274 | 275 | struct crypt *crypt_AES256_new(void) 276 | { 277 | return crypt_AES_new(EVP_aes_256_gcm()); 278 | } 279 | -------------------------------------------------------------------------------- /src/profile.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "profile.h" 10 | 11 | #define MAX_SAMPLES 128 12 | 13 | struct samples { 14 | char *s_desc; 15 | union { 16 | struct timeval s_tv; 17 | uint64_t s_tsc; 18 | } u; 19 | }; 20 | 21 | static struct state { 22 | struct samples s_time[MAX_SAMPLES]; 23 | int s_timec; 24 | struct timeval s_speed_a; 25 | struct timeval s_speed_b; 26 | unsigned int s_speed_num; 27 | unsigned int s_speed_avg; 28 | int s_speed_avgc; 29 | speed_cb s_speed_cb; 30 | int s_discard; 31 | unsigned int s_sum; 32 | unsigned int s_samples; 33 | int s_enable; 34 | int s_time_source; 35 | } _state; 36 | 37 | int time_diff(struct timeval *a, struct timeval *now) 38 | { 39 | int diff = 0; 40 | int neg = 1; 41 | 42 | if ((a->tv_sec > now->tv_sec) 43 | || (a->tv_sec == now->tv_sec && a->tv_usec > now->tv_usec)) { 44 | struct timeval *tmp = a; 45 | 46 | a = now; 47 | now = tmp; 48 | neg = -1; 49 | } 50 | 51 | diff = now->tv_sec - a->tv_sec; 52 | 53 | if (diff == 0) 54 | diff = now->tv_usec - a->tv_usec; 55 | else { 56 | diff--; 57 | diff *= 1000 * 1000; 58 | diff += 1000 * 1000 - a->tv_usec; 59 | diff += now->tv_usec; 60 | } 61 | 62 | assert(diff >= 0); 63 | 64 | return diff * neg; 65 | } 66 | 67 | static inline uint64_t do_get_tsc(void) 68 | { 69 | uint64_t t = 0; 70 | 71 | #if defined(__amd64__) || defined(__i386__) 72 | __asm__ volatile (".byte 0x0f, 0x31" : "=A" (t)); 73 | #else 74 | abort(); 75 | #endif 76 | 77 | return t; 78 | } 79 | 80 | uint64_t get_tsc(void) 81 | { 82 | return do_get_tsc(); 83 | } 84 | 85 | void profile_add(int verb, char *desc) 86 | { 87 | if (_state.s_enable < verb) 88 | return; 89 | 90 | assert(_state.s_timec < MAX_SAMPLES); 91 | 92 | _state.s_time[_state.s_timec].s_desc = desc; 93 | 94 | switch (_state.s_time_source) { 95 | case TIME_SOURCE_GETTIMEOFDAY: 96 | gettimeofday(&_state.s_time[_state.s_timec].u.s_tv, NULL); 97 | break; 98 | 99 | case TIME_SOURCE_TSC: 100 | _state.s_time[_state.s_timec].u.s_tsc = do_get_tsc(); 101 | break; 102 | 103 | default: 104 | assert(!"Unknown time source"); 105 | break; 106 | } 107 | 108 | _state.s_timec++; 109 | } 110 | 111 | static unsigned int sample_diff(struct samples *a, struct samples *b) 112 | { 113 | uint64_t tsc_diff; 114 | unsigned int x; 115 | 116 | switch (_state.s_time_source) { 117 | case TIME_SOURCE_GETTIMEOFDAY: 118 | return time_diff(&a->u.s_tv, &b->u.s_tv); 119 | 120 | case TIME_SOURCE_TSC: 121 | tsc_diff = b->u.s_tsc - a->u.s_tsc; 122 | assert(tsc_diff >= 0); 123 | 124 | x = (unsigned int) tsc_diff; 125 | assert(((uint64_t) x) == tsc_diff); 126 | return x; 127 | 128 | default: 129 | assert(!"Unknown time source"); 130 | break; 131 | } 132 | 133 | return -1; 134 | } 135 | 136 | static const char *sample_unit(void) 137 | { 138 | static const char *gt = "s.us"; 139 | static const char *tsc = "cycles"; 140 | 141 | switch (_state.s_time_source) { 142 | case TIME_SOURCE_GETTIMEOFDAY: 143 | return gt; 144 | 145 | case TIME_SOURCE_TSC: 146 | return tsc; 147 | 148 | default: 149 | assert(!"Unknown time source"); 150 | break; 151 | } 152 | 153 | return NULL; 154 | } 155 | 156 | static const char *sample_str(struct samples *s) 157 | { 158 | static char buf[1024]; 159 | 160 | switch (_state.s_time_source) { 161 | case TIME_SOURCE_GETTIMEOFDAY: 162 | sprintf(buf, "%u.%u", 163 | (unsigned int) s->u.s_tv.tv_sec, 164 | (unsigned int) s->u.s_tv.tv_usec); 165 | break; 166 | 167 | case TIME_SOURCE_TSC: 168 | sprintf(buf, "%" PRIu64, s->u.s_tsc); 169 | break; 170 | 171 | default: 172 | assert(!"Unknown time source"); 173 | break; 174 | } 175 | 176 | return buf; 177 | } 178 | 179 | static void print_time(void) 180 | { 181 | unsigned int total; 182 | struct samples *s = _state.s_time; 183 | unsigned int diff; 184 | float pc; 185 | 186 | total = sample_diff(&_state.s_time[0], 187 | &_state.s_time[_state.s_timec - 1]); 188 | 189 | printf("Time (%s)\t\t diff\t %%\tdesc\n", sample_unit()); 190 | 191 | while (_state.s_timec--) { 192 | if (s != _state.s_time) 193 | diff = sample_diff((s - 1), s); 194 | else 195 | diff = 0; 196 | 197 | pc = (float) diff / (float) total * 100.0; 198 | 199 | printf("%-20s\t%10u\t%4.1f\t%s\n", 200 | sample_str(s), 201 | diff, 202 | pc, 203 | s->s_desc); 204 | 205 | s++; 206 | } 207 | 208 | printf("Total time %u\n", total); 209 | 210 | _state.s_timec = 0; 211 | } 212 | 213 | void profile_print(void) 214 | { 215 | if (!_state.s_enable) 216 | return; 217 | 218 | if (_state.s_timec) 219 | print_time(); 220 | } 221 | 222 | void speed_start(speed_cb cb) 223 | { 224 | _state.s_speed_cb = cb; 225 | gettimeofday(&_state.s_speed_a, NULL); 226 | } 227 | 228 | void sample_add(unsigned int sample) 229 | { 230 | unsigned int old = _state.s_sum; 231 | 232 | if (_state.s_discard != 0) { 233 | _state.s_discard--; 234 | return; 235 | } 236 | 237 | _state.s_sum += sample; 238 | _state.s_samples++; 239 | 240 | assert(_state.s_sum >= old); 241 | assert(_state.s_samples); 242 | } 243 | 244 | void speed_add(unsigned int sample) 245 | { 246 | unsigned int old = _state.s_speed_num; 247 | unsigned int diff; 248 | unsigned int rate; 249 | float speed; 250 | unsigned int avg = 0; 251 | 252 | gettimeofday(&_state.s_speed_b, NULL); 253 | 254 | _state.s_speed_num += sample; 255 | assert(_state.s_speed_num >= old); 256 | 257 | diff = time_diff(&_state.s_speed_a, &_state.s_speed_b); 258 | 259 | if (diff < 1000 * 1000) 260 | return; 261 | 262 | speed = (float) _state.s_speed_num / (float) diff; 263 | 264 | if (_state.s_speed_avgc >= 5) { 265 | avg = (double) _state.s_speed_avg 266 | / (double) _state.s_speed_avgc; 267 | 268 | _state.s_speed_avg = 0; 269 | _state.s_speed_avgc = 0; 270 | } 271 | 272 | rate = _state.s_speed_cb(speed, avg); 273 | sample_add(rate); 274 | 275 | old = _state.s_speed_avg; 276 | _state.s_speed_avg += rate; 277 | assert(_state.s_speed_avg >= old); 278 | _state.s_speed_avgc++; 279 | 280 | _state.s_speed_a = _state.s_speed_b; 281 | _state.s_speed_num = 0; 282 | } 283 | 284 | static void print_average(void) 285 | { 286 | printf("%u samples, average %u\n", 287 | _state.s_samples, _state.s_sum / _state.s_samples); 288 | } 289 | 290 | void profile_end(void) 291 | { 292 | if (_state.s_samples) 293 | print_average(); 294 | } 295 | 296 | void profile_setopt(int opt, int val) 297 | { 298 | switch (opt) { 299 | case PROFILE_DISCARD: 300 | _state.s_discard = val; 301 | break; 302 | 303 | case PROFILE_ENABLE: 304 | _state.s_enable = val; 305 | break; 306 | 307 | case PROFILE_TIME_SOURCE: 308 | _state.s_time_source = val; 309 | break; 310 | 311 | default: 312 | abort(); 313 | } 314 | } 315 | -------------------------------------------------------------------------------- /src/linux.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #define __FAVOR_BSD 20 | #include 21 | 22 | #undef _POSIX_SOURCE 23 | 24 | #include "tcpcrypt_divert.h" 25 | #include "tcpcryptd.h" 26 | 27 | static struct nfq_handle *_h; 28 | static struct nfq_q_handle *_q; 29 | static unsigned int _mark; 30 | static struct nfct_handle *_ct; 31 | 32 | static struct ct_arg { 33 | struct sockaddr_in *ct_to; 34 | struct ip *ct_ip; 35 | int *ct_flags; 36 | int ct_rc; 37 | } _ct_arg; 38 | 39 | static int packet_input(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, 40 | struct nfq_data *nfa, void *data) 41 | { 42 | divert_cb cb = (divert_cb) data; 43 | unsigned char *d; 44 | int len; 45 | int rc; 46 | unsigned int id; 47 | struct nfqnl_msg_packet_hdr *ph = nfq_get_msg_packet_hdr(nfa); 48 | struct ip *ip; 49 | int flags = 0; 50 | struct timeval tv; 51 | int rlen = 0; 52 | void *rdata = NULL; 53 | 54 | len = nfq_get_payload(nfa, &d); 55 | if (len < 0) 56 | err(1, "nfq_get_payload()"); 57 | 58 | if (nfq_get_indev(nfa)) 59 | flags |= DF_IN; 60 | 61 | if (nfq_get_timestamp(nfa, &tv) == 0) 62 | set_time(&tv); 63 | else { 64 | static int warn = 0; 65 | 66 | if (!warn && !_conf.cf_disable_timers) 67 | xprintf(XP_ALWAYS, "No timestamp provided in packet" 68 | " - expect low performance due to" 69 | " calls to gettimeofday\n"); 70 | warn = 1; 71 | } 72 | 73 | rc = cb(d, len, flags); 74 | 75 | id = ntohl(ph->packet_id); 76 | 77 | switch (rc) { 78 | case DIVERT_MODIFY: 79 | ip = (struct ip*) d; 80 | rlen = ntohs(ip->ip_len); 81 | rdata = d; 82 | /* fallthrough */ 83 | case DIVERT_ACCEPT: 84 | if (_mark) { 85 | unsigned int mark = 0; 86 | 87 | assert((mark & _mark) == 0); 88 | nfq_set_verdict_mark(qh, id, NF_REPEAT, 89 | htonl(_mark | mark), 90 | rlen, rdata); 91 | } else 92 | nfq_set_verdict(qh, id, NF_ACCEPT, rlen, rdata); 93 | break; 94 | 95 | case DIVERT_DROP: 96 | nfq_set_verdict(qh, id, NF_DROP, 0, NULL); 97 | break; 98 | 99 | default: 100 | printf("Unknown verdict %d\n", rc); 101 | abort(); 102 | } 103 | 104 | return 0; 105 | } 106 | 107 | static int conntrack_find(enum nf_conntrack_msg_type type, 108 | struct nf_conntrack *ct, 109 | void *data) 110 | { 111 | struct ct_arg *arg = data; 112 | int *flags = arg->ct_flags; 113 | struct sockaddr_in *to = arg->ct_to; 114 | struct ip *ip = arg->ct_ip; 115 | struct tcphdr *tcp = (struct tcphdr*) ((unsigned long) ip 116 | + ip->ip_hl * 4); 117 | 118 | if (arg->ct_rc == 0) 119 | return NFCT_CB_CONTINUE; 120 | 121 | #if 0 122 | char buf[1024]; 123 | nfct_snprintf(buf, sizeof(buf), ct, type, NFCT_O_DEFAULT, 0); 124 | printf("YO [%s]\n", buf); 125 | return NFCT_CB_CONTINUE; 126 | #endif 127 | 128 | if (nfct_get_attr_u32(ct, ATTR_IPV4_SRC) != ip->ip_src.s_addr) 129 | return NFCT_CB_CONTINUE; 130 | 131 | if (nfct_get_attr_u16(ct, ATTR_PORT_SRC) != tcp->th_sport) 132 | return NFCT_CB_CONTINUE; 133 | 134 | switch (nfct_get_attr_u8(ct, ATTR_TCP_STATE)) { 135 | case TCP_CONNTRACK_SYN_RECV: 136 | *flags = DF_IN; 137 | break; 138 | 139 | case TCP_CONNTRACK_SYN_SENT: 140 | *flags = 0; 141 | break; 142 | 143 | default: 144 | return NFCT_CB_CONTINUE; 145 | } 146 | 147 | to->sin_addr.s_addr = nfct_get_attr_u32(ct, ATTR_ORIG_IPV4_DST); 148 | to->sin_port = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST); 149 | 150 | arg->ct_rc = 0; 151 | 152 | return NFCT_CB_CONTINUE; 153 | } 154 | 155 | static void conntrack_open(void) 156 | { 157 | if (!(_ct = nfct_open(CONNTRACK, 0))) 158 | err(1, "nfct_open()"); 159 | 160 | nfct_callback_register(_ct, NFCT_T_ALL, conntrack_find, &_ct_arg); 161 | } 162 | 163 | static int linux_open(int port, divert_cb cb) 164 | { 165 | unsigned int bufsize = 1024 * 1024 * 1; 166 | unsigned int rc; 167 | char *m; 168 | int fd, flags; 169 | 170 | _h = nfq_open(); 171 | if (!_h) 172 | err(1, "nfq_open()"); 173 | 174 | rc = nfnl_rcvbufsiz(nfq_nfnlh(_h), bufsize); 175 | if (rc != bufsize) 176 | xprintf(XP_DEBUG, "Buffer size %u wanted %u\n", rc, bufsize); 177 | 178 | /* reset in case of previous crash */ 179 | if (nfq_unbind_pf(_h, AF_INET) < 0) 180 | err(1, "nfq_unbind_pf()"); 181 | 182 | if (nfq_bind_pf(_h, AF_INET) < 0) 183 | err(1, "nfq_bind_pf()"); 184 | 185 | _q = nfq_create_queue(_h, port, packet_input, cb); 186 | if (!_q) 187 | err(1, "nfq_create_queue()"); 188 | 189 | if (nfq_set_mode(_q, NFQNL_COPY_PACKET, 0xffff) < 0) 190 | err(1, "nfq_set_mode()"); 191 | 192 | if (nfq_set_queue_maxlen(_q, 10000) < 0) 193 | err(1, "nfq_set_queue_maxlen()"); 194 | 195 | xprintf(XP_DEFAULT, 196 | "Divert packets using iptables -j NFQUEUE --queue-num %d\n", 197 | port); 198 | 199 | m = driver_param(0); 200 | if (m) { 201 | _mark = strtoul(m, NULL, 16); 202 | xprintf(XP_DEFAULT, "Also, add -m mark --mark 0x0/0x%x\n", 203 | _mark); 204 | } 205 | 206 | fd = nfq_fd(_h); 207 | 208 | flags = fcntl(fd, F_GETFL); 209 | if (flags == -1) 210 | err(1, "fcntl()"); 211 | 212 | if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) 213 | err(1, "fcntl()"); 214 | 215 | raw_open(); 216 | conntrack_open(); 217 | 218 | return fd; 219 | } 220 | 221 | static void linux_close(void) 222 | { 223 | if (_q) 224 | nfq_destroy_queue(_q); 225 | 226 | if (_h) 227 | nfq_close(_h); 228 | 229 | if (_ct) 230 | nfct_close(_ct); 231 | } 232 | 233 | static void linux_next_packet(int s) 234 | { 235 | char buf[2048]; 236 | int rc; 237 | 238 | rc = read(s, buf, sizeof(buf)); 239 | if (rc == -1) { 240 | if (errno == ENOBUFS) { 241 | printf("FUCK - we're dropping packets\n"); 242 | return; 243 | } 244 | 245 | err(1, "read(divert) %d", errno); 246 | } 247 | 248 | if (rc == 0) 249 | errx(1, "EOF"); 250 | 251 | nfq_handle_packet(_h, buf, rc); 252 | } 253 | 254 | static int linux_orig_dest(struct sockaddr_in *to, struct ip *ip, int *flags) 255 | { 256 | int family = AF_INET; 257 | struct ct_arg *arg = &_ct_arg; 258 | 259 | memset(arg, 0, sizeof(*arg)); 260 | 261 | arg->ct_to = to; 262 | arg->ct_ip = ip; 263 | arg->ct_flags = flags; 264 | arg->ct_rc = -1; 265 | 266 | /* XXX have specific filter */ 267 | if (nfct_query(_ct, NFCT_Q_DUMP, &family) < 0) 268 | err(1, "nfct_query()"); 269 | 270 | return arg->ct_rc; 271 | } 272 | 273 | struct divert *divert_get(void) 274 | { 275 | static struct divert _divert_linux = { 276 | .open = linux_open, 277 | .next_packet = linux_next_packet, 278 | .close = linux_close, 279 | .inject = raw_inject, 280 | .orig_dest = linux_orig_dest, 281 | }; 282 | 283 | if (_conf.cf_rdr) { 284 | struct divert *pcap = divert_get_pcap(); 285 | _divert_linux.inject = pcap->inject; 286 | } 287 | 288 | return &_divert_linux; 289 | } 290 | -------------------------------------------------------------------------------- /util/tcs.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "config.h" 9 | #include "src/inc.h" 10 | #include "src/tcpcryptd.h" 11 | #include "src/tcpcrypt.h" 12 | #include "src/tcpcrypt_ctl.h" 13 | #include "src/tcpcrypt_strings.h" 14 | #include "src/priv.h" 15 | 16 | static const char *_bind_ip = "0.0.0.0"; 17 | 18 | enum { 19 | TYPE_CLIENT = 0, 20 | TYPE_SERVER, 21 | TYPE_RAW, 22 | }; 23 | 24 | enum { 25 | FLAG_HELLO = 1, 26 | }; 27 | 28 | struct sock { 29 | int s; 30 | int type; 31 | int dead; 32 | time_t added; 33 | struct sockaddr_in peer; 34 | int port; 35 | int flags; 36 | struct sock *next; 37 | } _socks; 38 | 39 | struct client { 40 | int sport; 41 | int dport; 42 | int flags; 43 | struct in_addr ip; 44 | time_t added; 45 | struct client *next; 46 | } _clients; 47 | 48 | static struct sock *add_sock(int s) 49 | { 50 | struct sock *sock = malloc(sizeof(*sock)); 51 | 52 | if (!sock) 53 | err(1, "malloc()"); 54 | 55 | memset(sock, 0, sizeof(*sock)); 56 | 57 | sock->s = s; 58 | sock->added = time(NULL); 59 | 60 | sock->next = _socks.next; 61 | _socks.next = sock; 62 | 63 | return sock; 64 | } 65 | 66 | static void add_server(int port) 67 | { 68 | int s; 69 | struct sockaddr_in s_in; 70 | struct sock *sock; 71 | int one = 1; 72 | 73 | if ((s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) 74 | err(1, "socket()"); 75 | 76 | if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1) 77 | err(1, "setsockopt()"); 78 | 79 | memset(&s_in, 0, sizeof(s_in)); 80 | 81 | s_in.sin_family = PF_INET; 82 | s_in.sin_addr.s_addr = inet_addr(_bind_ip); 83 | s_in.sin_port = htons(port); 84 | 85 | if (bind(s, (struct sockaddr*) &s_in, sizeof(s_in)) == -1) 86 | err(1, "bind()"); 87 | 88 | if (listen(s, 5) == -1) 89 | err(1, "listen()"); 90 | 91 | sock = add_sock(s); 92 | sock->type = TYPE_SERVER; 93 | sock->port = port; 94 | } 95 | 96 | static void add_sniffer(void) 97 | { 98 | int s; 99 | struct sock *sock; 100 | 101 | if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) == -1) 102 | err(1, "socket()"); 103 | 104 | sock = add_sock(s); 105 | sock->type = TYPE_RAW; 106 | } 107 | 108 | static void find_client(struct sock *s) 109 | { 110 | struct client *c = &_clients; 111 | 112 | while (c->next) { 113 | struct client *next = c->next; 114 | struct client *del = NULL; 115 | 116 | if (next->dport == s->port 117 | && next->sport == ntohs(s->peer.sin_port)) { 118 | s->flags = next->flags; 119 | del = next; 120 | } 121 | 122 | if ((time(NULL) - next->added) > 10) 123 | del = next; 124 | 125 | if (del) { 126 | c->next = next->next; 127 | free(del); 128 | } else 129 | c = next; 130 | } 131 | } 132 | 133 | static void handle_server(struct sock *s) 134 | { 135 | struct sockaddr_in s_in; 136 | socklen_t len = sizeof(s_in); 137 | int dude; 138 | struct sock *d; 139 | 140 | dude = accept(s->s, (struct sockaddr*) &s_in, &len); 141 | 142 | if (dude == -1) { 143 | perror("accept()"); 144 | return; 145 | } 146 | 147 | d = add_sock(dude); 148 | 149 | memcpy(&d->peer, &s_in, sizeof(d->peer)); 150 | d->port = s->port; 151 | 152 | find_client(d); 153 | } 154 | 155 | static void handle_client(struct sock *s) 156 | { 157 | char buf[1024]; 158 | int rc; 159 | int got = -1; 160 | int i; 161 | int crypt = 0; 162 | unsigned int len; 163 | struct tm *tm; 164 | time_t t; 165 | 166 | len = sizeof(buf); 167 | rc = tcpcrypt_getsockopt(s->s, IPPROTO_TCP, TCP_CRYPT_SESSID, buf, 168 | &len); 169 | crypt = rc != -1; 170 | 171 | rc = read(s->s, buf, sizeof(buf) - 1); 172 | if (rc <= 0) { 173 | s->dead = 1; 174 | return; 175 | } 176 | 177 | buf[rc] = 0; 178 | 179 | s->dead = 1; 180 | 181 | for (i = 0; i < sizeof(REQS) / sizeof(*REQS); i++) { 182 | if (strcmp(buf, REQS[i]) == 0) { 183 | got = i; 184 | break; 185 | } 186 | } 187 | 188 | if (got == -1) 189 | return; 190 | 191 | snprintf(buf, sizeof(buf), "%s%d", TEST_REPLY, s->flags); 192 | rc = strlen(buf); 193 | 194 | if (write(s->s, buf, rc) != rc) 195 | return; 196 | 197 | t = time(NULL); 198 | tm = localtime(&t); 199 | strftime(buf, sizeof(buf), "%m/%d/%y %H:%M:%S", tm); 200 | 201 | printf("[%s] GOT %s:%d - %4d [MSG %d] crypt %d flags %d\n", 202 | buf, 203 | inet_ntoa(s->peer.sin_addr), 204 | ntohs(s->peer.sin_port), 205 | s->port, 206 | got, 207 | crypt, 208 | s->flags); 209 | 210 | s->dead = 1; 211 | } 212 | 213 | static void found_crypt(struct ip *ip, struct tcphdr *th) 214 | { 215 | struct client *c = malloc(sizeof(*c)); 216 | 217 | if (!c) 218 | err(1, "malloc()"); 219 | 220 | memset(c, 0, sizeof(*c)); 221 | 222 | c->ip = ip->ip_src; 223 | c->sport = ntohs(th->th_sport); 224 | c->dport = ntohs(th->th_dport); 225 | c->added = time(NULL); 226 | c->flags = FLAG_HELLO; 227 | c->next = _clients.next; 228 | 229 | _clients.next = c; 230 | } 231 | 232 | static void handle_raw(struct sock *s) 233 | { 234 | unsigned char buf[2048]; 235 | int rc; 236 | struct ip *ip = (struct ip*) buf; 237 | struct tcphdr *th; 238 | unsigned char *end, *p; 239 | 240 | if ((rc = read(s->s, buf, sizeof(buf))) <= 0) 241 | err(1, "read()"); 242 | 243 | if (ip->ip_v != 4) 244 | return; 245 | 246 | if (ip->ip_p != IPPROTO_TCP) 247 | return; 248 | 249 | th = (struct tcphdr*) (((unsigned long) ip) + (ip->ip_hl << 2)); 250 | 251 | if ((unsigned long) th >= (unsigned long) (&buf[rc] - sizeof(*th))) 252 | return; 253 | 254 | p = (unsigned char*) (th + 1); 255 | end = (unsigned char*) (((unsigned long) th) + (th->th_off << 2)); 256 | 257 | if ((unsigned long) end > (unsigned long) &buf[rc]) 258 | return; 259 | 260 | if (th->th_flags != TH_SYN) 261 | return; 262 | 263 | while (p < end) { 264 | int opt = *p++; 265 | int len; 266 | 267 | switch (opt) { 268 | case TCPOPT_EOL: 269 | case TCPOPT_NOP: 270 | continue; 271 | } 272 | 273 | if (p >= end) 274 | break; 275 | 276 | len = *p++ - 2; 277 | 278 | if ((p + len) >= end) 279 | break; 280 | 281 | switch (opt) { 282 | case TCPOPT_EXP: 283 | if (len >= 2 && ntohs(*((uint16_t*) p)) == EXID_ENO) 284 | found_crypt(ip, th); 285 | break; 286 | } 287 | 288 | p += len; 289 | } 290 | } 291 | 292 | static void process_socket(struct sock *s) 293 | { 294 | 295 | switch (s->type) { 296 | case TYPE_SERVER: 297 | handle_server(s); 298 | break; 299 | 300 | case TYPE_RAW: 301 | handle_raw(s); 302 | break; 303 | 304 | case TYPE_CLIENT: 305 | handle_client(s); 306 | break; 307 | 308 | default: 309 | printf("WTF %d\n", s->type); 310 | abort(); 311 | break; 312 | } 313 | } 314 | 315 | static void check_sockets(void) 316 | { 317 | struct sock *s = _socks.next; 318 | fd_set fds; 319 | int max = 0; 320 | struct timeval tv; 321 | 322 | FD_ZERO(&fds); 323 | 324 | while (s) { 325 | FD_SET(s->s, &fds); 326 | 327 | if (s->s > max) 328 | max = s->s; 329 | 330 | s = s->next; 331 | } 332 | 333 | tv.tv_sec = 5; 334 | tv.tv_usec = 0; 335 | 336 | if (select(max + 1, &fds, NULL, NULL, &tv) == -1) 337 | err(1, "select()"); 338 | 339 | s = &_socks; 340 | 341 | while ((s = s->next)) { 342 | if (FD_ISSET(s->s, &fds)) 343 | process_socket(s); 344 | } 345 | 346 | s = &_socks; 347 | 348 | while (s->next) { 349 | struct sock *next = s->next; 350 | 351 | if (next->type == TYPE_CLIENT 352 | && (time(NULL) - next->added > 10)) 353 | next->dead = 1; 354 | 355 | if (next->dead) { 356 | close(next->s); 357 | s->next = next->next; 358 | free(next); 359 | } else 360 | s = next; 361 | } 362 | } 363 | 364 | static void pwn(void) 365 | { 366 | add_sniffer(); 367 | add_server(80); 368 | add_server(7777); 369 | 370 | tzset(); 371 | 372 | drop_privs(TCPCRYPTD_JAIL_DIR, TCPCRYPTD_JAIL_USER); 373 | 374 | while (1) 375 | check_sockets(); 376 | } 377 | 378 | int main(int argc, const char *argv[]) 379 | { 380 | if (argc > 1) { 381 | _bind_ip = argv[1]; 382 | 383 | printf("Binding to %s\n", _bind_ip); 384 | } 385 | 386 | pwn(); 387 | exit(0); 388 | } 389 | -------------------------------------------------------------------------------- /src/unix.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #define __FAVOR_BSD 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "tcpcrypt_divert.h" 27 | #include "tcpcrypt.h" 28 | #include "tcpcryptd.h" 29 | #include "profile.h" 30 | #include "test.h" 31 | #include "crypto.h" 32 | #include "checksum.h" 33 | 34 | extern int pcap_set_want_pktap(pcap_t *, int); 35 | extern int pcap_set_filter_info(pcap_t *, const char *, int, bpf_u_int32); 36 | 37 | /* from tcpdump */ 38 | typedef struct pktap_header { 39 | uint32_t pkt_len; /* length of pktap header */ 40 | uint32_t pkt_rectype; /* type of record */ 41 | uint32_t pkt_dlt; /* DLT type of this packet */ 42 | char pkt_ifname[24]; /* interface name */ 43 | uint32_t pkt_flags; 44 | uint32_t pkt_pfamily; /* "protocol family" */ 45 | uint32_t pkt_llhdrlen; /* link-layer header length? */ 46 | uint32_t pkt_lltrlrlen; /* link-layer trailer length? */ 47 | uint32_t pkt_pid; /* process ID */ 48 | char pkt_cmdname[20]; /* command name */ 49 | uint32_t pkt_svc_class; /* "service class" */ 50 | uint16_t pkt_iftype; /* "interface type" */ 51 | uint16_t pkt_ifunit; /* unit number of interface? */ 52 | uint32_t pkt_epid; /* "effective process ID" */ 53 | char pkt_ecmdname[20]; /* "effective command name" */ 54 | } pktap_header_t; 55 | 56 | static divert_cb _cb; 57 | static int _s; 58 | static pcap_t *_pcap; 59 | 60 | void raw_open(void) 61 | { 62 | int one = 1; 63 | 64 | _s = socket(AF_INET, SOCK_RAW, IPPROTO_TCP); 65 | if (_s == -1) 66 | err(1, "socket()"); 67 | 68 | if (setsockopt(_s, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one)) 69 | == -1) 70 | err(1, "IP_HDRINCL"); 71 | } 72 | 73 | void raw_inject(void *data, int len) 74 | { 75 | int rc; 76 | struct ip *ip = data; 77 | struct tcphdr *tcp = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2)); 78 | struct sockaddr_in s_in; 79 | 80 | memset(&s_in, 0, sizeof(s_in)); 81 | 82 | s_in.sin_family = PF_INET; 83 | s_in.sin_addr = ip->ip_dst; 84 | s_in.sin_port = tcp->th_dport; 85 | 86 | #if defined(__FreeBSD__) 87 | #include 88 | #if __FreeBSD_version < 1000022 89 | #define HO_LEN 90 | #endif 91 | #endif 92 | #ifdef __DARWIN_UNIX03 93 | #define HO_LEN 94 | #endif 95 | #ifdef HO_LEN 96 | ip->ip_len = ntohs(ip->ip_len); 97 | ip->ip_off = ntohs(ip->ip_off); 98 | #endif 99 | 100 | rc = sendto(_s, data, len, 0, (struct sockaddr*) &s_in, 101 | sizeof(s_in)); 102 | if (rc == -1) 103 | err(1, "sendto(raw)"); 104 | 105 | if (rc != len) 106 | errx(1, "wrote %d/%d", rc, len); 107 | 108 | #ifdef HO_LEN 109 | ip->ip_len = htons(ip->ip_len); 110 | ip->ip_off = htons(ip->ip_off); 111 | #endif 112 | } 113 | 114 | static void divert_next_packet_pcap(int s) 115 | { 116 | struct pcap_pkthdr h; 117 | struct pktap_header *pktap; 118 | unsigned char *data; 119 | int len, rc; 120 | struct ip *ip; 121 | struct tcphdr *tcp; 122 | unsigned char copy[4096]; 123 | struct ether_header *eh; 124 | 125 | if ((data = (void*) pcap_next(_pcap, &h)) == NULL) 126 | errx(1, "pcap_next()"); 127 | 128 | if (h.caplen != h.len) { 129 | xprintf(XP_ALWAYS, "Short pcap %d %d\n", h.caplen, h.len); 130 | return; 131 | } 132 | 133 | len = h.caplen; 134 | 135 | pktap = (struct pktap_header *) data; 136 | if (len < sizeof(*pktap)) 137 | goto __bad_packet; 138 | 139 | if (len < pktap->pkt_len) 140 | goto __bad_packet; 141 | 142 | len -= pktap->pkt_len; 143 | 144 | /* This seems to be the redirected packet to the loopback - an extra 145 | * copy 146 | */ 147 | if (strcmp(pktap->pkt_ifname, "lo0") == 0 && pktap->pkt_pid == -1) 148 | return; 149 | 150 | /* deal with link layer */ 151 | eh = (struct ether_header*) (data + pktap->pkt_len); 152 | 153 | if (pktap->pkt_dlt == DLT_EN10MB) { 154 | if (len < pktap->pkt_llhdrlen || len < sizeof(*eh)) 155 | goto __bad_packet; 156 | 157 | if (ntohs(eh->ether_type) != ETHERTYPE_IP) 158 | return; 159 | } else if (pktap->pkt_dlt == DLT_NULL) { 160 | uint32_t *af = (uint32_t*) eh; 161 | if (len < pktap->pkt_llhdrlen || len < sizeof(*af)) 162 | goto __bad_packet; 163 | 164 | if (*af != PF_INET) 165 | return; 166 | } 167 | 168 | data = ((unsigned char*) eh) + pktap->pkt_llhdrlen; 169 | len -= pktap->pkt_llhdrlen; 170 | 171 | if (len < sizeof(*ip)) 172 | goto __bad_packet; 173 | 174 | ip = (struct ip*) data; 175 | 176 | /* Don't listen to our own injections */ 177 | if (ip->ip_tos == INJECT_TOS) 178 | return; 179 | 180 | if (ip->ip_p != IPPROTO_TCP) 181 | return; 182 | 183 | tcp = (struct tcphdr*) (((char*) ip) + (ip->ip_hl << 2)); 184 | if ((unsigned long) (tcp + 1) - (unsigned long) ip > len) 185 | goto __bad_packet; 186 | 187 | /* XXX grab from conf */ 188 | if (ntohs(tcp->th_sport) != 80 && ntohs(tcp->th_dport) != 80) 189 | return; 190 | 191 | assert(len < sizeof(copy)); 192 | memcpy(copy, data, len); 193 | data = copy; 194 | 195 | rc = _cb(data, len, pktap->pkt_flags & 1); 196 | 197 | switch (rc) { 198 | case DIVERT_DROP: 199 | case DIVERT_ACCEPT: 200 | break; 201 | 202 | case DIVERT_MODIFY: 203 | ip = (struct ip*) data; 204 | _divert->inject(data, ntohs(ip->ip_len)); 205 | break; 206 | } 207 | 208 | return; 209 | __bad_packet: 210 | xprintf(XP_ALWAYS, "Bad packet 1\n"); 211 | return; 212 | } 213 | 214 | static void divert_inject_pcap(void *data, int len) 215 | { 216 | struct ip *ip = data; 217 | uint8_t tos = ip->ip_tos; 218 | uint16_t sum = ip->ip_sum; 219 | 220 | /* annotate packets so firewall lets them through */ 221 | ip->ip_tos = INJECT_TOS; 222 | checksum_ip(ip); 223 | 224 | raw_inject(data, len); 225 | 226 | ip->ip_tos = tos; 227 | ip->ip_sum = sum; 228 | } 229 | 230 | static int divert_open_pcap(int port, divert_cb cb) 231 | { 232 | char buf[PCAP_ERRBUF_SIZE]; 233 | pcap_t *p; 234 | int fd; 235 | static const char *filter = "proto TCP and port 80"; 236 | #ifndef __DARWIN_UNIX03 237 | struct bpf_program fp; 238 | #endif 239 | 240 | p = pcap_create("any", buf); 241 | 242 | if (!p) 243 | errx(1, "pcap_create(): %s", buf); 244 | 245 | #ifdef __DARWIN_UNIX03 246 | pcap_set_want_pktap(p, 1); 247 | #endif 248 | pcap_set_snaplen(p, 2048); 249 | pcap_set_timeout(p, 1); 250 | pcap_activate(p); 251 | 252 | #ifdef __DARWIN_UNIX03 253 | if (pcap_set_datalink(p, DLT_PKTAP) == -1) { 254 | pcap_perror(p, "pcap_set_datalink()"); 255 | exit(1); 256 | } 257 | 258 | /* XXX need pktap_filter_packet for this to work */ 259 | if (pcap_set_filter_info(p, filter, 0, PCAP_NETMASK_UNKNOWN) == -1) 260 | errx(1, "pcap_set_filter_info()"); 261 | #else 262 | if (pcap_compile(p, &fp, filter, 0, PCAP_NETMASK_UNKNOWN) == -1) 263 | errx(1, "pcap_compile()"); 264 | 265 | if (pcap_setfilter(p, &fp) == -1) 266 | errx(1, "pcap_setfilter()"); 267 | #endif 268 | 269 | if ((fd = pcap_get_selectable_fd(p)) == -1) 270 | errx(1, "pcap_get_selectable_fd()"); 271 | 272 | _pcap = p; 273 | _cb = cb; 274 | 275 | raw_open(); 276 | 277 | xprintf(XP_ALWAYS, "Blackhole handshake and rdr using pf\n"); 278 | 279 | return fd; 280 | } 281 | 282 | static void divert_close_pcap(void) 283 | { 284 | pcap_close(_pcap); 285 | } 286 | 287 | struct divert *divert_get_pcap(void) 288 | { 289 | static struct divert _divert_pf = { 290 | .open = divert_open_pcap, 291 | .next_packet = divert_next_packet_pcap, 292 | .close = divert_close_pcap, 293 | .inject = divert_inject_pcap, 294 | }; 295 | 296 | return &_divert_pf; 297 | } 298 | -------------------------------------------------------------------------------- /contrib/cmac.c: -------------------------------------------------------------------------------- 1 | /* crypto/cmac/cmac.c */ 2 | /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL 3 | * project. 4 | */ 5 | /* ==================================================================== 6 | * Copyright (c) 2010 The OpenSSL Project. All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 15 | * 2. Redistributions in binary form must reproduce the above copyright 16 | * notice, this list of conditions and the following disclaimer in 17 | * the documentation and/or other materials provided with the 18 | * distribution. 19 | * 20 | * 3. All advertising materials mentioning features or use of this 21 | * software must display the following acknowledgment: 22 | * "This product includes software developed by the OpenSSL Project 23 | * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 24 | * 25 | * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 26 | * endorse or promote products derived from this software without 27 | * prior written permission. For written permission, please contact 28 | * licensing@OpenSSL.org. 29 | * 30 | * 5. Products derived from this software may not be called "OpenSSL" 31 | * nor may "OpenSSL" appear in their names without prior written 32 | * permission of the OpenSSL Project. 33 | * 34 | * 6. Redistributions of any form whatsoever must retain the following 35 | * acknowledgment: 36 | * "This product includes software developed by the OpenSSL Project 37 | * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 38 | * 39 | * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 40 | * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 41 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 42 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 43 | * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 44 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 45 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 46 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 47 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 48 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 49 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 50 | * OF THE POSSIBILITY OF SUCH DAMAGE. 51 | * ==================================================================== 52 | */ 53 | 54 | #include 55 | #include 56 | #include 57 | #include "cmac.h" 58 | 59 | struct CMAC_CTX_st 60 | { 61 | /* Cipher context to use */ 62 | EVP_CIPHER_CTX cctx; 63 | /* Keys k1 and k2 */ 64 | unsigned char k1[EVP_MAX_BLOCK_LENGTH]; 65 | unsigned char k2[EVP_MAX_BLOCK_LENGTH]; 66 | /* Temporary block */ 67 | unsigned char tbl[EVP_MAX_BLOCK_LENGTH]; 68 | /* Last (possibly partial) block */ 69 | unsigned char last_block[EVP_MAX_BLOCK_LENGTH]; 70 | /* Number of bytes in last block: -1 means context not initialised */ 71 | int nlast_block; 72 | }; 73 | 74 | 75 | /* Make temporary keys K1 and K2 */ 76 | 77 | static void make_kn(unsigned char *k1, unsigned char *l, int bl) 78 | { 79 | int i; 80 | /* Shift block to left, including carry */ 81 | for (i = 0; i < bl; i++) 82 | { 83 | k1[i] = l[i] << 1; 84 | if (i < bl - 1 && l[i + 1] & 0x80) 85 | k1[i] |= 1; 86 | } 87 | /* If MSB set fixup with R */ 88 | if (l[0] & 0x80) 89 | k1[bl - 1] ^= bl == 16 ? 0x87 : 0x1b; 90 | } 91 | 92 | CMAC_CTX *CMAC_CTX_new(void) 93 | { 94 | CMAC_CTX *ctx; 95 | ctx = OPENSSL_malloc(sizeof(CMAC_CTX)); 96 | if (!ctx) 97 | return NULL; 98 | EVP_CIPHER_CTX_init(&ctx->cctx); 99 | ctx->nlast_block = -1; 100 | return ctx; 101 | } 102 | 103 | void CMAC_CTX_cleanup(CMAC_CTX *ctx) 104 | { 105 | EVP_CIPHER_CTX_cleanup(&ctx->cctx); 106 | OPENSSL_cleanse(ctx->tbl, EVP_MAX_BLOCK_LENGTH); 107 | OPENSSL_cleanse(ctx->k1, EVP_MAX_BLOCK_LENGTH); 108 | OPENSSL_cleanse(ctx->k2, EVP_MAX_BLOCK_LENGTH); 109 | OPENSSL_cleanse(ctx->last_block, EVP_MAX_BLOCK_LENGTH); 110 | ctx->nlast_block = -1; 111 | } 112 | 113 | EVP_CIPHER_CTX *CMAC_CTX_get0_cipher_ctx(CMAC_CTX *ctx) 114 | { 115 | return &ctx->cctx; 116 | } 117 | 118 | void CMAC_CTX_free(CMAC_CTX *ctx) 119 | { 120 | CMAC_CTX_cleanup(ctx); 121 | OPENSSL_free(ctx); 122 | } 123 | 124 | int CMAC_Init(CMAC_CTX *ctx, const void *key, size_t keylen, 125 | const EVP_CIPHER *cipher, ENGINE *impl) 126 | { 127 | static unsigned char zero_iv[EVP_MAX_BLOCK_LENGTH]; 128 | /* All zeros means restart */ 129 | if (!key && !cipher && !impl && keylen == 0) 130 | { 131 | /* Not initialised */ 132 | if (ctx->nlast_block == -1) 133 | return 0; 134 | if (!EVP_EncryptInit_ex(&ctx->cctx, NULL, NULL, NULL, zero_iv)) 135 | return 0; 136 | return 1; 137 | } 138 | /* Initialiase context */ 139 | if (cipher && !EVP_EncryptInit_ex(&ctx->cctx, cipher, impl, NULL, NULL)) 140 | return 0; 141 | /* Non-NULL key means initialisation complete */ 142 | if (key) 143 | { 144 | int bl; 145 | if (!EVP_CIPHER_CTX_cipher(&ctx->cctx)) 146 | return 0; 147 | if (!EVP_CIPHER_CTX_set_key_length(&ctx->cctx, keylen)) 148 | return 0; 149 | if (!EVP_EncryptInit_ex(&ctx->cctx, NULL, NULL, key, zero_iv)) 150 | return 0; 151 | bl = EVP_CIPHER_CTX_block_size(&ctx->cctx); 152 | if (!EVP_Cipher(&ctx->cctx, ctx->tbl, zero_iv, bl)) 153 | return 0; 154 | make_kn(ctx->k1, ctx->tbl, bl); 155 | make_kn(ctx->k2, ctx->k1, bl); 156 | OPENSSL_cleanse(ctx->tbl, bl); 157 | /* Reset context again ready for first data block */ 158 | if (!EVP_EncryptInit_ex(&ctx->cctx, NULL, NULL, NULL, zero_iv)) 159 | return 0; 160 | /* Zero tbl so resume works */ 161 | memset(ctx->tbl, 0, bl); 162 | ctx->nlast_block = 0; 163 | } 164 | return 1; 165 | } 166 | 167 | int CMAC_Update(CMAC_CTX *ctx, const void *in, size_t dlen) 168 | { 169 | const unsigned char *data = in; 170 | size_t bl; 171 | if (ctx->nlast_block == -1) 172 | return 0; 173 | if (dlen == 0) 174 | return 1; 175 | bl = EVP_CIPHER_CTX_block_size(&ctx->cctx); 176 | /* Copy into partial block if we need to */ 177 | if (ctx->nlast_block > 0) 178 | { 179 | size_t nleft; 180 | nleft = bl - ctx->nlast_block; 181 | if (dlen < nleft) 182 | nleft = dlen; 183 | memcpy(ctx->last_block + ctx->nlast_block, data, nleft); 184 | dlen -= nleft; 185 | ctx->nlast_block += nleft; 186 | /* If no more to process return */ 187 | if (dlen == 0) 188 | return 1; 189 | data += nleft; 190 | /* Else not final block so encrypt it */ 191 | if (!EVP_Cipher(&ctx->cctx, ctx->tbl, ctx->last_block,bl)) 192 | return 0; 193 | } 194 | /* Encrypt all but one of the complete blocks left */ 195 | while(dlen > bl) 196 | { 197 | if (!EVP_Cipher(&ctx->cctx, ctx->tbl, data, bl)) 198 | return 0; 199 | dlen -= bl; 200 | data += bl; 201 | } 202 | /* Copy any data left to last block buffer */ 203 | memcpy(ctx->last_block, data, dlen); 204 | ctx->nlast_block = dlen; 205 | return 1; 206 | 207 | } 208 | 209 | int CMAC_Final(CMAC_CTX *ctx, unsigned char *out, size_t *poutlen) 210 | { 211 | int i, bl, lb; 212 | if (ctx->nlast_block == -1) 213 | return 0; 214 | bl = EVP_CIPHER_CTX_block_size(&ctx->cctx); 215 | *poutlen = (size_t)bl; 216 | if (!out) 217 | return 1; 218 | lb = ctx->nlast_block; 219 | /* Is last block complete? */ 220 | if (lb == bl) 221 | { 222 | for (i = 0; i < bl; i++) 223 | out[i] = ctx->last_block[i] ^ ctx->k1[i]; 224 | } 225 | else 226 | { 227 | ctx->last_block[lb] = 0x80; 228 | if (bl - lb > 1) 229 | memset(ctx->last_block + lb + 1, 0, bl - lb - 1); 230 | for (i = 0; i < bl; i++) 231 | out[i] = ctx->last_block[i] ^ ctx->k2[i]; 232 | } 233 | if (!EVP_Cipher(&ctx->cctx, out, out, bl)) 234 | { 235 | OPENSSL_cleanse(out, bl); 236 | return 0; 237 | } 238 | return 1; 239 | } 240 | 241 | int CMAC_resume(CMAC_CTX *ctx) 242 | { 243 | if (ctx->nlast_block == -1) 244 | return 0; 245 | /* The buffer "tbl" containes the last fully encrypted block 246 | * which is the last IV (or all zeroes if no last encrypted block). 247 | * The last block has not been modified since CMAC_final(). 248 | * So reinitliasing using the last decrypted block will allow 249 | * CMAC to continue after calling CMAC_Final(). 250 | */ 251 | return EVP_EncryptInit_ex(&ctx->cctx, NULL, NULL, NULL, ctx->tbl); 252 | } 253 | -------------------------------------------------------------------------------- /launchers/winlauncher/tcpcrypt.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "resource.h" 6 | #include "../../src/tcpcrypt_version.h" 7 | 8 | #define COBJMACROS 9 | 10 | #define WM_TERM (WM_APP + 1) 11 | 12 | static HANDLE _tcpcryptd = INVALID_HANDLE_VALUE; 13 | static HWND _hwnd; 14 | static HINSTANCE _hinstance; 15 | static NOTIFYICONDATA _nid[2]; 16 | static NOTIFYICONDATA *_nidcur = NULL; 17 | 18 | static WINAPI DWORD check_term(void *arg) 19 | { 20 | WaitForSingleObject(_tcpcryptd, INFINITE); 21 | 22 | _tcpcryptd = INVALID_HANDLE_VALUE; 23 | 24 | if (!PostMessage(_hwnd, WM_TERM, 0, 0)) 25 | MessageBox(_hwnd, "PostMessage()", "Error", MB_OK); 26 | 27 | return 0; 28 | } 29 | 30 | static void stop() 31 | { 32 | if (_tcpcryptd != INVALID_HANDLE_VALUE) { 33 | if (!TerminateProcess(_tcpcryptd, 0)) 34 | MessageBox(_hwnd, "TerminateProcess()", "Error", MB_OK); 35 | } 36 | 37 | _tcpcryptd = INVALID_HANDLE_VALUE; 38 | } 39 | 40 | static void die(int rc) 41 | { 42 | stop(); 43 | 44 | if (_nidcur) 45 | Shell_NotifyIcon(NIM_DELETE, _nidcur); 46 | 47 | exit(rc); 48 | } 49 | 50 | static void err(int rc, char *fmt, ...) 51 | { 52 | va_list ap; 53 | char buf[4096]; 54 | DWORD e; 55 | 56 | buf[0] = 0; 57 | e = GetLastError(); 58 | FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 59 | NULL, 60 | e, 61 | 0, 62 | buf, 63 | sizeof(buf), 64 | NULL); 65 | 66 | printf("ERR %ld [%s]\n", e, buf); 67 | 68 | va_start(ap, fmt); 69 | vsnprintf(buf, sizeof(buf), fmt, ap); 70 | va_end(ap); 71 | 72 | MessageBox(_hwnd, buf, "Error", MB_OK); 73 | 74 | die(rc); 75 | } 76 | 77 | static void get_path(char *path) 78 | { 79 | char *p; 80 | 81 | if (!GetModuleFileName(NULL, path, _MAX_PATH)) 82 | err(1, "GetModuleFileName()"); 83 | 84 | p = strrchr(path, '\\'); 85 | if (p) 86 | p[1] = 0; 87 | } 88 | 89 | static void start() 90 | { 91 | char cmd[_MAX_PATH]; 92 | char arg[1024]; 93 | PROCESS_INFORMATION pi; 94 | STARTUPINFO si; 95 | 96 | get_path(cmd); 97 | snprintf(cmd + strlen(cmd), sizeof(cmd) - strlen(cmd), "tcpcryptd.exe"); 98 | snprintf(arg, sizeof(arg), "%s -u :65532 -e", "tcpcryptd.exe"); 99 | 100 | memset(&si, 0, sizeof(si)); 101 | si.cb = sizeof(si); 102 | si.wShowWindow = SW_HIDE; 103 | si.dwFlags |= STARTF_USESHOWWINDOW; 104 | 105 | if (!CreateProcess(cmd, 106 | arg, 107 | NULL, 108 | NULL, 109 | FALSE, 110 | 0, 111 | NULL, 112 | NULL, 113 | &si, 114 | &pi)) 115 | err(1, "CreateProcess()"); 116 | 117 | _tcpcryptd = pi.hProcess; 118 | 119 | if (!CreateThread(NULL, 0, check_term, NULL, 0, NULL)) 120 | err(1, "CreateThread()"); 121 | } 122 | 123 | static void netstat() 124 | { 125 | char cmd[_MAX_PATH]; 126 | PROCESS_INFORMATION pi; 127 | STARTUPINFO si; 128 | HANDLE out[2], e[2]; 129 | SECURITY_ATTRIBUTES sa; 130 | HWND edit; 131 | DWORD rd; 132 | int l; 133 | 134 | edit = GetDlgItem(_hwnd, IDC_EDIT1); 135 | 136 | get_path(cmd); 137 | snprintf(cmd + strlen(cmd), sizeof(cmd) - strlen(cmd), "tcnetstat.exe"); 138 | 139 | memset(&sa, 0, sizeof(sa)); 140 | sa.nLength = sizeof(sa); 141 | sa.bInheritHandle = TRUE; 142 | 143 | if (!CreatePipe(&out[0], &out[1], &sa, 0)) 144 | err(1, "CreatePipe()"); 145 | 146 | if (!SetHandleInformation(out[0], HANDLE_FLAG_INHERIT, 0)) 147 | err(1, "SetHandleInformation()"); 148 | 149 | if (!DuplicateHandle(GetCurrentProcess(), out[1], 150 | GetCurrentProcess(), &e[1], 0, 151 | TRUE,DUPLICATE_SAME_ACCESS)) 152 | err(1, "DuplicateHandle()"); 153 | 154 | memset(&si, 0, sizeof(si)); 155 | si.cb = sizeof(si); 156 | si.dwFlags |= STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; 157 | si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); 158 | si.hStdOutput = out[1]; 159 | si.hStdError = e[1]; 160 | si.wShowWindow = SW_HIDE; 161 | 162 | if (!CreateProcess(cmd, 163 | "tcnetstat.exe -u :65532", 164 | NULL, 165 | NULL, 166 | TRUE, 167 | 0, 168 | NULL, 169 | NULL, 170 | &si, 171 | &pi)) 172 | err(1, "CreateProcess()"); 173 | 174 | CloseHandle(out[1]); 175 | CloseHandle(e[1]); 176 | 177 | SetWindowText(edit, ""); 178 | SetFocus(edit); 179 | l = 0; 180 | while (1) { 181 | int l; 182 | 183 | if (!ReadFile(out[0], cmd, sizeof(cmd) - 1, &rd, NULL)) 184 | break; 185 | 186 | cmd[rd] = 0; 187 | 188 | SendMessage(edit, EM_SETSEL, l, l); 189 | SendMessage(edit, EM_REPLACESEL, 0, (LPARAM) cmd); 190 | l += strlen(cmd); 191 | } 192 | 193 | CloseHandle(out[0]); 194 | } 195 | 196 | static void minimize(HWND hwnd) 197 | { 198 | ShowWindow(hwnd, SW_HIDE); 199 | } 200 | 201 | static void do_stop(HWND dlg) 202 | { 203 | HWND button = GetDlgItem(dlg, IDOK); 204 | 205 | SetWindowText(button, "Start"); 206 | 207 | SetWindowText(GetDlgItem(dlg, IDC_EDIT2), "tcpcrypt off"); 208 | 209 | _nidcur = &_nid[0]; 210 | Shell_NotifyIcon(NIM_MODIFY, _nidcur); 211 | SendMessage(_hwnd, WM_SETICON, ICON_SMALL, (LPARAM) _nidcur->hIcon); 212 | 213 | EnableWindow(GetDlgItem(dlg, IDC_BUTTON2), FALSE); 214 | } 215 | 216 | static void add_text(char *x) 217 | { 218 | } 219 | 220 | static void start_stop(HWND dlg) 221 | { 222 | HWND button = GetDlgItem(dlg, IDOK); 223 | 224 | if (!button) 225 | err(1, "GetDlgItem()"); 226 | 227 | if (_tcpcryptd == INVALID_HANDLE_VALUE) { 228 | start(); 229 | SetWindowText(button, "Stop"); 230 | SetWindowText(GetDlgItem(dlg, IDC_EDIT2), "tcpcrypt ON!"); 231 | _nidcur = &_nid[1]; 232 | Shell_NotifyIcon(NIM_MODIFY, _nidcur); 233 | SendMessage(_hwnd, WM_SETICON, ICON_SMALL, 234 | (LPARAM) _nidcur->hIcon); 235 | EnableWindow(GetDlgItem(dlg, IDC_BUTTON2), TRUE); 236 | } else { 237 | stop(); 238 | do_stop(dlg); 239 | } 240 | } 241 | 242 | static void setup_icons(void) 243 | { 244 | memset(&_nid[0], 0, sizeof(*_nid)); 245 | 246 | _nid[0].cbSize = sizeof(*_nid); 247 | _nid[0].hWnd = _hwnd; 248 | _nid[0].uID = 0; 249 | _nid[0].uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; 250 | _nid[0].uCallbackMessage = WM_USER; 251 | _nid[0].hIcon = LoadIcon(_hinstance, 252 | MAKEINTRESOURCE(IDI_OFF)); 253 | 254 | if (!_nid[0].hIcon) 255 | err(1, "LoadIcon()"); 256 | 257 | strcpy(_nid[0].szTip, "tcpcrypt off"); 258 | 259 | memcpy(&_nid[1], &_nid[0], sizeof(*_nid)); 260 | 261 | _nid[1].hIcon = LoadIcon(_hinstance, MAKEINTRESOURCE(IDI_ON)); 262 | if (!_nid[1].hIcon) 263 | err(1, "LoadIcon()"); 264 | 265 | strcpy(_nid[1].szTip, "tcpcrypt ON"); 266 | 267 | _nidcur = &_nid[0]; 268 | 269 | Shell_NotifyIcon(NIM_ADD, _nidcur); 270 | SendMessage(_hwnd, WM_SETICON, ICON_SMALL, (LPARAM) _nidcur->hIcon); 271 | } 272 | 273 | static void do_init(void) 274 | { 275 | char title[1024]; 276 | 277 | setup_icons(); 278 | 279 | snprintf(title, sizeof(title), "tcpcrypt v%s", TCPCRYPT_VERSION); 280 | 281 | SetWindowText(_hwnd, title); 282 | } 283 | 284 | static void hof(void) 285 | { 286 | if (((long long) ShellExecute(NULL, (LPCTSTR) "open", 287 | "http://tcpcrypt.org/fame.php", 288 | NULL, ".\\", SW_SHOWNORMAL)) < 33) 289 | err(1, "ShellExecute()"); 290 | } 291 | 292 | LRESULT CALLBACK DlgProc(HWND hWndDlg, UINT Msg, WPARAM wParam, LPARAM lParam) 293 | { 294 | switch (Msg) { 295 | case WM_USER: 296 | switch (lParam) { 297 | case WM_LBUTTONDBLCLK: 298 | ShowWindow(hWndDlg, SW_SHOW); 299 | return TRUE; 300 | } 301 | break; 302 | 303 | case WM_TERM: 304 | do_stop(hWndDlg); 305 | break; 306 | 307 | case WM_INITDIALOG: 308 | _hwnd = hWndDlg; 309 | do_init(); 310 | do_stop(_hwnd); 311 | 312 | start_stop(hWndDlg); /* didn't we say on by default? ;D */ 313 | break; 314 | 315 | case WM_SYSCOMMAND: 316 | if ((wParam & 0xfff0) == SC_MINIMIZE) { 317 | minimize(hWndDlg); 318 | return TRUE; 319 | } 320 | break; 321 | 322 | case WM_CLOSE: 323 | minimize(hWndDlg); 324 | return TRUE; 325 | 326 | case WM_COMMAND: 327 | switch(wParam) { 328 | case IDOK: 329 | start_stop(hWndDlg); 330 | return TRUE; 331 | case IDCANCEL: 332 | netstat(); 333 | return TRUE; 334 | 335 | case IDC_BUTTON1: 336 | EndDialog(hWndDlg, 0); 337 | return TRUE; 338 | 339 | case IDC_BUTTON2: 340 | hof(); 341 | return TRUE; 342 | } 343 | break; 344 | } 345 | 346 | return FALSE; 347 | } 348 | 349 | int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 350 | LPSTR szCmdLine, int iCmdShow) 351 | { 352 | _hinstance = hInstance; 353 | 354 | if (DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, 355 | (DLGPROC) DlgProc) == -1) 356 | err(1, "DialogBox()"); 357 | 358 | die(0); 359 | } 360 | --------------------------------------------------------------------------------