libradius: refactor generic RADIUS en-/decryption function to a message method
This commit is contained in:
parent
9aeb6cea4c
commit
15483a6223
|
@ -366,6 +366,67 @@ METHOD(radius_message_t, add, void,
|
|||
this->msg->length = htons(ntohs(this->msg->length) + attribute->length);
|
||||
}
|
||||
|
||||
METHOD(radius_message_t, crypt, bool,
|
||||
private_radius_message_t *this, chunk_t salt, chunk_t in, chunk_t out,
|
||||
chunk_t secret, hasher_t *hasher)
|
||||
{
|
||||
char b[HASH_SIZE_MD5];
|
||||
|
||||
/**
|
||||
* From RFC2548 (encryption):
|
||||
* b(1) = MD5(S + R + A) c(1) = p(1) xor b(1) C = c(1)
|
||||
* b(2) = MD5(S + c(1)) c(2) = p(2) xor b(2) C = C + c(2)
|
||||
* . . .
|
||||
* b(i) = MD5(S + c(i-1)) c(i) = p(i) xor b(i) C = C + c(i)
|
||||
*
|
||||
* P/C = Plain/Crypted => in/out
|
||||
* S = secret
|
||||
* R = authenticator
|
||||
* A = salt
|
||||
*/
|
||||
if (in.len != out.len)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
if (in.len % HASH_SIZE_MD5 || in.len < HASH_SIZE_MD5)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
if (out.ptr != in.ptr)
|
||||
{
|
||||
memcpy(out.ptr, in.ptr, in.len);
|
||||
}
|
||||
/* Preparse seed for first round:
|
||||
* b(1) = MD5(S + R + A) */
|
||||
if (!hasher->get_hash(hasher, secret, NULL) ||
|
||||
!hasher->get_hash(hasher,
|
||||
chunk_from_thing(this->msg->authenticator), NULL) ||
|
||||
!hasher->get_hash(hasher, salt, b))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
while (in.len)
|
||||
{
|
||||
/* p(i) = b(i) xor c(1) */
|
||||
memxor(out.ptr, b, HASH_SIZE_MD5);
|
||||
|
||||
out = chunk_skip(out, HASH_SIZE_MD5);
|
||||
if (out.len)
|
||||
{
|
||||
/* Prepare seed for next round::
|
||||
* b(i) = MD5(S + c(i-1)) */
|
||||
if (!hasher->get_hash(hasher, secret, NULL) ||
|
||||
!hasher->get_hash(hasher,
|
||||
chunk_create(in.ptr, HASH_SIZE_MD5), b))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
in = chunk_skip(in, HASH_SIZE_MD5);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
METHOD(radius_message_t, sign, bool,
|
||||
private_radius_message_t *this, u_int8_t *req_auth, chunk_t secret,
|
||||
hasher_t *hasher, signer_t *signer, rng_t *rng, bool msg_auth)
|
||||
|
@ -563,6 +624,7 @@ static private_radius_message_t *radius_message_create_empty()
|
|||
.get_encoding = _get_encoding,
|
||||
.sign = _sign,
|
||||
.verify = _verify,
|
||||
.crypt = _crypt,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
);
|
||||
|
|
|
@ -284,6 +284,22 @@ struct radius_message_t {
|
|||
bool (*verify)(radius_message_t *this, u_int8_t *req_auth, chunk_t secret,
|
||||
hasher_t *hasher, signer_t *signer);
|
||||
|
||||
/**
|
||||
* Perform RADIUS attribute en-/decryption.
|
||||
*
|
||||
* Performs en-/decryption by XOring the hash-extended secret into data,
|
||||
* as specified in RFC 2865 5.2 and used by RFC 2548.
|
||||
*
|
||||
* @param salt salt to append to message authenticator, if any
|
||||
* @param in data to en-/decrypt, multiple of HASH_SIZE_MD5
|
||||
* @param out en-/decrypted data, length equal to in
|
||||
* @param secret RADIUS secret
|
||||
* @param hasher MD5 hasher
|
||||
* @return TRUE if en-/decryption successful
|
||||
*/
|
||||
bool (*crypt)(radius_message_t *this, chunk_t salt, chunk_t in, chunk_t out,
|
||||
chunk_t secret, hasher_t *hasher);
|
||||
|
||||
/**
|
||||
* Destroy the message.
|
||||
*/
|
||||
|
|
|
@ -233,54 +233,17 @@ METHOD(radius_socket_t, request, radius_message_t*,
|
|||
static chunk_t decrypt_mppe_key(private_radius_socket_t *this, u_int16_t salt,
|
||||
chunk_t C, radius_message_t *request)
|
||||
{
|
||||
chunk_t A, R, P, seed;
|
||||
u_char *c, *p;
|
||||
chunk_t decrypted;
|
||||
|
||||
/**
|
||||
* From RFC2548 (encryption):
|
||||
* b(1) = MD5(S + R + A) c(1) = p(1) xor b(1) C = c(1)
|
||||
* b(2) = MD5(S + c(1)) c(2) = p(2) xor b(2) C = C + c(2)
|
||||
* . . .
|
||||
* b(i) = MD5(S + c(i-1)) c(i) = p(i) xor b(i) C = C + c(i)
|
||||
*/
|
||||
|
||||
if (C.len % HASH_SIZE_MD5 || C.len < HASH_SIZE_MD5)
|
||||
{
|
||||
return chunk_empty;
|
||||
}
|
||||
|
||||
A = chunk_create((u_char*)&salt, sizeof(salt));
|
||||
R = chunk_create(request->get_authenticator(request), HASH_SIZE_MD5);
|
||||
P = chunk_alloca(C.len);
|
||||
p = P.ptr;
|
||||
c = C.ptr;
|
||||
|
||||
seed = chunk_cata("cc", R, A);
|
||||
|
||||
while (c < C.ptr + C.len)
|
||||
{
|
||||
/* b(i) = MD5(S + c(i-1)) */
|
||||
if (!this->hasher->get_hash(this->hasher, this->secret, NULL) ||
|
||||
!this->hasher->get_hash(this->hasher, seed, p))
|
||||
{
|
||||
return chunk_empty;
|
||||
}
|
||||
|
||||
/* p(i) = b(i) xor c(1) */
|
||||
memxor(p, c, HASH_SIZE_MD5);
|
||||
|
||||
/* prepare next round */
|
||||
seed = chunk_create(c, HASH_SIZE_MD5);
|
||||
c += HASH_SIZE_MD5;
|
||||
p += HASH_SIZE_MD5;
|
||||
}
|
||||
|
||||
/* remove truncation, first byte is key length */
|
||||
if (*P.ptr >= P.len)
|
||||
decrypted = chunk_alloca(C.len);
|
||||
if (!request->crypt(request, chunk_from_thing(salt), C, decrypted,
|
||||
this->secret, this->hasher) ||
|
||||
decrypted.ptr[0] >= decrypted.len)
|
||||
{ /* decryption failed? */
|
||||
return chunk_empty;
|
||||
}
|
||||
return chunk_clone(chunk_create(P.ptr + 1, *P.ptr));
|
||||
/* remove truncation, first byte is key length */
|
||||
return chunk_clone(chunk_create(decrypted.ptr + 1, decrypted.ptr[0]));
|
||||
}
|
||||
|
||||
METHOD(radius_socket_t, decrypt_msk, chunk_t,
|
||||
|
|
Loading…
Reference in New Issue