本文实例讲述了python实现的des加密算法和3des加密算法。分享给大家供大家参考。具体实现方法如下:
#############################################################################
# documentation #
#############################################################################
# author: todd whiteman
# date: 16th march, 2009
# verion: 2.0.0
# license: public domain – free to do as you wish
# homepage: http://twhiteman.netfirms.com/des.html
#
# this is a pure python implementation of the des encryption algorithm.
# it’s pure python to avoid portability issues, since most des
# implementations are programmed in c (for performance reasons).
#
# triple des class is also implemented, utilising the des base. triple des
# is either des-ede3 with a 24 byte key, or des-ede2 with a 16 byte key.
#
# see the readme.txt that should come with this python module for the
# implementation methods used.
#
# thanks to:
# * david broadwell for ideas, comments and suggestions.
# * mario wolff for pointing out and debugging some triple des cbc errors.
# * santiago palladino for providing the pkcs5 padding technique.
# * shaya for correcting the pad_pkcs5 triple des cbc errors.
#
“””a pure python implementation of the des and triple des encryption algorithms.
class initialization
——————–
pydes.des(key, [mode], [iv], [pad], [padmode])
pydes.triple_des(key, [mode], [iv], [pad], [padmode])
key -> bytes containing the encryption key. 8 bytes for des, 16 or 24 bytes
for triple des
mode -> optional argument for encryption type, can be either
pydes.ecb (electronic code book) or pydes.cbc (cypher block chaining)
iv -> optional initial value bytes, must be supplied if using cbc mode.
length must be 8 bytes.
pad -> optional argument, set the pad character (pad_normal) to use during
all encrypt/decrpt operations done with this instance.
padmode -> optional argument, set the padding mode (pad_normal or pad_pkcs5)
to use during all encrypt/decrpt operations done with this instance.
i recommend to use pad_pkcs5 padding, as then you never need to worry about any
padding issues, as the padding can be removed unambiguously upon decrypting
data that was encrypted using pad_pkcs5 padmode.
common methods
————–
encrypt(data, [pad], [padmode])
decrypt(data, [pad], [padmode])
data -> bytes to be encrypted/decrypted
pad -> optional argument. only when using padmode of pad_normal. for
encryption, adds this characters to the end of the data block when
data is not a multiple of 8 bytes. for decryption, will remove the
trailing characters that match this pad character from the last 8
bytes of the unencrypted data block.
padmode -> optional argument, set the padding mode, must be one of pad_normal
or pad_pkcs5). defaults to pad_normal.
example
——-
from pydes import *
data = “please encrypt my data”
k = des(“descrypt”, cbc, “\0\0\0\0\0\0\0\0″, pad=none, padmode=pad_pkcs5)
# for python3, you’ll need to use bytes, i.e.:
# data = b”please encrypt my data”
# k = des(b”descrypt”, cbc, b”\0\0\0\0\0\0\0\0″, pad=none, padmode=pad_pkcs5)
d = k.encrypt(data)
print “encrypted: %r” % d
print “decrypted: %r” % k.decrypt(d)
assert k.decrypt(d, padmode=pad_pkcs5) == data
see the module source (pydes.py) for more examples of use.
you can also run the pydes.py file without and arguments to see a simple test.
note: this code was not written for high-end systems needing a fast
implementation, but rather a handy portable solution with small usage.
“””
import sys
# _pythonmajorversion is used to handle python2 and python3 differences.
_pythonmajorversion = sys.version_info[0]
# modes of crypting / cyphering
ecb = 0
cbc = 1
# modes of padding
pad_normal = 1
pad_pkcs5 = 2
# pad_pkcs5: is a method that will unambiguously remove all padding
# characters after decryption, when originally encrypted with
# this padding mode.
# for a good description of the pkcs5 padding technique, see:
# http://www.faqs.org/rfcs/rfc1423.html
# the base class shared by des and triple des.
class _basedes(object):
def __init__(self, mode=ecb, iv=none, pad=none, padmode=pad_normal):
if iv:
iv = self._guardagainstunicode(iv)
if pad:
pad = self._guardagainstunicode(pad)
self.block_size = 8
# sanity checking of arguments.
if pad and padmode == pad_pkcs5:
raise valueerror(“cannot use a pad character with pad_pkcs5”)
if iv and len(iv) != self.block_size:
raise valueerror(“invalid initial value (iv), must be a multiple of ” + str(self.block_size) + ” bytes”)
# set the passed in variables
self._mode = mode
self._iv = iv
self._padding = pad
self._padmode = padmode
def getkey(self):
“””getkey() -> bytes”””
return self.__key
def setkey(self, key):
“””will set the crypting key for this object.”””
key = self._guardagainstunicode(key)
self.__key = key
def getmode(self):
“””getmode() -> pydes.ecb or pydes.cbc”””
return self._mode
def setmode(self, mode):
“””sets the type of crypting mode, pydes.ecb or pydes.cbc”””
self._mode = mode
def getpadding(self):
“””getpadding() -> bytes of length 1. padding character.”””
return self._padding
def setpadding(self, pad):
“””setpadding() -> bytes of length 1. padding character.”””
if pad is not none:
pad = self._guardagainstunicode(pad)
self._padding = pad
def getpadmode(self):
“””getpadmode() -> pydes.pad_normal or pydes.pad_pkcs5″””
return self._padmode
def setpadmode(self, mode):
“””sets the type of padding mode, pydes.pad_normal or pydes.pad_pkcs5″””
self._padmode = mode
def getiv(self):
“””getiv() -> bytes”””
return self._iv
def setiv(self, iv):
“””will set the initial value, used in conjunction with cbc mode”””
if not iv or len(iv) != self.block_size:
raise valueerror(“invalid initial value (iv), must be a multiple of ” + str(self.block_size) + ” bytes”)
iv = self._guardagainstunicode(iv)
self._iv = iv
def _paddata(self, data, pad, padmode):
# pad data depending on the mode
if padmode is none:
# get the default padding mode.
padmode = self.getpadmode()
if pad and padmode == pad_pkcs5:
raise valueerror(“cannot use a pad character with pad_pkcs5”)
if padmode == pad_normal:
if len(data) % self.block_size == 0:
# no padding required.
return data
if not pad:
# get the default padding.
pad = self.getpadding()
if not pad:
raise valueerror(“data must be a multiple of ” + str(self.block_size) + ” bytes in length. use padmode=pad_pkcs5 or set the pad character.”)
data += (self.block_size – (len(data) % self.block_size)) * pad
elif padmode == pad_pkcs5:
pad_len = 8 – (len(data) % self.block_size)
if _pythonmajorversion < 3:
data += pad_len * chr(pad_len)
else:
data += bytes([pad_len] * pad_len)
return data
def _unpaddata(self, data, pad, padmode):
# unpad data depending on the mode.
if not data:
return data
if pad and padmode == pad_pkcs5:
raise valueerror("cannot use a pad character with pad_pkcs5")
if padmode is none:
# get the default padding mode.
padmode = self.getpadmode()
if padmode == pad_normal:
if not pad:
# get the default padding.
pad = self.getpadding()
if pad:
data = data[:-self.block_size] + \
data[-self.block_size:].rstrip(pad)
elif padmode == pad_pkcs5:
if _pythonmajorversion < 3:
pad_len = ord(data[-1])
else:
pad_len = data[-1]
data = data[:-pad_len]
return data
def _guardagainstunicode(self, data):
# only accept byte strings or ascii unicode values, otherwise
# there is no way to correctly decode the data into bytes.
if _pythonmajorversion < 3:
if isinstance(data, unicode):
raise valueerror("pydes can only work with bytes, not unicode strings.")
else:
if isinstance(data, str):
# only accept ascii unicode values.
try:
return data.encode('ascii')
except unicodeencodeerror:
pass
raise valueerror("pydes can only work with encoded strings, not unicode.")
return data
#############################################################################
# des #
#############################################################################
class des(_basedes):
"""des encryption/decrytpion class
supports ecb (electronic code book) and cbc (cypher block chaining) modes.
pydes.des(key,[mode], [iv])
key -> bytes containing the encryption key, must be exactly 8 bytes
mode -> optional argument for encryption type, can be either pydes.ecb
(electronic code book), pydes.cbc (cypher block chaining)
iv -> optional initial value bytes, must be supplied if using cbc mode.
must be 8 bytes in length.
pad -> optional argument, set the pad character (pad_normal) to use
during all encrypt/decrpt operations done with this instance.
padmode -> optional argument, set the padding mode (pad_normal or
pad_pkcs5) to use during all encrypt/decrpt operations done
with this instance.
“””
# permutation and translation tables for des
__pc1 = [56, 48, 40, 32, 24, 16, 8,
, 57, 49, 41, 33, 25, 17,
, 1, 58, 50, 42, 34, 26,
, 10, 2, 59, 51, 43, 35,
, 54, 46, 38, 30, 22, 14,
, 61, 53, 45, 37, 29, 21,
, 5, 60, 52, 44, 36, 28,
, 12, 4, 27, 19, 11, 3
]
# number left rotations of pc1
__left_rotations = [
, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
]
# permuted choice key (table 2)
__pc2 = [
, 16, 10, 23, 0, 4,
, 27, 14, 5, 20, 9,
, 18, 11, 3, 25, 7,
, 6, 26, 19, 12, 1,
, 51, 30, 36, 46, 54,
, 39, 50, 44, 32, 47,
, 48, 38, 55, 33, 52,
, 41, 49, 35, 28, 31
]
# initial permutation ip
__ip = [57, 49, 41, 33, 25, 17, 9, 1,
, 51, 43, 35, 27, 19, 11, 3,
, 53, 45, 37, 29, 21, 13, 5,
, 55, 47, 39, 31, 23, 15, 7,
, 48, 40, 32, 24, 16, 8, 0,
, 50, 42, 34, 26, 18, 10, 2,
, 52, 44, 36, 28, 20, 12, 4,
, 54, 46, 38, 30, 22, 14, 6
]
# expansion table for turning 32 bit blocks into 48 bits
__expansion_table = [
, 0, 1, 2, 3, 4,
, 4, 5, 6, 7, 8,
, 8, 9, 10, 11, 12,
, 12, 13, 14, 15, 16,
, 16, 17, 18, 19, 20,
, 20, 21, 22, 23, 24,
, 24, 25, 26, 27, 28,
, 28, 29, 30, 31, 0
]
# the (in)famous s-boxes
__sbox = [
# s1
[14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13],
# s2
[15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9],
# s3
[10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12],
# s4
[7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14],
# s5
[2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3],
# s6
[12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13],
# s7
[4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12],
# s8
[13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11],
]
# 32-bit permutation function p used on the output of the s-boxes
__p = [
, 6, 19, 20, 28, 11,
, 16, 0, 14, 22, 25,
, 17, 30, 9, 1, 7,
,13, 31, 26, 2, 8,
, 12, 29, 5, 21, 10,
, 24
]
# final permutation ip^-1
__fp = [
, 7, 47, 15, 55, 23, 63, 31,
, 6, 46, 14, 54, 22, 62, 30,
, 5, 45, 13, 53, 21, 61, 29,
, 4, 44, 12, 52, 20, 60, 28,
, 3, 43, 11, 51, 19, 59, 27,
, 2, 42, 10, 50, 18, 58, 26,
, 1, 41, 9, 49, 17, 57, 25,
, 0, 40, 8, 48, 16, 56, 24
]
# type of crypting being done
encrypt = 0x00
decrypt = 0x01
# initialisation
def __init__(self, key, mode=ecb, iv=none, pad=none, padmode=pad_normal):
# sanity checking of arguments.
if len(key) != 8:
raise valueerror(“invalid des key size. key must be exactly 8 bytes long.”)
_basedes.__init__(self, mode, iv, pad, padmode)
self.key_size = 8
self.l = []
self.r = []
self.kn = [ [0] * 48 ] * 16 # 16 48-bit keys (k1 – k16)
self.final = []
self.setkey(key)
def setkey(self, key):
“””will set the crypting key for this object. must be 8 bytes.”””
_basedes.setkey(self, key)
self.__create_sub_keys()
def __string_to_bitlist(self, data):
“””turn the string data, into a list of bits (1, 0)’s”””
if _pythonmajorversion < 3:
# turn the strings into integers. python 3 uses a bytes
# class, which already has this behaviour.
data = [ord(c) for c in data]
l = len(data) * 8
result = [0] * l
pos = 0
for ch in data:
i = 7
while i >= 0:
if ch & (1