Advertisement
Guest User

Untitled

a guest
Mar 6th, 2018
80
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.08 KB | None | 0 0
  1. package org.darkmeyer.net.protocol;
  2.  
  3. import java.math.BigInteger;
  4. import java.security.SecureRandom;
  5.  
  6. import org.apache.mina.core.buffer.IoBuffer;
  7. import org.apache.mina.core.session.IoSession;
  8. import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
  9. import org.apache.mina.filter.codec.ProtocolCodecFilter;
  10. import org.apache.mina.filter.codec.ProtocolDecoderOutput;
  11. import org.darkmeyer.Server;
  12. import org.darkmeyer.cache.Cache;
  13. import org.darkmeyer.cache.UpdateServer;
  14. import org.darkmeyer.game.Constants;
  15. import org.darkmeyer.game.RS2Server;
  16. import org.darkmeyer.game.world.entity.player.PlayerDetails;
  17. import org.darkmeyer.net.PacketBuilder;
  18. import org.darkmeyer.utility.IoBufferUtils;
  19. import org.darkmeyer.utility.TextUtils;
  20. import org.darkmeyer.website.impl.PlayerManager;
  21.  
  22. /**
  23. * Login protocol decoding class.
  24. *
  25. * @author Graham Edgecombe
  26. *
  27. */
  28. public class RS2LoginDecoder extends CumulativeProtocolDecoder {
  29.  
  30. /**
  31. * Opcode stage.
  32. */
  33. private static final int STATE_OPCODE = 0;
  34.  
  35. /**
  36. * Login stage.
  37. */
  38. private static final int STATE_LOGIN = 1;
  39.  
  40. /**
  41. * Precrypted stage.
  42. */
  43. private static final int STATE_PRECRYPTED = 2;
  44.  
  45. /**
  46. * Crypted stage.
  47. */
  48. private static final int STATE_CRYPTED = 3;
  49.  
  50. /**
  51. * Update stage.
  52. */
  53. private static final int STATE_UPDATE = -1;
  54.  
  55. /**
  56. * World stage.
  57. */
  58. public static final int STATE_WORLD = -2;
  59.  
  60. /**
  61. * Game opcode.
  62. */
  63. private static final int OPCODE_GAME = 14;
  64.  
  65. /**
  66. * Update opcode.
  67. */
  68. private static final int OPCODE_UPDATE = 15;
  69.  
  70. /**
  71. * Creation opcode.
  72. */
  73. public static final int OPCODE_BIRTH = 20;
  74.  
  75. /**
  76. * Creation opcode.
  77. */
  78. public static final int OPCODE_USERNAME = 21;
  79.  
  80. /**
  81. * Creation opcode.
  82. */
  83. public static final int OPCODE_CONFIRM = 22;
  84.  
  85. /**
  86. * World opcode.
  87. */
  88. public static final int OPCODE_WORLD = 255;
  89.  
  90. /**
  91. * Secure random number generator.
  92. */
  93. private static final SecureRandom RANDOM = new SecureRandom();
  94.  
  95. /**
  96. * The name hash is a simple hash of the name which is suspected to be used
  97. * to select the appropriate login server.
  98. */
  99. private int nameHashCode;
  100.  
  101. private static final BigInteger RSA_MODULUS = new BigInteger("125498824615949350413874884977165023857837620717675913416022592156144512829309361522499485234195039331502997944944451037585403884172514528660074650075696016312742090328026374541501140572023823295937082249637679411659266953715582336176458793896511013722964252960671897268005422957383371176404977134935689179731");
  102.  
  103. private static final BigInteger RSA_EXPONENT = new BigInteger("58801782313532152877898837191110462602844497297369032352195030857969231967432176698222251447066955654858515920707527930957092895178073510102154695513593800142844432039991902404675980615338532723208252107984745718385941397714011167941039598108432442828522345374662573784309558472354555033932567667781343503425");
  104.  
  105. @SuppressWarnings("unused")
  106. @Override
  107. protected boolean doDecode(final IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
  108. int state = (Integer) session.getAttribute("state", STATE_OPCODE);
  109. if (!RS2Server.getEngine().isRunning() && state != STATE_LOGIN) {
  110. //System.out.println("Cannot serve cache when it has yet to be loaded.");
  111. session.close(false);
  112. return false;
  113. }
  114. switch (state) {
  115. case STATE_UPDATE:
  116. if(Constants.USE_SEPARATE_FILE_SERVER) {
  117. in.rewind();
  118. return false;
  119. }
  120. while (in.remaining() >= 4) {
  121. int type = in.get() & 0xff;
  122. final int cache = in.get() & 0xff;
  123. final int id = in.getShort() & 0xffff;
  124. // if(cache == 6)
  125. // return true;
  126. switch (type) {
  127. case 0: // non-urgent
  128. // requests.add(new Request(cache, id));
  129. session.write(UpdateServer.getRequest(cache, id));
  130. break;
  131. case 1: // urgent
  132. session.write(UpdateServer.getRequest(cache, id));
  133. break;
  134. }
  135. // case 2: // clear requests
  136. // case 3:
  137. // requests.clear();
  138. // break;
  139. // case 4: // client error
  140. // break;
  141. // }
  142. // while (requests.size() > 0) {
  143. // Request request = (Request) requests.removeFirst();
  144. // session.write(UpdateServer.getRequest(request.getCache(),
  145. // request
  146. // .getId()));
  147. // Js5FileRequest request = (Js5FileRequest)
  148. // requests.removeFirst();
  149. // Js5Engine.getJs5Engine().addRequest(request);
  150. //}
  151. return true;
  152. }
  153. in.rewind();
  154. return false;
  155. case STATE_OPCODE:
  156. if (in.remaining() >= 1) {
  157. /*
  158. * Here we read the first opcode which indicates the type of
  159. * connection.
  160. *
  161. * 14 = game 15 = update
  162. *
  163. * Updating is disabled in the vast majority of 317 clients.
  164. */
  165. int opcode = in.get() & 0xFF;
  166. switch (opcode) {
  167. case OPCODE_GAME:
  168. session.setAttribute("state", STATE_LOGIN);
  169. return true;
  170. case OPCODE_UPDATE:
  171. if (in.remaining() >= 4) {
  172. if (in.getInt() != Server.VERSION) {
  173. System.out.println("Wrong update version");
  174. session.write(new PacketBuilder().put((byte) 6).toPacket());
  175. session.close(false);
  176. break;
  177. }
  178. session.setAttribute("state", STATE_UPDATE);
  179. session.write(new PacketBuilder().put((byte) 0).toPacket());
  180. return true;
  181. }
  182. in.rewind();
  183. return false;
  184. /*
  185. * if (in.remaining() >= 4) { if(in.getInt() !=
  186. * Server.VERSION) {
  187. * System.out.println("server version not matched");
  188. * session.write(new PacketBuilder().put((byte)
  189. * 6).toPacket()); session.close(false); break; }
  190. * //session.setAttribute("state", STATE_UPDATE);
  191. * session.write(new PacketBuilder().put((byte)
  192. * 0).toPacket());
  193. *
  194. * session.getFilterChain().remove("protocol");
  195. * session.getFilterChain().addFirst("protocol", new
  196. * ProtocolCodecFilter(RS2CodecFactory.JS5));
  197. *
  198. * return true; } in.rewind(); session.setAttribute("state",
  199. * STATE_LOGIN); return false;
  200. */
  201. default:
  202. System.out.println("Invalid opcode : " + opcode);
  203. session.close(false);
  204. break;
  205. }
  206. } else {
  207. in.rewind();
  208. return false;
  209. }
  210. break;
  211. case STATE_LOGIN:
  212. if (in.remaining() >= 1) {
  213. /*
  214. * The name hash is a simple hash of the name which is suspected
  215. * to be used to select the appropriate login server.
  216. */
  217. nameHashCode = in.get() & 0xFF;
  218.  
  219. /*
  220. * We generated the server session key using a SecureRandom
  221. * class for security.
  222. */
  223. long serverKey = RANDOM.nextLong();
  224.  
  225. /*
  226. * The initial response is just 0s which the client is set to
  227. * ignore (probably some sort of modification).
  228. */
  229. session.write(new PacketBuilder().put((byte) 0).putLong(serverKey).toPacket());
  230. session.setAttribute("state", STATE_PRECRYPTED);
  231. session.setAttribute("serverKey", serverKey);
  232. return true;
  233. }
  234. break;
  235. case STATE_PRECRYPTED:
  236. if (in.remaining() >= 2) {
  237. /*
  238. * We read the type of login.
  239. *
  240. * 16 = normal 18 = reconnection
  241. */
  242. int loginOpcode = in.get() & 0xFF;
  243. if (loginOpcode != 16 && loginOpcode != 18) {
  244. System.out.println("Invalid login opcode : " + loginOpcode);
  245. session.close(false);
  246. in.rewind();
  247. return false;
  248. }
  249.  
  250. /*
  251. * We read the size of the login packet.
  252. */
  253. int loginSize = in.get() & 0xFF;
  254.  
  255. /*
  256. * And calculated how long the encrypted block will be.
  257. */
  258. int loginEncryptSize = loginSize - (69);
  259.  
  260. /*
  261. * This could be invalid so if it is we ignore it.
  262. */
  263. if (loginEncryptSize <= 0) {
  264. System.out.println("Encrypted packet size zero or negative : " + loginEncryptSize);
  265. session.close(false);
  266. in.rewind();
  267. return false;
  268. }
  269. session.setAttribute("state", STATE_CRYPTED);
  270. session.setAttribute("size", loginSize);
  271. session.setAttribute("encryptSize", loginEncryptSize);
  272. return true;
  273. }
  274. break;
  275. case STATE_CRYPTED:
  276. int size = (Integer) session.getAttribute("size");
  277. int encryptSize = (Integer) session.getAttribute("encryptSize");
  278. if (in.remaining() >= size) {
  279.  
  280. /*
  281. * We now read a short which is the client version and check if
  282. * it equals 464.
  283. */
  284. final int version = in.getInt();
  285. final int gameframe = in.getInt();
  286. final int hitmarks = in.getInt();
  287. final boolean orbsOn = in.getInt() == 1;
  288. final boolean hpbars = in.getInt() == 1;
  289. final boolean newCursors = in.getInt() == 1;
  290. final boolean newMenus = in.getInt() == 1;
  291. final boolean newHits = in.getInt() == 1;
  292. final boolean tweening = in.getInt() == 1;
  293. final boolean hd = in.getInt() == 1;
  294. final boolean hdOnLogin = in.getInt() == 1;
  295. final int clientSize = in.getInt();
  296. final boolean isCensorOn = in.getInt() == 1;
  297.  
  298. final boolean wrong = !(version == 666 || version == 602 || version == 464 || version == 562 || version == 530 || version == 474);
  299. if (wrong) {
  300. System.out.println("wrong version: " + version);
  301. session.write(new PacketBuilder().put((byte)3).toPacket());
  302. session.close(false);
  303. in.rewind();
  304. return false;
  305. }
  306. final boolean wrong2 = !(gameframe == 562 || gameframe == 525 || gameframe == 464 || gameframe == 474 || gameframe == 530);
  307. if (wrong2) {
  308. System.out.println("wrong gameframe: " + gameframe);
  309. session.write(new PacketBuilder().put((byte)3).toPacket());
  310. session.close(false);
  311. in.rewind();
  312. return false;
  313. }
  314. final boolean lowMemoryVersion = (in.get() & 0xFF) == 1;
  315. boolean outdated = false;
  316. for (int i = 0; i < 16; i++) {
  317. int check = i;
  318. if (version == 666) {
  319. if (check == 0) {
  320. check = 26;
  321. } else if (check == 1) {
  322. check = 27;
  323. } else if (check == 7) {
  324. check = 28;
  325. }
  326. } else if (version == 602) {
  327. if (check == 0) {
  328. check = 22;
  329. } else if (check == 1) {
  330. check = 23;
  331. } else if (check == 7) {
  332. check = 24;
  333. }
  334. } else if (version == 562) {
  335. if (check == 0) {
  336. check = 16;
  337. } else if (check == 1) {
  338. check = 17;
  339. } else if (check == 7) {
  340. check = 18;
  341. }
  342. } else if (version == 530) {
  343. if (check == 0) {
  344. check = 19;
  345. } else if (check == 1) {
  346. check = 20;
  347. } else if (check == 7) {
  348. check = 21;
  349. }
  350. }
  351. int crc = in.getInt();
  352. int cachedCrc = Cache.getCacheFileManagers()[check].getInformation().getInformationContainer().getCrc();
  353. if(cachedCrc != crc) {
  354. outdated = true;
  355. }
  356. }
  357.  
  358. /*
  359. * The encrypted size includes the size byte which we don't
  360. * need.
  361. */
  362. encryptSize--;
  363.  
  364. /*
  365. * We check if there is a mismatch in the sizing.
  366. */
  367. int reportedSize = in.get() & 0xFF;
  368. if (reportedSize != encryptSize) {
  369. System.out.println("Reported size not equal to encrypted size");
  370. session.write(new PacketBuilder().put((byte)3).toPacket());
  371. session.close(false);
  372. in.rewind();
  373. return false;
  374. }
  375.  
  376. byte[] rsaPayload = new byte[encryptSize];
  377. in.get(rsaPayload);
  378. IoBuffer rsaBuffer = IoBuffer.wrap(new BigInteger(rsaPayload).modPow(RSA_EXPONENT, RSA_MODULUS).toByteArray());
  379.  
  380. /*
  381. * We now read the encrypted block opcode (although in most 317
  382. * clients and this server the RSA is disabled) and check it is
  383. * equal to 10.
  384. */
  385. int rsaOpcode = rsaBuffer.get() & 0xff;
  386. if (rsaOpcode != 10) {
  387. System.out.println("Invalid login block(RSA) opcode : " + rsaOpcode);
  388. session.write(new PacketBuilder().put((byte)3).toPacket());
  389. session.close(false);
  390. in.rewind();
  391. return false;
  392. }
  393.  
  394. /*
  395. * We read the client's session key.
  396. */
  397. long clientKey = rsaBuffer.getLong();
  398.  
  399. /*
  400. * And verify it has the correct server session key.
  401. */
  402. long serverKey = (Long) session.getAttribute("serverKey");
  403.  
  404. long reportedServerKey = rsaBuffer.getLong();
  405. if (reportedServerKey != serverKey) {
  406. System.out.println("Server key mismatch (expected : " + serverKey + ", reported : " + reportedServerKey + ")");
  407. session.write(new PacketBuilder().put((byte)3).toPacket());
  408. session.close(false);
  409. in.rewind();
  410. return false;
  411. }
  412.  
  413. /*
  414. * The UID, found in random.dat in newer clients and uid.dat in
  415. * older clients is a way of identifying a computer.
  416. *
  417. * However, some clients send a hardcoded or random UID, making
  418. * it useless in the private server scene.
  419. */
  420. int uid = rsaBuffer.getInt();
  421. String name = TextUtils.formatName(IoBufferUtils.getRS2String(rsaBuffer));
  422. name = name.replace("_", " ");
  423. name = name.trim().replaceAll("\\s+", " ");
  424. if (name.length() > Constants.USERNAME_LENGTH_LIMIT) {
  425. PacketBuilder bldr = new PacketBuilder();
  426. bldr.put((byte) 3);
  427. session.write(bldr.toPacket());
  428. return false;
  429. }
  430. String pass = IoBufferUtils.getRS2String(rsaBuffer);
  431. if (pass.length() > Constants.PASSWORD_LENGTH_LIMIT) {
  432. session.write(new PacketBuilder().put((byte)3).toPacket());
  433. session.close(false);
  434. in.rewind();
  435. return false;
  436. }
  437. if (!RS2Server.getEngine().isRunning()) {
  438. session.write(new PacketBuilder().put((byte)3).toPacket());
  439. session.close(false);
  440. in.rewind();
  441. return false;
  442.  
  443. }
  444. /*
  445. * We check if hash matches
  446. */
  447. long user_hash = TextUtils.stringToLong(name);
  448. int expectedHashCode = (int) (user_hash >> 16 & 31L);
  449. if (expectedHashCode != nameHashCode) {
  450. session.write(new PacketBuilder().put((byte)3).toPacket());
  451. session.close(false);
  452. in.rewind();
  453. return false;
  454. }
  455.  
  456. /*
  457. * And setup the ISAAC cipher which is used to encrypt and
  458. * decrypt opcodes.
  459. *
  460. * However, without RSA, this is rendered useless anyway.
  461. */
  462. int[] sessionKey = new int[4];
  463. sessionKey[0] = (int) (clientKey >> 32);
  464. sessionKey[1] = (int) clientKey;
  465. sessionKey[2] = (int) (reportedServerKey >> 32);
  466. sessionKey[3] = (int) reportedServerKey;
  467.  
  468. session.removeAttribute("state");
  469. session.removeAttribute("serverKey");
  470. session.removeAttribute("size");
  471. session.removeAttribute("encryptSize");
  472.  
  473. ISAACCipher inCipher = new ISAACCipher(sessionKey);
  474. for (int i = 0; i < 4; i++) {
  475. sessionKey[i] += 50;
  476. }
  477. ISAACCipher outCipher = new ISAACCipher(sessionKey);
  478.  
  479. /*
  480. * Now, the login has completed, and we do the appropriate
  481. * things to fire off the chain of events which will load and
  482. * check the saved games etc.
  483. */
  484. session.getFilterChain().remove("protocol");
  485. session.getFilterChain().addFirst("protocol", new ProtocolCodecFilter(RS2CodecFactory.GAME));
  486.  
  487. PlayerDetails pd = new PlayerDetails(session, name, pass, inCipher, outCipher, outdated, version, gameframe, hitmarks, orbsOn, hpbars, newCursors, newMenus, newHits, tweening, hd, hdOnLogin, clientSize, isCensorOn);
  488. PlayerManager.load_game(pd);
  489. }
  490. break;
  491. }
  492. in.rewind();
  493. return false;
  494. }
  495.  
  496. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement