1
\$\begingroup\$

I am trying to learn C and I came across the ROT13 scrambling system used to store some passwords.

Assuming the user types everything in correctly (uses 1 argument, uses a string not an int, etc.) would this be correct/safe to use? Or is there anything at all that I am doing wrong you can point out to me (techniques, indentation, anything at all)?

#include <stdio.h>
#include <string.h>

int main(int argc, char** argv)
{
    char* word = argv[1];
    int key = 13;

    // all the letters in the first argument 
    for (int n = 0, len = strlen(word); n < len; n++)
    {
        int currentLetter = word[n];

        char cipher = currentLetter + key;

        // make sure the next letter isn't over 26 or it isn't a ascii letter
        // if it is, do %26
        if ((currentLetter - 'a') + key > 26)
        {
            key = (currentLetter - 'a') + key) % 26;
            cipher = 'a' + key;
        }

        printf("%c", cipher);
        // reset the key and do the next letter
        key = 13;
        }
    }
    printf("\n");
    return 0;
}
\$\endgroup\$
1
  • \$\begingroup\$ In the interest of clarity: there is "safe to use" meaning the code contains no memory leaks or other defects, and "safe to use" meaning ROT13 is a viable algorithm for storing passwords. That latter is never the case. \$\endgroup\$
    – aghast
    Jan 21 at 16:49

3 Answers 3

4
\$\begingroup\$

Test your program with a variety of inputs. Include "abcdefghijklmnopqrstuvwxyz".

Have a look what happens for 'n'. Always try to make sure you test low values, high values and edge cases. 'Wrapping round' is a classic edge case.

Then look at this line:

if ((currentLetter - 'a') + key > 26)

This program only works for lower case 'passwords'.

You might look at the functions in #include <ctype.h> such as tolower(.) or islower(.) to extend to mixing upper and lower case.

NB Obviously ROT13 has no real cryptographic value of any kind. I mention that because I have seen it (and things not better) used in applications. You're doing this as a learning exercise. Right?

\$\endgroup\$
7
  • \$\begingroup\$ IMO ROT13 is perfectly fine to hide simple text from plain text searches in a fast and reliable way. You don't always have to use SHA-1 or AES encryption. It's not about the algorithm or it's security, it's about the actual use case. \$\endgroup\$
    – Mario
    Feb 19, 2015 at 7:50
  • \$\begingroup\$ @mario. A program that searches for 'plain text' will identify ROT13 strings as plain-text. The OP talks about passwords. The use case is that someone obtains the password file and seeks to hack it. Unless they're in kindergarten any self respecting hacker can pretty much read ROT13 let alone hack it. It might be fun to play games but I stand by my comment. No cryptographic value. \$\endgroup\$
    – user59064
    Feb 19, 2015 at 7:58
  • 1
    \$\begingroup\$ Okay, right, missed the password part. It's definitely not a good idea for passwords. :) \$\endgroup\$
    – Mario
    Feb 19, 2015 at 8:06
  • \$\begingroup\$ @Dan Allen Yeah, I this was used for just practice. And actually even before I used 'toLower(currentLetter)'. It did not work correctly. For example when I do './rot32 NICHOLAS' it outputs to '[VPU\YN`' When it should only output letters... \$\endgroup\$
    – ngngngn
    Feb 19, 2015 at 13:47
  • \$\begingroup\$ @Synapz I thought it was practice. But I really have seen it used in real systems protecting real billions of real money. You might simplify with if(cipher>'z'){cipher=cipher-26;} \$\endgroup\$
    – user59064
    Feb 19, 2015 at 13:57
0
\$\begingroup\$

ROT13 scrambling system used to store some passwords

If you find someone using it to store passwords, please tell them to stop, and to actually hash the passwords instead. ROT13 does not provide any security.

Beware of code like this:

 currentLetter - 'a'

The results are platform-dependent (or rather, character-set dependent). Not all character codings have the 26 alphabetical letters as consecutive elements - EBCDIC being the most common exception.

For a coding-independent approach, I would recommend a simple lookup table:

char translate[UCHAR_MAX+1];
/* first make all characters translate to themselves */
for (size_t i = 0;  i < sizeof translate;  ++i) {
    translate[i] = (char)i;
}
char *letters_am = "abcdefghijklm";
char *letters_nz = "nopqrstuvwxyz";
for (size_t i = 0;  letters_am[i];  ++i) {
     /* two corresponding lower-case chars */
     unsigned char c1 = letters_am[i];
     unsigned char c2 = letters_nz[i];
     translate[c1] = c2;
     translate[c2] = c1;
     /* same for their uppercase equivalents */
     c1 = toupper(c1);
     c2 = toupper(c2);
     translate[c1] = c2;
     translate[c2] = c1;
}

Once this table is initialised, we can then transform input very simply:

int c;
while ((c = getchar()) != EOF) {
    putchar(translate[c]);
}
\$\endgroup\$
-3
\$\begingroup\$

I think that the best way to decode ROT13 is with an algorithm like this:

    j = 0;
        while (buf[i] != '\0')
        {
                if ((buf[i] >= 'a' && buf[i] <= 'm') || (buf[i] >= 'A' && buf[i] <= 'M'))
                        buf[i] += 13;
                else if ((buf[i] >= 'n' && buf[i] <= 'z') || (buf[i] >= 'N' && buf[i] <= 'Z'))
                        buf[i] -= 13;
                decoded[j++] = buf[i];
                i++;
        }
        decoded[j+1] = '\0';
\$\endgroup\$
1
  • 2
    \$\begingroup\$ Welcome to Code Review! You have presented an alternative solution, but haven't reviewed the code. Please edit to show what aspects of the question code prompted you to write this version, and in what ways it's an improvement over the original. It may be worth (re-)reading How to Answer. \$\endgroup\$ Jan 21 at 14:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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