summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThorsten Behrens <sbehrens@gmx.li>2011-01-03 22:30:23 -0500
committerThorsten Behrens <sbehrens@gmx.li>2011-01-03 22:30:23 -0500
commit83cd648f8a125f788fd6afdf781775840455a317 (patch)
treecabe6731e83464d5fc0bae722563c96b193a18aa
parent560874f4b8711897ea644b8f5817113e7221dbec (diff)
downloadpycrypto-83cd648f8a125f788fd6afdf781775840455a317.tar.gz
Add unit test for AllOrNothing
Note that AllOrNothing fails occasionally. This has always been the case; the unit test merely forces the flaw to be exposed.
-rw-r--r--Doc/pycrypt.rst57
-rw-r--r--lib/Crypto/Protocol/AllOrNothing.py19
-rw-r--r--lib/Crypto/SelfTest/Protocol/__init__.py1
-rw-r--r--python-3-changes.txt11
4 files changed, 66 insertions, 22 deletions
diff --git a/Doc/pycrypt.rst b/Doc/pycrypt.rst
index 9005ee3..660d29b 100644
--- a/Doc/pycrypt.rst
+++ b/Doc/pycrypt.rst
@@ -321,7 +321,7 @@ CAST Variable/8 bytes
DES 8 bytes/8 bytes
DES3 (Triple DES) 16 bytes/8 bytes
IDEA 16 bytes/8 bytes
-RC5 Variable/8 bytes
+[RC5 Variable/8 bytes]
================= ============================
@@ -438,9 +438,15 @@ encrypt() will return a bytes object.
Algorithm-specific Notes for Encryption Algorithms
=======================================================
+[RC5 is not currently implemented in pycrypto]
+
RC5 has a bunch of parameters; see Ronald Rivest's paper at
<http://theory.lcs.mit.edu/~rivest/rc5rev.ps> for the
-implementation details. The keyword parameters are:
+implementation details. RC5 is patented by RSA Laboratories.
+RC5 supports 32-bit, 64-bit and 128-bit block sizes. RSA suggests a block size
+of 64-bit, a 128-bit key and 18-20 rounds.
+
+The keyword parameters are:
* ``version``: The version of the RC5 algorithm to use; currently
the only legal value is ``0x10`` for RC5 1.0.
@@ -451,7 +457,9 @@ implementation details. The keyword parameters are:
* ``rounds``: The number of rounds to apply, the larger the more
secure: this can be any value from 0 to 255, so you will have to
- choose a value balanced between speed and security.
+ choose a value balanced between speed and security. 12-round RC5
+ is susceptible to a differential attack. 18-20 rounds are suggested
+ as sufficient protection.
Security Notes
@@ -467,6 +475,10 @@ encrypted and forwarded to someone else. This is a
possible to choose plaintexts that reveal something about the key when
encrypted.
+Stream ciphers are only secure if any given key is never used twice.
+If two (or more) messages are encrypted using the same key in a stream
+cipher, the cipher can be broken fairly easily.
+
DES (5100 K/sec) has a 56-bit key; this is starting to become too small
for safety. It has been shown in 2009 that a ~$10,000 machine can break
DES in under a day on average. NIST has withdrawn FIPS 46-3 in 2005.
@@ -479,14 +491,21 @@ study applied against it. It is, however, slow.
There are no publicly known attacks against the full-round IDEA (3050 K/sec),
and it's been around long enough to have been examined. IDEA is patented but
free for non-commercial use. Patents are expected to expire in 2011/2012.
-There are no known attacks against ARC2 (2160 K/sec), ARC4 (8830 K/sec),
-Blowfish (9250 K/sec), CAST (2960 K/sec), or RC5 (2060 K/sec), but they're all
-relatively new algorithms and there hasn't been time for much analysis
-to be performed; use them for serious applications only after careful
-research.
+IDEA is one of the strongest symmetric ciphers available to the public, alongside
+AES and AES candidates.
+
+There are no known attacks against Blowfish (9250 K/sec), CAST (2960 K/sec),
+or RC5 (2060 K/sec), but they're all relatively new algorithms and there hasn't
+been time for much analysis to be performed; use them for serious applications
+only after careful research.
+
+pycrypto implements CAST with up to 128 bits key length (CAST-128). This
+algorithm is considered obsoleted by CAST-256. CAST is patented by Entrust
+Technologies and free for non-commercial use.
+
Bruce Schneier recommends his newer Twofish algorithm over Blowfish where
a fast, secure symmetric cipher is desired. Twofish was an AES candidate. It
-is slightly slower than Rijndael (the chose algorithm for AES) for 128-bit
+is slightly slower than Rijndael (the chosen algorithm for AES) for 128-bit
keys, and slightly faster for 256-bit keys.
AES, the Advanced Encryption Standard, was chosen by the US National
@@ -494,6 +513,26 @@ Institute of Standards and Technology from among 6 competitors, and is
probably your best choice. It runs at 7060 K/sec, so it's among the
faster algorithms around.
+ARC4 ("Alleged" RC4) (8830 K/sec) has been weakened. Specifically, it has been
+shown that the first few bytes of the ARC4 keystream are strongly non-random,
+leaking information about the key. When the long-term key and nonce are merely
+concatenated to form the ARC4 key, such as is done in WEP, this weakness can be
+used to discover the long-term key by observing a large number of messages
+encrypted with this key.
+Because of these possible related-key attacks, ARC4 should only be used with
+keys generated by a strong RNG, or from a source of sufficiently uncorrelated
+bits, such as the output of a hash function.
+A further possible defense is to discard the initial portion of the keystream.
+This altered algorithm is called RC4-drop(n).
+While ARC4 is in wide-spread use in several protocols, its use in new protocols
+or applications is discouraged.
+RC4 is patented by RSA Laboratories.
+
+ARC2 ("Alleged" RC2) is vulnerable to a related-key attack, 2^34 chosen
+plaintexts are needed.
+Because of these possible related-key attacks, ARC2 should only be used with
+keys generated by a strong RNG, or from a source of sufficiently uncorrelated
+bits, such as the output of a hash function.
Credits
=============
diff --git a/lib/Crypto/Protocol/AllOrNothing.py b/lib/Crypto/Protocol/AllOrNothing.py
index e43fd8b..f2d70bc 100644
--- a/lib/Crypto/Protocol/AllOrNothing.py
+++ b/lib/Crypto/Protocol/AllOrNothing.py
@@ -114,7 +114,7 @@ class AllOrNothing:
# the undigest() step.
block_size = self.__ciphermodule.block_size
padbytes = block_size - (len(text) % block_size)
- text = text + ' ' * padbytes
+ text = text + b(' ') * padbytes
# Run through the algorithm:
# s: number of message blocks (size of text / block_size)
@@ -128,7 +128,7 @@ class AllOrNothing:
# 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
+ s = divmod(len(text), block_size)[0]
blocks = []
hashes = []
for i in range(1, s+1):
@@ -219,8 +219,7 @@ class AllOrNothing:
# 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])
- # PY3K: This is meant to be text, do not change to bytes (data)
- text = ''.join(map(long_to_bytes, parts[:-1]))
+ text = b('').join(map(long_to_bytes, parts[:-1]))
return text[:-padbytes]
def _inventkey(self, key_size):
@@ -291,13 +290,13 @@ Where:
# ugly hack to force __import__ to give us the end-path module
module = __import__('Crypto.Cipher.'+ciphermodule, None, None, ['new'])
- a = AllOrNothing(module)
+ x = AllOrNothing(module)
print 'Original text:\n=========='
print __doc__
print '=========='
- msgblocks = a.digest(__doc__)
+ msgblocks = x.digest(b(__doc__))
print 'message blocks:'
- for i, blk in map(None, range(len(msgblocks)), msgblocks):
+ for i, blk in zip(range(len(msgblocks)), msgblocks):
# base64 adds a trailing newline
print ' %3d' % i,
if aslong:
@@ -306,9 +305,9 @@ Where:
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__:
+ y = AllOrNothing(module)
+ text = y.undigest(msgblocks)
+ if text == b(__doc__):
print 'They match!'
else:
print 'They differ!'
diff --git a/lib/Crypto/SelfTest/Protocol/__init__.py b/lib/Crypto/SelfTest/Protocol/__init__.py
index dba6148..fc18ba8 100644
--- a/lib/Crypto/SelfTest/Protocol/__init__.py
+++ b/lib/Crypto/SelfTest/Protocol/__init__.py
@@ -30,6 +30,7 @@ def get_tests(config={}):
tests = []
import test_chaffing; tests += test_chaffing.get_tests(config=config)
import test_rfc1751; tests += test_rfc1751.get_tests(config=config)
+ import test_AllOrNothing; tests += test_AllOrNothing.get_tests(config=config)
return tests
if __name__ == '__main__':
diff --git a/python-3-changes.txt b/python-3-changes.txt
index 880405b..ea2c04c 100644
--- a/python-3-changes.txt
+++ b/python-3-changes.txt
@@ -58,6 +58,12 @@ Use instead assertEqual(expr,True) for assert_ and assertEqual(expr,False) for
failIf
Added unit tests for Crypto.Random.random. Fixed random.shuffle().
+Not changed: random.sample() fails on Python 2.1. This is now exposed through
+ the unit test.
+
+Added unit test for Crypto.Protocol.AllOrNothing.
+Not changed: AllOrNothing fails when called a few times (<10, usually). This
+ is now exposed through the unit test.
C code:
@@ -95,12 +101,11 @@ getattr cannot be used to check against custom attributes in 3.x. For 3.x,
hexdigest() needed to be changed to return a Unicode object with 3.x
-TODO:
+TODO for extra credit:
- Check for type of string in functions and throw an error when it's not
correct. While at it, ensure that functions observe the guidelines below
re type.
This is friendlier than just relying on Python's errors.
-- Need additional unit tests for Protocol/AllOrNothing
- Make sure DerSequence slicing is tested, since I took the explicit slice
functions away in 3.x
-- Test install on all tested Python versions
+