Coverage Report

Created: 2026-03-15 06:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dovecot/src/lib-auth/password-scheme-pbkdf2.c
Line
Count
Source
1
/* Copyright (c) 2015-2018 Dovecot authors, see the included COPYING file */
2
3
#include "lib.h"
4
#include "buffer.h"
5
#include "str.h"
6
#include "password-scheme.h"
7
#include "hex-binary.h"
8
#include "hash-method.h"
9
#include "pkcs5.h"
10
11
0
#define PBKDF2_KEY_SIZE_SHA1 20
12
13
0
#define PBKDF2_GENERATE_SALT_LEN      16
14
0
#define PBKDF2_ROUNDS_DEFAULT          5000
15
16
static void
17
pbkdf_run(const char *plaintext, const char *salt,
18
    unsigned int rounds, unsigned char key_r[PBKDF2_KEY_SIZE_SHA1])
19
0
{
20
0
  memset(key_r, 0, PBKDF2_KEY_SIZE_SHA1);
21
0
  buffer_t buf;
22
0
  buffer_create_from_data(&buf, key_r, PBKDF2_KEY_SIZE_SHA1);
23
24
0
  pkcs5_pbkdf(PKCS5_PBKDF2, hash_method_lookup("sha1"),
25
0
    (const unsigned char *)plaintext, strlen(plaintext),
26
0
    (const unsigned char *)salt, strlen(salt),
27
0
    rounds, PBKDF2_KEY_SIZE_SHA1, &buf);
28
0
}
29
30
void pbkdf2_generate(const char *plaintext, const struct password_generate_params *params ATTR_UNUSED,
31
    const unsigned char **raw_password_r, size_t *size_r)
32
0
{
33
0
  unsigned char key[PBKDF2_KEY_SIZE_SHA1];
34
0
  const char *salt;
35
0
  string_t *str = t_str_new(64);
36
0
  unsigned int rounds = params->rounds;
37
38
0
  if (rounds == 0)
39
0
    rounds = PBKDF2_ROUNDS_DEFAULT;
40
0
  salt = password_generate_salt(PBKDF2_GENERATE_SALT_LEN);
41
0
  pbkdf_run(plaintext, salt, rounds, key);
42
43
0
  str_printfa(str, "$1$%s$%u$", salt, rounds);
44
0
  binary_to_hex_append(str, key, sizeof(key));
45
46
0
  *raw_password_r = str_data(str);
47
0
  *size_r = str_len(str);
48
0
}
49
50
int pbkdf2_verify(const char *plaintext, const struct password_generate_params *params ATTR_UNUSED,
51
        const unsigned char *raw_password, size_t size,
52
        const char **error_r)
53
0
{
54
0
  const char *const *fields;
55
0
  const char *salt;
56
0
  unsigned int rounds;
57
0
  unsigned char key1[PBKDF2_KEY_SIZE_SHA1], key2[PBKDF2_KEY_SIZE_SHA1];
58
0
  buffer_t buf;
59
60
  /* $1$salt$rounds$hash */
61
0
  if (size < 3 || memcmp(raw_password, "$1$", 3) != 0) {
62
0
    *error_r = "Invalid PBKDF2 passdb entry prefix";
63
0
    return -1;
64
0
  }
65
66
0
  fields = t_strsplit(t_strndup(raw_password + 3, size - 3), "$");
67
0
  salt = fields[0];
68
0
  if (str_array_length(fields) != 3 ||
69
0
      str_to_uint(fields[1], &rounds) < 0) {
70
0
    *error_r = "Invalid PBKDF2 passdb entry format";
71
0
    return -1;
72
0
  }
73
0
  buffer_create_from_data(&buf, key1, sizeof(key1));
74
0
  if (strlen(fields[2]) != sizeof(key1)*2 ||
75
0
      hex_to_binary(fields[2], &buf) < 0) {
76
0
    *error_r = "PBKDF2 hash not 160bit hex-encoded";
77
0
    return -1;
78
0
  }
79
80
0
  pbkdf_run(plaintext, salt, rounds, key2);
81
0
  return mem_equals_timing_safe(key1, key2, sizeof(key1)) ? 1 : 0;
82
0
}