John Coleman
2018-02-14 04:11:24 +01:00
committed by Jonas Stein
parent 50e0d69705
commit db613c9828
26 changed files with 11796 additions and 20 deletions
+4
View File
@@ -0,0 +1,4 @@
bin_PROGRAMS = stenc
AM_CXXFLAGS = $(INTI_CFLAGS) $(DEPS_CFLAGS)
stenc_SOURCES = main.cpp scsiencrypt.cpp scsiencrypt.h keyinfo.h keyinfo.cpp
#stenc_LDADD = $(INTI_LIBS)
+463
View File
@@ -0,0 +1,463 @@
# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
# Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
VPATH = @srcdir@
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkglibexecdir = $(libexecdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
bin_PROGRAMS = stenc$(EXEEXT)
subdir = src
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/configure.in
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
am__installdirs = "$(DESTDIR)$(bindir)"
PROGRAMS = $(bin_PROGRAMS)
am_stenc_OBJECTS = main.$(OBJEXT) scsiencrypt.$(OBJEXT) \
keyinfo.$(OBJEXT)
stenc_OBJECTS = $(am_stenc_OBJECTS)
stenc_LDADD = $(LDADD)
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
am__mv = mv -f
CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
CXXLD = $(CXX)
CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \
-o $@
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
CCLD = $(CC)
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
SOURCES = $(stenc_SOURCES)
DIST_SOURCES = $(stenc_SOURCES)
ETAGS = etags
CTAGS = ctags
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CXX = @CXX@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
GREP = @GREP@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LDFLAGS = @LDFLAGS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LTLIBOBJS = @LTLIBOBJS@
MAKEINFO = @MAKEINFO@
MKDIR_P = @MKDIR_P@
OBJEXT = @OBJEXT@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
VERSION = @VERSION@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build_alias = @build_alias@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host_alias = @host_alias@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
sysconfdir = @sysconfdir@
target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
AM_CXXFLAGS = $(INTI_CFLAGS) $(DEPS_CFLAGS)
stenc_SOURCES = main.cpp scsiencrypt.cpp scsiencrypt.h keyinfo.h keyinfo.cpp
all: all-am
.SUFFIXES:
.SUFFIXES: .cpp .o .obj
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
&& { if test -f $@; then exit 0; else break; fi; }; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --gnu src/Makefile
.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
install-binPROGRAMS: $(bin_PROGRAMS)
@$(NORMAL_INSTALL)
test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
@list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
for p in $$list; do echo "$$p $$p"; done | \
sed 's/$(EXEEXT)$$//' | \
while read p p1; do if test -f $$p; \
then echo "$$p"; echo "$$p"; else :; fi; \
done | \
sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \
-e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
sed 'N;N;N;s,\n, ,g' | \
$(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
{ d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
if ($$2 == $$4) files[d] = files[d] " " $$1; \
else { print "f", $$3 "/" $$4, $$1; } } \
END { for (d in files) print "f", d, files[d] }' | \
while read type dir files; do \
if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
test -z "$$files" || { \
echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
$(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
} \
; done
uninstall-binPROGRAMS:
@$(NORMAL_UNINSTALL)
@list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
files=`for p in $$list; do echo "$$p"; done | \
sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
-e 's/$$/$(EXEEXT)/' `; \
test -n "$$list" || exit 0; \
echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
cd "$(DESTDIR)$(bindir)" && rm -f $$files
clean-binPROGRAMS:
-test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
stenc$(EXEEXT): $(stenc_OBJECTS) $(stenc_DEPENDENCIES)
@rm -f stenc$(EXEEXT)
$(CXXLINK) $(stenc_OBJECTS) $(stenc_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keyinfo.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/scsiencrypt.Po@am__quote@
.cpp.o:
@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $<
.cpp.obj:
@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in files) print i; }; }'`; \
mkid -fID $$unique
tags: TAGS
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
set x; \
here=`pwd`; \
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in files) print i; }; }'`; \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
if test $$# -gt 0; then \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
"$$@" $$unique; \
else \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$unique; \
fi; \
fi
ctags: CTAGS
CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in files) print i; }; }'`; \
test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
test -f "$(distdir)/$$file" \
|| cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
check-am: all-am
check: check-am
all-am: Makefile $(PROGRAMS)
installdirs:
for dir in "$(DESTDIR)$(bindir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
`test -z '$(STRIP)' || \
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
mostlyclean-generic:
clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
clean-am: clean-binPROGRAMS clean-generic mostlyclean-am
distclean: distclean-am
-rm -rf ./$(DEPDIR)
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
dvi: dvi-am
dvi-am:
html: html-am
html-am:
info: info-am
info-am:
install-data-am:
install-dvi: install-dvi-am
install-dvi-am:
install-exec-am: install-binPROGRAMS
install-html: install-html-am
install-html-am:
install-info: install-info-am
install-info-am:
install-man:
install-pdf: install-pdf-am
install-pdf-am:
install-ps: install-ps-am
install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -rf ./$(DEPDIR)
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-compile mostlyclean-generic
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am: uninstall-binPROGRAMS
.MAKE: install-am install-strip
.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \
clean-generic ctags distclean distclean-compile \
distclean-generic distclean-tags distdir dvi dvi-am html \
html-am info info-am install install-am install-binPROGRAMS \
install-data install-data-am install-dvi install-dvi-am \
install-exec install-exec-am install-html install-html-am \
install-info install-info-am install-man install-pdf \
install-pdf-am install-ps install-ps-am install-strip \
installcheck installcheck-am installdirs maintainer-clean \
maintainer-clean-generic mostlyclean mostlyclean-compile \
mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \
uninstall-am uninstall-binPROGRAMS
#stenc_LDADD = $(INTI_LIBS)
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
+123
View File
@@ -0,0 +1,123 @@
#include <config.h>
#include <iostream>
#include <string.h>
#include <string>
#include <sstream>
#include "keyinfo.h"
#include "scsiencrypt.h"
using namespace std;
Keyinfo::Keyinfo(){
valid=false;
check="";
key=NULL;
keySize=0;
}
void Keyinfo::load(string hexinput){
valid=true;
if(hexinput.size()<2){
valid=false;
cout<<"Key input too short!"<<endl;
return;
}
//parse for invalid characters
for(unsigned int i=0;i<hexinput.size();i++){
switch((unsigned char)hexinput.at(i)){
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
break;
default:
cout<<"Invalid character '"<<hexinput.at(i)<<"' found in key!"<<endl;
valid=false;
return;
}
}
// delete the key if its already allocated
if(key!=NULL)
delete key;
// check that the input size is divisible by 2
if(hexinput.size()%2!=0){
valid=false;
cout<<"Each hexadecimal byte must consist of 2 digits!"<<endl;
return;
}
//convert the hex input to a char*
loadKey(hexinput);
//load the check value
loadCheck();
//check for oversized key
if(keySize==0 || keySize>SSP_KEY_LENGTH){
cout<<"Key size cannot exceed "<<(SSP_KEY_LENGTH*8)<<" bits!"<<endl;
cout<<"Provided key is "<<(keySize*8)<<" bits in length."<<endl;
valid=false;
return;
}
cout<<"Provided key length is "<<(keySize*8)<<" bits."<<endl;
cout<<"Key checksum is "<<check<<"."<<endl;
}
void Keyinfo::loadCheck() {
int i;
int chk = 0;
for (i = 0; i<keySize;i++) {
chk += ((int)key[i]) * (i + 1);
}
stringstream retval;
retval<<hex<<chk;
check=retval.str();
}
Keyinfo::~Keyinfo(){
delete key;
}
void Keyinfo::loadKey(string str)
{
int length = str.size();
// make sure the input string has an even digit numbers
if(length%2 == 1)
{
str = "0" + str;
length++;
}
// allocate memory for the output array
key = new char[length/2];
memset(key,0,(length/2)+1);
keySize = length/2;
stringstream sstr(str);
for(int i=0; i < keySize; i++)
{
char ch1, ch2;
sstr >> ch1 >> ch2;
int dig1=0, dig2=0;
if(isdigit(ch1)) dig1 = ch1 - '0';
else if(ch1>='A' && ch1<='F') dig1 = ch1 - 'A' + 10;
else if(ch1>='a' && ch1<='f') dig1 = ch1 - 'a' + 10;
if(isdigit(ch2)) dig2 = ch2 - '0';
else if(ch2>='A' && ch2<='F') dig2 = ch2 - 'A' + 10;
else if(ch2>='a' && ch2<='f') dig2 = ch2 - 'a' + 10;
key[i] = dig1*16 + dig2;
}
}
+20
View File
@@ -0,0 +1,20 @@
#ifndef KEYINFO_H
#define KEYINFO_H
#include <string>
class Keyinfo{
public:
char* key;
int keySize;
bool valid;
std::string check;
void load(std::string hexinput);
Keyinfo();
~Keyinfo();
private:
void loadKey(std::string str);
void loadCheck();
};
#endif
+535
View File
@@ -0,0 +1,535 @@
/*
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 <config.h>
#include <termios.h>
#include <unistd.h>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <fstream>
#include <string>
#include <sys/stat.h>
#include <time.h>
#ifdef OS_LINUX
#include <stdlib.h>
#include <string.h>
#endif
#include "scsiencrypt.h"
#include "keyinfo.h"
#define LOGFILE "/var/log/stenc"
typedef struct {
#ifndef SWAPBIT
unsigned char bit1:1;
unsigned char bit2:1;
unsigned char bit3:1;
unsigned char bit4:1;
unsigned char bit5:1;
unsigned char bit6:1;
unsigned char bit7:1;
unsigned char bit8:1;
#else
unsigned char bit8:1;
unsigned char bit7:1;
unsigned char bit6:1;
unsigned char bit5:1;
unsigned char bit4:1;
unsigned char bit3:1;
unsigned char bit2:1;
unsigned char bit1:1;
#endif
} bitcheck;
using namespace std;
void showUsage();
void errorOut(string message);
void inquiryDrive(string tapeDevice);
void showDriveStatus(string tapeDevice);
void showVolumeStatus(string tapeDevice);
string randomKey(int length);
string timestamp();
void echo(bool);
ofstream logFile;
//program entry point
int main(int argc, char **argv){
cout<<"stenc v"<<VERSION<<" - SCSI Tape Encryption Manager"<<endl;
bitcheck bc;
memset(&bc,0,1);
bc.bit2=1;
bc.bit5=1;
unsigned char check;
memcpy(&check,&bc,1);
switch((int)check){
case 0x12:
//this is good
break;
case 0x48:
#ifndef SWAPBIT
errorOut("Swapped bit ordering detected. Program needs to be configured with the --enable-swapbit option in order to function properly on your system");
#else
errorOut("Swapped bit ordering detected. Program needs to be configured with the --disable-swapbit option in order to function properly on your system");
#endif
break;
default:
cerr<<"Unknown bit check result "<<HEX(check)<<endl;
errorOut("Exiting program because it will not run properly");
break;
}
string tapeDrive="";
bool setting=false;
string keyFile;
SCSIEncryptOptions drvOptions;
//First load all of the options
for(int i=1;i<argc;i++){
string thisCmd=argv[i];
string nextCmd="";
if(i+1<argc){
if(strncmp(argv[i+1],"-",1)!=0)nextCmd=argv[i+1];
}
if(thisCmd=="-g"){ //Check if the help flag was passed. If it was, show usage and exit
if(nextCmd=="")errorOut("Key size must be specified when using -g");
i++; //skip the next argument
int keylength=atoi(nextCmd.c_str());
if (keylength % 8 != 0)errorOut("Key size must be divisible by 8");
keylength=keylength/8;
if(keylength>SSP_KEY_LENGTH){
cout<<"Warning: Keys over "<<(SSP_KEY_LENGTH*8)<<" bits cannot be used by this program!"<<endl;
}
string newkey=randomKey(keylength);
string keyfilename,keydesc;
cout<<"Filename to save key into: ";
getline(cin,keyfilename);
cout<<"Key description (optional): ";
getline(cin,keydesc);
if(keydesc.size()>SSP_UKAD_LENGTH){
errorOut("Description too long!");
}
ofstream kf;
kf.open(keyfilename.c_str(),ios::trunc);
if(!kf.is_open()){
errorOut("Could not open '"+keyfilename+"' for writing.");
}
kf<<newkey<<keydesc;
kf.close();
cout<<"Random key saved into '"<<keyfilename<<"'"<<endl;
chmod(keyfilename.c_str(),0600);
cout<<"Permissions of keyfile set to 600"<<endl;
exit(EXIT_SUCCESS);
}
else if(thisCmd=="-e"){
if(nextCmd=="")errorOut("Key file not specified after -k option");
if(nextCmd=="on")drvOptions.cryptMode=CRYPTMODE_ON; //encrypt, read only encrypted data
else if(nextCmd=="mixed")drvOptions.cryptMode=CRYPTMODE_MIXED;//encrypt, read encrypted and unencrypted data
else if(nextCmd=="rawread")drvOptions.cryptMode=CRYPTMODE_RAWREAD;//encrypt, read encrypted and unencrypted data
else if(nextCmd=="off")drvOptions.cryptMode=CRYPTMODE_OFF;//encrypt, read encrypted and unencrypted data
else errorOut("Unknown encryption mode '"+nextCmd+"'");//encrypt, read encrypted and unencrypted data
i++; //skip the next argument
setting=true;
}
else if(thisCmd=="-f"){
if(nextCmd=="")errorOut("Device not specified after -f option.");
tapeDrive=nextCmd; //set the tape drive
i++; //skip the next argument
}
else if(setting){
if(thisCmd=="-k"){
if(nextCmd=="")errorOut("Key file not specified after -k option");
keyFile=nextCmd; //set the key file
i++; //skip the next argument
}
else if(thisCmd=="--protect"){
if(drvOptions.rdmc==RDMC_UNPROTECT)errorOut("'--protect' cannot be specified at the same time as '--unprotect'");
drvOptions.rdmc=RDMC_PROTECT;
}
else if(thisCmd=="--unprotect"){
if(drvOptions.rdmc==RDMC_PROTECT)errorOut("'--unprotect' cannot be specified at the same time as '--protect'");
drvOptions.rdmc=RDMC_UNPROTECT;
}
else if(thisCmd=="--ckod"){
drvOptions.CKOD=true;
}
else if(thisCmd=="-a"){
if(nextCmd=="")errorOut("You must specify a numeric algorithm index when using the -a flag");
drvOptions.algorithmIndex=atoi(nextCmd.c_str());
i++; //skip the next argument
}
else{
errorOut("Unknown command '"+thisCmd+"'");
}
}
else{
errorOut("Unknown command '"+thisCmd+"'");
}
}
//validate the tape device
if(tapeDrive==""){
errorOut("Tape drive device must be specified with the -f option");
}
if(drvOptions.cryptMode==CRYPTMODE_RAWREAD && drvOptions.rdmc==RDMC_PROTECT){
errorOut("'--protect' is not valid when setting encryption mode to 'rawread'");
}
#ifndef DISABLE_DEVICE_NAME_CONVERSION
if(tapeDrive.find(".")==string::npos){
if(tapeDrive.substr(0,7)=="/dev/st"){
tapeDrive="/dev/nst"+tapeDrive.substr(7,tapeDrive.size()-6);
}
if(tapeDrive.substr(0,8)=="/dev/rmt" && tapeDrive.substr(tapeDrive.size()-2,2)!=".1" ){
tapeDrive="/dev/rmt"+tapeDrive.substr(8,tapeDrive.size()-7)+".1";
}
}
#endif
if(getuid()!=0){
errorOut("You must be root to read or set encryption options on a drive!");
}
logFile.open(LOGFILE,ios::app);
if(!logFile.is_open()){
cout<<"Warning: Could not open '"<<LOGFILE<<"' for key change auditing!"<<endl;
}
chmod(LOGFILE,0600);
if(!setting){
cout<<"Status for "<<tapeDrive<<endl;
cout<<"--------------------------------------------------"<<endl;
inquiryDrive(tapeDrive);
showDriveStatus(tapeDrive);
showVolumeStatus(tapeDrive);
exit(EXIT_SUCCESS);
}
Keyinfo ki;
if(drvOptions.cryptMode!=CRYPTMODE_OFF){
if(keyFile==""){
string p1="01";
string p2="02";
string kdesc="";
bool done=false;
while(!done){
cout<<"Enter key in hex format: ";
echo(false);
getline(cin,p1);
echo(true);
cout<<endl;
cout<<"Re-enter key in hex format: ";
echo(false);
getline(cin,p2);
echo(true);
cout<<endl;
if(p1!=p2){
cout<<"Keys do not match!!"<<endl;
}else{
ki.load(p1);
if(ki.valid){
bool descvalid=false;
while(!descvalid){
cout<<"Key description (optional): ";
getline(cin,kdesc);
cout<<endl;
descvalid=true;
if(kdesc.size()>SSP_UKAD_LENGTH)descvalid=false;
if(!descvalid)cout<<"Description too long!"<<endl;
}
cout<<"Set encryption using this key? [y/n]: ";
string ans="";
getline(cin,ans);
if(ans=="y"){
done=true;
}
}else cout<<"Invalid key!"<<endl;
}
}
drvOptions.keyName=kdesc;
}else{
//set keyInput here
string keyInput,kdesc;
ifstream myfile(keyFile.c_str());
if (myfile.is_open())
{
getline (myfile,keyInput);
getline (myfile,kdesc);
myfile.close();
ki.load(keyInput);
if(!ki.valid)
errorOut("Invalid key found in '"+keyFile+"'");
if(kdesc.size()>SSP_UKAD_LENGTH)
errorOut("Key description in '"+keyFile+"' too long!");
drvOptions.keyName=kdesc;
}else errorOut("Could not open '"+keyFile+"' for reading");
}
drvOptions.cryptoKey.assign(ki.key,ki.keySize);
}
//Write the options to the tape device
cout<<"Turning "<<((drvOptions.cryptMode!=CRYPTMODE_OFF)?"on":"off")<<" encryption on device '"<<tapeDrive<<"'..."<<endl;
bool res=SCSIWriteEncryptOptions(tapeDrive,&drvOptions);
if(res){
SSP_DES* opt=SSPGetDES(tapeDrive);
if(drvOptions.cryptMode!=CRYPTMODE_OFF && opt->des.encryptionMode!=2){
errorOut("Turning encryption on for '"+tapeDrive+"' failed!");
}
if(drvOptions.cryptMode==CRYPTMODE_OFF && opt->des.encryptionMode!=0){
errorOut("Turning encryption off for '"+tapeDrive+"' failed!");
}
delete opt;
if(drvOptions.cryptMode!=CRYPTMODE_OFF){
stringstream msg;
msg<<"Encryption turned on for device '"<<tapeDrive<<"'. ";
if(drvOptions.keyName.size()==0)
msg<<"Key Checksum: "<<ki.check;
else
msg<<"Key Descriptor: '"<<drvOptions.keyName<<"'";
msg<<" Key Instance: "<<dec<<BSLONG(opt->des.keyInstance)<<endl;
if(logFile.is_open()){
logFile<<timestamp()<<": "<<msg.str();
}
}else{
stringstream msg;
msg<< "Encryption turned off for device '"<<tapeDrive<<"'.";
msg<<" Key Instance: "<<dec<<BSLONG(opt->des.keyInstance)<<endl;
if(logFile.is_open())
logFile<<timestamp()<<": "<<msg.str();
}
cout<< "Success! See '"<<LOGFILE<<"' for a key change audit log."<<endl;
exit(EXIT_SUCCESS);
}
if(drvOptions.cryptMode!=CRYPTMODE_OFF){
errorOut("Turning encryption on for '"+tapeDrive+"' failed!");
}else{
errorOut("Turning encryption off for '"+tapeDrive+"' failed!");
}
}
//exits to shell with an error message
void errorOut(string message){
cerr<<"Error: "<<message<<endl;
showUsage();
exit(EXIT_FAILURE);
}
//shows the command usage
void showUsage(){
cout<<"Usage: stenc -g <length> | -f <device> [-e <on/mixed/rawread/off> [-k <file> ] [-a <number>] [--protect | --unprotect] [--ckod] ]"<<endl;
cout<<"Type 'man stenc' for more information."<<endl;
}
void inquiryDrive(string tapeDevice){
SCSI_PAGE_INQ* iresult=SCSIGetInquiry(tapeDevice);
cout<<left<<setw(25)<<"Device Mfg:";
cout.write((const char*)iresult->vender,8);
cout<<endl;
cout<<left<<setw(25)<<"Product ID:";
cout.write((const char*)iresult->productID,16);
cout<<endl;
cout<<left<<setw(25)<<"Product Revision:";
cout.write((const char*)iresult->productRev,4);
cout<<endl;
delete iresult;
}
void showDriveStatus(string tapeDrive){
SSP_DES* opt=SSPGetDES(tapeDrive);
if(opt==NULL)return;
cout<<left<<setw(25)<<"Data Output:";
switch ((int)opt->des.decryptionMode){
case 0x0:
cout<<"Not decrypting"<<endl;
cout<<setw(25)<<" "<<"Raw encrypted data not outputted"<<endl;
break;
case 0x1:
cout<<"Not decrypting"<<endl;
cout<<setw(25)<<" "<<"Raw encrypted data outputted"<<endl;
break;
case 0x2:
cout<<"Decrypting"<<endl;
cout<<setw(25)<<" "<<"Unencrypted data not outputted"<<endl;
break;
case 0x3:
cout<<"Decrypting"<<endl;
cout<<setw(25)<<" "<<"Unencrypted data outputted"<<endl;
break;
default:
cout<<"Unknown '0x"<<hex<<(int)opt->des.decryptionMode<<"' "<<endl;
break;
}
cout<<setw(25)<<"Data Input:";
switch((int)opt->des.encryptionMode){
case 0x0:
cout<<"Not encrypting"<<endl;
break;
case 0x2:
cout<<"Encrypting"<<endl;
break;
default:
cout<<"Unknown result '0x"<<hex<<(int)opt->des.encryptionMode<<"'"<<endl;
break;
}
if(opt->des.RDMD==1){
cout<<setw(25)<<" "<<"Protecting from raw read"<<endl;
}
cout<<setw(25)<<"Key Instance Counter:"<<dec<<BSLONG(opt->des.keyInstance)<<endl;
if(opt->des.algorithmIndex!=0){
cout<<setw(25)<<"Encryption Algorithm:"<<hex<<(int)opt->des.algorithmIndex<<endl;
}
if(opt->kads.size()>0){
for(unsigned int i=0;i<opt->kads.size();i++){
stringstream lbl;
lbl<<"Drive Key Desc.(";
switch(opt->kads[i].type){
case KAD_TYPE_UKAD:
lbl<<"uKAD): ";
cout<<setw(25)<<lbl.str();
cout.write((const char*)&opt->kads[i].descriptor,BSSHORT(opt->kads[i].descriptorLength));
cout<<endl;
break;
case KAD_TYPE_AKAD:
lbl<<"aKAD): ";
cout<<setw(25)<<lbl.str();
cout.write((const char*)&opt->kads[i].descriptor,BSSHORT(opt->kads[i].descriptorLength));
cout<<endl;
break;
}
}
}
delete opt;
}
void showVolumeStatus(string tapeDrive){
SSP_NBES* opt=SSPGetNBES(tapeDrive,true);
if(opt==NULL)return;
if(opt->nbes.compressionStatus!=0){
cout<<left<<setw(25)<<"Volume Compressed:";
switch(opt->nbes.compressionStatus){
case 0x00:
cout<<"Drive cannot determine"<<endl;
break;
default:
cout<<"Unknown result '"<<hex<<(int)opt->nbes.compressionStatus<<"'"<<endl;
break;
}
}
cout<<left<<setw(25)<<"Volume Encryption:";
switch((int)opt->nbes.encryptionStatus){
case 0x01:
cout<<"Unable to determine"<<endl;
break;
case 0x02:
cout<<"Logical block is not a logical block"<<endl;
break;
case 0x03:
cout<<"Not encrypted"<<endl;
break;
case 0x05:
cout<<"Encrypted and able to decrypt"<<endl;
if(opt->nbes.RDMDS==1)
cout<<left<<setw(25)<<" "<<"Protected from raw read"<<endl;
break;
case 0x06:
cout<<"Encrypted, but unable to decrypt due to invalid key. "<<endl;
if(opt->kads.size()>0){
for(unsigned int i=0;i<opt->kads.size();i++){
stringstream lbl;
lbl<<"Volume Key Desc.(";
switch(opt->kads[i].type){
case KAD_TYPE_UKAD:
lbl<<"uKAD): ";
cout<<setw(25)<<lbl.str();
cout.write((const char*)&opt->kads[i].descriptor,BSSHORT(opt->kads[i].descriptorLength));
cout<<endl;
break;
case KAD_TYPE_AKAD:
lbl<<"aKAD): ";
cout<<setw(25)<<lbl.str();
cout.write((const char*)&opt->kads[i].descriptor,BSSHORT(opt->kads[i].descriptorLength));
cout<<endl;
break;
}
}
}
if(opt->nbes.RDMDS==1)
cout<<left<<setw(25)<<" "<<"Protected from raw read"<<endl;
break;
default:
cout<<"Unknown result '"<<hex<<(int)opt->nbes.encryptionStatus<<"'"<<endl;
break;
}
if(opt->nbes.algorithmIndex!=0){
cout<<left<<setw(25)<<"Volume Algorithm:"<<(int)opt->nbes.algorithmIndex<<endl;
}
delete opt;
}
void echo( bool on = true )
{
struct termios settings;
tcgetattr( STDIN_FILENO, &settings );
settings.c_lflag = on
? (settings.c_lflag | ECHO )
: (settings.c_lflag & ~(ECHO));
tcsetattr( STDIN_FILENO, TCSANOW, &settings );
}
std::string timestamp(){
time_t tm;
time(&tm);
char buffer[80];
int len=strftime((char*)&buffer,80,"%Y-%m-%d",localtime(&tm));
string val;
val.assign(buffer,len);
return val;
}
string randomKey(int length)
{
cout<<"Enter random keys on the keyboard to seed the generator."<<endl<<"End by pressing enter..."<<endl;
double check=0;
char c=0;
echo(false);
while(c!=10){
check+=(int)c;
c=getchar();
}
echo(true);
srand(time(NULL)+(int)check);
stringstream retval;
for (int i=0; i<length; i++)
{
retval <<HEX(rand() % 256);
}
retval << endl;
return retval.str();
}
+605
View File
@@ -0,0 +1,605 @@
/*
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 <config.h>
#include <string>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <bitset>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#ifdef OS_AIX //AIX
#define _LINUX_SOURCE_COMPAT
#include <sys/scsi.h>
#include <sys/scsi_buf.h>
#include <sys/tape.h>
#include <sys/Atape.h>
#define SCSI_TIMEOUT 5
#else //Linux
#include <scsi/sg.h>
#include <scsi/scsi.h>
#define SCSI_TIMEOUT 5000
#include <stdlib.h>
#include <string.h>
#include <fstream>
#endif
#include <sys/mtio.h>
#include "scsiencrypt.h"
#define SSP_SPIN_OPCODE 0XA2
#define SSP_SPOUT_OPCODE 0XB5
#define SSP_SP_CMD_LEN 12
#define SSP_SP_PROTOCOL_TDE 0X20
#define BSINTTOCHAR(x) (unsigned char)((x & 0xff000000)>>24), (unsigned char)((x & 0x00ff0000)>>16),(unsigned char)((x & 0x0000ff00)>>8),(unsigned char)(x & 0x000000ff)
using namespace std;
void byteswap(unsigned char* array,int size,int value);
bool moveTape(std::string tapeDevice,int count,bool dirForward);
void outputSense(SCSI_PAGE_SENSE* sd);
void readIOError(int err);
bool SCSIExecute(string tapedevice, unsigned char* cmd_p,int cmd_len,unsigned char* dxfer_p,int dxfer_len, bool cmd_to_device, bool show_error);
typedef struct { //structure for setting data encryption
unsigned char pageCode [2];
unsigned char length [2];
#ifdef SWAPBIT
unsigned char scope :3;
unsigned char res_bits_1 :4;
unsigned char lock :1;
#else
unsigned char lock :1;
unsigned char res_bits_1 :4;
unsigned char scope :3;
#endif
#ifdef SWAPBIT
unsigned char CEEM :2;
unsigned char RDMC :2;
unsigned char sdk :1;
unsigned char ckod :1;
unsigned char ckorp :1;
unsigned char ckorl :1;
#else
unsigned char ckorl :1;
unsigned char ckorp :1;
unsigned char ckod :1;
unsigned char sdk :1;
unsigned char RDMC :2;
unsigned char CEEM :2;
#endif
unsigned char encryptionMode;
unsigned char decryptionMode;
unsigned char algorithmIndex;
unsigned char keyFormat;
unsigned char res_bits_2 [8];
unsigned char keyLength [2];
unsigned char keyData [SSP_KEY_LENGTH];
} SSP_PAGE_SDE;
unsigned char
scsi_sense_command[6]={
0x03,
0,0,0,
sizeof(SCSI_PAGE_SENSE),
0
},
scsi_inq_command[6] = {
0x12,
0,0,0,
sizeof(SCSI_PAGE_INQ),
0
},
spin_des_command [SSP_SP_CMD_LEN] = {
SSP_SPIN_OPCODE,
SSP_SP_PROTOCOL_TDE,
0,
0X20,
0,0,
BSINTTOCHAR(sizeof(SSP_PAGE_BUFFER)),
0,0
},
spin_nbes_command [SSP_SP_CMD_LEN] = {
SSP_SPIN_OPCODE,
SSP_SP_PROTOCOL_TDE,
0,
0X21,
0,0,
BSINTTOCHAR(sizeof(SSP_PAGE_BUFFER)),
0,0
};
//Gets encryption options on the tape drive
SSP_DES* SSPGetDES(string tapeDevice){
SSP_PAGE_BUFFER buffer;
memset(&buffer,0,sizeof(SSP_PAGE_BUFFER));
if(!SCSIExecute(tapeDevice,
(unsigned char*)&spin_des_command,
sizeof(spin_des_command),
(unsigned char*)&buffer,
sizeof(SSP_PAGE_BUFFER),
false,true))
{
return NULL;
}
SSP_DES* status=new SSP_DES(&buffer);
return status;
}
//Gets encryption options on the tape drive
SSP_NBES* SSPGetNBES(string tapeDevice,bool retry){
SSP_PAGE_BUFFER buffer;
memset(&buffer,0,sizeof(SSP_PAGE_BUFFER));
if(!SCSIExecute(tapeDevice,
(unsigned char*)&spin_nbes_command,
sizeof(spin_nbes_command),
(unsigned char*)&buffer,
sizeof(SSP_PAGE_BUFFER),
false,false))
{
return NULL;
}
SSP_NBES* status=new SSP_NBES(&buffer);
if(status->nbes.encryptionStatus==0x01 && retry){
//move to the start of the tape and try again
int moves=0;
while(true){
if(status==NULL)break;
if(status->nbes.encryptionStatus!=0x01)break;
if(moves>=MAX_TAPE_READ_BLOCKS)break;
delete status;
if(!moveTape(tapeDevice,1,true))break;
moves++;
status=SSPGetNBES(tapeDevice,false);
}
moveTape(tapeDevice,moves,false);
}
return status;
}
//Sends and inquiry to the device
SCSI_PAGE_INQ* SCSIGetInquiry(string tapeDevice){
SCSI_PAGE_INQ* status=new SCSI_PAGE_INQ;
memset(status,0,sizeof(SCSI_PAGE_INQ));
if(!SCSIExecute(tapeDevice,
(unsigned char*)&scsi_inq_command,
sizeof(scsi_inq_command),
(unsigned char*)status,
sizeof(SCSI_PAGE_INQ),
false,true))
{
exit(EXIT_FAILURE);
}
return status;
}
//Writes encryption options to the tape drive
bool SCSIWriteEncryptOptions(string tapeDevice, SCSIEncryptOptions* eOptions){
char buffer[1024];
memset(&buffer,0,1024);
SSP_PAGE_SDE options;
//copy the template over the options
memset(&options,0, sizeof(SSP_PAGE_SDE));
byteswap((unsigned char*)&options.pageCode,2,0x10);
int pagelen=sizeof(SSP_PAGE_SDE);
options.scope=2; //all IT nexus = 10b
options.RDMC=eOptions->rdmc;
options.ckod=(eOptions->CKOD)?1:0;
options.CEEM=DEFAULT_CEEM;
options.algorithmIndex=eOptions->algorithmIndex;
//set the specific options
switch(eOptions->cryptMode){
case CRYPTMODE_ON: //encrypt, read only encrypted data
options.encryptionMode=2;
options.decryptionMode=2;
break;
case CRYPTMODE_MIXED: //encrypt, read all data
options.encryptionMode=2;
options.decryptionMode=3;
break;
case CRYPTMODE_RAWREAD:
options.encryptionMode=2;
options.decryptionMode=1;
break;
default:
byteswap((unsigned char*)options.keyLength,2,DEFAULT_KEYSIZE);
eOptions->cryptoKey=""; //blank the key
eOptions->keyName=""; //blank the key name, not supported when turned off
break;
}
if(eOptions->cryptoKey!=""){
//byte swap the keylength
byteswap((unsigned char*)&options.keyLength,2,eOptions->cryptoKey.size());
//copy the crypto key into the options
eOptions->cryptoKey.copy((char*)&options.keyData, eOptions->cryptoKey.size(),0);
}
//create the key descriptor
if(eOptions->keyName!=""){
SSP_KAD kad;
kad.type=0x00;
kad.authenticated=0;
//set the descriptor length to the length of the keyName
byteswap((unsigned char*)&kad.descriptorLength,2,eOptions->keyName.size());
//get the size of the kad object
int kadlen=eOptions->keyName.size()+SSP_KAD_HEAD_LENGTH;
//increment the SPOUT page len
pagelen+=kadlen;
//increase the page size
eOptions->keyName.copy((char*)&kad.descriptor,eOptions->keyName.size(),0);
//copy the kad after the SDE command
memcpy(&buffer[sizeof(SSP_PAGE_SDE)],&kad,kadlen);
}
//update the pagelen in options
byteswap((unsigned char*)&options.length,2,pagelen-4); //set the page length, minus the length and pageCode
//copy the options to the beginning of the buffer
memcpy(&buffer,&options,sizeof(SSP_PAGE_SDE));
unsigned char spout_sde_command [SSP_SP_CMD_LEN] = {
SSP_SPOUT_OPCODE,
SSP_SP_PROTOCOL_TDE,
0,
0X10,
0,0,
BSINTTOCHAR(pagelen),
0,0
};
//return whether or not the command executed
return SCSIExecute(
tapeDevice,
(unsigned char*)&spout_sde_command,
sizeof(spout_sde_command),
(unsigned char*)&buffer,
pagelen,
true,true
);
}
bool SCSIExecute(string tapedrive, unsigned char* cmd_p,int cmd_len,unsigned char* dxfer_p,int dxfer_len, bool cmd_to_device, bool show_error)
{
const char* tapedevice=tapedrive.c_str();
int sg_fd,eresult,sresult;
SCSI_PAGE_SENSE* sd=new SCSI_PAGE_SENSE;
memset(sd,0,sizeof(SCSI_PAGE_SENSE));
#ifdef OS_AIX //AIX System
errno=0;
sg_fd = openx((char*)tapedevice, O_RDONLY , NULL, SC_DIAGNOSTIC);
if(!sg_fd || sg_fd==-1){
cerr<<"Could not open device '"<<tapedevice<<"'"<<endl;
exit(EXIT_FAILURE);
}
struct sc_iocmd cmdio;
memset(&cmdio,0,sizeof (struct sc_iocmd));
//copy the command bytes into the first part of the structure
memcpy(&cmdio.scsi_cdb,cmd_p,cmd_len);
cmdio.buffer=(char*)dxfer_p;
cmdio.timeout_value=SCSI_TIMEOUT;
cmdio.command_length=cmd_len;
cmdio.data_length=dxfer_len;
cmdio.status_validity=SC_SCSI_ERROR;
cmdio.flags=(cmd_to_device)?B_WRITE:B_READ;
errno=0;
eresult=ioctl(sg_fd, STIOCMD, &cmdio);
sresult=(int)cmdio.scsi_bus_status;
if(eresult!=0 && show_error){
readIOError(errno);
}
if(sresult==SC_CHECK_CONDITION){ //get the sense data
struct sc_iocmd scmdio;
memset(&scmdio,0,sizeof (struct sc_iocmd));
//copy the command bytes into the first part of the structure
memcpy(&scmdio.scsi_cdb,&scsi_sense_command,sizeof(scsi_sense_command));
scmdio.buffer=(char*)sd;
scmdio.timeout_value=SCSI_TIMEOUT;
scmdio.command_length=sizeof(scsi_sense_command);
scmdio.data_length=sizeof(SCSI_PAGE_SENSE);
scmdio.status_validity=SC_SCSI_ERROR;
scmdio.flags=B_READ;
errno=0;
if(!ioctl(sg_fd, STIOCMD, &scmdio)){
if(show_error)
outputSense(sd);
}else{
if(show_error){
cout<<"Error retrieving sense: ";
readIOError(errno);
}
}
}
#else //Linux routine
errno=0;
sg_fd = open(tapedevice, O_RDONLY);
if( sg_fd==-1){
cerr<<"Could not open device '"<<tapedevice<<"': ";
readIOError(errno);
exit(EXIT_FAILURE);
}
sg_io_hdr_t cmdio;
memset(&cmdio,0,sizeof(sg_io_hdr_t));
cmdio.cmd_len = cmd_len;
cmdio.dxfer_direction =(cmd_to_device)?SG_DXFER_TO_DEV:SG_DXFER_FROM_DEV;
cmdio.dxfer_len = dxfer_len;
cmdio.dxferp = dxfer_p;
cmdio.cmdp = cmd_p;
cmdio.sbp = (unsigned char*)sd;
cmdio.mx_sb_len=sizeof(SCSI_PAGE_SENSE);
cmdio.timeout = SCSI_TIMEOUT;
cmdio.interface_id = 'S';
errno=0;
eresult=ioctl(sg_fd, SG_IO, &cmdio);
if(eresult!=0){
readIOError(errno);
}
sresult=cmdio.status;
if(sresult!=0 && show_error){
outputSense(sd);
}
#endif
#ifdef DEBUGSCSI
cout<<"SCSI Command: ";
for(int i=0;i<cmd_len;i++){
cout<<HEX(cmd_p[i]);
}
cout<<endl;
cout<<"SCSI Data: ";
for(int i=0;i<dxfer_len;i++){
cout<<HEX(dxfer_p[i]);
}
cout<<endl;
#endif
close(sg_fd);
delete sd;
if(eresult!=0||sresult!=0){
return false;
}
return true;
}
void byteswap(unsigned char* array,int size,int value){
switch(size){
case 2:
array[0]=(unsigned char)((value & 0xff00)>>8);
array[1]=(unsigned char)(value & 0x00ff);
break;
case 4:
array[0]=(unsigned char)((value & 0xff000000)>>24);
array[1]=(unsigned char)((value & 0x00ff0000)>>16);
array[2]=(unsigned char)((value & 0x0000ff00)>>8);
array[3]=(unsigned char)(value & 0x000000ff);
break;
default:
cout<<"Unhandled byte swap length of "<<size<<endl;
break;
}
}
SCSIEncryptOptions::SCSIEncryptOptions(){
cryptMode=CRYPTMODE_OFF;
algorithmIndex=DEFAULT_ALGORITHM;
cryptoKey="";
CKOD=false;
keyName="";
rdmc=RDMC_DEFAULT;
}
SSP_NBES::SSP_NBES(SSP_PAGE_BUFFER* buffer){
memset(&nbes,0,sizeof(SSP_PAGE_NBES));
memcpy(&nbes,buffer,sizeof(SSP_PAGE_NBES));
loadKADs(buffer,sizeof(SSP_PAGE_NBES));
}
SSP_DES::SSP_DES(SSP_PAGE_BUFFER* buffer){
memset(&des,0,sizeof(SSP_PAGE_DES));
memcpy(&des,buffer,sizeof(SSP_PAGE_DES));
loadKADs(buffer,sizeof(SSP_PAGE_DES));
}
void KAD_CLASS::loadKADs(SSP_PAGE_BUFFER* buffer, int start){
char* rawbuff=(char*)buffer;
int length=BSSHORT(buffer->length)+4;
int pos=start;
while(pos<length){
SSP_KAD kad;
memset(&kad,0,sizeof(SSP_KAD));
memcpy(&kad,rawbuff+pos,SSP_KAD_HEAD_LENGTH);
pos+=SSP_KAD_HEAD_LENGTH;
if(pos>=length)break;
unsigned short kadDesLen=BSSHORT(kad.descriptorLength);
if(kadDesLen>0){
memcpy(&kad.descriptor,rawbuff+pos,kadDesLen);
pos+=kadDesLen;
}else pos++;
kads.push_back(kad);
}
}
bool moveTape(std::string tapeDevice,int count,bool dirForward){
struct mtop mt_command;
int sg_fd = open(tapeDevice.c_str(), O_RDONLY);
if(!sg_fd || sg_fd==-1){
return false;
}
errno=0;
bool retval=true;
#ifdef OS_LINUX
mt_command.mt_op = (dirForward)?MTFSR:MTBSR;
mt_command.mt_count = count;
ioctl(sg_fd, MTIOCTOP, &mt_command);
#else
mt_command.st_op = (dirForward)?MTFSR:MTBSR;
mt_command.st_count = count;
ioctl(sg_fd, STIOCTOP, &mt_command);
#endif
if(errno!=0)retval=false;
close(sg_fd);
errno=0;
return retval;
}
void readIOError(int err){
if(err==0)return;
cerr<<"ERROR: ";
switch(err){
case EAGAIN:
cerr<<"Device already open"<<endl;
break;
case EBUSY:
cerr<<"Device Busy"<<endl;
break;
case ETIMEDOUT:
cerr<<"Device operation timed out"<<endl;
break;
case EIO:
cerr<<"Device I/O Error."<<endl;
break;
case EPERM:
cerr<<"You do not have privileges to do this. Are you root?"<<endl;
break;
#ifdef OS_AIX
case EBADF:
cerr<<"EBADF"<<endl;
break;
case EFAULT:
cerr<<"EFAULT"<<endl;
break;
case EINTR:
cerr<<"EINTR"<<endl;
break;
case EINVAL:
cerr<<"Invalid device"<<endl;
break;
case ENOTTY:
cerr<<"ENOTTY"<<endl;
break;
case ENODEV:
cerr<<"Device is not responding"<<endl;
break;
case ENXIO:
cerr<<"ENXIO"<<endl;
break;
#endif
default:
if(errno!=0){
cerr<<"0x"<<hex<<errno<<endl;
}
}
}
void outputSense(SCSI_PAGE_SENSE* sd){
cerr<<left<<setw(25)<<"Sense Code: ";
switch((int)sd->senseKey){
case 0:
cerr<<"No specific error";
break;
case 2:
cerr<<"Device not ready";
break;
case 3:
cerr<<"Medium Error";
break;
case 4:
cerr<<"Hardware Error";
break;
case 5:
cerr<<"Illegal Request";
break;
case 6:
cerr<<"Unit Attention";
break;
case 7:
cerr<<"Data protect";
break;
case 8:
cerr<<"Blank tape";
break;
}
cerr<<" (0x"<<HEX(sd->senseKey)<<")"<<endl;
cerr<<left<<setw(25)<<" ASC:"<<"0x"<<HEX(sd->addSenseCode)<<endl;
cerr<<left<<setw(25)<<" ASCQ:"<<"0x"<<HEX(sd->addSenseCodeQual)<<endl;
if(sd->addSenseLen>0){
cerr<<left<<setw(25)<<" Additional data:"<<"0x";
for(int i=0;i<sd->addSenseLen;i++){
cerr<<HEX(sd->addSenseData[i]);
}
cerr<<endl;
}
#ifdef DEBUGSCSI
cerr<<left<<setw(25)<<" Raw Sense:"<<"0x";
char* rawsense=(char*)sd;
for(int i=0;i<sizeof(SCSI_PAGE_SENSE);i++){
cerr<<HEX(rawsense[i]);
}
cerr<<endl;
#endif
}
+329
View File
@@ -0,0 +1,329 @@
/*
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 <string>
#include <bitset>
#include <vector>
#define SSP_KEY_LENGTH 0X20
#define SSP_DESCRIPTOR_LENGTH 1024
#define SSP_PAGE_DES_LENGTH 24
#define SSP_PAGE_NBES_LENGTH 16
#define SSP_KAD_HEAD_LENGTH 4
#define SSP_PAGE_ALLOCATION 8192
#define SSP_UKAD_LENGTH 0x1e
#define KAD_TYPE_UKAD 0x00
#define KAD_TYPE_AKAD 0x01
#define KAD_TYPE_NONCE 0x02
#define KAD_TYPE_META 0x03
#define RDMC_PROTECT 0x03
#define RDMC_UNPROTECT 0x02
#define RDMC_DEFAULT 0x00
//outputs hex in a 2 digit pair
#define HEX( x ) right<<setw(2)<< setfill('0') << hex << (int)( x )<<setfill(' ')
//macro for a byte swapped short
#define BSSHORT( x ) ((unsigned short)( (x[0]<<8) + x[1] ))
//macro for a byte swapped int
#define BSLONG( x ) ((unsigned int)( (int)( x[0] << 24 ) + (int)( x[1] << 16 ) + (int)( x[2] << 8 ) + (int)( x[3] ) ))
typedef struct {
unsigned char pageCode [2];
unsigned char length [2];
#ifdef SWAPBIT
unsigned char nexusScope :3;
unsigned char res_bits_1 :2;
unsigned char keyScope :3;
#else
unsigned char keyScope :3;
unsigned char res_bits_1 :2;
unsigned char nexusScope :3;
#endif
unsigned char encryptionMode;
unsigned char decryptionMode;
unsigned char algorithmIndex;
unsigned char keyInstance [4];
#ifdef SWAPBIT
unsigned char res_bits_2 :1;
unsigned char parametersControl :3;
unsigned char VCELB :1;
unsigned char CEEMS :2;
unsigned char RDMD :1;
#else
unsigned char RDMD :1;
unsigned char CEEMS :2;
unsigned char VCELB :1;
unsigned char parametersControl :3;
unsigned char res_bits_2 :1;
#endif
unsigned char res_bits_3;
unsigned char ASDKCount [2];
unsigned char res_bits_4 [8];
} SSP_PAGE_DES; //device encryption status page
typedef struct {
unsigned char type;
#ifdef SWAPBIT
unsigned char res_bits_1 :5;
unsigned char authenticated :3;
#else
unsigned char authenticated :3;
unsigned char res_bits_1 :5;
#endif
unsigned char descriptorLength [2];
unsigned char descriptor [SSP_DESCRIPTOR_LENGTH]; //will actually be the size of descriptorLength
} SSP_KAD;
typedef struct{
unsigned char pageCode [2];
unsigned char length [2];
unsigned char buffer [SSP_PAGE_ALLOCATION];
} SSP_PAGE_BUFFER; //generic ssp page buffer
typedef struct {
unsigned char pageCode [2];
unsigned char length [2];
unsigned char log_obj_num [8];
#ifdef SWAPBIT
unsigned char compressionStatus :4;
unsigned char encryptionStatus :4;
#else
unsigned char encryptionStatus :4;
unsigned char compressionStatus :4;
#endif
unsigned char algorithmIndex;
#ifdef SWAPBIT
unsigned char res_bits_1 :6;
unsigned char EMES :1;
unsigned char RDMDS :1;
#else
unsigned char RDMDS :1;
unsigned char EMES :1;
unsigned char res_bits_1 :6;
#endif
unsigned char res_bits_2;
} SSP_PAGE_NBES; //next block encryption status page
typedef struct{
#ifndef SWAPBIT
unsigned char peripheralQualifier :3;
unsigned char periphrealDeviceType :5;
#else
unsigned char periphrealDeviceType :5;
unsigned char peripheralQualifier :3;
#endif
#ifndef SWAPBIT
unsigned char RMB :1;
unsigned char res_bits_1 :7;
#else
unsigned char res_bits_1 :7;
unsigned char RMB :1;
#endif
unsigned char Version [1];
#ifndef SWAPBIT
unsigned char obs_bits_1 :2;
unsigned char NORMACA :1;
unsigned char HISUP :1;
unsigned char responseDataFormat :4;
#else
unsigned char responseDataFormat :4;
unsigned char HISUP :1;
unsigned char NORMACA :1;
unsigned char obs_bits_1 :2;
#endif
unsigned char additionalLength [1];
#ifndef SWAPBIT
unsigned char SCCS :1;
unsigned char ACC :1;
unsigned char TPGS :2;
unsigned char threePC :1;
unsigned char res_bits_2 :2;
unsigned char protect :1;
#else
unsigned char protect :1;
unsigned char res_bits_2 :2;
unsigned char threePC :1;
unsigned char TPGS :2;
unsigned char ACC :1;
unsigned char SCCS :1;
#endif
#ifndef SWAPBIT
unsigned char obs_bits_2 :1;
unsigned char ENCSERV :1;
unsigned char VS :1;
unsigned char MULTIP :1;
unsigned char MCHNGR :1;
unsigned char obs_bits_3 :2;
unsigned char ADDR16 :1;
#else
unsigned char ADDR16 :1;
unsigned char obs_bits_3 :2;
unsigned char MCHNGR :1;
unsigned char MULTIP :1;
unsigned char VS :1;
unsigned char ENCSERV :1;
unsigned char obs_bits_2 :1;
#endif
#ifndef SWAPBIT
unsigned char obs_bits_4 :2;
unsigned char WBUS16 :1;
unsigned char SYNC :1;
unsigned char obs_bits_5 :2;
unsigned char CMDQUE :1;
unsigned char VS2 :1;
#else
unsigned char VS2 :1;
unsigned char CMDQUE :1;
unsigned char obs_bits_5 :2;
unsigned char SYNC :1;
unsigned char WBUS16 :1;
unsigned char obs_bits_4 :2;
#endif
unsigned char vender [8];
unsigned char productID [16];
unsigned char productRev [4];
unsigned char SN [7];
unsigned char venderUnique [12];
#ifndef SWAPBIT
unsigned char res_bits_3 :4;
unsigned char CLOCKING :2;
unsigned char QAS :1;
unsigned char IUS :1;
#else
unsigned char IUS :1;
unsigned char QAS :1;
unsigned char CLOCKING :2;
unsigned char res_bits_3 :4;
#endif
unsigned char res_bits_4 [1];
unsigned char versionDescriptor [16];
unsigned char res_bits_5 [22];
unsigned char copyright [1];
} SCSI_PAGE_INQ; //device inquiry response
typedef struct{
#ifdef SWAPBIT
unsigned char valid :1;
unsigned char responseCode :7;
#else
unsigned char responseCode :7;
unsigned char valid :1;
#endif
unsigned char res_bits_1;
#ifdef SWAPBIT
unsigned char filemark :1;
unsigned char EOM :1;
unsigned char ILI :1;
unsigned char res_bits_2 :1;
unsigned char senseKey :4;
#else
unsigned char senseKey :4;
unsigned char res_bits_2 :1;
unsigned char ILI :1;
unsigned char EOM :1;
unsigned char filemark :1;
#endif
unsigned char information [4];
unsigned char addSenseLen;
unsigned char cmdSpecificInfo [4];
unsigned char addSenseCode;
unsigned char addSenseCodeQual;
unsigned char fieldRepUnitCode;
#ifdef SWAPBIT
unsigned char sim :3; // system information message
unsigned char bpv :1; // bit pointer valid
unsigned char resvd2 :2; // reserved
unsigned char cd :1; // control/data
unsigned char SKSV :1;
#else
unsigned char SKSV :1;
unsigned char cd :1; // control/data
unsigned char resvd2 :2; // reserved
unsigned char bpv :1; // bit pointer valid
unsigned char sim :3; // system information message
#endif
unsigned char field [2]; // field pointer
unsigned char addSenseData [109];
} SCSI_PAGE_SENSE; //sense data response
class KAD_CLASS{
public:
std::vector<SSP_KAD> kads;
protected:
void loadKADs(SSP_PAGE_BUFFER* buffer, int start);
};
//class used to parse next block encryption status page
class SSP_NBES: public KAD_CLASS{
public:
SSP_PAGE_NBES nbes;
SSP_NBES(SSP_PAGE_BUFFER* buffer);
};
//class used to parse data encryption status page
class SSP_DES: public KAD_CLASS{
public:
SSP_PAGE_DES des;
SSP_DES(SSP_PAGE_BUFFER* buffer);
};
//enum for SCSIEncryptOptions.cryptMode
enum { CRYPTMODE_OFF, CRYPTMODE_MIXED,CRYPTMODE_ON,CRYPTMODE_RAWREAD};
//used to pass parameters to SCSIWriteEncryptOptions
class SCSIEncryptOptions {
public:
int rdmc;
bool CKOD;
int cryptMode;
unsigned int algorithmIndex;
std::string cryptoKey;
std::string keyName;
SCSIEncryptOptions();
};
//Gets encryption options on the tape drive
SSP_DES* SSPGetDES(std::string tapeDevice);
//Gets the encryption status from the tape volume
SSP_NBES* SSPGetNBES(std::string tapeDevice,bool retry);
//Writes encryption options to the tape drive
bool SCSIWriteEncryptOptions(std::string tapeDevice, SCSIEncryptOptions* eOptions);
//Gets device inquiry
SCSI_PAGE_INQ* SCSIGetInquiry(std::string tapeDevice);
#endif