Thread: XOR encryption

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

    XOR encryption

    I need some help with a XOR program I'm trying to write.

    I need to know if I'm on the right track here, and how I could decrypt it all. Reverse the process, so to speak. Please have a look at this code, but ignore all the unnecessary printf's, I'm just trying to follow the code through step by step.

    Are the for loops correct? I found some pseudo code in the forum which I decided to write the code from..
    If the encryption is in order, which I believe it is, then there's the small matter of decrypting it.. The process has to be reversed, that much I know, but it seems it will only decrypt as many characters as the key is based on. Somwhere, somehow, this needs to increment..

    itsme86, you've been of great help explaining the modulo and the caesar program. You mind taking a peek at this?

    Code:
    #include <stdio.h>
    #include <string.h>
    main()
    {
          char        plain[51];
          char        encry[51];
          char        key[5] = "ABCD";
          int           i, keylen = 0, keypos = 0;
          
          printf("Enter text: ");
          scanf("%[^\n]", plain);
          printf("You entered: %s\n", plain);
          keylen = strlen(key);
          printf("Encyption key is: %s\n", key);
          printf("Length of key is: %d\n", keylen);
          
          for ( i = 0; plain[i] != '\0'; i++ ) 
          {
              encry[i] = plain[i] ^ key[keypos];
              keypos++;
                    if ( keypos > keylen )
                       keypos = 0;
              
          }    
          printf("\nEncrypted text: %s\n", encry);        
    
          for ( i = 0; encry[i] != '\0'; i++ ) {
              plain[i] = encry[i] ^ key[i]; /*???*/   
              /* ??? */
              }
              
          printf("Decrypted: %s", plain);
          
          fflush(stdin);
          getchar();
    }

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    > printf("\nEncrypted text: %s\n", encry);
    'A' ^ 'A' is 0, which will not print very well with %s
    Similarly, other pairs of letters will produce similar non-printable results.

    > fflush(stdin);
    Ugh, read the FAQ.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Sep 2006
    Posts
    21
    Quote Originally Posted by Salem
    > printf("\nEncrypted text: %s\n", encry);
    'A' ^ 'A' is 0, which will not print very well with %s
    Similarly, other pairs of letters will produce similar non-printable results.

    > fflush(stdin);
    Ugh, read the FAQ.
    Yes, I know about the fflush(stdin); issue, but I thought I would leave it as it is and concentrate on the encryption and decryption instead.

    I've changed both my "Encrypted" and "Decrypted" part of the code to
    Code:
    puts("Encrypted text: ");
    puts(encry);
    Same for the decrypted text, but it's not decrypting the way it should.. Actually I don't even know if it's encrypting as it should.. Would you mind giving it a go?

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Well xor is so simple that decrypt is the same as encrypt

    So given something like
    void encrypt( char *message, const char *key, size_t messageLen, size_t keyLen );

    Calls of
    len = strlen(message);
    encrypt( message, key, len, strlen(key) );
    encrypt( message, key, len, strlen(key) );

    Will get you back to where you started.
    Just don't do any str... functions on the intermediate result.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  5. #5
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    As Salem said, encrypting is the same as decrypting.
    Code:
          for ( i = 0; plain[i] != '\0'; i++ ) 
          {
              encry[i] = plain[i] ^ key[keypos];
              keypos++;
                    if ( keypos > keylen )
                       keypos = 0;
              
          }    
          printf("\nEncrypted text: %s\n", encry);        
    
          for ( i = 0; encry[i] != '\0'; i++ ) {
              plain[i] = encry[i] ^ key[i]; /*???*/   
              /* ??? */
              }
    So you need to use key[keypos] for the decrypting too.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  6. #6
    Registered User
    Join Date
    Sep 2006
    Posts
    21
    Quote Originally Posted by Salem
    Well xor is so simple that decrypt is the same as encrypt

    So given something like
    void encrypt( char *message, const char *key, size_t messageLen, size_t keyLen );

    Calls of
    len = strlen(message);
    encrypt( message, key, len, strlen(key) );
    encrypt( message, key, len, strlen(key) );

    Will get you back to where you started.
    Just don't do any str... functions on the intermediate result.
    Yes, well.. this will most certainly be embarrasing.. Functions is in the next chapter of our book.. :-) But I'll do my best and read up on what that "void encrypt" part of the code does. I'm guessing the *'s are pointers and those are not discussed for a loooong time in our book.
    I'll read up on functions, as best I can, and maybe I'll be able to break that sucker.

  7. #7
    Registered User
    Join Date
    Sep 2006
    Posts
    21
    Quote Originally Posted by dwks
    As Salem said, encrypting is the same as decrypting.
    Code:
          for ( i = 0; plain[i] != '\0'; i++ ) 
          {
              encry[i] = plain[i] ^ key[keypos];
              keypos++;
                    if ( keypos > keylen )
                       keypos = 0;
              
          }    
          printf("\nEncrypted text: %s\n", encry);        
    
          for ( i = 0; encry[i] != '\0'; i++ ) {
              plain[i] = encry[i] ^ key[i]; /*???*/   
              /* ??? */
              }
    So you need to use key[keypos] for the decrypting too.
    I've tried different combinations, but I can't seem to get it right.. Something, somewhere, needs to increment, in order for it to allow more characters to be decrypted, and that's where I fail.. I'll try some more though..

  8. #8
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    It's quite simple.
    Code:
          for ( i = 0; plain[i] != '\0'; i++ ) 
          {
              encry[i] = plain[i] ^ key[keypos];
              keypos++;
                    if ( keypos > keylen )
                       keypos = 0;
              
          }    
          printf("\nEncrypted text: %s\n", encry);        
    
          for ( i = 0; encry[i] != '\0'; i++ ) {
              plain[i] = encry[i] ^ key[i]; /*???*/   
              /* ??? */
              }
    Use the code in the first loop in the second one.
    Code:
    /* decrypt loop */
          for ( i = 0; encry[i] != '\0'; i++ ) 
          {
              plain[i] = encry[i] ^ key[keypos];
              keypos++;
                    if ( keypos > keylen )
                       keypos = 0;
              
          }
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  9. #9
    Registered User
    Join Date
    Sep 2006
    Posts
    21
    Quote Originally Posted by dwks
    It's quite simple.
    Use the code in the first loop in the second one.
    Code:
    /* decrypt loop */
          for ( i = 0; encry[i] != '\0'; i++ ) 
          {
              plain[i] = encry[i] ^ key[keypos];
              keypos++;
                    if ( keypos > keylen )
                       keypos = 0;
              
          }
    Well, that's actually the first thing I tried, but I get garbage for output. I thought it would be the logical choice.. Here's the code, and whenever I try to decrypt I get garbage.. There has to be something wrong with the loops.. Saturday evening and I'm trying to get a XOR program to work.. Well, at least I'm committed :-)
    Code:
    #include <stdio.h>
    #include <string.h>
    main()
    {
          char        plain[51];
          char        encry[51];
          char        key[5] = "ABCD";
          int         i, keylen = 0, keypos = 0;
          
          printf("Enter text: ");
          scanf("%[^\n]", plain);
          printf("You entered: %s\n", plain);
          keylen = strlen(key);
          printf("Encryption key is: %s\n", key);
          printf("Length of key is: %d\n", keylen);
          
          for ( i = 0; plain[i] != '\0'; i++ ) 
          {
              encry[i] = plain[i] ^ key[keypos];
              keypos++;
                    if ( keypos > keylen )
                       keypos = 0;
                             
          }                 
          puts("Encrypted text: ");
          puts(encry);   
                            
          for ( i = 0; encry[i] != '\0'; i++ ) {
              plain[i] = encry[i] ^ key[keypos];
              keypos++;
                    if ( keypos > keylen )
                       keypos = 0;
              }
              
          puts("Decrypted: ");
          puts(plain);
          
          fflush(stdin);
          getchar();
    }

  10. #10
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    You have to set keypos to zero before the second loop. Otherwise it starts whereever the first loop left off.

    Your indentation is better.
    Code:
    fflush(stdin);
    But this is not.


    [edit] BTW, puts() appends a newline to the end of the string, so
    Code:
          puts("Decrypted: ");
          puts(plain);
    will print
    Code:
    Decrypted: 
    plaintext
    [/edit]
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  11. #11
    Registered User
    Join Date
    Sep 2006
    Posts
    21
    Quote Originally Posted by dwks
    You have to set keypos to zero before the second loop. Otherwise it starts whereever the first loop left off.

    Your indentation is better.
    Code:
    fflush(stdin);
    But this is not.


    [edit] BTW, puts() appends a newline to the end of the string, so
    Code:
          puts("Decrypted: ");
          puts(plain);
    will print
    Code:
    Decrypted: 
    plaintext
    [/edit]
    Haha, everyone keeps bugging me about the stdin :-) I promise, I'll do my best to get rid of it asap. Thanks for helping me with the program. It works quite nicely now.. I also changed my puts to fputs instead and got rid of the new line. Looks much better. I'm learning as I go..

    Code:
          fputs("Decrypted: ", stdout);
          puts(plain);
    There is one more thing, when it has decrypted the text, it spits out several of these garbage characters after the decrypted text. Is there something I could throw at that?

    If I encrypt and decrypt "testtest", for example - 39 characters get printed to the screen. 8 of them being the testtest and the rest is just arbitrary characters. Sample

    Code:
    Enter text: testtest
    You entered: testtest
    Encryption key is: ABCD
    Length of key is: 4
    Encrypted text: 5'00t$17↑¯É|p♣æ|    m♣æ|Ì┬┬w
    Keypos set to: 0
    Decrypt ch count: 39
    Decrypted: testtest\¯Ð>3Aæ=¢╝╗ ,GÊ8ÌâÇ4Ò┬┬w¶©├w`$=

  12. #12
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Code:
          for ( i = 0; encry[i] != '\0'; i++ ) {
    You never add a terminating NULL to encry[] so you'll never find one. (At least where you expect to.) Add this
    Code:
    encry[i] = 0;
    just after the first loop.

    [edit] You could use the isprint() function to only print characters that are printable. [/edit]
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  13. #13
    Registered User
    Join Date
    Sep 2006
    Posts
    21
    Quote Originally Posted by dwks
    Code:
          for ( i = 0; encry[i] != '\0'; i++ ) {
    You never add a terminating NULL to encry[] so you'll never find one. (At least where you expect to.) Add this
    Code:
    encry[i] = 0;
    just after the first loop.

    [edit] You could use the isprint() function to only print characters that are printable. [/edit]
    How can you possibly keep track of all those "small" details? That small program took me the better part of the day to put together. Oh, it's wonderful being a noob :-) I really appreciate your help!

    I'll rewrite the program for a little cleaner output and try to make the whole en-/decryption thingie into a function. Should be fun.

    Thanks again!

  14. #14
    int x = *((int *) NULL); Cactus_Hugger's Avatar
    Join Date
    Jul 2003
    Location
    Banks of the River Styx
    Posts
    902
    Quote Originally Posted by dwks
    Code:
          for ( i = 0; encry[i] != '\0'; i++ ) {
    You never add a terminating NULL to encry[] so you'll never find one. (At least where you expect to.) Add this
    Code:
    encry[i] = 0;
    just after the first loop.
    Salem mentioned this earlier...
    You cannot use part of the encrypted text to determine it's length. If you encrypt "ABCD" with key "ABCDE", those first As will cancel each other to a null. (Which is fine) You must record the length of the encrypted text in a variable. Like datalen = strlen(plain); and the make your loops:
    Code:
    for(i = 0; i < datalen; ++i)
    The null is totally unneeded, since it's never used by the loop. (You will want to ensure that whatever buffer you're decrypting into has a null after the decrypted text, however. Since you reuse the variable "plain", the old null from the plaintext should still be there.)
    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)

  15. #15
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Sorry, I should have thought of that . . .
    (You will want to ensure that whatever buffer you're decrypting into has a null after the decrypted text, however. Since you reuse the variable "plain", the old null from the plaintext should still be there.)
    If datalen is the return value of strlen(), you'd want to use <=datalen to encrypt the NULL as well, or just add the NULL after the decryption.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

Popular pages Recent additions subscribe to a feed