keyhook.c
author Ryan C. Gordon <icculus@icculus.org>
Fri, 23 Jun 2017 17:28:03 -0400
changeset 58 1390348facc7
parent 48 5b2b972c5078
permissions -rw-r--r--
Command line tool that decrypts an OPVault keychain and dumps it to stdout.

To compile: gcc -o opvault opvault.c cJSON.c -lcrypto

Usage: ./opvault </path/to/mykeychain.opvault> <password>

This is just a proof of concept; I'll be recycling this into proper OPVault
support in 1pass later and deleting this tool.

This uses OpenSSL's libcrypto for the math instead of all the homegrown
crypto this project is otherwise using. I'll probably migrate the rest in
this direction, too, since this wasn't as bad as I expected to use and
gets you all the package-manager mojo of automatic bug fixes and security
patches and shared code, etc.

cJSON parses JSON in C. That is from https://github.com/DaveGamble/cJSON

An example OPVault keychain from AgileBits is available here:

https://cache.agilebits.com/security-kb/
icculus@17
     1
// !!! FIXME: this is X11 specific.  :(
icculus@17
     2
icculus@17
     3
#include <stdio.h>
icculus@45
     4
icculus@45
     5
#if 1
icculus@17
     6
#include <stdlib.h>
icculus@17
     7
#include <string.h>
icculus@17
     8
#include <pthread.h>
icculus@17
     9
#include <unistd.h>
icculus@17
    10
icculus@17
    11
#include <X11/Xlib.h>
icculus@17
    12
#include <X11/Xlibint.h>
icculus@17
    13
#include <X11/extensions/record.h>
icculus@17
    14
icculus@17
    15
#include "keyhook.h"
icculus@17
    16
icculus@17
    17
static volatile int keyPressFlags = 0;
icculus@17
    18
static volatile int sawKeyCombo = 0;
icculus@17
    19
static void keyhookCallback(XPointer priv, XRecordInterceptData *data)
icculus@17
    20
{
icculus@17
    21
    const xEvent *xev = (const xEvent *) data->data;
icculus@17
    22
    if (data->category == XRecordFromServer)
icculus@17
    23
    {
icculus@17
    24
        if (xev->u.u.type == KeyPress)
icculus@17
    25
        {
icculus@48
    26
            const BYTE keycode = xev->u.u.detail;
icculus@48
    27
icculus@48
    28
            //printf("Pressed X11 keycode %u\n", (unsigned int) keycode);
icculus@48
    29
icculus@17
    30
            // !!! FIXME: don't hardcode these keycodes.
icculus@17
    31
            if ((keycode == 64) && (keyPressFlags == 0))
icculus@17
    32
                keyPressFlags++;
icculus@17
    33
            else if ((keycode == 133) && (keyPressFlags == 1))
icculus@17
    34
                keyPressFlags++;
icculus@17
    35
            else if ((keycode == 51) && (keyPressFlags == 2))
icculus@17
    36
            {
icculus@17
    37
                sawKeyCombo = 1;
icculus@17
    38
                keyPressFlags = 0;
icculus@17
    39
            } // else if
icculus@17
    40
            else
icculus@17
    41
                keyPressFlags = 0;
icculus@17
    42
        } // if
icculus@17
    43
        else if (xev->u.u.type == KeyRelease)
icculus@17
    44
        {
icculus@17
    45
            keyPressFlags = 0;
icculus@17
    46
        } // else if
icculus@17
    47
    } // if
icculus@17
    48
icculus@17
    49
    XRecordFreeData(data);
icculus@17
    50
} // keyhookCallback
icculus@17
    51
icculus@17
    52
icculus@17
    53
// every example I've seen needs two Display connections...one for the
icculus@17
    54
//  keyhook, and one to control it.
icculus@17
    55
static Display *ctrldpy = NULL;
icculus@17
    56
static Display *datadpy = NULL;
icculus@17
    57
static XRecordContext xrc = 0;
icculus@17
    58
icculus@17
    59
int initKeyHook(void)
icculus@17
    60
{
icculus@17
    61
    int major = 0;
icculus@17
    62
    int minor = 0;
icculus@17
    63
    XRecordRange *xrr = NULL;
icculus@17
    64
    XRecordClientSpec xrcs = XRecordAllClients;
icculus@17
    65
icculus@17
    66
    if (ctrldpy)
icculus@17
    67
        return 0;  // already initialized.
icculus@17
    68
icculus@17
    69
    ctrldpy = XOpenDisplay(NULL);
icculus@17
    70
    if (!ctrldpy)
icculus@17
    71
        goto failed;
icculus@17
    72
icculus@17
    73
    XSynchronize(ctrldpy, True);
icculus@17
    74
icculus@17
    75
    datadpy = XOpenDisplay(NULL);
icculus@17
    76
    if (!datadpy)
icculus@17
    77
        goto failed;
icculus@17
    78
    else if (!XRecordQueryVersion(ctrldpy, &major, &minor))
icculus@17
    79
        goto failed;
icculus@17
    80
    else if ((xrr = XRecordAllocRange()) == NULL)
icculus@17
    81
        goto failed;
icculus@17
    82
icculus@17
    83
    memset(xrr, '\0', sizeof (*xrr));
icculus@17
    84
    xrr->device_events.first = KeyPress;
icculus@17
    85
    xrr->device_events.last = KeyPress;
icculus@17
    86
icculus@17
    87
    if ((xrc = XRecordCreateContext(ctrldpy, 0, &xrcs, 1, &xrr, 1)) == 0)
icculus@17
    88
        goto failed;
icculus@17
    89
    else if (!XRecordEnableContextAsync(datadpy, xrc, keyhookCallback, NULL))
icculus@17
    90
        goto failed;
icculus@17
    91
icculus@17
    92
    XFree(xrr);
icculus@17
    93
    xrr = NULL;
icculus@17
    94
icculus@17
    95
    return 1;
icculus@17
    96
icculus@17
    97
failed:
icculus@17
    98
    deinitKeyHook();
icculus@17
    99
    if (xrr) XFree(xrr);
icculus@17
   100
icculus@17
   101
    return 0;
icculus@17
   102
} // initKeyHook
icculus@17
   103
icculus@17
   104
icculus@17
   105
void deinitKeyHook(void)
icculus@17
   106
{
icculus@17
   107
    if (ctrldpy)
icculus@17
   108
    {
icculus@17
   109
        if (xrc)
icculus@17
   110
        {
icculus@17
   111
            XRecordDisableContext(ctrldpy, xrc);
icculus@17
   112
            XRecordFreeContext(ctrldpy, xrc);
icculus@17
   113
        } // if
icculus@17
   114
        XCloseDisplay(ctrldpy);
icculus@17
   115
    } // if
icculus@17
   116
icculus@17
   117
    if (datadpy)
icculus@17
   118
        XCloseDisplay(datadpy);
icculus@17
   119
icculus@17
   120
    ctrldpy = NULL;
icculus@17
   121
    datadpy = NULL;
icculus@17
   122
    xrc = 0;
icculus@17
   123
    sawKeyCombo = 0;
icculus@17
   124
    keyPressFlags = 0;
icculus@17
   125
} // deinitKeyHook
icculus@17
   126
icculus@17
   127
icculus@17
   128
int pumpKeyHook(void)
icculus@17
   129
{
icculus@17
   130
    if (!datadpy)
icculus@17
   131
        return 0;
icculus@17
   132
icculus@17
   133
    sawKeyCombo = 0;
icculus@17
   134
    XRecordProcessReplies(datadpy);
icculus@17
   135
    return sawKeyCombo;
icculus@17
   136
} // pumpKeyHook
icculus@17
   137
icculus@45
   138
#else
icculus@45
   139
icculus@45
   140
int initKeyHook(void) { return 1; }
icculus@45
   141
void deinitKeyHook(void) {}
icculus@45
   142
icculus@45
   143
int pumpKeyHook(void)
icculus@45
   144
{
icculus@45
   145
static int x = 50;
icculus@45
   146
const int retval = (x == 50);
icculus@45
   147
if (++x > 50) x = 0;
icculus@45
   148
if (retval) printf("fire it!\n");
icculus@45
   149
return retval;
icculus@45
   150
}
icculus@45
   151
icculus@45
   152
#endif
icculus@45
   153
icculus@17
   154
// end of keyhook.c ...
icculus@17
   155