Yahoo's YMSG Protocol v16

This is my findings on version 16 of Yahoo's YMSG protocol.

Servers

cs101.msg.sp1.yahoo.com - cs130.msg.sp1.yahoo.com
cs101.msg.ac4.yahoo.com - cs130.msg.ac4.yahoo.com

Rekkanoryo says connect to http://vcs1.msg.yahoo.com/capacity (http://cs1.msg.vip.ogk.yahoo.co.jp/capacity for Yahoo Japan) and use the IP address specified as CS_IP_ADDRESS for our server.

Login

First we send the usual empty packet type 4C just to tell the server we are about to login

Next we send packet type 57 which only contains field type 1 containing our username

Yahoo's reply to this is packet type 57 which contains the following fields

  1  - Our username
  13 - Something to do with our status. Should be set to 2 in this reply
  94 - The challenge string
We then take the challenge string and use it to retrieve this url
  https://login.yahoo.com/config/pwtoken_get?src=ymsgr&ts=&login=USERNAME&passwd=PASSWORD&chal=CHALLENGESTRING
The reply to this will depend on if we have the correct information or not. The first line of the response will always be an integer indicating various things.
If the integer is 0 then the information we have supplied is correct.
100  - if username or password is missing.
1013 - username contains @yahoo.com or similar which needs removing.
1212 - is the username or password is incorrect.
1213 - is a security lock from to many failed login attempts
1214 - is a security lock
1218 - if the account has been deactivated by Yahoo
1235 - if the username does not exist.
1236 - locked due to to many login attempts
Seems to work just as well without the challenge string though.
Anyway if the username and password is correct the second line of the reply will be our token as such
  ymsgr=OURTOKEN
It has a third line as well but this serves no purpose to us.

Once we have our token we use it to retrieve this url
  https://login.yahoo.com/config/pwtoken_login?src=ymsgr&ts=&token=OURTOKEN
Again the first line of the reply is an intger to indicate the status with 0 being good and 100 meaning something is wrong.
Line 2 is our crumb as
  crumb=OURCRUMB
The next two lines contain our Y= cookie and T= cookie respectively. The last line is the life of the cookie.

Now we return back to normal YMSG

First we need to get a hash using the crumb and the challenge string. It just uses the standard Yahoo Base64 variation.
  Function for hashing the crumb

    Public Function ProcessAuth16(ByVal Crumb As String, ByVal Challenge As String)
        Dim Crypt As String = String.Join(String.Empty, New String() {Crumb, Challenge})
        Dim Hash As Byte() = HashAlgorithm.Create("MD5").ComputeHash(Encoding.[Default].GetBytes(Crypt))
        Dim Auth As String = Convert.ToBase64String(Hash).Replace("+", ".").Replace("/", "_").Replace("=", "-")
        Return Auth.ToString
    End Function
Here is the function as used in Pidgin
  /* This is the y64 alphabet... it's like base64, but has a . and a _ */
  static const char base64digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._";
  
  /* This is taken from Sylpheed by Hiroyuki Yamamoto.  We have our own tobase64 function
   * in util.c, but it has a bug I don't feel like finding right now ;) */
  static void to_y64(char *out, const unsigned char *in, gsize inlen)
  /* raw bytes in quasi-big-endian order to base 64 string (NUL-terminated) */
  {
    for (; inlen >= 3; inlen -= 3)
      {
        *out++ = base64digits[in[0] >> 2];
        *out++ = base64digits[((in[0] << 4) & 0x30) | (in[1] >> 4)];
        *out++ = base64digits[((in[1] << 2) & 0x3c) | (in[2] >> 6)];
        *out++ = base64digits[in[2] & 0x3f];
        in += 3;
      }
    if (inlen > 0)
      {
        unsigned char fragment;
  
        *out++ = base64digits[in[0] >> 2];
        fragment = (in[0] << 4) & 0x30;
        if (inlen > 1)
          fragment |= in[1] >> 4;
        *out++ = base64digits[fragment];
        *out++ = (inlen < 2) ? '-' : base64digits[(in[1] << 2) & 0x3c];
        *out++ = '-';
      }
    *out = '\0';
  }
We now send packet type 54 to our server with the following fields:
  1   - username
  0   - username
  277 - The Y cookie not including the Y= part
  278 - The T cookie not including the T= part
  307 - Our hash created using the Y64 function
  244 - Rekkanoryo says this is internal build number. I just use 2097087
  2   - username
  2   - Not sure why we use 2 again but this one just contains the character 1
  98  - Country but best just use us
  135 - Messenger version number. Currently I use 9.0.0.1389
And that's it. We have successfully logged in using YMSG version 16.