Coverage Report

Created: 2025-10-12 06:56

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-2025 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 <stdlib.h>
14
#include <string.h>
15
#include <errno.h>
16
#include "internal.h"
17
#include "af.h"
18
19
static void XORblock(const char *src1, const char *src2, char *dst, size_t n)
20
0
{
21
0
  size_t j;
22
23
0
  for (j = 0; j < n; j++)
24
0
    dst[j] = src1[j] ^ src2[j];
25
0
}
26
27
static int hash_buf(const char *src, char *dst, uint32_t iv,
28
        size_t len, const char *hash_name)
29
0
{
30
0
  struct crypt_hash *hd = NULL;
31
0
  char *iv_char = (char *)&iv;
32
0
  int r;
33
34
0
  iv = be32_to_cpu(iv);
35
0
  if (crypt_hash_init(&hd, hash_name))
36
0
    return -EINVAL;
37
38
0
  if ((r = crypt_hash_write(hd, iv_char, sizeof(uint32_t))))
39
0
    goto out;
40
41
0
  if ((r = crypt_hash_write(hd, src, len)))
42
0
    goto out;
43
44
0
  r = crypt_hash_final(hd, dst, len);
45
0
out:
46
0
  crypt_hash_destroy(hd);
47
0
  return r;
48
0
}
49
50
/*
51
 * diffuse: Information spreading over the whole dataset with
52
 * the help of hash function.
53
 */
54
static int diffuse(char *src, char *dst, size_t size, const char *hash_name)
55
0
{
56
0
  int r, hash_size = crypt_hash_size(hash_name);
57
0
  unsigned int digest_size;
58
0
  unsigned int i, blocks, padding;
59
60
0
  if (hash_size <= 0)
61
0
    return -EINVAL;
62
0
  digest_size = hash_size;
63
64
0
  blocks = size / digest_size;
65
0
  padding = size % digest_size;
66
67
0
  for (i = 0; i < blocks; i++) {
68
0
    r = hash_buf(src + digest_size * i,
69
0
          dst + digest_size * i,
70
0
          i, (size_t)digest_size, hash_name);
71
0
    if (r < 0)
72
0
      return r;
73
0
  }
74
75
0
  if (padding) {
76
0
    r = hash_buf(src + digest_size * i,
77
0
          dst + digest_size * i,
78
0
          i, (size_t)padding, hash_name);
79
0
    if (r < 0)
80
0
      return r;
81
0
  }
82
83
0
  return 0;
84
0
}
85
86
/*
87
 * Information splitting. The amount of data is multiplied by
88
 * blocknumbers. The same blocksize and blocknumbers values
89
 * must be supplied to AF_merge to recover information.
90
 */
91
int AF_split(struct crypt_device *ctx, const char *src, char *dst,
92
       size_t blocksize, unsigned int blocknumbers, const char *hash)
93
0
{
94
0
  unsigned int i;
95
0
  char *bufblock;
96
0
  int r;
97
98
0
  bufblock = crypt_safe_alloc(blocksize);
99
0
  if (!bufblock)
100
0
    return -ENOMEM;
101
102
  /* process everything except the last block */
103
0
  for (i = 0; i < blocknumbers - 1; i++) {
104
0
    r = crypt_random_get(ctx, dst + blocksize * i, blocksize, CRYPT_RND_NORMAL);
105
0
    if (r < 0)
106
0
      goto out;
107
108
0
    XORblock(dst + blocksize * i, bufblock, bufblock, blocksize);
109
0
    r = diffuse(bufblock, bufblock, blocksize, hash);
110
0
    if (r < 0)
111
0
      goto out;
112
0
  }
113
  /* the last block is computed */
114
0
  XORblock(src, bufblock, dst + blocksize * i, blocksize);
115
0
  r = 0;
116
0
out:
117
0
  crypt_safe_free(bufblock);
118
0
  return r;
119
0
}
120
121
int AF_merge(const char *src, char *dst,
122
       size_t blocksize, unsigned int blocknumbers, const char *hash)
123
0
{
124
0
  unsigned int i;
125
0
  char *bufblock;
126
0
  int r;
127
128
0
  bufblock = crypt_safe_alloc(blocksize);
129
0
  if (!bufblock)
130
0
    return -ENOMEM;
131
132
0
  for (i = 0; i < blocknumbers - 1; i++) {
133
0
    XORblock(src + blocksize * i, bufblock, bufblock, blocksize);
134
0
    r = diffuse(bufblock, bufblock, blocksize, hash);
135
0
    if (r < 0)
136
0
      goto out;
137
0
  }
138
0
  XORblock(src + blocksize * i, bufblock, dst, blocksize);
139
0
  r = 0;
140
0
out:
141
0
  crypt_safe_free(bufblock);
142
0
  return r;
143
0
}
144
145
/* Size of final split data including sector alignment */
146
size_t AF_split_sectors(size_t blocksize, unsigned int blocknumbers)
147
690
{
148
690
  size_t af_size;
149
150
  /* data material * stripes */
151
690
  af_size = blocksize * blocknumbers;
152
153
  /* round up to sector */
154
690
  af_size = (af_size + (SECTOR_SIZE - 1)) / SECTOR_SIZE;
155
156
690
  return af_size;
157
690
}