Guest User

Untitled

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