Public key cryptography, ** Roman **, isn't it (personal impression) </ sub>? It seems that you can do something fun, such as incorporating it into personally developed software, apart from its practicality.
However, as far as I googled roughly, ~~ I want to copy and paste script kiddies like myself ~~ I couldn't find any implementations that were extremely simple on the simple side, so for practice. just made it.
I thought that about 5% could be considered practical, so I will write it simply in Python and C #, and exchange encrypted data between the two. If this can be done, for example, data encrypted on the client side (C #) can be decrypted on the server side (Python), so it can be put to practical use, although it is a little.
** I don't say there is a better way to put it to practical use. ** **
With Anaconda, it's easy because it contains almost everything and an encryption module.
If you want to start with Python alone, install pycrypto. [^ 1]
[^ 1]: There are multiple modules with the same function (and the function names are slightly different), which seems to be a source of confusion when searching. Here, we will use the one that comes standard with Anaconda.
cmd.exe
pip install -U pycrypto
.NET Core 3.0 or higher (.NET Framework 5.0 RC1) is required for some functions to apply .NET Standard 2.1.
CreateKey.py
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
key_length = 1024
def createKey():
key = RSA.generate(key_length)
private_key = key.exportKey().decode('utf-8')
with open(file="private.pem", mode="w", encoding='utf-8') as file_out:
file_out.write(private_key)
public_key = key.publickey().exportKey().decode('utf-8')
with open(file="public.pem", mode="w", encoding='utf-8') as file_out:
file_out.write(public_key)
This will generate the key. The variable key_length specifies 1024 or greater, but according to the Manual for Another Similar Module (https://pycryptodome.readthedocs.io/en/latest/src/public_key/rsa.html), it should be 2048 or greater. Recommended, 1024,2048,3072 should be one of them. [^ 2] This time it doesn't need to be long, so 1024.
The generated key is saved separately as a private key and a public key. [^ 3]
[^ 2]: pycrypto manual is 404, where is the original?
[^ 3]: Actually, it seems that the public key data is also included in the private key file (?)
Read the public key file created in Python and try to encrypt the short sentence.
The sample is created by the console application (.NET Core 3.1).
main.cs
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
class Encrypt_sample
{
static void Main(string[] args)
{
const string message = @"This is test message!";
const string key_begin = "-----BEGIN PUBLIC KEY-----\r\n";
const string key_end = "\r\n-----END PUBLIC KEY-----";
string public_key = File.ReadAllText(@"public.pem");
public_key = public_key.Replace(key_begin, "").Replace(key_end, "");
var publicKeyBytes = Convert.FromBase64String(public_key);
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
rsa.ImportSubjectPublicKeyInfo(publicKeyBytes, out _);
byte[] encrypted = rsa.Encrypt(Encoding.UTF8.GetBytes(message), false);
File.WriteAllText(@"encrypted.txt", Convert.ToBase64String(encrypted));
}
}
}
The variable message is the string to be encrypted.
After reading the public key file public.pem created on the Python side, it is converted to bytes after removing the header and footer, and read into the RSACryptoServiceProvider type variable rsa with ImportSubjectPublicKeyInfo (). [^ 4]
[^ 4]: There is a function called ImportRSAPublicKey (), but this is the correct answer.
After that, encrypt the message converted to a byte string with Encrypt () and save the base64 converted text. The conversion is done so that it can be read as a text file.
If the second argument of Encrypt () is set to false, PKCS # 1 v1.5 padding will be used.
In the assumed situation, encryption is done on the C # side, but create a function so that you can confirm that encryption / decryption is possible even on Python.
Encrypt.py
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
message = R"This is test message!"
def encrypt():
with open(file="public.pem", mode='rb') as file_read:
public_pem = file_read.read()
public_key = RSA.importKey(public_pem)
public_cipher = PKCS1_v1_5.new(key=public_key)
encrypted = public_cipher.encrypt(message=message.encode())
with open(file="encrypted.txt", mode='w', encoding='utf-8') as w:
w.write(base64.b64encode(encrypted).decode('utf-8'))
As an actual work,
is.
The last is decryption.
Decrypt.py
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
def decrypt():
with open(file="private.pem", mode='rb') as file_read:
private_pem = file_read.read()
private_key = RSA.importKey(private_pem)
private_cipher = PKCS1_v1_5.new(key=private_key)
with open(file="encrypted.txt", mode='r', encoding='utf-8') as r:
encrypt_data = base64.b64decode(s=r.read())
decrypt_data = private_cipher.decrypt(ct=encrypt_data, sentinel="")
print(decrypt_data.decode('utf-8'))
If the character string displayed by the last print () is the same as the message when it was created in C #, the decryption is successful.
It's a frank impression that the code is shorter than I expected and it can be managed. ** I am surprised to find that it is relatively easy to encrypt / decrypt across languages by skipping detailed settings such as error handling, actual security, and practical encryption strength.
Please note that the ** code is really appropriate and should not be put to practical use. ** **
--General error handling --This and that about signatures --Higher encryption strength setting -* A strong heart that you can believe it's okay to implement this way *
Q&A
--Q: Why is there no key creation and decryption on the C # side?
→ Decryption aside (Is the private key deposited on the assumed client side?), And the key creation was a pass because the output to a format that can be shared was slightly troublesome. I will add if there is a good means.
Recommended Posts