faset over fra Z3950 til google books
This commit is contained in:
33
python/gdata/Crypto/Cipher/__init__.py
Normal file
33
python/gdata/Crypto/Cipher/__init__.py
Normal file
@@ -0,0 +1,33 @@
|
||||
"""Secret-key encryption algorithms.
|
||||
|
||||
Secret-key encryption algorithms transform plaintext in some way that
|
||||
is dependent on a key, producing ciphertext. This transformation can
|
||||
easily be reversed, if (and, hopefully, only if) one knows the key.
|
||||
|
||||
The encryption modules here all support the interface described in PEP
|
||||
272, "API for Block Encryption Algorithms".
|
||||
|
||||
If you don't know which algorithm to choose, use AES because it's
|
||||
standard and has undergone a fair bit of examination.
|
||||
|
||||
Crypto.Cipher.AES Advanced Encryption Standard
|
||||
Crypto.Cipher.ARC2 Alleged RC2
|
||||
Crypto.Cipher.ARC4 Alleged RC4
|
||||
Crypto.Cipher.Blowfish
|
||||
Crypto.Cipher.CAST
|
||||
Crypto.Cipher.DES The Data Encryption Standard. Very commonly used
|
||||
in the past, but today its 56-bit keys are too small.
|
||||
Crypto.Cipher.DES3 Triple DES.
|
||||
Crypto.Cipher.IDEA
|
||||
Crypto.Cipher.RC5
|
||||
Crypto.Cipher.XOR The simple XOR cipher.
|
||||
"""
|
||||
|
||||
__all__ = ['AES', 'ARC2', 'ARC4',
|
||||
'Blowfish', 'CAST', 'DES', 'DES3', 'IDEA', 'RC5',
|
||||
'XOR'
|
||||
]
|
||||
|
||||
__revision__ = "$Id: __init__.py,v 1.7 2003/02/28 15:28:35 akuchling Exp $"
|
||||
|
||||
|
108
python/gdata/Crypto/Hash/HMAC.py
Normal file
108
python/gdata/Crypto/Hash/HMAC.py
Normal file
@@ -0,0 +1,108 @@
|
||||
"""HMAC (Keyed-Hashing for Message Authentication) Python module.
|
||||
|
||||
Implements the HMAC algorithm as described by RFC 2104.
|
||||
|
||||
This is just a copy of the Python 2.2 HMAC module, modified to work when
|
||||
used on versions of Python before 2.2.
|
||||
"""
|
||||
|
||||
__revision__ = "$Id: HMAC.py,v 1.5 2002/07/25 17:19:02 z3p Exp $"
|
||||
|
||||
import string
|
||||
|
||||
def _strxor(s1, s2):
|
||||
"""Utility method. XOR the two strings s1 and s2 (must have same length).
|
||||
"""
|
||||
return "".join(map(lambda x, y: chr(ord(x) ^ ord(y)), s1, s2))
|
||||
|
||||
# The size of the digests returned by HMAC depends on the underlying
|
||||
# hashing module used.
|
||||
digest_size = None
|
||||
|
||||
class HMAC:
|
||||
"""RFC2104 HMAC class.
|
||||
|
||||
This supports the API for Cryptographic Hash Functions (PEP 247).
|
||||
"""
|
||||
|
||||
def __init__(self, key, msg = None, digestmod = None):
|
||||
"""Create a new HMAC object.
|
||||
|
||||
key: key for the keyed hash object.
|
||||
msg: Initial input for the hash, if provided.
|
||||
digestmod: A module supporting PEP 247. Defaults to the md5 module.
|
||||
"""
|
||||
if digestmod == None:
|
||||
import md5
|
||||
digestmod = md5
|
||||
|
||||
self.digestmod = digestmod
|
||||
self.outer = digestmod.new()
|
||||
self.inner = digestmod.new()
|
||||
try:
|
||||
self.digest_size = digestmod.digest_size
|
||||
except AttributeError:
|
||||
self.digest_size = len(self.outer.digest())
|
||||
|
||||
blocksize = 64
|
||||
ipad = "\x36" * blocksize
|
||||
opad = "\x5C" * blocksize
|
||||
|
||||
if len(key) > blocksize:
|
||||
key = digestmod.new(key).digest()
|
||||
|
||||
key = key + chr(0) * (blocksize - len(key))
|
||||
self.outer.update(_strxor(key, opad))
|
||||
self.inner.update(_strxor(key, ipad))
|
||||
if (msg):
|
||||
self.update(msg)
|
||||
|
||||
## def clear(self):
|
||||
## raise NotImplementedError, "clear() method not available in HMAC."
|
||||
|
||||
def update(self, msg):
|
||||
"""Update this hashing object with the string msg.
|
||||
"""
|
||||
self.inner.update(msg)
|
||||
|
||||
def copy(self):
|
||||
"""Return a separate copy of this hashing object.
|
||||
|
||||
An update to this copy won't affect the original object.
|
||||
"""
|
||||
other = HMAC("")
|
||||
other.digestmod = self.digestmod
|
||||
other.inner = self.inner.copy()
|
||||
other.outer = self.outer.copy()
|
||||
return other
|
||||
|
||||
def digest(self):
|
||||
"""Return the hash value of this hashing object.
|
||||
|
||||
This returns a string containing 8-bit data. The object is
|
||||
not altered in any way by this function; you can continue
|
||||
updating the object after calling this function.
|
||||
"""
|
||||
h = self.outer.copy()
|
||||
h.update(self.inner.digest())
|
||||
return h.digest()
|
||||
|
||||
def hexdigest(self):
|
||||
"""Like digest(), but returns a string of hexadecimal digits instead.
|
||||
"""
|
||||
return "".join([string.zfill(hex(ord(x))[2:], 2)
|
||||
for x in tuple(self.digest())])
|
||||
|
||||
def new(key, msg = None, digestmod = None):
|
||||
"""Create a new hashing object and return it.
|
||||
|
||||
key: The starting key for the hash.
|
||||
msg: if available, will immediately be hashed into the object's starting
|
||||
state.
|
||||
|
||||
You can now feed arbitrary strings into the object using its update()
|
||||
method, and can ask for the hash value at any time by calling its digest()
|
||||
method.
|
||||
"""
|
||||
return HMAC(key, msg, digestmod)
|
||||
|
13
python/gdata/Crypto/Hash/MD5.py
Normal file
13
python/gdata/Crypto/Hash/MD5.py
Normal file
@@ -0,0 +1,13 @@
|
||||
|
||||
# Just use the MD5 module from the Python standard library
|
||||
|
||||
__revision__ = "$Id: MD5.py,v 1.4 2002/07/11 14:31:19 akuchling Exp $"
|
||||
|
||||
from md5 import *
|
||||
|
||||
import md5
|
||||
if hasattr(md5, 'digestsize'):
|
||||
digest_size = digestsize
|
||||
del digestsize
|
||||
del md5
|
||||
|
11
python/gdata/Crypto/Hash/SHA.py
Normal file
11
python/gdata/Crypto/Hash/SHA.py
Normal file
@@ -0,0 +1,11 @@
|
||||
|
||||
# Just use the SHA module from the Python standard library
|
||||
|
||||
__revision__ = "$Id: SHA.py,v 1.4 2002/07/11 14:31:19 akuchling Exp $"
|
||||
|
||||
from sha import *
|
||||
import sha
|
||||
if hasattr(sha, 'digestsize'):
|
||||
digest_size = digestsize
|
||||
del digestsize
|
||||
del sha
|
24
python/gdata/Crypto/Hash/__init__.py
Normal file
24
python/gdata/Crypto/Hash/__init__.py
Normal file
@@ -0,0 +1,24 @@
|
||||
"""Hashing algorithms
|
||||
|
||||
Hash functions take arbitrary strings as input, and produce an output
|
||||
of fixed size that is dependent on the input; it should never be
|
||||
possible to derive the input data given only the hash function's
|
||||
output. Hash functions can be used simply as a checksum, or, in
|
||||
association with a public-key algorithm, can be used to implement
|
||||
digital signatures.
|
||||
|
||||
The hashing modules here all support the interface described in PEP
|
||||
247, "API for Cryptographic Hash Functions".
|
||||
|
||||
Submodules:
|
||||
Crypto.Hash.HMAC RFC 2104: Keyed-Hashing for Message Authentication
|
||||
Crypto.Hash.MD2
|
||||
Crypto.Hash.MD4
|
||||
Crypto.Hash.MD5
|
||||
Crypto.Hash.RIPEMD
|
||||
Crypto.Hash.SHA
|
||||
"""
|
||||
|
||||
__all__ = ['HMAC', 'MD2', 'MD4', 'MD5', 'RIPEMD', 'SHA', 'SHA256']
|
||||
__revision__ = "$Id: __init__.py,v 1.6 2003/12/19 14:24:25 akuchling Exp $"
|
||||
|
295
python/gdata/Crypto/Protocol/AllOrNothing.py
Normal file
295
python/gdata/Crypto/Protocol/AllOrNothing.py
Normal file
@@ -0,0 +1,295 @@
|
||||
"""This file implements all-or-nothing package transformations.
|
||||
|
||||
An all-or-nothing package transformation is one in which some text is
|
||||
transformed into message blocks, such that all blocks must be obtained before
|
||||
the reverse transformation can be applied. Thus, if any blocks are corrupted
|
||||
or lost, the original message cannot be reproduced.
|
||||
|
||||
An all-or-nothing package transformation is not encryption, although a block
|
||||
cipher algorithm is used. The encryption key is randomly generated and is
|
||||
extractable from the message blocks.
|
||||
|
||||
This class implements the All-Or-Nothing package transformation algorithm
|
||||
described in:
|
||||
|
||||
Ronald L. Rivest. "All-Or-Nothing Encryption and The Package Transform"
|
||||
http://theory.lcs.mit.edu/~rivest/fusion.pdf
|
||||
|
||||
"""
|
||||
|
||||
__revision__ = "$Id: AllOrNothing.py,v 1.8 2003/02/28 15:23:20 akuchling Exp $"
|
||||
|
||||
import operator
|
||||
import string
|
||||
from Crypto.Util.number import bytes_to_long, long_to_bytes
|
||||
|
||||
|
||||
|
||||
class AllOrNothing:
|
||||
"""Class implementing the All-or-Nothing package transform.
|
||||
|
||||
Methods for subclassing:
|
||||
|
||||
_inventkey(key_size):
|
||||
Returns a randomly generated key. Subclasses can use this to
|
||||
implement better random key generating algorithms. The default
|
||||
algorithm is probably not very cryptographically secure.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, ciphermodule, mode=None, IV=None):
|
||||
"""AllOrNothing(ciphermodule, mode=None, IV=None)
|
||||
|
||||
ciphermodule is a module implementing the cipher algorithm to
|
||||
use. It must provide the PEP272 interface.
|
||||
|
||||
Note that the encryption key is randomly generated
|
||||
automatically when needed. Optional arguments mode and IV are
|
||||
passed directly through to the ciphermodule.new() method; they
|
||||
are the feedback mode and initialization vector to use. All
|
||||
three arguments must be the same for the object used to create
|
||||
the digest, and to undigest'ify the message blocks.
|
||||
"""
|
||||
|
||||
self.__ciphermodule = ciphermodule
|
||||
self.__mode = mode
|
||||
self.__IV = IV
|
||||
self.__key_size = ciphermodule.key_size
|
||||
if self.__key_size == 0:
|
||||
self.__key_size = 16
|
||||
|
||||
__K0digit = chr(0x69)
|
||||
|
||||
def digest(self, text):
|
||||
"""digest(text:string) : [string]
|
||||
|
||||
Perform the All-or-Nothing package transform on the given
|
||||
string. Output is a list of message blocks describing the
|
||||
transformed text, where each block is a string of bit length equal
|
||||
to the ciphermodule's block_size.
|
||||
"""
|
||||
|
||||
# generate a random session key and K0, the key used to encrypt the
|
||||
# hash blocks. Rivest calls this a fixed, publically-known encryption
|
||||
# key, but says nothing about the security implications of this key or
|
||||
# how to choose it.
|
||||
key = self._inventkey(self.__key_size)
|
||||
K0 = self.__K0digit * self.__key_size
|
||||
|
||||
# we need two cipher objects here, one that is used to encrypt the
|
||||
# message blocks and one that is used to encrypt the hashes. The
|
||||
# former uses the randomly generated key, while the latter uses the
|
||||
# well-known key.
|
||||
mcipher = self.__newcipher(key)
|
||||
hcipher = self.__newcipher(K0)
|
||||
|
||||
# Pad the text so that its length is a multiple of the cipher's
|
||||
# block_size. Pad with trailing spaces, which will be eliminated in
|
||||
# the undigest() step.
|
||||
block_size = self.__ciphermodule.block_size
|
||||
padbytes = block_size - (len(text) % block_size)
|
||||
text = text + ' ' * padbytes
|
||||
|
||||
# Run through the algorithm:
|
||||
# s: number of message blocks (size of text / block_size)
|
||||
# input sequence: m1, m2, ... ms
|
||||
# random key K' (`key' in the code)
|
||||
# Compute output sequence: m'1, m'2, ... m's' for s' = s + 1
|
||||
# Let m'i = mi ^ E(K', i) for i = 1, 2, 3, ..., s
|
||||
# Let m's' = K' ^ h1 ^ h2 ^ ... hs
|
||||
# where hi = E(K0, m'i ^ i) for i = 1, 2, ... s
|
||||
#
|
||||
# The one complication I add is that the last message block is hard
|
||||
# coded to the number of padbytes added, so that these can be stripped
|
||||
# during the undigest() step
|
||||
s = len(text) / block_size
|
||||
blocks = []
|
||||
hashes = []
|
||||
for i in range(1, s+1):
|
||||
start = (i-1) * block_size
|
||||
end = start + block_size
|
||||
mi = text[start:end]
|
||||
assert len(mi) == block_size
|
||||
cipherblock = mcipher.encrypt(long_to_bytes(i, block_size))
|
||||
mticki = bytes_to_long(mi) ^ bytes_to_long(cipherblock)
|
||||
blocks.append(mticki)
|
||||
# calculate the hash block for this block
|
||||
hi = hcipher.encrypt(long_to_bytes(mticki ^ i, block_size))
|
||||
hashes.append(bytes_to_long(hi))
|
||||
|
||||
# Add the padbytes length as a message block
|
||||
i = i + 1
|
||||
cipherblock = mcipher.encrypt(long_to_bytes(i, block_size))
|
||||
mticki = padbytes ^ bytes_to_long(cipherblock)
|
||||
blocks.append(mticki)
|
||||
|
||||
# calculate this block's hash
|
||||
hi = hcipher.encrypt(long_to_bytes(mticki ^ i, block_size))
|
||||
hashes.append(bytes_to_long(hi))
|
||||
|
||||
# Now calculate the last message block of the sequence 1..s'. This
|
||||
# will contain the random session key XOR'd with all the hash blocks,
|
||||
# so that for undigest(), once all the hash blocks are calculated, the
|
||||
# session key can be trivially extracted. Calculating all the hash
|
||||
# blocks requires that all the message blocks be received, thus the
|
||||
# All-or-Nothing algorithm succeeds.
|
||||
mtick_stick = bytes_to_long(key) ^ reduce(operator.xor, hashes)
|
||||
blocks.append(mtick_stick)
|
||||
|
||||
# we convert the blocks to strings since in Python, byte sequences are
|
||||
# always represented as strings. This is more consistent with the
|
||||
# model that encryption and hash algorithms always operate on strings.
|
||||
return map(long_to_bytes, blocks)
|
||||
|
||||
|
||||
def undigest(self, blocks):
|
||||
"""undigest(blocks : [string]) : string
|
||||
|
||||
Perform the reverse package transformation on a list of message
|
||||
blocks. Note that the ciphermodule used for both transformations
|
||||
must be the same. blocks is a list of strings of bit length
|
||||
equal to the ciphermodule's block_size.
|
||||
"""
|
||||
|
||||
# better have at least 2 blocks, for the padbytes package and the hash
|
||||
# block accumulator
|
||||
if len(blocks) < 2:
|
||||
raise ValueError, "List must be at least length 2."
|
||||
|
||||
# blocks is a list of strings. We need to deal with them as long
|
||||
# integers
|
||||
blocks = map(bytes_to_long, blocks)
|
||||
|
||||
# Calculate the well-known key, to which the hash blocks are
|
||||
# encrypted, and create the hash cipher.
|
||||
K0 = self.__K0digit * self.__key_size
|
||||
hcipher = self.__newcipher(K0)
|
||||
|
||||
# Since we have all the blocks (or this method would have been called
|
||||
# prematurely), we can calcualte all the hash blocks.
|
||||
hashes = []
|
||||
for i in range(1, len(blocks)):
|
||||
mticki = blocks[i-1] ^ i
|
||||
hi = hcipher.encrypt(long_to_bytes(mticki))
|
||||
hashes.append(bytes_to_long(hi))
|
||||
|
||||
# now we can calculate K' (key). remember the last block contains
|
||||
# m's' which we don't include here
|
||||
key = blocks[-1] ^ reduce(operator.xor, hashes)
|
||||
|
||||
# and now we can create the cipher object
|
||||
mcipher = self.__newcipher(long_to_bytes(key))
|
||||
block_size = self.__ciphermodule.block_size
|
||||
|
||||
# And we can now decode the original message blocks
|
||||
parts = []
|
||||
for i in range(1, len(blocks)):
|
||||
cipherblock = mcipher.encrypt(long_to_bytes(i, block_size))
|
||||
mi = blocks[i-1] ^ bytes_to_long(cipherblock)
|
||||
parts.append(mi)
|
||||
|
||||
# The last message block contains the number of pad bytes appended to
|
||||
# the original text string, such that its length was an even multiple
|
||||
# of the cipher's block_size. This number should be small enough that
|
||||
# the conversion from long integer to integer should never overflow
|
||||
padbytes = int(parts[-1])
|
||||
text = string.join(map(long_to_bytes, parts[:-1]), '')
|
||||
return text[:-padbytes]
|
||||
|
||||
def _inventkey(self, key_size):
|
||||
# TBD: Not a very secure algorithm. Eventually, I'd like to use JHy's
|
||||
# kernelrand module
|
||||
import time
|
||||
from Crypto.Util import randpool
|
||||
# TBD: key_size * 2 to work around possible bug in RandomPool?
|
||||
pool = randpool.RandomPool(key_size * 2)
|
||||
while key_size > pool.entropy:
|
||||
pool.add_event()
|
||||
|
||||
# we now have enough entropy in the pool to get a key_size'd key
|
||||
return pool.get_bytes(key_size)
|
||||
|
||||
def __newcipher(self, key):
|
||||
if self.__mode is None and self.__IV is None:
|
||||
return self.__ciphermodule.new(key)
|
||||
elif self.__IV is None:
|
||||
return self.__ciphermodule.new(key, self.__mode)
|
||||
else:
|
||||
return self.__ciphermodule.new(key, self.__mode, self.__IV)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
import getopt
|
||||
import base64
|
||||
|
||||
usagemsg = '''\
|
||||
Test module usage: %(program)s [-c cipher] [-l] [-h]
|
||||
|
||||
Where:
|
||||
--cipher module
|
||||
-c module
|
||||
Cipher module to use. Default: %(ciphermodule)s
|
||||
|
||||
--aslong
|
||||
-l
|
||||
Print the encoded message blocks as long integers instead of base64
|
||||
encoded strings
|
||||
|
||||
--help
|
||||
-h
|
||||
Print this help message
|
||||
'''
|
||||
|
||||
ciphermodule = 'AES'
|
||||
aslong = 0
|
||||
|
||||
def usage(code, msg=None):
|
||||
if msg:
|
||||
print msg
|
||||
print usagemsg % {'program': sys.argv[0],
|
||||
'ciphermodule': ciphermodule}
|
||||
sys.exit(code)
|
||||
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:],
|
||||
'c:l', ['cipher=', 'aslong'])
|
||||
except getopt.error, msg:
|
||||
usage(1, msg)
|
||||
|
||||
if args:
|
||||
usage(1, 'Too many arguments')
|
||||
|
||||
for opt, arg in opts:
|
||||
if opt in ('-h', '--help'):
|
||||
usage(0)
|
||||
elif opt in ('-c', '--cipher'):
|
||||
ciphermodule = arg
|
||||
elif opt in ('-l', '--aslong'):
|
||||
aslong = 1
|
||||
|
||||
# ugly hack to force __import__ to give us the end-path module
|
||||
module = __import__('Crypto.Cipher.'+ciphermodule, None, None, ['new'])
|
||||
|
||||
a = AllOrNothing(module)
|
||||
print 'Original text:\n=========='
|
||||
print __doc__
|
||||
print '=========='
|
||||
msgblocks = a.digest(__doc__)
|
||||
print 'message blocks:'
|
||||
for i, blk in map(None, range(len(msgblocks)), msgblocks):
|
||||
# base64 adds a trailing newline
|
||||
print ' %3d' % i,
|
||||
if aslong:
|
||||
print bytes_to_long(blk)
|
||||
else:
|
||||
print base64.encodestring(blk)[:-1]
|
||||
#
|
||||
# get a new undigest-only object so there's no leakage
|
||||
b = AllOrNothing(module)
|
||||
text = b.undigest(msgblocks)
|
||||
if text == __doc__:
|
||||
print 'They match!'
|
||||
else:
|
||||
print 'They differ!'
|
229
python/gdata/Crypto/Protocol/Chaffing.py
Normal file
229
python/gdata/Crypto/Protocol/Chaffing.py
Normal file
@@ -0,0 +1,229 @@
|
||||
"""This file implements the chaffing algorithm.
|
||||
|
||||
Winnowing and chaffing is a technique for enhancing privacy without requiring
|
||||
strong encryption. In short, the technique takes a set of authenticated
|
||||
message blocks (the wheat) and adds a number of chaff blocks which have
|
||||
randomly chosen data and MAC fields. This means that to an adversary, the
|
||||
chaff blocks look as valid as the wheat blocks, and so the authentication
|
||||
would have to be performed on every block. By tailoring the number of chaff
|
||||
blocks added to the message, the sender can make breaking the message
|
||||
computationally infeasible. There are many other interesting properties of
|
||||
the winnow/chaff technique.
|
||||
|
||||
For example, say Alice is sending a message to Bob. She packetizes the
|
||||
message and performs an all-or-nothing transformation on the packets. Then
|
||||
she authenticates each packet with a message authentication code (MAC). The
|
||||
MAC is a hash of the data packet, and there is a secret key which she must
|
||||
share with Bob (key distribution is an exercise left to the reader). She then
|
||||
adds a serial number to each packet, and sends the packets to Bob.
|
||||
|
||||
Bob receives the packets, and using the shared secret authentication key,
|
||||
authenticates the MACs for each packet. Those packets that have bad MACs are
|
||||
simply discarded. The remainder are sorted by serial number, and passed
|
||||
through the reverse all-or-nothing transform. The transform means that an
|
||||
eavesdropper (say Eve) must acquire all the packets before any of the data can
|
||||
be read. If even one packet is missing, the data is useless.
|
||||
|
||||
There's one twist: by adding chaff packets, Alice and Bob can make Eve's job
|
||||
much harder, since Eve now has to break the shared secret key, or try every
|
||||
combination of wheat and chaff packet to read any of the message. The cool
|
||||
thing is that Bob doesn't need to add any additional code; the chaff packets
|
||||
are already filtered out because their MACs don't match (in all likelihood --
|
||||
since the data and MACs for the chaff packets are randomly chosen it is
|
||||
possible, but very unlikely that a chaff MAC will match the chaff data). And
|
||||
Alice need not even be the party adding the chaff! She could be completely
|
||||
unaware that a third party, say Charles, is adding chaff packets to her
|
||||
messages as they are transmitted.
|
||||
|
||||
For more information on winnowing and chaffing see this paper:
|
||||
|
||||
Ronald L. Rivest, "Chaffing and Winnowing: Confidentiality without Encryption"
|
||||
http://theory.lcs.mit.edu/~rivest/chaffing.txt
|
||||
|
||||
"""
|
||||
|
||||
__revision__ = "$Id: Chaffing.py,v 1.7 2003/02/28 15:23:21 akuchling Exp $"
|
||||
|
||||
from Crypto.Util.number import bytes_to_long
|
||||
|
||||
class Chaff:
|
||||
"""Class implementing the chaff adding algorithm.
|
||||
|
||||
Methods for subclasses:
|
||||
|
||||
_randnum(size):
|
||||
Returns a randomly generated number with a byte-length equal
|
||||
to size. Subclasses can use this to implement better random
|
||||
data and MAC generating algorithms. The default algorithm is
|
||||
probably not very cryptographically secure. It is most
|
||||
important that the chaff data does not contain any patterns
|
||||
that can be used to discern it from wheat data without running
|
||||
the MAC.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, factor=1.0, blocksper=1):
|
||||
"""Chaff(factor:float, blocksper:int)
|
||||
|
||||
factor is the number of message blocks to add chaff to,
|
||||
expressed as a percentage between 0.0 and 1.0. blocksper is
|
||||
the number of chaff blocks to include for each block being
|
||||
chaffed. Thus the defaults add one chaff block to every
|
||||
message block. By changing the defaults, you can adjust how
|
||||
computationally difficult it could be for an adversary to
|
||||
brute-force crack the message. The difficulty is expressed
|
||||
as:
|
||||
|
||||
pow(blocksper, int(factor * number-of-blocks))
|
||||
|
||||
For ease of implementation, when factor < 1.0, only the first
|
||||
int(factor*number-of-blocks) message blocks are chaffed.
|
||||
"""
|
||||
|
||||
if not (0.0<=factor<=1.0):
|
||||
raise ValueError, "'factor' must be between 0.0 and 1.0"
|
||||
if blocksper < 0:
|
||||
raise ValueError, "'blocksper' must be zero or more"
|
||||
|
||||
self.__factor = factor
|
||||
self.__blocksper = blocksper
|
||||
|
||||
|
||||
def chaff(self, blocks):
|
||||
"""chaff( [(serial-number:int, data:string, MAC:string)] )
|
||||
: [(int, string, string)]
|
||||
|
||||
Add chaff to message blocks. blocks is a list of 3-tuples of the
|
||||
form (serial-number, data, MAC).
|
||||
|
||||
Chaff is created by choosing a random number of the same
|
||||
byte-length as data, and another random number of the same
|
||||
byte-length as MAC. The message block's serial number is
|
||||
placed on the chaff block and all the packet's chaff blocks
|
||||
are randomly interspersed with the single wheat block. This
|
||||
method then returns a list of 3-tuples of the same form.
|
||||
Chaffed blocks will contain multiple instances of 3-tuples
|
||||
with the same serial number, but the only way to figure out
|
||||
which blocks are wheat and which are chaff is to perform the
|
||||
MAC hash and compare values.
|
||||
"""
|
||||
|
||||
chaffedblocks = []
|
||||
|
||||
# count is the number of blocks to add chaff to. blocksper is the
|
||||
# number of chaff blocks to add per message block that is being
|
||||
# chaffed.
|
||||
count = len(blocks) * self.__factor
|
||||
blocksper = range(self.__blocksper)
|
||||
for i, wheat in map(None, range(len(blocks)), blocks):
|
||||
# it shouldn't matter which of the n blocks we add chaff to, so for
|
||||
# ease of implementation, we'll just add them to the first count
|
||||
# blocks
|
||||
if i < count:
|
||||
serial, data, mac = wheat
|
||||
datasize = len(data)
|
||||
macsize = len(mac)
|
||||
addwheat = 1
|
||||
# add chaff to this block
|
||||
for j in blocksper:
|
||||
import sys
|
||||
chaffdata = self._randnum(datasize)
|
||||
chaffmac = self._randnum(macsize)
|
||||
chaff = (serial, chaffdata, chaffmac)
|
||||
# mix up the order, if the 5th bit is on then put the
|
||||
# wheat on the list
|
||||
if addwheat and bytes_to_long(self._randnum(16)) & 0x40:
|
||||
chaffedblocks.append(wheat)
|
||||
addwheat = 0
|
||||
chaffedblocks.append(chaff)
|
||||
if addwheat:
|
||||
chaffedblocks.append(wheat)
|
||||
else:
|
||||
# just add the wheat
|
||||
chaffedblocks.append(wheat)
|
||||
return chaffedblocks
|
||||
|
||||
def _randnum(self, size):
|
||||
# TBD: Not a very secure algorithm.
|
||||
# TBD: size * 2 to work around possible bug in RandomPool
|
||||
from Crypto.Util import randpool
|
||||
import time
|
||||
pool = randpool.RandomPool(size * 2)
|
||||
while size > pool.entropy:
|
||||
pass
|
||||
|
||||
# we now have enough entropy in the pool to get size bytes of random
|
||||
# data... well, probably
|
||||
return pool.get_bytes(size)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
text = """\
|
||||
We hold these truths to be self-evident, that all men are created equal, that
|
||||
they are endowed by their Creator with certain unalienable Rights, that among
|
||||
these are Life, Liberty, and the pursuit of Happiness. That to secure these
|
||||
rights, Governments are instituted among Men, deriving their just powers from
|
||||
the consent of the governed. That whenever any Form of Government becomes
|
||||
destructive of these ends, it is the Right of the People to alter or to
|
||||
abolish it, and to institute new Government, laying its foundation on such
|
||||
principles and organizing its powers in such form, as to them shall seem most
|
||||
likely to effect their Safety and Happiness.
|
||||
"""
|
||||
print 'Original text:\n=========='
|
||||
print text
|
||||
print '=========='
|
||||
|
||||
# first transform the text into packets
|
||||
blocks = [] ; size = 40
|
||||
for i in range(0, len(text), size):
|
||||
blocks.append( text[i:i+size] )
|
||||
|
||||
# now get MACs for all the text blocks. The key is obvious...
|
||||
print 'Calculating MACs...'
|
||||
from Crypto.Hash import HMAC, SHA
|
||||
key = 'Jefferson'
|
||||
macs = [HMAC.new(key, block, digestmod=SHA).digest()
|
||||
for block in blocks]
|
||||
|
||||
assert len(blocks) == len(macs)
|
||||
|
||||
# put these into a form acceptable as input to the chaffing procedure
|
||||
source = []
|
||||
m = map(None, range(len(blocks)), blocks, macs)
|
||||
print m
|
||||
for i, data, mac in m:
|
||||
source.append((i, data, mac))
|
||||
|
||||
# now chaff these
|
||||
print 'Adding chaff...'
|
||||
c = Chaff(factor=0.5, blocksper=2)
|
||||
chaffed = c.chaff(source)
|
||||
|
||||
from base64 import encodestring
|
||||
|
||||
# print the chaffed message blocks. meanwhile, separate the wheat from
|
||||
# the chaff
|
||||
|
||||
wheat = []
|
||||
print 'chaffed message blocks:'
|
||||
for i, data, mac in chaffed:
|
||||
# do the authentication
|
||||
h = HMAC.new(key, data, digestmod=SHA)
|
||||
pmac = h.digest()
|
||||
if pmac == mac:
|
||||
tag = '-->'
|
||||
wheat.append(data)
|
||||
else:
|
||||
tag = ' '
|
||||
# base64 adds a trailing newline
|
||||
print tag, '%3d' % i, \
|
||||
repr(data), encodestring(mac)[:-1]
|
||||
|
||||
# now decode the message packets and check it against the original text
|
||||
print 'Undigesting wheat...'
|
||||
newtext = "".join(wheat)
|
||||
if newtext == text:
|
||||
print 'They match!'
|
||||
else:
|
||||
print 'They differ!'
|
17
python/gdata/Crypto/Protocol/__init__.py
Normal file
17
python/gdata/Crypto/Protocol/__init__.py
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
"""Cryptographic protocols
|
||||
|
||||
Implements various cryptographic protocols. (Don't expect to find
|
||||
network protocols here.)
|
||||
|
||||
Crypto.Protocol.AllOrNothing Transforms a message into a set of message
|
||||
blocks, such that the blocks can be
|
||||
recombined to get the message back.
|
||||
|
||||
Crypto.Protocol.Chaffing Takes a set of authenticated message blocks
|
||||
(the wheat) and adds a number of
|
||||
randomly generated blocks (the chaff).
|
||||
"""
|
||||
|
||||
__all__ = ['AllOrNothing', 'Chaffing']
|
||||
__revision__ = "$Id: __init__.py,v 1.4 2003/02/28 15:23:21 akuchling Exp $"
|
238
python/gdata/Crypto/PublicKey/DSA.py
Normal file
238
python/gdata/Crypto/PublicKey/DSA.py
Normal file
@@ -0,0 +1,238 @@
|
||||
|
||||
#
|
||||
# DSA.py : Digital Signature Algorithm
|
||||
#
|
||||
# Part of the Python Cryptography Toolkit
|
||||
#
|
||||
# Distribute and use freely; there are no restrictions on further
|
||||
# dissemination and usage except those imposed by the laws of your
|
||||
# country of residence. This software is provided "as is" without
|
||||
# warranty of fitness for use or suitability for any purpose, express
|
||||
# or implied. Use at your own risk or not at all.
|
||||
#
|
||||
|
||||
__revision__ = "$Id: DSA.py,v 1.16 2004/05/06 12:52:54 akuchling Exp $"
|
||||
|
||||
from Crypto.PublicKey.pubkey import *
|
||||
from Crypto.Util import number
|
||||
from Crypto.Util.number import bytes_to_long, long_to_bytes
|
||||
from Crypto.Hash import SHA
|
||||
|
||||
try:
|
||||
from Crypto.PublicKey import _fastmath
|
||||
except ImportError:
|
||||
_fastmath = None
|
||||
|
||||
class error (Exception):
|
||||
pass
|
||||
|
||||
def generateQ(randfunc):
|
||||
S=randfunc(20)
|
||||
hash1=SHA.new(S).digest()
|
||||
hash2=SHA.new(long_to_bytes(bytes_to_long(S)+1)).digest()
|
||||
q = bignum(0)
|
||||
for i in range(0,20):
|
||||
c=ord(hash1[i])^ord(hash2[i])
|
||||
if i==0:
|
||||
c=c | 128
|
||||
if i==19:
|
||||
c= c | 1
|
||||
q=q*256+c
|
||||
while (not isPrime(q)):
|
||||
q=q+2
|
||||
if pow(2,159L) < q < pow(2,160L):
|
||||
return S, q
|
||||
raise error, 'Bad q value generated'
|
||||
|
||||
def generate(bits, randfunc, progress_func=None):
|
||||
"""generate(bits:int, randfunc:callable, progress_func:callable)
|
||||
|
||||
Generate a DSA key of length 'bits', using 'randfunc' to get
|
||||
random data and 'progress_func', if present, to display
|
||||
the progress of the key generation.
|
||||
"""
|
||||
|
||||
if bits<160:
|
||||
raise error, 'Key length <160 bits'
|
||||
obj=DSAobj()
|
||||
# Generate string S and prime q
|
||||
if progress_func:
|
||||
progress_func('p,q\n')
|
||||
while (1):
|
||||
S, obj.q = generateQ(randfunc)
|
||||
n=(bits-1)/160
|
||||
C, N, V = 0, 2, {}
|
||||
b=(obj.q >> 5) & 15
|
||||
powb=pow(bignum(2), b)
|
||||
powL1=pow(bignum(2), bits-1)
|
||||
while C<4096:
|
||||
for k in range(0, n+1):
|
||||
V[k]=bytes_to_long(SHA.new(S+str(N)+str(k)).digest())
|
||||
W=V[n] % powb
|
||||
for k in range(n-1, -1, -1):
|
||||
W=(W<<160L)+V[k]
|
||||
X=W+powL1
|
||||
p=X-(X%(2*obj.q)-1)
|
||||
if powL1<=p and isPrime(p):
|
||||
break
|
||||
C, N = C+1, N+n+1
|
||||
if C<4096:
|
||||
break
|
||||
if progress_func:
|
||||
progress_func('4096 multiples failed\n')
|
||||
|
||||
obj.p = p
|
||||
power=(p-1)/obj.q
|
||||
if progress_func:
|
||||
progress_func('h,g\n')
|
||||
while (1):
|
||||
h=bytes_to_long(randfunc(bits)) % (p-1)
|
||||
g=pow(h, power, p)
|
||||
if 1<h<p-1 and g>1:
|
||||
break
|
||||
obj.g=g
|
||||
if progress_func:
|
||||
progress_func('x,y\n')
|
||||
while (1):
|
||||
x=bytes_to_long(randfunc(20))
|
||||
if 0 < x < obj.q:
|
||||
break
|
||||
obj.x, obj.y = x, pow(g, x, p)
|
||||
return obj
|
||||
|
||||
def construct(tuple):
|
||||
"""construct(tuple:(long,long,long,long)|(long,long,long,long,long)):DSAobj
|
||||
Construct a DSA object from a 4- or 5-tuple of numbers.
|
||||
"""
|
||||
obj=DSAobj()
|
||||
if len(tuple) not in [4,5]:
|
||||
raise error, 'argument for construct() wrong length'
|
||||
for i in range(len(tuple)):
|
||||
field = obj.keydata[i]
|
||||
setattr(obj, field, tuple[i])
|
||||
return obj
|
||||
|
||||
class DSAobj(pubkey):
|
||||
keydata=['y', 'g', 'p', 'q', 'x']
|
||||
|
||||
def _encrypt(self, s, Kstr):
|
||||
raise error, 'DSA algorithm cannot encrypt data'
|
||||
|
||||
def _decrypt(self, s):
|
||||
raise error, 'DSA algorithm cannot decrypt data'
|
||||
|
||||
def _sign(self, M, K):
|
||||
if (K<2 or self.q<=K):
|
||||
raise error, 'K is not between 2 and q'
|
||||
r=pow(self.g, K, self.p) % self.q
|
||||
s=(inverse(K, self.q)*(M+self.x*r)) % self.q
|
||||
return (r,s)
|
||||
|
||||
def _verify(self, M, sig):
|
||||
r, s = sig
|
||||
if r<=0 or r>=self.q or s<=0 or s>=self.q:
|
||||
return 0
|
||||
w=inverse(s, self.q)
|
||||
u1, u2 = (M*w) % self.q, (r*w) % self.q
|
||||
v1 = pow(self.g, u1, self.p)
|
||||
v2 = pow(self.y, u2, self.p)
|
||||
v = ((v1*v2) % self.p)
|
||||
v = v % self.q
|
||||
if v==r:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def size(self):
|
||||
"Return the maximum number of bits that can be handled by this key."
|
||||
return number.size(self.p) - 1
|
||||
|
||||
def has_private(self):
|
||||
"""Return a Boolean denoting whether the object contains
|
||||
private components."""
|
||||
if hasattr(self, 'x'):
|
||||
return 1
|
||||
else:
|
||||
return 0
|
||||
|
||||
def can_sign(self):
|
||||
"""Return a Boolean value recording whether this algorithm can generate signatures."""
|
||||
return 1
|
||||
|
||||
def can_encrypt(self):
|
||||
"""Return a Boolean value recording whether this algorithm can encrypt data."""
|
||||
return 0
|
||||
|
||||
def publickey(self):
|
||||
"""Return a new key object containing only the public information."""
|
||||
return construct((self.y, self.g, self.p, self.q))
|
||||
|
||||
object=DSAobj
|
||||
|
||||
generate_py = generate
|
||||
construct_py = construct
|
||||
|
||||
class DSAobj_c(pubkey):
|
||||
keydata = ['y', 'g', 'p', 'q', 'x']
|
||||
|
||||
def __init__(self, key):
|
||||
self.key = key
|
||||
|
||||
def __getattr__(self, attr):
|
||||
if attr in self.keydata:
|
||||
return getattr(self.key, attr)
|
||||
else:
|
||||
if self.__dict__.has_key(attr):
|
||||
self.__dict__[attr]
|
||||
else:
|
||||
raise AttributeError, '%s instance has no attribute %s' % (self.__class__, attr)
|
||||
|
||||
def __getstate__(self):
|
||||
d = {}
|
||||
for k in self.keydata:
|
||||
if hasattr(self.key, k):
|
||||
d[k]=getattr(self.key, k)
|
||||
return d
|
||||
|
||||
def __setstate__(self, state):
|
||||
y,g,p,q = state['y'], state['g'], state['p'], state['q']
|
||||
if not state.has_key('x'):
|
||||
self.key = _fastmath.dsa_construct(y,g,p,q)
|
||||
else:
|
||||
x = state['x']
|
||||
self.key = _fastmath.dsa_construct(y,g,p,q,x)
|
||||
|
||||
def _sign(self, M, K):
|
||||
return self.key._sign(M, K)
|
||||
|
||||
def _verify(self, M, (r, s)):
|
||||
return self.key._verify(M, r, s)
|
||||
|
||||
def size(self):
|
||||
return self.key.size()
|
||||
|
||||
def has_private(self):
|
||||
return self.key.has_private()
|
||||
|
||||
def publickey(self):
|
||||
return construct_c((self.key.y, self.key.g, self.key.p, self.key.q))
|
||||
|
||||
def can_sign(self):
|
||||
return 1
|
||||
|
||||
def can_encrypt(self):
|
||||
return 0
|
||||
|
||||
def generate_c(bits, randfunc, progress_func=None):
|
||||
obj = generate_py(bits, randfunc, progress_func)
|
||||
y,g,p,q,x = obj.y, obj.g, obj.p, obj.q, obj.x
|
||||
return construct_c((y,g,p,q,x))
|
||||
|
||||
def construct_c(tuple):
|
||||
key = apply(_fastmath.dsa_construct, tuple)
|
||||
return DSAobj_c(key)
|
||||
|
||||
if _fastmath:
|
||||
#print "using C version of DSA"
|
||||
generate = generate_c
|
||||
construct = construct_c
|
||||
error = _fastmath.error
|
132
python/gdata/Crypto/PublicKey/ElGamal.py
Normal file
132
python/gdata/Crypto/PublicKey/ElGamal.py
Normal file
@@ -0,0 +1,132 @@
|
||||
#
|
||||
# ElGamal.py : ElGamal encryption/decryption and signatures
|
||||
#
|
||||
# Part of the Python Cryptography Toolkit
|
||||
#
|
||||
# Distribute and use freely; there are no restrictions on further
|
||||
# dissemination and usage except those imposed by the laws of your
|
||||
# country of residence. This software is provided "as is" without
|
||||
# warranty of fitness for use or suitability for any purpose, express
|
||||
# or implied. Use at your own risk or not at all.
|
||||
#
|
||||
|
||||
__revision__ = "$Id: ElGamal.py,v 1.9 2003/04/04 19:44:26 akuchling Exp $"
|
||||
|
||||
from Crypto.PublicKey.pubkey import *
|
||||
from Crypto.Util import number
|
||||
|
||||
class error (Exception):
|
||||
pass
|
||||
|
||||
# Generate an ElGamal key with N bits
|
||||
def generate(bits, randfunc, progress_func=None):
|
||||
"""generate(bits:int, randfunc:callable, progress_func:callable)
|
||||
|
||||
Generate an ElGamal key of length 'bits', using 'randfunc' to get
|
||||
random data and 'progress_func', if present, to display
|
||||
the progress of the key generation.
|
||||
"""
|
||||
obj=ElGamalobj()
|
||||
# Generate prime p
|
||||
if progress_func:
|
||||
progress_func('p\n')
|
||||
obj.p=bignum(getPrime(bits, randfunc))
|
||||
# Generate random number g
|
||||
if progress_func:
|
||||
progress_func('g\n')
|
||||
size=bits-1-(ord(randfunc(1)) & 63) # g will be from 1--64 bits smaller than p
|
||||
if size<1:
|
||||
size=bits-1
|
||||
while (1):
|
||||
obj.g=bignum(getPrime(size, randfunc))
|
||||
if obj.g < obj.p:
|
||||
break
|
||||
size=(size+1) % bits
|
||||
if size==0:
|
||||
size=4
|
||||
# Generate random number x
|
||||
if progress_func:
|
||||
progress_func('x\n')
|
||||
while (1):
|
||||
size=bits-1-ord(randfunc(1)) # x will be from 1 to 256 bits smaller than p
|
||||
if size>2:
|
||||
break
|
||||
while (1):
|
||||
obj.x=bignum(getPrime(size, randfunc))
|
||||
if obj.x < obj.p:
|
||||
break
|
||||
size = (size+1) % bits
|
||||
if size==0:
|
||||
size=4
|
||||
if progress_func:
|
||||
progress_func('y\n')
|
||||
obj.y = pow(obj.g, obj.x, obj.p)
|
||||
return obj
|
||||
|
||||
def construct(tuple):
|
||||
"""construct(tuple:(long,long,long,long)|(long,long,long,long,long)))
|
||||
: ElGamalobj
|
||||
Construct an ElGamal key from a 3- or 4-tuple of numbers.
|
||||
"""
|
||||
|
||||
obj=ElGamalobj()
|
||||
if len(tuple) not in [3,4]:
|
||||
raise error, 'argument for construct() wrong length'
|
||||
for i in range(len(tuple)):
|
||||
field = obj.keydata[i]
|
||||
setattr(obj, field, tuple[i])
|
||||
return obj
|
||||
|
||||
class ElGamalobj(pubkey):
|
||||
keydata=['p', 'g', 'y', 'x']
|
||||
|
||||
def _encrypt(self, M, K):
|
||||
a=pow(self.g, K, self.p)
|
||||
b=( M*pow(self.y, K, self.p) ) % self.p
|
||||
return ( a,b )
|
||||
|
||||
def _decrypt(self, M):
|
||||
if (not hasattr(self, 'x')):
|
||||
raise error, 'Private key not available in this object'
|
||||
ax=pow(M[0], self.x, self.p)
|
||||
plaintext=(M[1] * inverse(ax, self.p ) ) % self.p
|
||||
return plaintext
|
||||
|
||||
def _sign(self, M, K):
|
||||
if (not hasattr(self, 'x')):
|
||||
raise error, 'Private key not available in this object'
|
||||
p1=self.p-1
|
||||
if (GCD(K, p1)!=1):
|
||||
raise error, 'Bad K value: GCD(K,p-1)!=1'
|
||||
a=pow(self.g, K, self.p)
|
||||
t=(M-self.x*a) % p1
|
||||
while t<0: t=t+p1
|
||||
b=(t*inverse(K, p1)) % p1
|
||||
return (a, b)
|
||||
|
||||
def _verify(self, M, sig):
|
||||
v1=pow(self.y, sig[0], self.p)
|
||||
v1=(v1*pow(sig[0], sig[1], self.p)) % self.p
|
||||
v2=pow(self.g, M, self.p)
|
||||
if v1==v2:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def size(self):
|
||||
"Return the maximum number of bits that can be handled by this key."
|
||||
return number.size(self.p) - 1
|
||||
|
||||
def has_private(self):
|
||||
"""Return a Boolean denoting whether the object contains
|
||||
private components."""
|
||||
if hasattr(self, 'x'):
|
||||
return 1
|
||||
else:
|
||||
return 0
|
||||
|
||||
def publickey(self):
|
||||
"""Return a new key object containing only the public information."""
|
||||
return construct((self.p, self.g, self.y))
|
||||
|
||||
|
||||
object=ElGamalobj
|
256
python/gdata/Crypto/PublicKey/RSA.py
Normal file
256
python/gdata/Crypto/PublicKey/RSA.py
Normal file
@@ -0,0 +1,256 @@
|
||||
#
|
||||
# RSA.py : RSA encryption/decryption
|
||||
#
|
||||
# Part of the Python Cryptography Toolkit
|
||||
#
|
||||
# Distribute and use freely; there are no restrictions on further
|
||||
# dissemination and usage except those imposed by the laws of your
|
||||
# country of residence. This software is provided "as is" without
|
||||
# warranty of fitness for use or suitability for any purpose, express
|
||||
# or implied. Use at your own risk or not at all.
|
||||
#
|
||||
|
||||
__revision__ = "$Id: RSA.py,v 1.20 2004/05/06 12:52:54 akuchling Exp $"
|
||||
|
||||
from Crypto.PublicKey import pubkey
|
||||
from Crypto.Util import number
|
||||
|
||||
try:
|
||||
from Crypto.PublicKey import _fastmath
|
||||
except ImportError:
|
||||
_fastmath = None
|
||||
|
||||
class error (Exception):
|
||||
pass
|
||||
|
||||
def generate(bits, randfunc, progress_func=None):
|
||||
"""generate(bits:int, randfunc:callable, progress_func:callable)
|
||||
|
||||
Generate an RSA key of length 'bits', using 'randfunc' to get
|
||||
random data and 'progress_func', if present, to display
|
||||
the progress of the key generation.
|
||||
"""
|
||||
obj=RSAobj()
|
||||
|
||||
# Generate the prime factors of n
|
||||
if progress_func:
|
||||
progress_func('p,q\n')
|
||||
p = q = 1L
|
||||
while number.size(p*q) < bits:
|
||||
p = pubkey.getPrime(bits/2, randfunc)
|
||||
q = pubkey.getPrime(bits/2, randfunc)
|
||||
|
||||
# p shall be smaller than q (for calc of u)
|
||||
if p > q:
|
||||
(p, q)=(q, p)
|
||||
obj.p = p
|
||||
obj.q = q
|
||||
|
||||
if progress_func:
|
||||
progress_func('u\n')
|
||||
obj.u = pubkey.inverse(obj.p, obj.q)
|
||||
obj.n = obj.p*obj.q
|
||||
|
||||
obj.e = 65537L
|
||||
if progress_func:
|
||||
progress_func('d\n')
|
||||
obj.d=pubkey.inverse(obj.e, (obj.p-1)*(obj.q-1))
|
||||
|
||||
assert bits <= 1+obj.size(), "Generated key is too small"
|
||||
|
||||
return obj
|
||||
|
||||
def construct(tuple):
|
||||
"""construct(tuple:(long,) : RSAobj
|
||||
Construct an RSA object from a 2-, 3-, 5-, or 6-tuple of numbers.
|
||||
"""
|
||||
|
||||
obj=RSAobj()
|
||||
if len(tuple) not in [2,3,5,6]:
|
||||
raise error, 'argument for construct() wrong length'
|
||||
for i in range(len(tuple)):
|
||||
field = obj.keydata[i]
|
||||
setattr(obj, field, tuple[i])
|
||||
if len(tuple) >= 5:
|
||||
# Ensure p is smaller than q
|
||||
if obj.p>obj.q:
|
||||
(obj.p, obj.q)=(obj.q, obj.p)
|
||||
|
||||
if len(tuple) == 5:
|
||||
# u not supplied, so we're going to have to compute it.
|
||||
obj.u=pubkey.inverse(obj.p, obj.q)
|
||||
|
||||
return obj
|
||||
|
||||
class RSAobj(pubkey.pubkey):
|
||||
keydata = ['n', 'e', 'd', 'p', 'q', 'u']
|
||||
def _encrypt(self, plaintext, K=''):
|
||||
if self.n<=plaintext:
|
||||
raise error, 'Plaintext too large'
|
||||
return (pow(plaintext, self.e, self.n),)
|
||||
|
||||
def _decrypt(self, ciphertext):
|
||||
if (not hasattr(self, 'd')):
|
||||
raise error, 'Private key not available in this object'
|
||||
if self.n<=ciphertext[0]:
|
||||
raise error, 'Ciphertext too large'
|
||||
return pow(ciphertext[0], self.d, self.n)
|
||||
|
||||
def _sign(self, M, K=''):
|
||||
return (self._decrypt((M,)),)
|
||||
|
||||
def _verify(self, M, sig):
|
||||
m2=self._encrypt(sig[0])
|
||||
if m2[0]==M:
|
||||
return 1
|
||||
else: return 0
|
||||
|
||||
def _blind(self, M, B):
|
||||
tmp = pow(B, self.e, self.n)
|
||||
return (M * tmp) % self.n
|
||||
|
||||
def _unblind(self, M, B):
|
||||
tmp = pubkey.inverse(B, self.n)
|
||||
return (M * tmp) % self.n
|
||||
|
||||
def can_blind (self):
|
||||
"""can_blind() : bool
|
||||
Return a Boolean value recording whether this algorithm can
|
||||
blind data. (This does not imply that this
|
||||
particular key object has the private information required to
|
||||
to blind a message.)
|
||||
"""
|
||||
return 1
|
||||
|
||||
def size(self):
|
||||
"""size() : int
|
||||
Return the maximum number of bits that can be handled by this key.
|
||||
"""
|
||||
return number.size(self.n) - 1
|
||||
|
||||
def has_private(self):
|
||||
"""has_private() : bool
|
||||
Return a Boolean denoting whether the object contains
|
||||
private components.
|
||||
"""
|
||||
if hasattr(self, 'd'):
|
||||
return 1
|
||||
else: return 0
|
||||
|
||||
def publickey(self):
|
||||
"""publickey(): RSAobj
|
||||
Return a new key object containing only the public key information.
|
||||
"""
|
||||
return construct((self.n, self.e))
|
||||
|
||||
class RSAobj_c(pubkey.pubkey):
|
||||
keydata = ['n', 'e', 'd', 'p', 'q', 'u']
|
||||
|
||||
def __init__(self, key):
|
||||
self.key = key
|
||||
|
||||
def __getattr__(self, attr):
|
||||
if attr in self.keydata:
|
||||
return getattr(self.key, attr)
|
||||
else:
|
||||
if self.__dict__.has_key(attr):
|
||||
self.__dict__[attr]
|
||||
else:
|
||||
raise AttributeError, '%s instance has no attribute %s' % (self.__class__, attr)
|
||||
|
||||
def __getstate__(self):
|
||||
d = {}
|
||||
for k in self.keydata:
|
||||
if hasattr(self.key, k):
|
||||
d[k]=getattr(self.key, k)
|
||||
return d
|
||||
|
||||
def __setstate__(self, state):
|
||||
n,e = state['n'], state['e']
|
||||
if not state.has_key('d'):
|
||||
self.key = _fastmath.rsa_construct(n,e)
|
||||
else:
|
||||
d = state['d']
|
||||
if not state.has_key('q'):
|
||||
self.key = _fastmath.rsa_construct(n,e,d)
|
||||
else:
|
||||
p, q, u = state['p'], state['q'], state['u']
|
||||
self.key = _fastmath.rsa_construct(n,e,d,p,q,u)
|
||||
|
||||
def _encrypt(self, plain, K):
|
||||
return (self.key._encrypt(plain),)
|
||||
|
||||
def _decrypt(self, cipher):
|
||||
return self.key._decrypt(cipher[0])
|
||||
|
||||
def _sign(self, M, K):
|
||||
return (self.key._sign(M),)
|
||||
|
||||
def _verify(self, M, sig):
|
||||
return self.key._verify(M, sig[0])
|
||||
|
||||
def _blind(self, M, B):
|
||||
return self.key._blind(M, B)
|
||||
|
||||
def _unblind(self, M, B):
|
||||
return self.key._unblind(M, B)
|
||||
|
||||
def can_blind (self):
|
||||
return 1
|
||||
|
||||
def size(self):
|
||||
return self.key.size()
|
||||
|
||||
def has_private(self):
|
||||
return self.key.has_private()
|
||||
|
||||
def publickey(self):
|
||||
return construct_c((self.key.n, self.key.e))
|
||||
|
||||
def generate_c(bits, randfunc, progress_func = None):
|
||||
# Generate the prime factors of n
|
||||
if progress_func:
|
||||
progress_func('p,q\n')
|
||||
|
||||
p = q = 1L
|
||||
while number.size(p*q) < bits:
|
||||
p = pubkey.getPrime(bits/2, randfunc)
|
||||
q = pubkey.getPrime(bits/2, randfunc)
|
||||
|
||||
# p shall be smaller than q (for calc of u)
|
||||
if p > q:
|
||||
(p, q)=(q, p)
|
||||
if progress_func:
|
||||
progress_func('u\n')
|
||||
u=pubkey.inverse(p, q)
|
||||
n=p*q
|
||||
|
||||
e = 65537L
|
||||
if progress_func:
|
||||
progress_func('d\n')
|
||||
d=pubkey.inverse(e, (p-1)*(q-1))
|
||||
key = _fastmath.rsa_construct(n,e,d,p,q,u)
|
||||
obj = RSAobj_c(key)
|
||||
|
||||
## print p
|
||||
## print q
|
||||
## print number.size(p), number.size(q), number.size(q*p),
|
||||
## print obj.size(), bits
|
||||
assert bits <= 1+obj.size(), "Generated key is too small"
|
||||
return obj
|
||||
|
||||
|
||||
def construct_c(tuple):
|
||||
key = apply(_fastmath.rsa_construct, tuple)
|
||||
return RSAobj_c(key)
|
||||
|
||||
object = RSAobj
|
||||
|
||||
generate_py = generate
|
||||
construct_py = construct
|
||||
|
||||
if _fastmath:
|
||||
#print "using C version of RSA"
|
||||
generate = generate_c
|
||||
construct = construct_c
|
||||
error = _fastmath.error
|
17
python/gdata/Crypto/PublicKey/__init__.py
Normal file
17
python/gdata/Crypto/PublicKey/__init__.py
Normal file
@@ -0,0 +1,17 @@
|
||||
"""Public-key encryption and signature algorithms.
|
||||
|
||||
Public-key encryption uses two different keys, one for encryption and
|
||||
one for decryption. The encryption key can be made public, and the
|
||||
decryption key is kept private. Many public-key algorithms can also
|
||||
be used to sign messages, and some can *only* be used for signatures.
|
||||
|
||||
Crypto.PublicKey.DSA Digital Signature Algorithm. (Signature only)
|
||||
Crypto.PublicKey.ElGamal (Signing and encryption)
|
||||
Crypto.PublicKey.RSA (Signing, encryption, and blinding)
|
||||
Crypto.PublicKey.qNEW (Signature only)
|
||||
|
||||
"""
|
||||
|
||||
__all__ = ['RSA', 'DSA', 'ElGamal', 'qNEW']
|
||||
__revision__ = "$Id: __init__.py,v 1.4 2003/04/03 20:27:13 akuchling Exp $"
|
||||
|
172
python/gdata/Crypto/PublicKey/pubkey.py
Normal file
172
python/gdata/Crypto/PublicKey/pubkey.py
Normal file
@@ -0,0 +1,172 @@
|
||||
#
|
||||
# pubkey.py : Internal functions for public key operations
|
||||
#
|
||||
# Part of the Python Cryptography Toolkit
|
||||
#
|
||||
# Distribute and use freely; there are no restrictions on further
|
||||
# dissemination and usage except those imposed by the laws of your
|
||||
# country of residence. This software is provided "as is" without
|
||||
# warranty of fitness for use or suitability for any purpose, express
|
||||
# or implied. Use at your own risk or not at all.
|
||||
#
|
||||
|
||||
__revision__ = "$Id: pubkey.py,v 1.11 2003/04/03 20:36:14 akuchling Exp $"
|
||||
|
||||
import types, warnings
|
||||
from Crypto.Util.number import *
|
||||
|
||||
# Basic public key class
|
||||
class pubkey:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def __getstate__(self):
|
||||
"""To keep key objects platform-independent, the key data is
|
||||
converted to standard Python long integers before being
|
||||
written out. It will then be reconverted as necessary on
|
||||
restoration."""
|
||||
d=self.__dict__
|
||||
for key in self.keydata:
|
||||
if d.has_key(key): d[key]=long(d[key])
|
||||
return d
|
||||
|
||||
def __setstate__(self, d):
|
||||
"""On unpickling a key object, the key data is converted to the big
|
||||
number representation being used, whether that is Python long
|
||||
integers, MPZ objects, or whatever."""
|
||||
for key in self.keydata:
|
||||
if d.has_key(key): self.__dict__[key]=bignum(d[key])
|
||||
|
||||
def encrypt(self, plaintext, K):
|
||||
"""encrypt(plaintext:string|long, K:string|long) : tuple
|
||||
Encrypt the string or integer plaintext. K is a random
|
||||
parameter required by some algorithms.
|
||||
"""
|
||||
wasString=0
|
||||
if isinstance(plaintext, types.StringType):
|
||||
plaintext=bytes_to_long(plaintext) ; wasString=1
|
||||
if isinstance(K, types.StringType):
|
||||
K=bytes_to_long(K)
|
||||
ciphertext=self._encrypt(plaintext, K)
|
||||
if wasString: return tuple(map(long_to_bytes, ciphertext))
|
||||
else: return ciphertext
|
||||
|
||||
def decrypt(self, ciphertext):
|
||||
"""decrypt(ciphertext:tuple|string|long): string
|
||||
Decrypt 'ciphertext' using this key.
|
||||
"""
|
||||
wasString=0
|
||||
if not isinstance(ciphertext, types.TupleType):
|
||||
ciphertext=(ciphertext,)
|
||||
if isinstance(ciphertext[0], types.StringType):
|
||||
ciphertext=tuple(map(bytes_to_long, ciphertext)) ; wasString=1
|
||||
plaintext=self._decrypt(ciphertext)
|
||||
if wasString: return long_to_bytes(plaintext)
|
||||
else: return plaintext
|
||||
|
||||
def sign(self, M, K):
|
||||
"""sign(M : string|long, K:string|long) : tuple
|
||||
Return a tuple containing the signature for the message M.
|
||||
K is a random parameter required by some algorithms.
|
||||
"""
|
||||
if (not self.has_private()):
|
||||
raise error, 'Private key not available in this object'
|
||||
if isinstance(M, types.StringType): M=bytes_to_long(M)
|
||||
if isinstance(K, types.StringType): K=bytes_to_long(K)
|
||||
return self._sign(M, K)
|
||||
|
||||
def verify (self, M, signature):
|
||||
"""verify(M:string|long, signature:tuple) : bool
|
||||
Verify that the signature is valid for the message M;
|
||||
returns true if the signature checks out.
|
||||
"""
|
||||
if isinstance(M, types.StringType): M=bytes_to_long(M)
|
||||
return self._verify(M, signature)
|
||||
|
||||
# alias to compensate for the old validate() name
|
||||
def validate (self, M, signature):
|
||||
warnings.warn("validate() method name is obsolete; use verify()",
|
||||
DeprecationWarning)
|
||||
|
||||
def blind(self, M, B):
|
||||
"""blind(M : string|long, B : string|long) : string|long
|
||||
Blind message M using blinding factor B.
|
||||
"""
|
||||
wasString=0
|
||||
if isinstance(M, types.StringType):
|
||||
M=bytes_to_long(M) ; wasString=1
|
||||
if isinstance(B, types.StringType): B=bytes_to_long(B)
|
||||
blindedmessage=self._blind(M, B)
|
||||
if wasString: return long_to_bytes(blindedmessage)
|
||||
else: return blindedmessage
|
||||
|
||||
def unblind(self, M, B):
|
||||
"""unblind(M : string|long, B : string|long) : string|long
|
||||
Unblind message M using blinding factor B.
|
||||
"""
|
||||
wasString=0
|
||||
if isinstance(M, types.StringType):
|
||||
M=bytes_to_long(M) ; wasString=1
|
||||
if isinstance(B, types.StringType): B=bytes_to_long(B)
|
||||
unblindedmessage=self._unblind(M, B)
|
||||
if wasString: return long_to_bytes(unblindedmessage)
|
||||
else: return unblindedmessage
|
||||
|
||||
|
||||
# The following methods will usually be left alone, except for
|
||||
# signature-only algorithms. They both return Boolean values
|
||||
# recording whether this key's algorithm can sign and encrypt.
|
||||
def can_sign (self):
|
||||
"""can_sign() : bool
|
||||
Return a Boolean value recording whether this algorithm can
|
||||
generate signatures. (This does not imply that this
|
||||
particular key object has the private information required to
|
||||
to generate a signature.)
|
||||
"""
|
||||
return 1
|
||||
|
||||
def can_encrypt (self):
|
||||
"""can_encrypt() : bool
|
||||
Return a Boolean value recording whether this algorithm can
|
||||
encrypt data. (This does not imply that this
|
||||
particular key object has the private information required to
|
||||
to decrypt a message.)
|
||||
"""
|
||||
return 1
|
||||
|
||||
def can_blind (self):
|
||||
"""can_blind() : bool
|
||||
Return a Boolean value recording whether this algorithm can
|
||||
blind data. (This does not imply that this
|
||||
particular key object has the private information required to
|
||||
to blind a message.)
|
||||
"""
|
||||
return 0
|
||||
|
||||
# The following methods will certainly be overridden by
|
||||
# subclasses.
|
||||
|
||||
def size (self):
|
||||
"""size() : int
|
||||
Return the maximum number of bits that can be handled by this key.
|
||||
"""
|
||||
return 0
|
||||
|
||||
def has_private (self):
|
||||
"""has_private() : bool
|
||||
Return a Boolean denoting whether the object contains
|
||||
private components.
|
||||
"""
|
||||
return 0
|
||||
|
||||
def publickey (self):
|
||||
"""publickey(): object
|
||||
Return a new key object containing only the public information.
|
||||
"""
|
||||
return self
|
||||
|
||||
def __eq__ (self, other):
|
||||
"""__eq__(other): 0, 1
|
||||
Compare us to other for equality.
|
||||
"""
|
||||
return self.__getstate__() == other.__getstate__()
|
170
python/gdata/Crypto/PublicKey/qNEW.py
Normal file
170
python/gdata/Crypto/PublicKey/qNEW.py
Normal file
@@ -0,0 +1,170 @@
|
||||
#
|
||||
# qNEW.py : The q-NEW signature algorithm.
|
||||
#
|
||||
# Part of the Python Cryptography Toolkit
|
||||
#
|
||||
# Distribute and use freely; there are no restrictions on further
|
||||
# dissemination and usage except those imposed by the laws of your
|
||||
# country of residence. This software is provided "as is" without
|
||||
# warranty of fitness for use or suitability for any purpose, express
|
||||
# or implied. Use at your own risk or not at all.
|
||||
#
|
||||
|
||||
__revision__ = "$Id: qNEW.py,v 1.8 2003/04/04 15:13:35 akuchling Exp $"
|
||||
|
||||
from Crypto.PublicKey import pubkey
|
||||
from Crypto.Util.number import *
|
||||
from Crypto.Hash import SHA
|
||||
|
||||
class error (Exception):
|
||||
pass
|
||||
|
||||
HASHBITS = 160 # Size of SHA digests
|
||||
|
||||
def generate(bits, randfunc, progress_func=None):
|
||||
"""generate(bits:int, randfunc:callable, progress_func:callable)
|
||||
|
||||
Generate a qNEW key of length 'bits', using 'randfunc' to get
|
||||
random data and 'progress_func', if present, to display
|
||||
the progress of the key generation.
|
||||
"""
|
||||
obj=qNEWobj()
|
||||
|
||||
# Generate prime numbers p and q. q is a 160-bit prime
|
||||
# number. p is another prime number (the modulus) whose bit
|
||||
# size is chosen by the caller, and is generated so that p-1
|
||||
# is a multiple of q.
|
||||
#
|
||||
# Note that only a single seed is used to
|
||||
# generate p and q; if someone generates a key for you, you can
|
||||
# use the seed to duplicate the key generation. This can
|
||||
# protect you from someone generating values of p,q that have
|
||||
# some special form that's easy to break.
|
||||
if progress_func:
|
||||
progress_func('p,q\n')
|
||||
while (1):
|
||||
obj.q = getPrime(160, randfunc)
|
||||
# assert pow(2, 159L)<obj.q<pow(2, 160L)
|
||||
obj.seed = S = long_to_bytes(obj.q)
|
||||
C, N, V = 0, 2, {}
|
||||
# Compute b and n such that bits-1 = b + n*HASHBITS
|
||||
n= (bits-1) / HASHBITS
|
||||
b= (bits-1) % HASHBITS ; powb=2L << b
|
||||
powL1=pow(long(2), bits-1)
|
||||
while C<4096:
|
||||
# The V array will contain (bits-1) bits of random
|
||||
# data, that are assembled to produce a candidate
|
||||
# value for p.
|
||||
for k in range(0, n+1):
|
||||
V[k]=bytes_to_long(SHA.new(S+str(N)+str(k)).digest())
|
||||
p = V[n] % powb
|
||||
for k in range(n-1, -1, -1):
|
||||
p= (p << long(HASHBITS) )+V[k]
|
||||
p = p+powL1 # Ensure the high bit is set
|
||||
|
||||
# Ensure that p-1 is a multiple of q
|
||||
p = p - (p % (2*obj.q)-1)
|
||||
|
||||
# If p is still the right size, and it's prime, we're done!
|
||||
if powL1<=p and isPrime(p):
|
||||
break
|
||||
|
||||
# Otherwise, increment the counter and try again
|
||||
C, N = C+1, N+n+1
|
||||
if C<4096:
|
||||
break # Ended early, so exit the while loop
|
||||
if progress_func:
|
||||
progress_func('4096 values of p tried\n')
|
||||
|
||||
obj.p = p
|
||||
power=(p-1)/obj.q
|
||||
|
||||
# Next parameter: g = h**((p-1)/q) mod p, such that h is any
|
||||
# number <p-1, and g>1. g is kept; h can be discarded.
|
||||
if progress_func:
|
||||
progress_func('h,g\n')
|
||||
while (1):
|
||||
h=bytes_to_long(randfunc(bits)) % (p-1)
|
||||
g=pow(h, power, p)
|
||||
if 1<h<p-1 and g>1:
|
||||
break
|
||||
obj.g=g
|
||||
|
||||
# x is the private key information, and is
|
||||
# just a random number between 0 and q.
|
||||
# y=g**x mod p, and is part of the public information.
|
||||
if progress_func:
|
||||
progress_func('x,y\n')
|
||||
while (1):
|
||||
x=bytes_to_long(randfunc(20))
|
||||
if 0 < x < obj.q:
|
||||
break
|
||||
obj.x, obj.y=x, pow(g, x, p)
|
||||
|
||||
return obj
|
||||
|
||||
# Construct a qNEW object
|
||||
def construct(tuple):
|
||||
"""construct(tuple:(long,long,long,long)|(long,long,long,long,long)
|
||||
Construct a qNEW object from a 4- or 5-tuple of numbers.
|
||||
"""
|
||||
obj=qNEWobj()
|
||||
if len(tuple) not in [4,5]:
|
||||
raise error, 'argument for construct() wrong length'
|
||||
for i in range(len(tuple)):
|
||||
field = obj.keydata[i]
|
||||
setattr(obj, field, tuple[i])
|
||||
return obj
|
||||
|
||||
class qNEWobj(pubkey.pubkey):
|
||||
keydata=['p', 'q', 'g', 'y', 'x']
|
||||
|
||||
def _sign(self, M, K=''):
|
||||
if (self.q<=K):
|
||||
raise error, 'K is greater than q'
|
||||
if M<0:
|
||||
raise error, 'Illegal value of M (<0)'
|
||||
if M>=pow(2,161L):
|
||||
raise error, 'Illegal value of M (too large)'
|
||||
r=pow(self.g, K, self.p) % self.q
|
||||
s=(K- (r*M*self.x % self.q)) % self.q
|
||||
return (r,s)
|
||||
def _verify(self, M, sig):
|
||||
r, s = sig
|
||||
if r<=0 or r>=self.q or s<=0 or s>=self.q:
|
||||
return 0
|
||||
if M<0:
|
||||
raise error, 'Illegal value of M (<0)'
|
||||
if M<=0 or M>=pow(2,161L):
|
||||
return 0
|
||||
v1 = pow(self.g, s, self.p)
|
||||
v2 = pow(self.y, M*r, self.p)
|
||||
v = ((v1*v2) % self.p)
|
||||
v = v % self.q
|
||||
if v==r:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def size(self):
|
||||
"Return the maximum number of bits that can be handled by this key."
|
||||
return 160
|
||||
|
||||
def has_private(self):
|
||||
"""Return a Boolean denoting whether the object contains
|
||||
private components."""
|
||||
return hasattr(self, 'x')
|
||||
|
||||
def can_sign(self):
|
||||
"""Return a Boolean value recording whether this algorithm can generate signatures."""
|
||||
return 1
|
||||
|
||||
def can_encrypt(self):
|
||||
"""Return a Boolean value recording whether this algorithm can encrypt data."""
|
||||
return 0
|
||||
|
||||
def publickey(self):
|
||||
"""Return a new key object containing only the public information."""
|
||||
return construct((self.p, self.q, self.g, self.y))
|
||||
|
||||
object = qNEWobj
|
||||
|
342
python/gdata/Crypto/Util/RFC1751.py
Normal file
342
python/gdata/Crypto/Util/RFC1751.py
Normal file
@@ -0,0 +1,342 @@
|
||||
#!/usr/local/bin/python
|
||||
# rfc1751.py : Converts between 128-bit strings and a human-readable
|
||||
# sequence of words, as defined in RFC1751: "A Convention for
|
||||
# Human-Readable 128-bit Keys", by Daniel L. McDonald.
|
||||
|
||||
__revision__ = "$Id: RFC1751.py,v 1.6 2003/04/04 15:15:10 akuchling Exp $"
|
||||
|
||||
|
||||
import string, binascii
|
||||
|
||||
binary={0:'0000', 1:'0001', 2:'0010', 3:'0011', 4:'0100', 5:'0101',
|
||||
6:'0110', 7:'0111', 8:'1000', 9:'1001', 10:'1010', 11:'1011',
|
||||
12:'1100', 13:'1101', 14:'1110', 15:'1111'}
|
||||
|
||||
def _key2bin(s):
|
||||
"Convert a key into a string of binary digits"
|
||||
kl=map(lambda x: ord(x), s)
|
||||
kl=map(lambda x: binary[x/16]+binary[x&15], kl)
|
||||
return ''.join(kl)
|
||||
|
||||
def _extract(key, start, length):
|
||||
"""Extract a bitstring from a string of binary digits, and return its
|
||||
numeric value."""
|
||||
k=key[start:start+length]
|
||||
return reduce(lambda x,y: x*2+ord(y)-48, k, 0)
|
||||
|
||||
def key_to_english (key):
|
||||
"""key_to_english(key:string) : string
|
||||
Transform an arbitrary key into a string containing English words.
|
||||
The key length must be a multiple of 8.
|
||||
"""
|
||||
english=''
|
||||
for index in range(0, len(key), 8): # Loop over 8-byte subkeys
|
||||
subkey=key[index:index+8]
|
||||
# Compute the parity of the key
|
||||
skbin=_key2bin(subkey) ; p=0
|
||||
for i in range(0, 64, 2): p=p+_extract(skbin, i, 2)
|
||||
# Append parity bits to the subkey
|
||||
skbin=_key2bin(subkey+chr((p<<6) & 255))
|
||||
for i in range(0, 64, 11):
|
||||
english=english+wordlist[_extract(skbin, i, 11)]+' '
|
||||
|
||||
return english[:-1] # Remove the trailing space
|
||||
|
||||
def english_to_key (str):
|
||||
"""english_to_key(string):string
|
||||
Transform a string into a corresponding key.
|
||||
The string must contain words separated by whitespace; the number
|
||||
of words must be a multiple of 6.
|
||||
"""
|
||||
|
||||
L=string.split(string.upper(str)) ; key=''
|
||||
for index in range(0, len(L), 6):
|
||||
sublist=L[index:index+6] ; char=9*[0] ; bits=0
|
||||
for i in sublist:
|
||||
index = wordlist.index(i)
|
||||
shift = (8-(bits+11)%8) %8
|
||||
y = index << shift
|
||||
cl, cc, cr = (y>>16), (y>>8)&0xff, y & 0xff
|
||||
if (shift>5):
|
||||
char[bits/8] = char[bits/8] | cl
|
||||
char[bits/8+1] = char[bits/8+1] | cc
|
||||
char[bits/8+2] = char[bits/8+2] | cr
|
||||
elif shift>-3:
|
||||
char[bits/8] = char[bits/8] | cc
|
||||
char[bits/8+1] = char[bits/8+1] | cr
|
||||
else: char[bits/8] = char[bits/8] | cr
|
||||
bits=bits+11
|
||||
subkey=reduce(lambda x,y:x+chr(y), char, '')
|
||||
|
||||
# Check the parity of the resulting key
|
||||
skbin=_key2bin(subkey)
|
||||
p=0
|
||||
for i in range(0, 64, 2): p=p+_extract(skbin, i, 2)
|
||||
if (p&3) != _extract(skbin, 64, 2):
|
||||
raise ValueError, "Parity error in resulting key"
|
||||
key=key+subkey[0:8]
|
||||
return key
|
||||
|
||||
wordlist=[ "A", "ABE", "ACE", "ACT", "AD", "ADA", "ADD",
|
||||
"AGO", "AID", "AIM", "AIR", "ALL", "ALP", "AM", "AMY", "AN", "ANA",
|
||||
"AND", "ANN", "ANT", "ANY", "APE", "APS", "APT", "ARC", "ARE", "ARK",
|
||||
"ARM", "ART", "AS", "ASH", "ASK", "AT", "ATE", "AUG", "AUK", "AVE",
|
||||
"AWE", "AWK", "AWL", "AWN", "AX", "AYE", "BAD", "BAG", "BAH", "BAM",
|
||||
"BAN", "BAR", "BAT", "BAY", "BE", "BED", "BEE", "BEG", "BEN", "BET",
|
||||
"BEY", "BIB", "BID", "BIG", "BIN", "BIT", "BOB", "BOG", "BON", "BOO",
|
||||
"BOP", "BOW", "BOY", "BUB", "BUD", "BUG", "BUM", "BUN", "BUS", "BUT",
|
||||
"BUY", "BY", "BYE", "CAB", "CAL", "CAM", "CAN", "CAP", "CAR", "CAT",
|
||||
"CAW", "COD", "COG", "COL", "CON", "COO", "COP", "COT", "COW", "COY",
|
||||
"CRY", "CUB", "CUE", "CUP", "CUR", "CUT", "DAB", "DAD", "DAM", "DAN",
|
||||
"DAR", "DAY", "DEE", "DEL", "DEN", "DES", "DEW", "DID", "DIE", "DIG",
|
||||
"DIN", "DIP", "DO", "DOE", "DOG", "DON", "DOT", "DOW", "DRY", "DUB",
|
||||
"DUD", "DUE", "DUG", "DUN", "EAR", "EAT", "ED", "EEL", "EGG", "EGO",
|
||||
"ELI", "ELK", "ELM", "ELY", "EM", "END", "EST", "ETC", "EVA", "EVE",
|
||||
"EWE", "EYE", "FAD", "FAN", "FAR", "FAT", "FAY", "FED", "FEE", "FEW",
|
||||
"FIB", "FIG", "FIN", "FIR", "FIT", "FLO", "FLY", "FOE", "FOG", "FOR",
|
||||
"FRY", "FUM", "FUN", "FUR", "GAB", "GAD", "GAG", "GAL", "GAM", "GAP",
|
||||
"GAS", "GAY", "GEE", "GEL", "GEM", "GET", "GIG", "GIL", "GIN", "GO",
|
||||
"GOT", "GUM", "GUN", "GUS", "GUT", "GUY", "GYM", "GYP", "HA", "HAD",
|
||||
"HAL", "HAM", "HAN", "HAP", "HAS", "HAT", "HAW", "HAY", "HE", "HEM",
|
||||
"HEN", "HER", "HEW", "HEY", "HI", "HID", "HIM", "HIP", "HIS", "HIT",
|
||||
"HO", "HOB", "HOC", "HOE", "HOG", "HOP", "HOT", "HOW", "HUB", "HUE",
|
||||
"HUG", "HUH", "HUM", "HUT", "I", "ICY", "IDA", "IF", "IKE", "ILL",
|
||||
"INK", "INN", "IO", "ION", "IQ", "IRA", "IRE", "IRK", "IS", "IT",
|
||||
"ITS", "IVY", "JAB", "JAG", "JAM", "JAN", "JAR", "JAW", "JAY", "JET",
|
||||
"JIG", "JIM", "JO", "JOB", "JOE", "JOG", "JOT", "JOY", "JUG", "JUT",
|
||||
"KAY", "KEG", "KEN", "KEY", "KID", "KIM", "KIN", "KIT", "LA", "LAB",
|
||||
"LAC", "LAD", "LAG", "LAM", "LAP", "LAW", "LAY", "LEA", "LED", "LEE",
|
||||
"LEG", "LEN", "LEO", "LET", "LEW", "LID", "LIE", "LIN", "LIP", "LIT",
|
||||
"LO", "LOB", "LOG", "LOP", "LOS", "LOT", "LOU", "LOW", "LOY", "LUG",
|
||||
"LYE", "MA", "MAC", "MAD", "MAE", "MAN", "MAO", "MAP", "MAT", "MAW",
|
||||
"MAY", "ME", "MEG", "MEL", "MEN", "MET", "MEW", "MID", "MIN", "MIT",
|
||||
"MOB", "MOD", "MOE", "MOO", "MOP", "MOS", "MOT", "MOW", "MUD", "MUG",
|
||||
"MUM", "MY", "NAB", "NAG", "NAN", "NAP", "NAT", "NAY", "NE", "NED",
|
||||
"NEE", "NET", "NEW", "NIB", "NIL", "NIP", "NIT", "NO", "NOB", "NOD",
|
||||
"NON", "NOR", "NOT", "NOV", "NOW", "NU", "NUN", "NUT", "O", "OAF",
|
||||
"OAK", "OAR", "OAT", "ODD", "ODE", "OF", "OFF", "OFT", "OH", "OIL",
|
||||
"OK", "OLD", "ON", "ONE", "OR", "ORB", "ORE", "ORR", "OS", "OTT",
|
||||
"OUR", "OUT", "OVA", "OW", "OWE", "OWL", "OWN", "OX", "PA", "PAD",
|
||||
"PAL", "PAM", "PAN", "PAP", "PAR", "PAT", "PAW", "PAY", "PEA", "PEG",
|
||||
"PEN", "PEP", "PER", "PET", "PEW", "PHI", "PI", "PIE", "PIN", "PIT",
|
||||
"PLY", "PO", "POD", "POE", "POP", "POT", "POW", "PRO", "PRY", "PUB",
|
||||
"PUG", "PUN", "PUP", "PUT", "QUO", "RAG", "RAM", "RAN", "RAP", "RAT",
|
||||
"RAW", "RAY", "REB", "RED", "REP", "RET", "RIB", "RID", "RIG", "RIM",
|
||||
"RIO", "RIP", "ROB", "ROD", "ROE", "RON", "ROT", "ROW", "ROY", "RUB",
|
||||
"RUE", "RUG", "RUM", "RUN", "RYE", "SAC", "SAD", "SAG", "SAL", "SAM",
|
||||
"SAN", "SAP", "SAT", "SAW", "SAY", "SEA", "SEC", "SEE", "SEN", "SET",
|
||||
"SEW", "SHE", "SHY", "SIN", "SIP", "SIR", "SIS", "SIT", "SKI", "SKY",
|
||||
"SLY", "SO", "SOB", "SOD", "SON", "SOP", "SOW", "SOY", "SPA", "SPY",
|
||||
"SUB", "SUD", "SUE", "SUM", "SUN", "SUP", "TAB", "TAD", "TAG", "TAN",
|
||||
"TAP", "TAR", "TEA", "TED", "TEE", "TEN", "THE", "THY", "TIC", "TIE",
|
||||
"TIM", "TIN", "TIP", "TO", "TOE", "TOG", "TOM", "TON", "TOO", "TOP",
|
||||
"TOW", "TOY", "TRY", "TUB", "TUG", "TUM", "TUN", "TWO", "UN", "UP",
|
||||
"US", "USE", "VAN", "VAT", "VET", "VIE", "WAD", "WAG", "WAR", "WAS",
|
||||
"WAY", "WE", "WEB", "WED", "WEE", "WET", "WHO", "WHY", "WIN", "WIT",
|
||||
"WOK", "WON", "WOO", "WOW", "WRY", "WU", "YAM", "YAP", "YAW", "YE",
|
||||
"YEA", "YES", "YET", "YOU", "ABED", "ABEL", "ABET", "ABLE", "ABUT",
|
||||
"ACHE", "ACID", "ACME", "ACRE", "ACTA", "ACTS", "ADAM", "ADDS",
|
||||
"ADEN", "AFAR", "AFRO", "AGEE", "AHEM", "AHOY", "AIDA", "AIDE",
|
||||
"AIDS", "AIRY", "AJAR", "AKIN", "ALAN", "ALEC", "ALGA", "ALIA",
|
||||
"ALLY", "ALMA", "ALOE", "ALSO", "ALTO", "ALUM", "ALVA", "AMEN",
|
||||
"AMES", "AMID", "AMMO", "AMOK", "AMOS", "AMRA", "ANDY", "ANEW",
|
||||
"ANNA", "ANNE", "ANTE", "ANTI", "AQUA", "ARAB", "ARCH", "AREA",
|
||||
"ARGO", "ARID", "ARMY", "ARTS", "ARTY", "ASIA", "ASKS", "ATOM",
|
||||
"AUNT", "AURA", "AUTO", "AVER", "AVID", "AVIS", "AVON", "AVOW",
|
||||
"AWAY", "AWRY", "BABE", "BABY", "BACH", "BACK", "BADE", "BAIL",
|
||||
"BAIT", "BAKE", "BALD", "BALE", "BALI", "BALK", "BALL", "BALM",
|
||||
"BAND", "BANE", "BANG", "BANK", "BARB", "BARD", "BARE", "BARK",
|
||||
"BARN", "BARR", "BASE", "BASH", "BASK", "BASS", "BATE", "BATH",
|
||||
"BAWD", "BAWL", "BEAD", "BEAK", "BEAM", "BEAN", "BEAR", "BEAT",
|
||||
"BEAU", "BECK", "BEEF", "BEEN", "BEER",
|
||||
"BEET", "BELA", "BELL", "BELT", "BEND", "BENT", "BERG", "BERN",
|
||||
"BERT", "BESS", "BEST", "BETA", "BETH", "BHOY", "BIAS", "BIDE",
|
||||
"BIEN", "BILE", "BILK", "BILL", "BIND", "BING", "BIRD", "BITE",
|
||||
"BITS", "BLAB", "BLAT", "BLED", "BLEW", "BLOB", "BLOC", "BLOT",
|
||||
"BLOW", "BLUE", "BLUM", "BLUR", "BOAR", "BOAT", "BOCA", "BOCK",
|
||||
"BODE", "BODY", "BOGY", "BOHR", "BOIL", "BOLD", "BOLO", "BOLT",
|
||||
"BOMB", "BONA", "BOND", "BONE", "BONG", "BONN", "BONY", "BOOK",
|
||||
"BOOM", "BOON", "BOOT", "BORE", "BORG", "BORN", "BOSE", "BOSS",
|
||||
"BOTH", "BOUT", "BOWL", "BOYD", "BRAD", "BRAE", "BRAG", "BRAN",
|
||||
"BRAY", "BRED", "BREW", "BRIG", "BRIM", "BROW", "BUCK", "BUDD",
|
||||
"BUFF", "BULB", "BULK", "BULL", "BUNK", "BUNT", "BUOY", "BURG",
|
||||
"BURL", "BURN", "BURR", "BURT", "BURY", "BUSH", "BUSS", "BUST",
|
||||
"BUSY", "BYTE", "CADY", "CAFE", "CAGE", "CAIN", "CAKE", "CALF",
|
||||
"CALL", "CALM", "CAME", "CANE", "CANT", "CARD", "CARE", "CARL",
|
||||
"CARR", "CART", "CASE", "CASH", "CASK", "CAST", "CAVE", "CEIL",
|
||||
"CELL", "CENT", "CERN", "CHAD", "CHAR", "CHAT", "CHAW", "CHEF",
|
||||
"CHEN", "CHEW", "CHIC", "CHIN", "CHOU", "CHOW", "CHUB", "CHUG",
|
||||
"CHUM", "CITE", "CITY", "CLAD", "CLAM", "CLAN", "CLAW", "CLAY",
|
||||
"CLOD", "CLOG", "CLOT", "CLUB", "CLUE", "COAL", "COAT", "COCA",
|
||||
"COCK", "COCO", "CODA", "CODE", "CODY", "COED", "COIL", "COIN",
|
||||
"COKE", "COLA", "COLD", "COLT", "COMA", "COMB", "COME", "COOK",
|
||||
"COOL", "COON", "COOT", "CORD", "CORE", "CORK", "CORN", "COST",
|
||||
"COVE", "COWL", "CRAB", "CRAG", "CRAM", "CRAY", "CREW", "CRIB",
|
||||
"CROW", "CRUD", "CUBA", "CUBE", "CUFF", "CULL", "CULT", "CUNY",
|
||||
"CURB", "CURD", "CURE", "CURL", "CURT", "CUTS", "DADE", "DALE",
|
||||
"DAME", "DANA", "DANE", "DANG", "DANK", "DARE", "DARK", "DARN",
|
||||
"DART", "DASH", "DATA", "DATE", "DAVE", "DAVY", "DAWN", "DAYS",
|
||||
"DEAD", "DEAF", "DEAL", "DEAN", "DEAR", "DEBT", "DECK", "DEED",
|
||||
"DEEM", "DEER", "DEFT", "DEFY", "DELL", "DENT", "DENY", "DESK",
|
||||
"DIAL", "DICE", "DIED", "DIET", "DIME", "DINE", "DING", "DINT",
|
||||
"DIRE", "DIRT", "DISC", "DISH", "DISK", "DIVE", "DOCK", "DOES",
|
||||
"DOLE", "DOLL", "DOLT", "DOME", "DONE", "DOOM", "DOOR", "DORA",
|
||||
"DOSE", "DOTE", "DOUG", "DOUR", "DOVE", "DOWN", "DRAB", "DRAG",
|
||||
"DRAM", "DRAW", "DREW", "DRUB", "DRUG", "DRUM", "DUAL", "DUCK",
|
||||
"DUCT", "DUEL", "DUET", "DUKE", "DULL", "DUMB", "DUNE", "DUNK",
|
||||
"DUSK", "DUST", "DUTY", "EACH", "EARL", "EARN", "EASE", "EAST",
|
||||
"EASY", "EBEN", "ECHO", "EDDY", "EDEN", "EDGE", "EDGY", "EDIT",
|
||||
"EDNA", "EGAN", "ELAN", "ELBA", "ELLA", "ELSE", "EMIL", "EMIT",
|
||||
"EMMA", "ENDS", "ERIC", "EROS", "EVEN", "EVER", "EVIL", "EYED",
|
||||
"FACE", "FACT", "FADE", "FAIL", "FAIN", "FAIR", "FAKE", "FALL",
|
||||
"FAME", "FANG", "FARM", "FAST", "FATE", "FAWN", "FEAR", "FEAT",
|
||||
"FEED", "FEEL", "FEET", "FELL", "FELT", "FEND", "FERN", "FEST",
|
||||
"FEUD", "FIEF", "FIGS", "FILE", "FILL", "FILM", "FIND", "FINE",
|
||||
"FINK", "FIRE", "FIRM", "FISH", "FISK", "FIST", "FITS", "FIVE",
|
||||
"FLAG", "FLAK", "FLAM", "FLAT", "FLAW", "FLEA", "FLED", "FLEW",
|
||||
"FLIT", "FLOC", "FLOG", "FLOW", "FLUB", "FLUE", "FOAL", "FOAM",
|
||||
"FOGY", "FOIL", "FOLD", "FOLK", "FOND", "FONT", "FOOD", "FOOL",
|
||||
"FOOT", "FORD", "FORE", "FORK", "FORM", "FORT", "FOSS", "FOUL",
|
||||
"FOUR", "FOWL", "FRAU", "FRAY", "FRED", "FREE", "FRET", "FREY",
|
||||
"FROG", "FROM", "FUEL", "FULL", "FUME", "FUND", "FUNK", "FURY",
|
||||
"FUSE", "FUSS", "GAFF", "GAGE", "GAIL", "GAIN", "GAIT", "GALA",
|
||||
"GALE", "GALL", "GALT", "GAME", "GANG", "GARB", "GARY", "GASH",
|
||||
"GATE", "GAUL", "GAUR", "GAVE", "GAWK", "GEAR", "GELD", "GENE",
|
||||
"GENT", "GERM", "GETS", "GIBE", "GIFT", "GILD", "GILL", "GILT",
|
||||
"GINA", "GIRD", "GIRL", "GIST", "GIVE", "GLAD", "GLEE", "GLEN",
|
||||
"GLIB", "GLOB", "GLOM", "GLOW", "GLUE", "GLUM", "GLUT", "GOAD",
|
||||
"GOAL", "GOAT", "GOER", "GOES", "GOLD", "GOLF", "GONE", "GONG",
|
||||
"GOOD", "GOOF", "GORE", "GORY", "GOSH", "GOUT", "GOWN", "GRAB",
|
||||
"GRAD", "GRAY", "GREG", "GREW", "GREY", "GRID", "GRIM", "GRIN",
|
||||
"GRIT", "GROW", "GRUB", "GULF", "GULL", "GUNK", "GURU", "GUSH",
|
||||
"GUST", "GWEN", "GWYN", "HAAG", "HAAS", "HACK", "HAIL", "HAIR",
|
||||
"HALE", "HALF", "HALL", "HALO", "HALT", "HAND", "HANG", "HANK",
|
||||
"HANS", "HARD", "HARK", "HARM", "HART", "HASH", "HAST", "HATE",
|
||||
"HATH", "HAUL", "HAVE", "HAWK", "HAYS", "HEAD", "HEAL", "HEAR",
|
||||
"HEAT", "HEBE", "HECK", "HEED", "HEEL", "HEFT", "HELD", "HELL",
|
||||
"HELM", "HERB", "HERD", "HERE", "HERO", "HERS", "HESS", "HEWN",
|
||||
"HICK", "HIDE", "HIGH", "HIKE", "HILL", "HILT", "HIND", "HINT",
|
||||
"HIRE", "HISS", "HIVE", "HOBO", "HOCK", "HOFF", "HOLD", "HOLE",
|
||||
"HOLM", "HOLT", "HOME", "HONE", "HONK", "HOOD", "HOOF", "HOOK",
|
||||
"HOOT", "HORN", "HOSE", "HOST", "HOUR", "HOVE", "HOWE", "HOWL",
|
||||
"HOYT", "HUCK", "HUED", "HUFF", "HUGE", "HUGH", "HUGO", "HULK",
|
||||
"HULL", "HUNK", "HUNT", "HURD", "HURL", "HURT", "HUSH", "HYDE",
|
||||
"HYMN", "IBIS", "ICON", "IDEA", "IDLE", "IFFY", "INCA", "INCH",
|
||||
"INTO", "IONS", "IOTA", "IOWA", "IRIS", "IRMA", "IRON", "ISLE",
|
||||
"ITCH", "ITEM", "IVAN", "JACK", "JADE", "JAIL", "JAKE", "JANE",
|
||||
"JAVA", "JEAN", "JEFF", "JERK", "JESS", "JEST", "JIBE", "JILL",
|
||||
"JILT", "JIVE", "JOAN", "JOBS", "JOCK", "JOEL", "JOEY", "JOHN",
|
||||
"JOIN", "JOKE", "JOLT", "JOVE", "JUDD", "JUDE", "JUDO", "JUDY",
|
||||
"JUJU", "JUKE", "JULY", "JUNE", "JUNK", "JUNO", "JURY", "JUST",
|
||||
"JUTE", "KAHN", "KALE", "KANE", "KANT", "KARL", "KATE", "KEEL",
|
||||
"KEEN", "KENO", "KENT", "KERN", "KERR", "KEYS", "KICK", "KILL",
|
||||
"KIND", "KING", "KIRK", "KISS", "KITE", "KLAN", "KNEE", "KNEW",
|
||||
"KNIT", "KNOB", "KNOT", "KNOW", "KOCH", "KONG", "KUDO", "KURD",
|
||||
"KURT", "KYLE", "LACE", "LACK", "LACY", "LADY", "LAID", "LAIN",
|
||||
"LAIR", "LAKE", "LAMB", "LAME", "LAND", "LANE", "LANG", "LARD",
|
||||
"LARK", "LASS", "LAST", "LATE", "LAUD", "LAVA", "LAWN", "LAWS",
|
||||
"LAYS", "LEAD", "LEAF", "LEAK", "LEAN", "LEAR", "LEEK", "LEER",
|
||||
"LEFT", "LEND", "LENS", "LENT", "LEON", "LESK", "LESS", "LEST",
|
||||
"LETS", "LIAR", "LICE", "LICK", "LIED", "LIEN", "LIES", "LIEU",
|
||||
"LIFE", "LIFT", "LIKE", "LILA", "LILT", "LILY", "LIMA", "LIMB",
|
||||
"LIME", "LIND", "LINE", "LINK", "LINT", "LION", "LISA", "LIST",
|
||||
"LIVE", "LOAD", "LOAF", "LOAM", "LOAN", "LOCK", "LOFT", "LOGE",
|
||||
"LOIS", "LOLA", "LONE", "LONG", "LOOK", "LOON", "LOOT", "LORD",
|
||||
"LORE", "LOSE", "LOSS", "LOST", "LOUD", "LOVE", "LOWE", "LUCK",
|
||||
"LUCY", "LUGE", "LUKE", "LULU", "LUND", "LUNG", "LURA", "LURE",
|
||||
"LURK", "LUSH", "LUST", "LYLE", "LYNN", "LYON", "LYRA", "MACE",
|
||||
"MADE", "MAGI", "MAID", "MAIL", "MAIN", "MAKE", "MALE", "MALI",
|
||||
"MALL", "MALT", "MANA", "MANN", "MANY", "MARC", "MARE", "MARK",
|
||||
"MARS", "MART", "MARY", "MASH", "MASK", "MASS", "MAST", "MATE",
|
||||
"MATH", "MAUL", "MAYO", "MEAD", "MEAL", "MEAN", "MEAT", "MEEK",
|
||||
"MEET", "MELD", "MELT", "MEMO", "MEND", "MENU", "MERT", "MESH",
|
||||
"MESS", "MICE", "MIKE", "MILD", "MILE", "MILK", "MILL", "MILT",
|
||||
"MIMI", "MIND", "MINE", "MINI", "MINK", "MINT", "MIRE", "MISS",
|
||||
"MIST", "MITE", "MITT", "MOAN", "MOAT", "MOCK", "MODE", "MOLD",
|
||||
"MOLE", "MOLL", "MOLT", "MONA", "MONK", "MONT", "MOOD", "MOON",
|
||||
"MOOR", "MOOT", "MORE", "MORN", "MORT", "MOSS", "MOST", "MOTH",
|
||||
"MOVE", "MUCH", "MUCK", "MUDD", "MUFF", "MULE", "MULL", "MURK",
|
||||
"MUSH", "MUST", "MUTE", "MUTT", "MYRA", "MYTH", "NAGY", "NAIL",
|
||||
"NAIR", "NAME", "NARY", "NASH", "NAVE", "NAVY", "NEAL", "NEAR",
|
||||
"NEAT", "NECK", "NEED", "NEIL", "NELL", "NEON", "NERO", "NESS",
|
||||
"NEST", "NEWS", "NEWT", "NIBS", "NICE", "NICK", "NILE", "NINA",
|
||||
"NINE", "NOAH", "NODE", "NOEL", "NOLL", "NONE", "NOOK", "NOON",
|
||||
"NORM", "NOSE", "NOTE", "NOUN", "NOVA", "NUDE", "NULL", "NUMB",
|
||||
"OATH", "OBEY", "OBOE", "ODIN", "OHIO", "OILY", "OINT", "OKAY",
|
||||
"OLAF", "OLDY", "OLGA", "OLIN", "OMAN", "OMEN", "OMIT", "ONCE",
|
||||
"ONES", "ONLY", "ONTO", "ONUS", "ORAL", "ORGY", "OSLO", "OTIS",
|
||||
"OTTO", "OUCH", "OUST", "OUTS", "OVAL", "OVEN", "OVER", "OWLY",
|
||||
"OWNS", "QUAD", "QUIT", "QUOD", "RACE", "RACK", "RACY", "RAFT",
|
||||
"RAGE", "RAID", "RAIL", "RAIN", "RAKE", "RANK", "RANT", "RARE",
|
||||
"RASH", "RATE", "RAVE", "RAYS", "READ", "REAL", "REAM", "REAR",
|
||||
"RECK", "REED", "REEF", "REEK", "REEL", "REID", "REIN", "RENA",
|
||||
"REND", "RENT", "REST", "RICE", "RICH", "RICK", "RIDE", "RIFT",
|
||||
"RILL", "RIME", "RING", "RINK", "RISE", "RISK", "RITE", "ROAD",
|
||||
"ROAM", "ROAR", "ROBE", "ROCK", "RODE", "ROIL", "ROLL", "ROME",
|
||||
"ROOD", "ROOF", "ROOK", "ROOM", "ROOT", "ROSA", "ROSE", "ROSS",
|
||||
"ROSY", "ROTH", "ROUT", "ROVE", "ROWE", "ROWS", "RUBE", "RUBY",
|
||||
"RUDE", "RUDY", "RUIN", "RULE", "RUNG", "RUNS", "RUNT", "RUSE",
|
||||
"RUSH", "RUSK", "RUSS", "RUST", "RUTH", "SACK", "SAFE", "SAGE",
|
||||
"SAID", "SAIL", "SALE", "SALK", "SALT", "SAME", "SAND", "SANE",
|
||||
"SANG", "SANK", "SARA", "SAUL", "SAVE", "SAYS", "SCAN", "SCAR",
|
||||
"SCAT", "SCOT", "SEAL", "SEAM", "SEAR", "SEAT", "SEED", "SEEK",
|
||||
"SEEM", "SEEN", "SEES", "SELF", "SELL", "SEND", "SENT", "SETS",
|
||||
"SEWN", "SHAG", "SHAM", "SHAW", "SHAY", "SHED", "SHIM", "SHIN",
|
||||
"SHOD", "SHOE", "SHOT", "SHOW", "SHUN", "SHUT", "SICK", "SIDE",
|
||||
"SIFT", "SIGH", "SIGN", "SILK", "SILL", "SILO", "SILT", "SINE",
|
||||
"SING", "SINK", "SIRE", "SITE", "SITS", "SITU", "SKAT", "SKEW",
|
||||
"SKID", "SKIM", "SKIN", "SKIT", "SLAB", "SLAM", "SLAT", "SLAY",
|
||||
"SLED", "SLEW", "SLID", "SLIM", "SLIT", "SLOB", "SLOG", "SLOT",
|
||||
"SLOW", "SLUG", "SLUM", "SLUR", "SMOG", "SMUG", "SNAG", "SNOB",
|
||||
"SNOW", "SNUB", "SNUG", "SOAK", "SOAR", "SOCK", "SODA", "SOFA",
|
||||
"SOFT", "SOIL", "SOLD", "SOME", "SONG", "SOON", "SOOT", "SORE",
|
||||
"SORT", "SOUL", "SOUR", "SOWN", "STAB", "STAG", "STAN", "STAR",
|
||||
"STAY", "STEM", "STEW", "STIR", "STOW", "STUB", "STUN", "SUCH",
|
||||
"SUDS", "SUIT", "SULK", "SUMS", "SUNG", "SUNK", "SURE", "SURF",
|
||||
"SWAB", "SWAG", "SWAM", "SWAN", "SWAT", "SWAY", "SWIM", "SWUM",
|
||||
"TACK", "TACT", "TAIL", "TAKE", "TALE", "TALK", "TALL", "TANK",
|
||||
"TASK", "TATE", "TAUT", "TEAL", "TEAM", "TEAR", "TECH", "TEEM",
|
||||
"TEEN", "TEET", "TELL", "TEND", "TENT", "TERM", "TERN", "TESS",
|
||||
"TEST", "THAN", "THAT", "THEE", "THEM", "THEN", "THEY", "THIN",
|
||||
"THIS", "THUD", "THUG", "TICK", "TIDE", "TIDY", "TIED", "TIER",
|
||||
"TILE", "TILL", "TILT", "TIME", "TINA", "TINE", "TINT", "TINY",
|
||||
"TIRE", "TOAD", "TOGO", "TOIL", "TOLD", "TOLL", "TONE", "TONG",
|
||||
"TONY", "TOOK", "TOOL", "TOOT", "TORE", "TORN", "TOTE", "TOUR",
|
||||
"TOUT", "TOWN", "TRAG", "TRAM", "TRAY", "TREE", "TREK", "TRIG",
|
||||
"TRIM", "TRIO", "TROD", "TROT", "TROY", "TRUE", "TUBA", "TUBE",
|
||||
"TUCK", "TUFT", "TUNA", "TUNE", "TUNG", "TURF", "TURN", "TUSK",
|
||||
"TWIG", "TWIN", "TWIT", "ULAN", "UNIT", "URGE", "USED", "USER",
|
||||
"USES", "UTAH", "VAIL", "VAIN", "VALE", "VARY", "VASE", "VAST",
|
||||
"VEAL", "VEDA", "VEIL", "VEIN", "VEND", "VENT", "VERB", "VERY",
|
||||
"VETO", "VICE", "VIEW", "VINE", "VISE", "VOID", "VOLT", "VOTE",
|
||||
"WACK", "WADE", "WAGE", "WAIL", "WAIT", "WAKE", "WALE", "WALK",
|
||||
"WALL", "WALT", "WAND", "WANE", "WANG", "WANT", "WARD", "WARM",
|
||||
"WARN", "WART", "WASH", "WAST", "WATS", "WATT", "WAVE", "WAVY",
|
||||
"WAYS", "WEAK", "WEAL", "WEAN", "WEAR", "WEED", "WEEK", "WEIR",
|
||||
"WELD", "WELL", "WELT", "WENT", "WERE", "WERT", "WEST", "WHAM",
|
||||
"WHAT", "WHEE", "WHEN", "WHET", "WHOA", "WHOM", "WICK", "WIFE",
|
||||
"WILD", "WILL", "WIND", "WINE", "WING", "WINK", "WINO", "WIRE",
|
||||
"WISE", "WISH", "WITH", "WOLF", "WONT", "WOOD", "WOOL", "WORD",
|
||||
"WORE", "WORK", "WORM", "WORN", "WOVE", "WRIT", "WYNN", "YALE",
|
||||
"YANG", "YANK", "YARD", "YARN", "YAWL", "YAWN", "YEAH", "YEAR",
|
||||
"YELL", "YOGA", "YOKE" ]
|
||||
|
||||
if __name__=='__main__':
|
||||
data = [('EB33F77EE73D4053', 'TIDE ITCH SLOW REIN RULE MOT'),
|
||||
('CCAC2AED591056BE4F90FD441C534766',
|
||||
'RASH BUSH MILK LOOK BAD BRIM AVID GAFF BAIT ROT POD LOVE'),
|
||||
('EFF81F9BFBC65350920CDD7416DE8009',
|
||||
'TROD MUTE TAIL WARM CHAR KONG HAAG CITY BORE O TEAL AWL')
|
||||
]
|
||||
|
||||
for key, words in data:
|
||||
print 'Trying key', key
|
||||
key=binascii.a2b_hex(key)
|
||||
w2=key_to_english(key)
|
||||
if w2!=words:
|
||||
print 'key_to_english fails on key', repr(key), ', producing', str(w2)
|
||||
k2=english_to_key(words)
|
||||
if k2!=key:
|
||||
print 'english_to_key fails on key', repr(key), ', producing', repr(k2)
|
||||
|
||||
|
16
python/gdata/Crypto/Util/__init__.py
Normal file
16
python/gdata/Crypto/Util/__init__.py
Normal file
@@ -0,0 +1,16 @@
|
||||
"""Miscellaneous modules
|
||||
|
||||
Contains useful modules that don't belong into any of the
|
||||
other Crypto.* subpackages.
|
||||
|
||||
Crypto.Util.number Number-theoretic functions (primality testing, etc.)
|
||||
Crypto.Util.randpool Random number generation
|
||||
Crypto.Util.RFC1751 Converts between 128-bit keys and human-readable
|
||||
strings of words.
|
||||
|
||||
"""
|
||||
|
||||
__all__ = ['randpool', 'RFC1751', 'number']
|
||||
|
||||
__revision__ = "$Id: __init__.py,v 1.4 2003/02/28 15:26:00 akuchling Exp $"
|
||||
|
201
python/gdata/Crypto/Util/number.py
Normal file
201
python/gdata/Crypto/Util/number.py
Normal file
@@ -0,0 +1,201 @@
|
||||
#
|
||||
# number.py : Number-theoretic functions
|
||||
#
|
||||
# Part of the Python Cryptography Toolkit
|
||||
#
|
||||
# Distribute and use freely; there are no restrictions on further
|
||||
# dissemination and usage except those imposed by the laws of your
|
||||
# country of residence. This software is provided "as is" without
|
||||
# warranty of fitness for use or suitability for any purpose, express
|
||||
# or implied. Use at your own risk or not at all.
|
||||
#
|
||||
|
||||
__revision__ = "$Id: number.py,v 1.13 2003/04/04 18:21:07 akuchling Exp $"
|
||||
|
||||
bignum = long
|
||||
try:
|
||||
from Crypto.PublicKey import _fastmath
|
||||
except ImportError:
|
||||
_fastmath = None
|
||||
|
||||
# Commented out and replaced with faster versions below
|
||||
## def long2str(n):
|
||||
## s=''
|
||||
## while n>0:
|
||||
## s=chr(n & 255)+s
|
||||
## n=n>>8
|
||||
## return s
|
||||
|
||||
## import types
|
||||
## def str2long(s):
|
||||
## if type(s)!=types.StringType: return s # Integers will be left alone
|
||||
## return reduce(lambda x,y : x*256+ord(y), s, 0L)
|
||||
|
||||
def size (N):
|
||||
"""size(N:long) : int
|
||||
Returns the size of the number N in bits.
|
||||
"""
|
||||
bits, power = 0,1L
|
||||
while N >= power:
|
||||
bits += 1
|
||||
power = power << 1
|
||||
return bits
|
||||
|
||||
def getRandomNumber(N, randfunc):
|
||||
"""getRandomNumber(N:int, randfunc:callable):long
|
||||
Return an N-bit random number."""
|
||||
|
||||
S = randfunc(N/8)
|
||||
odd_bits = N % 8
|
||||
if odd_bits != 0:
|
||||
char = ord(randfunc(1)) >> (8-odd_bits)
|
||||
S = chr(char) + S
|
||||
value = bytes_to_long(S)
|
||||
value |= 2L ** (N-1) # Ensure high bit is set
|
||||
assert size(value) >= N
|
||||
return value
|
||||
|
||||
def GCD(x,y):
|
||||
"""GCD(x:long, y:long): long
|
||||
Return the GCD of x and y.
|
||||
"""
|
||||
x = abs(x) ; y = abs(y)
|
||||
while x > 0:
|
||||
x, y = y % x, x
|
||||
return y
|
||||
|
||||
def inverse(u, v):
|
||||
"""inverse(u:long, u:long):long
|
||||
Return the inverse of u mod v.
|
||||
"""
|
||||
u3, v3 = long(u), long(v)
|
||||
u1, v1 = 1L, 0L
|
||||
while v3 > 0:
|
||||
q=u3 / v3
|
||||
u1, v1 = v1, u1 - v1*q
|
||||
u3, v3 = v3, u3 - v3*q
|
||||
while u1<0:
|
||||
u1 = u1 + v
|
||||
return u1
|
||||
|
||||
# Given a number of bits to generate and a random generation function,
|
||||
# find a prime number of the appropriate size.
|
||||
|
||||
def getPrime(N, randfunc):
|
||||
"""getPrime(N:int, randfunc:callable):long
|
||||
Return a random N-bit prime number.
|
||||
"""
|
||||
|
||||
number=getRandomNumber(N, randfunc) | 1
|
||||
while (not isPrime(number)):
|
||||
number=number+2
|
||||
return number
|
||||
|
||||
def isPrime(N):
|
||||
"""isPrime(N:long):bool
|
||||
Return true if N is prime.
|
||||
"""
|
||||
if N == 1:
|
||||
return 0
|
||||
if N in sieve:
|
||||
return 1
|
||||
for i in sieve:
|
||||
if (N % i)==0:
|
||||
return 0
|
||||
|
||||
# Use the accelerator if available
|
||||
if _fastmath is not None:
|
||||
return _fastmath.isPrime(N)
|
||||
|
||||
# Compute the highest bit that's set in N
|
||||
N1 = N - 1L
|
||||
n = 1L
|
||||
while (n<N):
|
||||
n=n<<1L
|
||||
n = n >> 1L
|
||||
|
||||
# Rabin-Miller test
|
||||
for c in sieve[:7]:
|
||||
a=long(c) ; d=1L ; t=n
|
||||
while (t): # Iterate over the bits in N1
|
||||
x=(d*d) % N
|
||||
if x==1L and d!=1L and d!=N1:
|
||||
return 0 # Square root of 1 found
|
||||
if N1 & t:
|
||||
d=(x*a) % N
|
||||
else:
|
||||
d=x
|
||||
t = t >> 1L
|
||||
if d!=1L:
|
||||
return 0
|
||||
return 1
|
||||
|
||||
# Small primes used for checking primality; these are all the primes
|
||||
# less than 256. This should be enough to eliminate most of the odd
|
||||
# numbers before needing to do a Rabin-Miller test at all.
|
||||
|
||||
sieve=[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59,
|
||||
61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127,
|
||||
131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193,
|
||||
197, 199, 211, 223, 227, 229, 233, 239, 241, 251]
|
||||
|
||||
# Improved conversion functions contributed by Barry Warsaw, after
|
||||
# careful benchmarking
|
||||
|
||||
import struct
|
||||
|
||||
def long_to_bytes(n, blocksize=0):
|
||||
"""long_to_bytes(n:long, blocksize:int) : string
|
||||
Convert a long integer to a byte string.
|
||||
|
||||
If optional blocksize is given and greater than zero, pad the front of the
|
||||
byte string with binary zeros so that the length is a multiple of
|
||||
blocksize.
|
||||
"""
|
||||
# after much testing, this algorithm was deemed to be the fastest
|
||||
s = ''
|
||||
n = long(n)
|
||||
pack = struct.pack
|
||||
while n > 0:
|
||||
s = pack('>I', n & 0xffffffffL) + s
|
||||
n = n >> 32
|
||||
# strip off leading zeros
|
||||
for i in range(len(s)):
|
||||
if s[i] != '\000':
|
||||
break
|
||||
else:
|
||||
# only happens when n == 0
|
||||
s = '\000'
|
||||
i = 0
|
||||
s = s[i:]
|
||||
# add back some pad bytes. this could be done more efficiently w.r.t. the
|
||||
# de-padding being done above, but sigh...
|
||||
if blocksize > 0 and len(s) % blocksize:
|
||||
s = (blocksize - len(s) % blocksize) * '\000' + s
|
||||
return s
|
||||
|
||||
def bytes_to_long(s):
|
||||
"""bytes_to_long(string) : long
|
||||
Convert a byte string to a long integer.
|
||||
|
||||
This is (essentially) the inverse of long_to_bytes().
|
||||
"""
|
||||
acc = 0L
|
||||
unpack = struct.unpack
|
||||
length = len(s)
|
||||
if length % 4:
|
||||
extra = (4 - length % 4)
|
||||
s = '\000' * extra + s
|
||||
length = length + extra
|
||||
for i in range(0, length, 4):
|
||||
acc = (acc << 32) + unpack('>I', s[i:i+4])[0]
|
||||
return acc
|
||||
|
||||
# For backwards compatibility...
|
||||
import warnings
|
||||
def long2str(n, blocksize=0):
|
||||
warnings.warn("long2str() has been replaced by long_to_bytes()")
|
||||
return long_to_bytes(n, blocksize)
|
||||
def str2long(s):
|
||||
warnings.warn("str2long() has been replaced by bytes_to_long()")
|
||||
return bytes_to_long(s)
|
421
python/gdata/Crypto/Util/randpool.py
Normal file
421
python/gdata/Crypto/Util/randpool.py
Normal file
@@ -0,0 +1,421 @@
|
||||
#
|
||||
# randpool.py : Cryptographically strong random number generation
|
||||
#
|
||||
# Part of the Python Cryptography Toolkit
|
||||
#
|
||||
# Distribute and use freely; there are no restrictions on further
|
||||
# dissemination and usage except those imposed by the laws of your
|
||||
# country of residence. This software is provided "as is" without
|
||||
# warranty of fitness for use or suitability for any purpose, express
|
||||
# or implied. Use at your own risk or not at all.
|
||||
#
|
||||
|
||||
__revision__ = "$Id: randpool.py,v 1.14 2004/05/06 12:56:54 akuchling Exp $"
|
||||
|
||||
import time, array, types, warnings, os.path
|
||||
from Crypto.Util.number import long_to_bytes
|
||||
try:
|
||||
import Crypto.Util.winrandom as winrandom
|
||||
except:
|
||||
winrandom = None
|
||||
|
||||
STIRNUM = 3
|
||||
|
||||
class RandomPool:
|
||||
"""randpool.py : Cryptographically strong random number generation.
|
||||
|
||||
The implementation here is similar to the one in PGP. To be
|
||||
cryptographically strong, it must be difficult to determine the RNG's
|
||||
output, whether in the future or the past. This is done by using
|
||||
a cryptographic hash function to "stir" the random data.
|
||||
|
||||
Entropy is gathered in the same fashion as PGP; the highest-resolution
|
||||
clock around is read and the data is added to the random number pool.
|
||||
A conservative estimate of the entropy is then kept.
|
||||
|
||||
If a cryptographically secure random source is available (/dev/urandom
|
||||
on many Unixes, Windows CryptGenRandom on most Windows), then use
|
||||
it.
|
||||
|
||||
Instance Attributes:
|
||||
bits : int
|
||||
Maximum size of pool in bits
|
||||
bytes : int
|
||||
Maximum size of pool in bytes
|
||||
entropy : int
|
||||
Number of bits of entropy in this pool.
|
||||
|
||||
Methods:
|
||||
add_event([s]) : add some entropy to the pool
|
||||
get_bytes(int) : get N bytes of random data
|
||||
randomize([N]) : get N bytes of randomness from external source
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, numbytes = 160, cipher=None, hash=None):
|
||||
if hash is None:
|
||||
from Crypto.Hash import SHA as hash
|
||||
|
||||
# The cipher argument is vestigial; it was removed from
|
||||
# version 1.1 so RandomPool would work even in the limited
|
||||
# exportable subset of the code
|
||||
if cipher is not None:
|
||||
warnings.warn("'cipher' parameter is no longer used")
|
||||
|
||||
if isinstance(hash, types.StringType):
|
||||
# ugly hack to force __import__ to give us the end-path module
|
||||
hash = __import__('Crypto.Hash.'+hash,
|
||||
None, None, ['new'])
|
||||
warnings.warn("'hash' parameter should now be a hashing module")
|
||||
|
||||
self.bytes = numbytes
|
||||
self.bits = self.bytes*8
|
||||
self.entropy = 0
|
||||
self._hash = hash
|
||||
|
||||
# Construct an array to hold the random pool,
|
||||
# initializing it to 0.
|
||||
self._randpool = array.array('B', [0]*self.bytes)
|
||||
|
||||
self._event1 = self._event2 = 0
|
||||
self._addPos = 0
|
||||
self._getPos = hash.digest_size
|
||||
self._lastcounter=time.time()
|
||||
self.__counter = 0
|
||||
|
||||
self._measureTickSize() # Estimate timer resolution
|
||||
self._randomize()
|
||||
|
||||
def _updateEntropyEstimate(self, nbits):
|
||||
self.entropy += nbits
|
||||
if self.entropy < 0:
|
||||
self.entropy = 0
|
||||
elif self.entropy > self.bits:
|
||||
self.entropy = self.bits
|
||||
|
||||
def _randomize(self, N = 0, devname = '/dev/urandom'):
|
||||
"""_randomize(N, DEVNAME:device-filepath)
|
||||
collects N bits of randomness from some entropy source (e.g.,
|
||||
/dev/urandom on Unixes that have it, Windows CryptoAPI
|
||||
CryptGenRandom, etc)
|
||||
DEVNAME is optional, defaults to /dev/urandom. You can change it
|
||||
to /dev/random if you want to block till you get enough
|
||||
entropy.
|
||||
"""
|
||||
data = ''
|
||||
if N <= 0:
|
||||
nbytes = int((self.bits - self.entropy)/8+0.5)
|
||||
else:
|
||||
nbytes = int(N/8+0.5)
|
||||
if winrandom:
|
||||
# Windows CryptGenRandom provides random data.
|
||||
data = winrandom.new().get_bytes(nbytes)
|
||||
elif os.path.exists(devname):
|
||||
# Many OSes support a /dev/urandom device
|
||||
try:
|
||||
f=open(devname)
|
||||
data=f.read(nbytes)
|
||||
f.close()
|
||||
except IOError, (num, msg):
|
||||
if num!=2: raise IOError, (num, msg)
|
||||
# If the file wasn't found, ignore the error
|
||||
if data:
|
||||
self._addBytes(data)
|
||||
# Entropy estimate: The number of bits of
|
||||
# data obtained from the random source.
|
||||
self._updateEntropyEstimate(8*len(data))
|
||||
self.stir_n() # Wash the random pool
|
||||
|
||||
def randomize(self, N=0):
|
||||
"""randomize(N:int)
|
||||
use the class entropy source to get some entropy data.
|
||||
This is overridden by KeyboardRandomize().
|
||||
"""
|
||||
return self._randomize(N)
|
||||
|
||||
def stir_n(self, N = STIRNUM):
|
||||
"""stir_n(N)
|
||||
stirs the random pool N times
|
||||
"""
|
||||
for i in xrange(N):
|
||||
self.stir()
|
||||
|
||||
def stir (self, s = ''):
|
||||
"""stir(s:string)
|
||||
Mix up the randomness pool. This will call add_event() twice,
|
||||
but out of paranoia the entropy attribute will not be
|
||||
increased. The optional 's' parameter is a string that will
|
||||
be hashed with the randomness pool.
|
||||
"""
|
||||
|
||||
entropy=self.entropy # Save inital entropy value
|
||||
self.add_event()
|
||||
|
||||
# Loop over the randomness pool: hash its contents
|
||||
# along with a counter, and add the resulting digest
|
||||
# back into the pool.
|
||||
for i in range(self.bytes / self._hash.digest_size):
|
||||
h = self._hash.new(self._randpool)
|
||||
h.update(str(self.__counter) + str(i) + str(self._addPos) + s)
|
||||
self._addBytes( h.digest() )
|
||||
self.__counter = (self.__counter + 1) & 0xFFFFffffL
|
||||
|
||||
self._addPos, self._getPos = 0, self._hash.digest_size
|
||||
self.add_event()
|
||||
|
||||
# Restore the old value of the entropy.
|
||||
self.entropy=entropy
|
||||
|
||||
|
||||
def get_bytes (self, N):
|
||||
"""get_bytes(N:int) : string
|
||||
Return N bytes of random data.
|
||||
"""
|
||||
|
||||
s=''
|
||||
i, pool = self._getPos, self._randpool
|
||||
h=self._hash.new()
|
||||
dsize = self._hash.digest_size
|
||||
num = N
|
||||
while num > 0:
|
||||
h.update( self._randpool[i:i+dsize] )
|
||||
s = s + h.digest()
|
||||
num = num - dsize
|
||||
i = (i + dsize) % self.bytes
|
||||
if i<dsize:
|
||||
self.stir()
|
||||
i=self._getPos
|
||||
|
||||
self._getPos = i
|
||||
self._updateEntropyEstimate(- 8*N)
|
||||
return s[:N]
|
||||
|
||||
|
||||
def add_event(self, s=''):
|
||||
"""add_event(s:string)
|
||||
Add an event to the random pool. The current time is stored
|
||||
between calls and used to estimate the entropy. The optional
|
||||
's' parameter is a string that will also be XORed into the pool.
|
||||
Returns the estimated number of additional bits of entropy gain.
|
||||
"""
|
||||
event = time.time()*1000
|
||||
delta = self._noise()
|
||||
s = (s + long_to_bytes(event) +
|
||||
4*chr(0xaa) + long_to_bytes(delta) )
|
||||
self._addBytes(s)
|
||||
if event==self._event1 and event==self._event2:
|
||||
# If events are coming too closely together, assume there's
|
||||
# no effective entropy being added.
|
||||
bits=0
|
||||
else:
|
||||
# Count the number of bits in delta, and assume that's the entropy.
|
||||
bits=0
|
||||
while delta:
|
||||
delta, bits = delta>>1, bits+1
|
||||
if bits>8: bits=8
|
||||
|
||||
self._event1, self._event2 = event, self._event1
|
||||
|
||||
self._updateEntropyEstimate(bits)
|
||||
return bits
|
||||
|
||||
# Private functions
|
||||
def _noise(self):
|
||||
# Adds a bit of noise to the random pool, by adding in the
|
||||
# current time and CPU usage of this process.
|
||||
# The difference from the previous call to _noise() is taken
|
||||
# in an effort to estimate the entropy.
|
||||
t=time.time()
|
||||
delta = (t - self._lastcounter)/self._ticksize*1e6
|
||||
self._lastcounter = t
|
||||
self._addBytes(long_to_bytes(long(1000*time.time())))
|
||||
self._addBytes(long_to_bytes(long(1000*time.clock())))
|
||||
self._addBytes(long_to_bytes(long(1000*time.time())))
|
||||
self._addBytes(long_to_bytes(long(delta)))
|
||||
|
||||
# Reduce delta to a maximum of 8 bits so we don't add too much
|
||||
# entropy as a result of this call.
|
||||
delta=delta % 0xff
|
||||
return int(delta)
|
||||
|
||||
|
||||
def _measureTickSize(self):
|
||||
# _measureTickSize() tries to estimate a rough average of the
|
||||
# resolution of time that you can see from Python. It does
|
||||
# this by measuring the time 100 times, computing the delay
|
||||
# between measurements, and taking the median of the resulting
|
||||
# list. (We also hash all the times and add them to the pool)
|
||||
interval = [None] * 100
|
||||
h = self._hash.new(`(id(self),id(interval))`)
|
||||
|
||||
# Compute 100 differences
|
||||
t=time.time()
|
||||
h.update(`t`)
|
||||
i = 0
|
||||
j = 0
|
||||
while i < 100:
|
||||
t2=time.time()
|
||||
h.update(`(i,j,t2)`)
|
||||
j += 1
|
||||
delta=int((t2-t)*1e6)
|
||||
if delta:
|
||||
interval[i] = delta
|
||||
i += 1
|
||||
t=t2
|
||||
|
||||
# Take the median of the array of intervals
|
||||
interval.sort()
|
||||
self._ticksize=interval[len(interval)/2]
|
||||
h.update(`(interval,self._ticksize)`)
|
||||
# mix in the measurement times and wash the random pool
|
||||
self.stir(h.digest())
|
||||
|
||||
def _addBytes(self, s):
|
||||
"XOR the contents of the string S into the random pool"
|
||||
i, pool = self._addPos, self._randpool
|
||||
for j in range(0, len(s)):
|
||||
pool[i]=pool[i] ^ ord(s[j])
|
||||
i=(i+1) % self.bytes
|
||||
self._addPos = i
|
||||
|
||||
# Deprecated method names: remove in PCT 2.1 or later.
|
||||
def getBytes(self, N):
|
||||
warnings.warn("getBytes() method replaced by get_bytes()",
|
||||
DeprecationWarning)
|
||||
return self.get_bytes(N)
|
||||
|
||||
def addEvent (self, event, s=""):
|
||||
warnings.warn("addEvent() method replaced by add_event()",
|
||||
DeprecationWarning)
|
||||
return self.add_event(s + str(event))
|
||||
|
||||
class PersistentRandomPool (RandomPool):
|
||||
def __init__ (self, filename=None, *args, **kwargs):
|
||||
RandomPool.__init__(self, *args, **kwargs)
|
||||
self.filename = filename
|
||||
if filename:
|
||||
try:
|
||||
# the time taken to open and read the file might have
|
||||
# a little disk variability, modulo disk/kernel caching...
|
||||
f=open(filename, 'rb')
|
||||
self.add_event()
|
||||
data = f.read()
|
||||
self.add_event()
|
||||
# mix in the data from the file and wash the random pool
|
||||
self.stir(data)
|
||||
f.close()
|
||||
except IOError:
|
||||
# Oh, well; the file doesn't exist or is unreadable, so
|
||||
# we'll just ignore it.
|
||||
pass
|
||||
|
||||
def save(self):
|
||||
if self.filename == "":
|
||||
raise ValueError, "No filename set for this object"
|
||||
# wash the random pool before save, provides some forward secrecy for
|
||||
# old values of the pool.
|
||||
self.stir_n()
|
||||
f=open(self.filename, 'wb')
|
||||
self.add_event()
|
||||
f.write(self._randpool.tostring())
|
||||
f.close()
|
||||
self.add_event()
|
||||
# wash the pool again, provide some protection for future values
|
||||
self.stir()
|
||||
|
||||
# non-echoing Windows keyboard entry
|
||||
_kb = 0
|
||||
if not _kb:
|
||||
try:
|
||||
import msvcrt
|
||||
class KeyboardEntry:
|
||||
def getch(self):
|
||||
c = msvcrt.getch()
|
||||
if c in ('\000', '\xe0'):
|
||||
# function key
|
||||
c += msvcrt.getch()
|
||||
return c
|
||||
def close(self, delay = 0):
|
||||
if delay:
|
||||
time.sleep(delay)
|
||||
while msvcrt.kbhit():
|
||||
msvcrt.getch()
|
||||
_kb = 1
|
||||
except:
|
||||
pass
|
||||
|
||||
# non-echoing Posix keyboard entry
|
||||
if not _kb:
|
||||
try:
|
||||
import termios
|
||||
class KeyboardEntry:
|
||||
def __init__(self, fd = 0):
|
||||
self._fd = fd
|
||||
self._old = termios.tcgetattr(fd)
|
||||
new = termios.tcgetattr(fd)
|
||||
new[3]=new[3] & ~termios.ICANON & ~termios.ECHO
|
||||
termios.tcsetattr(fd, termios.TCSANOW, new)
|
||||
def getch(self):
|
||||
termios.tcflush(0, termios.TCIFLUSH) # XXX Leave this in?
|
||||
return os.read(self._fd, 1)
|
||||
def close(self, delay = 0):
|
||||
if delay:
|
||||
time.sleep(delay)
|
||||
termios.tcflush(self._fd, termios.TCIFLUSH)
|
||||
termios.tcsetattr(self._fd, termios.TCSAFLUSH, self._old)
|
||||
_kb = 1
|
||||
except:
|
||||
pass
|
||||
|
||||
class KeyboardRandomPool (PersistentRandomPool):
|
||||
def __init__(self, *args, **kwargs):
|
||||
PersistentRandomPool.__init__(self, *args, **kwargs)
|
||||
|
||||
def randomize(self, N = 0):
|
||||
"Adds N bits of entropy to random pool. If N is 0, fill up pool."
|
||||
import os, string, time
|
||||
if N <= 0:
|
||||
bits = self.bits - self.entropy
|
||||
else:
|
||||
bits = N*8
|
||||
if bits == 0:
|
||||
return
|
||||
print bits,'bits of entropy are now required. Please type on the keyboard'
|
||||
print 'until enough randomness has been accumulated.'
|
||||
kb = KeyboardEntry()
|
||||
s='' # We'll save the characters typed and add them to the pool.
|
||||
hash = self._hash
|
||||
e = 0
|
||||
try:
|
||||
while e < bits:
|
||||
temp=str(bits-e).rjust(6)
|
||||
os.write(1, temp)
|
||||
s=s+kb.getch()
|
||||
e += self.add_event(s)
|
||||
os.write(1, 6*chr(8))
|
||||
self.add_event(s+hash.new(s).digest() )
|
||||
finally:
|
||||
kb.close()
|
||||
print '\n\007 Enough. Please wait a moment.\n'
|
||||
self.stir_n() # wash the random pool.
|
||||
kb.close(4)
|
||||
|
||||
if __name__ == '__main__':
|
||||
pool = RandomPool()
|
||||
print 'random pool entropy', pool.entropy, 'bits'
|
||||
pool.add_event('something')
|
||||
print `pool.get_bytes(100)`
|
||||
import tempfile, os
|
||||
fname = tempfile.mktemp()
|
||||
pool = KeyboardRandomPool(filename=fname)
|
||||
print 'keyboard random pool entropy', pool.entropy, 'bits'
|
||||
pool.randomize()
|
||||
print 'keyboard random pool entropy', pool.entropy, 'bits'
|
||||
pool.randomize(128)
|
||||
pool.save()
|
||||
saved = open(fname, 'rb').read()
|
||||
print 'saved', `saved`
|
||||
print 'pool ', `pool._randpool.tostring()`
|
||||
newpool = PersistentRandomPool(fname)
|
||||
print 'persistent random pool entropy', pool.entropy, 'bits'
|
||||
os.remove(fname)
|
453
python/gdata/Crypto/Util/test.py
Normal file
453
python/gdata/Crypto/Util/test.py
Normal file
@@ -0,0 +1,453 @@
|
||||
#
|
||||
# test.py : Functions used for testing the modules
|
||||
#
|
||||
# Part of the Python Cryptography Toolkit
|
||||
#
|
||||
# Distribute and use freely; there are no restrictions on further
|
||||
# dissemination and usage except those imposed by the laws of your
|
||||
# country of residence. This software is provided "as is" without
|
||||
# warranty of fitness for use or suitability for any purpose, express
|
||||
# or implied. Use at your own risk or not at all.
|
||||
#
|
||||
|
||||
__revision__ = "$Id: test.py,v 1.16 2004/08/13 22:24:18 akuchling Exp $"
|
||||
|
||||
import binascii
|
||||
import string
|
||||
import testdata
|
||||
|
||||
from Crypto.Cipher import *
|
||||
|
||||
def die(string):
|
||||
import sys
|
||||
print '***ERROR: ', string
|
||||
# sys.exit(0) # Will default to continuing onward...
|
||||
|
||||
def print_timing (size, delta, verbose):
|
||||
if verbose:
|
||||
if delta == 0:
|
||||
print 'Unable to measure time -- elapsed time too small'
|
||||
else:
|
||||
print '%.2f K/sec' % (size/delta)
|
||||
|
||||
def exerciseBlockCipher(cipher, verbose):
|
||||
import string, time
|
||||
try:
|
||||
ciph = eval(cipher)
|
||||
except NameError:
|
||||
print cipher, 'module not available'
|
||||
return None
|
||||
print cipher+ ':'
|
||||
str='1' # Build 128K of test data
|
||||
for i in xrange(0, 17):
|
||||
str=str+str
|
||||
if ciph.key_size==0: ciph.key_size=16
|
||||
password = 'password12345678Extra text for password'[0:ciph.key_size]
|
||||
IV = 'Test IV Test IV Test IV Test'[0:ciph.block_size]
|
||||
|
||||
if verbose: print ' ECB mode:',
|
||||
obj=ciph.new(password, ciph.MODE_ECB)
|
||||
if obj.block_size != ciph.block_size:
|
||||
die("Module and cipher object block_size don't match")
|
||||
|
||||
text='1234567812345678'[0:ciph.block_size]
|
||||
c=obj.encrypt(text)
|
||||
if (obj.decrypt(c)!=text): die('Error encrypting "'+text+'"')
|
||||
text='KuchlingKuchling'[0:ciph.block_size]
|
||||
c=obj.encrypt(text)
|
||||
if (obj.decrypt(c)!=text): die('Error encrypting "'+text+'"')
|
||||
text='NotTodayNotEver!'[0:ciph.block_size]
|
||||
c=obj.encrypt(text)
|
||||
if (obj.decrypt(c)!=text): die('Error encrypting "'+text+'"')
|
||||
|
||||
start=time.time()
|
||||
s=obj.encrypt(str)
|
||||
s2=obj.decrypt(s)
|
||||
end=time.time()
|
||||
if (str!=s2):
|
||||
die('Error in resulting plaintext from ECB mode')
|
||||
print_timing(256, end-start, verbose)
|
||||
del obj
|
||||
|
||||
if verbose: print ' CFB mode:',
|
||||
obj1=ciph.new(password, ciph.MODE_CFB, IV)
|
||||
obj2=ciph.new(password, ciph.MODE_CFB, IV)
|
||||
start=time.time()
|
||||
ciphertext=obj1.encrypt(str[0:65536])
|
||||
plaintext=obj2.decrypt(ciphertext)
|
||||
end=time.time()
|
||||
if (plaintext!=str[0:65536]):
|
||||
die('Error in resulting plaintext from CFB mode')
|
||||
print_timing(64, end-start, verbose)
|
||||
del obj1, obj2
|
||||
|
||||
if verbose: print ' CBC mode:',
|
||||
obj1=ciph.new(password, ciph.MODE_CBC, IV)
|
||||
obj2=ciph.new(password, ciph.MODE_CBC, IV)
|
||||
start=time.time()
|
||||
ciphertext=obj1.encrypt(str)
|
||||
plaintext=obj2.decrypt(ciphertext)
|
||||
end=time.time()
|
||||
if (plaintext!=str):
|
||||
die('Error in resulting plaintext from CBC mode')
|
||||
print_timing(256, end-start, verbose)
|
||||
del obj1, obj2
|
||||
|
||||
if verbose: print ' PGP mode:',
|
||||
obj1=ciph.new(password, ciph.MODE_PGP, IV)
|
||||
obj2=ciph.new(password, ciph.MODE_PGP, IV)
|
||||
start=time.time()
|
||||
ciphertext=obj1.encrypt(str)
|
||||
plaintext=obj2.decrypt(ciphertext)
|
||||
end=time.time()
|
||||
if (plaintext!=str):
|
||||
die('Error in resulting plaintext from PGP mode')
|
||||
print_timing(256, end-start, verbose)
|
||||
del obj1, obj2
|
||||
|
||||
if verbose: print ' OFB mode:',
|
||||
obj1=ciph.new(password, ciph.MODE_OFB, IV)
|
||||
obj2=ciph.new(password, ciph.MODE_OFB, IV)
|
||||
start=time.time()
|
||||
ciphertext=obj1.encrypt(str)
|
||||
plaintext=obj2.decrypt(ciphertext)
|
||||
end=time.time()
|
||||
if (plaintext!=str):
|
||||
die('Error in resulting plaintext from OFB mode')
|
||||
print_timing(256, end-start, verbose)
|
||||
del obj1, obj2
|
||||
|
||||
def counter(length=ciph.block_size):
|
||||
return length * 'a'
|
||||
|
||||
if verbose: print ' CTR mode:',
|
||||
obj1=ciph.new(password, ciph.MODE_CTR, counter=counter)
|
||||
obj2=ciph.new(password, ciph.MODE_CTR, counter=counter)
|
||||
start=time.time()
|
||||
ciphertext=obj1.encrypt(str)
|
||||
plaintext=obj2.decrypt(ciphertext)
|
||||
end=time.time()
|
||||
if (plaintext!=str):
|
||||
die('Error in resulting plaintext from CTR mode')
|
||||
print_timing(256, end-start, verbose)
|
||||
del obj1, obj2
|
||||
|
||||
# Test the IV handling
|
||||
if verbose: print ' Testing IV handling'
|
||||
obj1=ciph.new(password, ciph.MODE_CBC, IV)
|
||||
plaintext='Test'*(ciph.block_size/4)*3
|
||||
ciphertext1=obj1.encrypt(plaintext)
|
||||
obj1.IV=IV
|
||||
ciphertext2=obj1.encrypt(plaintext)
|
||||
if ciphertext1!=ciphertext2:
|
||||
die('Error in setting IV')
|
||||
|
||||
# Test keyword arguments
|
||||
obj1=ciph.new(key=password)
|
||||
obj1=ciph.new(password, mode=ciph.MODE_CBC)
|
||||
obj1=ciph.new(mode=ciph.MODE_CBC, key=password)
|
||||
obj1=ciph.new(IV=IV, mode=ciph.MODE_CBC, key=password)
|
||||
|
||||
return ciph
|
||||
|
||||
def exerciseStreamCipher(cipher, verbose):
|
||||
import string, time
|
||||
try:
|
||||
ciph = eval(cipher)
|
||||
except (NameError):
|
||||
print cipher, 'module not available'
|
||||
return None
|
||||
print cipher + ':',
|
||||
str='1' # Build 128K of test data
|
||||
for i in xrange(0, 17):
|
||||
str=str+str
|
||||
key_size = ciph.key_size or 16
|
||||
password = 'password12345678Extra text for password'[0:key_size]
|
||||
|
||||
obj1=ciph.new(password)
|
||||
obj2=ciph.new(password)
|
||||
if obj1.block_size != ciph.block_size:
|
||||
die("Module and cipher object block_size don't match")
|
||||
if obj1.key_size != ciph.key_size:
|
||||
die("Module and cipher object key_size don't match")
|
||||
|
||||
text='1234567812345678Python'
|
||||
c=obj1.encrypt(text)
|
||||
if (obj2.decrypt(c)!=text): die('Error encrypting "'+text+'"')
|
||||
text='B1FF I2 A R3A11Y |<00L D00D!!!!!'
|
||||
c=obj1.encrypt(text)
|
||||
if (obj2.decrypt(c)!=text): die('Error encrypting "'+text+'"')
|
||||
text='SpamSpamSpamSpamSpamSpamSpamSpamSpam'
|
||||
c=obj1.encrypt(text)
|
||||
if (obj2.decrypt(c)!=text): die('Error encrypting "'+text+'"')
|
||||
|
||||
start=time.time()
|
||||
s=obj1.encrypt(str)
|
||||
str=obj2.decrypt(s)
|
||||
end=time.time()
|
||||
print_timing(256, end-start, verbose)
|
||||
del obj1, obj2
|
||||
|
||||
return ciph
|
||||
|
||||
def TestStreamModules(args=['arc4', 'XOR'], verbose=1):
|
||||
import sys, string
|
||||
args=map(string.lower, args)
|
||||
|
||||
if 'arc4' in args:
|
||||
# Test ARC4 stream cipher
|
||||
arc4=exerciseStreamCipher('ARC4', verbose)
|
||||
if (arc4!=None):
|
||||
for entry in testdata.arc4:
|
||||
key,plain,cipher=entry
|
||||
key=binascii.a2b_hex(key)
|
||||
plain=binascii.a2b_hex(plain)
|
||||
cipher=binascii.a2b_hex(cipher)
|
||||
obj=arc4.new(key)
|
||||
ciphertext=obj.encrypt(plain)
|
||||
if (ciphertext!=cipher):
|
||||
die('ARC4 failed on entry '+`entry`)
|
||||
|
||||
if 'xor' in args:
|
||||
# Test XOR stream cipher
|
||||
XOR=exerciseStreamCipher('XOR', verbose)
|
||||
if (XOR!=None):
|
||||
for entry in testdata.xor:
|
||||
key,plain,cipher=entry
|
||||
key=binascii.a2b_hex(key)
|
||||
plain=binascii.a2b_hex(plain)
|
||||
cipher=binascii.a2b_hex(cipher)
|
||||
obj=XOR.new(key)
|
||||
ciphertext=obj.encrypt(plain)
|
||||
if (ciphertext!=cipher):
|
||||
die('XOR failed on entry '+`entry`)
|
||||
|
||||
|
||||
def TestBlockModules(args=['aes', 'arc2', 'des', 'blowfish', 'cast', 'des3',
|
||||
'idea', 'rc5'],
|
||||
verbose=1):
|
||||
import string
|
||||
args=map(string.lower, args)
|
||||
if 'aes' in args:
|
||||
ciph=exerciseBlockCipher('AES', verbose) # AES
|
||||
if (ciph!=None):
|
||||
if verbose: print ' Verifying against test suite...'
|
||||
for entry in testdata.aes:
|
||||
key,plain,cipher=entry
|
||||
key=binascii.a2b_hex(key)
|
||||
plain=binascii.a2b_hex(plain)
|
||||
cipher=binascii.a2b_hex(cipher)
|
||||
obj=ciph.new(key, ciph.MODE_ECB)
|
||||
ciphertext=obj.encrypt(plain)
|
||||
if (ciphertext!=cipher):
|
||||
die('AES failed on entry '+`entry`)
|
||||
for i in ciphertext:
|
||||
if verbose: print hex(ord(i)),
|
||||
if verbose: print
|
||||
|
||||
for entry in testdata.aes_modes:
|
||||
mode, key, plain, cipher, kw = entry
|
||||
key=binascii.a2b_hex(key)
|
||||
plain=binascii.a2b_hex(plain)
|
||||
cipher=binascii.a2b_hex(cipher)
|
||||
obj=ciph.new(key, mode, **kw)
|
||||
obj2=ciph.new(key, mode, **kw)
|
||||
ciphertext=obj.encrypt(plain)
|
||||
if (ciphertext!=cipher):
|
||||
die('AES encrypt failed on entry '+`entry`)
|
||||
for i in ciphertext:
|
||||
if verbose: print hex(ord(i)),
|
||||
if verbose: print
|
||||
|
||||
plain2=obj2.decrypt(ciphertext)
|
||||
if plain2!=plain:
|
||||
die('AES decrypt failed on entry '+`entry`)
|
||||
for i in plain2:
|
||||
if verbose: print hex(ord(i)),
|
||||
if verbose: print
|
||||
|
||||
|
||||
if 'arc2' in args:
|
||||
ciph=exerciseBlockCipher('ARC2', verbose) # Alleged RC2
|
||||
if (ciph!=None):
|
||||
if verbose: print ' Verifying against test suite...'
|
||||
for entry in testdata.arc2:
|
||||
key,plain,cipher=entry
|
||||
key=binascii.a2b_hex(key)
|
||||
plain=binascii.a2b_hex(plain)
|
||||
cipher=binascii.a2b_hex(cipher)
|
||||
obj=ciph.new(key, ciph.MODE_ECB)
|
||||
ciphertext=obj.encrypt(plain)
|
||||
if (ciphertext!=cipher):
|
||||
die('ARC2 failed on entry '+`entry`)
|
||||
for i in ciphertext:
|
||||
if verbose: print hex(ord(i)),
|
||||
print
|
||||
|
||||
if 'blowfish' in args:
|
||||
ciph=exerciseBlockCipher('Blowfish',verbose)# Bruce Schneier's Blowfish cipher
|
||||
if (ciph!=None):
|
||||
if verbose: print ' Verifying against test suite...'
|
||||
for entry in testdata.blowfish:
|
||||
key,plain,cipher=entry
|
||||
key=binascii.a2b_hex(key)
|
||||
plain=binascii.a2b_hex(plain)
|
||||
cipher=binascii.a2b_hex(cipher)
|
||||
obj=ciph.new(key, ciph.MODE_ECB)
|
||||
ciphertext=obj.encrypt(plain)
|
||||
if (ciphertext!=cipher):
|
||||
die('Blowfish failed on entry '+`entry`)
|
||||
for i in ciphertext:
|
||||
if verbose: print hex(ord(i)),
|
||||
if verbose: print
|
||||
|
||||
if 'cast' in args:
|
||||
ciph=exerciseBlockCipher('CAST', verbose) # CAST-128
|
||||
if (ciph!=None):
|
||||
if verbose: print ' Verifying against test suite...'
|
||||
for entry in testdata.cast:
|
||||
key,plain,cipher=entry
|
||||
key=binascii.a2b_hex(key)
|
||||
plain=binascii.a2b_hex(plain)
|
||||
cipher=binascii.a2b_hex(cipher)
|
||||
obj=ciph.new(key, ciph.MODE_ECB)
|
||||
ciphertext=obj.encrypt(plain)
|
||||
if (ciphertext!=cipher):
|
||||
die('CAST failed on entry '+`entry`)
|
||||
for i in ciphertext:
|
||||
if verbose: print hex(ord(i)),
|
||||
if verbose: print
|
||||
|
||||
if 0:
|
||||
# The full-maintenance test; it requires 4 million encryptions,
|
||||
# and correspondingly is quite time-consuming. I've disabled
|
||||
# it; it's faster to compile block/cast.c with -DTEST and run
|
||||
# the resulting program.
|
||||
a = b = '\x01\x23\x45\x67\x12\x34\x56\x78\x23\x45\x67\x89\x34\x56\x78\x9A'
|
||||
|
||||
for i in range(0, 1000000):
|
||||
obj = cast.new(b, cast.MODE_ECB)
|
||||
a = obj.encrypt(a[:8]) + obj.encrypt(a[-8:])
|
||||
obj = cast.new(a, cast.MODE_ECB)
|
||||
b = obj.encrypt(b[:8]) + obj.encrypt(b[-8:])
|
||||
|
||||
if a!="\xEE\xA9\xD0\xA2\x49\xFD\x3B\xA6\xB3\x43\x6F\xB8\x9D\x6D\xCA\x92":
|
||||
if verbose: print 'CAST test failed: value of "a" doesn\'t match'
|
||||
if b!="\xB2\xC9\x5E\xB0\x0C\x31\xAD\x71\x80\xAC\x05\xB8\xE8\x3D\x69\x6E":
|
||||
if verbose: print 'CAST test failed: value of "b" doesn\'t match'
|
||||
|
||||
if 'des' in args:
|
||||
# Test/benchmark DES block cipher
|
||||
des=exerciseBlockCipher('DES', verbose)
|
||||
if (des!=None):
|
||||
# Various tests taken from the DES library packaged with Kerberos V4
|
||||
obj=des.new(binascii.a2b_hex('0123456789abcdef'), des.MODE_ECB)
|
||||
s=obj.encrypt('Now is t')
|
||||
if (s!=binascii.a2b_hex('3fa40e8a984d4815')):
|
||||
die('DES fails test 1')
|
||||
obj=des.new(binascii.a2b_hex('08192a3b4c5d6e7f'), des.MODE_ECB)
|
||||
s=obj.encrypt('\000\000\000\000\000\000\000\000')
|
||||
if (s!=binascii.a2b_hex('25ddac3e96176467')):
|
||||
die('DES fails test 2')
|
||||
obj=des.new(binascii.a2b_hex('0123456789abcdef'), des.MODE_CBC,
|
||||
binascii.a2b_hex('1234567890abcdef'))
|
||||
s=obj.encrypt("Now is the time for all ")
|
||||
if (s!=binascii.a2b_hex('e5c7cdde872bf27c43e934008c389c0f683788499a7c05f6')):
|
||||
die('DES fails test 3')
|
||||
obj=des.new(binascii.a2b_hex('0123456789abcdef'), des.MODE_CBC,
|
||||
binascii.a2b_hex('fedcba9876543210'))
|
||||
s=obj.encrypt("7654321 Now is the time for \000\000\000\000")
|
||||
if (s!=binascii.a2b_hex("ccd173ffab2039f4acd8aefddfd8a1eb468e91157888ba681d269397f7fe62b4")):
|
||||
die('DES fails test 4')
|
||||
del obj,s
|
||||
|
||||
# R. Rivest's test: see http://theory.lcs.mit.edu/~rivest/destest.txt
|
||||
x=binascii.a2b_hex('9474B8E8C73BCA7D')
|
||||
for i in range(0, 16):
|
||||
obj=des.new(x, des.MODE_ECB)
|
||||
if (i & 1): x=obj.decrypt(x)
|
||||
else: x=obj.encrypt(x)
|
||||
if x!=binascii.a2b_hex('1B1A2DDB4C642438'):
|
||||
die("DES fails Rivest's test")
|
||||
|
||||
if verbose: print ' Verifying against test suite...'
|
||||
for entry in testdata.des:
|
||||
key,plain,cipher=entry
|
||||
key=binascii.a2b_hex(key)
|
||||
plain=binascii.a2b_hex(plain)
|
||||
cipher=binascii.a2b_hex(cipher)
|
||||
obj=des.new(key, des.MODE_ECB)
|
||||
ciphertext=obj.encrypt(plain)
|
||||
if (ciphertext!=cipher):
|
||||
die('DES failed on entry '+`entry`)
|
||||
for entry in testdata.des_cbc:
|
||||
key, iv, plain, cipher=entry
|
||||
key, iv, cipher=binascii.a2b_hex(key),binascii.a2b_hex(iv),binascii.a2b_hex(cipher)
|
||||
obj1=des.new(key, des.MODE_CBC, iv)
|
||||
obj2=des.new(key, des.MODE_CBC, iv)
|
||||
ciphertext=obj1.encrypt(plain)
|
||||
if (ciphertext!=cipher):
|
||||
die('DES CBC mode failed on entry '+`entry`)
|
||||
|
||||
if 'des3' in args:
|
||||
ciph=exerciseBlockCipher('DES3', verbose) # Triple DES
|
||||
if (ciph!=None):
|
||||
if verbose: print ' Verifying against test suite...'
|
||||
for entry in testdata.des3:
|
||||
key,plain,cipher=entry
|
||||
key=binascii.a2b_hex(key)
|
||||
plain=binascii.a2b_hex(plain)
|
||||
cipher=binascii.a2b_hex(cipher)
|
||||
obj=ciph.new(key, ciph.MODE_ECB)
|
||||
ciphertext=obj.encrypt(plain)
|
||||
if (ciphertext!=cipher):
|
||||
die('DES3 failed on entry '+`entry`)
|
||||
for i in ciphertext:
|
||||
if verbose: print hex(ord(i)),
|
||||
if verbose: print
|
||||
for entry in testdata.des3_cbc:
|
||||
key, iv, plain, cipher=entry
|
||||
key, iv, cipher=binascii.a2b_hex(key),binascii.a2b_hex(iv),binascii.a2b_hex(cipher)
|
||||
obj1=ciph.new(key, ciph.MODE_CBC, iv)
|
||||
obj2=ciph.new(key, ciph.MODE_CBC, iv)
|
||||
ciphertext=obj1.encrypt(plain)
|
||||
if (ciphertext!=cipher):
|
||||
die('DES3 CBC mode failed on entry '+`entry`)
|
||||
|
||||
if 'idea' in args:
|
||||
ciph=exerciseBlockCipher('IDEA', verbose) # IDEA block cipher
|
||||
if (ciph!=None):
|
||||
if verbose: print ' Verifying against test suite...'
|
||||
for entry in testdata.idea:
|
||||
key,plain,cipher=entry
|
||||
key=binascii.a2b_hex(key)
|
||||
plain=binascii.a2b_hex(plain)
|
||||
cipher=binascii.a2b_hex(cipher)
|
||||
obj=ciph.new(key, ciph.MODE_ECB)
|
||||
ciphertext=obj.encrypt(plain)
|
||||
if (ciphertext!=cipher):
|
||||
die('IDEA failed on entry '+`entry`)
|
||||
|
||||
if 'rc5' in args:
|
||||
# Ronald Rivest's RC5 algorithm
|
||||
ciph=exerciseBlockCipher('RC5', verbose)
|
||||
if (ciph!=None):
|
||||
if verbose: print ' Verifying against test suite...'
|
||||
for entry in testdata.rc5:
|
||||
key,plain,cipher=entry
|
||||
key=binascii.a2b_hex(key)
|
||||
plain=binascii.a2b_hex(plain)
|
||||
cipher=binascii.a2b_hex(cipher)
|
||||
obj=ciph.new(key[4:], ciph.MODE_ECB,
|
||||
version =ord(key[0]),
|
||||
word_size=ord(key[1]),
|
||||
rounds =ord(key[2]) )
|
||||
ciphertext=obj.encrypt(plain)
|
||||
if (ciphertext!=cipher):
|
||||
die('RC5 failed on entry '+`entry`)
|
||||
for i in ciphertext:
|
||||
if verbose: print hex(ord(i)),
|
||||
if verbose: print
|
||||
|
||||
|
||||
|
25
python/gdata/Crypto/__init__.py
Normal file
25
python/gdata/Crypto/__init__.py
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
"""Python Cryptography Toolkit
|
||||
|
||||
A collection of cryptographic modules implementing various algorithms
|
||||
and protocols.
|
||||
|
||||
Subpackages:
|
||||
Crypto.Cipher Secret-key encryption algorithms (AES, DES, ARC4)
|
||||
Crypto.Hash Hashing algorithms (MD5, SHA, HMAC)
|
||||
Crypto.Protocol Cryptographic protocols (Chaffing, all-or-nothing
|
||||
transform). This package does not contain any
|
||||
network protocols.
|
||||
Crypto.PublicKey Public-key encryption and signature algorithms
|
||||
(RSA, DSA)
|
||||
Crypto.Util Various useful modules and functions (long-to-string
|
||||
conversion, random number generation, number
|
||||
theoretic functions)
|
||||
"""
|
||||
|
||||
__all__ = ['Cipher', 'Hash', 'Protocol', 'PublicKey', 'Util']
|
||||
|
||||
__version__ = '2.0.1'
|
||||
__revision__ = "$Id: __init__.py,v 1.12 2005/06/14 01:20:22 akuchling Exp $"
|
||||
|
||||
|
38
python/gdata/Crypto/test.py
Normal file
38
python/gdata/Crypto/test.py
Normal file
@@ -0,0 +1,38 @@
|
||||
#
|
||||
# Test script for the Python Cryptography Toolkit.
|
||||
#
|
||||
|
||||
__revision__ = "$Id: test.py,v 1.7 2002/07/11 14:31:19 akuchling Exp $"
|
||||
|
||||
import os, sys
|
||||
|
||||
|
||||
# Add the build directory to the front of sys.path
|
||||
from distutils.util import get_platform
|
||||
s = "build/lib.%s-%.3s" % (get_platform(), sys.version)
|
||||
s = os.path.join(os.getcwd(), s)
|
||||
sys.path.insert(0, s)
|
||||
s = os.path.join(os.getcwd(), 'test')
|
||||
sys.path.insert(0, s)
|
||||
|
||||
from Crypto.Util import test
|
||||
|
||||
args = sys.argv[1:]
|
||||
quiet = "--quiet" in args
|
||||
if quiet: args.remove('--quiet')
|
||||
|
||||
if not quiet:
|
||||
print '\nStream Ciphers:'
|
||||
print '==============='
|
||||
|
||||
if args: test.TestStreamModules(args, verbose= not quiet)
|
||||
else: test.TestStreamModules(verbose= not quiet)
|
||||
|
||||
if not quiet:
|
||||
print '\nBlock Ciphers:'
|
||||
print '=============='
|
||||
|
||||
if args: test.TestBlockModules(args, verbose= not quiet)
|
||||
else: test.TestBlockModules(verbose= not quiet)
|
||||
|
||||
|
Reference in New Issue
Block a user