Kirjautuminen

Haku

Tehtävät

Keskustelu: Koodit: Grypt-koodi

Sivun loppuun

jone2712 [03.07.2024 15:50:38]

#

Olen tutkinut ja debugannut grypt-koodin uudelleen. Se toimii kuten junan vessa. Paskapuhetta ettei koodi mukamas toimisi. Taas joidenkin näsäviisaiden mutu puheita, että "joo, koodi ei toimi, ja sen voi interpoloida auki". Näkisi vain sellaisen koodin. Se pitäisi olla, ennen kuin aloittaa arvostelemisen. Grypt-koodi ei anna yhtään reduntassia, vaikka yrittää avata gryptauksen avaimella, joka on yhden bitin päässä oikeasta avaimesta. Olen voinut julkaista koodin joskus, mutta uudelleen julkaisu ei ole pahitteeksi. Koodi on avoin, eli gryptauksen avaajalla on käytössä alkuperäinen koodi - siitä vain yrittämään.


INFORMAATION SALAUS

Aihe on hyvin mielenkiintoinen ja lukeutuu likimain sovelletun, ennustamattoman ja kokeellisen numerologiikan aihepiiriin.

Salauksen ensimmäinen päämäärä on redundanssin poisto. Datan möyhennyksen toisena tavoitteena on saada informaation palauttaminen mahdollisimman mahdottomaksi ilman oikeita taikasanoja.

Jos salaus- ja purkuavaimen pituus on esimerkiksi 256 bittiä, datasekvenssin avaamista pitäisi kokeilla suunnilleen 10^77 erilaisella avaimella. Vaikka käytössä olisi miljoona supertietokonetta, joista jokainen murjoisi yötä päivää miljoona avausyritystä millisekunnissa, kaikkien vaihtoehtojen seulomiseen kuluisi siltikin osapuilleen 10^51 miljoonaa vuotta.

Salausalgoritmit voidaan laittaa paremmuusjärjestykseen sen perusteella, kuinka paljon redundanssia palautuu, kun purkuavain lähestyy bitti bitiltä oikeaa taikasanaa. Hyvä salausmetodi pitää pintansa viimeiseen bittiäijään asti: vaikka avain olisi enää vain yhden bitin päässä oikeasta, purkufunktio tuottaisi edelleenkin järjetöntä bittimössöä.

Päinvastoin kehnompi salausalgoritmi antaa mahdollisuuden avaimen interpolointiin, ja palauttaa redundanssia yhä enemmän suhteessa avaimen oikeisiin bitteihin.

Sulautetut järjestelmät asettavat salausalgoritmeille rankat tehovaatimukset. Jos salausmetodi tuottaa umpimähkäisen kaaoksen jokaisella väärällä avaimella, ja käyttää vain murto-osan prosessointitehoa, silloin koodinpätkä täyttää asiansa paremmin kuin hyvin.

LIFE-SALAUSALGORITMI

Muun muassa Esko Valtaoja kirjoittaa eloisasti kirjassaan ”Kotona maailmankaikkeudessa” soluautomaateista. Life-pelissä bitit ”elävät” ja generoivat uusia sukupolvia. Tiettyyn tulevaisuuden hetkeen voidaan iteroitua äärettömän monella nykyhetkellä, jonka vuoksi peliä ei voi pelata menneisyyteen päin. 2^n-kutsukannalla taaksepäin interpoloiva rekursio hyydyttäisi hetkessä kaikki maailman läppärit.

Vuosien tutkimisen ja harrastamisen jälkeen onnistuin tekemään Life-pelin soluautomaatista vastaavan ja tehokkaan funktiosimulaation, jossa bittiotukset käyttäytyvät samalla tavalla. Mallia voi soveltaa parhaiten satunnaislukujen tuottamiseen ja informaation salaamiseen.

Salausalgoritmien lähdekoodit ovat avoimia. Ne eivät kaipaa näennäisiä kommentteja tai epätoivoisia selityksiä. Kukaan ei ymmärrä kovin perusteellisesti soluautomaatin, CRC:n tahi latinalaisen neliön toimintaperiaatteita. Ne ovat kummallisia ja kiinnostavia olioita, mutta verhoutuvat valitettavasti salaperäisyyteensä sisään. Ja vaikka ymmärtäisikin, ei ole olemassa niin tehokasta myllyä, jolla voisi rouhia esimerkiksi soluautomaatin tuottamat kaikki esipolvet.

Hyvä niin. Näistä komponenteista voidaan sitten soveltaa meidän tarpeisiin tehokas ja varma salausalgoritmi. Salausfunktio käsittelee dataa 32 tavun lohkoissa. Salausavain on myös 32 tavua = 256 bittiä pitkä:

/******************************************************************************
* Function: LifeCrypt                                                         *
*                                                                             *
* Use:      Kryptaa tai purkaa datalohkon. Ei saa kutsua suoraan, koska       *
*           luuppi möyhentää salaus- / purkuavaimen käyttökelvottomaksi.      *
*           Kutsu funktioita LifeEncrypt ja LifeDecrypt.                      *
*                                                                             *
*           Rajoitus: Latinalaisen neliön vuoksi datalohkon pituus pitää      *
*                     olla muotoa 2 potenssiin n, ja vähintään 32 tavua       *
*                     pitkä, koska 17 virittää 32*32 kerrannaisneliöt.        *
*                                                                             *
* Input:    char *data on osoitin 32 tavun data-lohkoon.                      *
*           char *key on osoitin 32 tavun = 256 bitin avaimeen.               *
*                                                                             *
* Output:   Salaamaton data kryptataan ja palautetaan samaan data-lohkoon.    *
*           Salattu data puretaan samoin annettuun data-lohkoon.              *
*                                                                             *
* Version:  0.01  09.10.04  JAr  ensimmäinen versio.                          *
*                                                                             *
******************************************************************************/
static void LifeCrypt(char *data, char *key)
{
   int i, f;
   long *life;
   long *apu, *upa;
   long BreakUp=0x00L;

   upa=(long*)(key+16);
   apu=life=(long*)key;

   for (i=0; i<32; i++)
   {
      life[0]+=(life[0]>>11)^(life[1]<<17);
      life[1]+=(life[0]<<19)^(life[1]>>13);

      life[0]+=life[2];
      life[1]-=life[3];

      BreakUp+=life[0]^life[1];
      life=life==apu? upa: apu;

      f=(int)(BreakUp>>28)&0x0f;
      data[i] ^= (char)(BreakUp>>f);
      data[i^17]^=(char)(BreakUp>>(8+f));
   }
}

/******************************************************************************
,* Function: LifeEncrypt                                                       *
*                                                                             *
* Use:      Salakoodaa datalohkon.                                            *
*                                                                             *
* Input:    void *block32 on osoitin 32 tavun lohkoon.                        *
*           const void *key32 on osoitin 32 tavun = 256 bitin avaimeen.       *
*                                                                             *
* Output:   Salattu data palautetaan lohkoon block32.                         *
*                                                                             *
* Version:  0.01  09.10.04  JAr  ensimmäinen versio.                          *
*                                                                             *
******************************************************************************/
void LifeEncrypt(void *block32, const void *key32)
{
   char key[32];
   memcpy(key, key32, 32);
   LifeCrypt((char*)block32, key);
}

/******************************************************************************
* Function: LifeDecrypt                                                       *
*                                                                             *
* Use:      Purkaa salakoodatun datalohkon.                                   *
*                                                                             *
* Input:    void *block32 on osoitin 32 tavun salakoodattuun lohkoon.         *
*           const void *key32 on osoitin 32 tavun = 256 bitin avaimeen.       *
*                                                                             *
* Output:   Alkuperäiseksi purettu data palautetaan lohkoon block32.          *
*                                                                             *
* Version:  0.01  09.10.04  JAr  ensimmäinen versio.                          *
*                                                                             *
******************************************************************************/
void LifeDecrypt(void *block32, const void *key32)
{
   LifeEncrypt(block32, key32);
}

/*
Kommentteja koodista ja esimerkkejä:

¤ Salaus- ja purkufunktio käyttävät samaa avainta, mutta sen perusteella salauksen voimasta ei voi tehdä johtopäätöksiä puoleen eikä toiseen.

¤ Miksi meidän järjestelmässä tarvittaisiin epäsymmetrinen salausmetodi, jossa olisi erikseen salausavain, purkuavain ja mahdollisesti vielä julkinenkin avain?

¤ Sulautetuissa järjestelmissä prosessointikapasiteetti per tehtävä on rajallinen, jonka vuoksi funktiot ja niiden tarkoitusperät pitää olla viimeisen päälle optimoituja.

¤ LifeCrypt-funktio on rehellisesti avoin koodi, ja sen voi turvallisin mielin laittaa yleiseen jakeluun. Ainoastaan oikea velho jossain muussa sfäärissä onnistuisi loihtimaan suunnilleen 128-kutsukannalla taaksepäin interpoloivan rekursion.

¤ Hyvä. Tämän vuoksi LifeCrypt-funktio pystyy ottelemaan viimeiseen bittiukkoon saakka, koska soluautomaatti pöyhii ja poimuttaa informaation likimain 12832 = 1067 askeleen päähän.

Esim.

¤ Seuraavassa main-funktiossa salataan 32-tavun informaatiolohko “TimoAnitaRikuSannaRistoOlliJouni”.

¤ 256-bitin avain on arvottu satunnaisluvuilla.
¤ Avaimesta kolhitaan vain yksi bitti, jolla data sitten yritetään avata.

¤ Tulos on yhtä kaoottista sekä teksti- että binäärimuodossa.

¤ Tämän jälkeen avaimen korruptoitu bitti korjataan ja salattu data avataan uudelleen täsmälleen oikealla avaimella, jolloin alkuperäinen informaatio saadaan takaisin.

main-funktion tuloste:

     Salattu informaatio: σf2╔←r-h¢S¢d£₧Ö¶ÜΣ╗╬d╒½e▬ª9è♦╫╙k
    Avausyrityksen tulos: Ω&→*»m╕[û=Y☻fe0╫:#ⁿ☻¢▌"πk▄4ü·-▀Æ
Alkuperäinen informaatio: TimoAnitaRikuSannaRistoOlliJouni

¤ Vaikka informaation avaamista yritettiin yhtä bittiä vaille validilla avaimella, LifeCrypt-funktio output on yhä tolkutonta bittisekamelskaa ilman järjen häivää. ”Redundanssia” edustaa lähinnä kaksi mustaa pikku-ukkoa, jotka nauravat ironisesti.

¤ Näin asian laita pitääkin olla. Hyvän salausmetodin ei saa antaa mahdollisuutta avaimen interpolointiin, vaan taikasanan pitää olla laakista ja prikulleen 256 bitin tarkkuudella oikein!
*/
void main(void)
{
   const char information[]="TimoAnitaRikuSannaRistoOlliJouni";
   char key[32]=
   {
      0x37, 0x9b, 0x6f, 0x2c, 0x93, 0x1f, 0x74, 0x48,
      0x23, 0x61, 0x31, 0x04, 0x5f, 0xb3, 0xbe, 0x2f,
      0x6c, 0xcb, 0xb1, 0x2d, 0x94, 0xbd, 0x60, 0xac,
      0xd0, 0x3c, 0x3d, 0x07, 0x58, 0xbf, 0xaf, 0xe0,
   };

   char data[32];
   char TextBuf[32+1];
   char CopyOfDataCrypt[32];

   memset(TextBuf, 0, 32+1);
   memcpy(data, information, 32);

   /* Salakoodataan informaatio "TimoAnitaRikuSannaRistoOlliJouni" */
   LifeEncrypt(data, key);
   memcpy(CopyOfDataCrypt, data, 32);

   /* Katsotaan, millaiselta mössöltä salakoodaus näyttää */
   memcpy(TextBuf, data, 32);
   printf("     Salattu informaatio: %s\n", TextBuf);

   /* Korruptoidaan avaimesta yksi bitti */
   key[0] |= (char)8;

   /* Yritetään avata salaus avaimella, joka on yhden bitin päässä oikeasta */
   LifeDecrypt(data, key);

   /* Katsotaan avauksen tulosta */
   memcpy(TextBuf, data, 32);
   printf("    Avausyrityksen tulos: %s\n", TextBuf);

   /* Korjataan tärvelty bitti oikeaksi ja yritetään uudelleen */
   key[0] &= ~(char)8;
   memcpy(data, CopyOfDataCrypt, 32);

   /* Avataan salaus uudestaan presiis oikealla avaimella */
   LifeDecrypt(data, key);

   /* Ja nyt pitäisi tulostua alkuperäinen informaatio */
   memcpy(TextBuf, data, 32);
   printf("Alkuperäinen informaatio: %s\n", TextBuf);
}

wy5vn [03.07.2024 17:01:50]

#

Ehkä salaisin valtiosalaisuudet kuitenkin aes256:sella

jlaire [03.07.2024 17:30:29]

#

Eiköhän tätä analysoitu jo 2021 ihan riittävästi: https://www.ohjelmointiputka.net/keskustelu/31984-cpp-kryptaus

Metabolix [05.07.2024 22:22:42]

#

Alkuperäinen koodi olettaa, että long on 32-bittinen, mutta esimerkiksi 64-bittisessä Linuxissa long on 64-bittinen, jolloin koodi ylittää 32-tavuisen puskurin ja tuottaa eri tuloksia.

Tässä on koodista versio, jossa on seuraavia kosmeettisia muutoksia:
- vaihdettu muuttujatyypit porttautuviksi (erityisesti int32_t),
- vaihdettu osoitinten (apu, upa) tilalle pelkkä indeksointi,
- erotettu avaimen sekoitus ja sillä tehtävä xor-kryptaus.

Koodin toiminta on ennallaan. Yhteensopivuuden vuoksi säilytin tässä C-tyyliset osoittimet enkä tehnyt datalle mitään uusia rakenteita. Saat Jone käyttää ihan vapaasti tätä versiota.

#include <stdint.h>
#include <string.h>

/**
* Sekoittaa 32 tavun (256 bitin) dataa.
* Sekoitus perustuu LifeCrypt-koodiin (JAr, Jouni Aro, 2004).
*
* @param input 32 tavun = 256 bitin syöte.
* @param output 32 tavun = 256 bitin tulos.
*/
static void LifeMix256(const void *input, void *output) {
    const int32_t *t = (const int32_t*)input;
    int32_t ints[8] = {t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7]};

    uint8_t *data = (uint8_t*)output;
    memset(data, 0, 32);

    int32_t x = 0;
    for (int i = 0; i < 32; i++) {
        int j = 4 * (i & 1);
        ints[j + 0] += (ints[j + 0] >> 11) ^ (ints[j + 1] << 17);
        ints[j + 1] += (ints[j + 0] << 19) ^ (ints[j + 1] >> 13);
        ints[j + 0] += ints[j + 2];
        ints[j + 1] -= ints[j + 3];

        x += ints[j + 0] ^ ints[j + 1];

        int f = (int)(x >> 28) & 0x0f;
        data[i] ^= x >> f;
        data[i ^ 17] ^= x >> (8 + f);
    }
}

/**
* Salaa tai purkaa 32 tavun datalohkon 32 tavun = 256 bitin avaimella.
* Salaus tapahtuu kaavalla tulos = data XOR LifeMix256(avain).
*
* @param data 32 tavun = 256 bitin datalohko.
* @param key 32 tavun = 256 bitin salausavain.
*/
static void LifeXorCrypt(void *data, const void *key) {
    uint8_t hash[32];
    LifeMix256(key, hash);

    uint8_t *output = (uint8_t*)data;
    for (int i = 0; i < 32; i++) {
        output[i] ^= hash[i];
    }
}

/**
 * Rajapinnan selkeyttämiseksi erilliset funktiot salaukselle ja purkamiselle.
 */
void LifeEncrypt(void *block32, const void *key32) {
    LifeXorCrypt(block32, key32);
}
void LifeDecrypt(void *block32, const void *key32) {
    LifeXorCrypt(block32, key32);
}

Grez [06.07.2024 10:46:55]

#

jone2712 kirjoitti:

Grypt-koodi ei anna yhtään reduntassia, vaikka yrittää avata gryptauksen avaimella, joka on yhden bitin päässä oikeasta avaimesta.

Tuntuu hullunkuriselta että toistelet tätä kokonaisturvallisuuden kannalta hirvittävän pientä yksittäistä seikkaa joka välissä.

Kuulostaa vähän samalta kun selittäisin kuinka mun suunnittelema auto on maailman tehokkain, koska siinä on aerodynaaminen sivupeili.

Metabolix [06.07.2024 15:16:46]

#

Minusta taas tuntuu hullunkuriselta yrittää kuvitella käyttötapausta, jossa hakkeri voi kokeilla johonkin järjestelmään eri salausavaimia ja saada jotenkin niistä palautetta, paljonko datasta on purettu oikein, kuitenkaan näkemättä dataa kummassakaan muodossa.

Jos hakkeria kiinnostaisi varsinainen data eikä alkuperäinen salausavain, silloinhan olisi turha murtaa Jonen algoritmia, kun voisi sen sijaan murtaa xor-kryptaukseen tarvittavan välituloksen, jonka LifeMix256 yllä refaktoroidussa koodissani tuottaa. Tosin en ole varma, onko tämä tavallisen xor-kryptauksen sisältyminen algoritmiin vielä päässyt osaksi kirjoittajan maailmankuvaa. :) :) :)

Samalla periaatteella voisi toteuttaa 256-bittisen salauksen vaikka SHA256:lla, eli tulos = data XOR SHA256(avain). Toki Jonen koodi on nopeampi ja käyttää vähemmän tilaa kuin SHA256. Esimerkiksi OpenSSL:n SHA256 vie koneellani noin kolminkertaisesti aikaa 10 miljoonan 32-tavuisen lohkon käsittelyyn.

wy5vn [11.07.2024 00:42:51]

#

Kysyin tekoälyltä:

https://chatgpt.com/share/41847848-204f-4e1f-87b2-06183b915138

mpni [11.07.2024 01:41:19]

#

Tuossa tapauksessa tekoäly ei voi paljon auttaa. Se tarttuu vain yksittäisiin sanoihin ja antaa palautteen sen mukaan. Oikeampi tapa olisi kysyä, kuinka koodia voisi parantaa ja analysoida tätä vastausta. Sama asia kuin kysyisit, että "Onko Ford hyvä auto?", kun taas toisaalta voisit kysyä, "Miksi Ford ei ole hyvä auto?", jos nyt ylipäätään oletetaan, että tekoäly on kaikkitietävä profeetta ja tarjoaa aina oikeita vastauksia...

wy5vn [11.07.2024 13:41:41]

#

No jep

Metabolix [11.07.2024 18:36:58]

#

Tekoälyn antaman analyysin virheestä tuli mieleeni: Vaikka yhden bitin muutos avaimessa sotkee tulosta paljon, yhden bitin muutos datassa aiheuttaa vain täsmälleen saman bitin muutoksen salauksen tai purun jälkeen. Eli tässä on Jonelle seuraava työsarka, miten saisi algoritmin tuottamaan "sekasotkua" myös datan yhden bitin muutoksissa.

Demo:

int main(void)
{
    char orig[32] = "TimoAnitaRikuSannaRistoOlliJone", enc[32], tmp[32];
    uint8_t key[32] = {1,2,3,4,5};

    // Salataan data.
    memcpy(enc, orig, 32);
    LifeEncrypt(enc, key);

    // 1) Puretaan ja näytetään.
    memcpy(tmp, enc, 32);
    LifeDecrypt(tmp, key);
    printf("%s ilman muutosta\n", tmp);

    // 2) Ajetaan joka merkille chr ^ 'A' ^ 'a'.
    for (int i = 0; orig[i]; ++i) {
        tmp[i] ^= 'A' ^ 'a';
    }
    printf("%s ^ 'A' ^ 'a'\n", tmp);

    // 3) Ajetaan sama xor-muutos ENNEN purkua ja näytetään, että tulos on sama.
    memcpy(tmp, enc, 32);
    for (int i = 0; orig[i]; ++i) {
        tmp[i] ^= 'A' ^ 'a';
    }
    LifeDecrypt(tmp, key);
    printf("%s ^ 'A' ^ 'a' jo ennen purkua\n", tmp);

    #ifdef WIN32
    getchar();
    #endif
}

Kannattaa tutustua myös aiheeseen Block cipher mode of operation. Erityisesti Jonen kannattaa kiinnittää huomiota kyseisellä sivulla esiintyvään pingviinin kuvaan, jossa esitetään graafisesti ongelma: jos sama viesti (samalla avaimella enkryptattuna) esiintyy kahteen kertaan, hakkeri näkee suoraan, että kyseessä on sama viesti, vaikka ei tietäisi sisältöä. Jonen algoritmissa tämä ongelma laajenee jokaiseen viestin bittiin, eli kun Jonen mikrokontrolleri sanoo ”data=1234”, hakkeri näkee ”asdf^qwer”, ja kun mikrokontrolleri sanoo ”data=5678”, hakkeri näkee ”asdf^zxcv”, ja tämäntyyppistä tietoa keräämällä hakkeri voi lopulta päästä kiinni dataan jopa purkamatta salausta.


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta