Coverage Report

Created: 2024-02-25 07:20

/src/libfsapfs/libfsapfs/libfsapfs_password.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Password functions
3
 *
4
 * Copyright (C) 2018-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 "libfsapfs_definitions.h"
28
#include "libfsapfs_libcerror.h"
29
#include "libfsapfs_libcnotify.h"
30
#include "libfsapfs_libhmac.h"
31
#include "libfsapfs_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 libfsapfs_password_pbkdf2(
37
     const uint8_t *password,
38
     size_t password_size,
39
     const uint8_t *salt,
40
     size_t salt_size,
41
     uint32_t number_of_iterations,
42
     uint8_t *output_data,
43
     size_t output_data_size,
44
     libcerror_error_t **error )
45
0
{
46
0
  uint8_t hash_buffer[ LIBHMAC_SHA256_HASH_SIZE ];
47
48
0
  uint8_t *data_buffer       = NULL;
49
0
  uint8_t *output_ptr        = NULL;
50
0
  static char *function      = "libfsapfs_password_pbkdf2";
51
0
  size_t block_offset        = 0;
52
0
  size_t data_buffer_size    = 0;
53
0
  size_t hash_size           = LIBHMAC_SHA256_HASH_SIZE;
54
0
  size_t remaining_data_size = 0;
55
0
  uint32_t block_index       = 0;
56
0
  uint32_t byte_index        = 0;
57
0
  uint32_t number_of_blocks  = 0;
58
0
  uint32_t password_iterator = 0;
59
0
  int result                 = 0;
60
61
0
  if( password == NULL )
62
0
  {
63
0
    libcerror_error_set(
64
0
     error,
65
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
66
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
67
0
     "%s: invalid password.",
68
0
     function );
69
70
0
    return( -1 );
71
0
  }
72
0
  if( password_size > (size_t) SSIZE_MAX )
73
0
  {
74
0
    libcerror_error_set(
75
0
     error,
76
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
77
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
78
0
     "%s: invalid password size value exceeds maximum.",
79
0
     function );
80
81
0
    return( -1 );
82
0
  }
83
0
  if( salt == NULL )
84
0
  {
85
0
    libcerror_error_set(
86
0
     error,
87
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
88
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
89
0
     "%s: invalid salt.",
90
0
     function );
91
92
0
    return( -1 );
93
0
  }
94
0
  if( salt_size > (size_t) SSIZE_MAX )
95
0
  {
96
0
    libcerror_error_set(
97
0
     error,
98
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
99
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
100
0
     "%s: invalid salt size value exceeds maximum.",
101
0
     function );
102
103
0
    return( -1 );
104
0
  }
105
0
  if( number_of_iterations == 0 )
106
0
  {
107
0
    libcerror_error_set(
108
0
     error,
109
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
110
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_ZERO_OR_LESS,
111
0
     "%s: invalid number of iterations value zero or less.",
112
0
     function );
113
114
0
    return( -1 );
115
0
  }
116
0
  if( output_data == NULL )
117
0
  {
118
0
    libcerror_error_set(
119
0
     error,
120
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
121
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
122
0
     "%s: invalid output data.",
123
0
     function );
124
125
0
    return( -1 );
126
0
  }
127
0
  if( output_data_size > (size_t) SSIZE_MAX )
128
0
  {
129
0
    libcerror_error_set(
130
0
     error,
131
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
132
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
133
0
     "%s: invalid output data size value exceeds maximum.",
134
0
     function );
135
136
0
    return( -1 );
137
0
  }
138
0
  if( memory_set(
139
0
       output_data,
140
0
       0,
141
0
       output_data_size ) == NULL )
142
0
  {
143
0
    libcerror_error_set(
144
0
     error,
145
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
146
0
     LIBCERROR_MEMORY_ERROR_COPY_FAILED,
147
0
     "%s: unable to clear output data.",
148
0
     function );
149
150
0
    goto on_error;
151
0
  }
152
/* TODO add bounds check */
153
0
  number_of_blocks    = output_data_size / hash_size;
154
0
  remaining_data_size = output_data_size - ( number_of_blocks * hash_size );
155
0
  data_buffer_size    = salt_size + 4;
156
157
0
  if( data_buffer_size > (size64_t) MEMORY_MAXIMUM_ALLOCATION_SIZE )
158
0
  {
159
0
    libcerror_error_set(
160
0
     error,
161
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
162
0
     LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
163
0
     "%s: invalid data buffer size value exceeds maximum allocation size.",
164
0
     function );
165
166
0
    goto on_error;
167
0
  }
168
0
  data_buffer = (uint8_t *) memory_allocate(
169
0
                             sizeof( uint8_t ) * data_buffer_size );
170
171
0
  if( data_buffer == NULL )
172
0
  {
173
0
    libcerror_error_set(
174
0
     error,
175
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
176
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
177
0
     "%s: unable to create data buffer.",
178
0
     function );
179
180
0
    goto on_error;
181
0
  }
182
0
  if( memory_set(
183
0
       data_buffer,
184
0
       0,
185
0
       data_buffer_size ) == NULL )
186
0
  {
187
0
    libcerror_error_set(
188
0
     error,
189
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
190
0
     LIBCERROR_MEMORY_ERROR_COPY_FAILED,
191
0
     "%s: unable to clear data buffer.",
192
0
     function );
193
194
0
    goto on_error;
195
0
  }
196
0
  if( memory_copy(
197
0
       data_buffer,
198
0
       salt,
199
0
       salt_size ) == NULL)
200
0
  {
201
0
    libcerror_error_set(
202
0
     error,
203
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
204
0
     LIBCERROR_MEMORY_ERROR_COPY_FAILED,
205
0
     "%s: unable to copy salt into data buffer.",
206
0
     function );
207
208
0
    goto on_error;
209
0
  }
210
#if defined( HAVE_DEBUG_OUTPUT )
211
  if( libcnotify_verbose != 0 )
212
  {
213
    libcnotify_printf(
214
     "%s: password:\n",
215
     function );
216
    libcnotify_print_data(
217
     password,
218
     password_size,
219
     0 );
220
221
    libcnotify_printf(
222
     "%s: data buffer:\n",
223
     function );
224
    libcnotify_print_data(
225
     data_buffer,
226
     data_buffer_size,
227
     0 );
228
229
    libcnotify_printf(
230
     "%s: number of iterations\t\t\t\t: %" PRIu32 "\n",
231
     function,
232
     number_of_iterations );
233
234
    libcnotify_printf(
235
     "%s: number of blocks\t\t\t\t: %" PRIu32 "\n",
236
     function,
237
     number_of_blocks );
238
239
    libcnotify_printf(
240
     "%s: remaining data size\t\t\t\t: %" PRIzd "\n",
241
     function,
242
     remaining_data_size );
243
244
    libcnotify_printf(
245
     "\n" );
246
  }
247
#endif
248
0
  for( block_index = 0;
249
0
       block_index < number_of_blocks;
250
0
       block_index++ )
251
0
  {
252
0
    output_ptr = &( output_data[ block_offset ] );
253
254
0
    byte_stream_copy_from_uint32_big_endian(
255
0
     &( data_buffer[ salt_size ] ),
256
0
     block_index + 1 );
257
258
0
                result = libhmac_sha256_calculate_hmac(
259
0
              password,
260
0
              password_size,
261
0
              data_buffer,
262
0
              data_buffer_size,
263
0
              hash_buffer,
264
0
              hash_size,
265
0
              error );
266
267
0
    if( result != 1 )
268
0
    {
269
0
      libcerror_error_set(
270
0
       error,
271
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
272
0
       LIBCERROR_RUNTIME_ERROR_GENERIC,
273
0
       "%s: unable to compute initial hmac for block %d.",
274
0
       function,
275
0
       block_index );
276
277
0
      goto on_error;
278
0
    }
279
0
    if( memory_copy(
280
0
         output_ptr,
281
0
         hash_buffer,
282
0
         hash_size ) == NULL )
283
0
    {
284
0
      libcerror_error_set(
285
0
       error,
286
0
       LIBCERROR_ERROR_DOMAIN_MEMORY,
287
0
       LIBCERROR_MEMORY_ERROR_COPY_FAILED,
288
0
       "%s: unable to copy hash buffer into output data.",
289
0
       function );
290
291
0
      goto on_error;
292
0
    }
293
0
    for( password_iterator = 0;
294
0
         password_iterator < number_of_iterations - 1;
295
0
         password_iterator++ )
296
0
    {
297
0
      result = libhmac_sha256_calculate_hmac(
298
0
                password,
299
0
                password_size,
300
0
                hash_buffer,
301
0
                hash_size,
302
0
                hash_buffer,
303
0
                hash_size,
304
0
                error );
305
306
0
      if( result != 1 )
307
0
      {
308
0
        libcerror_error_set(
309
0
         error,
310
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
311
0
         LIBCERROR_RUNTIME_ERROR_GENERIC,
312
0
         "%s: unable to compute initial hmac for block %d.",
313
0
         function,
314
0
         block_index);
315
316
0
        goto on_error;
317
0
      }
318
0
      for( byte_index = 0;
319
0
           byte_index < hash_size;
320
0
           byte_index++ )
321
0
      {
322
0
        output_ptr[ byte_index ] ^= hash_buffer[ byte_index ];
323
0
      }
324
0
    }
325
0
    block_offset += hash_size;
326
0
  }
327
0
  if( remaining_data_size > 0 )
328
0
  {
329
0
    output_ptr = &( output_data[ block_offset ] );
330
331
0
    byte_stream_copy_from_uint32_big_endian(
332
0
     &( data_buffer[ salt_size ] ),
333
0
     block_index + 1 );
334
335
0
    result = libhmac_sha256_calculate_hmac(
336
0
              password,
337
0
              password_size,
338
0
              data_buffer,
339
0
              data_buffer_size,
340
0
              hash_buffer,
341
0
              hash_size,
342
0
              error );
343
344
0
    if( result != 1 )
345
0
    {
346
0
      libcerror_error_set(
347
0
       error,
348
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
349
0
       LIBCERROR_RUNTIME_ERROR_GENERIC,
350
0
       "%s: unable to compute initial hmac for block %d.",
351
0
       function,
352
0
       block_index);
353
354
0
      goto on_error;
355
0
    }
356
0
    if( memory_copy(
357
0
         output_ptr,
358
0
         hash_buffer,
359
0
         remaining_data_size ) == NULL )
360
0
    {
361
0
      libcerror_error_set(
362
0
       error,
363
0
       LIBCERROR_ERROR_DOMAIN_MEMORY,
364
0
       LIBCERROR_MEMORY_ERROR_COPY_FAILED,
365
0
       "%s: unable to copy hash buffer into output data in last block.",
366
0
       function );
367
368
0
      goto on_error;
369
0
    }
370
0
    for( password_iterator = 0;
371
0
         password_iterator < number_of_iterations - 1;
372
0
         password_iterator++ )
373
0
    {
374
0
      result = libhmac_sha256_calculate_hmac(
375
0
                password,
376
0
                password_size,
377
0
                hash_buffer,
378
0
                hash_size,
379
0
                hash_buffer,
380
0
                hash_size,
381
0
                error );
382
383
0
      if( result != 1 )
384
0
      {
385
0
        libcerror_error_set(
386
0
         error,
387
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
388
0
         LIBCERROR_RUNTIME_ERROR_GENERIC,
389
0
         "%s: unable to compute initial hmac for block %d.",
390
0
         function,
391
0
         block_index );
392
393
0
        goto on_error;
394
0
      }
395
0
      for( byte_index = 0;
396
0
           byte_index < remaining_data_size;
397
0
           byte_index++ )
398
0
      {
399
0
        output_ptr[ byte_index ] ^= hash_buffer[ byte_index ];
400
0
      }
401
0
    }
402
0
  }
403
0
  if( data_buffer != NULL )
404
0
  {
405
0
    memory_free(
406
0
     data_buffer );
407
0
  }
408
0
  return( 1 );
409
410
0
on_error:
411
0
  if( data_buffer != NULL )
412
0
  {
413
0
    memory_free(
414
0
     data_buffer );
415
0
  }
416
0
  return( -1 );
417
0
}
418