pspp-convert: Add -a and -l options to search for a password.
[pspp] / src / data / encrypted-file.c
index b90126ed260be18b2163fe9c3a3ff63d17e15a0c..e340d04fce61d9727043758b7abac9a350bfcc9a 100644 (file)
@@ -17,6 +17,7 @@
 #include <config.h>
 
 #include "data/encrypted-file.h"
+#include "data/file-handle-def.h"
 
 #include <errno.h>
 #include <stdlib.h>
@@ -48,7 +49,6 @@ struct encrypted_file
     int Nr;
   };
 
-static bool try_password(struct encrypted_file *, const char *password);
 static bool decode_password (const char *input, char output[11]);
 static bool fill_buffer (struct encrypted_file *);
 
@@ -60,7 +60,7 @@ static bool fill_buffer (struct encrypted_file *);
 
    If FILENAME cannot be open or read, returns a negative errno value. */
 int
-encrypted_file_open (struct encrypted_file **fp, const char *filename)
+encrypted_file_open (struct encrypted_file **fp, const struct file_handle *fh)
 {
   struct encrypted_file *f;
   char header[36 + 16];
@@ -69,11 +69,11 @@ encrypted_file_open (struct encrypted_file **fp, const char *filename)
 
   f = xmalloc (sizeof *f);
   f->error = 0;
-  f->file = fn_open (filename, "rb");
+  f->file = fn_open (fh, "rb");
   if (f->file == NULL)
     {
       msg (ME, _("An error occurred while opening `%s': %s."),
-           filename, strerror (errno));
+           fh_get_file_name (fh), strerror (errno));
       retval = -errno;
       goto error;
     }
@@ -84,7 +84,7 @@ encrypted_file_open (struct encrypted_file **fp, const char *filename)
       int error = feof (f->file) ? 0 : errno;
       if (error)
         msg (ME, _("An error occurred while reading `%s': %s."),
-             filename, strerror (error));
+             fh_get_file_name (fh), strerror (error));
       retval = -error;
       goto error;
     }
@@ -107,7 +107,7 @@ encrypted_file_open (struct encrypted_file **fp, const char *filename)
 
 error:
   if (f->file)
-    fn_close (filename, f->file);
+    fn_close (fh, f->file);
   free (f);
   *fp = NULL;
 
@@ -121,9 +121,9 @@ encrypted_file_unlock (struct encrypted_file *f, const char *password)
 {
   char decoded_password[11];
 
-  return (try_password (f, password)
+  return (encrypted_file_unlock__ (f, password)
           || (decode_password (password, decoded_password)
-              && try_password (f, decoded_password)));
+              && encrypted_file_unlock__ (f, decoded_password)));
 }
 
 /* Attempts to read N bytes of plaintext from F into BUF.  Returns the number
@@ -286,12 +286,10 @@ decode_password (const char *input, char output[11])
   return true;
 }
 
-/* If CIPHERTEXT is the first ciphertext block in an encrypted .sav file for
-   PASSWORD, initializes rk[] and returns an nonzero Nr value.
-
-   Otherwise, returns zero. */
-static bool
-try_password(struct encrypted_file *f, const char *password)
+/* Attempts to use plaintext password PASSWORD to unlock F.  Returns true if
+   successful, otherwise false. */
+bool
+encrypted_file_unlock__ (struct encrypted_file *f, const char *password)
 {
   /* NIST SP 800-108 fixed data. */
   static const uint8_t fixed[] = {
@@ -347,7 +345,12 @@ try_password(struct encrypted_file *f, const char *password)
   rijndaelDecrypt (f->rk, f->Nr,
                    CHAR_CAST (const char *, f->ciphertext),
                    CHAR_CAST (char *, f->plaintext));
-  return !memcmp (f->plaintext, f->type == SYSTEM ? "$FL" : "* E", 3);
+
+  const char *magic = f->type == SYSTEM ? "$FL?@(#)" : "* Encoding";
+  for (int i = 0; magic[i]; i++)
+    if (magic[i] != '?' && f->plaintext[i] != magic[i])
+      return false;
+  return true;
 }
 
 static bool