Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions Common/DtaDev.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ along with sedutil. If not, see <http://www.gnu.org/licenses/>.
#include "DtaConstants.h"
#include "DtaEndianFixup.h"
#include "DtaHexDump.h"
#include "DtaHashPwd.h"

using namespace std;

Expand Down Expand Up @@ -313,6 +314,24 @@ void DtaDev::discovery0()
while (cpos < epos);

}

uint8_t DtaDev::printPasswordHash(char * password)
{
LOG(D1) << "Entering DtaDev::printPasswordHash()";
vector<uint8_t> hash;
DtaHashPwd(hash, password, this);

/* std::hex overwrites flags; save them, so we do not alter other output later */
ios_base::fmtflags saved_flags = cout.flags();

/* First two bytes are actually the opal header */
for (size_t i = 2; i < hash.size(); ++i)
cout << hex << setfill('0') << setw(2) << (int)hash[i];
cout << endl;
cout.flags(saved_flags);
return 0;
}

void DtaDev::puke()
{
LOG(D1) << "Entering DtaDev::puke()";
Expand Down Expand Up @@ -487,3 +506,9 @@ void DtaDev::puke()
if (disk_info.Unknown)
cout << "**** " << (uint16_t)disk_info.Unknown << " **** Unknown function codes IGNORED " << std::endl;
}

uint8_t DtaDev::prepareForS3Sleep(uint8_t lockingrange, char* password)
{
LOG(E) << "S3 sleep not supported on this platform";
return 1;
}
9 changes: 9 additions & 0 deletions Common/DtaDev.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ class DtaDev {
*/
void discovery0();

/** Print password hash, computed with this device's serial number
*/
uint8_t printPasswordHash(char * password);
/*
* virtual methods required in the OS specific
* device class
Expand Down Expand Up @@ -259,6 +262,11 @@ class DtaDev {
* @param password Password of administrative authority for locking range
*/
virtual uint8_t eraseLockingRange(uint8_t lockingrange, char * password) = 0;
/** Optionally implemented s3 sleep support.
* On Linux, it saves the password to the kernel to use on resume.
* @param password the password to save to the kernel
*/
virtual uint8_t prepareForS3Sleep(uint8_t lockingrange, char* password);
/** Dumps an object for diagnostic purposes
* @param sp index into the OPALUID table for the SP the object is in
* @param auth the authority to use for the dump
Expand Down Expand Up @@ -294,6 +302,7 @@ class DtaDev {
/** return the communications ID to be used for sessions to this device */
virtual uint16_t comID() = 0;
bool no_hash_passwords; /** disables hashing of passwords */
bool hex_passwords; /** converts passwords from hex before using them */
sedutiloutput output_format; /** standard, readable, JSON */
protected:
const char * dev; /**< character string representing the device in the OS lexicon */
Expand Down
48 changes: 33 additions & 15 deletions Common/DtaHashPwd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ extern "C" {
}
using namespace std;

void DtaHashPassword(vector<uint8_t> &hash, char * password, vector<uint8_t> salt,
unsigned int iter, uint8_t hashsize)
void DtaHashPassword(vector<uint8_t> &hash, const vector<uint8_t> &password,
const vector<uint8_t> &salt, unsigned int iter, uint8_t hashsize)
{
LOG(D1) << " Entered DtaHashPassword";
// if the hashsize can be > 255 the token overhead logic needs to be fixed
Expand All @@ -42,15 +42,15 @@ void DtaHashPassword(vector<uint8_t> &hash, char * password, vector<uint8_t> sal

hash.clear();
// don't hash the devault OPAL password ''
if (0 == strnlen(password, 32)) {
if (0 == password.size()) {
goto exit;
}
hash.reserve(hashsize + 2); // hope this will prevent reallocation
for (uint16_t i = 0; i < hashsize; i++) {
hash.push_back(' ');
}

cf_pbkdf2_hmac((uint8_t *)password, strnlen(password, 256),
cf_pbkdf2_hmac(&password[0], password.size(),
salt.data(), salt.size(),
iter,
hash.data(), hash.size(),
Expand All @@ -67,21 +67,38 @@ void DtaHashPwd(vector<uint8_t> &hash, char * password, DtaDev * d)
{
LOG(D1) << " Entered DtaHashPwd";
char *serNum;
vector<uint8_t> decoded_password;
if (d->hex_passwords)
{
for (char* p=password; *p; ++p)
{
uint8_t num1 = (uint8_t)(*p & 0x40 ? (*p & 0xf) + 9 : *p & 0xf);
++p;
if (*p == 0)
break;
uint8_t num2 = (uint8_t)(*p & 0x40 ? (*p & 0xf) + 9 : *p & 0xf);
decoded_password.push_back(num1 * 16 + num2);
}
}
else
{
decoded_password.assign(password, password + strlen(password));
}

if (d->no_hash_passwords) {
hash.clear();
for (uint16_t i = 0; i < strnlen(password, 32); i++)
hash.push_back(password[i]);
// add the token overhead
hash.insert(hash.begin(), (uint8_t)hash.size());
hash.insert(hash.begin(), 0xd0);
LOG(D1) << " Exit DtaHashPwd";
return;
if (decoded_password.size() > 32)
decoded_password.resize(32);
hash = decoded_password;
// add the token overhead
hash.insert(hash.begin(), (uint8_t)hash.size());
hash.insert(hash.begin(), 0xd0);
LOG(D1) << " Exit DtaHashPwd";
return;
}
serNum = d->getSerialNum();
vector<uint8_t> salt(serNum, serNum + 20);
// vector<uint8_t> salt(DEFAULTSALT);
DtaHashPassword(hash, password, salt);
DtaHashPassword(hash, decoded_password, salt);
LOG(D1) << " Exit DtaHashPwd"; // log for hash timing
}

Expand Down Expand Up @@ -109,7 +126,7 @@ int testresult(std::vector<uint8_t> &result, const char * expected, size_t len)
int Testsedutil(const PBKDF_TestTuple *testSet, unsigned int testSetSize)
{
int pass = 1;
std::vector<uint8_t> hash, seaSalt;
std::vector<uint8_t> hash, seaSalt, password;

for (unsigned int i = 0; i < testSetSize; i++) {
const PBKDF_TestTuple &tuple = testSet[i];
Expand All @@ -120,7 +137,8 @@ int Testsedutil(const PBKDF_TestTuple *testSet, unsigned int testSetSize)
}
printf("Password %s Salt %s Iterations %i Length %i\n", (char *)tuple.Password,
(char *) tuple.Salt, tuple.iterations, tuple.hashlen);
DtaHashPassword(hash, (char *) tuple.Password, seaSalt, tuple.iterations, tuple.hashlen);
password.assign(tuple.Password, tuple.Password+strlen(tuple.Password));
DtaHashPassword(hash, password, seaSalt, tuple.iterations, tuple.hashlen);
int fail = (testresult(hash, tuple.hexDerivedKey, tuple.hashlen) == 0);
pass = pass & fail;
}
Expand Down
2 changes: 1 addition & 1 deletion Common/DtaHashPwd.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ void DtaHashPwd(vector<uint8_t> &hash, char * password, DtaDev * device);
* @param iter number of iterations to be preformed
* @param hashsize size of hash to be returned
*/
void DtaHashPassword(vector<uint8_t> &hash, char * password, vector<uint8_t> salt,
void DtaHashPassword(vector<uint8_t> &hash, const vector<uint8_t> &password, const vector<uint8_t> &salt,
unsigned int iter = 500000, uint8_t hashsize = 32);
/** Test the hshing function using publicly available test cased and report */
int TestPBKDF2();
38 changes: 37 additions & 1 deletion Common/DtaOptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@ void usage()
printf("a utility to manage self encrypting drives that conform\n");
printf("to the TCG Enterprise, Opal, Opalite and Pyrite SSC specs\n");
printf("General Usage: (see readme for extended commandset)\n");
printf("sedutil-cli <-v> <-n> <action> <options> <device>\n");
printf("sedutil-cli <-v> <-n> <-x> <action> <options> <device>\n");
printf("-v (optional) increase verbosity, one to five v's\n");
printf("-n (optional) no password hashing. Passwords will be sent in clear text!\n");
printf("-l (optional) log style output to stderr only\n");
printf("-x (optional) password inputs are in hex form\n");
printf("actions \n");
printf("--scan \n");
printf(" Scans the devices on the system \n");
Expand Down Expand Up @@ -99,6 +100,12 @@ void usage()
printf(" AdminSP->Revert instead of ThisSP->RevertSP\n");
printf("--printDefaultPassword <device>\n");
printf(" print MSID \n");
printf("--printPasswordHash <password> <device>\n");
printf(" print the hash of the password \n");
printf(" as computed by sedutil. Hex-ecoded.\n");
printf("--prepareForS3Sleep <0...n> <Admin1password> <device>\n");
printf(" Automatically unlock range after S3 resume\n");
printf(" This command will save the password to kernel memory\n");
printf("\n");
printf("Examples \n");
printf("sedutil-cli --scan \n");
Expand Down Expand Up @@ -144,6 +151,10 @@ uint8_t DtaOptions(int argc, char * argv[], DTA_OPTIONS * opts)
opts->output_format = sedutilNormal;
outputFormat = sedutilNormal;
}
else if (!strcmp("-x", argv[i])) {
baseOptions += 1;
opts->hex_passwords = true;
}
else if (!(('-' == argv[i][0]) && ('-' == argv[i][1])) &&
(0 == opts->action))
{
Expand Down Expand Up @@ -515,6 +526,31 @@ uint8_t DtaOptions(int argc, char * argv[], DTA_OPTIONS * opts)
END_OPTION
BEGIN_OPTION(objDump, 5) i += 4; OPTION_IS(device) END_OPTION
BEGIN_OPTION(printDefaultPassword, 1) OPTION_IS(device) END_OPTION
BEGIN_OPTION(printPasswordHash, 2)
OPTION_IS(password)
OPTION_IS(device)
END_OPTION
BEGIN_OPTION(prepareForS3Sleep, 3)
TESTARG(0, lockingrange, 0)
TESTARG(1, lockingrange, 1)
TESTARG(2, lockingrange, 2)
TESTARG(3, lockingrange, 3)
TESTARG(4, lockingrange, 4)
TESTARG(5, lockingrange, 5)
TESTARG(6, lockingrange, 6)
TESTARG(7, lockingrange, 7)
TESTARG(8, lockingrange, 8)
TESTARG(9, lockingrange, 9)
TESTARG(10, lockingrange, 10)
TESTARG(11, lockingrange, 11)
TESTARG(12, lockingrange, 12)
TESTARG(13, lockingrange, 13)
TESTARG(14, lockingrange, 14)
TESTARG(15, lockingrange, 15)
TESTFAIL("Invalid Locking Range (0-15)")
OPTION_IS(password)
OPTION_IS(device)
END_OPTION
BEGIN_OPTION(rawCmd, 7) i += 6; OPTION_IS(device) END_OPTION
else {
LOG(E) << "Invalid command line argument " << argv[i];
Expand Down
3 changes: 3 additions & 0 deletions Common/DtaOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ typedef struct _DTA_OPTIONS {
uint8_t lrlength; /** the length in blocks of a lockingrange */

bool no_hash_passwords; /** global parameter, disables hashing of passwords */
bool hex_passwords; /** global parameter, all incoming passwords are treated as hex-encoded */
sedutiloutput output_format;
} DTA_OPTIONS;
/** Print a usage message */
Expand Down Expand Up @@ -95,6 +96,8 @@ typedef enum _sedutiloption {
validatePBKDF2,
objDump,
printDefaultPassword,
printPasswordHash,
prepareForS3Sleep,
rawCmd,

} sedutiloption;
Expand Down
10 changes: 10 additions & 0 deletions Common/sedutil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ int main(int argc, char * argv[])
// make sure DtaDev::no_hash_passwords is initialized
d->no_hash_passwords = opts.no_hash_passwords;

d->hex_passwords = opts.hex_passwords;

d->output_format = opts.output_format;
}

Expand Down Expand Up @@ -273,6 +275,14 @@ int main(int argc, char * argv[])
LOG(D) << "print default password";
return d->printDefaultPassword();
break;
case sedutiloption::printPasswordHash:
LOG(D) << "print password hash";
return d->printPasswordHash(argv[opts.password]);
break;
case sedutiloption::prepareForS3Sleep:
LOG(D) << "Preparing for S3 sleep " << (uint16_t) opts.lockingrange;
return d->prepareForS3Sleep(opts.lockingrange, argv[opts.password]);
break;
case sedutiloption::rawCmd:
LOG(D) << "Performing cmdDump ";
return d->rawCmd(argv[argc - 7], argv[argc - 6], argv[argc - 5], argv[argc - 4], argv[argc - 3], argv[argc - 2]);
Expand Down
6 changes: 4 additions & 2 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ sedutil_cli_SOURCES = linux/Version.h Common/sedutil.cpp Common/DtaOptions.cpp C
linux/DtaDevLinuxNvme.cpp linux/DtaDevLinuxNvme.h \
linux/DtaDevLinuxSata.cpp linux/DtaDevLinuxSata.h \
linux/DtaDevOS.cpp linux/DtaDevOS.h \
linux/DtaDevLinuxDrive.h linux/os.h \
linux/DtaDevLinuxDrive.cpp linux/DtaDevLinuxDrive.h \
linux/os.h \
$(SEDUTIL_COMMON_CODE)
CLEANFILES = linux/Version.h
BUILT_SOURCES = linux/Version.h
Expand All @@ -40,7 +41,8 @@ linuxpba_SOURCES = LinuxPBA/LinuxPBA.cpp LinuxPBA/GetPassPhrase.cpp LinuxPBA/Unl
linux/DtaDevLinuxNvme.cpp linux/DtaDevLinuxNvme.h \
linux/DtaDevLinuxSata.cpp linux/DtaDevLinuxSata.h \
linux/DtaDevOS.cpp linux/DtaDevOS.h \
linux/DtaDevLinuxDrive.h linux/os.h \
linux/DtaDevLinuxDrive.cpp linux/DtaDevLinuxDrive.h \
linux/os.h \
\
$(SEDUTIL_COMMON_CODE)
EXTRA_DIST = linux/GitVersion.sh linux/PSIDRevert_LINUX.txt linux/TestSuite.sh README.md docs/sedutil-cli.8
Expand Down
50 changes: 45 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ Unique to this repo are the following modifications:

* SHA512 password hashing vs SHA1 on original SEDutil
* Compatibile with AMD Ryzen and AMD Ryzen mobile systems
* Supports S3 sleep


## Build Process
Expand Down Expand Up @@ -238,7 +239,7 @@ Drive /dev/sdd Samsung SSD 850 EVO 250GB is OPAL NOT LOCKED

Verify that the PBA unlocks your drive, it should say "is OPAL Unlocked" If it doesn't then you will need to follow the steps at the end of this page to either remove OPAL or disable locking.

#Set a real password
# Set a real password

The SID and Admin1 passwords do not have to match but it makes things easier.
```
Expand Down Expand Up @@ -270,7 +271,48 @@ Expected Output:
You now need to COMPLETELY POWER DOWN YOUR SYSTEM
This will lock the drive so that when you restart your system it will boot the PBA.

##Recovery information:
## S3 sleep support

To make the machine able to recover from sleep, the following is needed:
* Kernel 4.13 or later
* this patched sedutil-cli
* following the guide here: https://github.com/ladar/sedutil/issues/4#issue-482078217 , (which in turn was born from Drive-Trust-Alliance/sedutil#90). For completeness, mirrored below:

1. (Optional for NVME drives, required for SATA) Edit /etc/default/grub to append `libata.allow_tpm=1` to the end the line GRUB_CMDLINE_LINUX_DEFAULT=

2. (Optional for NVME drives, required for SATA) Update `grub.cfg` by running # `update-grub`

3. Download (or build) the Linux binary from the release of this repo; extract and have it ready to run

4. (Optional for NVME drives, required for SATA) Reboot

5. Find your encryption key by
```
# sedutil-cli --printPasswordHash <password> /dev/nvme?
```
(namespace needs to be included for NVMe, e.g. /dev/nvme0n1; same for the following)

6. Add a systemd service that will execute the following command that will tell the kernel what password to use after wakeup. Note that the password needs to be in the hashed format already.

```
# sedutil-cli -n -x --prepareForS3Sleep 0 Admin1 <password hash> /dev/nvme?
```
Below is my /etc/systemd/system/seds3sleep.service

```
[Service]
Type=oneshot
ExecStart=/opt/sedutil-1.15.1-87/sedutil-cli -n -x --prepareForS3Sleep 0 Admin1 <my password hash> /dev/nvme?

[Install]
WantedBy=multi-user.target
Enable this service. # systemctl enable seds3sleep.service && systemctl start seds3sleep.service
```

**NOTE:** if you have multiple disks, you may want to include multiple `ExecStart` commands, and ideally try all the disks for all passwords as their numbers may randomly change. So for 2 disks having different passwords you may want to include 4 ExecStart statements.


# Recovery information:

If there is an issue after enabling locking you can either disable locking or remove OPAL to continue using your drive without locking.

Expand Down Expand Up @@ -307,7 +349,7 @@ Expected Output:

Some OPAL drives have a firmware bug that will erase all of your data if you issue the commands below. See [Remove OPAL](https://github.com/Drive-Trust-Alliance/sedutil/wiki/Remove-OPAL) for a list of drive/firmware pairs that is know to have been tested.

##To remove OPAL issue these commands:
## To remove OPAL issue these commands:

```
sedutil-cli --revertnoerase <password> <drive>
Expand Down Expand Up @@ -351,5 +393,3 @@ Expected output:

When this is finished the drive will be in a non-opal managed state. This would allow you to do anything that you could have done before starting OPAL management under OPAL. You can also reinitiate OPAL management if you wish.



Loading