Advertisement
Guest User

Untitled

a guest
Jun 22nd, 2017
73
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.38 KB | None | 0 0
  1. package org.ex.rs2.net;
  2.  
  3. import java.security.SecureRandom;
  4. import java.util.logging.Logger;
  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.ex.Server;
  12. import org.ex.rs2.model.World;
  13. import org.ex.rs2.model.player.PlayerDetails;
  14. import org.ex.rs2.net.ondemand.OnDemandPool;
  15. import org.ex.rs2.net.ondemand.OnDemandRequest;
  16. import org.ex.rs2.util.IoBufferUtils;
  17. import org.ex.rs2.util.NameUtils;
  18.  
  19. /**
  20. * Login protocol decoding class.
  21. *
  22. * @author Graham Edgecombe
  23. * @author Mike (Dailusion)
  24. *
  25. */
  26. public class RS2LoginDecoder extends CumulativeProtocolDecoder {
  27.  
  28. /**
  29. * Logger instance.
  30. */
  31. private static final Logger logger = Logger.getLogger(RS2LoginDecoder.class
  32. .getName());
  33.  
  34. /**
  35. * Opcode stage.
  36. */
  37. public static final int STATE_OPCODE = 0;
  38.  
  39. /**
  40. * Login stage.
  41. */
  42. public static final int STATE_LOGIN = 1;
  43.  
  44. /**
  45. * Precrypted stage.
  46. */
  47. public static final int STATE_PRECRYPTED = 2;
  48.  
  49. /**
  50. * Crypted stage.
  51. */
  52. public static final int STATE_CRYPTED = 3;
  53.  
  54. /**
  55. * Update stage.
  56. */
  57. public static final int STATE_UPDATE = -1;
  58.  
  59. /**
  60. * Game opcode.
  61. */
  62. public static final int OPCODE_GAME = 14;
  63.  
  64. /**
  65. * Update opcode.
  66. */
  67. public static final int OPCODE_UPDATE = 15;
  68.  
  69. /**
  70. * Secure random number generator.
  71. */
  72. private static final SecureRandom RANDOM = new SecureRandom();
  73.  
  74. /**
  75. * Initial login response.
  76. */
  77. private static final byte[] INITIAL_RESPONSE = new byte[] { 0x0, 0x0, 0x0,
  78. 0x0, 0x0, 0x0, 0x0, 0x0 };
  79.  
  80. @Override
  81. protected boolean doDecode(IoSession session, IoBuffer in,
  82. ProtocolDecoderOutput out) throws Exception {
  83. int state = (Integer) session.getAttribute("state", STATE_OPCODE);
  84. switch (state) {
  85. case STATE_UPDATE:
  86. if (in.remaining() >= 4) {
  87. /*
  88. * Here we read the cache id (idx file), file id and priority.
  89. */
  90. int cacheId = in.get() & 0xFF;
  91. int fileId = ((in.get() & 0xFF) << 8) | (in.get() & 0xFF);
  92. int priority = in.get() & 0xFF;
  93.  
  94. /*
  95. * We push the request into the ondemand pool so it can be
  96. * served.
  97. */
  98. OnDemandPool.getOnDemandPool()
  99. .pushRequest(
  100. new OnDemandRequest(session, cacheId, fileId,
  101. priority));
  102. return true;
  103. } else {
  104. in.rewind();
  105. return false;
  106. }
  107. case STATE_OPCODE:
  108. if (in.remaining() >= 1) {
  109. /*
  110. * Here we read the first opcode which indicates the type of
  111. * connection.
  112. *
  113. * 14 = game 15 = update
  114. *
  115. * Updating is disabled in the vast majority of 317 clients.
  116. */
  117. int opcode = in.get() & 0xFF;
  118. switch (opcode) {
  119. case OPCODE_GAME:
  120. session.setAttribute("state", STATE_LOGIN);
  121. return true;
  122. case OPCODE_UPDATE:
  123. session.setAttribute("state", STATE_UPDATE);
  124. session.write(new PacketBuilder().put(INITIAL_RESPONSE)
  125. .toPacket());
  126. return true;
  127. default:
  128. logger.info("Invalid opcode : " + opcode);
  129. session.close(false);
  130. break;
  131. }
  132. } else {
  133. in.rewind();
  134. return false;
  135. }
  136. break;
  137. case STATE_LOGIN:
  138. if (in.remaining() >= 1) {
  139. /*
  140. * The name hash is a simple hash of the name which is suspected
  141. * to be used to select the appropriate login server.
  142. */
  143. @SuppressWarnings("unused")
  144. int nameHash = in.get() & 0xFF;
  145.  
  146. /*
  147. * We generated the server session key using a SecureRandom
  148. * class for security.
  149. */
  150. long serverKey = RANDOM.nextLong();
  151.  
  152. /*
  153. * The initial response is just 0s which the client is set to
  154. * ignore (probably some sort of modification).
  155. */
  156. session.write(new PacketBuilder().put(INITIAL_RESPONSE)
  157. .put((byte) 0).putLong(serverKey).toPacket());
  158. session.setAttribute("state", STATE_PRECRYPTED);
  159. session.setAttribute("serverKey", serverKey);
  160. return true;
  161. }
  162. break;
  163. case STATE_PRECRYPTED:
  164. if (in.remaining() >= 2) {
  165. /*
  166. * We read the type of login.
  167. *
  168. * 16 = normal 18 = reconnection
  169. */
  170. int loginOpcode = in.get() & 0xFF;
  171. if (loginOpcode != 16 && loginOpcode != 18) {
  172. logger.info("Invalid login opcode : " + loginOpcode);
  173. session.close(false);
  174. in.rewind();
  175. return false;
  176. }
  177.  
  178. /*
  179. * We read the size of the login packet.
  180. */
  181. int loginSize = in.get() & 0xFF;
  182.  
  183. /*
  184. * And calculated how long the encrypted block will be.
  185. */
  186. int loginEncryptSize = loginSize - (36 + 1 + 1 + 2);
  187.  
  188. /*
  189. * This could be invalid so if it is we ignore it.
  190. */
  191. if (loginEncryptSize <= 0) {
  192. logger.info("Encrypted packet size zero or negative : "
  193. + loginEncryptSize);
  194. session.close(false);
  195. in.rewind();
  196. return false;
  197. }
  198. session.setAttribute("state", STATE_CRYPTED);
  199. session.setAttribute("size", loginSize);
  200. session.setAttribute("encryptSize", loginEncryptSize);
  201. return true;
  202. }
  203. break;
  204. case STATE_CRYPTED:
  205. int size = (Integer) session.getAttribute("size");
  206. int encryptSize = (Integer) session.getAttribute("encryptSize");
  207. if (in.remaining() >= size) {
  208. /*
  209. * We read the magic ID which is 255 (0xFF) which indicates this
  210. * is the real login packet.
  211. */
  212. int magicId = in.get() & 0xFF;
  213. if (magicId != 255) {
  214. logger.info("Incorrect magic id : " + magicId);
  215. session.close(false);
  216. in.rewind();
  217. return false;
  218. }
  219.  
  220. /*
  221. * We now read a short which is the client version and check if
  222. * it equals 317.
  223. */
  224. int version = in.getShort() & 0xFFFF;
  225. if (version != Server.VERSION) {
  226. logger.info("Incorrect version : " + version);
  227. session.close(false);
  228. in.rewind();
  229. return false;
  230. }
  231.  
  232. /*
  233. * The following byte indicates if we are using a low memory
  234. * version.
  235. */
  236. @SuppressWarnings("unused")
  237. boolean lowMemoryVersion = (in.get() & 0xFF) == 1;
  238.  
  239. /*
  240. * We know read the cache indices.
  241. */
  242. for (int i = 0; i < 9; i++) {
  243. in.getInt();
  244. }
  245.  
  246. /*
  247. * The encrypted size includes the size byte which we don't
  248. * need.
  249. */
  250. encryptSize--;
  251.  
  252. /*
  253. * We check if there is a mismatch in the sizing.
  254. */
  255. int reportedSize = in.get() & 0xFF;
  256. if (reportedSize != encryptSize) {
  257. logger.info("Packet size mismatch (expected : "
  258. + encryptSize + ", reported : " + reportedSize
  259. + ")");
  260. session.close(false);
  261. in.rewind();
  262. return false;
  263. }
  264.  
  265. /*
  266. * We now read the encrypted block opcode (although in most 317
  267. * clients and this server the RSA is disabled) and check it is
  268. * equal to 10.
  269. */
  270. int blockOpcode = in.get() & 0xFF;
  271. if (blockOpcode != 10) {
  272. logger.info("Invalid login block opcode : " + blockOpcode);
  273. session.close(false);
  274. in.rewind();
  275. return false;
  276. }
  277.  
  278. /*
  279. * We read the client's session key.
  280. */
  281. long clientKey = in.getLong();
  282.  
  283. /*
  284. * And verify it has the correct server session key.
  285. */
  286. long serverKey = (Long) session.getAttribute("serverKey");
  287. long reportedServerKey = in.getLong();
  288. if (reportedServerKey != serverKey) {
  289. logger.info("Server key mismatch (expected : " + serverKey
  290. + ", reported : " + reportedServerKey + ")");
  291. session.close(false);
  292. in.rewind();
  293. return false;
  294. }
  295.  
  296. /*
  297. * The UID, found in random.dat in newer clients and uid.dat in
  298. * older clients is a way of identifying a computer.
  299. *
  300. * However, some clients send a hardcoded or random UID, making
  301. * it useless in the private server scene.
  302. */
  303. int uid = in.getInt();
  304.  
  305. /*
  306. * We read and format the name and passwords.
  307. */
  308. String name = NameUtils.formatName(IoBufferUtils
  309. .getRS2String(in));
  310. String pass = IoBufferUtils.getRS2String(in);
  311. logger.info("Login request : username=" + name + " password="
  312. + pass);
  313.  
  314. /*
  315. * And setup the ISAAC cipher which is used to encrypt and
  316. * decrypt opcodes.
  317. *
  318. * However, without RSA, this is rendered useless anyway.
  319. */
  320. int[] sessionKey = new int[4];
  321. sessionKey[0] = (int) (clientKey >> 32);
  322. sessionKey[1] = (int) clientKey;
  323. sessionKey[2] = (int) (serverKey >> 32);
  324. sessionKey[3] = (int) serverKey;
  325.  
  326. session.removeAttribute("state");
  327. session.removeAttribute("serverKey");
  328. session.removeAttribute("size");
  329. session.removeAttribute("encryptSize");
  330.  
  331. ISAACCipher inCipher = new ISAACCipher(sessionKey);
  332. for (int i = 0; i < 4; i++) {
  333. sessionKey[i] += 50;
  334. }
  335. ISAACCipher outCipher = new ISAACCipher(sessionKey);
  336.  
  337. /*
  338. * Now, the login has completed, and we do the appropriate
  339. * things to fire off the chain of events which will load and
  340. * check the saved games etc.
  341. */
  342. session.getFilterChain().remove("protocol");
  343. session.getFilterChain().addFirst("protocol",
  344. new ProtocolCodecFilter(RS2CodecFactory.GAME));
  345.  
  346. PlayerDetails pd = new PlayerDetails(session, name, pass, uid,
  347. inCipher, outCipher);
  348. World.getWorld().load(pd);
  349. }
  350. break;
  351. }
  352. in.rewind();
  353. return false;
  354. }
  355.  
  356. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement