title: How to Solve "AES key must be either 16, 24, or 32 bytes long"
body: <p>I am trying to make a College project where i am trying implement a payment gateway to my website. The payment gateway I am using is Paytm (India).
  They have already provided me with the checksum.py file.
  But when i try to pass merchant ID and order id, I end up with the error.</p>
  
  <p>Here's the traceback:-</p>
  
  <pre><code>Environment:
  
  
  Request Method: POST
  Request URL: http://127.0.0.1:8000/orders/create/
  
  Django Version: 2.2
  Python Version: 3.7.3
  Installed Applications:
  ['django.contrib.admin',
   'django.contrib.auth',
   'crispy_forms',
   'social_django',
   'cart.apps.CartConfig',
   'payment.apps.PaymentConfig',
   'orders.apps.OrdersConfig',
   'django.contrib.contenttypes',
   'django.contrib.sessions',
   'django.contrib.messages',
   'django.contrib.staticfiles',
   'products',
   'drf_paytm',
   'drfaddons',
   'feedback.apps.FeedbackConfig',
   'users.apps.UsersConfig',
   'shop.apps.ShopConfig']
  Installed Middleware:
  ['django.middleware.security.SecurityMiddleware',
   'django.contrib.sessions.middleware.SessionMiddleware',
   'django.middleware.common.CommonMiddleware',
   'django.middleware.csrf.CsrfViewMiddleware',
   'django.contrib.auth.middleware.AuthenticationMiddleware',
   'django.contrib.messages.middleware.MessageMiddleware',
   'django.middleware.clickjacking.XFrameOptionsMiddleware',
   'social_django.middleware.SocialAuthExceptionMiddleware']
  
  
  
  Traceback:
  
  File "/Users/shyambalakrishnan/Dev/trydjango/lib/python3.7/site-packages/django/core/handlers/exception.py" in inner
    34.             response = get_response(request)
  
  File "/Users/shyambalakrishnan/Dev/trydjango/lib/python3.7/site-packages/django/core/handlers/base.py" in _get_response
    115.                 response = self.process_exception_by_middleware(e, request)
  
  File "/Users/shyambalakrishnan/Dev/trydjango/lib/python3.7/site-packages/django/core/handlers/base.py" in _get_response
    113.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)
  
  File "/Users/shyambalakrishnan/Dev/trydjango/lib/python3.7/site-packages/django/contrib/auth/decorators.py" in _wrapped_view
    21.                 return view_func(request, *args, **kwargs)
  
  File "/Users/shyambalakrishnan/Dev/trydjango/src/orders/views.py" in order_create
    40.             param_dict['CHECKSUMHASH'] = Checksum.generate_checksum_by_str(param_dict, MERCHANT_KEY)
  
  File "/Users/shyambalakrishnan/Dev/trydjango/src/payTm/Checksum.py" in generate_checksum_by_str
    52.     return __encode__(hash_string, IV, merchant_key)
  
  File "/Users/shyambalakrishnan/Dev/trydjango/src/payTm/Checksum.py" in __encode__
    102.     c = AES.new(key.encode('utf-8'), AES.MODE_CBC, iv.encode('utf-8'))
  
  File "/Users/shyambalakrishnan/Dev/trydjango/lib/python3.7/site-packages/Crypto/Cipher/AES.py" in new
    95.     return AESCipher(key, *args, **kwargs)
  
  File "/Users/shyambalakrishnan/Dev/trydjango/lib/python3.7/site-packages/Crypto/Cipher/AES.py" in __init__
    59.         blockalgo.BlockAlgo.__init__(self, _AES, key, *args, **kwargs)
  
  File "/Users/shyambalakrishnan/Dev/trydjango/lib/python3.7/site-packages/Crypto/Cipher/blockalgo.py" in __init__
    141.             self._cipher = factory.new(key, *args, **kwargs)
  
  Exception Type: ValueError at /orders/create/
  Exception Value: AES key must be either 16, 24, or 32 bytes long.
  </code></pre>
  
  <p>Here's my checksum.py file:</p>
  
  <pre><code>import base64
  import string
  import random
  import hashlib
  
  from Crypto.Cipher import AES
  
  
  IV = "@@@@&amp;&amp;&amp;&amp;####$$$$"
  BLOCK_SIZE = 16
  
  
  def generate_checksum(param_dict, merchant_key, salt=None):
      params_string = __get_param_string__(param_dict)
      salt = salt if salt else __id_generator__(4)
      final_string = '%s|%s' % (params_string, salt)
  
      hasher = hashlib.sha256(final_string.encode())
      hash_string = hasher.hexdigest()
  
      hash_string += salt
  
      return __encode__(hash_string, IV, merchant_key)
  
  def generate_refund_checksum(param_dict, merchant_key, salt=None):
      for i in param_dict:
          if("|" in param_dict[i]):
              param_dict = {}
              exit()
      params_string = __get_param_string__(param_dict)
      salt = salt if salt else __id_generator__(4)
      final_string = '%s|%s' % (params_string, salt)
  
      hasher = hashlib.sha256(final_string.encode())
      hash_string = hasher.hexdigest()
  
      hash_string += salt
  
      return __encode__(hash_string, IV, merchant_key)
  
  
  def generate_checksum_by_str(param_str, merchant_key, salt=None):
      params_string = param_str
      salt = salt if salt else __id_generator__(4)
      final_string = '%s|%s' % (params_string, salt)
  
      hasher = hashlib.sha256(final_string.encode())
      hash_string = hasher.hexdigest()
  
      hash_string += salt
  
      return __encode__(hash_string, IV, merchant_key)
  
  
  def verify_checksum(param_dict, merchant_key, checksum):
      # Remove checksum
      if 'CHECKSUMHASH' in param_dict:
          param_dict.pop('CHECKSUMHASH')
  
      # Get salt
      paytm_hash = __decode__(checksum, IV, merchant_key)
      salt = paytm_hash[-4:]
      calculated_checksum = generate_checksum(param_dict, merchant_key, salt=salt)
      return calculated_checksum == checksum
  
  def verify_checksum_by_str(param_str, merchant_key, checksum):
      # Remove checksum
      #if 'CHECKSUMHASH' in param_dict:
          #param_dict.pop('CHECKSUMHASH')
  
      # Get salt
      paytm_hash = __decode__(checksum, IV, merchant_key)
      salt = paytm_hash[-4:]
      calculated_checksum = generate_checksum_by_str(param_str, merchant_key, salt=salt)
      return calculated_checksum == checksum
  
  
  
  def __id_generator__(size=6, chars=string.ascii_uppercase + string.digits + string.ascii_lowercase):
      return ''.join(random.choice(chars) for _ in range(size))
  
  
  def __get_param_string__(params):
      params_string = []
      for key in sorted(params.keys()):
          if("REFUND" in params[key] or "|" in params[key]):
              respons_dict = {}
              exit()
          value = params[key]
          params_string.append('' if value == 'null' else str(value))
      return '|'.join(params_string)
  
  
  __pad__ = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * chr(BLOCK_SIZE - len(s) % BLOCK_SIZE)
  __unpad__ = lambda s: s[0:-ord(s[-1])]
  
  
  def __encode__(to_encode, iv, key):
      # Pad
      to_encode = __pad__(to_encode)
      # Encrypt
      c = AES.new(key.encode('utf-8'), AES.MODE_CBC, iv.encode('utf-8'))
      to_encode = c.encrypt(to_encode.encode('utf-8'))
      # Encode
      to_encode = base64.b64encode(to_encode)
      return to_encode.decode("UTF-8")
  
  
  def __decode__(to_decode, iv, key):
      # Decode
      to_decode = base64.b64decode(to_decode)
      # Decrypt
      c = AES.new(key.encode('utf-8'), AES.MODE_CBC, iv.encode('utf-8'))
      to_decode = c.decrypt(to_decode)
      if type(to_decode) == bytes:
          # convert bytes array to str.
          to_decode = to_decode.decode()
      # remove pad
      return __unpad__(to_decode)
  
  
  if __name__ == "__main__":
      params = {
          "MID": "mid",
          "ORDER_ID": "order_id",
          "CUST_ID": "cust_id",
          "TXN_AMOUNT": "1",
          "CHANNEL_ID": "WEB",
          "INDUSTRY_TYPE_ID": "Retail",
          "WEBSITE": "xxxxxxxxxxx"
      }
  
      print(verify_checksum(
          params, 'xxxxxxxxxxxxxxxx',
          "CD5ndX8VVjlzjWbbYoAtKQIlvtXPypQYOg0Fi2AUYKXZA5XSHiRF0FDj7vQu66S8MHx9NaDZ/uYm3WBOWHf+sDQAmTyxqUipA7i1nILlxrk="))
  
      print(generate_checksum(params, "xxxxxxxxxxxxxxxx"))
  </code></pre>
  
  <p>These are my current Version available:
  pycrypto==2.6.1
  pycryptodome==3.8.1</p>
  
  <p>My order/views.py:</p>
  
  <pre><code>from django.shortcuts import render
  from .models import OrderItem , Order
  from django.contrib.auth.decorators import login_required
  from django.http import HttpResponse
  from payTm import Checksum
  from django.views.decorators.csrf import csrf_exempt
  from .forms import OrderCreateForm
  from cart.cart import Cart
  MERCHANT_KEY = 'my_merchant_key'
  
  
  
  @login_required
  def order_create(request):
      cart = Cart(request)
      if request.method == 'POST':
          form = OrderCreateForm(request.POST)
          if form.is_valid():
              order = form.save()
              for item in cart:
                  OrderItem.objects.create(
                      order=order,
                      product=item['product'],
                      price=item['price'],
                      quantity=item['quantity'],
                      total_price=item['total_price'],
                  )
              cart.clear()
              param_dict = {
                  'MID': 'my_merchant_id',
                  'ORDER_ID': str(order.id),
                  'TXN_AMOUNT': str(order.total_cost),
                  'CUST_ID': order.email,
                  'INDUSTRY_TYPE_ID': 'Retail',
                  'WEBSITE': 'WEBSTAGING',
                  'CHANNEL_ID': 'WEB',
                  'CALLBACK_URL': 'http://127.0.0.1:8000/handlerequest/',
              }
              param_dict['CHECKSUMHASH'] = Checksum.generate_checksum(param_dict, MERCHANT_KEY)
          return render(request, 'paytm.html', {'order': order, 'param_dict': param_dict})
  
      else:
          form = OrderCreateForm()
          return render(request, 'create.html', {'form': form})
  
  @csrf_exempt
  def handlerequest(request,*args,**kwargs):
  
      return HttpRespone("Done")
  </code></pre>
  
  <p>How can i Solve this error? Or is their Checksum.py file buggy?</p>