CVE-2022-35928 (published 2022-08-03T20:15Z)

AES Crypt is a file encryption software for multiple platforms. AES Crypt for Linux built using the source on GitHub and having the version number 3.11 has a vulnerability with respect to reading user-provided passwords and confirmations via command-line prompts. Passwords lengths were not checked before being read. This vulnerability may lead to buffer overruns. This does _not_ affect source code found on aescrypt.com, nor is the vulnerability present when providing a password or a key via the `-p` or `-k` command-line options. The problem was fixed via in commit 68761851b and will be included in release 3.16. Users are advised to upgrade. Users unable to upgrade should us the `-p` or `-k` options to provide a password or key.

CVSS v3 base score: 5.5, MEDIUM (CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N)

Weakness information:
cwe_id: CWE-1284
cwe_name: Improper Validation of Specified Quantity in Input
description: The product receives input that is expected to specify a quantity (such as size or length), but it does not validate or incorrectly validates that the quantity has the required properties.
extended_description: 
				Specified quantities include size, length, frequency, price, rate, number of operations, time, and others. Code may rely on specified quantities to allocate resources, perform calculations, control iteration, etc. When the quantity is not properly validated, then attackers can specify malicious quantities to cause excessive resource allocation, trigger unexpected failures, enable buffer overflows, etc.
			
			

Fix information:
repo_url: https://github.com/paulej/AESCrypt
commit_details: repo_url: https://github.com/paulej/AESCrypt
author: Paul E. Jones
author_date: 2022-08-01 17:35:25-04:00
msg: Fixed security issue with passwords entered via a prompt
repository: repo_url: https://github.com/paulej/AESCrypt
repo_name: paulej/AESCrypt
description: File Encryption software for multiple platforms
repo_language: C
owner: paulej
file_changes: filename: .gitignore
change_type: ModificationType.ADD
diff: @@ -0,0 +1,2 @@
+/build
+Linux/build

programming_language: Batchfile
filename: CMakeLists.txt
change_type: ModificationType.MODIFY
diff: @@ -1,5 +1,16 @@
 cmake_minimum_required(VERSION 3.9)
 
-project( aescrypt )
+option(aescrypt_BUILD_TESTS "Build Tests for AESCrypt" ON)
 
-add_subdirectory( src/ )
+project(aescrypt
+        VERSION 3.16
+        DESCRIPTION "AES Crypt for Linux"
+        LANGUAGES C)
+
+add_subdirectory(src)
+
+include(CTest)
+
+if(BUILD_TESTING AND aescrypt_BUILD_TESTS)
+    add_subdirectory(test)
+endif()

programming_language: Shell
filename: README
change_type: ModificationType.MODIFY
diff: @@ -28,6 +28,9 @@ https://www.gnu.org/licenses/gpl-2.0.txt
 
 2. Installing
 
+NOTE: These instructions correspond to the official release files
+      available from aescrypt.com.
+
 Extract the source archive.  If you are reading this, you probably
 already have.  Just in case you have not, extract the files using
 a command like this:

programming_language: Markdown
filename: README.md
change_type: ModificationType.MODIFY
diff: @@ -1,32 +1,57 @@
 # AES Crypt (Linux source code)
 
-The Linux source code in the git respository is intended for use with
-"The Autotools". This includes the following packages: autoconf; automake; and, libtool.
-Install these from your distro packages.
+The Linux source code in the git repository is intended for use with CMake or
+"The Autotools".
+
+## CMake build
+
+Change to the Linux directory and issue the following commands to create
+a release build:
+
+```bash
+cmake -B build -S . --install-prefix=/usr -DCMAKE_BUILD_TYPE:STRING=Release
+cmake --build build --parallel
+```
+
+The aescrypt and aescrypt_keygen binaries will be placed in the directory
+`build/src/` once the build completes.
+
+If you wish to install the two binary files `aescrypt` and `aescrypt_keygen`,
+just run this command:
+
+```bash
+cmake --install build
+```
+
+To invoke the tests to ensure everything is working properly, do the following:
+
+```bash
+cd build
+make test
+```
+
+## Using Autotools
+
+Install these from your Linus distribution packages:
+
+* autoconf
+* automake
+* libtool
 
 Before you can build the software, you need to run the
 following command:
 
-```
-autoreconf -ivf 
+```bash
+autoreconf -ivf
 ```
 
 Note that the package maintainers, when producing an official release,
 will run the above command and only publish the source files needed
 to run "configure" and "make".  Official source releases can be downloaded
-from https://www.aescrypt.com/.
+from [aescrypt.com](https://www.aescrypt.com/download/).
 
 Package maintainers can create a tarball using the following command:
 
+```bash
+make dist
 ```
-make dist 
-```
-
-## CMake build
-
-    mkdir build
-    cd build
-    cmake ../
-    make
-
-

programming_language: Markdown
filename: CMakeLists.txt
change_type: ModificationType.MODIFY
diff: @@ -1,25 +1,34 @@
-cmake_minimum_required(VERSION 3.9)
-
 string(TIMESTAMP PACKAGE_DATE %Y-%m-%dT%H:%M:%SZ UTC)
-add_definitions( -DPACKAGE_NAME="aescrypt" )
-add_definitions( -DPACKAGE_VERSION="1.0.0" )
-add_definitions( -DPACKAGE_DATE="${PACKAGE_DATE}" )
 
-set( HEADER_FILES
-   password.h
-   aes.h
-   aesrandom.h
-   sha256.h
-   util.h
-   keyfile.h )
+# Build a version number into the binary library
+configure_file(version.h.in version.h @ONLY)
 
-set( COMMON_SOURCE_FILES
+add_executable(aescrypt
+   aescrypt.c
    aes.c
    aesrandom.c
    sha256.c
    util.c
    keyfile.c
-   password.c )
+   password.c)
+target_compile_definitions(aescrypt PRIVATE ENABLE_ICONV)
+
+target_include_directories(aescrypt
+    PRIVATE
+        $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>)
+
+add_executable(aescrypt_keygen
+   aescrypt_keygen.c
+   aes.c
+   aesrandom.c
+   sha256.c
+   util.c
+   keyfile.c
+   password.c)
+
+target_include_directories(aescrypt_keygen
+   PRIVATE
+       $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>)
 
-add_executable( aescrypt aescrypt.c ${COMMON_SOURCE_FILES} )
-add_executable( aescrypt_keygen aescrypt_keygen.c ${COMMON_SOURCE_FILES} )
+# Install target and associated include files
+install(TARGETS aescrypt aescrypt_keygen)

programming_language: Shell
filename: aescrypt.c
change_type: ModificationType.MODIFY
diff: @@ -1,6 +1,6 @@
 /*
  *  AES Crypt for Linux
- *  Copyright (C) 2007-2017
+ *  Copyright (C) 2007-2022
  *
  *  Contributors:
  *      Glenn Washburn <crass@berlios.de>
@@ -20,6 +20,8 @@
 
 #ifdef HAVE_CONFIG_H
 #include <config.h>
+#else
+#include "version.h"
 #endif
 #include <stdio.h>
 #include <string.h>
@@ -84,11 +86,11 @@ int encrypt_stream(FILE *infp, FILE *outfp, unsigned char* passwd, int passlen)
      * source of data.
      */
     memset(iv_key, 0, 48);
-    for (i=0; i<48; i+=16)
+    for (i = 0; i < 48; i += 16)
     {
         memset(buffer, 0, 32);
         sha256_starts(&sha_ctx);
-        for(j=0; j<256; j++)
+        for (j = 0; j < 256; j++)
         {
             if ((bytes_read = aesrandom_read(aesrand, buffer, 32)) != 32)
             {
@@ -100,7 +102,7 @@ int encrypt_stream(FILE *infp, FILE *outfp, unsigned char* passwd, int passlen)
             sha256_update(&sha_ctx, buffer, 32);
         }
         sha256_finish(&sha_ctx, digest);
-        memcpy(iv_key+i, digest, 16);
+        memcpy(iv_key + i, digest, 16);
     }
 
     /*
@@ -190,11 +192,11 @@ int encrypt_stream(FILE *infp, FILE *outfp, unsigned char* passwd, int passlen)
      * We will use an initialization vector comprised of the current time
      * process ID, and random data, all hashed together with SHA-256.
      */
-    sha256_starts(  &sha_ctx);
+    sha256_starts(&sha_ctx);
     current_time = time(NULL);
-    sha256_update(  &sha_ctx, (unsigned char *)&time, sizeof(current_time));
+    sha256_update(&sha_ctx, (unsigned char *) &time, sizeof(current_time));
     process_id = getpid();
-    sha256_update(  &sha_ctx, (unsigned char *)&process_id, sizeof(process_id));
+    sha256_update(&sha_ctx, (unsigned char *) &process_id, sizeof(process_id));
 
     for (i=0; i<256; i++)
     {
@@ -204,12 +206,10 @@ int encrypt_stream(FILE *infp, FILE *outfp, unsigned char* passwd, int passlen)
             aesrandom_close(aesrand);
             return -1;
         }
-        sha256_update(  &sha_ctx,
-                        buffer,
-                        32);
+        sha256_update(&sha_ctx, buffer, 32);
     }
 
-    sha256_finish(  &sha_ctx, digest);
+    sha256_finish(&sha_ctx, digest);
 
     memcpy(IV, digest, 16);
 
@@ -222,19 +222,16 @@ int encrypt_stream(FILE *infp, FILE *outfp, unsigned char* passwd, int passlen)
         fprintf(stderr, "Error: Could not write out initialization vector\n");
         return -1;
     }
-    
+
     /* Hash the IV and password 8192 times */
     memset(digest, 0, 32);
     memcpy(digest, IV, 16);
-    for(i=0; i<8192; i++)
+    for (i = 0; i < 8192; i++)
     {
-        sha256_starts(  &sha_ctx);
-        sha256_update(  &sha_ctx, digest, 32);
-        sha256_update(  &sha_ctx,
-                        passwd,
-                        (unsigned long)passlen);
-        sha256_finish(  &sha_ctx,
-                        digest);
+        sha256_starts(&sha_ctx);
+        sha256_update(&sha_ctx, digest, 32);
+        sha256_update(&sha_ctx, passwd, (unsigned long) passlen);
+        sha256_finish(&sha_ctx, digest);
     }
 
     /* Set the AES encryption key */
@@ -248,7 +245,7 @@ int encrypt_stream(FILE *infp, FILE *outfp, unsigned char* passwd, int passlen)
     memset(ipad, 0x36, 64);
     memset(opad, 0x5C, 64);
 
-    for(i=0; i<32; i++)
+    for (i = 0; i < 32; i++)
     {
         ipad[i] ^= digest[i];
         opad[i] ^= digest[i];
@@ -261,7 +258,7 @@ int encrypt_stream(FILE *infp, FILE *outfp, unsigned char* passwd, int passlen)
      * Encrypt the IV and key used to encrypt the plaintext file,
      * writing that encrypted text to the output file.
      */
-    for(i=0; i<48; i+=16)
+    for (i = 0; i < 48; i += 16)
     {
         /*
          * Place the next 16 octets of IV and key buffer into
@@ -273,14 +270,14 @@ int encrypt_stream(FILE *infp, FILE *outfp, unsigned char* passwd, int passlen)
          * XOR plain text block with previous encrypted
          * output (i.e., use CBC)
          */
-        for(j=0; j<16; j++)
+        for (j = 0; j < 16; j++)
         {
             buffer[j] ^= IV[j];
         }
 
         /* Encrypt the contents of the buffer */
         aes_encrypt(&aes_ctx, buffer, buffer);
-        
+
         /* Concatenate the "text" as we compute the HMAC */
         sha256_update(&sha_ctx, buffer, 16);
 
@@ -290,7 +287,7 @@ int encrypt_stream(FILE *infp, FILE *outfp, unsigned char* passwd, int passlen)
             fprintf(stderr, "Error: Could not write iv_key data\n");
             return -1;
         }
-        
+
         /* Update the IV (CBC mode) */
         memcpy(IV, buffer, 16);
     }
@@ -309,7 +306,7 @@ int encrypt_stream(FILE *infp, FILE *outfp, unsigned char* passwd, int passlen)
     }
 
     /* Re-load the IV and encryption key with the IV and
-     * key to now encrypt the datafile.  Also, reset the HMAC
+     * key to now encrypt the data file.  Also, reset the HMAC
      * computation.
      */
     memcpy(IV, iv_key, 16);
@@ -325,7 +322,7 @@ int encrypt_stream(FILE *infp, FILE *outfp, unsigned char* passwd, int passlen)
     memset(ipad, 0x36, 64);
     memset(opad, 0x5C, 64);
 
-    for(i=0; i<32; i++)
+    for (i = 0; i < 32; i++)
     {
         ipad[i] ^= iv_key[i+16];
         opad[i] ^= iv_key[i+16];
@@ -346,14 +343,14 @@ int encrypt_stream(FILE *infp, FILE *outfp, unsigned char* passwd, int passlen)
          * XOR plain text block with previous encrypted
          * output (i.e., use CBC)
          */
-        for(i=0; i<16; i++)
+        for (i = 0; i < 16; i++)
         {
             buffer[i] ^= IV[i];
         }
 
         /* Encrypt the contents of the buffer */
         aes_encrypt(&aes_ctx, buffer, buffer);
-        
+
         /* Concatenate the "text" as we compute the HMAC */
         sha256_update(&sha_ctx, buffer, 16);
 
@@ -363,7 +360,7 @@ int encrypt_stream(FILE *infp, FILE *outfp, unsigned char* passwd, int passlen)
             fprintf(stderr, "Error: Could not write to output file\n");
             return -1;
         }
-        
+
         /* Update the IV (CBC mode) */
         memcpy(IV, buffer, 16);
 
@@ -427,14 +424,14 @@ int decrypt_stream(FILE *infp, FILE *outfp, unsigned char* passwd, int passlen)
     unsigned char *head, *tail;
     unsigned char ipad[64], opad[64];
     int reached_eof = 0;
-    
+
     /* Read the file header */
     if ((bytes_read = fread(&aeshdr, 1, sizeof(aeshdr), infp)) !=
          sizeof(aescrypt_hdr))
     {
         if (feof(infp))
         {
-            fprintf(stderr, "Error: Input file is too short.\n");
+            fprintf(stderr, "Error: Input file is too short\n");
         }
         else
         {
@@ -446,7 +443,12 @@ int decrypt_stream(FILE *infp, FILE *outfp, unsigned char* passwd, int passlen)
     if (!(aeshdr.aes[0] == 'A' && aeshdr.aes[1] == 'E' &&
           aeshdr.aes[2] == 'S'))
     {
-        fprintf(stderr, "Error: Bad file header (not aescrypt file or is corrupted? [%x, %x, %x])\n", aeshdr.aes[0], aeshdr.aes[1], aeshdr.aes[2]);
+        fprintf(stderr,
+                "Error: Bad file header (not aescrypt file or is corrupted? "
+                "[%x, %x, %x])\n",
+                aeshdr.aes[0],
+                aeshdr.aes[1],
+                aeshdr.aes[2]);
         return -1;
     }
 
@@ -475,7 +477,7 @@ int decrypt_stream(FILE *infp, FILE *outfp, unsigned char* passwd, int passlen)
             {
                 if (feof(infp))
                 {
-                    fprintf(stderr, "Error: Input file is too short.\n");
+                    fprintf(stderr, "Error: Input file is too short\n");
                 }
                 else
                 {
@@ -491,7 +493,7 @@ int decrypt_stream(FILE *infp, FILE *outfp, unsigned char* passwd, int passlen)
                 {
                     if (feof(infp))
                     {
-                        fprintf(stderr, "Error: Input file is too short.\n");
+                        fprintf(stderr, "Error: Input file is too short\n");
                     }
                     else
                     {
@@ -508,7 +510,7 @@ int decrypt_stream(FILE *infp, FILE *outfp, unsigned char* passwd, int passlen)
     {
         if (feof(infp))
         {
-            fprintf(stderr, "Error: Input file is too short.\n");
+            fprintf(stderr, "Error: Input file is too short\n");
         }
         else
         {
@@ -520,15 +522,12 @@ int decrypt_stream(FILE *infp, FILE *outfp, unsigned char* passwd, int passlen)
     /* Hash the IV and password 8192 times */
     memset(digest, 0, 32);
     memcpy(digest, IV, 16);
-    for(i=0; i<8192; i++)
+    for (i = 0; i < 8192; i++)
     {
-        sha256_starts(  &sha_ctx);
-        sha256_update(  &sha_ctx, digest, 32);
-        sha256_update(  &sha_ctx,
-                        passwd,
-                        passlen);
-        sha256_finish(  &sha_ctx,
-                        digest);
+        sha256_starts(&sha_ctx);
+        sha256_update(&sha_ctx, digest, 32);
+        sha256_update(&sha_ctx, passwd, passlen);
+        sha256_finish(&sha_ctx, digest);
     }
 
     /* Set the AES encryption key */
@@ -541,7 +540,7 @@ int decrypt_stream(FILE *infp, FILE *outfp, unsigned char* passwd, int passlen)
     memset(ipad, 0x36, 64);
     memset(opad, 0x5C, 64);
 
-    for(i=0; i<32; i++)
+    for (i = 0; i < 32; i++)
     {
         ipad[i] ^= digest[i];
         opad[i] ^= digest[i];
@@ -555,13 +554,13 @@ int decrypt_stream(FILE *infp, FILE *outfp, unsigned char* passwd, int passlen)
      */
     if (aeshdr.version >= 0x01)
     {
-        for(i=0; i<48; i+=16)
+        for (i = 0; i < 48; i += 16)
         {
             if ((bytes_read = fread(buffer, 1, 16, infp)) != 16)
             {
                 if (feof(infp))
                 {
-                    fprintf(stderr, "Error: Input file is too short.\n");
+                    fprintf(stderr, "Error: Input file is too short\n");
                 }
                 else
                 {
@@ -579,9 +578,9 @@ int decrypt_stream(FILE *infp, FILE *outfp, unsigned char* passwd, int passlen)
              * XOR plain text block with previous encrypted
              * output (i.e., use CBC)
              */
-            for(j=0; j<16; j++)
+            for (j = 0; j < 16; j++)
             {
-                iv_key[i+j] = (buffer[j] ^ IV[j]);
+                iv_key[i + j] = (buffer[j] ^ IV[j]);
             }
 
             /* Update the IV (CBC mode) */
@@ -599,7 +598,7 @@ int decrypt_stream(FILE *infp, FILE *outfp, unsigned char* passwd, int passlen)
         {
             if (feof(infp))
             {
-                fprintf(stderr, "Error: Input file is too short.\n");
+                fprintf(stderr, "Error: Input file is too short\n");
             }
             else
             {
@@ -610,7 +609,9 @@ int decrypt_stream(FILE *infp, FILE *outfp, unsigned char* passwd, int passlen)
 
         if (memcmp(digest, buffer, 32))
         {
-            fprintf(stderr, "Error: Message has been altered or password is incorrect\n");
+            fprintf(stderr,
+                    "Error: Message has been altered or password is "
+                    "incorrect\n");
             return -1;
         }
 
@@ -632,10 +633,10 @@ int decrypt_stream(FILE *infp, FILE *outfp, unsigned char* passwd, int passlen)
         memset(ipad, 0x36, 64);
         memset(opad, 0x5C, 64);
 
-        for(i=0; i<32; i++)
+        for (i = 0; i < 32; i++)
         {
-            ipad[i] ^= iv_key[i+16];
-            opad[i] ^= iv_key[i+16];
+            ipad[i] ^= iv_key[i + 16];
+            opad[i] ^= iv_key[i + 16];
         }
 
         /* Wipe the IV and encryption key from memory */
@@ -644,7 +645,7 @@ int decrypt_stream(FILE *infp, FILE *outfp, unsigned char* passwd, int passlen)
         sha256_starts(&sha_ctx);
         sha256_update(&sha_ctx, ipad, 64);
     }
-    
+
     /*
      * Decrypt the balance of the file
      *
@@ -663,12 +664,12 @@ int decrypt_stream(FILE *infp, FILE *outfp, unsigned char* passwd, int passlen)
             /*
              * If there are less than 48 octets, the only valid count
              * is 32 for version 0 (HMAC) and 33 for version 1 or
-             * greater files ( file size modulo + HMAC)
+             * greater files (file size modulo + HMAC)
              */
             if ((aeshdr.version == 0x00 && bytes_read != 32) ||
                 (aeshdr.version >= 0x01 && bytes_read != 33))
             {
-                fprintf(stderr, "Error: Input file is corrupt (1:%u).\n",
+                fprintf(stderr, "Error: Input file is corrupt (1:%u)\n",
                         (unsigned) bytes_read);
                 return -1;
             }
@@ -693,7 +694,7 @@ int decrypt_stream(FILE *infp, FILE *outfp, unsigned char* passwd, int passlen)
                  */
                 if (aeshdr.last_block_size != 0)
                 {
-                    fprintf(stderr, "Error: Input file is corrupt (2).\n");
+                    fprintf(stderr, "Error: Input file is corrupt (2)\n");
                     return -1;
                 }
             }
@@ -724,7 +725,7 @@ int decrypt_stream(FILE *infp, FILE *outfp, unsigned char* passwd, int passlen)
                 if ((aeshdr.version == 0x00 && bytes_read > 0) ||
                     (aeshdr.version >= 0x01 && bytes_read != 1))
                 {
-                    fprintf(stderr, "Error: Input file is corrupt (3:%u).\n",
+                    fprintf(stderr, "Error: Input file is corrupt (3:%u)\n",
                             (unsigned) bytes_read);
                     return -1;
                 }
@@ -774,7 +775,7 @@ int decrypt_stream(FILE *infp, FILE *outfp, unsigned char* passwd, int passlen)
              * XOR plain text block with previous encrypted
              * output (i.e., use CBC)
              */
-            for(i=0; i<16; i++)
+            for (i = 0; i < 16; i++)
             {
                 tail[i] ^= IV[i];
             }
@@ -795,7 +796,7 @@ int decrypt_stream(FILE *infp, FILE *outfp, unsigned char* passwd, int passlen)
                 perror("Error writing decrypted block:");
                 return -1;
             }
-            
+
             /* Move the tail of the ring buffer forward */
             tail += 16;
             if (tail == (buffer+64))
@@ -844,11 +845,15 @@ int decrypt_stream(FILE *infp, FILE *outfp, unsigned char* passwd, int passlen)
     {
         if (aeshdr.version == 0x00)
         {
-            fprintf(stderr, "Error: Message has been altered or password is incorrect\n");
+            fprintf(stderr,
+                    "Error: Message has been altered or password is "
+                    "incorrect\n");
         }
         else
         {
-            fprintf(stderr, "Error: Message has been altered and should not be trusted\n");
+            fprintf(stderr,
+                    "Error: Message has been altered and should not be "
+                    "trusted\n");
         }
 
         return -1;
@@ -885,7 +890,9 @@ void usage(const char *progname)
         progname_real++;
     }
 
-    fprintf(stderr, "\nusage: %s {-e|-d} [ { -p <password> | -k <keyfile> } ] { [-o <output filename>] <file> | <file> [<file> ...] }\n\n",
+    fprintf(stderr,
+            "\nusage: %s {-e|-d} [ { -p <password> | -k <keyfile> } ] { [-o "
+            "<output filename>] <file> | <file> [<file> ...] }\n\n",
             progname_real);
 }
 
@@ -946,22 +953,25 @@ int main(int argc, char *argv[])
 
     /* Initialize the output filename */
     outfile[0] = '\0';
-    
+
     while ((rc = getopt(argc, argv, "vhdek:p:o:")) != -1)
     {
         switch (rc)
         {
             case 'h':
                 usage(argv[0]);
+                memset_secure(pass, 0, MAX_PASSWD_BUF);
                 return 0;
             case 'v':
                 version(argv[0]);
+                memset_secure(pass, 0, MAX_PASSWD_BUF);
                 return 0;
             case 'd':
                 if (mode != UNINIT)
                 {
                     fprintf(stderr, "Error: only specify one of -d or -e\n");
                     cleanup(outfile);
+                    memset_secure(pass, 0, MAX_PASSWD_BUF);
                     return -1;
                 }
                 mode = DEC;
@@ -971,6 +981,7 @@ int main(int argc, char *argv[])
                 {
                     fprintf(stderr, "Error: only specify one of -d or -e\n");
                     cleanup(outfile);
+                    memset_secure(pass, 0, MAX_PASSWD_BUF);
                     return -1;
                 }
                 mode = ENC;
@@ -980,6 +991,7 @@ int main(int argc, char *argv[])
                 {
                     fprintf(stderr, "Error: password supplied twice\n");
                     cleanup(outfile);
+                    memset_secure(pass, 0, MAX_PASSWD_BUF);
                     return -1;
                 }
                 if (optarg != 0)
@@ -989,6 +1001,7 @@ int main(int argc, char *argv[])
                         fprintf(stderr,
                                 "Error: keyfile cannot be read from stdin\n");
                         cleanup(outfile);
+                        memset_secure(pass, 0, MAX_PASSWD_BUF);
                         return -1;
                     }
 
@@ -996,6 +1009,7 @@ int main(int argc, char *argv[])
                     if (passlen < 0)
                     {
                         cleanup(outfile);
+                        memset_secure(pass, 0, MAX_PASSWD_BUF);
                         return -1;
                     }
                     password_acquired = 1;
@@ -1006,17 +1020,19 @@ int main(int argc, char *argv[])
                 {
                     fprintf(stderr, "Error: password supplied twice\n");
                     cleanup(outfile);
+                    memset_secure(pass, 0, MAX_PASSWD_BUF);
                     return -1;
                 }
                 if (optarg != 0)
                 {
-                    passlen = passwd_to_utf16(  (unsigned char*) optarg,
-                                                strlen((char *)optarg),
-                                                MAX_PASSWD_LEN,
-                                                pass);
+                    passlen = passwd_to_utf16((unsigned char *) optarg,
+                                              strlen((char *) optarg),
+                                              MAX_PASSWD_LEN,
+                                              pass);
                     if (passlen < 0)
                     {
                         cleanup(outfile);
+                        memset_secure(pass, 0, MAX_PASSWD_BUF);
                         return -1;
                     }
                     password_acquired = 1;
@@ -1034,6 +1050,7 @@ int main(int argc, char *argv[])
                     fprintf(stderr, "Error opening output file %s:", optarg);
                     perror("");
                     cleanup(outfile);
+                    memset_secure(pass, 0, MAX_PASSWD_BUF);
                     return -1;
                 }
                 strncpy(outfile, optarg, 1024);
@@ -1043,12 +1060,13 @@ int main(int argc, char *argv[])
                 fprintf(stderr, "Error: Unknown option '%c'\n", rc);
         }
     }
-    
+
     if (optind >= argc)
     {
         fprintf(stderr, "Error: No file argument specified\n");
         usage(argv[0]);
         cleanup(outfile);
+        memset_secure(pass, 0, MAX_PASSWD_BUF);
         return -1;
     }
 
@@ -1057,6 +1075,7 @@ int main(int argc, char *argv[])
         fprintf(stderr, "Error: -e or -d not specified\n");
         usage(argv[0]);
         cleanup(outfile);
+        memset_secure(pass, 0, MAX_PASSWD_BUF);
         return -1;
     }
 
@@ -1068,8 +1087,9 @@ int main(int argc, char *argv[])
         switch (passlen)
         {
             case 0: /* no password in input */
-                fprintf(stderr, "Error: No password supplied.\n");
+                fprintf(stderr, "Error: No password supplied\n");
                 cleanup(outfile);
+                memset_secure(pass, 0, MAX_PASSWD_BUF);
                 return -1;
             case AESCRYPT_READPWD_FOPEN:
             case AESCRYPT_READPWD_FILENO:
@@ -1078,23 +1098,22 @@ int main(int argc, char *argv[])
             case AESCRYPT_READPWD_FGETC:
             case AESCRYPT_READPWD_TOOLONG:
             case AESCRYPT_READPWD_ICONV:
-                fprintf(stderr, "Error in read_password: %s.\n",
+                fprintf(stderr, "Error in read_password: %s\n",
                         read_password_error(passlen));
                 cleanup(outfile);
+                memset_secure(pass, 0, MAX_PASSWD_BUF);
                 return -1;
             case AESCRYPT_READPWD_NOMATCH:
-                fprintf(stderr, "Error: Passwords don't match.\n");
+                fprintf(stderr, "Error: Passwords don't match\n");
                 cleanup(outfile);
+                memset_secure(pass, 0, MAX_PASSWD_BUF);
                 return -1;
         }
 
-        passlen = passwd_to_utf16(  pass,
-                                    strlen((char*)pass),
-                                    MAX_PASSWD_LEN,
-                                    pass);
-
+        // We should never get here, but "just in case"
         if (passlen < 0)
         {
+            fprintf(stderr, "Error: unexpected problem reading password\n");
             cleanup(outfile);
             /* For security reasons, erase the password */
             memset_secure(pass, 0, MAX_PASSWD_BUF);
@@ -1109,7 +1128,9 @@ int main(int argc, char *argv[])
         {
             fclose(outfp);
         }
-        fprintf(stderr, "Error: A single output file may not be specified with multiple input files.\n");
+        fprintf(stderr,
+                "Error: A single output file may not be specified with "
+                "multiple input files\n");
         usage(argv[0]);
         cleanup(outfile);
         /* For security reasons, erase the password */
@@ -1129,7 +1150,9 @@ int main(int argc, char *argv[])
                 {
                     fclose(outfp);
                 }
-                fprintf(stderr, "Error: STDIN may not be specified with multiple input files.\n");
+                fprintf(stderr,
+                        "Error: STDIN may not be specified with multiple input "
+                        "files\n");
                 usage(argv[0]);
                 cleanup(outfile);
                 /* For security reasons, erase the password */
@@ -1155,7 +1178,7 @@ int main(int argc, char *argv[])
             memset_secure(pass, 0, MAX_PASSWD_BUF);
             return -1;
         }
-        
+
         if (mode == ENC)
         {
             if (outfp == NULL)
@@ -1175,7 +1198,7 @@ int main(int argc, char *argv[])
                     return -1;
                 }
             }
-            
+
             rc = encrypt_stream(infp, outfp, pass, passlen);
         }
         else if (mode == DEC)
@@ -1199,14 +1222,14 @@ int main(int argc, char *argv[])
                     return -1;
                 }
             }
-            
+
             /*
              * should probably test against ascii, utf-16le, and utf-16be
              * encodings
              */
             rc = decrypt_stream(infp, outfp, pass, passlen);
         }
-        
+
         if ((infp != stdin) && (infp != NULL))
         {
             fclose(infp);
@@ -1233,7 +1256,7 @@ int main(int argc, char *argv[])
             return -1;
         }
 
-        /* Reset input/output file names and desriptors */
+        /* Reset input/output file names and descriptors */
         outfile[0] = '\0';
         infp = NULL;
         outfp = NULL;
@@ -1241,6 +1264,6 @@ int main(int argc, char *argv[])
 
     /* For security reasons, erase the password */
     memset_secure(pass, 0, MAX_PASSWD_BUF);
-    
+
     return rc;
 }

programming_language: C
filename: aescrypt.h
change_type: ModificationType.MODIFY
diff: @@ -1,7 +1,7 @@
 /*
  * aescrypt.h
  *
- * Copyright (C) 2007-2017
+ * Copyright (C) 2007-2022
  *
  * This software is licensed as "freeware."  Permission to distribute
  * this software in source and binary forms is hereby granted without a
@@ -20,7 +20,8 @@
 #include "aes.h"
 #include "sha256.h"
 
-typedef struct {
+typedef struct
+{
     char aes[3];
     unsigned char version;
     unsigned char last_block_size;

programming_language: C
filename: aescrypt_keygen.c
change_type: ModificationType.MODIFY
diff: @@ -1,6 +1,6 @@
 /*
  *  AES Crypt Key File Generator
- *  Copyright (C) 2007-2017
+ *  Copyright (C) 2007-2022
  *  Paul E. Jones <paulej@packetizer.com>
  *
  * This software is licensed as "freeware."  Permission to distribute
@@ -24,6 +24,8 @@
 
 #ifdef HAVE_CONFIG_H
 #include <config.h>
+#else
+#include "version.h"
 #endif
 #include <stdlib.h>
 #include <stdio.h>
@@ -65,7 +67,7 @@ int generate_password(int length, unsigned char *password)
     unsigned char *p;
     int i, n;
     int passlen;
-    
+
     if ((length <= 0) || (length > MAX_PASSWD_LEN))
     {
         fprintf(stderr, "Invalid password length specified.\n");
@@ -89,16 +91,13 @@ int generate_password(int length, unsigned char *password)
     fclose(randfp);
 
     /* Now ensure each octet is uses the defined character set */
-    for(i = 0, p = pwtemp; i < length; i++, p++)
+    for (i = 0, p = pwtemp; i < length; i++, p++)
     {
         *p = pwchars[((int)(*p)) % 64];
     }
 
     /* Convert the password to UTF-16LE */
-    passlen = passwd_to_utf16(  pwtemp,
-                                length,
-                                MAX_PASSWD_LEN,
-                                password);
+    passlen = passwd_to_utf16(pwtemp, length, MAX_PASSWD_LEN, password);
 
     return passlen;
 }
@@ -211,10 +210,10 @@ int main(int argc, char *argv[])
                 }
                 if (optarg != 0)
                 {
-                    passlen = passwd_to_utf16(  (unsigned char*) optarg,
-                                                strlen((char *)optarg),
-                                                MAX_PASSWD_LEN,
-                                                pass);
+                    passlen = passwd_to_utf16((unsigned char *) optarg,
+                                              strlen((char *) optarg),
+                                              MAX_PASSWD_LEN,
+                                              pass);
                     if (passlen < 0)
                     {
                         return -1;
@@ -227,7 +226,7 @@ int main(int argc, char *argv[])
                 return -1;
         }
     }
-    
+
     file_count = argc - optind;
     if (file_count != 1)
     {
@@ -296,7 +295,7 @@ int main(int argc, char *argv[])
         cleanup(outfile);
         return  -1;
     }
-    
+
     if (fwrite(pass, 1, passlen, outfp) != (size_t) passlen)
     {
         fprintf(stderr, "Error: Could not write password file.\n");

programming_language: C
filename: password.c
change_type: ModificationType.MODIFY
diff: @@ -1,6 +1,6 @@
 /*
  * AES Crypt for Linux
- * Copyright (C) 2007-2017
+ * Copyright (C) 2007-2022
  *
  * Contributors:
  *     Glenn Washburn <crass@berlios.de>
@@ -82,7 +82,6 @@ const char* read_password_error(int error)
  *    >= 0 the password length (0 if empty password is in input)
  *    < 0 error (return value indicating the specific error)
  */
-
 int read_password(unsigned char* buffer, encryptmode_t mode)
 {
 #ifndef WIN32
@@ -110,16 +109,10 @@ int read_password(unsigned char* buffer, encryptmode_t mode)
 #ifndef WIN32
     /* Open the tty */
     ftty = fopen("/dev/tty", "r+");
-    if (ftty == NULL)
-    {
-        return AESCRYPT_READPWD_FOPEN;
-    }
+    if (ftty == NULL) return AESCRYPT_READPWD_FOPEN;
     tty = fileno(ftty);
-    if (tty < 0)
-    {
-        return AESCRYPT_READPWD_FILENO;
-    }
- 
+    if (tty < 0) return AESCRYPT_READPWD_FILENO;
+
     /* Get the tty attrs */
     if (tcgetattr(tty, &t) < 0)
     {
@@ -222,8 +215,7 @@ int read_password(unsigned char* buffer, encryptmode_t mode)
             /* For security reasons, erase the password */
             memset_secure(pwd, 0, MAX_PASSWD_BUF);
             memset_secure(pwd_confirm, 0, MAX_PASSWD_BUF);
-            if (ftty != stderr)
-                fclose(ftty);
+            if (ftty != stderr) fclose(ftty);
             return AESCRYPT_READPWD_FGETC;
         }
 
@@ -236,39 +228,31 @@ int read_password(unsigned char* buffer, encryptmode_t mode)
             /* For security reasons, erase the password */
             memset_secure(pwd, 0, MAX_PASSWD_BUF);
             memset_secure(pwd_confirm, 0, MAX_PASSWD_BUF);
-            if (ftty != stderr)
-                fclose(ftty);
+            if (ftty != stderr) fclose(ftty);
             return AESCRYPT_READPWD_TOOLONG;
         }
     }
 
     /* Close the tty */
-    if (ftty != stderr)
-        fclose(ftty);
+    if (ftty != stderr) fclose(ftty);
 
     /* Password must be compared only when encrypting */
     if (mode == ENC)
     {
         /* Check if passwords match */
-        match = strcmp((char*)pwd, (char*)pwd_confirm);
+        match = strcmp((char *) pwd, (char *) pwd_confirm);
+
+        /* Securely erase the memory for the confirmed password */
         memset_secure(pwd_confirm, 0, MAX_PASSWD_BUF);
 
-        if (match != 0)
-        {
-            /* For security reasons, erase the password */
-            memset_secure(pwd, 0, MAX_PASSWD_BUF);
-            return AESCRYPT_READPWD_NOMATCH;
-        }
+        /* For security reasons, erase the password */
+        if (match != 0) return AESCRYPT_READPWD_NOMATCH;
     }
 
 #ifdef WIN32
     chars_read *= 2;
 #else
-    chars_read = passwd_to_utf16(
-       pwd,
-       chars_read,
-       MAX_PASSWD_LEN,
-       buffer);
+    chars_read = passwd_to_utf16(pwd, chars_read, MAX_PASSWD_LEN, buffer);
 
     if (chars_read < 0) {
         memset_secure(pwd_confirm, 0, MAX_PASSWD_BUF);
@@ -290,17 +274,22 @@ int passwd_to_utf16(unsigned char *in_passwd,
                     int max_length,
                     unsigned char *out_passwd)
 {
+    // Perform a password length check before proceeding
+    if (length > max_length)
+    {
+        fprintf(stderr, "Error: password too long\n");
+        return -1;
+    }
+
 #ifdef WIN32
     int ret;
     (void)length;
-    ret = MultiByteToWideChar(
-        CP_ACP,
-        0,
-        (LPCSTR)in_passwd,
-        -1,
-        (LPWSTR)out_passwd,
-        max_length / 2
-    );
+    ret = MultiByteToWideChar(CP_ACP,
+                              0,
+                              (LPCSTR) in_passwd,
+                              -1,
+                              (LPWSTR) out_passwd,
+                              max_length / 2);
     if (ret == 0)
         return AESCRYPT_READPWD_ICONV;
     return ret * 2;
@@ -308,11 +297,12 @@ int passwd_to_utf16(unsigned char *in_passwd,
 #ifndef ENABLE_ICONV
     /* support only latin */
     int i;
-    for (i=0;i<length+1;i++) {
-        out_passwd[i*2] = in_passwd[i];
-        out_passwd[i*2+1] = 0;
+    for (i = 0; i < length + 1; i++)
+    {
+        out_passwd[i * 2] = in_passwd[i];
+        out_passwd[i * 2 + 1] = 0;
     }
-    return length*2;
+    return length * 2;
 #else
     unsigned char *ic_outbuf,
                   *ic_inbuf;

programming_language: C
filename: password.h
change_type: ModificationType.MODIFY
diff: @@ -1,7 +1,7 @@
 /*
  * password.h
  *
- * Copyright (C) 2007-2017
+ * Copyright (C) 2007-2022
  *
  * This software is licensed as "freeware."  Permission to distribute
  * this software in source and binary forms is hereby granted without a
@@ -44,8 +44,6 @@ int passwd_to_utf16(unsigned char *in_passwd,
 
 const char* read_password_error(int error);
 
-int read_password(unsigned char* buffer,
-                  encryptmode_t mode);
-
+int read_password(unsigned char *buffer, encryptmode_t mode);
 
 #endif /* AESCRYPT_PASSWORD_H */

programming_language: Shell
filename: version.h.in
change_type: ModificationType.ADD
diff: @@ -0,0 +1,23 @@
+/*
+ *  version.h.in
+ *
+ *  Copyright (C) 2022
+ *  Paul E. Jones <paulej@packetizer.com>
+ *  All Rights Reserved
+ *
+ *  Description:
+ *      Defines version information strings that will be built into the
+ *      binary project file.
+ *
+ *  Portability Issues:
+ *      None.
+ */
+
+#ifndef VERSION_H
+#define VERSION_H
+
+static const char PACKAGE_NAME[] = "@PROJECT_NAME@";
+static const char PACKAGE_VERSION[] = "@PROJECT_VERSION@";
+static const char PACKAGE_DATE[] = "@PACKAGE_DATE@";
+
+#endif /* VERSION_H */

programming_language: C++
filename: CMakeLists.txt
change_type: ModificationType.ADD
diff: @@ -0,0 +1,11 @@
+add_executable(sha256_test ${PROJECT_SOURCE_DIR}/src/sha256.c)
+target_compile_definitions(sha256_test PRIVATE TEST)
+add_executable(aes_test ${PROJECT_SOURCE_DIR}/src/aes.c)
+target_compile_definitions(aes_test PRIVATE TEST)
+
+add_test(NAME sha256_test
+         COMMAND sha256_test)
+add_test(NAME aes_test
+         COMMAND aes_test)
+add_test(NAME aescrypt_test
+         COMMAND /bin/bash ${CMAKE_CURRENT_SOURCE_DIR}/test.sh ${aescrypt_BINARY_DIR})

programming_language: Shell
filename: test.sh
change_type: ModificationType.ADD
diff: @@ -0,0 +1,77 @@
+#!/bin/bash -e
+#
+# Encrypting and decrypting text files
+#     usage: test.sh <aescrypt binary build directory>
+#
+
+if [ $# != 1 ] ; then
+    echo Missing binary directory parameter
+    exit 1
+fi
+
+cd $1 || exit 1
+
+# Test zero-length file
+cat /dev/null > test.orig.txt
+./aescrypt -e -p "praxis" test.orig.txt
+cp test.orig.txt.aes test.txt.aes
+./aescrypt -d -p "praxis" test.txt.aes
+cmp test.orig.txt test.txt
+rm test.orig.txt test.orig.txt.aes test.txt.aes test.txt
+# Testing short file (one AES block)
+echo "Testing..." > test.orig.txt
+./aescrypt -e -p "praxis" test.orig.txt
+cp test.orig.txt.aes test.txt.aes
+./aescrypt -d -p "praxis" test.txt.aes
+cmp test.orig.txt test.txt
+rm test.orig.txt test.orig.txt.aes test.txt.aes test.txt
+
+# Test password length boundary
+
+# Test password length 0
+cat /dev/null >test.passwd.txt
+echo "Testing..." > test.txt
+
+# Expecting a failure here, but reflect opposite result code
+./aescrypt -e -p `cat test.passwd.txt` test.txt 2>/dev/null && \
+    echo Password length test 1 failed && \
+    exit 1 || \
+    true
+rm test.txt test.passwd.txt
+
+# Test password length 1023
+cat /dev/null >test.passwd.txt
+for x in `seq 1 1023`; do printf X >>test.passwd.txt; done
+echo "Testing..." > test.txt
+./aescrypt -e -p `cat test.passwd.txt` test.txt
+rm test.txt.aes test.txt test.passwd.txt
+
+# Test password length 1024
+cat /dev/null >test.passwd.txt
+for x in `seq 1 1024`; do printf X >>test.passwd.txt; done
+echo "Testing..." > test.txt
+./aescrypt -e -p `cat test.passwd.txt` test.txt
+rm test.txt.aes test.txt test.passwd.txt
+
+# Test password length 1025
+cat /dev/null >test.passwd.txt
+for x in `seq 1 1025`; do printf X >>test.passwd.txt; done
+echo "Testing..." > test.txt
+
+# Expecting a failure here, but reflect opposite result code
+./aescrypt -e -p `cat test.passwd.txt` test.txt 2>/dev/null && \
+    echo Password length test 2 failed && \
+    exit 1 || \
+    true
+rm test.txt test.passwd.txt
+
+# Testing longer file
+cat /dev/null >test.orig.txt
+for i in `seq 1 50000`; do echo "This is a test" >>test.orig.txt; done
+./aescrypt -e -p "praxis" test.orig.txt
+cp test.orig.txt.aes test.txt.aes
+./aescrypt -d -p "praxis" test.txt.aes
+cmp test.orig.txt test.txt
+rm test.orig.txt test.orig.txt.aes test.txt.aes test.txt
+
+echo AESCrypt tests passed

programming_language: Shell