Add EFS structure definitions to layout.h and adapt ntfsdecrypt for it.

More fixes/cleanups to decrypt.c.
This was all Yuval's work but I did some renaming afterwards and some
whitespace cleanups.
edge.strict_endians
antona 2005-07-28 10:36:31 +00:00
parent 0a18d2fce7
commit 2546690ee1
4 changed files with 174 additions and 58 deletions

View File

@ -251,7 +251,7 @@ typedef union {
EA_ATTR ea;
PROPERTY_SET property_set;
LOGGED_UTILITY_STREAM logged_util_stream;
EFS_ATTR efs;
EFS_ATTR_HEADER efs;
} attr_val;
extern void ntfs_attr_init(ntfs_attr *na, const BOOL non_resident,

View File

@ -1,8 +1,9 @@
/*
* layout.h - Ntfs on-disk layout structures. Part of the Linux-NTFS project.
*
* Copyright (c) 2000-2004 Anton Altaparmakov
* Copyright (c) 2000-2005 Anton Altaparmakov
* Copyright (c) 2005 Yura Pakhuchiy
* Copyright (c) 2005 Yuval Fledel
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
@ -2354,14 +2355,97 @@ typedef struct {
* Operations on this attribute are logged to the journal ($LogFile) like
* normal metadata changes.
*
* Used by the Encrypting File System (EFS). All encrypted files have this
* attribute with the name $EFS.
* Used by the Encrypting File System (EFS). All encrypted files have this
* attribute with the name $EFS. See below for the relevant structures.
*/
typedef struct {
/* Can be anything the creator chooses. */
/* EFS uses it as follows: */
// FIXME: Type this info, verifying it along the way. (AIA)
} __attribute__ ((__packed__)) LOGGED_UTILITY_STREAM, EFS_ATTR;
} __attribute__ ((__packed__)) LOGGED_UTILITY_STREAM;
/*
* $EFS Data Structure:
*
* The following information is about the data structures that are contained
* inside a logged utility stream (0x100) with a name of "$EFS".
*
* The stream starts with an instance of EFS_ATTR_HEADER.
*
* Next, at offsets offset_to_ddf_array and offset_to_drf_array (unless any of
* them is 0) there is a EFS_DF_ARRAY_HEADER immediately followed by a sequence
* of multiple data decryption/recovery fields.
*
* Each data decryption/recovery field starts with a EFS_DF_HEADER and the next
* one (if it exists) can be found by adding EFS_DF_HEADER->df_length bytes to
* the offset of the beginning of the current EFS_DF_HEADER.
*
* The data decryption/recovery field contains an EFS_DF_CERTIFICATE_HEADER, a
* SID, an optional GUID, an optional container name, a non-optional user name,
* and the encrypted FEK.
*
* Note all the below are best guesses so may have mistakes/inaccuracies.
* Corrections/clarifications/additions are always welcome!
*/
/* The header of the 0x100 attribute named "$EFS". */
typedef struct {
/* 0*/ u32 efs_length; /* Length of attribute in bytes. */
u32 unknown1; /* always 0? */
u32 unknown2; /* number of DDFs? */
u32 unknown3; /* number of DRFs? */
/* 16*/ u8 unknown4[16]; /* MD5 hash related to DDFs? */
/* 32*/ u8 unknown5[16]; /* MD5 hash related to DRFs? */
/* 48*/ u8 unknown6[16]; /* always 0? */
/* 64*/ u32 offset_to_ddf_array;/* Offset in bytes to the array of data
decryption fields (DDF), see below. Zero if
no DDFs are present. */
u32 offset_to_drf_array;/* Offset in bytes to the array of data
recovery fields (DRF), see below. Zero if
no DRFs are present. */
} __attribute__ ((__packed__)) EFS_ATTR_HEADER;
typedef struct {
u32 df_count; /* Number of data decryption/recovery fields in
the array. */
} __attribute__ ((__packed__)) EFS_DF_ARRAY_HEADER;
typedef struct {
/* 0*/ u32 df_length; /* Length of this data decryption/recovery
field in bytes. */
u32 cred_header_offset; /* Offset in bytes to the credential header. */
u32 fek_size; /* Size in bytes of the encrypted file
encryption key (FEK). */
u32 fek_offset; /* Offset in bytes to the FEK from the start of
the data decryption/recovery field. */
/* 16*/ u32 unknown1; /* always 0? */
} __attribute__ ((__packed__)) EFS_DF_HEADER;
typedef struct {
/* 0*/ u32 cred_length; /* Length of this credential in bytes. */
u32 sid_offset; /* Offset in bytes to the user's sid from start
of this structure. */
u32 cred_version; /* always 3? */
u32 cert_header_size; /* Size in bytes of the certificate header. */
/* 16*/ u32 cert_header_offset; /* Offset in bytes to the certificate header
from start of this structure. */
u32 unknown1; /* always 0? */
u32 unknown2; /* always 0? */
} __attribute__ ((__packed__)) EFS_DF_CREDENTIAL_HEADER;
typedef EFS_DF_CREDENTIAL_HEADER EFS_DF_CRED_HEADER;
typedef struct {
/* 0*/ u32 thumbprint_offset; /* Offset in bytes to the thumbprint. */
u32 thumbprint_size; /* Size of thumbprint in bytes. */
/* 8*/ u32 guid_offset; /* Offset in bytes to GUID from start
if this structure or 0 if no GUID
present. */
u32 container_name_offset; /* Offset in bytes to the name of the
container from start of this
structure or 0 if no name present. */
/* 16*/ u32 user_name_offset; /* Offset in bytes to the user name
from start of this structure. */
} __attribute__ ((__packed__)) EFS_DF_CERTIFICATE_HEADER;
typedef EFS_DF_CERTIFICATE_HEADER EFS_DF_CERT_HEADER;
#endif /* defined _NTFS_LAYOUT_H */

View File

@ -161,8 +161,7 @@ ntfs_decrypt_user_key_session *ntfs_decrypt_user_key_session_open(void)
return NULL;
}
if (!(hSystemStore = fnCertOpenStore(((LPCSTR)CERT_STORE_PROV_SYSTEM),
0, (HCRYPTPROV)NULL, CERT_SYSTEM_STORE_CURRENT_USER,
L"MY"))) {
0, 0, CERT_SYSTEM_STORE_CURRENT_USER, L"MY"))) {
fprintf(stderr, "Could not open system store.\n");
errno = EINVAL;
return NULL;
@ -195,6 +194,13 @@ void ntfs_decrypt_user_key_session_close(ntfs_decrypt_user_key_session *session)
free(session);
}
/**
* reverse_buffer -
*
* This is a utility function for reversing the order of a buffer in place.
* Users of this function should be very careful not to sweep byte order
* problems under the rug.
*/
static inline void reverse_buffer(unsigned char *buf, unsigned buf_size)
{
unsigned char t;
@ -256,14 +262,14 @@ ntfs_decrypt_user_key *ntfs_decrypt_user_key_open(
&key_size)) {
fprintf(stderr, "Could not export key: Error 0x%x\n",
(unsigned)GetLastError());
errno = -1;
errno = EINVAL;
return NULL;
}
CryptDestroyKey(hCryptKey);
rsa_pub_key = (RSAPUBKEY*)(key_blob + sizeof(PUBLICKEYSTRUC));
if ((err = gcry_ac_open(&gcry_handle, GCRY_AC_RSA, 0))) {
fprintf(stderr, "Could not init gcrypt handle\n");
errno = -1;
errno = EINVAL;
return NULL;
}
gcry_control(GCRYCTL_DISABLE_SECMEM, 0);
@ -302,8 +308,8 @@ ntfs_decrypt_user_key *ntfs_decrypt_user_key_open(
errno = EINVAL;
return NULL;
}
if ((key = (ntfs_decrypt_user_key*)malloc(
sizeof(NTFS_DECRYPT_USER_KEY))))
if ((key = (ntfs_decrypt_user_key*)
malloc(sizeof(NTFS_DECRYPT_USER_KEY))))
((NTFS_DECRYPT_USER_KEY*)key)->sexp_key = sexp_key;
// todo: release all
return key;
@ -312,8 +318,10 @@ decrypt_key_open_err:
CryptDestroyKey(hCryptKey);
if (pCert)
fnCertFreeCertificateContext(pCert);
#endif /* defined(__CYGWIN__) */
errno = EINVAL;
#else /* !defined(__CYGWIN__) */
errno = ENOTSUP;
#endif /* !defined(__CYGWIN__) */
return NULL;
}
@ -427,6 +435,14 @@ static void ntfs_desx_key_expand(const u8 *src, u32 *des_key,
*in_whitening = *(u64*)(md + 2);
}
/**
* ntfs_desx_setkey - libgcrypt set_key implementation for DES-X-MS128
* @context: pointer to a variable of type ntfs_desx_ctx
* @key: the 128 bit DES-X-MS128 key, concated with the DES handle
* @keylen: must always be 16
*
* This is the libgcrypt set_key implementation for DES-X-MS128.
*/
static gcry_err_code_t ntfs_desx_setkey(void *context, const u8 *key,
unsigned keylen)
{
@ -606,8 +622,6 @@ ntfs_decrypt_data_key *ntfs_decrypt_data_key_open(unsigned char *data,
case CALG_DESX:
/* FIXME: This really needs locking so it is safe from races. */
if (!ntfs_desx_module_count++) {
gcry_error_t err;
if (!desx_key_expand_test() || !des_test()) {
errno = EINVAL;
return NULL;

View File

@ -272,17 +272,60 @@ static int cat_decrypt(ntfs_inode *inode, ntfs_decrypt_data_key *fek)
return 0;
}
static ntfs_decrypt_data_key *get_fek_from_df_array(
ntfs_decrypt_user_key_session *session,
EFS_DF_ARRAY_HEADER *efs_df_array)
{
u32 ddf_count, hash_size, fek_size;
EFS_DF_CREDENTIAL_HEADER *efs_df_cred;
EFS_DF_CERTIFICATE_HEADER *efs_df_cert;
EFS_DF_HEADER *efs_df_header;
ntfs_decrypt_user_key *key;
u8 *hash_data, *fek_buf;
unsigned i;
efs_df_header = (EFS_DF_HEADER*)(efs_df_array + 1);
ddf_count = le32_to_cpu(efs_df_array->df_count);
for (i = 0; i < ddf_count; i++) {
//Eprintf("ddf #%u.\n", i);
efs_df_cred = (EFS_DF_CREDENTIAL_HEADER*)((u8*)efs_df_header +
le32_to_cpu(efs_df_header->cred_header_offset));
efs_df_cert = (EFS_DF_CERTIFICATE_HEADER*)((u8*)efs_df_cred +
le32_to_cpu(efs_df_cred->cert_header_offset));
hash_size = le32_to_cpu(efs_df_cert->thumbprint_size);
hash_data = (u8*)efs_df_cert +
le32_to_cpu(efs_df_cert->thumbprint_offset);
fek_size = le32_to_cpu(efs_df_header->fek_size);
fek_buf = (u8*)efs_df_header +
le32_to_cpu(efs_df_header->fek_offset);
if ((key = ntfs_decrypt_user_key_open(session, hash_data,
hash_size))) {
fek_size = ntfs_decrypt_user_key_decrypt(key, fek_buf,
fek_size);
ntfs_decrypt_user_key_close(key);
if (fek_size)
return ntfs_decrypt_data_key_open(fek_buf,
fek_size);
fprintf(stderr, "Failed to decrypt the FEK.\n");
} else
perror("Failed to open user key");
efs_df_header = (EFS_DF_HEADER*)((u8*)efs_df_header +
le32_to_cpu(efs_df_header->df_length));
}
return NULL;
}
/**
* get_fek
*/
static ntfs_decrypt_data_key *get_fek(ntfs_inode *inode)
{
ntfs_attr *na;
unsigned char *efs_buffer, *ddf, *certificate, *hash_data, *fek_buf;
u32 ddf_count, hash_size, fek_size;
unsigned i;
ntfs_decrypt_user_key_session *session;
ntfs_decrypt_user_key *key;
EFS_DF_ARRAY_HEADER *efs_df_array;
ntfs_decrypt_data_key *fek;
EFS_ATTR_HEADER *efs_attr;
u8 *efs_buffer;
ntfs_attr *na;
/* Obtain the $EFS contents. */
na = ntfs_attr_open(inode, AT_LOGGED_UTILITY_STREAM,
@ -313,44 +356,19 @@ static ntfs_decrypt_data_key *get_fek(ntfs_inode *inode)
return NULL;
}
/* Iterate through the DDFs & DRFs until we obtain a key. */
ddf = efs_buffer + le32_to_cpu(*(u32*)(efs_buffer + 0x40));
ddf_count = le32_to_cpu(*(u32*)ddf);
ddf = ddf + 0x04;
for (i = 0; i < ddf_count; i++) {
//Eprintf("ddf #%u.\n", i);
if (*(u32*)(ddf + 0x18))
certificate = (ddf + 0x30 +
le32_to_cpu(*(u32*)(ddf + 0x18)));
else
certificate = (ddf + 0x30);
hash_size = (unsigned)le32_to_cpu(*(u32*)certificate);
hash_data = certificate + (unsigned)
le32_to_cpu(*(u32*)(certificate + 0x04));
fek_size = (unsigned)le32_to_cpu(*(u32*)(ddf + 0x08));
fek_buf = ddf + (unsigned)le32_to_cpu(*(u32*)(ddf + 0x0c));
if ((key = ntfs_decrypt_user_key_open(session, hash_data,
hash_size))) {
fek_size = ntfs_decrypt_user_key_decrypt(key, fek_buf,
fek_size);
ntfs_decrypt_user_key_close(key);
if (fek_size) {
ntfs_decrypt_data_key *fek;
ntfs_decrypt_user_key_session_close(session);
fek = ntfs_decrypt_data_key_open(fek_buf,
fek_size);
free(efs_buffer);
return fek;
}
fprintf(stderr, "Failed to decrypt the FEK.\n");
} else
perror("Failed to open user key");
ddf = ddf + le32_to_cpu(*(u32*)(ddf + 0x08)) +
le32_to_cpu(*(u32*)(ddf + 0x0c));
efs_attr = (EFS_ATTR_HEADER*)efs_buffer;
efs_df_array = (EFS_DF_ARRAY_HEADER*)(efs_buffer +
le32_to_cpu(efs_attr->offset_to_ddf_array));
fek = get_fek_from_df_array(session, efs_df_array);
if (!fek) {
efs_df_array = (EFS_DF_ARRAY_HEADER*)(efs_buffer +
le32_to_cpu(efs_attr->offset_to_drf_array));
fek = get_fek_from_df_array(session, efs_df_array);
}
/* Close all and return. */
ntfs_decrypt_user_key_session_close(session);
return NULL;
free(efs_buffer);
return fek;
}
/**