This article will explain how to encrypt and decrypt data with RSA algorithm using PKCS#1 v1.5 padding scheme.
Note:- RSA is no longer recommended to use, it is not intuitive to implement and there are much better methods to use https://blog.trailofbits.com/2019/07/08/fuck-rsa/
https://www.sjoerdlangkemper.nl/2019/06/19/attacking-rsa/
https://cryptosense.com/blog/why-pkcs1v1-5-encryption-should-be-put-out-of-our-misery/
code output here: https://github.com/fi1ingcabinet/OpenSSL_Python3_RSA.git
Prerequisites
I will use the following:
$ openssl version LibreSSL 2.6.5 $ python3 --version Python 3.7.6 (venv) $ pip freeze pycrypto==2.6.1
STEP 1:- Create a RSA private key
OpenSSL | Python |
---|---|
These both do the same thing, create one file each, we can then look at them in the OS like the following. They’re PEM formatted, Base64 encoded private keys.
$ cat openSSLPrivKey.pem
—–BEGIN RSA PRIVATE KEY—–
MIIEpAIBAAKCAQEA14soHedBsAjutu0a8aM/o1waROe+Mz/wYsF7vn0dAScdomN0
Xo4zj3Z7Ly2TImds0a92KZoG69RyyrnhAdwU4Es4gCZsR61cQ4Mb08oIl6ILNhGV
KJfKssSUbR2wXu4pFy/gMjDou5eNcvr3n/6CExvYzRoKFKBnHPnncBoMcPzMBfnN
LxiNy2Ju1kCPh1cfCjWaNOJayYk0yn4Y40MiM2LqjWMNMeD4TsfrLA3zW12iJym3
zHqrOxHp47jtHyJeYgdHW/MnqEkwmUtqHLCA6O3LcTtSsxi/tWTfRneamCooqXOl
X2S9g19ihzfhZwPWZ0QFhAS5jlNYVf1/xH7H1QIDAQABAoIBAF3f5o33jT1c9pLG
+4goIGxGjc5a3BS4ETsBp6JUHVDGN3rlM+aGqmAeKxJmGAHQ56z/bUg7JC6L7Z7r
i9riflkdibMOiPRCxb9Fl9YK1OktkxJuX/c4/PgU88v+NTVzJoRJvqw9bu9c1ycv
tK+DCiXGaAsT/zXyklYlZS4GukpuktNus9W3XaFziXEcB9OC4Ayu9U+dN3Zdrhb7
dk7W+8e2s6TdQa08+3JFECU6MG8pWjVmoqR8ZprXEFKaZbJU/Mh7exgVSHDWbTnp
rWcaV4zV5/R0tI82xo1tDzUiYGiNGzpKEPUECaYVVmdWzXn6lqshSJKr7S+SH7gf
1Fz/+7UCgYEA68+5uUiKS/H4b+ZxIw97cdgMTnYJMz7P+39RNBvPaBl3Hgsx/KsH
SPpTijiVyuKy4a32RO+G+GLOmQUWeVzpAJK+2s1Tx7lOdsK+jRcEcgQzgTeOwnD5
OfXCuou6lFjMXKhX9fmWpD/ovuBHGf1fLbqY19k0ZkNnww3BmTZm1HcCgYEA6f84
oZHqBi4/5YyFIC7BTYmQO3Y2kvdoXWfTfSP2weOVQSc/ZqjtJCy+nqeW2lAhHtHc
NSNLegZEfUcdt+gxP6ADqcGJJ22fLfb0sZsGYNvfC+WhHCyaitUHGdkxDO4V2/BF
Vamw3zl7LFUbMdS2sIimX6tdiIuw5+SHzyga1RMCgYEAu6dlu72vWHppYts2Y1k5
ukHcoT+rWJ1+szwBKf+LkOLa+Qydrd2IgZm7iz42berzwUZHuVoHxXgTwo/a759x
SGR+/u3w4vpjJ30YWHzdq8IOHqFQuQlgO7CIUx1I0C7OClppDTSenXzCQcuGqXcJ
HAHnCbYuzcaMNxumWb+CG0cCgYEAvAGDzs0d6rlePWEZ1TG7vkC40g2463w9Lk8t
bW5n5ICmeyK9ng47+sS4o2Cjo+Sdt9WFyGwDSJegj8eD6S914lj+mHYXbMZ3DsdM
8yZLiacfHr/xImH0CXf/rJUFBA6HIZ97Fcixg6j7fjMjFnaCEnS4uEVHcV5LVQYY
2Ciw5mECgYBNkwyRpEwNOtDpWdnGfIQWFZXmDwarA/F4fXdo5hgHp8/s1GLR8JY0
vBml2sW6lYQnP2+P1tw/6L1xrCoGg1tSu5FWlSXZCsRoTNscau99widjc33SaOLV
q4Bn8dckeDJkSLJwcHZu1Z87RrJQQSlqQ7zPA55TtceYCqqitGE3bw==
—–END RSA PRIVATE KEY—–
STEP 2:- Generate the public key
OpenSSL | Python |
---|---|
These both also do the same thing. Producing a file like the following Base64, PEM encoded public key.
$ cat openSSLPubkey.pem
—–BEGIN PUBLIC KEY—–
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA14soHedBsAjutu0a8aM/
o1waROe+Mz/wYsF7vn0dAScdomN0Xo4zj3Z7Ly2TImds0a92KZoG69RyyrnhAdwU
4Es4gCZsR61cQ4Mb08oIl6ILNhGVKJfKssSUbR2wXu4pFy/gMjDou5eNcvr3n/6C
ExvYzRoKFKBnHPnncBoMcPzMBfnNLxiNy2Ju1kCPh1cfCjWaNOJayYk0yn4Y40Mi
M2LqjWMNMeD4TsfrLA3zW12iJym3zHqrOxHp47jtHyJeYgdHW/MnqEkwmUtqHLCA
6O3LcTtSsxi/tWTfRneamCooqXOlX2S9g19ihzfhZwPWZ0QFhAS5jlNYVf1/xH7H
1QIDAQAB
—–END PUBLIC KEY—–
STEP 3:- Encrypt data from a file
First lets create a file to encrypt:
$ cat plaintext.txt
The quick brown fox jumped over the lazy dogs.
OpenSSL | Python |
---|---|
These both create binary encoded files, like this (see below how to convert to base64 to copy/paste file):
$ hexdump openSSLCiphertext.bin
0000000 21 ce 8e 7e 2a a0 14 c0 33 5c a2 ca 5a 0e e9 64
0000010 27 40 23 8e 00 0f 2b bc 86 87 53 a2 8b 16 9a 70
0000020 68 19 4e a8 61 cc d5 9d db d4 7c 12 6c 4d a6 bc
0000030 4d d2 48 2f 93 10 07 8b 37 21 e0 60 ce 9e 7a 65
0000040 db 84 24 72 dd 37 62 51 67 cf 3e 52 9f 48 a5 f6
0000050 0b bb e9 50 8e 82 1f 04 2f f7 d9 6f 72 26 bd c9
0000060 75 17 ca 16 ad ca 23 b7 81 6a 68 a9 08 bd cf 0f
0000070 37 f5 4c da 68 98 42 4d 99 78 07 d7 83 2a da be
0000080 40 e2 78 e6 f1 df 96 29 7b 2d 44 27 38 a2 3b 58
0000090 98 06 66 8b ba 65 03 f3 a6 06 aa f7 8b ae 42 55
00000a0 ac ae fa 40 80 32 d7 ee a8 17 a1 ff d0 a3 53 f3
00000b0 c2 00 5a 34 40 84 bb f7 ca 50 ee cb b9 e2 a0 f0
00000c0 cb 21 f9 54 a8 b2 34 78 80 f2 9f 44 31 de e1 8f
00000d0 3b 4b 79 29 87 c6 ce 6d 0f 50 b8 00 2e df ad 02
00000e0 13 9d 8e ac ee a6 47 3e 08 13 3d ee d1 07 e0 66
00000f0 be 0e a3 08 59 72 35 ee 82 33 62 a8 a2 8f 23 b6
0000100
STEP 4:- Decrypt data from a file
Here we will do somethin slightly more interesting.
In OpenSSL we will decrypt the data we encrypted with Python
In Python we will decrypt the data we encrypted with OpenSSL
OpenSSL | Python |
---|---|
< |
These both successfully decrypt the files
Bonus – Decode Base64
In step 3 above the encrypted files were created as binary files, so if we try and ‘cat’ them to the terminal it doesn’t work.
We can convert any binary file to base64 using OpenSSL or Python like this:
OpenSSL | Python |
---|---|
And convert back again like this:
OpenSSL | Python |
---|---|
Conclusion
Hurrah!! We encrypted data with OpenSSL and Python, then decrypted the data with the opposite one showing that the implementation of RSA PKCS1.5 is equivalent (at least for this data!) between the two.
If I were to use this in any real scenario I would check an example of the specific data I will be encrypting/decrypting just to check it works. Particularly when the data length is changed. I’ll see a real world example of this in a future article.
Drawbacks of the above:- In the above python example the whole data is read into RAM at once. This will not work for large files since the RAM will fill up. Instead you’d be better streaming the data into Python. We will see this in the coming AES example, since RSA PKCS1.5 is hardly used for any large amounts of data, as articles at the top of the article explain.