Coverage Report

Created: 2025-06-13 07:22

/src/libregf/libregf/libregf_checksum.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Checksum functions
3
 *
4
 * Copyright (C) 2009-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 <types.h>
25
26
#include "libregf_checksum.h"
27
#include "libregf_libcerror.h"
28
29
/* The largest primary (or scalar) available
30
 * supported by a single load and store instruction
31
 */
32
typedef unsigned long int libregf_aligned_t;
33
34
/* Calculates the little-endian XOR-32 of a buffer
35
 * It uses the initial value to calculate a new XOR-32
36
 * Returns 1 if successful or -1 on error
37
 */
38
int libregf_checksum_calculate_little_endian_xor32(
39
     uint32_t *checksum_value,
40
     const uint8_t *buffer,
41
     size_t size,
42
     uint32_t initial_value,
43
     libcerror_error_t **error )
44
3.71k
{
45
3.71k
  libregf_aligned_t *aligned_buffer_iterator = NULL;
46
3.71k
  uint8_t *buffer_iterator                   = NULL;
47
3.71k
  static char *function                      = "libregf_checksum_calculate_little_endian_xor32";
48
3.71k
  libregf_aligned_t value_aligned            = 0;
49
3.71k
  uint32_t big_endian_value_32bit            = 0;
50
3.71k
  uint32_t safe_checksum_value               = 0;
51
3.71k
  uint32_t value_32bit                       = 0;
52
3.71k
  uint8_t alignment_count                    = 0;
53
3.71k
  uint8_t alignment_size                     = 0;
54
3.71k
  uint8_t byte_count                         = 0;
55
3.71k
  uint8_t byte_order                         = 0;
56
3.71k
  uint8_t byte_size                          = 0;
57
58
3.71k
  if( checksum_value == NULL )
59
0
  {
60
0
    libcerror_error_set(
61
0
     error,
62
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
63
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
64
0
     "%s: invalid checksum value.",
65
0
     function );
66
67
0
    return( -1 );
68
0
  }
69
3.71k
  if( buffer == NULL )
70
0
  {
71
0
    libcerror_error_set(
72
0
     error,
73
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
74
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
75
0
     "%s: invalid buffer.",
76
0
     function );
77
78
0
    return( -1 );
79
0
  }
80
3.71k
  if( size > (size_t) SSIZE_MAX )
81
0
  {
82
0
    libcerror_error_set(
83
0
     error,
84
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
85
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
86
0
     "%s: invalid size value exceeds maximum.",
87
0
     function );
88
89
0
    return( -1 );
90
0
  }
91
3.71k
  safe_checksum_value = initial_value;
92
93
3.71k
  buffer_iterator = (uint8_t *) buffer;
94
95
  /* Only optimize when there is the alignment is a multitude of 32-bit
96
   * and for buffers larger than the alignment
97
   */
98
3.71k
  if( ( ( sizeof( libregf_aligned_t ) % 4 ) == 0 )
99
3.71k
   && ( size > ( 2 * sizeof( libregf_aligned_t ) ) ) )
100
3.71k
  {
101
    /* Align the buffer iterator
102
     */
103
3.71k
    alignment_size = (uint8_t) ( (intptr_t) buffer_iterator % sizeof( libregf_aligned_t ) );
104
105
3.71k
    if( alignment_size > 0 )
106
0
    {
107
0
      byte_size = sizeof( libregf_aligned_t ) - alignment_size;
108
109
      /* Align the buffer iterator in 4-byte steps
110
       */
111
0
      while( byte_size != 0 )
112
0
      {
113
0
        value_32bit = 0;
114
0
        byte_count  = 1;
115
116
0
        if( byte_size >= 4 )
117
0
        {
118
0
          value_32bit |= buffer_iterator[ 3 ];
119
0
          value_32bit <<= 8;
120
121
0
          byte_count++;
122
0
        }
123
0
        if( byte_size >= 3 )
124
0
        {
125
0
          value_32bit |= buffer_iterator[ 2 ];
126
0
          value_32bit <<= 8;
127
128
0
          byte_count++;
129
0
        }
130
0
        if( byte_size >= 2 )
131
0
        {
132
0
          value_32bit |= buffer_iterator[ 1 ];
133
0
          value_32bit <<= 8;
134
135
0
          byte_count++;
136
0
        }
137
0
        value_32bit |= buffer_iterator[ 0 ];
138
139
0
        buffer_iterator += byte_count;
140
0
        byte_size       -= byte_count;
141
142
0
        safe_checksum_value ^= value_32bit;
143
0
      }
144
0
      size -= byte_count;
145
0
    }
146
3.71k
    aligned_buffer_iterator = (libregf_aligned_t *) buffer_iterator;
147
148
3.71k
    if( *buffer_iterator != (uint8_t) ( *aligned_buffer_iterator & 0xff ) )
149
0
    {
150
0
      byte_order = _BYTE_STREAM_ENDIAN_BIG;
151
0
    }
152
3.71k
    else
153
3.71k
    {
154
3.71k
      byte_order = _BYTE_STREAM_ENDIAN_LITTLE;
155
3.71k
    }
156
    /* Calculate the XOR value using the aligned buffer iterator
157
     */
158
237k
    while( size > sizeof( libregf_aligned_t ) )
159
234k
    {
160
234k
      value_aligned ^= *aligned_buffer_iterator;
161
162
234k
      aligned_buffer_iterator++;
163
164
234k
      size -= sizeof( libregf_aligned_t );
165
234k
    }
166
    /* Align the aligned XOR value with the 32-bit XOR value
167
     */
168
3.71k
    if( alignment_size > 0 )
169
0
    {
170
0
      byte_count      = ( alignment_size % 4 ) * 8;
171
0
      alignment_count = ( sizeof( libregf_aligned_t ) - alignment_size ) * 8;
172
173
0
      if( byte_order == _BYTE_STREAM_ENDIAN_BIG )
174
0
      {
175
        /* Shift twice to set unused bytes to 0
176
         */
177
0
        big_endian_value_32bit = (uint32_t) ( ( value_aligned >> alignment_count ) << byte_count );
178
179
        /* Change big-endian into little-endian
180
         */
181
0
        value_32bit = ( ( big_endian_value_32bit & 0x000000ffUL ) << 24 )
182
0
                    | ( ( big_endian_value_32bit & 0x0000ff00UL ) << 8 )
183
0
                    | ( ( big_endian_value_32bit >> 8 ) & 0x0000ff00UL )
184
0
                    | ( ( big_endian_value_32bit >> 24 ) & 0x000000ffUL );
185
186
        /* Strip-off the used part of the aligned value
187
         */
188
0
        value_aligned <<= alignment_count;
189
0
      }
190
0
      else if( byte_order == _BYTE_STREAM_ENDIAN_LITTLE )
191
0
      {
192
0
        value_32bit = (uint32_t) ( value_aligned << byte_count );
193
194
        /* Strip-off the used part of the aligned value
195
         */
196
0
        value_aligned >>= alignment_count;
197
0
      }
198
0
      safe_checksum_value ^= value_32bit;
199
0
    }
200
    /* Update the 32-bit XOR value with the aligned XOR value
201
     */
202
3.71k
    byte_size = (uint8_t) sizeof( libregf_aligned_t );
203
204
11.1k
    while( byte_size != 0 )
205
7.43k
    {
206
7.43k
      byte_count = ( ( byte_size / 4 ) - 1 ) * 32;
207
208
7.43k
      if( byte_order == _BYTE_STREAM_ENDIAN_BIG )
209
0
      {
210
0
        big_endian_value_32bit = (uint32_t) ( ( value_aligned >> byte_count ) & 0xffffffffUL );
211
212
        /* Change big-endian into little-endian
213
         */
214
0
        value_32bit = ( ( big_endian_value_32bit & 0x000000ffUL ) << 24 )
215
0
                    | ( ( big_endian_value_32bit & 0x0000ff00UL ) << 8 )
216
0
                    | ( ( big_endian_value_32bit >> 8 ) & 0x0000ff00UL )
217
0
                    | ( ( big_endian_value_32bit >> 24 ) & 0x000000ffUL );
218
0
      }
219
7.43k
      else if( byte_order == _BYTE_STREAM_ENDIAN_LITTLE )
220
7.43k
      {
221
7.43k
        value_32bit = (uint32_t) value_aligned;
222
223
7.43k
        value_aligned >>= byte_count;
224
7.43k
      }
225
7.43k
      byte_size -= 4;
226
227
7.43k
      safe_checksum_value ^= value_32bit;
228
7.43k
    }
229
    /* Re-align the buffer iterator
230
     */
231
3.71k
    buffer_iterator = (uint8_t *) aligned_buffer_iterator;
232
233
3.71k
    byte_size = 4 - ( alignment_size % 4 );
234
235
3.71k
    if( byte_size != 4 )
236
0
    {
237
0
      value_32bit   = buffer_iterator[ 0 ];
238
0
      value_32bit <<= 8;
239
240
0
      if( byte_size >= 2 )
241
0
      {
242
0
        value_32bit |= buffer_iterator[ 1 ];
243
0
      }
244
0
      value_32bit <<= 8;
245
246
0
      if( byte_size >= 3 )
247
0
      {
248
0
        value_32bit |= buffer_iterator[ 2 ];
249
0
      }
250
0
      value_32bit <<= 8;
251
252
0
      buffer_iterator += byte_size;
253
0
      size            -= byte_size;
254
255
0
      safe_checksum_value ^= value_32bit;
256
0
    }
257
3.71k
  }
258
7.43k
  while( size > 0 )
259
3.71k
  {
260
3.71k
    value_32bit = 0;
261
3.71k
    byte_count  = 1;
262
263
3.71k
    if( size >= 4 )
264
3.71k
    {
265
3.71k
      value_32bit |= buffer_iterator[ 3 ];
266
3.71k
      value_32bit <<= 8;
267
268
3.71k
      byte_count++;
269
3.71k
    }
270
3.71k
    if( size >= 3 )
271
3.71k
    {
272
3.71k
      value_32bit |= buffer_iterator[ 2 ];
273
3.71k
      value_32bit <<= 8;
274
275
3.71k
      byte_count++;
276
3.71k
    }
277
3.71k
    if( size >= 2 )
278
3.71k
    {
279
3.71k
      value_32bit |= buffer_iterator[ 1 ];
280
3.71k
      value_32bit <<= 8;
281
282
3.71k
      byte_count++;
283
3.71k
    }
284
3.71k
    value_32bit |= buffer_iterator[ 0 ];
285
286
3.71k
    buffer_iterator += byte_count;
287
3.71k
    size            -= byte_count;
288
289
3.71k
    safe_checksum_value ^= value_32bit;
290
3.71k
  }
291
3.71k
  *checksum_value = safe_checksum_value;
292
293
3.71k
  return( 1 );
294
3.71k
}
295