Note: this code causes core dumps. I didn't realize when I wrote it that I needed to use EVP_BytesToKey(). I have a version with the fix, but the salt is a static string, and I've heard that I should randomly generate the salt and store it with the encrypted data for decryption. I'll fix this issue in a future version. I want to get it done right before I upload another version to the Wiki. If you need something that works now, then send [GPS](me) an email. [GPS] - Thu May 9, 2002: I needed the ability to encrypt and decrypt a password database for my file server. I came up with this little extension to do so. You will need to have the OpenSSL Crypto library, which is freely available, and comes with most modern systems. Hint: Link with -lcrypto Enjoy! ---- #include #include #include #include #define CMD_ARGS (ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) int SecurityEncryptCmd CMD_ARGS { #define CHECK_STATUS(msg) if (status != 1) {\ free (encryptedData);\ EVP_CIPHER_CTX_cleanup (&ctx);\ Tcl_SetResult (interp, msg, TCL_STATIC);\ return TCL_ERROR;\ } unsigned char *key; /*store meaningless numbers in iv rather than [8], for debugging*/ unsigned char iv[] = "12345678"; unsigned char *inputData; unsigned char *encryptedData; EVP_CIPHER_CTX ctx; int totalLength = 0; int status = 0; int len = 0; int dataLength = 0; int blockSize = 0; Tcl_Obj *result; if (objc != 3) { Tcl_WrongNumArgs (interp, 0, NULL, "security:encrypt data key"); return TCL_ERROR; } inputData = Tcl_GetByteArrayFromObj (objv[1], &dataLength); /*The key should be NUL terminated*/ key = Tcl_GetString (objv[2]); /*for adding one block to the length */ blockSize = EVP_CIPHER_block_size (EVP_bf_cbc ()); encryptedData = Tcl_Alloc (dataLength + blockSize + 2); OpenSSL_add_all_algorithms (); EVP_CIPHER_CTX_init (&ctx); status = EVP_EncryptInit (&ctx, EVP_bf_cbc (), key, iv); CHECK_STATUS ("EVP_EncryptInit failed"); status = EVP_EncryptUpdate (&ctx, encryptedData, &len, inputData, dataLength); CHECK_STATUS ("EVP_EncryptUpdate failed"); totalLength += len; status = EVP_EncryptFinal (&ctx, encryptedData + totalLength, &len); CHECK_STATUS ("EVP_EncryptFinal failed"); totalLength += len; EVP_CIPHER_CTX_cleanup (&ctx); result = Tcl_NewByteArrayObj (encryptedData, totalLength); Tcl_SetObjResult (interp, result); Tcl_Free (encryptedData); #undef CHECK_STATUS return TCL_OK; } int SecurityDecryptCmd CMD_ARGS { #define CHECK_STATUS(msg) if (status != 1) {\ free (decryptedData);\ EVP_CIPHER_CTX_cleanup (&ctx);\ Tcl_SetResult (interp, msg, TCL_STATIC);\ return TCL_ERROR;\ } unsigned char *key; unsigned char iv[] = "12345678"; unsigned char *encryptedData; unsigned char *decryptedData; EVP_CIPHER_CTX ctx; int totalLength = 0; int status = 0; int len = 0; int encryptedLength = 0; int blockSize = 0; Tcl_Obj *result; if (objc != 3) { Tcl_WrongNumArgs (interp, 0, NULL, "security:decrypt data key"); return TCL_ERROR; } encryptedData = Tcl_GetByteArrayFromObj (objv[1], &encryptedLength); key = Tcl_GetString (objv[2]); blockSize = EVP_CIPHER_block_size (EVP_bf_cbc ()); decryptedData = Tcl_Alloc (encryptedLength + blockSize + 2); OpenSSL_add_all_algorithms (); EVP_CIPHER_CTX_init (&ctx); status = EVP_DecryptInit (&ctx, EVP_bf_cbc (), key, iv); CHECK_STATUS ("EVP_DecryptInit failed"); status = EVP_DecryptUpdate (&ctx, decryptedData, &len, encryptedData, encryptedLength); CHECK_STATUS ("EVP_DecryptInit failed"); totalLength += len; status = EVP_DecryptFinal (&ctx, decryptedData + totalLength, &len); CHECK_STATUS ("EVP_DecryptFinal failed; your password is probably incorrect."); totalLength += len; EVP_CIPHER_CTX_cleanup (&ctx); result = Tcl_NewByteArrayObj (decryptedData, totalLength); Tcl_SetObjResult (interp, result); Tcl_Free (decryptedData); #undef CHECK_STATUS return TCL_OK; } int Security_Init (Tcl_Interp *interp) { #define OBJ_CMD(name,func) Tcl_CreateObjCommand(interp, name, func, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL) OBJ_CMD ("security:encrypt", SecurityEncryptCmd); OBJ_CMD ("security:decrypt", SecurityDecryptCmd); #undef OBJ_CMD return TCL_OK; } int main (int argc, char *argv[]) { Tcl_Interp *interp; Tcl_FindExecutable (argv[0]); interp = Tcl_CreateInterp (); if (Tcl_Init (interp) != TCL_OK) { fprintf (stderr, "Tcl_Init error %s", Tcl_GetStringResult (interp)); exit (1); } if (Security_Init (interp) != TCL_OK) { fprintf (stderr, "Security_Init error %s\n", Tcl_GetStringResult (interp)); exit (1); } if (Tcl_EvalFile (interp, "./encrypt_test.tcl") != TCL_OK) { fprintf (stderr, "%s", Tcl_GetStringResult (interp)); exit (1); } return 0; } ---- #Test code set str "Hello World" set key abc set encData [security:encrypt $str $key] puts [security:decrypt $encData $key] ---- [Category Cryptography]