Chris_M_Thomasson

Highly Experimental HMAC cipher in C

Jun 4th, 2018
1,036
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 8.95 KB | None | 0 0
  1. /*
  2.     Chris M. Thomasson 6/4/2018
  3.     Experimental HMAC Cipher
  4.     C version with hardcoded secret key
  5.  
  6.     Using the following HMAC lib:
  7.  
  8.     https://github.com/ogay/hmac
  9.  
  10.     Here is some info on my cipher:
  11.  
  12.     http://funwithfractals.atspace.cc/ct_cipher
  13. ________________________________________________________*/
  14.  
  15.  
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <assert.h>
  19. #include <string.h>
  20. #include <time.h>
  21. #include "hmac_sha2.h"
  22.  
  23.  
  24. #define HMAC_SZ 32
  25.  
  26. // Uncomment PYTHON_TEST_VECTOR to sync with the Python 3 test vector
  27. // Python code: https://pastebin.com/raw/NAnsBJAZ
  28. // plaintext 9 bytes at: "Plaintext"
  29. // ciphertext bytes:
  30. // 723f811f5eb43df4e0dd50cc2016ff8f14f53137143135f31c99eb0030da44cbc6ace1d9be236858de
  31.  
  32.  
  33. //#define PYTHON_TEST_VECTOR
  34.  
  35.  
  36. struct ct_secret_key
  37. {
  38.     unsigned char* hmac_key;
  39.     size_t hmac_key_sz;
  40.     char* hmac_algo;
  41.     size_t rand_n;
  42. };
  43.  
  44. struct ct_buf
  45. {
  46.     unsigned char* p;
  47.     size_t sz;
  48. };
  49.  
  50.  
  51.  
  52. void ct_hex_printf(
  53.     FILE* fout,
  54.     unsigned char* buf,
  55.     size_t buf_sz
  56. ) {
  57.     for (size_t i = 0; i < buf_sz; i++)
  58.     {
  59.         fprintf(fout, "%02x", buf[i]);
  60.     }
  61. }
  62.  
  63.  
  64. unsigned char*
  65. ct_reverse(
  66.     unsigned char* P,
  67.     size_t P_sz
  68. ) {
  69.     for (size_t i = 0; i < P_sz / 2; ++i)
  70.     {
  71.         size_t r = P_sz - i - 1;
  72.         unsigned char t = P[i];
  73.         P[i] = P[r];
  74.         P[r] = t;
  75.     }
  76.  
  77.     return P;
  78. }
  79.  
  80.  
  81. size_t
  82. ct_file_get_size(
  83.     FILE* file
  84. ) {
  85.     size_t file_sz = 0;
  86.     for (file_sz = 0; fgetc(file) != EOF; ++file_sz);
  87.     rewind(file);
  88.     return file_sz;
  89. }
  90.  
  91.  
  92.  
  93. // return value ct_buf.p needs to be freed!
  94. struct ct_buf
  95. ct_file_copy(
  96.     FILE* file
  97. ) {
  98.     size_t file_sz = ct_file_get_size(file);
  99.     struct ct_buf buf = { calloc(1, file_sz), file_sz };
  100.     assert(buf.p);
  101.  
  102.     if (buf.p)
  103.     {
  104.         for (size_t i = 0; i < file_sz; ++i)
  105.         {
  106.             int byte = fgetc(file);
  107.             assert(byte != EOF);
  108.             buf.p[i] = byte;
  109.         }
  110.     }
  111.  
  112.     return buf;
  113. }
  114.  
  115.  
  116.  
  117. // return value ct_buf.p needs to be freed!
  118. struct ct_buf
  119. ct_prepend_from_file(
  120.     struct ct_secret_key const* const SK,
  121.     const char* fname
  122. ) {
  123.     FILE* file = fopen(fname, "rb");
  124.     assert(file);
  125.  
  126.     size_t file_sz = ct_file_get_size(file) + SK->rand_n;
  127.  
  128.     struct ct_buf buf = { calloc(1, file_sz), file_sz };
  129.  
  130.     if (buf.p)
  131.     {
  132.         // Prepend the random bytes.
  133.         // These should be drawn from a TRNG!!!
  134.  
  135.         srand((unsigned int)time(NULL));
  136.  
  137.         #if defined (PYTHON_TEST_VECTOR)
  138.             for (size_t i = 0; i < SK->rand_n; ++i)
  139.             {
  140.                 buf.p[i] = (unsigned char)i;
  141.             }
  142.         #else
  143.             for (size_t i = 0; i < SK->rand_n; ++i)
  144.             {
  145.                 buf.p[i] = rand() % 256;
  146.             }
  147.         #endif
  148.  
  149.         // Append the original plaintext
  150.         for (size_t i = SK->rand_n; i < file_sz; ++i)
  151.         {
  152.             int byte = fgetc(file);
  153.             assert(byte != EOF);
  154.             buf.p[i] = byte;
  155.         }
  156.     }
  157.  
  158.     fclose(file);
  159.  
  160.     return buf;
  161. }
  162.  
  163.  
  164. struct ct_buf
  165. ct_load_from_file(
  166.     const char* fname
  167. ) {
  168.     FILE* file = fopen(fname, "rb");
  169.     assert(file);
  170.  
  171.     size_t file_sz = ct_file_get_size(file);
  172.  
  173.     struct ct_buf buf = { calloc(1, file_sz), file_sz };
  174.  
  175.     if (buf.p)
  176.     {
  177.         // Append the original plaintext
  178.         for (size_t i = 0; i < file_sz; ++i)
  179.         {
  180.             int byte = fgetc(file);
  181.             assert(byte != EOF);
  182.             buf.p[i] = byte;
  183.         }
  184.     }
  185.  
  186.     fclose(file);
  187.  
  188.     return buf;
  189. }
  190.  
  191.  
  192. void ct_hmac_sha256_digest(
  193.     hmac_sha256_ctx* ctx,
  194.     unsigned char* digest
  195. ) {
  196.     hmac_sha256_ctx ctx_copy = *ctx;
  197.     hmac_sha256_final(&ctx_copy, digest, HMAC_SZ);
  198. }
  199.  
  200.  
  201. unsigned char*
  202. ct_crypt_round(
  203.     struct ct_secret_key* SK,
  204.     unsigned char* P,
  205.     size_t P_sz,
  206.     int M
  207. ) {
  208.     hmac_sha256_ctx H;
  209.  
  210.     hmac_sha256_init(&H, SK->hmac_key, SK->hmac_key_sz);
  211.     ct_reverse(SK->hmac_key, SK->hmac_key_sz);
  212.     hmac_sha256_update(&H, SK->hmac_key, SK->hmac_key_sz);
  213.     ct_reverse(SK->hmac_key, SK->hmac_key_sz);
  214.  
  215.     unsigned char D[256] = { 0 };
  216.  
  217.     size_t P_I = 0;
  218.  
  219.     unsigned long di = 0;
  220.  
  221.     while (P_I < P_sz)
  222.     {
  223.         ct_hmac_sha256_digest(&H, D);
  224.  
  225.         printf("\nD[%lu]:", di);
  226.         ct_hex_printf(stdout, D, HMAC_SZ);
  227.         printf("\n");
  228.  
  229.         size_t D_I = 0;
  230.         ++di;
  231.  
  232.         while (P_I < P_sz && D_I < HMAC_SZ)
  233.         {
  234.             unsigned char P_byte = P[P_I];
  235.             unsigned char C_byte = P_byte ^ D[D_I];
  236.             P[P_I] = C_byte;
  237.  
  238.             if (M == 0)
  239.             {
  240.                 unsigned char update[2] = {
  241.                     P_byte, C_byte
  242.                 };
  243.  
  244.                 hmac_sha256_update(&H, update, 2);
  245.             }
  246.  
  247.             else
  248.             {
  249.                 unsigned char update[2] = {
  250.                     C_byte, P_byte
  251.                 };
  252.  
  253.                 hmac_sha256_update(&H, update, 2);
  254.             }
  255.  
  256.             ++P_I;
  257.             ++D_I;
  258.         }
  259.     }
  260.  
  261.     return P;
  262. }
  263.  
  264.  
  265. unsigned char*
  266. ct_crypt(
  267.     struct ct_secret_key* SK,
  268.     unsigned char* P,
  269.     size_t P_sz,
  270.     int M
  271. ) {
  272.     printf("Crypt Round 0:\n________________________\n");
  273.     unsigned char* C = ct_crypt_round(SK, P, P_sz, M);
  274.     unsigned char* C_1 = ct_reverse(C, P_sz);
  275.     printf("\n\nCrypt Round 1:\n________________________\n");
  276.     C = ct_crypt_round(SK, C_1, P_sz, M);
  277.     return C;
  278. }
  279.  
  280.  
  281.  
  282. int
  283. ct_ciphertext_to_file(
  284.     FILE* fout,
  285.     struct ct_buf const* buf
  286. ) {
  287.     for (size_t i = 0; i < buf->sz; ++i)
  288.     {
  289.         int status = fputc((int)buf->p[i], fout);
  290.  
  291.         if (status == EOF)
  292.         {
  293.             assert(status != EOF);
  294.             return 0;
  295.         }
  296.     }
  297.  
  298.     return 1;
  299. }
  300.  
  301.  
  302. int
  303. ct_plaintext_to_file(
  304.     FILE* fout,
  305.     struct ct_secret_key* SK,
  306.     struct ct_buf const* buf
  307. ) {
  308.     assert(SK->rand_n <= buf->sz);
  309.  
  310.     for (size_t i = SK->rand_n; i < buf->sz; ++i)
  311.     {
  312.         int status = fputc((int)buf->p[i], fout);
  313.  
  314.         if (status == EOF)
  315.         {
  316.             assert(status != EOF);
  317.             return 0;
  318.         }
  319.     }
  320.  
  321.     return 1;
  322. }
  323.  
  324.  
  325. int
  326. ct_encrypt(
  327.     struct ct_secret_key* SK,
  328.     char const* fname_in,
  329.     char const* fname_out
  330. ) {
  331.     int status = 0;
  332.  
  333.     // Prepend the random bytes to the file...
  334.     struct ct_buf buf = ct_prepend_from_file(SK, fname_in);
  335.  
  336.     if (buf.p)
  337.     {
  338.         unsigned char* C = ct_crypt(SK, buf.p, buf.sz, 0);
  339.  
  340.         printf("\n\n\nCiphertext:");
  341.         ct_hex_printf(stdout, C, buf.sz);
  342.         printf("\n\n\n");
  343.  
  344.         // Write encrypted buffer to out file
  345.         {
  346.             FILE* fout = fopen(fname_out, "wb");
  347.             assert(fout);
  348.  
  349.             status = ct_ciphertext_to_file(fout, &buf);
  350.  
  351.             fclose(fout);
  352.         }
  353.  
  354.         free(buf.p);
  355.     }
  356.  
  357.     return status;
  358. }
  359.  
  360.  
  361. int
  362. ct_decrypt(
  363.     struct ct_secret_key* SK,
  364.     char const* fname_in,
  365.     char const* fname_out
  366. ) {
  367.     int status = 0;
  368.  
  369.     // Load the file...
  370.     struct ct_buf buf = ct_load_from_file(fname_in);
  371.  
  372.     if (buf.p)
  373.     {
  374.         unsigned char* C = ct_crypt(SK, buf.p, buf.sz, 1);
  375.  
  376.         printf("\n\n\nPlaintext:");
  377.         ct_hex_printf(stdout, C, buf.sz);
  378.         printf("\n\n\n");
  379.  
  380.         // Write decrypted buffer to out file
  381.         {
  382.             FILE* fout = fopen(fname_out, "wb");
  383.             assert(fout);
  384.  
  385.             status = ct_plaintext_to_file(fout, SK, &buf);
  386.  
  387.             fclose(fout);
  388.         }
  389.  
  390.         free(buf.p);
  391.     }
  392.  
  393.     return status;
  394. }
  395.  
  396.  
  397. void ct_help(void)
  398. {
  399.     printf(
  400.         "\n\n\n"
  401.         "Usage: program in_file out_file mode_flag\n\n"
  402.         "mode_flag -e is encrypt where the in_file gets encrypted as out_file\n\n"
  403.         "mode_flag -d is decrypt where the in_file gets decrypted as out_file\n\n"
  404.         "Example:\n\n"
  405.         "program plaintext ciphertext -e\n"
  406.         "program ciphertext plaintext_decrypt -d\n\n"
  407.     );
  408. }
  409.  
  410.  
  411. int main(int argc, char *argv[])
  412. {
  413.     if (argc != 4)
  414.     {
  415.         printf("argument count incorrect!\n");
  416.         ct_help();
  417.         return EXIT_FAILURE;
  418.     }
  419.  
  420.     {
  421.         int mode = 0;
  422.  
  423.         if (strcmp(argv[3], "-e") == 0)
  424.         {
  425.             mode = 0;
  426.         }
  427.  
  428.         else if (strcmp(argv[3], "-d") == 0)
  429.         {
  430.             mode = 1;
  431.         }
  432.  
  433.         else
  434.         {
  435.             printf("argument encrypt/decrypt incorrect!\n");
  436.             ct_help();
  437.             return EXIT_FAILURE;
  438.         }
  439.  
  440.         unsigned char hmac_key[] = "Password";
  441.  
  442.         struct ct_secret_key SK = {
  443.             hmac_key,
  444.             sizeof(hmac_key) - 1,
  445.             "sha256",
  446.             HMAC_SZ
  447.         };
  448.  
  449.         if (mode == 0)
  450.         {
  451.             ct_encrypt(&SK, argv[1], argv[2]);
  452.         }
  453.  
  454.         else
  455.         {
  456.             ct_decrypt(&SK, argv[1], argv[2]);
  457.         }
  458.     }
  459.  
  460.     return EXIT_SUCCESS;
  461. }
Advertisement
Add Comment
Please, Sign In to add comment