Coverage Report

Created: 2025-09-05 06:58

/src/libluksde/libluksde/libluksde_password.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Password functions
3
 *
4
 * Copyright (C) 2013-2024, 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
0
{
47
0
  uint8_t block_buffer[ 64 ];
48
0
  uint8_t hash_buffer[ 64 ];
49
50
0
  uint8_t *data_buffer       = NULL;
51
0
  static char *function      = "libluksde_password_pbkdf2";
52
0
  size_t data_buffer_size    = 0;
53
0
  size_t hash_size           = 0;
54
0
  size_t output_data_offset  = 0;
55
0
  size_t remaining_data_size = 0;
56
0
  uint32_t block_index       = 0;
57
0
  uint32_t byte_index        = 0;
58
0
  uint32_t number_of_blocks  = 0;
59
0
  uint32_t password_iterator = 0;
60
0
  int result                 = 0;
61
62
0
  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
0
  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
0
  switch( password_hashing_method )
85
0
  {
86
0
    case LIBLUKSDE_HASHING_METHOD_SHA1:
87
0
      hash_size = LIBHMAC_SHA1_HASH_SIZE;
88
0
      break;
89
90
0
    case LIBLUKSDE_HASHING_METHOD_SHA224:
91
0
      hash_size = LIBHMAC_SHA224_HASH_SIZE;
92
0
      break;
93
94
0
    case LIBLUKSDE_HASHING_METHOD_SHA256:
95
0
      hash_size = LIBHMAC_SHA256_HASH_SIZE;
96
0
      break;
97
98
0
    case LIBLUKSDE_HASHING_METHOD_SHA512:
99
0
      hash_size = LIBHMAC_SHA512_HASH_SIZE;
100
0
      break;
101
102
0
    default:
103
0
      libcerror_error_set(
104
0
       error,
105
0
       LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
106
0
       LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
107
0
       "%s: unsupported password hashing method.",
108
0
       function );
109
110
0
      return( -1 );
111
0
  }
112
0
  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
0
  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
0
  if( number_of_iterations == 0 )
135
0
  {
136
0
    libcerror_error_set(
137
0
     error,
138
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
139
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_ZERO_OR_LESS,
140
0
     "%s: invalid number of iterations value zero or less.",
141
0
     function );
142
143
0
    return( -1 );
144
0
  }
145
0
  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
0
  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
0
  if( memory_set(
168
0
       block_buffer,
169
0
       0,
170
0
       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
0
  if( memory_set(
182
0
       hash_buffer,
183
0
       0,
184
0
       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
0
  if( memory_set(
196
0
       output_data,
197
0
       0,
198
0
       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
0
  number_of_blocks    = output_data_size / hash_size;
211
0
  remaining_data_size = output_data_size % hash_size;
212
213
0
  if( remaining_data_size != 0 )
214
0
  {
215
0
    number_of_blocks += 1;
216
0
  }
217
0
  data_buffer_size = salt_size + 4;
218
219
0
  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
0
  data_buffer = (uint8_t *) memory_allocate(
231
0
                             sizeof( uint8_t ) * data_buffer_size );
232
233
0
  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
0
  if( memory_copy(
245
0
       data_buffer,
246
0
       salt,
247
0
       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
0
  byte_stream_copy_from_uint32_big_endian(
259
0
   &( data_buffer[ salt_size ] ),
260
0
   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
0
  for( block_index = 1;
307
0
       block_index <= number_of_blocks;
308
0
       block_index++ )
309
0
  {
310
0
    byte_stream_copy_from_uint32_big_endian(
311
0
     &( data_buffer[ salt_size ] ),
312
0
     block_index );
313
314
0
    switch( password_hashing_method )
315
0
    {
316
0
      case LIBLUKSDE_HASHING_METHOD_SHA1:
317
0
                    result = libhmac_sha1_calculate_hmac(
318
0
                  password,
319
0
                  password_length,
320
0
                  data_buffer,
321
0
                  data_buffer_size,
322
0
                  hash_buffer,
323
0
                  hash_size,
324
0
                  error );
325
0
        break;
326
327
0
      case LIBLUKSDE_HASHING_METHOD_SHA224:
328
0
                    result = libhmac_sha224_calculate_hmac(
329
0
                  password,
330
0
                  password_length,
331
0
                  data_buffer,
332
0
                  data_buffer_size,
333
0
                  hash_buffer,
334
0
                  hash_size,
335
0
                  error );
336
0
        break;
337
338
0
      case LIBLUKSDE_HASHING_METHOD_SHA256:
339
0
                    result = libhmac_sha256_calculate_hmac(
340
0
                  password,
341
0
                  password_length,
342
0
                  data_buffer,
343
0
                  data_buffer_size,
344
0
                  hash_buffer,
345
0
                  hash_size,
346
0
                  error );
347
0
        break;
348
349
0
      case LIBLUKSDE_HASHING_METHOD_SHA512:
350
0
                    result = libhmac_sha512_calculate_hmac(
351
0
                  password,
352
0
                  password_length,
353
0
                  data_buffer,
354
0
                  data_buffer_size,
355
0
                  hash_buffer,
356
0
                  hash_size,
357
0
                  error );
358
0
        break;
359
360
0
      default:
361
0
        result = 0;
362
0
        break;
363
0
    }
364
0
    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
0
    if( memory_copy(
377
0
         block_buffer,
378
0
         hash_buffer,
379
0
         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
0
    for( password_iterator = 1;
391
0
         password_iterator < number_of_iterations;
392
0
         password_iterator++ )
393
0
    {
394
0
      switch( password_hashing_method )
395
0
      {
396
0
        case LIBLUKSDE_HASHING_METHOD_SHA1:
397
0
          result = libhmac_sha1_calculate_hmac(
398
0
                    password,
399
0
                    password_length,
400
0
                    hash_buffer,
401
0
                    hash_size,
402
0
                    hash_buffer,
403
0
                    hash_size,
404
0
                    error );
405
0
          break;
406
407
0
        case LIBLUKSDE_HASHING_METHOD_SHA224:
408
0
          result = libhmac_sha224_calculate_hmac(
409
0
                    password,
410
0
                    password_length,
411
0
                    hash_buffer,
412
0
                    hash_size,
413
0
                    hash_buffer,
414
0
                    hash_size,
415
0
                    error );
416
0
          break;
417
418
0
        case LIBLUKSDE_HASHING_METHOD_SHA256:
419
0
          result = libhmac_sha256_calculate_hmac(
420
0
                    password,
421
0
                    password_length,
422
0
                    hash_buffer,
423
0
                    hash_size,
424
0
                    hash_buffer,
425
0
                    hash_size,
426
0
                    error );
427
0
          break;
428
429
0
        case LIBLUKSDE_HASHING_METHOD_SHA512:
430
0
          result = libhmac_sha512_calculate_hmac(
431
0
                    password,
432
0
                    password_length,
433
0
                    hash_buffer,
434
0
                    hash_size,
435
0
                    hash_buffer,
436
0
                    hash_size,
437
0
                    error );
438
0
          break;
439
440
0
        default:
441
0
          result = 0;
442
0
          break;
443
0
      }
444
0
      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
0
      for( byte_index = 0;
457
0
           byte_index < hash_size;
458
0
           byte_index++ )
459
0
      {
460
0
        block_buffer[ byte_index ] ^= hash_buffer[ byte_index ];
461
0
      }
462
0
    }
463
0
    if( hash_size > output_data_size )
464
0
    {
465
0
      hash_size = output_data_size;
466
0
    }
467
0
    if( memory_copy(
468
0
         &( output_data[ output_data_offset ] ),
469
0
         block_buffer,
470
0
         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
0
    output_data_offset += hash_size;
482
0
    output_data_size   -= hash_size;
483
0
  }
484
0
  if( data_buffer != NULL )
485
0
  {
486
0
    memory_free(
487
0
     data_buffer );
488
0
  }
489
0
  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
0
}
499