diff options
Diffstat (limited to 'Utilities/cmlibarchive/libarchive/archive_cryptor.c')
-rw-r--r-- | Utilities/cmlibarchive/libarchive/archive_cryptor.c | 519 |
1 files changed, 519 insertions, 0 deletions
diff --git a/Utilities/cmlibarchive/libarchive/archive_cryptor.c b/Utilities/cmlibarchive/libarchive/archive_cryptor.c new file mode 100644 index 0000000..8ab2b09 --- /dev/null +++ b/Utilities/cmlibarchive/libarchive/archive_cryptor.c @@ -0,0 +1,519 @@ +/*- +* Copyright (c) 2014 Michihiro NAKAJIMA +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "archive_platform.h" + +#ifdef HAVE_STRING_H +#include <string.h> +#endif +#include "archive.h" +#include "archive_cryptor_private.h" + +/* + * On systems that do not support any recognized crypto libraries, + * this file will normally define no usable symbols. + * + * But some compilers and linkers choke on empty object files, so + * define a public symbol that will always exist. This could + * be removed someday if this file gains another always-present + * symbol definition. + */ +int __libarchive_cryptor_build_hack(void) { + return 0; +} + +#ifdef ARCHIVE_CRYPTOR_USE_Apple_CommonCrypto + +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) +{ + CCKeyDerivationPBKDF(kCCPBKDF2, (const char *)pw, + pw_len, salt, salt_len, kCCPRFHmacAlgSHA1, rounds, + derived_key, derived_key_len); + 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_LIBMBEDCRYPTO) && defined(HAVE_MBEDTLS_PKCS5_H) + +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) +{ + mbedtls_md_context_t ctx; + const mbedtls_md_info_t *info; + int ret; + + mbedtls_md_init(&ctx); + info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1); + if (info == NULL) { + mbedtls_md_free(&ctx); + return (-1); + } + ret = mbedtls_md_setup(&ctx, info, 1); + if (ret != 0) { + mbedtls_md_free(&ctx); + return (-1); + } + ret = mbedtls_pkcs5_pbkdf2_hmac(&ctx, (const unsigned char *)pw, + pw_len, salt, salt_len, rounds, derived_key_len, derived_key); + + mbedtls_md_free(&ctx); + return (ret); +} + +#elif defined(HAVE_LIBNETTLE) && defined(HAVE_NETTLE_PBKDF2_H) + +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) { + pbkdf2_hmac_sha1((unsigned)pw_len, (const uint8_t *)pw, rounds, + salt_len, salt, derived_key_len, derived_key); + return 0; +} + +#elif defined(HAVE_LIBCRYPTO) && defined(HAVE_PKCS5_PBKDF2_HMAC_SHA1) + +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) { + + PKCS5_PBKDF2_HMAC_SHA1(pw, pw_len, salt, salt_len, rounds, + derived_key_len, derived_key); + return 0; +} + +#else + +/* Stub */ +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) { + (void)pw; /* UNUSED */ + (void)pw_len; /* UNUSED */ + (void)salt; /* UNUSED */ + (void)salt_len; /* UNUSED */ + (void)rounds; /* UNUSED */ + (void)derived_key; /* UNUSED */ + (void)derived_key_len; /* UNUSED */ + return -1; /* UNSUPPORTED */ +} + +#endif + +#ifdef ARCHIVE_CRYPTOR_USE_Apple_CommonCrypto +# if MAC_OS_X_VERSION_MAX_ALLOWED < 1090 +# define kCCAlgorithmAES kCCAlgorithmAES128 +# endif + +static int +aes_ctr_init(archive_crypto_ctx *ctx, const uint8_t *key, size_t key_len) +{ + CCCryptorStatus r; + + ctx->key_len = key_len; + memcpy(ctx->key, key, key_len); + memset(ctx->nonce, 0, sizeof(ctx->nonce)); + ctx->encr_pos = AES_BLOCK_SIZE; + r = CCCryptorCreateWithMode(kCCEncrypt, kCCModeECB, kCCAlgorithmAES, + ccNoPadding, NULL, key, key_len, NULL, 0, 0, 0, &ctx->ctx); + return (r == kCCSuccess)? 0: -1; +} + +static int +aes_ctr_encrypt_counter(archive_crypto_ctx *ctx) +{ + CCCryptorRef ref = ctx->ctx; + CCCryptorStatus r; + + r = CCCryptorReset(ref, NULL); + if (r != kCCSuccess && r != kCCUnimplemented) + return -1; + r = CCCryptorUpdate(ref, ctx->nonce, AES_BLOCK_SIZE, ctx->encr_buf, + AES_BLOCK_SIZE, NULL); + return (r == kCCSuccess)? 0: -1; +} + +static int +aes_ctr_release(archive_crypto_ctx *ctx) +{ + memset(ctx->key, 0, ctx->key_len); + memset(ctx->nonce, 0, sizeof(ctx->nonce)); + 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_LIBMBEDCRYPTO) && defined(HAVE_MBEDTLS_AES_H) + +static int +aes_ctr_init(archive_crypto_ctx *ctx, const uint8_t *key, size_t key_len) +{ + mbedtls_aes_init(&ctx->ctx); + ctx->key_len = key_len; + memcpy(ctx->key, key, key_len); + memset(ctx->nonce, 0, sizeof(ctx->nonce)); + ctx->encr_pos = AES_BLOCK_SIZE; + return 0; +} + +static int +aes_ctr_encrypt_counter(archive_crypto_ctx *ctx) +{ + if (mbedtls_aes_setkey_enc(&ctx->ctx, ctx->key, + ctx->key_len * 8) != 0) + return (-1); + if (mbedtls_aes_crypt_ecb(&ctx->ctx, MBEDTLS_AES_ENCRYPT, ctx->nonce, + ctx->encr_buf) != 0) + return (-1); + return 0; +} + +static int +aes_ctr_release(archive_crypto_ctx *ctx) +{ + mbedtls_aes_free(&ctx->ctx); + memset(ctx, 0, sizeof(*ctx)); + return 0; +} + +#elif defined(HAVE_LIBNETTLE) && defined(HAVE_NETTLE_AES_H) + +static int +aes_ctr_init(archive_crypto_ctx *ctx, const uint8_t *key, size_t key_len) +{ + ctx->key_len = key_len; + memcpy(ctx->key, key, key_len); + memset(ctx->nonce, 0, sizeof(ctx->nonce)); + ctx->encr_pos = AES_BLOCK_SIZE; + memset(&ctx->ctx, 0, sizeof(ctx->ctx)); + return 0; +} + +static int +aes_ctr_encrypt_counter(archive_crypto_ctx *ctx) +{ + aes_set_encrypt_key(&ctx->ctx, ctx->key_len, ctx->key); + aes_encrypt(&ctx->ctx, AES_BLOCK_SIZE, ctx->encr_buf, ctx->nonce); + return 0; +} + +static int +aes_ctr_release(archive_crypto_ctx *ctx) +{ + memset(ctx, 0, sizeof(*ctx)); + return 0; +} + +#elif defined(HAVE_LIBCRYPTO) + +static int +aes_ctr_init(archive_crypto_ctx *ctx, const uint8_t *key, size_t key_len) +{ + if ((ctx->ctx = EVP_CIPHER_CTX_new()) == NULL) + return -1; + + switch (key_len) { + case 16: ctx->type = EVP_aes_128_ecb(); break; + case 24: ctx->type = EVP_aes_192_ecb(); break; + case 32: ctx->type = EVP_aes_256_ecb(); break; + default: ctx->type = NULL; return -1; + } + + ctx->key_len = key_len; + memcpy(ctx->key, key, key_len); + memset(ctx->nonce, 0, sizeof(ctx->nonce)); + ctx->encr_pos = AES_BLOCK_SIZE; +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) + if (!EVP_CIPHER_CTX_reset(ctx->ctx)) { + EVP_CIPHER_CTX_free(ctx->ctx); + ctx->ctx = NULL; + } +#else + EVP_CIPHER_CTX_init(ctx->ctx); +#endif + return 0; +} + +static int +aes_ctr_encrypt_counter(archive_crypto_ctx *ctx) +{ + int outl = 0; + int r; + + r = EVP_EncryptInit_ex(ctx->ctx, ctx->type, NULL, ctx->key, NULL); + if (r == 0) + return -1; + r = EVP_EncryptUpdate(ctx->ctx, ctx->encr_buf, &outl, ctx->nonce, + AES_BLOCK_SIZE); + if (r == 0 || outl != AES_BLOCK_SIZE) + return -1; + return 0; +} + +static int +aes_ctr_release(archive_crypto_ctx *ctx) +{ + EVP_CIPHER_CTX_free(ctx->ctx); + memset(ctx->key, 0, ctx->key_len); + memset(ctx->nonce, 0, sizeof(ctx->nonce)); + return 0; +} + +#else + +#define ARCHIVE_CRYPTOR_STUB +/* Stub */ +static int +aes_ctr_init(archive_crypto_ctx *ctx, const uint8_t *key, size_t key_len) +{ + (void)ctx; /* UNUSED */ + (void)key; /* UNUSED */ + (void)key_len; /* UNUSED */ + return -1; +} + +static int +aes_ctr_encrypt_counter(archive_crypto_ctx *ctx) +{ + (void)ctx; /* UNUSED */ + return -1; +} + +static int +aes_ctr_release(archive_crypto_ctx *ctx) +{ + (void)ctx; /* UNUSED */ + return 0; +} + +#endif + +#ifdef ARCHIVE_CRYPTOR_STUB +static int +aes_ctr_update(archive_crypto_ctx *ctx, const uint8_t * const in, + size_t in_len, uint8_t * const out, size_t *out_len) +{ + (void)ctx; /* UNUSED */ + (void)in; /* UNUSED */ + (void)in_len; /* UNUSED */ + (void)out; /* UNUSED */ + (void)out_len; /* UNUSED */ + aes_ctr_encrypt_counter(ctx); /* UNUSED */ /* Fix unused function warning */ + return -1; +} + +#else +static void +aes_ctr_increase_counter(archive_crypto_ctx *ctx) +{ + uint8_t *const nonce = ctx->nonce; + int j; + + for (j = 0; j < 8; j++) { + if (++nonce[j]) + break; + } +} + +static int +aes_ctr_update(archive_crypto_ctx *ctx, const uint8_t * const in, + size_t in_len, uint8_t * const out, size_t *out_len) +{ + uint8_t *const ebuf = ctx->encr_buf; + unsigned pos = ctx->encr_pos; + unsigned max = (unsigned)((in_len < *out_len)? in_len: *out_len); + unsigned i; + + for (i = 0; i < max; ) { + if (pos == AES_BLOCK_SIZE) { + aes_ctr_increase_counter(ctx); + if (aes_ctr_encrypt_counter(ctx) != 0) + return -1; + while (max -i >= AES_BLOCK_SIZE) { + for (pos = 0; pos < AES_BLOCK_SIZE; pos++) + out[i+pos] = in[i+pos] ^ ebuf[pos]; + i += AES_BLOCK_SIZE; + aes_ctr_increase_counter(ctx); + if (aes_ctr_encrypt_counter(ctx) != 0) + return -1; + } + pos = 0; + if (i >= max) + break; + } + out[i] = in[i] ^ ebuf[pos++]; + i++; + } + ctx->encr_pos = pos; + *out_len = i; + + return 0; +} +#endif /* ARCHIVE_CRYPTOR_STUB */ + + +const struct archive_cryptor __archive_cryptor = +{ + &pbkdf2_sha1, + &aes_ctr_init, + &aes_ctr_update, + &aes_ctr_release, + &aes_ctr_init, + &aes_ctr_update, + &aes_ctr_release, +}; |