SHARE
TWEET

lc4.c

a guest Mar 3rd, 2020 23 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. //Compile with: gcc lc4.c -o lc4
  2. //Run with no arguments for help.
  3. //If you're going to use this other than to practice pen+paper crypto (you shouldn't, use gpg) then replace the rand() call with arc4random() and link with -lbsd.
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <time.h>
  8.  
  9. char state[6][6], I, J;
  10.  
  11. //char (e.g. a) to int (e.g. 10)
  12. char ctoi (char c) {
  13.   if (c == '#')                 return 0;
  14.   if (c == '_')                 return 1;
  15.   if ((c >= '2') && (c <= '9')) return c - '0';
  16.   if ((c >= 'a') && (c <= 'z')) return (c - 'a') + 10;
  17.  
  18.   printf("ERROR: '%c' is not a permitted character.\n", c);
  19.   exit(1);
  20. }
  21.  
  22. //int (e.g. 10) to char (e.g. a)
  23. char itoc (char i) {
  24.   if (i == 0)                 return '#';
  25.   if (i == 1)                 return '_';
  26.   if ((i >= 2) && (i <= 9))   return i + '0';
  27.   if ((i >= 10) && (i <= 35)) return (i - 10) + 'a';
  28.  
  29.   printf("ERROR: '%c' is not a valid encoding of any character.\n", i);
  30.   exit(1);
  31. }
  32.  
  33. void print_state () {
  34.   for (char i = 0; i < 6; ++i) {
  35.     for (char j = 0; j < 6; ++j)
  36.       printf("%c", itoc(state[i][j]));
  37.     printf(" ");
  38.   }
  39.   printf("i=%d j=%d\n", I, J);
  40. }
  41.  
  42. void init_state (const char* key) {
  43.   for (char i = 0; i <= 35; ++i)
  44.     state[i/6][i%6] = ctoi(key[i]);
  45.   I = 0;
  46.   J = 0;
  47.   printf(" init state: ");
  48.   print_state();
  49. }
  50.  
  51. //c is unencoded (e.g. 'a' rather than 10)
  52. void find_where_char_appears (char c, char* row, char* col) {
  53.   char c_enc = ctoi(c);
  54.   for (char i = 0; i < 6; ++i)
  55.     for (char j = 0; j < 6; ++j)
  56.       if (state[i][j] == c_enc)
  57.         { *row = i; *col = j; return; }
  58.  
  59.   printf("ERROR: Invalid state: Does not contain %c.\n", c);
  60.   exit(1);
  61. }
  62.  
  63. void right_rotate (char r, char* c, char x, char* y) {
  64.   //rotate
  65.   static char buf[6];
  66.   for (char col = 0; col < 6; ++col)
  67.     buf[col] = state[r][col?(col-1):5];
  68.   for (char col = 0; col < 6; ++col)
  69.     state[r][col] = buf[col];
  70.   //keep marker atop moved cell
  71.   *c = (*c+1)%6;
  72.   if (x == r) *y = (*y+1)%6;
  73.   if (I == r)  J = ( J+1)%6;
  74. }
  75.  
  76. void down_rotate (char* r, char c, char* x, char y) {
  77.   //rotate
  78.   static char buf[6];
  79.   for (char row = 0; row < 6; ++row)
  80.     buf[row] = state[row?(row-1):5][y];
  81.   for (char row = 0; row < 6; ++row)
  82.     state[row][y] = buf[row];
  83.   //keep marker atop moved cell
  84.   *x = (*x+1)%6;
  85.   if (c == y) *r = (*r+1)%6;
  86.   if (J == y)  I = ( I+1)%6;
  87. }
  88.  
  89. //the_char and the return value are unencoded (e.g. 'a' rather than 10)
  90. char encrypt_char (char the_char) {
  91.   char r, c;
  92.   find_where_char_appears(the_char, &r, &c);
  93.   char x = (r + state[I][J]/6) % 6;
  94.   char y = (c + state[I][J]%6) % 6;
  95.   char c_encrypted_encoded = state[x][y];
  96.   right_rotate( r, &c,  x, &y);
  97.   down_rotate (&r,  c, &x,  y);
  98.   I = (I + c_encrypted_encoded/6) % 6;
  99.   J = (J + c_encrypted_encoded%6) % 6;
  100.   printf("%c->%c, state: ", the_char, itoc(c_encrypted_encoded));
  101.   print_state();
  102.   return itoc(c_encrypted_encoded);
  103. }
  104.  
  105. //pt and the return value are unencoded (e.g. "foo" rather than [15,24,24])
  106. //return value must be free()d, and is nul-terminated
  107. char* encrypt_string (const char* pt) {
  108.   size_t len = strlen(pt);
  109.   char* ciphertext = malloc(len+1);
  110.   ciphertext[len] = '\0';
  111.   for (char* ct = ciphertext; *pt; ++pt, ++ct)
  112.     *ct = encrypt_char(*pt);
  113.   return ciphertext;
  114. }
  115.  
  116. //% doesn't behave as I wish for negatives
  117. char mod6 (char c) {
  118.   c %= 6;
  119.   return (c<0) ? 6+c : c;
  120. }
  121.  
  122. //the_char and the return value are unencoded (e.g. 'a' rather than 10)
  123. char decrypt_char (char the_char) {
  124.   char the_char_encoded = ctoi(the_char);
  125.   char x, y;
  126.   find_where_char_appears(the_char, &x, &y);
  127.   char r = mod6(x - state[I][J]/6);
  128.   char c = mod6(y - state[I][J]%6);
  129.   char c_decrypted_encoded = state[r][c];
  130.   right_rotate( r, &c,  x, &y);
  131.   down_rotate (&r,  c, &x,  y);
  132.   I = (I + the_char_encoded/6) % 6;
  133.   J = (J + the_char_encoded%6) % 6;
  134.   printf("%c->%c, state: ", the_char, itoc(c_decrypted_encoded));
  135.   print_state();
  136.   return itoc(c_decrypted_encoded);
  137. }
  138.  
  139. //pt and the return value are unencoded (e.g. "foo" rather than [15,24,24])
  140. //return value must be free()d, and is nul-terminated
  141. char* decrypt_string (const char* ct) {
  142.   size_t len = strlen(ct);
  143.   char* plaintext = malloc(len+1);
  144.   plaintext[len] = '\0';
  145.   for (char* pt = plaintext; *ct; ++pt, ++ct)
  146.     *pt = decrypt_char(*ct);
  147.   return plaintext;
  148. }
  149.  
  150. //*nonce will be assigned a pointer which must be free()d
  151. //return value must be free()d
  152. char* encrypt_message (const char* key, char** nonce, const char* signature, const char* plaintext) {
  153.   //generate nonce
  154.   size_t nonceSz = 6;
  155.   *nonce = malloc(nonceSz+1);
  156.   (*nonce)[nonceSz] = '\0';
  157.   for (int i = 0; i < nonceSz; ++i)
  158.     (*nonce)[i] = itoc(rand()%36);
  159.   //encrypt
  160.   init_state(key);
  161.   free(encrypt_string(*nonce));
  162.   char* ct_msg = encrypt_string(plaintext);
  163.   char* ct_sig = encrypt_string(signature);
  164.   //append the signature ciphertext to the message ciphertext
  165.   size_t msglen = strlen(ct_msg);
  166.   size_t siglen = strlen(ct_sig);
  167.   ct_msg = realloc(ct_msg, msglen+siglen+1);
  168.   memcpy(ct_msg+msglen, ct_sig, siglen+1);
  169.   free(ct_sig);
  170.   return ct_msg;
  171. }
  172.  
  173. //return value must be free()d
  174. char* decrypt_message (const char* key, const char* nonce, const char* signature, const char* ciphertext) {
  175.   //decrypt
  176.   init_state(key);
  177.   free(encrypt_string(nonce));
  178.   char* plaintext = decrypt_string(ciphertext);
  179.  
  180.   //verify the signature
  181.   char* sig = plaintext + (strlen(plaintext) - strlen(signature));
  182.   if (strcmp(sig, signature)) {
  183.     printf("ERROR: Signature doesn't match.\n");
  184.     exit(1);
  185.   }
  186.   return plaintext;
  187. }
  188.  
  189. int main (int argc, char** argv) {
  190.   srand(time(NULL));
  191.  
  192.   if ((argc != 4) && (argc != 5)) {
  193.     printf("Usage:\n"\
  194.            "  (encrypt) %s key sig msg\n"\
  195.            "  (decrypt) %s key sig msg nonce\n"\
  196.            "The key and signature are secret and reusable (rekey after 46,000 messages).\n"\
  197.            "The signature doesn't match if the ciphertext is modified.\n"\
  198.            "The nonce and ciphertext are public, the nonce may not be reused.\n"\
  199.            "The alphabet is [#_23456789abcdefghijklmnopqrstuvwxyz].\n"
  200.            "Keys are a permutation of the alphabet, selected uniformly at random. e.g. xv7ydq#opaj_39rzut8b45wcsgehmiknf26l.\n"\
  201.            "Signatures and messages are restricted to the alphabet, notably the alphabet does not contain upper case letters or spaces.\n"\
  202.            "Example: %s \"xv7ydq#opaj_39rzut8b45wcsgehmiknf26l\" \"#rubberducky\" \"this_is_a_test_of_lc4\"\n"\
  203.            "Example: %s \"xv7ydq#opaj_39rzut8b45wcsgehmiknf26l\" \"#rubberducky\" \"r3qicv_iypnlnywas3_qn#rwmtwlwhwuu\" \"bw6ib7\" \n"\
  204.            , argv[0], argv[0], argv[0], argv[0]);
  205.   } else {
  206.     char* key = argv[1];
  207.     char* sig = argv[2];
  208.     char* msg = argv[3];
  209.     if (argc == 4) { //encrypt
  210.       char* nonce = NULL;
  211.       char* ciphertext = encrypt_message(key, &nonce, sig, msg);
  212.       printf("nonce: %s\n", nonce);
  213.       printf("ciphertext: %s\n", ciphertext);
  214.       free(nonce);
  215.       free(ciphertext);
  216.     } else if (argc == 5) { //decrypt
  217.       char* nonce = argv[4];
  218.       char* plaintext = decrypt_message(key, nonce, sig, msg);
  219.       printf("plaintext: %s\n", plaintext);
  220.       free(plaintext);
  221.     }
  222.   }
  223.  
  224.   return 0;
  225. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
Top