Index: doc/tls.html ================================================================== --- doc/tls.html +++ doc/tls.html @@ -545,10 +545,20 @@ shared secret key. The cryptographic strength depends upon the size of the key and the security of the hash function used. It uses the same options as tls::digest, plus additional option -key to specify the key to use. To salt a password, append or prepend the salt data to the password. + +
tls::mac -cipher name + -digest name -key key ?-bin|-hex? + [-file filename | -command cmdName | + -chan channelId | -data data]
+
(OpenSSL 3.0+) Calculate the Message Authentication Code (MAC). MACs + are used to ensure authenticity and the integrity of data. It uses the + same options as tls::digest, plus the additional options + -cipher to specify the cipher to use, -digest to specify + the digest, and for certain ciphers, -key to specify the key.
tls::md4 data
Returns the MD4 message-digest for data as a hex string.
tls::md5 data
Index: generic/tlsDigest.c ================================================================== --- generic/tlsDigest.c +++ generic/tlsDigest.c @@ -1099,52 +1099,41 @@ *------------------------------------------------------------------- */ static int DigestMain(int type, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { int idx, start = 1, format = HEX_FORMAT, res = TCL_OK; Tcl_Obj *cmdObj = NULL, *dataObj = NULL, *fileObj = NULL, *keyObj = NULL; - const char *digestName = NULL, *cipherName = NULL, *channel = NULL, *opt; + const char *digestName = NULL, *cipherName = NULL, *macName = NULL, *channel = NULL, *opt; const EVP_MD *md = NULL; const EVP_CIPHER *cipher = NULL; /* Clear interp result */ Tcl_ResetResult(interp); /* Validate arg count */ if (objc < 3 || objc > 12) { - Tcl_WrongNumArgs(interp, 1, objv, "?-bin|-hex? ?-cipher name? ?-digest name? ?-key key? [-channel chan | -command cmdName | -file filename | ?-data? data]"); - return TCL_ERROR; - } - - /* Optimal case for a digest and blob of data */ - if (objc == 3 && type == TYPE_MD) { - digestName = Tcl_GetStringFromObj(objv[1],NULL); - if ((md = EVP_get_digestbyname(digestName)) != NULL) { - return DigestDataHandler(interp, objv[2], md, NULL, HEX_FORMAT | TYPE_MD, NULL); - } else { - Tcl_AppendResult(interp, "Invalid digest \"", digestName, "\"", NULL); - return TCL_ERROR; - } - } else { - /* Special case if first arg is digest, cipher, or mac */ - opt = Tcl_GetStringFromObj(objv[start], NULL); - if (opt[0] != '-') { - if (type == TYPE_MD || type == TYPE_HMAC) { - digestName = opt; - start++; - } else if (type == TYPE_CMAC) { - cipherName = opt; - start++; - } else if (type == TYPE_MAC) { - macName = opt; - start++; - } + Tcl_WrongNumArgs(interp, 1, objv, "?-bin|-hex? ?-cipher name? ?-digest name? ?-key key? ?-mac name? [-channel chan | -command cmdName | -file filename | ?-data? data]"); + return TCL_ERROR; + } + + /* Special case of first arg is digest, cipher, or mac */ + opt = Tcl_GetStringFromObj(objv[start], NULL); + if (opt[0] != '-') { + if (type == TYPE_MD || type == TYPE_HMAC) { + digestName = opt; + start++; + } else if (type == TYPE_CMAC) { + cipherName = opt; + start++; + } else if (type == TYPE_MAC) { + macName = opt; + start++; } } /* Get options */ for (idx = start; idx < objc; idx++) { - *opt = Tcl_GetStringFromObj(objv[idx], NULL); + opt = Tcl_GetStringFromObj(objv[idx], NULL); if (opt[0] != '-') { break; } @@ -1159,14 +1148,20 @@ OPTOBJ("-data", dataObj); OPTSTR("-digest", digestName); OPTOBJ("-file", fileObj); OPTOBJ("-filename", fileObj); OPTOBJ("-key", keyObj); + OPTSTR("-mac", macName); - OPTBAD("option", "-bin, -channel, -cipher, -command, -data, -digest, -file, -filename, -hex, or -key"); + OPTBAD("option", "-bin, -channel, -cipher, -command, -data, -digest, -file, -filename, -hex, -key, or -mac"); return TCL_ERROR; } + + /* If only 1 arg left, it's the data */ + if (idx < objc && dataObj == NULL) { + dataObj = objv[idx]; + } /* Get cipher */ if (cipherName != NULL) { cipher = EVP_get_cipherbyname(cipherName); type = TYPE_CMAC; @@ -1178,11 +1173,11 @@ } else if (type == TYPE_CMAC) { Tcl_AppendResult(interp, "No cipher specified", NULL); return TCL_ERROR; } - /* Get digest */ + /* Get message digest */ if (digestName != NULL) { md = EVP_get_digestbyname(digestName); if (md == NULL) { Tcl_AppendResult(interp, "Invalid digest \"", digestName, "\"", NULL); return TCL_ERROR; @@ -1197,14 +1192,30 @@ /* Get key */ if (keyObj != NULL) { if (type == TYPE_MD) { type = TYPE_HMAC; } + } else if (type != TYPE_MD) { Tcl_AppendResult(interp, "No key specified", NULL); return TCL_ERROR; } + + /* Get MAC */ + if (macName != NULL) { + if (strcmp(macName, "cmac") == 0) { + type = TYPE_CMAC; + } else if (strcmp(macName, "hmac") == 0) { + type = TYPE_HMAC; + } else { + Tcl_AppendResult(interp, "Invalid MAC \"", macName, "\"", NULL); + return TCL_ERROR; + } + } else if (type == TYPE_MAC) { + Tcl_AppendResult(interp, "No MAC specified", NULL); + return TCL_ERROR; + } /* Calc digest on file, stacked channel, using instance command, or data blob */ if (fileObj != NULL) { res = DigestFileHandler(interp, fileObj, md, cipher, format | type, keyObj); } else if (channel != NULL) { @@ -1244,10 +1255,14 @@ } static int HMACObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { return DigestMain(TYPE_HMAC, interp, objc, objv); } + +static int MACObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { + return DigestMain(TYPE_MAC, interp, objc, objv); +} /* *------------------------------------------------------------------- * * Message Digest Convenience Commands -- @@ -1312,14 +1327,15 @@ int Tls_DigestCommands(Tcl_Interp *interp) { Tcl_CreateObjCommand(interp, "tls::digest", MdObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "tls::md", MdObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "tls::cmac", CMACObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "tls::hmac", HMACObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); + Tcl_CreateObjCommand(interp, "tls::mac", MACObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "tls::md4", MD4ObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "tls::md5", MD5ObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "tls::sha1", SHA1ObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "tls::sha256", SHA256ObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "tls::sha512", SHA512ObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "tls::unstack", DigestUnstackObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); return TCL_OK; }