How do I create a GUID/UUID in Python that is platform independent? I hear there is a method using ActivePython on Windows but it's Windows only because it uses COM. Is there a method using plain Python?
The uuid module provides immutable UUID objects (the UUID class) and the functions uuid1(), uuid3(), uuid4(), uuid5() for generating version 1, 3, 4, and 5 UUIDs as specified in RFC 4122.
If all you want is a unique ID, you should probably call uuid1() or uuid4(). Note that uuid1() may compromise privacy since it creates a UUID containing the computer’s network address. uuid4() creates a random UUID.
UUID versions 6 and 7 - new Universally Unique Identifier (UUID) formats for use in modern applications and databases (draft) rfc - are available from https://pypi.org/project/uuid6/
Docs:
Python 2
Python 3
Examples (for both Python 2 and 3):
>>> import uuid
>>> # make a random UUID
>>> uuid.uuid4()
UUID('bd65600d-8669-4903-8a14-af88203add38')
>>> # Convert a UUID to a string of hex digits in standard form
>>> str(uuid.uuid4())
'f50ec0b7-f960-400d-91f0-c42a6d44e3d0'
>>> # Convert a UUID to a 32-character hexadecimal string
>>> uuid.uuid4().hex
'9fe2c4e93f654fdbb24c02b15259716c'
If you're using Python 2.5 or later, the uuid module is already included with the Python standard distribution.
Ex:
>>> import uuid
>>> uuid.uuid4()
UUID('5361a11b-615c-42bf-9bdb-e2c3790ada14')
I use GUIDs as random keys for database type operations.
The hexadecimal form, with the dashes and extra characters seem unnecessarily long to me. But I also like that strings representing hexadecimal numbers are very safe in that they do not contain characters that can cause problems in some situations such as '+','=', etc..
Instead of hexadecimal, I use a url-safe base64 string. The following does not conform to any UUID/GUID spec though (other than having the required amount of randomness).
import base64
import uuid
# get a UUID - URL safe, Base64
def get_a_uuid():
r_uuid = base64.urlsafe_b64encode(uuid.uuid4().bytes)
return r_uuid.replace('=', '')
If you need to pass UUID for a primary key for your model or unique field then below code returns the UUID object -
import uuid
uuid.uuid4()
If you need to pass UUID as a parameter for URL you can do like below code -
import uuid
str(uuid.uuid4())
If you want the hex value for a UUID you can do the below one -
import uuid
uuid.uuid4().hex
If you are making a website or app where you need to every time a unique id. It should be a string a number then UUID is a great package in python which is helping to create a unique id.
**pip install uuid**
import uuid
def get_uuid_id():
return str(uuid.uuid4())
print(get_uuid_id())
OUTPUT example: 89e5b891-cf2c-4396-8d1c-49be7f2ee02d
2019 Answer (for Windows):
If you want a permanent UUID that identifies a machine uniquely on Windows, you can use this trick: (Copied from my answer at https://stackoverflow.com/a/58416992/8874388).
from typing import Optional
import re
import subprocess
import uuid
def get_windows_uuid() -> Optional[uuid.UUID]:
try:
# Ask Windows for the device's permanent UUID. Throws if command missing/fails.
txt = subprocess.check_output("wmic csproduct get uuid").decode()
# Attempt to extract the UUID from the command's result.
match = re.search(r"\bUUID\b[\s\r\n]+([^\s\r\n]+)", txt)
if match is not None:
txt = match.group(1)
if txt is not None:
# Remove the surrounding whitespace (newlines, space, etc)
# and useless dashes etc, by only keeping hex (0-9 A-F) chars.
txt = re.sub(r"[^0-9A-Fa-f]+", "", txt)
# Ensure we have exactly 32 characters (16 bytes).
if len(txt) == 32:
return uuid.UUID(txt)
except:
pass # Silence subprocess exception.
return None
print(get_windows_uuid())
Uses Windows API to get the computer's permanent UUID, then processes the string to ensure it's a valid UUID, and lastly returns a Python object (https://docs.python.org/3/library/uuid.html) which gives you convenient ways to use the data (such as 128-bit integer, hex string, etc).
Good luck!
PS: The subprocess call could probably be replaced with ctypes directly calling Windows kernel/DLLs. But for my purposes this function is all I need. It does strong validation and produces correct results.
Run this command:
pip install uuid uuid6
And then run you can import uuid1, uuid3, uuid4 and uuid5 functions from the uuid package, and uuid6 and uuid7 functions from the uuid6 package.
An example output of calling each of these functions is as follows (except uuid3 and uuid5 which require parameters):
>>> import uuid, uuid6
>>> print(*(str(i()) for i in [uuid.uuid1, uuid.uuid4, uuid6.uuid6, uuid6.uuid7]), sep="\n")
646e934b-f20c-11ec-ad9f-54a1500ef01b
560e2227-c738-41d9-ad5a-bbed6a3bc273
1ecf20b6-46e9-634b-9e48-b2b9e6010c57
01818aa2-ec45-74e8-1f85-9d74e4846897
This function is fully configurable and generates unique uid based on the format specified
eg:- [8, 4, 4, 4, 12] , this is the format mentioned and it will generate the following uuid
LxoYNyXe-7hbQ-caJt-DSdU-PDAht56cMEWi
import random as r
def generate_uuid():
random_string = ''
random_str_seq = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
uuid_format = [8, 4, 4, 4, 12]
for n in uuid_format:
for i in range(0,n):
random_string += str(random_str_seq[r.randint(0, len(random_str_seq) - 1)])
if n != 12:
random_string += '-'
return random_string
Related
I'd like to change the thousands separator such that {:,}.format(1234) in Python uses a different character. The separator should be '\u066c'.
How can I set this without affecting any other locals settings?
EDIT: Any other suggestion for a unimposing separator viable in a fixed with font is welcome!
Your options are to either take the , formatted output and replace the commas, switch locales and use the 'n' number format (which will format the number based on the current locale), or use a third party library like babel. The latter gives you full locale control over number formatting, for example, provided there is a locale that uses U+066C as the thousands separator.
With the format() function, the first option is quite straight-forward really:
>>> format(1234, ',').replace(',', '\u066c')
'1٬234'
I have yet to find a locale that directly would use \u066c for Western Arabic numerals however; U+066C is commonly used only with Eastern Arabic numerals instead. Babel doesn't include any such locale data, at least.
You can pass any babel Locale object in to the babel.numbers.format_number() function, so if you need a custom separator you can clone an existing locale and set the Locale.number_symbols['group'] value:
from copy import deepcopy
from babel import Locale
us_locale = Locale('en', 'US')
base_locale.number_symbols # ensure instance has been populated
altered_locale = deepcopy(us_locale)
altered_locale.number_symbols['group'] = '\u066c'
Note that you have to access an attribute (or the ._data property) to trigger loading the locale configuration, before copying. Otherwise, the data between the original (source) locale and the altered locale will be shared (so the us_locale object in my snippet above would have the same number separator.
Using the altered_locale object now results in the expected output:
>>> from babel.numbers import format_number
>>> format_number(1234, locale=altered_locale)
'1٬234'
Taking Martijn's excellent answer further for use in Django, on how to override a locale in a Django template.
File myapp/templatetags/extra.py
from django import template
from django.utils.translation import get_language
from copy import deepcopy
from babel import Locale
from babel.numbers import format_number
register = template.Library()
#register.filter
def currency(value):
lang = get_language()
locale = deepcopy(Locale(lang))
if lang == 'ru': # for example if russian
locale.number_symbols['group'] = '.'
return format_number(value, locale=locale)
In template:
{% load extra %}
{{ price|currency }}
I need to generate a API key and Secret that would be stored in a Redis server. What would be the best way to generate a key and secret?
I am develop a Django-tastypie framework based app.
If you're on Python 3.6 or later, the secrets module is the way to go:
The secrets module is used for generating cryptographically strong random numbers suitable for managing data such as passwords, account authentication, security tokens, and related secrets.
In particular, secrets should be used in preference to the default pseudo-random number generator in the random module, which is designed for modelling and simulation, not security or cryptography.
e.g. to generate a 16 byte token:
>>> import secrets
>>> secrets.token_urlsafe(16)
'zs9XYCbTPKvux46UJckflw'
>>> secrets.token_hex(16)
'6bef18936ac12a9096e9fe7a8fe1f777'
For python3.6+
import secrets
generated_key = secrets.token_urlsafe(length)
For older versions of python:
for a very secure way of generating random number, you should use urandom:
from binascii import hexlify
key = hexlify(os.urandom(length))
this will produce bytes, call key.decode() if you need a string
For general non-secure random strings, with more settings, you can just generate keys of your desired length the python way:
import random
import string
def generate_key(length):
return ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(length))
And then you can just call it with your desired length key = generate_key(40).
You can specify what alphabet you want to use, for example using only string.ascii_lowercase for key consisting of only lowercase letters etc.
There is also Model for Api authentication in tastypie, might be worth checking out https://django-tastypie.readthedocs.org/en/latest/authentication.html#apikeyauthentication
you can also use following module to generate random string
1 - os.urandom(64).encode('hex') #from os module
2 - uuid.uuid4() # from uuid module
3 - get_random_string(length=32) #from django.utils.crypto
4 - secrets.token_hex(64) #from secrets >= python 3.6
Adding answer as I can't comment on T. Opletals answer.
You should not use random.choice as random isn't cryptographically secure. A better option would be random.SystemRandom() which uses the system source of randomness, on linux this would be urandom.
def generate_key(length):
char_set = string.ascii_letters + string.punctuation
urand = random.SystemRandom()
return ''.join([urand.choice(char_set) for _ in range(length)])
If you want an easy-to-use but highly customisable key generator, use key-generator pypi package.
Here is the GitHub repo where you can find the complete documentation.
Here's an example:
from key_generator.key_generator import generate
custom_key = generate(2, ['-', ':'], 3, 10, type_of_value = 'char', capital = 'mix', seed = 17).get_key()
print(custom_key) # ZLFdHXIUe-ekwJCu
Hope this helps :)
Disclaimer: This uses the key-generator library which I made.
I'm using: https://github.com/bitcoin-abe/bitcoin-abe to import the blockchain into a mysql DB it is almost done after 5 days. So I started looking at the data and didn't see any addresses. I know the BTC client doesn't use those, but it still would be nice to have them in another table. I was looking around at the code and found this:
def hash_to_address(version, hash):
vh = version + hash
return base58.b58encode(vh + double_sha256(vh)[:4])
In: https://github.com/bitcoin-abe/bitcoin-abe/blob/3004fe4bad6f64d4c032c735ee23bf9f052d825b/Abe/util.py
When I run a pubkey_hash through that function I don't get the expected result of an address. For example taking the following pubkey_hash: 62E907B15CBF27D5425399EBF6F0FB50EBB88F18
I should get: 1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa
But instead I get: 6GEZdxx5UiTk3U3LaLfsWwRaFAvXEpPNS5R4mqsJDXVJcTNNngTyB5i9S76MLTq
The script I created is:
import util
hash = '62E907B15CBF27D5425399EBF6F0FB50EBB88F18'
print util.hash_to_address("00", hash)
Any ideas or is there something else that would do the same correctly?
Appleman1234 pointed me in the right direction:
import util
hash = '62E907B15CBF27D5425399EBF6F0FB50EBB88F18'
hash = '00' + hash
print "Util: ", util.hash_to_address("", hash.decode('hex'))
The reason you don't get the result you expected is due to encoding.
The correct code for Python 2
import util
hash = '62e907b15cbf27d5425399ebf6f0fb50ebb88f18'
print util.hash_to_address("00".decode('hex'), hash.decode('hex'))
The correct code for Python 3
import util
import binascii
hash = '62e907b15cbf27d5425399ebf6f0fb50ebb88f18'
print util.hash_to_address(binascii.unhexlify("00"), binascii.unhexlify(hash))
The decode and unhexlify functions convert the hexadecimal ASCII representations into binary byte strings.
The problem you were having was that the hash of the binary string and the hash of its hexadecimal ASCII representation are two different hashs.
I'm looking to create a simple brute-force password-cracker which will hash an input from stdin and compare the result to an existing hash (for my securities class).
I've never done any actual programming involving hashes, though, since it's mostly been conceptual/mathematical parts so far. Is there a (relatively) easy-to-learn language which has a simple hash command? A friend of mine recommended Python but I'm not sure if there's anything else out there I could pick up within a day or two. I know a bit of C, but hashing seems relatively complicated and needs additional libraries.
Also, any syntax help with an actual hash command would be appreciated. The program itself needs to be able to support odd hash methods, like hashing a value twice or using a set salt that doesn't change, and be able to take input from stdin (for use with programs like johntheripper).
Assuming that you're only being asked to use the hash functions, and not to implement the hash yourself, Python's hashlib module has routines for md5 and sha1:
[Updated for Python 3, in which hashlib wants bytes, not strings:]
>>> import hashlib
>>> s = 'something to hash'
>>> sb = s.encode("utf8")
>>> hashlib.md5(sb)
<md5 HASH object # 0x7f36f5ce3440>
>>> hashlib.md5(sb).hexdigest()
'6f4815fdf1f1fd3f36ac295bf39d26b4'
>>> hashlib.sha1(sb).hexdigest()
'72668bc961b0a78bfa1633f6141bcea69ca37468'
[Legacy Python 2 version:]
>>> import hashlib
>>> s = 'something to hash'
>>> hashlib.md5(s)
<md5 HASH object # 0xb7714ca0>
>>> hashlib.md5(s).hexdigest()
'6f4815fdf1f1fd3f36ac295bf39d26b4'
>>> hashlib.sha1(s).hexdigest()
'72668bc961b0a78bfa1633f6141bcea69ca37468'
I think python is a fine choice for something like this. It has the hashlib module to start with, and if you need more power, the PyCrypto toolkit is easy to use and supports plenty of cryptographic primitives, including hashing. If you already know some C, then maybe just using that with the openssl libraries will be easier for you to pick up. In any case, it is usually worth the investment to learn a crypto library for your preferred language (especially for a crypto class), because eventually you will want to use something that you won't want to code by hand and be confident that it is implemented correctly.
As for syntax with an actual hash command, here is an example in python with PyCrypto for getting a SHA256 hash (using python 3.2):
import Crypto.Hash.SHA256
to_hash = "hello, how are you?"
sha256 = Crypto.Hash.SHA256.new()
sha256.update(to_hash.encode())
dgst = sha256.hexdigest()
print(dgst)
produces the output
5c1940d2a11cd8b1e256ea4183ba22cddfa7cc0d00610a159bd7f5886d01067a
The hashlib library in python contains the following :
'md5', 'new', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512'
for details check:
http://docs.python.org/release/3.1.3/library/hashlib.html
>>> import hashlib
>>> m = hashlib.md5()
>>> m.update(b"Nobody inspects")
>>> m.update(b" the spammish repetition")
>>> m.digest()
b'\xbbd\x9c\x83\xdd\x1e\xa5\xc9\xd9\xde\xc9\xa1\x8d\xf0\xff\xe9'
>>> m.digest_size
16
>>> m.block_size
64
This small python program suits best for these type of small jobs
hash.py
import hashlib
import sys
try:
hash_name = sys.argv[1]
except IndexError:
print 'Specify the hash name as the first argument.'
else:
try:
data = sys.argv[2]
except IndexError:
print 'Please enter the data to be hashed'
sys.exit()
h = hashlib.new(hash_name)
h.update(data)
print h.hexdigest()
Output
$ python hash.py sha1 password1
e38ad214943daad1d64c102faec29de4afe9da3d
$ python hash.py sha256 password1
0b14d501a594442a01c6859541bcb3e8164d183d32937b851835442f69d5c94e
$ python hash.py md5 password1
7c6a180b36896a0a8c02787eeafb0e4c
No programming language worth its salt can be learned in a few days. You may be able to get the syntax figured out, but not much beyond that. I like this article: http://norvig.com/21-days.html
There is probably not a best programming language for this. I can recommend C#, as it has simple cryptography classes in System.Security.Cryptography.
To find the MD5 hash of a byte array, you can use something like this:
byte[] hash = System.Security.Cryptography.MD5.Create().ComputeHash(myByteArray);
To use SHA1, just replace MD5 with SHA1.
If you want to get the hash of an ASCII string, you can get a byte array like so:
byte[] myByteArray = System.Text.Encoding.ASCII.GetBytes(myString);
An example function for converting a string to a hash:
// At the top of the file:
// using System.Security.Cryptography;
// using System.Text;
byte[] GetHash(string message)
{
return MD5.Create().ComputeHash(Encoding.ASCII.GetBytes(message));
}
I need to arrange some kind of encrpytion for generating user specific links. Users will be clicking this link and at some other view, related link with the crypted string will be decrypted and result will be returned.
For this, I need some kind of encryption function that consumes a number(or a string) that is the primary key of my selected item that is bound to the user account, also consuming some kind of seed and generating encryption code that will be decrypted at some other page.
so something like this
my_items_pk = 36 #primary key of an item
seed = "rsdjk324j23423j4j2" #some string for crypting
encrypted_string = encrypt(my_items_pk,seed)
#generates some crypted string such as "dsaj2j213jasas452k41k"
and at another page:
decrypt_input = encrypt(decypt,seed)
print decrypt_input
#gives 36
I want my "seed" to be some kind of primary variable (not some class) for this purpose (ie some number or string).
How can I achieve this under python and django ?
There are no encryption algorithms, per se, built in to Python. However, you might want to look at the Python Cryptography Toolkit (PyCrypt). I've only tinkered with it, but it's referenced in Python's documentation on cryptographic services. Here's an example of how you could encrypt a string with AES using PyCrypt:
from Crypto.Cipher import AES
from urllib import quote
# Note that for AES the key length must be either 16, 24, or 32 bytes
encryption_obj = AES.new('abcdefghijklmnop')
plain = "Testing"
# The plaintext must be a multiple of 16 bytes (for AES), so here we pad it
# with spaces if necessary.
mismatch = len(plain) % 16
if mismatch != 0:
padding = (16 - mismatch) * ' '
plain += padding
ciph = encryption_obj.encrypt(plain)
# Finally, to make the encrypted string safe to use in a URL we quote it
quoted_ciph = quote(ciph)
You would then make this part of your URL, perhaps as part of a GET request.
To decrypt, just reverse the process; assuming that encryption_obj is created as above, and that you've retrieved the relevant part of the URL, this would do it:
from urllib import unquote
# We've already created encryption_object as shown above
ciph = unquote(quoted_ciph)
plain = encryption_obj.decrypt(ciph)
You also might consider a different approach: one simple method would be to hash the primary key (with a salt, if you wish) and store the hash and pk in your database. Give the user the hash as part of their link, and when they return and present the hash, look up the corresponding pk and return the appropriate object. (If you want to go this route, check out the built-in library hashlib.)
As an example, you'd have something like this defined in models.py:
class Pk_lookup(models.Model):
# since we're using sha256, set the max_length of this field to 32
hashed_pk = models.CharField(primary_key=True, max_length=32)
key = models.IntegerField()
And you'd generate the hash in a view using something like the following:
import hashlib
import Pk_lookup
hash = hashlib.sha256()
hash.update(str(pk)) # pk has been defined previously
pk_digest = hash.digest()
lookup = Pk_lookup(hashed_pk=pk_digest,key=pk)
lookup.save()
Note that you'd have to quote this version as well; if you prefer, you can use hexdigest() instead of digest (you wouldn't have to quote the resulting string), but you'll have to adjust the length of the field to 64.
Django has features for this now. See https://docs.djangoproject.com/en/dev/topics/signing/
Quoting that page:
"Django provides both a low-level API for signing values and a high-level API for setting and reading signed cookies, one of the most common uses of signing in Web applications.
You may also find signing useful for the following:
Generating “recover my account” URLs for sending to users who have lost their password.
Ensuring data stored in hidden form fields has not been tampered with.
Generating one-time secret URLs for allowing temporary access to a protected resource, for - example a downloadable file that a user has paid for."