summaryrefslogtreecommitdiff
path: root/protocols/MSN
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/MSN')
-rw-r--r--protocols/MSN/msn.vcxproj8
-rw-r--r--protocols/MSN/src/msn_auth.cpp133
-rw-r--r--protocols/MSN/src/skylogin/README.md2
-rw-r--r--protocols/MSN/src/skylogin/common.c92
-rw-r--r--protocols/MSN/src/skylogin/common.h128
-rw-r--r--protocols/MSN/src/skylogin/crc.c113
-rw-r--r--protocols/MSN/src/skylogin/crc.h6
-rw-r--r--protocols/MSN/src/skylogin/credentials.c163
-rw-r--r--protocols/MSN/src/skylogin/credentials.h3
-rw-r--r--protocols/MSN/src/skylogin/login.c414
-rw-r--r--protocols/MSN/src/skylogin/login.h2
-rw-r--r--protocols/MSN/src/skylogin/objects.c252
-rw-r--r--protocols/MSN/src/skylogin/objects.h136
-rw-r--r--protocols/MSN/src/skylogin/platform.h6
-rw-r--r--protocols/MSN/src/skylogin/platform_w32.c195
-rw-r--r--protocols/MSN/src/skylogin/random.c178
-rw-r--r--protocols/MSN/src/skylogin/random.h7
-rw-r--r--protocols/MSN/src/skylogin/rc4comm.c83
-rw-r--r--protocols/MSN/src/skylogin/rc4comm.h3
-rw-r--r--protocols/MSN/src/skylogin/skylogin.c165
-rw-r--r--protocols/MSN/src/skylogin/skylogin.h57
-rw-r--r--protocols/MSN/src/skylogin/uic.c105
-rw-r--r--protocols/MSN/src/skylogin/uic.h3
23 files changed, 2161 insertions, 93 deletions
diff --git a/protocols/MSN/msn.vcxproj b/protocols/MSN/msn.vcxproj
index 87e7feff21..603d726bdc 100644
--- a/protocols/MSN/msn.vcxproj
+++ b/protocols/MSN/msn.vcxproj
@@ -29,5 +29,13 @@
<ClCompile>
<ExceptionHandling>Sync</ExceptionHandling>
</ClCompile>
+ <Link>
+ <AdditionalDependencies>libeay32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
</ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="src\skylogin\*.c">
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ </ClCompile>
+ </ItemGroup>
</Project>
diff --git a/protocols/MSN/src/msn_auth.cpp b/protocols/MSN/src/msn_auth.cpp
index e1c4b1713f..3e05906b30 100644
--- a/protocols/MSN/src/msn_auth.cpp
+++ b/protocols/MSN/src/msn_auth.cpp
@@ -24,6 +24,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "msn_ieembed.h"
#include "des.h"
+extern "C"
+{
+ #include "skylogin\skylogin.h"
+};
+
#define LOGIN_POST_PARAMS "client_id=00000000480BC46C&scope=service%3A%3Askype.com%3A%3AMBI_SSL&response_type=token&redirect_uri=https%3A%2F%2Flogin.live.com%2Foauth20_desktop.srf"
#define AUTH_URL "https://login.live.com/oauth20_authorize.srf?"LOGIN_POST_PARAMS
#define POST_URL "https://login.live.com/ppsecure/post.srf?"LOGIN_POST_PARAMS
@@ -33,18 +38,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
typedef BOOL (*pfnInternetGetCookieExA)(LPCSTR, LPCSTR, LPSTR, LPDWORD, DWORD, LPVOID);
pfnInternetGetCookieExA fpInternetGetCookieExA = NULL;
-
-/* SkyLogin Prototypes */
-typedef void* SkyLogin;
-typedef SkyLogin (*pfnSkyLogin_Init)();
-typedef void (*pfnSkyLogin_Exit)(SkyLogin pInst);
-typedef int (*pfnSkyLogin_LoadCredentials)(SkyLogin pInst, char *pszUser);
-typedef int (*pfnSkyLogin_PerformLogin)(SkyLogin pInst, char *pszUser, char *pszPass);
-typedef int (*pfnSkyLogin_CreateUICString)(SkyLogin pInst, const char *pszNonce, char *pszOutUIC);
-typedef int (*pfnSkyLogin_PerformLoginOAuth)(SkyLogin pInst, const char *OAuth);
-typedef int (*pfnSkyLogin_GetCredentialsUIC)(SkyLogin pInst, char *pszOutUIC);
-typedef char *(*pfnSkyLogin_GetUser)(SkyLogin pInst);
-
#define LOAD_FN(name) (##name = (pfn##name)GetProcAddress(hLibSkylogin, #name))
static const char defaultPassportUrl[] = "https://login.live.com/RST2.srf";
@@ -661,48 +654,25 @@ CMStringA CMsnProto::HotmailLogin(const char* url)
int CMsnProto::MSN_SkypeAuth(const char *pszNonce, char *pszUIC)
{
int iRet = -1;
- pfnSkyLogin_Init SkyLogin_Init;
- pfnSkyLogin_Exit SkyLogin_Exit;
- pfnSkyLogin_LoadCredentials SkyLogin_LoadCredentials;
- pfnSkyLogin_PerformLogin SkyLogin_PerformLogin;
- pfnSkyLogin_CreateUICString SkyLogin_CreateUICString;
-
- HMODULE hLibSkylogin = LoadLibrary(_T("Plugins\\skylogin.dll"));
- if (hLibSkylogin) {
-
- // load function pointers
- if (!LOAD_FN(SkyLogin_Init) ||
- !LOAD_FN(SkyLogin_Exit) ||
- !LOAD_FN(SkyLogin_LoadCredentials) ||
- !LOAD_FN(SkyLogin_PerformLogin) ||
- !LOAD_FN(SkyLogin_CreateUICString))
- {
- FreeLibrary(hLibSkylogin);
- return -2;
- }
- // Perform login
- SkyLogin hLogin = SkyLogin_Init();
- if (hLogin) {
- char szPassword[100];
- if (!db_get_static(NULL, m_szModuleName, "Password", szPassword, sizeof(szPassword))) {
- if (SkyLogin_LoadCredentials(hLogin, MyOptions.szEmail) ||
- SkyLogin_PerformLogin(hLogin, MyOptions.szEmail, szPassword))
- {
- if (SkyLogin_CreateUICString(hLogin, pszNonce, pszUIC))
- iRet = 1;
- }
- else
- iRet = 0;
- SkyLogin_Exit(hLogin);
+ // Perform login
+ SkyLogin hLogin = SkyLogin_Init();
+ if (hLogin) {
+ iRet = 0;
+
+ char szPassword[100];
+ if (!db_get_static(NULL, m_szModuleName, "Password", szPassword, sizeof(szPassword))) {
+ if (SkyLogin_LoadCredentials(hLogin, MyOptions.szEmail) ||
+ SkyLogin_PerformLogin(hLogin, MyOptions.szEmail, szPassword))
+ {
+ if (SkyLogin_CreateUICString(hLogin, pszNonce, pszUIC))
+ iRet = 1;
}
- else
- iRet = 0;
+
+ SkyLogin_Exit(hLogin);
}
- else
- iRet = -3;
- FreeLibrary(hLibSkylogin);
}
+
return iRet;
}
@@ -715,52 +685,29 @@ int CMsnProto::MSN_SkypeAuth(const char *pszNonce, char *pszUIC)
int CMsnProto::LoginSkypeOAuth(const char *pRefreshToken)
{
int iRet = -1;
- pfnSkyLogin_Init SkyLogin_Init;
- pfnSkyLogin_Exit SkyLogin_Exit;
- pfnSkyLogin_LoadCredentials SkyLogin_LoadCredentials;
- pfnSkyLogin_PerformLoginOAuth SkyLogin_PerformLoginOAuth;
- pfnSkyLogin_GetCredentialsUIC SkyLogin_GetCredentialsUIC;
- pfnSkyLogin_GetUser SkyLogin_GetUser;
-
- HMODULE hLibSkylogin = LoadLibrary(_T("Plugins\\skylogin.dll"));
- if (hLibSkylogin) {
- // load function pointers
- if (!LOAD_FN(SkyLogin_Init) ||
- !LOAD_FN(SkyLogin_Exit) ||
- !LOAD_FN(SkyLogin_LoadCredentials) ||
- !LOAD_FN(SkyLogin_PerformLoginOAuth) ||
- !LOAD_FN(SkyLogin_GetCredentialsUIC) ||
- !LOAD_FN(SkyLogin_GetUser))
- {
- FreeLibrary(hLibSkylogin);
- return -2;
- }
- // Perform login
- SkyLogin hLogin = SkyLogin_Init();
- if (hLogin) {
- char szLoginToken[1024];
- if (RefreshOAuth(pRefreshToken, "service::login.skype.com::MBI_SSL", szLoginToken) &&
- SkyLogin_PerformLoginOAuth(hLogin, szLoginToken))
- {
- char szUIC[1024];
- if (SkyLogin_GetCredentialsUIC(hLogin, szUIC)) {
- char *pszPartner;
-
- replaceStr(authUIC, szUIC);
- iRet = 1;
- if (pszPartner = SkyLogin_GetUser(hLogin))
- setString("SkypePartner", pszPartner);
- }
+ // Perform login
+ SkyLogin hLogin = SkyLogin_Init();
+ if (hLogin) {
+ char szLoginToken[1024];
+ if (RefreshOAuth(pRefreshToken, "service::login.skype.com::MBI_SSL", szLoginToken) &&
+ SkyLogin_PerformLoginOAuth(hLogin, szLoginToken))
+ {
+ char szUIC[1024];
+ if (SkyLogin_GetCredentialsUIC(hLogin, szUIC)) {
+ char *pszPartner;
+
+ replaceStr(authUIC, szUIC);
+ iRet = 1;
+ if (pszPartner = SkyLogin_GetUser(hLogin))
+ setString("SkypePartner", pszPartner);
}
- else
- iRet = 0;
- SkyLogin_Exit(hLogin);
- }
+ }
else
- iRet = -3;
- FreeLibrary(hLibSkylogin);
- }
+ iRet = 0;
+ SkyLogin_Exit(hLogin);
+ }
+
return iRet;
}
diff --git a/protocols/MSN/src/skylogin/README.md b/protocols/MSN/src/skylogin/README.md
new file mode 100644
index 0000000000..2139b870d7
--- /dev/null
+++ b/protocols/MSN/src/skylogin/README.md
@@ -0,0 +1,2 @@
+# skylogin
+C Code to login to Skype for UIC generation needed for msnp24
diff --git a/protocols/MSN/src/skylogin/common.c b/protocols/MSN/src/skylogin/common.c
new file mode 100644
index 0000000000..4aa14956e8
--- /dev/null
+++ b/protocols/MSN/src/skylogin/common.c
@@ -0,0 +1,92 @@
+/*
+ * Skype Login
+ *
+ * Based on:
+ * FakeSkype : Skype reverse engineering proof-of-concept client
+ * Ouanilo MEDEGAN (c) 2006 http://www.oklabs.net
+ * pyskype : Skype login Python script by uunicorn
+ *
+ * Written by: leecher@dose.0wnz.at (c) 2015
+ *
+ * Module: Common stuff, especially Skype Modulus
+ *
+ */
+#include "common.h"
+
+char *SkypeModulus1536[] = {"c095de9e868dc9fe1de94ab5e38e8dbdcae7e6249ef147de503f3e1c76e65af06f7714872f3527ee16410170196e4b2277db206827505bc48b4b63159f8eb0d56d14de686e5f6840e32522f8b7dafc6b901b83495757f4269b59440bc7824d4543eae2b00b9d4d21b0b056ae53d6cc6c3a35a5b10e72710cad00db5a42903e277e361cd1761a074afe997cc4a2c77427854ea1176da481cadb981ee145711c7160c5b31f5194f64ec919bf57dc544656f39bad7bbdacb6e46f22c30173df2ea7",
+ "a8f223612f4f5fc81ef1ca5e310b0b21532a72df6c1af0fbec87304aec983aab5d74a14cc72e53ef7752a248c0e5abe09484b597692015e796350989c88b3cae140ca82ccd9914e540468cf0edb35dcba4c352890e7a9eafac550b3978627651ad0a804f385ef5f4093ac6ee66b23e1f8202c61c6c0375eeb713852397ced2e199492aa61a3eab163d4c2625c873e95cafd95b80dd2d8732c8e25638a2007acfa6c8f1ff31cc2bc4ca8f4446f51da404335a48c955aaa3a4b57250d7ba29700b",
+ "aa4bc22ba5b925573c48bf886efad103a37d697283a3d37b8bf5a3eb2d09a9ae73e6905fcb3c6af06e4170b7a1856c70eab972cd3a468a28d7a87ceaad2404126dd5843f8895a0cfd9b07085afe60b8ae391a703479846d800737ab02fca5ead5673f416d5fb4a95e1d27bb4b7ca5411e74e98623f563b1d3709d749b3ee6d87242a8da04f39fd61ea679acc8e28601dadcc4434918dc544cd365f7b897600b3fb62875f4517ae32601764ae8d28b924074e47ebc2bcaaa42d9d8feb82137787",
+ NULL
+ };
+
+char *SkypeModulus2048[] = {"b8506aeed8ed30fe1c0e6774874b59206a77329042a49be2403da47d50052441067f87bcd57e6579b83df0bade2beff5b5cd8d87e8b3edac5f57fabccd49695974e2b5e5f0287d6c19ecc31b4504a9f8be25da78fa4ef345f91d339b73cc2d70b3904e11ca570ce9b5dc4b08b3c44b74dc463587ea637ef4456e61462b72042fc2f4ad5510a9850c06dc9a7374412fcadda955bd9800f9754cb3b8cc62d0e98d8282180971055b457c06f351e61164fc5a9de9d83d1d1378964001380b5b99ee4c5c7d50ac2462a4b7ea34fd32d90bd8d4b46410263673f900d1c60470165df9f3cb48016ab8ca45ce6875a71d977915ca8251b50258748dbc37fe332edc2855",
+ "bfe2db4bdf48358d3ae7c7d260989e4c7c1d81e6d9bd62e3a34dcaaa55f16c8c976a8862bc2462ae1b4063fd3d0de97e8aee5b793e171e22136319ff3474667c47ed1c14a892a19644005401cef46b5a8bd9510b3c8eeff80755decd2932cdca9119d96c5e16f6603b24ccc062822ca250336915a77aeab693268e1e22b1209d22f65a54cf7bcc7a4f9677eab54df8c33b16755ce1cf907efae988df8a4b4fad0591d95617189cd5ae0ef0935b2b458d72c7cc3de19a6268af4b06a8ce324292ca01b6a3adf7d133101a1e6659b03e0a1e14f07f8a11f5ec945c1a6f1eff06e75764262749acd6c3bf59503d970b038f77018cb09eb924fc2045db9b3248d6d5",
+ "9f2a6038e8132c3545bc7c5fbe56903e08e83353b1defe7042b5c8457ba5a40254b2812a843be54993dafed5fa55a415be652e2ff533483a1ab3907c5603df47a59311973c2b4c39cf942a58f12149ce0437b341aa58add6dc2ab27800f1f529975506c10925e5254ff0766ed276b194d36c783a7d426672e32e7d6881c91e167ccbb38f4f9ee703d621712b7de384c6c97fe5cf557c839d47ebf1c45db2ec554b4aebf203d00896e9b202e564251f6fc623f6810208ffd1497c4de673d87d693febc17ec5157aa5aa8a0055976fd4817b6ccef76d4525741820d72ef89c2558971189c5e42cdeb271590f6bb0e2bede43a28003f54298be689a39791ec8a919",
+ "bf137933ab269e3bacbea76da16f6ff06748028e79efe20aa696368fc88f6abca4571790f3d67ea4b6f382850f8f27a2ee4c044be541083d74ecbb30142070a7bc2746ff01fb243c4ec2a5fba296c3fb9c357429b4d511741bd2bf97034d29fe4fbd9013df87b725941e9696635fd53caf2f56b7b3609c51b8448256c4fb6078dde89f06d54c8bb4e2f6fbfb6ee42e698649e32e74dc542c94c2be3f9833ef22f988f9aa9c4fa5267b8aaf455ef06c693a36ca4447763e865086070713328e2f835649e1a15d78eaa6f90f9b5a6fac3f2eb3e24979bdacc4843956ef44c186f5007278c7d6cc1ceaefd8c56121ffa39c8d75873ae5a853b7cd1002885b49b209",
+ "d7edafe450023e3a4b0f7f1925196943ce1defd4d158cc868a29973bbedb9b90d203331b01c9752f254d7c922f8b5bdba2d25bd5955b887f26532afda73e37527f1265925ddbb6f1ed5efd660b1cad6ecb94628e1c90311a320db1a758ec36e3df926df48ebc1c099714dfe5e7541eec3ce96dd7d6f8b55288c081646c51a6b77f5c1ef1025b7862ee9d5e7d491293471ae7159daa40ccd7db2753071c11264aa5cc861d5fedc8fed6f2503b0a68a17d78cdfe3f698bd8af21ac1152f2dcef7c515bd9c9e4934cd9c9977ade4c77fbcd184111332f2737847b5ee713b6568d55c14618ae1e4ce088431709d9ad8fae987887ac829c3f7968bee8d1cfd347e341",
+ "d52af9c4194936e76ca66fd276533926d073b261c8de4cba4ea8f758dcce63e1c391220085ac94492926fde61ac0ca4b7b1acdd90a4d601b242cd2f890d8f826ab0c269bf1d23f497f2c236f1f57c01b881b88616eab2aa2028d533bb449b579063fcd287fba64ab0d64f4c1f38845d22017be45b7942348b494b1dd73982719be5ee37384b9feb41473e8bf71c8c4edab7a486907879e6a797baa2d7d9462fc24a7ad6a00598646064beb19f27513bee559f0316a398eaa5d5e618a41fc0d16ee1c6cf17e84bf7571227fe98a29d205c0ffd5546bed9f87e22e49ebee6d58e908e268d258d7520589f2b730d72639bb751ac4fb4d39125bb5b205bacfb423df",
+ "a4deafb40a982a87c989fe919b888dfe185113b17106b3241e7d166177b322b790131ddebae8d878bd8ae7e2e39794cab70988778cb13d121528e260eedabb3df35a320a02b7e68b63d4cd143d0ef93ab565d2163e467b77ae4644e9850e922fcdc61c58020e236a70557188e8ff2c332ff9e4f3d984042a2c802917ba9bcdf9277b4de3bf7055423bcac61332f2983d3fd9074dcb610e4c8d751bb38d4c20b470a8314d44790462e62c3b45a77cc290aab52b0a237fccd7513b5e8fd50ec4e79dac5047191417ffd68ebfa023f275a0fff93531cdda7b6287d34e41e89227c2942b6aeca11956fdb566f65be7f1c456b1b07b731cb78698b08478f5e7c856cb",
+ "a903c6079aac211634af60c85955889da69a552a2e994ef9395a53fc258c78c6308961d7bf3e87dd85ebb55087ffa151433514901e5b8e79458209864e82d839de8793002e15528d979a4b853a47a7d74e463ebdc321827308559c68a81f6de72660625f577ac42fc0addd31ad8697155de21d977bd9874ce65a6232cad0c08a21b9a2a3d4d14923115ff0d9b5f09e645f4d3a6c45ca1838a8f7a519b2d82fd82282678260d934bc8d42314ac6c703189ad734b2e9c8d285a50447fda2d01bd26452e63ce290ca1f88b1237abdd942372a384902ab3495a37bfd68c45d46008d134984f06f9114d411bd560fe48ec3a16a3f4ff0127ca52928f3261ddbb76b9d",
+ "b4792d7289d6aaba727b338d6ed91f7fa34f9d9abca23795bff72f7f38f4c27b416149489891c2b615d0b5db19a09d6462d26ee12526f93f4bd129655ecc890727f8a6ec71c17a82b02f68afe8dab6e40620236753784d4a279159dc613b2eebc1bbf9fa65b8ca1d13ded28ea575c591738772369ca4049329d10c06c194e92e13394f8b53c890235b922f18b24ccc71d59065aa6e45889da11d33feee17bd994c456d7635238f431403badb45b9ea907e4385ae2ef178dd5154c77895e9a8f60eef3c3969b356a0c11e6d3d4d0563c1e76d8268117f0eb4c160b3b941e77518a6361d17241f28c7f84ee0e378a831782e9dc688584a0ef9b383835e202bd67f",
+ NULL
+ };
+
+char *SkypeModulus4096[] = {"c3ac2b9912720fd9d5d121570bb8acb6c5b9b5ad4af08b75a68728860759a256f1c4357a329ac61528e968b7b41cae0f7c61784e0e72e465828fbb4e92931a2e14856d4a9600045df661cca37ccd6b993c93fcf62c0eab46882460df70b6f866293bd6d8fe35bcbd9c63ca4909c30652933d2b1943e67633af7ad0599ac8a61b914e2b97d9b1736683f1457695842951fff68e36fc170a54ddbb6b4f7d0361f5a6c36ad2837281aa9359460e6e15aa84d0e17ba9f1a9de3c88cc9233e371a6f18e48892e570679be601ddc134669967e2c550895ed97e49189b7164997eb266540b6b19d259188ddb9224ee846d1d2ca4e86eba4be39a7b1662f7e230b9d8a8f2553f3394a8b6f0668c3372bbba713064543b8f932ca34b3eb44bd8533191550b06960553a0e69386770569c1bc087d21976ef570f6634a5dd127407af32f39a56f5e72aed3590fa4722dc0a55e475b2d1ab39b2f0904168f97a16f4762d6804f7164feecc1a57823a3786c53bcdd73a7086ecd56142af052b86dec233ef8abeab437436c6c1c6ce231aa93bdf669f25c1c30b12df932df4b9662f90b1e1aaeca77a6c773dcb28669cf1852b8c14615e52905ccf3beac1546f499778dd01fc060876afe3f5f97de6d3cccae7a686222c17699f5968c453fd6f692e8254961018f5986d98c01c357d624d3d6c44e3b4ca344de00b2d8bf3939c2758b057bd4985",
+ "ba7463f3b6ccfd1327750915654e4823a5594b656cb9114b17146425bf5d720c9d94ca0bd2ca74ee8ac1af7940950ceebd161b1a631e4a6c98015a056d7af2decc2fc582a0b04ccb5eebb06a438816fbc594de942f9a90fb5c89bdcf215f0ddd59afba36b03538f5ef348dd96366900419c488263dbc547f26ffb54e9fb8faa5a9fed038bc2bd3b14a6b4ffaa5e01e84a029df338e47b267e15976508abb83b4bf88c523b5af7ba597fc4f4b07da84cd4eafb06cd9dee246854bb82be2620981e0c1491d0ed9ad67810cbf1ee7ad7d89a4c66ecb24f10d1c57e7a6947566a8a9739b2ca0af160761cddb4bf279ff6668a46c6c38a365dfeac5ba0f130418fe6234ae0642bff18c9a3422b0ef0f64373f7414ccf80cfd5440b3752de911542cdc10a25899ef7ff7ef32e8d6626caf5d8887d593a7323d663d5c1cd4885b48f3adfa529c42c9177519a2c283db8b68791dd8020cf2fb047fcf58d4605d3891074598eadf1b9c8da1a88b7fd7635d419c16ad109ed288f461d64325ae4929298c204e877515417645057bca10c6ceb3de4bd63441f2e2e2b03bad33781bf4e242f30da3e2407736668ced9193e022b75ab4f65d7201999fa317e9ad30a80080797279bfebd89614827c323979ec5141a25c15bf800f337907fe50b0cdb9eb07b9665958cc9373188dd58eb6571f1f41c4aa7b6357138557a37d122ab6c3f7cd2de9",
+ NULL
+ };
+
+
+uchar KeyDescTable[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x02, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x03, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x04, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x05, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x06, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x07, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x20, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x20, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF
+ };
+
+
+char *KeySelect(uint KeyIndex)
+{
+ uint *pKeyDescTable = (uint*)KeyDescTable;
+ char *pRet;
+
+ if (pKeyDescTable[1] <= 0x1000)
+ {
+ while (pKeyDescTable[2]<0xFFFFFFFF)
+ {
+ switch (pKeyDescTable[1])
+ {
+ case 0x600:
+ pRet = SkypeModulus1536[pKeyDescTable[2]]; break;
+ case 0x800:
+ pRet = SkypeModulus2048[pKeyDescTable[2]]; break;
+ case 0x1000:
+ pRet = SkypeModulus4096[pKeyDescTable[2]]; break;
+ default:
+ return NULL;
+ }
+ if (pKeyDescTable[0] == KeyIndex) return pRet;
+ pKeyDescTable += 3;
+ if (pKeyDescTable[1]>0x1000) return pRet;
+ }
+ }
+ return NULL;
+}
+
+
+
+
+#ifdef CRYPT_WOLFSSL
+#include "wolfssl.c"
+#endif
diff --git a/protocols/MSN/src/skylogin/common.h b/protocols/MSN/src/skylogin/common.h
new file mode 100644
index 0000000000..863d8af07a
--- /dev/null
+++ b/protocols/MSN/src/skylogin/common.h
@@ -0,0 +1,128 @@
+#ifndef __COMMON_H__
+#define __COMMON_H__
+
+#ifdef _WIN32
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <winsock.h>
+#pragma comment (lib,"ws2_32.lib")
+#define int64_t __int64
+
+#else
+
+#include <sys/socket.h>
+#include <netinet/ip.h>
+#include <arpa/inet.h>
+#include <string.h>
+typedef int SOCKET;
+#define closesocket close
+typedef int BOOL;
+#define TRUE 1
+#define FALSE 0
+
+#endif
+
+#ifdef DEBUG
+#include <stdio.h>
+#define DBGPRINT printf
+#else
+#define DBGPRINT
+#endif
+
+/* Use Skype 5+ Diffie-Hellmann RC4 wrapped login comunication.
+ * Fortunately Login servers also still work without it too.
+ * To keep library small and clean, we keep it disabled too,
+ * but you can enable it if you want.
+ */
+//#define USE_RC4
+
+#ifdef CRYPT_WOLFSSL
+#include "wolfssl.h"
+#else
+#include <openssl/md5.h>
+#include <openssl/aes.h>
+#include <openssl/rsa.h>
+#include <openssl/sha.h>
+#ifdef USE_RC4
+#include <openssl/rc4.h>
+#include <openssl/dh.h>
+#endif
+#endif
+
+typedef unsigned char uchar;
+typedef unsigned short ushort;
+typedef unsigned int uint;
+typedef unsigned long ulong;
+
+#define MAX_IP_LEN 15
+#define HTTPS_PORT 443
+
+#define NODEID_SZ 8
+#define HANDSHAKE_SZ 0x05
+#define CONCAT_SALT "\nskyper\n"
+#define KEYSZ 0x200
+#define SK_SZ 0xC0
+#define MODULUS_SZ 0x80
+#define HTTPS_HSR_MAGIC "\x16\x03\x01"
+#define HTTPS_HSRR_MAGIC "\x17\x03\x01"
+#define LOGIN_OK 4200
+
+#define RAW_PARAMS 0x41
+#define EXT_PARAMS 0x42
+
+#define VER_STR "0/6.18.0.105"
+
+typedef struct
+{
+ char ip[MAX_IP_LEN + 1];
+ int port;
+} Host;
+
+typedef struct
+{
+ uchar *Memory;
+ int MsZ;
+} Memory_U;
+
+typedef struct
+{
+ uchar *User;
+ uchar LoginHash[MD5_DIGEST_LENGTH];
+ uint Expiry;
+ RSA *RSAKeys;
+ //Memory_U Modulus;
+ Memory_U SignedCredentials;
+} SLoginDatas;
+
+typedef struct
+{
+ uchar SessionKey[SK_SZ];
+ uchar NodeID[NODEID_SZ];
+ uchar Language[2];
+ uint PublicIP;
+ SLoginDatas LoginD;
+} Skype_Inst;
+
+typedef struct
+{
+ SOCKET LSSock;
+#ifdef USE_RC4
+ RC4_KEY rc4_send;
+ RC4_KEY rc4_recv;
+#endif
+} LSConnection;
+
+#pragma pack(1)
+typedef struct
+{
+ unsigned char MAGIC[3];
+ unsigned short ResponseLen;
+} HttpsPacketHeader;
+
+#pragma pack()
+
+extern char *SkypeModulus1536[];
+
+char *KeySelect(uint KeyIndex);
+#endif
diff --git a/protocols/MSN/src/skylogin/crc.c b/protocols/MSN/src/skylogin/crc.c
new file mode 100644
index 0000000000..48cf20762c
--- /dev/null
+++ b/protocols/MSN/src/skylogin/crc.c
@@ -0,0 +1,113 @@
+#include "crc.h"
+
+ /* ============================================================= */
+ /* COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or */
+ /* code or tables extracted from it, as desired without restriction. */
+ /* */
+ /* First, the polynomial itself and its table of feedback terms. The */
+ /* polynomial is */
+ /* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */
+ /* */
+ /* Note that we take it "backwards" and put the highest-order term in */
+ /* the lowest-order bit. The X^32 term is "implied"; the LSB is the */
+ /* X^31 term, etc. The X^0 term (usually shown as "+1") results in */
+ /* the MSB being 1. */
+ /* */
+ /* Note that the usual hardware shift register implementation, which */
+ /* is what we're using (we're merely optimizing it by doing eight-bit */
+ /* chunks at a time) shifts bits into the lowest-order term. In our */
+ /* implementation, that means shifting towards the right. Why do we */
+ /* do it this way? Because the calculated CRC must be transmitted in */
+ /* order from highest-order term to lowest-order term. UARTs transmit */
+ /* characters in order from LSB to MSB. By storing the CRC this way, */
+ /* we hand it to the UART in the order low-byte to high-byte; the UART */
+ /* sends each low-bit to hight-bit; and the result is transmission bit */
+ /* by bit from highest- to lowest-order term without requiring any bit */
+ /* shuffling on our part. Reception works similarly. */
+ /* */
+ /* The feedback terms table consists of 256, 32-bit entries. Notes: */
+ /* */
+ /* The table can be generated at runtime if desired; code to do so */
+ /* is shown later. It might not be obvious, but the feedback */
+ /* terms simply represent the results of eight shift/xor opera- */
+ /* tions for all combinations of data and CRC register values. */
+ /* */
+ /* The values must be right-shifted by eight bits by the "updcrc" */
+ /* logic; the shift must be unsigned (bring in zeroes). On some */
+ /* hardware you could probably optimize the shift in assembler by */
+ /* using byte-swap instructions. */
+ /* polynomial $edb88320 */
+ /* */
+ /* -------------------------------------------------------------------- */
+
+static unsigned int crc32_tab[] = {
+ 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+ 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+ 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+ 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+ 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+ 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+ 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+ 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+ 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+ 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+ 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+ 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+ 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+ 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+ 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+ 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+ 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+ 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+ 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+ 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+ 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+ 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+ 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+ 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+ 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+ 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+ 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+ 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+ 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+ 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+ 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+ 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+ 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+ 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+ 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+ 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+ 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+ 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+ 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+ 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+ 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+ 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+ 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+ 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+ 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+ 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+ 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+ 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+ 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+ 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+ 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+ 0x2d02ef8dL
+ };
+
+/* Return a 32-bit CRC of the contents of the buffer. */
+
+unsigned int crc32(const unsigned char *s, unsigned int len, int salt)
+{
+ unsigned int crc32val;
+ unsigned int i;
+
+ crc32val = salt;
+ for (i = 0; i < len; i ++)
+ {
+ crc32val =
+ crc32_tab[(crc32val ^ s[i]) & 0xff] ^
+ (crc32val >> 8);
+ }
+ return crc32val;
+}
diff --git a/protocols/MSN/src/skylogin/crc.h b/protocols/MSN/src/skylogin/crc.h
new file mode 100644
index 0000000000..d2964e841b
--- /dev/null
+++ b/protocols/MSN/src/skylogin/crc.h
@@ -0,0 +1,6 @@
+#ifndef CRC_H
+#define CRC_H
+/* This computes a 32 bit CRC of the data in the buffer, and returns the
+ CRC. The polynomial used is 0xedb88320. */
+unsigned int crc32(const unsigned char *buf, unsigned int len, int salt);
+#endif /* CRC_H */
diff --git a/protocols/MSN/src/skylogin/credentials.c b/protocols/MSN/src/skylogin/credentials.c
new file mode 100644
index 0000000000..0fc886eea7
--- /dev/null
+++ b/protocols/MSN/src/skylogin/credentials.c
@@ -0,0 +1,163 @@
+/*
+ * Skype Login
+ *
+ * Based on:
+ * FakeSkype : Skype reverse engineering proof-of-concept client
+ * Ouanilo MEDEGAN (c) 2006 http://www.oklabs.net
+ * pyskype : Skype login Python script by uunicorn
+ *
+ * Written by: leecher@dose.0wnz.at (c) 2015
+ *
+ * Module: Credentials handling, reads/writes old Skype credentials format
+ *
+ */
+#include "common.h"
+#include "objects.h"
+#include "random.h"
+#include "crc.h"
+#include "credentials.h"
+#ifdef _WIN32
+#define CRC_SIZE sizeof(short)
+#else
+#define CRC_SIZE 0
+#endif
+
+
+Memory_U Credentials_Write(Skype_Inst *pInst)
+{
+ Memory_U creds;
+ uchar *Browser;
+ uint Crc;
+
+ creds.MsZ = sizeof(pInst->LoginD.LoginHash) + MODULUS_SZ + pInst->LoginD.SignedCredentials.MsZ + CRC_SIZE;
+ if (!(Browser = creds.Memory = malloc(creds.MsZ)))
+ {
+ creds.MsZ = 0;
+ return creds;
+ }
+ memcpy(Browser, pInst->LoginD.LoginHash, sizeof(pInst->LoginD.LoginHash));
+ Browser+=sizeof(pInst->LoginD.LoginHash);
+ BN_bn2bin(pInst->LoginD.RSAKeys->d, Browser);
+ Browser+=MODULUS_SZ;
+ memcpy(Browser, pInst->LoginD.SignedCredentials.Memory, pInst->LoginD.SignedCredentials.MsZ);
+ Browser+=pInst->LoginD.SignedCredentials.MsZ;
+#ifdef _WIN32
+ Crc = crc32(creds.Memory, Browser-creds.Memory, -1);
+ *Browser++ = *((uchar *)(&Crc) + 0);
+ *Browser++ = *((uchar *)(&Crc) + 1);
+#endif
+ return creds;
+}
+
+/*
+ 0 - OK
+ -1 - Invalid size of credentials blob
+ -2 - Invalid CRC
+ -3 - Out of memory
+ -4 - Unable to parse Signed credentials
+ -5 - RSA public key not found
+*/
+int Credentials_Read(Skype_Inst *pInst, Memory_U creds, SResponse *LoginDatas)
+{
+ uchar *Browser;
+ uint Crc, Idx;
+ RSA *Keys;
+
+ if (creds.MsZ < sizeof(pInst->LoginD.LoginHash) + MODULUS_SZ + 16 + CRC_SIZE)
+ return -1;
+
+#ifdef _WIN32
+ Crc = crc32(creds.Memory, creds.MsZ-2, -1);
+ if (*((uchar *)(&Crc) + 0) != *((uchar*)creds.Memory+creds.MsZ-2) ||
+ *((uchar *)(&Crc) + 1) != *((uchar*)creds.Memory+creds.MsZ-1))
+ {
+ DBGPRINT("Credentials: Bad CRC!");
+ return -2;
+ }
+#endif
+
+ Browser = creds.Memory;
+ memcpy (pInst->LoginD.LoginHash, Browser, sizeof(pInst->LoginD.LoginHash));
+ Browser+=sizeof(pInst->LoginD.LoginHash);
+ Keys=RSA_new();
+ BN_hex2bn(&(Keys->e), "010001");
+ Keys->d = BN_bin2bn(Browser, MODULUS_SZ, NULL);
+ Browser+=MODULUS_SZ;
+ if (pInst->LoginD.SignedCredentials.Memory) free(pInst->LoginD.SignedCredentials.Memory);
+ pInst->LoginD.SignedCredentials.MsZ = creds.MsZ - CRC_SIZE - (Browser-creds.Memory);
+ if (!(pInst->LoginD.SignedCredentials.Memory = malloc(pInst->LoginD.SignedCredentials.MsZ)))
+ {
+ pInst->LoginD.SignedCredentials.MsZ = 0;
+ RSA_free(Keys);
+ return -3;
+ }
+ memcpy(pInst->LoginD.SignedCredentials.Memory, Browser, pInst->LoginD.SignedCredentials.MsZ);
+
+ // Now credentials are read, but we need to finish LoginD.RSAKeys by unpacking Signed Credentials
+ if (Credentials_Parse(pInst->LoginD.SignedCredentials, LoginDatas)<0)
+ {
+ RSA_free(Keys);
+ return -4;
+ }
+
+ for (Idx = 0; Idx < LoginDatas->NbObj; Idx++)
+ {
+ if (LoginDatas->Objs[Idx].Id == OBJ_ID_LDMODULUS)
+ {
+ Keys->n = BN_bin2bn(LoginDatas->Objs[Idx].Value.Memory.Memory,
+ LoginDatas->Objs[Idx].Value.Memory.MsZ, NULL);
+ if (pInst->LoginD.RSAKeys) RSA_free(pInst->LoginD.RSAKeys);
+ pInst->LoginD.RSAKeys = Keys;
+ return 0;
+ }
+ }
+
+ RSA_free(Keys);
+ return -5;
+}
+
+int Credentials_Parse(Memory_U Pcred, SResponse *LoginDatas)
+{
+ uchar *PostProcessed, *Browser;
+ char *Key;
+ uint KeyIdx, PPsZ;
+ RSA *SkypeRSA;
+ Memory_U creds = Pcred;
+
+ if (!(creds.Memory = malloc(creds.MsZ)))
+ return -2;
+ KeyIdx = htonl(*(uint *)Pcred.Memory);
+ Pcred.Memory += sizeof(uint);
+ Pcred.MsZ -= sizeof(uint);
+
+ SkypeRSA = RSA_new();
+ Key = KeySelect(KeyIdx);
+ BN_hex2bn(&(SkypeRSA->n), Key);
+ BN_hex2bn(&(SkypeRSA->e), "010001");
+ PPsZ = RSA_public_decrypt(Pcred.MsZ, Pcred.Memory, creds.Memory, SkypeRSA, RSA_NO_PADDING);
+ RSA_free(SkypeRSA);
+ if (PPsZ == -1)
+ {
+ DBGPRINT("Decryption failed..\n");
+ free(creds.Memory);
+ return -1;
+ }
+
+ PostProcessed = FinalizeLoginDatas(creds.Memory, &PPsZ, NULL, 0);
+
+ if (PostProcessed == NULL)
+ {
+ DBGPRINT("Bad Datas Finalization..\n");
+ free (creds.Memory);
+ return -1;
+ }
+
+ LoginDatas->Objs = NULL;
+ LoginDatas->NbObj = 0;
+ Browser = PostProcessed;
+
+ ManageObjects(&Browser, PPsZ, LoginDatas);
+ free(PostProcessed);
+ free(creds.Memory);
+ return 0;
+}
diff --git a/protocols/MSN/src/skylogin/credentials.h b/protocols/MSN/src/skylogin/credentials.h
new file mode 100644
index 0000000000..ec09b8a89c
--- /dev/null
+++ b/protocols/MSN/src/skylogin/credentials.h
@@ -0,0 +1,3 @@
+Memory_U Credentials_Write(Skype_Inst *pInst);
+int Credentials_Read(Skype_Inst *pInst, Memory_U creds, SResponse *LoginDatas);
+int Credentials_Parse(Memory_U creds, SResponse *LoginDatas);
diff --git a/protocols/MSN/src/skylogin/login.c b/protocols/MSN/src/skylogin/login.c
new file mode 100644
index 0000000000..6e6856ad8e
--- /dev/null
+++ b/protocols/MSN/src/skylogin/login.c
@@ -0,0 +1,414 @@
+/*
+ * Skype Login
+ *
+ * Based on:
+ * FakeSkype : Skype reverse engineering proof-of-concept client
+ * Ouanilo MEDEGAN (c) 2006 http://www.oklabs.net
+ * pyskype : Skype login Python script by uunicorn
+ *
+ * Written by: leecher@dose.0wnz.at (c) 2015
+ *
+ * Module: Skype server login
+ *
+ */
+#include "common.h"
+#include "objects.h"
+#include "random.h"
+#include "platform.h"
+#include "crc.h"
+#ifdef _DEBUG
+#include <time.h>
+#endif
+
+#ifdef USE_RC4
+#include "rc4comm.c"
+#else
+#define RC4Comm_Init(conn) 0
+#define RC4Comm_Send(conn,buf,len) send(conn->LSSock,buf,len,0)
+#define RC4Comm_Recv(conn,buf,len) recv(conn->LSSock,buf,len,0)
+#endif
+
+static Host LoginServers[] = {
+ {"91.190.216.17", 33033},
+ {"91.190.218.40", 33033},
+};
+
+static BOOL SendHandShake2LS(LSConnection *pConn, Host *CurLS)
+{
+ uchar HandShakePkt[HANDSHAKE_SZ] = {0};
+ HttpsPacketHeader *HSHeader, Response;
+ struct sockaddr_in Sender={0};
+
+ HSHeader = (HttpsPacketHeader *)HandShakePkt;
+ memcpy(HSHeader->MAGIC, HTTPS_HSR_MAGIC, sizeof(HSHeader->MAGIC));
+ HSHeader->ResponseLen = 0;
+ DBGPRINT("Sending Handshake to Login Server %s..\n", CurLS->ip);
+ Sender.sin_family = AF_INET;
+ Sender.sin_port = htons((short)CurLS->port);
+ Sender.sin_addr.s_addr = inet_addr(CurLS->ip);
+ if (connect(pConn->LSSock, (struct sockaddr *)&Sender, sizeof(Sender)) < 0)
+ {
+ DBGPRINT("Connection refused..\n");
+ return FALSE;
+ }
+ if (RC4Comm_Init(pConn) < 0 ||
+ RC4Comm_Send(pConn, (const char *)HandShakePkt, HANDSHAKE_SZ)<=0 ||
+ RC4Comm_Recv(pConn, (char*)&Response, sizeof(Response))<=0 ||
+ memcmp(Response.MAGIC, HTTPS_HSRR_MAGIC, sizeof(Response.MAGIC)))
+ return FALSE;
+ return TRUE;
+}
+
+/* If Pass is NULL, User is assumed to be OAuth string and OAuth logon is performed */
+static int SendAuthentificationBlobLS(Skype_Inst *pInst, LSConnection *pConn, const char *User, const char *Pass)
+{
+ int64_t PlatForm;
+ uchar AuthBlob[0xFFFF] = {0};
+ uchar SHAResult[32] = {0};
+ uchar Modulus[MODULUS_SZ * 2] = {0};
+ uchar ivec[AES_BLOCK_SIZE] = {0};
+ uchar ecount_buf[AES_BLOCK_SIZE] = {0};
+ uint MiscDatas[0x05] = {0};
+ uchar SessionKey[SK_SZ];
+ uchar *Browser;
+ uchar *Mark;
+ uchar *MarkObjL;
+ uint Idx, Size, Crc, BSize, ret = 0;
+ HttpsPacketHeader *HSHeader;
+ uchar HSHeaderBuf[sizeof(HttpsPacketHeader)], RecvBuf[0x1000];
+ AES_KEY AesKey;
+ MD5_CTX Context;
+ RSA *SkypeRSA;
+ ObjectDesc Obj2000, ObjSessionKey, ObjZBool1, ObjRequestCode, ObjZBool2, ObjModulus, ObjPlatForm, ObjLang, ObjMiscDatas, ObjVer, ObjPubAddr;
+ SResponse Response={0};
+
+
+ if (!pInst->LoginD.RSAKeys)
+ {
+ BIGNUM *KeyExp;
+
+ DBGPRINT("Generating RSA Keys Pair (Size = %d Bits)..\n", KEYSZ);
+ pInst->LoginD.RSAKeys = RSA_new();
+ KeyExp = BN_new();
+ BN_set_word(KeyExp, RSA_F4);
+ Idx = RSA_generate_key_ex(pInst->LoginD.RSAKeys, KEYSZ * 2, KeyExp, NULL);
+ BN_free(KeyExp);
+ if (Idx == -1)
+ {
+ DBGPRINT("Error generating Keys..\n\n");
+ RSA_free(pInst->LoginD.RSAKeys);
+ pInst->LoginD.RSAKeys = NULL;
+ return (0);
+ }
+ }
+
+ Idx = BN_bn2bin(pInst->LoginD.RSAKeys->n, Modulus);
+ Idx = BN_bn2bin(pInst->LoginD.RSAKeys->d, Modulus + Idx);
+
+ Browser = AuthBlob;
+
+ HSHeader = (HttpsPacketHeader *)Browser;
+ memcpy(HSHeader->MAGIC, HTTPS_HSR_MAGIC, sizeof(HSHeader->MAGIC));
+ HSHeader->ResponseLen = htons(0xCD);
+ Browser += sizeof(HttpsPacketHeader);
+
+ *Browser++ = RAW_PARAMS;
+ *Browser++ = 0x03;
+
+ Obj2000.Family = OBJ_FAMILY_NBR;
+ Obj2000.Id = OBJ_ID_2000;
+ Obj2000.Value.Nbr = 0x2000;
+ WriteObject(&Browser, Obj2000);
+
+ SpecialSHA(pInst->SessionKey, SK_SZ, SHAResult, 32);
+ AES_set_encrypt_key(SHAResult, 256, &AesKey);
+
+ SkypeRSA = RSA_new();
+ BN_hex2bn(&(SkypeRSA->n), SkypeModulus1536[1]);
+ BN_hex2bn(&(SkypeRSA->e), "010001");
+ Idx = RSA_public_encrypt(SK_SZ, pInst->SessionKey, SessionKey, SkypeRSA, RSA_NO_PADDING);
+ RSA_free(SkypeRSA);
+ if (Idx < 0)
+ {
+ DBGPRINT("RSA_public_encrypt failed..\n\n");
+ return (0);
+ }
+
+ ObjSessionKey.Family = OBJ_FAMILY_BLOB;
+ ObjSessionKey.Id = OBJ_ID_SK;
+ ObjSessionKey.Value.Memory.Memory = (uchar *)&SessionKey;
+ ObjSessionKey.Value.Memory.MsZ = SK_SZ;
+ WriteObject(&Browser, ObjSessionKey);
+
+ ObjZBool1.Family = OBJ_FAMILY_NBR;
+ ObjZBool1.Id = OBJ_ID_ZBOOL1;
+ ObjZBool1.Value.Nbr = 0x01;
+ WriteObject(&Browser, ObjZBool1);
+
+ Mark = Browser;
+ HSHeader = (HttpsPacketHeader *)Browser;
+ memcpy(HSHeader->MAGIC, HTTPS_HSRR_MAGIC, sizeof(HSHeader->MAGIC));
+ HSHeader->ResponseLen = 0x00;
+ Browser += sizeof(HttpsPacketHeader);
+
+ MarkObjL = Browser;
+ if (Pass)
+ {
+ ObjectDesc ObjUserName, ObjSharedSecret;
+
+ *Browser++ = RAW_PARAMS;
+ *Browser++ = 0x04;
+
+ ObjRequestCode.Family = OBJ_FAMILY_NBR;
+ ObjRequestCode.Id = OBJ_ID_REQCODE;
+ ObjRequestCode.Value.Nbr = 0x1399;
+ WriteObject(&Browser, ObjRequestCode);
+
+ ObjZBool2.Family = OBJ_FAMILY_NBR;
+ ObjZBool2.Id = OBJ_ID_ZBOOL2;
+ ObjZBool2.Value.Nbr = 0x01;
+ WriteObject(&Browser, ObjZBool2);
+
+ ObjUserName.Family = OBJ_FAMILY_STRING;
+ ObjUserName.Id = OBJ_ID_USERNAME;
+ ObjUserName.Value.Memory.Memory = (uchar *)User;
+ ObjUserName.Value.Memory.MsZ = (uchar)strlen(User);
+ WriteObject(&Browser, ObjUserName);
+
+ MD5_Init(&Context);
+ MD5_Update(&Context, User, (ulong)strlen(User));
+ MD5_Update(&Context, CONCAT_SALT, (ulong)strlen(CONCAT_SALT));
+ MD5_Update(&Context, Pass, (ulong)strlen(Pass));
+ MD5_Final(pInst->LoginD.LoginHash, &Context);
+
+ ObjSharedSecret.Family = OBJ_FAMILY_BLOB;
+ ObjSharedSecret.Id = OBJ_ID_USERPASS;
+ ObjSharedSecret.Value.Memory.Memory = (uchar *)pInst->LoginD.LoginHash;
+ ObjSharedSecret.Value.Memory.MsZ = MD5_DIGEST_LENGTH;
+ WriteObject(&Browser, ObjSharedSecret);
+
+ *Browser++ = RAW_PARAMS;
+ *Browser++ = 0x06;
+
+ ObjModulus.Family = OBJ_FAMILY_BLOB;
+ ObjModulus.Id = OBJ_ID_MODULUS;
+ ObjModulus.Value.Memory.Memory = (uchar *)Modulus;
+ ObjModulus.Value.Memory.MsZ = MODULUS_SZ;
+ WriteObject(&Browser, ObjModulus);
+
+ PlatForm = PlatFormSpecific();
+
+ ObjPlatForm.Family = OBJ_FAMILY_TABLE;
+ ObjPlatForm.Id = OBJ_ID_PLATFORM;
+ memcpy(ObjPlatForm.Value.Table, (uchar *)&PlatForm, sizeof(ObjPlatForm.Value.Table));
+ WriteObject(&Browser, ObjPlatForm);
+
+ ObjLang.Family = OBJ_FAMILY_STRING;
+ ObjLang.Id = OBJ_ID_LANG;
+ ObjLang.Value.Memory.Memory = pInst->Language;
+ ObjLang.Value.Memory.MsZ = sizeof(pInst->Language);
+ WriteObject(&Browser, ObjLang);
+
+ FillMiscDatas(pInst, MiscDatas);
+ ObjMiscDatas.Family = OBJ_FAMILY_INTLIST;
+ ObjMiscDatas.Id = OBJ_ID_MISCD;
+ ObjMiscDatas.Value.Memory.Memory = (uchar *)MiscDatas;
+ ObjMiscDatas.Value.Memory.MsZ = 0x05;
+ WriteObject(&Browser, ObjMiscDatas);
+
+ ObjVer.Family = OBJ_FAMILY_STRING;
+ ObjVer.Id = OBJ_ID_VERSION;
+ ObjVer.Value.Memory.Memory = (uchar *)VER_STR;
+ ObjVer.Value.Memory.MsZ = (uchar)strlen(VER_STR);
+ WriteObject(&Browser, ObjVer);
+
+ ObjPubAddr.Family = OBJ_FAMILY_NBR;
+ ObjPubAddr.Id = OBJ_ID_PUBADDR;
+ ObjPubAddr.Value.Nbr = pInst->PublicIP;
+ WriteObject(&Browser, ObjPubAddr);
+ }
+ else
+ {
+ int64_t PartnerId = 999;
+ ObjectDesc ObjPartnerId, ObjOauth;
+
+ // OAuth logon
+ *Browser++ = RAW_PARAMS;
+ *Browser++ = 0x02;
+
+ ObjRequestCode.Family = OBJ_FAMILY_NBR;
+ ObjRequestCode.Id = OBJ_ID_REQCODE;
+ ObjRequestCode.Value.Nbr = 0x13a3;
+ WriteObject(&Browser, ObjRequestCode);
+
+ ObjZBool2.Family = OBJ_FAMILY_NBR;
+ ObjZBool2.Id = OBJ_ID_ZBOOL2;
+ ObjZBool2.Value.Nbr = 0x3d;
+ WriteObject(&Browser, ObjZBool2);
+
+ *Browser++ = RAW_PARAMS;
+ *Browser++ = 0x08;
+
+ ObjModulus.Family = OBJ_FAMILY_BLOB;
+ ObjModulus.Id = OBJ_ID_MODULUS;
+ ObjModulus.Value.Memory.Memory = (uchar *)Modulus;
+ ObjModulus.Value.Memory.MsZ = MODULUS_SZ;
+ WriteObject(&Browser, ObjModulus);
+
+ PlatForm = PlatFormSpecific();
+
+ ObjPlatForm.Family = OBJ_FAMILY_TABLE;
+ ObjPlatForm.Id = OBJ_ID_PLATFORM;
+ memcpy(ObjPlatForm.Value.Table, (uchar *)&PlatForm, sizeof(ObjPlatForm.Value.Table));
+ WriteObject(&Browser, ObjPlatForm);
+
+ FillMiscDatas(pInst, MiscDatas);
+ ObjMiscDatas.Family = OBJ_FAMILY_INTLIST;
+ ObjMiscDatas.Id = OBJ_ID_MISCD;
+ ObjMiscDatas.Value.Memory.Memory = (uchar *)MiscDatas;
+ ObjMiscDatas.Value.Memory.MsZ = 0x05;
+ WriteObject(&Browser, ObjMiscDatas);
+
+ ObjLang.Family = OBJ_FAMILY_STRING;
+ ObjLang.Id = OBJ_ID_LANG;
+ ObjLang.Value.Memory.Memory = pInst->Language;
+ ObjLang.Value.Memory.MsZ = sizeof(pInst->Language);
+ WriteObject(&Browser, ObjLang);
+
+ ObjPartnerId.Family = OBJ_FAMILY_TABLE;
+ ObjPlatForm.Id = OBJ_ID_PARTNERID;
+ memcpy(ObjPlatForm.Value.Table, (uchar *)&PartnerId, sizeof(ObjPlatForm.Value.Table));
+ WriteObject(&Browser, ObjPlatForm);
+
+ ObjOauth.Family = OBJ_FAMILY_STRING;
+ ObjOauth.Id = OBJ_ID_OAUTH;
+ ObjOauth.Value.Memory.Memory = (uchar *)User;
+ ObjOauth.Value.Memory.MsZ = strlen(User);
+ WriteObject(&Browser, ObjOauth);
+
+ ObjVer.Family = OBJ_FAMILY_STRING;
+ ObjVer.Id = OBJ_ID_VERSION;
+ ObjVer.Value.Memory.Memory = (uchar *)VER_STR;
+ ObjVer.Value.Memory.MsZ = (uchar)strlen(VER_STR);
+ WriteObject(&Browser, ObjVer);
+
+ ObjPubAddr.Family = OBJ_FAMILY_NBR;
+ ObjPubAddr.Id = OBJ_ID_PUBADDR;
+ ObjPubAddr.Value.Nbr = pInst->PublicIP;
+ WriteObject(&Browser, ObjPubAddr);
+ }
+
+ Size = (uint)(Browser - MarkObjL);
+ HSHeader->ResponseLen = htons((u_short)(Size + 0x02));
+
+ Idx = 0;
+ memset(ivec, 0, AES_BLOCK_SIZE);
+ memset(ecount_buf, 0, AES_BLOCK_SIZE);
+ AES_ctr128_encrypt(MarkObjL, MarkObjL, Size, &AesKey, ivec, ecount_buf, &Idx);
+
+ Crc = crc32(MarkObjL, Size, -1);
+ *Browser++ = *((uchar *)(&Crc) + 0);
+ *Browser++ = *((uchar *)(&Crc) + 1);
+
+ Size = (uint)(Browser - AuthBlob);
+
+ if (RC4Comm_Send(pConn, (const char *)AuthBlob, Size)<=0)
+ {
+ DBGPRINT("Sending to LS failed :'(..\n");
+ return (-1);
+ }
+
+ while (!ret && RC4Comm_Recv(pConn, (char *)&HSHeaderBuf, sizeof(HSHeaderBuf))>0)
+ {
+ HSHeader = (HttpsPacketHeader *)HSHeaderBuf;
+ if (strncmp((const char *)HSHeader->MAGIC, HTTPS_HSRR_MAGIC, strlen(HTTPS_HSRR_MAGIC)) ||
+ RC4Comm_Recv(pConn, (char *)RecvBuf, (BSize=htons(HSHeader->ResponseLen)))<=0)
+ {
+ DBGPRINT("Bad Response..\n");
+ return (-2);
+ }
+ DBGPRINT("Auth Response Got..\n\n");
+
+ Idx = 0;
+ memset(ivec, 0, AES_BLOCK_SIZE);
+ memset(ecount_buf, 0, AES_BLOCK_SIZE);
+ BSize-=2;
+ ivec[3] = 0x01;
+ ivec[7] = 0x01;
+ AES_ctr128_encrypt(RecvBuf, RecvBuf, BSize, &AesKey, ivec, ecount_buf, &Idx);
+
+ Browser = RecvBuf;
+ while (Browser<RecvBuf+BSize)
+ ManageObjects(&Browser, BSize, &Response);
+ for (Idx = 0; Idx < Response.NbObj; Idx++)
+ {
+ uint LdIdx = 0;
+
+
+ switch (Response.Objs[Idx].Id)
+ {
+ case OBJ_ID_LOGINANSWER:
+ switch (Response.Objs[Idx].Value.Nbr)
+ {
+ case LOGIN_OK:
+ DBGPRINT("Login Successful..\n");
+ ret = 1;
+ break;
+ default :
+ DBGPRINT("Login Failed.. Bad Credentials..\n");
+ FreeResponse(&Response);
+ return 0;
+ }
+ break;
+ case OBJ_ID_CIPHERDLOGD:
+ if (pInst->LoginD.SignedCredentials.Memory) free(pInst->LoginD.SignedCredentials.Memory);
+ if (!(pInst->LoginD.SignedCredentials.Memory = malloc(Response.Objs[Idx].Value.Memory.MsZ)))
+ {
+ FreeResponse(&Response);
+ return -2;
+ }
+ memcpy (pInst->LoginD.SignedCredentials.Memory, Response.Objs[Idx].Value.Memory.Memory,
+ (pInst->LoginD.SignedCredentials.MsZ = Response.Objs[Idx].Value.Memory.MsZ));
+ break;
+ }
+ }
+ FreeResponse(&Response);
+ }
+
+ return ret;
+}
+
+
+int PerformLogin(Skype_Inst *pInst, const char *User, const char *Pass)
+{
+ uint ReUse = 1;
+ int i;
+ LSConnection conn={0};
+ int iRet = 0;
+
+ for (i=0; !iRet && i<sizeof(LoginServers)/sizeof(LoginServers[0]); i++)
+ {
+ conn.LSSock = socket(AF_INET, SOCK_STREAM, 0);
+ setsockopt(conn.LSSock, SOL_SOCKET, SO_REUSEADDR, (const char *)&ReUse, sizeof(ReUse));
+
+ if (SendHandShake2LS(&conn, &LoginServers[i]))
+ {
+ DBGPRINT("Login Server %s OK ! Let's authenticate..\n", LoginServers[i].ip);
+ iRet = SendAuthentificationBlobLS(pInst, &conn, User, Pass);
+ }
+ closesocket(conn.LSSock);
+ }
+
+ if (!iRet) DBGPRINT("Login Failed..\n");
+ return iRet;
+}
+
+
+void InitInstance(Skype_Inst *pInst)
+{
+ memset(pInst, 0, sizeof(Skype_Inst));
+ GenSessionKey(pInst->SessionKey, sizeof(pInst->SessionKey));
+ InitNodeId(pInst);
+ memcpy(pInst->Language, "en", 2);
+ pInst->PublicIP = 0x7F000001; // 127.0.0.1, we could use hostscan to get real IP, but not necessary for just login
+}
diff --git a/protocols/MSN/src/skylogin/login.h b/protocols/MSN/src/skylogin/login.h
new file mode 100644
index 0000000000..6d5113466d
--- /dev/null
+++ b/protocols/MSN/src/skylogin/login.h
@@ -0,0 +1,2 @@
+int PerformLogin(Skype_Inst *pInst, const char *User, const char *Pass);
+void InitInstance(Skype_Inst *pInst);
diff --git a/protocols/MSN/src/skylogin/objects.c b/protocols/MSN/src/skylogin/objects.c
new file mode 100644
index 0000000000..f5941128f0
--- /dev/null
+++ b/protocols/MSN/src/skylogin/objects.c
@@ -0,0 +1,252 @@
+/*
+ * Skype Login
+ *
+ * Based on:
+ * FakeSkype : Skype reverse engineering proof-of-concept client
+ * Ouanilo MEDEGAN (c) 2006 http://www.oklabs.net
+ * pyskype : Skype login Python script by uunicorn
+ *
+ * Written by: leecher@dose.0wnz.at (c) 2015
+ *
+ * Module: Object management functions
+ *
+ */
+#include "common.h"
+#include "objects.h"
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <winsock.h>
+#endif
+
+void WriteValue(uchar **BufferAddr, uint Value)
+{
+ uint a;
+
+ for (a = Value; a > 0x7F; a >>= 7, (*BufferAddr)++) **BufferAddr = (uchar)a | 0x80;
+ **BufferAddr = (uchar) a;
+ (*BufferAddr)++;
+}
+
+void ReadValue(uchar **BufferAddr, uint *Value)
+{
+ uint a=0;
+ uchar c;
+
+ for (*Value=0, c=**BufferAddr; a==0 || (c & 0x80); a+=7, (*BufferAddr)++) *Value|=((c=**BufferAddr) & 0x7F) << a;
+}
+
+
+void WriteObject(uchar **Buffer, ObjectDesc Object)
+{
+ int IdxDown, IdxUp;
+
+ Object.ObjListInfos.Id = -1;
+ Object.ObjListInfos.Rank = 0;
+
+ WriteValue(Buffer, Object.Family);
+ WriteValue(Buffer, Object.Id);
+ switch(Object.Family)
+ {
+ case OBJ_FAMILY_NBR:
+ WriteValue(Buffer, Object.Value.Nbr);
+ break;
+ case OBJ_FAMILY_TABLE:
+ IdxUp = 0;
+ IdxDown = sizeof(Object.Value.Table) - 1;
+ while (IdxDown >= 0)
+ (*Buffer)[IdxDown--] = Object.Value.Table[IdxUp++];
+ *Buffer += sizeof(Object.Value.Table);
+ break;
+ case OBJ_FAMILY_NETADDR:
+ *(unsigned int *)(*Buffer) = inet_addr(Object.Value.Addr.ip);
+ *Buffer += 4;
+ *(unsigned short *)(*Buffer) = htons((u_short)Object.Value.Addr.port);
+ *Buffer += 2;
+ break;
+ case OBJ_FAMILY_BLOB:
+ WriteValue(Buffer, Object.Value.Memory.MsZ);
+ memcpy(*Buffer, Object.Value.Memory.Memory, Object.Value.Memory.MsZ);
+ *Buffer += Object.Value.Memory.MsZ;
+ break;
+ case OBJ_FAMILY_STRING:
+ memcpy(*Buffer, Object.Value.Memory.Memory, Object.Value.Memory.MsZ);
+ *Buffer += Object.Value.Memory.MsZ;
+ *(*Buffer) = 0x00;
+ *Buffer += 1;
+ break;
+ case OBJ_FAMILY_INTLIST:
+ {
+ uint *IntList;
+
+ IdxUp = 0;
+ IntList = (uint *)Object.Value.Memory.Memory;
+ WriteValue(Buffer, Object.Value.Memory.MsZ);
+ while (IdxUp < Object.Value.Memory.MsZ)
+ {
+ WriteValue(Buffer, IntList[IdxUp]);
+ IdxUp++;
+ }
+ break;
+ }
+ default:
+ DBGPRINT("WriteObject : Unmanaged Object Family\n");
+ break;
+ }
+}
+
+int DecodeRawObjects(uchar **Buffer, uint Size, SResponse *Response, ObjectDesc **Objs, int Suffix)
+{
+ int NbObjs, lIdx, IdxUp, IdxDown;
+ uint Family, Id;
+ uchar *Str, *Mark;
+ struct in_addr IP;
+ ObjectDesc *Object;
+ static int Idx = 0;
+ static int Level = 0;
+ static int CurObjListId = -1;
+ static uint CurObjListRank = 0;
+ uint LocalObjListRank;
+
+ LocalObjListRank = CurObjListRank;
+ NbObjs = Family = Id = lIdx = 0;
+ Mark = *Buffer;
+
+ ReadValue(Buffer, &NbObjs);
+ Level += 1;
+
+ if (Level == 1)
+ Idx += Suffix;
+
+ while (lIdx < NbObjs)
+ {
+ Family = **Buffer;
+ *Buffer += 1;
+ ReadValue(Buffer, &Id);
+ *Objs = (ObjectDesc *)realloc(*Objs, sizeof(ObjectDesc) * (Idx + 1));
+ Object = &((*Objs)[Idx]);
+ Object->Family = Family;
+ Object->Id = Id;
+ Object->ObjListInfos.Id = CurObjListId;
+ Object->ObjListInfos.Rank = LocalObjListRank;
+
+ switch (Family)
+ {
+ case OBJ_FAMILY_NBR:
+ ReadValue(Buffer, &(Object->Value.Nbr));
+ break;
+ case OBJ_FAMILY_TABLE:
+ IdxUp = 0;
+ IdxDown = sizeof(Object->Value.Table) - 1;
+ while (IdxDown >= 0)
+ Object->Value.Table[IdxUp++] = (*Buffer)[IdxDown--];
+ *Buffer += sizeof(Object->Value.Table);
+ break;
+ case OBJ_FAMILY_NETADDR:
+#ifdef _WIN32
+ IP.S_un.S_addr = *(unsigned int *)*Buffer;
+#else
+ IP.s_addr = *(unsigned int *)*Buffer;
+#endif
+ memset(Object->Value.Addr.ip, 0, MAX_IP_LEN + 1);
+ strncpy(Object->Value.Addr.ip, inet_ntoa(IP), MAX_IP_LEN + 1);
+ *Buffer += 4;
+ Object->Value.Addr.port = htons(*(unsigned short *)(*Buffer));
+ *Buffer += 2;
+ break;
+ case OBJ_FAMILY_BLOB:
+ ReadValue(Buffer, &(Object->Value.Memory.MsZ));
+ Object->Value.Memory.Memory = (uchar *)malloc(Object->Value.Memory.MsZ);
+ memcpy(Object->Value.Memory.Memory, *Buffer, Object->Value.Memory.MsZ);
+ *Buffer += Object->Value.Memory.MsZ;
+ break;
+ case OBJ_FAMILY_STRING:
+ Str = *Buffer;
+ Object->Value.Memory.MsZ = 1;
+ while (*Str++ != 0)
+ Object->Value.Memory.MsZ += 1;
+ Object->Value.Memory.Memory = (uchar *)malloc(Object->Value.Memory.MsZ);
+ memcpy(Object->Value.Memory.Memory, *Buffer, Object->Value.Memory.MsZ);
+ *Buffer += Object->Value.Memory.MsZ;
+ break;
+ case OBJ_FAMILY_INTLIST:
+ ReadValue(Buffer, &(Object->Value.Memory.MsZ));
+ Object->Value.Memory.Memory = (uchar *)malloc(Object->Value.Memory.MsZ * sizeof(uint));
+ for (IdxUp = 0; IdxUp < Object->Value.Memory.MsZ; IdxUp++)
+ ReadValue(Buffer, (uint*)(Object->Value.Memory.Memory + (IdxUp * sizeof(uint))));
+ break;
+ case OBJ_FAMILY_OBJLIST:
+ {
+ uint OldNbObj;
+ int OldCurObjListId;
+
+ OldCurObjListId = CurObjListId;
+ CurObjListId = (int)Id;
+ CurObjListRank += 1;
+ OldNbObj = Response->NbObj;
+ ManageObjects(Buffer, Size - (*Buffer - Mark), Response);
+ CurObjListId = OldCurObjListId;
+ //Suffix += Response->NbObj - OldNbObj;
+ NbObjs -= 1;
+ //Idx += (Response->NbObj - OldNbObj);
+ goto ContinueDecode;
+ break;
+ }
+ default :
+ break;
+ }
+ Idx += 1;
+ lIdx += 1;
+ContinueDecode:
+ continue ;
+ }
+
+ Level -= 1;
+ if (Level == 0)
+ {
+ Idx = 0;
+ CurObjListId = -1;
+ CurObjListRank = 0;
+ }
+ return (NbObjs);
+}
+
+int ManageObjects(uchar **Buffer, uint Size, SResponse *Response)
+{
+ uchar Mode;
+
+ Mode = **Buffer;
+ *Buffer += 1;
+ switch (Mode)
+ {
+ case RAW_PARAMS:
+ Response->NbObj += DecodeRawObjects(Buffer, Size - 1, Response, &(Response->Objs), Response->NbObj);
+ return 0;
+ case EXT_PARAMS:
+ // Not supported as not needed by plain login
+ //Response->NbObj += DecodeExtObjects(Buffer, Size - 1, Response, &(Response->Objs), Response->NbObj);
+ break;
+ default:
+ break;
+ }
+ return -1;
+}
+
+void FreeResponse(SResponse *Response)
+{
+ uint Idx;
+
+ for (Idx=0; Idx<Response->NbObj; Idx++)
+ {
+ switch (Response->Objs[Idx].Family)
+ {
+ case OBJ_FAMILY_BLOB:
+ case OBJ_FAMILY_STRING:
+ case OBJ_FAMILY_INTLIST:
+ if (Response->Objs[Idx].Value.Memory.Memory) free (Response->Objs[Idx].Value.Memory.Memory);
+ break;
+ }
+ }
+ free (Response->Objs);
+ memset(Response, 0, sizeof(SResponse));
+}
diff --git a/protocols/MSN/src/skylogin/objects.h b/protocols/MSN/src/skylogin/objects.h
new file mode 100644
index 0000000000..1c11ef9a8e
--- /dev/null
+++ b/protocols/MSN/src/skylogin/objects.h
@@ -0,0 +1,136 @@
+#include "common.h"
+
+typedef struct
+{
+ int Id;
+ uint Rank;
+} ObjListInfos_S;
+
+typedef struct
+{
+ uint Family;
+ uint Id;
+ union
+ {
+ Memory_U Memory;
+ uchar Table[8]; /* Actually DOUBLE int */
+ uint Nbr;
+ Host Addr;
+ } Value;
+ ObjListInfos_S ObjListInfos;
+} ObjectDesc;
+
+typedef struct
+{
+ ushort Cmd;
+ ushort PacketID;
+ ushort Reply2ID;
+ uint NbObj;
+ ObjectDesc *Objs;
+} SResponse;
+
+
+
+#define OBJ_FAMILY_NBR 0x00
+#define OBJ_FAMILY_TABLE 0x01
+#define OBJ_FAMILY_NETADDR 0x02
+#define OBJ_FAMILY_STRING 0x03
+#define OBJ_FAMILY_BLOB 0x04
+#define OBJ_FAMILY_OBJLIST 0x05
+#define OBJ_FAMILY_INTLIST 0x06
+
+#define OBJ_ID_NODEID 0x0D
+#define OBJ_ID_LPORT 0x10
+#define OBJ_ID_UPTIME 0x01
+#define OBJ_ID_STVL 0x23
+#define OBJ_ID_2000 0x09
+#define OBJ_ID_SK 0x08
+#define OBJ_ID_ZBOOL1 0x0C
+#define OBJ_ID_REQCODE 0x00
+#define OBJ_ID_ZBOOL2 0x02
+#define OBJ_ID_USERNAME 0x04
+#define OBJ_ID_USERPASS 0x05
+#define OBJ_ID_MODULUS 0x21
+#define OBJ_ID_PLATFORM 0x31
+#define OBJ_ID_LANG 0x36
+#define OBJ_ID_VERSION 0x0D
+#define OBJ_ID_PUBADDR 0x0E
+#define OBJ_ID_MISCD 0x33
+#define OBJ_ID_OAUTH 0x3D
+#define OBJ_ID_PARTNERID 0x3E
+#define OBJ_ID_STACKVER 0x0B
+#define OBJ_ID_STACKTS 0x0C
+#define OBJ_ID_PEERLPORT 0x10
+#define OBJ_ID_PUBNETADDR 0x11
+#define OBJ_ID_NBCONNECTED 0x09
+#define OBJ_ID_LOGINANSWER 0x01
+#define OBJ_ID_CIPHERDLOGD 0x24
+#define OBJ_ID_LDUSER 0x00
+#define OBJ_ID_LDEXPIRY 0x04
+#define OBJ_ID_LDMODULUS 0x01
+#define OBJ_ID_ESAUTHANSWR 0x0A
+#define OBJ_ID_ESHASHLIST 0x35
+#define OBJ_ID_HASH 0x32
+#define OBJ_ID_DISPLAYNAME 0x34
+#define OBJ_ID_UBLOB 0x33
+#define OBJ_ID_INTERNALNAM 0x10
+#define OBJ_ID_BUDDYSTATUS 0x79 // BUDDYSTATUS
+#define OBJ_ID_AUTHCERT 0x03
+#define OBJ_ID_USER2SEARCH 0x00
+#define OBJ_ID_BCMID 0x00
+#define OBJ_ID_BCMVER 0x01
+#define OBJ_ID_SLOTID 0x00
+#define OBJ_ID_SLOTNBSN 0x07
+#define OBJ_ID_SLOTSNADDR 0x03
+#define OBJ_ID_DIRBLOB 0x0B
+
+#define OBJ_ID_CIRNAME 0x14 // FULLNAME
+#define OBJ_ID_CILANG 0x24 // LANGUAGES
+#define OBJ_ID_CICOUNTRY 0x28 // COUNTRY
+#define OBJ_ID_CIREGION 0x2C // PROVINCE
+#define OBJ_ID_CIVILLE 0x30 // CITY
+#define OBJ_ID_CILOCATION 0x03
+#define OBJ_ID_CIPSTN_BAL 0x12D // PSTN_BALANCE
+#define OBJ_ID_CIPSTN_BALC 0x128 // PSTN_BALANCE_CURRENCY
+#define OBJ_ID_CIBIRTHDAY 0x1D // BIRTHDAY
+#define OBJ_ID_CIPHONE_H 0x34 // PHONE_HOME
+#define OBJ_ID_CIPHONE_O 0x38 // PHONE_OFFICE
+#define OBJ_ID_CIPHONE_M 0x3C // PHONE_MOBILE
+#define OBJ_ID_CIHOMEPAGE 0x44 // HOMEPAGE
+#define OBJ_ID_CIABOUT 0x48 // ABOUT
+#define OBJ_ID_CIALIASES 0x60 // ALIASES
+#define OBJ_ID_CIMOOD_TEXT 0x68 // MOOD_TEXT
+#define OBJ_ID_CIRICH_MOOD 0x334 // RICH_MOOD_TEXT
+#define OBJ_ID_CITIMEZONE 0x6D // TIMEZONE
+
+#define OBJ_ID_AUTHEDBUDD 0x71 // NROF_AUTHED_BUDDIES
+#define OBJ_ID_RCVDAUTHREQ 0x50 // RECEIVEDAUTHREQUEST
+#define OBJ_ID_ISAUTHORIZD 0x5D // ISAUTHORIZED / ISBLOCKED
+//#define OBJ_ID_DISPLAYNAME 0x84 // DISPLAYNAME
+#define OBJ_ID_ONLINESTAT 0x89 // ONLINESTATUS
+#define OBJ_ID_LASTONLINET 0x8D // LASTONLINETIMESTAMP
+#define OBJ_ID_CISEX 0x21 // SEX (MALE=1, FEMALE=2, UNKNOWN=0)
+
+
+#define OBJ_ID_FWTESTID 0x19
+#define OBJ_ID_FWTESTER 0x11
+#define OBJ_ID_PINGER 0x02
+#define OBJ_ID_TESTED 0x02
+#define OBJ_ID_TESTER 0x00
+#define OBJ_ID_RELAY 0x08
+#define OBJ_ID_SESPROPOSER 0x01
+#define OBJ_ID_SESCHALLENG 0x09
+#define OBJ_ID_SID2DEC 0x03
+#define OBJ_ID_SOLVEDCHALL 0x0A
+#define OBJ_ID_USRDBLOB 0x05
+#define OBJ_ID_AESPART1 0x06
+#define OBJ_ID_PEERLOGIN 0x00
+#define OBJ_ID_PEERSESSID 0x03
+
+#define OBJ_ID_GROUPID 0x269
+#define OBJ_ID_GROUPNAME 0x25C
+
+void WriteValue(uchar **BufferAddr, uint Value);
+void WriteObject(uchar **Buffer, ObjectDesc Object);
+int ManageObjects(uchar **Buffer, uint Size, SResponse *Response);
+void FreeResponse(SResponse *Response);
diff --git a/protocols/MSN/src/skylogin/platform.h b/protocols/MSN/src/skylogin/platform.h
new file mode 100644
index 0000000000..c5cf2d4438
--- /dev/null
+++ b/protocols/MSN/src/skylogin/platform.h
@@ -0,0 +1,6 @@
+int64_t PlatFormSpecific();
+void InitNodeId(Skype_Inst *pInst);
+void FillMiscDatas(Skype_Inst *pInst, unsigned int *Datas);
+void FillRndBuffer(unsigned char *Buffer);
+Memory_U Credentials_Load(char *pszUser);
+int Credentials_Save(Memory_U creds, char *pszUser);
diff --git a/protocols/MSN/src/skylogin/platform_w32.c b/protocols/MSN/src/skylogin/platform_w32.c
new file mode 100644
index 0000000000..eb75ed4e28
--- /dev/null
+++ b/protocols/MSN/src/skylogin/platform_w32.c
@@ -0,0 +1,195 @@
+/*
+ * Skype Login
+ *
+ * Based on:
+ * FakeSkype : Skype reverse engineering proof-of-concept client
+ * Ouanilo MEDEGAN (c) 2006 http://www.oklabs.net
+ * pyskype : Skype login Python script by uunicorn
+ *
+ * Written by: leecher@dose.0wnz.at (c) 2015
+ *
+ * Module: WINDOWS platform specific functions
+ *
+ */
+#include <rpc.h>
+#include "common.h"
+#include "random.h"
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#pragma comment (lib,"rpcrt4.lib")
+
+static uchar RandomSeed[SHA_DIGEST_LENGTH] = {0};
+
+static BOOL QueryRegValue(HKEY hKey, LPCTSTR lpSubKey, LPBYTE lpValue, LPDWORD pCbValue)
+{
+ char *pSubKey, *pTok, szKey[256]={0};
+ DWORD dwIndex;
+ LONG ret;
+
+ if ( !lpSubKey || !*lpSubKey ) return FALSE;
+ if ( *lpSubKey != '*' )
+ {
+ for (pSubKey = (char*)lpSubKey; *pSubKey != '*'; pSubKey = pTok + 1)
+ if (!(pTok = strchr(pSubKey, '\\'))) break;
+ if ( pSubKey > lpSubKey )
+ {
+ if ( pSubKey - lpSubKey == 1 ) return FALSE;
+ strncpy (szKey, lpSubKey, pSubKey - lpSubKey - 1);
+ if (RegOpenKeyA (hKey, szKey, &hKey) == ERROR_SUCCESS)
+ {
+ ret = QueryRegValue(hKey, pSubKey, lpValue, pCbValue);
+ RegCloseKey(hKey);
+ return ret;
+ }
+ return FALSE;
+ }
+ if ( *lpSubKey != '*' ) return RegQueryValueExA (hKey, lpSubKey, NULL, NULL, lpValue, pCbValue) == ERROR_SUCCESS;
+ }
+ if (lpSubKey[1] != '\\')
+ return RegQueryValueExA (hKey, lpSubKey, NULL, NULL, lpValue, pCbValue) == ERROR_SUCCESS;
+ for (dwIndex = 0; (ret = RegEnumKeyA (hKey, dwIndex, szKey, sizeof(szKey))) == ERROR_SUCCESS; dwIndex++)
+ {
+ char szSubKey[256];
+
+ sprintf (szSubKey, "%s%s", szKey, lpSubKey+1);
+ if (QueryRegValue (hKey, szSubKey, lpValue, pCbValue)) break;
+ }
+ return ret == ERROR_SUCCESS;
+}
+
+int64_t PlatFormSpecific()
+{
+ BYTE Buffer[0x400];
+ DWORD BufSz = 0x400;
+ int Idx, Used;
+
+ Used = Idx = 0;
+
+ if (QueryRegValue(HKEY_LOCAL_MACHINE,
+ "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\ProductId",
+ (LPBYTE)Buffer, &BufSz))
+ Used += BufSz;
+ BufSz = sizeof(Buffer)-Used;
+ if (QueryRegValue(HKEY_LOCAL_MACHINE,
+ "HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter\\*\\DiskController\\*\\DiskPeripheral\\*\\Identifier",
+ (LPBYTE)Buffer + Used, &BufSz))
+ Used += BufSz;
+ if (GetVolumeInformationA("C:\\", 0, 0, (LPDWORD)(Buffer + Used), 0, 0, 0, 0))
+ Used+=4;
+ return BytesSHA1I64(Buffer, Used);
+}
+
+void InitNodeId(Skype_Inst *pInst)
+{
+ DWORD BufSz = sizeof(pInst->NodeID);
+ HKEY hKey;
+
+ if (QueryRegValue(HKEY_LOCAL_MACHINE,
+ "SOFTWARE\\FakeSkype\\NodeId",
+ (LPBYTE)&pInst->NodeID, &BufSz)) return;
+ *(int64_t *)&pInst->NodeID = BytesRandomI64();
+ if (RegCreateKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\FakeSkype", &hKey) == ERROR_SUCCESS)
+ {
+ RegSetValueEx(hKey, "NodeId", 0, REG_BINARY, (LPBYTE)&pInst->NodeID, sizeof(pInst->NodeID));
+ RegCloseKey(hKey);
+ }
+
+ //FIXED NODEID
+ //memcpy_s(NodeID, NODEID_SZ, "\x49\x63\xff\xee\xe0\x5c\x9d\xf8", NODEID_SZ);
+ //memcpy_s(NodeID, NODEID_SZ, "\x97\xca\xb1\x72\x06\xf6\x72\xb4", NODEID_SZ);
+}
+
+Memory_U Credentials_Load(char *pszUser)
+{
+ Memory_U creds={0};
+ HKEY hKey;
+ char szKey[MAX_PATH];
+
+ sprintf (szKey, "SOFTWARE\\FakeSkype\\%s", pszUser);
+ if (RegCreateKey(HKEY_LOCAL_MACHINE, szKey, &hKey) == ERROR_SUCCESS)
+ {
+ if (RegQueryValueEx(hKey, "Credentials", NULL, NULL, NULL, &creds.MsZ) == ERROR_SUCCESS &&
+ creds.MsZ)
+ {
+ if (!(creds.Memory = malloc(creds.MsZ)))
+ creds.MsZ = 0;
+ if (creds.Memory && RegQueryValueEx(hKey, "Credentials", NULL, NULL, creds.Memory, &creds.MsZ) != ERROR_SUCCESS)
+ {
+ free(creds.Memory);
+ ZeroMemory(&creds, sizeof(creds));
+ }
+ }
+ RegCloseKey(hKey);
+ }
+ return creds;
+}
+
+int Credentials_Save(Memory_U creds, char *pszUser)
+{
+ HKEY hKey;
+ int iRet = 0;
+
+ char szKey[MAX_PATH];
+
+ sprintf (szKey, "SOFTWARE\\FakeSkype\\%s", pszUser);
+ if (RegCreateKey(HKEY_LOCAL_MACHINE, szKey, &hKey) == ERROR_SUCCESS)
+ {
+ iRet = RegSetValueEx(hKey, "Credentials", 0, REG_BINARY, creds.Memory, creds.MsZ) == ERROR_SUCCESS;
+ RegCloseKey(hKey);
+ }
+ return iRet;
+}
+
+void FillMiscDatas(Skype_Inst *pInst, unsigned int *Datas)
+{
+ BYTE Buffer[0x400];
+ DWORD BufSz = 0x400;
+ int ret;
+ int64_t PlatForm;
+
+ PlatForm = PlatFormSpecific();
+ Datas[0] = *(unsigned int *)&PlatForm;
+ Datas[1] = *(unsigned int *)&pInst->NodeID;
+
+ if (!QueryRegValue(HKEY_LOCAL_MACHINE,
+ "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\ProductId",
+ (LPBYTE)Buffer, &BufSz))
+ return;
+ Datas[2] = BytesSHA1(Buffer, BufSz);
+
+ BufSz = 0x400;
+ if (!QueryRegValue(HKEY_LOCAL_MACHINE,
+ "HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter\\*\\DiskController\\*\\DiskPeripheral\\*\\Identifier",
+ (LPBYTE)Buffer, &BufSz))
+ return;
+ Datas[3] = BytesSHA1(Buffer, BufSz);
+
+ ret = GetVolumeInformationA("C:\\", 0, 0, (LPDWORD)Buffer, 0, 0, 0, 0);
+ Datas[4] = BytesSHA1(Buffer, 0x04);
+}
+
+void FillRndBuffer(unsigned char *Buffer)
+{
+ SHA_CTX Context;
+ int idx;
+
+ idx = 0;
+ memcpy(Buffer, RandomSeed, SHA_DIGEST_LENGTH);
+ idx += sizeof(RandomSeed);
+ GlobalMemoryStatus((LPMEMORYSTATUS)&Buffer[idx]);
+ idx += sizeof(MEMORYSTATUS);
+ UuidCreate((UUID *)&Buffer[idx]);
+ idx += sizeof(UUID);
+ GetCursorPos((LPPOINT)&Buffer[idx]);
+ idx += sizeof(POINT);
+ *(DWORD *)(Buffer + idx) = GetTickCount();
+ *(DWORD *)(Buffer + idx + 4) = GetMessageTime();
+ *(DWORD *)(Buffer + idx + 8) = GetCurrentThreadId();
+ *(DWORD *)(Buffer + idx + 12) = GetCurrentProcessId();
+ idx += 16;
+ QueryPerformanceCounter((LARGE_INTEGER *)&Buffer[idx]);
+ SHA1_Init(&Context);
+ SHA1_Update(&Context, Buffer, 0x464);
+ SHA1_Update(&Context, "additional salt...", 0x13);
+ SHA1_Final(RandomSeed, &Context);
+}
diff --git a/protocols/MSN/src/skylogin/random.c b/protocols/MSN/src/skylogin/random.c
new file mode 100644
index 0000000000..3e41ec4da5
--- /dev/null
+++ b/protocols/MSN/src/skylogin/random.c
@@ -0,0 +1,178 @@
+/*
+ * Skype Login
+ *
+ * Based on:
+ * FakeSkype : Skype reverse engineering proof-of-concept client
+ * Ouanilo MEDEGAN (c) 2006 http://www.oklabs.net
+ * pyskype : Skype login Python script by uunicorn
+ *
+ * Written by: leecher@dose.0wnz.at (c) 2015
+ *
+ * Module: Data creation functions, i.e. random data
+ *
+ */
+#include <string.h>
+#include "common.h"
+#include "random.h"
+#include "platform.h"
+
+#define skrand(x) ((x)*0x00010DCD+0x00004271)
+
+unsigned int BytesSHA1(uchar *Data, uint Length)
+{
+ uchar Buffer[SHA_DIGEST_LENGTH];
+ SHA_CTX Context;
+
+ SHA1_Init(&Context);
+ SHA1_Update(&Context, Data, Length);
+ SHA1_Final(Buffer, &Context);
+ return *(unsigned int *)Buffer;
+}
+
+int64_t BytesSHA1I64(uchar *Data, uint Length)
+{
+ uchar Buffer[SHA_DIGEST_LENGTH];
+ SHA_CTX Context;
+
+ SHA1_Init(&Context);
+ SHA1_Update(&Context, Data, Length);
+ SHA1_Final(Buffer, &Context);
+ return *(int64_t *)Buffer;
+}
+
+unsigned int BytesRandom()
+{
+ uchar Buffer[0x464];
+
+ FillRndBuffer(Buffer);
+ return BytesSHA1(Buffer, 0x464);
+}
+
+int64_t BytesRandomI64()
+{
+ uchar Buffer[0x464];
+
+ FillRndBuffer(Buffer);
+ return BytesSHA1I64(Buffer, 0x464);
+}
+
+unsigned short BytesRandomWord()
+{
+ unsigned short RandomW;
+ unsigned int RandomDW;
+
+ RandomDW = BytesRandom();
+ RandomW = *(unsigned short *)&RandomDW;
+ RandomW += 0;
+ return (RandomW);
+}
+
+void SpecialSHA(uchar *SessionKey, uint SkSz, uchar *SHAResult, uint ResSz)
+{
+ SHA_CTX Context;
+ uchar Buffer[SHA_DIGEST_LENGTH];
+ char *Salts[] = {"\x00\x00\x00\x00", "\x00\x00\x00\x01"};
+ uint Idx = 0;
+
+ if (ResSz > 40)
+ return ;
+ while (ResSz > 20)
+ {
+ SHA1_Init(&Context);
+ SHA1_Update(&Context, Salts[Idx], 0x04);
+ SHA1_Update(&Context, SessionKey, SkSz);
+ SHA1_Final(Buffer, &Context);
+ memcpy(SHAResult + (Idx * SHA_DIGEST_LENGTH), Buffer, SHA_DIGEST_LENGTH);
+ Idx++;
+ ResSz -= SHA_DIGEST_LENGTH;
+ }
+
+ SHA1_Init(&Context);
+ SHA1_Update(&Context, Salts[Idx], 0x04);
+ SHA1_Update(&Context, SessionKey, SkSz);
+ SHA1_Final(Buffer, &Context);
+ memcpy(SHAResult + (Idx * SHA_DIGEST_LENGTH), Buffer, ResSz);
+}
+
+void BuildUnFinalizedDatas(uchar *Datas, uint Size, uchar *Result)
+{
+ uchar *Mark;
+ uint Idx;
+ SHA_CTX MDCtx;
+
+ Result[0x00] = 0x4B;
+ for (Idx = 1; Idx < (0x80 - (Size + SHA_DIGEST_LENGTH) - 2); Idx++)
+ Result[Idx] = 0xBB;
+ Result[Idx++] = 0xBA;
+
+ Mark = Result + Idx;
+
+ memcpy(Result + Idx, Datas, Size);
+ Idx += Size;
+
+ SHA1_Init(&MDCtx);
+ SHA1_Update(&MDCtx, Mark, Size);
+ SHA1_Final(Result + Idx, &MDCtx);
+ Idx += SHA_DIGEST_LENGTH;
+
+ Result[Idx] = 0xBC;
+}
+
+uchar *FinalizeLoginDatas(uchar *Buffer, uint *Size, uchar *Suite, int SuiteSz)
+{
+ int Idx;
+ uchar *Result;
+ SHA_CTX Context;
+ uchar SHARes[SHA_DIGEST_LENGTH] = {0};
+
+ Idx = 0;
+ if (Buffer[*Size - 1] != 0xBC)
+ return (NULL);
+ if (SuiteSz)
+ {
+ if (*Buffer != 0x6A)
+ return (NULL);
+ *Size = 0x6A + SuiteSz;
+ Idx += 1;
+ goto Copy;
+ }
+ while ((Buffer[Idx] & 0x0F) == 0x0B)
+ Idx++;
+ if ((Buffer[Idx] & 0x0F) != 0x0A)
+ return (NULL);
+ Idx += 1;
+ *Size = (*Size - 0x15) - Idx;
+
+Copy:
+ Result = (uchar *)malloc(*Size);
+ memcpy(Result, Buffer + Idx, *Size - SuiteSz);
+ if (SuiteSz) memcpy(Result + (*Size - SuiteSz), Suite, SuiteSz);
+
+ SHA1_Init(&Context);
+ SHA1_Update(&Context, Result, *Size);
+ SHA1_Final(SHARes, &Context);
+
+ if (strncmp((char *)SHARes, (char *)(Buffer + Idx + (*Size - SuiteSz)), SHA_DIGEST_LENGTH))
+ {
+ DBGPRINT("Bad SHA Digest for unencrypted Datas..\n");
+ free(Result);
+ return (NULL);
+ }
+
+ return (Result);
+}
+
+void GenSessionKey(uchar *Buffer, uint Size)
+{
+ uint Idx, Rander;
+
+ Rander = BytesRandom();
+ for (Idx = 0; Idx < Size; Idx++)
+ {
+ Rander = skrand(Rander);
+ Buffer[Idx] = ((uchar *)&Rander)[sizeof(Rander) - 1];
+ //Buffer[Idx] = (uchar)(Idx + 1);
+ }
+ Buffer[0] = 0x01;
+}
+
diff --git a/protocols/MSN/src/skylogin/random.h b/protocols/MSN/src/skylogin/random.h
new file mode 100644
index 0000000000..d87d1f784d
--- /dev/null
+++ b/protocols/MSN/src/skylogin/random.h
@@ -0,0 +1,7 @@
+unsigned int BytesSHA1(uchar *Data, uint Length);
+void GenSessionKey(uchar *Buffer, uint Size);
+void SpecialSHA(uchar *SessionKey, uint SkSz, uchar *SHAResult, uint ResSz);
+uchar *FinalizeLoginDatas(uchar *Buffer, uint *Size, uchar *Suite, int SuiteSz);
+int64_t BytesSHA1I64(uchar *Data, uint Length);
+int64_t BytesRandomI64();
+void BuildUnFinalizedDatas(uchar *Datas, uint Size, uchar *Result);
diff --git a/protocols/MSN/src/skylogin/rc4comm.c b/protocols/MSN/src/skylogin/rc4comm.c
new file mode 100644
index 0000000000..00890e245f
--- /dev/null
+++ b/protocols/MSN/src/skylogin/rc4comm.c
@@ -0,0 +1,83 @@
+/*
+ * Skype Login
+ *
+ * Based on:
+ * FakeSkype : Skype reverse engineering proof-of-concept client
+ * Ouanilo MEDEGAN (c) 2006 http://www.oklabs.net
+ * pyskype : Skype login Python script by uunicorn
+ *
+ * Written by: leecher@dose.0wnz.at (c) 2015
+ *
+ * Module: RC4 wrapped communication layer
+ *
+ */
+#include "common.h"
+#include "rc4comm.h"
+#ifdef USE_RC4
+#ifdef _WIN32
+#define alloca _alloca
+#endif
+
+static char *SkypeDHModulus348 = "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b13b202ffffffffffffffff";
+
+int RC4Comm_Init(LSConnection *pConn)
+{
+ DH *dh;
+ char pub_key[96], sec_key[48], ls_keybuf[1024];
+ BIGNUM *ls_key;
+ int ret = 0;
+
+ if (!(dh = DH_new())) return -1;
+ BN_hex2bn(&dh->g, "2");
+ BN_hex2bn(&dh->p, SkypeDHModulus348);
+ DH_generate_key(dh);
+ if (send(pConn->LSSock, pub_key, BN_bn2bin(dh->pub_key, pub_key), 0)>0)
+ {
+ if (recv(pConn->LSSock, ls_keybuf, sizeof(ls_keybuf), 0)>0)
+ {
+ ls_key = BN_bin2bn(ls_keybuf, 48, NULL);
+ if (DH_compute_key(sec_key, ls_key, dh)<=0) ret = -3; else
+ {
+ MD5_CTX Context;
+ uchar BufHash[MD5_DIGEST_LENGTH];
+
+ MD5_Init(&Context);
+ MD5_Update(&Context, "O", 1);
+ MD5_Update(&Context, sec_key, 48);
+ MD5_Final(BufHash, &Context);
+ if (send(pConn->LSSock, BufHash, 8, 0)>0)
+ {
+ /* Setup RC4 */
+ RC4_set_key(&pConn->rc4_send, 48, sec_key);
+ if (sec_key[0] == 0xFF) {DBGPRINT("First byte overflow, negotiation failed?");}
+ sec_key[0]++;
+ RC4_set_key(&pConn->rc4_recv, 48, sec_key);
+ } else
+ ret=-1;
+ }
+ BN_free(ls_key);
+ } else
+ ret=-1;
+ } else
+ ret=-1;
+
+ DH_free(dh);
+ return ret;
+}
+
+int RC4Comm_Send (LSConnection *pConn, const char * buf, int len)
+{
+ char *out = alloca(len);
+
+ RC4(&pConn->rc4_send, len, buf, out);
+ return send(pConn->LSSock, out, len, 0);
+}
+
+int RC4Comm_Recv (LSConnection *pConn, char * buf, int len)
+{
+ int ret = recv(pConn->LSSock, buf, len, 0);
+ if (ret > 0) RC4(&pConn->rc4_recv, ret, buf, buf);
+ return ret;
+}
+
+#endif
diff --git a/protocols/MSN/src/skylogin/rc4comm.h b/protocols/MSN/src/skylogin/rc4comm.h
new file mode 100644
index 0000000000..c9c24bb7b1
--- /dev/null
+++ b/protocols/MSN/src/skylogin/rc4comm.h
@@ -0,0 +1,3 @@
+int RC4Comm_Init(LSConnection *pConn);
+int RC4Comm_Send (LSConnection *pConn, const char * buf, int len);
+int RC4Comm_Recv (LSConnection *pConn, char * buf, int len);
diff --git a/protocols/MSN/src/skylogin/skylogin.c b/protocols/MSN/src/skylogin/skylogin.c
new file mode 100644
index 0000000000..4e42d552d1
--- /dev/null
+++ b/protocols/MSN/src/skylogin/skylogin.c
@@ -0,0 +1,165 @@
+/*
+ * Skype Login
+ *
+ * Based on:
+ * FakeSkype : Skype reverse engineering proof-of-concept client
+ * Ouanilo MEDEGAN (c) 2006 http://www.oklabs.net
+ * pyskype : Skype login Python script by uunicorn
+ *
+ * Written by: leecher@dose.0wnz.at (c) 2015
+ *
+ * Module: Main module which contains public functions of library
+ *
+ */
+#ifdef _WIN32
+#define EXPORT __declspec(dllexport)
+#define strcasecmp stricmp
+#endif
+#include <time.h>
+#include "common.h"
+#include "login.h"
+#include "platform.h"
+#include "uic.h"
+#include "objects.h"
+#include "credentials.h"
+#include "skylogin.h"
+
+EXPORT SkyLogin SkyLogin_Init()
+{
+ Skype_Inst *pInst = calloc(1, sizeof(Skype_Inst));
+
+#ifdef _WIN32
+ WORD wVersionRequested;
+ WSADATA wsaData;
+
+ wVersionRequested = MAKEWORD( 2, 2 );
+ WSAStartup( wVersionRequested, &wsaData);
+#endif
+
+ if (pInst) InitInstance(pInst);
+ return (SkyLogin*)pInst;
+}
+
+EXPORT void SkyLogin_Exit(SkyLogin pPInst)
+{
+ Skype_Inst *pInst = (Skype_Inst*)pPInst;
+ if (pInst->LoginD.User) free(pInst->LoginD.User);
+ if (pInst->LoginD.RSAKeys) RSA_free(pInst->LoginD.RSAKeys);
+ if (pInst->LoginD.SignedCredentials.Memory) free(pInst->LoginD.SignedCredentials.Memory);
+ free(pInst);
+}
+
+EXPORT int SkyLogin_LoadCredentials(SkyLogin pPInst, char *User)
+{
+ Skype_Inst *pInst = (Skype_Inst*)pPInst;
+
+ Memory_U creds = Credentials_Load(User);
+ int ret = 0;
+
+ if (creds.Memory)
+ {
+ // Credentials were found and loaded, now let's parse them.
+ SResponse LoginDatas;
+
+ if (Credentials_Read(pInst, creds, &LoginDatas) == 0)
+ {
+ // Credentials were successfully read :)
+ // Now verify if they are still valid
+ uint Idx;
+ time_t t;
+
+ for (Idx = 0, ret = 1; ret && Idx < LoginDatas.NbObj; Idx++)
+ {
+ switch (LoginDatas.Objs[Idx].Id)
+ {
+ case OBJ_ID_LDUSER:
+ // Credentials for wrong user?
+ ret = !strcasecmp(LoginDatas.Objs[Idx].Value.Memory.Memory, User);
+ if (pInst->LoginD.User) free(pInst->LoginD.User);
+ pInst->LoginD.User = strdup(LoginDatas.Objs[Idx].Value.Memory.Memory);
+ break;
+ case OBJ_ID_LDEXPIRY:
+ // Credentials expired?
+ ret = (int)LoginDatas.Objs[Idx].Value.Nbr * 60 > time(&t)-60;
+ break;
+ }
+ }
+ FreeResponse(&LoginDatas);
+ }
+ free(creds.Memory);
+ }
+ return ret;
+}
+
+EXPORT int SkyLogin_PerformLogin(SkyLogin pPInst, char *User, char *Pass)
+{
+ int ret;
+ Skype_Inst *pInst = (Skype_Inst*)pPInst;
+
+ if ((ret = PerformLogin(pInst, User, Pass)) > 0)
+ {
+ // On successful login, save login datas
+ Memory_U creds = Credentials_Write(pInst);
+ if (creds.Memory)
+ {
+ Credentials_Save(creds, User);
+ free (creds.Memory);
+ }
+
+ if (pInst->LoginD.User) free(pInst->LoginD.User);
+ pInst->LoginD.User = strdup(User);
+ }
+ return ret;
+}
+
+EXPORT int SkyLogin_PerformLoginOAuth(SkyLogin pPInst, const char *OAuth)
+{
+ int ret;
+ Skype_Inst *pInst = (Skype_Inst*)pPInst;
+
+ if ((ret = PerformLogin(pInst, OAuth, NULL)) > 0)
+ {
+ // On successful login, save login datas
+ Memory_U creds = Credentials_Write(pInst);
+ if (creds.Memory)
+ {
+ SResponse LoginDatas;
+
+ // We don't know user name, so read it from Credentials
+ if (Credentials_Parse(creds, &LoginDatas) == 0)
+ {
+ uint Idx;
+
+ for (Idx = 0; Idx < LoginDatas.NbObj; Idx++)
+ {
+ if (LoginDatas.Objs[Idx].Id == OBJ_ID_LDUSER)
+ {
+ Credentials_Save(creds, LoginDatas.Objs[Idx].Value.Memory.Memory);
+ if (pInst->LoginD.User) free(pInst->LoginD.User);
+ pInst->LoginD.User = strdup(LoginDatas.Objs[Idx].Value.Memory.Memory);
+ break;
+ }
+ }
+ FreeResponse(&LoginDatas);
+ }
+ free (creds.Memory);
+ }
+ }
+ return ret;
+}
+
+
+EXPORT int SkyLogin_CreateUICString(SkyLogin pInst, const char *pszNonce, char *pszOutUIC)
+{
+ return CreateUICString((Skype_Inst*)pInst, pszNonce, "WS-SecureConversationSESSION KEY TOKEN", pszOutUIC);
+}
+
+EXPORT int SkyLogin_GetCredentialsUIC(SkyLogin pInst, char *pszOutUIC)
+{
+ return GetCredentialsUIC((Skype_Inst*)pInst, pszOutUIC);
+}
+
+EXPORT char *SkyLogin_GetUser(SkyLogin pInst)
+{
+ return ((Skype_Inst*)pInst)->LoginD.User;
+}
diff --git a/protocols/MSN/src/skylogin/skylogin.h b/protocols/MSN/src/skylogin/skylogin.h
new file mode 100644
index 0000000000..c03b2d6283
--- /dev/null
+++ b/protocols/MSN/src/skylogin/skylogin.h
@@ -0,0 +1,57 @@
+typedef void* SkyLogin;
+
+/* Size of the buffer you should supply as pszOutUIC on SkyLogin_CreateUICString */
+#define UICSTR_SIZE 1024
+
+#ifndef EXPORT
+#define EXPORT
+#endif
+
+/* Initialize SkyLogin Instance */
+EXPORT SkyLogin SkyLogin_Init();
+
+/* Uninitialize Skylogin Instance */
+EXPORT void SkyLogin_Exit(SkyLogin pInst);
+
+/* Load Credentials from cache, if they are available and valid
+ * Returns:
+ * 1 if credentials are successfully loaded,
+ * 0 if they are invalid or don't exist */
+EXPORT int SkyLogin_LoadCredentials(SkyLogin pInst, char *pszUser);
+
+/* Perform login with Username and Password
+ * Returns:
+ * 1 on success, 0 on failure, -1 on socket error, -2 on bad response */
+EXPORT int SkyLogin_PerformLogin(SkyLogin pInst, char *pszUser, char *pszPass);
+
+/* Perform login with OAuth token
+ * Returns:
+ * 1 on success, 0 on failure, -1 on socket error, -2 on bad response */
+EXPORT int SkyLogin_PerformLoginOAuth(SkyLogin pInst, const char *OAuth);
+
+/* Creates UIC string from nonce pszNonce and places it in pszOutUIC
+ * pszOutUIC buffer should be at least UICSTR_SIZE in size.
+ *
+ * Returns:
+ * Size of UIC string in Bytes on success, 0 on failure
+ */
+EXPORT int SkyLogin_CreateUICString(SkyLogin pInst, const char *pszNonce, char *pszOutUIC);
+
+/* Gets the base64 encoded signed Credentials after login. They are required if
+ * you do OAUTH-Login instead of UICString from above.
+ * pszOutUIC buffer should be at least UICSTR_SIZE in size.
+ *
+ * Returns:
+ * Size of UIC string in Bytes on success, 0 on failure
+ */
+EXPORT int SkyLogin_GetCredentialsUIC(SkyLogin pInst, char *pszOutUIC);
+
+/* Gets the Skype username of the currently loaded login credentials.
+ * This can be useful if you do OAuth login and want to get the assigned
+ * Skype username without the need to query it seperately so that you can
+ * i.e. store it in your DB for later calls of SkyLogin_LoadCredentials()
+ *
+ * Returns:
+ * Pointer to the username, NULL if it doesn't exist. Ne need to free()!
+ */
+EXPORT char *SkyLogin_GetUser(SkyLogin pInst);
diff --git a/protocols/MSN/src/skylogin/uic.c b/protocols/MSN/src/skylogin/uic.c
new file mode 100644
index 0000000000..fe7ab64f94
--- /dev/null
+++ b/protocols/MSN/src/skylogin/uic.c
@@ -0,0 +1,105 @@
+/*
+ * Skype Login
+ *
+ * Based on:
+ * FakeSkype : Skype reverse engineering proof-of-concept client
+ * Ouanilo MEDEGAN (c) 2006 http://www.oklabs.net
+ * pyskype : Skype login Python script by uunicorn
+ *
+ * Written by: leecher@dose.0wnz.at (c) 2015
+ *
+ * Module: UIC generation
+ *
+ */
+#include "common.h"
+#include "random.h"
+#include "skylogin.h"
+
+#ifndef CRYPT_WOLFSSL
+/* OpenSSL Base64_Encode */
+#include <openssl/evp.h>
+#include <openssl/buffer.h>
+
+static int Base64_Encode(const uchar* in, uint inLen, uchar* out, uint* outLen)
+{
+ BIO *bmem, *b64;
+ BUF_MEM *bptr;
+ int ret=0;
+
+ b64 = BIO_new(BIO_f_base64());
+ bmem = BIO_new(BIO_s_mem());
+ b64 = BIO_push(b64, bmem);
+ BIO_write(b64, in, inLen);
+ BIO_flush(b64);
+ BIO_get_mem_ptr(b64, &bptr);
+ if (*outLen>(uint)bptr->length) *outLen=bptr->length; else ret=-1;
+ memcpy(out, bptr->data, *outLen);
+ BIO_free_all(b64);
+ return ret;
+}
+#endif
+
+
+Memory_U CreateUIC(Skype_Inst *pInst, const char *pszNonce, const char *pszSalt)
+{
+ Memory_U uic_pkt, uic={0};
+ SHA_CTX CredCtx;
+ uchar *p;
+ uchar SignedChallenge[0x80] = {0};
+ int cbSalt = strlen(pszSalt), cbNonce = strlen(pszNonce);
+
+ if (!(uic_pkt.Memory = (uchar*)malloc(uic_pkt.MsZ = SHA_DIGEST_LENGTH + cbSalt + cbNonce)))
+ return uic;
+ SHA1_Init(&CredCtx);
+ SHA1_Update(&CredCtx, pInst->LoginD.SignedCredentials.Memory, pInst->LoginD.SignedCredentials.MsZ);
+ SHA1_Update(&CredCtx, pszSalt, cbSalt);
+ SHA1_Final(uic_pkt.Memory, &CredCtx);
+ p = uic_pkt.Memory + SHA_DIGEST_LENGTH;
+ memcpy(p, pszSalt, cbSalt);
+ p+=cbSalt;
+ memcpy(p, pszNonce, cbNonce);
+ BuildUnFinalizedDatas(uic_pkt.Memory, uic_pkt.MsZ, SignedChallenge);
+ if (RSA_private_encrypt(sizeof(SignedChallenge), SignedChallenge, SignedChallenge,
+ pInst->LoginD.RSAKeys, RSA_NO_PADDING)<0)
+ return uic;
+ free (uic_pkt.Memory);
+ if (!(uic.Memory = (uchar*)malloc(uic.MsZ = sizeof(SignedChallenge) + pInst->LoginD.SignedCredentials.MsZ + 4)))
+ {
+ uic.MsZ=0;
+ return uic;
+ }
+ p = uic.Memory;
+ *((uint*)p) = htonl(pInst->LoginD.SignedCredentials.MsZ);
+ p+=sizeof(uint);
+ memcpy(p, pInst->LoginD.SignedCredentials.Memory, pInst->LoginD.SignedCredentials.MsZ);
+ p+=pInst->LoginD.SignedCredentials.MsZ;
+ memcpy(p, SignedChallenge, sizeof(SignedChallenge));
+ return uic;
+}
+
+
+int CreateUICString(Skype_Inst *pInst, const char *pszNonce, const char *pszSalt, char *pszOutUIC)
+{
+ Memory_U uic = CreateUIC(pInst, pszNonce, pszSalt);
+ uint outlen = UICSTR_SIZE;
+
+ if (uic.MsZ && uic.Memory)
+ {
+ Base64_Encode(uic.Memory, uic.MsZ, pszOutUIC, &outlen);
+ pszOutUIC[outlen]=0;
+ free(uic.Memory);
+ } else return 0;
+ return outlen;
+}
+
+int GetCredentialsUIC(Skype_Inst *pInst, char *pszOutUIC)
+{
+ uint outlen = UICSTR_SIZE;
+
+ if (pInst->LoginD.SignedCredentials.MsZ)
+ {
+ Base64_Encode(pInst->LoginD.SignedCredentials.Memory, pInst->LoginD.SignedCredentials.MsZ, pszOutUIC, &outlen);
+ pszOutUIC[outlen]=0;
+ } else return 0;
+ return outlen;
+}
diff --git a/protocols/MSN/src/skylogin/uic.h b/protocols/MSN/src/skylogin/uic.h
new file mode 100644
index 0000000000..ad870035a8
--- /dev/null
+++ b/protocols/MSN/src/skylogin/uic.h
@@ -0,0 +1,3 @@
+Memory_U CreateUIC(Skype_Inst *pInst, const char *pszNonce, const char *pszSalt);
+int CreateUICString(Skype_Inst *pInst, const char *pszNonce, const char *pszSalt, char *pszOutUIC);
+int GetCredentialsUIC(Skype_Inst *pInst, char *pszOutUIC);