aboutsummaryrefslogtreecommitdiff
path: root/src/Protocols/GameSpy0/algorithm.cpp
blob: 5250079de3c0cc9990d0eae3a1641248e5eccb66 (plain)
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
#include "securevalidate.h"

/* This algorithm is based on Luigi Auriemma's gsmsalg 0.3.3,
 * https://aluigi.altervista.org/papers/gsmsalg.h
 * under GNU General Public License v2.
 */
QString generateValidateString(const QByteArray &cipher,
                               const QByteArray &secure,
                               const int        &enctype)
{
    unsigned char cipherLength = static_cast<unsigned char>( cipher.length() );
    unsigned char secureLength = static_cast<unsigned char>( secure.length() );

    // fill array with ascii characters
    unsigned char enc[256];
    for (unsigned short j = 0; j < 256; j++)
    {
        enc[j] = static_cast<unsigned char>(j);
    }

    // cipher shuffle
    unsigned char a = 0, x;
    for (unsigned short j = 0; j < 256; j++)
    {
        a += enc[j] + cipher[j % cipherLength];
        x  = enc[a];
        enc[a] = enc[j];
        enc[j] = x;
    }

    // secure shuffle
    unsigned char tmp[66];
    unsigned char i = 0,
                  y = 0,
                  b = 0;
                  a = 0; // reset a
    for (i = 0; i < cipherLength; i++)
    {
        a += secure.at(i) + 1;
        x = enc[a];
        b += x;
        y = enc[b];
        enc[b] = x;
        enc[a] = y;
        tmp[i] = static_cast<unsigned char>( secure.at(i) ^ enc[ (x+y) & 0xff ] );
    }

    // part of the enctype 1-2 process (uses i from previous loop)
    for (secureLength = i; secureLength % 3; secureLength++)
    {
        tmp[secureLength] = 0;
    }

    // enctype 1 shuffle
    if (enctype == 1)
    {
        for (i = 0; i < secureLength; i++)
        {
            tmp[i] = enctype1_data[ tmp[i] ];
        }
    }
    else if (enctype == 2 )
    {
        for (i = 0; i < secureLength; i++)
        {
            tmp[i] = static_cast<unsigned char>(tmp[i] ^ cipher[i % cipherLength] );
        }
    }

    // final shuffle and stitch validate response together
    unsigned char z = 0;
    QString validate;
    for (i = 0; i < secureLength; i += 3)
    {
        x = (tmp[i]);
        y = (tmp[i+1]);
        z = (tmp[i+2]);

        validate.append( charshift (x >> 2) );
        validate.append( charshift (static_cast<unsigned char>(((x & 3)  << 4) | (y >> 4)) ));
        validate.append( charshift (static_cast<unsigned char>(((y & 15) << 2) | (z >> 6)) ));
        validate.append( charshift (z & 63));
    }
    return validate;
}

// part of gsmsalg 0.3.3 and license
unsigned char charshift ( const unsigned char &reg )
{
    if (reg <  26) return (reg + 'A');
    if (reg <  52) return (reg + 'G');
    if (reg <  62) return (reg - 4);
    if (reg == 62) return ('+');
    if (reg == 63) return ('/');
    return (0);
}