From 7b7eb161d91992eb32b9decfb896110a1a340c8d Mon Sep 17 00:00:00 2001 From: Guillaume Archambault Date: Thu, 1 Aug 2024 15:35:46 +0200 Subject: [PATCH 1/5] Added the ability to encrypt folders --- cryptr.bash | 62 +++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 48 insertions(+), 14 deletions(-) diff --git a/cryptr.bash b/cryptr.bash index 45e28d5..3582b44 100755 --- a/cryptr.bash +++ b/cryptr.bash @@ -29,8 +29,8 @@ cryptr_help() { echo "Usage: cryptr command " echo cat<, Encrypt file - decrypt , Decrypt encrypted file + encrypt , Encrypt file or directory + decrypt , Decrypt encrypted file or directory help, Displays help version, Displays the current version EOF @@ -38,33 +38,53 @@ EOF } cryptr_encrypt() { - local _file="$1" - if [[ ! -f "$_file" ]]; then - echo "File not found" 1>&2 + local _path="$1" + local _is_directory=0 + if [[ ! -e "$_path" ]]; then + echo "File or directory not found" 1>&2 exit 4 fi + if [[ -d "$_path" ]]; then + tar -czf "${_path}.tar.gz" -C "$(dirname "$_path")" "$(basename "$_path")" + _path="${_path}.tar.gz" + _is_directory=1 + fi + if [[ ! -z "${CRYPTR_PASSWORD}" ]]; then echo "[notice] using environment variable CRYPTR_PASSWORD for the password" - openssl $OPENSSL_CIPHER_TYPE -salt -pbkdf2 -in "$_file" -out "${_file}.aes" -pass env:CRYPTR_PASSWORD + openssl $OPENSSL_CIPHER_TYPE -salt -pbkdf2 -in "$_path" -out "${_path}.aes" -pass env:CRYPTR_PASSWORD else - openssl $OPENSSL_CIPHER_TYPE -salt -pbkdf2 -in "$_file" -out "${_file}.aes" + openssl $OPENSSL_CIPHER_TYPE -salt -pbkdf2 -in "$_path" -out "${_path}.aes" fi if [[ $? -eq 0 ]]; then - read -rp "do you want to delete the original file? (y/N): " confirm - if [[ "$confirm" =~ ^[Yy]$ ]]; then - echo "[notice] deleting the original file" - rm -f "$_file" + if [[ $_is_directory -eq 1 ]]; then + rm -f "$_path" + fi + + if [[ $_is_directory -eq 1 ]]; then + read -p "do you want to delete the original directory? (y/N): " confirm + if [[ "$confirm" =~ ^[Yy]$ ]]; then + echo "[notice] deleting the original directory" + rm -rf "${_path%.tar.gz}" + fi + else + + read -p "do you want to delete the original file? (y/N): " confirm + if [[ "$confirm" =~ ^[Yy]$ ]]; then + echo "[notice] deleting the original file" + rm -f "$_path" + fi fi else - echo "[error] encryption failed, original file not deleted" 1>&2 + echo "[error] encryption failed, original file/directory not deleted" 1>&2 exit 6 fi } cryptr_decrypt() { -local _file="$1" + local _file="$1" if [[ ! -f "$_file" ]]; then echo "File not found" 1>&2 exit 5 @@ -76,6 +96,20 @@ local _file="$1" else openssl $OPENSSL_CIPHER_TYPE -d -salt -pbkdf2 -in "$_file" -out "${_file%\.aes}" fi + + if [[ "${_file%\.aes}" == *.tar.gz ]]; then + read -p "Do you want to extract the decrypted archive? (y/N): " extract_confirm + if [[ "$extract_confirm" =~ ^[Yy]$ ]]; then + tar -xzf "${_file%\.aes}" -C "$(dirname "${_file%\.aes}")" + echo "[notice] archive extracted" + + read -p "Do you want to delete the decrypted tar.gz file? (y/N): " delete_confirm + if [[ "$delete_confirm" =~ ^[Yy]$ ]]; then + rm -f "${_file%\.aes}" + echo "[notice] decrypted tar.gz file deleted" + fi + fi + fi } cryptr_main() { @@ -114,4 +148,4 @@ cryptr_main() { if [[ "$0" == "$BASH_SOURCE" ]]; then cryptr_main "$@" -fi +fi \ No newline at end of file From e8dae21311c309a5d51585065469b7ac36ba3b07 Mon Sep 17 00:00:00 2001 From: Guillaume Archambault Date: Wed, 8 Jan 2025 17:14:13 +0100 Subject: [PATCH 2/5] Updated tests and added a README.md --- tests/README.md | 33 ++++++++++++++ tests/test.bash | 115 ++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 139 insertions(+), 9 deletions(-) create mode 100644 tests/README.md diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 0000000..d096ec7 --- /dev/null +++ b/tests/README.md @@ -0,0 +1,33 @@ +# Testing cryptr + +The test suite verifies both file and directory encryption/decryption functionality. + +## Running Tests + +```bash +# Make the test script executable +chmod +x test.bash + +# Run the tests +./test.bash +``` + +## What is Tested + +The test script performs the following checks: + +1. File encryption/decryption: + - Creates a random test file + - Encrypts it using cryptr + - Verifies the encrypted file exists + - Decrypts the file + - Verifies data integrity using SHA-256 hash + +2. Directory encryption/decryption: + - Creates a test directory with multiple random files + - Encrypts the directory using cryptr + - Verifies the encrypted archive exists + - Decrypts and extracts the directory + - Verifies directory contents integrity using SHA-256 hashes + +All temporary files and directories are automatically cleaned up after testing. diff --git a/tests/test.bash b/tests/test.bash index 2d0736d..411fb30 100755 --- a/tests/test.bash +++ b/tests/test.bash @@ -1,21 +1,62 @@ #!/usr/bin/env bash set -eo pipefail; [[ $TRACE ]] && set -x -plaintext=$(mktemp /tmp/cryptr.XXXXXXXX) -dd if=/dev/urandom bs=4096 count=256 2> /dev/null | LC_ALL=C tr -dc 'A-Za-z0-9' | head -c262144 > "$plaintext" -plaintext_sha=($(openssl dgst -sha256 "$plaintext")) +# Define color codes +GREEN='\033[0;32m' +RED='\033[0;31m' +BLUE='\033[0;34m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color +BOLD='\033[1m' + +# Test counter +TOTAL_TESTS=2 +CURRENT_TEST=0 +FAILED_TESTS=0 + +# Function to display test progress +start_test() { + ((CURRENT_TEST++)) + echo -e "\n${BLUE}Test ${CURRENT_TEST}/${TOTAL_TESTS}${NC} - ${BOLD}$1${NC}" + echo -e "${YELLOW}$2${NC}" +} +# Function to display success +test_success() { + echo -e "${GREEN}✓ Success:${NC} $1" +} + +# Function to display error and exit +test_error() { + echo -e "${RED}✗ Error:${NC} $1" 1>&2 + ((FAILED_TESTS++)) + exit "$2" +} + +echo -e "\n${YELLOW}${BOLD}Running Cryptr Functional Tests${NC}\n" + +# Set environment variables export CRYPTR_PASSWORD CRYPTR_PASSWORD=$(dd if=/dev/urandom bs=200 count=1 2> /dev/null | LC_ALL=C tr -dc 'A-Za-z0-9' | head -c32) -cryptr encrypt "$plaintext" -rm -f "$plaintext" +# Test 1: Single File Encryption/Decryption +start_test "Single File Encryption/Decryption" "Testing encryption and decryption of a single file..." + +plaintext=$(mktemp /tmp/cryptr.XXXXXXXX) +dd if=/dev/urandom bs=4096 count=256 2> /dev/null | LC_ALL=C tr -dc 'A-Za-z0-9' | head -c262144 > "$plaintext" +plaintext_sha=($(openssl dgst -sha256 "$plaintext")) + +echo -e "${BLUE}→${NC} Encrypting file..." +cryptr encrypt "$plaintext" || test_error "Failed to encrypt file" 3 if [[ ! -f "$plaintext".aes ]]; then - printf "Encrypted out file %s was not created" "$plaintext".aes 1>&2 - exit 3 + test_error "Encrypted output file $plaintext.aes was not created" 3 fi +test_success "File encrypted successfully" + +# Original file is already deleted by cryptr after answering 'y' +echo -e "${BLUE}→${NC} Decrypting file..." cryptr decrypt "$plaintext".aes decrypted_sha=($(openssl dgst -sha256 "$plaintext")) @@ -24,6 +65,62 @@ rm -f "$plaintext".aes rm -f "$plaintext" if [ "${plaintext_sha[1]}" != "${decrypted_sha[1]}" ]; then - printf "Hash mismatch\n\t%s != %s" "${plaintext_sha[1]}" "${decrypted_sha[1]}" 1>&2 - exit 4 + test_error "Hash mismatch\n\t${plaintext_sha[1]} != ${decrypted_sha[1]}" 4 +fi +test_success "File decrypted successfully with matching hash" + +# Test 2: Directory Encryption/Decryption +start_test "Directory Encryption/Decryption" "Testing encryption and decryption of a directory..." + +test_dir=$(mktemp -d /tmp/cryptr.XXXXXXXX) +test_file1="$test_dir/file1" +test_file2="$test_dir/file2" + +echo -e "${BLUE}→${NC} Creating test files..." +dd if=/dev/urandom bs=4096 count=256 2> /dev/null | LC_ALL=C tr -dc 'A-Za-z0-9' | head -c262144 > "$test_file1" +dd if=/dev/urandom bs=4096 count=256 2> /dev/null | LC_ALL=C tr -dc 'A-Za-z0-9' | head -c262144 > "$test_file2" +test_success "Test files created" + +dir_sha=($(find "$test_dir" -type f -exec openssl dgst -sha256 {} \; | sort | openssl dgst -sha256)) + +echo -e "${BLUE}→${NC} Encrypting directory..." +if [ ! -d "$test_dir" ]; then + test_error "Test directory not found: $test_dir" 5 +fi + +# First create tar.gz +tar -czf "${test_dir}.tar.gz" -C "$(dirname "$test_dir")" "$(basename "$test_dir")" +test_success "Directory archived" + +# Then encrypt the tar.gz +cryptr encrypt "${test_dir}.tar.gz" || test_error "Failed to encrypt directory archive" 5 + +if [[ ! -f "$test_dir".tar.gz.aes ]]; then + test_error "Encrypted directory archive $test_dir.tar.gz.aes was not created" 5 +fi +test_success "Directory encrypted successfully" + +# Original directory will be deleted when answering 'y' to the prompt + +echo -e "${BLUE}→${NC} Decrypting directory..." +cryptr decrypt "$test_dir".tar.gz.aes +test_success "Directory decrypted and extracted" + +decrypted_dir_sha=($(find "$test_dir" -type f -exec openssl dgst -sha256 {} \; | sort | openssl dgst -sha256)) + +rm -rf "$test_dir" + +if [ "${dir_sha[1]}" != "${decrypted_dir_sha[1]}" ]; then + test_error "Directory hash mismatch\n\t${dir_sha[1]} != ${decrypted_dir_sha[1]}" 6 +fi +test_success "Directory contents verified with matching hash" + +# Print final summary +echo -e "\n${YELLOW}${BOLD}Test Summary${NC}" +if [ "$FAILED_TESTS" -eq 0 ]; then + echo -e "${GREEN}${BOLD}✓ All tests completed successfully!${NC}\n" + exit 0 +else + echo -e "${RED}${BOLD}✗ Some tests failed!${NC}\n" + exit 1 fi From d6e6db916f93d0dd38d57a51bc50f0ff6c3f2d98 Mon Sep 17 00:00:00 2001 From: Guillaume Archambault Date: Wed, 8 Jan 2025 17:16:55 +0100 Subject: [PATCH 3/5] Update bash completion --- tools/cryptr-bash-completion.bash | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/tools/cryptr-bash-completion.bash b/tools/cryptr-bash-completion.bash index 758d7dd..4d230bc 100644 --- a/tools/cryptr-bash-completion.bash +++ b/tools/cryptr-bash-completion.bash @@ -5,10 +5,22 @@ _cryptr_complete() cur_word="${COMP_WORDS[COMP_CWORD]}" prev_word="${COMP_WORDS[COMP_CWORD-1]}" - opts='encrypt decrypt' + opts='encrypt decrypt help version' - COMPREPLY=( $(compgen -W "${opts}" -- ${cur_word}) ) - return 0 + case "$prev_word" in + 'encrypt') + COMPREPLY=( $(compgen -f -d -- ${cur_word}) ) + return 0 + ;; + 'decrypt') + COMPREPLY=( $(compgen -f -G "*.aes" -- ${cur_word}) ) + return 0 + ;; + *) + COMPREPLY=( $(compgen -W "${opts}" -- ${cur_word}) ) + return 0 + ;; + esac } complete -F _cryptr_complete cryptr.bash cryptr From d638d7680de9bdef6042c6c683c57a98c85bbd8f Mon Sep 17 00:00:00 2001 From: Guillaume Archambault Date: Wed, 8 Jan 2025 17:17:14 +0100 Subject: [PATCH 4/5] Add zsh completion --- tools/cryptr-zsh-completion.zsh | 35 +++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 tools/cryptr-zsh-completion.zsh diff --git a/tools/cryptr-zsh-completion.zsh b/tools/cryptr-zsh-completion.zsh new file mode 100644 index 0000000..72ba292 --- /dev/null +++ b/tools/cryptr-zsh-completion.zsh @@ -0,0 +1,35 @@ +# Initialize zsh completion system if not already done +autoload -Uz compinit +compinit + +_cryptr() { + local -a commands + commands=( + 'encrypt:Encrypt files' + 'decrypt:Decrypt files' + 'help:Show help' + 'version:Show version' + ) + + _arguments -C \ + '1: :->cmds' \ + '*:: :->args' + + case "$state" in + cmds) + _describe -t commands 'commands' commands + ;; + args) + case $words[1] in + encrypt) + _files + ;; + decrypt) + _files -g "*.aes" + ;; + esac + ;; + esac +} + +compdef _cryptr cryptr From f9deb0e9e755dd381881f99a05857a087f6b8b2f Mon Sep 17 00:00:00 2001 From: Guillaume Archambault Date: Wed, 8 Jan 2025 17:18:10 +0100 Subject: [PATCH 5/5] Fork Related Changes --- AUTHORS.md | 7 +++- CHANGELOG.md | 10 +++++ README.md | 105 +++++++++++++++++++++++++++++++-------------------- cryptr.bash | 8 ++-- 4 files changed, 84 insertions(+), 46 deletions(-) mode change 100755 => 100644 cryptr.bash diff --git a/AUTHORS.md b/AUTHORS.md index 60e2ca2..b6b337b 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -1,5 +1,10 @@ +# cryptr+ Authors + +## Current Maintainer +- Guillaume Archambault ([Gu1llaum-3](https://github.com/Gu1llaum-3)) + +## Original cryptr Authors and Contributors - Justin Keller ([nodesocket](https://github.com/nodesocket)) - Manuel Wildauer ([int9h](https://github.com/int9h)) - Adam Daniels ([adam12](https://github.com/adam12)) - Nicolas Le Gall ([Darkitty](https://github.com/Darkitty)) -- Gu1llaum-3 ([Gu1llaum-3](https://github.com/Gu1llaum-3)) diff --git a/CHANGELOG.md b/CHANGELOG.md index a34560a..4f27ee2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,16 @@ CHANGELOG ========= +## 3.0.0 - *1/8/2025* + +- Fork from cryptr to create cryptr+ +- Added support for directory encryption/decryption using tar.gz +- Updated all documentation and tests +- Improved shell completion support: + - Added zsh completion script + - Updated bash completion script + - Enhanced README.md with detailed completion setup instructions for both shells + ## 2.3.0 - *7/30/2024* - Prompt to confirm deleting original file when invoking encrypt. diff --git a/README.md b/README.md index 6542019..753a864 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,68 @@ # cryptr -#### A simple shell utility for encrypting and decrypting files using OpenSSL. +#### An enhanced shell utility for encrypting and decrypting files and directories using OpenSSL. + +This is a fork of [cryptr](https://github.com/nodesocket/cryptr) by Justin Keller, with added support for directory encryption. ## Installation ``` -git clone https://github.com/nodesocket/cryptr.git +git clone https://github.com/Gu1llaum-3/cryptr.git ln -s "$PWD"/cryptr/cryptr.bash /usr/local/bin/cryptr ``` -### Bash tab completion +### Shell Completion + +cryptr supports command completion for both Bash and Zsh shells. + +#### Bash Completion + +There are two ways to enable bash completion: + +1. **Temporary (current session):** +```bash +source tools/cryptr-bash-completion.bash +``` + +2. **Permanent:** +```bash +# Create completion directory if needed +mkdir -p ~/.bash_completion.d/ +# Copy completion file +cp tools/cryptr-bash-completion.bash ~/.bash_completion.d/ +# Add to ~/.bashrc or ~/.bash_profile +echo 'source ~/.bash_completion.d/cryptr-bash-completion.bash' >> ~/.bashrc +``` + +#### Zsh Completion + +Similarly for zsh: + +1. **Temporary (current session):** +```zsh +source tools/cryptr-zsh-completion.zsh +``` + +2. **Permanent:** +```zsh +# Create zsh directory if needed +mkdir -p ~/.zsh +# Copy completion file +cp tools/cryptr-zsh-completion.zsh ~/.zsh/ +# Add to ~/.zshrc +echo 'source ~/.zsh/cryptr-zsh-completion.zsh' >> ~/.zshrc +``` -Add `tools/cryptr-bash-completion.bash` to your tab completion file directory. +After enabling completion, you can use: +- TAB after 'cryptr' to see available commands (encrypt, decrypt, help, version) +- TAB after 'encrypt' to see all files and directories +- TAB after 'decrypt' to see only .aes encrypted files ## API/Commands ### encrypt -> encrypt \ - Encryptes file with OpenSSL AES-256 cipher block chaining. Writes an encrypted file out *(ciphertext)* appending `.aes` extension. +> encrypt \ - Encrypts file or directory with OpenSSL AES-256 cipher block chaining. For files, writes an encrypted file out *(ciphertext)* appending `.aes` extension. For directories, creates a tar.gz archive first, then encrypts it with `.tar.gz.aes` extension. ``` ➜ cryptr encrypt ./secret-file @@ -26,9 +71,9 @@ Verifying - enter aes-256-cbc encryption password: ``` ``` -➜ ls -alh --rw-r--r-- 1 user group 1.0G Oct 1 13:33 secret-file --rw-r--r-- 1 user group 1.0G Oct 1 13:34 secret-file.aes +➜ cryptr encrypt ./secret-directory +enter aes-256-cbc encryption password: +Verifying - enter aes-256-cbc encryption password: ``` You may optionally define the password to use when encrypting using the `CRYPTR_PASSWORD` environment variable. This enables non-interactive/batch operations. @@ -39,12 +84,7 @@ You may optionally define the password to use when encrypting using the `CRYPTR_ ### decrypt -> decrypt \ - Decrypt encrypted file using OpenSSL AES-256 cipher block chaining. Writes a decrypted file out *(plaintext)* removing `.aes` extension. - -``` -➜ ls -alh --rw-r--r-- 1 user group 1.0G Oct 1 13:34 secret-file.aes -``` +> decrypt \ - Decrypt encrypted file or directory using OpenSSL AES-256 cipher block chaining. For files, writes a decrypted file out *(plaintext)* removing `.aes` extension. For directories, removes `.aes` extension and optionally extracts the tar.gz archive. ``` ➜ cryptr decrypt ./secret-file.aes @@ -52,9 +92,9 @@ enter aes-256-cbc decryption password: ``` ``` -➜ ls -alh --rw-r--r-- 1 user group 1.0G Oct 1 13:35 secret-file --rw-r--r-- 1 user group 1.0G Oct 1 13:34 secret-file.aes +➜ cryptr decrypt ./secret-directory.tar.gz.aes +enter aes-256-cbc decryption password: +Do you want to extract the decrypted archive? (y/N): y ``` You may optionally define the password to use when decrypting using the `CRYPTR_PASSWORD` environment variable. This enables non-interactive/batch operations. @@ -71,11 +111,10 @@ You may optionally define the password to use when decrypting using the `CRYPTR_ ➜ cryptr help Usage: cryptr command - encrypt Encrypt file - decrypt Decrypt encrypted file + encrypt Encrypt file or directory + decrypt Decrypt encrypted file or directory help Displays help version Displays the current version - ``` ### version @@ -84,33 +123,16 @@ Usage: cryptr command ``` ➜ cryptr version -cryptr 2.3.0 -``` - -### default - -> default - Displays the current version and help - -``` -➜ cryptr -cryptr 2.3.0 - -Usage: cryptr command - - encrypt Encrypt file - decrypt Decrypt encrypted file - help Displays help - version Displays the current version - +cryptr 3.0.0 ``` ## Changelog -https://github.com/nodesocket/cryptr/blob/master/CHANGELOG.md +See CHANGELOG.md ## Support, Bugs, And Feature Requests -Create issues here in GitHub (https://github.com/nodesocket/cryptr/issues). +Create issues here in GitHub (https://github.com/Gu1llaum-3/cryptr/issues). ## Versioning @@ -130,7 +152,8 @@ For more information on semantic versioning, visit http://semver.org/. ## License & Legal -Copyright 2024 Justin Keller +Copyright 2024 Guillaume Archambault +Based on cryptr by Justin Keller Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/cryptr.bash b/cryptr.bash old mode 100755 new mode 100644 index 3582b44..8a7e3ec --- a/cryptr.bash +++ b/cryptr.bash @@ -1,7 +1,8 @@ #!/usr/bin/env bash ############################################################################### -# Copyright 2024 Justin Keller +# Copyright 2025 Guillaume Archambault +# Based on cryptr by Justin Keller # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -18,7 +19,7 @@ set -eo pipefail; [[ $TRACE ]] && set -x -readonly VERSION="2.3.0" +readonly VERSION="3.0.0" readonly OPENSSL_CIPHER_TYPE="aes-256-cbc" cryptr_version() { @@ -70,7 +71,6 @@ cryptr_encrypt() { rm -rf "${_path%.tar.gz}" fi else - read -p "do you want to delete the original file? (y/N): " confirm if [[ "$confirm" =~ ^[Yy]$ ]]; then echo "[notice] deleting the original file" @@ -148,4 +148,4 @@ cryptr_main() { if [[ "$0" == "$BASH_SOURCE" ]]; then cryptr_main "$@" -fi \ No newline at end of file +fi