Coverage Report

Created: 2026-08-31 07:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libluksde/libluksde/libluksde_password.c
Line
Count
Source
1
/*
2
 * Password functions
3
 *
4
 * Copyright (C) 2013-2026, Joachim Metz <joachim.metz@gmail.com>
5
 *
6
 * Refer to AUTHORS for acknowledgements.
7
 *
8
 * This program is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Lesser General Public License as published by
10
 * the Free Software Foundation, either version 3 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public License
19
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
20
 */
21
22
#include <common.h>
23
#include <byte_stream.h>
24
#include <memory.h>
25
#include <types.h>
26
27
#include "libluksde_definitions.h"
28
#include "libluksde_libcerror.h"
29
#include "libluksde_libcnotify.h"
30
#include "libluksde_libhmac.h"
31
#include "libluksde_password.h"
32
33
/* Compute a PBKDF2-derived key from the given input.
34
 * Returns 1 if successful or -1 on error
35
 */
36
int libluksde_password_pbkdf2(
37
     const uint8_t *password,
38
     size_t password_length,
39
     int password_hashing_method,
40
     const uint8_t *salt,
41
     size_t salt_size,
42
     uint32_t number_of_iterations,
43
     uint8_t *output_data,
44
     size_t output_data_size,
45
     libcerror_error_t **error )
46
1.10k
{
47
1.10k
  uint8_t block_buffer[ 64 ];
48
1.10k
  uint8_t hash_buffer[ 64 ];
49
50
1.10k
  uint8_t *data_buffer       = NULL;
51
1.10k
  static char *function      = "libluksde_password_pbkdf2";
52
1.10k
  size_t data_buffer_size    = 0;
53
1.10k
  size_t hash_size           = 0;
54
1.10k
  size_t output_data_offset  = 0;
55
1.10k
  size_t remaining_data_size = 0;
56
1.10k
  uint32_t block_index       = 0;
57
1.10k
  uint32_t byte_index        = 0;
58
1.10k
  uint32_t number_of_blocks  = 0;
59
1.10k
  uint32_t password_iterator = 0;
60
1.10k
  int result                 = 0;
61
62
1.10k
  if( password == NULL )
63
0
  {
64
0
    libcerror_error_set(
65
0
     error,
66
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
67
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
68
0
     "%s: invalid password.",
69
0
     function );
70
71
0
    return( -1 );
72
0
  }
73
1.10k
  if( password_length > (size_t) ( SSIZE_MAX - 1 ) )
74
0
  {
75
0
    libcerror_error_set(
76
0
     error,
77
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
78
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
79
0
     "%s: invalid password length value exceeds maximum.",
80
0
     function );
81
82
0
    return( -1 );
83
0
  }
84
1.10k
  switch( password_hashing_method )
85
1.10k
  {
86
1.02k
    case LIBLUKSDE_HASHING_METHOD_SHA1:
87
1.02k
      hash_size = LIBHMAC_SHA1_HASH_SIZE;
88
1.02k
      break;
89
90
39
    case LIBLUKSDE_HASHING_METHOD_SHA224:
91
39
      hash_size = LIBHMAC_SHA224_HASH_SIZE;
92
39
      break;
93
94
17
    case LIBLUKSDE_HASHING_METHOD_SHA256:
95
17
      hash_size = LIBHMAC_SHA256_HASH_SIZE;
96
17
      break;
97
98
19
    case LIBLUKSDE_HASHING_METHOD_SHA512:
99
19
      hash_size = LIBHMAC_SHA512_HASH_SIZE;
100
19
      break;
101
102
5
    default:
103
5
      libcerror_error_set(
104
5
       error,
105
5
       LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
106
5
       LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
107
5
       "%s: unsupported password hashing method.",
108
5
       function );
109
110
5
      return( -1 );
111
1.10k
  }
112
1.09k
  if( salt == NULL )
113
0
  {
114
0
    libcerror_error_set(
115
0
     error,
116
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
117
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
118
0
     "%s: invalid salt.",
119
0
     function );
120
121
0
    return( -1 );
122
0
  }
123
1.09k
  if( salt_size > (size_t) SSIZE_MAX )
124
0
  {
125
0
    libcerror_error_set(
126
0
     error,
127
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
128
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
129
0
     "%s: invalid salt size value exceeds maximum.",
130
0
     function );
131
132
0
    return( -1 );
133
0
  }
134
1.09k
  if( number_of_iterations == 0 )
135
4
  {
136
4
    libcerror_error_set(
137
4
     error,
138
4
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
139
4
     LIBCERROR_ARGUMENT_ERROR_VALUE_ZERO_OR_LESS,
140
4
     "%s: invalid number of iterations value zero or less.",
141
4
     function );
142
143
4
    return( -1 );
144
4
  }
145
1.09k
  if( output_data == NULL )
146
0
  {
147
0
    libcerror_error_set(
148
0
     error,
149
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
150
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
151
0
     "%s: invalid output data.",
152
0
     function );
153
154
0
    return( -1 );
155
0
  }
156
1.09k
  if( output_data_size > (size_t) SSIZE_MAX )
157
0
  {
158
0
    libcerror_error_set(
159
0
     error,
160
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
161
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
162
0
     "%s: invalid output data size value exceeds maximum.",
163
0
     function );
164
165
0
    return( -1 );
166
0
  }
167
1.09k
  if( memory_set(
168
1.09k
       block_buffer,
169
1.09k
       0,
170
1.09k
       64 ) == NULL )
171
0
  {
172
0
    libcerror_error_set(
173
0
     error,
174
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
175
0
     LIBCERROR_MEMORY_ERROR_COPY_FAILED,
176
0
     "%s: unable to clear hash buffer.",
177
0
     function );
178
179
0
    goto on_error;
180
0
  }
181
1.09k
  if( memory_set(
182
1.09k
       hash_buffer,
183
1.09k
       0,
184
1.09k
       64 ) == NULL )
185
0
  {
186
0
    libcerror_error_set(
187
0
     error,
188
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
189
0
     LIBCERROR_MEMORY_ERROR_COPY_FAILED,
190
0
     "%s: unable to clear hash buffer.",
191
0
     function );
192
193
0
    goto on_error;
194
0
  }
195
1.09k
  if( memory_set(
196
1.09k
       output_data,
197
1.09k
       0,
198
1.09k
       output_data_size ) == NULL )
199
0
  {
200
0
    libcerror_error_set(
201
0
     error,
202
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
203
0
     LIBCERROR_MEMORY_ERROR_COPY_FAILED,
204
0
     "%s: unable to clear output data.",
205
0
     function );
206
207
0
    goto on_error;
208
0
  }
209
/* TODO add bounds check */
210
1.09k
  number_of_blocks    = output_data_size / hash_size;
211
1.09k
  remaining_data_size = output_data_size % hash_size;
212
213
1.09k
  if( remaining_data_size != 0 )
214
653
  {
215
653
    number_of_blocks += 1;
216
653
  }
217
1.09k
  data_buffer_size = salt_size + 4;
218
219
1.09k
  if( data_buffer_size > (size_t) MEMORY_MAXIMUM_ALLOCATION_SIZE )
220
0
  {
221
0
    libcerror_error_set(
222
0
     error,
223
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
224
0
     LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
225
0
     "%s: invalid data buffer size value exceeds maximum allocation size.",
226
0
     function );
227
228
0
    return( -1 );
229
0
  }
230
1.09k
  data_buffer = (uint8_t *) memory_allocate(
231
1.09k
                             sizeof( uint8_t ) * data_buffer_size );
232
233
1.09k
  if( data_buffer == NULL )
234
0
  {
235
0
    libcerror_error_set(
236
0
     error,
237
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
238
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
239
0
     "%s: unable to create data buffer.",
240
0
     function );
241
242
0
    goto on_error;
243
0
  }
244
1.09k
  if( memory_copy(
245
1.09k
       data_buffer,
246
1.09k
       salt,
247
1.09k
       salt_size ) == NULL )
248
0
  {
249
0
    libcerror_error_set(
250
0
     error,
251
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
252
0
     LIBCERROR_MEMORY_ERROR_COPY_FAILED,
253
0
     "%s: unable to copy salt into data buffer.",
254
0
     function );
255
256
0
    goto on_error;
257
0
  }
258
1.09k
  byte_stream_copy_from_uint32_big_endian(
259
1.09k
   &( data_buffer[ salt_size ] ),
260
1.09k
   0 );
261
262
#if defined( HAVE_DEBUG_OUTPUT )
263
  if( libcnotify_verbose != 0 )
264
  {
265
    libcnotify_printf(
266
     "%s: password:\n",
267
     function );
268
    libcnotify_print_data(
269
     password,
270
     password_length,
271
     0 );
272
273
    libcnotify_printf(
274
     "%s: data buffer:\n",
275
     function );
276
    libcnotify_print_data(
277
     data_buffer,
278
     data_buffer_size,
279
     0 );
280
281
    libcnotify_printf(
282
     "%s: hash size\t\t\t\t\t: %" PRIzd "\n",
283
     function,
284
     hash_size );
285
286
    libcnotify_printf(
287
     "%s: number of iterations\t\t\t\t: %" PRIu32 "\n",
288
     function,
289
     number_of_iterations );
290
291
    libcnotify_printf(
292
     "%s: number of blocks\t\t\t\t: %" PRIu32 "\n",
293
     function,
294
     number_of_blocks );
295
296
    libcnotify_printf(
297
     "%s: remaining data size\t\t\t\t: %" PRIzd "\n",
298
     function,
299
     remaining_data_size );
300
301
    libcnotify_printf(
302
     "\n" );
303
  }
304
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
305
306
1.09k
  for( block_index = 1;
307
2.41k
       block_index <= number_of_blocks;
308
1.32k
       block_index++ )
309
1.32k
  {
310
1.32k
    byte_stream_copy_from_uint32_big_endian(
311
1.32k
     &( data_buffer[ salt_size ] ),
312
1.32k
     block_index );
313
314
1.32k
    switch( password_hashing_method )
315
1.32k
    {
316
1.19k
      case LIBLUKSDE_HASHING_METHOD_SHA1:
317
1.19k
                    result = libhmac_sha1_calculate_hmac(
318
1.19k
                  password,
319
1.19k
                  password_length,
320
1.19k
                  data_buffer,
321
1.19k
                  data_buffer_size,
322
1.19k
                  hash_buffer,
323
1.19k
                  hash_size,
324
1.19k
                  error );
325
1.19k
        break;
326
327
88
      case LIBLUKSDE_HASHING_METHOD_SHA224:
328
88
                    result = libhmac_sha224_calculate_hmac(
329
88
                  password,
330
88
                  password_length,
331
88
                  data_buffer,
332
88
                  data_buffer_size,
333
88
                  hash_buffer,
334
88
                  hash_size,
335
88
                  error );
336
88
        break;
337
338
19
      case LIBLUKSDE_HASHING_METHOD_SHA256:
339
19
                    result = libhmac_sha256_calculate_hmac(
340
19
                  password,
341
19
                  password_length,
342
19
                  data_buffer,
343
19
                  data_buffer_size,
344
19
                  hash_buffer,
345
19
                  hash_size,
346
19
                  error );
347
19
        break;
348
349
19
      case LIBLUKSDE_HASHING_METHOD_SHA512:
350
19
                    result = libhmac_sha512_calculate_hmac(
351
19
                  password,
352
19
                  password_length,
353
19
                  data_buffer,
354
19
                  data_buffer_size,
355
19
                  hash_buffer,
356
19
                  hash_size,
357
19
                  error );
358
19
        break;
359
360
0
      default:
361
0
        result = 0;
362
0
        break;
363
1.32k
    }
364
1.32k
    if( result != 1 )
365
0
    {
366
0
      libcerror_error_set(
367
0
       error,
368
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
369
0
       LIBCERROR_RUNTIME_ERROR_GENERIC,
370
0
       "%s: unable to compute initial hmac for block %d.",
371
0
       function,
372
0
       block_index );
373
374
0
      goto on_error;
375
0
    }
376
1.32k
    if( memory_copy(
377
1.32k
         block_buffer,
378
1.32k
         hash_buffer,
379
1.32k
         hash_size ) == NULL )
380
0
    {
381
0
      libcerror_error_set(
382
0
       error,
383
0
       LIBCERROR_ERROR_DOMAIN_MEMORY,
384
0
       LIBCERROR_MEMORY_ERROR_COPY_FAILED,
385
0
       "%s: unable to copy hash buffer into block buffer.",
386
0
       function );
387
388
0
      goto on_error;
389
0
    }
390
1.32k
    for( password_iterator = 1;
391
6.79M
         password_iterator < number_of_iterations;
392
6.79M
         password_iterator++ )
393
6.79M
    {
394
6.79M
      switch( password_hashing_method )
395
6.79M
      {
396
4.53M
        case LIBLUKSDE_HASHING_METHOD_SHA1:
397
4.53M
          result = libhmac_sha1_calculate_hmac(
398
4.53M
                    password,
399
4.53M
                    password_length,
400
4.53M
                    hash_buffer,
401
4.53M
                    hash_size,
402
4.53M
                    hash_buffer,
403
4.53M
                    hash_size,
404
4.53M
                    error );
405
4.53M
          break;
406
407
1.70M
        case LIBLUKSDE_HASHING_METHOD_SHA224:
408
1.70M
          result = libhmac_sha224_calculate_hmac(
409
1.70M
                    password,
410
1.70M
                    password_length,
411
1.70M
                    hash_buffer,
412
1.70M
                    hash_size,
413
1.70M
                    hash_buffer,
414
1.70M
                    hash_size,
415
1.70M
                    error );
416
1.70M
          break;
417
418
249k
        case LIBLUKSDE_HASHING_METHOD_SHA256:
419
249k
          result = libhmac_sha256_calculate_hmac(
420
249k
                    password,
421
249k
                    password_length,
422
249k
                    hash_buffer,
423
249k
                    hash_size,
424
249k
                    hash_buffer,
425
249k
                    hash_size,
426
249k
                    error );
427
249k
          break;
428
429
312k
        case LIBLUKSDE_HASHING_METHOD_SHA512:
430
312k
          result = libhmac_sha512_calculate_hmac(
431
312k
                    password,
432
312k
                    password_length,
433
312k
                    hash_buffer,
434
312k
                    hash_size,
435
312k
                    hash_buffer,
436
312k
                    hash_size,
437
312k
                    error );
438
312k
          break;
439
440
0
        default:
441
0
          result = 0;
442
0
          break;
443
6.79M
      }
444
6.79M
      if( result != 1 )
445
0
      {
446
0
        libcerror_error_set(
447
0
         error,
448
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
449
0
         LIBCERROR_RUNTIME_ERROR_GENERIC,
450
0
         "%s: unable to compute initial hmac for block %d.",
451
0
         function,
452
0
         block_index );
453
454
0
        goto on_error;
455
0
      }
456
6.79M
      for( byte_index = 0;
457
173M
           byte_index < hash_size;
458
166M
           byte_index++ )
459
166M
      {
460
166M
        block_buffer[ byte_index ] ^= hash_buffer[ byte_index ];
461
166M
      }
462
6.79M
    }
463
1.32k
    if( hash_size > output_data_size )
464
653
    {
465
653
      hash_size = output_data_size;
466
653
    }
467
1.32k
    if( memory_copy(
468
1.32k
         &( output_data[ output_data_offset ] ),
469
1.32k
         block_buffer,
470
1.32k
         hash_size ) == NULL )
471
0
    {
472
0
      libcerror_error_set(
473
0
       error,
474
0
       LIBCERROR_ERROR_DOMAIN_MEMORY,
475
0
       LIBCERROR_MEMORY_ERROR_COPY_FAILED,
476
0
       "%s: unable to copy block buffer into output data.",
477
0
       function );
478
479
0
      goto on_error;
480
0
    }
481
1.32k
    output_data_offset += hash_size;
482
1.32k
    output_data_size   -= hash_size;
483
1.32k
  }
484
1.09k
  if( data_buffer != NULL )
485
1.09k
  {
486
1.09k
    memory_free(
487
1.09k
     data_buffer );
488
1.09k
  }
489
1.09k
  return( 1 );
490
491
0
on_error:
492
0
  if( data_buffer != NULL )
493
0
  {
494
0
    memory_free(
495
0
     data_buffer );
496
0
  }
497
0
  return( -1 );
498
1.09k
}
499