c++ code tea encryption algorithm example details

  • 2020-08-22 22:22:30
  • OfStack

through c++ To implement the tea Encryption algorithm, which is finally compiled into so file and provided to the client in the way of JNI, mainly needs to solve the following three problems:

tea algorithm, which can be achieved by open source code; Solve the padding problem; The key is obfuscated to prevent the compiled and generated library files from being easily retrieved in reverse;

For the encryption algorithm of tea, there are mature language codes for reference, the following is the implementation of C++ :


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;
}

Generate the key and make a definite obfuscation of the key


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

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

// Do simple confusions 
static void confuse_key(uint32_t *key) {
 for (int i = 4; i > 0; i--) {
 key[4 - i] = tea_key[i - 1] ^ salt;
 }
}

Finally to achieve the encryption algorithm padding First, think about a question: Why padding ?

Because Tea is a block encryption algorithm, 8 bytes make 1 block. In a real world scenario, not all data to be encrypted would be multiples of 8. What if I want to encrypt 15,35, etc.? So there are two operations involved here:

When encrypting, the part less than 8 bytes is filled until the data to be encrypted is a multiple of 8; Remove the populated part when encrypting;

Then, the populated data must have a rule, the decrypted part of the data is known to be populated, rather than the real original data. The fill section must have a field that represents the fill length. At present, the filling method of PKCS#7 is commonly used. That is:

Each byte filled at the end is the fill length

For example, fill in 1 byte is: 0x01

Fill 5 bytes is: 0 x05, 0 x05, 0 x05, 0 x05, 0 x05;

One more question:

If the encrypted field is a multiple of 8, do you need padding?

The answer is also needed, because without padding, the decryptor might interpret the raw data as padding (if the last bits of the raw data happen to be the same as some padding encoding at this point), then the decryption is wrong.


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 You have to, even if you do TEA_BLOCK_SIZE Integer multiples of PI, plus PI panding ; 
 // if input_len % TEA_BLOCK_SIZE = 0 .   Is precisely 8 Multiple of, so rest_len = 0; padding_len = TEA_BLOCK_SIZE  fill 8 Bytes; 
 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);

 // In the 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) {
  // The last 1 a block Must contain padding , you need to padding Take out; 
  uint8_t padding_len = ((uint8_t *) (data + 2 * i))[TEA_BLOCK_SIZE - 1];
  out.stripData(padding_len);
 }
 }

 return true;
}

The complete code is now on github. https: / / github com kumustone /...

conclusion


Related articles: