Thread: Caesar encryption

  1. #1
    Registered User
    Join Date
    Sep 2006
    Posts
    21

    Caesar encryption

    I need some help with my program - a simple caesar cipher program. I'll come clean and admit that this is for a college class I'm taking. The assignment was to build a program that could encrypt messages by rotating the characters. I've managed to get it to work with single letters, but not with strings. I have no programming experience whatsoever so please try to explain things to me as you would to a five year old.

    Code:
    #include <stdio.h>
    
    main()
    {
    /*
          char        un;
          char        en;
          int         offset, i;
    
          printf("Enter a letter: ");
          scanf("%c", &un);
          fflush(stdin);
          
          for ( ;; )
          {
              printf("Enter offset [1,10]: ");
              scanf("%d", &offset);
              if ( offset >= 1 && offset <= 10 )
                  break;
                         
              else      
                 continue;
          }        
                    
          if ( un >= 'a' && un <= 'z' )
              en += (((un - 'a') + offset) % 26) + 'a';
          
          else
              en += (((un - 'A') + offset) % 26) + 'A';
          
          printf("Unencrypted: %c\n", un);
          printf("Encrypted: %c\n", en);
          
          fflush(stdin);
          getchar();
    */
    
          int       i, offset = 1, c;
          char      un[51];
          char      en[51];
    
          printf("Input: ");
          scanf("%[^\n]", un);
          
          for ( i = 0; i < un[i]; i++ )
                en[i] += (((un[i] - 'a') + offset) % 26) + 'a';
          
          printf("Unencrypted text: %s\n", un);
          printf("Encrypted text: %s\n", en);
                
          fflush(stdin);
          getchar();
    }
    The "first" program works as it should, but when I tried to extend the chars to whole strings I ran into some problems, and it just outputs garbage.

    So my questions is basically - why?

    Also - I need for someone to break this down for me: Exactly what happens here and why? Why does the lowercase alphabet get shifted to 0-25 when lowercase 'a' is removed? I understand that modulo rotates the a --> z part but again, I don't understand why it happens or why I should put back the lowercase 'a'.. I just don't get it.. I'm in desperate need of some assistance. Please, if you have some spare time, try to clarify this to me..
    Code:
    en[i] += (((un[i] - 'a') + offset) % 26) + 'a';
    I'd really appreciate some help..

  2. #2
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Code:
    for ( i = 0; i < un[i]; i++ )
    Your loop condition is wierd. You should be checking specifically for the end of the string, not for some ... whatever it is you're doing. Make sure i is less than 50, and that un[ i ] isn't '\0'.


    Quzah.
    Hope is the first step on the road to disappointment.

  3. #3
    Registered User
    Join Date
    Oct 2001
    Posts
    2,934
    >I don't understand why it happens or why I should put back the lowercase 'a'.. I just don't get it..
    Code:
    >en[i] += (((un[i] - 'a') + offset) % 26) + 'a';
    I could be wrong, but I think the idea is to do all the math on a number from 0 to 25, so you subtract out the 'a', do the math, then add back in the 'a'. And why the +=? Why not just:
    Code:
    en[i] = (((un[i] - 'a') + offset) % 26) + 'a';

  4. #4
    Registered User
    Join Date
    Sep 2006
    Posts
    21
    Quote Originally Posted by quzah
    Code:
    for ( i = 0; i < un[i]; i++ )
    Your loop condition is wierd. You should be checking specifically for the end of the string, not for some ... whatever it is you're doing. Make sure i is less than 50, and that un[ i ] isn't '\0'.


    Quzah.

    Allright, I've changed the loop to
    Code:
    for ( i = 0; i < un[51] && i != '\0'; i++ )
                en[i] = (((un[i] - 'a') + offset) % 26) + 'a';
    But still, no output. Why won't this work? How come there is no output except for a ". That's the only output I get, regardless of what I type..

  5. #5
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Quote Originally Posted by Machiaveli
    Allright, I've changed the loop to
    Code:
    for ( i = 0; i < un[51] && i != '\0'; i++ )
    When you have an array, and you put a number in there (between the brackets), you're no longer talking about the entire array, you're talking about one specific character. You're close, but backwards:
    Code:
    for ( i = 0; i < 51 && un[ i ] != '\0'; i++ )
    "set i to zero"
    "for every count of i, where i is less than 51, and the value stored in array location i isn't the null charcter..."
    "now increment i"


    Quzah.
    Hope is the first step on the road to disappointment.

  6. #6
    Gawking at stupidity
    Join Date
    Jul 2004
    Location
    Oregon, USA
    Posts
    3,218
    Why does the lowercase alphabet get shifted to 0-25 when lowercase 'a' is removed? I understand that modulo rotates the a --> z part but again, I don't understand why it happens or why I should put back the lowercase 'a'
    So let me get this straight. You basically stole some code, tried to play it off like you wrote it, and then tried hacking away at it until it did what you wanted?

    If you had written that line of code you would know how/why it works.
    If you understand what you're doing, you're not learning anything.

  7. #7
    Registered User
    Join Date
    Sep 2006
    Posts
    21
    Quote Originally Posted by quzah
    When you have an array, and you put a number in there (between the brackets), you're no longer talking about the entire array, you're talking about one specific character. You're close, but backwards:
    Code:
    for ( i = 0; i < 51 && un[ i ] != '\0'; i++ )
    "set i to zero"
    "for every count of i, where i is less than 51, and the value stored in array location i isn't the null charcter..."
    "now increment i"


    Quzah.
    AH! You're a lifesaver! I've been sitting in front of my computer for who knows how long and I wanted to figure it out by myself but I was getting too tired and it's close to midnight here so at least I can have a good nights sleep :-)

    Thank you, thank you, thank you!

  8. #8
    Registered User
    Join Date
    Sep 2006
    Posts
    21
    Quote Originally Posted by itsme86
    So let me get this straight. You basically stole some code,
    Right.
    tried to play it off like you wrote it,
    No.
    and then tried hacking away at it until it did what you wanted?
    Pretty much.
    If you had written that line of code you would know how/why it works.
    So, let me get this straight.. When you don't understand something you just go: "It wasn't for me anyway"? I guess that's why you felt the need to make stupid remarks instead of answering the questions. Why don't you enlighten me as to what that part of the code does, eh? How does one learn to program? By reading books or by writing code?

  9. #9
    Gawking at stupidity
    Join Date
    Jul 2004
    Location
    Oregon, USA
    Posts
    3,218
    Look up an ASCII table. See where 'a' is on that table. Characters are just numbers in a different representation. This allows you to do things like 'b' - 'a' and get 1.
    If you understand what you're doing, you're not learning anything.

  10. #10
    Registered User
    Join Date
    Sep 2006
    Posts
    21
    Quote Originally Posted by itsme86
    Look up an ASCII table. See where 'a' is on that table. Characters are just numbers in a different representation. This allows you to do things like 'b' - 'a' and get 1.
    Sure, a = 97, b = 98, different codes for different characters. But why take away a, it's the logic behind it all that I just don't understand. Why remove the a to begin with? I'm sorry, I'm really slow today..

  11. #11
    Registered User
    Join Date
    Sep 2006
    Posts
    21
    This is from another thread here at cprogramming.com. The gentleman that I stole the code snippet from is joshdick. He explained what every part of the code does, but I just don't get it..

    This code implements a Caesar cipher.

    plaintext[i] is the ith letter in that string.
    I subtract 'a' so that the lowercase alphabet is shifted to [0-25].
    I add the offset. This is the part that actually does the encryption. 'a' becomes 'd', etc.
    I modulo 26 so that 'z' will become 'c', etc. This part is important.
    And finally, I add 'a' back so that the lowercase alphabet displays its proper ASCII values.

    Code:
    	string plaintext = "theeaglefliesatmidnight";
    	string ciphertext;
    	int n = plaintext.length();
    	int offset = 3;
    	for(int i =0; i < n; ++i)
    	{
    	  ciphertext += ( ( (plaintext[i] - 'a') + offset) % 26) + 'a';
    	}
    	cout << ciphertext << endl;
    Of course, I had to modify it, since this was for c++..
    Anyway, it's the logic behind that whole string that I just can't wrap my head around..

    Why remove a?
    How does the modulo perform it's operation?
    In what order does the addition and subtraction occur?
    Those types of questions..

    Anyway, better get some sleep.
    Thank you all!

  12. #12
    Gawking at stupidity
    Join Date
    Jul 2004
    Location
    Oregon, USA
    Posts
    3,218
    modulo gives you the remainder of the division operator. So if you did somechar % 26, for 25 you'd get 25, 26 you'd get 0, 27 you'd get 1, etc. This doesn't work easily unless your "bottom" is 0. let's say you do 'z' + 1. You get 123. What would you use for the second operand for modulus? if you used 123 you'd get 0. Well that's fine, but what's 0? It certainly isn't 'a'. So you decide you can just add 'a' back to get back into the right range. Well, now that only works when you end up shifting past 'z'. If you had 'a' + 1 you certainly wouldn't want to add 'a' to it.

    By making the range start at 0 instead of 97 you bypass all these problems.

    As far as what order things happen in...they happen from the innermost set of parentheses to the outermost. Just like in math. If you had 2 * (3 + 5) you do the 3+5 first and then multiply that result by 2.
    If you understand what you're doing, you're not learning anything.

  13. #13
    int x = *((int *) NULL); Cactus_Hugger's Avatar
    Join Date
    Jul 2003
    Location
    Banks of the River Styx
    Posts
    902
    Why remove a?
    Because of the modulus operator. Modulus merely returns the remainer of a division problem.
    How does the modulo perform it's operation?
    Magic. (How does + or / or * do it's work?) Take a % b. The result will be the remainder between the two numbers.
    In what order does the addition and substraction occur?
    What we call operator precedence. This is very well defined, Google it. (See this)

    The whole thing has a terrible lot of parentheses. It can be reduced to:
    Code:
    ciphertext += (plaintext[i] - 'a' + offset) % 26 + 'a';
    Take the letter a. First, we shift the whole alphabet, so that whatever value represents 'a' is now 0, 'b' is 1, etc. We add in the offset (shift), so 0 becomes 3 (or 'a' becomes 'd'). There's one problem with this: what about 'z'? It's value, 25, would become 28, which isn't valid. So we do a "% 26" on it - 28 % 26 = 2, or 'c', which is correct. When then shift the letters back to what numbers the machine uses to represent them by adding 'a'.
    long time; /* know C? */
    Unprecedented performance: Nothing ever ran this slow before.
    Any sufficiently advanced bug is indistinguishable from a feature.
    Real Programmers confuse Halloween and Christmas, because dec 25 == oct 31.
    The best way to accelerate an IBM is at 9.8 m/s/s.
    recursion (re - cur' - zhun) n. 1. (see recursion)

  14. #14
    Registered User
    Join Date
    Sep 2006
    Posts
    21
    Thank you both! I'm starting to grasp the concept of how all that works.. It's my third week and we only have class a couple of hours a week, so it's hard to fully understand everything at once.

    But I seem to have some problems with it still.. Whenever I use certain characters alone, like 't', or 'o' I get garbage, but if I type 'rst' for example, the output is fine. The alphabet works up to and including 'k' = 'abcdefghijk' but if I type 'abcdefghijkl' I get garbage at the end. But I can start with 'k' and move up to 'u' without problems.. klmnopqrstu works..
    How come there is an extra character sometimes, but not always - depending on what characters I've typed in? Does the new line character mess things up, or is there something wrong with the code itself?

    EDIT: I had to initialize the array.. duh..
    Next I'll tackle how to ignore characters like spaces, periods and whatnot to get a cleaner output.

    itsme86,
    This won't be the assignment I hand over. I have another one, where the characters are in two separate arrays. One that starts with A, B, C... and another that starts with Z, A, B creating a offset of 1. It works, although it's not as elegant as the code above (if it indeed worked!). But i'd really like to see how this comes together. I need to learn this..

    Once again, thank you for responding!
    Last edited by Machiaveli; 09-14-2006 at 05:36 AM.

  15. #15
    Registered User
    Join Date
    Sep 2006
    Posts
    21
    After I initialized the array the output is correct, without any funny characters, but I can't seem to make it skip spaces, for example. I've tried some if conditions to have it ignore spaces, but it just kills the for-loop.. Leaving me with only the first word encrypted.
    I played around with the code and found a ugly way to remove the U's that spaces get after being "encrypted", but it's not ideal.. at all.
    Believe me, I've tried reading up on if conditionals and loops..

    I don't like programming (since I suck at it) nor will I ever become a programmer, but I had to take this course since it's part of the whole course program. Next is assembler and perl.. Oh, good.
    Help me out here, please.

    Code:
    #include <stdio.h>
    
    main()
    {
    
          int       i, offset = 1;
          char      un[51] = {0};
          char      en[51] = {0};
          
          printf("Input: ");
          scanf("%[^\n]", un);
    
          for ( i = 0; i < 51 && un[i] != '\0'; i++ )
          {   
              if (un[i] != ' ') /* This kills my for-loop! */
                   en[i] = (((un[i] - 'a') + offset) % 26) + 'a';
                   
                  /*if ( en[i] == 'U' ) Spaces are dispayed as U's in the output. */
                   /*    en[i] = ' ';   It's an ugly solution, I know, but at least it works.. */
                                            
          }       
          
          printf("Unencrypted text: %s\n", un);
          printf("Encrypted text:   %s\n", en);
          
          fflush(stdin);
          getchar();
          
    }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 16
    Last Post: 11-23-2007, 01:48 PM
  2. help needed with edit control & encryption
    By willc0de4food in forum Windows Programming
    Replies: 2
    Last Post: 03-16-2006, 08:21 PM
  3. abt encryption algorithm
    By purIn in forum C Programming
    Replies: 9
    Last Post: 12-22-2003, 10:16 PM
  4. What's wrong with my Stream Cipher Encryption?
    By Davros in forum C++ Programming
    Replies: 3
    Last Post: 04-18-2002, 09:51 PM
  5. File Encryption & Read/Write in Binary Mode
    By kuphryn in forum C++ Programming
    Replies: 5
    Last Post: 11-30-2001, 06:45 PM