From 3f58832474a4b270e136544016a401ef773ac065 Mon Sep 17 00:00:00 2001 From: Justus Winter Date: Thu, 17 Jan 2019 11:11:27 +0100 Subject: openpgp-ffi: New crate. - This creates a new crate, 'sequoia-openpgp-ffi', and moves a handful of functions from 'sequoia-ffi' to it. - The 'sequoia-ffi' crate is a superset of the 'sequoia-openpgp-ffi' crate. This is accomplished by some include! magic. - My first attempt involved having 'sequoia-ffi' depend on 'sequoia-openpgp-ffi', so that the former just re-exports the symbols. However, that turned out to be unreliable, and might be not what we want, because it could also duplicate parts of Rust's standard library. - Fixes #144. --- openpgp-ffi/examples/.gitignore | 5 ++ openpgp-ffi/examples/Makefile | 17 +++++++ openpgp-ffi/examples/armor.c | 60 ++++++++++++++++++++++++ openpgp-ffi/examples/encrypt-for.c | 96 ++++++++++++++++++++++++++++++++++++++ openpgp-ffi/examples/example.c | 45 ++++++++++++++++++ openpgp-ffi/examples/parser.c | 93 ++++++++++++++++++++++++++++++++++++ openpgp-ffi/examples/reader.c | 48 +++++++++++++++++++ 7 files changed, 364 insertions(+) create mode 100644 openpgp-ffi/examples/.gitignore create mode 100644 openpgp-ffi/examples/Makefile create mode 100644 openpgp-ffi/examples/armor.c create mode 100644 openpgp-ffi/examples/encrypt-for.c create mode 100644 openpgp-ffi/examples/example.c create mode 100644 openpgp-ffi/examples/parser.c create mode 100644 openpgp-ffi/examples/reader.c (limited to 'openpgp-ffi/examples') diff --git a/openpgp-ffi/examples/.gitignore b/openpgp-ffi/examples/.gitignore new file mode 100644 index 00000000..6a47c497 --- /dev/null +++ b/openpgp-ffi/examples/.gitignore @@ -0,0 +1,5 @@ +armor +encrypt-for +example +parser +reader diff --git a/openpgp-ffi/examples/Makefile b/openpgp-ffi/examples/Makefile new file mode 100644 index 00000000..29408634 --- /dev/null +++ b/openpgp-ffi/examples/Makefile @@ -0,0 +1,17 @@ +# Makefile for examples written in C. + +CARGO ?= cargo +CARGO_TARGET_DIR ?= $(shell pwd)/../../target +# We currently only support absolute paths. +CARGO_TARGET_DIR := $(abspath $(CARGO_TARGET_DIR)) + +TARGETS = example reader parser encrypt-for armor +CFLAGS = -I../include -O0 -g -Wall -Werror +LDFLAGS = -L$(CARGO_TARGET_DIR)/debug -lsequoia_openpgp_ffi + +all: $(TARGETS) + +clean: + rm -f $(TARGETS) + +$(TARGETS): ../include/sequoia/openpgp.h diff --git a/openpgp-ffi/examples/armor.c b/openpgp-ffi/examples/armor.c new file mode 100644 index 00000000..9b965c5b --- /dev/null +++ b/openpgp-ffi/examples/armor.c @@ -0,0 +1,60 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +#include + +const char *armored = + "-----BEGIN PGP ARMORED FILE-----\n" + "Key0: Value0\n" + "Key1: Value1\n" + "\n" + "SGVsbG8gd29ybGQh\n" + "=s4Gu\n" + "-----END PGP ARMORED FILE-----\n"; + +int +main (int argc, char **argv) +{ + sq_error_t err; + sq_reader_t bytes; + sq_reader_t armor; + sq_armor_kind_t kind; + char message[12]; + sq_armor_header_t *header; + size_t header_len; + + bytes = sq_reader_from_bytes ((uint8_t *) armored, strlen (armored)); + armor = sq_armor_reader_new (bytes, SQ_ARMOR_KIND_ANY); + + header = sq_armor_reader_headers (&err, armor, &header_len); + if (header == NULL) + error (1, 0, "Getting headers failed: %s", sq_error_string (err)); + + assert (header_len == 2); + assert (strcmp (header[0].key, "Key0") == 0 + && strcmp (header[0].value, "Value0") == 0); + assert (strcmp (header[1].key, "Key1") == 0 + && strcmp (header[1].value, "Value1") == 0); + for (size_t i = 0; i < header_len; i++) + { + free (header[i].key); + free (header[i].value); + } + free (header); + + kind = sq_armor_reader_kind (armor); + assert (kind == SQ_ARMOR_KIND_FILE); + + if (sq_reader_read (&err, armor, (uint8_t *) message, 12) < 0) + error (1, 0, "Reading failed: %s", sq_error_string (err)); + + assert (memcmp (message, "Hello world!", 12) == 0); + + sq_reader_free (armor); + sq_reader_free (bytes); + return 0; +} diff --git a/openpgp-ffi/examples/encrypt-for.c b/openpgp-ffi/examples/encrypt-for.c new file mode 100644 index 00000000..ab0943ba --- /dev/null +++ b/openpgp-ffi/examples/encrypt-for.c @@ -0,0 +1,96 @@ +/* This example demonstrates how to use the low-level interface to + encrypt a file. */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +int +main (int argc, char **argv) +{ + struct stat st; + int fd; + uint8_t *b; + sq_status_t rc; + sq_error_t err; + int use_armor = 1; + sq_tpk_t tpk; + sq_writer_t sink; + sq_writer_stack_t writer = NULL; + void *cipher = NULL; + size_t cipher_bytes = 0; + + if (argc != 2) + error (1, 0, "Usage: %s cipher", argv[0]); + + if (stat (argv[1], &st)) + error (1, errno, "%s", argv[1]); + + fd = open (argv[1], O_RDONLY); + if (fd == -1) + error (1, errno, "%s", argv[1]); + + b = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); + close (fd); + if (b == MAP_FAILED) + error (1, errno, "mmap"); + + tpk = sq_tpk_from_bytes (&err, b, st.st_size); + if (tpk == NULL) + error (1, 0, "sq_packet_parser_from_bytes: %s", sq_error_string (err)); + + sink = sq_writer_alloc (&cipher, &cipher_bytes); + + if (use_armor) + sink = sq_armor_writer_new (&err, sink, SQ_ARMOR_KIND_MESSAGE, + NULL, 0); + + writer = sq_writer_stack_message (sink); + writer = sq_encryptor_new (&err, + writer, + NULL, 0, /* no passwords */ + &tpk, 1, + SQ_ENCRYPTION_MODE_FOR_TRANSPORT); + if (writer == NULL) + error (1, 0, "sq_encryptor_new: %s", sq_error_string (err)); + + writer = sq_literal_writer_new (&err, writer); + if (writer == NULL) + error (1, 0, "sq_literal_writer_new: %s", sq_error_string (err)); + + size_t nread; + uint8_t buf[4096]; + while ((nread = fread (buf, 1, sizeof buf, stdin))) + { + uint8_t *b = buf; + while (nread) + { + ssize_t written; + written = sq_writer_stack_write (&err, writer, b, nread); + if (written < 0) + error (1, 0, "sq_writer_stack_write: %s", sq_error_string (err)); + + b += written; + nread -= written; + } + } + + rc = sq_writer_stack_finalize (&err, writer); + writer = NULL; + if (rc) + error (1, 0, "sq_writer_stack_write: %s", sq_error_string (err)); + + fwrite (cipher, 1, cipher_bytes, stdout); + + munmap (b, st.st_size); + return 0; +} diff --git a/openpgp-ffi/examples/example.c b/openpgp-ffi/examples/example.c new file mode 100644 index 00000000..ac23ff57 --- /dev/null +++ b/openpgp-ffi/examples/example.c @@ -0,0 +1,45 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +int +main (int argc, char **argv) +{ + struct stat st; + int fd; + uint8_t *b; + sq_error_t err; + sq_tpk_t tpk; + + if (argc != 2) + error (1, 0, "Usage: %s ", argv[0]); + + if (stat (argv[1], &st)) + error (1, errno, "%s", argv[1]); + + fd = open (argv[1], O_RDONLY); + if (fd == -1) + error (1, errno, "%s", argv[1]); + + b = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (b == MAP_FAILED) + error (1, errno, "mmap"); + + tpk = sq_tpk_from_bytes (&err, b, st.st_size); + if (tpk == NULL) + error (1, 0, "sq_tpk_from_bytes: %s", sq_error_string (err)); + + sq_tpk_dump (tpk); + sq_tpk_free (tpk); + munmap (b, st.st_size); + close (fd); + return 0; +} diff --git a/openpgp-ffi/examples/parser.c b/openpgp-ffi/examples/parser.c new file mode 100644 index 00000000..81b097af --- /dev/null +++ b/openpgp-ffi/examples/parser.c @@ -0,0 +1,93 @@ +/* This example demonstrates how to use the packet parser from C. It + * also serves as a simple benchmark. */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +int +main (int argc, char **argv) +{ + struct stat st; + int fd; + uint8_t *b; + sq_status_t rc; + sq_error_t err; + sq_packet_parser_result_t ppr; + sq_packet_parser_t pp; + + if (argc != 2) + error (1, 0, "Usage: %s ", argv[0]); + + if (stat (argv[1], &st)) + error (1, errno, "%s", argv[1]); + + fd = open (argv[1], O_RDONLY); + if (fd == -1) + error (1, errno, "%s", argv[1]); + + b = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); + close (fd); + if (b == MAP_FAILED) + error (1, errno, "mmap"); + + size_t n = 0; + time_t start = time (NULL); + time_t elapsed; + size_t tens_of_s = 0; + + ppr = sq_packet_parser_from_bytes (&err, b, st.st_size); + while (ppr && (pp = sq_packet_parser_result_packet_parser (ppr))) + { + // Get a reference to the packet that is currently being parsed. + sq_packet_t p = sq_packet_parser_packet (pp); + + if (sq_packet_tag(p) == SQ_TAG_LITERAL) + { + // Stream the packet here. + } + + // Finish parsing the current packet (returned in p), and read + // the header of the next packet (returned in ppr). + rc = sq_packet_parser_next (&err, pp, &p, &ppr); + if (rc) + error (1, 0, "sq_packet_parser_from_bytes: %s", + sq_error_string (err)); + + // We now own p. If we want, we can save it in some structure. + // This would be useful when collecting PKESK packets. Either + // way, we need to free it when we are done. + + n += 1; + + sq_packet_free (p); + + elapsed = time (NULL) - start; + if (elapsed % 10 == 0 && tens_of_s != elapsed / 10) + { + fprintf (stderr, + "Parsed %ld packets in %ld seconds, %.2f packets/s.\n", + n, elapsed, (double) n / (double) elapsed); + fflush (stderr); + tens_of_s = elapsed / 10; + } + } + if (ppr == NULL) + error (1, 0, "sq_packet_parser_from_bytes: %s", sq_error_string (err)); + + fprintf (stderr, "Parsed %ld packets in %ld seconds, %.2f packets/s.\n", + n, elapsed, (double) n / (double) elapsed); + + sq_packet_parser_result_free (ppr); + munmap (b, st.st_size); + return 0; +} diff --git a/openpgp-ffi/examples/reader.c b/openpgp-ffi/examples/reader.c new file mode 100644 index 00000000..019d87d9 --- /dev/null +++ b/openpgp-ffi/examples/reader.c @@ -0,0 +1,48 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +int +main (int argc, char **argv) +{ + struct stat st; + int fd; + uint8_t *b; + sq_error_t err; + sq_reader_t reader; + sq_tpk_t tpk; + + if (argc != 2) + error (1, 0, "Usage: %s ", argv[0]); + + if (stat (argv[1], &st)) + error (1, errno, "%s", argv[1]); + + fd = open (argv[1], O_RDONLY); + if (fd == -1) + error (1, errno, "%s", argv[1]); + + b = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (b == MAP_FAILED) + error (1, errno, "mmap"); + + reader = sq_reader_from_bytes (b, st.st_size); + tpk = sq_tpk_from_reader (&err, reader); + if (tpk == NULL) + error (1, 0, "sq_tpk_from_reader: %s", sq_error_string (err)); + + sq_tpk_dump (tpk); + sq_tpk_free (tpk); + sq_reader_free (reader); + munmap (b, st.st_size); + close (fd); + return 0; +} -- cgit v1.2.3