Miesco Posted August 19, 2004 Report Posted August 19, 2004 Could someone please explain the encryption, I know it uses the XOR operator but what does it do to each byte?
50% Packetloss Posted August 19, 2004 Report Posted August 19, 2004 I can explain XOR In C++ the symbol looks like this ^ and its a bitwise operatorHere is a good example of some code that will swap values Lets sayint a=7;int b=10; a ^= b;b ^= a;a ^= b; Now you are saying "WTF", ill explain. The binary value of 7 is 00000111 and the binary value of 10 is 00001010 So what XOR means is Exclusive OR, ill show you how a regular OR works (c++ the operator is | ) 00000111 = 700001010 = 10 OR'd together the number becomes 00001111 = 15 So what happened was that the numbers combined. In an Exclusive OR (XOR) 00000111 = 700001010 = 10 XOR'd together 00001101 = 13 So hopely you see the difference, because its kinda hard to explain So in that swap code i posted above //a ^=b does the below//00000111//00001010 a ^=b; //a now = 00001101 //b ^=a does the below//00001101//00001010b ^=a; //b now = 00000111 //a ^=b does the below//00001101//00000111a ^=b;//a now = 1010 So in the end, a = 10 and b = 7 thus the values have been swaped
Miesco Posted August 20, 2004 Author Report Posted August 20, 2004 Well I did know what the xor operator does, but I didn't know you can swap numbers like that. Anyways, im looking to see an explaination of the subspace encryption.
»Maverick Posted August 20, 2004 Report Posted August 20, 2004 The subspace encryption has not been broken by anyone (yet). I doubt if it ever will. Thus no one will be able to explain you the encryption. (Also because it kept secret to avoid people making their own client and cheat) -MMaverick
Bak Posted August 20, 2004 Report Posted August 20, 2004 the subspace encryption has been broken, you're thinking of continuum encryption. this is straight from http://www.ssihosting.com/catid/files/addendum.txt -=Encryption=- SubSpace uses encryption.  Encryption means to obscure the true meaning of a message using a numerical pattern. When SubSpace connects to a SubGame game server, it firsts completes a key exchange. ie. 00 01 KK KK KK KK VV VV 00 05 SS SS RR RR 00 06 SS SS RR RR TT TT TT TT 00 02 ~K ~K ~K ~K 'KK = Random number (must be negative) 'VV = Encryption version (1 for SubSpace, 16 for Continuum) 'SS = Number of connections since last recycle 'RR = Random number 'TT = Local time '~K = Session key (must be unary -KK) There is some protocol that goes along with these packets: 00 01 gets resent until 00 02 is recv'd. If KK >= 0, then a proper SubSpace server will not acknowledge your connection. 00 05/00 06 isn't used in older SubSpace servers, it's recommended you take this  into account while designing your own stack. Up until the 00 02 response, no other packet types (should be) accepted by the server. Why we use 00 05/00 06: A few years ago I discovered that sending a massive load of 00 01 packets to a SubGame would effectively create a Denial of Service condition; PriitK patched it by masterfully recoding the connection protocol for SubGame to ignore requests until it gets an 00 06 response to SG's 00 05.  It is therefore a fix for a nasty problem. Why we use packets limited to 520 bytes: For both bandwidth reasons and, interestingly enough, the hard fact that SubSpace's encryption uses a buffer of 520 bytes - anything longer cannot be decoded. There are some ways to disable encryption: Send a KK field of 0.  00 01 00 00 00 00 01 00 The server must respond with a NULL key (no encryption). Custom SubSpace stacks may ignore this. Encryption may be disabled server-side if the key you send is the same as the key you get back. But if you want to use encryption: The lengthy DOC by Coconut emulator explains how he ripped SS encryption to a DLL file with SoftICE for use in VB programs.  MERVBot contains C++ code which encapsulates all aspects of maintaining a SubSpace session, including encryption. Security of the encryption: This method of encryption is very weak to a chosen-plaintext attack, and tends to share every fourth byte of the keystream with other connections established within ~48 hours. For example, SECRET_KEY ^ PLAINTEXT -> CIPHER_TEXT, if you know PLAINTEXT then PLAINTEXT ^ CIPHER_TEXT = SECRET_KEY.  In short, do not trust any personal data on a logged connection to SubSpace.  Continuum, on the other hand, has military-grade encryption =)) Then from mervbot's encrypt.cpp: //////// Misc. encryption //////// char ROT13(char c) { if (c >= 'a' && c <= 'z') { c += 13; if (c > 'z') c -= 26; } else if (c >= 'A' && c <= 'Z') { c += 13; if (c > 'Z') c -= 26; } return c; } //////// SubSpace packet encryption //////// // Courtesy of Coconut Emulator SS_ENCR::SS_ENCR() { key = 0; sentKey = 0; } Uint32 SS_ENCR::generateKey() { if (sentKey) return sentKey; Uint32 edx = getTime() * 0xCCCCCCCD; Uint32 res = (keygen.getNext() << 16) + (edx >> 3) + keygen.getNext(); res = (res ^ edx) - edx; if (res <= 0x7fffffff) res = ~res + 1; return (sentKey = res); } Uint32 SS_ENCR::getSessionKey(Uint32 clientKey) { return ((~clientKey) + 1); // Two's complement, same as arithmetic minus on unsigned data } bool SS_ENCR::validateSessionKey(Uint32 serverKey) { return ((serverKey == sentKey) || (serverKey == getSessionKey(sentKey))); } bool SS_ENCR::initializeEncryption(Uint32 serverKey) { if (!validateSessionKey(serverKey)) return false; if (sentKey == serverKey) { key = 0; memset(keystream, 0, 520); } else { key = serverKey; Uint16 *stream = (Uint16*)keystream; prng.seed(serverKey); for (Uint32 i = 0; i < 260; ++i) { stream[i] = prng.getNextE(); } } return true; } void SS_ENCR::encrypt(char *msg, Uint32 len) { if (!key) return; Uint32 ksi = 0, i = 1, IV = key; if (*msg == 0) { if (len <= 2) return; ++i; } while (i + 4 <= len) { *(Uint32*)&msg[i] = IV = (getLong(msg, i) ^ getLong(keystream, ksi) ^ IV); i += 4; ksi += 4; } Uint32 diff = len - i; if (diff) { Uint32 buffer = 0; memcpy(&buffer, msg + i, diff); buffer ^= getLong(keystream, ksi) ^ IV; memcpy(msg + i, &buffer, diff); } } void SS_ENCR::decrypt(char *msg, Uint32 len) { if (!key) return; Uint32 ksi = 0, i = 1, IV = key, EDX; if (*msg == 0) { if (len <= 2) return; ++i; } while (i + 4 <= len) { EDX = getLong(msg, i); *(Uint32*)&msg[i] = getLong(keystream, ksi) ^ IV ^ EDX; IV = EDX; i += 4; ksi += 4; } Uint32 diff = len - i; if (diff) { Uint32 buffer = 0; memcpy(&buffer, msg + i, diff); buffer ^= getLong(keystream, ksi) ^ IV; memcpy(msg + i, &buffer, diff); } } void SS_ENCR::reset() { key = 0; sentKey = 0; } //////// Billing password encryption //////// // Also from Coconut Emulator void hashP!@#$%^&*word(BYTE *in, BYTE *out) { Uint32 StrLen = STRLEN((char*)in); BYTE Factor = simpleChecksum(in, StrLen); BYTE Char; for (Uint32 L = 0; L < StrLen; ++L) { Char = in[L] ^ Factor; Factor = (Factor ^ (Char << (Char & 3))) & 255; if (Char == 0) Char = 0xED; out[L] = Char; } out[L] = 0; } //////// Billing password decryption //////// void inverseHash(BYTE *In, BYTE *Out, BYTE Key) { size_t StrLen = STRLEN((char*)In); for (Uint32 L = 0; L < StrLen; ++L) { BYTE Char = In[L]; if (Char == 0xED) Char = 0; Out[L] = Char ^ (BYTE)Key; Key = (Key ^ (Char << (Char & 3))) & 255; } } void decryptHashedP!@#$%^&*word(BYTE *password) { Uint32 StrLen = STRLEN((char*)password); BYTE *Buffer = new BYTE[StrLen + 1]; Buffer[StrLen] = 0; // passwords of EVEN length are very easy to crack. if (StrLen & 1) { // Guess and check to find one of the solutions for (int i = 0; i < 256; ++i) { // Generate a possible solution inverseHash(password, Buffer, i); // Compare resultant hash with given hash BYTE Char, Key = i; bool OK = true; for (Uint32 L = 0; L < StrLen; ++L) { Char = Buffer[L]; if (!isPrintable(Char)) { OK = false; break; } Char ^= Key; Key = (Key ^ (Char << (Char & 3))) & 255; if (Char == 0) Char = 0xED; if (Char != password[L]) { OK = false; break; } } if (OK) break; } } else { // Generate password checksum inverseHash(password, Buffer, 0); // Generate actual password inverseHash(password, Buffer, simpleChecksum(Buffer, StrLen)); } memcpy(password, Buffer, StrLen); delete Buffer; Buffer = NULL; } make what you want of it...
Miesco Posted August 22, 2004 Author Report Posted August 22, 2004 I think I already got the encryption this is what I got (in perl): sub initialize { my $seed = $_[0]; my ($tempSeed, $oldSeed); $tempSeed = $seed; for ($i = 0; $i < (520 / 2); $i++) { $oldSeed = $tempSeed; $tempSeed = (($oldSeed * 0x834E0B5F) >> 48) & 0xffffffff; $tempSeed = (($tempSeed + ($tempSeed >> 31)) & 0xffffffff); $tempSeed = (((($oldSeed % 0x1F31D) * 16807) - ($tempSeed * 2836) + 123) & 0xffffffff); if ($tempSeed > 0x7fffffff ) { $tempSeed = (($tempSeed + 0x7fffffff) & 0xffffffff); } $table[$i .. ($i+1)] = ence_short(short(tempSeed & 0xffff)); }} sub ssencrypt { my @packet = @_; my ($tempKey, $count, @output); $tempKey = $serverKey; #$count = scalar(@packet) + (4 - scalar(@packet) % 4); $count = scalar(@packet); @output = @packet; for ($i = 0; $i < $count; $i += 4) { $tempInt = dece_int(@output[$i .. ($i+3)]) ^ dece_int($table[$i]) ^ $tempKey; $tempKey = $tempInt; @output[$i .. ($i+3)] = ence_int(int($tempInt & 0xffffffff)); } return @output;} sub ssdecrypt { my @packet = @_; my ($tempKey, $count, @output); $tempKey = $serverKey; #$count = scalar(@packet) + (4 - scalar(@packet) % 4); $count = scalar(@packet); @output = @packet; for ($i = 0; $i < $count; $i += 4) { $tempInt = dece_int($table[$i]) ^ $tempKey ^ dece_int(@output[$i .. ($i+3)]); $tempKey = dece_int($i .. ($i+3)); @output[$i .. ($i+3)] = ence_int(int($tempInt & 0xffffffff)); } return @output;}
catid Posted August 31, 2004 Report Posted August 31, 2004 The subspace encryption has not been broken by anyone (yet). I doubt if it ever will. Thus no one will be able to explain you the encryption. (Also because it kept secret to avoid people making their own client and cheat) -MMaverickSubSpace encryption is broken in every sense of the word. There's some code on my website that can decrypt password packets without the key, which would be useful if you were using one of the old buffer stealing exploits.
Recommended Posts