How to use AES Encryption and Decryption from Scala to Python - python

I have a code in scala where I have my encryption and decryption code, It works fine and the code is:
import java.util.Base64
import javax.crypto.Cipher
import javax.crypto.spec.{IvParameterSpec, SecretKeySpec}
class Encryption {
val key = "enIntVecTest2020"
val initVector = "encryptionIntVec"
def encrypt(text: String): String = {
val iv = new IvParameterSpec(initVector.getBytes("UTF-8"))
val skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES")
val cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING")
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv)
val encrypted = cipher.doFinal(text.getBytes())
return Base64.getEncoder().encodeToString(encrypted)
}
def decrypt(text:String) :String={
val iv = new IvParameterSpec(initVector.getBytes("UTF-8"))
val skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES")
val cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING")
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv)
val original = cipher.doFinal(Base64.getDecoder.decode(text))
new String(original)
}
}
val encryptobj = new Encryption()
val pwd = "#test#12345"
val result =encryptobj.encrypt(pwd)
pwd: String = #test#12345
result: String = lHhq1OzMSYnj+0XxiNzKhQ==
val pwd1 = encryptobj.decrypt(result)
println(pwd1)
pwd1: String = #test#12345
#test#12345
I tried in Python to achieve the same but does not give the expected encryption result, here is my code(I took the help of other similar answers):
from hashlib import sha256
import base64
from Crypto import Random
from Crypto.Cipher import AES
BS = 16
pad = lambda s: bytes(s + (BS - len(s) % BS) * chr(BS - len(s) % BS), 'utf-8')
unpad = lambda s : s[0:-ord(s[-1:])]
class AESCipher:
def __init__( self, key ):
self.key = bytes(key, 'utf-8')
def encrypt( self, raw ):
raw = pad(raw)
iv = "encryptionIntVec".encode('utf-8')
cipher = AES.new(self.key, AES.MODE_CBC, iv )
return base64.b64encode( iv + cipher.encrypt( raw ) )
def decrypt( self, enc ):
enc = base64.b64decode(enc)
iv = enc[:16]
cipher = AES.new(self.key, AES.MODE_CBC, iv )
return unpad(cipher.decrypt( enc[16:] )).decode('utf8')
cipher = AESCipher('enIntVecTest2020')
encrypted = cipher.encrypt('#test#12345')
decrypted = cipher.decrypt(encrypted)
print(encrypted)
b'ZW5jcnlwdGlvbkludFZlY5R4atTszEmJ4/tF8YjcyoU='
As you can see both the encryption is not right, I don't know where I am doing wrong. Please help in achieving the same encrypting result in python as showing in scala, I would be much thankful.

Thanks to #Topaco answer and after some search it worked.
import base64
from Crypto.Cipher import AES
BS = 16
pad = lambda s: bytes(s + (BS - len(s) % BS) * chr(BS - len(s) % BS), 'utf-8')
unpad = lambda s : s[0:-ord(s[-1:])]
class AESCipher:
def __init__( self, key ):
self.key = bytes(key, 'utf-8')
def encrypt( self, raw ):
raw = pad(raw)
iv = "encryptionIntVec".encode('utf-8')
cipher = AES.new(self.key, AES.MODE_CBC, iv )
return base64.b64encode(cipher.encrypt( raw ) )
def decrypt( self, enc ):
iv = "encryptionIntVec".encode('utf-8')
enc = base64.b64decode(enc)
cipher = AES.new(self.key, AES.MODE_CBC, iv )
return unpad(cipher.decrypt( enc )).decode('utf8')
cipher = AESCipher('enIntVecTest2020')
encrypted = cipher.encrypt('#test#12345')
print(encrypted.decode('utf-8'))
-> lHhq1OzMSYnj+0XxiNzKhQ==
decrypted = cipher.decrypt(encrypted)
print(decrypted)
-> #test#12345

Related

How do I URL-encode (to pass in URL) the byte string from AES.encrypt?

How do I url encode a byte string and then decode the encoded byte string from AES?
This is my code:
from Cryptodome.Cipher import AES
from Cryptodome.Util.Padding import pad, unpad
key = "00112233445566778899aabbccddeeff".encode("utf8")
iv = b'\x0cK\x1c\x82\xf1\xa9w\xfe\xa9\x9a\xd0\xb3\x8c\xec1\x1c' # os.urandom(16)
aes = AES.new(key, AES.MODE_CBC, iv)
data = pad(b'HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH', 16) # <- 16 bytes
encd = aes.encrypt(data) # this works, but it's a byte string, not a string
aes = AES.new(key, AES.MODE_CBC, iv)
decd = unpad(aes.decrypt(encd), 16) # this works, it's a string
a = urllib.parse.quote(encd) # this works
b = urllib.parse.unquote(a) # this works
can_not_decrypt = unpad(aes.decrypt( b, 16)) # But this one does not work???
This is what i tried to solve my question, it doesn't work:
a = urllib.parse.quote(encd) # this works
b = urllib.parse.unquote(a) # this works
can_not_decrypt = unpad(aes.decrypt( b, 16)) # But this one does not work???
You are passing 16 as second argument to decrypt, as opposed to unpad.
can_not_decrypt = unpad(aes.decrypt( b, 16))
should be
can_not_decrypt = unpad(aes.decrypt(b), 16)
Working example with urllib.parse:
import urllib.parse
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
key = "00112233445566778899aabbccddeeff".encode("utf8")
iv = b'\x0cK\x1c\x82\xf1\xa9w\xfe\xa9\x9a\xd0\xb3\x8c\xec1\x1c' # os.urandom(16)
aesenc = AES.new(key, AES.MODE_CBC, iv)
data = pad(b'AllworkandnoplaymakesJackadullboyAllworkandnoplaymakesJackadullboyAllworkandnoplay...', 16)
encd = aesenc.encrypt(data) # this works, but it's a byte string, not a string
aesdec = AES.new(key, AES.MODE_CBC, iv)
a = urllib.parse.quote(encd)
print("Urlencoded: {}".format(a))
b = urllib.parse.unquote_to_bytes(a)
decd = unpad(aesdec.decrypt(b), 16)
print("Decoded: {}".format(decd))
Working example with base64 instead of urllib:
import base64
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
key = "00112233445566778899aabbccddeeff".encode("utf8")
iv = b'\x0cK\x1c\x82\xf1\xa9w\xfe\xa9\x9a\xd0\xb3\x8c\xec1\x1c' # os.urandom(16)
aesenc = AES.new(key, AES.MODE_CBC, iv)
data = pad(b'AllworkandnoplaymakesJackadullboyAllworkandnoplaymakesJackadullboyAllworkandnoplay...', 16)
encd = aesenc.encrypt(data) # this works, but it's a byte string, not a string
aesdec = AES.new(key, AES.MODE_CBC, iv)
a = base64.b64encode(encd, b"-_")
print("Base64: {}".format(a.decode('ascii')))
b = base64.b64decode(a, b"-_")
decd = unpad(aesdec.decrypt(b), 16)
print("Decoded: {}".format(decd))

Python AES-256-CBC equivalent from PHP

I found this algorithm that works very well for me to encrypt data between PHP and Flutter, I have looked for its equivalent in Python 3 but it gives me different results, will someone have a reference on how I can pass that function to its equivalent in Python?
function encrypt( $string, $encrypt=true) {
$secret_key = 'SuperSecretKey';
$secret_iv = 'SuperSecretBLOCK';
$output = false;
$encrypt_method = "AES-256-CBC";
$key = hash( 'sha256', $secret_key );
$iv = substr( hash( 'sha256', $secret_iv ), 0, 16 );
if($encrypt) {
$output = base64_encode( openssl_encrypt( $string, $encrypt_method, $key, 0, $iv ) );
} else {
$output = openssl_decrypt( base64_decode( $string ), $encrypt_method, $key, 0, $iv );
}
return $output;
}
I tried this code but it gives me different results
import base64
import hashlib
from Crypto.Cipher import AES
class AESCipher:
def __init__(self, key, iv):
self.key = hashlib.sha256(key.encode('utf-8')).digest()
self.iv = hashlib.sha256(iv.encode('utf-8')).digest()[:16]
__pad = lambda self, s: s + (AES.block_size - len(s) % AES.block_size) * chr(
AES.block_size - len(s) % AES.block_size)
__unpad = lambda self, s: s[0:-ord(s[-1])]
def encrypt(self, raw):
raw = self.__pad(raw)
cipher = AES.new(self.key, AES.MODE_CBC, self.iv)
return base64.b64encode(cipher.encrypt(raw.encode('utf-8')))
def decrypt(self, enc):
enc = base64.b64decode(enc)
cipher = AES.new(self.key, AES.MODE_CBC, self.iv)
return self.__unpad(cipher.decrypt(enc).decode("utf-8"))
cipher = AESCipher('SuperSecretKey', 'SuperSecretBLOCK')
print(cipher.encrypt('hola').decode('utf-8'))

Python to Kotlin AES communication (javax.crypto.BadPaddingException)

I am trying to encrypt a UTF-8 string on Python with AES and decrypt it in Kotlin, here is the Python encrypt part:
class aes():
def __init__(self, key):
self.bs = AES.block_size
self.key = hashlib.sha256(key.encode()).digest()
def encrypt(self, raw):
raw = self.pad(raw)
iv = self.key[:self.bs] # Random.new().read(self.bs)
cipher = AES.new(self.key, AES.MODE_CBC, iv)
return base64.b64encode(iv + cipher.encrypt(raw.encode()))
def pad(self, s):
return s + (self.bs - len(s) % self.bs) * chr(self.bs - len(s) % self.bs)
...
client_key = self.rsa.decrypt(int(connection.recv(bufsize).decode()))
enc = aes(client_key)
em = enc.encrypt("AES_OK")
connection.send(em+b'\0')
And the Kotlin part decrypting it:
object AES256 {
private val decorder = Base64.getDecoder()
private fun cipher(opmode:Int, secretKey:String):Cipher {
val c = Cipher.getInstance("AES/CBC/PKCS7Padding")
val sk = SecretKeySpec(secretKey.toByteArray(Charsets.UTF_8), "AES")
val iv = IvParameterSpec(secretKey.substring(0, 16).toByteArray(Charsets.UTF_8))
c.init(opmode, sk, iv)
return c
}
#RequiresApi(Build.VERSION_CODES.O)
fun decrypt(str:String, secretKey:String):String {
val byteStr = decorder.decode(str.toByteArray(Charsets.UTF_8))
// Error here
return String(cipher(Cipher.DECRYPT_MODE, secretKey).doFinal(byteStr))
}
}
fun readBytes(input: BufferedReader) : String {
var byte: Int = input.read()
var r = ""
while(byte != 0) {
r += byte.toChar()
byte = input.read()
}
return r
}
resposta = readBytes(input)
resposta = AES256.decrypt(resposta, atc_aesk.toString(Charsets.UTF_8))
And I get the following exception:
javax.crypto.BadPaddingException: error:1e000065:Cipher functions:OPENSSL_internal:BAD_DECRYPT
All the RSA and connection code works properly, the ciphertext and key are the same on both sides.
I'm using a 32 bytes key, I also tried a 16 bytes one, same error.
I would greatly appreciate any help or input, thanks.
The user President James K. Polk answered this in a comment, the mistake was that I hashed the key only in the Python code and not in Kotlin... self.key = hashlib.sha256(key.encode()).digest()
I tried finding the problem like a whole week, I really feel so dumb, thank you President James K. Polk.
I had exactly the same use case and seemed to have copied the same code from some places online. Still took me a second. Here is a working pair:
class AESCipher(object):
def __init__(self, key):
self.bs = AES.block_size
self.key = hashlib.sha256(key.encode()).digest()
def encrypt(self, raw):
raw = self._pad(raw)
iv = Random.new().read(AES.block_size)
cipher = AES.new(self.key, AES.MODE_CBC, iv)
return base64.b64encode(iv + cipher.encrypt(raw.encode())).decode('utf-8')
def _pad(self, s):
return s + (self.bs - len(s) % self.bs) * chr(self.bs - len(s) % self.bs)
class AESCipher(private val key: String) {
private fun createCipher(mode: Int, ivBytes: ByteArray): Cipher {
val c = Cipher.getInstance("AES/CBC/PKCS7Padding")
val sk = SecretKeySpec(key.getSha256(), "AES")
val iv = IvParameterSpec(ivBytes)
c.init(Cipher.DECRYPT_MODE, sk, iv)
return c
}
fun decrypt(data: String): ByteArray {
val bytes = Base64.decode(data, Base64.DEFAULT)
val ivBytes = bytes.take(16).toByteArray()
val rawDataBytes = bytes.drop(16).toByteArray()
val cipher = createCipher(Cipher.DECRYPT_MODE, ivBytes)
return cipher.doFinal(rawDataBytes)
}
private fun String.getSha256(): ByteArray {
val digest = MessageDigest.getInstance("SHA-256").also { it.reset() }
return digest.digest(this.toByteArray())
}
}
If you pass the same key string to them, they will work together. Notice that the data exposed and consumed is already a Base64 string.

AES-CBC 128, 192 and 256 encryption decryption in Python 3 using PKCS#7 padding

I have searched a lot on SO about complete encryption decryption example with my requirement. In fact, I've got many links and examples but None is working for me for AES-192-CBC mode and AES-256-CBC.
I have got following example which is supposed to be working with all types but it is working only with AES-128-CBC mode. I am new to Python. Can anyone help me where I am wrong?
I am using Python 3.4 on windows and I can not move to Python 2.7.
import base64
from Crypto.Cipher import AES
class AESCipher:
class InvalidBlockSizeError(Exception):
"""Raised for invalid block sizes"""
pass
def __init__(self, key, block_size=16):
if block_size < 2 or block_size > 255:
raise AESCipher.InvalidBlockSizeError('The block size must be between 2 and 255, inclusive')
self.block_size = block_size
self.key = key
self.iv = bytes(key[0:16], 'utf-8')
print(self.key)
print(key[0:16])
def __pad(self, text):
text_length = len(text)
amount_to_pad = self.block_size - (text_length % self.block_size)
if amount_to_pad == 0:
amount_to_pad = self.block_size
self.pad = chr(amount_to_pad)
return text + self.pad * amount_to_pad
def __unpad(self, text):
#pad = ord(text[-1])
#return text[:-pad]
text = text.rstrip(self.pad)
return text
def encrypt( self, raw ):
raw = self.__pad(raw)
cipher = AES.new(self.key, AES.MODE_CBC, self.iv)
return base64.b64encode(cipher.encrypt(raw))
def decrypt( self, enc ):
enc = base64.b64decode(enc)
cipher = AES.new(self.key, AES.MODE_CBC, self.iv )
return self.__unpad(cipher.decrypt(enc).decode("utf-8"))
e = AESCipher('1234567812345678', 16)
#e = AESCipher('123456781234567812345678', 24)
#e = AESCipher('12345678123456781234567812345678', 32)
secret_data = "hi"
enc_str = e.encrypt(secret_data)
print('enc_str: ' + enc_str.decode())
dec_str = e.decrypt(enc_str)
print('dec str: ' + dec_str)
Though this code encrypts the data with 192 and 256 bit encryption and successfully decrypt that too but my other .Net and Ruby application only able to decrypt the data which was encrypted using 128 encryption.
Note .Net and Ruby application are successfully tested with each other and with online encryption tool with all encryption types.
Note that my application requires AES-CBC mode and PKCS#7 padding and must be run on Python 3.4.
Made it working by padding of 16 bytes for any encryption types. For that I used AES.block_size which is 16 by default for AES.
import base64
from Crypto.Cipher import AES
class AESCipher:
class InvalidBlockSizeError(Exception):
"""Raised for invalid block sizes"""
pass
def __init__(self, key):
self.key = key
self.iv = bytes(key[0:16], 'utf-8')
print(self.key)
print(key[0:16])
def __pad(self, text):
text_length = len(text)
amount_to_pad = AES.block_size - (text_length % AES.block_size)
if amount_to_pad == 0:
amount_to_pad = AES.block_size
pad = chr(amount_to_pad)
return text + pad * amount_to_pad
def __unpad(self, text):
pad = ord(text[-1])
return text[:-pad]
def encrypt( self, raw ):
raw = self.__pad(raw)
cipher = AES.new(self.key, AES.MODE_CBC, self.iv)
return base64.b64encode(cipher.encrypt(raw))
def decrypt( self, enc ):
enc = base64.b64decode(enc)
cipher = AES.new(self.key, AES.MODE_CBC, self.iv )
return self.__unpad(cipher.decrypt(enc).decode("utf-8"))
e = AESCipher('1234567812345678', 16)
#e = AESCipher('123456781234567812345678', 24)
#e = AESCipher('12345678123456781234567812345678', 32)
secret_data = "hi"
enc_str = e.encrypt(secret_data)
print('enc_str: ' + enc_str.decode())
dec_str = e.decrypt(enc_str)
print('dec str: ' + dec_str)

Problem with M2Crypto's AES

Can someone please point out mistakes in this code:
__author__="gaurav"
__date__ ="$15 Feb, 2011 5:10:59 PM$"
import M2Crypto
from base64 import b64encode, b64decode
ENC=1
DEC=0
def AES_build_cipher(key, iv, op=ENC):
""""""""
return M2Crypto.EVP.Cipher(alg='aes_128_cbc', key=key, iv=iv, op=op)
def AES_encryptor(key,msg, iv=None):
""""""
#Decode the key and iv
key = b64decode(key)
if iv is None:
iv = '\0' * 16
else:
iv = b64decode(iv)
# Return the encryption function
def encrypt(data):
cipher = AES_build_cipher(key, iv, ENC)
v = cipher.update(data)
v = v + cipher.final()
del cipher
v = b64encode(v)
return v
print "AES encryption successful\n"
return encrypt(msg)
def AES_decryptor(key,msg, iv=None):
""""""
#Decode the key and iv
key = b64decode(key)
if iv is None:
iv = '\0' * 16
else:
iv = b64decode(iv)
# Return the decryption function
def decrypt(data):
data = b64decode(data)
cipher = AES_build_cipher(key, iv, DEC)
v = cipher.update(data)
v = v + cipher.final()
del cipher
return v
print "AES dencryption successful\n"
return decrypt(msg)
if __name__ == "__main__":
msg=AES_encryptor(b64encode("123452345"),msg=b64encode("qwrtttrtyutyyyyy"))
print AES_decryptor(b64encode("123452345"),msg=msg)
Error:
AES encryption successful
AES dencryption successful
Traceback (most recent call last):
File "/home/gaurav/NetBeansProjects/temp/src/temp.py", line 54, in <module>
print AES_decryptor(b64encode("123452345"),msg)
File "/home/gaurav/NetBeansProjects/temp/src/temp.py", line 51, in AES_decryptor
return decrypt(iv)
File "/home/gaurav/NetBeansProjects/temp/src/temp.py", line 47, in decrypt
v = v + cipher.final()
File "/usr/local/lib/python2.6/dist-packages/M2Crypto-0.21.1-py2.6-linux-i686.egg/M2Crypto/EVP.py", line 128, in final
return m2.cipher_final(self.ctx)
M2Crypto.EVP.EVPError: wrong final block length
After correcting the indentation and a small change in __main__, your code seems to work with Python 2.7.3 and M2Crypto-0.21.1:
__author__="gaurav"
__date__ ="$15 Feb, 2011 5:10:59 PM$"
import M2Crypto
from base64 import b64encode, b64decode
ENC=1
DEC=0
def AES_build_cipher(key, iv, op=ENC):
""""""""
return M2Crypto.EVP.Cipher(alg='aes_128_cbc', key=key, iv=iv, op=op)
def AES_encryptor(key,msg, iv=None):
""""""
#Decode the key and iv
key = b64decode(key)
if iv is None:
iv = '\0' * 16
else:
iv = b64decode(iv)
# Return the encryption function
def encrypt(data):
cipher = AES_build_cipher(key, iv, ENC)
v = cipher.update(data)
v = v + cipher.final()
del cipher
v = b64encode(v)
return v
print "AES encryption successful\n"
return encrypt(msg)
def AES_decryptor(key,msg, iv=None):
""""""
#Decode the key and iv
key = b64decode(key)
if iv is None:
iv = '\0' * 16
else:
iv = b64decode(iv)
# Return the decryption function
def decrypt(data):
data = b64decode(data)
cipher = AES_build_cipher(key, iv, DEC)
v = cipher.update(data)
v = v + cipher.final()
del cipher
return v
print "AES decryption successful\n"
return decrypt(msg)
if __name__ == "__main__":
key="123452345"
msg="qwrtttrtyutyyyyy"
encrypted_msg=AES_encryptor(b64encode(key),b64encode(msg))
print b64decode(AES_decryptor(b64encode(key),encrypted_msg))

Categories

Resources