1 |
|
|
/* $OpenBSD: chap_ms.c,v 1.9 2015/08/21 11:59:27 reyk Exp $ */ |
2 |
|
|
|
3 |
|
|
/* |
4 |
|
|
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org> |
5 |
|
|
* Copyright (c) 1997-2001 Brian Somers <brian@Awfulhak.org> |
6 |
|
|
* Copyright (c) 1997 Gabor Kincses <gabor@acm.org> |
7 |
|
|
* Copyright (c) 1995 Eric Rosenquist |
8 |
|
|
* |
9 |
|
|
* All rights reserved. |
10 |
|
|
* |
11 |
|
|
* Redistribution and use in source and binary forms, with or without |
12 |
|
|
* modification, are permitted provided that the following conditions |
13 |
|
|
* are met: |
14 |
|
|
* 1. Redistributions of source code must retain the above copyright |
15 |
|
|
* notice, this list of conditions and the following disclaimer. |
16 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
17 |
|
|
* notice, this list of conditions and the following disclaimer in the |
18 |
|
|
* documentation and/or other materials provided with the distribution. |
19 |
|
|
* |
20 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
21 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
22 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
23 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
24 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
25 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
26 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
27 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
28 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
29 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
30 |
|
|
* SUCH DAMAGE. |
31 |
|
|
*/ |
32 |
|
|
|
33 |
|
|
#include <sys/types.h> |
34 |
|
|
|
35 |
|
|
#include <ctype.h> |
36 |
|
|
#include <string.h> |
37 |
|
|
#include <stdio.h> |
38 |
|
|
|
39 |
|
|
#include <openssl/evp.h> |
40 |
|
|
#include <openssl/des.h> |
41 |
|
|
#include <openssl/md4.h> |
42 |
|
|
#include <openssl/md5.h> |
43 |
|
|
#include <openssl/sha.h> |
44 |
|
|
|
45 |
|
|
#include "chap_ms.h" |
46 |
|
|
|
47 |
|
|
/* |
48 |
|
|
* Documentation & specifications: |
49 |
|
|
* |
50 |
|
|
* MS-CHAP (CHAP80) RFC2433 |
51 |
|
|
* MS-CHAP-V2 (CHAP81) RFC2759 |
52 |
|
|
* MPPE key management RFC3079 |
53 |
|
|
* |
54 |
|
|
* Security analysis: |
55 |
|
|
* Schneier/Mudge/Wagner, "MS-CHAP-v2", Oct 99 |
56 |
|
|
* "It is unclear to us why this protocol is so complicated." |
57 |
|
|
*/ |
58 |
|
|
|
59 |
|
|
static uint8_t sha1_pad1[40] = { |
60 |
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
61 |
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
62 |
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
63 |
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 |
64 |
|
|
}; |
65 |
|
|
|
66 |
|
|
static uint8_t sha1_pad2[40] = { |
67 |
|
|
0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, |
68 |
|
|
0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, |
69 |
|
|
0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, |
70 |
|
|
0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 |
71 |
|
|
}; |
72 |
|
|
|
73 |
|
|
uint8_t get7bits(uint8_t *, int); |
74 |
|
|
void mschap_des_addparity(uint8_t *, uint8_t *); |
75 |
|
|
void mschap_des_encrypt(uint8_t *, uint8_t *, uint8_t *); |
76 |
|
|
void mschap_challenge_response(uint8_t *, uint8_t *, uint8_t *); |
77 |
|
|
|
78 |
|
|
uint8_t |
79 |
|
|
get7bits(uint8_t *in, int start) |
80 |
|
|
{ |
81 |
|
|
unsigned int word; |
82 |
|
|
|
83 |
|
|
word = (unsigned int)in[start / 8] << 8; |
84 |
|
|
word |= (unsigned int)in[start / 8 + 1]; |
85 |
|
|
word >>= 15 - (start % 8 + 7); |
86 |
|
|
|
87 |
|
|
return (word & 0xfe); |
88 |
|
|
} |
89 |
|
|
|
90 |
|
|
/* IN 56 bit DES key missing parity bits |
91 |
|
|
OUT 64 bit DES key with parity bits added */ |
92 |
|
|
void |
93 |
|
|
mschap_des_addparity(uint8_t *key, uint8_t *des_key) |
94 |
|
|
{ |
95 |
|
|
des_key[0] = get7bits(key, 0); |
96 |
|
|
des_key[1] = get7bits(key, 7); |
97 |
|
|
des_key[2] = get7bits(key, 14); |
98 |
|
|
des_key[3] = get7bits(key, 21); |
99 |
|
|
des_key[4] = get7bits(key, 28); |
100 |
|
|
des_key[5] = get7bits(key, 35); |
101 |
|
|
des_key[6] = get7bits(key, 42); |
102 |
|
|
des_key[7] = get7bits(key, 49); |
103 |
|
|
|
104 |
|
|
DES_set_odd_parity((DES_cblock *)des_key); |
105 |
|
|
} |
106 |
|
|
|
107 |
|
|
void |
108 |
|
|
mschap_des_encrypt(uint8_t *clear, uint8_t *key, uint8_t *cipher) |
109 |
|
|
{ |
110 |
|
|
DES_cblock des_key; |
111 |
|
|
DES_key_schedule key_schedule; |
112 |
|
|
|
113 |
|
|
mschap_des_addparity(key, des_key); |
114 |
|
|
|
115 |
|
|
DES_set_key(&des_key, &key_schedule); |
116 |
|
|
DES_ecb_encrypt((DES_cblock *)clear, (DES_cblock *)cipher, |
117 |
|
|
&key_schedule, 1); |
118 |
|
|
} |
119 |
|
|
|
120 |
|
|
void |
121 |
|
|
mschap_challenge_response(uint8_t *challenge, uint8_t *pwhash, |
122 |
|
|
uint8_t *response) |
123 |
|
|
{ |
124 |
|
|
uint8_t padpwhash[21 + 1]; |
125 |
|
|
|
126 |
|
|
bzero(&padpwhash, sizeof(padpwhash)); |
127 |
|
|
memcpy(padpwhash, pwhash, MSCHAP_HASH_SZ); |
128 |
|
|
|
129 |
|
|
mschap_des_encrypt(challenge, padpwhash + 0, response + 0); |
130 |
|
|
mschap_des_encrypt(challenge, padpwhash + 7, response + 8); |
131 |
|
|
mschap_des_encrypt(challenge, padpwhash + 14, response + 16); |
132 |
|
|
} |
133 |
|
|
|
134 |
|
|
void |
135 |
|
|
mschap_ntpassword_hash(uint8_t *in, int inlen, uint8_t *hash) |
136 |
|
|
{ |
137 |
|
|
EVP_MD_CTX ctx; |
138 |
|
|
unsigned int mdlen; |
139 |
|
|
|
140 |
|
|
EVP_DigestInit(&ctx, EVP_md4()); |
141 |
|
|
EVP_DigestUpdate(&ctx, in, inlen); |
142 |
|
|
EVP_DigestFinal(&ctx, hash, &mdlen); |
143 |
|
|
} |
144 |
|
|
|
145 |
|
|
void |
146 |
|
|
mschap_challenge_hash(uint8_t *peer_challenge, uint8_t *auth_challenge, |
147 |
|
|
uint8_t *username, int usernamelen, uint8_t *challenge) |
148 |
|
|
{ |
149 |
|
|
EVP_MD_CTX ctx; |
150 |
|
|
uint8_t md[SHA_DIGEST_LENGTH]; |
151 |
|
|
unsigned int mdlen; |
152 |
|
|
uint8_t *name; |
153 |
|
|
|
154 |
|
|
if ((name = strrchr(username, '\\')) == NULL) |
155 |
|
|
name = username; |
156 |
|
|
else |
157 |
|
|
name++; |
158 |
|
|
|
159 |
|
|
EVP_DigestInit(&ctx, EVP_sha1()); |
160 |
|
|
EVP_DigestUpdate(&ctx, peer_challenge, MSCHAPV2_CHALLENGE_SZ); |
161 |
|
|
EVP_DigestUpdate(&ctx, auth_challenge, MSCHAPV2_CHALLENGE_SZ); |
162 |
|
|
EVP_DigestUpdate(&ctx, name, strlen(name)); |
163 |
|
|
EVP_DigestFinal(&ctx, md, &mdlen); |
164 |
|
|
|
165 |
|
|
memcpy(challenge, md, MSCHAP_CHALLENGE_SZ); |
166 |
|
|
} |
167 |
|
|
|
168 |
|
|
void |
169 |
|
|
mschap_nt_response(uint8_t *auth_challenge, uint8_t *peer_challenge, |
170 |
|
|
uint8_t *username, int usernamelen, uint8_t *password, int passwordlen, |
171 |
|
|
uint8_t *response) |
172 |
|
|
{ |
173 |
|
|
uint8_t challenge[MSCHAP_CHALLENGE_SZ]; |
174 |
|
|
uint8_t password_hash[MSCHAP_HASH_SZ]; |
175 |
|
|
|
176 |
|
|
mschap_challenge_hash(peer_challenge, auth_challenge, |
177 |
|
|
username, usernamelen, challenge); |
178 |
|
|
|
179 |
|
|
mschap_ntpassword_hash(password, passwordlen, password_hash); |
180 |
|
|
mschap_challenge_response(challenge, password_hash, response); |
181 |
|
|
} |
182 |
|
|
|
183 |
|
|
void |
184 |
|
|
mschap_auth_response(uint8_t *password, int passwordlen, |
185 |
|
|
uint8_t *ntresponse, uint8_t *auth_challenge, uint8_t *peer_challenge, |
186 |
|
|
uint8_t *username, int usernamelen, uint8_t *auth_response) |
187 |
|
|
{ |
188 |
|
|
EVP_MD_CTX ctx; |
189 |
|
|
uint8_t password_hash[MSCHAP_HASH_SZ]; |
190 |
|
|
uint8_t password_hash2[MSCHAP_HASH_SZ]; |
191 |
|
|
uint8_t challenge[MSCHAP_CHALLENGE_SZ]; |
192 |
|
|
uint8_t md[SHA_DIGEST_LENGTH], *ptr; |
193 |
|
|
unsigned int mdlen; |
194 |
|
|
int i; |
195 |
|
|
const uint8_t hex[] = "0123456789ABCDEF"; |
196 |
|
|
static uint8_t magic1[39] = { |
197 |
|
|
0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76, |
198 |
|
|
0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65, |
199 |
|
|
0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67, |
200 |
|
|
0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 |
201 |
|
|
}; |
202 |
|
|
static uint8_t magic2[41] = { |
203 |
|
|
0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B, |
204 |
|
|
0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F, |
205 |
|
|
0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E, |
206 |
|
|
0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F, |
207 |
|
|
0x6E |
208 |
|
|
}; |
209 |
|
|
|
210 |
|
|
mschap_ntpassword_hash(password, passwordlen, password_hash); |
211 |
|
|
mschap_ntpassword_hash(password_hash, MSCHAP_HASH_SZ, password_hash2); |
212 |
|
|
|
213 |
|
|
EVP_DigestInit(&ctx, EVP_sha1()); |
214 |
|
|
EVP_DigestUpdate(&ctx, password_hash2, sizeof(password_hash2)); |
215 |
|
|
EVP_DigestUpdate(&ctx, ntresponse, 24); |
216 |
|
|
EVP_DigestUpdate(&ctx, magic1, 39); |
217 |
|
|
EVP_DigestFinal(&ctx, md, &mdlen); |
218 |
|
|
|
219 |
|
|
mschap_challenge_hash(peer_challenge, auth_challenge, |
220 |
|
|
username, usernamelen, challenge); |
221 |
|
|
|
222 |
|
|
EVP_DigestInit(&ctx, EVP_sha1()); |
223 |
|
|
EVP_DigestUpdate(&ctx, md, sizeof(md)); |
224 |
|
|
EVP_DigestUpdate(&ctx, challenge, sizeof(challenge)); |
225 |
|
|
EVP_DigestUpdate(&ctx, magic2, 41); |
226 |
|
|
EVP_DigestFinal(&ctx, md, &mdlen); |
227 |
|
|
|
228 |
|
|
/* |
229 |
|
|
* Encode the value of 'Digest' as "S=" followed by |
230 |
|
|
* 40 ASCII hexadecimal digits and return it in |
231 |
|
|
* AuthenticatorResponse. |
232 |
|
|
* For example, |
233 |
|
|
* "S=0123456789ABCDEF0123456789ABCDEF01234567" |
234 |
|
|
*/ |
235 |
|
|
ptr = auth_response; |
236 |
|
|
*ptr++ = 'S'; |
237 |
|
|
*ptr++ = '='; |
238 |
|
|
for (i = 0; i < SHA_DIGEST_LENGTH; i++) { |
239 |
|
|
*ptr++ = hex[md[i] >> 4]; |
240 |
|
|
*ptr++ = hex[md[i] & 0x0f]; |
241 |
|
|
} |
242 |
|
|
} |
243 |
|
|
|
244 |
|
|
void |
245 |
|
|
mschap_masterkey(uint8_t *password_hash2, uint8_t *ntresponse, |
246 |
|
|
uint8_t *masterkey) |
247 |
|
|
{ |
248 |
|
|
uint8_t md[SHA_DIGEST_LENGTH]; |
249 |
|
|
unsigned int mdlen; |
250 |
|
|
EVP_MD_CTX ctx; |
251 |
|
|
static uint8_t magic1[27] = { |
252 |
|
|
0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, |
253 |
|
|
0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d, |
254 |
|
|
0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 |
255 |
|
|
}; |
256 |
|
|
|
257 |
|
|
EVP_DigestInit(&ctx, EVP_sha1()); |
258 |
|
|
EVP_DigestUpdate(&ctx, password_hash2, MSCHAP_HASH_SZ); |
259 |
|
|
EVP_DigestUpdate(&ctx, ntresponse, 24); |
260 |
|
|
EVP_DigestUpdate(&ctx, magic1, 27); |
261 |
|
|
EVP_DigestFinal(&ctx, md, &mdlen); |
262 |
|
|
|
263 |
|
|
memcpy(masterkey, md, 16); |
264 |
|
|
} |
265 |
|
|
|
266 |
|
|
void |
267 |
|
|
mschap_asymetric_startkey(uint8_t *masterkey, uint8_t *sessionkey, |
268 |
|
|
int sessionkeylen, int issend, int isserver) |
269 |
|
|
{ |
270 |
|
|
EVP_MD_CTX ctx; |
271 |
|
|
uint8_t md[SHA_DIGEST_LENGTH]; |
272 |
|
|
unsigned int mdlen; |
273 |
|
|
uint8_t *s; |
274 |
|
|
static uint8_t magic2[84] = { |
275 |
|
|
0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, |
276 |
|
|
0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, |
277 |
|
|
0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, |
278 |
|
|
0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79, |
279 |
|
|
0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, |
280 |
|
|
0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65, |
281 |
|
|
0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, |
282 |
|
|
0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, |
283 |
|
|
0x6b, 0x65, 0x79, 0x2e |
284 |
|
|
}; |
285 |
|
|
static uint8_t magic3[84] = { |
286 |
|
|
0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, |
287 |
|
|
0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, |
288 |
|
|
0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, |
289 |
|
|
0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, |
290 |
|
|
0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, |
291 |
|
|
0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, |
292 |
|
|
0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, |
293 |
|
|
0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, |
294 |
|
|
0x6b, 0x65, 0x79, 0x2e |
295 |
|
|
}; |
296 |
|
|
|
297 |
|
|
if (issend) |
298 |
|
|
s = isserver ? magic3 : magic2; |
299 |
|
|
else |
300 |
|
|
s = isserver ? magic2 : magic3; |
301 |
|
|
|
302 |
|
|
EVP_DigestInit(&ctx, EVP_sha1()); |
303 |
|
|
EVP_DigestUpdate(&ctx, masterkey, 16); |
304 |
|
|
EVP_DigestUpdate(&ctx, sha1_pad1, 40); |
305 |
|
|
EVP_DigestUpdate(&ctx, s, 84); |
306 |
|
|
EVP_DigestUpdate(&ctx, sha1_pad2, 40); |
307 |
|
|
EVP_DigestFinal(&ctx, md, &mdlen); |
308 |
|
|
|
309 |
|
|
memcpy(sessionkey, md, sessionkeylen); |
310 |
|
|
} |
311 |
|
|
|
312 |
|
|
void |
313 |
|
|
mschap_msk(uint8_t *password, int passwordlen, |
314 |
|
|
uint8_t *ntresponse, uint8_t *msk) |
315 |
|
|
{ |
316 |
|
|
uint8_t password_hash[MSCHAP_HASH_SZ]; |
317 |
|
|
uint8_t password_hash2[MSCHAP_HASH_SZ]; |
318 |
|
|
uint8_t masterkey[MSCHAP_MASTERKEY_SZ]; |
319 |
|
|
uint8_t sendkey[MSCHAP_MASTERKEY_SZ]; |
320 |
|
|
uint8_t recvkey[MSCHAP_MASTERKEY_SZ]; |
321 |
|
|
|
322 |
|
|
mschap_ntpassword_hash(password, passwordlen, password_hash); |
323 |
|
|
mschap_ntpassword_hash(password_hash, MSCHAP_HASH_SZ, password_hash2); |
324 |
|
|
|
325 |
|
|
mschap_masterkey(password_hash2, ntresponse, masterkey); |
326 |
|
|
mschap_asymetric_startkey(masterkey, recvkey, sizeof(recvkey), 0, 1); |
327 |
|
|
mschap_asymetric_startkey(masterkey, sendkey, sizeof(sendkey), 1, 1); |
328 |
|
|
|
329 |
|
|
/* 16 bytes receive key + 16 bytes send key + 32 bytes 0 padding */ |
330 |
|
|
bzero(msk, MSCHAP_MSK_SZ); |
331 |
|
|
memcpy(msk, &recvkey, sizeof(recvkey)); |
332 |
|
|
memcpy(msk + sizeof(recvkey), &sendkey, sizeof(sendkey)); |
333 |
|
|
} |
334 |
|
|
|
335 |
|
|
void |
336 |
|
|
mschap_radiuskey(uint8_t *plain, const uint8_t *crypted, |
337 |
|
|
const uint8_t *authenticator, const uint8_t *secret) |
338 |
|
|
{ |
339 |
|
|
EVP_MD_CTX ctx; |
340 |
|
|
uint8_t b[MD5_DIGEST_LENGTH], p[32]; |
341 |
|
|
unsigned int i, mdlen; |
342 |
|
|
|
343 |
|
|
EVP_DigestInit(&ctx, EVP_md5()); |
344 |
|
|
EVP_DigestUpdate(&ctx, secret, strlen(secret)); |
345 |
|
|
EVP_DigestUpdate(&ctx, authenticator, 16); |
346 |
|
|
EVP_DigestUpdate(&ctx, crypted, 2); |
347 |
|
|
EVP_DigestFinal(&ctx, b, &mdlen); |
348 |
|
|
|
349 |
|
|
for (i = 0; i < mdlen; i++) { |
350 |
|
|
p[i] = b[i] ^ crypted[i+2]; |
351 |
|
|
} |
352 |
|
|
|
353 |
|
|
EVP_DigestInit(&ctx, EVP_md5()); |
354 |
|
|
EVP_DigestUpdate(&ctx, secret, strlen(secret)); |
355 |
|
|
EVP_DigestUpdate(&ctx, crypted + 2, mdlen); |
356 |
|
|
EVP_DigestFinal(&ctx, b, &mdlen); |
357 |
|
|
|
358 |
|
|
for (i = 0; i < mdlen; i++) { |
359 |
|
|
p[i+16] = b[i] ^ crypted[i+18]; |
360 |
|
|
} |
361 |
|
|
|
362 |
|
|
memcpy(plain, p+1, 16); |
363 |
|
|
} |