aboutsummaryrefslogtreecommitdiffstats
path: root/dispass.c
blob: 4f0c88ae78eb9c2f6055fb5dfc7a9cf20e9122bf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include <stdio.h>
#include <string.h>
#include <openssl/sha.h>
#include <openssl/pem.h>
#include <limits.h>

#include "dispass.h"

#define MIN(A, B) ((A) < (B) ? (A) : (B))
#define MAXLEN (SHA512_DIGEST_LENGTH * 2)

static char *
base64encode(const void *data, int len)
{ /* Copied from http://stackoverflow.com/a/16511093/459915 */
    BIO *b64_bio, *mem_bio;
    BUF_MEM *mem_bio_mem_ptr;
    char *ret;

    b64_bio = BIO_new(BIO_f_base64());
    mem_bio = BIO_new(BIO_s_mem());
    BIO_push(b64_bio, mem_bio);
    BIO_set_flags(b64_bio, BIO_FLAGS_BASE64_NO_NL);

    BIO_write(b64_bio, data, len);
    BIO_flush(b64_bio);

    BIO_get_mem_ptr(mem_bio, &mem_bio_mem_ptr);
    BIO_set_close(mem_bio, BIO_NOCLOSE);
    BIO_free_all(b64_bio);

    (*mem_bio_mem_ptr).data[(*mem_bio_mem_ptr).length] = '\0';
    ret = calloc((*mem_bio_mem_ptr).length, sizeof(char));
    strncpy(ret, (*mem_bio_mem_ptr).data, (*mem_bio_mem_ptr).length);
    BUF_MEM_free(mem_bio_mem_ptr);

    return ret;
}

static void
sha512_to_string(unsigned char *data, char *buff)
{
    int i;

    for (i = 0; i < SHA512_DIGEST_LENGTH; i++) {
        char sbuff[3] = { '\0' };
        sprintf(sbuff, "%02x", data[i]);
        strcat(buff, sbuff);
    }
}

static void
rmchar(char rm, char **s)
{
    int i, j = 0;
    char *new;
    size_t len;

    if (!strchr(*s, rm))
        return;

    len = strlen(*s);
    new = calloc(len + 1, sizeof(char));

    for (i = 0; i < len; i++) {
        char c;

        if ((c = (*s)[i]) != rm)
            new[j++] = c;
    }

    strncpy(*s, new, len);
    free(new);
}

char *
dispass1(char *label, char *password, int len, long long unsigned seqno)
{
    unsigned char *d;
    size_t tbufflen = strlen(label) + strlen(password) + 1;
    char *tbuff = calloc(tbufflen, sizeof(char));
    char buff[MAXLEN + 1] = { '\0' };
    char *b64;

    strcat(tbuff, label);
    strcat(tbuff, password);
    d = SHA512((unsigned char *)tbuff, strlen(tbuff), 0);
    free(tbuff);
    sha512_to_string(d, buff);
    b64 = base64encode(buff, strlen(buff));
    b64[MIN(len, MAXLEN)] = '\0';
    rmchar('=', &b64);

    return b64;
}

char *
dispass2(char *label, char *password, int len, long long unsigned seqno)
{
    unsigned char *d;
    char ibuff[300];
    char *tbuff, *b64;
    char buff[MAXLEN + 1] = { '\0' };

    sprintf(ibuff, "%llu", seqno);
    tbuff = calloc(strlen(label) + strlen(ibuff) + strlen(password) + 1,
                   sizeof(char));
    strcat(tbuff, label);
    strcat(tbuff, ibuff);
    strcat(tbuff, password);
    d = SHA512((unsigned char *)tbuff, strlen(tbuff), 0);
    free(tbuff);
    sha512_to_string(d, buff);
    b64 = base64encode(buff, strlen(buff));
    b64[MIN(len, MAXLEN)] = '\0';
    rmchar('=', &b64);

    return b64;
}