reHDD/src/shred/shred.cpp

414 lines
12 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);
#ifdef LOG_LEVEL_HIGH
Logger::logThis()->info("Shred-Task: RandomRead: " + to_string(blksz) + " - Drive: " + drive->getSerial());
#endif
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)
{
#ifdef LOG_LEVEL_HIGH
Logger::logThis()->info("Shred-Task: alwaysrand");
#endif
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;
#ifdef LOG_LEVEL_HIGH
Logger::logThis()->info("Shred-Task: DriveWrite: " + to_string((noround && last) ? l : blksz) + " - Drive: " + drive->getSerial());
#endif
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