]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Property handle __archive_read_next_passphrase function.
authorMichihiro NAKAJIMA <ggcueroad@gmail.com>
Mon, 15 Sep 2014 09:10:58 +0000 (18:10 +0900)
committerMichihiro NAKAJIMA <ggcueroad@gmail.com>
Mon, 15 Sep 2014 09:10:58 +0000 (18:10 +0900)
Return the same passphrase while the passphraes is passed
even if it was passed by a callback function.

libarchive/archive_read_add_passphrase.c
libarchive/archive_read_support_format_zip.c
libarchive/test/test_archive_read_add_passphrase.c
libarchive/test/test_read_format_zip_traditional_encryption_data.c
libarchive/test/test_read_format_zip_winzip_aes.c

index da8ce506136d0f0418e520f4bd6131caa914a30b..f67f1ebc6e272081d7bf685d7256cb4aa42e82da 100644 (file)
@@ -51,6 +51,35 @@ remove_passphrases_from_head(struct archive_read *a)
        return (p);
 }
 
+static void
+insert_passphrase_to_head(struct archive_read *a,
+    struct archive_read_passphrase *p)
+{
+       p->next = a->passphrases.first;
+       a->passphrases.first = p;
+}
+
+static struct archive_read_passphrase *
+new_read_passphrase(struct archive_read *a, const char *passphrase)
+{
+       struct archive_read_passphrase *p;
+
+       p = malloc(sizeof(*p));
+       if (p == NULL) {
+               archive_set_error(&a->archive, ENOMEM,
+                   "Can't allocate memory");
+               return (NULL);
+       }
+       p->passphrase = strdup(passphrase);
+       if (p->passphrase == NULL) {
+               free(p);
+               archive_set_error(&a->archive, ENOMEM,
+                   "Can't allocate memory");
+               return (NULL);
+       }
+       return (p);
+}
+
 int
 archive_read_add_passphrase(struct archive *_a, const char *passphrase)
 {
@@ -66,19 +95,9 @@ archive_read_add_passphrase(struct archive *_a, const char *passphrase)
                return (ARCHIVE_FAILED);
        }
 
-       p = malloc(sizeof(*p));
-       if (p == NULL) {
-               archive_set_error(&a->archive, ENOMEM,
-                   "Can't allocate memory");
+       p = new_read_passphrase(a, passphrase);
+       if (p == NULL)
                return (ARCHIVE_FATAL);
-       }
-       p->passphrase = strdup(passphrase);
-       if (p->passphrase == NULL) {
-               free(p);
-               archive_set_error(&a->archive, ENOMEM,
-                   "Can't allocate memory");
-               return (ARCHIVE_FATAL);
-       }
        add_passphrase_to_tail(a, p);
 
        return (ARCHIVE_OK);
@@ -153,6 +172,13 @@ __archive_read_next_passphrase(struct archive_read *a)
                 * have it. */
                passphrase = a->passphrases.callback(&a->archive,
                    a->passphrases.client_data);
+               if (passphrase != NULL) {
+                       p = new_read_passphrase(a, passphrase);
+                       if (p == NULL)
+                               return (NULL);
+                       insert_passphrase_to_head(a, p);
+                       a->passphrases.candiate = 1;
+               }
        } else
                passphrase = NULL;
 
index a243c2116a2e074387d82db5186a36ae987651cc..7b28bff54e3b30d15824ba078fb2c16e91c3a289 100644 (file)
@@ -1573,21 +1573,13 @@ static int
 init_traditional_PKWARE_decryption(struct archive_read *a)
 {
        struct zip *zip = (struct zip *)(a->format->data);
-       const char *passphrase;
        const void *p;
-       uint8_t crcchk;
+       int retry;
        int r;
 
        if (zip->tctx_valid)
                return (ARCHIVE_OK);
 
-       passphrase = __archive_read_next_passphrase(a);
-       if (passphrase == NULL) {
-               archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-                   "Passowrd required for this entry");
-               return (ARCHIVE_FAILED);
-       }
-
        /*
           Read the 12 bytes encryption header stored at
           the start of the data area.
@@ -1599,15 +1591,33 @@ init_traditional_PKWARE_decryption(struct archive_read *a)
                    "Truncated ZIP file data");
                return (ARCHIVE_FATAL);
        }
-       /*
-        * Initialize ctx for Traditional PKWARE Decyption.
-        */
-       r = trad_enc_init(&zip->tctx, passphrase, strlen(passphrase),
-               p, ENC_HEADER_SIZE, &crcchk);
-       if (crcchk != zip->entry->decdat || r != 0) {
-               archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-                   "Incorrect passowrd");
-               return (ARCHIVE_FAILED);
+
+       for (retry = 0;; retry++) {
+               const char *passphrase;
+               uint8_t crcchk;
+
+               passphrase = __archive_read_next_passphrase(a);
+               if (passphrase == NULL) {
+                       archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+                           (retry > 0)?
+                               "Incorrect passphrase":
+                               "Passphrase required for this entry");
+                       return (ARCHIVE_FAILED);
+               }
+
+               /*
+                * Initialize ctx for Traditional PKWARE Decyption.
+                */
+               r = trad_enc_init(&zip->tctx, passphrase, strlen(passphrase),
+                       p, ENC_HEADER_SIZE, &crcchk);
+               if (r == 0 && crcchk == zip->entry->decdat)
+                       break;/* The passphrase is OK. */
+               if (retry > 10000) {
+                       /* Avoid infinity loop. */
+                       archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+                           "Too many incorrect passphrases");
+                       return (ARCHIVE_FAILED);
+               }
        }
 
        __archive_read_consume(a, ENC_HEADER_SIZE);
@@ -1625,23 +1635,16 @@ static int
 init_WinZip_AES_decryption(struct archive_read *a)
 {
        struct zip *zip = (struct zip *)(a->format->data);
-       const char *passphrase;
        const void *p;
        const uint8_t *pv;
        size_t key_len, salt_len;
        uint8_t derived_key[MAX_DERIVED_KEY_BUF_SIZE];
+       int retry;
        int r;
 
        if (zip->cctx_valid || zip->hctx_valid)
                return (ARCHIVE_OK);
 
-       passphrase = __archive_read_next_passphrase(a);
-       if (passphrase == NULL) {
-               archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-                   "Passowrd required for this entry");
-               return (ARCHIVE_FAILED);
-       }
-
        switch (zip->entry->aes_extra.strength) {
        case 1: salt_len = 8;  key_len = 16; break;
        case 2: salt_len = 12; key_len = 24; break;
@@ -1652,17 +1655,38 @@ init_WinZip_AES_decryption(struct archive_read *a)
        if (p == NULL)
                goto truncated;
 
-       memset(derived_key, 0, sizeof(derived_key));
-       archive_pbkdf2_sha1(passphrase, strlen(passphrase),
-           p, salt_len, 1000, derived_key, key_len * 2 + 2);
+       for (retry = 0;; retry++) {
+               const char *passphrase;
 
-       /* Check password verification value. */
-       pv = ((const uint8_t *)p) + salt_len;
-       if (derived_key[key_len * 2] != pv[0] ||
-           derived_key[key_len * 2 + 1] != pv[1]) {
-               archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-                   "Invalid passowrd");
-               return (ARCHIVE_FAILED);
+               passphrase = __archive_read_next_passphrase(a);
+               if (passphrase == NULL) {
+                       archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+                           (retry > 0)?
+                               "Incorrect passphrase":
+                               "Passphrase required for this entry");
+                       return (ARCHIVE_FAILED);
+               }
+               memset(derived_key, 0, sizeof(derived_key));
+               r = archive_pbkdf2_sha1(passphrase, strlen(passphrase),
+                   p, salt_len, 1000, derived_key, key_len * 2 + 2);
+               if (r != 0) {
+                       archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+                           "Decryption is unsupported due to lack of "
+                           "crypto library");
+                       return (ARCHIVE_FAILED);
+               }
+
+               /* Check password verification value. */
+               pv = ((const uint8_t *)p) + salt_len;
+               if (derived_key[key_len * 2] == pv[0] &&
+                   derived_key[key_len * 2 + 1] == pv[1])
+                       break;/* The passphrase is OK. */
+               if (retry > 10000) {
+                       /* Avoid infinity loop. */
+                       archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+                           "Too many incorrect passphrases");
+                       return (ARCHIVE_FAILED);
+               }
        }
 
        r = archive_decrypto_aes_ctr_init(&zip->cctx, derived_key, key_len);
index 6c2a4c011704787ec934a6be38891ad35f9c7e08..2811ab2f8d8ae3e1e206f91ef1db17c1843e3b2c 100644 (file)
@@ -177,6 +177,28 @@ DEFINE_TEST(test_archive_read_add_passphrase_set_callback2)
        archive_read_free(a);
 }
 
+DEFINE_TEST(test_archive_read_add_passphrase_set_callback3)
+{
+       struct archive* a = archive_read_new();
+       struct archive_read *ar = (struct archive_read *)a;
+       int client_data = 0;
+
+       assertEqualInt(ARCHIVE_OK,
+           archive_read_set_passphrase_callback(a, &client_data, callback2));
+
+       __archive_read_reset_passphrase(ar);
+       /* Fist call, we should get "passCallBack" as a passphrase. */
+       assertEqualString("passCallBack", __archive_read_next_passphrase(ar));
+       __archive_read_reset_passphrase(ar);
+       /* After reset passphrase, we should get "passCallBack"passphrase. */
+       assertEqualString("passCallBack", __archive_read_next_passphrase(ar));
+       /* Second call, we should get NULL which means all the pssphrases
+        * are passed already. */
+       assertEqualString(NULL, __archive_read_next_passphrase(ar));
+
+       archive_read_free(a);
+}
+
 DEFINE_TEST(test_archive_read_add_passphrase_multiple_with_callback)
 {
        struct archive* a = archive_read_new();
@@ -202,3 +224,36 @@ DEFINE_TEST(test_archive_read_add_passphrase_multiple_with_callback)
        archive_read_free(a);
 }
 
+DEFINE_TEST(test_archive_read_add_passphrase_multiple_with_callback2)
+{
+       struct archive* a = archive_read_new();
+       struct archive_read *ar = (struct archive_read *)a;
+       int client_data = 0;
+
+       assertEqualInt(ARCHIVE_OK, archive_read_add_passphrase(a, "pass1"));
+       assertEqualInt(ARCHIVE_OK, archive_read_add_passphrase(a, "pass2"));
+       assertEqualInt(ARCHIVE_OK,
+           archive_read_set_passphrase_callback(a, &client_data, callback2));
+
+       __archive_read_reset_passphrase(ar);
+       /* Fist call, we should get "pass1" as a passphrase. */
+       assertEqualString("pass1", __archive_read_next_passphrase(ar));
+       /* Second call, we should get "pass2" as a passphrase. */
+       assertEqualString("pass2", __archive_read_next_passphrase(ar));
+       /* Third call, we should get "passCallBack" as a passphrase. */
+       assertEqualString("passCallBack", __archive_read_next_passphrase(ar));
+
+       __archive_read_reset_passphrase(ar);
+       /* After reset passphrase, we should get "passCallBack" passphrase. */
+       assertEqualString("passCallBack", __archive_read_next_passphrase(ar));
+       /* Second call, we should get "pass1" as a passphrase. */
+       assertEqualString("pass1", __archive_read_next_passphrase(ar));
+       /* Third call, we should get "passCallBack" as a passphrase. */
+       assertEqualString("pass2", __archive_read_next_passphrase(ar));
+       /* Fourth call, we should get NULL which means all the pssphrases
+        * are passed already. */
+       assertEqualString(NULL, __archive_read_next_passphrase(ar));
+
+       archive_read_free(a);
+}
+
index 3b9fc11024b5144a5cfe4c6e382d47615cac39de..531dcaaacef1c824b564750a4b26747d01941ba2 100644 (file)
@@ -103,6 +103,11 @@ DEFINE_TEST(test_read_format_zip_traditional_encryption_data)
        assert((a = archive_read_new()) != NULL);
        assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
        assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+       /* Pass three passphrases to decrypt a file content. */
+       assertEqualIntA(a, ARCHIVE_OK,
+               archive_read_add_passphrase(a, "invalid_pass"));
+       assertEqualIntA(a, ARCHIVE_OK,
+               archive_read_add_passphrase(a, "invalid_phrase"));
        assertEqualIntA(a, ARCHIVE_OK,
                archive_read_add_passphrase(a, "12345678"));
        assertEqualIntA(a, ARCHIVE_OK, 
index 1cd05c25a7452e1b23e819dfbe502c6fd9064869..3f856131028a89a080b6b127a4158aa1dfae6a61 100644 (file)
@@ -89,6 +89,11 @@ test_winzip_aes(const char *refname)
        assert((a = archive_read_new()) != NULL);
        assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
        assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+       /* Pass three passphrases to decrypt a file content. */
+       assertEqualIntA(a, ARCHIVE_OK,
+               archive_read_add_passphrase(a, "invalid_pass"));
+       assertEqualIntA(a, ARCHIVE_OK,
+               archive_read_add_passphrase(a, "invalid_phrase"));
        assertEqualIntA(a, ARCHIVE_OK,
                archive_read_add_passphrase(a, "password"));
        assertEqualIntA(a, ARCHIVE_OK,