Thread: Signed unsigned ints?

  1. #1
    Registered User
    Join Date
    Aug 2006
    Posts
    43

    Unhappy Signed/unsigned issue, now with more broken-ness!

    So, I'm working on a bit of code to implement the (A)RC4 algorithm, for no reason other than for fun. My problem (please be kind - I know there are several issues with the code) is that, for some reason, the encryption algorithm likes to output signed ints. For example, if the plaintext input is "Hello." and the key is "1234" I get the following output:
    4d 2c 1d ffffffc3 ffffff9c ffffffc2
    I'm sure I'm missing a cast or something, but I'm completely lost. Any help would be fantastic.

    Code:
    #include <iostream>
    #include <string>
    #include <vector>
    
    using namespace std;
    
    string Encrypt(const string &plaintext, const unsigned int text_length, const string &key, const unsigned int key_length);
    
    int main()
    {
    	string plaintext, cyphertext, key;
    	cout << "Enter string to be encrypted/decrypted: ";
    	getline(cin, plaintext, '\n');
    	unsigned int text_length(plaintext.length());
    	cout << "Enter encryption key: ";
    	getline(cin, key, '\n');
    	unsigned int key_length(key.length());
    	cyphertext = Encrypt(plaintext, text_length, key, key_length);
    	for(unsigned int i = 0; i < text_length; ++i)
    		cout << hex << static_cast<unsigned int>(cyphertext.at(i)) << " ";
    
        return 0;
    }
    
    string Encrypt(const string &plaintext, const unsigned int text_length, const string &key, const unsigned int key_length)
    {
    	unsigned int i(0);
    	unsigned int j(0);
    	unsigned int k(0);
    	vector<unsigned int> S(256, 0);
    	string cyphertext;
    	
    	//BEGIN KEY-SCHEDULING ALGORITHM
    	for(i = 0; i < 256; ++i)
    	{
    		S.at(i) = i;	//initialize s-box S[0] = 0...S[255] = 255 
    	}
    	
    	for(i = 0; i < 256; ++i)
    	{
    		//transpose s-box values based on key
    		j = (j + S.at(i) + key.at(i % key_length)) % 256;
    		swap(S.at(i), S.at(j));
    	}
    	//END KEY-SCHEDULING ALGORITHM
    
    	//BEGIN PSEUDO-RANDOM GENORATION ALGORITHM
    	for(i = 0, j = 0; i < text_length; ++i)
    	{
    		//transpose s-box values based on s-box values
    		j = (j + 1) % 256;
    		k = (k + S.at(j)) % 256;
    		swap(S.at(j), S.at(k));
    		//encryption happens here
    		cyphertext += plaintext.at(i) ^ (S.at((S.at(j) + S.at(k)) % 256));
    	}
    	//END PSEUDO-RANDOM GENORATION ALGORITHM
    	
    	return cyphertext;
    }
    Last edited by Mostly Harmless; 08-22-2008 at 12:05 AM. Reason: Changed title for more flair.

  2. #2
    Banned master5001's Avatar
    Join Date
    Aug 2001
    Location
    Visalia, CA, USA
    Posts
    3,685
    ffffffc2 is unsigned... It sounds like underflow, but I am not seeing any operation that would cause an underflow.

    Code:
    cyphertext += plaintext.at(i) ^ (S.at((S.at(j) + S.at(k)) &#37; 256));
    That line looks dubiously like the culprit. But I am compilerless at the moment, so yeah...

  3. #3
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    I'm not familiar with ARC, but what's wrong with what you're getting? (As master points out, those are unsigned numbers.)

  4. #4
    Banned master5001's Avatar
    Join Date
    Aug 2001
    Location
    Visalia, CA, USA
    Posts
    3,685
    His result is supposed to be a single byte value... That is what is wrong. However, I am going to say as a pragmatist, if the code can successfully decode its output, what the hell is the problem? You aren't trying to compress data, you are trying to obscure it.

  5. #5
    60% Braindead
    Join Date
    Dec 2005
    Posts
    379
    Signed values are numbers without the ability to contain negative values. Unsigned values have this ability. Are you saying that the program is returning only positive values when it shoulden't be?
    Code:
    Error W8057 C:\\Life.cpp: Invalid number of arguments in function run(Brain *)

  6. #6
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Quote Originally Posted by Blackroot View Post
    Signed values are numbers without the ability to contain negative values. Unsigned values have this ability.
    You have this backwards.

  7. #7
    Registered User
    Join Date
    Jan 2008
    Posts
    290
    Considering that the string class is really a typedef'd basic_string<char>, every time you call the at() method it's probably returning a signed char, and somewhere in the Encrypt function a sign extension happens.

    I did a quick test by typedef'ing basic_string<unsigned char> ustring, and then converting all your strings to ustrings. Unfortunately this gave me issues with getline(), so I just switched to C-style input.

    Does this work for you?

    Code:
    #include <cstdio>
    #include <string>
    #include <vector>
    
    using namespace std;
    
    typedef basic_string<unsigned char> ustring;
    
    ustring Encrypt(const ustring &plaintext, const ustring &key);
    
    int main()
    {
       unsigned char buf[1024];
       ustring cyphertext, plaintext, key;
       
       fputs("Enter string to be encrypted/decrypted: ", stdout);
       fgets((char*)buf, sizeof(buf), stdin);
       plaintext.assign(buf);
       
       fputs("Enter encryption key: ", stdout);
       fgets((char*)buf, sizeof(buf), stdin);
       key.assign(buf);
       
       cyphertext = Encrypt(plaintext, key);
       
       for(unsigned int i = 0; i < cyphertext.length(); ++i)
          printf("%x ", cyphertext.at(i));
    
       return 0;
    }
    
    ustring Encrypt(const ustring &plaintext, const ustring &key)
    {
       unsigned int i(0);
       unsigned int j(0);
       unsigned int k(0);
       vector<unsigned int> S(256, 0);
       ustring cyphertext;
       
       //BEGIN KEY-SCHEDULING ALGORITHM
       for(i = 0; i < 256; ++i)
       {
          S.at(i) = i;   //initialize s-box S[0] = 0...S[255] = 255 
       }
       
       for(i = 0; i < 256; ++i)
       {
          //transpose s-box values based on key
          j = (j + S.at(i) + key.at(i % key.length())) % 256;
          swap(S.at(i), S.at(j));
       }
       //END KEY-SCHEDULING ALGORITHM
    
       //BEGIN PSEUDO-RANDOM GENORATION ALGORITHM
       for(i = 0, j = 0; i < plaintext.length(); ++i)
       {
          //transpose s-box values based on s-box values
          j = (j + 1) % 256;
          k = (k + S.at(j)) % 256;
          swap(S.at(j), S.at(k));
          //encryption happens here
          cyphertext += plaintext.at(i) ^ (S.at((S.at(j) + S.at(k)) % 256));
       }
       //END PSEUDO-RANDOM GENORATION ALGORITHM
       
       return cyphertext;
    }
    Code:
    >a.exe
    Enter string to be encrypted/decrypted: Hello.
    Enter encryption key: 1234
    39 2a 9c 93 ce 20 ed

  8. #8
    Registered User
    Join Date
    Aug 2006
    Posts
    43
    Quote Originally Posted by master5001 View Post
    ffffffc2 is unsigned... It sounds like underflow, but I am not seeing any operation that would cause an underflow.

    Code:
    cyphertext += plaintext.at(i) ^ (S.at((S.at(j) + S.at(k)) % 256));
    That line looks dubiously like the culprit. But I am compilerless at the moment, so yeah...
    Well, the math is being done correctly. That is, the xor operation is providing the correct results. So, for example, when it's time to encrypt the '.', you have:
    Code:
    cyphertext += "." ^ 236;
                =  46 ^ 236
                = 194
    That (unsigned) 194 is being stored in cyphertext as the signed int (char? wchar?) -62. This is what I don't know how to fix. I've tried substituting basic_string<unsigned char> for string, but that just breaks everything (like getline(), which I guess I don't know how to implement with basic_string<>).

    I could rewrite the entire thing with c-style string, I suppose, and I imagine it would work without a hitch, but that defeats the purpose.

  9. #9
    Registered User
    Join Date
    Aug 2006
    Posts
    43
    Quote Originally Posted by arpsmack View Post
    Considering that the string class is really a typedef'd basic_string<char>, every time you call the at() method it's probably returning a signed char, and somewhere in the Encrypt function a sign extension happens.

    I did a quick test by typedef'ing basic_string<unsigned char> ustring, and then converting all your strings to ustrings. Unfortunately this gave me issues with getline(), so I just switched to C-style input.

    Does this work for you?

    Code:
    ...snip...
    I read your post (which came in while I was writing mine) and had to look over my shoulder to make sure you weren't standing behind me reading what I was typing. Creepy.

    Thanks for getting it to work with the c-style input, but now I'm on a mission to find a way to get it to work with C++ strings. Ugh.
    Last edited by Mostly Harmless; 08-22-2008 at 12:37 AM.

  10. #10
    Registered User
    Join Date
    Jan 2008
    Posts
    290
    Quote Originally Posted by Mostly Harmless View Post
    I read your post (which came in while I was writing mine) and had to look over my shoulder to make sure you weren't standing behind me reading what I was typing. Creepy.

    Thanks for getting it to work with the c-style input, but now I'm on a mission to find a way to get it to work with C++ strings. Ugh.
    Alternatively, you could just cast the cyphertext to an unsigned char before casting to the int...
    Code:
    ...
    	for(unsigned int i = 0; i < text_length; ++i)
    		cout << hex << static_cast<unsigned int>(static_cast<unsigned char>(cyphertext.at(i))) << " ";
    ...
    Unfortunately, this gives different results than using unsigned char strings, which is why I think there's sign extension going on somewhere. Maybe there's another reason, but I'm tired and can't think too hard about it right now...

  11. #11
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    Quote Originally Posted by Mostly Harmless View Post

    Thanks for getting it to work with the c-style input, but now I'm on a mission to find a way to get it to work with C++ strings. Ugh.
    Perhaps you could compile char as unsigned if for some reason what arpsmack posted is insufficient.

  12. #12
    Registered User
    Join Date
    Jan 2008
    Posts
    290
    Oh MAN. I've been super lame recently. Your function works fine. The reason I was getting different output is because fgets() doesn't remove the trailing newline.

    All you have to do is convert the char to an unsigned char, and then to an int before printing it. This just avoids sign extension.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 12
    Last Post: 08-11-2008, 11:02 PM
  2. Heap corruption using zlib inflate
    By The Wazaa in forum C++ Programming
    Replies: 0
    Last Post: 03-29-2007, 12:43 PM
  3. Replies: 16
    Last Post: 10-29-2006, 05:04 AM
  4. Obtaining source & destination IP,details of ICMP Header & each of field of it ???
    By cromologic in forum Networking/Device Communication
    Replies: 1
    Last Post: 04-29-2006, 02:49 PM