|
Rename md5.c to md5.cpp and try again, seems it works in comand line mode it shows array sequense like this
->%@#$@%$#@%$#@
a->^&%&^%*&^%*(&%&%
e.t.c.
|
|
|
|
|
As pointed out by csteow this class (silently!) produces wrong results for binary data (exes, pictures, ...). It uses ::strlen(m_plainText) in CMD5::calcDigest(). strlen stops at the first '\0' and ignores the rest.
|
|
|
|
|
Here are the relevent definations from the headerfile:
CMD5(const char* plainText); //set plaintext in ctor
void setPlainText(const char* plainText);
I need to clarify these to state that "plaintext" refers to null terminated strings, since you can have text that isn't null terminated.
But I think it's a bit of a stretch to feed "exes, pictures...." to something called "plaintext" and then be surprised when the function doesn't do what you expect.
thanks,
Jim
|
|
|
|
|
Hello there,
thanx a lot for this good class. But in my opinion it isn't secure enough.
Thats the reason why i changed some Methods in your Class.
First of all we have to give the programmer the possibility to set up an Secret Key.
So you have to change the following things.
The First Function is SetPlainText !
void CMD5::setPlainText(const char* plainText,const char* SecretKey)
{
//set plaintext with a mutator, it's ok to
//to call this multiple times. If casting away the const-ness of plainText
//worries you, you could either make a local copy of the plain
//text string instead of just pointing at the user's string, or
//modify the RFC 1321 code to take 'const' plaintext, see example below.
m_plainText = const_cast<char*>(plainText);
m_secretkey = const_cast<char*>(SecretKey); // Added by Karsten Noa (Germany)
m_digestValid = calcDigest();
}
The Second Function is the Constructor.
CMD5::CMD5(const char* plainText,const char* SecretKey)
{
m_plainText = const_cast<char*>(plainText); //get a pointer to the plain text. If casting away the const-ness worries you,
//you could make a local copy of the plain text string.
m_secretkey = const_cast<char*>(SecretKey);
m_digestString[32]=0;
m_digestValid = calcDigest();
}
And last but not least we have to change the coding method in ->
bool CMD5::calcDigest()
{
//See RFC 1321 for details on how MD5Init, MD5Update, and MD5Final
//calculate a digest for the plain text
MD5_CTX context;
MD5Init(&context);
//the alternative to these ugly casts is to go into the RFC code and change the declarations
MD5Update(&context, reinterpret_cast<unsigned char="" *="">(m_secretkey), ::strlen(m_secretkey)); // This Line where added by Karsten Noa (Germany)
MD5Update(&context, reinterpret_cast<unsigned char="" *="">(m_plainText), ::strlen(m_plainText));
MD5Final(reinterpret_cast <unsigned char="" *="">(m_digest),&context);
//make a string version of the numeric digest value
int p=0;
for (int i = 0; i<16; i++)
{
::sprintf(&m_digestString[p],"%02x", m_digest[i]);
p+=2;
}
return true;
}
so for the first time thats all folks !
|
|
|
|
|
You wrote: "minor changes", but will the output still be compatible with standard md5? If not, I think you should have a salted (standard?) hashing method, and a standard MD5 compatible one. IE:
MD5::HashUnSalted(buf).
|
|
|
|
|
The class does not salt the input text. I will pass the compatablity test included in the RFC. Salting is just a technique the user can use if it is appropriate to the specific application.
Jim
|
|
|
|
|
First of all, i think this is a great article. I rate it 5.
I don't understand why recently on CodeProject we have such many not constructive comments.
This article not about how to use strong criptography, but for those who wants just use MD5 with greath C++ class.
So before you want to start thread about "hackers", i think u can create by self a new article and give it a title "How to hack hackers".
Implement a some new feature or fix a bug - and g0 - you can criticize anything, but before this you can only look what great things other coders do.
Best regards.
|
|
|
|
|
This is indeed a great & simple class. It took me some hours of search and reading compiler errors until I found this one which works just great without weird dependencies.
|
|
|
|
|
I used your class and I got it to output md5's once, but now it outputs this all the time :
ÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝp
WTF ! I didnt make any changes to your class, but I did put the code into a DLL.
It should still work when called from my app though. THe above output seems like a buffer isnt NULL terminated or something. Any thoughts as to why this is being outputted ?
|
|
|
|
|
Try making the buffer in your dll static. The ÝÝ... stuff means that the pointer is pointing to memory that has not been allocated, so there is a memory allocation issue somewhere.
Jim
|
|
|
|
|
You can't get from MD5 to the password but the password itself is still relatively simple. Hackers can go from "A" to "zzzzzzzz" and check the MD5 of each string against the stored value (oldest trick in the book).
So in addition to MD5 you should do something strange like running MD5 twice and then flip it and then combine with SHA1. If the hacker doesn't know your method then he can't use brute force.
|
|
|
|
|
That's called "salting" the hash. In real implementaitons of this I've added a few random characters to the input password to detere dictionary attack.
But after thinking about it a while, I choose to enforce strong passwords at the user input level rather than in the hash calculation.
I don't think anyone has brute forced an MD5 hash by any method other than dictionary attack.
Jim
|
|
|
|
|
Jim Howard wrote:
I don't think anyone has brute forced an MD5 hash by any method other than dictionary attack.
You've basically said you don't think anybody's ever written the alphabet without writing the alphabet.
- Jason
(SonorkID 100.611)
In the beginning, teachers taught the 5 W's: who, what, where, when, why. Now it's just a big damn G
|
|
|
|
|
You are right, my comments should have been limited to short passwords only. For a strong password brute force could take ~800 years. The hacker may assume the password has certain characteristics... I don't know what they do. If you hide your method (adding secret-text to input password) it makes trial and error even harder. I guess it depends on how paranoid the programmer is.
|
|
|
|
|
Thought you like to know, "A" to "zzzzzzzz", using the roughly 90 readable keyboard keys (4304672100000000 combos), and computing 1 million MD5 digests per second(good MD5 implimentation on multi ghz box), it'll still take you 136 years to go through all combinations.
|
|
|
|
|
(continuing thread @ 2004)
what if I tell u I have all 4304672100000000 combos stored on my PC and a single sql table lookup can retrieve your password immediately? of course for that to happen, I have to spend $20Million to buy thousands of harddisks.
|
|
|
|
|
see http://www.langfine.com/rsa_md5.htm
|
|
|
|
|
Revision from MD5 original code, you can digest BINARY file (Napster MP3) and password string(MSN Messenger authentication)
Usage:
CString szBuf;
CMD5 md5;
unsigned char digest[16];
unsigned char szPassword[40];
sscanf(lpszParam, "MD5 S %s", (char *)szPassword);
lstrcat((char *)szPassword, m_szPassword);
md5.MD5Init();
md5.MD5Update((unsigned char *)szPassword, lstrlen((LPCSTR)szPassword));
md5.MD5Final(digest);
szBuf.Format(_T("%s S %s"), m_szSecurityPackage, HexToString((LPCTSTR)digest));
m_MSNSock.MSNSend("USR", szBuf);
|
|
|
|
|
// MD5.h: interface for the CMD5 class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_MD5_H__8F46026A_1138_4441_BE43_CB9189B1CEEB__INCLUDED_)
#define AFX_MD5_H__8F46026A_1138_4441_BE43_CB9189B1CEEB__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
/* UINT4 defines a four byte word */
typedef unsigned long int UINT4;
class CMD5
{
public:
/* MD5 context. */
typedef struct {
unsigned long int state[4]; /* state (ABCD) */
unsigned long int count[2]; /* number of bits, modulo 2^64 (lsb first) */
unsigned char buffer[64]; /* input buffer */
} MD5_CTX;
public:
CMD5();
virtual ~CMD5();
public:
void MD5Init();
void MD5Update( unsigned char *input, /* input block */
unsigned int inputLen /* length of input block */);
void MD5Final(unsigned char digest[16] /* message digest */);
protected:
void MD5Transform(UINT4 [4], unsigned char [64]);
void Encode(unsigned char *, UINT4 *, unsigned int);
void Decode(UINT4 *, unsigned char *, unsigned int);
private:
MD5_CTX m_context;
};
|
|
|
|
|
#include "stdafx.h"
#include "MSNClient.h"
#include "MD5.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
/* 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
/* 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); \
}
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
};
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CMD5::CMD5()
{
}
CMD5::~CMD5()
{
}
/* MD5 initialization. Begins an MD5 operation, writing a new context.
*/
void CMD5::MD5Init()
{
m_context.count[0] = m_context.count[1] = 0;
/* Load magic initialization constants. */
m_context.state[0] = 0x67452301;
m_context.state[1] = 0xefcdab89;
m_context.state[2] = 0x98badcfe;
m_context.state[3] = 0x10325476;
}
/* MD5 block update operation. Continues an MD5 message-digest
operation, processing another message block, and updating the
context.
*/
void CMD5::MD5Update (
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)((m_context.count[0] >> 3) & 0x3F);
/* Update number of bits */
if ((m_context.count[0] += ((UINT4)inputLen << 3))
< ((UINT4)inputLen << 3))
m_context.count[1]++;
m_context.count[1] += ((UINT4)inputLen >> 29);
partLen = 64 - index;
/* Transform as many times as possible.
*/
if (inputLen >= partLen)
{
memcpy(&m_context.buffer[index], input, partLen);
MD5Transform (m_context.state, m_context.buffer);
for (i = partLen; i + 63 < inputLen; i += 64)
MD5Transform (m_context.state, &input[i]);
index = 0;
}
else
i = 0;
/* Buffer remaining input */
memcpy(&m_context.buffer[index], &input[i], inputLen-i);
}
/* MD5 finalization. Ends an MD5 message-digest operation, writing the
the message digest and zeroizing the context.
*/
void CMD5::MD5Final(
unsigned char digest[16] /* message digest */
)
{
unsigned char bits[8];
unsigned int index, padLen;
/* Save number of bits */
Encode (bits, m_context.count, 8);
/* Pad out to 56 mod 64.
*/
index = (unsigned int)((m_context.count[0] >> 3) & 0x3f);
padLen = (index < 56) ? (56 - index) : (120 - index);
MD5Update(PADDING, padLen);
/* Append length (before padding) */
MD5Update(bits, 8);
/* Store state in digest */
Encode(digest, m_context.state, 16);
/* Zeroize sensitive information.
*/
memset(&m_context, 0, sizeof(m_context));
}
|
|
|
|
|
/* MD5 basic transformation. Transforms state based on block.
*/
void CMD5::MD5Transform(
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. */
memset(x, 0, sizeof (x));
}
/* Encodes input (UINT4) into output (unsigned char). Assumes len is
a multiple of 4.
*/
void CMD5::Encode(
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.
*/
void CMD5::Decode(
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);
}
|
|
|
|
|
If the length of input string can't exceed 64?
and where is the output string?thank you.
|
|
|
|
|
Hi all,
Your class is cool, but im having problems to use it with and MFC project like an DLL or OCX control, its seems that only works in Win32 Application.
When the class MD5class.cpp is complied an error is generated with following message:
error:"unexpected end of file while looking for precompiled header directive"
I want to know what im doing wrong.
PS: Im using the Microsoft Visual C/C++ 6.0 compiler.
|
|
|
|
|
hi, It is easy to help you.
only add #include "stdafx.h" in your error file's head
That is ok.
|
|
|
|
|
However, by do so, there is another error as below,
>>
"d:\project\passwordtest\md5c.c(5) : fatal error C1853: 'Debug/PasswordTest.pch' is not a precompiled header file created with this compiler"
Can anybody help to tackle it ?
Thanks in Advance!;P
|
|
|
|
|