1 module buffer.packet; 2 3 import std.variant; 4 import std.bitmanip; 5 import std.traits; 6 import std.typecons; 7 import std.conv : to; 8 9 import cryption.aes; 10 import cryption.tea.xtea; 11 import cryption.rsa; 12 13 import buffer.utils; 14 15 enum CryptType 16 { 17 NONE = 0, 18 XTEA = 1, 19 AES = 2, 20 RSA = 3 21 } 22 23 template TypeID(Type) 24 { 25 static if (is(Unqual!Type == byte)) 26 const ubyte TypeID = 0x01; 27 else static if (is(Unqual!Type == ubyte)) 28 const ubyte TypeID = 0x02; 29 else static if (is(Unqual!Type == short)) 30 const ubyte TypeID = 0x03; 31 else static if (is(Unqual!Type == ushort)) 32 const ubyte TypeID = 0x04; 33 else static if (is(Unqual!Type == int)) 34 const ubyte TypeID = 0x05; 35 else static if (is(Unqual!Type == uint)) 36 const ubyte TypeID = 0x06; 37 else static if (is(Unqual!Type == long)) 38 const ubyte TypeID = 0x07; 39 else static if (is(Unqual!Type == ulong)) 40 const ubyte TypeID = 0x08; 41 else static if (is(Unqual!Type == float)) 42 const ubyte TypeID = 0x20; 43 else static if (is(Unqual!Type == double)) 44 const ubyte TypeID = 0x21; 45 else static if (is(Unqual!Type == bool)) 46 const ubyte TypeID = 0x30; 47 else static if (is(Unqual!Type == char)) 48 const ubyte TypeID = 0x40; 49 else static if (is(Unqual!Type == string)) 50 const ubyte TypeID = 0x41; 51 else 52 static assert(0, "Data types that are not supported: " ~ typeid(Type)); 53 } 54 55 package class Packet 56 { 57 static ubyte[] build(ushort magic, CryptType crypt, string key, Nullable!RSAKeyInfo rsaKey, ushort messageId, string method, Variant[] params) 58 { 59 assert(params.length > 0, "Parameter params must be provided."); 60 assert(method.length <= 255, "Paramter method cannot be greater than 255 characters."); 61 62 ubyte[] temp; 63 ubyte[] tlv; 64 65 void put(T)(Variant v) 66 { 67 tlv ~= TypeID!T; 68 temp = new ubyte[T.sizeof]; 69 temp.write!T(v.get!T, 0); 70 tlv ~= temp; 71 } 72 73 foreach (v; params) 74 { 75 if (v.type == typeid(byte)) 76 { 77 put!byte(v); 78 } 79 else if (v.type == typeid(ubyte)) 80 { 81 put!ubyte(v); 82 } 83 else if (v.type == typeid(short)) 84 { 85 put!short(v); 86 } 87 else if (v.type == typeid(ushort)) 88 { 89 put!ushort(v); 90 } 91 else if (v.type == typeid(int)) 92 { 93 put!int(v); 94 } 95 else if (v.type == typeid(uint)) 96 { 97 put!uint(v); 98 } 99 else if (v.type == typeid(long)) 100 { 101 put!long(v); 102 } 103 else if (v.type == typeid(ulong)) 104 { 105 put!ulong(v); 106 } 107 else if (v.type == typeid(float)) 108 { 109 put!float(v); 110 } 111 else if (v.type == typeid(double)) 112 { 113 put!double(v); 114 } 115 else if (v.type == typeid(bool)) 116 { 117 put!bool(v); 118 } 119 else if (v.type == typeid(char)) 120 { 121 put!char(v); 122 } 123 else if (v.type == typeid(string)) 124 { 125 tlv ~= TypeID!string; 126 string str = v.get!string; 127 temp = new ubyte[4]; 128 temp.write!int(cast(int) str.length, 0); 129 tlv ~= temp; 130 temp = cast(ubyte[]) str; 131 tlv ~= temp; 132 } 133 else 134 { 135 assert(0, "Data types id that are not supported: " ~ v.type.toString); 136 } 137 } 138 139 final switch (crypt) 140 { 141 case CryptType.NONE: 142 break; 143 case CryptType.XTEA: 144 tlv = Xtea.encrypt(tlv, key); 145 break; 146 case CryptType.AES: 147 tlv = AESUtils.encrypt!AES128(tlv, key); 148 break; 149 case CryptType.RSA: 150 tlv = RSA.encrypt(rsaKey, tlv); 151 break; 152 } 153 154 ubyte[] method_buf = cast(ubyte[]) method; 155 ubyte[] buffer = new ubyte[10]; 156 157 buffer.write!ushort(magic, 0); 158 buffer.write!int(cast(int)(2 + 2 + method_buf.length + tlv.length + 2), 2); 159 buffer.write!ushort(messageId, 6); 160 buffer.write!ushort(cast(ushort) method_buf.length, 8); 161 if (method_buf.length > 0) 162 buffer ~= method_buf; 163 buffer ~= tlv; 164 buffer ~= strToByte_hex(MD5(buffer)[0 .. 4]); 165 166 return buffer; 167 } 168 169 static void parseInfo(ubyte[] buffer, out ushort messageId, out string method) 170 { 171 assert(buffer != null && buffer.length >= 12, "Incorrect buffer length."); 172 173 messageId = buffer.peek!ushort(6); 174 175 ushort t_method_len = buffer.peek!ushort(8); 176 if (t_method_len > 0) 177 { 178 method = cast(string) buffer[10 .. 10 + t_method_len]; 179 } 180 } 181 182 static Variant[] parse(ubyte[] buffer, ushort magic, CryptType crypt, string key, Nullable!RSAKeyInfo rsaKey, out ushort messageId, out string method) 183 { 184 assert(buffer != null && buffer.length >= 12, "Incorrect buffer length."); 185 186 ushort t_magic, t_crc; 187 int t_len; 188 t_magic = buffer.peek!ushort(0); 189 t_len = buffer.peek!int(2); 190 191 if ((t_magic != magic) || (t_len > buffer.length - 6)) 192 return null; 193 194 buffer = buffer[0 .. t_len + 6]; 195 t_crc = buffer.peek!ushort(buffer.length - 2); 196 if (strToByte_hex(MD5(buffer[0 .. $ - 2])[0 .. 4]) != buffer[$ - 2 .. $]) 197 return null; 198 199 parseInfo(buffer, messageId, method); 200 201 ushort t_method_len = buffer.peek!ushort(8); 202 buffer = buffer[10 + t_method_len .. $ - 2]; 203 204 final switch (crypt) 205 { 206 case CryptType.NONE: 207 break; 208 case CryptType.XTEA: 209 buffer = Xtea.decrypt(buffer, key); 210 break; 211 case CryptType.AES: 212 buffer = AESUtils.decrypt!AES128(buffer, key); 213 break; 214 case CryptType.RSA: 215 buffer = RSA.decrypt(rsaKey, buffer); 216 break; 217 } 218 219 ubyte typeId; 220 int pos; 221 Variant[] ret; 222 223 void get(T)() 224 { 225 ret ~= Variant(buffer.peek!T(pos)); 226 pos += T.sizeof; 227 } 228 229 while (pos < buffer.length) 230 { 231 typeId = buffer[pos]; 232 pos++; 233 234 if (typeId == TypeID!byte) 235 { 236 get!byte; 237 } 238 else if (typeId == TypeID!ubyte) 239 { 240 get!ubyte; 241 } 242 else if (typeId == TypeID!short) 243 { 244 get!short; 245 } 246 else if (typeId == TypeID!ushort) 247 { 248 get!ushort; 249 } 250 else if (typeId == TypeID!int) 251 { 252 get!int; 253 } 254 else if (typeId == TypeID!uint) 255 { 256 get!uint; 257 } 258 else if (typeId == TypeID!long) 259 { 260 get!long; 261 } 262 else if (typeId == TypeID!ulong) 263 { 264 get!ulong; 265 } 266 else if (typeId == TypeID!float) 267 { 268 get!float; 269 } 270 else if (typeId == TypeID!double) 271 { 272 get!double; 273 } 274 else if (typeId == TypeID!bool) 275 { 276 get!bool; 277 } 278 else if (typeId == TypeID!char) 279 { 280 get!char; 281 } 282 else if (typeId == TypeID!string) 283 { 284 int temp = buffer.peek!int(pos); 285 pos += 4; 286 ret ~= Variant(cast(string) buffer[pos .. pos + temp]); 287 pos += temp; 288 } 289 else 290 { 291 assert(0, "Data types id that are not supported: " ~ typeId.to!string); 292 } 293 } 294 295 return ret; 296 } 297 }