summaryrefslogtreecommitdiff
path: root/src/skey/sha1.c
blob: d1c57d11391110c1b4e5d2dffb462de45c9d7d70 (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
#include <config.h>

#include <string.h>
#include <stdlib.h>
#include <arpa/inet.h>

#include <glib.h>

#include "skey.h"
#include "skeyutil.h"
#include "sha1.h"


#define SHA1_DIGESTSIZE       20
#define SHA1_BLOCKSIZE        64

#define HTONDIGEST(x) { \
      x[0] = htonl(x[0]); \
      x[1] = htonl(x[1]); \
      x[2] = htonl(x[2]); \
      x[3] = htonl(x[3]); \
      x[4] = htonl(x[4]); }

#ifdef WORDS_BIGENDIAN
/*
 * Note: this code is harmless on little-endian machines.
 */
static void byteReverse(unsigned char *buf, unsigned longs)
{
	guint32 t;
	do
	{
		t = (guint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
		    ((unsigned) buf[1] << 8 | buf[0]);
		*(guint32 *) buf = t;
		buf += 4;
	}
	while (--longs);
}
#endif


int SHA1Keycrunch(char *result, const char *seed, const char *passphrase)
{
	char *buf;
	gsize len;
	GChecksum *checksum;
	guint8 digest[20];
	gsize digest_len = sizeof (digest);
	guint32 *results;

	len = strlen(seed) + strlen(passphrase);
	if ((buf = (char *)g_try_malloc(len+1)) == NULL)
		return -1;

	strcpy(buf, seed);
	skey_lowcase(buf);
	strcat(buf, passphrase);
	skey_sevenbit(buf);

	checksum = g_checksum_new (G_CHECKSUM_SHA1);
	g_checksum_update (checksum, (const guchar *) buf, len);
	g_free(buf);

	g_checksum_get_digest (checksum, digest, &digest_len);
	g_assert (digest_len == 20);

	results = (guint32 *) digest;

#ifndef WORDS_BIGENDIAN
	HTONDIGEST(results);
#else
	byteReverse((unsigned char *)digest, 5);
#endif

	results = (guint32 *) digest;
	results[0] ^= results[2];
	results[1] ^= results[3];
	results[0] ^= results[4];

	memcpy((void *)result, (void *)results, SKEY_SIZE);

	g_checksum_free (checksum);

	return 0;
}

void SHA1SKey(char *x)
{
	GChecksum *checksum;
	guint8 digest[20];
	gsize digest_len = sizeof (digest);
	guint32 *results;

	checksum = g_checksum_new (G_CHECKSUM_SHA1);
	g_checksum_update (checksum, (const guchar *) x, SKEY_SIZE);
	g_checksum_get_digest (checksum, digest, &digest_len);
	g_assert (digest_len == 20);

	results = (guint32 *) digest;
#ifndef WORDS_BIGENDIAN
	HTONDIGEST(results);
#else
	byteReverse((unsigned char *)digest, 5);
#endif

	results[0] ^= results[2];
	results[1] ^= results[3];
	results[0] ^= results[4];

	memcpy((void *)x, (void *)results, SKEY_SIZE);

	g_checksum_free (checksum);
}