]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Implement HMAC, PBKDF2 and AES support on Windows using CNG for
authorMichihiro NAKAJIMA <ggcueroad@gmail.com>
Mon, 13 Oct 2014 05:41:21 +0000 (14:41 +0900)
committerMichihiro NAKAJIMA <ggcueroad@gmail.com>
Mon, 13 Oct 2014 05:41:21 +0000 (14:41 +0900)
Zip encryption and decryption.

CMakeLists.txt
build/cmake/config.h.in
configure.ac
libarchive/archive_cryptor.c
libarchive/archive_cryptor_private.h
libarchive/archive_hmac.c
libarchive/archive_hmac_private.h

index cdd1f0f2016da2c4a33293048a52600b061c03bd..74c83f6f9b27a86c179323edc29ec10803a5ec0f 100644 (file)
@@ -164,6 +164,8 @@ OPTION(ENABLE_BZip2 "Enable the use of the system found BZip2 library if found"
 OPTION(ENABLE_EXPAT "Enable the use of the system found EXPAT library if found" ON)
 OPTION(ENABLE_PCREPOSIX "Enable the use of the system found PCREPOSIX library if found" ON)
 OPTION(ENABLE_LibGCC "Enable the use of the system found LibGCC library if found" ON)
+# CNG is used for encrypt/decrypt Zip archives on Windows.
+OPTION(ENABLE_CNG "Enable the use of CNG(Crypto Next Generation)" ON)
 
 OPTION(ENABLE_TAR "Enable tar building" ON)
 OPTION(ENABLE_TAR_SHARED "Enable dynamic build of tar" FALSE)
@@ -571,6 +573,11 @@ LA_CHECK_INCLUDE_FILE("utime.h" HAVE_UTIME_H)
 LA_CHECK_INCLUDE_FILE("wchar.h" HAVE_WCHAR_H)
 LA_CHECK_INCLUDE_FILE("wctype.h" HAVE_WCTYPE_H)
 LA_CHECK_INCLUDE_FILE("windows.h" HAVE_WINDOWS_H)
+IF(ENABLE_CNG)
+  LA_CHECK_INCLUDE_FILE("Bcrypt.h" HAVE_BCRYPT_H)
+ELSE(ENABLE_CNG)
+  UNSET(HAVE_BCRYPT_H CACHE)
+ENDIF(ENABLE_CNG)
 # Following files need windwos.h, so we should test it after windows.h test.
 LA_CHECK_INCLUDE_FILE("wincrypt.h" HAVE_WINCRYPT_H)
 LA_CHECK_INCLUDE_FILE("winioctl.h" HAVE_WINIOCTL_H)
index ee48de87acef1fe096a75db07f77aa776aa312b0..a1272e18f72ba22e0642153ea4ff83cdb8291e59 100644 (file)
@@ -334,6 +334,9 @@ typedef uint64_t uintmax_t;
 /* Define to 1 if you have the <attr/xattr.h> header file. */
 #cmakedefine HAVE_ATTR_XATTR_H 1
 
+/* Define to 1 if you have the <Bcrypt.h> header file. */
+#cmakedefine HAVE_BCRYPT_H 1
+
 /* Define to 1 if you have the <bsdxml.h> header file. */
 #cmakedefine HAVE_BSDXML_H 1
 
index 216ab76faca68099ef54008c41c3eecb56b8b4ee..09e505c399d1e26fc353a4b35110608241ea3108 100644 (file)
@@ -276,6 +276,7 @@ AC_CHECK_HEADERS([sys/param.h sys/poll.h sys/select.h sys/statfs.h sys/statvfs.h
 AC_CHECK_HEADERS([sys/time.h sys/utime.h sys/utsname.h sys/vfs.h])
 AC_CHECK_HEADERS([time.h unistd.h utime.h wchar.h wctype.h])
 AC_CHECK_HEADERS([windows.h])
+AC_CHECK_HEADERS([Bcrypt.h])
 # check windows.h first; the other headers require it.
 AC_CHECK_HEADERS([wincrypt.h winioctl.h],[],[],
 [[#ifdef HAVE_WINDOWS_H
index 1d819fd48d264b0e960836a5e24ad2c342e03751..94dce5ace143092b9f7213cea6361be8dbe6a1f0 100644 (file)
@@ -44,6 +44,34 @@ pbkdf2_sha1(const char *pw, size_t pw_len, const uint8_t *salt,
        return 0;
 }
 
+#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H)
+#ifdef _MSC_VER
+#pragma comment(lib, "Bcrypt.lib")
+#endif
+
+static int
+pbkdf2_sha1(const char *pw, size_t pw_len, const uint8_t *salt,
+       size_t salt_len, unsigned rounds, uint8_t *derived_key,
+       size_t derived_key_len)
+{
+       NTSTATUS status;
+       BCRYPT_ALG_HANDLE hAlg;
+
+       status = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_SHA1_ALGORITHM,
+               MS_PRIMITIVE_PROVIDER, BCRYPT_ALG_HANDLE_HMAC_FLAG);
+       if (!BCRYPT_SUCCESS(status))
+               return -1;
+
+       status = BCryptDeriveKeyPBKDF2(hAlg,
+               (PUCHAR)(uintptr_t)pw, (ULONG)pw_len,
+               (PUCHAR)(uintptr_t)salt, (ULONG)salt_len, rounds,
+               (PUCHAR)derived_key, (ULONG)derived_key_len, 0);
+
+       BCryptCloseAlgorithmProvider(hAlg, 0);
+
+       return (BCRYPT_SUCCESS(status)) ? 0: -1;
+}
+
 #elif defined(HAVE_LIBNETTLE) && defined(HAVE_NETTLE_PBKDF2_H)
 
 static int
@@ -124,6 +152,107 @@ aes_ctr_release(archive_crypto_ctx *ctx)
        return 0;
 }
 
+#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H)
+
+static int
+aes_ctr_init(archive_crypto_ctx *ctx, const uint8_t *key, size_t key_len)
+{
+       BCRYPT_ALG_HANDLE hAlg;
+       BCRYPT_KEY_HANDLE hKey;
+       DWORD keyObj_len, aes_key_len;
+       PBYTE keyObj;
+       ULONG result;
+       NTSTATUS status;
+       BCRYPT_KEY_LENGTHS_STRUCT key_lengths;
+
+       ctx->hAlg = NULL;
+       ctx->hKey = NULL;
+       ctx->keyObj = NULL;
+       switch (key_len) {
+       case 16: aes_key_len = 128; break;
+       case 24: aes_key_len = 192; break;
+       case 32: aes_key_len = 256; break;
+       default: return -1;
+       }
+       status = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_AES_ALGORITHM,
+               MS_PRIMITIVE_PROVIDER, 0);
+       if (!BCRYPT_SUCCESS(status))
+               return -1;
+       status = BCryptGetProperty(hAlg, BCRYPT_KEY_LENGTHS, (PUCHAR)&key_lengths,
+               sizeof(key_lengths), &result, 0);
+       if (!BCRYPT_SUCCESS(status)) {
+               BCryptCloseAlgorithmProvider(hAlg, 0);
+               return -1;
+       }
+       if (key_lengths.dwMinLength > aes_key_len
+               || key_lengths.dwMaxLength < aes_key_len) {
+               BCryptCloseAlgorithmProvider(hAlg, 0);
+               return -1;
+       }
+       status = BCryptGetProperty(hAlg, BCRYPT_OBJECT_LENGTH, (PUCHAR)&keyObj_len,
+               sizeof(keyObj_len), &result, 0);
+       if (!BCRYPT_SUCCESS(status)) {
+               BCryptCloseAlgorithmProvider(hAlg, 0);
+               return -1;
+       }
+       keyObj = (PBYTE)HeapAlloc(GetProcessHeap(), 0, keyObj_len);
+       if (keyObj == NULL) {
+               BCryptCloseAlgorithmProvider(hAlg, 0);
+               return -1;
+       }
+       status = BCryptSetProperty(hAlg, BCRYPT_CHAINING_MODE,
+               (PUCHAR)BCRYPT_CHAIN_MODE_ECB, sizeof(BCRYPT_CHAIN_MODE_ECB), 0);
+       if (!BCRYPT_SUCCESS(status)) {
+               BCryptCloseAlgorithmProvider(hAlg, 0);
+               HeapFree(GetProcessHeap(), 0, keyObj);
+               return -1;
+       }
+       status = BCryptGenerateSymmetricKey(hAlg, &hKey,
+               keyObj, keyObj_len,
+               (PUCHAR)(uintptr_t)key, (ULONG)key_len, 0);
+       if (!BCRYPT_SUCCESS(status)) {
+               BCryptCloseAlgorithmProvider(hAlg, 0);
+               HeapFree(GetProcessHeap(), 0, keyObj);
+               return -1;
+       }
+
+       ctx->hAlg = hAlg;
+       ctx->hKey = hKey;
+       ctx->keyObj = keyObj;
+       ctx->keyObj_len = keyObj_len;
+       ctx->encr_pos = AES_BLOCK_SIZE;
+
+       return 0;
+}
+
+static int
+aes_ctr_encrypt_counter(archive_crypto_ctx *ctx)
+{
+       NTSTATUS status;
+       ULONG result;
+
+       status = BCryptEncrypt(ctx->hKey, (PUCHAR)ctx->nonce, AES_BLOCK_SIZE,
+               NULL, NULL, 0, (PUCHAR)ctx->encr_buf, AES_BLOCK_SIZE,
+               &result, 0);
+       return BCRYPT_SUCCESS(status) ? 0 : -1;
+}
+
+static int
+aes_ctr_release(archive_crypto_ctx *ctx)
+{
+
+       if (ctx->hAlg != NULL) {
+               BCryptCloseAlgorithmProvider(ctx->hAlg, 0);
+               ctx->hAlg = NULL;
+               BCryptDestroyKey(ctx->hKey);
+               ctx->hKey = NULL;
+               HeapFree(GetProcessHeap(), 0, ctx->keyObj);
+               ctx->keyObj = NULL;
+       }
+       memset(ctx, 0, sizeof(*ctx));
+       return 0;
+}
+
 #elif defined(HAVE_LIBNETTLE)
 
 static int
index 35b3385e0a11a13306aaa2973f12d3a88d64c5d4..88c208db64de1c67bd23c2ee5e44a47bb6341119 100644 (file)
@@ -45,14 +45,16 @@ typedef struct {
        unsigned        encr_pos;
 } archive_crypto_ctx;
 
-#elif defined(_WIN32) && !defined(__CYGWIN__)
+#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H)
+#include <Bcrypt.h>
 
 #define AES_MAX_KEY_SIZE 32
 #define AES_BLOCK_SIZE 16
 typedef struct {
-       int     ctx;
-       uint8_t         key[AES_MAX_KEY_SIZE];
-       unsigned        key_len;
+       BCRYPT_ALG_HANDLE hAlg;
+       BCRYPT_KEY_HANDLE hKey;
+       PBYTE           keyObj;
+       DWORD           keyObj_len;
        uint8_t         nonce[AES_BLOCK_SIZE];
        uint8_t         encr_buf[AES_BLOCK_SIZE];
        unsigned        encr_pos;
@@ -88,6 +90,10 @@ typedef struct {
        unsigned        encr_pos;
 } archive_crypto_ctx;
 
+#else
+
+typedef int archive_crypto_ctx;
+
 #endif
 
 /* defines */
index 9e6834ec9edbcb781e44970edb9f67dcaf421c09..898853bd1e76c666980449a405e3a778e3de8d66 100644 (file)
@@ -60,6 +60,75 @@ __hmac_sha1_cleanup(archive_hmac_sha1_ctx *ctx)
        memset(ctx, 0, sizeof(*ctx));
 }
 
+#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H)
+
+static int
+__hmac_sha1_init(archive_hmac_sha1_ctx *ctx, const uint8_t *key, size_t key_len)
+{
+       BCRYPT_ALG_HANDLE hAlg;
+       BCRYPT_HASH_HANDLE hHash;
+       DWORD hash_len;
+       PBYTE hash;
+       ULONG result;
+       NTSTATUS status;
+
+       ctx->hAlg = NULL;
+       status = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_SHA1_ALGORITHM,
+               MS_PRIMITIVE_PROVIDER, BCRYPT_ALG_HANDLE_HMAC_FLAG);
+       if (!BCRYPT_SUCCESS(status))
+               return -1;
+       status = BCryptGetProperty(hAlg, BCRYPT_HASH_LENGTH, (PUCHAR)&hash_len,
+               sizeof(hash_len), &result, 0);
+       if (!BCRYPT_SUCCESS(status)) {
+               BCryptCloseAlgorithmProvider(hAlg, 0);
+               return -1;
+       }
+       hash = (PBYTE)HeapAlloc(GetProcessHeap(), 0, hash_len);
+       if (hash == NULL) {
+               BCryptCloseAlgorithmProvider(hAlg, 0);
+               return -1;
+       }
+       status = BCryptCreateHash(hAlg, &hHash, NULL, 0,
+               (PUCHAR)key, (ULONG)key_len, BCRYPT_HASH_REUSABLE_FLAG);
+       if (!BCRYPT_SUCCESS(status)) {
+               BCryptCloseAlgorithmProvider(hAlg, 0);
+               HeapFree(GetProcessHeap(), 0, hash);
+               return -1;
+       }
+
+       ctx->hAlg = hAlg;
+       ctx->hHash = hHash;
+       ctx->hash_len = hash_len;
+       ctx->hash = hash;
+
+       return 0;
+}
+
+static void
+__hmac_sha1_update(archive_hmac_sha1_ctx *ctx, const uint8_t *data,
+       size_t data_len)
+{
+       BCryptHashData(ctx->hHash, (PUCHAR)(uintptr_t)data, (ULONG)data_len, 0);
+}
+
+static void
+__hmac_sha1_final(archive_hmac_sha1_ctx *ctx, uint8_t *out, size_t *out_len)
+{
+       BCryptFinishHash(ctx->hHash, ctx->hash, ctx->hash_len, 0);
+       if (ctx->hash_len == *out_len)
+               memcpy(out, ctx->hash, *out_len);
+}
+
+static void
+__hmac_sha1_cleanup(archive_hmac_sha1_ctx *ctx)
+{
+       if (ctx->hAlg != NULL) {
+               BCryptCloseAlgorithmProvider(ctx->hAlg, 0);
+               HeapFree(GetProcessHeap(), 0, ctx->hash);
+               ctx->hAlg = NULL;
+       }
+}
+
 #elif defined(HAVE_LIBNETTLE)
 
 static int
index 223e7ca6629f66e0d126e00382695dabfc0bba1c..e5be3dc7a541a5ae69259246b314bcfa898e56bd 100644 (file)
 typedef        CCHmacContext archive_hmac_sha1_ctx;
 
 #elif defined(_WIN32) && !defined(__CYGWIN__)
+#include <Bcrypt.h>
 
-typedef int archive_hmac_sha1_ctx;
+typedef struct {
+       BCRYPT_ALG_HANDLE       hAlg;
+       BCRYPT_HASH_HANDLE      hHash;
+       DWORD                           hash_len;
+       PBYTE                           hash;
+
+} archive_hmac_sha1_ctx;
 
 #elif defined(HAVE_LIBNETTLE)
 #include <nettle/hmac.h>
@@ -49,6 +56,10 @@ typedef      struct hmac_sha1_ctx archive_hmac_sha1_ctx;
 
 typedef        HMAC_CTX archive_hmac_sha1_ctx;
 
+#else
+
+typedef int archive_hmac_sha1_ctx;
+
 #endif