Quote// I don't really like this function being here, but I can't think of anywhere else it might belong :-/
private void checkServerSignature(byte []sig, byte []ip) throws IOException
{
// The constants
BigIntegerEx key = new BigIntegerEx(BigIntegerEx.LITTLE_ENDIAN, new byte[] { 0x01, 0x00, 0x01, 0x00 });
BigIntegerEx mod = new BigIntegerEx(BigIntegerEx.LITTLE_ENDIAN, new byte[]
{
(byte) 0xD5, (byte) 0xA3, (byte) 0xD6, (byte) 0xAB, (byte) 0x0F, (byte) 0x0D, (byte) 0xC5, (byte) 0x0F, (byte) 0xC3, (byte) 0xFA, (byte) 0x6E, (byte) 0x78, (byte) 0x9D, (byte) 0x0B, (byte) 0xE3, (byte) 0x32,
(byte) 0xB0, (byte) 0xFA, (byte) 0x20, (byte) 0xE8, (byte) 0x42, (byte) 0x19, (byte) 0xB4, (byte) 0xA1, (byte) 0x3A, (byte) 0x3B, (byte) 0xCD, (byte) 0x0E, (byte) 0x8F, (byte) 0xB5, (byte) 0x56, (byte) 0xB5,
(byte) 0xDC, (byte) 0xE5, (byte) 0xC1, (byte) 0xFC, (byte) 0x2D, (byte) 0xBA, (byte) 0x56, (byte) 0x35, (byte) 0x29, (byte) 0x0F, (byte) 0x48, (byte) 0x0B, (byte) 0x15, (byte) 0x5A, (byte) 0x39, (byte) 0xFC,
(byte) 0x88, (byte) 0x07, (byte) 0x43, (byte) 0x9E, (byte) 0xCB, (byte) 0xF3, (byte) 0xB8, (byte) 0x73, (byte) 0xC9, (byte) 0xE1, (byte) 0x77, (byte) 0xD5, (byte) 0xA1, (byte) 0x06, (byte) 0xA6, (byte) 0x20,
(byte) 0xD0, (byte) 0x82, (byte) 0xC5, (byte) 0x2D, (byte) 0x4D, (byte) 0xD3, (byte) 0x25, (byte) 0xF4, (byte) 0xFD, (byte) 0x26, (byte) 0xFC, (byte) 0xE4, (byte) 0xC2, (byte) 0x00, (byte) 0xDD, (byte) 0x98,
(byte) 0x2A, (byte) 0xF4, (byte) 0x3D, (byte) 0x5E, (byte) 0x08, (byte) 0x8A, (byte) 0xD3, (byte) 0x20, (byte) 0x41, (byte) 0x84, (byte) 0x32, (byte) 0x69, (byte) 0x8E, (byte) 0x8A, (byte) 0x34, (byte) 0x76,
(byte) 0xEA, (byte) 0x16, (byte) 0x8E, (byte) 0x66, (byte) 0x40, (byte) 0xD9, (byte) 0x32, (byte) 0xB0, (byte) 0x2D, (byte) 0xF5, (byte) 0xBD, (byte) 0xE7, (byte) 0x57, (byte) 0x51, (byte) 0x78, (byte) 0x96,
(byte) 0xC2, (byte) 0xED, (byte) 0x40, (byte) 0x41, (byte) 0xCC, (byte) 0x54, (byte) 0x9D, (byte) 0xFD, (byte) 0xB6, (byte) 0x8D, (byte) 0xC2, (byte) 0xBA, (byte) 0x7F, (byte) 0x69, (byte) 0x8D, (byte) 0xCF
});
// Do the calculation
byte []result = new BigIntegerEx(BigIntegerEx.LITTLE_ENDIAN, sig).modPow(key, mod).toByteArray();
// Create the array of the correct result
byte []correctResult = new byte[result.length];
// Put the ip into the array
correctResult[0] = ip[0];
correctResult[1] = ip[1];
correctResult[2] = ip[2];
correctResult[3] = ip[3];
// Pad the result with 0xBB's
for(int i = 4; i < correctResult.length; i++)
correctResult = (byte) 0xBB;
for(int i = 0; i < result.length; i++)
if(result != correctResult)
throw new IOException("Error! Server failed validation check!");
}
Quote from: Punk on May 25, 2009, 04:26:29 PM
I talked this over with brew and we came to the conclusion that the signature is generated by the servers ipaddress in conjuction with powmod.
I talked this over with brew and we came to the conclusion that the signature is generated by the servers ipaddress in conjuction with powmod.
Quote from: iago on May 26, 2009, 12:10:01 PMthe easy answer is, it's impossible. :)Tut-tut, iago! It's impossible just because the public key is 1024 bits? Brute forcing the key would be trivial! Never mind how many lifetimes it would take...
Quote from: Camel on May 26, 2009, 02:06:32 PMNot anymore. Original versions of War3 worked fine if you just didn't include the check (or maybe if you 00'ed it out, I forget now). But they fixed that loophole.Quote from: iago on May 26, 2009, 12:10:01 PMthe easy answer is, it's impossible. :)Tut-tut, iago! It's impossible just because the public key is 1024 bits? Brute forcing the key would be trivial! Never mind how many lifetimes it would take...
[edit] Out of curiosity, does the official client allow any way to bypass this check?
Quote from: Camel on May 26, 2009, 09:22:46 PM
bool verifyItIsBlizzard() {
return YES_IT_IS;
}
Quote from: Punk on May 26, 2009, 06:58:48 PM
Brew gave me a good idea. What if you temporarily changed the subroutine that verifies the address to always return a pos value then change it back after 0x51?
Quote from: Camel on May 26, 2009, 09:22:46 PM
bool verifyItIsBlizzard() {
return YES_IT_IS;
}
Quote from: iago on May 26, 2009, 12:10:01 PM
Aha, I just noticed that you asked how to generate the signature, not how to verify it -- the easy answer is, it's impossible. :)
The long answer is, you have to hack Blizzard or something if you want it.
Quote from: Joe on May 29, 2009, 05:00:47 AMneh?Quote from: iago on May 26, 2009, 12:10:01 PM
Aha, I just noticed that you asked how to generate the signature, not how to verify it -- the easy answer is, it's impossible. :)
The long answer is, you have to hack Blizzard or something if you want it.
Well, it's 128 characters. That means that there's only 255^128 different possibilities. It shouldn't take more than a fewhoursdecades to generate the one for your IP.
And since it's mod, I think there may be more than one correct number.
Quote from: Joe on May 29, 2009, 05:00:47 AMNo. Just no.
Well, it's 128 characters. That means that there's only 10^128 different possibilities. It shouldn't take more than a few hours to generate the one for your IP.
And since it's mod, I think there may be more than one correct number.
Quote8^128 / 2GHz in years = 6.2430045 × 1098 years
Quote from: sdfg on May 29, 2009, 04:54:24 PMNo, I don't think the birthday attack applies here, since you can't get them to encrypt arbitrary plaintext. Or something. :)
Correct me if i'm wrong, but using the birthday attack principle couldn't you get that down to 8^64?
Quote from: iago on May 25, 2009, 04:42:43 PM
You can find an implementation somewhere on my wiki or, if nothing else, in JavaOp2. :)
<edit>Quote// I don't really like this function being here, but I can't think of anywhere else it might belong :-/
private void checkServerSignature(byte []sig, byte []ip) throws IOException
{
// The constants
BigIntegerEx key = new BigIntegerEx(BigIntegerEx.LITTLE_ENDIAN, new byte[] { 0x01, 0x00, 0x01, 0x00 });
BigIntegerEx mod = new BigIntegerEx(BigIntegerEx.LITTLE_ENDIAN, new byte[]
{
(byte) 0xD5, (byte) 0xA3, (byte) 0xD6, (byte) 0xAB, (byte) 0x0F, (byte) 0x0D, (byte) 0xC5, (byte) 0x0F, (byte) 0xC3, (byte) 0xFA, (byte) 0x6E, (byte) 0x78, (byte) 0x9D, (byte) 0x0B, (byte) 0xE3, (byte) 0x32,
(byte) 0xB0, (byte) 0xFA, (byte) 0x20, (byte) 0xE8, (byte) 0x42, (byte) 0x19, (byte) 0xB4, (byte) 0xA1, (byte) 0x3A, (byte) 0x3B, (byte) 0xCD, (byte) 0x0E, (byte) 0x8F, (byte) 0xB5, (byte) 0x56, (byte) 0xB5,
(byte) 0xDC, (byte) 0xE5, (byte) 0xC1, (byte) 0xFC, (byte) 0x2D, (byte) 0xBA, (byte) 0x56, (byte) 0x35, (byte) 0x29, (byte) 0x0F, (byte) 0x48, (byte) 0x0B, (byte) 0x15, (byte) 0x5A, (byte) 0x39, (byte) 0xFC,
(byte) 0x88, (byte) 0x07, (byte) 0x43, (byte) 0x9E, (byte) 0xCB, (byte) 0xF3, (byte) 0xB8, (byte) 0x73, (byte) 0xC9, (byte) 0xE1, (byte) 0x77, (byte) 0xD5, (byte) 0xA1, (byte) 0x06, (byte) 0xA6, (byte) 0x20,
(byte) 0xD0, (byte) 0x82, (byte) 0xC5, (byte) 0x2D, (byte) 0x4D, (byte) 0xD3, (byte) 0x25, (byte) 0xF4, (byte) 0xFD, (byte) 0x26, (byte) 0xFC, (byte) 0xE4, (byte) 0xC2, (byte) 0x00, (byte) 0xDD, (byte) 0x98,
(byte) 0x2A, (byte) 0xF4, (byte) 0x3D, (byte) 0x5E, (byte) 0x08, (byte) 0x8A, (byte) 0xD3, (byte) 0x20, (byte) 0x41, (byte) 0x84, (byte) 0x32, (byte) 0x69, (byte) 0x8E, (byte) 0x8A, (byte) 0x34, (byte) 0x76,
(byte) 0xEA, (byte) 0x16, (byte) 0x8E, (byte) 0x66, (byte) 0x40, (byte) 0xD9, (byte) 0x32, (byte) 0xB0, (byte) 0x2D, (byte) 0xF5, (byte) 0xBD, (byte) 0xE7, (byte) 0x57, (byte) 0x51, (byte) 0x78, (byte) 0x96,
(byte) 0xC2, (byte) 0xED, (byte) 0x40, (byte) 0x41, (byte) 0xCC, (byte) 0x54, (byte) 0x9D, (byte) 0xFD, (byte) 0xB6, (byte) 0x8D, (byte) 0xC2, (byte) 0xBA, (byte) 0x7F, (byte) 0x69, (byte) 0x8D, (byte) 0xCF
});
// Do the calculation
byte []result = new BigIntegerEx(BigIntegerEx.LITTLE_ENDIAN, sig).modPow(key, mod).toByteArray();
for(int i = 0; i < 4; i++)
if(result[i] != ip[i])
throw new IOException("Error! Server failed validation check!");
for(int i = 4; i < result.length; i++)
if(result[i] != (byte) 0xBB)
throw new IOException("Error! Server failed validation check!");
}
Think you can figure it out from there?
Quote from: sdfg on May 29, 2009, 04:54:24 PMThe birthday attack principle is based on the idea that hashing sqrt(hash strength) variations of each of two different inputs will (probably) result in a hash collision. A classic example is getting a digital signature on an evil message by requesting a signature on sqrt(strength) variants of an innocent message, and then testing each of those signatures for collision with sqrt(strength) variants of an evil message.
Correct me if i'm wrong, but using the birthday attack principle couldn't you get that down to 8^64?
Quote from: iago on May 29, 2009, 05:32:59 PMThe reason iago gave is sufficient to preclude the possibility of performing a birthday attack, but there's an even better reason: what the client expects to see is that the hash itself matches the IP address, not the message. The very nature of the birthday attack is finding hashing collisions, but the hash is invariant.
I don't think the birthday attack applies here, since you can't get them to encrypt arbitrary plaintext. Or something. :)