Overview
Comment: | Added Hashed MAC (HMAC) support. Added -key option to specify key to create Hashed Message Authentication Code (HMAC). Implemented data and file support, but not channel yet. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | crypto |
Files: | files | file ages | folders |
SHA3-256: |
41ad13317271058852b0ec5673383688 |
User & Date: | bohagan on 2023-10-29 21:06:46 |
Other Links: | branch diff | manifest | tags |
Context
2023-10-29
| ||
22:50 | Updated documentation for HMAC key option check-in: 92ad9d0c97 user: bohagan tags: crypto | |
21:06 | Added Hashed MAC (HMAC) support. Added -key option to specify key to create Hashed Message Authentication Code (HMAC). Implemented data and file support, but not channel yet. check-in: 41ad133172 user: bohagan tags: crypto | |
01:39 | Added digest channel test cases check-in: 5a5c14c5db user: bohagan tags: crypto | |
Changes
Modified generic/tlsDigest.c from [feada0df14] to [c51db5e24a].
︙ | ︙ | |||
11 12 13 14 15 16 17 | #include <stdio.h> #include <string.h> #include <openssl/evp.h> /* Constants */ const char *hex = "0123456789ABCDEF"; #define REASON() ERR_reason_error_string(ERR_get_error()) | | > > | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | #include <stdio.h> #include <string.h> #include <openssl/evp.h> /* Constants */ const char *hex = "0123456789ABCDEF"; #define REASON() ERR_reason_error_string(ERR_get_error()) #define BUFFER_SIZE 65536 #define BIN_FORMAT 0 #define HEX_FORMAT 1 /* * This structure describes the per-instance state of an SSL channel. * * The SSL processing context is maintained here, in the ClientData */ typedef struct DigestState { |
︙ | ︙ | |||
48 49 50 51 52 53 54 | * TCL_OK or TCL_ERROR * * Side effects: * Result is message digest or error message * *------------------------------------------------------------------- */ | | > | > | > > | | < | < > > | | > > > > > | < | | | > | > | < | < < | > | > > > > | < < | | > > | > > > > < < > > > > | > > > > > > > > > > > > | 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 | * TCL_OK or TCL_ERROR * * Side effects: * Result is message digest or error message * *------------------------------------------------------------------- */ int DigestFile(Tcl_Interp *interp, Tcl_Obj *filename, const EVP_MD *md, int format, Tcl_Obj *keyObj) { EVP_MD_CTX *ctx = (EVP_MD_CTX *) NULL; HMAC_CTX *hctx = (HMAC_CTX *) NULL; Tcl_Channel chan; unsigned char buf[BUFFER_SIZE]; unsigned char md_buf[EVP_MAX_MD_SIZE]; unsigned int md_len; unsigned char *key; int key_len, res; /* Open file channel */ chan = Tcl_FSOpenFileChannel(interp, filename, "rb", 0444); if (chan == (Tcl_Channel) NULL) { return TCL_ERROR; } /* Configure channel */ if (Tcl_SetChannelOption(interp, chan, "-translation", "binary") == TCL_ERROR) { goto error; } Tcl_SetChannelBufferSize(chan, BUFFER_SIZE); /* Create message digest context */ if (keyObj == NULL) { ctx = EVP_MD_CTX_new(); res = (ctx != NULL); } else { hctx = HMAC_CTX_new(); res = (hctx != NULL); } if (!res) { Tcl_AppendResult(interp, "Create digest context failed: ", REASON(), NULL); goto error; } /* Initialize hash function */ if (keyObj == NULL) { res = EVP_DigestInit_ex(ctx, md, NULL); } else { key = Tcl_GetByteArrayFromObj(keyObj, &key_len); res = HMAC_Init_ex(hctx, (const void *) key, key_len, md, NULL); } if (!res) { Tcl_AppendResult(interp, "Initialize digest failed: ", REASON(), NULL); goto error; } /* Read file data and update hash function */ while (!Tcl_Eof(chan)) { int len = Tcl_ReadRaw(chan, (char *) buf, BUFFER_SIZE); if (keyObj == NULL) { res = EVP_DigestUpdate(ctx, &buf, (size_t) len); } else { res = HMAC_Update(hctx, &buf[0], (size_t) len); } if (len > 0 && !res) { Tcl_AppendResult(interp, "Update digest failed: ", REASON(), NULL); goto error; } } /* Close channel */ if (Tcl_Close(interp, chan) == TCL_ERROR) { chan = (Tcl_Channel) NULL; goto error; } chan = (Tcl_Channel) NULL; /* Finalize hash function and calculate message digest */ if (keyObj == NULL) { res = EVP_DigestFinal_ex(ctx, md_buf, &md_len); } else { res = HMAC_Final(hctx, md_buf, &md_len); } if (!res) { Tcl_AppendResult(interp, "Finalize digest failed: ", REASON(), NULL); goto error; } /* Done with struct */ EVP_MD_CTX_free(ctx); ctx = NULL; /* Return message digest as either a binary or hex string */ if (format == BIN_FORMAT) { Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(md_buf, md_len)); } else { Tcl_Obj *resultObj = Tcl_NewObj(); unsigned char *ptr = Tcl_SetByteArrayLength(resultObj, md_len*2); for (unsigned int i = 0; i < md_len; i++) { *ptr++ = hex[(md_buf[i] >> 4) & 0x0F]; *ptr++ = hex[md_buf[i] & 0x0F]; } Tcl_SetObjResult(interp, resultObj); } return TCL_OK; error: if (chan != (Tcl_Channel) NULL) { Tcl_Close(interp, chan); } if (ctx != (EVP_MD_CTX *) NULL) { EVP_MD_CTX_free(ctx); } if (hctx != (HMAC_CTX *) NULL) { HMAC_CTX_free(hctx); } return TCL_ERROR; } /*******************************************************************/ /* *------------------------------------------------------------------- * |
︙ | ︙ | |||
283 284 285 286 287 288 289 | /* Get message digest */ if (!EVP_DigestFinal_ex(statePtr->ctx, md_buf, &md_len)) { *errorCodePtr = EINVAL; /* Write message digest to output channel as byte array or hex string */ } else if (md_len > 0) { | | | 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 | /* Get message digest */ if (!EVP_DigestFinal_ex(statePtr->ctx, md_buf, &md_len)) { *errorCodePtr = EINVAL; /* Write message digest to output channel as byte array or hex string */ } else if (md_len > 0) { if (statePtr->format == BIN_FORMAT) { read = md_len; memcpy(buf, md_buf, read); } else { unsigned char hex_buf[EVP_MAX_MD_SIZE*2]; unsigned char *ptr = hex_buf; |
︙ | ︙ | |||
660 661 662 663 664 665 666 | * * Side effects: * Sets result to message digest or error message * *------------------------------------------------------------------- */ int | | > | | > | > > > > > > > > > > > > | | 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 | * * Side effects: * Sets result to message digest or error message * *------------------------------------------------------------------- */ int DigestHashFunction(Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], const EVP_MD *md, int format, Tcl_Obj *keyObj) { char *data; int len, res; unsigned int md_len; unsigned char md_buf[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 digest based on hash function */ if (keyObj == NULL) { res = EVP_Digest(data, (size_t) len, md_buf, &md_len, md, NULL); } else { unsigned char *key, *hmac; int key_len; key = Tcl_GetByteArrayFromObj(keyObj, &key_len); hmac = HMAC(md, (const void *) key, key_len, (const unsigned char *) data, (size_t) len, md_buf, &md_len); res = (hmac != NULL); } /* Output digest to result per format (bin or hex) */ if (res) { if (format == BIN_FORMAT) { Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(md_buf, md_len)); } else { Tcl_Obj *resultObj = Tcl_NewObj(); unsigned char *ptr = Tcl_SetByteArrayLength(resultObj, md_len*2); for (unsigned int i = 0; i < md_len; i++) { |
︙ | ︙ | |||
718 719 720 721 722 723 724 | * Side effects: * Sets result to message digest or error message * *------------------------------------------------------------------- */ static int DigestObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { | | | | | | | | | | > | | | | 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 | * Side effects: * Sets result to message digest or error message * *------------------------------------------------------------------- */ static int DigestObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { int idx, len, format = HEX_FORMAT, key_len = 0, data_len = 0; const char *digestname, *channel = NULL; Tcl_Obj *dataObj = NULL, *fileObj = NULL, *keyObj = NULL; unsigned char *key = NULL; const EVP_MD *md; Tcl_ResetResult(interp); if (objc < 3 || objc > 7) { Tcl_WrongNumArgs(interp, 1, objv, "type ?-bin|-hex? ?-key hmac_key? [-channel chan | -file filename | ?-data? data]"); return TCL_ERROR; } /* Get digest */ digestname = Tcl_GetStringFromObj(objv[1], &len); if (digestname == NULL || (md = EVP_get_digestbyname(digestname)) == NULL) { Tcl_AppendResult(interp, "Invalid digest type \"", digestname, "\"", NULL); return TCL_ERROR; } /* Optimal case for blob of data */ if (objc == 3) { return DigestHashFunction(interp, --objc, ++objv, md, format, NULL); } /* Get options */ for (idx = 2; idx < objc-1; idx++) { char *opt = Tcl_GetStringFromObj(objv[idx], NULL); if (opt[0] != '-') break; OPTFLAG("-bin", format, BIN_FORMAT); OPTFLAG("-binary", format, BIN_FORMAT); OPTFLAG("-hex", format, HEX_FORMAT); OPTFLAG("-hexadecimal", format, HEX_FORMAT); OPTOBJ("-data", dataObj); OPTSTR("-chan", channel); OPTSTR("-channel", channel); OPTOBJ("-file", fileObj); OPTOBJ("-filename", fileObj); OPTOBJ("-key", keyObj); OPTBAD("option", "-bin, -data, -file, -filename, -hex, or -key"); return TCL_ERROR; } /* If no option for last arg, then its the data */ if (idx < objc) { dataObj = objv[idx]; } /* Calc digest on file, stacked channel, or data blob */ if (fileObj != NULL) { return DigestFile(interp, fileObj, md, format, keyObj); } else if (channel != NULL) { return DigestChannel(interp, channel, md, format); } else if (dataObj != NULL) { Tcl_Obj *objs[2]; objs[0] = NULL; objs[1] = dataObj; return DigestHashFunction(interp, 2, objs, md, format, keyObj); } Tcl_AppendResult(interp, "No data specified.", NULL); return TCL_ERROR; } /* |
︙ | ︙ | |||
801 802 803 804 805 806 807 | * * Side effects: * Sets result to message digest or error message * *------------------------------------------------------------------- */ int DigestMD4Cmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { | | | | | | 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 | * * Side effects: * Sets result to message digest or error message * *------------------------------------------------------------------- */ int DigestMD4Cmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { return DigestHashFunction(interp, objc, objv, EVP_md4(), HEX_FORMAT, NULL); } int DigestMD5Cmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { return DigestHashFunction(interp, objc, objv, EVP_md5(), HEX_FORMAT, NULL); } int DigestSHA1Cmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { return DigestHashFunction(interp, objc, objv, EVP_sha1(), HEX_FORMAT, NULL); } int DigestSHA256Cmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { return DigestHashFunction(interp, objc, objv, EVP_sha256(), HEX_FORMAT, NULL); } /* *------------------------------------------------------------------- * * Tls_DigestCommands -- * |
︙ | ︙ |