Skip to content
Browse files

zcrypt: Implement AES encryption support using GPG.

  • Loading branch information...
1 parent c836519 commit 8bd190d63b2f2c09ea416e7be7c51d974f56bfaf @nelhage committed Mar 17, 2010
Showing with 279 additions and 36 deletions.
  1. +3 −0 Makefile
  2. +118 −0 filterproc.c
  3. +9 −0 filterproc.h
  4. +149 −36 zcrypt.c
View
3 Makefile
@@ -1,2 +1,5 @@
CFLAGS=$(shell pkg-config glib-2.0 --cflags)
LDFLAGS=$(shell pkg-config glib-2.0 --libs)
+
+zcrypt: zcrypt.o filterproc.o
+
View
118 filterproc.c
@@ -0,0 +1,118 @@
+#include <signal.h>
+#include <unistd.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include <glib.h>
+
+int send_receive(int rfd, int wfd, const char *out, char **in)
+{
+ GString *str = g_string_new("");
+ char buf[1024];
+ nfds_t nfds;
+ int err = 0;
+ struct pollfd fds[2];
+ struct sigaction sig = {.sa_handler = SIG_IGN}, old;
+
+ fcntl(rfd, F_SETFL, O_NONBLOCK | fcntl(rfd, F_GETFL));
+ fcntl(wfd, F_SETFL, O_NONBLOCK | fcntl(wfd, F_GETFL));
+
+ fds[0].fd = rfd;
+ fds[0].events = POLLIN;
+ fds[1].fd = wfd;
+ fds[1].events = POLLOUT;
+
+ sigaction(SIGPIPE, &sig, &old);
+
+ while(1) {
+ if(out && *out) {
+ nfds = 2;
+ } else {
+ nfds = 1;
+ }
+ err = poll(fds, nfds, -1);
+ if(err < 0) {
+ break;
+ }
+ if(out && *out) {
+ if(fds[1].revents & POLLOUT) {
+ err = write(wfd, out, strlen(out));
+ if(err > 0) {
+ out += err;
+ }
+ if(err < 0) {
+ out = NULL;
+ }
+ }
+ if(!out || !*out || fds[1].revents & (POLLERR | POLLHUP)) {
+ close(wfd);
+ out = NULL;
+ }
+ }
+ if(fds[0].revents & POLLIN) {
+ err = read(rfd, buf, sizeof(buf));
+ if(err <= 0) {
+ break;
+ }
+ g_string_append_len(str, buf, err);
+ } else if(fds[0].revents & (POLLHUP | POLLERR)) {
+ err = 0;
+ break;
+ }
+ }
+
+ *in = g_string_free(str, err < 0);
+ sigaction(SIGPIPE, &old, NULL);
+ return err;
+}
+
+int call_filter(const char *prog, const char *const *argv, const char *in, char **out, int *status)
+{
+ int err = 0;
+ pid_t pid;
+ int rfd[2];
+ int wfd[2];
+
+ if((err = pipe(rfd))) goto out;
+ if((err = pipe(wfd))) goto out_close_rfd;
+
+ pid = fork();
+ if(pid < 0) {
+ err = pid;
+ goto out_close_all;
+ }
+ if(pid) {
+ /* parent */
+ close(rfd[1]);
+ close(wfd[0]);
+ err = send_receive(rfd[0], wfd[1], in, out);
+ if(err == 0) {
+ waitpid(pid, status, 0);
+ }
+ } else {
+ /* child */
+ close(rfd[0]);
+ close(wfd[1]);
+ dup2(rfd[1], 1);
+ dup2(wfd[0], 0);
+ close(rfd[1]);
+ close(wfd[0]);
+
+ if(execvp(prog, (char *const *)argv)) {
+ _exit(-1);
+ }
+ }
+
+ out_close_all:
+ close(wfd[0]);
+ close(wfd[1]);
+ out_close_rfd:
+ close(rfd[0]);
+ close(rfd[1]);
+ out:
+ return err;
+}
View
9 filterproc.h
@@ -0,0 +1,9 @@
+#ifndef __FILTER_PROC_H__
+#define __FILTER_PROC_H__
+
+int call_filter(const char *prog,
+ const char *const *argv,
+ const char *in,
+ char **out, int *status);
+
+#endif
View
185 zcrypt.c
@@ -15,15 +15,19 @@
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
+#include <ctype.h>
#ifdef HAVE_KERBEROS_IV
#include <kerberosIV/des.h>
#else
#include <openssl/des.h>
#endif
-#define MAX_KEY 128
-#define MAX_LINE 128
+#include "filterproc.h"
+
+#define MAX_KEY 128
+#define MAX_LINE 128
+#define MAX_RESULT 4096
#ifndef TRUE
#define TRUE -1
@@ -51,10 +55,16 @@ char *GetZephyrVarKeyFile(char *whoami, char *class, char *instance);
int ParseCryptSpec(char *spec, char **keyfile);
char *BuildArgString(char **argv, int start, int end);
char *read_keystring(char *keyfile);
+
int do_encrypt(int zephyr, char *class, char *instance,
ZWRITEOPTIONS *zoptions, char* keyfile, int cipher);
int do_encrypt_des(char *keyfile, char *in, int len, FILE *out);
-int do_decrypt(char *keystring);
+int do_encrypt_aes(char *keyfile, char *in, int len, FILE *out);
+
+int do_decrypt(char *keyfile, int cipher);
+int do_decrypt_aes(char *keyfile);
+int do_decrypt_des(char *keyfile);
+
#define M_NONE 0
#define M_ZEPHYR_ENCRYPT 1
@@ -297,21 +307,47 @@ int main(int argc, char *argv[])
else
{
if (mode == M_ZEPHYR_ENCRYPT || mode == M_ENCRYPT)
- do_encrypt((mode == M_ZEPHYR_ENCRYPT), class, instance,
- &zoptions, keyfile, cipher);
+ error = !do_encrypt((mode == M_ZEPHYR_ENCRYPT), class, instance,
+ &zoptions, keyfile, cipher);
else
- do_decrypt(keyfile);
+ error = !do_decrypt(keyfile, cipher);
}
/* Always print the **END** message if -D is specified. */
if (mode == M_DECRYPT)
printf("**END**\n");
- return 0;
+
+ return error;
}
int ParseCryptSpec(char *spec, char **keyfile) {
+ int cipher = CIPHER_DES;
+ char *cipher_name = strdup(spec);
+ char *colon = strchr(cipher_name, ':');
+
*keyfile = spec;
- return CIPHER_DES;
+
+ if (colon) {
+ char *rest = strchr(spec, ':') + 1;
+ while(isspace(*rest)) rest++;
+
+ *colon-- = '\0';
+ while (colon >= cipher_name && isspace(*colon)) {
+ *colon = '\0';
+ }
+
+ if(strcmp(cipher_name, "AES") == 0) {
+ cipher = CIPHER_AES;
+ *keyfile = rest;
+ } else if(strcmp(cipher_name, "DES") == 0) {
+ cipher = CIPHER_DES;
+ *keyfile = rest;
+ }
+ }
+
+ free(cipher_name);
+
+ return cipher;
}
/* Build a space-separated string from argv from elements between start *
@@ -521,8 +557,6 @@ void CloseZephyrPipe(FILE *pipe)
zephyrpipe_pid = 0;
}
-#define MAX_RESULT 2048
-
#define BASE_CODE 70
#define LAST_CODE (BASE_CODE + 15)
#define OUTPUT_BLOCK_SIZE 16
@@ -537,10 +571,41 @@ void block_to_ascii(unsigned char *output, FILE *outfile)
}
}
-char *GetInputBuffer(ZWRITEOPTIONS *zoptions, int *length) {
+char *slurp_stdin(int ignoredot, int *length) {
char *buf;
char *inptr;
+ if ((inptr = buf = (char *)malloc(MAX_RESULT)) == NULL)
+ {
+ fprintf(stderr, "Memory allocation error\n");
+ return NULL;
+ }
+ while (inptr - buf < MAX_RESULT - MAX_LINE - 20)
+ {
+ if (fgets(inptr, MAX_LINE, stdin) == NULL)
+ break;
+
+ if (inptr[0])
+ {
+ if (inptr[0] == '.' && inptr[1] == '\n' && !ignoredot)
+ {
+ inptr[0] = '\0';
+ break;
+ }
+ else
+ inptr += strlen(inptr);
+ }
+ else
+ break;
+ }
+ *length = inptr - buf;
+
+ return buf;
+}
+
+char *GetInputBuffer(ZWRITEOPTIONS *zoptions, int *length) {
+ char *buf;
+
if (zoptions->flags & ZCRYPT_OPT_MESSAGE)
{
/* Use the -m message */
@@ -559,29 +624,7 @@ char *GetInputBuffer(ZWRITEOPTIONS *zoptions, int *length) {
zoptions->flags |= ZCRYPT_OPT_IGNOREDOT;
}
- if ((inptr = buf = (char *)malloc(MAX_RESULT)) == NULL)
- {
- fprintf(stderr, "Memory allocation error\n");
- return NULL;
- }
- while (inptr - buf < MAX_RESULT - MAX_LINE - 20)
- {
- if (!fgets(inptr, MAX_LINE, stdin)) break;
- if (inptr[0])
- {
- if (inptr[0] == '.' && inptr[1] == '\n' &&
- !(zoptions->flags & ZCRYPT_OPT_IGNOREDOT))
- {
- inptr[0] = '\0';
- break;
- }
- else
- inptr += strlen(inptr);
- }
- else
- break;
- }
- *length = inptr - buf;
+ buf = slurp_stdin(zoptions->flags & ZCRYPT_OPT_IGNOREDOT, length);
}
return buf;
}
@@ -636,7 +679,7 @@ int do_encrypt(int zephyr, char *class, char *instance,
out = do_encrypt_des(keyfile, inbuff, buflen, outfile);
break;
case CIPHER_AES:
- out = FALSE;
+ out = do_encrypt_aes(keyfile, inbuff, buflen, outfile);
break;
}
@@ -707,6 +750,31 @@ int do_encrypt_des(char *keyfile, char *in, int length, FILE *outfile)
return TRUE;
}
+int do_encrypt_aes(char *keyfile, char *in, int length, FILE *outfile)
+{
+ char *out;
+ int err, status;
+ const char *argv[] = {
+ "gpg",
+ "--symmetric",
+ "--batch",
+ "--quiet",
+ "--no-use-agent",
+ "--armor",
+ "--cipher-algo", "AES",
+ "--passphrase-file", keyfile,
+ NULL
+ };
+ err = call_filter("gpg", argv, in, &out, &status);
+ if(err || status) {
+ if(out) g_free(out);
+ return FALSE;
+ }
+ fwrite(out, strlen(out), 1, outfile);
+ g_free(out);
+ return TRUE;
+}
+
/* Read a half-byte from stdin, skipping invalid characters. Returns -1
if at EOF or file error */
int read_ascii_nybble(void)
@@ -758,15 +826,60 @@ int read_ascii_block(unsigned char *input)
}
/* Decrypt stdin */
-int do_decrypt(char *keystring)
+int do_decrypt(char *keyfile, int cipher)
{
+ switch(cipher) {
+ case CIPHER_DES:
+ return do_decrypt_des(keyfile);
+ case CIPHER_AES:
+ return do_decrypt_aes(keyfile);
+ default:
+ return FALSE;
+ }
+}
+
+int do_decrypt_aes(char *keyfile) {
+ char *in, *out;
+ int length;
+ const char *argv[] = {
+ "gpg",
+ "--decrypt",
+ "--batch",
+ "--no-use-agent",
+ "--quiet",
+ "--passphrase-file", keyfile,
+ NULL
+ };
+ int err, status;
+
+ in = slurp_stdin(TRUE, &length);
+ if(!in) return FALSE;
+
+ err = call_filter("gpg", argv, in, &out, &status);
+ if(err || status) {
+ if(out) g_free(out);
+ return FALSE;
+ }
+ fwrite(out, strlen(out), 1, stdout);
+ g_free(out);
+
+ return TRUE;
+}
+
+int do_decrypt_des(char *keyfile) {
des_key_schedule schedule;
unsigned char input[8], output[8];
+ char *keystring;
output[0] = '\0'; /* In case no message at all */
+ keystring = read_keystring(keyfile);
+ if(!keystring) return FALSE;
+
owl_zcrypt_string_to_schedule(keystring, &schedule);
+ free(keystring);
+
while (read_ascii_block(input))
{
des_ecb_encrypt(&input, &output, schedule, FALSE);

0 comments on commit 8bd190d

Please sign in to comment.
Something went wrong with that request. Please try again.