//this returns an empty buffer if error public byte[] Decrypt(byte[] input, out int length) { int version, len = input.Length; if (len < 261) { length = 0; return(new byte[] { }); } else { int mod_size = len % 256; if (mod_size == 32) { version = 1; } else if (mod_size == 33) { version = 2; } else if (mod_size == 5) { version = 3; } else { length = 0; return(new byte[] { }); } } byte[] cipher8, output; int output_len; if (version == 1) { output_len = len - 32; output = new byte[output_len]; Buffer.BlockCopy(input, 32, output, 0, output_len); cipher8 = cipher8_from_iv(input); } else if (version == 2) { output_len = len - 33; output = new byte[output_len]; Buffer.BlockCopy(input, 32, output, 0, output_len); cipher8 = cipher8_from_iv(input); } else { output_len = len - 5; output = new byte[output_len]; Buffer.BlockCopy(input, 4, output, 0, output_len); byte[] tmp = new byte[4]; Buffer.BlockCopy(input, 0, tmp, 0, 4); Array.Reverse(tmp); uint ms = BitConverter.ToUInt32(tmp, 0); cipher8 = cipher8_from_rand(ref ms); if (input[len - 1] != make_integrity_byte(gen_rand(ref ms))) { length = 0; return(new byte[] { }); } } Collection <byte[]> outputcontent = new Collection <byte[]>(); //break into chunks of 256 int roundedsize = (output_len + 255) / 256; //round up for (int i = 0; i < roundedsize; i++) { outputcontent.Add(new byte[256]); } for (int i = 0; i < output_len; i++) { outputcontent[i / 256][i % 256] = output[i]; } for (int i = 0; i < outputcontent.Count; i++) { uint[] temp2 = new uint[0x100 / 4]; uint[] temp3 = new uint[0x100 / 4]; Buffer.BlockCopy(outputcontent[i], 0, temp2, 0, 0x100); Buffer.BlockCopy(temp2, 0, temp3, 0, 0x100); if (version == 1) { Shuffles.Unshuffle(temp2); } else { Shuffles.Unshuffle2(temp2); } Buffer.BlockCopy(temp2, 0, outputcontent[i], 0, 0x100); for (int j = 0; j < 256; j++) { outputcontent[i][j] ^= cipher8[j]; } Buffer.BlockCopy(temp3, 0, cipher8, 0, 0x100); } byte[] ret = new byte[output_len]; for (int i = 0; i < outputcontent.Count; i++) { Buffer.BlockCopy(outputcontent[i], 0, ret, i * 256, 0x100); } length = output_len - ret.Last(); return(ret); }
//this returns an empty buffer if error public static byte[] Decrypt(byte[] input, out int length) { int version, len = input.Length; if (len < 261) { length = 0; return(new byte[] { }); } var modSize = len % 256; switch (modSize) { case 32: version = 1; break; case 33: version = 2; break; case 5: version = 3; break; default: length = 0; return(new byte[] { }); } byte[] cipher8, output; int outputLen; switch (version) { case 1: outputLen = len - 32; output = new byte[outputLen]; Buffer.BlockCopy(input, 32, output, 0, outputLen); cipher8 = Cipher8FromIv(input); break; case 2: outputLen = len - 33; output = new byte[outputLen]; Buffer.BlockCopy(input, 32, output, 0, outputLen); cipher8 = Cipher8FromIv(input); break; default: outputLen = len - 5; output = new byte[outputLen]; Buffer.BlockCopy(input, 4, output, 0, outputLen); var tmp = new byte[4]; Buffer.BlockCopy(input, 0, tmp, 0, 4); Array.Reverse(tmp); var ms = BitConverter.ToUInt32(tmp, 0); cipher8 = Cipher8FromRand(ref ms); if (input[len - 1] != MakeIntegrityByte(GenerateRand(ref ms))) { length = 0; return(new byte[] { }); } break; } var outputcontent = new Collection <byte[]>(); //break into chunks of 256 var roundedsize = (outputLen + 255) / 256; //round up for (var i = 0; i < roundedsize; i++) { outputcontent.Add(new byte[256]); } for (var i = 0; i < outputLen; i++) { outputcontent[i / 256][i % 256] = output[i]; } foreach (var bytes in outputcontent) { var temp2 = new uint[0x100 / 4]; var temp3 = new uint[0x100 / 4]; Buffer.BlockCopy(bytes, 0, temp2, 0, 0x100); Buffer.BlockCopy(temp2, 0, temp3, 0, 0x100); if (version == 1) { Shuffles.Unshuffle(temp2); } else { Shuffles.Unshuffle2(temp2); } Buffer.BlockCopy(temp2, 0, bytes, 0, 0x100); for (var j = 0; j < 256; j++) { bytes[j] ^= cipher8[j]; } Buffer.BlockCopy(temp3, 0, cipher8, 0, 0x100); } var ret = new byte[outputLen]; for (var i = 0; i < outputcontent.Count; i++) { Buffer.BlockCopy(outputcontent[i], 0, ret, i * 256, 0x100); } length = outputLen - ret.Last(); return(ret); }