1/*
2 * Copyright (c) 1995 - 2003 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the Institute nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#define HC_DEPRECATED_CRYPTO
35
36#include "config.h"
37
38#include "otp_locl.h"
39
40#include "otp_md.h"
41#include "crypto-headers.h"
42
43/*
44 * Compress len bytes from md into key
45 */
46
47static void
48compressmd (OtpKey key, unsigned char *md, size_t len)
49{
50    u_char *p = key;
51
52    memset (p, 0, OTPKEYSIZE);
53    while(len) {
54	*p++ ^= *md++;
55	*p++ ^= *md++;
56	*p++ ^= *md++;
57	*p++ ^= *md++;
58	len -= 4;
59	if (p == key + OTPKEYSIZE)
60	    p = key;
61    }
62}
63
64/*
65 * For histerical reasons, in the OTP definition it's said that
66 * the result from SHA must be stored in little-endian order.  See
67 * draft-ietf-otp-01.txt.
68 */
69
70static void
71little_endian(unsigned char *res, size_t len)
72{
73    unsigned char t;
74    size_t i;
75
76    for (i = 0; i < len; i += 4) {
77	t = res[i + 0]; res[i + 0] = res[i + 3]; res[i + 3] = t;
78	t = res[i + 1]; res[i + 1] = res[i + 2]; res[i + 2] = t;
79    }
80}
81
82static int
83otp_md_init (OtpKey key,
84	     const char *pwd,
85	     const char *seed,
86	     const EVP_MD *md,
87	     int le,
88	     unsigned char *res,
89	     size_t ressz)
90{
91    EVP_MD_CTX *ctx;
92    char *p;
93    int len;
94
95    ctx = EVP_MD_CTX_create();
96
97    len = strlen(pwd) + strlen(seed);
98    p = malloc (len + 1);
99    if (p == NULL)
100	return -1;
101    strlcpy (p, seed, len + 1);
102    strlwr (p);
103    strlcat (p, pwd, len + 1);
104
105    EVP_DigestInit_ex(ctx, md, NULL);
106    EVP_DigestUpdate(ctx, p, len);
107    EVP_DigestFinal_ex(ctx, res, NULL);
108
109    EVP_MD_CTX_destroy(ctx);
110
111    if (le)
112    	little_endian(res, ressz);
113
114    free (p);
115    compressmd (key, res, ressz);
116    return 0;
117}
118
119static int
120otp_md_next (OtpKey key,
121	     const EVP_MD *md,
122	     int le,
123	     unsigned char *res,
124	     size_t ressz)
125{
126    EVP_MD_CTX *ctx;
127
128    ctx = EVP_MD_CTX_create();
129
130    EVP_DigestInit_ex(ctx, md, NULL);
131    EVP_DigestUpdate(ctx, key, OTPKEYSIZE);
132    EVP_DigestFinal_ex(ctx, res, NULL);
133
134    EVP_MD_CTX_destroy(ctx);
135
136    if (le)
137	little_endian(res, ressz);
138
139    compressmd (key, res, ressz);
140    return 0;
141}
142
143static int
144otp_md_hash (const char *data,
145	     size_t len,
146	     const EVP_MD *md,
147	     int le,
148	     unsigned char *res,
149	     size_t ressz)
150{
151    EVP_MD_CTX *ctx;
152    ctx = EVP_MD_CTX_create();
153
154    EVP_DigestInit_ex(ctx, md, NULL);
155    EVP_DigestUpdate(ctx, data, len);
156    EVP_DigestFinal_ex(ctx, res, NULL);
157
158    EVP_MD_CTX_destroy(ctx);
159
160    if (le)
161	little_endian(res, ressz);
162
163    return 0;
164}
165
166int
167otp_md4_init (OtpKey key, const char *pwd, const char *seed)
168{
169  unsigned char res[16];
170  return otp_md_init (key, pwd, seed, EVP_md4(), 0, res, sizeof(res));
171}
172
173int
174otp_md4_hash (const char *data,
175	      size_t len,
176	      unsigned char *res)
177{
178  return otp_md_hash (data, len, EVP_md4(), 0, res, 16);
179}
180
181int
182otp_md4_next (OtpKey key)
183{
184  unsigned char res[16];
185  return otp_md_next (key, EVP_md4(), 0, res, sizeof(res));
186}
187
188
189int
190otp_md5_init (OtpKey key, const char *pwd, const char *seed)
191{
192  unsigned char res[16];
193  return otp_md_init (key, pwd, seed, EVP_md5(), 0, res, sizeof(res));
194}
195
196int
197otp_md5_hash (const char *data,
198	      size_t len,
199	      unsigned char *res)
200{
201  return otp_md_hash (data, len, EVP_md5(), 0, res, 16);
202}
203
204int
205otp_md5_next (OtpKey key)
206{
207  unsigned char res[16];
208  return otp_md_next (key, EVP_md5(), 0, res, sizeof(res));
209}
210
211int
212otp_sha_init (OtpKey key, const char *pwd, const char *seed)
213{
214  unsigned char res[20];
215  return otp_md_init (key, pwd, seed, EVP_sha1(), 1, res, sizeof(res));
216}
217
218int
219otp_sha_hash (const char *data,
220	      size_t len,
221	      unsigned char *res)
222{
223  return otp_md_hash (data, len, EVP_sha1(), 1, res, 20);
224}
225
226int
227otp_sha_next (OtpKey key)
228{
229  unsigned char res[20];
230  return otp_md_next (key, EVP_sha1(), 1, res, sizeof(res));
231}
232