Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HAFAS mobile API 1.16: find out how the mic & mac parameters work #187

Closed
derhuerst opened this issue Jan 8, 2018 · 36 comments
Closed

HAFAS mobile API 1.16: find out how the mic & mac parameters work #187

derhuerst opened this issue Jan 8, 2018 · 36 comments

Comments

@derhuerst
Copy link

derhuerst commented Jan 8, 2018

[this is a cross-post from public-transport/hafas-client#3]

The VBB endpoint now has a 1.16 API version, which provides more detailed responses. Also, older versions might be shut off in the future.

There are to query parameters mic & mac though, which seem to be necessary to get data. I haven't figured out how they work. It might be similar to the way Deutsche Bahn does it.

Maybe someone from the community of this project knows what they are and how they work?

@alexander-albers
Copy link
Contributor

I came across the same issue a few weeks ago: mic = MD5(requestString), mac = MD5(mic + salt). Same as with the checksum parameter, both md5 hashes need to be in hex representation.
I hope that helps. :)

@derhuerst
Copy link
Author

derhuerst commented Jan 13, 2018

But what is the value for salt? Does someone know? 😉

@alexander-albers
Copy link
Contributor

Yeah, that's a little trickier. ;)

First, you need to find the HCI_CHECKSUM, usually located in haf_config_base.properties. Then, you need to "decrypt" the checksum as done here: https://pastebin.com/4RAmgbF8. The result can be then used as the hash value. :)

@derhuerst
Copy link
Author

derhuerst commented Jan 14, 2018

thanks for you help! i don't have all puzzle pieces together though.

  • Is the encrypted checksum (HCI_CHECKSUM) stored in the config file as base64 or plain text? It looks a lot like base64.
  • I haven't found out what the PKCS5Padding part of the cipher exactly means and how to implement it in other languages.
  • Did you mean that the decrypted checksum can be used as a salt?

@alexander-albers
Copy link
Contributor

  • Correct, the checksum is stored as base64.
  • You only need to decrypt the checksum once. You can run the Java snippet (which also decodes the base64 hci) and just use the result in your preferred language.
  • Yes, the decrypted checksum is what I referred to as salt and can be used for the mac parameter.

@derhuerst
Copy link
Author

derhuerst commented Jan 14, 2018

@derhuerst
Copy link
Author

derhuerst commented Jan 14, 2018

@alexander-albers On last request. In order to reduce the number of error sources, could you give me an example encrypted checksum/salt pair that I can verify against?

I've found this encrypted checksum for Deutsche Bahn: rGhXPq+xAlvJd8T8cMnojdD0IoaOY53X7DPAbcXYe5g=.

I have the following salt as the result: a0a18e5cdced2d697afe46aef5097ec269ce1ab8e73e1effbf769e866ef71ebc.

@alexander-albers
Copy link
Contributor

alexander-albers commented Jan 14, 2018

The encrypted checksum is correct, but the salt would be bdI8UVj40K5fvxwf (same as in your mentioned GitHub project).

System.out.println(decrypt("rGhXPq+xAlvJd8T8cMnojdD0IoaOY53X7DPAbcXYe5g=".getBytes(StandardCharsets.UTF_8)));

@derhuerst
Copy link
Author

Finally got it working.

derhuerst added a commit to public-transport/hafas-client that referenced this issue Jan 15, 2018
@schildbach
Copy link
Owner

@alexander-albers Thanks for this valuable info.

@derhuerst Do you plan to submit a PR for Hafas 1.16 support? It would be a nice feature to have!

@derhuerst
Copy link
Author

derhuerst commented Jan 22, 2018

@schildbach I don't think I'm proficient enough in Java. I haven't implemented the 1.16 protocol in my JS client yet, but once I did, I may either submit a PR or at least provide all the knowledge I have.

@derhuerst
Copy link
Author

@alexander-albers I need your help again.

I extracted the encrypted checksum jvKrxmixHfD58eaNuQU4xcRWamPNQ/VYKfr2STdKvHA= from the VBB Android app. With my tool based on your code, I decrypted the following salt:

5243544a4d3266467846667878516649 – hex
RCTJM2fFxFfxxQfI – utf8

A recorded request from the latest VBB Android app:

POST /bin/mgate.exe?mac=f1de7eace70370b8613359f9dc2b81bc&mic=b5d1f2fd4c9de9764e04f93c135af4b1 HTTP/1.1
User-Agent: Dalvik/2.1.0 (Linux; U; Android 5.1; SHIFT5.1 Build/LMY47I)
Content-Type: application/json;charset=UTF-8
Host: fahrinfo.vbb.de
Connection: Keep-Alive
Accept-Encoding: gzip
Content-Length: 376

{"auth":{"aid":"hafas-vbb-apps","type":"AID"},"client":{"id":"VBB","name":"Bus & Bahn ","os":"Android 5.1","res":"720x1216","type":"AND","ua":"Dalvik/2.1.0 (Linux; U; Android 5.1; SHIFT5.1 Build/LMY47I)","v":1000029},"ext":"VBB.1","formatted":false,"lang":"deu","svcReqL":[{"cfg":{"polyEnc":"GPA"},"meth":"JourneyDetails","req":{"jid":"1|28233|20|86|21022018"}}],"ver":"1.16"}

I calculated the mic correctly (b5d1f2fd4c9de9764e04f93c135af4b1 ), but the mac doesn't match (I got 3edc9c3b1a166c983de78668d403fc2b).

I assume the key for decrypting the salt is different for VBB apps. Or did I miss something?

@alexander-albers
Copy link
Contributor

Hi! The key seems correct to me. How did you calculate the mac parameter? You need to perform md5(md5(requestString) + salt). Both md5 functions need to return a hex value, and the salt needs to be in utf8 representation.

@derhuerst
Copy link
Author

Node crypto doesn't work with strings, but with binary data directly. Therefore it doesn't matter if I had specified the salt as hex or utf8 before. My code works with the example we discussed before.

@derhuerst
Copy link
Author

What's you mac result, given the encrypted salt and request string above?

@alexander-albers
Copy link
Contributor

I’m not sure how strings work in Node, but in Java it does make a difference when you concartenate two utf strings instead of two hex strings. Try to convert the first result to a hex string first and combine that one with the hex representation of your salt. Then, you can encode the resulting string to binary again and use if for the second md5 function.

@derhuerst
Copy link
Author

Would you mind trying to reproduce this with Java? If you don't get the correct mac either, the salt must be wrong.

@derhuerst
Copy link
Author

@alexander-albers ping (:

@alexander-albers
Copy link
Contributor

Did you try to concartenate both hex strings before applying the md5 function?

@derhuerst
Copy link
Author

As I said, in Node there's no difference between Buffer.from(str1 + str2, 'utf8') and Buffer.concat([Buffer.from(str1, 'utf8'), Buffer.from(str2, 'utf8')]).

@alexander-albers
Copy link
Contributor

I get that, but are you using the hex representation of both the md5-encoded request string and the salt?

@derhuerst
Copy link
Author

derhuerst commented Mar 2, 2018

No, I use the binary representation for hashing:

const md5 = buf => require('crypto').createHash('md5').update(buf).digest()

const req = Buffer.from('{"auth":{"aid":"hafas-vbb-apps","type":"AID"},"client":{"id":"VBB","name":"Bus & Bahn ","os":"Android 5.1","res":"720x1216","type":"AND","ua":"Dalvik/2.1.0 (Linux; U; Android 5.1; SHIFT5.1 Build/LMY47I)","v":1000029},"ext":"VBB.1","formatted":false,"lang":"deu","svcReqL":[{"cfg":{"polyEnc":"GPA"},"meth":"JourneyDetails","req":{"jid":"1|28233|20|86|21022018"}}],"ver":"1.16"}', 'utf8')

const mic = md5(req)
mic.toString('hex') // b5d1f2fd4c9de9764e04f93c135af4b1, matches!

const salt = Buffer.from('5243544a4d3266467846667878516649', 'hex') // decrypted using your code
const mac = md5(Buffer.concat([mic, salt]))
mac.toString('hex') // 3edc9c3b1a166c983de78668d403fc2b, does not match!

@alexander-albers
Copy link
Contributor

Try the following:
const mac = md5(Buffer.concat([Buffer.from(mic.toString('hex'), 'utf8'), salt]))

@derhuerst
Copy link
Author

Thanks again! I really didn't expect that they would process the MIC differently than the salt. Reading your comments, I thought you were confused about the way of handling crypto in Node.

@guitar9
Copy link

guitar9 commented May 20, 2018

hi i have another question. I have looked the requests of the Deutsche Bahn app. I am stucked where to get the array with station informations. There is a checksum. Sombody knows how to calculate the checksum? I want to do this calculation in javascript. But if somebody knows how to calculate it in java it would be nice.
This are example request i tried out.

aaaa = af9343ee2b5d0df1bb1c41cc94cb7639
aaab = f041d6c597cd4a8df7e10534fdc00f66
aaac = 6f3f57478e37bd7e6d2e7c2af284162f
aaad = 734a5c3794a160fdc3e9c9d441c9dae3
....
bbbbb = 8ec957faad401f5fe01c1d129646ad2e

image

@derhuerst
Copy link
Author

@guitar9

Sombody knows how to calculate the checksum?

See above. I've implemented this here:

https://github.com/public-transport/hafas-client/blob/48f2cefb5b2b65a5f84f5c499835c3315ab67322/p/db/index.js#L134-L135

https://github.com/public-transport/hafas-client/blob/ef42edbfd7d8384c153b0bf712235eca4eae44c7/lib/request.js#L32-L38

But if somebody knows how to calculate it in java it would be nice.

See above as well.

@schildbach
Copy link
Owner

I just implemented the checksum parameter: #209

Does anyone know an mgate.exe that needs the checksum (not the mic/mac) except the DB?

@schildbach
Copy link
Owner

I also implemented mic/mac and merged. See c410fcd and 9fbd1f1.

@schildbach
Copy link
Owner

schildbach commented Jan 5, 2019

@derhuerst In your tool above, where does the key 61483646387a527569426e6d33336655 come from?

@schildbach
Copy link
Owner

Likewise, @alexander-albers where did you get the key 97, 72, 54, 70, 56, 122, 82, 117, 105, 66, 110, 109, 51, 51, 102, 85 in your pastebin from?

@alexander-albers
Copy link
Contributor

@schildbach the key is hardcoded into every app.

@schildbach
Copy link
Owner

@alexander-albers Right, but where? Everything we're talking about here is hardcoded into the app, but the key doesn't appear in /res/raw/haf_config_base.properties.

@alexander-albers
Copy link
Contributor

@schildbach No, the key is actually hardcoded, it is in the Java-code of the Android app. :P

@schildbach
Copy link
Owner

FWIW:

grep -RFl "<title[^>]*>(.*?)</title>"
grep -F -A17 ".array-data" <file>

@derhuerst
Copy link
Author

The key for the encrypted salt from haf_config_base.properties is hard-coded as a byte array in the Java code.

@derhuerst derhuerst reopened this Jan 5, 2019
@derhuerst
Copy link
Author

Will elaborate on this later, after my vacation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants