📜 ⬆️ ⬇️

Cryptography in simple language: parse symmetric and asymmetric encryption on the example of the Star Wars plot (Updated)

Hello to all readers of Habr! Not so long ago, I decided to deal with encryption algorithms and electronic signature principles. The topic, I think, is interesting and relevant. In the process of learning I tried several libraries, but the most convenient from my point of view is the PyCrypto library. She has excellent documentation, accompanied by examples.

image

After reading the material you learn the following points:
')
  1. What is encryption;
  2. What distinguishes symmetric encryption from asymmetric;
  3. In which case it is more efficient to use symmetric, and in which asymmetric encryption;
  4. What is a data hash and what is it used for in encryption;

The relevance of the topic is constantly growing. The use of cryptography has long been not limited to encrypting information. Encryption algorithms in one form or another are used daily by us when visiting sites via the HTTPS protocol, when making purchases with a bank card, and when communicating in instant messengers. Over the past few years, blockchain technologies, which are also based on cryptography, have received wide attention.

The purpose of this article is to acquaint the reader with the basic encryption algorithms. When writing an article, I tried to give as much attention as possible to the question of practical application. Python 3.6 was used for programming. When writing code, I tried to divide it into separate parts and comment on all key points.

In this article, I did not understand the digital signature, but after understanding asymmetric encryption, the meaning of this technology will become clear.

Plot


Let us mentally transfer to the Star Wars universe before the events of Episode 6, when the resistance forces become aware of the start of building a new Death Star. The command plans to introduce a reconnaissance group under the guise of builders. The operation is very dangerous, communication with the headquarters will be difficult. In the case of emergency Stew, each member of the group can send and receive messages from headquarters on an unprotected frequency.

The purpose of the reconnaissance group is any data that can shed light on the configuration, weaponry and designation of the future station. For data storage it is planned to develop special equipment and software.

The headquarters approved two variants of this operation:

Plan A - returning agents with data to rebel forces;
Plan B - remote transmission of plans from the Death Star itself, using the equipment of the station. The transfer of information in this case will be fast, but after the transfer, the agent is likely to be calculated and caught.

Scheme
image

You are a programmer in a team that is responsible for software development.

When planning an operation, several possible negative scenarios are considered:


Of these scenarios, the tasks are modeled:

  1. Content must be securely encrypted and protected from changes;
  2. In the case of loss of encryption keys or their compromise, it should be possible to obtain new encryption keys remotely at a frequency that can be heard by the enemy.

Information encryption


Let's solve the problem of encrypting information:

Encryption key is used to encrypt and decrypt information. It is the key that makes encryption reversible. Each agent will be provided with an encryption key. After downloading the data, the agent will encrypt it and send it to the resistance headquarters.

Description of encryption principle
The method by which encryption and decryption of a message is performed using a single key is called symmetric encryption .

image

The weak point of symmetric encryption is the encryption key, or rather its delivery to the addressee. If the key is compromised during delivery, the third party will easily decode the message. The strength of symmetric encryption is its speed, which makes it possible to encode large amounts of data.

Asymmetric encryption to encrypt data uses two interconnected keys: public and private.

image

The mechanism of action is as follows:

  1. the addressee sends the OPEN key to the sender;
  2. The sender encodes the message using the received public key. At the same time, the message can now be decoded only by the private key;
  3. when receiving an encrypted message, the recipient decodes it with a CLOSED key (which was generated in a pair with an open one).


Let's get started in programming! To develop the necessary software, we will use the Python library called pycrypto . She has excellent documentation and presents all common encryption algorithms.

To begin with, we will develop a functional for symmetric encryption called Advanced Encryption Standard (AES) . It is one of the most common symmetric encryption algorithms.

from Crypto.Cipher import AES #   from Crypto.Hash import SHA256 #        SHA. from Crypto.Hash import MD5 #            32  from Crypto import Random def transform_password(password_str): """Transform the password string into 32 bit MD5 hash :param password_str: <str> password in plain text; :return: <str> Transformed password fixed length """ h = MD5.new() h.update(key.encode()) return h.hexdigest() def symmetric_encrypt(message, key, verbose = True): """Encripts the message using symmetric AES algorythm. :param message: <str> Message for encryption; :param key: <object> symmetric key; :return: <object> Message encrypted with key """ key_MD5 = transform_password(key) #      32  message_hash = SHA256.new(message.encode()) message_with_hash = message.encode() + message_hash.hexdigest().encode() #     .      iv = Random.new().read(AES.block_size) cipher = AES.new(key_MD5, AES.MODE_CFB, iv) #     . AES.MODE_CFB -   ,      iv. https://www.dlitz.net/software/pycrypto/api/current/Crypto.Cipher.blockalgo-module.html#MODE_CFB encrypted_message = iv + cipher.encrypt(message_with_hash) #       .  ,       ,       . if verbose: print(f'Message was encrypted into: {encrypted_message.hex()}') return encrypted_message def symmetric_decrypt(encr_message, key): """Decripts the message using private_key and check it's hash :param encrypted_message: <object> Encrypted message :param key: <object> symmetric key; :return: <object> Message decripted with key """ key_MD5 = transform_password(key) #   ,      bsize = AES.block_size dsize = SHA256.digest_size*2 iv = Random.new().read(bsize) cipher = AES.new(key_MD5, AES.MODE_CFB, iv) decrypted_message_with_hesh = cipher.decrypt(encr_message)[bsize:] #     ,      decrypted_message = decrypted_message_with_hesh[:-dsize] #   ,      digest = SHA256.new(decrypted_message).hexdigest() #    .     ,     . if digest==decrypted_message_with_hesh[-dsize:].decode(): #      ,      ,   print(f"Success!\nEncrypted hash is {decrypted_message_with_hesh[-dsize:].decode()}\nDecrypted hash is {digest}") return decrypted_message.decode() else: print(f"Encryption was not correct: the hash of decripted message doesn't match with encrypted hash\nEncrypted hash is {decrypted_message_with_hesh[-dsize:]}\nDecrypted hash is {digest}") 

Check the code for example
 message = """  120   120  / 120   10     30-5 (2)    4.0 """ key = 'Traveling through hyperspace ain't like dusting crops, farm boy.' encr_message = symmetric_encrypt(message, key, verbose = True) print('\n') print('DECRIPTION') decr_message = symmetric_decrypt(encr_message, key) print(decr_message) 

 Message was encrypted into: ed10e4c65358bb9e351c801c3b3200b21fa86a24021c317bb5c9d8b3f76bdf9f3a7d26781a22402f0e4f41ca831b6d2da9e1e6878c34c79ddc7959af3ae9fc2ba0cfff1c0180a7e0f637f1aa5b24507d552d5dfe7625e7b81d817b5882b2b19bb95f3988a03c78f850098dfc8e6089863deaa39b887eaea4c1d4ba006edaec90205d54b27ed4ac70ed75cdd01732e1176bf04218beb8ae742ff708a201a9d1cb57dd5f2e70dc3239208d23705f7a3aae3e315c4df6d73c871b66c4995cce5f19738f731cd58755d21ed92612c44197f875cddf3f7aa1d60e435ce1492679b9d60c4b8538f52408f321711ac1d2daa6dbbc33dc655abca10e2f5fd3ff27823995b9dcdb62c0bafc1963ab539ccb466f1c140479df34b0005f578f72fcdd76b17391332037b801f74f733a08 DECRIPTION Success! Encrypted hash is b0dbb35b28fbff258350a50c39282b73e31f408c9da937c81d8d48115b491026 Decrypted hash is b0dbb35b28fbff258350a50c39282b73e31f408c9da937c81d8d48115b491026  120   120  / 120   10     30-5 (2)    4.0 


As you can see, we successfully encrypted the message with the public key.
Run the code several times. You will see that each time the encrypted part changes. This happens because during encryption, we applied the Cipher FeedBack (AES.MODECFB) mode, in which the plaintext blocks are mixed with the ciphertext blocks. iv - initialization vector (read more about the mode here ). When decrypting a message, we see that the hash of the decrypted message coincides with the hash that we added during encryption. This means that the decoding was correct.

What is a hash
A document hash is simply a string of characters that is unique to a particular dataset. With any change in the data hash is very much changed. In other words, a hash is a kind of “fingerprint” for any data set.



But what if the encryption keys are compromised for some reason? Then anyone can decipher the information.

In this case, we need to somehow change the encryption keys remotely in frequency, which can be heard by the enemy. We assume that it is already listening. So how do we do this? Here comes another method called asymmetric encryption (or a public key cryptographic system). Unlike symmetric encryption, it uses two keys: open and closed. The message is encrypted with the public key, after which it can only be decrypted with the private key. The public key in decryption will be useless. However, there is an important point: the private key must necessarily be from the generated pair with an open one. Having a public key is one of several important and interesting properties of asymmetric encryption. That is, we can transmit the public key by any channel and not be afraid that it will be used to decrypt the message.

At the same time, in relation to our task, there is one nuance - asymmetric encryption is suitable for small data, for example, short messages. We can only guess about the amount of data obtained by intelligence. Of course, we can break all the data into small fragments and encode each of them with a private key, but there is a more optimal solution. (The problem is addressed here ).

Decision

User Akela_wolf rightly noticed, anyone can generate and send the public key. I made some adjustments to the plan.

It will be correct if, before sending agents, the headquarters will generate several key pairs and assign a private key to each agent. It is better to generate just a few pairs, so that each agent has an individual key. This is necessary to precisely personalize the key owner.
Then, in the event of key compromise, the center will create a new SYMMETRIC key, encode it to each agent with public keys and send it through an open channel.
General solution scheme






Old solution
  1. The agent will generate a key pair (open and closed) in place, then send the public key to the rebel forces;
  2. At the headquarters of the resistance will create a new key for SYMMETRIC encryption;
  3. The symmetric key is encoded with the public key that the agent sent;
  4. The encrypted symmetric key will be sent to the agent who decodes it with the private key.

Pay attention to our broadcast on the open channel:

  1. The agent sends the OPEN key from the pair, the CLOSED key is with him;
  2. The headquarters of the resistance sends a symmetric encryption key, encrypted by the public key sent by the agent.


Neither the first nor the second message represent any value during the interception.


Write the code:

 #          RSA. #        SHA256 from Crypto.PublicKey import RSA #      def generate_keys(bits = 2048): """Generates the pair of private and public keys. :param bits: <int> Key length, or size (in bits) of the RSA modulus (default 2048) :return: <object> private_key, <object> public_key """ private_key = RSA.generate(bits) public_key = private_key.publickey() return private_key, public_key private_key, public_key = generate_keys(bits = 2048) 

Let's see what the keys look like.
 print(private_key.exportKey(format='PEM').decode()) print('\n') print('#'*65) print('\n') print(public_key.exportKey(format='PEM').decode()) 

-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA4JDLu7Vtvg2yqbH6Y0eJPfoEsOlKzgmOodqhA1CqkEG4OpKi
sGW7ciGP4v37GE6edHBCEy4UNkVQtnpPBjzTHvKd1pO70B84vD5OSrS7uNw2EYkj
d/ZwhrJMrcQKRwPkkM4OiewaaAaK0vPWJIKwlW61DY9X7LfNz7aOKMTbKnm1vdR0
919AV98FUmNoQBgka6nXFGmNbi7D43MtLwxBZIXfFupEiANSvOs+57hgaCho7OWM
GUOjLkG6HBscPhJ2W1H5DU9GjwL24ynTvKifgo1/2ue61MV1Pzh5CVaicJKNaRtg
Pd99gFhBGINsXV2X6Jh/W5nNsCddU4EI0AlO8wIDAQABAoIBAARM4YnjrIlSK9Sy
EtBp40frjMFyhjsx1ahlzmWI2utORt/gRPtJx3AlEmNPZ8qMXt5t8+X4IOz1INmN
uAuviH90N++O/q66mlSIgOlPUrT0ipiFXseCUZ9StMMzGNtJSMw5FfAwNEU/stLd
VoF2ezkxWIg88XsX/fn3Tfub4XKLvu4raJGcJ+Fo2GI9hYEGKnHhSuHvDHekTLlQ
z46O+cIwtehbFGcKesyK3zDD1uP5YLPIWpiqt1TgKjJzRF0l4ZJLk+RT7kU2pGIQ
mosOnr+06WyMIg724yQyAIwtS9X0czKBGUESrtTTb1HCXLeTwnncOTxh6q2z42LF
tn34+DECgYEA6EEp4oTvjfTQfUQPMByuAjF1hpdFHQqRymygiFgoF+Mg3QmL0w8j
/84H/q7s8FSx+3th8MK87bFq4lrry+h/mYwmvF5zZbhxcnl2uaX+KUPgpT6TgvAo
WOv2wc4BSaoo9DrxrZId86vpO2qbopw6gkBsvw47HSoQ+FSqXtZ0p8kCgYEA94Zj
b1ulctUjybiszO93TAjkzx3lU3yL+B1eZiQXtJa3mgG+ka1R/uMfr0NlT+Jzo0My
wHV30YRJDxziCrDol9OgSSU0sXwEcUxUIBLBwXLCp1EmMsYG9PB/x4OTWve35a8F
O+rMxuvWaZeIOfVCfL8UEcWweYaVdWIonJN+ltsCgYEAjeSZ2UlMLZce9RjqioNL
EA31dlfeoqJ9dYUuAn6RaB6cSk51vWlnnfXazo9CNIYaAsFbkcL3t+QHn+jaXEZc
BowocjbmG4Q20zBAB6XRBJbynSIA7yMYE1N9+uOHx+CMisGkO12krOUfZex4zzzR
RhhkF8ly9htoKL9ZIv20YXkCgYBzH3UF6PkVZJ5lhtgP5Nx2Z7iLwBrV7ppnBrnO
BcFkw6iXH3KT7KmzQ82LxWvMcMVZzLpBGyFkOAOG3OchE9DKNKpa+sv8NHMYguip
li+5mneAPFTozoOTznuPvtl9OLO2RuXHTVh6uFub9tdsJW8L+A8MiQagLwE6fDHp
SQxaewKBgQDIyzL1THpW3+AMNrOZuI/d3Em5wpGJiZbDSBRosvsfGm/sHaz4Ik5E
nWnftgktmsAD60eORTTh9/ww/nm7f3q9kzT8Sv1MmqeRXq9VFIOeP/+8SSE/7LzD
izlb5xEtVD8LuY54jHyiOxiZC++TQswMnOKKi0Gx26MDoO7Tx9akVw==
-----END RSA PRIVATE KEY-----

#################################################################

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4JDLu7Vtvg2yqbH6Y0eJ
PfoEsOlKzgmOodqhA1CqkEG4OpKisGW7ciGP4v37GE6edHBCEy4UNkVQtnpPBjzT
HvKd1pO70B84vD5OSrS7uNw2EYkjd/ZwhrJMrcQKRwPkkM4OiewaaAaK0vPWJIKw
lW61DY9X7LfNz7aOKMTbKnm1vdR0919AV98FUmNoQBgka6nXFGmNbi7D43MtLwxB
ZIXfFupEiANSvOs+57hgaCho7OWMGUOjLkG6HBscPhJ2W1H5DU9GjwL24ynTvKif
go1/2ue61MV1Pzh5CVaicJKNaRtgPd99gFhBGINsXV2X6Jh/W5nNsCddU4EI0AlO
8wIDAQAB
-----END PUBLIC KEY-----

As you can see, asymmetric encryption keys are long mathematically generated sequences of characters.

So we generated the keys. Now let's write a function to encode the data:

 from Crypto.PublicKey import RSA #        RSA. from Crypto.Hash import SHA256 #        SHA256.    #       from Crypto.Cipher import PKCS1_OAEP #   def encrypt_message(message, public_key, verbose = True): """Encripts the message using public_key. :param message: <str> Message for encryption :param public_key: <object> public_key :param verbose: <bool> Print description; :return: <object> Message encrypted with public_key """ message_hash = SHA256.new(message.encode()) #   . cipher = PKCS1_OAEP.new(public_key) message_with_hash = message.encode() + message_hash.hexdigest().encode() #      ,          encrypted_message = cipher.encrypt(message_with_hash) if verbose: print(f'Message: {message} was encrypted to\n{encrypted_message.hex()}') return encrypted_message def decrypt_message(encrypted_message, private_key): """Decripts the message using private_key and check it's hash :param encrypted_message: <object> Encrypted message :param private_key: <object> private_key :return: <object> Message decripted with private_key """ dsize = SHA256.digest_size*2 cipher = PKCS1_OAEP.new(private_key) decrypted_message_with_hesh = cipher.decrypt(encrypted_message) #   (  ) decrypted_message = decrypted_message_with_hesh[:-dsize] #      digest = SHA256.new(decrypted_message).hexdigest() #     if digest==decrypted_message_with_hesh[-dsize:].decode(): #      ,      ,   print(f"Success!\nEncrypted hash is {decrypted_message_with_hesh[-dsize:].decode()}\nDecrypted hash is {digest}") return decrypted_message.decode() else: print(f"Encryption was not correct: the hash of decripted message doesn't match with encrypted hash\nEncrypted hash is {decrypted_message_with_hesh[-dsize:]}\nDecrypted hash is {digest}") 

Steps to work
  1. The agent generates a pair of keys:
     private_key, public_key = generate_keys() 

  2. Sends an OPEN key to headquarters;
  3. In the headquarters using a public key encode the key for symmetric encryption:
     new_symmetric_key = 'SOME_KEY_asdfasdfasdfasdfsdfgrtwhetynt' encr_msg = encrypt_message(new_symmetric_key, public_key) 

    Conclusion
    Message: SOME_KEY_asdfasdfasdfasdfsdfgrtwhetynt was encrypted to
    41e940507c96397e3feb4a53390c982633bb1775a52957996a8069bd22063086a0e831bf775a17909276aba0d0478ee6c953837c8ea5d20d40e1c8eb463aaa1bc5c93c71677b1a85e90439c9dbda8a98ce168acb38368155437c66815b84aa2fbdda0eb909e4e6079b4410c720eddd955ed048193bf87f8f9976a17ee32a58a71dfddf3db116343d949d29c25f72c511a440a50a5d4f1e01c37b24a1cb4127e191d3231328b2f120c7dbd0cb5bf19823f0978b8ed17d25952de4b146ef9724fff359eb2af503fdfd72b91525a5503b076ba9aaaeac55af3f8d210c12d579d45dd70362123c0b4b36ef9c2f7705e6f884a25553eb0e11e5077f11fa986d0ff280


  4. This long sequence is sent back to the agent;
  5. The agent decrypts the received message using the private key:
     recieved_symmetric_key = decrypt_message(encr_msg, private_key) print('\n') print(f"New symmetric key is: {recieved_symmetric_key}") 

    Conclusion
     Success! Encrypted hash is 42ad66445a05ac09e684bb21f9b487d95b9cfa11d02e0b459931321ee02f7c1c Decrypted hash is 42ad66445a05ac09e684bb21f9b487d95b9cfa11d02e0b459931321ee02f7c1c New symmetric key is: SOME_KEY_asdfasdfasdfasdfsdfgrtwhetynt 


  6. Then, using a new symmetric key, the agent encrypts the received data:

     message = """  120   120  / 120   10     30-5 (2)    4.0 """ encr_message = symmetric_encrypt(message, recieved_symmetric_key, verbose = True) 

    Conclusion
     Message was encrypted into: 


  7. The headquarters produce decryption:
     print('DECRIPTION') decr_message = symmetric_decrypt(encr_message, new_symmetric_key) print(decr_message) 

    Conclusion
     DECRIPTION Success! Encrypted hash is b0dbb35b28fbff258350a50c39282b73e31f408c9da937c81d8d48115b491026 Decrypted hash is b0dbb35b28fbff258350a50c39282b73e31f408c9da937c81d8d48115b491026  120   120  / 120   10     30-5 (2)    4.0 




Voila!

In this abstract example, we saw the work of common encryption algorithms. Symmetric and asymmetric encryption, as well as hashing, are used in the work of the web , electronic signature , blockchain and cryptocurrencies . I hope the material was useful for understanding the work of these technologies.

Afterword


As a result, the rebel intelligence was able to obtain accurate information about the station’s vulnerability and the path to it, the presence of the Emperor for inspection, the presence of the power grid and its source on Endor. The empire figured out spies, misinformed them about the station’s combat capability. The station was also assigned to the satellite of Endor, from where it was protected by a shield.

But we know how it all ended;)

Source: https://habr.com/ru/post/452042/


All Articles