Updated DB_Helper by adding firebase methods.
This commit is contained in:
parent
485cc3bbba
commit
c82121d036
1810 changed files with 537281 additions and 1 deletions
397
venv/Lib/site-packages/Crypto/Protocol/KDF.py
Normal file
397
venv/Lib/site-packages/Crypto/Protocol/KDF.py
Normal file
|
@ -0,0 +1,397 @@
|
|||
#
|
||||
# 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).
|
||||
"""
|
||||
|
||||
import struct
|
||||
from struct import unpack
|
||||
|
||||
from Crypto.Util.py3compat import *
|
||||
|
||||
from Crypto.Hash import SHA1, SHA256, HMAC, CMAC
|
||||
from Crypto.Util.strxor import strxor
|
||||
from Crypto.Util.number import size as bit_size, long_to_bytes, bytes_to_long
|
||||
|
||||
from Crypto.Util._raw_api import (load_pycryptodome_raw_lib,
|
||||
create_string_buffer,
|
||||
get_raw_buffer)
|
||||
from functools import reduce
|
||||
|
||||
_raw_salsa20_lib = load_pycryptodome_raw_lib("Crypto.Cipher._Salsa20",
|
||||
"""
|
||||
int Salsa20_8_core(const uint8_t *x, const uint8_t *y,
|
||||
uint8_t *out);
|
||||
uint32_t load_le_uint32(const uint8_t *in);
|
||||
""")
|
||||
|
||||
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 TypeError("Selected hash algorithm has a too short digest (%d bytes)." % digest)
|
||||
if len(salt) != 8:
|
||||
raise ValueError("Salt is not 8 bytes long (%d bytes instead)." % len(salt))
|
||||
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 function 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()
|
||||
|
||||
def link(s):
|
||||
s[0], s[1] = s[1], prf(password, s[1])
|
||||
return s[0]
|
||||
|
||||
key = b('')
|
||||
i = 1
|
||||
while len(key)<dkLen:
|
||||
s = [ prf(password, salt + struct.pack(">I", i)) ] * 2
|
||||
key += reduce(strxor, (link(s) for j in range(count)) )
|
||||
i += 1
|
||||
return key[:dkLen]
|
||||
|
||||
|
||||
class _S2V(object):
|
||||
"""String-to-vector PRF as defined in `RFC5297`_.
|
||||
|
||||
This class implements a pseudorandom function family
|
||||
based on CMAC that takes as input a vector of strings.
|
||||
|
||||
.. _RFC5297: http://tools.ietf.org/html/rfc5297
|
||||
"""
|
||||
|
||||
def __init__(self, key, ciphermod, cipher_params=None):
|
||||
"""Initialize the S2V PRF.
|
||||
|
||||
:Parameters:
|
||||
key : byte string
|
||||
A secret that can be used as key for CMACs
|
||||
based on ciphers from ``ciphermod``.
|
||||
ciphermod : module
|
||||
A block cipher module from `Crypto.Cipher`.
|
||||
cipher_params : dictionary
|
||||
A set of extra parameters to use to create a cipher instance.
|
||||
"""
|
||||
|
||||
self._key = key
|
||||
self._ciphermod = ciphermod
|
||||
self._last_string = self._cache = bchr(0)*ciphermod.block_size
|
||||
self._n_updates = ciphermod.block_size*8-1
|
||||
if cipher_params is None:
|
||||
self._cipher_params = {}
|
||||
else:
|
||||
self._cipher_params = dict(cipher_params)
|
||||
|
||||
@staticmethod
|
||||
def new(key, ciphermod):
|
||||
"""Create a new S2V PRF.
|
||||
|
||||
:Parameters:
|
||||
key : byte string
|
||||
A secret that can be used as key for CMACs
|
||||
based on ciphers from ``ciphermod``.
|
||||
ciphermod : module
|
||||
A block cipher module from `Crypto.Cipher`.
|
||||
"""
|
||||
return _S2V(key, ciphermod)
|
||||
|
||||
def _double(self, bs):
|
||||
doubled = bytes_to_long(bs)<<1
|
||||
if bord(bs[0]) & 0x80:
|
||||
doubled ^= 0x87
|
||||
return long_to_bytes(doubled, len(bs))[-len(bs):]
|
||||
|
||||
def update(self, item):
|
||||
"""Pass the next component of the vector.
|
||||
|
||||
The maximum number of components you can pass is equal to the block
|
||||
length of the cipher (in bits) minus 1.
|
||||
|
||||
:Parameters:
|
||||
item : byte string
|
||||
The next component of the vector.
|
||||
:Raise TypeError: when the limit on the number of components has been reached.
|
||||
:Raise ValueError: when the component is empty
|
||||
"""
|
||||
|
||||
if not item:
|
||||
raise ValueError("A component cannot be empty")
|
||||
|
||||
if self._n_updates==0:
|
||||
raise TypeError("Too many components passed to S2V")
|
||||
self._n_updates -= 1
|
||||
|
||||
mac = CMAC.new(self._key,
|
||||
msg=self._last_string,
|
||||
ciphermod=self._ciphermod,
|
||||
cipher_params=self._cipher_params)
|
||||
self._cache = strxor(self._double(self._cache), mac.digest())
|
||||
self._last_string = item
|
||||
|
||||
def derive(self):
|
||||
""""Derive a secret from the vector of components.
|
||||
|
||||
:Return: a byte string, as long as the block length of the cipher.
|
||||
"""
|
||||
|
||||
if len(self._last_string)>=16:
|
||||
final = self._last_string[:-16] + strxor(self._last_string[-16:], self._cache)
|
||||
else:
|
||||
padded = (self._last_string + bchr(0x80)+ bchr(0)*15)[:16]
|
||||
final = strxor(padded, self._double(self._cache))
|
||||
mac = CMAC.new(self._key,
|
||||
msg=final,
|
||||
ciphermod=self._ciphermod,
|
||||
cipher_params=self._cipher_params)
|
||||
return mac.digest()
|
||||
|
||||
|
||||
def HKDF(master, key_len, salt, hashmod, num_keys=1, context=None):
|
||||
"""Derive one or more keys from a master secret using
|
||||
the HMAC-based KDF defined in RFC5869_.
|
||||
|
||||
This KDF is not suitable for deriving keys from a password or for key
|
||||
stretching. Use `PBKDF2` instead.
|
||||
|
||||
HKDF is a key derivation method approved by NIST in `SP 800 56C`__.
|
||||
|
||||
:Parameters:
|
||||
master : byte string
|
||||
The unguessable value used by the KDF to generate the other keys.
|
||||
It must be a high-entropy secret, though not necessarily uniform.
|
||||
It must not be a password.
|
||||
salt : byte string
|
||||
A non-secret, reusable value that strengthens the randomness
|
||||
extraction step.
|
||||
Ideally, it is as long as the digest size of the chosen hash.
|
||||
If empty, a string of zeroes in used.
|
||||
key_len : integer
|
||||
The length in bytes of every derived key.
|
||||
hashmod : module
|
||||
A cryptographic hash algorithm from `Crypto.Hash`.
|
||||
`Crypto.Hash.SHA512` is a good choice.
|
||||
num_keys : integer
|
||||
The number of keys to derive. Every key is ``key_len`` bytes long.
|
||||
The maximum cumulative length of all keys is
|
||||
255 times the digest size.
|
||||
context : byte string
|
||||
Optional identifier describing what the keys are used for.
|
||||
|
||||
:Return: A byte string or a tuple of byte strings.
|
||||
|
||||
.. _RFC5869: http://tools.ietf.org/html/rfc5869
|
||||
.. __: http://csrc.nist.gov/publications/nistpubs/800-56C/SP-800-56C.pdf
|
||||
"""
|
||||
|
||||
output_len = key_len * num_keys
|
||||
if output_len > (255 * hashmod.digest_size):
|
||||
raise ValueError("Too much secret data to derive")
|
||||
if not salt:
|
||||
salt = bchr(0) * hashmod.digest_size
|
||||
if context is None:
|
||||
context = b("")
|
||||
|
||||
# Step 1: extract
|
||||
hmac = HMAC.new(salt, master, digestmod=hashmod)
|
||||
prk = hmac.digest()
|
||||
|
||||
# Step 2: expand
|
||||
t = [b("")]
|
||||
n = 1
|
||||
tlen = 0
|
||||
while tlen < output_len:
|
||||
hmac = HMAC.new(prk, t[-1] + context + bchr(n), digestmod=hashmod)
|
||||
t.append(hmac.digest())
|
||||
tlen += hashmod.digest_size
|
||||
n += 1
|
||||
derived_output = b("").join(t)
|
||||
if num_keys == 1:
|
||||
return derived_output[:key_len]
|
||||
kol = [derived_output[idx:idx + key_len]
|
||||
for idx in range(0, output_len, key_len)]
|
||||
return list(kol[:num_keys])
|
||||
|
||||
|
||||
def _scryptBlockMix(blocks, len_blocks):
|
||||
"""Hash function for ROMix."""
|
||||
|
||||
x = blocks[-1]
|
||||
core = _raw_salsa20_lib.Salsa20_8_core
|
||||
result = [ create_string_buffer(64) for _ in range(len(blocks)) ]
|
||||
for i in range(len(blocks)):
|
||||
core(x, blocks[i], result[i])
|
||||
x = result[i]
|
||||
return [result[i + j] for j in range(2)
|
||||
for i in range(0, len_blocks, 2)]
|
||||
|
||||
|
||||
def _scryptROMix(blocks, n):
|
||||
"""Sequential memory-hard function for scrypt."""
|
||||
|
||||
x = [blocks[i:i + 64] for i in range(0, len(blocks), 64)]
|
||||
len_x = len(x)
|
||||
v = [None]*n
|
||||
load_le_uint32 = _raw_salsa20_lib.load_le_uint32
|
||||
for i in range(n):
|
||||
v[i] = x
|
||||
x = _scryptBlockMix(x, len_x)
|
||||
for i in range(n):
|
||||
j = load_le_uint32(x[-1]) & (n - 1)
|
||||
t = [strxor(x[idx], v[j][idx]) for idx in range(len_x)]
|
||||
x = _scryptBlockMix(t, len_x)
|
||||
return b("").join([get_raw_buffer(y) for y in x])
|
||||
|
||||
|
||||
def scrypt(password, salt, key_len, N, r, p, num_keys=1):
|
||||
"""Derive one or more keys from a passphrase.
|
||||
|
||||
This function performs key derivation according to
|
||||
the `scrypt`_ algorithm, introduced in Percival's paper
|
||||
`"Stronger key derivation via sequential memory-hard functions"`__.
|
||||
|
||||
This implementation is based on the `RFC draft`__.
|
||||
|
||||
:Parameters:
|
||||
password : string
|
||||
The secret pass phrase to generate the keys 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.
|
||||
key_len : integer
|
||||
The length in bytes of every derived key.
|
||||
N : integer
|
||||
CPU/Memory cost parameter. It must be a power of 2 and less
|
||||
than ``2**32``.
|
||||
r : integer
|
||||
Block size parameter.
|
||||
p : integer
|
||||
Parallelization parameter.
|
||||
It must be no greater than ``(2**32-1)/(4r)``.
|
||||
num_keys : integer
|
||||
The number of keys to derive. Every key is ``key_len`` bytes long.
|
||||
By default, only 1 key is generated.
|
||||
The maximum cumulative length of all keys is ``(2**32-1)*32``
|
||||
(that is, 128TB).
|
||||
|
||||
A good choice of parameters *(N, r , p)* was suggested
|
||||
by Colin Percival in his `presentation in 2009`__:
|
||||
|
||||
- *(16384, 8, 1)* for interactive logins (<=100ms)
|
||||
- *(1048576, 8, 1)* for file encryption (<=5s)
|
||||
|
||||
:Return: A byte string or a tuple of byte strings.
|
||||
|
||||
.. _scrypt: http://www.tarsnap.com/scrypt.html
|
||||
.. __: http://www.tarsnap.com/scrypt/scrypt.pdf
|
||||
.. __: http://tools.ietf.org/html/draft-josefsson-scrypt-kdf-03
|
||||
.. __: http://www.tarsnap.com/scrypt/scrypt-slides.pdf
|
||||
"""
|
||||
|
||||
if 2 ** (bit_size(N) - 1) != N:
|
||||
raise ValueError("N must be a power of 2")
|
||||
if N >= 2 ** 32:
|
||||
raise ValueError("N is too big")
|
||||
if p > ((2 ** 32 - 1) * 32) // (128 * r):
|
||||
raise ValueError("p or r are too big")
|
||||
|
||||
prf_hmac_sha256 = lambda p, s: HMAC.new(p, s, SHA256).digest()
|
||||
|
||||
blocks = PBKDF2(password, salt, p * 128 * r, 1, prf=prf_hmac_sha256)
|
||||
|
||||
blocks = b("").join([_scryptROMix(blocks[x:x + 128 * r], N)
|
||||
for x in range(0, len(blocks), 128 * r)])
|
||||
|
||||
dk = PBKDF2(password, blocks, key_len * num_keys, 1,
|
||||
prf=prf_hmac_sha256)
|
||||
|
||||
if num_keys == 1:
|
||||
return dk
|
||||
|
||||
kol = [dk[idx:idx + key_len]
|
||||
for idx in range(0, key_len * num_keys, key_len)]
|
||||
return kol
|
331
venv/Lib/site-packages/Crypto/Protocol/SecretSharing.py
Normal file
331
venv/Lib/site-packages/Crypto/Protocol/SecretSharing.py
Normal file
|
@ -0,0 +1,331 @@
|
|||
#
|
||||
# SecretSharing.py : distribute a secret amongst a group of participants
|
||||
#
|
||||
# ===================================================================
|
||||
#
|
||||
# Copyright (c) 2014, Legrandin <helderijs@gmail.com>
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in
|
||||
# the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
# ===================================================================
|
||||
|
||||
"""This file implements secret sharing protocols.
|
||||
|
||||
In a *(k, n)* secret sharing protocol, a honest dealer breaks a secret
|
||||
into multiple shares that are distributed amongst *n* players.
|
||||
|
||||
The protocol guarantees that nobody can learn anything about the
|
||||
secret, unless *k* players gather together to assemble their shares.
|
||||
"""
|
||||
|
||||
from Crypto.Util.py3compat import *
|
||||
from Crypto.Util import number
|
||||
from Crypto.Util.number import long_to_bytes, bytes_to_long
|
||||
from Crypto.Random import get_random_bytes as rng
|
||||
|
||||
def _mult_gf2(f1, f2):
|
||||
"""Multiply two polynomials in GF(2)"""
|
||||
|
||||
# Ensure f2 is the smallest
|
||||
if f2 > f1:
|
||||
f1, f2 = f2, f1
|
||||
z = 0
|
||||
while f2:
|
||||
if f2 & 1:
|
||||
z ^= f1
|
||||
f1 <<= 1
|
||||
f2 >>= 1
|
||||
return z
|
||||
|
||||
|
||||
def _div_gf2(a, b):
|
||||
"""
|
||||
Compute division of polynomials over GF(2).
|
||||
Given a and b, it finds two polynomials q and r such that:
|
||||
|
||||
a = b*q + r with deg(r)<deg(b)
|
||||
"""
|
||||
|
||||
if (a < b):
|
||||
return 0, a
|
||||
|
||||
deg = number.size
|
||||
q = 0
|
||||
r = a
|
||||
d = deg(b)
|
||||
while deg(r) >= d:
|
||||
s = 1 << (deg(r) - d)
|
||||
q ^= s
|
||||
r ^= _mult_gf2(b, s)
|
||||
return (q, r)
|
||||
|
||||
|
||||
class _Element(object):
|
||||
"""Element of GF(2^128) field"""
|
||||
|
||||
# The irreducible polynomial defining this field is 1+x+x^2+x^7+x^128
|
||||
irr_poly = 1 + 2 + 4 + 128 + 2 ** 128
|
||||
|
||||
def __init__(self, encoded_value):
|
||||
"""Initialize the element to a certain value.
|
||||
|
||||
The value passed as parameter is internally encoded as
|
||||
a 128-bit integer, where each bit represents a polynomial
|
||||
coefficient. The LSB is the constant coefficient.
|
||||
"""
|
||||
|
||||
if isinstance(encoded_value, int):
|
||||
self._value = encoded_value
|
||||
elif len(encoded_value) == 16:
|
||||
self._value = bytes_to_long(encoded_value)
|
||||
else:
|
||||
raise ValueError("The encoded value must be an integer or a 16 byte string")
|
||||
|
||||
def __int__(self):
|
||||
"""Return the field element, encoded as a 128-bit integer."""
|
||||
|
||||
return self._value
|
||||
|
||||
def encode(self):
|
||||
"""Return the field element, encoded as a 16 byte string."""
|
||||
|
||||
return long_to_bytes(self._value, 16)
|
||||
|
||||
def __mul__(self, factor):
|
||||
|
||||
f1 = self._value
|
||||
f2 = factor._value
|
||||
|
||||
# Make sure that f2 is the smallest, to speed up the loop
|
||||
if f2 > f1:
|
||||
f1, f2 = f2, f1
|
||||
|
||||
if self.irr_poly in (f1, f2):
|
||||
return _Element(0)
|
||||
mask1 = 2 ** 128
|
||||
v, z = f1, 0
|
||||
while f2:
|
||||
if f2 & 1:
|
||||
z ^= v
|
||||
v <<= 1
|
||||
if v & mask1:
|
||||
v ^= self.irr_poly
|
||||
f2 >>= 1
|
||||
return _Element(z)
|
||||
|
||||
def __add__(self, term):
|
||||
return _Element(self._value ^ term._value)
|
||||
|
||||
def inverse(self):
|
||||
"""Return the inverse of this element in GF(2^128)."""
|
||||
|
||||
# We use the Extended GCD algorithm
|
||||
# http://en.wikipedia.org/wiki/Polynomial_greatest_common_divisor
|
||||
|
||||
r0, r1 = self._value, self.irr_poly
|
||||
s0, s1 = 1, 0
|
||||
while r1 > 0:
|
||||
q = _div_gf2(r0, r1)[0]
|
||||
r0, r1 = r1, r0 ^ _mult_gf2(q, r1)
|
||||
s0, s1 = s1, s0 ^ _mult_gf2(q, s1)
|
||||
return _Element(s0)
|
||||
|
||||
|
||||
class Shamir(object):
|
||||
"""Shamir's secret sharing scheme.
|
||||
|
||||
This class implements the Shamir's secret sharing protocol
|
||||
described in his original paper `"How to share a secret"`__.
|
||||
|
||||
All shares are points over a 2-dimensional curve. At least
|
||||
*k* points (that is, shares) are required to reconstruct the curve,
|
||||
and therefore the secret.
|
||||
|
||||
This implementation is primarilly meant to protect AES128 keys.
|
||||
To that end, the secret is associated to a curve in
|
||||
the field GF(2^128) defined by the irreducible polynomial
|
||||
*x^128 + x^7 + x^2 + x + 1* (the same used in AES-GCM).
|
||||
The shares are always 16 bytes long.
|
||||
|
||||
Data produced by this implementation are compatible to the popular
|
||||
`ssss`_ tool if used with 128 bit security (parameter *"-s 128"*)
|
||||
and no dispersion (parameter *"-D"*).
|
||||
|
||||
As an example, the following code shows how to protect a file meant
|
||||
for 5 people, in such a way that 2 of the 5 are required to
|
||||
reassemble it.
|
||||
|
||||
>>> from binascii import hexlify
|
||||
>>> from Crypto.Cipher import AES
|
||||
>>> from Crypto.Random import get_random_bytes
|
||||
>>> from Crypto.Protocol.secret_sharing import Shamir
|
||||
>>>
|
||||
>>> key = get_random_bytes(16)
|
||||
>>> shares = Shamir.split(2, 5, key)
|
||||
>>> for idx, share in shares:
|
||||
>>> print "Index #%d: %s" % (idx, hexlify(share))
|
||||
>>>
|
||||
>>> fi = open("clear_file.txt", "rb")
|
||||
>>> fo = open("enc_file.txt", "wb")
|
||||
>>>
|
||||
>>> cipher = AES.new(key, AES.MODE_EAX)
|
||||
>>> ct, tag = cipher.encrypt(fi.read()), cipher.digest()
|
||||
>>> fo.write(nonce + tag + ct)
|
||||
|
||||
Each person can be given one share and the encrypted file.
|
||||
|
||||
When 2 people gather together with their shares, the can
|
||||
decrypt the file:
|
||||
|
||||
>>> from binascii import unhexlify
|
||||
>>> from Crypto.Cipher import AES
|
||||
>>> from Crypto.Protocol.secret_sharing import Shamir
|
||||
>>>
|
||||
>>> shares = []
|
||||
>>> for x in range(2):
|
||||
>>> in_str = raw_input("Enter index and share separated by comma: ")
|
||||
>>> idx, share = [ strip(s) for s in in_str.split(",") ]
|
||||
>>> shares.append((idx, unhexlify(share)))
|
||||
>>> key = Shamir.combine(shares)
|
||||
>>>
|
||||
>>> fi = open("enc_file.txt", "rb")
|
||||
>>> nonce, tag = [ fi.read(16) for x in range(2) ]
|
||||
>>> cipher = AES.new(key, AES.MODE_EAX, nonce)
|
||||
>>> try:
|
||||
>>> result = cipher.decrypt(fi.read())
|
||||
>>> cipher.verify(tag)
|
||||
>>> with open("clear_file2.txt", "wb") as fo:
|
||||
>>> fo.write(result)
|
||||
>>> except ValueError:
|
||||
>>> print "The shares were incorrect"
|
||||
|
||||
:attention:
|
||||
Reconstruction does not guarantee that the result is authentic.
|
||||
In particular, a malicious participant in the scheme has the
|
||||
ability to force an algebric transformation on the result by
|
||||
manipulating her share.
|
||||
|
||||
It is important to use the scheme in combination with an
|
||||
authentication mechanism (the EAX cipher mode in the example).
|
||||
|
||||
.. __: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.80.8910&rep=rep1&type=pdf
|
||||
.. _ssss: http://point-at-infinity.org/ssss/
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def split(k, n, secret):
|
||||
"""Split a secret into *n* shares.
|
||||
|
||||
The secret can be reconstructed later when *k* shares
|
||||
out of the original *n* are recombined. Each share
|
||||
must be kept confidential to the person it was
|
||||
assigned to.
|
||||
|
||||
Each share is associated to an index (starting from 1),
|
||||
which must be presented when the secret is recombined.
|
||||
|
||||
:Parameters:
|
||||
k : integer
|
||||
The number of shares that must be present in order to reconstruct
|
||||
the secret.
|
||||
n : integer
|
||||
The total number of shares to create (>*k*).
|
||||
secret : byte string
|
||||
The 16 byte string (e.g. the AES128 key) to split.
|
||||
:Return:
|
||||
*n* tuples, each containing the unique index (an integer) and
|
||||
the share (a byte string, 16 bytes long) meant for a
|
||||
participant.
|
||||
"""
|
||||
|
||||
#
|
||||
# We create a polynomial with random coefficients in GF(2^128):
|
||||
#
|
||||
# p(x) = \sum_{i=0}^{k-1} c_i * x^i
|
||||
#
|
||||
# c_0 is the encoded secret
|
||||
#
|
||||
|
||||
coeffs = [_Element(rng(16)) for i in range(k - 1)]
|
||||
coeffs.insert(0, _Element(secret))
|
||||
|
||||
# Each share is y_i = p(x_i) where x_i is the public index
|
||||
# associated to each of the n users.
|
||||
|
||||
def make_share(user, coeffs):
|
||||
share, x, idx = [_Element(p) for p in (0, 1, user)]
|
||||
for coeff in coeffs:
|
||||
share += coeff * x
|
||||
x *= idx
|
||||
return share.encode()
|
||||
|
||||
return [(i, make_share(i, coeffs)) for i in range(1, n + 1)]
|
||||
|
||||
@staticmethod
|
||||
def combine(shares):
|
||||
"""Recombine a secret, if enough shares are presented.
|
||||
|
||||
:Parameters:
|
||||
shares : tuples
|
||||
At least *k* tuples, each containin the index (an integer) and
|
||||
the share (a byte string, 16 bytes long) that were assigned to
|
||||
a participant.
|
||||
:Return:
|
||||
The original secret, as a byte string (16 bytes long).
|
||||
"""
|
||||
|
||||
#
|
||||
# Given k points (x,y), the interpolation polynomial of degree k-1 is:
|
||||
#
|
||||
# L(x) = \sum_{j=0}^{k-1} y_i * l_j(x)
|
||||
#
|
||||
# where:
|
||||
#
|
||||
# l_j(x) = \prod_{ \overset{0 \le m \le k-1}{m \ne j} }
|
||||
# \frac{x - x_m}{x_j - x_m}
|
||||
#
|
||||
# However, in this case we are purely intersted in the constant
|
||||
# coefficient of L(x).
|
||||
#
|
||||
|
||||
shares = [[_Element(y) for y in x] for x in shares]
|
||||
|
||||
result = _Element(0)
|
||||
k = len(shares)
|
||||
for j in range(k):
|
||||
x_j, y_j = shares[j]
|
||||
|
||||
coeff_0_l = _Element(0)
|
||||
while not int(coeff_0_l):
|
||||
coeff_0_l = _Element(rng(16))
|
||||
inv = coeff_0_l.inverse()
|
||||
|
||||
for m in range(k):
|
||||
x_m = shares[m][0]
|
||||
if m != j:
|
||||
t = x_m * (x_j + x_m).inverse()
|
||||
coeff_0_l *= t
|
||||
result += y_j * coeff_0_l * inv
|
||||
return result.encode()
|
43
venv/Lib/site-packages/Crypto/Protocol/__init__.py
Normal file
43
venv/Lib/site-packages/Crypto/Protocol/__init__.py
Normal file
|
@ -0,0 +1,43 @@
|
|||
# ===================================================================
|
||||
#
|
||||
# Copyright (c) 2014, Legrandin <helderijs@gmail.com>
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in
|
||||
# the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
# ===================================================================
|
||||
|
||||
"""Cryptographic protocols
|
||||
|
||||
Implements various cryptographic protocols. (Don't expect to find
|
||||
network protocols here.)
|
||||
|
||||
Crypto.Protocol.KDF
|
||||
A collection of standard key derivation functions.
|
||||
|
||||
Crypto.Protocol.SecretSharing
|
||||
Distribute a secret amongst a group of participants.
|
||||
"""
|
||||
|
||||
__all__ = ['KDF', 'SecretSharing']
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue