I'm trying to encrypt a message using AES-256-CBC but I get different behavior in Ruby and Python versions. It seems like Python's AES encryption does not add a suffix.
require 'base64'
require 'aescrypt'
key = "z\r}\xE6\xB5\xB0P:\x80D#+\x96S\xAB (\x87\xDD#3x\xB9\xF3\xB4\xE7*qTKz\xC1"
iv = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
data = "\xC7u\xE7\xB7W\xED\xE60\xCD\n\xA1\x11;\xD1\x02f\x1A\xB3\x88)\xCAR\xA6B*\xB7\x82\x86/&\x86F"
Base64.encode64(AESCrypt.encrypt_data(data, key, iv, "AES-256-CBC"))
=> "ldB7M0nr+FP6I9NiogtvysUFfUC2vIt6Hj7cwzEiUEal76Cpyc+x6RTiHgkq\n6j7n\n"
Whereas in Python using cryptography:
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
import base64
backend = default_backend()
key = "z\r}\xE6\xB5\xB0P:\x80D#+\x96S\xAB (\x87\xDD#3x\xB9\xF3\xB4\xE7*qTKz\xC1"
iv = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
data = "\xC7u\xE7\xB7W\xED\xE60\xCD\n\xA1\x11;\xD1\x02f\x1A\xB3\x88)\xCAR\xA6B*\xB7\x82\x86/&\x86F"
cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=backend)
encryptor = cipher.encryptor()
ct = encryptor.update(data) + encryptor.finalize()
base64.b64encode(ct)
=> 'ldB7M0nr+FP6I9NiogtvysUFfUC2vIt6Hj7cwzEiUEY='
You can see the encrypted text produced by Ruby library has extra 16 bytes. I have Java code as well which produces exact same ciphertext as Ruby version. Python code is behaving oddly. How can I change the Python code so that it produces the same ciphertext?
A friend pointed out the problem: the encrypt method requires padded data:
from Crypto.Util.Padding import pad
ct = encryptor.update(pad(data,16)) + encryptor.finalize()
Related
I'm doing encryption with my program, but I'm worried about exposing an initial layout in the plaintext.
As you can see, I intend to encrypt sha256 of the plain text plus the plain text, all together, I will use the sha256 to calculate integrity and check if the content was not changed.
encrypt: sha256 of plaintext + plaintext, padding
And as you can see, I'm concerned that an attacker might know that the first few bytes are a pattern of letters and numbers that are part of a sha256 of the original message.
In this case, the IV is not secret, and the attacker could have the IV and the Encryption.
My question is if my method of use is safe or an attacker could get lucky.
An example:
#need: pip install pycryptodome
from Crypto.Cipher import AES;
from Crypto.Util.Padding import pad;
from Crypto.Random import get_random_bytes;
from hashlib import sha256;
textPlain = input("Enter text plain: ").encode(); #(secret)
shaMsg = sha256(textPlain).hexdigest();
password = pad(b"APasswordExample", 16, "iso7816"); #(secret)
iv = get_random_bytes(16); #(no secret)
secretBytes = shaMsg.encode()+textPlain;
secretBytes = pad(secretBytes, 16, "iso7816");
cip = AES.new(password, AES.MODE_CBC, iv);
encrypted = cip.encrypt(secretBytes);
So I would like you to give me your opinion about my encryption
Thanks :D
I have a project written in python. I use cryptography library to encrypt and decrypt data.
I do it how is shown in their tutorial.
Here is my python code:
import base64
import os
from cryptography.fernet import Fernet
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
password = b"my password"
salt = os.urandom(16)
kdf = PBKDF2HMAC(algorithm=hashes.SHA256(),
length=32,
salt=salt,
iterations=100000,
backend=default_backend())
key = base64.urlsafe_b64encode(kdf.derive(password))
f = Fernet(key)
data = b"my data..."
token = f.encrypt(data)
Then for decryption I can just use:
f.decrypt(token)
Everything works perfectly in python but now I need to do the same thing in kotlin. I found out about fernet java-8 library but I don't know how to use it in the same way.
The problem is that I have two tools: one is written in python and another I want to write in kotlin. Both tools are meant to do the same thing - the python one is for desktop and the kotlin one is gonna be an android app. So it is really important for their encryption to be the same, so that files encrypted in python (desktop tool) can be decrypted in kotlin (android app) and vice versa.
But I don't know how to write analogous kotlin code.
You see there is a function (or class) called PBKDF2HMAC and there is also base64.urlsafe_b64encode and others. And I don't know what are analogous functions in kotlin or fernet java-8.
So how should I do it? Assuming that in kotlin I have to use password and salt I used in python.
Thanks!
In Java/Kotlin, using fernet-java8, the token generated with the Python code could be decrypted as follows:
import java.security.SecureRandom
import java.util.Base64
import javax.crypto.spec.PBEKeySpec
import javax.crypto.SecretKeyFactory
import com.macasaet.fernet.Key
import com.macasaet.fernet.Token
import com.macasaet.fernet.StringValidator
import com.macasaet.fernet.Validator
import java.time.Duration
import java.time.temporal.TemporalAmount
...
// Data from encryption
val salt = Base64.getUrlDecoder().decode("2Yb8EwpYkMlycHxoKcmHuA==")
val token = Token.fromString("gAAAAABfoAmp7C7IWVgA5urICEIspm_MPAGZ-SyGnPEVUBBNerWQ-K6mpSoYTwRkUt3FobyAFHbYfhNtiGMe_96yyLvUoeLIIg==");
// Derive Fernet key
val key = deriveKey("my password", salt)
val fernetKey = Key(key)
// Decrypt
val validator: Validator<String> = object : StringValidator {
override fun getTimeToLive(): TemporalAmount {
return Duration.ofHours(24)
}
}
val data = token.validateAndDecrypt(fernetKey, validator)
println(data) // my data...
with:
fun deriveKey(password: String, salt: ByteArray): String {
val iterations = 100000
val derivedKeyLength = 256
val spec = PBEKeySpec(password.toCharArray(), salt, iterations, derivedKeyLength)
val secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256")
val key = secretKeyFactory.generateSecret(spec).encoded
return Base64.getUrlEncoder().encodeToString(key)
}
Here the Fernet key is derived using the key derivation function PBKDF2. PBKDF2 expects various input parameters, such as a password, a digest, a salt, an iteration count and the desired key length. In the posted example the key is returned Base64url encoded.For decryption the same parameters must be used as for encryption. Since the salt is usually (as in the posted code) randomly generated during encryption, it must be passed to the decryption side along with the ciphertext (note: the salt is not a secret).
The validator sets the time-to-live (by default 60s) to 24h, see here for more details.
In the posted Python code the export of the salt has to be added, e.g. by Base64url encoding it analogous to key and token (and printing it for simplicity). In practice, salt and token could also be concatenated during encryption and separated during decryption.
Update:
The encryption part is analogous:
// Generate salt
val salt = generateSalt()
println(Base64.getUrlEncoder().encodeToString(salt))
// Derive Fernet key
val key = deriveKey("my password", salt)
val fernetKey = Key(key)
// Encrypt
val data = "my data..."
val token = Token.generate(fernetKey, data)
println(token.serialise()) // the Base64url encoded token
with
fun generateSalt(): ByteArray {
val random = SecureRandom()
val salt = ByteArray(16)
random.nextBytes(salt)
return salt
}
This question already has answers here:
How to decrypt OpenSSL AES-encrypted files in Python?
(7 answers)
Closed 4 years ago.
I encrypted a file using openssl using the below command
cat input.txt
hello world
openssl aes-256-cbc -pass pass:'00112233445566778899aabbccddeeff' -iv a2a8a78be66075c94ca5be53c8865251 -nosalt -base64 -in input.txt -out output.txt
cat output.txt
pt7DqtAwtTjPbTlzVApucQ==
How can i decrypt the file using python Crypto package. I tried the below and it didn't work.
>>> from Crypto.Cipher import AES
>>> from base64 import b64decode
>>> with open('output.txt') as f:
... aes = AES.new('00112233445566778899aabbccddeeff', AES.MODE_CBC, IV='a2a8a78be66075c94ca5be53c8865251'.decode('hex'))
... print(aes.decrypt(b64decode(f.read())))
...
L�|�L ��O�*$&9�
I need a way to encrypt a file using openssl aes-256-cbc cipher and decrypt in python
The password is not the key. Openssl uses EVP_BytesToKey to create an appropriate key (& IV, if necessary) from the password and the salt.
As James K Polk mentions in a comment, you can use the -P (or -p) option to tell Openssl to print the key (in hex ), which you can then pass to Crypto.Cipher. Alternatively, you can implement EVP_BytesToKey in Python, as shown below. This is a simplified version of EVP_BytesToKey that uses no salt, and the default value of 1 for the count arg.
As the EVP_BytesToKey docs state, this is a rather weak password derivation function. As the hashlib docs mention, modern password derivation normally performs hundreds of thousands of hashes to make password hashing attacks very slow.
We also need a function to remove the PKCS7 padding from the decrypted data bytes. The unpad function below simply assumes that the padding data is valid. In real software the unpad function must verify that the padded data is valid to prevent padding-based attacks. My unpad function also assumes the data has been encoded as UTF-8 bytes and decodes the unpadded data to text.
from __future__ import print_function
from Crypto.Cipher import AES
from base64 import b64decode
from hashlib import md5
def evp_simple(data):
out = ''
while len(out) < 32:
out += md5(out + data).digest()
return out[:32]
def unpad(s):
offset = ord(s[-1])
return s[:-offset].decode('utf-8')
iv = 'a2a8a78be66075c94ca5be53c8865251'.decode('hex')
passwd = '00112233445566778899aabbccddeeff'
key = evp_simple(passwd)
print('key', key.encode('hex'))
aes = AES.new(key, AES.MODE_CBC, IV=iv)
data = b64decode('pt7DqtAwtTjPbTlzVApucQ==')
raw = aes.decrypt(data)
print(repr(raw), len(raw))
plain = unpad(raw)
print(repr(plain), len(plain))
output
key b4377f7babf2991b7d6983c4d3e19cd4dd37e31af1c9c689ca22e90e365be18b
'hello world\n\x04\x04\x04\x04' 16
u'hello world\n' 12
That code will not run on Python 3, so here's a Python 3 version.
from Crypto.Cipher import AES
from base64 import b64decode
from hashlib import md5
def evp_simple(data):
out = b''
while len(out) < 32:
out += md5(out + data).digest()
return out[:32]
def unpad(s):
offset = s[-1]
return s[:-offset].decode('utf-8')
iv = bytes.fromhex('a2a8a78be66075c94ca5be53c8865251')
passwd = b'00112233445566778899aabbccddeeff'
key = evp_simple(passwd)
aes = AES.new(key, AES.MODE_CBC, IV=iv)
data = b64decode('pt7DqtAwtTjPbTlzVApucQ==')
raw = aes.decrypt(data)
print(repr(raw), len(raw))
plain = unpad(raw)
print(repr(plain), len(plain))
output
b'hello world\n\x04\x04\x04\x04' 16
'hello world\n' 12
I have been encrypting messages with a nodejs module like so:
var crypto = require('crypto'),
algorithm = 'aes-256-ctr',
password = 'd6F3Efeq';
function encrypt(text){
var cipher = crypto.createCipher(algorithm,password)
var crypted = cipher.update(text,'utf8','hex')
crypted += cipher.final('hex');
return crypted;
}
(from here:https://lollyrock.com/articles/nodejs-encryption/)
However, using the same secret, same algorithm and same mode I cannot decrypt this using cryptography in Python.
Here's one of the things I've tried:
crypto = AES.new(password, AES.MODE_CTR)
print(crypto.decrypt(message.decode("hex")))
Returns binary data. Encoding it in UTF-8 fails, and most interestingly:
it seems AWS.new generates a random iv each time, and the result of the decryption is different for each run!
.. Now, the nodeJS library does not return a Nonce, so I don't know what else to bring with me from the NodeJS function apart from the ciphertext and the password (secret) - any ideas?
I'm trying to use the cryptography python module (cryptography.io) but cannot implement a working example. From example in documentation.
This code:
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import openssl
from cryptography.hazmat.backends import default_backend
dbackend = default_backend
iv = 'ababababcdcdcdcd1212121234343434'.encode('hex')
cipher = Cipher(modes.CBC(iv), algorithms.AES('aabbccddaabbccdd1122334411223344'.decode('hex')), backend=dbackend)
e = cipher.encryptor()
ct = e.update("Secret messagexx") + e.finalize()
d = cipher.decryptor()
clear = d.update(ct) + d.finalize()
fails with:
cryptography.exceptions.UnsupportedAlgorithm: Backend object does not implement CipherBackend.
I then try with openssl backend:
obackend = openssl.backend
cipher = Cipher(modes.CBC(iv), algorithms.AES('aabbccddaabbccdd1122334411223344'.decode('hex')), backend=obackend)
And it fails with:
TypeError: Expected interface of CipherAlgorithm.
I've been trying to read the docs but I can't even get the example code to work. Any help appreciated.
Update - solved:
In case someone stumbles over this I add this working example here (where I use ECB mode which was what I actually wanted).
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
backend = default_backend()
cipher = Cipher(algorithms.AES('aabbccddaabbccdd1122334411223344'.decode('hex')), modes.ECB(), backend=backend)
e = cipher.encryptor()
ct = e.update("Secret messagexx") + e.finalize()
d = cipher.decryptor()
clear = d.update(ct) + d.finalize()
print clear
You are passing default_backend as the backend argument, but that's actually a function. Call it with default_backend() and it will return a backend object you can pass in.
The non-hazmat layer does contain a symmetric encryption recipe (known as Fernet), so you may want to consider using that if it meets your needs.