How do I supply a password and decrypt on NT

Leigh S. Jones, KR6X kr6x@kr6x.com
Fri Jun 14 20:09:02 2002


----- Original Message -----
From: "Clough, Samuel" <Samuel_Clough@invesco.com>
To: <gnupg-users@gnupg.org>
Sent: Friday, June 14, 2002 10:38
Subject: How do I supply a password and decrypt on NT


> I'm running gnupg on NT (not by choice).  Anyway, I need to be able to
> automate encryption and decryption.  What should I use to do this and is
it
> possible?
>
> I can decrypt using:
> gpg --decrypt source.txt > output.txt
>
> But is there a way around being prompted for a password?
> I tried the --passphrase-fd option, but cannot find a way to assign a file
> descriptor in windows or to feed it someone through the standard input.
Is
> there a way to do this in windows?
>
> Can I do something by running in batch mode?  I don't have a good
> understanding of running that way and have not found documentation for
> decryption in batch mode.
>
> I need something automated so I'm basically hacking my way to a com
> component that has api calls to send a dos command and return the output.
I
> then parse the output to see if it succeeded.  The problem is I need to
get
> around the password prompt on decryption.  Any help would be very much
> appreciated.  I've tried everything in the man pages and can't see a way
to
> do this on windows.

This is a popular question on this reflector!

The following is old code; I no longer use this exact method, having
converted
to using pipes.  It was written for the Borland C 4.51 compiler, and works.
In
the scheme below, the calling process (which could be a batch file) writes
the
password to a file that has been opened with appropriate security privileges
to protect the contents of the file from prying eyes.  The calling process
(or
batch file) then calls this tiny "wrapper" executable which calls gpg.  Most
of the
code below is involved in deleting the password file as soon as possible and
as surely as possible.

But the code was tailored to clearsign text files rather than to decrypt
them,
so you'll have to adapt the code to make it decrypt.

The most important thing to note here is that the --passphrase-fd option
when
used with the MingW32 implementation of gpg 1.0.6 (that was the current
release when this code was written) requires that the file descriptor be
converted to an OSF handle before being placed on the command line.

The example below uses files for all of the file descriptors, and as I noted
above, I now use pipes.  That requires the use of the MSVC6 compiler or
similar rather than the Borland compiler.  I was not able to make the MS
C library dll create pipes for me from within the Borland compiler, so I
now use a different compiler to get a more secure version of the program.
Of course, the Borland compiler can open executables as pipes, but cannot
handle both the input and output end of the executable as pipes and cannot
give me an open pipe with both ends free.

Note the use of low level file IO.  Some of that is not necessary, but it
works.

----------------

#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 ( ) */