00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 package require critcl
00017 package provide rc4c 1.0.0
00018
00019 namespace ::rc4 {
00020
00021 critcl::ccode {
00022 typedef struct RC4_CTX {
00023 unsigned char x;
00024 unsigned char y;
00025 unsigned char s[256];
00026 } RC4_CTX;
00027
00028 */
00029
00030
00031 static void trace(const char *format, ...)
00032 {
00033 va_list args;
00034 va_start(args, format);
00035 vfprintf(stderr, format, args);
00036 va_end(args);
00037 }
00038 static Tcl_ObjType rc4_type;
00039
00040 static void rc4_free_rep(Tcl_Obj *obj)
00041 {
00042 RC4_CTX *ctx = (RC4_CTX *)obj->internalRep.otherValuePtr;
00043 TRACE("rc4_free_rep(%08x)\n", (long)obj);
00044 Tcl_Free((char *)ctx);
00045 }
00046
00047 static void rc4_dup_rep(Tcl_Obj *obj, Tcl_Obj *dup)
00048 {
00049 RC4_CTX *ctx = (RC4_CTX *)obj->internalRep.otherValuePtr;
00050 TRACE("rc4_dup_rep(%08x,%08x)\n", (long)obj, (long)dup);
00051 dup->internalRep.otherValuePtr = (RC4_CTX *)Tcl_Alloc(sizeof(RC4_CTX));
00052 memcpy(dup->internalRep.otherValuePtr, ctx, sizeof(RC4_CTX));
00053 dup->typePtr = &rc4_type;
00054 }
00055
00056 static void rc4_string_rep(Tcl_Obj* obj)
00057 {
00058 RC4_CTX *ctx = (RC4_CTX *)obj->internalRep.otherValuePtr;
00059 Tcl_Obj* tmpObj;
00060 char* str;
00061 TRACE("rc4_string_rep(%08x)\n", (long)obj);
00062
00063 tmpObj = Tcl_NewByteArrayObj((char *)ctx, sizeof(RC4_CTX));
00064 Tcl_IncrRefCount(tmpObj);
00065
00066 str = Tcl_GetStringFromObj(tmpObj, &obj->length);
00067 obj->bytes = Tcl_Alloc(obj->length + 1);
00068 memcpy(obj->bytes, str, obj->length + 1);
00069
00070 Tcl_DecrRefCount(tmpObj);
00071 }
00072
00073 static int rc4_from_any(Tcl_Interp* interp, Tcl_Obj* obj)
00074 {
00075 TRACE("rc4_from_any %08x\n", (long)obj);
00076 return TCL_ERROR;
00077 }
00078
00079 static Tcl_ObjType rc4_type = {
00080 "rc4c", rc4_free_rep, rc4_dup_rep, rc4_string_rep, rc4_from_any
00081 };
00082
00083 inline
00084
00085 void swap (unsigned char *lhs, unsigned char *rhs) {
00086 unsigned char t = *lhs;
00087 *lhs = *rhs;
00088 *rhs = t;
00089 }
00090 }
00091
00092 critcl::ccommand rc4c_init {dummy interp objc objv} {
00093 RC4_CTX *ctx;
00094 Tcl_Obj *obj;
00095 const unsigned char *k;
00096 int n = 0, i = 0, j = 0, keylen;
00097
00098 if (objc != 2) {
00099 Tcl_WrongNumArgs(interp, 1, objv, "keystring");
00100 return TCL_ERROR;
00101 }
00102
00103 k = Tcl_GetByteArrayFromObj(objv[1], &keylen);
00104
00105 obj = Tcl_NewObj();
00106 ctx = (RC4_CTX *)Tcl_Alloc(sizeof(RC4_CTX));
00107 ctx->x = 0;
00108 ctx->y = 0;
00109 for (n = 0; n < 256; n++)
00110 ctx->s[n] = n;
00111 for (n = 0; n < 256; n++) {
00112 j = (k[i] + ctx->s[n] + j) % 256;
00113 swap(&ctx->s[n], &ctx->s[j]);
00114 i = (i + 1) % keylen;
00115 }
00116
00117 if (obj->typePtr != NULL && obj->typePtr->freeIntRepProc != NULL)
00118 obj->typePtr->freeIntRepProc(obj);
00119 obj->internalRep.otherValuePtr = ctx;
00120 obj->typePtr = &rc4_type;
00121 Tcl_SetObjResult(interp, obj);
00122 Tcl_IncrRefCount(obj);
00123 Tcl_InvalidateStringRep(obj);
00124 return TCL_OK;
00125 }
00126
00127 critcl::ccommand rc4c {dummy interp objc objv} {
00128 Tcl_Obj *resObj = NULL;
00129 RC4_CTX *ctx = NULL;
00130 unsigned char *data, *res, x, y;
00131 int size, n, i;
00132
00133 if (objc != 3) {
00134 Tcl_WrongNumArgs(interp, 1, objv, "key data");
00135 return TCL_ERROR;
00136 }
00137
00138 if (objv[1]->typePtr != &rc4_type
00139 && rc4_from_any(interp, objv[1]) != TCL_OK) {
00140 return TCL_ERROR;
00141 }
00142
00143 ctx = objv[1]->internalRep.otherValuePtr;
00144 data = Tcl_GetByteArrayFromObj(objv[2], &size);
00145 res = (unsigned char *)Tcl_Alloc(size);
00146
00147 x = ctx->x;
00148 y = ctx->y;
00149 for (n = 0; n < size; n++) {
00150 x = (x + 1) % 256;
00151 y = (ctx->s[x] + y) % 256;
00152 swap(&ctx->s[x], &ctx->s[y]);
00153 i = (ctx->s[x] + ctx->s[y]) % 256;
00154 res[n] = data[n] ^ ctx->s[i];
00155 }
00156 ctx->x = x;
00157 ctx->y = y;
00158
00159 resObj = Tcl_NewByteArrayObj(res, size);
00160 Tcl_SetObjResult(interp, resObj);
00161 Tcl_Free(res);
00162 return TCL_OK;
00163 }
00164 }
00165