跳转至

File tripledes.cc

File List > details > tripledes.cc

Go to the documentation of this file

#include <cstdio>
#include <qqmusic/details/tripledes.h>

namespace qqmusic::details {

static std::vector<std::vector<uint32_t>> key_schedule(const uint8_t* key_head,
                                                       size_t key_size,
                                                       tripledes_crypt_mode mode);

static uint32_t bitnum(const uint8_t* head, size_t size, uint32_t b, uint32_t c);

static uint32_t bitnum_intl(uint32_t a, uint32_t b, uint32_t c);

static uint32_t bitnum_intr(uint32_t a, uint32_t b, uint32_t c);

static void crypt(utils::buffer& buf, std::vector<std::vector<uint32_t>> key);

static void initial_permutation(uint32_t* a, uint32_t* b, utils::buffer& buf);

static void inverse_permutation(uint32_t a, uint32_t b, utils::buffer& buf);

static uint32_t transform(uint32_t state, std::vector<uint32_t> key);

static uint32_t sbox_bit(uint32_t a);

// extern api
tripledes_key_schedule tripledes_key_setup(const uint8_t* key_head,
                                           size_t key_size,
                                           tripledes_crypt_mode mode) {
    std::vector<std::vector<std::vector<uint32_t>>> res;

    if (mode == tripledes_crypt_mode::encrypt) {
        res.push_back(key_schedule(key_head, key_size, tripledes_crypt_mode::encrypt));
        res.push_back(key_schedule(key_head + 8, key_size - 8, tripledes_crypt_mode::decrypt));
        res.push_back(key_schedule(key_head + 16, key_size - 16, tripledes_crypt_mode::encrypt));
    } else {
        res.push_back(key_schedule(key_head + 16, key_size - 16, tripledes_crypt_mode::decrypt));
        res.push_back(key_schedule(key_head + 8, key_size - 8, tripledes_crypt_mode::encrypt));
        res.push_back(key_schedule(key_head, key_size, tripledes_crypt_mode::decrypt));
    }

    return res;
}

// extern api
void tripledes_crypt(utils::buffer& buf_in,
                     utils::buffer& buf_out,
                     tripledes_key_schedule key_schedule) {
    for (int i = 0; i < 3; ++i) {
        crypt(buf_in, key_schedule[i]);
    }

    // insert processed data into output buffer
    buf_out.append(buf_in.data(), buf_in.size());
}

static std::vector<std::vector<uint32_t>> key_schedule(const uint8_t* key_head,
                                                       size_t key_size,
                                                       tripledes_crypt_mode mode) {
    std::vector<std::vector<uint32_t>> schedule(16, std::vector<uint32_t>(6, 0L));
    const uint32_t key_rnd_shift[] = {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};
    const uint32_t key_perm_c[] = {56, 48, 40, 32, 24, 16, 8,  0,  57, 49, 41, 33, 25, 17,
                                   9,  1,  58, 50, 42, 34, 26, 18, 10, 2,  59, 51, 43, 35};
    const uint32_t key_perm_d[] = {62, 54, 46, 38, 30, 22, 14, 6,  61, 53, 45, 37, 29, 21,
                                   13, 5,  60, 52, 44, 36, 28, 20, 12, 4,  27, 19, 11, 3};
    const uint32_t key_compression[] = {13, 16, 10, 23, 0,  4,  2,  27, 14, 5,  20, 9,
                                        22, 18, 11, 3,  25, 7,  15, 6,  26, 19, 12, 1,
                                        40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47,
                                        43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31};

    uint32_t c = 0, d = 0;
    for (int i = 0; i < 28; ++i) {
        c += bitnum(key_head, key_size, key_perm_c[i], 31 - i);
        d += bitnum(key_head, key_size, key_perm_d[i], 31 - i);
    }

    for (int i = 0; i < 16; ++i) {
        c = ((c << key_rnd_shift[i]) | (c >> (28 - key_rnd_shift[i]))) & 0xfffffff0;
        d = ((d << key_rnd_shift[i]) | (d >> (28 - key_rnd_shift[i]))) & 0xfffffff0;

        int togen = mode == tripledes_crypt_mode::decrypt ? 15 - i : i;

        for (int j = 0; j < 6; ++j) {
            schedule[togen][j] = 0;
        }

        for (int j = 0; j < 24; ++j) {
            schedule[togen][j / 8] |= bitnum_intr(c, key_compression[j], 7 - (j % 8));
        }

        for (int j = 24; j < 48; ++j) {
            schedule[togen][j / 8] |= bitnum_intr(d, key_compression[j] - 27, 7 - (j % 8));
        }
    }

    return schedule;
}

static uint32_t bitnum(const uint8_t* head, size_t size, uint32_t b, uint32_t c) {
    return ((head[(b / 32) * 4 + 3 - (b % 32) / 8] >> (7 - b % 8)) & 1) << c;
}

static uint32_t bitnum_intl(uint32_t a, uint32_t b, uint32_t c) {
    return ((a << b) & 0x80000000) >> c;
}

static uint32_t bitnum_intr(uint32_t a, uint32_t b, uint32_t c) {
    return ((a >> (31 - b)) & 1) << c;
}

static void crypt(utils::buffer& buf, std::vector<std::vector<uint32_t>> key) {
    uint32_t a = 0, b = 0;
    initial_permutation(&a, &b, buf);

    for (int i = 0; i < 15; ++i) {
        long tmp = b;
        b = transform(b, key[i]) ^ a;
        a = tmp;
    }
    a = transform(b, key[15]) ^ a;

    inverse_permutation(a, b, buf);
}

static void initial_permutation(uint32_t* a, uint32_t* b, utils::buffer& buf) {
    uint8_t* input_data = buf.data();
    size_t size = buf.size();

    *a = (bitnum(input_data, size, 57, 31) | bitnum(input_data, size, 49, 30)
          | bitnum(input_data, size, 41, 29) | bitnum(input_data, size, 33, 28)
          | bitnum(input_data, size, 25, 27) | bitnum(input_data, size, 17, 26)
          | bitnum(input_data, size, 9, 25) | bitnum(input_data, size, 1, 24)
          | bitnum(input_data, size, 59, 23) | bitnum(input_data, size, 51, 22)
          | bitnum(input_data, size, 43, 21) | bitnum(input_data, size, 35, 20)
          | bitnum(input_data, size, 27, 19) | bitnum(input_data, size, 19, 18)
          | bitnum(input_data, size, 11, 17) | bitnum(input_data, size, 3, 16)
          | bitnum(input_data, size, 61, 15) | bitnum(input_data, size, 53, 14)
          | bitnum(input_data, size, 45, 13) | bitnum(input_data, size, 37, 12)
          | bitnum(input_data, size, 29, 11) | bitnum(input_data, size, 21, 10)
          | bitnum(input_data, size, 13, 9) | bitnum(input_data, size, 5, 8)
          | bitnum(input_data, size, 63, 7) | bitnum(input_data, size, 55, 6)
          | bitnum(input_data, size, 47, 5) | bitnum(input_data, size, 39, 4)
          | bitnum(input_data, size, 31, 3) | bitnum(input_data, size, 23, 2)
          | bitnum(input_data, size, 15, 1) | bitnum(input_data, size, 7, 0));

    *b = (bitnum(input_data, size, 56, 31) | bitnum(input_data, size, 48, 30)
          | bitnum(input_data, size, 40, 29) | bitnum(input_data, size, 32, 28)
          | bitnum(input_data, size, 24, 27) | bitnum(input_data, size, 16, 26)
          | bitnum(input_data, size, 8, 25) | bitnum(input_data, size, 0, 24)
          | bitnum(input_data, size, 58, 23) | bitnum(input_data, size, 50, 22)
          | bitnum(input_data, size, 42, 21) | bitnum(input_data, size, 34, 20)
          | bitnum(input_data, size, 26, 19) | bitnum(input_data, size, 18, 18)
          | bitnum(input_data, size, 10, 17) | bitnum(input_data, size, 2, 16)
          | bitnum(input_data, size, 60, 15) | bitnum(input_data, size, 52, 14)
          | bitnum(input_data, size, 44, 13) | bitnum(input_data, size, 36, 12)
          | bitnum(input_data, size, 28, 11) | bitnum(input_data, size, 20, 10)
          | bitnum(input_data, size, 12, 9) | bitnum(input_data, size, 4, 8)
          | bitnum(input_data, size, 62, 7) | bitnum(input_data, size, 54, 6)
          | bitnum(input_data, size, 46, 5) | bitnum(input_data, size, 38, 4)
          | bitnum(input_data, size, 30, 3) | bitnum(input_data, size, 22, 2)
          | bitnum(input_data, size, 14, 1) | bitnum(input_data, size, 6, 0));
}

static void inverse_permutation(uint32_t a, uint32_t b, utils::buffer& buf) {
    uint8_t data[8] = {0};

    data[3] = (bitnum_intr(b, 7, 7) | bitnum_intr(a, 7, 6) | bitnum_intr(b, 15, 5)
               | bitnum_intr(a, 15, 4) | bitnum_intr(b, 23, 3) | bitnum_intr(a, 23, 2)
               | bitnum_intr(b, 31, 1) | bitnum_intr(a, 31, 0));

    data[2] = (bitnum_intr(b, 6, 7) | bitnum_intr(a, 6, 6) | bitnum_intr(b, 14, 5)
               | bitnum_intr(a, 14, 4) | bitnum_intr(b, 22, 3) | bitnum_intr(a, 22, 2)
               | bitnum_intr(b, 30, 1) | bitnum_intr(a, 30, 0));

    data[1] = (bitnum_intr(b, 5, 7) | bitnum_intr(a, 5, 6) | bitnum_intr(b, 13, 5)
               | bitnum_intr(a, 13, 4) | bitnum_intr(b, 21, 3) | bitnum_intr(a, 21, 2)
               | bitnum_intr(b, 29, 1) | bitnum_intr(a, 29, 0));

    data[0] = (bitnum_intr(b, 4, 7) | bitnum_intr(a, 4, 6) | bitnum_intr(b, 12, 5)
               | bitnum_intr(a, 12, 4) | bitnum_intr(b, 20, 3) | bitnum_intr(a, 20, 2)
               | bitnum_intr(b, 28, 1) | bitnum_intr(a, 28, 0));

    data[7] = (bitnum_intr(b, 3, 7) | bitnum_intr(a, 3, 6) | bitnum_intr(b, 11, 5)
               | bitnum_intr(a, 11, 4) | bitnum_intr(b, 19, 3) | bitnum_intr(a, 19, 2)
               | bitnum_intr(b, 27, 1) | bitnum_intr(a, 27, 0));

    data[6] = (bitnum_intr(b, 2, 7) | bitnum_intr(a, 2, 6) | bitnum_intr(b, 10, 5)
               | bitnum_intr(a, 10, 4) | bitnum_intr(b, 18, 3) | bitnum_intr(a, 18, 2)
               | bitnum_intr(b, 26, 1) | bitnum_intr(a, 26, 0));

    data[5] = (bitnum_intr(b, 1, 7) | bitnum_intr(a, 1, 6) | bitnum_intr(b, 9, 5)
               | bitnum_intr(a, 9, 4) | bitnum_intr(b, 17, 3) | bitnum_intr(a, 17, 2)
               | bitnum_intr(b, 25, 1) | bitnum_intr(a, 25, 0));

    data[4] = (bitnum_intr(b, 0, 7) | bitnum_intr(a, 0, 6) | bitnum_intr(b, 8, 5)
               | bitnum_intr(a, 8, 4) | bitnum_intr(b, 16, 3) | bitnum_intr(a, 16, 2)
               | bitnum_intr(b, 24, 1) | bitnum_intr(a, 24, 0));

    buf.clear();
    buf.append(data, 8);
}

static uint32_t transform(uint32_t state, std::vector<uint32_t> key) {
    uint32_t sbox[8][64] = {
        // sbox1
        {14, 4,  13, 1, 2,  15, 11, 8, 3, 10, 6, 12, 5,  9,  0,  7,  0,  15, 7,  4,  14, 2,
         13, 1,  10, 6, 12, 11, 9,  5, 3, 8,  4, 1,  14, 8,  13, 6,  2,  11, 15, 12, 9,  7,
         3,  10, 5,  0, 15, 12, 8,  2, 4, 9,  1, 7,  5,  11, 3,  14, 10, 0,  6,  13},

        // sbox2
        {15, 1,  8,  14, 6,  11, 3,  4, 9,  7,  2, 13, 12, 0,  5,  10, 3,  13, 4,  7, 15, 2,
         8,  15, 12, 0,  1,  10, 6,  9, 11, 5,  0, 14, 7,  11, 10, 4,  13, 1,  5,  8, 12, 6,
         9,  3,  2,  15, 13, 8,  10, 1, 3,  15, 4, 2,  11, 6,  7,  12, 0,  5,  14, 9},

        // sbox3
        {10, 0,  9,  14, 6, 3,  15, 5,  1,  13, 12, 7, 11, 4,  2,  8,  13, 7, 0,  9, 3, 4,
         6,  10, 2,  8,  5, 14, 12, 11, 15, 1,  13, 6, 4,  9,  8,  15, 3,  0, 11, 1, 2, 12,
         5,  10, 14, 7,  1, 10, 13, 0,  6,  9,  8,  7, 4,  15, 14, 3,  11, 5, 2,  12},

        // sbox4
        {7, 13, 14, 3, 0, 6,  9, 10, 1,  2,  8,  5, 11, 12, 4,  15, 13, 8,  11, 5, 6, 15,
         0, 3,  4,  7, 2, 12, 1, 10, 14, 9,  10, 6, 9,  0,  12, 11, 7,  13, 15, 1, 3, 14,
         5, 2,  8,  4, 3, 15, 0, 6,  10, 10, 13, 8, 9,  4,  5,  11, 12, 7,  2,  14},

        // sbox5
        {2,  12, 4, 1,  7,  10, 11, 6, 8, 5,  3, 15, 13, 0,  14, 9,  14, 11, 2,  12, 4,  7,
         13, 1,  5, 0,  15, 10, 3,  9, 8, 6,  4, 2,  1,  11, 10, 13, 7,  8,  15, 9,  12, 5,
         6,  3,  0, 14, 11, 8,  12, 7, 1, 14, 2, 13, 6,  15, 0,  9,  10, 4,  5,  3},

        // sbox6
        {12, 1,  10, 15, 9,  2,  6, 8,  0, 13, 3,  4,  14, 7,  5, 11, 10, 15, 4, 2, 7, 12,
         9,  5,  6,  1,  13, 14, 0, 11, 3, 8,  9,  14, 15, 5,  2, 8,  12, 3,  7, 0, 4, 10,
         1,  13, 11, 6,  4,  3,  2, 12, 9, 5,  15, 10, 11, 14, 1, 7,  6,  0,  8, 13},

        // sbox7
        {4, 11, 2,  14, 15, 0,  8,  13, 3, 12, 9,  7, 5,  10, 6,  1,  13, 0,  11, 7,  4, 9,
         1, 10, 14, 3,  5,  12, 2,  15, 8, 6,  1,  4, 11, 13, 12, 3,  7,  14, 10, 15, 6, 8,
         0, 5,  9,  2,  6,  11, 13, 8,  1, 4,  10, 7, 9,  5,  0,  15, 14, 2,  3,  12},

        // sbox8
        {13, 2, 8,  4, 6, 15, 11, 1,  10, 9,  3, 14, 5,  0,  12, 7,  1,  15, 13, 8, 10, 3,
         7,  4, 12, 5, 6, 11, 0,  14, 9,  2,  7, 11, 4,  1,  9,  12, 14, 2,  0,  6, 10, 13,
         15, 3, 5,  8, 2, 1,  14, 7,  4,  10, 8, 13, 15, 12, 9,  0,  3,  5,  6,  11},
    };

    uint32_t t1 = (bitnum_intl(state, 31, 0) | ((state & 0xf0000000) >> 1)
                   | bitnum_intl(state, 4, 5) | bitnum_intl(state, 3, 6)
                   | ((state & 0x0f000000) >> 3) | bitnum_intl(state, 8, 11)
                   | bitnum_intl(state, 7, 12) | ((state & 0x00f00000) >> 5)
                   | bitnum_intl(state, 12, 17) | bitnum_intl(state, 11, 18)
                   | ((state & 0x000f0000) >> 7) | bitnum_intl(state, 16, 23));

    uint32_t t2 = (bitnum_intl(state, 15, 0) | ((state & 0x0000f000) << 15)
                   | bitnum_intl(state, 20, 5) | bitnum_intl(state, 19, 6)
                   | ((state & 0x00000f00) << 13) | bitnum_intl(state, 24, 11)
                   | bitnum_intl(state, 23, 12) | ((state & 0x000000f0) << 11)
                   | bitnum_intl(state, 28, 17) | bitnum_intl(state, 27, 18)
                   | ((state & 0x0000000f) << 9) | bitnum_intl(state, 0, 23));

    uint32_t lrgstate[] = {
        (t1 >> 24) & 0x000000ff,
        (t1 >> 16) & 0x000000ff,
        (t1 >> 8) & 0x000000ff,
        (t2 >> 24) & 0x000000ff,
        (t2 >> 16) & 0x000000ff,
        (t2 >> 8) & 0x000000ff,
    };

    for (int i = 0; i < 6; ++i) {
        lrgstate[i] ^= key[i];
    }

    state = ((sbox[0][sbox_bit(lrgstate[0] >> 2)] << 28)
             | (sbox[1][sbox_bit(((lrgstate[0] & 0x03) << 4) | (lrgstate[1] >> 4))] << 24)
             | (sbox[2][sbox_bit(((lrgstate[1] & 0x0f) << 2) | (lrgstate[2] >> 6))] << 20)
             | (sbox[3][sbox_bit(lrgstate[2] & 0x3f)] << 16)
             | (sbox[4][sbox_bit(lrgstate[3] >> 2)] << 12)
             | (sbox[5][sbox_bit(((lrgstate[3] & 0x03) << 4) | (lrgstate[4] >> 4))] << 8)
             | (sbox[6][sbox_bit(((lrgstate[4] & 0x0f) << 2) | (lrgstate[5] >> 6))] << 4)
             | sbox[7][sbox_bit(lrgstate[5] & 0x3f)]);

    return (bitnum_intl(state, 15, 0) | bitnum_intl(state, 6, 1) | bitnum_intl(state, 19, 2)
            | bitnum_intl(state, 20, 3) | bitnum_intl(state, 28, 4) | bitnum_intl(state, 11, 5)
            | bitnum_intl(state, 27, 6) | bitnum_intl(state, 16, 7) | bitnum_intl(state, 0, 8)
            | bitnum_intl(state, 14, 9) | bitnum_intl(state, 22, 10) | bitnum_intl(state, 25, 11)
            | bitnum_intl(state, 4, 12) | bitnum_intl(state, 17, 13) | bitnum_intl(state, 30, 14)
            | bitnum_intl(state, 9, 15) | bitnum_intl(state, 1, 16) | bitnum_intl(state, 7, 17)
            | bitnum_intl(state, 23, 18) | bitnum_intl(state, 13, 19) | bitnum_intl(state, 31, 20)
            | bitnum_intl(state, 26, 21) | bitnum_intl(state, 2, 22) | bitnum_intl(state, 8, 23)
            | bitnum_intl(state, 18, 24) | bitnum_intl(state, 12, 25) | bitnum_intl(state, 29, 26)
            | bitnum_intl(state, 5, 27) | bitnum_intl(state, 21, 28) | bitnum_intl(state, 10, 29)
            | bitnum_intl(state, 3, 30) | bitnum_intl(state, 24, 31));
}

static uint32_t sbox_bit(uint32_t a) {
    return (a & 32) | ((a & 31) >> 1) | ((a & 1) << 4);
}

} // namespace qqmusic::details