pysha3 not giving the right answer - python

With the following code,
# $ pip install pysha3
import sys
if sys.version_info < (3, 4):
import sha3
import hashlib
s = hashlib.new("sha3_512")
s.update(b"")
print(s.hexdigest())
I am getting
0eab42de4c3ceb9235fc91acffe746b29c29a8c366b7c60e4e67c466f36a4304c00fa9caf9d87976ba469bcbe06713b435f091ef2769fb160cdab33d3670680e
instead of
a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26
cf. https://en.wikipedia.org/wiki/SHA-3#Examples_of_SHA-3_variants
Could anyone advise me?

The pysha3 module you found was based on an draft of the SHA-3 specification, before it was standardised.
The module was created as a POC for Python issue 16113, and the code has not been updated since 2012. The NIST standard wasn't finalised until October 2015. As such, the implementation can't be used if you expect it to follow the released standard.
That ticket links to an implementation that does claim to have been updated to the standard: https://github.com/bjornedstrom/python-sha3. That package doesn't appear to be listed on PyPI, but can be installed with pip directly from GitHub:
pip install git+https://github.com/bjornedstrom/python-sha3
and this package does produce the expected result:
>>> import hashlib
>>> import sha3
>>> hashlib.sha3_512(b'').hexdigest()
b'a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26'
This package doesn't patch the built-in hashlib.new() constructor, but that's easily done by plugging in the constructor into the module cache:
>>> hashlib.__builtin_constructor_cache['sha3_512'] = sha3.sha3_512
>>> hashlib.new('sha3_512')
<sha3.SHA3512 object at 0x10b381a90>

SHA3 has been added to the built-in hashlib module in Python 3.6:
What’s New In Python 3.6
The SHA-3 hash functions sha3_224(), sha3_256(), sha3_384(),
sha3_512(), and SHAKE hash functions shake_128() and shake_256() were
added. (Contributed by Christian Heimes in issue 16113. Keccak Code
Package by Guido Bertoni, Joan Daemen, Michaël Peeters, Gilles Van
Assche, and Ronny Van Keer.)
It can be used in the follow way:
>>> import sys
>>> import hashlib
>>> s = hashlib.new("sha3_512") # sha3_224, sha3_256 and sha3_384 are also available
>>> s.update(b"")
>>> print(s.hexdigest())
a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26

Related

Ensuring minimum version for imported Python package

Most Python packages follow the convention that the version is provided as a string at [package_name].version.version. Let's use Numpy as an example. Say I wanted to import Numpy but ensure that the minimum version is 1.18.1. This is what I do currently:
import numpy as np
if tuple(map(int, np.version.version.split('.'))) < (1, 18, 1):
raise ImportError('Numpy version too low! Must be >= 1.18.1')
While this seems to work, it requires me to import the package before the version can be checked. It would be nice to not have to import the package if the condition is not satisfied.
It also seems a bit "hacky" and it feels like there's probably a method using the Python standard library that does this. Something like version('numpy') > '1.18.1'. But I haven't been able to find one.
Is there a way to check the version of a package BEFORE importing it within the bounds of the Python standard library?
I am looking for a programmatic solution in Python code. Telling me to use a requirements.txt or pip install is not answering the question.
Edit to add context: Adding this package to my requirements.txt is not useful as the imported package is supposed to be an optional dependency. This code would go in a submodule that is optionally loaded in the __init__.py via a try statement. Essentially, some functionality of the package is only available if a package of minimum version is found and successfully imported.
Run pip show for a specific package using subprocess then parse the result to compare the installed version to your requirment(s).
>>> import subprocess
>>> result = subprocess.run(['pip', 'show', 'numpy'], stdout=subprocess.PIPE)
>>> result.stdout
b'Name: numpy\r\nVersion: 1.17.4\r\nSummary: NumPy is the fundamental package for array computing with Python.\r\nHome-page: https://www.numpy.org\r\nAuthor: Travis E. Oliphant et al.\r\nAuthor-email: None\r\nLicense: BSD\r\nLocation: c:\\python38\\lib\\site-packages\r\nRequires: \r\nRequired-by: scipy, scikit-learn, perfplot, pandas, opencv-python, matplotlib\r\n'
>>> result = subprocess.run(['pip', 'show', 'pandas'], stdout=subprocess.PIPE)
>>> for thing in result.stdout.splitlines():
... print(thing)
b'Name: pandas'
b'Version: 0.25.3'
b'Summary: Powerful data structures for data analysis, time series, and statistics'
b'Home-page: http://pandas.pydata.org'
b'Author: None'
b'Author-email: None'
b'License: BSD'
b'Location: c:\\python38\\lib\\site-packages'
b'Requires: numpy, python-dateutil, pytz'
b'Required-by: '
>>>
>>> from email.header import Header
>>> result = subprocess.run(['pip', 'show', 'pandas'], stdout=subprocess.PIPE)
>>> h = Header(result.stdout)
>>> print(str(h))
Name: pandas
Version: 0.25.3
Summary: Powerful data structures for data analysis, time series, and statistics
Home-page: http://pandas.pydata.org
Author: None
Author-email: None
License: BSD
Location: c:\python38\lib\site-packages
Requires: python-dateutil, pytz, numpy
Required-by:
>>> d = {}
>>> for line in result.stdout.decode().splitlines():
... k,v = line.split(':',1)
... d[k] = v
>>> d['Version']
' 0.25.3'
>>>
Or look at everything:
>>> result = subprocess.run(['pip', 'list'], stdout=subprocess.PIPE)
>>> for thing in result.stdout.splitlines():
print(thing)
b'Package Version '
b'---------------- ----------'
b'-illow 6.2.1 '
b'aiohttp 3.6.2 '
b'appdirs 1.4.3 '
...
Use containers to control all the dependencies and runtime environment of your program. An easy way to do it would be to create a Docker image that holds the exact version of python that you require. Then use a requirements.txt to install the correct python modules you need with the exact versions.
Lastly, you can create a shell script or something similar to actually spin-up the docker container with one click.
Alternatively (if Docker seems overkill), check out venv

Can we pickle continuations in PyPy? How?

I am trying PyPy for the first time because I need serializable continuations. Specifically, this is what I am attempting:
from _continuation import continulet
import pickle
def f(cont):
cont.switch(111)
cont.switch(222)
cont.switch(333)
c = continulet(f)
print(c.switch())
print(c.switch())
saved = pickle.dumps(c)
When I try to pickle c I get this error, though: NotImplementedError: continulet's pickle support is currently disabled.
So, is there some way to enable pickling of continuations? The message suggests this, but so far I couldn't find out how.
Edit: I am using "PyPy 7.3.1 with GCC 9.3.0" (Python 3.6.9) on Linux.

How to create a universal program code for different versions of a program library?

I use a software library that has different function names in different versions of the library.
I try to use the following code:
some_variable = module.old_name_of_function()
But this code only works with the old version of the program library.
I plan to use the code on different computers, with different installed versions of the software library.
Some computers have a new version of the program library installed, and the following code should be used there:
some_variable = module.new_name_of_function()
And if I use old_name_of_function() in the new version of the library, I will get an error.
How to solve this issue?
I suppose you could do
try:
my_func = module.old_name_of_function
except AttributeError:
my_func = module.new_name_of_function
some_variable = my_func()
You can use pkg_resources module for it (example for numpy):
import pkg_resources
pkg_resources.get_distribution("numpy").version
will return:
'1.15.2'
Then you can use cases, ifs or something else to run a function you need.
For example:
import pkg_resources
version = pkg_resources.get_distribution("numpy").version
v = version.split('.')
if int(v[0]) == 1 and int(v[1]) < 17:
print('WAKA')
else:
print('NEW WAKA')
will print 'WAKA' for every 1.X version of numpy, where X < 17.

CSPRNG Python 2.7 implementation

How can I implement a CSPRNG algorithm in python 2.7?
In python 3.6 there is the secrets module, but I have not found anything for python 2.7
Use the os.urandom() and andom.SystemRandom class to secure random generator in Python 2
Get systemRandom instance out of random class.
Example of systemRandom:-
import random
systemRandom = random.SystemRandom()
SystemRandom.randint()
randomNumber=systemRandom.randint(1,30)
Example of os.urandom
import os
import struct
print(struct.unpack('i', os.urandom(4)))
print(struct.unpack('i', os.urandom(4)))
Refer to this to get started with CSPRNG.
cryptographically secure pseudorandom number generator (CSPRNG)
>>> import random
>>> random.SystemRandom().randint(2**128, 2**(128+1))
414898192462243312770563947893545439929L
>>>
>>> random.SystemRandom().randint(2**128, 2**(128+1))
551865749877602333306492786340710356728L
>>>
>>> random.SystemRandom().randint(2**128, 2**(128+1))
536575901254084412494463427722820032319L

Unique session id in python

How do I generate a unique session id in Python?
UPDATE: 2016-12-21
A lot has happened in a the last ~5yrs. /dev/urandom has been updated and is now considered a high-entropy source of randomness on modern Linux kernels and distributions. In the last 6mo we've seen entropy starvation on a Linux 3.19 kernel using Ubuntu, so I don't think this issue is "resolved", but it's sufficiently difficult to end up with low-entropy randomness when asking for any amount of randomness from the OS.
I hate to say this, but none of the other solutions posted here are correct with regards to being a "secure session ID."
# pip install M2Crypto
import base64, M2Crypto
def generate_session_id(num_bytes = 16):
return base64.b64encode(M2Crypto.m2.rand_bytes(num_bytes))
Neither uuid() or os.urandom() are good choices for generating session IDs. Both may generate random results, but random does not mean it is secure due to poor entropy. See "How to Crack a Linear Congruential Generator" by Haldir or NIST's resources on Random Number Generation. If you still want to use a UUID, then use a UUID that was generated with a good initial random number:
import uuid, M2Crypto
uuid.UUID(bytes = M2Crypto.m2.rand_bytes(num_bytes)))
# UUID('5e85edc4-7078-d214-e773-f8caae16fe6c')
or:
# pip install pyOpenSSL
import uuid, OpenSSL
uuid.UUID(bytes = OpenSSL.rand.bytes(16))
# UUID('c9bf635f-b0cc-d278-a2c5-01eaae654461')
M2Crypto is best OpenSSL API in Python atm as pyOpenSSL appears to be maintained only to support legacy applications.
You can use the uuid library like so:
import uuid
my_id = uuid.uuid1() # or uuid.uuid4()
Python 3.6 makes most other answers here a bit out of date. Versions including 3.6 and beyond include the secrets module, which is designed for precisely this purpose.
If you need to generate a cryptographically secure string for any purpose on the web, refer to that module.
https://docs.python.org/3/library/secrets.html
Example:
import secrets
def make_token():
"""
Creates a cryptographically-secure, URL-safe string
"""
return secrets.token_urlsafe(16)
In use:
>>> make_token()
'B31YOaQpb8Hxnxv1DXG6nA'
import os, base64
def generate_session():
return base64.b64encode(os.urandom(16))
It can be as simple as creating a random number. Of course, you'd have to store your session IDs in a database or something and check each one you generate to make sure it's not a duplicate, but odds are it never will be if the numbers are large enough.

Categories