[ itf @ 12.12.2010. 17:54 ] @
Zanima me ima li itko implementaciju ovih algoritama u C++ (Builderu)? Uspio sam napraviti enkripciju/dekripciju preko Indy komponenti (mime, uux), ali bi htio nešto sa barem 128 bita.

Nešto sam našao i na netu ali ne u potpunosti. Npr:

Code (cpp):
#include <IdHashMessageDigest.hpp>
//---------------------------------------------------------------------------
String __fastcall MD5Encode(const String texto)
{
     String result;
     TIdHashMessageDigest5 *idmd5= new TIdHashMessageDigest5();
     try
     {
        result= idmd5->HashStringAsHex(texto);
     }
     __finally
     {
        delete idmd5;
     }
     return result;
}


..ali ne znam kako dekodirati sadržaj.
[ Nedeljko @ 12.12.2010. 18:01 ] @
MD5 je heš funkcija, a za njih ne postoji dekodiranje. Uz to, nije više preporučljiva kao kriptografski heš zbog uočenih slabosti.
[ itf @ 12.12.2010. 18:12 ] @
Koji bi onda algoritam bio najbolji i najjednostavniji za implementaciju?
[ kiklop74 @ 13.12.2010. 00:51 ] @
Zasto izmisljati toplu vodu. Ima gotovih biblioteka za takve stvari. Evo sta bi bili najpozeljniji kandidati:

OpenSSL http://www.openssl.org/
Crypto++ http://www.cryptopp.com/
Microsoft CryptoAPI http://msdn.microsoft.com/en-us/library/aa380256.aspx


[ Nedeljko @ 13.12.2010. 12:06 ] @
Što se tiče izbora algoritama, vikipedija daje tabelu. Ja bih se po njoj opredelio za SHA-256/224.

Što se implementacije tiče, koristio bih Crypto++.
[ itf @ 13.12.2010. 12:53 ] @
Za moje potrebe dobar je čak i običan hash sa md5, ali kako čitam proglašen je nesigurnim pa idem dalje. Sad sam instalirao ovu crypto++ biblioteku pa ću malo prostudirati.

Hvala svima.
[ itf @ 13.12.2010. 14:09 ] @
Evo konkretnog primjera za RSA ako će nekome trebati:

Code (cpp):

// potrebno ukljuciti cryptlib.lib

#include "randpool.h"
#include "rsa.h"
#include "hex.h"
#include "files.h"
#include <iostream>

using namespace std;
using namespace CryptoPP;

void GenerateRSAKey(unsigned int keyLength, const char *privFilename, const char *pubFilename, const char *seed)
{
    RandomPool randPool;
    randPool.Put((byte *)seed, strlen(seed));

    RSAES_OAEP_SHA_Decryptor priv(randPool, keyLength);
    HexEncoder privFile(new FileSink(privFilename));
     priv.DEREncode(privFile);
     privFile.MessageEnd();

     RSAES_OAEP_SHA_Encryptor pub(priv);
     HexEncoder pubFile(new FileSink(pubFilename));
     pub.DEREncode(pubFile);
        pubFile.MessageEnd();
}
string RSAEncryptString(const char *pubFilename, const char *seed, const char *message)
{
       FileSource pubFile(pubFilename, true, new HexDecoder);
        RSAES_OAEP_SHA_Encryptor pub(pubFile);

       RandomPool randPool;
       randPool.Put((byte *)seed, strlen(seed));

       string result;
        StringSource(message, true, new PK_EncryptorFilter(randPool, pub, new HexEncoder(new StringSink(result))));
       return result;
}
RandomPool & GlobalRNG()
{
        static RandomPool randomPool;
        return randomPool;
}
string RSADecryptString(const char *privFilename, const char *ciphertext)
{
       FileSource privFile(privFilename, true, new HexDecoder);
        RSAES_OAEP_SHA_Decryptor priv(privFile);

        string result;
        StringSource(ciphertext, true, new HexDecoder(new PK_DecryptorFilter(GlobalRNG(), priv, new StringSink(result))));
        return result;

}

int main()
{
    char priKey[128] = {0};
    char pubKey[128] = {0};
     char seed[1024] = {0};

     strcpy(priKey, "mojprvivatnikljuc");
     strcpy(pubKey, "mojjavnikljuc");
     strcpy(seed, "seed");
     GenerateRSAKey(1024, priKey, pubKey, seed);

        char message[1024] = {0};
     cout<<"Origin Text:\t"<<"Hello World!"<<endl<<endl;
     strcpy(message, "Hello World!");
     string encryptedText = RSAEncryptString(pubKey, seed, message); // RSA

     cout<<"Encrypted Text:\t"<<encryptedText<<endl<<"duljina: " << encryptedText.length()<<endl<<endl;
     string decryptedText = RSADecryptString(priKey, encryptedText.c_str()); // RSA
     cout<<"Decrypted Text:\t"<<decryptedText<<endl<<endl;

     return 0;
}


Ovo radi ali mi je malo nejasna dubina enkripcije. Koliko vidim, ona ovisi o duljini ključa? Npr. za 1024 ulazna znaka dobijem 256 izlaznih, ili za 2048 znakova dobijem 512? I malo mi je nejasan ovaj seed? Vidim da ima neke veze s generiranjem slučajnih brojeva ali ne vidim kakvu točno ulogu ima.
[ Nedeljko @ 13.12.2010. 15:51 ] @
Ovde sam izložio teorijske osnove RSA.

Najpre se generišu veliki različiti prosti brojevi p i q i izračunaju n=pq i (p-1)(q-1). Potom se izabere neki broj e, koji će pripadati javnom ključu (najčešće 65537) i izračuna broj d takav da je ed-1 deljivo sa (p-1)(q-1). Javni ključ čine brojevi n i e, a privatni brojevi n i d (odnosno d, pošto se n zna iz javnog ključa), dok se brojevi p, q i (p-1)(q-1) moraju bezbedno uništiti. Obzirom da je tipično e=65537, možemo reći da se javni deo praktično sastoji iz broja n, a tajni iz broja d.

Poruka se deli na blokove od kojih se svaki može kodirati sa k bita tako da je 2k+2<(p-1)(q-1). Naravno, k je poznat, a p, q i (p-1)(q-1) su uništeni. Ako neki nekriptovani blok odgovara binarnom zapisu broja m, onda je kriptovan oblik bloka binarni zapis broja c u opsegu od 0 do 2k-1 takav da je (m+2)e-c-2 deljivo sa n. Što se dekriptovanja tiče, sasvim je slično, jer je (c+2)d-e-2 deljivo sa n sa verovatnoćom većom od oko 1-1/p-1/q. Rizik da poruka bude pogrešno dekriptovana se prihvata. Napominjem da je pronalaženje bar jedne takve poruke dovoljno da se razbije takav ključ, ali se taj rizik prihvata jer je 1/p+1/q blisko nuli.

Obzirom da n i d imaju otprilike onoliko bitova koliko i zbir bitova za p i q, jasno je zašto se dobijaju blokovi oko 4 puta manje dužine od dužine para ključeva (javni je (n,e), a privatni (n,d)).

Brojevi p i q su generisani nasumično (uz uslov da imaju odgovarajući broj bita, pri čemu bi odnos broja bitova od p i q trebao da bude od 40:60 do 45:55 i da prosti brojevi p i q uvećani/umanjeni za 1 nemaju samo male proste faktore, već i bar neki veliki). Stoga je neophodno koristiti generator (pseudo)slučajnih brojeva, a on zahteva početnu vrednost semena. Ako oni nisu kriptografski sigurni, može se napad izvršiti na njih.

Primera radi Mersen-Tvister algoritam za generisanje pseudoslučajnih brojeva nije podesan za kriptografske svrhe, bar ne u svom osnovnom obliku, iako ima odlične statističke osobine (vrlo je podesan za simulacije), jer ako znaš bilo kojih 624 uzastopnih generisanih binarnih reči dužine 32 bita, možeš predvideti sve prethodne i sve sledeće. Recimo, ako si e generisao slučajno (nisi se držao standardne preporuke o ozboru e=3 ili e=65537), onda on predstavlja niz uzastopnih generisanih bajtova, pa se na osnovu toga može rekonstruisati ostatak procesa generisanja ključeva i unapred i unazad i eto privatnog ključa.

Ako se nije vodilo računa o generisanju semena, opet sve pada u vodu, jer je ceo postupak generisanja ključeva jednoznačno određen semenom i algoritmom (koji je poznat), pa se postupak generisanja ključeva može ponoviti i opet doći do privatnog ključa. O jednom takvom slučaju se već raspravljalo ovde. Dakle, jedini izvor slučajnosti je bio PID (process ID), koji na Linuksu ima 16 bita, tako da program za generisanje ključeva nije mogao da generiše više od 65536 različitih parova ključeva (koji se svi generišu vrlo brzo) i sve ostalo pade u vodu. Treba voditi računa da izvor entropije bude dovoljno bogat, a onda dodatno primeniti neku dobru heš funkciju, koja dovodi seme na potrebnu širinu za seme korišćenog generatora pseudoslučajnih brojeva i vrši difuziju, tako da ako neko ima deo informacija o izvorima entropije, ne može praktično ništa da zaključi o semenu.

Jednostavno, kriptografija je lanac koji je jak koliko i najslabija karika. Stoga se mora voditi računa bukvalno o svemu. Ako se ključevi generišu korišćenjem generatora slučajnih, a ne pseudoslučajnih brojeva, onda nema zime. Na primer, mogu se koristiti posebni kvantni uređaji u tu svrhu. Problem je samo što imaju neku cenu zbog koje nisu standardna oprema svakog računara.
[ itf @ 13.12.2010. 21:36 ] @
Vrlo temeljito. Hvala
[ Nedeljko @ 14.12.2010. 09:57 ] @
Izgleda da Crypto++ nema funkcije za generisanje kriptografski sigurnog semena, pa očekuje da ga napuniš. To je i logično, jer osim platformski nezavisnih izvora entropije, na svakom OS-u ima izvora entropije koji su specifični za taj OS, a Crypto++ je platformski nezavisna biblioteka.

WinAPI ima svoje funkcije za generisanje kriptografski sigurnih pseudoslučajnih nizova znakova, pa na vindouz sistemima možeš koristiti to, a na juniksolikim sistemima /dev/urandom virtuelnu datoteku. Na taj način treba postaviti seme generatora pseudoslučajnih brojeva. U tvom kodu je trebalo napuniti samo string seed i to ne nekim lepim stringom, već slučajnim nizom bajtova dobijenim na opisani način. Stringovi priKey i pubKey su izlazni (a ne ulazno-izlazni) argumenti funkcije GenerateRSAKey, pa je njihov sadržaj pre poziva funkcije za generisanje ključeva nebitan.

Sa druge strane, ne mislim da treba posezati za RSA algoritmom kada su npr. vojne svrhe u pitanju, jer postoji kvantni algoritam za efikasno razbijanje RSA. Za njegovu upotrebu uje neophodan kvantni računar, kakav trenutno ne postoji na tržištu. Međutim, IBM je uspeo da u svojim laboratorijama proizvede kvantni računar malog kapaciteta i to je samo pitanje razvoja na kome se radi. Otkud ja znam da neko nije već razvio za vojne svrhe dovoljno jak kvantni računar, koji drži u tajnosti?

Na svu sreću, postoje i drugi algoritmi kriptografije javnim ključem, koji nisu zasnovani na težini faktorizacije prirodnog broja na proste činioce i samim tim nisu podložni navedenom algoritmu razbijanja.

[Ovu poruku je menjao Nedeljko dana 14.12.2010. u 11:34 GMT+1]
[ itf @ 14.12.2010. 10:24 ] @
Hoćeš reći da niti RSA nije dovoljno siguran? Kako sam gledao na wikipediji uglavnom je siguran i nude čak i nagrade ako ga se probije. Inače, malo me buni.. koliko bita iznosi enkripcija ukoliko je ulaznih znakova 1024 a izlaznih 256? 256 bitna?
[ Nedeljko @ 14.12.2010. 10:40 ] @
Čim se budu pojavili kvantni računari, RSA će biti neupotrebljiv. Na klasičnim mašinama nije poznat matod za razbijanje RSA ako se sve uradi kako treba. Zato ja ne mogu da razbijem RSA. Nemam kvantni računar. E, sad, kvantni računari su ostvarivi. U to nema nikakve sumnje. Pitanje je samo da li su javno dostupne informacije o razvoju tačne ili je neko u tajnosti uspeo da razvije kvantni računar dovoljnog kapaciteta.

Što se tiče drugog pitanja (ulaz 1024 bita, izlaz 256) nisam ga razumeo.
[ itf @ 14.12.2010. 11:31 ] @
Mislim da će ipak proći dosta vremena dok kvantna računala budu u standardnoj upotrebi, a do tada ću ići s RSA.

A za ovo drugo.. pitanje je koliko je velika (jaka) enkripcija (256, 512 ili 1024bit-a) ako imam ulaznih 1024 znaka a izlaznih 256 tj. općenito koliko jaku enkripciju je napravio RSA u ovom slučaju.
[ Nedeljko @ 14.12.2010. 12:24 ] @
Pa, smatra se da RSA širine 4096 bita trenutno ne može niko da razbije. Naravno, ta granica se pomera razvojem računara. Sa druge strane, možeš koristiti i kraće ključeve za informacije čiji je rok važenja ograničen.

Malo me buni to da imaš manje izlaznih znakova od ulaznih.
[ itf @ 14.12.2010. 12:31 ] @
To i mene buni. Slobodno pokreni gornji primjer koda pa ćeš vidjeti da je u pravilu uvijek 4 puta manje izlaznih nego ulaznih znakova. Zato niti ne razumijem koliko je jaka enkripcija.
[ Nedeljko @ 14.12.2010. 14:08 ] @
Tebi su privatni i javni ključ širine 128 bajtova ili 1024 bita, pa treba da očekuješ i toliku širinu bloka. Izgleda da je javni ključ n, tajni d, a da je za e uzeta standardna vrednost 65537.

Tvoja poruka "Hello World!" je kratka, pa staje u jedan blok od 128 bajtova. Međutim, string koji si dobio je heksadekadni zapis tog bloka, odnosno svaki bajt se predstavlja sa 2 znaka, pa je zato dužine 256.
[ itf @ 14.12.2010. 14:47 ] @
Zapravo me najviše brine da li ako odaberem generiranje RSA 1024 s privatnim/javnim ključevima duljine 128 (sve kao u gornjem primjeru) ću uvijek dobiti istu izlaznu duljinu (256) bez ozbira na stvarni sadržaj ulazne poruke i njenu duljinu?

EDIT: Sad promjenio duljine javnih i privatnih ključeva na 256 i opet na izlazu dobijem niz duljine 256...
[ Nedeljko @ 14.12.2010. 16:00 ] @
Pozabavio sam se tvojim kodom malo bolje.

Očigledno "širina 1024 bita" znači da je širina bloka 1024 bita, odnosno 128 bajta. Promelnljive pubKey i privKey sadrže samo imena datoteka u kojima će biti smešteni ključevi, a ne same ključeve.

Ne znam šta si menjao u programu, ali da bi povećao širinu na 256 bajta, odnosno 2048 bita, treba samo u liniji

Code:
GenerateRSAKey(1024, priKey, pubKey, seed);


da promeniš 1024 u 2048. Sve ostalo ostaje isto.

[Ovu poruku je menjao Nedeljko dana 14.12.2010. u 17:21 GMT+1]
[ itf @ 15.12.2010. 09:02 ] @
Heh.. još samo da gornji primjer nekako modificiram da mi se javni i privatni ključ vraćaju preko argumenata funkcije (call by reference) a ne da se spremaju u datoteke. Ako netko već ima to napravljeno molio bih da stavi.
[ Lord Of The Nations @ 20.04.2011. 16:26 ] @
Iskreno ja mislim da ni jedan javni algoritam nije siguran.
Siguran algoritam je onaj koji napravis sam.
Zasto ne izmisliti toplu vodu ako samo ti znas njenu temperaturu?
A ako se radi o aplikacijama za konekciju na neke servere koje vec koriste
nesto kao na primer ssl. . . onda se mora pratiti njihov std.
[ mmix @ 20.04.2011. 17:06 ] @
Citat:
Lord Of The Nations:Siguran algoritam je onaj koji napravis sam.
Zasto ne izmisliti toplu vodu ako samo ti znas njenu temperaturu?


To o cemu pricas je security through obscurity, ljudi nisu glupi, pre ili kasnije neko ce ocitati temepraturu tvoje vode i onda ce celokupna security infrastruktura okoju si podigaoo na tome pasti kao kula od karata. Drugo, nije nimalo lako napraviti svoj cipher cak ni teorijski a kamoli ga implementirati tako da mu ne smanjis bezbednost kroz nenamerne bagove i otvaranje side-channel pozicija za napad, itd.