pax_global_header00006660000000000000000000000064150402704140014507gustar00rootroot0000000000000052 comment=704b5dd7dd0be93390e35b286bbf4af0b24c9ff4 scsitape-stenc-704b5dd/000077500000000000000000000000001504027041400150475ustar00rootroot00000000000000scsitape-stenc-704b5dd/.clang-format000066400000000000000000000104131504027041400174210ustar00rootroot00000000000000# 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 ... scsitape-stenc-704b5dd/.github/000077500000000000000000000000001504027041400164075ustar00rootroot00000000000000scsitape-stenc-704b5dd/.github/workflows/000077500000000000000000000000001504027041400204445ustar00rootroot00000000000000scsitape-stenc-704b5dd/.github/workflows/c-cpp.yml000066400000000000000000000011241504027041400221670ustar00rootroot00000000000000# 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 scsitape-stenc-704b5dd/.github/workflows/codeql.yml000066400000000000000000000020451504027041400224370ustar00rootroot00000000000000# 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}}" scsitape-stenc-704b5dd/.gitignore000066400000000000000000000017441504027041400170450ustar00rootroot00000000000000# SPDX-FileCopyrightText: 2022 stenc authors # # SPDX-License-Identifier: CC0-1.0 # Tempfiles *~ # Prerequisites *.d # Compiled Object files *.slo *.lo *.o *.obj # Precompiled Headers *.gch *.pch # Compiled Dynamic libraries *.so *.dylib *.dll # Compiled Static libraries *.lai *.la *.a *.lib # Executables *.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 scsitape-stenc-704b5dd/AUTHORS.md000066400000000000000000000004641504027041400165220ustar00rootroot00000000000000 stenc AUTHORS ============= The authors of stenc are * John Coleman * Samuel Martinez Jr. * Jonas Stein * James Wilson scsitape-stenc-704b5dd/CONTRIBUTING.md000066400000000000000000000003761504027041400173060ustar00rootroot00000000000000 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. scsitape-stenc-704b5dd/ChangeLog000066400000000000000000000163661504027041400166350ustar00rootroot000000000000002025-07-24 Jonas Stein * Version upgraded to 2.0.1 * Fix typo in configure. Superflous ] 2023-05-14 Jonas Stein * Version upgraded to 2.0.0 * define C++17 as minimal C++ version * build manpage with pandoc * Add license information according to the SPDX standard * Dropped AIX support. If you can test and develop code for AIX, please contact us. * Added bash completion * New syntax * Added missing includes * Special thanks to James Wilson, Paweł Marciniak, Christian Reiss and Alvaro Muñoz 2022-04-25 Jonas Stein * 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 * Version upgraded to 1.1.0 * Code cleanup * Use /dev/random to create a key 2020-06-16 Jonas Stein * Version upgraded to 1.0.8 * Merged patches to fix make files and provide more error messages 2018-02-13 Jonas Stein * Merged patches from various sources * move from SF to github in cooperation with John Coleman 2017-11-20 Adam Nielsen * Add patch which fixes double free bug (import from upstream git) 2017-11-19 Denys Berkovskyy * Add patches which enable compilation of stenc on kfreebsd architecture. The changes include addition of FreeBSD detection to configure.ac and modification of source code to use FreeBSD specific includes. * Bump standards version to 4.1.1. Switch to the https form of the copyright-format URL in the Format field of debian/copyright file. * Add patches to fix lintian warnings (fix typo in manpage and rename configure.in to configure.ac) * Add patch to fix inclusion of standard headers on non-linux systems (Closes: Debian bug 881781) 2014-01-06 John Coleman * Version upgraded to 1.0.7 * Included unistd.h in scsiencrypt.cpp to prevent compile issue on ArchLinux per report by fukawi2@gmail.com * Remove the --enable-swapbit and modified code to use the BYTE_ORDER and__BYTE_ORDER macros * -kd argument added to specify a uKAD via command line * -k option now required to set the output key file when using the -g option * status is now simplified, --detail argument added to restore previous behavior * the program now sets the umask when creating a new key file to prevent other users from being able to read it * Some devices will issue an I/O error on the first command sent to the device after a tape is inserted. Modified the program to retry 1 time if the first command fails. 2012-02-29 John Coleman * Version upgraded to 1.0.6 * The --protect option now should work properly and the --unprotect option has been added. If you specify neither, the drive will use it's default. * Sense data now always returns properly * Fixed a number of problems related to bit ordering in structures * Added the --enable-swapbit configure option to fix problems on AIX with the bit ordering being reversed in the structures. The program will now error out if it detects the program was compiled with the wrong option. * Added the --with-default-algorithm configure option to specify a default algorithm, so you don't have to do it with each set operation * Added the --with-default-ceem configure option in order to specify a different CEEM flag other than the drive default. * Added the --disable-device-name-conversion configure option to prevent the program from converting device names to rewinding device names * Added the --with-default-keysize configure option to specify the keysize to send to the drive when turning encryption off 2012-02-24 John Coleman * Version upgraded to 1.0.5 * Updated manual to reflect that stenc may not work if there is no tape in the device * Updated manual to reflect that keys are no longer padded * The program will now seek up to 100 blocks on the tape drive in order to determine the volume encryption status. The tape will be returned to the previous position after the status is returned. * The program now automatically converts /dev/st* device names to /dev/nst* and /dev/rmt* device names to /dev/rmt*.1 to prevent rewinding. * Updated --with-static-libgcc configure option to work on AIX 2012-02-22 John Coleman * Version upgraded to 1.0.4 * Fixed a compliler warning related to the seeding the random generator * Change the --with-statgcc configure option to --with-static-libgcc and modified that option to work with linux as well as AIX * Cleaned up various constants for consistancy * Changed some function names for consistancy * Added code to read KAD (Key Descriptors) and display them if found * Generating a key with -g now asks for a key description as well (optional) * Setting encryption without the -k option will now ask for a key description as well (optional) * Sense data is now checked and outputted if the device does not accept the command * added the 'mixed' encryption mode * added the 'rawread' encryption mode * changed the -u flag to --protect to avoid confusion and correct a mistake * added the --ckod flag to instruct the drive to clear its key when the volume is dismounted * The program now chmods /var/log/stenc to 600 to prevent unauthorized users from getting key change history * Algorithm is no longer put into /var/log/stenc. Security related. * Key checksums are now overriden by the key descriptor in /var/log/stenc. Security related. 2012-02-16 John Coleman * Version upgraded to 1.0.3 * Program now validates key input properly * Key checksums work much better * Program now displays key size, key checksum, and whether or not it is padding a key when it is entered. * Manual entry has been updated 2012-02-15 John Coleman * Version upgraded to 1.0.2 * Created 'man' entry for stenc and updated help file to reference manual * Key Instance Counter is now stamped into the log file when turning off encryption * Key Instance Counter is now displayed in the device status even when it is not encrypting 2012-02-15 Sam Martinez * Version upgraded to 1.0.1 * Added random key generator 2012-02-14 John Coleman * Version upgraded to 1.0.0 * Removed most C code and replaced with C++ code * Simplified all command line arguments * Added a key change audit log file (/var/log/stenc) * Removed the ability to enter a key as part of the command (security related) * Key entry is now hidden from stdout and is verified for accuracy * Added the ability to use file for a key using the -k option * Program now exits if you aren't root * added the --with-statgcc configure option to link static libgcc libraries 2010-09-03 John Coleman * Program now prompts if you turn encryption completely off * Added -f option to suppress prompting * Program now displays proper ioctl errors (i.e. I/O, permission, etc.) * Device vendor, product ID, and product revision are now displayed with each request * Errors now properly display whether or not the device accepted the command 2010-09-02 John Coleman * Initial Release * Added basic support for AIX 5.3, error codes still not outputted scsitape-stenc-704b5dd/ChangeLog.license000066400000000000000000000001261504027041400202410ustar00rootroot00000000000000SPDX-FileCopyrightText: 2022 stenc authors SPDX-License-Identifier: GPL-2.0-or-later scsitape-stenc-704b5dd/INSTALL000066400000000000000000000221121504027041400160760ustar00rootroot00000000000000Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. This file is free documentation; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. Basic Installation ================== These are generic installation instructions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). It can also use an optional file (typically called `config.cache' and enabled with `--cache-file=config.cache' or simply `-C') that saves the results of its tests to speed up reconfiguring. (Caching is disabled by default to prevent problems with accidental use of stale cache files.) If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If you are using the cache, and at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.ac' (or `configure.in') is used to create `configure' by a program called `autoconf'. You only need `configure.ac' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. If you're using `csh' on an old version of System V, you might need to type `sh ./configure' instead to prevent `csh' from trying to execute `configure' itself. Running `configure' takes awhile. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package. 4. Type `make install' to install the programs and any data files and documentation. 5. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. Run `./configure --help' for details on some of the pertinent environment variables. You can give `configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix *Note Defining Variables::, for more details. Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you must use a version of `make' that supports the `VPATH' variable, such as GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. If you have to use a `make' that does not support the `VPATH' variable, you have to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. Installation Names ================== By default, `make install' will install the package's files in `/usr/local/bin', `/usr/local/man', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PATH'. On AIX, this should probably be set to '/usr' You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you give `configure' the option `--exec-prefix=PATH', the package will use PATH as the prefix for installing programs and libraries. Documentation and other data files will still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=PATH' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Optional Features ================= Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Specifying the System Type ========================== There may be some features `configure' cannot figure out automatically, but needs to determine by the type of machine the package will run on. Usually, assuming the package is built to be run on the _same_ architectures, `configure' can figure that out, but if it prints a message saying it cannot guess the machine type, give it the `--build=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name which has the form: CPU-COMPANY-SYSTEM where SYSTEM can have one of these forms: OS KERNEL-OS See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the machine type. If you are _building_ compiler tools for cross-compiling, you should use the `--target=TYPE' option to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a platform different from the build platform, you should specify the "host" platform (i.e., that on which the generated programs will eventually be run) with `--host=TYPE'. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Defining Variables ================== Variables not defined in a site shell script can be set in the environment passed to `configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set them in the `configure' command line, using `VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc will cause the specified gcc to be used as the C compiler (unless it is overridden in the site shell script). `configure' Invocation ====================== `configure' recognizes the following options to control how it operates. `--help' `-h' Print a summary of the options to `configure', and exit. `--version' `-V' Print the version of Autoconf used to generate the `configure' script, and exit. `--cache-file=FILE' Enable the cache: use and save the results of the tests in FILE, traditionally `config.cache'. FILE defaults to `/dev/null' to disable caching. `--config-cache' `-C' Alias for `--cache-file=config.cache'. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `configure' also accepts some other, not widely useful, options. Run `configure --help' for more details. scsitape-stenc-704b5dd/INSTALL.license000066400000000000000000000001361504027041400175210ustar00rootroot00000000000000SPDX-FileCopyrightText: 1994 Free Software Foundation, Inc. SPDX-License-Identifier: CC0-1.0 scsitape-stenc-704b5dd/LICENSES/000077500000000000000000000000001504027041400162545ustar00rootroot00000000000000scsitape-stenc-704b5dd/LICENSES/BSL-1.0.txt000066400000000000000000000024721504027041400177360ustar00rootroot00000000000000Boost 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. scsitape-stenc-704b5dd/LICENSES/CC0-1.0.txt000066400000000000000000000156101504027041400176610ustar00rootroot00000000000000Creative 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. scsitape-stenc-704b5dd/LICENSES/GPL-2.0-or-later.txt000066400000000000000000000416711504027041400214700ustar00rootroot00000000000000GNU 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 scsitape-stenc-704b5dd/Makefile.am000066400000000000000000000002241504027041400171010ustar00rootroot00000000000000# SPDX-FileCopyrightText: 2022 stenc authors # # SPDX-License-Identifier: CC0-1.0 SUBDIRS = src man tests bash-completion # EXTRA_DIST = buildconf scsitape-stenc-704b5dd/README.md000066400000000000000000000050431504027041400163300ustar00rootroot00000000000000 [![REUSE status](https://api.reuse.software/badge/github.com/scsitape/stenc/)](https://api.reuse.software/info/github.com/scsitape/stenc/) Stenc ----- 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 Linux and FreeBSD * Supports most SSP compliant devices, such as LTO-4 tape drives * Key change audit logging * AES Encryption * Key Descriptor Management Get the source code and compile ------------------------------- ``` git clone https://github.com/scsitape/stenc.git cd stenc/ autoreconf --install ./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 -------------- [![Packaging status](https://repology.org/badge/vertical-allrepos/stenc.svg)](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-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 the Free Software Foundation; version 2 of the License. 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. 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 scsitape-stenc-704b5dd/autogen.sh000077500000000000000000000002061504027041400170460ustar00rootroot00000000000000#!/bin/sh # SPDX-FileCopyrightText: 2022 stenc authors # # SPDX-License-Identifier: GPL-2.0-or-later autoreconf --install || exit 1 scsitape-stenc-704b5dd/bash-completion/000077500000000000000000000000001504027041400201335ustar00rootroot00000000000000scsitape-stenc-704b5dd/bash-completion/Makefile.am000066400000000000000000000002771504027041400221750ustar00rootroot00000000000000# SPDX-FileCopyrightText: 2022 stenc authors # # SPDX-License-Identifier: CC0-1.0 if ENABLE_BASH_COMPLETION bashcompletiondir = $(BASH_COMPLETION_DIR) dist_bashcompletion_DATA = stenc endif scsitape-stenc-704b5dd/bash-completion/stenc000066400000000000000000000023341504027041400211740ustar00rootroot00000000000000#/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 scsitape-stenc-704b5dd/configure.ac000066400000000000000000000036001504027041400173340ustar00rootroot00000000000000# SPDX-FileCopyrightText: 2022 stenc authors # SPDX-License-Identifier: GPL-2.0-or-later AC_INIT([stenc],[2.0.1]) 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 AC_MSG_CHECKING(whether to output raw SCSI messages) AC_ARG_WITH([scsi-debug], [AS_HELP_STRING([--with-scsi-debug],[enable scsi communication debug])], [AC_DEFINE([DEBUGSCSI],[1],[Define if you want to debug SCSI Communication]) AC_MSG_RESULT(yes)], [AC_MSG_RESULT(no)]) AC_MSG_CHECKING(your OS) system=`uname` case $system in Linux) AC_DEFINE(OS_LINUX,1,"") AC_MSG_RESULT(Linux) ;; FreeBSD) AC_DEFINE(OS_FREEBSD,1,"") AC_MSG_RESULT(FreeBSD) ;; *) AC_MSG_ERROR(unknown OS type: $system) ;; esac AC_MSG_CHECKING(whether to build with static libgcc) AC_ARG_WITH([static-libgcc], [AS_HELP_STRING([--with-static-libgcc],[build with static libgcc library])], [ AC_MSG_RESULT(yes) LDFLAGS="${LDFLAGS} -static-libgcc -Wl,-static -lstdc++ -lsupc++" ], [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.])]) 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_CONFIG_FILES([Makefile src/Makefile man/Makefile tests/Makefile bash-completion/Makefile]) AC_OUTPUT scsitape-stenc-704b5dd/man/000077500000000000000000000000001504027041400156225ustar00rootroot00000000000000scsitape-stenc-704b5dd/man/Makefile.am000066400000000000000000000004021504027041400176520ustar00rootroot00000000000000# 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 scsitape-stenc-704b5dd/man/stenc.rst000066400000000000000000000163031504027041400174730ustar00rootroot00000000000000.. 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 . 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) scsitape-stenc-704b5dd/src/000077500000000000000000000000001504027041400156365ustar00rootroot00000000000000scsitape-stenc-704b5dd/src/Makefile.am000066400000000000000000000003631504027041400176740ustar00rootroot00000000000000# SPDX-FileCopyrightText: 2022 stenc authors # # SPDX-License-Identifier: CC0-1.0 bin_PROGRAMS = stenc AM_CXXFLAGS = -std=c++17 $(INTI_CFLAGS) $(DEPS_CFLAGS) stenc_SOURCES = main.cpp scsiencrypt.cpp scsiencrypt.h #stenc_LDADD = $(INTI_LIBS) scsitape-stenc-704b5dd/src/main.cpp000066400000000000000000000625441504027041400173010ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 stenc authors // // SPDX-License-Identifier: GPL-2.0-or-later /* stenc - program to set and retrieve hardware based encryption options from certain SCSI devices (i.e. LTO4 Tape drives) Original program copyright 2010 John D. Coleman 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; version 2 of the License. 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if HAVE_ARPA_INET_H #include #endif #if HAVE_NETINET_IN_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #include "scsiencrypt.h" using namespace std::literals::string_literals; static const auto column_width {std::setw(33)}; static std::optional> key_from_hex_chars(const std::string& s) { auto it = s.data(); std::vector bytes; if (s.size() % 2) { // treated as if there is an implicit leading 0 std::uint8_t result; auto [ptr, ec] {std::from_chars(it, it + 1, result, 16)}; if (ec != std::errc {}) { return {}; } bytes.push_back(result); it = ptr; } while (*it) { std::uint8_t result; auto [ptr, ec] {std::from_chars(it, it + 2, result, 16)}; if (ec != std::errc {}) { return {}; } bytes.push_back(result); it = ptr; } return bytes; } // shows the command usage static void print_usage(std::ostream& os) { os << "\ Usage: stenc [OPTION...]\n\ \n\ Mandatory arguments to long options are mandatory for short options too.\n\ -f, --file=DEVICE use DEVICE as the tape drive to operate on\n\ -e, --encrypt=ENC-MODE set encryption mode to ENC-MODE\n\ -d, --decrypt=DEC-MODE set decryption mode to DEC-MODE\n\ -k, --key-file=FILE read encryption key and key descriptor from FILE,\n\ or standard input when FILE is -\n\ -a, --algorithm=INDEX use encryption algorithm INDEX\n\ --allow-raw-read mark written blocks to allow raw reads of\n\ encrypted data\n\ --no-allow-raw-read mark written blocks to disallow raw reads of\n\ encrypted data\n\ --ckod clear key on demount of tape media\n\ -h, --help print this usage statement and exit\n\ --version print version information and exit\n\ \n\ ENC-MODE is one of the following:\n\ off Data written to DEVICE will not be encrypted\n\ on Data written to DEVICE will be encrypted\n\ \n\ DEC-MODE is one of the following:\n\ off Data read from DEVICE will not be decrypted and only unencrypted\n\ records can be read.\n\ on Data read from DEVICE will be decrypted and only encrypted records\n\ can be read.\n\ mixed Data read from DEVICE will be decrypted, if needed. Both encrypted\n\ and unencrypted records can be read.\n\ \n\ INDEX is a number that selects the encryption algorithm and mode to use.\n\ \n\ When neither options to set encryption or decryption mode are given, print\n\ encryption status and capabilities of DEVICE, including a list of supported\n\ algorithm indexes.\n"; } static void print_algorithm_name(std::ostream& os, const std::uint32_t code) { auto fill {os.fill('0')}; auto flags {os.flags(std::ios_base::hex | std::ios_base::right)}; // Reference: SFSC / INCITS 501-2016 if (0x80010400 <= code && code <= 0x8001FFFF) { os << "Vendor specific 0x" << std::setw(8) << code; } switch (code) { case 0x0001000C: os << "AES-256-CBC-HMAC-SHA-1"; break; case 0x00010010: os << "AES-256-CCM-128"; break; case 0x00010014: os << "AES-256-GCM-128"; break; case 0x00010016: os << "AES-256-XTS-HMAC-SHA-512"; break; default: os << "Unknown 0x" << std::setw(8) << code; } os.flags(flags); os.fill(fill); } static void print_algorithms( std::ostream& os, const std::vector>& ads) { os << "Supported algorithms:\n"; for (const scsi::algorithm_descriptor& ad: ads) { os << std::left << std::setw(5) << static_cast(ad.algorithm_index); print_algorithm_name(os, ntohl(ad.security_algorithm_code)); os.put('\n'); // Print KAD capabilities and size auto dkad_c {static_cast( ad.flags3 & scsi::algorithm_descriptor::flags3_dkad_c_mask)}; if (dkad_c == 2u << scsi::algorithm_descriptor::flags3_dkad_c_pos) { os << std::left << std::setw(5) << "" << "Key descriptors not allowed\n"; } else if (dkad_c) { os << std::left << std::setw(5) << ""; if (dkad_c == 1u << scsi::algorithm_descriptor::flags3_dkad_c_pos) { os << "Key descriptors required, "; } else { os << "Key descriptors allowed, "; } if ((ad.flags2 & scsi::algorithm_descriptor::flags2_ukadf_mask) == scsi::algorithm_descriptor::flags2_ukadf_mask) { os << "fixed "; } else { os << "maximum "; } os << std::dec << ntohs(ad.maximum_ukad_length) << " bytes\n"; } // Print raw decryption mode capability: auto rdmc_c {static_cast( ad.flags3 & scsi::algorithm_descriptor::flags3_rdmc_c_mask)}; switch (rdmc_c) { case 1u << scsi::algorithm_descriptor::flags3_rdmc_c_pos: case 6u << scsi::algorithm_descriptor::flags3_rdmc_c_pos: os << std::left << std::setw(5) << ""; os << "Raw decryption mode not allowed\n"; break; case 4u << scsi::algorithm_descriptor::flags3_rdmc_c_pos: case 5u << scsi::algorithm_descriptor::flags3_rdmc_c_pos: case 7u << scsi::algorithm_descriptor::flags3_rdmc_c_pos: os << std::left << std::setw(5) << ""; os << "Raw decryption mode allowed, raw read "; if (rdmc_c == 4u << scsi::algorithm_descriptor::flags3_rdmc_c_pos) { os << "disabled by default\n"; } else { os << "enabled by default\n"; } break; } } } template inline static void print_fixed_buffer(std::ostream& os, const std::array buffer) { // rtrim and print fixed length buffer auto end = std::find_if(buffer.rbegin(), buffer.rend(), [](char c) { return !std::isspace(c); }).base(); std::for_each(buffer.begin(), end, [&](char c) { os.put(c); }); } static void print_device_inquiry(std::ostream& os, const scsi::inquiry_data& iresult) { print_fixed_buffer(os, iresult.vendor); os.put(' '); print_fixed_buffer(os, iresult.product_id); os.put(' '); print_fixed_buffer(os, iresult.product_rev); } static void print_device_status(std::ostream& os, const scsi::page_des& opt, const std::map& algorithms) { os << std::left << column_width << "Reading:"; switch (opt.decryption_mode) { case scsi::decrypt_mode::off: case scsi::decrypt_mode::raw: os << "Not decrypting\n"; break; case scsi::decrypt_mode::on: case scsi::decrypt_mode::mixed: os << "Decrypting ("; if (algorithms.find(opt.algorithm_index) != algorithms.end()) { os << algorithms.at(opt.algorithm_index); } else { os << "algorithm " << static_cast(opt.algorithm_index); } os << ")\n"; if (opt.decryption_mode == scsi::decrypt_mode::on) { os << column_width << ' ' << "Unencrypted blocks not readable\n"; } break; default: os << "Unknown '0x" << std::hex << static_cast(opt.decryption_mode) << "' \n"; break; } os << column_width << "Writing:"; switch (opt.encryption_mode) { case scsi::encrypt_mode::off: os << "Not encrypting\n"; break; case scsi::encrypt_mode::on: os << "Encrypting ("; if (algorithms.find(opt.algorithm_index) != algorithms.end()) { os << algorithms.at(opt.algorithm_index); } else { os << "algorithm " << static_cast(opt.algorithm_index); } os << ")\n"; break; default: os << "Unknown result '0x" << std::hex << static_cast(opt.encryption_mode) << "'\n"; break; } if ((opt.flags & scsi::page_des::flags_rdmd_mask) == scsi::page_des::flags_rdmd_mask) { os << column_width << ' ' << "Protecting from raw read\n"; } os << column_width << "Key instance counter:" << std::dec << ntohl(opt.key_instance_counter) << '\n'; for (const scsi::kad& kd: scsi::read_page_kads(opt)) { if (kd.type == scsi::kad_type::ukad) { os << column_width << "Drive key desc. (U-KAD):"; os.write(reinterpret_cast(kd.descriptor), ntohs(kd.length)); os.put('\n'); } else if (kd.type == scsi::kad_type::akad) { os << column_width << "Drive key desc. (A-KAD):"; os.write(reinterpret_cast(kd.descriptor), ntohs(kd.length)); os.put('\n'); } } } static void print_block_status(std::ostream& os, const scsi::page_nbes& opt, const std::map& algorithms) { os << std::left << column_width << "Current block status:"; auto encryption_status {static_cast( opt.status & scsi::page_nbes::status_encryption_mask)}; switch (encryption_status) { case 0u << scsi::page_nbes::status_encryption_pos: case 1u << scsi::page_nbes::status_encryption_pos: os << "Unable to determine\n"; break; case 2u << scsi::page_nbes::status_encryption_pos: os << "Tape position not at a logical block\n"; break; case 3u << scsi::page_nbes::status_encryption_pos: os << "Not encrypted\n"; break; case 5u << scsi::page_nbes::status_encryption_pos: os << "Encrypted and able to decrypt ("; if (algorithms.find(opt.algorithm_index) != algorithms.end()) { os << algorithms.at(opt.algorithm_index); } else { os << "algorithm " << static_cast(opt.algorithm_index); } os << ")\n"; if ((opt.flags & scsi::page_nbes::flags_rdmds_mask) == scsi::page_nbes::flags_rdmds_mask) { os << std::left << column_width << ' ' << "Protected from raw read\n"; } break; case 6u << scsi::page_nbes::status_encryption_pos: os << "Encrypted, key missing or invalid ("; if (algorithms.find(opt.algorithm_index) != algorithms.end()) { os << algorithms.at(opt.algorithm_index); } else { os << "algorithm " << static_cast(opt.algorithm_index); } os << ")\n"; if ((opt.flags & scsi::page_nbes::flags_rdmds_mask) == scsi::page_nbes::flags_rdmds_mask) { os << std::left << column_width << ' ' << "Protected from raw read\n"; } for (const scsi::kad& kd: read_page_kads(opt)) { if (kd.type == scsi::kad_type::ukad) { os << column_width << "Current block key desc. (U-KAD):"; os.write(reinterpret_cast(kd.descriptor), ntohs(kd.length)); os.put('\n'); } else if (kd.type == scsi::kad_type::akad) { os << column_width << "Current block key desc. (A-KAD):"; os.write(reinterpret_cast(kd.descriptor), ntohs(kd.length)); os.put('\n'); } } break; default: os << "Unknown result '" << std::hex << static_cast(encryption_status) << "'\n"; break; } } static void echo(bool on) { struct termios settings {}; tcgetattr(STDIN_FILENO, &settings); settings.c_lflag = on ? (settings.c_lflag | ECHO) : (settings.c_lflag & ~(ECHO)); tcsetattr(STDIN_FILENO, TCSANOW, &settings); } #if !defined(CATCH_CONFIG_MAIN) int main(int argc, char **argv) { std::string tapeDrive; std::string keyFile; std::optional enc_mode; std::optional dec_mode; std::optional algorithm_index; std::vector key; std::string key_name; scsi::sde_rdmc rdmc {}; scsi::kadf kad_format {}; bool ckod {}; alignas(4) scsi::page_buffer buffer {}; enum opt_key : int { opt_version = 256, opt_ckod, opt_rdmc_enable, opt_rdmc_disable, }; const struct option long_options[] = { {"algorithm", required_argument, nullptr, 'a'}, {"decrypt", required_argument, nullptr, 'd'}, {"encrypt", required_argument, nullptr, 'e'}, {"file", required_argument, nullptr, 'f'}, {"key-file", required_argument, nullptr, 'k'}, {"help", no_argument, nullptr, 'h'}, {"ckod", no_argument, nullptr, opt_ckod}, {"allow-raw-read", no_argument, nullptr, opt_rdmc_enable}, {"no-allow-raw-read", no_argument, nullptr, opt_rdmc_disable}, {"version", no_argument, nullptr, opt_version}, {nullptr, 0, nullptr, 0}, }; int opt_char; while ((opt_char = getopt_long(argc, argv, "+a:d:e:f:k:h", long_options, nullptr)) != -1) { switch (opt_char) { case 'a': { char *endptr; auto conv_result {std::strtoul(optarg, &endptr, 10)}; if (errno || *endptr || conv_result > std::numeric_limits< decltype(algorithm_index)::value_type>::max()) { std::cerr << "stenc: Algorithm index " << optarg << " out of range\n"; std::exit(EXIT_FAILURE); } algorithm_index = conv_result; } break; case 'd': { std::string arg {optarg}; if (arg == "on"s) { dec_mode = scsi::decrypt_mode::on; } else if (arg == "off"s) { dec_mode = scsi::decrypt_mode::off; } else if (arg == "mixed"s) { dec_mode = scsi::decrypt_mode::mixed; } else { print_usage(std::cerr); std::exit(EXIT_FAILURE); } } break; case 'e': { std::string arg {optarg}; if (arg == "on"s) { enc_mode = scsi::encrypt_mode::on; } else if (arg == "off"s) { enc_mode = scsi::encrypt_mode::off; } else { print_usage(std::cerr); std::exit(EXIT_FAILURE); } } break; case 'f': tapeDrive = optarg; break; case 'k': keyFile = optarg; break; case opt_ckod: ckod = true; break; case opt_rdmc_enable: rdmc = scsi::sde_rdmc::enabled; break; case opt_rdmc_disable: rdmc = scsi::sde_rdmc::disabled; break; case 'h': print_usage(std::cout); std::exit(EXIT_SUCCESS); case opt_version: std::cout << "stenc " VERSION " - SCSI Tape Encryption Manager\n" << "https://github.com/scsitape/stenc\n"; std::exit(EXIT_SUCCESS); default: print_usage(std::cerr); std::exit(EXIT_FAILURE); } } if (optind != argc) { // left-over unparsed arguments or options print_usage(std::cerr); std::exit(EXIT_FAILURE); } // select device from env variable or system default if not given with -f if (tapeDrive.empty()) { const char *env_tape = getenv("TAPE"); if (env_tape != nullptr) { tapeDrive = env_tape; } else { tapeDrive = DEFTAPE; } } openlog("stenc", LOG_CONS, LOG_USER); if (!enc_mode && !dec_mode) { try { auto inquiry_data {scsi::get_inquiry(tapeDrive)}; std::cout << "Status for " << tapeDrive << " ("; print_device_inquiry(std::cout, inquiry_data); std::cout << ")\n--------------------------------------------------\n"; // Build map of algorithm index -> algorithm name auto ads {scsi::read_algorithms( scsi::get_dec(tapeDrive, buffer, sizeof(buffer)))}; std::map algo_names; std::for_each(ads.begin(), ads.end(), [&algo_names](const scsi::algorithm_descriptor& ad) { std::ostringstream oss; print_algorithm_name(oss, ntohl(ad.security_algorithm_code)); algo_names[ad.algorithm_index] = oss.str(); }); std::ostringstream oss; print_algorithms( oss, ads); // save output here since buffer will be overwritten print_device_status(std::cout, scsi::get_des(tapeDrive, buffer, sizeof(buffer)), algo_names); if (scsi::is_device_ready(tapeDrive)) { try { print_block_status(std::cout, scsi::get_nbes(tapeDrive, buffer, sizeof(buffer)), algo_names); } catch (const scsi::scsi_error& err) { // #71: ignore BLANK CHECK sense key that some drives may return // during media access check in getting NBES auto sense_key {err.get_sense().flags & scsi::sense_data::flags_sense_key_mask}; if (sense_key != scsi::sense_data::blank_check) { throw; } } } std::cout << oss.str(); std::exit(EXIT_SUCCESS); } catch (const scsi::scsi_error& err) { std::cerr << "stenc: " << err.what() << '\n'; scsi::print_sense_data(std::cerr, err.get_sense()); std::exit(EXIT_FAILURE); } catch (const std::runtime_error& err) { std::cerr << "stenc: " << err.what() << '\n'; std::exit(EXIT_FAILURE); } } // Infer encrypt/decrypt mode when only one is specified if (enc_mode && !dec_mode) { if (enc_mode == scsi::encrypt_mode::off) { dec_mode = scsi::decrypt_mode::off; std::cerr << "Decrypt mode not specified, using decrypt = off\n"; } else if (enc_mode == scsi::encrypt_mode::on) { dec_mode = scsi::decrypt_mode::on; std::cerr << "Decrypt mode not specified, using decrypt = on\n"; } else { std::cerr << "stenc: Unexpected encrypt mode " << static_cast(*enc_mode) << '\n'; std::exit(EXIT_FAILURE); } } else if (!enc_mode && dec_mode) { if (dec_mode == scsi::decrypt_mode::off) { enc_mode = scsi::encrypt_mode::off; std::cerr << "Encrypt mode not specified, using encrypt = off\n"; } else if (dec_mode == scsi::decrypt_mode::on || dec_mode == scsi::decrypt_mode::mixed) { enc_mode = scsi::encrypt_mode::on; std::cerr << "Encrypt mode not specified, using encrypt = on\n"; } else { std::cerr << "stenc: Unexpected decrypt mode " << static_cast(*dec_mode) << '\n'; std::exit(EXIT_FAILURE); } } if (enc_mode != scsi::encrypt_mode::off || dec_mode != scsi::decrypt_mode::off) { if (keyFile.empty()) { std::cerr << "stenc: Encryption key required but no key file specified\n"; std::exit(EXIT_FAILURE); } // set keyInput here std::string keyInput; if (keyFile == "-"s) { // Read key file from standard input if (isatty(STDIN_FILENO)) { std::cout << "Enter key in hex format (input will be hidden): "; echo(false); } std::getline(std::cin, keyInput); if (isatty(STDIN_FILENO)) { std::cout << "\nEnter key descriptor (optional): "; echo(true); } std::getline(std::cin, key_name); } else { std::ifstream myfile {keyFile}; if (!myfile.is_open()) { std::cerr << "stenc: Cannot open " << keyFile << ": " << strerror(errno) << '\n'; std::exit(EXIT_FAILURE); } std::getline(myfile, keyInput); std::getline(myfile, key_name); } if (auto key_bytes = key_from_hex_chars(keyInput)) { key = *key_bytes; } else { std::cerr << "stenc: Invalid key in key file\n"; std::exit(EXIT_FAILURE); } } try { auto algorithms {scsi::read_algorithms( scsi::get_dec(tapeDrive, buffer, sizeof(buffer)))}; if (algorithm_index == std::nullopt) { if (algorithms.size() == 1) { // Pick the only available algorithm if not specified const scsi::algorithm_descriptor& ad = algorithms[0]; std::cerr << "Algorithm index not specified, using " << std::dec << static_cast(ad.algorithm_index) << " ("; print_algorithm_name(std::cerr, ntohl(ad.security_algorithm_code)); std::cerr << ")\n"; algorithm_index = ad.algorithm_index; } else { std::cerr << "stenc: Algorithm index not specified\n"; print_algorithms(std::cerr, algorithms); std::exit(EXIT_FAILURE); } } auto algo_it { std::find_if(algorithms.begin(), algorithms.end(), [algorithm_index](const scsi::algorithm_descriptor& ad) { return ad.algorithm_index == algorithm_index; })}; if (algo_it == algorithms.end()) { std::cerr << "stenc: Algorithm index " << std::dec << static_cast(*algorithm_index) << " not supported by device\n"; std::exit(EXIT_FAILURE); } const scsi::algorithm_descriptor& ad = *algo_it; auto encrypt_c {static_cast( ad.flags1 & scsi::algorithm_descriptor::flags1_encrypt_c_mask)}; if (enc_mode != scsi::encrypt_mode::off && encrypt_c != 2u << scsi::algorithm_descriptor::flags1_encrypt_c_pos) { std::cerr << "stenc: Device does not support encryption using algorithm index " << std::dec << static_cast(*algorithm_index) << '\n'; std::exit(EXIT_FAILURE); } auto decrypt_c {static_cast( ad.flags1 & scsi::algorithm_descriptor::flags1_decrypt_c_mask)}; if (dec_mode != scsi::decrypt_mode::off && decrypt_c != 2u << scsi::algorithm_descriptor::flags1_decrypt_c_pos) { std::cerr << "stenc: Device does not support decryption using algorithm index " << std::dec << static_cast(*algorithm_index) << '\n'; std::exit(EXIT_FAILURE); } if ((enc_mode != scsi::encrypt_mode::off || dec_mode != scsi::decrypt_mode::off) && key.size() != ntohs(ad.key_length)) { std::cerr << "stenc: Incorrect key size, expected " << std::dec << ntohs(ad.key_length) << " bytes, got " << key.size() << '\n'; std::exit(EXIT_FAILURE); } if (key_name.size() > ntohs(ad.maximum_ukad_length)) { std::cerr << "stenc: Key descriptor exceeds maximum length of " << std::dec << ntohs(ad.maximum_ukad_length) << " bytes\n"; std::exit(EXIT_FAILURE); } bool ukad_fixed = (ad.flags2 & scsi::algorithm_descriptor::flags2_ukadf_mask) == scsi::algorithm_descriptor::flags2_ukadf_mask; if (ukad_fixed && key_name.size() < ntohs(ad.maximum_ukad_length)) { // Pad key descriptor to required length key_name.resize(ntohs(ad.maximum_ukad_length), ' '); } if ((ad.flags2 & scsi::algorithm_descriptor::flags2_kadf_c_mask) == scsi::algorithm_descriptor::flags2_kadf_c_mask) { kad_format = scsi::kadf::ascii_key_name; // set KAD format field if allowed } if (enc_mode != scsi::encrypt_mode::on) { // key descriptor only valid when key is used for writing key_name.erase(); } if (rdmc != scsi::sde_rdmc {}) { auto rdmc_c {static_cast( ad.flags3 & scsi::algorithm_descriptor::flags3_rdmc_c_mask)}; if (rdmc_c == 6u << scsi::algorithm_descriptor::flags3_rdmc_c_pos || rdmc_c == 7u << scsi::algorithm_descriptor::flags3_rdmc_c_pos) { std::cerr << "stenc: Device does not allow control of raw reads\n"; std::exit(EXIT_FAILURE); } } if (ckod && !scsi::is_device_ready(tapeDrive)) { std::cerr << "stenc: Cannot use --ckod when no tape media is loaded\n"; std::exit(EXIT_FAILURE); } // Write the options to the tape device std::cerr << "Changing encryption settings for device " << tapeDrive << "...\n"; auto sde_buffer {scsi::make_sde(enc_mode.value(), dec_mode.value(), algorithm_index.value(), key, key_name, kad_format, rdmc, ckod)}; scsi::write_sde(tapeDrive, sde_buffer.get()); auto& opt {scsi::get_des(tapeDrive, buffer, sizeof(buffer))}; std::ostringstream oss; oss << "Encryption settings changed for device " << tapeDrive << ": mode: encrypt = " << enc_mode.value() << ", decrypt = " << dec_mode.value() << '.'; if (!key_name.empty()) { oss << " Key descriptor: '" << key_name << "',"; } oss << " Key instance counter: " << std::dec << ntohl(opt.key_instance_counter) << '\n'; syslog(LOG_NOTICE, "%s", oss.str().c_str()); std::cerr << "Success! See system logs for a key change audit log.\n"; } catch (const scsi::scsi_error& err) { std::cerr << "stenc: " << err.what() << '\n'; scsi::print_sense_data(std::cerr, err.get_sense()); std::exit(EXIT_FAILURE); } catch (const std::runtime_error& err) { std::cerr << "stenc: " << err.what() << '\n'; std::exit(EXIT_FAILURE); } } #endif // defined(CATCH_CONFIG_MAIN) scsitape-stenc-704b5dd/src/scsiencrypt.cpp000066400000000000000000000314631504027041400207170ustar00rootroot00000000000000// 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 Original program copyright 2010 John D. Coleman 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; version 2 of the License. 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #if defined(OS_LINUX) #include constexpr unsigned int SCSI_TIMEOUT {5000u}; #elif defined(OS_FREEBSD) #include #include constexpr unsigned int SCSI_TIMEOUT {5000u}; constexpr unsigned int RETRYCOUNT {1u}; #else #error "OS type is not set" #endif #include "scsiencrypt.h" 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 BSINTTOCHAR(x) \ static_cast((x) >> 24), static_cast((x) >> 16), \ static_cast((x) >> 8), static_cast((x)) // generic_deleter permits the use of std::unique_ptr for RAII on non-pointer // types like file descriptors. template 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; } }; void operator()(pointer p) const noexcept { d(p); } }; using unique_fd = std::unique_ptr>; enum class scsi_direction { to_device, from_device }; struct hex { std::uint8_t value; }; 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)}; os << std::setw(2) << static_cast(h.value); 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(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 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()}; } sg_io_hdr cmdio {}; auto sense_buf {std::make_unique()}; 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(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 { 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 { 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(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()}; 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(length), 0, 0, }; scsi_execute(device, spin_des_command, sizeof(spin_des_command), buffer, length, scsi_direction::from_device); auto& page {reinterpret_cast(*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(length), 0, 0, }; scsi_execute(device, spin_nbes_command, sizeof(spin_nbes_command), buffer, length, scsi_direction::from_device); auto& page {reinterpret_cast(*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_dec& get_dec(const std::string& device, std::uint8_t *buffer, std::size_t length) { 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(*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; } inquiry_data get_inquiry(const std::string& device) { 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(&inq), sizeof(inq), scsi_direction::from_device); #if defined(DEBUGSCSI) std::cerr << "SCSI Response: "; print_buffer(std::cerr, reinterpret_cast(&inq), std::min(sizeof(inquiry_data), inquiry_data::header_size + inq.additional_length)); #endif return inq; } std::unique_ptr make_sde(encrypt_mode enc_mode, decrypt_mode dec_mode, std::uint8_t algorithm_index, const std::vector& key, const std::string& key_name, kadf kad_format, sde_rdmc rdmc, bool ckod) { std::size_t length {sizeof(page_sde) + key.size()}; if (!key_name.empty()) { length += sizeof(kad) + key_name.size(); } auto buffer {std::make_unique(length)}; auto& page {reinterpret_cast(*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>(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( *(buffer.get() + sizeof(page_sde) + key.size()))}; ukad.length = htons(key_name.size()); std::memcpy(ukad.descriptor, key_name.data(), key_name.size()); } return buffer; } void write_sde(const std::string& device, const std::uint8_t *sde_buffer) { auto& page {reinterpret_cast(*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(length), 0, 0, }; scsi_execute(device, spout_sde_command, sizeof(spout_sde_command), const_cast(sde_buffer), length, scsi_direction::to_device); } void print_sense_data(std::ostream& os, const sense_data& sd) { os << std::left << std::setw(25) << "Sense Code: "; auto sense_key {sd.flags & sense_data::flags_sense_key_mask}; switch (sense_key) { case sense_data::no_sense: os << "No specific error"; break; case sense_data::recovered_error: os << "Recovered error"; break; 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(sense_key)} << ")\n"; os << std::left << std::setw(25) << " ASC:" << "0x" << hex {sd.additional_sense_code} << '\n'; os << std::left << std::setw(25) << " ASCQ:" << "0x" << hex {sd.additional_sense_qualifier} << '\n'; #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(&sd)}; os << std::left << std::setw(25) << " Raw sense data:"; print_buffer(os, rawsense, sense_data_length); #endif } std::vector> read_algorithms(const page_dec& page) { auto it {reinterpret_cast(&page.ads[0])}; const auto end {reinterpret_cast(&page) + ntohs(page.length) + sizeof(page_header)}; std::vector> v {}; while (it < end) { auto elem {reinterpret_cast(it)}; v.push_back(std::cref(*elem)); it += ntohs(elem->length) + algorithm_descriptor::header_size; } return v; } } // namespace scsi scsitape-stenc-704b5dd/src/scsiencrypt.h000066400000000000000000000371001504027041400203560ustar00rootroot00000000000000// 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 Original program copyright 2010 John D. Coleman 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; version 2 of the License. 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. */ #ifndef _SCSIENC_H #define _SCSIENC_H #include #include #include #include #include #include #include #include #include #include #include #if HAVE_ARPA_INET_H #include #endif #if HAVE_NETINET_IN_H #include #endif namespace scsi { 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; } 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 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 }; 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 vendor; std::array product_id; std::array 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; class scsi_error : public std::runtime_error { public: explicit scsi_error(std::unique_ptr&& buf) : std::runtime_error {"SCSI I/O error"}, sense_buf {std::move(buf)} {} const sense_data& get_sense() const { return reinterpret_cast(*sense_buf->data()); } private: std::unique_ptr sense_buf; }; // Extract pointers to kad structures within a variable-length page. // Page must have a page_header layout template std::vector> read_page_kads(const Page& page) { const auto start {reinterpret_cast(&page)}; auto it {start + sizeof(Page)}; const auto end {start + ntohs(page.length) + sizeof(page_header)}; std::vector> v {}; while (it < end) { auto elem {reinterpret_cast(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 make_sde(encrypt_mode enc_mode, decrypt_mode dec_mode, std::uint8_t algorithm_index, const std::vector& 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> read_algorithms(const page_dec& page); } // namespace scsi #endif scsitape-stenc-704b5dd/stenc.spec000066400000000000000000000020021504027041400170310ustar00rootroot00000000000000# 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 - 2.x.x-1 - Version 2.0.0 Pre-release scsitape-stenc-704b5dd/stenc.xml000066400000000000000000000065471504027041400167210ustar00rootroot00000000000000 stenc 1.0.7 VERSION VENDOR stenc 1.0.8 VERSION VENDOR stenc 1.1.0 VERSION VENDOR stenc 1.1.1 VERSION VENDOR stenc 2.0.0 VERSION VENDOR stenc 2.0.1 VERSION VENDOR scsitape-stenc-704b5dd/stenc.xml.license000066400000000000000000000001151504027041400203230ustar00rootroot00000000000000SPDX-FileCopyrightText: 2022 stenc authors SPDX-License-Identifier: CC0-1.0 scsitape-stenc-704b5dd/tests/000077500000000000000000000000001504027041400162115ustar00rootroot00000000000000scsitape-stenc-704b5dd/tests/Makefile.am000066400000000000000000000004631504027041400202500ustar00rootroot00000000000000# 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 scsitape-stenc-704b5dd/tests/catch.hpp000066400000000000000000024040631504027041400200150ustar00rootroot00000000000000// Copyright (c) 2022 Two Blue Cubes Ltd. All rights reserved. // SPDX-FileCopyrightText: 2022 Two Blue Cubes Ltd. All rights reserved. // // SPDX-License-Identifier: BSL-1.0 /* * Catch v2.13.9 * Generated: 2022-04-12 22:37:23.260201 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly * Copyright (c) 2022 Two Blue Cubes Ltd. All rights reserved. * * Distributed under the Boost Software License, Version 1.0. (See accompanying * file LICENSES/BSL-1.0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ #ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED #define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED // start catch.hpp #define CATCH_VERSION_MAJOR 2 #define CATCH_VERSION_MINOR 13 #define CATCH_VERSION_PATCH 9 #ifdef __clang__ # pragma clang system_header #elif defined __GNUC__ # pragma GCC system_header #endif // start catch_suppress_warnings.h #ifdef __clang__ # ifdef __ICC // icpc defines the __clang__ macro # pragma warning(push) # pragma warning(disable: 161 1682) # else // __ICC # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wpadded" # pragma clang diagnostic ignored "-Wswitch-enum" # pragma clang diagnostic ignored "-Wcovered-switch-default" # endif #elif defined __GNUC__ // Because REQUIREs trigger GCC's -Wparentheses, and because still // supported version of g++ have only buggy support for _Pragmas, // Wparentheses have to be suppressed globally. # pragma GCC diagnostic ignored "-Wparentheses" // See #674 for details # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wunused-variable" # pragma GCC diagnostic ignored "-Wpadded" #endif // end catch_suppress_warnings.h #if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) # define CATCH_IMPL # define CATCH_CONFIG_ALL_PARTS #endif // In the impl file, we want to have access to all parts of the headers // Can also be used to sanely support PCHs #if defined(CATCH_CONFIG_ALL_PARTS) # define CATCH_CONFIG_EXTERNAL_INTERFACES # if defined(CATCH_CONFIG_DISABLE_MATCHERS) # undef CATCH_CONFIG_DISABLE_MATCHERS # endif # if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) # define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER # endif #endif #if !defined(CATCH_CONFIG_IMPL_ONLY) // start catch_platform.h // See e.g.: // https://opensource.apple.com/source/CarbonHeaders/CarbonHeaders-18.1/TargetConditionals.h.auto.html #ifdef __APPLE__ # include # if (defined(TARGET_OS_OSX) && TARGET_OS_OSX == 1) || \ (defined(TARGET_OS_MAC) && TARGET_OS_MAC == 1) # define CATCH_PLATFORM_MAC # elif (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1) # define CATCH_PLATFORM_IPHONE # endif #elif defined(linux) || defined(__linux) || defined(__linux__) # define CATCH_PLATFORM_LINUX #elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__) # define CATCH_PLATFORM_WINDOWS #endif // end catch_platform.h #ifdef CATCH_IMPL # ifndef CLARA_CONFIG_MAIN # define CLARA_CONFIG_MAIN_NOT_DEFINED # define CLARA_CONFIG_MAIN # endif #endif // start catch_user_interfaces.h namespace Catch { unsigned int rngSeed(); } // end catch_user_interfaces.h // start catch_tag_alias_autoregistrar.h // start catch_common.h // start catch_compiler_capabilities.h // Detect a number of compiler features - by compiler // The following features are defined: // // CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported? // CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? // CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? // CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled? // **************** // Note to maintainers: if new toggles are added please document them // in configuration.md, too // **************** // In general each macro has a _NO_ form // (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature. // Many features, at point of detection, define an _INTERNAL_ macro, so they // can be combined, en-mass, with the _NO_ forms later. #ifdef __cplusplus # if (__cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) # define CATCH_CPP14_OR_GREATER # endif # if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) # define CATCH_CPP17_OR_GREATER # endif #endif // Only GCC compiler should be used in this block, so other compilers trying to // mask themselves as GCC should be ignored. #if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__) # define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" ) # define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" ) # define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) #endif #if defined(__clang__) # define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" ) # define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" ) // As of this writing, IBM XL's implementation of __builtin_constant_p has a bug // which results in calls to destructors being emitted for each temporary, // without a matching initialization. In practice, this can result in something // like `std::string::~string` being called on an uninitialized value. // // For example, this code will likely segfault under IBM XL: // ``` // REQUIRE(std::string("12") + "34" == "1234") // ``` // // Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented. # if !defined(__ibmxl__) && !defined(__CUDACC__) # define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg) */ # endif # define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) # define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) # define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" ) # define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ _Pragma( "clang diagnostic ignored \"-Wunused-template\"" ) #endif // __clang__ //////////////////////////////////////////////////////////////////////////////// // Assume that non-Windows platforms support posix signals by default #if !defined(CATCH_PLATFORM_WINDOWS) #define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS #endif //////////////////////////////////////////////////////////////////////////////// // We know some environments not to support full POSIX signals #if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__) #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS #endif #ifdef __OS400__ # define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS # define CATCH_CONFIG_COLOUR_NONE #endif //////////////////////////////////////////////////////////////////////////////// // Android somehow still does not support std::to_string #if defined(__ANDROID__) # define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING # define CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE #endif //////////////////////////////////////////////////////////////////////////////// // Not all Windows environments support SEH properly #if defined(__MINGW32__) # define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH #endif //////////////////////////////////////////////////////////////////////////////// // PS4 #if defined(__ORBIS__) # define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE #endif //////////////////////////////////////////////////////////////////////////////// // Cygwin #ifdef __CYGWIN__ // Required for some versions of Cygwin to declare gettimeofday // see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin # define _BSD_SOURCE // some versions of cygwin (most) do not support std::to_string. Use the libstd check. // https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813 # if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \ && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF)) # define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING # endif #endif // __CYGWIN__ //////////////////////////////////////////////////////////////////////////////// // Visual C++ #if defined(_MSC_VER) // Universal Windows platform does not support SEH // Or console colours (or console at all...) # if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) # define CATCH_CONFIG_COLOUR_NONE # else # define CATCH_INTERNAL_CONFIG_WINDOWS_SEH # endif # if !defined(__clang__) // Handle Clang masquerading for msvc // MSVC traditional preprocessor needs some workaround for __VA_ARGS__ // _MSVC_TRADITIONAL == 0 means new conformant preprocessor // _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor # if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL) # define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR # endif // MSVC_TRADITIONAL // Only do this if we're not using clang on Windows, which uses `diagnostic push` & `diagnostic pop` # define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) ) # define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) ) # endif // __clang__ #endif // _MSC_VER #if defined(_REENTRANT) || defined(_MSC_VER) // Enable async processing, as -pthread is specified or no additional linking is required # define CATCH_INTERNAL_CONFIG_USE_ASYNC #endif // _MSC_VER //////////////////////////////////////////////////////////////////////////////// // Check if we are compiled with -fno-exceptions or equivalent #if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND) # define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED #endif //////////////////////////////////////////////////////////////////////////////// // DJGPP #ifdef __DJGPP__ # define CATCH_INTERNAL_CONFIG_NO_WCHAR #endif // __DJGPP__ //////////////////////////////////////////////////////////////////////////////// // Embarcadero C++Build #if defined(__BORLANDC__) #define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN #endif //////////////////////////////////////////////////////////////////////////////// // Use of __COUNTER__ is suppressed during code analysis in // CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly // handled by it. // Otherwise all supported compilers support COUNTER macro, // but user still might want to turn it off #if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) #define CATCH_INTERNAL_CONFIG_COUNTER #endif //////////////////////////////////////////////////////////////////////////////// // RTX is a special version of Windows that is real time. // This means that it is detected as Windows, but does not provide // the same set of capabilities as real Windows does. #if defined(UNDER_RTSS) || defined(RTX64_BUILD) #define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH #define CATCH_INTERNAL_CONFIG_NO_ASYNC #define CATCH_CONFIG_COLOUR_NONE #endif #if !defined(_GLIBCXX_USE_C99_MATH_TR1) #define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER #endif // Various stdlib support checks that require __has_include #if defined(__has_include) // Check if string_view is available and usable #if __has_include() && defined(CATCH_CPP17_OR_GREATER) # define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW #endif // Check if optional is available and usable # if __has_include() && defined(CATCH_CPP17_OR_GREATER) # define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) // Check if byte is available and usable # if __has_include() && defined(CATCH_CPP17_OR_GREATER) # include # if defined(__cpp_lib_byte) && (__cpp_lib_byte > 0) # define CATCH_INTERNAL_CONFIG_CPP17_BYTE # endif # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) // Check if variant is available and usable # if __has_include() && defined(CATCH_CPP17_OR_GREATER) # if defined(__clang__) && (__clang_major__ < 8) // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852 // fix should be in clang 8, workaround in libstdc++ 8.2 # include # if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) # define CATCH_CONFIG_NO_CPP17_VARIANT # else # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT # endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) # else # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT # endif // defined(__clang__) && (__clang_major__ < 8) # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) #endif // defined(__has_include) #if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) # define CATCH_CONFIG_COUNTER #endif #if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH) # define CATCH_CONFIG_WINDOWS_SEH #endif // This is set by default, because we assume that unix compilers are posix-signal-compatible by default. #if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) # define CATCH_CONFIG_POSIX_SIGNALS #endif // This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions. #if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR) # define CATCH_CONFIG_WCHAR #endif #if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING) # define CATCH_CONFIG_CPP11_TO_STRING #endif #if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL) # define CATCH_CONFIG_CPP17_OPTIONAL #endif #if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW) # define CATCH_CONFIG_CPP17_STRING_VIEW #endif #if defined(CATCH_INTERNAL_CONFIG_CPP17_VARIANT) && !defined(CATCH_CONFIG_NO_CPP17_VARIANT) && !defined(CATCH_CONFIG_CPP17_VARIANT) # define CATCH_CONFIG_CPP17_VARIANT #endif #if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE) # define CATCH_CONFIG_CPP17_BYTE #endif #if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) # define CATCH_INTERNAL_CONFIG_NEW_CAPTURE #endif #if defined(CATCH_INTERNAL_CONFIG_NEW_CAPTURE) && !defined(CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NEW_CAPTURE) # define CATCH_CONFIG_NEW_CAPTURE #endif #if !defined(CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) # define CATCH_CONFIG_DISABLE_EXCEPTIONS #endif #if defined(CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_NO_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_POLYFILL_ISNAN) # define CATCH_CONFIG_POLYFILL_ISNAN #endif #if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC) && !defined(CATCH_INTERNAL_CONFIG_NO_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC) # define CATCH_CONFIG_USE_ASYNC #endif #if defined(CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_NO_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_ANDROID_LOGWRITE) # define CATCH_CONFIG_ANDROID_LOGWRITE #endif #if defined(CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_NO_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) # define CATCH_CONFIG_GLOBAL_NEXTAFTER #endif // Even if we do not think the compiler has that warning, we still have // to provide a macro that can be used by the code. #if !defined(CATCH_INTERNAL_START_WARNINGS_SUPPRESSION) # define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION #endif #if !defined(CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION) # define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION #endif #if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS #endif #if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS #endif #if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS #endif #if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS #endif // The goal of this macro is to avoid evaluation of the arguments, but // still have the compiler warn on problems inside... #if !defined(CATCH_INTERNAL_IGNORE_BUT_WARN) # define CATCH_INTERNAL_IGNORE_BUT_WARN(...) #endif #if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10) # undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS #elif defined(__clang__) && (__clang_major__ < 5) # undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS #endif #if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS #endif #if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) #define CATCH_TRY if ((true)) #define CATCH_CATCH_ALL if ((false)) #define CATCH_CATCH_ANON(type) if ((false)) #else #define CATCH_TRY try #define CATCH_CATCH_ALL catch (...) #define CATCH_CATCH_ANON(type) catch (type) #endif #if defined(CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_NO_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) #define CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #endif // end catch_compiler_capabilities.h #define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line #define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) #ifdef CATCH_CONFIG_COUNTER # define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) #else # define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) #endif #include #include #include // We need a dummy global operator<< so we can bring it into Catch namespace later struct Catch_global_namespace_dummy {}; std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); namespace Catch { struct CaseSensitive { enum Choice { Yes, No }; }; class NonCopyable { NonCopyable( NonCopyable const& ) = delete; NonCopyable( NonCopyable && ) = delete; NonCopyable& operator = ( NonCopyable const& ) = delete; NonCopyable& operator = ( NonCopyable && ) = delete; protected: NonCopyable(); virtual ~NonCopyable(); }; struct SourceLineInfo { SourceLineInfo() = delete; SourceLineInfo( char const* _file, std::size_t _line ) noexcept : file( _file ), line( _line ) {} SourceLineInfo( SourceLineInfo const& other ) = default; SourceLineInfo& operator = ( SourceLineInfo const& ) = default; SourceLineInfo( SourceLineInfo&& ) noexcept = default; SourceLineInfo& operator = ( SourceLineInfo&& ) noexcept = default; bool empty() const noexcept { return file[0] == '\0'; } bool operator == ( SourceLineInfo const& other ) const noexcept; bool operator < ( SourceLineInfo const& other ) const noexcept; char const* file; std::size_t line; }; std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); // Bring in operator<< from global namespace into Catch namespace // This is necessary because the overload of operator<< above makes // lookup stop at namespace Catch using ::operator<<; // Use this in variadic streaming macros to allow // >> +StreamEndStop // as well as // >> stuff +StreamEndStop struct StreamEndStop { std::string operator+() const; }; template T const& operator + ( T const& value, StreamEndStop ) { return value; } } #define CATCH_INTERNAL_LINEINFO \ ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) // end catch_common.h namespace Catch { struct RegistrarForTagAliases { RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); }; } // end namespace Catch #define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION // end catch_tag_alias_autoregistrar.h // start catch_test_registry.h // start catch_interfaces_testcase.h #include namespace Catch { class TestSpec; struct ITestInvoker { virtual void invoke () const = 0; virtual ~ITestInvoker(); }; class TestCase; struct IConfig; struct ITestCaseRegistry { virtual ~ITestCaseRegistry(); virtual std::vector const& getAllTests() const = 0; virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; }; bool isThrowSafe( TestCase const& testCase, IConfig const& config ); bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); std::vector const& getAllTestCasesSorted( IConfig const& config ); } // end catch_interfaces_testcase.h // start catch_stringref.h #include #include #include #include namespace Catch { /// A non-owning string class (similar to the forthcoming std::string_view) /// Note that, because a StringRef may be a substring of another string, /// it may not be null terminated. class StringRef { public: using size_type = std::size_t; using const_iterator = const char*; private: static constexpr char const* const s_empty = ""; char const* m_start = s_empty; size_type m_size = 0; public: // construction constexpr StringRef() noexcept = default; StringRef( char const* rawChars ) noexcept; constexpr StringRef( char const* rawChars, size_type size ) noexcept : m_start( rawChars ), m_size( size ) {} StringRef( std::string const& stdString ) noexcept : m_start( stdString.c_str() ), m_size( stdString.size() ) {} explicit operator std::string() const { return std::string(m_start, m_size); } public: // operators auto operator == ( StringRef const& other ) const noexcept -> bool; auto operator != (StringRef const& other) const noexcept -> bool { return !(*this == other); } auto operator[] ( size_type index ) const noexcept -> char { assert(index < m_size); return m_start[index]; } public: // named queries constexpr auto empty() const noexcept -> bool { return m_size == 0; } constexpr auto size() const noexcept -> size_type { return m_size; } // Returns the current start pointer. If the StringRef is not // null-terminated, throws std::domain_exception auto c_str() const -> char const*; public: // substrings and searches // Returns a substring of [start, start + length). // If start + length > size(), then the substring is [start, size()). // If start > size(), then the substring is empty. auto substr( size_type start, size_type length ) const noexcept -> StringRef; // Returns the current start pointer. May not be null-terminated. auto data() const noexcept -> char const*; constexpr auto isNullTerminated() const noexcept -> bool { return m_start[m_size] == '\0'; } public: // iterators constexpr const_iterator begin() const { return m_start; } constexpr const_iterator end() const { return m_start + m_size; } }; auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&; auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; constexpr auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { return StringRef( rawChars, size ); } } // namespace Catch constexpr auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { return Catch::StringRef( rawChars, size ); } // end catch_stringref.h // start catch_preprocessor.hpp #define CATCH_RECURSION_LEVEL0(...) __VA_ARGS__ #define CATCH_RECURSION_LEVEL1(...) CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(__VA_ARGS__))) #define CATCH_RECURSION_LEVEL2(...) CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(__VA_ARGS__))) #define CATCH_RECURSION_LEVEL3(...) CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(__VA_ARGS__))) #define CATCH_RECURSION_LEVEL4(...) CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(__VA_ARGS__))) #define CATCH_RECURSION_LEVEL5(...) CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(__VA_ARGS__))) #ifdef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_EXPAND_VARGS(...) __VA_ARGS__ // MSVC needs more evaluations #define CATCH_RECURSION_LEVEL6(...) CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(__VA_ARGS__))) #define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL6(CATCH_RECURSION_LEVEL6(__VA_ARGS__)) #else #define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL5(__VA_ARGS__) #endif #define CATCH_REC_END(...) #define CATCH_REC_OUT #define CATCH_EMPTY() #define CATCH_DEFER(id) id CATCH_EMPTY() #define CATCH_REC_GET_END2() 0, CATCH_REC_END #define CATCH_REC_GET_END1(...) CATCH_REC_GET_END2 #define CATCH_REC_GET_END(...) CATCH_REC_GET_END1 #define CATCH_REC_NEXT0(test, next, ...) next CATCH_REC_OUT #define CATCH_REC_NEXT1(test, next) CATCH_DEFER ( CATCH_REC_NEXT0 ) ( test, next, 0) #define CATCH_REC_NEXT(test, next) CATCH_REC_NEXT1(CATCH_REC_GET_END test, next) #define CATCH_REC_LIST0(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) #define CATCH_REC_LIST1(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0) ) ( f, peek, __VA_ARGS__ ) #define CATCH_REC_LIST2(f, x, peek, ...) f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) #define CATCH_REC_LIST0_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) #define CATCH_REC_LIST1_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0_UD) ) ( f, userdata, peek, __VA_ARGS__ ) #define CATCH_REC_LIST2_UD(f, userdata, x, peek, ...) f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) // Applies the function macro `f` to each of the remaining parameters, inserts commas between the results, // and passes userdata as the first parameter to each invocation, // e.g. CATCH_REC_LIST_UD(f, x, a, b, c) evaluates to f(x, a), f(x, b), f(x, c) #define CATCH_REC_LIST_UD(f, userdata, ...) CATCH_RECURSE(CATCH_REC_LIST2_UD(f, userdata, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) #define CATCH_REC_LIST(f, ...) CATCH_RECURSE(CATCH_REC_LIST2(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) #define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param) #define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__ #define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__ #define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF #define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__) #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__ #define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) #else // MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF #define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__) #define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__ #define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1) #endif #define INTERNAL_CATCH_MAKE_NAMESPACE2(...) ns_##__VA_ARGS__ #define INTERNAL_CATCH_MAKE_NAMESPACE(name) INTERNAL_CATCH_MAKE_NAMESPACE2(name) #define INTERNAL_CATCH_REMOVE_PARENS(...) INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF __VA_ARGS__) #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) decltype(get_wrapper()) #define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)) #else #define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) INTERNAL_CATCH_EXPAND_VARGS(decltype(get_wrapper())) #define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))) #endif #define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(...)\ CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,__VA_ARGS__) #define INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_0) INTERNAL_CATCH_REMOVE_PARENS(_0) #define INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_0, _1) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_1) #define INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_0, _1, _2) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_1, _2) #define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3) #define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4) #define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5) #define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _3, _4, _5, _6) #define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7) #define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8) #define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9) #define INTERNAL_CATCH_REMOVE_PARENS_11_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10) #define INTERNAL_CATCH_VA_NARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N #define INTERNAL_CATCH_TYPE_GEN\ template struct TypeList {};\ template\ constexpr auto get_wrapper() noexcept -> TypeList { return {}; }\ template class...> struct TemplateTypeList{};\ template class...Cs>\ constexpr auto get_wrapper() noexcept -> TemplateTypeList { return {}; }\ template\ struct append;\ template\ struct rewrap;\ template class, typename...>\ struct create;\ template class, typename>\ struct convert;\ \ template \ struct append { using type = T; };\ template< template class L1, typename...E1, template class L2, typename...E2, typename...Rest>\ struct append, L2, Rest...> { using type = typename append, Rest...>::type; };\ template< template class L1, typename...E1, typename...Rest>\ struct append, TypeList, Rest...> { using type = L1; };\ \ template< template class Container, template class List, typename...elems>\ struct rewrap, List> { using type = TypeList>; };\ template< template class Container, template class List, class...Elems, typename...Elements>\ struct rewrap, List, Elements...> { using type = typename append>, typename rewrap, Elements...>::type>::type; };\ \ template