123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450 |
- /*-
- * 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_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)
- 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_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;
- EVP_CIPHER_CTX_init(ctx->ctx);
- 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,
- };
|