uac authentication

git-svn-id: http://svn.berlios.de/svnroot/repos/sems/trunk@126 8eb893ce-cfd4-0310-b710-fb5ebe64c474
sayer/1.4-spce2.6
Stefan Sayer 20 years ago
parent 7d6b3bf377
commit 3af1d3dd6f

@ -0,0 +1,20 @@
plug_in_name = uac_auth
module_extra_objs = md5.o
module_ldflags =
module_cflags =
#md5.o: md5.c md5.d
# $(CC) $(cflags) -c $< -o $@
#
#md5.d: md5.c md5.h Makefile
# $(CC) -MM $< $(cflags) > $@
%.o : %.c %.d
$(CC) $(cflags) -c $< -o $@
%.d : %.c %.h Makefile
$(CC) -MM $< $(cflags) > $@
include ../Makefile.app_module

@ -0,0 +1,389 @@
/*
* $Id: AmSession.cpp,v 1.42.2.10 2005/09/02 13:47:46 rco Exp $
*
* Copyright (C) 2002-2003 Fhg Fokus
* Copyright (C) 2006 iptego GmbH
*
* This file is part of sems, a free SIP media server.
*
* sems is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version
*
* For a license to use the ser software under conditions
* other than those described here, or to purchase support for this
* software, please contact iptel.org by e-mail at the following addresses:
* info@iptel.org
*
* sems is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "UACAuth.h"
#include "AmSipRequest.h"
#include <map>
using std::map;
#define MOD_NAME "uac_auth"
EXPORT_SESSION_EVENT_HANDLER_FACTORY(UACAuthFactory, MOD_NAME);
int UACAuthFactory::onLoad()
{
return 0;
}
bool UACAuthFactory::onInvite(const AmSipRequest& req)
{
return false;
}
AmSessionEventHandler* UACAuthFactory::getHandler(AmSession* s)
{
AmSessionEventHandler* res = NULL;
CredentialHolder* c = dynamic_cast<CredentialHolder*>(s);
if (c != NULL) {
res = new UACAuth(s, c->getCredentials());
} else {
DBG("no credentials for new session. not enabling auth session handler.\n");
}
return res;
}
UACAuth::UACAuth(AmSession* s,
UACAuthCred* cred)
: AmSessionEventHandler(s),
credential(cred)
{
}
bool UACAuth::process(AmEvent* ev)
{
return false;
}
bool UACAuth::onSipEvent(AmSipEvent* ev)
{
return false;
}
bool UACAuth::onSipRequest(const AmSipRequest& req)
{
return false;
}
bool UACAuth::onSipReply(const AmSipReply& reply)
{
DBG("on sip reply --------------------------\n");
bool processed = false;
if (reply.code==407 || reply.code==401) {
DBG("SIP reply with code %d cseq %d .\n", reply.code, reply.cseq);
map<unsigned int, SIPRequestInfo >::iterator ri =
sent_requests.find(reply.cseq);
if (ri!= sent_requests.end())
{
DBG(" UACAuth - processing with reply code %d \n", reply.code);
string auth_hdr = (reply.code==407) ? getHeader(reply.hdrs, "Proxy-Authenticate") :
getHeader(reply.hdrs, "WWW-Authenticate");
string result;
if (do_auth(reply.code, auth_hdr,
ri->second.method,
s->dlg.remote_uri, result)) {
string hdrs = ri->second.hdrs;
// TODO: strip headers
// ((code==401) ? stripHeader(ri->second.hdrs, "Authorization") :
// stripHeader(ri->second.hdrs, "Proxy-Authorization"));
hdrs += result;
// resend request
if (s->dlg.sendRequest(ri->second.method,
ri->second.content_type,
ri->second.body,
hdrs) != 0)
processed = true;
}
}
}
if (reply.code >= 200)
sent_requests.erase(reply.cseq); // now we dont need it any more
return processed;
}
bool UACAuth::onSendRequest(const string& method,
const string& content_type,
const string& body,
string& hdrs,
unsigned int cseq)
{
DBG("adding %d to list of sent requests.\n", cseq);
sent_requests[cseq] = SIPRequestInfo(method,
content_type,
body,
hdrs);
return false;
}
bool UACAuth::onSendReply(const AmSipRequest& req,
unsigned int code,const string& reason,
const string& content_type,const string& body,
string& hdrs)
{
return false;
}
#include "md5global.h"
typedef struct {
UINT4 state[4]; /* state (ABCD) */
UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
unsigned char buffer[64]; /* input buffer */
} MD5_CTX;
extern "C" void MD5Init (MD5_CTX * ctx);
extern "C" void MD5Update (MD5_CTX *, unsigned char *, unsigned int);
extern "C" void MD5Final (unsigned char [16], MD5_CTX *);
using std::string;
void w_MD5Update(MD5_CTX *ctx, const string& s) {
unsigned char a[255];
if (s.length()>255) {
ERROR("string too long\n");
return;
}
memcpy(a, s.c_str(), s.length());
MD5Update(ctx, a, s.length());
}
string UACAuth::find_attribute(const string& name, const string& header) {
string res;
size_t pos1 = header.find(name);
if (pos1!=string::npos) {
pos1+=name.length();
pos1 = header.find_first_not_of(" =\"", pos1);
if (pos1 != string::npos) {
size_t pos2 = header.find_first_of(",\"", pos1);
if (pos2 != string::npos) {
res = header.substr(pos1, pos2-pos1);
}
}
}
return res;
}
bool UACAuth::parse_header(const string& auth_hdr, UACAuthDigestChallenge& challenge) {
size_t p = auth_hdr.find_first_not_of(' ');
if (auth_hdr.substr(p, 6) != "Digest") {
ERROR("only Digest auth supported\n");
return false;
}
// inefficient parsing...TODO: optimize this
challenge.realm = find_attribute("realm", auth_hdr);
challenge.domain = find_attribute("domain", auth_hdr);
challenge.nonce = find_attribute("nonce", auth_hdr);
challenge.opaque = find_attribute("opaque", auth_hdr);
challenge.algorithm = find_attribute("algorithm", auth_hdr);
challenge.qop = find_attribute("qop", auth_hdr);
return (challenge.realm.length() && challenge.nonce.length());
}
bool UACAuth::do_auth(const unsigned int code, const string& auth_hdr,
const string& method, const string& uri, string& result) {
if (!auth_hdr.length()) {
ERROR("empty auth header.\n");
return false;
}
UACAuthDigestChallenge challenge;
if (!parse_header(auth_hdr, challenge)) {
ERROR("error parsing auth header '%s'\n", auth_hdr.c_str());
return false;
}
if ((challenge.algorithm.length()) && (challenge.algorithm != "MD5")) {
DBG("unsupported algorithm: '%s'\n", challenge.algorithm.c_str());
return false;
}
DBG("realm='%s', domain='%s', nonce='%s'\n", challenge.realm.c_str(),
challenge.domain.c_str(), challenge.nonce.c_str());
if (credential->realm.length()
&& (credential->realm != challenge.realm)) {
DBG("realm mismatch ('%s' vs '%s'). auth failed.\n",
credential->realm.c_str(),challenge.realm.c_str());
return false;
}
HASHHEX ha1;
HASHHEX ha2;
HASHHEX response;
/* do authentication */
uac_calc_HA1( challenge, ""/*cnonce*/, ha1);
uac_calc_HA2( method, uri, challenge, 0/*hentity*/, ha2);
uac_calc_response( ha1, ha2, challenge, ""/*nc*/, "" /*cnonce*/, response);
DBG("calculated response = %s\n", response);
// compile auth response
result = ((code==401) ? "Authorization: Digest username=\"" :
"Proxy-Authorization: Digest username=\"")
+ credential->user + "\", realm=\"" + challenge.realm + "\", nonce=\""+challenge.nonce +
"\", uri=\""+uri+"\", ";
if (challenge.opaque.length())
result+="opaque=\""+challenge.opaque+"\", ";
result+="response=\""+string((char*)response)+"\", algorithm=\"MD5\"\n";
DBG("Auth req hdr: '%s'\n", result.c_str());
return true;
}
// These functions come basically from ser's uac module
static inline void cvt_hex(HASH bin, HASHHEX hex)
{
unsigned short i;
unsigned char j;
for (i = 0; i<HASHLEN; i++)
{
j = (bin[i] >> 4) & 0xf;
if (j <= 9)
{
hex[i * 2] = (j + '0');
} else {
hex[i * 2] = (j + 'a' - 10);
}
j = bin[i] & 0xf;
if (j <= 9)
{
hex[i * 2 + 1] = (j + '0');
} else {
hex[i * 2 + 1] = (j + 'a' - 10);
}
};
hex[HASHHEXLEN] = '\0';
}
/*
* calculate H(A1)
*/
void UACAuth::uac_calc_HA1(UACAuthDigestChallenge& challenge,
string cnonce,
HASHHEX sess_key)
{
MD5_CTX Md5Ctx;
HASH HA1;
MD5Init(&Md5Ctx);
w_MD5Update(&Md5Ctx, credential->user);
w_MD5Update(&Md5Ctx, ":");
// use realm from challenge in case of
// empty credential realm (ignore realm)
w_MD5Update(&Md5Ctx, challenge.realm);
w_MD5Update(&Md5Ctx, ":");
w_MD5Update(&Md5Ctx, credential->pwd);
MD5Final(HA1, &Md5Ctx);
// MD5sess ...not supported
// if ( flags & AUTHENTICATE_MD5SESS )
// {
// MD5Init(&Md5Ctx);
// MD5Update(&Md5Ctx, HA1, HASHLEN);
// MD5Update(&Md5Ctx, ":", 1);
// MD5Update(&Md5Ctx, challenge.nonce.c_str(), challenge.nonce.length());
// MD5Update(&Md5Ctx, ":", 1);
// MD5Update(&Md5Ctx, cnonce.c_str(), cnonce.length());
// MD5Final(HA1, &Md5Ctx);
// };
cvt_hex(HA1, sess_key);
}
/*
* calculate H(A2)
*/
void UACAuth::uac_calc_HA2( const string& method, const string& uri,
UACAuthDigestChallenge& challenge,
HASHHEX hentity,
HASHHEX HA2Hex )
{
unsigned char hc[1]; hc[0]=':';
MD5_CTX Md5Ctx;
HASH HA2;
MD5Init(&Md5Ctx);
w_MD5Update(&Md5Ctx, method);
MD5Update(&Md5Ctx, hc, 1);
w_MD5Update(&Md5Ctx, uri);
if ( challenge.qop == "auth-int" )
{
MD5Update(&Md5Ctx, hc, 1);
MD5Update(&Md5Ctx, hentity, HASHHEXLEN);
};
MD5Final(HA2, &Md5Ctx);
cvt_hex(HA2, HA2Hex);
}
/*
* calculate request-digest/response-digest as per HTTP Digest spec
*/
void UACAuth::uac_calc_response( HASHHEX ha1, HASHHEX ha2,
UACAuthDigestChallenge& challenge,
const string& nc, const string& cnonce,
HASHHEX response)
{
unsigned char hc[1]; hc[0]=':';
MD5_CTX Md5Ctx;
HASH RespHash;
MD5Init(&Md5Ctx);
MD5Update(&Md5Ctx, ha1, HASHHEXLEN);
MD5Update(&Md5Ctx, hc, 1);
w_MD5Update(&Md5Ctx, challenge.nonce);
MD5Update(&Md5Ctx, hc, 1);
if (challenge.qop.length())
{
w_MD5Update(&Md5Ctx, nc);
MD5Update(&Md5Ctx, hc, 1);
w_MD5Update(&Md5Ctx, cnonce);
MD5Update(&Md5Ctx, hc, 1);
w_MD5Update(&Md5Ctx, challenge.qop);
MD5Update(&Md5Ctx, hc, 1);
};
MD5Update(&Md5Ctx, ha2, HASHHEXLEN);
MD5Final(RespHash, &Md5Ctx);
cvt_hex(RespHash, response);
}

@ -0,0 +1,137 @@
#ifndef UACAuth_h
#define UACAuth_h
#include "AmApi.h"
#include "AmSession.h"
#include <string>
using std::string;
#include <map>
using std::map;
#define HASHLEN 16
typedef unsigned char HASH[HASHLEN];
#define HASHHEXLEN 32
typedef unsigned char HASHHEX[HASHHEXLEN+1];
struct UACAuthDigestChallenge {
std::string domain;
std::string realm;
std::string qop;
std::string nonce;
std::string opaque;
bool stale;
std::string algorithm;
};
struct UACAuthCred {
string realm;
string user;
string pwd;
UACAuthCred(const string& realm,
const string& user,
const string& pwd)
: realm(realm), user(user), pwd(pwd) { }
};
class CredentialHolder {
UACAuthCred cred;
public:
CredentialHolder(const string& realm,
const string& user,
const string& pwd)
: cred(realm,user,pwd) { }
UACAuthCred* getCredentials() { return &cred; }
};
class UACAuthFactory
: public AmSessionEventHandlerFactory
{
public:
UACAuthFactory(const string& name)
: AmSessionEventHandlerFactory(name)
{ }
int onLoad();
// SessionEventHandler API
AmSessionEventHandler* getHandler(AmSession* s);
bool onInvite(const AmSipRequest&);
};
struct SIPRequestInfo {
string method;
string content_type;
string body;
string hdrs;
SIPRequestInfo(const string& method,
const string& content_type,
const string& body,
const string& hdrs)
: method(method), content_type(content_type),
body(body), hdrs(hdrs) { }
SIPRequestInfo() {}
};
class UACAuth: public AmSessionEventHandler
{
map<unsigned int, SIPRequestInfo> sent_requests;
UACAuthCred* credential;
std::string find_attribute(const std::string& name, const std::string& header);
bool parse_header(const std::string& auth_hdr, UACAuthDigestChallenge& challenge);
void uac_calc_HA1(UACAuthDigestChallenge& challenge,
std::string cnonce,
HASHHEX sess_key);
void uac_calc_HA2( const std::string& method, const std::string& uri,
UACAuthDigestChallenge& challenge,
HASHHEX hentity,
HASHHEX HA2Hex );
void uac_calc_response( HASHHEX ha1, HASHHEX ha2,
UACAuthDigestChallenge& challenge,
const std::string& nc, const std::string& cnonce,
HASHHEX response);
/**
* do auth on cmd with nonce in auth_hdr if possible
* @return true if successful
*/
bool do_auth(const unsigned int code, const string& auth_hdr,
const string& method, const string& uri, string& result);
public:
UACAuth(AmSession* s, UACAuthCred* cred);
virtual ~UACAuth(){ }
/* SEH Hooks @see AmSessionEventHandler */
virtual bool process(AmEvent*);
virtual bool onSipEvent(AmSipEvent*);
virtual bool onSipRequest(const AmSipRequest&);
virtual bool onSipReply(const AmSipReply&);
virtual bool onSendRequest(const string& method,
const string& content_type,
const string& body,
string& hdrs,
unsigned int cseq);
virtual bool onSendReply(const AmSipRequest& req,
unsigned int code,
const string& reason,
const string& content_type,
const string& body,
string& hdrs);
};
#endif

@ -0,0 +1,357 @@
/*
$Id: md5.c,v 1.1 2005/07/13 16:45:42 sayer Exp $
MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
rights reserved.
License to copy and use this software is granted provided that it
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
Algorithm" in all material mentioning or referencing this software
or this function.
License is also granted to make and use derivative works provided
that such works are identified as "derived from the RSA Data
Security, Inc. MD5 Message-Digest Algorithm" in all material
mentioning or referencing the derived work.
RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this
documentation and/or software.
*/
#include <string.h>
#include "md5global.h"
#include "md5.h"
#define USE_MEM
/* Constants for MD5Transform routine.
*/
#define S11 7
#define S12 12
#define S13 17
#define S14 22
#define S21 5
#define S22 9
#define S23 14
#define S24 20
#define S31 4
#define S32 11
#define S33 16
#define S34 23
#define S41 6
#define S42 10
#define S43 15
#define S44 21
static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64]));
static void Encode PROTO_LIST
((unsigned char *, UINT4 *, unsigned int));
static void Decode PROTO_LIST
((UINT4 *, unsigned char *, unsigned int));
static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int));
static unsigned char PADDING[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/* F, G, H and I are basic MD5 functions.
*/
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))
/* ROTATE_LEFT rotates x left n bits.
*/
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
Rotation is separate from addition to prevent recomputation.
*/
#define FF(a, b, c, d, x, s, ac) { \
(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define GG(a, b, c, d, x, s, ac) { \
(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define HH(a, b, c, d, x, s, ac) { \
(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define II(a, b, c, d, x, s, ac) { \
(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
/* MD5 initialization. Begins an MD5 operation, writing a new context.
*/
void MD5Init (context)
MD5_CTX *context; /* context */
{
context->count[0] = context->count[1] = 0;
/* Load magic initialization constants.
*/
context->state[0] = 0x67452301;
context->state[1] = 0xefcdab89;
context->state[2] = 0x98badcfe;
context->state[3] = 0x10325476;
}
/* MD5 block update operation. Continues an MD5 message-digest
operation, processing another message block, and updating the
context.
*/
void MD5Update (context, input, inputLen)
MD5_CTX *context; /* context */
unsigned char *input; /* input block */
unsigned int inputLen; /* length of input block */
{
unsigned int i, index, partLen;
/* Compute number of bytes mod 64 */
index = (unsigned int)((context->count[0] >> 3) & 0x3F);
/* Update number of bits */
if ((context->count[0] += ((UINT4)inputLen << 3))
< ((UINT4)inputLen << 3))
context->count[1]++;
context->count[1] += ((UINT4)inputLen >> 29);
partLen = 64 - index;
/* Transform as many times as possible.
*/
if (inputLen >= partLen) {
MD5_memcpy
((POINTER)&context->buffer[index], (POINTER)input, partLen);
MD5Transform (context->state, context->buffer);
for (i = partLen; i + 63 < inputLen; i += 64)
MD5Transform (context->state, &input[i]);
index = 0;
}
else
i = 0;
/* Buffer remaining input */
MD5_memcpy
((POINTER)&context->buffer[index], (POINTER)&input[i],
inputLen-i);
}
/* MD5 finalization. Ends an MD5 message-digest operation, writing the
the message digest and zeroizing the context.
*/
void MD5Final (digest, context)
unsigned char digest[16]; /* message digest */
MD5_CTX *context; /* context */
{
unsigned char bits[8];
unsigned int index, padLen;
/* Save number of bits */
Encode (bits, context->count, 8);
/* Pad out to 56 mod 64.
*/
index = (unsigned int)((context->count[0] >> 3) & 0x3f);
padLen = (index < 56) ? (56 - index) : (120 - index);
MD5Update (context, PADDING, padLen);
/* Append length (before padding) */
MD5Update (context, bits, 8);
/* Store state in digest */
Encode (digest, context->state, 16);
/* Zeroize sensitive information.
*/
MD5_memset ((POINTER)context, 0, sizeof (*context));
}
/* MD5 basic transformation. Transforms state based on block.
*/
static void MD5Transform (state, block)
UINT4 state[4];
unsigned char block[64];
{
UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
Decode (x, block, 64);
/* Round 1 */
FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
/* Round 2 */
GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
/* Round 3 */
HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
/* Round 4 */
II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
/* Zeroize sensitive information.
*/
MD5_memset ((POINTER)x, 0, sizeof (x));
}
/* Encodes input (UINT4) into output (unsigned char). Assumes len is
a multiple of 4.
*/
static void Encode (output, input, len)
unsigned char *output;
UINT4 *input;
unsigned int len;
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4) {
output[j] = (unsigned char)(input[i] & 0xff);
output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
}
}
/* Decodes input (unsigned char) into output (UINT4). Assumes len is
a multiple of 4.
*/
static void Decode (output, input, len)
UINT4 *output;
unsigned char *input;
unsigned int len;
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4)
output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
(((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
}
/* Note: Replace "for loop" with standard memcpy if possible.
*/
static void MD5_memcpy (output, input, len)
POINTER output;
POINTER input;
unsigned int len;
{
#ifndef USE_MEM
unsigned int i;
for (i = 0; i < len; i++)
output[i] = input[i];
#else
memcpy( output, input, len );
#endif
}
/* Note: Replace "for loop" with standard memset if possible.
*/
static void MD5_memset (output, value, len)
POINTER output;
int value;
unsigned int len;
{
#ifndef USE_MEM
unsigned int i;
for (i = 0; i < len; i++)
((char *)output)[i] = (char)value;
#else
memset( output, value, len );
#endif
}

@ -0,0 +1,45 @@
/* MD5.H - header file for MD5C.C
* $Id: md5.h,v 1.1 2005/07/13 16:45:42 sayer Exp $
*/
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
rights reserved.
License to copy and use this software is granted provided that it
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
Algorithm" in all material mentioning or referencing this software
or this function.
License is also granted to make and use derivative works provided
that such works are identified as "derived from the RSA Data
Security, Inc. MD5 Message-Digest Algorithm" in all material
mentioning or referencing the derived work.
RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this
documentation and/or software.
*/
#ifndef MD5_H
#define MD5_H
#include "md5global.h"
/* MD5 context. */
typedef struct {
UINT4 state[4]; /* state (ABCD) */
UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
unsigned char buffer[64]; /* input buffer */
} MD5_CTX;
void MD5Init PROTO_LIST ((MD5_CTX *));
void MD5Update PROTO_LIST
((MD5_CTX *, unsigned char *, unsigned int));
void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *));
#endif /* MD5_H */

@ -0,0 +1,38 @@
/* GLOBAL.H - RSAREF types and constants
*
*/
/* PROTOTYPES should be set to one if and only if the compiler supports
function argument prototyping.
The following makes PROTOTYPES default to 0 if it has not already
been defined with C compiler flags.
*/
#ifndef MD5GLOBAL_H
#define MD5GLOBAL_H
#ifndef PROTOTYPES
#define PROTOTYPES 0
#endif
/* POINTER defines a generic pointer type */
typedef unsigned char *POINTER;
/* UINT2 defines a two byte word */
typedef unsigned short int UINT2;
/* UINT4 defines a four byte word */
typedef unsigned int UINT4;
/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
returns an empty list.
*/
#if PROTOTYPES
#define PROTO_LIST(list) list
#else
#define PROTO_LIST(list) ()
#endif
#endif /* MD5GLOBAL_H */
Loading…
Cancel
Save