public static void Decrypt(ref byte[] buffer, EbCryptMethod method, UInt32 key, int offset, int length) { switch (method) { case EbCryptMethod.NDB_CRYPT_NONE: return; case EbCryptMethod.NDB_CRYPT_PERMUTE: for (int i = offset; i < offset + length; i++) { buffer[i] = Compressible[buffer[i]]; } break; case EbCryptMethod.NDB_CRYPT_CYCLIC: { // We've never seen an actual example of this // This is what we hope is a valid implementation UInt16 salt = (UInt16)(((key & 0xffff0000) >> 16) ^ (key & 0x0000ffff)); for (int i = offset; i < offset + length; i++) { byte lower_salt = (byte)(salt & 0x00ff); byte upper_salt = (byte)((salt & 0xff00) >> 8); byte index = buffer[i]; index += lower_salt; index = Cyclic1[index]; index += upper_salt; index = Cyclic2[index]; index -= upper_salt; index = Compressible[index]; index -= lower_salt; buffer[i] = index; salt++; } // Throw until the code has been validated throw new XstException("Decryption of Cyclic algorithm not validated"); //break; } default: throw new XstException("Encryption method not known"); } }
// Read the file header, and the B trees that give us access to nodes and data blocks private void ReadHeaderAndIndexes() { using (var fs = GetReadStream()) { var h = Map.ReadType <FileHeader1>(fs); if (h.dwMagic != 0x4e444221) { throw new XstException("File is not a .ost or .pst file: the magic cookie is missing"); } if (h.wVer == 0x15 || h.wVer == 0x17) { var h2 = Map.ReadType <FileHeader2Unicode>(fs); bCryptMethod = h2.bCryptMethod; IsUnicode = true; ReadBTPageUnicode(fs, h2.root.BREFNBT.ib, nodeTree.Root); ReadBTPageUnicode(fs, h2.root.BREFBBT.ib, dataTree.Root); } else if (h.wVer == 0x24) { // This value indicates the use of 4K pages, as opposed to 512 bytes // It is used only in .ost files, and was introduced in Office 2013 // It is not documented in [MS-PST], being .ost only var h2 = Map.ReadType <FileHeader2Unicode>(fs); bCryptMethod = h2.bCryptMethod; IsUnicode = true; IsUnicode4K = true; ReadBTPageUnicode4K(fs, h2.root.BREFNBT.ib, nodeTree.Root); ReadBTPageUnicode4K(fs, h2.root.BREFBBT.ib, dataTree.Root); } else if (h.wVer == 0x0e || h.wVer == 0x0f) { var h2 = Map.ReadType <FileHeader2ANSI>(fs); bCryptMethod = h2.bCryptMethod; IsUnicode = false; ReadBTPageANSI(fs, h2.root.BREFNBT.ib, nodeTree.Root); ReadBTPageANSI(fs, h2.root.BREFBBT.ib, dataTree.Root); } else { throw new XstException("Unrecognised header type"); } } }