Page 1 of 1

Authentication Issues

Posted: 05 May 2011, 05:28
by pR0Ps
I'm writing an ADC bot in Delphi and I'm having a few issues with authenticated logins.

I'm generating the Tiger hash with the Delphi Encryption Compendium (a well-respected cryptographic suit for Delphi) so I'm reasonably confident that the hashing algorithm isn't the problem.

I've written BinToBase32 and Base32ToBin functions which convert between UTF-8 and Base32 string encodings. They also add 0's to the end of the binary representation of the string if the length of it is not divisible by 5 (for BinToBase32) or 8 (for Base32ToBin) to make it encode properly . Once again, I'm reasonably sure the 2 functions work properly as I can convert a string back and forth with no difference to the original (except letters on the end due to the padding). I can provide the source for them if needed.

When hashing the password and random data I use the following function:

Code: Select all

function HashADCPassword(key : string; pass : UTF8String): string;
begin
  Result := BinToBase32(THash_Tiger.CalcBinary(pass + Base32ToBin(key), TFormat_Copy));
end;
Where 'THash_Tiger.CalcBinary' is the hashing function and 'TFormat_Copy' is the output format (meaning copy the binary data with no formatting).

As far as I understand the ADC spec, this is the proper way of computing the hash to send back to the hubsoft.

However, with another client I recorded this with a password of 'none':

Code: Select all

[Incoming] IGPA PDCQPYQG75AQFJBA4BD5QIYY2FTTQRVBAFG5BOTURPZ3Z4JNRIAA
[Outgoing] HPAS 4EJM7GAJGMSKQZVUSHPGYAQ53HNNZGLVJN5SDNQ
When I replicate this scenario (using the data the other client was given) with my program I get a final hash of

Code: Select all

CP4POWXTLRIKQYFCXWG2FY56ECS3COSPCZNDGVI
which is obviously wrong.

I'm probably doing something really small wrong, but I've been stewing over it for a few days now and getting nowhere so I figured I'd ask for help.

PS: I'm not sure if this is the right place for this, feel free to move it if it isn't.

Re: Authentication Issues

Posted: 05 May 2011, 07:54
by andyhhp
2 possibilities:

1) which hub/client are you testing against? I had a problem exactly like this when doing the authentication and it turned out that the other half was using a botched implementation. I would suggest starting with hash(PID) == CID as at this point, the only thing which could go wrong is the hash.

The other option is to run the tiger hash test suite http://www.cs.technion.ac.il/~biham/Rep ... format.dat, which might actually be a better starting point. Please note that for test vector 6, you need to expand the ..'s - the message = "foo" is sadly not literally foo, despite its implications.

There are two tiger hash functions - Tiger and Tiger2. They differer only in how they pad the input stream up to the required block size. However, this results in vastly different hashes. See http://en.wikipedia.org/wiki/Tiger_hash for a comparison.

Hope this gives you a starting point

~Andrew

Re: Authentication Issues

Posted: 05 May 2011, 19:40
by pR0Ps
I should have mentioned that I was testing against ADCH++ v2.7.0 (r488) Release and the data was captured from ApexDC++ v1.4.3. The login by that client was successful and I'm testing my program against the same hub.

I also just ran the hashing algorithm against that test suite and it passed with flying colours. It correctly hashed all of the large sampling of values I threw at it. It's definitely not the hashing function that's the problem.

My UTF-8 -> Base32 conversions don't add in the '=' for padding the final result up to a multiple of 8 characters. EX:

Code: Select all

BintoBase32 ('A') produces 'IE', not 'IE======'
ADC doesn't use these though so it shouldn't matter, correct?

I tried with a simple CID/PID pair that I know is working but...

Code: Select all

CID = D2MTCFRCZLUJA7TLZDU2MJAYPWS2JZHNNZX5FUA
PID = V2U7PQKHZXJ4M5QWNIO6SEB4NKN4CDHT6M2V4EA
BinToBase32(THash_Tiger.CalcBinary(Base32ToBin('PID'), TFormat_Copy)) => 'VYV5AS63PRAQZDUFVQYZ2XNFZBLM6DYV6DVPHXY'
Is this code

Code: Select all

function HashADCPassword(key : string; pass : UTF8String): string;
begin
  Result := BinToBase32(THash_Tiger.CalcBinary(pass + Base32ToBin(key), TFormat_Copy));
end;
the correct way of encoding the input and output of the hashing function? If the hashing function is right, as well as the Base32 <-> UTF8 conversions, that seems like the only point there could be a bug.

Re: Authentication Issues

Posted: 05 May 2011, 21:18
by andyhhp
ADC doesn't use these though so it shouldn't matter, correct?
This is a point of contention. The spec states base32 which requires the padding to resolve ambiguity, but the spec BNF excludes the padding. All DC++ based clients are happy with either, but Jucy is specifically not - it failes if you provide the padding. I know this from implementing my hub.

There is talk to make the spec more strict, because at the moment there are ambiguities which have the potential to cause problems. Nothing has happened so far though.

As for the PID/CID pair, dont you mean:

Code: Select all

BinToBase32(THash_Tiger.CalcBinary(Base32ToBin(PID), TFormat_Copy))
instead of

Code: Select all

BinToBase32(THash_Tiger.CalcBinary(Base32ToBin('PID'), TFormat_Copy))
?

It would make a significant difference.

As for the authentication, what exactly does the + operator do when given a LHS of UTF8String and a rhs of binary string? Chances are that it is playing funny buggers with the btyes with high bits set.

Re: Authentication Issues

Posted: 09 May 2011, 14:13
by pR0Ps
andyhhp wrote:Dont you mean:

Code: Select all

BinToBase32(THash_Tiger.CalcBinary(Base32ToBin(PID), TFormat_Copy))
instead of

Code: Select all

BinToBase32(THash_Tiger.CalcBinary(Base32ToBin('PID'), TFormat_Copy))
?
Yes, I didn't copy-paste the code, I quickly typed up an example with my hash results and forgot to remove the quotes. Yes, that would probably mess something up :lol:
andyhhp wrote: What exactly does the + operator do when given a LHS of UTF8String and a rhs of binary string? Chances are that it is playing funny buggers with the btyes with high bits set.
I'm now converting each of the strings to a string of its binary representation, adding those strings together, converting it to a UTF8String, THEN hashing it. I get the same result.

It has to be something with the way I encode/decode the 8-bit strings. My entire encoding unit is at this link if anyone wants to take a look.

http://dl.dropbox.com/u/1430741/StrEncode.pas

Re: Authentication Issues

Posted: 09 May 2011, 19:54
by Pretorian
Generate random data and store it in PID_raw, then;
PID = Base32( PID_raw )
CID = Base32( Hash( PID_raw ) )

For GPA/PAS, assuming that '12345' is the random data supplied in GPA, then;
PAS = Base32( Hash( password + '12345' ) )

Re: Authentication Issues

Posted: 31 May 2011, 06:33
by pR0Ps
I found the solution.

The problem was when the Base32 encoded string (5 bits per character) was converted to an unencoded string (8 bits per character) there was a discrepancy. The Base32-encoded string to hash was 39 characters long. At 5 bits per character, that gives it a total of 195 bits. 195 bits divided into 8 bit characters gives 24 characters, plus 3 extra bits. In my original implementation, I added 0's on the end of the binary representation to complete the last character, rather than discarding them.

When I started trying to hash the unencoded string (essentially just plain bytes of data), those extra 0's that got passed into the hashing function messed with it, giving me the wrong answer.

As soon as I started chopping off the extra bits instead of padding them with 0's, everything started working beautifully.


EDIT: The link to the source code in the above post is now invalid, but the source code for the entire project is available on the Sourceforge project page (the issue is fixed as of Alpha 5)