mirror of
https://github.com/Legrandin/pycryptodome.git
synced 2025-12-08 05:19:46 +00:00
First version of bcrypt
This commit is contained in:
parent
c33fcd2c66
commit
ca975e96ad
8 changed files with 451 additions and 23 deletions
122
lib/Crypto/Cipher/_EKSBlowfish.py
Normal file
122
lib/Crypto/Cipher/_EKSBlowfish.py
Normal file
|
|
@ -0,0 +1,122 @@
|
||||||
|
# ===================================================================
|
||||||
|
#
|
||||||
|
# Copyright (c) 2019, 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.
|
||||||
|
# ===================================================================
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from Crypto.Cipher import _create_cipher
|
||||||
|
from Crypto.Util._raw_api import (load_pycryptodome_raw_lib,
|
||||||
|
VoidPointer, SmartPointer, c_size_t,
|
||||||
|
c_uint8_ptr, c_uint)
|
||||||
|
|
||||||
|
_raw_blowfish_lib = load_pycryptodome_raw_lib(
|
||||||
|
"Crypto.Cipher._raw_eksblowfish",
|
||||||
|
"""
|
||||||
|
int EKSBlowfish_start_operation(const uint8_t key[],
|
||||||
|
size_t key_len,
|
||||||
|
const uint8_t salt[16],
|
||||||
|
unsigned cost,
|
||||||
|
void **pResult);
|
||||||
|
int EKSBlowfish_encrypt(const void *state,
|
||||||
|
const uint8_t *in,
|
||||||
|
uint8_t *out,
|
||||||
|
size_t data_len);
|
||||||
|
int EKSBlowfish_decrypt(const void *state,
|
||||||
|
const uint8_t *in,
|
||||||
|
uint8_t *out,
|
||||||
|
size_t data_len);
|
||||||
|
int EKSBlowfish_stop_operation(void *state);
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _create_base_cipher(dict_parameters):
|
||||||
|
"""This method instantiates and returns a smart pointer to
|
||||||
|
a low-level base cipher. It will absorb named parameters in
|
||||||
|
the process."""
|
||||||
|
|
||||||
|
try:
|
||||||
|
key = dict_parameters.pop("key")
|
||||||
|
salt = dict_parameters.pop("salt")
|
||||||
|
cost = dict_parameters.pop("cost")
|
||||||
|
except KeyError as e:
|
||||||
|
raise TypeError("Missing EKSBlowfish parameter: " + str(e))
|
||||||
|
|
||||||
|
if len(key) not in key_size:
|
||||||
|
raise ValueError("Incorrect EKSBlowfish key length (%d bytes)" % len(key))
|
||||||
|
|
||||||
|
if len(salt) != 16:
|
||||||
|
raise ValueError("Incorrect salt length (%d bytes)" % len(salt))
|
||||||
|
|
||||||
|
start_operation = _raw_blowfish_lib.EKSBlowfish_start_operation
|
||||||
|
stop_operation = _raw_blowfish_lib.EKSBlowfish_stop_operation
|
||||||
|
|
||||||
|
void_p = VoidPointer()
|
||||||
|
result = start_operation(c_uint8_ptr(key),
|
||||||
|
c_size_t(len(key)),
|
||||||
|
c_uint8_ptr(salt),
|
||||||
|
c_uint(cost),
|
||||||
|
void_p.address_of())
|
||||||
|
if result:
|
||||||
|
raise ValueError("Error %X while instantiating the EKSBlowfish cipher"
|
||||||
|
% result)
|
||||||
|
return SmartPointer(void_p.get(), stop_operation)
|
||||||
|
|
||||||
|
|
||||||
|
def new(key, mode, salt, cost):
|
||||||
|
"""Create a new EKSBlowfish cipher
|
||||||
|
|
||||||
|
Args:
|
||||||
|
|
||||||
|
key (bytes, bytearray, memoryview):
|
||||||
|
The secret key to use in the symmetric cipher.
|
||||||
|
Its length can vary from 5 to 56 bytes.
|
||||||
|
|
||||||
|
mode (one of the supported ``MODE_*`` constants):
|
||||||
|
The chaining mode to use for encryption or decryption.
|
||||||
|
|
||||||
|
salt (bytes, bytearray, memoryview):
|
||||||
|
The 16 byte salt that bcrypt uses to thwart rainbow table attacks
|
||||||
|
|
||||||
|
cost (integer):
|
||||||
|
The complexity factor in bcrypt
|
||||||
|
|
||||||
|
:Return: an EKSBlowfish object
|
||||||
|
"""
|
||||||
|
|
||||||
|
kwargs = { 'salt':salt, 'cost':cost }
|
||||||
|
return _create_cipher(sys.modules[__name__], key, mode, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
MODE_ECB = 1
|
||||||
|
|
||||||
|
# Size of a data block (in bytes)
|
||||||
|
block_size = 8
|
||||||
|
# Size of a key (in bytes)
|
||||||
|
key_size = range(4, 56 + 1)
|
||||||
15
lib/Crypto/Cipher/_EKSBlowfish.pyi
Normal file
15
lib/Crypto/Cipher/_EKSBlowfish.pyi
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
from typing import Union, Iterable
|
||||||
|
|
||||||
|
from Crypto.Cipher._mode_ecb import EcbMode
|
||||||
|
|
||||||
|
MODE_ECB: int
|
||||||
|
|
||||||
|
Buffer = Union[bytes, bytearray, memoryview]
|
||||||
|
|
||||||
|
def new(key: Buffer,
|
||||||
|
mode: int,
|
||||||
|
salt: Buffer,
|
||||||
|
cost: int) -> EcbMode: ...
|
||||||
|
|
||||||
|
block_size: int
|
||||||
|
key_size: Iterable[int]
|
||||||
|
|
@ -43,7 +43,7 @@ from Crypto.Random import get_random_bytes
|
||||||
__all__ = ['new', 'HMAC']
|
__all__ = ['new', 'HMAC']
|
||||||
|
|
||||||
|
|
||||||
class HMAC:
|
class HMAC(object):
|
||||||
"""An HMAC hash object.
|
"""An HMAC hash object.
|
||||||
Do not instantiate directly. Use the :func:`new` function.
|
Do not instantiate directly. Use the :func:`new` function.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,13 +21,16 @@
|
||||||
# SOFTWARE.
|
# SOFTWARE.
|
||||||
# ===================================================================
|
# ===================================================================
|
||||||
|
|
||||||
|
import re
|
||||||
import struct
|
import struct
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
|
|
||||||
from Crypto.Util.py3compat import tobytes, bord, _copy_bytes, iter_range
|
from Crypto.Util.py3compat import (tobytes, bord, _copy_bytes, iter_range,
|
||||||
|
tostr, bchr, bstr)
|
||||||
|
|
||||||
from Crypto.Hash import SHA1, SHA256, HMAC, CMAC
|
from Crypto.Hash import SHA1, SHA256, HMAC, CMAC, BLAKE2s
|
||||||
from Crypto.Util.strxor import strxor
|
from Crypto.Util.strxor import strxor
|
||||||
|
from Crypto.Random import get_random_bytes
|
||||||
from Crypto.Util.number import size as bit_size, long_to_bytes, bytes_to_long
|
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,
|
from Crypto.Util._raw_api import (load_pycryptodome_raw_lib,
|
||||||
|
|
@ -328,6 +331,7 @@ def HKDF(master, key_len, salt, hashmod, num_keys=1, context=None):
|
||||||
return list(kol[:num_keys])
|
return list(kol[:num_keys])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def scrypt(password, salt, key_len, N, r, p, num_keys=1):
|
def scrypt(password, salt, key_len, N, r, p, num_keys=1):
|
||||||
"""Derive one or more keys from a passphrase.
|
"""Derive one or more keys from a passphrase.
|
||||||
|
|
||||||
|
|
@ -415,3 +419,153 @@ def scrypt(password, salt, key_len, N, r, p, num_keys=1):
|
||||||
kol = [dk[idx:idx + key_len]
|
kol = [dk[idx:idx + key_len]
|
||||||
for idx in iter_range(0, key_len * num_keys, key_len)]
|
for idx in iter_range(0, key_len * num_keys, key_len)]
|
||||||
return kol
|
return kol
|
||||||
|
|
||||||
|
|
||||||
|
def _bcrypt_encode(data):
|
||||||
|
s = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
||||||
|
|
||||||
|
bits = []
|
||||||
|
for c in data:
|
||||||
|
bits_c = bin(bord(c))[2:].zfill(8)
|
||||||
|
bits.append(bstr(bits_c))
|
||||||
|
bits = b"".join(bits)
|
||||||
|
|
||||||
|
bits6 = [ bits[idx:idx+6] for idx in range(0, len(bits), 6) ]
|
||||||
|
|
||||||
|
result = []
|
||||||
|
for g in bits6[:-1]:
|
||||||
|
idx = int(g, 2)
|
||||||
|
result.append(s[idx])
|
||||||
|
|
||||||
|
g = bits6[-1]
|
||||||
|
idx = int(g, 2) << (6 - len(g))
|
||||||
|
result.append(s[idx])
|
||||||
|
result = "".join(result)
|
||||||
|
|
||||||
|
return tobytes(result)
|
||||||
|
|
||||||
|
|
||||||
|
def _bcrypt_decode(data):
|
||||||
|
s = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
||||||
|
|
||||||
|
bits = []
|
||||||
|
for c in tostr(data):
|
||||||
|
idx = s.find(c)
|
||||||
|
bits6 = bin(idx)[2:].zfill(6)
|
||||||
|
bits.append(bits6)
|
||||||
|
bits = "".join(bits)
|
||||||
|
|
||||||
|
modulo4 = len(data) % 4
|
||||||
|
if modulo4 == 1:
|
||||||
|
raise ValueError("Incorrect length")
|
||||||
|
elif modulo4 == 2:
|
||||||
|
bits = bits[:-4]
|
||||||
|
elif modulo4 == 3:
|
||||||
|
bits = bits[:-2]
|
||||||
|
|
||||||
|
bits8 = [ bits[idx:idx+8] for idx in range(0, len(bits), 8) ]
|
||||||
|
|
||||||
|
result = []
|
||||||
|
for g in bits8:
|
||||||
|
result.append(bchr(int(g, 2)))
|
||||||
|
result = b"".join(result)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def bcrypt(password, cost, salt=None):
|
||||||
|
"""Hash a password into a key, using the OpenBSD bcrypt protocol.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
password (byte string or string):
|
||||||
|
The secret password or pass phrase.
|
||||||
|
It must be at most 72 bytes long.
|
||||||
|
Unicode strings will be encoded as UTF-8.
|
||||||
|
cost (integer):
|
||||||
|
The exponential factor that makes it slower to compute the hash.
|
||||||
|
It must be in the range 4 to 31.
|
||||||
|
salt (byte string):
|
||||||
|
Optional. Random byte string to thwarts dictionary and rainbow table
|
||||||
|
attacks. It must be 16 bytes long.
|
||||||
|
If not passed, a random value is generated.
|
||||||
|
|
||||||
|
Return (byte string):
|
||||||
|
The bcrypt hash
|
||||||
|
"""
|
||||||
|
|
||||||
|
from Crypto.Cipher import _EKSBlowfish
|
||||||
|
|
||||||
|
password = tobytes(password, "utf-8")
|
||||||
|
|
||||||
|
if len(password) < 72:
|
||||||
|
password += b"\x00"
|
||||||
|
if len(password) > 72:
|
||||||
|
raise ValueError("The password is too long. It must be 72 bytes at most.")
|
||||||
|
|
||||||
|
if salt is None:
|
||||||
|
salt = get_random_bytes(16)
|
||||||
|
|
||||||
|
if len(salt) != 16:
|
||||||
|
raise ValueError("bcrypt salt must be 16 bytes long")
|
||||||
|
|
||||||
|
if not (4 <= cost <= 31):
|
||||||
|
raise ValueError("bcrypt cost factor must be in the range 4..31")
|
||||||
|
|
||||||
|
cipher = _EKSBlowfish.new(password, _EKSBlowfish.MODE_ECB, salt, cost)
|
||||||
|
ctext = b"OrpheanBeholderScryDoubt"
|
||||||
|
for _ in range(64):
|
||||||
|
ctext = cipher.encrypt(ctext)
|
||||||
|
|
||||||
|
cost_enc = b"$" + bstr(str(cost).zfill(2))
|
||||||
|
salt_enc = b"$" + _bcrypt_encode(salt)
|
||||||
|
|
||||||
|
# Only use 23 bytes, not 24
|
||||||
|
hash_enc = _bcrypt_encode(ctext[:-1])
|
||||||
|
|
||||||
|
result = b"$2a" + cost_enc + salt_enc + hash_enc
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def bcrypt_check(password, bcrypt_hash):
|
||||||
|
"""Verify if the provided password matches the given bcrypt hash.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
password (byte string or string):
|
||||||
|
The secret password or pass phrase to test.
|
||||||
|
It must be at most 72 bytes long.
|
||||||
|
Unicode strings will be encoded as UTF-8.
|
||||||
|
bcrypt_hash (byte string):
|
||||||
|
The reference bcrypt hash the password needs to be checked against.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: if password is invalid
|
||||||
|
"""
|
||||||
|
|
||||||
|
bcrypt_hash = tobytes(bcrypt_hash)
|
||||||
|
|
||||||
|
if len(bcrypt_hash) != 60:
|
||||||
|
raise ValueError("Incorrect length of the bcrypt hash: %d bytes instead of 60" % len(bcrypt_hash))
|
||||||
|
|
||||||
|
if bcrypt_hash[:4] != b'$2a$':
|
||||||
|
raise ValueError("Unsupported prefix")
|
||||||
|
|
||||||
|
p = re.compile(b'\$2a\$([0-9][0-9])\$([A-Za-z0-9./]{22,22})([A-Za-z0-9./]{31,31})')
|
||||||
|
r = p.match(bcrypt_hash)
|
||||||
|
if not r:
|
||||||
|
raise ValueError("Incorrect bcrypt hash format")
|
||||||
|
|
||||||
|
cost = int(r.group(1))
|
||||||
|
if not (4 <= cost <= 31):
|
||||||
|
raise ValueError("Incorrect cost")
|
||||||
|
|
||||||
|
salt = _bcrypt_decode(r.group(2))
|
||||||
|
|
||||||
|
bcrypt_hash2 = bcrypt(password, cost, salt)
|
||||||
|
|
||||||
|
secret = get_random_bytes(16)
|
||||||
|
|
||||||
|
mac1 = BLAKE2s.new(digest_bits=160, key=secret, data=bcrypt_hash).digest()
|
||||||
|
mac2 = BLAKE2s.new(digest_bits=160, key=secret, data=bcrypt_hash2).digest()
|
||||||
|
if mac1 != mac2:
|
||||||
|
raise ValueError("Incorrect bcrypt hash")
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,10 @@ from Crypto.SelfTest.st_common import list_test_cases
|
||||||
from Crypto.Hash import SHA1, HMAC, SHA256, MD5, SHA224, SHA384, SHA512
|
from Crypto.Hash import SHA1, HMAC, SHA256, MD5, SHA224, SHA384, SHA512
|
||||||
from Crypto.Cipher import AES, DES3
|
from Crypto.Cipher import AES, DES3
|
||||||
|
|
||||||
from Crypto.Protocol.KDF import PBKDF1, PBKDF2, _S2V, HKDF, scrypt
|
from Crypto.Protocol.KDF import (PBKDF1, PBKDF2, _S2V, HKDF, scrypt,
|
||||||
|
bcrypt, bcrypt_check)
|
||||||
|
|
||||||
|
from Crypto.Protocol.KDF import _bcrypt_decode
|
||||||
|
|
||||||
|
|
||||||
def t2b(t):
|
def t2b(t):
|
||||||
|
|
@ -441,6 +444,30 @@ class scrypt_Tests(unittest.TestCase):
|
||||||
self.assertEqual((ref[:4], ref[4:8], ref[8:]), (key1, key2, key3))
|
self.assertEqual((ref[:4], ref[4:8], ref[8:]), (key1, key2, key3))
|
||||||
|
|
||||||
|
|
||||||
|
class bcrypt_Tests(unittest.TestCase):
|
||||||
|
|
||||||
|
# https://github.com/patrickfav/bcrypt/wiki/Published-Test-Vectors
|
||||||
|
|
||||||
|
def test_random_password_and_salt_short_pw(self):
|
||||||
|
|
||||||
|
# password, cost, salt, bcrypt hash
|
||||||
|
tvs = [
|
||||||
|
(b"<.S.2K(Zq'", 4, b"VYAclAMpaXY/oqAo9yUpku", b"$2a$04$VYAclAMpaXY/oqAo9yUpkuWmoYywaPzyhu56HxXpVltnBIfmO9tgu"),
|
||||||
|
(b"5.rApO%5jA", 5, b"kVNDrnYKvbNr5AIcxNzeIu", b"$2a$05$kVNDrnYKvbNr5AIcxNzeIuRcyIF5cZk6UrwHGxENbxP5dVv.WQM/G"),
|
||||||
|
(b"oW++kSrQW^", 6, b"QLKkRMH9Am6irtPeSKN5sO", b"$2a$06$QLKkRMH9Am6irtPeSKN5sObJGr3j47cO6Pdf5JZ0AsJXuze0IbsNm"),
|
||||||
|
(b"ggJ\\KbTnDG", 7, b"4H896R09bzjhapgCPS/LYu", b"$2a$07$4H896R09bzjhapgCPS/LYuMzAQluVgR5iu/ALF8L8Aln6lzzYXwbq"),
|
||||||
|
(b"49b0:;VkH/", 8, b"hfvO2retKrSrx5f2RXikWe", b"$2a$08$hfvO2retKrSrx5f2RXikWeFWdtSesPlbj08t/uXxCeZoHRWDz/xFe"),
|
||||||
|
(b">9N^5jc##'", 9, b"XZLvl7rMB3EvM0c1.JHivu", b"$2a$09$XZLvl7rMB3EvM0c1.JHivuIDPJWeNJPTVrpjZIEVRYYB/mF6cYgJK"),
|
||||||
|
(b"\\$ch)s4WXp", 10, b"aIjpMOLK5qiS9zjhcHR5TO", b"$2a$10$aIjpMOLK5qiS9zjhcHR5TOU7v2NFDmcsBmSFDt5EHOgp/jeTF3O/q"),
|
||||||
|
(b"RYoj\\_>2P7", 12, b"esIAHiQAJNNBrsr5V13l7.", b"$2a$12$esIAHiQAJNNBrsr5V13l7.RFWWJI2BZFtQlkFyiWXjou05GyuREZa"),
|
||||||
|
]
|
||||||
|
|
||||||
|
for (idx, (password, cost, salt64, result)) in enumerate(tvs):
|
||||||
|
x = bcrypt(password, cost, salt=_bcrypt_decode(salt64))
|
||||||
|
self.assertEqual(x, result)
|
||||||
|
bcrypt_check(password, result)
|
||||||
|
|
||||||
|
|
||||||
def get_tests(config={}):
|
def get_tests(config={}):
|
||||||
|
|
||||||
if not config.get('slow_tests'):
|
if not config.get('slow_tests'):
|
||||||
|
|
@ -453,6 +480,7 @@ def get_tests(config={}):
|
||||||
tests += list_test_cases(S2V_Tests)
|
tests += list_test_cases(S2V_Tests)
|
||||||
tests += list_test_cases(HKDF_Tests)
|
tests += list_test_cases(HKDF_Tests)
|
||||||
tests += list_test_cases(scrypt_Tests)
|
tests += list_test_cases(scrypt_Tests)
|
||||||
|
tests += list_test_cases(bcrypt_Tests)
|
||||||
|
|
||||||
return tests
|
return tests
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -71,9 +71,9 @@ if sys.version_info[0] == 2:
|
||||||
return str(s)
|
return str(s)
|
||||||
def bord(s):
|
def bord(s):
|
||||||
return ord(s)
|
return ord(s)
|
||||||
def tobytes(s):
|
def tobytes(s, encoding="latin-1"):
|
||||||
if isinstance(s, unicode):
|
if isinstance(s, unicode):
|
||||||
return s.encode("latin-1")
|
return s.encode(encoding)
|
||||||
else:
|
else:
|
||||||
return ''.join(s)
|
return ''.join(s)
|
||||||
def tostr(bs):
|
def tostr(bs):
|
||||||
|
|
@ -114,12 +114,12 @@ else:
|
||||||
return bytes(s)
|
return bytes(s)
|
||||||
def bord(s):
|
def bord(s):
|
||||||
return s
|
return s
|
||||||
def tobytes(s):
|
def tobytes(s, encoding="latin-1"):
|
||||||
if isinstance(s,bytes):
|
if isinstance(s,bytes):
|
||||||
return s
|
return s
|
||||||
else:
|
else:
|
||||||
if isinstance(s,str):
|
if isinstance(s,str):
|
||||||
return s.encode("latin-1")
|
return s.encode(encoding)
|
||||||
else:
|
else:
|
||||||
return bytes([s])
|
return bytes([s])
|
||||||
def tostr(bs):
|
def tostr(bs):
|
||||||
|
|
|
||||||
4
setup.py
4
setup.py
|
|
@ -356,6 +356,10 @@ ext_modules = [
|
||||||
Extension("Crypto.Cipher._raw_blowfish",
|
Extension("Crypto.Cipher._raw_blowfish",
|
||||||
include_dirs=['src/'],
|
include_dirs=['src/'],
|
||||||
sources=["src/blowfish.c"]),
|
sources=["src/blowfish.c"]),
|
||||||
|
Extension("Crypto.Cipher._raw_eksblowfish",
|
||||||
|
include_dirs=['src/'],
|
||||||
|
define_macros=[('EKS',None),],
|
||||||
|
sources=["src/blowfish.c"]),
|
||||||
Extension("Crypto.Cipher._raw_cast",
|
Extension("Crypto.Cipher._raw_cast",
|
||||||
include_dirs=['src/'],
|
include_dirs=['src/'],
|
||||||
sources=["src/CAST.c"]),
|
sources=["src/CAST.c"]),
|
||||||
|
|
|
||||||
135
src/blowfish.c
135
src/blowfish.c
|
|
@ -37,7 +37,13 @@
|
||||||
|
|
||||||
FAKE_INIT(raw_blowfish)
|
FAKE_INIT(raw_blowfish)
|
||||||
|
|
||||||
|
#ifdef EKS
|
||||||
|
#define NON_STANDARD_START_OPERATION
|
||||||
|
#define MODULE_NAME EKSBlowfish
|
||||||
|
#else
|
||||||
#define MODULE_NAME Blowfish
|
#define MODULE_NAME Blowfish
|
||||||
|
#endif
|
||||||
|
|
||||||
#define BLOCK_SIZE 8
|
#define BLOCK_SIZE 8
|
||||||
#define KEY_SIZE 0
|
#define KEY_SIZE 0
|
||||||
|
|
||||||
|
|
@ -116,14 +122,12 @@ static void bf_decrypt(const struct block_state *state, uint32_t *Lx, uint32_t *
|
||||||
*Rx = R;
|
*Rx = R;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int xorkey(uint32_t P[18], const uint8_t *key, size_t keylength)
|
static inline void xorP(uint32_t P[18], const uint8_t *key, size_t keylength)
|
||||||
{
|
{
|
||||||
uint8_t P_buf[4*18];
|
uint8_t P_buf[4*18];
|
||||||
size_t P_idx;
|
size_t P_idx;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
|
||||||
assert(keylength > 0);
|
|
||||||
|
|
||||||
P_idx = 0;
|
P_idx = 0;
|
||||||
while (P_idx < sizeof(P_buf)) {
|
while (P_idx < sizeof(P_buf)) {
|
||||||
size_t tc;
|
size_t tc;
|
||||||
|
|
@ -139,24 +143,14 @@ static int xorkey(uint32_t P[18], const uint8_t *key, size_t keylength)
|
||||||
P[i] ^= LOAD_U32_BIG(P_buf + P_idx);
|
P[i] ^= LOAD_U32_BIG(P_buf + P_idx);
|
||||||
P_idx += 4;
|
P_idx += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int block_init(struct block_state *state, const uint8_t *key, size_t keylength)
|
static inline void encryptState(struct block_state *state, const uint8_t *key, size_t keylength)
|
||||||
{
|
{
|
||||||
unsigned i, j;
|
unsigned i, j;
|
||||||
uint32_t L, R;
|
uint32_t L, R;
|
||||||
|
|
||||||
/* Allowed key length: 32 to 448 bits */
|
xorP(state->P, key, keylength);
|
||||||
if (keylength < 4 || keylength > 56) {
|
|
||||||
return ERR_KEY_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(state->S, S_init, sizeof S_init);
|
|
||||||
memcpy(state->P, P_init, sizeof P_init);
|
|
||||||
|
|
||||||
xorkey(state->P, key, keylength);
|
|
||||||
|
|
||||||
L = R = 0;
|
L = R = 0;
|
||||||
for (i=0; i<18; i+=2) {
|
for (i=0; i<18; i+=2) {
|
||||||
|
|
@ -171,10 +165,99 @@ static int block_init(struct block_state *state, const uint8_t *key, size_t keyl
|
||||||
state->S[j][i+1] = R;
|
state->S[j][i+1] = R;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef EKS
|
||||||
|
|
||||||
|
static int block_init(struct block_state *state, const uint8_t *key, size_t keylength)
|
||||||
|
{
|
||||||
|
/* Allowed key length: 32 to 448 bits */
|
||||||
|
if (keylength < 4 || keylength > 56) {
|
||||||
|
return ERR_KEY_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(state->S, S_init, sizeof S_init);
|
||||||
|
memcpy(state->P, P_init, sizeof P_init);
|
||||||
|
|
||||||
|
encryptState(state, key, keylength);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static void encryptStateWithSalt(struct block_state *state, const uint8_t *key, size_t keylength, const uint8_t salt[16])
|
||||||
|
{
|
||||||
|
uint32_t S1, S2, S3, S4;
|
||||||
|
uint32_t L, R;
|
||||||
|
unsigned i, j;
|
||||||
|
|
||||||
|
xorP(state->P, key, keylength);
|
||||||
|
|
||||||
|
S1 = LOAD_U32_BIG(salt);
|
||||||
|
S2 = LOAD_U32_BIG(salt+4);
|
||||||
|
S3 = LOAD_U32_BIG(salt+8);
|
||||||
|
S4 = LOAD_U32_BIG(salt+12);
|
||||||
|
|
||||||
|
L = R = 0;
|
||||||
|
for (i=0;;) {
|
||||||
|
L ^= S1;
|
||||||
|
R ^= S2;
|
||||||
|
bf_encrypt(state, &L, &R);
|
||||||
|
state->P[i++] = L;
|
||||||
|
state->P[i++] = R;
|
||||||
|
|
||||||
|
if (i == 18) break;
|
||||||
|
|
||||||
|
L ^= S3;
|
||||||
|
R ^= S4;
|
||||||
|
bf_encrypt(state, &L, &R);
|
||||||
|
state->P[i++] = L;
|
||||||
|
state->P[i++] = R;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (j=0; j<4; j++) {
|
||||||
|
for (i=0; i<256;) {
|
||||||
|
L ^= S3;
|
||||||
|
R ^= S4;
|
||||||
|
bf_encrypt(state, &L, &R);
|
||||||
|
state->S[j][i++] = L;
|
||||||
|
state->S[j][i++] = R;
|
||||||
|
|
||||||
|
L ^= S1;
|
||||||
|
R ^= S2;
|
||||||
|
bf_encrypt(state, &L, &R);
|
||||||
|
state->S[j][i++] = L;
|
||||||
|
state->S[j][i++] = R;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int block_init(struct block_state *state, const uint8_t *key, size_t keylength, const uint8_t salt[16], unsigned cost)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
/* Allowed key length: 32 to 448 bits */
|
||||||
|
if (keylength < 4 || keylength > 56) {
|
||||||
|
return ERR_KEY_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* InitState */
|
||||||
|
memcpy(state->S, S_init, sizeof S_init);
|
||||||
|
memcpy(state->P, P_init, sizeof P_init);
|
||||||
|
|
||||||
|
encryptStateWithSalt(state, key, keylength, salt);
|
||||||
|
|
||||||
|
for (i=0; i<(1 << cost); i++) {
|
||||||
|
encryptState(state, key, keylength);
|
||||||
|
encryptState(state, salt, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
static void block_finalize(struct block_state* state)
|
static void block_finalize(struct block_state* state)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
@ -202,3 +285,25 @@ static inline void block_decrypt(struct block_state *state, const uint8_t *in, u
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "block_common.c"
|
#include "block_common.c"
|
||||||
|
|
||||||
|
#ifdef EKS
|
||||||
|
EXPORT_SYM int CIPHER_START_OPERATION(const uint8_t key[], size_t key_len, const uint8_t salt[16], unsigned cost, CIPHER_STATE_TYPE **pResult)
|
||||||
|
{
|
||||||
|
BlockBase *block_base;
|
||||||
|
|
||||||
|
if ((key == NULL) || (pResult == NULL))
|
||||||
|
return ERR_NULL;
|
||||||
|
|
||||||
|
*pResult = calloc(1, sizeof(CIPHER_STATE_TYPE));
|
||||||
|
if (NULL == *pResult)
|
||||||
|
return ERR_MEMORY;
|
||||||
|
|
||||||
|
block_base = &((*pResult)->base_state);
|
||||||
|
block_base->encrypt = &CIPHER_ENCRYPT;
|
||||||
|
block_base->decrypt = &CIPHER_DECRYPT;
|
||||||
|
block_base->destructor = &CIPHER_STOP_OPERATION;
|
||||||
|
block_base->block_len = BLOCK_SIZE;
|
||||||
|
|
||||||
|
return block_init(&(*pResult)->algo_state, (unsigned char*)key, key_len, salt, cost);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue