-1

so i want to encrypt file .txt with keyword i was input. but i got error message

Object type <class 'tuple'> cannot be passed to C code

my problem is with this code:

aes = AES.new(key.encode('utf8'), AES.MODE_CTR, counter=ctr)

if i add encode to ctr, then i got error message 'dict' object has no attribute 'encode'

if i remove don't add any encode to key and ctr, then i got error message Object type <class 'str'> cannot be passed to C code

can someone please help me to fix it? i was using django to encrypt with AES 128 with method CTR. or maybe someone can give me example aes encryption with another method but can be run in django. here's my full function code:

# AES supports multiple key sizes: 16 (AES128), 24 (AES192), or 32 (AES256).
key_bytes = 16
# Takes as input a 32-byte key and an arbitrary-length plaintext and returns a
# pair (iv, ciphtertext). "iv" stands for initialization vector.
def encrypt(key, testpass):
    assert len(key) == key_bytes
    print(testpass)
    print(key)
    # Choose a random, 16-byte IV.
    iv = Random.new().read(AES.block_size)

    # Convert the IV to a Python integer.
    iv_int = int(binascii.hexlify(iv), 16)

    # Create a new Counter object with IV = iv_int.
    ctr = Counter.new(AES.block_size * 8, initial_value=iv_int)
    print(ctr)

    # Create AES-CTR cipher.
    aes = AES.new(key.encode('utf8'), AES.MODE_CTR, counter=ctr)

    # Encrypt and return IV and ciphertext.
    ciphertext = aes.encrypt(testpass)
    print(iv)
    print(ciphertext)
    return (iv, ciphertext)

here's how i called that function:

testpass = Audio_store.objects.all().values_list('password').last()
enkripsi = encrypt("testingtesting11", testpass)

when i print testpass, it contains ('testpass_3kEMV2T.txt',)

but when i print testpass.encode("utf-8"), it shows nothing

  • 1
    Does this answer your question? [Object type cannot be passed to C code - virtual environment](https://stackoverflow.com/questions/50302827/object-type-class-str-cannot-be-passed-to-c-code-virtual-environment) – Sunderam Dubey Aug 23 '22 at 18:07
  • nope, because my ctr is directory not string. so i cannot use encode to ctr @SunderamDubey – HelpMePlease Aug 23 '22 at 18:13
  • The code works on my machine. Maybe you pass the parameters wrong, the key must be passed as string, the plaintext as bytes like object. Post the encrypt() call you used with test data. – Topaco Aug 23 '22 at 18:20
  • i was update it @Topaco – HelpMePlease Aug 23 '22 at 18:25
  • How is `password` stored and retrieved from your database, as text? – wkl Aug 23 '22 at 18:27
  • actually i will get it from html and use it to django. but i was try the code with make variable contains string, like the example key="testingtesting11" the file what will be encrypt, i got it from database using models @wkl – HelpMePlease Aug 23 '22 at 18:31
  • In that case, you're probably just passing in your plaintext as `str` and not `bytes`, you need to encode it either before passing it to your `encrypt` method or do it inside. – wkl Aug 23 '22 at 18:32
  • how to make testpass to bytes? i was try ciphertext = aes.encrypt(testpass.encode("utf-8")) but i got error 'tuple' object has no attribute 'encode' @wkl when i print testpass, there's like this ('testpass_3kEMV2T.txt',) i was update my post – HelpMePlease Aug 23 '22 at 18:33
  • `testpass` is currently something retrieved from (I assume) the django ORM, so what does it look like? Print it out and put it into your post. – wkl Aug 23 '22 at 18:34

1 Answers1

0

Your test data is ('testpass_3kEMV2T.txt',), you need to pull out the element from the tuple and pass it in as bytes to your encrypt method, because the AES.encrypt method requires bytes | bytearray | memoryview as its argument. Here's a version of your encrypt that determines if the argument you pass it is a str and encodes it to bytes if so (but it doesn't check if it's otherwise bytes, I leave that as an exercise for you if you want more stringent checking).

import binascii


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

key_bytes = 16

# here's a rudimentary change that accepts bytes or
# str
def encrypt(key, plaintext):
    if isinstance(plaintext, str):
        plaintext = plaintext.encode("utf-8")

    assert len(key) == key_bytes
    # Choose a random, 16-byte IV.
    iv = Random.new().read(AES.block_size)

    # Convert the IV to a Python integer.
    iv_int = int(binascii.hexlify(iv), 16)

    # Create a new Counter object with IV = iv_int.
    ctr = Counter.new(AES.block_size * 8, initial_value=iv_int)
    print(ctr)

    # Create AES-CTR cipher.
    aes = AES.new(key.encode('utf8'), AES.MODE_CTR, counter=ctr)

    # Encrypt and return IV and ciphertext.
    ciphertext = aes.encrypt(plaintext)
    return (iv, ciphertext)

# for now, since you're getting your data from the db which is a 1-tuple, you have to pull out the first elem
testpass = ('testpass_3kEMV2T.txt',)
print(encrypt("a"*16, testpass[0]))

Output:

{'counter_len': 16, 'prefix': b'', 'suffix': b'', 'initial_value': 302861312392273214314458272471454024973, 'little_endian': False}
(b'\xe3\xd8\xf7\x90\xcd\x96m\xcb\xa5g)\xd1\xda\xc3\x85\r', b'-F)\x83\x9a\xf9\xe1\xc3\xfb\xfa_<^\x1c:q\x07\xa1@\xbb')
wkl
  • 77,184
  • 16
  • 165
  • 176
  • why my "Union" is not definedPylance?? – HelpMePlease Aug 23 '22 at 18:53
  • @HelpMePlease whoops, sorry - you need to do `from typing import Union` (just updated my answer). If you're using Python 3.10, you can write `plaintext: Union[bytes|str]` as `plaintext: bytes | str`. – wkl Aug 23 '22 at 18:55
  • the union not error again. but isn't plaintext = plaintext.encode("utf-8") change to testpass = plaintext.encode("utf-8") ? – HelpMePlease Aug 23 '22 at 19:00
  • @HelpMePlease okay, sorry, problems of cut-paste and stuff. Just updated the entire code block and tested it again to make sure it works. I also took out the typehinting since they're optional and was just there to demonstrate. But if you're curious about them, [look at `typing`](https://docs.python.org/3/library/typing.html) for what I was trying to do. – wkl Aug 23 '22 at 19:03
  • if isinstance(plaintext, str): not works on me. the plaintext still ('testpass_3kEMV2T.txt',) – HelpMePlease Aug 23 '22 at 19:08
  • @HelpMePlease, did you see the part of my code where I define `testpass = ('testpass_3kEMV2T.txt',)` (which is what your data looks like) and then do `print(encrypt("a"*16, testpass[0]))`? You have to pull out the first element of the `tuple` you get back from the ORM, can't pass in `testpass` directly. – wkl Aug 23 '22 at 19:10
  • ah i see, now i understand what you mean! if i got the result from ciptertext (b'\x93|H\x84\x8ev?\xf7T\x12\x18\xe3\x9aU\xc3\xff', b'\x80\xe2NI\xc3\xe2\x90\xbb\xf3\x91Ur\xc9\x9eR\xd0 K\xd1\xf0DD'), it's mean the file was encrypt right? – HelpMePlease Aug 23 '22 at 19:22
  • @HelpMePlease yes, the code just does what you originally did and returns a tuple of `(iv, cipher)` so the second element in the return is the encrypted data. – wkl Aug 23 '22 at 19:26
  • thank you so much! btw, where's the file was encrypt? is it in the database? – HelpMePlease Aug 23 '22 at 19:28
  • @HelpMePlease right now you don’t do anything with the returned ciphertext. You’d have to write the code to save it (first you should use `binascii.hexlify` to convert the ciphertext from bytes to hex if you’re going to be saving the encrypted data to a database). – wkl Aug 23 '22 at 19:49