update windows build to Python 3.7

This commit is contained in:
j 2019-01-20 16:05:31 +05:30
commit ddc59ab92d
5761 changed files with 750298 additions and 213405 deletions

View file

@ -1,130 +1,130 @@
# -*- coding: utf-8 -*-
#
# Cipher/ARC2.py : ARC2.py
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
"""RC2 symmetric cipher
RC2_ (Rivest's Cipher version 2) is a symmetric block cipher designed
by Ron Rivest in 1987. The cipher started as a proprietary design,
that was reverse engineered and anonymously posted on Usenet in 1996.
For this reason, the algorithm was first called *Alleged* RC2 (ARC2),
since the company that owned RC2 (RSA Data Inc.) did not confirm whether
the details leaked into public domain were really correct.
The company eventually published its full specification in RFC2268_.
RC2 has a fixed data block size of 8 bytes. Length of its keys can vary from
8 to 128 bits. One particular property of RC2 is that the actual
cryptographic strength of the key (*effective key length*) can be reduced
via a parameter.
Even though RC2 is not cryptographically broken, it has not been analyzed as
thoroughly as AES, which is also faster than RC2.
New designs should not use RC2.
As an example, encryption can be done as follows:
>>> from Crypto.Cipher import ARC2
>>> from Crypto import Random
>>>
>>> key = b'Sixteen byte key'
>>> iv = Random.new().read(ARC2.block_size)
>>> cipher = ARC2.new(key, ARC2.MODE_CFB, iv)
>>> msg = iv + cipher.encrypt(b'Attack at dawn')
.. _RC2: http://en.wikipedia.org/wiki/RC2
.. _RFC2268: http://tools.ietf.org/html/rfc2268
:undocumented: __revision__, __package__
"""
__revision__ = "$Id$"
from Crypto.Cipher import blockalgo
from Crypto.Cipher import _ARC2
class RC2Cipher (blockalgo.BlockAlgo):
"""RC2 cipher object"""
def __init__(self, key, *args, **kwargs):
"""Initialize an ARC2 cipher object
See also `new()` at the module level."""
blockalgo.BlockAlgo.__init__(self, _ARC2, key, *args, **kwargs)
def new(key, *args, **kwargs):
"""Create a new RC2 cipher
:Parameters:
key : byte string
The secret key to use in the symmetric cipher.
Its length can vary from 1 to 128 bytes.
:Keywords:
mode : a *MODE_** constant
The chaining mode to use for encryption or decryption.
Default is `MODE_ECB`.
IV : byte string
The initialization vector to use for encryption or decryption.
It is ignored for `MODE_ECB` and `MODE_CTR`.
For `MODE_OPENPGP`, IV must be `block_size` bytes long for encryption
and `block_size` +2 bytes for decryption (in the latter case, it is
actually the *encrypted* IV which was prefixed to the ciphertext).
It is mandatory.
For all other modes, it must be `block_size` bytes longs. It is optional and
when not present it will be given a default value of all zeroes.
counter : callable
(*Only* `MODE_CTR`). A stateful function that returns the next
*counter block*, which is a byte string of `block_size` bytes.
For better performance, use `Crypto.Util.Counter`.
segment_size : integer
(*Only* `MODE_CFB`).The number of bits the plaintext and ciphertext
are segmented in.
It must be a multiple of 8. If 0 or not specified, it will be assumed to be 8.
effective_keylen : integer
Maximum cryptographic strength of the key, in bits.
It can vary from 0 to 1024. The default value is 1024.
:Return: an `RC2Cipher` object
"""
return RC2Cipher(key, *args, **kwargs)
#: Electronic Code Book (ECB). See `blockalgo.MODE_ECB`.
MODE_ECB = 1
#: Cipher-Block Chaining (CBC). See `blockalgo.MODE_CBC`.
MODE_CBC = 2
#: Cipher FeedBack (CFB). See `blockalgo.MODE_CFB`.
MODE_CFB = 3
#: This mode should not be used.
MODE_PGP = 4
#: Output FeedBack (OFB). See `blockalgo.MODE_OFB`.
MODE_OFB = 5
#: CounTer Mode (CTR). See `blockalgo.MODE_CTR`.
MODE_CTR = 6
#: OpenPGP Mode. See `blockalgo.MODE_OPENPGP`.
MODE_OPENPGP = 7
#: Size of a data block (in bytes)
block_size = 8
#: Size of a key (in bytes)
key_size = range(1,16+1)
# -*- coding: utf-8 -*-
#
# Cipher/ARC2.py : ARC2.py
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
"""RC2 symmetric cipher
RC2_ (Rivest's Cipher version 2) is a symmetric block cipher designed
by Ron Rivest in 1987. The cipher started as a proprietary design,
that was reverse engineered and anonymously posted on Usenet in 1996.
For this reason, the algorithm was first called *Alleged* RC2 (ARC2),
since the company that owned RC2 (RSA Data Inc.) did not confirm whether
the details leaked into public domain were really correct.
The company eventually published its full specification in RFC2268_.
RC2 has a fixed data block size of 8 bytes. Length of its keys can vary from
8 to 128 bits. One particular property of RC2 is that the actual
cryptographic strength of the key (*effective key length*) can be reduced
via a parameter.
Even though RC2 is not cryptographically broken, it has not been analyzed as
thoroughly as AES, which is also faster than RC2.
New designs should not use RC2.
As an example, encryption can be done as follows:
>>> from Crypto.Cipher import ARC2
>>> from Crypto import Random
>>>
>>> key = b'Sixteen byte key'
>>> iv = Random.new().read(ARC2.block_size)
>>> cipher = ARC2.new(key, ARC2.MODE_CFB, iv)
>>> msg = iv + cipher.encrypt(b'Attack at dawn')
.. _RC2: http://en.wikipedia.org/wiki/RC2
.. _RFC2268: http://tools.ietf.org/html/rfc2268
:undocumented: __revision__, __package__
"""
__revision__ = "$Id$"
from Crypto.Cipher import blockalgo
from Crypto.Cipher import _ARC2
class RC2Cipher (blockalgo.BlockAlgo):
"""RC2 cipher object"""
def __init__(self, key, *args, **kwargs):
"""Initialize an ARC2 cipher object
See also `new()` at the module level."""
blockalgo.BlockAlgo.__init__(self, _ARC2, key, *args, **kwargs)
def new(key, *args, **kwargs):
"""Create a new RC2 cipher
:Parameters:
key : byte string
The secret key to use in the symmetric cipher.
Its length can vary from 1 to 128 bytes.
:Keywords:
mode : a *MODE_** constant
The chaining mode to use for encryption or decryption.
Default is `MODE_ECB`.
IV : byte string
The initialization vector to use for encryption or decryption.
It is ignored for `MODE_ECB` and `MODE_CTR`.
For `MODE_OPENPGP`, IV must be `block_size` bytes long for encryption
and `block_size` +2 bytes for decryption (in the latter case, it is
actually the *encrypted* IV which was prefixed to the ciphertext).
It is mandatory.
For all other modes, it must be `block_size` bytes longs. It is optional and
when not present it will be given a default value of all zeroes.
counter : callable
(*Only* `MODE_CTR`). A stateful function that returns the next
*counter block*, which is a byte string of `block_size` bytes.
For better performance, use `Crypto.Util.Counter`.
segment_size : integer
(*Only* `MODE_CFB`).The number of bits the plaintext and ciphertext
are segmented in.
It must be a multiple of 8. If 0 or not specified, it will be assumed to be 8.
effective_keylen : integer
Maximum cryptographic strength of the key, in bits.
It can vary from 0 to 1024. The default value is 1024.
:Return: an `RC2Cipher` object
"""
return RC2Cipher(key, *args, **kwargs)
#: Electronic Code Book (ECB). See `blockalgo.MODE_ECB`.
MODE_ECB = 1
#: Cipher-Block Chaining (CBC). See `blockalgo.MODE_CBC`.
MODE_CBC = 2
#: Cipher FeedBack (CFB). See `blockalgo.MODE_CFB`.
MODE_CFB = 3
#: This mode should not be used.
MODE_PGP = 4
#: Output FeedBack (OFB). See `blockalgo.MODE_OFB`.
MODE_OFB = 5
#: CounTer Mode (CTR). See `blockalgo.MODE_CTR`.
MODE_CTR = 6
#: OpenPGP Mode. See `blockalgo.MODE_OPENPGP`.
MODE_OPENPGP = 7
#: Size of a data block (in bytes)
block_size = 8
#: Size of a key (in bytes)
key_size = range(1,16+1)

View file

@ -1,120 +1,120 @@
# -*- coding: utf-8 -*-
#
# Cipher/ARC4.py : ARC4
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
"""ARC4 symmetric cipher
ARC4_ (Alleged RC4) is an implementation of RC4 (Rivest's Cipher version 4),
a symmetric stream cipher designed by Ron Rivest in 1987.
The cipher started as a proprietary design, that was reverse engineered and
anonymously posted on Usenet in 1994. The company that owns RC4 (RSA Data
Inc.) never confirmed the correctness of the leaked algorithm.
Unlike RC2, the company has never published the full specification of RC4,
of whom it still holds the trademark.
ARC4 keys can vary in length from 40 to 2048 bits.
One problem of ARC4 is that it does not take a nonce or an IV. If it is required
to encrypt multiple messages with the same long-term key, a distinct
independent nonce must be created for each message, and a short-term key must
be derived from the combination of the long-term key and the nonce.
Due to the weak key scheduling algorithm of RC2, the combination must be carried
out with a complex function (e.g. a cryptographic hash) and not by simply
concatenating key and nonce.
New designs should not use ARC4. A good alternative is AES
(`Crypto.Cipher.AES`) in any of the modes that turn it into a stream cipher (OFB, CFB, or CTR).
As an example, encryption can be done as follows:
>>> from Crypto.Cipher import ARC4
>>> from Crypto.Hash import SHA
>>> from Crypto import Random
>>>
>>> key = b'Very long and confidential key'
>>> nonce = Random.new().read(16)
>>> tempkey = SHA.new(key+nonce).digest()
>>> cipher = ARC4.new(tempkey)
>>> msg = nonce + cipher.encrypt(b'Open the pod bay doors, HAL')
.. _ARC4: http://en.wikipedia.org/wiki/RC4
:undocumented: __revision__, __package__
"""
__revision__ = "$Id$"
from Crypto.Cipher import _ARC4
class ARC4Cipher:
"""ARC4 cipher object"""
def __init__(self, key, *args, **kwargs):
"""Initialize an ARC4 cipher object
See also `new()` at the module level."""
self._cipher = _ARC4.new(key, *args, **kwargs)
self.block_size = self._cipher.block_size
self.key_size = self._cipher.key_size
def encrypt(self, plaintext):
"""Encrypt a piece of data.
:Parameters:
plaintext : byte string
The piece of data to encrypt. It can be of any size.
:Return: the encrypted data (byte string, as long as the
plaintext).
"""
return self._cipher.encrypt(plaintext)
def decrypt(self, ciphertext):
"""Decrypt a piece of data.
:Parameters:
ciphertext : byte string
The piece of data to decrypt. It can be of any size.
:Return: the decrypted data (byte string, as long as the
ciphertext).
"""
return self._cipher.decrypt(ciphertext)
def new(key, *args, **kwargs):
"""Create a new ARC4 cipher
:Parameters:
key : byte string
The secret key to use in the symmetric cipher.
It can have any length, with a minimum of 40 bytes.
Its cryptograpic strength is always capped to 2048 bits (256 bytes).
:Return: an `ARC4Cipher` object
"""
return ARC4Cipher(key, *args, **kwargs)
#: Size of a data block (in bytes)
block_size = 1
#: Size of a key (in bytes)
key_size = range(1,256+1)
# -*- coding: utf-8 -*-
#
# Cipher/ARC4.py : ARC4
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
"""ARC4 symmetric cipher
ARC4_ (Alleged RC4) is an implementation of RC4 (Rivest's Cipher version 4),
a symmetric stream cipher designed by Ron Rivest in 1987.
The cipher started as a proprietary design, that was reverse engineered and
anonymously posted on Usenet in 1994. The company that owns RC4 (RSA Data
Inc.) never confirmed the correctness of the leaked algorithm.
Unlike RC2, the company has never published the full specification of RC4,
of whom it still holds the trademark.
ARC4 keys can vary in length from 40 to 2048 bits.
One problem of ARC4 is that it does not take a nonce or an IV. If it is required
to encrypt multiple messages with the same long-term key, a distinct
independent nonce must be created for each message, and a short-term key must
be derived from the combination of the long-term key and the nonce.
Due to the weak key scheduling algorithm of RC2, the combination must be carried
out with a complex function (e.g. a cryptographic hash) and not by simply
concatenating key and nonce.
New designs should not use ARC4. A good alternative is AES
(`Crypto.Cipher.AES`) in any of the modes that turn it into a stream cipher (OFB, CFB, or CTR).
As an example, encryption can be done as follows:
>>> from Crypto.Cipher import ARC4
>>> from Crypto.Hash import SHA
>>> from Crypto import Random
>>>
>>> key = b'Very long and confidential key'
>>> nonce = Random.new().read(16)
>>> tempkey = SHA.new(key+nonce).digest()
>>> cipher = ARC4.new(tempkey)
>>> msg = nonce + cipher.encrypt(b'Open the pod bay doors, HAL')
.. _ARC4: http://en.wikipedia.org/wiki/RC4
:undocumented: __revision__, __package__
"""
__revision__ = "$Id$"
from Crypto.Cipher import _ARC4
class ARC4Cipher:
"""ARC4 cipher object"""
def __init__(self, key, *args, **kwargs):
"""Initialize an ARC4 cipher object
See also `new()` at the module level."""
self._cipher = _ARC4.new(key, *args, **kwargs)
self.block_size = self._cipher.block_size
self.key_size = self._cipher.key_size
def encrypt(self, plaintext):
"""Encrypt a piece of data.
:Parameters:
plaintext : byte string
The piece of data to encrypt. It can be of any size.
:Return: the encrypted data (byte string, as long as the
plaintext).
"""
return self._cipher.encrypt(plaintext)
def decrypt(self, ciphertext):
"""Decrypt a piece of data.
:Parameters:
ciphertext : byte string
The piece of data to decrypt. It can be of any size.
:Return: the decrypted data (byte string, as long as the
ciphertext).
"""
return self._cipher.decrypt(ciphertext)
def new(key, *args, **kwargs):
"""Create a new ARC4 cipher
:Parameters:
key : byte string
The secret key to use in the symmetric cipher.
It can have any length, with a minimum of 40 bytes.
Its cryptograpic strength is always capped to 2048 bits (256 bytes).
:Return: an `ARC4Cipher` object
"""
return ARC4Cipher(key, *args, **kwargs)
#: Size of a data block (in bytes)
block_size = 1
#: Size of a key (in bytes)
key_size = range(1,256+1)

View file

@ -1,121 +1,121 @@
# -*- coding: utf-8 -*-
#
# Cipher/Blowfish.py : Blowfish
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
"""Blowfish symmetric cipher
Blowfish_ is a symmetric block cipher designed by Bruce Schneier.
It has a fixed data block size of 8 bytes and its keys can vary in length
from 32 to 448 bits (4 to 56 bytes).
Blowfish is deemed secure and it is fast. However, its keys should be chosen
to be big enough to withstand a brute force attack (e.g. at least 16 bytes).
As an example, encryption can be done as follows:
>>> from Crypto.Cipher import Blowfish
>>> from Crypto import Random
>>> from struct import pack
>>>
>>> bs = Blowfish.block_size
>>> key = b'An arbitrarily long key'
>>> iv = Random.new().read(bs)
>>> cipher = Blowfish.new(key, Blowfish.MODE_CBC, iv)
>>> plaintext = b'docendo discimus '
>>> plen = bs - divmod(len(plaintext),bs)[1]
>>> padding = [plen]*plen
>>> padding = pack('b'*plen, *padding)
>>> msg = iv + cipher.encrypt(plaintext + padding)
.. _Blowfish: http://www.schneier.com/blowfish.html
:undocumented: __revision__, __package__
"""
__revision__ = "$Id$"
from Crypto.Cipher import blockalgo
from Crypto.Cipher import _Blowfish
class BlowfishCipher (blockalgo.BlockAlgo):
"""Blowfish cipher object"""
def __init__(self, key, *args, **kwargs):
"""Initialize a Blowfish cipher object
See also `new()` at the module level."""
blockalgo.BlockAlgo.__init__(self, _Blowfish, key, *args, **kwargs)
def new(key, *args, **kwargs):
"""Create a new Blowfish cipher
:Parameters:
key : byte string
The secret key to use in the symmetric cipher.
Its length can vary from 4 to 56 bytes.
:Keywords:
mode : a *MODE_** constant
The chaining mode to use for encryption or decryption.
Default is `MODE_ECB`.
IV : byte string
The initialization vector to use for encryption or decryption.
It is ignored for `MODE_ECB` and `MODE_CTR`.
For `MODE_OPENPGP`, IV must be `block_size` bytes long for encryption
and `block_size` +2 bytes for decryption (in the latter case, it is
actually the *encrypted* IV which was prefixed to the ciphertext).
It is mandatory.
For all other modes, it must be `block_size` bytes longs. It is optional and
when not present it will be given a default value of all zeroes.
counter : callable
(*Only* `MODE_CTR`). A stateful function that returns the next
*counter block*, which is a byte string of `block_size` bytes.
For better performance, use `Crypto.Util.Counter`.
segment_size : integer
(*Only* `MODE_CFB`).The number of bits the plaintext and ciphertext
are segmented in.
It must be a multiple of 8. If 0 or not specified, it will be assumed to be 8.
:Return: a `BlowfishCipher` object
"""
return BlowfishCipher(key, *args, **kwargs)
#: Electronic Code Book (ECB). See `blockalgo.MODE_ECB`.
MODE_ECB = 1
#: Cipher-Block Chaining (CBC). See `blockalgo.MODE_CBC`.
MODE_CBC = 2
#: Cipher FeedBack (CFB). See `blockalgo.MODE_CFB`.
MODE_CFB = 3
#: This mode should not be used.
MODE_PGP = 4
#: Output FeedBack (OFB). See `blockalgo.MODE_OFB`.
MODE_OFB = 5
#: CounTer Mode (CTR). See `blockalgo.MODE_CTR`.
MODE_CTR = 6
#: OpenPGP Mode. See `blockalgo.MODE_OPENPGP`.
MODE_OPENPGP = 7
#: Size of a data block (in bytes)
block_size = 8
#: Size of a key (in bytes)
key_size = range(4,56+1)
# -*- coding: utf-8 -*-
#
# Cipher/Blowfish.py : Blowfish
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
"""Blowfish symmetric cipher
Blowfish_ is a symmetric block cipher designed by Bruce Schneier.
It has a fixed data block size of 8 bytes and its keys can vary in length
from 32 to 448 bits (4 to 56 bytes).
Blowfish is deemed secure and it is fast. However, its keys should be chosen
to be big enough to withstand a brute force attack (e.g. at least 16 bytes).
As an example, encryption can be done as follows:
>>> from Crypto.Cipher import Blowfish
>>> from Crypto import Random
>>> from struct import pack
>>>
>>> bs = Blowfish.block_size
>>> key = b'An arbitrarily long key'
>>> iv = Random.new().read(bs)
>>> cipher = Blowfish.new(key, Blowfish.MODE_CBC, iv)
>>> plaintext = b'docendo discimus '
>>> plen = bs - divmod(len(plaintext),bs)[1]
>>> padding = [plen]*plen
>>> padding = pack('b'*plen, *padding)
>>> msg = iv + cipher.encrypt(plaintext + padding)
.. _Blowfish: http://www.schneier.com/blowfish.html
:undocumented: __revision__, __package__
"""
__revision__ = "$Id$"
from Crypto.Cipher import blockalgo
from Crypto.Cipher import _Blowfish
class BlowfishCipher (blockalgo.BlockAlgo):
"""Blowfish cipher object"""
def __init__(self, key, *args, **kwargs):
"""Initialize a Blowfish cipher object
See also `new()` at the module level."""
blockalgo.BlockAlgo.__init__(self, _Blowfish, key, *args, **kwargs)
def new(key, *args, **kwargs):
"""Create a new Blowfish cipher
:Parameters:
key : byte string
The secret key to use in the symmetric cipher.
Its length can vary from 4 to 56 bytes.
:Keywords:
mode : a *MODE_** constant
The chaining mode to use for encryption or decryption.
Default is `MODE_ECB`.
IV : byte string
The initialization vector to use for encryption or decryption.
It is ignored for `MODE_ECB` and `MODE_CTR`.
For `MODE_OPENPGP`, IV must be `block_size` bytes long for encryption
and `block_size` +2 bytes for decryption (in the latter case, it is
actually the *encrypted* IV which was prefixed to the ciphertext).
It is mandatory.
For all other modes, it must be `block_size` bytes longs. It is optional and
when not present it will be given a default value of all zeroes.
counter : callable
(*Only* `MODE_CTR`). A stateful function that returns the next
*counter block*, which is a byte string of `block_size` bytes.
For better performance, use `Crypto.Util.Counter`.
segment_size : integer
(*Only* `MODE_CFB`).The number of bits the plaintext and ciphertext
are segmented in.
It must be a multiple of 8. If 0 or not specified, it will be assumed to be 8.
:Return: a `BlowfishCipher` object
"""
return BlowfishCipher(key, *args, **kwargs)
#: Electronic Code Book (ECB). See `blockalgo.MODE_ECB`.
MODE_ECB = 1
#: Cipher-Block Chaining (CBC). See `blockalgo.MODE_CBC`.
MODE_CBC = 2
#: Cipher FeedBack (CFB). See `blockalgo.MODE_CFB`.
MODE_CFB = 3
#: This mode should not be used.
MODE_PGP = 4
#: Output FeedBack (OFB). See `blockalgo.MODE_OFB`.
MODE_OFB = 5
#: CounTer Mode (CTR). See `blockalgo.MODE_CTR`.
MODE_CTR = 6
#: OpenPGP Mode. See `blockalgo.MODE_OPENPGP`.
MODE_OPENPGP = 7
#: Size of a data block (in bytes)
block_size = 8
#: Size of a key (in bytes)
key_size = range(4,56+1)

View file

@ -1,123 +1,123 @@
# -*- coding: utf-8 -*-
#
# Cipher/CAST.py : CAST
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
"""CAST-128 symmetric cipher
CAST-128_ (or CAST5) is a symmetric block cipher specified in RFC2144_.
It has a fixed data block size of 8 bytes. Its key can vary in length
from 40 to 128 bits.
CAST is deemed to be cryptographically secure, but its usage is not widespread.
Keys of sufficient length should be used to prevent brute force attacks
(128 bits are recommended).
As an example, encryption can be done as follows:
>>> from Crypto.Cipher import CAST
>>> from Crypto import Random
>>>
>>> key = b'Sixteen byte key'
>>> iv = Random.new().read(CAST.block_size)
>>> cipher = CAST.new(key, CAST.MODE_OPENPGP, iv)
>>> plaintext = b'sona si latine loqueris '
>>> msg = cipher.encrypt(plaintext)
>>>
...
>>> eiv = msg[:CAST.block_size+2]
>>> ciphertext = msg[CAST.block_size+2:]
>>> cipher = CAST.new(key, CAST.MODE_OPENPGP, eiv)
>>> print cipher.decrypt(ciphertext)
.. _CAST-128: http://en.wikipedia.org/wiki/CAST-128
.. _RFC2144: http://tools.ietf.org/html/rfc2144
:undocumented: __revision__, __package__
"""
__revision__ = "$Id$"
from Crypto.Cipher import blockalgo
from Crypto.Cipher import _CAST
class CAST128Cipher(blockalgo.BlockAlgo):
"""CAST-128 cipher object"""
def __init__(self, key, *args, **kwargs):
"""Initialize a CAST-128 cipher object
See also `new()` at the module level."""
blockalgo.BlockAlgo.__init__(self, _CAST, key, *args, **kwargs)
def new(key, *args, **kwargs):
"""Create a new CAST-128 cipher
:Parameters:
key : byte string
The secret key to use in the symmetric cipher.
Its length may vary from 5 to 16 bytes.
:Keywords:
mode : a *MODE_** constant
The chaining mode to use for encryption or decryption.
Default is `MODE_ECB`.
IV : byte string
The initialization vector to use for encryption or decryption.
It is ignored for `MODE_ECB` and `MODE_CTR`.
For `MODE_OPENPGP`, IV must be `block_size` bytes long for encryption
and `block_size` +2 bytes for decryption (in the latter case, it is
actually the *encrypted* IV which was prefixed to the ciphertext).
It is mandatory.
For all other modes, it must be `block_size` bytes longs. It is optional and
when not present it will be given a default value of all zeroes.
counter : callable
(*Only* `MODE_CTR`). A stateful function that returns the next
*counter block*, which is a byte string of `block_size` bytes.
For better performance, use `Crypto.Util.Counter`.
segment_size : integer
(*Only* `MODE_CFB`).The number of bits the plaintext and ciphertext
are segmented in.
It must be a multiple of 8. If 0 or not specified, it will be assumed to be 8.
:Return: an `CAST128Cipher` object
"""
return CAST128Cipher(key, *args, **kwargs)
#: Electronic Code Book (ECB). See `blockalgo.MODE_ECB`.
MODE_ECB = 1
#: Cipher-Block Chaining (CBC). See `blockalgo.MODE_CBC`.
MODE_CBC = 2
#: Cipher FeedBack (CFB). See `blockalgo.MODE_CFB`.
MODE_CFB = 3
#: This mode should not be used.
MODE_PGP = 4
#: Output FeedBack (OFB). See `blockalgo.MODE_OFB`.
MODE_OFB = 5
#: CounTer Mode (CTR). See `blockalgo.MODE_CTR`.
MODE_CTR = 6
#: OpenPGP Mode. See `blockalgo.MODE_OPENPGP`.
MODE_OPENPGP = 7
#: Size of a data block (in bytes)
block_size = 8
#: Size of a key (in bytes)
key_size = range(5,16+1)
# -*- coding: utf-8 -*-
#
# Cipher/CAST.py : CAST
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
"""CAST-128 symmetric cipher
CAST-128_ (or CAST5) is a symmetric block cipher specified in RFC2144_.
It has a fixed data block size of 8 bytes. Its key can vary in length
from 40 to 128 bits.
CAST is deemed to be cryptographically secure, but its usage is not widespread.
Keys of sufficient length should be used to prevent brute force attacks
(128 bits are recommended).
As an example, encryption can be done as follows:
>>> from Crypto.Cipher import CAST
>>> from Crypto import Random
>>>
>>> key = b'Sixteen byte key'
>>> iv = Random.new().read(CAST.block_size)
>>> cipher = CAST.new(key, CAST.MODE_OPENPGP, iv)
>>> plaintext = b'sona si latine loqueris '
>>> msg = cipher.encrypt(plaintext)
>>>
...
>>> eiv = msg[:CAST.block_size+2]
>>> ciphertext = msg[CAST.block_size+2:]
>>> cipher = CAST.new(key, CAST.MODE_OPENPGP, eiv)
>>> print cipher.decrypt(ciphertext)
.. _CAST-128: http://en.wikipedia.org/wiki/CAST-128
.. _RFC2144: http://tools.ietf.org/html/rfc2144
:undocumented: __revision__, __package__
"""
__revision__ = "$Id$"
from Crypto.Cipher import blockalgo
from Crypto.Cipher import _CAST
class CAST128Cipher(blockalgo.BlockAlgo):
"""CAST-128 cipher object"""
def __init__(self, key, *args, **kwargs):
"""Initialize a CAST-128 cipher object
See also `new()` at the module level."""
blockalgo.BlockAlgo.__init__(self, _CAST, key, *args, **kwargs)
def new(key, *args, **kwargs):
"""Create a new CAST-128 cipher
:Parameters:
key : byte string
The secret key to use in the symmetric cipher.
Its length may vary from 5 to 16 bytes.
:Keywords:
mode : a *MODE_** constant
The chaining mode to use for encryption or decryption.
Default is `MODE_ECB`.
IV : byte string
The initialization vector to use for encryption or decryption.
It is ignored for `MODE_ECB` and `MODE_CTR`.
For `MODE_OPENPGP`, IV must be `block_size` bytes long for encryption
and `block_size` +2 bytes for decryption (in the latter case, it is
actually the *encrypted* IV which was prefixed to the ciphertext).
It is mandatory.
For all other modes, it must be `block_size` bytes longs. It is optional and
when not present it will be given a default value of all zeroes.
counter : callable
(*Only* `MODE_CTR`). A stateful function that returns the next
*counter block*, which is a byte string of `block_size` bytes.
For better performance, use `Crypto.Util.Counter`.
segment_size : integer
(*Only* `MODE_CFB`).The number of bits the plaintext and ciphertext
are segmented in.
It must be a multiple of 8. If 0 or not specified, it will be assumed to be 8.
:Return: an `CAST128Cipher` object
"""
return CAST128Cipher(key, *args, **kwargs)
#: Electronic Code Book (ECB). See `blockalgo.MODE_ECB`.
MODE_ECB = 1
#: Cipher-Block Chaining (CBC). See `blockalgo.MODE_CBC`.
MODE_CBC = 2
#: Cipher FeedBack (CFB). See `blockalgo.MODE_CFB`.
MODE_CFB = 3
#: This mode should not be used.
MODE_PGP = 4
#: Output FeedBack (OFB). See `blockalgo.MODE_OFB`.
MODE_OFB = 5
#: CounTer Mode (CTR). See `blockalgo.MODE_CTR`.
MODE_CTR = 6
#: OpenPGP Mode. See `blockalgo.MODE_OPENPGP`.
MODE_OPENPGP = 7
#: Size of a data block (in bytes)
block_size = 8
#: Size of a key (in bytes)
key_size = range(5,16+1)

View file

@ -1,255 +1,255 @@
# -*- coding: utf-8 -*-
#
# Cipher/PKCS1_OAEP.py : PKCS#1 OAEP
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
"""RSA encryption protocol according to PKCS#1 OAEP
See RFC3447__ or the `original RSA Labs specification`__ .
This scheme is more properly called ``RSAES-OAEP``.
As an example, a sender may encrypt a message in this way:
>>> from Crypto.Cipher import PKCS1_OAEP
>>> from Crypto.PublicKey import RSA
>>>
>>> message = 'To be encrypted'
>>> key = RSA.importKey(open('pubkey.der').read())
>>> cipher = PKCS1_OAEP.new(key)
>>> ciphertext = cipher.encrypt(message)
At the receiver side, decryption can be done using the private part of
the RSA key:
>>> key = RSA.importKey(open('privkey.der').read())
>>> cipher = PKCS1_OAP.new(key)
>>> message = cipher.decrypt(ciphertext)
:undocumented: __revision__, __package__
.. __: http://www.ietf.org/rfc/rfc3447.txt
.. __: http://www.rsa.com/rsalabs/node.asp?id=2125.
"""
__revision__ = "$Id$"
__all__ = [ 'new', 'PKCS1OAEP_Cipher' ]
import Crypto.Signature.PKCS1_PSS
import Crypto.Hash.SHA
from Crypto.Util.py3compat import *
import Crypto.Util.number
from Crypto.Util.number import ceil_div
from Crypto.Util.strxor import strxor
class PKCS1OAEP_Cipher:
"""This cipher can perform PKCS#1 v1.5 OAEP encryption or decryption."""
def __init__(self, key, hashAlgo, mgfunc, label):
"""Initialize this PKCS#1 OAEP cipher object.
:Parameters:
key : an RSA key object
If a private half is given, both encryption and decryption are possible.
If a public half is given, only encryption is possible.
hashAlgo : hash object
The hash function to use. This can be a module under `Crypto.Hash`
or an existing hash object created from any of such modules. If not specified,
`Crypto.Hash.SHA` (that is, SHA-1) is used.
mgfunc : callable
A mask generation function that accepts two parameters: a string to
use as seed, and the lenth of the mask to generate, in bytes.
If not specified, the standard MGF1 is used (a safe choice).
label : string
A label to apply to this particular encryption. If not specified,
an empty string is used. Specifying a label does not improve
security.
:attention: Modify the mask generation function only if you know what you are doing.
Sender and receiver must use the same one.
"""
self._key = key
if hashAlgo:
self._hashObj = hashAlgo
else:
self._hashObj = Crypto.Hash.SHA
if mgfunc:
self._mgf = mgfunc
else:
self._mgf = lambda x,y: Crypto.Signature.PKCS1_PSS.MGF1(x,y,self._hashObj)
self._label = label
def can_encrypt(self):
"""Return True/1 if this cipher object can be used for encryption."""
return self._key.can_encrypt()
def can_decrypt(self):
"""Return True/1 if this cipher object can be used for decryption."""
return self._key.can_decrypt()
def encrypt(self, message):
"""Produce the PKCS#1 OAEP encryption of a message.
This function is named ``RSAES-OAEP-ENCRYPT``, and is specified in
section 7.1.1 of RFC3447.
:Parameters:
message : string
The message to encrypt, also known as plaintext. It can be of
variable length, but not longer than the RSA modulus (in bytes)
minus 2, minus twice the hash output size.
:Return: A string, the ciphertext in which the message is encrypted.
It is as long as the RSA modulus (in bytes).
:Raise ValueError:
If the RSA key length is not sufficiently long to deal with the given
message.
"""
# TODO: Verify the key is RSA
randFunc = self._key._randfunc
# See 7.1.1 in RFC3447
modBits = Crypto.Util.number.size(self._key.n)
k = ceil_div(modBits,8) # Convert from bits to bytes
hLen = self._hashObj.digest_size
mLen = len(message)
# Step 1b
ps_len = k-mLen-2*hLen-2
if ps_len<0:
raise ValueError("Plaintext is too long.")
# Step 2a
lHash = self._hashObj.new(self._label).digest()
# Step 2b
ps = bchr(0x00)*ps_len
# Step 2c
db = lHash + ps + bchr(0x01) + message
# Step 2d
ros = randFunc(hLen)
# Step 2e
dbMask = self._mgf(ros, k-hLen-1)
# Step 2f
maskedDB = strxor(db, dbMask)
# Step 2g
seedMask = self._mgf(maskedDB, hLen)
# Step 2h
maskedSeed = strxor(ros, seedMask)
# Step 2i
em = bchr(0x00) + maskedSeed + maskedDB
# Step 3a (OS2IP), step 3b (RSAEP), part of step 3c (I2OSP)
m = self._key.encrypt(em, 0)[0]
# Complete step 3c (I2OSP)
c = bchr(0x00)*(k-len(m)) + m
return c
def decrypt(self, ct):
"""Decrypt a PKCS#1 OAEP ciphertext.
This function is named ``RSAES-OAEP-DECRYPT``, and is specified in
section 7.1.2 of RFC3447.
:Parameters:
ct : string
The ciphertext that contains the message to recover.
:Return: A string, the original message.
:Raise ValueError:
If the ciphertext length is incorrect, or if the decryption does not
succeed.
:Raise TypeError:
If the RSA key has no private half.
"""
# TODO: Verify the key is RSA
# See 7.1.2 in RFC3447
modBits = Crypto.Util.number.size(self._key.n)
k = ceil_div(modBits,8) # Convert from bits to bytes
hLen = self._hashObj.digest_size
# Step 1b and 1c
if len(ct) != k or k<hLen+2:
raise ValueError("Ciphertext with incorrect length.")
# Step 2a (O2SIP), 2b (RSADP), and part of 2c (I2OSP)
m = self._key.decrypt(ct)
# Complete step 2c (I2OSP)
em = bchr(0x00)*(k-len(m)) + m
# Step 3a
lHash = self._hashObj.new(self._label).digest()
# Step 3b
y = em[0]
# y must be 0, but we MUST NOT check it here in order not to
# allow attacks like Manger's (http://dl.acm.org/citation.cfm?id=704143)
maskedSeed = em[1:hLen+1]
maskedDB = em[hLen+1:]
# Step 3c
seedMask = self._mgf(maskedDB, hLen)
# Step 3d
seed = strxor(maskedSeed, seedMask)
# Step 3e
dbMask = self._mgf(seed, k-hLen-1)
# Step 3f
db = strxor(maskedDB, dbMask)
# Step 3g
valid = 1
one = db[hLen:].find(bchr(0x01))
lHash1 = db[:hLen]
if lHash1!=lHash:
valid = 0
if one<0:
valid = 0
if bord(y)!=0:
valid = 0
if not valid:
raise ValueError("Incorrect decryption.")
# Step 4
return db[hLen+one+1:]
def new(key, hashAlgo=None, mgfunc=None, label=b('')):
"""Return a cipher object `PKCS1OAEP_Cipher` that can be used to perform PKCS#1 OAEP encryption or decryption.
:Parameters:
key : RSA key object
The key to use to encrypt or decrypt the message. This is a `Crypto.PublicKey.RSA` object.
Decryption is only possible if *key* is a private RSA key.
hashAlgo : hash object
The hash function to use. This can be a module under `Crypto.Hash`
or an existing hash object created from any of such modules. If not specified,
`Crypto.Hash.SHA` (that is, SHA-1) is used.
mgfunc : callable
A mask generation function that accepts two parameters: a string to
use as seed, and the lenth of the mask to generate, in bytes.
If not specified, the standard MGF1 is used (a safe choice).
label : string
A label to apply to this particular encryption. If not specified,
an empty string is used. Specifying a label does not improve
security.
:attention: Modify the mask generation function only if you know what you are doing.
Sender and receiver must use the same one.
"""
return PKCS1OAEP_Cipher(key, hashAlgo, mgfunc, label)
# -*- coding: utf-8 -*-
#
# Cipher/PKCS1_OAEP.py : PKCS#1 OAEP
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
"""RSA encryption protocol according to PKCS#1 OAEP
See RFC3447__ or the `original RSA Labs specification`__ .
This scheme is more properly called ``RSAES-OAEP``.
As an example, a sender may encrypt a message in this way:
>>> from Crypto.Cipher import PKCS1_OAEP
>>> from Crypto.PublicKey import RSA
>>>
>>> message = 'To be encrypted'
>>> key = RSA.importKey(open('pubkey.der').read())
>>> cipher = PKCS1_OAEP.new(key)
>>> ciphertext = cipher.encrypt(message)
At the receiver side, decryption can be done using the private part of
the RSA key:
>>> key = RSA.importKey(open('privkey.der').read())
>>> cipher = PKCS1_OAP.new(key)
>>> message = cipher.decrypt(ciphertext)
:undocumented: __revision__, __package__
.. __: http://www.ietf.org/rfc/rfc3447.txt
.. __: http://www.rsa.com/rsalabs/node.asp?id=2125.
"""
__revision__ = "$Id$"
__all__ = [ 'new', 'PKCS1OAEP_Cipher' ]
import Crypto.Signature.PKCS1_PSS
import Crypto.Hash.SHA
from Crypto.Util.py3compat import *
import Crypto.Util.number
from Crypto.Util.number import ceil_div
from Crypto.Util.strxor import strxor
class PKCS1OAEP_Cipher:
"""This cipher can perform PKCS#1 v1.5 OAEP encryption or decryption."""
def __init__(self, key, hashAlgo, mgfunc, label):
"""Initialize this PKCS#1 OAEP cipher object.
:Parameters:
key : an RSA key object
If a private half is given, both encryption and decryption are possible.
If a public half is given, only encryption is possible.
hashAlgo : hash object
The hash function to use. This can be a module under `Crypto.Hash`
or an existing hash object created from any of such modules. If not specified,
`Crypto.Hash.SHA` (that is, SHA-1) is used.
mgfunc : callable
A mask generation function that accepts two parameters: a string to
use as seed, and the lenth of the mask to generate, in bytes.
If not specified, the standard MGF1 is used (a safe choice).
label : string
A label to apply to this particular encryption. If not specified,
an empty string is used. Specifying a label does not improve
security.
:attention: Modify the mask generation function only if you know what you are doing.
Sender and receiver must use the same one.
"""
self._key = key
if hashAlgo:
self._hashObj = hashAlgo
else:
self._hashObj = Crypto.Hash.SHA
if mgfunc:
self._mgf = mgfunc
else:
self._mgf = lambda x,y: Crypto.Signature.PKCS1_PSS.MGF1(x,y,self._hashObj)
self._label = label
def can_encrypt(self):
"""Return True/1 if this cipher object can be used for encryption."""
return self._key.can_encrypt()
def can_decrypt(self):
"""Return True/1 if this cipher object can be used for decryption."""
return self._key.can_decrypt()
def encrypt(self, message):
"""Produce the PKCS#1 OAEP encryption of a message.
This function is named ``RSAES-OAEP-ENCRYPT``, and is specified in
section 7.1.1 of RFC3447.
:Parameters:
message : string
The message to encrypt, also known as plaintext. It can be of
variable length, but not longer than the RSA modulus (in bytes)
minus 2, minus twice the hash output size.
:Return: A string, the ciphertext in which the message is encrypted.
It is as long as the RSA modulus (in bytes).
:Raise ValueError:
If the RSA key length is not sufficiently long to deal with the given
message.
"""
# TODO: Verify the key is RSA
randFunc = self._key._randfunc
# See 7.1.1 in RFC3447
modBits = Crypto.Util.number.size(self._key.n)
k = ceil_div(modBits,8) # Convert from bits to bytes
hLen = self._hashObj.digest_size
mLen = len(message)
# Step 1b
ps_len = k-mLen-2*hLen-2
if ps_len<0:
raise ValueError("Plaintext is too long.")
# Step 2a
lHash = self._hashObj.new(self._label).digest()
# Step 2b
ps = bchr(0x00)*ps_len
# Step 2c
db = lHash + ps + bchr(0x01) + message
# Step 2d
ros = randFunc(hLen)
# Step 2e
dbMask = self._mgf(ros, k-hLen-1)
# Step 2f
maskedDB = strxor(db, dbMask)
# Step 2g
seedMask = self._mgf(maskedDB, hLen)
# Step 2h
maskedSeed = strxor(ros, seedMask)
# Step 2i
em = bchr(0x00) + maskedSeed + maskedDB
# Step 3a (OS2IP), step 3b (RSAEP), part of step 3c (I2OSP)
m = self._key.encrypt(em, 0)[0]
# Complete step 3c (I2OSP)
c = bchr(0x00)*(k-len(m)) + m
return c
def decrypt(self, ct):
"""Decrypt a PKCS#1 OAEP ciphertext.
This function is named ``RSAES-OAEP-DECRYPT``, and is specified in
section 7.1.2 of RFC3447.
:Parameters:
ct : string
The ciphertext that contains the message to recover.
:Return: A string, the original message.
:Raise ValueError:
If the ciphertext length is incorrect, or if the decryption does not
succeed.
:Raise TypeError:
If the RSA key has no private half.
"""
# TODO: Verify the key is RSA
# See 7.1.2 in RFC3447
modBits = Crypto.Util.number.size(self._key.n)
k = ceil_div(modBits,8) # Convert from bits to bytes
hLen = self._hashObj.digest_size
# Step 1b and 1c
if len(ct) != k or k<hLen+2:
raise ValueError("Ciphertext with incorrect length.")
# Step 2a (O2SIP), 2b (RSADP), and part of 2c (I2OSP)
m = self._key.decrypt(ct)
# Complete step 2c (I2OSP)
em = bchr(0x00)*(k-len(m)) + m
# Step 3a
lHash = self._hashObj.new(self._label).digest()
# Step 3b
y = em[0]
# y must be 0, but we MUST NOT check it here in order not to
# allow attacks like Manger's (http://dl.acm.org/citation.cfm?id=704143)
maskedSeed = em[1:hLen+1]
maskedDB = em[hLen+1:]
# Step 3c
seedMask = self._mgf(maskedDB, hLen)
# Step 3d
seed = strxor(maskedSeed, seedMask)
# Step 3e
dbMask = self._mgf(seed, k-hLen-1)
# Step 3f
db = strxor(maskedDB, dbMask)
# Step 3g
valid = 1
one = db[hLen:].find(bchr(0x01))
lHash1 = db[:hLen]
if lHash1!=lHash:
valid = 0
if one<0:
valid = 0
if bord(y)!=0:
valid = 0
if not valid:
raise ValueError("Incorrect decryption.")
# Step 4
return db[hLen+one+1:]
def new(key, hashAlgo=None, mgfunc=None, label=b('')):
"""Return a cipher object `PKCS1OAEP_Cipher` that can be used to perform PKCS#1 OAEP encryption or decryption.
:Parameters:
key : RSA key object
The key to use to encrypt or decrypt the message. This is a `Crypto.PublicKey.RSA` object.
Decryption is only possible if *key* is a private RSA key.
hashAlgo : hash object
The hash function to use. This can be a module under `Crypto.Hash`
or an existing hash object created from any of such modules. If not specified,
`Crypto.Hash.SHA` (that is, SHA-1) is used.
mgfunc : callable
A mask generation function that accepts two parameters: a string to
use as seed, and the lenth of the mask to generate, in bytes.
If not specified, the standard MGF1 is used (a safe choice).
label : string
A label to apply to this particular encryption. If not specified,
an empty string is used. Specifying a label does not improve
security.
:attention: Modify the mask generation function only if you know what you are doing.
Sender and receiver must use the same one.
"""
return PKCS1OAEP_Cipher(key, hashAlgo, mgfunc, label)

View file

@ -1,226 +1,226 @@
# -*- coding: utf-8 -*-
#
# Cipher/PKCS1-v1_5.py : PKCS#1 v1.5
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
"""RSA encryption protocol according to PKCS#1 v1.5
See RFC3447__ or the `original RSA Labs specification`__ .
This scheme is more properly called ``RSAES-PKCS1-v1_5``.
**If you are designing a new protocol, consider using the more robust PKCS#1 OAEP.**
As an example, a sender may encrypt a message in this way:
>>> from Crypto.Cipher import PKCS1_v1_5
>>> from Crypto.PublicKey import RSA
>>> from Crypto.Hash import SHA
>>>
>>> message = 'To be encrypted'
>>> h = SHA.new(message)
>>>
>>> key = RSA.importKey(open('pubkey.der').read())
>>> cipher = PKCS1_v1_5.new(key)
>>> ciphertext = cipher.encrypt(message+h.digest())
At the receiver side, decryption can be done using the private part of
the RSA key:
>>> From Crypto.Hash import SHA
>>> from Crypto import Random
>>>
>>> key = RSA.importKey(open('privkey.der').read())
>>>
>>> dsize = SHA.digest_size
>>> sentinel = Random.new().read(15+dsize) # Let's assume that average data length is 15
>>>
>>> cipher = PKCS1_v1_5.new(key)
>>> message = cipher.decrypt(ciphertext, sentinel)
>>>
>>> digest = SHA.new(message[:-dsize]).digest()
>>> if digest==message[-dsize:]: # Note how we DO NOT look for the sentinel
>>> print "Encryption was correct."
>>> else:
>>> print "Encryption was not correct."
:undocumented: __revision__, __package__
.. __: http://www.ietf.org/rfc/rfc3447.txt
.. __: http://www.rsa.com/rsalabs/node.asp?id=2125.
"""
__revision__ = "$Id$"
__all__ = [ 'new', 'PKCS115_Cipher' ]
from Crypto.Util.number import ceil_div
from Crypto.Util.py3compat import *
import Crypto.Util.number
class PKCS115_Cipher:
"""This cipher can perform PKCS#1 v1.5 RSA encryption or decryption."""
def __init__(self, key):
"""Initialize this PKCS#1 v1.5 cipher object.
:Parameters:
key : an RSA key object
If a private half is given, both encryption and decryption are possible.
If a public half is given, only encryption is possible.
"""
self._key = key
def can_encrypt(self):
"""Return True if this cipher object can be used for encryption."""
return self._key.can_encrypt()
def can_decrypt(self):
"""Return True if this cipher object can be used for decryption."""
return self._key.can_decrypt()
def encrypt(self, message):
"""Produce the PKCS#1 v1.5 encryption of a message.
This function is named ``RSAES-PKCS1-V1_5-ENCRYPT``, and is specified in
section 7.2.1 of RFC3447.
For a complete example see `Crypto.Cipher.PKCS1_v1_5`.
:Parameters:
message : byte string
The message to encrypt, also known as plaintext. It can be of
variable length, but not longer than the RSA modulus (in bytes) minus 11.
:Return: A byte string, the ciphertext in which the message is encrypted.
It is as long as the RSA modulus (in bytes).
:Raise ValueError:
If the RSA key length is not sufficiently long to deal with the given
message.
"""
# TODO: Verify the key is RSA
randFunc = self._key._randfunc
# See 7.2.1 in RFC3447
modBits = Crypto.Util.number.size(self._key.n)
k = ceil_div(modBits,8) # Convert from bits to bytes
mLen = len(message)
# Step 1
if mLen > k-11:
raise ValueError("Plaintext is too long.")
# Step 2a
class nonZeroRandByte:
def __init__(self, rf): self.rf=rf
def __call__(self, c):
while bord(c)==0x00: c=self.rf(1)[0]
return c
ps = tobytes(list(map(nonZeroRandByte(randFunc), randFunc(k-mLen-3))))
# Step 2b
em = b('\x00\x02') + ps + bchr(0x00) + message
# Step 3a (OS2IP), step 3b (RSAEP), part of step 3c (I2OSP)
m = self._key.encrypt(em, 0)[0]
# Complete step 3c (I2OSP)
c = bchr(0x00)*(k-len(m)) + m
return c
def decrypt(self, ct, sentinel):
"""Decrypt a PKCS#1 v1.5 ciphertext.
This function is named ``RSAES-PKCS1-V1_5-DECRYPT``, and is specified in
section 7.2.2 of RFC3447.
For a complete example see `Crypto.Cipher.PKCS1_v1_5`.
:Parameters:
ct : byte string
The ciphertext that contains the message to recover.
sentinel : any type
The object to return to indicate that an error was detected during decryption.
:Return: A byte string. It is either the original message or the ``sentinel`` (in case of an error).
:Raise ValueError:
If the ciphertext length is incorrect
:Raise TypeError:
If the RSA key has no private half.
:attention:
You should **never** let the party who submitted the ciphertext know that
this function returned the ``sentinel`` value.
Armed with such knowledge (for a fair amount of carefully crafted but invalid ciphertexts),
an attacker is able to recontruct the plaintext of any other encryption that were carried out
with the same RSA public key (see `Bleichenbacher's`__ attack).
In general, it should not be possible for the other party to distinguish
whether processing at the server side failed because the value returned
was a ``sentinel`` as opposed to a random, invalid message.
In fact, the second option is not that unlikely: encryption done according to PKCS#1 v1.5
embeds no good integrity check. There is roughly one chance
in 2^16 for a random ciphertext to be returned as a valid message
(although random looking).
It is therefore advisabled to:
1. Select as ``sentinel`` a value that resembles a plausable random, invalid message.
2. Not report back an error as soon as you detect a ``sentinel`` value.
Put differently, you should not explicitly check if the returned value is the ``sentinel`` or not.
3. Cover all possible errors with a single, generic error indicator.
4. Embed into the definition of ``message`` (at the protocol level) a digest (e.g. ``SHA-1``).
It is recommended for it to be the rightmost part ``message``.
5. Where possible, monitor the number of errors due to ciphertexts originating from the same party,
and slow down the rate of the requests from such party (or even blacklist it altogether).
**If you are designing a new protocol, consider using the more robust PKCS#1 OAEP.**
.. __: http://www.bell-labs.com/user/bleichen/papers/pkcs.ps
"""
# TODO: Verify the key is RSA
# See 7.2.1 in RFC3447
modBits = Crypto.Util.number.size(self._key.n)
k = ceil_div(modBits,8) # Convert from bits to bytes
# Step 1
if len(ct) != k:
raise ValueError("Ciphertext with incorrect length.")
# Step 2a (O2SIP), 2b (RSADP), and part of 2c (I2OSP)
m = self._key.decrypt(ct)
# Complete step 2c (I2OSP)
em = bchr(0x00)*(k-len(m)) + m
# Step 3
sep = em.find(bchr(0x00),2)
if not em.startswith(b('\x00\x02')) or sep<10:
return sentinel
# Step 4
return em[sep+1:]
def new(key):
"""Return a cipher object `PKCS115_Cipher` that can be used to perform PKCS#1 v1.5 encryption or decryption.
:Parameters:
key : RSA key object
The key to use to encrypt or decrypt the message. This is a `Crypto.PublicKey.RSA` object.
Decryption is only possible if *key* is a private RSA key.
"""
return PKCS115_Cipher(key)
# -*- coding: utf-8 -*-
#
# Cipher/PKCS1-v1_5.py : PKCS#1 v1.5
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
"""RSA encryption protocol according to PKCS#1 v1.5
See RFC3447__ or the `original RSA Labs specification`__ .
This scheme is more properly called ``RSAES-PKCS1-v1_5``.
**If you are designing a new protocol, consider using the more robust PKCS#1 OAEP.**
As an example, a sender may encrypt a message in this way:
>>> from Crypto.Cipher import PKCS1_v1_5
>>> from Crypto.PublicKey import RSA
>>> from Crypto.Hash import SHA
>>>
>>> message = 'To be encrypted'
>>> h = SHA.new(message)
>>>
>>> key = RSA.importKey(open('pubkey.der').read())
>>> cipher = PKCS1_v1_5.new(key)
>>> ciphertext = cipher.encrypt(message+h.digest())
At the receiver side, decryption can be done using the private part of
the RSA key:
>>> From Crypto.Hash import SHA
>>> from Crypto import Random
>>>
>>> key = RSA.importKey(open('privkey.der').read())
>>>
>>> dsize = SHA.digest_size
>>> sentinel = Random.new().read(15+dsize) # Let's assume that average data length is 15
>>>
>>> cipher = PKCS1_v1_5.new(key)
>>> message = cipher.decrypt(ciphertext, sentinel)
>>>
>>> digest = SHA.new(message[:-dsize]).digest()
>>> if digest==message[-dsize:]: # Note how we DO NOT look for the sentinel
>>> print "Encryption was correct."
>>> else:
>>> print "Encryption was not correct."
:undocumented: __revision__, __package__
.. __: http://www.ietf.org/rfc/rfc3447.txt
.. __: http://www.rsa.com/rsalabs/node.asp?id=2125.
"""
__revision__ = "$Id$"
__all__ = [ 'new', 'PKCS115_Cipher' ]
from Crypto.Util.number import ceil_div
from Crypto.Util.py3compat import *
import Crypto.Util.number
class PKCS115_Cipher:
"""This cipher can perform PKCS#1 v1.5 RSA encryption or decryption."""
def __init__(self, key):
"""Initialize this PKCS#1 v1.5 cipher object.
:Parameters:
key : an RSA key object
If a private half is given, both encryption and decryption are possible.
If a public half is given, only encryption is possible.
"""
self._key = key
def can_encrypt(self):
"""Return True if this cipher object can be used for encryption."""
return self._key.can_encrypt()
def can_decrypt(self):
"""Return True if this cipher object can be used for decryption."""
return self._key.can_decrypt()
def encrypt(self, message):
"""Produce the PKCS#1 v1.5 encryption of a message.
This function is named ``RSAES-PKCS1-V1_5-ENCRYPT``, and is specified in
section 7.2.1 of RFC3447.
For a complete example see `Crypto.Cipher.PKCS1_v1_5`.
:Parameters:
message : byte string
The message to encrypt, also known as plaintext. It can be of
variable length, but not longer than the RSA modulus (in bytes) minus 11.
:Return: A byte string, the ciphertext in which the message is encrypted.
It is as long as the RSA modulus (in bytes).
:Raise ValueError:
If the RSA key length is not sufficiently long to deal with the given
message.
"""
# TODO: Verify the key is RSA
randFunc = self._key._randfunc
# See 7.2.1 in RFC3447
modBits = Crypto.Util.number.size(self._key.n)
k = ceil_div(modBits,8) # Convert from bits to bytes
mLen = len(message)
# Step 1
if mLen > k-11:
raise ValueError("Plaintext is too long.")
# Step 2a
class nonZeroRandByte:
def __init__(self, rf): self.rf=rf
def __call__(self, c):
while bord(c)==0x00: c=self.rf(1)[0]
return c
ps = tobytes(list(map(nonZeroRandByte(randFunc), randFunc(k-mLen-3))))
# Step 2b
em = b('\x00\x02') + ps + bchr(0x00) + message
# Step 3a (OS2IP), step 3b (RSAEP), part of step 3c (I2OSP)
m = self._key.encrypt(em, 0)[0]
# Complete step 3c (I2OSP)
c = bchr(0x00)*(k-len(m)) + m
return c
def decrypt(self, ct, sentinel):
"""Decrypt a PKCS#1 v1.5 ciphertext.
This function is named ``RSAES-PKCS1-V1_5-DECRYPT``, and is specified in
section 7.2.2 of RFC3447.
For a complete example see `Crypto.Cipher.PKCS1_v1_5`.
:Parameters:
ct : byte string
The ciphertext that contains the message to recover.
sentinel : any type
The object to return to indicate that an error was detected during decryption.
:Return: A byte string. It is either the original message or the ``sentinel`` (in case of an error).
:Raise ValueError:
If the ciphertext length is incorrect
:Raise TypeError:
If the RSA key has no private half.
:attention:
You should **never** let the party who submitted the ciphertext know that
this function returned the ``sentinel`` value.
Armed with such knowledge (for a fair amount of carefully crafted but invalid ciphertexts),
an attacker is able to recontruct the plaintext of any other encryption that were carried out
with the same RSA public key (see `Bleichenbacher's`__ attack).
In general, it should not be possible for the other party to distinguish
whether processing at the server side failed because the value returned
was a ``sentinel`` as opposed to a random, invalid message.
In fact, the second option is not that unlikely: encryption done according to PKCS#1 v1.5
embeds no good integrity check. There is roughly one chance
in 2^16 for a random ciphertext to be returned as a valid message
(although random looking).
It is therefore advisabled to:
1. Select as ``sentinel`` a value that resembles a plausable random, invalid message.
2. Not report back an error as soon as you detect a ``sentinel`` value.
Put differently, you should not explicitly check if the returned value is the ``sentinel`` or not.
3. Cover all possible errors with a single, generic error indicator.
4. Embed into the definition of ``message`` (at the protocol level) a digest (e.g. ``SHA-1``).
It is recommended for it to be the rightmost part ``message``.
5. Where possible, monitor the number of errors due to ciphertexts originating from the same party,
and slow down the rate of the requests from such party (or even blacklist it altogether).
**If you are designing a new protocol, consider using the more robust PKCS#1 OAEP.**
.. __: http://www.bell-labs.com/user/bleichen/papers/pkcs.ps
"""
# TODO: Verify the key is RSA
# See 7.2.1 in RFC3447
modBits = Crypto.Util.number.size(self._key.n)
k = ceil_div(modBits,8) # Convert from bits to bytes
# Step 1
if len(ct) != k:
raise ValueError("Ciphertext with incorrect length.")
# Step 2a (O2SIP), 2b (RSADP), and part of 2c (I2OSP)
m = self._key.decrypt(ct)
# Complete step 2c (I2OSP)
em = bchr(0x00)*(k-len(m)) + m
# Step 3
sep = em.find(bchr(0x00),2)
if not em.startswith(b('\x00\x02')) or sep<10:
return sentinel
# Step 4
return em[sep+1:]
def new(key):
"""Return a cipher object `PKCS115_Cipher` that can be used to perform PKCS#1 v1.5 encryption or decryption.
:Parameters:
key : RSA key object
The key to use to encrypt or decrypt the message. This is a `Crypto.PublicKey.RSA` object.
Decryption is only possible if *key* is a private RSA key.
"""
return PKCS115_Cipher(key)

View file

@ -1,86 +1,86 @@
# -*- coding: utf-8 -*-
#
# Cipher/XOR.py : XOR
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
"""XOR toy cipher
XOR is one the simplest stream ciphers. Encryption and decryption are
performed by XOR-ing data with a keystream made by contatenating
the key.
Do not use it for real applications!
:undocumented: __revision__, __package__
"""
__revision__ = "$Id$"
from Crypto.Cipher import _XOR
class XORCipher:
"""XOR cipher object"""
def __init__(self, key, *args, **kwargs):
"""Initialize a XOR cipher object
See also `new()` at the module level."""
self._cipher = _XOR.new(key, *args, **kwargs)
self.block_size = self._cipher.block_size
self.key_size = self._cipher.key_size
def encrypt(self, plaintext):
"""Encrypt a piece of data.
:Parameters:
plaintext : byte string
The piece of data to encrypt. It can be of any size.
:Return: the encrypted data (byte string, as long as the
plaintext).
"""
return self._cipher.encrypt(plaintext)
def decrypt(self, ciphertext):
"""Decrypt a piece of data.
:Parameters:
ciphertext : byte string
The piece of data to decrypt. It can be of any size.
:Return: the decrypted data (byte string, as long as the
ciphertext).
"""
return self._cipher.decrypt(ciphertext)
def new(key, *args, **kwargs):
"""Create a new XOR cipher
:Parameters:
key : byte string
The secret key to use in the symmetric cipher.
Its length may vary from 1 to 32 bytes.
:Return: an `XORCipher` object
"""
return XORCipher(key, *args, **kwargs)
#: Size of a data block (in bytes)
block_size = 1
#: Size of a key (in bytes)
key_size = range(1,32+1)
# -*- coding: utf-8 -*-
#
# Cipher/XOR.py : XOR
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
"""XOR toy cipher
XOR is one the simplest stream ciphers. Encryption and decryption are
performed by XOR-ing data with a keystream made by contatenating
the key.
Do not use it for real applications!
:undocumented: __revision__, __package__
"""
__revision__ = "$Id$"
from Crypto.Cipher import _XOR
class XORCipher:
"""XOR cipher object"""
def __init__(self, key, *args, **kwargs):
"""Initialize a XOR cipher object
See also `new()` at the module level."""
self._cipher = _XOR.new(key, *args, **kwargs)
self.block_size = self._cipher.block_size
self.key_size = self._cipher.key_size
def encrypt(self, plaintext):
"""Encrypt a piece of data.
:Parameters:
plaintext : byte string
The piece of data to encrypt. It can be of any size.
:Return: the encrypted data (byte string, as long as the
plaintext).
"""
return self._cipher.encrypt(plaintext)
def decrypt(self, ciphertext):
"""Decrypt a piece of data.
:Parameters:
ciphertext : byte string
The piece of data to decrypt. It can be of any size.
:Return: the decrypted data (byte string, as long as the
ciphertext).
"""
return self._cipher.decrypt(ciphertext)
def new(key, *args, **kwargs):
"""Create a new XOR cipher
:Parameters:
key : byte string
The secret key to use in the symmetric cipher.
Its length may vary from 1 to 32 bytes.
:Return: an `XORCipher` object
"""
return XORCipher(key, *args, **kwargs)
#: Size of a data block (in bytes)
block_size = 1
#: Size of a key (in bytes)
key_size = range(1,32+1)

View file

@ -1,212 +1,212 @@
# HMAC.py - Implements the HMAC algorithm as described by RFC 2104.
#
# ===================================================================
# Portions Copyright (c) 2001, 2002, 2003 Python Software Foundation;
# All Rights Reserved
#
# This file contains code from the Python 2.2 hmac.py module (the
# "Original Code"), with modifications made after it was incorporated
# into PyCrypto (the "Modifications").
#
# To the best of our knowledge, the Python Software Foundation is the
# copyright holder of the Original Code, and has licensed it under the
# Python 2.2 license. See the file LEGAL/copy/LICENSE.python-2.2 for
# details.
#
# The Modifications to this file are dedicated to the public domain.
# To the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever. No rights are
# reserved.
#
# 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.
# ===================================================================
"""HMAC (Hash-based Message Authentication Code) algorithm
HMAC is a MAC defined in RFC2104_ and FIPS-198_ and constructed using
a cryptograpic hash algorithm.
It is usually named *HMAC-X*, where *X* is the hash algorithm; for
instance *HMAC-SHA1* or *HMAC-MD5*.
The strength of an HMAC depends on:
- the strength of the hash algorithm
- the length and entropy of the secret key
An example of possible usage is the following:
>>> from Crypto.Hash import HMAC
>>>
>>> secret = b'Swordfish'
>>> h = HMAC.new(secret)
>>> h.update(b'Hello')
>>> print h.hexdigest()
.. _RFC2104: http://www.ietf.org/rfc/rfc2104.txt
.. _FIPS-198: http://csrc.nist.gov/publications/fips/fips198/fips-198a.pdf
"""
# This is just a copy of the Python 2.2 HMAC module, modified to work when
# used on versions of Python before 2.2.
__revision__ = "$Id$"
__all__ = ['new', 'digest_size', 'HMAC' ]
from Crypto.Util.strxor import strxor_c
from Crypto.Util.py3compat import *
#: The size of the authentication tag produced by the MAC.
#: It matches the digest size on the underlying
#: hashing module used.
digest_size = None
class HMAC:
"""Class that implements HMAC"""
#: The size of the authentication tag produced by the MAC.
#: It matches the digest size on the underlying
#: hashing module used.
digest_size = None
def __init__(self, key, msg = None, digestmod = None):
"""Create a new HMAC object.
:Parameters:
key : byte string
secret key for the MAC object.
It must be long enough to match the expected security level of the
MAC. However, there is no benefit in using keys longer than the
`digest_size` of the underlying hash algorithm.
msg : byte string
The very first chunk of the message to authenticate.
It is equivalent to an early call to `update()`. Optional.
:Parameter digestmod:
The hash algorithm the HMAC is based on.
Default is `Crypto.Hash.MD5`.
:Type digestmod:
A hash module or object instantiated from `Crypto.Hash`
"""
if digestmod is None:
from . import MD5
digestmod = MD5
self.digestmod = digestmod
self.outer = digestmod.new()
self.inner = digestmod.new()
try:
self.digest_size = digestmod.digest_size
except AttributeError:
self.digest_size = len(self.outer.digest())
try:
# The block size is 128 bytes for SHA384 and SHA512 and 64 bytes
# for the others hash function
blocksize = digestmod.block_size
except AttributeError:
blocksize = 64
ipad = 0x36
opad = 0x5C
if len(key) > blocksize:
key = digestmod.new(key).digest()
key = key + bchr(0) * (blocksize - len(key))
self.outer.update(strxor_c(key, opad))
self.inner.update(strxor_c(key, ipad))
if (msg):
self.update(msg)
def update(self, msg):
"""Continue authentication of a message by consuming the next chunk of data.
Repeated calls are equivalent to a single call with the concatenation
of all the arguments. In other words:
>>> m.update(a); m.update(b)
is equivalent to:
>>> m.update(a+b)
:Parameters:
msg : byte string
The next chunk of the message being authenticated
"""
self.inner.update(msg)
def copy(self):
"""Return a copy ("clone") of the MAC object.
The copy will have the same internal state as the original MAC
object.
This can be used to efficiently compute the MAC of strings that
share a common initial substring.
:Returns: An `HMAC` object
"""
other = HMAC(b(""))
other.digestmod = self.digestmod
other.inner = self.inner.copy()
other.outer = self.outer.copy()
return other
def digest(self):
"""Return the **binary** (non-printable) MAC of the message that has
been authenticated so far.
This method does not change the state of the MAC object.
You can continue updating the object after calling this function.
:Return: A byte string of `digest_size` bytes. It may contain non-ASCII
characters, including null bytes.
"""
h = self.outer.copy()
h.update(self.inner.digest())
return h.digest()
def hexdigest(self):
"""Return the **printable** MAC of the message that has been
authenticated so far.
This method does not change the state of the MAC object.
:Return: A string of 2* `digest_size` bytes. It contains only
hexadecimal ASCII digits.
"""
return "".join(["%02x" % bord(x)
for x in tuple(self.digest())])
def new(key, msg = None, digestmod = None):
"""Create a new HMAC object.
:Parameters:
key : byte string
key for the MAC object.
It must be long enough to match the expected security level of the
MAC. However, there is no benefit in using keys longer than the
`digest_size` of the underlying hash algorithm.
msg : byte string
The very first chunk of the message to authenticate.
It is equivalent to an early call to `HMAC.update()`.
Optional.
:Parameter digestmod:
The hash to use to implement the HMAC. Default is `Crypto.Hash.MD5`.
:Type digestmod:
A hash module or instantiated object from `Crypto.Hash`
:Returns: An `HMAC` object
"""
return HMAC(key, msg, digestmod)
# HMAC.py - Implements the HMAC algorithm as described by RFC 2104.
#
# ===================================================================
# Portions Copyright (c) 2001, 2002, 2003 Python Software Foundation;
# All Rights Reserved
#
# This file contains code from the Python 2.2 hmac.py module (the
# "Original Code"), with modifications made after it was incorporated
# into PyCrypto (the "Modifications").
#
# To the best of our knowledge, the Python Software Foundation is the
# copyright holder of the Original Code, and has licensed it under the
# Python 2.2 license. See the file LEGAL/copy/LICENSE.python-2.2 for
# details.
#
# The Modifications to this file are dedicated to the public domain.
# To the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever. No rights are
# reserved.
#
# 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.
# ===================================================================
"""HMAC (Hash-based Message Authentication Code) algorithm
HMAC is a MAC defined in RFC2104_ and FIPS-198_ and constructed using
a cryptograpic hash algorithm.
It is usually named *HMAC-X*, where *X* is the hash algorithm; for
instance *HMAC-SHA1* or *HMAC-MD5*.
The strength of an HMAC depends on:
- the strength of the hash algorithm
- the length and entropy of the secret key
An example of possible usage is the following:
>>> from Crypto.Hash import HMAC
>>>
>>> secret = b'Swordfish'
>>> h = HMAC.new(secret)
>>> h.update(b'Hello')
>>> print h.hexdigest()
.. _RFC2104: http://www.ietf.org/rfc/rfc2104.txt
.. _FIPS-198: http://csrc.nist.gov/publications/fips/fips198/fips-198a.pdf
"""
# This is just a copy of the Python 2.2 HMAC module, modified to work when
# used on versions of Python before 2.2.
__revision__ = "$Id$"
__all__ = ['new', 'digest_size', 'HMAC' ]
from Crypto.Util.strxor import strxor_c
from Crypto.Util.py3compat import *
#: The size of the authentication tag produced by the MAC.
#: It matches the digest size on the underlying
#: hashing module used.
digest_size = None
class HMAC:
"""Class that implements HMAC"""
#: The size of the authentication tag produced by the MAC.
#: It matches the digest size on the underlying
#: hashing module used.
digest_size = None
def __init__(self, key, msg = None, digestmod = None):
"""Create a new HMAC object.
:Parameters:
key : byte string
secret key for the MAC object.
It must be long enough to match the expected security level of the
MAC. However, there is no benefit in using keys longer than the
`digest_size` of the underlying hash algorithm.
msg : byte string
The very first chunk of the message to authenticate.
It is equivalent to an early call to `update()`. Optional.
:Parameter digestmod:
The hash algorithm the HMAC is based on.
Default is `Crypto.Hash.MD5`.
:Type digestmod:
A hash module or object instantiated from `Crypto.Hash`
"""
if digestmod is None:
from . import MD5
digestmod = MD5
self.digestmod = digestmod
self.outer = digestmod.new()
self.inner = digestmod.new()
try:
self.digest_size = digestmod.digest_size
except AttributeError:
self.digest_size = len(self.outer.digest())
try:
# The block size is 128 bytes for SHA384 and SHA512 and 64 bytes
# for the others hash function
blocksize = digestmod.block_size
except AttributeError:
blocksize = 64
ipad = 0x36
opad = 0x5C
if len(key) > blocksize:
key = digestmod.new(key).digest()
key = key + bchr(0) * (blocksize - len(key))
self.outer.update(strxor_c(key, opad))
self.inner.update(strxor_c(key, ipad))
if (msg):
self.update(msg)
def update(self, msg):
"""Continue authentication of a message by consuming the next chunk of data.
Repeated calls are equivalent to a single call with the concatenation
of all the arguments. In other words:
>>> m.update(a); m.update(b)
is equivalent to:
>>> m.update(a+b)
:Parameters:
msg : byte string
The next chunk of the message being authenticated
"""
self.inner.update(msg)
def copy(self):
"""Return a copy ("clone") of the MAC object.
The copy will have the same internal state as the original MAC
object.
This can be used to efficiently compute the MAC of strings that
share a common initial substring.
:Returns: An `HMAC` object
"""
other = HMAC(b(""))
other.digestmod = self.digestmod
other.inner = self.inner.copy()
other.outer = self.outer.copy()
return other
def digest(self):
"""Return the **binary** (non-printable) MAC of the message that has
been authenticated so far.
This method does not change the state of the MAC object.
You can continue updating the object after calling this function.
:Return: A byte string of `digest_size` bytes. It may contain non-ASCII
characters, including null bytes.
"""
h = self.outer.copy()
h.update(self.inner.digest())
return h.digest()
def hexdigest(self):
"""Return the **printable** MAC of the message that has been
authenticated so far.
This method does not change the state of the MAC object.
:Return: A string of 2* `digest_size` bytes. It contains only
hexadecimal ASCII digits.
"""
return "".join(["%02x" % bord(x)
for x in tuple(self.digest())])
def new(key, msg = None, digestmod = None):
"""Create a new HMAC object.
:Parameters:
key : byte string
key for the MAC object.
It must be long enough to match the expected security level of the
MAC. However, there is no benefit in using keys longer than the
`digest_size` of the underlying hash algorithm.
msg : byte string
The very first chunk of the message to authenticate.
It is equivalent to an early call to `HMAC.update()`.
Optional.
:Parameter digestmod:
The hash to use to implement the HMAC. Default is `Crypto.Hash.MD5`.
:Type digestmod:
A hash module or instantiated object from `Crypto.Hash`
:Returns: An `HMAC` object
"""
return HMAC(key, msg, digestmod)

View file

@ -1,97 +1,97 @@
# -*- coding: utf-8 -*-
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
"""MD5 cryptographic hash algorithm.
MD5 is specified in RFC1321_ and produces the 128 bit digest of a message.
>>> from Crypto.Hash import MD5
>>>
>>> h = MD5.new()
>>> h.update(b'Hello')
>>> print h.hexdigest()
MD5 stand for Message Digest version 5, and it was invented by Rivest in 1991.
This algorithm is insecure. Do not use it for new designs.
.. _RFC1321: http://tools.ietf.org/html/rfc1321
"""
_revision__ = "$Id$"
__all__ = ['new', 'digest_size', 'MD5Hash' ]
from Crypto.Util.py3compat import *
from Crypto.Hash.hashalgo import HashAlgo
try:
# The md5 module is deprecated in Python 2.6, so use hashlib when possible.
import hashlib
hashFactory = hashlib.md5
except ImportError:
from . import md5
hashFactory = md5
class MD5Hash(HashAlgo):
"""Class that implements an MD5 hash
:undocumented: block_size
"""
#: ASN.1 Object identifier (OID)::
#:
#: id-md5 OBJECT IDENTIFIER ::= {
#: iso(1) member-body(2) us(840) rsadsi(113549)
#: digestAlgorithm(2) 5
#: }
#:
#: This value uniquely identifies the MD5 algorithm.
oid = b('\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x05')
digest_size = 16
block_size = 64
def __init__(self, data=None):
HashAlgo.__init__(self, hashFactory, data)
def new(self, data=None):
return MD5Hash(data)
def new(data=None):
"""Return a fresh instance of the hash object.
:Parameters:
data : byte string
The very first chunk of the message to hash.
It is equivalent to an early call to `MD5Hash.update()`.
Optional.
:Return: A `MD5Hash` object
"""
return MD5Hash().new(data)
#: The size of the resulting hash in bytes.
digest_size = MD5Hash.digest_size
#: The internal block size of the hash algorithm in bytes.
block_size = MD5Hash.block_size
# -*- coding: utf-8 -*-
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
"""MD5 cryptographic hash algorithm.
MD5 is specified in RFC1321_ and produces the 128 bit digest of a message.
>>> from Crypto.Hash import MD5
>>>
>>> h = MD5.new()
>>> h.update(b'Hello')
>>> print h.hexdigest()
MD5 stand for Message Digest version 5, and it was invented by Rivest in 1991.
This algorithm is insecure. Do not use it for new designs.
.. _RFC1321: http://tools.ietf.org/html/rfc1321
"""
_revision__ = "$Id$"
__all__ = ['new', 'digest_size', 'MD5Hash' ]
from Crypto.Util.py3compat import *
from Crypto.Hash.hashalgo import HashAlgo
try:
# The md5 module is deprecated in Python 2.6, so use hashlib when possible.
import hashlib
hashFactory = hashlib.md5
except ImportError:
from . import md5
hashFactory = md5
class MD5Hash(HashAlgo):
"""Class that implements an MD5 hash
:undocumented: block_size
"""
#: ASN.1 Object identifier (OID)::
#:
#: id-md5 OBJECT IDENTIFIER ::= {
#: iso(1) member-body(2) us(840) rsadsi(113549)
#: digestAlgorithm(2) 5
#: }
#:
#: This value uniquely identifies the MD5 algorithm.
oid = b('\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x05')
digest_size = 16
block_size = 64
def __init__(self, data=None):
HashAlgo.__init__(self, hashFactory, data)
def new(self, data=None):
return MD5Hash(data)
def new(data=None):
"""Return a fresh instance of the hash object.
:Parameters:
data : byte string
The very first chunk of the message to hash.
It is equivalent to an early call to `MD5Hash.update()`.
Optional.
:Return: A `MD5Hash` object
"""
return MD5Hash().new(data)
#: The size of the resulting hash in bytes.
digest_size = MD5Hash.digest_size
#: The internal block size of the hash algorithm in bytes.
block_size = MD5Hash.block_size

View file

@ -1,98 +1,98 @@
# -*- coding: utf-8 -*-
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
"""SHA-1 cryptographic hash algorithm.
SHA-1_ produces the 160 bit digest of a message.
>>> from Crypto.Hash import SHA
>>>
>>> h = SHA.new()
>>> h.update(b'Hello')
>>> print h.hexdigest()
*SHA* stands for Secure Hash Algorithm.
This algorithm is not considered secure. Do not use it for new designs.
.. _SHA-1: http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf
"""
_revision__ = "$Id$"
__all__ = ['new', 'digest_size', 'SHA1Hash' ]
from Crypto.Util.py3compat import *
from Crypto.Hash.hashalgo import HashAlgo
try:
# The sha module is deprecated in Python 2.6, so use hashlib when possible.
import hashlib
hashFactory = hashlib.sha1
except ImportError:
from . import sha
hashFactory = sha
class SHA1Hash(HashAlgo):
"""Class that implements a SHA-1 hash
:undocumented: block_size
"""
#: ASN.1 Object identifier (OID)::
#:
#: id-sha1 OBJECT IDENTIFIER ::= {
#: iso(1) identified-organization(3) oiw(14) secsig(3)
#: algorithms(2) 26
#: }
#:
#: This value uniquely identifies the SHA-1 algorithm.
oid = b('\x06\x05\x2b\x0e\x03\x02\x1a')
digest_size = 20
block_size = 64
def __init__(self, data=None):
HashAlgo.__init__(self, hashFactory, data)
def new(self, data=None):
return SHA1Hash(data)
def new(data=None):
"""Return a fresh instance of the hash object.
:Parameters:
data : byte string
The very first chunk of the message to hash.
It is equivalent to an early call to `SHA1Hash.update()`.
Optional.
:Return: A `SHA1Hash` object
"""
return SHA1Hash().new(data)
#: The size of the resulting hash in bytes.
digest_size = SHA1Hash.digest_size
#: The internal block size of the hash algorithm in bytes.
block_size = SHA1Hash.block_size
# -*- coding: utf-8 -*-
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
"""SHA-1 cryptographic hash algorithm.
SHA-1_ produces the 160 bit digest of a message.
>>> from Crypto.Hash import SHA
>>>
>>> h = SHA.new()
>>> h.update(b'Hello')
>>> print h.hexdigest()
*SHA* stands for Secure Hash Algorithm.
This algorithm is not considered secure. Do not use it for new designs.
.. _SHA-1: http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf
"""
_revision__ = "$Id$"
__all__ = ['new', 'digest_size', 'SHA1Hash' ]
from Crypto.Util.py3compat import *
from Crypto.Hash.hashalgo import HashAlgo
try:
# The sha module is deprecated in Python 2.6, so use hashlib when possible.
import hashlib
hashFactory = hashlib.sha1
except ImportError:
from . import sha
hashFactory = sha
class SHA1Hash(HashAlgo):
"""Class that implements a SHA-1 hash
:undocumented: block_size
"""
#: ASN.1 Object identifier (OID)::
#:
#: id-sha1 OBJECT IDENTIFIER ::= {
#: iso(1) identified-organization(3) oiw(14) secsig(3)
#: algorithms(2) 26
#: }
#:
#: This value uniquely identifies the SHA-1 algorithm.
oid = b('\x06\x05\x2b\x0e\x03\x02\x1a')
digest_size = 20
block_size = 64
def __init__(self, data=None):
HashAlgo.__init__(self, hashFactory, data)
def new(self, data=None):
return SHA1Hash(data)
def new(data=None):
"""Return a fresh instance of the hash object.
:Parameters:
data : byte string
The very first chunk of the message to hash.
It is equivalent to an early call to `SHA1Hash.update()`.
Optional.
:Return: A `SHA1Hash` object
"""
return SHA1Hash().new(data)
#: The size of the resulting hash in bytes.
digest_size = SHA1Hash.digest_size
#: The internal block size of the hash algorithm in bytes.
block_size = SHA1Hash.block_size

Binary file not shown.

Binary file not shown.

View file

@ -1,320 +1,320 @@
#
# AllOrNothing.py : all-or-nothing package transformations
#
# Part of the Python Cryptography Toolkit
#
# Written by Andrew M. Kuchling and others
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
"""This file implements all-or-nothing package transformations.
An all-or-nothing package transformation is one in which some text is
transformed into message blocks, such that all blocks must be obtained before
the reverse transformation can be applied. Thus, if any blocks are corrupted
or lost, the original message cannot be reproduced.
An all-or-nothing package transformation is not encryption, although a block
cipher algorithm is used. The encryption key is randomly generated and is
extractable from the message blocks.
This class implements the All-Or-Nothing package transformation algorithm
described in:
Ronald L. Rivest. "All-Or-Nothing Encryption and The Package Transform"
http://theory.lcs.mit.edu/~rivest/fusion.pdf
"""
__revision__ = "$Id$"
import operator
import sys
from Crypto.Util.number import bytes_to_long, long_to_bytes
from Crypto.Util.py3compat import *
from functools import reduce
def isInt(x):
test = 0
try:
test += x
except TypeError:
return 0
return 1
class AllOrNothing:
"""Class implementing the All-or-Nothing package transform.
Methods for subclassing:
_inventkey(key_size):
Returns a randomly generated key. Subclasses can use this to
implement better random key generating algorithms. The default
algorithm is probably not very cryptographically secure.
"""
def __init__(self, ciphermodule, mode=None, IV=None):
"""AllOrNothing(ciphermodule, mode=None, IV=None)
ciphermodule is a module implementing the cipher algorithm to
use. It must provide the PEP272 interface.
Note that the encryption key is randomly generated
automatically when needed. Optional arguments mode and IV are
passed directly through to the ciphermodule.new() method; they
are the feedback mode and initialization vector to use. All
three arguments must be the same for the object used to create
the digest, and to undigest'ify the message blocks.
"""
self.__ciphermodule = ciphermodule
self.__mode = mode
self.__IV = IV
self.__key_size = ciphermodule.key_size
if not isInt(self.__key_size) or self.__key_size==0:
self.__key_size = 16
__K0digit = bchr(0x69)
def digest(self, text):
"""digest(text:string) : [string]
Perform the All-or-Nothing package transform on the given
string. Output is a list of message blocks describing the
transformed text, where each block is a string of bit length equal
to the ciphermodule's block_size.
"""
# generate a random session key and K0, the key used to encrypt the
# hash blocks. Rivest calls this a fixed, publically-known encryption
# key, but says nothing about the security implications of this key or
# how to choose it.
key = self._inventkey(self.__key_size)
K0 = self.__K0digit * self.__key_size
# we need two cipher objects here, one that is used to encrypt the
# message blocks and one that is used to encrypt the hashes. The
# former uses the randomly generated key, while the latter uses the
# well-known key.
mcipher = self.__newcipher(key)
hcipher = self.__newcipher(K0)
# Pad the text so that its length is a multiple of the cipher's
# block_size. Pad with trailing spaces, which will be eliminated in
# the undigest() step.
block_size = self.__ciphermodule.block_size
padbytes = block_size - (len(text) % block_size)
text = text + b(' ') * padbytes
# Run through the algorithm:
# s: number of message blocks (size of text / block_size)
# input sequence: m1, m2, ... ms
# random key K' (`key' in the code)
# Compute output sequence: m'1, m'2, ... m's' for s' = s + 1
# Let m'i = mi ^ E(K', i) for i = 1, 2, 3, ..., s
# Let m's' = K' ^ h1 ^ h2 ^ ... hs
# where hi = E(K0, m'i ^ i) for i = 1, 2, ... s
#
# The one complication I add is that the last message block is hard
# coded to the number of padbytes added, so that these can be stripped
# during the undigest() step
s = divmod(len(text), block_size)[0]
blocks = []
hashes = []
for i in range(1, s+1):
start = (i-1) * block_size
end = start + block_size
mi = text[start:end]
assert len(mi) == block_size
cipherblock = mcipher.encrypt(long_to_bytes(i, block_size))
mticki = bytes_to_long(mi) ^ bytes_to_long(cipherblock)
blocks.append(mticki)
# calculate the hash block for this block
hi = hcipher.encrypt(long_to_bytes(mticki ^ i, block_size))
hashes.append(bytes_to_long(hi))
# Add the padbytes length as a message block
i = i + 1
cipherblock = mcipher.encrypt(long_to_bytes(i, block_size))
mticki = padbytes ^ bytes_to_long(cipherblock)
blocks.append(mticki)
# calculate this block's hash
hi = hcipher.encrypt(long_to_bytes(mticki ^ i, block_size))
hashes.append(bytes_to_long(hi))
# Now calculate the last message block of the sequence 1..s'. This
# will contain the random session key XOR'd with all the hash blocks,
# so that for undigest(), once all the hash blocks are calculated, the
# session key can be trivially extracted. Calculating all the hash
# blocks requires that all the message blocks be received, thus the
# All-or-Nothing algorithm succeeds.
mtick_stick = bytes_to_long(key) ^ reduce(operator.xor, hashes)
blocks.append(mtick_stick)
# we convert the blocks to strings since in Python, byte sequences are
# always represented as strings. This is more consistent with the
# model that encryption and hash algorithms always operate on strings.
return [long_to_bytes(i,self.__ciphermodule.block_size) for i in blocks]
def undigest(self, blocks):
"""undigest(blocks : [string]) : string
Perform the reverse package transformation on a list of message
blocks. Note that the ciphermodule used for both transformations
must be the same. blocks is a list of strings of bit length
equal to the ciphermodule's block_size.
"""
# better have at least 2 blocks, for the padbytes package and the hash
# block accumulator
if len(blocks) < 2:
raise ValueError("List must be at least length 2.")
# blocks is a list of strings. We need to deal with them as long
# integers
blocks = list(map(bytes_to_long, blocks))
# Calculate the well-known key, to which the hash blocks are
# encrypted, and create the hash cipher.
K0 = self.__K0digit * self.__key_size
hcipher = self.__newcipher(K0)
block_size = self.__ciphermodule.block_size
# Since we have all the blocks (or this method would have been called
# prematurely), we can calculate all the hash blocks.
hashes = []
for i in range(1, len(blocks)):
mticki = blocks[i-1] ^ i
hi = hcipher.encrypt(long_to_bytes(mticki, block_size))
hashes.append(bytes_to_long(hi))
# now we can calculate K' (key). remember the last block contains
# m's' which we don't include here
key = blocks[-1] ^ reduce(operator.xor, hashes)
# and now we can create the cipher object
mcipher = self.__newcipher(long_to_bytes(key, self.__key_size))
# And we can now decode the original message blocks
parts = []
for i in range(1, len(blocks)):
cipherblock = mcipher.encrypt(long_to_bytes(i, block_size))
mi = blocks[i-1] ^ bytes_to_long(cipherblock)
parts.append(mi)
# The last message block contains the number of pad bytes appended to
# the original text string, such that its length was an even multiple
# of the cipher's block_size. This number should be small enough that
# the conversion from long integer to integer should never overflow
padbytes = int(parts[-1])
text = b('').join(map(long_to_bytes, parts[:-1]))
return text[:-padbytes]
def _inventkey(self, key_size):
# Return key_size random bytes
from Crypto import Random
return Random.new().read(key_size)
def __newcipher(self, key):
if self.__mode is None and self.__IV is None:
return self.__ciphermodule.new(key)
elif self.__IV is None:
return self.__ciphermodule.new(key, self.__mode)
else:
return self.__ciphermodule.new(key, self.__mode, self.__IV)
if __name__ == '__main__':
import sys
import getopt
import base64
usagemsg = '''\
Test module usage: %(program)s [-c cipher] [-l] [-h]
Where:
--cipher module
-c module
Cipher module to use. Default: %(ciphermodule)s
--aslong
-l
Print the encoded message blocks as long integers instead of base64
encoded strings
--help
-h
Print this help message
'''
ciphermodule = 'AES'
aslong = 0
def usage(code, msg=None):
if msg:
print(msg)
print(usagemsg % {'program': sys.argv[0],
'ciphermodule': ciphermodule})
sys.exit(code)
try:
opts, args = getopt.getopt(sys.argv[1:],
'c:l', ['cipher=', 'aslong'])
except getopt.error as msg:
usage(1, msg)
if args:
usage(1, 'Too many arguments')
for opt, arg in opts:
if opt in ('-h', '--help'):
usage(0)
elif opt in ('-c', '--cipher'):
ciphermodule = arg
elif opt in ('-l', '--aslong'):
aslong = 1
# ugly hack to force __import__ to give us the end-path module
module = __import__('Crypto.Cipher.'+ciphermodule, None, None, ['new'])
x = AllOrNothing(module)
print('Original text:\n==========')
print(__doc__)
print('==========')
msgblocks = x.digest(b(__doc__))
print('message blocks:')
for i, blk in zip(list(range(len(msgblocks))), msgblocks):
# base64 adds a trailing newline
print(' %3d' % i, end=' ')
if aslong:
print(bytes_to_long(blk))
else:
print(base64.encodestring(blk)[:-1])
#
# get a new undigest-only object so there's no leakage
y = AllOrNothing(module)
text = y.undigest(msgblocks)
if text == b(__doc__):
print('They match!')
else:
print('They differ!')
#
# AllOrNothing.py : all-or-nothing package transformations
#
# Part of the Python Cryptography Toolkit
#
# Written by Andrew M. Kuchling and others
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
"""This file implements all-or-nothing package transformations.
An all-or-nothing package transformation is one in which some text is
transformed into message blocks, such that all blocks must be obtained before
the reverse transformation can be applied. Thus, if any blocks are corrupted
or lost, the original message cannot be reproduced.
An all-or-nothing package transformation is not encryption, although a block
cipher algorithm is used. The encryption key is randomly generated and is
extractable from the message blocks.
This class implements the All-Or-Nothing package transformation algorithm
described in:
Ronald L. Rivest. "All-Or-Nothing Encryption and The Package Transform"
http://theory.lcs.mit.edu/~rivest/fusion.pdf
"""
__revision__ = "$Id$"
import operator
import sys
from Crypto.Util.number import bytes_to_long, long_to_bytes
from Crypto.Util.py3compat import *
from functools import reduce
def isInt(x):
test = 0
try:
test += x
except TypeError:
return 0
return 1
class AllOrNothing:
"""Class implementing the All-or-Nothing package transform.
Methods for subclassing:
_inventkey(key_size):
Returns a randomly generated key. Subclasses can use this to
implement better random key generating algorithms. The default
algorithm is probably not very cryptographically secure.
"""
def __init__(self, ciphermodule, mode=None, IV=None):
"""AllOrNothing(ciphermodule, mode=None, IV=None)
ciphermodule is a module implementing the cipher algorithm to
use. It must provide the PEP272 interface.
Note that the encryption key is randomly generated
automatically when needed. Optional arguments mode and IV are
passed directly through to the ciphermodule.new() method; they
are the feedback mode and initialization vector to use. All
three arguments must be the same for the object used to create
the digest, and to undigest'ify the message blocks.
"""
self.__ciphermodule = ciphermodule
self.__mode = mode
self.__IV = IV
self.__key_size = ciphermodule.key_size
if not isInt(self.__key_size) or self.__key_size==0:
self.__key_size = 16
__K0digit = bchr(0x69)
def digest(self, text):
"""digest(text:string) : [string]
Perform the All-or-Nothing package transform on the given
string. Output is a list of message blocks describing the
transformed text, where each block is a string of bit length equal
to the ciphermodule's block_size.
"""
# generate a random session key and K0, the key used to encrypt the
# hash blocks. Rivest calls this a fixed, publically-known encryption
# key, but says nothing about the security implications of this key or
# how to choose it.
key = self._inventkey(self.__key_size)
K0 = self.__K0digit * self.__key_size
# we need two cipher objects here, one that is used to encrypt the
# message blocks and one that is used to encrypt the hashes. The
# former uses the randomly generated key, while the latter uses the
# well-known key.
mcipher = self.__newcipher(key)
hcipher = self.__newcipher(K0)
# Pad the text so that its length is a multiple of the cipher's
# block_size. Pad with trailing spaces, which will be eliminated in
# the undigest() step.
block_size = self.__ciphermodule.block_size
padbytes = block_size - (len(text) % block_size)
text = text + b(' ') * padbytes
# Run through the algorithm:
# s: number of message blocks (size of text / block_size)
# input sequence: m1, m2, ... ms
# random key K' (`key' in the code)
# Compute output sequence: m'1, m'2, ... m's' for s' = s + 1
# Let m'i = mi ^ E(K', i) for i = 1, 2, 3, ..., s
# Let m's' = K' ^ h1 ^ h2 ^ ... hs
# where hi = E(K0, m'i ^ i) for i = 1, 2, ... s
#
# The one complication I add is that the last message block is hard
# coded to the number of padbytes added, so that these can be stripped
# during the undigest() step
s = divmod(len(text), block_size)[0]
blocks = []
hashes = []
for i in range(1, s+1):
start = (i-1) * block_size
end = start + block_size
mi = text[start:end]
assert len(mi) == block_size
cipherblock = mcipher.encrypt(long_to_bytes(i, block_size))
mticki = bytes_to_long(mi) ^ bytes_to_long(cipherblock)
blocks.append(mticki)
# calculate the hash block for this block
hi = hcipher.encrypt(long_to_bytes(mticki ^ i, block_size))
hashes.append(bytes_to_long(hi))
# Add the padbytes length as a message block
i = i + 1
cipherblock = mcipher.encrypt(long_to_bytes(i, block_size))
mticki = padbytes ^ bytes_to_long(cipherblock)
blocks.append(mticki)
# calculate this block's hash
hi = hcipher.encrypt(long_to_bytes(mticki ^ i, block_size))
hashes.append(bytes_to_long(hi))
# Now calculate the last message block of the sequence 1..s'. This
# will contain the random session key XOR'd with all the hash blocks,
# so that for undigest(), once all the hash blocks are calculated, the
# session key can be trivially extracted. Calculating all the hash
# blocks requires that all the message blocks be received, thus the
# All-or-Nothing algorithm succeeds.
mtick_stick = bytes_to_long(key) ^ reduce(operator.xor, hashes)
blocks.append(mtick_stick)
# we convert the blocks to strings since in Python, byte sequences are
# always represented as strings. This is more consistent with the
# model that encryption and hash algorithms always operate on strings.
return [long_to_bytes(i,self.__ciphermodule.block_size) for i in blocks]
def undigest(self, blocks):
"""undigest(blocks : [string]) : string
Perform the reverse package transformation on a list of message
blocks. Note that the ciphermodule used for both transformations
must be the same. blocks is a list of strings of bit length
equal to the ciphermodule's block_size.
"""
# better have at least 2 blocks, for the padbytes package and the hash
# block accumulator
if len(blocks) < 2:
raise ValueError("List must be at least length 2.")
# blocks is a list of strings. We need to deal with them as long
# integers
blocks = list(map(bytes_to_long, blocks))
# Calculate the well-known key, to which the hash blocks are
# encrypted, and create the hash cipher.
K0 = self.__K0digit * self.__key_size
hcipher = self.__newcipher(K0)
block_size = self.__ciphermodule.block_size
# Since we have all the blocks (or this method would have been called
# prematurely), we can calculate all the hash blocks.
hashes = []
for i in range(1, len(blocks)):
mticki = blocks[i-1] ^ i
hi = hcipher.encrypt(long_to_bytes(mticki, block_size))
hashes.append(bytes_to_long(hi))
# now we can calculate K' (key). remember the last block contains
# m's' which we don't include here
key = blocks[-1] ^ reduce(operator.xor, hashes)
# and now we can create the cipher object
mcipher = self.__newcipher(long_to_bytes(key, self.__key_size))
# And we can now decode the original message blocks
parts = []
for i in range(1, len(blocks)):
cipherblock = mcipher.encrypt(long_to_bytes(i, block_size))
mi = blocks[i-1] ^ bytes_to_long(cipherblock)
parts.append(mi)
# The last message block contains the number of pad bytes appended to
# the original text string, such that its length was an even multiple
# of the cipher's block_size. This number should be small enough that
# the conversion from long integer to integer should never overflow
padbytes = int(parts[-1])
text = b('').join(map(long_to_bytes, parts[:-1]))
return text[:-padbytes]
def _inventkey(self, key_size):
# Return key_size random bytes
from Crypto import Random
return Random.new().read(key_size)
def __newcipher(self, key):
if self.__mode is None and self.__IV is None:
return self.__ciphermodule.new(key)
elif self.__IV is None:
return self.__ciphermodule.new(key, self.__mode)
else:
return self.__ciphermodule.new(key, self.__mode, self.__IV)
if __name__ == '__main__':
import sys
import getopt
import base64
usagemsg = '''\
Test module usage: %(program)s [-c cipher] [-l] [-h]
Where:
--cipher module
-c module
Cipher module to use. Default: %(ciphermodule)s
--aslong
-l
Print the encoded message blocks as long integers instead of base64
encoded strings
--help
-h
Print this help message
'''
ciphermodule = 'AES'
aslong = 0
def usage(code, msg=None):
if msg:
print(msg)
print(usagemsg % {'program': sys.argv[0],
'ciphermodule': ciphermodule})
sys.exit(code)
try:
opts, args = getopt.getopt(sys.argv[1:],
'c:l', ['cipher=', 'aslong'])
except getopt.error as msg:
usage(1, msg)
if args:
usage(1, 'Too many arguments')
for opt, arg in opts:
if opt in ('-h', '--help'):
usage(0)
elif opt in ('-c', '--cipher'):
ciphermodule = arg
elif opt in ('-l', '--aslong'):
aslong = 1
# ugly hack to force __import__ to give us the end-path module
module = __import__('Crypto.Cipher.'+ciphermodule, None, None, ['new'])
x = AllOrNothing(module)
print('Original text:\n==========')
print(__doc__)
print('==========')
msgblocks = x.digest(b(__doc__))
print('message blocks:')
for i, blk in zip(list(range(len(msgblocks))), msgblocks):
# base64 adds a trailing newline
print(' %3d' % i, end=' ')
if aslong:
print(bytes_to_long(blk))
else:
print(base64.encodestring(blk)[:-1])
#
# get a new undigest-only object so there's no leakage
y = AllOrNothing(module)
text = y.undigest(msgblocks)
if text == b(__doc__):
print('They match!')
else:
print('They differ!')

View file

@ -1,245 +1,245 @@
#
# Chaffing.py : chaffing & winnowing support
#
# Part of the Python Cryptography Toolkit
#
# Written by Andrew M. Kuchling, Barry A. Warsaw, and others
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
#
"""This file implements the chaffing algorithm.
Winnowing and chaffing is a technique for enhancing privacy without requiring
strong encryption. In short, the technique takes a set of authenticated
message blocks (the wheat) and adds a number of chaff blocks which have
randomly chosen data and MAC fields. This means that to an adversary, the
chaff blocks look as valid as the wheat blocks, and so the authentication
would have to be performed on every block. By tailoring the number of chaff
blocks added to the message, the sender can make breaking the message
computationally infeasible. There are many other interesting properties of
the winnow/chaff technique.
For example, say Alice is sending a message to Bob. She packetizes the
message and performs an all-or-nothing transformation on the packets. Then
she authenticates each packet with a message authentication code (MAC). The
MAC is a hash of the data packet, and there is a secret key which she must
share with Bob (key distribution is an exercise left to the reader). She then
adds a serial number to each packet, and sends the packets to Bob.
Bob receives the packets, and using the shared secret authentication key,
authenticates the MACs for each packet. Those packets that have bad MACs are
simply discarded. The remainder are sorted by serial number, and passed
through the reverse all-or-nothing transform. The transform means that an
eavesdropper (say Eve) must acquire all the packets before any of the data can
be read. If even one packet is missing, the data is useless.
There's one twist: by adding chaff packets, Alice and Bob can make Eve's job
much harder, since Eve now has to break the shared secret key, or try every
combination of wheat and chaff packet to read any of the message. The cool
thing is that Bob doesn't need to add any additional code; the chaff packets
are already filtered out because their MACs don't match (in all likelihood --
since the data and MACs for the chaff packets are randomly chosen it is
possible, but very unlikely that a chaff MAC will match the chaff data). And
Alice need not even be the party adding the chaff! She could be completely
unaware that a third party, say Charles, is adding chaff packets to her
messages as they are transmitted.
For more information on winnowing and chaffing see this paper:
Ronald L. Rivest, "Chaffing and Winnowing: Confidentiality without Encryption"
http://theory.lcs.mit.edu/~rivest/chaffing.txt
"""
__revision__ = "$Id$"
from Crypto.Util.number import bytes_to_long
class Chaff:
"""Class implementing the chaff adding algorithm.
Methods for subclasses:
_randnum(size):
Returns a randomly generated number with a byte-length equal
to size. Subclasses can use this to implement better random
data and MAC generating algorithms. The default algorithm is
probably not very cryptographically secure. It is most
important that the chaff data does not contain any patterns
that can be used to discern it from wheat data without running
the MAC.
"""
def __init__(self, factor=1.0, blocksper=1):
"""Chaff(factor:float, blocksper:int)
factor is the number of message blocks to add chaff to,
expressed as a percentage between 0.0 and 1.0. blocksper is
the number of chaff blocks to include for each block being
chaffed. Thus the defaults add one chaff block to every
message block. By changing the defaults, you can adjust how
computationally difficult it could be for an adversary to
brute-force crack the message. The difficulty is expressed
as:
pow(blocksper, int(factor * number-of-blocks))
For ease of implementation, when factor < 1.0, only the first
int(factor*number-of-blocks) message blocks are chaffed.
"""
if not (0.0<=factor<=1.0):
raise ValueError("'factor' must be between 0.0 and 1.0")
if blocksper < 0:
raise ValueError("'blocksper' must be zero or more")
self.__factor = factor
self.__blocksper = blocksper
def chaff(self, blocks):
"""chaff( [(serial-number:int, data:string, MAC:string)] )
: [(int, string, string)]
Add chaff to message blocks. blocks is a list of 3-tuples of the
form (serial-number, data, MAC).
Chaff is created by choosing a random number of the same
byte-length as data, and another random number of the same
byte-length as MAC. The message block's serial number is
placed on the chaff block and all the packet's chaff blocks
are randomly interspersed with the single wheat block. This
method then returns a list of 3-tuples of the same form.
Chaffed blocks will contain multiple instances of 3-tuples
with the same serial number, but the only way to figure out
which blocks are wheat and which are chaff is to perform the
MAC hash and compare values.
"""
chaffedblocks = []
# count is the number of blocks to add chaff to. blocksper is the
# number of chaff blocks to add per message block that is being
# chaffed.
count = len(blocks) * self.__factor
blocksper = list(range(self.__blocksper))
for i, wheat in zip(list(range(len(blocks))), blocks):
# it shouldn't matter which of the n blocks we add chaff to, so for
# ease of implementation, we'll just add them to the first count
# blocks
if i < count:
serial, data, mac = wheat
datasize = len(data)
macsize = len(mac)
addwheat = 1
# add chaff to this block
for j in blocksper:
import sys
chaffdata = self._randnum(datasize)
chaffmac = self._randnum(macsize)
chaff = (serial, chaffdata, chaffmac)
# mix up the order, if the 5th bit is on then put the
# wheat on the list
if addwheat and bytes_to_long(self._randnum(16)) & 0x40:
chaffedblocks.append(wheat)
addwheat = 0
chaffedblocks.append(chaff)
if addwheat:
chaffedblocks.append(wheat)
else:
# just add the wheat
chaffedblocks.append(wheat)
return chaffedblocks
def _randnum(self, size):
from Crypto import Random
return Random.new().read(size)
if __name__ == '__main__':
text = """\
We hold these truths to be self-evident, that all men are created equal, that
they are endowed by their Creator with certain unalienable Rights, that among
these are Life, Liberty, and the pursuit of Happiness. That to secure these
rights, Governments are instituted among Men, deriving their just powers from
the consent of the governed. That whenever any Form of Government becomes
destructive of these ends, it is the Right of the People to alter or to
abolish it, and to institute new Government, laying its foundation on such
principles and organizing its powers in such form, as to them shall seem most
likely to effect their Safety and Happiness.
"""
print('Original text:\n==========')
print(text)
print('==========')
# first transform the text into packets
blocks = [] ; size = 40
for i in range(0, len(text), size):
blocks.append( text[i:i+size] )
# now get MACs for all the text blocks. The key is obvious...
print('Calculating MACs...')
from Crypto.Hash import HMAC, SHA
key = 'Jefferson'
macs = [HMAC.new(key, block, digestmod=SHA).digest()
for block in blocks]
assert len(blocks) == len(macs)
# put these into a form acceptable as input to the chaffing procedure
source = []
m = list(zip(list(range(len(blocks))), blocks, macs))
print(m)
for i, data, mac in m:
source.append((i, data, mac))
# now chaff these
print('Adding chaff...')
c = Chaff(factor=0.5, blocksper=2)
chaffed = c.chaff(source)
from base64 import encodestring
# print the chaffed message blocks. meanwhile, separate the wheat from
# the chaff
wheat = []
print('chaffed message blocks:')
for i, data, mac in chaffed:
# do the authentication
h = HMAC.new(key, data, digestmod=SHA)
pmac = h.digest()
if pmac == mac:
tag = '-->'
wheat.append(data)
else:
tag = ' '
# base64 adds a trailing newline
print(tag, '%3d' % i, \
repr(data), encodestring(mac)[:-1])
# now decode the message packets and check it against the original text
print('Undigesting wheat...')
# PY3K: This is meant to be text, do not change to bytes (data)
newtext = "".join(wheat)
if newtext == text:
print('They match!')
else:
print('They differ!')
#
# Chaffing.py : chaffing & winnowing support
#
# Part of the Python Cryptography Toolkit
#
# Written by Andrew M. Kuchling, Barry A. Warsaw, and others
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
#
"""This file implements the chaffing algorithm.
Winnowing and chaffing is a technique for enhancing privacy without requiring
strong encryption. In short, the technique takes a set of authenticated
message blocks (the wheat) and adds a number of chaff blocks which have
randomly chosen data and MAC fields. This means that to an adversary, the
chaff blocks look as valid as the wheat blocks, and so the authentication
would have to be performed on every block. By tailoring the number of chaff
blocks added to the message, the sender can make breaking the message
computationally infeasible. There are many other interesting properties of
the winnow/chaff technique.
For example, say Alice is sending a message to Bob. She packetizes the
message and performs an all-or-nothing transformation on the packets. Then
she authenticates each packet with a message authentication code (MAC). The
MAC is a hash of the data packet, and there is a secret key which she must
share with Bob (key distribution is an exercise left to the reader). She then
adds a serial number to each packet, and sends the packets to Bob.
Bob receives the packets, and using the shared secret authentication key,
authenticates the MACs for each packet. Those packets that have bad MACs are
simply discarded. The remainder are sorted by serial number, and passed
through the reverse all-or-nothing transform. The transform means that an
eavesdropper (say Eve) must acquire all the packets before any of the data can
be read. If even one packet is missing, the data is useless.
There's one twist: by adding chaff packets, Alice and Bob can make Eve's job
much harder, since Eve now has to break the shared secret key, or try every
combination of wheat and chaff packet to read any of the message. The cool
thing is that Bob doesn't need to add any additional code; the chaff packets
are already filtered out because their MACs don't match (in all likelihood --
since the data and MACs for the chaff packets are randomly chosen it is
possible, but very unlikely that a chaff MAC will match the chaff data). And
Alice need not even be the party adding the chaff! She could be completely
unaware that a third party, say Charles, is adding chaff packets to her
messages as they are transmitted.
For more information on winnowing and chaffing see this paper:
Ronald L. Rivest, "Chaffing and Winnowing: Confidentiality without Encryption"
http://theory.lcs.mit.edu/~rivest/chaffing.txt
"""
__revision__ = "$Id$"
from Crypto.Util.number import bytes_to_long
class Chaff:
"""Class implementing the chaff adding algorithm.
Methods for subclasses:
_randnum(size):
Returns a randomly generated number with a byte-length equal
to size. Subclasses can use this to implement better random
data and MAC generating algorithms. The default algorithm is
probably not very cryptographically secure. It is most
important that the chaff data does not contain any patterns
that can be used to discern it from wheat data without running
the MAC.
"""
def __init__(self, factor=1.0, blocksper=1):
"""Chaff(factor:float, blocksper:int)
factor is the number of message blocks to add chaff to,
expressed as a percentage between 0.0 and 1.0. blocksper is
the number of chaff blocks to include for each block being
chaffed. Thus the defaults add one chaff block to every
message block. By changing the defaults, you can adjust how
computationally difficult it could be for an adversary to
brute-force crack the message. The difficulty is expressed
as:
pow(blocksper, int(factor * number-of-blocks))
For ease of implementation, when factor < 1.0, only the first
int(factor*number-of-blocks) message blocks are chaffed.
"""
if not (0.0<=factor<=1.0):
raise ValueError("'factor' must be between 0.0 and 1.0")
if blocksper < 0:
raise ValueError("'blocksper' must be zero or more")
self.__factor = factor
self.__blocksper = blocksper
def chaff(self, blocks):
"""chaff( [(serial-number:int, data:string, MAC:string)] )
: [(int, string, string)]
Add chaff to message blocks. blocks is a list of 3-tuples of the
form (serial-number, data, MAC).
Chaff is created by choosing a random number of the same
byte-length as data, and another random number of the same
byte-length as MAC. The message block's serial number is
placed on the chaff block and all the packet's chaff blocks
are randomly interspersed with the single wheat block. This
method then returns a list of 3-tuples of the same form.
Chaffed blocks will contain multiple instances of 3-tuples
with the same serial number, but the only way to figure out
which blocks are wheat and which are chaff is to perform the
MAC hash and compare values.
"""
chaffedblocks = []
# count is the number of blocks to add chaff to. blocksper is the
# number of chaff blocks to add per message block that is being
# chaffed.
count = len(blocks) * self.__factor
blocksper = list(range(self.__blocksper))
for i, wheat in zip(list(range(len(blocks))), blocks):
# it shouldn't matter which of the n blocks we add chaff to, so for
# ease of implementation, we'll just add them to the first count
# blocks
if i < count:
serial, data, mac = wheat
datasize = len(data)
macsize = len(mac)
addwheat = 1
# add chaff to this block
for j in blocksper:
import sys
chaffdata = self._randnum(datasize)
chaffmac = self._randnum(macsize)
chaff = (serial, chaffdata, chaffmac)
# mix up the order, if the 5th bit is on then put the
# wheat on the list
if addwheat and bytes_to_long(self._randnum(16)) & 0x40:
chaffedblocks.append(wheat)
addwheat = 0
chaffedblocks.append(chaff)
if addwheat:
chaffedblocks.append(wheat)
else:
# just add the wheat
chaffedblocks.append(wheat)
return chaffedblocks
def _randnum(self, size):
from Crypto import Random
return Random.new().read(size)
if __name__ == '__main__':
text = """\
We hold these truths to be self-evident, that all men are created equal, that
they are endowed by their Creator with certain unalienable Rights, that among
these are Life, Liberty, and the pursuit of Happiness. That to secure these
rights, Governments are instituted among Men, deriving their just powers from
the consent of the governed. That whenever any Form of Government becomes
destructive of these ends, it is the Right of the People to alter or to
abolish it, and to institute new Government, laying its foundation on such
principles and organizing its powers in such form, as to them shall seem most
likely to effect their Safety and Happiness.
"""
print('Original text:\n==========')
print(text)
print('==========')
# first transform the text into packets
blocks = [] ; size = 40
for i in range(0, len(text), size):
blocks.append( text[i:i+size] )
# now get MACs for all the text blocks. The key is obvious...
print('Calculating MACs...')
from Crypto.Hash import HMAC, SHA
key = 'Jefferson'
macs = [HMAC.new(key, block, digestmod=SHA).digest()
for block in blocks]
assert len(blocks) == len(macs)
# put these into a form acceptable as input to the chaffing procedure
source = []
m = list(zip(list(range(len(blocks))), blocks, macs))
print(m)
for i, data, mac in m:
source.append((i, data, mac))
# now chaff these
print('Adding chaff...')
c = Chaff(factor=0.5, blocksper=2)
chaffed = c.chaff(source)
from base64 import encodestring
# print the chaffed message blocks. meanwhile, separate the wheat from
# the chaff
wheat = []
print('chaffed message blocks:')
for i, data, mac in chaffed:
# do the authentication
h = HMAC.new(key, data, digestmod=SHA)
pmac = h.digest()
if pmac == mac:
tag = '-->'
wheat.append(data)
else:
tag = ' '
# base64 adds a trailing newline
print(tag, '%3d' % i, \
repr(data), encodestring(mac)[:-1])
# now decode the message packets and check it against the original text
print('Undigesting wheat...')
# PY3K: This is meant to be text, do not change to bytes (data)
newtext = "".join(wheat)
if newtext == text:
print('They match!')
else:
print('They differ!')

View file

@ -1,123 +1,123 @@
#
# KDF.py : a collection of Key Derivation Functions
#
# Part of the Python Cryptography Toolkit
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
"""This file contains a collection of standard key derivation functions.
A key derivation function derives one or more secondary secret keys from
one primary secret (a master key or a pass phrase).
This is typically done to insulate the secondary keys from each other,
to avoid that leakage of a secondary key compromises the security of the
master key, or to thwart attacks on pass phrases (e.g. via rainbow tables).
:undocumented: __revision__
"""
__revision__ = "$Id$"
import math
import struct
from Crypto.Util.py3compat import *
from Crypto.Hash import SHA as SHA1, HMAC
from Crypto.Util.strxor import strxor
def PBKDF1(password, salt, dkLen, count=1000, hashAlgo=None):
"""Derive one key from a password (or passphrase).
This function performs key derivation according an old version of
the PKCS#5 standard (v1.5).
This algorithm is called ``PBKDF1``. Even though it is still described
in the latest version of the PKCS#5 standard (version 2, or RFC2898),
newer applications should use the more secure and versatile `PBKDF2` instead.
:Parameters:
password : string
The secret password or pass phrase to generate the key from.
salt : byte string
An 8 byte string to use for better protection from dictionary attacks.
This value does not need to be kept secret, but it should be randomly
chosen for each derivation.
dkLen : integer
The length of the desired key. Default is 16 bytes, suitable for instance for `Crypto.Cipher.AES`.
count : integer
The number of iterations to carry out. It's recommended to use at least 1000.
hashAlgo : module
The hash algorithm to use, as a module or an object from the `Crypto.Hash` package.
The digest length must be no shorter than ``dkLen``.
The default algorithm is `SHA1`.
:Return: A byte string of length `dkLen` that can be used as key.
"""
if not hashAlgo:
hashAlgo = SHA1
password = tobytes(password)
pHash = hashAlgo.new(password+salt)
digest = pHash.digest_size
if dkLen>digest:
raise ValueError("Selected hash algorithm has a too short digest (%d bytes)." % digest)
if len(salt)!=8:
raise ValueError("Salt is not 8 bytes long.")
for i in range(count-1):
pHash = pHash.new(pHash.digest())
return pHash.digest()[:dkLen]
def PBKDF2(password, salt, dkLen=16, count=1000, prf=None):
"""Derive one or more keys from a password (or passphrase).
This performs key derivation according to the PKCS#5 standard (v2.0),
by means of the ``PBKDF2`` algorithm.
:Parameters:
password : string
The secret password or pass phrase to generate the key from.
salt : string
A string to use for better protection from dictionary attacks.
This value does not need to be kept secret, but it should be randomly
chosen for each derivation. It is recommended to be at least 8 bytes long.
dkLen : integer
The cumulative length of the desired keys. Default is 16 bytes, suitable for instance for `Crypto.Cipher.AES`.
count : integer
The number of iterations to carry out. It's recommended to use at least 1000.
prf : callable
A pseudorandom function. It must be a function that returns a pseudorandom string
from two parameters: a secret and a salt. If not specified, HMAC-SHA1 is used.
:Return: A byte string of length `dkLen` that can be used as key material.
If you wanted multiple keys, just break up this string into segments of the desired length.
"""
password = tobytes(password)
if prf is None:
prf = lambda p,s: HMAC.new(p,s,SHA1).digest()
key = b('')
i = 1
while len(key)<dkLen:
U = previousU = prf(password,salt+struct.pack(">I", i))
for j in range(count-1):
previousU = t = prf(password,previousU)
U = strxor(U,t)
key += U
i = i + 1
return key[:dkLen]
#
# KDF.py : a collection of Key Derivation Functions
#
# Part of the Python Cryptography Toolkit
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
"""This file contains a collection of standard key derivation functions.
A key derivation function derives one or more secondary secret keys from
one primary secret (a master key or a pass phrase).
This is typically done to insulate the secondary keys from each other,
to avoid that leakage of a secondary key compromises the security of the
master key, or to thwart attacks on pass phrases (e.g. via rainbow tables).
:undocumented: __revision__
"""
__revision__ = "$Id$"
import math
import struct
from Crypto.Util.py3compat import *
from Crypto.Hash import SHA as SHA1, HMAC
from Crypto.Util.strxor import strxor
def PBKDF1(password, salt, dkLen, count=1000, hashAlgo=None):
"""Derive one key from a password (or passphrase).
This function performs key derivation according an old version of
the PKCS#5 standard (v1.5).
This algorithm is called ``PBKDF1``. Even though it is still described
in the latest version of the PKCS#5 standard (version 2, or RFC2898),
newer applications should use the more secure and versatile `PBKDF2` instead.
:Parameters:
password : string
The secret password or pass phrase to generate the key from.
salt : byte string
An 8 byte string to use for better protection from dictionary attacks.
This value does not need to be kept secret, but it should be randomly
chosen for each derivation.
dkLen : integer
The length of the desired key. Default is 16 bytes, suitable for instance for `Crypto.Cipher.AES`.
count : integer
The number of iterations to carry out. It's recommended to use at least 1000.
hashAlgo : module
The hash algorithm to use, as a module or an object from the `Crypto.Hash` package.
The digest length must be no shorter than ``dkLen``.
The default algorithm is `SHA1`.
:Return: A byte string of length `dkLen` that can be used as key.
"""
if not hashAlgo:
hashAlgo = SHA1
password = tobytes(password)
pHash = hashAlgo.new(password+salt)
digest = pHash.digest_size
if dkLen>digest:
raise ValueError("Selected hash algorithm has a too short digest (%d bytes)." % digest)
if len(salt)!=8:
raise ValueError("Salt is not 8 bytes long.")
for i in range(count-1):
pHash = pHash.new(pHash.digest())
return pHash.digest()[:dkLen]
def PBKDF2(password, salt, dkLen=16, count=1000, prf=None):
"""Derive one or more keys from a password (or passphrase).
This performs key derivation according to the PKCS#5 standard (v2.0),
by means of the ``PBKDF2`` algorithm.
:Parameters:
password : string
The secret password or pass phrase to generate the key from.
salt : string
A string to use for better protection from dictionary attacks.
This value does not need to be kept secret, but it should be randomly
chosen for each derivation. It is recommended to be at least 8 bytes long.
dkLen : integer
The cumulative length of the desired keys. Default is 16 bytes, suitable for instance for `Crypto.Cipher.AES`.
count : integer
The number of iterations to carry out. It's recommended to use at least 1000.
prf : callable
A pseudorandom function. It must be a function that returns a pseudorandom string
from two parameters: a secret and a salt. If not specified, HMAC-SHA1 is used.
:Return: A byte string of length `dkLen` that can be used as key material.
If you wanted multiple keys, just break up this string into segments of the desired length.
"""
password = tobytes(password)
if prf is None:
prf = lambda p,s: HMAC.new(p,s,SHA1).digest()
key = b('')
i = 1
while len(key)<dkLen:
U = previousU = prf(password,salt+struct.pack(">I", i))
for j in range(count-1):
previousU = t = prf(password,previousU)
U = strxor(U,t)
key += U
i = i + 1
return key[:dkLen]

View file

@ -1,379 +1,379 @@
# -*- coding: utf-8 -*-
#
# PublicKey/DSA.py : DSA signature primitive
#
# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
"""DSA public-key signature algorithm.
DSA_ is a widespread public-key signature algorithm. Its security is
based on the discrete logarithm problem (DLP_). Given a cyclic
group, a generator *g*, and an element *h*, it is hard
to find an integer *x* such that *g^x = h*. The problem is believed
to be difficult, and it has been proved such (and therefore secure) for
more than 30 years.
The group is actually a sub-group over the integers modulo *p*, with *p* prime.
The sub-group order is *q*, which is prime too; it always holds that *(p-1)* is a multiple of *q*.
The cryptographic strength is linked to the magnitude of *p* and *q*.
The signer holds a value *x* (*0<x<q-1*) as private key, and its public
key (*y* where *y=g^x mod p*) is distributed.
In 2012, a sufficient size is deemed to be 2048 bits for *p* and 256 bits for *q*.
For more information, see the most recent ECRYPT_ report.
DSA is reasonably secure for new designs.
The algorithm can only be used for authentication (digital signature).
DSA cannot be used for confidentiality (encryption).
The values *(p,q,g)* are called *domain parameters*;
they are not sensitive but must be shared by both parties (the signer and the verifier).
Different signers can share the same domain parameters with no security
concerns.
The DSA signature is twice as big as the size of *q* (64 bytes if *q* is 256 bit
long).
This module provides facilities for generating new DSA keys and for constructing
them from known components. DSA keys allows you to perform basic signing and
verification.
>>> from Crypto.Random import random
>>> from Crypto.PublicKey import DSA
>>> from Crypto.Hash import SHA
>>>
>>> message = "Hello"
>>> key = DSA.generate(1024)
>>> h = SHA.new(message).digest()
>>> k = random.StrongRandom().randint(1,key.q-1)
>>> sig = key.sign(h,k)
>>> ...
>>> if key.verify(h,sig):
>>> print "OK"
>>> else:
>>> print "Incorrect signature"
.. _DSA: http://en.wikipedia.org/wiki/Digital_Signature_Algorithm
.. _DLP: http://www.cosic.esat.kuleuven.be/publications/talk-78.pdf
.. _ECRYPT: http://www.ecrypt.eu.org/documents/D.SPA.17.pdf
"""
__revision__ = "$Id$"
__all__ = ['generate', 'construct', 'error', 'DSAImplementation', '_DSAobj']
import sys
if sys.version_info[0] == 2 and sys.version_info[1] == 1:
from Crypto.Util.py21compat import *
from Crypto.PublicKey import _DSA, _slowmath, pubkey
from Crypto import Random
try:
from Crypto.PublicKey import _fastmath
except ImportError:
_fastmath = None
class _DSAobj(pubkey.pubkey):
"""Class defining an actual DSA key.
:undocumented: __getstate__, __setstate__, __repr__, __getattr__
"""
#: Dictionary of DSA parameters.
#:
#: A public key will only have the following entries:
#:
#: - **y**, the public key.
#: - **g**, the generator.
#: - **p**, the modulus.
#: - **q**, the order of the sub-group.
#:
#: A private key will also have:
#:
#: - **x**, the private key.
keydata = ['y', 'g', 'p', 'q', 'x']
def __init__(self, implementation, key):
self.implementation = implementation
self.key = key
def __getattr__(self, attrname):
if attrname in self.keydata:
# For backward compatibility, allow the user to get (not set) the
# DSA key parameters directly from this object.
return getattr(self.key, attrname)
else:
raise AttributeError("%s object has no %r attribute" % (self.__class__.__name__, attrname,))
def sign(self, M, K):
"""Sign a piece of data with DSA.
:Parameter M: The piece of data to sign with DSA. It may
not be longer in bit size than the sub-group order (*q*).
:Type M: byte string or long
:Parameter K: A secret number, chosen randomly in the closed
range *[1,q-1]*.
:Type K: long (recommended) or byte string (not recommended)
:attention: selection of *K* is crucial for security. Generating a
random number larger than *q* and taking the modulus by *q* is
**not** secure, since smaller values will occur more frequently.
Generating a random number systematically smaller than *q-1*
(e.g. *floor((q-1)/8)* random bytes) is also **not** secure. In general,
it shall not be possible for an attacker to know the value of `any
bit of K`__.
:attention: The number *K* shall not be reused for any other
operation and shall be discarded immediately.
:attention: M must be a digest cryptographic hash, otherwise
an attacker may mount an existential forgery attack.
:Return: A tuple with 2 longs.
.. __: http://www.di.ens.fr/~pnguyen/pub_NgSh00.htm
"""
return pubkey.pubkey.sign(self, M, K)
def verify(self, M, signature):
"""Verify the validity of a DSA signature.
:Parameter M: The expected message.
:Type M: byte string or long
:Parameter signature: The DSA signature to verify.
:Type signature: A tuple with 2 longs as return by `sign`
:Return: True if the signature is correct, False otherwise.
"""
return pubkey.pubkey.verify(self, M, signature)
def _encrypt(self, c, K):
raise TypeError("DSA cannot encrypt")
def _decrypt(self, c):
raise TypeError("DSA cannot decrypt")
def _blind(self, m, r):
raise TypeError("DSA cannot blind")
def _unblind(self, m, r):
raise TypeError("DSA cannot unblind")
def _sign(self, m, k):
return self.key._sign(m, k)
def _verify(self, m, sig):
(r, s) = sig
return self.key._verify(m, r, s)
def has_private(self):
return self.key.has_private()
def size(self):
return self.key.size()
def can_blind(self):
return False
def can_encrypt(self):
return False
def can_sign(self):
return True
def publickey(self):
return self.implementation.construct((self.key.y, self.key.g, self.key.p, self.key.q))
def __getstate__(self):
d = {}
for k in self.keydata:
try:
d[k] = getattr(self.key, k)
except AttributeError:
pass
return d
def __setstate__(self, d):
if not hasattr(self, 'implementation'):
self.implementation = DSAImplementation()
t = []
for k in self.keydata:
if k not in d:
break
t.append(d[k])
self.key = self.implementation._math.dsa_construct(*tuple(t))
def __repr__(self):
attrs = []
for k in self.keydata:
if k == 'p':
attrs.append("p(%d)" % (self.size()+1,))
elif hasattr(self.key, k):
attrs.append(k)
if self.has_private():
attrs.append("private")
# PY3K: This is meant to be text, do not change to bytes (data)
return "<%s @0x%x %s>" % (self.__class__.__name__, id(self), ",".join(attrs))
class DSAImplementation(object):
"""
A DSA key factory.
This class is only internally used to implement the methods of the
`Crypto.PublicKey.DSA` module.
"""
def __init__(self, **kwargs):
"""Create a new DSA key factory.
:Keywords:
use_fast_math : bool
Specify which mathematic library to use:
- *None* (default). Use fastest math available.
- *True* . Use fast math.
- *False* . Use slow math.
default_randfunc : callable
Specify how to collect random data:
- *None* (default). Use Random.new().read().
- not *None* . Use the specified function directly.
:Raise RuntimeError:
When **use_fast_math** =True but fast math is not available.
"""
use_fast_math = kwargs.get('use_fast_math', None)
if use_fast_math is None: # Automatic
if _fastmath is not None:
self._math = _fastmath
else:
self._math = _slowmath
elif use_fast_math: # Explicitly select fast math
if _fastmath is not None:
self._math = _fastmath
else:
raise RuntimeError("fast math module not available")
else: # Explicitly select slow math
self._math = _slowmath
self.error = self._math.error
# 'default_randfunc' parameter:
# None (default) - use Random.new().read
# not None - use the specified function
self._default_randfunc = kwargs.get('default_randfunc', None)
self._current_randfunc = None
def _get_randfunc(self, randfunc):
if randfunc is not None:
return randfunc
elif self._current_randfunc is None:
self._current_randfunc = Random.new().read
return self._current_randfunc
def generate(self, bits, randfunc=None, progress_func=None):
"""Randomly generate a fresh, new DSA key.
:Parameters:
bits : int
Key length, or size (in bits) of the DSA modulus
*p*.
It must be a multiple of 64, in the closed
interval [512,1024].
randfunc : callable
Random number generation function; it should accept
a single integer N and return a string of random data
N bytes long.
If not specified, a new one will be instantiated
from ``Crypto.Random``.
progress_func : callable
Optional function that will be called with a short string
containing the key parameter currently being generated;
it's useful for interactive applications where a user is
waiting for a key to be generated.
:attention: You should always use a cryptographically secure random number generator,
such as the one defined in the ``Crypto.Random`` module; **don't** just use the
current time and the ``random`` module.
:Return: A DSA key object (`_DSAobj`).
:Raise ValueError:
When **bits** is too little, too big, or not a multiple of 64.
"""
# Check against FIPS 186-2, which says that the size of the prime p
# must be a multiple of 64 bits between 512 and 1024
for i in (0, 1, 2, 3, 4, 5, 6, 7, 8):
if bits == 512 + 64*i:
return self._generate(bits, randfunc, progress_func)
# The March 2006 draft of FIPS 186-3 also allows 2048 and 3072-bit
# primes, but only with longer q values. Since the current DSA
# implementation only supports a 160-bit q, we don't support larger
# values.
raise ValueError("Number of bits in p must be a multiple of 64 between 512 and 1024, not %d bits" % (bits,))
def _generate(self, bits, randfunc=None, progress_func=None):
rf = self._get_randfunc(randfunc)
obj = _DSA.generate_py(bits, rf, progress_func) # TODO: Don't use legacy _DSA module
key = self._math.dsa_construct(obj.y, obj.g, obj.p, obj.q, obj.x)
return _DSAobj(self, key)
def construct(self, tup):
"""Construct a DSA key from a tuple of valid DSA components.
The modulus *p* must be a prime.
The following equations must apply:
- p-1 = 0 mod q
- g^x = y mod p
- 0 < x < q
- 1 < g < p
:Parameters:
tup : tuple
A tuple of long integers, with 4 or 5 items
in the following order:
1. Public key (*y*).
2. Sub-group generator (*g*).
3. Modulus, finite field order (*p*).
4. Sub-group order (*q*).
5. Private key (*x*). Optional.
:Return: A DSA key object (`_DSAobj`).
"""
key = self._math.dsa_construct(*tup)
return _DSAobj(self, key)
_impl = DSAImplementation()
generate = _impl.generate
construct = _impl.construct
error = _impl.error
# vim:set ts=4 sw=4 sts=4 expandtab:
# -*- coding: utf-8 -*-
#
# PublicKey/DSA.py : DSA signature primitive
#
# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
"""DSA public-key signature algorithm.
DSA_ is a widespread public-key signature algorithm. Its security is
based on the discrete logarithm problem (DLP_). Given a cyclic
group, a generator *g*, and an element *h*, it is hard
to find an integer *x* such that *g^x = h*. The problem is believed
to be difficult, and it has been proved such (and therefore secure) for
more than 30 years.
The group is actually a sub-group over the integers modulo *p*, with *p* prime.
The sub-group order is *q*, which is prime too; it always holds that *(p-1)* is a multiple of *q*.
The cryptographic strength is linked to the magnitude of *p* and *q*.
The signer holds a value *x* (*0<x<q-1*) as private key, and its public
key (*y* where *y=g^x mod p*) is distributed.
In 2012, a sufficient size is deemed to be 2048 bits for *p* and 256 bits for *q*.
For more information, see the most recent ECRYPT_ report.
DSA is reasonably secure for new designs.
The algorithm can only be used for authentication (digital signature).
DSA cannot be used for confidentiality (encryption).
The values *(p,q,g)* are called *domain parameters*;
they are not sensitive but must be shared by both parties (the signer and the verifier).
Different signers can share the same domain parameters with no security
concerns.
The DSA signature is twice as big as the size of *q* (64 bytes if *q* is 256 bit
long).
This module provides facilities for generating new DSA keys and for constructing
them from known components. DSA keys allows you to perform basic signing and
verification.
>>> from Crypto.Random import random
>>> from Crypto.PublicKey import DSA
>>> from Crypto.Hash import SHA
>>>
>>> message = "Hello"
>>> key = DSA.generate(1024)
>>> h = SHA.new(message).digest()
>>> k = random.StrongRandom().randint(1,key.q-1)
>>> sig = key.sign(h,k)
>>> ...
>>> if key.verify(h,sig):
>>> print "OK"
>>> else:
>>> print "Incorrect signature"
.. _DSA: http://en.wikipedia.org/wiki/Digital_Signature_Algorithm
.. _DLP: http://www.cosic.esat.kuleuven.be/publications/talk-78.pdf
.. _ECRYPT: http://www.ecrypt.eu.org/documents/D.SPA.17.pdf
"""
__revision__ = "$Id$"
__all__ = ['generate', 'construct', 'error', 'DSAImplementation', '_DSAobj']
import sys
if sys.version_info[0] == 2 and sys.version_info[1] == 1:
from Crypto.Util.py21compat import *
from Crypto.PublicKey import _DSA, _slowmath, pubkey
from Crypto import Random
try:
from Crypto.PublicKey import _fastmath
except ImportError:
_fastmath = None
class _DSAobj(pubkey.pubkey):
"""Class defining an actual DSA key.
:undocumented: __getstate__, __setstate__, __repr__, __getattr__
"""
#: Dictionary of DSA parameters.
#:
#: A public key will only have the following entries:
#:
#: - **y**, the public key.
#: - **g**, the generator.
#: - **p**, the modulus.
#: - **q**, the order of the sub-group.
#:
#: A private key will also have:
#:
#: - **x**, the private key.
keydata = ['y', 'g', 'p', 'q', 'x']
def __init__(self, implementation, key):
self.implementation = implementation
self.key = key
def __getattr__(self, attrname):
if attrname in self.keydata:
# For backward compatibility, allow the user to get (not set) the
# DSA key parameters directly from this object.
return getattr(self.key, attrname)
else:
raise AttributeError("%s object has no %r attribute" % (self.__class__.__name__, attrname,))
def sign(self, M, K):
"""Sign a piece of data with DSA.
:Parameter M: The piece of data to sign with DSA. It may
not be longer in bit size than the sub-group order (*q*).
:Type M: byte string or long
:Parameter K: A secret number, chosen randomly in the closed
range *[1,q-1]*.
:Type K: long (recommended) or byte string (not recommended)
:attention: selection of *K* is crucial for security. Generating a
random number larger than *q* and taking the modulus by *q* is
**not** secure, since smaller values will occur more frequently.
Generating a random number systematically smaller than *q-1*
(e.g. *floor((q-1)/8)* random bytes) is also **not** secure. In general,
it shall not be possible for an attacker to know the value of `any
bit of K`__.
:attention: The number *K* shall not be reused for any other
operation and shall be discarded immediately.
:attention: M must be a digest cryptographic hash, otherwise
an attacker may mount an existential forgery attack.
:Return: A tuple with 2 longs.
.. __: http://www.di.ens.fr/~pnguyen/pub_NgSh00.htm
"""
return pubkey.pubkey.sign(self, M, K)
def verify(self, M, signature):
"""Verify the validity of a DSA signature.
:Parameter M: The expected message.
:Type M: byte string or long
:Parameter signature: The DSA signature to verify.
:Type signature: A tuple with 2 longs as return by `sign`
:Return: True if the signature is correct, False otherwise.
"""
return pubkey.pubkey.verify(self, M, signature)
def _encrypt(self, c, K):
raise TypeError("DSA cannot encrypt")
def _decrypt(self, c):
raise TypeError("DSA cannot decrypt")
def _blind(self, m, r):
raise TypeError("DSA cannot blind")
def _unblind(self, m, r):
raise TypeError("DSA cannot unblind")
def _sign(self, m, k):
return self.key._sign(m, k)
def _verify(self, m, sig):
(r, s) = sig
return self.key._verify(m, r, s)
def has_private(self):
return self.key.has_private()
def size(self):
return self.key.size()
def can_blind(self):
return False
def can_encrypt(self):
return False
def can_sign(self):
return True
def publickey(self):
return self.implementation.construct((self.key.y, self.key.g, self.key.p, self.key.q))
def __getstate__(self):
d = {}
for k in self.keydata:
try:
d[k] = getattr(self.key, k)
except AttributeError:
pass
return d
def __setstate__(self, d):
if not hasattr(self, 'implementation'):
self.implementation = DSAImplementation()
t = []
for k in self.keydata:
if k not in d:
break
t.append(d[k])
self.key = self.implementation._math.dsa_construct(*tuple(t))
def __repr__(self):
attrs = []
for k in self.keydata:
if k == 'p':
attrs.append("p(%d)" % (self.size()+1,))
elif hasattr(self.key, k):
attrs.append(k)
if self.has_private():
attrs.append("private")
# PY3K: This is meant to be text, do not change to bytes (data)
return "<%s @0x%x %s>" % (self.__class__.__name__, id(self), ",".join(attrs))
class DSAImplementation(object):
"""
A DSA key factory.
This class is only internally used to implement the methods of the
`Crypto.PublicKey.DSA` module.
"""
def __init__(self, **kwargs):
"""Create a new DSA key factory.
:Keywords:
use_fast_math : bool
Specify which mathematic library to use:
- *None* (default). Use fastest math available.
- *True* . Use fast math.
- *False* . Use slow math.
default_randfunc : callable
Specify how to collect random data:
- *None* (default). Use Random.new().read().
- not *None* . Use the specified function directly.
:Raise RuntimeError:
When **use_fast_math** =True but fast math is not available.
"""
use_fast_math = kwargs.get('use_fast_math', None)
if use_fast_math is None: # Automatic
if _fastmath is not None:
self._math = _fastmath
else:
self._math = _slowmath
elif use_fast_math: # Explicitly select fast math
if _fastmath is not None:
self._math = _fastmath
else:
raise RuntimeError("fast math module not available")
else: # Explicitly select slow math
self._math = _slowmath
self.error = self._math.error
# 'default_randfunc' parameter:
# None (default) - use Random.new().read
# not None - use the specified function
self._default_randfunc = kwargs.get('default_randfunc', None)
self._current_randfunc = None
def _get_randfunc(self, randfunc):
if randfunc is not None:
return randfunc
elif self._current_randfunc is None:
self._current_randfunc = Random.new().read
return self._current_randfunc
def generate(self, bits, randfunc=None, progress_func=None):
"""Randomly generate a fresh, new DSA key.
:Parameters:
bits : int
Key length, or size (in bits) of the DSA modulus
*p*.
It must be a multiple of 64, in the closed
interval [512,1024].
randfunc : callable
Random number generation function; it should accept
a single integer N and return a string of random data
N bytes long.
If not specified, a new one will be instantiated
from ``Crypto.Random``.
progress_func : callable
Optional function that will be called with a short string
containing the key parameter currently being generated;
it's useful for interactive applications where a user is
waiting for a key to be generated.
:attention: You should always use a cryptographically secure random number generator,
such as the one defined in the ``Crypto.Random`` module; **don't** just use the
current time and the ``random`` module.
:Return: A DSA key object (`_DSAobj`).
:Raise ValueError:
When **bits** is too little, too big, or not a multiple of 64.
"""
# Check against FIPS 186-2, which says that the size of the prime p
# must be a multiple of 64 bits between 512 and 1024
for i in (0, 1, 2, 3, 4, 5, 6, 7, 8):
if bits == 512 + 64*i:
return self._generate(bits, randfunc, progress_func)
# The March 2006 draft of FIPS 186-3 also allows 2048 and 3072-bit
# primes, but only with longer q values. Since the current DSA
# implementation only supports a 160-bit q, we don't support larger
# values.
raise ValueError("Number of bits in p must be a multiple of 64 between 512 and 1024, not %d bits" % (bits,))
def _generate(self, bits, randfunc=None, progress_func=None):
rf = self._get_randfunc(randfunc)
obj = _DSA.generate_py(bits, rf, progress_func) # TODO: Don't use legacy _DSA module
key = self._math.dsa_construct(obj.y, obj.g, obj.p, obj.q, obj.x)
return _DSAobj(self, key)
def construct(self, tup):
"""Construct a DSA key from a tuple of valid DSA components.
The modulus *p* must be a prime.
The following equations must apply:
- p-1 = 0 mod q
- g^x = y mod p
- 0 < x < q
- 1 < g < p
:Parameters:
tup : tuple
A tuple of long integers, with 4 or 5 items
in the following order:
1. Public key (*y*).
2. Sub-group generator (*g*).
3. Modulus, finite field order (*p*).
4. Sub-group order (*q*).
5. Private key (*x*). Optional.
:Return: A DSA key object (`_DSAobj`).
"""
key = self._math.dsa_construct(*tup)
return _DSAobj(self, key)
_impl = DSAImplementation()
generate = _impl.generate
construct = _impl.construct
error = _impl.error
# vim:set ts=4 sw=4 sts=4 expandtab:

File diff suppressed because it is too large Load diff

View file

@ -1,115 +1,115 @@
#
# DSA.py : Digital Signature Algorithm
#
# Part of the Python Cryptography Toolkit
#
# Written by Andrew Kuchling, Paul Swartz, and others
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
#
__revision__ = "$Id$"
from Crypto.PublicKey.pubkey import *
from Crypto.Util import number
from Crypto.Util.number import bytes_to_long, long_to_bytes
from Crypto.Hash import SHA
from Crypto.Util.py3compat import *
class error (Exception):
pass
def generateQ(randfunc):
S=randfunc(20)
hash1=SHA.new(S).digest()
hash2=SHA.new(long_to_bytes(bytes_to_long(S)+1)).digest()
q = bignum(0)
for i in range(0,20):
c=bord(hash1[i])^bord(hash2[i])
if i==0:
c=c | 128
if i==19:
c= c | 1
q=q*256+c
while (not isPrime(q)):
q=q+2
if pow(2,159) < q < pow(2,160):
return S, q
raise RuntimeError('Bad q value generated')
def generate_py(bits, randfunc, progress_func=None):
"""generate(bits:int, randfunc:callable, progress_func:callable)
Generate a DSA key of length 'bits', using 'randfunc' to get
random data and 'progress_func', if present, to display
the progress of the key generation.
"""
if bits<160:
raise ValueError('Key length < 160 bits')
obj=DSAobj()
# Generate string S and prime q
if progress_func:
progress_func('p,q\n')
while (1):
S, obj.q = generateQ(randfunc)
n=divmod(bits-1, 160)[0]
C, N, V = 0, 2, {}
b=(obj.q >> 5) & 15
powb=pow(bignum(2), b)
powL1=pow(bignum(2), bits-1)
while C<4096:
for k in range(0, n+1):
V[k]=bytes_to_long(SHA.new(S+bstr(N)+bstr(k)).digest())
W=V[n] % powb
for k in range(n-1, -1, -1):
W=(W<<160)+V[k]
X=W+powL1
p=X-(X%(2*obj.q)-1)
if powL1<=p and isPrime(p):
break
C, N = C+1, N+n+1
if C<4096:
break
if progress_func:
progress_func('4096 multiples failed\n')
obj.p = p
power=divmod(p-1, obj.q)[0]
if progress_func:
progress_func('h,g\n')
while (1):
h=bytes_to_long(randfunc(bits)) % (p-1)
g=pow(h, power, p)
if 1<h<p-1 and g>1:
break
obj.g=g
if progress_func:
progress_func('x,y\n')
while (1):
x=bytes_to_long(randfunc(20))
if 0 < x < obj.q:
break
obj.x, obj.y = x, pow(g, x, p)
return obj
class DSAobj:
pass
#
# DSA.py : Digital Signature Algorithm
#
# Part of the Python Cryptography Toolkit
#
# Written by Andrew Kuchling, Paul Swartz, and others
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
#
__revision__ = "$Id$"
from Crypto.PublicKey.pubkey import *
from Crypto.Util import number
from Crypto.Util.number import bytes_to_long, long_to_bytes
from Crypto.Hash import SHA
from Crypto.Util.py3compat import *
class error (Exception):
pass
def generateQ(randfunc):
S=randfunc(20)
hash1=SHA.new(S).digest()
hash2=SHA.new(long_to_bytes(bytes_to_long(S)+1)).digest()
q = bignum(0)
for i in range(0,20):
c=bord(hash1[i])^bord(hash2[i])
if i==0:
c=c | 128
if i==19:
c= c | 1
q=q*256+c
while (not isPrime(q)):
q=q+2
if pow(2,159) < q < pow(2,160):
return S, q
raise RuntimeError('Bad q value generated')
def generate_py(bits, randfunc, progress_func=None):
"""generate(bits:int, randfunc:callable, progress_func:callable)
Generate a DSA key of length 'bits', using 'randfunc' to get
random data and 'progress_func', if present, to display
the progress of the key generation.
"""
if bits<160:
raise ValueError('Key length < 160 bits')
obj=DSAobj()
# Generate string S and prime q
if progress_func:
progress_func('p,q\n')
while (1):
S, obj.q = generateQ(randfunc)
n=divmod(bits-1, 160)[0]
C, N, V = 0, 2, {}
b=(obj.q >> 5) & 15
powb=pow(bignum(2), b)
powL1=pow(bignum(2), bits-1)
while C<4096:
for k in range(0, n+1):
V[k]=bytes_to_long(SHA.new(S+bstr(N)+bstr(k)).digest())
W=V[n] % powb
for k in range(n-1, -1, -1):
W=(W<<160)+V[k]
X=W+powL1
p=X-(X%(2*obj.q)-1)
if powL1<=p and isPrime(p):
break
C, N = C+1, N+n+1
if C<4096:
break
if progress_func:
progress_func('4096 multiples failed\n')
obj.p = p
power=divmod(p-1, obj.q)[0]
if progress_func:
progress_func('h,g\n')
while (1):
h=bytes_to_long(randfunc(bits)) % (p-1)
g=pow(h, power, p)
if 1<h<p-1 and g>1:
break
obj.g=g
if progress_func:
progress_func('x,y\n')
while (1):
x=bytes_to_long(randfunc(20))
if 0 < x < obj.q:
break
obj.x, obj.y = x, pow(g, x, p)
return obj
class DSAobj:
pass

View file

@ -1,81 +1,81 @@
#
# RSA.py : RSA encryption/decryption
#
# Part of the Python Cryptography Toolkit
#
# Written by Andrew Kuchling, Paul Swartz, and others
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
#
__revision__ = "$Id$"
from Crypto.PublicKey import pubkey
from Crypto.Util import number
def generate_py(bits, randfunc, progress_func=None, e=65537):
"""generate(bits:int, randfunc:callable, progress_func:callable, e:int)
Generate an RSA key of length 'bits', public exponent 'e'(which must be
odd), using 'randfunc' to get random data and 'progress_func',
if present, to display the progress of the key generation.
"""
obj=RSAobj()
obj.e = int(e)
# Generate the prime factors of n
if progress_func:
progress_func('p,q\n')
p = q = 1
while number.size(p*q) < bits:
# Note that q might be one bit longer than p if somebody specifies an odd
# number of bits for the key. (Why would anyone do that? You don't get
# more security.)
p = pubkey.getStrongPrime(bits>>1, obj.e, 1e-12, randfunc)
q = pubkey.getStrongPrime(bits - (bits>>1), obj.e, 1e-12, randfunc)
# It's OK for p to be larger than q, but let's be
# kind to the function that will invert it for
# th calculation of u.
if p > q:
(p, q)=(q, p)
obj.p = p
obj.q = q
if progress_func:
progress_func('u\n')
obj.u = pubkey.inverse(obj.p, obj.q)
obj.n = obj.p*obj.q
if progress_func:
progress_func('d\n')
obj.d=pubkey.inverse(obj.e, (obj.p-1)*(obj.q-1))
assert bits <= 1+obj.size(), "Generated key is too small"
return obj
class RSAobj(pubkey.pubkey):
def size(self):
"""size() : int
Return the maximum number of bits that can be handled by this key.
"""
return number.size(self.n) - 1
#
# RSA.py : RSA encryption/decryption
#
# Part of the Python Cryptography Toolkit
#
# Written by Andrew Kuchling, Paul Swartz, and others
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
#
__revision__ = "$Id$"
from Crypto.PublicKey import pubkey
from Crypto.Util import number
def generate_py(bits, randfunc, progress_func=None, e=65537):
"""generate(bits:int, randfunc:callable, progress_func:callable, e:int)
Generate an RSA key of length 'bits', public exponent 'e'(which must be
odd), using 'randfunc' to get random data and 'progress_func',
if present, to display the progress of the key generation.
"""
obj=RSAobj()
obj.e = int(e)
# Generate the prime factors of n
if progress_func:
progress_func('p,q\n')
p = q = 1
while number.size(p*q) < bits:
# Note that q might be one bit longer than p if somebody specifies an odd
# number of bits for the key. (Why would anyone do that? You don't get
# more security.)
p = pubkey.getStrongPrime(bits>>1, obj.e, 1e-12, randfunc)
q = pubkey.getStrongPrime(bits - (bits>>1), obj.e, 1e-12, randfunc)
# It's OK for p to be larger than q, but let's be
# kind to the function that will invert it for
# th calculation of u.
if p > q:
(p, q)=(q, p)
obj.p = p
obj.q = q
if progress_func:
progress_func('u\n')
obj.u = pubkey.inverse(obj.p, obj.q)
obj.n = obj.p*obj.q
if progress_func:
progress_func('d\n')
obj.d=pubkey.inverse(obj.e, (obj.p-1)*(obj.q-1))
assert bits <= 1+obj.size(), "Generated key is too small"
return obj
class RSAobj(pubkey.pubkey):
def size(self):
"""size() : int
Return the maximum number of bits that can be handled by this key.
"""
return number.size(self.n) - 1

View file

@ -1,187 +1,187 @@
# -*- coding: utf-8 -*-
#
# PubKey/RSA/_slowmath.py : Pure Python implementation of the RSA portions of _fastmath
#
# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
"""Pure Python implementation of the RSA-related portions of Crypto.PublicKey._fastmath."""
__revision__ = "$Id$"
__all__ = ['rsa_construct']
import sys
if sys.version_info[0] == 2 and sys.version_info[1] == 1:
from Crypto.Util.py21compat import *
from Crypto.Util.number import size, inverse, GCD
class error(Exception):
pass
class _RSAKey(object):
def _blind(self, m, r):
# compute r**e * m (mod n)
return m * pow(r, self.e, self.n)
def _unblind(self, m, r):
# compute m / r (mod n)
return inverse(r, self.n) * m % self.n
def _decrypt(self, c):
# compute c**d (mod n)
if not self.has_private():
raise TypeError("No private key")
if (hasattr(self,'p') and hasattr(self,'q') and hasattr(self,'u')):
m1 = pow(c, self.d % (self.p-1), self.p)
m2 = pow(c, self.d % (self.q-1), self.q)
h = m2 - m1
if (h<0):
h = h + self.q
h = h*self.u % self.q
return h*self.p+m1
return pow(c, self.d, self.n)
def _encrypt(self, m):
# compute m**d (mod n)
return pow(m, self.e, self.n)
def _sign(self, m): # alias for _decrypt
if not self.has_private():
raise TypeError("No private key")
return self._decrypt(m)
def _verify(self, m, sig):
return self._encrypt(sig) == m
def has_private(self):
return hasattr(self, 'd')
def size(self):
"""Return the maximum number of bits that can be encrypted"""
return size(self.n) - 1
def rsa_construct(n, e, d=None, p=None, q=None, u=None):
"""Construct an RSAKey object"""
assert isinstance(n, int)
assert isinstance(e, int)
assert isinstance(d, (int, type(None)))
assert isinstance(p, (int, type(None)))
assert isinstance(q, (int, type(None)))
assert isinstance(u, (int, type(None)))
obj = _RSAKey()
obj.n = n
obj.e = e
if d is None:
return obj
obj.d = d
if p is not None and q is not None:
obj.p = p
obj.q = q
else:
# Compute factors p and q from the private exponent d.
# We assume that n has no more than two factors.
# See 8.2.2(i) in Handbook of Applied Cryptography.
ktot = d*e-1
# The quantity d*e-1 is a multiple of phi(n), even,
# and can be represented as t*2^s.
t = ktot
while t%2==0:
t=divmod(t,2)[0]
# Cycle through all multiplicative inverses in Zn.
# The algorithm is non-deterministic, but there is a 50% chance
# any candidate a leads to successful factoring.
# See "Digitalized Signatures and Public Key Functions as Intractable
# as Factorization", M. Rabin, 1979
spotted = 0
a = 2
while not spotted and a<100:
k = t
# Cycle through all values a^{t*2^i}=a^k
while k<ktot:
cand = pow(a,k,n)
# Check if a^k is a non-trivial root of unity (mod n)
if cand!=1 and cand!=(n-1) and pow(cand,2,n)==1:
# We have found a number such that (cand-1)(cand+1)=0 (mod n).
# Either of the terms divides n.
obj.p = GCD(cand+1,n)
spotted = 1
break
k = k*2
# This value was not any good... let's try another!
a = a+2
if not spotted:
raise ValueError("Unable to compute factors p and q from exponent d.")
# Found !
assert ((n % obj.p)==0)
obj.q = divmod(n,obj.p)[0]
if u is not None:
obj.u = u
else:
obj.u = inverse(obj.p, obj.q)
return obj
class _DSAKey(object):
def size(self):
"""Return the maximum number of bits that can be encrypted"""
return size(self.p) - 1
def has_private(self):
return hasattr(self, 'x')
def _sign(self, m, k): # alias for _decrypt
# SECURITY TODO - We _should_ be computing SHA1(m), but we don't because that's the API.
if not self.has_private():
raise TypeError("No private key")
if not (1 < k < self.q):
raise ValueError("k is not between 2 and q-1")
inv_k = inverse(k, self.q) # Compute k**-1 mod q
r = pow(self.g, k, self.p) % self.q # r = (g**k mod p) mod q
s = (inv_k * (m + self.x * r)) % self.q
return (r, s)
def _verify(self, m, r, s):
# SECURITY TODO - We _should_ be computing SHA1(m), but we don't because that's the API.
if not (0 < r < self.q) or not (0 < s < self.q):
return False
w = inverse(s, self.q)
u1 = (m*w) % self.q
u2 = (r*w) % self.q
v = (pow(self.g, u1, self.p) * pow(self.y, u2, self.p) % self.p) % self.q
return v == r
def dsa_construct(y, g, p, q, x=None):
assert isinstance(y, int)
assert isinstance(g, int)
assert isinstance(p, int)
assert isinstance(q, int)
assert isinstance(x, (int, type(None)))
obj = _DSAKey()
obj.y = y
obj.g = g
obj.p = p
obj.q = q
if x is not None: obj.x = x
return obj
# vim:set ts=4 sw=4 sts=4 expandtab:
# -*- coding: utf-8 -*-
#
# PubKey/RSA/_slowmath.py : Pure Python implementation of the RSA portions of _fastmath
#
# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
"""Pure Python implementation of the RSA-related portions of Crypto.PublicKey._fastmath."""
__revision__ = "$Id$"
__all__ = ['rsa_construct']
import sys
if sys.version_info[0] == 2 and sys.version_info[1] == 1:
from Crypto.Util.py21compat import *
from Crypto.Util.number import size, inverse, GCD
class error(Exception):
pass
class _RSAKey(object):
def _blind(self, m, r):
# compute r**e * m (mod n)
return m * pow(r, self.e, self.n)
def _unblind(self, m, r):
# compute m / r (mod n)
return inverse(r, self.n) * m % self.n
def _decrypt(self, c):
# compute c**d (mod n)
if not self.has_private():
raise TypeError("No private key")
if (hasattr(self,'p') and hasattr(self,'q') and hasattr(self,'u')):
m1 = pow(c, self.d % (self.p-1), self.p)
m2 = pow(c, self.d % (self.q-1), self.q)
h = m2 - m1
if (h<0):
h = h + self.q
h = h*self.u % self.q
return h*self.p+m1
return pow(c, self.d, self.n)
def _encrypt(self, m):
# compute m**d (mod n)
return pow(m, self.e, self.n)
def _sign(self, m): # alias for _decrypt
if not self.has_private():
raise TypeError("No private key")
return self._decrypt(m)
def _verify(self, m, sig):
return self._encrypt(sig) == m
def has_private(self):
return hasattr(self, 'd')
def size(self):
"""Return the maximum number of bits that can be encrypted"""
return size(self.n) - 1
def rsa_construct(n, e, d=None, p=None, q=None, u=None):
"""Construct an RSAKey object"""
assert isinstance(n, int)
assert isinstance(e, int)
assert isinstance(d, (int, type(None)))
assert isinstance(p, (int, type(None)))
assert isinstance(q, (int, type(None)))
assert isinstance(u, (int, type(None)))
obj = _RSAKey()
obj.n = n
obj.e = e
if d is None:
return obj
obj.d = d
if p is not None and q is not None:
obj.p = p
obj.q = q
else:
# Compute factors p and q from the private exponent d.
# We assume that n has no more than two factors.
# See 8.2.2(i) in Handbook of Applied Cryptography.
ktot = d*e-1
# The quantity d*e-1 is a multiple of phi(n), even,
# and can be represented as t*2^s.
t = ktot
while t%2==0:
t=divmod(t,2)[0]
# Cycle through all multiplicative inverses in Zn.
# The algorithm is non-deterministic, but there is a 50% chance
# any candidate a leads to successful factoring.
# See "Digitalized Signatures and Public Key Functions as Intractable
# as Factorization", M. Rabin, 1979
spotted = 0
a = 2
while not spotted and a<100:
k = t
# Cycle through all values a^{t*2^i}=a^k
while k<ktot:
cand = pow(a,k,n)
# Check if a^k is a non-trivial root of unity (mod n)
if cand!=1 and cand!=(n-1) and pow(cand,2,n)==1:
# We have found a number such that (cand-1)(cand+1)=0 (mod n).
# Either of the terms divides n.
obj.p = GCD(cand+1,n)
spotted = 1
break
k = k*2
# This value was not any good... let's try another!
a = a+2
if not spotted:
raise ValueError("Unable to compute factors p and q from exponent d.")
# Found !
assert ((n % obj.p)==0)
obj.q = divmod(n,obj.p)[0]
if u is not None:
obj.u = u
else:
obj.u = inverse(obj.p, obj.q)
return obj
class _DSAKey(object):
def size(self):
"""Return the maximum number of bits that can be encrypted"""
return size(self.p) - 1
def has_private(self):
return hasattr(self, 'x')
def _sign(self, m, k): # alias for _decrypt
# SECURITY TODO - We _should_ be computing SHA1(m), but we don't because that's the API.
if not self.has_private():
raise TypeError("No private key")
if not (1 < k < self.q):
raise ValueError("k is not between 2 and q-1")
inv_k = inverse(k, self.q) # Compute k**-1 mod q
r = pow(self.g, k, self.p) % self.q # r = (g**k mod p) mod q
s = (inv_k * (m + self.x * r)) % self.q
return (r, s)
def _verify(self, m, r, s):
# SECURITY TODO - We _should_ be computing SHA1(m), but we don't because that's the API.
if not (0 < r < self.q) or not (0 < s < self.q):
return False
w = inverse(s, self.q)
u1 = (m*w) % self.q
u2 = (r*w) % self.q
v = (pow(self.g, u1, self.p) * pow(self.y, u2, self.p) % self.p) % self.q
return v == r
def dsa_construct(y, g, p, q, x=None):
assert isinstance(y, int)
assert isinstance(g, int)
assert isinstance(p, int)
assert isinstance(q, int)
assert isinstance(x, (int, type(None)))
obj = _DSAKey()
obj.y = y
obj.g = g
obj.p = p
obj.q = q
if x is not None: obj.x = x
return obj
# vim:set ts=4 sw=4 sts=4 expandtab:

View file

@ -1,240 +1,240 @@
#
# pubkey.py : Internal functions for public key operations
#
# Part of the Python Cryptography Toolkit
#
# Written by Andrew Kuchling, Paul Swartz, and others
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
#
__revision__ = "$Id$"
import types, warnings
from Crypto.Util.number import *
# Basic public key class
class pubkey:
"""An abstract class for a public key object.
:undocumented: __getstate__, __setstate__, __eq__, __ne__, validate
"""
def __init__(self):
pass
def __getstate__(self):
"""To keep key objects platform-independent, the key data is
converted to standard Python long integers before being
written out. It will then be reconverted as necessary on
restoration."""
d=self.__dict__
for key in self.keydata:
if key in d: d[key]=int(d[key])
return d
def __setstate__(self, d):
"""On unpickling a key object, the key data is converted to the big
number representation being used, whether that is Python long
integers, MPZ objects, or whatever."""
for key in self.keydata:
if key in d: self.__dict__[key]=bignum(d[key])
def encrypt(self, plaintext, K):
"""Encrypt a piece of data.
:Parameter plaintext: The piece of data to encrypt.
:Type plaintext: byte string or long
:Parameter K: A random parameter required by some algorithms
:Type K: byte string or long
:Return: A tuple with two items. Each item is of the same type as the
plaintext (string or long).
"""
wasString=0
if isinstance(plaintext, bytes):
plaintext=bytes_to_long(plaintext) ; wasString=1
if isinstance(K, bytes):
K=bytes_to_long(K)
ciphertext=self._encrypt(plaintext, K)
if wasString: return tuple(map(long_to_bytes, ciphertext))
else: return ciphertext
def decrypt(self, ciphertext):
"""Decrypt a piece of data.
:Parameter ciphertext: The piece of data to decrypt.
:Type ciphertext: byte string, long or a 2-item tuple as returned by `encrypt`
:Return: A byte string if ciphertext was a byte string or a tuple
of byte strings. A long otherwise.
"""
wasString=0
if not isinstance(ciphertext, tuple):
ciphertext=(ciphertext,)
if isinstance(ciphertext[0], bytes):
ciphertext=tuple(map(bytes_to_long, ciphertext)) ; wasString=1
plaintext=self._decrypt(ciphertext)
if wasString: return long_to_bytes(plaintext)
else: return plaintext
def sign(self, M, K):
"""Sign a piece of data.
:Parameter M: The piece of data to encrypt.
:Type M: byte string or long
:Parameter K: A random parameter required by some algorithms
:Type K: byte string or long
:Return: A tuple with two items.
"""
if (not self.has_private()):
raise TypeError('Private key not available in this object')
if isinstance(M, bytes): M=bytes_to_long(M)
if isinstance(K, bytes): K=bytes_to_long(K)
return self._sign(M, K)
def verify (self, M, signature):
"""Verify the validity of a signature.
:Parameter M: The expected message.
:Type M: byte string or long
:Parameter signature: The signature to verify.
:Type signature: tuple with two items, as return by `sign`
:Return: True if the signature is correct, False otherwise.
"""
if isinstance(M, bytes): M=bytes_to_long(M)
return self._verify(M, signature)
# alias to compensate for the old validate() name
def validate (self, M, signature):
warnings.warn("validate() method name is obsolete; use verify()",
DeprecationWarning)
def blind(self, M, B):
"""Blind a message to prevent certain side-channel attacks.
:Parameter M: The message to blind.
:Type M: byte string or long
:Parameter B: Blinding factor.
:Type B: byte string or long
:Return: A byte string if M was so. A long otherwise.
"""
wasString=0
if isinstance(M, bytes):
M=bytes_to_long(M) ; wasString=1
if isinstance(B, bytes): B=bytes_to_long(B)
blindedmessage=self._blind(M, B)
if wasString: return long_to_bytes(blindedmessage)
else: return blindedmessage
def unblind(self, M, B):
"""Unblind a message after cryptographic processing.
:Parameter M: The encoded message to unblind.
:Type M: byte string or long
:Parameter B: Blinding factor.
:Type B: byte string or long
"""
wasString=0
if isinstance(M, bytes):
M=bytes_to_long(M) ; wasString=1
if isinstance(B, bytes): B=bytes_to_long(B)
unblindedmessage=self._unblind(M, B)
if wasString: return long_to_bytes(unblindedmessage)
else: return unblindedmessage
# The following methods will usually be left alone, except for
# signature-only algorithms. They both return Boolean values
# recording whether this key's algorithm can sign and encrypt.
def can_sign (self):
"""Tell if the algorithm can deal with cryptographic signatures.
This property concerns the *algorithm*, not the key itself.
It may happen that this particular key object hasn't got
the private information required to generate a signature.
:Return: boolean
"""
return 1
def can_encrypt (self):
"""Tell if the algorithm can deal with data encryption.
This property concerns the *algorithm*, not the key itself.
It may happen that this particular key object hasn't got
the private information required to decrypt data.
:Return: boolean
"""
return 1
def can_blind (self):
"""Tell if the algorithm can deal with data blinding.
This property concerns the *algorithm*, not the key itself.
It may happen that this particular key object hasn't got
the private information required carry out blinding.
:Return: boolean
"""
return 0
# The following methods will certainly be overridden by
# subclasses.
def size (self):
"""Tell the maximum number of bits that can be handled by this key.
:Return: int
"""
return 0
def has_private (self):
"""Tell if the key object contains private components.
:Return: bool
"""
return 0
def publickey (self):
"""Construct a new key carrying only the public information.
:Return: A new `pubkey` object.
"""
return self
def __eq__ (self, other):
"""__eq__(other): 0, 1
Compare us to other for equality.
"""
return self.__getstate__() == other.__getstate__()
def __ne__ (self, other):
"""__ne__(other): 0, 1
Compare us to other for inequality.
"""
return not self.__eq__(other)
#
# pubkey.py : Internal functions for public key operations
#
# Part of the Python Cryptography Toolkit
#
# Written by Andrew Kuchling, Paul Swartz, and others
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
#
__revision__ = "$Id$"
import types, warnings
from Crypto.Util.number import *
# Basic public key class
class pubkey:
"""An abstract class for a public key object.
:undocumented: __getstate__, __setstate__, __eq__, __ne__, validate
"""
def __init__(self):
pass
def __getstate__(self):
"""To keep key objects platform-independent, the key data is
converted to standard Python long integers before being
written out. It will then be reconverted as necessary on
restoration."""
d=self.__dict__
for key in self.keydata:
if key in d: d[key]=int(d[key])
return d
def __setstate__(self, d):
"""On unpickling a key object, the key data is converted to the big
number representation being used, whether that is Python long
integers, MPZ objects, or whatever."""
for key in self.keydata:
if key in d: self.__dict__[key]=bignum(d[key])
def encrypt(self, plaintext, K):
"""Encrypt a piece of data.
:Parameter plaintext: The piece of data to encrypt.
:Type plaintext: byte string or long
:Parameter K: A random parameter required by some algorithms
:Type K: byte string or long
:Return: A tuple with two items. Each item is of the same type as the
plaintext (string or long).
"""
wasString=0
if isinstance(plaintext, bytes):
plaintext=bytes_to_long(plaintext) ; wasString=1
if isinstance(K, bytes):
K=bytes_to_long(K)
ciphertext=self._encrypt(plaintext, K)
if wasString: return tuple(map(long_to_bytes, ciphertext))
else: return ciphertext
def decrypt(self, ciphertext):
"""Decrypt a piece of data.
:Parameter ciphertext: The piece of data to decrypt.
:Type ciphertext: byte string, long or a 2-item tuple as returned by `encrypt`
:Return: A byte string if ciphertext was a byte string or a tuple
of byte strings. A long otherwise.
"""
wasString=0
if not isinstance(ciphertext, tuple):
ciphertext=(ciphertext,)
if isinstance(ciphertext[0], bytes):
ciphertext=tuple(map(bytes_to_long, ciphertext)) ; wasString=1
plaintext=self._decrypt(ciphertext)
if wasString: return long_to_bytes(plaintext)
else: return plaintext
def sign(self, M, K):
"""Sign a piece of data.
:Parameter M: The piece of data to encrypt.
:Type M: byte string or long
:Parameter K: A random parameter required by some algorithms
:Type K: byte string or long
:Return: A tuple with two items.
"""
if (not self.has_private()):
raise TypeError('Private key not available in this object')
if isinstance(M, bytes): M=bytes_to_long(M)
if isinstance(K, bytes): K=bytes_to_long(K)
return self._sign(M, K)
def verify (self, M, signature):
"""Verify the validity of a signature.
:Parameter M: The expected message.
:Type M: byte string or long
:Parameter signature: The signature to verify.
:Type signature: tuple with two items, as return by `sign`
:Return: True if the signature is correct, False otherwise.
"""
if isinstance(M, bytes): M=bytes_to_long(M)
return self._verify(M, signature)
# alias to compensate for the old validate() name
def validate (self, M, signature):
warnings.warn("validate() method name is obsolete; use verify()",
DeprecationWarning)
def blind(self, M, B):
"""Blind a message to prevent certain side-channel attacks.
:Parameter M: The message to blind.
:Type M: byte string or long
:Parameter B: Blinding factor.
:Type B: byte string or long
:Return: A byte string if M was so. A long otherwise.
"""
wasString=0
if isinstance(M, bytes):
M=bytes_to_long(M) ; wasString=1
if isinstance(B, bytes): B=bytes_to_long(B)
blindedmessage=self._blind(M, B)
if wasString: return long_to_bytes(blindedmessage)
else: return blindedmessage
def unblind(self, M, B):
"""Unblind a message after cryptographic processing.
:Parameter M: The encoded message to unblind.
:Type M: byte string or long
:Parameter B: Blinding factor.
:Type B: byte string or long
"""
wasString=0
if isinstance(M, bytes):
M=bytes_to_long(M) ; wasString=1
if isinstance(B, bytes): B=bytes_to_long(B)
unblindedmessage=self._unblind(M, B)
if wasString: return long_to_bytes(unblindedmessage)
else: return unblindedmessage
# The following methods will usually be left alone, except for
# signature-only algorithms. They both return Boolean values
# recording whether this key's algorithm can sign and encrypt.
def can_sign (self):
"""Tell if the algorithm can deal with cryptographic signatures.
This property concerns the *algorithm*, not the key itself.
It may happen that this particular key object hasn't got
the private information required to generate a signature.
:Return: boolean
"""
return 1
def can_encrypt (self):
"""Tell if the algorithm can deal with data encryption.
This property concerns the *algorithm*, not the key itself.
It may happen that this particular key object hasn't got
the private information required to decrypt data.
:Return: boolean
"""
return 1
def can_blind (self):
"""Tell if the algorithm can deal with data blinding.
This property concerns the *algorithm*, not the key itself.
It may happen that this particular key object hasn't got
the private information required carry out blinding.
:Return: boolean
"""
return 0
# The following methods will certainly be overridden by
# subclasses.
def size (self):
"""Tell the maximum number of bits that can be handled by this key.
:Return: int
"""
return 0
def has_private (self):
"""Tell if the key object contains private components.
:Return: bool
"""
return 0
def publickey (self):
"""Construct a new key carrying only the public information.
:Return: A new `pubkey` object.
"""
return self
def __eq__ (self, other):
"""__eq__(other): 0, 1
Compare us to other for equality.
"""
return self.__getstate__() == other.__getstate__()
def __ne__ (self, other):
"""__ne__(other): 0, 1
Compare us to other for inequality.
"""
return not self.__eq__(other)

View file

@ -1,171 +1,171 @@
# -*- coding: ascii -*-
#
# FortunaAccumulator.py : Fortuna's internal accumulator
#
# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
__revision__ = "$Id$"
import sys
if sys.version_info[0] == 2 and sys.version_info[1] == 1:
from Crypto.Util.py21compat import *
from Crypto.Util.py3compat import *
from binascii import b2a_hex
import time
import warnings
from Crypto.pct_warnings import ClockRewindWarning
from . import SHAd256
from . import FortunaGenerator
class FortunaPool(object):
"""Fortuna pool type
This object acts like a hash object, with the following differences:
- It keeps a count (the .length attribute) of the number of bytes that
have been added to the pool
- It supports a .reset() method for in-place reinitialization
- The method to add bytes to the pool is .append(), not .update().
"""
digest_size = SHAd256.digest_size
def __init__(self):
self.reset()
def append(self, data):
self._h.update(data)
self.length += len(data)
def digest(self):
return self._h.digest()
def hexdigest(self):
if sys.version_info[0] == 2:
return b2a_hex(self.digest())
else:
return b2a_hex(self.digest()).decode()
def reset(self):
self._h = SHAd256.new()
self.length = 0
def which_pools(r):
"""Return a list of pools indexes (in range(32)) that are to be included during reseed number r.
According to _Practical Cryptography_, chapter 10.5.2 "Pools":
"Pool P_i is included if 2**i is a divisor of r. Thus P_0 is used
every reseed, P_1 every other reseed, P_2 every fourth reseed, etc."
"""
# This is a separate function so that it can be unit-tested.
assert r >= 1
retval = []
mask = 0
for i in range(32):
# "Pool P_i is included if 2**i is a divisor of [reseed_count]"
if (r & mask) == 0:
retval.append(i)
else:
break # optimization. once this fails, it always fails
mask = (mask << 1) | 1
return retval
class FortunaAccumulator(object):
# An estimate of how many bytes we must append to pool 0 before it will
# contain 128 bits of entropy (with respect to an attack). We reseed the
# generator only after pool 0 contains `min_pool_size` bytes. Note that
# unlike with some other PRNGs, Fortuna's security does not rely on the
# accuracy of this estimate---we can accord to be optimistic here.
min_pool_size = 64 # size in bytes
# If an attacker can predict some (but not all) of our entropy sources, the
# `min_pool_size` check may not be sufficient to prevent a successful state
# compromise extension attack. To resist this attack, Fortuna spreads the
# input across 32 pools, which are then consumed (to reseed the output
# generator) with exponentially decreasing frequency.
#
# In order to prevent an attacker from gaining knowledge of all 32 pools
# before we have a chance to fill them with enough information that the
# attacker cannot predict, we impose a rate limit of 10 reseeds/second (one
# per 100 ms). This ensures that a hypothetical 33rd pool would only be
# needed after a minimum of 13 years of sustained attack.
reseed_interval = 0.100 # time in seconds
def __init__(self):
self.reseed_count = 0
self.generator = FortunaGenerator.AESGenerator()
self.last_reseed = None
# Initialize 32 FortunaPool instances.
# NB: This is _not_ equivalent to [FortunaPool()]*32, which would give
# us 32 references to the _same_ FortunaPool instance (and cause the
# assertion below to fail).
self.pools = [FortunaPool() for i in range(32)] # 32 pools
assert(self.pools[0] is not self.pools[1])
def _forget_last_reseed(self):
# This is not part of the standard Fortuna definition, and using this
# function frequently can weaken Fortuna's ability to resist a state
# compromise extension attack, but we need this in order to properly
# implement Crypto.Random.atfork(). Otherwise, forked child processes
# might continue to use their parent's PRNG state for up to 100ms in
# some cases. (e.g. CVE-2013-1445)
self.last_reseed = None
def random_data(self, bytes):
current_time = time.time()
if (self.last_reseed is not None and self.last_reseed > current_time): # Avoid float comparison to None to make Py3k happy
warnings.warn("Clock rewind detected. Resetting last_reseed.", ClockRewindWarning)
self.last_reseed = None
if (self.pools[0].length >= self.min_pool_size and
(self.last_reseed is None or
current_time > self.last_reseed + self.reseed_interval)):
self._reseed(current_time)
# The following should fail if we haven't seeded the pool yet.
return self.generator.pseudo_random_data(bytes)
def _reseed(self, current_time=None):
if current_time is None:
current_time = time.time()
seed = []
self.reseed_count += 1
self.last_reseed = current_time
for i in which_pools(self.reseed_count):
seed.append(self.pools[i].digest())
self.pools[i].reset()
seed = b("").join(seed)
self.generator.reseed(seed)
def add_random_event(self, source_number, pool_number, data):
assert 1 <= len(data) <= 32
assert 0 <= source_number <= 255
assert 0 <= pool_number <= 31
self.pools[pool_number].append(bchr(source_number))
self.pools[pool_number].append(bchr(len(data)))
self.pools[pool_number].append(data)
# vim:set ts=4 sw=4 sts=4 expandtab:
# -*- coding: ascii -*-
#
# FortunaAccumulator.py : Fortuna's internal accumulator
#
# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
__revision__ = "$Id$"
import sys
if sys.version_info[0] == 2 and sys.version_info[1] == 1:
from Crypto.Util.py21compat import *
from Crypto.Util.py3compat import *
from binascii import b2a_hex
import time
import warnings
from Crypto.pct_warnings import ClockRewindWarning
from . import SHAd256
from . import FortunaGenerator
class FortunaPool(object):
"""Fortuna pool type
This object acts like a hash object, with the following differences:
- It keeps a count (the .length attribute) of the number of bytes that
have been added to the pool
- It supports a .reset() method for in-place reinitialization
- The method to add bytes to the pool is .append(), not .update().
"""
digest_size = SHAd256.digest_size
def __init__(self):
self.reset()
def append(self, data):
self._h.update(data)
self.length += len(data)
def digest(self):
return self._h.digest()
def hexdigest(self):
if sys.version_info[0] == 2:
return b2a_hex(self.digest())
else:
return b2a_hex(self.digest()).decode()
def reset(self):
self._h = SHAd256.new()
self.length = 0
def which_pools(r):
"""Return a list of pools indexes (in range(32)) that are to be included during reseed number r.
According to _Practical Cryptography_, chapter 10.5.2 "Pools":
"Pool P_i is included if 2**i is a divisor of r. Thus P_0 is used
every reseed, P_1 every other reseed, P_2 every fourth reseed, etc."
"""
# This is a separate function so that it can be unit-tested.
assert r >= 1
retval = []
mask = 0
for i in range(32):
# "Pool P_i is included if 2**i is a divisor of [reseed_count]"
if (r & mask) == 0:
retval.append(i)
else:
break # optimization. once this fails, it always fails
mask = (mask << 1) | 1
return retval
class FortunaAccumulator(object):
# An estimate of how many bytes we must append to pool 0 before it will
# contain 128 bits of entropy (with respect to an attack). We reseed the
# generator only after pool 0 contains `min_pool_size` bytes. Note that
# unlike with some other PRNGs, Fortuna's security does not rely on the
# accuracy of this estimate---we can accord to be optimistic here.
min_pool_size = 64 # size in bytes
# If an attacker can predict some (but not all) of our entropy sources, the
# `min_pool_size` check may not be sufficient to prevent a successful state
# compromise extension attack. To resist this attack, Fortuna spreads the
# input across 32 pools, which are then consumed (to reseed the output
# generator) with exponentially decreasing frequency.
#
# In order to prevent an attacker from gaining knowledge of all 32 pools
# before we have a chance to fill them with enough information that the
# attacker cannot predict, we impose a rate limit of 10 reseeds/second (one
# per 100 ms). This ensures that a hypothetical 33rd pool would only be
# needed after a minimum of 13 years of sustained attack.
reseed_interval = 0.100 # time in seconds
def __init__(self):
self.reseed_count = 0
self.generator = FortunaGenerator.AESGenerator()
self.last_reseed = None
# Initialize 32 FortunaPool instances.
# NB: This is _not_ equivalent to [FortunaPool()]*32, which would give
# us 32 references to the _same_ FortunaPool instance (and cause the
# assertion below to fail).
self.pools = [FortunaPool() for i in range(32)] # 32 pools
assert(self.pools[0] is not self.pools[1])
def _forget_last_reseed(self):
# This is not part of the standard Fortuna definition, and using this
# function frequently can weaken Fortuna's ability to resist a state
# compromise extension attack, but we need this in order to properly
# implement Crypto.Random.atfork(). Otherwise, forked child processes
# might continue to use their parent's PRNG state for up to 100ms in
# some cases. (e.g. CVE-2013-1445)
self.last_reseed = None
def random_data(self, bytes):
current_time = time.time()
if (self.last_reseed is not None and self.last_reseed > current_time): # Avoid float comparison to None to make Py3k happy
warnings.warn("Clock rewind detected. Resetting last_reseed.", ClockRewindWarning)
self.last_reseed = None
if (self.pools[0].length >= self.min_pool_size and
(self.last_reseed is None or
current_time > self.last_reseed + self.reseed_interval)):
self._reseed(current_time)
# The following should fail if we haven't seeded the pool yet.
return self.generator.pseudo_random_data(bytes)
def _reseed(self, current_time=None):
if current_time is None:
current_time = time.time()
seed = []
self.reseed_count += 1
self.last_reseed = current_time
for i in which_pools(self.reseed_count):
seed.append(self.pools[i].digest())
self.pools[i].reset()
seed = b("").join(seed)
self.generator.reseed(seed)
def add_random_event(self, source_number, pool_number, data):
assert 1 <= len(data) <= 32
assert 0 <= source_number <= 255
assert 0 <= pool_number <= 31
self.pools[pool_number].append(bchr(source_number))
self.pools[pool_number].append(bchr(len(data)))
self.pools[pool_number].append(data)
# vim:set ts=4 sw=4 sts=4 expandtab:

View file

@ -1,132 +1,132 @@
# -*- coding: ascii -*-
#
# FortunaGenerator.py : Fortuna's internal PRNG
#
# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
__revision__ = "$Id$"
import sys
if sys.version_info[0] is 2 and sys.version_info[1] is 1:
from Crypto.Util.py21compat import *
from Crypto.Util.py3compat import *
import struct
from Crypto.Util.number import ceil_shift, exact_log2, exact_div
from Crypto.Util import Counter
from Crypto.Cipher import AES
from . import SHAd256
class AESGenerator(object):
"""The Fortuna "generator"
This is used internally by the Fortuna PRNG to generate arbitrary amounts
of pseudorandom data from a smaller amount of seed data.
The output is generated by running AES-256 in counter mode and re-keying
after every mebibyte (2**16 blocks) of output.
"""
block_size = AES.block_size # output block size in octets (128 bits)
key_size = 32 # key size in octets (256 bits)
# Because of the birthday paradox, we expect to find approximately one
# collision for every 2**64 blocks of output from a real random source.
# However, this code generates pseudorandom data by running AES in
# counter mode, so there will be no collisions until the counter
# (theoretically) wraps around at 2**128 blocks. Thus, in order to prevent
# Fortuna's pseudorandom output from deviating perceptibly from a true
# random source, Ferguson and Schneier specify a limit of 2**16 blocks
# without rekeying.
max_blocks_per_request = 2**16 # Allow no more than this number of blocks per _pseudo_random_data request
_four_kiblocks_of_zeros = b("\0") * block_size * 4096
def __init__(self):
self.counter = Counter.new(nbits=self.block_size*8, initial_value=0, little_endian=True)
self.key = None
# Set some helper constants
self.block_size_shift = exact_log2(self.block_size)
assert (1 << self.block_size_shift) == self.block_size
self.blocks_per_key = exact_div(self.key_size, self.block_size)
assert self.key_size == self.blocks_per_key * self.block_size
self.max_bytes_per_request = self.max_blocks_per_request * self.block_size
def reseed(self, seed):
if self.key is None:
self.key = b("\0") * self.key_size
self._set_key(SHAd256.new(self.key + seed).digest())
self.counter() # increment counter
assert len(self.key) == self.key_size
def pseudo_random_data(self, bytes):
assert bytes >= 0
num_full_blocks = bytes >> 20
remainder = bytes & ((1<<20)-1)
retval = []
for i in range(num_full_blocks):
retval.append(self._pseudo_random_data(1<<20))
retval.append(self._pseudo_random_data(remainder))
return b("").join(retval)
def _set_key(self, key):
self.key = key
self._cipher = AES.new(key, AES.MODE_CTR, counter=self.counter)
def _pseudo_random_data(self, bytes):
if not (0 <= bytes <= self.max_bytes_per_request):
raise AssertionError("You cannot ask for more than 1 MiB of data per request")
num_blocks = ceil_shift(bytes, self.block_size_shift) # num_blocks = ceil(bytes / self.block_size)
# Compute the output
retval = self._generate_blocks(num_blocks)[:bytes]
# Switch to a new key to avoid later compromises of this output (i.e.
# state compromise extension attacks)
self._set_key(self._generate_blocks(self.blocks_per_key))
assert len(retval) == bytes
assert len(self.key) == self.key_size
return retval
def _generate_blocks(self, num_blocks):
if self.key is None:
raise AssertionError("generator must be seeded before use")
assert 0 <= num_blocks <= self.max_blocks_per_request
retval = []
for i in range(num_blocks >> 12): # xrange(num_blocks / 4096)
retval.append(self._cipher.encrypt(self._four_kiblocks_of_zeros))
remaining_bytes = (num_blocks & 4095) << self.block_size_shift # (num_blocks % 4095) * self.block_size
retval.append(self._cipher.encrypt(self._four_kiblocks_of_zeros[:remaining_bytes]))
return b("").join(retval)
# vim:set ts=4 sw=4 sts=4 expandtab:
# -*- coding: ascii -*-
#
# FortunaGenerator.py : Fortuna's internal PRNG
#
# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
__revision__ = "$Id$"
import sys
if sys.version_info[0] is 2 and sys.version_info[1] is 1:
from Crypto.Util.py21compat import *
from Crypto.Util.py3compat import *
import struct
from Crypto.Util.number import ceil_shift, exact_log2, exact_div
from Crypto.Util import Counter
from Crypto.Cipher import AES
from . import SHAd256
class AESGenerator(object):
"""The Fortuna "generator"
This is used internally by the Fortuna PRNG to generate arbitrary amounts
of pseudorandom data from a smaller amount of seed data.
The output is generated by running AES-256 in counter mode and re-keying
after every mebibyte (2**16 blocks) of output.
"""
block_size = AES.block_size # output block size in octets (128 bits)
key_size = 32 # key size in octets (256 bits)
# Because of the birthday paradox, we expect to find approximately one
# collision for every 2**64 blocks of output from a real random source.
# However, this code generates pseudorandom data by running AES in
# counter mode, so there will be no collisions until the counter
# (theoretically) wraps around at 2**128 blocks. Thus, in order to prevent
# Fortuna's pseudorandom output from deviating perceptibly from a true
# random source, Ferguson and Schneier specify a limit of 2**16 blocks
# without rekeying.
max_blocks_per_request = 2**16 # Allow no more than this number of blocks per _pseudo_random_data request
_four_kiblocks_of_zeros = b("\0") * block_size * 4096
def __init__(self):
self.counter = Counter.new(nbits=self.block_size*8, initial_value=0, little_endian=True)
self.key = None
# Set some helper constants
self.block_size_shift = exact_log2(self.block_size)
assert (1 << self.block_size_shift) == self.block_size
self.blocks_per_key = exact_div(self.key_size, self.block_size)
assert self.key_size == self.blocks_per_key * self.block_size
self.max_bytes_per_request = self.max_blocks_per_request * self.block_size
def reseed(self, seed):
if self.key is None:
self.key = b("\0") * self.key_size
self._set_key(SHAd256.new(self.key + seed).digest())
self.counter() # increment counter
assert len(self.key) == self.key_size
def pseudo_random_data(self, bytes):
assert bytes >= 0
num_full_blocks = bytes >> 20
remainder = bytes & ((1<<20)-1)
retval = []
for i in range(num_full_blocks):
retval.append(self._pseudo_random_data(1<<20))
retval.append(self._pseudo_random_data(remainder))
return b("").join(retval)
def _set_key(self, key):
self.key = key
self._cipher = AES.new(key, AES.MODE_CTR, counter=self.counter)
def _pseudo_random_data(self, bytes):
if not (0 <= bytes <= self.max_bytes_per_request):
raise AssertionError("You cannot ask for more than 1 MiB of data per request")
num_blocks = ceil_shift(bytes, self.block_size_shift) # num_blocks = ceil(bytes / self.block_size)
# Compute the output
retval = self._generate_blocks(num_blocks)[:bytes]
# Switch to a new key to avoid later compromises of this output (i.e.
# state compromise extension attacks)
self._set_key(self._generate_blocks(self.blocks_per_key))
assert len(retval) == bytes
assert len(self.key) == self.key_size
return retval
def _generate_blocks(self, num_blocks):
if self.key is None:
raise AssertionError("generator must be seeded before use")
assert 0 <= num_blocks <= self.max_blocks_per_request
retval = []
for i in range(num_blocks >> 12): # xrange(num_blocks / 4096)
retval.append(self._cipher.encrypt(self._four_kiblocks_of_zeros))
remaining_bytes = (num_blocks & 4095) << self.block_size_shift # (num_blocks % 4095) * self.block_size
retval.append(self._cipher.encrypt(self._four_kiblocks_of_zeros[:remaining_bytes]))
return b("").join(retval)
# vim:set ts=4 sw=4 sts=4 expandtab:

View file

@ -1,46 +1,46 @@
#
# Random/OSRNG/fallback.py : Fallback entropy source for systems with os.urandom
#
# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
__revision__ = "$Id$"
__all__ = ['PythonOSURandomRNG']
import os
from .rng_base import BaseRNG
class PythonOSURandomRNG(BaseRNG):
name = "<os.urandom>"
def __init__(self):
self._read = os.urandom
BaseRNG.__init__(self)
def _close(self):
self._read = None
def new(*args, **kwargs):
return PythonOSURandomRNG(*args, **kwargs)
# vim:set ts=4 sw=4 sts=4 expandtab:
#
# Random/OSRNG/fallback.py : Fallback entropy source for systems with os.urandom
#
# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
__revision__ = "$Id$"
__all__ = ['PythonOSURandomRNG']
import os
from .rng_base import BaseRNG
class PythonOSURandomRNG(BaseRNG):
name = "<os.urandom>"
def __init__(self):
self._read = os.urandom
BaseRNG.__init__(self)
def _close(self):
self._read = None
def new(*args, **kwargs):
return PythonOSURandomRNG(*args, **kwargs)
# vim:set ts=4 sw=4 sts=4 expandtab:

View file

@ -1,74 +1,74 @@
#
# Random/OSRNG/nt.py : OS entropy source for MS Windows
#
# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
__revision__ = "$Id$"
__all__ = ['WindowsRNG']
from . import winrandom
from .rng_base import BaseRNG
class WindowsRNG(BaseRNG):
name = "<CryptGenRandom>"
def __init__(self):
self.__winrand = winrandom.new()
BaseRNG.__init__(self)
def flush(self):
"""Work around weakness in Windows RNG.
The CryptGenRandom mechanism in some versions of Windows allows an
attacker to learn 128 KiB of past and future output. As a workaround,
this function reads 128 KiB of 'random' data from Windows and discards
it.
For more information about the weaknesses in CryptGenRandom, see
_Cryptanalysis of the Random Number Generator of the Windows Operating
System_, by Leo Dorrendorf and Zvi Gutterman and Benny Pinkas
http://eprint.iacr.org/2007/419
"""
if self.closed:
raise ValueError("I/O operation on closed file")
data = self.__winrand.get_bytes(128*1024)
assert (len(data) == 128*1024)
BaseRNG.flush(self)
def _close(self):
self.__winrand = None
def _read(self, N):
# Unfortunately, research shows that CryptGenRandom doesn't provide
# forward secrecy and fails the next-bit test unless we apply a
# workaround, which we do here. See http://eprint.iacr.org/2007/419
# for information on the vulnerability.
self.flush()
data = self.__winrand.get_bytes(N)
self.flush()
return data
def new(*args, **kwargs):
return WindowsRNG(*args, **kwargs)
# vim:set ts=4 sw=4 sts=4 expandtab:
#
# Random/OSRNG/nt.py : OS entropy source for MS Windows
#
# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
__revision__ = "$Id$"
__all__ = ['WindowsRNG']
import winrandom
from .rng_base import BaseRNG
class WindowsRNG(BaseRNG):
name = "<CryptGenRandom>"
def __init__(self):
self.__winrand = winrandom.new()
BaseRNG.__init__(self)
def flush(self):
"""Work around weakness in Windows RNG.
The CryptGenRandom mechanism in some versions of Windows allows an
attacker to learn 128 KiB of past and future output. As a workaround,
this function reads 128 KiB of 'random' data from Windows and discards
it.
For more information about the weaknesses in CryptGenRandom, see
_Cryptanalysis of the Random Number Generator of the Windows Operating
System_, by Leo Dorrendorf and Zvi Gutterman and Benny Pinkas
http://eprint.iacr.org/2007/419
"""
if self.closed:
raise ValueError("I/O operation on closed file")
data = self.__winrand.get_bytes(128*1024)
assert (len(data) == 128*1024)
BaseRNG.flush(self)
def _close(self):
self.__winrand = None
def _read(self, N):
# Unfortunately, research shows that CryptGenRandom doesn't provide
# forward secrecy and fails the next-bit test unless we apply a
# workaround, which we do here. See http://eprint.iacr.org/2007/419
# for information on the vulnerability.
self.flush()
data = self.__winrand.get_bytes(N)
self.flush()
return data
def new(*args, **kwargs):
return WindowsRNG(*args, **kwargs)
# vim:set ts=4 sw=4 sts=4 expandtab:

View file

@ -1,86 +1,86 @@
#
# Random/OSRNG/posix.py : OS entropy source for POSIX systems
#
# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
__revision__ = "$Id$"
__all__ = ['DevURandomRNG']
import errno
import os
import stat
from .rng_base import BaseRNG
from Crypto.Util.py3compat import b
class DevURandomRNG(BaseRNG):
def __init__(self, devname=None):
if devname is None:
self.name = "/dev/urandom"
else:
self.name = devname
# Test that /dev/urandom is a character special device
f = open(self.name, "rb", 0)
fmode = os.fstat(f.fileno())[stat.ST_MODE]
if not stat.S_ISCHR(fmode):
f.close()
raise TypeError("%r is not a character special device" % (self.name,))
self.__file = f
BaseRNG.__init__(self)
def _close(self):
self.__file.close()
def _read(self, N):
# Starting with Python 3 open with buffering=0 returns a FileIO object.
# FileIO.read behaves like read(2) and not like fread(3) and thus we
# have to handle the case that read returns less data as requested here
# more carefully.
data = b("")
while len(data) < N:
try:
d = self.__file.read(N - len(data))
except IOError as e:
# read(2) has been interrupted by a signal; redo the read
if e.errno == errno.EINTR:
continue
raise
if d is None:
# __file is in non-blocking mode and no data is available
return data
if len(d) == 0:
# __file is in blocking mode and arrived at EOF
return data
data += d
return data
def new(*args, **kwargs):
return DevURandomRNG(*args, **kwargs)
# vim:set ts=4 sw=4 sts=4 expandtab:
#
# Random/OSRNG/posix.py : OS entropy source for POSIX systems
#
# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
__revision__ = "$Id$"
__all__ = ['DevURandomRNG']
import errno
import os
import stat
from .rng_base import BaseRNG
from Crypto.Util.py3compat import b
class DevURandomRNG(BaseRNG):
def __init__(self, devname=None):
if devname is None:
self.name = "/dev/urandom"
else:
self.name = devname
# Test that /dev/urandom is a character special device
f = open(self.name, "rb", 0)
fmode = os.fstat(f.fileno())[stat.ST_MODE]
if not stat.S_ISCHR(fmode):
f.close()
raise TypeError("%r is not a character special device" % (self.name,))
self.__file = f
BaseRNG.__init__(self)
def _close(self):
self.__file.close()
def _read(self, N):
# Starting with Python 3 open with buffering=0 returns a FileIO object.
# FileIO.read behaves like read(2) and not like fread(3) and thus we
# have to handle the case that read returns less data as requested here
# more carefully.
data = b("")
while len(data) < N:
try:
d = self.__file.read(N - len(data))
except IOError as e:
# read(2) has been interrupted by a signal; redo the read
if e.errno == errno.EINTR:
continue
raise
if d is None:
# __file is in non-blocking mode and no data is available
return data
if len(d) == 0:
# __file is in blocking mode and arrived at EOF
return data
data += d
return data
def new(*args, **kwargs):
return DevURandomRNG(*args, **kwargs)
# vim:set ts=4 sw=4 sts=4 expandtab:

View file

@ -1,88 +1,88 @@
#
# Random/OSRNG/rng_base.py : Base class for OSRNG
#
# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
__revision__ = "$Id$"
import sys
if sys.version_info[0] == 2 and sys.version_info[1] == 1:
from Crypto.Util.py21compat import *
class BaseRNG(object):
def __init__(self):
self.closed = False
self._selftest()
def __del__(self):
self.close()
def _selftest(self):
# Test that urandom can return data
data = self.read(16)
if len(data) != 16:
raise AssertionError("read truncated")
# Test that we get different data every time (if we don't, the RNG is
# probably malfunctioning)
data2 = self.read(16)
if data == data2:
raise AssertionError("OS RNG returned duplicate data")
# PEP 343: Support for the "with" statement
def __enter__(self):
pass
def __exit__(self):
"""PEP 343 support"""
self.close()
def close(self):
if not self.closed:
self._close()
self.closed = True
def flush(self):
pass
def read(self, N=-1):
"""Return N bytes from the RNG."""
if self.closed:
raise ValueError("I/O operation on closed file")
if not isinstance(N, int):
raise TypeError("an integer is required")
if N < 0:
raise ValueError("cannot read to end of infinite stream")
elif N == 0:
return ""
data = self._read(N)
if len(data) != N:
raise AssertionError("%s produced truncated output (requested %d, got %d)" % (self.name, N, len(data)))
return data
def _close(self):
raise NotImplementedError("child class must implement this")
def _read(self, N):
raise NotImplementedError("child class must implement this")
# vim:set ts=4 sw=4 sts=4 expandtab:
#
# Random/OSRNG/rng_base.py : Base class for OSRNG
#
# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# 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.
# ===================================================================
__revision__ = "$Id$"
import sys
if sys.version_info[0] == 2 and sys.version_info[1] == 1:
from Crypto.Util.py21compat import *
class BaseRNG(object):
def __init__(self):
self.closed = False
self._selftest()
def __del__(self):
self.close()
def _selftest(self):
# Test that urandom can return data
data = self.read(16)
if len(data) != 16:
raise AssertionError("read truncated")
# Test that we get different data every time (if we don't, the RNG is
# probably malfunctioning)
data2 = self.read(16)
if data == data2:
raise AssertionError("OS RNG returned duplicate data")
# PEP 343: Support for the "with" statement
def __enter__(self):
pass
def __exit__(self):
"""PEP 343 support"""
self.close()
def close(self):
if not self.closed:
self._close()
self.closed = True
def flush(self):
pass
def read(self, N=-1):
"""Return N bytes from the RNG."""
if self.closed:
raise ValueError("I/O operation on closed file")
if not isinstance(N, int):
raise TypeError("an integer is required")
if N < 0:
raise ValueError("cannot read to end of infinite stream")
elif N == 0:
return ""
data = self._read(N)
if len(data) != N:
raise AssertionError("%s produced truncated output (requested %d, got %d)" % (self.name, N, len(data)))
return data
def _close(self):
raise NotImplementedError("child class must implement this")
def _read(self, N):
raise NotImplementedError("child class must implement this")
# vim:set ts=4 sw=4 sts=4 expandtab:

Some files were not shown because too many files have changed in this diff Show more