📄 cli.c
字号:
int r;
if (f == -1)
{
perror ("Cannot open /dev/random");
return FALSE;
}
while ((r = read (f, buf++, 1)) == 1 && --len);
if (r == -1)
{
perror ("Read from /dev/random failed");
close (f);
return FALSE;
}
if (len > 0)
{
perror ("Cannot read enough bytes from /dev/random");
close (f);
return FALSE;
}
close (f);
return TRUE;
}
void HexDump (unsigned __int8 *data, unsigned int length)
{
while (length--)
printf ("%02x", (unsigned int) *data++);
}
double GetTime ()
{
struct timeval tv;
gettimeofday (&tv, NULL);
return (double)tv.tv_sec + (double)tv.tv_usec / 1000000;
}
static __int64 TotalSectors, StartSector;
static double StartTime;
static double LastUpdateTime;
void InitProgressBar (__int64 totalSectors)
{
LastUpdateTime = 0;
StartTime = GetTime ();
TotalSectors = totalSectors;
}
BOOL UpdateProgressBar (__int64 sector)
{
unsigned __int64 s = sector - StartSector;
double t = GetTime ();
double elapsed = t - StartTime;
unsigned __int64 bytesDone = (s + 1) * SECTOR_SIZE;
unsigned __int64 bytesPerSec = bytesDone / (1 + elapsed);
int timeRemain = (int)((TotalSectors - s) / ((s + 1)/(elapsed + 1) + 1));
if (DisplayProgress && IsTerminal && t - LastUpdateTime > 0.2)
{
printf ("\rDone: %.2f MB Speed: %.2f MB/s Left: %d:%02d:%02d "
, (double)bytesDone / 1024 / 1024
, (double)bytesPerSec / 1024 / 1024
, timeRemain / 3600
, (timeRemain % 3600) / 60
, (timeRemain % 3600) % 60);
fflush (stdout);
LastUpdateTime = t;
}
}
static BOOL ParseSize (char *string, uint64_t *size)
{
if (sscanf (string, "%lld", size) == 1)
{
if (strchr (string, 'k') || strchr (string, 'K'))
*size *= 1024;
else if (strchr (string, 'M'))
*size *= 1024 * 1024;
else if (strchr (string, 'G'))
*size *= 1024 * 1024 * 1024;
*size &= ~0x1FF;
return TRUE;
}
return FALSE;
}
static BOOL CreateVolume (char *hostPath)
{
PCRYPTO_INFO ci;
char header[HEADER_SIZE];
char path[MAX_PATH];
char str[128];
FILE *f;
fatparams ft;
Password *pw = &password;
unsigned __int64 startSector, totalSectors, hostSize;
BOOL hiddenVolume;
int randReq;
int i, r = 0;
DropEffectiveUserId ();
// Volume type
switch (VolumeType)
{
case VOLUME_TYPE_NORMAL:
hiddenVolume = FALSE;
break;
case VOLUME_TYPE_HIDDEN:
hiddenVolume = TRUE;
Quick = TRUE;
break;
default:
puts ("Volume type:\n 1) Normal\n 2) Hidden");
hiddenVolume = AskSelection (1, 1, 2) == 2;
break;
}
// Host file or device
hostPath = AskVolumePath (hostPath, hiddenVolume ? "Enter volume path" : "Enter file or device name for new volume");
if (hiddenVolume)
{
if (!IsFile (hostPath) && !IsBlockDevice (hostPath))
{
error ("File or device %s does not exist. Hidden volume cannot be created.\n", hostPath);
return FALSE;
}
f = fopen (hostPath, "r+b");
}
else if (IsFile (hostPath))
{
error ("File %s already exists.\n", hostPath);
return FALSE;
}
else
{
f = fopen (hostPath, "wb");
}
if (!f)
{
perror ("Cannot open file or device");
return FALSE;
}
EAMode = LRW;
// Filesystem
if (!Filesystem)
{
puts ("Filesystem:\n 1) FAT\n 2) None");
Filesystem = AskSelection (1, 1, 2) == 1 ? "FAT" : "None";
}
// Host file/device size
if (fseek (f, 0, SEEK_END) == -1 || (hostSize = ftello (f)) == (unsigned __int64)-1)
{
perror ("Cannot determine host file/device size");
goto err;
}
// Volume size
if (IsBlockDevice (hostPath) && !hiddenVolume)
{
if (VolumeSize != 0)
{
error ("Volume size cannot be changed for device-hosted volumes.\n");
goto err;
}
VolumeSize = hostSize;
}
else if (VolumeSize == 0)
{
while (!AskString ("Enter volume size (bytes - size/sizeK/sizeM/sizeG)", str, sizeof (str))
|| !ParseSize (str, &VolumeSize)
|| VolumeSize == 0);
puts ("");
}
if (hiddenVolume && VolumeSize > hostSize - MIN_VOLUME_SIZE )
{
error ("Outer volume too small for the size specified.\n");
goto err;
}
if (strcasecmp ("FAT", Filesystem) == 0)
{
if (VolumeSize < MIN_VOLUME_SIZE || VolumeSize > MAX_FAT_VOLUME_SIZE)
{
error ("Specified volume size cannot be used with FAT filesystem.\n");
goto err;
}
}
// Hash algorithm
if (HashAlgorithm == 0)
{
puts ("Hash algorithm:");
for (i = 1; i <= LAST_PRF_ID; i++)
printf ("%2d) %s\n", i, HashGetName (i));
HashAlgorithm = AskSelection (1, 1, LAST_PRF_ID);
}
// Encryption algorithm
if (EA == 0)
{
int max = 0;
ea:
puts ("Encryption algorithm:");
for (i = EAGetFirst (); i != 0; i = EAGetNext (i))
{
if (EAGetFirstMode (i) == LRW)
{
printf ("%2d) %s\n", i, EAGetName (str, i));
max = i;
}
}
EA = AskSelection (1, EAGetFirst (), max);
if (CipherGetBlockSize (EAGetFirstCipher (EA)) == 8
&& VolumeSize > WARN_VOL_SIZE_BLOCK64)
{
char s[3];
AskString ("WARNING: You have selected a 64-bit block cipher. Due to security reasons,\n"
"for this volume size, it is strongly recommended to select a 128-bit block cipher\n"
"(for example, AES, Serpent, or Twofish) instead.\n\n"
"Continue? [y/N]", s, sizeof (s));
puts ("");
if (strcmp (s, "y") && strcmp (s, "Y"))
goto ea;
}
}
randReq = EAGetKeySize (EA) * 2 + DISK_IV_SIZE * 2 + PKCS5_SALT_SIZE;
// Password
if (!CmdPasswordValid)
{
while (1)
{
AskPassword ("Enter password for new volume '%s': ", hostPath, &password);
if (!DisplayPassword)
{
Password pv;
AskPassword ("Re-enter password%s", ": ", &pv);
if (password.Length != pv.Length || memcmp (password.Text, pv.Text, pv.Length))
{
puts ("Passwords do not match.\n");
continue;
}
}
break;
}
puts ("");
}
else
pw = &CmdPassword;
if (FirstKeyFile && !KeyFilesApply (pw, FirstKeyFile, !UpdateTime))
{
error ("Error while processing keyfiles\n");
goto err;
}
RandBytesFillRequired (randReq);
// Create volume header
r = VolumeWriteHeader (header,
EA,
EAMode,
pw,
HashAlgorithm,
0,
0,
&ci,
hiddenVolume ? VolumeSize : 0,
FALSE);
if (r == ERR_CIPHER_INIT_WEAK_KEY)
{
error ("A weak or a potentially weak key has been generated. Please try again.\n");
goto err;
}
if (r != 0)
{
error ("Volume header creation failed.\n");
goto err;
}
totalSectors = VolumeSize / SECTOR_SIZE;
ci->hiddenVolumeOffset = hostSize - VolumeSize - HIDDEN_VOL_HEADER_OFFSET;
startSector = !hiddenVolume ? 1 : (ci->hiddenVolumeOffset / SECTOR_SIZE);
if (DisplayKeys)
{
printf ("Master Key: ");
HexDump (ci->master_key, EAGetKeySize (ci->ea));
printf ("\nSecondary Key: ");
HexDump (ci->iv, sizeof (ci->iv));
puts ("\n");
}
// Write header
if (hiddenVolume)
{
if (fseek (f, -HIDDEN_VOL_HEADER_OFFSET, SEEK_END) == -1)
{
perror ("Cannot seek to hidden volume header location");
goto err;
}
}
else
{
if (fseek (f, 0, SEEK_SET) == -1)
{
perror ("Cannot seek to volume header location");
goto err;
}
}
if (fwrite (header, 1, HEADER_SIZE, f) != HEADER_SIZE)
{
perror ("Cannot write volume header");
goto err;
}
InitProgressBar (totalSectors - 1);
StartSector = startSector;
if (Quick && !hiddenVolume && IsFile (hostPath))
Quick = FALSE;
if (strcasecmp ("FAT", Filesystem) == 0)
{
if (hiddenVolume)
{
if (fseeko (f, startSector * SECTOR_SIZE, SEEK_SET) == -1)
{
perror ("Cannot seek to hidden volume data area");
goto err;
}
}
ft.num_sectors = (unsigned int) totalSectors - 1;
ft.cluster_size = ClusterSize;
memcpy (ft.volume_name, "NO NAME ", 11);
GetFatParams (&ft);
r = FormatFat (startSector, &ft, f, ci, Quick);
}
else if (!hiddenVolume)
{
r = FormatNoFs (startSector, totalSectors - 1, f, ci, Quick);
}
if (r == ERR_OS_ERROR)
{
perror ("Volume creation failed");
goto err;
}
if (DisplayProgress && IsTerminal)
puts ("\nVolume created.");
crypto_close (ci);
fclose (f);
return TRUE;
err:
fclose (f);
return FALSE;
}
static BOOL ChangePassword (char *volumePath)
{
char header[HEADER_SIZE];
char path[MAX_PATH];
Password *pw = &password;
PCRYPTO_INFO ci = NULL, ci2 = NULL;
uint64_t startSector, totalSectors;
time_t modTime = 0, acTime;
int wipePass, ret = TRUE;
int fd, r;
FILE *f;
// Volume path
volumePath = AskVolumePath (volumePath, "Enter volume path");
// Open volume
if (!OpenVolume (volumePath, "Enter current password for '%s': ", volumePath, FALSE,
&ci, &startSector, &totalSectors, &modTime, &acTime))
return FALSE;
// New password and/or keyfile(s)
if (!CmdPassword2Valid)
{
while (1)
{
AskPassword ("Enter new password for '%s': ", volumePath, &password);
if (!DisplayPassword)
{
Password pv;
AskPassword ("Re-enter new password%s", ": ", &pv);
if (password.Length != pv.Length || memcmp (password.Text, pv.Text, pv.Length))
{
puts ("Passwords do not match.\n");
continue;
}
}
break;
}
puts ("");
}
else
pw = &CmdPassword2;
if (FirstNewKeyFile && !KeyFilesApply (pw, FirstNewKeyFile, !UpdateTime))
{
error ("Error while processing new keyfiles\n");
return FALSE;
}
fd = open (volumePath, O_RDWR | O_SYNC);
if (fd == -1)
{
perror ("Cannot open file or device");
return FALSE;
}
f = fdopen (fd, "r+b");
// Write a new volume header
for (wipePass = 0; wipePass < DISK_WIPE_PASSES; wipePass++)
{
BOOL wipeMode = wipePass < DISK_WIPE_PASSES - 1;
if (!wipeMode)
{
if (Verbose) puts ("\n");
RandBytesFillRequired (PKCS5_SALT_SIZE);
}
r = VolumeWriteHeader (header,
ci->ea,
ci->mode,
pw,
HashAlgorithm == 0 ? ci->pkcs5 : HashAlgorithm,
(char *)ci->master_key,
ci->volume_creation_time,
&ci2,
ci->hiddenVolumeSize,
wipeMode);
if (r == ERR_CIPHER_INIT_WEAK_KEY)
{
ret = FALSE;
error ("A weak or a potentially weak key has been generated. Please try again.\n");
goto err;
}
if (r != 0)
{
error ("Volume header creation failed.\n");
ret = FALSE;
goto err;
}
crypto_close (ci2);
ci2 = NULL;
if (ci->hiddenVolumeSize)
{
if (fseek (f, -HIDDEN_VOL_HEADER_OFFSET, SEEK_END) == -1)
{
perror ("Cannot seek to hidden volume header location");
ret = FALSE;
goto err;
}
}
else
{
if (fseek (f, 0, SEEK_SET) == -1)
{
perror ("Cannot seek to volume header location");
ret = FALSE;
goto err;
}
}
if (Verbose)
{
printf ("\rWriting header (pass %d)", wipePass);
fflush (stdout);
}
if (fwrite (header, 1, HEADER_SIZE, f) != HEADER_SIZE)
{
perror ("Cannot write volume header");
ret = FALSE;
goto err;
}
fflush (f);
fdatasync (fd);
}
printf ("%sPassword and/or keyfile(s) changed.\n", Verbose ? "\n" : "");
err:
crypto_close (ci);
close (fd);
if (!UpdateTime && modTime != 0)
RestoreFileTime (volumePath, modTime, acTime);
return ret;
}
static BOOL BackupVolumeHeaders (char *backupFile, char *volumePath)
{
char path[MAX_PATH];
char header[HEADER_SIZE * 2];
FILE *f = NULL, *fb = NULL;
struct stat volumeStat;
int ret = FALSE;
DropEffectiveUserId ();
// Volume path
volumePath = AskVolumePath (volumePath, "Enter volume path");
if (strcmp (backupFile, volumePath) == 0)
{
error ("Volume path identical to backup file\n");
goto err;
}
volumeStat.st_mtime = 0;
if (IsFile (volumePath) && stat (volumePath, &volumeStat) != 0)
{
perror ("Cannot read volume's modification and access time");
volumeStat.st_mtime = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -