Changes by: antona
Update of /cvsroot/linux-ntfs/ntfsprogs/ntfsprogs
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29728
Modified Files:
ntfsdecrypt.c decrypt.c decrypt.h
Log Message:
First pass at massive cleanup of ntfsdectypt/decrypt.
Index: ntfsdecrypt.c
===================================================================
RCS file: /cvsroot/linux-ntfs/ntfsprogs/ntfsprogs/ntfsdecrypt.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -p -r1.5 -r1.6
--- ntfsdecrypt.c 27 Jul 2005 10:48:46 -0000 1.5
+++ ntfsdecrypt.c 27 Jul 2005 15:55:42 -0000 1.6
@@ -210,13 +210,14 @@ static int parse_options(int argc, char
/**
* cat
*/
-static int cat_decrypt(ntfs_inode *inode, decrypt_key *fek)
+static int cat_decrypt(ntfs_inode *inode, ntfs_decrypt_data_key *fek)
{
int bufsize = 512;
char *buffer;
ntfs_attr *attr;
s64 bytes_read, written, offset, total;
- unsigned int i;
+ s64 old_data_size, old_initialized_size;
+ unsigned i;
buffer = malloc(bufsize);
if (!buffer)
@@ -233,6 +234,8 @@ static int cat_decrypt(ntfs_inode *inode
// clear the encrypted bit, otherwise the library won't allow reading.
NAttrClearEncrypted(attr);
// extend the size, we may need to read past the end of the stream.
+ old_data_size = attr->data_size;
+ old_initialized_size = attr->initialized_size;
attr->data_size = attr->initialized_size = attr->allocated_size;
offset = 0;
@@ -244,8 +247,8 @@ static int cat_decrypt(ntfs_inode *inode
}
if (!bytes_read)
break;
- if ((i = decrypt_decrypt_sector(fek, buffer, offset)) <
- bytes_read) {
+ if ((i = ntfs_decrypt_data_key_decrypt_sector(fek, buffer,
+ offset)) < bytes_read) {
perror("ERROR: Couldn't decrypt all data!");
Eprintf("%u/%lld/%lld/%lld\n", i, (long long)bytes_read,
(long long)offset, (long long)total);
@@ -261,6 +264,9 @@ static int cat_decrypt(ntfs_inode *inode
offset += bytes_read;
total -= bytes_read;
}
+ attr->data_size = old_data_size;
+ attr->initialized_size = old_initialized_size;
+ NAttrSetEncrypted(attr);
ntfs_attr_close(attr);
free(buffer);
return 0;
@@ -269,41 +275,44 @@ static int cat_decrypt(ntfs_inode *inode
/**
* get_fek
*/
-static decrypt_key *get_fek(ntfs_inode * inode)
+static ntfs_decrypt_data_key *get_fek(ntfs_inode *inode)
{
ntfs_attr *na;
- char *efs_buffer, *ddf, *certificate, *hash_data, *fek_buf;
+ unsigned char *efs_buffer, *ddf, *certificate, *hash_data, *fek_buf;
u32 ddf_count, hash_size, fek_size;
- unsigned int i;
- decrypt_session *session;
- decrypt_key *key;
+ unsigned i;
+ ntfs_decrypt_user_key_session *session;
+ ntfs_decrypt_user_key *key;
- /* obtain the $EFS contents */
+ /* Obtain the $EFS contents. */
na = ntfs_attr_open(inode, AT_LOGGED_UTILITY_STREAM,
EFS, EFS_name_length);
if (!na) {
- perror("Error");
+ perror("Failed to open $EFS attribute");
return NULL;
}
efs_buffer = malloc(na->data_size);
if (!efs_buffer) {
- perror("malloc failed");
+ perror("Failed to allocate internal buffer");
+ ntfs_attr_close(na);
return NULL;
}
if (ntfs_attr_pread(na, 0, na->data_size, efs_buffer) !=
na->data_size) {
- perror("ntfs_attr_pread failed");
+ perror("Failed to read $EFS attribute");
free(efs_buffer);
+ ntfs_attr_close(na);
return NULL;
}
ntfs_attr_close(na);
/* Init the CryptoAPI. */
- if (!(session = decrypt_open())) {
- perror("Could not init the cryptoAPI.");
+ if (!(session = ntfs_decrypt_user_key_session_open())) {
+ perror("Failed to initialize the cryptoAPI");
+ free(efs_buffer);
return NULL;
}
- /* Iterate through the DDFs & DRFs until you obtain a key. */
+ /* 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);
@@ -315,32 +324,32 @@ static decrypt_key *get_fek(ntfs_inode *
le32_to_cpu(*(u32*)(ddf + 0x18)));
else
certificate = (ddf + 0x30);
-
- hash_size = (unsigned int)le32_to_cpu(*(u32*)certificate);
- hash_data = certificate + (unsigned int)
+ hash_size = (unsigned)le32_to_cpu(*(u32*)certificate);
+ hash_data = certificate + (unsigned)
le32_to_cpu(*(u32*)(certificate + 0x04));
- fek_size = (unsigned int)le32_to_cpu(*(u32*)(ddf + 0x08));
- fek_buf = ddf + (unsigned int)le32_to_cpu(*(u32*)(ddf + 0x0c));
-
- if ((key = decrypt_user_key_open(session, hash_size,
- hash_data))) {
- if ((fek_size = decrypt_decrypt(key, fek_size,
- fek_buf)))
- return decrypt_make_key(session, fek_size,
- fek_buf);
- perror("error decrypting the FEK.");
- decrypt_user_key_close(key);
- decrypt_close(session);
- errno = -1;
- return NULL;
- decrypt_user_key_close(key);
+ 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
- Eprintf("Could not open key.\n");
-
+ perror("Failed to open user key");
ddf = ddf + le32_to_cpu(*(u32*)(ddf + 0x08)) +
le32_to_cpu(*(u32*)(ddf + 0x0c));
}
- decrypt_close(session);
+ ntfs_decrypt_user_key_session_close(session);
return NULL;
}
@@ -356,7 +365,7 @@ int main(int argc, char *argv[])
{
ntfs_volume *vol;
ntfs_inode *inode;
- decrypt_key *fek;
+ ntfs_decrypt_data_key *fek;
int result = 1;
if (!parse_options(argc, argv))
@@ -381,7 +390,7 @@ int main(int argc, char *argv[])
fek = get_fek(inode);
if (fek) {
result = cat_decrypt(inode, fek);
- decrypt_user_key_close(fek);
+ ntfs_decrypt_data_key_close(fek);
} else {
Eprintf("Could not obtain FEK.\n");
result = 1;
Index: decrypt.c
===================================================================
RCS file: /cvsroot/linux-ntfs/ntfsprogs/ntfsprogs/decrypt.c,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -p -r1.13 -r1.14
--- decrypt.c 27 Jul 2005 10:48:46 -0000 1.13
+++ decrypt.c 27 Jul 2005 15:55:42 -0000 1.14
@@ -68,7 +68,7 @@ static LPFN_CertFindCertificateInStore f
static LPFN_CertFreeCertificateContext fnCertFreeCertificateContext;
static LPFN_CertOpenStore fnCertOpenStore;
-/* global variable: handle to crypt32.dll */
+/* Global variable: Handle to crypt32.dll */
static HMODULE hCrypt32 = INVALID_HANDLE_VALUE;
#else /* !defined(__CYGWIN__) */
@@ -92,113 +92,28 @@ typedef struct {
#else /* !defined(__CYGWIN__) */
int nothing; /* unused */
#endif /* !defined(__CYGWIN__) */
-} DECRYPT_SESSION;
+} NTFS_DECRYPT_USER_KEY_SESSION;
+
+typedef struct {
+ gcry_sexp_t sexp_key; // the user's RSA key.
+} NTFS_DECRYPT_USER_KEY;
typedef struct {
- u64 desx_key[3];
u8 *key_data;
u32 alg_id;
gcry_cipher_hd_t gcry_cipher_hd;
- gcry_sexp_t sexp_key; // the user's RSA key.
-} DECRYPT_KEY;
+ gcry_cipher_hd_t *des_gcry_cipher_hd_ptr;
+} NTFS_DECRYPT_DATA_KEY;
/* DESX-MS128 implementation for libgcrypt. */
-static gcry_module_t desx_module;
-static int desx_algorithm_id = -1;
+static gcry_module_t ntfs_desx_module;
+static int ntfs_desx_algorithm_id = -1;
+static int ntfs_desx_module_count;
-typedef struct desx_ctx {
+typedef struct {
+ u64 in_whitening, out_whitening;
gcry_cipher_hd_t gcry_cipher_hd;
- u8 in_whitening[8], out_whitening[8];
-} desx_ctx;
-
-/**
- * desx_key_expand - expand a 128-bit desx key to the needed 192-bit key
- * @src: source buffer containing 128-bit key
- * @dst: destination buffer to write 192-bit key to
- *
- * Expands the on-disk 128-bit desx key to the needed full 192-bit desx key
- * required to perform desx {de,en}cryption.
- *
- * FIXME: Is this endianness safe? I think so but I may be wrong...
- */
-static void desx_key_expand(const u8 *src, u8 *in_whitening, u8 *out_whitening,
- u8 *des_key)
-{
- static const int salt_len = 12;
- static const u8 *salt1 = "Dan Simon ";
- static const u8 *salt2 = "Scott Field";
- u8 md[16];
- MD5_CTX ctx1, ctx2;
-
- MD5_Init(&ctx1);
-
- /* Hash the on-disk key. */
- MD5_Update(&ctx1, src, 128 / 8);
- memcpy(&ctx2, &ctx1, sizeof(ctx1));
-
- /* Hash with the first salt and store the result. */
- MD5_Update(&ctx1, salt1, salt_len);
- MD5_Final(md, &ctx1);
- ((u32*)des_key)[0] = ((u32*)md)[0] ^ ((u32*)md)[1];
- ((u32*)des_key)[1] = ((u32*)md)[2] ^ ((u32*)md)[3];
-
- /* Hash with the second salt and store the result. */
- MD5_Update(&ctx2, salt2, salt_len);
- MD5_Final(md, &ctx2);
- memcpy(out_whitening, md, 8);
- memcpy(in_whitening, md + 8, 8);
-}
-
-static gcry_err_code_t do_desx_setkey(void *context, const u8 *key,
- unsigned keylen)
-{
- struct desx_ctx *ctx = (desx_ctx*)context;
- gcry_error_t err;
- u8 des_key[8];
-
- if (keylen != 16) {
- fprintf(stderr, "not 16\n");
- return GPG_ERR_INV_KEYLEN;
- }
- if ((err = gcry_cipher_open(&ctx->gcry_cipher_hd, GCRY_CIPHER_DES,
- GCRY_CIPHER_MODE_ECB, 0)) != GPG_ERR_NO_ERROR)
- return err;
- if ((err = gcry_cipher_reset(ctx->gcry_cipher_hd)))
- fprintf(stderr, "err is %u.\n", err);
- desx_key_expand(key, ctx->in_whitening, ctx->out_whitening, des_key);
-#if 0
- fprintf(stderr, "expanded keys (hex) =\n\t0x%llx (des)\n\t"
- "0x%llx (in-whitening)\n\t"
- "0x%llx (out-whitening)\n", *(u64*)des_key,
- *(u64*)ctx->in_whitening, *(u64*)ctx->out_whitening);
-#endif
- if ((err = gcry_cipher_setkey(ctx->gcry_cipher_hd, des_key, 8))) {
- fprintf(stderr, "do_desx_setkey: error %u.\n", err);
- // TODO: destroy gcry_cipher_hd
- }
- return GPG_ERR_NO_ERROR;
-}
-
-static void do_desx_decrypt(void *context, u8 *outbuf, const u8 *inbuf)
-{
- struct desx_ctx *ctx = (desx_ctx*)context;
- gcry_error_t err;
- u8 buf[8];
-
- *((u64*)buf) = *((const u64*)inbuf) ^ *(const u64*)ctx->out_whitening;
- if ((err = gcry_cipher_encrypt(ctx->gcry_cipher_hd, outbuf, 8, buf, 8)))
- fprintf(stderr, "desx decryption failed: %u.\n", err);
- *((u64*)outbuf) ^= *(const u64*)ctx->in_whitening;
-}
-
-static gcry_cipher_spec_t cipher = {
- .name = "DES-X-MS128",
- .blocksize = 8,
- .keylen = 128,
- .contextsize = sizeof(struct desx_ctx),
- .setkey = do_desx_setkey,
- .decrypt = do_desx_decrypt,
-};
+} ntfs_desx_ctx;
#ifdef __CYGWIN__
static int cryptoAPI_init_imports(void)
@@ -225,170 +140,62 @@ static int cryptoAPI_init_imports(void)
fnCertOpenStore = (LPFN_CertOpenStore)GetProcAddress(hCrypt32,
"CertOpenStore");
return fnCryptAcquireCertificatePrivateKey && fnCertCloseStore &&
- fnCertFindCertificateInStore && fnCertFreeCertificateContext &&
- fnCertOpenStore;
+ fnCertFindCertificateInStore &&
+ fnCertFreeCertificateContext && fnCertOpenStore;
}
#endif /* defined(__CYGWIN__) */
-//#define DO_CRYPTO_TESTS 1
-
-#ifdef DO_CRYPTO_TESTS
-/* Do not remove this test code from this file! AIA */
-static BOOL desx_key_expand_test(void)
+ntfs_decrypt_user_key_session *ntfs_decrypt_user_key_session_open(void)
{
- const u8 known_desx_on_disk_key[16] = {
- 0xa1, 0xf9, 0xe0, 0xb2, 0x53, 0x23, 0x9e, 0x8f,
- 0x0f, 0x91, 0x45, 0xd9, 0x8e, 0x20, 0xec, 0x30
- };
- const u8 known_desx_expanded_key[24] = {
- 0x27, 0xd1, 0x93, 0x09, 0xcb, 0x78, 0x93, 0x1f,
- 0xed, 0xda, 0x4c, 0x47, 0x60, 0x49, 0xdb, 0x8d,
- 0x75, 0xf6, 0xa0, 0x1a, 0xc0, 0xca, 0x28, 0x1e
- };
- u8 test_desx_expanded_key[24];
- int res;
-
- desx_key_expand(known_desx_on_disk_key, test_desx_expanded_key);
- res = !memcmp(test_desx_expanded_key, known_desx_expanded_key,
- sizeof(known_desx_expanded_key));
- fprintf(stderr, "Testing whether desx_key_expand() works: %s\n",
- res ? "SUCCESS" : "FAILED");
- return res;
-}
-
-static BOOL des_test(void)
-{
- const u8 known_des_key[8] = {
- 0x27, 0xd1, 0x93, 0x09, 0xcb, 0x78, 0x93, 0x1f
- };
- const u8 known_des_encrypted_data[8] = {
- 0xdc, 0xf7, 0x68, 0x2a, 0xaf, 0x48, 0x53, 0x0f
- };
- const u8 known_decrypted_data[8] = {
- 0xd8, 0xd9, 0x15, 0x23, 0x5b, 0x88, 0x0e, 0x09
- };
- u8 test_decrypted_data[8];
- int res;
- gcry_error_t gcry_error2;
- gcry_cipher_hd_t gcry_cipher_hd;
-
- if ((gcry_error2 = gcry_cipher_open(&gcry_cipher_hd, GCRY_CIPHER_DES,
- GCRY_CIPHER_MODE_ECB, 0)) != GPG_ERR_NO_ERROR) {
- fprintf(stderr, "Failed to open des cipher (gcry_error2 is "
- "%u).\n", gcry_error2);
- return FALSE;
- }
- if ((gcry_error2 = gcry_cipher_setkey(gcry_cipher_hd, known_des_key,
- sizeof(known_des_key)))) {
- fprintf(stderr, "Failed to set des key (gcry_error2 is %u).\n",
- gcry_error2);
- gcry_cipher_close(gcry_cipher_hd);
- return FALSE;
- }
- memcpy(test_decrypted_data, known_des_encrypted_data,
- sizeof(known_des_encrypted_data));
- /*
- * Apply DES decyption (ntfs actually uses encryption when decrypting).
- */
- gcry_error2 = gcry_cipher_encrypt(gcry_cipher_hd, test_decrypted_data,
- sizeof(test_decrypted_data), NULL, 0);
- gcry_cipher_close(gcry_cipher_hd);
- if (gcry_error2) {
- fprintf(stderr, "Failed to des decrypt test data (gcry_error2 "
- "is %u).\n", gcry_error2);
- return FALSE;
- }
- res = !memcmp(test_decrypted_data, known_decrypted_data,
- sizeof(known_decrypted_data));
- fprintf(stderr, "Testing whether des decryption works: %s\n",
- res ? "SUCCESS" : "FAILED");
- return res;
-}
-
-#else /* !defined(DO_CRYPTO_TESTS) */
-
-static inline BOOL desx_key_expand_test(void)
-{
- return TRUE;
-}
-
-static inline BOOL des_test(void)
-{
- return TRUE;
-}
-
-#endif /* !defined(DO_CRYPTO_TESTS) */
-
-decrypt_session *decrypt_open(void)
-{
- decrypt_session *session;
-
- /* TODO: refcount 'module' */
- if (desx_algorithm_id == -1) {
- if (!desx_key_expand_test())
- return NULL;
- if (!des_test())
- return NULL;
- if (gcry_cipher_register(&cipher, &desx_algorithm_id,
- &desx_module))
- return NULL;
- }
- //fprintf(stderr, "desx_algorithm_id: %d\n", desx_algorithm_id);
-
- gcry_control(GCRYCTL_DISABLE_SECMEM, 0);
-
+ ntfs_decrypt_user_key_session *session;
#ifdef __CYGWIN__
HCERTSTORE hSystemStore;
+ /*
+ * FIXME: This really needs locking and reference counting so it is
+ * safe from races.
+ */
if (!cryptoAPI_init_imports()) {
fprintf(stderr, "Some imports do not exist.\n");
- errno = -1;
+ errno = EINVAL;
return NULL;
}
-
- if (!(hSystemStore = fnCertOpenStore(((LPCSTR) CERT_STORE_PROV_SYSTEM),
- 0, (HCRYPTPROV) NULL, CERT_SYSTEM_STORE_CURRENT_USER,
- L"MY"))) {
+ if (!(hSystemStore = fnCertOpenStore(((LPCSTR)CERT_STORE_PROV_SYSTEM),
+ 0, NULL, CERT_SYSTEM_STORE_CURRENT_USER, L"MY"))) {
fprintf(stderr, "Could not open system store.\n");
- errno = -1;
+ errno = EINVAL;
return NULL;
}
#endif /* defined(__CYGWIN__) */
- session = (decrypt_session*)malloc(sizeof(DECRYPT_SESSION));
+ session = malloc(sizeof(NTFS_DECRYPT_USER_KEY_SESSION));
#ifdef __CYGWIN__
- ((DECRYPT_SESSION *)session)->hSystemStore = hSystemStore;
+ ((NTFS_DECRYPT_USER_KEY_SESSION*)session)->hSystemStore = hSystemStore;
#endif /* defined(__CYGWIN__) */
return session;
}
-void decrypt_close(decrypt_session *session)
+void ntfs_decrypt_user_key_session_close(ntfs_decrypt_user_key_session *session)
{
#ifdef __CYGWIN__
- if (((DECRYPT_SESSION*)session)->hSystemStore)
- fnCertCloseStore(((DECRYPT_SESSION*)session)->hSystemStore,
- CERT_CLOSE_STORE_CHECK_FLAG);
- /* fixme: racy */
- FreeLibrary(hCrypt32);
+ HMODULE tmp;
+
+ if (((NTFS_DECRYPT_USER_KEY_SESSION*)session)->hSystemStore)
+ fnCertCloseStore(((NTFS_DECRYPT_USER_KEY_SESSION*)session)->
+ hSystemStore, CERT_CLOSE_STORE_CHECK_FLAG);
+ /*
+ * FIXME: This really needs locking and reference counting so it is
+ * safe from races.
+ */
+ tmp = hCrypt32;
hCrypt32 = INVALID_HANDLE_VALUE;
+ FreeLibrary(tmp);
#endif /* defined(__CYGWIN__) */
free(session);
}
-static inline void reverse_buffer(unsigned char *buf, unsigned int buf_size)
-{
- unsigned char t;
- unsigned int i;
-
- for (i = 0; i < buf_size / 2; i++) {
- t = buf[i];
- buf[i] = buf[buf_size - i - 1];
- buf[buf_size - i - 1] = t;
- }
-}
-
-decrypt_key *decrypt_user_key_open(
- decrypt_session *session __attribute__ ((unused)),
- int thumb_size, void *thumb_print)
+ntfs_decrypt_user_key *ntfs_decrypt_user_key_open(
+ ntfs_decrypt_user_key_session *session __attribute__((unused)),
+ unsigned char *thumb_print, unsigned thumb_size)
{
#ifdef __CYGWIN__
CRYPT_HASH_BLOB hash_blob;
@@ -396,7 +203,7 @@ decrypt_key *decrypt_user_key_open(
PCCERT_CONTEXT pCert;
BOOL fCallerFreeProv;
HCRYPTKEY hCryptKey;
- decrypt_key *key;
+ ntfs_decrypt_user_key *key;
DWORD dwKeySpec;
DWORD key_size;
BYTE key_blob[1000];
@@ -434,12 +241,10 @@ decrypt_key *decrypt_user_key_open(
if (!CryptExportKey(hCryptKey, 0, PRIVATEKEYBLOB, 0, key_blob,
&key_size)) {
fprintf(stderr, "Could not export key: Error 0x%x\n",
- (unsigned int)GetLastError());
+ (unsigned)GetLastError());
errno = -1;
return NULL;
}
- if (!(key = (decrypt_key*)malloc(sizeof(DECRYPT_KEY))))
- goto decrypt_key_open_err;
CryptDestroyKey(hCryptKey);
rsa_pub_key = (RSAPUBKEY*)(key_blob + sizeof(PUBLICKEYSTRUC));
if ((err = gcry_ac_open(&gcry_handle, GCRY_AC_RSA, 0))) {
@@ -468,21 +273,22 @@ decrypt_key *decrypt_user_key_open(
reverse_buffer(mpi_data, size);
if ((rc = gcry_mpi_scan(&u, GCRYMPI_FMT_USG, mpi_data, size, &size)))
fprintf(stderr, "error scanning u.\n");
-
mpi_data += (rsa_pub_key->bitlen / 16);
size = rsa_pub_key->bitlen / 8;
reverse_buffer(mpi_data, size);
if ((rc = gcry_mpi_scan(&d, GCRYMPI_FMT_USG, mpi_data, size, &size)))
fprintf(stderr, "error scanning d.\n");
+ sexp_key = NULL;
if ((rc = gcry_sexp_build(&sexp_key, NULL, "(private-key (rsa (n %m) "
"(e %m) (d %m) (p %m) (q %m) (u %m)))", n, e, d, p, q,
u))) {
fprintf(stderr, "Could build sexp from data, (error = 0x%x)\n",
rc);
- errno = -1;
- return FALSE;
+ errno = EINVAL;
+ return NULL;
}
- ((DECRYPT_KEY*)key)->sexp_key = sexp_key;
+ if ((key = (decrypt_key*)malloc(sizeof(NTFS_DECRYPT_USER_KEY))))
+ ((NTFS_DECRYPT_USER_KEY*)key)->sexp_key = sexp_key;
// todo: release all
return key;
decrypt_key_open_err:
@@ -490,45 +296,51 @@ decrypt_key_open_err:
CryptDestroyKey(hCryptKey);
if (pCert)
fnCertFreeCertificateContext(pCert);
-#endif // defined(__CYGWIN__)
+#endif /* defined(__CYGWIN__) */
errno = ENOTSUP;
return NULL;
}
-void decrypt_user_key_close(decrypt_key *key)
+void ntfs_decrypt_user_key_close(ntfs_decrypt_user_key *key)
{
- DECRYPT_KEY *dkey = (DECRYPT_KEY*)key;
- if (dkey->gcry_cipher_hd)
- gcry_cipher_close(dkey->gcry_cipher_hd);
+ gcry_sexp_release(((NTFS_DECRYPT_USER_KEY*)key)->sexp_key);
free(key);
}
+static inline void reverse_buffer(unsigned char *buf, unsigned buf_size)
+{
+ unsigned char t;
+ unsigned i;
+
+ for (i = 0; i < buf_size / 2; i++) {
+ t = buf[i];
+ buf[i] = buf[buf_size - i - 1];
+ buf[buf_size - i - 1] = t;
+ }
+}
+
/**
- * decrypt_decrypt
- *
* warning: decrypting into the input buffer!
*/
-unsigned int decrypt_decrypt(decrypt_key *key, unsigned int data_size,
- unsigned char *data)
+unsigned ntfs_decrypt_user_key_decrypt(ntfs_decrypt_user_key *key,
+ unsigned char *data, unsigned data_size)
{
gcry_sexp_t sexp_plain_data, sexp_enc_data;
gcry_ac_handle_t gcry_handle;
gcry_mpi_t mpi_buf;
gcry_ac_data_t in;
gcry_error_t err;
- unsigned int size, padding_length, i;
+ unsigned size, padding_length, i;
int rc;
if ((err = gcry_ac_open(&gcry_handle, GCRY_AC_RSA, 0))) {
fprintf(stderr, "Could not init gcrypt handle\n");
- errno = -1;
- return FALSE;
+ errno = EINVAL;
+ return 0;
}
if ((rc = gcry_ac_data_new(&in)))
fprintf(stderr, "error allocating 'in'.\n");
-
reverse_buffer(data, data_size);
-
size = data_size;
if ((rc = gcry_mpi_scan(&mpi_buf, GCRYMPI_FMT_USG, data,
(size_t)data_size, &size)))
@@ -537,31 +349,30 @@ unsigned int decrypt_decrypt(decrypt_key
"(rsa (a %m)))", mpi_buf))) {
fprintf(stderr, "Could build sexp from data, (error = 0x%x)\n",
rc);
- errno = -1;
- return FALSE;
+ errno = EINVAL;
+ return 0;
}
if ((rc = gcry_pk_decrypt(&sexp_plain_data, sexp_enc_data,
- ((DECRYPT_KEY*)key)->sexp_key))) {
+ ((NTFS_DECRYPT_USER_KEY*)key)->sexp_key))) {
fprintf(stderr, "Could not decrypt fek via s-exp, (error = "
"0x%x)\n", rc);
- errno = -1;
- return FALSE;
+ errno = EINVAL;
+ return 0;
}
sexp_plain_data = gcry_sexp_find_token(sexp_plain_data, "value", 0);
if (!mpi_buf) {
fprintf(stderr, "Could find value in s-exp, (error = 0x%x)\n",
rc);
- errno = -1;
- return FALSE;
+ errno = EINVAL;
+ return 0;
}
mpi_buf = gcry_sexp_nth_mpi(sexp_plain_data, 1, GCRYMPI_FMT_USG);
-
if ((rc = gcry_mpi_print(GCRYMPI_FMT_USG, data, data_size, &size,
mpi_buf))) {
fprintf(stderr, "Could copy decrypted data back, (error = "
"0x%x)\n", rc);
- errno = -1;
- return FALSE;
+ errno = EINVAL;
+ return 0;
}
// remove the pkcs1 padding
for (padding_length = 1; (padding_length < size) &&
@@ -577,78 +388,319 @@ unsigned int decrypt_decrypt(decrypt_key
return size - padding_length;
}
-unsigned int decrypt_decrypt_sector(decrypt_key *key, void *data,
- unsigned long long offset)
+/**
+ * ntfs_desx_key_expand - expand a 128-bit desx key to the needed 192-bit key
+ * @src: source buffer containing 128-bit key
+ *
+ * Expands the on-disk 128-bit desx key to the needed des key, the in-, and the
+ * out-whitening keys required to perform desx {de,en}cryption.
+ */
+static void ntfs_desx_key_expand(const u8 *src, u32 *des_key,
+ u64 *out_whitening, u64 *in_whitening)
{
+ static const int salt_len = 12;
+ static const u8 *salt1 = "Dan Simon ";
+ static const u8 *salt2 = "Scott Field";
+ u32 md[4];
+ MD5_CTX ctx1, ctx2;
+
+ MD5_Init(&ctx1);
+
+ /* Hash the on-disk key. */
+ MD5_Update(&ctx1, src, 128 / 8);
+ memcpy(&ctx2, &ctx1, sizeof(ctx1));
+
+ /* Hash with the first salt and store the result. */
+ MD5_Update(&ctx1, salt1, salt_len);
+ MD5_Final((u8*)md, &ctx1);
+ des_key[0] = md[0] ^ md[1];
+ des_key[1] = md[2] ^ md[3];
+
+ /* Hash with the second salt and store the result. */
+ MD5_Update(&ctx2, salt2, salt_len);
+ MD5_Final((u8*)md, &ctx2);
+ *out_whitening = *(u64*)md;
+ *in_whitening = *(u64*)(md + 2);
+}
+
+static gcry_err_code_t ntfs_desx_setkey(void *context, const u8 *key,
+ unsigned keylen)
+{
+ ntfs_desx_ctx *ctx = context;
gcry_error_t err;
- DECRYPT_KEY *dkey = (DECRYPT_KEY*)key;
+ u8 des_key[8];
- if ((err = gcry_cipher_reset(dkey->gcry_cipher_hd)))
- fprintf(stderr, "sector_decrypt: error is %u.\n", err);
- // FIXME: Why are we not calling gcry_cipher_setiv() here instead of
- // doing it by hand after the decryption?
- // It wants iv length 8 but we give it 16 for AES256 so it does not
- // like it...
- if ((err = gcry_cipher_decrypt(dkey->gcry_cipher_hd, data, 512, NULL,
- 0)))
- fprintf(stderr, "sector_decrypt: error is %u.\n", err);
- /* Apply the IV. */
- if (dkey->alg_id == CALG_AES_256) {
- ((u64*)data)[0] ^= 0x5816657be9161312LL + offset;
- ((u64*)data)[1] ^= 0x1989adbe44918961LL + offset;
- } else {
- /* All other algos (Des, 3Des, DesX) use the same IV. */
- ((u64*)data)[0] ^= 0x169119629891ad13LL + offset;
+ if (keylen != 16) {
+ fprintf(stderr, "Key length for desx must be 16.\n");
+ return GPG_ERR_INV_KEYLEN;
}
- return 512;
+ err = gcry_cipher_open(&ctx->gcry_cipher_hd, GCRY_CIPHER_DES,
+ GCRY_CIPHER_MODE_ECB, 0);
+ if (err != GPG_ERR_NO_ERROR) {
+ fprintf(stderr, "Failed to open des cipher (error 0x%x).\n",
+ err);
+ return err;
+ }
+ ntfs_desx_key_expand(key, (u32*)des_key, &ctx->out_whitening,
+ &ctx->in_whitening);
+ err = gcry_cipher_setkey(ctx->gcry_cipher_hd, des_key, sizeof(des_key));
+ if (err != GPG_ERR_NO_ERROR) {
+ fprintf(stderr, "Failed to set des key (error 0x%x.\n", err);
+ gcry_cipher_close(ctx->gcry_cipher_hd);
+ return err;
+ }
+ /*
+ * Take a note of the ctx->gcry_cipher_hd since we need to close it at
+ * ntfs_decrypt_data_key_close() time.
+ */
+ *(gcry_cipher_hd_t*)(key + ((keylen + 7) & ~7)) = ctx->gcry_cipher_hd;
+ return GPG_ERR_NO_ERROR;
}
-decrypt_key *decrypt_make_key(decrypt_session *session __attribute__ ((unused)),
- unsigned int data_size __attribute__ ((unused)),
- unsigned char *data)
+static void ntfs_desx_decrypt(void *context, u8 *outbuf, const u8 *inbuf)
{
- DECRYPT_KEY *key;
- unsigned int key_size, gcry_algo;
+ ntfs_desx_ctx *ctx = context;
gcry_error_t err;
- key_size = *(u32*)data;
+ *(u64*)outbuf = *(const u64*)inbuf ^ ctx->out_whitening;
+ err = gcry_cipher_encrypt(ctx->gcry_cipher_hd, outbuf, 8, NULL, 0);
+ if (err != GPG_ERR_NO_ERROR)
+ fprintf(stderr, "Des decryption failed (error 0x%x).\n", err);
+ *(u64*)outbuf ^= ctx->in_whitening;
+}
- if (!(key = (DECRYPT_KEY*)malloc(sizeof(DECRYPT_KEY)))) {
- errno = -1;
- return NULL;
+static gcry_cipher_spec_t ntfs_desx_cipher = {
+ .name = "DES-X-MS128",
+ .blocksize = 8,
+ .keylen = 128,
+ .contextsize = sizeof(ntfs_desx_ctx),
+ .setkey = ntfs_desx_setkey,
+ .decrypt = ntfs_desx_decrypt,
+};
+
+//#define DO_CRYPTO_TESTS 1
+
+#ifdef DO_CRYPTO_TESTS
+/* Do not remove this test code from this file! AIA */
+static BOOL desx_key_expand_test(void)
+{
+ const u8 known_desx_on_disk_key[16] = {
+ 0xa1, 0xf9, 0xe0, 0xb2, 0x53, 0x23, 0x9e, 0x8f,
+ 0x0f, 0x91, 0x45, 0xd9, 0x8e, 0x20, 0xec, 0x30
+ };
+ const u8 known_des_key[8] = {
+ 0x27, 0xd1, 0x93, 0x09, 0xcb, 0x78, 0x93, 0x1f,
+ };
+ const u8 known_out_whitening[8] = {
+ 0xed, 0xda, 0x4c, 0x47, 0x60, 0x49, 0xdb, 0x8d,
+ };
+ const u8 known_in_whitening[8] = {
+ 0x75, 0xf6, 0xa0, 0x1a, 0xc0, 0xca, 0x28, 0x1e
+ };
+ u64 test_des_key, test_out_whitening, test_in_whitening;
+ BOOL res;
+
+ desx_key_expand(known_desx_on_disk_key, (u32*)test_des_key,
+ (u64*)test_out_whitening, (u64*)test_in_whitening);
+ res = test_des_key != *(u64*)known_des_key ||
+ test_out_whitening != *(u64*)known_out_whitening ||
+ test_in_whitening != *(u64*)known_in_whitening;
+ fprintf(stderr, "Testing whether ntfs_desx_key_expand() works: %s\n",
+ res ? "SUCCESS" : "FAILED");
+ return res;
+}
+
+static BOOL ntfs_des_test(void)
+{
+ const u8 known_des_key[8] = {
+ 0x27, 0xd1, 0x93, 0x09, 0xcb, 0x78, 0x93, 0x1f
+ };
+ const u8 known_des_encrypted_data[8] = {
+ 0xdc, 0xf7, 0x68, 0x2a, 0xaf, 0x48, 0x53, 0x0f
+ };
+ const u8 known_decrypted_data[8] = {
+ 0xd8, 0xd9, 0x15, 0x23, 0x5b, 0x88, 0x0e, 0x09
+ };
+ u8 test_decrypted_data[8];
+ int res;
+ gcry_error_t err;
+ gcry_cipher_hd_t gcry_cipher_hd;
+
+ err = gcry_cipher_open(&gcry_cipher_hd, GCRY_CIPHER_DES,
+ GCRY_CIPHER_MODE_ECB, 0);
+ if (err != GPG_ERR_NO_ERROR) {
+ fprintf(stderr, "Failed to open des cipher (error 0x%x).\n",
+ err);
+ return FALSE;
}
+ err = gcry_cipher_setkey(gcry_cipher_hd, known_des_key,
+ sizeof(known_des_key));
+ if (err != GPG_ERR_NO_ERROR) {
+ fprintf(stderr, "Failed to set des key (error 0x%x.\n", err);
+ gcry_cipher_close(gcry_cipher_hd);
+ return FALSE;
+ }
+ /*
+ * Apply DES decryption (ntfs actually uses encryption when decrypting).
+ */
+ err = gcry_cipher_encrypt(gcry_cipher_hd, test_decrypted_data,
+ sizeof(test_decrypted_data), known_des_encrypted_data,
+ sizeof(known_des_encrypted_data));
+ gcry_cipher_close(gcry_cipher_hd);
+ if (err) {
+ fprintf(stderr, "Failed to des decrypt test data (error "
+ "0x%x).\n", err);
+ return FALSE;
+ }
+ res = !memcmp(test_decrypted_data, known_decrypted_data,
+ sizeof(known_decrypted_data));
+ fprintf(stderr, "Testing whether des decryption works: %s\n",
+ res ? "SUCCESS" : "FAILED");
+ return res;
+}
+
+#else /* !defined(DO_CRYPTO_TESTS) */
+
+static inline BOOL desx_key_expand_test(void)
+{
+ return TRUE;
+}
+
+static inline BOOL des_test(void)
+{
+ return TRUE;
+}
+
+#endif /* !defined(DO_CRYPTO_TESTS) */
+
+ntfs_decrypt_data_key *ntfs_decrypt_data_key_open(unsigned char *data,
+ unsigned data_size __attribute__((unused)))
+{
+ NTFS_DECRYPT_DATA_KEY *key;
+ unsigned key_size, wanted_key_size, gcry_algo;
+ gcry_error_t err;
+
key_size = *(u32*)data;
+ key = (NTFS_DECRYPT_DATA_KEY*)malloc(((((sizeof(*key) + 7) & ~7) +
+ key_size + 7) & ~7) + sizeof(gcry_cipher_hd_t));
+ if (!key) {
+ errno = ENOMEM;
+ return NULL;
+ }
key->alg_id = *(u32*)(data + 8);
- key->key_data = data + 16;
-
+ key->key_data = (u8*)key + ((sizeof(*key) + 7) & ~7);
+ memcpy(key->key_data, data + 16, key_size);
+ key->des_gcry_cipher_hd_ptr = (gcry_cipher_hd_t*)(key->key_data +
+ ((key_size + 7) & ~7));
+ *key->des_gcry_cipher_hd_ptr = NULL;
switch (key->alg_id) {
case CALG_DESX:
- //fprintf(stderr, "DESX key of %u bytes\n", key_size);
- gcry_algo = desx_algorithm_id;
+ /* 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;
+ }
+ err = gcry_cipher_register(&ntfs_desx_cipher,
+ &ntfs_desx_algorithm_id,
+ &ntfs_desx_module);
+ if (err != GPG_ERR_NO_ERROR) {
+ fprintf(stderr, "Failed to register desx "
+ "cipher (error 0x%x).\n", err);
+ errno = EINVAL;
+ return NULL;
+ }
+ gcry_control(GCRYCTL_DISABLE_SECMEM, 0);
+ }
+ wanted_key_size = 16;
+ gcry_algo = ntfs_desx_algorithm_id;
break;
case CALG_3DES:
- //fprintf(stderr, "3DES Key of %u bytes\n", key_size);
+ wanted_key_size = 24;
gcry_algo = GCRY_CIPHER_3DES;
break;
case CALG_AES_256:
- //fprintf(stderr, "AES Key of %u bytes\n", key_size);
+ wanted_key_size = 32;
gcry_algo = GCRY_CIPHER_AES256;
break;
default:
- fprintf(stderr, "DES key of %u bytes\n", key_size);
- fprintf(stderr, "This probably will not work... "
- "It is completely untested.\n");
+ wanted_key_size = 8;
gcry_algo = GCRY_CIPHER_DES;
- break;
+ fprintf(stderr, "DES is not supported at present. Please "
+ "email lin...@li... "
+ "and say that you saw this message. We will "
+ "then implement support for DES.\n");
+ free(key);
+ errno = ENOTSUP;
+ return NULL;
}
- if ((err = gcry_cipher_open(&key->gcry_cipher_hd, gcry_algo,
- GCRY_CIPHER_MODE_CBC, 0)) != GPG_ERR_NO_ERROR) {
- fprintf(stderr, "gcry_cipher_open failed with 0x%x.\n", err);
- errno = -1;
+ if (key_size != wanted_key_size) {
+ fprintf(stderr, "%s key of %u bytes but needed size is %u "
+ "bytes, assuming corrupt key. Aborting.\n",
+ gcry_cipher_algo_name(gcry_algo), key_size,
+ wanted_key_size);
+ free(key);
+ errno = EIO;
+ return NULL;
+ }
+ err = gcry_cipher_open(&key->gcry_cipher_hd, gcry_algo,
+ GCRY_CIPHER_MODE_CBC, 0);
+ if (err != GPG_ERR_NO_ERROR) {
+ fprintf(stderr, "gcry_cipher_open() failed with error 0x%x.\n",
+ err);
+ free(key);
+ errno = EINVAL;
return 0;
}
- if ((err = gcry_cipher_setkey(key->gcry_cipher_hd, key->key_data,
- key_size)))
- fprintf(stderr, "gcry_cipher_setkey failed with 0x%x.\n", err);
- return (decrypt_key*)key;
+ err = gcry_cipher_setkey(key->gcry_cipher_hd, key->key_data, key_size);
+ if (err != GPG_ERR_NO_ERROR) {
+ fprintf(stderr, "gcry_cipher_setkey() failed with error "
+ "0x%x.\n", err);
+ gcry_cipher_close(key->gcry_cipher_hd);
+ free(key);
+ errno = EINVAL;
+ return NULL;
+ }
+ return (ntfs_decrypt_data_key*)key;
+}
+
+void ntfs_decrypt_data_key_close(ntfs_decrypt_data_key *key)
+{
+ NTFS_DECRYPT_DATA_KEY *dkey = (NTFS_DECRYPT_DATA_KEY*)key;
+ if (*dkey->des_gcry_cipher_hd_ptr)
+ gcry_cipher_close(*dkey->des_gcry_cipher_hd_ptr);
+ gcry_cipher_close(dkey->gcry_cipher_hd);
+ free(key);
+ /* FIXME: This really needs locking so it is safe from races. */
+ if (!--ntfs_desx_module_count) {
+ gcry_cipher_unregister(ntfs_desx_module);
+ ntfs_desx_module = NULL;
+ ntfs_desx_algorithm_id = -1;
+ }
+}
+
+unsigned ntfs_decrypt_data_key_decrypt_sector(ntfs_decrypt_data_key *key,
+ unsigned char *data, unsigned long long offset)
+{
+ NTFS_DECRYPT_DATA_KEY *dkey = (NTFS_DECRYPT_DATA_KEY*)key;
+ gcry_error_t err;
+
+ // FIXME: Why are we not calling gcry_cipher_setiv() here instead of
+ // doing it by hand after the decryption?
+ // It wants iv length 8 but we give it 16 for AES256 so it does not
+ // like it...
+ if ((err = gcry_cipher_decrypt(dkey->gcry_cipher_hd, data, 512, NULL,
+ 0)))
+ fprintf(stderr, "sector_decrypt: error is %u.\n", err);
+ /* Apply the IV. */
+ if (dkey->alg_id == CALG_AES_256) {
+ ((u64*)data)[0] ^= 0x5816657be9161312LL + offset;
+ ((u64*)data)[1] ^= 0x1989adbe44918961LL + offset;
+ } else {
+ /* All other algos (Des, 3Des, DesX) use the same IV. */
+ ((u64*)data)[0] ^= 0x169119629891ad13LL + offset;
+ }
+ return 512;
}
Index: decrypt.h
===================================================================
RCS file: /cvsroot/linux-ntfs/ntfsprogs/ntfsprogs/decrypt.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -p -r1.3 -r1.4
--- decrypt.h 27 Jul 2005 10:30:57 -0000 1.3
+++ decrypt.h 27 Jul 2005 15:55:43 -0000 1.4
@@ -1,8 +1,9 @@
/*
- * decrypt.h - interface for decryption rutines.
- * Part of the Linux-NTFS project.
+ * decrypt.h - Interface for decryption rutines. Part of the Linux-NTFS
+ * project.
*
* Copyright (c) 2005 Yuval Fledel
+ * Copyright (c) 2005 Anton Altaparmakov
*
* 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
@@ -23,20 +24,27 @@
#ifndef _NTFS_DECRYPT_H
#define _NTFS_DECRYPT_H
-typedef void *decrypt_session;
-typedef void *decrypt_key;
+typedef void *ntfs_decrypt_user_key_session;
+typedef void *ntfs_decrypt_user_key;
+typedef void *ntfs_decrypt_data_key;
-extern decrypt_session *decrypt_open(void);
-extern void decrypt_close(decrypt_session * session);
-extern decrypt_key *decrypt_user_key_open(decrypt_session * session,
- int thumb_size, void *thumb_print);
-extern void decrypt_user_key_close(decrypt_key * key);
-extern unsigned int decrypt_decrypt(decrypt_key * key, unsigned int data_size,
- unsigned char *data);
-extern unsigned int decrypt_decrypt_sector(decrypt_key * key, void *data,
- unsigned long long offset);
-extern decrypt_key *decrypt_make_key(decrypt_session * session,
- unsigned int data_size, unsigned char *data);
-extern int decrypt_get_block_size(decrypt_key * key);
+extern ntfs_decrypt_user_key_session *ntfs_decrypt_user_key_session_open(void);
+extern void ntfs_decrypt_user_key_session_close(
+ ntfs_decrypt_user_key_session *session);
+
+extern ntfs_decrypt_user_key *ntfs_decrypt_user_key_open(
+ ntfs_decrypt_user_key_session *session,
+ unsigned char *thumb_print, unsigned thumb_size);
+extern void ntfs_decrypt_user_key_close(ntfs_decrypt_user_key *key);
+
+extern unsigned ntfs_decrypt_user_key_decrypt(ntfs_decrypt_user_key *key,
+ unsigned char *data, unsigned data_size);
+
+extern ntfs_decrypt_data_key *ntfs_decrypt_data_key_open(unsigned char *data,
+ unsigned data_size);
+extern void ntfs_decrypt_data_key_close(ntfs_decrypt_data_key *key);
+
+extern unsigned ntfs_decrypt_data_key_decrypt_sector(ntfs_decrypt_data_key *key,
+ unsigned char *data, unsigned long long offset);
#endif /* defined _NTFS_DECRYPT_H */
|