简体   繁体   中英

realtime stream gpg encryption in c over pipe

I'm trying to use gpg to encrypt data in realtime. I'm already using libgcrypt directly but i need a standard format. I discarded gpgme since it did not seem suitable for a realtime stream application.

What I would like to accomplish is this command line:

gpg --passphrase hackerpass --symmetric -c

in the terminal it works well, print header, out the data and ends with the footer with a EOF CTRL-D, perfect!

This is the sample code, simple fork, bidirectional pipe, i write the data and wait the result asynchronously but ... the execution of gpg does not end, in reality it seems that the data does not arrive, i receive only the header, at fd close gpg does not receive EOF:

#include <fcntl.h>
#include <sys/wait.h>
#include <sys/prctl.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>

int main(int argc, char *argv[]) {

    pid_t pid = 0;
    int inpipefd[2];
    int outpipefd[2];
    char buf[256];
    int status;

    pipe(inpipefd);
    pipe(outpipefd);

    pid = fork();

    if (pid == 0) {
        // Child       

        dup2(outpipefd[0], STDIN_FILENO);
        dup2(inpipefd[1], STDOUT_FILENO);
        //dup2(inpipefd[1], STDERR_FILENO);

        //ask kernel to deliver SIGTERM in case the parent dies
        prctl(PR_SET_PDEATHSIG, SIGTERM);

        execlp("/bin/sh", "/bin/sh", "-c", "/usr/bin/gpg --passphrase pass --symmetric -c", (char *) NULL);

        exit(1);
    }

    //close unused pipe ends
    close(outpipefd[0]);
    close(inpipefd[1]);

    int flags;

    flags = fcntl(inpipefd[0], F_GETFL, 0);
    flags |= O_NONBLOCK;
    fcntl(inpipefd[0], F_SETFL, flags);

    // write example data       

    char *data = "dummy dummy";

    ssize_t out = write(outpipefd[1], data, strlen(data));

    if (out != strlen(data)) {
        printf("fail write\n");
        exit(-1);
    }

    close(outpipefd[1]);

    int hasPendingData = 1;

    while (hasPendingData) {

        ssize_t r = read(inpipefd[0], buf, 255);

        if (r == -1 && errno == EAGAIN) {
            // in process
            printf("no data available, wait...\n");
            usleep(500000);

        } else if (r > 0) {
            printf("Incoming %ld bytes\n", (long) r);

        } else {
            // EOF 
            hasPendingData = 0;
            printf("no mode data available, exit...\n");
        }

    }

    waitpid(pid, &status, 0);

    return 0;
}

Just a guess here, but you have several unclosed duplicate file descriptors in the sub-process. Gpg won't get EOF until those file descriptors are closed. As long as any process could possible write to them, it will just keep waiting for more.

Another thing to watch out for is the gpg blocking while writing waiting for your process to read the pipe. If that happens, your writing stage could then get blocked. Won't happen with very small amounts of data but could happen later if you put any volume through. Both write and read need to be non-blocking and running simultaneously.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM