Jump to content


Κρυπτογραφία για προγραμματιστές


Jaco

Recommended Posts

Με αφορμή το post του Αστρολάβου περί ασφάλειας δεδομένων και κρυπτογράφησης, είπα να θυμηθώ λίγο τα παλιά και να δώσω έναν οδηγό για όσους ασχολούνται με τον προγραμματισμό και δεν έχουν ασχοληθεί με το θέμα της κρυπτογράφησης. Είχα ξαναγράψει ένα σχετικό άρθρο πριν από περίπου 10 χρόνια για το θέμα αυτό σε ένα άλλο φόρουμ, αλλά παρότι για τους κλασσικούς αλγόριθμους κρυπτογράφησης δεν έχουν αλλάξει πολλά, έχει κυλίσει πολύ νερό στο αυλάκι από τότε για το software development και κυρίως έχει αλλάξει το σκηνικό λόγο του internet. Το περίεργο είναι πως παρόλο που τα εργαλεία για την προστασία των δεδομένων είναι πλέον περισσότερα, παρόλ' αυτά χρησιμοποιούνται ελάχιστα σε σύγκριση με την προσπάθεια που γίνεται για την εκμαίευση πληροφοριών από τους χρήστες και τα δεδομένα τους. Από την μια την ευθύνη την έχουν οι ίδιοι οι χρήστες, καθότι αν αυτοί δεν επιδιώκουν την προστασία των δεδομένων τους, αυτά δεν θα είναι ποτέ ασφαλή και κατά δεύτερον οι developers οι οποίοι δεν φροντίζουν να γράψουν εφαρμογές που να προστατεύουν τα δεδομένα των χρηστών τους. Για το δεύτερο ευθύνεται η αδιαφορία ή η άγνοια των developers να κατανοήσουν την σημασία της ασφάλειας των δεδομένων, αλλά και η υποτιθέμενη δυσκολία της κρυπτογράφησης. Με τα εργαλεία που υπάρχουν πλέον η δυσκολία είναι απλά δικαιολογία και το μόνο που χρειάζεται είναι ένα layer παραπάνω στην εφαρμογή που να αναλαμβάνει το encryption, είτε αυτό είναι στην τοπική αποθήκευση των δεδομένων, είτε κυρίως στην μεταφορά τους μέσω διαδικτύου.

Πλέον τα πάντα έχουν απλοποιηθεί καθώς έχουν κυκλοφορήσει αρκετές βιβλιοθήκες για κρυπτογράφηση για διάφορες γλώσσες και επίσης δεν χρειάζεται πολύ ψάξιμο για να βρεθούν οι αλγόριθμοι αυτοί, αλλά και πολύ κόπος για να γίνουν port από την μια πλατφόρμα στην άλλη. Παρόλο όμως που τα πράγματα είναι πιο εύκολα, επειδή ο τομέας αυτός δεν έχει πολύ κίνηση και γενικά δεν είναι τόσο mainstream στον προγραμματισμό, υπάρχει μάλλον έλλειψη πληροφοριών και μια μικρή δυσκολία ώστε να μπορεί να ξεκινήσει κάποιος ο οποίος δεν έχει ασχοληθεί.

Σκοπός του άρθρου (αν μπορούμε να το πούμε έτσι) είναι να κάνουμε compile το libgcrypt και το gnupg στα windows και να γράψουμε ένα απλό πρόγραμμα που να χρησιμοποιεί έναν συμμετρικό αλγόριθμο κρυπτογράφησης, τον AES. Δεν θα πω πολλά λόγια περί αλγορίθμων και κρυπτογράφησης καθώς υπάρχουν αρκετά άρθρα στο internet που τα εξηγούν όλα πολύ αναλυτικά και καλύτερα απ' ότι θα το έκανα εγώ, αλλά θα δούμε βήμα-βήμα πως μπορούν να γίνουν compile αυτές οι βιβλιοθήκες στα windows και να γράψουμε ένα απλό πρόγραμμα. Στην συνέχεια θα δούμε πως από αυτό μπορούμε να φτιάξουμε μια δυναμική βιβλιοθήκη την οποία μπορούμε να την χρησιμοποιούμε σε οποιαδήποτε εφαρμογή θέλουμε και σε πληθώρα από πλατφόρμες και γλώσσες, οπότε έτσι μπορούμε να φτιάχνουμε δικά μας εργαλεία τα οποία κουμπώνουν σχεδόν παντού.

Αλγόριθμοι κρυπτόγραφησης.

Γενικά υπάρχουν 2 είδη αλγόριθμων κρυπτογράφησης, οι συμμετρικοί και οι ασύμμετροι. Οι συμμετρικοί είναι οι αλγόριθμοι οι οποίοι χρησιμοποιούν το ίδιο κλειδί για την κρυπτογράφηση και την αποκρυπτογράφηση, ενώ οι ασύμμετροι χρησιμοποιούν διαφορετικό (γνωστό και ως public key cryptography). Γνωστοί συμμετρικοί αλγόριθμοι είναι οι AES, DES, Serpent, Blowfish και Twofish, τους οποίους τους χρησιμοποιούν και προγράμματα όπως το truecrypt για την κρυπτογράφηση partitions και αρχείων και από αυτούς, ο πιο ευρεία χρησιμοποιημένος είναι ο AES που τον χρησιμοποιεί πληθώρα εφαρμογών, λόγο της ταχύτητάς του και της ασφάλειας που παρέχει (όπως το γνωστό μας 7-zip). Οι ασύμμετροι αλγόριθμοι από την άλλη είναι περισσότεροι λόγο του ότι παρέχουν μεγαλύτερη ασφάλεια και γενικά ελκύουν περισσότερη έρευνα λόγο της σύνθετης φύσης τους και του ανταγωνιστικού πνεύματος που επικρατεί κυρίως ακαδημαϊκά, για την εύρεση του καλύτερου αλγορίθμου. Οι πιο γνωστοί (και γενικά παλιοί) ασύμμετροι αλγόριθμοι κρυπτογράφησης είναι οι RSA και DSA.

Γενική αρχή είναι πως κανένας αλγόριθμος κρυπτογράφησης δεν παρέχει απόλυτη προστασία και όλοι θεωρητικά μπορούν να σπάσουν, άλλες φορές γρήγορα και άλλες φορές πιο αργά, ανάλογα με την εφαρμογή. Για παράδειγμα όταν μια επικοινωνία γίνεται συνεχώς με την χρήση του ίδιου συμμετρικού κλειδιού, τότε η πιθανότητα να σπάσει αυξάνει όσο το κλειδί παραμένει το ίδιο και αυξάνει ακόμα περισσότερο όσο αυξάνει ο όγκος των δεδομένων που κρυπτογραφείται με αυτό. Η μόνη κρυπτογράφηση αυτού του είδους που δεν μπορεί να σπάσει, είναι η χρήση ενός συμμετρικού αλγόριθμου κρυπτογράφησης του οποίου το κλειδί έχει το ίδιο μήκος/μέγεθος με το κείμενο το οποίο θα κρυπτογραφηθεί (one time pad keys) (One-time pad - Wikipedia, the free encyclopedia). Αυτό είναι ακόμα πιο ασφαλές αν το κείμενο είναι αρκετά μεγάλο σε μέγεθος, άρα και το κλειδί. Επίσης θεωρητικά όλοι οι μέθοδοι κρυπτογράφησης είναι ευάλωτες σε επιθέσεις τύπου brute force, αλλά επιτυχημένη κρυπτογράφηση είναι τελικά αυτή της οποία ο χρόνος που χρειάζεται για να σπάσει είναι μεγαλύτερος από τον χρόνο τον οποίο χρειάζεται να παραμείνει μυστικό το μήνυμα, καθώς μετά το πέρας του χρόνου η αξία της πληροφορίας είναι πια αδιάφορη. Τι γίνεται όμως με τα δεδομένα των χρηστών; Τι ασφάλεια πρέπει να έχουν; Πρακτικά, οποιαδήποτε κρυπτογράφηση απαιτεί μεγάλη επεξεργαστική ισχύ και χρόνο για να σπάσει είναι αρκετή, καθώς ο όγκος των δεδομένων που κυκλοφορεί πχ στο ιντερνετ είναι τόσο μεγάλος που πρακτικά δεν υπάρχει χρόνος και πόροι για να επεξεργαστούν τέτοια πληροφορία, εκτός και αν ο χρήστης και τα δεδομένα του είναι στοχευμένα. Ακόμα και τότε όμως η ασφάλεια μπορεί να είναι πολύ αυξημένη, πχ χρήση one-time-pad κλειδιών.

Τι θα χρειαστούμε.

Επειδή το gcrypt είναι γραμμένο για posix συστήματα, θα χρειαστούμε έναν gcc compiler και τις ανάλογες posix βιβλιοθήκες. Για τον λόγο αυτό κατεβάζουμε τον TDM-GCC. H τελευταία έκδοση τώρα είναι η 4.6.1, την οποία, ανεξάρτητα από το path που προτείνει ο installer την και εγκαθιστούμε στο C:\MinGW. Στην συνέχεια εγκαθιστούμε και το MSYS, το οποίο είναι μια συλλογή εργαλείων του unix για τα windows και την οποία θα χρειαστούμε. Το MSYS το εγκαθιστούμε από τον installer του mingw που κατεβάζουμε από εδώ (έκδοση 2011118 τώρα που γράφεται το κείμενο). Μόλις τρέξουμε τον installer επιλέγουμε να εγκαταστήσει μόνο το MSYS και τίποτα άλλο στο C:\MinGW. Αφού τελειώσουμε με τις δυο εγκαστάσεις τότε από το control panel → system → advanced system settings → Advanced → Environment Variables → System variables κάνουμε edit στο PATH και προσθέτουμε τις εξής δυο καταχωρήσεις

C:\MinGW\bin;C:\MinGW\msys\1.0\local\bin

Προσοχή στον χαρακτήρα “;” ανάμεσα σε κάθε path εκτός από το τέλος.

Στην συνέχεια κατεβάζουμε τα παρακάτω

Το libgcrypt είναι η βιβλιοθήκη η οποία προέκυψε από το gnupg και τα libgpg-error, libassuan, libksba, w32pth, zlib είναι βιβλιοθήκες που χρειάζονται για να γίνουν build το libcrypt και το gnupg που μας ενδιαφέρει.

Αφού τα κατεβάσουμε τα κάνουμε όπου θέλουμε extract με την χρήση του 7zip. Στην συνέχεια τρέχουμε το MinGW Shell από το start menu, το οποίο είναι ουσιαστικά το MSYS. Αν υποθέσουμε ότι τα αρχεία είναι στο C:\tmp τότε αρχίζουμε να κάνουμε configure και build τις βιβλιοθήκες μία-μία. Οπότε στο shell γράφουμε

 
$ cd /c/tmp/libgpg-error-1.9
$ ./configure
$ ./make
$ ./make install

το configure ψάχνει να βρει τα στοιχεία του συστήματος και αν πληρούνται οι προϋποθέσεις για να μπορέσει να γίνει build το source code και μόλις τελεώσει δημιουργεί ένα makefile. Με την make γίνεται build το makefile και με το install όλα τα αρχεία της βιβλιοθήκης αντιγράφονται μέσα στο bin και στο include του MSYS, οπότε μην τα ψάχνετε στο mingw, γι' αυτό πιο πάνω προσθέσαμε στο path το C:\MinGW\msys\1.0\local\bin.

Τα ίδια βήματα τα κάνουμε και τις υπόλοιπες βιβλιοθήκες

$ cd /c/tmp/libassuan-2.0.3
$ ./configure
$ ./make
$ ./make install

$ cd /c/tmp/libksba-1.2.0
$ ./configure
$ ./make
$ ./make install

$ cd /c/tmp/w32pth-2.0.4
$ ./configure
$ ./make
$ ./make install

Την βιβλιοθήκη του zlib τώρα πρέπει να την χακέψουμε λίγο και επειδή θα δυσκολευτείτε να βγάλετε άκρη, απλά ακολουθείτε το σφάλμα που σας βγάζει και μάλλον στην συγκεκριμένη περίπτωση θα διαμαρτυρηθεί και θα ζητήσει να την κάνουμε compile με το makefile για w32. Επειδή όμως θέλουμε να το παρακάμψουμε αυτό, ανοίγουμε το αρχείο “configure” μέσα στον φάκελο zlib-1.2.6 με ένα notepad και πάμε και κάνουμε comment την γραμμή στην οποία χτυπάει το σφάλμα του configurator και επιστρέφει με exit 1. Στην έκδοση που αναφερόμαστε, είναι η γραμμή 186 και απλά βάζουμε μια δίεση μπροστά για να γίνει

#exit 1

Οπότε μόλις φτάνει ο έλεγχος εκεί, απλά αγνοεί το σφάλμα και συνεχίζει, το οποίο όμως θέλουμε να συμβεί. Άρα και για το zlib κάνουμε τα παρακάτω

$ cd /c/tmp/zlib-1.2.6
$ ./configure
$ ./make
$ ./make install

Μετά για το libgcrypt απλά κάνουμε το παρακάτω

$ cd /c/tmp/libgcrypt-1.5.0
$ ./configure
$ ./make
$ ./make install

και τέλος για να μπορέσουμε να κάνουμε compile το gnupg, θα πρέπει πάλι να πειράξουμε μερικά makefiles γιατί για κάποιο λόγο τους λείπουν τα flags για την βιβλιοθήκη του zlib. Αυτό δεν ξέρω αν είναι παράλειψη των σχεδιαστών του zlib, αλλά δεν υπήρχε πουθενά το flag αυτό και σίγουρα χρειάζεται για να γίνει compile. Τέλος πάντων εκεί που χρειάστηκε να το προσθέσω είναι στα αρχεία

gnupg-2.0.18\g10\Makefile

gnupg-2.0.18\tools\Makefile

και απλά βρείτε την γραμμή που ξεκινάει με LIBGCRYPT_LIBS και προσθέστε στο τέλος το “-lz”, δηλαδή η γραμμή θα πρέπει να δείχνει ως εξής

LIBGCRYPT_LIBS = -L/usr/local/lib -lgcrypt -lgpg-error -lz

Λογικά μπορείτε να το βάλετε και αλλού, αλλά εκεί μου δούλεψε καθώς θεώρησα ότι είναι το default definition που καλεί το makefile.

Οπότε και για το gnupg έχουμε

$ cd /c/tmp/gnupg-2.0.18
$ ./configure
$ ./make

Το τελευταίο δεν χρειάζεται install γιατί δεν είναι βιβλιοθήκη.

Link to comment
Share on other sites

Πάμε τώρα να δούμε τι κάναμε. Σαν ide προτείνω τον eclipse-cdt ο οποίος συνεργάζεται άψογα με το mingw.

Αφού τον εγκαταστήσετε θα πρέπει να βρει μόνος του το mingw στο default path του, οπότε πάτε στο file → new → C project → Executable και διαλέγετε ένα “Hello world ANSI C project” από το project type και toolchain το “MinGW GCC”, διαλέγετε που θα σωθεί το αρχείο και δημιουργείτε το project. Μετά ανοίγετε το main.c αρχείο και πατάτε στον eclipse, Project → properties → C/C++ Build → Settings → Tool settings → GCC C Compiler → Includes και προσθέτετε στα include paths το “C:\MinGW\msys\1.0\local\include”. Τέλος με τον ίδιο τρόπο προσθέτετε στο Project → properties → C/C++ Build → Settings → Tool settings → MinGW C Linker → Libraries το “gcrypt” στα Libraries και το "C:\MinGW\msys\1.0\local\lib" στο Library search path. Έτσι μαθαίνουμε τον compiler που να αναζητήσει τις βιβλιοθήκες και τα αρχεία που χρειάζονται.

Δημιουργούμε τα παρακάτω αρχεία και βάζουμε τον παρακάτω κώδικα στο καθένα.

gcrypt_test.c


/*
============================================================================
Name : gcrypt_test.c
Author : Jaco
Version :
Copyright : meh
Description : Encryption/decryption test with gcrypt including b64
============================================================================
*/

#include <stdio.h>
#include <stdlib.h>
#include "C:\MinGW\msys\1.0\local\include\gcrypt.h"
#include "base64.h" //see: http://www.koders.com/c/fidDF059C42D2FEC30FDCBF3363492CEE8F24ED5252.aspx

char* Encrypt(const char * plaintext, const char * key, size_t * len);
char* b64Encrypt(const char * plaintext, const char * key, size_t * len);

char* Decrypt(const char * encBuffer, size_t encBufferLen, const char * key);
char* b64Decrypt(const char * b64encText, const char * key, size_t * len);
//char * Decrypt(const char * encBuffer, char * key);

int main(void) {

char plaintext[] = "This is the text we need to encrypt!";
char key[] = "just a plain text key :p";
size_t len = 0;

char * b64encText = NULL;

printf("plaintext: %s\n\n", plaintext);
printf("key: %s\n\n", key);

if ( (b64encText = b64Encrypt(plaintext, key, &len))) {
//printf( "Message successfully encrypted and coded.\n");
printf("enc + b64 = %s\n\n", b64encText);
}
printf("len: %d\n", len-1);

char * decText = NULL;
if ( (decText = b64Decrypt(b64encText, key, &len)) ) {
//printf( "Message successfully decrypted and decoded.\n");
printf("dec = %s\n", decText);
}
printf("len: %d\n", len-1);

free(b64encText);
free(decText);

return EXIT_SUCCESS;
}

/**
* @brief Encrypts a buffer with the given key and then encodes the result buffer to b64
* @see Encrypt
* @param[in] plaintext The buffer that will be encrypted
* @param[in] key The encryption key
* @param[out] len The returned buffer length
* @[U][URL="http://www.thelab.gr/member.php?u=12779"]ret[/URL][/U]val <char*> A pointer to the encrypted data
*/
char* b64Encrypt(const char * plaintext, const char * key, size_t * len)
{
char* encText = NULL; //encr buffer
char* b64Buffer = NULL; //encr+b64enc buffer
size_t encTextLen = 0; //buffer len

if ((encText = Encrypt(plaintext, key, &encTextLen))) { // Encrypt message
b64Buffer = encode_base64(encTextLen, (unsigned char*) encText); // Encode message to b64
}
free(encText); encText = NULL;
*len = strlen(b64Buffer)+1;
return(b64Buffer);
}

/**
* @brief Encrypts a buffer with the given encryption key
* @see b64Encrypt
* @param[in] plaintext The buffer that will be encrypted
* @param[in] key The encryption key
* @param[out] len The returned buffer length
* @[U][URL="http://www.thelab.gr/member.php?u=12779"]ret[/URL][/U]val <char*> A pointer to the encrypted data
*/
char* Encrypt(const char * plaintext, const char * key, size_t * len)
{
gcry_cipher_hd_t hdl; // handler
gcry_error_t err; // err container
char* encBuffer = NULL; // pointer to encr data

size_t bufferLen = strlen(plaintext)+1; // plaintext length + trailing zero
size_t totalLen = 16 - (bufferLen % 16) + bufferLen; // buffer len + padding/trailing zeros

char * paddedBuffer = malloc(totalLen); // allocate mem for the padded buffer
encBuffer = malloc(totalLen); // allocate mem for encr buffer

//memset(paddedBuffer, 0, totalLen); // this step isn't really needed, just fills buffer with zeros
memcpy(paddedBuffer, plaintext, bufferLen); // copy plaintext to zero-filled buffer

err = gcry_cipher_open(&hdl, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB, 0); //create gcrypt handle
if (err) goto handle_err;

err = gcry_cipher_setkey(hdl, key, gcry_cipher_get_algo_keylen(GCRY_CIPHER_AES128)); //set encr/dec key
if (err) goto handle_err;

err = gcry_cipher_setiv(hdl, NULL, gcry_cipher_get_algo_blklen(GCRY_CIPHER_AES128)); //initialize the default encr/dec vector
if (err) goto handle_err;

err = gcry_cipher_encrypt(hdl, encBuffer, totalLen, paddedBuffer, totalLen); //encrypt buffer
if (err) goto handle_err;

// Error handling
handle_err:
if (err) {
#ifdef DBG_PRNT
printf("Encryption error: %s, %s\n", gcry_strsource(err), gcry_strerror(err));
#endif
free(encBuffer); encBuffer = NULL; //release buffer
}

//Clean up
free(paddedBuffer); paddedBuffer = NULL; //release temporary buffer
gcry_cipher_close(hdl); //release handle
*len = totalLen;
return(encBuffer); //return the pointer to the encr data
}

/**
* @brief Decodes a b64 encoded buffer and then decrypts it with the decryption key
* @see Decrypt
* @param[in] b64encText The buffer that will be decoded and decrypted
* @param[in] key The decryption key
* @param[out] len The returned buffer length
* @[U][URL="http://www.thelab.gr/member.php?u=12779"]ret[/URL][/U]val <char*> A pointer to the decrypted data
*/
char* b64Decrypt(const char * b64encText, const char * key, size_t * len)
{
char * encBuffer = NULL;
char * decBuffer = NULL;
int decLen = 0; //decoded buffer len

encBuffer = malloc(strlen(b64encText));

if ( (decLen = decode_base64((unsigned char*) encBuffer, b64encText)) ) {
decBuffer = Decrypt(encBuffer, decLen, key);
}

free(encBuffer); encBuffer = NULL;
*len = strlen(decBuffer)+1;
return(decBuffer);
}

/**
* @brief Decrypts a buffer with the given decryption key
* @see b64Decrypt
* @param[in] encBuffer The buffer that will be encrypted
* @param[in] encBufferLen The buffer's length
* @param[in] key The decryption key
* @[U][URL="http://www.thelab.gr/member.php?u=12779"]ret[/URL][/U]val <char*> A pointer to the encrypted data
*/
char* Decrypt(const char * encBuffer, size_t encBufferLen, const char * key)
{
gcry_cipher_hd_t hdl;
gcry_error_t err;

char* decBuffer = malloc(encBufferLen); // allocate mem for encr buffer

err = gcry_cipher_open(&hdl, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB, 0); //create decryption handler
if (err) goto handle_err;

err = gcry_cipher_setkey(hdl, key, gcry_cipher_get_algo_keylen(GCRY_CIPHER_AES128)); //set decryption key
if (err) goto handle_err;

err = gcry_cipher_setiv(hdl, 0, gcry_cipher_get_algo_blklen(GCRY_CIPHER_AES128)); //set vector
if (err) goto handle_err;

err = gcry_cipher_decrypt(hdl, decBuffer, encBufferLen, encBuffer, encBufferLen); //decrypt
if (err) goto handle_err;

// Error handling
handle_err:
if (err) {
#ifdef DBG_PRNT
printf("Decryption error: %s, %s\n", gcry_strsource(err), gcry_strerror(err));
#endif
free(decBuffer); decBuffer = NULL; //release buffer
}

// clean up after ourselves
gcry_cipher_close(hdl); //close handle
return(decBuffer);
}

base64.h


/**
* Copyright (C), 2000-2007 by the monit project group.
* All Rights Reserved.
*
* 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 3 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, see <http: www.gnu.org="" licenses="">.
*/


#ifndef BASE64_H
#define BASE64_H

int decode_base64(unsigned char *dest, const char *src);
char *encode_base64(int size, unsigned char *src);

#endif /* BASE64_H_ */
[CODE][/SPOILER]




base64.cpp

[SPOILER][code]
/*
* Copyright (C), 2000-2007 by the monit project group.
* All Rights Reserved.
*
* 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 3 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, see <http: www.gnu.org="" licenses="">.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "base64.h"

/* Private prototypes */
static int is_base64(char c);
static char encode(unsigned char u);
static unsigned char decode(char c);


/**
* Implementation of base64 encoding/decoding.
*
* @author Jan-Henrik Haukeland, <hauk@tildeslash.com>
*
* @version \$Id: base64.c,v 1.19 2007/07/25 12:54:31 hauk Exp $
*
* @[U][URL="http://www.thelab.gr/member.php?u=3567"]fil[/URL][/U]e
*/



/* ------------------------------------------------------------------ Public */



/**
* Base64 encode and return size data in 'src'. The caller must free the
* returned string.
* @param size The size of the data in src
* @param src The data to be base64 encode
* @[U][URL="http://www.thelab.gr/member.php?u=12779"]ret[/URL][/U]urn encoded string otherwise NULL
*/
char *encode_base64(int size, unsigned char *src) {

int i;
char *out, *p;

if(!src)
return NULL;

if(!size)
size= strlen((char *)src);

out= (char*) malloc(size*4/3+4);

p= out;

for(i=0; i<size; i+="3)" {="">

unsigned char b1=0, b2=0, b3=0, b4=0, b5=0, b6=0, b7=0;

b1 = src[i];

if(i+1<size)>
b2 = src[i+1];

if(i+2<size)>
b3 = src[i+2];

b4= b1>>2;
b5= ((b1&0x3)<<4)|(b2>>4);
b6= ((b2&0xf)<<2)|(b3>>6);
b7= b3&0x3f;

*p++= encode(b4);
*p++= encode(b5);

if(i+1<size) {="">
*p++= encode(b6);
} else {
*p++= '=';
}

if(i+2<size) {="">
*p++= encode(b7);
} else {
*p++= '=';
}

}

return out;

}


/**
* Decode the base64 encoded string 'src' into the memory pointed to by
* 'dest'. The dest buffer is [B]not[/B] NUL terminated.
* @param dest Pointer to memory for holding the decoded string.
* Must be large enough to recieve the decoded string.
* @param src A base64 encoded string.
* @[U][URL="http://www.thelab.gr/member.php?u=12779"]ret[/URL][/U]urn TRUE (the length of the decoded string) if decode
* succeeded otherwise FALSE.
*/
int decode_base64(unsigned char *dest, const char *src) {

if(src && *src) {

unsigned char *p= dest;
int k, l= strlen(src)+1;
unsigned char *buf= (unsigned char*) malloc(l);


/* Ignore non base64 chars as per the POSIX standard */
for(k=0, l=0; src[k]; k++) {

if(is_base64(src[k])) {

buf[l++]= src[k];

}

}

for(k=0; k<l; k+="4)" {="">

char c1='A', c2='A', c3='A', c4='A';
unsigned char b1=0, b2=0, b3=0, b4=0;

c1= buf[k];

if(k+1<l) {="">

c2= buf[k+1];

}

if(k+2<l) {="">

c3= buf[k+2];

}

if(k+3<l) {="">

c4= buf[k+3];

}

b1= decode(c1);
b2= decode(c2);
b3= decode(c3);
b4= decode(c4);

*p++=((b1<<2)|(b2>>4) );

if(c3 != '=') {

*p++=(((b2&0xf)<<4)|(b3>>2) );

}

if(c4 != '=') {

*p++=(((b3&0x3)<<6)|b4 );

}

}

free(buf);

return(p-dest);

}

return 0;

}


/* ----------------------------------------------------------------- Private */


/**
* Base64 encode one byte
*/
static char encode(unsigned char u) {

if(u < 26) return 'A'+u;
if(u < 52) return 'a'+(u-26);
if(u < 62) return '0'+(u-52);
if(u == 62) return '+';

return '/';

}


/**
* Decode a base64 character
*/
static unsigned char decode(char c) {

if(c >= 'A' && c <= 'Z') return(c - 'A');
if(c >= 'a' && c <= 'z') return(c - 'a' + 26);
if(c >= '0' && c <= '9') return(c - '0' + 52);
if(c == '+') return 62;

return 63;

}


/**
* Return TRUE if 'c' is a valid base64 character, otherwise FALSE
*/
static int is_base64(char c) {

if((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
(c >= '0' && c <= '9') || (c == '+') ||
(c == '/') || (c == '=')) {

return 1;

}

return 0;

}


Όποιος θέλει μπορεί για ευκολία να κατεβάσει και τα αρχεία από εδώ.

Μόλις κάνουμε compile και τρέξουμε το πρόγραμμα θα δούμε το παρακάτω

attachment.php?attachmentid=48783&stc=1&d=1331987033

Με άλλα λόγια, αυτό που κάναμε είναι ότι πήραμε ένα κείμενο και το κρυπτογραφήσαμε με ένα κλειδί, επειδή όμως μετά την κρυπτογράφηση τα δεδομένα είναι σε binary μορφή χρησιμοποιήσαμε έναν base64 encoder και τα κωδικοποιήσαμε έτσι ώστε να είναι σε αναγνώσιμη μορφή και τυπώσαμε το αποτέλεσμα. Στην συνέχεια κάναμε την αντίστροφη διαδικασία, δηλαδή αποκωδικοποιήσαμε το base64 ξανά σε binary, το αποκρυπτογραφήσαμε με το ίδιο κλειδί και τυπώσαμε ξανά το κείμενο... Το αποτέλεσμα φαίνεται στην εικόνα παραπάνω.

Ο Αλγόριθμος κρυπτογράφησης που χρησιμοποιήθηκε είναι ο AES-128 τον οποίο μας τον παρέχει η βιβλιοθήκη του gcrypt.

post-5249-1416075943,4699_thumb.png

gcrypt_test.zip

Link to comment
Share on other sites

Ωραία όλ' αυτά αλλά ακόμα δεν έχει φανεί η πρακτικότητα του, οπότε πάμε να φτιάξουμε ένα dll με τον κώδικα αυτό, το γιατί θα το δούμε παρακάτω. Δημιουργούμε ένα καινούργιο C project στον eclipse με toolchain ξανά τον MinGW, αλλά αυτή τη φορά διαλέγουμε να φτιάξουμε ένα shared library project και του δίνουμε το όνομα gcrypt_dll. Ξανακάνουμε όπως και πριν την ίδια διαδικασία και προσθέτουμε τα δυο αρχεία 'base64.h' και 'base64.c', βάζουμε ξανά όπως και πριν τα σωστά paths από τις βιβλιοθήκες και τα includes και απλά στο αρχείο gcrypt_dll.c βάζουμε τα παρακάτω.

gcrypt_dll.c


/*
============================================================================
Name : gcrypt_dll.c
Author : Jaco
Version :
Copyright : meh
Description : AES Encryption/decryption using gcrypt and base-64 encoding
============================================================================
*/


#include <stdio.h>
#include <stdlib.h>
#include "C:\MinGW\msys\1.0\local\include\gcrypt.h"
#include "base64.h" //see: http://www.koders.com/c/fidDF059C42D2FEC30FDCBF3363492CEE8F24ED5252.aspx

__cdecl
char* Encrypt(const char * plaintext, const char * key, size_t * len);
__cdecl
char* b64Encrypt(const char * plaintext, const char * key, size_t * len);

__cdecl
char* Decrypt(const char * encBuffer, size_t encBufferLen, const char * key);
__cdecl
char* b64Decrypt(const char * b64encText, const char * key, size_t * len);


/**
* @brief Encrypts a buffer with the given key and then encodes the result buffer to b64
* @see Encrypt
* @param[in] plaintext The buffer that will be encrypted
* @param[in] key The encryption key
* @param[out] len The returned buffer length
* @[U][URL="http://www.thelab.gr/member.php?u=12779"]ret[/URL][/U]val <char*> A pointer to the encrypted data
*/
__cdecl
char* b64Encrypt(const char * plaintext, const char * key, size_t * len)
{
char* encText = NULL; //encr buffer
char* b64Buffer = NULL; //encr+b64enc buffer
size_t encTextLen = 0; //buffer len

if ((encText = Encrypt(plaintext, key, &encTextLen))) { // Encrypt message
b64Buffer = encode_base64(encTextLen, (unsigned char*) encText); // Encode message to b64
}
free(encText); encText = NULL;
*len = strlen(b64Buffer)+1;
return(b64Buffer);
}

/**
* @brief Encrypts a buffer with the given encryption key
* @see b64Encrypt
* @param[in] plaintext The buffer that will be encrypted
* @param[in] key The encryption key
* @param[out] len The returned buffer length
* @[U][URL="http://www.thelab.gr/member.php?u=12779"]ret[/URL][/U]val <char*> A pointer to the encrypted data
*/
__cdecl
char* Encrypt(const char * plaintext, const char * key, size_t * len)
{
gcry_cipher_hd_t hdl; // handler
gcry_error_t err; // err container
char* encBuffer = NULL; // pointer to encr data

size_t bufferLen = strlen(plaintext)+1; // plaintext length + trailing zero
size_t totalLen = 16 - (bufferLen % 16) + bufferLen; // buffer len + padding/trailing zeros

char * paddedBuffer = malloc(totalLen); // allocate mem for the padded buffer
encBuffer = malloc(totalLen); // allocate mem for encr buffer

//memset(paddedBuffer, 0, totalLen); // this step isn't really needed, just fills buffer with zeros
memcpy(paddedBuffer, plaintext, bufferLen); // copy plaintext to zero-filled buffer

err = gcry_cipher_open(&hdl, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB, 0); //create gcrypt handle
if (err) goto handle_err;

err = gcry_cipher_setkey(hdl, key, gcry_cipher_get_algo_keylen(GCRY_CIPHER_AES128)); //set encr/dec key
if (err) goto handle_err;

err = gcry_cipher_setiv(hdl, NULL, gcry_cipher_get_algo_blklen(GCRY_CIPHER_AES128)); //initialize the default encr/dec vector
if (err) goto handle_err;

err = gcry_cipher_encrypt(hdl, encBuffer, totalLen, paddedBuffer, totalLen); //encrypt buffer
if (err) goto handle_err;

// Error handling
handle_err:
if (err) {
#ifdef DBG_PRNT
printf("Encryption error: %s, %s\n", gcry_strsource(err), gcry_strerror(err));
#endif
free(encBuffer); encBuffer = NULL; //release buffer
}

//Clean up
free(paddedBuffer); paddedBuffer = NULL; //release temporary buffer
gcry_cipher_close(hdl); //release handle
*len = totalLen;
return(encBuffer); //return the pointer to the encr data
}

/**
* @brief Decodes a b64 encoded buffer and then decrypts it with the decryption key
* @see Decrypt
* @param[in] b64encText The buffer that will be decoded and decrypted
* @param[in] key The decryption key
* @param[out] len The returned buffer length
* @[U][URL="http://www.thelab.gr/member.php?u=12779"]ret[/URL][/U]val <char*> A pointer to the decrypted data
*/
__cdecl
char* b64Decrypt(const char * b64encText, const char * key, size_t * len)
{
char * encBuffer = NULL;
char * decBuffer = NULL;
int decLen = 0; //decoded buffer len

encBuffer = malloc(strlen(b64encText));

if ( (decLen = decode_base64((unsigned char*) encBuffer, b64encText)) ) {
decBuffer = Decrypt(encBuffer, decLen, key);
}

free(encBuffer); encBuffer = NULL;
*len = strlen(decBuffer)+1;
return(decBuffer);
}

/**
* @brief Decrypts a buffer with the given decryption key
* @see b64Decrypt
* @param[in] encBuffer The buffer that will be encrypted
* @param[in] encBufferLen The buffer's length
* @param[in] key The decryption key
* @[U][URL="http://www.thelab.gr/member.php?u=12779"]ret[/URL][/U]val <char*> A pointer to the encrypted data
*/
__cdecl
char* Decrypt(const char * encBuffer, size_t encBufferLen, const char * key)
{
gcry_cipher_hd_t hdl;
gcry_error_t err;

char* decBuffer = malloc(encBufferLen); // allocate mem for encr buffer

err = gcry_cipher_open(&hdl, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB, 0); //create decryption handler
if (err) goto handle_err;

err = gcry_cipher_setkey(hdl, key, gcry_cipher_get_algo_keylen(GCRY_CIPHER_AES128)); //set decryption key
if (err) goto handle_err;

err = gcry_cipher_setiv(hdl, 0, gcry_cipher_get_algo_blklen(GCRY_CIPHER_AES128)); //set vector
if (err) goto handle_err;

err = gcry_cipher_decrypt(hdl, decBuffer, encBufferLen, encBuffer, encBufferLen); //decrypt
if (err) goto handle_err;

// Error handling
handle_err:
if (err) {
#ifdef DBG_PRNT
printf("Decryption error: %s, %s\n", gcry_strsource(err), gcry_strerror(err));
#endif
free(decBuffer); decBuffer = NULL; //release buffer
}

// clean up after ourselves
gcry_cipher_close(hdl); //close handle
return(decBuffer);
}

Κάνουμε build το πρόγραμμα (επιλέξτε release) και προκύπτει το αρχείο libgcrypt_dll.dll.

Όποιος θέλει για ευκολία μπορεί να κατεβάζει το project από εδώ.

Αυτό που κάναμε τώρα είναι να δημιουργήσουμε μια δυναμική βιβλιοθήκη (dll) την οποία τώρα μπορούμε να χρησιμοποιήσουμε με οποιοδήποτε τρόπο, όπως θα δούμε στην συνέχεια.

Για να δούμε τώρα ποια entry points έχει το dll μας χρησιμοποιούμε το dllexp, το οποίο τελικά θα δούμε τα παρακάτω

attachment.php?attachmentid=48796&stc=1&d=1331989139

και τα δυο entrypoints που θα αγαπήσουμε στην συνέχεια είναι τα b64Encrypt και b64Decrypt, τα οποία μας παρέχουν και το encryption/decryption και το base64 encoding/decoding...

gcrypt_dll.zip

post-5249-1416075943,6251_thumb.png

Link to comment
Share on other sites

Η δύναμη μιας δυναμικής βιβλιοθήκης για τους προγραμματιστές είναι ότι τους δίνει την δυνατότητα να χρησιμοποιούν τον κώδικα που έχουν γράψει μια φορά, σε πολλές προγραμματιστικές πλατφόρμες ανάλογα με το project το οποίο πρέπει να φέρουν εις πέρας. Μιλώντας τώρα για windows λειτουργικά, μπορούμε να φτιάξουμε μια δυναμική βιβλιοθήκη που να παρέχει κρυπτογράφηση στον πελάτη μας και να μπορεί να ενσωματωθεί σε πληθώρα εφαρμογών που του έχουμε γράψει. Με τον τρόπο αυτό γράψαμε μια φορά τον κώδικα για την κρυπτογράφηση και τώρα μπορούμε να τον χρησιμοποιήσουμε σχεδόν παντού.

Πάμε να δούμε όμως και μερικά παραδείγματα των οποίων μπορείτε να κατεβάζετε και τον κώδικα για το καθένα.

C++/Qt (source)

attachment.php?attachmentid=48787&stc=1&d=1331988374


#include <QLibrary>
#include <QDebug>

int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);

QLibrary gcrypt("libgcrypt_dll.dll");
// Encoder
typedef char* (*b64Encoder)(const char * plaintext, const char * key, int * len);
b64Encoder encoder = (b64Encoder) gcrypt.resolve("b64Encrypt");
// Decoder
typedef char* (*b64Decoder)(const char * encBuffer, const char * key, int * len);
b64Decoder decoder = (b64Decoder) gcrypt.resolve("b64Decrypt");

QByteArray plaintext("This is the text we need to encrypt!");
QByteArray key("just a plain text key :p");

qDebug() << "plaintext: " << plaintext;
qDebug() << "\nkey: " << key;

if (encoder && decoder) {
int len;
char * encout = encoder(plaintext.constData(), key.constData(), &len);
qDebug() << "\nenc + b64: " << encout;

char * decout = decoder(encout, key.constData(), &len);
qDebug() << "\ndec: " << decout;

free(encout); encout = NULL;
free(decout); decout = NULL;
}

return a.exec();
}
#include <QtCore/QCoreApplication>

C# .net (VS2010) (source)

attachment.php?attachmentid=48789&stc=1&d=1331988499


using System.Runtime.InteropServices;


namespace cs_gcrypt_test
{

class Program
{
[DllImport("libgcrypt_dll.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern int b64Encrypt([MarshalAs(UnmanagedType.LPStr)] String plainText,
[MarshalAs(UnmanagedType.LPStr)] String key,
out IntPtr b64encOut);


[DllImport("libgcrypt_dll.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern int b64Decrypt([MarshalAs(UnmanagedType.LPStr)] String b64encText,
[MarshalAs(UnmanagedType.LPStr)] String key,
out IntPtr decBuffer);
//[MarshalAs(UnmanagedType.LPArray)] byte[] string_filled_in_dll,

static void Main(string[] args)
{
IntPtr strout = new IntPtr();

String plaintext = "This is the text we need to encrypt!";
String key = "just a plain text key :p";


Console.WriteLine("plaintext: " + plaintext);
Console.WriteLine("\nkey: " + key);

int res = b64Encrypt(plaintext, key, out strout);
String str = Marshal.PtrToStringAnsi(strout); //marshal pointer to str
Console.WriteLine("\nenc + b64: " + str);


IntPtr strout2 = new IntPtr();
res = b64Decrypt(str, key, out strout2);
str = Marshal.PtrToStringAnsi(strout2); //marshal pointer to str
Console.WriteLine("\ndec: " + str);

Console.Read();
}
}
}
using System;

qt_gcrypt_test.zip

post-5249-1416075943,5265_thumb.png

cs_gcrypt_test.zip

post-5249-1416075943,5474_thumb.png

Link to comment
Share on other sites

Delphi (fpc + lazarus) (source)

attachment.php?attachmentid=48790&stc=1&d=1331988691



{$mode objfpc}{$H+}

uses {$IFDEF UNIX} {$IFDEF UseCThreads}
cthreads, {$ENDIF} {$ENDIF}
Classes,
SysUtils,
CustApp,
Windows { you can add units after this };

type

{ TMyApplication }

TMyApplication = class(TCustomApplication)
protected
procedure DoRun; override;
public
constructor Create(TheOwner: TComponent); override;
destructor Destroy; override;
end;

{ TMyApplication }

function b64Encrypt(plaintext: PAnsiChar; key: PAnsiChar; out len: Pointer): PAnsiChar;
cdecl; external 'libgcrypt_dll.dll' Name 'b64Encrypt';

function b64Decrypt(encBuffer: PAnsiChar; key: PAnsiChar; out len: Pointer): PAnsiChar;
cdecl; external 'libgcrypt_dll.dll' Name 'b64Decrypt';

procedure TMyApplication.DoRun;
var
ErrorMsg: string;
plaintext: ansistring;
key: ansistring;
encText: PAnsiChar = nil;
decText: PAnsiChar = nil;
len: integer;

begin

{ add your program here }
plaintext := 'This is the text we need to encrypt!';
key := 'just a plain text key :p';

Writeln('plaintext: ' + plaintext + #13#10);
Writeln('key: ' + key + #13#10);

encText := b64Encrypt(PAnsiChar(plaintext), PAnsiChar(key), Pointer(len));
Writeln('enc: ' + encText + #13#10);

decText := b64Decrypt(encText, PAnsiChar(key), Pointer(len));
Writeln('dec: ' + decText);

Readln;
Terminate;
end;

constructor TMyApplication.Create(TheOwner: TComponent);
begin
inherited Create(TheOwner);
StopOnException := True;
end;

destructor TMyApplication.Destroy;
begin
inherited Destroy;
end;

var
Application: TMyApplication;

{$R *.res}

begin
Application := TMyApplication.Create(nil);
Application.Title := 'fpc_gcrypt_test';
Application.Run;
Application.Free;
end.
program fpc_gcrypt_test;

Perl (source)

attachment.php?attachmentid=48792&stc=1&d=1331988720


use warnings;
use Win32::API;

my $encrypt = Win32::API->new('libgcrypt_dll','b64Encrypt','PPP','P', '_cdecl') or die $^E;
my $decrypt = Win32::API->new('libgcrypt_dll','b64Decrypt','PPP','P', '_cdecl') or die $^E;

my $plaintext = 'This is the text we need to encrypt!';
my $key = 'just a plain text key :p';
my $len = ""; #just create the instance
print "\n\nplaintext: ".$plaintext."\n\n";
print "key: ".$key."\n\n";
my $enc = $encrypt->Call($plaintext, $key, \$len); #call encrypt function from dll
print "enc: ".$enc."\n\n";
my $dec = $decrypt->Call($enc, $key, \$len); #call decrypt function from dll
print "dec: ".$dec."\n\n";
use strict;

post-5249-1416075943,5602_thumb.png

fpc_gcrypt_test.zip

post-5249-1416075943,5871_thumb.png

pl_gcrypt_test.zip

Link to comment
Share on other sites

Ruby (source)

attachment.php?attachmentid=48794&stc=1&d=1331988934


require 'dl'

encrypt = Win32API.new('libgcrypt_dll', 'b64Encrypt', ['P', 'P', 'PI'], 'P')
decrypt = Win32API.new('libgcrypt_dll', 'b64Decrypt', ['P', 'P', 'P'], 'P')

plaintext = "This is the text we need to encrypt!"
key = "just a plain text key :p"
puts "plaintext: " + plaintext + "\n\n"
puts "key: " + key + "\n\n"

len_ = [0].pack("l") #create the int pointer
enc = DL::CPtr[encrypt.Call(plaintext,key,len_)] #use CPtr to get data
len = len_.unpack("l").first #get value from int pointer (not really needed it's the length)
encStr = enc.to_s().gsub("cp/rub","") #this is ruby bug that adds "cp/rub" at the end of a c string
DL.free enc #free mem
puts "enc: " + encStr + "\n\n"

dec = DL::CPtr[decrypt.Call(encStr,key,len_)] #use CPtr to get data
decStr = dec.to_s()
puts "dec: " + decStr + "\n\n"
DL.free dec

exit = gets()
require 'Win32API'

post-5249-1416075943,6073_thumb.png

rb_gcrypt_test.zip

Link to comment
Share on other sites

Εδώ ας πούμε και μερικές λεπτομέρειες εν τάχει...

Καταρχήν παρέλειψα επίτηδες την java γιατί ως γνωστών για να χρησιμοποιήθεί σε αυτή κάποιο dll, θα πρέπει να φτιαχτεί άλλος C++ wrapper και να φορτωθεί μέσω JNI και επειδή αυτό είναι ολίγον τραγικό, το αφήνω σε όποιον έχει όρεξη...

Επίσης, επιλέξαμε το dll γιατί μας προσφέρει την ταχύτητα εκτέλεσης του binary κώδικα και επειδή είναι portable για όλες σχεδόν τις πλατφόρμες. Παρόλ' αυτά όμως χρειάζεται προσοχή στο πως γράφουμε τον κώδικα γιατί δεν υποστηρίζουν όλες οι γλώσσες και τα frameworks αυτά που υποστηρίζει η C. Για παράδειγμα η συνάρτηση που κάνει το encryption είναι η παρακάτω

char* b64Encrypt(const char * plaintext, const char * key, size_t * len);

Αυτή επιστρέφει έναν pointer στα κρυπτογραφημένα δεδομένα τα οποία είναι πλέον ευθύνη του προγραμματιστή να ελευθερώσει την μνήμη.. Το καλό εδώ είναι ότι η μνήμη θα ελευθερωθεί ούτως ή άλλως μόλις τερματίσει το πρόγραμμα, αλλά παρόλ' αυτά χρειάζεται προσοχή στον χειρισμό και επίσης δεν μπορούν όλες οι γλώσσες να απελευθερώσουν την μνήμη αυτή...

Κάποιος όμως θα παρατηρούσε και θα έλεγε, "ωραία, αλλά αυτό δεν είναι πιο σωστό;"

int b64Encrypt(const char * plaintext, const char * key, char** enctext);

Δηλαδή να επιστρέφει το μήκος και να έχει σαν τρίτη παράμετρο έναν pointer σε ένα array για τον buffer...? Όντως, αυτό θα ήταν πιο "όμορφο" και πάλι θα έκανε την ίδια ακριβώς δουλειά, όμως όταν γράφουμε με σκοπό να χρησιμοποιήσουμε αυτό το dll σε πολλές γλώσσες προγραμματισμού, θέλει προσοχή. Για παράδειγμα, ενώ η Qt, η C# και η delphi δεν έχουν πρόβλημα να χειριστούν τέτοιους pointers, η scripting γλώσσες έχουν, γιατί δεν έχουν εξελιχθεί ώστε να χειρίζονται τέτοιου τύπου δεδομένα.

Οπότε αυτό που καταφέραμε είναι να φτιάξουμε προγραμματιστικά ένα τρόπο κρυπτογράφησης δεδομένων, τον οποίο μπορούμε πλέον να χρησιμοποιήσουμε σχεδόν παντού. Αν και τα παραδείγματα είναι επίτηδες απλοϊκά, μπορείτε να τα χρησιμοποιήσετε για να φτιάξετε ένα κώδικα που να κάνει κάτι χρήσιμο. Τα εργαλεία πλέον υπάρχουν και είναι εύκολα, οπότε οι προγραμματιστές πρέπει να τα χρησιμοποιούν για την καλύτερη ασφάλεια των δεδομένων των πελατών τους.

Link to comment
Share on other sites

Ωραίο άρθρο! Μία μικρή διόρθωση στο "θεωρητικό" κομμάτι:

Οι ασύμμετροι αλγόριθμοι από την άλλη είναι περισσότεροι λόγο του ότι παρέχουν μεγαλύτερη ασφάλεια και γενικά ελκύουν περισσότερη έρευνα λόγο της σύνθετης φύσης τους και του ανταγωνιστικού πνεύματος που επικρατεί κυρίως ακαδημαϊκά, για την εύρεση του καλύτερου αλγορίθμου. Οι πιο γνωστοί (και γενικά παλιοί) ασύμμετροι αλγόριθμοι κρυπτογράφησης είναι οι RSA και DSA

Οι ασύμμετροι αλγόριθμοι δεν είναι πιο ασφαλείς.

Για την ακρίβεια τα κλειδιά τους πρέπει να είναι πολύ μεγαλύτερα από έναν αντίστοιχο συμμετρικό αλγόριθμο για να προσφέρουν τον ίδιο επίπεδο ασφαλείας.

Τα μεγάλα σχετικά κλειδιά σε συνδυασμό με τις πολύπλοκες (υπολογιστικά) διαδικασίες που απαιτούνται, είναι οι βασικοί λόγοι που καθιστούν υπολογιστικά ακριβή διαδικασία την ασύμμετρη κρυπτογράφηση/αποκρυπτογράφηση - ειδικά, δε, σε σύγκριση με τα συμμετρικά σχήματα.

Είναι όμως απαραίτητα εργαλεία σε πολλές σύγχρονες εφαρμογές διότι, σε αντίθεση με τους συμμετρικούς, δεν απαιτούν την ύπαρξη ασφαλούς καναλιού για την συμφωνία/επικοινωνία του μυστικού κλειδιού (με ό,τι αυτό συνεπάγεται). Αυτό το πολύ σημαντικό τους πλεονέκτημα, σε συνδυασμό με τα θέματα απόδοσης που έχουν (τα οποία είναι ακόμα πιο σημαντικά στις μέρες μας με το ambient computing, τις φορητές συσκευές και γενικώς τα resource-starved συστήματα) στρέφουν την έρευνα περισσότερο σε αυτούς.

Στην πράξη συνήθως επιλέγουμε υβριδικά συστήματα (βλ. SSL, PGP μεταξύ άλλων) όπου ξεκινάμε με έναν ασύμμετρο αλγόριθμό για την αρχική "γνωριμία" των συστημάτων και τη δημιουργία ασφαλούς καναλιού μέσα από το οποίο θα μεταδοθεί ένα μυστικό κλειδί. Όταν και τα δύο μέρη λάβουν και συμφωνήσουν σε αυτό, ο κύριος όγκος της κρυπτογράφησης γίνεται με έναν ταχύτερο, συμμετρικό αλγόριθμο και το παραπάνω μυστικό κλειδί. Πολύ χοντρικά, γιατί υπάρχουν και ανταλλαγές πιστοποιητικών, έλεγχοι ακεραιότητας κλπ, αλλά you get the idea.

Link to comment
Share on other sites

Βέβαια, οι υβριδικοί είναι αυτοί που έχουν επικρατήσει και το πιο χαρακτηριστικό παράδειγμα που χρησιμοποιούμε οι περισσότεροι, είναι το γνωστό μας ssh... Απλά η αυξημένη ασφάλεια των ασύμμετρων σε σχέση με τους συμμετρικούς είναι στο ότι σε κανονικές συνθήκες, από το public δεν μπορείς να βγάλεις το private...

Πάντως οι πιο ασφαλείς αλγόριθμοι κρυπτογράφησης είναι αυτοί που δεν φέρουν το "RFC" στην αρχή του τίτλου τους και γενικά δεν έχουν δημοσιευτεί... :p

Link to comment
Share on other sites

Βέβαια, οι υβριδικοί είναι αυτοί που έχουν επικρατήσει και το πιο χαρακτηριστικό παράδειγμα που χρησιμοποιούμε οι περισσότεροι, είναι το γνωστό μας ssh... Απλά η αυξημένη ασφάλεια των ασύμμετρων σε σχέση με τους συμμετρικούς είναι στο ότι σε κανονικές συνθήκες, από το public δεν μπορείς να βγάλεις το private...

Δεν τους δίνει παραπάνω ασφάλεια αυτό το χαρακτηριστικό.

Απλά είναι μία βασική αρχή πάνω στην οποία βασίζονται για να ξεπεραστεί η ανάγκη ύπαρξης του ασφαλούς καναλιού που λέγαμε παραπάνω. Αν έπρεπε να συγκρίνουμε συμμετρικούς και ασύμμετρους, οι πρώτοι είναι πιο ασφαλείς με την έννοια ότι προσφέρουν ένα Χ επίπεδο ασφάλειας με μικρότερα κλειδιά από ότι οι αντίστοιχοι συμμετρικοί.

Τα δύο κλειδιά (ιδιωτικό και δημόσιο) που φέρει κάθε οντότητα συνδέονται μεταξύ τους με μία μαθηματική σχέση που (θεωρητικά) είναι δύσκολο να "λυθεί" (π.χ. παραγοντοποίηση γινομένου αρκετά μεγάλων πρώτων αριθμών στην περίπτωση του RSA). Αν αύριο βρούμε εύκολο τρόπο να λύνουμε το πρόβλημα αυτό καταρρέει και η ασφάλεια των ασύμμετρων που στηρίζονται σε αυτό.

Πάντως οι πιο ασφαλείς αλγόριθμοι κρυπτογράφησης είναι αυτοί που δεν φέρουν το "RFC" στην αρχή του τίτλου τους και γενικά δεν έχουν δημοσιευτεί... :p

Δε θα το έλεγα. Οι πιο ασφαλείς αλγόριθμοι είναι αποδεδειγμένα αυτοί που τους έχουν δει περισσότερα μάτια (από ακαδημαϊκή κοινότητα, industry, enthusiasts κλπ). Tα παραδείγματα στην ιστορία της κρυπτογραφίας είναι πολλά.

To concept "security through obscurity" δεν δουλεύει τόσο καλά στην πράξη και η σύσταση είναι να αποφεύγεται.

Γι'αυτό άλλωστε τα standards σε αλγορίθμους κρυπτογράφησης, συναρτήσεις κατακερματισμού και λοιπά cryptographic primitives (που προκύπτουν από ανοικτούς διεθνείς διαγωνισμούς) είναι και αυτά που συστήνουν η NIST, η SANS και οι λοιποί φορείς για εφαρμογή σε κρατικές υπηρεσίες, εταιρείες κλπ.

Δεν πρέπει να ανησυχούμε για τους αλγορίθμους αλλά για την σωστή εφαρμογή τους στα πλαίσια ενός κρυπτοσυστήματος (ο αδύναμος κρίκος είναι ο άνθρωπος).

Link to comment
Share on other sites

Στο δεύτερο κομμάτι θα διαφωνήσω, γιατί η μυστικότητα ενός αλγόριθμου, ειδικά στην κρυπτογραφία, είναι αυτή που διαφυλάσσει καλύτερα την ασφάλεια του... και επίσης όσο μη συμβατικός είναι αυτός ο αλγόριθμος (δηλαδή έχει ανοχή στις εντροπίες, επαναληψημότητα κλπ), τόσο μεγαλύτερη ασφάλεια παρέχει, γιατί δεν θα δουλέψουν τα στάνταρ εργαλεία και μέθοδοι που θα τον σπάσουν... Είναι αλλιώς να ξέρει κάποιος πως από το Α πήγες στο Β και τελείως διαφορετικό όταν δεν έχει ιδέα...

Επίσης μην ξεχνάμε ότι η χρήση πιστοποιημένων αλγορίθμων κρυπτογράφησης, πέρα από την πιστοποιημένη ασφάλεια παρέχουν και πιστοποιημένο τρόπο να τους σπάσεις, γιατί ακόμα και με brute force μέθοδο θα βαδίζεις σε στάνταρ αλγόριθμους και όχι στα τυφλά...

Edit:

Επίσης ο λόγος που είπα ότι οι ασύμμετροι είναι πιο ασφαλείς, είναι ότι το προσωπικό σου κλειδί παραμένει πάντα κρυφό και δεν μπορεί να βρεθεί από το δημόσιο, ενώ στους συμμετρικούς αναγκαστικά μοιράζεσαι το ίδιο κλειδί με τον άλλο... αυτό φυσικά και παρέχει μεγαλύτερη ασφάλεια δεν νομίζεις...? 'Αλλο που η ταχύτητα είναι αρκετά μικρότερη, αυτό δεν έχει να κάνει με την ασφάλεια...

Link to comment
Share on other sites

Στο δεύτερο κομμάτι θα διαφωνήσω, γιατί η μυστικότητα ενός αλγόριθμου, ειδικά στην κρυπτογραφία, είναι αυτή που διαφυλάσσει καλύτερα την ασφάλεια του... και επίσης όσο μη συμβατικός είναι αυτός ο αλγόριθμος (δηλαδή έχει ανοχή στις εντροπίες, επαναληψημότητα κλπ), τόσο μεγαλύτερη ασφάλεια παρέχει, γιατί δεν θα δουλέψουν τα στάνταρ εργαλεία και μέθοδοι που θα τον σπάσουν... Είναι αλλιώς να ξέρει κάποιος πως από το Α πήγες στο Β και τελείως διαφορετικό όταν δεν έχει ιδέα...

Με συγχωρείς αλλά αυτά είναι εικασίες/απόψεις.

O καθένας μπορεί να νομίζει ότι είναι σε θέση να φτιάξει έναν αλγόριθμο καλύτερο/ασφαλέστερο από τον RSA, τον AES κλπ, αλλά στην πραγματικότητα ελάχιστοι μπορούν, οπότε οι υπόλοιποι απλά τρώνε τα μούτρα τους.

Δεν υπάρχει καλύτερη πιστοποίηση για την ασφάλεια ενός αλγορίθμου από τους peer-reviewed διεθνείς διαγωνισμούς.

Εγώ σου αναφέρω ποιά είναι η σύσταση από τους αρμόδιους φορείς, τι μαθαίνουν στα InfoSec MSc κλπ.

Στο παραπάνω link που έδωσα, θα διάβασες:

Security through obscurity has never achieved engineering acceptance as an approach to securing a system, as it contradicts the principle of "keeping it simple". The United States National Institute of Standards and Technology (NIST) specifically recommends against security through obscurity in more than one document. Quoting from one, "System security should not depend on the secrecy of the implementation or its components."

Από εκεί και πέρα ο καθένας κάνει ό,τι νομίζει για την εταιρεία στην οποία εργάζεται (αν του το επιτρέπει η θέση του) και αναλαμβάνει και την ευθύνη αν κάτι πάει στραβά.

Αν, αν λέμε, υπάρξει κάποιο incident και η εταιρεία δουλεύει proprietary λύση (την οποία "πήρες πάνω σου" ως επιλογή), καλή τύχη στο υπόλοιπο της καριέρας σου.

Αν κάτι πάει στραβά και εσύ έκανες ό,τι ήταν ανθρωπίνως για να εφαρμόσεις το good practice και τα σχετικά standards που το συνοδεύουν, το incident θα είναι μία στατιστική ή το πολύ-πολύ να φέρει κάποιο review πολιτικής ασφαλείας κλπ. Δεν θα σε πάρει μαζί του.

Επίσης μην ξεχνάμε ότι η χρήση πιστοποιημένων αλγορίθμων κρυπτογράφησης, πέρα από την πιστοποιημένη ασφάλεια παρέχουν και πιστοποιημένο τρόπο να τους σπάσεις, γιατί ακόμα και με brute force μέθοδο θα βαδίζεις σε στάνταρ αλγόριθμους και όχι στα τυφλά...

Αν υπάρχει πιστοποιημένος τρόπος να σπάσεις έναν αλγόριθμό, δεν υπάρχει πιστοποιημένη ασφάλεια ή, στην καλύτερη, υπάρχει πιστοποιημένη περιορισμένη ασφάλεια την οποία οφείλεις να γνωρίζεις και άρα να χρησιμοποιείς μόνο όταν σου αρκεί για τη συγκεκριμένη εφαρμογή.

Σε οποιαδήποτε υπόνοια "σπασίματος" κάποιου αλγορίθμου, ανανεώνονται άμεσα οι σχετικές συστάσεις από NIST κλπ και προτείνονται εναλλακτικές λύσεις.

Επίσης ο λόγος που είπα ότι οι ασύμμετροι είναι πιο ασφαλείς, είναι ότι το προσωπικό σου κλειδί παραμένει πάντα κρυφό και δεν μπορεί να βρεθεί από το δημόσιο, ενώ στους συμμετρικούς αναγκαστικά μοιράζεσαι το ίδιο κλειδί με τον άλλο... αυτό φυσικά και παρέχει μεγαλύτερη ασφάλεια δεν νομίζεις...? 'Αλλο που η ταχύτητα είναι αρκετά μικρότερη, αυτό δεν έχει να κάνει με την ασφάλεια...

Βρε συ, δεν είναι τι νομίζω εγώ ή εσύ. :p

Όλα αυτά ανήκουν στην Κρυπτογραφία και είναι ένας πολύ συγκεκριμένος επιστημονικός κλάδος στον οποίο τυχαίνει να κάνω Διδακτορικό.

Άπτεται των μαθηματικών και έχει επαρκέστατη βιβλιογραφία. Πιάσε όποιο σχετικό βιβλίο θέλεις να τα δεις. :T:

Link to comment
Share on other sites

Πάντως θα με ενδιέφερε σίγουρα να μάθω γιατί η συμμετρική κρυπτογράφηση είναι πιο ασφαλής από την ασύμμετρη, αν έχεις κάποια βιβλιογραφία πες μου... Μπορεί να έχω καταλάβει λάθος...

Για το security through obscurity πάντως στο ίδιο link που παρέθεσες αναφέρει

The principle of security through obscurity was more generally accepted in cryptographic work in the days when essentially all well-informed cryptographers were employed by national intelligence agencies, such as the National Security Agency. Now that cryptographers often work at universities, where researchers publish many or even all of their results, and publicly test others' designs, or in private industry, where results are more often controlled by patents and copyrights than by secrecy, the argument has lost some of its former popularity.
Κοινώς, δεν είναι αποδεδειγμένα κακή πρακτική ή μη ασφαλής, απλά λέει ότι προστίθεται άλλη μια παράμετρος ασφάλειας που έχει να κάνει με το να παραμείνει και ο αλγόριθμος, πέρα από το κλειδί... Επίσης αν ήταν όντως κακή πρακτική, τότε γιατί η βιομηχανία που έχει πραγματικά ανάγκη την κρυπτογράφηση χρησιμοποιεί ακόμα τέτοιες πρακτικές ...? πχ στρατιωτικές εφαρμογές, αλλά και τηλεπικοινωνιακές...

Προσωπική εκτίμηση μου είναι ο έλεγχος των κρυπτογραφικών μεθόδων μέσω οργανισμών κτλ, αποσκοπεί περισσότερο στην γνώση και τον έλεγχο της πληροφορίας πάνω έρευνας στον χώρο, παρά στην πραγματική ασφάλεια...

Edit:

Τώρα το εμπέδωσα, έγραψες για το μήκος των κλειδιών (συμμετρική/ασύμμετρη), έχεις δίκιο... μου κόλλησε το επίπεδο ασφάλειας, ότι είναι χαμηλότερο στους ασύμμετρους...

Link to comment
Share on other sites

Για τα κλειδιά, ένα πρόχειρο link που βρήκα:

http://www.ecrypt.eu.org/documents/D.SPA.7.pdf

Για τους "κλειστούς" αλγορίθμους το κράξιμο είναι άπειρο στο net από τους ειδικούς (ανθρώπους του industry, ακαδημαϊκούς κλπ)... Ψάξε για proprietary cryptographic algorithms και θα πειστείς.

Ενδεικτικά τι λέει ο Bruce Schneier (καλά, κράζει με κάθε ευκαιρία, αλλά αυτό βρήκα άμεσα):

Some rely on proprietary encryption algorithms. Invariably, these are very weak. Counterpane has had considerable success breaking published encryption algorithms; our track record against proprietary ones is even better. Keeping the algorithm secret isn't much of an impediment to analysis, anyway--it only takes a couple of days to reverse-engineer the cryptographic algorithm from executable code. One system we analyzed, the S/MIME 2 electronic-mail standard, took a relatively strong design and implemented it with a weak cryptographic algorithm. The system for DVD encryption took a weak algorithm and made it weaker.

We've seen many other cryptographic mistakes: implementations that repeat "unique" random values, digital signature algorithms that don't properly verify parameters, hash functions altered to defeat the very properties they're being used for. We've seen cryptographic protocols used in ways that were not intended by the protocols' designers, and protocols "optimized" in seemingly trivial ways that completely break their security.

Ένα άλλο σχόλιο, από ένα όνομα με τεράστιο ειδικό βάρος (βλ. Diffie-Hellman key exchange, η βάση για το public key crypto):

Whitfield Diffie is the co-inventor of public-key cryptography (the basis of all Internet security) and chief security officer and senior staff engineer at Sun Microsystems. In his 2003 article Risky business: Keeping security a secret, he argues that proprietary vendor's claims that their software is more secure because it's secret is nonsense. He identifies and then counters two main claims made by proprietary vendors: (1) that release of code benefits attackers more than anyone else because a lot of hostile eyes can also look at open-source code, and that (2) a few expert eyes are better than several random ones. He first notes that while giving programmers access to a piece of software doesn't guarantee they will study it carefully, there is a group of programmers who can be expected to care deeply: Those who either use the software personally or work for an enterprise that depends on it. "In fact, auditing the programs on which an enterprise depends for its own security is a natural function of the enterprise's own information-security organization." He then counters the second argument, noting that "As for the notion that open source's usefulness to opponents outweighs the advantages to users, that argument flies in the face of one of the most important principles in security: A secret that cannot be readily changed should be regarded as a vulnerability." He closes noting that

"It's simply unrealistic to depend on secrecy for security in computer software. You may be able to keep the exact workings of the program out of general circulation, but can you prevent the code from being reverse-engineered by serious opponents? Probably not."

Είπαμε, από εκεί και πέρα ο καθένας εφαρμόζει ότι θέλει - και παίρνει το ανάλογο ρίσκο.

Στην Microsoft ας πούμε επιμένουν με proprietary ενώ την έχουν πατήσει άπειρες φορές (Kerberos, PPTP VPN, NTLM, SysKey, EFS, RNG κ.ο.κ.). :p

Link to comment
Share on other sites

Καλά ο Schneider είναι περιπτωσάρα ρε συ, αυτός είναι βγαλμένος από τον ψυχρό πόλεμο... Θυμάμαι διάβαζα παλιότερα σε ένα βιβλίο του, πως μια από τις μεθόδους να σπάσεις μια κρυπτογράφηση είναι η απαγωγή και η απειλή... :hehe:

Πέρα από την πλάκα όμως, ο Schneider είναι της σχολής του Kerckhoff (γι' αυτό και η κακιά λύσσα εναντίων του proprietary), πρέπει να έχει δουλέψει στα άπειρα στρατιωτικά projects και φυσικά έχει τις άπειρες γνώσεις στο αντικείμενο... σέβομαι αυτό που λέει (άλλωστε ποιος είμαι να πω ότι δεν έχει δίκιο), αλλά τον κόβω πως ακόμα και αυτός έχει χρησιμοποιήσει και έχει προτείνει πολλές φορές δικά του συστήματα και όχι "πιστοποιημένα"... θεωρίες θα μου πεις, αλλά δεν μπορώ με τίποτα να χωνέψω πχ ότι η επικοινωνία με βαλλιστικούς πυραύλους (οκ τραβηγμένο, αλλά καταλαβαίνεις τι εννοώ) είναι με κάποιο πιστοποιημένο αλγόριθμο...

Το ξέρω ότι έχουμε ξεφύγει από το θέμα, γιατί πάνω κάτω σε commercial projects δεν θα ανακαλύψεις τον τροχό αλλά θα χρησιμοποιήσεις έτοιμα εργαλεία όπως το gpg, αλλά έχει ενδιαφέρον το αν τελικά το "security through obscurity" είναι fail ή όχι...

Link to comment
Share on other sites

  • 4 weeks later...

Το SDES απ' ότι κατάλαβα όμως δεν είναι αλγόριθμος κρυπτογράφησης, είναι ένα πρωτόκολλο που αναλαμβάνει την ανταλλαγή κλειδιών...

Αν εννοείς DES, τότε αρκεί να αλλάξεις στο dll τον αλγόριθμο κρυπτογράφησης και σε όλα τα υπόλοιπα προγράμματα δεν χρειάζεται να αλλάξεις ούτε κόμμα, θα παίζουν κανονικά, χωρίς να καταλάβουν την διαφορά... Αυτό είναι και το βολικό με το dll, δηλαδή κάνεις σε ένα σημείο την αλλαγή και αυτή περνάει αυτόματα παντού...

Link to comment
Share on other sites

  • 1 year later...

NSA's Decade-Long Plan to Undermine Encryption Includes Backdoors, Stolen Keys, Manipulating Standards | Threat Level | Wired.com

"The most shocking revelation involves the NSA’s efforts to deliberately weaken international encryption standards developers use to make their encryption secure..."

Όπως λέει και ο Bruce:

"Cryptography forms the basis for trust online. By deliberately undermining online security in a short-sighted effort to eavesdrop, the NSA is undermining the very fabric of the Internet."

Παπάρες. Και μετά τους φταίει η Κίνα.

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Δημιουργία...

Important Information

Ο ιστότοπος theLab.gr χρησιμοποιεί cookies για να διασφαλίσει την καλύτερη εμπειρία σας κατά την περιήγηση. Μπορείτε να προσαρμόσετε τις ρυθμίσεις των cookies σας , διαφορετικά θα υποθέσουμε ότι είστε εντάξει για να συνεχίσετε.