/* * Copyright (C) 2006 Richard Kotal * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Library General Public License as published * by the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ static void ns_mcrypt_AlgoModes (Tcl_Interp * interp, char *type, char *dir) { int size; int i = 0; char **buf = NULL; if (interp == NULL || type == NULL) return; if (type == STR_ALGO) { buf = mcrypt_list_algorithms(dir,&size); } else if (type == STR_MODES) { buf = mcrypt_list_modes(dir,&size); } if (size == 0 || buf == NULL) return; for (i = 0; i < size; i++) { if (buf[i] == NULL) continue; Tcl_AppendElement (interp, buf[i]); } if (buf != NULL) mcrypt_free_p(buf,size); return; } #define N 1024 static int ns_mcrypt_Capability (Tcl_Interp * interp, char *name, char *dir, char *type) { char buf[N]; if (interp == NULL || type == NULL) return TCL_ERROR; if (name == NULL) { Tcl_SetResult (interp, "Algorithm or mode name is NULL.", TCL_STATIC); return TCL_ERROR; } if (STREQ(type,STR_MODES)) { int algo_mode_block = 0; int mode_block = 0; algo_mode_block = mcrypt_module_is_block_algorithm_mode(name,dir); mode_block = mcrypt_module_is_block_mode(name,dir); memset(buf,'\0',N); sprintf(buf, "%d", mode_block); Tcl_AppendElement (interp, buf); memset(buf,'\0',N); sprintf(buf, "%d", algo_mode_block); Tcl_AppendElement (interp, buf); } else if (STREQ(type,STR_ALGO)) { int algo_self_test = 0; int algo_block = 0; int algo_block_size = 0; int algo_key_size = 0; int *sizes = NULL; int key_sizes = 0; algo_self_test = mcrypt_module_self_test(name,dir); algo_block = mcrypt_module_is_block_algorithm(name,dir); algo_block_size = mcrypt_module_get_algo_block_size(name,dir); algo_key_size = mcrypt_module_get_algo_key_size(name,dir); sizes = mcrypt_module_get_algo_supported_key_sizes(name,dir,&key_sizes); memset(buf,'\0',N); sprintf(buf, "%d", algo_self_test); Tcl_AppendElement (interp, buf); memset(buf,'\0',N); sprintf(buf, "%d", algo_block); Tcl_AppendElement (interp, buf); memset(buf,'\0',N); sprintf(buf, "%d", algo_block_size); Tcl_AppendElement (interp, buf); memset(buf,'\0',N); sprintf(buf, "%d", algo_key_size); Tcl_AppendElement (interp, buf); memset(buf,'\0',N); sprintf(buf, "%d", key_sizes); Tcl_AppendElement (interp, buf); if (key_sizes > 0) { int j = 0; Tcl_DString pds; Tcl_DStringInit(&pds); for (j = 0; j < key_sizes; j++) { memset(buf,'\0',N); sprintf(buf, "%d", sizes[j]); Tcl_DStringAppendElement(&pds, buf); } Tcl_AppendElement (interp, Tcl_DStringValue(&pds)); Tcl_DStringFree(&pds); } if (sizes != NULL) free(sizes); } return TCL_OK; } static int ns_mcrypt_NewObj (Tcl_Interp * interp, char *algo, char *mode, char *algodir, char *modedir) { Tcl_Obj *out = NULL; MCRYPT td = MCRYPT_FAILED; int ret = TCL_ERROR; if (interp == NULL) return ret; if (algo == NULL) { Tcl_SetResult (interp, "Algorithm name is NULL.", TCL_STATIC); return ret; } if (mode == NULL) { Tcl_SetResult (interp, "Mode name is NULL.", TCL_STATIC); return ret; } td = mcrypt_module_open (algo,algodir,mode,modedir); if (td == MCRYPT_FAILED) { Tcl_SetResult (interp, "Cannot create mcrypt object.", TCL_STATIC); return ret; } out = ns_mcrypt_CreateObj (td); if (ns_mcrypt_IsMcryptObj (out, STR_MCRYPT) != NS_TRUE) { mcrypt_module_close (td); Tcl_SetResult (interp, "Cannot create mcrypt object.", TCL_STATIC); return ret; } Tcl_SetObjResult (interp, out); return TCL_OK; } static Tcl_Obj * ns_mcrypt_CreateObj (MCRYPT td) { Tcl_Obj *out = NULL; if (td == NULL) return out; out = Tcl_NewObj (); if (out == NULL) return out; Tcl_IncrRefCount (out); out->internalRep.twoPtrValue.ptr1 = (void *) td; out->internalRep.twoPtrValue.ptr2 = NULL; out->typePtr = &tclMcryptType; out->bytes = STR_MCRYPT; out->length = strlen (STR_MCRYPT); return out; } static int ns_mcrypt_DestroyObj (Tcl_Obj * obj) { MCRYPT td = NULL; int ret = TCL_ERROR; void *IV = NULL; if (ns_mcrypt_IsMcryptObj (obj, STR_MCRYPT) != NS_TRUE) return ret; td = (MCRYPT) obj->internalRep.twoPtrValue.ptr1; if (td != NULL) mcrypt_module_close (td); IV = obj->internalRep.twoPtrValue.ptr2; if (IV != NULL) Ns_Free(IV); obj->internalRep.twoPtrValue.ptr1 = NULL; obj->internalRep.twoPtrValue.ptr2 = NULL; obj->bytes = NULL; obj->length = 0; Tcl_DecrRefCount (obj); return TCL_OK; } static void FreeMcryptInternalRep(Tcl_Obj *obj) { ns_mcrypt_DestroyObj (obj); return; } static int ns_mcrypt_InitObj(Tcl_Interp *interp, Tcl_Obj *obj,char *key, int keysize) { int ret = TCL_ERROR; void *IV = NULL; MCRYPT td = NULL; int iv_algo_size = 0; int max_key_length, i, count; int *key_length_sizes = NULL; char *keyword = NULL; int err = 0; if (interp == NULL) return ret; if (ns_mcrypt_IsMcryptObj (obj, STR_MCRYPT) != NS_TRUE) return ret; if (key == NULL) { Tcl_SetResult (interp, "Keyword must be set.", TCL_STATIC); return ret; } td = (MCRYPT) obj->internalRep.twoPtrValue.ptr1; if (td == NULL) { Tcl_SetResult (interp, "Mcrypt Object is NULL.", TCL_STATIC); return ret; } IV = obj->internalRep.twoPtrValue.ptr2; iv_algo_size = mcrypt_enc_get_iv_size(td); if (IV == NULL && iv_algo_size != 0) { Tcl_SetResult (interp, "Init vector must be set. See mcrypt initvector set ...", TCL_STATIC); return ret; } max_key_length = mcrypt_enc_get_key_size(td); if (keysize > max_key_length) { Tcl_SetResult (interp, "Size of key is too large for this algorithm.", TCL_STATIC); return ret; } key_length_sizes = mcrypt_enc_get_supported_key_sizes(td, &count); if (count == 0 && key_length_sizes == NULL) { /* all lengths 1 - max_key_length = OK */ keyword = Ns_Malloc(keysize); memset(keyword, '\0',keysize); memcpy(keyword, key, keysize); } else if (count == 1) { /* only max_key_length = OK */ keyword = Ns_Malloc(key_length_sizes[0]); memset(keyword,'\0',key_length_sizes[0]); memcpy(keyword, key, ns_mcrypt_Min(keysize, key_length_sizes[0])); keysize = key_length_sizes[0]; } else { /* dertermine smallest supported key > length of requested key */ int keysize_tmp = keysize; keysize = max_key_length; /* start with max key length */ for (i = 0; i < count; i++) { if (key_length_sizes[i] >= keysize_tmp && key_length_sizes[i] < keysize) { keysize = key_length_sizes[i]; } } keyword = Ns_Malloc(keysize); memset(keyword, '\0' ,keysize); memcpy(keyword, key, ns_mcrypt_Min(keysize_tmp, keysize)); } if(key_length_sizes != NULL) mcrypt_free (key_length_sizes); err = mcrypt_generic_init(td, keyword, keysize, IV); if (keyword != NULL) Ns_Free(keyword); if (err < 0) { Tcl_SetResult (interp, (char *)mcrypt_strerror(err), TCL_STATIC); return ret; } return TCL_OK; } static int ns_mcrypt_CryptObj(Tcl_Interp *interp, Tcl_Obj *obj,int type, char *_text, int _textsize, int in_bin, int out_bin) { int ret = TCL_ERROR; MCRYPT td = NULL; int err = 0; int block_size = 0; char *str = NULL; int textsize = 0; char *text = NULL; if (interp == NULL) return ret; if (ns_mcrypt_IsMcryptObj (obj, STR_MCRYPT) != NS_TRUE) return ret; if (_text == NULL) { Tcl_SetResult (interp, "plain or cipher text must be set.", TCL_STATIC); return ret; } td = (MCRYPT) obj->internalRep.twoPtrValue.ptr1; if (td == NULL) { Tcl_SetResult (interp, "Mcrypt Object is NULL.", TCL_STATIC); return ret; } switch (in_bin) { case 2: { int len = (1 + (_textsize * 2)); // int len = (3 + (_textsize * 3) / 4); text = Ns_Malloc (len); memset(text, '\0',len); textsize = Ns_HtuuDecode (_text, text, len); if (textsize == 0) { if (text != NULL) Ns_Free (text); Tcl_SetResult (interp, "Cannot uudecode data string.", TCL_STATIC); return ret; } break; } case 3: { text = ns_mcrypt_utils_unasciify(_text,_textsize); if (text == NULL) { Tcl_SetResult (interp, "Cannot decode hex data string.", TCL_STATIC); return ret; } textsize = _textsize/2; break; } case 1: default: { text = Ns_StrCopy2(_text,_textsize); textsize = _textsize; break; } } /* Check blocksize */ if (mcrypt_enc_is_block_mode(td) == 1) { /* It's a block algorithm */ int textsize_tmp = textsize; block_size = mcrypt_enc_get_block_size(td); textsize = (((textsize_tmp - 1) / block_size) + 1) * block_size; str = Ns_Malloc(textsize); memset(str,'\0' ,textsize); memcpy(str, text, textsize_tmp); } else { /* It's not a block algorithm */ str = Ns_Malloc(textsize); memset(str,'\0' ,textsize); memcpy(str, text, textsize); } if(text != NULL) Ns_Free(text); if (type == CRYPT) { err = mcrypt_generic(td, (void *)str, textsize); } else { err = mdecrypt_generic(td, (void *)str, textsize); } if (err != 0) { if (str != NULL) Ns_Free(str); Tcl_SetResult (interp, "Cannot crypt/decrypt text.", TCL_STATIC); return ret; } switch (out_bin) { case 2: { // int size = (1 + (textsize * 4) / 3); int size = (1 + (textsize * 2)); unsigned char b64[size]; memset(b64,'\0',size); Ns_HtuuEncode ((unsigned char *) str, textsize, b64); Tcl_AppendResult (interp, b64, NULL); break; } case 3: { char *buf = NULL; buf = ns_mcrypt_utils_asciify (str, textsize); Tcl_AppendResult (interp, buf, NULL); if(buf != NULL) Ns_Free (buf); break; } case 4: { Tcl_DString buf; Tcl_DStringInit(&buf); Tcl_DStringAppend(&buf,str, textsize); Tcl_AppendResult (interp, buf.string, NULL); Tcl_DStringFree(&buf); break; } case 1: default: { Tcl_Obj *bytearray = NULL; bytearray = Tcl_NewByteArrayObj (str, textsize); Tcl_SetObjResult (interp, bytearray); break; } } if (str != NULL) Ns_Free(str); return TCL_OK; } static int ns_mcrypt_FlushObj (Tcl_Interp *interp, Tcl_Obj * obj) { MCRYPT td = NULL; int ret = TCL_ERROR; int err = 0; if (interp == NULL) return ret; if (ns_mcrypt_IsMcryptObj (obj, STR_MCRYPT) != NS_TRUE) return ret; td = (MCRYPT) obj->internalRep.twoPtrValue.ptr1; if (td != NULL) err = mcrypt_generic_deinit (td); if (err < 0) { Tcl_SetResult (interp, (char *)mcrypt_strerror(err), TCL_STATIC); return ret; } return TCL_OK; } static int ns_mcrypt_SetIV(Tcl_Interp *interp,Tcl_Obj *obj,int bin, char *IV, int size) { int ret = TCL_ERROR; void *objIV = NULL; MCRYPT td = MCRYPT_FAILED; void *buf = NULL; int iv_algo_size = 0; int t; if (interp == NULL) return ret; if (ns_mcrypt_IsMcryptObj (obj, STR_MCRYPT) != NS_TRUE) return ret; td = (MCRYPT) obj->internalRep.twoPtrValue.ptr1; if (td == NULL || td == MCRYPT_FAILED) return ret; iv_algo_size = mcrypt_enc_get_iv_size(td); objIV = obj->internalRep.twoPtrValue.ptr2; if (objIV != NULL) Ns_Free(objIV); objIV = NULL; buf = Ns_Malloc(iv_algo_size); memset(buf,'\0',iv_algo_size); if ((IV == NULL || size == 0) && bin != 4) goto end; switch (bin) { case 1: { if (iv_algo_size > size) iv_algo_size = size; memcpy(buf,IV,iv_algo_size); break; } case 2: { // int len = (3 + (size * 3) / 4); int len = (1 + (size * 2) ); void *tmp = NULL; tmp = Ns_Malloc (len); memset(tmp,'\0',len); size = Ns_HtuuDecode (IV, tmp, len); if (size == 0) { if (tmp != NULL) Ns_Free (tmp); if (buf != NULL) Ns_Free (buf); Tcl_SetResult (interp, "Cannot uudecode init vector.", TCL_STATIC); return ret; } if (iv_algo_size > size) iv_algo_size = size; memcpy(buf,tmp,iv_algo_size); if (tmp != NULL) Ns_Free (tmp); break; } case 3: { void *tmp = NULL; tmp = ns_mcrypt_utils_unasciify(IV,size); if (tmp == NULL) { if (buf != NULL) Ns_Free (buf); Tcl_SetResult (interp, "Cannot decode hex init vector.", TCL_STATIC); return ret; } if (iv_algo_size > size/2) iv_algo_size = size/2; memcpy(buf,tmp,iv_algo_size); if (tmp != NULL) Ns_Free (tmp); break; } case 4: { int j = 0; char *tmp = (char *)buf; time(&t); srand(t); for (j = 0 ; j < iv_algo_size; j++) *tmp++ = rand(); break; } } end: obj->internalRep.twoPtrValue.ptr2 = buf; return TCL_OK; } static int ns_mcrypt_GetIV(Tcl_Interp *interp,Tcl_Obj *obj,int bin) { int ret = TCL_ERROR; void *objIV = NULL; MCRYPT td = MCRYPT_FAILED; int iv_algo_size = 0; if (interp == NULL) return ret; if (ns_mcrypt_IsMcryptObj (obj, STR_MCRYPT) != NS_TRUE) return ret; td = (MCRYPT) obj->internalRep.twoPtrValue.ptr1; if (td == NULL || td == MCRYPT_FAILED) { Tcl_SetResult (interp, "Mcrypt module is not initialize (is NULL).", TCL_STATIC); return ret; } iv_algo_size = mcrypt_enc_get_iv_size(td); objIV = obj->internalRep.twoPtrValue.ptr2; if (objIV == NULL) { Tcl_SetResult (interp, "Init vector is not initialize (is NULL).", TCL_STATIC); return ret; } switch (bin) { case 1: { Tcl_Obj *bytearray = NULL; bytearray = Tcl_NewByteArrayObj (objIV, iv_algo_size); Tcl_SetObjResult (interp, bytearray); break; } case 2: { int size = (1 + (iv_algo_size * 2) ); // int size = (1 + (iv_algo_size * 4) / 3); unsigned char b64[size]; memset(b64,'\0',size); Ns_HtuuEncode ((unsigned char *) objIV, iv_algo_size, b64); Tcl_AppendResult (interp, b64, NULL); break; } case 3: { char *tmp = NULL; tmp = ns_mcrypt_utils_asciify (objIV, iv_algo_size); Tcl_AppendResult (interp, tmp, NULL); if(tmp != NULL) Ns_Free (tmp); break; } } return TCL_OK; } static int ns_mcrypt_PutShareCryptObj (Tcl_Interp * interp, Tcl_Obj * obj) { int ret = TCL_ERROR; if (interp == NULL || ns_mcrypt_IsMcryptObj (obj, STR_MCRYPT) != NS_TRUE) return ret; Tcl_IncrRefCount (obj); Tcl_SetIntObj (Tcl_GetObjResult (interp), (int) obj); return TCL_OK; } static int ns_mcrypt_GetShareCryptObj (Tcl_Interp * interp, Tcl_Obj * obj) { Tcl_Obj *out = NULL; int buf; int ret = TCL_ERROR; if (interp == NULL || obj == NULL) return ret; Tcl_GetIntFromObj (interp, obj, &buf); out = (Tcl_Obj *) buf; if (ns_mcrypt_IsMcryptObj (out, STR_MCRYPT) != NS_TRUE) { Tcl_SetResult (interp, "Cannot create mcrypt object.", TCL_STATIC); return ret; } Tcl_DecrRefCount (out); Tcl_SetObjResult (interp, out); return TCL_OK; } static void UpdateStringOfMcrypt(Tcl_Obj *obj) { return; } static int SetMcryptFromAny( Tcl_Interp *interp, Tcl_Obj *objPtr) { return TCL_ERROR; } static void DupMcryptInternalRep(Tcl_Obj *srcPtr, Tcl_Obj *copyPtr) { if (srcPtr == NULL) return; copyPtr->typePtr = &tclMcryptType; copyPtr->bytes = srcPtr->bytes; copyPtr->length = srcPtr->length; copyPtr->internalRep.twoPtrValue.ptr1 = NULL; copyPtr->internalRep.twoPtrValue.ptr2 = NULL; return; }