Class SidRemasker


  • public class SidRemasker
    extends Object
    Masks and re-masks the SIDs a database stores.

    Every SID is held as its plaintext xored with an rc4 keystream, under a key folded out of page 0. The fold reads the creation date and the password field, so anything which writes the password field moves the key and leaves every stored SID describing the key the database used to have. Ms access then prompts for a password and refuses to open the database, or opens it showing no tables, because no entry in MSysACEs resolves to the current user.

    Two things write that field: setting the jet database password, and adding or removing office encryption, which fills it with the low byte of the encoding key.

    The plaintext SIDs never have to be known. Xoring out the old keystream and in the new one converts a stored value directly, so this works for a database created under any workgroup file.

    Author:
    James Ahlborn
    • Method Detail

      • createSidKey

        public static int createSidKey​(ByteBuffer headerPage,
                                       JetFormat format)
        Folds the 32-bit key which masks every SID in the database out of the given header page. The fold walks the even bytes of the password region, which are the low bytes of the utf-16 password, over a value seeded from the database creation date. The region runs past the password field and takes in the creation date a second time, which is why the key changes with the creation date even when there is no password at all.
      • remaskSids

        public static void remaskSids​(DatabaseImpl db,
                                      int oldKey,
                                      int newKey)
                               throws IOException
        Converts every SID in the given database from the old key to the new one.

        Every row of both columns is converted. That is right for a password change, where ms access re-masks everything, and it is more than ms access does when it encrypts an .accdb: there it re-masks all of MSysACEs but only the MSysObjects.Owner rows it happens to rewrite, and the rows it skips keep describing the key the database had before.

        Converting those skipped rows a second time leaves them meaningless. Which rows ms access skips cannot be worked out from the database: MSysACEs does not use every SID MSysObjects does, so unmasking is not enough to tell a skipped row from a converted one. Ms access opens a database whose Owner values are all converted, and reads MSysACEs rather than Owner when it decides what the current user may see, so converting everything is safe.

        Throws:
        IOException