Blob Blame History Raw
From b55cc396ce1a8e9e3961e8ad350a034ac5161348 Mon Sep 17 00:00:00 2001
From: Howard McLauchlan <hmclauchlan@fb.com>
Date: Tue, 16 Aug 2022 21:48:38 -0700
Subject: [PATCH 1/3] Shuffle GetPassPhrase{.h, .cpp} in makefile.am

Moving GetPassPhrase.o down into SEDUTIL_LINUX_CODE, since we need it
for the securemode/password-setting work.

This is fine since AFAICT linuxpba_SOURCES eventually gets consumed in
conjunction with SEDUTIL_LINUX_CODE, so that binary will get access to
the TU.

Keeping this as seperate commit since it might be a little bit subtle /
weird, depending on what Make is doing behind the scenes.

Signed-off-by: Howard McLauchlan <hmclauchlan@fb.com>
---
 Makefile.am | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index 6656d593..82c51010 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -28,7 +28,8 @@ SEDUTIL_LINUX_CODE = \
 	linux/Version.h linux/os.h linux/DtaDevLinuxDrive.h \
 	linux/DtaDevLinuxNvme.cpp linux/DtaDevLinuxSata.cpp \
 	linux/DtaDevLinuxNvme.h linux/DtaDevLinuxSata.h \
-	linux/DtaDevOS.cpp linux/DtaDevOS.h 
+	linux/DtaDevOS.cpp linux/DtaDevOS.h \
+	LinuxPBA/GetPassPhrase.cpp LinuxPBA/GetPassPhrase.h
 sbin_PROGRAMS = sedutil-cli linuxpba
 sedutil_cli_SOURCES = Common/sedutil.cpp Common/DtaOptions.cpp \
 	Common/DtaOptions.h \
@@ -37,8 +38,7 @@ sedutil_cli_SOURCES = Common/sedutil.cpp Common/DtaOptions.cpp \
 CLEANFILES = linux/Version.h
 BUILT_SOURCES = linux/Version.h
 #
-linuxpba_SOURCES = LinuxPBA/LinuxPBA.cpp LinuxPBA/GetPassPhrase.cpp LinuxPBA/UnlockSEDs.cpp \
-	LinuxPBA/GetPassPhrase.h LinuxPBA/UnlockSEDs.h \
+linuxpba_SOURCES = LinuxPBA/LinuxPBA.cpp LinuxPBA/UnlockSEDs.cpp LinuxPBA/UnlockSEDs.h \
 	$(SEDUTIL_LINUX_CODE) \
 	$(SEDUTIL_COMMON_CODE)
 EXTRA_DIST = linux/GitVersion.sh linux/PSIDRevert_LINUX.txt linux/TestSuite.sh README.md docs/sedutil-cli.8

From fc3c2d35a98de84b18b7d6a11f65070147b74024 Mon Sep 17 00:00:00 2001
From: Howard McLauchlan <hmclauchlan@fb.com>
Date: Tue, 16 Aug 2022 22:11:04 -0700
Subject: [PATCH 2/3] Add securemode/password-setting

*BASICALLY CLEANED UP VERSION OF https://github.com/Drive-Trust-Alliance/sedutil/pull/271*

This commit does what the linked PR says, and also fixes a few bugs in
that original PR. I'm not sure what the right way to give credit is and
it was very painful to resurrect CVE's original patches and roll my own
on top, so the disclaimer here is that it's like 95% his code :).

A few notable things:
* We don't need to modify the makefiles, since we split that out in the
  prior commit.
* We fixed his original makefile, which didn't quite work: that change
  is folded naturally into prior commit.
* The generated makefiles don't need to change, because since CVE's
  original patchset, GetPassPhrase.o was introduced organically to the
  codebase, and ergo the makefiles.

The most interesting thing here is we allow hashing to be forced off by
`-n` even during secure mode.

The key issue we ran into was that if a drive is originally set with no
hashing, then hash'd invocations in the future will fail(obviously). As
implemented, CVE's original patches will silently debug output, and then
turn on hashing without telling the user.

Not a domain expert in why hashing is necessary here, but in either
case, I think we should support the case where a password was originally
set without hashing, by allowing hashing to be turned off _if_ specified
explicitly.

We also do some sneaky business by ensuring -n is evaluated after -s, so
-n will always override -s, if provided.

Signed-off-by: Howard McLauchlan <hmclauchlan@fb.com>
---
 Common/DtaDev.h             |  16 +++--
 Common/DtaDevEnterprise.cpp |  30 ++++++---
 Common/DtaDevEnterprise.h   |  16 +++--
 Common/DtaDevGeneric.cpp    |  12 ++--
 Common/DtaDevGeneric.h      |  17 +++--
 Common/DtaDevOpal.cpp       | 128 ++++++++++++++++++++++++++++--------
 Common/DtaDevOpal.h         |  26 ++++++--
 Common/DtaOptions.cpp       | 112 ++++++++++++++++++-------------
 Common/DtaOptions.h         |  36 +++++++---
 Common/sedutil.cpp          |  81 ++++++++++++-----------
 linux/os.h                  |   2 +
 11 files changed, 319 insertions(+), 157 deletions(-)

diff --git a/Common/DtaDev.h b/Common/DtaDev.h
index 473f7bd0..c73c179e 100644
--- a/Common/DtaDev.h
+++ b/Common/DtaDev.h
@@ -111,8 +111,9 @@ class DtaDev {
 	/** User command to prepare the device for management by sedutil.
 	 * Specific to the SSC that the device supports
 	 * @param password the password that is to be assigned to the SSC master entities
+     * @param securemode is the new password should be interactively asked
 	 */
-	virtual uint8_t initialSetup(char * password) = 0;
+	virtual uint8_t initialSetup(char * password, bool securemode = false) = 0;
 	/** User command to prepare the drive for Single User Mode and rekey a SUM locking range.
 	 * @param lockingrange locking range number to enable
 	 * @param start LBA to start locking range
@@ -120,28 +121,30 @@ class DtaDev {
 	 * @param Admin1Password admin1 password for TPer
 	 * @param password User password to set for locking range
 	 */
-	virtual uint8_t setup_SUM(uint8_t lockingrange, uint64_t start, uint64_t length, char *Admin1Password, char * password) = 0;
+	virtual uint8_t setup_SUM(uint8_t lockingrange, uint64_t start, uint64_t length, char *Admin1Password, char * password, bool securemode = false) = 0;
 	/** Set the SID password.
 	 * Requires special handling because password is not always hashed.
 	 * @param oldpassword  current SID password
 	 * @param newpassword  value password is to be changed to
 	 * @param hasholdpwd  is the old password to be hashed before being added to the bytestream
 	 * @param hashnewpwd  is the new password to be hashed before being added to the bytestream
+     * @param securemode is the new password should be interactively asked
 	 */
 	virtual uint8_t setSIDPassword(char * oldpassword, char * newpassword,
-		uint8_t hasholdpwd = 1, uint8_t hashnewpwd = 1) = 0;
+		uint8_t hasholdpwd = 1, uint8_t hashnewpwd = 1, bool securemode = false) = 0;
 	/** Set the password of a locking SP user.
 	 * @param password  current password
 	 * @param userid the userid whose password is to be changed
 	 * @param newpassword  value password is to be changed to
+     * @param securemode is the new password shoulb be interactively asked
 	 */
-	virtual uint8_t setPassword(char * password, char * userid, char * newpassword) = 0;
+	virtual uint8_t setPassword(char * password, char * userid, char * newpassword, bool securemode = false) = 0;
 	/** Set the password of a locking SP user in Single User Mode.
          * @param password  current user password
          * @param userid the userid whose password is to be changed
          * @param newpassword  value password is to be changed to
          */
-	virtual uint8_t setNewPassword_SUM(char * password, char * userid, char * newpassword) = 0;
+	virtual uint8_t setNewPassword_SUM(char * password, char * userid, char * newpassword, bool securemode = false) = 0;
 	/** Loads a disk image file to the shadow MBR table.
 	 * @param password the password for the administrative authority with access to the table
 	 * @param filename the filename of the disk image
@@ -230,8 +233,9 @@ class DtaDev {
 	virtual uint8_t eraseLockingRange_SUM(uint8_t lockingrange, char * password) = 0;
 	/** Change the SID password from it's MSID default
 	 * @param newpassword  new password for SID and locking SP admins
+     * @param securemode is the new password should be interactively asked
 	 */
-	virtual uint8_t takeOwnership(char * newpassword) = 0;
+	virtual uint8_t takeOwnership(char * newpassword, bool securemode = false) = 0;
 	/** Reset the Locking SP to its factory default condition
 	 * ERASES ALL DATA!
 	 * @param password of Administrative user
diff --git a/Common/DtaDevEnterprise.cpp b/Common/DtaDevEnterprise.cpp
index ae649ec5..ba2e97a7 100644
--- a/Common/DtaDevEnterprise.cpp
+++ b/Common/DtaDevEnterprise.cpp
@@ -171,12 +171,12 @@ DtaDevEnterprise::DtaDevEnterprise(const char * devref)
 DtaDevEnterprise::~DtaDevEnterprise()
 {
 }
-uint8_t DtaDevEnterprise::initialSetup(char * password)
+uint8_t DtaDevEnterprise::initialSetup(char * password, bool securemode)
 {
 	LOG(D1) << "Entering initialSetup()";
 	uint8_t lastRC;
 
-	if ((lastRC = takeOwnership(password)) != 0) {
+	if ((lastRC = takeOwnership(password, securemode)) != 0) {
 		LOG(E) << "Initial setup failed - unable to take ownership";
 		return lastRC;
 	}
@@ -196,7 +196,7 @@ uint8_t DtaDevEnterprise::initialSetup(char * password)
 	LOG(D1) << "Exiting initialSetup()";
 	return 0;
 }
-uint8_t DtaDevEnterprise::setup_SUM(uint8_t lockingrange, uint64_t start, uint64_t length, char *Admin1Password, char * password)
+uint8_t DtaDevEnterprise::setup_SUM(uint8_t lockingrange, uint64_t start, uint64_t length, char *Admin1Password, char * password, bool securemode)
 {
 	LOG(D1) << "Entering DtaDevEnterprise::setup_SUM";
 	LOG(I) << "setup_SUM not supported on DtaDevEnterprise";
@@ -377,13 +377,18 @@ uint8_t DtaDevEnterprise::revertLockingSP(char * password, uint8_t keep)
 	LOG(D1) << "Exiting DtaDevEnterprise::revertLockingSP()";
 	return 0;
 }
-uint8_t DtaDevEnterprise::setPassword(char * password, char * userid, char * newpassword)
+uint8_t DtaDevEnterprise::setPassword(char * password, char * userid, char * newpassword, bool securemode)
 {
 	LOG(D1) << "Entering DtaDevEnterprise::setPassword" ;
-	uint8_t lastRC;
+	uint8_t lastRC = 0;
 	string defaultPassword;
 	char *pwd = password, *newpwd = newpassword;
 
+    if (securemode) {
+        LOG(I) << "setSIDPassword in secure mode in the Enterprise SSC is not supported";
+        return lastRC;
+    }
+
 	if (11 > strnlen(userid, 15)) {
 		LOG(E) << "Invalid Userid " << userid;
 		return DTAERROR_INVALID_PARAMETER;
@@ -463,7 +468,7 @@ uint8_t DtaDevEnterprise::setPassword(char * password, char * userid, char * new
 	LOG(D1) << "Exiting DtaDevEnterprise::setPassword()";
 	return 0;
 }
-uint8_t DtaDevEnterprise::setNewPassword_SUM(char * password, char * userid, char * newpassword)
+uint8_t DtaDevEnterprise::setNewPassword_SUM(char * password, char * userid, char * newpassword, bool securemode)
 {
 	LOG(D1) << "Entering DtaDevEnterprise::setNewPassword_SUM()";
 	LOG(I) << "setNewPassword_SUM is not in the Enterprise SSC and not supported";
@@ -1022,7 +1027,7 @@ uint8_t DtaDevEnterprise::eraseLockingRange_SUM(uint8_t lockingrange, char * pas
 	LOG(D1) << "Exiting DtaDevEnterprise::eraseLockingRange_SUM()";
 	return DTAERROR_INVALID_PARAMETER;
 }
-uint8_t DtaDevEnterprise::takeOwnership(char * newpassword)
+uint8_t DtaDevEnterprise::takeOwnership(char * newpassword, bool securemode)
 {
 	string defaultPassword;
 	uint8_t lastRC;
@@ -1033,7 +1038,7 @@ uint8_t DtaDevEnterprise::takeOwnership(char * newpassword)
 		return lastRC;
 	}
 	defaultPassword = response.getString(5);
-	if ((lastRC = setSIDPassword((char *)defaultPassword.c_str(), newpassword, 0)) != 0) {
+	if ((lastRC = setSIDPassword((char *)defaultPassword.c_str(), newpassword, 0, 1, securemode)) != 0) {
 		LOG(E) << "takeOwnership failed unable to set new SID password";
 		return lastRC;
 	}
@@ -1270,10 +1275,15 @@ uint8_t DtaDevEnterprise::printDefaultPassword()
     return 0;
 }
 uint8_t DtaDevEnterprise::setSIDPassword(char * oldpassword, char * newpassword,
-	uint8_t hasholdpwd, uint8_t hashnewpwd)
+	uint8_t hasholdpwd, uint8_t hashnewpwd, bool securemode)
 {
 	LOG(D1) << "Entering DtaDevEnterprise::setSIDPassword()";
-	uint8_t lastRC;
+	uint8_t lastRC = 0;
+
+    if (securemode) {
+        LOG(I) << "setSIDPassword in the Enterprise SSC is not supported";
+        return lastRC;
+    }
 
 	vector<uint8_t> user;
     set8(user, OPALUID[OPAL_SID_UID]);
diff --git a/Common/DtaDevEnterprise.h b/Common/DtaDevEnterprise.h
index 5350da5c..4a6d2e2e 100644
--- a/Common/DtaDevEnterprise.h
+++ b/Common/DtaDevEnterprise.h
@@ -57,8 +57,9 @@ class DtaDevEnterprise : public DtaDevOS {
 	uint16_t comID();
         /** Change the SID password from it's MSID default 
          * @param newpassword  new password for SID 
+         * @param securemode is the new password should be interactively asked
          */
-	uint8_t takeOwnership(char * newpassword);
+	uint8_t takeOwnership(char * newpassword, bool securemode = false);
         /** Change the passwords for the enabled Bandmasters and the Erasemaster 
          * from the MSID default.
          * @param defaultPassword the MSID password
@@ -80,9 +81,10 @@ class DtaDevEnterprise : public DtaDevOS {
          * @param newpassword  value password is to be changed to
          * @param hasholdpwd  is the old password to be hashed before being added to the bytestream
          * @param hashnewpwd  is the new password to be hashed before being added to the bytestream
+         * @param securemode is the new password should be interactively asked
          */ 
 	uint8_t setSIDPassword(char * oldpassword, char * newpassword,
-		uint8_t hasholdpwd = 1, uint8_t hashnewpwd = 1);
+		uint8_t hasholdpwd = 1, uint8_t hashnewpwd = 1, bool securemode = false);
         /** set a single column in an object table 
          * @param table the UID of the table
          * @param name the column name to be set
@@ -124,10 +126,11 @@ class DtaDevEnterprise : public DtaDevOS {
          * @param password  current password
          * @param userid the userid whose password is to be changed 
          * @param newpassword  value password is to be changed to
+         * @param securemode is the new password should be interactively asked
          */
-	uint8_t setPassword(char * password, char * userid, char * newpassword);
+	uint8_t setPassword(char * password, char * userid, char * newpassword, bool securemode = false);
 	/** dummy code not implemented in the enterprise SSC*/
-	uint8_t setNewPassword_SUM(char * password, char * userid, char * newpassword);
+	uint8_t setNewPassword_SUM(char * password, char * userid, char * newpassword, bool securemode = false);
 	uint8_t setLockingRange(uint8_t lockingrange, uint8_t lockingstate,
 		char * password);
 	/** dummy code not implemented in the enterprise SSC*/
@@ -180,10 +183,11 @@ class DtaDevEnterprise : public DtaDevOS {
          /** User command to prepare the device for management by sedutil. 
          * Specific to the SSC that the device supports
          * @param password the password that is to be assigned to the SSC master entities 
+         * @param securemode is the new password should be interactively asked
          */
-	uint8_t initialSetup(char * password);
+	uint8_t initialSetup(char * password, bool securemode = false);
 	/** dummy code not implemented in the enterprise SSC*/
-	uint8_t setup_SUM(uint8_t lockingrange, uint64_t start, uint64_t length, char *Admin1Password, char * password);
+	uint8_t setup_SUM(uint8_t lockingrange, uint64_t start, uint64_t length, char *Admin1Password, char * password, bool securemode = false);
         /** Displays the identify and discovery 0 information */
 	void puke();
          /** Dumps an object for diagnostic purposes
diff --git a/Common/DtaDevGeneric.cpp b/Common/DtaDevGeneric.cpp
index 6f5d57c6..8e1bdc91 100644
--- a/Common/DtaDevGeneric.cpp
+++ b/Common/DtaDevGeneric.cpp
@@ -62,13 +62,13 @@ DtaDevGeneric::~DtaDevGeneric()
 void DtaDevGeneric::init(const char * devref)
 {
 }
-uint8NOCODE(initialSetup, char *password)
+uint8NOCODE(initialSetup, char *password, bool securemode)
 uint8NOCODE(configureLockingRange,uint8_t lockingrange, 
 	uint8_t enabled, char * password)
 uint8NOCODE(revertLockingSP,char * password, uint8_t keep)
-uint8NOCODE(setup_SUM, uint8_t lockingrange, uint64_t start, uint64_t length, char *Admin1Password, char * password)
-uint8NOCODE(setPassword,char * password, char * userid, char * newpassword)
-uint8NOCODE(setNewPassword_SUM,char * password, char * userid, char * newpassword)
+uint8NOCODE(setup_SUM, uint8_t lockingrange, uint64_t start, uint64_t length, char *Admin1Password, char * password, bool securemode)
+uint8NOCODE(setPassword,char * password, char * userid, char * newpassword, bool securemode)
+uint8NOCODE(setNewPassword_SUM,char * password, char * userid, char * newpassword, bool securemode)
 uint8NOCODE(setMBREnable,uint8_t mbrstate, char * Admin1Password)
 uint8NOCODE(setMBRDone,uint8_t mbrstate, char * Admin1Password)
 uint8NOCODE(setLockingRange,uint8_t lockingrange, uint8_t lockingstate,
@@ -90,9 +90,9 @@ uint8NOCODE(loadPBA,char * password, char * filename)
 uint8NOCODE(activateLockingSP,char * password)
 uint8NOCODE(activateLockingSP_SUM,uint8_t lockingrange, char * password)
 uint8NOCODE(eraseLockingRange_SUM, uint8_t lockingrange, char * password)
-uint8NOCODE(takeOwnership, char * newpassword)
+uint8NOCODE(takeOwnership, char * newpassword, bool securemode)
 uint8NOCODE(setSIDPassword,char * oldpassword, char * newpassword,
-	uint8_t hasholdpwd, uint8_t hashnewpwd)
+	uint8_t hasholdpwd, uint8_t hashnewpwd, bool securemode)
 uint16_t DtaDevGeneric::comID()
 {
 	LOG(E) << "Generic Device class does not support function " << "comID" << std::endl; 
diff --git a/Common/DtaDevGeneric.h b/Common/DtaDevGeneric.h
index 9f5f9752..07728781 100644
--- a/Common/DtaDevGeneric.h
+++ b/Common/DtaDevGeneric.h
@@ -56,36 +56,40 @@ class DtaDevGeneric : public DtaDevOS {
          * Specific to the SSC that the device supports
          * @param password the password that is to be assigned to the SSC master entities 
          */
-	 uint8_t initialSetup(char * password) ;
+	 uint8_t initialSetup(char * password, bool securemode) ;
 	/** User command to prepare the drive for Single User Mode and rekey a SUM locking range.
          * @param lockingrange locking range number to enable
          * @param start LBA to start locking range
          * @param length length (in blocks) for locking range
          * @param Admin1Password admin1 password for TPer
          * @param password User password to set for locking range
+         * @param securemode is the new password shoulb be interactively asked
          */
-         uint8_t setup_SUM(uint8_t lockingrange, uint64_t start, uint64_t length, char *Admin1Password, char * password);
+         uint8_t setup_SUM(uint8_t lockingrange, uint64_t start, uint64_t length, char *Admin1Password, char * password, bool securemode = false);
           /** Set the SID password.
          * Requires special handling because password is not always hashed.
          * @param oldpassword  current SID password
          * @param newpassword  value password is to be changed to
          * @param hasholdpwd  is the old password to be hashed before being added to the bytestream
          * @param hashnewpwd  is the new password to be hashed before being added to the bytestream
+         * @param securemode is the new password shoulb be interactively asked
          */ 
 	 uint8_t setSIDPassword(char * oldpassword, char * newpassword,
-		uint8_t hasholdpwd = 1, uint8_t hashnewpwd = 1) ;
+		uint8_t hasholdpwd = 1, uint8_t hashnewpwd = 1, bool securemode = false) ;
          /** Set the password of a locking SP user.
           * @param password  current password
          * @param userid the userid whose password is to be changed 
          * @param newpassword  value password is to be changed to
+         * @param securemode is the new password should be interactively asked
          */
-	 uint8_t setPassword(char * password, char * userid, char * newpassword) ;
+	 uint8_t setPassword(char * password, char * userid, char * newpassword, bool securemode = false) ;
 	 /** Set the password of a locking SP user in Single User Mode.
          * @param password  current user password
          * @param userid the userid whose password is to be changed
          * @param newpassword  value password is to be changed to
+         * @param securemode is the new password should be interactively asked
          */
-	 uint8_t setNewPassword_SUM(char * password, char * userid, char * newpassword) ;
+	 uint8_t setNewPassword_SUM(char * password, char * userid, char * newpassword, bool securemode = false) ;
           /** Loads a disk image file to the shadow MBR table.
          * @param password the password for the administrative authority with access to the table
          * @param filename the filename of the disk image
@@ -174,8 +178,9 @@ class DtaDevGeneric : public DtaDevOS {
         uint8_t eraseLockingRange_SUM(uint8_t lockingrange, char * password);
         /** Change the SID password from it's MSID default 
          * @param newpassword  new password for SID and locking SP admins
+         * @param securemode is the new password should be interactively asked
          */ 
-	 uint8_t takeOwnership(char * newpassword) ;
+	 uint8_t takeOwnership(char * newpassword, bool securemode = false) ;
          /** Reset the Locking SP to its factory default condition
          * ERASES ALL DATA!
          * @param password of Administrative user
diff --git a/Common/DtaDevOpal.cpp b/Common/DtaDevOpal.cpp
index 1cb5701a..0f6ccc70 100644
--- a/Common/DtaDevOpal.cpp
+++ b/Common/DtaDevOpal.cpp
@@ -50,31 +50,43 @@ void DtaDevOpal::init(const char * devref)
 	if((lastRC = properties()) != 0) { LOG(E) << "Properties exchange failed";}
 }
 
-uint8_t DtaDevOpal::initialSetup(char * password)
+uint8_t DtaDevOpal::initialSetup(char * password, bool securemode)
 {
 	LOG(D1) << "Entering initialSetup()";
+    std::string newpwd;
 	uint8_t lastRC;
-	if ((lastRC = takeOwnership(password)) != 0) {
+
+#ifdef __linux__
+    if (securemode) {
+        if (askNewPassword(newpwd, true) != OPALSTATUSCODE::SUCCESS) {
+            LOG(E) << "Wrong password confirmation. Failure of password update.";
+            lastRC =  OPALSTATUSCODE::FAIL;
+            return lastRC;
+        }
+    }
+#endif
+
+	if ((lastRC = takeOwnership((securemode)?(char*)newpwd.c_str():password)) != 0) {
 		LOG(E) << "Initial setup failed - unable to take ownership";
 		return lastRC;
 	}
-	if ((lastRC = activateLockingSP(password)) != 0) {
+	if ((lastRC = activateLockingSP((securemode)?(char*)newpwd.c_str():password)) != 0) {
 		LOG(E) << "Initial setup failed - unable to activate LockingSP";
 		return lastRC;
 	}
-	if ((lastRC = configureLockingRange(0, DTA_DISABLELOCKING, password)) != 0) {
+	if ((lastRC = configureLockingRange(0, DTA_DISABLELOCKING, (securemode)?(char*)newpwd.c_str():password)) != 0) {
 		LOG(E) << "Initial setup failed - unable to configure global locking range";
 		return lastRC;
 	}
-	if ((lastRC = setLockingRange(0, OPAL_LOCKINGSTATE::READWRITE, password)) != 0) {
+	if ((lastRC = setLockingRange(0, OPAL_LOCKINGSTATE::READWRITE, (securemode)?(char*)newpwd.c_str():password)) != 0) {
 		LOG(E) << "Initial setup failed - unable to set global locking range RW";
 		return lastRC;
 	}
-	if ((lastRC = setMBRDone(1, password)) != 0){
+	if ((lastRC = setMBRDone(1, (securemode)?(char*)newpwd.c_str():password)) != 0){
 		LOG(E) << "Initial setup failed - unable to Enable MBR shadow";
 		return lastRC;
 	}
-	if ((lastRC = setMBREnable(1, password)) != 0){
+	if ((lastRC = setMBREnable(1, (securemode)?(char*)newpwd.c_str():password)) != 0){
 		LOG(E) << "Initial setup failed - unable to Enable MBR shadow";
 		return lastRC;
 	}
@@ -84,7 +96,7 @@ uint8_t DtaDevOpal::initialSetup(char * password)
 	return 0;
 }
 
-uint8_t DtaDevOpal::setup_SUM(uint8_t lockingrange, uint64_t start, uint64_t length, char *Admin1Password, char * password)
+uint8_t DtaDevOpal::setup_SUM(uint8_t lockingrange, uint64_t start, uint64_t length, char *Admin1Password, char * password, bool securemode)
 {
 	LOG(D1) << "Entering setup_SUM()";
 	uint8_t lastRC;
@@ -108,7 +120,7 @@ uint8_t DtaDevOpal::setup_SUM(uint8_t lockingrange, uint64_t start, uint64_t len
 	if (!disk_info.Locking_lockingEnabled)
 	{
 		LOG(D1) << "LockingSP not enabled. Beginning initial setup flow.";
-		if ((lastRC = takeOwnership(Admin1Password)) != 0) {
+		if ((lastRC = takeOwnership(Admin1Password, securemode)) != 0) {
 			LOG(E) << "Setup_SUM failed - unable to take ownership";
 			return lastRC;
 		}
@@ -147,7 +159,7 @@ uint8_t DtaDevOpal::setup_SUM(uint8_t lockingrange, uint64_t start, uint64_t len
 		LOG(E) << "Setup_SUM failed - unable to enable locking range";
 		return lastRC;
 	}
-	if ((lastRC = setNewPassword_SUM(defaultPW, (char *)userId.c_str(), password)) != 0) {
+	if ((lastRC = setNewPassword_SUM(defaultPW, (char *)userId.c_str(), password, securemode)) != 0) {
 		LOG(E) << "Setup_SUM failed - unable to set new locking range password";
 		return lastRC;
 	}
@@ -688,12 +700,13 @@ uint8_t DtaDevOpal::getAuth4User(char * userid, uint8_t uidorcpin, std::vector<u
 	LOG(D1) << "Exiting DtaDevOpal::getAuth4User()";
 	return 0;
 }
-uint8_t DtaDevOpal::setPassword(char * password, char * userid, char * newpassword)
+uint8_t DtaDevOpal::setPassword(char * password, char * userid, char * newpassword, bool securemode)
 {
 	LOG(D1) << "Entering DtaDevOpal::setPassword" ;
 	uint8_t lastRC;
 	std::vector<uint8_t> userCPIN, hash;
 	session = new DtaSession(this);
+
 	if (NULL == session) {
 		LOG(E) << "Unable to create session object ";
 		return DTAERROR_OBJECT_CREATE_FAILED;
@@ -707,7 +720,28 @@ uint8_t DtaDevOpal::setPassword(char * password, char * userid, char * newpasswo
 		delete session;
 		return lastRC;
 	}
-	DtaHashPwd(hash, newpassword, this);
+
+    // Ask and confirm new password
+#ifdef __linux__
+    if (securemode) {
+        std::string newpwd;
+        if (askNewPassword(newpwd, true) == OPALSTATUSCODE::SUCCESS) {
+            DtaHashPwd(hash, (char*)newpwd.c_str(), this);
+        }
+        else {
+            LOG(E) << "Wrong password confirmation. Failure of password update.";
+            delete session;
+            lastRC =  OPALSTATUSCODE::FAIL;
+            return lastRC;
+        }
+    }
+    else {
+#endif //__linux__
+        DtaHashPwd(hash, newpassword, this);
+#ifdef __linux__
+    }
+#endif //__linux__
+
 	if ((lastRC = setTable(userCPIN, OPAL_TOKEN::PIN, hash)) != 0) {
 		LOG(E) << "Unable to set user " << userid << " new password ";
 		delete session;
@@ -718,7 +752,7 @@ uint8_t DtaDevOpal::setPassword(char * password, char * userid, char * newpasswo
 	LOG(D1) << "Exiting DtaDevOpal::setPassword()";
 	return 0;
 }
-uint8_t DtaDevOpal::setNewPassword_SUM(char * password, char * userid, char * newpassword)
+uint8_t DtaDevOpal::setNewPassword_SUM(char * password, char * userid, char * newpassword, bool securemode)
 {
 	LOG(D1) << "Entering DtaDevOpal::setNewPassword_SUM";
 	uint8_t lastRC;
@@ -1391,7 +1425,7 @@ uint8_t DtaDevOpal::eraseLockingRange_SUM(uint8_t lockingrange, char * password)
 	return 0;
 }
 
-uint8_t DtaDevOpal::takeOwnership(char * newpassword)
+uint8_t DtaDevOpal::takeOwnership(char * newpassword, bool securemode)
 {
 	LOG(D1) << "Entering DtaDevOpal::takeOwnership()";
 	uint8_t lastRC;
@@ -1399,7 +1433,7 @@ uint8_t DtaDevOpal::takeOwnership(char * newpassword)
 		LOG(E) << "Unable to read MSID password ";
 		return lastRC;
 	}
-	if ((lastRC = setSIDPassword((char *)response.getString(4).c_str(), newpassword, 0)) != 0) {
+	if ((lastRC = setSIDPassword((char *)response.getString(4).c_str(), newpassword, 0, 1, securemode)) != 0) {
 		LOG(E) << "takeOwnership failed";
 		return lastRC;
 	}
@@ -1447,7 +1481,7 @@ uint8_t DtaDevOpal::printDefaultPassword()
     return 0;
 }
 uint8_t DtaDevOpal::setSIDPassword(char * oldpassword, char * newpassword,
-	uint8_t hasholdpwd, uint8_t hashnewpwd)
+	uint8_t hasholdpwd, uint8_t hashnewpwd, bool securemode)
 {
 	vector<uint8_t> hash, table;
 	LOG(D1) << "Entering DtaDevOpal::setSIDPassword()";
@@ -1468,17 +1502,39 @@ uint8_t DtaDevOpal::setSIDPassword(char * oldpassword, char * newpassword,
 	for (int i = 0; i < 8; i++) {
 		table.push_back(OPALUID[OPAL_UID::OPAL_C_PIN_SID][i]);
 	}
+
 	hash.clear();
-	if (hashnewpwd) {
-		DtaHashPwd(hash, newpassword, this);
-	}
-	else {
-		hash.push_back(0xd0);
-		hash.push_back((uint8_t)strnlen(newpassword, 255));
-		for (uint16_t i = 0; i < strnlen(newpassword, 255); i++) {
-			hash.push_back(newpassword[i]);
-		}
-	}
+
+#ifdef __linux__
+    if (securemode) {
+        // In secure mode, the password hashing is mandatory
+        std::string newpwd;
+        if (askNewPassword(newpwd, true) == OPALSTATUSCODE::SUCCESS) {
+            DtaHashPwd(hash, (char*)newpwd.c_str(), this);
+        }
+        else {
+            LOG(E) << "Wrong password confirmation. Failure of password update.";
+            delete session;
+            lastRC =  DTAERROR_INVALID_PARAMETER;
+            return lastRC;
+        }
+    }
+    else {
+#endif //__linux__
+        if (hashnewpwd) {
+            DtaHashPwd(hash, newpassword, this);
+        }
+        else {
+            hash.push_back(0xd0);
+            hash.push_back((uint8_t)strnlen(newpassword, 255));
+            for (uint16_t i = 0; i < strnlen(newpassword, 255); i++) {
+                hash.push_back(newpassword[i]);
+            }
+        }
+#ifdef __linux__
+    }
+#endif //__linux__
+
 	if ((lastRC = setTable(table, OPAL_TOKEN::PIN, hash)) != 0) {
 		LOG(E) << "Unable to set new SID password ";
 		delete session;
@@ -1833,4 +1889,22 @@ 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
+}
+#ifdef __linux__
+uint8_t DtaDevOpal::askNewPassword(std::string &password, bool confirm) {
+    uint8_t lastRC = OPALSTATUSCODE::SUCCESS;
+    password = GetPassPhrase("Please enter the new password ");
+
+    if (confirm) {
+        std::string pwdcheck = GetPassPhrase("Please confirm the new password ");
+
+        if (password != pwdcheck) {
+            password.clear();
+            lastRC = OPALSTATUSCODE::FAIL;
+        }
+    }
+
+    return lastRC;
+}
+#endif //__linux__
+
diff --git a/Common/DtaDevOpal.h b/Common/DtaDevOpal.h
index 60004db4..389b97f9 100644
--- a/Common/DtaDevOpal.h
+++ b/Common/DtaDevOpal.h
@@ -61,8 +61,9 @@ class DtaDevOpal : public DtaDevOS {
 	virtual uint16_t comID() = 0;
         /** Change the SID password from it's MSID default 
          * @param newpassword  new password for SID 
+         * @param securemode is the new password should be interactively asked
          */
-	uint8_t takeOwnership(char * newpassword);
+	uint8_t takeOwnership(char * newpassword, bool securemode = false);
         /** retrieve the MSID password */
 	uint8_t printDefaultPassword();
         /** retrieve a single row from a table 
@@ -78,9 +79,10 @@ class DtaDevOpal : public DtaDevOS {
          * @param newpassword  value password is to be changed to
          * @param hasholdpwd  is the old password to be hashed before being added to the bytestream
          * @param hashnewpwd  is the new password to be hashed before being added to the bytestream
+         * @param securemode is the new password should be interactively asked
          */ 
 	uint8_t setSIDPassword(char * oldpassword, char * newpassword,
-		uint8_t hasholdpwd = 1, uint8_t hashnewpwd = 1);
+		uint8_t hasholdpwd = 1, uint8_t hashnewpwd = 1, bool securemode = false);
          /** set a single column in an object table 
          * @param table the UID of the table
          * @param name the column name to be set
@@ -143,14 +145,16 @@ class DtaDevOpal : public DtaDevOS {
          * @param password  current password
          * @param userid the userid whose password is to be changed 
          * @param newpassword  value password is to be changed to
+         * @param securemode is the new password should be interactively asked
          */
-	uint8_t setPassword(char * password, char * userid, char * newpassword);
+	uint8_t setPassword(char * password, char * userid, char * newpassword, bool securemode = false);
 	/** Set the password of a locking SP user in Single User Mode.
          * @param password  current user password
          * @param userid the userid whose password is to be changed
          * @param newpassword  value password is to be changed to
+         * @param securemode is the new password should be interactively asked
          */
-	uint8_t setNewPassword_SUM(char * password, char * userid, char * newpassword);
+	uint8_t setNewPassword_SUM(char * password, char * userid, char * newpassword, bool securemode = false);
         /** User command to manipulate the state of a locking range.
          * RW|RO|LK are the supported states @see OPAL_LOCKINGSTATE
          * @param lockingrange locking range number
@@ -229,16 +233,18 @@ class DtaDevOpal : public DtaDevOS {
         /** User command to prepare the device for management by sedutil. 
          * Specific to the SSC that the device supports
          * @param password the password that is to be assigned to the SSC master entities 
+         * @param securemode is the new password should be interactively asked
          */
-	uint8_t initialSetup(char * password);
+	uint8_t initialSetup(char * password, bool securemode);
 	/** User command to prepare the drive for Single User Mode and rekey a SUM locking range.
          * @param lockingrange locking range number to enable
          * @param start LBA to start locking range
          * @param length length (in blocks) for locking range
          * @param Admin1Password admin1 password for TPer
          * @param password User password to set for locking range
+         * @param securemode is the new password should be interactively asked
          */
-        uint8_t setup_SUM(uint8_t lockingrange, uint64_t start, uint64_t length, char *Admin1Password, char * password);
+        uint8_t setup_SUM(uint8_t lockingrange, uint64_t start, uint64_t length, char *Admin1Password, char * password, bool securemode = false);
           /** Displays the identify and discovery 0 information */
 	void puke();
          /** Dumps an object for diagnostic purposes
@@ -289,4 +295,12 @@ class DtaDevOpal : public DtaDevOS {
 	 */
 	lrStatus_t getLockingRange_status(uint8_t lockingrange, char * password);
 
+    /** Ask the user to input a new password.
+      * This function fails if the first password and it's confirmation differs
+      * @param password The new password entered by the user
+      * @param confirm Is a double check necessary
+      */
+#ifdef __linux__
+    uint8_t askNewPassword(std::string &password, bool confirm = false);
+#endif //__linux__
 };
diff --git a/Common/DtaOptions.cpp b/Common/DtaOptions.cpp
index fdacc403..0d1752ee 100644
--- a/Common/DtaOptions.cpp
+++ b/Common/DtaOptions.cpp
@@ -27,8 +27,10 @@ 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> <action> <options> <device>\n");
+    printf("sedutil-cli <-v> <-n> <-s> <action> <options> <device>\n");
     printf("-v (optional)                       increase verbosity, one to five v's\n");
+    printf("-s (optional)                       secure mode. Passwords will be asked interactively to the user.\n");
+    printf("                                    Available only on linux.\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("actions \n");
@@ -130,11 +132,31 @@ uint8_t DtaOptions(int argc, char * argv[], DTA_OPTIONS * opts)
 			LOG(D) << "Log level set to " << CLog::ToString(CLog::FromInt(loggingLevel));
 			LOG(D) << "sedutil version : " << GIT_VERSION;
 		}
+        else if (!(strcmp("-s", argv[i]))) {
+            baseOptions += 1;
+#ifdef __linux__
+            opts->secure_mode = true;
+            opts->no_hash_passwords = false;
+#else
+            LOG(E) << "Secure mode not implemented";
+#endif //__linux__
+        }
 		else if (!(strcmp("-n", argv[i]))) {
-                        baseOptions += 1;
-			opts->no_hash_passwords = true;
-			LOG(D) << "Password hashing is disabled";
-                }
+            baseOptions += 1;
+#ifdef __linux__
+            if (!opts->secure_mode) {
+#endif //__linux__
+                opts->no_hash_passwords = true;
+                LOG(D) << "Password hashing is disabled";
+#ifdef __linux__
+            }
+            else {
+                LOG(D) << "No password hashing incompatible with secure mode";
+            }
+            LOG(D) << "Disabling password hashing in secure mode (-s)";
+            opts->no_hash_passwords = true;
+#endif //__linux__
+        }
 		else if (!strcmp("-l", argv[i])) {
 			baseOptions += 1;
 			opts->output_format = sedutilNormal;
@@ -146,10 +168,10 @@ uint8_t DtaOptions(int argc, char * argv[], DTA_OPTIONS * opts)
 			LOG(E) << "Argument " << (uint16_t) i << " (" << argv[i] << ") should be a command";
 			return DTAERROR_INVALID_COMMAND;
 		}
-		BEGIN_OPTION(initialSetup, 2) OPTION_IS(password) OPTION_IS(device) END_OPTION
-		BEGIN_OPTION(setSIDPassword, 3) OPTION_IS(password) OPTION_IS(newpassword) 
+		BEGIN_OPTION(initialSetup, 2, 1) OPTION_IS(password) OPTION_IS(device) END_OPTION
+		BEGIN_OPTION(setSIDPassword, 3, 1) OPTION_IS(password) OPTION_IS(newpassword)
 		         OPTION_IS(device) END_OPTION
-		BEGIN_OPTION(setup_SUM, 6)
+		BEGIN_OPTION(setup_SUM, 6, 4)
 			TESTARG(0, lockingrange, 0)
 			TESTARG(1, lockingrange, 1)
 			TESTARG(2, lockingrange, 2)
@@ -173,20 +195,20 @@ uint8_t DtaOptions(int argc, char * argv[], DTA_OPTIONS * opts)
 			OPTION_IS(newpassword)
 			OPTION_IS(device)
 			END_OPTION
-		BEGIN_OPTION(setAdmin1Pwd, 3) OPTION_IS(password) OPTION_IS(newpassword) 
+		BEGIN_OPTION(setAdmin1Pwd, 3, 1) OPTION_IS(password) OPTION_IS(newpassword)
 			OPTION_IS(device) END_OPTION
-		BEGIN_OPTION(loadPBAimage, 3) OPTION_IS(password) OPTION_IS(pbafile) 
+		BEGIN_OPTION(loadPBAimage, 3, 2) OPTION_IS(password) OPTION_IS(pbafile)
 			OPTION_IS(device) END_OPTION
-		BEGIN_OPTION(revertTPer, 2) OPTION_IS(password) OPTION_IS(device) END_OPTION
-		BEGIN_OPTION(revertNoErase, 2) OPTION_IS(password) OPTION_IS(device) END_OPTION
-		BEGIN_OPTION(PSIDrevert, 2) OPTION_IS(password) OPTION_IS(device) END_OPTION
-		BEGIN_OPTION(PSIDrevertAdminSP, 2) OPTION_IS(password) OPTION_IS(device) END_OPTION
-		BEGIN_OPTION(yesIreallywanttoERASEALLmydatausingthePSID, 2) OPTION_IS(password) 
+		BEGIN_OPTION(revertTPer, 2, 1) OPTION_IS(password) OPTION_IS(device) END_OPTION
+		BEGIN_OPTION(revertNoErase, 2, 1) OPTION_IS(password) OPTION_IS(device) END_OPTION
+		BEGIN_OPTION(PSIDrevert, 2, 1) OPTION_IS(password) OPTION_IS(device) END_OPTION
+		BEGIN_OPTION(PSIDrevertAdminSP, 2, 1) OPTION_IS(password) OPTION_IS(device) END_OPTION
+		BEGIN_OPTION(yesIreallywanttoERASEALLmydatausingthePSID, 2, 1) OPTION_IS(password)
 			OPTION_IS(device) END_OPTION
-		BEGIN_OPTION(enableuser, 2) OPTION_IS(password) OPTION_IS(userid) 
+		BEGIN_OPTION(enableuser, 3, 2) OPTION_IS(password) OPTION_IS(userid)
 			OPTION_IS(device) END_OPTION
-		BEGIN_OPTION(activateLockingSP, 2) OPTION_IS(password) OPTION_IS(device) END_OPTION
-		BEGIN_OPTION(activateLockingSP_SUM, 3)
+		BEGIN_OPTION(activateLockingSP, 2, 1) OPTION_IS(password) OPTION_IS(device) END_OPTION
+		BEGIN_OPTION(activateLockingSP_SUM, 3, 2)
 			TESTARG(0, lockingrange, 0)
 			TESTARG(1, lockingrange, 1)
 			TESTARG(2, lockingrange, 2)
@@ -205,7 +227,7 @@ uint8_t DtaOptions(int argc, char * argv[], DTA_OPTIONS * opts)
 			TESTARG(15, lockingrange, 15)
 			TESTFAIL("Invalid Locking Range (0-15)")
 			OPTION_IS(password) OPTION_IS(device) END_OPTION
-		BEGIN_OPTION(eraseLockingRange_SUM, 3)
+		BEGIN_OPTION(eraseLockingRange_SUM, 3, 2)
 			TESTARG(0, lockingrange, 0)
 			TESTARG(1, lockingrange, 1)
 			TESTARG(2, lockingrange, 2)
@@ -224,10 +246,10 @@ uint8_t DtaOptions(int argc, char * argv[], DTA_OPTIONS * opts)
 			TESTARG(15, lockingrange, 15)
 			TESTFAIL("Invalid Locking Range (1-15)")
 			OPTION_IS(password) OPTION_IS(device) END_OPTION
-		BEGIN_OPTION(query, 1) OPTION_IS(device) END_OPTION
-		BEGIN_OPTION(scan, 0)  END_OPTION
-		BEGIN_OPTION(isValidSED, 1) OPTION_IS(device) END_OPTION
-		BEGIN_OPTION(eraseLockingRange, 3)
+		BEGIN_OPTION(query, 1, 1) OPTION_IS(device) END_OPTION
+		BEGIN_OPTION(scan, 0, 0)  END_OPTION
+		BEGIN_OPTION(isValidSED, 1, 1) OPTION_IS(device) END_OPTION
+		BEGIN_OPTION(eraseLockingRange, 3, 2)
 			TESTARG(0, lockingrange, 0)
 			TESTARG(1, lockingrange, 1)
 			TESTARG(2, lockingrange, 2)
@@ -248,14 +270,14 @@ uint8_t DtaOptions(int argc, char * argv[], DTA_OPTIONS * opts)
 			OPTION_IS(password)
 			OPTION_IS(device)
 			END_OPTION
-		BEGIN_OPTION(takeOwnership, 2) OPTION_IS(password) OPTION_IS(device) END_OPTION
-		BEGIN_OPTION(revertLockingSP, 2) OPTION_IS(password) OPTION_IS(device) END_OPTION
-		BEGIN_OPTION(setPassword, 4) OPTION_IS(password) OPTION_IS(userid)
+		BEGIN_OPTION(takeOwnership, 2, 1) OPTION_IS(password) OPTION_IS(device) END_OPTION
+		BEGIN_OPTION(revertLockingSP, 2, 1) OPTION_IS(password) OPTION_IS(device) END_OPTION
+		BEGIN_OPTION(setPassword, 4, 2) OPTION_IS(password) OPTION_IS(userid)
 			OPTION_IS(newpassword) OPTION_IS(device) END_OPTION
-		BEGIN_OPTION(setPassword_SUM, 4) OPTION_IS(password) OPTION_IS(userid)
+		BEGIN_OPTION(setPassword_SUM, 4, 2) OPTION_IS(password) OPTION_IS(userid)
 			OPTION_IS(newpassword) OPTION_IS(device) END_OPTION
-		BEGIN_OPTION(validatePBKDF2, 0) END_OPTION
-		BEGIN_OPTION(setMBREnable, 3)
+		BEGIN_OPTION(validatePBKDF2, 0, 0) END_OPTION
+		BEGIN_OPTION(setMBREnable, 3, 2)
 			TESTARG(ON, mbrstate, 1)
 			TESTARG(on, mbrstate, 1)
 			TESTARG(off, mbrstate, 0)
@@ -264,7 +286,7 @@ uint8_t DtaOptions(int argc, char * argv[], DTA_OPTIONS * opts)
 			OPTION_IS(password)
 			OPTION_IS(device)
 			END_OPTION
-		BEGIN_OPTION(setMBRDone, 3)
+		BEGIN_OPTION(setMBRDone, 3, 2)
 			TESTARG(ON, mbrstate, 1)
 			TESTARG(on, mbrstate, 1)
 			TESTARG(off, mbrstate, 0)
@@ -273,7 +295,7 @@ uint8_t DtaOptions(int argc, char * argv[], DTA_OPTIONS * opts)
 			OPTION_IS(password)
 			OPTION_IS(device)
 			END_OPTION
-		BEGIN_OPTION(setLockingRange, 4)
+		BEGIN_OPTION(setLockingRange, 4, 3)
 			TESTARG(0, lockingrange, 0)
 			TESTARG(1, lockingrange, 1)
 			TESTARG(2, lockingrange, 2)
@@ -301,7 +323,7 @@ uint8_t DtaOptions(int argc, char * argv[], DTA_OPTIONS * opts)
 			OPTION_IS(password)
 			OPTION_IS(device)
 			END_OPTION
-		BEGIN_OPTION(setLockingRange_SUM, 4)
+		BEGIN_OPTION(setLockingRange_SUM, 4, 3)
 			TESTARG(0, lockingrange, 0)
 			TESTARG(1, lockingrange, 1)
 			TESTARG(2, lockingrange, 2)
@@ -329,7 +351,7 @@ uint8_t DtaOptions(int argc, char * argv[], DTA_OPTIONS * opts)
 			OPTION_IS(password)
 			OPTION_IS(device)
 			END_OPTION
-		BEGIN_OPTION(enableLockingRange, 3)
+		BEGIN_OPTION(enableLockingRange, 3, 2)
 			TESTARG(0, lockingrange, 0)
 			TESTARG(1, lockingrange, 1)
 			TESTARG(2, lockingrange, 2)
@@ -350,7 +372,7 @@ uint8_t DtaOptions(int argc, char * argv[], DTA_OPTIONS * opts)
 			OPTION_IS(password)
 			OPTION_IS(device)
 			END_OPTION
-		BEGIN_OPTION(disableLockingRange, 3)
+		BEGIN_OPTION(disableLockingRange, 3, 2)
 			TESTARG(0, lockingrange, 0)
 			TESTARG(1, lockingrange, 1)
 			TESTARG(2, lockingrange, 2)
@@ -371,7 +393,7 @@ uint8_t DtaOptions(int argc, char * argv[], DTA_OPTIONS * opts)
 			OPTION_IS(password)
 			OPTION_IS(device)
 			END_OPTION
-		BEGIN_OPTION(setupLockingRange, 5)
+		BEGIN_OPTION(setupLockingRange, 5, 4)
 			TESTARG(0, lockingrange, 0)
 			TESTARG(1, lockingrange, 1)
 			TESTARG(2, lockingrange, 2)
@@ -394,7 +416,7 @@ uint8_t DtaOptions(int argc, char * argv[], DTA_OPTIONS * opts)
 			OPTION_IS(password)
 			OPTION_IS(device)
 			END_OPTION
-		BEGIN_OPTION(setupLockingRange_SUM, 5)
+		BEGIN_OPTION(setupLockingRange_SUM, 5, 4)
 			TESTARG(0, lockingrange, 0)
 			TESTARG(1, lockingrange, 1)
 			TESTARG(2, lockingrange, 2)
@@ -417,7 +439,7 @@ uint8_t DtaOptions(int argc, char * argv[], DTA_OPTIONS * opts)
 			OPTION_IS(password)
 			OPTION_IS(device)
 			END_OPTION
-		BEGIN_OPTION(readonlyLockingRange, 3)
+		BEGIN_OPTION(readonlyLockingRange, 3, 2)
 			TESTARG(0, lockingrange, 0)
 			TESTARG(1, lockingrange, 1)
 			TESTARG(2, lockingrange, 2)
@@ -438,11 +460,11 @@ uint8_t DtaOptions(int argc, char * argv[], DTA_OPTIONS * opts)
 			OPTION_IS(password)
 			OPTION_IS(device)
 			END_OPTION
-		BEGIN_OPTION(listLockingRanges, 2)
+		BEGIN_OPTION(listLockingRanges, 2, 1)
 			OPTION_IS(password)
 			OPTION_IS(device)
 			END_OPTION
-		BEGIN_OPTION(listLockingRange, 3)
+		BEGIN_OPTION(listLockingRange, 3, 2)
 			TESTARG(0, lockingrange, 0)
 			TESTARG(1, lockingrange, 1)
 			TESTARG(2, lockingrange, 2)
@@ -463,7 +485,7 @@ uint8_t DtaOptions(int argc, char * argv[], DTA_OPTIONS * opts)
 			OPTION_IS(password)
 			OPTION_IS(device)
 			END_OPTION
-		BEGIN_OPTION(rekeyLockingRange, 3)
+		BEGIN_OPTION(rekeyLockingRange, 3, 2)
 			TESTARG(0, lockingrange, 0)
 			TESTARG(1, lockingrange, 1)
 			TESTARG(2, lockingrange, 2)
@@ -484,11 +506,11 @@ uint8_t DtaOptions(int argc, char * argv[], DTA_OPTIONS * opts)
 			OPTION_IS(password)
 			OPTION_IS(device)
 			END_OPTION
-		BEGIN_OPTION(setBandsEnabled, 2)
+		BEGIN_OPTION(setBandsEnabled, 2, 1)
 			OPTION_IS(password)
 			OPTION_IS(device)
 			END_OPTION
-		BEGIN_OPTION(setBandEnabled, 3)
+		BEGIN_OPTION(setBandEnabled, 3, 2)
 			TESTARG(0, lockingrange, 0)
 			TESTARG(1, lockingrange, 1)
 			TESTARG(2, lockingrange, 2)
@@ -509,9 +531,9 @@ uint8_t DtaOptions(int argc, char * argv[], DTA_OPTIONS * opts)
 			OPTION_IS(password)
 			OPTION_IS(device)
 			END_OPTION
-		BEGIN_OPTION(objDump, 5) i += 4; OPTION_IS(device) END_OPTION
-        BEGIN_OPTION(printDefaultPassword, 1) OPTION_IS(device) END_OPTION
-		BEGIN_OPTION(rawCmd, 7) i += 6; OPTION_IS(device) END_OPTION
+		BEGIN_OPTION(objDump, 5, 5) i += 4; OPTION_IS(device) END_OPTION
+        BEGIN_OPTION(printDefaultPassword, 1, 1) OPTION_IS(device) END_OPTION
+		BEGIN_OPTION(rawCmd, 7, 7) i += 6; OPTION_IS(device) END_OPTION
 		else {
             LOG(E) << "Invalid command line argument " << argv[i];
 			return DTAERROR_INVALID_COMMAND;
diff --git a/Common/DtaOptions.h b/Common/DtaOptions.h
index c012af1d..4ae3bc29 100644
--- a/Common/DtaOptions.h
+++ b/Common/DtaOptions.h
@@ -43,6 +43,8 @@ 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 secure_mode; /** global parameter, enable the secure mode */
+    bool ask_password; /** global parameter, to know if the password needs to be interactively asked to the user */
 	sedutiloutput output_format;
 } DTA_OPTIONS;
 /** Print a usage message */
@@ -98,16 +100,18 @@ typedef enum _sedutiloption {
 	rawCmd,
 
 } sedutiloption;
+
 /** verify the number of arguments passed */
-#define CHECKARGS(x) \
-if((x+baseOptions) != argc) { \
-	LOG(E) << "Incorrect number of paramaters for " << argv[i] << " command"; \
-	return 100; \
-	}
+#define CHECKARGS(x1, x2) \
+    int a = opts->secure_mode? x2: x1;\
+    if((a+baseOptions) != argc) { \
+        LOG(E) << "Incorrect number of paramaters for " << argv[i] << " command"; \
+        return 100; \
+    }
 /** Test the command input for a recognized argument */
-#define BEGIN_OPTION(cmdstring,args) \
+#define BEGIN_OPTION(cmdstring,args,args_secure) \
 				else if (!(strcasecmp(#cmdstring, &argv[i][2]))) { \
-				CHECKARGS(args) \
+				CHECKARGS(args, args_secure) \
 				opts->action = sedutiloption::cmdstring; \
 
 /** end of an OPTION */
@@ -126,6 +130,22 @@ i++;
 
 /** set the argc value for this parameter in the options structure */
 #define OPTION_IS(option_field) \
-				opts->option_field = ++i; 
+                if (opts->secure_mode && \
+                        (!(strcasecmp(#option_field, "password")) || \
+                        !(strcasecmp(#option_field, "newpassword")))) { \
+                    opts->option_field = 255; \
+                    if (opts->action != sedutiloption::initialSetup)\
+                        opts->ask_password = true; \
+                } \
+                else { \
+                    opts->option_field = ++i; \
+                }\
+
+/** Return the interactive password in secure mode or command line arg*/
+#define GET_PASSWORD() \
+    opts.secure_mode? (char*) interactive_password.c_str() : argv[opts.password]\
+
+#define GET_NEW_PASSWORD() \
+    opts.secure_mode? (char*)"" : argv[opts.newpassword]\
 
 #endif /* _DTAOPTIONS_H */
diff --git a/Common/sedutil.cpp b/Common/sedutil.cpp
index fe6df19a..7053cd3c 100644
--- a/Common/sedutil.cpp
+++ b/Common/sedutil.cpp
@@ -54,10 +54,17 @@ int main(int argc, char * argv[])
 {
 	DTA_OPTIONS opts;
 	DtaDev *tempDev = NULL, *d = NULL;
+    std::string interactive_password;
 	if (DtaOptions(argc, argv, &opts)) {
 		return DTAERROR_COMMAND_ERROR;
 	}
 	
+#ifdef __linux__
+    if (opts.secure_mode && opts.ask_password) {
+        interactive_password = GetPassPhrase("Please enter password ");
+    }
+#endif //__linux__
+
 	if ((opts.action != sedutiloption::scan) && 
 		(opts.action != sedutiloption::validatePBKDF2) &&
 		(opts.action != sedutiloption::isValidSED)) {
@@ -99,101 +106,101 @@ int main(int argc, char * argv[])
     switch (opts.action) {
  	case sedutiloption::initialSetup:
 		LOG(D) << "Performing initial setup to use sedutil on drive " << argv[opts.device];
-        return (d->initialSetup(argv[opts.password]));
+        return (d->initialSetup(GET_PASSWORD(), opts.secure_mode));
 	case sedutiloption::setup_SUM:
 		LOG(D) << "Performing SUM setup on drive " << argv[opts.device];
 		return (d->setup_SUM(opts.lockingrange, atoll(argv[opts.lrstart]),
-			atoll(argv[opts.lrlength]), argv[opts.password], argv[opts.newpassword]));
+			atoll(argv[opts.lrlength]), GET_PASSWORD(), GET_NEW_PASSWORD(), opts.secure_mode));
 		break;
 	case sedutiloption::setSIDPassword:
         LOG(D) << "Performing setSIDPassword ";
-        return d->setSIDPassword(argv[opts.password], argv[opts.newpassword]);
+        return d->setSIDPassword(GET_PASSWORD(), GET_NEW_PASSWORD(), opts.no_hash_passwords? 0 : 1, opts.no_hash_passwords? 0 : 1, opts.secure_mode);
 		break;
 	case sedutiloption::setAdmin1Pwd:
         LOG(D) << "Performing setPAdmin1Pwd ";
-        return d->setPassword(argv[opts.password], (char *) "Admin1",
-                            argv[opts.newpassword]);
+        return d->setPassword(GET_PASSWORD(), (char *) "Admin1",
+                            GET_NEW_PASSWORD(), opts.secure_mode);
 		break;
 	case sedutiloption::loadPBAimage:
         LOG(D) << "Loading PBA image " << argv[opts.pbafile] << " to " << opts.device;
-        return d->loadPBA(argv[opts.password], argv[opts.pbafile]);
+        return d->loadPBA(GET_PASSWORD(), argv[opts.pbafile]);
 		break;
 	case sedutiloption::setLockingRange:
         LOG(D) << "Setting Locking Range " << (uint16_t) opts.lockingrange << " " << (uint16_t) opts.lockingstate;
-        return d->setLockingRange(opts.lockingrange, opts.lockingstate, argv[opts.password]);
+        return d->setLockingRange(opts.lockingrange, opts.lockingstate, GET_PASSWORD());
 		break;
 	case sedutiloption::setLockingRange_SUM:
 		LOG(D) << "Setting Locking Range " << (uint16_t)opts.lockingrange << " " << (uint16_t)opts.lockingstate << " in Single User Mode";
-		return d->setLockingRange_SUM(opts.lockingrange, opts.lockingstate, argv[opts.password]);
+		return d->setLockingRange_SUM(opts.lockingrange, opts.lockingstate, GET_PASSWORD());
 		break;
 	case sedutiloption::enableLockingRange:
         LOG(D) << "Enabling Locking Range " << (uint16_t) opts.lockingrange;
         return (d->configureLockingRange(opts.lockingrange,
-			(DTA_READLOCKINGENABLED | DTA_WRITELOCKINGENABLED), argv[opts.password]));
+			(DTA_READLOCKINGENABLED | DTA_WRITELOCKINGENABLED), GET_PASSWORD()));
         break;
 	case sedutiloption::disableLockingRange:
 		LOG(D) << "Disabling Locking Range " << (uint16_t) opts.lockingrange;
 		return (d->configureLockingRange(opts.lockingrange, DTA_DISABLELOCKING,
-			argv[opts.password]));
+			GET_PASSWORD()));
 		break;
 	case sedutiloption::readonlyLockingRange:
 		LOG(D) << "Enabling Locking Range " << (uint16_t)opts.lockingrange;
 		return (d->configureLockingRange(opts.lockingrange,
-			DTA_WRITELOCKINGENABLED, argv[opts.password]));
+			DTA_WRITELOCKINGENABLED, GET_PASSWORD()));
 		break;
 	case sedutiloption::setupLockingRange:
 		LOG(D) << "Setup Locking Range " << (uint16_t)opts.lockingrange;
 		return (d->setupLockingRange(opts.lockingrange, atoll(argv[opts.lrstart]),
-			atoll(argv[opts.lrlength]), argv[opts.password]));
+			atoll(argv[opts.lrlength]), GET_PASSWORD()));
 		break;
 	case sedutiloption::setupLockingRange_SUM:
 		LOG(D) << "Setup Locking Range " << (uint16_t)opts.lockingrange << " in Single User Mode";
 		return (d->setupLockingRange_SUM(opts.lockingrange, atoll(argv[opts.lrstart]),
-			atoll(argv[opts.lrlength]), argv[opts.password]));
+			atoll(argv[opts.lrlength]), GET_PASSWORD()));
 		break;
 	case sedutiloption::listLockingRanges:
 		LOG(D) << "List Locking Ranges ";
-		return (d->listLockingRanges(argv[opts.password], -1));
+		return (d->listLockingRanges(GET_PASSWORD(), -1));
 		break;
 	case sedutiloption::listLockingRange:
 		LOG(D) << "List Locking Range[" << opts.lockingrange << "]";
-		return (d->listLockingRanges(argv[opts.password], opts.lockingrange));
+		return (d->listLockingRanges(GET_PASSWORD(), opts.lockingrange));
 		break;
     case sedutiloption::rekeyLockingRange:
 		LOG(D) << "Rekey Locking Range[" << opts.lockingrange << "]";
-		return (d->rekeyLockingRange(opts.lockingrange, argv[opts.password]));
+		return (d->rekeyLockingRange(opts.lockingrange, GET_PASSWORD()));
         break;
     case sedutiloption::setBandsEnabled:
         LOG(D) << "Set bands Enabled";
-        return (d->setBandsEnabled(-1, argv[opts.password]));
+        return (d->setBandsEnabled(-1, GET_PASSWORD()));
         break;
     case sedutiloption::setBandEnabled:
         LOG(D) << "Set band[" << opts.lockingrange << "] enabled";
-        return (d->setBandsEnabled(opts.lockingrange, argv[opts.password]));
+        return (d->setBandsEnabled(opts.lockingrange, GET_PASSWORD()));
         break;
 	case sedutiloption::setMBRDone:
 		LOG(D) << "Setting MBRDone " << (uint16_t)opts.mbrstate;
-		return (d->setMBRDone(opts.mbrstate, argv[opts.password]));
+		return (d->setMBRDone(opts.mbrstate, GET_PASSWORD()));
 		break;
 	case sedutiloption::setMBREnable:
 		LOG(D) << "Setting MBREnable " << (uint16_t)opts.mbrstate;
-		return (d->setMBREnable(opts.mbrstate, argv[opts.password]));
+		return (d->setMBREnable(opts.mbrstate, GET_PASSWORD()));
 		break;
 	case sedutiloption::enableuser:
         LOG(D) << "Performing enable user for user " << argv[opts.userid];
-        return d->enableUser(argv[opts.password], argv[opts.userid]);
+        return d->enableUser(GET_PASSWORD(), argv[opts.userid]);
         break;
 	case sedutiloption::activateLockingSP:
 		LOG(D) << "Activating the LockingSP on" << argv[opts.device];
-        return d->activateLockingSP(argv[opts.password]);
+        return d->activateLockingSP(GET_PASSWORD());
         break;
 	case sedutiloption::activateLockingSP_SUM:
 		LOG(D) << "Activating the LockingSP on" << argv[opts.device];
-		return d->activateLockingSP_SUM(opts.lockingrange, argv[opts.password]);
+		return d->activateLockingSP_SUM(opts.lockingrange, GET_PASSWORD());
 		break;
 	case sedutiloption::eraseLockingRange_SUM:
 		LOG(D) << "Erasing LockingRange " << opts.lockingrange << " on" << argv[opts.device];
-		return d->eraseLockingRange_SUM(opts.lockingrange, argv[opts.password]);
+		return d->eraseLockingRange_SUM(opts.lockingrange, GET_PASSWORD());
 		break;
     case sedutiloption::query:
 		LOG(D) << "Performing diskquery() on " << argv[opts.device];
@@ -210,29 +217,29 @@ int main(int argc, char * argv[])
         break;
 	case sedutiloption::takeOwnership:
 		LOG(D) << "Taking Ownership of the drive at" << argv[opts.device];
-        return d->takeOwnership(argv[opts.password]);
+        return d->takeOwnership(GET_PASSWORD(), opts.secure_mode);
         break;
  	case sedutiloption::revertLockingSP:
 		LOG(D) << "Performing revertLockingSP on " << argv[opts.device];
-        return d->revertLockingSP(argv[opts.password], 0);
+        return d->revertLockingSP(GET_PASSWORD(), 0);
         break;
 	case sedutiloption::setPassword:
         LOG(D) << "Performing setPassword for user " << argv[opts.userid];
-        return d->setPassword(argv[opts.password], argv[opts.userid],
-                              argv[opts.newpassword]);
+        return d->setPassword(GET_PASSWORD(), argv[opts.userid],
+                              GET_NEW_PASSWORD(), opts.secure_mode);
         break;
 	case sedutiloption::setPassword_SUM:
 		LOG(D) << "Performing setPassword in SUM mode for user " << argv[opts.userid];
-		return d->setNewPassword_SUM(argv[opts.password], argv[opts.userid],
-			argv[opts.newpassword]);
+		return d->setNewPassword_SUM(GET_PASSWORD(), argv[opts.userid],
+			GET_NEW_PASSWORD(), opts.secure_mode);
 		break;
 	case sedutiloption::revertTPer:
 		LOG(D) << "Performing revertTPer on " << argv[opts.device];
-        return d->revertTPer(argv[opts.password], 0, 0);
+        return d->revertTPer(GET_PASSWORD(), 0, 0);
         break;
 	case sedutiloption::revertNoErase:
 		LOG(D) << "Performing revertLockingSP  keep global locking range on " << argv[opts.device];
-		return d->revertLockingSP(argv[opts.password], 1);
+		return d->revertLockingSP(GET_PASSWORD(), 1);
 		break;
 	case sedutiloption::validatePBKDF2:
         LOG(D) << "Performing PBKDF2 validation ";
@@ -240,16 +247,16 @@ int main(int argc, char * argv[])
         break;
 	case sedutiloption::yesIreallywanttoERASEALLmydatausingthePSID:
 	case sedutiloption::PSIDrevert:
-		LOG(D) << "Performing a PSID Revert on " << argv[opts.device] << " with password " << argv[opts.password];
-        return d->revertTPer(argv[opts.password], 1, 0);
+		LOG(D) << "Performing a PSID Revert on " << argv[opts.device] << " with password " << GET_PASSWORD();
+        return d->revertTPer(GET_PASSWORD(), 1, 0);
         break;
 	case sedutiloption::PSIDrevertAdminSP:
-		LOG(D) << "Performing a PSID RevertAdminSP on " << argv[opts.device] << " with password " << argv[opts.password];
-        return d->revertTPer(argv[opts.password], 1, 1);
+		LOG(D) << "Performing a PSID RevertAdminSP on " << argv[opts.device] << " with password " << GET_PASSWORD();
+        return d->revertTPer(GET_PASSWORD(), 1, 1);
         break;
 	case sedutiloption::eraseLockingRange:
 		LOG(D) << "Erase Locking Range " << (uint16_t)opts.lockingrange;
-		return (d->eraseLockingRange(opts.lockingrange, argv[opts.password]));
+		return (d->eraseLockingRange(opts.lockingrange, GET_PASSWORD()));
 		break;
 	case sedutiloption::objDump:
 		LOG(D) << "Performing objDump " ;
diff --git a/linux/os.h b/linux/os.h
index 89a798ee..e65a0c4e 100644
--- a/linux/os.h
+++ b/linux/os.h
@@ -33,3 +33,5 @@ along with sedutil.  If not, see <http://www.gnu.org/licenses/>.
 #define SNPRINTF snprintf
 #define DEVICEMASK snprintf(devname,23,"/dev/sd%c",(char) 0x61+i)
 #define DEVICEEXAMPLE "/dev/sdc"
+
+#include "../LinuxPBA/GetPassPhrase.h"

From e4452be67f3f5ae326ba6be4fe92048eddc2720b Mon Sep 17 00:00:00 2001
From: Howard McLauchlan <hmclauchlan@fb.com>
Date: Tue, 16 Aug 2022 22:33:51 -0700
Subject: [PATCH 3/3] Add verifySIDPassword

This is a utility I added to aid debugging, but generally seems like a
good idea. Before adding this, the only way we had of checking "do i
have the right password" was to try to change it, which does seem a
little weird. The pattern of change_password -> verify_password seems a
little more sane to me.

The implementation of this command is a little scuffed though. Under the
hood, we attempt to start a session with the passed in password. There
are many reasons for a session start to fail, and verifySIDPassword
faithfully returns them. On success, however, the password must be
correct.

Signed-off-by: Howard McLauchlan <hmclauchlan@fb.com>
---
 Common/DtaDev.h             |  7 +++++++
 Common/DtaDevEnterprise.cpp |  6 ++++++
 Common/DtaDevEnterprise.h   |  7 +++++++
 Common/DtaDevGeneric.cpp    |  1 +
 Common/DtaDevGeneric.h      |  7 +++++++
 Common/DtaDevOpal.cpp       | 26 ++++++++++++++++++++++++++
 Common/DtaDevOpal.h         |  8 ++++++++
 Common/DtaOptions.cpp       |  3 +++
 Common/DtaOptions.h         |  1 +
 Common/sedutil.cpp          |  4 ++++
 10 files changed, 70 insertions(+)

diff --git a/Common/DtaDev.h b/Common/DtaDev.h
index c73c179e..98777b09 100644
--- a/Common/DtaDev.h
+++ b/Common/DtaDev.h
@@ -132,6 +132,13 @@ class DtaDev {
 	 */
 	virtual uint8_t setSIDPassword(char * oldpassword, char * newpassword,
 		uint8_t hasholdpwd = 1, uint8_t hashnewpwd = 1, bool securemode = false) = 0;
+	/** Verify the SID pasword.
+	 * Requires special handling because password is not always hashed.
+	 * @param password      SID password to be tested
+	 * @param hashpwd      Should the password be hashed. See comments in function Impl.
+     * @param securemode    Should the password be interactively obtained.
+	 */
+    virtual uint8_t verifySIDPassword(char const * const password, uint8_t hashpwd, bool securemode) = 0;
 	/** Set the password of a locking SP user.
 	 * @param password  current password
 	 * @param userid the userid whose password is to be changed
diff --git a/Common/DtaDevEnterprise.cpp b/Common/DtaDevEnterprise.cpp
index ba2e97a7..f00c9ccd 100644
--- a/Common/DtaDevEnterprise.cpp
+++ b/Common/DtaDevEnterprise.cpp
@@ -1346,6 +1346,12 @@ uint8_t DtaDevEnterprise::setSIDPassword(char * oldpassword, char * newpassword,
 	LOG(D1) << "Exiting DtaDevEnterprise::setSIDPassword()";
 	return 0;
 }
+uint8_t DtaDevEnterprise::verifySIDPassword(char const * const, uint8_t, bool)
+{
+    LOG(E) << "DtaDevEnterprise does not support verifySIDPassword" << std::endl;
+    return DTAERROR_INVALID_COMMAND;
+}
+
 uint8_t DtaDevEnterprise::setTable(vector<uint8_t> table, const char *name,
 	OPAL_TOKEN value)
 {
diff --git a/Common/DtaDevEnterprise.h b/Common/DtaDevEnterprise.h
index 4a6d2e2e..b1950269 100644
--- a/Common/DtaDevEnterprise.h
+++ b/Common/DtaDevEnterprise.h
@@ -85,6 +85,13 @@ class DtaDevEnterprise : public DtaDevOS {
          */ 
 	uint8_t setSIDPassword(char * oldpassword, char * newpassword,
 		uint8_t hasholdpwd = 1, uint8_t hashnewpwd = 1, bool securemode = false);
+        /** Verify the SID pasword.
+         * Requires special handling because password is not always hashed.
+         * @param password      SID password to be tested
+         * @param hashpwdd      Should the password be hashed. See comments in function Impl.
+         * @param securemode    Should the password be interactively obtained.
+         */
+    uint8_t verifySIDPassword(char const * const password, uint8_t hashpwd, bool securemode);
         /** set a single column in an object table 
          * @param table the UID of the table
          * @param name the column name to be set
diff --git a/Common/DtaDevGeneric.cpp b/Common/DtaDevGeneric.cpp
index 8e1bdc91..02b6ad98 100644
--- a/Common/DtaDevGeneric.cpp
+++ b/Common/DtaDevGeneric.cpp
@@ -93,6 +93,7 @@ uint8NOCODE(eraseLockingRange_SUM, uint8_t lockingrange, char * password)
 uint8NOCODE(takeOwnership, char * newpassword, bool securemode)
 uint8NOCODE(setSIDPassword,char * oldpassword, char * newpassword,
 	uint8_t hasholdpwd, uint8_t hashnewpwd, bool securemode)
+uint8NOCODE(verifySIDPassword, char const * const password, uint8_t hashpwd, bool securemode)
 uint16_t DtaDevGeneric::comID()
 {
 	LOG(E) << "Generic Device class does not support function " << "comID" << std::endl; 
diff --git a/Common/DtaDevGeneric.h b/Common/DtaDevGeneric.h
index 07728781..999209e4 100644
--- a/Common/DtaDevGeneric.h
+++ b/Common/DtaDevGeneric.h
@@ -76,6 +76,13 @@ class DtaDevGeneric : public DtaDevOS {
          */ 
 	 uint8_t setSIDPassword(char * oldpassword, char * newpassword,
 		uint8_t hasholdpwd = 1, uint8_t hashnewpwd = 1, bool securemode = false) ;
+        /** Verify the SID pasword.
+         * Requires special handling because password is not always hashed.
+         * @param password      SID password to be tested
+         * @param hashpwdd      Should the password be hashed. See comments in function Impl.
+         * @param securemode    Should the password be interactively obtained.
+         */
+    uint8_t verifySIDPassword(char const * const password, uint8_t hashpwd, bool securemode);
          /** Set the password of a locking SP user.
           * @param password  current password
          * @param userid the userid whose password is to be changed 
diff --git a/Common/DtaDevOpal.cpp b/Common/DtaDevOpal.cpp
index 0f6ccc70..a5e7edaf 100644
--- a/Common/DtaDevOpal.cpp
+++ b/Common/DtaDevOpal.cpp
@@ -1545,6 +1545,32 @@ uint8_t DtaDevOpal::setSIDPassword(char * oldpassword, char * newpassword,
 	return 0;
 }
 
+uint8_t DtaDevOpal::verifySIDPassword(char const * const password, uint8_t hashpwd, bool securemode)
+{
+	LOG(D1) << "Entering DtaDevOpal::setSIDPassword()";
+	uint8_t lastRC;
+	session = new DtaSession(this);
+
+    if (!session) {
+		LOG(E) << "Unable to create session object ";
+		return DTAERROR_OBJECT_CREATE_FAILED;
+	}
+	if (!hashpwd)
+        session->dontHashPwd();
+	if ((lastRC = session->start(OPAL_UID::OPAL_ADMINSP_UID,
+		const_cast<char*>(password), OPAL_UID::OPAL_SID_UID)) != 0) {
+		delete session;
+		return lastRC;
+	}
+	delete session;
+	LOG(D1) << "Exiting DtaDevOpal::VerifySIDPassword";
+
+    // Logging to ERROR on success is weird, but this is an easy way to force
+    // output to console without mucking around the internals of this codebase.
+    LOG(E)  << "Successfully verified SIDPassword";
+	return 0;
+}
+
 uint8_t DtaDevOpal::setTable(vector<uint8_t> table, OPAL_TOKEN name,
 	OPAL_TOKEN value)
 {
diff --git a/Common/DtaDevOpal.h b/Common/DtaDevOpal.h
index 389b97f9..50c9dd20 100644
--- a/Common/DtaDevOpal.h
+++ b/Common/DtaDevOpal.h
@@ -83,6 +83,14 @@ class DtaDevOpal : public DtaDevOS {
          */ 
 	uint8_t setSIDPassword(char * oldpassword, char * newpassword,
 		uint8_t hasholdpwd = 1, uint8_t hashnewpwd = 1, bool securemode = false);
+        /** Verify the SID pasword.
+         * Requires special handling because password is not always hashed.
+         * @param password      SID password to be tested
+         * @param hashpwdd      Should the password be hashed. See comments in function Impl.
+         * @param securemode    Should the password be interactively obtained.
+         */
+    uint8_t verifySIDPassword(char const * const password, uint8_t hashpwd, bool securemode);
+
          /** set a single column in an object table 
          * @param table the UID of the table
          * @param name the column name to be set
diff --git a/Common/DtaOptions.cpp b/Common/DtaOptions.cpp
index 0d1752ee..0e3eb9fb 100644
--- a/Common/DtaOptions.cpp
+++ b/Common/DtaOptions.cpp
@@ -71,6 +71,8 @@ void usage()
 	printf("--setPassword <oldpassword, \"\" for MSID> <userid> <newpassword> <device> \n");
 	printf("                                Change the Enterprise password for userid\n");
 	printf("                                \"EraseMaster\" or \"BandMaster<n>\", 0 <= n <= 1023\n");
+    printf("--verifySIDPassword <SIDpassword> <device>\n");
+    printf("                                Verify the SID password for given device\n");
 	printf("--setLockingRange <0...n> <RW|RO|LK> <Admin1password> <device> \n");
 	printf("                                Set the status of a Locking Range\n");
 	printf("                                0 = GLobal 1..n  = LRn \n");
@@ -171,6 +173,7 @@ uint8_t DtaOptions(int argc, char * argv[], DTA_OPTIONS * opts)
 		BEGIN_OPTION(initialSetup, 2, 1) OPTION_IS(password) OPTION_IS(device) END_OPTION
 		BEGIN_OPTION(setSIDPassword, 3, 1) OPTION_IS(password) OPTION_IS(newpassword)
 		         OPTION_IS(device) END_OPTION
+        BEGIN_OPTION(verifySIDPassword, 2 /*num_args_non_secure*/, 1/*num_args_secure*/) OPTION_IS(password) OPTION_IS(device) END_OPTION
 		BEGIN_OPTION(setup_SUM, 6, 4)
 			TESTARG(0, lockingrange, 0)
 			TESTARG(1, lockingrange, 1)
diff --git a/Common/DtaOptions.h b/Common/DtaOptions.h
index 4ae3bc29..990cd566 100644
--- a/Common/DtaOptions.h
+++ b/Common/DtaOptions.h
@@ -60,6 +60,7 @@ typedef enum _sedutiloption {
 	deadbeef,    // 0 should indicate no action specified
 	initialSetup,
 	setSIDPassword,
+    verifySIDPassword,
 	setup_SUM,
 	setAdmin1Pwd,
 	setPassword,
diff --git a/Common/sedutil.cpp b/Common/sedutil.cpp
index 7053cd3c..4c0e9ff5 100644
--- a/Common/sedutil.cpp
+++ b/Common/sedutil.cpp
@@ -116,6 +116,10 @@ int main(int argc, char * argv[])
         LOG(D) << "Performing setSIDPassword ";
         return d->setSIDPassword(GET_PASSWORD(), GET_NEW_PASSWORD(), opts.no_hash_passwords? 0 : 1, opts.no_hash_passwords? 0 : 1, opts.secure_mode);
 		break;
+    case sedutiloption::verifySIDPassword:
+        LOG(D) << "Performing verifySIDPassword ";
+        return d->verifySIDPassword(GET_PASSWORD(), !opts.no_hash_passwords, opts.secure_mode);
+        break;
 	case sedutiloption::setAdmin1Pwd:
         LOG(D) << "Performing setPAdmin1Pwd ";
         return d->setPassword(GET_PASSWORD(), (char *) "Admin1",