#!/usr/bin/env bash # encrypt_file # ------------ # Cifra o descifra un archivo usando AES-256-CBC con PBKDF2 (310.000 iteraciones). # La contraseña se lee de la variable de entorno ENCRYPT_PASSWORD o se solicita # interactivamente por stdin. # # USO (directo): # encrypt_file encrypt # encrypt_file decrypt # ENCRYPT_PASSWORD=secreto encrypt_file encrypt archivo.txt # # Depende de: openssl SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$SCRIPT_DIR/../shell/bash_colors.sh" source "$SCRIPT_DIR/../shell/bash_log.sh" bash_colors bash_log_init # ─── Funciones puras ────────────────────────────────────────────────────────── _enc_output_path_encrypt() { local input="$1" echo "${input}.enc" } _enc_output_path_decrypt() { local input="$1" if [[ "$input" == *.enc ]]; then echo "${input%.enc}" else echo "${input}.dec" fi } _enc_human_size() { local file="$1" du -sh "$file" 2>/dev/null | cut -f1 } # ─── Funciones de efecto ──────────────────────────────────────────name────────── _enc_ask_password() { local pass read -rsp "Contraseña: " pass echo "" >&2 echo "$pass" } _enc_ask_password_confirm() { local pass1 pass2 read -rsp "Contraseña: " pass1 echo "" >&2 read -rsp "Confirmar contraseña: " pass2 echo "" >&2 if [[ "$pass1" != "$pass2" ]]; then error "Las contraseñas no coinciden" >&2 return 1 fi if [[ ${#pass1} -lt 8 ]]; then warning "La contraseña es muy corta (mínimo 8 caracteres recomendado)" fi echo "$pass1" } _enc_do_encrypt() { local input="$1" local output="$2" local password="$3" openssl enc -aes-256-cbc -pbkdf2 -iter 310000 \ -in "$input" -out "$output" \ -pass "pass:${password}" 2>/dev/null } _enc_do_decrypt() { local input="$1" local output="$2" local password="$3" openssl enc -d -aes-256-cbc -pbkdf2 -iter 310000 \ -in "$input" -out "$output" \ -pass "pass:${password}" 2>/dev/null } # ─── Punto de entrada ───────────────────────────────────────────────────────── encrypt_file() { local mode="$1" local file="$2" if [[ -z "$mode" || -z "$file" ]]; then error "encrypt_file: uso: encrypt_file " >&2 return 1 fi if ! command -v openssl &>/dev/null; then error "encrypt_file: 'openssl' no está instalado (sudo apt install openssl)" >&2 return 1 fi if [[ ! -f "$file" ]]; then error "encrypt_file: archivo no encontrado: $file" >&2 return 1 fi local password if [[ -n "${ENCRYPT_PASSWORD:-}" ]]; then password="$ENCRYPT_PASSWORD" else case "$mode" in encrypt) password="$(_enc_ask_password_confirm)" || return 1 ;; decrypt) password="$(_enc_ask_password)" ;; *) error "encrypt_file: modo no válido '$mode'. Use: encrypt|decrypt" >&2 return 1 ;; esac fi case "$mode" in encrypt) local output output="$(_enc_output_path_encrypt "$file")" info "Archivo: ${file} ($(_enc_human_size "$file"))" info "Salida: ${output}" info "Cifrando con AES-256-CBC + PBKDF2..." if _enc_do_encrypt "$file" "$output" "$password"; then success "Archivo cifrado: ${output} ($(_enc_human_size "$output"))" else error "encrypt_file: el cifrado falló" >&2 rm -f "$output" return 1 fi ;; decrypt) local output output="$(_enc_output_path_decrypt "$file")" info "Archivo: ${file} ($(_enc_human_size "$file"))" info "Salida: ${output}" info "Descifrando..." if _enc_do_decrypt "$file" "$output" "$password"; then success "Archivo descifrado: ${output} ($(_enc_human_size "$output"))" else error "encrypt_file: el descifrado falló -- ¿contraseña incorrecta?" >&2 rm -f "$output" return 1 fi ;; esac # Limpiar contraseña de memoria password="" } # Ejecutar si se llama directamente if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then encrypt_file "$@" fi