Multiple File Encryption (Win32)

Leigh S. Jones, KR6X kr6x@kr6x.com
Wed Apr 10 18:51:02 2002


OK; here's the finished C language wrapper program file for Borland C.  Or,
at least, partially finished.
Eventually I'd like to add some additional security, like taking file
ownership to assure privacy of the
password file during the many milliseconds that it is in existence.

Once again, the program that follows was tailored to applying signatures,
but could easily be adapted
to decryption under batch mode.  For this program, the command line
arguments include two file
names that will be used as the output file name (in this case the
clearsigned text file) and a "status" file
that will collect some output from the GPG program itself.  The batch file
calling this program must
create the file containing the password (remember that for security's sake
the password should not be
on the command line) and pass along the filename to this program.  The
program has a feature (that
can be disabled) that would check for a network time server immediately
prior to applying the
signature.  You wouldn't want any of that stuff for decryption.  My
application really wanted to know if
the signature had been successfully applied -- you might not care for some
of the error checking...

#include <sys\stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
#include <string.h>

int main ( int argc, char *argv[ ] )

   {
   int passphrase;
   int status;
   int error;
   int time_error;
   FILE *ptr;
   char buf[ 1024 ];

/***************************************************************************
****
* argv strings represent:
*
* user_id
*
* passphrase
*
* target_file
*
* passphrase_file
*
* status_file
*
****************************************************************************
***/

   time_error = 0;
   if ( ( argc != 6 ) && ( argc != 7 ) )
      {
      if ( ( strncmp ( "NULL", argv[ 2 ], 4 ) ) && ( argc > 4 ) )
         {
         passphrase = open ( argv[ 4 ],
                             O_CREAT | O_WRONLY | O_TRUNC | O_TEXT,
                             S_IREAD | S_IWRITE );
         write ( passphrase, "12345678901234567890", 20 );
         close ( passphrase );
         unlink ( argv[ 4 ] );
         } /* end if ( strncmp ( "NULL", argv[ 2 ], 4 ) ) */
      return ( -1 );
      } /* end if ( argc != 7 ) */
   if ( ( argc == 7 ) &&
        strncmp ( argv[ 6 ],
        "NO_TIME_SET",
        strlen ( "NO_TIME_SET" ) ) )
      {
      if ( ( strncmp ( "NULL", argv[ 2 ], 4 ) ) && ( argc > 4 ) )
         {
         passphrase = open ( argv[ 4 ],
                             O_CREAT | O_WRONLY | O_TRUNC | O_TEXT,
                             S_IREAD | S_IWRITE );
         write ( passphrase, "12345678901234567890", 20 );
         close ( passphrase );
         unlink ( argv[ 4 ] );
         } /* end if ( strncmp ( "NULL", argv[ 2 ], 4 ) ) */
      return ( -1 );
      } /* end if ( argc != 7 ) */
   if ( argc == 6 )
      {
      sprintf ( buf, "NET TIME /SET /Y" );
      ptr = _popen ( buf, "rt" );
      while ( !feof ( ptr ) ) fgets ( buf, sizeof ( buf ), ptr );
      time_error = _pclose ( ptr );
      } /* end if ( ( argc == 7 ) && ( ... ) ) */

/***************************************************************************
****
* passing "NULL" as the password results in reading of the password file
* rather than creation of a new password file
****************************************************************************
***/

   if ( strncmp ( "NULL", argv[ 2 ], 4 ) )
      {

/***************************************************************************
****
* set up to pass the password in a temporary file
* first, open the temporary file for writing, checking for failure
****************************************************************************
***/

      passphrase = open ( argv[ 4 ],
                          O_CREAT | O_WRONLY | O_TRUNC | O_TEXT,
                          S_IREAD | S_IWRITE );
      if ( passphrase <= 0 )
         {
         return ( -2 );
         } /* end if ( passphrase <= 0 ) */

/***************************************************************************
****
* write the password from the command line to the temporary file
****************************************************************************
***/

      if ( write ( passphrase, argv[ 2 ], strlen ( argv[ 2 ] ) ) <= 0 )
         {
         close ( passphrase );
         unlink ( argv[ 4 ] );
         return ( -3 );
         } /* end if ( write ( passphrase, ... ) <= 0 ) */

/***************************************************************************
****
* close the temporary file and reopen for reading
****************************************************************************
***/

      if ( close ( passphrase ) != 0 )
         {
         passphrase = open ( argv[ 4 ],
                             O_CREAT | O_WRONLY | O_TRUNC | O_TEXT,
                             S_IREAD | S_IWRITE );
         write ( passphrase, "12345678901234567890", 20 );
         close ( passphrase );
         unlink ( argv[ 4 ] );
         return ( -4 );
         } /* end if ( close ( passphrase ) <= 0 ) */
      } /* end if ( strncmp ( "NULL", argv[ 2 ], 4 ) */
   passphrase = open ( argv[ 4 ], O_RDONLY | O_TEXT );
   if ( passphrase <= 0 )
      {
      passphrase = open ( argv[ 4 ],
                          O_CREAT | O_WRONLY | O_TRUNC | O_TEXT,
                          S_IREAD | S_IWRITE );
      write ( passphrase, "12345678901234567890", 20 );
      close ( passphrase );
      unlink ( argv[ 4 ] );
      return ( -5 );
      } /* end if ( passphrase <= 0 ) */

/***************************************************************************
****
* open the temporary file for writing
****************************************************************************
***/

   status = open ( argv[ 5 ],
                   O_CREAT | O_WRONLY | O_TRUNC | O_TEXT,
                   S_IREAD | S_IWRITE );
   if ( status <= 0 )
      {
      close ( passphrase );
      passphrase = open ( argv[ 4 ],
                          O_CREAT | O_WRONLY | O_TRUNC | O_TEXT,
                          S_IREAD | S_IWRITE );
      write ( passphrase, "12345678901234567890", 20 );
      close ( passphrase );
      unlink ( argv[ 4 ] );
      return ( -6 );
      } /* end if ( passphrase <= 0 ) */

/***************************************************************************
****
* form and execute the command line that runs gpg
****************************************************************************
***/

   sprintf ( buf,
             "gpg --passphrase %d --status-fd %d -u %s --batch --clearsign
%s",
             _get_osfhandle ( ( int ) passphrase ),
             _get_osfhandle ( ( int ) status ),
             argv[ 1 ],
             argv[ 3 ] );
   ptr = _popen ( buf, "rt" );
   if ( !ptr )
      {
      close ( passphrase );
      passphrase = open ( argv[ 4 ],
                          O_CREAT | O_WRONLY | O_TRUNC | O_TEXT,
                          S_IREAD | S_IWRITE );
      write ( passphrase, "12345678901234567890", 20 );
      close ( passphrase );
      unlink ( argv[ 4 ] );
      close ( status );
      unlink ( argv[ 5 ] );
      return ( -7 );
      } /* end if ( !ptr ) */
   while ( !feof ( ptr ) ) fgets ( buf, sizeof ( buf ), ptr );

/***************************************************************************
****
* close the pipe from gpg and check for nonzero exit status
****************************************************************************
***/

   if ( ( error = _pclose ( ptr ) ) != 0 )
      {
      close ( passphrase );
      passphrase = open ( argv[ 4 ],
                          O_CREAT | O_WRONLY | O_TRUNC | O_TEXT,
                          S_IREAD | S_IWRITE );
      write ( passphrase, "12345678901234567890", 20 );
      close ( passphrase );
      unlink ( argv[ 4 ] );
      close ( status );
      status = open ( argv[ 5 ], O_RDONLY | O_TEXT );
      read ( status, buf, sizeof ( buf ) - 1 );

/***************************************************************************
****
* the first line of the status file should contain "USERID_HINT"
****************************************************************************
***/

      if ( !strstr ( buf, "[GNUPG:] USERID_HINT" ) )
         {
         if ( error == 2 )
            {
            error = -111;
            }
         close ( status );
         unlink ( argv[ 5 ] );
         return ( error - 100 );
         } /* end if ( strncmp ( buf, "[GNUPG:] USERID_HINT", ... ) */

/***************************************************************************
****
* the second line of the status file should contain "NEED_PASSPHRASE"
****************************************************************************
***/

      if ( !strstr ( buf, "[GNUPG:] NEED_PASSPHRASE" ) )
         {
         if ( error == 2 )
            {
            error = -112;
            }
         close ( status );
         unlink ( argv[ 5 ] );
         return ( error - 100 );
         } /* end if ( strncmp ( buf, "[GNUPG:] NEED_PASSPHRASE", ... ) */

/***************************************************************************
****
* the third line of the status file should contain "GOOD_PASSPHRASE"
****************************************************************************
***/

      if ( !strstr ( buf, "[GNUPG:] GOOD_PASSPHRASE" ) )
         {
         if ( error == 2 )
            {
            error = -113;
            }
         close ( status );
         unlink ( argv[ 5 ] );
         return ( error - 100 );
         } /* end if ( strncmp ( buf, "[GNUPG:] GOOD_PASSPHRASE", ... ) */

/***************************************************************************
****
* the fourth line of the status file should contain "SIG_CREATED"
****************************************************************************
***/

      if ( !strstr ( buf, "[GNUPG:] SIG_CREATED" ) )
         {
         if ( error == 2 )
            {
            error = -114;
            }
         close ( status );
         unlink ( argv[ 5 ] );
         return ( error - 100 );
         } /* end if ( strncmp ( buf, "[GNUPG:] SIG_CREATED", ... ) */
      close ( status );
      unlink ( argv[ 5 ] );
      return ( error - 100 );
      } /* end if ( !ptr ) */

/***************************************************************************
****
* close the temporary (password) file and delete it
****************************************************************************
***/

   if ( close ( passphrase ) != 0 )
      {
      passphrase = open ( argv[ 4 ],
                          O_CREAT | O_WRONLY | O_TRUNC | O_TEXT,
                          S_IREAD | S_IWRITE );
      write ( passphrase, "12345678901234567890", 20 );
      close ( passphrase );
      unlink ( argv[ 4 ] );
      close ( status );
      unlink ( argv[ 5 ] );
      return ( -8 );
      } /* end if ( close ( passphrase ) <= 0 ) */
   if ( unlink ( argv[ 4 ] ) )
      {
      close ( status );
      unlink ( argv[ 5 ] );
      return ( -9 );
      } /* end if ( close ( passphrase ) <= 0 ) */

/***************************************************************************
****
* read back the status file written to by gpg and check for signs of failure
****************************************************************************
***/

   close ( status );
   status = open ( argv[ 5 ], O_RDONLY | O_TEXT );
   read ( status, buf, sizeof ( buf ) - 1 );
   close ( status );
   unlink ( argv[ 5 ] );

/***************************************************************************
****
* the first line of the status file should contain "USERID_HINT"
****************************************************************************
***/

   if ( !strstr ( buf, "[GNUPG:] USERID_HINT" ) )
      {
      return ( -10 );
      } /* end if ( strncmp ( buf, "[GNUPG:] USERID_HINT", ... ) */

/***************************************************************************
****
* the second line of the status file should contain "NEED_PASSPHRASE"
****************************************************************************
***/

   if ( !strstr ( buf, "[GNUPG:] NEED_PASSPHRASE" ) )
      {
      return ( -11 );
      } /* end if ( strncmp ( buf, "[GNUPG:] NEED_PASSPHRASE", ... ) */

/***************************************************************************
****
* the third line of the status file should contain "GOOD_PASSPHRASE"
****************************************************************************
***/

   if ( !strstr ( buf, "[GNUPG:] GOOD_PASSPHRASE" ) )
      {
      return ( -12 );
      } /* end if ( strncmp ( buf, "[GNUPG:] GOOD_PASSPHRASE", ... ) */

/***************************************************************************
****
* the fourth line of the status file should contain "SIG_CREATED"
****************************************************************************
***/

   if ( !strstr ( buf, "[GNUPG:] SIG_CREATED" ) )
      {
      return ( -13 );
      } /* end if ( strncmp ( buf, "[GNUPG:] SIG_CREATED", ... ) */
   if ( time_error )
      {
      return ( -1000 - time_error );
      } /* end if ( time_error ) */

/***************************************************************************
****
* exit with success status
****************************************************************************
***/

   return ( 0 );
   } /* end main ( ) */

----- Original Message -----
From: AthlonRob
To: gnupg-users@gnupg.org
Sent: Tuesday, April 09, 2002 17:45
Subject: Multiple File Encryption (Win32)


Hi all-

I'm trying to come up with a way to encrypt batches of files... 10-15 at
most with varying file names.  I want the files to be encrypted into either
a single large file or in to multiple files, each replacing the
non-encrypted version.  The files are *NOT* ASCII text.  I want to then be
able to decrypt each of them to the original state with a single command
(batch file)

Now... after searching around the web for a while, I'm not having much luck.
Any thoughts?  I've got GnuPG downloaded and working.  I'm running Windows
XP... so this is a Win32 thing.

Rob