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.
Related
I'm playing around with the cryptography library in Python and I have a CRL object. Here is the setup:
from cryptography import x509
from cryptography.hazmat.backends import default_backend
from cryptography.x509.oid import ExtensionOID, NameOID, AuthorityInformationAccessOID
# Need to set default backend for cryptography as our version is low:
default_backend = default_backend()
crl_file = path_to/some_crl_file.crl
crl = x509.load_pem_x509_crl(crl_file, default_backend)
print(crl.extensions)
I receive the following output of extensions:
<Extensions([<Extension(oid=<ObjectIdentifier(oid=2.5.29.20, name=cRLNumber)>, critical=False, value=<CRLNumber(17)>)>, <Extension(oid=<ObjectIdentifier(oid=2.5.29.35, name=authorityKeyIdentifier)>, critical=False, value=<AuthorityKeyIdentifier(key_identifier=b"\xe4\xaf+&q\x1a+H'\x85/Rf,\xef\xf0\x89\x13q>", authority_cert_issuer=None, authority_cert_serial_number=None)>)>])>
I then get the CRL Number with the following:
print(crl.extensions.get_extension_for_oid(ExtensionOID.CRL_NUMBER).value)
This outputs <CRLNumber(17)>. How do I get it so that I receive the int value of 17 from this?
I swear someone answered this and I responded, but maybe I dreamed it up.
Anywho. I took another look into this and resolved it with the following:
print(crl.extensions.get_extension_for_oid(ExtensionOID.CRL_NUMBER).value.crl_number)
I needed to add the .crl_number at the end of value.
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
}
I am communicating with our clients server. For an api I need to sign a string with my private key. They have the following condition to follow
User SHA 256 algorithm to calculate the hash of the string
Use the private key and RSA (PKCS1_PADDING) algorithm to sign the Hash Value.
Base64 encode the encrypted Hash Value
and I am doing following
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA256
from Crypto.PublicKey import RSA
import base64
pkey = RSA.importKey(keystring)
message = "Hello world"
h = SHA256.new(message.encode())
signature = PKCS1_v1_5.new(pkey).sign(h)
result = base64.b64encode(signature).decode()
Here I am getting a string as result. But on the server side my signature is not matching.
Is there anything I am going wrong with ?? Can anyone help me on this ?
I came back to this question recently and noticed it was never resolved. I don't know what was going wrong with the OPs setup but the following code worked for me.
First, the python code that generates the signature of "Hello world":
from Cryptodome.Signature import PKCS1_v1_5
from Cryptodome.Hash import SHA256
from Cryptodome.PublicKey import RSA
import base64
def sign(message: str, private_key_str: str) -> str:
priv_key = RSA.importKey(private_key_str)
h = SHA256.new(message.encode('utf-8'))
signature = PKCS1_v1_5.new(priv_key).sign(h)
result = base64.b64encode(signature).decode()
return result
And now the Java code that verifies it:
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
...
...
public static boolean verify(String message, String b64Sig, byte[] pubkey_spki) throws GeneralSecurityException {
var pubKey = (PublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(pubkey_spki));
var verifier = Signature.getInstance("SHA256withRSA");
verifier.initVerify(pubKey);
verifier.update(message.getBytes(StandardCharsets.UTF_8));
return verifier.verify(Base64.getDecoder().decode(b64Sig));
}
Perhaps the trickiest part of this is specifying the correct padding scheme in each language/library. These signatures use the scheme identified as RSASSA-PKCS1-v1_5 in the PKCS#1 RFC 8017. On the python side this is accomplished by providing the SHA256 hash object to the PKCS1_v1_5 signature object. In Java it is perhaps a little more straightforward in that you ask for Signature object that implements the RSA algorithm with SHA256 as the hash function, but still have to know that this is RSASSA-PKCS1-v1_5 and not some other possibility in RFC 8017.
I think if one is not already something of an expert then understanding that these magic choices in python and Java produce compatible code is going to be difficult.
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()
I am trying to encrypt a small string using Python and Ruby. I've written code in both these languages that should do exactly the same thing:
In Python:
from Crypto.PublicKey import RSA
from Crypto.Util import asn1
from Crypto import Random
import sys, time, signal, socket, requests, re, base64
pubkey = "9B596422997705A8805F25232C252B72C6B68752446A30BF9117783FE094F8559CA4A7AA5DBECAEC163596E96CD9577BDF232EF2F45DC474458BDA8EC272311924B8A176896E690135323D16800CFB9661352737FEDA9FB8DD44B6025EA8037CBA136DAE2DC0061B2C66A6F564E2C9E9579DAFD9BFF09ACF3B6E39BF363370F4A8AD1F88E3AE9A7F2C1B1C75AC00EAE308F57EC9FBDA244FC8B0D1234677A6BEE228FEE00BF653E8E010D0E59A30D0A1194298E052399A62E6FBD490CF03E16A1166F901E996D53DE776169B4EE8705E1512CCB69F8086C66213667A070A65DA28AF18FC8FC01D37158706A0B952D0963A9A4E4A6451758710C9ADD1245AB057389535AB0FA1D363A29ED8AE797D1EE958352E55D4AD4565C826E9EF12FA53AE443418FD704091039E190690FD55BF32E7E8C7D7668B8F0550C5E650C7D021F63A5055B7C1AEE6A669079494C4B964C6EA7D131FA1662CF5F5C83721D6F218038262E9DDFE236015EE331A8556D934F405B4203359EE055EA42BE831614919539A183C1C6AD8002E7E58E0C2BCA8462ADBF3916C62857F8099E57C45D85042E99A56630DF545D10DD338410D294E968A5640F11C7485651B246C5E7CA028A5368A0A74E040B08DF84C8676E568FC12266D54BA716672B05E0AA4EE40C64B358567C18791FD29ABA19EACA4142E2856C6E1988E2028703B3E283FA12C8E492FDB"
foobar = "foobar"
pubkey_int = long(pubkey,16)
pub_exp = 65537L
pubkey_obj = RSA.construct((pubkey_int, pub_exp))
encypted_data = pubkey_obj.encrypt(foobar, pub_exp)
encypted_data_b64 = base64.b64encode(encypted_data[0])
print encypted_data_b64
In Ruby:
require 'openssl'
require 'base64'
pubkey = "9B596422997705A8805F25232C252B72C6B68752446A30BF9117783FE094F8559CA4A7AA5DBECAEC163596E96CD9577BDF232EF2F45DC474458BDA8EC272311924B8A176896E690135323D16800CFB9661352737FEDA9FB8DD44B6025EA8037CBA136DAE2DC0061B2C66A6F564E2C9E9579DAFD9BFF09ACF3B6E39BF363370F4A8AD1F88E3AE9A7F2C1B1C75AC00EAE308F57EC9FBDA244FC8B0D1234677A6BEE228FEE00BF653E8E010D0E59A30D0A1194298E052399A62E6FBD490CF03E16A1166F901E996D53DE776169B4EE8705E1512CCB69F8086C66213667A070A65DA28AF18FC8FC01D37158706A0B952D0963A9A4E4A6451758710C9ADD1245AB057389535AB0FA1D363A29ED8AE797D1EE958352E55D4AD4565C826E9EF12FA53AE443418FD704091039E190690FD55BF32E7E8C7D7668B8F0550C5E650C7D021F63A5055B7C1AEE6A669079494C4B964C6EA7D131FA1662CF5F5C83721D6F218038262E9DDFE236015EE331A8556D934F405B4203359EE055EA42BE831614919539A183C1C6AD8002E7E58E0C2BCA8462ADBF3916C62857F8099E57C45D85042E99A56630DF545D10DD338410D294E968A5640F11C7485651B246C5E7CA028A5368A0A74E040B08DF84C8676E568FC12266D54BA716672B05E0AA4EE40C64B358567C18791FD29ABA19EACA4142E2856C6E1988E2028703B3E283FA12C8E492FDB"
foobar = "foobar"
asn1_sequence = OpenSSL::ASN1::Sequence.new(
[
OpenSSL::ASN1::Integer.new("0x#{pubkey}".to_i(16)),
OpenSSL::ASN1::Integer.new("0x10001".to_i(16))
]
)
public_key = OpenSSL::PKey::RSA.new(asn1_sequence)
data = Base64.encode64(public_key.public_encrypt(foobar))
puts data
Both these scripts are trying to encrypt the string foobar using the same public key. I expected both of them to output the same results each time, however this is not the case. Furthermore, every time the Ruby Script is executed, it outputs a different result.
Can someone help me identify the difference between these two scripts that is responsible for this behavior?
I am able to solve this issue by reading the documentation for Class _RSAobj (https://www.dlitz.net/software/pycrypto/api/current/Crypto.PublicKey.RSA._RSAobj-class.html#encrypt)
Attention: this function performs the plain, primitive RSA encryption
(textbook). In real applications, you always need to use proper
cryptographic padding, and you should not directly encrypt data with
this method. Failure to do so may lead to security vulnerabilities. It
is recommended to use modules Crypto.Cipher.PKCS1_OAEP or
Crypto.Cipher.PKCS1_v1_5 instead.
Looks like cryptographic padding is not used by default in the RSA module for Python, hence the difference.
Modified Python Script:
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
import sys, time, signal, socket, requests, re, base64
pubkey = "9B596422997705A8805F25232C252B72C6B68752446A30BF9117783FE094F8559CA4A7AA5DBECAEC163596E96CD9577BDF232EF2F45DC474458BDA8EC272311924B8A176896E690135323D16800CFB9661352737FEDA9FB8DD44B6025EA8037CBA136DAE2DC0061B2C66A6F564E2C9E9579DAFD9BFF09ACF3B6E39BF363370F4A8AD1F88E3AE9A7F2C1B1C75AC00EAE308F57EC9FBDA244FC8B0D1234677A6BEE228FEE00BF653E8E010D0E59A30D0A1194298E052399A62E6FBD490CF03E16A1166F901E996D53DE776169B4EE8705E1512CCB69F8086C66213667A070A65DA28AF18FC8FC01D37158706A0B952D0963A9A4E4A6451758710C9ADD1245AB057389535AB0FA1D363A29ED8AE797D1EE958352E55D4AD4565C826E9EF12FA53AE443418FD704091039E190690FD55BF32E7E8C7D7668B8F0550C5E650C7D021F63A5055B7C1AEE6A669079494C4B964C6EA7D131FA1662CF5F5C83721D6F218038262E9DDFE236015EE331A8556D934F405B4203359EE055EA42BE831614919539A183C1C6AD8002E7E58E0C2BCA8462ADBF3916C62857F8099E57C45D85042E99A56630DF545D10DD338410D294E968A5640F11C7485651B246C5E7CA028A5368A0A74E040B08DF84C8676E568FC12266D54BA716672B05E0AA4EE40C64B358567C18791FD29ABA19EACA4142E2856C6E1988E2028703B3E283FA12C8E492FDB"
foobar = "foobar"
pubkey_int = long(pubkey,16)
pub_exp = 65537L
pubkey_obj = RSA.construct((pubkey_int, pub_exp))
cipher = PKCS1_v1_5.new(pubkey_obj)
encypted_data = cipher.encrypt(foobar)
encypted_data_b64 = base64.b64encode(encypted_data)
print encypted_data_b64