# Multi-stage build: Use Alpine for building, scratch for final image # Alpine is the smallest base image (~5MB) with package manager FROM alpine:latest AS build # Install build dependencies with --no-cache to prevent package cache storage # build-base: gcc, make, and essential build tools # musl-dev: C library headers for static linking # linux-headers: Kernel headers for system calls # upx: Ultimate Packer for eXecutables - binary compression tool # binutils: For objcopy command RUN apk add --no-cache build-base musl-dev linux-headers upx binutils # Set working directory for all subsequent operations WORKDIR /src # Copy all yescrypt source and header files flat (no subdirectories) COPY yescrypt/*.h . COPY yescrypt/yescrypt-ref.c . COPY yescrypt/yescrypt-common.c . COPY yescrypt/sha256.c . COPY yescrypt/insecure_memzero.c . # Copy main bruteforce source code COPY bruteforce.c . # Enhanced compilation with maximum size optimization # Each flag explained: # -static: Create statically linked executable (no external dependencies) # -Os: Optimize for size, not speed # -s: Strip all symbol table and relocation information # -fomit-frame-pointer: Don't keep frame pointer in registers (saves one register) # -fdata-sections: Place each data item in its own section (enables dead code elimination) # -ffunction-sections: Place each function in its own section (enables dead code elimination) # -fno-unwind-tables: Don't generate unwind tables for exception handling # -fno-asynchronous-unwind-tables: Don't generate async unwind tables # -Wl,--gc-sections: Remove unused sections during linking (dead code elimination) # -Wl,--strip-all: Strip all symbols during linking RUN gcc -static -Os -s \ -fomit-frame-pointer \ -fdata-sections \ -ffunction-sections \ -fno-unwind-tables \ -fno-asynchronous-unwind-tables \ -Wl,--gc-sections \ -Wl,--strip-all \ -o bruteforce \ bruteforce.c \ yescrypt-ref.c \ yescrypt-common.c \ sha256.c \ insecure_memzero.c \ # Additional binary stripping to remove specific sections: # --strip-all: Remove all symbol and debug information # --remove-section=.comment: Remove compiler/version comments # --remove-section=.note.*: Remove all note sections (build info, ABI notes) # --remove-section=.eh_frame: Remove exception handling frame information && strip --strip-all \ --remove-section=.comment \ --remove-section=.note.* \ --remove-section=.eh_frame \ bruteforce \ # === Remove residual padding BEFORE compression === \ && objcopy --pad-to=0 --gap-fill=0 bruteforce bruteforce.pad \ && mv bruteforce.pad bruteforce \ # === UPX variant shoot-out: keep smaller of two compressions === \ && cp bruteforce bruteforce.ultra && upx --ultra-brute bruteforce.ultra \ && cp bruteforce bruteforce.lzma && upx --lzma --best --no-align bruteforce.lzma \ && if [ $(stat -c%s bruteforce.ultra) -le $(stat -c%s bruteforce.lzma) ]; then \ mv bruteforce.ultra bruteforce; rm bruteforce.lzma; \ else \ mv bruteforce.lzma bruteforce; rm bruteforce.ultra; \ fi # Final stage: Start with completely empty image (scratch) # This ensures absolute minimum size - no OS layer at all FROM scratch # Copy only the final compressed binary from build stage # --from=build: Copy from the build stage, not from host COPY --from=build /src/bruteforce / # Set the default command for the container # Array format prevents shell interpretation and reduces overhead ENTRYPOINT ["/bruteforce"]