7
\$\begingroup\$

My boss needs me to embed the MD5 digest in a file path, but the problem is MD5 contains escape characters.

I've already taught about a uc%duc%d... format, but it also makes lengthy file names. In Linux it's not a problem since the Linux kernel could handle them.

char * uc_encode_md5(const char * password)
{
  char digest_output[1024];
  MD5_CTX md5_ctx ;
  MD5_Init(&md5_ctx);
  MD5_Update(&md5_ctx,password,strlen(password));
  MD5_Final((unsigned char*) digest_output,&md5_ctx);
  char* ret = (char*) malloc(500);
  int len=0;
  int i ;
  for(i=0;i<16;i++)
  {
   len+= sprintf(&ret[len],"uc%d",(unsigned char)digest_output[i]); 
  }

  return ret;
}

Any better way than this? Since my just boss shared what to do, but not how to do it: what's the best practice here?

How about #ifdef's? I could suggest more formats on here and let him choose when I get back to him later tonight.

For example:

char * uc_encode_md5(const char * password)
{
#ifdef _UC_PATH_ENCODE_
  char digest_output[1024];
  MD5_CTX md5_ctx ;
  MD5_Init(&md5_ctx);
  MD5_Update(&md5_ctx,password,strlen(password));
  MD5_Final((unsigned char*) digest_output,&md5_ctx);
  char* ret = (char*) malloc(500);
  int len=0;
  int i ;
  for(i=0;i<16;i++)
  {
   len+= sprintf(&ret[len],"uc%d",(unsigned char)digest_output[i]); 
  }
#endif /* endif _UC_PATH_ENCODE_ */
  return ret;
}
\$\endgroup\$
  • \$\begingroup\$ MD5 is a number. Convert the number into a string that is the ASCII representation of the number. Note: Usually this is done as hex number. If you make sure it is 0 padded it should always be 32 characters long (for 128 bit MD5). As each 8 bits is converted into two hex digits. \$\endgroup\$ – Martin York Feb 9 '14 at 18:09
10
\$\begingroup\$

MD5 is simply a 128 bit number.

Convert the number into a string that is the ASCII representation of the number. Note: Usually this is done as hex number. If you make sure it is 0 padded it will be 32 characters long (as each 8 bits is converted into two hex digits).

This is how I would do it:

static_assert(sizeof(int) == 4, "Figure it out with other sizes");

int*  data = reinterpret_cast<int*>(ret);
int   len  = 128 / (sizeof(int) * 8);

for(int i=len-1; i >= 0; --i)
{
    std::cout << std::setfill('0') << std::setw(8) << std::hex << data[i];
}
\$\endgroup\$
  • 1
    \$\begingroup\$ static_assert is a keyword, and isn't in std. Also, you probably meant sizeof(int) == 4. \$\endgroup\$ – Yuushi Feb 10 '14 at 2:11
  • \$\begingroup\$ I'd avoid this code since it's endian and int size dependent. I'd rather iterate byte wise. \$\endgroup\$ – CodesInChaos Feb 10 '14 at 14:38
  • \$\begingroup\$ @CodesInChaos: Yes there is definitely an issue with endianess of the int. The reason I did not care in this situation was it was only being used to generate a filename. This suggests they are using the filename to distribute the data files evenly across a distributed filesystem. If it is not being used for validation the actual order is not that important. If it is being used for validation then you should be more careful. But you can also provide your own answer. \$\endgroup\$ – Martin York Feb 10 '14 at 20:34

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.