Arthur

Pemberton

Full-stack web applications developer


Replicating Chilkat AES Cryptography with PyCrypto

November 22, 2016Arthur Pemberton0 Comments

Today, I had the need to replicate an encrypted query string token to inter-operate with a third-party commercial application. I was able to determine the library, symmetrical algorithm and secret key being used to create the token. Turns out, it was an ASP.net web application using the Chilkat .NET library to do the encryption and decryption. Specifically, it was the Chilkat AES (aka Rijndael) methods being used.

It took me awhile to properly replicate. Luckily, the Chilkat team had made a blog post on inter-library compatibility: https://www.chilkatsoft.com/p/p_123.asp.

From that, I was able to work out the appropriate settings, and put together these wrapper methods.

# PyCrypto import
from Crypto.Cipher import AES


def chilkat_aes_encrypt(key, bytes, hex=False, iv=None, mode=None):
	"""
	Method to emulate the default settings of Chilkat AES decryption using PyCrypto.
	
	See: https://www.chilkatsoft.com/p/p_123.asp
	"""
	
	if len(key) < 16:
		key += '\0' * ( 16 - len(key) )
		pass
	if iv is None:
		iv = chr(0) * 16
		pass
	if mode is None:
		mode = AES.MODE_CBC
		pass
	
	remainder = len(bytes) / 16
	if remainder > 0:
		pad_len = ((( len(bytes) // 16 ) + 1) * 16) - len(bytes)
		bytes += chr(pad_len) * pad_len
		pass
	
	cipher = AES.new(key, mode, iv)
		
	crypt = cipher.encrypt(bytes)
	
	if hex:
		crypt = binascii.hexlify(crypt).upper()
		pass
	
	return crypt

def chilkat_aes_decrypt(key, bytes, hex=False, iv=None, mode=None):
	"""
	Method to emulate the default settings of Chilkat AES decryption using PyCrypto.
	
	See: https://www.chilkatsoft.com/p/p_123.asp
	"""
	
	if hex:
		bytes = binascii.unhexlify(bytes)
		pass
	
	if len(key) < 16:
		key += '\0' * ( 16 - len(key) )
		pass
	if iv is None:
		iv = chr(0) * 16
		pass
	if mode is None:
		mode = AES.MODE_CBC
		pass
		
	cipher = AES.new(key, mode, iv)
	
	plain = cipher.decrypt(bytes)
	
	last = ord( plain[-1] )
	if last < 16 and len(plain) > last:
		indexed = ord( plain[ -1 * last ] )
		
		if last == indexed:
			plain = plain[: -1 * last]
			pass
		pass
	
	return plain

Leave a Reply