Shellsec

Fuld version: C/C++ lille introduktion til Xor kryptering
Du ser lige nu en skrabet udgave af vores indhold. Se den fulde version med ordentlig formatering.
Vil i nær fremtid smide et par tråde op omkring kryptering samt netværk. Spørg endelig hvis i har et emne, I gerne vil have taget op!

Introduktion til Xor
[Billede: physics-meme.png]

Allerførst, jeg vil forsøge at skære det meste ud i pap, så selv lycia-slænget har en chance.

Hvad skal jeg bruge det til?
Enhver programmør vil på et eller andet tidspunkt kommer ud for, at skulle behandle sensitiv data. Men udover at kryptere data for at beskytte mod sniffing data leaks .o.l., kan kryptering anvendes til mange andre formål. Lad os forestille os, at vi har lavet et server-klient login-system. Systemet skal være sikkert, så man får et nyt kodeord, hvergang man logger ind (ligesom nemid). Systemet ser således ud:
  1. Serveren sender chipertekst (krypterede string) til klienten
  2. Klienten dekryptere til den oprindelig string
  3. Klienten returnerer den oprindelige string til serveren
  4. Serveren afslutter med at checke, om den returnerede string er tilsvarende den oprindelige.
Overstående er muligvis et dårligt eksempel, men you get the point...
En anden mulighed til et lign. system, kunne laves ved at benytte assymetriske krypteringsalgoritmer. Assymetriske chipers bruger en key til at kryptere, og en anden til at dekryptere. Jeg vil dog komme ind på en lidt simplere krypteringsalgoritme, også kaldet chiper, kaldet Xor. Fordelen ved Xor er, at det er meget nemt at forstå, og ikke kræver meget forhåndsviden, før man kan gå i gang.

Hvad er kryptering?
Kryptering har til formål at omdanne data til en 'ulæsbar' version, der umuliggør, at den oprindelige data kan læses uden brug af den modsatte process, der indebærer at man har den originale nøgle.

En krypteringsalgoritme eller cipher, skal egentlig bare betragtes som en hvilken som helst anden algoritme. Altså, en slags opskrift på, hvordan noget skal håndteres. Lad os kigge på RSA algoritmen:

p = 3 and q = 11 // Vælg to primtal
n = p * q = 3 * 11 = 33 // Beregn
φ(n) = (p - 1) * (q - 1) = 2 * 10 = 20 // Beregn
e = 7 // e skal være 1<e< φ(n) og e samt n er indbyrdes primisk
// Bestem end værdi hvor (d * e) % φ(n) = 1.
// F.eks. d = 3 [(3 * 7) % 20 = 1]
(e, n) => (7, 33) // Public key
(d, n) => (3, 33) // Private key
m = 2 is c = 27 % 33 = 29 // Encrypting
c = 29 is m = 293 % 33 = 2 // Decryption

Overstående eksempel var mest for at forklare en algoritme, og ikke et forsøg på, at lære jer hvordan RSA algoritmen fungerer. For at lave et par RSA keys, skal man altså bare følge 'opskriften'.

Hvordan virker Xor?
Som en start kan jeg afsløre, at chiperen ikke kun hedder Xor, fordi det lyder |337!1. Xor er et sammendrag af "exclusive or", og er en bitwise boolean operator i C++. Den kan altså returnere TRUE eller FALSE. Hvis den ene Xor gate er TRUE og den anden er FALSE, i vilkårlig rækkefølge, returneres altid TRUE. Hvis begge er TRUE eller False Returneres FALSE.

Kode:
|0||0|=|0| // FALSE
|1||0|=|1| // TRUE
|0||1|=|1| // TRUE
|1||1|=|0| // FALSE

Men hvordan kan vi bruge det til at kryptere noget? Lad os forestille os, at vi ville kryptere bogstavet 'P'. 'P's' ascii værdi er 80. Vi skriver 80 om til det binære talsystem (2-tals) , i stedet for det decimale (10 tals).

Kode:
P-->80-->1010000
chr  ascii  binært

Vi finder et bogstav, vi vil anvende som "nøgle".

Kode:
A-->65-->1000001
chr  ascii  binært

Tror egentlig ikke jeg behøver forklare det her...

Kode:
1010000 // P
1000001 // A Nøgle
-------- // Xor
0010001 // ASCII 17

For at dekryptere vores bogstav igen, gør vi det samme.
Kode:
0010001 // ASCII 17
1000001 // A Nøgle
-------- // Xor
1010000 // P
[/code]

TADA! Simpelt? Prøv selv!

Hvis vi ville have krypteret et ord eller end string, havde vi benyttet samme fremgangsmåde, bare med alle tegn.

Xor i C++
I C++ er Xor operatoren '^' tegnet. Lad os starte med, at kryptere og dekryptere en variabel af 'char' data typen.

#include <iostream>

int main()
{
char cryptthis;
char key;

std::cout << "Char to encrypt: ";
std::cin >> cryptthis;
std::cout << "Key: ";
std::cin >> key;

cryptthis ^=key; // Xor operation. Præcis som vi gjorde det manuelt.
std::cout << "The encrypted character is: " << cryptthis ;

cryptthis ^=key; // Som nævnt dekryptere vi på samme måde.
std::cout << "\nThe decrypted character is: " << cryptthis;

return 1337;
}
Hvis vi skulle gøre dette ved en string, er alt vi behøver, som førnævnt at 'køre' det hele igennem. Lad os slutte af med, at lave et program med en Xor encrypt / decrypt function.

/*
Prepare for slamkode!
*/
#include <iostream>
#include <string>
using namespace std;

string XOREnc(string str, string key)
{
string enc("");
for (unsigned int i=0; i < str.length(); i++) // Her checker vi hele stringen igennem ligesom vi gjorde manuelt. Læg mærke til, at vi en string som key.
enc += str[i] ^ key[i % (sizeof(key) / sizeof(char))]; // Kan i se problemet? Hvis key<str. Lille øvelse til jer.
return enc;
}

int main()
{
string str, encrypted, decrypted, key;
cin >> str;
cin >> key;
encrypted = XOREnc(str, key);
decrypted = XOREnc(encrypted, key); // Vi kan som sagt benytte samme function til dekryptering.
cout << "Encrypted string: " << encrypted << endl;
cout << "Decrypted string: " << decrypted;
return 1337;
}
Så let kan kryptering være.

Blev skrevet i går kl. 3 :D. Kan godt være jeg kommer til at rette lidt i den...
Super godt forklaret :) Jeg lavede engang to XOR kryperingsfunktioner i PHP, men det er meget vigtigt at gøre opmærksom på at det er en meget svag kryptering, og kan nemt brydes hvis den samme passphrase bruges flere gange.
Kode:
#ifndef C_XORSTRING_H
#define C_XORSTRING_H

template <int XORSTART, int BUFLEN, int XREFKILLER>
class XorStr
{
private:
    XorStr();
public:
    char s[BUFLEN];

    XorStr(const char* xs);
    ~XorStr(){ for(int i=0;i<BUFLEN;i++)s[i]=0;} // clear string from stack
};

template <int XORSTART, int BUFLEN, int XREFKILLER>
XorStr<XORSTART,BUFLEN,XREFKILLER>::XorStr(const char* xs)
{
    int xvalue = XORSTART;
    int i = 0;
    for(;i<(BUFLEN-1);i++) {
        s[i] = xs[i-XREFKILLER]^xvalue;
        xvalue += 1;
        xvalue %= 256;
    }
    s[BUFLEN-1] = 0;
}
#endif

XorStr<0x58,9,0xE76FE99B>("\x35\x36\x34\x34\x72\x39\x32\x33"+0xE76FE99B).s

= mono.dll
Tak for det dejlige læsestof. +1
Godt arbejde havre!
Det er et stykke tid siden jeg ar arbejdet med den slags, så altid godt at få opfrisket lidt på sagerne.
Bedste tutorial/guide/introduktion på Shellsec i rigtig lang tid. Du fortjener +rep for den.
https://www.shellsec.pw/traad-c-c-lille-...kryptering

Q: Hvad skal jeg bruge det til?
A: OTP keystreams

otp_keystream [ -k key ] || [ -K keystream [-o offset]] < in_file > out_file / pipe / etc

# dd if=/dev/sda bs=$((1024*1024*10)) | ./otp_keystream -K bigrandom | nc -v yesyoumayhaveacopy.com 10101
Kode:
/* begin otp_keystream.c */
FILE *keystream = NULL;

int
main(int argc, char *argv[]) {
 char c;
 char k;
 char b;
 char opt;
 char *usage = "Usage: xor [-k key ] || [ -K keystream [-o offset]] < stdin > stdout";
 char *key = NULL;
 int key_len = 0;
 int key_it = 0;
 int key_mode = 0;
 int keystream_mode = 0;
 long long int key_offset = 0;
 long long int out_offset = 0;

 while ( ( opt = getopt (argc, argv, "k:K:o:") ) != -1 ) {
   switch(opt) {
   case 'o':
     key_offset = atol (optarg);
     break;
   case 'K':
     keystream = fopen (optarg, "r");
     if(!keystream) {
       fprintf(stderr,"FATAL: Cannot open '%s' for reading.\n", optarg);
       return(1);
     }
     keystream_mode++;
     break;
   case 'k':
     key = strndup (optarg, strlen (optarg));
     key_len = strlen (optarg);
     key_mode++;
     break;
   }
 }
 argv += optind;
 argc -= optind;
 
 if(!key_mode && !keystream_mode) {
   fprintf(stderr, "%s\n", usage);
   return(1);
 }
 
 if(key_mode) {
   while ( (c = getc (stdin)) != EOF ) {
     b = (c^key[key_it++]);
     putc (b, stdout);
     if(key_it==key_len)
       key_it = 0;
   }
 }
 else if(keystream_mode) {
   while (( fread ((char *)&c, 1, sizeof (char), stdin)) != 0 ) {
     key_offset += fread ((char *)&k, 1, sizeof (char), keystream);
     b = (c^k);
     out_offset += fwrite ((char *)&b, 1, sizeof (char), stdout);
     if(key_offset != out_offset) {
       fprintf (
                stderr,
                "FATAL: Input length exceeds length of keystream (%lli).\n",
                key_offset
                );
       return(1);
     }
   }
   fprintf (stderr, "Keystream offset=%lli\n", key_offset);
 }
}
/* end otp_keystream.c */