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 import std.exception; 9 10 import crypto.aes; 11 import crypto.tea; 12 import crypto.rsa; 13 14 import buffer.utils; 15 16 enum CryptType 17 { 18 NONE = 0, 19 XTEA = 1, 20 AES = 2, 21 RSA = 3, 22 RSA_XTEA_MIXIN = 4 23 } 24 25 template TypeID(Type) 26 { 27 static if (is(Unqual!Type == byte)) 28 const ubyte TypeID = 0x01; 29 else static if (is(Unqual!Type == ubyte)) 30 const ubyte TypeID = 0x02; 31 else static if (is(Unqual!Type == short)) 32 const ubyte TypeID = 0x03; 33 else static if (is(Unqual!Type == ushort)) 34 const ubyte TypeID = 0x04; 35 else static if (is(Unqual!Type == int)) 36 const ubyte TypeID = 0x05; 37 else static if (is(Unqual!Type == uint)) 38 const ubyte TypeID = 0x06; 39 else static if (is(Unqual!Type == long)) 40 const ubyte TypeID = 0x07; 41 else static if (is(Unqual!Type == ulong)) 42 const ubyte TypeID = 0x08; 43 else static if (is(Unqual!Type == float)) 44 const ubyte TypeID = 0x20; 45 else static if (is(Unqual!Type == double)) 46 const ubyte TypeID = 0x21; 47 else static if (is(Unqual!Type == real)) 48 const ubyte TypeID = 0x22; 49 else static if (is(Unqual!Type == bool)) 50 const ubyte TypeID = 0x30; 51 else static if (is(Unqual!Type == char)) 52 const ubyte TypeID = 0x40; 53 else static if (is(Unqual!Type == string)) 54 const ubyte TypeID = 0x41; 55 else 56 static assert(0, "Data types that are not supported: " ~ typeid(Type)); 57 } 58 59 package: 60 61 class Packet 62 { 63 static ubyte[] build(ushort magic, CryptType crypt, string key, Nullable!RSAKeyInfo rsaKey, string name, string method, Variant[] params) 64 { 65 assert(name.length <= 255, "Paramter name cannot be greater than 255 characters."); 66 assert(method.length <= 255, "Paramter method cannot be greater than 255 characters."); 67 assert(params.length > 0, "Parameter params must be provided."); 68 69 ubyte[] tlv; 70 BufferBuilder bb = new BufferBuilder(&tlv); 71 72 foreach (v; params) 73 { 74 if (v.type == typeid(byte)) 75 { 76 bb.put!byte(v.get!byte, true, false, 0); 77 } 78 else if (v.type == typeid(ubyte)) 79 { 80 bb.put!ubyte(v.get!ubyte, true, false, 0); 81 } 82 else if (v.type == typeid(short)) 83 { 84 bb.put!short(v.get!short, true, false, 0); 85 } 86 else if (v.type == typeid(ushort)) 87 { 88 bb.put!ushort(v.get!ushort, true, false, 0); 89 } 90 else if (v.type == typeid(int)) 91 { 92 bb.put!int(v.get!int, true, false, 0); 93 } 94 else if (v.type == typeid(uint)) 95 { 96 bb.put!uint(v.get!uint, true, false, 0); 97 } 98 else if (v.type == typeid(long)) 99 { 100 bb.put!long(v.get!long, true, false, 0); 101 } 102 else if (v.type == typeid(ulong)) 103 { 104 bb.put!ulong(v.get!ulong, true, false, 0); 105 } 106 else if (v.type == typeid(float)) 107 { 108 bb.put!float(v.get!float, true, false, 0); 109 } 110 else if (v.type == typeid(double)) 111 { 112 bb.put!double(v.get!double, true, false, 0); 113 } 114 else if (v.type == typeid(real)) 115 { 116 bb.put!real(v.get!real, true, false, 0); 117 } 118 else if (v.type == typeid(bool)) 119 { 120 bb.put!bool(v.get!bool, true, false, 0); 121 } 122 else if (v.type == typeid(char)) 123 { 124 bb.put!char(v.get!char, true, false, 0); 125 } 126 else if (v.type == typeid(string)) 127 { 128 bb.put!string(v.get!string, true, true, 4); 129 } 130 else 131 { 132 assert(0, "Data types id that are not supported: " ~ v.type.toString); 133 } 134 } 135 136 final switch (crypt) 137 { 138 case CryptType.NONE: 139 break; 140 case CryptType.XTEA: 141 tlv = Xtea.encrypt(tlv, key); 142 break; 143 case CryptType.AES: 144 tlv = AESUtils.encrypt!AES128(tlv, key); 145 break; 146 case CryptType.RSA: 147 tlv = RSA.encrypt(rsaKey, tlv); 148 break; 149 case CryptType.RSA_XTEA_MIXIN: 150 tlv = RSA.encrypt(rsaKey, tlv, true); 151 } 152 153 ubyte[] buffer; 154 bb = new BufferBuilder(&buffer); 155 bb.put!ushort(magic, false, false, 0); 156 bb.put!int(0, false, false, 0); // length, seize a seat. 157 bb.put!string(name, false, true, 2); 158 bb.put!string(method, false, true, 2); 159 buffer ~= tlv; 160 buffer.write!int(cast(int)(buffer.length - 2 - 4 + 2), 2); 161 buffer ~= strToByte_hex(MD5(buffer)[0 .. 4]); 162 163 return buffer; 164 } 165 166 static size_t parseInfo(ubyte[] buffer, out string name, out string method) 167 { 168 enforce(buffer != null && buffer.length >= 10, "Incorrect buffer length."); 169 170 ushort len1 = buffer.peek!ushort(6); 171 if (len1 > 0) 172 { 173 name = cast(string) buffer[8 .. 8 + len1]; 174 } 175 176 ushort len2 = buffer.peek!ushort(8 + len1); 177 if (len2 > 0) 178 { 179 method = cast(string) buffer[10 + len1 .. 10 + len1 + len2]; 180 } 181 182 return 10 + len1 + len2; 183 } 184 185 static Variant[] parse(ubyte[] buffer, ushort magic, CryptType crypt, string key, Nullable!RSAKeyInfo rsaKey, out string name, out string method) 186 { 187 enforce(buffer != null && buffer.length >= 10, "Incorrect buffer length."); 188 189 ushort t_magic; 190 int t_len; 191 t_magic = buffer.peek!ushort(0); 192 t_len = buffer.peek!int(2); 193 194 if ((t_magic != magic) || (t_len > cast(int)buffer.length - 6)) 195 { 196 return null; 197 } 198 199 buffer = buffer[0 .. t_len + 6]; 200 if (strToByte_hex(MD5(buffer[0 .. $ - 2])[0 .. 4]) != buffer[$ - 2 .. $]) 201 { 202 return null; 203 } 204 205 size_t tlv_pos = parseInfo(buffer, name, method); 206 buffer = buffer[tlv_pos .. $ - 2]; 207 208 final switch (crypt) 209 { 210 case CryptType.NONE: 211 break; 212 case CryptType.XTEA: 213 buffer = Xtea.decrypt(buffer, key); 214 break; 215 case CryptType.AES: 216 buffer = AESUtils.decrypt!AES128(buffer, key); 217 break; 218 case CryptType.RSA: 219 buffer = RSA.decrypt(rsaKey, buffer); 220 break; 221 case CryptType.RSA_XTEA_MIXIN: 222 buffer = RSA.decrypt(rsaKey, buffer, true); 223 break; 224 } 225 226 ubyte typeId; 227 int pos; 228 Variant[] ret; 229 230 void get(T)() 231 { 232 ret ~= Variant(buffer.peek!T(pos)); 233 pos += T.sizeof; 234 } 235 236 while (pos < buffer.length) 237 { 238 typeId = buffer[pos]; 239 pos++; 240 241 if (typeId == TypeID!byte) 242 { 243 get!byte; 244 } 245 else if (typeId == TypeID!ubyte) 246 { 247 get!ubyte; 248 } 249 else if (typeId == TypeID!short) 250 { 251 get!short; 252 } 253 else if (typeId == TypeID!ushort) 254 { 255 get!ushort; 256 } 257 else if (typeId == TypeID!int) 258 { 259 get!int; 260 } 261 else if (typeId == TypeID!uint) 262 { 263 get!uint; 264 } 265 else if (typeId == TypeID!long) 266 { 267 get!long; 268 } 269 else if (typeId == TypeID!ulong) 270 { 271 get!ulong; 272 } 273 else if (typeId == TypeID!float) 274 { 275 get!float; 276 } 277 else if (typeId == TypeID!double) 278 { 279 get!double; 280 } 281 else if (typeId == TypeID!real) 282 { 283 //get!real; 284 ret ~= Variant(ubyteToReal(buffer[pos .. pos + real.sizeof])); 285 pos += real.sizeof; 286 } 287 else if (typeId == TypeID!bool) 288 { 289 get!bool; 290 } 291 else if (typeId == TypeID!char) 292 { 293 get!char; 294 } 295 else if (typeId == TypeID!string) 296 { 297 int temp = buffer.peek!int(pos); 298 pos += 4; 299 ret ~= Variant(cast(string) buffer[pos .. pos + temp]); 300 pos += temp; 301 } 302 else 303 { 304 assert(0, "Data types id that are not supported: " ~ typeId.to!string); 305 } 306 } 307 308 return ret; 309 } 310 } 311 312 class BufferBuilder 313 { 314 public ubyte[]* buffer; 315 316 this(ubyte[]* buffer) 317 { 318 this.buffer = buffer; 319 } 320 321 size_t put(T)(T value, bool isWriteTypeInfo, bool isWriteLengthInfo, int lengthBytes) 322 { 323 assert(lengthBytes == 0 || lengthBytes == 2 || lengthBytes == 4); 324 325 ubyte[] buf_data; 326 size_t len; 327 328 if (isWriteTypeInfo) 329 { 330 *buffer ~= TypeID!T; 331 } 332 333 static if (is(Unqual!T == string)) 334 { 335 buf_data = cast(ubyte[])value; 336 len = buf_data.length; 337 } 338 else static if (is(Unqual!T == real)) 339 { 340 buf_data = realToUByte(value); 341 len = real.sizeof; 342 } 343 else 344 { 345 buf_data = new ubyte[T.sizeof]; 346 buf_data.write!T(value, 0); 347 len = T.sizeof; 348 } 349 350 if (isWriteLengthInfo && lengthBytes > 0) 351 { 352 ubyte[] buf_len = new ubyte[lengthBytes]; 353 if (lengthBytes == 2) 354 buf_len.write!ushort(cast(ushort)len, 0); 355 else 356 buf_len.write!int(cast(int)len, 0); 357 358 *buffer ~= buf_len; 359 } 360 361 *buffer ~= buf_data; 362 363 return len; 364 } 365 }