AES encryption error: The input data is not a complete block - python-3.x

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.

Related

ValueError: Invalid password or PKCS12 data when retrieving certificate with a password from azure key vault

I'm writing code to retrieve certificate (as key, cert) from Azure Key Vault. The code runs perfectly when i remove the password from the certificate. How can i make it work with a password for example: abc()^WER123.
I've already tried several methods for decoding the password, transforming to bytes, using hashes.SHA256 as kdf algorithm. Nothing works.. It gives me this error:
"ValueError: Invalid password or PKCS12 data"
Here my latest code:
import base64
from azure.identity import ClientSecretCredential
from azure.keyvault.certificates import CertificateClient
from azure.keyvault.secrets import SecretClient
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.primitives.serialization import pkcs12
def get_keyCert_fromKeyVault():
TENANT_ID = ''
CLIENT_ID = ''
CLIENT_SECRET = ''
KEYVAULT_NAME = ''
KEYVAULT_URI = f"https://{KEYVAULT_NAME}.vault.azure.net/"
credential = ClientSecretCredential(
tenant_id=TENANT_ID,
client_id=CLIENT_ID,
client_secret=CLIENT_SECRET
)
#get certificate from vault
certificate_client = CertificateClient(vault_url=KEYVAULT_URI, credential=credential)
certificate = certificate_client.get_certificate("cert_name")
#get certificate from secret id of the cert.
secret_client = SecretClient(vault_url=KEYVAULT_URI, credential=credential)
certificate_secret = secret_client.get_secret(name=certificate.name)
cert_bytes = base64.b64decode(certificate_secret.value)
password_provided =b'abc()^WER123'
salt = os.urandom(16)
kdf = PBKDF2HMAC(
algorithm=hashes.SHA1(),
length=64,
salt=salt,
iterations=480000,
backend=default_backend()
)
password = base64.urlsafe_b64encode(kdf.derive(password_provided))
private_key, public_certificate, additional_certificates =
pkcs12.load_key_and_certificates(
data=cert_bytes,
password=password
)
return private_key, public_certificate
Please Help!
Thanks in advance
I have followed the below steps to retrieve the certificate from the Azure key vault.
Step 1: Create Azure key vault and upload certificates to it.
Step 2: Setup python and run below code to retrieve certificates.
import os
import base64
import requests
import json
KEY_VAULT_URL = "https://<keyvault-name>.vault.azure.net"
TENANT_ID = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
CLIENT_ID = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
CLIENT_SECRET = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
CERT_NAME = "testcert010203"
def get_access_token():
auth_url = f"https://login.microsoftonline.com/{TENANT_ID}/oauth2/v2.0/token"
auth_data = {
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET,
"grant_type": "client_credentials",
"scope": f"https://vault.azure.net/.default"
}
response = requests.post(auth_url, data=auth_data)
response.raise_for_status()
return response.json()["access_token"]
def get_certificate(access_token):
"""Get the certificate from Azure Key Vault."""
cert_url = f"{KEY_VAULT_URL}/certificates/{CERT_NAME}?api-version=7.0"
headers = {
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json"
}
response = requests.get(cert_url, headers=headers)
response.raise_for_status()
return response.json()
if __name__ == "__main__":
access_token = get_access_token()
cert_data = get_certificate(access_token)
print("Certificate data:")
print(json.dumps(cert_data, indent=4))
Step 3: Verify the certificate in the output.

AEAD AES-256-GCM in Node.js

How to decrypt data encrypted by other languages with Node.js?
To describe the problem, we write some code in Python:
plain_text = 'some data'
nonce = 'some nonce string'
associated_data = 'some associated data'
key = '--- 32 bytes secret key here ---'
encrypting in python
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import base64
aesgcm = AESGCM(key.encode())
encrypted = aesgcm.encrypt(nonce.encode(), plain_text.encode(), associated_data.encode())
print(aesgcm.decrypt(nonce.encode(), encrypted, associated_data.encode()))
ciphertext = base64.b64encode(encrypted)
Decrypting in Node.js, we don't need additional dependencies.
The crypto module has implemented GCM algorithm, but it is different in concept.
const crypto = require('crypto')
encrypted = Buffer.from(ciphertext, 'base64')
let decipher = crypto.createDecipheriv('AES-256-GCM', key, nonce)
decipher.setAuthTag(encrypted.slice(-16))
decipher.setAAD(Buffer.from(associated_data))
let output = Buffer.concat([
decipher.update(encrypted.slice(0, -16)),
decipher.final()
])
console.log(output.toString())

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))

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.

Create RSA Token in nodejs

I'm trying to authenticate to a REST API using encryption.
First I need to call the API to get an encryptionKey and a timestamp.
The encryptionKey is in Base 64 format.
Then I need to create a RSAToken using the key and finaly encrypt the password using password + "|" + timestamp.
This is some sample code using python to authenticate to the API
key, timestamp = get_encryption_key()
decoded_key = key.decode('base64')
rsa_key = RSA.importKey(decoded_key)
encrypted = rsa_key.encrypt(password + '|' + str(timestamp), 'x')
encrypted_password = encrypted[0]
and
import base64
from Crypto.PublicKey import RSA
r = requests.get(my_url, headers=headers)
myData = r.json()
decoded = base64.b64decode(myData['encryptionKey'])
key = RSA.importKey(decoded)
enc = key.encrypt(password + '|' + str(myData['timeStamp']), 'x')
encryptedPassword = enc[0]
session = "/session"
my_url = url + session
payload = {"identifier": identifier,
"password": encryptedPassword,
"encryptedPassword": "True"
}
Any hints to achieve this under Node?
You can use crypto.publicEncrypt to encrypt your password. Notice the padding, you might want to use the right padding that is being used in your Python script.
const crypto = require('crypto');
const constants = require('constants');
const decodedKey = Buffer(encriptionKey, 'base64').toString();
const encryptedPassword = crypto.publicEncrypt({
key: decodedKey,
padding : constants.RSA_PKCS1_OAEP_PADDING
} , Buffer(`${password}|${timestamp}`));
Check out this node.js test to find out more examples for different padding.

Resources