Coverage Report

Created: 2025-06-22 07:35

/src/libfvde/libfvde/libfvde_password.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Password functions
3
 *
4
 * Copyright (C) 2011-2024, Omar Choudary <choudary.omar@gmail.com>
5
 *                          Joachim Metz <joachim.metz@gmail.com>
6
 *
7
 * Refer to AUTHORS for acknowledgements.
8
 *
9
 * This program is free software: you can redistribute it and/or modify
10
 * it under the terms of the GNU Lesser General Public License as published by
11
 * the Free Software Foundation, either version 3 of the License, or
12
 * (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public License
20
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
21
 */
22
23
#include <common.h>
24
#include <byte_stream.h>
25
#include <memory.h>
26
#include <types.h>
27
28
#include "libfvde_definitions.h"
29
#include "libfvde_libcerror.h"
30
#include "libfvde_libcnotify.h"
31
#include "libfvde_libhmac.h"
32
#include "libfvde_libuna.h"
33
#include "libfvde_password.h"
34
35
/* Compute a PBKDF2-derived key from the given input.
36
 * Returns 1 if successful or -1 on error
37
 */
38
int libfvde_password_pbkdf2(
39
     const uint8_t *password,
40
     size_t password_size,
41
     const uint8_t *salt,
42
     size_t salt_size,
43
     uint32_t number_of_iterations,
44
     uint8_t *output_data,
45
     size_t output_data_size,
46
     libcerror_error_t **error )
47
0
{
48
0
  uint8_t hash_buffer[ LIBHMAC_SHA256_HASH_SIZE ];
49
50
0
  uint8_t *data_buffer       = NULL;
51
0
  uint8_t *output_ptr        = NULL;
52
0
  static char *function      = "libfvde_password_pbkdf2";
53
0
  size_t block_offset        = 0;
54
0
  size_t data_buffer_size    = 0;
55
0
  size_t hash_size           = LIBHMAC_SHA256_HASH_SIZE;
56
0
  size_t remaining_data_size = 0;
57
0
  uint32_t block_index       = 0;
58
0
  uint32_t byte_index        = 0;
59
0
  uint32_t number_of_blocks  = 0;
60
0
  uint32_t password_iterator = 0;
61
0
  int result                 = 0;
62
63
0
  if( password == NULL )
64
0
  {
65
0
    libcerror_error_set(
66
0
     error,
67
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
68
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
69
0
     "%s: invalid password.",
70
0
     function );
71
72
0
    return( -1 );
73
0
  }
74
0
  if( password_size > (size_t) SSIZE_MAX )
75
0
  {
76
0
    libcerror_error_set(
77
0
     error,
78
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
79
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
80
0
     "%s: invalid password size value exceeds maximum.",
81
0
     function );
82
83
0
    return( -1 );
84
0
  }
85
0
  if( salt == NULL )
86
0
  {
87
0
    libcerror_error_set(
88
0
     error,
89
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
90
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
91
0
     "%s: invalid salt.",
92
0
     function );
93
94
0
    return( -1 );
95
0
  }
96
0
  if( salt_size > (size_t) ( MEMORY_MAXIMUM_ALLOCATION_SIZE - 4 ) )
97
0
  {
98
0
    libcerror_error_set(
99
0
     error,
100
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
101
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
102
0
     "%s: invalid salt size value exceeds maximum.",
103
0
     function );
104
105
0
    return( -1 );
106
0
  }
107
0
  if( number_of_iterations == 0 )
108
0
  {
109
0
    libcerror_error_set(
110
0
     error,
111
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
112
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_ZERO_OR_LESS,
113
0
     "%s: invalid number of iterations value zero or less.",
114
0
     function );
115
116
0
    return( -1 );
117
0
  }
118
0
  if( output_data == NULL )
119
0
  {
120
0
    libcerror_error_set(
121
0
     error,
122
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
123
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
124
0
     "%s: invalid output data.",
125
0
     function );
126
127
0
    return( -1 );
128
0
  }
129
0
  if( output_data_size > (size_t) SSIZE_MAX )
130
0
  {
131
0
    libcerror_error_set(
132
0
     error,
133
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
134
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
135
0
     "%s: invalid output data size value exceeds maximum.",
136
0
     function );
137
138
0
    return( -1 );
139
0
  }
140
0
  if( memory_set(
141
0
       output_data,
142
0
       0,
143
0
       output_data_size ) == NULL )
144
0
  {
145
0
    libcerror_error_set(
146
0
     error,
147
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
148
0
     LIBCERROR_MEMORY_ERROR_COPY_FAILED,
149
0
     "%s: unable to clear output data.",
150
0
     function );
151
152
0
    goto on_error;
153
0
  }
154
/* TODO add bounds check */
155
0
  number_of_blocks    = output_data_size / hash_size;
156
0
  remaining_data_size = output_data_size - ( number_of_blocks * hash_size );
157
0
  data_buffer_size    = salt_size + 4;
158
159
0
  data_buffer = (uint8_t *) memory_allocate(
160
0
                             sizeof( uint8_t ) * data_buffer_size );
161
162
0
  if( data_buffer == NULL )
163
0
  {
164
0
    libcerror_error_set(
165
0
     error,
166
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
167
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
168
0
     "%s: unable to create data buffer.",
169
0
     function );
170
171
0
    goto on_error;
172
0
  }
173
0
  if( memory_set(
174
0
       data_buffer,
175
0
       0,
176
0
       data_buffer_size ) == NULL )
177
0
  {
178
0
    libcerror_error_set(
179
0
     error,
180
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
181
0
     LIBCERROR_MEMORY_ERROR_COPY_FAILED,
182
0
     "%s: unable to clear data buffer.",
183
0
     function );
184
185
0
    goto on_error;
186
0
  }
187
0
  if( memory_copy(
188
0
       data_buffer,
189
0
       salt,
190
0
       salt_size ) == NULL)
191
0
  {
192
0
    libcerror_error_set(
193
0
     error,
194
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
195
0
     LIBCERROR_MEMORY_ERROR_COPY_FAILED,
196
0
     "%s: unable to copy salt into data buffer.",
197
0
     function );
198
199
0
    goto on_error;
200
0
  }
201
#if defined( HAVE_DEBUG_OUTPUT )
202
  if( libcnotify_verbose != 0 )
203
  {
204
    libcnotify_printf(
205
     "%s: password:\n",
206
     function );
207
    libcnotify_print_data(
208
     password,
209
     password_size,
210
     0 );
211
212
    libcnotify_printf(
213
     "%s: data buffer:\n",
214
     function );
215
    libcnotify_print_data(
216
     data_buffer,
217
     data_buffer_size,
218
     0 );
219
220
    libcnotify_printf(
221
     "%s: number of iterations\t\t\t\t: %" PRIu32 "\n",
222
     function,
223
     number_of_iterations );
224
225
    libcnotify_printf(
226
     "%s: number of blocks\t\t\t\t: %" PRIu32 "\n",
227
     function,
228
     number_of_blocks );
229
230
    libcnotify_printf(
231
     "%s: remaining data size\t\t\t\t: %" PRIzd "\n",
232
     function,
233
     remaining_data_size );
234
235
    libcnotify_printf(
236
     "\n" );
237
  }
238
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
239
240
0
  for( block_index = 0;
241
0
       block_index < number_of_blocks;
242
0
       block_index++ )
243
0
  {
244
0
    output_ptr = &( output_data[ block_offset ] );
245
246
0
    byte_stream_copy_from_uint32_big_endian(
247
0
     &( data_buffer[ salt_size ] ),
248
0
     block_index + 1 );
249
250
0
                result = libhmac_sha256_calculate_hmac(
251
0
              password,
252
0
              password_size,
253
0
              data_buffer,
254
0
              data_buffer_size,
255
0
              hash_buffer,
256
0
              hash_size,
257
0
              error );
258
259
0
    if( result != 1 )
260
0
    {
261
0
      libcerror_error_set(
262
0
       error,
263
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
264
0
       LIBCERROR_RUNTIME_ERROR_GENERIC,
265
0
       "%s: unable to compute initial hmac for block %d.",
266
0
       function,
267
0
       block_index );
268
269
0
      goto on_error;
270
0
    }
271
0
    if( memory_copy(
272
0
         output_ptr,
273
0
         hash_buffer,
274
0
         hash_size ) == NULL )
275
0
    {
276
0
      libcerror_error_set(
277
0
       error,
278
0
       LIBCERROR_ERROR_DOMAIN_MEMORY,
279
0
       LIBCERROR_MEMORY_ERROR_COPY_FAILED,
280
0
       "%s: unable to copy hash buffer into output data.",
281
0
       function );
282
283
0
      goto on_error;
284
0
    }
285
0
    for( password_iterator = 0;
286
0
         password_iterator < number_of_iterations - 1;
287
0
         password_iterator++ )
288
0
    {
289
0
      result = libhmac_sha256_calculate_hmac(
290
0
                password,
291
0
                password_size,
292
0
                hash_buffer,
293
0
                hash_size,
294
0
                hash_buffer,
295
0
                hash_size,
296
0
                error );
297
298
0
      if( result != 1 )
299
0
      {
300
0
        libcerror_error_set(
301
0
         error,
302
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
303
0
         LIBCERROR_RUNTIME_ERROR_GENERIC,
304
0
         "%s: unable to compute initial hmac for block %d.",
305
0
         function,
306
0
         block_index);
307
308
0
        goto on_error;
309
0
      }
310
0
      for( byte_index = 0;
311
0
           byte_index < hash_size;
312
0
           byte_index++ )
313
0
      {
314
0
        output_ptr[ byte_index ] ^= hash_buffer[ byte_index ];
315
0
      }
316
0
    }
317
0
    block_offset += hash_size;
318
0
  }
319
0
  if( remaining_data_size > 0 )
320
0
  {
321
0
    output_ptr = &( output_data[ block_offset ] );
322
323
0
    byte_stream_copy_from_uint32_big_endian(
324
0
     &( data_buffer[ salt_size ] ),
325
0
     block_index + 1 );
326
327
0
    result = libhmac_sha256_calculate_hmac(
328
0
              password,
329
0
              password_size,
330
0
              data_buffer,
331
0
              data_buffer_size,
332
0
              hash_buffer,
333
0
              hash_size,
334
0
              error );
335
336
0
    if( result != 1 )
337
0
    {
338
0
      libcerror_error_set(
339
0
       error,
340
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
341
0
       LIBCERROR_RUNTIME_ERROR_GENERIC,
342
0
       "%s: unable to compute initial hmac for block %d.",
343
0
       function,
344
0
       block_index);
345
346
0
      goto on_error;
347
0
    }
348
0
    if( memory_copy(
349
0
         output_ptr,
350
0
         hash_buffer,
351
0
         remaining_data_size ) == NULL )
352
0
    {
353
0
      libcerror_error_set(
354
0
       error,
355
0
       LIBCERROR_ERROR_DOMAIN_MEMORY,
356
0
       LIBCERROR_MEMORY_ERROR_COPY_FAILED,
357
0
       "%s: unable to copy hash buffer into output data in last block.",
358
0
       function );
359
360
0
      goto on_error;
361
0
    }
362
0
    for( password_iterator = 0;
363
0
         password_iterator < number_of_iterations - 1;
364
0
         password_iterator++ )
365
0
    {
366
0
      result = libhmac_sha256_calculate_hmac(
367
0
                password,
368
0
                password_size,
369
0
                hash_buffer,
370
0
                hash_size,
371
0
                hash_buffer,
372
0
                hash_size,
373
0
                error );
374
375
0
      if( result != 1 )
376
0
      {
377
0
        libcerror_error_set(
378
0
         error,
379
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
380
0
         LIBCERROR_RUNTIME_ERROR_GENERIC,
381
0
         "%s: unable to compute initial hmac for block %d.",
382
0
         function,
383
0
         block_index );
384
385
0
        goto on_error;
386
0
      }
387
0
      for( byte_index = 0;
388
0
           byte_index < remaining_data_size;
389
0
           byte_index++ )
390
0
      {
391
0
        output_ptr[ byte_index ] ^= hash_buffer[ byte_index ];
392
0
      }
393
0
    }
394
0
  }
395
0
  if( data_buffer != NULL )
396
0
  {
397
0
    memory_free(
398
0
     data_buffer );
399
0
  }
400
0
  return( 1 );
401
402
0
on_error:
403
0
  if( data_buffer != NULL )
404
0
  {
405
0
    memory_free(
406
0
     data_buffer );
407
0
  }
408
0
  return( -1 );
409
0
}
410
411
/* Copies the password from an UTF-8 formatted string
412
 * Returns 1 if successful or -1 on error
413
 */
414
int libfvde_password_copy_from_utf8_string(
415
     uint8_t **password,
416
     size_t *password_size,
417
     const uint8_t *utf8_string,
418
     size_t utf8_string_length,
419
     libcerror_error_t **error )
420
0
{
421
0
  uint8_t *safe_password    = NULL;
422
0
  static char *function     = "libfvde_password_copy_from_utf8_string";
423
0
  size_t safe_password_size = 0;
424
425
0
  if( password == NULL )
426
0
  {
427
0
    libcerror_error_set(
428
0
     error,
429
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
430
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
431
0
     "%s: invalid password.",
432
0
     function );
433
434
0
    return( -1 );
435
0
  }
436
0
  if( password_size == NULL )
437
0
  {
438
0
    libcerror_error_set(
439
0
     error,
440
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
441
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
442
0
     "%s: invalid password size.",
443
0
     function );
444
445
0
    return( -1 );
446
0
  }
447
0
  if( libuna_byte_stream_size_from_utf8(
448
0
       utf8_string,
449
0
       utf8_string_length,
450
0
       LIBUNA_CODEPAGE_US_ASCII,
451
0
       &safe_password_size,
452
0
       error ) != 1 )
453
0
  {
454
0
    libcerror_error_set(
455
0
     error,
456
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
457
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
458
0
     "%s: unable to determine size of password from UTF-8 string.",
459
0
     function );
460
461
0
    goto on_error;
462
0
  }
463
0
  if( ( safe_password_size == 0 )
464
0
   || ( safe_password_size > (size_t) ( MEMORY_MAXIMUM_ALLOCATION_SIZE - 1 ) ) )
465
0
  {
466
0
    libcerror_error_set(
467
0
     error,
468
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
469
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
470
0
     "%s: invalid password size value out of bounds.",
471
0
     function );
472
473
0
    goto on_error;
474
0
  }
475
0
  safe_password = (uint8_t *) memory_allocate(
476
0
                               sizeof( uint8_t ) * ( safe_password_size + 1 ) );
477
478
0
  if( safe_password == NULL )
479
0
  {
480
0
    libcerror_error_set(
481
0
     error,
482
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
483
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
484
0
     "%s: unable to create password.",
485
0
     function );
486
487
0
    goto on_error;
488
0
  }
489
0
  if( libuna_byte_stream_copy_from_utf8(
490
0
       safe_password,
491
0
       safe_password_size,
492
0
       LIBUNA_CODEPAGE_US_ASCII,
493
0
       utf8_string,
494
0
       utf8_string_length,
495
0
       error ) != 1 )
496
0
  {
497
0
    libcerror_error_set(
498
0
     error,
499
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
500
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
501
0
     "%s: unable to copy password from UTF-8 string.",
502
0
     function );
503
504
0
    goto on_error;
505
0
  }
506
0
  safe_password[ safe_password_size ] = 0;
507
508
0
  *password      = safe_password;
509
0
  *password_size = safe_password_size + 1;
510
511
0
  return( 1 );
512
513
0
on_error:
514
0
  if( safe_password != NULL )
515
0
  {
516
0
    memory_set(
517
0
     safe_password,
518
0
     0,
519
0
     safe_password_size );
520
0
    memory_free(
521
0
     safe_password );
522
0
  }
523
0
  return( -1 );
524
0
}
525
526
/* Copies the password from an UTF-16 formatted string
527
 * Returns 1 if successful or -1 on error
528
 */
529
int libfvde_password_copy_from_utf16_string(
530
     uint8_t **password,
531
     size_t *password_size,
532
     const uint16_t *utf16_string,
533
     size_t utf16_string_length,
534
     libcerror_error_t **error )
535
0
{
536
0
  uint8_t *safe_password    = NULL;
537
0
  static char *function     = "libfvde_password_copy_from_utf16_string";
538
0
  size_t safe_password_size = 0;
539
540
0
  if( password == NULL )
541
0
  {
542
0
    libcerror_error_set(
543
0
     error,
544
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
545
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
546
0
     "%s: invalid password.",
547
0
     function );
548
549
0
    return( -1 );
550
0
  }
551
0
  if( password_size == NULL )
552
0
  {
553
0
    libcerror_error_set(
554
0
     error,
555
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
556
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
557
0
     "%s: invalid password size.",
558
0
     function );
559
560
0
    return( -1 );
561
0
  }
562
0
  if( libuna_byte_stream_size_from_utf16(
563
0
       utf16_string,
564
0
       utf16_string_length,
565
0
       LIBUNA_CODEPAGE_US_ASCII,
566
0
       &safe_password_size,
567
0
       error ) != 1 )
568
0
  {
569
0
    libcerror_error_set(
570
0
     error,
571
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
572
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
573
0
     "%s: unable to determine size of password from UTF-16 string.",
574
0
     function );
575
576
0
    goto on_error;
577
0
  }
578
0
  if( ( safe_password_size == 0 )
579
0
   || ( safe_password_size > (size_t) ( MEMORY_MAXIMUM_ALLOCATION_SIZE - 1 ) ) )
580
0
  {
581
0
    libcerror_error_set(
582
0
     error,
583
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
584
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
585
0
     "%s: invalid password size value out of bounds.",
586
0
     function );
587
588
0
    goto on_error;
589
0
  }
590
0
  safe_password = (uint8_t *) memory_allocate(
591
0
                               sizeof( uint8_t ) * ( safe_password_size + 1 ) );
592
593
0
  if( safe_password == NULL )
594
0
  {
595
0
    libcerror_error_set(
596
0
     error,
597
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
598
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
599
0
     "%s: unable to create password.",
600
0
     function );
601
602
0
    goto on_error;
603
0
  }
604
0
  if( libuna_byte_stream_copy_from_utf16(
605
0
       safe_password,
606
0
       safe_password_size,
607
0
       LIBUNA_CODEPAGE_US_ASCII,
608
0
       utf16_string,
609
0
       utf16_string_length,
610
0
       error ) != 1 )
611
0
  {
612
0
    libcerror_error_set(
613
0
     error,
614
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
615
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
616
0
     "%s: unable to copy password from UTF-16 string.",
617
0
     function );
618
619
0
    goto on_error;
620
0
  }
621
0
  safe_password[ safe_password_size ] = 0;
622
623
0
  *password      = safe_password;
624
0
  *password_size = safe_password_size + 1;
625
626
0
  return( 1 );
627
628
0
on_error:
629
0
  if( safe_password != NULL )
630
0
  {
631
0
    memory_set(
632
0
     safe_password,
633
0
     0,
634
0
     safe_password_size );
635
0
    memory_free(
636
0
     safe_password );
637
0
  }
638
0
  return( -1 );
639
0
}
640