How to implement data encryption with the server's public key on a website that provides HTTPS?
Occasionally, when diagnosing mock hacking on a mobile app or website, there are cases in which the data is encrypted with a random symmetric key method and transmitted to the server without encrypting the data using the public key of the server.
From an attacker's point of view, the most symmetric key schemes have the key on the client, so decrypting attack it is only a matter of time.
In some cases, the key is simply base64-encoded, shift, or XOR, making decryption very easy from the attacker's point of view. These vulnerabilities are not uncommonly discovered for a very long time.
As you know, an important factor to consider when encrypting data is key management.
Key management includes generating and storing keys, exchanging keys safely, and countermeasures in case of key loss (key change management).
Here, we will show you a simple Python example code of how to extract the public key from the server's certificate, encrypt data with this public key, and send it to the server, without bringing the symmetric key to the client to avoid the burden of key management.
The simple Python code below is an example of encrypting data using the public key of the server on the client and sending it to the server.
EXAMPLE CODE
The simple Python code below is an example of encrypting data using the public key of the server on the client and sending it to the server, and this code is a sample that prevents the decryption key from being exposed to attackers by using a separate private key.
- Since this code is an example, you need to add a part that verifies the validity of the certificate when applying it in practice. You should write this part yourself, right? ^^
- The reason why the encrypted data in the code is encoded with base64 is to control the length of the data.
- The test website https://check-host.net/ip-info is for checking data on the server.
- In a situation where it is unavoidable to encrypt a key by downloading it to the client using a symmetric key method, it is common to encrypt the symmetric key with the server's public key and send it down.
Import ssl
import socket
import requests
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.serialization import load_pem_public_key
from cryptography import x509
from cryptography.hazmat.primitives.asymmetric import dsa, rsa
from cryptography.hazmat.primitives import hashes
import base64
hostname = 'sample.net'
port = 443
print("Enter a value to encrypt")
plain_text = input()
context = ssl.create_default_context()
with socket.create_connection((hostname, port)) as sock:
with context.wrap_socket(sock, server_hostname=hostname) as ssock:
# Extract the server's public key from the SSL/TLS certificate
pem_cert = ssock.getpeercert(binary_form=True)
cert = ssl.DER_cert_to_PEM_cert(pem_cert)
public_key_pem = cert.split("\n")[:-1]
public_key_pem = ''.join(public_key_pem)
# Load the public key into an RSA object
publickey = x509.load_pem_x509_certificate(public_key_pem.encode())
publickey = publickey.public_key()
# Encrypt the plain text using the server's public key
plain_text = plain_text.encode('utf-8')
cipher_text = publickey.encrypt(
plain_text,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA1(),
label=None
)
)
# Print the encrypted cipher text
datas = {
'enc' : base64.b64encode(cipher_text).decode()
}
url = "https://sample.net/test.php"
#Steps for 1,2,3
print("1. input plain text : " + plain_text.decode())
print("2. python encrypt cipher_text with base64 : " + base64.b64encode(cipher_text).decode()) print("3. post body : " + str(datas))
response = requests.post(url, data= datas)
#Steps for 4,5,6
print(response.text)