Cryptography.py using encrypt with private key and decrypt with public key - python-3.x

I need to encrypt a string using a private key. Then I want to use the asymmetric public key to decrypt the encrypted string and obtain the original string. I am using cryptography.py which allows the opposite (public for encryption and private for decryption). Is there a method included with this library that would allow me to do this?
Note: I have tried to use the private_key.sign() method and this works for encryption. Reading articles I learned this is not a safe nor 'good' way of encrypting and is only used to verify the key.
I am open to using a different library if I need to. I have done a lot of research on this topic and can not find anything online that works with python. Im open for suggestions, thanks.
I will post my code below, read_public() and read_private() is returning an rsa object from crytopgraphy.py
def encrypt(message):
######### Public (shared) device only #########
message = bytes(message,'utf-8')
private_key = read_private()
encrypted = private_key.encrypt( #use private
message,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
return encrypted
def decrypt(encrypted):
######### Private device only ##########
#encrypted = bytes(encrypted, 'utf-8')
public_key = read_public()
original_message = public_key.decrypt( #use public
encrypted,
padding.OAEP(
#mask generated function object
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
return original_message
output: Console output
I understand this error message and why it does not work, is there a way to make this work?

Related

AES encryption error: The input data is not a complete block

I want to encrypt username and password using AES and Python. I want to encrypt username and password with the following details :
key = "qwertyui89765432";
aes.KeySize = 128;
aes.BlockSize = 128;
aes.Mode = CipherMode.ECB; // Noncompliant
aes.Padding = PaddingMode.PKCS7;
code :
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from Crypto.Util.Padding import unpad
key = 'qwertyui897654321'
username = "Welcome!#34"
cipher = AES.new(key.encode('utf8'), AES.MODE_ECB)
msg =cipher.encrypt(pad(username.encode('utf8'), 16))
print(msg.hex())
I used the above code encrypting username and password and I used the encrypted username and password in the Postman for getting the response.At that time, I got an error like below:
{
"Status": "FAILED",
"EmpCode": "",
"Remarks": "The input data is not a complete block."
}
Is there any mismatch in the encryption code with respect to the above given details?
Can anyone suggest a solution to solve this issue.

crypto.load_certificate / Get public key encryption

How is it possible from crypto.load_certificate to get the public key encryption ? (for example "RSA (2048 Bits").
I can get the public key easily as below :
from OpenSSL import crypto
cert = crypto.load_certificate(crypto.FILETYPE_PEM, open("certificate.crt")).read()
pubKey = cert.get_pubkey()
But I couldn't find anything in the documentation concerning the encryption. Any ideas?
Actually it is really simple :
from OpenSSL import crypto
cert = crypto.load_certificate(crypto.FILETYPE_PEM, open("certificate.crt")).read()
pubKey = cert.get_pubkey()
keySize = pubKey.bits()
if pubKey.type() == crypto.TYPE_RSA:
keyType = 'RSA'
elif pubKey.type() == crypto.TYPE_DSA:
keyType = 'DSA'
print(keyType + "-" + str(keySize))

Access Denied Signed URL Python3 using cloud front

I am trying to create signed urls for my s3 bucket to which only select people will have access to until the time expires.
I am not able to find the issue in my code. Please help
import boto
from boto.cloudfront import CloudFrontConnection
from boto.cloudfront.distribution import Distribution
import base64
import json
import rsa
import time
def lambda_handler(event, context):
url = "https://notYourUrl.com/example.html"
expires = int(time.time() + 36000)
pem = """-----BEGIN RSA PRIVATE KEY-----
myKey
-----END RSA PRIVATE KEY-----"""
Cloudfront console
key_pair_id = 'myKey'
policy = {
"Statement": [
{
"Resource":url,
"Condition":{
"DateLessThan":{"AWS:EpochTime":expires},
}
}
]
}
policy = json.dumps(policy)
private_key = rsa.PrivateKey.load_pkcs1(pem)
policy = policy.encode("utf-8")
signed = rsa.sign(policy, private_key, 'SHA-1')
policy = base64.b64encode(policy)
policy = policy.decode("utf-8")
signature = base64.urlsafe_b64encode(signed)
signature = signature.decode("utf-8")
policy = policy.replace("+", "-")
policy = policy.replace("=", "_")
policy = policy.replace("/", "~")
signature = signature.replace("+", "-")
signature = signature.replace("=", "_")
signature = signature.replace("/", "~")
print("%s?Expires=%s&Signature=%s&Key-Pair-Id=%s" % (url,expires, signature, key_pair_id))
When I test the file on lambda I am able to produce and print a URL but when I access the URL I receive an access denied error message from the XML file.
I am not sure what I am doing wrong at this point. To test if I am able to generated any SignedUrl I created a node.js lambda in which I am successfully able to generate the URL and even access my page.
<Error>
<Code>AccessDenied</Code>
<Message>Access denied</Message>
</Error>
After many failed tries to make my code work I decided to go with a different approach and used node.js to fullfill my needs. The code below works perfectly and I am able to generate signed url's
For now I used a hardcoded time value to test my code and will later on work on getting that dynamically using datetime.
var AWS = require('aws-sdk');
var keyPairId = 'myKeyPairId';
var privateKey = '-----BEGIN RSA PRIVATE KEY-----' + '\n' +
'-----END RSA PRIVATE KEY-----';
var signer = new AWS.CloudFront.Signer(keyPairId, privateKey);
exports.handler = function(event, context) {
var options = {url: "https://notYourUrl.com/example.html", expires: 1621987200, 'Content-Type': 'text/html'};
//console.log(options);
const cookies = signer.getSignedCookie(options);
const url = signer.getSignedUrl(options);
console.log("Printing URL "+url);
console.log(cookies);
};

Python RSA key, recieved the key but getting error "This is not a private key"

code for cilent
import socket, json
from Cryptodome.Cipher import PKCS1_OAEP, PKCS1_v1_5
from Cryptodome.Random import get_random_bytes
from Cryptodome.PublicKey import RSA
def getnewsocket():
return socket.socket(socket.AF_INET, socket.SOCK_STREAM)
clientsocket = getnewsocket()
clientsocket.connect(('localhost', 8089))
rsa_public = clientsocket.recv(99999)
encyrpted = clientsocket.recv(99999)
print(rsa_public)
rsakey = RSA.import_key(rsa_public.decode())
print(rsakey)
cipher = PKCS1_OAEP.new(rsakey)
decrypted = cipher.decrypt(encyrpted)
print(decrypted)
code for server
from Cryptodome.Cipher import PKCS1_OAEP, PKCS1_v1_5
from Cryptodome.Random import get_random_bytes
from Cryptodome.PublicKey import RSA
import socket
import json
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serversocket.bind(('0.0.0.0', 8089)) # 0.0.0.0 is a special address
print("Server activated, waiting for client to connect")
serversocket.listen(5)
connection, address = serversocket.accept()
rsakey_pair=RSA.generate(2048)
rsa_private = rsakey_pair
rsa_public = rsakey_pair.publickey().export_key()
hi = b"this is a plain text"
print(rsa_public)
cipher = PKCS1_OAEP.new(rsa_private)
encyrpted = cipher.encrypt(hi)
connection.sendall(rsa_public)
connection.sendall(encyrpted)
tried alot of ways but is either getting bytes cannot be n or this is not a private key. Always unable to decrypt the content of ciper text at client. I guess the error is something related to socket only can send bytes, so when the key had send through the socket, although it is still in bytes but is a different kind of bytes
error :
File "C:\Users\shang\AppData\Local\Programs\Python\Python37-32\lib\site-packages\Cryptodome\Cipher\PKCS1_OAEP.py", line 171, in decrypt
m_int = self._key._decrypt(ct_int)
File "C:\Users\shang\AppData\Local\Programs\Python\Python37-32\lib\site-packages\Cryptodome\PublicKey\RSA.py", line 151, in _decrypt
raise TypeError("This is not a private key")
TypeError: This is not a private key
Well, yes, that's because it is a public key.
rsakey = RSA.import_key(rsa_public.decode())
cipher = PKCS1_OAEP.new(rsakey)
decrypted = cipher.decrypt(encyrpted)
It is not possible to encrypt with a private key by definition. Encryption is performed using the public key, decryption using the private key. Public and private keys are not interchangeable for RSA. Maybe you want to generate a signature instead?
The only reason why the encryption with the private key succeeds is that it is likely that it also contains the public exponent and therefore the public key. Of course, the public key doesn't contain the private key as that needs to be kept private.
Note that even if it would be secure to encrypt with a private key if both keys (and thus the modulus) are kept private then you might as well use symmetric encryption, e.g. using the hash over the modulus as AES key.

How to realize this js encrypt script in python?

Recently I am doing something like auto-login with python, but i am a freshman in this area.
I want to login to www.jd.com, and after fetch the post data with Chrome, I found this
uuid:37ac1f08-0ed9-4e0d-a424-76c31d566915
eid:ZLTFMPUYPUVH3AQWGB3I4YEJ5YR4EQLSXV7YKAX27FNOY3CPTY37EVDW755A2DUGP6GKOFADCU7JKKYCAMYM3QHAS4
fp:b871dc2da5cf2bf85a6a5a56259e28e3
_t:_ntscXrr
loginType:f
loginname:xxxxxxx
nloginpwd:RAc2wPFCr7jwP5ocHh295pGBuZL9xUYzlWh108xqsp6o90x6KiHVTbw3Yn6NRz8YMDp%2BOHlT58oinO%2FuLwvysmD3XKazm0MYEulWseG2gotduYTywA6%2FrO1hUskfVjHuPoLu8r3stjNRQ0dnKF%2BvIxganMiDEUTiUmliAGQqnWc%3D
chkRememberMe:
authcode:
pubKey:MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDC7kw8r6tq43pwApYvkJ5laljaN9BZb21TAIfT%2FvexbobzH7Q8SUdP5uDPXEBKzOjx2L28y7Xs1d9v3tdPfKI2LR7PAzWBmDMn8riHrDDNpUpJnlAGUqJG9ooPn8j7YNpcxCa1iybOlc2kEhmJn5uwoanQq%2BCA6agNkqly2H4j6wIDAQAB
sa_token:B68C442BE645754F33277E701208059007998C0A52BF7A8EAD6AD256C8D009D929F000C9DF4192A57234E3EA6F615E156C81EFA53D580517BB9357FB9516A01E25761124AE9AF7B3CFA3C38D38484A73343117232D8C7101034817F5DC7B6F52055B86745C3B42647752AEED916BA60EBBC84732E823766B234DC3A36C47691794488C0EAF9A459DC55C70B43B5F9AE3A233810AAC8D52FE65CB29B0C97A162039D4626DD8AFF4ECE8ABDB2411B3D4509C293CD344C3BAF14F059FF462D18C8761724FAF12E2BF3C590E14AE8198C7542C8A575F7FAD5B021BC1A4C852AB71E972157546E442CF0E9E7ABA667A02DD8386375595080A9E9A1B232DCE0944244FDC6AB4A499CC881E1BB8BA47831877F6AD6CF02FFF5671C60461E90517D1761B40FD6CA361677595F096C4E5250D72FDCC6E1FF89771AE1B0F1C89B7DCAFB88BD6F068F47850A7EBC747F35939552C7E32B28E6D347D5AEB78B9334779D4896431CCA166537C67690687B1DDA7CC9881914D2A9F25CAF2B80EB8E2D0DFED09EBB766287A6E34179DCC9530DF3D4FCD28C17845571E587FFA3FD0B69E3ACBC80FCBCE115EFD6CBC87BB8ED4D95AAAA680
seqSid:1777115819395099100
Here the password is encrypted, and later I found this js code
function getEntryptPwd(pwd){
var pubKey = $('#pubKey').val();
if(!pwd || !pubKey || !SysConfig.encryptInfo){
return pwd;
}
var encrypt = new JSEncrypt();
encrypt.setPublicKey(pubKey);
return encrypt.encrypt(pwd);
}
However, I don't know how to do the same thing in python, could anyone please tell me how to this?
Any suggestion would be greatly appreciated.
here is my way to encrypt the password using pubkey you get from the html.
Request the login url to get the pubkey (also other informations).
Install a third-party module rsa.
pip install rsa
Run the following script to encrypt your password based on pubkey.
And you can find my code here. :)
<input type="hidden" name="pubKey" id="pubKey" value="MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDC7kw8r6tq43pwApYvkJ5laljaN9BZb21TAIfT/vexbobzH7Q8SUdP5uDPXEBKzOjx2L28y7Xs1d9v3tdPfKI2LR7PAzWBmDMn8riHrDDNpUpJnlAGUqJG9ooPn8j7YNpcxCa1iybOlc2kEhmJn5uwoanQq+CA6agNkqly2H4j6wIDAQAB" class="hide"/>
(admin) $ cat encrypt.py
import rsa
import base64
import os
def bytes2hex(s):
return s.decode()
def bytes2base64(s):
return bytes2hex(base64.standard_b64encode(s))
class RSA():
def __init__(self):
# self.pubkey = self.load_pub_key(pubkey) if pubkey else None
self.pubkey = None
pass
def form_pem_pub_key(self, keystr,):
"""
Fortmat a public key string to PEM format, in which start with
BEGIN PUBLIC KEY and end with END PUBLIC KEY.
Parameters:
keystr -- the public key string of PEM-encoded(base64)
Returns:
-- Formatted public key string
"""
import textwrap
line_len = 64
begin = ['-----BEGIN PUBLIC KEY-----']
end = ['-----END PUBLIC KEY-----']
return '\n'.join(begin + textwrap.wrap(keystr, line_len) + end)
def check_pem_key_str(self, keystr,):
return False
pass
def load_pem_pub_key(self, pubkey,):
if isinstance(pubkey, str):
keystr = pubkey if self.check_pem_key_str(pubkey) else self.form_pem_pub_key(pubkey)
self.pubkey = rsa.PublicKey.load_pkcs1_openssl_pem(keystr)
def encrypt(self, msg):
if not self.pubkey:
raise ValueError('Pubic key is empty, please load it first.')
# convert string or other type to bytes
msg = msg if isinstance(msg, bytes) else str(msg).encode()
return bytes2base64(rsa.encrypt(msg, self.pubkey))
def encrypt_password(pubkey, password):
rsa = RSA()
rsa.load_pem_pub_key(pubkey)
return rsa.encrypt(password)
password = 'test'
pubkey = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDC7kw8r6tq43pwApYvkJ5laljaN9BZb21TAIfT/vexbobzH7Q8SUdP5uDPXEBKzOjx2L28y7Xs1d9v3tdPfKI2LR7PAzWBmDMn8riHrDDNpUpJnlAGUqJG9ooPn8j7YNpcxCa1iybOlc2kEhmJn5uwoanQq+CA6agNkqly2H4j6wIDAQAB'
print(encrypt_password(pubkey, password))
(admin) $ python encrypt.py
nQJvsRspY+zAnywU9YsSTNHb/OoNOLLbADsenBwOlDHnv//UUPpBidA4n4pN7Frm0iIRQAJT1hRNAu/tASZjihtWiOYuwD+XFos2Tmk+SLRIc6VvqvAL9CJFLrzbIS3tgbx9vkyM30Qy6ENFOyOcpR7nV93xY82F1dB7bRsuNGU=

Resources