Coverage Report

Created: 2023-06-07 06:53

/src/libbde/libbde/libbde_password.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Password functions
3
 *
4
 * Copyright (C) 2011-2023, 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_libhmac.h"
30
#include "libbde_libuna.h"
31
#include "libbde_password.h"
32
33
/* Calculates the SHA256 hash of an UTF-8 formatted password
34
 * Returns 1 if successful or -1 on error
35
 */
36
int libbde_utf8_password_calculate_hash(
37
     const uint8_t *utf8_string,
38
     size_t utf8_string_length,
39
     uint8_t *password_hash,
40
     size_t password_hash_size,
41
     libcerror_error_t **error )
42
0
{
43
0
  uint8_t *utf16_stream    = NULL;
44
0
  static char *function    = "libbde_utf8_password_calculate_hash";
45
0
  size_t utf16_stream_size = 0;
46
47
0
  if( password_hash == NULL )
48
0
  {
49
0
    libcerror_error_set(
50
0
     error,
51
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
52
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
53
0
     "%s: invalid password hash.",
54
0
     function );
55
56
0
    return( -1 );
57
0
  }
58
0
  if( password_hash_size != 32 )
59
0
  {
60
0
    libcerror_error_set(
61
0
     error,
62
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
63
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
64
0
     "%s: password hash size value out of bounds.",
65
0
     function );
66
67
0
    return( -1 );
68
0
  }
69
0
  if( libuna_utf16_stream_size_from_utf8(
70
0
       utf8_string,
71
0
       utf8_string_length,
72
0
       &utf16_stream_size,
73
0
       error ) != 1 )
74
0
  {
75
0
    libcerror_error_set(
76
0
     error,
77
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
78
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
79
0
     "%s: unable to determine UTF-16 stream size.",
80
0
     function );
81
82
0
    goto on_error;
83
0
  }
84
0
  if( ( utf16_stream_size == 0 )
85
0
   || ( utf16_stream_size > MEMORY_MAXIMUM_ALLOCATION_SIZE ) )
86
0
  {
87
0
    libcerror_error_set(
88
0
     error,
89
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
90
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
91
0
     "%s: invalid UTF-16 stream size value out of bounds.",
92
0
     function );
93
94
0
    goto on_error;
95
0
  }
96
0
  utf16_stream = (uint8_t *) memory_allocate(
97
0
                              sizeof( uint8_t ) * utf16_stream_size );
98
99
0
  if( utf16_stream == NULL )
100
0
  {
101
0
    libcerror_error_set(
102
0
     error,
103
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
104
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
105
0
     "%s: unable to create UTF-16 stream.",
106
0
     function );
107
108
0
    goto on_error;
109
0
  }
110
0
  if( libuna_utf16_stream_copy_from_utf8(
111
0
       utf16_stream,
112
0
       utf16_stream_size,
113
0
       LIBUNA_ENDIAN_LITTLE,
114
0
       utf8_string,
115
0
       utf8_string_length,
116
0
       error ) != 1 )
117
0
  {
118
0
    libcerror_error_set(
119
0
     error,
120
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
121
0
     LIBCERROR_RUNTIME_ERROR_COPY_FAILED,
122
0
     "%s: unable to copy UTF-8 string to UTF-16 stream size.",
123
0
     function );
124
125
0
    goto on_error;
126
0
  }
127
#if defined( HAVE_DEBUG_OUTPUT )
128
    if( libcnotify_verbose != 0 )
129
    {
130
      libcnotify_printf(
131
       "%s: password:\n",
132
       function );
133
      libcnotify_print_data(
134
       utf16_stream,
135
       utf16_stream_size,
136
       0 );
137
    }
138
#endif
139
  /* Ignore the byte-order mark in the UTF16 stream
140
   */
141
0
  if( libhmac_sha256_calculate(
142
0
       &( utf16_stream[ 2 ] ),
143
0
       utf16_stream_size - 2,
144
0
       password_hash,
145
0
       password_hash_size,
146
0
       error ) != 1 )
147
0
  {
148
0
    libcerror_error_set(
149
0
     error,
150
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
151
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
152
0
     "%s: unable to calculate password hash.",
153
0
     function );
154
155
0
    goto on_error;
156
0
  }
157
0
  if( libhmac_sha256_calculate(
158
0
       password_hash,
159
0
       password_hash_size,
160
0
       password_hash,
161
0
       password_hash_size,
162
0
       error ) != 1 )
163
0
  {
164
0
    libcerror_error_set(
165
0
     error,
166
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
167
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
168
0
     "%s: unable to calculate password hash.",
169
0
     function );
170
171
0
    goto on_error;
172
0
  }
173
0
  if( memory_set(
174
0
       utf16_stream,
175
0
       0,
176
0
       utf16_stream_size ) == NULL )
177
0
  {
178
0
    libcerror_error_set(
179
0
     error,
180
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
181
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
182
0
     "%s: unable to clear UTF-16 stream.",
183
0
     function );
184
185
0
    goto on_error;
186
0
  }
187
0
  memory_free(
188
0
   utf16_stream );
189
190
0
  return( 1 );
191
192
0
on_error:
193
0
  if( utf16_stream != NULL )
194
0
  {
195
0
    memory_set(
196
0
     utf16_stream,
197
0
     0,
198
0
     utf16_stream_size );
199
0
    memory_free(
200
0
     utf16_stream );
201
0
  }
202
0
  return( -1 );
203
0
}
204
205
/* Calculates the SHA256 hash of an UTF-16 formatted password
206
 * Returns 1 if successful, 0 if password is invalid or -1 on error
207
 */
208
int libbde_utf16_password_calculate_hash(
209
     const uint16_t *utf16_string,
210
     size_t utf16_string_length,
211
     uint8_t *password_hash,
212
     size_t password_hash_size,
213
     libcerror_error_t **error )
214
0
{
215
0
  uint8_t *utf16_stream    = NULL;
216
0
  static char *function    = "libbde_utf16_password_calculate_hash";
217
0
  size_t utf16_stream_size = 0;
218
219
0
  if( password_hash == NULL )
220
0
  {
221
0
    libcerror_error_set(
222
0
     error,
223
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
224
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
225
0
     "%s: invalid password hash.",
226
0
     function );
227
228
0
    return( -1 );
229
0
  }
230
0
  if( password_hash_size != 32 )
231
0
  {
232
0
    libcerror_error_set(
233
0
     error,
234
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
235
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
236
0
     "%s: password hash size value out of bounds.",
237
0
     function );
238
239
0
    return( -1 );
240
0
  }
241
0
  if( libuna_utf16_stream_size_from_utf16(
242
0
       utf16_string,
243
0
       utf16_string_length,
244
0
       &utf16_stream_size,
245
0
       error ) != 1 )
246
0
  {
247
0
    libcerror_error_set(
248
0
     error,
249
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
250
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
251
0
     "%s: unable to determine UTF-16 stream size.",
252
0
     function );
253
254
0
    goto on_error;
255
0
  }
256
0
  if( ( utf16_stream_size == 0 )
257
0
   || ( utf16_stream_size > MEMORY_MAXIMUM_ALLOCATION_SIZE ) )
258
0
  {
259
0
    libcerror_error_set(
260
0
     error,
261
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
262
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
263
0
     "%s: invalid UTF-16 stream size value out of bounds.",
264
0
     function );
265
266
0
    goto on_error;
267
0
  }
268
0
  utf16_stream = (uint8_t *) memory_allocate(
269
0
                              sizeof( uint8_t ) * utf16_stream_size );
270
271
0
  if( utf16_stream == NULL )
272
0
  {
273
0
    libcerror_error_set(
274
0
     error,
275
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
276
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
277
0
     "%s: unable to create UTF-16 stream.",
278
0
     function );
279
280
0
    goto on_error;
281
0
  }
282
0
  if( libuna_utf16_stream_copy_from_utf16(
283
0
       utf16_stream,
284
0
       utf16_stream_size,
285
0
       LIBUNA_ENDIAN_LITTLE,
286
0
       utf16_string,
287
0
       utf16_string_length,
288
0
       error ) != 1 )
289
0
  {
290
0
    libcerror_error_set(
291
0
     error,
292
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
293
0
     LIBCERROR_RUNTIME_ERROR_COPY_FAILED,
294
0
     "%s: unable to copy UTF-16 string to UTF-16 stream size.",
295
0
     function );
296
297
0
    goto on_error;
298
0
  }
299
  /* Ignore the byte-order mark in the UTF16 stream
300
   */
301
0
  if( libhmac_sha256_calculate(
302
0
       &( utf16_stream[ 2 ] ),
303
0
       utf16_stream_size - 2,
304
0
       password_hash,
305
0
       password_hash_size,
306
0
       error ) != 1 )
307
0
  {
308
0
    libcerror_error_set(
309
0
     error,
310
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
311
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
312
0
     "%s: unable to calculate password hash.",
313
0
     function );
314
315
0
    goto on_error;
316
0
  }
317
0
  if( libhmac_sha256_calculate(
318
0
       password_hash,
319
0
       password_hash_size,
320
0
       password_hash,
321
0
       password_hash_size,
322
0
       error ) != 1 )
323
0
  {
324
0
    libcerror_error_set(
325
0
     error,
326
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
327
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
328
0
     "%s: unable to calculate password hash.",
329
0
     function );
330
331
0
    goto on_error;
332
0
  }
333
0
  if( memory_set(
334
0
       utf16_stream,
335
0
       0,
336
0
       utf16_stream_size ) == NULL )
337
0
  {
338
0
    libcerror_error_set(
339
0
     error,
340
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
341
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
342
0
     "%s: unable to clear UTF-16 stream.",
343
0
     function );
344
345
0
    goto on_error;
346
0
  }
347
0
  memory_free(
348
0
   utf16_stream );
349
350
0
  return( 1 );
351
352
0
on_error:
353
0
  if( utf16_stream != NULL )
354
0
  {
355
0
    memory_set(
356
0
     utf16_stream,
357
0
     0,
358
0
     utf16_stream_size );
359
0
    memory_free(
360
0
     utf16_stream );
361
0
  }
362
0
  return( -1 );
363
0
}
364
365
/* Calculates the password key for a certain password and salt
366
 * Returns 1 if successful or -1 on error
367
 */
368
int libbde_password_calculate_key(
369
     const uint8_t *password_hash,
370
     size_t password_hash_size,
371
     const uint8_t *salt,
372
     size_t salt_size,
373
     uint8_t *key,
374
     size_t key_size,
375
     libcerror_error_t **error )
376
0
{
377
0
  libbde_password_key_data_t password_key_data;
378
379
0
  static char *function = "libbde_password_calculate_key";
380
381
0
  if( password_hash == NULL )
382
0
  {
383
0
    libcerror_error_set(
384
0
     error,
385
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
386
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
387
0
     "%s: invalid password hash.",
388
0
     function );
389
390
0
    return( -1 );
391
0
  }
392
0
  if( password_hash_size != 32 )
393
0
  {
394
0
    libcerror_error_set(
395
0
     error,
396
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
397
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
398
0
     "%s: password hash size value out of bounds.",
399
0
     function );
400
401
0
    return( -1 );
402
0
  }
403
0
  if( salt == NULL )
404
0
  {
405
0
    libcerror_error_set(
406
0
     error,
407
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
408
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
409
0
     "%s: invalid salt.",
410
0
     function );
411
412
0
    return( -1 );
413
0
  }
414
0
  if( salt_size != 16 )
415
0
  {
416
0
    libcerror_error_set(
417
0
     error,
418
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
419
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
420
0
     "%s: salt size value out of bounds.",
421
0
     function );
422
423
0
    return( -1 );
424
0
  }
425
0
  if( key == 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 key.",
432
0
     function );
433
434
0
    return( -1 );
435
0
  }
436
0
  if( key_size != 32 )
437
0
  {
438
0
    libcerror_error_set(
439
0
     error,
440
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
441
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
442
0
     "%s: key size value out of bounds.",
443
0
     function );
444
445
0
    return( -1 );
446
0
  }
447
0
  if( memory_set(
448
0
       &password_key_data,
449
0
       0,
450
0
       sizeof( libbde_password_key_data_t ) ) == NULL )
451
0
  {
452
0
    libcerror_error_set(
453
0
     error,
454
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
455
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
456
0
     "%s: unable to clear password key data.",
457
0
     function );
458
459
0
    return( -1 );
460
0
  }
461
0
  if( memory_copy(
462
0
       &( password_key_data.initial_sha256_hash ),
463
0
       password_hash,
464
0
       password_hash_size ) == NULL )
465
0
  {
466
0
    libcerror_error_set(
467
0
     error,
468
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
469
0
     LIBCERROR_MEMORY_ERROR_COPY_FAILED,
470
0
     "%s: unable to copy password hash to password key data.",
471
0
     function );
472
473
0
    return( -1 );
474
0
  }
475
0
  if( memory_copy(
476
0
       &( password_key_data.salt ),
477
0
       salt,
478
0
       salt_size ) == NULL )
479
0
  {
480
0
    libcerror_error_set(
481
0
     error,
482
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
483
0
     LIBCERROR_MEMORY_ERROR_COPY_FAILED,
484
0
     "%s: unable to copy salt to password key data.",
485
0
     function );
486
487
0
    return( -1 );
488
0
  }
489
  /* The password key is the SHA256 digest hash after 0x100000 key iterations
490
   */
491
0
  for( password_key_data.iteration_count = 0;
492
0
       password_key_data.iteration_count < 0x000fffffUL;
493
0
       password_key_data.iteration_count += 1 )
494
0
  {
495
0
    if( libhmac_sha256_calculate(
496
0
         (uint8_t *) &password_key_data,
497
0
         sizeof( libbde_password_key_data_t ),
498
0
         password_key_data.last_sha256_hash,
499
0
         LIBHMAC_SHA256_HASH_SIZE,
500
0
         error ) != 1 )
501
0
    {
502
0
      libcerror_error_set(
503
0
       error,
504
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
505
0
       LIBCERROR_RUNTIME_ERROR_SET_FAILED,
506
0
       "%s: unable to calculate SHA256.",
507
0
       function );
508
509
0
      return( -1 );
510
0
    }
511
0
  }
512
0
  if( libhmac_sha256_calculate(
513
0
       (uint8_t *) &password_key_data,
514
0
       sizeof( libbde_password_key_data_t ),
515
0
       key,
516
0
       key_size,
517
0
       error ) != 1 )
518
0
  {
519
0
    libcerror_error_set(
520
0
     error,
521
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
522
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
523
0
     "%s: unable to calculate SHA256.",
524
0
     function );
525
526
0
    return( -1 );
527
0
  }
528
0
  return( 1 );
529
0
}
530