tea加密算法c++代碼的實現

經過c++來實現tea加密算法,最終編譯成so文件,以JNI的方式提供給客戶端調用,主要須要解決如下三個問題:c++

  1. 實現tea算法,這都有開源的代碼能夠實現;
  2. 解決padding問題;
  3. 密鑰作一個混淆,防止編譯生成的庫文件方便的被逆向拿到;

對於tea的加密算法,有成熟的各語言代碼能夠借鑑,下面是C++的實現:git

static void tea_encrypt(uint32_t *v, uint32_t *k) {
    uint32_t v0 = v[0], v1 = v[1], sum = 0, i;
    uint32_t delta = 0x9e3779b9;
    uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];

    for (i = 0; i < tea_round; i++) {
        sum += delta;
        v0 += ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
        v1 += ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
    }

    v[0] = v0;
    v[1] = v1;
}

static void tea_decrypt(uint32_t *v, uint32_t *k) {
    uint32_t v0 = v[0], v1 = v[1], sum, i;
    sum = (tea_round == 16) ? 0xE3779B90 : 0xC6EF3720;

    uint32_t delta = 0x9e3779b9;
    uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];
    for (i = 0; i < tea_round; i++) {
        v1 -= ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
        v0 -= ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
        sum -= delta;
    }

    v[0] = v0;
    v[1] = v1;
}

生成密鑰,並對密鑰作必定的混淆github

static uint32_t tea_key[4] = {
        0x34561234, 0x111f3423, 0x34d57910, 0x00989034
};

static uint32_t salt = 0x12031243;
static int tea_round = 16;

//作簡單的混淆
static void confuse_key(uint32_t *key) {
    for (int i = 4; i > 0; i--) {
        key[4 - i] = tea_key[i - 1] ^ salt;
    }
}

最後要實現加密算法的padding,首先思考一個問題,爲何要padding呢?算法

由於Tea是塊加密算法,8個字節爲一個塊。而在現實的場景中,不會全部的要加密的數據都8的倍數。好比我要加密15,35等字節該怎麼辦?那麼這裏須要涉及到兩個操做:ui

  • 加密的時在不足8個字節的部分進行填充,直至待加密數據爲8的倍數;
  • 加密時將填充的部分去掉;

那麼,填充的數據是必需要有必定規則的,解密的人才知道這部分數據是填充的,而非真實的原始數據。填充部分必須有包含有表示填充長度的字段。目前比較經常使用的是PKCS#7填充法;即:編碼

末尾填充的每一個字節均爲填充長度

好比填充一個字節就是: 0x01加密

填充5個字節就是: 0x05,0x05,0x05,0x05,0x05;rest

還有一個問題:code

  • 若是加密的字段正好爲8的倍數,需不須要padding呢?

答案是也須要的,由於若是沒有padding,解密者可能會把原始數據當作padding來解析(若是此時原始數據的最後幾位剛好與某種padding編碼相同),那麼就解密出錯了。ip

bool encrypt(const void *input, int input_len, DataBuffer &out) {
    if (input == NULL || input_len <= 0)
        return false;

    unsigned int rest_len = input_len % TEA_BLOCK_SIZE;
    //padding是必須帶的,即使是TEA_BLOCK_SIZE的整數倍,也要加panding;
    //若是input_len % TEA_BLOCK_SIZE = 0, 正好是8的倍數,那麼rest_len = 0; padding_len = TEA_BLOCK_SIZE 補8個字節;
    unsigned int padding_len = TEA_BLOCK_SIZE - rest_len;

    int blocks = (input_len + padding_len) / TEA_BLOCK_SIZE;
    out.expand(blocks * TEA_BLOCK_SIZE);
    out.writeBytes((const void *) input, input_len);

    //放入padding
    for (int i = 0; i < padding_len; i++) {
        out.writeInt8(padding_len);
    }

    uint32_t key[4];
    confuse_key(key);

    uint32_t *data = (uint32_t *) out.getData();
    for (int i = 0; i < blocks; i++) {
        tea_encrypt((uint32_t *) (data + 2 * i), key);
    }

    return true;
}

bool decrypt(const void *input, int input_len, DataBuffer &out) {
    if (input == NULL || input_len < 8)
        return false;

    int blocks = input_len / 8;
    out.expand(blocks * 8);
    out.writeBytes((const void *) input, blocks * 8);

    uint32_t key[4];
    confuse_key(key);

    uint32_t *data = (uint32_t *) out.getData();
    for (int i = 0; i < blocks; i++) {
        tea_decrypt((uint32_t *) (data + 2 * i), key);
        if (i == blocks - 1) {
            //最後一個block,一定包含padding,須要把padding拿出來;
            uint8_t padding_len = ((uint8_t *) (data + 2 * i))[TEA_BLOCK_SIZE - 1];
            out.stripData(padding_len);
        }
    }

    return true;
}

完整的代碼已經放到github上。https://github.com/kumustone/...

相關文章
相關標籤/搜索