@@ -134,11 +134,11 @@ * No result or error message * *------------------------------------------------------------------- */ int EncryptInitialize(Tcl_Interp *interp, int type, EVP_CIPHER_CTX **ctx, - Tcl_Obj *cipherObj, Tcl_Obj *keyObj, Tcl_Obj *ivObj) { + Tcl_Obj *cipherObj, Tcl_Obj *keyObj, Tcl_Obj *ivObj, int padding) { const EVP_CIPHER *cipher; void *keyString = NULL, *ivString = NULL; Tcl_Size key_len = 0, iv_len = 0; int res, max; unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH]; @@ -178,21 +178,38 @@ if((*ctx = EVP_CIPHER_CTX_new()) == NULL) { Tcl_AppendResult(interp, "Memory allocation error", (char *) NULL); return TCL_ERROR; } - /* Initialize the operation. Need appropriate key and iv size. */ + /* Initialize the operation */ if (type == TYPE_ENCRYPT) { - res = EVP_EncryptInit_ex(*ctx, cipher, NULL, key, iv); + res = EVP_EncryptInit_ex(*ctx, cipher, NULL, NULL, NULL); } else { - res = EVP_DecryptInit_ex(*ctx, cipher, NULL, key, iv); + res = EVP_DecryptInit_ex(*ctx, cipher, NULL, NULL, NULL); } if(!res) { Tcl_AppendResult(interp, "Initialize failed: ", GET_ERR_REASON(), (char *) NULL); return TCL_ERROR; } + + /* Turn off PKCS#7 padding */ + if (!padding) { + EVP_CIPHER_CTX_set_padding(*ctx, padding); + } + + /* Set key and IV */ + if (type == TYPE_ENCRYPT) { + res = EVP_EncryptInit_ex(*ctx, NULL, NULL, key, iv); + } else { + res = EVP_DecryptInit_ex(*ctx, NULL, NULL, key, iv); + } + + if(!res) { + Tcl_AppendResult(interp, "Set key and IV failed: ", GET_ERR_REASON(), (char *) NULL); + return TCL_ERROR; + } /* Erase buffers */ memset(key, 0, EVP_MAX_KEY_LENGTH); memset(iv, 0, EVP_MAX_IV_LENGTH); return TCL_OK; @@ -738,11 +755,11 @@ * Adds transform to channel and sets result to channel id or error message. * *---------------------------------------------------------------------- */ static int EncryptChannelHandler(Tcl_Interp *interp, int type, const char *channel, - Tcl_Obj *cipherObj, Tcl_Obj *digestObj, Tcl_Obj *keyObj, Tcl_Obj *ivObj) { + Tcl_Obj *cipherObj, Tcl_Obj *digestObj, Tcl_Obj *keyObj, Tcl_Obj *ivObj, int padding) { int mode; /* OR-ed combination of TCL_READABLE and TCL_WRITABLE */ Tcl_Channel chan; EncryptState *statePtr; dprintf("Called"); @@ -772,11 +789,11 @@ } statePtr->self = chan; statePtr->mode = mode; /* Initialize function */ - if (EncryptInitialize(interp, type, &statePtr->ctx, cipherObj, keyObj, ivObj) != TCL_OK) { + if (EncryptInitialize(interp, type, &statePtr->ctx, cipherObj, keyObj, ivObj, padding) != TCL_OK) { EncryptStateFree(statePtr); return TCL_ERROR; } /* Stack channel */ @@ -961,12 +978,12 @@ * Side effects: * Creates command or error message * *------------------------------------------------------------------- */ -int EncryptCommandHandler(Tcl_Interp *interp, int type, Tcl_Obj *cmdObj, - Tcl_Obj *cipherObj, Tcl_Obj *digestObj, Tcl_Obj *keyObj, Tcl_Obj *ivObj) { +int EncryptCommandHandler(Tcl_Interp *interp, int type, Tcl_Obj *cmdObj, Tcl_Obj *cipherObj, + Tcl_Obj *digestObj, Tcl_Obj *keyObj, Tcl_Obj *ivObj, int padding) { EncryptState *statePtr; char *cmdName = Tcl_GetString(cmdObj); dprintf("Called"); @@ -974,11 +991,11 @@ Tcl_AppendResult(interp, "Memory allocation error", (char *) NULL); return TCL_ERROR; } /* Initialize function */ - if (EncryptInitialize(interp, type, &statePtr->ctx, cipherObj, keyObj, ivObj) != TCL_OK) { + if (EncryptInitialize(interp, type, &statePtr->ctx, cipherObj, keyObj, ivObj, padding) != TCL_OK) { EncryptStateFree(statePtr); return TCL_ERROR; } /* Create instance command */ @@ -1006,11 +1023,11 @@ * 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) { + Tcl_Obj *digestObj, Tcl_Obj *keyObj, Tcl_Obj *ivObj, int padding) { EVP_CIPHER_CTX *ctx = NULL; int out_len = 0, len = 0, res = TCL_OK; Tcl_Size data_len = 0; unsigned char *data, *out_buf; Tcl_Obj *resultObj; @@ -1032,11 +1049,11 @@ Tcl_AppendResult(interp, "Memory allocation error", (char *) NULL); return TCL_ERROR; } /* Perform operation */ - if (EncryptInitialize(interp, type, &ctx, cipherObj, keyObj, ivObj) != TCL_OK || + if (EncryptInitialize(interp, type, &ctx, cipherObj, keyObj, ivObj, padding) != TCL_OK || EncryptUpdate(interp, type, ctx, out_buf, &out_len, data, data_len) != TCL_OK || EncryptFinalize(interp, type, ctx, out_buf+out_len, &len) != TCL_OK) { res = TCL_ERROR; goto done; } @@ -1076,11 +1093,11 @@ * size of outFile, or an error message. * *------------------------------------------------------------------- */ int EncryptFileHandler(Tcl_Interp *interp, int type, Tcl_Obj *inFileObj, Tcl_Obj *outFileObj, - Tcl_Obj *cipherObj, Tcl_Obj *digestObj, Tcl_Obj *keyObj, Tcl_Obj *ivObj) { + Tcl_Obj *cipherObj, Tcl_Obj *digestObj, Tcl_Obj *keyObj, Tcl_Obj *ivObj, int padding) { EVP_CIPHER_CTX *ctx = NULL; int total = 0, res, out_len = 0, len; Tcl_Channel in = NULL, out = NULL; unsigned char in_buf[BUFFER_SIZE]; unsigned char out_buf[BUFFER_SIZE+EVP_MAX_BLOCK_LENGTH]; @@ -1097,11 +1114,11 @@ Tcl_Close(interp, in); return TCL_ERROR; } /* Initialize operation */ - if ((res = EncryptInitialize(interp, type, &ctx, cipherObj, keyObj, ivObj)) != TCL_OK) { + if ((res = EncryptInitialize(interp, type, &ctx, cipherObj, keyObj, ivObj, padding)) != TCL_OK) { goto done; } /* Read file data from inFile, encrypt/decrypt it, then output to outFile */ while (!Tcl_Eof(in)) { @@ -1161,15 +1178,15 @@ /*******************************************************************/ static const char *command_opts [] = { "-chan", "-channel", "-cipher", "-command", "-data", "-digest", "-infile", "-filename", - "-outfile", "-hash", "-iv", "-key", "-mac", NULL}; + "-outfile", "-hash", "-iv", "-key", "-mac", "-padding", NULL}; enum _command_opts { _opt_chan, _opt_channel, _opt_cipher, _opt_command, _opt_data, _opt_digest, _opt_infile, - _opt_filename, _opt_outfile, _opt_hash, _opt_iv, _opt_key, _opt_mac + _opt_filename, _opt_outfile, _opt_hash, _opt_iv, _opt_key, _opt_mac, _opt_padding }; /* *------------------------------------------------------------------- * @@ -1187,21 +1204,21 @@ */ static int EncryptMain(int type, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { Tcl_Obj *cipherObj = NULL, *cmdObj = NULL, *dataObj = NULL, *digestObj = NULL; Tcl_Obj *inFileObj = NULL, *outFileObj = NULL, *keyObj = NULL, *ivObj = NULL, *macObj = NULL; const char *channel = NULL, *opt; - int res, start = 1; + int res, start = 1, padding = 1; Tcl_Size fn; dprintf("Called"); /* 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? ?-mac name? [-channel chan | -command cmdName | -infile filename -outfile filename | ?-data? data]"); + Tcl_WrongNumArgs(interp, 1, objv, "?-cipher? name ?-digest name? -key key ?-iv string? ?-mac name? ?-padding boolean? [-channel chan | -command cmdName | -infile filename -outfile filename | ?-data? data]"); return TCL_ERROR; } /* Special case of first arg is cipher */ opt = Tcl_GetString(objv[start]); @@ -1268,10 +1285,13 @@ keyObj = objv[idx]; break; case _opt_mac: macObj = objv[idx]; break; + case _opt_padding: + GET_OPT_BOOL(objv[idx], &padding); + break; } } /* Check for required options */ if (cipherObj == NULL) { @@ -1281,17 +1301,17 @@ return TCL_ERROR; } /* Perform encryption function on file, stacked channel, using instance command, or data blob */ if (inFileObj != NULL && outFileObj != NULL) { - res = EncryptFileHandler(interp, type, inFileObj, outFileObj, cipherObj, digestObj, keyObj, ivObj); + res = EncryptFileHandler(interp, type, inFileObj, outFileObj, cipherObj, digestObj, keyObj, ivObj, padding); } else if (channel != NULL) { - res = EncryptChannelHandler(interp, type, channel, cipherObj, digestObj, keyObj, ivObj); + res = EncryptChannelHandler(interp, type, channel, cipherObj, digestObj, keyObj, ivObj, padding); } else if (cmdObj != NULL) { - res = EncryptCommandHandler(interp, type, cmdObj, cipherObj, digestObj, keyObj, ivObj); + res = EncryptCommandHandler(interp, type, cmdObj, cipherObj, digestObj, keyObj, ivObj, padding); } else if (dataObj != NULL) { - res = EncryptDataHandler(interp, type, dataObj, cipherObj, digestObj, keyObj, ivObj); + res = EncryptDataHandler(interp, type, dataObj, cipherObj, digestObj, keyObj, ivObj, padding); } else { Tcl_AppendResult(interp, "No operation specified: Use -channel, -command, -data, or -infile option", (char *) NULL); res = TCL_ERROR; } return res;