In CFB mode the size of the shift register must be specified, whereby the different libraries often use different default values. For distinction, the size of the shift register in bits is often appended to the CFB, i.e. CFB8 uses a shift register of 8 bits and CFB128 a shift register of 128 bits.
Cryptography has the two variants CFB8 and CFB128, where the latter is simply called CFB. PyCryptodome allows the setting in integer multiples of 8 bit by using the parameter segment_size
with the default value 8 bit.
So in the current code Cryptography uses CFB128 and PyCryptodome uses CFB8 (its default value), which causes the different results.
The following combinations work:
PyCryptodome with segment_size=128
and Cryptography with CFB. Both correspond to CFB128:
# CFB with a 128 bit shift-register
# Output as hex-string: 63230751cc1efe25b980d9e707396a1a171cd413e6e77f1cd7a2d3deb2217255a36ae9cbf86c66
...
aes = Cipher(algorithms.AES(KEY), modes.CFB(IV), default_backend()).encryptor()
...
ctr = AES.new(KEY, AES.MODE_CFB, iv=IV, segment_size=128)
...
PyCryptodome with segment_size=8
(the default value) and Cryptography with CFB8. Both correspond to CFB8:
# CFB with a 8 bit shift-register
# Output as hex-string: 63d263889ffe94dd4740580067ee798da474c567b8b54319a5022650085c62674628f7c9e790c3
...
aes = Cipher(algorithms.AES(KEY), modes.CFB8(IV), default_backend()).encryptor()
...
ctr = AES.new(KEY, AES.MODE_CFB, iv=IV, segment_size=8)
...
Note, that (1) both Python libraries provide an identical result for the OFB mode, since both use OFB128. (2) CFB128 is faster than CFB8: In CFB8, AES encryption has to be called 16 times for each block vs. 1 time in CFB128.