Index: generic/tlsEncrypt.c ================================================================== --- generic/tlsEncrypt.c +++ generic/tlsEncrypt.c @@ -31,81 +31,65 @@ /*******************************************************************/ /* *------------------------------------------------------------------- * - * CryptoDataHandler -- + * EncryptInitialize -- * - * Perform encryption function on a block of data and return result. + * Initialize an encryption function * * Returns: - * TCL_OK or TCL_ERROR + * TCL_OK if successful or TCL_ERROR for failure with result set + * to error message. * * Side effects: - * Sets result or error message + * No result or error message * *------------------------------------------------------------------- */ -int -Encrypt_DataHandler(Tcl_Interp *interp, int type, Tcl_Obj *dataObj, Tcl_Obj *cipherObj, - Tcl_Obj *digestObj, Tcl_Obj *keyObj, Tcl_Obj *ivObj) { - EVP_CIPHER_CTX *ctx; +int EncryptInitialize(Tcl_Interp *interp, int type, EVP_CIPHER_CTX **ctx, + Tcl_Obj *cipherObj, Tcl_Obj *keyObj, Tcl_Obj *ivObj) { const EVP_CIPHER *cipher; - char *cipherName = NULL, *data = NULL, *key = NULL, *iv = NULL; - int cipher_len = 0, data_len = 0, key_len = 0, iv_len = 0, out_len = 0, tmplen, res; - unsigned char *outbuf; - Tcl_Obj *resultObj; + char *cipherName = NULL, *key = NULL, *iv = NULL; + int cipher_len = 0, data_len = 0, key_len = 0, iv_len = 0, res; dprintf("Called"); + /* Get encryption parameters */ if (cipherObj != NULL) { cipherName = Tcl_GetStringFromObj(cipherObj, &cipher_len); } if (keyObj != NULL) { key = Tcl_GetStringFromObj(keyObj, &key_len); } if (ivObj != NULL) { iv = Tcl_GetStringFromObj(ivObj, &iv_len); } - if (dataObj != NULL) { - data = Tcl_GetByteArrayFromObj(dataObj, &data_len); - } else { - Tcl_AppendResult(interp, "No data", NULL); - } /* Get cipher name */ #if OPENSSL_VERSION_NUMBER < 0x30000000L cipher = EVP_get_cipherbyname(cipherName); #else cipher = EVP_CIPHER_fetch(NULL, cipherName, NULL); #endif if (cipher == NULL) { - Tcl_AppendResult(interp, "Invalid cipher: ", cipherName, NULL); - return TCL_ERROR; - } - - /* Allocate storage for encrypted data. Size should be data size + block size. */ - resultObj = Tcl_NewObj(); - outbuf = Tcl_SetByteArrayLength(resultObj, data_len+1024); - if (resultObj == NULL || outbuf == NULL) { - Tcl_AppendResult(interp, "Memory allocation error", (char *) NULL); + Tcl_AppendResult(interp, "Invalid cipher: \"", cipherName, "\"", NULL); return TCL_ERROR; } /* Create and initialize the context */ - if((ctx = EVP_CIPHER_CTX_new()) == NULL) { + if((*ctx = EVP_CIPHER_CTX_new()) == NULL) { Tcl_AppendResult(interp, "Memory allocation error", (char *) NULL); - Tcl_DecrRefCount(resultObj); return TCL_ERROR; } /* Initialize the operation. Need appropriate key and iv size. */ #if OPENSSL_VERSION_NUMBER < 0x30000000L if (type == TYPE_ENCRYPT) { - res = EVP_EncryptInit_ex(ctx, cipher, NULL, key, iv); + res = EVP_EncryptInit_ex(*ctx, cipher, NULL, key, iv); } else { - res = EVP_DecryptInit_ex(ctx, cipher, NULL, key, iv); + res = EVP_DecryptInit_ex(*ctx, cipher, NULL, key, iv); } #else OSSL_PARAM params[2]; int index = 0; @@ -121,60 +105,163 @@ } #endif if(!res) { Tcl_AppendResult(interp, "Initialize failed: ", REASON(), NULL); - Tcl_DecrRefCount(resultObj); - EVP_CIPHER_CTX_free(ctx); return TCL_ERROR; } + return TCL_OK; +} + +/* + *------------------------------------------------------------------- + * + * EncryptUpdate -- + * + * Update an encryption function with data + * + * Returns: + * 1 if successful or 0 for failure + * + * Side effects: + * Adds encrypted data to buffer or sets result to error message + * + *------------------------------------------------------------------- + */ +int EncryptUpdate(Tcl_Interp *interp, int type, EVP_CIPHER_CTX *ctx, unsigned char *outbuf, + int *out_len, unsigned char *data, int data_len) { + int res, len = 0; + + dprintf("Called"); /* Encrypt/decrypt data */ if (type == TYPE_ENCRYPT) { - res = EVP_EncryptUpdate(ctx, outbuf, &out_len, data, data_len); + res = EVP_EncryptUpdate(ctx, outbuf, out_len, data, data_len); } else { - res = EVP_DecryptUpdate(ctx, outbuf, &out_len, data, data_len); + res = EVP_DecryptUpdate(ctx, outbuf, out_len, data, data_len); } - if (!res) { + if (res) { + *out_len += len; + return TCL_OK; + } else { Tcl_AppendResult(interp, "Update failed: ", REASON(), NULL); - Tcl_DecrRefCount(resultObj); - EVP_CIPHER_CTX_free(ctx); return TCL_ERROR; } +} + +/* + *------------------------------------------------------------------- + * + * EncryptFinalize -- + * + * Finalize an encryption function + * + * Returns: + * TCL_OK if successful or TCL_ERROR for failure with result set + * to error message. + * + * Side effects: + * Adds encrypted data to buffer or sets result to error message + * + *------------------------------------------------------------------- + */ +int EncryptFinalize(Tcl_Interp *interp, int type, EVP_CIPHER_CTX *ctx, unsigned char *outbuf, + int *out_len) { + int res, len = 0; + + dprintf("Called"); /* Finalize data */ if (type == TYPE_ENCRYPT) { - res = EVP_EncryptFinal_ex(ctx, outbuf+out_len, &tmplen); + res = EVP_EncryptFinal_ex(ctx, outbuf, out_len); } else { - res = EVP_DecryptFinal_ex(ctx, outbuf+out_len, &tmplen); + res = EVP_DecryptFinal_ex(ctx, outbuf, out_len); } - if (!res) { + if (res) { + *out_len += len; + return TCL_OK; + } else { Tcl_AppendResult(interp, "Finalize failed: ", REASON(), NULL); - Tcl_DecrRefCount(resultObj); - EVP_CIPHER_CTX_free(ctx); + return TCL_ERROR; + } +} + +/*******************************************************************/ + +/* + *------------------------------------------------------------------- + * + * EncryptDataHandler -- + * + * Perform encryption function on a block of data and return result. + * + * Returns: + * TCL_OK or TCL_ERROR + * + * Side effects: + * Sets result or error message + * + *------------------------------------------------------------------- + */ +int EncryptDataHandler(Tcl_Interp *interp, int type, Tcl_Obj *dataObj, Tcl_Obj *cipherObj, + Tcl_Obj *digestObj, Tcl_Obj *keyObj, Tcl_Obj *ivObj) { + EVP_CIPHER_CTX *ctx = NULL; + int data_len = 0, out_len = 0, res; + unsigned char *data, *outbuf; + Tcl_Obj *resultObj; + + dprintf("Called"); + + /* Get data */ + if (dataObj != NULL) { + data = Tcl_GetByteArrayFromObj(dataObj, &data_len); + } else { + Tcl_AppendResult(interp, "No data", NULL); + return TCL_ERROR; + } + + /* Allocate storage for encrypted data. Size should be data size + block size. */ + resultObj = Tcl_NewObj(); + outbuf = Tcl_SetByteArrayLength(resultObj, data_len+1024); + if (resultObj == NULL || outbuf == NULL) { + Tcl_AppendResult(interp, "Memory allocation error", (char *) NULL); return TCL_ERROR; } - out_len += tmplen; - outbuf = Tcl_SetByteArrayLength(resultObj, out_len); + /* Perform operation */ + if (EncryptInitialize(interp, type, &ctx, cipherObj, keyObj, ivObj) != TCL_OK || + EncryptUpdate(interp, type, ctx, outbuf, &out_len, data, data_len) != TCL_OK || + EncryptFinalize(interp, type, ctx, outbuf+out_len, &out_len) != TCL_OK) { + res = TCL_ERROR; + goto done; + } - /* Set return result */ - Tcl_SetObjResult(interp, resultObj); +done: + /* Set output result */ + if (res == TCL_OK) { + outbuf = Tcl_SetByteArrayLength(resultObj, out_len); + Tcl_SetObjResult(interp, resultObj); + } else { + Tcl_DecrRefCount(resultObj); + /* Result is error message */ + } /* Clean up */ - EVP_CIPHER_CTX_free(ctx); - return TCL_OK; + if (ctx != NULL) { + EVP_CIPHER_CTX_free(ctx); + } + return res; } /*******************************************************************/ /* *------------------------------------------------------------------- * - * EncryptionMain -- + * EncryptMain -- * * Perform encryption function and return result. * * Returns: * TCL_OK or TCL_ERROR @@ -182,14 +269,14 @@ * Side effects: * Sets result or error message * *------------------------------------------------------------------- */ -static int EncryptionMain(int type, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { +static int EncryptMain(int type, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { int res = TCL_OK; Tcl_Obj *cipherObj = NULL, *cmdObj = NULL, *dataObj = NULL, *digestObj = NULL; - Tcl_Obj *inFileObj = NULL, *outFileObj = NULL, *keyObj = NULL, *ivObj = NULL; + Tcl_Obj *inFileObj = NULL, *outFileObj = NULL, *keyObj = NULL, *ivObj = NULL, *macObj = NULL; const char *channel = NULL, *opt; const EVP_MD *md = NULL; const EVP_CIPHER *cipher = NULL; dprintf("Called"); @@ -197,11 +284,11 @@ /* Clear interp result */ Tcl_ResetResult(interp); /* Validate arg count */ if (objc < 3 || objc > 12) { - Tcl_WrongNumArgs(interp, 1, objv, "?-cipher name? ?-digest name? ?-key key? ?-iv string? [-data data]"); + Tcl_WrongNumArgs(interp, 1, objv, "-cipher name ?-digest name? ?-key key? ?-iv string? [-data data]"); return TCL_ERROR; } /* Get options */ for (int idx = 1; idx < objc; idx++) { @@ -229,11 +316,11 @@ return TCL_ERROR; } /* Perform encryption function on file, stacked channel, using instance command, or data blob */ if (dataObj != NULL) { - res = Encrypt_DataHandler(interp, type, dataObj, cipherObj, digestObj, keyObj, ivObj); + res = EncryptDataHandler(interp, type, dataObj, cipherObj, digestObj, keyObj, ivObj); } else { Tcl_AppendResult(interp, "No operation specified: Use -data option", NULL); res = TCL_ERROR; } return res; @@ -253,15 +340,15 @@ * Command dependent * *------------------------------------------------------------------- */ static int EncryptObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { - return EncryptionMain(TYPE_ENCRYPT, interp, objc, objv); + return EncryptMain(TYPE_ENCRYPT, interp, objc, objv); } static int DecryptObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { - return EncryptionMain(TYPE_DECRYPT, interp, objc, objv); + return EncryptMain(TYPE_DECRYPT, interp, objc, objv); } /* *------------------------------------------------------------------- * @@ -278,7 +365,8 @@ *------------------------------------------------------------------- */ int Tls_EncryptCommands(Tcl_Interp *interp) { Tcl_CreateObjCommand(interp, "tls::encrypt", EncryptObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "tls::decrypt", DecryptObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); + return TCL_OK; }