الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

>> إلى مبرمجي C المتقدمين جداً

مغلق
بدأه config في 8 سبتمبر 2004 · 6 رد · 863 مشاهدة · في الأسئلة المجابة
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

السلام عليكم

اريد احد من المتمكنين في البرمجة بلغة C من كتابة شرح مفصل تفصيلا دقيقا

عن كيفية عمل شفرة MD5 ..

لو وضعنا حرف واحد وشفرناه بـMD5 لظهر لنا 33 خانة....

ولو وضعنا كلمة .. نفس الشئ

ولو شفرنا المصحف كاملاً فإنه لن يتجاوز الثلاثة والثلاثون حرفا...

كييف

خذ مثال:-

abc

900150983cd24fb0d6963f7d28e17f72

config

2245023265ae4cf87d02c8b6ba991139

منتديات الفريق العربي للبرمجة

84140831002f31dca071ee20833b57a5

ولو شفرنا بأي لغة -اليابانية مثلاً- فإن النتيجة ثابتة

تفضلوا الشفرة المصدرية لـ MD5 بلغة سي .. واشرحوها لي.. ولو كان الشرح ببرنامج

Microsoft Visio يكون افضل

md5.h

#ifndef _MD5_H
#define _MD5_H

#ifndef uint8
#define uint8  unsigned char
#endif

#ifndef uint32
#define uint32 unsigned long int
#endif

typedef struct
{
    uint32 total[2];
    uint32 state[4];
    uint8 buffer[64];
}
md5_context;

void md5_starts( md5_context *ctx );
void md5_update( md5_context *ctx, uint8 *input, uint32 length );
void md5_finish( md5_context *ctx, uint8 digest[16] );

#endif /* md5.h */

md5.c

/*
 *  RFC 1321 compliant MD5 implementation
 *
 *  Copyright (C) 2001-2003  Christophe Devine
 *
 *  This program 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.
 *
 *  This program 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 <string.h>

#include "md5.h"

#define GET_UINT32(n,b,i)                       \
{                                               \
    (n) = ( (uint32) (b)[(i)    ]       )       \
        | ( (uint32) (b)[(i) + 1] <<  8 )       \
        | ( (uint32) (b)[(i) + 2] << 16 )       \
        | ( (uint32) (b)[(i) + 3] << 24 );      \
}

#define PUT_UINT32(n,b,i)                       \
{                                               \
    (b)[(i)    ] = (uint8) ( (n)       );       \
    (b)[(i) + 1] = (uint8) ( (n) >>  8 );       \
    (b)[(i) + 2] = (uint8) ( (n) >> 16 );       \
    (b)[(i) + 3] = (uint8) ( (n) >> 24 );       \
}

void md5_starts( md5_context *ctx )
{
    ctx->total[0] = 0;
    ctx->total[1] = 0;

    ctx->state[0] = 0x67452301;
    ctx->state[1] = 0xEFCDAB89;
    ctx->state[2] = 0x98BADCFE;
    ctx->state[3] = 0x10325476;
}

void md5_process( md5_context *ctx, uint8 data[64] )
{
    uint32 X[16], A, B, C, D;

    GET_UINT32( X[0],  data,  0 );
    GET_UINT32( X[1],  data,  4 );
    GET_UINT32( X[2],  data,  8 );
    GET_UINT32( X[3],  data, 12 );
    GET_UINT32( X[4],  data, 16 );
    GET_UINT32( X[5],  data, 20 );
    GET_UINT32( X[6],  data, 24 );
    GET_UINT32( X[7],  data, 28 );
    GET_UINT32( X[8],  data, 32 );
    GET_UINT32( X[9],  data, 36 );
    GET_UINT32( X[10], data, 40 );
    GET_UINT32( X[11], data, 44 );
    GET_UINT32( X[12], data, 48 );
    GET_UINT32( X[13], data, 52 );
    GET_UINT32( X[14], data, 56 );
    GET_UINT32( X[15], data, 60 );

#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))

#define P(a,b,c,d,k,s,t)                                \
{                                                       \
    a += F(b,c,d) + X[k] + t; a = S(a,s) + b;           \
}

    A = ctx->state[0];
    B = ctx->state[1];
    C = ctx->state[2];
    D = ctx->state[3];

#define F(x,y,z) (z ^ (x & (y ^ z)))

    P( A, B, C, D,  0,  7, 0xD76AA478 );
    P( D, A, B, C,  1, 12, 0xE8C7B756 );
    P( C, D, A, B,  2, 17, 0x242070DB );
    P( B, C, D, A,  3, 22, 0xC1BDCEEE );
    P( A, B, C, D,  4,  7, 0xF57C0FAF );
    P( D, A, B, C,  5, 12, 0x4787C62A );
    P( C, D, A, B,  6, 17, 0xA8304613 );
    P( B, C, D, A,  7, 22, 0xFD469501 );
    P( A, B, C, D,  8,  7, 0x698098D8 );
    P( D, A, B, C,  9, 12, 0x8B44F7AF );
    P( C, D, A, B, 10, 17, 0xFFFF5BB1 );
    P( B, C, D, A, 11, 22, 0x895CD7BE );
    P( A, B, C, D, 12,  7, 0x6B901122 );
    P( D, A, B, C, 13, 12, 0xFD987193 );
    P( C, D, A, B, 14, 17, 0xA679438E );
    P( B, C, D, A, 15, 22, 0x49B40821 );

#undef F

#define F(x,y,z) (y ^ (z & (x ^ y)))

    P( A, B, C, D,  1,  5, 0xF61E2562 );
    P( D, A, B, C,  6,  9, 0xC040B340 );
    P( C, D, A, B, 11, 14, 0x265E5A51 );
    P( B, C, D, A,  0, 20, 0xE9B6C7AA );
    P( A, B, C, D,  5,  5, 0xD62F105D );
    P( D, A, B, C, 10,  9, 0x02441453 );
    P( C, D, A, B, 15, 14, 0xD8A1E681 );
    P( B, C, D, A,  4, 20, 0xE7D3FBC8 );
    P( A, B, C, D,  9,  5, 0x21E1CDE6 );
    P( D, A, B, C, 14,  9, 0xC33707D6 );
    P( C, D, A, B,  3, 14, 0xF4D50D87 );
    P( B, C, D, A,  8, 20, 0x455A14ED );
    P( A, B, C, D, 13,  5, 0xA9E3E905 );
    P( D, A, B, C,  2,  9, 0xFCEFA3F8 );
    P( C, D, A, B,  7, 14, 0x676F02D9 );
    P( B, C, D, A, 12, 20, 0x8D2A4C8A );

#undef F
    
#define F(x,y,z) (x ^ y ^ z)

    P( A, B, C, D,  5,  4, 0xFFFA3942 );
    P( D, A, B, C,  8, 11, 0x8771F681 );
    P( C, D, A, B, 11, 16, 0x6D9D6122 );
    P( B, C, D, A, 14, 23, 0xFDE5380C );
    P( A, B, C, D,  1,  4, 0xA4BEEA44 );
    P( D, A, B, C,  4, 11, 0x4BDECFA9 );
    P( C, D, A, B,  7, 16, 0xF6BB4B60 );
    P( B, C, D, A, 10, 23, 0xBEBFBC70 );
    P( A, B, C, D, 13,  4, 0x289B7EC6 );
    P( D, A, B, C,  0, 11, 0xEAA127FA );
    P( C, D, A, B,  3, 16, 0xD4EF3085 );
    P( B, C, D, A,  6, 23, 0x04881D05 );
    P( A, B, C, D,  9,  4, 0xD9D4D039 );
    P( D, A, B, C, 12, 11, 0xE6DB99E5 );
    P( C, D, A, B, 15, 16, 0x1FA27CF8 );
    P( B, C, D, A,  2, 23, 0xC4AC5665 );

#undef F

#define F(x,y,z) (y ^ (x | ~z))

    P( A, B, C, D,  0,  6, 0xF4292244 );
    P( D, A, B, C,  7, 10, 0x432AFF97 );
    P( C, D, A, B, 14, 15, 0xAB9423A7 );
    P( B, C, D, A,  5, 21, 0xFC93A039 );
    P( A, B, C, D, 12,  6, 0x655B59C3 );
    P( D, A, B, C,  3, 10, 0x8F0CCC92 );
    P( C, D, A, B, 10, 15, 0xFFEFF47D );
    P( B, C, D, A,  1, 21, 0x85845DD1 );
    P( A, B, C, D,  8,  6, 0x6FA87E4F );
    P( D, A, B, C, 15, 10, 0xFE2CE6E0 );
    P( C, D, A, B,  6, 15, 0xA3014314 );
    P( B, C, D, A, 13, 21, 0x4E0811A1 );
    P( A, B, C, D,  4,  6, 0xF7537E82 );
    P( D, A, B, C, 11, 10, 0xBD3AF235 );
    P( C, D, A, B,  2, 15, 0x2AD7D2BB );
    P( B, C, D, A,  9, 21, 0xEB86D391 );

#undef F

    ctx->state[0] += A;
    ctx->state[1] += B;
    ctx->state[2] += C;
    ctx->state[3] += D;
}

void md5_update( md5_context *ctx, uint8 *input, uint32 length )
{
    uint32 left, fill;

    if( ! length ) return;

    left = ctx->total[0] & 0x3F;
    fill = 64 - left;

    ctx->total[0] += length;
    ctx->total[0] &= 0xFFFFFFFF;

    if( ctx->total[0] < length )
        ctx->total[1]++;

    if( left && length >= fill )
    {
        memcpy( (void *) (ctx->buffer + left),
                (void *) input, fill );
        md5_process( ctx, ctx->buffer );
        length -= fill;
        input  += fill;
        left = 0;
    }

    while( length >= 64 )
    {
        md5_process( ctx, input );
        length -= 64;
        input  += 64;
    }

    if( length )
    {
        memcpy( (void *) (ctx->buffer + left),
                (void *) input, length );
    }
}

static uint8 md5_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
};

void md5_finish( md5_context *ctx, uint8 digest[16] )
{
    uint32 last, padn;
    uint32 high, low;
    uint8 msglen[8];

    high = ( ctx->total[0] >> 29 )
         | ( ctx->total[1] <<  3 );
    low  = ( ctx->total[0] <<  3 );

    PUT_UINT32( low,  msglen, 0 );
    PUT_UINT32( high, msglen, 4 );

    last = ctx->total[0] & 0x3F;
    padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );

    md5_update( ctx, md5_padding, padn );
    md5_update( ctx, msglen, 8 );

    PUT_UINT32( ctx->state[0], digest,  0 );
    PUT_UINT32( ctx->state[1], digest,  4 );
    PUT_UINT32( ctx->state[2], digest,  8 );
    PUT_UINT32( ctx->state[3], digest, 12 );
}

#ifdef TEST

#include <stdlib.h>
#include <stdio.h>

/*
 * those are the standard RFC 1321 test vectors
 */

static char *msg[] = 
{
    "",
    "a",
    "abc",
    "message digest",
    "abcdefghijklmnopqrstuvwxyz",
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
    "12345678901234567890123456789012345678901234567890123456789012" \
        "345678901234567890"
};

static char *val[] =
{
    "d41d8cd98f00b204e9800998ecf8427e",
    "0cc175b9c0f1b6a831c399e269772661",
    "900150983cd24fb0d6963f7d28e17f72",
    "f96b697d7cb7938d525a2f31aaf161d0",
    "c3fcd3d76192e4007dfb496cca67e13b",
    "d174ab98d277d9f5a5611c2c9f419d9f",
    "57edf4a22be3c955ac49da2e2107b67a"
};

int main( int argc, char *argv[] )
{
    FILE *f;
    int i, j;
    char output[33];
    md5_context ctx;
    unsigned char buf[1000];
    unsigned char md5sum[16];

    if( argc < 2 )
    {
        printf( "\n MD5 Validation Tests:\n\n" );

        for( i = 0; i < 7; i++ )
        {
            printf( " Test %d ", i + 1 );

            md5_starts( &ctx );
            md5_update( &ctx, (uint8 *) msg, strlen( msg ) );
            md5_finish( &ctx, md5sum );

            for( j = 0; j < 16; j++ )
            {
                sprintf( output + j * 2, "%02x", md5sum[j] );
            }

            if( memcmp( output, val, 32 ) )
            {
                printf( "failed!\n" );
                return( 1 );
            }

            printf( "passed.\n" );
        }

        printf( "\n" );
    }
    else
    {
        if( ! ( f = fopen( argv[1], "rb" ) ) )
        {
            perror( "fopen" );
            return( 1 );
        }

        md5_starts( &ctx );

        while( ( i = fread( buf, 1, sizeof( buf ), f ) ) > 0 )
        {
            md5_update( &ctx, buf, i );
        }

        md5_finish( &ctx, md5sum );

        for( j = 0; j < 16; j++ )
        {
            printf( "%02x", md5sum[j] );
        }

        printf( "  %s\n", argv[1] );
    }

    return( 0 );
}

#endif

تم تعديل هذه المشاركة بواسطة config في 8 سبتمبر 2004 في 00:27

#2

الموضوع أثار اهتمامي حقا ,, وكنت أبحث في أمور كهذه قبل فترة ,,

انتظرني حتى يوم الغد ,, وسأبحت معك ,, لأني أريد أن أنام الآن :)

banner_60_468.gif

NOTHING IS IMPOSSIBLE

#3

احلام سعيدة

#4

السلام عليكم

بالنسبة للكود - فعلا روعة وطريقتة ذكية

أما سؤالك عن كيفية عمل هذا التشفير

فإن البرنامج نفسة لا يعرف الحل ?

لأنة لا يوجد فك تشفير لهذا الكود

كما قلت مثلا يحول كل المصحف إلى 5cad4bf4a648acb67b10b003f164f4ac

هذة القيمة = 16 حرف وهي بالترميز هكس من 0 إلى F

وبما أنة لا يستطيع إرجاع 16 حرف إلى ألاف الأحرف

فيسمى تشفير وحيد الإتجاة

ولة إسم آخر التشفير العشوائي

ولكن السؤال كيف إستطاع إظهار هذة القيم المختلفة

والحل بكل بساطة :

لماذا إختار طول المفتاح = 16 حرف

لماذا إختار إظهار القيم بالترميز الهكس(0-1-2-3-4-5-6-7-8-9-A- B-C-D-E-F ) تساوي 16 إحتمال

والنتيجة :

16 * 16 =256 وهو عدد كل الإحتمالات المتوقعة لبايت واحد أو حرف

لاحظ كيف بدأ

void md5_starts( md5_context *ctx )
{
   ctx->total[0] = 0;
   ctx->total[1] = 0;

   ctx->state[0] = 0x67452301;
   ctx->state[1] = 0xEFCDAB89;
   ctx->state[2] = 0x98BADCFE;
   ctx->state[3] = 0x10325476;
}

وهنا إختار الرموز التي ستظهر وهي ترميز الهكس لها 16 إحتمال (ولاحظ حجم 4 مجموعات =16 بايت وهو طول المفتاح )

كما قام بقلب القيم المتشابة لاحظ اول رقم 6 يتكرر في آخر المجموعة =6 و7 وهكذا

لكي لاتظهر نفس القيمة متشابة ولكي يطول المفتاح قدر الأمكان

ثم تتم القرائة على حرف حرف

       while( ( i = fread( buf, 1, sizeof( buf ), f ) ) > 0 )
       {
           md5_update( &ctx, buf, i );
       }

ويمرر التنفيذ إلى الدالة md5_update بعد قرائة كل حرف

void md5_update( md5_context *ctx, uint8 *input, uint32 length )
{
   uint32 left, fill;

   if( ! length ) return;

   left = ctx->total[0] & 0x3F;
   fill = 64 - left;

   ctx->total[0] += length;
   ctx->total[0] &= 0xFFFFFFFF;

   if( ctx->total[0] < length )
       ctx->total[1]++;

   if( left && length >= fill )
   {
       memcpy( (void *) (ctx->buffer + left),
               (void *) input, fill );
       md5_process( ctx, ctx->buffer );
       length -= fill;
       input  += fill;
       left = 0;
   }

   while( length >= 64 )
   {
       md5_process( ctx, input );
       length -= 64;
       input  += 64;
   }

   if( length )
   {
       memcpy( (void *) (ctx->buffer + left),
               (void *) input, length );
   }
}

الغرض من هذة الدالة تصغير حجم البيانات إلى أن تصل لمرحلة يستطيع البرنامج تقسيمها إلى 16 قسم

تجد أنة بدأ

   left = ctx->total[0] & 0x3F;
   fill = 64 - left;

والقيمة 0x3F تساوي 64

وأستخدمت مع تعليمة AND إلي هي & مع مجموع البايتات الذي وصل لها التنفيذ

لكي تنقصة إلى أن يصل مجموع الحروف 1024 بايت أي واحد كيلو بايت

لأن طول المفتاح 16 بايت * 64 = 1024 بايت

وإذا وصلت حجم البيانات التي تريد تشفيرها إلى 1 كيلو بايت يتم تنفيذ الكود

   if( left && length >= fill )
   {
       memcpy( (void *) (ctx->buffer + left),
               (void *) input, fill );
       md5_process( ctx, ctx->buffer );
       length -= fill;
       input  += fill;
       left = 0;
   }

لينقل فقط بايت واحد من 1024 بايت ( والباقي يحذفها )

ثم بدأ تنفيذ md5_process

   uint32 X[16], A, B, C, D;

   GET_UINT32( X[0],  data,  0 );
   GET_UINT32( X[1],  data,  4 );
   GET_UINT32( X[2],  data,  8 );
   GET_UINT32( X[3],  data, 12 );
   GET_UINT32( X[4],  data, 16 );
   GET_UINT32( X[5],  data, 20 );
   GET_UINT32( X[6],  data, 24 );
   GET_UINT32( X[7],  data, 28 );
   GET_UINT32( X[8],  data, 32 );
   GET_UINT32( X[9],  data, 36 );
   GET_UINT32( X[10], data, 40 );
   GET_UINT32( X[11], data, 44 );
   GET_UINT32( X[12], data, 48 );
   GET_UINT32( X[13], data, 52 );
   GET_UINT32( X[14], data, 56 );
   GET_UINT32( X[15], data, 60 );

في بدية الكود أنشأ 4 مصفوفات كل مصفوفة من 16 قيمة (لأن 4*16=64 )

كما أن قيمة كل مصفوفة ستحمل 2 بايت =16 بت =16*64 =1024 =1كيلوبايت

أما مضاعفات 4 التي إستخدمها (لي رأيين حولها )

الأول : أن 4 هي العامل المشترك بين 16 و 64

الثاني : أن البرنامج يظهر المفتاح كأرقام هكس وحجم رقم الهكس 1 نيبل أي 4 بت

المهم أن كل الموضوع يدور حول 16 بايت

هذا ما توصلت إلية

فهل توجد طريقة أخرى - الله أعلم

http://www.jaascois.com

*************************************************

مجموعة مواضيع - إحتراف البرمجة -

ّ~~~~~~~~~~~~~~~~~~~~~~

البرمجة المتقدمة & الهندسة العكسية & برمجة وأمن الأنظمة

/index.php?showtopic=45002

آخر المواضيع :

+- تحليل جرائم الكمبيوتر -+

أنظمة اليونكس(Solaris,HP, AIX,SCO)وانواع المعالجات

ثغرة SMS لأجهزة الجوال Siemens 3568i !

أخطاء وثغرات البرامج العربية !!!

سلسلة مواضيع - أمن وحماية مواقع الويب -

E البرمجة المتقدمة X للملفات التنفيذية E

سلسلة مواضيع ثغرات الأنظمة وإختراق الأجهزة

**************************************************

<span style='font-size:14pt;line-height:100%'>الإرادة تحـــقق السيـــادة</span>

**************************************************

#5

MD5 ليس تشفيرا بمعنى الكلمة ولكنه يعتبر ضمن الhash ويقوم على اخذ pattern من البيانات ويستخدم للتحقق من أن البيانات لم يتغير أو لم يتم العبث به ولذلك تجد الطول ثابتا مهما تغير طول البيانات ... ولذلك أيضا فهو أحادي الاتجاه لا يمكن فكه بل يتم مقارنة القيمتين بعد الhash

ولكنه قابل للكسر كما أعلن قبل فترة .

Igonrance is HeLL,need to say any more?

Laziness is HeLL, Lazy programmers must be shoot on the head

Stupidity is HeLL, u can patch everything but not human stupidity

#6

شكراً للجميع Jass ما قصرت كفيت ووفيت ........

SaD jAckAl نعم هو قابل للكسر .. ولدي البرنامج الخاص بالكسر

#7

السلام عليكم و رحمة الله و بركاته

جزاكم الله خيراً على المجهود و كذلك أخي jaas الذي سبح في الكود و أخرج لنا السمك :)

بالنسبة لفضاء القيم للتابع MD5 فهو 16^16 و ليس 16 * 16 كما سقطت من أخونا jaas سهواً فكما أن القيم الممكنة ل 8 بتات في النظام الثنائي هي 2^8 فإن 16 خانة في النظام الست عشري هي 16 ^ 16

المهم بما أن MD5 هو تابع تقطيع Hash فإنه يحول كل القيم إلى واحدة من 16 ^ 16 قيمة و حسب مبدأ أنه إذا كان لدينا 9 حمامات و 8 أعشاش فلا بد من وجود حمامتين معاً في عش واحد فلدينا فقط 16 ^ 16 رسالة لها MD5 مختلف عن بعضها و باقي الرسائل سوف تتداخل بنفس القيم لل MD5 فإذا كان أحد الأخوة يعلم تحت أي الظروف (على أي نوع من الرساثل) يتم التداخل فنحن بانتظار الفائدة

هذا الموضوع مغلق.

مواضيع مشابهة