3
\$\begingroup\$

What follows is the first almost useful C program I've successfully written since an Intro to Programming class in college. I'm hoping to slowly maybe work my way up to Objective-C/Cocoa development, but figured I'd start by re-teaching myself the basics. I write PHP for a living, so some things, particularly pointers, are kind of tough to get my head around.

The below is my attempt at implementing the standard tripcode algorithm. Here are some particular areas for which I'd like some (ugh) pointers:

  • There's one compiler warning I couldn't get rid of. The line char *tripped = tripify(argv[x]); in the main function causes "Passing argument 1 of 'tripify' discards qualifiers from pointer target type." What does this mean? I'm guessing maybe it means that argv[x] is a value, instead of a pointer to a value; but if that's the case, why does the code work anyway?
  • Does the static keyword do what I think it does - not initialize the variable on successive function calls, but just reuses the previous value? This is what static does in PHP, but I'm not sure if it's analogous.
  • Is there a better way to do the bit about replacing characters in the salt than how I did it? That bit strikes me as very awkward. Is there an equivalent of PHP's strtr() lurking about somewhere?
  • The actual tripcode algorithm is not very secure. It's a bug feature of the algorithm that I'm well aware of and that's not what I'm asking about here.
#include <stdio.h>
#include <unistd.h> // crypt()
#include <string.h> // strcat(), strncpy()
#include <stdlib.h> // calloc()

char *tripify (char *code) {
  char *saltprep = calloc(255, sizeof(char));
  // Set saltprep to the code appended with "H.."
  strcat(saltprep, code);
  strcat(saltprep, "H..");
  // Get the second and third chars of the saltprep to use as salt
  char *salt = calloc(2, sizeof(char));
  strncpy(salt, saltprep + 1, 2);
  // Replace certain characters in the salt with a corresponding letter
  static char saltreplacefrom[13] = ":;<=>?@[\\]^_`";
  static char saltreplaceto[13] = "ABCDEFGabcdef";
  for (char replacex = 0; replacex < 13; replacex++) {
    if (salt[0] == saltreplacefrom[replacex]) {
      salt[0] = saltreplaceto[replacex];
    }
    if (salt[1] == saltreplacefrom[replacex]) {
      salt[1] = saltreplaceto[replacex];
    }
  }
  // Crypt the code with the salt
  char *crypted = crypt(code, salt);
  // Get the last ten characters of the crypted code
  char *crypted_trimmed = calloc(10, sizeof(char));
  strncpy(crypted_trimmed, crypted + 3, 10);
  // Return
  return crypted_trimmed; 
}

int main (int argc, const char* argv[]) {
  if (argc > 1) {
    for (int x = 1; x < argc; x++) {
      // Get tripcoded value
      char *tripped = tripify(argv[x]);
      // Print input followed by tripcoded value
      printf("%s: %s\n", argv[x], tripped);
    }
  }
  return 0;
}
\$\endgroup\$
3
\$\begingroup\$

There's one compiler warning I couldn't get rid of. The line char *tripped = tripify(argv[x]);

This means the type you are passing is more constrained then type being used in the function.
Looking at the types we have:

  • const char* argv[].

This when you do argv[x] the type is:

  • const char* argv_x

Notice the const. If we now look at the type of the function:

  • char *tripify (char *code)

Notice the parameter here does not have a const on it. So you have a pointer where you are not allowed to change any of the characters (probably because they are in private protected memory and trying to change them is going to cause a seg fault). You are passing this to a function that does not promises not to change the values (if it does some platforms will crash (while others it will work happily)).

You have two options:

1) Make a copy of the string before passing (remember to clean up afterwords).

tmp = strdup(argv[x]);
tripify(tmp);
free(tmp);

2) Change the type of the function:

char *tripify (const char *code)
// Note: If your old code does actually change the value of code then you
//       now need to make a copy internally so it can still be mutated.

Does the static keyword do what I think it does

Yes. Unfortunately static keyword is overloaded. So let me be specific. When static is used in a function context (like above) it means the variable has a longevity beyond the end of the function and will maintain its state between calls.

Note. Since both your static variables are read only you should probably make them const. This will prevent accidents. Also do not specify an exact length for the arrays. By leaving them blank the compiler will calculate the correct size this will help in the long run if these arrays are ever modified. (Note they should have been 14 anyway. When you use a string "Bla" the compiler is already adding a null terminator { 'B', 'l', 'a', '\0'} to the string that you forgot to compensate for)

static const char saltreplacefrom[] = ":;<=>?@[\\]^_`";
static const char saltreplaceto[] = "ABCDEFGabcdef";

Is there a better way to do the bit about replacing characters in the salt than how I did it? That bit strikes me as very awkward. Is there an equivalent of PHP's strtr() lurking about somewhere?

Yes. C contains all the C-String manipulation functions you want (including strstr()). They are in the header file <string.h>

As a final comment I find your code very dense (and the comments meaningless). White space is your friend spread the code out to make it readable. Add comments that explain what you are doing but eching the code is not worth the effort the code is more precise and is reasonable (explain why and overall technique not a line by line).

Sorry: Here is strtr()

char* strtr(char const* s, char const* in, char const* out)
{
    char swaper[] = {   0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
                        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
                        0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
                        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
                        0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
                        0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
                        0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
                        0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
                        0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
                        0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
                        0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
                        0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
                        0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
                        0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
                        0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF };


    // The swapper array is set up so that swapper['a']  returns 'a' etc.
    // So by default it is the null operation

    // This is to add the in/out data into the swapper array.
    // The smallest string will cause the loop to exit.
    for(;*in && *out; ++in, ++out)
    {
        swaper[*in] = *out;
    }

    // Create a duplicate of the array.
    // The php version generates a new string (so this does aswell).
    char* result    = strdup(s);

    // loop over the string and swap each element.
    // Most of the time the swap will be null operation unless the
    // above loop has changed the default value.
    for(char* loop = result;*loop;++loop)
    {
        *result = swaper[*result];
    }
    return result;
}
\$\endgroup\$
1
  • \$\begingroup\$ Thanks, that was pretty much the answer I was looking for. I guess I need to keep a sharper eye out on the scope of my variables. One note, though: "Yes. C contains all the C-String manipulation functions you want (including strstr()). They are in the header file <string.h>" -- I'm afraid I wasn't making a typo when asking for strtr()… strstr() isn't quite what I'm looking for. I suppose I'm just spoiled by PHP's ridiculous selection of string manipulation functions. \$\endgroup\$ – Garrett Albright Oct 3 '11 at 3:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.