Index: generic/tlsEncrypt.c ================================================================== --- generic/tlsEncrypt.c +++ generic/tlsEncrypt.c @@ -136,24 +136,29 @@ *------------------------------------------------------------------- */ 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, *key = NULL, *iv = NULL; - int cipher_len = 0, key_len = 0, iv_len = 0, res; + char *cipherName = NULL, *keyString = NULL, *ivString = NULL; + int cipher_len = 0, key_len = 0, iv_len = 0, res, max; + unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH]; dprintf("Called"); + /* Init buffers */ + memset(key, 0, EVP_MAX_KEY_LENGTH); + memset(iv, 0, EVP_MAX_IV_LENGTH); + /* Get encryption parameters */ if (cipherObj != NULL) { cipherName = Tcl_GetStringFromObj(cipherObj, &cipher_len); } if (keyObj != NULL) { - key = Tcl_GetStringFromObj(keyObj, &key_len); + keyString = Tcl_GetByteArrayFromObj(keyObj, &key_len); } if (ivObj != NULL) { - iv = Tcl_GetStringFromObj(ivObj, &iv_len); + ivString = Tcl_GetByteArrayFromObj(ivObj, &iv_len); } /* Get cipher name */ #if OPENSSL_VERSION_NUMBER < 0x30000000L cipher = EVP_get_cipherbyname(cipherName); @@ -162,10 +167,40 @@ #endif if (cipher == NULL) { Tcl_AppendResult(interp, "Invalid cipher: \"", cipherName, "\"", NULL); return TCL_ERROR; } + + if (key_len > 0) { +#if OPENSSL_VERSION_NUMBER < 0x30000000L + max = EVP_CIPHER_key_length(cipher); +#else + max = EVP_CIPHER_get_key_length(cipher); +#endif + if (max == 0) { + } else if (key_len <= max) { + memcpy((void *) key, (const void *) keyString, (size_t) key_len); + } else { + Tcl_SetObjResult(interp, Tcl_ObjPrintf("Key too long. Must be <= %d bytes", max)); + return TCL_ERROR; + } + } + + if (iv_len > 0) { +#if OPENSSL_VERSION_NUMBER < 0x30000000L + max = EVP_CIPHER_iv_length(cipher); +#else + max = EVP_CIPHER_get_iv_length(cipher); +#endif + if (max == 0) { + } else if (iv_len <= max) { + memcpy((void *) iv, (const void *) ivString, (size_t) iv_len); + } else { + Tcl_SetObjResult(interp, Tcl_ObjPrintf("IV too long. Must be <= %d bytes", max)); + return TCL_ERROR; + } + } /* Create and initialize the context */ if((*ctx = EVP_CIPHER_CTX_new()) == NULL) { Tcl_AppendResult(interp, "Memory allocation error", (char *) NULL); return TCL_ERROR; @@ -1177,11 +1212,11 @@ */ 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; + int idx, res, start = 1; dprintf("Called"); /* Clear interp result */ Tcl_ResetResult(interp); @@ -1189,13 +1224,22 @@ /* 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]"); return TCL_ERROR; } + + /* Special case of first arg is cipher */ + opt = Tcl_GetStringFromObj(objv[start], NULL); + if (opt[0] != '-') { + if (type == TYPE_ENCRYPT || type == TYPE_DECRYPT) { + cipherObj = objv[start]; + start++; + } + } /* Get options */ - for (int idx = 1; idx < objc; idx++) { + for (idx = start; idx < objc; idx++) { opt = Tcl_GetStringFromObj(objv[idx], NULL); if (opt[0] != '-') { break; } @@ -1213,10 +1257,15 @@ OPTOBJ("-mac", macObj); OPTBAD("option", "-chan, -channel, -cipher, -command, -data, -digest, -infile, -key, -iv, -mac, -outfile"); return TCL_ERROR; } + + /* If only 1 arg left, it's the data */ + if (idx < objc && dataObj == NULL) { + dataObj = objv[idx]; + } /* Check for required options */ if (cipherObj == NULL) { Tcl_AppendResult(interp, "No cipher", NULL); } else if (keyObj == NULL) {