admin管理员组

文章数量:1391995

I need to work with data which was encrypted using the aes-128-ctr implementation of trezor-crypto in python. However, using pycryptodome in python to encrypt the same data with the same parameters giving me a different result.

C++ code using trezor-crypto library

#include <vector>
#include <iostream>
#include <cassert>
#include "TrezorCrypto/aes.h"

std::vector<uint8_t> iv = HexToBytes("cd26feb0cb51469d06b8134251da1d02");
std::vector<uint8_t> key = HexToBytes("130886bab757196acdd97243cad73d74571c462ed8c8791afbfce94ca6a37a1c");
std::vector<uint8_t> plaintext = HexToBytes("48656c6c6f20576f726c6421"); // = Hello World! in utf-8

aes_encrypt_ctx ctx;
auto result = aes_encrypt_key128(key.data(), &ctx);
assert(result == EXIT_SUCCESS);
std::vector<uint8_t> encrypted(plaintext.size());
result = aes_ctr_encrypt(plaintext.data(), encrypted.data(), plaintext.size(), iv.data(), aes_ctr_cbuf_inc, &ctx)
assert(result == EXIT_SUCCESS);
std::cout << BytesToHex(encrypted.data(), encrypted.size()) << std::endl;
// e61da4e002a75e857a3a2954

I double-checked the HexToBytes/BytesToHex helpers which produce the exact same byte sequence as bytes.fromhex/bytes.hex methods in python!

Python code using PyCryptoDome

from Crypto.Util import Counter
from Crypto.Cipher import AES

iv = bytes.fromhex("cd26feb0cb51469d06b8134251da1d02")
key = bytes.fromhex("130886bab757196acdd97243cad73d74571c462ed8c8791afbfce94ca6a37a1c")
plaintext = bytes.fromhex("48656c6c6f20576f726c6421")

ctr = Counter.new(128, initial_value=int.from_bytes(iv))
aes = AES.new(key, AES.MODE_CTR, counter=ctr)
encrypted = aes.encrypt(plaintext)
print(encrypted.hex())
# c80f8d90f05dc9346f972b62

Both scripts use the exact same data but produce different results (e61da4e002a75e857a3a2954 in c++/trezor-crypto and c80f8d90f05dc9346f972b62 in python/pycryptodome).

My best guess is that the Counter setup in the python code is wrong but I can't find the exact issue.

Is there something wrong with the python code or does trezor-crypto's functions produce wrong results?

I need to work with data which was encrypted using the aes-128-ctr implementation of trezor-crypto in python. However, using pycryptodome in python to encrypt the same data with the same parameters giving me a different result.

C++ code using trezor-crypto library

#include <vector>
#include <iostream>
#include <cassert>
#include "TrezorCrypto/aes.h"

std::vector<uint8_t> iv = HexToBytes("cd26feb0cb51469d06b8134251da1d02");
std::vector<uint8_t> key = HexToBytes("130886bab757196acdd97243cad73d74571c462ed8c8791afbfce94ca6a37a1c");
std::vector<uint8_t> plaintext = HexToBytes("48656c6c6f20576f726c6421"); // = Hello World! in utf-8

aes_encrypt_ctx ctx;
auto result = aes_encrypt_key128(key.data(), &ctx);
assert(result == EXIT_SUCCESS);
std::vector<uint8_t> encrypted(plaintext.size());
result = aes_ctr_encrypt(plaintext.data(), encrypted.data(), plaintext.size(), iv.data(), aes_ctr_cbuf_inc, &ctx)
assert(result == EXIT_SUCCESS);
std::cout << BytesToHex(encrypted.data(), encrypted.size()) << std::endl;
// e61da4e002a75e857a3a2954

I double-checked the HexToBytes/BytesToHex helpers which produce the exact same byte sequence as bytes.fromhex/bytes.hex methods in python!

Python code using PyCryptoDome

from Crypto.Util import Counter
from Crypto.Cipher import AES

iv = bytes.fromhex("cd26feb0cb51469d06b8134251da1d02")
key = bytes.fromhex("130886bab757196acdd97243cad73d74571c462ed8c8791afbfce94ca6a37a1c")
plaintext = bytes.fromhex("48656c6c6f20576f726c6421")

ctr = Counter.new(128, initial_value=int.from_bytes(iv))
aes = AES.new(key, AES.MODE_CTR, counter=ctr)
encrypted = aes.encrypt(plaintext)
print(encrypted.hex())
# c80f8d90f05dc9346f972b62

Both scripts use the exact same data but produce different results (e61da4e002a75e857a3a2954 in c++/trezor-crypto and c80f8d90f05dc9346f972b62 in python/pycryptodome).

My best guess is that the Counter setup in the python code is wrong but I can't find the exact issue.

Is there something wrong with the python code or does trezor-crypto's functions produce wrong results?

Share Improve this question edited Mar 12 at 19:49 DevilsJin asked Mar 12 at 19:12 DevilsJinDevilsJin 1171 silver badge14 bronze badges 1
  • 1 Side note your C++ will not work at all in release builds. NEVER put code into assert statements. – Pepijn Kramer Commented Mar 12 at 19:29
Add a comment  | 

2 Answers 2

Reset to default 1

Page 55 of NIST Special Pub 800-38A lists some test vectors for CTR-AES128.Encrypt. Plug them into both implementations and tell us which implementation deviates from the spec.


F.5 CTR Example Vectors

F.5.1 CTR-AES128.Encrypt

Key            2b7e151628aed2a6abf7158809cf4f3c
Init. Counter  f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff

Block #1
Input Block    f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff
Output Block   ec8cdf7398607cb0f2d21675ea9ea1e4
Plaintext      6bc1bee22e409f96e93d7e117393172a
Ciphertext     874d6191b620e3261bef6864990db6ce

After following the advice of J_H's answer, I realized the key I use is 32-byte (which is aes-256-ctr) instead of 16-byte long. Since the PyCryptoDome aes implementation handles encrypting the key itself, it (correctly) used aes-256-ctr while my c++ implementation was using aes-128-ctr without key length check.

So for my example, the fix is to use aes_encrypt_key (which checks the key length and would chose aes_encrypt_key256 for my key) instead of aes_encrypt_key128 .

#include <vector>
#include <iostream>
#include <cassert>
#include "TrezorCrypto/aes.h"

std::vector<uint8_t> iv = HexToBytes("cd26feb0cb51469d06b8134251da1d02");
std::vector<uint8_t> key = HexToBytes("130886bab757196acdd97243cad73d74571c462ed8c8791afbfce94ca6a37a1c");
std::vector<uint8_t> plaintext = HexToBytes("48656c6c6f20576f726c6421"); // = Hello World! in utf-8

aes_encrypt_ctx ctx;
auto result = aes_encrypt_key(key.data(), key.size(), &ctx); // let trezor-crypto check and chose keylength
assert(result == EXIT_SUCCESS);
std::vector<uint8_t> encrypted(plaintext.size());
result = aes_ctr_encrypt(plaintext.data(), encrypted.data(), plaintext.size(), iv.data(), aes_ctr_cbuf_inc, &ctx)
assert(result == EXIT_SUCCESS);
std::cout << BytesToHex(encrypted.data(), encrypted.size()) << std::endl;
// c80f8d90f05dc9346f972b62

本文标签: cEncryption with AES128CTR using trezorcrypto giving different results in pythonStack Overflow