# python2
>>> import BaseHTTPServer, SimpleHTTPServer
>>> import ssl
>>> host, port = 'localhost', 5566
>>> handler = SimpleHTTPServer.SimpleHTTPRequestHandler
>>> httpd = BaseHTTPServer.HTTPServer((host, port), handler)
>>> httpd.socket = ssl.wrap_socket(httpd.socket,
... certfile='./cert.crt',
... keyfile='./cert.key',
... server_side=True)
>>> httpd.serve_forever()
# python3
>>> from http import server
>>> handler = server.SimpleHTTPRequestHandler
>>> import ssl
>>> host, port = 'localhost', 5566
>>> httpd = server.HTTPServer((host, port), handler)
>>> httpd.socket = ssl.wrap_socket(httpd.socket,
... certfile='./cert.crt',
... keyfile='./cert.key',
... server_side=True)
...
>>> httpd.serve_forever()
from cryptography import x509
from cryptography.hazmat.backends import default_backend
backend = default_backend()
with open('./cert.crt', 'rb') as f:
crt_data = f.read()
cert = x509.load_pem_x509_certificate(crt_data, backend)
class Certificate:
_fields = ['country_name',
'state_or_province_name',
'locality_name',
'organization_name',
'organizational_unit_name',
'common_name',
'email_address']
def __init__(self, cert):
assert isinstance(cert, x509.Certificate)
self._cert = cert
for attr in self._fields:
oid = getattr(x509, 'OID_' + attr.upper())
subject = cert.subject
info = subject.get_attributes_for_oid(oid)
setattr(self, attr, info)
cert = Certificate(cert)
for attr in cert._fields:
for info in getattr(cert, attr):
print("{}: {}".format(info._oid._name, info._value))
output:
$ genrsa -out cert.key
Generating RSA private key, 1024 bit long modulus
..........++++++
...++++++
e is 65537 (0x10001)
$ openssl req -x509 -new -nodes \
> -key cert.key -days 365 \
> -out cert.crt
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:TW
State or Province Name (full name) [Some-State]:Taiwan
Locality Name (eg, city) []:Taipei
Organization Name (eg, company) [Internet Widgits Pty Ltd]:personal
Organizational Unit Name (eg, section) []:personal
Common Name (e.g. server FQDN or YOUR name) []:localhost
Email Address []:[email protected]
$ python3 cert.py
countryName: TW
stateOrProvinceName: Taiwan
localityName: Taipei
organizationName: personal
organizationalUnitName: personal
commonName: localhost
emailAddress: [email protected]
from __future__ import print_function, unicode_literals
from datetime import datetime, timedelta
from OpenSSL import crypto
# load private key
ftype = crypto.FILETYPE_PEM
with open('key.pem', 'rb') as f: k = f.read()
k = crypto.load_privatekey(ftype, k)
now = datetime.now()
expire = now + timedelta(days=365)
# country (countryName, C)
# state or province name (stateOrProvinceName, ST)
# locality (locality, L)
# organization (organizationName, O)
# organizational unit (organizationalUnitName, OU)
# common name (commonName, CN)
cert = crypto.X509()
cert.get_subject().C = "TW"
cert.get_subject().ST = "Taiwan"
cert.get_subject().L = "Taipei"
cert.get_subject().O = "pysheeet"
cert.get_subject().OU = "cheat sheet"
cert.get_subject().CN = "pythonsheets.com"
cert.set_serial_number(1000)
cert.set_notBefore(now.strftime("%Y%m%d%H%M%SZ").encode())
cert.set_notAfter(expire.strftime("%Y%m%d%H%M%SZ").encode())
cert.set_issuer(cert.get_subject())
cert.set_pubkey(k)
cert.sign(k, 'sha1')
with open('cert.pem', "wb") as f:
f.write(crypto.dump_certificate(ftype, cert))
output:
$ openssl genrsa -out key.pem 2048
Generating RSA private key, 2048 bit long modulus
.............+++
..................................+++
e is 65537 (0x10001)
$ python3 x509.py
$ openssl x509 -subject -issuer -noout -in cert.pem
subject= /C=TW/ST=Taiwan/L=Taipei/O=pysheeet/OU=cheat sheet/CN=pythonsheets.com
issuer= /C=TW/ST=Taiwan/L=Taipei/O=pysheeet/OU=cheat sheet/CN=pythonsheets.com
from __future__ import print_function, unicode_literals
from OpenSSL import crypto
# load private key
ftype = crypto.FILETYPE_PEM
with open('key.pem', 'rb') as f: key = f.read()
key = crypto.load_privatekey(ftype, key)
req = crypto.X509Req()
alt_name = [ b"DNS:www.pythonsheeets.com",
b"DNS:doc.pythonsheeets.com" ]
key_usage = [ b"Digital Signature",
b"Non Repudiation",
b"Key Encipherment" ]
# country (countryName, C)
# state or province name (stateOrProvinceName, ST)
# locality (locality, L)
# organization (organizationName, O)
# organizational unit (organizationalUnitName, OU)
# common name (commonName, CN)
req.get_subject().C = "TW"
req.get_subject().ST = "Taiwan"
req.get_subject().L = "Taipei"
req.get_subject().O = "pysheeet"
req.get_subject().OU = "cheat sheet"
req.get_subject().CN = "pythonsheets.com"
req.add_extensions([
crypto.X509Extension( b"basicConstraints",
False,
b"CA:FALSE"),
crypto.X509Extension( b"keyUsage",
False,
b",".join(key_usage)),
crypto.X509Extension( b"subjectAltName",
False,
b",".join(alt_name))
])
req.set_pubkey(key)
req.sign(key, "sha256")
csr = crypto.dump_certificate_request(ftype, req)
with open("cert.csr", 'wb') as f: f.write(csr)
output:
# create a root ca
$ openssl genrsa -out ca-key.pem 2048
Generating RSA private key, 2048 bit long modulus
.....+++
.......................................+++
e is 65537 (0x10001)
$ openssl req -x509 -new -nodes -key ca-key.pem \
> -days 10000 -out ca.pem -subj "/CN=root-ca"
# prepare a csr
$ openssl genrsa -out key.pem 2048
Generating RSA private key, 2048 bit long modulus
....+++
......................................+++
e is 65537 (0x10001)
$ python3 x509.py
# prepare openssl.cnf
cat <<EOF > openssl.cnf
> [req]
> req_extensions = v3_req
> distinguished_name = req_distinguished_name
> [req_distinguished_name]
> [ v3_req ]
> basicConstraints = CA:FALSE
> keyUsage = nonRepudiation, digitalSignature, keyEncipherment
> subjectAltName = @alt_names
> [alt_names]
> DNS.1 = www.pythonsheets.com
> DNS.2 = doc.pythonsheets.com
> EOF
# sign a csr
$ openssl x509 -req -in cert.csr -CA ca.pem \
> -CAkey ca-key.pem -CAcreateserial -out cert.pem \
> -days 365 -extensions v3_req -extfile openssl.cnf
Signature ok
subject=/C=TW/ST=Taiwan/L=Taipei/O=pysheeet/OU=cheat sheet/CN=pythonsheets.com
Getting CA Private Key
# check
$ openssl x509 -in cert.pem -text -noout
# $ openssl genrsa cert.key 2048
>>> from cryptography.hazmat.backends import default_backend
>>> from cryptography.hazmat.primitives import serialization
>>> from cryptography.hazmat.primitives.asymmetric import rsa
>>> key = rsa.generate_private_key(
... public_exponent=65537,
... key_size=2048,
... backend=default_backend())
...
>>> with open('cert.key', 'wb') as f:
... f.write(key.private_bytes(
... encoding=serialization.Encoding.PEM,
... format=serialization.PrivateFormat.TraditionalOpenSSL,
... encryption_algorithm=serialization.NoEncryption()))
from __future__ import print_function, unicode_literals
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA256
def signer(privkey, data):
rsakey = RSA.importKey(privkey)
signer = PKCS1_v1_5.new(rsakey)
digest = SHA256.new()
digest.update(data)
return signer.sign(digest)
with open('private.key', 'rb') as f: key = f.read()
with open('foo.tgz', 'rb') as f: data = f.read()
sign = signer(key, data)
with open('foo.tgz.sha256', 'wb') as f: f.write(sign)
output:
# gernerate public & private key
$ openssl genrsa -out private.key 2048
$ openssl rsa -in private.key -pubout -out public.key
$ python3 sign.py
$ openssl dgst -sha256 -verify public.key -signature foo.tgz.sha256 foo.tgz
Verified OK
from __future__ import print_function, unicode_literals
import sys
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA256
def verifier(pubkey, sig, data):
rsakey = RSA.importKey(key)
signer = PKCS1_v1_5.new(rsakey)
digest = SHA256.new()
digest.update(data)
return signer.verify(digest, sig)
with open("public.key", 'rb') as f: key = f.read()
with open("foo.tgz.sha256", 'rb') as f: sig = f.read()
with open("foo.tgz", 'rb') as f: data = f.read()
if verifier(key, sig, data):
print("Verified OK")
else:
print("Verification Failure")
output:
# gernerate public & private key
$ openssl genrsa -out private.key 2048
$ openssl rsa -in private.key -pubout -out public.key
# do verification
$ cat /dev/urandom | head -c 512 | base64 > foo.txt
$ tar -zcf foo.tgz foo.txt
$ openssl dgst -sha256 -sign private.key -out foo.tgz.sha256 foo.tgz
$ python3 verify.py
Verified OK
# do verification via openssl
$ openssl dgst -sha256 -verify public.key -signature foo.tgz.sha256 foo.tgz
Verified OK
from __future__ import print_function, unicode_literals
import base64
import sys
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
key_text = sys.stdin.read()
# import key via rsa module
pubkey = RSA.importKey(key_text)
# create a cipher via PKCS1.5
cipher = PKCS1_v1_5.new(pubkey)
# encrypt
cipher_text = cipher.encrypt(b"Hello RSA!")
# do base64 encode
cipher_text = base64.b64encode(cipher_text)
print(cipher_text.decode('utf-8'))
output:
$ openssl genrsa -out private.key 2048
$ openssl rsa -in private.key -pubout -out public.key
$ cat public.key |\
> python3 rsa.py |\
> openssl base64 -d -A |\
> openssl rsautl -decrypt -inkey private.key
Hello RSA!
from __future__ import print_function, unicode_literals
import base64
import sys
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
from Crypto.PublicKey.RSA import construct
# prepare public key
e = int('10001', 16)
n = int(sys.stdin.read(), 16)
pubkey = construct((n, e))
# create a cipher via PKCS1.5
cipher = PKCS1_v1_5.new(pubkey)
# encrypt
cipher_text = cipher.encrypt(b"Hello RSA!")
# do base64 encode
cipher_text = base64.b64encode(cipher_text)
print(cipher_text.decode('utf-8'))
output:
$ openssl genrsa -out private.key 2048
$ openssl rsa -in private.key -pubout -out public.key
$ # check (n, e)
$ openssl rsa -pubin -inform PEM -text -noout < public.key
Public-Key: (2048 bit)
Modulus:
00:93:d5:58:0c:18:cf:91:f0:74:af:1b:40:09:73:
0c:d8:13:23:6c:44:60:0d:83:71:e6:f9:61:85:e5:
b2:d0:8a:73:5c:02:02:51:9a:4f:a7:ab:05:d5:74:
ff:4d:88:3d:e2:91:b8:b0:9f:7e:a9:a3:b2:3c:99:
1c:9a:42:4d:ac:2f:6a:e7:eb:0f:a7:e0:a5:81:e5:
98:49:49:d5:15:3d:53:42:12:08:db:b0:e7:66:2d:
71:5b:ea:55:4e:2d:9b:40:79:f8:7d:6e:5d:f4:a7:
d8:13:cb:13:91:c9:ac:5b:55:62:70:44:25:50:ca:
94:de:78:5d:97:e8:a9:33:66:4f:90:10:00:62:21:
b6:60:52:65:76:bd:a3:3b:cf:2a:db:3f:66:5f:0d:
a3:35:ff:29:34:26:6d:63:a2:a6:77:96:5a:84:c7:
6a:0c:4f:48:52:70:11:8f:85:11:a0:78:f8:60:4b:
5d:d8:4b:b2:64:e5:ec:99:72:c5:a8:1b:ab:5c:09:
e1:80:70:91:06:22:ba:97:33:56:0b:65:d8:f3:35:
66:f8:f9:ea:b9:84:64:8e:3c:14:f7:3d:1f:2c:67:
ce:64:cf:f9:c5:16:6b:03:a1:7a:c7:fa:4c:38:56:
ee:e0:4d:5f:ec:46:7e:1f:08:7c:e6:45:a1:fc:17:
1f:91
Exponent: 65537 (0x10001)
$ openssl rsa -pubin -in public.key -modulus -noout |\
> cut -d'=' -f 2 |\
> python3 rsa.py |\
> openssl base64 -d -A |\
> openssl rsautl -decrypt -inkey private.key
Hello RSA!
from __future__ import print_function, unicode_literals
import base64
import sys
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
# read key file
with open('private.key') as f: key_text = f.read()
# create a private key object
privkey = RSA.importKey(key_text)
# create a cipher object
cipher = PKCS1_v1_5.new(privkey)
# decode base64
cipher_text = base64.b64decode(sys.stdin.read())
# decrypt
plain_text = cipher.decrypt(cipher_text, None)
print(plain_text.decode('utf-8').strip())
output:
$ openssl genrsa -out private.key 2048
$ openssl rsa -in private.key -pubout -out public.key
$ echo "Hello openssl RSA encrypt" |\
> openssl rsautl -encrypt -pubin -inkey public.key |\
> openssl base64 -e -A |\
> python3 rsa.py
Hello openssl RSA encrypt
from __future__ import print_function, unicode_literals
import base64
import sys
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
# read key file
key_text = sys.stdin.read()
# create a public key object
pubkey = RSA.importKey(key_text)
# create a cipher object
cipher = PKCS1_OAEP.new(pubkey)
# encrypt plain text
cipher_text = cipher.encrypt(b"Hello RSA OAEP!")
# encode via base64
cipher_text = base64.b64encode(cipher_text)
print(cipher_text.decode('utf-8'))
output:
$ openssl genrsa -out private.key 2048
$ openssl rsa -in private.key -pubout -out public.key
$ cat public.key |\
> python3 rsa.py |\
> openssl base64 -d -A |\
> openssl rsautl -decrypt -oaep -inkey private.key
Hello RSA OAEP!
from __future__ import print_function, unicode_literals
import base64
import sys
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
# read key file
with open('private.key') as f: key_text = f.read()
# create a private key object
privkey = RSA.importKey(key_text)
# create a cipher object
cipher = PKCS1_OAEP.new(privkey)
# decode base64
cipher_text = base64.b64decode(sys.stdin.read())
# decrypt
plain_text = cipher.decrypt(cipher_text)
print(plain_text.decode('utf-8').strip())
output:
$ openssl genrsa -out private.key 2048
$ openssl rsa -in private.key -pubout -out public.key
$ echo "Hello RSA encrypt via OAEP" |\
> openssl rsautl -encrypt -pubin -oaep -inkey public.key |\
> openssl base64 -e -A |\
> python3 rsa.py
Hello RSA encrypt via OAEP
import socket
from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import dsa
alice, bob = socket.socketpair()
def gen_dsa_key():
private_key = dsa.generate_private_key(
key_size=2048, backend=default_backend())
return private_key, private_key.public_key()
def sign_data(data, private_key):
signature = private_key.sign(data, hashes.SHA256())
return signature
def verify_data(data, signature, public_key):
try:
public_key.verify(signature, data, hashes.SHA256())
except InvalidSignature:
print("recv msg: {} not trust!".format(data))
else:
print("check msg: {} success!".format(data))
# generate alice private & public key
alice_private_key, alice_public_key = gen_dsa_key()
# alice send message to bob, then bob recv
alice_msg = b"Hello Bob"
b = alice.send(alice_msg)
bob_recv_msg = bob.recv(1024)
# alice send signature to bob, then bob recv
signature = sign_data(alice_msg, alice_private_key)
b = alice.send(signature)
bob_recv_signature = bob.recv(1024)
# bob check message recv from alice
verify_data(bob_recv_msg, bob_recv_signature, alice_public_key)
# attacker modify the msg will make the msg check fail
verify_data(b"I'm attacker!", bob_recv_signature, alice_public_key)
output:
$ python3 test_dsa.py
check msg: b'Hello Bob' success!
recv msg: b"I'm attacker!" not trust!
from __future__ import print_function, unicode_literals
import struct
import sys
import os
from cryptography.hazmat.primitives import padding
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.ciphers import (
Cipher,
algorithms,
modes)
backend = default_backend()
key = os.urandom(32)
iv = os.urandom(16)
def encrypt(ptext):
pad = padding.PKCS7(128).padder()
ptext = pad.update(ptext) + pad.finalize()
alg = algorithms.AES(key)
mode = modes.CBC(iv)
cipher = Cipher(alg, mode, backend=backend)
encryptor = cipher.encryptor()
ctext = encryptor.update(ptext) + encryptor.finalize()
return ctext
print("key: {}".format(key.hex()))
print("iv: {}".format(iv.hex()))
if len(sys.argv) != 3:
raise Exception("usage: cmd [file] [enc file]")
# read plain text from file
with open(sys.argv[1], 'rb') as f:
plaintext = f.read()
# encrypt file
ciphertext = encrypt(plaintext)
with open(sys.argv[2], 'wb') as f:
f.write(ciphertext)
output:
$ echo "Encrypt file via AES-CBC" > test.txt
$ python3 aes.py test.txt test.enc
key: f239d9609e3f318b7afda7e4bb8db5b8734f504cf67f55e45dfe75f90d24fefc
iv: 8d6383b469f100d25293fb244ccb951e
$ openssl aes-256-cbc -d -in test.enc -out secrets.txt.new \
> -K f239d9609e3f318b7afda7e4bb8db5b8734f504cf67f55e45dfe75f90d24fefc \
> -iv 8d6383b469f100d25293fb244ccb951e
$ cat secrets.txt.new
Encrypt file via AES-CBC
from __future__ import print_function, unicode_literals
import struct
import sys
import os
from binascii import unhexlify
from cryptography.hazmat.primitives import padding
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.ciphers import (
Cipher,
algorithms,
modes)
backend = default_backend()
def decrypt(key, iv, ctext):
alg = algorithms.AES(key)
mode = modes.CBC(iv)
cipher = Cipher(alg, mode, backend=backend)
decryptor = cipher.decryptor()
ptext = decryptor.update(ctext) + decryptor.finalize()
unpadder = padding.PKCS7(128).unpadder() # 128 bit
ptext = unpadder.update(ptext) + unpadder.finalize()
return ptext
if len(sys.argv) != 4:
raise Exception("usage: cmd [key] [iv] [file]")
# read cipher text from file
with open(sys.argv[3], 'rb') as f:
ciphertext = f.read()
# decrypt file
key, iv = unhexlify(sys.argv[1]), unhexlify(sys.argv[2])
plaintext = decrypt(key, iv, ciphertext)
print(plaintext)
output:
$ echo "Encrypt file via AES-CBC" > test.txt
$ key=`openssl rand -hex 32`
$ iv=`openssl rand -hex 16`
$ openssl enc -aes-256-cbc -in test.txt -out test.enc -K $key -iv $iv
$ python3 aes.py $key $iv test.enc
from __future__ import print_function, unicode_literals
import base64
import struct
import sys
import os
from hashlib import md5, sha1
from cryptography.hazmat.primitives import padding
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.ciphers import (
Cipher,
algorithms,
modes)
backend = default_backend()
def EVP_ByteToKey(pwd, md, salt, key_len, iv_len):
buf = md(pwd + salt).digest()
d = buf
while len(buf) < (iv_len + key_len):
d = md(d + pwd + salt).digest()
buf += d
return buf[:key_len], buf[key_len:key_len + iv_len]
def aes_encrypt(pwd, ptext, md):
key_len, iv_len = 32, 16
# generate salt
salt = os.urandom(8)
# generate key, iv from password
key, iv = EVP_ByteToKey(pwd, md, salt, key_len, iv_len)
# pad plaintext
pad = padding.PKCS7(128).padder()
ptext = pad.update(ptext) + pad.finalize()
# create an encryptor
alg = algorithms.AES(key)
mode = modes.CBC(iv)
cipher = Cipher(alg, mode, backend=backend)
encryptor = cipher.encryptor()
# encrypt plain text
ctext = encryptor.update(ptext) + encryptor.finalize()
ctext = b'Salted__' + salt + ctext
# encode base64
ctext = base64.b64encode(ctext)
return ctext
if len(sys.argv) != 2: raise Exception("usage: CMD [md]")
md = globals()[sys.argv[1]]
plaintext = sys.stdin.read().encode('utf-8')
pwd = b"password"
print(aes_encrypt(pwd, plaintext, md).decode('utf-8'))
output:
# with md5 digest
$ echo "Encrypt plaintext via AES-CBC from a given password" |\
> python3 aes.py md5 |\
> openssl base64 -d -A |\
> openssl aes-256-cbc -md md5 -d -k password
Encrypt plaintext via AES-CBC from a given password
# with sha1 digest
$ echo "Encrypt plaintext via AES-CBC from a given password" |\
> python3 aes.py sha1 |\
> openssl base64 -d -A |\
> openssl aes-256-cbc -md sha1 -d -k password
Encrypt plaintext via AES-CBC from a given password
from __future__ import print_function, unicode_literals
import base64
import struct
import sys
import os
from hashlib import md5, sha1
from cryptography.hazmat.primitives import padding
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.ciphers import (
Cipher,
algorithms,
modes)
backend = default_backend()
def EVP_ByteToKey(pwd, md, salt, key_len, iv_len):
buf = md(pwd + salt).digest()
d = buf
while len(buf) < (iv_len + key_len):
d = md(d + pwd + salt).digest()
buf += d
return buf[:key_len], buf[key_len:key_len + iv_len]
def aes_decrypt(pwd, ctext, md):
ctext = base64.b64decode(ctext)
# check magic
if ctext[:8] != b'Salted__':
raise Exception("bad magic number")
# get salt
salt = ctext[8:16]
# generate key, iv from password
key, iv = EVP_ByteToKey(pwd, md, salt, 32, 16)
# decrypt
alg = algorithms.AES(key)
mode = modes.CBC(iv)
cipher = Cipher(alg, mode, backend=backend)
decryptor = cipher.decryptor()
ptext = decryptor.update(ctext[16:]) + decryptor.finalize()
# unpad plaintext
unpadder = padding.PKCS7(128).unpadder() # 128 bit
ptext = unpadder.update(ptext) + unpadder.finalize()
return ptext.strip()
if len(sys.argv) != 2: raise Exception("usage: CMD [md]")
md = globals()[sys.argv[1]]
ciphertext = sys.stdin.read().encode('utf-8')
pwd = b"password"
print(aes_decrypt(pwd, ciphertext, md).decode('utf-8'))
output:
# with md5 digest
$ echo "Decrypt ciphertext via AES-CBC from a given password" |\
> openssl aes-256-cbc -e -md md5 -salt -A -k password |\
> openssl base64 -e -A |\
> python3 aes.py md5
Decrypt ciphertext via AES-CBC from a given password
# with sha1 digest
$ echo "Decrypt ciphertext via AES-CBC from a given password" |\
> openssl aes-256-cbc -e -md sha1 -salt -A -k password |\
> openssl base64 -e -A |\
> python3 aes.py sha1
Decrypt ciphertext via AES-CBC from a given password
from __future__ import print_function, unicode_literals
import struct
import base64
import sys
from hashlib import md5, sha1
from Crypto.Cipher import AES
from Crypto.Random.random import getrandbits
# AES CBC requires blocks to be aligned on 16-byte boundaries.
BS = 16
pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS).encode('utf-8')
unpad = lambda s : s[0:-ord(s[-1])]
def EVP_ByteToKey(pwd, md, salt, key_len, iv_len):
buf = md(pwd + salt).digest()
d = buf
while len(buf) < (iv_len + key_len):
d = md(d + pwd + salt).digest()
buf += d
return buf[:key_len], buf[key_len:key_len + iv_len]
def aes_encrypt(pwd, plaintext, md):
key_len, iv_len = 32, 16
# generate salt
salt = struct.pack('=Q', getrandbits(64))
# generate key, iv from password
key, iv = EVP_ByteToKey(pwd, md, salt, key_len, iv_len)
# pad plaintext
plaintext = pad(plaintext)
# create a cipher object
cipher = AES.new(key, AES.MODE_CBC, iv)
# ref: openssl/apps/enc.c
ciphertext = b'Salted__' + salt + cipher.encrypt(plaintext)
# encode base64
ciphertext = base64.b64encode(ciphertext)
return ciphertext
if len(sys.argv) != 2: raise Exception("usage: CMD [md]")
md = globals()[sys.argv[1]]
plaintext = sys.stdin.read().encode('utf-8')
pwd = b"password"
print(aes_encrypt(pwd, plaintext, md).decode('utf-8'))
output:
# with md5 digest
$ echo "Encrypt plaintext via AES-CBC from a given password" |\
> python3 aes.py md5 |\
> openssl base64 -d -A |\
> openssl aes-256-cbc -md md5 -d -k password
Encrypt plaintext via AES-CBC from a given password
# with sha1 digest
$ echo "Encrypt plaintext via AES-CBC from a given password" |\
> python3 aes.py sha1 |\
> openssl base64 -d -A |\
> openssl aes-256-cbc -md sha1 -d -k password
Encrypt plaintext via AES-CBC from a given password
from __future__ import print_function, unicode_literals
import struct
import base64
import sys
from hashlib import md5, sha1
from Crypto.Cipher import AES
from Crypto.Random.random import getrandbits
# AES CBC requires blocks to be aligned on 16-byte boundaries.
BS = 16
unpad = lambda s : s[0:-s[-1]]
def EVP_ByteToKey(pwd, md, salt, key_len, iv_len):
buf = md(pwd + salt).digest()
d = buf
while len(buf) < (iv_len + key_len):
d = md(d + pwd + salt).digest()
buf += d
return buf[:key_len], buf[key_len:key_len + iv_len]
def aes_decrypt(pwd, ciphertext, md):
ciphertext = base64.b64decode(ciphertext)
# check magic
if ciphertext[:8] != b'Salted__':
raise Exception("bad magic number")
# get salt
salt = ciphertext[8:16]
# get key, iv
key, iv = EVP_ByteToKey(pwd, md, salt, 32, 16)
# decrypt
cipher = AES.new(key, AES.MODE_CBC, iv)
return unpad(cipher.decrypt(ciphertext[16:])).strip()
if len(sys.argv) != 2: raise Exception("usage: CMD [md]")
md = globals()[sys.argv[1]]
ciphertext = sys.stdin.read().encode('utf-8')
pwd = b"password"
print(aes_decrypt(pwd, ciphertext, md).decode('utf-8'))
output:
# with md5 digest
$ echo "Decrypt ciphertext via AES-CBC from a given password" |\
> openssl aes-256-cbc -e -md md5 -salt -A -k password |\
> openssl base64 -e -A |\
> python3 aes.py md5
Decrypt ciphertext via AES-CBC from a given password
# with sha1 digest
$ echo "Decrypt ciphertext via AES-CBC from a given password" |\
> openssl aes-256-cbc -e -md sha1 -salt -A -k password |\
> openssl base64 -e -A |\
> python3 aes.py sha1
Decrypt ciphertext via AES-CBC from a given password