diff --git a/Makefile b/Makefile
index 1e20ef5d..8b6f7ea2 100644
--- a/Makefile
+++ b/Makefile
@@ -59,6 +59,7 @@ SOFTWARE = BCACHE_TOOLS \
MDADM \
MULTIPATH_TOOLS \
POPT \
+ SEDUTIL \
STRACE \
THIN_PROVISIONING_TOOLS \
UNIONFS_FUSE \
diff --git a/defaults/software.sh b/defaults/software.sh
index 01c504b2..d5e90f56 100644
--- a/defaults/software.sh
+++ b/defaults/software.sh
@@ -198,6 +198,12 @@ GKPKG_POPT_SRCTAR="${GKPKG_POPT_SRCTAR:-${DISTDIR}/popt-${GKPKG_POPT_PV}.tar.gz}
GKPKG_POPT_SRCDIR="${GKPKG_POPT_SRCDIR:-popt-${GKPKG_POPT_PV}}"
GKPKG_POPT_BINPKG="${GKPKG_POPT_BINPKG:-%%CACHE%%/popt-${GKPKG_POPT_PV}-%%ARCH%%.tar.xz}"
+GKPKG_SEDUTIL_PN="sedutil"
+GKPKG_SEDUTIL_PV="${GKPKG_SEDUTIL_PV:-${VERSION_SEDUTIL}}"
+GKPKG_SEDUTIL_SRCTAR="${GKPKG_SEDUTIL_SRCTAR:-${DISTDIR}/sedutil-${GKPKG_SEDUTIL_PV}.tar.gz}"
+GKPKG_SEDUTIL_SRCDIR="${GKPKG_SEDUTIL_SRCDIR:-sedutil-${GKPKG_SEDUTIL_PV}}"
+GKPKG_SEDUTIL_BINPKG="${GKPKG_SEDUTIL_BINPKG:-%%CACHE%%/sedutil-${GKPKG_SEDUTIL_PV}-%%ARCH%%.tar.xz}"
+
GKPKG_STRACE_PN="strace"
GKPKG_STRACE_PV="${GKPKG_STRACE_PV:-${VERSION_STRACE}}"
GKPKG_STRACE_DEPS="libaio"
diff --git a/gen_cmdline.sh b/gen_cmdline.sh
index 5857d48a..f177562d 100755
--- a/gen_cmdline.sh
+++ b/gen_cmdline.sh
@@ -582,6 +582,10 @@ parse_cmdline() {
fi
print_info 3 "CMD_SSH_HOST_KEYS: ${CMD_SSH_HOST_KEYS}"
;;
+ --sedutil|--no-sedutil)
+ CMD_SEDUTIL=$(parse_optbool "$*")
+ print_info 3 "CMD_SEDUTIL: ${CMD_SEDUTIL}"
+ ;;
--strace|--no-strace)
CMD_STRACE=$(parse_optbool "$*")
print_info 3 "CMD_STRACE: ${CMD_STRACE}"
diff --git a/gen_determineargs.sh b/gen_determineargs.sh
index d29ad48a..a4535157 100755
--- a/gen_determineargs.sh
+++ b/gen_determineargs.sh
@@ -416,6 +416,7 @@ determine_real_args() {
set_config_with_override BOOL SSH CMD_SSH "no"
set_config_with_override STRING SSH_AUTHORIZED_KEYS_FILE CMD_SSH_AUTHORIZED_KEYS_FILE "/etc/dropbear/authorized_keys"
set_config_with_override STRING SSH_HOST_KEYS CMD_SSH_HOST_KEYS "create"
+ set_config_with_override BOOL SEDUTIL CMD_SEDUTIL "no"
set_config_with_override BOOL STRACE CMD_STRACE "no"
set_config_with_override BOOL BCACHE CMD_BCACHE "no"
set_config_with_override BOOL LVM CMD_LVM "no"
diff --git a/gen_initramfs.sh b/gen_initramfs.sh
index 2cfa0fdb..002b057d 100755
--- a/gen_initramfs.sh
+++ b/gen_initramfs.sh
@@ -484,6 +484,7 @@ append_base_layout() {
isTrue "${ZFS}" && build_parameters+=( --zfs ) || build_parameters+=( --no-zfs )
isTrue "${SPLASH}" && build_parameters+=( --splash ) || build_parameters+=( --no-splash )
isTrue "${PLYMOUTH}" && build_parameters+=( --plymouth ) || build_parameters+=( --no-plymouth )
+ isTrue "${SEDUTIL}" && build_parameters+=( --sedutil ) || build_parameters+=( --no-sedutil )
isTrue "${STRACE}" && build_parameters+=( --strace ) || build_parameters+=( --no-strace )
isTrue "${KEYCTL}" && build_parameters+=( --keyctl ) || build_parameters+=( --no-keyctl )
isTrue "${GPG}" && build_parameters+=( --gpg ) || build_parameters+=( --no-gpg )
@@ -1386,6 +1387,32 @@ append_plymouth() {
fi
}
+append_sedutil() {
+ local PN=sedutil
+ local TDIR="${TEMP}/initramfs-${PN}-temp"
+ if [ -d "${TDIR}" ]
+ then
+ rm -r "${TDIR}" || gen_die "Failed to clean out existing '${TDIR}'!"
+ fi
+
+ populate_binpkg ${PN}
+
+ mkdir -p "${TDIR}" || gen_die "Failed to create '${TDIR}'!"
+
+ unpack "$(get_gkpkg_binpkg "${PN}")" "${TDIR}"
+
+ cd "${TDIR}" || gen_die "Failed to chdir to '${TDIR}'!"
+ log_future_cpio_content
+ find . -print0 | "${CPIO_COMMAND}" ${CPIO_ARGS} --append -F "${CPIO_ARCHIVE}" \
+ || gen_die "Failed to append ${PN} to cpio!"
+
+ cd "${TEMP}" || die "Failed to chdir to '${TEMP}'!"
+ if isTrue "${CLEANUP}"
+ then
+ rm -rf "${TDIR}"
+ fi
+}
+
append_strace() {
local PN=strace
local TDIR="${TEMP}/initramfs-${PN}-temp"
@@ -2168,6 +2195,7 @@ create_initramfs() {
append_data 'multipath' "${MULTIPATH}"
append_data 'splash' "${SPLASH}"
append_data 'plymouth' "${PLYMOUTH}"
+ append_data 'sedutil' "${SEDUTIL}"
append_data 'strace' "${STRACE}"
append_data 'unionfs_fuse' "${UNIONFS}"
append_data 'xfsprogs' "${XFSPROGS}"
diff --git a/gkbuilds/sedutil.gkbuild b/gkbuilds/sedutil.gkbuild
new file mode 100644
index 00000000..fcdf7120
--- /dev/null
+++ b/gkbuilds/sedutil.gkbuild
@@ -0,0 +1,25 @@
+# Copyright 1999-2021 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+#
+
+src_prepare() {
+ default
+
+ gkautoreconf
+}
+
+src_configure() {
+ append-ldflags -static
+
+ local myopts=(
+ )
+
+ gkconf "${myopts[@]}"
+}
+
+src_install() {
+ default
+
+ rm -rf "${D}"/usr/sbin/linuxpba
+ rm -rf "${D}"/usr/share
+}
diff --git a/patches/sedutil/1.20.0/sedutil-1.20.0-fix-uint8_t.patch b/patches/sedutil/1.20.0/sedutil-1.20.0-fix-uint8_t.patch
new file mode 100644
index 00000000..8e0c4d07
--- /dev/null
+++ b/patches/sedutil/1.20.0/sedutil-1.20.0-fix-uint8_t.patch
@@ -0,0 +1,12 @@
+diff --git a/Common/DtaOptions.h b/Common/DtaOptions.h
+index c012af1..4d88539 100644
+--- a/Common/DtaOptions.h
++++ b/Common/DtaOptions.h
+@@ -20,6 +20,7 @@ along with sedutil. If not, see .
+
+ #ifndef _DTAOPTIONS_H
+ #define _DTAOPTIONS_H
++#include
+
+ /** Output modes */
+ typedef enum _sedutiloutput {
diff --git a/patches/sedutil/1.20.0/sedutil-1.20.0-s3-support.patch b/patches/sedutil/1.20.0/sedutil-1.20.0-s3-support.patch
new file mode 100644
index 00000000..2de7cf73
--- /dev/null
+++ b/patches/sedutil/1.20.0/sedutil-1.20.0-s3-support.patch
@@ -0,0 +1,524 @@
+diff --git a/Common/DtaDev.cpp b/Common/DtaDev.cpp
+index 0346acf..283dd05 100644
+--- a/Common/DtaDev.cpp
++++ b/Common/DtaDev.cpp
+@@ -32,6 +32,7 @@ along with sedutil. If not, see .
+ #include "DtaConstants.h"
+ #include "DtaEndianFixup.h"
+ #include "DtaHexDump.h"
++#include "DtaHashPwd.h"
+
+ using namespace std;
+
+@@ -211,6 +212,24 @@ void DtaDev::discovery0()
+ while (cpos < epos);
+
+ }
++
++uint8_t DtaDev::printPasswordHash(char * password)
++{
++ LOG(D1) << "Entering DtaDev::printPasswordHash()";
++ vector 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()";
+@@ -300,3 +319,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;
++}
+diff --git a/Common/DtaDev.h b/Common/DtaDev.h
+index 473f7bd..e103633 100644
+--- a/Common/DtaDev.h
++++ b/Common/DtaDev.h
+@@ -74,6 +74,9 @@ public:
+ */
+ 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
+@@ -249,6 +252,11 @@ public:
+ * @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 ti use for the dump
+@@ -284,6 +292,7 @@ public:
+ /** 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 */
+diff --git a/Common/DtaDevEnterprise.cpp b/Common/DtaDevEnterprise.cpp
+index ae649ec..76e6e39 100644
+--- a/Common/DtaDevEnterprise.cpp
++++ b/Common/DtaDevEnterprise.cpp
+@@ -1439,7 +1439,7 @@ uint8_t DtaDevEnterprise::exec(DtaCommand * cmd, DtaResponse & resp, uint8_t pro
+ IFLOG(D) DtaAnnotatedDump(IF_RECV, cmd->getRespBuffer(), SWAP32(hdr->cp.length) + sizeof (OPALComPacket));
+ IFLOG(D3) DtaHexDump(cmd->getRespBuffer(), SWAP32(hdr->cp.length) + sizeof (OPALComPacket));
+ if (0 != rc) {
+- LOG(E) << "Command failed on recv" << (uint16_t) rc;
++ LOG(E) << "Command failed on recv, returned " << (uint16_t) rc;
+ return rc;
+ }
+ resp.init(cmd->getRespBuffer());
+diff --git a/Common/DtaDevOpal.cpp b/Common/DtaDevOpal.cpp
+index 1cb5701..3014ebb 100644
+--- a/Common/DtaDevOpal.cpp
++++ b/Common/DtaDevOpal.cpp
+@@ -1583,7 +1583,7 @@ uint8_t DtaDevOpal::exec(DtaCommand * cmd, DtaResponse & resp, uint8_t protocol)
+ LOG(D3) << std::endl << "Dumping reply buffer";
+ IFLOG(D3) DtaHexDump(cmd->getRespBuffer(), SWAP32(hdr->cp.length) + sizeof (OPALComPacket));
+ if (0 != lastRC) {
+- LOG(E) << "Command failed on recv" << (uint16_t) lastRC;
++ LOG(E) << "Command failed on recv, returned " << (uint16_t) lastRC;
+ return lastRC;
+ }
+ resp.init(cmd->getRespBuffer());
+@@ -1833,4 +1833,4 @@ uint8_t DtaDevOpal::rawCmd(char *sp, char * hexauth, char *pass,
+ delete session;
+ LOG(D1) << "Exiting DtaDevEnterprise::rawCmd";
+ return 0;
+-}
+\ No newline at end of file
++}
+diff --git a/Common/DtaHashPwd.cpp b/Common/DtaHashPwd.cpp
+index 1997393..d3b888a 100644
+--- a/Common/DtaHashPwd.cpp
++++ b/Common/DtaHashPwd.cpp
+@@ -32,8 +32,8 @@ extern "C" {
+ }
+ using namespace std;
+
+-void DtaHashPassword(vector &hash, char * password, vector salt,
+- unsigned int iter, uint8_t hashsize)
++void DtaHashPassword(vector &hash, const vector& password,
++ const vector& 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
+@@ -42,7 +42,7 @@ void DtaHashPassword(vector &hash, char * password, vector 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
+@@ -50,7 +50,7 @@ void DtaHashPassword(vector &hash, char * password, vector sal
+ 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(),
+@@ -67,21 +67,38 @@ void DtaHashPwd(vector &hash, char * password, DtaDev * d)
+ {
+ LOG(D1) << " Entered DtaHashPwd";
+ char *serNum;
++ vector 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 salt(serNum, serNum + 20);
+ // vector salt(DEFAULTSALT);
+- DtaHashPassword(hash, password, salt);
++ DtaHashPassword(hash, decoded_password, salt);
+ LOG(D1) << " Exit DtaHashPwd"; // log for hash timing
+ }
+
+@@ -109,7 +126,7 @@ int testresult(std::vector &result, const char * expected, size_t len)
+ int Testsedutil(const PBKDF_TestTuple *testSet, unsigned int testSetSize)
+ {
+ int pass = 1;
+- std::vector hash, seaSalt;
++ std::vector hash, seaSalt, password;
+
+ for (unsigned int i = 0; i < testSetSize; i++) {
+ const PBKDF_TestTuple &tuple = testSet[i];
+@@ -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;
+ }
+diff --git a/Common/DtaHashPwd.h b/Common/DtaHashPwd.h
+index 3815f7c..2e28497 100644
+--- a/Common/DtaHashPwd.h
++++ b/Common/DtaHashPwd.h
+@@ -41,7 +41,7 @@ void DtaHashPwd(vector &hash, char * password, DtaDev * device);
+ * @param iter number of iterations to be preformed
+ * @param hashsize size of hash to be returned
+ */
+-void DtaHashPassword(vector &hash, char * password, vector salt,
+- unsigned int iter = 75000, uint8_t hashsize = 32);
++void DtaHashPassword(vector &hash, const vector &password,
++ const vector &salt, unsigned int iter = 75000, uint8_t hashsize = 32);
+ /** Test the hshing function using publicly available test cased and report */
+ int TestPBKDF2();
+diff --git a/Common/DtaOptions.cpp b/Common/DtaOptions.cpp
+index fdacc40..91cc240 100644
+--- a/Common/DtaOptions.cpp
++++ b/Common/DtaOptions.cpp
+@@ -27,10 +27,11 @@ void usage()
+ printf("a utility to manage self encrypting drives that conform\n");
+ printf("to the Trusted Computing Group OPAL 2.0 SSC specification\n");
+ printf("General Usage: (see readme for extended commandset)\n");
+- printf("sedutil-cli <-v> <-n> \n");
++ printf("sedutil-cli <-v> <-n> <-x> \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");
+@@ -95,6 +96,12 @@ void usage()
+ printf(" revert the device using the PSID *ERASING* *ALL* the data \n");
+ printf("--printDefaultPassword \n");
+ printf(" print MSID \n");
++ printf("--printPasswordHash \n");
++ printf(" print the hash of the password \n");
++ printf(" as computed by sedutil. Hex-ecoded.\n");
++ printf("--prepareForS3Sleep <0...n> \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");
+@@ -140,6 +147,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))
+ {
+@@ -511,6 +522,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];
+diff --git a/Common/DtaOptions.h b/Common/DtaOptions.h
+index c012af1..669eef8 100644
+--- a/Common/DtaOptions.h
++++ b/Common/DtaOptions.h
+@@ -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 */
+@@ -95,6 +96,8 @@ typedef enum _sedutiloption {
+ validatePBKDF2,
+ objDump,
+ printDefaultPassword,
++ printPasswordHash,
++ prepareForS3Sleep,
+ rawCmd,
+
+ } sedutiloption;
+diff --git a/Common/sedutil.cpp b/Common/sedutil.cpp
+index fe6df19..4427e87 100644
+--- a/Common/sedutil.cpp
++++ b/Common/sedutil.cpp
+@@ -93,6 +93,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;
+ }
+
+@@ -259,6 +261,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]);
+diff --git a/Makefile.am b/Makefile.am
+index 6656d59..35b6aad 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -25,7 +25,8 @@ SEDUTIL_COMMON_CODE = Common/log.h \
+ Common/pbkdf2/bitops.h Common/pbkdf2/blockwise.h \
+ Common/pbkdf2/handy.h Common/pbkdf2/tassert.h
+ SEDUTIL_LINUX_CODE = \
+- linux/Version.h linux/os.h linux/DtaDevLinuxDrive.h \
++ linux/Version.h linux/os.h \
++ linux/DtaDevLinuxDrive.h linux/DtaDevLinuxDrive.cpp \
+ linux/DtaDevLinuxNvme.cpp linux/DtaDevLinuxSata.cpp \
+ linux/DtaDevLinuxNvme.h linux/DtaDevLinuxSata.h \
+ linux/DtaDevOS.cpp linux/DtaDevOS.h
+diff --git a/linux/DtaDevLinuxDrive.cpp b/linux/DtaDevLinuxDrive.cpp
+new file mode 100755
+index 0000000..dda4642
+--- /dev/null
++++ b/linux/DtaDevLinuxDrive.cpp
+@@ -0,0 +1,46 @@
++/* C:B**************************************************************************
++Copyright 2017, Alex Badics
++
++This file is part of sedutil.
++
++sedutil is free software: you can redistribute it and/or modify
++it under the terms of the GNU General Public License as published by
++the Free Software Foundation, either version 3 of the License, or
++(at your option) any later version.
++
++sedutil is distributed in the hope that it will be useful,
++but WITHOUT ANY WARRANTY; without even the implied warranty of
++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++GNU General Public License for more details.
++
++You should have received a copy of the GNU General Public License
++along with sedutil. If not, see .
++
++ * C:E********************************************************************** */
++#include "os.h"
++#include
++#include
++#include "DtaDevLinuxDrive.h"
++
++using namespace std;
++
++uint8_t DtaDevLinuxDrive::prepareForS3Sleep(uint8_t lockingrange, const vector &password_hash)
++{
++ LOG(D1) << "Entering DtaDevLinuxDrive::prepareForS3Sleep";
++
++ opal_lock_unlock opal_ioctl_data={};
++ opal_ioctl_data.l_state = OPAL_RW;
++ opal_ioctl_data.session.who = OPAL_ADMIN1;
++ opal_ioctl_data.session.opal_key.lr = lockingrange;
++
++ size_t hash_len=min(password_hash.size(), sizeof(opal_ioctl_data.session.opal_key.key));
++ LOG(D2) << "Setting a hash of length" << hash_len;
++
++ memcpy(opal_ioctl_data.session.opal_key.key, &password_hash[0], hash_len);
++ opal_ioctl_data.session.opal_key.key_len = hash_len;
++
++ int err = ioctl(fd, IOC_OPAL_SAVE, &opal_ioctl_data);
++ if (err < 0)
++ return errno;
++ return 0;
++}
+diff --git a/linux/DtaDevLinuxDrive.h b/linux/DtaDevLinuxDrive.h
+index d2022a1..39d1951 100755
+--- a/linux/DtaDevLinuxDrive.h
++++ b/linux/DtaDevLinuxDrive.h
+@@ -18,8 +18,10 @@ along with sedutil. If not, see .
+
+ * C:E********************************************************************** */
+ #pragma once
++#include
+ #include "DtaStructures.h"
+
++using namespace std;
+ /** virtual implementation for a disk interface-generic disk drive
+ */
+ class DtaDevLinuxDrive {
+@@ -45,4 +47,7 @@ public:
+ void * buffer, uint32_t bufferlen) = 0;
+ /** Routine to send an identify to the device */
+ virtual void identify(OPAL_DiskInfo& disk_info) = 0;
++ /** Save the password hash to the kernel for S3 sleep wakeup */
++ uint8_t prepareForS3Sleep(uint8_t lockingrange, const vector &password_hash);
++ int fd; /**< Linux handle for the device */
+ };
+diff --git a/linux/DtaDevLinuxNvme.h b/linux/DtaDevLinuxNvme.h
+index 3ea6874..b305a88 100755
+--- a/linux/DtaDevLinuxNvme.h
++++ b/linux/DtaDevLinuxNvme.h
+@@ -59,5 +59,4 @@ public:
+ void * buffer, uint32_t bufferlen);
+ /** NVMe specific routine to send an identify to the device */
+ void identify(OPAL_DiskInfo& disk_info);
+- int fd; /**< Linux handle for the device */
+ };
+diff --git a/linux/DtaDevLinuxSata.h b/linux/DtaDevLinuxSata.h
+index 14b7e12..6e19b44 100755
+--- a/linux/DtaDevLinuxSata.h
++++ b/linux/DtaDevLinuxSata.h
+@@ -55,6 +55,5 @@ public:
+ void * buffer, uint32_t bufferlen);
+ /** Linux specific routine to send an ATA identify to the device */
+ void identify_SAS(OPAL_DiskInfo *disk_info);
+- int fd; /**< Linux handle for the device */
+ int isSAS; /* The device is sas */
+ };
+diff --git a/linux/DtaDevOS.cpp b/linux/DtaDevOS.cpp
+index 5261e73..6ad6001 100644
+--- a/linux/DtaDevOS.cpp
++++ b/linux/DtaDevOS.cpp
+@@ -38,6 +38,9 @@ along with sedutil. If not, see .
+ #include "DtaDevLinuxSata.h"
+ #include "DtaDevLinuxNvme.h"
+ #include "DtaDevGeneric.h"
++#include "DtaHashPwd.h"
++#include "DtaSession.h"
++#include "DtaDevOpal.h"
+
+ using namespace std;
+
+@@ -165,6 +168,36 @@ int DtaDevOS::diskScan()
+ return 0;
+ }
+
++uint8_t DtaDevOS::prepareForS3Sleep(uint8_t lockingrange, char* password)
++{
++ LOG(D1) << "Entering DtaDevOS::prepareForS3Sleep ";
++ LOG(D2) << "Starting testing of password ";
++ session = new DtaSession(this);
++ if (NULL == session) {
++ LOG(E) << "Unable to create session object ";
++ return DTAERROR_OBJECT_CREATE_FAILED;
++ }
++ int err;
++ if ((err = session->start(OPAL_UID::OPAL_LOCKINGSP_UID, password, OPAL_UID::OPAL_ADMIN1_UID)) != 0) {
++ delete session;
++ LOG(E) << "Unable to authenticate with the given password";
++ return err;
++ }
++ delete session;
++ LOG(D2) << "Test successful, saving it to kernel ";
++ vector hash;
++ DtaHashPwd(hash, password, this);
++ hash.erase(hash.begin(), hash.begin()+2);
++
++ err = drive->prepareForS3Sleep(lockingrange, hash);
++ if (err)
++ {
++ LOG(E) << "Error saving the password to the kernel errno = " << errno;
++ return errno;
++ }
++ return 0;
++}
++
+ /** Close the device reference so this object can be delete. */
+ DtaDevOS::~DtaDevOS()
+ {
+diff --git a/linux/DtaDevOS.h b/linux/DtaDevOS.h
+index beeacb3..fc3705f 100644
+--- a/linux/DtaDevOS.h
++++ b/linux/DtaDevOS.h
+@@ -49,6 +49,8 @@ public:
+ void * buffer, uint32_t bufferlen);
+ /** A static class to scan for supported drives */
+ static int diskScan();
++ /** Save device key to kernel for S3 sleep resume */
++ uint8_t prepareForS3Sleep(uint8_t lockingrange, char* password);
+ protected:
+ /** OS specific command to Wait for specified number of milliseconds
+ * @param ms number of milliseconds to wait