2013년 9월 21일 토요일

LINE(라인) protocol analysis [4] : Registration


* 2014.08.02 update *

If you need a python code right away, then please keep in touch with https://github.com/carpedm20/LINE



* This post is composed of a collection of data that I got from the analysis of LINE registration
* I will beautify this post, later...


* There are two kinds of registration, one is for mobile phone and the other for tablet

* 1. For mobile phone : use SMS registration
* 2. For tablet : login with e-mail and password authentication

Links
====

https://gd2.line.naver.jp/authct/v1/keys/naver
http://t.line.naver.jp/authct/v1/keys # not working

# t stands for tablet ( maybe..? )
# t.line.naver.jp/authct is used when 'RegisterWithNaverIdOrEmailPageVM.SetIdentityCredential()' is called

https://t.line.naver.jp/authct/v1/keys/naver
https://t.line.naver.jp/authct/v1/keys/line



Wireshark Filter
============

ip.addr == 119.235.235.0/24 

.Net Reflector
===========



1. Tablet authentication
===================


  1. # from 'https://t.line.naver.jp/authct/v1/keys/line'
  2. {
  3.   "session_key":"jvhk3Vl3A1KJ8nK0",
  4.   "rsa_key":
  5.     "1696, # key name
  6.    DBAE063DBDC04244CD0D6669AC6545CD0E7337C1E6ABC74E4C939D3958AADB2EF5B51013D46C0BFD1C9AFFEAA72F771DA4D450347606EFBD082625920202EF848204E783456F59AD953EA3E5872A38CF6415C97B818DB6AD2C6C9AF84676DFFB358EA41F08A4B81D8F3A653F7D68C449F5650B5894323D0B3C0A1A12FEB9E6EBBDEB6F69B2AA1136741D3ACC504048AFAEBDB52C034F, # e
  7.    010001" # n
  8. }
  9. # personal information
  10. string password = String.fromCharCode (session_key.length) + session_key  
  11.                 + String.fromCharCode (email.length) + email  
  12.                 + String.fromCharCode (password.length) + password;  
  13. # generate encrypted password
  14. var rsa =  new  RSAKey ();  
  15. rsa.setPublic (evalue, nvalue);  
  16. password = rsa.encrypt (password);  
  17. # send POST request to http://gd2.line.naver.jp/rest/v1/login
  18. {
  19.   id : keyname  // In this case, '1696'
  20.   password : password  // encrypted password
  21.   persistent : 0  //  
  22.   provider : 1  //
  23. }

2. Mobile registration
=================

1. gm.line.naver.jp/api/v3/TalkService.do

   # request : [startverification] country_code + phone_number + druid + device_name + ???
   # response: auth_key(?)

2. gm.line.naver.jp/api/v3/TalkService.do

   # request : [verifyphone] auth_key + druid
   # response: verifyphone


3. gm.line.naver.jp/api/v3/TalkService.do

   # request : [registerDevice] auth_key
   # response : encrypted_key -> this is used to make X-Line-Access ( by using bellow C# code)



  # This code will make X-Line-Access key from auth_key

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. namespace ConsoleApplication1
  6. {
  7.    
  8.     class Program
  9.     {
  10.         static void Main(string[] args)
  11.         {
  12.             String issuedTo = "1" ;
  13.             DateTime l = DateTime .UtcNow;
  14.             long timestamp = (long )((- new DateTime(1970110001)).TotalMilliseconds);
  15.             String authToken = "????"; // auth_key
  16.             string[] strArray = authToken.Split(new char[] { ':' });
  17.             string issueTo = strArray[0];
  18.             string encodedSecretKey = strArray[1];
  19.             string str2 = string .Format("iat: {1}\n", issuedTo, timestamp);
  20.             string str3 = Convert .ToBase64String(Encoding.UTF8.GetBytes(str2));
  21.             string str4 = string .Empty;
  22.             string str5 = str3 + "." + str4;
  23.             byte[] key = Convert .FromBase64String(str3);
  24.             string str6 = Convert.ToBase64String(LINE.Service.YamlWebToken .HmacAlgorithm.CreateInstance(LINE.Service.YamlWebToken.DEFAULT_ALOGORITHM.Name, key).ComputeHash(Encoding.UTF8.GetBytes(str5)));
  25.             String str = str5 + "." + str6 // base64(issuedTo) + '..' + Hmac(SecretKey)
  26.         }
  27.     }
  28. }



In my view point, the analysis of LINE protocol was much easier than LOCO protocol which uses their own protocol.

Now, what...? :)

2013년 9월 12일 목요일

LINE(라인) protocol analysis [3] : session key


* 2014.08.02 update *

If you need a python code right away, then please keep in touch with https://github.com/carpedm20/LINE



Finally, I want to talk about session key  and auth key.


5. Session key

At first, I tried to follow UpdateAuthToken() function because this function adds the "X-Line-Access" header to the HTTP protocol.

As I followed this function, I finally arrived to create() function which updates the old session key.

It wasn't hard to understand how this function updates authKey, but I couldn't figure out when LINE change an auth key.

It seems like LINE's session key is changed when a user change his/her mobile phone or re-install the application.

In other words, the session key won't be changed if you don't erase or change your mobile phone.

This can cause security problems if someone change the code of LINE application and distribute it to the internet...but I don't think it will happen :)

Bellow is the list of functions that I followed to find out how LINE update their authorization key.

  1. public void UpdateAuthToken(string authKey)
  2. {
  3.     if (authKey != null)
  4.     {
  5.         this._transport.AddRequestHeader("X-Line-Access", AccessTokenHelper.GetAccessToken(authKey)); // add "X-Line-Access" header to HTTP(s) protocol
  6.     }
  7. }
  8. public void UpdateAuthToken(string authKey)
  9. {
  10.     try
  11.     {
  12.         if (authKey != null)
  13.         {
  14.             this._transport.AddRequestHeader("X-Line-Access", AccessTokenHelper.GetAccessToken(authKey)); // add "X-Line-Access" header to HTTP(s) protocol
  15.         }
  16.     }
  17.     catch (Exception)
  18.     {
  19.     }
  20. }

  21. private void _addCustomHeader(HttpWebRequest httpWebRequest)
  22. {
  23.     Profile current = ProfileViewModel.GetInstance().Current;
  24.     httpWebRequest.get_Headers().set_Item("X-Line-Access", AccessTokenHelper.GetAccessToken(current.AuthKey)); // add "X-Line-Access" header to HTTP(s) protocol
  25.     httpWebRequest.get_Headers().set_Item("X-Line-Application", DeviceUtility.GetLineApplicationString());
  26.     httpWebRequest.get_Headers().set_Item("Cache-Control""no-cache");
  27.     httpWebRequest.get_Headers().set_Item("Pragma""no-cache");
  28. }
  29. public static string GetAccessToken(string authKey)
  30. {
  31.     long timestamp = (DateTime.get_UtcNow() - new DateTime(0x7b2, 110001)).get_TotalMilliseconds(); // use time stamp for making access token
  32.     return GetAccessToken(timestamp, authKey);
  33. }
  34. public static string GetAccessToken(long timestamp, string authKey)
  35. {
  36.     if (((_accessToken == "") || !_accessToken.Equals(_lastAuthToken)) || (timestamp > (_lastUpdated + 0x5265c00L)))
  37.     {
  38.         lock (_thisLock)
  39.         {
  40.             _accessToken = Generate(authKey, timestamp);
  41.             _lastUpdated = timestamp;
  42.             _lastAuthToken = authKey;
  43.         }
  44.     }
  45.     return _accessToken;
  46. }
  47. public static string Generate(string authToken, long timestamp)
  48. {
  49.     string[] strArray = authToken.Split(new char[] { ':' });
  50.     if (strArray.Length != 2)
  51.     {
  52.         throw new ArgumentException("authToken");
  53.     }
  54.     string issueTo = strArray[0]; // use previous authToken for the new authToken
  55.     string encodedSecretKey = strArray[1]// use previous authToken for the new authToken
  56.     string str3 = YamlWebToken.Create(issueTo, timestamp, encodedSecretKey);
  57.     return (issueTo + ":" + str3);
  58. }
  59. public class YamlWebToken
  60. {
  61.     // Fields
  62.     public static HmacAlgorithm DEFAULT_ALOGORITHM; // use Hmac algorith for generating token
  63.     // Methods
  64.     static YamlWebToken();
  65.     public YamlWebToken();
  66.     public static string Create(string issueTo, long timestamp, string encodedSecretKey);
  67.     public static string Create(string issuedTo, long timestamp, string encodedSecretKey, HmacAlgorithm algorithm);
  68.     // Nested Types
  69.     public class HmacAlgorithm
  70.     {
  71.         // Methods
  72.         public HmacAlgorithm(string name);
  73.         public static HMAC CreateInstance(string name, byte[] key);
  74.         // Properties
  75.         public string Name { get; set; }
  76.     }
  77. }
  78. public static string Create(string issueTo, long timestamp, string encodedSecretKey)
  79. {
  80.     return Create(issueTo, timestamp, encodedSecretKey, DEFAULT_ALOGORITHM);
  81. }
  82. public static string Create(string issuedTo, long timestamp, string encodedSecretKey, HmacAlgorithm algorithm)
  83. {
  84.     string str = "";
  85.     try
  86.     {
            // core algorithm to make new session key
  87.         string str2 = string.Format("iat: {1}\n", issuedTo, timestamp)
  88.         string str3 = Convert.ToBase64String(Encoding.get_UTF8().GetBytes(str2));
  89.         string str4 = string.Empty;
  90.         string str5 = str3 + "." + str4;
  91.         byte[] key = Convert.FromBase64String(encodedSecretKey);
  92.         string str6 = Convert.ToBase64String(HmacAlgorithm.CreateInstance(algorithm.Name, key).ComputeHash(Encoding.get_UTF8().GetBytes(str5)));
  93.         str = str5 + "." + str6; // base64(issuedTo) + '..' + Hmac(SecretKey)
  94.     }
  95.     catch (Exception)
  96.     {
  97.     }
  98.     return str;
  99. }

Anyway, I wrote an C# code that make updated session key... 

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. namespace ConsoleApplication1
  6. {
  7.    
  8.     class Program
  9.     {
  10.         static void Main(string[] args)
  11.         {
  12.             String issuedTo = "1" ;
  13.             DateTime l = DateTime .UtcNow;
  14.             long timestamp = (long )((- new DateTime(1970110001)).TotalMilliseconds);
  15.             String authToken = "????" // your old session key
  16.             string[] strArray = authToken.Split(new char[] { ':' });
  17.             string issueTo = strArray[0];
  18.             string encodedSecretKey = strArray[1];
  19.             string str2 = string .Format("iat: {1}\n", issuedTo, timestamp);
  20.             string str3 = Convert .ToBase64String(Encoding.UTF8.GetBytes(str2));
  21.             string str4 = string .Empty;
  22.             string str5 = str3 + "." + str4;
  23.             byte[] key = Convert .FromBase64String(encodedSecretKey);
  24.             string str6 = Convert.ToBase64String(LINE.Service.YamlWebToken .HmacAlgorithm.CreateInstance(LINE.Service.YamlWebToken.DEFAULT_ALOGORITHM.Name, key).ComputeHash(Encoding.UTF8.GetBytes(str5)));
  25.             String str = str5 + "." + str6 // base64(issuedTo) + '..' + Hmac(SecretKey)
  26.         }
  27.     }
  28. }