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)
{
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);
* 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;
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.
"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);
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;
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);
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();
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);
+}
+
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,
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,