/// <summary> /// Encode a psb byte array manually /// </summary> /// <param name="key"></param> /// <param name="inputBytes"></param> /// <param name="mode"></param> /// <param name="position"></param> /// <returns></returns> public static byte[] EncodeToBytes(uint key, byte[] inputBytes, EncodeMode mode = EncodeMode.Encrypt, EncodePosition position = EncodePosition.Auto) { using (var input = new MemoryStream(inputBytes)) { using (var output = new MemoryStream((int)input.Length)) { Encode(key, mode, position, input, output); return(output.ToArray()); } } }
/// <summary> /// Encrypt or decrypt PSB and write to a file /// </summary> /// <param name="key"></param> /// <param name="savePath"></param> /// <param name="mode"></param> /// <param name="position"></param> public void EncodeToFile(uint key, string savePath, EncodeMode mode = EncodeMode.Encrypt, EncodePosition position = EncodePosition.Auto) { using (var input = File.OpenRead(Path)) { using (var output = File.Open(savePath, FileMode.Create, FileAccess.ReadWrite)) { var header = Encode(key, mode, position, input, output); if (header != null) { Header = header; } } } }
/// <summary> /// Encode (Encrypt/Decrypt) PSB file /// </summary> /// <param name="key"></param> /// <param name="mode"></param> /// <param name="position"></param> /// <param name="input"></param> /// <param name="output"></param> /// <returns>Unencrypted Header for reference. Usually you shouldn't use it.</returns> public static PsbHeader Encode(uint key, EncodeMode mode, EncodePosition position, Stream input, Stream output) { input.Seek(0, SeekOrigin.Begin); output.Seek(0, SeekOrigin.Begin); PsbHeader header = new PsbHeader(); PsbStreamContext context = new PsbStreamContext(key); BinaryReader br = new BinaryReader(input); BinaryWriter bw = new BinaryWriter(output); header.Signature = br.ReadChars(4); header.Version = br.ReadUInt16(); bw.Write(header.Signature); //Signature bw.Write(header.Version); //Version header.HeaderEncrypt = br.ReadUInt16(); //headerEncrypt, sometimes we don't believe it when encoding header.HeaderLength = br.ReadUInt32(); header.OffsetNames = br.ReadUInt32(); br.BaseStream.Seek(-8, SeekOrigin.Current); void WriteOriginal() { bw.Write(header.HeaderEncrypt); WriteOriginalPartialHeader(br, bw, header); WriteOriginalBody(br, bw); } switch (position) { case EncodePosition.Auto: bool headerEnc = TestHeaderEncrypted(br.BaseStream, header); bool bodyEnc = TestBodyEncrypted(br, header); if (headerEnc && bodyEnc) //MARK: is this possible? { mode = EncodeMode.Decrypt; } if (!headerEnc && !bodyEnc) { mode = EncodeMode.Encrypt; } switch (mode) { case EncodeMode.Encrypt: if (header.Version > 2) //Header Encrypted; Body Clean { bw.Write((ushort)1); if (headerEnc) { WriteOriginalPartialHeader(br, bw, header); WriteOriginalBody(br, bw); break; } WriteEncryptPartialHeader(br, bw, context, header); WriteOriginalBody(br, bw); break; } else //Header Clean; Body Encrpyted { bw.Write((ushort)0); // if (headerEnc) { WriteDecryptPartialHeader(br, bw, context, header); context = new PsbStreamContext(key); WriteEncodeBody(br, bw, context, header); } else { WriteOriginalPartialHeader(br, bw, header); WriteEncodeBody(br, bw, context, header); } } break; case EncodeMode.Decrypt: bw.Write((ushort)0); // if (headerEnc) { WriteDecryptPartialHeader(br, bw, context, header); } else { WriteOriginalPartialHeader(br, bw, header); } if (bodyEnc) { WriteEncodeBody(br, bw, context, header); } else { WriteOriginalBody(br, bw); } break; default: WriteOriginal(); break; } break; case EncodePosition.Body: switch (mode) { case EncodeMode.Encrypt: case EncodeMode.Decrypt: bw.Write(header.HeaderEncrypt); //We believe file is clean so write original header but encrypt body WriteOriginalPartialHeader(br, bw, header); WriteEncodeBody(br, bw, context, header); break; default: WriteOriginal(); break; } break; case EncodePosition.Header: switch (mode) { case EncodeMode.Encrypt: bw.Write((ushort)1); WriteEncryptPartialHeader(br, bw, context, header); WriteOriginalBody(br, bw); break; case EncodeMode.Decrypt: bw.Write((ushort)0); // WriteDecryptPartialHeader(br, bw, context, header); WriteOriginalBody(br, bw); break; default: WriteOriginal(); break; } break; case EncodePosition.Full: switch (mode) { case EncodeMode.Encrypt: bw.Write((ushort)1); WriteEncryptPartialHeader(br, bw, context, header); WriteEncodeBody(br, bw, context, header); break; case EncodeMode.Decrypt: bw.Write((ushort)1); // WriteDecryptPartialHeader(br, bw, context, header); WriteEncodeBody(br, bw, context, header); break; default: WriteOriginal(); break; } break; default: WriteOriginal(); break; } bw.Flush(); output.Seek(0, SeekOrigin.Begin); return(header); }