6 Commits
1.1.0 ... 1.1.1

Author SHA1 Message Date
Jonas Stein
708932b383 Version bump 1.1.1
Version 1.1.1
2022-04-25 01:14:02 +02:00
Jonas Stein
226c5bcef0 remove duplicate test
Closes: https://github.com/scsitape/stenc/issues/41
2022-04-24 22:00:05 +02:00
Jonas Stein
4a7b143d50 Add tests to README 2022-04-24 21:19:57 +02:00
James Wilson
ff413aac3e Add unit tests and add const 2022-04-24 20:09:08 +02:00
Paweł Marciniak
f1a36eba42 Reintroduce HEX macro as fix
Co-authored-by: Paweł Marciniak <sunwire+git@gmail.com>
2022-04-24 16:35:52 +02:00
Paweł Marciniak
844306dbe4 cast to proper type (#38)
Co-authored-by: Paweł Marciniak <sunwire+git@gmail.com>
2022-04-24 12:52:30 +02:00
14 changed files with 18381 additions and 51 deletions

View File

@@ -23,7 +23,3 @@ jobs:
run: make check
- name: make distcheck
run: make distcheck
- name: make check
run: make check
- name: make distcheck
run: make distcheck

8
.gitignore vendored
View File

@@ -30,6 +30,10 @@
*.out
*.app
src/stenc
tests/scsi
# dist outputs
*.tar.gz
# Generated Makefile
# (meta build system like autotools,
@@ -57,6 +61,7 @@ autom4te.cache
/compile
/config.cache
/config.guess
/config.h
/config.h.in
/config.log
/config.status
@@ -67,3 +72,6 @@ autom4te.cache
/install-sh
/missing
/stamp-h1
/tests/*.log
/tests/*.trs

View File

@@ -1,3 +1,9 @@
2022-04-25 Jonas Stein <news@jonasstein.de>
* Version upgraded to 1.1.1
* Testframework Catch added
* Fixed bug (mixed HEX macro and std::hex)
* More constants marked with const
2022-04-22 Jonas Stein <news@jonasstein.de>
* Version upgraded to 1.1.0
* Code cleanup

View File

@@ -1,2 +1,2 @@
SUBDIRS = src man
SUBDIRS = src man tests
# EXTRA_DIST = buildconf

View File

@@ -26,7 +26,8 @@ Get the source code and compile
git clone git@github.com:scsitape/stenc.git
cd stenc/
autoreconf --install
./configure
./autogen.sh && ./configure
make check # optionally run the catch testing framework
make
```
@@ -37,7 +38,7 @@ Linux Packages
License
-------
Program copyright 2012-2018 contributing authors.
Program copyright 2012-2022 contributing authors.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
AC_INIT([stenc],[1.1.0])
AC_CONFIG_SRCDIR([src/main.cpp])
AM_INIT_AUTOMAKE([foreign])
AM_INIT_AUTOMAKE([foreign subdir-objects])
AC_CONFIG_HEADERS([config.h])
AC_CHECK_HEADER([sys/types.h])
@@ -105,6 +105,6 @@ fi
AC_CONFIG_FILES([Makefile src/Makefile man/Makefile])
AC_CONFIG_FILES([Makefile src/Makefile man/Makefile tests/Makefile])
AC_OUTPUT

View File

@@ -602,7 +602,7 @@ std::string randomKey(int length) {
if (random.is_open()) {
for (int i = 0; i < length; i++) {
random.read(reinterpret_cast<char *>(&rnd), 1);
retval << std::hex << rnd;
retval << std::hex << std::setfill('0') << setw(2) << static_cast<int>(rnd);
}
random.close();
} else {

View File

@@ -194,13 +194,8 @@ SCSI_PAGE_INQ *SCSIGetInquiry(std::string tapeDevice) {
return status;
}
// Writes encryption options to the tape drive
bool SCSIWriteEncryptOptions(std::string tapeDevice,
SCSIEncryptOptions *eOptions) {
char buffer[1024];
memset(&buffer, 0, 1024);
int SCSIInitSDEPage(SCSIEncryptOptions *eOptions,
uint8_t *buffer) {
SSP_PAGE_SDE options;
// copy the template over the options
memset(&options, 0, sizeof(SSP_PAGE_SDE));
@@ -213,23 +208,23 @@ bool SCSIWriteEncryptOptions(std::string tapeDevice,
options.algorithmIndex = eOptions->algorithmIndex;
// set the specific options
switch (eOptions->cryptMode) {
case CRYPTMODE_ON: // encrypt, read only encrypted data
options.encryptionMode = 2;
options.decryptionMode = 2;
break;
case CRYPTMODE_MIXED: // encrypt, read all data
options.encryptionMode = 2;
options.decryptionMode = 3;
break;
case CRYPTMODE_RAWREAD:
options.encryptionMode = 2;
options.decryptionMode = 1;
break;
default:
byteswap((unsigned char *)options.keyLength, 2, DEFAULT_KEYSIZE);
eOptions->cryptoKey = ""; // blank the key
eOptions->keyName = ""; // blank the key name, not supported when turned off
break;
case CRYPTMODE_ON: // encrypt, read only encrypted data
options.encryptionMode = 2;
options.decryptionMode = 2;
break;
case CRYPTMODE_MIXED: // encrypt, read all data
options.encryptionMode = 2;
options.decryptionMode = 3;
break;
case CRYPTMODE_RAWREAD:
options.encryptionMode = 2;
options.decryptionMode = 1;
break;
default:
byteswap((unsigned char *)options.keyLength, 2, DEFAULT_KEYSIZE);
eOptions->cryptoKey = ""; // blank the key
eOptions->keyName = ""; // blank the key name, not supported when turned off
break;
}
if (eOptions->cryptoKey != "") {
@@ -263,7 +258,16 @@ bool SCSIWriteEncryptOptions(std::string tapeDevice,
pagelen - 4); // set the page length, minus the length and pageCode
// copy the options to the beginning of the buffer
memcpy(&buffer, &options, sizeof(SSP_PAGE_SDE));
memcpy(buffer, &options, sizeof(SSP_PAGE_SDE));
return pagelen;
}
// Writes encryption options to the tape drive
bool SCSIWriteEncryptOptions(std::string tapeDevice,
SCSIEncryptOptions *eOptions) {
uint8_t buffer[1024];
memset(&buffer, 0, 1024);
int pagelen = SCSIInitSDEPage(eOptions, buffer);
unsigned char spout_sde_command[SSP_SP_CMD_LEN] = {SSP_SPOUT_OPCODE,
SSP_SP_PROTOCOL_TDE,
@@ -371,13 +375,13 @@ bool SCSIExecute(std::string tapedrive, unsigned char *cmd_p, int cmd_len,
#ifdef DEBUGSCSI
std::cout << "SCSI Command: ";
for (int i = 0; i < cmd_len; i++) {
std::cout << std::hex << cmd_p[i];
std::cout << HEX(cmd_p[i]);
}
std::cout << "\n";
std::cout << "SCSI Data: ";
for (int i = 0; i < dxfer_len; i++) {
std::cout << std::hex << (dxfer_p[i]);
std::cout << HEX(dxfer_p[i]));
}
std::cout << std::endl;
#endif
@@ -427,19 +431,19 @@ SCSIEncryptOptions::SCSIEncryptOptions() {
rdmc = RDMC_DEFAULT;
}
SSP_NBES::SSP_NBES(SSP_PAGE_BUFFER *buffer) {
SSP_NBES::SSP_NBES(const SSP_PAGE_BUFFER *buffer) {
memset(&nbes, 0, sizeof(SSP_PAGE_NBES));
memcpy(&nbes, buffer, sizeof(SSP_PAGE_NBES));
loadKADs(buffer, sizeof(SSP_PAGE_NBES));
}
SSP_DES::SSP_DES(SSP_PAGE_BUFFER *buffer) {
SSP_DES::SSP_DES(const SSP_PAGE_BUFFER *buffer) {
memset(&des, 0, sizeof(SSP_PAGE_DES));
memcpy(&des, buffer, sizeof(SSP_PAGE_DES));
loadKADs(buffer, sizeof(SSP_PAGE_DES));
}
void KAD_CLASS::loadKADs(SSP_PAGE_BUFFER *buffer, int start) {
char *rawbuff = (char *)buffer;
void KAD_CLASS::loadKADs(const SSP_PAGE_BUFFER *buffer, int start) {
const char *rawbuff = (const char *)buffer;
int length = BSSHORT(buffer->length) + 4;
int pos = start;
while (pos < length) {
@@ -569,20 +573,20 @@ void outputSense(SCSI_PAGE_SENSE *sd) {
break;
}
std::cerr << " (0x" << std::hex << (sd->senseKey) << ")\n";
std::cerr << " (0x" << HEX(sd->senseKey) << ")\n";
std::cerr << std::left << std::setw(25) << " ASC:"
<< "0x" << std::hex << (sd->addSenseCode) << "\n";
<< "0x" << HEX(sd->addSenseCode) << "\n";
std::cerr << std::left << std::setw(25) << " ASCQ:"
<< "0x" << std::hex << (sd->addSenseCodeQual) << "\n";
<< "0x" << HEX(sd->addSenseCodeQual) << "\n";
if (sd->addSenseLen > 0) {
std::cerr << std::left << std::setw(25) << " Additional data:"
<< "0x";
for (int i = 0; i < sd->addSenseLen; i++) {
std::cerr << std::hex << (sd->addSenseData[i]);
std::cerr << HEX(sd->addSenseData[i]);
}
std::cerr << "\n";
}
@@ -592,7 +596,7 @@ void outputSense(SCSI_PAGE_SENSE *sd) {
char *rawsense = (char *)sd;
for (int i = 0; i < sizeof(SCSI_PAGE_SENSE); i++) {
std::cerr << std::hex << (rawsense[i]);
std::cerr << HEX(rawsense[i]);
}
std::cerr << "\n";
#endif

View File

@@ -37,7 +37,7 @@ GNU General Public License for more details.
// outputs hex in a 2 digit pair
#define HEX(x) \
right << setw(2) << setfill('0') << hex << (int)(x) << setfill(' ')
std::right << std::setw(2) << std::setfill('0') << std::hex << (int)(x) << std::setfill(' ')
// macro for a byte swapped short
#define BSSHORT(x) ((unsigned short)((x[0] << 8) + x[1]))
// macro for a byte swapped int
@@ -317,20 +317,20 @@ public:
std::vector<SSP_KAD> kads;
protected:
void loadKADs(SSP_PAGE_BUFFER *buffer, int start);
void loadKADs(const SSP_PAGE_BUFFER *buffer, int start);
};
// class used to parse next block encryption status page
class SSP_NBES : public KAD_CLASS {
public:
SSP_PAGE_NBES nbes;
SSP_NBES(SSP_PAGE_BUFFER *buffer);
SSP_NBES(const SSP_PAGE_BUFFER *buffer);
};
// class used to parse data encryption status page
class SSP_DES : public KAD_CLASS {
public:
SSP_PAGE_DES des;
SSP_DES(SSP_PAGE_BUFFER *buffer);
SSP_DES(const SSP_PAGE_BUFFER *buffer);
};
// enum for SCSIEncryptOptions.cryptMode
@@ -353,6 +353,8 @@ SSP_DES *SSPGetDES(std::string tapeDevice);
// Gets the encryption status from the tape volume
SSP_NBES *SSPGetNBES(std::string tapeDevice, bool retry);
// Writes encryption options to the tape drive
int SCSIInitSDEPage(SCSIEncryptOptions *eOptions,
uint8_t *buffer);
bool SCSIWriteEncryptOptions(std::string tapeDevice,
SCSIEncryptOptions *eOptions);
// Gets device inquiry

View File

@@ -1,5 +1,5 @@
Name: stenc
Version: 1.1.0
Version: 1.1.1
Release: 3%{?dist}
Summary: SCSI Tape Encryption Manager

118
tests/.clang-format Normal file
View File

@@ -0,0 +1,118 @@
---
Language: Cpp
# BasedOnStyle: LLVM
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Right
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: MultiLine
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
- Regex: '.*'
Priority: 1
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: false
IndentPPDirectives: None
IndentWidth: 2
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
ReflowComments: true
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 8
UseTab: Never
...

4
tests/Makefile.am Normal file
View File

@@ -0,0 +1,4 @@
AM_CPPFLAGS=-I${top_srcdir}/src
TESTS=scsi
check_PROGRAMS=scsi
scsi_SOURCES=catch.hpp scsi.cpp ${top_srcdir}/src/scsiencrypt.cpp

17970
tests/catch.hpp Normal file

File diff suppressed because it is too large Load Diff

221
tests/scsi.cpp Normal file
View File

@@ -0,0 +1,221 @@
#define CATCH_CONFIG_MAIN
#include "catch.hpp"
#include "config.h"
#include "scsiencrypt.h"
using namespace std::literals::string_literals;
/**
* Compare the SPOUT Set Data Encryption pages generated by stenc to an
* expected output buffer based on the SCSI command spec.
*
* This checks that the program can correctly format command buffers that
* reflect available input and program options.
*/
TEST_CASE("Disable encryption command", "[scsi]") {
SCSIEncryptOptions opt;
uint8_t buffer[1024] {};
const uint8_t expected[] {
0x00, 0x10, // page code
0x00, 0x30, // page length
0x40, // scope
DEFAULT_CEEM << 6, // CEEM, CKOD, RDMC, et al.
0x00, // encyption mode
0x00, // decryption mode
0x01, // algorithm index
0x00, // key format
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved [8]
0x00, 0x20, // key length
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
opt.cryptMode = CRYPTMODE_OFF;
opt.algorithmIndex = 1;
int pagelen = SCSIInitSDEPage(&opt, buffer);
REQUIRE(pagelen == sizeof(expected));
REQUIRE(memcmp(buffer, expected, sizeof(expected)) == 0);
}
TEST_CASE("Enable encryption command", "[scsi]") {
SCSIEncryptOptions opt;
uint8_t buffer[1024] {};
const uint8_t expected[] {
0x00, 0x10, // page code
0x00, 0x30, // page length
0x40, // scope
DEFAULT_CEEM << 6, // CEEM, CKOD, RDMC, et al.
0x02, // encyption mode
0x02, // decryption mode
0x01, // algorithm index
0x00, // key format
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved [8]
0x00, 0x20, // key length
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
};
opt.cryptMode = CRYPTMODE_ON;
opt.algorithmIndex = 1;
opt.cryptoKey = "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF"s
"\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF"s;
opt.keyName = ""s;
int pagelen = SCSIInitSDEPage(&opt, buffer);
REQUIRE(pagelen == sizeof(expected));
REQUIRE(memcmp(buffer, expected, sizeof(expected)) == 0);
}
TEST_CASE("Enable encryption command with options", "[scsi]") {
SCSIEncryptOptions opt;
uint8_t buffer[1024] {};
const uint8_t expected[] {
0x00, 0x10, // page code
0x00, 0x30, // page length
0x40, // scope
DEFAULT_CEEM << 6 | 0x24, // CEEM, CKOD, RDMC, et al.
0x02, // encyption mode
0x02, // decryption mode
0x01, // algorithm index
0x00, // key format
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved [8]
0x00, 0x20, // key length
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
};
opt.rdmc = 2;
opt.CKOD = true;
opt.cryptMode = CRYPTMODE_ON;
opt.algorithmIndex = 1;
opt.cryptoKey = "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF"s
"\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF"s;
opt.keyName = ""s;
int pagelen = SCSIInitSDEPage(&opt, buffer);
REQUIRE(pagelen == sizeof(expected));
REQUIRE(memcmp(buffer, expected, sizeof(expected)) == 0);
}
TEST_CASE("Enable encryption command with key name", "[scsi]") {
SCSIEncryptOptions opt;
uint8_t buffer[1024] {};
const uint8_t expected[] {
0x00, 0x10, // page code
0x00, 0x40, // page length
0x40, // scope
DEFAULT_CEEM << 6, // CEEM, CKOD, RDMC, et al.
0x02, // encyption mode
0x02, // decryption mode
0x01, // algorithm index
0x00, // key format
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved [8]
0x00, 0x20, // key length
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
// KAD
0x00, // type
0x00, // authenticated
0x00, 0x0c, // length
0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21,
};
opt.cryptMode = CRYPTMODE_ON;
opt.algorithmIndex = 1;
opt.cryptoKey = "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF"s
"\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF"s;
opt.keyName = "Hello world!"s;
int pagelen = SCSIInitSDEPage(&opt, buffer);
REQUIRE(pagelen == sizeof(expected));
REQUIRE(memcmp(buffer, expected, sizeof(expected)) == 0);
}
/**
* Check the representation of the SPIN Device Encryption Status page
* matches the values from the raw buffer. Input buffers were observed
* from device traffic.
*
* This checks the SSP_DES structure layout matches the spec, especially
* with regard to byte ordering and bitfield positions.
*/
TEST_CASE("Interpret device encryption status page", "[scsi]") {
const uint8_t buffer[] {
0x00, 0x20, // page code
0x00, 0x24, // length
0x42, // nexus = 2h, key scope = 2h
0x02, // encryption mode
0x02, // decryption mode
0x01, // algorithm index
0x00, 0x00, 0x00, 0x01, // key instance counter
0x18, // parameters control = 1, VCELB = 1, CEEMS = 0, RDMD = 0
0x00, // KAD format
0x00, 0x00, // ADSK count
0x00, 0x00, 0x00, 0x00, // reserved[8]
0x00, 0x00, 0x00, 0x00,
// KAD descriptor
0x00, // descriptor type
0x01, // authenticated
0x00, 0x0c, // length
0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21,
};
SSP_DES page(reinterpret_cast<const SSP_PAGE_BUFFER*>(buffer));
REQUIRE(BSSHORT(page.des.pageCode) == 0x20);
REQUIRE(BSSHORT(page.des.length) == 0x24);
REQUIRE(page.des.nexusScope == 2);
REQUIRE(page.des.keyScope == 2);
REQUIRE(page.des.encryptionMode == 2);
REQUIRE(page.des.decryptionMode == 2);
REQUIRE(page.des.algorithmIndex == 1);
REQUIRE(BSLONG(page.des.keyInstance) == 1);
REQUIRE(page.des.parametersControl == 1);
REQUIRE(page.des.VCELB == 1);
REQUIRE(page.des.CEEMS == 0);
REQUIRE(page.des.RDMD == 0);
REQUIRE(page.kads.size() == 1);
REQUIRE(page.kads[0].authenticated == 1);
REQUIRE(BSSHORT(page.kads[0].descriptorLength) == std::strlen("Hello world!"));
REQUIRE(memcmp(page.kads[0].descriptor, "Hello world!", BSSHORT(page.kads[0].descriptorLength)) == 0);
}
TEST_CASE("Interpret next block encryption status page", "[scsi]") {
const uint8_t buffer[] {
0x00, 0x21, // page code
0x00, 0x1c, // length
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x05, // compression status = 0, encryption status = 5h
0x01, // algorithm index
0x00, // EMES = 0, RDMDS = 0
0x00, // KAD format
// KAD descriptor
0x00, // descriptor type
0x01, // authenticated
0x00, 0x0c, // length
0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21,
};
SSP_NBES page(reinterpret_cast<const SSP_PAGE_BUFFER*>(buffer));
REQUIRE(BSSHORT(page.nbes.pageCode) == 0x21);
REQUIRE(BSSHORT(page.nbes.length) == 0x1c);
REQUIRE(page.nbes.compressionStatus == 0);
REQUIRE(page.nbes.encryptionStatus == 5);
REQUIRE(page.nbes.algorithmIndex == 1);
REQUIRE(page.nbes.EMES == 0);
REQUIRE(page.nbes.RDMDS == 0);
REQUIRE(page.kads.size() == 1);
REQUIRE(page.kads[0].authenticated == 1);
REQUIRE(BSSHORT(page.kads[0].descriptorLength) == std::strlen("Hello world!"));
REQUIRE(memcmp(page.kads[0].descriptor, "Hello world!", BSSHORT(page.kads[0].descriptorLength)) == 0);
}