Coverage Report

Created: 2025-06-13 07:21

/src/libbde/libbde/libbde_recovery.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Recovery functions
3
 *
4
 * Copyright (C) 2011-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 "libbde_libcerror.h"
28
#include "libbde_libcnotify.h"
29
#include "libbde_libfvalue.h"
30
#include "libbde_libhmac.h"
31
#include "libbde_recovery.h"
32
33
/* Calculates the SHA256 hash of an UTF-8 formatted recovery password
34
 * Returns 1 if successful, 0 if recovery password is invalid or -1 on error
35
 */
36
int libbde_utf8_recovery_password_calculate_hash(
37
     const uint8_t *utf8_string,
38
     size_t utf8_string_length,
39
     uint8_t *recovery_password_hash,
40
     size_t recovery_password_hash_size,
41
     libcerror_error_t **error )
42
0
{
43
0
  uint8_t binary_recovery_password[ 16 ];
44
45
0
  libfvalue_split_utf8_string_t *split_string = NULL;
46
0
  uint8_t *string_segment                     = NULL;
47
0
  static char *function                       = "libbde_utf8_recovery_password_calculate_hash";
48
0
  size_t string_segment_index                 = 0;
49
0
  size_t string_segment_size                  = 0;
50
0
  uint64_t value_64bit                        = 0;
51
0
  int number_of_segments                      = 0;
52
0
  int result                                  = 0;
53
0
  int segment_index                           = 0;
54
55
0
  if( recovery_password_hash == NULL )
56
0
  {
57
0
    libcerror_error_set(
58
0
     error,
59
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
60
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
61
0
     "%s: invalid recovery password hash.",
62
0
     function );
63
64
0
    return( -1 );
65
0
  }
66
0
  if( recovery_password_hash_size != 32 )
67
0
  {
68
0
    libcerror_error_set(
69
0
     error,
70
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
71
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
72
0
     "%s: recovery password hash size value out of bounds.",
73
0
     function );
74
75
0
    return( -1 );
76
0
  }
77
0
  if( libfvalue_utf8_string_split(
78
0
       utf8_string,
79
0
       utf8_string_length + 1,
80
0
       (uint8_t) '-',
81
0
       &split_string,
82
0
       error ) != 1 )
83
0
  {
84
0
    libcerror_error_set(
85
0
     error,
86
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
87
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
88
0
     "%s: unable to split string.",
89
0
     function );
90
91
0
    goto on_error;
92
0
  }
93
0
  if( libfvalue_split_utf8_string_get_number_of_segments(
94
0
       split_string,
95
0
       &number_of_segments,
96
0
       error ) != 1 )
97
0
  {
98
0
    libcerror_error_set(
99
0
     error,
100
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
101
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
102
0
     "%s: unable to retrieve number of segments in split string.",
103
0
     function );
104
105
0
    goto on_error;
106
0
  }
107
  /* The recovery password consists of 8 segments
108
   */
109
0
  if( number_of_segments == 8 )
110
0
  {
111
0
    for( segment_index = 0;
112
0
         segment_index < number_of_segments;
113
0
         segment_index++ )
114
0
    {
115
0
      if( libfvalue_split_utf8_string_get_segment_by_index(
116
0
           split_string,
117
0
           segment_index,
118
0
           &string_segment,
119
0
           &string_segment_size,
120
0
           error ) != 1 )
121
0
      {
122
0
        libcerror_error_set(
123
0
         error,
124
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
125
0
         LIBCERROR_RUNTIME_ERROR_GET_FAILED,
126
0
         "%s: unable to retrieve segment: %d from split string.",
127
0
         function,
128
0
         segment_index );
129
130
0
        goto on_error;
131
0
      }
132
0
      string_segment_index = 0;
133
134
0
      if( libfvalue_utf8_string_with_index_copy_to_integer(
135
0
           string_segment,
136
0
           string_segment_size,
137
0
           &string_segment_index,
138
0
           &value_64bit,
139
0
           16,
140
0
           LIBFVALUE_INTEGER_FORMAT_TYPE_DECIMAL_UNSIGNED,
141
0
           error ) != 1 )
142
0
      {
143
0
        libcerror_error_set(
144
0
         error,
145
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
146
0
         LIBCERROR_RUNTIME_ERROR_GET_FAILED,
147
0
         "%s: unable to determine binary value for segment: %d from split string.",
148
0
         function,
149
0
         segment_index );
150
151
0
        goto on_error;
152
0
      }
153
      /* A recovery password segment should be dividable by 11
154
       */
155
0
      if( ( value_64bit % 11 ) != 0 )
156
0
      {
157
0
        break;
158
0
      }
159
0
      value_64bit /= 11;
160
161
      /* A recovery password segment / 11 should be <= 65535 (0xffff)
162
       */
163
0
      if( value_64bit > (uint64_t) UINT16_MAX )
164
0
      {
165
0
        break;
166
0
      }
167
0
      byte_stream_copy_from_uint16_little_endian(
168
0
       &( binary_recovery_password[ segment_index * 2 ] ),
169
0
       value_64bit );
170
0
    }
171
0
    result = 1;
172
0
  }
173
0
  if( libfvalue_split_utf8_string_free(
174
0
       &split_string,
175
0
       error ) != 1 )
176
0
  {
177
0
    libcerror_error_set(
178
0
     error,
179
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
180
0
     LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
181
0
     "%s: unable to free split string.",
182
0
     function );
183
184
0
    goto on_error;
185
0
  }
186
0
  if( result == 1 )
187
0
  {
188
#if defined( HAVE_DEBUG_OUTPUT )
189
    if( libcnotify_verbose != 0 )
190
    {
191
      libcnotify_printf(
192
       "%s: binary recovery password:\n",
193
       function );
194
      libcnotify_print_data(
195
       binary_recovery_password,
196
       16,
197
       0 );
198
    }
199
#endif
200
0
    if( libhmac_sha256_calculate(
201
0
         binary_recovery_password,
202
0
         16,
203
0
         recovery_password_hash,
204
0
         recovery_password_hash_size,
205
0
         error ) != 1 )
206
0
    {
207
0
      libcerror_error_set(
208
0
       error,
209
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
210
0
       LIBCERROR_RUNTIME_ERROR_SET_FAILED,
211
0
       "%s: unable to calculate recovery password hash.",
212
0
       function );
213
214
0
      goto on_error;
215
0
    }
216
0
    if( memory_set(
217
0
         binary_recovery_password,
218
0
         0,
219
0
         16 ) == NULL )
220
0
    {
221
0
      libcerror_error_set(
222
0
       error,
223
0
       LIBCERROR_ERROR_DOMAIN_MEMORY,
224
0
       LIBCERROR_MEMORY_ERROR_SET_FAILED,
225
0
       "%s: unable to clear binary recovery password.",
226
0
       function );
227
228
0
      goto on_error;
229
0
    }
230
0
  }
231
0
  return( result );
232
233
0
on_error:
234
0
  if( split_string != NULL )
235
0
  {
236
0
    libfvalue_split_utf8_string_free(
237
0
     &split_string,
238
0
     NULL );
239
0
  }
240
0
  memory_set(
241
0
   binary_recovery_password,
242
0
   0,
243
0
   16 );
244
245
0
  return( -1 );
246
0
}
247
248
/* Calculates the SHA256 hash of an UTF-16 formatted recovery password
249
 * Returns 1 if successful, 0 if recovery password is invalid or -1 on error
250
 */
251
int libbde_utf16_recovery_password_calculate_hash(
252
     const uint16_t *utf16_string,
253
     size_t utf16_string_length,
254
     uint8_t *recovery_password_hash,
255
     size_t recovery_password_hash_size,
256
     libcerror_error_t **error )
257
0
{
258
0
  uint8_t binary_recovery_password[ 16 ];
259
260
0
  libfvalue_split_utf16_string_t *split_string = NULL;
261
0
  uint16_t *string_segment                     = NULL;
262
0
  static char *function                        = "libbde_utf16_recovery_password_calculate_hash";
263
0
  size_t string_segment_index                  = 0;
264
0
  size_t string_segment_size                   = 0;
265
0
  uint64_t value_64bit                         = 0;
266
0
  int number_of_segments                       = 0;
267
0
  int result                                   = 0;
268
0
  int segment_index                            = 0;
269
270
0
  if( recovery_password_hash == NULL )
271
0
  {
272
0
    libcerror_error_set(
273
0
     error,
274
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
275
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
276
0
     "%s: invalid recovery password hash.",
277
0
     function );
278
279
0
    return( -1 );
280
0
  }
281
0
  if( recovery_password_hash_size != 32 )
282
0
  {
283
0
    libcerror_error_set(
284
0
     error,
285
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
286
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
287
0
     "%s: recovery password hash size value out of bounds.",
288
0
     function );
289
290
0
    return( -1 );
291
0
  }
292
0
  if( libfvalue_utf16_string_split(
293
0
       utf16_string,
294
0
       utf16_string_length + 1,
295
0
       (uint16_t) '-',
296
0
       &split_string,
297
0
       error ) != 1 )
298
0
  {
299
0
    libcerror_error_set(
300
0
     error,
301
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
302
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
303
0
     "%s: unable to split string.",
304
0
     function );
305
306
0
    goto on_error;
307
0
  }
308
0
  if( libfvalue_split_utf16_string_get_number_of_segments(
309
0
       split_string,
310
0
       &number_of_segments,
311
0
       error ) != 1 )
312
0
  {
313
0
    libcerror_error_set(
314
0
     error,
315
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
316
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
317
0
     "%s: unable to retrieve number of segments in split string.",
318
0
     function );
319
320
0
    goto on_error;
321
0
  }
322
  /* The recovery password consists of 8 segments
323
   */
324
0
  if( number_of_segments == 8 )
325
0
  {
326
0
    for( segment_index = 0;
327
0
         segment_index < number_of_segments;
328
0
         segment_index++ )
329
0
    {
330
0
      if( libfvalue_split_utf16_string_get_segment_by_index(
331
0
           split_string,
332
0
           segment_index,
333
0
           &string_segment,
334
0
           &string_segment_size,
335
0
           error ) != 1 )
336
0
      {
337
0
        libcerror_error_set(
338
0
         error,
339
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
340
0
         LIBCERROR_RUNTIME_ERROR_GET_FAILED,
341
0
         "%s: unable to retrieve segment: %d from split string.",
342
0
         function,
343
0
         segment_index );
344
345
0
        goto on_error;
346
0
      }
347
0
      string_segment_index = 0;
348
349
0
      if( libfvalue_utf16_string_with_index_copy_to_integer(
350
0
           string_segment,
351
0
           string_segment_size,
352
0
           &string_segment_index,
353
0
           &value_64bit,
354
0
           16,
355
0
           LIBFVALUE_INTEGER_FORMAT_TYPE_DECIMAL_UNSIGNED,
356
0
           error ) != 1 )
357
0
      {
358
0
        libcerror_error_set(
359
0
         error,
360
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
361
0
         LIBCERROR_RUNTIME_ERROR_GET_FAILED,
362
0
         "%s: unable to determine binary value for segment: %d from split string.",
363
0
         function,
364
0
         segment_index );
365
366
0
        goto on_error;
367
0
      }
368
      /* A recovery password segment should be dividable by 11
369
       */
370
0
      if( ( value_64bit % 11 ) != 0 )
371
0
      {
372
0
        break;
373
0
      }
374
0
      value_64bit /= 11;
375
376
      /* A recovery password segment / 11 should be <= 65535 (0xffff)
377
       */
378
0
      if( value_64bit > (uint64_t) UINT16_MAX )
379
0
      {
380
0
        break;
381
0
      }
382
0
      byte_stream_copy_from_uint16_little_endian(
383
0
       &( binary_recovery_password[ segment_index * 2 ] ),
384
0
       value_64bit );
385
0
    }
386
0
    result = 1;
387
0
  }
388
0
  if( libfvalue_split_utf16_string_free(
389
0
       &split_string,
390
0
       error ) != 1 )
391
0
  {
392
0
    libcerror_error_set(
393
0
     error,
394
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
395
0
     LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
396
0
     "%s: unable to free split string.",
397
0
     function );
398
399
0
    goto on_error;
400
0
  }
401
0
  if( result == 1 )
402
0
  {
403
#if defined( HAVE_DEBUG_OUTPUT )
404
    if( libcnotify_verbose != 0 )
405
    {
406
      libcnotify_printf(
407
       "%s: binary recovery password:\n",
408
       function );
409
      libcnotify_print_data(
410
       binary_recovery_password,
411
       16,
412
       0 );
413
    }
414
#endif
415
0
    if( libhmac_sha256_calculate(
416
0
         binary_recovery_password,
417
0
         16,
418
0
         recovery_password_hash,
419
0
         recovery_password_hash_size,
420
0
         error ) != 1 )
421
0
    {
422
0
      libcerror_error_set(
423
0
       error,
424
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
425
0
       LIBCERROR_RUNTIME_ERROR_SET_FAILED,
426
0
       "%s: unable to calculate recovery password hash.",
427
0
       function );
428
429
0
      goto on_error;
430
0
    }
431
0
    if( memory_set(
432
0
         binary_recovery_password,
433
0
         0,
434
0
         16 ) == NULL )
435
0
    {
436
0
      libcerror_error_set(
437
0
       error,
438
0
       LIBCERROR_ERROR_DOMAIN_MEMORY,
439
0
       LIBCERROR_MEMORY_ERROR_SET_FAILED,
440
0
       "%s: unable to clear binary recovery password.",
441
0
       function );
442
443
0
      goto on_error;
444
0
    }
445
0
  }
446
0
  return( result );
447
448
0
on_error:
449
0
  if( split_string != NULL )
450
0
  {
451
0
    libfvalue_split_utf16_string_free(
452
0
     &split_string,
453
0
     NULL );
454
0
  }
455
0
  memory_set(
456
0
   binary_recovery_password,
457
0
   0,
458
0
   16 );
459
460
0
  return( -1 );
461
0
}
462