hashlib --- هش‌های امن و چکیده‌های پیام

کد منبع: Lib/hashlib.py


این ماژول یک رابط مشترک را برای بسیاری از الگوریتم‌های هش متفاوت پیاده‌سازی می‌کند. موارد شامل‌شده عبارت‌اند از الگوریتم‌های هش امن FIPS یعنی SHA224، SHA256، SHA384، SHA512، (تعریف‌شده در the FIPS 180-4 standard)، سری SHA-3 (تعریف‌شده در the FIPS 202 standard) و همچنین الگوریتم‌های قدیمی SHA1 (formerly part of FIPS) و الگوریتم MD5 (تعریف‌شده در سند اینترنتی RFC 1321).

توجه

اگر به توابع هش adler32 یا crc32 نیاز دارید، این توابع در ماژول zlib در دسترس هستند.

الگوریتم‌های هش

برای هر نوع هش <hash>، یک متد سازنده با همان نام وجود دارد. همه آن‌ها یک شیء هش با رابط ساده یکسان برمی‌گردانند. برای مثال: از sha256() برای ایجاد یک شیء هش SHA-256 استفاده کنید. اکنون می‌توانید با استفاده از متد update، این شیء را با اشیاء شبه‌بایت (به‌طور معمول bytes) تغذیه کنید. در هر زمان می‌توانید با استفاده از متدهای digest() یا hexdigest()، چکیده <digest> حاصل از الحاق داده‌هایی که تاکنون به آن داده شده است را از آن بخواهید.

برای امکان‌پذیر کردن چندنخی، GIL پایتون هنگام محاسبه‌ی هشی که بیش از ۲۰۴۷ بایت داده را به‌صورت یک‌جا در سازنده یا متد .update خود دریافت کرده است، آزاد می‌شود.

سازنده‌هایی برای الگوریتم‌های هش که همیشه در این ماژول موجود هستند، عبارت‌اند از sha1()، sha224()، sha256()، sha384()، sha512()، sha3_224()، sha3_256()، sha3_384()، sha3_512()، shake_128()، shake_256()، blake2b() و blake2s(). md5() نیز معمولاً در دسترس است، هرچند اگر از یک نسخه‌ی ساخت نادر «سازگار با FIPS» پایتون استفاده می‌کنید، ممکن است وجود نداشته باشد یا مسدود شده باشد. این موارد با algorithms_guaranteed متناظر هستند.

اگر hashlib توزیع پایتون شما با ساختی از OpenSSL پیوند داده شده باشد که سایر الگوریتم‌ها را فراهم کند، ممکن است الگوریتم‌های اضافی دیگری نیز در دسترس باشند. سایر الگوریتم‌ها در دسترس بودنشان در همه نصب‌ها تضمین نمی‌شود و تنها با نام از طریق new() قابل دسترسی خواهند بود. algorithms_available را ببینید.

هشدار

برخی الگوریتم‌ها دارای ضعف‌های شناخته‌شده در برخورد هش هستند (از جمله MD5 و SHA1). به Attacks on cryptographic hash algorithms و بخش hashlib-seealso در پایان این سند مراجعه کنید.

اضافه شده در نسخه‌ی 3.6: سازنده‌های SHA3 (Keccak) و SHAKE یعنی sha3_224()، sha3_256()، sha3_384()، sha3_512()، shake_128() و shake_256() افزوده شدند. blake2b() و blake2s() افزوده شدند.

تغییر یافته در نسخه‌ی 3.9: تمام سازنده‌های hashlib یک آرگومان فقط کلیدواژه‌ای usedforsecurity با مقدار پیش‌فرض True می‌پذیرند. یک مقدار نادرست اجازه می‌دهد از الگوریتم‌های هش ناامن و مسدودشده در محیط‌های محدودشده استفاده شود. False نشان می‌دهد که الگوریتم هش در یک زمینه‌ی امنیتی استفاده نمی‌شود، مثلاً به‌عنوان یک تابع فشرده‌سازی یک‌طرفه‌ی غیررمزنگاری.

تغییر یافته در نسخه‌ی 3.9: Hashlib اکنون در صورتی که OpenSSL آن‌ها را فراهم کند، از SHA3 و SHAKE از OpenSSL استفاده می‌کند.

تغییر یافته در نسخه‌ی 3.12: برای هر یک از الگوریتم‌های MD5، SHA1، SHA2 یا SHA3 که OpenSSL پیوندداده‌شده آن‌ها را فراهم نمی‌کند، به یک پیاده‌سازی تأییدشده از HACL* project متوسل می‌شویم.

استفاده

برای به دست آوردن خلاصه‌ی رشته‌ی بایتی b"Nobody inspects the spammish repetition":

>>> import hashlib
>>> m = hashlib.sha256()
>>> m.update(b"Nobody inspects")
>>> m.update(b" the spammish repetition")
>>> m.digest()
b'\x03\x1e\xdd}Ae\x15\x93\xc5\xfe\\\x00o\xa5u+7\xfd\xdf\xf7\xbcN\x84:\xa6\xaf\x0c\x95\x0fK\x94\x06'
>>> m.hexdigest()
'031edd7d41651593c5fe5c006fa5752b37fddff7bc4e843aa6af0c950f4b9406'

فشرده‌تر:

>>> hashlib.sha256(b"Nobody inspects the spammish repetition").hexdigest()
'031edd7d41651593c5fe5c006fa5752b37fddff7bc4e843aa6af0c950f4b9406'

سازنده‌ها

hashlib.new(name, [data, ]*, usedforsecurity=True)

یک سازنده‌ی عام است که رشته‌ی name الگوریتم مورد نظر را به‌عنوان نخستین پارامتر خود می‌گیرد. همچنین وجود دارد تا امکان دسترسی به هش‌های فهرست‌شده در بالا و نیز هر الگوریتم دیگری را که کتابخانه‌ی OpenSSL شما ممکن است ارائه دهد، فراهم کند.

استفاده از new() با نام یک الگوریتم:

>>> h = hashlib.new('sha256')
>>> h.update(b"Nobody inspects the spammish repetition")
>>> h.hexdigest()
'031edd7d41651593c5fe5c006fa5752b37fddff7bc4e843aa6af0c950f4b9406'
hashlib.md5([data, ]*, usedforsecurity=True)
hashlib.sha1([data, ]*, usedforsecurity=True)
hashlib.sha224([data, ]*, usedforsecurity=True)
hashlib.sha256([data, ]*, usedforsecurity=True)
hashlib.sha384([data, ]*, usedforsecurity=True)
hashlib.sha512([data, ]*, usedforsecurity=True)
hashlib.sha3_224([data, ]*, usedforsecurity=True)
hashlib.sha3_256([data, ]*, usedforsecurity=True)
hashlib.sha3_384([data, ]*, usedforsecurity=True)
hashlib.sha3_512([data, ]*, usedforsecurity=True)

سازنده‌های نام‌داری مانند این‌ها سریع‌تر از ارسال نام الگوریتم به new() هستند.

ویژگی‌ها

Hashlib ویژگی‌های ثابت زیر را در سطح ماژول فراهم می‌کند:

hashlib.algorithms_guaranteed

مجموعه‌ای شامل نام‌های الگوریتم‌های هش که تضمین شده است این ماژول در همه پلتفرم‌ها از آن‌ها پشتیبانی می‌کند. توجه داشته باشید که 'md5' با وجود اینکه برخی فروشندگان بالادستی یک ساخت پایتون عجیب «منطبق با FIPS» ارائه می‌کنند که آن را حذف می‌کند، در این فهرست قرار دارد.

اضافه شده در نسخه‌ی 3.2.

hashlib.algorithms_available

مجموعه‌ای شامل نام‌های الگوریتم‌های هش موجود در مفسر پایتونِ در حال اجرا است. این نام‌ها هنگامی که به new() ارسال شوند، شناخته خواهند شد. algorithms_guaranteed همیشه زیرمجموعه‌ای خواهد بود. ممکن است یک الگوریتم یکسان چندین بار با نام‌های مختلف در این مجموعه ظاهر شود (به لطف OpenSSL).

اضافه شده در نسخه‌ی 3.2.

اشیاء هش

مقادیر زیر به‌عنوان ویژگی‌های ثابت اشیاء هش برگردانده‌شده توسط سازنده‌ها ارائه می‌شوند:

hash.digest_size

اندازه‌ی هش حاصل بر حسب بایت.

hash.block_size

اندازه‌ی بلوک داخلی الگوریتم هش بر حسب بایت.

یک شیء هش دارای ویژگی‌های زیر است:

hash.name

نام کانونیکال این هش، که همیشه با حروف کوچک است و همیشه به‌عنوان پارامتری برای new() جهت ایجاد هش دیگری از این نوع مناسب است.

تغییر یافته در نسخه‌ی 3.4: ویژگی name از ابتدای پیدایش CPython وجود داشته است، اما تا Python 3.4 به‌طور رسمی مشخص نشده بود، بنابراین ممکن است در برخی پلتفرم‌ها وجود نداشته باشد.

یک شیء هش دارای متدهای زیر است:

hash.update(data)

شیء هش را با bytes-like object به‌روزرسانی کنید. فراخوانی‌های مکرر معادل یک فراخوانی با الحاق همه آرگومان‌ها است: m.update(a); m.update(b) معادل m.update(a+b) است.

hash.digest()

چکیده‌ای از داده‌هایی که تاکنون به متد update() ارسال شده است را برمی‌گرداند. این یک شیء از نوع bytes به اندازه digest_size است که ممکن است حاوی بایت‌هایی در کل بازه از ۰ تا ۲۵۵ باشد.

hash.hexdigest()

مانند digest()، با این تفاوت که چکیده به‌صورت یک شیء رشته‌ای با طولی دو برابر برگردانده می‌شود که تنها شامل ارقام مبنای شانزده است. می‌توان از آن برای تبادل امن مقدار در ایمیل یا سایر محیط‌های غیردودویی استفاده کرد.

hash.copy()

یک کپی («clone») از شیء هش برمی‌گرداند. می‌توان از این برای محاسبه‌ی کارآمد چکیده‌های داده‌هایی که یک زیررشته‌ی آغازین مشترک دارند استفاده کرد.

چکیده‌های با طول متغیر SHAKE

hashlib.shake_128([data, ]*, usedforsecurity=True)
hashlib.shake_256([data, ]*, usedforsecurity=True)

الگوریتم‌های shake_128() و shake_256() چکیده‌هایی با طول متغیر فراهم می‌کنند که length_in_bits//2 آن‌ها تا ۱۲۸ یا ۲۵۶ بیت امنیت دارد. به همین دلیل، متدهای digest آن‌ها نیازمند یک طول هستند. حداکثر طول توسط الگوریتم SHAKE محدود نشده است.

shake.digest(length)

خلاصه‌ی داده‌هایی که تاکنون به متد update() ارسال شده‌اند را برمی‌گرداند. این یک شیء bytes به اندازه‌ی length است که ممکن است شامل بایت‌هایی در کل بازه‌ی ۰ تا ۲۵۵ باشد.

shake.hexdigest(length)

مانند digest() است، با این تفاوت که مقدار خلاصه به‌صورت یک شیء رشته‌ای با طولی دو برابر برگردانده می‌شود که فقط شامل ارقام مبنای شانزده است. می‌توان از آن برای تبادل مقدار در ایمیل یا سایر محیط‌های غیردودویی استفاده کرد.

نمونه استفاده:

>>> h = hashlib.shake_256(b'Nobody inspects the spammish repetition')
>>> h.hexdigest(20)
'44709d6fcb83d92a76dcb0b668c98e1b1d3dafe7'

هش‌کردن پرونده

ماژول hashlib یک تابع کمکی برای هش‌کردن کارآمد یک پرونده یا شیء شبه‌پرونده فراهم می‌کند.

hashlib.file_digest(fileobj, digest, /)

یک شیء digest برمی‌گرداند که با محتوای شیء پرونده به‌روزرسانی شده است.

fileobj باید یک شیء شبه‌پرونده باشد که برای خواندن در حالت دودویی باز شده باشد. اشیای پرونده حاصل از تابع توکار open()، نمونه‌های BytesIO، اشیای SocketIO حاصل از socket.socket.makefile() و موارد مشابه پذیرفته می‌شوند. fileobj باید در حالت مسدودکننده باز شده باشد، در غیر این صورت ممکن است BlockingIOError پرتاب شود.

این تابع ممکن است ورودی/خروجی پایتون را دور بزند و به‌طور مستقیم از توصیف‌گر فایلِ حاصل از fileno() استفاده کند. باید فرض شود که fileobj پس از بازگشت یا پرتاب استثنا توسط این تابع، در وضعیت نامعلومی قرار دارد. بستن fileobj بر عهده‌ی فراخواننده است.

digest باید یکی از این موارد باشد: نام یک الگوریتم هش به‌صورت str، یک سازنده هش، یا یک شیء فراخوانی‌پذیر که یک شیء هش برمی‌گرداند.

مثال:

>>> import io, hashlib, hmac
>>> with open("library/hashlib.rst", "rb") as f:
...     digest = hashlib.file_digest(f, "sha256")
...
>>> digest.hexdigest()
'...'
>>> buf = io.BytesIO(b"somedata")
>>> mac1 = hmac.HMAC(b"key", digestmod=hashlib.sha512)
>>> digest = hashlib.file_digest(buf, lambda: mac1)
>>> digest is mac1
True
>>> mac2 = hmac.HMAC(b"key", b"somedata", digestmod=hashlib.sha512)
>>> mac1.digest() == mac2.digest()
True

اضافه شده در نسخه‌ی 3.11.

تغییر یافته در نسخه‌ی 3.14: اکنون اگر پرونده در حالت غیرمسدودکننده باز شده باشد، BlockingIOError پرتاب می‌شود. پیش‌تر، بایت‌های نول کاذب به خلاصه افزوده می‌شدند.

اشتقاق کلید

الگوریتم‌های اشتقاق کلید و کشش کلید (key derivation and key stretching) برای هش کردن امن گذرواژه طراحی شده‌اند. الگوریتم‌های ساده‌ای مانند sha1(password) در برابر حملات جستجوی فراگیر (brute-force) مقاوم نیستند. یک تابع خوب برای هش کردن گذرواژه باید قابل‌تنظیم، کند و شامل یک نمک (salt) باشد.

hashlib.pbkdf2_hmac(hash_name, password, salt, iterations, dklen=None)

این تابع، تابع استخراج کلید مبتنی بر گذرواژه PKCS#5 نسخه 2 را فراهم می‌کند. این تابع از HMAC به‌عنوان تابع شبه‌تصادفی استفاده می‌کند.

رشته hash_name نام موردنظر الگوریتم خلاصه‌سازی هش برای HMAC است، برای مثال 'sha1' یا 'sha256'. password و salt به‌عنوان بافرهایی از بایت‌ها تفسیر می‌شوند. برنامه‌ها و کتابخانه‌ها باید password را به یک طول معقول محدود کنند (برای مثال ۱۰۲۴). salt باید حدود ۱۶ بایت یا بیشتر از یک منبع مناسب باشد، برای مثال os.urandom().

تعداد تکرارها باید بر اساس الگوریتم هش و توان محاسباتی انتخاب شود. از سال ۲۰۲۲، صدها هزار تکرار از SHA-256 پیشنهاد می‌شود. برای درک دلیل و شیوه انتخاب بهترین گزینه برای برنامه‌تان، پیوست A.2.2 از NIST-SP-800-132 را بخوانید. پاسخ‌های موجود در stackexchange pbkdf2 iterations question به‌تفصیل توضیح داده‌اند.

dklen طول کلید مشتق‌شده بر حسب بایت است. اگر dklen برابر None باشد، از اندازه‌ی چکیده‌ی الگوریتم هش hash_name استفاده می‌شود، مثلاً ۶۴ برای SHA-512.

>>> from hashlib import pbkdf2_hmac
>>> our_app_iters = 500_000  # Application specific, read above.
>>> dk = pbkdf2_hmac('sha256', b'password', b'bad salt' * 2, our_app_iters)
>>> dk.hex()
'15530bba69924174860db778f2c6f8104d3aaf9d26241840c8c4a641c8d000a9'

تابع تنها زمانی در دسترس است که پایتون با OpenSSL کامپایل شده باشد.

اضافه شده در نسخه‌ی 3.4.

تغییر یافته در نسخه‌ی 3.12: تابع اکنون تنها زمانی در دسترس است که پایتون با OpenSSL ساخته شده باشد. پیاده‌سازی کندِ پایتون خالص حذف شده است.

hashlib.scrypt(password, *, salt, n, r, p, maxmem=0, dklen=64)

این تابع، تابع استخراج کلید مبتنی بر گذرواژه‌ی scrypt را همان‌گونه که در RFC 7914 تعریف‌شده است، فراهم می‌کند.

password و salt باید اشیاء شبه‌بایت (bytes-like object) باشند. برنامه‌ها و کتابخانه‌ها باید password را به یک طول معقول محدود کنند (برای مثال ۱۰۲۴). salt باید حدود ۱۶ بایت یا بیشتر از یک منبع مناسب باشد، برای مثال os.urandom().

n عامل هزینه‌ی CPU/حافظه است، r اندازه‌ی بلوک، p عامل موازی‌سازی و maxmem حافظه را محدود می‌کند (مقدار پیش‌فرض در OpenSSL 1.1.0 برابر ۳۲ MiB است). dklen طول کلید مشتق‌شده بر حسب بایت است.

اضافه شده در نسخه‌ی 3.6.

BLAKE2

BLAKE2 یک تابع هش رمزنگاری تعریف‌شده در RFC 7693 است که در دو گونه ارائه می‌شود:

  • BLAKE2b، برای سکوهای ۶۴ بیتی بهینه‌سازی شده است و خلاصه‌هایی با هر اندازه‌ای بین ۱ تا ۶۴ بایت تولید می‌کند،

  • BLAKE2s، برای پلتفرم‌های ۸ تا ۳۲ بیتی بهینه‌سازی شده است و خلاصه‌هایی در هر اندازه‌ای بین ۱ تا ۳۲ بایت تولید می‌کند.

BLAKE2 از حالت کلیددار (جایگزینی سریع‌تر و ساده‌تر برای HMACهش نمک‌دار، شخصی‌سازی و هش درختی پشتیبانی می‌کند.

اشیای هش این ماژول از API اشیای hashlib در کتابخانه استاندارد پیروی می‌کنند.

ایجاد اشیای هش

اشیای هش جدید با فراخوانی توابع سازنده ایجاد می‌شوند:

hashlib.blake2b(data=b'', *, digest_size=64, key=b'', salt=b'', person=b'', fanout=1, depth=1, leaf_size=0, node_offset=0, node_depth=0, inner_size=0, last_node=False, usedforsecurity=True)
hashlib.blake2s(data=b'', *, digest_size=32, key=b'', salt=b'', person=b'', fanout=1, depth=1, leaf_size=0, node_offset=0, node_depth=0, inner_size=0, last_node=False, usedforsecurity=True)

این توابع، اشیای هش متناظر برای محاسبه‌ی BLAKE2b یا BLAKE2s را برمی‌گردانند. آن‌ها به‌اختیار این پارامترهای عمومی را می‌پذیرند:

  • data: تکه‌ی اولیه‌ای از داده برای هش کردن، که باید یک bytes-like object باشد. این آرگومان فقط می‌تواند به‌عنوان آرگومان جایگاهی ارسال شود.

  • digest_size: اندازه‌ی چکیده‌ی خروجی بر حسب بایت.

  • key: کلید برای هش کلیددار (تا ۶۴ بایت برای BLAKE2b، تا ۳۲ بایت برای BLAKE2s).

  • salt: نمک برای هش‌سازی تصادفی (تا ۱۶ بایت برای BLAKE2b، تا ۸ بایت برای BLAKE2s).

  • person: رشته‌ی شخصی‌سازی (تا ۱۶ بایت برای BLAKE2b و تا ۸ بایت برای BLAKE2s).

جدول زیر محدودیت‌های پارامترهای عمومی (بر حسب بایت) را نشان می‌دهد:

هش

digest_size

len(key)

len(salt)

len(person)

BLAKE2b

64

64

16

16

BLAKE2s

32

32

8

8

توجه

مشخصات BLAKE2 طول‌های ثابتی را برای پارامترهای salt و personalization تعریف می‌کند؛ با این حال، این پیاده‌سازی برای سهولت، رشته‌های بایتی با هر اندازه‌ای تا طول مشخص‌شده را می‌پذیرد. اگر طول پارامتر کمتر از طول مشخص‌شده باشد، با صفر پر می‌شود؛ بنابراین، برای مثال، b'salt' و b'salt\x00' مقدار یکسانی هستند. (این موضوع برای key صدق نمی‌کند.)

این اندازه‌ها به‌عنوان ثابت‌های ماژول constants که در زیر توضیح داده شده‌اند، در دسترس هستند.

توابع سازنده همچنین پارامترهای هش‌سازی درختی (tree hashing) زیر را می‌پذیرند:

  • fanout: fanout (۰ تا ۲۵۵، ۰ در صورت نامحدود بودن، ۱ در حالت ترتیبی).

  • depth: حداکثر عمق درخت (۱ تا ۲۵۵، ۲۵۵ اگر نامحدود باشد، ۱ در حالت متوالی).

  • leaf_size: حداکثر طول بایتی برگ (۰ تا 2**32-1، ۰ اگر نامحدود یا در حالت ترتیبی).

  • node_offset: آفست گره (node offset) (۰ تا 2**64-1 برای BLAKE2b، ۰ تا 2**48-1 برای BLAKE2s، ۰ برای اولین برگ سمت چپ، یا در حالت ترتیبی).

  • node_depth: عمق گره (۰ تا ۲۵۵، ۰ برای برگ‌ها، یا در حالت ترتیبی).

  • inner_size: اندازه‌ی digest داخلی (۰ تا ۶۴ برای BLAKE2b، ۰ تا ۳۲ برای BLAKE2s، ۰ در حالت ترتیبی).

  • last_node: بولی که نشان می‌دهد گره پردازش‌شده آخرین گره است (در حالت ترتیبی False).

توضیح پارامترهای حالت درختی.

برای بررسی جامع هش درختی، بخش 2.10 در BLAKE2 specification را ببینید.

ثابت‌ها

blake2b.SALT_SIZE
blake2s.SALT_SIZE

طول نمک (salt) (حداکثر طول پذیرفته‌شده توسط سازنده‌ها).

blake2b.PERSON_SIZE
blake2s.PERSON_SIZE

طول رشته‌ی شخصی‌سازی (بیشینه طول پذیرفته‌شده توسط سازنده‌ها).

blake2b.MAX_KEY_SIZE
blake2s.MAX_KEY_SIZE

حداکثر اندازه کلید.

blake2b.MAX_DIGEST_SIZE
blake2s.MAX_DIGEST_SIZE

حداکثر اندازه‌ی چکیده که تابع هش می‌تواند خروجی بدهد.

مثال‌ها

درهم‌سازی ساده

برای محاسبه‌ی هش برخی داده‌ها، باید ابتدا یک شیء هش را با فراخوانی تابع کارخانه‌ایٔ مناسب (blake2b() یا blake2s()) بسازید، سپس با فراخوانی update() روی شیء، آن را با داده‌ها به‌روزرسانی کنید و در نهایت، مقدار خلاصه را با فراخوانی digest() از شیء بگیرید (یا برای رشته‌ی کدگذاری‌شده به‌صورت مبنای شانزده، hexdigest() را فراخوانی کنید).

>>> from hashlib import blake2b
>>> h = blake2b()
>>> h.update(b'Hello world')
>>> h.hexdigest()
'6ff843ba685842aa82031d3f53c48b66326df7639a63d128974c5c14f31a0f33343a8c65551134ed1ae0f2b0dd2bb495dc81039e3eeb0aa1bb0388bbeac29183'

به‌عنوان یک میان‌بر، می‌توانید اولین تکه داده را برای به‌روزرسانی مستقیماً به‌عنوان آرگومان جایگاهی به سازنده ارسال کنید:

>>> from hashlib import blake2b
>>> blake2b(b'Hello world').hexdigest()
'6ff843ba685842aa82031d3f53c48b66326df7639a63d128974c5c14f31a0f33343a8c65551134ed1ae0f2b0dd2bb495dc81039e3eeb0aa1bb0388bbeac29183'

می‌توانید hash.update() را هر چند بار که نیاز دارید برای به‌روزرسانی تدریجی هش فراخوانی کنید:

>>> from hashlib import blake2b
>>> items = [b'Hello', b' ', b'world']
>>> h = blake2b()
>>> for item in items:
...     h.update(item)
...
>>> h.hexdigest()
'6ff843ba685842aa82031d3f53c48b66326df7639a63d128974c5c14f31a0f33343a8c65551134ed1ae0f2b0dd2bb495dc81039e3eeb0aa1bb0388bbeac29183'

استفاده از اندازه‌های مختلف چکیده

BLAKE2 دارای اندازه‌ی قابل‌پیکربندی برای خلاصه‌ها است، تا ۶۴ بایت برای BLAKE2b و تا ۳۲ بایت برای BLAKE2s. برای مثال، برای جایگزینی SHA-1 با BLAKE2b بدون تغییر اندازه‌ی خروجی، می‌توانیم به BLAKE2b بگوییم خلاصه‌های ۲۰ بایتی تولید کند:

>>> from hashlib import blake2b
>>> h = blake2b(digest_size=20)
>>> h.update(b'Replacing SHA1 with the more secure function')
>>> h.hexdigest()
'd24f26cf8de66472d58d4e1b1774b4c9158b1f4c'
>>> h.digest_size
20
>>> len(h.digest())
20

اشیای هش با اندازه‌های چکیده متفاوت، خروجی‌های کاملاً متفاوتی دارند (هش‌های کوتاه‌تر پیشوندهای هش‌های بلندتر نیستند)؛ BLAKE2b و BLAKE2s حتی اگر طول خروجی یکسان باشد، خروجی‌های متفاوتی تولید می‌کنند:

>>> from hashlib import blake2b, blake2s
>>> blake2b(digest_size=10).hexdigest()
'6fa1d8fcfd719046d762'
>>> blake2b(digest_size=11).hexdigest()
'eb6ec15daf9546254f0809'
>>> blake2s(digest_size=10).hexdigest()
'1bf21a98c78a1c376ae9'
>>> blake2s(digest_size=11).hexdigest()
'567004bf96e4a25773ebf4'

هش کلیددار (Keyed hashing)

هش کلیددار می‌تواند برای اصالت‌سنجی به‌عنوان جایگزینی سریع‌تر و ساده‌تر برای کد اصالت‌سنجی پیام مبتنی بر هش (HMAC) استفاده شود. BLAKE2 می‌تواند به‌لطف ویژگی تمایزناپذیری که از BLAKE به ارث رسیده است، به‌صورت امن در حالت prefix-MAC استفاده شود.

این مثال نشان می‌دهد که چگونه می‌توانید یک کد احراز هویت ۱۲۸ بیتی (کدگذاری‌شده به مبنای شانزده) را برای پیام b'message data' با کلید b'pseudorandom key' دریافت کنید:

>>> from hashlib import blake2b
>>> h = blake2b(key=b'pseudorandom key', digest_size=16)
>>> h.update(b'message data')
>>> h.hexdigest()
'3d363ff7401e02026f4a4687d4863ced'

به‌عنوان یک مثال عملی، یک برنامه کاربردی وب می‌تواند کوکی‌های ارسالی به کاربران را به‌صورت متقارن امضا کند و بعداً آن‌ها را تأیید کند تا اطمینان حاصل شود که دستکاری نشده‌اند:

>>> from hashlib import blake2b
>>> from hmac import compare_digest
>>>
>>> SECRET_KEY = b'pseudorandomly generated server secret key'
>>> AUTH_SIZE = 16
>>>
>>> def sign(cookie):
...     h = blake2b(digest_size=AUTH_SIZE, key=SECRET_KEY)
...     h.update(cookie)
...     return h.hexdigest().encode('utf-8')
>>>
>>> def verify(cookie, sig):
...     good_sig = sign(cookie)
...     return compare_digest(good_sig, sig)
>>>
>>> cookie = b'user-alice'
>>> sig = sign(cookie)
>>> print("{0},{1}".format(cookie.decode('utf-8'), sig))
user-alice,b'43b3c982cf697e0c5ab22172d1ca7421'
>>> verify(cookie, sig)
True
>>> verify(b'user-bob', sig)
False
>>> verify(cookie, b'0102030405060708090a0b0c0d0e0f00')
False

با وجود این‌که یک حالت هش کلیددار بومی وجود دارد، البته می‌توان از BLAKE2 در ساختار HMAC با ماژول hmac استفاده کرد:

>>> import hmac, hashlib
>>> m = hmac.new(b'secret key', digestmod=hashlib.blake2s)
>>> m.update(b'message')
>>> m.hexdigest()
'e3c8102868d28b5ff85fc35dda07329970d1a01e273c37481326fe0c861c8142'

درهم‌سازی تصادفی

با تنظیم پارامتر salt، کاربران می‌توانند تصادفی‌سازی را در تابع هش اعمال کنند. هش تصادفی‌شده برای محافظت در برابر حملات تصادم به تابع هش استفاده‌شده در امضاهای دیجیتال مفید است.

هش‌سازی تصادفی‌سازی‌شده (randomized hashing) برای موقعیت‌هایی طراحی شده است که در آن‌ها یک طرف، یعنی تهیه‌کننده پیام، تمام یا بخشی از یک پیام را تولید می‌کند تا توسط طرف دوم، یعنی امضاکننده پیام، امضا شود. اگر تهیه‌کننده پیام قادر به یافتن برخوردهای تابع هش رمزنگاری باشد (یعنی دو پیام که مقدار هش یکسانی تولید می‌کنند)، ممکن است نسخه‌های معناداری از پیام را تهیه کند که مقدار هش و امضای دیجیتال یکسانی تولید می‌کنند، اما نتایج متفاوتی دارند (برای مثال، انتقال ۱٬۰۰۰٬۰۰۰ دلار به یک حساب، به‌جای ۱۰ دلار). توابع هش رمزنگاری با هدف اصلی مقاومت در برابر برخورد طراحی شده‌اند، اما تمرکز کنونی بر حملات به توابع هش رمزنگاری ممکن است موجب شود که یک تابع هش رمزنگاری معین، مقاومت کمتری در برابر برخورد از حد انتظار داشته باشد. هش‌سازی تصادفی‌سازی‌شده با کاهش احتمال این‌که تهیه‌کننده بتواند دو یا چند پیام تولید کند که در نهایت در جریان فرآیند تولید امضای دیجیتال مقدار هش یکسانی را به دست می‌دهند، محافظت بیشتری برای امضاکننده فراهم می‌کند --- حتی اگر یافتن برخوردها برای تابع هش عملی باشد. با این حال، هنگامی که تمام بخش‌های پیام توسط امضاکننده تهیه شده باشند، استفاده از هش‌سازی تصادفی‌سازی‌شده ممکن است میزان امنیت فراهم‌شده توسط امضای دیجیتال را کاهش دهد.

(NIST SP-800-106 "Randomized Hashing for Digital Signatures")

در BLAKE2، نمک (salt) به‌عنوان یک ورودی یک‌باره برای تابع هش در حین مقداردهی اولیه پردازش می‌شود، نه به‌عنوان ورودی برای هر تابع فشرده‌سازی.

هشدار

هش نمک‌دار (یا فقط هش) با BLAKE2 یا هر تابع هش رمزنگاری عمومی دیگری، مانند SHA-256، برای هش کردن گذرواژه‌ها مناسب نیست. برای اطلاعات بیشتر BLAKE2 FAQ را ببینید.

>>> import os
>>> from hashlib import blake2b
>>> msg = b'some message'
>>> # Calculate the first hash with a random salt.
>>> salt1 = os.urandom(blake2b.SALT_SIZE)
>>> h1 = blake2b(salt=salt1)
>>> h1.update(msg)
>>> # Calculate the second hash with a different random salt.
>>> salt2 = os.urandom(blake2b.SALT_SIZE)
>>> h2 = blake2b(salt=salt2)
>>> h2.update(msg)
>>> # The digests are different.
>>> h1.digest() != h2.digest()
True

شخصی‌سازی

گاهی مفید است که تابع هش را وادار کنیم تا برای یک ورودی یکسان، چکیده‌های متفاوتی را برای اهداف مختلف تولید کند. به نقل از نویسندگان تابع هش Skein:

توصیه می‌کنیم همه‌ی طراحان برنامه به‌جدی انجام این کار را در نظر بگیرند؛ ما پروتکل‌های زیادی دیده‌ایم که در آن‌ها هشی که در بخشی از پروتکل محاسبه می‌شود، می‌تواند در بخشی کاملاً متفاوت استفاده شود، زیرا دو محاسبه‌ی هش روی داده‌های مشابه یا مرتبط انجام شده است و مهاجم می‌تواند برنامه را مجبور کند ورودی‌های هش را یکسان کند. شخصی‌سازی هر تابع هش استفاده‌شده در پروتکل، این نوع حمله را به‌طور قاطع متوقف می‌سازد.

(The Skein Hash Function Family، ص. ۲۱)

می‌توان BLAKE2 را با ارسال بایت‌ها به آرگومان person شخصی‌سازی کرد:

>>> from hashlib import blake2b
>>> FILES_HASH_PERSON = b'MyApp Files Hash'
>>> BLOCK_HASH_PERSON = b'MyApp Block Hash'
>>> h = blake2b(digest_size=32, person=FILES_HASH_PERSON)
>>> h.update(b'the same content')
>>> h.hexdigest()
'20d9cd024d4fb086aae819a1432dd2466de12947831b75c5a30cf2676095d3b4'
>>> h = blake2b(digest_size=32, person=BLOCK_HASH_PERSON)
>>> h.update(b'the same content')
>>> h.hexdigest()
'cf68fb5761b9c44e7878bfb2c4c9aea52264a80b75005e65619778de59f383a3'

شخصی‌سازی به همراه حالت کلیددار (keyed mode) همچنین می‌تواند برای استخراج کلیدهای مختلف از یک کلید واحد استفاده شود.

>>> from hashlib import blake2s
>>> from base64 import b64decode, b64encode
>>> orig_key = b64decode(b'Rm5EPJai72qcK3RGBpW3vPNfZy5OZothY+kHY6h21KM=')
>>> enc_key = blake2s(key=orig_key, person=b'kEncrypt').digest()
>>> mac_key = blake2s(key=orig_key, person=b'kMAC').digest()
>>> print(b64encode(enc_key).decode('utf-8'))
rbPb15S/Z9t+agffno5wuhB77VbRi6F9Iv2qIxU7WHw=
>>> print(b64encode(mac_key).decode('utf-8'))
G9GtHFE1YluXY1zWPlYk1e/nWfu0WSEb0KRcjhDeP/o=

حالت درختی

در اینجا مثالی از هش کردن یک درخت کمینه با دو گره برگ آورده شده است:

  10
 /  \
00  01

این مثال از خلاصه‌های داخلی ۶۴ بایتی استفاده می‌کند و خلاصه نهایی ۳۲ بایتی را برمی‌گرداند:

>>> from hashlib import blake2b
>>>
>>> FANOUT = 2
>>> DEPTH = 2
>>> LEAF_SIZE = 4096
>>> INNER_SIZE = 64
>>>
>>> buf = bytearray(6000)
>>>
>>> # Left leaf
... h00 = blake2b(buf[0:LEAF_SIZE], fanout=FANOUT, depth=DEPTH,
...               leaf_size=LEAF_SIZE, inner_size=INNER_SIZE,
...               node_offset=0, node_depth=0, last_node=False)
>>> # Right leaf
... h01 = blake2b(buf[LEAF_SIZE:], fanout=FANOUT, depth=DEPTH,
...               leaf_size=LEAF_SIZE, inner_size=INNER_SIZE,
...               node_offset=1, node_depth=0, last_node=True)
>>> # Root node
... h10 = blake2b(digest_size=32, fanout=FANOUT, depth=DEPTH,
...               leaf_size=LEAF_SIZE, inner_size=INNER_SIZE,
...               node_offset=0, node_depth=1, last_node=True)
>>> h10.update(h00.digest())
>>> h10.update(h01.digest())
>>> h10.hexdigest()
'3ad2a9b37c6070e374c7a8c508fe20ca86b6ed54e286e93a0318e95e881db5aa'

دست‌اندرکاران

BLAKE2 توسط Jean-Philippe Aumasson، Samuel Neves، Zooko Wilcox-O'Hearn و Christian Winnerlein بر اساس BLAKE، فینالیست SHA-3، که توسط Jean-Philippe Aumasson، Luca Henzen، Willi Meier و Raphael C.-W. Phan ایجاد شده بود، طراحی شد.

این از الگوریتم اصلی رمز ChaCha استفاده می‌کند که توسط Daniel J. Bernstein طراحی شده است.

پیاده‌سازی کتابخانه‌ی استاندارد بر اساس ماژول pyblake2 است. این پیاده‌سازی توسط Dmitry Chestnykh و بر اساس پیاده‌سازی C نوشته‌شده توسط Samuel Neves نوشته شده است. مستندات از pyblake2 کپی شده و توسط Dmitry Chestnykh نوشته شده است.

کد C تا حدی برای پایتون توسط Christian Heimes بازنویسی شد.

وقف‌نامه‌ی مالکیت عمومی زیر شامل پیاده‌سازی تابع هش C، کد توسعه، و این مستندات می‌شود:

تا حد امکان طبق قانون، نویسنده(ها) تمامی حق نشر و حقوق مرتبط و همسایه مربوط به این نرم‌افزار را به حوزه عمومی در سراسر جهان اختصاص داده‌اند. این نرم‌افزار بدون هیچ‌گونه ضمانتی توزیع می‌شود.

شما باید نسخه‌ای از CC0 Public Domain Dedication را به‌همراه این نرم‌افزار دریافت کرده باشید. در غیر این صورت، https://creativecommons.org/publicdomain/zero/1.0/ را ببینید.

افراد زیر در توسعه کمک کرده‌اند یا تغییرات خود را به پروژه و مالکیت عمومی، مطابق با Creative Commons Public Domain Dedication 1.0 Universal، اهدا کرده‌اند:

  • Alexandr Sokolovskiy

همچنین ملاحظه نمائید

ماژول hmac

ماژولی برای تولید کدهای اصالت‌سنجی پیام با استفاده از هش‌ها.

ماژول base64

راهی دیگر برای کدگذاری هش‌های دودویی برای محیط‌های غیردودویی.

https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.180-4.pdf

انتشاریه FIPS 180-4 درباره الگوریتم‌های هش امن (Secure Hash Algorithms).

https://csrc.nist.gov/pubs/fips/202/final

انتشاریه FIPS 202 درباره‌ی استاندارد SHA-3.

https://www.blake2.net/

وب‌سایت رسمی BLAKE2.

https://fa.wikipedia.org/wiki/تابع_هش_رمزنگاری

مقاله‌ی ویکی‌پدیا حاوی اطلاعاتی درباره‌ی این‌که کدام الگوریتم‌ها مشکلات شناخته‌شده دارند و این موضوع چه معنایی برای استفاده از آن‌ها دارد.

https://www.ietf.org/rfc/rfc8018.txt

PKCS #5: مشخصات رمزنگاری مبتنی بر گذرواژه نسخه 2.1

https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-132.pdf

توصیه‌ی NIST برای اشتقاق کلید مبتنی بر گذرواژه.