├── .gitmodules ├── .gitignore ├── src ├── safe_rw.h ├── common.h ├── encpipe_p.h ├── safe_rw.c └── encpipe.c ├── LICENSE ├── README.md ├── Makefile └── .clang-format /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "ext/libhydrogen"] 2 | path = ext/libhydrogen 3 | url = https://github.com/jedisct1/libhydrogen 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.bc 2 | *.cmake 3 | *.dSYM 4 | *.done 5 | *.final 6 | *.gcda 7 | *.gcno 8 | *.i 9 | *.la 10 | *.lo 11 | *.log 12 | *.mem 13 | *.nexe 14 | *.o 15 | *.plist 16 | *.scan 17 | *.sdf 18 | *.status 19 | *.su 20 | *.tar.* 21 | *~ 22 | .DS_Store 23 | .deps 24 | .dirstamp 25 | .done 26 | .libs 27 | build.options.json 28 | coverage.info 29 | depcomp 30 | encpipe 31 | -------------------------------------------------------------------------------- /src/safe_rw.h: -------------------------------------------------------------------------------- 1 | #ifndef safe_rw_H 2 | #define safe_rw_H 3 | 4 | #include 5 | #include 6 | 7 | ssize_t safe_write(const int fd, const void* const buf_, size_t count, const int timeout); 8 | 9 | ssize_t safe_read(const int fd, void* const buf_, size_t count); 10 | 11 | ssize_t safe_read_partial(const int fd, void* const buf_, const size_t max_count); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | /* 2 | * ISC License 3 | * 4 | * Copyright (c) 2018-2025 5 | * Frank Denis 6 | * 7 | * Permission to use, copy, modify, and/or distribute this software for any 8 | * purpose with or without fee is hereby granted, provided that the above 9 | * copyright notice and this permission notice appear in all copies. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | */ 19 | -------------------------------------------------------------------------------- /src/common.h: -------------------------------------------------------------------------------- 1 | #ifndef common_H 2 | #define common_H 1 3 | 4 | #define LOAD32_LE(SRC) load32_le(SRC) 5 | static inline uint32_t 6 | load32_le(const uint8_t src[4]) 7 | { 8 | uint32_t w = (uint32_t) src[0]; 9 | w |= (uint32_t) src[1] << 8; 10 | w |= (uint32_t) src[2] << 16; 11 | w |= (uint32_t) src[3] << 24; 12 | return w; 13 | } 14 | 15 | #define STORE32_LE(DST, W) store32_le((DST), (W)) 16 | static inline void 17 | store32_le(uint8_t dst[4], uint32_t w) 18 | { 19 | dst[0] = (uint8_t) w; 20 | w >>= 8; 21 | dst[1] = (uint8_t) w; 22 | w >>= 8; 23 | dst[2] = (uint8_t) w; 24 | w >>= 8; 25 | dst[3] = (uint8_t) w; 26 | } 27 | 28 | static void 29 | die(int print_errno, const char *format, ...) 30 | { 31 | va_list ap; 32 | 33 | va_start(ap, format); 34 | vfprintf(stderr, format, ap); 35 | va_end(ap); 36 | if (print_errno) { 37 | fprintf(stderr, "- %s", strerror(errno)); 38 | } 39 | fprintf(stderr, "\n"); 40 | 41 | exit(1); 42 | } 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /src/encpipe_p.h: -------------------------------------------------------------------------------- 1 | #ifndef encpipe_p_H 2 | #define encpipe_p_H 1 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | 21 | #include "common.h" 22 | #include "safe_rw.h" 23 | 24 | #define MIN_BUFFER_SIZE 512 25 | #define MAX_BUFFER_SIZE 0x7fffffff 26 | #define DEFAULT_BUFFER_SIZE (1 * 1024 * 1024) 27 | #define HYDRO_CONTEXT "EncPipe" 28 | #define PWHASH_OPSLIMIT 1000000 29 | #define PWHASH_MEMLIMIT 0 30 | #define PWHASH_THREADS 1 31 | 32 | typedef struct Context_ { 33 | char * in; 34 | char * out; 35 | unsigned char key[hydro_secretbox_KEYBYTES]; 36 | unsigned char *buf; 37 | size_t sizeof_buf; 38 | int fd_in; 39 | int fd_out; 40 | int encrypt; 41 | int has_key; 42 | } Context; 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Encpipe 2 | ======= 3 | 4 | The dum^H^H^Hsimplest encryption tool in the world. 5 | 6 | # Usage 7 | 8 | Encrypt a file using a password: 9 | 10 | ```sh 11 | encpipe -e -p password -i inputfile -o outputfile 12 | ``` 13 | 14 | Decrypt a file using a password: 15 | 16 | ```sh 17 | encpipe -d -p password -i inputfile -o outputfile 18 | ``` 19 | 20 | `-i` and `-o` can be set to `-` or omitted to read/write from the 21 | standard input/output. 22 | 23 | `-P password_file` can be used to read the password, or an arbitrary 24 | long key (that doesn't have to be text) from a file. 25 | 26 | If you don't feel inspired, `-G` prints a random password. 27 | 28 | Example - encrypted file transfer: 29 | 30 | ```sh 31 | nc -l 6666 | encpipe -d -p password 32 | encpipe -e -p password -i /etc/passwd | nc 127.0.0.1 6666 33 | ``` 34 | 35 | Example - compressed, encrypted archives: 36 | 37 | ```sh 38 | zstd -5 -v -c "$FILE" | encpipe -e -p "$PASSWD" -o "${FILE}.zst.encpipe" 39 | ``` 40 | 41 | # Dependencies 42 | 43 | None. It includes [libhydrogen](https://libhydrogen.org) as a 44 | submodule. There is nothing to install. 45 | 46 | # Installation 47 | 48 | ```sh 49 | make 50 | sudo make install 51 | ``` 52 | 53 | # Why 54 | 55 | It was faster to write than remember how to use GnuPG and OpenSSL. 56 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PREFIX ?= /usr/local 2 | WFLAGS ?= -Wall -Wextra -Wmissing-prototypes -Wdiv-by-zero -Wbad-function-cast -Wcast-align -Wcast-qual -Wfloat-equal -Wmissing-declarations -Wnested-externs -Wno-unknown-pragmas -Wpointer-arith -Wredundant-decls -Wstrict-prototypes -Wswitch-enum -Wno-type-limits 3 | CFLAGS ?= -O3 -mtune=native -fno-exceptions -flto $(WFLAGS) 4 | CPPFLAGS += -I. -Iext/libhydrogen 5 | STRIP ?= strip 6 | 7 | OBJ = ext/libhydrogen/hydrogen.o src/encpipe.o src/safe_rw.o 8 | 9 | SRC = \ 10 | ext/libhydrogen/hydrogen.c \ 11 | src/common.h \ 12 | src/encpipe.c \ 13 | src/encpipe_p.h \ 14 | src/safe_rw.c \ 15 | src/safe_rw.h 16 | 17 | all: bin test 18 | 19 | bin: encpipe 20 | 21 | $(OBJ): $(SRC) 22 | 23 | .c.o: 24 | $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< 25 | 26 | encpipe: $(OBJ) 27 | $(CC) $(CFLAGS) -o encpipe $(LDFLAGS) $(OBJ) 28 | 29 | ext/libhydrogen/hydrogen.c: 30 | git submodule update --init || echo "** Make sure you cloned the repository **" >&2 31 | 32 | install: all 33 | -$(STRIP) --strip-all encpipe 2> /dev/null || $(STRIP) encpipe 2> /dev/null 34 | mkdir -p $(PREFIX)/bin 35 | install -o 0 -g 0 -m 0755 encpipe $(PREFIX)/bin 2> /dev/null || install -m 0755 encpipe $(PREFIX)/bin 36 | 37 | uninstall: 38 | rm -f $(PREFIX)/bin/encpipe 39 | 40 | test: bin 41 | @echo test | ./encpipe -e -p password | ./encpipe -d -p password -o /dev/null 42 | 43 | .PHONY: clean 44 | 45 | clean: 46 | rm -f encpipe $(OBJ) 47 | 48 | distclean: clean 49 | 50 | .SUFFIXES: .c .o 51 | 52 | check: test 53 | 54 | distclean: clean 55 | -------------------------------------------------------------------------------- /src/safe_rw.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #ifndef SSIZE_MAX 12 | #define SSIZE_MAX (SIZE_MAX / 2 - 1) 13 | #endif 14 | 15 | #include "safe_rw.h" 16 | 17 | ssize_t 18 | safe_write(const int fd, const void *const buf_, size_t count, const int timeout) 19 | { 20 | struct pollfd pfd; 21 | const char * buf = (const char *) buf_; 22 | ssize_t written; 23 | 24 | pfd.fd = fd; 25 | pfd.events = POLLOUT; 26 | 27 | assert(count <= SSIZE_MAX); 28 | while (count > (size_t) 0) { 29 | while ((written = write(fd, buf, count)) <= (ssize_t) 0) { 30 | if (errno == EAGAIN) { 31 | if (poll(&pfd, (nfds_t) 1, timeout) == 0) { 32 | errno = ETIMEDOUT; 33 | goto ret; 34 | } 35 | } else if (errno != EINTR) { 36 | goto ret; 37 | } 38 | } 39 | buf += written; 40 | count -= (size_t) written; 41 | } 42 | ret: 43 | return (ssize_t)(buf - (const char *) buf_); 44 | } 45 | 46 | ssize_t 47 | safe_read(const int fd, void *const buf_, size_t count) 48 | { 49 | unsigned char *buf = (unsigned char *) buf_; 50 | ssize_t readnb; 51 | 52 | assert(count <= SSIZE_MAX); 53 | do { 54 | while ((readnb = read(fd, buf, count)) < (ssize_t) 0 && errno == EINTR) 55 | ; 56 | if (readnb < (ssize_t) 0) { 57 | return readnb; 58 | } 59 | if (readnb == (ssize_t) 0) { 60 | break; 61 | } 62 | count -= (size_t) readnb; 63 | buf += readnb; 64 | } while (count > (ssize_t) 0); 65 | 66 | return (ssize_t)(buf - (unsigned char *) buf_); 67 | } 68 | 69 | ssize_t 70 | safe_read_partial(const int fd, void *const buf_, const size_t max_count) 71 | { 72 | unsigned char *const buf = (unsigned char *) buf_; 73 | ssize_t readnb; 74 | 75 | assert(max_count <= SSIZE_MAX); 76 | while ((readnb = read(fd, buf, max_count)) < (ssize_t) 0 && errno == EINTR) 77 | ; 78 | 79 | return readnb; 80 | } 81 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | AccessModifierOffset: -4 4 | AlignAfterOpenBracket: Align 5 | AlignConsecutiveAssignments: true 6 | AlignConsecutiveDeclarations: true 7 | AlignEscapedNewlinesLeft: true 8 | AlignOperands: true 9 | AlignTrailingComments: true 10 | AllowAllParametersOfDeclarationOnNextLine: true 11 | AllowShortBlocksOnASingleLine: false 12 | AllowShortCaseLabelsOnASingleLine: false 13 | AllowShortFunctionsOnASingleLine: Inline 14 | AllowShortIfStatementsOnASingleLine: false 15 | AllowShortLoopsOnASingleLine: false 16 | AlwaysBreakAfterDefinitionReturnType: None 17 | AlwaysBreakAfterReturnType: TopLevelDefinitions 18 | AlwaysBreakBeforeMultilineStrings: true 19 | AlwaysBreakTemplateDeclarations: true 20 | BinPackArguments: true 21 | BinPackParameters: true 22 | BraceWrapping: 23 | AfterClass: false 24 | AfterControlStatement: false 25 | AfterEnum: false 26 | AfterFunction: true 27 | AfterNamespace: false 28 | AfterObjCDeclaration: false 29 | AfterStruct: false 30 | AfterUnion: false 31 | BeforeCatch: false 32 | BeforeElse: false 33 | IndentBraces: false 34 | BreakBeforeBinaryOperators: None 35 | BreakBeforeBraces: WebKit 36 | BreakBeforeTernaryOperators: true 37 | BreakConstructorInitializersBeforeComma: true 38 | BreakAfterJavaFieldAnnotations: false 39 | BreakStringLiterals: true 40 | ColumnLimit: 100 41 | CommentPragmas: '^ IWYU pragma:' 42 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 43 | ConstructorInitializerIndentWidth: 4 44 | ContinuationIndentWidth: 4 45 | Cpp11BracedListStyle: false 46 | DerivePointerAlignment: true 47 | DisableFormat: false 48 | ExperimentalAutoDetectBinPacking: false 49 | ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] 50 | IncludeCategories: 51 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/' 52 | Priority: 2 53 | - Regex: '^(<|"(gtest|isl|json)/)' 54 | Priority: 3 55 | - Regex: '.*' 56 | Priority: 1 57 | IncludeIsMainRegex: '$' 58 | IndentCaseLabels: false 59 | IndentWidth: 4 60 | IndentWrappedFunctionNames: false 61 | JavaScriptQuotes: Leave 62 | JavaScriptWrapImports: true 63 | KeepEmptyLinesAtTheStartOfBlocks: false 64 | MacroBlockBegin: '' 65 | MacroBlockEnd: '' 66 | MaxEmptyLinesToKeep: 1 67 | NamespaceIndentation: Inner 68 | ObjCBlockIndentWidth: 4 69 | ObjCSpaceAfterProperty: true 70 | ObjCSpaceBeforeProtocolList: true 71 | PenaltyBreakBeforeFirstCallParameter: 19 72 | PenaltyBreakComment: 300 73 | PenaltyBreakFirstLessLess: 120 74 | PenaltyBreakString: 1000 75 | PenaltyExcessCharacter: 1000000 76 | PenaltyReturnTypeOnItsOwnLine: 60 77 | PointerAlignment: Right 78 | ReflowComments: true 79 | SortIncludes: true 80 | SpaceAfterCStyleCast: true 81 | SpaceAfterTemplateKeyword: true 82 | SpaceBeforeAssignmentOperators: true 83 | SpaceBeforeParens: ControlStatements 84 | SpaceInEmptyParentheses: false 85 | SpacesBeforeTrailingComments: 1 86 | SpacesInAngles: false 87 | SpacesInContainerLiterals: true 88 | SpacesInCStyleCastParentheses: false 89 | SpacesInParentheses: false 90 | SpacesInSquareBrackets: false 91 | Standard: Cpp11 92 | TabWidth: 8 93 | UseTab: Never 94 | ... 95 | 96 | -------------------------------------------------------------------------------- /src/encpipe.c: -------------------------------------------------------------------------------- 1 | #include "encpipe_p.h" 2 | 3 | static struct option getopt_long_options[] = { 4 | { "help", 0, NULL, 'h' }, { "decrypt", 0, NULL, 'd' }, { "encrypt", 0, NULL, 'e' }, 5 | { "in", 1, NULL, 'i' }, { "out", 1, NULL, 'o' }, { "pass", 1, NULL, 'p' }, 6 | { "passfile", 1, NULL, 'P' }, { "passgen", 0, NULL, 'G' }, { NULL, 0, NULL, 0 } 7 | }; 8 | static const char *getopt_options = "hdeGi:o:p:P:"; 9 | 10 | static void 11 | usage(FILE *stream) 12 | { 13 | fputs( 14 | "Usage:\n" 15 | " encpipe -G\n" 16 | " encpipe {-e | -d} {-p | -P } [-i ] [-o ]\n" 17 | "\n" 18 | "Options:\n" 19 | " -G, --passgen generate a random password\n" 20 | " -e, --encrypt encryption mode\n" 21 | " -d, --decrypt decryption mode\n" 22 | " -p, --pass use \n" 23 | " -P, --passfile read password from \n" 24 | " -i, --in read input from \n" 25 | " -o, --out write output to \n" 26 | " -h, --help print this message\n", 27 | stream); 28 | exit(2); 29 | } 30 | 31 | static int 32 | file_open(const char *file, int create) 33 | { 34 | int fd; 35 | 36 | if (file == NULL || (file[0] == '-' && file[1] == 0)) { 37 | return create ? STDOUT_FILENO : STDIN_FILENO; 38 | } 39 | fd = create ? open(file, O_CREAT | O_WRONLY | O_TRUNC, 0644) : open(file, O_RDONLY); 40 | if (fd == -1) { 41 | die(1, "Unable to access [%s]", file); 42 | } 43 | return fd; 44 | } 45 | 46 | static void 47 | derive_key(Context *ctx, char *password, size_t password_len) 48 | { 49 | static uint8_t master_key[hydro_pwhash_MASTERKEYBYTES] = { 0 }; 50 | 51 | if (ctx->has_key) { 52 | die(0, "A single key is enough"); 53 | } 54 | if (hydro_pwhash_deterministic(ctx->key, sizeof ctx->key, password, password_len, HYDRO_CONTEXT, 55 | master_key, PWHASH_OPSLIMIT, PWHASH_MEMLIMIT, 56 | PWHASH_THREADS) != 0) { 57 | die(0, "Password hashing failed"); 58 | } 59 | hydro_memzero(password, password_len); 60 | ctx->has_key = 1; 61 | } 62 | 63 | static int 64 | stream_encrypt(Context *ctx) 65 | { 66 | unsigned char *const chunk_size_p = ctx->buf; 67 | unsigned char *const chunk = chunk_size_p + 4; 68 | uint64_t chunk_id; 69 | ssize_t max_chunk_size; 70 | ssize_t chunk_size; 71 | 72 | assert(ctx->sizeof_buf >= 4 + hydro_secretbox_HEADERBYTES); 73 | max_chunk_size = ctx->sizeof_buf - 4 - hydro_secretbox_HEADERBYTES; 74 | assert(max_chunk_size <= 0x7fffffff); 75 | chunk_id = 0; 76 | while ((chunk_size = safe_read_partial(ctx->fd_in, chunk, max_chunk_size)) >= 0) { 77 | STORE32_LE(chunk_size_p, (uint32_t) chunk_size); 78 | if (hydro_secretbox_encrypt(chunk, chunk, chunk_size, chunk_id, HYDRO_CONTEXT, ctx->key) != 79 | 0) { 80 | die(0, "Encryption error"); 81 | } 82 | if (safe_write(ctx->fd_out, chunk_size_p, 4 + hydro_secretbox_HEADERBYTES + chunk_size, 83 | -1) < 0) { 84 | die(1, "write()"); 85 | } 86 | if (chunk_size == 0) { 87 | break; 88 | } 89 | chunk_id++; 90 | } 91 | if (chunk_size < 0) { 92 | die(1, "read()"); 93 | } 94 | return 0; 95 | } 96 | 97 | static int 98 | stream_decrypt(Context *ctx) 99 | { 100 | unsigned char *const chunk_size_p = ctx->buf; 101 | unsigned char *const chunk = chunk_size_p + 4; 102 | uint64_t chunk_id; 103 | ssize_t readnb; 104 | ssize_t max_chunk_size; 105 | ssize_t chunk_size; 106 | 107 | assert(ctx->sizeof_buf >= 4 + hydro_secretbox_HEADERBYTES); 108 | max_chunk_size = ctx->sizeof_buf - 4 - hydro_secretbox_HEADERBYTES; 109 | assert(max_chunk_size <= 0x7fffffff); 110 | chunk_id = 0; 111 | while ((readnb = safe_read(ctx->fd_in, chunk_size_p, 4)) == 4) { 112 | chunk_size = LOAD32_LE(chunk_size_p); 113 | if (chunk_size > max_chunk_size) { 114 | die(0, "Chunk size too large ([%zd] > [%zd])", chunk_size, max_chunk_size); 115 | } 116 | if (safe_read(ctx->fd_in, chunk, chunk_size + hydro_secretbox_HEADERBYTES) != 117 | chunk_size + hydro_secretbox_HEADERBYTES) { 118 | die(0, "Chunk too short ([%zd] bytes expected)", chunk_size); 119 | } 120 | if (hydro_secretbox_decrypt(chunk, chunk, chunk_size + hydro_secretbox_HEADERBYTES, 121 | chunk_id, HYDRO_CONTEXT, ctx->key) != 0) { 122 | fprintf(stderr, "Unable to decrypt chunk #%" PRIu64 " - ", chunk_id); 123 | if (chunk_id == 0) { 124 | die(0, "Wrong password or key?"); 125 | } else { 126 | die(0, "Corrupted or incomplete file?"); 127 | } 128 | } 129 | if (chunk_size == 0) { 130 | break; 131 | } 132 | if (safe_write(ctx->fd_out, chunk, chunk_size, -1) < 0) { 133 | die(1, "write()"); 134 | } 135 | chunk_id++; 136 | } 137 | if (readnb < 0) { 138 | die(1, "read()"); 139 | } 140 | if (chunk_size != 0) { 141 | die(0, "Premature end of file"); 142 | } 143 | return 0; 144 | } 145 | 146 | static int 147 | read_password_file(Context *ctx, const char *file) 148 | { 149 | char password_[512], *password = password_; 150 | ssize_t password_len; 151 | int fd; 152 | 153 | fd = file_open(file, 0); 154 | if ((password_len = safe_read(fd, password, sizeof password_)) < 0) { 155 | die(1, "Unable to read the password"); 156 | } 157 | while (password_len > 0 && 158 | (password[password_len - 1] == ' ' || password[password_len - 1] == '\r' || 159 | password[password_len - 1] == '\n')) { 160 | password_len--; 161 | } 162 | while (password_len > 0 && (*password == ' ' || *password == '\r' || *password == '\n')) { 163 | password++; 164 | password_len--; 165 | } 166 | if (password_len <= 0) { 167 | die(0, "Empty password"); 168 | } 169 | close(fd); 170 | derive_key(ctx, password, password_len); 171 | 172 | return 0; 173 | } 174 | 175 | static void 176 | read_password_from_terminal(Context *ctx) 177 | { 178 | char password[512]; 179 | char *p; 180 | 181 | printf("Password: "); 182 | fflush(stdout); 183 | if (fgets(password, sizeof password, stdin) == NULL) { 184 | die(1, "fgets()"); 185 | } 186 | if ((p = strchr(password, '\r')) != NULL) { 187 | *p = 0; 188 | } 189 | if ((p = strchr(password, '\n')) != NULL) { 190 | *p = 0; 191 | } 192 | derive_key(ctx, password, strlen(password)); 193 | } 194 | 195 | static void 196 | passgen(void) 197 | { 198 | unsigned char password[32]; 199 | char hex[32 * 2 + 1]; 200 | 201 | hydro_random_buf(password, sizeof password); 202 | hydro_bin2hex(hex, sizeof hex, password, sizeof password); 203 | puts(hex); 204 | hydro_memzero(password, sizeof password); 205 | hydro_memzero(hex, sizeof hex); 206 | exit(0); 207 | } 208 | 209 | static void 210 | options_parse(Context *ctx, int argc, char *argv[]) 211 | { 212 | int opt_flag; 213 | int option_index = 0; 214 | 215 | ctx->encrypt = -1; 216 | ctx->in = NULL; 217 | ctx->out = NULL; 218 | optind = 0; 219 | #ifdef _OPTRESET 220 | optreset = 1; 221 | #endif 222 | while ((opt_flag = getopt_long(argc, argv, getopt_options, getopt_long_options, 223 | &option_index)) != -1) { 224 | switch (opt_flag) { 225 | case 'd': 226 | ctx->encrypt = 0; 227 | break; 228 | case 'e': 229 | ctx->encrypt = 1; 230 | break; 231 | case 'G': 232 | passgen(); 233 | break; /* NOTREACHED */ 234 | case 'h': 235 | usage(stdout); 236 | break; /* NOTREACHED */ 237 | case 'i': 238 | ctx->in = optarg; 239 | break; 240 | case 'o': 241 | ctx->out = optarg; 242 | break; 243 | case 'p': 244 | derive_key(ctx, optarg, strlen(optarg)); 245 | break; 246 | case 'P': 247 | read_password_file(ctx, optarg); 248 | break; 249 | default: 250 | usage(stderr); 251 | } 252 | } 253 | if (ctx->encrypt == -1) { 254 | usage(stderr); 255 | } 256 | if (ctx->has_key == 0) { 257 | read_password_from_terminal(ctx); 258 | } 259 | } 260 | 261 | int 262 | main(int argc, char *argv[]) 263 | { 264 | Context ctx; 265 | 266 | if (hydro_init() < 0) { 267 | die(1, "Unable to initialize the crypto library"); 268 | } 269 | memset(&ctx, 0, sizeof ctx); 270 | options_parse(&ctx, argc, argv); 271 | ctx.sizeof_buf = DEFAULT_BUFFER_SIZE; 272 | if (ctx.sizeof_buf < MIN_BUFFER_SIZE) { 273 | ctx.sizeof_buf = MIN_BUFFER_SIZE; 274 | } else if (ctx.sizeof_buf > MAX_BUFFER_SIZE) { 275 | ctx.sizeof_buf = MAX_BUFFER_SIZE; 276 | } 277 | if ((ctx.buf = (unsigned char *) malloc(ctx.sizeof_buf)) == NULL) { 278 | die(1, "malloc()"); 279 | } 280 | assert(sizeof HYDRO_CONTEXT == hydro_secretbox_CONTEXTBYTES); 281 | 282 | ctx.fd_in = file_open(ctx.in, 0); 283 | ctx.fd_out = file_open(ctx.out, 1); 284 | if (ctx.encrypt) { 285 | stream_encrypt(&ctx); 286 | } else { 287 | stream_decrypt(&ctx); 288 | } 289 | free(ctx.buf); 290 | close(ctx.fd_out); 291 | close(ctx.fd_in); 292 | hydro_memzero(&ctx, sizeof ctx); 293 | 294 | return 0; 295 | } 296 | --------------------------------------------------------------------------------