Cleanup & reorganization (#73)
scsi::get_des & others should take a non-const buffer since they modify it Reorder functions in main.cpp to declare internal functions static Fix compile error in newer GCC (Compilation error #72) with more explicit cast Remove some unused constants Add KAD type enum Pass key vector by reference instead of copying Closes: https://github.com/scsitape/stenc/issues/72
This commit is contained in:
475
src/main.cpp
475
src/main.cpp
@@ -43,20 +43,13 @@ GNU General Public License for more details.
|
||||
|
||||
#include "scsiencrypt.h"
|
||||
|
||||
void showUsage();
|
||||
void errorOut(const std::string& message);
|
||||
void inquiryDrive(const std::string& tapeDevice);
|
||||
void showDriveStatus(const std::string& tapeDevice, bool detail);
|
||||
void showVolumeStatus(const std::string& tapeDevice);
|
||||
void echo(bool);
|
||||
|
||||
static std::optional<std::vector<uint8_t>> key_from_hex_chars(const std::string& s)
|
||||
static std::optional<std::vector<std::uint8_t>> key_from_hex_chars(const std::string& s)
|
||||
{
|
||||
auto it = s.data();
|
||||
std::vector<uint8_t> bytes;
|
||||
std::vector<std::uint8_t> bytes;
|
||||
|
||||
if (s.size() % 2) { // treated as if there is an implicit leading 0
|
||||
uint8_t result;
|
||||
std::uint8_t result;
|
||||
auto [ptr, ec] { std::from_chars(it, it + 1, result, 16) };
|
||||
if (ec != std::errc {}) {
|
||||
return {};
|
||||
@@ -66,7 +59,7 @@ static std::optional<std::vector<uint8_t>> key_from_hex_chars(const std::string&
|
||||
}
|
||||
|
||||
while (*it) {
|
||||
uint8_t result;
|
||||
std::uint8_t result;
|
||||
auto [ptr, ec] { std::from_chars(it, it + 2, result, 16) };
|
||||
if (ec != std::errc {}) {
|
||||
return {};
|
||||
@@ -77,6 +70,232 @@ static std::optional<std::vector<uint8_t>> key_from_hex_chars(const std::string&
|
||||
return bytes;
|
||||
}
|
||||
|
||||
// shows the command usage
|
||||
static void showUsage() {
|
||||
std::cerr
|
||||
<< "Usage: stenc --version | "
|
||||
"-f <device> [--detail] [-e <on/mixed/rawread/off> [-k <file>] "
|
||||
"[-kd <description>] [-a <index>] [--protect | --unprotect] [--ckod] ]\n\n"
|
||||
"Type 'man stenc' for more information.\n";
|
||||
}
|
||||
|
||||
// exits to shell with an error message
|
||||
static void errorOut(const std::string& message) {
|
||||
std::cerr << "Error: " << message << "\n";
|
||||
showUsage();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static void print_device_inquiry(std::ostream& os, const scsi::inquiry_data& iresult)
|
||||
{
|
||||
os << std::left << std::setw(25) << "Vendor:";
|
||||
os.write(iresult.vendor, 8);
|
||||
os.put('\n');
|
||||
os << std::left << std::setw(25) << "Product ID:";
|
||||
os.write(iresult.product_id, 16);
|
||||
os.put('\n');
|
||||
os << std::left << std::setw(25) << "Product Revision:";
|
||||
os.write(iresult.product_rev, 4);
|
||||
os.put('\n');
|
||||
}
|
||||
|
||||
static void inquiryDrive(const std::string& tapeDevice) {
|
||||
// todo: std::cout should not be used outside main()
|
||||
auto iresult {scsi::get_inquiry(tapeDevice)};
|
||||
print_device_inquiry(std::cout, iresult);
|
||||
}
|
||||
|
||||
static void print_device_status(std::ostream& os, const scsi::page_des& opt, bool detail)
|
||||
{
|
||||
std::string emode = "unknown";
|
||||
os << std::left << std::setw(25) << "Drive Encryption:";
|
||||
if (opt.encryption_mode == scsi::encrypt_mode::on && // encrypt
|
||||
opt.decryption_mode == scsi::decrypt_mode::on // read only encrypted data
|
||||
)
|
||||
emode = "on";
|
||||
if (opt.encryption_mode == scsi::encrypt_mode::on && // encrypt
|
||||
opt.decryption_mode == scsi::decrypt_mode::mixed // read encrypted and unencrypted
|
||||
)
|
||||
emode = "mixed";
|
||||
|
||||
if (opt.encryption_mode == scsi::encrypt_mode::on && // encrypt
|
||||
opt.decryption_mode == scsi::decrypt_mode::raw // read encrypted and unencrypted
|
||||
)
|
||||
emode = "rawread";
|
||||
|
||||
if (opt.encryption_mode == scsi::encrypt_mode::off && // encrypt
|
||||
opt.decryption_mode == scsi::decrypt_mode::off // read encrypted and unencrypted
|
||||
)
|
||||
emode = "off";
|
||||
|
||||
os << emode << "\n";
|
||||
if (detail) {
|
||||
os << std::left << std::setw(25) << "Drive Output:";
|
||||
switch (opt.decryption_mode) {
|
||||
case scsi::decrypt_mode::off:
|
||||
os << "Not decrypting\n";
|
||||
os << std::setw(25) << " "
|
||||
<< "Raw encrypted data not outputted\n";
|
||||
break;
|
||||
case scsi::decrypt_mode::raw:
|
||||
os << "Not decrypting\n";
|
||||
os << std::setw(25) << " "
|
||||
<< "Raw encrypted data outputted\n";
|
||||
break;
|
||||
case scsi::decrypt_mode::on:
|
||||
os << "Decrypting\n";
|
||||
os << std::setw(25) << " "
|
||||
<< "Unencrypted data not outputted\n";
|
||||
break;
|
||||
case scsi::decrypt_mode::mixed:
|
||||
os << "Decrypting\n";
|
||||
os << std::setw(25) << " "
|
||||
<< "Unencrypted data outputted\n";
|
||||
break;
|
||||
default:
|
||||
os << "Unknown '0x" << std::hex << static_cast<unsigned int>(opt.decryption_mode)
|
||||
<< "' \n";
|
||||
break;
|
||||
}
|
||||
os << std::setw(25) << "Drive Input:";
|
||||
switch (opt.encryption_mode) {
|
||||
case scsi::encrypt_mode::off:
|
||||
os << "Not encrypting\n";
|
||||
break;
|
||||
case scsi::encrypt_mode::on:
|
||||
os << "Encrypting\n";
|
||||
break;
|
||||
default:
|
||||
os << "Unknown result '0x" << std::hex
|
||||
<< static_cast<unsigned int>(opt.encryption_mode) << "'\n";
|
||||
break;
|
||||
}
|
||||
if ((opt.flags & scsi::page_des::flags_rdmd_mask) == scsi::page_des::flags_rdmd_mask) {
|
||||
os << std::setw(25) << " "
|
||||
<< "Protecting from raw read\n";
|
||||
}
|
||||
|
||||
os << std::setw(25) << "Key Instance Counter:" << std::dec
|
||||
<< ntohl(opt.key_instance_counter) << "\n";
|
||||
if (opt.algorithm_index != 0) {
|
||||
os << std::setw(25) << "Encryption Algorithm:" << std::hex
|
||||
<< static_cast<unsigned int>(opt.algorithm_index) << "\n";
|
||||
}
|
||||
}
|
||||
auto kads {scsi::read_page_kads(opt)};
|
||||
for (auto kd: kads) {
|
||||
switch (kd->type) {
|
||||
case scsi::kad_type::ukad:
|
||||
os << std::setw(25) << "Drive Key Desc.(uKAD): ";
|
||||
os.write(reinterpret_cast<const char *>(kd->descriptor), ntohs(kd->length));
|
||||
os.put('\n');
|
||||
break;
|
||||
case scsi::kad_type::akad:
|
||||
os << std::setw(25) << "Drive Key Desc.(aKAD): ";
|
||||
os.write(reinterpret_cast<const char *>(kd->descriptor), ntohs(kd->length));
|
||||
os.put('\n');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void showDriveStatus(const std::string& tapeDrive, bool detail) {
|
||||
alignas(4) scsi::page_buffer buffer;
|
||||
scsi::get_des(tapeDrive, buffer, sizeof(buffer));
|
||||
auto& opt {reinterpret_cast<const scsi::page_des&>(buffer)};
|
||||
|
||||
print_device_status(std::cout, opt, detail);
|
||||
}
|
||||
|
||||
static void print_volume_status(std::ostream& os, const scsi::page_nbes& opt)
|
||||
{
|
||||
auto compression_status {
|
||||
static_cast<std::uint8_t>((opt.status & scsi::page_nbes::status_compression_mask)
|
||||
>> scsi::page_nbes::status_compression_pos)
|
||||
};
|
||||
// From vendor docs, no known drives actually report anything other than 0
|
||||
if (compression_status != 0u) {
|
||||
os << std::left << std::setw(25) << "Volume Compressed:";
|
||||
switch (compression_status) {
|
||||
case 0u:
|
||||
os << "Drive cannot determine\n";
|
||||
break;
|
||||
default:
|
||||
os << "Unknown result '" << std::hex
|
||||
<< static_cast<unsigned int>(compression_status) << "'\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
os << std::left << std::setw(25) << "Volume Encryption:";
|
||||
auto encryption_status {
|
||||
static_cast<std::uint8_t>((opt.status & scsi::page_nbes::status_encryption_mask)
|
||||
>> scsi::page_nbes::status_encryption_pos)
|
||||
};
|
||||
auto kads {read_page_kads(opt)};
|
||||
switch (encryption_status) {
|
||||
case 0u:
|
||||
case 1u:
|
||||
os << "Unable to determine\n";
|
||||
break;
|
||||
case 2u:
|
||||
os << "Tape position not at a logical block\n";
|
||||
break;
|
||||
case 3u:
|
||||
os << "Not encrypted\n";
|
||||
break;
|
||||
case 5u:
|
||||
os << "Encrypted and able to decrypt\n";
|
||||
if ((opt.flags & scsi::page_nbes::flags_rdmds_mask) == scsi::page_nbes::flags_rdmds_mask) {
|
||||
os << std::left << std::setw(25) << " Protected from raw read\n";
|
||||
}
|
||||
break;
|
||||
case 6u:
|
||||
os << "Encrypted, but unable to decrypt due to invalid key.\n";
|
||||
for (auto kd: kads) {
|
||||
switch (kd->type) {
|
||||
case scsi::kad_type::ukad:
|
||||
os << std::setw(25) << "Volume Key Desc.(uKAD): ";
|
||||
os.write(reinterpret_cast<const char *>(kd->descriptor), ntohs(kd->length));
|
||||
os.put('\n');
|
||||
break;
|
||||
case scsi::kad_type::akad:
|
||||
os << std::setw(25) << "Volume Key Desc.(aKAD): ";
|
||||
os.write(reinterpret_cast<const char *>(kd->descriptor), ntohs(kd->length));
|
||||
os.put('\n');
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((opt.flags & scsi::page_nbes::flags_rdmds_mask) == scsi::page_nbes::flags_rdmds_mask) {
|
||||
os << std::left << std::setw(25) << " Protected from raw read\n";
|
||||
}
|
||||
break;
|
||||
default:
|
||||
os << "Unknown result '" << std::hex
|
||||
<< static_cast<unsigned int>(encryption_status) << "'\n";
|
||||
break;
|
||||
}
|
||||
if (opt.algorithm_index != 0) {
|
||||
os << std::left << std::setw(25)
|
||||
<< "Volume Algorithm:" << static_cast<unsigned int>(opt.algorithm_index) << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
static void showVolumeStatus(const std::string& tapeDrive) {
|
||||
alignas(4) scsi::page_buffer buffer;
|
||||
scsi::get_nbes(tapeDrive, buffer, sizeof(buffer));
|
||||
auto& opt {reinterpret_cast<const scsi::page_nbes&>(buffer)};
|
||||
|
||||
print_volume_status(std::cout, opt);
|
||||
}
|
||||
|
||||
static void echo(bool on) {
|
||||
struct termios settings {};
|
||||
tcgetattr(STDIN_FILENO, &settings);
|
||||
settings.c_lflag =
|
||||
on ? (settings.c_lflag | ECHO) : (settings.c_lflag & ~(ECHO));
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &settings);
|
||||
}
|
||||
|
||||
#if !defined(CATCH_CONFIG_MAIN)
|
||||
int main(int argc, const char **argv) {
|
||||
std::string tapeDrive;
|
||||
@@ -106,10 +325,10 @@ int main(int argc, const char **argv) {
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
if (thisCmd == "-e") {
|
||||
if (nextCmd == ""){
|
||||
if (nextCmd == "") {
|
||||
errorOut("Key file not specified after -k option");
|
||||
}
|
||||
if (nextCmd == "on"){
|
||||
if (nextCmd == "on") {
|
||||
// encrypt, read only encrypted data
|
||||
enc_mode = scsi::encrypt_mode::on;
|
||||
dec_mode = scsi::decrypt_mode::on;
|
||||
@@ -156,7 +375,7 @@ int main(int argc, const char **argv) {
|
||||
}
|
||||
rdmc = scsi::sde_rdmc::disabled;
|
||||
} else if (thisCmd == "--unprotect") {
|
||||
if (rdmc == scsi::sde_rdmc::disabled){
|
||||
if (rdmc == scsi::sde_rdmc::disabled) {
|
||||
errorOut("'--unprotect' cannot be specified at the same time as "
|
||||
"'--protect'");
|
||||
}
|
||||
@@ -197,11 +416,11 @@ int main(int argc, const char **argv) {
|
||||
<< "--------------------------------------------------\n";
|
||||
|
||||
try {
|
||||
if (detail){
|
||||
if (detail) {
|
||||
inquiryDrive(tapeDrive);
|
||||
}
|
||||
showDriveStatus(tapeDrive, detail);
|
||||
if (detail){
|
||||
if (detail) {
|
||||
showVolumeStatus(tapeDrive);
|
||||
}
|
||||
exit(EXIT_SUCCESS);
|
||||
@@ -321,227 +540,3 @@ int main(int argc, const char **argv) {
|
||||
}
|
||||
}
|
||||
#endif // defined(CATCH_CONFIG_MAIN)
|
||||
|
||||
// exits to shell with an error message
|
||||
void errorOut(const std::string& message) {
|
||||
std::cerr << "Error: " << message << "\n";
|
||||
showUsage();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// shows the command usage
|
||||
void showUsage() {
|
||||
std::cerr
|
||||
<< "Usage: stenc --version | "
|
||||
"-f <device> [--detail] [-e <on/mixed/rawread/off> [-k <file>] "
|
||||
"[-kd <description>] [-a <index>] [--protect | --unprotect] [--ckod] ]\n\n"
|
||||
"Type 'man stenc' for more information.\n";
|
||||
}
|
||||
|
||||
static void print_device_inquiry(std::ostream& os, const scsi::inquiry_data& iresult)
|
||||
{
|
||||
os << std::left << std::setw(25) << "Vendor:";
|
||||
os.write(iresult.vendor, 8);
|
||||
os.put('\n');
|
||||
os << std::left << std::setw(25) << "Product ID:";
|
||||
os.write(iresult.product_id, 16);
|
||||
os.put('\n');
|
||||
os << std::left << std::setw(25) << "Product Revision:";
|
||||
os.write(iresult.product_rev, 4);
|
||||
os.put('\n');
|
||||
}
|
||||
|
||||
void inquiryDrive(const std::string& tapeDevice) {
|
||||
// todo: std::cout should not be used outside main()
|
||||
auto iresult {scsi::get_inquiry(tapeDevice)};
|
||||
print_device_inquiry(std::cout, iresult);
|
||||
}
|
||||
|
||||
static void print_device_status(std::ostream& os, const scsi::page_des& opt, bool detail)
|
||||
{
|
||||
std::string emode = "unknown";
|
||||
os << std::left << std::setw(25) << "Drive Encryption:";
|
||||
if (opt.encryption_mode == scsi::encrypt_mode::on && // encrypt
|
||||
opt.decryption_mode == scsi::decrypt_mode::on // read only encrypted data
|
||||
)
|
||||
emode = "on";
|
||||
if (opt.encryption_mode == scsi::encrypt_mode::on && // encrypt
|
||||
opt.decryption_mode == scsi::decrypt_mode::mixed // read encrypted and unencrypted
|
||||
)
|
||||
emode = "mixed";
|
||||
|
||||
if (opt.encryption_mode == scsi::encrypt_mode::on && // encrypt
|
||||
opt.decryption_mode == scsi::decrypt_mode::raw // read encrypted and unencrypted
|
||||
)
|
||||
emode = "rawread";
|
||||
|
||||
if (opt.encryption_mode == scsi::encrypt_mode::off && // encrypt
|
||||
opt.decryption_mode == scsi::decrypt_mode::off // read encrypted and unencrypted
|
||||
)
|
||||
emode = "off";
|
||||
|
||||
os << emode << "\n";
|
||||
if (detail) {
|
||||
os << std::left << std::setw(25) << "Drive Output:";
|
||||
switch (opt.decryption_mode) {
|
||||
case scsi::decrypt_mode::off:
|
||||
os << "Not decrypting\n";
|
||||
os << std::setw(25) << " "
|
||||
<< "Raw encrypted data not outputted\n";
|
||||
break;
|
||||
case scsi::decrypt_mode::raw:
|
||||
os << "Not decrypting\n";
|
||||
os << std::setw(25) << " "
|
||||
<< "Raw encrypted data outputted\n";
|
||||
break;
|
||||
case scsi::decrypt_mode::on:
|
||||
os << "Decrypting\n";
|
||||
os << std::setw(25) << " "
|
||||
<< "Unencrypted data not outputted\n";
|
||||
break;
|
||||
case scsi::decrypt_mode::mixed:
|
||||
os << "Decrypting\n";
|
||||
os << std::setw(25) << " "
|
||||
<< "Unencrypted data outputted\n";
|
||||
break;
|
||||
default:
|
||||
os << "Unknown '0x" << std::hex << static_cast<unsigned int>(opt.decryption_mode)
|
||||
<< "' \n";
|
||||
break;
|
||||
}
|
||||
os << std::setw(25) << "Drive Input:";
|
||||
switch (opt.encryption_mode) {
|
||||
case scsi::encrypt_mode::off:
|
||||
os << "Not encrypting\n";
|
||||
break;
|
||||
case scsi::encrypt_mode::on:
|
||||
os << "Encrypting\n";
|
||||
break;
|
||||
default:
|
||||
os << "Unknown result '0x" << std::hex
|
||||
<< static_cast<unsigned int>(opt.encryption_mode) << "'\n";
|
||||
break;
|
||||
}
|
||||
if ((opt.flags & scsi::page_des::flags_rdmd_mask) == scsi::page_des::flags_rdmd_mask) {
|
||||
os << std::setw(25) << " "
|
||||
<< "Protecting from raw read\n";
|
||||
}
|
||||
|
||||
os << std::setw(25) << "Key Instance Counter:" << std::dec
|
||||
<< ntohl(opt.key_instance_counter) << "\n";
|
||||
if (opt.algorithm_index != 0) {
|
||||
os << std::setw(25) << "Encryption Algorithm:" << std::hex
|
||||
<< static_cast<unsigned int>(opt.algorithm_index) << "\n";
|
||||
}
|
||||
}
|
||||
auto kads {scsi::read_page_kads(opt)};
|
||||
for (auto kd: kads) {
|
||||
switch (kd->type) {
|
||||
case KAD_TYPE_UKAD:
|
||||
os << std::setw(25) << "Drive Key Desc.(uKAD): ";
|
||||
os.write(reinterpret_cast<const char *>(kd->descriptor), ntohs(kd->length));
|
||||
os.put('\n');
|
||||
break;
|
||||
case KAD_TYPE_AKAD:
|
||||
os << std::setw(25) << "Drive Key Desc.(aKAD): ";
|
||||
os.write(reinterpret_cast<const char *>(kd->descriptor), ntohs(kd->length));
|
||||
os.put('\n');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void showDriveStatus(const std::string& tapeDrive, bool detail) {
|
||||
alignas(4) scsi::page_buffer buffer;
|
||||
scsi::get_des(tapeDrive, buffer, sizeof(buffer));
|
||||
auto& opt {reinterpret_cast<const scsi::page_des&>(buffer)};
|
||||
|
||||
print_device_status(std::cout, opt, detail);
|
||||
}
|
||||
|
||||
static void print_volume_status(std::ostream& os, const scsi::page_nbes& opt)
|
||||
{
|
||||
auto compression_status {
|
||||
static_cast<std::uint8_t>((opt.status & scsi::page_nbes::status_compression_mask)
|
||||
>> scsi::page_nbes::status_compression_pos)
|
||||
};
|
||||
if (compression_status != 0u) {
|
||||
os << std::left << std::setw(25) << "Volume Compressed:";
|
||||
switch (compression_status) {
|
||||
case 0u:
|
||||
os << "Drive cannot determine\n";
|
||||
break;
|
||||
default:
|
||||
os << "Unknown result '" << std::hex
|
||||
<< static_cast<unsigned int>(compression_status) << "'\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
os << std::left << std::setw(25) << "Volume Encryption:";
|
||||
auto encryption_status {
|
||||
static_cast<std::uint8_t>((opt.status & scsi::page_nbes::status_encryption_mask)
|
||||
>> scsi::page_nbes::status_encryption_pos)
|
||||
};
|
||||
auto kads {read_page_kads(opt)};
|
||||
switch (encryption_status) {
|
||||
case 1u:
|
||||
os << "Unable to determine\n";
|
||||
break;
|
||||
case 2u:
|
||||
os << "Logical block is not a logical block\n";
|
||||
break;
|
||||
case 3u:
|
||||
os << "Not encrypted\n";
|
||||
break;
|
||||
case 5u:
|
||||
os << "Encrypted and able to decrypt\n";
|
||||
if ((opt.flags & scsi::page_nbes::flags_rdmds_mask) == scsi::page_nbes::flags_rdmds_mask) {
|
||||
os << std::left << std::setw(25) << " Protected from raw read\n";
|
||||
}
|
||||
break;
|
||||
case 6u:
|
||||
os << "Encrypted, but unable to decrypt due to invalid key.\n";
|
||||
for (auto kd: kads) {
|
||||
switch (kd->type) {
|
||||
case KAD_TYPE_UKAD:
|
||||
os << std::setw(25) << "Volume Key Desc.(uKAD): ";
|
||||
os.write(reinterpret_cast<const char *>(kd->descriptor), ntohs(kd->length));
|
||||
os.put('\n');
|
||||
break;
|
||||
case KAD_TYPE_AKAD:
|
||||
os << std::setw(25) << "Volume Key Desc.(aKAD): ";
|
||||
os.write(reinterpret_cast<const char *>(kd->descriptor), ntohs(kd->length));
|
||||
os.put('\n');
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((opt.flags & scsi::page_nbes::flags_rdmds_mask) == scsi::page_nbes::flags_rdmds_mask) {
|
||||
os << std::left << std::setw(25) << " Protected from raw read\n";
|
||||
}
|
||||
break;
|
||||
default:
|
||||
os << "Unknown result '" << std::hex
|
||||
<< static_cast<unsigned int>(encryption_status) << "'\n";
|
||||
break;
|
||||
}
|
||||
if (opt.algorithm_index != 0) {
|
||||
os << std::left << std::setw(25)
|
||||
<< "Volume Algorithm:" << static_cast<unsigned int>(opt.algorithm_index) << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
void showVolumeStatus(const std::string& tapeDrive) {
|
||||
alignas(4) scsi::page_buffer buffer;
|
||||
scsi::get_nbes(tapeDrive, buffer, sizeof(buffer));
|
||||
auto& opt {reinterpret_cast<const scsi::page_nbes&>(buffer)};
|
||||
|
||||
print_volume_status(std::cout, opt);
|
||||
}
|
||||
|
||||
void echo(bool on) {
|
||||
struct termios settings {};
|
||||
tcgetattr(STDIN_FILENO, &settings);
|
||||
settings.c_lflag =
|
||||
on ? (settings.c_lflag | ECHO) : (settings.c_lflag & ~(ECHO));
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &settings);
|
||||
}
|
||||
|
||||
@@ -20,20 +20,14 @@ GNU General Public License for more details.
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mtio.h>
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#if defined(OS_LINUX)
|
||||
#include <scsi/scsi.h>
|
||||
@@ -85,7 +79,7 @@ using unique_fd = std::unique_ptr<int, generic_deleter<int, -1, decltype(&close)
|
||||
enum class scsi_direction { to_device, from_device };
|
||||
|
||||
static void scsi_execute(const std::string& device, const std::uint8_t *cmd_p,
|
||||
std::size_t cmd_len, const std::uint8_t *dxfer_p,
|
||||
std::size_t cmd_len, std::uint8_t *dxfer_p,
|
||||
std::size_t dxfer_len, scsi_direction direction)
|
||||
{
|
||||
#if defined(OS_LINUX)
|
||||
@@ -103,7 +97,7 @@ static void scsi_execute(const std::string& device, const std::uint8_t *cmd_p,
|
||||
cmdio.dxfer_direction = (direction == scsi_direction::to_device)
|
||||
? SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV;
|
||||
cmdio.dxfer_len = dxfer_len;
|
||||
cmdio.dxferp = const_cast<unsigned char*>(dxfer_p);
|
||||
cmdio.dxferp = dxfer_p;
|
||||
cmdio.cmdp = const_cast<unsigned char*>(cmd_p);
|
||||
cmdio.sbp = sense_buf->data();
|
||||
cmdio.mx_sb_len = sizeof(decltype(sense_buf)::element_type);
|
||||
@@ -134,8 +128,8 @@ static void scsi_execute(const std::string& device, const std::uint8_t *cmd_p,
|
||||
cam_fill_csio(&ccb->csio, RETRYCOUNT, nullptr,
|
||||
CAM_PASS_ERR_RECOVER | CAM_CDB_POINTER |
|
||||
(direction == scsi_direction::to_device ? CAM_DIR_OUT : CAM_DIR_IN),
|
||||
MSG_SIMPLE_Q_TAG, const_cast<u_int8_t*>(dxfer_p),
|
||||
dxfer_len, SSD_FULL_SIZE, cmd_len, SCSI_TIMEOUT);
|
||||
MSG_SIMPLE_Q_TAG, dxfer_p, dxfer_len, SSD_FULL_SIZE, cmd_len,
|
||||
SCSI_TIMEOUT);
|
||||
ccb->csio.cdb_io.cdb_ptr = const_cast<u_int8_t*>(cmd_p);
|
||||
if (cam_send_ccb(dev.get(), ccb.get())) {
|
||||
throw std::system_error {errno, std::generic_category()};
|
||||
@@ -152,8 +146,7 @@ static void scsi_execute(const std::string& device, const std::uint8_t *cmd_p,
|
||||
|
||||
namespace scsi {
|
||||
|
||||
void get_des(const std::string& device, const std::uint8_t *buffer,
|
||||
std::size_t length)
|
||||
void get_des(const std::string& device, std::uint8_t *buffer, std::size_t length)
|
||||
{
|
||||
const std::uint8_t spin_des_command[] {
|
||||
SSP_SPIN_OPCODE,
|
||||
@@ -170,8 +163,7 @@ void get_des(const std::string& device, const std::uint8_t *buffer,
|
||||
buffer, length, scsi_direction::from_device);
|
||||
}
|
||||
|
||||
void get_nbes(const std::string& device, const std::uint8_t *buffer,
|
||||
std::size_t length)
|
||||
void get_nbes(const std::string& device, std::uint8_t *buffer, std::size_t length)
|
||||
{
|
||||
const std::uint8_t spin_nbes_command[] {
|
||||
SSP_SPIN_OPCODE,
|
||||
@@ -188,8 +180,7 @@ void get_nbes(const std::string& device, const std::uint8_t *buffer,
|
||||
buffer, length, scsi_direction::from_device);
|
||||
}
|
||||
|
||||
void get_dec(const std::string& device, const std::uint8_t *buffer,
|
||||
std::size_t length)
|
||||
void get_dec(const std::string& device, std::uint8_t *buffer, std::size_t length)
|
||||
{
|
||||
const uint8_t spin_dec_command[] {
|
||||
SSP_SPIN_OPCODE,
|
||||
@@ -208,9 +199,9 @@ void get_dec(const std::string& device, const std::uint8_t *buffer,
|
||||
inquiry_data get_inquiry(const std::string& device)
|
||||
{
|
||||
const uint8_t scsi_inq_command[] {0x12, 0, 0, 0, sizeof(inquiry_data), 0};
|
||||
inquiry_data inq;
|
||||
inquiry_data inq {};
|
||||
scsi_execute(device, scsi_inq_command, sizeof(scsi_inq_command),
|
||||
reinterpret_cast<const std::uint8_t*>(&inq), sizeof(inq),
|
||||
reinterpret_cast<std::uint8_t*>(&inq), sizeof(inq),
|
||||
scsi_direction::from_device);
|
||||
return inq;
|
||||
}
|
||||
@@ -218,7 +209,7 @@ inquiry_data get_inquiry(const std::string& device)
|
||||
std::unique_ptr<const std::uint8_t[]> make_sde(encrypt_mode enc_mode,
|
||||
decrypt_mode dec_mode,
|
||||
std::uint8_t algorithm_index,
|
||||
const std::vector<std::uint8_t> key,
|
||||
const std::vector<std::uint8_t>& key,
|
||||
const std::string& key_name,
|
||||
sde_rdmc rdmc, bool ckod)
|
||||
{
|
||||
@@ -233,7 +224,7 @@ std::unique_ptr<const std::uint8_t[]> make_sde(encrypt_mode enc_mode,
|
||||
page.length = htons(length - sizeof(page_header));
|
||||
page.control = std::byte {2u} << page_sde::control_scope_pos; // all IT nexus = 10b
|
||||
page.flags |= std::byte {DEFAULT_CEEM} << page_sde::flags_ceem_pos;
|
||||
page.flags |= std::byte {rdmc};
|
||||
page.flags |= std::byte {static_cast<std::underlying_type_t<sde_rdmc>>(rdmc)};
|
||||
if (ckod) {
|
||||
page.flags |= page_sde::flags_ckod_mask;
|
||||
}
|
||||
@@ -269,7 +260,7 @@ void write_sde(const std::string& device, const std::uint8_t *sde_buffer)
|
||||
};
|
||||
|
||||
scsi_execute(device, spout_sde_command, sizeof(spout_sde_command),
|
||||
sde_buffer, length, scsi_direction::to_device);
|
||||
const_cast<std::uint8_t*>(sde_buffer), length, scsi_direction::to_device);
|
||||
}
|
||||
|
||||
void print_sense_data(std::ostream& os, const sense_data& sd) {
|
||||
|
||||
@@ -34,20 +34,8 @@ GNU General Public License for more details.
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
constexpr size_t SSP_KEY_LENGTH = 0X20;
|
||||
constexpr size_t SSP_DESCRIPTOR_LENGTH = 1024;
|
||||
constexpr size_t SSP_KAD_HEAD_LENGTH = 4;
|
||||
constexpr size_t SSP_PAGE_ALLOCATION = 8192;
|
||||
constexpr size_t SSP_UKAD_LENGTH = 0x1e;
|
||||
|
||||
constexpr uint8_t KAD_TYPE_UKAD = 0x00;
|
||||
constexpr uint8_t KAD_TYPE_AKAD = 0x01;
|
||||
constexpr uint8_t KAD_TYPE_NONCE = 0x02;
|
||||
constexpr uint8_t KAD_TYPE_META = 0x03;
|
||||
|
||||
constexpr uint8_t RDMC_PROTECT = 0x03;
|
||||
constexpr uint8_t RDMC_UNPROTECT = 0x02;
|
||||
constexpr uint8_t RDMC_DEFAULT = 0x00;
|
||||
constexpr std::size_t SSP_PAGE_ALLOCATION = 8192;
|
||||
constexpr std::size_t SSP_UKAD_LENGTH = 0x1e;
|
||||
|
||||
// outputs hex in a 2 digit pair
|
||||
#define HEX(x) \
|
||||
@@ -68,9 +56,17 @@ enum class decrypt_mode: std::uint8_t {
|
||||
mixed = 3u,
|
||||
};
|
||||
|
||||
enum class kad_type: std::uint8_t {
|
||||
ukad = 0u, // unauthenticated key-associated data
|
||||
akad = 1u, // authenticated key-associated data
|
||||
nonce = 2u, // nonce value
|
||||
mkad = 3u, // metadata key-associated data
|
||||
wkkad = 4u, // wrapped key key-associated data
|
||||
};
|
||||
|
||||
// key-associated data
|
||||
struct __attribute__((packed)) kad {
|
||||
std::uint8_t type;
|
||||
kad_type type;
|
||||
std::byte flags;
|
||||
static constexpr auto flags_authenticated_pos {0u};
|
||||
static constexpr std::byte flags_authenticated_mask {7u << flags_authenticated_pos};
|
||||
@@ -152,8 +148,8 @@ static_assert(sizeof(page_sde) == 20u);
|
||||
|
||||
enum class sde_rdmc: std::uint8_t {
|
||||
algorithm_default = 0u << page_sde::flags_rdmc_pos,
|
||||
enabled = 2u << page_sde::flags_rdmc_pos,
|
||||
disabled = 3u << page_sde::flags_rdmc_pos,
|
||||
enabled = 2u << page_sde::flags_rdmc_pos, // corresponds to --unprotect command line option
|
||||
disabled = 3u << page_sde::flags_rdmc_pos, // corresponds to --protect command line option
|
||||
};
|
||||
|
||||
// next block encryption status page
|
||||
@@ -327,21 +323,18 @@ std::vector<const kad *> read_page_kads(const Page& page)
|
||||
|
||||
inquiry_data get_inquiry(const std::string& device);
|
||||
// Get data encryption status page
|
||||
void get_des(const std::string& device, const std::uint8_t *buffer,
|
||||
std::size_t length);
|
||||
void get_des(const std::string& device, std::uint8_t *buffer, std::size_t length);
|
||||
// Get next block encryption status page
|
||||
void get_nbes(const std::string& device, const std::uint8_t *buffer,
|
||||
std::size_t length);
|
||||
void get_nbes(const std::string& device, std::uint8_t *buffer, std::size_t length);
|
||||
// Get device encryption capabilities
|
||||
void get_dec(const std::string& device, const std::uint8_t *buffer,
|
||||
std::size_t length);
|
||||
void get_dec(const std::string& device, std::uint8_t *buffer, std::size_t length);
|
||||
// Fill out a set data encryption page with parameters.
|
||||
// Result is allocated and returned as a std::unique_ptr and should
|
||||
// be sent to the device using scsi::write_sde
|
||||
std::unique_ptr<const std::uint8_t[]> make_sde(encrypt_mode enc_mode,
|
||||
decrypt_mode dec_mode,
|
||||
std::uint8_t algorithm_index,
|
||||
const std::vector<std::uint8_t> key,
|
||||
const std::vector<std::uint8_t>& key,
|
||||
const std::string& key_name,
|
||||
sde_rdmc rdmc, bool ckod);
|
||||
// Write set data encryption parameters to device
|
||||
|
||||
Reference in New Issue
Block a user