[med-svn] [Git][med-team/libsecrecy][upstream] New upstream version 0.0.5+ds

Étienne Mollier (@emollier) gitlab at salsa.debian.org
Sat Oct 23 22:57:21 BST 2021



Étienne Mollier pushed to branch upstream at Debian Med / libsecrecy


Commits:
d9b3411b by Étienne Mollier at 2021-10-23T23:40:04+02:00
New upstream version 0.0.5+ds
- - - - -


12 changed files:

- ChangeLog
- configure.ac
- release.sh
- src/Makefile.am
- + src/apps/secrecy.1
- src/apps/secrecy.cpp
- src/libsecrecy/AESEncryptKey.hpp
- src/libsecrecy/GCMFactoryBase.hpp
- src/libsecrecy/GCMStreamHeader.hpp
- src/libsecrecy/RawKey.hpp
- + src/libsecrecy/SecrecyKeyValueStore.hpp
- − src/libsecrecy/libsecrecy.hpp


Changes:

=====================================
ChangeLog
=====================================
@@ -1,3 +1,24 @@
+libsecrecy (0.0.5-1) unstable; urgency=medium
+
+  * Update email address of Étienne Mollier in the manual page for secrecy
+  * Add manual page for secrecy app kindly provided by Étienne Mollier.
+
+ -- German Tischler-Höhle <germant at miltenyibiotec.de>  Tue, 14 Sep 2021 09:29:12 +0200
+
+libsecrecy (0.0.4-1) unstable; urgency=medium
+
+  * Avoid object copying in SecrecyKeyValueStore during map traversal
+
+ -- German Tischler-Höhle <germant at miltenyibiotec.de>  Mon, 13 Sep 2021 13:01:43 +0200
+
+libsecrecy (0.0.3-1) unstable; urgency=medium
+
+  * Remove autogenerated file
+  * Avoid object copying in GCMStreamHeader
+  * Check for existence of key directory when listing keys (output empty list instead of failing with an exception)
+
+ -- German Tischler-Höhle <germant at miltenyibiotec.de>  Mon, 13 Sep 2021 12:34:49 +0200
+
 libsecrecy (0.0.2-1) unstable; urgency=medium
 
   * Implement key caching infrastructure


=====================================
configure.ac
=====================================
@@ -1,5 +1,5 @@
-AC_INIT(libsecrecy,0.0.2,[germant at miltenyibiotec.de],[libsecrecy],[https://gitlab.com/german.tischler/libsecrecy])
-LIBRARY_VERSION=0:2:0
+AC_INIT(libsecrecy,0.0.5,[germant at miltenyibiotec.de],[libsecrecy],[https://gitlab.com/german.tischler/libsecrecy])
+LIBRARY_VERSION=0:5:0
 AC_MSG_NOTICE([Configuring for source in directory ${srcdir}])
 AC_CANONICAL_SYSTEM
 AC_CANONICAL_HOST


=====================================
release.sh
=====================================
@@ -1,4 +1,5 @@
 #! /bin/bash
+set -e
 
 # update branches
 git checkout experimental


=====================================
src/Makefile.am
=====================================
@@ -11,6 +11,10 @@ lib_LTLIBRARIES = # libsecrecy.la
 
 noinst_HEADERS = # 
 
+MANPAGES = apps/secrecy.1
+man_MANS = ${MANPAGES}
+EXTRA_DIST = ${MANPAGES}
+
 #libsecrecy_la_CPPFLAGS = ${AM_CPPFLAGS} @LIBSECRECYCPPFLAGS@ @ZLIBCPPFLAGS@ @NETTLECPPFLAGS@ @GPGMECPPFLAGS@ @LIBDEFLATECPPFLAGS@
 #libsecrecy_la_CXXFLAGS = @LIBSECRECYCXXFLAGS@ ${AM_CXXFLAGS} @WARNCXXFLAGS@
 #libsecrecy_la_LDFLAGS = @LIBSECRECYLDFLAGS@ -version-info ${LIBRARY_VERSION} @NETTLELDFLAGS@ @GPGMELDFLAGS@ @LIBDEFLATELDFLAGS@
@@ -43,6 +47,7 @@ libsecrecy_include_HEADERS=\
 	libsecrecy/LockedMemory.hpp \
 	libsecrecy/NumToHex.hpp \
 	libsecrecy/RawKey.hpp \
+	libsecrecy/SecrecyKeyValueStore.hpp \
 	libsecrecy/Yarrow.hpp
 	
 EXTRA_PROGRAMS = # 


=====================================
src/apps/secrecy.1
=====================================
@@ -0,0 +1,262 @@
+.TH SECRECY 1 2020-11-13 GNU "User's Manual"
+.SH NAME
+.B secrecy
+\- libsecrecy encryption and key management tool
+.SH SYNOPSIS
+.B secrecy createKey
+.I cipher gpgid keyname
+.PP
+.B secrecy encrypt
+.RI [ keyhash | keyname ]
+.PP
+.B secrecy decrypt
+.PP
+.B secrecy exportKey
+.RI [ keyhash | keyname ]
+.I gpgid
+.PP
+.B secrecy importKey
+.I gpgid
+.PP
+.B secrecy listKeys
+.PP
+.B secrecy setDefaultKey
+.I keyname
+.SH DESCRIPTION
+.PP
+The
+.B libsecrecy
+distribution comes with a command line tool called
+.BR secrecy .
+This tool currently has seven subcommands:
+.BR createKey ,
+.BR encrypt ,
+.BR decrypt ,
+.BR exportKey ,
+.BR importKey ,
+.B listKeys
+and
+.BR setDefaultKey .
+.PP
+The program
+.B secrecy
+accepts several subcommands.
+It is to be noted that, currently,
+.B secrecy
+has no arguments for reading and writing any file.
+One has to rely on the shell capabilities to read and write plain files,
+encrypted files,
+and key exports,
+using pipes and redirection operators.
+Subcommands are the following:
+.TP
+\fBsecrecy createKey\fI cipher gpgid keyname\fR
+create keys for the
+.BR libsecrecy ,
+where
+.I cipher
+can currently take the values
+.BR AES128 ,
+.B AES192
+or
+.BR AES256 ,
+.I gpgid
+needs to be a valid id (normally an email address) present as a secret key in
+.BR gpg (1)'s
+keyring,
+which can be used for securely storing the AES key for use by
+.BR libsecrecy ,
+and
+.I keyname
+can be chosen as a human readable name for the key created,
+for instance "mykey".
+The program outputs a key hash in the form of a hexadecimal encoded string.
+Either this key hash or the key name given can to be provided to the encrypt command of
+.B secrecy
+for encrypting files using the newly created key.
+.TP
+\fBsecrecy encrypt\fR [\fIkeyhash\fR|\fIkeyname\fR]
+This subcommand allows one to encrypt files.
+.IR keyhash / keyname
+is either the hexadecimal string which was printed by
+.B createKey
+when creating the key,
+or the name given to
+.B createKey
+when creating the key.
+If the string provided is empty,
+then the default key name is used if any has been set;
+see
+.BR setDefaultKey .
+Note that this command needs to decrypt the key from it's
+.BR gpg (1)
+encoded form,
+so you will need to provide the respective passphrase in some form.
+.TP
+\fBsecrecy decrypt\fR
+This subcommand allows one to decrypt files.
+It needs to decrypt the key from it's
+.BR gpg (1)
+encoded form,
+so you will need to provide the respective passphrase in some form.
+Note that you do not need to provide the
+.I keyhash
+for decryption as this information is provided inside the encrypted file..
+.TP
+\fBsecrecy exportKey\fR [\fIkeyname\fR|\fIkeyhash\fR] \fIgpgid\fR
+Export to an encrypted transfer format,
+for passing data on to third parties,
+via the
+.B exportKey
+command of
+.BR secrecy .
+.I keyname
+or
+.I keyhash
+are valid key name or hash respectively,
+and
+.I gpgid
+is a string identifying the recipient of the key.
+The public key of
+.I gpgid
+needs to be available in
+.BR gpg 's
+key database.
+.TP
+\fBsecrecry importKey \fIgpgid\fR
+Import a key from the format produced by the
+.B exportKey
+command using the
+.B importKey
+command,
+where
+.I gpgid
+designates the
+.B gpg
+key which will be used to locally encrypt the key for storing it in
+.BR libsecrecy 's
+database.
+.TP
+.B secrecy listKeys
+List installed keys.  It prints a tabulation separated table such that the first column contains the key names and the second the respective key hash values.
+.TP
+\fBsecrecy setDefaultKey \fIkeyname\fR
+Change the default key.  The default key is used when an empty
+.I keyname
+is used for running any command accepting a key name,
+with the obvious exceptions of
+.B createKey
+and
+.BR setDefaultKey .
+.PP
+.SH FILES
+.PP
+AES keys are stored encrypted using
+.BR gpg (1)
+via
+.BR gpgme .
+Each key is assigned a hash
+.I H
+value at creation time.
+.I H
+is computed as the SHA256 checksum of a randomly generated sequence.
+Keys are stored and searched for in the directory set in the environment variable
+.IR LIBSECRECY_KEYDIR .
+If this variable is not set,
+then the subdirectory
+.B .libsecrecy
+inside the current users home directory,
+designated by the environment variable
+.IR HOME ,
+is used.
+Inside this directory the key for hash
+.I H
+is stored in the file
+.BR hash/H ,
+otherwise said:
+.BR hash/3E35C013C66C66B09E3E0B923451530C62D4346D9F5165906FC94B9B4D35E28E ,
+where the respective files are encrypted using
+.BR gpgme .
+The secret key used for this encryption can be set at key creation time.
+.PP
+.SH EXAMPLES
+.PP
+Create an
+.I AES256
+key using your GPG ID,
+for instance
+.IR foo at example.org ,
+and call it
+.IR mykey :
+.PP
+.EX
+        $ secrecy createKey AES256 foo at example.org mykey
+        3E35C013C66C66B09E3E0B923451530C62D4346D9F5165906FC94B9B4D35E28E
+.EE
+.PP
+List available keys:
+.PP
+.EX
+        $ secrecy listKeys
+        mykey	3E35C013C66C66B09E3E0B923451530C62D4346D9F5165906FC94B9B4D35E28E
+.EE
+.PP
+Set
+.I mykey
+as default key:
+.PP
+.EX
+        $ secrecy setDefaultKey mykey
+.EE
+.PP
+Encrypt
+.I file
+into
+.IR file.encrypted ,
+using the default key:
+.PP
+.EX
+        $ secrecy encrypt < file > file.encrypted
+.EE
+.PP
+Decrypt
+.I file.encrypted
+into
+.IR file.decrypted ,
+using the default key:
+.PP
+.EX
+        $ secrecy decrypt < file.encrypted > file.decrypted
+.EE
+.PP
+Prepare an export of
+.I mykey
+for use by the person behind GPG ID
+.IR bar at example.org ,
+whose public key should be accessible in the user's
+.BR gpg (1)
+keyring.
+The key will be exported into the file
+.IR export.key :
+.PP
+.EX
+        $ secrecy exportKey mykey bar at example.org > export.key
+.EE
+.PP
+.SH AUTHORS
+.PP
+.B secrecy
+is a program part of the
+.BR libsecrecy ,
+written by German Tischler-Höhle <germant at miltenyibiotec.de>.
+.PP
+The present manual page is written by Étienne Mollier <emollier at debian.org> for the Debian project.
+.SH SEE ALSO
+.PP
+See the
+.UR https://gnupg.org/documentation/manuals/gnupg/OpenPGP-Key-Management.html#OpenPGP-Key-Management
+GnuPG documentation relative to key management
+.UE
+for creating and handling
+.BR gpg (1)
+keys.


=====================================
src/apps/secrecy.cpp
=====================================
@@ -50,14 +50,14 @@ void writeKey(std::string const & gpgrecipient, std::string const & keyname)
 	// read back key and check for equality
 	std::string const keyfiledata = libsecrecy::RawKeyBase::readKeyData(hexhash,false /* do not try to resolve name */);
 	std::istringstream keydataistr(keyfiledata);
-	libsecrecy::RawKeyBase::expectMagic(keydataistr);
-	std::string const keycipher = libsecrecy::GCMStreamBase::readString(keydataistr);
-	std::string const rkeyname = libsecrecy::GCMStreamBase::readString(keydataistr);
+
+	std::shared_ptr<libsecrecy::SecrecyKeyValueStore> SKV(libsecrecy::RawKeyBase::loadMetaData(keydataistr));
+	std::string const keycipher = SKV->getStringValue("cipher");
 
 	if ( keycipher != K.getPrefix() )
 		throw std::runtime_error("Decoded key does not match encoded key (wrong cipher)");
 
-	key_type KB(gpgme,keydataistr);
+	key_type KB(gpgme,keydataistr,*SKV);
 
 	bool const eq = (K == KB);
 
@@ -110,12 +110,14 @@ static std::string getExportedKeyMagic()
 }
 
 template<typename key_type>
-void exportKey(std::string const & sgpgid, std::istream & keydataistr, std::string const & keyname)
+void exportKey(std::string const & sgpgid, std::istream & keydataistr, libsecrecy::SecrecyKeyValueStore const & SKV)
 {
 	libsecrecy::GPGMEContext gpgme;
-	key_type KB(gpgme,keydataistr);
+	key_type KB(gpgme,keydataistr,SKV);
 	std::shared_ptr< libsecrecy::LockedMemory<char> > const keyhex = KB.keyToHex();
 
+	std::string const keyname = SKV.getStringValue("keyname");
+
 	std::ostringstream ostr;
 	libsecrecy::GCMStreamBase::writeString(ostr,getExportedKeyMagic());
 	libsecrecy::GCMStreamBase::writeString(ostr,KB.getPrefix());
@@ -180,21 +182,21 @@ int exportKey(char const * progname, int argc, char * argv[])
 	// read back key and check for equality
 	std::string const keyfiledata = libsecrecy::RawKeyBase::readKeyData(skeyname,true /* try to resolve name */);
 	std::istringstream keydataistr(keyfiledata);
-	libsecrecy::RawKeyBase::expectMagic(keydataistr);
-	std::string const keycipher = libsecrecy::GCMStreamBase::readString(keydataistr);
-	std::string const rkeyname = libsecrecy::GCMStreamBase::readString(keydataistr);
+
+	std::shared_ptr<libsecrecy::SecrecyKeyValueStore> SKV(libsecrecy::RawKeyBase::loadMetaData(keydataistr));
+	std::string const keycipher = SKV->getStringValue("cipher");
 
 	if ( keycipher == "AES256" )
 	{
-		exportKey<libsecrecy::AES256EncryptKey>(sgpgid,keydataistr,rkeyname);
+		exportKey<libsecrecy::AES256EncryptKey>(sgpgid,keydataistr,*SKV);
 	}
 	else if ( keycipher == "AES192" )
 	{
-		exportKey<libsecrecy::AES192EncryptKey>(sgpgid,keydataistr,rkeyname);
+		exportKey<libsecrecy::AES192EncryptKey>(sgpgid,keydataistr,*SKV);
 	}
 	else if ( keycipher == "AES128" )
 	{
-		exportKey<libsecrecy::AES128EncryptKey>(sgpgid,keydataistr,rkeyname);
+		exportKey<libsecrecy::AES128EncryptKey>(sgpgid,keydataistr,*SKV);
 	}
 	else
 	{


=====================================
src/libsecrecy/AESEncryptKey.hpp
=====================================
@@ -81,9 +81,9 @@ namespace libsecrecy
 			set_encrypt_key_func(ctx,kptr->get());
 		}
 
-		EncryptKey(libsecrecy::GPGMEContext & context, std::istream & in) : kptr(new raw_key_type), lctx(1), ctx(lctx.get())
+		EncryptKey(libsecrecy::GPGMEContext & context, std::istream & in, SecrecyKeyValueStore const & SKV) : kptr(new raw_key_type), lctx(1), ctx(lctx.get())
 		{
-			kptr->readKey(context,in);
+			kptr->readKey(context,in,SKV);
 			set_encrypt_key_func(ctx,kptr->get());
 		}
 


=====================================
src/libsecrecy/GCMFactoryBase.hpp
=====================================
@@ -41,9 +41,10 @@ namespace libsecrecy
 		{
 			std::string const keyfiledata = RawKeyBase::readKeyData(hexhash,resolve);
 			std::istringstream keydataistr(keyfiledata);
-			RawKeyBase::expectMagic(keydataistr);
-			std::string const scipher = GCMStreamBase::readString(keydataistr);
-			std::string const keyname = GCMStreamBase::readString(keydataistr);
+			std::shared_ptr<libsecrecy::SecrecyKeyValueStore> SKV(libsecrecy::RawKeyBase::loadMetaData(keydataistr));
+			std::string const scipher = SKV->getStringValue("cipher");
+			std::string const skeyname = SKV->getStringValue("keyname");
+
 			std::string keyhex;
 			std::shared_ptr<RawKeyBase> RKB;
 
@@ -52,7 +53,7 @@ namespace libsecrecy
 				typedef AES128EncryptKey key_type;
 				typedef key_type::raw_key_type raw_key_type;
 				std::shared_ptr<RawKeyBase> TRKB(new raw_key_type);
-				dynamic_cast<raw_key_type *>(TRKB.get())->readKey(context,keydataistr);
+				dynamic_cast<raw_key_type *>(TRKB.get())->readKey(context,keydataistr,*SKV);
 				keyhex = dynamic_cast<raw_key_type *>(TRKB.get())->hashToHex();
 				RKB = TRKB;
 			}
@@ -61,7 +62,7 @@ namespace libsecrecy
 				typedef AES192EncryptKey key_type;
 				typedef key_type::raw_key_type raw_key_type;
 				std::shared_ptr<RawKeyBase> TRKB(new raw_key_type);
-				dynamic_cast<raw_key_type *>(TRKB.get())->readKey(context,keydataistr);
+				dynamic_cast<raw_key_type *>(TRKB.get())->readKey(context,keydataistr,*SKV);
 				keyhex = dynamic_cast<raw_key_type *>(TRKB.get())->hashToHex();
 				RKB = TRKB;
 			}
@@ -70,12 +71,12 @@ namespace libsecrecy
 				typedef AES256EncryptKey key_type;
 				typedef key_type::raw_key_type raw_key_type;
 				std::shared_ptr<RawKeyBase> TRKB(new raw_key_type);
-				dynamic_cast<raw_key_type *>(TRKB.get())->readKey(context,keydataistr);
+				dynamic_cast<raw_key_type *>(TRKB.get())->readKey(context,keydataistr,*SKV);
 				keyhex = dynamic_cast<raw_key_type *>(TRKB.get())->hashToHex();
 				RKB = TRKB;
 			}
 
-			return RawKeyObject(RKB,scipher,keyname,keyhex);
+			return RawKeyObject(RKB,scipher,skeyname,keyhex);
 		}
 
 		static RawKeyObject obtainKey(


=====================================
src/libsecrecy/GCMStreamHeader.hpp
=====================================
@@ -26,14 +26,12 @@
 #if ! defined(LIBSECRECY_GCMSTREAMHEADER_HPP)
 #define LIBSECRECY_GCMSTREAMHEADER_HPP
 
-#include <libsecrecy/GCMStreamBase.hpp>
+#include <libsecrecy/SecrecyKeyValueStore.hpp>
 #include <libsecrecy/GCMIV.hpp>
-#include <map>
-#include <vector>
 
 namespace libsecrecy
 {
-	struct GCMStreamHeader : public GCMStreamBase
+	struct GCMStreamHeader : public SecrecyKeyValueStore
 	{
 		std::map<std::string,std::string> M;
 
@@ -46,71 +44,9 @@ namespace libsecrecy
 		{}
 
 		GCMStreamHeader(std::istream & in)
+		: SecrecyKeyValueStore(in,getMagic())
 		{
-			char const * magic = getMagic();
-			while ( *magic )
-			{
-				char const c = getChecked(in);
-				char const e = *(magic++);
-				if ( c != e )
-				{
-					throw std::runtime_error("libsecrecy::GCMStreamHeader: mismatch in file magic");
-				}
-			}
 
-			std::size_t const numfields = readNumber(in);
-
-			for ( std::size_t i = 0; i < numfields; ++i )
-			{
-				std::string const key = readString(in);
-				std::string const value = readString(in);
-				M[key] = value;
-			}
-		}
-
-		std::string toString() const
-		{
-			std::ostringstream ostr;
-			for ( auto const it : M )
-				ostr << "M[" << it.first << "]=" << it.second << "\n";
-			return ostr.str();
-		}
-
-		std::vector<uint8_t> decodeHexField(std::string const & key) const
-		{
-			auto const it = M.find(key);
-
-			if ( it == M.end() )
-				throw std::runtime_error(std::string("libsecrecy::GCMStreamHeader::decodeHexField: key ") + key + " is not present");
-
-			std::string const shex = it->second;
-
-			if ( shex.size() % 2 != 0 )
-			{
-				std::ostringstream ostr;
-				ostr << "libsecrecy::GCMStreamHeader::decodeHexField: value " << shex << " for key " << key << " has uneven length";
-				throw std::runtime_error(ostr.str());
-			}
-
-			std::vector<uint8_t> V;
-			std::string::const_iterator sit = shex.begin();
-			while ( sit != shex.end() )
-			{
-				char const chigh = *(sit++);
-				assert ( sit != shex.end() );
-				char const clow = *(sit++);
-				V.push_back((NumToHex::hexToNum(chigh) << 4) | NumToHex::hexToNum(clow));
-			}
-
-			return V;
-		}
-
-		std::pair < std::shared_ptr<uint8_t[]>, std::size_t > decodeHexFieldAsArray(std::string const & key) const
-		{
-			std::vector<uint8_t> const V(decodeHexField(key));
-			std::shared_ptr<uint8_t[]> ptr(new uint8_t[V.size()]);
-			std::copy(V.begin(),V.end(),ptr.get());
-			return std::make_pair(ptr,V.size());
 		}
 
 		std::pair < std::shared_ptr<uint8_t[]>, std::size_t > getAuthData() const
@@ -130,97 +66,14 @@ namespace libsecrecy
 		{
 			std::size_t r = 0;
 
-			// write magic
-			char const * magic = getMagic();
-			std::size_t const l_magic = strlen(magic);
-			out.write(magic,l_magic);
-			r += l_magic;
-
-			// number of key=value pairs
-			r += writeNumber(out,M.size());
-
-			for ( auto it : M )
-			{
-				r += writeString(out,it.first);
-				r += writeString(out,it.second);
-			}
-
-			if ( ! out )
-			{
-				throw std::runtime_error("libsecrecy::GCMStreamHeader::serialise: failed to write data");
-			}
+			r += SecrecyKeyValueStore::serialise(out,getMagic());
 
 			return r;
 		}
 
 		std::size_t size() const
 		{
-			std::ostringstream ostr;
-			std::size_t const r = serialise(ostr);
-
-			if ( r != ostr.str().size() )
-			{
-				std::ostringstream eostr;
-				eostr << "libsecrecy::GCMStreamHeader::size: mismatch between computed r=" << r << " and actual " << ostr.str().size();
-				throw std::runtime_error(eostr.str());
-			}
-
-			return r;
-		}
-
-		void setStringValue(std::string const & key, std::string const & value)
-		{
-			M[key] = value;
-		}
-
-		template<typename value_type>
-		void setNumericalValue(std::string const & key, value_type const & v)
-		{
-			std::ostringstream ostr;
-			ostr << v;
-			setStringValue(key,ostr.str());
-		}
-
-		std::string getStringValue(std::string const & key) const
-		{
-			auto const it = M.find(key);
-
-			if ( it == M.end() )
-			{
-				std::ostringstream ostr;
-				ostr << "libsecrecy::GCMStreamHeader::getStringValue: field " << key << " is not present";
-				throw std::runtime_error(ostr.str());
-			}
-
-			return it->second;
-		}
-
-		template<typename value_type>
-		value_type getParsedValue(std::string const & key) const
-		{
-			auto const it = M.find(key);
-
-			if ( it == M.end() )
-			{
-				std::ostringstream ostr;
-				ostr << "libsecrecy::GCMStreamHeader::getParsedValue: field " << key << " is not present";
-				throw std::runtime_error(ostr.str());
-			}
-
-			std::istringstream istr(it->second);
-			value_type v;
-			istr >> v;
-
-			if ( istr && istr.peek() == std::istream::traits_type::eof() )
-			{
-				return v;
-			}
-			else
-			{
-				std::ostringstream ostr;
-				ostr << "libsecrecy::GCMStreamHeader::getParsedValue: field " << key << " has unparsable value " << it->second;
-				throw std::runtime_error(ostr.str());
-			}
+			return SecrecyKeyValueStore::size(getMagic());
 		}
 	};
 }


=====================================
src/libsecrecy/RawKey.hpp
=====================================
@@ -29,6 +29,7 @@
 #include <libsecrecy/GPGMEContext.hpp>
 #include <libsecrecy/Yarrow.hpp>
 #include <libsecrecy/GCMStreamBase.hpp>
+#include <libsecrecy/SecrecyKeyValueStore.hpp>
 #include <nettle/aes.h>
 #include <cstdlib>
 #include <filesystem>
@@ -236,17 +237,20 @@ namespace libsecrecy
 		{
 			std::string const keynamedir = getKeyNameDirectory();
 
-			for ( auto const & p : std::filesystem::directory_iterator(keynamedir) )
+			if ( std::filesystem::exists(keynamedir) )
 			{
-				std::filesystem::path const keypath = p.path();
-				std::string hash;
-
-				if ( std::filesystem::exists(keypath) && std::filesystem::is_symlink(keypath) )
+				for ( auto const & p : std::filesystem::directory_iterator(keynamedir) )
 				{
-					hash = static_cast<std::string>(std::filesystem::path(followSymLink(keypath)).filename());
-				}
+					std::filesystem::path const keypath = p.path();
+					std::string hash;
+
+					if ( std::filesystem::exists(keypath) && std::filesystem::is_symlink(keypath) )
+					{
+						hash = static_cast<std::string>(std::filesystem::path(followSymLink(keypath)).filename());
+					}
 
-				out << static_cast<std::string>(keypath.filename()) << "\t" << hash << "\n";
+					out << static_cast<std::string>(keypath.filename()) << "\t" << hash << "\n";
+				}
 			}
 		}
 
@@ -289,6 +293,12 @@ namespace libsecrecy
 			return static_cast<std::string>(curpath);
 		}
 
+		static std::shared_ptr<SecrecyKeyValueStore> loadMetaData(std::istream & in)
+		{
+			std::shared_ptr<SecrecyKeyValueStore> ptr(new SecrecyKeyValueStore(in,getMagic()));
+			return ptr;
+		}
+
 		static std::string readKeyData(std::string hexhash, bool tryname)
 		{
 			if ( !hexhash.size() && tryname )
@@ -391,18 +401,6 @@ namespace libsecrecy
 		{
 			return "LIBSECRECY_KEY";
 		}
-
-		static void expectMagic(std::istream & in)
-		{
-			std::string const magic = GCMStreamBase::readString(in);
-
-			if ( magic != getMagic() )
-			{
-				std::ostringstream estr;
-				estr << "libsecrecy::RawKey::expectMagic: mismatch in file identifier";
-				throw std::runtime_error(estr.str());
-			}
-		}
 	};
 
 	struct RawKeyObject
@@ -619,13 +617,12 @@ namespace libsecrecy
 
 			std::ostringstream sstr;
 
-			GCMStreamBase::writeString(sstr,getMagic());
-			// write prefix / cipher
-			GCMStreamBase::writeString(sstr,cipher);
-			// write name value
-			GCMStreamBase::writeString(sstr,keyname);
-			// write hash value
-			GCMStreamBase::writeString(sstr,hashToHex());
+			SecrecyKeyValueStore SKV;
+			SKV.setStringValue("cipher",cipher);
+			SKV.setStringValue("keyname",keyname);
+			SKV.setStringValue("hash",hashToHex());
+			SKV.serialise(sstr,getMagic());
+
 			// write encrypted key
 			context.encrypt(
 				reinterpret_cast<char const *>(L.begin()),
@@ -681,9 +678,9 @@ namespace libsecrecy
 			std::filesystem::current_path(lcwd);
 		}
 
-		void readKey(libsecrecy::GPGMEContext & context, std::istream & in)
+		void readKey(libsecrecy::GPGMEContext & context, std::istream & in, SecrecyKeyValueStore const & SKV)
 		{
-			std::string const shexhash = GCMStreamBase::readString(in);
+			std::string const shexhash = SKV.getStringValue("hash");
 
 			if ( shexhash.size() != 2*digestsize )
 			{


=====================================
src/libsecrecy/SecrecyKeyValueStore.hpp
=====================================
@@ -0,0 +1,208 @@
+/**
+ * Copyright 2020 German Tischler-Höhle
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ **/
+#if ! defined(LIBSECRECY_SECRECYKEYVALUESTORE_HPP)
+#define LIBSECRECY_SECRECYKEYVALUESTORE_HPP
+
+#include <libsecrecy/GCMStreamBase.hpp>
+#include <map>
+#include <vector>
+
+namespace libsecrecy
+{
+	struct SecrecyKeyValueStore : public GCMStreamBase
+	{
+		std::map<std::string,std::string> M;
+
+		SecrecyKeyValueStore()
+		{}
+		SecrecyKeyValueStore(std::istream & in, std::string const & smagic)
+		{
+			char const * magic = smagic.c_str();
+
+			while ( *magic )
+			{
+				char const c = getChecked(in);
+				char const e = *(magic++);
+				if ( c != e )
+				{
+					throw std::runtime_error("libsecrecy::SecrecyKeyValueStore: mismatch in file magic");
+				}
+			}
+
+			std::size_t const numfields = readNumber(in);
+
+			for ( std::size_t i = 0; i < numfields; ++i )
+			{
+				std::string const key = readString(in);
+				std::string const value = readString(in);
+				M[key] = value;
+			}
+		}
+
+		std::string toString() const
+		{
+			std::ostringstream ostr;
+			for ( auto const & it : M )
+				ostr << "M[" << it.first << "]=" << it.second << "\n";
+			return ostr.str();
+		}
+
+		std::vector<uint8_t> decodeHexField(std::string const & key) const
+		{
+			auto const it = M.find(key);
+
+			if ( it == M.end() )
+				throw std::runtime_error(std::string("libsecrecy::SecrecyKeyValueStore::decodeHexField: key ") + key + " is not present");
+
+			std::string const shex = it->second;
+
+			if ( shex.size() % 2 != 0 )
+			{
+				std::ostringstream ostr;
+				ostr << "libsecrecy::SecrecyKeyValueStore::decodeHexField: value " << shex << " for key " << key << " has uneven length";
+				throw std::runtime_error(ostr.str());
+			}
+
+			std::vector<uint8_t> V;
+			std::string::const_iterator sit = shex.begin();
+			while ( sit != shex.end() )
+			{
+				char const chigh = *(sit++);
+				assert ( sit != shex.end() );
+				char const clow = *(sit++);
+				V.push_back((NumToHex::hexToNum(chigh) << 4) | NumToHex::hexToNum(clow));
+			}
+
+			return V;
+		}
+
+		std::pair < std::shared_ptr<uint8_t[]>, std::size_t > decodeHexFieldAsArray(std::string const & key) const
+		{
+			std::vector<uint8_t> const V(decodeHexField(key));
+			std::shared_ptr<uint8_t[]> ptr(new uint8_t[V.size()]);
+			std::copy(V.begin(),V.end(),ptr.get());
+			return std::make_pair(ptr,V.size());
+		}
+
+		std::size_t serialise(std::ostream & out, std::string const & smagic) const
+		{
+			std::size_t r = 0;
+
+			// write magic
+			char const * magic = smagic.c_str();
+			std::size_t const l_magic = strlen(magic);
+			out.write(magic,l_magic);
+			r += l_magic;
+
+			// number of key=value pairs
+			r += writeNumber(out,M.size());
+
+			for ( auto it : M )
+			{
+				r += writeString(out,it.first);
+				r += writeString(out,it.second);
+			}
+
+			if ( ! out )
+			{
+				throw std::runtime_error("libsecrecy::SecrecyKeyValueStore::serialise: failed to write data");
+			}
+
+			return r;
+		}
+
+		std::size_t size(std::string const & smagic) const
+		{
+			std::ostringstream ostr;
+			std::size_t const r = serialise(ostr,smagic);
+
+			if ( r != ostr.str().size() )
+			{
+				std::ostringstream eostr;
+				eostr << "libsecrecy::SecrecyKeyValueStore::size: mismatch between computed r=" << r << " and actual " << ostr.str().size();
+				throw std::runtime_error(eostr.str());
+			}
+
+			return r;
+		}
+
+		void setStringValue(std::string const & key, std::string const & value)
+		{
+			M[key] = value;
+		}
+
+		template<typename value_type>
+		void setNumericalValue(std::string const & key, value_type const & v)
+		{
+			std::ostringstream ostr;
+			ostr << v;
+			setStringValue(key,ostr.str());
+		}
+
+		std::string getStringValue(std::string const & key) const
+		{
+			auto const it = M.find(key);
+
+			if ( it == M.end() )
+			{
+				std::ostringstream ostr;
+				ostr << "libsecrecy::SecrecyKeyValueStore::getStringValue: field " << key << " is not present";
+				throw std::runtime_error(ostr.str());
+			}
+
+			return it->second;
+		}
+
+		template<typename value_type>
+		value_type getParsedValue(std::string const & key) const
+		{
+			auto const it = M.find(key);
+
+			if ( it == M.end() )
+			{
+				std::ostringstream ostr;
+				ostr << "libsecrecy::SecrecyKeyValueStore::getParsedValue: field " << key << " is not present";
+				throw std::runtime_error(ostr.str());
+			}
+
+			std::istringstream istr(it->second);
+			value_type v;
+			istr >> v;
+
+			if ( istr && istr.peek() == std::istream::traits_type::eof() )
+			{
+				return v;
+			}
+			else
+			{
+				std::ostringstream ostr;
+				ostr << "libsecrecy::SecrecyKeyValueStore::getParsedValue: field " << key << " has unparsable value " << it->second;
+				throw std::runtime_error(ostr.str());
+			}
+		}
+	};
+}
+#endif


=====================================
src/libsecrecy/libsecrecy.hpp deleted
=====================================
@@ -1,69 +0,0 @@
-/**
- * Copyright 2020 German Tischler-Höhle
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- **/
-
-/**
- * headers
- **/
-
-/**
- * functions
- **/
-
-/**
- * functions blocks
- **/
-
-/**
- * compiler features
- **/
-
-/**
- * third party libraries
- **/
-
-/**
- * capabilities in third party libraries
- **/
-
-/**
- * flag constants
- **/
-
-/**
- * numeric constants
- **/
-
-/**
- * compilation flags
- **/
-
-/**
- * enable/disable feature flags
- **/
-
-/**
- * info flags
- **/



View it on GitLab: https://salsa.debian.org/med-team/libsecrecy/-/commit/d9b3411bd0a3f9d685041e80caed60b755e041f2

-- 
View it on GitLab: https://salsa.debian.org/med-team/libsecrecy/-/commit/d9b3411bd0a3f9d685041e80caed60b755e041f2
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/debian-med-commit/attachments/20211023/88d96fcf/attachment-0001.htm>


More information about the debian-med-commit mailing list