Compare commits
84 Commits
1.0.8
...
stenc-2.0.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4b0b7e1575 | ||
|
|
b853fd604a | ||
|
|
7943f1860e | ||
|
|
57591d01a9 | ||
|
|
daa541a654 | ||
|
|
7e449bff7b | ||
|
|
22e21715f2 | ||
|
|
0e53223fc5 | ||
|
|
9d7b1ed4b8 | ||
|
|
965bba59bf | ||
|
|
bfb35cd968 | ||
|
|
c979a3da74 | ||
|
|
eb012d9538 | ||
|
|
31d63481d5 | ||
|
|
8b1756eb89 | ||
|
|
89d354e927 | ||
|
|
5366997e79 | ||
|
|
13af87abaa | ||
|
|
918afb35fb | ||
|
|
f800dc2f51 | ||
|
|
a3d03e5211 | ||
|
|
f77e46eeb0 | ||
|
|
e6f7f1b7b3 | ||
|
|
b2082bf854 | ||
|
|
23f8d829bf | ||
|
|
1200fe92ee | ||
|
|
c6bf88e25f | ||
|
|
aeab6f03de | ||
|
|
490251f101 | ||
|
|
d2b7363769 | ||
|
|
86cca0804c | ||
|
|
a7a7c4750c | ||
|
|
8caaf85fbb | ||
|
|
f5856d7591 | ||
|
|
eeb7d72686 | ||
|
|
1508f432ad | ||
|
|
08bd10230f | ||
|
|
13cf62cf8b | ||
|
|
8ebccddc50 | ||
|
|
ebabc39c3e | ||
|
|
88975cc9ed | ||
|
|
8b7e99556a | ||
|
|
44603e4884 | ||
|
|
859c1a0757 | ||
|
|
e6ac5fa3f0 | ||
|
|
f893ee93cc | ||
|
|
fbba173a1f | ||
|
|
8078a346d1 | ||
|
|
13f09ea5aa | ||
|
|
030c674fbc | ||
|
|
1e26d47230 | ||
|
|
fe4cf3c00d | ||
|
|
c5f8c9e73e | ||
|
|
41b8baec2a | ||
|
|
fb588dda64 | ||
|
|
1ece43b1cb | ||
|
|
20edbdcb3d | ||
|
|
6c7492046b | ||
|
|
88b0bccea1 | ||
|
|
708932b383 | ||
|
|
226c5bcef0 | ||
|
|
4a7b143d50 | ||
|
|
ff413aac3e | ||
|
|
f1a36eba42 | ||
|
|
844306dbe4 | ||
|
|
8ff2e4c4eb | ||
|
|
0ad0a208d5 | ||
|
|
59d5c6c0fa | ||
|
|
35b852cfeb | ||
|
|
88a507932e | ||
|
|
aa2244308d | ||
|
|
e1e3676660 | ||
|
|
d4ffed77ab | ||
|
|
82aca41962 | ||
|
|
b6b7cd90c0 | ||
|
|
e92ccb49ff | ||
|
|
9feb3f8739 | ||
|
|
1dce245cce | ||
|
|
b650fb67c0 | ||
|
|
70859dfdaa | ||
|
|
fc403b6267 | ||
|
|
aefb37e563 | ||
|
|
90586aa018 | ||
|
|
a4f407f361 |
154
.clang-format
Normal file
154
.clang-format
Normal file
@@ -0,0 +1,154 @@
|
||||
# SPDX-FileCopyrightText: 2022 stenc authors
|
||||
#
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
---
|
||||
Language: Cpp
|
||||
# BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -2
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveMacros: false
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveBitFields: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlines: Right
|
||||
AlignOperands: Align
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllConstructorInitializersOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortEnumsOnASingleLine: true
|
||||
AllowShortBlocksOnASingleLine: Never
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: MultiLine
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: false
|
||||
AfterControlStatement: Never
|
||||
AfterEnum: false
|
||||
AfterFunction: true
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
BeforeLambdaBody: false
|
||||
BeforeWhile: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: false
|
||||
SplitEmptyRecord: false
|
||||
SplitEmptyNamespace: false
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Custom
|
||||
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
|
||||
DeriveLineEnding: 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
|
||||
SortPriority: 0
|
||||
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
||||
Priority: 3
|
||||
SortPriority: 0
|
||||
- Regex: '.*'
|
||||
Priority: 1
|
||||
SortPriority: 0
|
||||
IncludeIsMainRegex: '(Test)?$'
|
||||
IncludeIsMainSourceRegex: ''
|
||||
IndentCaseLabels: false
|
||||
IndentCaseBlocks: false
|
||||
IndentGotoLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentExternBlock: AfterExternBlock
|
||||
IndentWidth: 2
|
||||
IndentWrappedFunctionNames: false
|
||||
InsertTrailingCommas: None
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCBinPackProtocolList: Auto
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCBreakBeforeNestedBlockParam: true
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 60
|
||||
PointerAlignment: Right
|
||||
ReferenceAlignment: Left
|
||||
ReflowComments: true
|
||||
SortIncludes: true
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCpp11BracedList: true
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: false
|
||||
SpaceInEmptyBlock: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: false
|
||||
SpacesInConditionalStatement: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
SpaceBeforeSquareBrackets: false
|
||||
Standard: c++17
|
||||
StatementMacros:
|
||||
- Q_UNUSED
|
||||
- QT_REQUIRE_VERSION
|
||||
TabWidth: 8
|
||||
UseCRLF: false
|
||||
UseTab: Never
|
||||
WhitespaceSensitiveMacros:
|
||||
- STRINGIZE
|
||||
- PP_STRINGIZE
|
||||
- BOOST_PP_STRINGIZE
|
||||
...
|
||||
|
||||
32
.github/workflows/c-cpp.yml
vendored
Normal file
32
.github/workflows/c-cpp.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
# SPDX-FileCopyrightText: 2022 stenc authors
|
||||
#
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
name: C/C++ CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
#install pandoc
|
||||
- name: Install pandoc package
|
||||
run: |
|
||||
sudo apt-get -y install pandoc
|
||||
- name: autoconf
|
||||
run: autoreconf -i
|
||||
- name: configure
|
||||
run: ./configure
|
||||
- name: make
|
||||
run: make
|
||||
- name: make check
|
||||
run: make check
|
||||
- name: make distcheck
|
||||
run: make distcheck
|
||||
55
.github/workflows/codeql.yml
vendored
Normal file
55
.github/workflows/codeql.yml
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
# SPDX-FileCopyrightText: 2022 stenc authors
|
||||
#
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ 'master' ]
|
||||
pull_request:
|
||||
branches: [ 'master' ]
|
||||
schedule:
|
||||
- cron: '4 11 * * 6'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'cpp' ]
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
|
||||
|
||||
- name: Install pandoc package
|
||||
run: |
|
||||
sudo apt-get -y install pandoc
|
||||
- name: autoconf
|
||||
run: autoreconf -i
|
||||
- name: configure
|
||||
run: ./configure
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
queries: +security-and-quality
|
||||
|
||||
- name: make
|
||||
run: make
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
61
.gitignore
vendored
61
.gitignore
vendored
@@ -1,3 +1,10 @@
|
||||
# SPDX-FileCopyrightText: 2022 stenc authors
|
||||
#
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
# Tempfiles
|
||||
*~
|
||||
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
@@ -16,10 +23,6 @@
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
*.smod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
@@ -30,3 +33,53 @@
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
src/stenc
|
||||
tests/scsi
|
||||
tests/output
|
||||
|
||||
# Other outputs
|
||||
man/stenc.1
|
||||
|
||||
# dist outputs
|
||||
*.tar.gz
|
||||
|
||||
# Generated Makefile
|
||||
# (meta build system like autotools,
|
||||
# can automatically generate from config.status script
|
||||
# (which is called by configure script))
|
||||
Makefile
|
||||
|
||||
# http://www.gnu.org/software/automake
|
||||
|
||||
Makefile.in
|
||||
/ar-lib
|
||||
/mdate-sh
|
||||
/py-compile
|
||||
/test-driver
|
||||
/ylwrap
|
||||
.deps/
|
||||
.dirstamp
|
||||
|
||||
# http://www.gnu.org/software/autoconf
|
||||
|
||||
autom4te.cache
|
||||
/autoscan.log
|
||||
/autoscan-*.log
|
||||
/aclocal.m4
|
||||
/compile
|
||||
/config.cache
|
||||
/config.guess
|
||||
/config.h
|
||||
/config.h.in
|
||||
/config.log
|
||||
/config.status
|
||||
/config.sub
|
||||
/configure
|
||||
/configure.scan
|
||||
/depcomp
|
||||
/install-sh
|
||||
/missing
|
||||
/stamp-h1
|
||||
|
||||
/tests/*.log
|
||||
/tests/*.trs
|
||||
|
||||
9
AUTHORS
9
AUTHORS
@@ -1,9 +0,0 @@
|
||||
stenc AUTHORS
|
||||
===============================================================================
|
||||
|
||||
The authors of stenc are
|
||||
|
||||
John Coleman <ninthclowd@user.sourceforge.net>
|
||||
Samuel Martinez Jr. <sam_martinez_82@hotmail.com>
|
||||
|
||||
|
||||
15
AUTHORS.md
Normal file
15
AUTHORS.md
Normal file
@@ -0,0 +1,15 @@
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2022 stenc authors
|
||||
|
||||
SPDX-License-Identifier: CC0-1.0
|
||||
-->
|
||||
|
||||
stenc AUTHORS
|
||||
=============
|
||||
|
||||
The authors of stenc are
|
||||
|
||||
* John Coleman <ninthclowd@user.sourceforge.net>
|
||||
* Samuel Martinez Jr. <sam_martinez_82@hotmail.com>
|
||||
* Jonas Stein <news@jonasstein.de>
|
||||
* James Wilson <jmw@jmw.name>
|
||||
@@ -1,3 +1,9 @@
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2022 stenc authors
|
||||
|
||||
SPDX-License-Identifier: CC0-1.0
|
||||
-->
|
||||
|
||||
The Stenc team is looking forward to your contribution.
|
||||
Please prepare a pull request, or send us your `.patch` file
|
||||
Leave also a note, how you have tested the code.
|
||||
|
||||
340
COPYING
340
COPYING
@@ -1,340 +0,0 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
||||
19
ChangeLog
19
ChangeLog
@@ -1,3 +1,22 @@
|
||||
xxxx-xx-xx
|
||||
* Version upgraded to 2.x.x
|
||||
* Removed KeyInfo; use standard library to parse hex strings
|
||||
* define C++17 as minimal C++ version
|
||||
* build manpage with pandoc
|
||||
* Dropped AIX support. If you can test and develop code for AIX, please contact us.
|
||||
* Added bash completion
|
||||
|
||||
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
|
||||
* Use /dev/random to create a key
|
||||
|
||||
2020-06-16 Jonas Stein <news@jonasstein.de>
|
||||
* Version upgraded to 1.0.8
|
||||
* Merged patches to fix make files and provide more error messages
|
||||
|
||||
3
ChangeLog.license
Normal file
3
ChangeLog.license
Normal file
@@ -0,0 +1,3 @@
|
||||
SPDX-FileCopyrightText: 2022 stenc authors
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
3
INSTALL.license
Normal file
3
INSTALL.license
Normal file
@@ -0,0 +1,3 @@
|
||||
SPDX-FileCopyrightText: 1994 Free Software Foundation, Inc.
|
||||
|
||||
SPDX-License-Identifier: CC0-1.0
|
||||
7
LICENSES/BSL-1.0.txt
Normal file
7
LICENSES/BSL-1.0.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
121
LICENSES/CC0-1.0.txt
Normal file
121
LICENSES/CC0-1.0.txt
Normal file
@@ -0,0 +1,121 @@
|
||||
Creative Commons Legal Code
|
||||
|
||||
CC0 1.0 Universal
|
||||
|
||||
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
|
||||
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
|
||||
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
|
||||
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
|
||||
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
|
||||
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
|
||||
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
|
||||
HEREUNDER.
|
||||
|
||||
Statement of Purpose
|
||||
|
||||
The laws of most jurisdictions throughout the world automatically confer
|
||||
exclusive Copyright and Related Rights (defined below) upon the creator
|
||||
and subsequent owner(s) (each and all, an "owner") of an original work of
|
||||
authorship and/or a database (each, a "Work").
|
||||
|
||||
Certain owners wish to permanently relinquish those rights to a Work for
|
||||
the purpose of contributing to a commons of creative, cultural and
|
||||
scientific works ("Commons") that the public can reliably and without fear
|
||||
of later claims of infringement build upon, modify, incorporate in other
|
||||
works, reuse and redistribute as freely as possible in any form whatsoever
|
||||
and for any purposes, including without limitation commercial purposes.
|
||||
These owners may contribute to the Commons to promote the ideal of a free
|
||||
culture and the further production of creative, cultural and scientific
|
||||
works, or to gain reputation or greater distribution for their Work in
|
||||
part through the use and efforts of others.
|
||||
|
||||
For these and/or other purposes and motivations, and without any
|
||||
expectation of additional consideration or compensation, the person
|
||||
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
|
||||
is an owner of Copyright and Related Rights in the Work, voluntarily
|
||||
elects to apply CC0 to the Work and publicly distribute the Work under its
|
||||
terms, with knowledge of his or her Copyright and Related Rights in the
|
||||
Work and the meaning and intended legal effect of CC0 on those rights.
|
||||
|
||||
1. Copyright and Related Rights. A Work made available under CC0 may be
|
||||
protected by copyright and related or neighboring rights ("Copyright and
|
||||
Related Rights"). Copyright and Related Rights include, but are not
|
||||
limited to, the following:
|
||||
|
||||
i. the right to reproduce, adapt, distribute, perform, display,
|
||||
communicate, and translate a Work;
|
||||
ii. moral rights retained by the original author(s) and/or performer(s);
|
||||
iii. publicity and privacy rights pertaining to a person's image or
|
||||
likeness depicted in a Work;
|
||||
iv. rights protecting against unfair competition in regards to a Work,
|
||||
subject to the limitations in paragraph 4(a), below;
|
||||
v. rights protecting the extraction, dissemination, use and reuse of data
|
||||
in a Work;
|
||||
vi. database rights (such as those arising under Directive 96/9/EC of the
|
||||
European Parliament and of the Council of 11 March 1996 on the legal
|
||||
protection of databases, and under any national implementation
|
||||
thereof, including any amended or successor version of such
|
||||
directive); and
|
||||
vii. other similar, equivalent or corresponding rights throughout the
|
||||
world based on applicable law or treaty, and any national
|
||||
implementations thereof.
|
||||
|
||||
2. Waiver. To the greatest extent permitted by, but not in contravention
|
||||
of, applicable law, Affirmer hereby overtly, fully, permanently,
|
||||
irrevocably and unconditionally waives, abandons, and surrenders all of
|
||||
Affirmer's Copyright and Related Rights and associated claims and causes
|
||||
of action, whether now known or unknown (including existing as well as
|
||||
future claims and causes of action), in the Work (i) in all territories
|
||||
worldwide, (ii) for the maximum duration provided by applicable law or
|
||||
treaty (including future time extensions), (iii) in any current or future
|
||||
medium and for any number of copies, and (iv) for any purpose whatsoever,
|
||||
including without limitation commercial, advertising or promotional
|
||||
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
|
||||
member of the public at large and to the detriment of Affirmer's heirs and
|
||||
successors, fully intending that such Waiver shall not be subject to
|
||||
revocation, rescission, cancellation, termination, or any other legal or
|
||||
equitable action to disrupt the quiet enjoyment of the Work by the public
|
||||
as contemplated by Affirmer's express Statement of Purpose.
|
||||
|
||||
3. Public License Fallback. Should any part of the Waiver for any reason
|
||||
be judged legally invalid or ineffective under applicable law, then the
|
||||
Waiver shall be preserved to the maximum extent permitted taking into
|
||||
account Affirmer's express Statement of Purpose. In addition, to the
|
||||
extent the Waiver is so judged Affirmer hereby grants to each affected
|
||||
person a royalty-free, non transferable, non sublicensable, non exclusive,
|
||||
irrevocable and unconditional license to exercise Affirmer's Copyright and
|
||||
Related Rights in the Work (i) in all territories worldwide, (ii) for the
|
||||
maximum duration provided by applicable law or treaty (including future
|
||||
time extensions), (iii) in any current or future medium and for any number
|
||||
of copies, and (iv) for any purpose whatsoever, including without
|
||||
limitation commercial, advertising or promotional purposes (the
|
||||
"License"). The License shall be deemed effective as of the date CC0 was
|
||||
applied by Affirmer to the Work. Should any part of the License for any
|
||||
reason be judged legally invalid or ineffective under applicable law, such
|
||||
partial invalidity or ineffectiveness shall not invalidate the remainder
|
||||
of the License, and in such case Affirmer hereby affirms that he or she
|
||||
will not (i) exercise any of his or her remaining Copyright and Related
|
||||
Rights in the Work or (ii) assert any associated claims and causes of
|
||||
action with respect to the Work, in either case contrary to Affirmer's
|
||||
express Statement of Purpose.
|
||||
|
||||
4. Limitations and Disclaimers.
|
||||
|
||||
a. No trademark or patent rights held by Affirmer are waived, abandoned,
|
||||
surrendered, licensed or otherwise affected by this document.
|
||||
b. Affirmer offers the Work as-is and makes no representations or
|
||||
warranties of any kind concerning the Work, express, implied,
|
||||
statutory or otherwise, including without limitation warranties of
|
||||
title, merchantability, fitness for a particular purpose, non
|
||||
infringement, or the absence of latent or other defects, accuracy, or
|
||||
the present or absence of errors, whether or not discoverable, all to
|
||||
the greatest extent permissible under applicable law.
|
||||
c. Affirmer disclaims responsibility for clearing rights of other persons
|
||||
that may apply to the Work or any use thereof, including without
|
||||
limitation any person's Copyright and Related Rights in the Work.
|
||||
Further, Affirmer disclaims responsibility for obtaining any necessary
|
||||
consents, permissions or other rights required for any use of the
|
||||
Work.
|
||||
d. Affirmer understands and acknowledges that Creative Commons is not a
|
||||
party to this document and has no duty or obligation with respect to
|
||||
this CC0 or use of the Work.
|
||||
117
LICENSES/GPL-2.0-or-later.txt
Normal file
117
LICENSES/GPL-2.0-or-later.txt
Normal file
@@ -0,0 +1,117 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and modification follow.
|
||||
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
one line to give the program's name and an idea of what it does. Copyright (C) yyyy name of author
|
||||
|
||||
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 the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
signature of Ty Coon, 1 April 1989 Ty Coon, President of Vice
|
||||
@@ -1,2 +1,6 @@
|
||||
SUBDIRS = src man
|
||||
EXTRA_DIST = buildconf
|
||||
# SPDX-FileCopyrightText: 2022 stenc authors
|
||||
#
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
SUBDIRS = src man tests bash-completion
|
||||
# EXTRA_DIST = buildconf
|
||||
|
||||
53
README.md
53
README.md
@@ -1,17 +1,24 @@
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2022 stenc authors
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
-->
|
||||
|
||||
[](https://api.reuse.software/info/github.com/scsitape/stenc/)
|
||||
|
||||
Stenc
|
||||
-----
|
||||
|
||||
SCSI Tape Encryption Manager - Manages encryption on LTO tape drives (starting with generation 4) with hardware-based encryption.
|
||||
Program should work on any other SCSI security protocol (SSP) capable tape drives. Built specifically for Linux and AIX.
|
||||
SCSI Tape Encryption Manager - Manages hardware encryption on LTO tape drives (starting with generation 4).
|
||||
Program should work on any other SCSI security protocol (SSP) capable tape drives.
|
||||
Supports key change auditing and key descriptors (uKAD).
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
* SCSI hardware-based encryption management
|
||||
* Supports AIX and Linux
|
||||
* Supports Linux and FreeBSD
|
||||
* Supports most SSP compliant devices, such as LTO-4 tape drives
|
||||
* Random key generation
|
||||
* Key change audit logging
|
||||
* AES Encryption
|
||||
* Key Descriptor Management
|
||||
@@ -20,21 +27,43 @@ Get the source code and compile
|
||||
-------------------------------
|
||||
|
||||
```
|
||||
git clone git@github.com:scsitape/stenc.git
|
||||
git clone https://github.com/scsitape/stenc.git
|
||||
cd stenc/
|
||||
autoreconf --install
|
||||
./configure
|
||||
./autogen.sh && ./configure
|
||||
make check # optionally run the catch testing framework
|
||||
make
|
||||
```
|
||||
|
||||
Usage example
|
||||
-------------
|
||||
|
||||
```
|
||||
$ stenc -f /dev/nst0
|
||||
Status for /dev/nst0 (TANDBERG LTO-6 HH 3579)
|
||||
--------------------------------------------------
|
||||
Reading: Decrypting (AES-256-GCM-128)
|
||||
Writing: Encrypting (AES-256-GCM-128)
|
||||
Protecting from raw read
|
||||
Key instance counter: 1
|
||||
Drive key desc. (U-KAD): mykey20170113
|
||||
Supported algorithms:
|
||||
1 AES-256-GCM-128
|
||||
Key descriptors allowed, maximum 32 bytes
|
||||
Raw decryption mode allowed, raw read enabled by default
|
||||
```
|
||||
|
||||
Linux Packages
|
||||
--------------
|
||||
[](https://repology.org/metapackage/stenc)
|
||||
|
||||
Requirements
|
||||
------------
|
||||
AIX support was suspended on 2022-05-08 until we have contributors who can develop and test the code on AIX.
|
||||
|
||||
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
|
||||
@@ -45,3 +74,13 @@ 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.
|
||||
|
||||
Further reading
|
||||
---------------
|
||||
|
||||
IBM Tape Library Guide for Open Systems
|
||||
ISBN-13: 9780738458342
|
||||
http://www.redbooks.ibm.com/abstracts/sg245946.html?Open
|
||||
|
||||
|
||||
SCSI-Programming-HOWTO
|
||||
https://tldp.org/HOWTO/archived/SCSI-Programming-HOWTO/SCSI-Programming-HOWTO-9.html
|
||||
|
||||
@@ -1,2 +1,7 @@
|
||||
#/usr/bin/env sh
|
||||
#!/bin/sh
|
||||
|
||||
# SPDX-FileCopyrightText: 2022 stenc authors
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
autoreconf --install || exit 1
|
||||
|
||||
8
bash-completion/Makefile.am
Normal file
8
bash-completion/Makefile.am
Normal file
@@ -0,0 +1,8 @@
|
||||
# SPDX-FileCopyrightText: 2022 stenc authors
|
||||
#
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
if ENABLE_BASH_COMPLETION
|
||||
bashcompletiondir = $(BASH_COMPLETION_DIR)
|
||||
dist_bashcompletion_DATA = stenc
|
||||
endif
|
||||
49
bash-completion/stenc
Normal file
49
bash-completion/stenc
Normal file
@@ -0,0 +1,49 @@
|
||||
#/usr/bin/env bash
|
||||
|
||||
# SPDX-FileCopyrightText: 2022 stenc authors
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#stenc bash completion
|
||||
|
||||
_stenc () {
|
||||
local cur prev words cword
|
||||
_init_completion || return
|
||||
|
||||
COMPREPLY=()
|
||||
|
||||
case $prev in
|
||||
--version )
|
||||
return
|
||||
;;
|
||||
-f )
|
||||
#list tape devices
|
||||
if [[ $(uname) == Linux ]]; then
|
||||
for tape in /sys/class/scsi_tape/*;
|
||||
do devs+="/dev/${tape##*/} ";
|
||||
done;
|
||||
COMPREPLY=($(compgen -W "$devs" -- "$cur"))
|
||||
else
|
||||
_filedir
|
||||
fi
|
||||
return
|
||||
;;
|
||||
-e | --encrypt )
|
||||
COMPREPLY=($(compgen -W 'off on' -- "$cur"))
|
||||
return
|
||||
;;
|
||||
-d | --decrypt )
|
||||
COMPREPLY=($(compgen -W 'off on mixed' -- "$cur"))
|
||||
return
|
||||
;;
|
||||
-k | --key-file )
|
||||
_filedir
|
||||
return
|
||||
;;
|
||||
esac
|
||||
|
||||
if [[ $cur == -* ]]; then
|
||||
COMPREPLY=($(compgen -W '-f --file -e --encrypt -d --decrypt -k --key-file -a --algorithm --allow-raw-read --no-allow-raw-read --ckod -h --help --version' -- "$cur"))
|
||||
return
|
||||
fi
|
||||
}
|
||||
complete -F _stenc stenc
|
||||
81
configure.ac
81
configure.ac
@@ -1,17 +1,16 @@
|
||||
AC_INIT([stenc], [1.0.8])
|
||||
AC_CONFIG_SRCDIR([src/main.cpp])
|
||||
AM_INIT_AUTOMAKE([foreign])
|
||||
# SPDX-FileCopyrightText: 2022 stenc authors
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_CHECK_HEADER([sys/types.h])
|
||||
AC_CHECK_HEADER([sys/machine.h])
|
||||
AC_INIT([stenc],[2.0.0])
|
||||
AC_CONFIG_SRCDIR([src/main.cpp])
|
||||
AM_INIT_AUTOMAKE([foreign subdir-objects])
|
||||
|
||||
AC_CONFIG_HEADERS([config.h])]
|
||||
AC_CHECK_HEADERS
|
||||
AC_CHECK_HEADERS([arpa/inet.h netinet/in.h])
|
||||
# Checks for programs
|
||||
AC_PROG_CXX
|
||||
|
||||
# Checks for header files.
|
||||
AC_HEADER_STDC
|
||||
|
||||
|
||||
AC_MSG_CHECKING(whether to output raw SCSI messages)
|
||||
AC_ARG_WITH([scsi-debug],
|
||||
[AS_HELP_STRING([--with-scsi-debug],[enable scsi communication debug])],
|
||||
@@ -19,29 +18,6 @@ AC_ARG_WITH([scsi-debug],
|
||||
AC_MSG_RESULT(yes)],
|
||||
[AC_MSG_RESULT(no)])
|
||||
|
||||
AC_MSG_CHECKING(max tape read blocks for volume status)
|
||||
AC_ARG_WITH([max-tape-read-blocks],
|
||||
[AS_HELP_STRING([--with-max-tape-read-blocks=<number>],[how many blocks the tape drive will seek to determine the encryption status on the volume. Defaults to 100])],
|
||||
[AC_DEFINE_UNQUOTED([MAX_TAPE_READ_BLOCKS],$withval,"") AC_MSG_RESULT($withval)],
|
||||
[AC_DEFINE([MAX_TAPE_READ_BLOCKS],100,"") AC_MSG_RESULT(100)])
|
||||
|
||||
AC_MSG_CHECKING(default encryption algorithm index to use)
|
||||
AC_ARG_WITH([default-algorithm],
|
||||
[AS_HELP_STRING([--with-default-algorithm=<number>],[the default algorithm index to set for encryption. Defaults to 0])],
|
||||
[AC_DEFINE_UNQUOTED([DEFAULT_ALGORITHM],$withval,"") AC_MSG_RESULT($withval)],
|
||||
[AC_DEFINE([DEFAULT_ALGORITHM],0,"") AC_MSG_RESULT(0)])
|
||||
|
||||
AC_MSG_CHECKING(default CEEM flag to use)
|
||||
AC_ARG_WITH([default-ceem],
|
||||
[AS_HELP_STRING([--with-default-ceem=<number>],[the default CEEM flag when setting options. Defaults to 0])],
|
||||
[AC_DEFINE_UNQUOTED([DEFAULT_CEEM],$withval,"") AC_MSG_RESULT($withval)],
|
||||
[AC_DEFINE([DEFAULT_CEEM],0,"") AC_MSG_RESULT(0)])
|
||||
AC_MSG_CHECKING(default key size to use)
|
||||
AC_ARG_WITH([default-key-size],
|
||||
[AS_HELP_STRING([--with-default-key-size=<bytes>],[the default key size for your drive. Only used when turning off encryption. Defaults to 32 (256 bit)])],
|
||||
[AC_DEFINE_UNQUOTED([DEFAULT_KEYSIZE],$withval,"") AC_MSG_RESULT($withval)],
|
||||
[AC_DEFINE([DEFAULT_KEYSIZE],32,"") AC_MSG_RESULT(32)])
|
||||
|
||||
AC_MSG_CHECKING(your OS)
|
||||
system=`uname`
|
||||
case $system in
|
||||
@@ -53,10 +29,6 @@ case $system in
|
||||
AC_DEFINE(OS_FREEBSD,1,"")
|
||||
AC_MSG_RESULT(FreeBSD)
|
||||
;;
|
||||
AIX)
|
||||
AC_DEFINE(OS_AIX,1,"")
|
||||
AC_MSG_RESULT(AIX)
|
||||
;;
|
||||
*)
|
||||
AC_MSG_ERROR(unknown OS type: $system)
|
||||
;;
|
||||
@@ -67,31 +39,28 @@ AC_ARG_WITH([static-libgcc],
|
||||
[AS_HELP_STRING([--with-static-libgcc],[build with static libgcc library])],
|
||||
[
|
||||
AC_MSG_RESULT(yes)
|
||||
if test "${system}" = "AIX"; then
|
||||
LDFLAGS="${LDFLAGS} -static-libgcc -Wl,-bstatic -lstdc++ -Wl,-bdynamic -lsupc++"
|
||||
else
|
||||
LDFLAGS="${LDFLAGS} -static-libgcc -Wl,-static -lstdc++ -lsupc++"
|
||||
|
||||
fi
|
||||
],
|
||||
[AC_MSG_RESULT(no)])
|
||||
|
||||
AC_CHECK_PROG(PANDOC, [pandoc], [yes])
|
||||
AM_CONDITIONAL([FOUND_PANDOC], [test "x$PANDOC" = xyes])
|
||||
AM_COND_IF([FOUND_PANDOC],,[AC_MSG_ERROR([required program 'pandoc' not found.])])
|
||||
|
||||
AC_MSG_CHECKING(whether to convert rewinding device names to non-rewinding device names)
|
||||
AC_ARG_ENABLE([device-name-conversion],
|
||||
[AS_HELP_STRING([--enable-device-name-conversion],[converts /dev/st* to /dev/st*.1 and /dev/rmt* to /dev/rmt*.1 to prevent rewinds. Enabled by default.])],
|
||||
[enable_dnc=$enableval],
|
||||
[enable_dnc="yes"]
|
||||
)
|
||||
|
||||
if test "$enable_dnc" = "yes"; then
|
||||
AC_MSG_RESULT(yes)
|
||||
else
|
||||
AC_DEFINE(DISABLE_DEVICE_NAME_CONVERSION,1,"")
|
||||
AC_MSG_RESULT(no)
|
||||
if test "${system}" = "FreeBSD"; then
|
||||
LIBS="${LIBS} -lcam"
|
||||
fi
|
||||
|
||||
# BASH completion
|
||||
PKG_CHECK_VAR([BASH_COMPLETION_DIR], [bash-completion >= 2.0], [completionsdir],
|
||||
[
|
||||
with_bash_completion_dir=yes;
|
||||
AC_MSG_NOTICE(BASH_COMPLETION_DIR is $BASH_COMPLETION_DIR);
|
||||
AC_SUBST([BASH_COMPLETION_DIR])
|
||||
],
|
||||
[with_bash_completion_dir=no])
|
||||
|
||||
AM_CONDITIONAL([ENABLE_BASH_COMPLETION],[test "x$with_bash_completion_dir" != "xno"])
|
||||
|
||||
AC_OUTPUT(Makefile src/Makefile man/Makefile)
|
||||
|
||||
AC_CONFIG_FILES([Makefile src/Makefile man/Makefile tests/Makefile bash-completion/Makefile])
|
||||
AC_OUTPUT
|
||||
|
||||
@@ -1 +1,19 @@
|
||||
dist_man_MANS = stenc.1
|
||||
# SPDX-FileCopyrightText: 2022 stenc authors
|
||||
#
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
man1_MANS = stenc.1
|
||||
|
||||
EXTRA_DIST = stenc.rst
|
||||
|
||||
all: stenc.1
|
||||
|
||||
stenc.1: stenc.rst
|
||||
pandoc --standalone --to man $? -o $@
|
||||
|
||||
clean:
|
||||
rm -f stenc.1
|
||||
|
||||
distclean: clean
|
||||
rm -f Makefile
|
||||
|
||||
|
||||
128
man/stenc.1
128
man/stenc.1
@@ -1,128 +0,0 @@
|
||||
.TH STENC 1
|
||||
|
||||
.SH NAME
|
||||
|
||||
stenc - SCSI Tape Hardware Encryption Manager
|
||||
|
||||
.SH SYNOPSIS
|
||||
\fBstenc\fR \fB\-g\fR \fIlength\fR \fB\-k\fR \fIfile\fR [\fB\-kd\fR \fIdescription\fR]
|
||||
.br
|
||||
\fBstenc\fR \fB\-f\fR \fIdevice\fR [\fB\-\-detail\fR]
|
||||
.br
|
||||
\fBstenc\fR \fB\-f\fR \fIdevice\fR \fB\-e\fR \fBon\fR|\fBmixed\fR|\fBrawread\fR [\fB\-a\fR \fIindex\fR] [\fB\-k\fR \fIfile\fR] [\fB\-\-ckod\fR] [\fB\-\-protect\fR | \fB\-\-unprotect\fR]
|
||||
.br
|
||||
\fBstenc\fR \fB\-f\fR \fIdevice\fR \fB\-e\fR \fBoff\fR [\fB\-a\fR \fIindex\fR] [\fB\-\-ckod\fR] [\fB\-\-protect\fR | \fB\-\-unprotect\fR]
|
||||
.br
|
||||
\fBstenc\fR \fB\-\-version\fR
|
||||
|
||||
|
||||
.SH AVAILABILITY
|
||||
|
||||
Linux, AIX
|
||||
|
||||
.SH DESCRIPTION
|
||||
|
||||
Allows you to manage hardware encryption on SSP enabled tape devices (LTO4, LTO5, etc).
|
||||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
\fB\-g \fIlength\fR \fB\-k\fR \fB<file to save as>\fR [\fB\-kd\fR \fI<key descriptor(uKAD)>\fR]
|
||||
Generates a key file of \fIlength\fR (in bits) containing a random hexadecimal key. After entering this option, you will be required to press random keys followed by the enter key. This will seed the random number generator so that your key is more secure. Specify the file to save the key into with the -k option (you will need write permissions to that file location). Lastly you can enter an optional key description using the -kd flag (see \fIKEY DESCRIPTORS\fR). This key file can then be used with the \fB\-k\fR option. You should not generate a key file over an unsecured remote session. Typically, key files should be set to 256 bits (32 hexadecimal bytes), however your device may only support 128 bits.
|
||||
|
||||
.TP
|
||||
\fB\-f\fR \fIdevice\fR
|
||||
|
||||
Specifies the device to use (i.e. \fI/dev/nst0, /dev/rmt0.1, /dev/sg0\fR). Use the \fBlsscsi\fR command to determine the appropriate device to use. You should always use a device name that does not rewind (i.e. use /dev/nst0 instead of /dev/st0, /dev/rmt0.1 instead of /dev/rmt0). Use commands like 'cat /proc/scsi/scsi', 'lsscsi', and 'lsdev' to determine the proper device to use. On some distros, a /dev/sg device must be used instead of a /dev/st device.
|
||||
|
||||
If this is the only option specified, the status of the device will be displayed. To retrieve more detailed status information, add \fB\-\-detail\fR. If you are root and the status command fails, either the \fIdevice\fR is incorrect (try another link to the device: \fI/dev/rmt0.1\fR, \fI/dev/nst0\fR, \fI/dev/tape\fR, etc.), a tape may not be in the drive, you may be using the wrong algorithm for the tape drive (see the \fB\-a\fR option), or the device does not support SCSI Security Protocol. \fBstenc\fR may read up to 100 blocks of the tape, starting at the current position, in order to determine if the volume has been encrypted. For this reason, you should not run the status command while another process is accessing the drive. If the device returns \fIUnable to determine\fR for the volume encryption status, you may need to move to a section of the tape that contains data (i.e. \fBmt -f <device> fsr <count>\fR) or rewind the tape in order for \fBstenc\fR to output the volume status.
|
||||
|
||||
.TP
|
||||
\fB\-e\fR \fBon\fR | \fBmixed\fR | \fBrawread\fR | \fBoff\fR
|
||||
|
||||
Sets the encryption mode for the device specified with \fB\-f\fR option. Successful operations of this type will create an audit entry in the \fI/var/log/stenc\fR file. If \fBoff\fR is not specified and the \fB\-k\fR option is not specified, the program will require the user to enter a hexadecimal key (see \fIKEY INPUT SYNTAX\fR) and an optional key description (see \fIKEY DESCRIPTORS\fR).
|
||||
|
||||
\fBon\fR - The drive will encrypt all data sent to it and will only output data it is able to decrypt, ignoring unencrypted data on the drive.
|
||||
|
||||
\fBmixed\fR - The drive will encrypt all data sent to it and will output both encrypted data and unencrypted data, providing the drive is able to do so.
|
||||
|
||||
\fBrawread\fR - The drive will encrypt all data sent to it and will output unencrypted data and raw encrypted data. You will probably need to have specified \fB\-\-unprotect\fR when the data was written in order to read it with this option. Some drives do not support this option. See the \fB\-\-protect\fR option.
|
||||
|
||||
\fBoff\fR - The drive will neither encrypt data sent to it, or decrypt encrypted data found on the drive. If this command fails you may have switch your algorithm or specify a different default key size when you configure the program
|
||||
|
||||
\fBWARNING:\fR The SCSI device will revert all encryption settings if the tape device is power cycled (if the tape drive is extenal, it may keep the settings even if the system is rebooted). You can modify you local startup script (/etc/rc.local, /etc/rc, etc.) to set encryption at reboot if need be. If you do this, you will need to use the \fB\-k\fR option to prevent the system from waiting on the local console user to enter the encryption key.
|
||||
|
||||
.TP
|
||||
\fB\-a\fR \fIindex\fR
|
||||
|
||||
Only valid when setting encryption (see the \fB\-e\fR option). Specifies the algorithm index to use for the device (defaults to 0, which can be changed using the --with-default-algorithm configure option). Setting encryption on/off may fail on some devices if this is not the correct algorithm for the drive (i.e. HP drives use an algorithm index of 1).
|
||||
|
||||
.TP
|
||||
\fB\-\-ckod\fR
|
||||
|
||||
Only valid when setting encryption (see the \fB\-e\fR option). Instructs the drive to clear its encryption keys when the volume is unmounted instead of keeping it until the drive is power cycled. Some devices may not support this option.
|
||||
|
||||
.TP
|
||||
\fB\-\-protect\fR | \fB\-\-unprotect\fR
|
||||
|
||||
Only valid when setting encryption (see the \fB\-e\fR option). Instructs the drive to \fBprotect\fR or \fBunprotect\fR any encrypted data from being raw read. See the \fB\-e rawread\fR option. Some devices may not support these options.
|
||||
|
||||
.TP
|
||||
\fB\-k\fR \fIfile\fR
|
||||
|
||||
Only valid when turning encryption on (see the \fB\-e\fR option) or generating a new key (see the \fB\-g\fR option). When turning encryption on, this specifies the location of a key file previously generated with the \fB\-g\fR option. When generating a new key with the \fB\-g\fR option, this specifies the key file that the new key will be saved into. Key files should be owned by root ('\fBchown root\fR') and only readable by root ('\fBchmod 600\fR'). \fBstenc\fR automatically chmods key files generated with the \fB\-g\fR option.
|
||||
.SH KEY INPUT SYNTAX
|
||||
.TP
|
||||
|
||||
All keys should be a maximum of 256 bits (32 bytes). \fBstenc\fR requires that all keys are entered using 2 digit hexadecimal bytes, with no delimiters in between bytes. Do not precede your key input with '0x'. If you try to use a key size that the drive does not support, the command will error. When using a key file, the second line in the file can contain an optional key description that will be displayed with the device status (see the \fB\-f\fR option).
|
||||
|
||||
.TP
|
||||
\fBExample 128 bit Key:\fR
|
||||
000102030405060708090a0b0c0d0e0f
|
||||
|
||||
.TP
|
||||
\fBExample 256 bit Key:\fR
|
||||
000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f
|
||||
|
||||
.SH EXAMPLE
|
||||
.TP
|
||||
\fBstenc -g 256 -k /etc/tape.key -kd "September Tape Key"\fR
|
||||
Generate a random 256 bit key file with the description "September Tape Key" and save it into /etc/tape.key
|
||||
.TP
|
||||
\fBstenc -f /dev/st0 -e on -k /etc/stenc.key\fR
|
||||
Turns on encryption on /dev/st0 using the key contained in /etc/stenc.key
|
||||
.TP
|
||||
\fBstenc -f /dev/st0 -e on\fR
|
||||
Asks user to input a key in hexadecimal format and then turns on encryption for /dev/st0 using that key
|
||||
.TP
|
||||
\fBstenc -f /dev/st0 -e off\fR
|
||||
Turns off encryption for /dev/st0
|
||||
.TP
|
||||
\fBstenc -f /dev/st0 --detail\fR
|
||||
Outputs the detailed encryption status of /dev/st0
|
||||
.TP
|
||||
\fBtail /var/log/stenc\fR
|
||||
Lists the last few key change audit entries
|
||||
|
||||
.SH KEY CHANGE AUDITING
|
||||
Each time a key is changed using this program, a corresponding entry will be entered into the \fI/var/log/stenc\fR file. These entries will have an \fIKey Instance Counter\fR corresponding to the counter listed in the device status (see the \fB\-f\fR option). Each time the key is set, a checksum of that key (or a key description) is also listed in this file. This allows you to know when keys were changed and if the key you are using is the same as a prior key. If an unauthorized party would compromise this log file, your key security would be decreased if checksums were present in the log. To prevent this, you should use key descriptors instead of checksums (see \fIKEY DESCRIPTORS\fR).
|
||||
|
||||
.SH KEY DESCRIPTORS
|
||||
Key descriptors are set when using the \fB\-g\fR option or the \fB\-e\fR option. They will be displayed when retrieving the drive status (see the \fB\-f\fR option). These descriptors will be written to the volume, so they should NEVER contain information that would reduce the security of the key (i.e. a checksum, bitlength, algorithm, a portion of the key). If \fBstenc\fR detects that the volume is encrypted but it cannot decrypt the data, the key descriptor on the volume will be displayed as part of the device status. This can be useful for determining which key goes to which volume.
|
||||
|
||||
.SH AUTHOR
|
||||
Written by \fBJohn Coleman\fR and \fBSamuel Martinez Jr.\fR of SunWest Educational Credit Union.
|
||||
|
||||
.SH REPORTING BUGS
|
||||
Report \fBstenc\fR bugs to \fIjcoleman1981@live.com\fR.
|
||||
|
||||
.SH PROJECT UPDATES
|
||||
Visit \fBhttp://sourceforge.net/projects/stenc/\fR for more information.
|
||||
|
||||
.SH COPYRIGHT
|
||||
Copyright 2012 contributing authors. License GPLv2: GNU GPL version 2 <http://gnu.org/licenses/gpl.html>. This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.
|
||||
|
||||
.SH SEE ALSO
|
||||
\fBmt\fR(1L)
|
||||
.br
|
||||
\fBlsscsi\fR(8)
|
||||
|
||||
207
man/stenc.rst
Normal file
207
man/stenc.rst
Normal file
@@ -0,0 +1,207 @@
|
||||
.. SPDX-FileCopyrightText: 2022 stenc authors
|
||||
..
|
||||
.. SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
=================================
|
||||
STENC(1) |General Commands Manual
|
||||
=================================
|
||||
|
||||
NAME
|
||||
====
|
||||
|
||||
stenc - SCSI Tape Hardware Encryption Manager
|
||||
|
||||
SYNOPSIS
|
||||
========
|
||||
|
||||
| **stenc** [**-f** *DEVICE*]
|
||||
| **stenc** [**-f** *DEVICE*] [**-e** *ENC-MODE*] [**-d** *DEC-MODE*] [*OPTIONS*]
|
||||
|
||||
DESCRIPTION
|
||||
===========
|
||||
|
||||
**stenc** manages hardware data encryption on tape devices that support
|
||||
the SCSI security protocol.
|
||||
|
||||
Controlling device encryption
|
||||
-----------------------------
|
||||
|
||||
The encryption mode (what happens to data written to the
|
||||
device), and decryption mode (what happens to data read from the device)
|
||||
can be controlled independently. If only one of the following options is
|
||||
given, the other mode will be inferred to set the encryption and decryption
|
||||
modes in tandem.
|
||||
|
||||
**-e, --encrypt**=\ *ENC-MODE*
|
||||
Sets the encryption mode. *ENC-MODE* is either *off* or *on*.
|
||||
|
||||
**off**
|
||||
Data written to the device will be not encrypted.
|
||||
|
||||
**on**
|
||||
Data written to the device will be encrypted.
|
||||
|
||||
**-d, --decrypt**=\ *DEC-MODE*
|
||||
Sets the decryption mode. *DEC-MODE* is either *off*, *on*, or *mixed*.
|
||||
|
||||
**off**
|
||||
Data read from the device will not be decrypted and only unencrypted
|
||||
tape blocks can be read.
|
||||
|
||||
**on**
|
||||
Data read from the device will be decrypted and only encrypted tape blocks can
|
||||
be read. The drive will only read data it is able to decrypt, and will not
|
||||
read unencrypted data on the drive.
|
||||
|
||||
**mixed**
|
||||
Data read from the device will be decrypted, if needed. Both encrypted and
|
||||
unencrypted tape blocks can be read. The drive will read both encrypted
|
||||
data and unencrypted data, provided the drive is able to do so.
|
||||
|
||||
Viewing device status
|
||||
---------------------
|
||||
|
||||
When neither options to set encryption or decryption mode are given, **stenc**
|
||||
prints the encryption settings, the encryption status of the current block,
|
||||
and capabilities of the device, including a list of supported algorithm indexes.
|
||||
The device may display current block encryption status as *Unable to determine*
|
||||
if the tape is positioned at a filemark or end of tape, in which case it may be
|
||||
necessary to move the tape position using **mt**\ (1).
|
||||
|
||||
OPTIONS
|
||||
=======
|
||||
|
||||
**-f, --file**=\ *DEVICE*
|
||||
Specifies the device to use (e.g. */dev/nst0*, */dev/nsa0*, */dev/rmt0.1*).
|
||||
Use the **lsscsi**\ (8) command on Linux, or **camcontrol**\ (8) on FreeBSD
|
||||
to determine the appropriate device to use. It is recommended to the use a
|
||||
non-rewinding device (i.e. */dev/nst0* instead of */dev/st0*, */dev/rmt0.1*
|
||||
instead of */dev/rmt0*). Typically, only the superuser can access tape
|
||||
devices.
|
||||
|
||||
If this option is omitted, and the environment variable **TAPE** is
|
||||
set, it is used. Otherwise, a default device defined in the system header
|
||||
*mtio.h* is used.
|
||||
|
||||
**-a, --algorithm**=\ *index*
|
||||
Selects the encryption algorithm to use for the device.
|
||||
Changing encryption settings may fail on some devices if this is not a
|
||||
supported algorithm for the drive (e.g. HP drives use an algorithm
|
||||
index of 1). A list of supported algorithms can be obtained by requesting
|
||||
device status. If the device only
|
||||
supports one algorithm, this option may be omitted and **stenc** will use
|
||||
the only choice. Otherwise **stenc** will print the list of supported algorithms
|
||||
and exit if this option is omitted.
|
||||
|
||||
**-k, --key-file**=\ *FILE* \| *-*
|
||||
Read the encryption key and optional key descriptor from *FILE*, or
|
||||
standard input when *FILE* is *-*. If standard input is a terminal,
|
||||
this will prompt for the key and optional key
|
||||
descriptor. This option is required when *ENC-MODE* and *DEC-MODE*
|
||||
are not both *off*. See *KEY INPUT SYNTAX* for the expected format of the
|
||||
key file.
|
||||
|
||||
**--ckod**
|
||||
Clear key on demount. Instructs the device to clear its encryption keys when
|
||||
the tape is unloaded instead of keeping it until the drive is power cycled.
|
||||
This option may only be given if tape media is presently loaded in the
|
||||
device. Some devices may not support this option.
|
||||
|
||||
**--allow-raw-read** \| **--no-allow-raw-read**
|
||||
Instructs the device to mark encrypted blocks written to the tape to allow
|
||||
(or disallow) subsequent raw mode reads. If neither option is given, the
|
||||
device default is used, which can be found by requesting the device status.
|
||||
Some devices may not support these options.
|
||||
|
||||
**-h, --help**
|
||||
Print a usage message and exit.
|
||||
|
||||
**--version**
|
||||
Print version information and exit.
|
||||
|
||||
KEY INPUT SYNTAX
|
||||
================
|
||||
|
||||
**stenc** requires that all keys are entered as text hexadecimal strings,
|
||||
with no delimiters in between bytes. Do not precede your key input with *0x*.
|
||||
When using a key file, the second line in the file can contain an optional
|
||||
key descriptor that will be displayed with the device status (see
|
||||
*KEY DESCRIPTORS*).
|
||||
|
||||
Keys can be generated using any cryptographically secure entropy source,
|
||||
such as the **random**\ (4) device or the **openssl**\ (1SSL) suite of commands.
|
||||
A 256-bit key file can be created with the following command:
|
||||
|
||||
openssl rand -hex 32
|
||||
|
||||
**Example 128 bit key:**
|
||||
|
||||
000102030405060708090a0b0c0d0e0f
|
||||
|
||||
**Example 256 bit key:**
|
||||
|
||||
000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f
|
||||
|
||||
**Example 256 key file with key descriptor:**
|
||||
|
||||
| 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f
|
||||
| April backup key
|
||||
|
||||
KEY DESCRIPTORS
|
||||
===============
|
||||
|
||||
A key file (see *KEY INPUT SYNTAX*) can optionally include a key descriptor.
|
||||
The descriptor will be written with each tape block, and will be displayed
|
||||
when retrieving the drive status, so it should *never* contain information
|
||||
that would reduce the security of the key (i.e. a checksum or any portion of
|
||||
the key). If **stenc** detects a tape block is encrypted but it cannot decrypt
|
||||
the data, the key descriptor of the current block, if any, will be displayed
|
||||
as part of the device status. This can be useful for determining which key
|
||||
is used.
|
||||
|
||||
KEY CHANGE AUDITING
|
||||
===================
|
||||
|
||||
Each time device encryption settings are changed, **stenc** will write an
|
||||
entry to the system log. These entries will have a *Key Instance Counter*
|
||||
corresponding to the counter listed in the device status. Each time the key
|
||||
is set, the key descriptor, if any, is also written to the log. This allows
|
||||
you to know when keys were changed and if the key you are using is the same
|
||||
as a prior key.
|
||||
|
||||
EXAMPLE
|
||||
=======
|
||||
|
||||
**stenc -f /dev/nst0 -e on -d on -k /etc/stenc.key**
|
||||
Turns on encryption and decryption for */dev/nst0* using the key
|
||||
in */etc/stenc.key*
|
||||
|
||||
**stenc -f /dev/nst0 -e on -d mixed -k -**
|
||||
Asks user to input a key in hexadecimal format and then turns on
|
||||
encryption, with mixed decryption mode, for */dev/nst0*
|
||||
|
||||
**stenc -f /dev/nst0 -e off -d off**
|
||||
Turns off encryption and decryption for */dev/nst0*
|
||||
|
||||
**stenc -f /dev/nst0**
|
||||
Prints the encryption status of */dev/nst0*
|
||||
|
||||
BUGS
|
||||
====
|
||||
|
||||
Report bugs to **https://github.com/scsitape/stenc/issues**
|
||||
|
||||
COPYRIGHT
|
||||
=========
|
||||
|
||||
Copyright 2012-2022 contributing authors. License GPLv2: GNU GPL version 2
|
||||
<http://gnu.org/licenses/gpl.html>. This is free software: you are free
|
||||
to change and redistribute it. There is NO WARRANTY, to the extent
|
||||
permitted by law.
|
||||
|
||||
SEE ALSO
|
||||
========
|
||||
|
||||
| **openssl**\ (1SSL)
|
||||
| **mt**\ (1)
|
||||
| **lsscsi**\ (8)
|
||||
@@ -1,4 +1,8 @@
|
||||
# SPDX-FileCopyrightText: 2022 stenc authors
|
||||
#
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
bin_PROGRAMS = stenc
|
||||
AM_CXXFLAGS = $(INTI_CFLAGS) $(DEPS_CFLAGS)
|
||||
stenc_SOURCES = main.cpp scsiencrypt.cpp scsiencrypt.h keyinfo.h keyinfo.cpp
|
||||
AM_CXXFLAGS = -std=c++17 $(INTI_CFLAGS) $(DEPS_CFLAGS)
|
||||
stenc_SOURCES = main.cpp scsiencrypt.cpp scsiencrypt.h
|
||||
#stenc_LDADD = $(INTI_LIBS)
|
||||
|
||||
123
src/keyinfo.cpp
123
src/keyinfo.cpp
@@ -1,123 +0,0 @@
|
||||
#include <config.h>
|
||||
#include <iostream>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include "keyinfo.h"
|
||||
#include "scsiencrypt.h"
|
||||
using namespace std;
|
||||
|
||||
Keyinfo::Keyinfo(){
|
||||
valid=false;
|
||||
check="";
|
||||
key=NULL;
|
||||
keySize=0;
|
||||
}
|
||||
void Keyinfo::load(string hexinput){
|
||||
valid=true;
|
||||
if(hexinput.size()<2){
|
||||
valid=false;
|
||||
cout<<"Key input too short!"<<endl;
|
||||
return;
|
||||
|
||||
}
|
||||
//parse for invalid characters
|
||||
for(unsigned int i=0;i<hexinput.size();i++){
|
||||
switch((unsigned char)hexinput.at(i)){
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
case 'a':
|
||||
case 'b':
|
||||
case 'c':
|
||||
case 'd':
|
||||
case 'e':
|
||||
case 'f':
|
||||
case 'A':
|
||||
case 'B':
|
||||
case 'C':
|
||||
case 'D':
|
||||
case 'E':
|
||||
case 'F':
|
||||
break;
|
||||
default:
|
||||
cout<<"Invalid character '"<<hexinput.at(i)<<"' found in key!"<<endl;
|
||||
valid=false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// delete the key if its already allocated
|
||||
if(key!=NULL)
|
||||
delete key;
|
||||
// check that the input size is divisible by 2
|
||||
if(hexinput.size()%2!=0){
|
||||
valid=false;
|
||||
cout<<"Each hexadecimal byte must consist of 2 digits!"<<endl;
|
||||
return;
|
||||
}
|
||||
//convert the hex input to a char*
|
||||
loadKey(hexinput);
|
||||
//load the check value
|
||||
loadCheck();
|
||||
//check for oversized key
|
||||
if(keySize==0 || keySize>SSP_KEY_LENGTH){
|
||||
cout<<"Key size cannot exceed "<<(SSP_KEY_LENGTH*8)<<" bits!"<<endl;
|
||||
cout<<"Provided key is "<<(keySize*8)<<" bits in length."<<endl;
|
||||
valid=false;
|
||||
return;
|
||||
}
|
||||
cout<<"Provided key length is "<<(keySize*8)<<" bits."<<endl;
|
||||
cout<<"Key checksum is "<<check<<"."<<endl;
|
||||
|
||||
|
||||
}
|
||||
void Keyinfo::loadCheck() {
|
||||
int i;
|
||||
int chk = 0;
|
||||
for (i = 0; i<keySize;i++) {
|
||||
chk += ((int)key[i]) * (i + 1);
|
||||
}
|
||||
stringstream retval;
|
||||
retval<<hex<<chk;
|
||||
check=retval.str();
|
||||
}
|
||||
Keyinfo::~Keyinfo(){
|
||||
delete key;
|
||||
}
|
||||
void Keyinfo::loadKey(string str)
|
||||
{
|
||||
int length = str.size();
|
||||
// make sure the input string has an even digit numbers
|
||||
if(length%2 == 1)
|
||||
{
|
||||
str = "0" + str;
|
||||
length++;
|
||||
}
|
||||
|
||||
// allocate memory for the output array
|
||||
key = new char[length/2];
|
||||
memset(key,0,(length/2)+1);
|
||||
keySize = length/2;
|
||||
|
||||
stringstream sstr(str);
|
||||
for(int i=0; i < keySize; i++)
|
||||
{
|
||||
char ch1, ch2;
|
||||
sstr >> ch1 >> ch2;
|
||||
int dig1=0, dig2=0;
|
||||
if(isdigit(ch1)) dig1 = ch1 - '0';
|
||||
else if(ch1>='A' && ch1<='F') dig1 = ch1 - 'A' + 10;
|
||||
else if(ch1>='a' && ch1<='f') dig1 = ch1 - 'a' + 10;
|
||||
if(isdigit(ch2)) dig2 = ch2 - '0';
|
||||
else if(ch2>='A' && ch2<='F') dig2 = ch2 - 'A' + 10;
|
||||
else if(ch2>='a' && ch2<='f') dig2 = ch2 - 'a' + 10;
|
||||
key[i] = dig1*16 + dig2;
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
#ifndef KEYINFO_H
|
||||
#define KEYINFO_H
|
||||
#include <string>
|
||||
|
||||
class Keyinfo{
|
||||
public:
|
||||
char* key;
|
||||
int keySize;
|
||||
bool valid;
|
||||
std::string check;
|
||||
void load(std::string hexinput);
|
||||
Keyinfo();
|
||||
~Keyinfo();
|
||||
private:
|
||||
void loadKey(std::string str);
|
||||
void loadCheck();
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
1235
src/main.cpp
1235
src/main.cpp
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,7 @@
|
||||
// SPDX-FileCopyrightText: 2022 stenc authors
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
/*
|
||||
Header file to send and recieve SPIN/SPOUT commands to SCSI device
|
||||
|
||||
@@ -13,614 +17,433 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
#include <config.h>
|
||||
#include <string>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <bitset>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
#include <type_traits>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#if defined(OS_LINUX)
|
||||
#include <scsi/sg.h>
|
||||
#include <scsi/scsi.h>
|
||||
#define SCSI_TIMEOUT 5000
|
||||
constexpr unsigned int SCSI_TIMEOUT {5000u};
|
||||
#elif defined(OS_FREEBSD)
|
||||
#include <cam/scsi/scsi_sg.h>
|
||||
#define SCSI_TIMEOUT 5000
|
||||
#elif defined(OS_AIX)
|
||||
#define _LINUX_SOURCE_COMPAT
|
||||
#include <sys/scsi.h>
|
||||
#include <sys/scsi_buf.h>
|
||||
#include <sys/tape.h>
|
||||
#include <sys/Atape.h>
|
||||
#define SCSI_TIMEOUT 5
|
||||
#include <cam/scsi/scsi_message.h>
|
||||
#include <camlib.h>
|
||||
constexpr unsigned int SCSI_TIMEOUT {5000u};
|
||||
constexpr unsigned int RETRYCOUNT {1u};
|
||||
#else
|
||||
#error "OS type is not set"
|
||||
#endif
|
||||
|
||||
#include <sys/mtio.h>
|
||||
#include "scsiencrypt.h"
|
||||
|
||||
#define SSP_SPIN_OPCODE 0XA2
|
||||
#define SSP_SPOUT_OPCODE 0XB5
|
||||
#define SSP_SP_CMD_LEN 12
|
||||
#define SSP_SP_PROTOCOL_TDE 0X20
|
||||
constexpr std::uint8_t SSP_SPIN_OPCODE {0xa2};
|
||||
constexpr std::uint8_t SSP_SPOUT_OPCODE {0xb5};
|
||||
constexpr std::uint8_t SSP_SP_PROTOCOL_TDE {0x20};
|
||||
|
||||
#define RETRYCOUNT 1
|
||||
#define BSINTTOCHAR(x) \
|
||||
static_cast<std::uint8_t>((x) >> 24), static_cast<std::uint8_t>((x) >> 16), \
|
||||
static_cast<std::uint8_t>((x) >> 8), static_cast<std::uint8_t>((x))
|
||||
|
||||
#define BSINTTOCHAR(x) (unsigned char)((x & 0xff000000)>>24), (unsigned char)((x & 0x00ff0000)>>16),(unsigned char)((x & 0x0000ff00)>>8),(unsigned char)(x & 0x000000ff)
|
||||
// generic_deleter permits the use of std::unique_ptr for RAII on non-pointer
|
||||
// types like file descriptors.
|
||||
template <typename T, T null_value, typename Deleter, Deleter d>
|
||||
struct generic_deleter {
|
||||
class pointer {
|
||||
T t;
|
||||
|
||||
public:
|
||||
pointer() : t {null_value} {}
|
||||
pointer(T t) : t {t} {}
|
||||
pointer(std::nullptr_t) : t {null_value} {}
|
||||
explicit operator bool() const noexcept { return t != null_value; }
|
||||
friend bool operator==(pointer lhs, pointer rhs) noexcept
|
||||
{
|
||||
return lhs.t == rhs.t;
|
||||
}
|
||||
friend bool operator!=(pointer lhs, pointer rhs) noexcept
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
operator T() const noexcept { return t; }
|
||||
};
|
||||
|
||||
using namespace std;
|
||||
void operator()(pointer p) const noexcept { d(p); }
|
||||
};
|
||||
using unique_fd =
|
||||
std::unique_ptr<int, generic_deleter<int, -1, decltype(&close), &close>>;
|
||||
|
||||
enum class scsi_direction { to_device, from_device };
|
||||
|
||||
void byteswap(unsigned char* array,int size,int value);
|
||||
bool moveTape(std::string tapeDevice,int count,bool dirForward);
|
||||
void outputSense(SCSI_PAGE_SENSE* sd);
|
||||
void readIOError(int err);
|
||||
struct hex {
|
||||
std::uint8_t value;
|
||||
};
|
||||
|
||||
bool SCSIExecute(string tapedevice, unsigned char* cmd_p,int cmd_len,unsigned char* dxfer_p,int dxfer_len, bool cmd_to_device, bool show_error);
|
||||
inline std::ostream& operator<<(std::ostream& os, hex h)
|
||||
{
|
||||
auto fill {os.fill('0')};
|
||||
auto flags {os.flags(std::ios_base::hex | std::ios_base::right)};
|
||||
|
||||
typedef struct { //structure for setting data encryption
|
||||
unsigned char pageCode [2];
|
||||
unsigned char length [2];
|
||||
os << std::setw(2) << static_cast<unsigned int>(h.value);
|
||||
|
||||
#if STENC_BIG_ENDIAN == 1
|
||||
unsigned char scope :3;
|
||||
unsigned char res_bits_1 :4;
|
||||
unsigned char lock :1;
|
||||
#else
|
||||
unsigned char lock :1;
|
||||
unsigned char res_bits_1 :4;
|
||||
unsigned char scope :3;
|
||||
os.flags(flags);
|
||||
os.fill(fill);
|
||||
return os;
|
||||
}
|
||||
|
||||
void print_buffer(std::ostream& os, const std::uint8_t *begin,
|
||||
std::size_t length)
|
||||
{
|
||||
auto fill {os.fill('0')};
|
||||
auto flags {os.flags(std::ios_base::hex | std::ios_base::right)};
|
||||
|
||||
std::for_each(begin, begin + length, [&](auto b) {
|
||||
os << std::setw(2) << static_cast<unsigned int>(b) << ' ';
|
||||
});
|
||||
|
||||
os.put('\n');
|
||||
|
||||
os.flags(flags);
|
||||
os.fill(fill);
|
||||
}
|
||||
|
||||
static void scsi_execute(const std::string& device, const std::uint8_t *cmd_p,
|
||||
std::size_t cmd_len, std::uint8_t *dxfer_p,
|
||||
std::size_t dxfer_len, scsi_direction direction)
|
||||
{
|
||||
#if defined(DEBUGSCSI)
|
||||
std::cerr << "SCSI Command: ";
|
||||
print_buffer(std::cerr, cmd_p, cmd_len);
|
||||
|
||||
if (direction == scsi_direction::to_device && dxfer_len > 0u) {
|
||||
std::cerr << "SCSI Data: ";
|
||||
print_buffer(std::cerr, dxfer_p, dxfer_len);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if STENC_BIG_ENDIAN == 1
|
||||
unsigned char CEEM :2;
|
||||
unsigned char RDMC :2;
|
||||
unsigned char sdk :1;
|
||||
unsigned char ckod :1;
|
||||
unsigned char ckorp :1;
|
||||
unsigned char ckorl :1;
|
||||
#else
|
||||
unsigned char ckorl :1;
|
||||
unsigned char ckorp :1;
|
||||
unsigned char ckod :1;
|
||||
unsigned char sdk :1;
|
||||
unsigned char RDMC :2;
|
||||
unsigned char CEEM :2;
|
||||
#endif
|
||||
unsigned char encryptionMode;
|
||||
unsigned char decryptionMode;
|
||||
unsigned char algorithmIndex;
|
||||
unsigned char keyFormat;
|
||||
unsigned char res_bits_2 [8];
|
||||
unsigned char keyLength [2];
|
||||
unsigned char keyData [SSP_KEY_LENGTH];
|
||||
} SSP_PAGE_SDE;
|
||||
#if defined(OS_LINUX)
|
||||
unique_fd fd {open(device.c_str(), O_RDONLY | O_NDELAY)};
|
||||
if (!fd) {
|
||||
std::ostringstream oss;
|
||||
oss << "Cannot open device " << device;
|
||||
throw std::system_error {errno, std::generic_category(), oss.str()};
|
||||
}
|
||||
|
||||
unsigned char
|
||||
scsi_sense_command[6]={
|
||||
0x03,
|
||||
0,0,0,
|
||||
sizeof(SCSI_PAGE_SENSE),
|
||||
0
|
||||
},
|
||||
scsi_inq_command[6] = {
|
||||
0x12,
|
||||
0,0,0,
|
||||
sizeof(SCSI_PAGE_INQ),
|
||||
0
|
||||
},
|
||||
spin_des_command [SSP_SP_CMD_LEN] = {
|
||||
sg_io_hdr cmdio {};
|
||||
auto sense_buf {std::make_unique<scsi::sense_buffer>()};
|
||||
|
||||
cmdio.cmd_len = cmd_len;
|
||||
cmdio.dxfer_direction = (direction == scsi_direction::to_device)
|
||||
? SG_DXFER_TO_DEV
|
||||
: SG_DXFER_FROM_DEV;
|
||||
cmdio.dxfer_len = dxfer_len;
|
||||
cmdio.dxferp = dxfer_p;
|
||||
cmdio.cmdp = const_cast<unsigned char *>(cmd_p);
|
||||
cmdio.sbp = sense_buf->data();
|
||||
cmdio.mx_sb_len = sizeof(decltype(sense_buf)::element_type);
|
||||
cmdio.timeout = SCSI_TIMEOUT;
|
||||
cmdio.interface_id = 'S';
|
||||
|
||||
if (ioctl(fd.get(), SG_IO, &cmdio)) {
|
||||
throw std::system_error {errno, std::generic_category()};
|
||||
}
|
||||
if (cmdio.status) {
|
||||
throw scsi::scsi_error {std::move(sense_buf)};
|
||||
}
|
||||
#elif defined(OS_FREEBSD)
|
||||
auto dev = std::unique_ptr<struct cam_device, decltype(&cam_close_device)> {
|
||||
cam_open_device(device.c_str(), O_RDWR), &cam_close_device};
|
||||
if (dev == nullptr) {
|
||||
std::ostringstream oss;
|
||||
oss << "Cannot open device " << device << ": " << cam_errbuf;
|
||||
throw std::runtime_error {oss.str()};
|
||||
}
|
||||
auto ccb = std::unique_ptr<union ccb, decltype(&cam_freeccb)> {
|
||||
cam_getccb(dev.get()), &cam_freeccb};
|
||||
if (ccb == nullptr) {
|
||||
throw std::bad_alloc {};
|
||||
}
|
||||
CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->csio);
|
||||
|
||||
cam_fill_csio(
|
||||
&ccb->csio, RETRYCOUNT, nullptr,
|
||||
CAM_PASS_ERR_RECOVER | CAM_CDB_POINTER |
|
||||
(direction == scsi_direction::to_device ? CAM_DIR_OUT : CAM_DIR_IN),
|
||||
MSG_SIMPLE_Q_TAG, dxfer_p, dxfer_len, SSD_FULL_SIZE, cmd_len,
|
||||
SCSI_TIMEOUT);
|
||||
ccb->csio.cdb_io.cdb_ptr = const_cast<u_int8_t *>(cmd_p);
|
||||
if (cam_send_ccb(dev.get(), ccb.get())) {
|
||||
throw std::system_error {errno, std::generic_category()};
|
||||
}
|
||||
if (ccb->csio.scsi_status) {
|
||||
auto sense_buf {std::make_unique<scsi::sense_buffer>()};
|
||||
std::memcpy(sense_buf->data(), &ccb->csio.sense_data,
|
||||
sizeof(scsi::sense_buffer));
|
||||
throw scsi::scsi_error {std::move(sense_buf)};
|
||||
}
|
||||
#else
|
||||
#error "OS type is not set"
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace scsi {
|
||||
|
||||
bool is_device_ready(const std::string& device)
|
||||
{
|
||||
const std::uint8_t test_unit_ready_cmd[6] {};
|
||||
|
||||
try {
|
||||
scsi_execute(device, test_unit_ready_cmd, sizeof(test_unit_ready_cmd),
|
||||
nullptr, 0u, scsi_direction::from_device);
|
||||
return true;
|
||||
} catch (const scsi::scsi_error& err) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const page_des& get_des(const std::string& device, std::uint8_t *buffer,
|
||||
std::size_t length)
|
||||
{
|
||||
const std::uint8_t spin_des_command[] {
|
||||
SSP_SPIN_OPCODE,
|
||||
SSP_SP_PROTOCOL_TDE,
|
||||
0,
|
||||
0X20,
|
||||
0,0,
|
||||
BSINTTOCHAR(sizeof(SSP_PAGE_BUFFER)),
|
||||
0,0
|
||||
},
|
||||
spin_nbes_command [SSP_SP_CMD_LEN] = {
|
||||
0,
|
||||
0,
|
||||
BSINTTOCHAR(length),
|
||||
0,
|
||||
0,
|
||||
};
|
||||
scsi_execute(device, spin_des_command, sizeof(spin_des_command), buffer,
|
||||
length, scsi_direction::from_device);
|
||||
auto& page {reinterpret_cast<const page_des&>(*buffer)};
|
||||
|
||||
#if defined(DEBUGSCSI)
|
||||
std::cerr << "SCSI Response: ";
|
||||
print_buffer(std::cerr, buffer,
|
||||
std::min(length, sizeof(page_header) + ntohs(page.length)));
|
||||
#endif
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
const page_nbes& get_nbes(const std::string& device, std::uint8_t *buffer,
|
||||
std::size_t length)
|
||||
{
|
||||
const std::uint8_t spin_nbes_command[] {
|
||||
SSP_SPIN_OPCODE,
|
||||
SSP_SP_PROTOCOL_TDE,
|
||||
0,
|
||||
0X21,
|
||||
0,0,
|
||||
BSINTTOCHAR(sizeof(SSP_PAGE_BUFFER)),
|
||||
0,0
|
||||
0,
|
||||
0,
|
||||
BSINTTOCHAR(length),
|
||||
0,
|
||||
0,
|
||||
};
|
||||
scsi_execute(device, spin_nbes_command, sizeof(spin_nbes_command), buffer,
|
||||
length, scsi_direction::from_device);
|
||||
auto& page {reinterpret_cast<const page_nbes&>(*buffer)};
|
||||
|
||||
//Gets encryption options on the tape drive
|
||||
SSP_DES* SSPGetDES(string tapeDevice){
|
||||
SSP_PAGE_BUFFER buffer;
|
||||
memset(&buffer,0,sizeof(SSP_PAGE_BUFFER));
|
||||
if(!SCSIExecute(tapeDevice,
|
||||
(unsigned char*)&spin_des_command,
|
||||
sizeof(spin_des_command),
|
||||
(unsigned char*)&buffer,
|
||||
sizeof(SSP_PAGE_BUFFER),
|
||||
false,true))
|
||||
#if defined(DEBUGSCSI)
|
||||
std::cerr << "SCSI Response: ";
|
||||
print_buffer(std::cerr, buffer,
|
||||
std::min(length, sizeof(page_header) + ntohs(page.length)));
|
||||
#endif
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
const page_dec& get_dec(const std::string& device, std::uint8_t *buffer,
|
||||
std::size_t length)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
SSP_DES* status=new SSP_DES(&buffer);
|
||||
return status;
|
||||
const std::uint8_t spin_dec_command[] {
|
||||
SSP_SPIN_OPCODE,
|
||||
SSP_SP_PROTOCOL_TDE,
|
||||
0x00,
|
||||
0x10,
|
||||
0,
|
||||
0,
|
||||
BSINTTOCHAR(length),
|
||||
0,
|
||||
0,
|
||||
};
|
||||
scsi_execute(device, spin_dec_command, sizeof(spin_dec_command), buffer,
|
||||
length, scsi_direction::from_device);
|
||||
auto& page {reinterpret_cast<const page_dec&>(*buffer)};
|
||||
|
||||
#if defined(DEBUGSCSI)
|
||||
std::cerr << "SCSI Response: ";
|
||||
print_buffer(std::cerr, buffer,
|
||||
std::min(length, sizeof(page_header) + ntohs(page.length)));
|
||||
#endif
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
//Gets encryption options on the tape drive
|
||||
SSP_NBES* SSPGetNBES(string tapeDevice,bool retry){
|
||||
|
||||
SSP_PAGE_BUFFER buffer;
|
||||
memset(&buffer,0,sizeof(SSP_PAGE_BUFFER));
|
||||
if(!SCSIExecute(tapeDevice,
|
||||
(unsigned char*)&spin_nbes_command,
|
||||
sizeof(spin_nbes_command),
|
||||
(unsigned char*)&buffer,
|
||||
sizeof(SSP_PAGE_BUFFER),
|
||||
false,false))
|
||||
inquiry_data get_inquiry(const std::string& device)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
SSP_NBES* status=new SSP_NBES(&buffer);
|
||||
if(status->nbes.encryptionStatus==0x01 && retry){
|
||||
//move to the start of the tape and try again
|
||||
int moves=0;
|
||||
while(true){
|
||||
if(status==NULL)break;
|
||||
if(status->nbes.encryptionStatus!=0x01)break;
|
||||
if(moves>=MAX_TAPE_READ_BLOCKS)break;
|
||||
delete status;
|
||||
status=NULL; //double free bug fix provided by Adam Nielsen
|
||||
if(!moveTape(tapeDevice,1,true))break;
|
||||
moves++;
|
||||
status=SSPGetNBES(tapeDevice,false);
|
||||
}
|
||||
moveTape(tapeDevice,moves,false);
|
||||
}
|
||||
return status;
|
||||
|
||||
const std::uint8_t scsi_inq_command[] {
|
||||
0x12, 0, 0, 0, sizeof(inquiry_data), 0,
|
||||
};
|
||||
inquiry_data inq {};
|
||||
scsi_execute(device, scsi_inq_command, sizeof(scsi_inq_command),
|
||||
reinterpret_cast<std::uint8_t *>(&inq), sizeof(inq),
|
||||
scsi_direction::from_device);
|
||||
|
||||
#if defined(DEBUGSCSI)
|
||||
std::cerr << "SCSI Response: ";
|
||||
print_buffer(std::cerr, reinterpret_cast<std::uint8_t *>(&inq),
|
||||
std::min(sizeof(inquiry_data),
|
||||
inquiry_data::header_size + inq.additional_length));
|
||||
#endif
|
||||
|
||||
return inq;
|
||||
}
|
||||
|
||||
//Sends and inquiry to the device
|
||||
SCSI_PAGE_INQ* SCSIGetInquiry(string tapeDevice){
|
||||
SCSI_PAGE_INQ* status=new SCSI_PAGE_INQ;
|
||||
memset(status,0,sizeof(SCSI_PAGE_INQ));
|
||||
if(!SCSIExecute(tapeDevice,
|
||||
(unsigned char*)&scsi_inq_command,
|
||||
sizeof(scsi_inq_command),
|
||||
(unsigned char*)status,
|
||||
sizeof(SCSI_PAGE_INQ),
|
||||
false,true))
|
||||
std::unique_ptr<const std::uint8_t[]>
|
||||
make_sde(encrypt_mode enc_mode, decrypt_mode dec_mode,
|
||||
std::uint8_t algorithm_index, const std::vector<std::uint8_t>& key,
|
||||
const std::string& key_name, kadf kad_format, sde_rdmc rdmc, bool ckod)
|
||||
{
|
||||
exit(EXIT_FAILURE);
|
||||
std::size_t length {sizeof(page_sde) + key.size()};
|
||||
if (!key_name.empty()) {
|
||||
length += sizeof(kad) + key_name.size();
|
||||
}
|
||||
return status;
|
||||
auto buffer {std::make_unique<std::uint8_t[]>(length)};
|
||||
auto& page {reinterpret_cast<page_sde&>(*buffer.get())};
|
||||
|
||||
page.page_code = htons(0x10);
|
||||
page.length = htons(length - sizeof(page_header));
|
||||
page.control = std::byte {2u}
|
||||
<< page_sde::control_scope_pos; // all IT nexus = 10b
|
||||
// no external encryption mode check for widest compatibility of reads
|
||||
page.flags |= std::byte {1u} << page_sde::flags_ceem_pos;
|
||||
page.flags |= std::byte {static_cast<std::underlying_type_t<sde_rdmc>>(rdmc)};
|
||||
if (ckod) {
|
||||
page.flags |= page_sde::flags_ckod_mask;
|
||||
}
|
||||
page.encryption_mode = enc_mode;
|
||||
page.decryption_mode = dec_mode;
|
||||
page.algorithm_index = algorithm_index;
|
||||
page.kad_format = kad_format;
|
||||
page.key_length = htons(key.size());
|
||||
std::memcpy(page.key, key.data(), key.size());
|
||||
|
||||
if (!key_name.empty()) {
|
||||
auto& ukad {reinterpret_cast<kad&>(
|
||||
*(buffer.get() + sizeof(page_sde) + key.size()))};
|
||||
ukad.length = htons(key_name.size());
|
||||
std::memcpy(ukad.descriptor, key_name.data(), key_name.size());
|
||||
}
|
||||
|
||||
|
||||
//Writes encryption options to the tape drive
|
||||
bool SCSIWriteEncryptOptions(string tapeDevice, SCSIEncryptOptions* eOptions){
|
||||
|
||||
char buffer[1024];
|
||||
memset(&buffer,0,1024);
|
||||
|
||||
SSP_PAGE_SDE options;
|
||||
//copy the template over the options
|
||||
memset(&options,0, sizeof(SSP_PAGE_SDE));
|
||||
byteswap((unsigned char*)&options.pageCode,2,0x10);
|
||||
int pagelen=sizeof(SSP_PAGE_SDE);
|
||||
options.scope=2; //all IT nexus = 10b
|
||||
options.RDMC=eOptions->rdmc;
|
||||
options.ckod=(eOptions->CKOD)?1:0;
|
||||
options.CEEM=DEFAULT_CEEM;
|
||||
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;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
if(eOptions->cryptoKey!=""){
|
||||
//byte swap the keylength
|
||||
byteswap((unsigned char*)&options.keyLength,2,eOptions->cryptoKey.size());
|
||||
//copy the crypto key into the options
|
||||
eOptions->cryptoKey.copy((char*)&options.keyData, eOptions->cryptoKey.size(),0);
|
||||
}
|
||||
//create the key descriptor
|
||||
if(eOptions->keyName!=""){
|
||||
SSP_KAD kad;
|
||||
memset(&kad,0,sizeof(kad));
|
||||
kad.type=0x00;
|
||||
kad.authenticated=0;
|
||||
//set the descriptor length to the length of the keyName
|
||||
byteswap((unsigned char*)&kad.descriptorLength,2,eOptions->keyName.size());
|
||||
|
||||
//get the size of the kad object
|
||||
int kadlen=eOptions->keyName.size()+SSP_KAD_HEAD_LENGTH;
|
||||
//increment the SPOUT page len
|
||||
pagelen+=kadlen;
|
||||
//increase the page size
|
||||
eOptions->keyName.copy((char*)&kad.descriptor,eOptions->keyName.size(),0);
|
||||
//copy the kad after the SDE command
|
||||
memcpy(&buffer[sizeof(SSP_PAGE_SDE)],&kad,kadlen);
|
||||
}
|
||||
//update the pagelen in options
|
||||
byteswap((unsigned char*)&options.length,2,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));
|
||||
|
||||
unsigned char spout_sde_command [SSP_SP_CMD_LEN] = {
|
||||
void write_sde(const std::string& device, const std::uint8_t *sde_buffer)
|
||||
{
|
||||
auto& page {reinterpret_cast<const page_sde&>(*sde_buffer)};
|
||||
std::size_t length {sizeof(page_header) + ntohs(page.length)};
|
||||
const std::uint8_t spout_sde_command[] {
|
||||
SSP_SPOUT_OPCODE,
|
||||
SSP_SP_PROTOCOL_TDE,
|
||||
0,
|
||||
0X10,
|
||||
0,0,
|
||||
BSINTTOCHAR(pagelen),
|
||||
0,0
|
||||
0,
|
||||
0,
|
||||
BSINTTOCHAR(length),
|
||||
0,
|
||||
0,
|
||||
};
|
||||
|
||||
|
||||
//return whether or not the command executed
|
||||
return SCSIExecute(
|
||||
tapeDevice,
|
||||
(unsigned char*)&spout_sde_command,
|
||||
sizeof(spout_sde_command),
|
||||
(unsigned char*)&buffer,
|
||||
pagelen,
|
||||
true,true
|
||||
);
|
||||
scsi_execute(device, spout_sde_command, sizeof(spout_sde_command),
|
||||
const_cast<std::uint8_t *>(sde_buffer), length,
|
||||
scsi_direction::to_device);
|
||||
}
|
||||
|
||||
bool SCSIExecute(string tapedrive, unsigned char* cmd_p,int cmd_len,unsigned char* dxfer_p,int dxfer_len, bool cmd_to_device, bool show_error)
|
||||
void print_sense_data(std::ostream& os, const sense_data& sd)
|
||||
{
|
||||
const char* tapedevice=tapedrive.c_str();
|
||||
int sg_fd,eresult,sresult,ioerr,retries;
|
||||
SCSI_PAGE_SENSE* sd=new SCSI_PAGE_SENSE;
|
||||
memset(sd,0,sizeof(SCSI_PAGE_SENSE));
|
||||
os << std::left << std::setw(25) << "Sense Code: ";
|
||||
|
||||
#if defined(OS_LINUX) || defined(OS_FREEBSD) // Linux or FreeBSD System
|
||||
errno=0;
|
||||
sg_fd = open(tapedevice, O_RDONLY);
|
||||
if( sg_fd==-1){
|
||||
cerr<<"Could not open device '"<<tapedevice<<"': ";
|
||||
readIOError(errno);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
auto sense_key {sd.flags & sense_data::flags_sense_key_mask};
|
||||
|
||||
|
||||
sg_io_hdr cmdio;
|
||||
memset(&cmdio,0,sizeof(sg_io_hdr));
|
||||
cmdio.cmd_len = cmd_len;
|
||||
cmdio.dxfer_direction =(cmd_to_device)?SG_DXFER_TO_DEV:SG_DXFER_FROM_DEV;
|
||||
cmdio.dxfer_len = dxfer_len;
|
||||
cmdio.dxferp = dxfer_p;
|
||||
cmdio.cmdp = cmd_p;
|
||||
cmdio.sbp = (unsigned char*)sd;
|
||||
cmdio.mx_sb_len=sizeof(SCSI_PAGE_SENSE);
|
||||
cmdio.timeout = SCSI_TIMEOUT;
|
||||
cmdio.interface_id = 'S';
|
||||
retries=0;
|
||||
do{
|
||||
errno=0;
|
||||
eresult=ioctl(sg_fd, SG_IO, &cmdio);
|
||||
if(eresult!=0)
|
||||
ioerr=errno;
|
||||
retries++;
|
||||
}while(errno!=0 && retries<=RETRYCOUNT);
|
||||
|
||||
|
||||
sresult=cmdio.status;
|
||||
#elif defined(OS_AIX) // AIX System
|
||||
|
||||
errno=0;
|
||||
sg_fd = openx((char*)tapedevice, O_RDONLY , NULL, SC_DIAGNOSTIC);
|
||||
if(!sg_fd || sg_fd==-1){
|
||||
cerr<<"Could not open device '"<<tapedevice<<"'"<<endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
struct sc_iocmd cmdio;
|
||||
memset(&cmdio,0,sizeof (struct sc_iocmd));
|
||||
//copy the command bytes into the first part of the structure
|
||||
memcpy(&cmdio.scsi_cdb,cmd_p,cmd_len);
|
||||
cmdio.buffer=(char*)dxfer_p;
|
||||
cmdio.timeout_value=SCSI_TIMEOUT;
|
||||
cmdio.command_length=cmd_len;
|
||||
cmdio.data_length=dxfer_len;
|
||||
cmdio.status_validity=SC_SCSI_ERROR;
|
||||
cmdio.flags=(cmd_to_device)?B_WRITE:B_READ;
|
||||
|
||||
retries=0;
|
||||
do{
|
||||
errno=0;
|
||||
eresult=ioctl(sg_fd, STIOCMD, &cmdio);
|
||||
sresult=(int)cmdio.scsi_bus_status;
|
||||
if(eresult!=0)
|
||||
ioerr=errno;
|
||||
retries++;
|
||||
}while(errno!=0 && retries<=RETRYCOUNT);
|
||||
|
||||
|
||||
if(sresult==SC_CHECK_CONDITION){ //get the sense data
|
||||
|
||||
struct sc_iocmd scmdio;
|
||||
memset(&scmdio,0,sizeof (struct sc_iocmd));
|
||||
//copy the command bytes into the first part of the structure
|
||||
memcpy(&scmdio.scsi_cdb,&scsi_sense_command,sizeof(scsi_sense_command));
|
||||
scmdio.buffer=(char*)sd;
|
||||
scmdio.timeout_value=SCSI_TIMEOUT;
|
||||
scmdio.command_length=sizeof(scsi_sense_command);
|
||||
scmdio.data_length=sizeof(SCSI_PAGE_SENSE);
|
||||
scmdio.status_validity=SC_SCSI_ERROR;
|
||||
scmdio.flags=B_READ;
|
||||
|
||||
errno=0;
|
||||
ioctl(sg_fd, STIOCMD, &scmdio);
|
||||
|
||||
}
|
||||
#else
|
||||
#error "OS type is not set"
|
||||
#endif
|
||||
#ifdef DEBUGSCSI
|
||||
cout<<"SCSI Command: ";
|
||||
for(int i=0;i<cmd_len;i++){
|
||||
cout<<HEX(cmd_p[i]);
|
||||
}
|
||||
cout<<endl;
|
||||
|
||||
|
||||
cout<<"SCSI Data: ";
|
||||
for(int i=0;i<dxfer_len;i++){
|
||||
cout<<HEX(dxfer_p[i]);
|
||||
}
|
||||
cout<<endl;
|
||||
#endif
|
||||
close(sg_fd);
|
||||
|
||||
|
||||
bool retval=true;
|
||||
|
||||
if(eresult!=0){
|
||||
if(show_error)
|
||||
readIOError(ioerr);
|
||||
retval=false;
|
||||
|
||||
}
|
||||
|
||||
if(sresult!=0){
|
||||
if(show_error)
|
||||
outputSense(sd);
|
||||
retval=false;
|
||||
}
|
||||
delete sd;
|
||||
return retval;
|
||||
}
|
||||
void byteswap(unsigned char* array,int size,int value){
|
||||
switch(size){
|
||||
case 2:
|
||||
array[0]=(unsigned char)((value & 0xff00)>>8);
|
||||
array[1]=(unsigned char)(value & 0x00ff);
|
||||
switch (sense_key) {
|
||||
case sense_data::no_sense:
|
||||
os << "No specific error";
|
||||
break;
|
||||
case 4:
|
||||
array[0]=(unsigned char)((value & 0xff000000)>>24);
|
||||
array[1]=(unsigned char)((value & 0x00ff0000)>>16);
|
||||
array[2]=(unsigned char)((value & 0x0000ff00)>>8);
|
||||
array[3]=(unsigned char)(value & 0x000000ff);
|
||||
|
||||
case sense_data::recovered_error:
|
||||
os << "Recovered error";
|
||||
break;
|
||||
default:
|
||||
cout<<"Unhandled byte swap length of "<<size<<endl;
|
||||
case sense_data::not_ready:
|
||||
os << "Device not ready";
|
||||
break;
|
||||
case sense_data::medium_error:
|
||||
os << "Medium Error";
|
||||
break;
|
||||
case sense_data::hardware_error:
|
||||
os << "Hardware Error";
|
||||
break;
|
||||
case sense_data::illegal_request:
|
||||
os << "Illegal Request";
|
||||
break;
|
||||
case sense_data::unit_attention:
|
||||
os << "Unit Attention";
|
||||
break;
|
||||
case sense_data::data_protect:
|
||||
os << "Data protect";
|
||||
break;
|
||||
case sense_data::blank_check:
|
||||
os << "Blank tape";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
os << " (0x" << hex {static_cast<std::uint8_t>(sense_key)} << ")\n";
|
||||
|
||||
SCSIEncryptOptions::SCSIEncryptOptions(){
|
||||
cryptMode=CRYPTMODE_OFF;
|
||||
algorithmIndex=DEFAULT_ALGORITHM;
|
||||
cryptoKey="";
|
||||
CKOD=false;
|
||||
keyName="";
|
||||
rdmc=RDMC_DEFAULT;
|
||||
}
|
||||
os << std::left << std::setw(25) << " ASC:"
|
||||
<< "0x" << hex {sd.additional_sense_code} << '\n';
|
||||
|
||||
SSP_NBES::SSP_NBES(SSP_PAGE_BUFFER* buffer){
|
||||
memset(&nbes,0,sizeof(SSP_PAGE_NBES));
|
||||
memcpy(&nbes,buffer,sizeof(SSP_PAGE_NBES));
|
||||
loadKADs(buffer,sizeof(SSP_PAGE_NBES));
|
||||
os << std::left << std::setw(25) << " ASCQ:"
|
||||
<< "0x" << hex {sd.additional_sense_qualifier} << '\n';
|
||||
|
||||
}
|
||||
SSP_DES::SSP_DES(SSP_PAGE_BUFFER* buffer){
|
||||
memset(&des,0,sizeof(SSP_PAGE_DES));
|
||||
memcpy(&des,buffer,sizeof(SSP_PAGE_DES));
|
||||
loadKADs(buffer,sizeof(SSP_PAGE_DES));
|
||||
}
|
||||
#if defined(DEBUGSCSI)
|
||||
auto sense_data_length {
|
||||
std::min(sense_data::maximum_size,
|
||||
sd.additional_sense_length + sense_data::header_size)};
|
||||
auto rawsense {reinterpret_cast<const std::uint8_t *>(&sd)};
|
||||
|
||||
void KAD_CLASS::loadKADs(SSP_PAGE_BUFFER* buffer, int start){
|
||||
char* rawbuff=(char*)buffer;
|
||||
int length=BSSHORT(buffer->length)+4;
|
||||
int pos=start;
|
||||
while(pos<length){
|
||||
SSP_KAD kad;
|
||||
memset(&kad,0,sizeof(SSP_KAD));
|
||||
memcpy(&kad,rawbuff+pos,SSP_KAD_HEAD_LENGTH);
|
||||
pos+=SSP_KAD_HEAD_LENGTH;
|
||||
if(pos>=length)break;
|
||||
unsigned short kadDesLen=BSSHORT(kad.descriptorLength);
|
||||
if(kadDesLen>0){
|
||||
memcpy(&kad.descriptor,rawbuff+pos,kadDesLen);
|
||||
pos+=kadDesLen;
|
||||
}else pos++;
|
||||
kads.push_back(kad);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
bool moveTape(std::string tapeDevice,int count,bool dirForward){
|
||||
struct mtop mt_command;
|
||||
int sg_fd = open(tapeDevice.c_str(), O_RDONLY);
|
||||
if(!sg_fd || sg_fd==-1){
|
||||
return false;
|
||||
}
|
||||
errno=0;
|
||||
bool retval=true;
|
||||
#if defined(OS_LINUX) || defined(OS_FREEBSD) // Linux or FreeBSD System
|
||||
|
||||
mt_command.mt_op = (dirForward)?MTFSR:MTBSR;
|
||||
mt_command.mt_count = count;
|
||||
ioctl(sg_fd, MTIOCTOP, &mt_command);
|
||||
#elif defined(OS_AIX)
|
||||
mt_command.st_op = (dirForward)?MTFSR:MTBSR;
|
||||
mt_command.st_count = count;
|
||||
ioctl(sg_fd, STIOCTOP, &mt_command);
|
||||
#else
|
||||
#error "OS type is not set"
|
||||
#endif
|
||||
if(errno!=0)retval=false;
|
||||
|
||||
close(sg_fd);
|
||||
errno=0;
|
||||
return retval;
|
||||
}
|
||||
|
||||
void readIOError(int err){
|
||||
if(err==0)return;
|
||||
cerr<<"ERROR: ";
|
||||
switch(err){
|
||||
case EAGAIN:
|
||||
cerr<<"Device already open"<<endl;
|
||||
break;
|
||||
case EBUSY:
|
||||
cerr<<"Device Busy"<<endl;
|
||||
break;
|
||||
case ETIMEDOUT:
|
||||
cerr<<"Device operation timed out"<<endl;
|
||||
break;
|
||||
case EIO:
|
||||
cerr<<"Device I/O Error."<<endl;
|
||||
break;
|
||||
case EPERM:
|
||||
cerr<<"You do not have privileges to do this. Are you root?"<<endl;
|
||||
break;
|
||||
#ifdef OS_AIX
|
||||
case EBADF:
|
||||
cerr<<"EBADF"<<endl;
|
||||
break;
|
||||
case EFAULT:
|
||||
cerr<<"EFAULT"<<endl;
|
||||
break;
|
||||
case EINTR:
|
||||
cerr<<"EINTR"<<endl;
|
||||
break;
|
||||
case EINVAL:
|
||||
cerr<<"Invalid device"<<endl;
|
||||
break;
|
||||
|
||||
case ENOTTY:
|
||||
cerr<<"ENOTTY"<<endl;
|
||||
break;
|
||||
|
||||
case ENODEV:
|
||||
cerr<<"Device is not responding"<<endl;
|
||||
break;
|
||||
|
||||
case ENXIO:
|
||||
cerr<<"ENXIO"<<endl;
|
||||
break;
|
||||
|
||||
#endif
|
||||
default:
|
||||
if(errno!=0){
|
||||
cerr<<"0x"<<hex<<errno<<" "<<strerror(errno)<<endl;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
void outputSense(SCSI_PAGE_SENSE* sd){
|
||||
cerr<<left<<setw(25)<<"Sense Code: ";
|
||||
|
||||
switch((int)sd->senseKey){
|
||||
case 0:
|
||||
cerr<<"No specific error";
|
||||
break;
|
||||
case 2:
|
||||
cerr<<"Device not ready";
|
||||
break;
|
||||
case 3:
|
||||
cerr<<"Medium Error";
|
||||
break;
|
||||
case 4:
|
||||
cerr<<"Hardware Error";
|
||||
break;
|
||||
case 5:
|
||||
cerr<<"Illegal Request";
|
||||
break;
|
||||
case 6:
|
||||
cerr<<"Unit Attention";
|
||||
break;
|
||||
case 7:
|
||||
cerr<<"Data protect";
|
||||
break;
|
||||
case 8:
|
||||
cerr<<"Blank tape";
|
||||
break;
|
||||
|
||||
}
|
||||
cerr<<" (0x"<<HEX(sd->senseKey)<<")"<<endl;
|
||||
cerr<<left<<setw(25)<<" ASC:"<<"0x"<<HEX(sd->addSenseCode)<<endl;
|
||||
cerr<<left<<setw(25)<<" ASCQ:"<<"0x"<<HEX(sd->addSenseCodeQual)<<endl;
|
||||
if(sd->addSenseLen>0){
|
||||
cerr<<left<<setw(25)<<" Additional data:"<<"0x";
|
||||
|
||||
for(int i=0;i<sd->addSenseLen;i++){
|
||||
cerr<<HEX(sd->addSenseData[i]);
|
||||
}
|
||||
cerr<<endl;
|
||||
}
|
||||
#ifdef DEBUGSCSI
|
||||
cerr<<left<<setw(25)<<" Raw Sense:"<<"0x";
|
||||
char* rawsense=(char*)sd;
|
||||
|
||||
for(int i=0;i<sizeof(SCSI_PAGE_SENSE);i++){
|
||||
cerr<<HEX(rawsense[i]);
|
||||
}
|
||||
cerr<<endl;
|
||||
os << std::left << std::setw(25) << " Raw sense data:";
|
||||
print_buffer(os, rawsense, sense_data_length);
|
||||
#endif
|
||||
}
|
||||
|
||||
std::vector<std::reference_wrapper<const algorithm_descriptor>>
|
||||
read_algorithms(const page_dec& page)
|
||||
{
|
||||
auto it {reinterpret_cast<const std::uint8_t *>(&page.ads[0])};
|
||||
const auto end {reinterpret_cast<const std::uint8_t *>(&page) +
|
||||
ntohs(page.length) + sizeof(page_header)};
|
||||
std::vector<std::reference_wrapper<const algorithm_descriptor>> v {};
|
||||
|
||||
while (it < end) {
|
||||
auto elem {reinterpret_cast<const algorithm_descriptor *>(it)};
|
||||
v.push_back(std::cref(*elem));
|
||||
it += ntohs(elem->length) + algorithm_descriptor::header_size;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
} // namespace scsi
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
// SPDX-FileCopyrightText: 2022 stenc authors
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
/*
|
||||
Header file to send and recieve SPIN/SPOUT commands to SCSI device
|
||||
|
||||
@@ -15,350 +19,424 @@ GNU General Public License for more details.
|
||||
|
||||
#ifndef _SCSIENC_H
|
||||
#define _SCSIENC_H
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <bitset>
|
||||
#include <vector>
|
||||
#define SSP_KEY_LENGTH 0X20
|
||||
#define SSP_DESCRIPTOR_LENGTH 1024
|
||||
#define SSP_PAGE_DES_LENGTH 24
|
||||
#define SSP_PAGE_NBES_LENGTH 16
|
||||
#define SSP_KAD_HEAD_LENGTH 4
|
||||
#define SSP_PAGE_ALLOCATION 8192
|
||||
#define SSP_UKAD_LENGTH 0x1e
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
|
||||
#define KAD_TYPE_UKAD 0x00
|
||||
#define KAD_TYPE_AKAD 0x01
|
||||
#define KAD_TYPE_NONCE 0x02
|
||||
#define KAD_TYPE_META 0x03
|
||||
|
||||
#define RDMC_PROTECT 0x03
|
||||
#define RDMC_UNPROTECT 0x02
|
||||
#define RDMC_DEFAULT 0x00
|
||||
|
||||
//outputs hex in a 2 digit pair
|
||||
#define HEX( x ) right<<setw(2)<< setfill('0') << hex << (int)( x )<<setfill(' ')
|
||||
//macro for a byte swapped short
|
||||
#define BSSHORT( x ) ((unsigned short)( (x[0]<<8) + x[1] ))
|
||||
//macro for a byte swapped int
|
||||
#define BSLONG( x ) ((unsigned int)( (int)( x[0] << 24 ) + (int)( x[1] << 16 ) + (int)( x[2] << 8 ) + (int)( x[3] ) ))
|
||||
|
||||
#ifdef HAVE_SYS_MACHINE_H
|
||||
#include <sys/machine.h>
|
||||
#if HAVE_ARPA_INET_H
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
#if HAVE_NETINET_IN_H
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
namespace scsi {
|
||||
|
||||
#ifdef BYTE_ORDER
|
||||
#define STENC_BYTE_ORDER BYTE_ORDER
|
||||
#endif
|
||||
#ifndef STENC_BYTE_ORDER
|
||||
#ifdef __BYTE_ORDER
|
||||
#define STENC_BYTE_ORDER __BYTE_ORDER
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef BIG_ENDIAN
|
||||
#define STENC_TYPE_BIG_ENDIAN BIG_ENDIAN
|
||||
#endif
|
||||
#ifndef STENC_TYPE_BIG_ENDIAN
|
||||
#ifdef __BIG_ENDIAN
|
||||
#define STENC_TYPE_BIG_ENDIAN __BIG_ENDIAN
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if STENC_BYTE_ORDER == STENC_TYPE_BIG_ENDIAN
|
||||
#define STENC_BIG_ENDIAN 1
|
||||
#else
|
||||
#define STENC_BIG_ENDIAN 0
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
typedef struct {
|
||||
unsigned char pageCode [2];
|
||||
unsigned char length [2];
|
||||
|
||||
#if STENC_BIG_ENDIAN == 1
|
||||
unsigned char nexusScope :3;
|
||||
unsigned char res_bits_1 :2;
|
||||
unsigned char keyScope :3;
|
||||
#else
|
||||
unsigned char keyScope :3;
|
||||
unsigned char res_bits_1 :2;
|
||||
unsigned char nexusScope :3;
|
||||
#endif
|
||||
unsigned char encryptionMode;
|
||||
unsigned char decryptionMode;
|
||||
unsigned char algorithmIndex;
|
||||
unsigned char keyInstance [4];
|
||||
#if STENC_BIG_ENDIAN == 1
|
||||
unsigned char res_bits_2 :1;
|
||||
unsigned char parametersControl :3;
|
||||
unsigned char VCELB :1;
|
||||
unsigned char CEEMS :2;
|
||||
unsigned char RDMD :1;
|
||||
#else
|
||||
|
||||
unsigned char RDMD :1;
|
||||
unsigned char CEEMS :2;
|
||||
unsigned char VCELB :1;
|
||||
unsigned char parametersControl :3;
|
||||
unsigned char res_bits_2 :1;
|
||||
#endif
|
||||
unsigned char res_bits_3;
|
||||
unsigned char ASDKCount [2];
|
||||
unsigned char res_bits_4 [8];
|
||||
|
||||
} SSP_PAGE_DES; //device encryption status page
|
||||
|
||||
typedef struct {
|
||||
unsigned char type;
|
||||
#if STENC_BIG_ENDIAN == 1
|
||||
unsigned char res_bits_1 :5;
|
||||
unsigned char authenticated :3;
|
||||
#else
|
||||
unsigned char authenticated :3;
|
||||
unsigned char res_bits_1 :5;
|
||||
#endif
|
||||
unsigned char descriptorLength [2];
|
||||
unsigned char descriptor [SSP_DESCRIPTOR_LENGTH]; //will actually be the size of descriptorLength
|
||||
} SSP_KAD;
|
||||
|
||||
typedef struct{
|
||||
unsigned char pageCode [2];
|
||||
unsigned char length [2];
|
||||
unsigned char buffer [SSP_PAGE_ALLOCATION];
|
||||
} SSP_PAGE_BUFFER; //generic ssp page buffer
|
||||
|
||||
|
||||
typedef struct {
|
||||
unsigned char pageCode [2];
|
||||
unsigned char length [2];
|
||||
unsigned char log_obj_num [8];
|
||||
#if STENC_BIG_ENDIAN == 1
|
||||
unsigned char compressionStatus :4;
|
||||
unsigned char encryptionStatus :4;
|
||||
#else
|
||||
unsigned char encryptionStatus :4;
|
||||
unsigned char compressionStatus :4;
|
||||
#endif
|
||||
|
||||
unsigned char algorithmIndex;
|
||||
#if STENC_BIG_ENDIAN == 1
|
||||
unsigned char res_bits_1 :6;
|
||||
unsigned char EMES :1;
|
||||
unsigned char RDMDS :1;
|
||||
#else
|
||||
unsigned char RDMDS :1;
|
||||
unsigned char EMES :1;
|
||||
unsigned char res_bits_1 :6;
|
||||
#endif
|
||||
|
||||
unsigned char res_bits_2;
|
||||
} SSP_PAGE_NBES; //next block encryption status page
|
||||
|
||||
|
||||
typedef struct{
|
||||
|
||||
#if STENC_BIG_ENDIAN == 0
|
||||
unsigned char peripheralQualifier :3;
|
||||
unsigned char periphrealDeviceType :5;
|
||||
#else
|
||||
unsigned char periphrealDeviceType :5;
|
||||
unsigned char peripheralQualifier :3;
|
||||
#endif
|
||||
|
||||
#if STENC_BIG_ENDIAN == 0
|
||||
unsigned char RMB :1;
|
||||
unsigned char res_bits_1 :7;
|
||||
#else
|
||||
unsigned char res_bits_1 :7;
|
||||
unsigned char RMB :1;
|
||||
#endif
|
||||
unsigned char Version [1];
|
||||
|
||||
#if STENC_BIG_ENDIAN == 0
|
||||
unsigned char obs_bits_1 :2;
|
||||
unsigned char NORMACA :1;
|
||||
unsigned char HISUP :1;
|
||||
unsigned char responseDataFormat :4;
|
||||
#else
|
||||
unsigned char responseDataFormat :4;
|
||||
unsigned char HISUP :1;
|
||||
unsigned char NORMACA :1;
|
||||
unsigned char obs_bits_1 :2;
|
||||
#endif
|
||||
|
||||
unsigned char additionalLength [1];
|
||||
|
||||
#if STENC_BIG_ENDIAN == 0
|
||||
unsigned char SCCS :1;
|
||||
unsigned char ACC :1;
|
||||
unsigned char TPGS :2;
|
||||
unsigned char threePC :1;
|
||||
unsigned char res_bits_2 :2;
|
||||
unsigned char protect :1;
|
||||
#else
|
||||
unsigned char protect :1;
|
||||
unsigned char res_bits_2 :2;
|
||||
unsigned char threePC :1;
|
||||
unsigned char TPGS :2;
|
||||
unsigned char ACC :1;
|
||||
unsigned char SCCS :1;
|
||||
#endif
|
||||
|
||||
|
||||
#if STENC_BIG_ENDIAN == 0
|
||||
unsigned char obs_bits_2 :1;
|
||||
unsigned char ENCSERV :1;
|
||||
unsigned char VS :1;
|
||||
unsigned char MULTIP :1;
|
||||
unsigned char MCHNGR :1;
|
||||
unsigned char obs_bits_3 :2;
|
||||
unsigned char ADDR16 :1;
|
||||
#else
|
||||
unsigned char ADDR16 :1;
|
||||
unsigned char obs_bits_3 :2;
|
||||
unsigned char MCHNGR :1;
|
||||
unsigned char MULTIP :1;
|
||||
unsigned char VS :1;
|
||||
unsigned char ENCSERV :1;
|
||||
unsigned char obs_bits_2 :1;
|
||||
#endif
|
||||
|
||||
|
||||
#if STENC_BIG_ENDIAN == 0
|
||||
unsigned char obs_bits_4 :2;
|
||||
unsigned char WBUS16 :1;
|
||||
unsigned char SYNC :1;
|
||||
unsigned char obs_bits_5 :2;
|
||||
unsigned char CMDQUE :1;
|
||||
unsigned char VS2 :1;
|
||||
#else
|
||||
unsigned char VS2 :1;
|
||||
unsigned char CMDQUE :1;
|
||||
unsigned char obs_bits_5 :2;
|
||||
unsigned char SYNC :1;
|
||||
unsigned char WBUS16 :1;
|
||||
unsigned char obs_bits_4 :2;
|
||||
#endif
|
||||
|
||||
unsigned char vender [8];
|
||||
unsigned char productID [16];
|
||||
unsigned char productRev [4];
|
||||
unsigned char SN [7];
|
||||
unsigned char venderUnique [12];
|
||||
|
||||
#if STENC_BIG_ENDIAN == 0
|
||||
unsigned char res_bits_3 :4;
|
||||
unsigned char CLOCKING :2;
|
||||
unsigned char QAS :1;
|
||||
unsigned char IUS :1;
|
||||
#else
|
||||
unsigned char IUS :1;
|
||||
unsigned char QAS :1;
|
||||
unsigned char CLOCKING :2;
|
||||
unsigned char res_bits_3 :4;
|
||||
#endif
|
||||
|
||||
unsigned char res_bits_4 [1];
|
||||
unsigned char versionDescriptor [16];
|
||||
unsigned char res_bits_5 [22];
|
||||
unsigned char copyright [1];
|
||||
} SCSI_PAGE_INQ; //device inquiry response
|
||||
typedef struct{
|
||||
#if STENC_BIG_ENDIAN == 1
|
||||
unsigned char valid :1;
|
||||
unsigned char responseCode :7;
|
||||
#else
|
||||
unsigned char responseCode :7;
|
||||
unsigned char valid :1;
|
||||
#endif
|
||||
unsigned char res_bits_1;
|
||||
|
||||
#if STENC_BIG_ENDIAN == 1
|
||||
unsigned char filemark :1;
|
||||
unsigned char EOM :1;
|
||||
unsigned char ILI :1;
|
||||
unsigned char res_bits_2 :1;
|
||||
unsigned char senseKey :4;
|
||||
#else
|
||||
unsigned char senseKey :4;
|
||||
unsigned char res_bits_2 :1;
|
||||
unsigned char ILI :1;
|
||||
unsigned char EOM :1;
|
||||
unsigned char filemark :1;
|
||||
#endif
|
||||
unsigned char information [4];
|
||||
unsigned char addSenseLen;
|
||||
unsigned char cmdSpecificInfo [4];
|
||||
unsigned char addSenseCode;
|
||||
unsigned char addSenseCodeQual;
|
||||
unsigned char fieldRepUnitCode;
|
||||
#if STENC_BIG_ENDIAN == 1
|
||||
unsigned char sim :3; // system information message
|
||||
unsigned char bpv :1; // bit pointer valid
|
||||
unsigned char resvd2 :2; // reserved
|
||||
unsigned char cd :1; // control/data
|
||||
unsigned char SKSV :1;
|
||||
|
||||
#else
|
||||
unsigned char SKSV :1;
|
||||
unsigned char cd :1; // control/data
|
||||
unsigned char resvd2 :2; // reserved
|
||||
unsigned char bpv :1; // bit pointer valid
|
||||
unsigned char sim :3; // system information message
|
||||
#endif
|
||||
unsigned char field [2]; // field pointer
|
||||
unsigned char addSenseData [109];
|
||||
} SCSI_PAGE_SENSE; //sense data response
|
||||
class KAD_CLASS{
|
||||
public:
|
||||
std::vector<SSP_KAD> kads;
|
||||
protected:
|
||||
void loadKADs(SSP_PAGE_BUFFER* buffer, int start);
|
||||
enum class encrypt_mode : std::uint8_t {
|
||||
off = 0u,
|
||||
external = 1u,
|
||||
on = 2u,
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, encrypt_mode m)
|
||||
{
|
||||
if (m == encrypt_mode::off) {
|
||||
os << "off";
|
||||
} else if (m == encrypt_mode::external) {
|
||||
os << "external";
|
||||
} else {
|
||||
os << "on";
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
//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);
|
||||
};
|
||||
//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);
|
||||
enum class decrypt_mode : std::uint8_t {
|
||||
off = 0u,
|
||||
raw = 1u,
|
||||
on = 2u,
|
||||
mixed = 3u,
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, decrypt_mode m)
|
||||
{
|
||||
if (m == decrypt_mode::off) {
|
||||
os << "off";
|
||||
} else if (m == decrypt_mode::raw) {
|
||||
os << "raw";
|
||||
} else if (m == decrypt_mode::on) {
|
||||
os << "on";
|
||||
} else {
|
||||
os << "mixed";
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
//enum for SCSIEncryptOptions.cryptMode
|
||||
enum { CRYPTMODE_OFF, CRYPTMODE_MIXED,CRYPTMODE_ON,CRYPTMODE_RAWREAD};
|
||||
|
||||
//used to pass parameters to SCSIWriteEncryptOptions
|
||||
class SCSIEncryptOptions {
|
||||
public:
|
||||
int rdmc;
|
||||
bool CKOD;
|
||||
int cryptMode;
|
||||
unsigned int algorithmIndex;
|
||||
std::string cryptoKey;
|
||||
std::string keyName;
|
||||
SCSIEncryptOptions();
|
||||
enum class kad_type : std::uint8_t {
|
||||
ukad = 0u, // unauthenticated key-associated data
|
||||
akad = 1u, // authenticated key-associated data
|
||||
nonce = 2u, // nonce value
|
||||
mkad = 3u, // metadata key-associated data
|
||||
wkkad = 4u, // wrapped key key-associated data
|
||||
};
|
||||
|
||||
//Gets encryption options on the tape drive
|
||||
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
|
||||
bool SCSIWriteEncryptOptions(std::string tapeDevice, SCSIEncryptOptions* eOptions);
|
||||
//Gets device inquiry
|
||||
SCSI_PAGE_INQ* SCSIGetInquiry(std::string tapeDevice);
|
||||
enum class kadf : std::uint8_t {
|
||||
unspecified = 0u,
|
||||
binary_key_name = 1u,
|
||||
ascii_key_name = 2u,
|
||||
};
|
||||
|
||||
// key-associated data
|
||||
struct __attribute__((packed)) kad {
|
||||
kad_type type;
|
||||
std::byte flags;
|
||||
static constexpr auto flags_authenticated_pos {0u};
|
||||
static constexpr std::byte flags_authenticated_mask {
|
||||
7u << flags_authenticated_pos};
|
||||
std::uint16_t length;
|
||||
std::uint8_t descriptor[];
|
||||
};
|
||||
static_assert(sizeof(kad) == 4u);
|
||||
|
||||
// common 4-byte header of all SP-IN and SP-OUT pages
|
||||
struct __attribute__((packed)) page_header {
|
||||
std::uint16_t page_code;
|
||||
std::uint16_t length;
|
||||
};
|
||||
static_assert(sizeof(page_header) == 4u);
|
||||
|
||||
// device encryption status page
|
||||
struct __attribute__((packed)) page_des {
|
||||
std::uint16_t page_code;
|
||||
std::uint16_t length;
|
||||
std::byte scope;
|
||||
static constexpr auto scope_it_nexus_pos {5u};
|
||||
static constexpr std::byte scope_it_nexus_mask {7u << scope_it_nexus_pos};
|
||||
static constexpr auto scope_encryption_pos {0u};
|
||||
static constexpr std::byte scope_encryption_mask {7u << scope_encryption_pos};
|
||||
encrypt_mode encryption_mode;
|
||||
decrypt_mode decryption_mode;
|
||||
std::uint8_t algorithm_index;
|
||||
std::uint32_t key_instance_counter;
|
||||
std::byte flags;
|
||||
static constexpr auto flags_parameters_control_pos {4u};
|
||||
static constexpr std::byte flags_parameters_control_mask {
|
||||
7u << flags_parameters_control_pos};
|
||||
// volume contains encrypted logical blocks
|
||||
static constexpr auto flags_vcelb_pos {3u};
|
||||
static constexpr std::byte flags_vcelb_mask {1u << flags_vcelb_pos};
|
||||
// check external encryption mode status
|
||||
static constexpr auto flags_ceems_pos {1u};
|
||||
static constexpr std::byte flags_ceems_mask {3u << flags_ceems_pos};
|
||||
// raw decryption mode disabled
|
||||
static constexpr auto flags_rdmd_pos {0u};
|
||||
static constexpr std::byte flags_rdmd_mask {1u << flags_rdmd_pos};
|
||||
kadf kad_format;
|
||||
std::uint16_t asdk_count;
|
||||
std::byte reserved[8];
|
||||
kad kads[];
|
||||
};
|
||||
static_assert(sizeof(page_des) == 24u);
|
||||
|
||||
constexpr std::size_t SSP_PAGE_ALLOCATION = 8192;
|
||||
using page_buffer = std::uint8_t[SSP_PAGE_ALLOCATION];
|
||||
|
||||
// set data encryption page
|
||||
struct __attribute__((packed)) page_sde {
|
||||
std::uint16_t page_code;
|
||||
std::uint16_t length;
|
||||
std::byte control;
|
||||
static constexpr auto control_scope_pos {5u};
|
||||
static constexpr std::byte control_scope_mask {7u << control_scope_pos};
|
||||
static constexpr auto control_lock_pos {0u};
|
||||
static constexpr std::byte control_lock_mask {1u << control_lock_pos};
|
||||
std::byte flags;
|
||||
// check external encryption mode
|
||||
static constexpr auto flags_ceem_pos {6u};
|
||||
static constexpr std::byte flags_ceem_mask {3u << flags_ceem_pos};
|
||||
// raw decryption mode control
|
||||
static constexpr auto flags_rdmc_pos {4u};
|
||||
static constexpr std::byte flags_rdmc_mask {3u << flags_rdmc_pos};
|
||||
// supplemental decryption key
|
||||
static constexpr auto flags_sdk_pos {3u};
|
||||
static constexpr std::byte flags_sdk_mask {1u << flags_sdk_pos};
|
||||
// clear key on demount
|
||||
static constexpr auto flags_ckod_pos {2u};
|
||||
static constexpr std::byte flags_ckod_mask {1u << flags_ckod_pos};
|
||||
// clear key on reservation preempt
|
||||
static constexpr auto flags_ckorp_pos {1u};
|
||||
static constexpr std::byte flags_ckorp_mask {1u << flags_ckorp_pos};
|
||||
// clear key on reservation loss
|
||||
static constexpr auto flags_ckorl_pos {0u};
|
||||
static constexpr std::byte flags_ckorl_mask {1u << flags_ckorl_pos};
|
||||
encrypt_mode encryption_mode;
|
||||
decrypt_mode decryption_mode;
|
||||
std::uint8_t algorithm_index;
|
||||
std::uint8_t key_format;
|
||||
kadf kad_format;
|
||||
std::byte reserved[7];
|
||||
std::uint16_t key_length;
|
||||
std::uint8_t key[];
|
||||
};
|
||||
static_assert(sizeof(page_sde) == 20u);
|
||||
|
||||
enum class sde_rdmc : std::uint8_t {
|
||||
algorithm_default = 0u << page_sde::flags_rdmc_pos,
|
||||
enabled = 2u << page_sde::flags_rdmc_pos, // corresponds to --allow-raw-read
|
||||
// command line option
|
||||
disabled =
|
||||
3u << page_sde::flags_rdmc_pos, // corresponds to --no-allow-raw-read
|
||||
// command line option
|
||||
};
|
||||
|
||||
// next block encryption status page
|
||||
struct __attribute__((packed)) page_nbes {
|
||||
std::uint16_t page_code;
|
||||
std::uint16_t length;
|
||||
std::uint64_t logical_object_number;
|
||||
std::byte status;
|
||||
static constexpr auto status_compression_pos {4u};
|
||||
static constexpr std::byte status_compression_mask {
|
||||
15u << status_compression_pos};
|
||||
static constexpr auto status_encryption_pos {0u};
|
||||
static constexpr std::byte status_encryption_mask {15u
|
||||
<< status_encryption_pos};
|
||||
std::uint8_t algorithm_index;
|
||||
std::byte flags;
|
||||
// encryption mode external status
|
||||
static constexpr auto flags_emes_pos {1u};
|
||||
static constexpr std::byte flags_emes_mask {1u << flags_emes_pos};
|
||||
// raw decryption mode disabled status
|
||||
static constexpr auto flags_rdmds_pos {0u};
|
||||
static constexpr std::byte flags_rdmds_mask {1u << flags_rdmds_pos};
|
||||
kadf kad_format;
|
||||
kad kads[];
|
||||
};
|
||||
static_assert(sizeof(page_nbes) == 16u);
|
||||
|
||||
struct __attribute__((packed)) algorithm_descriptor {
|
||||
std::uint8_t algorithm_index;
|
||||
std::byte reserved1;
|
||||
std::uint16_t length;
|
||||
std::byte flags1;
|
||||
// algorithm valid for mounted volume
|
||||
static constexpr auto flags1_avfmv_pos {7u};
|
||||
static constexpr std::byte flags1_avfmv_mask {1u << flags1_avfmv_pos};
|
||||
// supplemental decryption key capable
|
||||
static constexpr auto flags1_sdk_c_pos {6u};
|
||||
static constexpr std::byte flags1_sdk_c_mask {1u << flags1_sdk_c_pos};
|
||||
// message authentication code capable
|
||||
static constexpr auto flags1_mac_c_pos {5u};
|
||||
static constexpr std::byte flags1_mac_c_mask {1u << flags1_mac_c_pos};
|
||||
// distinguish encrypted logical block capable
|
||||
static constexpr auto flags1_delb_c_pos {4u};
|
||||
static constexpr std::byte flags1_delb_c_mask {1u << flags1_delb_c_pos};
|
||||
// decryption capabilities
|
||||
static constexpr auto flags1_decrypt_c_pos {2u};
|
||||
static constexpr std::byte flags1_decrypt_c_mask {3u << flags1_decrypt_c_pos};
|
||||
// encryption capabilities
|
||||
static constexpr auto flags1_encrypt_c_pos {0u};
|
||||
static constexpr std::byte flags1_encrypt_c_mask {3u << flags1_encrypt_c_pos};
|
||||
std::byte flags2;
|
||||
// algorithm valid for current logical position
|
||||
static constexpr auto flags2_avfcp_pos {6u};
|
||||
static constexpr std::byte flags2_avfcp_mask {3u << flags2_avfcp_pos};
|
||||
// nonce capabilities
|
||||
static constexpr auto flags2_nonce_pos {4u};
|
||||
static constexpr std::byte flags2_nonce_mask {3u << flags2_nonce_pos};
|
||||
// KAD format capable
|
||||
static constexpr auto flags2_kadf_c_pos {3u};
|
||||
static constexpr std::byte flags2_kadf_c_mask {1u << flags2_kadf_c_pos};
|
||||
// volume contains encrypted logical blocks capable
|
||||
static constexpr auto flags2_vcelb_c_pos {2u};
|
||||
static constexpr std::byte flags2_vcelb_c_mask {1u << flags2_vcelb_c_pos};
|
||||
// U-KAD fixed
|
||||
static constexpr auto flags2_ukadf_pos {1u};
|
||||
static constexpr std::byte flags2_ukadf_mask {1u << flags2_ukadf_pos};
|
||||
// A-KAD fixed
|
||||
static constexpr auto flags2_akadf_pos {0u};
|
||||
static constexpr std::byte flags2_akadf_mask {1u << flags2_akadf_pos};
|
||||
std::uint16_t maximum_ukad_length;
|
||||
std::uint16_t maximum_akad_length;
|
||||
std::uint16_t key_length;
|
||||
std::byte flags3;
|
||||
// decryption capabilities
|
||||
static constexpr auto flags3_dkad_c_pos {6u};
|
||||
static constexpr std::byte flags3_dkad_c_mask {3u << flags3_dkad_c_pos};
|
||||
// external encryption mode control capabilities
|
||||
static constexpr auto flags3_eemc_c_pos {4u};
|
||||
static constexpr std::byte flags3_eemc_c_mask {3u << flags3_eemc_c_pos};
|
||||
// raw decryption mode control capabilities
|
||||
static constexpr auto flags3_rdmc_c_pos {1u};
|
||||
static constexpr std::byte flags3_rdmc_c_mask {7u << flags3_rdmc_c_pos};
|
||||
// encryption algorithm records encryption mode
|
||||
static constexpr auto flags3_earem_pos {0u};
|
||||
static constexpr std::byte flags3_earem_mask {1u << flags3_earem_pos};
|
||||
std::uint8_t maximum_eedk_count;
|
||||
static constexpr auto maximum_eedk_count_pos {0u};
|
||||
static constexpr std::uint8_t maximum_eedk_count_mask {
|
||||
15u << maximum_eedk_count_pos};
|
||||
std::uint16_t msdk_count;
|
||||
std::uint16_t maximum_eedk_size;
|
||||
std::byte reserved2[2];
|
||||
std::uint32_t security_algorithm_code;
|
||||
|
||||
static constexpr std::size_t header_size {4u};
|
||||
};
|
||||
static_assert(sizeof(algorithm_descriptor) == 24u);
|
||||
|
||||
// device encryption capabilities page
|
||||
struct __attribute__((packed)) page_dec {
|
||||
std::uint16_t page_code;
|
||||
std::uint16_t length;
|
||||
std::byte flags;
|
||||
// external data encryption control capable
|
||||
static constexpr auto flags_extdecc_pos {2u};
|
||||
static constexpr std::byte flags_extdecc_mask {3u << flags_extdecc_pos};
|
||||
// configuration prevented
|
||||
static constexpr auto flags_cfg_p_pos {0u};
|
||||
static constexpr std::byte flags_cfg_p_mask {3u << flags_cfg_p_pos};
|
||||
std::byte reserved[15];
|
||||
algorithm_descriptor ads[];
|
||||
};
|
||||
static_assert(sizeof(page_dec) == 20u);
|
||||
|
||||
struct __attribute__((packed)) inquiry_data {
|
||||
// bitfield definitions omitted since stenc only uses vendor and product info
|
||||
std::byte peripheral;
|
||||
std::byte flags1;
|
||||
std::uint8_t version;
|
||||
std::byte flags2;
|
||||
std::uint8_t additional_length;
|
||||
std::byte flags3;
|
||||
std::byte flags4;
|
||||
std::byte flags5;
|
||||
std::array<char, 8> vendor;
|
||||
std::array<char, 16> product_id;
|
||||
std::array<char, 4> product_rev;
|
||||
std::uint8_t vendor_specific[20];
|
||||
std::byte reserved1[2];
|
||||
std::uint16_t version_descriptor[8];
|
||||
std::byte reserved2[22];
|
||||
|
||||
static constexpr std::size_t header_size {5u};
|
||||
};
|
||||
static_assert(sizeof(inquiry_data) == 96u);
|
||||
|
||||
struct __attribute__((packed)) sense_data {
|
||||
std::byte response;
|
||||
static constexpr auto response_valid_pos {7u};
|
||||
static constexpr std::byte response_valid_mask {1u << response_valid_pos};
|
||||
static constexpr auto response_code_pos {0u};
|
||||
static constexpr std::byte response_code_mask {127u << response_code_pos};
|
||||
std::byte reserved;
|
||||
std::byte flags;
|
||||
static constexpr auto flags_filemark_pos {7u};
|
||||
static constexpr std::byte flags_filemark_mask {1u << flags_filemark_pos};
|
||||
static constexpr auto flags_eom_pos {6u}; // end of medium
|
||||
static constexpr std::byte flags_eom_mask {1u << flags_eom_pos};
|
||||
static constexpr auto flags_ili_pos {5u}; // incorrect length indicator
|
||||
static constexpr std::byte flags_ili_mask {1u << flags_ili_pos};
|
||||
static constexpr auto flags_sdat_ovfl_pos {4u}; // sense data overflow
|
||||
static constexpr std::byte flags_sdat_ovfl_mask {1u << flags_sdat_ovfl_pos};
|
||||
static constexpr auto flags_sense_key_pos {0u};
|
||||
static constexpr std::byte flags_sense_key_mask {15u << flags_sense_key_pos};
|
||||
std::uint8_t information[4];
|
||||
std::uint8_t additional_sense_length;
|
||||
std::uint8_t command_specific_information[4];
|
||||
std::uint8_t additional_sense_code;
|
||||
std::uint8_t additional_sense_qualifier;
|
||||
std::uint8_t field_replaceable_unit_code;
|
||||
std::uint8_t sense_key_specific[3];
|
||||
std::uint8_t additional_sense_bytes[];
|
||||
|
||||
static constexpr std::byte no_sense {0u};
|
||||
static constexpr std::byte recovered_error {1u};
|
||||
static constexpr std::byte not_ready {2u};
|
||||
static constexpr std::byte medium_error {3u};
|
||||
static constexpr std::byte hardware_error {4u};
|
||||
static constexpr std::byte illegal_request {5u};
|
||||
static constexpr std::byte unit_attention {6u};
|
||||
static constexpr std::byte data_protect {7u};
|
||||
static constexpr std::byte blank_check {8u};
|
||||
|
||||
static constexpr std::size_t header_size {8u};
|
||||
static constexpr std::size_t maximum_size {252u}; // per SPC-5
|
||||
};
|
||||
static_assert(sizeof(sense_data) == 18u);
|
||||
|
||||
// declared as std::array instead of std::uint8_t[] because
|
||||
// std::unique_ptr does not allow construction of fixed-sized arrays
|
||||
using sense_buffer = std::array<std::uint8_t, sense_data::maximum_size>;
|
||||
|
||||
class scsi_error : public std::runtime_error {
|
||||
public:
|
||||
explicit scsi_error(std::unique_ptr<sense_buffer>&& buf)
|
||||
: std::runtime_error {"SCSI I/O error"}, sense_buf {std::move(buf)}
|
||||
{}
|
||||
const sense_data& get_sense() const
|
||||
{
|
||||
return reinterpret_cast<sense_data&>(*sense_buf->data());
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<sense_buffer> sense_buf;
|
||||
};
|
||||
|
||||
// Extract pointers to kad structures within a variable-length page.
|
||||
// Page must have a page_header layout
|
||||
template <typename Page>
|
||||
std::vector<std::reference_wrapper<const kad>> read_page_kads(const Page& page)
|
||||
{
|
||||
const auto start {reinterpret_cast<const std::uint8_t *>(&page)};
|
||||
auto it {start + sizeof(Page)};
|
||||
const auto end {start + ntohs(page.length) + sizeof(page_header)};
|
||||
std::vector<std::reference_wrapper<const kad>> v {};
|
||||
|
||||
while (it < end) {
|
||||
auto elem {reinterpret_cast<const kad *>(it)};
|
||||
v.push_back(std::cref(*elem));
|
||||
it += ntohs(elem->length) + sizeof(kad);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
// Check if a tape is loaded
|
||||
bool is_device_ready(const std::string& device);
|
||||
// Get SCSI inquiry data from device
|
||||
inquiry_data get_inquiry(const std::string& device);
|
||||
// Get data encryption status page
|
||||
const page_des& get_des(const std::string& device, std::uint8_t *buffer,
|
||||
std::size_t length);
|
||||
// Get next block encryption status page
|
||||
const page_nbes& get_nbes(const std::string& device, std::uint8_t *buffer,
|
||||
std::size_t length);
|
||||
// Get device encryption capabilities
|
||||
const page_dec& get_dec(const std::string& device, std::uint8_t *buffer,
|
||||
std::size_t length);
|
||||
// Fill out a set data encryption page with parameters.
|
||||
// Result is allocated and returned as a std::unique_ptr and should
|
||||
// be sent to the device using scsi::write_sde
|
||||
std::unique_ptr<const std::uint8_t[]>
|
||||
make_sde(encrypt_mode enc_mode, decrypt_mode dec_mode,
|
||||
std::uint8_t algorithm_index, const std::vector<std::uint8_t>& key,
|
||||
const std::string& key_name, kadf key_format, sde_rdmc rdmc,
|
||||
bool ckod);
|
||||
// Write set data encryption parameters to device
|
||||
void write_sde(const std::string& device, const std::uint8_t *sde_buffer);
|
||||
void print_sense_data(std::ostream& os, const sense_data& sd);
|
||||
std::vector<std::reference_wrapper<const algorithm_descriptor>>
|
||||
read_algorithms(const page_dec& page);
|
||||
|
||||
} // namespace scsi
|
||||
|
||||
#endif
|
||||
|
||||
45
stenc.spec
Normal file
45
stenc.spec
Normal file
@@ -0,0 +1,45 @@
|
||||
# SPDX-FileCopyrightText: 2022 stenc authors
|
||||
#
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
Name: stenc
|
||||
Version: 2.x.x
|
||||
Release: 1%{?dist}
|
||||
Summary: SCSI Tape Encryption Manager
|
||||
|
||||
License: GPL-2.0-or-later
|
||||
URL: https://github.com/scsitape/stenc
|
||||
Source0: https://github.com/scsitape/stenc/archive/%{version}.tar.gz#/%{name}-%{version}.tar.gz
|
||||
|
||||
BuildRequires: gcc-c++
|
||||
BuildRequires: make
|
||||
BuildRequires: autoconf
|
||||
BuildRequires: automake
|
||||
BuildRequires: bash-completion
|
||||
|
||||
%description
|
||||
SCSI Tape Encryption Manager - Manages encryption on LTO 4 and newer tape
|
||||
drives with hardware-based encryption
|
||||
|
||||
%prep
|
||||
%autosetup
|
||||
|
||||
%build
|
||||
./autogen.sh
|
||||
%configure
|
||||
make %{?_smp_mflags}
|
||||
|
||||
%install
|
||||
make install DESTDIR=%{buildroot}
|
||||
|
||||
%files
|
||||
%license LICENSES/GPL-2.0-or-later.txt
|
||||
%doc README.md AUTHORS.md
|
||||
%{_bindir}/stenc
|
||||
%{_mandir}/man1/stenc.1*
|
||||
%{_datadir}/bash-completion/completions/stenc
|
||||
|
||||
%changelog
|
||||
* Sat Aug 27 2022 Paweł Marciniak <sunwire+repo@gmail.com> - 2.x.x-1
|
||||
- Version 2.0.0 Pre-release
|
||||
|
||||
43
stenc.xml
Normal file
43
stenc.xml
Normal file
@@ -0,0 +1,43 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<cpe-list xmlns:config="http://scap.nist.gov/schema/configuration/0.1" xmlns="http://cpe.mitre.org/dictionary/2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlnsscap-core="http://scap.nist.gov/schema/scap-core/0.3" xmlns:cpe-23="http://scap.nist.gov/schema/cpe-extension/2.3" xmlns:ns6="http://scap.nist.gov/schema/scap-core/0.1" xmlns:meta="http://scap.nist.gov/schema/cpe-dictionary-metadata/0.2" xsi:schemaLocation="http://scap.nist.gov/schema/cpe-extension/2.3 https://scap.nist.gov/schema/cpe/2.3/cpe-dictionary-extension_2.3.xsd http://cpe.mitre.org/dictionary/2.0 https://scap.nist.gov/schema/cpe/2.3/cpe-dictionary_2.3.xsd http://scap.nist.gov/schema/cpe-dictionary-metadata/0.2 https://scap.nist.gov/schema/cpe/2.1/cpe-dictionary-metadata_0.2.xsd http://scap.nist.gov/schema/scap-core/0.3 https://scap.nist.gov/schema/nvd/scap-core_0.3.xsd http://scap.nist.gov/schema/configuration/0.1 https://scap.nist.gov/schema/nvd/configuration_0.1.xsd http://scap.nist.gov/schema/scap-core/0.1 https://scap.nist.gov/schema/nvd/scap-core_0.1.xsd">
|
||||
<cpe-item name="cpe:/a:stencproject:stenc:1.0.7">
|
||||
<title xml:lang="en-US">stenc 1.0.7</title>
|
||||
<references>
|
||||
<reference href="https://github.com/scsitape/stenc/releases">VERSION</reference>
|
||||
<reference href="https://github.com/scsitape">VENDOR</reference>
|
||||
</references>
|
||||
<cpe-23:cpe23-item name="cpe:2.3:a:stencproject:stenc:1.0.7:*:*:*:*:*:*:*"/>
|
||||
</cpe-item>
|
||||
<cpe-item name="cpe:/a:stencproject:stenc:1.0.8">
|
||||
<title xml:lang="en-US">stenc 1.0.8</title>
|
||||
<references>
|
||||
<reference href="https://github.com/scsitape/stenc/releases">VERSION</reference>
|
||||
<reference href="https://github.com/scsitape">VENDOR</reference>
|
||||
</references>
|
||||
<cpe-23:cpe23-item name="cpe:2.3:a:stencproject:stenc:1.0.8:*:*:*:*:*:*:*"/>
|
||||
</cpe-item>
|
||||
<cpe-item name="cpe:/a:stencproject:stenc:1.1.0">
|
||||
<title xml:lang="en-US">stenc 1.1.0</title>
|
||||
<references>
|
||||
<reference href="https://github.com/scsitape/stenc/releases">VERSION</reference>
|
||||
<reference href="https://github.com/scsitape">VENDOR</reference>
|
||||
</references>
|
||||
<cpe-23:cpe23-item name="cpe:2.3:a:stencproject:stenc:1.1.0:*:*:*:*:*:*:*"/>
|
||||
</cpe-item>
|
||||
<cpe-item name="cpe:/a:stencproject:stenc:1.1.1">
|
||||
<title xml:lang="en-US">stenc 1.1.1</title>
|
||||
<references>
|
||||
<reference href="https://github.com/scsitape/stenc/releases">VERSION</reference>
|
||||
<reference href="https://github.com/scsitape">VENDOR</reference>
|
||||
</references>
|
||||
<cpe-23:cpe23-item name="cpe:2.3:a:stencproject:stenc:1.1.1:*:*:*:*:*:*:*"/>
|
||||
</cpe-item>
|
||||
<cpe-item name="cpe:/a:stencproject:stenc:2.0.0">
|
||||
<title xml:lang="en-US">stenc 2.0.0</title>
|
||||
<references>
|
||||
<reference href="https://github.com/scsitape/stenc/releases">VERSION</reference>
|
||||
<reference href="https://github.com/scsitape">VENDOR</reference>
|
||||
</references>
|
||||
<cpe-23:cpe23-item name="cpe:2.3:a:stencproject:stenc:2.0.0:*:*:*:*:*:*:*"/>
|
||||
</cpe-item>
|
||||
</cpe-list>
|
||||
3
stenc.xml.license
Normal file
3
stenc.xml.license
Normal file
@@ -0,0 +1,3 @@
|
||||
SPDX-FileCopyrightText: 2022 stenc authors
|
||||
|
||||
SPDX-License-Identifier: CC0-1.0
|
||||
9
tests/Makefile.am
Normal file
9
tests/Makefile.am
Normal file
@@ -0,0 +1,9 @@
|
||||
# SPDX-FileCopyrightText: 2022 stenc authors
|
||||
#
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
AM_CPPFLAGS=-std=c++17 -I${top_srcdir}/src
|
||||
TESTS=scsi output
|
||||
check_PROGRAMS=scsi output
|
||||
scsi_SOURCES=catch.hpp scsi.cpp ${top_srcdir}/src/scsiencrypt.cpp
|
||||
output_SOURCES=catch.hpp output.cpp ${top_srcdir}/src/scsiencrypt.cpp
|
||||
17976
tests/catch.hpp
Normal file
17976
tests/catch.hpp
Normal file
File diff suppressed because it is too large
Load Diff
178
tests/output.cpp
Normal file
178
tests/output.cpp
Normal file
@@ -0,0 +1,178 @@
|
||||
// SPDX-FileCopyrightText: 2022 stenc authors
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include "catch.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "main.cpp"
|
||||
|
||||
using namespace std::literals::string_literals;
|
||||
|
||||
TEST_CASE("Test key_from_hex_chars", "[output]")
|
||||
{
|
||||
REQUIRE(key_from_hex_chars(""s) == std::vector<std::uint8_t> {});
|
||||
REQUIRE(key_from_hex_chars("hello"s) == std::nullopt);
|
||||
REQUIRE(key_from_hex_chars("12z"s) == std::nullopt);
|
||||
REQUIRE(key_from_hex_chars("0xabcd"s) == std::nullopt);
|
||||
REQUIRE(key_from_hex_chars("ab cd"s) == std::nullopt);
|
||||
REQUIRE(key_from_hex_chars("a"s) == std::vector<std::uint8_t> {0x0a});
|
||||
REQUIRE(key_from_hex_chars("0123456789abcdef"s) ==
|
||||
std::vector<std::uint8_t> {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd,
|
||||
0xef});
|
||||
REQUIRE(key_from_hex_chars("0123456789ABCDEF"s) ==
|
||||
std::vector<std::uint8_t> {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd,
|
||||
0xef});
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare the output of stenc given device responses
|
||||
*
|
||||
* These tests check the representation and interpretation of raw device data
|
||||
* and that the program output accurately reports the meaning of the data.
|
||||
*/
|
||||
TEST_CASE("Test SCSI inquiry output", "[output]")
|
||||
{
|
||||
const std::uint8_t response[] {
|
||||
0x01, 0x80, 0x00, 0x02, 0x5b, 0x00, 0x00, 0x02, 0x41, 0x43, 0x4d, 0x45,
|
||||
0x20, 0x20, 0x20, 0x20, 0x55, 0x6c, 0x74, 0x72, 0x69, 0x75, 0x6d, 0x2d,
|
||||
0x31, 0x30, 0x30, 0x30, 0x20, 0x20, 0x20, 0x20, 0x31, 0x32, 0x33, 0x34,
|
||||
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, 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,
|
||||
};
|
||||
const std::string expected_output {"ACME Ultrium-1000 1234"s};
|
||||
std::ostringstream oss;
|
||||
print_device_inquiry(oss,
|
||||
reinterpret_cast<const scsi::inquiry_data&>(response));
|
||||
REQUIRE(oss.str() == expected_output);
|
||||
}
|
||||
|
||||
TEST_CASE("SCSI get device encryption status output 1", "[output]")
|
||||
{
|
||||
std::map<std::uint8_t, std::string> algorithms {
|
||||
{1, "AES-256-GCM-128"s},
|
||||
};
|
||||
const std::uint8_t page[] {
|
||||
0x00, 0x20, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
const std::string expected_output {"\
|
||||
Reading: Not decrypting\n\
|
||||
Writing: Not encrypting\n\
|
||||
Key instance counter: 0\n"s};
|
||||
std::ostringstream oss;
|
||||
print_device_status(oss, reinterpret_cast<const scsi::page_des&>(page),
|
||||
algorithms);
|
||||
REQUIRE(oss.str() == expected_output);
|
||||
}
|
||||
|
||||
TEST_CASE("SCSI get device encryption status output 2", "[output]")
|
||||
{
|
||||
std::map<std::uint8_t, std::string> algorithms {
|
||||
{1, "AES-256-GCM-128"s},
|
||||
};
|
||||
const std::uint8_t page[] {
|
||||
0x00, 0x20, 0x00, 0x24, 0x42, 0x02, 0x02, 0x01, 0x00, 0x00,
|
||||
0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x48, 0x65,
|
||||
0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21,
|
||||
};
|
||||
const std::string expected_output {"\
|
||||
Reading: Decrypting (AES-256-GCM-128)\n\
|
||||
Unencrypted blocks not readable\n\
|
||||
Writing: Encrypting (AES-256-GCM-128)\n\
|
||||
Key instance counter: 1\n\
|
||||
Drive key desc. (U-KAD): Hello world!\n"s};
|
||||
std::ostringstream oss;
|
||||
print_device_status(oss, reinterpret_cast<const scsi::page_des&>(page),
|
||||
algorithms);
|
||||
REQUIRE(oss.str() == expected_output);
|
||||
}
|
||||
|
||||
TEST_CASE("Test SCSI get next block encryption status output 1", "[output]")
|
||||
{
|
||||
std::map<std::uint8_t, std::string> algorithms {
|
||||
{1, "AES-256-GCM-128"s},
|
||||
};
|
||||
const std::uint8_t page[] {
|
||||
0x00, 0x21, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
|
||||
};
|
||||
const std::string expected_output {"\
|
||||
Current block status: Not encrypted\n"s};
|
||||
std::ostringstream oss;
|
||||
print_block_status(oss, reinterpret_cast<const scsi::page_nbes&>(page),
|
||||
algorithms);
|
||||
REQUIRE(oss.str() == expected_output);
|
||||
}
|
||||
|
||||
TEST_CASE("Test SCSI get next block encryption status output 2", "[output]")
|
||||
{
|
||||
std::map<std::uint8_t, std::string> algorithms {
|
||||
{1, "AES-256-GCM-128"s},
|
||||
};
|
||||
const std::uint8_t page[] {
|
||||
0x00, 0x21, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0c, 0x48, 0x65,
|
||||
0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21,
|
||||
};
|
||||
const std::string expected_output {"\
|
||||
Current block status: Encrypted and able to decrypt (AES-256-GCM-128)\n"s};
|
||||
std::ostringstream oss;
|
||||
print_block_status(oss, reinterpret_cast<const scsi::page_nbes&>(page),
|
||||
algorithms);
|
||||
REQUIRE(oss.str() == expected_output);
|
||||
}
|
||||
|
||||
TEST_CASE("Test SCSI get next block encryption status output 3", "[output]")
|
||||
{
|
||||
std::map<std::uint8_t, std::string> algorithms {
|
||||
{1, "AES-256-GCM-128"s},
|
||||
};
|
||||
const std::uint8_t page[] {
|
||||
0x00, 0x21, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x06, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x0c, 0x48, 0x65,
|
||||
0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21,
|
||||
};
|
||||
const std::string expected_output {"\
|
||||
Current block status: Encrypted, key missing or invalid (AES-256-GCM-128)\n\
|
||||
Current block key desc. (U-KAD): Hello world!\n"s};
|
||||
std::ostringstream oss;
|
||||
print_block_status(oss, reinterpret_cast<const scsi::page_nbes&>(page),
|
||||
algorithms);
|
||||
REQUIRE(oss.str() == expected_output);
|
||||
}
|
||||
|
||||
TEST_CASE("Test SCSI get data encryption capabilities output", "[output]")
|
||||
{
|
||||
const std::uint8_t page[] {
|
||||
0x00, 0x10, 0x00, 0x3c, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x14,
|
||||
0x8a, 0x8c, 0x00, 0x20, 0x00, 0x3c, 0x00, 0x20, 0xed, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x14, 0x02, 0x00, 0x00, 0x14,
|
||||
0x8a, 0x8f, 0x00, 0x20, 0x00, 0x3c, 0x00, 0x20, 0xd9, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x10,
|
||||
};
|
||||
const std::string expected_output {"\
|
||||
Supported algorithms:\n\
|
||||
1 AES-256-GCM-128\n\
|
||||
Key descriptors allowed, maximum 32 bytes\n\
|
||||
Raw decryption mode not allowed\n\
|
||||
2 AES-256-CCM-128\n\
|
||||
Key descriptors allowed, fixed 32 bytes\n\
|
||||
Raw decryption mode allowed, raw read disabled by default\n"s};
|
||||
std::ostringstream oss;
|
||||
print_algorithms(oss, scsi::read_algorithms(
|
||||
reinterpret_cast<const scsi::page_dec&>(page)));
|
||||
REQUIRE(oss.str() == expected_output);
|
||||
}
|
||||
427
tests/scsi.cpp
Normal file
427
tests/scsi.cpp
Normal file
@@ -0,0 +1,427 @@
|
||||
// SPDX-FileCopyrightText: 2022 stenc authors
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include "catch.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#if HAVE_ARPA_INET_H
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
#if HAVE_NETINET_IN_H
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#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]")
|
||||
{
|
||||
const std::uint8_t expected[] {
|
||||
// clang-format off
|
||||
0x00, 0x10, // page code
|
||||
0x00, 0x10, // page length
|
||||
0x40, // scope
|
||||
0x40, // CEEM, CKOD, RDMC, et al.
|
||||
0x00, // encyption mode
|
||||
0x00, // decryption mode
|
||||
0x01, // algorithm index
|
||||
0x00, // key format
|
||||
0x00, // KAD format
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved [7]
|
||||
0x00, 0x00 // key length
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
std::vector<std::uint8_t> key {};
|
||||
std::string key_name {};
|
||||
|
||||
auto page_buffer {scsi::make_sde(
|
||||
scsi::encrypt_mode::off, scsi::decrypt_mode::off, 1u, key, key_name,
|
||||
scsi::kadf::unspecified, scsi::sde_rdmc::algorithm_default, false)};
|
||||
auto& page {reinterpret_cast<const scsi::page_sde&>(*page_buffer.get())};
|
||||
REQUIRE(sizeof(scsi::page_header) + ntohs(page.length) == sizeof(expected));
|
||||
REQUIRE(std::memcmp(&page, expected, sizeof(expected)) == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("Enable encryption command", "[scsi]")
|
||||
{
|
||||
const std::uint8_t expected[] {
|
||||
// clang-format off
|
||||
0x00, 0x10, // page code
|
||||
0x00, 0x30, // page length
|
||||
0x40, // scope
|
||||
0x40, // CEEM, CKOD, RDMC, et al.
|
||||
0x02, // encyption mode
|
||||
0x02, // decryption mode
|
||||
0x01, // algorithm index
|
||||
0x00, // key format
|
||||
0x00, // KAD format
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved [7]
|
||||
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,
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
std::vector<std::uint8_t> key {
|
||||
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,
|
||||
};
|
||||
std::string key_name {};
|
||||
|
||||
auto page_buffer {scsi::make_sde(
|
||||
scsi::encrypt_mode::on, scsi::decrypt_mode::on, 1u, key, key_name,
|
||||
scsi::kadf::unspecified, scsi::sde_rdmc::algorithm_default, false)};
|
||||
auto& page {reinterpret_cast<const scsi::page_sde&>(*page_buffer.get())};
|
||||
REQUIRE(sizeof(scsi::page_header) + ntohs(page.length) == sizeof(expected));
|
||||
REQUIRE(std::memcmp(&page, expected, sizeof(expected)) == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("Enable encryption command with options", "[scsi]")
|
||||
{
|
||||
const std::uint8_t expected[] {
|
||||
// clang-format off
|
||||
0x00, 0x10, // page code
|
||||
0x00, 0x30, // page length
|
||||
0x40, // scope
|
||||
0x64, // CEEM, CKOD, RDMC, et al.
|
||||
0x02, // encyption mode
|
||||
0x02, // decryption mode
|
||||
0x01, // algorithm index
|
||||
0x00, // key format
|
||||
0x01, // KAD format
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved [7]
|
||||
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,
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
std::vector<std::uint8_t> key {
|
||||
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,
|
||||
};
|
||||
std::string key_name {};
|
||||
|
||||
auto page_buffer {scsi::make_sde(
|
||||
scsi::encrypt_mode::on, scsi::decrypt_mode::on, 1u, key, key_name,
|
||||
scsi::kadf::binary_key_name, scsi::sde_rdmc::enabled, true)};
|
||||
auto& page {reinterpret_cast<const scsi::page_sde&>(*page_buffer.get())};
|
||||
REQUIRE(sizeof(scsi::page_header) + ntohs(page.length) == sizeof(expected));
|
||||
REQUIRE(std::memcmp(&page, expected, sizeof(expected)) == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("Enable encryption command with key name", "[scsi]")
|
||||
{
|
||||
const std::uint8_t expected[] {
|
||||
// clang-format off
|
||||
0x00, 0x10, // page code
|
||||
0x00, 0x40, // page length
|
||||
0x40, // scope
|
||||
0x40, // CEEM, CKOD, RDMC, et al.
|
||||
0x02, // encyption mode
|
||||
0x02, // decryption mode
|
||||
0x01, // algorithm index
|
||||
0x00, // key format
|
||||
0x02, // KAD format
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved [7]
|
||||
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,
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
std::vector<std::uint8_t> key {
|
||||
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,
|
||||
};
|
||||
std::string key_name {"Hello world!"s};
|
||||
|
||||
auto page_buffer {scsi::make_sde(
|
||||
scsi::encrypt_mode::on, scsi::decrypt_mode::on, 1u, key, key_name,
|
||||
scsi::kadf::ascii_key_name, scsi::sde_rdmc::algorithm_default, false)};
|
||||
auto& page {reinterpret_cast<const scsi::page_sde&>(*page_buffer.get())};
|
||||
REQUIRE(sizeof(scsi::page_header) + ntohs(page.length) == sizeof(expected));
|
||||
REQUIRE(std::memcmp(&page, 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 std::uint8_t buffer[] {
|
||||
// clang-format off
|
||||
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,
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
auto& page_des {reinterpret_cast<const scsi::page_des&>(buffer)};
|
||||
REQUIRE(ntohs(page_des.page_code) == 0x20u);
|
||||
REQUIRE(ntohs(page_des.length) == 36u);
|
||||
REQUIRE((page_des.scope & scsi::page_des::scope_it_nexus_mask) ==
|
||||
std::byte {2u} << scsi::page_des::scope_it_nexus_pos);
|
||||
REQUIRE((page_des.scope & scsi::page_des::scope_encryption_mask) ==
|
||||
std::byte {2u} << scsi::page_des::scope_encryption_pos);
|
||||
REQUIRE(page_des.encryption_mode == scsi::encrypt_mode::on);
|
||||
REQUIRE(page_des.decryption_mode == scsi::decrypt_mode::on);
|
||||
REQUIRE(page_des.algorithm_index == 1u);
|
||||
REQUIRE(ntohl(page_des.key_instance_counter) == 1u);
|
||||
REQUIRE((page_des.flags & scsi::page_des::flags_parameters_control_mask) ==
|
||||
std::byte {1u} << scsi::page_des::flags_parameters_control_pos);
|
||||
REQUIRE((page_des.flags & scsi::page_des::flags_vcelb_mask) ==
|
||||
scsi::page_des::flags_vcelb_mask);
|
||||
REQUIRE((page_des.flags & scsi::page_des::flags_ceems_mask) == std::byte {});
|
||||
REQUIRE((page_des.flags & scsi::page_des::flags_rdmd_mask) == std::byte {});
|
||||
|
||||
auto kads = read_page_kads(page_des);
|
||||
REQUIRE(kads.size() == 1u);
|
||||
const scsi::kad& kd = kads[0];
|
||||
REQUIRE((kd.flags & scsi::kad::flags_authenticated_mask) == std::byte {1u});
|
||||
REQUIRE(ntohs(kd.length) == std::strlen("Hello world!"));
|
||||
REQUIRE(std::memcmp(kd.descriptor, "Hello world!", ntohs(kd.length)) == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("Interpret next block encryption status page", "[scsi]")
|
||||
{
|
||||
const std::uint8_t buffer[] {
|
||||
// clang-format off
|
||||
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,
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
auto& page_nbes {reinterpret_cast<const scsi::page_nbes&>(buffer)};
|
||||
REQUIRE(ntohs(page_nbes.page_code) == 0x21u);
|
||||
REQUIRE(ntohs(page_nbes.length) == 28u);
|
||||
REQUIRE((page_nbes.status & scsi::page_nbes::status_compression_mask) ==
|
||||
std::byte {});
|
||||
REQUIRE((page_nbes.status & scsi::page_nbes::status_encryption_mask) ==
|
||||
std::byte {5u} << scsi::page_nbes::status_encryption_pos);
|
||||
REQUIRE(page_nbes.algorithm_index == 1u);
|
||||
REQUIRE((page_nbes.flags & scsi::page_nbes::flags_emes_mask) == std::byte {});
|
||||
REQUIRE((page_nbes.flags & scsi::page_nbes::flags_rdmds_mask) ==
|
||||
std::byte {});
|
||||
|
||||
auto kads = read_page_kads(page_nbes);
|
||||
REQUIRE(kads.size() == 1u);
|
||||
const scsi::kad& kd = kads[0];
|
||||
REQUIRE((kd.flags & scsi::kad::flags_authenticated_mask) == std::byte {1u});
|
||||
REQUIRE(ntohs(kd.length) == std::strlen("Hello world!"));
|
||||
REQUIRE(std::memcmp(kd.descriptor, "Hello world!", ntohs(kd.length)) == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("Interpret data encryption capabilties page", "[scsi]")
|
||||
{
|
||||
const std::uint8_t buffer[] {
|
||||
// clang-format off
|
||||
0x00, 0x10, // page code
|
||||
0x00, 0x3c, // length
|
||||
0x09, // EXTDECC and CFG_P
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// algorithm 1
|
||||
0x01,
|
||||
0x00,
|
||||
0x00, 0x14,
|
||||
0x8a, // capabilties
|
||||
0x8c,
|
||||
0x00, 0x20,
|
||||
0x00, 0x3c,
|
||||
0x00, 0x20,
|
||||
0xed,
|
||||
0x00,
|
||||
0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
0x00, 0x01, 0x00, 0x14,
|
||||
// algorithm 2
|
||||
0x02,
|
||||
0x00,
|
||||
0x00, 0x14,
|
||||
0x8a, // capabilties
|
||||
0x8f,
|
||||
0x00, 0x20,
|
||||
0x00, 0x3c,
|
||||
0x00, 0x20,
|
||||
0xd9,
|
||||
0x00,
|
||||
0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
0x00, 0x01, 0x00, 0x10,
|
||||
// clang-format on
|
||||
};
|
||||
static_assert(sizeof(buffer) == sizeof(scsi::page_dec) +
|
||||
2 * sizeof(scsi::algorithm_descriptor));
|
||||
|
||||
auto& page_dec {reinterpret_cast<const scsi::page_dec&>(buffer)};
|
||||
REQUIRE(ntohs(page_dec.page_code) == 0x10u);
|
||||
REQUIRE(ntohs(page_dec.length) == 60u);
|
||||
|
||||
REQUIRE((page_dec.flags & scsi::page_dec::flags_extdecc_mask) ==
|
||||
std::byte {2u} << scsi::page_dec::flags_extdecc_pos);
|
||||
REQUIRE((page_dec.flags & scsi::page_dec::flags_cfg_p_mask) ==
|
||||
std::byte {1u} << scsi::page_dec::flags_cfg_p_pos);
|
||||
|
||||
auto algorithms {read_algorithms(page_dec)};
|
||||
REQUIRE(algorithms.size() == 2u);
|
||||
|
||||
const scsi::algorithm_descriptor& algo1 = algorithms[0];
|
||||
REQUIRE(algo1.algorithm_index == 1u);
|
||||
REQUIRE(ntohs(algo1.length) == 20u);
|
||||
REQUIRE((algo1.flags1 & scsi::algorithm_descriptor::flags1_avfmv_mask) ==
|
||||
scsi::algorithm_descriptor::flags1_avfmv_mask);
|
||||
REQUIRE((algo1.flags1 & scsi::algorithm_descriptor::flags1_sdk_c_mask) ==
|
||||
std::byte {});
|
||||
REQUIRE((algo1.flags1 & scsi::algorithm_descriptor::flags1_mac_c_mask) ==
|
||||
std::byte {});
|
||||
REQUIRE((algo1.flags1 & scsi::algorithm_descriptor::flags1_delb_c_mask) ==
|
||||
std::byte {});
|
||||
REQUIRE((algo1.flags1 & scsi::algorithm_descriptor::flags1_decrypt_c_mask) ==
|
||||
std::byte {2u} << scsi::algorithm_descriptor::flags1_decrypt_c_pos);
|
||||
REQUIRE((algo1.flags1 & scsi::algorithm_descriptor::flags1_encrypt_c_mask) ==
|
||||
std::byte {2u} << scsi::algorithm_descriptor::flags1_encrypt_c_pos);
|
||||
|
||||
REQUIRE((algo1.flags2 & scsi::algorithm_descriptor::flags2_avfcp_mask) ==
|
||||
std::byte {2u} << scsi::algorithm_descriptor::flags2_avfcp_pos);
|
||||
REQUIRE((algo1.flags2 & scsi::algorithm_descriptor::flags2_nonce_mask) ==
|
||||
std::byte {});
|
||||
REQUIRE((algo1.flags2 & scsi::algorithm_descriptor::flags2_kadf_c_mask) ==
|
||||
scsi::algorithm_descriptor::flags2_kadf_c_mask);
|
||||
REQUIRE((algo1.flags2 & scsi::algorithm_descriptor::flags2_vcelb_c_mask) ==
|
||||
scsi::algorithm_descriptor::flags2_vcelb_c_mask);
|
||||
REQUIRE((algo1.flags2 & scsi::algorithm_descriptor::flags2_ukadf_mask) ==
|
||||
std::byte {});
|
||||
REQUIRE((algo1.flags2 & scsi::algorithm_descriptor::flags2_akadf_mask) ==
|
||||
std::byte {});
|
||||
|
||||
REQUIRE(ntohs(algo1.maximum_ukad_length) == 32u);
|
||||
REQUIRE(ntohs(algo1.maximum_akad_length) == 60u);
|
||||
REQUIRE(ntohs(algo1.key_length) == 32u);
|
||||
|
||||
REQUIRE((algo1.flags3 & scsi::algorithm_descriptor::flags3_dkad_c_mask) ==
|
||||
std::byte {3u} << scsi::algorithm_descriptor::flags3_dkad_c_pos);
|
||||
REQUIRE((algo1.flags3 & scsi::algorithm_descriptor::flags3_eemc_c_mask) ==
|
||||
std::byte {2u} << scsi::algorithm_descriptor::flags3_eemc_c_pos);
|
||||
REQUIRE((algo1.flags3 & scsi::algorithm_descriptor::flags3_rdmc_c_mask) ==
|
||||
std::byte {6u} << scsi::algorithm_descriptor::flags3_rdmc_c_pos);
|
||||
REQUIRE((algo1.flags3 & scsi::algorithm_descriptor::flags3_earem_mask) ==
|
||||
scsi::algorithm_descriptor::flags3_earem_mask);
|
||||
|
||||
REQUIRE((algo1.maximum_eedk_count &
|
||||
scsi::algorithm_descriptor::maximum_eedk_count_mask) == 0u);
|
||||
REQUIRE(ntohs(algo1.msdk_count) == 0u);
|
||||
REQUIRE(ntohs(algo1.maximum_eedk_size) == 0u);
|
||||
REQUIRE(ntohl(algo1.security_algorithm_code) == 0x00010014u);
|
||||
|
||||
const scsi::algorithm_descriptor& algo2 = algorithms[1];
|
||||
REQUIRE(algo2.algorithm_index == 2u);
|
||||
REQUIRE(ntohs(algo2.length) == 20u);
|
||||
REQUIRE((algo2.flags1 & scsi::algorithm_descriptor::flags1_avfmv_mask) ==
|
||||
scsi::algorithm_descriptor::flags1_avfmv_mask);
|
||||
REQUIRE((algo2.flags1 & scsi::algorithm_descriptor::flags1_sdk_c_mask) ==
|
||||
std::byte {});
|
||||
REQUIRE((algo2.flags1 & scsi::algorithm_descriptor::flags1_mac_c_mask) ==
|
||||
std::byte {});
|
||||
REQUIRE((algo2.flags1 & scsi::algorithm_descriptor::flags1_delb_c_mask) ==
|
||||
std::byte {});
|
||||
REQUIRE((algo2.flags1 & scsi::algorithm_descriptor::flags1_decrypt_c_mask) ==
|
||||
std::byte {2u} << scsi::algorithm_descriptor::flags1_decrypt_c_pos);
|
||||
REQUIRE((algo2.flags1 & scsi::algorithm_descriptor::flags1_encrypt_c_mask) ==
|
||||
std::byte {2u} << scsi::algorithm_descriptor::flags1_encrypt_c_pos);
|
||||
|
||||
REQUIRE((algo2.flags2 & scsi::algorithm_descriptor::flags2_avfcp_mask) ==
|
||||
std::byte {2u} << scsi::algorithm_descriptor::flags2_avfcp_pos);
|
||||
REQUIRE((algo2.flags2 & scsi::algorithm_descriptor::flags2_nonce_mask) ==
|
||||
std::byte {});
|
||||
REQUIRE((algo2.flags2 & scsi::algorithm_descriptor::flags2_kadf_c_mask) ==
|
||||
scsi::algorithm_descriptor::flags2_kadf_c_mask);
|
||||
REQUIRE((algo2.flags2 & scsi::algorithm_descriptor::flags2_vcelb_c_mask) ==
|
||||
scsi::algorithm_descriptor::flags2_vcelb_c_mask);
|
||||
REQUIRE((algo2.flags2 & scsi::algorithm_descriptor::flags2_ukadf_mask) ==
|
||||
scsi::algorithm_descriptor::flags2_ukadf_mask);
|
||||
REQUIRE((algo2.flags2 & scsi::algorithm_descriptor::flags2_akadf_mask) ==
|
||||
scsi::algorithm_descriptor::flags2_akadf_mask);
|
||||
|
||||
REQUIRE(ntohs(algo2.maximum_ukad_length) == 32u);
|
||||
REQUIRE(ntohs(algo2.maximum_akad_length) == 60u);
|
||||
REQUIRE(ntohs(algo2.key_length) == 32u);
|
||||
|
||||
REQUIRE((algo2.flags3 & scsi::algorithm_descriptor::flags3_dkad_c_mask) ==
|
||||
std::byte {3u} << scsi::algorithm_descriptor::flags3_dkad_c_pos);
|
||||
REQUIRE((algo2.flags3 & scsi::algorithm_descriptor::flags3_eemc_c_mask) ==
|
||||
std::byte {1u} << scsi::algorithm_descriptor::flags3_eemc_c_pos);
|
||||
REQUIRE((algo2.flags3 & scsi::algorithm_descriptor::flags3_rdmc_c_mask) ==
|
||||
std::byte {4u} << scsi::algorithm_descriptor::flags3_rdmc_c_pos);
|
||||
REQUIRE((algo2.flags3 & scsi::algorithm_descriptor::flags3_earem_mask) ==
|
||||
scsi::algorithm_descriptor::flags3_earem_mask);
|
||||
|
||||
REQUIRE((algo2.maximum_eedk_count &
|
||||
scsi::algorithm_descriptor::maximum_eedk_count_mask) == 0u);
|
||||
REQUIRE(ntohs(algo2.msdk_count) == 0u);
|
||||
REQUIRE(ntohs(algo2.maximum_eedk_size) == 0u);
|
||||
REQUIRE(ntohl(algo2.security_algorithm_code) == 0x00010010u);
|
||||
}
|
||||
Reference in New Issue
Block a user