2014년 8월 2일 토요일
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
===================
- # from 'https://t.line.naver.jp/authct/v1/keys/line'
- {
- "session_key":"jvhk3Vl3A1KJ8nK0",
- "rsa_key":
- "1696, # key name
- DBAE063DBDC04244CD0D6669AC6545CD0E7337C1E6ABC74E4C939D3958AADB2EF5B51013D46C0BFD1C9AFFEAA72F771DA4D450347606EFBD082625920202EF848204E783456F59AD953EA3E5872A38CF6415C97B818DB6AD2C6C9AF84676DFFB358EA41F08A4B81D8F3A653F7D68C449F5650B5894323D0B3C0A1A12FEB9E6EBBDEB6F69B2AA1136741D3ACC504048AFAEBDB52C034F, # e
- 010001" # n
- }
- # personal information
- string password = String.fromCharCode (session_key.length) + session_key
- + String.fromCharCode (email.length) + email
- + String.fromCharCode (password.length) + password;
- # generate encrypted password
- var rsa = new RSAKey ();
- rsa.setPublic (evalue, nvalue);
- password = rsa.encrypt (password);
- # send POST request to http://gd2.line.naver.jp/rest/v1/login
- {
- id : keyname // In this case, '1696'
- password : password // encrypted password
- persistent : 0 //
- provider : 1 //
- }
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
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- namespace ConsoleApplication1
- {
- class Program
- {
- static void Main(string[] args)
- {
- String issuedTo = "1" ;
- DateTime l = DateTime .UtcNow;
- long timestamp = (long )((l - new DateTime(1970, 1, 1, 0, 0, 0, 1)).TotalMilliseconds);
- String authToken = "????"; // auth_key
- string[] strArray = authToken.Split(new char[] { ':' });
- string issueTo = strArray[0];
- string encodedSecretKey = strArray[1];
- string str2 = string .Format("iat: {1}\n", issuedTo, timestamp);
- string str3 = Convert .ToBase64String(Encoding.UTF8.GetBytes(str2));
- string str4 = string .Empty;
- string str5 = str3 + "." + str4;
- byte[] key = Convert .FromBase64String(str3);
- string str6 = Convert.ToBase64String(LINE.Service.YamlWebToken .HmacAlgorithm.CreateInstance(LINE.Service.YamlWebToken.DEFAULT_ALOGORITHM.Name, key).ComputeHash(Encoding.UTF8.GetBytes(str5)));
- String str = str5 + "." + str6; // base64(issuedTo) + '..' + Hmac(SecretKey)
- }
- }
- }
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.
- public void UpdateAuthToken(string authKey)
- {
- if (authKey != null)
- {
- this._transport.AddRequestHeader("X-Line-Access", AccessTokenHelper.GetAccessToken(authKey)); // add "X-Line-Access" header to HTTP(s) protocol
- }
- }
- public void UpdateAuthToken(string authKey)
- {
- try
- {
- if (authKey != null)
- {
- this._transport.AddRequestHeader("X-Line-Access", AccessTokenHelper.GetAccessToken(authKey)); // add "X-Line-Access" header to HTTP(s) protocol
- }
- }
- catch (Exception)
- {
- }
- }
- private void _addCustomHeader(HttpWebRequest httpWebRequest)
- {
- Profile current = ProfileViewModel.GetInstance().Current;
- httpWebRequest.get_Headers().set_Item("X-Line-Access", AccessTokenHelper.GetAccessToken(current.AuthKey)); // add "X-Line-Access" header to HTTP(s) protocol
- httpWebRequest.get_Headers().set_Item("X-Line-Application", DeviceUtility.GetLineApplicationString());
- httpWebRequest.get_Headers().set_Item("Cache-Control", "no-cache");
- httpWebRequest.get_Headers().set_Item("Pragma", "no-cache");
- }
- public static string GetAccessToken(string authKey)
- {
- long timestamp = (DateTime.get_UtcNow() - new DateTime(0x7b2, 1, 1, 0, 0, 0, 1)).get_TotalMilliseconds(); // use time stamp for making access token
- return GetAccessToken(timestamp, authKey);
- }
- public static string GetAccessToken(long timestamp, string authKey)
- {
- if (((_accessToken == "") || !_accessToken.Equals(_lastAuthToken)) || (timestamp > (_lastUpdated + 0x5265c00L)))
- {
- lock (_thisLock)
- {
- _accessToken = Generate(authKey, timestamp);
- _lastUpdated = timestamp;
- _lastAuthToken = authKey;
- }
- }
- return _accessToken;
- }
- public static string Generate(string authToken, long timestamp)
- {
- string[] strArray = authToken.Split(new char[] { ':' });
- if (strArray.Length != 2)
- {
- throw new ArgumentException("authToken");
- }
- string issueTo = strArray[0]; // use previous authToken for the new authToken
- string encodedSecretKey = strArray[1]; // use previous authToken for the new authToken
- string str3 = YamlWebToken.Create(issueTo, timestamp, encodedSecretKey);
- return (issueTo + ":" + str3);
- }
- public class YamlWebToken
- {
- // Fields
- public static HmacAlgorithm DEFAULT_ALOGORITHM; // use Hmac algorith for generating token
- // Methods
- static YamlWebToken();
- public YamlWebToken();
- public static string Create(string issueTo, long timestamp, string encodedSecretKey);
- public static string Create(string issuedTo, long timestamp, string encodedSecretKey, HmacAlgorithm algorithm);
- // Nested Types
- public class HmacAlgorithm
- {
- // Methods
- public HmacAlgorithm(string name);
- public static HMAC CreateInstance(string name, byte[] key);
- // Properties
- public string Name { get; set; }
- }
- }
- public static string Create(string issueTo, long timestamp, string encodedSecretKey)
- {
- return Create(issueTo, timestamp, encodedSecretKey, DEFAULT_ALOGORITHM);
- }
- public static string Create(string issuedTo, long timestamp, string encodedSecretKey, HmacAlgorithm algorithm)
- {
- string str = "";
- try
- {
// core algorithm to make new session key - string str2 = string.Format("iat: {1}\n", issuedTo, timestamp);
- string str3 = Convert.ToBase64String(Encoding.get_UTF8().GetBytes(str2));
- string str4 = string.Empty;
- string str5 = str3 + "." + str4;
- byte[] key = Convert.FromBase64String(encodedSecretKey);
- string str6 = Convert.ToBase64String(HmacAlgorithm.CreateInstance(algorithm.Name, key).ComputeHash(Encoding.get_UTF8().GetBytes(str5)));
- str = str5 + "." + str6; // base64(issuedTo) + '..' + Hmac(SecretKey)
- }
- catch (Exception)
- {
- }
- return str;
- }
Anyway, I wrote an C# code that make updated session key...
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- namespace ConsoleApplication1
- {
- class Program
- {
- static void Main(string[] args)
- {
- String issuedTo = "1" ;
- DateTime l = DateTime .UtcNow;
- long timestamp = (long )((l - new DateTime(1970, 1, 1, 0, 0, 0, 1)).TotalMilliseconds);
- String authToken = "????" // your old session key
- string[] strArray = authToken.Split(new char[] { ':' });
- string issueTo = strArray[0];
- string encodedSecretKey = strArray[1];
- string str2 = string .Format("iat: {1}\n", issuedTo, timestamp);
- string str3 = Convert .ToBase64String(Encoding.UTF8.GetBytes(str2));
- string str4 = string .Empty;
- string str5 = str3 + "." + str4;
- byte[] key = Convert .FromBase64String(encodedSecretKey);
- string str6 = Convert.ToBase64String(LINE.Service.YamlWebToken .HmacAlgorithm.CreateInstance(LINE.Service.YamlWebToken.DEFAULT_ALOGORITHM.Name, key).ComputeHash(Encoding.UTF8.GetBytes(str5)));
- String str = str5 + "." + str6; // base64(issuedTo) + '..' + Hmac(SecretKey)
- }
- }
- }
피드 구독하기:
글 (Atom)