404 lines
11 KiB
C++
404 lines
11 KiB
C++
/**
|
|
* @file shred.cpp
|
|
* @brief shred drive
|
|
* @author hendrik schutter
|
|
* @date 03.05.2020
|
|
*/
|
|
|
|
#include "../../include/reHDD.h"
|
|
#ifndef DRYRUN
|
|
static char *randsrc = (char*) "/dev/urandom";
|
|
static int force = 0, rmf = 0, zrf = 0, noround = 0, verbose = 0, syncio = 0, alwaysrand = 0, reqrand = 0;
|
|
|
|
static char sfbuf[PATH_MAX*2];
|
|
|
|
struct tfnge_stream
|
|
{
|
|
TFNG_UNIT_TYPE key[TFNG_NR_KEY_UNITS];
|
|
TFNG_UNIT_TYPE iv[TFNG_NR_BLOCK_UNITS];
|
|
TFNG_BYTE_TYPE carry_block[TFNG_BLOCK_SIZE];
|
|
size_t carry_bytes;
|
|
};
|
|
|
|
static struct tfnge_stream tfnge;
|
|
#endif
|
|
|
|
Shred::Shred()
|
|
{
|
|
|
|
}
|
|
|
|
|
|
Shred::~Shred()
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* \brief shred drive with shred
|
|
* \param pointer of Drive instance
|
|
* \return void
|
|
*/
|
|
void Shred::shredDrive(Drive* drive, int* ipSignalFd)
|
|
{
|
|
#ifdef DRYRUN
|
|
for(int i = 0; i<=100; i++)
|
|
{
|
|
if(drive->state != Drive::SHRED_ACTIVE)
|
|
{
|
|
return;
|
|
}
|
|
drive->setTaskPercentage(i+0.05);
|
|
write(*ipSignalFd, "A",1);
|
|
usleep(20000);
|
|
}
|
|
#endif
|
|
|
|
#ifndef DRYRUN
|
|
|
|
struct stat st;
|
|
char *buf, *s, *d, rc = 0;
|
|
int f, rsf;
|
|
int xret = 0, pat = 0, last = 0, special = 0, iIteration = 0;
|
|
size_t blksz = 0, x, y;
|
|
size_t l, ll = NOSIZE;
|
|
|
|
const char *cpDrivePath = drive->getPath().c_str();
|
|
|
|
blockcount_max = SHRED_ITERATIONS*(drive->getCapacity()/4096);
|
|
|
|
#ifdef LOG_LEVEL_HIGH
|
|
Logger::logThis()->info("Shred-Task: Max-BlockCount: " + to_string(blockcount_max) + " - Drive: " + drive->getSerial());
|
|
#endif
|
|
|
|
d32Percent = 0U;
|
|
|
|
rsf = open(randsrc, O_RDONLY | O_LARGEFILE);
|
|
if (rsf == -1)
|
|
{
|
|
perror(randsrc);
|
|
exit(1);
|
|
}
|
|
|
|
special = pat = 0;
|
|
iIteration = SHRED_ITERATIONS;
|
|
if (verbose) fprintf(stderr, "destroying %s ...\n", cpDrivePath);
|
|
|
|
if (stat(cpDrivePath, &st) == -1)
|
|
{
|
|
perror(cpDrivePath);
|
|
XRET(1);
|
|
goto _return;
|
|
}
|
|
if (!blksz) blksz = (size_t)st.st_blksize;
|
|
|
|
else l = ll = st.st_size;
|
|
if (l == 0 && !S_ISREG(st.st_mode)) special = 1;
|
|
memset(&st, 0, sizeof(struct stat));
|
|
|
|
if (force) if (chmod(cpDrivePath, S_IRUSR|S_IWUSR) == -1)
|
|
{
|
|
perror(cpDrivePath);
|
|
XRET(1);
|
|
}
|
|
f = open(cpDrivePath, O_WRONLY | O_LARGEFILE | O_NOCTTY | syncio);
|
|
if (f == -1)
|
|
{
|
|
XRET(1);
|
|
perror(cpDrivePath);
|
|
goto _return;
|
|
}
|
|
|
|
buf = (char*) malloc(blksz);
|
|
if (!buf)
|
|
{
|
|
perror("malloc");
|
|
XRET(2);
|
|
fprintf(stderr, "Continuing with fixed buffer (%zu bytes long)\n", sizeof(sfbuf));
|
|
buf = sfbuf;
|
|
blksz = sizeof(sfbuf);
|
|
}
|
|
memset(buf, 0, blksz);
|
|
|
|
if (read(rsf, buf, blksz) <= 0) fprintf(stderr, "%s: read 0 bytes (wanted %zu)\n", randsrc, blksz);
|
|
tfnge_init(&tfnge, buf);
|
|
|
|
//iteration loop
|
|
while (iIteration)
|
|
{
|
|
lseek(f, 0L, SEEK_SET);
|
|
|
|
if (iIteration <= 1 && zrf)
|
|
{
|
|
pat = 1;
|
|
rc = 0;
|
|
}
|
|
else if (iIteration == SHRED_ITERATIONS && reqrand)
|
|
{
|
|
pat = 0;
|
|
}
|
|
else if (!alwaysrand)
|
|
{
|
|
if (read(rsf, &rc, 1) <= 0) fprintf(stderr, "%s: read 0 bytes (wanted 1)\n", randsrc);
|
|
pat = rc%2;
|
|
if (read(rsf, &rc, 1) <= 0) fprintf(stderr, "%s: read 0 bytes (wanted 1)\n", randsrc);
|
|
}
|
|
else pat = 0;
|
|
|
|
if (verbose)
|
|
{
|
|
if (pat) fprintf(stderr, "iteration (pat) %d (%02hhx%02hhx%02hhx) ...\n", SHRED_ITERATIONS-iIteration+1, rc, rc, rc);
|
|
else fprintf(stderr, "iteration (!pat) %d (random) ...\n", SHRED_ITERATIONS-iIteration+1);
|
|
}
|
|
// write block loop
|
|
while (1)
|
|
{
|
|
if(drive->state != Drive::SHRED_ACTIVE)
|
|
{
|
|
drive->setTaskPercentage(0);
|
|
d32Percent = 0.00;
|
|
blockcount = 0;
|
|
blockcount_max = 0;
|
|
Logger::logThis()->info("Aborted shred for: " + drive->getModelName() + "-" + drive->getSerial());
|
|
goto _return;
|
|
}
|
|
|
|
double d32TmpPercent = calcProgress();
|
|
|
|
|
|
|
|
if((d32TmpPercent-d32Percent) >= 0.09)
|
|
{
|
|
drive->setTaskPercentage(d32TmpPercent);
|
|
d32Percent = d32TmpPercent;
|
|
#ifdef LOG_LEVEL_HIGH
|
|
Logger::logThis()->info("Shred-Task: BlockCount: " + to_string(blockcount) + " - progress: " + to_string(d32Percent) + " - Drive: " + drive->getSerial());
|
|
#endif
|
|
write(*ipSignalFd, "A",1);
|
|
}
|
|
|
|
if (!pat)
|
|
{
|
|
tfnge_emit(buf, blksz, &tfnge);
|
|
}
|
|
else
|
|
{
|
|
memset(buf, rc, blksz);
|
|
}
|
|
|
|
if (l <= blksz && !special)
|
|
{
|
|
last = 1;
|
|
}
|
|
errno = 0;
|
|
l -= write(f, buf, (noround && last) ? l : blksz);
|
|
if (errno)
|
|
{
|
|
perror(cpDrivePath);
|
|
errno = 0;
|
|
break;
|
|
}
|
|
|
|
if (last)
|
|
{
|
|
last = 0;
|
|
break;
|
|
}
|
|
}
|
|
// write block loop end
|
|
l = ll;
|
|
fdatasync(f);
|
|
iIteration--;
|
|
} //iteration loop end
|
|
|
|
if (rmf)
|
|
{
|
|
close(f);
|
|
f = open(cpDrivePath, O_WRONLY | O_TRUNC | O_LARGEFILE | O_NOCTTY | syncio);
|
|
if (verbose) fprintf(stderr, "removing %s ...\n", cpDrivePath);
|
|
x = strnlen(cpDrivePath, sizeof(sfbuf)/2);
|
|
s = sfbuf+(sizeof(sfbuf)/2);
|
|
memcpy(sfbuf, cpDrivePath, x);
|
|
*(sfbuf+x) = 0;
|
|
d = strrchr(sfbuf, '/');
|
|
if (d)
|
|
{
|
|
d++;
|
|
y = d-sfbuf;
|
|
memset(d, '0', x-(d-sfbuf));
|
|
}
|
|
else
|
|
{
|
|
y = 0;
|
|
memset(sfbuf, '0', x);
|
|
}
|
|
memcpy(s, sfbuf, x);
|
|
*(s+x) = 0;
|
|
|
|
/* Somehow I need to rename original to destination */
|
|
if (access(s, R_OK) != -1)
|
|
{
|
|
fprintf(stderr, "%s already exists!\n", s);
|
|
unlink(cpDrivePath);
|
|
goto _return;
|
|
}
|
|
if (verbose) fprintf(stderr, "%s -> %s\n", cpDrivePath, s);
|
|
if (rename(cpDrivePath, s) == -1)
|
|
{
|
|
perror(s);
|
|
goto _return;
|
|
}
|
|
|
|
while (x > y+1)
|
|
{
|
|
*(sfbuf+x) = 0;
|
|
x--;
|
|
*(s+x) = 0;
|
|
if (access(s, R_OK) != -1)
|
|
{
|
|
fprintf(stderr, "%s already exists!\n", s);
|
|
unlink(sfbuf);
|
|
goto _return;
|
|
}
|
|
if (verbose) fprintf(stderr, "%s -> %s\n", sfbuf, s);
|
|
if (rename(sfbuf, s) == -1)
|
|
{
|
|
perror(s);
|
|
goto _return;
|
|
}
|
|
}
|
|
|
|
if (verbose) fprintf(stderr, "remove %s\n", s);
|
|
unlink(s);
|
|
if (verbose) fprintf(stderr, "done away with %s.\n", cpDrivePath);
|
|
}
|
|
|
|
tfnge_emit(NULL, 0, &tfnge);
|
|
if (buf && buf != sfbuf) free(buf);
|
|
if (f != -1) close(f);
|
|
|
|
_return:
|
|
optind++;
|
|
close(rsf);
|
|
#endif
|
|
if(drive->state == Drive::SHRED_ACTIVE)
|
|
{
|
|
drive->bWasShredded = true;
|
|
drive->state= Drive::NONE;
|
|
drive->setTaskPercentage(0);
|
|
Logger::logThis()->info("Finished shred for: " + drive->getModelName() + "-" + drive->getSerial());
|
|
}
|
|
}
|
|
#ifndef DRYRUN
|
|
|
|
double Shred::calcProgress()
|
|
{
|
|
blockcount++;
|
|
return ((((double)blockcount/(double)blockcount_max))*100);
|
|
}
|
|
|
|
|
|
void Shred::tfnge_init_iv(struct tfnge_stream *tfe, const void *key, const void *iv)
|
|
{
|
|
memset(tfe, 0, sizeof(struct tfnge_stream));
|
|
memcpy(tfe->key, key, TFNG_KEY_SIZE);
|
|
if (iv) memcpy(tfe->iv, iv, TFNG_BLOCK_SIZE);
|
|
tfe->carry_bytes = 0;
|
|
}
|
|
|
|
void Shred::tfnge_init(struct tfnge_stream *tfe, const void *key)
|
|
{
|
|
tfnge_init_iv(tfe, key, NULL);
|
|
}
|
|
|
|
void Shred::tfng_encrypt_rawblk(TFNG_UNIT_TYPE *O, const TFNG_UNIT_TYPE *I, const TFNG_UNIT_TYPE *K)
|
|
{
|
|
TFNG_UNIT_TYPE X, Y, Z, T;
|
|
TFNG_UNIT_TYPE K0, K1, K2, K3;
|
|
TFNG_UNIT_TYPE K4, T0, T1, T2;
|
|
|
|
X = I[0];
|
|
Y = I[1];
|
|
Z = I[2];
|
|
T = I[3];
|
|
|
|
K0 = K[0];
|
|
K1 = K[1];
|
|
K2 = K[2];
|
|
K3 = K[3];
|
|
K4 = K[4];
|
|
T0 = K[5];
|
|
T1 = K[6];
|
|
T2 = K[7];
|
|
|
|
PROCESS_BLOCKP( 1,K1,T0,K0,K3,K2,T1);
|
|
PROCESS_BLOCKN( 2,K2,T1,K1,K4,K3,T2);
|
|
PROCESS_BLOCKP( 3,K3,T2,K2,K0,K4,T0);
|
|
PROCESS_BLOCKN( 4,K4,T0,K3,K1,K0,T1);
|
|
|
|
PROCESS_BLOCKP( 5,K0,T1,K4,K2,K1,T2);
|
|
PROCESS_BLOCKN( 6,K1,T2,K0,K3,K2,T0);
|
|
PROCESS_BLOCKP( 7,K2,T0,K1,K4,K3,T1);
|
|
PROCESS_BLOCKN( 8,K3,T1,K2,K0,K4,T2);
|
|
|
|
PROCESS_BLOCKP( 9,K4,T2,K3,K1,K0,T0);
|
|
PROCESS_BLOCKN(10,K0,T0,K4,K2,K1,T1);
|
|
PROCESS_BLOCKP(11,K1,T1,K0,K3,K2,T2);
|
|
PROCESS_BLOCKN(12,K2,T2,K1,K4,K3,T0);
|
|
|
|
O[0] = X + K3;
|
|
O[1] = Y + K4 + T0;
|
|
O[2] = Z + K0 + T1;
|
|
O[3] = T + K1 + 18;
|
|
}
|
|
|
|
void Shred::tfnge_emit(void *dst, size_t szdst, struct tfnge_stream *tfe)
|
|
{
|
|
TFNG_BYTE_TYPE *udst = (uint8_t*) dst;
|
|
size_t sz = szdst;
|
|
|
|
if (!dst && szdst == 0)
|
|
{
|
|
memset(tfe, 0, sizeof(struct tfnge_stream));
|
|
return;
|
|
}
|
|
|
|
if (tfe->carry_bytes > 0)
|
|
{
|
|
if (tfe->carry_bytes > szdst)
|
|
{
|
|
memcpy(udst, tfe->carry_block, szdst);
|
|
memmove(tfe->carry_block, tfe->carry_block+szdst, tfe->carry_bytes-szdst);
|
|
tfe->carry_bytes -= szdst;
|
|
return;
|
|
}
|
|
|
|
memcpy(udst, tfe->carry_block, tfe->carry_bytes);
|
|
udst += tfe->carry_bytes;
|
|
sz -= tfe->carry_bytes;
|
|
tfe->carry_bytes = 0;
|
|
}
|
|
|
|
if (sz >= TFNG_BLOCK_SIZE)
|
|
{
|
|
do
|
|
{
|
|
tfng_encrypt_rawblk(tfe->iv, tfe->iv, tfe->key);
|
|
memcpy(udst, tfe->iv, TFNG_BLOCK_SIZE);
|
|
udst += TFNG_BLOCK_SIZE;
|
|
}
|
|
while ((sz -= TFNG_BLOCK_SIZE) >= TFNG_BLOCK_SIZE);
|
|
}
|
|
|
|
if (sz)
|
|
{
|
|
tfng_encrypt_rawblk(tfe->iv, tfe->iv, tfe->key);
|
|
memcpy(udst, tfe->iv, sz);
|
|
udst = (TFNG_BYTE_TYPE *)tfe->iv;
|
|
tfe->carry_bytes = TFNG_BLOCK_SIZE-sz;
|
|
memcpy(tfe->carry_block, udst+sz, tfe->carry_bytes);
|
|
}
|
|
}
|
|
#endif |