Skip to content

Instantly share code, notes, and snippets.

@mhanne
Last active May 9, 2020 07:02
Show Gist options
  • Save mhanne/1630071 to your computer and use it in GitHub Desktop.
Save mhanne/1630071 to your computer and use it in GitHub Desktop.
libotr usage example
#include <assert.h>
#include <stdio.h>
#include <gcrypt.h>
#include <string.h>
#include <libotr/proto.h>
#include <libotr/userstate.h>
#include <libotr/message.h>
#include <libotr/privkey.h>
static void print_hex(char *string)
{
int i;
for (i = 0; i < strlen(string); i++) {
printf("%x", string[i]);
}
printf("\n");
}
static void print_hexa(char *name, char *value)
{
printf("%s = '%s'\n", name, value);
printf("%s = 0x", name);
print_hex(value);
}
#define PRINT(var) print_hexa(#var, var);
OtrlUserState tst1_userstate;
OtrlUserState tst2_userstate;
OtrlMessageAppOps ui_ops ;
OtrlUserState get_userstate(const char *username)
{
if (strcmp(username, "tst1")) {
return tst1_userstate;
} else if(strcmp(username, "tst2")) {
return tst2_userstate;
} else {
/* we really want to blow up so an error is visible immediately */
assert(0);
return NULL;
}
}
static OtrlPolicy policy_cb(void *opdata, ConnContext *context)
{
printf("policy_cb\n");
return OTRL_POLICY_DEFAULT;
}
static void create_privkey_cb(void *opdata, const char *accountname,
const char *protocol)
{
char *filename = malloc(snprintf(NULL, 0, "keys_%s.txt", accountname) + 1);
sprintf(filename, "keys_%s.txt", accountname);
printf("create_privkey_cb\n");
printf("account = %s\n", accountname);
printf("filename = %s\n", filename);
otrl_privkey_generate(get_userstate(accountname), filename, accountname, protocol);
otrl_privkey_read(get_userstate(accountname), filename);
printf("key generated\n");
}
static int is_logged_in_cb(void *opdata, const char *accountname,
const char *protocol, const char *recipient)
{
printf("is_online_cb\n");
return -1;
}
static void inject_message_cb(void *opdata, const char *accountname,
const char *protocol, const char *recipient, const char *message)
{
printf("inject_message_cb\n");
printf("from = %s\n", accountname);
printf("to = %s\n", recipient);
printf("message = '%s'\n", message);
char *msg_decrypt = NULL;
int intern_message;
intern_message = otrl_message_receiving(
get_userstate(recipient),
&ui_ops,
NULL,
recipient,
protocol,
accountname,
message,
&msg_decrypt,
NULL,
NULL,
NULL,
NULL
);
printf("decrypted msg = '%s'\n", msg_decrypt);
printf("err = %i\n", intern_message);
}
static void update_context_list_cb(void *opdata)
{
printf("update_context_list_cb\n");
}
static void new_fingerprint_cb(void *opdata, OtrlUserState us,
const char *accountname, const char *protocol, const char *username,
unsigned char fingerprint[20])
{
printf("new_fingerprint_cb\n");
}
static void write_fingerprints_cb(void *opdata)
{
printf("write_fingerprints_cb\n");
}
static void gone_secure_cb(void *opdata, ConnContext *context) {
printf(" -> gone_secure_cb\n");
return;
}
static void gone_insecure_cb(void *opdata, ConnContext *context)
{
printf("gone_insecure_cb\n");
}
static void still_secure_cb(void *opdata, ConnContext *context, int is_reply)
{
printf("still_secure_cb\n");
}
static int max_message_size_cb(void *opdata, ConnContext *context)
{
printf("max_message_size_cb\n");
return 512;
}
static const char *account_name_cb(void *opdata, const char *account_name, const char *protocol)
{
printf("account_name_cb\n");
return 0;
}
static void account_name_free_cb(void *opdata, const char *account_name)
{
printf("account_name_cb\n");
}
static void received_symkey_cb(void *opdata, ConnContext *context, unsigned int use, const unsigned char *usedata, size_t usedatalen, const unsigned char *symkey)
{
printf("received_symkey_cb\n");
}
static const char *otr_error_message_cb(void *opdata, ConnContext *context, OtrlErrorCode err_code)
{
printf("otr_error_message_cb\n");
printf("OtrlErrorCode = %i\n", err_code);
return 0;
}
static void otr_error_message_free_cb(void *opdata, const char *err_msg)
{
printf("otr_error_message_free\n");
}
static const char *resent_msg_prefix_cb(void *opdata, ConnContext *context)
{
printf("resent_msg_prefix\n");
return NULL;
}
static void resent_msg_prefix_free_cb(void *opdata, const char *prefix)
{
printf("otr_error_message_free\n");
}
static void handle_smp_event_cb(void *opdata, OtrlSMPEvent smp_event, ConnContext *context, unsigned short progress_percent, char *question)
{
printf("handle_smp_event\n");
}
static void handle_msg_event_cb(void *opdata, OtrlMessageEvent msg_event, ConnContext *context, const char *message, gcry_error_t err)
{
printf("handle_msg_event\n");
}
static void create_instag(void *opdata, const char *accountname, const char *protocol)
{
printf("create_instag(accountname=\"%s\", protocol=\"%s\")\n", accountname, protocol);
char *filename = malloc(snprintf(NULL, 0, "instag_%s.txt", accountname) + 1);
sprintf(filename, "instag_%s.txt", accountname);
otrl_instag_generate(get_userstate(accountname), filename, accountname, protocol);
}
static void convert_msg(void *opdata, ConnContext *context, OtrlConvertType convert_type, char **dest, const char *src)
{
printf("convert_msg\n");
}
static void convert_free(void *opdata, ConnContext *context, char *dest)
{
printf("convert_free\n");
}
OtrlMessageAppOps ui_ops = {
policy_cb,
create_privkey_cb,
is_logged_in_cb,
inject_message_cb,
update_context_list_cb,
new_fingerprint_cb,
write_fingerprints_cb,
gone_secure_cb,
gone_insecure_cb,
still_secure_cb,
max_message_size_cb,
account_name_cb,
account_name_free_cb,
received_symkey_cb,
otr_error_message_cb,
otr_error_message_free_cb,
resent_msg_prefix_cb,
resent_msg_prefix_free_cb,
handle_smp_event_cb,
handle_msg_event_cb,
create_instag,
convert_msg,
convert_free
};
int main() {
OTRL_INIT;
tst1_userstate = otrl_userstate_create();
tst2_userstate = otrl_userstate_create();
otrl_privkey_read(get_userstate("tst1"), "keys_tst1.txt");
otrl_privkey_read(get_userstate("tst2"), "keys_tst2.txt");
otrl_privkey_read_fingerprints(get_userstate("tst1"), "fingerprints1.txt",
NULL, NULL);
otrl_privkey_read_fingerprints(get_userstate("tst2"), "fingerprints2.txt",
NULL, NULL);
gcry_error_t err;
int ignore_message; // if a message is protocol intern this gets true and msg can be ignored by the client
// otrl_privkey_generate(get_userstate("tst2"), "keys1.txt", "tst1", "xmpp");
char *msg1_plain = "message 1";
char *msg1_crypt = NULL;
char *msg1_decrypt = NULL;
printf("sending\n");
err = otrl_message_sending(
get_userstate("tst1"),
&ui_ops,
NULL,
"tst1",
"xmpp",
"tst2",
OTRL_INSTAG_BEST,
msg1_plain,
NULL,
&msg1_crypt,
OTRL_FRAGMENT_SEND_SKIP,
NULL,
NULL,
NULL
);
if (!err == GPG_ERR_NO_ERROR) {
printf("something went wrong during encrypting\n");
}
/*
it seems like the first message is not encrypted at first
but if you look closely, you will notice that there is a
0x2092020999920920920920202020992020920202099202099
attached to the end of it. printf just returns
empty spaces for that, so you have print the hex
version of it
*/
PRINT(msg1_plain);
PRINT(msg1_crypt);
printf("receiving\n");
ignore_message = otrl_message_receiving(
get_userstate("tst2"),
&ui_ops,
NULL,
"tst2",
"xmpp",
"tst1",
msg1_crypt,
&msg1_decrypt,
NULL,
NULL,
NULL,
NULL
);
printf("msg_1_decrypt = '%s'\n", msg1_decrypt);
char* msg2_plain = "this schould be OTR stuff jessss:)!!!!!:))))))";
char* msg2_crypt = NULL;
char* msg2_decrypt = NULL;
err = otrl_message_sending(
get_userstate("tst1"),
&ui_ops,
NULL,
"tst1",
"xmpp",
"tst2",
OTRL_INSTAG_BEST,
msg2_plain,
NULL,
&msg2_crypt,
OTRL_FRAGMENT_SEND_SKIP,
NULL,
NULL,
NULL
);
if (!err == GPG_ERR_NO_ERROR) {
printf("something went wrong during encrypting\n");
}
PRINT(msg2_plain);
PRINT(msg2_crypt);
ignore_message = otrl_message_receiving(
get_userstate("tst2"),
&ui_ops,
NULL,
"tst2",
"xmpp",
"tst1",
msg2_crypt,
&msg2_decrypt,
NULL,
NULL,
NULL,
NULL
);
printf("msg2_decrypt = %s\n", msg2_decrypt);
return 0;
}
all: example
example: example.c
gcc example.c -lotr -o example
.PHONY: clean
clean:
rm -f example
run: example
./example
@txdv
Copy link

txdv commented Aug 20, 2015

Can you maybe help me and tell me how one does generate a 'keys_tst1.txt'. The documentation file says DSA key, but when I generate one and give to the readfile function it just complains "Invalid length specifier in S-expression".

This is the function I am using:

ssh-keygen -t dsa -b 1024 -C "otr2"

@mhanne
Copy link
Author

mhanne commented Mar 23, 2016

Awesome, you updated it to the new library version :D

There's no need to generate the privkeys via an external program (I guess you figured that part out). OTR will call the create_privkey callback when it needs a privkey and doesn't have one. So we can just call otrl_privkey_generate from there.

Same thing goes for instags; now that it is generating one when requested, it can successfully establish an encrypted session again.

@jeroen
Copy link

jeroen commented Dec 18, 2016

I think you're missing some parentheses:

example.c:277:7: warning: logical not is only applied to the left hand side of this comparison [-Wlogical-not-parentheses]
  if (!err == GPG_ERR_NO_ERROR) {
      ^    ~~
example.c:277:7: note: add parentheses after the '!' to evaluate the comparison first
  if (!err == GPG_ERR_NO_ERROR) {
      ^
       (                      )
example.c:277:7: note: add parentheses around left hand side expression to silence this warning
  if (!err == GPG_ERR_NO_ERROR) {
      ^
      (   )
example.c:330:7: warning: logical not is only applied to the left hand side of this comparison [-Wlogical-not-parentheses]
  if (!err == GPG_ERR_NO_ERROR) {
      ^    ~~
example.c:330:7: note: add parentheses after the '!' to evaluate the comparison first
  if (!err == GPG_ERR_NO_ERROR) {
      ^
       (                      )
example.c:330:7: note: add parentheses around left hand side expression to silence this warning
  if (!err == GPG_ERR_NO_ERROR) {
      ^
      (   )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment