aboutsummaryrefslogtreecommitdiffstats
path: root/src/libradius
diff options
context:
space:
mode:
authorMartin Willi <martin@revosec.ch>2013-07-22 13:45:31 +0200
committerMartin Willi <martin@revosec.ch>2013-07-29 09:00:48 +0200
commit15483a622324b55da28ef4faa1cba6a899ea1039 (patch)
tree0d0bf463a97eee1368f3f6207df38b3cfce13def /src/libradius
parent9aeb6cea4c09f2035b99ae56d66269cde1d85070 (diff)
downloadstrongswan-15483a622324b55da28ef4faa1cba6a899ea1039.tar.bz2
strongswan-15483a622324b55da28ef4faa1cba6a899ea1039.tar.xz
libradius: refactor generic RADIUS en-/decryption function to a message method
Diffstat (limited to 'src/libradius')
-rw-r--r--src/libradius/radius_message.c62
-rw-r--r--src/libradius/radius_message.h16
-rw-r--r--src/libradius/radius_socket.c51
3 files changed, 85 insertions, 44 deletions
diff --git a/src/libradius/radius_message.c b/src/libradius/radius_message.c
index e7717ff7a..dd3993704 100644
--- a/src/libradius/radius_message.c
+++ b/src/libradius/radius_message.c
@@ -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,
},
);
diff --git a/src/libradius/radius_message.h b/src/libradius/radius_message.h
index c49323490..4ce03a44e 100644
--- a/src/libradius/radius_message.h
+++ b/src/libradius/radius_message.h
@@ -285,6 +285,22 @@ struct radius_message_t {
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.
*/
void (*destroy)(radius_message_t *this);
diff --git a/src/libradius/radius_socket.c b/src/libradius/radius_socket.c
index 7dab968d8..f432151c0 100644
--- a/src/libradius/radius_socket.c
+++ b/src/libradius/radius_socket.c
@@ -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,