/relevation/branches/1.1/python-cryptoplus/src/CryptoPlus/Cipher/DES3.py |
---|
0,0 → 1,74 |
from blockcipher import * |
import Crypto.Cipher.DES3 |
def new(key,mode=MODE_ECB,IV=None,counter=None,segment_size=None): |
"""Create a new cipher object |
DES using pycrypto for algo and pycryptoplus for ciphermode |
key = raw string containing the 2/3 keys |
- DES-EDE2: supply 2 keys as 1 single concatenated 16byte key= key1|key2 |
- DES-EDE3: supply 3 keys as 1 single concatenated 24byte key= key1|key2|key3 |
mode = python_AES.MODE_ECB/CBC/CFB/OFB/CTR/CMAC, default is ECB |
IV = IV as a raw string, default is "all zero" IV |
-> only needed for CBC mode |
counter = counter object (CryptoPlus.Util.util.Counter) |
-> only needed for CTR mode |
segment_size = amount of bits to use from the keystream in each chain part |
-> supported values: multiple of 8 between 8 and the blocksize |
of the cipher (only per byte access possible), default is 8 |
-> only needed for CFB mode |
EXAMPLES: |
********** |
IMPORTING: |
----------- |
>>> from CryptoPlus.Cipher import DES3 |
CBC TDES-EDE3 EXAMPLE: (using test vectors from http://csrc.nist.gov/groups/STM/cavp/documents/des/DESMMT.pdf) |
------------ |
>>> key = ('37ae5ebf46dff2dc0754b94f31cbb3855e7fd36dc870bfae').decode('hex') |
>>> IV = ('3d1de3cc132e3b65').decode('hex') |
>>> cipher = DES3.new(key, DES3.MODE_CBC, IV) |
>>> ciphertext = cipher.encrypt(('84401f78fe6c10876d8ea23094ea5309').decode('hex')) |
>>> (ciphertext).encode('hex') |
'7b1f7c7e3b1c948ebd04a75ffba7d2f5' |
>>> decipher = DES3.new(key, DES3.MODE_CBC, IV) |
>>> plaintext = decipher.decrypt(ciphertext) |
>>> (plaintext).encode('hex') |
'84401f78fe6c10876d8ea23094ea5309' |
CMAC TDES-EDE3 EXAMPLE: (http://csrc.nist.gov/publications/nistpubs/800-38B/Updated_CMAC_Examples.pdf) |
------------- |
>>> key = '8aa83bf8cbda10620bc1bf19fbb6cd58bc313d4a371ca8b5'.decode('hex') |
>>> plaintext = '6bc1bee22e409f96e93d7e117393172aae2d8a57'.decode('hex') |
>>> cipher = DES3.new(key, DES3.MODE_CMAC) |
>>> cipher.encrypt(plaintext).encode('hex') |
'743ddbe0ce2dc2ed' |
CMAC TDES-EDE2 EXAMPLE: |
----------------------- |
testvector: http://csrc.nist.gov/groups/STM/cavp/documents/mac/cmactestvectors.zip |
>>> key1 = "5104f2c76180c1d3".decode('hex') |
>>> key2 = "b9df763e31ada716".decode('hex') |
>>> key = key1 + key2 |
>>> plaintext = 'a6866be2fa6678f264a19c4474968e3f4eec24f5086d'.decode('hex') |
>>> cipher = DES3.new(key, DES3.MODE_CMAC) |
>>> cipher.encrypt(plaintext).encode('hex') |
'32e7758f3f614dbf' |
""" |
return DES3(key,mode,IV,counter,segment_size) |
class DES3(BlockCipher): |
def __init__(self,key,mode,IV,counter,segment_size): |
cipher_module = Crypto.Cipher.DES3.new |
self.blocksize = 8 |
BlockCipher.__init__(self,key,mode,IV,counter,cipher_module,segment_size) |
def _test(): |
import doctest |
doctest.testmod() |
if __name__ == "__main__": |
_test() |
/relevation/branches/1.1/python-cryptoplus/src/CryptoPlus/Cipher/__init__.py |
---|
0,0 → 1,10 |
from Crypto.Cipher import ARC4, XOR |
__all__ = ["AES","python_AES","python_DES","python_DES3","DES","DES3","Blowfish","python_Blowfish","python_Twofish","python_Serpent","python_Rijndael","ARC4","ARC2","CAST","XOR","python_PRESENT"] |
try: |
import Crypto.Cipher.IDEA |
__all__.append("IDEA") |
__all__.append("RC5") |
except ImportError: |
pass |
/relevation/branches/1.1/python-cryptoplus/src/CryptoPlus/Cipher/python_DES3.py |
---|
0,0 → 1,80 |
from blockcipher import * |
import pyDes |
def new(key,mode=MODE_ECB,IV=None,counter=None,segment_size=None): |
"""Create a DES-EDE3 or DES-EDE2 cipher object |
wrapper for pure python 3DES implementation pyDes.py |
key = raw string containing the 2/3 keys |
- DES-EDE2: supply 2 keys as 1 single concatenated 16byte key= key1|key2 |
- DES-EDE3: supply 3 keys as 1 single concatenated 24byte key= key1|key2|key3 |
mode = python_AES.MODE_ECB/CBC/CFB/OFB/CTR/CMAC, default is ECB |
IV = IV as a raw string, default is "all zero" IV |
-> only needed for CBC mode |
counter = counter object (CryptoPlus.Util.util.Counter) |
-> only needed for CTR mode |
segment_size = amount of bits to use from the keystream in each chain part |
-> supported values: multiple of 8 between 8 and the blocksize |
of the cipher (only per byte access possible), default is 8 |
-> only needed for CFB mode |
EXAMPLES: |
********** |
IMPORTING: |
----------- |
>>> from CryptoPlus.Cipher import python_DES3 |
CBC TDES-EDE3 EXAMPLE: (using test vectors from http://csrc.nist.gov/groups/STM/cavp/documents/des/DESMMT.pdf) |
------------ |
>>> key = ('37ae5ebf46dff2dc0754b94f31cbb3855e7fd36dc870bfae').decode('hex') |
>>> IV = ('3d1de3cc132e3b65').decode('hex') |
>>> cipher = python_DES3.new(key, python_DES3.MODE_CBC, IV) |
>>> ciphertext = cipher.encrypt(('84401f78fe6c10876d8ea23094ea5309').decode('hex')) |
>>> (ciphertext).encode('hex') |
'7b1f7c7e3b1c948ebd04a75ffba7d2f5' |
>>> decipher = python_DES3.new(key, python_DES3.MODE_CBC, IV) |
>>> plaintext = decipher.decrypt(ciphertext) |
>>> (plaintext).encode('hex') |
'84401f78fe6c10876d8ea23094ea5309' |
CMAC TDES-EDE3 EXAMPLE: |
------------- |
testvector: http://csrc.nist.gov/publications/nistpubs/800-38B/Updated_CMAC_Examples.pdf |
>>> key = '8aa83bf8cbda10620bc1bf19fbb6cd58bc313d4a371ca8b5'.decode('hex') |
>>> plaintext = '6bc1bee22e409f96e93d7e117393172aae2d8a57'.decode('hex') |
>>> cipher = python_DES3.new(key, python_DES3.MODE_CMAC) |
>>> cipher.encrypt(plaintext).encode('hex') |
'743ddbe0ce2dc2ed' |
CMAC TDES-EDE2 EXAMPLE: |
----------------------- |
testvector: http://csrc.nist.gov/groups/STM/cavp/documents/mac/cmactestvectors.zip |
>>> key1 = "5104f2c76180c1d3".decode('hex') |
>>> key2 = "b9df763e31ada716".decode('hex') |
>>> key = key1 + key2 |
>>> plaintext = 'a6866be2fa6678f264a19c4474968e3f4eec24f5086d'.decode('hex') |
>>> cipher = python_DES3.new(key, python_DES3.MODE_CMAC) |
>>> cipher.encrypt(plaintext).encode('hex') |
'32e7758f3f614dbf'""" |
return python_DES3(key,mode,IV,counter,segment_size) |
class python_DES3(BlockCipher): |
key_error_message = "Key should be 128 or 192 bits" |
def __init__(self,key,mode,IV,counter,segment_size): |
cipher_module = pyDes.triple_des |
self.blocksize = 8 |
BlockCipher.__init__(self,key,mode,IV,counter,cipher_module,segment_size) |
def keylen_valid(self,key): |
return len(key) in (16,24) |
def _test(): |
import doctest |
doctest.testmod() |
if __name__ == "__main__": |
_test() |
/relevation/branches/1.1/python-cryptoplus/src/CryptoPlus/Cipher/IDEA.py |
---|
0,0 → 1,52 |
from blockcipher import * |
try: |
import Crypto.Cipher.IDEA |
except ImportError: |
print "Crypto.Cipher.IDEA isn't available. You're probably using the Debian pycrypto version. Install the original pycrypto for IDEA." |
raise |
def new(key,mode=MODE_ECB,IV=None,counter=None,segment_size=None): |
"""Create a new cipher object |
IDEA using pycrypto for algo and pycryptoplus for ciphermode |
key = raw string containing the keys |
mode = python_AES.MODE_ECB/CBC/CFB/OFB/CTR/CMAC, default is ECB |
IV = IV as a raw string, default is "all zero" IV |
-> only needed for CBC mode |
counter = counter object (CryptoPlus.Util.util.Counter) |
-> only needed for CTR mode |
segment_size = amount of bits to use from the keystream in each chain part |
-> supported values: multiple of 8 between 8 and the blocksize |
of the cipher (only per byte access possible), default is 8 |
-> only needed for CFB mode |
EXAMPLES: |
********** |
IMPORTING: |
----------- |
>>> from CryptoPlus.Cipher import IDEA |
https://www.cosic.esat.kuleuven.be/nessie/testvectors/ |
----------------------------------------- |
>>> from CryptoPlus.Cipher import IDEA |
>>> key = "2BD6459F82C5B300952C49104881FF48".decode('hex') |
>>> plaintext = "F129A6601EF62A47".decode('hex') |
>>> cipher = IDEA.new(key,IDEA.MODE_ECB,) |
>>> cipher.encrypt(plaintext).encode('hex').upper() |
'EA024714AD5C4D84' |
""" |
return IDEA(key,mode,IV,counter,segment_size) |
class IDEA(BlockCipher): |
def __init__(self,key,mode,IV,counter,segment_size): |
cipher_module = Crypto.Cipher.IDEA.new |
self.blocksize = 8 |
BlockCipher.__init__(self,key,mode,IV,counter,cipher_module,segment_size) |
def _test(): |
import doctest |
doctest.testmod() |
if __name__ == "__main__": |
_test() |
/relevation/branches/1.1/python-cryptoplus/src/CryptoPlus/Cipher/AES.py |
---|
0,0 → 1,147 |
from blockcipher import * |
import Crypto.Cipher.AES |
def new(key,mode=MODE_ECB,IV=None,counter=None,segment_size=None): |
"""Create a new cipher object |
key = raw string containing the key, AES-128..256 will be selected according to the key length |
-> when using XTS mode: the key should be a tuple of the 2 keys needed |
mode = AES.MODE_ECB/CBC/CFB/OFB/CTR/XTS/CMAC, default is ECB |
IV = IV as a raw string, default is "all zero" IV |
-> only needed for CBC mode |
counter = counter object (CryptoPlus.Util.util.Counter) |
-> only needed for CTR mode |
segment_size = amount of bits to use from the keystream in each chain part |
-> supported values: multiple of 8 between 8 and the blocksize |
of the cipher (only per byte access possible), default is 8 |
-> only needed for CFB mode |
EXAMPLES: |
********** |
IMPORTING: |
----------- |
>>> from CryptoPlus.Cipher import AES |
ECB EXAMPLE: |
------------- |
NIST Special Publication 800-38A http://cryptome.org/bcm/sp800-38a.htm#F |
>>> cipher = AES.new('2b7e151628aed2a6abf7158809cf4f3c'.decode('hex')) |
>>> crypted = cipher.encrypt('6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51'.decode('hex')) |
>>> crypted.encode('hex') |
'3ad77bb40d7a3660a89ecaf32466ef97f5d3d58503b9699de785895a96fdbaaf' |
>>> decipher = AES.new('2b7e151628aed2a6abf7158809cf4f3c'.decode('hex')) |
>>> decipher.decrypt(crypted).encode('hex') |
'6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51' |
CBC EXAMPLE (plaintext = 3 blocksizes): |
----------------------------------------- |
NIST Special Publication 800-38A http://cryptome.org/bcm/sp800-38a.htm#F |
>>> key = ('2b7e151628aed2a6abf7158809cf4f3c').decode('hex') |
>>> IV = ('000102030405060708090a0b0c0d0e0f').decode('hex') |
>>> plaintext1 = ('6bc1bee22e409f96e93d7e117393172a').decode('hex') |
>>> plaintext2 = ('ae2d8a571e03ac9c9eb76fac45af8e51').decode('hex') |
>>> plaintext3 = ('30c81c46a35ce411e5fbc1191a0a52ef').decode('hex') |
>>> cipher = AES.new(key,AES.MODE_CBC,IV) |
>>> ciphertext = cipher.encrypt(plaintext1 + plaintext2 + plaintext3) |
>>> (ciphertext).encode('hex') |
'7649abac8119b246cee98e9b12e9197d5086cb9b507219ee95db113a917678b273bed6b8e3c1743b7116e69e22229516' |
>>> decipher = AES.new(key,AES.MODE_CBC,IV) |
>>> plaintext = decipher.decrypt(ciphertext) |
>>> (plaintext).encode('hex') |
'6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52ef' |
OR: supply plaintext as separate pieces: |
------------------------------------------ |
>>> cipher = AES.new(key,AES.MODE_CBC,IV) |
>>> ( cipher.encrypt(plaintext1 + plaintext2[:-2]) ).encode('hex') |
'7649abac8119b246cee98e9b12e9197d' |
>>> ( cipher.encrypt(plaintext2[-2:] + plaintext3) ).encode('hex') |
'5086cb9b507219ee95db113a917678b273bed6b8e3c1743b7116e69e22229516' |
>>> decipher = AES.new(key,AES.MODE_CBC,IV) |
>>> (decipher.decrypt(ciphertext[:22])).encode('hex') |
'6bc1bee22e409f96e93d7e117393172a' |
>>> (decipher.decrypt(ciphertext[22:])).encode('hex') |
'ae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52ef' |
CTR EXAMPLE: |
------------ |
NIST Special Publication 800-38A http://cryptome.org/bcm/sp800-38a.htm#F |
>>> from CryptoPlus.Util.util import Counter |
>>> key = '2b7e151628aed2a6abf7158809cf4f3c'.decode('hex') |
>>> counter = Counter('f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff'.decode('hex')) |
>>> cipher = AES.new(key,AES.MODE_CTR,counter=counter) |
>>> plaintext1 = '6bc1bee22e409f96e93d7e117393172a'.decode('hex') |
>>> plaintext2 = 'ae2d8a571e03ac9c9eb76fac45af8e51'.decode('hex') |
>>> plaintext3 = '30c81c46a35ce411e5fbc1191a0a52ef'.decode('hex') |
>>> ciphertext = cipher.encrypt(plaintext1 + plaintext2 + plaintext3) |
>>> ciphertext.encode('hex') |
'874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff5ae4df3edbd5d35e5b4f09020db03eab' |
>>> counter2 = Counter('f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff'.decode('hex')) |
>>> decipher = AES.new(key,AES.MODE_CTR,counter=counter2) |
>>> decipher.decrypt(ciphertext).encode('hex') |
'6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52ef' |
XTS EXAMPLE: |
cipher/decipher plaintext of 3 blocks, provided as a 2 pieces (31 bytes + 33 bytes) |
------------ |
>>> key = (('2b7e151628aed2a6abf7158809cf4f3c').decode('hex'),('2b7e151628aed2a6abf7158809cf4f3c').decode('hex')) |
>>> plaintext1 = ('6bc1bee22e409f96e93d7e117393172a').decode('hex') |
>>> plaintext2 = ('ae2d8a571e03ac9c9eb76fac45af8e51').decode('hex') |
>>> plaintext3 = ('30c81c46a35ce411e5fbc1191a0a52ef').decode('hex') |
>>> cipher = AES.new(key,AES.MODE_XTS) |
>>> ciphertext = cipher.encrypt(plaintext1 + plaintext2[:15]) |
>>> decipher = AES.new(key,AES.MODE_XTS) |
>>> deciphertext = decipher.decrypt(ciphertext) |
>>> (deciphertext).encode('hex') |
'6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e' |
>>> ciphertext2 = cipher.encrypt(plaintext2[15:]+plaintext3) |
>>> deciphertext2 = decipher.decrypt(ciphertext2) |
>>> (deciphertext2).encode('hex') |
'5130c81c46a35ce411e5fbc1191a0a52ef' |
XTS-AES-128 applied for a data unit of 512 bytes |
testvector: http://grouper.ieee.org/groups/1619/email/pdf00086.pdf |
>>> key = ('27182818284590452353602874713526'.decode('hex'),'31415926535897932384626433832795'.decode('hex')) |
>>> plaintext = '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff'.decode('hex') |
>>> cipher = AES.new(key,AES.MODE_XTS) |
>>> cipher.encrypt(plaintext).encode('hex') |
'27a7479befa1d476489f308cd4cfa6e2a96e4bbe3208ff25287dd3819616e89cc78cf7f5e543445f8333d8fa7f56000005279fa5d8b5e4ad40e736ddb4d35412328063fd2aab53e5ea1e0a9f332500a5df9487d07a5c92cc512c8866c7e860ce93fdf166a24912b422976146ae20ce846bb7dc9ba94a767aaef20c0d61ad02655ea92dc4c4e41a8952c651d33174be51a10c421110e6d81588ede82103a252d8a750e8768defffed9122810aaeb99f9172af82b604dc4b8e51bcb08235a6f4341332e4ca60482a4ba1a03b3e65008fc5da76b70bf1690db4eae29c5f1badd03c5ccf2a55d705ddcd86d449511ceb7ec30bf12b1fa35b913f9f747a8afd1b130e94bff94effd01a91735ca1726acd0b197c4e5b03393697e126826fb6bbde8ecc1e08298516e2c9ed03ff3c1b7860f6de76d4cecd94c8119855ef5297ca67e9f3e7ff72b1e99785ca0a7e7720c5b36dc6d72cac9574c8cbbc2f801e23e56fd344b07f22154beba0f08ce8891e643ed995c94d9a69c9f1b5f499027a78572aeebd74d20cc39881c213ee770b1010e4bea718846977ae119f7a023ab58cca0ad752afe656bb3c17256a9f6e9bf19fdd5a38fc82bbe872c5539edb609ef4f79c203ebb140f2e583cb2ad15b4aa5b655016a8449277dbd477ef2c8d6c017db738b18deb4a427d1923ce3ff262735779a418f20a282df920147beabe421ee5319d0568' |
CMAC EXAMPLE: |
------------- |
NIST publication 800-38B: http://csrc.nist.gov/publications/nistpubs/800-38B/Updated_CMAC_Examples.pdf |
>>> key = '2b7e151628aed2a6abf7158809cf4f3c'.decode('hex') |
>>> plaintext = '6bc1bee22e409f96e93d7e117393172a'.decode('hex') |
>>> cipher = AES.new(key,AES.MODE_CMAC) |
>>> cipher.encrypt(plaintext).encode('hex') |
'070a16b46b4d4144f79bdd9dd04a287c' |
CMAC EXAMPLE2: |
-------------- |
>>> key = '2b7e151628aed2a6abf7158809cf4f3c'.decode('hex') |
>>> plaintext = '6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411'.decode('hex') |
>>> cipher = AES.new(key,AES.MODE_CMAC) |
>>> cipher.encrypt(plaintext).encode('hex') |
'dfa66747de9ae63030ca32611497c827' |
""" |
return AES(key,mode,IV,counter,segment_size) |
class AES(BlockCipher): |
"""AES using pycrypto for algo and pycryptoplus for ciphermode |
""" |
def __init__(self,key,mode,IV,counter,segment_size): |
cipher_module = Crypto.Cipher.AES.new |
self.blocksize = 16 |
BlockCipher.__init__(self,key,mode,IV,counter,cipher_module,segment_size) |
def _test(): |
import doctest |
doctest.testmod() |
if __name__ == "__main__": |
_test() |
/relevation/branches/1.1/python-cryptoplus/src/CryptoPlus/Cipher/python_AES.py |
---|
0,0 → 1,299 |
from blockcipher import * |
from rijndael import rijndael |
def new(key,mode=MODE_ECB,IV=None,counter=None,segment_size=None): |
"""Create a new cipher object |
Wrapper for pure python implementation rijndael.py |
key = raw string containing the key, AES-128..256 will be selected according to the key length |
-> when using XTS mode: the key should be a tuple containing the 2 keys needed |
mode = python_AES.MODE_ECB/CBC/CFB/OFB/CTR/XTS/CMAC, default is ECB |
-> for every mode, except ECB and CTR, it is important to construct a seperate cipher for encryption and decryption |
IV = IV as a raw string, default is "all zero" IV |
-> needed for CBC, CFB and OFB mode |
counter = counter object (CryptoPlus.Util.util.Counter) |
-> only needed for CTR mode |
-> use a seperate counter object for the cipher and decipher: the counter is updated directly, not a copy |
see CTR example further on in the docstring |
segment_size = amount of bits to use from the keystream in each chain part |
-> supported values: multiple of 8 between 8 and the blocksize |
of the cipher (only per byte access possible), default is 8 |
-> only needed for CFB mode |
Notes: |
- Always construct a seperate cipher object for encryption and decryption. Once a cipher object has been used for encryption, |
it can't be used for decryption because it keeps a state (if necessary) for the IV. |
EXAMPLES: |
********** |
IMPORTING: |
----------- |
>>> from CryptoPlus.Cipher import python_AES |
ECB EXAMPLE: |
------------- |
NIST Special Publication 800-38A http://cryptome.org/bcm/sp800-38a.htm#F |
>>> cipher = python_AES.new('2b7e151628aed2a6abf7158809cf4f3c'.decode('hex')) |
>>> crypted = cipher.encrypt('6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51'.decode('hex')) |
>>> crypted.encode('hex') |
'3ad77bb40d7a3660a89ecaf32466ef97f5d3d58503b9699de785895a96fdbaaf' |
>>> decipher = python_AES.new('2b7e151628aed2a6abf7158809cf4f3c'.decode('hex')) |
>>> decipher.decrypt(crypted).encode('hex') |
'6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51' |
PADDING EXAMPLE: |
----------------- |
>>> cipher = python_AES.new('0123456789012345') |
>>> crypt = cipher.encrypt('0123456789012') |
>>> crypt += cipher.final() |
>>> decipher = python_AES.new('0123456789012345') |
>>> decipher.decrypt(crypt) |
'0123456789012\\x03\\x03\\x03' |
CBC EXAMPLE (plaintext = 3 blocksizes): |
----------------------------------------- |
NIST Special Publication 800-38A http://cryptome.org/bcm/sp800-38a.htm#F |
>>> key = ('2b7e151628aed2a6abf7158809cf4f3c').decode('hex') |
>>> IV = ('000102030405060708090a0b0c0d0e0f').decode('hex') |
>>> plaintext1 = ('6bc1bee22e409f96e93d7e117393172a').decode('hex') |
>>> plaintext2 = ('ae2d8a571e03ac9c9eb76fac45af8e51').decode('hex') |
>>> plaintext3 = ('30c81c46a35ce411e5fbc1191a0a52ef').decode('hex') |
>>> cipher = python_AES.new(key,python_AES.MODE_CBC,IV) |
>>> ciphertext = cipher.encrypt(plaintext1 + plaintext2 + plaintext3) |
>>> (ciphertext).encode('hex') |
'7649abac8119b246cee98e9b12e9197d5086cb9b507219ee95db113a917678b273bed6b8e3c1743b7116e69e22229516' |
>>> decipher = python_AES.new(key,python_AES.MODE_CBC,IV) |
>>> plaintext = decipher.decrypt(ciphertext) |
>>> (plaintext).encode('hex') |
'6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52ef' |
OR: supply plaintext as seperate pieces: |
------------------------------------------ |
>>> cipher = python_AES.new(key,python_AES.MODE_CBC,IV) |
>>> ( cipher.encrypt(plaintext1 + plaintext2[:-2]) ).encode('hex') |
'7649abac8119b246cee98e9b12e9197d' |
>>> ( cipher.encrypt(plaintext2[-2:] + plaintext3) ).encode('hex') |
'5086cb9b507219ee95db113a917678b273bed6b8e3c1743b7116e69e22229516' |
>>> decipher = python_AES.new(key,python_AES.MODE_CBC,IV) |
>>> (decipher.decrypt(ciphertext[:22])).encode('hex') |
'6bc1bee22e409f96e93d7e117393172a' |
>>> (decipher.decrypt(ciphertext[22:])).encode('hex') |
'ae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52ef' |
CFB EXAMPLE: (CFB8-AES192) |
------------ |
NIST Special Publication 800-38A http://cryptome.org/bcm/sp800-38a.htm#F |
>>> key = '2b7e151628aed2a6abf7158809cf4f3c'.decode('hex') |
>>> IV = '000102030405060708090a0b0c0d0e0f'.decode('hex') |
>>> plain = '6bc1bee22e409f96e93d7e117393172a'.decode('hex') |
>>> cipher = python_AES.new(key,python_AES.MODE_CFB,IV=IV,segment_size=8) |
>>> ciphertext = cipher.encrypt(plain) |
>>> ciphertext.encode('hex') |
'3b79424c9c0dd436bace9e0ed4586a4f' |
>>> decipher = python_AES.new(key,python_AES.MODE_CFB,IV) |
>>> decipher.decrypt(ciphertext).encode('hex') |
'6bc1bee22e409f96e93d7e117393172a' |
CFB EXAMPLE: (CFB128-AES192) |
------------ |
NIST Special Publication 800-38A http://cryptome.org/bcm/sp800-38a.htm#F |
>>> key = '8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b'.decode('hex') |
>>> IV = '000102030405060708090a0b0c0d0e0f'.decode('hex') |
>>> plain = '6bc1bee22e409f96e93d7e117393172a'.decode('hex') |
>>> cipher = python_AES.new(key,python_AES.MODE_CFB,IV=IV,segment_size=128) |
>>> output1 = cipher.encrypt(plain) |
>>> output1.encode('hex') |
'cdc80d6fddf18cab34c25909c99a4174' |
>>> plain = 'ae2d8a571e03ac9c9eb76fac45af8e51'.decode('hex') |
>>> output2 = cipher.encrypt(plain) |
>>> output2.encode('hex') |
'67ce7f7f81173621961a2b70171d3d7a' |
>>> decipher = python_AES.new(key,python_AES.MODE_CFB,IV=IV,segment_size=128) |
>>> decipher.decrypt(output1+output2).encode('hex') |
'6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51' |
CFB EXAMPLE: same as previous but now as a streamcipher |
------------ |
>>> key = '8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b'.decode('hex') |
>>> IV = '000102030405060708090a0b0c0d0e0f'.decode('hex') |
>>> plain = '6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51'.decode('hex') |
>>> cipher = python_AES.new(key,python_AES.MODE_CFB,IV=IV,segment_size=128) |
>>> output = '' |
>>> for i in plain: output += cipher.encrypt(i) |
>>> output.encode('hex') |
'cdc80d6fddf18cab34c25909c99a417467ce7f7f81173621961a2b70171d3d7a' |
OFB EXAMPLE: (OFB128-AES192) |
------------ |
NIST Special Publication 800-38A http://cryptome.org/bcm/sp800-38a.htm#F |
>>> key = '8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b'.decode('hex') |
>>> IV = '000102030405060708090a0b0c0d0e0f'.decode('hex') |
>>> plain = '6bc1bee22e409f96e93d7e117393172a'.decode('hex') |
>>> cipher = python_AES.new(key,python_AES.MODE_OFB,IV) |
>>> output1 = cipher.encrypt(plain) |
>>> output1.encode('hex') |
'cdc80d6fddf18cab34c25909c99a4174' |
>>> plain = 'ae2d8a571e03ac9c9eb76fac45af8e51'.decode('hex') |
>>> output2 = cipher.encrypt(plain) |
>>> output2.encode('hex') |
'fcc28b8d4c63837c09e81700c1100401' |
>>> decipher = python_AES.new(key,python_AES.MODE_OFB,IV) |
>>> decipher.decrypt(output1 + output2).encode('hex') |
'6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51' |
OFB EXAMPLE: same as previous but now as a streamcipher |
------------ |
>>> key = '8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b'.decode('hex') |
>>> IV = '000102030405060708090a0b0c0d0e0f'.decode('hex') |
>>> plain = '6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51'.decode('hex') |
>>> cipher = python_AES.new(key,python_AES.MODE_OFB,IV) |
>>> output = '' |
>>> for i in plain: output += cipher.encrypt(i) |
>>> output.encode('hex') |
'cdc80d6fddf18cab34c25909c99a4174fcc28b8d4c63837c09e81700c1100401' |
CTR EXAMPLE: |
------------ |
NIST Special Publication 800-38A http://cryptome.org/bcm/sp800-38a.htm#F |
>>> from CryptoPlus.Util.util import Counter |
>>> key = '2b7e151628aed2a6abf7158809cf4f3c'.decode('hex') |
>>> counter = Counter('f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff'.decode('hex')) |
>>> cipher = python_AES.new(key,python_AES.MODE_CTR,counter=counter) |
>>> plaintext1 = '6bc1bee22e409f96e93d7e117393172a'.decode('hex') |
>>> plaintext2 = 'ae2d8a571e03ac9c9eb76fac45af8e51'.decode('hex') |
>>> plaintext3 = '30c81c46a35ce411e5fbc1191a0a52ef'.decode('hex') |
>>> ciphertext = cipher.encrypt(plaintext1 + plaintext2 + plaintext3) |
>>> ciphertext.encode('hex') |
'874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff5ae4df3edbd5d35e5b4f09020db03eab' |
>>> counter2 = Counter('f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff'.decode('hex')) |
>>> decipher = python_AES.new(key,python_AES.MODE_CTR,counter=counter2) |
>>> decipher.decrypt(ciphertext).encode('hex') |
'6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52ef' |
XTS EXAMPLE: |
------------ |
XTS-AES-128 applied for a data unit of 512 bytes |
IEEE P1619/D16: http://grouper.ieee.org/groups/1619/email/pdf00086.pdf |
>>> key = ('27182818284590452353602874713526'.decode('hex'),'31415926535897932384626433832795'.decode('hex')) |
>>> plaintext = '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff'.decode('hex') |
>>> cipher = python_AES.new(key,python_AES.MODE_XTS) |
>>> ciphertext = cipher.encrypt(plaintext) |
>>> ciphertext.encode('hex') |
'27a7479befa1d476489f308cd4cfa6e2a96e4bbe3208ff25287dd3819616e89cc78cf7f5e543445f8333d8fa7f56000005279fa5d8b5e4ad40e736ddb4d35412328063fd2aab53e5ea1e0a9f332500a5df9487d07a5c92cc512c8866c7e860ce93fdf166a24912b422976146ae20ce846bb7dc9ba94a767aaef20c0d61ad02655ea92dc4c4e41a8952c651d33174be51a10c421110e6d81588ede82103a252d8a750e8768defffed9122810aaeb99f9172af82b604dc4b8e51bcb08235a6f4341332e4ca60482a4ba1a03b3e65008fc5da76b70bf1690db4eae29c5f1badd03c5ccf2a55d705ddcd86d449511ceb7ec30bf12b1fa35b913f9f747a8afd1b130e94bff94effd01a91735ca1726acd0b197c4e5b03393697e126826fb6bbde8ecc1e08298516e2c9ed03ff3c1b7860f6de76d4cecd94c8119855ef5297ca67e9f3e7ff72b1e99785ca0a7e7720c5b36dc6d72cac9574c8cbbc2f801e23e56fd344b07f22154beba0f08ce8891e643ed995c94d9a69c9f1b5f499027a78572aeebd74d20cc39881c213ee770b1010e4bea718846977ae119f7a023ab58cca0ad752afe656bb3c17256a9f6e9bf19fdd5a38fc82bbe872c5539edb609ef4f79c203ebb140f2e583cb2ad15b4aa5b655016a8449277dbd477ef2c8d6c017db738b18deb4a427d1923ce3ff262735779a418f20a282df920147beabe421ee5319d0568' |
>>> decipher = python_AES.new(key,python_AES.MODE_XTS) |
>>> decipher.decrypt(ciphertext).encode('hex') |
'000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff' |
using data sequence number n |
>>> key = ('fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0'.decode('hex'),'22222222222222222222222222222222'.decode('hex')) |
>>> plain ='4444444444444444444444444444444444444444444444444444444444444444'.decode('hex') |
>>> n = '3333333333'.decode('hex') |
>>> cipher = python_AES.new(key,python_AES.MODE_XTS) |
>>> ciphertext = cipher.encrypt(plain,n) |
>>> ciphertext.encode('hex') |
'af85336b597afc1a900b2eb21ec949d292df4c047e0b21532186a5971a227a89' |
>>> decipher = python_AES.new(key,python_AES.MODE_XTS) |
>>> decipher.decrypt(ciphertext,n).encode('hex') |
'4444444444444444444444444444444444444444444444444444444444444444' |
>>> key = ('27182818284590452353602874713526'.decode('hex'),'31415926535897932384626433832795'.decode('hex')) |
>>> plain ='72efc1ebfe1ee25975a6eb3aa8589dda2b261f1c85bdab442a9e5b2dd1d7c3957a16fc08e526d4b1223f1b1232a11af274c3d70dac57f83e0983c498f1a6f1aecb021c3e70085a1e527f1ce41ee5911a82020161529cd82773762daf5459de94a0a82adae7e1703c808543c29ed6fb32d9e004327c1355180c995a07741493a09c21ba01a387882da4f62534b87bb15d60d197201c0fd3bf30c1500a3ecfecdd66d8721f90bcc4c17ee925c61b0a03727a9c0d5f5ca462fbfa0af1c2513a9d9d4b5345bd27a5f6e653f751693e6b6a2b8ead57d511e00e58c45b7b8d005af79288f5c7c22fd4f1bf7a898b03a5634c6a1ae3f9fae5de4f296a2896b23e7ed43ed14fa5a2803f4d28f0d3ffcf24757677aebdb47bb388378708948a8d4126ed1839e0da29a537a8c198b3c66ab00712dd261674bf45a73d67f76914f830ca014b65596f27e4cf62de66125a5566df9975155628b400fbfb3a29040ed50faffdbb18aece7c5c44693260aab386c0a37b11b114f1c415aebb653be468179428d43a4d8bc3ec38813eca30a13cf1bb18d524f1992d44d8b1a42ea30b22e6c95b199d8d182f8840b09d059585c31ad691fa0619ff038aca2c39a943421157361717c49d322028a74648113bd8c9d7ec77cf3c89c1ec8718ceff8516d96b34c3c614f10699c9abc4ed0411506223bea16af35c883accdbe1104eef0cfdb54e12fb230a'.decode('hex') |
>>> n = 'ff'.decode('hex') |
>>> cipher = python_AES.new(key,python_AES.MODE_XTS) |
>>> cipher.encrypt(plain,n).encode('hex') |
'3260ae8dad1f4a32c5cafe3ab0eb95549d461a67ceb9e5aa2d3afb62dece0553193ba50c75be251e08d1d08f1088576c7efdfaaf3f459559571e12511753b07af073f35da06af0ce0bbf6b8f5ccc5cea500ec1b211bd51f63b606bf6528796ca12173ba39b8935ee44ccce646f90a45bf9ccc567f0ace13dc2d53ebeedc81f58b2e41179dddf0d5a5c42f5d8506c1a5d2f8f59f3ea873cbcd0eec19acbf325423bd3dcb8c2b1bf1d1eaed0eba7f0698e4314fbeb2f1566d1b9253008cbccf45a2b0d9c5c9c21474f4076e02be26050b99dee4fd68a4cf890e496e4fcae7b70f94ea5a9062da0daeba1993d2ccd1dd3c244b8428801495a58b216547e7e847c46d1d756377b6242d2e5fb83bf752b54e0df71e889f3a2bb0f4c10805bf3c590376e3c24e22ff57f7fa965577375325cea5d920db94b9c336b455f6e894c01866fe9fbb8c8d3f70a2957285f6dfb5dcd8cbf54782f8fe7766d4723819913ac773421e3a31095866bad22c86a6036b2518b2059b4229d18c8c2ccbdf906c6cc6e82464ee57bddb0bebcb1dc645325bfb3e665ef7251082c88ebb1cf203bd779fdd38675713c8daadd17e1cabee432b09787b6ddf3304e38b731b45df5df51b78fcfb3d32466028d0ba36555e7e11ab0ee0666061d1645d962444bc47a38188930a84b4d561395c73c087021927ca638b7afc8a8679ccb84c26555440ec7f10445cd' |
>>> key = ('2718281828459045235360287471352662497757247093699959574966967627'.decode('hex'),'3141592653589793238462643383279502884197169399375105820974944592'.decode('hex')) |
>>> plain ='000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff'.decode('hex') |
>>> n = 'ffffffffff'.decode('hex') |
>>> cipher = python_AES.new(key,python_AES.MODE_XTS) |
>>> ciphertext = cipher.encrypt(plain,n) |
>>> ciphertext.encode('hex') |
'64497e5a831e4a932c09be3e5393376daa599548b816031d224bbf50a818ed2350eae7e96087c8a0db51ad290bd00c1ac1620857635bf246c176ab463be30b808da548081ac847b158e1264be25bb0910bbc92647108089415d45fab1b3d2604e8a8eff1ae4020cfa39936b66827b23f371b92200be90251e6d73c5f86de5fd4a950781933d79a28272b782a2ec313efdfcc0628f43d744c2dc2ff3dcb66999b50c7ca895b0c64791eeaa5f29499fb1c026f84ce5b5c72ba1083cddb5ce45434631665c333b60b11593fb253c5179a2c8db813782a004856a1653011e93fb6d876c18366dd8683f53412c0c180f9c848592d593f8609ca736317d356e13e2bff3a9f59cd9aeb19cd482593d8c46128bb32423b37a9adfb482b99453fbe25a41bf6feb4aa0bef5ed24bf73c762978025482c13115e4015aac992e5613a3b5c2f685b84795cb6e9b2656d8c88157e52c42f978d8634c43d06fea928f2822e465aa6576e9bf419384506cc3ce3c54ac1a6f67dc66f3b30191e698380bc999b05abce19dc0c6dcc2dd001ec535ba18deb2df1a101023108318c75dc98611a09dc48a0acdec676fabdf222f07e026f059b672b56e5cbc8e1d21bbd867dd927212054681d70ea737134cdfce93b6f82ae22423274e58a0821cc5502e2d0ab4585e94de6975be5e0b4efce51cd3e70c25a1fbbbd609d273ad5b0d59631c531f6a0a57b9' |
>>> decipher = python_AES.new(key,python_AES.MODE_XTS) |
>>> decipher.decrypt(ciphertext,n).encode('hex') |
'000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff' |
using plaintext not a multiple of 16 |
>>> key = ('fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0'.decode('hex'),'bfbebdbcbbbab9b8b7b6b5b4b3b2b1b0'.decode('hex')) |
>>> plaintext = '000102030405060708090a0b0c0d0e0f10111213'.decode('hex') |
>>> n = '9a78563412'.decode('hex') |
>>> cipher = python_AES.new(key,python_AES.MODE_XTS) |
>>> ciphertext = cipher.encrypt(plaintext,n) |
>>> ciphertext.encode('hex') |
'9d84c813f719aa2c7be3f66171c7c5c2edbf9dac' |
>>> decipher = python_AES.new(key,python_AES.MODE_XTS) |
>>> decipher.decrypt(ciphertext,n).encode('hex') |
'000102030405060708090a0b0c0d0e0f10111213' |
>>> key = ('fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0'.decode('hex'),'bfbebdbcbbbab9b8b7b6b5b4b3b2b1b0'.decode('hex')) |
>>> plaintext = '000102030405060708090a0b0c0d0e0f10'.decode('hex') |
>>> n = '9a78563412'.decode('hex') |
>>> cipher = python_AES.new(key,python_AES.MODE_XTS) |
>>> ciphertext = cipher.encrypt(plaintext,n) |
>>> ciphertext.encode('hex') |
'6c1625db4671522d3d7599601de7ca09ed' |
>>> decipher = python_AES.new(key,python_AES.MODE_XTS) |
>>> decipher.decrypt(ciphertext,n).encode('hex') |
'000102030405060708090a0b0c0d0e0f10' |
>>> key = ('e0e1e2e3e4e5e6e7e8e9eaebecedeeef'.decode('hex'),'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf'.decode('hex')) |
>>> plaintext = '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff'.decode('hex') |
>>> n = '21436587a9'.decode('hex') |
>>> cipher = python_AES.new(key,python_AES.MODE_XTS) |
>>> ciphertext = cipher.encrypt(plaintext,n) |
>>> ciphertext.encode('hex') |
'38b45812ef43a05bd957e545907e223b954ab4aaf088303ad910eadf14b42be68b2461149d8c8ba85f992be970bc621f1b06573f63e867bf5875acafa04e42ccbd7bd3c2a0fb1fff791ec5ec36c66ae4ac1e806d81fbf709dbe29e471fad38549c8e66f5345d7c1eb94f405d1ec785cc6f6a68f6254dd8339f9d84057e01a17741990482999516b5611a38f41bb6478e6f173f320805dd71b1932fc333cb9ee39936beea9ad96fa10fb4112b901734ddad40bc1878995f8e11aee7d141a2f5d48b7a4e1e7f0b2c04830e69a4fd1378411c2f287edf48c6c4e5c247a19680f7fe41cefbd49b582106e3616cbbe4dfb2344b2ae9519391f3e0fb4922254b1d6d2d19c6d4d537b3a26f3bcc51588b32f3eca0829b6a5ac72578fb814fb43cf80d64a233e3f997a3f02683342f2b33d25b492536b93becb2f5e1a8b82f5b883342729e8ae09d16938841a21a97fb543eea3bbff59f13c1a18449e398701c1ad51648346cbc04c27bb2da3b93a1372ccae548fb53bee476f9e9c91773b1bb19828394d55d3e1a20ed69113a860b6829ffa847224604435070221b257e8dff783615d2cae4803a93aa4334ab482a0afac9c0aeda70b45a481df5dec5df8cc0f423c77a5fd46cd312021d4b438862419a791be03bb4d97c0e59578542531ba466a83baf92cefc151b5cc1611a167893819b63fb8a6b18e86de60290fa72b797b0ce59f3' |
>>> decipher = python_AES.new(key,python_AES.MODE_XTS) |
>>> decipher.decrypt(ciphertext,n).encode('hex') |
'000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff' |
CMAC EXAMPLE: |
------------- |
NIST publication 800-38B: http://csrc.nist.gov/publications/nistpubs/800-38B/Updated_CMAC_Examples.pdf |
>>> key = '2b7e151628aed2a6abf7158809cf4f3c'.decode('hex') |
>>> plaintext = '6bc1bee22e409f96e93d7e117393172a'.decode('hex') |
>>> cipher = python_AES.new(key,python_AES.MODE_CMAC) |
>>> cipher.encrypt(plaintext).encode('hex')[:16] |
'070a16b46b4d4144' |
CMAC EXAMPLE2: |
-------------- |
>>> key = '2b7e151628aed2a6abf7158809cf4f3c'.decode('hex') |
>>> plaintext = '6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411'.decode('hex') |
>>> cipher = python_AES.new(key,python_AES.MODE_CMAC) |
>>> cipher.encrypt(plaintext).encode('hex')[:16] |
'dfa66747de9ae630' |
""" |
return python_AES(key,mode,IV,counter,segment_size) |
class python_AES(BlockCipher): |
key_error_message = ("Key should be 128, 192 or 256 bits") |
def __init__(self,key,mode,IV,counter,segment_size): |
cipher_module = rijndael |
args = {'block_size':16} |
self.blocksize = 16 |
BlockCipher.__init__(self,key,mode,IV,counter,cipher_module,segment_size,args) |
def keylen_valid(self,key): |
return len(key) in (16,24,32) |
def _test(): |
import doctest |
doctest.testmod() |
if __name__ == "__main__": |
_test() |
/relevation/branches/1.1/python-cryptoplus/src/CryptoPlus/Cipher/DES.py |
---|
0,0 → 1,51 |
from blockcipher import * |
import Crypto.Cipher.DES |
def new(key,mode=MODE_ECB,IV=None,counter=None,segment_size=None): |
"""Create a new cipher object |
DES using pycrypto for algo and pycryptoplus for ciphermode |
key = raw string containing the keys |
mode = python_AES.MODE_ECB/CBC/CFB/OFB/CTR/CMAC, default is ECB |
IV = IV as a raw string, default is "all zero" IV |
-> only needed for CBC mode |
counter = counter object (CryptoPlus.Util.util.Counter) |
-> only needed for CTR mode |
segment_size = amount of bits to use from the keystream in each chain part |
-> supported values: multiple of 8 between 8 and the blocksize |
of the cipher (only per byte access possible), default is 8 |
-> only needed for CFB mode |
EXAMPLES: |
********** |
IMPORTING: |
----------- |
>>> from CryptoPlus.Cipher import DES |
EXAMPLE (test vectors from NESSIE): |
----------------------------------- |
>>> cipher = DES.new(('7CA110454A1A6E57').decode('hex')) |
>>> ciphertext = cipher.encrypt(('01A1D6D039776742').decode('hex')) |
>>> (ciphertext).encode('hex') |
'690f5b0d9a26939b' |
>>> plaintext = cipher.decrypt(ciphertext) |
>>> (plaintext).encode('hex') |
'01a1d6d039776742' |
""" |
return DES(key,mode,IV,counter,segment_size) |
class DES(BlockCipher): |
def __init__(self,key,mode,IV,counter,segment_size): |
cipher_module = Crypto.Cipher.DES.new |
self.blocksize = 8 |
BlockCipher.__init__(self,key,mode,IV,counter,cipher_module,segment_size) |
def _test(): |
import doctest |
doctest.testmod() |
if __name__ == "__main__": |
_test() |
/relevation/branches/1.1/python-cryptoplus/src/CryptoPlus/Cipher/python_DES.py |
---|
0,0 → 1,57 |
from blockcipher import * |
import pyDes |
def new(key,mode=MODE_ECB,IV=None,counter=None,segment_size=None): |
"""Create a new cipher object |
wrapper for pure python implementation pyDes.py |
key = raw string containing the key |
mode = python_DES.MODE_ECB/CBC/CFB/OFB/CTR/CMAC, default is ECB |
-> for every mode, except ECB and CTR, it is important to construct a seperate cipher for encryption and decryption |
IV = IV as a raw string, default is "all zero" IV |
-> needed for CBC, CFB and OFB mode |
counter = counter object (CryptoPlus.Util.util.Counter) |
-> only needed for CTR mode |
-> use a seperate counter object for the cipher and decipher: the counter is updated directly, not a copy |
see CTR example further on in the docstring |
segment_size = amount of bits to use from the keystream in each chain part |
-> supported values: multiple of 8 between 8 and the blocksize |
of the cipher (only per byte access possible), default is 8 |
-> only needed for CFB mode |
EXAMPLES: |
********** |
IMPORTING: |
----------- |
>>> from CryptoPlus.Cipher import python_DES |
EXAMPLE (test vectors from NESSIE): |
----------------------------------- |
>>> cipher = python_DES.new(('7CA110454A1A6E57').decode('hex')) |
>>> ciphertext = cipher.encrypt(('01A1D6D039776742').decode('hex')) |
>>> (ciphertext).encode('hex') |
'690f5b0d9a26939b' |
>>> plaintext = cipher.decrypt(ciphertext) |
>>> (plaintext).encode('hex') |
'01a1d6d039776742' |
""" |
return python_DES(key,mode,IV,counter,segment_size) |
class python_DES(BlockCipher): |
key_error_message = ("Key should be 64 bits") |
def __init__(self,key,mode,IV,counter,segment_size): |
cipher_module = pyDes.des |
self.blocksize = 8 |
BlockCipher.__init__(self,key,mode,IV,counter,cipher_module,segment_size) |
def keylen_valid(self,key): |
return len(key) == 8 |
def _test(): |
import doctest |
doctest.testmod() |
if __name__ == "__main__": |
_test() |
/relevation/branches/1.1/python-cryptoplus/src/CryptoPlus/Cipher/Blowfish.py |
---|
0,0 → 1,77 |
from blockcipher import * |
import Crypto.Cipher.Blowfish |
def new(key,mode=MODE_ECB,IV=None,counter=None,segment_size=None): |
"""Create a new cipher object |
Blowfish using pycrypto for algo and pycryptoplus for ciphermode |
key = raw string containing the key |
mode = Blowfish.MODE_ECB/CBC/CFB/OFB/CTR/CMAC, default is ECB |
IV = IV as a raw string, default is "all zero" IV |
-> only needed for CBC mode |
counter = counter object (CryptoPlus.Util.util.Counter) |
-> only needed for CTR mode |
segment_size = amount of bits to use from the keystream in each chain part |
-> supported values: multiple of 8 between 8 and the blocksize |
of the cipher (only per byte access possible), default is 8 |
-> only needed for CFB mode |
EXAMPLES: |
********** |
IMPORTING: |
----------- |
>>> from CryptoPlus.Cipher import Blowfish |
ECB EXAMPLE: http://www.schneier.com/code/vectors.txt |
------------- |
>>> cipher = Blowfish.new(('0131D9619DC1376E').decode('hex')) |
>>> ( cipher.encrypt(('5CD54CA83DEF57DA').decode('hex')) ).encode('hex') |
'b1b8cc0b250f09a0' |
>>> ( cipher.decrypt((_).decode('hex')) ).encode('hex') |
'5cd54ca83def57da' |
CBC, CFB, OFB EXAMPLE: http://www.schneier.com/code/vectors.txt |
---------------------- |
>>> key = ('0123456789ABCDEFF0E1D2C3B4A59687').decode('hex') |
>>> IV = ('FEDCBA9876543210').decode('hex') |
>>> plaintext = ('37363534333231204E6F77206973207468652074696D6520').decode('hex') |
>>> cipher = Blowfish.new(key,Blowfish.MODE_CBC,IV) |
>>> ciphertext = cipher.encrypt(plaintext) |
>>> (ciphertext).encode('hex').upper() |
'6B77B4D63006DEE605B156E27403979358DEB9E7154616D9' |
>>> key = '0123456789ABCDEFF0E1D2C3B4A59687'.decode('hex') |
>>> iv = 'FEDCBA9876543210'.decode('hex') |
>>> plaintext = '37363534333231204E6F77206973207468652074696D6520666F722000'.decode('hex') |
>>> cipher = Blowfish.new(key,Blowfish.MODE_CBC,iv) |
>>> ciphertext = cipher.encrypt(plaintext) |
>>> (ciphertext).encode('hex').upper() |
'6B77B4D63006DEE605B156E27403979358DEB9E7154616D9' |
>>> cipher = Blowfish.new(key,Blowfish.MODE_CFB,iv,segment_size=64) |
>>> ciphertext = cipher.encrypt(plaintext) |
>>> (ciphertext).encode('hex').upper() |
'E73214A2822139CAF26ECF6D2EB9E76E3DA3DE04D1517200519D57A6C3' |
>>> cipher = Blowfish.new(key,Blowfish.MODE_OFB,iv) |
>>> ciphertext = cipher.encrypt(plaintext) |
>>> (ciphertext).encode('hex').upper() |
'E73214A2822139CA62B343CC5B65587310DD908D0C241B2263C2CF80DA' |
""" |
return Blowfish(key,mode,IV,counter,segment_size) |
class Blowfish(BlockCipher): |
def __init__(self,key,mode,IV,counter,segment_size): |
cipher_module = Crypto.Cipher.Blowfish.new |
self.blocksize = 8 |
BlockCipher.__init__(self,key,mode,IV,counter,cipher_module,segment_size) |
def _test(): |
import doctest |
doctest.testmod() |
if __name__ == "__main__": |
_test() |
/relevation/branches/1.1/python-cryptoplus/src/CryptoPlus/Cipher/python_Blowfish.py |
---|
0,0 → 1,82 |
from blockcipher import * |
from pyblowfish import Blowfish |
def new(key,mode=MODE_ECB,IV=None,counter=None,segment_size=None): |
"""Create a new cipher object |
Wrapper for pure python implementation pyblowfish.py |
key = raw string containing the key |
mode = Blowfish.MODE_ECB/CBC/CFB/OFB/CTR/CMAC, default is ECB |
IV = IV as a raw string, default is "all zero" IV |
-> only needed for CBC mode |
counter = counter object (CryptoPlus.Util.util.Counter) |
-> only needed for CTR mode |
segment_size = amount of bits to use from the keystream in each chain part |
-> supported values: multiple of 8 between 8 and the blocksize |
of the cipher (only per byte access possible), default is 8 |
-> only needed for CFB mode |
EXAMPLES: |
********** |
IMPORTING: |
----------- |
>>> from CryptoPlus.Cipher import python_Blowfish |
EXAMPLE: (http://www.schneier.com/code/vectors.txt) |
---------- |
>>> cipher = python_Blowfish.new(('0131D9619DC1376E').decode('hex')) |
>>> ( cipher.encrypt(('5CD54CA83DEF57DA').decode('hex')) ).encode('hex') |
'b1b8cc0b250f09a0' |
>>> ( cipher.decrypt((_).decode('hex')) ).encode('hex') |
'5cd54ca83def57da' |
CBC, CFB, OFB EXAMPLE: http://www.schneier.com/code/vectors.txt |
---------------------- |
>>> key = ('0123456789ABCDEFF0E1D2C3B4A59687').decode('hex') |
>>> IV = ('FEDCBA9876543210').decode('hex') |
>>> plaintext = ('37363534333231204E6F77206973207468652074696D6520').decode('hex') |
>>> cipher = python_Blowfish.new(key,python_Blowfish.MODE_CBC,IV) |
>>> ciphertext = cipher.encrypt(plaintext) |
>>> (ciphertext).encode('hex').upper() |
'6B77B4D63006DEE605B156E27403979358DEB9E7154616D9' |
>>> key = '0123456789ABCDEFF0E1D2C3B4A59687'.decode('hex') |
>>> iv = 'FEDCBA9876543210'.decode('hex') |
>>> plaintext = '37363534333231204E6F77206973207468652074696D6520666F722000'.decode('hex') |
>>> cipher = python_Blowfish.new(key,python_Blowfish.MODE_CBC,iv) |
>>> ciphertext = cipher.encrypt(plaintext) |
>>> (ciphertext).encode('hex').upper() |
'6B77B4D63006DEE605B156E27403979358DEB9E7154616D9' |
>>> cipher = python_Blowfish.new(key,python_Blowfish.MODE_CFB,iv,segment_size=64) |
>>> ciphertext = cipher.encrypt(plaintext) |
>>> (ciphertext).encode('hex').upper() |
'E73214A2822139CAF26ECF6D2EB9E76E3DA3DE04D1517200519D57A6C3' |
>>> cipher = python_Blowfish.new(key,python_Blowfish.MODE_OFB,iv) |
>>> ciphertext = cipher.encrypt(plaintext) |
>>> (ciphertext).encode('hex').upper() |
'E73214A2822139CA62B343CC5B65587310DD908D0C241B2263C2CF80DA'""" |
return python_Blowfish(key,mode,IV,counter,segment_size) |
class python_Blowfish(BlockCipher): |
key_error_message = "Key should be between 8 and 56 bytes (64 <-> 448 bits)" |
def __init__(self,key,mode,IV,counter,segment_size): |
cipher_module = Blowfish |
self.blocksize = 8 |
BlockCipher.__init__(self,key,mode,IV,counter,cipher_module,segment_size) |
def keylen_valid(self,key): |
return 8 <= len(key) <= 56 |
def _test(): |
import doctest |
doctest.testmod() |
if __name__ == "__main__": |
_test() |
/relevation/branches/1.1/python-cryptoplus/src/CryptoPlus/Cipher/python_Serpent.py |
---|
0,0 → 1,68 |
from blockcipher import * |
from pyserpent import Serpent |
def new(key,mode=MODE_ECB,IV=None,counter=None,segment_size=None): |
"""Create a new cipher object |
Wrapper for pure python implementation pyserpent.py |
key = raw string containing the key |
-> when using XTS mode: the key should be a tuple containing the 2 keys needed |
mode = python_Serpent.MODE_ECB/CBC/CFB/OFB/CTR/XTS/CMAC, default is ECB |
-> for every mode, except ECB and CTR, it is important to construct a seperate cipher for encryption and decryption |
IV = IV as a raw string, default is "all zero" IV |
-> needed for CBC, CFB and OFB mode |
counter = counter object (CryptoPlus.Util.util.Counter) |
-> only needed for CTR mode |
-> use a seperate counter object for the cipher and decipher: the counter is updated directly, not a copy |
see CTR example further on in the docstring |
EXAMPLES: |
********** |
IMPORTING: |
----------- |
>>> from CryptoPlus.Cipher import python_Serpent |
EXAMPLE: |
--------- |
NESSIE Test Vectors: http://www.cs.technion.ac.il/~biham/Reports/Serpent/Serpent-128-128.verified.test-vectors |
>>> cipher = python_Serpent.new(('000102030405060708090A0B0C0D0E0F').decode('hex')) |
>>> (cipher.encrypt(('33B3DC87EDDD9B0F6A1F407D14919365').decode('hex'))).encode('hex').upper() |
'00112233445566778899AABBCCDDEEFF' |
>>> ( cipher.decrypt((_).decode('hex')) ).encode('hex').upper() |
'33B3DC87EDDD9B0F6A1F407D14919365' |
>>> cipher = python_Serpent.new(('FDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFD').decode('hex')) |
>>> (cipher.encrypt(('FDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFD').decode('hex'))).encode('hex').upper() |
'81F9163BDF39B5BB2932AB91DF2A5FFC' |
>>> ( cipher.decrypt((_).decode('hex')) ).encode('hex').upper() |
'FDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFD' |
CBC EXAMPLE: |
------------- |
>>> key = ('000102030405060708090A0B0C0D0E0F').decode('hex') |
>>> IV = ('00000000000000000000000000000000').decode('hex') |
>>> plaintext = ('33B3DC87EDDD9B0F6A1F407D14919365'*3).decode('hex') |
>>> cipher = python_Serpent.new(key,python_Serpent.MODE_CBC,IV) |
>>> ciphertext = cipher.encrypt(plaintext) |
>>> decipher = python_Serpent.new(key,python_Serpent.MODE_CBC,IV) |
>>> ( decipher.decrypt(ciphertext)).encode('hex').upper() |
'33B3DC87EDDD9B0F6A1F407D1491936533B3DC87EDDD9B0F6A1F407D1491936533B3DC87EDDD9B0F6A1F407D14919365' |
""" |
return python_Serpent(key,mode,IV,counter,segment_size) |
class python_Serpent(BlockCipher): |
def __init__(self,key,mode,IV,counter,segment_size): |
if len(key) not in (16,24,32) and type(key) is not tuple: |
raise ValueError("Key should be 128, 192 or 256 bits") |
cipher_module = Serpent |
self.blocksize = 16 |
BlockCipher.__init__(self,key,mode,IV,counter,cipher_module,segment_size) |
def _test(): |
import doctest |
doctest.testmod() |
if __name__ == "__main__": |
_test() |
/relevation/branches/1.1/python-cryptoplus/src/CryptoPlus/Cipher/python_PRESENT.py |
---|
0,0 → 1,94 |
from blockcipher import * |
from pypresent import Present |
def new(key,mode=MODE_ECB,IV=None,counter=None,segment_size=None,rounds=32): |
"""Create a new cipher object |
Wrapper for pure python implementation rijndael.py |
key = raw string containing the key, AES-128..256 will be selected according to the key length |
mode = python_PRESENT.MODE_ECB/CBC/CFB/OFB/CTR/CMAC, default is ECB |
-> for every mode, except ECB and CTR, it is important to construct a seperate cipher for encryption and decryption |
IV = IV as a raw string, default is "all zero" IV |
-> needed for CBC, CFB and OFB mode |
counter = counter object (CryptoPlus.Util.util.Counter) |
-> only needed for CTR mode |
-> use a seperate counter object for the cipher and decipher: the counter is updated directly, not a copy |
see CTR example further on in the docstring |
rounds = amount of rounds |
segment_size = amount of bits to use from the keystream in each chain part |
-> supported values: multiple of 8 between 8 and the blocksize |
of the cipher (only per byte access possible), default is 8 |
-> only needed for CFB mode |
rounds = amount of rounds, default = 32 |
Notes: |
- Always construct a seperate cipher object for encryption and decryption. Once a cipher object has been used for encryption, |
it can't be used for decryption because it keeps a state (if necessary) for the IV. |
EXAMPLES: |
********** |
IMPORTING: |
----------- |
>>> from CryptoPlus.Cipher import python_PRESENT |
ECB Test Vectors: |
------------------ |
>>> key = "00000000000000000000".decode('hex') |
>>> plain = "0000000000000000".decode('hex') |
>>> cipher = python_PRESENT.new(key,python_PRESENT.MODE_ECB) |
>>> cipher.encrypt(plain).encode('hex') |
'5579c1387b228445' |
>>> key = "00000000000000000000000000000000".decode('hex') |
>>> plain = "0000000000000000".decode('hex') |
>>> cipher = python_PRESENT.new(key,python_PRESENT.MODE_ECB,rounds=64) |
>>> cipher.encrypt(plain).encode('hex') |
'59a27d01607ebf05' |
>>> key = "00000000000000000000".decode('hex') |
>>> plain = "0000000000000000".decode('hex') |
>>> cipher = python_PRESENT.new(key,python_PRESENT.MODE_ECB,rounds=64) |
>>> cipher.encrypt(plain).encode('hex') |
'13991dd588bc1288' |
Test Vectors for maximum rounds supported by PRESENT reference C code: |
----------------------------------------------------------------------- |
>>> key = "0123456789abcdef0123".decode('hex') |
>>> plain = "0123456789abcdef".decode('hex') |
>>> cipher = python_PRESENT.new(key,python_PRESENT.MODE_ECB,rounds=65534) |
>>> ciphertext = cipher.encrypt(plain) |
>>> ciphertext.encode('hex') |
'a140dc5d7175ca20' |
>>> cipher.decrypt(ciphertext).encode('hex') |
'0123456789abcdef' |
>>> key = "0123456789abcdef0123456789abcdef".decode('hex') |
>>> plain = "0123456789abcdef".decode('hex') |
>>> cipher = python_PRESENT.new(key,python_PRESENT.MODE_ECB,rounds=65534) |
>>> ciphertext = cipher.encrypt(plain) |
>>> ciphertext.encode('hex') |
'21007772e5d4ef14' |
>>> cipher.decrypt(ciphertext).encode('hex') |
'0123456789abcdef' |
""" |
return python_PRESENT(key,mode,IV,counter,rounds,segment_size) |
class python_PRESENT(BlockCipher): |
key_error_message = "Key should be 80 or 128 bits" |
def __init__(self,key,mode,IV,counter,rounds,segment_size): |
cipher_module = Present |
args = {'rounds':rounds} |
self.blocksize = 8 |
BlockCipher.__init__(self,key,mode,IV,counter,cipher_module,segment_size,args) |
def keylen_valid(self,key): |
return len(key) in (10,16) |
def _test(): |
import doctest |
doctest.testmod() |
if __name__ == "__main__": |
_test() |
/relevation/branches/1.1/python-cryptoplus/src/CryptoPlus/Cipher/python_Twofish.py |
---|
0,0 → 1,55 |
from blockcipher import * |
from pytwofish import Twofish |
def new(key,mode=MODE_ECB,IV=None,counter=None,segment_size=None): |
"""Create a new cipher object |
Wrapper for pure python implementation pytwofish.py |
key = raw string containing the key |
-> when using XTS mode: the key should be a tuple containing the 2 keys needed |
mode = python_Twofish.MODE_ECB/CBC/CFB/OFB/CTR/XTS/CMAC, default is ECB |
-> for every mode, except ECB and CTR, it is important to construct a seperate cipher for encryption and decryption |
IV = IV as a raw string, default is "all zero" IV |
-> needed for CBC, CFB and OFB mode |
counter = counter object (CryptoPlus.Util.util.Counter) |
-> only needed for CTR mode |
-> use a seperate counter object for the cipher and decipher: the counter is updated directly, not a copy |
see CTR example further on in the docstring |
segment_size = amount of bits to use from the keystream in each chain part |
-> supported values: multiple of 8 between 8 and the blocksize |
of the cipher (only per byte access possible), default is 8 |
-> only needed for CFB mode |
EXAMPLES: |
********** |
IMPORTING: |
----------- |
>>> from CryptoPlus.Cipher import python_Twofish |
EXAMPLE: |
---------- |
http://www.schneier.com/code/ecb_ival.txt -> test vector I=5 |
>>> cipher = python_Twofish.new(('019F9809DE1711858FAAC3A3BA20FBC3').decode('hex')) |
>>> (cipher.encrypt(('6363977DE839486297E661C6C9D668EB').decode('hex'))).encode('hex').upper() |
'816D5BD0FAE35342BF2A7412C246F752' |
>>> ( cipher.decrypt((_).decode('hex')) ).encode('hex').upper() |
'6363977DE839486297E661C6C9D668EB' |
""" |
return python_Twofish(key,mode,IV,counter,segment_size) |
class python_Twofish(BlockCipher): |
def __init__(self,key,mode,IV,counter,segment_size): |
if len(key) not in (16,24,32) and type(key) is not tuple: |
raise ValueError("Key should be 128, 192 or 256 bits") |
cipher_module = Twofish |
self.blocksize = 16 |
BlockCipher.__init__(self,key,mode,IV,counter,cipher_module,segment_size) |
def _test(): |
import doctest |
doctest.testmod() |
if __name__ == "__main__": |
_test() |
/relevation/branches/1.1/python-cryptoplus/src/CryptoPlus/Cipher/pyDes.py |
---|
0,0 → 1,803 |
############################################################################# |
# Documentation # |
############################################################################# |
# Author: Todd Whiteman |
# Date: 12th September, 2005 |
# Verion: 1.2 |
# Homepage: http://twhiteman.netfirms.com/des.html |
# |
# This algorithm is a pure python implementation of the DES algorithm. |
# It is in pure python to avoid portability issues, since most DES |
# implementations are programmed in C (for performance reasons). |
# |
# Triple DES class is also implemented, utilising the DES base. Triple DES |
# is either DES-EDE3 with a 24 byte key, or DES-EDE2 with a 16 byte key. |
# |
# See the README.txt that should come with this python module for the |
# implementation methods used. |
# |
# Thanks to David Broadwell for ideas, comments and suggestions. |
# Thanks to Mario Wolff for pointing out and debugging some triple des CBC errors. |
# |
"""A pure python implementation of the DES and TRIPLE DES encryption algorithms |
pyDes.des(key, [mode], [IV]) |
pyDes.triple_des(key, [mode], [IV]) |
key -> String containing the encryption key. 8 bytes for DES, 16 or 24 bytes |
for Triple DES |
mode -> Optional argument for encryption type, can be either |
pyDes.ECB (Electronic Code Book) or pyDes.CBC (Cypher Block Chaining) |
IV -> Optional argument, must be supplied if using CBC mode. Must be 8 bytes |
Example: |
from pyDes import * |
data = "Please encrypt my string" |
k = des("DESCRYPT", " ", CBC, "\0\0\0\0\0\0\0\0") |
d = k.encrypt(data) |
print "Encypted string: " + d |
print "Decypted string: " + k.decrypt(d) |
See the module source (pyDes.py) for more examples of use. |
You can slo run the pyDes.py file without and arguments to see a simple test. |
Note: This code was not written for high-end systems needing a fast |
implementation, but rather a handy portable solution with small usage. |
""" |
# Modes of crypting / cyphering |
ECB = 0 |
CBC = 1 |
############################################################################# |
# DES # |
############################################################################# |
class des: |
"""DES encryption/decrytpion class |
Supports ECB (Electronic Code Book) and CBC (Cypher Block Chaining) modes. |
pyDes.des(key,[mode], [IV]) |
key -> The encryption key string, must be exactly 8 bytes |
mode -> Optional argument for encryption type, can be either pyDes.ECB |
(Electronic Code Book), pyDes.CBC (Cypher Block Chaining) |
IV -> Optional string argument, must be supplied if using CBC mode. |
Must be 8 bytes in length. |
""" |
# Permutation and translation tables for DES |
__pc1 = [56, 48, 40, 32, 24, 16, 8, |
0, 57, 49, 41, 33, 25, 17, |
9, 1, 58, 50, 42, 34, 26, |
18, 10, 2, 59, 51, 43, 35, |
62, 54, 46, 38, 30, 22, 14, |
6, 61, 53, 45, 37, 29, 21, |
13, 5, 60, 52, 44, 36, 28, |
20, 12, 4, 27, 19, 11, 3 |
] |
# number left rotations of pc1 |
__left_rotations = [ |
1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 |
] |
# permuted choice key (table 2) |
__pc2 = [ |
13, 16, 10, 23, 0, 4, |
2, 27, 14, 5, 20, 9, |
22, 18, 11, 3, 25, 7, |
15, 6, 26, 19, 12, 1, |
40, 51, 30, 36, 46, 54, |
29, 39, 50, 44, 32, 47, |
43, 48, 38, 55, 33, 52, |
45, 41, 49, 35, 28, 31 |
] |
# initial permutation IP |
__ip = [57, 49, 41, 33, 25, 17, 9, 1, |
59, 51, 43, 35, 27, 19, 11, 3, |
61, 53, 45, 37, 29, 21, 13, 5, |
63, 55, 47, 39, 31, 23, 15, 7, |
56, 48, 40, 32, 24, 16, 8, 0, |
58, 50, 42, 34, 26, 18, 10, 2, |
60, 52, 44, 36, 28, 20, 12, 4, |
62, 54, 46, 38, 30, 22, 14, 6 |
] |
# Expansion table for turning 32 bit blocks into 48 bits |
__expansion_table = [ |
31, 0, 1, 2, 3, 4, |
3, 4, 5, 6, 7, 8, |
7, 8, 9, 10, 11, 12, |
11, 12, 13, 14, 15, 16, |
15, 16, 17, 18, 19, 20, |
19, 20, 21, 22, 23, 24, |
23, 24, 25, 26, 27, 28, |
27, 28, 29, 30, 31, 0 |
] |
# The (in)famous S-boxes |
__sbox = [ |
# S1 |
[14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, |
0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, |
4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, |
15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13], |
# S2 |
[15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, |
3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, |
0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, |
13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9], |
# S3 |
[10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, |
13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, |
13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, |
1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12], |
# S4 |
[7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, |
13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, |
10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, |
3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14], |
# S5 |
[2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, |
14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, |
4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, |
11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3], |
# S6 |
[12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, |
10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, |
9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, |
4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13], |
# S7 |
[4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, |
13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, |
1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, |
6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12], |
# S8 |
[13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, |
1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, |
7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, |
2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11], |
] |
# 32-bit permutation function P used on the output of the S-boxes |
__p = [ |
15, 6, 19, 20, 28, 11, |
27, 16, 0, 14, 22, 25, |
4, 17, 30, 9, 1, 7, |
23,13, 31, 26, 2, 8, |
18, 12, 29, 5, 21, 10, |
3, 24 |
] |
# final permutation IP^-1 |
__fp = [ |
39, 7, 47, 15, 55, 23, 63, 31, |
38, 6, 46, 14, 54, 22, 62, 30, |
37, 5, 45, 13, 53, 21, 61, 29, |
36, 4, 44, 12, 52, 20, 60, 28, |
35, 3, 43, 11, 51, 19, 59, 27, |
34, 2, 42, 10, 50, 18, 58, 26, |
33, 1, 41, 9, 49, 17, 57, 25, |
32, 0, 40, 8, 48, 16, 56, 24 |
] |
# Type of crypting being done |
ENCRYPT = 0x00 |
DECRYPT = 0x01 |
# Initialisation |
def __init__(self, key, mode=ECB, IV=None): |
if len(key) != 8: |
raise ValueError("Invalid DES key size. Key must be exactly 8 bytes long.") |
self.block_size = 8 |
self.key_size = 8 |
self.__padding = '' |
# Set the passed in variables |
self.setMode(mode) |
if IV: |
self.setIV(IV) |
self.L = [] |
self.R = [] |
self.Kn = [ [0] * 48 ] * 16 # 16 48-bit keys (K1 - K16) |
self.final = [] |
self.setKey(key) |
def getKey(self): |
"""getKey() -> string""" |
return self.__key |
def setKey(self, key): |
"""Will set the crypting key for this object. Must be 8 bytes.""" |
self.__key = key |
self.__create_sub_keys() |
def getMode(self): |
"""getMode() -> pyDes.ECB or pyDes.CBC""" |
return self.__mode |
def setMode(self, mode): |
"""Sets the type of crypting mode, pyDes.ECB or pyDes.CBC""" |
self.__mode = mode |
def getIV(self): |
"""getIV() -> string""" |
return self.__iv |
def setIV(self, IV): |
"""Will set the Initial Value, used in conjunction with CBC mode""" |
if not IV or len(IV) != self.block_size: |
raise ValueError("Invalid Initial Value (IV), must be a multiple of " + str(self.block_size) + " bytes") |
self.__iv = IV |
def getPadding(self): |
"""getPadding() -> string of length 1. Padding character.""" |
return self.__padding |
def __String_to_BitList(self, data): |
"""Turn the string data, into a list of bits (1, 0)'s""" |
l = len(data) * 8 |
result = [0] * l |
pos = 0 |
for c in data: |
i = 7 |
ch = ord(c) |
while i >= 0: |
if ch & (1 << i) != 0: |
result[pos] = 1 |
else: |
result[pos] = 0 |
pos += 1 |
i -= 1 |
return result |
def __BitList_to_String(self, data): |
"""Turn the list of bits -> data, into a string""" |
result = '' |
pos = 0 |
c = 0 |
while pos < len(data): |
c += data[pos] << (7 - (pos % 8)) |
if (pos % 8) == 7: |
result += chr(c) |
c = 0 |
pos += 1 |
return result |
def __permutate(self, table, block): |
"""Permutate this block with the specified table""" |
return map(lambda x: block[x], table) |
# Transform the secret key, so that it is ready for data processing |
# Create the 16 subkeys, K[1] - K[16] |
def __create_sub_keys(self): |
"""Create the 16 subkeys K[1] to K[16] from the given key""" |
key = self.__permutate(des.__pc1, self.__String_to_BitList(self.getKey())) |
i = 0 |
# Split into Left and Right sections |
self.L = key[:28] |
self.R = key[28:] |
while i < 16: |
j = 0 |
# Perform circular left shifts |
while j < des.__left_rotations[i]: |
self.L.append(self.L[0]) |
del self.L[0] |
self.R.append(self.R[0]) |
del self.R[0] |
j += 1 |
# Create one of the 16 subkeys through pc2 permutation |
self.Kn[i] = self.__permutate(des.__pc2, self.L + self.R) |
i += 1 |
# Main part of the encryption algorithm, the number cruncher :) |
def __des_crypt(self, block, crypt_type): |
"""Crypt the block of data through DES bit-manipulation""" |
block = self.__permutate(des.__ip, block) |
self.L = block[:32] |
self.R = block[32:] |
# Encryption starts from Kn[1] through to Kn[16] |
if crypt_type == des.ENCRYPT: |
iteration = 0 |
iteration_adjustment = 1 |
# Decryption starts from Kn[16] down to Kn[1] |
else: |
iteration = 15 |
iteration_adjustment = -1 |
i = 0 |
while i < 16: |
# Make a copy of R[i-1], this will later become L[i] |
tempR = self.R[:] |
# Permutate R[i - 1] to start creating R[i] |
self.R = self.__permutate(des.__expansion_table, self.R) |
# Exclusive or R[i - 1] with K[i], create B[1] to B[8] whilst here |
self.R = map(lambda x, y: x ^ y, self.R, self.Kn[iteration]) |
B = [self.R[:6], self.R[6:12], self.R[12:18], self.R[18:24], self.R[24:30], self.R[30:36], self.R[36:42], self.R[42:]] |
# Optimization: Replaced below commented code with above |
#j = 0 |
#B = [] |
#while j < len(self.R): |
# self.R[j] = self.R[j] ^ self.Kn[iteration][j] |
# j += 1 |
# if j % 6 == 0: |
# B.append(self.R[j-6:j]) |
# Permutate B[1] to B[8] using the S-Boxes |
j = 0 |
Bn = [0] * 32 |
pos = 0 |
while j < 8: |
# Work out the offsets |
m = (B[j][0] << 1) + B[j][5] |
n = (B[j][1] << 3) + (B[j][2] << 2) + (B[j][3] << 1) + B[j][4] |
# Find the permutation value |
v = des.__sbox[j][(m << 4) + n] |
# Turn value into bits, add it to result: Bn |
Bn[pos] = (v & 8) >> 3 |
Bn[pos + 1] = (v & 4) >> 2 |
Bn[pos + 2] = (v & 2) >> 1 |
Bn[pos + 3] = v & 1 |
pos += 4 |
j += 1 |
# Permutate the concatination of B[1] to B[8] (Bn) |
self.R = self.__permutate(des.__p, Bn) |
# Xor with L[i - 1] |
self.R = map(lambda x, y: x ^ y, self.R, self.L) |
# Optimization: This now replaces the below commented code |
#j = 0 |
#while j < len(self.R): |
# self.R[j] = self.R[j] ^ self.L[j] |
# j += 1 |
# L[i] becomes R[i - 1] |
self.L = tempR |
i += 1 |
iteration += iteration_adjustment |
# Final permutation of R[16]L[16] |
self.final = self.__permutate(des.__fp, self.R + self.L) |
return self.final |
# Data to be encrypted/decrypted |
def crypt(self, data, crypt_type): |
"""Crypt the data in blocks, running it through des_crypt()""" |
# Error check the data |
if not data: |
return '' |
if len(data) % self.block_size != 0: |
if crypt_type == des.DECRYPT: # Decryption must work on 8 byte blocks |
raise ValueError("Invalid data length, data must be a multiple of " + str(self.block_size) + " bytes\n.") |
if not self.getPadding(): |
raise ValueError("Invalid data length, data must be a multiple of " + str(self.block_size) + " bytes\n. Try setting the optional padding character") |
else: |
data += (self.block_size - (len(data) % self.block_size)) * self.getPadding() |
# print "Len of data: %f" % (len(data) / self.block_size) |
if self.getMode() == CBC: |
if self.getIV(): |
iv = self.__String_to_BitList(self.getIV()) |
else: |
raise ValueError("For CBC mode, you must supply the Initial Value (IV) for ciphering") |
# Split the data into blocks, crypting each one seperately |
i = 0 |
dict = {} |
result = [] |
#cached = 0 |
#lines = 0 |
while i < len(data): |
# Test code for caching encryption results |
#lines += 1 |
#if dict.has_key(data[i:i+8]): |
#print "Cached result for: %s" % data[i:i+8] |
# cached += 1 |
# result.append(dict[data[i:i+8]]) |
# i += 8 |
# continue |
block = self.__String_to_BitList(data[i:i+8]) |
# Xor with IV if using CBC mode |
if self.getMode() == CBC: |
if crypt_type == des.ENCRYPT: |
block = map(lambda x, y: x ^ y, block, iv) |
#j = 0 |
#while j < len(block): |
# block[j] = block[j] ^ iv[j] |
# j += 1 |
processed_block = self.__des_crypt(block, crypt_type) |
if crypt_type == des.DECRYPT: |
processed_block = map(lambda x, y: x ^ y, processed_block, iv) |
#j = 0 |
#while j < len(processed_block): |
# processed_block[j] = processed_block[j] ^ iv[j] |
# j += 1 |
iv = block |
else: |
iv = processed_block |
else: |
processed_block = self.__des_crypt(block, crypt_type) |
# Add the resulting crypted block to our list |
#d = self.__BitList_to_String(processed_block) |
#result.append(d) |
result.append(self.__BitList_to_String(processed_block)) |
#dict[data[i:i+8]] = d |
i += 8 |
# print "Lines: %d, cached: %d" % (lines, cached) |
# Remove the padding from the last block |
if crypt_type == des.DECRYPT and self.getPadding(): |
#print "Removing decrypt pad" |
s = result[-1] |
while s[-1] == self.getPadding(): |
s = s[:-1] |
result[-1] = s |
# Return the full crypted string |
return ''.join(result) |
def encrypt(self, data, pad=''): |
"""encrypt(data, [pad]) -> string |
data : String to be encrypted |
pad : Optional argument for encryption padding. Must only be one byte |
The data must be a multiple of 8 bytes and will be encrypted |
with the already specified key. Data does not have to be a |
multiple of 8 bytes if the padding character is supplied, the |
data will then be padded to a multiple of 8 bytes with this |
pad character. |
""" |
self.__padding = pad |
return self.crypt(data, des.ENCRYPT) |
def decrypt(self, data, pad=''): |
"""decrypt(data, [pad]) -> string |
data : String to be encrypted |
pad : Optional argument for decryption padding. Must only be one byte |
The data must be a multiple of 8 bytes and will be decrypted |
with the already specified key. If the optional padding character |
is supplied, then the un-encypted data will have the padding characters |
removed from the end of the string. This pad removal only occurs on the |
last 8 bytes of the data (last data block). |
""" |
self.__padding = pad |
return self.crypt(data, des.DECRYPT) |
############################################################################# |
# Triple DES # |
############################################################################# |
class triple_des: |
"""Triple DES encryption/decrytpion class |
This algorithm uses the DES-EDE3 (when a 24 byte key is supplied) or |
the DES-EDE2 (when a 16 byte key is supplied) encryption methods. |
Supports ECB (Electronic Code Book) and CBC (Cypher Block Chaining) modes. |
pyDes.des(key, [mode], [IV]) |
key -> The encryption key string, must be either 16 or 24 bytes long |
mode -> Optional argument for encryption type, can be either pyDes.ECB |
(Electronic Code Book), pyDes.CBC (Cypher Block Chaining) |
IV -> Optional string argument, must be supplied if using CBC mode. |
Must be 8 bytes in length. |
""" |
def __init__(self, key, mode=ECB, IV=None): |
self.block_size = 8 |
self.setMode(mode) |
self.__padding = '' |
self.__iv = IV |
self.setKey(key) |
def getKey(self): |
"""getKey() -> string""" |
return self.__key |
def setKey(self, key): |
"""Will set the crypting key for this object. Either 16 or 24 bytes long.""" |
self.key_size = 24 # Use DES-EDE3 mode |
if len(key) != self.key_size: |
if len(key) == 16: # Use DES-EDE2 mode |
self.key_size = 16 |
else: |
raise ValueError("Invalid triple DES key size. Key must be either 16 or 24 bytes long") |
if self.getMode() == CBC: |
if not self.getIV(): |
# Use the first 8 bytes of the key |
self.setIV(key[:self.block_size]) |
if len(self.getIV()) != self.block_size: |
raise ValueError("Invalid IV, must be 8 bytes in length") |
self.__key1 = des(key[:8], self.getMode(), self.getIV()) |
self.__key2 = des(key[8:16], self.getMode(), self.getIV()) |
if self.key_size == 16: |
self.__key3 = self.__key1 |
else: |
self.__key3 = des(key[16:], self.getMode(), self.getIV()) |
self.__key = key |
def getMode(self): |
"""getMode() -> pyDes.ECB or pyDes.CBC""" |
return self.__mode |
def setMode(self, mode): |
"""Sets the type of crypting mode, pyDes.ECB or pyDes.CBC""" |
self.__mode = mode |
def getIV(self): |
"""getIV() -> string""" |
return self.__iv |
def setIV(self, IV): |
"""Will set the Initial Value, used in conjunction with CBC mode""" |
self.__iv = IV |
def encrypt(self, data, pad=''): |
"""encrypt(data, [pad]) -> string |
data : String to be encrypted |
pad : Optional argument for encryption padding. Must only be one byte |
The data must be a multiple of 8 bytes and will be encrypted |
with the already specified key. Data does not have to be a |
multiple of 8 bytes if the padding character is supplied, the |
data will then be padded to a multiple of 8 bytes with this |
pad character. |
""" |
if self.getMode() == CBC: |
self.__key1.setIV(self.getIV()) |
self.__key2.setIV(self.getIV()) |
self.__key3.setIV(self.getIV()) |
i = 0 |
result = [] |
while i < len(data): |
block = self.__key1.encrypt(data[i:i+8], pad) |
block = self.__key2.decrypt(block) |
block = self.__key3.encrypt(block) |
self.__key1.setIV(block) |
self.__key2.setIV(block) |
self.__key3.setIV(block) |
result.append(block) |
i += 8 |
return ''.join(result) |
else: |
data = self.__key1.encrypt(data, pad) |
data = self.__key2.decrypt(data) |
return self.__key3.encrypt(data) |
def decrypt(self, data, pad=''): |
"""decrypt(data, [pad]) -> string |
data : String to be encrypted |
pad : Optional argument for decryption padding. Must only be one byte |
The data must be a multiple of 8 bytes and will be decrypted |
with the already specified key. If the optional padding character |
is supplied, then the un-encypted data will have the padding characters |
removed from the end of the string. This pad removal only occurs on the |
last 8 bytes of the data (last data block). |
""" |
if self.getMode() == CBC: |
self.__key1.setIV(self.getIV()) |
self.__key2.setIV(self.getIV()) |
self.__key3.setIV(self.getIV()) |
i = 0 |
result = [] |
while i < len(data): |
iv = data[i:i+8] |
block = self.__key3.decrypt(iv) |
block = self.__key2.encrypt(block) |
block = self.__key1.decrypt(block, pad) |
self.__key1.setIV(iv) |
self.__key2.setIV(iv) |
self.__key3.setIV(iv) |
result.append(block) |
i += 8 |
return ''.join(result) |
else: |
data = self.__key3.decrypt(data) |
data = self.__key2.encrypt(data) |
return self.__key1.decrypt(data, pad) |
############################################################################# |
# Examples # |
############################################################################# |
def example_triple_des(): |
from time import time |
# Utility module |
from binascii import unhexlify as unhex |
# example shows triple-des encryption using the des class |
print "Example of triple DES encryption in default ECB mode (DES-EDE3)\n" |
print "Triple des using the des class (3 times)" |
t = time() |
k1 = des(unhex("133457799BBCDFF1")) |
k2 = des(unhex("1122334455667788")) |
k3 = des(unhex("77661100DD223311")) |
d = "Triple DES test string, to be encrypted and decrypted..." |
print "Key1: %s" % k1.getKey() |
print "Key2: %s" % k2.getKey() |
print "Key3: %s" % k3.getKey() |
print "Data: %s" % d |
e1 = k1.encrypt(d) |
e2 = k2.decrypt(e1) |
e3 = k3.encrypt(e2) |
print "Encrypted: " + e3 |
d3 = k3.decrypt(e3) |
d2 = k2.encrypt(d3) |
d1 = k1.decrypt(d2) |
print "Decrypted: " + d1 |
print "DES time taken: %f (%d crypt operations)" % (time() - t, 6 * (len(d) / 8)) |
print "" |
# Example below uses the triple-des class to achieve the same as above |
print "Now using triple des class" |
t = time() |
t1 = triple_des(unhex("133457799BBCDFF1112233445566778877661100DD223311")) |
print "Key: %s" % t1.getKey() |
print "Data: %s" % d |
td1 = t1.encrypt(d) |
print "Encrypted: " + td1 |
td2 = t1.decrypt(td1) |
print "Decrypted: " + td2 |
print "Triple DES time taken: %f (%d crypt operations)" % (time() - t, 6 * (len(d) / 8)) |
def example_des(): |
from time import time |
# example of DES encrypting in CBC mode with the IV of "\0\0\0\0\0\0\0\0" |
print "Example of DES encryption using CBC mode\n" |
t = time() |
k = des("DESCRYPT", CBC, "\0\0\0\0\0\0\0\0") |
data = "DES encryption algorithm" |
print "Key : " + k.getKey() |
print "Data : " + data |
d = k.encrypt(data) |
print "Encrypted: " + d |
d = k.decrypt(d) |
print "Decrypted: " + d |
print "DES time taken: %f (6 crypt operations)" % (time() - t) |
print "" |
def __test__(): |
example_des() |
example_triple_des() |
def __fulltest__(): |
# This should not produce any unexpected errors or exceptions |
from binascii import unhexlify as unhex |
from binascii import hexlify as dohex |
__test__() |
print "" |
k = des("\0\0\0\0\0\0\0\0", CBC, "\0\0\0\0\0\0\0\0") |
d = k.encrypt("DES encryption algorithm") |
if k.decrypt(d) != "DES encryption algorithm": |
print "Test 1 Error: Unencypted data block does not match start data" |
k = des("\0\0\0\0\0\0\0\0", CBC, "\0\0\0\0\0\0\0\0") |
d = k.encrypt("Default string of text", '*') |
if k.decrypt(d, "*") != "Default string of text": |
print "Test 2 Error: Unencypted data block does not match start data" |
k = des("\r\n\tABC\r\n") |
d = k.encrypt("String to Pad", '*') |
if k.decrypt(d) != "String to Pad***": |
print "'%s'" % k.decrypt(d) |
print "Test 3 Error: Unencypted data block does not match start data" |
k = des("\r\n\tABC\r\n") |
d = k.encrypt(unhex("000102030405060708FF8FDCB04080"), unhex("44")) |
if k.decrypt(d, unhex("44")) != unhex("000102030405060708FF8FDCB04080"): |
print "Test 4a Error: Unencypted data block does not match start data" |
if k.decrypt(d) != unhex("000102030405060708FF8FDCB0408044"): |
print "Test 4b Error: Unencypted data block does not match start data" |
k = triple_des("MyDesKey\r\n\tABC\r\n0987*543") |
d = k.encrypt(unhex("000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080")) |
if k.decrypt(d) != unhex("000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080"): |
print "Test 5 Error: Unencypted data block does not match start data" |
k = triple_des("\r\n\tABC\r\n0987*543") |
d = k.encrypt(unhex("000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080")) |
if k.decrypt(d) != unhex("000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080"): |
print "Test 6 Error: Unencypted data block does not match start data" |
k = triple_des("MyDesKey\r\n\tABC\r\n0987*54B", CBC, "12341234") |
d = k.encrypt(unhex("000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080")) |
if k.decrypt(d) != unhex("000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080"): |
print "Test 7 Error: Triple DES CBC failed." |
k = triple_des("MyDesKey\r\n\tABC\r\n0987*54B", CBC, "12341234") |
d = k.encrypt(unhex("000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDC"), '.') |
if k.decrypt(d, '.') != unhex("000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDC"): |
print "Test 8 Error: Triple DES CBC with padding failed." |
def __filetest__(): |
from time import time |
f = open("pyDes.py", "rb+") |
d = f.read() |
f.close() |
t = time() |
k = des("MyDESKey") |
d = k.encrypt(d, " ") |
f = open("pyDes.py.enc", "wb+") |
f.write(d) |
f.close() |
d = k.decrypt(d, " ") |
f = open("pyDes.py.dec", "wb+") |
f.write(d) |
f.close() |
print "DES file test time: %f" % (time() - t) |
def __profile__(): |
import profile |
profile.run('__fulltest__()') |
#profile.run('__filetest__()') |
if __name__ == '__main__': |
__test__() |
#__fulltest__() |
#__filetest__() |
#__profile__() |
/relevation/branches/1.1/python-cryptoplus/src/CryptoPlus/Cipher/blockcipher.py |
---|
0,0 → 1,594 |
# ============================================================================= |
# Copyright (c) 2008 Christophe Oosterlynck <christophe.oosterlynck_AT_gmail.com> |
# & NXP ( Philippe Teuwen <philippe.teuwen_AT_nxp.com> ) |
# |
# Permission is hereby granted, free of charge, to any person obtaining a copy |
# of this software and associated documentation files (the "Software"), to deal |
# in the Software without restriction, including without limitation the rights |
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
# copies of the Software, and to permit persons to whom the Software is |
# furnished to do so, subject to the following conditions: |
# |
# The above copyright notice and this permission notice shall be included in |
# all copies or substantial portions of the Software. |
# |
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
# THE SOFTWARE. |
# ============================================================================= |
from ..Util import util |
from array import array |
from ..Util import padding |
MODE_ECB = 1 |
MODE_CBC = 2 |
MODE_CFB = 3 |
MODE_OFB = 5 |
MODE_CTR = 6 |
MODE_XTS = 7 |
MODE_CMAC = 8 |
class BlockCipher(): |
""" Base class for all blockciphers |
""" |
key_error_message = "Wrong key size" #should be overwritten in child classes |
def __init__(self,key,mode,IV,counter,cipher_module,segment_size,args={}): |
# Cipher classes inheriting from this one take care of: |
# self.blocksize |
# self.cipher |
self.key = key |
self.mode = mode |
self.cache = '' |
self.ed = None |
if 'keylen_valid' in dir(self): #wrappers for pycrypto functions don't have this function |
if not self.keylen_valid(key) and type(key) is not tuple: |
raise ValueError(self.key_error_message) |
if IV == None: |
self.IV = '\x00'*self.blocksize |
else: |
self.IV = IV |
if segment_size == None: |
segment_size = 8 |
if mode <> MODE_XTS: |
self.cipher = cipher_module(self.key,**args) |
if mode == MODE_ECB: |
self.chain = ECB(self.cipher, self.blocksize) |
elif mode == MODE_CBC: |
if len(self.IV) <> self.blocksize: |
raise Exception,"the IV length should be %i bytes"%self.blocksize |
self.chain = CBC(self.cipher, self.blocksize,self.IV) |
elif mode == MODE_CFB: |
if len(self.IV) <> self.blocksize: |
raise Exception,"the IV length should be %i bytes"%self.blocksize |
if segment_size > self.blocksize*8 or segment_size%8 <> 0: |
# current CFB implementation doesn't support bit level acces => segment_size should be multiple of bytes |
raise ValueError,"segment size should be a multiple of 8 bits between 8 and %i"%(self.blocksize*8) |
self.chain = CFB(self.cipher, self.blocksize,self.IV,segment_size) |
elif mode == MODE_OFB: |
if len(self.IV) <> self.blocksize: |
raise ValueError("the IV length should be %i bytes"%self.blocksize) |
self.chain = OFB(self.cipher, self.blocksize,self.IV) |
elif mode == MODE_CTR: |
if (counter == None) or not callable(counter): |
raise Exception,"Supply a valid counter object for the CTR mode" |
self.chain = CTR(self.cipher,self.blocksize,counter) |
elif mode == MODE_XTS: |
if self.blocksize <> 16: |
raise Exception,'XTS only works with blockcipher that have a 128-bit blocksize' |
if not(type(key) == tuple and len(key) == 2): |
raise Exception,'Supply two keys as a tuple when using XTS' |
if 'keylen_valid' in dir(self): #wrappers for pycrypto functions don't have this function |
if not self.keylen_valid(key[0]) or not self.keylen_valid(key[1]): |
raise ValueError(self.key_error_message) |
self.cipher = cipher_module(self.key[0],**args) |
self.cipher2 = cipher_module(self.key[1],**args) |
self.chain = XTS(self.cipher, self.cipher2) |
elif mode == MODE_CMAC: |
if self.blocksize not in (8,16): |
raise Exception,'CMAC only works with blockcipher that have a 64 or 128-bit blocksize' |
self.chain = CMAC(self.cipher,self.blocksize,self.IV) |
else: |
raise Exception,"Unknown chaining mode!" |
def encrypt(self,plaintext,n=''): |
"""Encrypt some plaintext |
plaintext = a string of binary data |
n = the 'tweak' value when the chaining mode is XTS |
The encrypt function will encrypt the supplied plaintext. |
The behavior varies slightly depending on the chaining mode. |
ECB, CBC: |
--------- |
When the supplied plaintext is not a multiple of the blocksize |
of the cipher, then the remaining plaintext will be cached. |
The next time the encrypt function is called with some plaintext, |
the new plaintext will be concatenated to the cache and then |
cache+plaintext will be encrypted. |
CFB, OFB, CTR: |
-------------- |
When the chaining mode allows the cipher to act as a stream cipher, |
the encrypt function will always encrypt all of the supplied |
plaintext immediately. No cache will be kept. |
XTS: |
---- |
Because the handling of the last two blocks is linked, |
it needs the whole block of plaintext to be supplied at once. |
Every encrypt function called on a XTS cipher will output |
an encrypted block based on the current supplied plaintext block. |
CMAC: |
----- |
Everytime the function is called, the hash from the input data is calculated. |
No finalizing needed. |
The hashlength is equal to block size of the used block cipher. |
""" |
#self.ed = 'e' if chain is encrypting, 'd' if decrypting, |
# None if nothing happened with the chain yet |
#assert self.ed in ('e',None) |
# makes sure you don't encrypt with a cipher that has started decrypting |
self.ed = 'e' |
if self.mode == MODE_XTS: |
# data sequence number (or 'tweak') has to be provided when in XTS mode |
return self.chain.update(plaintext,'e',n) |
else: |
return self.chain.update(plaintext,'e') |
def decrypt(self,ciphertext,n=''): |
"""Decrypt some ciphertext |
ciphertext = a string of binary data |
n = the 'tweak' value when the chaining mode is XTS |
The decrypt function will decrypt the supplied ciphertext. |
The behavior varies slightly depending on the chaining mode. |
ECB, CBC: |
--------- |
When the supplied ciphertext is not a multiple of the blocksize |
of the cipher, then the remaining ciphertext will be cached. |
The next time the decrypt function is called with some ciphertext, |
the new ciphertext will be concatenated to the cache and then |
cache+ciphertext will be decrypted. |
CFB, OFB, CTR: |
-------------- |
When the chaining mode allows the cipher to act as a stream cipher, |
the decrypt function will always decrypt all of the supplied |
ciphertext immediately. No cache will be kept. |
XTS: |
---- |
Because the handling of the last two blocks is linked, |
it needs the whole block of ciphertext to be supplied at once. |
Every decrypt function called on a XTS cipher will output |
a decrypted block based on the current supplied ciphertext block. |
CMAC: |
----- |
Mode not supported for decryption as this does not make sense. |
""" |
#self.ed = 'e' if chain is encrypting, 'd' if decrypting, |
# None if nothing happened with the chain yet |
#assert self.ed in ('d',None) |
# makes sure you don't decrypt with a cipher that has started encrypting |
self.ed = 'd' |
if self.mode == MODE_XTS: |
# data sequence number (or 'tweak') has to be provided when in XTS mode |
return self.chain.update(ciphertext,'d',n) |
else: |
return self.chain.update(ciphertext,'d') |
def final(self,padfct=padding.PKCS7): |
# TODO: after calling final, reset the IV? so the cipher is as good as new? |
"""Finalizes the encryption by padding the cache |
padfct = padding function |
import from CryptoPlus.Util.padding |
For ECB, CBC: the remaining bytes in the cache will be padded and |
encrypted. |
For OFB,CFB, CTR: an encrypted padding will be returned, making the |
total outputed bytes since construction of the cipher |
a multiple of the blocksize of that cipher. |
If the cipher has been used for decryption, the final function won't do |
anything. You have to manually unpad if necessary. |
After finalization, the chain can still be used but the IV, counter etc |
aren't reset but just continue as they were after the last step (finalization step). |
""" |
assert self.mode not in (MODE_XTS, MODE_CMAC) # finalizing (=padding) doesn't make sense when in XTS or CMAC mode |
if self.ed == 'e': |
# when the chain is in encryption mode, finalizing will pad the cache and encrypt this last block |
if self.mode in (MODE_OFB,MODE_CFB,MODE_CTR): |
dummy = '0'*(self.chain.totalbytes%self.blocksize) # a dummy string that will be used to get a valid padding |
else: #ECB, CBC |
dummy = self.chain.cache |
pad = padfct(dummy,padding.PAD,self.blocksize)[len(dummy):] # construct the padding necessary |
return self.chain.update(pad,'e') # supply the padding to the update function => chain cache will be "cache+padding" |
else: |
# final function doesn't make sense when decrypting => padding should be removed manually |
pass |
class ECB: |
"""ECB chaining mode |
""" |
def __init__(self, codebook, blocksize): |
self.cache = '' |
self.codebook = codebook |
self.blocksize = blocksize |
def update(self, data, ed): |
"""Processes the given ciphertext/plaintext |
Inputs: |
data: raw string of any length |
ed: 'e' for encryption, 'd' for decryption |
Output: |
processed raw string block(s), if any |
When the supplied data is not a multiple of the blocksize |
of the cipher, then the remaining input data will be cached. |
The next time the update function is called with some data, |
the new data will be concatenated to the cache and then |
cache+data will be processed and full blocks will be outputted. |
""" |
output_blocks = [] |
self.cache += data |
if len(self.cache) < self.blocksize: |
return '' |
for i in xrange(0, len(self.cache)-self.blocksize+1, self.blocksize): |
#the only difference between encryption/decryption in the chain is the cipher block |
if ed == 'e': |
output_blocks.append(self.codebook.encrypt( self.cache[i:i + self.blocksize] )) |
else: |
output_blocks.append(self.codebook.decrypt( self.cache[i:i + self.blocksize] )) |
self.cache = self.cache[i+self.blocksize:] |
return ''.join(output_blocks) |
class CBC: |
"""CBC chaining mode |
""" |
def __init__(self, codebook, blocksize, IV): |
self.IV = IV |
self.cache = '' |
self.codebook = codebook |
self.blocksize = blocksize |
def update(self, data, ed): |
"""Processes the given ciphertext/plaintext |
Inputs: |
data: raw string of any length |
ed: 'e' for encryption, 'd' for decryption |
Output: |
processed raw string block(s), if any |
When the supplied data is not a multiple of the blocksize |
of the cipher, then the remaining input data will be cached. |
The next time the update function is called with some data, |
the new data will be concatenated to the cache and then |
cache+data will be processed and full blocks will be outputted. |
""" |
if ed == 'e': |
encrypted_blocks = '' |
self.cache += data |
if len(self.cache) < self.blocksize: |
return '' |
for i in xrange(0, len(self.cache)-self.blocksize+1, self.blocksize): |
self.IV = self.codebook.encrypt(util.xorstring(self.cache[i:i+self.blocksize],self.IV)) |
encrypted_blocks += self.IV |
self.cache = self.cache[i+self.blocksize:] |
return encrypted_blocks |
else: |
decrypted_blocks = '' |
self.cache += data |
if len(self.cache) < self.blocksize: |
return '' |
for i in xrange(0, len(self.cache)-self.blocksize+1, self.blocksize): |
plaintext = util.xorstring(self.IV,self.codebook.decrypt(self.cache[i:i + self.blocksize])) |
self.IV = self.cache[i:i + self.blocksize] |
decrypted_blocks+=plaintext |
self.cache = self.cache[i+self.blocksize:] |
return decrypted_blocks |
class CFB: |
# TODO: bit access instead of only byte level access |
"""CFB Chaining Mode |
Can be accessed as a stream cipher. |
""" |
def __init__(self, codebook, blocksize, IV,segment_size): |
self.codebook = codebook |
self.IV = IV |
self.blocksize = blocksize |
self.segment_size = segment_size/8 |
self.keystream = [] |
self.totalbytes = 0 |
def update(self, data, ed): |
"""Processes the given ciphertext/plaintext |
Inputs: |
data: raw string of any multiple of bytes |
ed: 'e' for encryption, 'd' for decryption |
Output: |
processed raw string |
The encrypt/decrypt functions will always process all of the supplied |
input data immediately. No cache will be kept. |
""" |
output = list(data) |
for i in xrange(len(data)): |
if ed =='e': |
if len(self.keystream) == 0: |
block = self.codebook.encrypt(self.IV) |
self.keystream = list(block)[:self.segment_size] # keystream consists of the s MSB's |
self.IV = self.IV[self.segment_size:] # keeping (b-s) LSB's |
output[i] = chr(ord(output[i]) ^ ord(self.keystream.pop(0))) |
self.IV += output[i] # the IV for the next block in the chain is being built byte per byte as the ciphertext flows in |
else: |
if len(self.keystream) == 0: |
block = self.codebook.encrypt(self.IV) |
self.keystream = list(block)[:self.segment_size] |
self.IV = self.IV[self.segment_size:] |
self.IV += output[i] |
output[i] = chr(ord(output[i]) ^ ord(self.keystream.pop(0))) |
self.totalbytes += len(output) |
return ''.join(output) |
class OFB: |
"""OFB Chaining Mode |
Can be accessed as a stream cipher. |
""" |
def __init__(self, codebook, blocksize, IV): |
self.codebook = codebook |
self.IV = IV |
self.blocksize = blocksize |
self.keystream = [] |
self.totalbytes = 0 |
def update(self, data, ed): |
"""Processes the given ciphertext/plaintext |
Inputs: |
data: raw string of any multiple of bytes |
ed: 'e' for encryption, 'd' for decryption |
Output: |
processed raw string |
The encrypt/decrypt functions will always process all of the supplied |
input data immediately. No cache will be kept. |
""" |
#no difference between encryption and decryption mode |
n = len(data) |
blocksize = self.blocksize |
output = list(data) |
for i in xrange(n): |
if len(self.keystream) == 0: #encrypt a new counter block when the current keystream is fully used |
self.IV = self.codebook.encrypt(self.IV) |
self.keystream = list(self.IV) |
output[i] = chr(ord(output[i]) ^ ord(self.keystream.pop(0))) #as long as an encrypted counter value is available, the output is just "input XOR keystream" |
self.totalbytes += len(output) |
return ''.join(output) |
class CTR: |
"""CTR Chaining Mode |
Can be accessed as a stream cipher. |
""" |
# initial counter value can be choosen, decryption always starts from beginning |
# -> you can start from anywhere yourself: just feed the cipher encoded blocks and feed a counter with the corresponding value |
def __init__(self, codebook, blocksize, counter): |
self.codebook = codebook |
self.counter = counter |
self.blocksize = blocksize |
self.keystream = [] #holds the output of the current encrypted counter value |
self.totalbytes = 0 |
def update(self, data, ed): |
"""Processes the given ciphertext/plaintext |
Inputs: |
data: raw string of any multiple of bytes |
ed: 'e' for encryption, 'd' for decryption |
Output: |
processed raw string |
The encrypt/decrypt functions will always process all of the supplied |
input data immediately. No cache will be kept. |
""" |
# no need for the encryption/decryption distinction: both are the same |
n = len(data) |
blocksize = self.blocksize |
output = list(data) |
for i in xrange(n): |
if len(self.keystream) == 0: #encrypt a new counter block when the current keystream is fully used |
block = self.codebook.encrypt(self.counter()) |
self.keystream = list(block) |
output[i] = chr(ord(output[i])^ord(self.keystream.pop(0))) #as long as an encrypted counter value is available, the output is just "input XOR keystream" |
self.totalbytes += len(output) |
return ''.join(output) |
class XTS: |
"""XTS Chaining Mode |
Usable with blockciphers with a 16-byte blocksize |
""" |
# TODO: allow other blocksizes besides 16bytes? |
def __init__(self,codebook1, codebook2): |
self.cache = '' |
self.codebook1 = codebook1 |
self.codebook2 = codebook2 |
def update(self, data, ed,tweak=''): |
# supply n as a raw string |
# tweak = data sequence number |
"""Perform a XTS encrypt/decrypt operation. |
Because the handling of the last two blocks is linked, |
it needs the whole block of ciphertext to be supplied at once. |
Every decrypt function called on a XTS cipher will output |
a decrypted block based on the current supplied ciphertext block. |
""" |
output = '' |
assert len(data) > 15, "At least one block of 128 bits needs to be supplied" |
assert len(data) < 128*pow(2,20) |
# initializing T |
# e_k2_n = E_K2(tweak) |
e_k2_n = self.codebook2.encrypt(tweak+ '\x00' * (16-len(tweak)))[::-1] |
self.T = util.string2number(e_k2_n) |
i=0 |
while i < ((len(data) // 16)-1): #Decrypt all the blocks but one last full block and opt one last partial block |
# C = E_K1(P xor T) xor T |
output += self.__xts_step(ed,data[i*16:(i+1)*16],self.T) |
# T = E_K2(n) mul (a pow i) |
self.__T_update() |
i+=1 |
# Check if the data supplied is a multiple of 16 bytes -> one last full block and we're done |
if len(data[i*16:]) == 16: |
# C = E_K1(P xor T) xor T |
output += self.__xts_step(ed,data[i*16:(i+1)*16],self.T) |
# T = E_K2(n) mul (a pow i) |
self.__T_update() |
else: |
T_temp = [self.T] |
self.__T_update() |
T_temp.append(self.T) |
if ed=='d': |
# Permutation of the last two indexes |
T_temp.reverse() |
# Decrypt/Encrypt the last two blocks when data is not a multiple of 16 bytes |
Cm1 = data[i*16:(i+1)*16] |
Cm = data[(i+1)*16:] |
PP = self.__xts_step(ed,Cm1,T_temp[0]) |
Cp = PP[len(Cm):] |
Pm = PP[:len(Cm)] |
CC = Cm+Cp |
Pm1 = self.__xts_step(ed,CC,T_temp[1]) |
output += Pm1 + Pm |
return output |
def __xts_step(self,ed,tocrypt,T): |
T_string = util.number2string_N(T,16)[::-1] |
# C = E_K1(P xor T) xor T |
if ed == 'd': |
return util.xorstring(T_string, self.codebook1.decrypt(util.xorstring(T_string, tocrypt))) |
else: |
return util.xorstring(T_string, self.codebook1.encrypt(util.xorstring(T_string, tocrypt))) |
def __T_update(self): |
# Used for calculating T for a certain step using the T value from the previous step |
self.T = self.T << 1 |
# if (Cout) |
if self.T >> (8*16): |
#T[0] ^= GF_128_FDBK; |
self.T = self.T ^ 0x100000000000000000000000000000087L |
class CMAC: |
"""CMAC chaining mode |
Supports every cipher with a blocksize available |
in the list CMAC.supported_blocksizes. |
The hashlength is equal to block size of the used block cipher. |
Usable with blockciphers with a 8 or 16-byte blocksize |
""" |
# TODO: move to hash module? |
# TODO: change update behaviour to .update() and .digest() as for all hash modules? |
# -> other hash functions in pycrypto: calling update, concatenates current input with previous input and hashes everything |
__Rb_dictionary = {64:0x000000000000001b,128:0x00000000000000000000000000000087} |
supported_blocksizes = __Rb_dictionary.keys() |
def __init__(self,codebook,blocksize,IV): |
# Purpose of init: calculate Lu & Lu2 |
#blocksize (in bytes): to select the Rb constant in the dictionary |
#Rb as a dictionary: adding support for other blocksizes is easy |
self.cache='' |
self.blocksize = blocksize |
self.codebook = codebook |
self.IV = IV |
#Rb_dictionary: holds values for Rb for different blocksizes |
# values for 64 and 128 bits found here: http://www.nuee.nagoya-u.ac.jp/labs/tiwata/omac/omac.html |
# explanation from: http://csrc.nist.gov/publications/nistpubs/800-38B/SP_800-38B.pdf |
# Rb is a representation of a certain irreducible binary polynomial of degree b, namely, |
# the lexicographically first among all such polynomials with the minimum possible number of |
# nonzero terms. If this polynomial is expressed as ub+cb-1ub-1+...+c2u2+c1u+c0, where the |
# coefficients cb-1, cb-2, ..., c2, c1, c0 are either 0 or 1, then Rb is the bit string cb-1cb-2...c2c1c0. |
self.Rb = self.__Rb_dictionary[blocksize*8] |
mask1 = int(('\xff'*blocksize).encode('hex'),16) |
mask2 = int(('\x80' + '\x00'*(blocksize-1) ).encode('hex'),16) |
L = int(self.codebook.encrypt('\x00'*blocksize).encode('hex'),16) |
if L & mask2: |
Lu = ((L << 1) & mask1) ^ self.Rb |
else: |
Lu = L << 1 |
Lu = Lu & mask1 |
if Lu & mask2: |
Lu2 = ((Lu << 1) & mask1)^ self.Rb |
else: |
Lu2 = Lu << 1 |
Lu2 = Lu2 & mask1 |
self.Lu =util.number2string_N(Lu,self.blocksize) |
self.Lu2=util.number2string_N(Lu2,self.blocksize) |
def update(self, data, ed): |
"""Processes the given ciphertext/plaintext |
Inputs: |
data: raw string of any length |
ed: 'e' for encryption, 'd' for decryption |
Output: |
hashed data as raw string |
This is not really an update function: |
Everytime the function is called, the hash from the input data is calculated. |
No finalizing needed. |
""" |
assert ed == 'e' |
blocksize = self.blocksize |
m = (len(data)+blocksize-1)/blocksize #m = amount of datablocks |
i=0 |
for i in range(1,m): |
self.IV = self.codebook.encrypt( util.xorstring(data[(i-1)*blocksize:(i)*blocksize],self.IV) ) |
if len(data[(i)*blocksize:])==blocksize: |
X = util.xorstring(util.xorstring(data[(i)*blocksize:],self.IV),self.Lu) |
else: |
tmp = data[(i)*blocksize:] + '\x80' + '\x00'*(blocksize - len(data[(i)*blocksize:])-1) |
X = util.xorstring(util.xorstring(tmp,self.IV),self.Lu2) |
T = self.codebook.encrypt(X) |
return T |
/relevation/branches/1.1/python-cryptoplus/src/CryptoPlus/Cipher/pyblowfish.py |
---|
0,0 → 1,513 |
# |
# blowfish.py |
# Copyright (C) Michael Gilfix <mgilfix@gmail.com> |
# |
# This module is open source; you can redistribute it and/or |
# modify it under the terms of the GPL or Artistic License. |
# These licenses are available at http://www.opensource.org |
# |
# This software must be used and distributed in accordance |
# with the law. The author claims no liability for its |
# misuse. |
# |
# This program is distributed in the hope that it will be useful, |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
# |
""" |
Blowfish Encryption |
This module is a pure python implementation of Bruce Schneier's |
encryption scheme 'Blowfish'. Blowish is a 16-round Feistel Network |
cipher and offers substantial speed gains over DES. |
The key is a string of length anywhere between 64 and 448 bits, or |
equivalently 8 and 56 bytes. The encryption and decryption functions |
operate on 64-bit blocks, or 8 byte strings. |
Send questions, comments, bugs my way. Or, just let me know you're |
using the software: |
Michael Gilfix <mgilfix@gmail.com> |
""" |
__author__ = "Michael Gilfix <mgilfix@gmail.com>" |
import copy |
class Blowfish: |
"""Blowfish encryption Scheme |
This class implements the encryption and decryption |
functionality of the Blowfish cipher. |
Public functions: |
def __init__(self, key) |
Creates an instance of blowfish using 'key' |
as the encryption key. Key is a string of |
length ranging from 8 to 56 bytes (64 to 448 |
bits). Once the instance of the object is |
created, the key is no longer necessary. |
def encrypt(self, data): |
Convenience method. Calls crypt under the covers. |
def decrypt(self, data): |
Convenience method. Calls crypt under the covers. |
def crypt(self, data, direction): |
Performs actual encryption/decryption of data |
depending on the direction. The data is broken |
up into 8 byte chunks for the ciphering |
process. If the data does not align on 8 byte |
chunks, then null padding is added. This is |
removed upon decryption. |
def cipher(self, xl, xr, direction): |
Encrypts a 64-bit block of data where xl is |
the upper 32-bits and xr is the lower 32-bits. |
'direction' is the direction to apply the |
cipher, either ENCRYPT or DECRYPT constants. |
returns a tuple of either encrypted or decrypted |
data of the left half and right half of the |
64-bit block. |
Private members: |
def __round_func(self, xl) |
Performs an obscuring function on the 32-bit |
block of data 'xl', which is the left half of |
the 64-bit block of data. Returns the 32-bit |
result as a long integer. |
""" |
# Cipher directions |
ENCRYPT = 0 |
DECRYPT = 1 |
# For the __round_func |
MODULUS = 2L ** 32 |
# Constants |
BLOCK_SIZE = 8 |
MAX_KEY_LENGTH = 56 |
P_BOXES = [ |
0x243F6A88L, 0x85A308D3L, 0x13198A2EL, 0x03707344L, |
0xA4093822L, 0x299F31D0L, 0x082EFA98L, 0xEC4E6C89L, |
0x452821E6L, 0x38D01377L, 0xBE5466CFL, 0x34E90C6CL, |
0xC0AC29B7L, 0xC97C50DDL, 0x3F84D5B5L, 0xB5470917L, |
0x9216D5D9L, 0x8979FB1BL |
] |
S_BOXES = [ |
[ |
0xD1310BA6L, 0x98DFB5ACL, 0x2FFD72DBL, 0xD01ADFB7L, |
0xB8E1AFEDL, 0x6A267E96L, 0xBA7C9045L, 0xF12C7F99L, |
0x24A19947L, 0xB3916CF7L, 0x0801F2E2L, 0x858EFC16L, |
0x636920D8L, 0x71574E69L, 0xA458FEA3L, 0xF4933D7EL, |
0x0D95748FL, 0x728EB658L, 0x718BCD58L, 0x82154AEEL, |
0x7B54A41DL, 0xC25A59B5L, 0x9C30D539L, 0x2AF26013L, |
0xC5D1B023L, 0x286085F0L, 0xCA417918L, 0xB8DB38EFL, |
0x8E79DCB0L, 0x603A180EL, 0x6C9E0E8BL, 0xB01E8A3EL, |
0xD71577C1L, 0xBD314B27L, 0x78AF2FDAL, 0x55605C60L, |
0xE65525F3L, 0xAA55AB94L, 0x57489862L, 0x63E81440L, |
0x55CA396AL, 0x2AAB10B6L, 0xB4CC5C34L, 0x1141E8CEL, |
0xA15486AFL, 0x7C72E993L, 0xB3EE1411L, 0x636FBC2AL, |
0x2BA9C55DL, 0x741831F6L, 0xCE5C3E16L, 0x9B87931EL, |
0xAFD6BA33L, 0x6C24CF5CL, 0x7A325381L, 0x28958677L, |
0x3B8F4898L, 0x6B4BB9AFL, 0xC4BFE81BL, 0x66282193L, |
0x61D809CCL, 0xFB21A991L, 0x487CAC60L, 0x5DEC8032L, |
0xEF845D5DL, 0xE98575B1L, 0xDC262302L, 0xEB651B88L, |
0x23893E81L, 0xD396ACC5L, 0x0F6D6FF3L, 0x83F44239L, |
0x2E0B4482L, 0xA4842004L, 0x69C8F04AL, 0x9E1F9B5EL, |
0x21C66842L, 0xF6E96C9AL, 0x670C9C61L, 0xABD388F0L, |
0x6A51A0D2L, 0xD8542F68L, 0x960FA728L, 0xAB5133A3L, |
0x6EEF0B6CL, 0x137A3BE4L, 0xBA3BF050L, 0x7EFB2A98L, |
0xA1F1651DL, 0x39AF0176L, 0x66CA593EL, 0x82430E88L, |
0x8CEE8619L, 0x456F9FB4L, 0x7D84A5C3L, 0x3B8B5EBEL, |
0xE06F75D8L, 0x85C12073L, 0x401A449FL, 0x56C16AA6L, |
0x4ED3AA62L, 0x363F7706L, 0x1BFEDF72L, 0x429B023DL, |
0x37D0D724L, 0xD00A1248L, 0xDB0FEAD3L, 0x49F1C09BL, |
0x075372C9L, 0x80991B7BL, 0x25D479D8L, 0xF6E8DEF7L, |
0xE3FE501AL, 0xB6794C3BL, 0x976CE0BDL, 0x04C006BAL, |
0xC1A94FB6L, 0x409F60C4L, 0x5E5C9EC2L, 0x196A2463L, |
0x68FB6FAFL, 0x3E6C53B5L, 0x1339B2EBL, 0x3B52EC6FL, |
0x6DFC511FL, 0x9B30952CL, 0xCC814544L, 0xAF5EBD09L, |
0xBEE3D004L, 0xDE334AFDL, 0x660F2807L, 0x192E4BB3L, |
0xC0CBA857L, 0x45C8740FL, 0xD20B5F39L, 0xB9D3FBDBL, |
0x5579C0BDL, 0x1A60320AL, 0xD6A100C6L, 0x402C7279L, |
0x679F25FEL, 0xFB1FA3CCL, 0x8EA5E9F8L, 0xDB3222F8L, |
0x3C7516DFL, 0xFD616B15L, 0x2F501EC8L, 0xAD0552ABL, |
0x323DB5FAL, 0xFD238760L, 0x53317B48L, 0x3E00DF82L, |
0x9E5C57BBL, 0xCA6F8CA0L, 0x1A87562EL, 0xDF1769DBL, |
0xD542A8F6L, 0x287EFFC3L, 0xAC6732C6L, 0x8C4F5573L, |
0x695B27B0L, 0xBBCA58C8L, 0xE1FFA35DL, 0xB8F011A0L, |
0x10FA3D98L, 0xFD2183B8L, 0x4AFCB56CL, 0x2DD1D35BL, |
0x9A53E479L, 0xB6F84565L, 0xD28E49BCL, 0x4BFB9790L, |
0xE1DDF2DAL, 0xA4CB7E33L, 0x62FB1341L, 0xCEE4C6E8L, |
0xEF20CADAL, 0x36774C01L, 0xD07E9EFEL, 0x2BF11FB4L, |
0x95DBDA4DL, 0xAE909198L, 0xEAAD8E71L, 0x6B93D5A0L, |
0xD08ED1D0L, 0xAFC725E0L, 0x8E3C5B2FL, 0x8E7594B7L, |
0x8FF6E2FBL, 0xF2122B64L, 0x8888B812L, 0x900DF01CL, |
0x4FAD5EA0L, 0x688FC31CL, 0xD1CFF191L, 0xB3A8C1ADL, |
0x2F2F2218L, 0xBE0E1777L, 0xEA752DFEL, 0x8B021FA1L, |
0xE5A0CC0FL, 0xB56F74E8L, 0x18ACF3D6L, 0xCE89E299L, |
0xB4A84FE0L, 0xFD13E0B7L, 0x7CC43B81L, 0xD2ADA8D9L, |
0x165FA266L, 0x80957705L, 0x93CC7314L, 0x211A1477L, |
0xE6AD2065L, 0x77B5FA86L, 0xC75442F5L, 0xFB9D35CFL, |
0xEBCDAF0CL, 0x7B3E89A0L, 0xD6411BD3L, 0xAE1E7E49L, |
0x00250E2DL, 0x2071B35EL, 0x226800BBL, 0x57B8E0AFL, |
0x2464369BL, 0xF009B91EL, 0x5563911DL, 0x59DFA6AAL, |
0x78C14389L, 0xD95A537FL, 0x207D5BA2L, 0x02E5B9C5L, |
0x83260376L, 0x6295CFA9L, 0x11C81968L, 0x4E734A41L, |
0xB3472DCAL, 0x7B14A94AL, 0x1B510052L, 0x9A532915L, |
0xD60F573FL, 0xBC9BC6E4L, 0x2B60A476L, 0x81E67400L, |
0x08BA6FB5L, 0x571BE91FL, 0xF296EC6BL, 0x2A0DD915L, |
0xB6636521L, 0xE7B9F9B6L, 0xFF34052EL, 0xC5855664L, |
0x53B02D5DL, 0xA99F8FA1L, 0x08BA4799L, 0x6E85076A |
], |
[ |
0x4B7A70E9L, 0xB5B32944L, 0xDB75092EL, 0xC4192623L, |
0xAD6EA6B0L, 0x49A7DF7DL, 0x9CEE60B8L, 0x8FEDB266L, |
0xECAA8C71L, 0x699A17FFL, 0x5664526CL, 0xC2B19EE1L, |
0x193602A5L, 0x75094C29L, 0xA0591340L, 0xE4183A3EL, |
0x3F54989AL, 0x5B429D65L, 0x6B8FE4D6L, 0x99F73FD6L, |
0xA1D29C07L, 0xEFE830F5L, 0x4D2D38E6L, 0xF0255DC1L, |
0x4CDD2086L, 0x8470EB26L, 0x6382E9C6L, 0x021ECC5EL, |
0x09686B3FL, 0x3EBAEFC9L, 0x3C971814L, 0x6B6A70A1L, |
0x687F3584L, 0x52A0E286L, 0xB79C5305L, 0xAA500737L, |
0x3E07841CL, 0x7FDEAE5CL, 0x8E7D44ECL, 0x5716F2B8L, |
0xB03ADA37L, 0xF0500C0DL, 0xF01C1F04L, 0x0200B3FFL, |
0xAE0CF51AL, 0x3CB574B2L, 0x25837A58L, 0xDC0921BDL, |
0xD19113F9L, 0x7CA92FF6L, 0x94324773L, 0x22F54701L, |
0x3AE5E581L, 0x37C2DADCL, 0xC8B57634L, 0x9AF3DDA7L, |
0xA9446146L, 0x0FD0030EL, 0xECC8C73EL, 0xA4751E41L, |
0xE238CD99L, 0x3BEA0E2FL, 0x3280BBA1L, 0x183EB331L, |
0x4E548B38L, 0x4F6DB908L, 0x6F420D03L, 0xF60A04BFL, |
0x2CB81290L, 0x24977C79L, 0x5679B072L, 0xBCAF89AFL, |
0xDE9A771FL, 0xD9930810L, 0xB38BAE12L, 0xDCCF3F2EL, |
0x5512721FL, 0x2E6B7124L, 0x501ADDE6L, 0x9F84CD87L, |
0x7A584718L, 0x7408DA17L, 0xBC9F9ABCL, 0xE94B7D8CL, |
0xEC7AEC3AL, 0xDB851DFAL, 0x63094366L, 0xC464C3D2L, |
0xEF1C1847L, 0x3215D908L, 0xDD433B37L, 0x24C2BA16L, |
0x12A14D43L, 0x2A65C451L, 0x50940002L, 0x133AE4DDL, |
0x71DFF89EL, 0x10314E55L, 0x81AC77D6L, 0x5F11199BL, |
0x043556F1L, 0xD7A3C76BL, 0x3C11183BL, 0x5924A509L, |
0xF28FE6EDL, 0x97F1FBFAL, 0x9EBABF2CL, 0x1E153C6EL, |
0x86E34570L, 0xEAE96FB1L, 0x860E5E0AL, 0x5A3E2AB3L, |
0x771FE71CL, 0x4E3D06FAL, 0x2965DCB9L, 0x99E71D0FL, |
0x803E89D6L, 0x5266C825L, 0x2E4CC978L, 0x9C10B36AL, |
0xC6150EBAL, 0x94E2EA78L, 0xA5FC3C53L, 0x1E0A2DF4L, |
0xF2F74EA7L, 0x361D2B3DL, 0x1939260FL, 0x19C27960L, |
0x5223A708L, 0xF71312B6L, 0xEBADFE6EL, 0xEAC31F66L, |
0xE3BC4595L, 0xA67BC883L, 0xB17F37D1L, 0x018CFF28L, |
0xC332DDEFL, 0xBE6C5AA5L, 0x65582185L, 0x68AB9802L, |
0xEECEA50FL, 0xDB2F953BL, 0x2AEF7DADL, 0x5B6E2F84L, |
0x1521B628L, 0x29076170L, 0xECDD4775L, 0x619F1510L, |
0x13CCA830L, 0xEB61BD96L, 0x0334FE1EL, 0xAA0363CFL, |
0xB5735C90L, 0x4C70A239L, 0xD59E9E0BL, 0xCBAADE14L, |
0xEECC86BCL, 0x60622CA7L, 0x9CAB5CABL, 0xB2F3846EL, |
0x648B1EAFL, 0x19BDF0CAL, 0xA02369B9L, 0x655ABB50L, |
0x40685A32L, 0x3C2AB4B3L, 0x319EE9D5L, 0xC021B8F7L, |
0x9B540B19L, 0x875FA099L, 0x95F7997EL, 0x623D7DA8L, |
0xF837889AL, 0x97E32D77L, 0x11ED935FL, 0x16681281L, |
0x0E358829L, 0xC7E61FD6L, 0x96DEDFA1L, 0x7858BA99L, |
0x57F584A5L, 0x1B227263L, 0x9B83C3FFL, 0x1AC24696L, |
0xCDB30AEBL, 0x532E3054L, 0x8FD948E4L, 0x6DBC3128L, |
0x58EBF2EFL, 0x34C6FFEAL, 0xFE28ED61L, 0xEE7C3C73L, |
0x5D4A14D9L, 0xE864B7E3L, 0x42105D14L, 0x203E13E0L, |
0x45EEE2B6L, 0xA3AAABEAL, 0xDB6C4F15L, 0xFACB4FD0L, |
0xC742F442L, 0xEF6ABBB5L, 0x654F3B1DL, 0x41CD2105L, |
0xD81E799EL, 0x86854DC7L, 0xE44B476AL, 0x3D816250L, |
0xCF62A1F2L, 0x5B8D2646L, 0xFC8883A0L, 0xC1C7B6A3L, |
0x7F1524C3L, 0x69CB7492L, 0x47848A0BL, 0x5692B285L, |
0x095BBF00L, 0xAD19489DL, 0x1462B174L, 0x23820E00L, |
0x58428D2AL, 0x0C55F5EAL, 0x1DADF43EL, 0x233F7061L, |
0x3372F092L, 0x8D937E41L, 0xD65FECF1L, 0x6C223BDBL, |
0x7CDE3759L, 0xCBEE7460L, 0x4085F2A7L, 0xCE77326EL, |
0xA6078084L, 0x19F8509EL, 0xE8EFD855L, 0x61D99735L, |
0xA969A7AAL, 0xC50C06C2L, 0x5A04ABFCL, 0x800BCADCL, |
0x9E447A2EL, 0xC3453484L, 0xFDD56705L, 0x0E1E9EC9L, |
0xDB73DBD3L, 0x105588CDL, 0x675FDA79L, 0xE3674340L, |
0xC5C43465L, 0x713E38D8L, 0x3D28F89EL, 0xF16DFF20L, |
0x153E21E7L, 0x8FB03D4AL, 0xE6E39F2BL, 0xDB83ADF7 |
], |
[ |
0xE93D5A68L, 0x948140F7L, 0xF64C261CL, 0x94692934L, |
0x411520F7L, 0x7602D4F7L, 0xBCF46B2EL, 0xD4A20068L, |
0xD4082471L, 0x3320F46AL, 0x43B7D4B7L, 0x500061AFL, |
0x1E39F62EL, 0x97244546L, 0x14214F74L, 0xBF8B8840L, |
0x4D95FC1DL, 0x96B591AFL, 0x70F4DDD3L, 0x66A02F45L, |
0xBFBC09ECL, 0x03BD9785L, 0x7FAC6DD0L, 0x31CB8504L, |
0x96EB27B3L, 0x55FD3941L, 0xDA2547E6L, 0xABCA0A9AL, |
0x28507825L, 0x530429F4L, 0x0A2C86DAL, 0xE9B66DFBL, |
0x68DC1462L, 0xD7486900L, 0x680EC0A4L, 0x27A18DEEL, |
0x4F3FFEA2L, 0xE887AD8CL, 0xB58CE006L, 0x7AF4D6B6L, |
0xAACE1E7CL, 0xD3375FECL, 0xCE78A399L, 0x406B2A42L, |
0x20FE9E35L, 0xD9F385B9L, 0xEE39D7ABL, 0x3B124E8BL, |
0x1DC9FAF7L, 0x4B6D1856L, 0x26A36631L, 0xEAE397B2L, |
0x3A6EFA74L, 0xDD5B4332L, 0x6841E7F7L, 0xCA7820FBL, |
0xFB0AF54EL, 0xD8FEB397L, 0x454056ACL, 0xBA489527L, |
0x55533A3AL, 0x20838D87L, 0xFE6BA9B7L, 0xD096954BL, |
0x55A867BCL, 0xA1159A58L, 0xCCA92963L, 0x99E1DB33L, |
0xA62A4A56L, 0x3F3125F9L, 0x5EF47E1CL, 0x9029317CL, |
0xFDF8E802L, 0x04272F70L, 0x80BB155CL, 0x05282CE3L, |
0x95C11548L, 0xE4C66D22L, 0x48C1133FL, 0xC70F86DCL, |
0x07F9C9EEL, 0x41041F0FL, 0x404779A4L, 0x5D886E17L, |
0x325F51EBL, 0xD59BC0D1L, 0xF2BCC18FL, 0x41113564L, |
0x257B7834L, 0x602A9C60L, 0xDFF8E8A3L, 0x1F636C1BL, |
0x0E12B4C2L, 0x02E1329EL, 0xAF664FD1L, 0xCAD18115L, |
0x6B2395E0L, 0x333E92E1L, 0x3B240B62L, 0xEEBEB922L, |
0x85B2A20EL, 0xE6BA0D99L, 0xDE720C8CL, 0x2DA2F728L, |
0xD0127845L, 0x95B794FDL, 0x647D0862L, 0xE7CCF5F0L, |
0x5449A36FL, 0x877D48FAL, 0xC39DFD27L, 0xF33E8D1EL, |
0x0A476341L, 0x992EFF74L, 0x3A6F6EABL, 0xF4F8FD37L, |
0xA812DC60L, 0xA1EBDDF8L, 0x991BE14CL, 0xDB6E6B0DL, |
0xC67B5510L, 0x6D672C37L, 0x2765D43BL, 0xDCD0E804L, |
0xF1290DC7L, 0xCC00FFA3L, 0xB5390F92L, 0x690FED0BL, |
0x667B9FFBL, 0xCEDB7D9CL, 0xA091CF0BL, 0xD9155EA3L, |
0xBB132F88L, 0x515BAD24L, 0x7B9479BFL, 0x763BD6EBL, |
0x37392EB3L, 0xCC115979L, 0x8026E297L, 0xF42E312DL, |
0x6842ADA7L, 0xC66A2B3BL, 0x12754CCCL, 0x782EF11CL, |
0x6A124237L, 0xB79251E7L, 0x06A1BBE6L, 0x4BFB6350L, |
0x1A6B1018L, 0x11CAEDFAL, 0x3D25BDD8L, 0xE2E1C3C9L, |
0x44421659L, 0x0A121386L, 0xD90CEC6EL, 0xD5ABEA2AL, |
0x64AF674EL, 0xDA86A85FL, 0xBEBFE988L, 0x64E4C3FEL, |
0x9DBC8057L, 0xF0F7C086L, 0x60787BF8L, 0x6003604DL, |
0xD1FD8346L, 0xF6381FB0L, 0x7745AE04L, 0xD736FCCCL, |
0x83426B33L, 0xF01EAB71L, 0xB0804187L, 0x3C005E5FL, |
0x77A057BEL, 0xBDE8AE24L, 0x55464299L, 0xBF582E61L, |
0x4E58F48FL, 0xF2DDFDA2L, 0xF474EF38L, 0x8789BDC2L, |
0x5366F9C3L, 0xC8B38E74L, 0xB475F255L, 0x46FCD9B9L, |
0x7AEB2661L, 0x8B1DDF84L, 0x846A0E79L, 0x915F95E2L, |
0x466E598EL, 0x20B45770L, 0x8CD55591L, 0xC902DE4CL, |
0xB90BACE1L, 0xBB8205D0L, 0x11A86248L, 0x7574A99EL, |
0xB77F19B6L, 0xE0A9DC09L, 0x662D09A1L, 0xC4324633L, |
0xE85A1F02L, 0x09F0BE8CL, 0x4A99A025L, 0x1D6EFE10L, |
0x1AB93D1DL, 0x0BA5A4DFL, 0xA186F20FL, 0x2868F169L, |
0xDCB7DA83L, 0x573906FEL, 0xA1E2CE9BL, 0x4FCD7F52L, |
0x50115E01L, 0xA70683FAL, 0xA002B5C4L, 0x0DE6D027L, |
0x9AF88C27L, 0x773F8641L, 0xC3604C06L, 0x61A806B5L, |
0xF0177A28L, 0xC0F586E0L, 0x006058AAL, 0x30DC7D62L, |
0x11E69ED7L, 0x2338EA63L, 0x53C2DD94L, 0xC2C21634L, |
0xBBCBEE56L, 0x90BCB6DEL, 0xEBFC7DA1L, 0xCE591D76L, |
0x6F05E409L, 0x4B7C0188L, 0x39720A3DL, 0x7C927C24L, |
0x86E3725FL, 0x724D9DB9L, 0x1AC15BB4L, 0xD39EB8FCL, |
0xED545578L, 0x08FCA5B5L, 0xD83D7CD3L, 0x4DAD0FC4L, |
0x1E50EF5EL, 0xB161E6F8L, 0xA28514D9L, 0x6C51133CL, |
0x6FD5C7E7L, 0x56E14EC4L, 0x362ABFCEL, 0xDDC6C837L, |
0xD79A3234L, 0x92638212L, 0x670EFA8EL, 0x406000E0 |
], |
[ |
0x3A39CE37L, 0xD3FAF5CFL, 0xABC27737L, 0x5AC52D1BL, |
0x5CB0679EL, 0x4FA33742L, 0xD3822740L, 0x99BC9BBEL, |
0xD5118E9DL, 0xBF0F7315L, 0xD62D1C7EL, 0xC700C47BL, |
0xB78C1B6BL, 0x21A19045L, 0xB26EB1BEL, 0x6A366EB4L, |
0x5748AB2FL, 0xBC946E79L, 0xC6A376D2L, 0x6549C2C8L, |
0x530FF8EEL, 0x468DDE7DL, 0xD5730A1DL, 0x4CD04DC6L, |
0x2939BBDBL, 0xA9BA4650L, 0xAC9526E8L, 0xBE5EE304L, |
0xA1FAD5F0L, 0x6A2D519AL, 0x63EF8CE2L, 0x9A86EE22L, |
0xC089C2B8L, 0x43242EF6L, 0xA51E03AAL, 0x9CF2D0A4L, |
0x83C061BAL, 0x9BE96A4DL, 0x8FE51550L, 0xBA645BD6L, |
0x2826A2F9L, 0xA73A3AE1L, 0x4BA99586L, 0xEF5562E9L, |
0xC72FEFD3L, 0xF752F7DAL, 0x3F046F69L, 0x77FA0A59L, |
0x80E4A915L, 0x87B08601L, 0x9B09E6ADL, 0x3B3EE593L, |
0xE990FD5AL, 0x9E34D797L, 0x2CF0B7D9L, 0x022B8B51L, |
0x96D5AC3AL, 0x017DA67DL, 0xD1CF3ED6L, 0x7C7D2D28L, |
0x1F9F25CFL, 0xADF2B89BL, 0x5AD6B472L, 0x5A88F54CL, |
0xE029AC71L, 0xE019A5E6L, 0x47B0ACFDL, 0xED93FA9BL, |
0xE8D3C48DL, 0x283B57CCL, 0xF8D56629L, 0x79132E28L, |
0x785F0191L, 0xED756055L, 0xF7960E44L, 0xE3D35E8CL, |
0x15056DD4L, 0x88F46DBAL, 0x03A16125L, 0x0564F0BDL, |
0xC3EB9E15L, 0x3C9057A2L, 0x97271AECL, 0xA93A072AL, |
0x1B3F6D9BL, 0x1E6321F5L, 0xF59C66FBL, 0x26DCF319L, |
0x7533D928L, 0xB155FDF5L, 0x03563482L, 0x8ABA3CBBL, |
0x28517711L, 0xC20AD9F8L, 0xABCC5167L, 0xCCAD925FL, |
0x4DE81751L, 0x3830DC8EL, 0x379D5862L, 0x9320F991L, |
0xEA7A90C2L, 0xFB3E7BCEL, 0x5121CE64L, 0x774FBE32L, |
0xA8B6E37EL, 0xC3293D46L, 0x48DE5369L, 0x6413E680L, |
0xA2AE0810L, 0xDD6DB224L, 0x69852DFDL, 0x09072166L, |
0xB39A460AL, 0x6445C0DDL, 0x586CDECFL, 0x1C20C8AEL, |
0x5BBEF7DDL, 0x1B588D40L, 0xCCD2017FL, 0x6BB4E3BBL, |
0xDDA26A7EL, 0x3A59FF45L, 0x3E350A44L, 0xBCB4CDD5L, |
0x72EACEA8L, 0xFA6484BBL, 0x8D6612AEL, 0xBF3C6F47L, |
0xD29BE463L, 0x542F5D9EL, 0xAEC2771BL, 0xF64E6370L, |
0x740E0D8DL, 0xE75B1357L, 0xF8721671L, 0xAF537D5DL, |
0x4040CB08L, 0x4EB4E2CCL, 0x34D2466AL, 0x0115AF84L, |
0xE1B00428L, 0x95983A1DL, 0x06B89FB4L, 0xCE6EA048L, |
0x6F3F3B82L, 0x3520AB82L, 0x011A1D4BL, 0x277227F8L, |
0x611560B1L, 0xE7933FDCL, 0xBB3A792BL, 0x344525BDL, |
0xA08839E1L, 0x51CE794BL, 0x2F32C9B7L, 0xA01FBAC9L, |
0xE01CC87EL, 0xBCC7D1F6L, 0xCF0111C3L, 0xA1E8AAC7L, |
0x1A908749L, 0xD44FBD9AL, 0xD0DADECBL, 0xD50ADA38L, |
0x0339C32AL, 0xC6913667L, 0x8DF9317CL, 0xE0B12B4FL, |
0xF79E59B7L, 0x43F5BB3AL, 0xF2D519FFL, 0x27D9459CL, |
0xBF97222CL, 0x15E6FC2AL, 0x0F91FC71L, 0x9B941525L, |
0xFAE59361L, 0xCEB69CEBL, 0xC2A86459L, 0x12BAA8D1L, |
0xB6C1075EL, 0xE3056A0CL, 0x10D25065L, 0xCB03A442L, |
0xE0EC6E0EL, 0x1698DB3BL, 0x4C98A0BEL, 0x3278E964L, |
0x9F1F9532L, 0xE0D392DFL, 0xD3A0342BL, 0x8971F21EL, |
0x1B0A7441L, 0x4BA3348CL, 0xC5BE7120L, 0xC37632D8L, |
0xDF359F8DL, 0x9B992F2EL, 0xE60B6F47L, 0x0FE3F11DL, |
0xE54CDA54L, 0x1EDAD891L, 0xCE6279CFL, 0xCD3E7E6FL, |
0x1618B166L, 0xFD2C1D05L, 0x848FD2C5L, 0xF6FB2299L, |
0xF523F357L, 0xA6327623L, 0x93A83531L, 0x56CCCD02L, |
0xACF08162L, 0x5A75EBB5L, 0x6E163697L, 0x88D273CCL, |
0xDE966292L, 0x81B949D0L, 0x4C50901BL, 0x71C65614L, |
0xE6C6C7BDL, 0x327A140AL, 0x45E1D006L, 0xC3F27B9AL, |
0xC9AA53FDL, 0x62A80F00L, 0xBB25BFE2L, 0x35BDD2F6L, |
0x71126905L, 0xB2040222L, 0xB6CBCF7CL, 0xCD769C2BL, |
0x53113EC0L, 0x1640E3D3L, 0x38ABBD60L, 0x2547ADF0L, |
0xBA38209CL, 0xF746CE76L, 0x77AFA1C5L, 0x20756060L, |
0x85CBFE4EL, 0x8AE88DD8L, 0x7AAAF9B0L, 0x4CF9AA7EL, |
0x1948C25CL, 0x02FB8A8CL, 0x01C36AE4L, 0xD6EBE1F9L, |
0x90D4F869L, 0xA65CDEA0L, 0x3F09252DL, 0xC208E69FL, |
0xB74E6132L, 0xCE77E25BL, 0x578FDFE3L, 0x3AC372E6 |
] |
] |
def __init__(self, key): |
if not key or len(key) < 8 or len(key) > 56: |
raise ValueError, "Invalid cipher key length: %s" %len(key) |
# Initialize cipher copies from static data |
self.p_boxes = copy.deepcopy(self.P_BOXES) |
self.s_boxes = copy.deepcopy(self.S_BOXES) |
# Cycle through the p-boxes and round-robin XOR the |
# key ordinals with the p-boxes |
key_ord = map(ord, key) |
key_len = len(key_ord) |
index = 0 |
for i in range(len(self.p_boxes)): |
val = (key_ord[index % key_len] << 24) + \ |
(key_ord[(index + 1) % key_len] << 16) + \ |
(key_ord[(index + 2) % key_len] << 8) + \ |
key_ord[(index + 3) % key_len] |
self.p_boxes[i] = self.p_boxes[i] ^ val |
index = index + 4 |
# For the chaining process |
l, r = 0, 0 |
# Begin chain replacing the p-boxes |
for i in range(0, len(self.p_boxes), 2): |
l, r = self.cipher(l, r, self.ENCRYPT) |
self.p_boxes[i] = l |
self.p_boxes[i + 1] = r |
# Chain replace the s-boxes |
for i in range(len(self.s_boxes)): |
for j in range(0, len(self.s_boxes[i]), 2): |
l, r = self.cipher(l, r, self.ENCRYPT) |
self.s_boxes[i][j] = l |
self.s_boxes[i][j + 1] = r |
def cipher(self, xl, xr, direction): |
if direction == self.ENCRYPT: |
for i in range(16): |
xl = xl ^ self.p_boxes[i] |
xr = self.__round_func(xl) ^ xr |
xl, xr = xr, xl |
xl, xr = xr, xl |
xr = xr ^ self.p_boxes[16] |
xl = xl ^ self.p_boxes[17] |
else: |
for i in range(17, 1, -1): |
xl = xl ^ self.p_boxes[i] |
xr = self.__round_func(xl) ^ xr |
xl, xr = xr, xl |
xl, xr = xr, xl |
xr = xr ^ self.p_boxes[1] |
xl = xl ^ self.p_boxes[0] |
return xl, xr |
def __round_func(self, xl): |
a = (xl & 0xFF000000) >> 24 |
b = (xl & 0x00FF0000) >> 16 |
c = (xl & 0x0000FF00) >> 8 |
d = xl & 0x000000FF |
# Perform all ops as longs then and out the last 32-bits to |
# obtain the integer |
f = (self.s_boxes[0][a] + self.s_boxes[1][b]) % self.MODULUS |
f = f ^ self.s_boxes[2][c] |
f = f + self.s_boxes[3][d] |
f = (f % self.MODULUS) & 0xFFFFFFFF |
return int(f) |
def crypt(self, data, direction): |
# Pad the data if need be so it has 8 byte chunks |
align = len(data) % 8 |
if align != 0: |
padding = '\x00' * (8 - align) |
data += padding |
result = '' |
for i in range(0, len(data), 8): |
# Use big endianess since that's what everyone else uses |
chunk = map(ord, data[i : i + 8]) |
xl = chunk[3] | (chunk[2] << 8) | (chunk[1] << 16) | (chunk[0] << 24) |
xr = chunk[7] | (chunk[6] << 8) | (chunk[5] << 16) | (chunk[4] << 24) |
xl, xr = self.cipher(xl, xr, direction) |
chunk = ( |
(xl >> 24) & 0xFF, (xl >> 16) & 0xFF, (xl >> 8) & 0xFF, xl & 0xFF, |
(xr >> 24) & 0xFF, (xr >> 16) & 0xFF, (xr >> 8) & 0xFF, xr & 0xFF |
) |
result += ''.join(map(chr, chunk)) |
# Strip the padding if we decrypted |
if direction == self.DECRYPT: |
result = result.rstrip('\x00') |
return result |
def encrypt(self, data): |
return self.crypt(data, self.ENCRYPT) |
def decrypt(self, data): |
return self.crypt(data, self.DECRYPT) |
def block_size(self): |
return self.BLOCK_SIZE |
def max_key_length(self): |
return self.MAX_KEY_LENGTH |
def max_key_bits(self): |
return self.max_key_length() * self.block_size() |
############################################################## |
# Simple module testing |
if __name__ == '__main__': |
key = 'This is a simple test key' |
cipher = Blowfish(key) |
print "Max key bits: %s" %cipher.max_key_bits() |
print "Testing encryption:" |
xl = 123456 |
xr = 654321 |
print "\tPlain text: (%s, %s)" %(xl, xr) |
cl, cr = cipher.cipher(xl, xr, cipher.ENCRYPT) |
print "\tCrypted is: (%s, %s)" %(cl, cr) |
dl, dr = cipher.cipher(cl, cr, cipher.DECRYPT) |
print "\tUnencrypted is: (%s, %s)" %(dl, dr) |
print "Testing buffer encrypt:" |
text = 'This is my test string. Sample text goes here' |
print "\tText: [%s], len: %s" %(text, len(text)) |
crypted = cipher.encrypt(text) |
print "\tEncrypted: [%s]" %crypted |
decrypted = cipher.decrypt(crypted) |
print "\tDecrypted: [%s]" %decrypted |
print "Testing decryption from separate instances:" |
cipher1 = Blowfish(key) |
crypted = cipher1.encrypt(text) |
print "\tEncrypt cipher1: [%s]" %crypted |
cipher2 = Blowfish(key) |
decrypted = cipher2.decrypt(crypted) |
print "\tDecrypt cipher2: [%s]" %decrypted |
/relevation/branches/1.1/python-cryptoplus/src/CryptoPlus/Cipher/ARC2.py |
---|
0,0 → 1,59 |
from blockcipher import * |
import Crypto.Cipher.ARC2 |
import Crypto |
from pkg_resources import parse_version |
def new(key,mode=MODE_ECB,IV=None,counter=None,segment_size=None,effective_keylen=None): |
"""Create a new cipher object |
ARC2 using pycrypto for algo and pycryptoplus for ciphermode |
key = raw string containing the keys |
mode = python_AES.MODE_ECB/CBC/CFB/OFB/CTR/CMAC, default is ECB |
IV = IV as a raw string, default is "all zero" IV |
-> only needed for CBC mode |
counter = counter object (CryptoPlus.Util.util.Counter) |
-> only needed for CTR mode |
segment_size = amount of bits to use from the keystream in each chain part |
-> supported values: multiple of 8 between 8 and the blocksize |
of the cipher (only per byte access possible), default is 8 |
-> only needed for CFB mode |
effective_keylen = how much bits to effectively use from the supplied key |
-> will only be used when the pycrypto version on your system is >2.0.1 |
EXAMPLES: |
********** |
IMPORTING: |
----------- |
>>> from CryptoPlus.Cipher import ARC2 |
http://www.ietf.org/rfc/rfc2268.txt |
Doctest will fail when using pycrypto 2.0.1 and older |
------------------------------------ |
>>> key = "0000000000000000".decode('hex') |
>>> plaintext = "0000000000000000".decode('hex') |
>>> ek = 63 |
>>> cipher = ARC2.new(key,ARC2.MODE_ECB,effective_keylen=ek) |
>>> cipher.encrypt(plaintext).encode('hex') |
'ebb773f993278eff' |
""" |
return ARC2(key,mode,IV,counter,effective_keylen,segment_size) |
class ARC2(BlockCipher): |
def __init__(self,key,mode,IV,counter,effective_keylen,segment_size): |
# pycrypto versions newer than 2.0.1 will have support for "effective_keylen" |
if parse_version(Crypto.__version__) <= parse_version("2.0.1"): |
cipher_module = Crypto.Cipher.ARC2.new |
args = {} |
else: |
cipher_module = Crypto.Cipher.ARC2.new |
args = {'effective_keylen':effective_keylen} |
self.blocksize = 8 |
BlockCipher.__init__(self,key,mode,IV,counter,cipher_module,segment_size,args) |
def _test(): |
import doctest |
doctest.testmod() |
if __name__ == "__main__": |
_test() |
/relevation/branches/1.1/python-cryptoplus/src/CryptoPlus/Cipher/rijndael.py |
---|
0,0 → 1,392 |
""" |
A pure python (slow) implementation of rijndael with a decent interface |
To include - |
from rijndael import rijndael |
To do a key setup - |
r = rijndael(key, block_size = 16) |
key must be a string of length 16, 24, or 32 |
blocksize must be 16, 24, or 32. Default is 16 |
To use - |
ciphertext = r.encrypt(plaintext) |
plaintext = r.decrypt(ciphertext) |
If any strings are of the wrong length a ValueError is thrown |
""" |
# ported from the Java reference code by Bram Cohen, bram@gawth.com, April 2001 |
# this code is public domain, unless someone makes |
# an intellectual property claim against the reference |
# code, in which case it can be made public domain by |
# deleting all the comments and renaming all the variables |
import copy |
import string |
#----------------------- |
#TREV - ADDED BECAUSE THERE'S WARNINGS ABOUT INT OVERFLOW BEHAVIOR CHANGING IN |
#2.4..... |
import os |
if os.name != "java": |
import exceptions |
if hasattr(exceptions, "FutureWarning"): |
import warnings |
warnings.filterwarnings("ignore", category=FutureWarning, append=1) |
#----------------------- |
shifts = [[[0, 0], [1, 3], [2, 2], [3, 1]], |
[[0, 0], [1, 5], [2, 4], [3, 3]], |
[[0, 0], [1, 7], [3, 5], [4, 4]]] |
# [keysize][block_size] |
num_rounds = {16: {16: 10, 24: 12, 32: 14}, 24: {16: 12, 24: 12, 32: 14}, 32: {16: 14, 24: 14, 32: 14}} |
A = [[1, 1, 1, 1, 1, 0, 0, 0], |
[0, 1, 1, 1, 1, 1, 0, 0], |
[0, 0, 1, 1, 1, 1, 1, 0], |
[0, 0, 0, 1, 1, 1, 1, 1], |
[1, 0, 0, 0, 1, 1, 1, 1], |
[1, 1, 0, 0, 0, 1, 1, 1], |
[1, 1, 1, 0, 0, 0, 1, 1], |
[1, 1, 1, 1, 0, 0, 0, 1]] |
# produce log and alog tables, needed for multiplying in the |
# field GF(2^m) (generator = 3) |
alog = [1] |
for i in xrange(255): |
j = (alog[-1] << 1) ^ alog[-1] |
if j & 0x100 != 0: |
j ^= 0x11B |
alog.append(j) |
log = [0] * 256 |
for i in xrange(1, 255): |
log[alog[i]] = i |
# multiply two elements of GF(2^m) |
def mul(a, b): |
if a == 0 or b == 0: |
return 0 |
return alog[(log[a & 0xFF] + log[b & 0xFF]) % 255] |
# substitution box based on F^{-1}(x) |
box = [[0] * 8 for i in xrange(256)] |
box[1][7] = 1 |
for i in xrange(2, 256): |
j = alog[255 - log[i]] |
for t in xrange(8): |
box[i][t] = (j >> (7 - t)) & 0x01 |
B = [0, 1, 1, 0, 0, 0, 1, 1] |
# affine transform: box[i] <- B + A*box[i] |
cox = [[0] * 8 for i in xrange(256)] |
for i in xrange(256): |
for t in xrange(8): |
cox[i][t] = B[t] |
for j in xrange(8): |
cox[i][t] ^= A[t][j] * box[i][j] |
# S-boxes and inverse S-boxes |
S = [0] * 256 |
Si = [0] * 256 |
for i in xrange(256): |
S[i] = cox[i][0] << 7 |
for t in xrange(1, 8): |
S[i] ^= cox[i][t] << (7-t) |
Si[S[i] & 0xFF] = i |
# T-boxes |
G = [[2, 1, 1, 3], |
[3, 2, 1, 1], |
[1, 3, 2, 1], |
[1, 1, 3, 2]] |
AA = [[0] * 8 for i in xrange(4)] |
for i in xrange(4): |
for j in xrange(4): |
AA[i][j] = G[i][j] |
AA[i][i+4] = 1 |
for i in xrange(4): |
pivot = AA[i][i] |
if pivot == 0: |
t = i + 1 |
while AA[t][i] == 0 and t < 4: |
t += 1 |
assert t != 4, 'G matrix must be invertible' |
for j in xrange(8): |
AA[i][j], AA[t][j] = AA[t][j], AA[i][j] |
pivot = AA[i][i] |
for j in xrange(8): |
if AA[i][j] != 0: |
AA[i][j] = alog[(255 + log[AA[i][j] & 0xFF] - log[pivot & 0xFF]) % 255] |
for t in xrange(4): |
if i != t: |
for j in xrange(i+1, 8): |
AA[t][j] ^= mul(AA[i][j], AA[t][i]) |
AA[t][i] = 0 |
iG = [[0] * 4 for i in xrange(4)] |
for i in xrange(4): |
for j in xrange(4): |
iG[i][j] = AA[i][j + 4] |
def mul4(a, bs): |
if a == 0: |
return 0 |
r = 0 |
for b in bs: |
r <<= 8 |
if b != 0: |
r = r | mul(a, b) |
return r |
T1 = [] |
T2 = [] |
T3 = [] |
T4 = [] |
T5 = [] |
T6 = [] |
T7 = [] |
T8 = [] |
U1 = [] |
U2 = [] |
U3 = [] |
U4 = [] |
for t in xrange(256): |
s = S[t] |
T1.append(mul4(s, G[0])) |
T2.append(mul4(s, G[1])) |
T3.append(mul4(s, G[2])) |
T4.append(mul4(s, G[3])) |
s = Si[t] |
T5.append(mul4(s, iG[0])) |
T6.append(mul4(s, iG[1])) |
T7.append(mul4(s, iG[2])) |
T8.append(mul4(s, iG[3])) |
U1.append(mul4(t, iG[0])) |
U2.append(mul4(t, iG[1])) |
U3.append(mul4(t, iG[2])) |
U4.append(mul4(t, iG[3])) |
# round constants |
rcon = [1] |
r = 1 |
for t in xrange(1, 30): |
r = mul(2, r) |
rcon.append(r) |
del A |
del AA |
del pivot |
del B |
del G |
del box |
del log |
del alog |
del i |
del j |
del r |
del s |
del t |
del mul |
del mul4 |
del cox |
del iG |
class rijndael: |
def __init__(self, key, block_size = 16): |
if block_size != 16 and block_size != 24 and block_size != 32: |
raise ValueError('Invalid block size: ' + str(block_size)) |
if len(key) != 16 and len(key) != 24 and len(key) != 32: |
raise ValueError('Invalid key size: ' + str(len(key))) |
self.block_size = block_size |
ROUNDS = num_rounds[len(key)][block_size] |
BC = block_size / 4 |
# encryption round keys |
Ke = [[0] * BC for i in xrange(ROUNDS + 1)] |
# decryption round keys |
Kd = [[0] * BC for i in xrange(ROUNDS + 1)] |
ROUND_KEY_COUNT = (ROUNDS + 1) * BC |
KC = len(key) / 4 |
# copy user material bytes into temporary ints |
tk = [] |
for i in xrange(0, KC): |
tk.append((ord(key[i * 4]) << 24) | (ord(key[i * 4 + 1]) << 16) | |
(ord(key[i * 4 + 2]) << 8) | ord(key[i * 4 + 3])) |
# copy values into round key arrays |
t = 0 |
j = 0 |
while j < KC and t < ROUND_KEY_COUNT: |
Ke[t / BC][t % BC] = tk[j] |
Kd[ROUNDS - (t / BC)][t % BC] = tk[j] |
j += 1 |
t += 1 |
tt = 0 |
rconpointer = 0 |
while t < ROUND_KEY_COUNT: |
# extrapolate using phi (the round key evolution function) |
tt = tk[KC - 1] |
tk[0] ^= (S[(tt >> 16) & 0xFF] & 0xFF) << 24 ^ \ |
(S[(tt >> 8) & 0xFF] & 0xFF) << 16 ^ \ |
(S[ tt & 0xFF] & 0xFF) << 8 ^ \ |
(S[(tt >> 24) & 0xFF] & 0xFF) ^ \ |
(rcon[rconpointer] & 0xFF) << 24 |
rconpointer += 1 |
if KC != 8: |
for i in xrange(1, KC): |
tk[i] ^= tk[i-1] |
else: |
for i in xrange(1, KC / 2): |
tk[i] ^= tk[i-1] |
tt = tk[KC / 2 - 1] |
tk[KC / 2] ^= (S[ tt & 0xFF] & 0xFF) ^ \ |
(S[(tt >> 8) & 0xFF] & 0xFF) << 8 ^ \ |
(S[(tt >> 16) & 0xFF] & 0xFF) << 16 ^ \ |
(S[(tt >> 24) & 0xFF] & 0xFF) << 24 |
for i in xrange(KC / 2 + 1, KC): |
tk[i] ^= tk[i-1] |
# copy values into round key arrays |
j = 0 |
while j < KC and t < ROUND_KEY_COUNT: |
Ke[t / BC][t % BC] = tk[j] |
Kd[ROUNDS - (t / BC)][t % BC] = tk[j] |
j += 1 |
t += 1 |
# inverse MixColumn where needed |
for r in xrange(1, ROUNDS): |
for j in xrange(BC): |
tt = Kd[r][j] |
Kd[r][j] = U1[(tt >> 24) & 0xFF] ^ \ |
U2[(tt >> 16) & 0xFF] ^ \ |
U3[(tt >> 8) & 0xFF] ^ \ |
U4[ tt & 0xFF] |
self.Ke = Ke |
self.Kd = Kd |
def encrypt(self, plaintext): |
if len(plaintext) != self.block_size: |
raise ValueError('wrong block length, expected ' + str(self.block_size) + ' got ' + str(len(plaintext))) |
Ke = self.Ke |
BC = self.block_size / 4 |
ROUNDS = len(Ke) - 1 |
if BC == 4: |
SC = 0 |
elif BC == 6: |
SC = 1 |
else: |
SC = 2 |
s1 = shifts[SC][1][0] |
s2 = shifts[SC][2][0] |
s3 = shifts[SC][3][0] |
a = [0] * BC |
# temporary work array |
t = [] |
# plaintext to ints + key |
for i in xrange(BC): |
t.append((ord(plaintext[i * 4 ]) << 24 | |
ord(plaintext[i * 4 + 1]) << 16 | |
ord(plaintext[i * 4 + 2]) << 8 | |
ord(plaintext[i * 4 + 3]) ) ^ Ke[0][i]) |
# apply round transforms |
for r in xrange(1, ROUNDS): |
for i in xrange(BC): |
a[i] = (T1[(t[ i ] >> 24) & 0xFF] ^ |
T2[(t[(i + s1) % BC] >> 16) & 0xFF] ^ |
T3[(t[(i + s2) % BC] >> 8) & 0xFF] ^ |
T4[ t[(i + s3) % BC] & 0xFF] ) ^ Ke[r][i] |
t = copy.copy(a) |
# last round is special |
result = [] |
for i in xrange(BC): |
tt = Ke[ROUNDS][i] |
result.append((S[(t[ i ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF) |
result.append((S[(t[(i + s1) % BC] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF) |
result.append((S[(t[(i + s2) % BC] >> 8) & 0xFF] ^ (tt >> 8)) & 0xFF) |
result.append((S[ t[(i + s3) % BC] & 0xFF] ^ tt ) & 0xFF) |
return string.join(map(chr, result), '') |
def decrypt(self, ciphertext): |
if len(ciphertext) != self.block_size: |
raise ValueError('wrong block length, expected ' + str(self.block_size) + ' got ' + str(len(plaintext))) |
Kd = self.Kd |
BC = self.block_size / 4 |
ROUNDS = len(Kd) - 1 |
if BC == 4: |
SC = 0 |
elif BC == 6: |
SC = 1 |
else: |
SC = 2 |
s1 = shifts[SC][1][1] |
s2 = shifts[SC][2][1] |
s3 = shifts[SC][3][1] |
a = [0] * BC |
# temporary work array |
t = [0] * BC |
# ciphertext to ints + key |
for i in xrange(BC): |
t[i] = (ord(ciphertext[i * 4 ]) << 24 | |
ord(ciphertext[i * 4 + 1]) << 16 | |
ord(ciphertext[i * 4 + 2]) << 8 | |
ord(ciphertext[i * 4 + 3]) ) ^ Kd[0][i] |
# apply round transforms |
for r in xrange(1, ROUNDS): |
for i in xrange(BC): |
a[i] = (T5[(t[ i ] >> 24) & 0xFF] ^ |
T6[(t[(i + s1) % BC] >> 16) & 0xFF] ^ |
T7[(t[(i + s2) % BC] >> 8) & 0xFF] ^ |
T8[ t[(i + s3) % BC] & 0xFF] ) ^ Kd[r][i] |
t = copy.copy(a) |
# last round is special |
result = [] |
for i in xrange(BC): |
tt = Kd[ROUNDS][i] |
result.append((Si[(t[ i ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF) |
result.append((Si[(t[(i + s1) % BC] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF) |
result.append((Si[(t[(i + s2) % BC] >> 8) & 0xFF] ^ (tt >> 8)) & 0xFF) |
result.append((Si[ t[(i + s3) % BC] & 0xFF] ^ tt ) & 0xFF) |
return string.join(map(chr, result), '') |
def encrypt(key, block): |
return rijndael(key, len(block)).encrypt(block) |
def decrypt(key, block): |
return rijndael(key, len(block)).decrypt(block) |
def test(): |
def t(kl, bl): |
b = 'b' * bl |
r = rijndael('a' * kl, bl) |
assert r.decrypt(r.encrypt(b)) == b |
t(16, 16) |
t(16, 24) |
t(16, 32) |
t(24, 16) |
t(24, 24) |
t(24, 32) |
t(32, 16) |
t(32, 24) |
t(32, 32) |
/relevation/branches/1.1/python-cryptoplus/src/CryptoPlus/Cipher/python_Rijndael.py |
---|
0,0 → 1,107 |
from blockcipher import * |
from rijndael import rijndael |
def new(key,mode=MODE_ECB,IV=None,counter=None,segment_size=None,blocksize=None): |
"""Create a new cipher object |
Wrapper for pure python implementation rijndael.py |
key = raw string containing the key |
-> supported key size are 16, 24 and 32 bytes |
mode = python_Rijndael.MODE_ECB/CBC/CFB/OFB/CTR/XTS/CMAC, default is ECB |
-> for every mode, except ECB and CTR, it is important to construct a seperate cipher for encryption and decryption |
IV = IV as a raw string, default is "all zero" IV |
-> needed for CBC, CFB and OFB mode |
counter = counter object (CryptoPlus.Util.util.Counter) |
-> only needed for CTR mode |
-> use a seperate counter object for the cipher and decipher: the counter is updated directly, not a copy |
see CTR example further on in the docstring |
segment_size = amount of bits to use from the keystream in each chain part |
-> supported values: multiple of 8 between 8 and the blocksize |
of the cipher (only per byte access possible), default is 8 |
-> only needed for CFB mode |
blocksize = blocksize in bytes |
-> supported blocksizes are 16, 24 and 32 bytes, must be 16 if XTS mode. |
EXAMPLES: |
********** |
IMPORTING: |
----------- |
>>> from CryptoPlus.Cipher import python_Rijndael |
EXAMPLE: |
-------- |
24 byte block, 32 byte key (http://fp.gladman.plus.com/cryptography_technology/rijndael/) |
>>> key = '2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da56a784d9045190cfe'.decode('hex') |
>>> plaintext ='3243f6a8885a308d313198a2e03707344a4093822299f31d'.decode('hex') |
>>> cipher = python_Rijndael.new(key,python_Rijndael.MODE_ECB,blocksize=24) |
>>> cipher.encrypt(plaintext).encode('hex') |
'0ebacf199e3315c2e34b24fcc7c46ef4388aa475d66c194c' |
CBC EXAMPLE (plaintext = 3 blocksizes) (AES): |
----------------------------------------- |
>>> key = ('2b7e151628aed2a6abf7158809cf4f3c').decode('hex') |
>>> IV = ('000102030405060708090a0b0c0d0e0f').decode('hex') |
>>> plaintext1 = ('6bc1bee22e409f96e93d7e117393172a').decode('hex') |
>>> plaintext2 = ('ae2d8a571e03ac9c9eb76fac45af8e51').decode('hex') |
>>> plaintext3 = ('30c81c46a35ce411e5fbc1191a0a52ef').decode('hex') |
>>> cipher = python_Rijndael.new(key,python_Rijndael.MODE_CBC,IV,blocksize=16) |
>>> ciphertext = cipher.encrypt(plaintext1 + plaintext2 + plaintext3) |
>>> (ciphertext).encode('hex') |
'7649abac8119b246cee98e9b12e9197d5086cb9b507219ee95db113a917678b273bed6b8e3c1743b7116e69e22229516' |
>>> decipher = python_Rijndael.new(key,python_Rijndael.MODE_CBC,IV,blocksize=16) |
>>> plaintext = decipher.decrypt(ciphertext) |
>>> (plaintext).encode('hex') |
'6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52ef' |
XTS EXAMPLE: |
------------ |
(Examples for XTS-AES) |
XTS-AES-128 applied for a data unit of 512 bytes |
testvector: http://grouper.ieee.org/groups/1619/email/pdf00086.pdf |
>>> key = ('27182818284590452353602874713526'.decode('hex'),'31415926535897932384626433832795'.decode('hex')) |
>>> plaintext = '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff'.decode('hex') |
>>> cipher = python_Rijndael.new(key,python_Rijndael.MODE_XTS,blocksize=16) |
>>> ciphertext = cipher.encrypt(plaintext) |
>>> ciphertext.encode('hex') |
'27a7479befa1d476489f308cd4cfa6e2a96e4bbe3208ff25287dd3819616e89cc78cf7f5e543445f8333d8fa7f56000005279fa5d8b5e4ad40e736ddb4d35412328063fd2aab53e5ea1e0a9f332500a5df9487d07a5c92cc512c8866c7e860ce93fdf166a24912b422976146ae20ce846bb7dc9ba94a767aaef20c0d61ad02655ea92dc4c4e41a8952c651d33174be51a10c421110e6d81588ede82103a252d8a750e8768defffed9122810aaeb99f9172af82b604dc4b8e51bcb08235a6f4341332e4ca60482a4ba1a03b3e65008fc5da76b70bf1690db4eae29c5f1badd03c5ccf2a55d705ddcd86d449511ceb7ec30bf12b1fa35b913f9f747a8afd1b130e94bff94effd01a91735ca1726acd0b197c4e5b03393697e126826fb6bbde8ecc1e08298516e2c9ed03ff3c1b7860f6de76d4cecd94c8119855ef5297ca67e9f3e7ff72b1e99785ca0a7e7720c5b36dc6d72cac9574c8cbbc2f801e23e56fd344b07f22154beba0f08ce8891e643ed995c94d9a69c9f1b5f499027a78572aeebd74d20cc39881c213ee770b1010e4bea718846977ae119f7a023ab58cca0ad752afe656bb3c17256a9f6e9bf19fdd5a38fc82bbe872c5539edb609ef4f79c203ebb140f2e583cb2ad15b4aa5b655016a8449277dbd477ef2c8d6c017db738b18deb4a427d1923ce3ff262735779a418f20a282df920147beabe421ee5319d0568' |
>>> decipher = python_Rijndael.new(key,python_Rijndael.MODE_XTS,blocksize=16) |
>>> decipher.decrypt(ciphertext).encode('hex') |
'000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff' |
using data sequence number n |
>>> key = ('fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0'.decode('hex'),'22222222222222222222222222222222'.decode('hex')) |
>>> plain ='4444444444444444444444444444444444444444444444444444444444444444'.decode('hex') |
>>> n = '3333333333'.decode('hex') |
>>> cipher = python_Rijndael.new(key,python_Rijndael.MODE_XTS,blocksize=16) |
>>> ciphertext = cipher.encrypt(plain,n) |
>>> ciphertext.encode('hex') |
'af85336b597afc1a900b2eb21ec949d292df4c047e0b21532186a5971a227a89' |
>>> decipher = python_Rijndael.new(key,python_Rijndael.MODE_XTS,blocksize=16) |
>>> decipher.decrypt(ciphertext,n).encode('hex') |
'4444444444444444444444444444444444444444444444444444444444444444' |
""" |
return python_Rijndael(key,mode,IV,counter,blocksize,segment_size) |
class python_Rijndael(BlockCipher): |
key_error_message = ("Key should be 128, 192 or 256 bits") |
def __init__(self,key,mode,IV,counter,blocksize,segment_size): |
if blocksize not in (16,24,32): |
raise ValueError("Blocksize should be 16, 24 or 32") |
cipher_module = rijndael |
args = {'block_size':blocksize} |
self.blocksize = blocksize |
BlockCipher.__init__(self,key,mode,IV,counter,cipher_module,segment_size,args) |
def keylen_valid(self,key): |
return len(key) in (16,24,32) |
def _test(): |
import doctest |
doctest.testmod() |
if __name__ == "__main__": |
_test() |
/relevation/branches/1.1/python-cryptoplus/src/CryptoPlus/Cipher/RC5.py |
---|
0,0 → 1,58 |
from blockcipher import * |
try: |
import Crypto.Cipher.RC5 |
except ImportError: |
print "Crypto.Cipher.RC5 isn't available. You're probably using the Debian pycrypto version. Install the original pycrypto for RC5." |
raise |
def new(key,mode=MODE_ECB,IV=None,counter=None,segment_size=None,rounds=12,word_size=32): |
"""Create a new cipher object |
RC5 using pycrypto for algo and pycryptoplus for ciphermode |
key = raw string containing the keys |
multiple of 8 bits between 0 <-> 2040 bits |
mode = python_AES.MODE_ECB/CBC/CFB/OFB/CTR/CMAC, default is ECB |
IV = IV as a raw string, default is "all zero" IV |
-> only needed for CBC mode |
counter = counter object (CryptoPlus.Util.util.Counter) |
-> only needed for CTR mode |
segment_size = amount of bits to use from the keystream in each chain part |
-> supported values: multiple of 8 between 8 and the blocksize |
of the cipher (only per byte access possible), default is 8 |
-> only needed for CFB mode |
rounds = amount of rounds, default = 12 |
minimum 12 and multiple of 2 |
word_size = RC5 word size (bits), supported = 16 and 32, default = 32 |
RC5 encrypts blocks of size 2*word_size |
EXAMPLES: |
********** |
IMPORTING: |
----------- |
>>> from CryptoPlus.Cipher import RC5 |
https://www.cosic.esat.kuleuven.be/nessie/testvectors/ |
----------------------------------------- |
>>> key = "00000000000000000000000000000000".decode('hex') |
>>> plaintext = "0000000000000000".decode('hex') |
>>> rounds = 12 |
>>> cipher = RC5.new(key,RC5.MODE_ECB,rounds=rounds) |
>>> cipher.encrypt(plaintext).encode('hex') |
'21a5dbee154b8f6d' |
""" |
return RC5(key,mode,IV,counter,rounds,word_size,segment_size) |
class RC5(BlockCipher): |
def __init__(self,key,mode,IV,counter,rounds,word_size,segment_size): |
cipher_module = Crypto.Cipher.RC5.new |
args = {'rounds':rounds,'word_size':word_size} |
self.blocksize = (2*word_size)/8 |
BlockCipher.__init__(self,key,mode,IV,counter,cipher_module,segment_size,args) |
def _test(): |
import doctest |
doctest.testmod() |
if __name__ == "__main__": |
_test() |
/relevation/branches/1.1/python-cryptoplus/src/CryptoPlus/Cipher/pypresent.py |
---|
0,0 → 1,229 |
# Python PRESENT implementation |
# Version: 1.0 |
# Date: 13/10/2008 |
# |
# ============================================================================= |
# Copyright (c) 2008 Christophe Oosterlynck <christophe.oosterlynck_AT_gmail.com> |
# & NXP ( Philippe Teuwen <philippe.teuwen_AT_nxp.com> ) |
# |
# Permission is hereby granted, free of charge, to any person obtaining a copy |
# of this software and associated documentation files (the "Software"), to deal |
# in the Software without restriction, including without limitation the rights |
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
# copies of the Software, and to permit persons to whom the Software is |
# furnished to do so, subject to the following conditions: |
# |
# The above copyright notice and this permission notice shall be included in |
# all copies or substantial portions of the Software. |
# |
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
# THE SOFTWARE. |
# ============================================================================= |
""" PRESENT block cipher implementation |
USAGE EXAMPLE: |
--------------- |
Importing: |
----------- |
>>> from pypresent import Present |
Encrypting with a 80-bit key: |
------------------------------ |
>>> key = "00000000000000000000".decode('hex') |
>>> plain = "0000000000000000".decode('hex') |
>>> cipher = Present(key) |
>>> encrypted = cipher.encrypt(plain) |
>>> encrypted.encode('hex') |
'5579c1387b228445' |
>>> decrypted = cipher.decrypt(encrypted) |
>>> decrypted.encode('hex') |
'0000000000000000' |
Encrypting with a 128-bit key: |
------------------------------- |
>>> key = "0123456789abcdef0123456789abcdef".decode('hex') |
>>> plain = "0123456789abcdef".decode('hex') |
>>> cipher = Present(key) |
>>> encrypted = cipher.encrypt(plain) |
>>> encrypted.encode('hex') |
'0e9d28685e671dd6' |
>>> decrypted = cipher.decrypt(encrypted) |
>>> decrypted.encode('hex') |
'0123456789abcdef' |
fully based on standard specifications: http://www.crypto.ruhr-uni-bochum.de/imperia/md/content/texte/publications/conferences/present_ches2007.pdf |
test vectors: http://www.crypto.ruhr-uni-bochum.de/imperia/md/content/texte/publications/conferences/slides/present_testvectors.zip |
""" |
class Present: |
def __init__(self,key,rounds=32): |
"""Create a PRESENT cipher object |
key: the key as a 128-bit or 80-bit rawstring |
rounds: the number of rounds as an integer, 32 by default |
""" |
self.rounds = rounds |
if len(key) * 8 == 80: |
self.roundkeys = generateRoundkeys80(string2number(key),self.rounds) |
elif len(key) * 8 == 128: |
self.roundkeys = generateRoundkeys128(string2number(key),self.rounds) |
else: |
raise ValueError, "Key must be a 128-bit or 80-bit rawstring" |
def encrypt(self,block): |
"""Encrypt 1 block (8 bytes) |
Input: plaintext block as raw string |
Output: ciphertext block as raw string |
""" |
state = string2number(block) |
for i in xrange (self.rounds-1): |
state = addRoundKey(state,self.roundkeys[i]) |
state = sBoxLayer(state) |
state = pLayer(state) |
cipher = addRoundKey(state,self.roundkeys[-1]) |
return number2string_N(cipher,8) |
def decrypt(self,block): |
"""Decrypt 1 block (8 bytes) |
Input: ciphertext block as raw string |
Output: plaintext block as raw string |
""" |
state = string2number(block) |
for i in xrange (self.rounds-1): |
state = addRoundKey(state,self.roundkeys[-i-1]) |
state = pLayer_dec(state) |
state = sBoxLayer_dec(state) |
decipher = addRoundKey(state,self.roundkeys[0]) |
return number2string_N(decipher,8) |
def get_block_size(self): |
return 8 |
# 0 1 2 3 4 5 6 7 8 9 a b c d e f |
Sbox= [0xc,0x5,0x6,0xb,0x9,0x0,0xa,0xd,0x3,0xe,0xf,0x8,0x4,0x7,0x1,0x2] |
Sbox_inv = [Sbox.index(x) for x in xrange(16)] |
PBox = [0,16,32,48,1,17,33,49,2,18,34,50,3,19,35,51, |
4,20,36,52,5,21,37,53,6,22,38,54,7,23,39,55, |
8,24,40,56,9,25,41,57,10,26,42,58,11,27,43,59, |
12,28,44,60,13,29,45,61,14,30,46,62,15,31,47,63] |
PBox_inv = [PBox.index(x) for x in xrange(64)] |
def generateRoundkeys80(key,rounds): |
"""Generate the roundkeys for a 80-bit key |
Input: |
key: the key as a 80-bit integer |
rounds: the number of rounds as an integer |
Output: list of 64-bit roundkeys as integers""" |
roundkeys = [] |
for i in xrange(1,rounds+1): # (K1 ... K32) |
# rawkey: used in comments to show what happens at bitlevel |
# rawKey[0:64] |
roundkeys.append(key >>16) |
#1. Shift |
#rawKey[19:len(rawKey)]+rawKey[0:19] |
key = ((key & (2**19-1)) << 61) + (key >> 19) |
#2. SBox |
#rawKey[76:80] = S(rawKey[76:80]) |
key = (Sbox[key >> 76] << 76)+(key & (2**76-1)) |
#3. Salt |
#rawKey[15:20] ^ i |
key ^= i << 15 |
return roundkeys |
def generateRoundkeys128(key,rounds): |
"""Generate the roundkeys for a 128-bit key |
Input: |
key: the key as a 128-bit integer |
rounds: the number of rounds as an integer |
Output: list of 64-bit roundkeys as integers""" |
roundkeys = [] |
for i in xrange(1,rounds+1): # (K1 ... K32) |
# rawkey: used in comments to show what happens at bitlevel |
roundkeys.append(key >>64) |
#1. Shift |
key = ((key & (2**67-1)) << 61) + (key >> 67) |
#2. SBox |
key = (Sbox[key >> 124] << 124)+(Sbox[(key >> 120) & 0xF] << 120)+(key & (2**120-1)) |
#3. Salt |
#rawKey[62:67] ^ i |
key ^= i << 62 |
return roundkeys |
def addRoundKey(state,roundkey): |
return state ^ roundkey |
def sBoxLayer(state): |
"""SBox function for encryption |
Input: 64-bit integer |
Output: 64-bit integer""" |
output = 0 |
for i in xrange(16): |
output += Sbox[( state >> (i*4)) & 0xF] << (i*4) |
return output |
def sBoxLayer_dec(state): |
"""Inverse SBox function for decryption |
Input: 64-bit integer |
Output: 64-bit integer""" |
output = 0 |
for i in xrange(16): |
output += Sbox_inv[( state >> (i*4)) & 0xF] << (i*4) |
return output |
def pLayer(state): |
"""Permutation layer for encryption |
Input: 64-bit integer |
Output: 64-bit integer""" |
output = 0 |
for i in xrange(64): |
output += ((state >> i) & 0x01) << PBox[i] |
return output |
def pLayer_dec(state): |
"""Permutation layer for decryption |
Input: 64-bit integer |
Output: 64-bit integer""" |
output = 0 |
for i in xrange(64): |
output += ((state >> i) & 0x01) << PBox_inv[i] |
return output |
def string2number(i): |
""" Convert a string to a number |
Input: string (big-endian) |
Output: long or integer |
""" |
return int(i.encode('hex'),16) |
def number2string_N(i, N): |
"""Convert a number to a string of fixed size |
i: long or integer |
N: length of string |
Output: string (big-endian) |
""" |
s = '%0*x' % (N*2, i) |
return s.decode('hex') |
def _test(): |
import doctest |
doctest.testmod() |
if __name__ == "__main__": |
_test() |
/relevation/branches/1.1/python-cryptoplus/src/CryptoPlus/Cipher/pyserpent.py |
---|
0,0 → 1,1354 |
#!/usr/local/bin/python |
# $Id: serpref.py,v 1.19 1998/09/02 21:28:02 fms Exp $ |
# |
# Python reference implementation of Serpent. |
# |
# Written by Frank Stajano, |
# Olivetti Oracle Research Laboratory <http://www.orl.co.uk/~fms/> and |
# Cambridge University Computer Laboratory <http://www.cl.cam.ac.uk/~fms27/>. |
# |
# (c) 1998 Olivetti Oracle Research Laboratory (ORL) |
# |
# Original (Python) Serpent reference development started on 1998 02 12. |
# C implementation development started on 1998 03 04. |
# |
# Serpent cipher invented by Ross Anderson, Eli Biham, Lars Knudsen. |
# Serpent is a candidate for the Advanced Encryption Standard. |
# -------------------------------------------------------------- |
"""This is an illustrative reference implementation of the Serpent cipher |
invented by Eli Biham, Ross Anderson, Lars Knudsen. It is written for the |
human reader more than for the machine and, as such, it is optimised for |
clarity rather than speed. ("Premature optimisation is the root of all |
evil.") |
It can print out all the intermediate results (such as the subkeys) for a |
given input and key so that implementers debugging erroneous code can |
quickly verify which one of the building blocks is giving the wrong |
answers. |
This version implements Serpent-1, i.e. the variant defined in the final |
submission to NIST. |
""" |
# -------------------------------------------------------------- |
# My own additions |
# -------------------------------------------------------------- |
class Serpent: |
#class to |
def __init__(self,key): |
key = key.encode('hex') |
bitsInKey = keyLengthInBitsOf(key) |
rawKey = convertToBitstring(reverse(key.lower()), bitsInKey) |
self.userKey = makeLongKey(rawKey) |
def encrypt(self,block): |
plainText = convertToBitstring(reverse(block.encode("hex").lower()), 128) |
cipherText = encrypt(plainText, self.userKey) |
return reverse(bitstring2hexstring(cipherText)).decode('hex') |
def decrypt(self,block): |
cipherText = convertToBitstring(reverse(block.encode("hex").lower()), 128) |
plainText = decrypt(cipherText, self.userKey) |
return reverse(bitstring2hexstring(plainText)).decode('hex') |
def get_block_size(self): |
return 16 |
def reverse(toreverse): |
out = "" |
for i in range(len(toreverse)/2): |
out += toreverse[len(toreverse)-i*2-2:len(toreverse)-i*2] |
return out |
# -------------------------------------------------------------- |
# |
# -------------------------------------------------------------- |
# -------------------------------------------------------------- |
# Requires python 1.5, freely available from http://www.python.org/ |
# -------------------------------------------------------------- |
import string |
import sys |
import getopt |
import re |
# -------------------------------------------------------------- |
# Functions used in the formal description of the cipher |
def S(box, input): |
"""Apply S-box number 'box' to 4-bit bitstring 'input' and return a |
4-bit bitstring as the result.""" |
return SBoxBitstring[box%8][input] |
# There used to be 32 different S-boxes in serpent-0. Now there are |
# only 8, each of which is used 4 times (Sboxes 8, 16, 24 are all |
# identical to Sbox 0, etc). Hence the %8. |
def SInverse(box, output): |
"""Apply S-box number 'box' in reverse to 4-bit bitstring 'output' and |
return a 4-bit bitstring (the input) as the result.""" |
return SBoxBitstringInverse[box%8][output] |
def SHat(box, input): |
"""Apply a parallel array of 32 copies of S-box number 'box' to the |
128-bit bitstring 'input' and return a 128-bit bitstring as the |
result.""" |
result = "" |
for i in range(32): |
result = result + S(box, input[4*i:4*(i+1)]) |
return result |
def SHatInverse(box, output): |
"""Apply, in reverse, a parallel array of 32 copies of S-box number |
'box' to the 128-bit bitstring 'output' and return a 128-bit bitstring |
(the input) as the result.""" |
result = "" |
for i in range(32): |
result = result + SInverse(box, output[4*i:4*(i+1)]) |
return result |
def SBitslice(box, words): |
"""Take 'words', a list of 4 32-bit bitstrings, least significant word |
first. Return a similar list of 4 32-bit bitstrings obtained as |
follows. For each bit position from 0 to 31, apply S-box number 'box' |
to the 4 input bits coming from the current position in each of the |
items in 'words'; and put the 4 output bits in the corresponding |
positions in the output words.""" |
result = ["", "", "", ""] |
for i in range(32): # ideally in parallel |
quad = S(box, words[0][i] + words[1][i] + words[2][i] + words[3][i]) |
for j in range(4): |
result[j] = result[j] + quad[j] |
return result |
def SBitsliceInverse(box, words): |
"""Take 'words', a list of 4 32-bit bitstrings, least significant word |
first. Return a similar list of 4 32-bit bitstrings obtained as |
follows. For each bit position from 0 to 31, apply S-box number 'box' |
in reverse to the 4 output bits coming from the current position in |
each of the items in the supplied 'words'; and put the 4 input bits in |
the corresponding positions in the returned words.""" |
result = ["", "", "", ""] |
for i in range(32): # ideally in parallel |
quad = SInverse( |
box, words[0][i] + words[1][i] + words[2][i] + words[3][i]) |
for j in range(4): |
result[j] = result[j] + quad[j] |
return result |
def LT(input): |
"""Apply the table-based version of the linear transformation to the |
128-bit string 'input' and return a 128-bit string as the result.""" |
if len(input) != 128: |
raise ValueError, "input to LT is not 128 bit long" |
result = "" |
for i in range(len(LTTable)): |
outputBit = "0" |
for j in LTTable[i]: |
outputBit = xor(outputBit, input[j]) |
result = result + outputBit |
return result |
def LTInverse(output): |
"""Apply the table-based version of the inverse of the linear |
transformation to the 128-bit string 'output' and return a 128-bit |
string (the input) as the result.""" |
if len(output) != 128: |
raise ValueError, "input to inverse LT is not 128 bit long" |
result = "" |
for i in range(len(LTTableInverse)): |
inputBit = "0" |
for j in LTTableInverse[i]: |
inputBit = xor(inputBit, output[j]) |
result = result + inputBit |
return result |
def LTBitslice(X): |
"""Apply the equations-based version of the linear transformation to |
'X', a list of 4 32-bit bitstrings, least significant bitstring first, |
and return another list of 4 32-bit bitstrings as the result.""" |
X[0] = rotateLeft(X[0], 13) |
X[2] = rotateLeft(X[2], 3) |
X[1] = xor(X[1], X[0], X[2]) |
X[3] = xor(X[3], X[2], shiftLeft(X[0], 3)) |
X[1] = rotateLeft(X[1], 1) |
X[3] = rotateLeft(X[3], 7) |
X[0] = xor(X[0], X[1], X[3]) |
X[2] = xor(X[2], X[3], shiftLeft(X[1], 7)) |
X[0] = rotateLeft(X[0], 5) |
X[2] = rotateLeft(X[2], 22) |
return X |
def LTBitsliceInverse(X): |
"""Apply, in reverse, the equations-based version of the linear |
transformation to 'X', a list of 4 32-bit bitstrings, least significant |
bitstring first, and return another list of 4 32-bit bitstrings as the |
result.""" |
X[2] = rotateRight(X[2], 22) |
X[0] = rotateRight(X[0], 5) |
X[2] = xor(X[2], X[3], shiftLeft(X[1], 7)) |
X[0] = xor(X[0], X[1], X[3]) |
X[3] = rotateRight(X[3], 7) |
X[1] = rotateRight(X[1], 1) |
X[3] = xor(X[3], X[2], shiftLeft(X[0], 3)) |
X[1] = xor(X[1], X[0], X[2]) |
X[2] = rotateRight(X[2], 3) |
X[0] = rotateRight(X[0], 13) |
return X |
def IP(input): |
"""Apply the Initial Permutation to the 128-bit bitstring 'input' |
and return a 128-bit bitstring as the result.""" |
return applyPermutation(IPTable, input) |
def FP(input): |
"""Apply the Final Permutation to the 128-bit bitstring 'input' |
and return a 128-bit bitstring as the result.""" |
return applyPermutation(FPTable, input) |
def IPInverse(output): |
"""Apply the Initial Permutation in reverse.""" |
return FP(output) |
def FPInverse(output): |
"""Apply the Final Permutation in reverse.""" |
return IP(output) |
def applyPermutation(permutationTable, input): |
"""Apply the permutation specified by the 128-element list |
'permutationTable' to the 128-bit bitstring 'input' and return a |
128-bit bitstring as the result.""" |
if len(input) != len(permutationTable): |
raise ValueError, "input size (%d) doesn't match perm table size (%d)"\ |
% (len(input), len(permutationTable)) |
result = "" |
for i in range(len(permutationTable)): |
result = result + input[permutationTable[i]] |
return result |
def R(i, BHati, KHat): |
"""Apply round 'i' to the 128-bit bitstring 'BHati', returning another |
128-bit bitstring (conceptually BHatiPlus1). Do this using the |
appropriately numbered subkey(s) from the 'KHat' list of 33 128-bit |
bitstrings.""" |
#O.show("BHati", BHati, "(i=%2d) BHati" % i) |
xored = xor(BHati, KHat[i]) |
#O.show("xored", xored, "(i=%2d) xored" % i) |
SHati = SHat(i, xored) |
#O.show("SHati", SHati, "(i=%2d) SHati" % i) |
if 0 <= i <= r-2: |
BHatiPlus1 = LT(SHati) |
elif i == r-1: |
BHatiPlus1 = xor(SHati, KHat[r]) |
else: |
raise ValueError, "round %d is out of 0..%d range" % (i, r-1) |
#O.show("BHatiPlus1", BHatiPlus1, "(i=%2d) BHatiPlus1" % i) |
return BHatiPlus1 |
def RInverse(i, BHatiPlus1, KHat): |
"""Apply round 'i' in reverse to the 128-bit bitstring 'BHatiPlus1', |
returning another 128-bit bitstring (conceptually BHati). Do this using |
the appropriately numbered subkey(s) from the 'KHat' list of 33 128-bit |
bitstrings.""" |
#O.show("BHatiPlus1", BHatiPlus1, "(i=%2d) BHatiPlus1" % i) |
if 0 <= i <= r-2: |
SHati = LTInverse(BHatiPlus1) |
elif i == r-1: |
SHati = xor(BHatiPlus1, KHat[r]) |
else: |
raise ValueError, "round %d is out of 0..%d range" % (i, r-1) |
#O.show("SHati", SHati, "(i=%2d) SHati" % i) |
xored = SHatInverse(i, SHati) |
#O.show("xored", xored, "(i=%2d) xored" % i) |
BHati = xor(xored, KHat[i]) |
#O.show("BHati", BHati, "(i=%2d) BHati" % i) |
return BHati |
def RBitslice(i, Bi, K): |
"""Apply round 'i' (bitslice version) to the 128-bit bitstring 'Bi' and |
return another 128-bit bitstring (conceptually B i+1). Use the |
appropriately numbered subkey(s) from the 'K' list of 33 128-bit |
bitstrings.""" |
#O.show("Bi", Bi, "(i=%2d) Bi" % i) |
# 1. Key mixing |
xored = xor (Bi, K[i]) |
#O.show("xored", xored, "(i=%2d) xored" % i) |
# 2. S Boxes |
Si = SBitslice(i, quadSplit(xored)) |
# Input and output to SBitslice are both lists of 4 32-bit bitstrings |
#O.show("Si", Si, "(i=%2d) Si" % i, "tlb") |
# 3. Linear Transformation |
if i == r-1: |
# In the last round, replaced by an additional key mixing |
BiPlus1 = xor(quadJoin(Si), K[r]) |
else: |
BiPlus1 = quadJoin(LTBitslice(Si)) |
# BIPlus1 is a 128-bit bitstring |
#O.show("BiPlus1", BiPlus1, "(i=%2d) BiPlus1" % i) |
return BiPlus1 |
def RBitsliceInverse(i, BiPlus1, K): |
"""Apply the inverse of round 'i' (bitslice version) to the 128-bit |
bitstring 'BiPlus1' and return another 128-bit bitstring (conceptually |
B i). Use the appropriately numbered subkey(s) from the 'K' list of 33 |
128-bit bitstrings.""" |
#O.show("BiPlus1", BiPlus1, "(i=%2d) BiPlus1" % i) |
# 3. Linear Transformation |
if i == r-1: |
# In the last round, replaced by an additional key mixing |
Si = quadSplit(xor(BiPlus1, K[r])) |
else: |
Si = LTBitsliceInverse(quadSplit(BiPlus1)) |
# SOutput (same as LTInput) is a list of 4 32-bit bitstrings |
#O.show("Si", Si, "(i=%2d) Si" % i, "tlb") |
# 2. S Boxes |
xored = SBitsliceInverse(i, Si) |
# SInput and SOutput are both lists of 4 32-bit bitstrings |
#O.show("xored", xored, "(i=%2d) xored" % i) |
# 1. Key mixing |
Bi = xor (quadJoin(xored), K[i]) |
#O.show("Bi", Bi, "(i=%2d) Bi" % i) |
return Bi |
def encrypt(plainText, userKey): |
"""Encrypt the 128-bit bitstring 'plainText' with the 256-bit bitstring |
'userKey', using the normal algorithm, and return a 128-bit ciphertext |
bitstring.""" |
#O.show("fnTitle", "encrypt", None, "tu") |
#O.show("plainText", plainText, "plainText") |
#O.show("userKey", userKey, "userKey") |
K, KHat = makeSubkeys(userKey) |
BHat = IP(plainText) # BHat_0 at this stage |
for i in range(r): |
BHat = R(i, BHat, KHat) # Produce BHat_i+1 from BHat_i |
# BHat is now _32 i.e. _r |
C = FP(BHat) |
#O.show("cipherText", C, "cipherText") |
return C |
def encryptBitslice(plainText, userKey): |
"""Encrypt the 128-bit bitstring 'plainText' with the 256-bit bitstring |
'userKey', using the bitslice algorithm, and return a 128-bit ciphertext |
bitstring.""" |
#O.show("fnTitle", "encryptBitslice", None, "tu") |
#O.show("plainText", plainText, "plainText") |
#O.show("userKey", userKey, "userKey") |
K, KHat = makeSubkeys(userKey) |
B = plainText # B_0 at this stage |
for i in range(r): |
B = RBitslice(i, B, K) # Produce B_i+1 from B_i |
# B is now _r |
#O.show("cipherText", B, "cipherText") |
return B |
def decrypt(cipherText, userKey): |
"""Decrypt the 128-bit bitstring 'cipherText' with the 256-bit |
bitstring 'userKey', using the normal algorithm, and return a 128-bit |
plaintext bitstring.""" |
#O.show("fnTitle", "decrypt", None, "tu") |
#O.show("cipherText", cipherText, "cipherText") |
#O.show("userKey", userKey, "userKey") |
K, KHat = makeSubkeys(userKey) |
BHat = FPInverse(cipherText) # BHat_r at this stage |
for i in range(r-1, -1, -1): # from r-1 down to 0 included |
BHat = RInverse(i, BHat, KHat) # Produce BHat_i from BHat_i+1 |
# BHat is now _0 |
plainText = IPInverse(BHat) |
#O.show("plainText", plainText, "plainText") |
return plainText |
def decryptBitslice(cipherText, userKey): |
"""Decrypt the 128-bit bitstring 'cipherText' with the 256-bit |
bitstring 'userKey', using the bitslice algorithm, and return a 128-bit |
plaintext bitstring.""" |
#O.show("fnTitle", "decryptBitslice", None, "tu") |
#O.show("cipherText", cipherText, "cipherText") |
#O.show("userKey", userKey, "userKey") |
K, KHat = makeSubkeys(userKey) |
B = cipherText # B_r at this stage |
for i in range(r-1, -1, -1): # from r-1 down to 0 included |
B = RBitsliceInverse(i, B, K) # Produce B_i from B_i+1 |
# B is now _0 |
#O.show("plainText", B, "plainText") |
return B |
def makeSubkeys(userKey): |
"""Given the 256-bit bitstring 'userKey' (shown as K in the paper, but |
we can't use that name because of a collision with K[i] used later for |
something else), return two lists (conceptually K and KHat) of 33 |
128-bit bitstrings each.""" |
# Because in Python I can't index a list from anything other than 0, |
# I use a dictionary instead to legibly represent the w_i that are |
# indexed from -8. |
# We write the key as 8 32-bit words w-8 ... w-1 |
# ENOTE: w-8 is the least significant word |
w = {} |
for i in range(-8, 0): |
w[i] = userKey[(i+8)*32:(i+9)*32] |
#O.show("wi", w[i], "(i=%2d) wi" % i) |
# We expand these to a prekey w0 ... w131 with the affine recurrence |
for i in range(132): |
w[i] = rotateLeft( |
xor(w[i-8], w[i-5], w[i-3], w[i-1], |
bitstring(phi, 32), bitstring(i,32)), |
11) |
#O.show("wi", w[i], "(i=%2d) wi" % i) |
# The round keys are now calculated from the prekeys using the S-boxes |
# in bitslice mode. Each k[i] is a 32-bit bitstring. |
k = {} |
for i in range(r+1): |
whichS = (r + 3 - i) % r |
k[0+4*i] = "" |
k[1+4*i] = "" |
k[2+4*i] = "" |
k[3+4*i] = "" |
for j in range(32): # for every bit in the k and w words |
# ENOTE: w0 and k0 are the least significant words, w99 and k99 |
# the most. |
input = w[0+4*i][j] + w[1+4*i][j] + w[2+4*i][j] + w[3+4*i][j] |
output = S(whichS, input) |
for l in range(4): |
k[l+4*i] = k[l+4*i] + output[l] |
# We then renumber the 32 bit values k_j as 128 bit subkeys K_i. |
K = [] |
for i in range(33): |
# ENOTE: k4i is the least significant word, k4i+3 the most. |
K.append(k[4*i] + k[4*i+1] + k[4*i+2] + k[4*i+3]) |
# We now apply IP to the round key in order to place the key bits in |
# the correct column |
KHat = [] |
for i in range(33): |
KHat.append(IP(K[i])) |
#O.show("Ki", K[i], "(i=%2d) Ki" % i) |
#O.show("KHati", KHat[i], "(i=%2d) KHati" % i) |
return K, KHat |
def makeLongKey(k): |
"""Take a key k in bitstring format. Return the long version of that |
key.""" |
l = len(k) |
if l % 32 != 0 or l < 64 or l > 256: |
raise ValueError, "Invalid key length (%d bits)" % l |
if l == 256: |
return k |
else: |
return k + "1" + "0"*(256 -l -1) |
# -------------------------------------------------------------- |
# Generic bit-level primitives |
# Internally, we represent the numbers manipulated by the cipher in a |
# format that we call 'bitstring'. This is a string of "0" and "1" |
# characters containing the binary representation of the number in |
# little-endian format (so that subscripting with an index of i gives bit |
# number i, corresponding to a weight of 2^i). This representation is only |
# defined for nonnegative numbers (you can see why: think of the great |
# unnecessary mess that would result from sign extension, two's complement |
# and so on). Example: 10 decimal is "0101" in bitstring format. |
def bitstring(n, minlen=1): |
"""Translate n from integer to bitstring, padding it with 0s as |
necessary to reach the minimum length 'minlen'. 'n' must be >= 0 since |
the bitstring format is undefined for negative integers. Note that, |
while the bitstring format can represent arbitrarily large numbers, |
this is not so for Python's normal integer type: on a 32-bit machine, |
values of n >= 2^31 need to be expressed as python long integers or |
they will "look" negative and won't work. E.g. 0x80000000 needs to be |
passed in as 0x80000000L, or it will be taken as -2147483648 instead of |
+2147483648L. |
EXAMPLE: bitstring(10, 8) -> "01010000" |
""" |
if minlen < 1: |
raise ValueError, "a bitstring must have at least 1 char" |
if n < 0: |
raise ValueError, "bitstring representation undefined for neg numbers" |
result = "" |
while n > 0: |
if n & 1: |
result = result + "1" |
else: |
result = result + "0" |
n = n >> 1 |
if len(result) < minlen: |
result = result + "0" * (minlen - len(result)) |
return result |
def binaryXor(n1, n2): |
"""Return the xor of two bitstrings of equal length as another |
bitstring of the same length. |
EXAMPLE: binaryXor("10010", "00011") -> "10001" |
""" |
if len(n1) != len(n2): |
raise ValueError, "can't xor bitstrings of different " + \ |
"lengths (%d and %d)" % (len(n1), len(n2)) |
# We assume that they are genuine bitstrings instead of just random |
# character strings. |
result = "" |
for i in range(len(n1)): |
if n1[i] == n2[i]: |
result = result + "0" |
else: |
result = result + "1" |
return result |
def xor(*args): |
"""Return the xor of an arbitrary number of bitstrings of the same |
length as another bitstring of the same length. |
EXAMPLE: xor("01", "11", "10") -> "00" |
""" |
if args == []: |
raise ValueError, "at least one argument needed" |
result = args[0] |
for arg in args[1:]: |
result = binaryXor(result, arg) |
return result |
def rotateLeft(input, places): |
"""Take a bitstring 'input' of arbitrary length. Rotate it left by |
'places' places. Left means that the 'places' most significant bits are |
taken out and reinserted as the least significant bits. Note that, |
because the bitstring representation is little-endian, the visual |
effect is actually that of rotating the string to the right. |
EXAMPLE: rotateLeft("000111", 2) -> "110001" |
""" |
p = places % len(input) |
return input[-p:] + input[:-p] |
def rotateRight(input, places): |
return rotateLeft(input, -places) |
def shiftLeft(input, p): |
"""Take a bitstring 'input' of arbitrary length. Shift it left by 'p' |
places. Left means that the 'p' most significant bits are shifted out |
and dropped, while 'p' 0s are inserted in the the least significant |
bits. Note that, because the bitstring representation is little-endian, |
the visual effect is actually that of shifting the string to the |
right. Negative values for 'p' are allowed, with the effect of shifting |
right instead (i.e. the 0s are inserted in the most significant bits). |
EXAMPLE: shiftLeft("000111", 2) -> "000001" |
shiftLeft("000111", -2) -> "011100" |
""" |
if abs(p) >= len(input): |
# Everything gets shifted out anyway |
return "0" * len(input) |
if p < 0: |
# Shift right instead |
return input[-p:] + "0" * len(input[:-p]) |
elif p == 0: |
return input |
else: # p > 0, normal case |
return "0" * len(input[-p:]) + input[:-p] |
def shiftRight(input, p): |
"""Take a bitstring 'input' and shift it right by 'p' places. See the |
doc for shiftLeft for more details.""" |
return shiftLeft(input, -p) |
def keyLengthInBitsOf(k): |
"""Take a string k in I/O format and return the number of bits in it.""" |
return len(k) * 4 |
# -------------------------------------------------------------- |
# Hex conversion functions |
# For I/O we use BIG-ENDIAN hexstrings. Do not get confused: internal stuff |
# is LITTLE-ENDIAN bitstrings (so that digit i has weight 2^i) while |
# external stuff is in BIG-ENDIAN hexstrings (so that it's shorter and it |
# looks like the numbers you normally write down). The external (I/O) |
# representation is the same as used by the C reference implementation. |
bin2hex = { |
# Given a 4-char bitstring, return the corresponding 1-char hexstring |
"0000": "0", "1000": "1", "0100": "2", "1100": "3", |
"0010": "4", "1010": "5", "0110": "6", "1110": "7", |
"0001": "8", "1001": "9", "0101": "a", "1101": "b", |
"0011": "c", "1011": "d", "0111": "e", "1111": "f", |
} |
# Make the reverse lookup table too |
hex2bin = {} |
for (bin, hex) in bin2hex.items(): |
hex2bin[hex] = bin |
def bitstring2hexstring(b): |
"""Take bitstring 'b' and return the corresponding hexstring.""" |
result = "" |
l = len(b) |
if l % 4: |
b = b + "0" * (4-(l%4)) |
for i in range(0, len(b), 4): |
result = result+bin2hex[b[i:i+4]] |
return reverseString(result) |
def hexstring2bitstring(h): |
"""Take hexstring 'h' and return the corresponding bitstring.""" |
result = "" |
for c in reverseString(h): |
result = result + hex2bin[c] |
return result |
def reverseString(s): |
l = list(s) |
l.reverse() |
return string.join(l, "") |
# -------------------------------------------------------------- |
# Format conversions |
def quadSplit(b128): |
"""Take a 128-bit bitstring and return it as a list of 4 32-bit |
bitstrings, least significant bitstring first.""" |
if len(b128) != 128: |
raise ValueError, "must be 128 bits long, not " + len(b128) |
result = [] |
for i in range(4): |
result.append(b128[(i*32):(i+1)*32]) |
return result |
def quadJoin(l4x32): |
"""Take a list of 4 32-bit bitstrings and return it as a single 128-bit |
bitstring obtained by concatenating the internal ones.""" |
if len(l4x32) != 4: |
raise ValueError, "need a list of 4 bitstrings, not " + len(l4x32) |
return l4x32[0] + l4x32[1] + l4x32[2] + l4x32[3] |
# -------------------------------------------------- |
# Seeing what happens inside |
class Observer: |
"""An object of this class can selectively display the values of the |
variables you want to observe while the program is running. There are |
tags that you can switch on or off. You sprinkle show() statements |
throughout the program to show the value of a variable at a particular |
point: show() will display the relevant variable only if the |
corresponding tag is currently on. The special tag "ALL" forces all |
show() statements to display their variable.""" |
typesOfVariable = { |
"tu": "unknown", "tb": "bitstring", "tlb": "list of bitstrings",} |
def __init__(self, tags=[]): |
self.tags = {} |
for tag in tags: |
self.tags[tag] = 1 |
def addTag(self, *tags): |
"""Add the supplied tag(s) to those that are currently active, |
i.e. those that, if a corresponding "show()" is executed, will |
print something.""" |
for t in tags: |
self.tags[t] = 1 |
def removeTag(self, *tags): |
"""Remove the supplied tag(s) from those currently active.""" |
for t in tags: |
if t in self.tags.keys(): |
del self.tags[t] |
def show(self, tag, variable, label=None, type="tb"): |
"""Conditionally print a message with the current value of |
'variable'. The message will only be printed if the supplied 'tag' |
is among the active ones (or if the 'ALL' tag is active). The |
'label', if not null, is printed before the value of the |
'variable'; if it is null, it is substituted with the 'tag'. The |
'type' of the 'variable' (giving us a clue on how to print it) must |
be one of Observer.typesOfVariable.""" |
if label == None: |
label = tag |
if "ALL" in self.tags.keys() or tag in self.tags.keys(): |
if type == "tu": |
output = `variable` |
elif type == "tb": |
output = bitstring2hexstring(variable) |
elif type == "tlb": |
output = "" |
for item in variable: |
output = output + " %s" % bitstring2hexstring(item) |
output = "[" + output[1:] + "]" |
else: |
raise ValueError, "unknown type: %s. Valid ones are %s" % ( |
type, self.typesOfVariable.keys()) |
print label, |
if output: |
print "=", output |
else: |
# We make one global observer object that is always available |
O = Observer(["plainText", "userKey", "cipherText"]) |
# -------------------------------------------------------------- |
# Constants |
phi = 0x9e3779b9L |
r = 32 |
# -------------------------------------------------------------- |
# Data tables |
# Each element of this list corresponds to one S-box. Each S-box in turn is |
# a list of 16 integers in the range 0..15, without repetitions. Having the |
# value v (say, 14) in position p (say, 0) means that if the input to that |
# S-box is the pattern p (0, or 0x0) then the output will be the pattern v |
# (14, or 0xe). |
SBoxDecimalTable = [ |
[ 3, 8,15, 1,10, 6, 5,11,14,13, 4, 2, 7, 0, 9,12 ], # S0 |
[15,12, 2, 7, 9, 0, 5,10, 1,11,14, 8, 6,13, 3, 4 ], # S1 |
[ 8, 6, 7, 9, 3,12,10,15,13, 1,14, 4, 0,11, 5, 2 ], # S2 |
[ 0,15,11, 8,12, 9, 6, 3,13, 1, 2, 4,10, 7, 5,14 ], # S3 |
[ 1,15, 8, 3,12, 0,11, 6, 2, 5, 4,10, 9,14, 7,13 ], # S4 |
[15, 5, 2,11, 4,10, 9,12, 0, 3,14, 8,13, 6, 7, 1 ], # S5 |
[ 7, 2,12, 5, 8, 4, 6,11,14, 9, 1,15,13, 3,10, 0 ], # S6 |
[ 1,13,15, 0,14, 8, 2,11, 7, 4,12,10, 9, 3, 5, 6 ], # S7 |
] |
# NB: in serpent-0, this was a list of 32 sublists (for the 32 different |
# S-boxes derived from DES). In the final version of Serpent only 8 S-boxes |
# are used, with each one being reused 4 times. |
# Make another version of this table as a list of dictionaries: one |
# dictionary per S-box, where the value of the entry indexed by i tells you |
# the output configuration when the input is i, with both the index and the |
# value being bitstrings. Make also the inverse: another list of |
# dictionaries, one per S-box, where each dictionary gets the output of the |
# S-box as the key and gives you the input, with both values being 4-bit |
# bitstrings. |
SBoxBitstring = [] |
SBoxBitstringInverse = [] |
for line in SBoxDecimalTable: |
dict = {} |
inverseDict = {} |
for i in range(len(line)): |
index = bitstring(i, 4) |
value = bitstring(line[i], 4) |
dict[index] = value |
inverseDict[value] = index |
SBoxBitstring.append(dict) |
SBoxBitstringInverse.append(inverseDict) |
# The Initial and Final permutations are each represented by one list |
# containing the integers in 0..127 without repetitions. Having value v |
# (say, 32) at position p (say, 1) means that the output bit at position p |
# (1) comes from the input bit at position v (32). |
IPTable = [ |
0, 32, 64, 96, 1, 33, 65, 97, 2, 34, 66, 98, 3, 35, 67, 99, |
4, 36, 68, 100, 5, 37, 69, 101, 6, 38, 70, 102, 7, 39, 71, 103, |
8, 40, 72, 104, 9, 41, 73, 105, 10, 42, 74, 106, 11, 43, 75, 107, |
12, 44, 76, 108, 13, 45, 77, 109, 14, 46, 78, 110, 15, 47, 79, 111, |
16, 48, 80, 112, 17, 49, 81, 113, 18, 50, 82, 114, 19, 51, 83, 115, |
20, 52, 84, 116, 21, 53, 85, 117, 22, 54, 86, 118, 23, 55, 87, 119, |
24, 56, 88, 120, 25, 57, 89, 121, 26, 58, 90, 122, 27, 59, 91, 123, |
28, 60, 92, 124, 29, 61, 93, 125, 30, 62, 94, 126, 31, 63, 95, 127, |
] |
FPTable = [ |
0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, |
64, 68, 72, 76, 80, 84, 88, 92, 96, 100, 104, 108, 112, 116, 120, 124, |
1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61, |
65, 69, 73, 77, 81, 85, 89, 93, 97, 101, 105, 109, 113, 117, 121, 125, |
2, 6, 10, 14, 18, 22, 26, 30, 34, 38, 42, 46, 50, 54, 58, 62, |
66, 70, 74, 78, 82, 86, 90, 94, 98, 102, 106, 110, 114, 118, 122, 126, |
3, 7, 11, 15, 19, 23, 27, 31, 35, 39, 43, 47, 51, 55, 59, 63, |
67, 71, 75, 79, 83, 87, 91, 95, 99, 103, 107, 111, 115, 119, 123, 127, |
] |
# The Linear Transformation is represented as a list of 128 lists, one for |
# each output bit. Each one of the 128 lists is composed of a variable |
# number of integers in 0..127 specifying the positions of the input bits |
# that must be XORed together (say, 72, 144 and 125) to yield the output |
# bit corresponding to the position of that list (say, 1). |
LTTable = [ |
[16, 52, 56, 70, 83, 94, 105], |
[72, 114, 125], |
[2, 9, 15, 30, 76, 84, 126], |
[36, 90, 103], |
[20, 56, 60, 74, 87, 98, 109], |
[1, 76, 118], |
[2, 6, 13, 19, 34, 80, 88], |
[40, 94, 107], |
[24, 60, 64, 78, 91, 102, 113], |
[5, 80, 122], |
[6, 10, 17, 23, 38, 84, 92], |
[44, 98, 111], |
[28, 64, 68, 82, 95, 106, 117], |
[9, 84, 126], |
[10, 14, 21, 27, 42, 88, 96], |
[48, 102, 115], |
[32, 68, 72, 86, 99, 110, 121], |
[2, 13, 88], |
[14, 18, 25, 31, 46, 92, 100], |
[52, 106, 119], |
[36, 72, 76, 90, 103, 114, 125], |
[6, 17, 92], |
[18, 22, 29, 35, 50, 96, 104], |
[56, 110, 123], |
[1, 40, 76, 80, 94, 107, 118], |
[10, 21, 96], |
[22, 26, 33, 39, 54, 100, 108], |
[60, 114, 127], |
[5, 44, 80, 84, 98, 111, 122], |
[14, 25, 100], |
[26, 30, 37, 43, 58, 104, 112], |
[3, 118], |
[9, 48, 84, 88, 102, 115, 126], |
[18, 29, 104], |
[30, 34, 41, 47, 62, 108, 116], |
[7, 122], |
[2, 13, 52, 88, 92, 106, 119], |
[22, 33, 108], |
[34, 38, 45, 51, 66, 112, 120], |
[11, 126], |
[6, 17, 56, 92, 96, 110, 123], |
[26, 37, 112], |
[38, 42, 49, 55, 70, 116, 124], |
[2, 15, 76], |
[10, 21, 60, 96, 100, 114, 127], |
[30, 41, 116], |
[0, 42, 46, 53, 59, 74, 120], |
[6, 19, 80], |
[3, 14, 25, 100, 104, 118], |
[34, 45, 120], |
[4, 46, 50, 57, 63, 78, 124], |
[10, 23, 84], |
[7, 18, 29, 104, 108, 122], |
[38, 49, 124], |
[0, 8, 50, 54, 61, 67, 82], |
[14, 27, 88], |
[11, 22, 33, 108, 112, 126], |
[0, 42, 53], |
[4, 12, 54, 58, 65, 71, 86], |
[18, 31, 92], |
[2, 15, 26, 37, 76, 112, 116], |
[4, 46, 57], |
[8, 16, 58, 62, 69, 75, 90], |
[22, 35, 96], |
[6, 19, 30, 41, 80, 116, 120], |
[8, 50, 61], |
[12, 20, 62, 66, 73, 79, 94], |
[26, 39, 100], |
[10, 23, 34, 45, 84, 120, 124], |
[12, 54, 65], |
[16, 24, 66, 70, 77, 83, 98], |
[30, 43, 104], |
[0, 14, 27, 38, 49, 88, 124], |
[16, 58, 69], |
[20, 28, 70, 74, 81, 87, 102], |
[34, 47, 108], |
[0, 4, 18, 31, 42, 53, 92], |
[20, 62, 73], |
[24, 32, 74, 78, 85, 91, 106], |
[38, 51, 112], |
[4, 8, 22, 35, 46, 57, 96], |
[24, 66, 77], |
[28, 36, 78, 82, 89, 95, 110], |
[42, 55, 116], |
[8, 12, 26, 39, 50, 61, 100], |
[28, 70, 81], |
[32, 40, 82, 86, 93, 99, 114], |
[46, 59, 120], |
[12, 16, 30, 43, 54, 65, 104], |
[32, 74, 85], |
[36, 90, 103, 118], |
[50, 63, 124], |
[16, 20, 34, 47, 58, 69, 108], |
[36, 78, 89], |
[40, 94, 107, 122], |
[0, 54, 67], |
[20, 24, 38, 51, 62, 73, 112], |
[40, 82, 93], |
[44, 98, 111, 126], |
[4, 58, 71], |
[24, 28, 42, 55, 66, 77, 116], |
[44, 86, 97], |
[2, 48, 102, 115], |
[8, 62, 75], |
[28, 32, 46, 59, 70, 81, 120], |
[48, 90, 101], |
[6, 52, 106, 119], |
[12, 66, 79], |
[32, 36, 50, 63, 74, 85, 124], |
[52, 94, 105], |
[10, 56, 110, 123], |
[16, 70, 83], |
[0, 36, 40, 54, 67, 78, 89], |
[56, 98, 109], |
[14, 60, 114, 127], |
[20, 74, 87], |
[4, 40, 44, 58, 71, 82, 93], |
[60, 102, 113], |
[3, 18, 72, 114, 118, 125], |
[24, 78, 91], |
[8, 44, 48, 62, 75, 86, 97], |
[64, 106, 117], |
[1, 7, 22, 76, 118, 122], |
[28, 82, 95], |
[12, 48, 52, 66, 79, 90, 101], |
[68, 110, 121], |
[5, 11, 26, 80, 122, 126], |
[32, 86, 99], |
] |
# The following table is necessary for the non-bitslice decryption. |
LTTableInverse = [ |
[53, 55, 72], |
[1, 5, 20, 90], |
[15, 102], |
[3, 31, 90], |
[57, 59, 76], |
[5, 9, 24, 94], |
[19, 106], |
[7, 35, 94], |
[61, 63, 80], |
[9, 13, 28, 98], |
[23, 110], |
[11, 39, 98], |
[65, 67, 84], |
[13, 17, 32, 102], |
[27, 114], |
[1, 3, 15, 20, 43, 102], |
[69, 71, 88], |
[17, 21, 36, 106], |
[1, 31, 118], |
[5, 7, 19, 24, 47, 106], |
[73, 75, 92], |
[21, 25, 40, 110], |
[5, 35, 122], |
[9, 11, 23, 28, 51, 110], |
[77, 79, 96], |
[25, 29, 44, 114], |
[9, 39, 126], |
[13, 15, 27, 32, 55, 114], |
[81, 83, 100], |
[1, 29, 33, 48, 118], |
[2, 13, 43], |
[1, 17, 19, 31, 36, 59, 118], |
[85, 87, 104], |
[5, 33, 37, 52, 122], |
[6, 17, 47], |
[5, 21, 23, 35, 40, 63, 122], |
[89, 91, 108], |
[9, 37, 41, 56, 126], |
[10, 21, 51], |
[9, 25, 27, 39, 44, 67, 126], |
[93, 95, 112], |
[2, 13, 41, 45, 60], |
[14, 25, 55], |
[2, 13, 29, 31, 43, 48, 71], |
[97, 99, 116], |
[6, 17, 45, 49, 64], |
[18, 29, 59], |
[6, 17, 33, 35, 47, 52, 75], |
[101, 103, 120], |
[10, 21, 49, 53, 68], |
[22, 33, 63], |
[10, 21, 37, 39, 51, 56, 79], |
[105, 107, 124], |
[14, 25, 53, 57, 72], |
[26, 37, 67], |
[14, 25, 41, 43, 55, 60, 83], |
[0, 109, 111], |
[18, 29, 57, 61, 76], |
[30, 41, 71], |
[18, 29, 45, 47, 59, 64, 87], |
[4, 113, 115], |
[22, 33, 61, 65, 80], |
[34, 45, 75], |
[22, 33, 49, 51, 63, 68, 91], |
[8, 117, 119], |
[26, 37, 65, 69, 84], |
[38, 49, 79], |
[26, 37, 53, 55, 67, 72, 95], |
[12, 121, 123], |
[30, 41, 69, 73, 88], |
[42, 53, 83], |
[30, 41, 57, 59, 71, 76, 99], |
[16, 125, 127], |
[34, 45, 73, 77, 92], |
[46, 57, 87], |
[34, 45, 61, 63, 75, 80, 103], |
[1, 3, 20], |
[38, 49, 77, 81, 96], |
[50, 61, 91], |
[38, 49, 65, 67, 79, 84, 107], |
[5, 7, 24], |
[42, 53, 81, 85, 100], |
[54, 65, 95], |
[42, 53, 69, 71, 83, 88, 111], |
[9, 11, 28], |
[46, 57, 85, 89, 104], |
[58, 69, 99], |
[46, 57, 73, 75, 87, 92, 115], |
[13, 15, 32], |
[50, 61, 89, 93, 108], |
[62, 73, 103], |
[50, 61, 77, 79, 91, 96, 119], |
[17, 19, 36], |
[54, 65, 93, 97, 112], |
[66, 77, 107], |
[54, 65, 81, 83, 95, 100, 123], |
[21, 23, 40], |
[58, 69, 97, 101, 116], |
[70, 81, 111], |
[58, 69, 85, 87, 99, 104, 127], |
[25, 27, 44], |
[62, 73, 101, 105, 120], |
[74, 85, 115], |
[3, 62, 73, 89, 91, 103, 108], |
[29, 31, 48], |
[66, 77, 105, 109, 124], |
[78, 89, 119], |
[7, 66, 77, 93, 95, 107, 112], |
[33, 35, 52], |
[0, 70, 81, 109, 113], |
[82, 93, 123], |
[11, 70, 81, 97, 99, 111, 116], |
[37, 39, 56], |
[4, 74, 85, 113, 117], |
[86, 97, 127], |
[15, 74, 85, 101, 103, 115, 120], |
[41, 43, 60], |
[8, 78, 89, 117, 121], |
[3, 90], |
[19, 78, 89, 105, 107, 119, 124], |
[45, 47, 64], |
[12, 82, 93, 121, 125], |
[7, 94], |
[0, 23, 82, 93, 109, 111, 123], |
[49, 51, 68], |
[1, 16, 86, 97, 125], |
[11, 98], |
[4, 27, 86, 97, 113, 115, 127], |
] |
# -------------------------------------------------- |
# Handling command line arguments and stuff |
help = """ |
# $Id: serpref.py,v 1.19 1998/09/02 21:28:02 fms Exp $ |
# |
# Python reference implementation of Serpent. |
# |
# Written by Frank Stajano, |
# Olivetti Oracle Research Laboratory <http://www.orl.co.uk/~fms/> and |
# Cambridge University Computer Laboratory <http://www.cl.cam.ac.uk/~fms27/>. |
# |
# (c) 1998 Olivetti Oracle Research Laboratory (ORL) |
# |
# Original (Python) Serpent reference development started on 1998 02 12. |
# C implementation development started on 1998 03 04. |
# |
# Serpent cipher invented by Ross Anderson, Eli Biham, Lars Knudsen. |
# Serpent is a candidate for the Advanced Encryption Standard. |
Encrypts or decrypts one block of data using the Serpent cipher and |
optionally showing you what's going on inside at the various stages of |
the computation. |
SYNTAX: serpref mode [options] |
MODE is one of the following: |
-e -> encrypt |
-d -> decrypt |
-h -> help (the text you're reading right now) |
OPTIONS are: |
-p plainText -> The 128-bit value to be encrypted. Required in mode -e, |
ignored otherwise. Short texts are zeropadded. |
-c cipherText -> The 128-bit value to be decrypted. Required in mode -d, |
ignored otherwise. Short texts are zeropadded. |
-k key -> The value of the key (allowed lengths are from 64 to |
256 bits, but must be a multiple of 32 bits). Keys |
shorter than 256 bits are internally transformed into |
the equivalent long keys (NOT the same as zeropadding!). |
Required for -e and -d. |
-t tagName -> Turn on the observer tag with that name. This means that |
any observer messages associated with this tag will |
now be displayed. This option may be specified several |
times to add multiple tags. |
The special tag ALL turns on all the messages. |
-b -> Use the bitslice version instead of the traditional |
version, which is otherwise used by default. Optional. |
TAGS: |
These are the tags of the quantities you can currently observe with |
-t. Names are modelled on the paper's notation. |
For the non-bitslice: BHati xored SHati BHatiPlus1 wi KHati |
For the bitslice: Bi xored Si BiPlus1 wi Ki |
Generic: plainText userKey cipherText testTitle fnTitle |
I/O FORMAT: |
All I/O is performed using hex numbers of the appropriate size, written |
as sequences of hex digits, most significant digit first (big-endian), |
without any leading or trailing markers such as 0x, &, h or whatever. |
Example: the number ten is "a" in four bits or "000a" in sixteen bits. |
USAGE EXAMPLES: |
serpref -e -k 123456789abcdef -p 0 |
Encrypt the plaintext "all zeros" with the given key. |
serpref -e -b -k 123456789abcdef -p 0 |
Same as above, but the extra -b requests bitslice operation. As |
things are, we won't notice the difference, but see below... |
serpref -e -b -k 123456789abcdef -p 0 -t Bi |
Same as above, but the "-t Bi" prints out all the intermediate |
results with a tag of Bi, allowing you to see what happens inside |
the rounds. Compare this with the following... |
serpref -e -k 123456789abcdef -p 0 -t BHati |
Same as above except that we are back to the non-bitslice version |
(there is no -b) and we are printing the items with the BHati tag |
(which is the equivalent of Bi for the non-bitslice version). |
serpref -e -k 123456789abcdef -p 0 -t xored -t SHati -t BHati |
Same as above but we are requesting even more details, basically |
looking at all the intermediate results of each round as well. (You |
could use the single magic tag -t ALL if you didn't want to have to |
find out the names of the individual tags.) |
""" |
def helpExit(message = None): |
print help |
if message: |
print "ERROR:", message |
sys.exit() |
def convertToBitstring(input, numBits): |
"""Take a string 'input', theoretically in std I/O format, but in |
practice liable to contain any sort of crap since it's user supplied, |
and return its bitstring representation, normalised to numBits |
bits. Raise the appropriate variant of ValueError (with explanatory |
message) if anything can't be done (this includes the case where the |
'input', while otherwise syntactically correct, can't be represented in |
'numBits' bits).""" |
if re.match("^[0-9a-f]+$", input): |
bitstring = hexstring2bitstring(input) |
else: |
raise ValueError, "%s is not a valid hexstring" % input |
# assert: bitstring now contains the bitstring version of the input |
if len(bitstring) > numBits: |
# Last chance: maybe it's got some useless 0s... |
if re.match("^0+$", bitstring[numBits:]): |
bitstring = bitstring[:numBits] |
else: |
raise ValueError, "input too large to fit in %d bits" % numBits |
else: |
bitstring = bitstring + "0" * (numBits-len(bitstring)) |
return bitstring |
def main(): |
optList, rest = getopt.getopt(sys.argv[1:], "edhbt:k:p:c:") |
if rest: |
helpExit("Sorry, can't make sense of this: '%s'" % rest) |
# Transform the list of options into a more comfortable |
# dictionary. This only works with non-repeated options, though, so |
# tags (which are repeated) must be dealt with separately. |
options = {} |
for key, value in optList: |
if key == "-t": |
O.addTag(value) |
else: |
if key in options.keys(): |
helpExit("Multiple occurrences of " + key) |
else: |
options[string.strip(key)] = string.strip(value) |
# Not more than one mode |
mode = None |
for k in options.keys(): |
if k in ["-e", "-d", "-h"]: |
if mode: |
helpExit("you can only specify one mode") |
else: |
mode = k |
if not mode: |
helpExit("No mode specified") |
# Put plainText, userKey, cipherText in bitstring format. |
plainText = userKey = cipherText = None |
if options.has_key("-k"): |
bitsInKey = keyLengthInBitsOf(options["-k"]) |
rawKey = convertToBitstring(options["-k"], bitsInKey) |
userKey = makeLongKey(rawKey) |
if options.has_key("-p"): |
plainText = convertToBitstring(options["-p"], 128) |
if options.has_key("-c"): |
cipherText = convertToBitstring(options["-c"], 128) |
if mode == "-e" or mode == "-d": |
if not userKey: |
helpExit("-k (key) required with -e (encrypt) or -d (decrypt)") |
if mode == "-e": |
if not plainText: |
helpExit("-p (plaintext) is required when doing -e (encrypt)") |
if mode == "-d": |
if not cipherText: |
helpExit("-c (ciphertext) is required when doing -d (decrypt)") |
# Perform the action specified by the mode |
# NOTE that the observer will automatically print the basic stuff such |
# as plainText, userKey and cipherText (in the right format too), so we |
# only need to perform the action, without adding any extra print |
# statements here. |
if mode == "-e": |
if options.has_key("-b"): |
cipherText = encryptBitslice(plainText, userKey) |
else: |
cipherText = encrypt(plainText, userKey) |
elif mode == "-d": |
if options.has_key("-b"): |
plainText = decryptBitslice(cipherText, userKey) |
else: |
plainText = decrypt(cipherText, userKey) |
elif mode == "-s": |
O.addTag("testTitle", "fnTitle") |
printTest(test1(plainText, userKey)) |
printTest(test2(plainText, userKey)) |
printTest(test3(plainText, userKey)) |
else: |
helpExit() |
if __name__ == "__main__": |
main() |
/relevation/branches/1.1/python-cryptoplus/src/CryptoPlus/Cipher/CAST.py |
---|
0,0 → 1,57 |
from blockcipher import * |
import Crypto.Cipher.CAST |
def new(key,mode=MODE_ECB,IV=None,counter=None,segment_size=None): |
"""Create a new cipher object |
CAST using pycrypto for algo and pycryptoplus for ciphermode |
key = raw string containing the keys |
mode = python_AES.MODE_ECB/CBC/CFB/OFB/CTR/CMAC, default is ECB |
IV = IV as a raw string, default is "all zero" IV |
-> only needed for CBC mode |
counter = counter object (CryptoPlus.Util.util.Counter) |
-> only needed for CTR mode |
segment_size = amount of bits to use from the keystream in each chain part |
-> supported values: multiple of 8 between 8 and the blocksize |
of the cipher (only per byte access possible), default is 8 |
-> only needed for CFB mode |
EXAMPLES: |
********** |
IMPORTING: |
----------- |
>>> from CryptoPlus.Cipher import CAST |
ECB example: http://www.rfc-editor.org/rfc/rfc2144.txt |
------------- |
128 bit key |
>>> key = "0123456712345678234567893456789A".decode('hex') |
>>> plaintext = "0123456789ABCDEF".decode('hex') |
>>> cipher = CAST.new(key,CAST.MODE_ECB,) |
>>> cipher.encrypt(plaintext).encode('hex') |
'238b4fe5847e44b2' |
40 bit key |
>>> from CryptoPlus.Cipher import CAST |
>>> key = "0123456712".decode('hex') |
>>> plaintext = "0123456789ABCDEF".decode('hex') |
>>> cipher = CAST.new(key,CAST.MODE_ECB,) |
>>> cipher.encrypt(plaintext).encode('hex').upper() |
'7AC816D16E9B302E' |
""" |
return CAST(key,mode,IV,counter,segment_size) |
class CAST(BlockCipher): |
def __init__(self,key,mode,IV,counter,segment_size): |
cipher_module = Crypto.Cipher.CAST.new |
self.blocksize = 8 |
BlockCipher.__init__(self,key,mode,IV,counter,cipher_module,segment_size) |
def _test(): |
import doctest |
doctest.testmod() |
if __name__ == "__main__": |
_test() |
/relevation/branches/1.1/python-cryptoplus/src/CryptoPlus/Cipher/pytwofish.py |
---|
0,0 → 1,397 |
## twofish.py - pure Python implementation of the Twofish algorithm. |
## Bjorn Edstrom <be@bjrn.se> 13 december 2007. |
## |
## Copyrights |
## ========== |
## |
## This code is a derived from an implementation by Dr Brian Gladman |
## (gladman@seven77.demon.co.uk) which is subject to the following license. |
## This Python implementation is not subject to any other license. |
## |
##/* This is an independent implementation of the encryption algorithm: */ |
##/* */ |
##/* Twofish by Bruce Schneier and colleagues */ |
##/* */ |
##/* which is a candidate algorithm in the Advanced Encryption Standard */ |
##/* programme of the US National Institute of Standards and Technology. */ |
##/* */ |
##/* Copyright in this implementation is held by Dr B R Gladman but I */ |
##/* hereby give permission for its free direct or derivative use subject */ |
##/* to acknowledgment of its origin and compliance with any conditions */ |
##/* that the originators of t he algorithm place on its exploitation. */ |
##/* */ |
##/* My thanks to Doug Whiting and Niels Ferguson for comments that led */ |
##/* to improvements in this implementation. */ |
##/* */ |
##/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999 */ |
## |
## The above copyright notice must not be removed. |
## |
## Information |
## =========== |
## |
## Anyone thinking of using this code should reconsider. It's slow. |
## Try python-mcrypt instead. In case a faster library is not installed |
## on the target system, this code can be used as a portable fallback. |
try: |
import psyco |
psyco.full() |
except ImportError: |
pass |
block_size = 16 |
key_size = 32 |
class Twofish: |
def __init__(self, key=None): |
"""Twofish.""" |
if key: |
self.set_key(key) |
def set_key(self, key): |
"""Init.""" |
key_len = len(key) |
if key_len not in [16, 24, 32]: |
# XXX: add padding? |
raise KeyError, "key must be 16, 24 or 32 bytes" |
if key_len % 4: |
# XXX: add padding? |
raise KeyError, "key not a multiple of 4" |
if key_len > 32: |
# XXX: prune? |
raise KeyError, "key_len > 32" |
self.context = TWI() |
key_word32 = [0] * 32 |
i = 0 |
while key: |
key_word32[i] = struct.unpack("<L", key[0:4])[0] |
key = key[4:] |
i += 1 |
set_key(self.context, key_word32, key_len) |
def decrypt(self, block): |
"""Decrypt blocks.""" |
if len(block) % 16: |
raise ValueError, "block size must be a multiple of 16" |
plaintext = '' |
while block: |
a, b, c, d = struct.unpack("<4L", block[:16]) |
temp = [a, b, c, d] |
decrypt(self.context, temp) |
plaintext += struct.pack("<4L", *temp) |
block = block[16:] |
return plaintext |
def encrypt(self, block): |
"""Encrypt blocks.""" |
if len(block) % 16: |
raise ValueError, "block size must be a multiple of 16" |
ciphertext = '' |
while block: |
a, b, c, d = struct.unpack("<4L", block[0:16]) |
temp = [a, b, c, d] |
encrypt(self.context, temp) |
ciphertext += struct.pack("<4L", *temp) |
block = block[16:] |
return ciphertext |
def get_name(self): |
"""Return the name of the cipher.""" |
return "Twofish" |
def get_block_size(self): |
"""Get cipher block size in bytes.""" |
return 16 |
def get_key_size(self): |
"""Get cipher key size in bytes.""" |
return 32 |
# |
# Private. |
# |
import struct |
import sys |
WORD_BIGENDIAN = 0 |
if sys.byteorder == 'big': |
WORD_BIGENDIAN = 1 |
def rotr32(x, n): |
return (x >> n) | ((x << (32 - n)) & 0xFFFFFFFF) |
def rotl32(x, n): |
return ((x << n) & 0xFFFFFFFF) | (x >> (32 - n)) |
def byteswap32(x): |
return ((x & 0xff) << 24) | (((x >> 8) & 0xff) << 16) | \ |
(((x >> 16) & 0xff) << 8) | ((x >> 24) & 0xff) |
class TWI: |
def __init__(self): |
self.k_len = 0 # word32 |
self.l_key = [0]*40 # word32 |
self.s_key = [0]*4 # word32 |
self.qt_gen = 0 # word32 |
self.q_tab = [[0]*256, [0]*256] # byte |
self.mt_gen = 0 # word32 |
self.m_tab = [[0]*256, [0]*256, [0]*256, [0]*256] # word32 |
self.mk_tab = [[0]*256, [0]*256, [0]*256, [0]*256] # word32 |
def byte(x, n): |
return (x >> (8 * n)) & 0xff |
tab_5b = [0, 90, 180, 238] |
tab_ef = [0, 238, 180, 90] |
ror4 = [0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15] |
ashx = [0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, 5, 14, 7] |
qt0 = [[8, 1, 7, 13, 6, 15, 3, 2, 0, 11, 5, 9, 14, 12, 10, 4], |
[2, 8, 11, 13, 15, 7, 6, 14, 3, 1, 9, 4, 0, 10, 12, 5]] |
qt1 = [[14, 12, 11, 8, 1, 2, 3, 5, 15, 4, 10, 6, 7, 0, 9, 13], |
[1, 14, 2, 11, 4, 12, 3, 7, 6, 13, 10, 5, 15, 9, 0, 8]] |
qt2 = [[11, 10, 5, 14, 6, 13, 9, 0, 12, 8, 15, 3, 2, 4, 7, 1], |
[4, 12, 7, 5, 1, 6, 9, 10, 0, 14, 13, 8, 2, 11, 3, 15]] |
qt3 = [[13, 7, 15, 4, 1, 2, 6, 14, 9, 11, 3, 0, 8, 5, 12, 10], |
[11, 9, 5, 1, 12, 3, 13, 14, 6, 4, 7, 15, 2, 0, 8, 10]] |
def qp(n, x): # word32, byte |
n %= 0x100000000 |
x %= 0x100 |
a0 = x >> 4; |
b0 = x & 15; |
a1 = a0 ^ b0; |
b1 = ror4[b0] ^ ashx[a0]; |
a2 = qt0[n][a1]; |
b2 = qt1[n][b1]; |
a3 = a2 ^ b2; |
b3 = ror4[b2] ^ ashx[a2]; |
a4 = qt2[n][a3]; |
b4 = qt3[n][b3]; |
return (b4 << 4) | a4; |
def gen_qtab(pkey): |
for i in xrange(256): |
pkey.q_tab[0][i] = qp(0, i) |
pkey.q_tab[1][i] = qp(1, i) |
def gen_mtab(pkey): |
for i in xrange(256): |
f01 = pkey.q_tab[1][i] |
f01 = pkey.q_tab[1][i]; |
f5b = ((f01) ^ ((f01) >> 2) ^ tab_5b[(f01) & 3]); |
fef = ((f01) ^ ((f01) >> 1) ^ ((f01) >> 2) ^ tab_ef[(f01) & 3]); |
pkey.m_tab[0][i] = f01 + (f5b << 8) + (fef << 16) + (fef << 24); |
pkey.m_tab[2][i] = f5b + (fef << 8) + (f01 << 16) + (fef << 24); |
f01 = pkey.q_tab[0][i]; |
f5b = ((f01) ^ ((f01) >> 2) ^ tab_5b[(f01) & 3]); |
fef = ((f01) ^ ((f01) >> 1) ^ ((f01) >> 2) ^ tab_ef[(f01) & 3]); |
pkey.m_tab[1][i] = fef + (fef << 8) + (f5b << 16) + (f01 << 24); |
pkey.m_tab[3][i] = f5b + (f01 << 8) + (fef << 16) + (f5b << 24); |
def gen_mk_tab(pkey, key): |
if pkey.k_len == 2: |
for i in xrange(256): |
by = i % 0x100 |
pkey.mk_tab[0][i] = pkey.m_tab[0][pkey.q_tab[0][pkey.q_tab[0][by] ^ byte(key[1],0)] ^ byte(key[0],0)]; |
pkey.mk_tab[1][i] = pkey.m_tab[1][pkey.q_tab[0][pkey.q_tab[1][by] ^ byte(key[1],1)] ^ byte(key[0],1)]; |
pkey.mk_tab[2][i] = pkey.m_tab[2][pkey.q_tab[1][pkey.q_tab[0][by] ^ byte(key[1],2)] ^ byte(key[0],2)]; |
pkey.mk_tab[3][i] = pkey.m_tab[3][pkey.q_tab[1][pkey.q_tab[1][by] ^ byte(key[1],3)] ^ byte(key[0],3)]; |
if pkey.k_len == 3: |
for i in xrange(256): |
by = i % 0x100 |
pkey.mk_tab[0][i] = pkey.m_tab[0][pkey.q_tab[0][pkey.q_tab[0][pkey.q_tab[1][by] ^ byte(key[2], 0)] ^ byte(key[1], 0)] ^ byte(key[0], 0)]; |
pkey.mk_tab[1][i] = pkey.m_tab[1][pkey.q_tab[0][pkey.q_tab[1][pkey.q_tab[1][by] ^ byte(key[2], 1)] ^ byte(key[1], 1)] ^ byte(key[0], 1)]; |
pkey.mk_tab[2][i] = pkey.m_tab[2][pkey.q_tab[1][pkey.q_tab[0][pkey.q_tab[0][by] ^ byte(key[2], 2)] ^ byte(key[1], 2)] ^ byte(key[0], 2)]; |
pkey.mk_tab[3][i] = pkey.m_tab[3][pkey.q_tab[1][pkey.q_tab[1][pkey.q_tab[0][by] ^ byte(key[2], 3)] ^ byte(key[1], 3)] ^ byte(key[0], 3)]; |
if pkey.k_len == 4: |
for i in xrange(256): |
by = i % 0x100 |
pkey.mk_tab[0][i] = pkey.m_tab[0][pkey.q_tab[0][pkey.q_tab[0][pkey.q_tab[1][pkey.q_tab[1][by] ^ byte(key[3], 0)] ^ byte(key[2], 0)] ^ byte(key[1], 0)] ^ byte(key[0], 0)]; |
pkey.mk_tab[1][i] = pkey.m_tab[1][pkey.q_tab[0][pkey.q_tab[1][pkey.q_tab[1][pkey.q_tab[0][by] ^ byte(key[3], 1)] ^ byte(key[2], 1)] ^ byte(key[1], 1)] ^ byte(key[0], 1)]; |
pkey.mk_tab[2][i] = pkey.m_tab[2][pkey.q_tab[1][pkey.q_tab[0][pkey.q_tab[0][pkey.q_tab[0][by] ^ byte(key[3], 2)] ^ byte(key[2], 2)] ^ byte(key[1], 2)] ^ byte(key[0], 2)]; |
pkey.mk_tab[3][i] = pkey.m_tab[3][pkey.q_tab[1][pkey.q_tab[1][pkey.q_tab[0][pkey.q_tab[1][by] ^ byte(key[3], 3)] ^ byte(key[2], 3)] ^ byte(key[1], 3)] ^ byte(key[0], 3)]; |
def h_fun(pkey, x, key): |
b0 = byte(x, 0); |
b1 = byte(x, 1); |
b2 = byte(x, 2); |
b3 = byte(x, 3); |
if pkey.k_len >= 4: |
b0 = pkey.q_tab[1][b0] ^ byte(key[3], 0); |
b1 = pkey.q_tab[0][b1] ^ byte(key[3], 1); |
b2 = pkey.q_tab[0][b2] ^ byte(key[3], 2); |
b3 = pkey.q_tab[1][b3] ^ byte(key[3], 3); |
if pkey.k_len >= 3: |
b0 = pkey.q_tab[1][b0] ^ byte(key[2], 0); |
b1 = pkey.q_tab[1][b1] ^ byte(key[2], 1); |
b2 = pkey.q_tab[0][b2] ^ byte(key[2], 2); |
b3 = pkey.q_tab[0][b3] ^ byte(key[2], 3); |
if pkey.k_len >= 2: |
b0 = pkey.q_tab[0][pkey.q_tab[0][b0] ^ byte(key[1], 0)] ^ byte(key[0], 0); |
b1 = pkey.q_tab[0][pkey.q_tab[1][b1] ^ byte(key[1], 1)] ^ byte(key[0], 1); |
b2 = pkey.q_tab[1][pkey.q_tab[0][b2] ^ byte(key[1], 2)] ^ byte(key[0], 2); |
b3 = pkey.q_tab[1][pkey.q_tab[1][b3] ^ byte(key[1], 3)] ^ byte(key[0], 3); |
return pkey.m_tab[0][b0] ^ pkey.m_tab[1][b1] ^ pkey.m_tab[2][b2] ^ pkey.m_tab[3][b3]; |
def mds_rem(p0, p1): |
i, t, u = 0, 0, 0 |
for i in xrange(8): |
t = p1 >> 24 |
p1 = ((p1 << 8) & 0xffffffff) | (p0 >> 24) |
p0 = (p0 << 8) & 0xffffffff |
u = (t << 1) & 0xffffffff |
if t & 0x80: |
u ^= 0x0000014d |
p1 ^= t ^ ((u << 16) & 0xffffffff) |
u ^= (t >> 1) |
if t & 0x01: |
u ^= 0x0000014d >> 1 |
p1 ^= ((u << 24) & 0xffffffff) | ((u << 8) & 0xffffffff) |
return p1 |
def set_key(pkey, in_key, key_len): |
pkey.qt_gen = 0 |
if not pkey.qt_gen: |
gen_qtab(pkey) |
pkey.qt_gen = 1 |
pkey.mt_gen = 0 |
if not pkey.mt_gen: |
gen_mtab(pkey) |
pkey.mt_gen = 1 |
pkey.k_len = (key_len * 8) / 64 |
a = 0 |
b = 0 |
me_key = [0,0,0,0] |
mo_key = [0,0,0,0] |
for i in xrange(pkey.k_len): |
if WORD_BIGENDIAN: |
a = byteswap32(in_key[i + 1]) |
me_key[i] = a |
b = byteswap32(in_key[i + i + 1]) |
else: |
a = in_key[i + i] |
me_key[i] = a |
b = in_key[i + i + 1] |
mo_key[i] = b |
pkey.s_key[pkey.k_len - i - 1] = mds_rem(a, b); |
for i in xrange(0, 40, 2): |
a = (0x01010101 * i) % 0x100000000; |
b = (a + 0x01010101) % 0x100000000; |
a = h_fun(pkey, a, me_key); |
b = rotl32(h_fun(pkey, b, mo_key), 8); |
pkey.l_key[i] = (a + b) % 0x100000000; |
pkey.l_key[i + 1] = rotl32((a + 2 * b) % 0x100000000, 9); |
gen_mk_tab(pkey, pkey.s_key) |
def encrypt(pkey, in_blk): |
blk = [0, 0, 0, 0] |
if WORD_BIGENDIAN: |
blk[0] = byteswap32(in_blk[0]) ^ pkey.l_key[0]; |
blk[1] = byteswap32(in_blk[1]) ^ pkey.l_key[1]; |
blk[2] = byteswap32(in_blk[2]) ^ pkey.l_key[2]; |
blk[3] = byteswap32(in_blk[3]) ^ pkey.l_key[3]; |
else: |
blk[0] = in_blk[0] ^ pkey.l_key[0]; |
blk[1] = in_blk[1] ^ pkey.l_key[1]; |
blk[2] = in_blk[2] ^ pkey.l_key[2]; |
blk[3] = in_blk[3] ^ pkey.l_key[3]; |
for i in xrange(8): |
t1 = ( pkey.mk_tab[0][byte(blk[1],3)] ^ pkey.mk_tab[1][byte(blk[1],0)] ^ pkey.mk_tab[2][byte(blk[1],1)] ^ pkey.mk_tab[3][byte(blk[1],2)] ); |
t0 = ( pkey.mk_tab[0][byte(blk[0],0)] ^ pkey.mk_tab[1][byte(blk[0],1)] ^ pkey.mk_tab[2][byte(blk[0],2)] ^ pkey.mk_tab[3][byte(blk[0],3)] ); |
blk[2] = rotr32(blk[2] ^ ((t0 + t1 + pkey.l_key[4 * (i) + 8]) % 0x100000000), 1); |
blk[3] = rotl32(blk[3], 1) ^ ((t0 + 2 * t1 + pkey.l_key[4 * (i) + 9]) % 0x100000000); |
t1 = ( pkey.mk_tab[0][byte(blk[3],3)] ^ pkey.mk_tab[1][byte(blk[3],0)] ^ pkey.mk_tab[2][byte(blk[3],1)] ^ pkey.mk_tab[3][byte(blk[3],2)] ); |
t0 = ( pkey.mk_tab[0][byte(blk[2],0)] ^ pkey.mk_tab[1][byte(blk[2],1)] ^ pkey.mk_tab[2][byte(blk[2],2)] ^ pkey.mk_tab[3][byte(blk[2],3)] ); |
blk[0] = rotr32(blk[0] ^ ((t0 + t1 + pkey.l_key[4 * (i) + 10]) % 0x100000000), 1); |
blk[1] = rotl32(blk[1], 1) ^ ((t0 + 2 * t1 + pkey.l_key[4 * (i) + 11]) % 0x100000000); |
if WORD_BIGENDIAN: |
in_blk[0] = byteswap32(blk[2] ^ pkey.l_key[4]); |
in_blk[1] = byteswap32(blk[3] ^ pkey.l_key[5]); |
in_blk[2] = byteswap32(blk[0] ^ pkey.l_key[6]); |
in_blk[3] = byteswap32(blk[1] ^ pkey.l_key[7]); |
else: |
in_blk[0] = blk[2] ^ pkey.l_key[4]; |
in_blk[1] = blk[3] ^ pkey.l_key[5]; |
in_blk[2] = blk[0] ^ pkey.l_key[6]; |
in_blk[3] = blk[1] ^ pkey.l_key[7]; |
return |
def decrypt(pkey, in_blk): |
blk = [0, 0, 0, 0] |
if WORD_BIGENDIAN: |
blk[0] = byteswap32(in_blk[0]) ^ pkey.l_key[4]; |
blk[1] = byteswap32(in_blk[1]) ^ pkey.l_key[5]; |
blk[2] = byteswap32(in_blk[2]) ^ pkey.l_key[6]; |
blk[3] = byteswap32(in_blk[3]) ^ pkey.l_key[7]; |
else: |
blk[0] = in_blk[0] ^ pkey.l_key[4]; |
blk[1] = in_blk[1] ^ pkey.l_key[5]; |
blk[2] = in_blk[2] ^ pkey.l_key[6]; |
blk[3] = in_blk[3] ^ pkey.l_key[7]; |
for i in xrange(7, -1, -1): |
t1 = ( pkey.mk_tab[0][byte(blk[1],3)] ^ pkey.mk_tab[1][byte(blk[1],0)] ^ pkey.mk_tab[2][byte(blk[1],1)] ^ pkey.mk_tab[3][byte(blk[1],2)] ) |
t0 = ( pkey.mk_tab[0][byte(blk[0],0)] ^ pkey.mk_tab[1][byte(blk[0],1)] ^ pkey.mk_tab[2][byte(blk[0],2)] ^ pkey.mk_tab[3][byte(blk[0],3)] ) |
blk[2] = rotl32(blk[2], 1) ^ ((t0 + t1 + pkey.l_key[4 * (i) + 10]) % 0x100000000) |
blk[3] = rotr32(blk[3] ^ ((t0 + 2 * t1 + pkey.l_key[4 * (i) + 11]) % 0x100000000), 1) |
t1 = ( pkey.mk_tab[0][byte(blk[3],3)] ^ pkey.mk_tab[1][byte(blk[3],0)] ^ pkey.mk_tab[2][byte(blk[3],1)] ^ pkey.mk_tab[3][byte(blk[3],2)] ) |
t0 = ( pkey.mk_tab[0][byte(blk[2],0)] ^ pkey.mk_tab[1][byte(blk[2],1)] ^ pkey.mk_tab[2][byte(blk[2],2)] ^ pkey.mk_tab[3][byte(blk[2],3)] ) |
blk[0] = rotl32(blk[0], 1) ^ ((t0 + t1 + pkey.l_key[4 * (i) + 8]) % 0x100000000) |
blk[1] = rotr32(blk[1] ^ ((t0 + 2 * t1 + pkey.l_key[4 * (i) + 9]) % 0x100000000), 1) |
if WORD_BIGENDIAN: |
in_blk[0] = byteswap32(blk[2] ^ pkey.l_key[0]); |
in_blk[1] = byteswap32(blk[3] ^ pkey.l_key[1]); |
in_blk[2] = byteswap32(blk[0] ^ pkey.l_key[2]); |
in_blk[3] = byteswap32(blk[1] ^ pkey.l_key[3]); |
else: |
in_blk[0] = blk[2] ^ pkey.l_key[0]; |
in_blk[1] = blk[3] ^ pkey.l_key[1]; |
in_blk[2] = blk[0] ^ pkey.l_key[2]; |
in_blk[3] = blk[1] ^ pkey.l_key[3]; |
return |
__testkey = '\xD4\x3B\xB7\x55\x6E\xA3\x2E\x46\xF2\xA2\x82\xB7\xD4\x5B\x4E\x0D\x57\xFF\x73\x9D\x4D\xC9\x2C\x1B\xD7\xFC\x01\x70\x0C\xC8\x21\x6F' |
__testdat = '\x90\xAF\xE9\x1B\xB2\x88\x54\x4F\x2C\x32\xDC\x23\x9B\x26\x35\xE6' |
assert 'l\xb4V\x1c@\xbf\n\x97\x05\x93\x1c\xb6\xd4\x08\xe7\xfa' == Twofish(__testkey).encrypt(__testdat) |
assert __testdat == Twofish(__testkey).decrypt('l\xb4V\x1c@\xbf\n\x97\x05\x93\x1c\xb6\xd4\x08\xe7\xfa') |