Advertisement
Guest User

Untitled

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