c over pipe 中的实时流 gpg 加密
realtime stream gpg encryption in c over pipe
我正在尝试使用 gpg 实时加密数据。我已经在直接使用 libgcrypt 但我需要一个标准格式。我放弃了 gpgme,因为它似乎不适合实时流应用程序。
我想完成的是这个命令行:
gpg --passphrase hackerpass --symmetric -c
在终端中运行良好,打印 header,输出数据并以带有 EOF CTRL-D 的页脚结束,完美!
这是示例代码,简单的fork,双向管道,我异步写入数据并等待结果但是...实际上gpg的执行并没有结束似乎数据没有到达,我只收到 header,在 fd close gpg 没有收到 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;
}
这里只是一个猜测,但是 sub-process 中有几个未关闭的重复文件描述符。在这些文件描述符关闭之前,Gpg 不会得到 EOF。只要任何进程都可以写入它们,它就会一直等待更多。
另一件需要注意的事情是 gpg 在写入等待进程读取管道时阻塞。如果发生这种情况,您的写作阶段可能会受阻。非常少量的数据不会发生,但如果您通过任何卷,则可能会在以后发生。写入和读取需要同时为non-blocking和运行。
我正在尝试使用 gpg 实时加密数据。我已经在直接使用 libgcrypt 但我需要一个标准格式。我放弃了 gpgme,因为它似乎不适合实时流应用程序。
我想完成的是这个命令行:
gpg --passphrase hackerpass --symmetric -c
在终端中运行良好,打印 header,输出数据并以带有 EOF CTRL-D 的页脚结束,完美!
这是示例代码,简单的fork,双向管道,我异步写入数据并等待结果但是...实际上gpg的执行并没有结束似乎数据没有到达,我只收到 header,在 fd close gpg 没有收到 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;
}
这里只是一个猜测,但是 sub-process 中有几个未关闭的重复文件描述符。在这些文件描述符关闭之前,Gpg 不会得到 EOF。只要任何进程都可以写入它们,它就会一直等待更多。
另一件需要注意的事情是 gpg 在写入等待进程读取管道时阻塞。如果发生这种情况,您的写作阶段可能会受阻。非常少量的数据不会发生,但如果您通过任何卷,则可能会在以后发生。写入和读取需要同时为non-blocking和运行。