Witam,

Jakis czas temu gadu gadu wprowadzilo mozliwosci logowania do serwera
przy uzyciu SHA1 (hash na hasle+seedzie) Nie wiem dokladnie od jakiej
wersji klienta jest to mozliwe. Ale serwer akceptuje logowania nawet jak
ma protokol ustawiony na 6.0 wiec w sumie malo istotne.. Wazne, ze hash
SHA1 jest troche trudniej zlamac, niz ten generowany przy uzyciu
gg_login_hash() nie wiem jak bardzo porzadane jest bezpieczenstwo hasla
w libgadu, i w innych klientach. Ale. Jak mamy mozliwosc... To imho
mozna skorzystac. Jak beda jakies duze bledy przez to, to albo sie
naprawi albo wywali. Testowo mozna wrzucic?

Przetestowano na ekg2 przez dodanie p.use_sha1 = 2 przed gg_login(&p)
#v+
20:56:28 // gg_watch_fd() challenge 5cdf934a --> SHA1 hash: 
83c209ec3a96c1ec1f9ed936f5255c5342d64b88
[ciach]
20:56:28 // gg_watch_fd() sending GG_LOGIN70 packet
20:56:28 // gg_watch_fd() login succeded
#v-

Nazwy funkcji/typ do hashowania SHA1 sa poprzedzone LIBGADU_* tak na wszelki 
wypadek 
zeby nie kolidowalo z funkcjami z openssl zdefiniowanych w <openssl/sha.h>...

Nie wiem czy pakiet sie powinien nazywac GG_LOGIN70... moze GG_LOGIN65,
albo GG_LOGIN66, albo zupelnie inaczej. Mnie tam pasowalo GG_LOGIN70 ;)

Pakiet (struct gg_login70) jest troche mniej znany niz ten z struct gg_login60 
ale
aktualnie dziala... pola external_ip, external_port zawsze widzialem
wyzerowane, wiec nie powiem czy dokladnie jest takie samo przeznaczenie
tych pul.. Albo czy nie sa powinny byc wczesniej, np. w gg_login70.empty, ktore
wyglada na dosc spory obszar nie zarezerwowany.

Przypisywanie wartosci do odpowiednich struktur... uznalem ze pola ktore
znacza to samo moga byc definiowane w tych samych miejscach.. Jesli
lepiej zeby gg_login60 bylo definiowane w jednym ifie, a gg_login70 w
drugim, moge zmienic.

Funkcja kodujaca SHA1 wyciagnieta ze zrodel ekg2 i plugin jabber z
digest.c w wersji 1.6.. 
Mozna tez w sumie wykorzystac linkowanie sie z
bibloteka OpenSSL i korzystac stamtad z funkcji SHA1*() a jesli nie to w
ogole wylaczyc wsparcie dla hashowania, spowoduje to tez zmniejszenie o sporo
rozmiaru wynikowej latki.

Bede tez wdzieczny za jakiekolwiek inne komentarze odnosnie kodu.
Index: include/libgadu.h.in
===================================================================
RCS file: /home/cvs/libgadu/include/libgadu.h.in,v
retrieving revision 1.2
diff -u -p -r1.2 libgadu.h.in
--- include/libgadu.h.in        16 Nov 2006 17:16:34 -0000      1.2
+++ include/libgadu.h.in        11 Mar 2007 20:00:13 -0000
@@ -213,6 +213,8 @@ struct gg_session {
        int userlist_blocks;    /* na ile kawałków podzielono listę kontaktów */
 
        struct gg_image_queue *images;  /* aktualnie wczytywane obrazki */
+
+       int use_sha1;           /* czy mamy korzystac z hashowania hasla przy 
uzyciu SHA1 */
 };
 
 /*
@@ -425,8 +427,10 @@ struct gg_login_params {
        int tls;                        /* czy łączymy po TLS? */
        int image_size;                 /* maksymalny rozmiar obrazka w KiB */
        int era_omnix;                  /* czy udawać klienta era omnix? */
+       int use_sha1;                   /* czy uzywamy nowego logowania przy 
uzyciu gg_login70 i hashowania hasla przy uzyciu SHA1
+                                        * 0 - nie, 1 - tylko wtedy gdy jest 
odpowiedni protokol [XXX], 2 - zawsze */
 
-       char dummy[6 * sizeof(int)];    /* miejsce na kolejnych 6 zmiennych,
+       char dummy[5 * sizeof(int)];    /* miejsce na kolejnych 6 zmiennych,
                                         * żeby z dodaniem parametru nie 
                                         * zmieniał się rozmiar struktury */
 };
@@ -1000,6 +1004,7 @@ int gg_write(struct gg_session *sess, co
 void *gg_recv_packet(struct gg_session *sess);
 int gg_send_packet(struct gg_session *sess, int type, ...);
 unsigned int gg_login_hash(const unsigned char *password, unsigned int seed);
+void gg_login_hash_sha1(const unsigned char *password, unsigned int seed, 
unsigned char *result);
 uint32_t gg_fix32(uint32_t x);
 uint16_t gg_fix16(uint16_t x);
 #define fix16 gg_fix16
@@ -1083,6 +1088,24 @@ struct gg_login60 {
        uint8_t dunno2;                 /* 0xbe */
 } GG_PACKED;
 
+#define GG_LOGIN70 0x19
+
+struct gg_login70 {
+       uint32_t uin;                   /* mój numerek [gg_login60] */
+       uint8_t dunno0;                 /* 02 */
+       unsigned char hash[20];         /* sha1 [haslo i seed] */
+       unsigned char empty[44];        /* ??? duzo 00 ??? */
+       uint32_t status;                /* status na dzień dobry [gg_login60] */
+       uint32_t version;               /* moja wersja klienta [gg_login60] */
+       uint8_t dunno1;                 /* 0x00 [gg_login60] */
+       uint32_t local_ip;              /* mój adres ip [gg_login60] */
+       uint16_t local_port;            /* port, na którym słucham [gg_login60] 
*/
+       uint32_t external_ip;           /* XXX, untested */
+       uint16_t external_port;         /* XXX, untested */
+       uint8_t image_size;             /* maksymalny rozmiar grafiki w KiB 
[gg_login60] */
+       uint8_t dunno2;                 /* 0xbe [gg_login60] */
+} GG_PACKED;
+
 #define GG_LOGIN_OK 0x0003
 
 #define GG_LOGIN_FAILED 0x0009
Index: src/events.c
===================================================================
RCS file: /home/cvs/libgadu/src/events.c,v
retrieving revision 1.108
diff -u -p -r1.108 events.c
--- src/events.c        16 Nov 2006 17:16:36 -0000      1.108
+++ src/events.c        11 Mar 2007 20:00:14 -0000
@@ -1335,14 +1335,17 @@ struct gg_event *gg_watch_fd(struct gg_s
                        struct gg_header *h;                    
                        struct gg_welcome *w;
                        struct gg_login60 l;
-                       unsigned int hash;
+                       struct gg_login70 l70;
+                       unsigned int hash = 0;
                        unsigned char *password = (unsigned char*) 
sess->password;
                        int ret;
                        
                        gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() 
GG_STATE_READING_KEY\n");
 
                        memset(&l, 0, sizeof(l));
-                       l.dunno2 = 0xbe;
+                       memset(&l70, 0, sizeof(l70));
+                       l70.dunno0 = 0x02;
+                       l70.dunno2 = l.dunno2 = 0xbe;
 
                        /* XXX bardzo, bardzo, bardzo głupi pomysł na pozbycie
                         * się tekstu wrzucanego przez proxy. */
@@ -1397,9 +1400,18 @@ struct gg_event *gg_watch_fd(struct gg_s
                        w = (struct gg_welcome*) ((char*) h + sizeof(struct 
gg_header));
                        w->key = gg_fix32(w->key);
 
-                       hash = gg_login_hash(password, w->key);
+                       /* sprawdz czy mamy hashowac przy uzyciu starej funkcji 
hash gg_login_hash() */
+                       if (!sess->use_sha1) {
+                               hash = gg_login_hash(password, w->key);
        
-                       gg_debug_session(sess, GG_DEBUG_DUMP, "// gg_watch_fd() 
challenge %.4x --> hash %.8x\n", w->key, hash);
+                               gg_debug_session(sess, GG_DEBUG_DUMP, "// 
gg_watch_fd() challenge %.4x --> hash %.8x\n", w->key, hash);
+                       } else {        /* czy tez z hashowania dla nowego 
protokolu gg_login_hash_sha1() */
+                               gg_login_hash_sha1(password, w->key, l70.hash);
+
+                               gg_debug_session(sess, GG_DEBUG_DUMP, "// 
gg_watch_fd() challenge %.4x --> SHA1 hash: 
%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x\n",
 w->key, 
+                                               l70.hash[ 0], l70.hash[ 1], 
l70.hash[ 2], l70.hash[ 3], l70.hash[ 4], l70.hash[ 5], l70.hash[ 6], l70.hash[ 
7], l70.hash[ 8], l70.hash[ 9],
+                                               l70.hash[10], l70.hash[11], 
l70.hash[12], l70.hash[13], l70.hash[14], l70.hash[15], l70.hash[16], 
l70.hash[17], l70.hash[18], l70.hash[19]);
+                       }
        
                        free(h);
 
@@ -1420,28 +1432,33 @@ struct gg_event *gg_watch_fd(struct gg_s
 
                                if (!getsockname(sess->fd, (struct sockaddr*) 
&sin, &sin_len)) {
                                        gg_debug_session(sess, GG_DEBUG_MISC, 
"// gg_watch_fd() detected address to %s\n", inet_ntoa(sin.sin_addr));
-                                       l.local_ip = sin.sin_addr.s_addr;
+                                       l70.local_ip = l.local_ip = 
sin.sin_addr.s_addr;
                                } else {
                                        gg_debug_session(sess, GG_DEBUG_MISC, 
"// gg_watch_fd() unable to detect address\n");
-                                       l.local_ip = 0;
+                                       l70.local_ip = l.local_ip = 0;
                                }
                        } else 
-                               l.local_ip = gg_dcc_ip;
+                               l70.local_ip = l.local_ip = gg_dcc_ip;
                
-                       l.uin = gg_fix32(sess->uin);
-                       l.hash = gg_fix32(hash);
-                       l.status = gg_fix32(sess->initial_status ? 
sess->initial_status : GG_STATUS_AVAIL);
-                       l.version = gg_fix32(sess->protocol_version);
-                       l.local_port = gg_fix16(gg_dcc_port);
-                       l.image_size = sess->image_size;
+                       l70.uin         = l.uin         = gg_fix32(sess->uin);
+                                       l.hash          = gg_fix32(hash);       
/* hash dla l70 zostal juz ustawiony przez gg_login_hash_sha1() */
+                       l70.status      = l.status      = 
gg_fix32(sess->initial_status ? sess->initial_status : GG_STATUS_AVAIL);
+                       l70.version     = l.version     = 
gg_fix32(sess->protocol_version);
+                       l70.local_port  = l.local_port  = gg_fix16(gg_dcc_port);
+                       l70.image_size  = l.image_size  = sess->image_size;
                        
                        if (sess->external_addr && sess->external_port > 1023) {
                                l.external_ip = sess->external_addr;
                                l.external_port = gg_fix16(sess->external_port);
                        }
 
-                       gg_debug_session(sess, GG_DEBUG_TRAFFIC, "// 
gg_watch_fd() sending GG_LOGIN60 packet\n");
-                       ret = gg_send_packet(sess, GG_LOGIN60, &l, sizeof(l), 
sess->initial_descr, (sess->initial_descr) ? strlen(sess->initial_descr) : 0, 
NULL);
+                       if (!sess->use_sha1) {          /* dla slabszego hasha, 
korzystamy z GG_LOGIN60 */
+                               gg_debug_session(sess, GG_DEBUG_TRAFFIC, "// 
gg_watch_fd() sending GG_LOGIN60 packet\n");
+                               ret = gg_send_packet(sess, GG_LOGIN60, &l, 
sizeof(l), sess->initial_descr, (sess->initial_descr) ? 
strlen(sess->initial_descr) : 0, NULL);
+                       } else {                        /* dla SHA1 hasha, 
korzystamy z GG_LOGIN70 [XXX, nazwa] */
+                               gg_debug_session(sess, GG_DEBUG_TRAFFIC, "// 
gg_watch_fd() sending GG_LOGIN70 packet\n");
+                               ret = gg_send_packet(sess, GG_LOGIN70, &l70, 
sizeof(l70), sess->initial_descr, (sess->initial_descr) ? 
strlen(sess->initial_descr) : 0, NULL);
+                       }
 
                        free(sess->initial_descr);
                        sess->initial_descr = NULL;
Index: src/libgadu.c
===================================================================
RCS file: /home/cvs/libgadu/src/libgadu.c,v
retrieving revision 1.154
diff -u -p -r1.154 libgadu.c
--- src/libgadu.c       16 Nov 2006 17:16:36 -0000      1.154
+++ src/libgadu.c       11 Mar 2007 20:00:14 -0000
@@ -50,6 +50,33 @@
 #  include <openssl/rand.h>
 #endif
 
+
+#if !defined(WORDS_BIGENDIAN) && !defined(LITTLE_ENDIAN)
+#  define LITTLE_ENDIAN
+#endif
+
+#define SHA1HANDSOFF
+
+typedef struct {
+    uint32_t state[5];
+    uint32_t count[2];
+    unsigned char buffer[64];
+} LIBGADU_SHA1_CTX;
+
+/*
+SHA-1 in C
+By Steve Reid <[EMAIL PROTECTED]>
+100% Public Domain
+
+Test Vectors (from FIPS PUB 180-1)
+"abc"
+  A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+  84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+A million repetitions of "a"
+  34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+*/
+
 int gg_debug_level = 0;
 void (*gg_debug_handler)(int level, const char *format, va_list ap) = NULL;
 void (*gg_debug_handler_session)(struct gg_session *sess, int level, const 
char *format, va_list ap) = NULL;
@@ -170,6 +197,172 @@ unsigned int gg_login_hash(const unsigne
        return y;
 }
 
+/* SHA1 hash */
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+/* blk0() and blk() perform the initial expand. */
+/* I got the idea of expanding during the round function from SSLeay */
+#ifdef LITTLE_ENDIAN
+#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
+    |(rol(block->l[i],8)&0x00FF00FF))
+#else
+#define blk0(i) block->l[i]
+#endif
+#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
+    ^block->l[(i+2)&15]^block->l[i&15],1))
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) 
z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R1(v,w,x,y,z,i) 
z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) 
z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+
+/* Hash a single 512-bit block. This is the core of the algorithm. */
+
+static void LIBGADU_SHA1Transform(uint32_t state[5], const unsigned char 
buffer[64])
+{
+       uint32_t a, b, c, d, e;
+       typedef union {
+               unsigned char c[64];
+               uint32_t l[16];
+       } CHAR64LONG16;
+       CHAR64LONG16* block;
+#ifdef SHA1HANDSOFF
+       static unsigned char workspace[64];
+       block = (CHAR64LONG16*)workspace;
+       memcpy(block, buffer, 64);
+#else
+       block = (CHAR64LONG16*)buffer;
+#endif
+       /* Copy context->state[] to working vars */
+       a = state[0];
+       b = state[1];
+       c = state[2];
+       d = state[3];
+       e = state[4];
+       /* 4 rounds of 20 operations each. Loop unrolled. */
+       R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+       R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+       R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+       R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+       R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+       R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+       R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+       R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+       R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+       R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+       R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+       R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+       R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+       R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+       R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+       R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+       R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+       R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+       R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+       R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+       /* Add the working vars back into context.state[] */
+       state[0] += a;
+       state[1] += b;
+       state[2] += c;
+       state[3] += d;
+       state[4] += e;
+       /* Wipe variables */
+       a = b = c = d = e = 0;
+}
+
+
+/* SHA1Init - Initialize new context */
+
+static void LIBGADU_SHA1Init(LIBGADU_SHA1_CTX* context)
+{
+       /* SHA1 initialization constants */
+       context->state[0] = 0x67452301;
+       context->state[1] = 0xEFCDAB89;
+       context->state[2] = 0x98BADCFE;
+       context->state[3] = 0x10325476;
+       context->state[4] = 0xC3D2E1F0;
+       context->count[0] = context->count[1] = 0;
+}
+
+
+/* Run your data through this. */
+
+static void LIBGADU_SHA1Update(LIBGADU_SHA1_CTX* context, const unsigned char* 
data, unsigned int len)
+{
+       unsigned int i, j;
+
+       j = (context->count[0] >> 3) & 63;
+       if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
+       context->count[1] += (len >> 29);
+       if ((j + len) > 63) {
+               memcpy(&context->buffer[j], data, (i = 64-j));
+               LIBGADU_SHA1Transform(context->state, context->buffer);
+               for ( ; i + 63 < len; i += 64) {
+                       LIBGADU_SHA1Transform(context->state, &data[i]);
+               }
+               j = 0;
+       }
+       else i = 0;
+       memcpy(&context->buffer[j], &data[i], len - i);
+}
+
+
+/* Add padding and return the message digest. */
+
+static void LIBGADU_SHA1Final(unsigned char digest[20], LIBGADU_SHA1_CTX* 
context)
+{
+       uint32_t i, j;
+       unsigned char finalcount[8];
+
+       for (i = 0; i < 8; i++) {
+               finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 
1)]
+                                       >> ((3-(i & 3)) * 8) ) & 255);  /* 
Endian independent */
+       }
+       LIBGADU_SHA1Update(context, (unsigned char *)"\200", 1);
+       while ((context->count[0] & 504) != 448) {
+               LIBGADU_SHA1Update(context, (unsigned char *)"\0", 1);
+       }
+       LIBGADU_SHA1Update(context, finalcount, 8);  /* Should cause a 
SHA1Transform() */
+       for (i = 0; i < 20; i++) {
+               digest[i] = (unsigned char)
+                       ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+       }
+       /* Wipe variables */
+       i = j = 0;
+       memset(context->buffer, 0, 64);
+       memset(context->state, 0, 20);
+       memset(context->count, 0, 8);
+       memset(&finalcount, 0, 8);
+#ifdef SHA1HANDSOFF  /* make SHA1Transform overwrite it's own static vars */
+       LIBGADU_SHA1Transform(context->state, context->buffer);
+#endif
+}
+
+/**
+ * gg_login_hash_sha1()
+ *
+ * liczy hash z hasla i danego seeda, korzystajac z SHA1 
+ *
+ *  - password - haslo do hashowania
+ *  - seed - wartosc podana przez serwer
+ *  - result - przynajmniej 20 znakowy bufor ktory otrzyma hash
+ */
+
+void gg_login_hash_sha1(const unsigned char *password, unsigned int seed, 
unsigned char *result)
+{
+       LIBGADU_SHA1_CTX ctx;
+
+       LIBGADU_SHA1Init(&ctx);
+       LIBGADU_SHA1Update(&ctx, password, strlen(password));
+       LIBGADU_SHA1Update(&ctx, (unsigned char *) &seed, 4);
+
+       LIBGADU_SHA1Final(result, &ctx);
+}
+
 /*
  * gg_resolve() // funkcja wewnętrzna
  *
@@ -825,6 +1018,12 @@ struct gg_session *gg_login(const struct
                port = GG_APPMSG_PORT;
        }
 
+       /* Sprawdzmy czy program korzystajacy z libgadu chce zeby hasla byly 
silniej hashowane (przy uzyciu SHA1).
+        * Gdy use_sha 2 to zawsze, gdy 1 to trzeba znalezc wersje protokolu od 
ktorej oryginalny klient gg, to robi. 
+        */
+       if (p->use_sha1 == 2 || (p->use_sha1 == 1 && p->protocol_version > 
0xffff /* XXX */))
+               sess->use_sha1 = 1;
+
        if (!p->async) {
                struct in_addr a;
 
_______________________________________________
libgadu-devel mailing list
libgadu-devel@lists.ziew.org
http://lists.ziew.org/mailman/listinfo/libgadu-devel

Reply via email to