From 0e7ec4dd193141bff3bc6b0565de76e6b28a8457 Mon Sep 17 00:00:00 2001
From: Michal Hlavinka <mhlavink@redhat.com>
Date: Jun 30 2025 20:32:37 +0000
Subject: [PATCH 1/2] use g_memdup2 instead of deprecated g_memdup


---

diff --git a/lib/crypto.c b/lib/crypto.c
index 5b562d1..b78b886 100644
--- a/lib/crypto.c
+++ b/lib/crypto.c
@@ -298,7 +298,7 @@ encrypt_asymmetric (size_t *res_size, const void *data, size_t size,
     }
 
   *res_size = dest_item.len;
-  res = g_memdup (dest_item.data, dest_item.len);
+  res = g_memdup2 (dest_item.data, dest_item.len);
   PORT_FreeArena (res_arena, PR_FALSE);
   NSS_CMSMessage_Destroy (cmsg);
   return res;
@@ -343,7 +343,7 @@ decrypt_asymmetric (size_t *res_size, const void *data, size_t size,
       error_from_pr (error);
       goto err_cmsg;
     }
-  res = g_memdup (dest->data, dest->len);
+  res = g_memdup2 (dest->data, dest->len);
   *res_size = dest->len;
 
   NSS_CMSMessage_Destroy (cmsg);
@@ -449,13 +449,13 @@ wrap_asymmetric (void **wrapped_secret, size_t *wrapped_secret_size,
   SECKEY_DestroyPublicKey (public_key);
   PK11_FreeSymKey (secret_key);
 
-  *wrapped_secret = g_memdup (wrapped_secret_item.data,
+  *wrapped_secret = g_memdup2 (wrapped_secret_item.data,
 			      wrapped_secret_item.len);
   *wrapped_secret_size = wrapped_secret_item.len;
   SECITEM_FreeItem (&wrapped_secret_item, PR_FALSE);
-  *issuer = g_memdup (isn->derIssuer.data, isn->derIssuer.len);
+  *issuer = g_memdup2 (isn->derIssuer.data, isn->derIssuer.len);
   *issuer_size = isn->derIssuer.len;
-  *sn = g_memdup (isn->serialNumber.data, isn->serialNumber.len);
+  *sn = g_memdup2 (isn->serialNumber.data, isn->serialNumber.len);
   *sn_size = isn->serialNumber.len;
   PORT_FreeArena (isn_arena, PR_FALSE);
   return 0;
@@ -538,7 +538,7 @@ unwrap_asymmetric (size_t *clear_secret_size, const void *wrapped_secret_data,
       goto err_secret_key;
     }
   clear_secret_item = PK11_GetKeyData (secret_key);
-  ret = g_memdup (clear_secret_item->data, clear_secret_item->len);
+  ret = g_memdup2 (clear_secret_item->data, clear_secret_item->len);
   *clear_secret_size = clear_secret_item->len;
   PK11_FreeSymKey (secret_key);
 
@@ -612,11 +612,11 @@ wrap_symmetric (void **wrapped_secret, size_t *wrapped_secret_size, void **iv,
   PK11_FreeSymKey (secret_key);
 
   iv_data = PK11_IVFromParam (mechanism, wrapping_param, &iv_data_size);
-  *iv = g_memdup (iv_data, iv_data_size);
+  *iv = g_memdup2 (iv_data, iv_data_size);
   *iv_size = iv_data_size;
   SECITEM_FreeItem (wrapping_param, PR_TRUE);
 
-  *wrapped_secret = g_memdup (wrapped_secret_item.data,
+  *wrapped_secret = g_memdup2 (wrapped_secret_item.data,
 			      wrapped_secret_item.len);
   *wrapped_secret_size = wrapped_secret_item.len;
   SECITEM_FreeItem (&wrapped_secret_item, PR_FALSE);
@@ -671,7 +671,7 @@ unwrap_symmetric (size_t *clear_secret_size, PK11SymKey *wrapping_key,
       goto err_secret_key;
     }
   clear_secret_item = PK11_GetKeyData (secret_key);
-  ret = g_memdup (clear_secret_item->data, clear_secret_item->len);
+  ret = g_memdup2 (clear_secret_item->data, clear_secret_item->len);
   *clear_secret_size = clear_secret_item->len;
   PK11_FreeSymKey (secret_key);
 
@@ -827,7 +827,7 @@ encrypt_with_passphrase (size_t *res_size, const void *data, size_t size,
 		   _("Unknown error getting encryption result"));
       goto err_ctx;
     }
-  res = g_memdup (gpgme_res, *res_size);
+  res = g_memdup2 (gpgme_res, *res_size);
   gpgme_free (gpgme_res);
 
   gpgme_release (ctx);
@@ -883,7 +883,7 @@ decrypt_with_passphrase (size_t *res_size, const void *data, size_t size,
 		   _("Unknown error getting decryption result"));
       goto err_ctx;
     }
-  res = g_memdup (gpgme_res, *res_size);
+  res = g_memdup2 (gpgme_res, *res_size);
   gpgme_free (gpgme_res);
 
   gpgme_release (ctx);
diff --git a/lib/kmip.c b/lib/kmip.c
index 333603c..9e7ae51 100644
--- a/lib/kmip.c
+++ b/lib/kmip.c
@@ -98,7 +98,7 @@ kmip_key_value_set_bytes (struct kmip_key_value *value, const void *bytes,
 {
   kmip_key_value_free_v (value);
   value->type = KMIP_KEY_VALUE_BYTES;
-  value->v.bytes.data = g_memdup (bytes, len);
+  value->v.bytes.data = g_memdup2 (bytes, len);
   value->v.bytes.len = len;
 }
 
@@ -110,7 +110,7 @@ kmip_key_value_set_symmetric_key (struct kmip_key_value *value, const void *key,
   kmip_key_value_free_v (value);
   value->type = KMIP_KEY_VALUE_SYMMETRIC_KEY;
   value->v.key = g_new (struct kmip_symmetric_key, 1);
-  value->v.key->data = g_memdup (key, len);
+  value->v.key->data = g_memdup2 (key, len);
   value->v.key->len = len;
 }
 
@@ -920,7 +920,7 @@ get_bytes (struct kmip_decoding_state *kmip, void **bytes, size_t *size,
 		   _("Unexpected end of data"));
       return -1;
     }
-  *bytes = g_memdup (kmip->data, s);
+  *bytes = g_memdup2 (kmip->data, s);
   *size = s;
   kmip->data += s;
   kmip->left -= s;
@@ -1884,7 +1884,7 @@ kmip_libvk_packet_wrap_secret_symmetric (struct kmip_libvk_packet *packet,
   key_block->wrapping = g_new (struct kmip_key_wrapping_data, 1);
   key_block->wrapping->method = KMIP_WRAPPING_LIBVK_ENCRYPT_KEY_ONLY;
   key_block->wrapping->encryption_key = encryption_key;
-  key_block->wrapping->iv = g_memdup (iv, iv_len);
+  key_block->wrapping->iv = g_memdup2 (iv, iv_len);
   key_block->wrapping->iv_len = iv_len;
 
   g_free (iv);
diff --git a/lib/volume.c b/lib/volume.c
index 696d8b5..bfcc383 100644
--- a/lib/volume.c
+++ b/lib/volume.c
@@ -83,7 +83,7 @@ volume_create_data_encryption_key_packet (struct kmip_key_value **kv,
   key_value = g_new (struct kmip_key_value, 1);
   key_value->type = KMIP_KEY_VALUE_SYMMETRIC_KEY;
   key_value->v.key = g_new (struct kmip_symmetric_key, 1);
-  key_value->v.key->data = g_memdup (key, key_bytes);
+  key_value->v.key->data = g_memdup2 (key, key_bytes);
   key_value->v.key->len = key_bytes;
   key_value->attributes = g_ptr_array_new ();
   add_common_volume_attributes (key_value, vol);
@@ -129,7 +129,7 @@ volume_create_passphrase_packet (struct kmip_key_value **kv,
 
   key_value = g_new (struct kmip_key_value, 1);
   key_value->type = KMIP_KEY_VALUE_BYTES;
-  key_value->v.bytes.data = g_memdup (passphrase, size);
+  key_value->v.bytes.data = g_memdup2 (passphrase, size);
   key_value->v.bytes.len = size;
   key_value->attributes = g_ptr_array_new ();
   add_common_volume_attributes (key_value, vol);
diff --git a/lib/volume_luks.c b/lib/volume_luks.c
index 4d32d9b..d92febc 100644
--- a/lib/volume_luks.c
+++ b/lib/volume_luks.c
@@ -154,7 +154,7 @@ luks_replace_key (struct libvk_volume *vol, const void *key)
       memset (luks->key, 0, luks->key_bytes);
       g_free (luks->key);
     }
-  luks->key = g_memdup (key, luks->key_bytes);
+  luks->key = g_memdup2 (key, luks->key_bytes);
 }
 
 /* Replace the passphrase in VOL, if any, by PASSPHRASE */
@@ -791,7 +791,7 @@ luks_parse_escrow_packet (struct libvk_volume *vol,
 			   _("Key length mismatch"));
 	      goto err;
 	    }
-	  vol->v.luks->key = g_memdup (key_value->v.key->data,
+	  vol->v.luks->key = g_memdup2 (key_value->v.key->data,
 				       key_value->v.key->len);
 	}
       break;
diff --git a/src/volume_key.c b/src/volume_key.c
index 9642072..53dd27d 100644
--- a/src/volume_key.c
+++ b/src/volume_key.c
@@ -388,7 +388,7 @@ read_batch_string (void)
       free (buf);
       return NULL;
     }
-  res = g_memdup (buf, len);
+  res = g_memdup2 (buf, len);
   free (buf);
   return res;
 }
@@ -531,7 +531,7 @@ generic_ui_cb (void *id, const char *prompt, int echo)
 	  free (buf);
 	  return NULL;
 	}
-      res = g_memdup (buf, len + 1);
+      res = g_memdup2 (buf, len + 1);
       free (buf);
       return res;
     }

From a750748519e758fad2a2f8a738137750d1caabdf Mon Sep 17 00:00:00 2001
From: Michal Hlavinka <mhlavink@redhat.com>
Date: Jul 02 2025 12:34:46 +0000
Subject: [PATCH 2/2] add option to use Sequoia sq instead of gpgme


There are concerns after LibrePGP and OpenPGP split, this should allow
downstreams to choose.

---

diff --git a/configure.ac b/configure.ac
index 7d3d27a..3015c97 100644
--- a/configure.ac
+++ b/configure.ac
@@ -195,7 +195,13 @@ AC_DEFINE(G_DISABLE_DEPRECATED, 1,
 PKG_CHECK_MODULES(libcryptsetup, [libcryptsetup])
 PKG_CHECK_MODULES(nss, [nss])
 
-AM_PATH_GPGME
+AM_CHECK_SQ([external])
+AM_CONDITIONAL([WITH_SQ], [test x$SQ_PATH != x])
+
+# Check for GPGME only if --with-sq was not specified
+AS_IF([test "x$SQ_PATH" = "x"],
+      [AM_PATH_GPGME],
+      [AC_MSG_NOTICE([Skipping GPGME check, using sq instead])])
 
 AM_GNU_GETTEXT([external])
 AM_GNU_GETTEXT_VERSION([0.18.2])
diff --git a/lib/Makefile.am b/lib/Makefile.am
index e69c846..6939061 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -33,6 +33,12 @@ libvolume_key_la_SOURCES = SECerrs.h SSLerrs.h \
 	ui.c ui.h \
 	volume.c volume.h \
 	volume_luks.c volume_luks.h
+if WITH_SQ
+libvolume_key_la_SOURCES += crypto-sq.c crypto-sq.h
+else
+libvolume_key_la_SOURCES += crypto-gpgme.c crypto-gpgme.h
+endif
+
 libvolume_key_la_CPPFLAGS = $(AM_CPPFLAGS) $(LOCALEDIR_CPPFLAGS)
 libvolume_key_la_LDFLAGS = -version-info $(VERSION_INFO)
 libvolume_key_la_LIBADD = $(blkid_LIBS) $(glib_LIBS) $(GPGME_LIBS) \
diff --git a/lib/crypto-gpgme.c b/lib/crypto-gpgme.c
new file mode 100644
index 0000000..5befb29
--- /dev/null
+++ b/lib/crypto-gpgme.c
@@ -0,0 +1,432 @@
+/* libgpgme utils */
+static void
+error_from_gpgme (GError **error, gpgme_error_t e)
+{
+    size_t len;
+    char *s;
+
+    s = NULL;
+    len = 100;
+    for (;;)
+    {
+        s = g_realloc (s, len);
+        if (gpgme_strerror_r (e, s, len) == 0)
+            break;
+        len *= 2;
+    }
+    g_set_error (error, LIBVK_ERROR, LIBVK_ERROR_CRYPTO, _("%s: %s"),
+                gpgme_strsource (e), s);
+    g_free (s);
+}
+
+static gpgme_error_t
+gpgme_passphrase_cb (void *hook, const char *uid_hint,
+                    const char *passphrase_info, int prev_was_bad, int fd)
+{
+    static const char nl = '\n';
+
+    const char *pw;
+    size_t len;
+    ssize_t res;
+
+    (void)uid_hint;
+    (void)passphrase_info;
+    if (prev_was_bad != 0)
+        return GPG_ERR_CANCELED;
+    pw = hook;
+    len = strlen (pw);
+    while (len != 0)
+    {
+        res = write (fd, pw, len);
+        if (res < 0)
+            return gpgme_error_from_errno (errno);
+        pw += res;
+        len -= res;
+    }
+    if (write (fd, &nl, sizeof (nl)) < 0)
+        return gpgme_error_from_errno (errno);
+    return 0;
+}
+// Error helper (simplified from GPGME’s error_from_gpgme)
+
+
+/* Create and configure a gpgme context, to use PASSPHRASE.
+ *   Return 0 if OK, -1 on error. */
+static int
+init_gpgme (gpgme_ctx_t *res, const char *passphrase, GError **error)
+{
+    gpgme_ctx_t ctx;
+    gpgme_error_t e;
+
+    (void)gpgme_check_version (NULL);
+    e = gpgme_new (&ctx);
+    if (e != GPG_ERR_NO_ERROR)
+    {
+        error_from_gpgme (error, e);
+        goto err;
+    }
+    e = gpgme_set_locale (ctx, LC_CTYPE, setlocale (LC_CTYPE, NULL));
+    if (e != GPG_ERR_NO_ERROR)
+    {
+        error_from_gpgme (error, e);
+        goto err_ctx;
+    }
+    e = gpgme_set_locale (ctx, LC_MESSAGES, setlocale (LC_MESSAGES, NULL));
+    if (e != GPG_ERR_NO_ERROR)
+    {
+        error_from_gpgme (error, e);
+        goto err_ctx;
+    }
+    e = gpgme_set_protocol (ctx, GPGME_PROTOCOL_OpenPGP);
+    if (e != GPG_ERR_NO_ERROR)
+    {
+        error_from_gpgme (error, e);
+        goto err_ctx;
+    }
+    e = gpgme_ctx_set_engine_info (ctx, GPGME_PROTOCOL_OpenPGP, GPG_PATH, NULL);
+    if (e != GPG_ERR_NO_ERROR)
+    {
+        error_from_gpgme (error, e);
+        goto err_ctx;
+    }
+    gpgme_set_pinentry_mode (ctx, GPGME_PINENTRY_MODE_LOOPBACK);
+    gpgme_set_passphrase_cb (ctx, gpgme_passphrase_cb, (void *)passphrase);
+    *res = ctx;
+    return 0;
+
+    err_ctx:
+    gpgme_release (ctx);
+    err:
+    return -1;
+}
+
+/* LIBVK_PACKET_FORMAT_PASSPHRASE */
+
+/* Encrypt DATA of SIZE using PASSPHRASE.
+ *   Return encrypted data (for g_free()), setting RES_SIZE to the size of the
+ *   result, on success, NULL otherwise. */
+void *
+encrypt_with_passphrase (size_t *res_size, const void *data, size_t size,
+                         const char *passphrase, GError **error)
+{
+    gpgme_ctx_t ctx;
+    gpgme_error_t e;
+    gpgme_data_t src_data, dest_data;
+    void *gpgme_res, *res;
+
+    // FIXME: this should eventually use CMS
+    if (init_gpgme (&ctx, passphrase, error) != 0)
+        goto err;
+    e = gpgme_data_new_from_mem (&src_data, data, size, 0);
+    if (e != GPG_ERR_NO_ERROR)
+    {
+        error_from_gpgme (error, e);
+        goto err_ctx;
+    }
+    e = gpgme_data_new (&dest_data);
+    if (e != GPG_ERR_NO_ERROR)
+    {
+        error_from_gpgme (error, e);
+        goto err_src_data;
+    }
+    e = gpgme_op_encrypt (ctx, NULL, 0, src_data, dest_data);
+    if (e != GPG_ERR_NO_ERROR)
+    {
+        error_from_gpgme (error, e);
+        goto err_dest_data;
+    }
+    gpgme_data_release (src_data);
+    gpgme_res = gpgme_data_release_and_get_mem (dest_data, res_size);
+    if (gpgme_res == NULL)
+    {
+        g_set_error (error, LIBVK_ERROR, LIBVK_ERROR_CRYPTO,
+                     _("Unknown error getting encryption result"));
+        goto err_ctx;
+    }
+    res = g_memdup2 (gpgme_res, *res_size);
+    gpgme_free (gpgme_res);
+
+    gpgme_release (ctx);
+    return res;
+
+    err_dest_data:
+    gpgme_data_release (src_data);
+    err_src_data:
+    gpgme_data_release (dest_data);
+    err_ctx:
+    gpgme_release (ctx);
+    err:
+    return NULL;
+}
+
+/* Decrypt DATA of SIZE using PASSPHRASE.
+ *   Return decrypted data (for g_free()), setting RES_SIZE to the size of the
+ *   result, on success, NULL otherwise. */
+void *
+decrypt_with_passphrase (size_t *res_size, const void *data, size_t size,
+                        const char *passphrase, GError **error)
+{
+    gpgme_ctx_t ctx;
+    gpgme_error_t e;
+    gpgme_data_t src_data, dest_data;
+    void *gpgme_res, *res;
+
+    if (init_gpgme (&ctx, passphrase, error) != 0)
+        goto err;
+    e = gpgme_data_new_from_mem (&src_data, data, size, 0);
+    if (e != GPG_ERR_NO_ERROR)
+    {
+        error_from_gpgme (error, e);
+        goto err_ctx;
+    }
+    e = gpgme_data_new (&dest_data);
+    if (e != GPG_ERR_NO_ERROR)
+    {
+        error_from_gpgme (error, e);
+        goto err_src_data;
+    }
+    e = gpgme_op_decrypt (ctx, src_data, dest_data);
+    if (e != GPG_ERR_NO_ERROR)
+    {
+        error_from_gpgme (error, e);
+        goto err_dest_data;
+    }
+    gpgme_data_release (src_data);
+    gpgme_res = gpgme_data_release_and_get_mem (dest_data, res_size);
+    if (gpgme_res == NULL)
+    {
+        g_set_error (error, LIBVK_ERROR, LIBVK_ERROR_CRYPTO,
+                     _("Unknown error getting decryption result"));
+        goto err_ctx;
+    }
+    res = g_memdup2 (gpgme_res, *res_size);
+    gpgme_free (gpgme_res);
+
+    gpgme_release (ctx);
+    return res;
+
+    err_dest_data:
+    gpgme_data_release (src_data);
+    err_src_data:
+    gpgme_data_release (dest_data);
+    err_ctx:
+    gpgme_release (ctx);
+    err:
+    return NULL;
+}
+/* libgpgme utils */
+static void
+error_from_gpgme (GError **error, gpgme_error_t e)
+{
+    size_t len;
+    char *s;
+
+    s = NULL;
+    len = 100;
+    for (;;)
+    {
+        s = g_realloc (s, len);
+        if (gpgme_strerror_r (e, s, len) == 0)
+            break;
+        len *= 2;
+    }
+    g_set_error (error, LIBVK_ERROR, LIBVK_ERROR_CRYPTO, _("%s: %s"),
+                gpgme_strsource (e), s);
+    g_free (s);
+}
+
+static gpgme_error_t
+gpgme_passphrase_cb (void *hook, const char *uid_hint,
+                    const char *passphrase_info, int prev_was_bad, int fd)
+{
+    static const char nl = '\n';
+
+    const char *pw;
+    size_t len;
+    ssize_t res;
+
+    (void)uid_hint;
+    (void)passphrase_info;
+    if (prev_was_bad != 0)
+        return GPG_ERR_CANCELED;
+    pw = hook;
+    len = strlen (pw);
+    while (len != 0)
+    {
+        res = write (fd, pw, len);
+        if (res < 0)
+            return gpgme_error_from_errno (errno);
+        pw += res;
+        len -= res;
+    }
+    if (write (fd, &nl, sizeof (nl)) < 0)
+        return gpgme_error_from_errno (errno);
+    return 0;
+}
+// Error helper (simplified from GPGME’s error_from_gpgme)
+
+
+/* Create and configure a gpgme context, to use PASSPHRASE.
+ *   Return 0 if OK, -1 on error. */
+static int
+init_gpgme (gpgme_ctx_t *res, const char *passphrase, GError **error)
+{
+    gpgme_ctx_t ctx;
+    gpgme_error_t e;
+
+    (void)gpgme_check_version (NULL);
+    e = gpgme_new (&ctx);
+    if (e != GPG_ERR_NO_ERROR)
+    {
+        error_from_gpgme (error, e);
+        goto err;
+    }
+    e = gpgme_set_locale (ctx, LC_CTYPE, setlocale (LC_CTYPE, NULL));
+    if (e != GPG_ERR_NO_ERROR)
+    {
+        error_from_gpgme (error, e);
+        goto err_ctx;
+    }
+    e = gpgme_set_locale (ctx, LC_MESSAGES, setlocale (LC_MESSAGES, NULL));
+    if (e != GPG_ERR_NO_ERROR)
+    {
+        error_from_gpgme (error, e);
+        goto err_ctx;
+    }
+    e = gpgme_set_protocol (ctx, GPGME_PROTOCOL_OpenPGP);
+    if (e != GPG_ERR_NO_ERROR)
+    {
+        error_from_gpgme (error, e);
+        goto err_ctx;
+    }
+    e = gpgme_ctx_set_engine_info (ctx, GPGME_PROTOCOL_OpenPGP, GPG_PATH, NULL);
+    if (e != GPG_ERR_NO_ERROR)
+    {
+        error_from_gpgme (error, e);
+        goto err_ctx;
+    }
+    gpgme_set_pinentry_mode (ctx, GPGME_PINENTRY_MODE_LOOPBACK);
+    gpgme_set_passphrase_cb (ctx, gpgme_passphrase_cb, (void *)passphrase);
+    *res = ctx;
+    return 0;
+
+    err_ctx:
+    gpgme_release (ctx);
+    err:
+    return -1;
+}
+
+/* LIBVK_PACKET_FORMAT_PASSPHRASE */
+
+/* Encrypt DATA of SIZE using PASSPHRASE.
+ *   Return encrypted data (for g_free()), setting RES_SIZE to the size of the
+ *   result, on success, NULL otherwise. */
+void *
+encrypt_with_passphrase (size_t *res_size, const void *data, size_t size,
+                         const char *passphrase, GError **error)
+{
+    gpgme_ctx_t ctx;
+    gpgme_error_t e;
+    gpgme_data_t src_data, dest_data;
+    void *gpgme_res, *res;
+
+    // FIXME: this should eventually use CMS
+    if (init_gpgme (&ctx, passphrase, error) != 0)
+        goto err;
+    e = gpgme_data_new_from_mem (&src_data, data, size, 0);
+    if (e != GPG_ERR_NO_ERROR)
+    {
+        error_from_gpgme (error, e);
+        goto err_ctx;
+    }
+    e = gpgme_data_new (&dest_data);
+    if (e != GPG_ERR_NO_ERROR)
+    {
+        error_from_gpgme (error, e);
+        goto err_src_data;
+    }
+    e = gpgme_op_encrypt (ctx, NULL, 0, src_data, dest_data);
+    if (e != GPG_ERR_NO_ERROR)
+    {
+        error_from_gpgme (error, e);
+        goto err_dest_data;
+    }
+    gpgme_data_release (src_data);
+    gpgme_res = gpgme_data_release_and_get_mem (dest_data, res_size);
+    if (gpgme_res == NULL)
+    {
+        g_set_error (error, LIBVK_ERROR, LIBVK_ERROR_CRYPTO,
+                     _("Unknown error getting encryption result"));
+        goto err_ctx;
+    }
+    res = g_memdup2 (gpgme_res, *res_size);
+    gpgme_free (gpgme_res);
+
+    gpgme_release (ctx);
+    return res;
+
+    err_dest_data:
+    gpgme_data_release (src_data);
+    err_src_data:
+    gpgme_data_release (dest_data);
+    err_ctx:
+    gpgme_release (ctx);
+    err:
+    return NULL;
+}
+
+/* Decrypt DATA of SIZE using PASSPHRASE.
+ *   Return decrypted data (for g_free()), setting RES_SIZE to the size of the
+ *   result, on success, NULL otherwise. */
+void *
+decrypt_with_passphrase (size_t *res_size, const void *data, size_t size,
+                        const char *passphrase, GError **error)
+{
+    gpgme_ctx_t ctx;
+    gpgme_error_t e;
+    gpgme_data_t src_data, dest_data;
+    void *gpgme_res, *res;
+
+    if (init_gpgme (&ctx, passphrase, error) != 0)
+        goto err;
+    e = gpgme_data_new_from_mem (&src_data, data, size, 0);
+    if (e != GPG_ERR_NO_ERROR)
+    {
+        error_from_gpgme (error, e);
+        goto err_ctx;
+    }
+    e = gpgme_data_new (&dest_data);
+    if (e != GPG_ERR_NO_ERROR)
+    {
+        error_from_gpgme (error, e);
+        goto err_src_data;
+    }
+    e = gpgme_op_decrypt (ctx, src_data, dest_data);
+    if (e != GPG_ERR_NO_ERROR)
+    {
+        error_from_gpgme (error, e);
+        goto err_dest_data;
+    }
+    gpgme_data_release (src_data);
+    gpgme_res = gpgme_data_release_and_get_mem (dest_data, res_size);
+    if (gpgme_res == NULL)
+    {
+        g_set_error (error, LIBVK_ERROR, LIBVK_ERROR_CRYPTO,
+                     _("Unknown error getting decryption result"));
+        goto err_ctx;
+    }
+    res = g_memdup2 (gpgme_res, *res_size);
+    gpgme_free (gpgme_res);
+
+    gpgme_release (ctx);
+    return res;
+
+    err_dest_data:
+    gpgme_data_release (src_data);
+    err_src_data:
+    gpgme_data_release (dest_data);
+    err_ctx:
+    gpgme_release (ctx);
+    err:
+    return NULL;
+}
diff --git a/lib/crypto-gpgme.h b/lib/crypto-gpgme.h
new file mode 100644
index 0000000..985adcc
--- /dev/null
+++ b/lib/crypto-gpgme.h
@@ -0,0 +1,16 @@
+#ifndef CRYPTO_GPGME_H
+#define CRYPTO_GPGME_H
+void *encrypt_with_passphrase (size_t *res_size, const void *data, size_t size,
+                         const char *passphrase, GError **error);
+
+void *decrypt_with_passphrase (size_t *res_size, const void *data, size_t size,
+                         const char *passphrase, GError **error);
+#endif
+#ifndef CRYPTO_GPGME_H
+#define CRYPTO_GPGME_H
+void *encrypt_with_passphrase (size_t *res_size, const void *data, size_t size,
+                         const char *passphrase, GError **error);
+
+void *decrypt_with_passphrase (size_t *res_size, const void *data, size_t size,
+                         const char *passphrase, GError **error);
+#endif
diff --git a/lib/crypto-sq.c b/lib/crypto-sq.c
new file mode 100644
index 0000000..6e94be1
--- /dev/null
+++ b/lib/crypto-sq.c
@@ -0,0 +1,382 @@
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include "crypto-sq.h"
+#include "libvolume_key.h"
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+
+struct _sqme_ctx {
+    char *passphrase;
+};
+
+struct _sqme_data {
+    void *buf;
+    size_t size;
+    int owned;  // Whether we own the buffer (1) or not (0)
+};
+
+/* Error Handling */
+GQuark sqme_error_quark(void) {
+    return g_quark_from_static_string("sqme-error-quark");
+}
+
+void sqme_set_error(GError **error, sqme_error_t e, const char *msg) {
+    if (error) {
+        g_set_error(error, SQGPGME_ERROR, e, "%s", msg);
+    }
+}
+
+const char *sqme_strerror(sqme_error_t err) {
+    switch (err) {
+        case SQGPGME_ERR_NO_ERROR: return "No error";
+        case SQGPGME_ERR_GENERAL: return "General error";
+        case SQGPGME_ERR_ENOMEM: return "Out of memory";
+        case SQGPGME_ERR_CANCELED: return "Operation canceled";
+        case SQGPGME_ERR_BAD_PASSPHRASE: return "Bad passphrase";
+        case SQGPGME_ERR_SYSTEM: return "System error";
+        default: return "Unknown error";
+    }
+}
+
+/* Context Management */
+sqme_error_t sqme_new(sqme_ctx_t **ctx) {
+    *ctx = g_malloc0(sizeof(sqme_ctx_t));
+    if (!*ctx) return SQGPGME_ERR_ENOMEM;
+    return SQGPGME_ERR_NO_ERROR;
+}
+
+void sqme_release(sqme_ctx_t *ctx) {
+    if (!ctx) return;
+    g_free(ctx->passphrase);
+    g_free(ctx);
+}
+
+sqme_error_t sqme_set_passphrase(sqme_ctx_t *ctx, const char *passphrase) {
+    if (!ctx) return SQGPGME_ERR_GENERAL;
+    g_free(ctx->passphrase);
+    ctx->passphrase = g_strdup(passphrase);
+    return SQGPGME_ERR_NO_ERROR;
+}
+
+/* Data Management */
+sqme_error_t sqme_data_new_from_mem(sqme_data_t **data, const void *buf, size_t size, int copy) {
+    *data = g_malloc0(sizeof(sqme_data_t));
+    if (!*data) return SQGPGME_ERR_ENOMEM;
+    if (copy) {
+        (*data)->buf = g_memdup2(buf, size);
+        (*data)->owned = 1;
+    } else {
+        (*data)->buf = (void *)buf;
+        (*data)->owned = 0;
+    }
+    (*data)->size = size;
+    return SQGPGME_ERR_NO_ERROR;
+}
+
+sqme_error_t sqme_data_new(sqme_data_t **data) {
+    *data = g_malloc0(sizeof(sqme_data_t));
+    if (!*data) return SQGPGME_ERR_ENOMEM;
+    return SQGPGME_ERR_NO_ERROR;
+}
+
+void sqme_data_release(sqme_data_t *data) {
+    if (!data) return;
+    if (data->owned) g_free(data->buf);
+    g_free(data);
+}
+
+void *sqme_data_release_and_get_mem(sqme_data_t *data, size_t *size) {
+    if (!data) return NULL;
+    void *buf = data->buf;
+    *size = data->size;
+    data->buf = NULL;  // Prevent double free
+    sqme_data_release(data);
+    return buf;
+}
+
+/* Encryption/Decryption Helpers */
+static sqme_error_t run_sq(const char *passphrase, const char *cmd, const void *in, size_t in_size, void **out, size_t *out_size, GError **error) {
+    int in_pipe[2], out_pipe[2], err_pipe[2];
+    pid_t pid;
+    ssize_t total_read = 0;
+    char *out_buf = NULL;
+    size_t buf_size = 0;
+    char fifo_prefix[] = "/tmp/sqme_fifoXXXXXX";
+    char fifo_path[64]; // reserve some space for fifo_prefix and strcat later
+    int fifo_fd;
+
+    // Create named pipe (FIFO)
+    if (mkdtemp(fifo_prefix) == NULL) {
+        return SQGPGME_ERR_SYSTEM;
+    }
+    strcat(strcpy(fifo_path, fifo_prefix), "/fifo");
+    if (mkfifo(fifo_path, 0600) < 0) {
+        rmdir(fifo_prefix);
+        return SQGPGME_ERR_SYSTEM;
+    }
+
+    if (pipe(in_pipe) < 0 || pipe(out_pipe) < 0 || pipe(err_pipe) < 0) {
+        unlink(fifo_path);
+        return SQGPGME_ERR_SYSTEM;
+    }
+
+    pid = fork();
+    if (pid < 0) {
+        close(in_pipe[0]); close(in_pipe[1]);
+        close(out_pipe[0]); close(out_pipe[1]);
+        close(err_pipe[0]); close(err_pipe[1]);
+        unlink(fifo_path);
+        rmdir(fifo_prefix);
+        return SQGPGME_ERR_SYSTEM;
+    }
+
+    if (pid == 0) {  // Child process
+        close(in_pipe[1]);
+        close(out_pipe[0]);
+        close(err_pipe[0]);
+
+        dup2(in_pipe[0], STDIN_FILENO);
+        dup2(out_pipe[1], STDOUT_FILENO);
+        dup2(err_pipe[1], STDERR_FILENO);
+
+        if (strcmp(cmd, "encrypt") == 0) {
+            execlp(SQ_PATH, SQ_PATH, "encrypt", "--with-password-file", fifo_path, "--without-signature", NULL);
+        } else if (strcmp(cmd, "decrypt") == 0) {
+            execlp(SQ_PATH, SQ_PATH, "decrypt", "--password-file", fifo_path, NULL);
+        }
+        if (errno == ENOENT)
+            _exit(127);
+        _exit(126);  // If exec fails
+    }
+
+    // Parent process
+    close(in_pipe[0]);
+    close(out_pipe[1]);
+    close(err_pipe[1]);
+
+    // Write passphrase to FIFO (non-blocking write in a separate fork to avoid blocking)
+    pid_t fifo_pid = fork();
+    if (fifo_pid < 0) {
+        close(in_pipe[1]);
+        close(out_pipe[0]);
+        close(err_pipe[0]);
+        waitpid(pid, NULL, 0);
+        unlink(fifo_path);
+        return SQGPGME_ERR_SYSTEM;
+    }
+    if (fifo_pid == 0) {
+        fifo_fd = open(fifo_path, O_WRONLY);  // Blocks until sq opens for reading
+        if (fifo_fd >= 0) {
+            write(fifo_fd, passphrase, strlen(passphrase));  // No \n
+            close(fifo_fd);
+        }
+        _exit(0);
+    }
+
+    // Write input data to in_pipe
+    size_t remaining = in_size;
+    const char *in_ptr = in;
+    while (remaining > 0) {
+        ssize_t written = write(in_pipe[1], in_ptr, remaining);
+        if (written < 0) {
+            close(in_pipe[1]);
+            close(out_pipe[0]);
+            close(err_pipe[0]);
+            waitpid(pid, NULL, 0);
+            waitpid(fifo_pid, NULL, 0);
+            unlink(fifo_path);
+            rmdir(fifo_prefix);
+            return SQGPGME_ERR_SYSTEM;
+        }
+        in_ptr += written;
+        remaining -= written;
+    }
+    close(in_pipe[1]);
+
+    // Read output from out_pipe
+    char buffer[4096];
+    while (1) {
+        ssize_t n = read(out_pipe[0], buffer, sizeof(buffer));
+        if (n <= 0) break;  // EOF or error
+        if (total_read + n > buf_size) {
+            buf_size = total_read + n + 4096;  // Grow buffer with padding
+            out_buf = g_realloc(out_buf, buf_size);
+        }
+        memcpy(out_buf + total_read, buffer, n);
+        total_read += n;
+    }
+    close(out_pipe[0]);
+
+    // Read stderr for error messages
+    char err_buf[1024];
+    ssize_t err_len = read(err_pipe[0], err_buf, sizeof(err_buf) - 1);
+    close(err_pipe[0]);
+    if (err_len > 0) {
+        err_buf[err_len] = '\0';
+    }
+
+    int status;
+    waitpid(pid, &status, 0);
+
+    int exit_code = 0;
+    if (WIFEXITED(status) && ((exit_code=WEXITSTATUS(status)) !=0)) {
+        // exit_code = WEXITSTATUS(status);
+        kill(fifo_pid, SIGTERM); // Terminate second child if still running
+        g_free(out_buf);
+        if (err_len > 0) {
+            sqme_set_error(error, SQGPGME_ERR_BAD_PASSPHRASE, err_buf);
+        } else if (exit_code == 126) {
+            sqme_set_error(error, SQGPGME_ERR_SYSTEM, "Execution of 'sq' failed");
+        } else if (exit_code == 127) {
+            sqme_set_error(error, SQGPGME_ERR_SYSTEM, "sq executable not found");
+        } else {
+            sqme_set_error(error, SQGPGME_ERR_BAD_PASSPHRASE, "Command failed, possibly bad passphrase");
+        }
+    }
+    waitpid(fifo_pid, NULL, 0);  // Clean up FIFO writer
+    rmdir(fifo_prefix);
+    unlink(fifo_path);  // Remove FIFO
+
+    if (exit_code) {
+        return SQGPGME_ERR_BAD_PASSPHRASE;
+    }
+
+    *out = out_buf;
+    *out_size = total_read;
+    return SQGPGME_ERR_NO_ERROR;
+}
+
+sqme_error_t sqme_op_encrypt(sqme_ctx_t *ctx, sqme_data_t *in, sqme_data_t *out, GError **error) {
+    if (!ctx || !in || !out || !ctx->passphrase) return SQGPGME_ERR_GENERAL;
+    void *out_buf;
+    size_t out_size;
+    sqme_error_t err = run_sq(ctx->passphrase, "encrypt", in->buf, in->size, &out_buf, &out_size, error);
+    if (err == SQGPGME_ERR_NO_ERROR) {
+        out->buf = out_buf;
+        out->size = out_size;
+        out->owned = 1;
+    }
+    return err;
+}
+
+sqme_error_t sqme_op_decrypt(sqme_ctx_t *ctx, sqme_data_t *in, sqme_data_t *out, GError **error) {
+    if (!ctx || !in || !out || !ctx->passphrase) return SQGPGME_ERR_GENERAL;
+    void *out_buf;
+    size_t out_size;
+    sqme_error_t err = run_sq(ctx->passphrase, "decrypt", in->buf, in->size, &out_buf, &out_size, error);
+    if (err == SQGPGME_ERR_NO_ERROR) {
+        out->buf = out_buf;
+        out->size = out_size;
+        out->owned = 1;
+    }
+    return err;
+}
+
+void *
+encrypt_with_passphrase(size_t *res_size, const void *data, size_t size,
+                        const char *passphrase, GError **error)
+{
+    sqme_ctx_t *ctx;
+    sqme_data_t *src_data, *dest_data;
+    void *res;
+
+    if (sqme_new(&ctx) != SQGPGME_ERR_NO_ERROR) {
+        sqme_set_error(error, SQGPGME_ERR_ENOMEM, "Failed to create context");
+        goto err;
+    }
+    if (sqme_set_passphrase(ctx, passphrase) != SQGPGME_ERR_NO_ERROR) {
+        sqme_set_error(error, SQGPGME_ERR_GENERAL, "Failed to set passphrase");
+        goto err_ctx;
+    }
+    if (sqme_data_new_from_mem(&src_data, data, size, 0) != SQGPGME_ERR_NO_ERROR) {
+        sqme_set_error(error, SQGPGME_ERR_ENOMEM, "Failed to create source data");
+        goto err_ctx;
+    }
+    if (sqme_data_new(&dest_data) != SQGPGME_ERR_NO_ERROR) {
+        sqme_set_error(error, SQGPGME_ERR_ENOMEM, "Failed to create destination data");
+        goto err_src_data;
+    }
+    if (sqme_op_encrypt(ctx, src_data, dest_data, error) != SQGPGME_ERR_NO_ERROR) {
+        if (!*error)
+            sqme_set_error(error, SQGPGME_ERR_BAD_PASSPHRASE, "Encryption failed, possibly bad passphrase");
+        goto err_dest_data;
+    }
+
+    sqme_data_release(src_data);
+    res = sqme_data_release_and_get_mem(dest_data, res_size);
+    if (!res) {
+        g_set_error(error, LIBVK_ERROR, LIBVK_ERROR_CRYPTO, _("Unknown error getting encryption result"));
+        goto err_ctx;
+    }
+    sqme_release(ctx);
+    return res;
+
+    err_dest_data:
+    sqme_data_release(dest_data);
+    err_src_data:
+    sqme_data_release(src_data);
+    err_ctx:
+    sqme_release(ctx);
+    err:
+    return NULL;
+}
+
+
+/* Decrypt DATA of SIZE using PASSPHRASE.
+ *   Return decrypted data (for g_free()), setting RES_SIZE to the size of the
+ *   result, on success, NULL otherwise. */
+void *
+decrypt_with_passphrase(size_t *res_size, const void *data, size_t size,
+                        const char *passphrase, GError **error)
+{
+    sqme_ctx_t *ctx;
+    sqme_data_t *src_data, *dest_data;
+    void *res;
+
+    if (sqme_new(&ctx) != SQGPGME_ERR_NO_ERROR) {
+        sqme_set_error(error, SQGPGME_ERR_ENOMEM, "Failed to create context");
+        goto err;
+    }
+    if (sqme_set_passphrase(ctx, passphrase) != SQGPGME_ERR_NO_ERROR) {
+        sqme_set_error(error, SQGPGME_ERR_GENERAL, "Failed to set passphrase");
+        goto err_ctx;
+    }
+    if (sqme_data_new_from_mem(&src_data, data, size, 0) != SQGPGME_ERR_NO_ERROR) {
+        sqme_set_error(error, SQGPGME_ERR_ENOMEM, "Failed to create source data");
+        goto err_ctx;
+    }
+    if (sqme_data_new(&dest_data) != SQGPGME_ERR_NO_ERROR) {
+        sqme_set_error(error, SQGPGME_ERR_ENOMEM, "Failed to create destination data");
+        goto err_src_data;
+    }
+    if (sqme_op_decrypt(ctx, src_data, dest_data, error) != SQGPGME_ERR_NO_ERROR) {
+        if (!*error)
+            sqme_set_error(error, SQGPGME_ERR_BAD_PASSPHRASE, "Decryption failed, possibly bad passphrase");
+        goto err_dest_data;
+    }
+
+    sqme_data_release(src_data);
+    res = sqme_data_release_and_get_mem(dest_data, res_size);
+    if (!res) {
+        g_set_error(error, LIBVK_ERROR, LIBVK_ERROR_CRYPTO, _("Unknown error getting encryption result"));
+        goto err_ctx;
+    }
+    sqme_release(ctx);
+    return res;
+
+    err_dest_data:
+    sqme_data_release(dest_data);
+    err_src_data:
+    sqme_data_release(src_data);
+    err_ctx:
+    sqme_release(ctx);
+    err:
+    return NULL;
+}
diff --git a/lib/crypto-sq.h b/lib/crypto-sq.h
new file mode 100644
index 0000000..e7ff6ca
--- /dev/null
+++ b/lib/crypto-sq.h
@@ -0,0 +1,45 @@
+#ifndef SQME_H
+#define SQME_H
+
+#include <stddef.h>
+#include <glib.h>
+
+typedef enum {
+    SQGPGME_ERR_NO_ERROR = 0,
+    SQGPGME_ERR_GENERAL = 1,
+    SQGPGME_ERR_ENOMEM = 2,
+    SQGPGME_ERR_CANCELED = 3,
+    SQGPGME_ERR_BAD_PASSPHRASE = 4,
+    SQGPGME_ERR_SYSTEM = 5
+} sqme_error_t;
+
+typedef struct _sqme_ctx sqme_ctx_t;
+typedef struct _sqme_data sqme_data_t;
+
+// Error domain for sqme
+GQuark sqme_error_quark(void);
+#define SQGPGME_ERROR (sqme_error_quark())
+
+sqme_error_t sqme_new(sqme_ctx_t **ctx);
+void sqme_release(sqme_ctx_t *ctx);
+sqme_error_t sqme_set_passphrase(sqme_ctx_t *ctx, const char *passphrase);
+
+sqme_error_t sqme_data_new_from_mem(sqme_data_t **data, const void *buf, size_t size, int copy);
+sqme_error_t sqme_data_new(sqme_data_t **data);
+void sqme_data_release(sqme_data_t *data);
+void *sqme_data_release_and_get_mem(sqme_data_t *data, size_t *size);
+
+sqme_error_t sqme_op_encrypt(sqme_ctx_t *ctx, sqme_data_t *in, sqme_data_t *out, GError **error);
+sqme_error_t sqme_op_decrypt(sqme_ctx_t *ctx, sqme_data_t *in, sqme_data_t *out, GError **error);
+
+const char *sqme_strerror(sqme_error_t err);
+void sqme_set_error(GError **error, sqme_error_t e, const char *msg);
+
+void *encrypt_with_passphrase(size_t *res_size, const void *data, size_t size,
+                        const char *passphrase, GError **error);
+
+void *decrypt_with_passphrase(size_t *res_size, const void *data, size_t size,
+                        const char *passphrase, GError **error);
+
+#endif /* SQME_H */
+
diff --git a/lib/crypto.c b/lib/crypto.c
index b78b886..b85246c 100644
--- a/lib/crypto.c
+++ b/lib/crypto.c
@@ -26,7 +26,6 @@ Author: Miloslav Trmač <mitr@redhat.com> */
 #include <cms.h>
 #include <glib.h>
 #include <glib/gi18n-lib.h>
-#include <gpgme.h>
 #include <keyhi.h>
 #include <nss.h>
 #include <pk11pub.h>
@@ -34,6 +33,11 @@ Author: Miloslav Trmač <mitr@redhat.com> */
 #include <prinit.h>
 #include <smime.h>
 
+#if WITH_SQ
+# include "crypto-sq.h"
+#else
+# include "crypto-gpgme.h"
+#endif
 #include "crypto.h"
 #include "nss_error.h"
 #include "libvolume_key.h"
@@ -682,219 +686,3 @@ unwrap_symmetric (size_t *clear_secret_size, PK11SymKey *wrapping_key,
  err:
   return NULL;
 }
-
- /* libgpgme utils */
-
-static void
-error_from_gpgme (GError **error, gpgme_error_t e)
-{
-  size_t len;
-  char *s;
-
-  s = NULL;
-  len = 100;
-  for (;;)
-    {
-      s = g_realloc (s, len);
-      if (gpgme_strerror_r (e, s, len) == 0)
-	break;
-      len *= 2;
-    }
-  g_set_error (error, LIBVK_ERROR, LIBVK_ERROR_CRYPTO, _("%s: %s"),
-	       gpgme_strsource (e), s);
-  g_free (s);
-}
-
-static gpgme_error_t
-gpgme_passphrase_cb (void *hook, const char *uid_hint,
-		     const char *passphrase_info, int prev_was_bad, int fd)
-{
-  static const char nl = '\n';
-
-  const char *pw;
-  size_t len;
-  ssize_t res;
-
-  (void)uid_hint;
-  (void)passphrase_info;
-  if (prev_was_bad != 0)
-    return GPG_ERR_CANCELED;
-  pw = hook;
-  len = strlen (pw);
-  while (len != 0)
-    {
-      res = write (fd, pw, len);
-      if (res < 0)
-	return gpgme_error_from_errno (errno);
-      pw += res;
-      len -= res;
-    }
-  if (write (fd, &nl, sizeof (nl)) < 0)
-    return gpgme_error_from_errno (errno);
-  return 0;
-}
-
-/* Create and configure a gpgme context, to use PASSPHRASE.
-   Return 0 if OK, -1 on error. */
-static int
-init_gpgme (gpgme_ctx_t *res, const char *passphrase, GError **error)
-{
-  gpgme_ctx_t ctx;
-  gpgme_error_t e;
-
-  (void)gpgme_check_version (NULL);
-  e = gpgme_new (&ctx);
-  if (e != GPG_ERR_NO_ERROR)
-    {
-      error_from_gpgme (error, e);
-      goto err;
-    }
-  e = gpgme_set_locale (ctx, LC_CTYPE, setlocale (LC_CTYPE, NULL));
-  if (e != GPG_ERR_NO_ERROR)
-    {
-      error_from_gpgme (error, e);
-      goto err_ctx;
-    }
-  e = gpgme_set_locale (ctx, LC_MESSAGES, setlocale (LC_MESSAGES, NULL));
-  if (e != GPG_ERR_NO_ERROR)
-    {
-      error_from_gpgme (error, e);
-      goto err_ctx;
-    }
-  e = gpgme_set_protocol (ctx, GPGME_PROTOCOL_OpenPGP);
-  if (e != GPG_ERR_NO_ERROR)
-    {
-      error_from_gpgme (error, e);
-      goto err_ctx;
-    }
-  e = gpgme_ctx_set_engine_info (ctx, GPGME_PROTOCOL_OpenPGP, GPG_PATH, NULL);
-  if (e != GPG_ERR_NO_ERROR)
-    {
-      error_from_gpgme (error, e);
-      goto err_ctx;
-    }
-  gpgme_set_pinentry_mode (ctx, GPGME_PINENTRY_MODE_LOOPBACK);
-  gpgme_set_passphrase_cb (ctx, gpgme_passphrase_cb, (void *)passphrase);
-  *res = ctx;
-  return 0;
-
- err_ctx:
-  gpgme_release (ctx);
- err:
-  return -1;
-}
-
- /* LIBVK_PACKET_FORMAT_PASSPHRASE */
-
-/* Encrypt DATA of SIZE using PASSPHRASE.
-   Return encrypted data (for g_free()), setting RES_SIZE to the size of the
-   result, on success, NULL otherwise. */
-void *
-encrypt_with_passphrase (size_t *res_size, const void *data, size_t size,
-			 const char *passphrase, GError **error)
-{
-  gpgme_ctx_t ctx;
-  gpgme_error_t e;
-  gpgme_data_t src_data, dest_data;
-  void *gpgme_res, *res;
-
-  // FIXME: this should eventually use CMS
-  if (init_gpgme (&ctx, passphrase, error) != 0)
-      goto err;
-  e = gpgme_data_new_from_mem (&src_data, data, size, 0);
-  if (e != GPG_ERR_NO_ERROR)
-    {
-      error_from_gpgme (error, e);
-      goto err_ctx;
-    }
-  e = gpgme_data_new (&dest_data);
-  if (e != GPG_ERR_NO_ERROR)
-    {
-      error_from_gpgme (error, e);
-      goto err_src_data;
-    }
-  e = gpgme_op_encrypt (ctx, NULL, 0, src_data, dest_data);
-  if (e != GPG_ERR_NO_ERROR)
-    {
-      error_from_gpgme (error, e);
-      goto err_dest_data;
-    }
-  gpgme_data_release (src_data);
-  gpgme_res = gpgme_data_release_and_get_mem (dest_data, res_size);
-  if (gpgme_res == NULL)
-    {
-      g_set_error (error, LIBVK_ERROR, LIBVK_ERROR_CRYPTO,
-		   _("Unknown error getting encryption result"));
-      goto err_ctx;
-    }
-  res = g_memdup2 (gpgme_res, *res_size);
-  gpgme_free (gpgme_res);
-
-  gpgme_release (ctx);
-  return res;
-
- err_dest_data:
-  gpgme_data_release (src_data);
- err_src_data:
-  gpgme_data_release (dest_data);
- err_ctx:
-  gpgme_release (ctx);
- err:
-  return NULL;
-}
-
-/* Decrypt DATA of SIZE using PASSPHRASE.
-   Return decrypted data (for g_free()), setting RES_SIZE to the size of the
-   result, on success, NULL otherwise. */
-void *
-decrypt_with_passphrase (size_t *res_size, const void *data, size_t size,
-			 const char *passphrase, GError **error)
-{
-  gpgme_ctx_t ctx;
-  gpgme_error_t e;
-  gpgme_data_t src_data, dest_data;
-  void *gpgme_res, *res;
-
-  if (init_gpgme (&ctx, passphrase, error) != 0)
-      goto err;
-  e = gpgme_data_new_from_mem (&src_data, data, size, 0);
-  if (e != GPG_ERR_NO_ERROR)
-    {
-      error_from_gpgme (error, e);
-      goto err_ctx;
-    }
-  e = gpgme_data_new (&dest_data);
-  if (e != GPG_ERR_NO_ERROR)
-    {
-      error_from_gpgme (error, e);
-      goto err_src_data;
-    }
-  e = gpgme_op_decrypt (ctx, src_data, dest_data);
-  if (e != GPG_ERR_NO_ERROR)
-    {
-      error_from_gpgme (error, e);
-      goto err_dest_data;
-    }
-  gpgme_data_release (src_data);
-  gpgme_res = gpgme_data_release_and_get_mem (dest_data, res_size);
-  if (gpgme_res == NULL)
-    {
-      g_set_error (error, LIBVK_ERROR, LIBVK_ERROR_CRYPTO,
-		   _("Unknown error getting decryption result"));
-      goto err_ctx;
-    }
-  res = g_memdup2 (gpgme_res, *res_size);
-  gpgme_free (gpgme_res);
-
-  gpgme_release (ctx);
-  return res;
-
- err_dest_data:
-  gpgme_data_release (src_data);
- err_src_data:
-  gpgme_data_release (dest_data);
- err_ctx:
-  gpgme_release (ctx);
- err:
-  return NULL;
-}
diff --git a/m4/sq.m4 b/m4/sq.m4
new file mode 100644
index 0000000..28d7023
--- /dev/null
+++ b/m4/sq.m4
@@ -0,0 +1,34 @@
+AC_DEFUN([AM_CHECK_SQ],
+[
+  AC_ARG_WITH([sq],
+    [AS_HELP_STRING([--with-sq=PATH],
+      [specify the path to the Sequoia 'sq' binary])],
+    [sq_path="$withval"],
+    [sq_path=""])
+
+
+  SQ_PATH=""
+  if test "x$sq_path" != "x" -a "x$sq_path" != "xyes" ; then
+  AC_MSG_CHECKING([for Sequoia sq])
+    if test -x "$sq_path"; then
+      SQ_PATH="$sq_path"
+      AC_MSG_RESULT([found at $sq_path])
+    else
+      AC_MSG_ERROR([specified sq binary at $sq_path is not executable])
+    fi
+  else
+    # Search for sq in PATH
+    AC_PATH_PROG([SQ_PATH], [sq])
+
+    if test "x$SQ_PATH" = "x"; then
+      AC_MSG_ERROR([Sequoia sq binary not found in PATH])
+    fi
+  fi
+
+  # Define variables only if sq is found
+  if test "x$SQ_PATH" != "x"; then
+    AC_SUBST([SQ_PATH])
+    AC_DEFINE_UNQUOTED([SQ_PATH], ["$SQ_PATH"], [Path to Sequoia sq binary])
+    AC_DEFINE([WITH_SQ], [1], [Define to 1 if Sequoia sq binary is available])
+  fi
+])

