Index: configure
==================================================================
--- configure
+++ configure
@@ -5394,11 +5394,11 @@
 # This defines PKG(_STUB)_SOURCES, PKG(_STUB)_OBJECTS, PKG_HEADERS
 # and PKG_TCL_SOURCES.
 #-----------------------------------------------------------------------
 
 
-    vars="tls.c tlsBIO.c tlsIO.c tlsX509.c"
+    vars="tls.c tlsBIO.c tlsDigest.c tlsIO.c tlsX509.c"
     for i in $vars; do
 	case $i in
 	    \$*)
 		# allow $-var names
 		PKG_SOURCES="$PKG_SOURCES $i"

Index: configure.ac
==================================================================
--- configure.ac
+++ configure.ac
@@ -69,11 +69,11 @@
 # and runtime Tcl library files in TEA_ADD_TCL_SOURCES.
 # This defines PKG(_STUB)_SOURCES, PKG(_STUB)_OBJECTS, PKG_HEADERS
 # and PKG_TCL_SOURCES.
 #-----------------------------------------------------------------------
 
-TEA_ADD_SOURCES([tls.c tlsBIO.c tlsIO.c tlsX509.c])
+TEA_ADD_SOURCES([tls.c tlsBIO.c tlsDigest.c tlsIO.c tlsX509.c])
 TEA_ADD_HEADERS([generic/tls.h])
 TEA_ADD_INCLUDES([])
 TEA_ADD_LIBS([])
 TEA_ADD_CFLAGS([])
 TEA_ADD_STUB_SOURCES([])

Index: generic/tls.c
==================================================================
--- generic/tls.c
+++ generic/tls.c
@@ -930,131 +930,10 @@
 /********************/
 
 /*
  *-------------------------------------------------------------------
  *
- * Hash Calc --
- *
- *	Calculate message digest of data using type hash algorithm.
- *
- * Results:
- *	A standard Tcl result.
- *
- * Side effects:
- *	None.
- *
- *-------------------------------------------------------------------
- */
-int
-HashCalc(Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], const EVP_MD *type) {
-    char *data;
-    int len;
-    unsigned int mdlen;
-    unsigned char mdbuf[EVP_MAX_MD_SIZE];
-    const char *hex = "0123456789ABCDEF";
-
-    if (objc != 2) {
-	Tcl_WrongNumArgs(interp, 1, objv, "data");
-	return TCL_ERROR;
-    }
-
-    /* Get data */
-    data = Tcl_GetByteArrayFromObj(objv[1], &len);
-    if (data == NULL || len == 0) {
-	Tcl_SetResult(interp, "No data", NULL);
-	return TCL_ERROR;
-    }
-
-    /* Calc hash value, create hex representation, and write to result */
-    if (EVP_Digest(data, (size_t) len, mdbuf, &mdlen, type, NULL)) {
-	Tcl_Obj *resultObj;
-	unsigned char *ptr;
-	resultObj = Tcl_NewObj();
-	ptr = Tcl_SetByteArrayLength(resultObj, mdlen*2);
-
-	for (unsigned int i = 0; i < mdlen; i++) {
-	    *ptr++ = hex[(mdbuf[i] >> 4) & 0x0F];
-	    *ptr++ = hex[mdbuf[i] & 0x0F];
-	}
-	Tcl_SetObjResult(interp, resultObj);
-    } else {
-	Tcl_SetResult(interp, "Hash calculation error", NULL);
-	return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-/*
- *-------------------------------------------------------------------
- *
- * Hash Commands --
- *
- *	Return the digest as a hex string for data using type message digest.
- *
- * Results:
- *	A standard Tcl result.
- *
- * Side effects:
- *	None.
- *
- *-------------------------------------------------------------------
- */
-DigestCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) {
-    int len;
-    const char *name;
-    const EVP_MD *type;
-
-    if (objc != 3) {
-	Tcl_WrongNumArgs(interp, 1, objv, "type data");
-	return TCL_ERROR;
-    }
-
-    name = Tcl_GetStringFromObj(objv[1],&len);
-    if (name == NULL || (type = EVP_get_digestbyname(name)) == NULL) {
-	Tcl_AppendResult(interp, "Invalid digest type \"", name, "\"", NULL);
-	return TCL_ERROR;
-    }
-    objc--;
-    objv++;
-    return HashCalc(interp, objc, objv, type);
-}
-
-/*
- * Command to Calculate MD4 Message Digest
- */
-int
-DigestMD4Cmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) {
-    return HashCalc(interp, objc, objv, EVP_md4());
-}
-
-/*
- * Command to Calculate MD5 Message Digest
- */
-int
-DigestMD5Cmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) {
-    return HashCalc(interp, objc, objv, EVP_md5());
-}
-
-/*
- * Command to Calculate SHA-1 Hash
- */
-int
-DigestSHA1Cmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) {
-    return HashCalc(interp, objc, objv, EVP_sha1());
-}
-
-/*
- * Command to Calculate SHA2 SHA-256 Hash
- */
-int
-DigestSHA256Cmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) {
-    return HashCalc(interp, objc, objv, EVP_sha256());
-}
-
-/*
- *-------------------------------------------------------------------
- *
  * Hash List Command --
  *
  *	Return a list of all valid hash algorithms or message digests.
  *
  * Results:
@@ -2973,16 +2852,12 @@
 
     Tcl_CreateObjCommand(interp, "tls::ciphers", CiphersObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
     Tcl_CreateObjCommand(interp, "tls::protocols", ProtocolsObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
     Tcl_CreateObjCommand(interp, "tls::version", VersionObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
 
-    Tcl_CreateObjCommand(interp, "tls::digest", DigestCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
+    Tls_DigestCommands(interp);
     Tcl_CreateObjCommand(interp, "tls::digests", DigestListCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
-    Tcl_CreateObjCommand(interp, "tls::md4", DigestMD4Cmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
-    Tcl_CreateObjCommand(interp, "tls::md5", DigestMD5Cmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
-    Tcl_CreateObjCommand(interp, "tls::sha1", DigestSHA1Cmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
-    Tcl_CreateObjCommand(interp, "tls::sha256", DigestSHA256Cmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
 
     if (interp) {
 	Tcl_Eval(interp, tlsTclInitScript);
     }
 

ADDED   generic/tlsDigest.c
Index: generic/tlsDigest.c
==================================================================
--- /dev/null
+++ generic/tlsDigest.c
@@ -0,0 +1,163 @@
+/*
+ * Digest Commands
+ *
+ * Copyright (C) 2023 Brian O'Hagan
+ *
+ */
+
+#include "tlsInt.h"
+#include <tcl.h>
+#include <stdio.h>
+#include <string.h>
+#include <openssl/evp.h>
+
+/* Constants */
+const char *hex = "0123456789ABCDEF";
+
+
+/*******************************************************************/
+
+/*
+ *-------------------------------------------------------------------
+ *
+ * Hash Calc --
+ *
+ *	Calculate message digest of data using type hash algorithm.
+ *
+ * Results:
+ *	A standard Tcl result.
+ *
+ * Side effects:
+ *	None.
+ *
+ *-------------------------------------------------------------------
+ */
+int
+HashCalc(Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], const EVP_MD *type) {
+    char *data;
+    int len;
+    unsigned int mdlen;
+    unsigned char mdbuf[EVP_MAX_MD_SIZE];
+
+    if (objc != 2) {
+	Tcl_WrongNumArgs(interp, 1, objv, "data");
+	return TCL_ERROR;
+    }
+
+    /* Get data */
+    data = Tcl_GetByteArrayFromObj(objv[1], &len);
+    if (data == NULL || len == 0) {
+	Tcl_SetResult(interp, "No data", NULL);
+	return TCL_ERROR;
+    }
+
+    /* Calculate hash value, create hex representation, and write to result */
+    if (EVP_Digest(data, (size_t) len, mdbuf, &mdlen, type, NULL)) {
+	Tcl_Obj *resultObj;
+	unsigned char *ptr;
+	resultObj = Tcl_NewObj();
+	ptr = Tcl_SetByteArrayLength(resultObj, mdlen*2);
+
+	for (unsigned int i = 0; i < mdlen; i++) {
+	    *ptr++ = hex[(mdbuf[i] >> 4) & 0x0F];
+	    *ptr++ = hex[mdbuf[i] & 0x0F];
+	}
+	Tcl_SetObjResult(interp, resultObj);
+    } else {
+	Tcl_SetResult(interp, "Hash calculation error", NULL);
+	return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+/*
+ *-------------------------------------------------------------------
+ *
+ * Hash Commands --
+ *
+ *	Return the digest as a hex string for data using type message digest.
+ *
+ * Results:
+ *	A standard Tcl result.
+ *
+ * Side effects:
+ *	None.
+ *
+ *-------------------------------------------------------------------
+ */
+DigestObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) {
+    int len;
+    const char *name;
+    const EVP_MD *type;
+
+    if (objc != 3) {
+	Tcl_WrongNumArgs(interp, 1, objv, "type data");
+	return TCL_ERROR;
+    }
+
+    name = Tcl_GetStringFromObj(objv[1],&len);
+    if (name == NULL || (type = EVP_get_digestbyname(name)) == NULL) {
+	Tcl_AppendResult(interp, "Invalid digest type \"", name, "\"", NULL);
+	return TCL_ERROR;
+    }
+    objc--;
+    objv++;
+    return HashCalc(interp, objc, objv, type);
+}
+
+/*
+ * Command to Calculate MD4 Message Digest
+ */
+int
+DigestMD4Cmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) {
+    return HashCalc(interp, objc, objv, EVP_md4());
+}
+
+/*
+ * Command to Calculate MD5 Message Digest
+ */
+int
+DigestMD5Cmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) {
+    return HashCalc(interp, objc, objv, EVP_md5());
+}
+
+/*
+ * Command to Calculate SHA-1 Hash
+ */
+int
+DigestSHA1Cmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) {
+    return HashCalc(interp, objc, objv, EVP_sha1());
+}
+
+/*
+ * Command to Calculate SHA2 SHA-256 Hash
+ */
+int
+DigestSHA256Cmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) {
+    return HashCalc(interp, objc, objv, EVP_sha256());
+}
+
+/*
+ *-------------------------------------------------------------------
+ *
+ * Tls_DigestCommands --
+ *
+ *	Create digest commands
+ *
+ * Returns:
+ *	TCL_OK or TCL_ERROR
+ *
+ * Side effects:
+ *	Creates commands
+ *
+ *-------------------------------------------------------------------
+ */
+int Tls_DigestCommands(Tcl_Interp *interp) {
+    Tcl_CreateObjCommand(interp, "tls::digest", DigestObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
+    Tcl_CreateObjCommand(interp, "tls::md4", DigestMD4Cmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
+    Tcl_CreateObjCommand(interp, "tls::md5", DigestMD5Cmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
+    Tcl_CreateObjCommand(interp, "tls::sha1", DigestSHA1Cmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
+    Tcl_CreateObjCommand(interp, "tls::sha256", DigestSHA256Cmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
+    return TCL_OK;
+}
+

Index: generic/tlsInt.h
==================================================================
--- generic/tlsInt.h
+++ generic/tlsInt.h
@@ -192,10 +192,11 @@
 Tcl_Obj		*Tls_NewCAObj(Tcl_Interp *interp, const SSL *ssl, int peer);
 void            Tls_Error(State *statePtr, char *msg);
 void            Tls_Free(char *blockPtr);
 void            Tls_Clean(State *statePtr);
 int             Tls_WaitForConnect(State *statePtr, int *errorCodePtr, int handshakeFailureIsPermanent);
+int             Tls_DigestCommands(Tcl_Interp *interp);
 
 BIO             *BIO_new_tcl(State* statePtr, int flags);
 
 #define PTR2INT(x) ((int) ((intptr_t) (x)))
 

Index: win/makefile.vc
==================================================================
--- win/makefile.vc
+++ win/makefile.vc
@@ -25,20 +25,22 @@
 # Note the resource file does not makes sense if doing a static library build
 # hence it is under that condition. TMP_DIR is the output directory
 # defined by rules for object files.
 PRJ_OBJS = $(TMP_DIR)\tls.obj \
 	$(TMP_DIR)\tlsBIO.obj \
+	$(TMP_DIR)\tlsDigest.obj \
 	$(TMP_DIR)\tlsIO.obj \
 	$(TMP_DIR)\tlsX509.obj
 
 # Define any additional project include flags
 # SSL_INSTALL_FOLDER = with the OpenSSL installation folder following.
 PRJ_INCLUDES = -I"$(SSL_INSTALL_FOLDER)\include" -I"$(OPENSSL_INSTALL_DIR)\include"
 
 # Define any additional compiler flags that might be required for the project
 PRJ_DEFINES = -D NO_SSL2 -D NO_SSL3 -D _CRT_SECURE_NO_WARNINGS
- 
+
+#
 # SSL Libs:
 #    1. ${LIBCRYPTO}.dll
 #    2. ${LIBSSL}.dll
 # Where LIBCRYPTO (#1.) and LIBSSL (#2.) are defined as follows:
 #    v1.1: libcrypto-1.1-x64.dll and libssl-1.1-x64.dll
@@ -53,10 +55,14 @@
 # Define the standard targets
 !include "targets.vc"
 
 # Project specific targets
 
+all:
+
+clean: default-clean
+
 # We must define a pkgindex target that will create a pkgIndex.tcl
 # file in the $(OUT_DIR) directory. We can just redirect to the
 # default-pkgindex target for our sample extension.
 pkgindex: default-pkgindex