Coverage Report

Created: 2026-09-13 06:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cryptsetup/lib/luks1/af.c
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
 * AFsplitter - Anti forensic information splitter
4
 *
5
 * Copyright (C) 2004 Clemens Fruhwirth <clemens@endorphin.org>
6
 * Copyright (C) 2009-2026 Red Hat, Inc. All rights reserved.
7
 *
8
 * AFsplitter diffuses information over a large stripe of data,
9
 * therefore supporting secure data destruction.
10
 */
11
12
#include <stddef.h>
13
#include <stdint.h>
14
#include <stdlib.h>
15
#include <string.h>
16
#include <errno.h>
17
#include "internal.h"
18
#include "af.h"
19
20
static void XORblock(const char *src1, const char *src2, char *dst, size_t n)
21
0
{
22
0
  size_t j;
23
24
0
  for (j = 0; j < n; j++)
25
0
    dst[j] = src1[j] ^ src2[j];
26
0
}
27
28
static int hash_buf(const char *src, char *dst, uint32_t iv,
29
        size_t len, const char *hash_name)
30
0
{
31
0
  struct crypt_hash *hd = NULL;
32
0
  char *iv_char = (char *)&iv;
33
0
  int r;
34
35
0
  iv = be32_to_cpu(iv);
36
0
  if (crypt_hash_init(&hd, hash_name))
37
0
    return -EINVAL;
38
39
0
  if ((r = crypt_hash_write(hd, iv_char, sizeof(uint32_t))))
40
0
    goto out;
41
42
0
  if ((r = crypt_hash_write(hd, src, len)))
43
0
    goto out;
44
45
0
  r = crypt_hash_final(hd, dst, len);
46
0
out:
47
0
  crypt_hash_destroy(hd);
48
0
  return r;
49
0
}
50
51
/*
52
 * diffuse: Information spreading over the whole dataset with
53
 * the help of hash function.
54
 */
55
static int diffuse(char *src, char *dst, size_t size, const char *hash_name)
56
0
{
57
0
  int r, hash_size = crypt_hash_size(hash_name);
58
0
  unsigned int digest_size;
59
0
  unsigned int i, blocks, padding;
60
61
0
  if (hash_size <= 0)
62
0
    return -EINVAL;
63
0
  digest_size = hash_size;
64
65
0
  blocks = size / digest_size;
66
0
  padding = size % digest_size;
67
68
0
  for (i = 0; i < blocks; i++) {
69
0
    r = hash_buf(src + digest_size * i,
70
0
          dst + digest_size * i,
71
0
          i, (size_t)digest_size, hash_name);
72
0
    if (r < 0)
73
0
      return r;
74
0
  }
75
76
0
  if (padding) {
77
0
    r = hash_buf(src + digest_size * i,
78
0
          dst + digest_size * i,
79
0
          i, (size_t)padding, hash_name);
80
0
    if (r < 0)
81
0
      return r;
82
0
  }
83
84
0
  return 0;
85
0
}
86
87
/*
88
 * Information splitting. The amount of data is multiplied by
89
 * blocknumbers. The same blocksize and blocknumbers values
90
 * must be supplied to AF_merge to recover information.
91
 */
92
int AF_split(struct crypt_device *ctx, const char *src, char *dst,
93
       size_t blocksize, unsigned int blocknumbers, const char *hash)
94
0
{
95
0
  unsigned int i;
96
0
  char *bufblock;
97
0
  int r;
98
99
0
  bufblock = crypt_safe_alloc(blocksize);
100
0
  if (!bufblock)
101
0
    return -ENOMEM;
102
103
  /* process everything except the last block */
104
0
  for (i = 0; i < blocknumbers - 1; i++) {
105
0
    r = crypt_random_get(ctx, dst + blocksize * i, blocksize, CRYPT_RND_NORMAL);
106
0
    if (r < 0)
107
0
      goto out;
108
109
0
    XORblock(dst + blocksize * i, bufblock, bufblock, blocksize);
110
0
    r = diffuse(bufblock, bufblock, blocksize, hash);
111
0
    if (r < 0)
112
0
      goto out;
113
0
  }
114
  /* the last block is computed */
115
0
  XORblock(src, bufblock, dst + blocksize * i, blocksize);
116
0
  r = 0;
117
0
out:
118
0
  crypt_safe_free(bufblock);
119
0
  return r;
120
0
}
121
122
int AF_merge(const char *src, char *dst,
123
       size_t blocksize, unsigned int blocknumbers, const char *hash)
124
0
{
125
0
  unsigned int i;
126
0
  char *bufblock;
127
0
  int r;
128
129
0
  bufblock = crypt_safe_alloc(blocksize);
130
0
  if (!bufblock)
131
0
    return -ENOMEM;
132
133
0
  for (i = 0; i < blocknumbers - 1; i++) {
134
0
    XORblock(src + blocksize * i, bufblock, bufblock, blocksize);
135
0
    r = diffuse(bufblock, bufblock, blocksize, hash);
136
0
    if (r < 0)
137
0
      goto out;
138
0
  }
139
0
  XORblock(src + blocksize * i, bufblock, dst, blocksize);
140
0
  r = 0;
141
0
out:
142
0
  crypt_safe_free(bufblock);
143
0
  return r;
144
0
}
145
146
/* Size of final split data including sector alignment */
147
size_t AF_split_sectors(size_t blocksize, unsigned int blocknumbers)
148
0
{
149
0
  size_t af_size;
150
151
0
  if (!blocknumbers || blocksize >= (SIZE_MAX / blocknumbers))
152
0
    return 0;
153
154
  /* data material * stripes */
155
0
  af_size = blocksize * blocknumbers;
156
157
0
  if (af_size >= (SIZE_MAX - SECTOR_SIZE + 1))
158
0
    return 0;
159
160
  /* round up to sector */
161
0
  return (af_size + (SECTOR_SIZE - 1)) / SECTOR_SIZE;
162
0
}