Last active
May 9, 2020 07:02
-
-
Save mhanne/1630071 to your computer and use it in GitHub Desktop.
libotr usage example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
all: example | |
example: example.c | |
gcc example.c -lotr -o example | |
.PHONY: clean | |
clean: | |
rm -f example | |
run: example | |
./example |
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.
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
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"