summaryrefslogtreecommitdiffstats
path: root/tcllib/modules/rc4/rc4c.tcl
diff options
context:
space:
mode:
Diffstat (limited to 'tcllib/modules/rc4/rc4c.tcl')
-rw-r--r--tcllib/modules/rc4/rc4c.tcl168
1 files changed, 168 insertions, 0 deletions
diff --git a/tcllib/modules/rc4/rc4c.tcl b/tcllib/modules/rc4/rc4c.tcl
new file mode 100644
index 0000000..fd717df
--- /dev/null
+++ b/tcllib/modules/rc4/rc4c.tcl
@@ -0,0 +1,168 @@
+# rc4c.tcl - Copyright (C) 2004 Pat Thoyts <patthoyts@users.sourceforge.net>
+#
+# This provides a critcl C implementation of RC4
+#
+# INSTALLATION
+# ------------
+# This package uses critcl (http://wiki.tcl.tk/critcl). To build do:
+# critcl -libdir <your-tcl-lib-dir> -pkg rc4c rc4c
+#
+# To build this for tcllib use sak.tcl:
+# tclsh sak.tcl critcl
+# generates a tcllibc module.
+#
+# $Id: rc4c.tcl,v 1.4 2009/05/07 00:14:02 patthoyts Exp $
+
+package require critcl
+# @sak notprovided rc4c
+package provide rc4c 1.1.0
+
+namespace eval ::rc4 {
+
+ critcl::ccode {
+ #include <string.h>
+
+ typedef struct RC4_CTX {
+ unsigned char x;
+ unsigned char y;
+ unsigned char s[256];
+ } RC4_CTX;
+
+ /* #define TRACE trace */
+ #define TRACE 1 ? ((void)0) : trace
+
+ static void trace(const char *format, ...)
+ {
+ va_list args;
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+ }
+ static Tcl_ObjType rc4_type;
+
+ static void rc4_free_rep(Tcl_Obj *obj)
+ {
+ RC4_CTX *ctx = (RC4_CTX *)obj->internalRep.otherValuePtr;
+ TRACE("rc4_free_rep(%08x)\n", (long)obj);
+ Tcl_Free((char *)ctx);
+ }
+
+ static void rc4_dup_rep(Tcl_Obj *obj, Tcl_Obj *dup)
+ {
+ RC4_CTX *ctx = (RC4_CTX *)obj->internalRep.otherValuePtr;
+ TRACE("rc4_dup_rep(%08x,%08x)\n", (long)obj, (long)dup);
+ dup->internalRep.otherValuePtr = (RC4_CTX *)Tcl_Alloc(sizeof(RC4_CTX));
+ memcpy(dup->internalRep.otherValuePtr, ctx, sizeof(RC4_CTX));
+ dup->typePtr = &rc4_type;
+ }
+
+ static void rc4_string_rep(Tcl_Obj* obj)
+ {
+ RC4_CTX *ctx = (RC4_CTX *)obj->internalRep.otherValuePtr;
+ Tcl_Obj* tmpObj;
+ char* str;
+ TRACE("rc4_string_rep(%08x)\n", (long)obj);
+ /* convert via a byte array to properly handle null bytes */
+ tmpObj = Tcl_NewByteArrayObj((unsigned char *)ctx, sizeof(RC4_CTX));
+ Tcl_IncrRefCount(tmpObj);
+
+ str = Tcl_GetStringFromObj(tmpObj, &obj->length);
+ obj->bytes = Tcl_Alloc(obj->length + 1);
+ memcpy(obj->bytes, str, obj->length + 1);
+
+ Tcl_DecrRefCount(tmpObj);
+ }
+
+ static int rc4_from_any(Tcl_Interp* interp, Tcl_Obj* obj)
+ {
+ TRACE("rc4_from_any %08x\n", (long)obj);
+ return TCL_ERROR;
+ }
+
+ static Tcl_ObjType rc4_type = {
+ "rc4c", rc4_free_rep, rc4_dup_rep, rc4_string_rep, rc4_from_any
+ };
+#ifdef __GNUC__
+ inline
+#elif defined(_MSC_VER)
+ __inline
+#endif
+ void swap (unsigned char *lhs, unsigned char *rhs) {
+ unsigned char t = *lhs;
+ *lhs = *rhs;
+ *rhs = t;
+ }
+ }
+
+ critcl::ccommand rc4c_init {dummy interp objc objv} {
+ RC4_CTX *ctx;
+ Tcl_Obj *obj;
+ const unsigned char *k;
+ int n = 0, i = 0, j = 0, keylen;
+
+ if (objc != 2) {
+ Tcl_WrongNumArgs(interp, 1, objv, "keystring");
+ return TCL_ERROR;
+ }
+
+ k = Tcl_GetByteArrayFromObj(objv[1], &keylen);
+
+ obj = Tcl_NewObj();
+ ctx = (RC4_CTX *)Tcl_Alloc(sizeof(RC4_CTX));
+ ctx->x = 0;
+ ctx->y = 0;
+ for (n = 0; n < 256; n++)
+ ctx->s[n] = n;
+ for (n = 0; n < 256; n++) {
+ j = (k[i] + ctx->s[n] + j) % 256;
+ swap(&ctx->s[n], &ctx->s[j]);
+ i = (i + 1) % keylen;
+ }
+
+ if (obj->typePtr != NULL && obj->typePtr->freeIntRepProc != NULL)
+ obj->typePtr->freeIntRepProc(obj);
+ obj->internalRep.otherValuePtr = ctx;
+ obj->typePtr = &rc4_type;
+ Tcl_InvalidateStringRep(obj);
+ Tcl_SetObjResult(interp, obj);
+ return TCL_OK;
+ }
+
+ critcl::ccommand rc4c {dummy interp objc objv} {
+ Tcl_Obj *resObj = NULL;
+ RC4_CTX *ctx = NULL;
+ unsigned char *data, *res, x, y;
+ int size, n, i;
+
+ if (objc != 3) {
+ Tcl_WrongNumArgs(interp, 1, objv, "key data");
+ return TCL_ERROR;
+ }
+
+ if (objv[1]->typePtr != &rc4_type
+ && rc4_from_any(interp, objv[1]) != TCL_OK) {
+ return TCL_ERROR;
+ }
+
+ ctx = objv[1]->internalRep.otherValuePtr;
+ data = Tcl_GetByteArrayFromObj(objv[2], &size);
+ res = (unsigned char *)Tcl_Alloc(size);
+
+ x = ctx->x;
+ y = ctx->y;
+ for (n = 0; n < size; n++) {
+ x = (x + 1) % 256;
+ y = (ctx->s[x] + y) % 256;
+ swap(&ctx->s[x], &ctx->s[y]);
+ i = (ctx->s[x] + ctx->s[y]) % 256;
+ res[n] = data[n] ^ ctx->s[i];
+ }
+ ctx->x = x;
+ ctx->y = y;
+
+ resObj = Tcl_NewByteArrayObj(res, size);
+ Tcl_SetObjResult(interp, resObj);
+ Tcl_Free((char*)res);
+ return TCL_OK;
+ }
+}