Coverage Report

Created: 2024-05-21 06:33

/src/cryptsetup/lib/luks1/af.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * AFsplitter - Anti forensic information splitter
3
 *
4
 * Copyright (C) 2004 Clemens Fruhwirth <clemens@endorphin.org>
5
 * Copyright (C) 2009-2024 Red Hat, Inc. All rights reserved.
6
 *
7
 * AFsplitter diffuses information over a large stripe of data,
8
 * therefore supporting secure data destruction.
9
 *
10
 * This program is free software; you can redistribute it and/or
11
 * modify it under the terms of the GNU General Public License
12
 * as published by the Free Software Foundation; either version 2
13
 * of the License, or (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 * GNU Library General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU General Public License
21
 * along with this program; if not, write to the Free Software
22
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23
 */
24
25
#include <stddef.h>
26
#include <stdlib.h>
27
#include <string.h>
28
#include <errno.h>
29
#include "internal.h"
30
#include "af.h"
31
32
static void XORblock(const char *src1, const char *src2, char *dst, size_t n)
33
0
{
34
0
  size_t j;
35
36
0
  for (j = 0; j < n; j++)
37
0
    dst[j] = src1[j] ^ src2[j];
38
0
}
39
40
static int hash_buf(const char *src, char *dst, uint32_t iv,
41
        size_t len, const char *hash_name)
42
0
{
43
0
  struct crypt_hash *hd = NULL;
44
0
  char *iv_char = (char *)&iv;
45
0
  int r;
46
47
0
  iv = be32_to_cpu(iv);
48
0
  if (crypt_hash_init(&hd, hash_name))
49
0
    return -EINVAL;
50
51
0
  if ((r = crypt_hash_write(hd, iv_char, sizeof(uint32_t))))
52
0
    goto out;
53
54
0
  if ((r = crypt_hash_write(hd, src, len)))
55
0
    goto out;
56
57
0
  r = crypt_hash_final(hd, dst, len);
58
0
out:
59
0
  crypt_hash_destroy(hd);
60
0
  return r;
61
0
}
62
63
/*
64
 * diffuse: Information spreading over the whole dataset with
65
 * the help of hash function.
66
 */
67
static int diffuse(char *src, char *dst, size_t size, const char *hash_name)
68
0
{
69
0
  int r, hash_size = crypt_hash_size(hash_name);
70
0
  unsigned int digest_size;
71
0
  unsigned int i, blocks, padding;
72
73
0
  if (hash_size <= 0)
74
0
    return -EINVAL;
75
0
  digest_size = hash_size;
76
77
0
  blocks = size / digest_size;
78
0
  padding = size % digest_size;
79
80
0
  for (i = 0; i < blocks; i++) {
81
0
    r = hash_buf(src + digest_size * i,
82
0
          dst + digest_size * i,
83
0
          i, (size_t)digest_size, hash_name);
84
0
    if (r < 0)
85
0
      return r;
86
0
  }
87
88
0
  if (padding) {
89
0
    r = hash_buf(src + digest_size * i,
90
0
          dst + digest_size * i,
91
0
          i, (size_t)padding, hash_name);
92
0
    if (r < 0)
93
0
      return r;
94
0
  }
95
96
0
  return 0;
97
0
}
98
99
/*
100
 * Information splitting. The amount of data is multiplied by
101
 * blocknumbers. The same blocksize and blocknumbers values
102
 * must be supplied to AF_merge to recover information.
103
 */
104
int AF_split(struct crypt_device *ctx, const char *src, char *dst,
105
       size_t blocksize, unsigned int blocknumbers, const char *hash)
106
0
{
107
0
  unsigned int i;
108
0
  char *bufblock;
109
0
  int r;
110
111
0
  bufblock = crypt_safe_alloc(blocksize);
112
0
  if (!bufblock)
113
0
    return -ENOMEM;
114
115
  /* process everything except the last block */
116
0
  for (i = 0; i < blocknumbers - 1; i++) {
117
0
    r = crypt_random_get(ctx, dst + blocksize * i, blocksize, CRYPT_RND_NORMAL);
118
0
    if (r < 0)
119
0
      goto out;
120
121
0
    XORblock(dst + blocksize * i, bufblock, bufblock, blocksize);
122
0
    r = diffuse(bufblock, bufblock, blocksize, hash);
123
0
    if (r < 0)
124
0
      goto out;
125
0
  }
126
  /* the last block is computed */
127
0
  XORblock(src, bufblock, dst + blocksize * i, blocksize);
128
0
  r = 0;
129
0
out:
130
0
  crypt_safe_free(bufblock);
131
0
  return r;
132
0
}
133
134
int AF_merge(const char *src, char *dst,
135
       size_t blocksize, unsigned int blocknumbers, const char *hash)
136
0
{
137
0
  unsigned int i;
138
0
  char *bufblock;
139
0
  int r;
140
141
0
  bufblock = crypt_safe_alloc(blocksize);
142
0
  if (!bufblock)
143
0
    return -ENOMEM;
144
145
0
  for (i = 0; i < blocknumbers - 1; i++) {
146
0
    XORblock(src + blocksize * i, bufblock, bufblock, blocksize);
147
0
    r = diffuse(bufblock, bufblock, blocksize, hash);
148
0
    if (r < 0)
149
0
      goto out;
150
0
  }
151
0
  XORblock(src + blocksize * i, bufblock, dst, blocksize);
152
0
  r = 0;
153
0
out:
154
0
  crypt_safe_free(bufblock);
155
0
  return r;
156
0
}
157
158
/* Size of final split data including sector alignment */
159
size_t AF_split_sectors(size_t blocksize, unsigned int blocknumbers)
160
693
{
161
693
  size_t af_size;
162
163
  /* data material * stripes */
164
693
  af_size = blocksize * blocknumbers;
165
166
  /* round up to sector */
167
693
  af_size = (af_size + (SECTOR_SIZE - 1)) / SECTOR_SIZE;
168
169
693
  return af_size;
170
693
}