/*++

Copyright (c) Microsoft Corporation. All rights reserved.

Module Name:

    efsstruc.h

Abstract:

    EFS (Encrypting File System) defines, data and function prototypes.

Author:

    Robert Reichel      (RobertRe)
    Robert Gu           (RobertG)

Environment:

Revision History:

--*/

#ifndef _EFSSTRUC_
#define _EFSSTRUC_

#ifdef __cplusplus
extern "C" {
#endif

#ifndef ALGIDDEF
#define ALGIDDEF
typedef unsigned int ALG_ID;
#endif

//
// Our OID.  Remove from here once it's in the real headers.
//

#ifndef szOID_EFS_CRYPTO
#define szOID_EFS_CRYPTO	"1.3.6.1.4.1.311.10.3.4"
#endif

#ifndef szOID_EFS_RECOVERY
#define szOID_EFS_RECOVERY      "1.3.6.1.4.1.311.10.3.4.1"
#endif


//
// Context flag
//

#define CONTEXT_FOR_EXPORT      0x00000000
#define CONTEXT_FOR_IMPORT      0x00000001
#define CONTEXT_INVALID         0x00000002
#define CONTEXT_OPEN_FOR_DIR    0x00008000

//
// Context ID
//
#define EFS_CONTEXT_ID  0x00000001

//
// Signature type
//
#define SIG_LENGTH              0x00000008
#define SIG_NO_MATCH            0x00000000
#define SIG_EFS_FILE            0x00000001
#define SIG_EFS_STREAM          0x00000002
#define SIG_EFS_DATA            0x00000003

//
// Export file format stream flag information
//

#define STREAM_NOT_ENCRYPTED    0x0001

#define EFS_EXP_FORMAT_CURRENT_VERSION  0x0100
#define EFS_SIGNATURE_LENGTH    4
#define EFS_STREAM_ID    0x1910

#define FSCTL_IMPORT_INPUT_LENGTH 4 * 1024
#define FSCTL_EXPORT_INPUT_LENGTH 128
#define FSCTL_OUTPUT_INITIAL_LENGTH    68 * 1024
#define FSCTL_OUTPUT_LESS_LENGTH       8 * 1024
#define FSCTL_OUTPUT_MIN_LENGTH        20 * 1024
#define FSCTL_OUTPUT_MISC_LENGTH       4 * 1024

//
// FSCTL data shared between server and driver
//

#define EFS_SET_ENCRYPT                 0
#define EFS_SET_ATTRIBUTE               1
#define EFS_DEL_ATTRIBUTE               2
#define EFS_GET_ATTRIBUTE               3
#define EFS_OVERWRITE_ATTRIBUTE         4
#define EFS_ENCRYPT_DONE                5
#define EFS_DECRYPT_BEGIN               6

//
// Mask for Set EFS Attribute
//

#define WRITE_EFS_ATTRIBUTE     0x00000001
#define SET_EFS_KEYBLOB         0x00000002

//
// Sub code of SET_ENCRYPT FSCTL
//

#define EFS_FSCTL_ON_DIR                0x80000000
#define EFS_ENCRYPT_FILE                0x00000001
#define EFS_DECRYPT_FILE                0x00000002
#define EFS_ENCRYPT_STREAM              0x00000003
#define EFS_DECRYPT_STREAM              0x00000004
#define EFS_DECRYPT_DIRFILE             0x80000002
#define EFS_ENCRYPT_DIRSTR              0x80000003
#define EFS_DECRYPT_DIRSTR              0x80000004


//
// EFS Version Information
//
// EFS_CURRENT_VERSION must always be the highest known revision
// level.  This value is placed in the EfsVersion field of the
// $EFS header.
//

#define EFS_VERSION_1                   (0x00000001)
#define EFS_VERSION_2                   (0x00000002)
#define EFS_CURRENT_VERSION             EFS_VERSION_2



///////////////////////////////////////////////////////////////////////////////
//                                                                            /
// EFS Data structures                                                        /
//                                                                            /
///////////////////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////////////
//                                                                  /
// EFS_KEY Structure                                                /
//                                                                  /
/////////////////////////////////////////////////////////////////////

typedef struct _EFS_KEY {

    //
    // The length in bytes of the appended key.
    //

    ULONG KeyLength;

    //
    // The number of bits of entropy in the key.
    // For example, an 8 byte key has 56 bits of
    // entropy.
    //

    ULONG Entropy;

    //
    // The algorithm used in conjunction with this key.
    //
    // Note: this is not the algorithm used to encrypt the
    // actual key data itself.
    //

    ALG_ID Algorithm;

    //
    // This structure must be a multiple of 8 in size,
    // including the KeyData at the end.
    //

    ULONG Pad;

    //
    // KeyData is appended to the end of the structure.
    //

    // UCHAR KeyData[1];

} EFS_KEY, *PEFS_KEY;

//
// Private macros to manipulate data structures
//

#define EFS_KEY_SIZE( pKey ) (sizeof( EFS_KEY ) + (pKey)->KeyLength)

#define EFS_KEY_DATA( Key )  (PUCHAR)(((PUCHAR)(Key)) + sizeof( EFS_KEY ))

#define OFFSET_TO_POINTER( FieldName, Base )  ((PCHAR)(Base) + (Base)->FieldName)

#define POINTER_TO_OFFSET( Pointer, Base ) (((PUCHAR)(Pointer)) - ((PUCHAR)(Base)))

//
// We're going to use MD5 to hash the EFS stream.  MD5 yields a 16 byte long hash.
//

#define MD5_HASH_SIZE   16

typedef struct _EFS_DATA_STREAM_HEADER {
    ULONG Length;
    ULONG State;
    ULONG EfsVersion;
    ULONG CryptoApiVersion;
    GUID  EfsId;
    UCHAR EfsHash[MD5_HASH_SIZE];
    UCHAR DrfIntegrity[MD5_HASH_SIZE];
    ULONG DataDecryptionField;          //Offset to DDF
    ULONG DataRecoveryField;            //Offset to DRF
    ULONG Reserved;
    ULONG Reserved2;
    ULONG Reserved3;
} EFS_DATA_STREAM_HEADER, *PEFS_DATA_STREAM_HEADER;



///////////////////////////////////////////////////////////////////////////////
//                                                                            /
// EFS_PUBLIC_KEY_INFO                                                        /
//                                                                            /
// This structure is used to contain all the information necessary to decrypt /
// the FEK.                                                                   /
//                                                                            /
///////////////////////////////////////////////////////////////////////////////


typedef struct _EFS_CERT_HASH_DATA {
    ULONG   pbHash;             // offset from start of structure
    ULONG   cbHash;             // count of bytes in hash
    ULONG   ContainerName;      // hint data, offset to LPWSTR
    ULONG   ProviderName;       // hint data, offset to LPWSTR
    ULONG   lpDisplayInformation; // offset to an LPWSTR
} EFS_CERT_HASH_DATA, *PEFS_CERT_HASH_DATA;

typedef struct _EFS_PUBLIC_KEY_INFO {

    //
    // The length of this entire structure, including string data
    // appended to the end.
    //

    ULONG Length;

    //
    // Sid of owner of the public key (regardless of format).
    // This field is to be treated as a hint only.
    //

    ULONG PossibleKeyOwner;

    //
    // Contains information describing how to interpret
    // the public key information
    //

    ULONG KeySourceTag;

    union {
        struct {

            //
            // The following fields contain offsets based at the
            // beginning of the structure.  Each offset is to
            // a NULL terminated WCHAR string.
            //

            ULONG ContainerName;
            ULONG ProviderName;

            //
            // The exported public key used to encrypt the FEK.
            // This field contains an offset from the beginning of the
            // structure.
            //

            ULONG PublicKeyBlob;

            //
            // Length of the PublicKeyBlob in bytes
            //

            ULONG PublicKeyBlobLength;

        } ContainerInfo;

        struct {

            ULONG CertificateLength;       // in bytes
            ULONG Certificate;             // offset from start of structure

        } CertificateInfo;

        struct {

            ULONG ThumbprintLength;        // in bytes
            ULONG CertHashData;            // offset from start of structure

        } CertificateThumbprint;
    };



} EFS_PUBLIC_KEY_INFO, *PEFS_PUBLIC_KEY_INFO;

//
// Possible KeyTag values
//

typedef enum _PUBLIC_KEY_SOURCE_TAG {
    EfsCryptoAPIContainer = 1,
    EfsCertificate,
    EfsCertificateThumbprint
} PUBLIC_KEY_SOURCE_TAG, *PPUBLIC_KEY_SOURCE_TAG;


///////////////////////////////////////////////////////////////////////////////
//                                                                            /
//  RECOVERY_KEY Data Structure                                               /
//                                                                            /
///////////////////////////////////////////////////////////////////////////////

//
// Current format of recovery data.
//

typedef struct _RECOVERY_KEY_1_1   {
        ULONG               TotalLength;
        EFS_PUBLIC_KEY_INFO PublicKeyInfo;
} RECOVERY_KEY_1_1, *PRECOVERY_KEY_1_1;



///////////////////////////////////////////////////////////////////////////////
//                                                                            /
// KEY_INTEGRITY_INFO                                                         /
//                                                                            /
// The KEY_INTEGRITY_INFO structure is used to verify that                    /
// the user's key has correctly decrypted the file's FEK.                     /
//                                                                            /
///////////////////////////////////////////////////////////////////////////////

typedef struct _KEY_INTEGRITY_INFO {

    //
    // The length of the entire structure, including the
    // variable length integrity information appended to
    // the end
    //

    ULONG Length;

    //
    // The algorithm used to hash the combined FEK and
    // public key
    //

    ALG_ID HashAlgorithm;

    //
    // The length of just the hash data.
    //

    ULONG HashDataLength;

    //
    // Integrity information goes here
    //

    // UCHAR Integrity Info[]
} KEY_INTEGRITY_INFO, *PKEY_INTEGRITY_INFO;

typedef struct _EFS_KEY_SALT {
    ULONG Length;   // total length of header plus data
    ULONG SaltType; // figure out what you want for this
    //
    // Put data here, so total length of the structure is
    // sizeof( EFS_KEY_SALT ) + length of your data
    //
} EFS_KEY_SALT, *PEFS_KEY_SALT;

//
// EFS Private DataStructures
//

typedef struct _ENCRYPTED_KEY {

    //
    // Total length of this structure and its data
    //

    ULONG Length;

    //
    // contains an offset from beginning of structure,
    // used to decrypt the EncryptedKey
    //

    ULONG PublicKeyInfo;

    //
    // Length in bytes of EncryptedFEK field
    //

    ULONG EncryptedFEKLength;

    //
    // offset from beginning of structure to encrypted
    // EFS_KEY containing the FEK
    //
    // Type is PUCHAR because data is encrypted.
    //

    ULONG EncryptedFEK;

    //
    // offset from beginning of structure to KEY_INTEGRITY_INFO
    //

    ULONG EfsKeySalt;

    //
    // FEK Data
    //
    // KEY_INTEGRITY_INFO Data
    //
    // PEFS_PUBLIC_KEY_INFO Data
    //

} ENCRYPTED_KEY, *PENCRYPTED_KEY;


//
// The Key Ring Structure.
//

typedef struct _ENCRYPTED_KEYS {
    ULONG           KeyCount;
    ENCRYPTED_KEY   EncryptedKey[1];
} ENCRYPTED_KEYS, *PENCRYPTED_KEYS;

typedef ENCRYPTED_KEYS      DDF, *PDDF;
typedef ENCRYPTED_KEYS      DRF, *PDRF;

typedef struct _EFS_STREAM_SIZE {
    ULONG       StreamFlag;
    LARGE_INTEGER   EOFSize;
    LARGE_INTEGER   AllocSize;
} EFS_STREAM_SIZE, *PEFS_STREAM_SIZE;

#define NEXT_ENCRYPTED_KEY( pEncryptedKey )  (PENCRYPTED_KEY)(((PBYTE)(pEncryptedKey)) + *((ULONG UNALIGNED *)&((PENCRYPTED_KEY)(pEncryptedKey))->Length))


//
// Import context
//

typedef struct IMPORT_CONTEXT{

    ULONG       ContextID; //To distinguish from other LSA context. Offset is fixed across LSA.
    ULONG       Flag;   // Indicate the type of context
    HANDLE      Handle; // File handle, used to create rest streams
    ULONG       Attribute;
    ULONG       CreateDisposition;
    ULONG       CreateOptions;
    ULONG       DesiredAccess;

} IMPORT_CONTEXT, *PIMPORT_CONTEXT;

//
// Export context
//

typedef struct EXPORT_CONTEXT{

    ULONG           ContextID; //To distinguish from other LSA context. Offset is fixed across LSA.
    ULONG           Flag;   // Indicate the type of context
    HANDLE          Handle; // File handle, used to open rest streams
    ULONG           NumberOfStreams;
    PHANDLE         StreamHandles;
    PUNICODE_STRING StreamNames;
    PFILE_STREAM_INFORMATION StreamInfoBase;

} EXPORT_CONTEXT, *PEXPORT_CONTEXT;

//
// EFS Export/Import RPC pipe status
//

typedef struct EFS_EXIM_STATE{
    PVOID   ExImCallback;
    PVOID   CallbackContext;
    char     *WorkBuf;
    ULONG   BufLength;
    ULONG  Status;
} EFS_EXIM_STATE, *PEFS_EXIM_STATE;

//
// Export file format
//

typedef struct EFSEXP_FILE_HEADER{

    ULONG  VersionID;   // Export file version
    WCHAR  FileSignature[EFS_SIGNATURE_LENGTH]; // Signature of the file
    ULONG  Reserved[2];
    //STREAM_DADA     Streams[0];  // An array of STREAM_BLOCK

} EFSEXP_FILE_HEADER, *PEFSEXP_FILE_HEADER;

typedef struct EFSEXP_STREAM_HEADER{

    ULONG    Length; // Redundant information. The length of this block not including DataBlocks but
                     // including itself; This field is to simplify the import routine.
    WCHAR    StreamSignature[EFS_SIGNATURE_LENGTH]; // Signature of the stream
    ULONG    Flag;  // Indicating if the stream is encrypted or not and etc.
    ULONG    Reserved[2];  // For future use
    ULONG    NameLength;   // Length of the stream name
    //WCHAR    StreamName[0];   // ID of the stream, Binary value can be used.
    //DATA_BLOCK   DataBlocks[0]; // Variable number of data block

} EFSEXP_STREAM_HEADER, *PEFSEXP_STREAM_HEADER;

typedef struct EFSEXP_DATA_HEADER{

    ULONG Length;      // Length of the block including this ULONG
    WCHAR DataSignature[EFS_SIGNATURE_LENGTH]; // Signature of the data
    ULONG Flag;          // For future use.
    // BYTE  DataBlock[N];  // N = Length - 2 * sizeof (ULONG) - 4 * sizeof (WCHAR)

} EFSEXP_DATA_HEADER, *PEFSEXP_DATA_HEADER;

//
//  TotalLength - total length of the RECOVERY_KEY Datastructure.
//
//  KeyName     - the storage stream will actually have the characters terminated by
//              a NULL character.
//  AlgorithmId - CryptAPI Algorithm ID - in V1 it is always RSA.
//
//  CSPName     - the storage stream will actually have the characters terminated by
//              a NULL character.
//  CSPType     - CryptAPI type of CSP.
//
//  PublicBlobLength - Length of the public blob that is importable in CryptoAPI in bytes.
//

//
//  Recovery Policy Data Structures
//

typedef struct _RECOVERY_POLICY_HEADER {
    USHORT      MajorRevision;
    USHORT      MinorRevision;
    ULONG       RecoveryKeyCount;
} RECOVERY_POLICY_HEADER, *PRECOVERY_POLICY_HEADER;

typedef struct _RECOVERY_POLICY_1_1    {
        RECOVERY_POLICY_HEADER  RecoveryPolicyHeader;
        RECOVERY_KEY_1_1        RecoveryKeyList[1];
}   RECOVERY_POLICY_1_1, *PRECOVERY_POLICY_1_1;

#define EFS_RECOVERY_POLICY_MAJOR_REVISION_1   (1)
#define EFS_RECOVERY_POLICY_MINOR_REVISION_0   (0)

#define EFS_RECOVERY_POLICY_MINOR_REVISION_1   (1)

//
//  Major/Minor Revision - revision number of policy information.
//
//  RecoveryKeyCount - number of recovery keys configured in this policy.
//
//  RecoveryKeyList - array of recovery keys.
//

//
// Session Key Structure
//

#define SESSION_KEY_SIZE    8
#define COMMON_FSCTL_HEADER_SIZE (7 * sizeof( ULONG ) + 2 * SESSION_KEY_SIZE)

typedef struct _EFS_INIT_DATAEXG {
    UCHAR Key[SESSION_KEY_SIZE];
    HANDLE LsaProcessID; // The reason we use HANDLE is for the sake of 64 bits
} EFS_INIT_DATAEXG, *PEFS_INIT_DATAEXG;


//
// Server API, callable from kernel mode
//

NTSTATUS
EfsGenerateKey(
      PEFS_KEY * Fek,
      PEFS_DATA_STREAM_HEADER * EfsStream,
      PEFS_DATA_STREAM_HEADER DirectoryEfsStream,
      ULONG DirectoryEfsStreamLength,
      PVOID * BufferBase,
      PULONG BufferLength
      );


NTSTATUS
GenerateDirEfs(
    PEFS_DATA_STREAM_HEADER DirectoryEfsStream,
    ULONG DirectoryEfsStreamLength,
    PEFS_DATA_STREAM_HEADER * NewEfs,
    PVOID * BufferBase,
    PULONG BufferLength
    );


#define EFS_OPEN_NORMAL  1
#define EFS_OPEN_RESTORE 2
#define EFS_OPEN_BACKUP  3

NTSTATUS
EfsDecryptFek(
    IN OUT PEFS_KEY * Fek,
    IN PEFS_DATA_STREAM_HEADER CurrentEfs,
    IN ULONG EfsStreamLength,
    IN ULONG OpenType,                      //Normal, Recovery or Backup
    OUT PEFS_DATA_STREAM_HEADER *NewEfs,     //In case the DDF, DRF are changed
    PVOID * BufferBase,
    PULONG BufferLength
    );

NTSTATUS
GenerateSessionKey(
    OUT EFS_INIT_DATAEXG * SessionKey
    );


//
// Private usermode server API
//

ULONG
EfsEncryptFileRPCClient(
    IN PUNICODE_STRING    FileName
    );

ULONG
EfsDecryptFileRPCClient(
    PUNICODE_STRING      FileName,
    ULONG   OpenFlag
    );

ULONG
EfsOpenFileRawRPCClient(
    IN  LPCWSTR    FileName,
    IN  ULONG   Flags,
    OUT PVOID * Context
    );

VOID
EfsCloseFileRawRPCClient(
    IN  PVOID   Context
    );

#ifdef __cplusplus
}
#endif

#endif // _EFSSTRUC_
