Python is a great programming language for data analysis, web development, networking and more. While working with data , storing in files, sending to a remote machine and so on, we sometimes need to encrypt the data to prevent unauthorised access.
With python cryptographic packages we can encrypt and decrypt data using various methods , we can also sign data, create hash , use secure communication and more. In this post I’m using PyCrypto package but there are more packages you can use to do the same (less or more)
Installing PyCrypto
# pip install pycrypto
PyCrypto package supports encryption and decryption with symmetric and asymmetric algorithm , hashing with various methods, digital signature, random numbers and more.
Symmetric Encryption
The simplest way to encrypt and decrypt data is to use a symmetric encryption. We need to create a key for any pair. To encrypt and decrypt the data we use the same key:
Plain Text + Key ==> Cipher Text
Cipher Text + Key ==> Plain Text
It is very easy to create a new symmetric algorithm , for example – change every second bit (1 => 0 , 0 => 1) . The big challenge is to create algorithm that will not simply hacked.
Generally a good algorithm should be easy to use (encryption and decryption) and hard to hack
Example – AES
To use AES we need to create Key and IV (initalization vector). the Key is shared between the pair , The IV can be different for each message.
from Crypto.Cipher import AES key = b'ABCDEFGHIJ123456' iv = b'1234567890ZYXWVU' cipher = AES.new(key, AES.MODE_CFB, iv) data = 'hello world' msg = iv + cipher.encrypt(data)
Now the other side need the key to decrypt the message using the same Key and IV:
plain=cipher.decrypt(msg) print (plain[16:])
We skip the IV to print the data
Other symmetric algorithms available in PyCrypto are DES, 3DES, RC2, RC4 and more – see Crypto.Cipher module documentation for details
Asymmetric Encryption
The big problem with symmetric encryption is how to share the keys between each pair. We can’t send it over the network in plain text because any “men in a middle” can read it. We need a secure way to exchange the keys.
Asymmetric encryption works with 2 keys for each side – private key that we need to save and never send it to anyone and public key that we can publish anywhere. The data that we encrypt with one key can only be decrypted with the other key so if someone wants to send me a message , he encrypt the message with my public key, to decrypt it back i need to use my private key
Example – RSA
Every user has a private and public key pair , minimum 512 bit. To generate key pair we need:
- Choose 2 prime numbers (big) : Q, P
- N = Q * P
- Maximum message length we can encrypt is log(N)
- Z = (P – 1) * (Q – 1)
- Find E coprime to Z (that is gcd(Z,E) = 1)
- Find D such as D*E=1 mod Z
- E and D are the private and public keys
- Encrypt using (message ^ E) mod N
- Decrypt using (message ^ D) mod N
Example with numbers (very simple):
- P=5
- Q=11
- N = P*Q =55
- k<log(55) = 5 – maximum message length is 5 bit
- Z=(P-1)*(Q-1)=40
- E=13
- D=37
- D*E=481 => 481 mod 40 = 1
If we want to send the message ‘11010’ (26)
- We are using the public key (13)
- 26^13 mod 55 = 31 (‘11111’)
- send ‘11111’ to the other side
- The other side has the private key (37)
- 31^37 mod 55 = 26
Using PyCrypto
First we generate the key pair
from Crypto.PublicKey import RSA key = RSA.generate(2048)
export the public key to pem file and send it to the other side:
f = open('mykey','w') f.write(key.exportKey('OpenSSH')) f.close()
The other side open the file and encrypt data to send:
f = open('mykey.pem','r') clientkey = RSA.importKey(f.read()) encdata = clientkey.encrypt("hello python",10)
To decrypt encdata to plain text use:
t=key.decrypt(encdata) print (t) # hello python
Hashing
Hashing is “one way” algorithm. You can produce hash from data but you can’t do the opposite. Hashing is useful if we want to make sure the source was not tampered. For example , if you download a package from the web, you can check the hash and compare it with the reported hash provided by the author. If someone changed the package the hashing will be different
For example, if you want to download the Linux kernel source , we want to make sure that the hacker didn’t change the original code and made a security hole to help him attack the product later. So we can download also the hashing file and check the source to see the both equal
You need to download the pgp file and compare it with the generated hash
To use hashing with PcCrypto choose one of the supported algorithms: SHA, MD5 and more
Example
from Crypto.Hash import SHA256 h=SHA256.new() h.update('hello') h.hexdigest()
Digital signature
If A wants to send data to B, he need to encrypt it using B public key. The problem we need to solve is – how B can be sure he got the message from A? The solution is signing the message with A private key:
- Encrypt the message with B public key
- Encrypt the result with A private key
- Send to B
- B uses A public key to decrypt the message and then its private key to get the plain text
To use digital signature with PyCrypto use DSA class
from Crypto.Random import random from Crypto.PublicKey import DSA from Crypto.Hash import SHA message = "Hello" key = DSA.generate(1024) h = SHA.new(message).digest() k = random.StrongRandom().randint(1,key.q-1) sig = key.sign(h,k) if key.verify(h,sig): print ("OK") else: print ("Incorrect signature")
10 thoughts on “Python – Basics of Cryptography and API”
Comments are closed.
[…] Python – Basics of Cryptography and API […]
In the RSA pycrypto Example you are saving the public key to a file and it is used for encrypt. But I am not seeing any private key you saved in to any file. Once the keys are generated only we will do encrypt and decrypt using keys. every time we will not generate keys.. Can you explain me how to save a private key and use it while decrypting.
You can use different export format (not OpenSSH) and you will get also the private key but if you want 2 different files do the following:
# export private and public keys
f = open(‘bothkeys.pem’,’w’)
f.write(key.exportKey(‘PEM’))
f.close()
# export only public key
f= open(‘onlypublic.pem’,’w’)
f.write(key.publickey().exportKey(‘PEM’))
f.close()
now send the file onlypublic.pem to anyone you want
The PyCrypto is not maintained anymore, please don’t advertise this package! It is not only old but also broken, read https://nvd.nist.gov/vuln/detail/CVE-2013-7459
Use proper maintained and future proof Python packages like cryptography (https://cryptography.io/) or pycryptodome (https://www.pycryptodome.org/en/latest/).
i didn’t advertise PyCrypto, just used it to demonstrate cryptography
It’s 2018 and you make a tutorial on a package that’s been dead since 2014. That sucks. 🙁
the post is more about cryptography and not about the package.
The section on digital signatures in the explanation (but not code sample) performs an encryption step using the pk which just muddies the explanation a bit as its not signing.
Normally you’d sign and then encrypt anyway. but that’s by the by. to sign you would create a digest and encrypt it using the private key using a padding scheme e.g. pkcs#2.1
The encryption uses rsa but the signature example uses dsa without explaining dsa. why not show a rsa signature.
also this is a deprecated library as others have stated.
GreAT POST! Thanks!!
Let me know what you think.