mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 09:27:59 +00:00
Initial checkin: beta 0.43
[originally from svn r11]
This commit is contained in:
commit
c74130d423
56
Makefile
Normal file
56
Makefile
Normal file
@ -0,0 +1,56 @@
|
||||
# Makefile for PuTTY. Use `FWHACK=/DFWHACK' to cause the firewall hack
|
||||
# to be built in. (requires rebuild of ssh.obj only)
|
||||
|
||||
CFLAGS = /nologo /W3 /YX /O2 /Yd /D_X86_ /D_WINDOWS /DDEBUG /ML /Fd
|
||||
|
||||
.c.obj:
|
||||
cl $(FWHACK) $(CFLAGS) /c $*.c
|
||||
|
||||
OBJS1 = window.obj windlg.obj terminal.obj telnet.obj misc.obj noise.obj
|
||||
OBJS2 = ssh.obj sshcrc.obj sshdes.obj sshmd5.obj sshrsa.obj sshrand.obj
|
||||
OBJS3 = sshsha.obj
|
||||
RESRC = win_res.res
|
||||
LIBS1 = advapi32.lib user32.lib gdi32.lib
|
||||
LIBS2 = wsock32.lib comctl32.lib comdlg32.lib
|
||||
|
||||
putty.exe: $(OBJS1) $(OBJS2) $(OBJS3) $(RESRC) link.rsp
|
||||
link /debug -out:putty.exe @link.rsp
|
||||
|
||||
puttyd.exe: $(OBJS1) $(OBJS2) $(OBJS3) $(RESRC) link.rsp
|
||||
link /debug -out:puttyd.exe @link.rsp
|
||||
|
||||
link.rsp: makefile
|
||||
echo /nologo /subsystem:windows > link.rsp
|
||||
echo $(OBJS1) >> link.rsp
|
||||
echo $(OBJS2) >> link.rsp
|
||||
echo $(OBJS3) >> link.rsp
|
||||
echo $(RESRC) >> link.rsp
|
||||
echo $(LIBS1) >> link.rsp
|
||||
echo $(LIBS2) >> link.rsp
|
||||
|
||||
window.obj: window.c putty.h win_res.h
|
||||
windlg.obj: windlg.c putty.h ssh.h win_res.h
|
||||
terminal.obj: terminal.c putty.h
|
||||
telnet.obj: telnet.c putty.h
|
||||
misc.obj: misc.c putty.h
|
||||
noise.obj: noise.c putty.h ssh.h
|
||||
ssh.obj: ssh.c ssh.h putty.h
|
||||
sshcrc.obj: sshcrc.c ssh.h
|
||||
sshdes.obj: sshdes.c ssh.h
|
||||
sshmd5.obj: sshmd5.c ssh.h
|
||||
sshrsa.obj: sshrsa.c ssh.h
|
||||
sshsha.obj: sshsha.c ssh.h
|
||||
sshrand.obj: sshrand.c ssh.h
|
||||
|
||||
win_res.res: win_res.rc win_res.h putty.ico
|
||||
rc $(FWHACK) -r win_res.rc
|
||||
|
||||
clean:
|
||||
del *.obj
|
||||
del *.exe
|
||||
del *.res
|
||||
del *.pch
|
||||
del *.aps
|
||||
del *.ilk
|
||||
del *.pdb
|
||||
del link.rsp
|
67
misc.c
Normal file
67
misc.c
Normal file
@ -0,0 +1,67 @@
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "putty.h"
|
||||
|
||||
/* My own versions of malloc, realloc and free. Because I want malloc and
|
||||
* realloc to bomb out and exit the program if they run out of memory,
|
||||
* realloc to reliably call malloc if passed a NULL pointer, and free
|
||||
* to reliably do nothing if passed a NULL pointer. Of course we can also
|
||||
* put trace printouts in, if we need to. */
|
||||
|
||||
#ifdef MALLOC_LOG
|
||||
static FILE *fp = NULL;
|
||||
|
||||
void mlog(char *file, int line) {
|
||||
if (!fp)
|
||||
fp = fopen("putty_mem.log", "w");
|
||||
if (fp)
|
||||
fprintf (fp, "%s:%d: ", file, line);
|
||||
}
|
||||
#endif
|
||||
|
||||
void *safemalloc(size_t size) {
|
||||
void *p = malloc (size);
|
||||
if (!p) {
|
||||
MessageBox(NULL, "Out of memory!", "PuTTY Fatal Error",
|
||||
MB_SYSTEMMODAL | MB_ICONERROR | MB_OK);
|
||||
exit(1);
|
||||
}
|
||||
#ifdef MALLOC_LOG
|
||||
if (fp)
|
||||
fprintf(fp, "malloc(%d) returns %p\n", size, p);
|
||||
#endif
|
||||
return p;
|
||||
}
|
||||
|
||||
void *saferealloc(void *ptr, size_t size) {
|
||||
void *p;
|
||||
if (!ptr)
|
||||
p = malloc (size);
|
||||
else
|
||||
p = realloc (ptr, size);
|
||||
if (!p) {
|
||||
MessageBox(NULL, "Out of memory!", "PuTTY Fatal Error",
|
||||
MB_SYSTEMMODAL | MB_ICONERROR | MB_OK);
|
||||
exit(1);
|
||||
}
|
||||
#ifdef MALLOC_LOG
|
||||
if (fp)
|
||||
fprintf(fp, "realloc(%p,%d) returns %p\n", ptr, size, p);
|
||||
#endif
|
||||
return p;
|
||||
}
|
||||
|
||||
void safefree(void *ptr) {
|
||||
if (ptr) {
|
||||
#ifdef MALLOC_LOG
|
||||
if (fp)
|
||||
fprintf(fp, "free(%p)\n", ptr);
|
||||
#endif
|
||||
free (ptr);
|
||||
}
|
||||
#ifdef MALLOC_LOG
|
||||
else if (fp)
|
||||
fprintf(fp, "freeing null pointer - no action taken\n");
|
||||
#endif
|
||||
}
|
148
noise.c
Normal file
148
noise.c
Normal file
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Noise generation for PuTTY's cryptographic random number
|
||||
* generator.
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "putty.h"
|
||||
#include "ssh.h"
|
||||
|
||||
static char seedpath[2*MAX_PATH+10] = "\0";
|
||||
|
||||
/*
|
||||
* Find the random seed file path and store it in `seedpath'.
|
||||
*/
|
||||
static void get_seedpath(void) {
|
||||
HKEY rkey;
|
||||
DWORD type, size;
|
||||
|
||||
size = sizeof(seedpath);
|
||||
|
||||
if (RegOpenKey(HKEY_CURRENT_USER, PUTTY_REG_POS, &rkey)==ERROR_SUCCESS) {
|
||||
int ret = RegQueryValueEx(rkey, "RandSeedFile",
|
||||
0, &type, seedpath, &size);
|
||||
if (ret != ERROR_SUCCESS || type != REG_SZ)
|
||||
seedpath[0] = '\0';
|
||||
RegCloseKey(rkey);
|
||||
} else
|
||||
seedpath[0] = '\0';
|
||||
|
||||
if (!seedpath[0]) {
|
||||
int len, ret;
|
||||
|
||||
len = GetEnvironmentVariable("HOMEDRIVE", seedpath, sizeof(seedpath));
|
||||
ret = GetEnvironmentVariable("HOMEPATH", seedpath+len,
|
||||
sizeof(seedpath)-len);
|
||||
if (ret == 0) { /* probably win95; store in \WINDOWS */
|
||||
GetWindowsDirectory(seedpath, sizeof(seedpath));
|
||||
len = strlen(seedpath);
|
||||
} else
|
||||
len += ret;
|
||||
strcpy(seedpath+len, "\\PUTTY.RND");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called once, at PuTTY startup, and will do some
|
||||
* seriously silly things like listing directories and getting disk
|
||||
* free space and a process snapshot.
|
||||
*/
|
||||
|
||||
void noise_get_heavy(void (*func) (void *, int)) {
|
||||
HANDLE srch;
|
||||
HANDLE seedf;
|
||||
WIN32_FIND_DATA finddata;
|
||||
char winpath[MAX_PATH+3];
|
||||
|
||||
GetWindowsDirectory(winpath, sizeof(winpath));
|
||||
strcat(winpath, "\\*");
|
||||
srch = FindFirstFile(winpath, &finddata);
|
||||
if (srch != INVALID_HANDLE_VALUE) {
|
||||
do {
|
||||
func(&finddata, sizeof(finddata));
|
||||
} while (FindNextFile(srch, &finddata));
|
||||
FindClose(srch);
|
||||
}
|
||||
|
||||
if (!seedpath[0])
|
||||
get_seedpath();
|
||||
|
||||
seedf = CreateFile(seedpath, GENERIC_READ,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL, OPEN_EXISTING, 0, NULL);
|
||||
|
||||
if (seedf) {
|
||||
while (1) {
|
||||
char buf[1024];
|
||||
DWORD len;
|
||||
|
||||
if (ReadFile(seedf, buf, sizeof(buf), &len, NULL) && len)
|
||||
func(buf, len);
|
||||
else
|
||||
break;
|
||||
}
|
||||
CloseHandle(seedf);
|
||||
}
|
||||
}
|
||||
|
||||
void random_save_seed(void) {
|
||||
HANDLE seedf;
|
||||
|
||||
if (!seedpath[0])
|
||||
get_seedpath();
|
||||
|
||||
seedf = CreateFile(seedpath, GENERIC_WRITE, 0,
|
||||
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
if (seedf) {
|
||||
int len;
|
||||
DWORD lenwritten;
|
||||
void *data;
|
||||
|
||||
random_get_savedata(&data, &len);
|
||||
WriteFile(seedf, data, len, &lenwritten, NULL);
|
||||
CloseHandle(seedf);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called every time the random pool needs
|
||||
* stirring, and will acquire the system time in all available
|
||||
* forms and the battery status.
|
||||
*/
|
||||
void noise_get_light(void (*func) (void *, int)) {
|
||||
SYSTEMTIME systime;
|
||||
DWORD adjust[2];
|
||||
BOOL rubbish;
|
||||
SYSTEM_POWER_STATUS pwrstat;
|
||||
|
||||
GetSystemTime(&systime);
|
||||
func(&systime, sizeof(systime));
|
||||
|
||||
GetSystemTimeAdjustment(&adjust[0], &adjust[1], &rubbish);
|
||||
func(&adjust, sizeof(adjust));
|
||||
|
||||
if (GetSystemPowerStatus(&pwrstat))
|
||||
func(&pwrstat, sizeof(pwrstat));
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called on every keypress or mouse move, and
|
||||
* will add the current Windows time and performance monitor
|
||||
* counter to the noise pool. It gets the scan code or mouse
|
||||
* position passed in.
|
||||
*/
|
||||
void noise_ultralight(DWORD data) {
|
||||
DWORD wintime;
|
||||
LARGE_INTEGER perftime;
|
||||
|
||||
random_add_noise(&data, sizeof(DWORD));
|
||||
|
||||
wintime = GetTickCount();
|
||||
random_add_noise(&wintime, sizeof(DWORD));
|
||||
|
||||
if (QueryPerformanceCounter(&perftime))
|
||||
random_add_noise(&perftime, sizeof(perftime));
|
||||
}
|
252
putty.h
Normal file
252
putty.h
Normal file
@ -0,0 +1,252 @@
|
||||
#ifndef PUTTY_PUTTY_H
|
||||
#define PUTTY_PUTTY_H
|
||||
|
||||
#define PUTTY_REG_POS "Software\\SimonTatham\\PuTTY"
|
||||
|
||||
/*
|
||||
* Global variables. Most modules declare these `extern', but
|
||||
* window.c will do `#define PUTTY_DO_GLOBALS' before including this
|
||||
* module, and so will get them properly defined.
|
||||
*/
|
||||
#ifdef PUTTY_DO_GLOBALS
|
||||
#define GLOBAL
|
||||
#else
|
||||
#define GLOBAL extern
|
||||
#endif
|
||||
|
||||
#define ATTR_ACTCURS 0x80000000UL /* active cursor (block) */
|
||||
#define ATTR_PASCURS 0x40000000UL /* passive cursor (box) */
|
||||
#define ATTR_INVALID 0x20000000UL
|
||||
#define ATTR_WRAPPED 0x10000000UL
|
||||
|
||||
#define ATTR_ASCII 0x00000000UL /* normal ASCII charset ESC ( B */
|
||||
#define ATTR_GBCHR 0x00100000UL /* UK variant charset ESC ( A */
|
||||
#define ATTR_LINEDRW 0x00200000UL /* line drawing charset ESC ( 0 */
|
||||
|
||||
#define ATTR_BOLD 0x00000100UL
|
||||
#define ATTR_UNDER 0x00000200UL
|
||||
#define ATTR_REVERSE 0x00000400UL
|
||||
#define ATTR_FGMASK 0x0000F000UL
|
||||
#define ATTR_BGMASK 0x000F0000UL
|
||||
#define ATTR_FGSHIFT 12
|
||||
#define ATTR_BGSHIFT 16
|
||||
|
||||
#define ATTR_DEFAULT 0x00098000UL
|
||||
#define ATTR_DEFFG 0x00008000UL
|
||||
#define ATTR_DEFBG 0x00090000UL
|
||||
#define ATTR_CUR_XOR 0x000BA000UL
|
||||
#define ERASE_CHAR (ATTR_DEFAULT | ' ')
|
||||
#define ATTR_MASK 0xFFFFFF00UL
|
||||
#define CHAR_MASK 0x000000FFUL
|
||||
|
||||
typedef HDC Context;
|
||||
#define SEL_NL { 13, 10 }
|
||||
|
||||
GLOBAL int rows, cols, savelines;
|
||||
|
||||
GLOBAL int font_width, font_height;
|
||||
|
||||
#define INBUF_SIZE 2048
|
||||
#define INBUF_MASK (INBUF_SIZE-1)
|
||||
GLOBAL unsigned char inbuf[INBUF_SIZE];
|
||||
GLOBAL int inbuf_head, inbuf_reap;
|
||||
|
||||
#define OUTBUF_SIZE 2048
|
||||
#define OUTBUF_MASK (OUTBUF_SIZE-1)
|
||||
GLOBAL unsigned char outbuf[OUTBUF_SIZE];
|
||||
GLOBAL int outbuf_head, outbuf_reap;
|
||||
|
||||
GLOBAL int has_focus;
|
||||
|
||||
GLOBAL int app_cursor_keys, app_keypad_keys;
|
||||
|
||||
#define WM_NETEVENT (WM_USER + 1)
|
||||
|
||||
typedef enum {
|
||||
TS_AYT, TS_BRK, TS_SYNCH, TS_EC, TS_EL, TS_GA, TS_NOP, TS_ABORT,
|
||||
TS_AO, TS_IP, TS_SUSP, TS_EOR, TS_EOF
|
||||
} Telnet_Special;
|
||||
|
||||
typedef enum {
|
||||
MB_NOTHING, MB_SELECT, MB_EXTEND, MB_PASTE
|
||||
} Mouse_Button;
|
||||
|
||||
typedef enum {
|
||||
MA_NOTHING, MA_CLICK, MA_2CLK, MA_3CLK, MA_DRAG, MA_RELEASE
|
||||
} Mouse_Action;
|
||||
|
||||
typedef enum {
|
||||
VT_XWINDOWS, VT_OEMANSI, VT_OEMONLY, VT_POORMAN
|
||||
} VT_Mode;
|
||||
|
||||
typedef struct {
|
||||
char *(*init) (HWND hwnd, char *host, int port, char **realhost);
|
||||
int (*msg) (WPARAM wParam, LPARAM lParam);
|
||||
void (*send) (char *buf, int len);
|
||||
void (*size) (void);
|
||||
void (*special) (Telnet_Special code);
|
||||
} Backend;
|
||||
|
||||
GLOBAL Backend *back;
|
||||
|
||||
typedef struct {
|
||||
/* Basic options */
|
||||
char host[512];
|
||||
int port;
|
||||
enum { PROT_TELNET, PROT_SSH } protocol;
|
||||
int close_on_exit;
|
||||
/* Telnet options */
|
||||
char termtype[32];
|
||||
char termspeed[32];
|
||||
char environ[1024]; /* VAR\tvalue\0VAR\tvalue\0\0 */
|
||||
char username[32];
|
||||
int rfc_environ;
|
||||
/* Keyboard options */
|
||||
int bksp_is_delete;
|
||||
int rxvt_homeend;
|
||||
int linux_funkeys;
|
||||
int app_cursor;
|
||||
int app_keypad;
|
||||
/* Terminal options */
|
||||
int savelines;
|
||||
int dec_om;
|
||||
int wrap_mode;
|
||||
int win_name_always;
|
||||
int width, height;
|
||||
char font[64];
|
||||
int fontisbold;
|
||||
int fontheight;
|
||||
VT_Mode vtmode;
|
||||
/* Colour options */
|
||||
int try_palette;
|
||||
int bold_colour;
|
||||
unsigned char colours[22][3];
|
||||
/* Selection options */
|
||||
int mouse_is_xterm;
|
||||
short wordness[256];
|
||||
} Config;
|
||||
|
||||
GLOBAL Config cfg;
|
||||
|
||||
/*
|
||||
* Exports from window.c.
|
||||
*/
|
||||
void request_resize (int, int);
|
||||
void do_text (Context, int, int, char *, int, unsigned long);
|
||||
void set_title (char *);
|
||||
void set_icon (char *);
|
||||
void set_sbar (int, int, int);
|
||||
Context get_ctx();
|
||||
void free_ctx (Context);
|
||||
void palette_set (int, int, int, int);
|
||||
void palette_reset (void);
|
||||
void write_clip (void *, int);
|
||||
void get_clip (void **, int *);
|
||||
void optimised_move (int, int, int);
|
||||
void fatalbox (char *, ...);
|
||||
void beep (void);
|
||||
#define OPTIMISE_IS_SCROLL 1
|
||||
|
||||
/*
|
||||
* Exports from noise.c.
|
||||
*/
|
||||
void noise_get_heavy(void (*func) (void *, int));
|
||||
void noise_get_light(void (*func) (void *, int));
|
||||
void noise_ultralight(DWORD data);
|
||||
void random_save_seed(void);
|
||||
|
||||
/*
|
||||
* Exports from windlg.c.
|
||||
*/
|
||||
int do_config (void);
|
||||
int do_reconfig (HWND);
|
||||
void do_defaults (char *);
|
||||
void lognegot (char *);
|
||||
void shownegot (HWND);
|
||||
void showabout (HWND);
|
||||
void verify_ssh_host_key(char *host, struct RSAKey *key);
|
||||
|
||||
/*
|
||||
* Exports from terminal.c.
|
||||
*/
|
||||
|
||||
void term_init (void);
|
||||
void term_size (int, int, int);
|
||||
void term_out (void);
|
||||
void term_paint (Context, int, int, int, int);
|
||||
void term_scroll (int, int);
|
||||
void term_pwron (void);
|
||||
void term_clrsb (void);
|
||||
void term_mouse (Mouse_Button, Mouse_Action, int, int);
|
||||
void term_deselect (void);
|
||||
void term_update (void);
|
||||
void term_invalidate(void);
|
||||
|
||||
/*
|
||||
* Exports from telnet.c.
|
||||
*/
|
||||
|
||||
Backend telnet_backend;
|
||||
|
||||
/*
|
||||
* Exports from ssh.c.
|
||||
*/
|
||||
|
||||
Backend ssh_backend;
|
||||
|
||||
/*
|
||||
* Exports from sshrand.c.
|
||||
*/
|
||||
|
||||
void random_add_noise(void *noise, int length);
|
||||
void random_init(void);
|
||||
int random_byte(void);
|
||||
void random_get_savedata(void **data, int *len);
|
||||
|
||||
/*
|
||||
* Exports from misc.c.
|
||||
*/
|
||||
|
||||
/* #define MALLOC_LOG do this if you suspect putty of leaking memory */
|
||||
#ifdef MALLOC_LOG
|
||||
#define smalloc(z) (mlog(__FILE__,__LINE__), safemalloc(z))
|
||||
#define srealloc(y,z) (mlog(__FILE__,__LINE__), saferealloc(y,z))
|
||||
#define sfree(z) (mlog(__FILE__,__LINE__), safefree(z))
|
||||
void mlog(char *, int);
|
||||
#else
|
||||
#define smalloc safemalloc
|
||||
#define srealloc saferealloc
|
||||
#define sfree safefree
|
||||
#endif
|
||||
|
||||
void *safemalloc(size_t);
|
||||
void *saferealloc(void *, size_t);
|
||||
void safefree(void *);
|
||||
|
||||
/*
|
||||
* A debug system.
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
#include <stdarg.h>
|
||||
#define debug(x) (dprintf x)
|
||||
static void dprintf(char *fmt, ...) {
|
||||
char buf[2048];
|
||||
DWORD dw;
|
||||
va_list ap;
|
||||
static int gotconsole = 0;
|
||||
|
||||
if (!gotconsole) {
|
||||
AllocConsole();
|
||||
gotconsole = 1;
|
||||
}
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsprintf(buf, fmt, ap);
|
||||
WriteFile (GetStdHandle(STD_OUTPUT_HANDLE), buf, strlen(buf), &dw, NULL);
|
||||
va_end(ap);
|
||||
}
|
||||
#else
|
||||
#define debug(x)
|
||||
#endif
|
||||
|
||||
#endif
|
15
resource.h
Normal file
15
resource.h
Normal file
@ -0,0 +1,15 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Developer Studio generated include file.
|
||||
// Used by win_res.rc
|
||||
//
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 101
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1000
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
694
ssh.c
Normal file
694
ssh.c
Normal file
@ -0,0 +1,694 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <winsock.h>
|
||||
|
||||
#include "putty.h"
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#include "ssh.h"
|
||||
|
||||
/* Coroutine mechanics for the sillier bits of the code */
|
||||
#define crBegin1 static int crLine = 0;
|
||||
#define crBegin2 switch(crLine) { case 0:;
|
||||
#define crBegin crBegin1; crBegin2;
|
||||
#define crFinish(z) } crLine = 0; return (z)
|
||||
#define crFinishV } crLine = 0; return
|
||||
#define crReturn(z) \
|
||||
do {\
|
||||
crLine=__LINE__; return (z); case __LINE__:;\
|
||||
} while (0)
|
||||
#define crReturnV \
|
||||
do {\
|
||||
crLine=__LINE__; return; case __LINE__:;\
|
||||
} while (0)
|
||||
#define crStop(z) do{ crLine = 0; return (z); }while(0)
|
||||
#define crStopV do{ crLine = 0; return; }while(0)
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
static SOCKET s = INVALID_SOCKET;
|
||||
|
||||
static unsigned char session_key[32];
|
||||
static struct ssh_cipher *cipher = NULL;
|
||||
|
||||
static char *savedhost;
|
||||
|
||||
static enum {
|
||||
SSH_STATE_BEFORE_SIZE,
|
||||
SSH_STATE_INTERMED,
|
||||
SSH_STATE_SESSION
|
||||
} ssh_state = SSH_STATE_BEFORE_SIZE;
|
||||
|
||||
static int size_needed = FALSE;
|
||||
|
||||
static void s_write (char *buf, int len) {
|
||||
while (len > 0) {
|
||||
int i = send (s, buf, len, 0);
|
||||
if (i > 0)
|
||||
len -= i, buf += i;
|
||||
}
|
||||
}
|
||||
|
||||
static int s_read (char *buf, int len) {
|
||||
int ret = 0;
|
||||
while (len > 0) {
|
||||
int i = recv (s, buf, len, 0);
|
||||
if (i > 0)
|
||||
len -= i, buf += i, ret += i;
|
||||
else
|
||||
return i;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void c_write (char *buf, int len) {
|
||||
while (len--) {
|
||||
int new_head = (inbuf_head + 1) & INBUF_MASK;
|
||||
int c = (unsigned char) *buf;
|
||||
if (new_head != inbuf_reap) {
|
||||
inbuf[inbuf_head] = *buf++;
|
||||
inbuf_head = new_head;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Packet {
|
||||
long length;
|
||||
int type;
|
||||
unsigned long crc;
|
||||
unsigned char *data;
|
||||
unsigned char *body;
|
||||
long maxlen;
|
||||
};
|
||||
|
||||
static struct Packet pktin = { 0, 0, 0, NULL, 0 };
|
||||
static struct Packet pktout = { 0, 0, 0, NULL, 0 };
|
||||
|
||||
static void ssh_protocol(unsigned char *in, int inlen, int ispkt);
|
||||
static void ssh_size(void);
|
||||
|
||||
static void ssh_gotdata(unsigned char *data, int datalen) {
|
||||
static long len, biglen, to_read;
|
||||
static unsigned char c, *p;
|
||||
static int i, pad;
|
||||
static char padding[8];
|
||||
static unsigned char word[4];
|
||||
|
||||
crBegin;
|
||||
while (1) {
|
||||
for (i = len = 0; i < 4; i++) {
|
||||
while (datalen == 0)
|
||||
crReturnV;
|
||||
len = (len << 8) + *data;
|
||||
data++, datalen--;
|
||||
}
|
||||
|
||||
pad = 8 - (len%8);
|
||||
|
||||
biglen = len + pad;
|
||||
|
||||
len -= 5; /* type and CRC */
|
||||
|
||||
pktin.length = len;
|
||||
if (pktin.maxlen < biglen) {
|
||||
pktin.maxlen = biglen;
|
||||
pktin.data = (pktin.data == NULL ? malloc(biglen) :
|
||||
realloc(pktin.data, biglen));
|
||||
if (!pktin.data)
|
||||
fatalbox("Out of memory");
|
||||
}
|
||||
|
||||
p = pktin.data, to_read = biglen;
|
||||
while (to_read > 0) {
|
||||
static int chunk;
|
||||
chunk = to_read;
|
||||
while (datalen == 0)
|
||||
crReturnV;
|
||||
if (chunk > datalen)
|
||||
chunk = datalen;
|
||||
memcpy(p, data, chunk);
|
||||
data += chunk;
|
||||
datalen -= chunk;
|
||||
p += chunk;
|
||||
to_read -= chunk;
|
||||
}
|
||||
|
||||
if (cipher)
|
||||
cipher->decrypt(pktin.data, biglen);
|
||||
|
||||
pktin.type = pktin.data[pad];
|
||||
pktin.body = pktin.data+pad+1;
|
||||
|
||||
if (pktin.type == 36) { /* SSH_MSG_DEBUG */
|
||||
/* FIXME: log it */
|
||||
} else
|
||||
ssh_protocol(NULL, 0, 1);
|
||||
}
|
||||
crFinishV;
|
||||
}
|
||||
|
||||
static void s_wrpkt_start(int type, int len) {
|
||||
int pad, biglen;
|
||||
|
||||
len += 5; /* type and CRC */
|
||||
pad = 8 - (len%8);
|
||||
biglen = len + pad;
|
||||
|
||||
pktout.length = len-5;
|
||||
if (pktout.maxlen < biglen) {
|
||||
pktout.maxlen = biglen;
|
||||
pktout.data = (pktout.data == NULL ? malloc(biglen) :
|
||||
realloc(pktout.data, biglen));
|
||||
if (!pktout.data)
|
||||
fatalbox("Out of memory");
|
||||
}
|
||||
|
||||
pktout.type = type;
|
||||
pktout.body = pktout.data+4+pad+1;
|
||||
}
|
||||
|
||||
static void s_wrpkt(void) {
|
||||
int pad, len, biglen, i;
|
||||
unsigned long crc;
|
||||
|
||||
len = pktout.length + 5; /* type and CRC */
|
||||
pad = 8 - (len%8);
|
||||
biglen = len + pad;
|
||||
|
||||
pktout.body[-1] = pktout.type;
|
||||
for (i=0; i<pad; i++)
|
||||
pktout.data[i+4] = random_byte();
|
||||
crc = crc32(pktout.data+4, biglen-4);
|
||||
|
||||
pktout.data[biglen+0] = (unsigned char) ((crc >> 24) & 0xFF);
|
||||
pktout.data[biglen+1] = (unsigned char) ((crc >> 16) & 0xFF);
|
||||
pktout.data[biglen+2] = (unsigned char) ((crc >> 8) & 0xFF);
|
||||
pktout.data[biglen+3] = (unsigned char) (crc & 0xFF);
|
||||
|
||||
pktout.data[0] = (len >> 24) & 0xFF;
|
||||
pktout.data[1] = (len >> 16) & 0xFF;
|
||||
pktout.data[2] = (len >> 8) & 0xFF;
|
||||
pktout.data[3] = len & 0xFF;
|
||||
|
||||
if (cipher)
|
||||
cipher->encrypt(pktout.data+4, biglen);
|
||||
|
||||
s_write(pktout.data, biglen+4);
|
||||
}
|
||||
|
||||
static int do_ssh_init(void) {
|
||||
char c;
|
||||
char version[10];
|
||||
char vstring[40];
|
||||
int i;
|
||||
|
||||
#ifdef FWHACK
|
||||
i = 0;
|
||||
while (s_read(&c, 1) == 1) {
|
||||
if (c == 'S' && i < 2) i++;
|
||||
else if (c == 'S' && i == 2) i = 2;
|
||||
else if (c == 'H' && i == 2) break;
|
||||
else i = 0;
|
||||
}
|
||||
#else
|
||||
if (s_read(&c,1) != 1 || c != 'S') return 0;
|
||||
if (s_read(&c,1) != 1 || c != 'S') return 0;
|
||||
if (s_read(&c,1) != 1 || c != 'H') return 0;
|
||||
#endif
|
||||
if (s_read(&c,1) != 1 || c != '-') return 0;
|
||||
i = 0;
|
||||
while (1) {
|
||||
if (s_read(&c,1) != 1)
|
||||
return 0;
|
||||
if (i >= 0) {
|
||||
if (c == '-') {
|
||||
version[i] = '\0';
|
||||
i = -1;
|
||||
} else if (i < sizeof(version)-1)
|
||||
version[i++] = c;
|
||||
}
|
||||
else if (c == '\n')
|
||||
break;
|
||||
}
|
||||
|
||||
sprintf(vstring, "SSH-%s-7.7.7\n",
|
||||
(strcmp(version, "1.5") <= 0 ? version : "1.5"));
|
||||
s_write(vstring, strlen(vstring));
|
||||
}
|
||||
|
||||
static void ssh_protocol(unsigned char *in, int inlen, int ispkt) {
|
||||
int i, j, len;
|
||||
unsigned char session_id[16];
|
||||
unsigned char *rsabuf, *keystr1, *keystr2;
|
||||
unsigned char cookie[8];
|
||||
struct RSAKey servkey, hostkey;
|
||||
struct MD5Context md5c;
|
||||
|
||||
extern struct ssh_cipher ssh_3des;
|
||||
|
||||
crBegin;
|
||||
|
||||
random_init();
|
||||
|
||||
while (!ispkt)
|
||||
crReturnV;
|
||||
|
||||
if (pktin.type != 2)
|
||||
fatalbox("Public key packet not received");
|
||||
|
||||
memcpy(cookie, pktin.body, 8);
|
||||
|
||||
MD5Init(&md5c);
|
||||
|
||||
i = makekey(pktin.body+8, &servkey, &keystr1);
|
||||
|
||||
j = makekey(pktin.body+8+i, &hostkey, &keystr2);
|
||||
|
||||
MD5Update(&md5c, keystr2, hostkey.bytes);
|
||||
MD5Update(&md5c, keystr1, servkey.bytes);
|
||||
MD5Update(&md5c, pktin.body, 8);
|
||||
|
||||
MD5Final(session_id, &md5c);
|
||||
|
||||
for (i=0; i<32; i++)
|
||||
session_key[i] = random_byte();
|
||||
|
||||
len = (hostkey.bytes > servkey.bytes ? hostkey.bytes : servkey.bytes);
|
||||
|
||||
rsabuf = malloc(len);
|
||||
if (!rsabuf)
|
||||
fatalbox("Out of memory");
|
||||
|
||||
verify_ssh_host_key(savedhost, &hostkey);
|
||||
|
||||
for (i=0; i<32; i++) {
|
||||
rsabuf[i] = session_key[i];
|
||||
if (i < 16)
|
||||
rsabuf[i] ^= session_id[i];
|
||||
}
|
||||
|
||||
if (hostkey.bytes > servkey.bytes) {
|
||||
rsaencrypt(rsabuf, 32, &servkey);
|
||||
rsaencrypt(rsabuf, servkey.bytes, &hostkey);
|
||||
} else {
|
||||
rsaencrypt(rsabuf, 32, &hostkey);
|
||||
rsaencrypt(rsabuf, hostkey.bytes, &servkey);
|
||||
}
|
||||
|
||||
s_wrpkt_start(3, len+15);
|
||||
pktout.body[0] = 3; /* SSH_CIPHER_3DES */
|
||||
memcpy(pktout.body+1, cookie, 8);
|
||||
pktout.body[9] = (len*8) >> 8;
|
||||
pktout.body[10] = (len*8) & 0xFF;
|
||||
memcpy(pktout.body+11, rsabuf, len);
|
||||
pktout.body[len+11] = pktout.body[len+12] = 0; /* protocol flags */
|
||||
pktout.body[len+13] = pktout.body[len+14] = 0;
|
||||
s_wrpkt();
|
||||
|
||||
free(rsabuf);
|
||||
|
||||
cipher = &ssh_3des;
|
||||
cipher->sesskey(session_key);
|
||||
|
||||
do { crReturnV; } while (!ispkt);
|
||||
|
||||
if (pktin.type != 14)
|
||||
fatalbox("Encryption not successfully enabled");
|
||||
|
||||
fflush(stdout);
|
||||
{
|
||||
static char username[100];
|
||||
static int pos = 0;
|
||||
static char c;
|
||||
if (!*cfg.username) {
|
||||
c_write("login as: ", 10);
|
||||
while (pos >= 0) {
|
||||
do { crReturnV; } while (ispkt);
|
||||
while (inlen--) switch (c = *in++) {
|
||||
case 10: case 13:
|
||||
username[pos] = 0;
|
||||
pos = -1;
|
||||
break;
|
||||
case 8: case 127:
|
||||
if (pos > 0) {
|
||||
c_write("\b \b", 3);
|
||||
pos--;
|
||||
}
|
||||
break;
|
||||
case 21: case 27:
|
||||
while (pos > 0) {
|
||||
c_write("\b \b", 3);
|
||||
pos--;
|
||||
}
|
||||
break;
|
||||
case 3: case 4:
|
||||
random_save_seed();
|
||||
exit(0);
|
||||
break;
|
||||
default:
|
||||
if (c >= ' ' && c <= '~' && pos < 40) {
|
||||
username[pos++] = c;
|
||||
c_write(&c, 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
c_write("\r\n", 2);
|
||||
username[strcspn(username, "\n\r")] = '\0';
|
||||
} else {
|
||||
char stuff[200];
|
||||
strncpy(username, cfg.username, 99);
|
||||
username[99] = '\0';
|
||||
sprintf(stuff, "Sent username \"%s\".\r\n", username);
|
||||
c_write(stuff, strlen(stuff));
|
||||
}
|
||||
s_wrpkt_start(4, 4+strlen(username));
|
||||
pktout.body[0] = pktout.body[1] = pktout.body[2] = 0;
|
||||
pktout.body[3] = strlen(username);
|
||||
memcpy(pktout.body+4, username, strlen(username));
|
||||
s_wrpkt();
|
||||
}
|
||||
|
||||
do { crReturnV; } while (!ispkt);
|
||||
|
||||
while (pktin.type == 15) {
|
||||
static char password[100];
|
||||
static int pos;
|
||||
static char c;
|
||||
c_write("password: ", 10);
|
||||
pos = 0;
|
||||
while (pos >= 0) {
|
||||
do { crReturnV; } while (ispkt);
|
||||
while (inlen--) switch (c = *in++) {
|
||||
case 10: case 13:
|
||||
password[pos] = 0;
|
||||
pos = -1;
|
||||
break;
|
||||
case 8: case 127:
|
||||
if (pos > 0)
|
||||
pos--;
|
||||
break;
|
||||
case 21: case 27:
|
||||
pos = 0;
|
||||
break;
|
||||
case 3: case 4:
|
||||
random_save_seed();
|
||||
exit(0);
|
||||
break;
|
||||
default:
|
||||
if (c >= ' ' && c <= '~' && pos < 40)
|
||||
password[pos++] = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
c_write("\r\n", 2);
|
||||
s_wrpkt_start(9, 4+strlen(password));
|
||||
pktout.body[0] = pktout.body[1] = pktout.body[2] = 0;
|
||||
pktout.body[3] = strlen(password);
|
||||
memcpy(pktout.body+4, password, strlen(password));
|
||||
s_wrpkt();
|
||||
memset(password, 0, strlen(password));
|
||||
do { crReturnV; } while (!ispkt);
|
||||
if (pktin.type == 15) {
|
||||
c_write("Access denied\r\n", 15);
|
||||
} else if (pktin.type != 14) {
|
||||
fatalbox("Strange packet received, type %d", pktin.type);
|
||||
}
|
||||
}
|
||||
|
||||
i = strlen(cfg.termtype);
|
||||
s_wrpkt_start(10, i+5*4+1);
|
||||
pktout.body[0] = (i >> 24) & 0xFF;
|
||||
pktout.body[1] = (i >> 16) & 0xFF;
|
||||
pktout.body[2] = (i >> 8) & 0xFF;
|
||||
pktout.body[3] = i & 0xFF;
|
||||
memcpy(pktout.body+4, cfg.termtype, i);
|
||||
i += 4;
|
||||
pktout.body[i++] = (rows >> 24) & 0xFF;
|
||||
pktout.body[i++] = (rows >> 16) & 0xFF;
|
||||
pktout.body[i++] = (rows >> 8) & 0xFF;
|
||||
pktout.body[i++] = rows & 0xFF;
|
||||
pktout.body[i++] = (cols >> 24) & 0xFF;
|
||||
pktout.body[i++] = (cols >> 16) & 0xFF;
|
||||
pktout.body[i++] = (cols >> 8) & 0xFF;
|
||||
pktout.body[i++] = cols & 0xFF;
|
||||
memset(pktout.body+i, 0, 9); /* 0 pixwidth, 0 pixheight, 0.b endofopt */
|
||||
s_wrpkt();
|
||||
ssh_state = SSH_STATE_INTERMED;
|
||||
do { crReturnV; } while (!ispkt);
|
||||
if (pktin.type != 14 && pktin.type != 15) {
|
||||
fatalbox("Protocol confusion");
|
||||
} else if (pktin.type == 15) {
|
||||
c_write("Server refused to allocate pty\r\n", 32);
|
||||
}
|
||||
|
||||
s_wrpkt_start(12, 0);
|
||||
s_wrpkt();
|
||||
|
||||
ssh_state = SSH_STATE_SESSION;
|
||||
if (size_needed)
|
||||
ssh_size();
|
||||
|
||||
while (1) {
|
||||
crReturnV;
|
||||
if (ispkt) {
|
||||
if (pktin.type == 17 || pktin.type == 18) {
|
||||
long len = 0;
|
||||
for (i = 0; i < 4; i++)
|
||||
len = (len << 8) + pktin.body[i];
|
||||
c_write(pktin.body+4, len);
|
||||
} else if (pktin.type == 1) {
|
||||
/* SSH_MSG_DISCONNECT: do nothing */
|
||||
} else if (pktin.type == 14) {
|
||||
/* SSH_MSG_SUCCESS: may be from EXEC_SHELL on some servers */
|
||||
} else if (pktin.type == 15) {
|
||||
/* SSH_MSG_FAILURE: may be from EXEC_SHELL on some servers
|
||||
* if no pty is available or in other odd cases. Ignore */
|
||||
} else if (pktin.type == 20) {
|
||||
/* EXITSTATUS */
|
||||
s_wrpkt_start(33, 0);
|
||||
s_wrpkt();
|
||||
} else {
|
||||
fatalbox("Strange packet received: type %d", pktin.type);
|
||||
}
|
||||
} else {
|
||||
s_wrpkt_start(16, 4+inlen);
|
||||
pktout.body[0] = (inlen >> 24) & 0xFF;
|
||||
pktout.body[1] = (inlen >> 16) & 0xFF;
|
||||
pktout.body[2] = (inlen >> 8) & 0xFF;
|
||||
pktout.body[3] = inlen & 0xFF;
|
||||
memcpy(pktout.body+4, in, inlen);
|
||||
s_wrpkt();
|
||||
}
|
||||
}
|
||||
|
||||
crFinishV;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called to set up the connection. Will arrange for WM_NETEVENT
|
||||
* messages to be passed to the specified window, whose window
|
||||
* procedure should then call telnet_msg().
|
||||
*
|
||||
* Returns an error message, or NULL on success.
|
||||
*
|
||||
* Also places the canonical host name into `realhost'.
|
||||
*/
|
||||
static char *ssh_init (HWND hwnd, char *host, int port, char **realhost) {
|
||||
SOCKADDR_IN addr;
|
||||
struct hostent *h;
|
||||
unsigned long a;
|
||||
#ifdef FWHACK
|
||||
char *FWhost;
|
||||
int FWport;
|
||||
#endif
|
||||
|
||||
savedhost = malloc(1+strlen(host));
|
||||
if (!savedhost)
|
||||
fatalbox("Out of memory");
|
||||
strcpy(savedhost, host);
|
||||
|
||||
#ifdef FWHACK
|
||||
FWhost = host;
|
||||
FWport = port;
|
||||
host = FWSTR;
|
||||
port = 23;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Try to find host.
|
||||
*/
|
||||
if ( (a = inet_addr(host)) == (unsigned long) INADDR_NONE) {
|
||||
if ( (h = gethostbyname(host)) == NULL)
|
||||
switch (WSAGetLastError()) {
|
||||
case WSAENETDOWN: return "Network is down";
|
||||
case WSAHOST_NOT_FOUND: case WSANO_DATA:
|
||||
return "Host does not exist";
|
||||
case WSATRY_AGAIN: return "Host not found";
|
||||
default: return "gethostbyname: unknown error";
|
||||
}
|
||||
memcpy (&a, h->h_addr, sizeof(a));
|
||||
*realhost = h->h_name;
|
||||
} else
|
||||
*realhost = host;
|
||||
#ifdef FWHACK
|
||||
*realhost = FWhost;
|
||||
#endif
|
||||
a = ntohl(a);
|
||||
|
||||
if (port < 0)
|
||||
port = 22; /* default ssh port */
|
||||
|
||||
/*
|
||||
* Open socket.
|
||||
*/
|
||||
s = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (s == INVALID_SOCKET)
|
||||
switch (WSAGetLastError()) {
|
||||
case WSAENETDOWN: return "Network is down";
|
||||
case WSAEAFNOSUPPORT: return "TCP/IP support not present";
|
||||
default: return "socket(): unknown error";
|
||||
}
|
||||
|
||||
/*
|
||||
* Bind to local address.
|
||||
*/
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
addr.sin_port = htons(0);
|
||||
if (bind (s, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR)
|
||||
switch (WSAGetLastError()) {
|
||||
case WSAENETDOWN: return "Network is down";
|
||||
default: return "bind(): unknown error";
|
||||
}
|
||||
|
||||
/*
|
||||
* Connect to remote address.
|
||||
*/
|
||||
addr.sin_addr.s_addr = htonl(a);
|
||||
addr.sin_port = htons((short)port);
|
||||
if (connect (s, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR)
|
||||
switch (WSAGetLastError()) {
|
||||
case WSAENETDOWN: return "Network is down";
|
||||
case WSAECONNREFUSED: return "Connection refused";
|
||||
case WSAENETUNREACH: return "Network is unreachable";
|
||||
case WSAEHOSTUNREACH: return "No route to host";
|
||||
default: return "connect(): unknown error";
|
||||
}
|
||||
|
||||
#ifdef FWHACK
|
||||
send(s, "connect ", 8, 0);
|
||||
send(s, FWhost, strlen(FWhost), 0);
|
||||
{
|
||||
char buf[20];
|
||||
sprintf(buf, " %d\n", FWport);
|
||||
send (s, buf, strlen(buf), 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!do_ssh_init())
|
||||
return "Protocol initialisation error";
|
||||
|
||||
if (WSAAsyncSelect (s, hwnd, WM_NETEVENT, FD_READ | FD_CLOSE) == SOCKET_ERROR)
|
||||
switch (WSAGetLastError()) {
|
||||
case WSAENETDOWN: return "Network is down";
|
||||
default: return "WSAAsyncSelect(): unknown error";
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Process a WM_NETEVENT message. Will return 0 if the connection
|
||||
* has closed, or <0 for a socket error.
|
||||
*/
|
||||
static int ssh_msg (WPARAM wParam, LPARAM lParam) {
|
||||
int ret;
|
||||
char buf[256];
|
||||
|
||||
if (s == INVALID_SOCKET) /* how the hell did we get here?! */
|
||||
return -5000;
|
||||
|
||||
if (WSAGETSELECTERROR(lParam) != 0)
|
||||
return -WSAGETSELECTERROR(lParam);
|
||||
|
||||
switch (WSAGETSELECTEVENT(lParam)) {
|
||||
case FD_READ:
|
||||
ret = recv(s, buf, sizeof(buf), 0);
|
||||
if (ret < 0 && WSAGetLastError() == WSAEWOULDBLOCK)
|
||||
return 1;
|
||||
if (ret < 0) /* any _other_ error */
|
||||
return -10000-WSAGetLastError();
|
||||
if (ret == 0) {
|
||||
s = INVALID_SOCKET;
|
||||
return 0; /* can't happen, in theory */
|
||||
}
|
||||
ssh_gotdata (buf, ret);
|
||||
return 1;
|
||||
case FD_CLOSE:
|
||||
s = INVALID_SOCKET;
|
||||
return 0;
|
||||
}
|
||||
return 1; /* shouldn't happen, but WTF */
|
||||
}
|
||||
|
||||
/*
|
||||
* Called to send data down the Telnet connection.
|
||||
*/
|
||||
static void ssh_send (char *buf, int len) {
|
||||
if (s == INVALID_SOCKET)
|
||||
return;
|
||||
|
||||
ssh_protocol(buf, len, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called to set the size of the window from Telnet's POV.
|
||||
*/
|
||||
static void ssh_size(void) {
|
||||
switch (ssh_state) {
|
||||
case SSH_STATE_BEFORE_SIZE:
|
||||
break; /* do nothing */
|
||||
case SSH_STATE_INTERMED:
|
||||
size_needed = TRUE; /* buffer for later */
|
||||
break;
|
||||
case SSH_STATE_SESSION:
|
||||
s_wrpkt_start(11, 16);
|
||||
pktout.body[0] = (rows >> 24) & 0xFF;
|
||||
pktout.body[1] = (rows >> 16) & 0xFF;
|
||||
pktout.body[2] = (rows >> 8) & 0xFF;
|
||||
pktout.body[3] = rows & 0xFF;
|
||||
pktout.body[4] = (cols >> 24) & 0xFF;
|
||||
pktout.body[5] = (cols >> 16) & 0xFF;
|
||||
pktout.body[6] = (cols >> 8) & 0xFF;
|
||||
pktout.body[7] = cols & 0xFF;
|
||||
memset(pktout.body+8, 0, 8);
|
||||
s_wrpkt();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (Send Telnet special codes)
|
||||
*/
|
||||
static void ssh_special (Telnet_Special code) {
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
Backend ssh_backend = {
|
||||
ssh_init,
|
||||
ssh_msg,
|
||||
ssh_send,
|
||||
ssh_size,
|
||||
ssh_special
|
||||
};
|
39
ssh.h
Normal file
39
ssh.h
Normal file
@ -0,0 +1,39 @@
|
||||
struct RSAKey {
|
||||
int bits;
|
||||
int bytes;
|
||||
void *modulus;
|
||||
void *exponent;
|
||||
};
|
||||
|
||||
int makekey(unsigned char *data, struct RSAKey *result,
|
||||
unsigned char **keystr);
|
||||
void rsaencrypt(unsigned char *data, int length, struct RSAKey *key);
|
||||
int rsastr_len(struct RSAKey *key);
|
||||
void rsastr_fmt(char *str, struct RSAKey *key);
|
||||
|
||||
typedef unsigned int word32;
|
||||
typedef unsigned int uint32;
|
||||
|
||||
unsigned long crc32(const unsigned char *s, unsigned int len);
|
||||
|
||||
struct MD5Context {
|
||||
uint32 buf[4];
|
||||
uint32 bits[2];
|
||||
unsigned char in[64];
|
||||
};
|
||||
|
||||
void MD5Init(struct MD5Context *context);
|
||||
void MD5Update(struct MD5Context *context, unsigned char const *buf,
|
||||
unsigned len);
|
||||
void MD5Final(unsigned char digest[16], struct MD5Context *context);
|
||||
|
||||
struct ssh_cipher {
|
||||
void (*sesskey)(unsigned char *key);
|
||||
void (*encrypt)(unsigned char *blk, int len);
|
||||
void (*decrypt)(unsigned char *blk, int len);
|
||||
};
|
||||
|
||||
void SHATransform(word32 *digest, word32 *data);
|
||||
|
||||
int random_byte(void);
|
||||
void random_add_noise(void *noise, int length);
|
111
sshcrc.c
Normal file
111
sshcrc.c
Normal file
@ -0,0 +1,111 @@
|
||||
/* ============================================================= */
|
||||
/* COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or */
|
||||
/* code or tables extracted from it, as desired without restriction. */
|
||||
/* */
|
||||
/* First, the polynomial itself and its table of feedback terms. The */
|
||||
/* polynomial is */
|
||||
/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */
|
||||
/* */
|
||||
/* Note that we take it "backwards" and put the highest-order term in */
|
||||
/* the lowest-order bit. The X^32 term is "implied"; the LSB is the */
|
||||
/* X^31 term, etc. The X^0 term (usually shown as "+1") results in */
|
||||
/* the MSB being 1. */
|
||||
/* */
|
||||
/* Note that the usual hardware shift register implementation, which */
|
||||
/* is what we're using (we're merely optimizing it by doing eight-bit */
|
||||
/* chunks at a time) shifts bits into the lowest-order term. In our */
|
||||
/* implementation, that means shifting towards the right. Why do we */
|
||||
/* do it this way? Because the calculated CRC must be transmitted in */
|
||||
/* order from highest-order term to lowest-order term. UARTs transmit */
|
||||
/* characters in order from LSB to MSB. By storing the CRC this way, */
|
||||
/* we hand it to the UART in the order low-byte to high-byte; the UART */
|
||||
/* sends each low-bit to hight-bit; and the result is transmission bit */
|
||||
/* by bit from highest- to lowest-order term without requiring any bit */
|
||||
/* shuffling on our part. Reception works similarly. */
|
||||
/* */
|
||||
/* The feedback terms table consists of 256, 32-bit entries. Notes: */
|
||||
/* */
|
||||
/* The table can be generated at runtime if desired; code to do so */
|
||||
/* is shown later. It might not be obvious, but the feedback */
|
||||
/* terms simply represent the results of eight shift/xor opera- */
|
||||
/* tions for all combinations of data and CRC register values. */
|
||||
/* */
|
||||
/* The values must be right-shifted by eight bits by the "updcrc" */
|
||||
/* logic; the shift must be unsigned (bring in zeroes). On some */
|
||||
/* hardware you could probably optimize the shift in assembler by */
|
||||
/* using byte-swap instructions. */
|
||||
/* polynomial $edb88320 */
|
||||
/* */
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
static unsigned long crc32_tab[] = {
|
||||
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
|
||||
0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
|
||||
0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
|
||||
0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
|
||||
0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
|
||||
0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
|
||||
0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
|
||||
0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
|
||||
0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
|
||||
0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
|
||||
0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
|
||||
0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
|
||||
0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
|
||||
0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
|
||||
0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
|
||||
0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
|
||||
0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
|
||||
0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
|
||||
0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
|
||||
0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
|
||||
0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
|
||||
0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
|
||||
0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
|
||||
0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
|
||||
0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
|
||||
0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
|
||||
0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
|
||||
0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
|
||||
0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
|
||||
0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
|
||||
0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
|
||||
0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
|
||||
0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
|
||||
0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
|
||||
0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
|
||||
0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
|
||||
0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
|
||||
0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
|
||||
0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
|
||||
0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
|
||||
0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
|
||||
0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
|
||||
0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
|
||||
0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
|
||||
0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
|
||||
0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
|
||||
0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
|
||||
0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
|
||||
0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
|
||||
0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
|
||||
0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
|
||||
0x2d02ef8dL
|
||||
};
|
||||
|
||||
/* Return a 32-bit CRC of the contents of the buffer. */
|
||||
|
||||
unsigned long crc32(const unsigned char *s, unsigned int len)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned long crc32val;
|
||||
|
||||
crc32val = 0;
|
||||
for (i = 0; i < len; i ++)
|
||||
{
|
||||
crc32val =
|
||||
crc32_tab[(crc32val ^ s[i]) & 0xff] ^
|
||||
(crc32val >> 8);
|
||||
}
|
||||
return crc32val;
|
||||
}
|
768
sshdes.c
Normal file
768
sshdes.c
Normal file
@ -0,0 +1,768 @@
|
||||
#include <assert.h>
|
||||
#include "ssh.h"
|
||||
|
||||
/*
|
||||
|
||||
DES implementation; 1995 Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
This implementation is derived from libdes-3.06, which is copyright
|
||||
(c) 1993 Eric Young, and distributed under the GNU GPL or the ARTISTIC licence
|
||||
(at the user's option). The original distribution can be found e.g. from
|
||||
ftp://ftp.dsi.unimi.it/pub/security/crypt/libdes/libdes-3.06.tar.gz.
|
||||
|
||||
This implementation is distributed under the same terms. See
|
||||
libdes-README, libdes-ARTISTIC, and libdes-COPYING for more
|
||||
information.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id: sshdes.c,v 1.1 1999/01/08 13:02:12 simon Exp $
|
||||
* $Log: sshdes.c,v $
|
||||
* Revision 1.1 1999/01/08 13:02:12 simon
|
||||
* Initial checkin: beta 0.43
|
||||
*
|
||||
* Revision 1.1.1.1 1996/02/18 21:38:11 ylo
|
||||
* Imported ssh-1.2.13.
|
||||
*
|
||||
* Revision 1.2 1995/07/13 01:22:57 ylo
|
||||
* Added cvs log.
|
||||
*
|
||||
* $Endlog$
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
word32 key_schedule[32];
|
||||
} DESContext;
|
||||
|
||||
/* Sets the des key for the context. Initializes the context. The least
|
||||
significant bit of each byte of the key is ignored as parity. */
|
||||
static void des_set_key(unsigned char *key, DESContext *ks);
|
||||
|
||||
/* Encrypts 32 bits in l,r, and stores the result in output[0] and output[1].
|
||||
Performs encryption if encrypt is non-zero, and decryption if it is zero.
|
||||
The key context must have been initialized previously with des_set_key. */
|
||||
static void des_encrypt(word32 l, word32 r, word32 *output, DESContext *ks,
|
||||
int encrypt);
|
||||
|
||||
/* Encrypts len bytes from src to dest in CBC modes. Len must be a multiple
|
||||
of 8. iv will be modified at end to a value suitable for continuing
|
||||
encryption. */
|
||||
static void des_cbc_encrypt(DESContext *ks, unsigned char *iv, unsigned char *dest,
|
||||
const unsigned char *src, unsigned int len);
|
||||
|
||||
/* Decrypts len bytes from src to dest in CBC modes. Len must be a multiple
|
||||
of 8. iv will be modified at end to a value suitable for continuing
|
||||
decryption. */
|
||||
static void des_cbc_decrypt(DESContext *ks, unsigned char *iv, unsigned char *dest,
|
||||
const unsigned char *src, unsigned int len);
|
||||
|
||||
/* Encrypts in CBC mode using triple-DES. */
|
||||
static void des_3cbc_encrypt(DESContext *ks1, unsigned char *iv1,
|
||||
DESContext *ks2, unsigned char *iv2,
|
||||
DESContext *ks3, unsigned char *iv3,
|
||||
unsigned char *dest, const unsigned char *src,
|
||||
unsigned int len);
|
||||
|
||||
/* Decrypts in CBC mode using triple-DES. */
|
||||
static void des_3cbc_decrypt(DESContext *ks1, unsigned char *iv1,
|
||||
DESContext *ks2, unsigned char *iv2,
|
||||
DESContext *ks3, unsigned char *iv3,
|
||||
unsigned char *dest, const unsigned char *src,
|
||||
unsigned int len);
|
||||
|
||||
#define GET_32BIT_LSB_FIRST(cp) \
|
||||
(((unsigned long)(unsigned char)(cp)[0]) | \
|
||||
((unsigned long)(unsigned char)(cp)[1] << 8) | \
|
||||
((unsigned long)(unsigned char)(cp)[2] << 16) | \
|
||||
((unsigned long)(unsigned char)(cp)[3] << 24))
|
||||
|
||||
#define PUT_32BIT_LSB_FIRST(cp, value) do { \
|
||||
(cp)[0] = (value); \
|
||||
(cp)[1] = (value) >> 8; \
|
||||
(cp)[2] = (value) >> 16; \
|
||||
(cp)[3] = (value) >> 24; } while (0)
|
||||
|
||||
/*
|
||||
|
||||
DES implementation; 1995 Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
This implementation is derived from libdes-3.06, which is copyright
|
||||
(c) 1993 Eric Young, and distributed under the GNU GPL or the ARTISTIC licence
|
||||
(at the user's option). The original distribution can be found e.g. from
|
||||
ftp://ftp.dsi.unimi.it/pub/security/crypt/libdes/libdes-3.06.tar.gz.
|
||||
|
||||
This implementation is distributed under the same terms. See
|
||||
libdes-README, libdes-ARTISTIC, and libdes-COPYING for more
|
||||
information.
|
||||
|
||||
A description of the DES algorithm can be found in every modern book on
|
||||
cryptography and data security, including the following:
|
||||
|
||||
Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1994.
|
||||
|
||||
Jennifer Seberry and Josed Pieprzyk: Cryptography: An Introduction to
|
||||
Computer Security. Prentice-Hall, 1989.
|
||||
|
||||
Man Young Rhee: Cryptography and Secure Data Communications. McGraw-Hill,
|
||||
1994.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id: sshdes.c,v 1.1 1999/01/08 13:02:12 simon Exp $
|
||||
* $Log: sshdes.c,v $
|
||||
* Revision 1.1 1999/01/08 13:02:12 simon
|
||||
* Initial checkin: beta 0.43
|
||||
*
|
||||
* Revision 1.1.1.1 1996/02/18 21:38:11 ylo
|
||||
* Imported ssh-1.2.13.
|
||||
*
|
||||
* Revision 1.2 1995/07/13 01:22:25 ylo
|
||||
* Added cvs log.
|
||||
*
|
||||
* $Endlog$
|
||||
*/
|
||||
|
||||
/* Table for key generation. This used to be in sk.h. */
|
||||
/* Copyright (C) 1993 Eric Young - see README for more details */
|
||||
static const word32 des_skb[8][64]={
|
||||
/* for C bits (numbered as per FIPS 46) 1 2 3 4 5 6 */
|
||||
{ 0x00000000,0x00000010,0x20000000,0x20000010,
|
||||
0x00010000,0x00010010,0x20010000,0x20010010,
|
||||
0x00000800,0x00000810,0x20000800,0x20000810,
|
||||
0x00010800,0x00010810,0x20010800,0x20010810,
|
||||
0x00000020,0x00000030,0x20000020,0x20000030,
|
||||
0x00010020,0x00010030,0x20010020,0x20010030,
|
||||
0x00000820,0x00000830,0x20000820,0x20000830,
|
||||
0x00010820,0x00010830,0x20010820,0x20010830,
|
||||
0x00080000,0x00080010,0x20080000,0x20080010,
|
||||
0x00090000,0x00090010,0x20090000,0x20090010,
|
||||
0x00080800,0x00080810,0x20080800,0x20080810,
|
||||
0x00090800,0x00090810,0x20090800,0x20090810,
|
||||
0x00080020,0x00080030,0x20080020,0x20080030,
|
||||
0x00090020,0x00090030,0x20090020,0x20090030,
|
||||
0x00080820,0x00080830,0x20080820,0x20080830,
|
||||
0x00090820,0x00090830,0x20090820,0x20090830 },
|
||||
/* for C bits (numbered as per FIPS 46) 7 8 10 11 12 13 */
|
||||
{ 0x00000000,0x02000000,0x00002000,0x02002000,
|
||||
0x00200000,0x02200000,0x00202000,0x02202000,
|
||||
0x00000004,0x02000004,0x00002004,0x02002004,
|
||||
0x00200004,0x02200004,0x00202004,0x02202004,
|
||||
0x00000400,0x02000400,0x00002400,0x02002400,
|
||||
0x00200400,0x02200400,0x00202400,0x02202400,
|
||||
0x00000404,0x02000404,0x00002404,0x02002404,
|
||||
0x00200404,0x02200404,0x00202404,0x02202404,
|
||||
0x10000000,0x12000000,0x10002000,0x12002000,
|
||||
0x10200000,0x12200000,0x10202000,0x12202000,
|
||||
0x10000004,0x12000004,0x10002004,0x12002004,
|
||||
0x10200004,0x12200004,0x10202004,0x12202004,
|
||||
0x10000400,0x12000400,0x10002400,0x12002400,
|
||||
0x10200400,0x12200400,0x10202400,0x12202400,
|
||||
0x10000404,0x12000404,0x10002404,0x12002404,
|
||||
0x10200404,0x12200404,0x10202404,0x12202404 },
|
||||
/* for C bits (numbered as per FIPS 46) 14 15 16 17 19 20 */
|
||||
{ 0x00000000,0x00000001,0x00040000,0x00040001,
|
||||
0x01000000,0x01000001,0x01040000,0x01040001,
|
||||
0x00000002,0x00000003,0x00040002,0x00040003,
|
||||
0x01000002,0x01000003,0x01040002,0x01040003,
|
||||
0x00000200,0x00000201,0x00040200,0x00040201,
|
||||
0x01000200,0x01000201,0x01040200,0x01040201,
|
||||
0x00000202,0x00000203,0x00040202,0x00040203,
|
||||
0x01000202,0x01000203,0x01040202,0x01040203,
|
||||
0x08000000,0x08000001,0x08040000,0x08040001,
|
||||
0x09000000,0x09000001,0x09040000,0x09040001,
|
||||
0x08000002,0x08000003,0x08040002,0x08040003,
|
||||
0x09000002,0x09000003,0x09040002,0x09040003,
|
||||
0x08000200,0x08000201,0x08040200,0x08040201,
|
||||
0x09000200,0x09000201,0x09040200,0x09040201,
|
||||
0x08000202,0x08000203,0x08040202,0x08040203,
|
||||
0x09000202,0x09000203,0x09040202,0x09040203 },
|
||||
/* for C bits (numbered as per FIPS 46) 21 23 24 26 27 28 */
|
||||
{ 0x00000000,0x00100000,0x00000100,0x00100100,
|
||||
0x00000008,0x00100008,0x00000108,0x00100108,
|
||||
0x00001000,0x00101000,0x00001100,0x00101100,
|
||||
0x00001008,0x00101008,0x00001108,0x00101108,
|
||||
0x04000000,0x04100000,0x04000100,0x04100100,
|
||||
0x04000008,0x04100008,0x04000108,0x04100108,
|
||||
0x04001000,0x04101000,0x04001100,0x04101100,
|
||||
0x04001008,0x04101008,0x04001108,0x04101108,
|
||||
0x00020000,0x00120000,0x00020100,0x00120100,
|
||||
0x00020008,0x00120008,0x00020108,0x00120108,
|
||||
0x00021000,0x00121000,0x00021100,0x00121100,
|
||||
0x00021008,0x00121008,0x00021108,0x00121108,
|
||||
0x04020000,0x04120000,0x04020100,0x04120100,
|
||||
0x04020008,0x04120008,0x04020108,0x04120108,
|
||||
0x04021000,0x04121000,0x04021100,0x04121100,
|
||||
0x04021008,0x04121008,0x04021108,0x04121108 },
|
||||
/* for D bits (numbered as per FIPS 46) 1 2 3 4 5 6 */
|
||||
{ 0x00000000,0x10000000,0x00010000,0x10010000,
|
||||
0x00000004,0x10000004,0x00010004,0x10010004,
|
||||
0x20000000,0x30000000,0x20010000,0x30010000,
|
||||
0x20000004,0x30000004,0x20010004,0x30010004,
|
||||
0x00100000,0x10100000,0x00110000,0x10110000,
|
||||
0x00100004,0x10100004,0x00110004,0x10110004,
|
||||
0x20100000,0x30100000,0x20110000,0x30110000,
|
||||
0x20100004,0x30100004,0x20110004,0x30110004,
|
||||
0x00001000,0x10001000,0x00011000,0x10011000,
|
||||
0x00001004,0x10001004,0x00011004,0x10011004,
|
||||
0x20001000,0x30001000,0x20011000,0x30011000,
|
||||
0x20001004,0x30001004,0x20011004,0x30011004,
|
||||
0x00101000,0x10101000,0x00111000,0x10111000,
|
||||
0x00101004,0x10101004,0x00111004,0x10111004,
|
||||
0x20101000,0x30101000,0x20111000,0x30111000,
|
||||
0x20101004,0x30101004,0x20111004,0x30111004 },
|
||||
/* for D bits (numbered as per FIPS 46) 8 9 11 12 13 14 */
|
||||
{ 0x00000000,0x08000000,0x00000008,0x08000008,
|
||||
0x00000400,0x08000400,0x00000408,0x08000408,
|
||||
0x00020000,0x08020000,0x00020008,0x08020008,
|
||||
0x00020400,0x08020400,0x00020408,0x08020408,
|
||||
0x00000001,0x08000001,0x00000009,0x08000009,
|
||||
0x00000401,0x08000401,0x00000409,0x08000409,
|
||||
0x00020001,0x08020001,0x00020009,0x08020009,
|
||||
0x00020401,0x08020401,0x00020409,0x08020409,
|
||||
0x02000000,0x0A000000,0x02000008,0x0A000008,
|
||||
0x02000400,0x0A000400,0x02000408,0x0A000408,
|
||||
0x02020000,0x0A020000,0x02020008,0x0A020008,
|
||||
0x02020400,0x0A020400,0x02020408,0x0A020408,
|
||||
0x02000001,0x0A000001,0x02000009,0x0A000009,
|
||||
0x02000401,0x0A000401,0x02000409,0x0A000409,
|
||||
0x02020001,0x0A020001,0x02020009,0x0A020009,
|
||||
0x02020401,0x0A020401,0x02020409,0x0A020409 },
|
||||
/* for D bits (numbered as per FIPS 46) 16 17 18 19 20 21 */
|
||||
{ 0x00000000,0x00000100,0x00080000,0x00080100,
|
||||
0x01000000,0x01000100,0x01080000,0x01080100,
|
||||
0x00000010,0x00000110,0x00080010,0x00080110,
|
||||
0x01000010,0x01000110,0x01080010,0x01080110,
|
||||
0x00200000,0x00200100,0x00280000,0x00280100,
|
||||
0x01200000,0x01200100,0x01280000,0x01280100,
|
||||
0x00200010,0x00200110,0x00280010,0x00280110,
|
||||
0x01200010,0x01200110,0x01280010,0x01280110,
|
||||
0x00000200,0x00000300,0x00080200,0x00080300,
|
||||
0x01000200,0x01000300,0x01080200,0x01080300,
|
||||
0x00000210,0x00000310,0x00080210,0x00080310,
|
||||
0x01000210,0x01000310,0x01080210,0x01080310,
|
||||
0x00200200,0x00200300,0x00280200,0x00280300,
|
||||
0x01200200,0x01200300,0x01280200,0x01280300,
|
||||
0x00200210,0x00200310,0x00280210,0x00280310,
|
||||
0x01200210,0x01200310,0x01280210,0x01280310 },
|
||||
/* for D bits (numbered as per FIPS 46) 22 23 24 25 27 28 */
|
||||
{ 0x00000000,0x04000000,0x00040000,0x04040000,
|
||||
0x00000002,0x04000002,0x00040002,0x04040002,
|
||||
0x00002000,0x04002000,0x00042000,0x04042000,
|
||||
0x00002002,0x04002002,0x00042002,0x04042002,
|
||||
0x00000020,0x04000020,0x00040020,0x04040020,
|
||||
0x00000022,0x04000022,0x00040022,0x04040022,
|
||||
0x00002020,0x04002020,0x00042020,0x04042020,
|
||||
0x00002022,0x04002022,0x00042022,0x04042022,
|
||||
0x00000800,0x04000800,0x00040800,0x04040800,
|
||||
0x00000802,0x04000802,0x00040802,0x04040802,
|
||||
0x00002800,0x04002800,0x00042800,0x04042800,
|
||||
0x00002802,0x04002802,0x00042802,0x04042802,
|
||||
0x00000820,0x04000820,0x00040820,0x04040820,
|
||||
0x00000822,0x04000822,0x00040822,0x04040822,
|
||||
0x00002820,0x04002820,0x00042820,0x04042820,
|
||||
0x00002822,0x04002822,0x00042822,0x04042822 }
|
||||
};
|
||||
|
||||
/* Tables used for executing des. This used to be in spr.h. */
|
||||
/* Copyright (C) 1993 Eric Young - see README for more details */
|
||||
static const word32 des_SPtrans[8][64]={
|
||||
/* nibble 0 */
|
||||
{ 0x00820200, 0x00020000, 0x80800000, 0x80820200,
|
||||
0x00800000, 0x80020200, 0x80020000, 0x80800000,
|
||||
0x80020200, 0x00820200, 0x00820000, 0x80000200,
|
||||
0x80800200, 0x00800000, 0x00000000, 0x80020000,
|
||||
0x00020000, 0x80000000, 0x00800200, 0x00020200,
|
||||
0x80820200, 0x00820000, 0x80000200, 0x00800200,
|
||||
0x80000000, 0x00000200, 0x00020200, 0x80820000,
|
||||
0x00000200, 0x80800200, 0x80820000, 0x00000000,
|
||||
0x00000000, 0x80820200, 0x00800200, 0x80020000,
|
||||
0x00820200, 0x00020000, 0x80000200, 0x00800200,
|
||||
0x80820000, 0x00000200, 0x00020200, 0x80800000,
|
||||
0x80020200, 0x80000000, 0x80800000, 0x00820000,
|
||||
0x80820200, 0x00020200, 0x00820000, 0x80800200,
|
||||
0x00800000, 0x80000200, 0x80020000, 0x00000000,
|
||||
0x00020000, 0x00800000, 0x80800200, 0x00820200,
|
||||
0x80000000, 0x80820000, 0x00000200, 0x80020200 },
|
||||
|
||||
/* nibble 1 */
|
||||
{ 0x10042004, 0x00000000, 0x00042000, 0x10040000,
|
||||
0x10000004, 0x00002004, 0x10002000, 0x00042000,
|
||||
0x00002000, 0x10040004, 0x00000004, 0x10002000,
|
||||
0x00040004, 0x10042000, 0x10040000, 0x00000004,
|
||||
0x00040000, 0x10002004, 0x10040004, 0x00002000,
|
||||
0x00042004, 0x10000000, 0x00000000, 0x00040004,
|
||||
0x10002004, 0x00042004, 0x10042000, 0x10000004,
|
||||
0x10000000, 0x00040000, 0x00002004, 0x10042004,
|
||||
0x00040004, 0x10042000, 0x10002000, 0x00042004,
|
||||
0x10042004, 0x00040004, 0x10000004, 0x00000000,
|
||||
0x10000000, 0x00002004, 0x00040000, 0x10040004,
|
||||
0x00002000, 0x10000000, 0x00042004, 0x10002004,
|
||||
0x10042000, 0x00002000, 0x00000000, 0x10000004,
|
||||
0x00000004, 0x10042004, 0x00042000, 0x10040000,
|
||||
0x10040004, 0x00040000, 0x00002004, 0x10002000,
|
||||
0x10002004, 0x00000004, 0x10040000, 0x00042000 },
|
||||
|
||||
/* nibble 2 */
|
||||
{ 0x41000000, 0x01010040, 0x00000040, 0x41000040,
|
||||
0x40010000, 0x01000000, 0x41000040, 0x00010040,
|
||||
0x01000040, 0x00010000, 0x01010000, 0x40000000,
|
||||
0x41010040, 0x40000040, 0x40000000, 0x41010000,
|
||||
0x00000000, 0x40010000, 0x01010040, 0x00000040,
|
||||
0x40000040, 0x41010040, 0x00010000, 0x41000000,
|
||||
0x41010000, 0x01000040, 0x40010040, 0x01010000,
|
||||
0x00010040, 0x00000000, 0x01000000, 0x40010040,
|
||||
0x01010040, 0x00000040, 0x40000000, 0x00010000,
|
||||
0x40000040, 0x40010000, 0x01010000, 0x41000040,
|
||||
0x00000000, 0x01010040, 0x00010040, 0x41010000,
|
||||
0x40010000, 0x01000000, 0x41010040, 0x40000000,
|
||||
0x40010040, 0x41000000, 0x01000000, 0x41010040,
|
||||
0x00010000, 0x01000040, 0x41000040, 0x00010040,
|
||||
0x01000040, 0x00000000, 0x41010000, 0x40000040,
|
||||
0x41000000, 0x40010040, 0x00000040, 0x01010000 },
|
||||
|
||||
/* nibble 3 */
|
||||
{ 0x00100402, 0x04000400, 0x00000002, 0x04100402,
|
||||
0x00000000, 0x04100000, 0x04000402, 0x00100002,
|
||||
0x04100400, 0x04000002, 0x04000000, 0x00000402,
|
||||
0x04000002, 0x00100402, 0x00100000, 0x04000000,
|
||||
0x04100002, 0x00100400, 0x00000400, 0x00000002,
|
||||
0x00100400, 0x04000402, 0x04100000, 0x00000400,
|
||||
0x00000402, 0x00000000, 0x00100002, 0x04100400,
|
||||
0x04000400, 0x04100002, 0x04100402, 0x00100000,
|
||||
0x04100002, 0x00000402, 0x00100000, 0x04000002,
|
||||
0x00100400, 0x04000400, 0x00000002, 0x04100000,
|
||||
0x04000402, 0x00000000, 0x00000400, 0x00100002,
|
||||
0x00000000, 0x04100002, 0x04100400, 0x00000400,
|
||||
0x04000000, 0x04100402, 0x00100402, 0x00100000,
|
||||
0x04100402, 0x00000002, 0x04000400, 0x00100402,
|
||||
0x00100002, 0x00100400, 0x04100000, 0x04000402,
|
||||
0x00000402, 0x04000000, 0x04000002, 0x04100400 },
|
||||
|
||||
/* nibble 4 */
|
||||
{ 0x02000000, 0x00004000, 0x00000100, 0x02004108,
|
||||
0x02004008, 0x02000100, 0x00004108, 0x02004000,
|
||||
0x00004000, 0x00000008, 0x02000008, 0x00004100,
|
||||
0x02000108, 0x02004008, 0x02004100, 0x00000000,
|
||||
0x00004100, 0x02000000, 0x00004008, 0x00000108,
|
||||
0x02000100, 0x00004108, 0x00000000, 0x02000008,
|
||||
0x00000008, 0x02000108, 0x02004108, 0x00004008,
|
||||
0x02004000, 0x00000100, 0x00000108, 0x02004100,
|
||||
0x02004100, 0x02000108, 0x00004008, 0x02004000,
|
||||
0x00004000, 0x00000008, 0x02000008, 0x02000100,
|
||||
0x02000000, 0x00004100, 0x02004108, 0x00000000,
|
||||
0x00004108, 0x02000000, 0x00000100, 0x00004008,
|
||||
0x02000108, 0x00000100, 0x00000000, 0x02004108,
|
||||
0x02004008, 0x02004100, 0x00000108, 0x00004000,
|
||||
0x00004100, 0x02004008, 0x02000100, 0x00000108,
|
||||
0x00000008, 0x00004108, 0x02004000, 0x02000008 },
|
||||
|
||||
/* nibble 5 */
|
||||
{ 0x20000010, 0x00080010, 0x00000000, 0x20080800,
|
||||
0x00080010, 0x00000800, 0x20000810, 0x00080000,
|
||||
0x00000810, 0x20080810, 0x00080800, 0x20000000,
|
||||
0x20000800, 0x20000010, 0x20080000, 0x00080810,
|
||||
0x00080000, 0x20000810, 0x20080010, 0x00000000,
|
||||
0x00000800, 0x00000010, 0x20080800, 0x20080010,
|
||||
0x20080810, 0x20080000, 0x20000000, 0x00000810,
|
||||
0x00000010, 0x00080800, 0x00080810, 0x20000800,
|
||||
0x00000810, 0x20000000, 0x20000800, 0x00080810,
|
||||
0x20080800, 0x00080010, 0x00000000, 0x20000800,
|
||||
0x20000000, 0x00000800, 0x20080010, 0x00080000,
|
||||
0x00080010, 0x20080810, 0x00080800, 0x00000010,
|
||||
0x20080810, 0x00080800, 0x00080000, 0x20000810,
|
||||
0x20000010, 0x20080000, 0x00080810, 0x00000000,
|
||||
0x00000800, 0x20000010, 0x20000810, 0x20080800,
|
||||
0x20080000, 0x00000810, 0x00000010, 0x20080010 },
|
||||
|
||||
/* nibble 6 */
|
||||
{ 0x00001000, 0x00000080, 0x00400080, 0x00400001,
|
||||
0x00401081, 0x00001001, 0x00001080, 0x00000000,
|
||||
0x00400000, 0x00400081, 0x00000081, 0x00401000,
|
||||
0x00000001, 0x00401080, 0x00401000, 0x00000081,
|
||||
0x00400081, 0x00001000, 0x00001001, 0x00401081,
|
||||
0x00000000, 0x00400080, 0x00400001, 0x00001080,
|
||||
0x00401001, 0x00001081, 0x00401080, 0x00000001,
|
||||
0x00001081, 0x00401001, 0x00000080, 0x00400000,
|
||||
0x00001081, 0x00401000, 0x00401001, 0x00000081,
|
||||
0x00001000, 0x00000080, 0x00400000, 0x00401001,
|
||||
0x00400081, 0x00001081, 0x00001080, 0x00000000,
|
||||
0x00000080, 0x00400001, 0x00000001, 0x00400080,
|
||||
0x00000000, 0x00400081, 0x00400080, 0x00001080,
|
||||
0x00000081, 0x00001000, 0x00401081, 0x00400000,
|
||||
0x00401080, 0x00000001, 0x00001001, 0x00401081,
|
||||
0x00400001, 0x00401080, 0x00401000, 0x00001001 },
|
||||
|
||||
/* nibble 7 */
|
||||
{ 0x08200020, 0x08208000, 0x00008020, 0x00000000,
|
||||
0x08008000, 0x00200020, 0x08200000, 0x08208020,
|
||||
0x00000020, 0x08000000, 0x00208000, 0x00008020,
|
||||
0x00208020, 0x08008020, 0x08000020, 0x08200000,
|
||||
0x00008000, 0x00208020, 0x00200020, 0x08008000,
|
||||
0x08208020, 0x08000020, 0x00000000, 0x00208000,
|
||||
0x08000000, 0x00200000, 0x08008020, 0x08200020,
|
||||
0x00200000, 0x00008000, 0x08208000, 0x00000020,
|
||||
0x00200000, 0x00008000, 0x08000020, 0x08208020,
|
||||
0x00008020, 0x08000000, 0x00000000, 0x00208000,
|
||||
0x08200020, 0x08008020, 0x08008000, 0x00200020,
|
||||
0x08208000, 0x00000020, 0x00200020, 0x08008000,
|
||||
0x08208020, 0x00200000, 0x08200000, 0x08000020,
|
||||
0x00208000, 0x00008020, 0x08008020, 0x08200000,
|
||||
0x00000020, 0x08208000, 0x00208020, 0x00000000,
|
||||
0x08000000, 0x08200020, 0x00008000, 0x00208020 }};
|
||||
|
||||
/* Some stuff that used to be in des_locl.h. Heavily modified. */
|
||||
/* IP and FP
|
||||
* The problem is more of a geometric problem that random bit fiddling.
|
||||
0 1 2 3 4 5 6 7 62 54 46 38 30 22 14 6
|
||||
8 9 10 11 12 13 14 15 60 52 44 36 28 20 12 4
|
||||
16 17 18 19 20 21 22 23 58 50 42 34 26 18 10 2
|
||||
24 25 26 27 28 29 30 31 to 56 48 40 32 24 16 8 0
|
||||
|
||||
32 33 34 35 36 37 38 39 63 55 47 39 31 23 15 7
|
||||
40 41 42 43 44 45 46 47 61 53 45 37 29 21 13 5
|
||||
48 49 50 51 52 53 54 55 59 51 43 35 27 19 11 3
|
||||
56 57 58 59 60 61 62 63 57 49 41 33 25 17 9 1
|
||||
|
||||
The output has been subject to swaps of the form
|
||||
0 1 -> 3 1 but the odd and even bits have been put into
|
||||
2 3 2 0
|
||||
different words. The main trick is to remember that
|
||||
t=((l>>size)^r)&(mask);
|
||||
r^=t;
|
||||
l^=(t<<size);
|
||||
can be used to swap and move bits between words.
|
||||
|
||||
So l = 0 1 2 3 r = 16 17 18 19
|
||||
4 5 6 7 20 21 22 23
|
||||
8 9 10 11 24 25 26 27
|
||||
12 13 14 15 28 29 30 31
|
||||
becomes (for size == 2 and mask == 0x3333)
|
||||
t = 2^16 3^17 -- -- l = 0 1 16 17 r = 2 3 18 19
|
||||
6^20 7^21 -- -- 4 5 20 21 6 7 22 23
|
||||
10^24 11^25 -- -- 8 9 24 25 10 11 24 25
|
||||
14^28 15^29 -- -- 12 13 28 29 14 15 28 29
|
||||
|
||||
Thanks for hints from Richard Outerbridge - he told me IP&FP
|
||||
could be done in 15 xor, 10 shifts and 5 ands.
|
||||
When I finally started to think of the problem in 2D
|
||||
I first got ~42 operations without xors. When I remembered
|
||||
how to use xors :-) I got it to its final state.
|
||||
*/
|
||||
#define PERM_OP(a,b,t,n,m) ((t)=((((a)>>(n))^(b))&(m)),\
|
||||
(b)^=(t),\
|
||||
(a)^=((t)<<(n)))
|
||||
|
||||
#define IP(l,r,t) \
|
||||
PERM_OP(r,l,t, 4,0x0f0f0f0f); \
|
||||
PERM_OP(l,r,t,16,0x0000ffff); \
|
||||
PERM_OP(r,l,t, 2,0x33333333); \
|
||||
PERM_OP(l,r,t, 8,0x00ff00ff); \
|
||||
PERM_OP(r,l,t, 1,0x55555555);
|
||||
|
||||
#define FP(l,r,t) \
|
||||
PERM_OP(l,r,t, 1,0x55555555); \
|
||||
PERM_OP(r,l,t, 8,0x00ff00ff); \
|
||||
PERM_OP(l,r,t, 2,0x33333333); \
|
||||
PERM_OP(r,l,t,16,0x0000ffff); \
|
||||
PERM_OP(l,r,t, 4,0x0f0f0f0f);
|
||||
|
||||
#define D_ENCRYPT(L,R,S) \
|
||||
u=(R^s[S ]); \
|
||||
t=R^s[S+1]; \
|
||||
t=((t>>4)+(t<<28)); \
|
||||
L^= des_SPtrans[1][(t )&0x3f]| \
|
||||
des_SPtrans[3][(t>> 8)&0x3f]| \
|
||||
des_SPtrans[5][(t>>16)&0x3f]| \
|
||||
des_SPtrans[7][(t>>24)&0x3f]| \
|
||||
des_SPtrans[0][(u )&0x3f]| \
|
||||
des_SPtrans[2][(u>> 8)&0x3f]| \
|
||||
des_SPtrans[4][(u>>16)&0x3f]| \
|
||||
des_SPtrans[6][(u>>24)&0x3f];
|
||||
|
||||
/* This part is based on code that used to be in ecb_enc.c. */
|
||||
/* Copyright (C) 1993 Eric Young - see README for more details */
|
||||
|
||||
static void des_encrypt(word32 l, word32 r, word32 *output, DESContext *ks,
|
||||
int encrypt)
|
||||
{
|
||||
register word32 t,u;
|
||||
register int i;
|
||||
register word32 *s;
|
||||
|
||||
s = ks->key_schedule;
|
||||
|
||||
IP(l,r,t);
|
||||
/* Things have been modified so that the initial rotate is
|
||||
* done outside the loop. This required the
|
||||
* des_SPtrans values in sp.h to be rotated 1 bit to the right.
|
||||
* One perl script later and things have a 5% speed up on a sparc2.
|
||||
* Thanks to Richard Outerbridge <71755.204@CompuServe.COM>
|
||||
* for pointing this out. */
|
||||
t=(r<<1)|(r>>31);
|
||||
r=(l<<1)|(l>>31);
|
||||
l=t;
|
||||
|
||||
/* I don't know if it is worth the effort of loop unrolling the
|
||||
* inner loop */
|
||||
if (encrypt)
|
||||
{
|
||||
for (i=0; i<32; i+=4)
|
||||
{
|
||||
D_ENCRYPT(l,r,i+0); /* 1 */
|
||||
D_ENCRYPT(r,l,i+2); /* 2 */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i=30; i>0; i-=4)
|
||||
{
|
||||
D_ENCRYPT(l,r,i-0); /* 16 */
|
||||
D_ENCRYPT(r,l,i-2); /* 15 */
|
||||
}
|
||||
}
|
||||
l=(l>>1)|(l<<31);
|
||||
r=(r>>1)|(r<<31);
|
||||
|
||||
FP(r,l,t);
|
||||
output[0]=l;
|
||||
output[1]=r;
|
||||
}
|
||||
|
||||
/* Code based on set_key.c. */
|
||||
/* Copyright (C) 1993 Eric Young - see README for more details */
|
||||
|
||||
#define HPERM_OP(a,t,n,m) ((t)=((((a)<<(16-(n)))^(a))&(m)),\
|
||||
(a)=(a)^(t)^(t>>(16-(n))))
|
||||
|
||||
static void des_set_key(unsigned char *key, DESContext *ks)
|
||||
{
|
||||
register word32 c, d, t, s, shifts;
|
||||
register int i;
|
||||
register word32 *schedule;
|
||||
|
||||
schedule = ks->key_schedule;
|
||||
|
||||
c = GET_32BIT_LSB_FIRST(key);
|
||||
d = GET_32BIT_LSB_FIRST(key + 4);
|
||||
|
||||
/* I now do it in 47 simple operations :-)
|
||||
* Thanks to John Fletcher (john_fletcher@lccmail.ocf.llnl.gov)
|
||||
* for the inspiration. :-) */
|
||||
PERM_OP(d,c,t,4,0x0f0f0f0f);
|
||||
HPERM_OP(c,t,-2,0xcccc0000);
|
||||
HPERM_OP(d,t,-2,0xcccc0000);
|
||||
PERM_OP(d,c,t,1,0x55555555);
|
||||
PERM_OP(c,d,t,8,0x00ff00ff);
|
||||
PERM_OP(d,c,t,1,0x55555555);
|
||||
d = ((d & 0xff) << 16) | (d & 0xff00) |
|
||||
((d >> 16) & 0xff) | ((c >> 4) & 0xf000000);
|
||||
c&=0x0fffffff;
|
||||
|
||||
shifts = 0x7efc;
|
||||
for (i=0; i < 16; i++)
|
||||
{
|
||||
if (shifts & 1)
|
||||
{ c=((c>>2)|(c<<26)); d=((d>>2)|(d<<26)); }
|
||||
else
|
||||
{ c=((c>>1)|(c<<27)); d=((d>>1)|(d<<27)); }
|
||||
shifts >>= 1;
|
||||
c&=0x0fffffff;
|
||||
d&=0x0fffffff;
|
||||
|
||||
/* could be a few less shifts but I am to lazy at this
|
||||
* point in time to investigate */
|
||||
|
||||
s = des_skb[0][ (c )&0x3f ] |
|
||||
des_skb[1][((c>> 6)&0x03)|((c>> 7)&0x3c)] |
|
||||
des_skb[2][((c>>13)&0x0f)|((c>>14)&0x30)] |
|
||||
des_skb[3][((c>>20)&0x01)|((c>>21)&0x06)|((c>>22)&0x38)];
|
||||
|
||||
t = des_skb[4][ (d )&0x3f ] |
|
||||
des_skb[5][((d>> 7)&0x03)|((d>> 8)&0x3c)] |
|
||||
des_skb[6][ (d>>15)&0x3f ] |
|
||||
des_skb[7][((d>>21)&0x0f)|((d>>22)&0x30)];
|
||||
|
||||
/* table contained 0213 4657 */
|
||||
*schedule++ = ((t << 16) | (s & 0xffff));
|
||||
s = ((s >> 16) | (t & 0xffff0000));
|
||||
*schedule++ = (s << 4) | (s >> 28);
|
||||
}
|
||||
}
|
||||
|
||||
static void des_cbc_encrypt(DESContext *ks, unsigned char *iv,
|
||||
unsigned char *dest, const unsigned char *src,
|
||||
unsigned int len)
|
||||
{
|
||||
word32 iv0, iv1, out[2];
|
||||
unsigned int i;
|
||||
|
||||
assert((len & 7) == 0);
|
||||
|
||||
iv0 = GET_32BIT_LSB_FIRST(iv);
|
||||
iv1 = GET_32BIT_LSB_FIRST(iv + 4);
|
||||
|
||||
for (i = 0; i < len; i += 8)
|
||||
{
|
||||
iv0 ^= GET_32BIT_LSB_FIRST(src + i);
|
||||
iv1 ^= GET_32BIT_LSB_FIRST(src + i + 4);
|
||||
des_encrypt(iv0, iv1, out, ks, 1);
|
||||
iv0 = out[0];
|
||||
iv1 = out[1];
|
||||
PUT_32BIT_LSB_FIRST(dest + i, iv0);
|
||||
PUT_32BIT_LSB_FIRST(dest + i + 4, iv1);
|
||||
}
|
||||
PUT_32BIT_LSB_FIRST(iv, iv0);
|
||||
PUT_32BIT_LSB_FIRST(iv + 4, iv1);
|
||||
}
|
||||
|
||||
static void des_cbc_decrypt(DESContext *ks, unsigned char *iv,
|
||||
unsigned char *dest, const unsigned char *src,
|
||||
unsigned int len)
|
||||
{
|
||||
word32 iv0, iv1, d0, d1, out[2];
|
||||
unsigned int i;
|
||||
|
||||
assert((len & 7) == 0);
|
||||
|
||||
iv0 = GET_32BIT_LSB_FIRST(iv);
|
||||
iv1 = GET_32BIT_LSB_FIRST(iv + 4);
|
||||
|
||||
for (i = 0; i < len; i += 8)
|
||||
{
|
||||
d0 = GET_32BIT_LSB_FIRST(src + i);
|
||||
d1 = GET_32BIT_LSB_FIRST(src + i + 4);
|
||||
des_encrypt(d0, d1, out, ks, 0);
|
||||
iv0 ^= out[0];
|
||||
iv1 ^= out[1];
|
||||
PUT_32BIT_LSB_FIRST(dest + i, iv0);
|
||||
PUT_32BIT_LSB_FIRST(dest + i + 4, iv1);
|
||||
iv0 = d0;
|
||||
iv1 = d1;
|
||||
}
|
||||
PUT_32BIT_LSB_FIRST(iv, iv0);
|
||||
PUT_32BIT_LSB_FIRST(iv + 4, iv1);
|
||||
}
|
||||
|
||||
static void des_3cbc_encrypt(DESContext *ks1, unsigned char *iv1,
|
||||
DESContext *ks2, unsigned char *iv2,
|
||||
DESContext *ks3, unsigned char *iv3,
|
||||
unsigned char *dest, const unsigned char *src,
|
||||
unsigned int len)
|
||||
{
|
||||
des_cbc_encrypt(ks1, iv1, dest, src, len);
|
||||
des_cbc_decrypt(ks2, iv2, dest, dest, len);
|
||||
des_cbc_encrypt(ks3, iv3, dest, dest, len);
|
||||
}
|
||||
|
||||
static void des_3cbc_decrypt(DESContext *ks1, unsigned char *iv1,
|
||||
DESContext *ks2, unsigned char *iv2,
|
||||
DESContext *ks3, unsigned char *iv3,
|
||||
unsigned char *dest, const unsigned char *src,
|
||||
unsigned int len)
|
||||
{
|
||||
des_cbc_decrypt(ks3, iv3, dest, src, len);
|
||||
des_cbc_encrypt(ks2, iv2, dest, dest, len);
|
||||
des_cbc_decrypt(ks1, iv1, dest, dest, len);
|
||||
}
|
||||
|
||||
DESContext ekey1, ekey2, ekey3;
|
||||
unsigned char eiv1[8], eiv2[8], eiv3[8];
|
||||
|
||||
DESContext dkey1, dkey2, dkey3;
|
||||
unsigned char div1[8], div2[8], div3[8];
|
||||
|
||||
static void des3_sesskey(unsigned char *key) {
|
||||
des_set_key(key, &ekey1);
|
||||
des_set_key(key+8, &ekey2);
|
||||
des_set_key(key+16, &ekey3);
|
||||
memset(eiv1, 0, sizeof(eiv1));
|
||||
memset(eiv2, 0, sizeof(eiv2));
|
||||
memset(eiv3, 0, sizeof(eiv3));
|
||||
des_set_key(key, &dkey1);
|
||||
des_set_key(key+8, &dkey2);
|
||||
des_set_key(key+16, &dkey3);
|
||||
memset(div1, 0, sizeof(div1));
|
||||
memset(div2, 0, sizeof(div2));
|
||||
memset(div3, 0, sizeof(div3));
|
||||
}
|
||||
|
||||
static void des3_encrypt_blk(unsigned char *blk, int len) {
|
||||
des_3cbc_encrypt(&ekey1, eiv1, &ekey2, eiv2, &ekey3, eiv3, blk, blk, len);
|
||||
}
|
||||
|
||||
static void des3_decrypt_blk(unsigned char *blk, int len) {
|
||||
des_3cbc_decrypt(&dkey1, div1, &dkey2, div2, &dkey3, div3, blk, blk, len);
|
||||
}
|
||||
|
||||
struct ssh_cipher ssh_3des = {
|
||||
des3_sesskey,
|
||||
des3_encrypt_blk,
|
||||
des3_decrypt_blk
|
||||
};
|
||||
|
||||
#ifdef DES_TEST
|
||||
|
||||
void des_encrypt_buf(DESContext *ks, unsigned char *out,
|
||||
const unsigned char *in, int encrypt)
|
||||
{
|
||||
word32 in0, in1, output[0];
|
||||
|
||||
in0 = GET_32BIT_LSB_FIRST(in);
|
||||
in1 = GET_32BIT_LSB_FIRST(in + 4);
|
||||
des_encrypt(in0, in1, output, ks, encrypt);
|
||||
PUT_32BIT_LSB_FIRST(out, output[0]);
|
||||
PUT_32BIT_LSB_FIRST(out + 4, output[1]);
|
||||
}
|
||||
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
FILE *f;
|
||||
char line[1024], *cp;
|
||||
int i, value;
|
||||
unsigned char key[8], data[8], result[8], output[8];
|
||||
DESContext ks;
|
||||
|
||||
while (fgets(line, sizeof(line), stdin))
|
||||
{
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
if (sscanf(line + 2 * i, "%02x", &value) != 1)
|
||||
{
|
||||
fprintf(stderr, "1st col, i = %d, line: %s", i, line);
|
||||
exit(1);
|
||||
}
|
||||
key[i] = value;
|
||||
}
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
if (sscanf(line + 2 * i + 17, "%02x", &value) != 1)
|
||||
{
|
||||
fprintf(stderr, "2nd col, i = %d, line: %s", i, line);
|
||||
exit(1);
|
||||
}
|
||||
data[i] = value;
|
||||
}
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
if (sscanf(line + 2 * i + 2*17, "%02x", &value) != 1)
|
||||
{
|
||||
fprintf(stderr, "3rd col, i = %d, line: %s", i, line);
|
||||
exit(1);
|
||||
}
|
||||
result[i] = value;
|
||||
}
|
||||
des_set_key(key, &ks);
|
||||
des_encrypt_buf(&ks, output, data, 1);
|
||||
if (memcmp(output, result, 8) != 0)
|
||||
fprintf(stderr, "Encrypt failed: %s", line);
|
||||
des_encrypt_buf(&ks, output, result, 0);
|
||||
if (memcmp(output, data, 8) != 0)
|
||||
fprintf(stderr, "Decrypt failed: %s", line);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
#endif /* DES_TEST */
|
||||
|
249
sshmd5.c
Normal file
249
sshmd5.c
Normal file
@ -0,0 +1,249 @@
|
||||
/* This code has been heavily hacked by Tatu Ylonen <ylo@cs.hut.fi> to
|
||||
make it compile on machines like Cray that don't have a 32 bit integer
|
||||
type. */
|
||||
/*
|
||||
* This code implements the MD5 message-digest algorithm.
|
||||
* The algorithm is due to Ron Rivest. This code was
|
||||
* written by Colin Plumb in 1993, no copyright is claimed.
|
||||
* This code is in the public domain; do with it what you wish.
|
||||
*
|
||||
* Equivalent code is available from RSA Data Security, Inc.
|
||||
* This code has been tested against that, and is equivalent,
|
||||
* except that you don't need to include two pages of legalese
|
||||
* with every copy.
|
||||
*
|
||||
* To compute the message digest of a chunk of bytes, declare an
|
||||
* MD5Context structure, pass it to MD5Init, call MD5Update as
|
||||
* needed on buffers full of bytes, and then call MD5Final, which
|
||||
* will fill a supplied 16-byte array with the digest.
|
||||
*/
|
||||
|
||||
#include "ssh.h"
|
||||
|
||||
#define GET_32BIT_LSB_FIRST(cp) \
|
||||
(((unsigned long)(unsigned char)(cp)[0]) | \
|
||||
((unsigned long)(unsigned char)(cp)[1] << 8) | \
|
||||
((unsigned long)(unsigned char)(cp)[2] << 16) | \
|
||||
((unsigned long)(unsigned char)(cp)[3] << 24))
|
||||
|
||||
#define PUT_32BIT_LSB_FIRST(cp, value) do { \
|
||||
(cp)[0] = (value); \
|
||||
(cp)[1] = (value) >> 8; \
|
||||
(cp)[2] = (value) >> 16; \
|
||||
(cp)[3] = (value) >> 24; } while (0)
|
||||
|
||||
void MD5Transform(uint32 buf[4], const unsigned char in[64]);
|
||||
|
||||
/*
|
||||
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
|
||||
* initialization constants.
|
||||
*/
|
||||
void MD5Init(struct MD5Context *ctx)
|
||||
{
|
||||
ctx->buf[0] = 0x67452301;
|
||||
ctx->buf[1] = 0xefcdab89;
|
||||
ctx->buf[2] = 0x98badcfe;
|
||||
ctx->buf[3] = 0x10325476;
|
||||
|
||||
ctx->bits[0] = 0;
|
||||
ctx->bits[1] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update context to reflect the concatenation of another buffer full
|
||||
* of bytes.
|
||||
*/
|
||||
void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
|
||||
{
|
||||
uint32 t;
|
||||
|
||||
/* Update bitcount */
|
||||
|
||||
t = ctx->bits[0];
|
||||
if ((ctx->bits[0] = (t + ((uint32)len << 3)) & 0xffffffff) < t)
|
||||
ctx->bits[1]++; /* Carry from low to high */
|
||||
ctx->bits[1] += len >> 29;
|
||||
|
||||
t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
|
||||
|
||||
/* Handle any leading odd-sized chunks */
|
||||
|
||||
if (t) {
|
||||
unsigned char *p = ctx->in + t;
|
||||
|
||||
t = 64 - t;
|
||||
if (len < t) {
|
||||
memcpy(p, buf, len);
|
||||
return;
|
||||
}
|
||||
memcpy(p, buf, t);
|
||||
MD5Transform(ctx->buf, ctx->in);
|
||||
buf += t;
|
||||
len -= t;
|
||||
}
|
||||
/* Process data in 64-byte chunks */
|
||||
|
||||
while (len >= 64) {
|
||||
memcpy(ctx->in, buf, 64);
|
||||
MD5Transform(ctx->buf, ctx->in);
|
||||
buf += 64;
|
||||
len -= 64;
|
||||
}
|
||||
|
||||
/* Handle any remaining bytes of data. */
|
||||
|
||||
memcpy(ctx->in, buf, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Final wrapup - pad to 64-byte boundary with the bit pattern
|
||||
* 1 0* (64-bit count of bits processed, MSB-first)
|
||||
*/
|
||||
void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
|
||||
{
|
||||
unsigned count;
|
||||
unsigned char *p;
|
||||
|
||||
/* Compute number of bytes mod 64 */
|
||||
count = (ctx->bits[0] >> 3) & 0x3F;
|
||||
|
||||
/* Set the first char of padding to 0x80. This is safe since there is
|
||||
always at least one byte free */
|
||||
p = ctx->in + count;
|
||||
*p++ = 0x80;
|
||||
|
||||
/* Bytes of padding needed to make 64 bytes */
|
||||
count = 64 - 1 - count;
|
||||
|
||||
/* Pad out to 56 mod 64 */
|
||||
if (count < 8) {
|
||||
/* Two lots of padding: Pad the first block to 64 bytes */
|
||||
memset(p, 0, count);
|
||||
MD5Transform(ctx->buf, ctx->in);
|
||||
|
||||
/* Now fill the next block with 56 bytes */
|
||||
memset(ctx->in, 0, 56);
|
||||
} else {
|
||||
/* Pad block to 56 bytes */
|
||||
memset(p, 0, count - 8);
|
||||
}
|
||||
|
||||
/* Append length in bits and transform */
|
||||
PUT_32BIT_LSB_FIRST(ctx->in + 56, ctx->bits[0]);
|
||||
PUT_32BIT_LSB_FIRST(ctx->in + 60, ctx->bits[1]);
|
||||
|
||||
MD5Transform(ctx->buf, ctx->in);
|
||||
PUT_32BIT_LSB_FIRST(digest, ctx->buf[0]);
|
||||
PUT_32BIT_LSB_FIRST(digest + 4, ctx->buf[1]);
|
||||
PUT_32BIT_LSB_FIRST(digest + 8, ctx->buf[2]);
|
||||
PUT_32BIT_LSB_FIRST(digest + 12, ctx->buf[3]);
|
||||
memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
|
||||
}
|
||||
|
||||
#ifndef ASM_MD5
|
||||
|
||||
/* The four core functions - F1 is optimized somewhat */
|
||||
|
||||
/* #define F1(x, y, z) (x & y | ~x & z) */
|
||||
#define F1(x, y, z) (z ^ (x & (y ^ z)))
|
||||
#define F2(x, y, z) F1(z, x, y)
|
||||
#define F3(x, y, z) (x ^ y ^ z)
|
||||
#define F4(x, y, z) (y ^ (x | ~z))
|
||||
|
||||
/* This is the central step in the MD5 algorithm. */
|
||||
#define MD5STEP(f, w, x, y, z, data, s) \
|
||||
( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
|
||||
|
||||
/*
|
||||
* The core of the MD5 algorithm, this alters an existing MD5 hash to
|
||||
* reflect the addition of 16 longwords of new data. MD5Update blocks
|
||||
* the data and converts bytes into longwords for this routine.
|
||||
*/
|
||||
void MD5Transform(uint32 buf[4], const unsigned char inext[64])
|
||||
{
|
||||
register word32 a, b, c, d, i;
|
||||
word32 in[16];
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
in[i] = GET_32BIT_LSB_FIRST(inext + 4 * i);
|
||||
|
||||
a = buf[0];
|
||||
b = buf[1];
|
||||
c = buf[2];
|
||||
d = buf[3];
|
||||
|
||||
MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
|
||||
|
||||
MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
|
||||
|
||||
MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
|
||||
|
||||
MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
|
||||
|
||||
buf[0] += a;
|
||||
buf[1] += b;
|
||||
buf[2] += c;
|
||||
buf[3] += d;
|
||||
}
|
||||
|
||||
#endif
|
169
sshrand.c
Normal file
169
sshrand.c
Normal file
@ -0,0 +1,169 @@
|
||||
/*
|
||||
* cryptographic random number generator for PuTTY's ssh client
|
||||
*/
|
||||
|
||||
#include "ssh.h"
|
||||
|
||||
void noise_get_heavy(void (*func) (void *, int));
|
||||
void noise_get_light(void (*func) (void *, int));
|
||||
|
||||
/*
|
||||
* `pool' itself is a pool of random data which we actually use: we
|
||||
* return bytes from `pool', at position `poolpos', until `poolpos'
|
||||
* reaches the end of the pool. At this point we generate more
|
||||
* random data, by adding noise, stirring well, and resetting
|
||||
* `poolpos' to point to just past the beginning of the pool (not
|
||||
* _the_ beginning, since otherwise we'd give away the whole
|
||||
* contents of our pool, and attackers would just have to guess the
|
||||
* next lot of noise).
|
||||
*
|
||||
* `incomingb' buffers acquired noise data, until it gets full, at
|
||||
* which point the acquired noise is SHA'ed into `incoming' and
|
||||
* `incomingb' is cleared. The noise in `incoming' is used as part
|
||||
* of the noise for each stirring of the pool, in addition to local
|
||||
* time, process listings, and other such stuff.
|
||||
*/
|
||||
|
||||
#define HASHINPUT 64 /* 64 bytes SHA input */
|
||||
#define HASHSIZE 20 /* 160 bits SHA output */
|
||||
#define POOLSIZE 1200 /* size of random pool */
|
||||
|
||||
struct RandPool {
|
||||
unsigned char pool[POOLSIZE];
|
||||
int poolpos;
|
||||
|
||||
unsigned char incoming[HASHSIZE];
|
||||
|
||||
unsigned char incomingb[HASHINPUT];
|
||||
int incomingpos;
|
||||
};
|
||||
|
||||
static struct RandPool pool;
|
||||
|
||||
void random_add_noise(void *noise, int length) {
|
||||
unsigned char *p = noise;
|
||||
|
||||
while (length >= (HASHINPUT - pool.incomingpos)) {
|
||||
memcpy(pool.incomingb + pool.incomingpos, p,
|
||||
HASHINPUT - pool.incomingpos);
|
||||
p += HASHINPUT - pool.incomingpos;
|
||||
length -= HASHINPUT - pool.incomingpos;
|
||||
SHATransform((word32 *)pool.incoming, (word32 *)pool.incomingb);
|
||||
pool.incomingpos = 0;
|
||||
}
|
||||
|
||||
memcpy(pool.incomingb, p, length);
|
||||
pool.incomingpos = length;
|
||||
}
|
||||
|
||||
void random_stir(void) {
|
||||
word32 block[HASHINPUT/sizeof(word32)];
|
||||
word32 digest[HASHSIZE/sizeof(word32)];
|
||||
int i, j, k;
|
||||
|
||||
noise_get_light(random_add_noise);
|
||||
|
||||
SHATransform((word32 *)pool.incoming, (word32 *)pool.incomingb);
|
||||
pool.incomingpos = 0;
|
||||
|
||||
/*
|
||||
* Chunks of this code are blatantly endianness-dependent, but
|
||||
* as it's all random bits anyway, WHO CARES?
|
||||
*/
|
||||
memcpy(digest, pool.incoming, sizeof(digest));
|
||||
|
||||
/*
|
||||
* Make two passes over the pool.
|
||||
*/
|
||||
for (i = 0; i < 2; i++) {
|
||||
|
||||
/*
|
||||
* We operate SHA in CFB mode, repeatedly adding the same
|
||||
* block of data to the digest. But we're also fiddling
|
||||
* with the digest-so-far, so this shouldn't be Bad or
|
||||
* anything.
|
||||
*/
|
||||
memcpy(block, pool.pool, sizeof(block));
|
||||
|
||||
/*
|
||||
* Each pass processes the pool backwards in blocks of
|
||||
* HASHSIZE, just so that in general we get the output of
|
||||
* SHA before the corresponding input, in the hope that
|
||||
* things will be that much less predictable that way
|
||||
* round, when we subsequently return bytes ...
|
||||
*/
|
||||
for (j = POOLSIZE; (j -= HASHSIZE) >= 0 ;) {
|
||||
/*
|
||||
* XOR the bit of the pool we're processing into the
|
||||
* digest.
|
||||
*/
|
||||
|
||||
for (k = 0; k < sizeof(digest)/sizeof(*digest); k++)
|
||||
digest[k] ^= ((word32 *)(pool.pool+j))[k];
|
||||
|
||||
/*
|
||||
* Munge our unrevealed first block of the pool into
|
||||
* it.
|
||||
*/
|
||||
SHATransform(digest, block);
|
||||
|
||||
/*
|
||||
* Stick the result back into the pool.
|
||||
*/
|
||||
|
||||
for (k = 0; k < sizeof(digest)/sizeof(*digest); k++)
|
||||
((word32 *)(pool.pool+j))[k] = digest[k];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Might as well save this value back into `incoming', just so
|
||||
* there'll be some extra bizarreness there.
|
||||
*/
|
||||
SHATransform(digest, block);
|
||||
memcpy(digest, pool.incoming, sizeof(digest));
|
||||
|
||||
pool.poolpos = sizeof(pool.incoming);
|
||||
}
|
||||
|
||||
static void random_add_heavynoise(void *noise, int length) {
|
||||
unsigned char *p = noise;
|
||||
|
||||
while (length >= (POOLSIZE - pool.poolpos)) {
|
||||
memcpy(pool.pool + pool.poolpos, p, POOLSIZE - pool.poolpos);
|
||||
p += POOLSIZE - pool.poolpos;
|
||||
length -= POOLSIZE - pool.poolpos;
|
||||
random_stir();
|
||||
pool.poolpos = 0;
|
||||
}
|
||||
|
||||
memcpy(pool.pool, p, length);
|
||||
pool.poolpos = length;
|
||||
}
|
||||
|
||||
void random_init(void) {
|
||||
memset(&pool, 0, sizeof(pool)); /* just to start with */
|
||||
|
||||
/*
|
||||
* For noise_get_heavy, we temporarily use `poolpos' as the
|
||||
* pointer for addition of noise, rather than extraction of
|
||||
* random numbers.
|
||||
*/
|
||||
pool.poolpos = 0;
|
||||
noise_get_heavy(random_add_heavynoise);
|
||||
|
||||
random_stir();
|
||||
}
|
||||
|
||||
int random_byte(void) {
|
||||
if (pool.poolpos >= POOLSIZE)
|
||||
random_stir();
|
||||
|
||||
return pool.pool[pool.poolpos++];
|
||||
}
|
||||
|
||||
void random_get_savedata(void **data, int *len) {
|
||||
random_stir();
|
||||
*data = pool.pool+pool.poolpos;
|
||||
*len = POOLSIZE/2;
|
||||
}
|
412
sshrsa.c
Normal file
412
sshrsa.c
Normal file
@ -0,0 +1,412 @@
|
||||
/*
|
||||
* RSA implementation just sufficient for ssh client-side
|
||||
* initialisation step
|
||||
*/
|
||||
|
||||
/*#include <windows.h>
|
||||
#define RSADEBUG
|
||||
#define DLVL 2
|
||||
#include "stel.h"*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ssh.h"
|
||||
|
||||
typedef unsigned short *Bignum;
|
||||
|
||||
static unsigned short Zero[1] = { 0 };
|
||||
|
||||
#if defined TESTMODE || defined RSADEBUG
|
||||
#ifndef DLVL
|
||||
#define DLVL 10000
|
||||
#endif
|
||||
#define debug(x) bndebug(#x,x)
|
||||
static int level = 0;
|
||||
static void bndebug(char *name, Bignum b) {
|
||||
int i;
|
||||
int w = 50-level-strlen(name)-5*b[0];
|
||||
if (level >= DLVL)
|
||||
return;
|
||||
if (w < 0) w = 0;
|
||||
dprintf("%*s%s%*s", level, "", name, w, "");
|
||||
for (i=b[0]; i>0; i--)
|
||||
dprintf(" %04x", b[i]);
|
||||
dprintf("\n");
|
||||
}
|
||||
#define dmsg(x) do {if(level<DLVL){dprintf("%*s",level,"");printf x;}} while(0)
|
||||
#define enter(x) do { dmsg(x); level += 4; } while(0)
|
||||
#define leave(x) do { level -= 4; dmsg(x); } while(0)
|
||||
#else
|
||||
#define debug(x)
|
||||
#define dmsg(x)
|
||||
#define enter(x)
|
||||
#define leave(x)
|
||||
#endif
|
||||
|
||||
static Bignum newbn(int length) {
|
||||
Bignum b = malloc((length+1)*sizeof(unsigned short));
|
||||
if (!b)
|
||||
abort(); /* FIXME */
|
||||
b[0] = length;
|
||||
return b;
|
||||
}
|
||||
|
||||
static void freebn(Bignum b) {
|
||||
free(b);
|
||||
}
|
||||
|
||||
static int msb(Bignum r) {
|
||||
int i;
|
||||
int j;
|
||||
unsigned short n;
|
||||
|
||||
for (i=r[0]; i>0; i--)
|
||||
if (r[i])
|
||||
break;
|
||||
|
||||
j = (i-1)*16;
|
||||
n = r[i];
|
||||
if (n & 0xFF00) j += 8, n >>= 8;
|
||||
if (n & 0x00F0) j += 4, n >>= 4;
|
||||
if (n & 0x000C) j += 2, n >>= 2;
|
||||
if (n & 0x0002) j += 1, n >>= 1;
|
||||
|
||||
return j;
|
||||
}
|
||||
|
||||
static void add(Bignum r1, Bignum r2, Bignum result) {
|
||||
int i;
|
||||
long stuff = 0;
|
||||
|
||||
enter((">add\n"));
|
||||
debug(r1);
|
||||
debug(r2);
|
||||
|
||||
for (i = 1 ;; i++) {
|
||||
if (i <= r1[0])
|
||||
stuff += r1[i];
|
||||
if (i <= r2[0])
|
||||
stuff += r2[i];
|
||||
if (i <= result[0])
|
||||
result[i] = stuff & 0xFFFFU;
|
||||
if (i > r1[0] && i > r2[0] && i >= result[0])
|
||||
break;
|
||||
stuff >>= 16;
|
||||
}
|
||||
|
||||
debug(result);
|
||||
leave(("<add\n"));
|
||||
}
|
||||
|
||||
static void sub(Bignum r1, Bignum r2, Bignum result) {
|
||||
int i;
|
||||
long stuff = 0;
|
||||
|
||||
enter((">sub\n"));
|
||||
debug(r1);
|
||||
debug(r2);
|
||||
|
||||
for (i = 1 ;; i++) {
|
||||
if (i <= r1[0])
|
||||
stuff += r1[i];
|
||||
if (i <= r2[0])
|
||||
stuff -= r2[i];
|
||||
if (i <= result[0])
|
||||
result[i] = stuff & 0xFFFFU;
|
||||
if (i > r1[0] && i > r2[0] && i >= result[0])
|
||||
break;
|
||||
stuff = stuff<0 ? -1 : 0;
|
||||
}
|
||||
|
||||
debug(result);
|
||||
leave(("<sub\n"));
|
||||
}
|
||||
|
||||
static int ge(Bignum r1, Bignum r2) {
|
||||
int i;
|
||||
|
||||
enter((">ge\n"));
|
||||
debug(r1);
|
||||
debug(r2);
|
||||
|
||||
if (r1[0] < r2[0])
|
||||
i = r2[0];
|
||||
else
|
||||
i = r1[0];
|
||||
|
||||
while (i > 0) {
|
||||
unsigned short n1 = (i > r1[0] ? 0 : r1[i]);
|
||||
unsigned short n2 = (i > r2[0] ? 0 : r2[i]);
|
||||
|
||||
if (n1 > n2) {
|
||||
dmsg(("greater\n"));
|
||||
leave(("<ge\n"));
|
||||
return 1; /* r1 > r2 */
|
||||
} else if (n1 < n2) {
|
||||
dmsg(("less\n"));
|
||||
leave(("<ge\n"));
|
||||
return 0; /* r1 < r2 */
|
||||
}
|
||||
|
||||
i--;
|
||||
}
|
||||
|
||||
dmsg(("equal\n"));
|
||||
leave(("<ge\n"));
|
||||
return 1; /* r1 = r2 */
|
||||
}
|
||||
|
||||
static void modmult(Bignum r1, Bignum r2, Bignum modulus, Bignum result) {
|
||||
Bignum temp = newbn(modulus[0]+1);
|
||||
Bignum tmp2 = newbn(modulus[0]+1);
|
||||
int i;
|
||||
int bit, bits, digit, smallbit;
|
||||
|
||||
enter((">modmult\n"));
|
||||
debug(r1);
|
||||
debug(r2);
|
||||
debug(modulus);
|
||||
|
||||
for (i=1; i<=result[0]; i++)
|
||||
result[i] = 0; /* result := 0 */
|
||||
for (i=1; i<=temp[0]; i++)
|
||||
temp[i] = (i > r2[0] ? 0 : r2[i]); /* temp := r2 */
|
||||
|
||||
bits = 1+msb(r1);
|
||||
|
||||
for (bit = 0; bit < bits; bit++) {
|
||||
digit = 1 + bit / 16;
|
||||
smallbit = bit % 16;
|
||||
|
||||
debug(temp);
|
||||
if (digit <= r1[0] && (r1[digit] & (1<<smallbit))) {
|
||||
dmsg(("bit %d\n", bit));
|
||||
add(temp, result, tmp2);
|
||||
if (ge(tmp2, modulus))
|
||||
sub(tmp2, modulus, result);
|
||||
else
|
||||
add(tmp2, Zero, result);
|
||||
debug(result);
|
||||
}
|
||||
|
||||
add(temp, temp, tmp2);
|
||||
if (ge(tmp2, modulus))
|
||||
sub(tmp2, modulus, temp);
|
||||
else
|
||||
add(tmp2, Zero, temp);
|
||||
}
|
||||
|
||||
freebn(temp);
|
||||
freebn(tmp2);
|
||||
|
||||
debug(result);
|
||||
leave(("<modmult\n"));
|
||||
}
|
||||
|
||||
static void modpow(Bignum r1, Bignum r2, Bignum modulus, Bignum result) {
|
||||
Bignum temp = newbn(modulus[0]+1);
|
||||
Bignum tmp2 = newbn(modulus[0]+1);
|
||||
int i;
|
||||
int bit, bits, digit, smallbit;
|
||||
|
||||
enter((">modpow\n"));
|
||||
debug(r1);
|
||||
debug(r2);
|
||||
debug(modulus);
|
||||
|
||||
for (i=1; i<=result[0]; i++)
|
||||
result[i] = (i==1); /* result := 1 */
|
||||
for (i=1; i<=temp[0]; i++)
|
||||
temp[i] = (i > r1[0] ? 0 : r1[i]); /* temp := r1 */
|
||||
|
||||
bits = 1+msb(r2);
|
||||
|
||||
for (bit = 0; bit < bits; bit++) {
|
||||
digit = 1 + bit / 16;
|
||||
smallbit = bit % 16;
|
||||
|
||||
debug(temp);
|
||||
if (digit <= r2[0] && (r2[digit] & (1<<smallbit))) {
|
||||
dmsg(("bit %d\n", bit));
|
||||
modmult(temp, result, modulus, tmp2);
|
||||
add(tmp2, Zero, result);
|
||||
debug(result);
|
||||
}
|
||||
|
||||
modmult(temp, temp, modulus, tmp2);
|
||||
add(tmp2, Zero, temp);
|
||||
}
|
||||
|
||||
freebn(temp);
|
||||
freebn(tmp2);
|
||||
|
||||
debug(result);
|
||||
leave(("<modpow\n"));
|
||||
}
|
||||
|
||||
int makekey(unsigned char *data, struct RSAKey *result,
|
||||
unsigned char **keystr) {
|
||||
unsigned char *p = data;
|
||||
Bignum bn[2];
|
||||
int i, j;
|
||||
int w, b;
|
||||
|
||||
result->bits = 0;
|
||||
for (i=0; i<4; i++)
|
||||
result->bits = (result->bits << 8) + *p++;
|
||||
|
||||
for (j=0; j<2; j++) {
|
||||
|
||||
w = 0;
|
||||
for (i=0; i<2; i++)
|
||||
w = (w << 8) + *p++;
|
||||
|
||||
result->bytes = b = (w+7)/8; /* bits -> bytes */
|
||||
w = (w+15)/16; /* bits -> words */
|
||||
|
||||
bn[j] = newbn(w);
|
||||
|
||||
if (keystr) *keystr = p; /* point at key string, second time */
|
||||
|
||||
for (i=1; i<=w; i++)
|
||||
bn[j][i] = 0;
|
||||
for (i=0; i<b; i++) {
|
||||
unsigned char byte = *p++;
|
||||
if ((b-i) & 1)
|
||||
bn[j][w-i/2] |= byte;
|
||||
else
|
||||
bn[j][w-i/2] |= byte<<8;
|
||||
}
|
||||
|
||||
debug(bn[j]);
|
||||
|
||||
}
|
||||
|
||||
result->exponent = bn[0];
|
||||
result->modulus = bn[1];
|
||||
|
||||
return p - data;
|
||||
}
|
||||
|
||||
void rsaencrypt(unsigned char *data, int length, struct RSAKey *key) {
|
||||
Bignum b1, b2;
|
||||
int w, i;
|
||||
unsigned char *p;
|
||||
|
||||
debug(key->exponent);
|
||||
|
||||
memmove(data+key->bytes-length, data, length);
|
||||
data[0] = 0;
|
||||
data[1] = 2;
|
||||
|
||||
for (i = 2; i < key->bytes-length-1; i++) {
|
||||
do {
|
||||
data[i] = random_byte();
|
||||
} while (data[i] == 0);
|
||||
}
|
||||
data[key->bytes-length-1] = 0;
|
||||
|
||||
w = (key->bytes+1)/2;
|
||||
|
||||
b1 = newbn(w);
|
||||
b2 = newbn(w);
|
||||
|
||||
p = data;
|
||||
for (i=1; i<=w; i++)
|
||||
b1[i] = 0;
|
||||
for (i=0; i<key->bytes; i++) {
|
||||
unsigned char byte = *p++;
|
||||
if ((key->bytes-i) & 1)
|
||||
b1[w-i/2] |= byte;
|
||||
else
|
||||
b1[w-i/2] |= byte<<8;
|
||||
}
|
||||
|
||||
debug(b1);
|
||||
|
||||
modpow(b1, key->exponent, key->modulus, b2);
|
||||
|
||||
debug(b2);
|
||||
|
||||
p = data;
|
||||
for (i=0; i<key->bytes; i++) {
|
||||
unsigned char b;
|
||||
if (i & 1)
|
||||
b = b2[w-i/2] & 0xFF;
|
||||
else
|
||||
b = b2[w-i/2] >> 8;
|
||||
*p++ = b;
|
||||
}
|
||||
|
||||
freebn(b1);
|
||||
freebn(b2);
|
||||
}
|
||||
|
||||
int rsastr_len(struct RSAKey *key) {
|
||||
Bignum md, ex;
|
||||
|
||||
md = key->modulus;
|
||||
ex = key->exponent;
|
||||
return 4 * (ex[0]+md[0]) + 10;
|
||||
}
|
||||
|
||||
void rsastr_fmt(char *str, struct RSAKey *key) {
|
||||
Bignum md, ex;
|
||||
int len = 0, i;
|
||||
|
||||
md = key->modulus;
|
||||
ex = key->exponent;
|
||||
|
||||
for (i=1; i<=ex[0]; i++) {
|
||||
sprintf(str+len, "%04x", ex[i]);
|
||||
len += strlen(str+len);
|
||||
}
|
||||
str[len++] = '/';
|
||||
for (i=1; i<=md[0]; i++) {
|
||||
sprintf(str+len, "%04x", md[i]);
|
||||
len += strlen(str+len);
|
||||
}
|
||||
str[len] = '\0';
|
||||
}
|
||||
|
||||
#ifdef TESTMODE
|
||||
|
||||
#ifndef NODDY
|
||||
#define p1 10007
|
||||
#define p2 10069
|
||||
#define p3 10177
|
||||
#else
|
||||
#define p1 3
|
||||
#define p2 7
|
||||
#define p3 13
|
||||
#endif
|
||||
|
||||
unsigned short P1[2] = { 1, p1 };
|
||||
unsigned short P2[2] = { 1, p2 };
|
||||
unsigned short P3[2] = { 1, p3 };
|
||||
unsigned short bigmod[5] = { 4, 0, 0, 0, 32768U };
|
||||
unsigned short mod[5] = { 4, 0, 0, 0, 0 };
|
||||
unsigned short a[5] = { 4, 0, 0, 0, 0 };
|
||||
unsigned short b[5] = { 4, 0, 0, 0, 0 };
|
||||
unsigned short c[5] = { 4, 0, 0, 0, 0 };
|
||||
unsigned short One[2] = { 1, 1 };
|
||||
unsigned short Two[2] = { 1, 2 };
|
||||
|
||||
int main(void) {
|
||||
modmult(P1, P2, bigmod, a); debug(a);
|
||||
modmult(a, P3, bigmod, mod); debug(mod);
|
||||
|
||||
sub(P1, One, a); debug(a);
|
||||
sub(P2, One, b); debug(b);
|
||||
modmult(a, b, bigmod, c); debug(c);
|
||||
sub(P3, One, a); debug(a);
|
||||
modmult(a, c, bigmod, b); debug(b);
|
||||
|
||||
modpow(Two, b, mod, a); debug(a);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
141
sshsha.c
Normal file
141
sshsha.c
Normal file
@ -0,0 +1,141 @@
|
||||
/*
|
||||
* The following code was taken directly from drivers/char/random.c
|
||||
* in the Linux kernel.
|
||||
*/
|
||||
|
||||
#include "ssh.h"
|
||||
|
||||
/*
|
||||
* SHA transform algorithm, taken from code written by Peter Gutman,
|
||||
* and apparently in the public domain.
|
||||
*/
|
||||
|
||||
/* The SHA f()-functions. */
|
||||
|
||||
#define f1(x,y,z) ( z ^ ( x & ( y ^ z ) ) ) /* Rounds 0-19 */
|
||||
#define f2(x,y,z) ( x ^ y ^ z ) /* Rounds 20-39 */
|
||||
#define f3(x,y,z) ( ( x & y ) | ( z & ( x | y ) ) ) /* Rounds 40-59 */
|
||||
#define f4(x,y,z) ( x ^ y ^ z ) /* Rounds 60-79 */
|
||||
|
||||
/* The SHA Mysterious Constants */
|
||||
|
||||
#define K1 0x5A827999L /* Rounds 0-19 */
|
||||
#define K2 0x6ED9EBA1L /* Rounds 20-39 */
|
||||
#define K3 0x8F1BBCDCL /* Rounds 40-59 */
|
||||
#define K4 0xCA62C1D6L /* Rounds 60-79 */
|
||||
|
||||
#define ROTL(n,X) ( ( ( X ) << n ) | ( ( X ) >> ( 32 - n ) ) )
|
||||
|
||||
#define expand(W,i) ( W[ i & 15 ] = \
|
||||
ROTL( 1, ( W[ i & 15 ] ^ W[ (i - 14) & 15 ] ^ \
|
||||
W[ (i - 8) & 15 ] ^ W[ (i - 3) & 15 ] ) ) )
|
||||
|
||||
#define subRound(a, b, c, d, e, f, k, data) \
|
||||
( e += ROTL( 5, a ) + f( b, c, d ) + k + data, b = ROTL( 30, b ) )
|
||||
|
||||
|
||||
void SHATransform(word32 *digest, word32 *data)
|
||||
{
|
||||
word32 A, B, C, D, E; /* Local vars */
|
||||
word32 eData[ 16 ]; /* Expanded data */
|
||||
|
||||
/* Set up first buffer and local data buffer */
|
||||
A = digest[ 0 ];
|
||||
B = digest[ 1 ];
|
||||
C = digest[ 2 ];
|
||||
D = digest[ 3 ];
|
||||
E = digest[ 4 ];
|
||||
memcpy( eData, data, 16*sizeof(word32));
|
||||
|
||||
/* Heavy mangling, in 4 sub-rounds of 20 iterations each. */
|
||||
subRound( A, B, C, D, E, f1, K1, eData[ 0 ] );
|
||||
subRound( E, A, B, C, D, f1, K1, eData[ 1 ] );
|
||||
subRound( D, E, A, B, C, f1, K1, eData[ 2 ] );
|
||||
subRound( C, D, E, A, B, f1, K1, eData[ 3 ] );
|
||||
subRound( B, C, D, E, A, f1, K1, eData[ 4 ] );
|
||||
subRound( A, B, C, D, E, f1, K1, eData[ 5 ] );
|
||||
subRound( E, A, B, C, D, f1, K1, eData[ 6 ] );
|
||||
subRound( D, E, A, B, C, f1, K1, eData[ 7 ] );
|
||||
subRound( C, D, E, A, B, f1, K1, eData[ 8 ] );
|
||||
subRound( B, C, D, E, A, f1, K1, eData[ 9 ] );
|
||||
subRound( A, B, C, D, E, f1, K1, eData[ 10 ] );
|
||||
subRound( E, A, B, C, D, f1, K1, eData[ 11 ] );
|
||||
subRound( D, E, A, B, C, f1, K1, eData[ 12 ] );
|
||||
subRound( C, D, E, A, B, f1, K1, eData[ 13 ] );
|
||||
subRound( B, C, D, E, A, f1, K1, eData[ 14 ] );
|
||||
subRound( A, B, C, D, E, f1, K1, eData[ 15 ] );
|
||||
subRound( E, A, B, C, D, f1, K1, expand( eData, 16 ) );
|
||||
subRound( D, E, A, B, C, f1, K1, expand( eData, 17 ) );
|
||||
subRound( C, D, E, A, B, f1, K1, expand( eData, 18 ) );
|
||||
subRound( B, C, D, E, A, f1, K1, expand( eData, 19 ) );
|
||||
|
||||
subRound( A, B, C, D, E, f2, K2, expand( eData, 20 ) );
|
||||
subRound( E, A, B, C, D, f2, K2, expand( eData, 21 ) );
|
||||
subRound( D, E, A, B, C, f2, K2, expand( eData, 22 ) );
|
||||
subRound( C, D, E, A, B, f2, K2, expand( eData, 23 ) );
|
||||
subRound( B, C, D, E, A, f2, K2, expand( eData, 24 ) );
|
||||
subRound( A, B, C, D, E, f2, K2, expand( eData, 25 ) );
|
||||
subRound( E, A, B, C, D, f2, K2, expand( eData, 26 ) );
|
||||
subRound( D, E, A, B, C, f2, K2, expand( eData, 27 ) );
|
||||
subRound( C, D, E, A, B, f2, K2, expand( eData, 28 ) );
|
||||
subRound( B, C, D, E, A, f2, K2, expand( eData, 29 ) );
|
||||
subRound( A, B, C, D, E, f2, K2, expand( eData, 30 ) );
|
||||
subRound( E, A, B, C, D, f2, K2, expand( eData, 31 ) );
|
||||
subRound( D, E, A, B, C, f2, K2, expand( eData, 32 ) );
|
||||
subRound( C, D, E, A, B, f2, K2, expand( eData, 33 ) );
|
||||
subRound( B, C, D, E, A, f2, K2, expand( eData, 34 ) );
|
||||
subRound( A, B, C, D, E, f2, K2, expand( eData, 35 ) );
|
||||
subRound( E, A, B, C, D, f2, K2, expand( eData, 36 ) );
|
||||
subRound( D, E, A, B, C, f2, K2, expand( eData, 37 ) );
|
||||
subRound( C, D, E, A, B, f2, K2, expand( eData, 38 ) );
|
||||
subRound( B, C, D, E, A, f2, K2, expand( eData, 39 ) );
|
||||
|
||||
subRound( A, B, C, D, E, f3, K3, expand( eData, 40 ) );
|
||||
subRound( E, A, B, C, D, f3, K3, expand( eData, 41 ) );
|
||||
subRound( D, E, A, B, C, f3, K3, expand( eData, 42 ) );
|
||||
subRound( C, D, E, A, B, f3, K3, expand( eData, 43 ) );
|
||||
subRound( B, C, D, E, A, f3, K3, expand( eData, 44 ) );
|
||||
subRound( A, B, C, D, E, f3, K3, expand( eData, 45 ) );
|
||||
subRound( E, A, B, C, D, f3, K3, expand( eData, 46 ) );
|
||||
subRound( D, E, A, B, C, f3, K3, expand( eData, 47 ) );
|
||||
subRound( C, D, E, A, B, f3, K3, expand( eData, 48 ) );
|
||||
subRound( B, C, D, E, A, f3, K3, expand( eData, 49 ) );
|
||||
subRound( A, B, C, D, E, f3, K3, expand( eData, 50 ) );
|
||||
subRound( E, A, B, C, D, f3, K3, expand( eData, 51 ) );
|
||||
subRound( D, E, A, B, C, f3, K3, expand( eData, 52 ) );
|
||||
subRound( C, D, E, A, B, f3, K3, expand( eData, 53 ) );
|
||||
subRound( B, C, D, E, A, f3, K3, expand( eData, 54 ) );
|
||||
subRound( A, B, C, D, E, f3, K3, expand( eData, 55 ) );
|
||||
subRound( E, A, B, C, D, f3, K3, expand( eData, 56 ) );
|
||||
subRound( D, E, A, B, C, f3, K3, expand( eData, 57 ) );
|
||||
subRound( C, D, E, A, B, f3, K3, expand( eData, 58 ) );
|
||||
subRound( B, C, D, E, A, f3, K3, expand( eData, 59 ) );
|
||||
|
||||
subRound( A, B, C, D, E, f4, K4, expand( eData, 60 ) );
|
||||
subRound( E, A, B, C, D, f4, K4, expand( eData, 61 ) );
|
||||
subRound( D, E, A, B, C, f4, K4, expand( eData, 62 ) );
|
||||
subRound( C, D, E, A, B, f4, K4, expand( eData, 63 ) );
|
||||
subRound( B, C, D, E, A, f4, K4, expand( eData, 64 ) );
|
||||
subRound( A, B, C, D, E, f4, K4, expand( eData, 65 ) );
|
||||
subRound( E, A, B, C, D, f4, K4, expand( eData, 66 ) );
|
||||
subRound( D, E, A, B, C, f4, K4, expand( eData, 67 ) );
|
||||
subRound( C, D, E, A, B, f4, K4, expand( eData, 68 ) );
|
||||
subRound( B, C, D, E, A, f4, K4, expand( eData, 69 ) );
|
||||
subRound( A, B, C, D, E, f4, K4, expand( eData, 70 ) );
|
||||
subRound( E, A, B, C, D, f4, K4, expand( eData, 71 ) );
|
||||
subRound( D, E, A, B, C, f4, K4, expand( eData, 72 ) );
|
||||
subRound( C, D, E, A, B, f4, K4, expand( eData, 73 ) );
|
||||
subRound( B, C, D, E, A, f4, K4, expand( eData, 74 ) );
|
||||
subRound( A, B, C, D, E, f4, K4, expand( eData, 75 ) );
|
||||
subRound( E, A, B, C, D, f4, K4, expand( eData, 76 ) );
|
||||
subRound( D, E, A, B, C, f4, K4, expand( eData, 77 ) );
|
||||
subRound( C, D, E, A, B, f4, K4, expand( eData, 78 ) );
|
||||
subRound( B, C, D, E, A, f4, K4, expand( eData, 79 ) );
|
||||
|
||||
/* Build message digest */
|
||||
digest[ 0 ] += A;
|
||||
digest[ 1 ] += B;
|
||||
digest[ 2 ] += C;
|
||||
digest[ 3 ] += D;
|
||||
digest[ 4 ] += E;
|
||||
}
|
720
telnet.c
Normal file
720
telnet.c
Normal file
@ -0,0 +1,720 @@
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <winsock.h>
|
||||
|
||||
#include "putty.h"
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
static SOCKET s = INVALID_SOCKET;
|
||||
|
||||
#define IAC 255 /* interpret as command: */
|
||||
#define DONT 254 /* you are not to use option */
|
||||
#define DO 253 /* please, you use option */
|
||||
#define WONT 252 /* I won't use option */
|
||||
#define WILL 251 /* I will use option */
|
||||
#define SB 250 /* interpret as subnegotiation */
|
||||
#define SE 240 /* end sub negotiation */
|
||||
|
||||
#define GA 249 /* you may reverse the line */
|
||||
#define EL 248 /* erase the current line */
|
||||
#define EC 247 /* erase the current character */
|
||||
#define AYT 246 /* are you there */
|
||||
#define AO 245 /* abort output--but let prog finish */
|
||||
#define IP 244 /* interrupt process--permanently */
|
||||
#define BREAK 243 /* break */
|
||||
#define DM 242 /* data mark--for connect. cleaning */
|
||||
#define NOP 241 /* nop */
|
||||
#define EOR 239 /* end of record (transparent mode) */
|
||||
#define ABORT 238 /* Abort process */
|
||||
#define SUSP 237 /* Suspend process */
|
||||
#define xEOF 236 /* End of file: EOF is already used... */
|
||||
|
||||
#define TELOPT_BINARY 0 /* 8-bit data path */
|
||||
#define TELOPT_ECHO 1 /* echo */
|
||||
#define TELOPT_RCP 2 /* prepare to reconnect */
|
||||
#define TELOPT_SGA 3 /* suppress go ahead */
|
||||
#define TELOPT_NAMS 4 /* approximate message size */
|
||||
#define TELOPT_STATUS 5 /* give status */
|
||||
#define TELOPT_TM 6 /* timing mark */
|
||||
#define TELOPT_RCTE 7 /* remote controlled transmission and echo */
|
||||
#define TELOPT_NAOL 8 /* negotiate about output line width */
|
||||
#define TELOPT_NAOP 9 /* negotiate about output page size */
|
||||
#define TELOPT_NAOCRD 10 /* negotiate about CR disposition */
|
||||
#define TELOPT_NAOHTS 11 /* negotiate about horizontal tabstops */
|
||||
#define TELOPT_NAOHTD 12 /* negotiate about horizontal tab disposition */
|
||||
#define TELOPT_NAOFFD 13 /* negotiate about formfeed disposition */
|
||||
#define TELOPT_NAOVTS 14 /* negotiate about vertical tab stops */
|
||||
#define TELOPT_NAOVTD 15 /* negotiate about vertical tab disposition */
|
||||
#define TELOPT_NAOLFD 16 /* negotiate about output LF disposition */
|
||||
#define TELOPT_XASCII 17 /* extended ascic character set */
|
||||
#define TELOPT_LOGOUT 18 /* force logout */
|
||||
#define TELOPT_BM 19 /* byte macro */
|
||||
#define TELOPT_DET 20 /* data entry terminal */
|
||||
#define TELOPT_SUPDUP 21 /* supdup protocol */
|
||||
#define TELOPT_SUPDUPOUTPUT 22 /* supdup output */
|
||||
#define TELOPT_SNDLOC 23 /* send location */
|
||||
#define TELOPT_TTYPE 24 /* terminal type */
|
||||
#define TELOPT_EOR 25 /* end or record */
|
||||
#define TELOPT_TUID 26 /* TACACS user identification */
|
||||
#define TELOPT_OUTMRK 27 /* output marking */
|
||||
#define TELOPT_TTYLOC 28 /* terminal location number */
|
||||
#define TELOPT_3270REGIME 29 /* 3270 regime */
|
||||
#define TELOPT_X3PAD 30 /* X.3 PAD */
|
||||
#define TELOPT_NAWS 31 /* window size */
|
||||
#define TELOPT_TSPEED 32 /* terminal speed */
|
||||
#define TELOPT_LFLOW 33 /* remote flow control */
|
||||
#define TELOPT_LINEMODE 34 /* Linemode option */
|
||||
#define TELOPT_XDISPLOC 35 /* X Display Location */
|
||||
#define TELOPT_OLD_ENVIRON 36 /* Old - Environment variables */
|
||||
#define TELOPT_AUTHENTICATION 37/* Authenticate */
|
||||
#define TELOPT_ENCRYPT 38 /* Encryption option */
|
||||
#define TELOPT_NEW_ENVIRON 39 /* New - Environment variables */
|
||||
#define TELOPT_EXOPL 255 /* extended-options-list */
|
||||
|
||||
#define TELQUAL_IS 0 /* option is... */
|
||||
#define TELQUAL_SEND 1 /* send option */
|
||||
#define TELQUAL_INFO 2 /* ENVIRON: informational version of IS */
|
||||
#define BSD_VAR 1
|
||||
#define BSD_VALUE 0
|
||||
#define RFC_VAR 0
|
||||
#define RFC_VALUE 1
|
||||
|
||||
#define CR 13
|
||||
#define LF 10
|
||||
#define NUL 0
|
||||
|
||||
#define iswritable(x) ( (x) != IAC && (x) != CR )
|
||||
|
||||
static char *telopt(int opt) {
|
||||
#define i(x) if (opt == TELOPT_ ## x) return #x;
|
||||
i(BINARY); i(ECHO); i(RCP); i(SGA); i(NAMS); i(STATUS); i(TM); i(RCTE);
|
||||
i(NAOL); i(NAOP); i(NAOCRD); i(NAOHTS); i(NAOHTD); i(NAOFFD); i(NAOVTS);
|
||||
i(NAOVTD); i(NAOLFD); i(XASCII); i(LOGOUT); i(BM); i(DET); i(SUPDUP);
|
||||
i(SUPDUPOUTPUT); i(SNDLOC); i(TTYPE); i(EOR); i(TUID); i(OUTMRK);
|
||||
i(TTYLOC); i(X3PAD); i(NAWS); i(TSPEED); i(LFLOW); i(LINEMODE);
|
||||
i(XDISPLOC); i(OLD_ENVIRON); i(AUTHENTICATION); i(ENCRYPT);
|
||||
i(NEW_ENVIRON); i(EXOPL);
|
||||
#undef i
|
||||
return "<unknown>";
|
||||
}
|
||||
|
||||
static void telnet_size(void);
|
||||
|
||||
struct Opt {
|
||||
int send; /* what we initially send */
|
||||
int nsend; /* -ve send if requested to stop it */
|
||||
int ack, nak; /* +ve and -ve acknowledgements */
|
||||
int option; /* the option code */
|
||||
enum {
|
||||
REQUESTED, ACTIVE, INACTIVE, REALLY_INACTIVE
|
||||
} state;
|
||||
};
|
||||
|
||||
static struct Opt o_naws = {WILL, WONT, DO, DONT, TELOPT_NAWS, REQUESTED};
|
||||
static struct Opt o_tspeed = {WILL, WONT, DO, DONT, TELOPT_TSPEED, REQUESTED};
|
||||
static struct Opt o_ttype = {WILL, WONT, DO, DONT, TELOPT_TTYPE, REQUESTED};
|
||||
static struct Opt o_oenv = {WILL, WONT, DO, DONT, TELOPT_OLD_ENVIRON,
|
||||
INACTIVE};
|
||||
static struct Opt o_nenv = {WILL, WONT, DO, DONT, TELOPT_NEW_ENVIRON,
|
||||
REQUESTED};
|
||||
static struct Opt o_echo = {DO, DONT, WILL, WONT, TELOPT_ECHO, REQUESTED};
|
||||
static struct Opt o_we_sga = {WILL, WONT, DO, DONT, TELOPT_SGA, REQUESTED};
|
||||
static struct Opt o_they_sga = {DO, DONT, WILL, WONT, TELOPT_SGA, REQUESTED};
|
||||
|
||||
static struct Opt *opts[] = {
|
||||
&o_naws, &o_tspeed, &o_ttype, &o_oenv, &o_nenv, &o_echo,
|
||||
&o_we_sga, &o_they_sga, NULL
|
||||
};
|
||||
|
||||
#if 0
|
||||
static int in_synch;
|
||||
#endif
|
||||
|
||||
static int sb_opt, sb_len;
|
||||
static char *sb_buf = NULL;
|
||||
static int sb_size = 0;
|
||||
#define SB_DELTA 1024
|
||||
|
||||
static void try_write (void) {
|
||||
while (outbuf_head != outbuf_reap) {
|
||||
int end = (outbuf_reap < outbuf_head ? outbuf_head : OUTBUF_SIZE);
|
||||
int len = end - outbuf_reap;
|
||||
int ret;
|
||||
|
||||
ret = send (s, outbuf+outbuf_reap, len, 0);
|
||||
if (ret > 0)
|
||||
outbuf_reap = (outbuf_reap + ret) & OUTBUF_MASK;
|
||||
if (ret < len)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void s_write (void *buf, int len) {
|
||||
unsigned char *p = buf;
|
||||
while (len--) {
|
||||
int new_head = (outbuf_head + 1) & OUTBUF_MASK;
|
||||
if (new_head != outbuf_reap) {
|
||||
outbuf[outbuf_head] = *p++;
|
||||
outbuf_head = new_head;
|
||||
}
|
||||
}
|
||||
try_write();
|
||||
}
|
||||
|
||||
static void c_write (char *buf, int len) {
|
||||
while (len--) {
|
||||
int new_head = (inbuf_head + 1) & INBUF_MASK;
|
||||
int c = (unsigned char) *buf;
|
||||
if (new_head != inbuf_reap) {
|
||||
inbuf[inbuf_head] = *buf++;
|
||||
inbuf_head = new_head;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void log_option (char *sender, int cmd, int option) {
|
||||
char buf[50];
|
||||
sprintf(buf, "%s:\t%s %s", sender,
|
||||
(cmd == WILL ? "WILL" : cmd == WONT ? "WONT" :
|
||||
cmd == DO ? "DO" : cmd == DONT ? "DONT" : "<??>"),
|
||||
telopt(option));
|
||||
lognegot(buf);
|
||||
}
|
||||
|
||||
static void send_opt (int cmd, int option) {
|
||||
unsigned char b[3];
|
||||
|
||||
b[0] = IAC; b[1] = cmd; b[2] = option;
|
||||
s_write (b, 3);
|
||||
log_option("client", cmd, option);
|
||||
}
|
||||
|
||||
static void deactivate_option (struct Opt *o) {
|
||||
if (o->state == REQUESTED || o->state == ACTIVE)
|
||||
send_opt (o->nsend, o->option);
|
||||
o->state = REALLY_INACTIVE;
|
||||
}
|
||||
|
||||
static void activate_option (struct Opt *o) {
|
||||
if (o->send == WILL && o->option == TELOPT_NAWS)
|
||||
telnet_size();
|
||||
if (o->send == WILL &&
|
||||
(o->option == TELOPT_NEW_ENVIRON ||
|
||||
o->option == TELOPT_OLD_ENVIRON)) {
|
||||
/*
|
||||
* We may only have one kind of ENVIRON going at a time.
|
||||
* This is a hack, but who cares.
|
||||
*/
|
||||
deactivate_option (o->option==TELOPT_NEW_ENVIRON ? &o_oenv : &o_nenv);
|
||||
}
|
||||
}
|
||||
|
||||
static void refused_option (struct Opt *o) {
|
||||
if (o->send == WILL && o->option == TELOPT_NEW_ENVIRON &&
|
||||
o_oenv.state == INACTIVE) {
|
||||
send_opt (WILL, TELOPT_OLD_ENVIRON);
|
||||
o_oenv.state = REQUESTED;
|
||||
}
|
||||
}
|
||||
|
||||
static void proc_rec_opt (int cmd, int option) {
|
||||
struct Opt **o;
|
||||
|
||||
log_option ("server", cmd, option);
|
||||
for (o = opts; *o; o++) {
|
||||
if ((*o)->option == option && (*o)->ack == cmd) {
|
||||
switch ((*o)->state) {
|
||||
case REQUESTED:
|
||||
(*o)->state = ACTIVE;
|
||||
activate_option (*o);
|
||||
break;
|
||||
case ACTIVE:
|
||||
break;
|
||||
case INACTIVE:
|
||||
(*o)->state = ACTIVE;
|
||||
send_opt ((*o)->send, option);
|
||||
activate_option (*o);
|
||||
break;
|
||||
case REALLY_INACTIVE:
|
||||
send_opt ((*o)->nsend, option);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
} else if ((*o)->option == option && (*o)->nak == cmd) {
|
||||
switch ((*o)->state) {
|
||||
case REQUESTED:
|
||||
(*o)->state = INACTIVE;
|
||||
refused_option (*o);
|
||||
break;
|
||||
case ACTIVE:
|
||||
(*o)->state = INACTIVE;
|
||||
send_opt ((*o)->nsend, option);
|
||||
break;
|
||||
case INACTIVE:
|
||||
case REALLY_INACTIVE:
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* If we reach here, the option was one we weren't prepared to
|
||||
* cope with. So send a negative ack.
|
||||
*/
|
||||
send_opt ((cmd == WILL ? DONT : WONT), option);
|
||||
}
|
||||
|
||||
static void process_subneg (void) {
|
||||
unsigned char b[2048], *p, *q;
|
||||
int var, value, n;
|
||||
char *e;
|
||||
|
||||
switch (sb_opt) {
|
||||
case TELOPT_TSPEED:
|
||||
if (sb_len == 1 && sb_buf[0] == TELQUAL_SEND) {
|
||||
char logbuf[sizeof(cfg.termspeed)+80];
|
||||
b[0] = IAC; b[1] = SB; b[2] = TELOPT_TSPEED;
|
||||
b[3] = TELQUAL_IS;
|
||||
strcpy(b+4, cfg.termspeed);
|
||||
n = 4 + strlen(cfg.termspeed);
|
||||
b[n] = IAC; b[n+1] = SE;
|
||||
s_write (b, n+2);
|
||||
lognegot("server:\tSB TSPEED SEND");
|
||||
sprintf(logbuf, "client:\tSB TSPEED IS %s", cfg.termspeed);
|
||||
lognegot (logbuf);
|
||||
} else
|
||||
lognegot ("server:\tSB TSPEED <something weird>");
|
||||
break;
|
||||
case TELOPT_TTYPE:
|
||||
if (sb_len == 1 && sb_buf[0] == TELQUAL_SEND) {
|
||||
char logbuf[sizeof(cfg.termtype)+80];
|
||||
b[0] = IAC; b[1] = SB; b[2] = TELOPT_TTYPE;
|
||||
b[3] = TELQUAL_IS;
|
||||
for (n = 0; cfg.termtype[n]; n++)
|
||||
b[n+4] = (cfg.termtype[n] >= 'a' && cfg.termtype[n] <= 'z' ?
|
||||
cfg.termtype[n] + 'A'-'a' : cfg.termtype[n]);
|
||||
b[n+4] = IAC; b[n+5] = SE;
|
||||
s_write (b, n+6);
|
||||
b[n+4] = 0;
|
||||
lognegot("server:\tSB TTYPE SEND");
|
||||
sprintf(logbuf, "client:\tSB TTYPE IS %s", b+4);
|
||||
lognegot(logbuf);
|
||||
} else
|
||||
lognegot("server:\tSB TTYPE <something weird>\r\n");
|
||||
break;
|
||||
case TELOPT_OLD_ENVIRON:
|
||||
case TELOPT_NEW_ENVIRON:
|
||||
p = sb_buf;
|
||||
q = p + sb_len;
|
||||
if (p < q && *p == TELQUAL_SEND) {
|
||||
char logbuf[50];
|
||||
p++;
|
||||
sprintf (logbuf, "server:\tSB %s SEND", telopt(sb_opt));
|
||||
lognegot (logbuf);
|
||||
if (sb_opt == TELOPT_OLD_ENVIRON) {
|
||||
if (cfg.rfc_environ) {
|
||||
value = RFC_VALUE;
|
||||
var = RFC_VAR;
|
||||
} else {
|
||||
value = BSD_VALUE;
|
||||
var = BSD_VAR;
|
||||
}
|
||||
/*
|
||||
* Try to guess the sense of VAR and VALUE.
|
||||
*/
|
||||
while (p < q) {
|
||||
if (*p == RFC_VAR) {
|
||||
value = RFC_VALUE;
|
||||
var = RFC_VAR;
|
||||
} else if (*p == BSD_VAR) {
|
||||
value = BSD_VALUE;
|
||||
var = BSD_VAR;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* With NEW_ENVIRON, the sense of VAR and VALUE
|
||||
* isn't in doubt.
|
||||
*/
|
||||
value = RFC_VALUE;
|
||||
var = RFC_VAR;
|
||||
}
|
||||
b[0] = IAC; b[1] = SB; b[2] = sb_opt;
|
||||
b[3] = TELQUAL_IS;
|
||||
n = 4;
|
||||
e = cfg.environ;
|
||||
while (*e) {
|
||||
b[n++] = var;
|
||||
while (*e && *e != '\t') b[n++] = *e++;
|
||||
if (*e == '\t') e++;
|
||||
b[n++] = value;
|
||||
while (*e) b[n++] = *e++;
|
||||
e++;
|
||||
}
|
||||
if (*cfg.username) {
|
||||
b[n++] = var; b[n++] = 'U'; b[n++] = 'S';
|
||||
b[n++] = 'E'; b[n++] = 'R'; b[n++] = value;
|
||||
e = cfg.username;
|
||||
while (*e) b[n++] = *e++;
|
||||
}
|
||||
b[n++] = IAC; b[n++] = SE;
|
||||
s_write (b, n);
|
||||
sprintf(logbuf, "client:\tSB %s IS %s", telopt(sb_opt),
|
||||
n==6 ? "<nothing>" : "<stuff>");
|
||||
lognegot (logbuf);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static enum {
|
||||
TOPLEVEL, SEENIAC, SEENWILL, SEENWONT, SEENDO, SEENDONT,
|
||||
SEENSB, SUBNEGOT, SUBNEG_IAC, SEENCR
|
||||
} telnet_state = TOPLEVEL;
|
||||
|
||||
static void do_telnet_read (char *buf, int len) {
|
||||
unsigned char b[10];
|
||||
|
||||
while (len--) {
|
||||
int c = (unsigned char) *buf++;
|
||||
|
||||
switch (telnet_state) {
|
||||
case TOPLEVEL:
|
||||
case SEENCR:
|
||||
if (c == NUL && telnet_state == SEENCR)
|
||||
telnet_state = TOPLEVEL;
|
||||
else if (c == IAC)
|
||||
telnet_state = SEENIAC;
|
||||
else {
|
||||
b[0] = c;
|
||||
#if 0
|
||||
if (!in_synch)
|
||||
#endif
|
||||
c_write (b, 1);
|
||||
if (c == CR)
|
||||
telnet_state = SEENCR;
|
||||
else
|
||||
telnet_state = TOPLEVEL;
|
||||
}
|
||||
break;
|
||||
case SEENIAC:
|
||||
if (c == DO) telnet_state = SEENDO;
|
||||
else if (c == DONT) telnet_state = SEENDONT;
|
||||
else if (c == WILL) telnet_state = SEENWILL;
|
||||
else if (c == WONT) telnet_state = SEENWONT;
|
||||
else if (c == SB) telnet_state = SEENSB;
|
||||
else telnet_state = TOPLEVEL;/* ignore _everything_ else! */
|
||||
break;
|
||||
case SEENWILL:
|
||||
proc_rec_opt (WILL, c);
|
||||
telnet_state = TOPLEVEL;
|
||||
break;
|
||||
case SEENWONT:
|
||||
proc_rec_opt (WONT, c);
|
||||
telnet_state = TOPLEVEL;
|
||||
break;
|
||||
case SEENDO:
|
||||
proc_rec_opt (DO, c);
|
||||
telnet_state = TOPLEVEL;
|
||||
break;
|
||||
case SEENDONT:
|
||||
proc_rec_opt (DONT, c);
|
||||
telnet_state = TOPLEVEL;
|
||||
break;
|
||||
case SEENSB:
|
||||
sb_opt = c;
|
||||
sb_len = 0;
|
||||
telnet_state = SUBNEGOT;
|
||||
break;
|
||||
case SUBNEGOT:
|
||||
if (c == IAC)
|
||||
telnet_state = SUBNEG_IAC;
|
||||
else {
|
||||
subneg_addchar:
|
||||
if (sb_len >= sb_size) {
|
||||
char *newbuf;
|
||||
sb_size += SB_DELTA;
|
||||
newbuf = (sb_buf ?
|
||||
realloc(sb_buf, sb_size) :
|
||||
malloc(sb_size));
|
||||
if (newbuf)
|
||||
sb_buf = newbuf;
|
||||
else
|
||||
sb_size -= SB_DELTA;
|
||||
}
|
||||
if (sb_len < sb_size)
|
||||
sb_buf[sb_len++] = c;
|
||||
telnet_state = SUBNEGOT;/* in case we came here by goto */
|
||||
}
|
||||
break;
|
||||
case SUBNEG_IAC:
|
||||
if (c != SE)
|
||||
goto subneg_addchar; /* yes, it's a hack, I know, but... */
|
||||
else {
|
||||
process_subneg();
|
||||
telnet_state = TOPLEVEL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Called to set up the Telnet connection. Will arrange for
|
||||
* WM_NETEVENT messages to be passed to the specified window, whose
|
||||
* window procedure should then call telnet_msg().
|
||||
*
|
||||
* Returns an error message, or NULL on success.
|
||||
*
|
||||
* Also places the canonical host name into `realhost'.
|
||||
*/
|
||||
static char *telnet_init (HWND hwnd, char *host, int port, char **realhost) {
|
||||
SOCKADDR_IN addr;
|
||||
struct hostent *h;
|
||||
unsigned long a;
|
||||
|
||||
/*
|
||||
* Try to find host.
|
||||
*/
|
||||
if ( (a = inet_addr(host)) == (unsigned long) INADDR_NONE) {
|
||||
if ( (h = gethostbyname(host)) == NULL)
|
||||
switch (WSAGetLastError()) {
|
||||
case WSAENETDOWN: return "Network is down";
|
||||
case WSAHOST_NOT_FOUND: case WSANO_DATA:
|
||||
return "Host does not exist";
|
||||
case WSATRY_AGAIN: return "Host not found";
|
||||
default: return "gethostbyname: unknown error";
|
||||
}
|
||||
memcpy (&a, h->h_addr, sizeof(a));
|
||||
*realhost = h->h_name;
|
||||
} else
|
||||
*realhost = host;
|
||||
a = ntohl(a);
|
||||
|
||||
if (port < 0)
|
||||
port = 23; /* default telnet port */
|
||||
|
||||
/*
|
||||
* Open socket.
|
||||
*/
|
||||
s = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (s == INVALID_SOCKET)
|
||||
switch (WSAGetLastError()) {
|
||||
case WSAENETDOWN: return "Network is down";
|
||||
case WSAEAFNOSUPPORT: return "TCP/IP support not present";
|
||||
default: return "socket(): unknown error";
|
||||
}
|
||||
|
||||
#if 0
|
||||
{
|
||||
BOOL b = TRUE;
|
||||
setsockopt (s, SOL_SOCKET, SO_OOBINLINE, (void *)&b, sizeof(b));
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Bind to local address.
|
||||
*/
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
addr.sin_port = htons(0);
|
||||
if (bind (s, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR)
|
||||
switch (WSAGetLastError()) {
|
||||
case WSAENETDOWN: return "Network is down";
|
||||
default: return "bind(): unknown error";
|
||||
}
|
||||
|
||||
/*
|
||||
* Connect to remote address.
|
||||
*/
|
||||
addr.sin_addr.s_addr = htonl(a);
|
||||
addr.sin_port = htons((short)port);
|
||||
if (connect (s, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR)
|
||||
switch (WSAGetLastError()) {
|
||||
case WSAENETDOWN: return "Network is down";
|
||||
case WSAECONNREFUSED: return "Connection refused";
|
||||
case WSAENETUNREACH: return "Network is unreachable";
|
||||
case WSAEHOSTUNREACH: return "No route to host";
|
||||
default: return "connect(): unknown error";
|
||||
}
|
||||
|
||||
if (WSAAsyncSelect (s, hwnd, WM_NETEVENT, FD_READ |
|
||||
FD_WRITE | FD_OOB | FD_CLOSE) == SOCKET_ERROR)
|
||||
switch (WSAGetLastError()) {
|
||||
case WSAENETDOWN: return "Network is down";
|
||||
default: return "WSAAsyncSelect(): unknown error";
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialise option states.
|
||||
*/
|
||||
{
|
||||
struct Opt **o;
|
||||
|
||||
for (o = opts; *o; o++)
|
||||
if ((*o)->state == REQUESTED)
|
||||
send_opt ((*o)->send, (*o)->option);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Set up SYNCH state.
|
||||
*/
|
||||
in_synch = FALSE;
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Process a WM_NETEVENT message. Will return 0 if the connection
|
||||
* has closed, or <0 for a socket error.
|
||||
*/
|
||||
static int telnet_msg (WPARAM wParam, LPARAM lParam) {
|
||||
int ret;
|
||||
char buf[256];
|
||||
|
||||
if (s == INVALID_SOCKET) /* how the hell did we get here?! */
|
||||
return -5000;
|
||||
|
||||
if (WSAGETSELECTERROR(lParam) != 0)
|
||||
return -WSAGETSELECTERROR(lParam);
|
||||
|
||||
switch (WSAGETSELECTEVENT(lParam)) {
|
||||
case FD_READ:
|
||||
ret = recv(s, buf, sizeof(buf), 0);
|
||||
if (ret < 0 && WSAGetLastError() == WSAEWOULDBLOCK)
|
||||
return 1;
|
||||
if (ret < 0) /* any _other_ error */
|
||||
return -10000-WSAGetLastError();
|
||||
if (ret == 0) {
|
||||
s = INVALID_SOCKET;
|
||||
return 0; /* can't happen, in theory */
|
||||
}
|
||||
#if 0
|
||||
if (in_synch) {
|
||||
BOOL i;
|
||||
if (ioctlsocket (s, SIOCATMARK, &i) < 0) {
|
||||
return -20000-WSAGetLastError();
|
||||
}
|
||||
if (i)
|
||||
in_synch = FALSE;
|
||||
}
|
||||
#endif
|
||||
do_telnet_read (buf, ret);
|
||||
return 1;
|
||||
case FD_OOB:
|
||||
do {
|
||||
ret = recv(s, buf, sizeof(buf), 0);
|
||||
} while (ret > 0);
|
||||
telnet_state = TOPLEVEL;
|
||||
do {
|
||||
ret = recv(s, buf, 1, MSG_OOB);
|
||||
if (ret > 0)
|
||||
do_telnet_read (buf, ret);
|
||||
} while (ret > 0);
|
||||
if (ret < 0 && WSAGetLastError() != WSAEWOULDBLOCK)
|
||||
return -30000-WSAGetLastError();
|
||||
return 1;
|
||||
case FD_WRITE:
|
||||
if (outbuf_head != outbuf_reap)
|
||||
try_write();
|
||||
return 1;
|
||||
case FD_CLOSE:
|
||||
s = INVALID_SOCKET;
|
||||
return 0;
|
||||
}
|
||||
return 1; /* shouldn't happen, but WTF */
|
||||
}
|
||||
|
||||
/*
|
||||
* Called to send data down the Telnet connection.
|
||||
*/
|
||||
static void telnet_send (char *buf, int len) {
|
||||
char *p;
|
||||
static unsigned char iac[2] = { IAC, IAC };
|
||||
static unsigned char cr[2] = { CR, NUL };
|
||||
|
||||
if (s == INVALID_SOCKET)
|
||||
return;
|
||||
|
||||
p = buf;
|
||||
while (p < buf+len) {
|
||||
char *q = p;
|
||||
|
||||
while (iswritable((unsigned char)*p) && p < buf+len) p++;
|
||||
s_write (q, p-q);
|
||||
|
||||
while (p < buf+len && !iswritable((unsigned char)*p)) {
|
||||
s_write ((unsigned char)*p == IAC ? iac : cr, 2);
|
||||
p++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Called to set the size of the window from Telnet's POV.
|
||||
*/
|
||||
static void telnet_size(void) {
|
||||
unsigned char b[16];
|
||||
char logbuf[50];
|
||||
|
||||
if (s == INVALID_SOCKET || o_naws.state != ACTIVE)
|
||||
return;
|
||||
b[0] = IAC; b[1] = SB; b[2] = TELOPT_NAWS;
|
||||
b[3] = cols >> 8; b[4] = cols & 0xFF;
|
||||
b[5] = rows >> 8; b[6] = rows & 0xFF;
|
||||
b[7] = IAC; b[8] = SE;
|
||||
s_write (b, 9);
|
||||
sprintf(logbuf, "client:\tSB NAWS %d,%d",
|
||||
((unsigned char)b[3] << 8) + (unsigned char)b[4],
|
||||
((unsigned char)b[5] << 8) + (unsigned char)b[6]);
|
||||
lognegot (logbuf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send Telnet special codes.
|
||||
*/
|
||||
static void telnet_special (Telnet_Special code) {
|
||||
unsigned char b[2];
|
||||
|
||||
if (s == INVALID_SOCKET)
|
||||
return;
|
||||
|
||||
b[0] = IAC;
|
||||
switch (code) {
|
||||
case TS_AYT: b[1] = AYT; s_write (b, 2); break;
|
||||
case TS_BRK: b[1] = BREAK; s_write (b, 2); break;
|
||||
case TS_EC: b[1] = EC; s_write (b, 2); break;
|
||||
case TS_EL: b[1] = EL; s_write (b, 2); break;
|
||||
case TS_GA: b[1] = GA; s_write (b, 2); break;
|
||||
case TS_NOP: b[1] = NOP; s_write (b, 2); break;
|
||||
case TS_ABORT: b[1] = ABORT; s_write (b, 2); break;
|
||||
case TS_AO: b[1] = AO; s_write (b, 2); break;
|
||||
case TS_IP: b[1] = IP; s_write (b, 2); break;
|
||||
case TS_SUSP: b[1] = SUSP; s_write (b, 2); break;
|
||||
case TS_EOR: b[1] = EOR; s_write (b, 2); break;
|
||||
case TS_EOF: b[1] = xEOF; s_write (b, 2); break;
|
||||
case TS_SYNCH:
|
||||
outbuf_head = outbuf_reap = 0;
|
||||
b[0] = DM;
|
||||
send (s, b, 1, MSG_OOB);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Backend telnet_backend = {
|
||||
telnet_init,
|
||||
telnet_msg,
|
||||
telnet_send,
|
||||
telnet_size,
|
||||
telnet_special
|
||||
};
|
1447
terminal.c
Normal file
1447
terminal.c
Normal file
File diff suppressed because it is too large
Load Diff
116
win_res.h
Normal file
116
win_res.h
Normal file
@ -0,0 +1,116 @@
|
||||
#ifndef PUTTY_WIN_RES_H
|
||||
#define PUTTY_WIN_RES_H
|
||||
|
||||
#define IDI_MAINICON 200
|
||||
|
||||
#define IDD_MAINBOX 102
|
||||
#define IDD_PANEL0 103
|
||||
#define IDD_PANEL1 104
|
||||
#define IDD_PANEL2 105
|
||||
#define IDD_PANEL3 106
|
||||
#define IDD_PANEL35 107
|
||||
#define IDD_PANEL4 108
|
||||
#define IDD_PANEL5 109
|
||||
#define IDD_LOGBOX 110
|
||||
#define IDD_ABOUTBOX 111
|
||||
#define IDD_RECONF 112
|
||||
#define IDD_LICENCEBOX 113
|
||||
|
||||
#define IDN_LIST 1001
|
||||
|
||||
#define IDA_ICON 1001
|
||||
#define IDA_TEXT 1002
|
||||
#define IDA_LICENCE 1003
|
||||
|
||||
#define IDC_TAB 1001
|
||||
#define IDC_ABOUT 1002
|
||||
|
||||
#define IDC0_HOSTSTATIC 1001
|
||||
#define IDC0_HOST 1002
|
||||
#define IDC0_PORTSTATIC 1003
|
||||
#define IDC0_PORT 1004
|
||||
#define IDC0_PROTSTATIC 1005
|
||||
#define IDC0_PROTTELNET 1006
|
||||
#define IDC0_PROTSSH 1007
|
||||
#define IDC0_SESSSTATIC 1008
|
||||
#define IDC0_SESSEDIT 1009
|
||||
#define IDC0_SESSLIST 1010
|
||||
#define IDC0_SESSLOAD 1011
|
||||
#define IDC0_SESSSAVE 1012
|
||||
#define IDC0_SESSDEL 1013
|
||||
#define IDC0_CLOSEEXIT 1014
|
||||
|
||||
#define IDC1_DELSTATIC 1001
|
||||
#define IDC1_DEL008 1002
|
||||
#define IDC1_DEL127 1003
|
||||
#define IDC1_HOMESTATIC 1004
|
||||
#define IDC1_HOMETILDE 1005
|
||||
#define IDC1_HOMERXVT 1006
|
||||
#define IDC1_FUNCSTATIC 1007
|
||||
#define IDC1_FUNCTILDE 1008
|
||||
#define IDC1_FUNCLINUX 1009
|
||||
#define IDC1_KPSTATIC 1010
|
||||
#define IDC1_KPNORMAL 1011
|
||||
#define IDC1_KPAPPLIC 1012
|
||||
#define IDC1_CURSTATIC 1013
|
||||
#define IDC1_CURNORMAL 1014
|
||||
#define IDC1_CURAPPLIC 1015
|
||||
|
||||
#define IDC2_WRAPMODE 1001
|
||||
#define IDC2_DECOM 1002
|
||||
#define IDC2_WINNAME 1003
|
||||
#define IDC2_DIMSTATIC 1004
|
||||
#define IDC2_ROWSSTATIC 1005
|
||||
#define IDC2_ROWSEDIT 1006
|
||||
#define IDC2_COLSSTATIC 1007
|
||||
#define IDC2_COLSEDIT 1008
|
||||
#define IDC2_SAVESTATIC 1009
|
||||
#define IDC2_SAVEEDIT 1010
|
||||
#define IDC2_FONTSTATIC 1011
|
||||
#define IDC2_CHOOSEFONT 1012
|
||||
#define IDC2_VTSTATIC 1013
|
||||
#define IDC2_VTXWINDOWS 1014
|
||||
#define IDC2_VTOEMANSI 1015
|
||||
#define IDC2_VTOEMONLY 1016
|
||||
#define IDC2_VTPOORMAN 1017
|
||||
|
||||
#define IDC3_TTSTATIC 1001
|
||||
#define IDC3_TTEDIT 1002
|
||||
#define IDC3_TSSTATIC 1003
|
||||
#define IDC3_TSEDIT 1004
|
||||
#define IDC3_LOGSTATIC 1005
|
||||
#define IDC3_LOGEDIT 1006
|
||||
#define IDC3_ENVSTATIC 1007
|
||||
#define IDC3_VARSTATIC 1008
|
||||
#define IDC3_VAREDIT 1009
|
||||
#define IDC3_VALSTATIC 1010
|
||||
#define IDC3_VALEDIT 1011
|
||||
#define IDC3_ENVLIST 1012
|
||||
#define IDC3_ENVADD 1013
|
||||
#define IDC3_ENVREMOVE 1014
|
||||
#define IDC3_EMSTATIC 1015
|
||||
#define IDC3_EMBSD 1016
|
||||
#define IDC3_EMRFC 1017
|
||||
|
||||
#define IDC4_MBSTATIC 1001
|
||||
#define IDC4_MBWINDOWS 1002
|
||||
#define IDC4_MBXTERM 1003
|
||||
#define IDC4_CCSTATIC 1004
|
||||
#define IDC4_CCLIST 1005
|
||||
#define IDC4_CCSET 1006
|
||||
#define IDC4_CCSTATIC2 1007
|
||||
#define IDC4_CCEDIT 1008
|
||||
|
||||
#define IDC5_BOLDCOLOUR 1001
|
||||
#define IDC5_PALETTE 1002
|
||||
#define IDC5_STATIC 1003
|
||||
#define IDC5_LIST 1004
|
||||
#define IDC5_RSTATIC 1005
|
||||
#define IDC5_GSTATIC 1006
|
||||
#define IDC5_BSTATIC 1007
|
||||
#define IDC5_RVALUE 1008
|
||||
#define IDC5_GVALUE 1009
|
||||
#define IDC5_BVALUE 1010
|
||||
#define IDC5_CHANGE 1011
|
||||
|
||||
#endif
|
235
win_res.rc
Normal file
235
win_res.rc
Normal file
@ -0,0 +1,235 @@
|
||||
#include <winresrc.h>
|
||||
|
||||
#define TCS_MULTILINE 0x0200
|
||||
|
||||
#include "win_res.h"
|
||||
|
||||
IDI_MAINICON ICON "putty.ico"
|
||||
|
||||
IDD_ABOUTBOX DIALOG DISCARDABLE 140, 40, 136, 58
|
||||
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "About PuTTY"
|
||||
FONT 8, "MS Sans Serif"
|
||||
BEGIN
|
||||
DEFPUSHBUTTON "&Close", IDOK, 82, 40, 48, 14
|
||||
PUSHBUTTON "View &Licence", IDA_LICENCE, 6, 40, 70, 14
|
||||
ICON IDI_MAINICON, IDA_ICON, 10, 10, 0, 0
|
||||
LTEXT "PuTTY Beta 0.43\n\251 1997-8 Simon Tatham\nAll rights reserved.",
|
||||
IDA_TEXT, 40, 6, 96, 24
|
||||
END
|
||||
|
||||
IDD_MAINBOX DIALOG DISCARDABLE 0, 0, 180, 216
|
||||
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "PuTTY Configuration"
|
||||
FONT 8, "MS Sans Serif"
|
||||
BEGIN
|
||||
DEFPUSHBUTTON "&Open", IDOK, 86, 199, 44, 14
|
||||
PUSHBUTTON "&Cancel", IDCANCEL, 133, 199, 44, 14
|
||||
PUSHBUTTON "&About", IDC_ABOUT, 3, 199, 44, 14, NOT WS_TABSTOP
|
||||
CONTROL "", IDC_TAB, L"SysTabControl32", TCS_MULTILINE | WS_TABSTOP,
|
||||
3, 3, 174, 193
|
||||
END
|
||||
|
||||
IDD_RECONF DIALOG DISCARDABLE 0, 0, 180, 216
|
||||
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "PuTTY Reconfiguration"
|
||||
FONT 8, "MS Sans Serif"
|
||||
BEGIN
|
||||
DEFPUSHBUTTON "&Apply", IDOK, 86, 199, 44, 14
|
||||
PUSHBUTTON "&Cancel", IDCANCEL, 133, 199, 44, 14
|
||||
CONTROL "", IDC_TAB, L"SysTabControl32", TCS_MULTILINE | WS_TABSTOP,
|
||||
3, 3, 174, 193
|
||||
END
|
||||
|
||||
IDD_PANEL0 DIALOG DISCARDABLE 6, 30, 168, 163
|
||||
STYLE WS_CHILD | WS_VISIBLE | NOT WS_BORDER
|
||||
FONT 8, "MS Sans Serif"
|
||||
BEGIN
|
||||
LTEXT "Host Name", IDC0_HOSTSTATIC, 3, 3, 122, 8
|
||||
EDITTEXT IDC0_HOST, 3, 11, 122, 12, ES_AUTOHSCROLL
|
||||
LTEXT "Port", IDC0_PORTSTATIC, 131, 3, 34, 8
|
||||
EDITTEXT IDC0_PORT, 131, 11, 34, 12
|
||||
#ifdef FWHACK
|
||||
RTEXT "Protocol:", IDC0_PROTSTATIC, 3, 29, 77, 8
|
||||
AUTORADIOBUTTON "Telnet", IDC0_PROTTELNET, 86, 29, 33, 10, WS_GROUP
|
||||
AUTORADIOBUTTON "SSH/hack", IDC0_PROTSSH, 122, 29, 43, 10
|
||||
#else
|
||||
RTEXT "Protocol:", IDC0_PROTSTATIC, 3, 29, 87, 8
|
||||
AUTORADIOBUTTON "Telnet", IDC0_PROTTELNET, 96, 29, 33, 10, WS_GROUP
|
||||
AUTORADIOBUTTON "SSH", IDC0_PROTSSH, 132, 29, 33, 10
|
||||
#endif
|
||||
LTEXT "Stored Sessions", IDC0_SESSSTATIC, 3, 40, 122, 8
|
||||
EDITTEXT IDC0_SESSEDIT, 3, 48, 122, 12, ES_AUTOHSCROLL
|
||||
LISTBOX IDC0_SESSLIST, 3, 63, 122, 81, LBS_HASSTRINGS | WS_VSCROLL
|
||||
PUSHBUTTON "Load", IDC0_SESSLOAD, 131, 63, 34, 14
|
||||
PUSHBUTTON "Save", IDC0_SESSSAVE, 131, 80, 34, 14
|
||||
PUSHBUTTON "Delete", IDC0_SESSDEL, 131, 97, 34, 14
|
||||
AUTOCHECKBOX "Close Window on Exit", IDC0_CLOSEEXIT, 3, 147, 162, 10
|
||||
END
|
||||
|
||||
IDD_PANEL1 DIALOG DISCARDABLE 6, 30, 168, 163
|
||||
STYLE WS_CHILD | WS_VISIBLE | NOT WS_BORDER
|
||||
FONT 8, "MS Sans Serif"
|
||||
BEGIN
|
||||
LTEXT "Action of Backspace:", IDC1_DELSTATIC, 3, 3, 162, 8
|
||||
AUTORADIOBUTTON "Control-H (ASCII 8)", IDC1_DEL008, 3, 12, 162, 10, WS_GROUP
|
||||
AUTORADIOBUTTON "Control-? (ASCII 127)", IDC1_DEL127, 3, 22, 162, 10
|
||||
LTEXT "Action of Home and End:", IDC1_HOMESTATIC, 3, 35, 162, 8
|
||||
AUTORADIOBUTTON "Standard (ESC [ 1 ~ and ESC [ 4 ~)",
|
||||
IDC1_HOMETILDE, 3, 44, 162, 10, WS_GROUP
|
||||
AUTORADIOBUTTON "rxvt (ESC [ H and ESC O w)",
|
||||
IDC1_HOMERXVT, 3, 54, 162, 10
|
||||
LTEXT "Action of F1 through F5:", IDC1_FUNCSTATIC, 3, 67, 162, 8
|
||||
AUTORADIOBUTTON "Standard (ESC [ 11 ~ through ESC [ 15 ~)",
|
||||
IDC1_FUNCTILDE, 3, 76, 162, 10, WS_GROUP
|
||||
AUTORADIOBUTTON "Linux (ESC [ [ A through ESC [ [ E)",
|
||||
IDC1_FUNCLINUX, 3, 86, 162, 10
|
||||
LTEXT "Initial state of numeric keypad:", IDC1_KPSTATIC, 3, 99, 162, 8
|
||||
AUTORADIOBUTTON "Normal (depends on NumLock)",
|
||||
IDC1_KPNORMAL, 3, 108, 162, 10, WS_GROUP
|
||||
AUTORADIOBUTTON "Application (ESC O P etc)",
|
||||
IDC1_KPAPPLIC, 3, 118, 162, 10
|
||||
LTEXT "Initial state of cursor keys:", IDC1_CURSTATIC, 3, 131, 162, 8
|
||||
AUTORADIOBUTTON "Normal (ESC [ A through ESC [ D)",
|
||||
IDC1_CURNORMAL, 3, 140, 162, 10, WS_GROUP
|
||||
AUTORADIOBUTTON "Application (ESC O A through ESC O D)",
|
||||
IDC1_CURAPPLIC, 3, 150, 162, 10
|
||||
END
|
||||
|
||||
IDD_PANEL2 DIALOG DISCARDABLE 6, 30, 168, 163
|
||||
STYLE WS_CHILD | WS_VISIBLE | NOT WS_BORDER
|
||||
FONT 8, "MS Sans Serif"
|
||||
BEGIN
|
||||
AUTOCHECKBOX "Auto wrap mode initially on", IDC2_WRAPMODE, 3, 3, 162, 10
|
||||
AUTOCHECKBOX "DEC Origin Mode initially on", IDC2_DECOM, 3, 13, 162, 10
|
||||
AUTOCHECKBOX "Avoid ever using icon title", IDC2_WINNAME, 3, 23, 162, 10
|
||||
LTEXT "Terminal screen dimensions:", IDC2_DIMSTATIC, 3, 33, 162, 8
|
||||
RTEXT "Rows", IDC2_ROWSSTATIC, 20, 44, 90, 8
|
||||
EDITTEXT IDC2_ROWSEDIT, 118, 42, 30, 12
|
||||
RTEXT "Columns", IDC2_COLSSTATIC, 20, 59, 90, 8
|
||||
EDITTEXT IDC2_COLSEDIT, 118, 57, 30, 12
|
||||
RTEXT "Saved lines of scrollback", IDC2_SAVESTATIC, 20, 74, 90, 8
|
||||
EDITTEXT IDC2_SAVEEDIT, 118, 72, 30, 12
|
||||
LTEXT "Font:", IDC2_FONTSTATIC, 3, 93, 99, 8
|
||||
PUSHBUTTON "Change...", IDC2_CHOOSEFONT, 105, 90, 60, 14
|
||||
LTEXT "Handling of VT100 line drawing characters:",IDC2_VTSTATIC, 3, 111, 162, 8
|
||||
AUTORADIOBUTTON "Font has XWindows encoding",
|
||||
IDC2_VTXWINDOWS, 3, 120, 162, 10, WS_GROUP
|
||||
AUTORADIOBUTTON "Use font in both ANSI and OEM modes",
|
||||
IDC2_VTOEMANSI, 3, 130, 162, 10
|
||||
AUTORADIOBUTTON "Use font in OEM mode only",
|
||||
IDC2_VTOEMONLY, 3, 140, 162, 10
|
||||
AUTORADIOBUTTON "Poor man's line drawing (""+"", ""-"" and ""|"")",
|
||||
IDC2_VTPOORMAN, 3, 150, 162, 10
|
||||
END
|
||||
|
||||
IDD_PANEL3 DIALOG DISCARDABLE 6, 30, 168, 163
|
||||
STYLE WS_CHILD | WS_VISIBLE | NOT WS_BORDER
|
||||
FONT 8, "MS Sans Serif"
|
||||
BEGIN
|
||||
LTEXT "Terminal-type string", IDC3_TTSTATIC, 3, 5, 90, 8
|
||||
EDITTEXT IDC3_TTEDIT, 96, 3, 69, 12, ES_AUTOHSCROLL
|
||||
LTEXT "Terminal-speed string", IDC3_TSSTATIC, 3, 20, 90, 8
|
||||
EDITTEXT IDC3_TSEDIT, 96, 18, 69, 12, ES_AUTOHSCROLL
|
||||
LTEXT "Auto-login username", IDC3_LOGSTATIC, 3, 35, 90, 8
|
||||
EDITTEXT IDC3_LOGEDIT, 96, 33, 69, 12, ES_AUTOHSCROLL
|
||||
LTEXT "Environment variables:", IDC3_ENVSTATIC, 3, 53, 162, 8
|
||||
LTEXT "Variable", IDC3_VARSTATIC, 3, 70, 29, 8
|
||||
EDITTEXT IDC3_VAREDIT, 35, 68, 35, 12, ES_AUTOHSCROLL
|
||||
LTEXT "Value", IDC3_VALSTATIC, 76, 70, 19, 8
|
||||
EDITTEXT IDC3_VALEDIT, 98, 68, 67, 12, ES_AUTOHSCROLL
|
||||
LISTBOX IDC3_ENVLIST, 3, 85, 122, 55,
|
||||
LBS_HASSTRINGS | LBS_USETABSTOPS | WS_VSCROLL
|
||||
PUSHBUTTON "Add", IDC3_ENVADD, 131, 85, 34, 14
|
||||
PUSHBUTTON "Remove", IDC3_ENVREMOVE, 131, 102, 34, 14
|
||||
LTEXT "ENVIRON interpretation:", IDC3_EMSTATIC, 3, 147, 90, 8
|
||||
AUTORADIOBUTTON "BSD", IDC3_EMBSD, 96, 147, 33, 10, WS_GROUP
|
||||
AUTORADIOBUTTON "RFC", IDC3_EMRFC, 132, 147, 33, 10
|
||||
END
|
||||
|
||||
IDD_PANEL35 DIALOG DISCARDABLE 6, 30, 168, 163
|
||||
STYLE WS_CHILD | WS_VISIBLE | NOT WS_BORDER
|
||||
FONT 8, "MS Sans Serif"
|
||||
BEGIN
|
||||
LTEXT "Terminal-type string", IDC3_TTSTATIC, 3, 5, 90, 8
|
||||
EDITTEXT IDC3_TTEDIT, 96, 3, 69, 12, ES_AUTOHSCROLL
|
||||
LTEXT "Auto-login username", IDC3_LOGSTATIC, 3, 35, 90, 8
|
||||
EDITTEXT IDC3_LOGEDIT, 96, 33, 69, 12, ES_AUTOHSCROLL
|
||||
END
|
||||
|
||||
IDD_PANEL4 DIALOG DISCARDABLE 6, 30, 168, 163
|
||||
STYLE WS_CHILD | WS_VISIBLE | NOT WS_BORDER
|
||||
FONT 8, "MS Sans Serif"
|
||||
BEGIN
|
||||
LTEXT "Action of mouse buttons:", IDC4_MBSTATIC, 3, 3, 162, 8
|
||||
AUTORADIOBUTTON "Windows (Right pastes, Middle extends)",
|
||||
IDC4_MBWINDOWS, 3, 12, 162, 10, WS_GROUP
|
||||
AUTORADIOBUTTON "xterm (Right extends, Middle pastes)",
|
||||
IDC4_MBXTERM, 3, 22, 162, 10
|
||||
LTEXT "Character classes:", IDC4_CCSTATIC, 3, 35, 162, 8
|
||||
LISTBOX IDC4_CCLIST, 3, 45, 162, 96,
|
||||
LBS_HASSTRINGS | WS_VSCROLL | LBS_USETABSTOPS | LBS_MULTIPLESEL
|
||||
PUSHBUTTON "Set", IDC4_CCSET, 33, 145, 34, 14
|
||||
LTEXT "to class", IDC4_CCSTATIC2, 73, 148, 26, 8
|
||||
EDITTEXT IDC4_CCEDIT, 105, 146, 36, 12
|
||||
END
|
||||
|
||||
IDD_PANEL5 DIALOG DISCARDABLE 6, 30, 168, 163
|
||||
STYLE WS_CHILD | WS_VISIBLE | NOT WS_BORDER
|
||||
FONT 8, "MS Sans Serif"
|
||||
BEGIN
|
||||
AUTOCHECKBOX "Bolded text is a different colour", IDC5_BOLDCOLOUR,3, 10, 162, 10
|
||||
AUTOCHECKBOX "Attempt to use logical palettes", IDC5_PALETTE, 3, 25, 162, 10
|
||||
LTEXT "Colours:", IDC5_STATIC, 3, 40, 162, 8
|
||||
LISTBOX IDC5_LIST, 3, 50, 100, 110, LBS_HASSTRINGS | WS_VSCROLL
|
||||
LTEXT "Red:", IDC5_RSTATIC, 109, 50, 27, 8
|
||||
RTEXT "", IDC5_RVALUE, 138, 50, 27, 8
|
||||
LTEXT "Green:", IDC5_GSTATIC, 109, 58, 27, 8
|
||||
RTEXT "", IDC5_GVALUE, 138, 58, 27, 8
|
||||
LTEXT "Blue:", IDC5_BSTATIC, 109, 66, 27, 8
|
||||
RTEXT "", IDC5_BVALUE, 138, 66, 27, 8
|
||||
PUSHBUTTON "Change...", IDC5_CHANGE, 109, 140, 56, 14
|
||||
END
|
||||
|
||||
IDD_LOGBOX DIALOG DISCARDABLE 100, 20, 160, 119
|
||||
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "PuTTY Negotiation Log"
|
||||
FONT 8, "MS Sans Serif"
|
||||
BEGIN
|
||||
DEFPUSHBUTTON "&Close", IDOK, 58, 102, 44, 14
|
||||
LISTBOX IDN_LIST, 3, 3, 154, 95, LBS_HASSTRINGS | LBS_USETABSTOPS | WS_VSCROLL
|
||||
END
|
||||
|
||||
IDD_LICENCEBOX DIALOG DISCARDABLE 50, 50, 226, 231
|
||||
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "PuTTY Licence"
|
||||
FONT 8, "MS Sans Serif"
|
||||
BEGIN
|
||||
DEFPUSHBUTTON "OK", IDOK, 98, 211, 44, 14
|
||||
|
||||
LTEXT "Copyright \251 1998 Simon Tatham", 1000, 10, 10, 206, 8
|
||||
LTEXT "Portions copyright Gary S. Brown and Eric Young", 1100, 10, 18, 206, 8
|
||||
|
||||
LTEXT "Permission is hereby granted, free of charge, to any person", 1002, 10, 34, 206, 8
|
||||
LTEXT "obtaining a copy of this software and associated documentation", 1003, 10, 42, 206, 8
|
||||
LTEXT "files (the ""Software""), to deal in the Software without restriction,", 1004, 10, 50, 206, 8
|
||||
LTEXT "including without limitation the rights to use, copy, modify, merge,", 1005, 10, 58, 206, 8
|
||||
LTEXT "publish, distribute, sublicense, and/or sell copies of the Software,", 1006, 10, 66, 206, 8
|
||||
LTEXT "and to permit persons to whom the Software is furnished to do so,", 1007, 10, 74, 206, 8
|
||||
LTEXT "subject to the following conditions:", 1008, 10, 82, 206, 8
|
||||
|
||||
LTEXT "The above copyright notice and this permission notice shall be", 1010, 10, 98, 206, 8
|
||||
LTEXT "included in all copies or substantial portions of the Software.", 1011, 10, 106, 206, 8
|
||||
|
||||
LTEXT "THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT", 1013, 10, 122, 206, 8
|
||||
LTEXT "WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,", 1014, 10, 130, 206, 8
|
||||
LTEXT "INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF", 1015, 10, 138, 206, 8
|
||||
LTEXT "MERCHANTABILITY, FITNESS FOR A PARTICULAR", 1016, 10, 146, 206, 8
|
||||
LTEXT "PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL", 1017, 10, 154, 206, 8
|
||||
LTEXT "SIMON TATHAM BE LIABLE FOR ANY CLAIM, DAMAGES OR", 1018, 10, 162, 206, 8
|
||||
LTEXT "OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,", 1019, 10, 170, 206, 8
|
||||
LTEXT "TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN", 1020, 10, 178, 206, 8
|
||||
LTEXT "CONNECTION WITH THE SOFTWARE OR THE USE OR", 1021, 10, 186, 206, 8
|
||||
LTEXT "OTHER DEALINGS IN THE SOFTWARE.", 1022, 10, 194, 206, 8
|
||||
|
||||
END
|
Loading…
Reference in New Issue
Block a user