Python: Cryptodomex not working with DSA verification - python

I tried to verify the signature of a file by DSA encryption. I am using Pyton 3.6 and pycryptodomex version 3.4.7.
Unhappily the documentation code seems to be outdated (was trying to get a simple example working):
from Crypto.PublicKey import DSA
from Crypto.Signature import DSS
from Crypto.Hash import SHA256
# Create a new DSA key
key = DSA.generate(2048)
f = open("public_key.pem", "w")
f.write(key.publickey().exportKey(key))
# Sign a message
message = b"Hello"
hash_obj = SHA256.new(message)
signer = DSS.new(key, 'fips-186-3')
signature = key.sign(hash_obj)
# Load the public key
f = open("public_key.pem", "r")
hash_obj = SHA256.new(message)
pub_key = DSA.import_key(f.read())
# Verify the authenticity of the message
if pub_key.verify(hash_obj, signature):
print "OK"
else:
print "Incorrect signature"
this is my code, tried to fix the function calls which were not working:
from Cryptodome.PublicKey import DSA
from Cryptodome.Signature import DSS
from Cryptodome.Hash import SHA256
# Create a new DSA key
key = DSA.generate(2048)
print(key.exportKey())
# Sign a message
message = b"Hello"
hash_obj = SHA256.new(message)
signer = DSS.new(key, 'fips-186-3')
signature = signer.sign(hash_obj)
# Load the public key
pub_key = DSA.import_key(key.publickey().exportKey())
verifyer = DSS.new(pub_key, 'fips-186-3')
hash_obj = SHA256.new(message)
# Verify the authenticity of the message
if verifyer.verify(hash_obj, signature):
print("OK")
else:
print("Incorrect signature")
Can someone help me with this topic?

works like that
from Crypto.PublicKey import DSA
from Crypto.Signature import DSS
from Crypto.Hash import SHA256
import base64
# Create a new DSA key
key = DSA.generate(2048)
f = open("public_key.pem", "w")
f.write(base64.b64encode(key.publickey().export_key()).decode("utf-8") )
f.close()
# Sign a message
message = b"Hello"
hash_obj = SHA256.new(message)
signer = DSS.new(key, 'fips-186-3')
signature = signer.sign(hash_obj)
# Load the public key
f = open("public_key.pem", "r")
hash_obj = SHA256.new(message)
pub_key = DSA.import_key(base64.b64decode(f.read()))
verifier = DSS.new(pub_key, 'fips-186-3')
# Verify the authenticity of the message
try:
verifier.verify(hash_obj, signature)
print("The message is authentic.")
except ValueError:
print("The message is not authentic.")

Related

Error decrypting using AES GCM in Python; AttributeError: 'Cipher' object has no attribute 'decrypt'

I am sending some information to a https server and receving a response. To increase the privary, I want to use some kind of encryption.
I am sending json data and I am encrypting the data as following
I am using Python3.6
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
from cryptography.hazmat.primitives import hashes, hmac
from cryptography.hazmat.backends import default_backend
salt = os.urandom(16)
password = b'password'
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=32,
salt=salt,
iterations=10000
)
key = kdf.derive(password)
cipher = Cipher(algorithms.AES(key), modes.GCM(salt), backend=default_backend())
decryptor = cipher.decryptor()
encryptor = cipher.encryptor()
headers = {'Content-Type': 'application/json'}
data = {'xxxx': xxxx, 'xxxx': xxxx}
encrypted_data = encryptor.update(json.dumps(data).encode('utf-8')) + encryptor.finalize()
tag = encryptor.tag
Now, I am trying to decrypt the data as following
encrypted_data_b64 = request['encrypted_data']
tag_b64 = request['tag']
salt_b64 = request['salt']
encrypted_data = base64.b64decode(encrypted_data_b64)
tag = base64.b64decode(tag_b64)
salt = base64.b64decode(salt_b64)
password = b'password'
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=32,
salt=salt,
iterations=10000
)
key = kdf.derive(password)
cipher = Cipher(algorithms.AES(key), modes.GCM(salt), backend=default_backend())
decrypted_data = cipher.decrypt(encrypted_data, tag)
getting error :
AttributeError: 'Cipher' object has no attribute 'decrypt'
Also, tried
decryptor = cipher.decryptor()
decrypted_data = decryptor.update(encrypted_data) + decryptor.finalize()
Gettting error:
"Authentication tag must be provided when decrypting." ValueError: Authentication tag must be provided when decrypting.
So, I tried
decrypted_data = decryptor.update(encrypted_data) +
decryptor.finalize(tag) TypeError: finalize() takes 1 positional
argument but 2 were given
Any suggestion will be helpful.

Python RSA message encryption "Plaintext is too long"?

I'm using the following code to implement a basic RSA solution for encrypting and decrypting data, but when I try to encrypt any text that is longer than 87 characters I get an error saying Plaintext is too long from the file Crypto/Cipher/PKCS1_OAEP.py.
I read on other questions that RSA cannot encrypt and decrypt large sets of data but I'm not sure if that's true. If it is, what other options can I use to encrypt any amount of data?
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA512, SHA384, SHA256, SHA, MD5
from Crypto import Random
from base64 import b64encode, b64decode
hash = "SHA-256"
def newkeys(keysize):
random_generator = Random.new().read
key = RSA.generate(keysize, random_generator)
private, public = key, key.publickey()
return public, private
def encrypt(message, pub_key):
cipher = PKCS1_OAEP.new(pub_key)
return cipher.encrypt(message)
i fixed it like this : [This is on my code i havent edited yours]
with open(file, 'rb') as f:
fernet_key = f.read()
if len(fernet_key) > 80 :
fernet_key1 = ''
tostart = 0
toadd = 0
flag_tostart = 0
while True:
if fernet_key1 == fernet_key:
break
else:
flag_tostart = flag_tostart +1
if flag_tostart == '2'or flag_tostart > 2 or flag_tostart == 2:
tostart = tostart + 80
toadd = toadd +80
if tostart == 0 :
tostart = 0
else:
tostart = tostart + 80
fernet_key[tostart:toadd] += fernet_key1
public_crypter = PKCS1_OAEP.new(public_key)
with open(file, 'wb') as f:
enc_fernet_key =
public_crypter.encrypt(fernet_key1)
f.write(enc_fernet_key)

Fernet Invalid Token Error for Password Manager

I am currently trying to make a custom little password manager in Python using the cryptography module. Encryption with a master password seems okay, but decrypting it results in 2 errors:
Here's the code:
import os
import base64
import pickle
from cryptography.fernet import Fernet
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
logins = {}
masterpass = bytes(input('Unlock login ring with master password: '), 'utf-8')
def newLogin(email, username, password):
logins['{}:{}'.format(email, username)] = password
def loadLogins():
salt = os.urandom(16)
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=32,
salt=salt,
iterations=100000,
backend=default_backend()
)
key = base64.urlsafe_b64encode(kdf.derive(masterpass))
f = Fernet(key)
file = open('keyring.keys', 'rb')
token = f.decrypt(file.read())
print(file.read())
file.close()
def saveLogins():
salt = os.urandom(16)
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=32,
salt=salt,
iterations=100000,
backend=default_backend()
)
key = base64.urlsafe_b64encode(kdf.derive(masterpass))
f = Fernet(key)
logs = ['{}'.format(x) for x in logins]
pasw = ['{}'.format(logins[y]) for y in logins]
keys = []
for i in range(len(logins)):
keys += logs[i] + ':' + pasw[i] + ';'
print(''.join(keys))
keyring = f.encrypt(bytes(''.join(keys), 'utf-8'))
file = open('keyring.keys', 'wb')
pickle.dump(keyring, file)
file.close()
The way my code works is you have to give it a master password initially. It will then store that master password as a bytes object. Next, you can add/update logins to the logins dictionary. Then, using the Fernet recipe for passwords (Using passwords with Fernet (cryptography module)), I convert the master password into a Fernet key for encrypting and decrypting the logins to and from a file. As stated above, the encryption works fine, but decryption always results in an error. Am I doing something wrong with my decryption function? Or how I implement the password encryption/decryption?
Thanks.
Sorry, stupid mistakes where made. The solution was to generate an os.urandom salt and use that as a literal (aka "magic number") for the derivation of the key. Also, I just need to derive the key only once, not in every function.
I also need to call pickle.load on the file I am going to write to. Here is a working solution:
import base64
import pickle
from cryptography.fernet import Fernet
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
logins = {}
masterpass = bytes(input('Unlock login ring with master password: '), 'utf-8')
# Derive key from master password
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=32,
salt=b'\xaab\xc0\xe0+\xc8\xb29\xc5\xe9\xbb\xfb\xaa\xb6\xab\xa7',
iterations=100000,
backend=default_backend()
)
key = base64.urlsafe_b64encode(kdf.derive(masterpass))
f = Fernet(key)
# Add or update login information in
# the logins dictionary.
def setLogin(website, email, username, password):
logins[website] = '{}:{}:{}'.format(email, username, password)
# Load and decrypt the logins and
# return them in string format.
def loadLogins():
file = open('keyring.keys', 'rb')
token = f.decrypt( pickle.load(file) )
file.close()
return token.decode('utf-8')
# Separate and load logins into the
# logins dictionary.
def parseLogins(strLogins):
individual_logins = strLogins.split(';')
for i in range(len(individual_logins)):
if (individual_logins[i] != ''):
website, email, username, password = individual_logins[i].split(':')
setLogin(website, email, username, password)
print(individual_logins)
# Encrypt and save logins in a bytes file
# using the master password.
def saveLogins():
logs = ['{}'.format(x) for x in logins]
pasw = ['{}'.format(logins[y]) for y in logins]
keys = []
for i in range(len(logins)):
keys += logs[i] + ':' + pasw[i] + ';'
print(''.join(keys))
keyring = f.encrypt(bytes(''.join(keys), 'utf-8'))
file = open('keyring.keys', 'wb')
pickle.dump(keyring, file)
print(keyring)
file.close()
# Display all login information.
def showLogins():
for i in logins:
info = logins[i].split(':')
website = i
email = info[0]
username = info[1]
password = info[2]
print(f'\nWebsite: {website}\nEmail: {email}\nUsername: {username}\nPassword: {password}\n')

AttributeError: 'bytes' object has no attribute 'encrypt'

I would like to generate an RSA key pair, and then write functions to decrypt using the public key and encrypt using the private key.
At the moment I am generating my keys as follows
from cryptography.hazmat.primitives import serialization as crypto_serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.backends import default_backend as crypto_default_backend
key = rsa.generate_private_key(
backend=crypto_default_backend(),
public_exponent=65537,
key_size=2048
)
private_key = key.private_bytes(
crypto_serialization.Encoding.PEM,
crypto_serialization.PrivateFormat.PKCS8,
crypto_serialization.NoEncryption())
public_key = key.public_key().public_bytes(
crypto_serialization.Encoding.OpenSSH,
crypto_serialization.PublicFormat.OpenSSH
)
I then followed the cryptography documentation to encrypt with RSA, it says
message = b"encrypted data"
ciphertext = private_key.encrypt(
message,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
I replaced public_key with private_key.
And to decrypt
plaintext = public_key.decrypt(
ciphertext,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
Here I replaced private_key with public_key.
However, running the encrypt part gives me the error "AttributeError: 'bytes' object has no attribute 'encrypt'".
How can I fix this?
To fix your problem, use:
public_key = key.public_key()
You should not use public_key = key.public_key().public_bytes(...) as you will get bytes. You are mixing bytes and key.
Also use the public key to encrypt (not private):
from cryptography.hazmat.primitives import serialization as crypto_serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.backends import default_backend as crypto_default_backend
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import hashes
key = rsa.generate_private_key(
backend=crypto_default_backend(),
public_exponent=65537,
key_size=2048
)
private_key = key.private_bytes(
crypto_serialization.Encoding.PEM,
crypto_serialization.PrivateFormat.PKCS8,
crypto_serialization.NoEncryption())
public_key = key.public_key()
message = b"encrypted data"
ciphertext = public_key.encrypt(
message,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)

How to encrypt messages with ECC in pycryptodom

I'm using Hybrid encryption(RSA+AES) but the length was large and now i want to use ECC instead of RSA, but in pycryptodom there is no implementation for that..
this is my RSA code
def generate_keys():
key = RSA.generate(1024)
private_key = key.exportKey(format='PEM', pkcs=8,
protection="scryptAndAES128-CBC")
f = open("private_key.pem", "wb")
f.write(private_key)
public_key = key.publickey().exportKey('PEM')
f = open("public_key.pem", "wb")
f.write(public_key)
f.close()
def encrypt(username, msg):
#get the reciever's public key
f = open("{}.pem".format(username)) # a.salama.pem
recipient_key = RSA.import_key(f.read())
f.close()
# Encrypt the session key with the reciever's public RSA key
cipher_rsa = PKCS1_OAEP.new(recipient_key)
# Encrypt the data with the AES session key
session_key = get_random_bytes(16)
cipher_aes = AES.new(session_key, AES.MODE_EAX)
ciphertext, tag = cipher_aes.encrypt_and_digest(msg.encode('utf-
8'))
encrypted_data = cipher_rsa.encrypt(session_key) +
cipher_aes.nonce + tag + ciphertext
encrypted_data = base64.b64encode(encrypted_data)
return encrypted_data
And after trying to use ECC+AES the code will be
from Crypto.PublicKey import ECC
from Crypto.Random import get_random_bytes
from Crypto.Cipher import AES, PKCS1_OAEP
import base64
def generate_keys():
key = ECC.generate(curve='P-256') #3072 RSA
private_key = key.export_key(format='PEM')
f = open('private_key.pem','wt')
f.write(private_key)
f.close()
public_key = key.public_key().export_key(format='PEM')
f = open('public_key.pem','wt')
f.write(public_key)
f.close()
def encrypt(username, msg):
#get the reciever's public key
f = open("{}.pem".format(username), 'rt') # a.salama.pem
recipient_key = ECC.import_key(f.read())
f.close()
# Encrypt the session key with the reciever's public RSA key
cipher_rsa = PKCS1_OAEP.new(recipient_key)
# Encrypt the data with the AES session key
session_key = get_random_bytes(16)
#we use the EAX mode to allow detection of unauthorized
modifications.
cipher_aes = AES.new(session_key, AES.MODE_EAX)
ciphertext, tag = cipher_aes.encrypt_and_digest(msg.encode('utf-
8'))
encrypted_data = cipher_rsa.encrypt(session_key) +
cipher_aes.nonce + tag + ciphertext
encrypted_data = base64.b64encode(encrypted_data)
return encrypted_data.decode()
This gives me error in this line
cipher_rsa = PKCS1_OAEP.new(recipient_key)
but i want to encrypt the session key with the public key, how to do this with pycryptodome or any other way
Pycryptodome does not support elliptic curve-based encryption (ECC encryption).
Use the ECIES algorithm instead, e.g. this Python library: https://github.com/kigawas/eciespy
The ECIES (Elliptic Curve Integrated Encryption Scheme) is hybrid encryption scheme, which combines ECC public-key cryptography to asymmetrically encrypt a session key, used later to encrypt the input data with a symmetric cipher (e.g. with AES-GCM).
I know this is an old question, but to anyone else that comes here:
You can use Pycryptodome or Cryptography for this now. Using Pycrptodome for example:
from Crypto.PublicKey import ECC
def get_or_create_public_key(filename: str = "private_key.pem"):
""" Helper function to retrieve public key """
private_key_file = os.path.join(settings.BASE_DIR, filename)
if os.path.exists(private_key_file):
file = open(private_key_file, "rt")
private_key = ECC.import_key(file.read(), passphrase=settings.SECRET_KEY)
else:
private_key = ECC.generate(curve="P-256")
file = open(private_key_file, "wt")
file.write(
private_key.export_key(
format="PEM",
use_pkcs8=True,
passphrase=settings.SECRET_KEY,
protection="PBKDF2WithHMAC-SHA1AndAES128-CBC",
)
)
file.close()
public_key = private_key.public_key()
return public_key.export_key(format="PEM")

Categories

Resources