2095
2097
/* Extract LENGTH bits from the char array S starting with bit number
2097
static unsigned long
2098
extract (const char *s, int start, int length)
2098
START. It always reads three consecutive octects, which means it
2099
can read past end of data when START is at the edge of the region. */
2102
extract (const unsigned char *s, int start, int length)
2100
2104
unsigned char cl = s[start / 8];
2101
2105
unsigned char cc = s[start / 8 + 1];
2102
2106
unsigned char cr = s[start / 8 + 2];
2103
unsigned long x = ((long)(cl << 8 | cc) << 8 | cr);
2105
x = x >> (24 - (length + (start % 8)));
2106
x = (x & (0xffff >> (16 - length)));
2108
x = (uint32_t)(cl << 8 | cc) << 8 | cr;
2109
x >>= 24 - (length + (start % 8));
2110
x &= (0xffff >> (16 - length));
2110
#define STRLEN4(s) (!*(s) ? 0 : \
2113
(!*(s + 3) ? 3 : 4))))
2114
/* Length of a string known to be at least 1 and at most 4 chars
2117
#define STRLEN_1_4(s) (!(s)[1] ? 1 : !(s)[2] ? 2 : !(s)[3] ? 3 : 4)
2115
2119
/* Encode 8 bytes in C as a string of English words and store them to
2116
2120
STORE. Returns STORE. */
2118
btoe (char *store, const char *c)
2123
btoe (char *store, const unsigned char *c)
2120
char cp[10]; /* add in room for the parity 2 bits +
2125
unsigned char cp[10]; /* add in room for the parity 2 bits +
2121
2126
extract() slop. */
2123
char *ostore = store;
2128
char *store_beg = store;
2126
2132
/* Workaround for extract() reads beyond end of data */
2127
memset (cp, 0, sizeof(cp));
2128
2134
memcpy (cp, c, 8);
2129
/* Compute parity. */
2136
/* Compute parity and append it to CP. */
2130
2137
for (p = 0, i = 0; i < 64; i += 2)
2131
2138
p += extract (cp, i, 2);
2133
2139
cp[8] = (char)p << 6;
2141
/* The 64 bits of input and the two parity bits comprise 66 bits of
2142
data that are now in CP. We convert that information, 11 bits at
2143
a time, to English words indexed from Wp. Since there are 2048
2144
(2^11) words in Wp, every 11-bit combination corresponds to a
2134
2146
memcpy (store, &Wp[extract (cp, 0, 11)][0], 4);
2135
store += STRLEN4 (store);
2147
store += STRLEN_1_4 (store);
2136
2148
*store++ = ' ';
2137
2149
memcpy (store, &Wp[extract (cp, 11, 11)][0], 4);
2138
store += STRLEN4 (store);
2150
store += STRLEN_1_4 (store);
2139
2151
*store++ = ' ';
2140
2152
memcpy (store, &Wp[extract (cp, 22, 11)][0], 4);
2141
store += STRLEN4 (store);
2153
store += STRLEN_1_4 (store);
2142
2154
*store++ = ' ';
2143
2155
memcpy (store, &Wp[extract (cp, 33, 11)][0], 4);
2144
store += STRLEN4 (store);
2156
store += STRLEN_1_4 (store);
2145
2157
*store++ = ' ';
2146
2158
memcpy (store, &Wp[extract (cp, 44, 11)][0], 4);
2147
store += STRLEN4 (store);
2159
store += STRLEN_1_4 (store);
2148
2160
*store++ = ' ';
2149
2161
memcpy (store, &Wp[extract (cp, 55, 11)][0], 4);
2151
store[4] = '\0'; /* make sure the string is zero-terminated */
2153
DEBUGP (("store is `%s'\n", ostore));
2162
store[4] = '\0'; /* make sure the string is terminated */
2164
DEBUGP (("wrote `%s' to STORE\n", store_beg));
2158
/* #### Document me! */
2168
/* Calculate the SKEY response, based on the sequence, seed
2169
(challenge), and the secret password. The calculated response is
2170
used instead of the real password when logging in to SKEY-enabled
2173
The result is calculated like this:
2175
+ Concatenate SEED and PASS and calculate the 16-byte MD5 checksum.
2177
+ Shorten the checksum to eight bytes by folding the second eight
2178
bytes onto the first eight using XOR. The resulting eight-byte
2179
sequence is the key.
2181
+ MD5-process the key, fold the checksum to eight bytes and store
2182
it back to the key. Repeat this crunching SEQUENCE times.
2183
(Sequence is a number that gets decremented every time the user
2184
logs in to the server. Therefore an eavesdropper would have to
2185
invert the hash function in order to guess the next one-time
2188
+ Convert the resulting 64-bit key to 6 English words separated by
2189
spaces (see btoe for details) and return the resulting ASCII
2192
All this is described in section 6 of rfc2289 in more detail. */
2160
calculate_skey_response (int sequence, const char *seed, const char *pass)
2195
skey_response (int sequence, const char *seed, const char *pass)
2163
static char buf[33];
2165
ALLOCA_MD5_CONTEXT (ctx);
2166
unsigned long results[4]; /* #### this looks 32-bit-minded */
2167
char *feed = (char *) alloca (strlen (seed) + strlen (pass) + 1);
2169
strcpy (feed, seed);
2170
strcat (feed, pass);
2173
gen_md5_update ((unsigned char *)feed, strlen (feed), ctx);
2174
gen_md5_finish (ctx, (unsigned char *)results);
2176
results[0] ^= results[2];
2177
results[1] ^= results[3];
2178
memcpy (key, (char *) results, 8);
2180
while (0 < sequence--)
2197
unsigned char key[8];
2199
/* Room to hold 6 four-letter words (heh), 5 space separators, and
2200
the terminating \0. 24+5+1 == 30 */
2201
static char english[30];
2203
ALLOCA_MD5_CONTEXT (md5_ctx);
2204
uint32_t checksum[4];
2206
gen_md5_init (md5_ctx);
2207
gen_md5_update ((const unsigned char *)seed, strlen(seed), md5_ctx);
2208
gen_md5_update ((const unsigned char *)pass, strlen(pass), md5_ctx);
2209
gen_md5_finish (md5_ctx, (unsigned char *)checksum);
2210
checksum[0] ^= checksum[2];
2211
checksum[1] ^= checksum[3];
2212
memcpy (key, checksum, 8);
2214
while (sequence-- > 0)
2183
gen_md5_update ((unsigned char *)key, 8, ctx);
2184
gen_md5_finish (ctx, (unsigned char *)results);
2185
results[0] ^= results[2];
2186
results[1] ^= results[3];
2187
memcpy (key, (char *) results, 8);
2216
gen_md5_init (md5_ctx);
2217
gen_md5_update ((unsigned char *) key, 8, md5_ctx);
2218
gen_md5_finish (md5_ctx, (unsigned char *) checksum);
2219
checksum[0] ^= checksum[2];
2220
checksum[1] ^= checksum[3];
2221
memcpy (key, checksum, 8);
2223
return btoe (english, key);