[JAVA] Reverse engineering Bitwise

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Disksoft
  • Registratie: September 2003
  • Laatst online: 09-09 23:17
Hallo,

Ik ben momenteel bezig met het reverse engineering van een stuk code.
Ik wil de volgende functie omdraaien.
Java:
1
2
3
4
5
6
7
    private static int f(int x)
    {
        x &= 65535;     
        x = 0xFFFF & k43[(x >> 8 & 0xFF)] << 8 | k21[(x & 0xFF)];

        return (x << 5 & 0xFFFF | x >> 11) & 0xFFFF;
    }


Ik heb bovenstaand stuk zelf uitgerekend.
De input van x=9553 en de uitkomst is 31572 (gecheckt met de debug mode).
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
f(x=9553) {
    x &= 65535;     
    x = 0xFFFF & k43[(x >> 8 & 0xFF)] << 8 | k21[(x & 0xFF)];

    //  x = 65535  & K43[(x >> 8 &  255)] << 8 | K21[(x &  255)];
    //  x = 65535  & K43[37] << 8 | K21[81];
    //  x = 65535  & 163 << 8 | 218;
    //  x = 65535  & 41728 | 218
    //  x = 65535  & 41946
      
    return (x << 5 & 0xFFFF | x >> 11) & 0xFFFF;
//1 return (41946 << 5 & 65535 | 41946 >> 11) & 65535;
//2 return (1342272 & 65535 | 20) & 65535;
//3 return (31552 | 20) & 65535;
//4 return 31572 & 65535;
//5 return 31572
}


Wat ik nu wil is dus van de waarde 31572 naar 9553 terug rekenen.

Wat heb ik tot nu toe:
Java:
1
2
3
4
5
6
7
8
9
    private static int fr(int x)
    {
        x ^= 20;
        System.out.println("x is now: " +x);  // x= 31552 wat overeenkomt met return 3
        x |= ~65535;
        System.out.println("x zou nu 1342272 moeten zijn.");
        
        return x;
    }

Waar ik tegen aanloop is het volgende hoe kan ik van de waarde 31552 weer naar de waarde 1342272 terwijl ik alleen een tweede waarde weet van 65535

code:
1
2
3
4
5
6
7
8
9
10
11
Functie f
    00000000000101000111101101000000    1342272
    00000000000000001111111111111111    65535
    --------------------------------    AND (&)
    00000000000000000111101101000000    31552

Functie fr ??
    00000000000000000111101101000000    31552
    00000000000000001111111111111111    65535
    ================================    ??????
    00000000000101000111101101000000    1342272


Dit is maar een klein stukje van de totale code die ik aan het omzetten ben, wat het normale script doet ik het volgende.

Het normale script is een controle van een login methode.
Je krijgt een 4 letterige naam [hoofdletters] en een Id [4-6 cijfers] en Pin code [4 cijfers].
In die combinatie van [NAME], [ID] en [PIN] zit een geldigheidsdatum verwerkt bijvoorbeeld 12/2014
In de Id+Pin code zit ook de naam verwerkt. Hij checkt dus ook of de [ID]+[PIN] combinatie geldig is met de ingegeven [NAME]

Bijvoorbeeld de naam BERO.
Het bijbehorende id is: 180093
De bijbehorende pin is: 8770
Deze code is geldig tot 12/2014

Wat het totale script doet is hij checkt of de combinatie [ID] en [PIN] de naam BERO kunnen creëren en of de geldigheidsdatum hoger is dan de huidige datum.

Ik wil uiteindelijk zelf code's kunnen genereren zodat ik deze inlog methode ook kan gebruiken.

Ik zal het totaal plaatje even erbij plakken, misschien is het nodig om bovenstaande vraag te kunnen beantwoorden.
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
import java.io.Serializable;
import java.util.ArrayList;
import java.util.GregorianCalendar;

public class User
implements Serializable
{
    private static final long serialVersionUID = 1L;

    private static int[] K4 = { 7, 13, 10, 1, 0, 8, 9, 15, 14, 4, 6, 12, 11, 2, 5, 3 };
    private static int[] K3 = { 5, 8, 1, 13, 10, 3, 4, 2, 14, 15, 12, 7, 6, 0, 9, 11 };
    private static int[] K2 = { 14, 11, 4, 12, 6, 13, 15, 10, 2, 3, 8, 1, 0, 7, 5, 9 };
    private static int[] K1 = { 4, 10, 9, 2, 13, 8, 0, 14, 6, 11, 1, 12, 7, 15, 5, 3 };

    private static int[] k43 = new int[256];
    private static int[] k21 = new int[256];

    private static int[] SDKEY = { 83, 75, 73, 68, 65, 84, 65, 0 };
    private static int[] SDKEY1 = { 96, 87, 84, 78, 74, 92, 72, 0 };

    public static void main(String[] args) {
        
        System.out.println("Login: 2014");
        loginAsServiceTechnician("BERO", 180093, 8750);

        /*  Waar ik uiteindelijk heen wil
        *  generateServiceTechnicain("BERO", "12", "2014");
        */
        
    }

    private static long ghostdecrypt(long in, int[] key)
    {
        for (int i = 0; i < 256; i++)
        {
            k43[i] = ((K4[(i >> 4)] << 4 | K3[(i & 0xF)]) & 0xFFFF);
            k21[i] = ((K2[(i >> 4)] << 4 | K1[(i & 0xF)]) & 0xFFFF);
        }

        for (int i = 0; i < 7; i++) {
            SDKEY1[i] = (SDKEY1[i] - 13 + i);
        }

        for (int i = 0; i < 8; i++) {
            SDKEY[i] = ((SDKEY[i] ^ SDKEY1[(7 - i)]) & 0xFFFF);
        }
        
        int n2 = (int)(in >> 16 & 0xFFFF);
        int n1 = (int)(in & 0xFFFF);

        
        int f = f(n1 + key[0]);
        n2 ^= 0xFFFF & f;
        n1 ^= 0xFFFF & f(n2 + key[1]);
        n2 ^= 0xFFFF & f(n1 + key[2]);
        n1 ^= 0xFFFF & f(n2 + key[3]);      
        n2 ^= 0xFFFF & f(n1 + key[4]);
        n1 ^= 0xFFFF & f(n2 + key[5]);
        n2 ^= 0xFFFF & f(n1 + key[6]);
        n1 ^= 0xFFFF & f(n2 + key[7]);

        n2 ^= 0xFFFF & f(n1 + key[7]);
        n1 ^= 0xFFFF & f(n2 + key[6]);
        n2 ^= 0xFFFF & f(n1 + key[5]);
        n1 ^= 0xFFFF & f(n2 + key[4]);
        n2 ^= 0xFFFF & f(n1 + key[3]);
        n1 ^= 0xFFFF & f(n2 + key[2]);
        n2 ^= 0xFFFF & f(n1 + key[1]);
        n1 ^= 0xFFFF & f(n2 + key[0]);

        K4 = new int[] { 7, 13, 10, 1, 0, 8, 9, 15, 14, 4, 6, 12, 11, 2, 5, 3 };
        K3 = new int[] { 5, 8, 1, 13, 10, 3, 4, 2, 14, 15, 12, 7, 6, 0, 9, 11 };
        K2 = new int[] { 14, 11, 4, 12, 6, 13, 15, 10, 2, 3, 8, 1, 0, 7, 5, 9 };
        K1 = new int[] { 4, 10, 9, 2, 13, 8, 0, 14, 6, 11, 1, 12, 7, 15, 5, 3 };

        k43 = new int[256];
        k21 = new int[256];

        SDKEY = new int[] { 83, 75, 73, 68, 65, 84, 65, 0 };
        SDKEY1 = new int[] { 96, 87, 84, 78, 74, 92, 72, 0 };

        return (n1 << 16) + n2;
    }

    private static int f(int x)
    {
        x &= 65535;     
        x = 0xFFFF & k43[(x >> 8 & 0xFF)] << 8 | k21[(x & 0xFF)];
        
        System.out.println(((x << 5 & 0xFFFF | x >> 11) & 0xFFFF));

        return (x << 5 & 0xFFFF | x >> 11) & 0xFFFF;
    }

    public static boolean loginAsServiceTechnician(String name, int id, int pin)
    {
        long data = ghostdecrypt(id * 10000 + pin, SDKEY);

        long months = data >> 20 & 0x1FF;

        char[] calculatedNameChars = new char[4];

        for (int i = 3; i >= 0; i--)
        {
            calculatedNameChars[i] = ((char)(int)((data & 0x1F) + 65L));
            data >>= 5;
        }

        String calculatedname = new String(calculatedNameChars);

        GregorianCalendar calendar = new GregorianCalendar();
        long monthsNow = calendar.get(1) * 12 + calendar.get(2) + 1;

        long validUntilMonth = 23929L + months;

        if (validUntilMonth <= monthsNow) {
            System.out.println("Authorization has Expired");
            return false;
        }

        if (name.equalsIgnoreCase(calculatedname))
        {
            System.out.println("Welcome "+name);
            return true;
        }
        System.out.println("Incorrect PIN");
        return false;
    }
}


Kan iemand mij helpen om deze hindernis over te steken.

Acties:
  • 0 Henk 'm!

  • Gerco
  • Registratie: Mei 2000
  • Laatst online: 03:25

Gerco

Professional Newbie

Wat je wilt is onmogelijk. Om even heel makkelijk te zeggen voor de volgende berekening:
code:
1
2
3
4
5
6
7
8
9
10
11
Functie f
    00000000000101000111101101000000    1342272
    00000000000000001111111111111111    65535
    --------------------------------    AND (&)
    00000000000000000111101101000000    31552

Functie fr ??
    00000000000000000111101101000000    31552
    00000000000000001111111111111111    65535
    ================================    ??????
    00000000000101000111101101000000    1342272


De operatie x &= 0xFFFF is niet om te draaien omdat er gegevens verloren gaan. Die gegevens kun je niet meer terug krijgen. Aangezien de functie "ghostdecrypt" heet lijkt het waarschijnlijk dat je wel een "ghostencrypt" functie kunt schrijven, maar waarschijnlijk niet door de bestaande functie gewoon om te draaien.

Je zult moeten begrijpen wat de functie doet en dat omkeren ipv instructie voor instructie te werken. Iets als x >> 8 & 0xFF is niet direct om te draaien (je verliest immers informatie), maar als je bekijkt wat het doet "lees de waarde van de tweede byte in het getal" is het al een stuk begrijpelijker en daar kun je wat mee.

[ Voor 29% gewijzigd door Gerco op 30-12-2014 22:02 ]

- "Als ik zou willen dat je het begreep, legde ik het wel beter uit!" | All number systems are base 10!


Acties:
  • 0 Henk 'm!

  • Daos
  • Registratie: Oktober 2004
  • Niet online
De functie die je probeert te reverse-engineren is vrij zeker een cryptografische hash. Samengevat: die functies zijn er op gemaakt dat ze maar 1 kant op werken. Je kan iets hashen en dat is alles wat je (als het goed is) er mee kan. Natuurlijk proberen meer mensen zoals jij ze te kraken en dat noemen we bij succes een collision attack of een preimage attack (wat jij wilt).

In jouw geval gaat het waarschijnlijk om een Russische GOST (zonder h) cipher. Als je weet welke variant, kan je zoeken of hij al gekraakt is. Zelf kraken is vrijwel onmogelijk (en misschien zelfs verboden: in NL staan lange celstraffen op het (proberen) omzeilen van beveiligingen)

edit:
Ik ben er nog niet helemaal uit. Misschien wil je geen hash kraken, maar zoek je gewoon hoe je iets moet encrypten. Dan moet je alleen even het encrypt-algoritme voor die GOST opzoeken en de juiste argumenten voeren.

[ Voor 11% gewijzigd door Daos op 30-12-2014 21:57 ]


Acties:
  • 0 Henk 'm!

  • Gerco
  • Registratie: Mei 2000
  • Laatst online: 03:25

Gerco

Professional Newbie

Er hoeft hier niets voor gekraakt te worden, alleen iets geencrypt en ik had wel zin in een puzzeltje dus ik heb de "ghostencrypt" functie voor je geschreven. Het principe is eigenlijk vrij eenvoudig en je hoeft daar de functie "f" niet eens voor om te keren. Het enige wat f() doet is een waarde genereren waar vervolgens de cipher/plaintext mee wordt geXORed.

Als je die XOR wilt omdraaien hoef je alleen het resultaat nogmaals te XORen met dezelfde waarde. Het is dus cruciaal om die functie f() ongemoeid te laten aangezien die bij zowel decryptie als encryptie dezelfde waardes moet returnen. Het enige verschil zit hem in de volgorde van de XOR operaties: Bij encryptie en decryptie moeten die natuurlijk in omgekeerde volgorde gedaan worden.

De oorspronkelijke code gebruikte als invoer zowel "key" als "SDKEY" en "SDKEY1". "key" en "SDKEY" waren dezelfde array dus die heb ik hier maar samengevoegd in de sdKey0 parameter. SDKEY1 heb ik hernoemd naar sdKey1, paste beter bij de rest.

Ik heb ook de functie f wat aangepast door de substitutie arrays als parameters mee te geven. Dat is iets minder smerig dan static variabelen aanpassen en na aanroep weer resetten naar de oorspronkelijke waarde.

Nu je de encrypt functie hebt kun je laatste stuk zelf doen. Je moet die encrypt functie gebruiken nadat je de goede plaintext hebt samengesteld met de juiste naam en vervaldatum erin.

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
    public static void main(String[] args) {
        long crypt = 180093 * 10000 + 8750;
        long plain = ghostdecrypt(crypt, getSDKEY0(), getSDKEY1());
        long recrypt = ghostencrypt(plain, getSDKEY0(), getSDKEY1());
     
        System.out.println(String.format("Crypt  : %x\nPlain  : %x\nRecrypt: %x", crypt, plain, recrypt));
    }

    private static long ghostencrypt(final long plain, int[] sdKey0, int[] sdKey1) {
        int[] K1 = new int[] { 4, 10, 9, 2, 13, 8, 0, 14, 6, 11, 1, 12, 7, 15, 5, 3 };
        int[] K2 = new int[] { 14, 11, 4, 12, 6, 13, 15, 10, 2, 3, 8, 1, 0, 7, 5, 9 };
        int[] K3 = new int[] { 5, 8, 1, 13, 10, 3, 4, 2, 14, 15, 12, 7, 6, 0, 9, 11 };
        int[] K4 = new int[] { 7, 13, 10, 1, 0, 8, 9, 15, 14, 4, 6, 12, 11, 2, 5, 3 };
        
        int[] k43 = new int[256];
        int[] k21 = new int[256];

        for (int i = 0; i < 256; i++)
        {
            k43[i] = ((K4[(i >> 4)] << 4 | K3[(i & 0xF)]) & 0xFFFF);
            k21[i] = ((K2[(i >> 4)] << 4 | K1[(i & 0xF)]) & 0xFFFF);
        }
        
        for (int i = 0; i < 7; i++) {
            sdKey1[i] = (sdKey1[i] - 13 + i);
        }

        for (int i = 0; i < 8; i++) {
            sdKey0[i] = ((sdKey0[i] ^ sdKey1[(7 - i)]) & 0xFFFF);
        }
        
        // Split into two 16 bit values, n1 being the higher 16 bits
        int n1 = (int)(plain >> 16 & 0xFFFF);
        int n2 = (int)(plain & 0xFFFF);
        
        // Perform encryption
        n1 ^= 0xFFFF & f(n2 + sdKey0[0], k43, k21);
        n2 ^= 0xFFFF & f(n1 + sdKey0[1], k43, k21);
        n1 ^= 0xFFFF & f(n2 + sdKey0[2], k43, k21);
        n2 ^= 0xFFFF & f(n1 + sdKey0[3], k43, k21);
        n1 ^= 0xFFFF & f(n2 + sdKey0[4], k43, k21);
        n2 ^= 0xFFFF & f(n1 + sdKey0[5], k43, k21);
        n1 ^= 0xFFFF & f(n2 + sdKey0[6], k43, k21);
        n2 ^= 0xFFFF & f(n1 + sdKey0[7], k43, k21);
        
        n1 ^= 0xFFFF & f(n2 + sdKey0[7], k43, k21);
        n2 ^= 0xFFFF & f(n1 + sdKey0[6], k43, k21);
        n1 ^= 0xFFFF & f(n2 + sdKey0[5], k43, k21);
        n2 ^= 0xFFFF & f(n1 + sdKey0[4], k43, k21);
        n1 ^= 0xFFFF & f(n2 + sdKey0[3], k43, k21);      
        n2 ^= 0xFFFF & f(n1 + sdKey0[2], k43, k21);
        n1 ^= 0xFFFF & f(n2 + sdKey0[1], k43, k21);
        n2 ^= 0xFFFF & f(n1 + sdKey0[0], k43, k21);
        
        // Reassemble back into a 32 bit value, with n1 in the lower 16 bits
        return ((long)n2 << 16) + (long)n1;
    }

    private static int f(int x, int[] k43, int[] k21)
    {
        // Only keep lowest 16 bits of the input
        x &= 0xFFFF; 
        
        // Take the high and low byte of x separately
        int highbyte = (x >> 8 & 0xFF);
        int lowbyte = (x & 0xFF);
        
        // Convert them using the substitution tables given
        highbyte = k43[highbyte];
        lowbyte  = k21[lowbyte];
        
        // Reassemble into a 16 bit value and keep only lower 16 bits
        x = 0xFFFF & highbyte << 8 | lowbyte;

        // Shuffle the bits (yyyyyxxxxxxxxxxx -> xxxxxxxxxxxyyyyy) and return
        return (x << 5 & 0xFFFF | x >> 11) & 0xFFFF;
    }

    private static int[] getSDKEY0() { 
        return new int[] {83, 75, 73, 68, 65, 84, 65, 0 };
    }
    
    private static int[] getSDKEY1() {
        return new int[] { 96, 87, 84, 78, 74, 92, 72, 0 };
    }


[edit]
Dit is niet de GOST cipher. GOST is een 64 bit block cipher met multiple rounds. Dit lijkt gewoon op wat home-grown crypto voor password validatie van een oud pakket (ergens uit 1994, schat ik uit de losse pols). Als er een block size is is het 32 bits en er is maar 1 round met een 128 bit key. Encryptie kun je dit niet echt noemen, een eerstejaars cryptanalyst hakt hier waarschijnlijk zonder moeite doorheen, ook zonder keys. (Dat is een gok, ik ben geen cryptanalist, maar er zitten een hele berg enorme zwakheden en gaten in deze cipher).

[edit2]
Ik had het aantal rounds verkeerd geïnterpreteerd en daardoor was mijn conclusie wat voorbarig (om maar niet te zeggen complete onzin). Dit is een afgeleide van GOST, zie later. Ik denk nog steeds dat het pakket uit 1994 komt, maar dat heeft weinig met de cipher te maken. De verloopdatum in de plaintext is gebaseerd op januari 1994 (misschien december 1993 of februari 1994).

[ Voor 10% gewijzigd door Gerco op 31-12-2014 17:55 . Reden: Bugje opgelost (met dank aan Java signed-only arithmetic) ]

- "Als ik zou willen dat je het begreep, legde ik het wel beter uit!" | All number systems are base 10!


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Daos schreef op dinsdag 30 december 2014 @ 21:40:
(en misschien zelfs verboden: in NL staan lange celstraffen op het (proberen) omzeilen van beveiligingen)
Zover ik weet is het in nederland niet verboden om beveiligingen te omzeilen. Hetgeen je daarmee doet kan mogelijk wel strafbaar zijn.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

  • terje7601
  • Registratie: September 2009
  • Laatst online: 08-02-2024
Gerco schreef op woensdag 31 december 2014 @ 04:10:
[edit]
Dit is niet de GOST cipher. GOST is een 64 bit block cipher met multiple rounds. Dit lijkt gewoon op wat home-grown crypto voor password validatie van een oud pakket (ergens uit 1994, schat ik uit de losse pols). Als er een block size is is het 32 bits en er is maar 1 round met een 128 bit key. Encryptie kun je dit niet echt noemen, een eerstejaars cryptanalyst hakt hier waarschijnlijk zonder moeite doorheen, ook zonder keys. (Dat is een gok, ik ben geen cryptanalist, maar er zitten een hele berg enorme zwakheden en gaten in deze cipher).
Volgens mij heeft Daos gelijk & is dit gewoon de GOST hash functie. De K1,K2,K3,K4 arrays uit de code staan ook gewoon beschreven als test parameters.

Acties:
  • 0 Henk 'm!

  • Gerco
  • Registratie: Mei 2000
  • Laatst online: 03:25

Gerco

Professional Newbie

Na er beter naar gekeken te hebben (het was laat gisteren) denk ik dat het inderdaad geen home grown crypto is. Tenminste niet zoals ik eerst dacht. Het zal een afgeleide van GOST zijn, maar het is gewoonweg niet hetzelfde:

GOSTghost
Block size64 bits32 bits
Key size256 bits128 bits
Rounds3216


De round function die deze ghost cipher gebruikt lijkt dezelfde te zijn als die van GOST, met de aanpassing in het aantal bits en hij wordt slechts 16x toegepast. Deze cipher lijkt dus op GOST en is er met zekerheid op gebaseerd, maar een out of the box GOST encrypt/decrypt functie gaat op deze data zeer zeker niet werken.

Het lijkt erop dat iemand de specs van GOST gepakt heeft en het geïmplementeerd heeft voor een kleiner aantal bits door alles te halveren. Volgens Wikipedia bestaat 32 bit GOST iig niet en ook in RFC 5830 zie ik geen 32 bits block size genoemd worden.

[ Voor 30% gewijzigd door Gerco op 31-12-2014 16:47 ]

- "Als ik zou willen dat je het begreep, legde ik het wel beter uit!" | All number systems are base 10!


Acties:
  • 0 Henk 'm!

  • Disksoft
  • Registratie: September 2003
  • Laatst online: 09-09 23:17
Thanks allen voor de informatie, ik ga kijken of ik hier mee verder kan.

Acties:
  • 0 Henk 'm!

  • Compizfox
  • Registratie: Januari 2009
  • Laatst online: 22:41

Compizfox

Bait for wenchmarks

Daos schreef op dinsdag 30 december 2014 @ 21:40:
Zelf kraken is vrijwel onmogelijk (en misschien zelfs verboden: in NL staan lange celstraffen op het (proberen) omzeilen van beveiligingen)
Maar het 'kraken' van een hashfunctie is veel breder dan het omzeilen van een beveiliging. Als je een hashfunctie echt zou kunnen kraken (en dus niet slechts het opstellen van een zooitje rainbowtables om zo collisions te misbruiken), dan betekent dat dat je een tekortkoming in het algoritme hebt ontdekt of misschien wel een wiskundig probleem hebt opgelost.

Ik geloof er dus niks van dat jouw redenering klopt. Het zou toch wat zijn dat je, als je zo'n belangrijk probleem hebt ontdekt in een veelgebruikt algoritme, dat je het niet (legaal) naar buiten mag brengen?

Gewoon een heel grote verzameling snoertjes


Acties:
  • 0 Henk 'm!

  • Disksoft
  • Registratie: September 2003
  • Laatst online: 09-09 23:17
Gerco,

Door de manier van opschonen van de code wat jij had gedaan ik bij mij het kwartje gevallen.
De oude methode die ik gepost had deed exact het zelfde, en ik kon al naar de plain versie toe rekenen.
Maar door dat ik nu duidelijker inzicht heb wat er gebeurt ben ik er achter hoe het werkt.

Elke 5 bits zijn is een waarde.
code:
1
2
3
4
5
6
7
10011111100000010010010001[01110]   1338020398  [01110] O
100111111000000100100[10001]        41813137    [10001] R  
1001111110000001[00100]             130660      [00100] E
10011111100[00001]                  40833       [00001] B
100111[11100]                       1276        [11100] 28
1[00111]                            39          [00111] 7
1                                   1           [1]


Ik moet alleen nog uitvogelen hoe het met de datum is berekend maar hier ga ik ook wel uit komen.
Het is me gelukt om met andere initialen een werkende code te maken voor 2015 ;-)
Aangezien ik eerst mijn nieuwe code terug gerekend heb zodat ik weet wat de rest waarde was, en vervolgens de nieuwe berekend heb.

Nogmaals bedankt iedereen voor de verhelderende uitleg! *O* *O* *O* *O*

Acties:
  • 0 Henk 'm!

  • Gerco
  • Registratie: Mei 2000
  • Laatst online: 03:25

Gerco

Professional Newbie

Die datum stelt niet zoveel voor. De variabele die is opgeslagen in de plaintext is een 9 bits getal wat het aantal maanden na Januari 1994 (of misschien eind 1993) voorstelt dat de code geldig is. Als de huidige datum dus later is dan 1994*12 + "months" is de code geldig.

De structuur van de plaintext is dus als volgt:

10 mmmmmmmmm aaaaa bbbbb ccccc ddddd

10 = constante bits, functie onbekend
m = months
a = eerste char van naam
b = tweede char van naam
etc.

Voorbeeld:
10 100001000 00110 00100 10001 00010
      264      G     E     R     C

264 + (12*1994)+1 = 2015*12+12+1 = Geldig tot December 2015



Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
    private static Technician generateServiceTechnician(String name, int year, int month) {
        if(name.length() != 4) {
            throw new IllegalArgumentException("Name must be 4 characters");
        }
        
        long data = 2; // MSB of plaintext is always 1 for unknown reason 
        
        // Encode the months in 9 bits
        long validUntilMonths = year * 12 + month + 1;
        long months = validUntilMonths - ((12*1994) + 1);
        data <<= 9;
        data += months & 0x1FF;
        
        // Encode the name into 5 bits per character
        for(int i=0; i<name.length(); i++) {
            char c = (char)(name.charAt(i) - 65);
            data <<= 5;
            data += c & 0x1F;
        }
        
        // Encrypt the data
        long cryptData = ghostencrypt(data, getSDKEY0(), getSDKEY1());
        
        // Now split in pin and id
        long pin = cryptData % 10000L; // Last 4 digits
        long id  = (cryptData - pin) / 10000L; // Remaining digits
        
        return new Technician(name, (int)id, (int)pin);
    }

    private static class Technician {
        private String name;
        private int id;
        private int pin;
        
        public Technician(String name, int id, int pin) {
            this.name = name;
            this.id = id;
            this.pin = pin;
        }
        
        @Override
        public String toString() {
            return "Technician [name=" + name + ", id=" + id + ", pin=" + pin + "]";
        }
    }


Bonusvraag: Aangezien het aantal maanden in 9 bits gecodeerd is, hoe lang kun je de verlooptijd maximaal maken voordat deze inlogmethode niet meer kan werken?

[ Voor 11% gewijzigd door Gerco op 02-01-2015 02:10 ]

- "Als ik zou willen dat je het begreep, legde ik het wel beter uit!" | All number systems are base 10!


Acties:
  • 0 Henk 'm!

  • Disksoft
  • Registratie: September 2003
  • Laatst online: 09-09 23:17
Gerco schreef op vrijdag 02 januari 2015 @ 01:49:
Die datum stelt niet zoveel voor. De variabele die is opgeslagen in de plaintext is een 9 bits getal wat het aantal maanden na Januari 1994 (of misschien eind 1993) voorstelt dat de code geldig is. Als de huidige datum dus later is dan 1994*12 + "months" is de code geldig.

De structuur van de plaintext is dus als volgt:

10 mmmmmmmmm aaaaa bbbbb ccccc ddddd

10 = constante bits, functie onbekend
m = months
a = eerste char van naam
b = tweede char van naam
etc.

Voorbeeld:
10 100001000 00110 00100 10001 00010
      264      G     E     R     C

264 + (12*1994)+1 = 2015*12+12+1 = Geldig tot December 2015



Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
    private static Technician generateServiceTechnician(String name, int year, int month) {
        if(name.length() != 4) {
            throw new IllegalArgumentException("Name must be 4 characters");
        }
        
        long data = 2; // MSB of plaintext is always 1 for unknown reason 
        
        // Encode the months in 9 bits
        long validUntilMonths = year * 12 + month + 1;
        long months = validUntilMonths - ((12*1994) + 1);
        data <<= 9;
        data += months & 0x1FF;
        
        // Encode the name into 5 bits per character
        for(int i=0; i<name.length(); i++) {
            char c = (char)(name.charAt(i) - 65);
            data <<= 5;
            data += c & 0x1F;
        }
        
        // Encrypt the data
        long cryptData = ghostencrypt(data, getSDKEY0(), getSDKEY1());
        
        // Now split in pin and id
        long pin = cryptData % 10000L; // Last 4 digits
        long id  = (cryptData - pin) / 10000L; // Remaining digits
        
        return new Technician(name, (int)id, (int)pin);
    }

    private static class Technician {
        private String name;
        private int id;
        private int pin;
        
        public Technician(String name, int id, int pin) {
            this.name = name;
            this.id = id;
            this.pin = pin;
        }
        
        @Override
        public String toString() {
            return "Technician [name=" + name + ", id=" + id + ", pin=" + pin + "]";
        }
    }


Bonusvraag: Aangezien het aantal maanden in 9 bits gecodeerd is, hoe lang kun je de verlooptijd maximaal maken voordat deze inlogmethode niet meer kan werken?
2036??

Acties:
  • 0 Henk 'm!

  • Disksoft
  • Registratie: September 2003
  • Laatst online: 09-09 23:17
Gerco schreef op vrijdag 02 januari 2015 @ 01:49:
...
[/code]

Bonusvraag: Aangezien het aantal maanden in 9 bits gecodeerd is, hoe lang kun je de verlooptijd maximaal maken voordat deze inlogmethode niet meer kan werken?
Ik ben nu bezig met een ander stukje wat van dezelfde Ghostcrypt functie gebruik maakt.
Ik heb de juiste manier van checken weten te achterhalen, alleen in mijn ogen is het onmogelijk om het terug te rekenen zodat je zelf de waardes weer kan maken.

Klopt mijn bevinding?

Bij num3, num4 en num5 gaan zoveel gegevens verloren dat ik niet kan terug rekenen naar de waarde die uit de Ghostcrypt komt.

Van het eerste voorbeeld CheckSystem(722036578L, 500314, 1) is de Ghostcrypt waarde 17577722
Hoe ik ook reken ik kom er niet op uit. Ook niet op 8788861 wat na 1 Bit shift naar links ook 17577722 is.

Zelf denk ik dat ik een soort gelijke functie als f moet schrijven, of de functie moet gebruiken om terug te kunnen rekenen.

Hoe ik het nu ook probeer het lukt niet.

De waardes die vooraf bekend zijn:
facilityNumber
systemNumber
en dat er standaard een 5 in bit 2,3,4 verwerkt zit.

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// CheckSystem
    
    CheckSystem(722036578L, 500314, 1)      
    CheckSystem(2203907415L, 502286, 3);
    CheckSystem(1865368801, 505057, 3);
    CheckSystem(986839560, 502807, 1);

    CheckSystem(3129331134, 503649, 1);  // Zelfde 503649 nummer, systeemnr 1 i.p.v. 3
    CheckSystem(1351603952, 503649, 3); // Zelfde 503649 nummer, systeemnr 3 i.p.v. 1

    public void CheckSystem (long systemCode, long facilityNumber, int systemNumber) {
        
        long num2 = Ghostcrypt(systemCode, getSDKEY0(), getSDKEY1());
        int num3 = (int) (num2 >> 1 & 5);
        int num4  = (int) (num2 >> 24);
        int num5 = (int) ((facilityNumber%10) + (num2 >>4 & 1048575) * 10);
        
        System.out.println("Input Facility Number: " + facilityNumber);
        System.out.println("Calculated Facility Number: " + num5);
        System.out.println();
        
        System.out.println("Input Systemnumber: " + systemNumber);
        System.out.println("Calculated Systemnumber: " + num4);
        System.out.println();
        
        System.out.println("Calculated value must be 5 and is: " + num3);
        System.out.println("");
        
        if(facilityNumber == num5 && systemNumber == num4 && num3 == 5) {
            System.out.println("Code is geldig");
        }
        else {
            System.out.println("Code is ongeldig");
        }
        
    }


Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// f Functie
    private static int f(int x, int[] k43, int[] k21)
    {
        // Only keep lowest 16 bits of the input
        x &= 0xFFFF; 
        
        // Take the high and low byte of x separately
        int highbyte = (x >> 8 & 0xFF);
        int lowbyte = (x & 0xFF);
        
        // Convert them using the substitution tables given
        highbyte = k43[highbyte];
        lowbyte  = k21[lowbyte];
        
        // Reassemble into a 16 bit value and keep only lower 16 bits
        x = 0xFFFF & highbyte << 8 | lowbyte;

        // Shuffle the bits (yyyyyxxxxxxxxxxx -> xxxxxxxxxxxyyyyy) and return
        return (x << 5 & 0xFFFF | x >> 11) & 0xFFFF;
    }

Acties:
  • 0 Henk 'm!

  • Gerco
  • Registratie: Mei 2000
  • Laatst online: 03:25

Gerco

Professional Newbie

Ik geloof niet dat ik je probleem helemaal begrijp, maar de opbouw van deze code lijkt best wel veel op de vorige. De bits betekenen het volgende:

     1098 7654 3210 9876 5432 1098 7654 3210     Notes
bit0                                       =     Unused
bit2                                     =       Unused
num3                                    = =      Bits 3-1: Shift right 1 bit and AND with 0101
num4 ==== ====                                   Bits 31-24 = systemNumber
num5           ==== ==== ==== ==== ====          Bits 23-4  = Math.floor(facilityNumber / 10)


Als ik het goed heb zouden deze getallen moeten werken:
System code: 2869021477
Facility number: 31337
System number: 42

[edit]
Waar ik overigens ook achter kwam: Het resultaat in ghostencrypt() en ghostdecrypt() lijken volstrekt identiek te zijn, ook al is de volgorde van de XOR operaties omgedraaid. De hele functie ghostencrypt() is daardoor compleet overbodig, je hebt maar 1 functie nodig.

[ Voor 22% gewijzigd door Gerco op 04-01-2015 21:15 ]

- "Als ik zou willen dat je het begreep, legde ik het wel beter uit!" | All number systems are base 10!


Acties:
  • 0 Henk 'm!

  • Disksoft
  • Registratie: September 2003
  • Laatst online: 09-09 23:17
Gerco schreef op zondag 04 januari 2015 @ 21:10:
Ik geloof niet dat ik je probleem helemaal begrijp, maar de opbouw van deze code lijkt best wel veel op de vorige. De bits betekenen het volgende:

     1098 7654 3210 9876 5432 1098 7654 3210     Notes
bit0                                       =     Unused
bit2                                     =       Unused
num3                                    = =      Bits 3-1: Shift right 1 bit and AND with 0101
num4 ==== ====                                   Bits 31-24 = systemNumber
num5           ==== ==== ==== ==== ====          Bits 23-4  = Math.floor(facilityNumber / 10)


Als ik het goed heb zouden deze getallen moeten werken:
System code: 2869021477
Facility number: 31337
System number: 42

[edit]
Waar ik overigens ook achter kwam: Het resultaat in ghostencrypt() en ghostdecrypt() lijken volstrekt identiek te zijn, ook al is de volgorde van de XOR operaties omgedraaid. De hele functie ghostencrypt() is daardoor compleet overbodig, je hebt maar 1 functie nodig.
De code die je gemaakt hebt klopt.
Alleen ik zie nog steeds niet hoe je hem samen gesteld.

Kan je een voorbeeld doen met de System Code: 1351603952 en Facility number: 503649 en System Number: 1
Wellicht zie ik dan wat er gebeurt ik haal het nu niet uit het voorbeeld van je.

code:
1
2
3
4
5
6
7
8
// Klopt dit?
1098 7654 3210 9876 5432 1098 7654 3210

        1 0000 1100 0100 1011 1100 1011
                                  =====
          ========================    5
==========         50364
         1

[ Voor 7% gewijzigd door Disksoft op 04-01-2015 21:32 ]


Acties:
  • 0 Henk 'm!

  • Gerco
  • Registratie: Mei 2000
  • Laatst online: 03:25

Gerco

Professional Newbie

Met die getallen kom ik uit op een andere system code: 1294837078. Voor zover ik kan zien is dat omdat bit 0 van de plaintext in de originele data op 1 staat. Deze bit wordt verder niet gebruikt bij de validatie maar zorgt wel voor een ander resultaat na encryptie.

Crypt: 10111010100001011100110110111110 (ba85cdbe) (3129331134)
Orig :        1000011000100101111001011 ( 10c4bcb) (17583051)
New  :        1000011000100101111001010 ( 10c4bca) (17583050)
NewC :  1001101001011011010010101010110 (4d2da556) (1294837078)


Als je bit 0 op 1 zet komt het wel goed uit. Geen idee wat die bit betekent, maar ik zou gokken dat bits 0-3 een soort access control zijn. Of misschien een facility type en deze controle keurt alleen facilities goed waarbij bits 1 en 3 aan staan en negeert bits 0 en 2.

Crypt: 10111010100001011100110110111110 (ba85cdbe) (3129331134)
Orig :        1000011000100101111001011 ( 10c4bcb) (17583051)
New  :        1000011000100101111001011 ( 10c4bcb) (17583051)
NewC : 10111010100001011100110110111110 (ba85cdbe) (3129331134)


De denkfout die je, volgens mij, maakt is dat je bits 0-3 als een getal ziet. Ik denk niet dat het een getal moet voorstellen. Ik denk dat het 4 vlaggen zijn die elk iets anders uitdrukken. Twee van die vlaggen worden bij deze validatie gebruikt en 2 niet. Bij een andere validatie kunnen het andere vlaggen zijn die van belang zijn. Het is dus niet te zeggen wat die vlaggen betekenen anders dan dat er 2 aan moeten staan om de facility goed te keuren bij deze controle.

[ Voor 18% gewijzigd door Gerco op 04-01-2015 22:01 ]

- "Als ik zou willen dat je het begreep, legde ik het wel beter uit!" | All number systems are base 10!

Pagina: 1