I have the following implementation of HMAC:
"""HMAC (Keyed-Hashing for Message Authentication) Python module.
Implements the HMAC algorithm as described by RFC 2104.
"""
impot hashlib
import warnings as _warnings
trans_5C = bytes((x ^ 0x5C) for x in range(256))
trans_36 = bytes((x ^ 0x36) for x in range(256))
# The size of the digests returned by HMAC depends on the underlying
# hashing module used. Use digest_size from the instance of HMAC instead.
digest_size = None
class HMAC:
"""RFC 2104 HMAC class. Also complies with RFC 4231.
This supports the API for Cryptographic Hash Functions (PEP 247).
"""
blocksize = 64 # 512-bit HMAC; can be changed in subclasses.
def __init__(self, key, msg = None, digestmod = None):
"""Create a new HMAC object.
key: key for the keyed hash object.
msg: Initial input for the hash, if provided.
digestmod: A module supporting PEP 247. *OR*
A hashlib constructor returning a new hash object.
Defaults to hashlib.md5.
Note: key and msg must be bytes objects.
"""
if not isinstance(key, bytes):
raise TypeError("expected bytes, but got %r" % type(key).__name__)
if digestmod is None:
import hashlib
digestmod = hashlib.md5
if hasattr(digestmod, '__call__'):
self.digest_cons = digestmod
else:
self.digest_cons = lambda d=b'': digestmod.new(d)
self.outer = self.digest_cons()
self.inner = self.digest_cons()
self.digest_size = self.inner.digest_size
if hasattr(self.inner, 'block_size'):
blocksize = self.inner.block_size
if blocksize < 16:
_warnings.warn('block_size of %d seems too small; using our '
'default of %d.' % (blocksize, self.blocksize),
RuntimeWarning, 2)
blocksize = self.blocksize
else:
_warnings.warn('No block_size attribute on given digest object; '
'Assuming %d.' % (self.blocksize),
RuntimeWarning, 2)
blocksize = self.blocksize
if len(key) > blocksize:
key = self.digest_cons(key).digest()
key = key + bytes(blocksize - len(key))
self.outer.update(key.translate(trans_5C))
self.inner.update(key.translate(trans_36))
if msg is not None:
self.update(msg)
def update(self, msg):
"""Update this hashing object with the string msg.
"""
if not isinstance(msg, bytes):
raise TypeError("expected bytes, but got %r" % type(msg).__name__)
self.inner.update(msg)
def copy(self):
"""Return a separate copy of this hashing object.
An update to this copy won't affect the original object.
"""
# Call __new__ directly to avoid the expensive __init__.
other = self.__class__.__new__(self.__class__)
other.digest_cons = self.digest_cons
other.digest_size = self.digest_size
other.inner = self.inner.copy()
other.outer = self.outer.copy()
return other
def _current(self):
"""Return a hash object for the current state.
To be used only internally with digest() and hexdigest().
"""
h = self.outer.copy()
h.update(self.inner.digest())
return h
def digest(self):
"""Return the hash value of this hashing object.
This returns a string containing 8-bit data. The object is
not altered in any way by this function; you can continue
updating the object after calling this function.
"""
h = self._current()
return h.digest()
def hexdigest(self):
"""Like digest(), but returns a string of hexadecimal digits instead.
"""
h = self._current()
return h.hexdigest()
def new(key, msg = None, digestmod = None):
"""Create a new hashing object and return it.
key: The starting key for the hash.
msg: if available, will immediately be hashed into the object's starting
state.
You can now feed arbitrary strings into the object using its update()
method, and can ask for the hash value at any time by calling its digest()
method.
"""
return HMAC(key, msg, digestmod)
if __name__ == '__main__':
bin = b'R\x9d\x94r\x12\xa4\x1a\xec\xb4\x11\x90\xdcY\x9a\x96\xccReWimBsDWONrzoeO'
h = new(bin, digestmod=hashlib.sha256)
h.update(b"hello")
d = h.hexdigest()
print(d)
assert d == 'a4d000deb3faec0b6d3acf5730c5973727478fa918fb65195c75b0a62f7f12c8'
this code works fine in Python 3, however it fails in Python 2:
~$ python hmac.py
Traceback (most recent call last):
File "hmac.py", line 128, in <module>
h = new(bin, digestmod=hashlib.sha256)
File "hmac.py", line 123, in new
return HMAC(key, msg, digestmod)
File "hmac.py", line 67, in __init__
self.outer.update(key.translate(trans_5C))
ValueError: translation table must be 256 characters long
How can I make this code work for Python 2? Specifically, how can I convert
trans_5C = bytes((x ^ 0x5C) for x in range(256))
trans_36 = bytes((x ^ 0x36) for x in range(256))
into an equivalent in Python 2?
Using
trans_5C = ''.join(chr(x ^ 0x5C) for x in range(256))
trans_36 = ''.join(chr(x ^ 0x36) for x in range(256))
still causes the hmac to fail:
python hmac.py
34669003b12998c4f555dcc6110188a96af0caf889858a3ab81929aa89339b0a
Traceback (most recent call last):
File "hmac.py", line 133, in <module>
assert d == 'a4d000deb3faec0b6d3acf5730c5973727478fa918fb65195c75b0a62f7f12c8'
AssertionError
however, the implementation works fine in Python 3...
This is a somewhat bizarre one. "bytes" in Python 2 is the same as "str", so that command is actually producing the string "<generator object at 0x12345678>".
The equivalent in Python 2 is
trans_36 = ''.join(chr(x ^ 0x36) for x in range(256))
Related
my code has an error in line 14 saying bytes object has no attribute oid. I am not sure why is it giving me this error.
from Crypto.PublicKey import DSA
from Crypto.Signature import DSS
import random
import os
def generate_dsa_key_pair(bits=1024):
"""Generates a DSA key pair with the given number of bits."""
key = DSA.generate(bits)
return key
def sign_text(text, key):
"""Signs the given text using the given DSA private key."""
signer = DSS.new(key, 'fips-186-3')
**signature = signer.sign(text.encode())**
return signature
def create_p2ms_script(n, m):
"""Creates a P2MS script using the given number of public keys and signatures."""
# Generate N DSA key pairs
keys = [generate_dsa_key_pair() for i in range(n)]
# Select M private keys from the N keys
priv_keys = random.sample(keys, m)
# Generate M signatures using the private keys
signatures = [sign_text("help me", priv_key) for priv_key in priv_keys]
# Create scriptPubKey by concatenating the N public keys
scriptPubKey = b''.join([key.publickey().export_key(format='DER') for key in keys])
# Create scriptSig by concatenating the M signatures
scriptSig = b''.join(signatures)
return scriptPubKey, scriptSig
def save_script_to_file(script, filename):
"""Saves the given script to the specified file."""
with open(filename, 'wb') as f:
f.write(script)
def execute_p2ms_script(scriptPubKey, scriptSig):
"""Executes the given P2MS script by verifying the signatures using the public keys."""
# Split scriptPubKey into individual public keys
pub_keys = [DSA.import_key(key) for key in scriptPubKey.split(b'\x00\x02\x81\x81') if key]
# Split scriptSig into individual signatures
signatures = [sig for sig in scriptSig.split(b'\x00\x02\x81\x81') if sig]
# Check if the number of signatures matches the number of public keys
if len(signatures) != len(pub_keys):
return False
# Verify each signature using the corresponding public key
for i, sig in enumerate(signatures):
verifier = DSS.new(pub_keys[i], 'fips-186-3')
if not verifier.verify("help me ".encode(), sig):
return False
return True
if __name__ == '__main__':
n = int(input("Enter the number of public keys (N): "))
m = int(input("Enter the number of signatures (M): "))
# Create P2MS script
scriptPubKey, scriptSig = create_p2ms_script(n, m)
# Save script
I have tried to hash the object but then my code wouldn't work. I have bolded the line, can someone please explain to me?
for context, my code is meant to replicate a P2MS function.
edit: the full traceback is as follows:
Exception has occurred: AttributeError
'bytes' object has no attribute 'oid'
File ", line 14, in sign_text signature = signer.sign(text.encode())
File , line 26, in <listcomp> signatures = [sign_text("help me", priv_key) for priv_key in priv_keys]
File , line 26, in create_p2ms_script signatures = [sign_text("help me", priv_key) for priv_key in priv_keys]
File , line 66, in <module> scriptPubKey, scriptSig = create_p2ms_script(n, m)
AttributeError: 'bytes' object has no attribute 'oid'
The bytes object is what's returned by text.encode(). It's a UTF-8 encoded string and it does not have an attribute oid.
That is not what DSS.sign(msg_hash) expects. It expects a hash object (which conveniently has an attribute oid), see also PyCryptoDome doc on sign. So a Crypto.Hash object has to be created first as described here:
from Crypto.Hash import SHA256
# ... line 14
hash_object = SHA256.new(data=text.encode())
signature = signer.sign(hash_object)
In your question, you said that passing a hash object did not work. However, that's the proper way to do it. You cannot make a wish on an API and expect things to work. See the API as a contract. It specifies what you need to give and what you get in return.
Make your code run without throwing exceptions. Once you're there and you still encounter errors after passing a hash, please post another question. A thorough explanation of expected and actual behavior beyond "would not work" would also be helpful.
There is code here that I am trying to convert from Python2 to Python3. In this section of code, data is received from a socket. data is declared to be an empty string and then concatenated. This is an important Python2 to 3 distinction. In Python3, the 'received' variable is of type Bytes and thus needs to be converted to string first via the use of str(). However, str() needs an encoding parameter. What would the default one be for python 2? I've tried several different encodings (latin-1 and such) but they seem to not match up with a magic value that is defined here after being unpacked here
"\xffSMB seems to decode correctly while "\xfeSMB does not.
I have adjusted the non_polling_read function and the NetBIOSSessionPacket class as follows. Full modified source code available on GitHub.
def non_polling_read(self, read_length, timeout):
data = b''
bytes_left = read_length
while bytes_left > 0:
try:
ready, _, _ = select.select([self._sock.fileno()], [], [], timeout)
if not ready:
raise NetBIOSTimeout
received = self._sock.recv(bytes_left)
if len(received) == 0:
raise NetBIOSError('Error while reading from remote', ERRCLASS_OS, None)
data = data + received
bytes_left = read_length - len(data)
except select.error as ex:
if ex[0] != errno.EINTR and ex[0] != errno.EAGAIN:
raise NetBIOSError('Error occurs while reading from remote', ERRCLASS_OS, ex[0])
return data
class NetBIOSSessionPacket:
def __init__(self, data=0):
self.type = 0x0
self.flags = 0x0
self.length = 0x0
if data == 0:
self._trailer = ''
else:
try:
self.type = data[0]
if self.type == NETBIOS_SESSION_MESSAGE:
self.length = data[1] << 16 | (unpack('!H', data[2:4])[0])
else:
self.flags = data[1]
self.length = unpack('!H', data[2:4])[0]
self._trailer = data[4:]
except Exception as e:
import traceback
traceback.print_exc()
raise NetBIOSError('Wrong packet format ')
When I start the server and issue 'smbclient -L 127.0.0.1 -d 4' from the commandline, the server first creates a libs.nmb.NetBIOSTCPSession which appears to be working well. Once it tries to unwrap the libs.nmb.NetBIOSSessionPacket, it throws an exception.
Traceback (most recent call last):
File "/root/PycharmProjects/HoneySMB/libs/smbserver.py", line 3975, in processRequest
packet = smb.NewSMBPacket(data=data)
File "/root/PycharmProjects/HoneySMB/libs/smb.py", line 690, in __init__
Structure.__init__(self, **kargs)
File "/root/PycharmProjects/HoneySMB/libs/structure.py", line 77, in __init__
self.fromString(data)
File "/root/PycharmProjects/HoneySMB/libs/structure.py", line 144, in fromString
self[field[0]] = self.unpack(field[1], data[:size], dataClassOrCode = dataClassOrCode, field = field[0])
File "/root/PycharmProjects/HoneySMB/libs/structure.py", line 288, in unpack
raise Exception("Unpacked data doesn't match constant value %r should be %r" % (data, answer))
Exception: ("Unpacked data doesn't match constant value b'\\xffSMB' should be 'ÿSMB'", 'When unpacking field \'Signature | "ÿSMB | b\'\\xffSMBr\\x00\\x00\\x00\\x00\\x18C\\xc8\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\xfe\\xff\\x00\\x00\\x00\\x00\\x00\\xb1\\x00\\x02PC NETWORK PROGRAM 1.0\\x00\\x02MICROSOFT NETWORKS 1.03\\x00\\x02MICROSOFT NETWORKS 3.0\\x00\\x02LANMAN1.0\\x00\\x02LM1.2X002\\x00\\x02DOS LANMAN2.1\\x00\\x02LANMAN2.1\\x00\\x02Samba\\x00\\x02NT LANMAN 1.0\\x00\\x02NT LM 0.12\\x00\\x02SMB 2.002\\x00\\x02SMB 2.???\\x00\'[:4]\'')
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/root/PycharmProjects/HoneySMB/libs/smbserver.py", line 3597, in handle
resp = self.__SMB.processRequest(self.__connId, p.get_trailer())
File "/root/PycharmProjects/HoneySMB/libs/smbserver.py", line 3979, in processRequest
packet = smb2.SMB2Packet(data=data)
File "/root/PycharmProjects/HoneySMB/libs/smb3structs.py", line 435, in __init__
Structure.__init__(self,data)
File "/root/PycharmProjects/HoneySMB/libs/structure.py", line 77, in __init__
self.fromString(data)
File "/root/PycharmProjects/HoneySMB/libs/structure.py", line 144, in fromString
self[field[0]] = self.unpack(field[1], data[:size], dataClassOrCode = dataClassOrCode, field = field[0])
File "/root/PycharmProjects/HoneySMB/libs/structure.py", line 288, in unpack
raise Exception("Unpacked data doesn't match constant value %r should be %r" % (data, answer))
Exception: ("Unpacked data doesn't match constant value b'\\xffSMB' should be 'þSMB'", 'When unpacking field \'ProtocolID | "þSMB | b\'\\xffSMBr\\x00\\x00\\x00\\x00\\x18C\\xc8\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\xfe\\xff\\x00\\x00\\x00\\x00\\x00\\xb1\\x00\\x02PC NETWORK PROGRAM 1.0\\x00\\x02MICROSOFT NETWORKS 1.03\\x00\\x02MICROSOFT NETWORKS 3.0\\x00\\x02LANMAN1.0\\x00\\x02LM1.2X002\\x00\\x02DOS LANMAN2.1\\x00\\x02LANMAN2.1\\x00\\x02Samba\\x00\\x02NT LANMAN 1.0\\x00\\x02NT LM 0.12\\x00\\x02SMB 2.002\\x00\\x02SMB 2.???\\x00\'[:4]\'')
Now it's obvious why this throws an exception. After all, 0xFF does NOT equal ÿ or þ. The question is why is 0xFF the value it tries to write in there in the first place when it should be two different values?
The original python 2 code seems to be quite close to C (using unpack and importing cstring). Is there an obvious benefit to this here or could this be done more simply?
My actual question is:
In the original code, there is no reference to any encoding anywhere. So how is this divined then? Where does it translate 0xFF to ÿ?
A couple o' years ago i created a cryptograph module in python with PyCryptoDome Version 2.6.1.
Now with the new PyCryptoDome Version 3.6.6 and Python 3.6 i got a TypeError with the same code. The error is thrown in the "_init_crypter" - method:
File "/usr/local/lib/python3.6/dist-packages/Crypto/Cipher/AES.py", line 206, in new
return _create_cipher(sys.modules[__name__], key, mode, *args, **kwargs)
File "/usr/local/lib/python3.6/dist-packages/Crypto/Cipher/__init__.py", line 79, in _create_cipher
return modes[mode](factory, **kwargs)
File "/usr/local/lib/python3.6/dist-packages/Crypto/Cipher/_mode_cbc.py", line 253, in _create_cbc_cipher
return CbcMode(cipher_state, iv)
File "/usr/local/lib/python3.6/dist-packages/Crypto/Cipher/_mode_cbc.py", line 96, in __init__
c_uint8_ptr(iv),
File "/usr/local/lib/python3.6/dist-packages/Crypto/Util/_raw_api.py", line 196, in c_uint8_ptr
raise TypeError("Object type %s cannot be passed to C code" % type(data))
TypeError: Object type <class 'str'> cannot be passed to C code
How can i fix this!
My Code for both versions:
import os
from base64 import b64encode, b64decode
import hashlib
from Crypto.Cipher import Blowfish, AES
class Crypt:
fileextension = ".enc"
def __init__(self, crypter, key="", encoding="utf-8"):
self._mode = -1
self._encoding = encoding
self._crypter = Blowfish
self._blocksize = 8
self._key_32byte = ""
self._cryptographer = None
self.set_crypter(crypter)
if key:
self.set_key(key)
def _init_crypter(self):
# self._key_32byte <- set in set_key-method
# self._mode = AES.MODE_CBC <- set in set_crypter-method
# self._blocksize = 16 <- set in set_crypter-method
self._cryptographer = self._crypter.new(
self._key_32byte,
self._mode,
IV=self._blocksize * '\x00'
)
# and further code ...
The key and IV parameter must be a binary type (bytes) and not a text type (str).
If you're loading your key from a file, be sure to open it in binary mode:
with open('keyfile', 'rb') as f:
...
If your key is a literal in code, make sure it is a binary literal:
key = b'badbadbadkey'
And last, to construct your IV parameter, it must be a sequence of bytes.
For example:
>>> Blowfish.new(b'badbadbadkey', 2, IV=8 * b'\x00')
<Crypto.Cipher._mode_cbc.CbcMode object at 0x7f434187b8d0>
Ok - after hours i got it! Only one letter solves the problem:
'\x00' must be b'\x00':
def _init_crypter(self):
self._cryptographer = self._crypter.new(
self._key_32byte,
self._mode,
IV=self._blocksize * b'\x00'
)
I wrote a custom encoding code snippet. When i run it on pyton 3.6 i got type error. I couldn't figure it out exactly. The code snippet is working fine with python 2.7.
import os
import sys
import base64
def encode(key, clear):
"""encode custom """
enc = []
for i in range(len(clear)):
key_c = key[i % len(key)]
enc_c = chr((ord(clear[i]) + ord(key_c)) % 256)
#change the int or str
enc.append(enc_c)
return base64.urlsafe_b64encode("".join(enc))
clear = "ABCDEFGH"
encode_var = encode("crumbs", clear)
Error Log :
(py3) C:\Dev\crumbles>python s1.py
Traceback (most recent call last):
File "s1.py", line 45, in <module>
encode_var = encode("crumbs", clear)
File "s1.py", line 42, in encode
return base64.urlsafe_b64encode("".join(enc))
File "C:\Users\Cookie1\Anaconda3\envs\py3\lib\base64.py", line 118, in urlsafe
_b64encode
return b64encode(s).translate(_urlsafe_encode_translation)
File "C:\Users\Cookie1\Anaconda3\envs\py3\lib\base64.py", line 58, in b64encod
e
encoded = binascii.b2a_base64(s, newline=False)
TypeError: a bytes-like object is required, not 'str'
You are passing in text, not a binary bytes object. The base64.urlsafe_b64encode() function expects bytes, not text.
Generate bytes instead:
from itertools import cycle
def encode(key, clear):
"""encode custom """
key, clear = cycle(key.encode()), clear.encode()
enc = bytes((c + k) % 256 for c, k in zip(clear, key))
return base64.urlsafe_b64encode(enc)
I used a few iterator tricks to produce the integers that bytes() accepts.
Note that it is more common to use XOR to produce encrypted bytes when creating a single-key encryption:
from operator import xor
key, clear = cycle(key.encode()), clear.encode()
enc = bytes(map(xor, clear, key))
That's because XOR is trivially reversed by using the same key; clear XOR key produces the encrypted text, and encrypted XOR key produces the cleartext again.
I have following code
import sys
from ctypes import *
from ctypes.util import find_library
libc = cdll.LoadLibrary(find_library("c"))
CTL_KERN = 1
KERN_SHMMAX = 34
sysctl_names = {
'memory_shared_buffers' : (CTL_KERN, KERN_SHMMAX),
}
def posix_sysctl_long(name):
_mem = c_uint64(0)
_arr = c_int * 2
_name = _arr()
_name[0] = c_int(sysctl_names[name][0])
_name[1] = c_int(sysctl_names[name][1])
result = libc.sysctl(_name, byref(_mem), c_size_t(sizeof(_mem)), None, c_size_t(0))
if result != 0:
raise Exception('sysctl returned with error %s' % result)
return _mem.value
print posix_sysctl_long('memory_shared_buffers')
which produces following result:
Traceback (most recent call last):
File "test.py", line 23, in <module>
print posix_sysctl_long('memory_shared_buffers')
File "test.py", line 20, in posix_sysctl_long
raise Exception('sysctl returned with error %s' % result)
Exception: sysctl returned with error -1
I gues I did something wrong. What would be the correct calling convention? How would I find out what exactly went wrong?
You are not providing the correct values to the sysctl function. Detailed information on the arguments of sysctl() can be found here.
Here are your errors:
You have forgotten the nlen argument (second argument)
The oldlenp argument is a pointer to the size, not directly the size
Here is the correct function (with minor improvement):
def posix_sysctl_long(name):
_mem = c_uint64(0)
_def = sysctl_names[name]
_arr = c_int * len(_def)
_name = _arr()
for i, v in enumerate(_def):
_name[i] = c_int(v)
_sz = c_size_t(sizeof(_mem))
result = libc.sysctl(_name, len(_def), byref(_mem), byref(_sz), None, c_size_t(0))
if result != 0:
raise Exception('sysctl returned with error %s' % result)
return _mem.value