about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/pgp/gpg.c92
-rw-r--r--src/pgp/gpg.h3
-rw-r--r--src/xmpp/message.c30
-rw-r--r--src/xmpp/presence.c2
-rw-r--r--src/xmpp/stanza.h1
5 files changed, 109 insertions, 19 deletions
diff --git a/src/pgp/gpg.c b/src/pgp/gpg.c
index 69723c01..68fe6526 100644
--- a/src/pgp/gpg.c
+++ b/src/pgp/gpg.c
@@ -42,13 +42,14 @@
 #include "pgp/gpg.h"
 #include "log.h"
 
-#define PGP_HEADER "-----BEGIN PGP SIGNATURE-----"
-#define PGP_FOOTER "-----END PGP SIGNATURE-----"
+#define PGP_SIGNATURE_HEADER "-----BEGIN PGP SIGNATURE-----"
+#define PGP_SIGNATURE_FOOTER "-----END PGP SIGNATURE-----"
+#define PGP_MESSAGE_FOOTER "-----END PGP MESSAGE-----"
 
 static const char *libversion;
 static GHashTable *fingerprints;
 
-static char* _remove_header_footer(char *str);
+static char* _remove_header_footer(char *str, const char * const footer);
 static char* _add_header_footer(const char * const str);
 
 void
@@ -171,7 +172,7 @@ p_gpg_verify(const char * const barejid, const char *const sign)
 }
 
 char*
-p_gpg_sign_str(const char * const str, const char * const fp)
+p_gpg_sign(const char * const str, const char * const fp)
 {
     gpgme_ctx_t ctx;
     gpgme_error_t error = gpgme_new(&ctx);
@@ -222,7 +223,7 @@ p_gpg_sign_str(const char * const str, const char * const fp)
     char *signed_str = gpgme_data_release_and_get_mem(signed_data, &len);
     if (signed_str != NULL) {
         signed_str[len] = 0;
-        result = _remove_header_footer(signed_str);
+        result = _remove_header_footer(signed_str, PGP_SIGNATURE_FOOTER);
     }
     gpgme_free(signed_str);
     gpgme_release(ctx);
@@ -231,26 +232,85 @@ p_gpg_sign_str(const char * const str, const char * const fp)
     return result;
 }
 
-static char*
-_remove_header_footer(char *str)
+char *
+p_gpg_encrypt(const char * const barejid, const char * const message)
 {
-    char *pointer = str;
+    char *fp = g_hash_table_lookup(fingerprints, barejid);
+
+    if (!fp) {
+        return NULL;
+    }
+
+    gpgme_key_t keys[2];
+
+    keys[0] = NULL;
+    keys[1] = NULL;
+
+    gpgme_ctx_t ctx;
+    gpgme_error_t error = gpgme_new(&ctx);
+    if (error) {
+        log_error("GPG: Failed to create gpgme context. %s %s", gpgme_strsource(error), gpgme_strerror(error));
+        return NULL;
+    }
+
+    gpgme_key_t key;
+    error = gpgme_get_key(ctx, fp, &key, 0);
+    if (error || key == NULL) {
+        log_error("GPG: Failed to get key. %s %s", gpgme_strsource(error), gpgme_strerror(error));
+        gpgme_release(ctx);
+        return NULL;
+    }
+
+    keys[0] = key;
+
+    gpgme_data_t plain;
+    gpgme_data_t cipher;
+    gpgme_data_new_from_mem(&plain, message, strlen(message), 1);
+    gpgme_data_new(&cipher);
+
+    gpgme_set_armor(ctx, 1);
+    error = gpgme_op_encrypt(ctx, keys, GPGME_ENCRYPT_ALWAYS_TRUST, plain, cipher);
+    if (error) {
+        log_error("GPG: Failed to encrypt message. %s %s", gpgme_strsource(error), gpgme_strerror(error));
+        gpgme_release(ctx);
+        return NULL;
+    }
+    gpgme_data_release(plain);
 
+    char *cipher_str = NULL;
+    char *result = NULL;
+    size_t len;
+    cipher_str = gpgme_data_release_and_get_mem(cipher, &len);
+    if (cipher_str) {
+        result = _remove_header_footer(cipher_str, PGP_MESSAGE_FOOTER);
+    }
+
+    gpgme_free(cipher_str);
+    gpgme_release(ctx);
+
+    return result;
+}
+
+static char*
+_remove_header_footer(char *str, const char * const footer)
+{
+    int pos = 0;
     int newlines = 0;
+
     while (newlines < 3) {
-        if (pointer[0] == '\n') {
+        if (str[pos] == '\n') {
             newlines++;
         }
-        pointer++;
+        pos++;
 
-        if (strlen(pointer) == 0) {
+        if (str[pos] == '\0') {
             return NULL;
         }
     }
 
-    char *stripped = malloc(strlen(pointer)+1-strlen(PGP_FOOTER));
-    strncpy(stripped,pointer,strlen(pointer)-strlen(PGP_FOOTER));
-    stripped[strlen(pointer)-strlen(PGP_FOOTER)] = '\0';
+    char *stripped = strdup(&str[pos]);
+    char *footer_start = g_strrstr(stripped, footer);
+    footer_start[0] = '\0';
 
     return stripped;
 }
@@ -260,11 +320,11 @@ _add_header_footer(const char * const str)
 {
     GString *result_str = g_string_new("");
 
-    g_string_append(result_str, PGP_HEADER);
+    g_string_append(result_str, PGP_SIGNATURE_HEADER);
     g_string_append(result_str, "\n\n");
     g_string_append(result_str, str);
     g_string_append(result_str, "\n");
-    g_string_append(result_str, PGP_FOOTER);
+    g_string_append(result_str, PGP_SIGNATURE_FOOTER);
 
     char *result = result_str->str;
     g_string_free(result_str, FALSE);
diff --git a/src/pgp/gpg.h b/src/pgp/gpg.h
index 7c058024..bd60f439 100644
--- a/src/pgp/gpg.h
+++ b/src/pgp/gpg.h
@@ -47,7 +47,8 @@ GSList* p_gpg_list_keys(void);
 GHashTable* p_gpg_fingerprints(void);
 const char* p_gpg_libver(void);
 void p_gpg_free_key(ProfPGPKey *key);
-char* p_gpg_sign_str(const char * const str, const char * const fp);
+char* p_gpg_sign(const char * const str, const char * const fp);
 void p_gpg_verify(const char * const barejid, const char *const sign);
+char* p_gpg_encrypt(const char * const barejid, const char * const message);
 
 #endif
diff --git a/src/xmpp/message.c b/src/xmpp/message.c
index e6927f76..57e434c5 100644
--- a/src/xmpp/message.c
+++ b/src/xmpp/message.c
@@ -49,6 +49,7 @@
 #include "roster_list.h"
 #include "xmpp/stanza.h"
 #include "xmpp/xmpp.h"
+#include "pgp/gpg.h"
 
 #define HANDLE(ns, type, func) xmpp_handler_add(conn, func, ns, STANZA_NAME_MESSAGE, type, ctx)
 
@@ -104,7 +105,34 @@ message_send_chat(const char * const barejid, const char * const msg)
     }
 
     char *id = create_unique_id("msg");
-    xmpp_stanza_t *message = stanza_create_message(ctx, id, jid, STANZA_TYPE_CHAT, msg);
+    xmpp_stanza_t *message = NULL;
+
+#ifdef HAVE_LIBGPGME
+    char *account_name = jabber_get_account_name();
+    ProfAccount *account = accounts_get_account(account_name);
+    if (account->pgp_keyid) {
+        Jid *jidp = jid_create(jid);
+        char *encrypted = p_gpg_encrypt(jidp->barejid, msg);
+        if (encrypted) {
+            message = stanza_create_message(ctx, id, jid, STANZA_TYPE_CHAT, "This message is encrypted.");
+            xmpp_stanza_t *x = xmpp_stanza_new(ctx);
+            xmpp_stanza_set_name(x, STANZA_NAME_X);
+            xmpp_stanza_set_ns(x, STANZA_NS_ENCRYPTED);
+            xmpp_stanza_t *enc_st = xmpp_stanza_new(ctx);
+            xmpp_stanza_set_text(enc_st, encrypted);
+            xmpp_stanza_add_child(x, enc_st);
+            xmpp_stanza_release(enc_st);
+            xmpp_stanza_add_child(message, x);
+            xmpp_stanza_release(x);
+            free(encrypted);
+        } else {
+            message = stanza_create_message(ctx, id, jid, STANZA_TYPE_CHAT, msg);
+        }
+    }
+#else
+    message = stanza_create_message(ctx, id, jid, STANZA_TYPE_CHAT, msg);
+#endif
+
     free(jid);
 
     if (state) {
diff --git a/src/xmpp/presence.c b/src/xmpp/presence.c
index 241932e6..07ac05dd 100644
--- a/src/xmpp/presence.c
+++ b/src/xmpp/presence.c
@@ -232,7 +232,7 @@ presence_update(const resource_presence_t presence_type, const char * const msg,
     char *account_name = jabber_get_account_name();
     ProfAccount *account = accounts_get_account(account_name);
     if (account->pgp_keyid) {
-        char *signed_status = p_gpg_sign_str(msg, account->pgp_keyid);
+        char *signed_status = p_gpg_sign(msg, account->pgp_keyid);
 
         if (signed_status) {
             xmpp_stanza_t *x = xmpp_stanza_new(ctx);
diff --git a/src/xmpp/stanza.h b/src/xmpp/stanza.h
index 1460642d..6bd01ab4 100644
--- a/src/xmpp/stanza.h
+++ b/src/xmpp/stanza.h
@@ -160,6 +160,7 @@
 #define STANZA_NS_FORWARD "urn:xmpp:forward:0"
 #define STANZA_NS_RECEIPTS "urn:xmpp:receipts"
 #define STANZA_NS_SIGNED "jabber:x:signed"
+#define STANZA_NS_ENCRYPTED "jabber:x:encrypted"
 
 #define STANZA_DATAFORM_SOFTWARE "urn:xmpp:dataforms:softwareinfo"