hashlib --- Băm an toàn và tóm tắt tin nhắn

Source code: Lib/hashlib.py


Mô-đun này triển khai một giao diện chung cho nhiều thuật toán băm khác nhau. Bao gồm các thuật toán băm an toàn FIPS SHA224, SHA256, SHA384, SHA512, (được xác định trong the FIPS 180-4 standard), chuỗi SHA-3 (được xác định trong the FIPS 202 standard) cũng như các thuật toán cũ SHA1 (formerly part of FIPS) và thuật toán MD5 (được xác định trong internet RFC 1321).

Ghi chú

Nếu bạn muốn các hàm băm adler32 hoặc crc32, chúng có sẵn trong mô-đun zlib.

Thuật toán băm

Có một phương thức khởi tạo được đặt tên cho từng loại hash. Tất cả đều trả về một đối tượng băm có cùng giao diện đơn giản. Ví dụ: sử dụng sha256() để tạo đối tượng băm SHA-256. Bây giờ bạn có thể cung cấp đối tượng này bằng bytes-like objects (thường là bytes) bằng phương thức update. Tại bất kỳ thời điểm nào, bạn có thể yêu cầu nó cung cấp digest về việc nối dữ liệu được cung cấp cho nó cho đến nay bằng cách sử dụng các phương thức digest() hoặc hexdigest().

Để cho phép đa luồng, GIL Python được phát hành trong khi tính toán hàm băm cung cấp hơn 2047 byte dữ liệu cùng một lúc trong hàm tạo hoặc phương thức .update của nó.

Các hàm tạo cho thuật toán băm luôn có trong mô-đun này là sha1(), sha224(), sha256(), sha384(), sha512(), sha3_224(), sha3_256(), sha3_384(), sha3_512(), shake_128(), shake_256(), blake2b()blake2s(). md5() thường có sẵn, mặc dù nó có thể bị thiếu hoặc bị chặn nếu bạn đang sử dụng bản dựng Python "tuân thủ FIPS" hiếm có. Chúng tương ứng với algorithms_guaranteed.

Các thuật toán bổ sung cũng có thể khả dụng nếu hashlib của bản phân phối Python của bạn được liên kết với bản dựng OpenSSL do các bản phân phối khác cung cấp. Những người khác are not guaranteed available trên tất cả các cài đặt và sẽ chỉ có thể truy cập được bằng tên qua new(). Xem algorithms_available.

Cảnh báo

Một số thuật toán đã biết điểm yếu của va chạm băm (bao gồm MD5 và SHA1). Tham khảo phần Attacks on cryptographic hash algorithmshashlib-seealso ở cuối tài liệu này.

Added in version 3.6: Các hàm tạo SHA3 (Keccak) và SHAKE sha3_224(), sha3_256(), sha3_384(), sha3_512(), shake_128(), shake_256() đã được thêm vào. blake2b()blake2s() đã được thêm vào.

Thay đổi trong phiên bản 3.9: Tất cả các hàm tạo hashlib đều lấy đối số chỉ từ khóa usedforsecurity với giá trị mặc định True. Giá trị sai cho phép sử dụng thuật toán băm không an toàn và bị chặn trong môi trường bị hạn chế. False chỉ ra rằng thuật toán băm không được sử dụng trong bối cảnh bảo mật, ví dụ: như một chức năng nén một chiều không mật mã.

Thay đổi trong phiên bản 3.9: Hashlib hiện sử dụng SHA3 và SHAKE từ OpenSSL nếu nó cung cấp.

Thay đổi trong phiên bản 3.12: Đối với bất kỳ thuật toán MD5, SHA1, SHA2 hoặc SHA3 nào mà OpenSSL được liên kết không cung cấp, chúng tôi sẽ quay lại triển khai đã được xác minh từ HACL* project.

Cách sử dụng

Để có được bản tóm tắt của chuỗi byte b"Nobody inspects the spammish repetition":

>>> nhập hashlib
>>> m = hashlib.sha256()
>>> m.update(b"Không ai kiểm tra")
>>> m.update(b" sự lặp lại spam")
>>> 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'

Cô đọng hơn:

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

nhà xây dựng

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

Là một hàm tạo chung lấy chuỗi name của thuật toán mong muốn làm tham số đầu tiên. Nó cũng tồn tại để cho phép truy cập vào các hàm băm được liệt kê ở trên cũng như bất kỳ thuật toán nào khác mà thư viện OpenSSL của bạn có thể cung cấp.

Sử dụng new() với tên thuật toán:

>>> 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)

Các hàm tạo được đặt tên như thế này nhanh hơn việc chuyển tên thuật toán tới new().

Thuộc tính

Hashlib cung cấp các thuộc tính mô-đun không đổi sau:

hashlib.algorithms_guaranteed

Một bộ chứa tên của các thuật toán băm được đảm bảo sẽ được mô-đun này hỗ trợ trên tất cả các nền tảng. Lưu ý rằng 'md5' nằm trong danh sách này mặc dù một số nhà cung cấp thượng nguồn cung cấp bản dựng Python "tuân thủ FIPS" kỳ lạ loại trừ nó.

Added in version 3.2.

hashlib.algorithms_available

Một tập hợp chứa tên của các thuật toán băm có sẵn trong trình thông dịch Python đang chạy. Những tên này sẽ được nhận dạng khi được chuyển tới new(). algorithms_guaranteed sẽ luôn là một tập hợp con. Thuật toán tương tự có thể xuất hiện nhiều lần trong bộ này dưới các tên khác nhau (nhờ OpenSSL).

Added in version 3.2.

Đối tượng băm

Các giá trị sau được cung cấp dưới dạng thuộc tính không đổi của đối tượng băm được hàm tạo trả về:

hash.digest_size

Kích thước của hàm băm kết quả tính bằng byte.

hash.block_size

Kích thước khối bên trong của thuật toán băm tính bằng byte.

Một đối tượng băm có các thuộc tính sau:

hash.name

Tên chuẩn của hàm băm này, luôn viết thường và luôn phù hợp làm tham số cho new() để tạo một hàm băm khác thuộc loại này.

Thay đổi trong phiên bản 3.4: Thuộc tính tên đã có trong CPython kể từ khi nó ra đời, nhưng cho đến khi Python 3.4 chưa được chỉ định chính thức, do đó có thể không tồn tại trên một số nền tảng.

Một đối tượng băm có các phương thức sau:

hash.update(data)

Cập nhật đối tượng băm bằng bytes-like object. Các cuộc gọi lặp lại tương đương với một cuộc gọi duy nhất có sự kết hợp của tất cả các đối số: m.update(a); m.update(b) tương đương với m.update(a+b).

hash.digest()

Trả về bản tóm tắt dữ liệu được truyền cho phương thức update() cho đến nay. Đây là đối tượng byte có kích thước digest_size có thể chứa byte trong toàn bộ phạm vi từ 0 đến 255.

hash.hexdigest()

Giống như digest() ngoại trừ thông báo được trả về dưới dạng đối tượng chuỗi có độ dài gấp đôi, chỉ chứa các chữ số thập lục phân. Điều này có thể được sử dụng để trao đổi giá trị một cách an toàn trong email hoặc các môi trường phi nhị phân khác.

hash.copy()

Trả về một bản sao ("bản sao") của đối tượng băm. Điều này có thể được sử dụng để tính toán hiệu quả các bản tóm tắt dữ liệu chia sẻ một chuỗi con ban đầu chung.

SHAKE thông báo có độ dài thay đổi

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

Thuật toán shake_128()shake_256() cung cấp các bản tóm tắt có độ dài thay đổi với độ dài_in_bits//2 lên đến 128 hoặc 256 bit bảo mật. Như vậy, phương pháp tiêu hóa của họ yêu cầu độ dài. Độ dài tối đa không bị giới hạn bởi thuật toán SHAKE.

shake.digest(length)

Trả về bản tóm tắt dữ liệu được truyền cho phương thức update() cho đến nay. Đây là đối tượng byte có kích thước length có thể chứa byte trong toàn bộ phạm vi từ 0 đến 255.

shake.hexdigest(length)

Giống như digest() ngoại trừ thông báo được trả về dưới dạng đối tượng chuỗi có độ dài gấp đôi, chỉ chứa các chữ số thập lục phân. Điều này có thể được sử dụng để trao đổi giá trị trong email hoặc các môi trường phi nhị phân khác.

Ví dụ sử dụng:

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

Băm tập tin

Mô-đun hashlib cung cấp chức năng trợ giúp để băm hiệu quả một tệp hoặc đối tượng giống tệp.

hashlib.file_digest(fileobj, digest, /)

Trả về một đối tượng thông báo đã được cập nhật với nội dung của đối tượng tệp.

fileobj phải là một đối tượng giống như tệp được mở để đọc ở chế độ nhị phân. Nó chấp nhận các đối tượng tệp từ các phiên bản open(), BytesIO dựng sẵn, các đối tượng SocketIO từ socket.socket.makefile(), v.v. fileobj phải được mở ở chế độ chặn, nếu không BlockingIOError có thể được nâng lên.

Hàm này có thể bỏ qua I/O của Python và sử dụng trực tiếp bộ mô tả tệp từ fileno(). fileobj phải được coi là ở trạng thái không xác định sau khi hàm này trả về hoặc tăng lên. Người gọi có quyền đóng fileobj.

digest phải là tên thuật toán băm dưới dạng str, hàm tạo băm hoặc có thể gọi được để trả về đối tượng băm.

Ví dụ:

>>> 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

Added in version 3.11.

Thay đổi trong phiên bản 3.14: Bây giờ sẽ tăng BlockingIOError nếu tệp được mở ở chế độ không chặn. Trước đây, các byte rỗng giả đã được thêm vào bản tóm tắt.

Đạo hàm chính

Thuật toán dẫn xuất khóa và kéo dài khóa được thiết kế để băm mật khẩu an toàn. Các thuật toán ngây thơ như sha1(password) không có khả năng chống lại các cuộc tấn công vũ phu. Chức năng băm mật khẩu tốt phải có thể điều chỉnh được, chậm và bao gồm salt.

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

Hàm này cung cấp hàm dẫn xuất khóa dựa trên mật khẩu PKCS#5 2. Nó sử dụng HMAC làm hàm giả ngẫu nhiên.

Chuỗi hash_name là tên mong muốn của thuật toán phân loại băm cho HMAC, ví dụ: 'sha1' hoặc 'sha256'. passwordsalt được hiểu là bộ đệm byte. Các ứng dụng và thư viện nên giới hạn password ở độ dài hợp lý (ví dụ: 1024). salt phải có khoảng 16 byte trở lên từ một nguồn thích hợp, ví dụ: os.urandom().

Số lượng iterations nên được chọn dựa trên thuật toán băm và khả năng tính toán. Tính đến năm 2022, hàng trăm nghìn lần lặp lại SHA-256 đã được đề xuất. Để biết lý do tại sao và cách chọn những gì tốt nhất cho ứng dụng của bạn, hãy đọc Appendix A.2.2 của NIST-SP-800-132. Các câu trả lời trên stackexchange pbkdf2 iterations question đều giải thích chi tiết.

dklen là độ dài của khóa dẫn xuất tính bằng byte. Nếu dklenNone thì kích thước tóm tắt của thuật toán băm hash_name sẽ được sử dụng, ví dụ: 64 cho 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'

Chức năng chỉ khả dụng khi Python được biên dịch bằng OpenSSL.

Added in version 3.4.

Thay đổi trong phiên bản 3.12: Chức năng hiện chỉ khả dụng khi Python được xây dựng bằng OpenSSL. Việc triển khai Python thuần túy chậm đã bị xóa.

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

Hàm này cung cấp hàm phái sinh khóa dựa trên mật khẩu mã hóa như được xác định trong RFC 7914.

passwordsalt phải là bytes-like objects. Các ứng dụng và thư viện nên giới hạn password ở độ dài hợp lý (ví dụ: 1024). salt phải có khoảng 16 byte trở lên từ một nguồn thích hợp, ví dụ: os.urandom().

n là hệ số chi phí CPU/Bộ nhớ, r kích thước khối, hệ số song song pmaxmem giới hạn bộ nhớ (OpenSSL 1.1.0 mặc định là 32 MiB). dklen là độ dài của khóa dẫn xuất tính bằng byte.

Added in version 3.6.

BLAKE2

BLAKE2 là hàm băm mật mã được xác định trong RFC 7693 và có hai loại:

  • BLAKE2b, được tối ưu hóa cho nền tảng 64 bit và tạo ra các bản tóm tắt có kích thước bất kỳ từ 1 đến 64 byte,

  • BLAKE2s, được tối ưu hóa cho nền tảng 8 đến 32 bit và tạo ra các bản tóm tắt có kích thước bất kỳ từ 1 đến 32 byte.

BLAKE2 hỗ trợ keyed mode (sự thay thế nhanh hơn và đơn giản hơn cho HMAC), salted hashing, personalizationtree hashing.

Các đối tượng băm từ mô-đun này tuân theo API của các đối tượng hashlib của thư viện chuẩn.

Tạo đối tượng băm

Các đối tượng băm mới được tạo bằng cách gọi các hàm tạo:

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)

Các hàm này trả về các đối tượng băm tương ứng để tính toán BLAKE2b hoặc BLAKE2. Họ tùy ý lấy các tham số chung sau:

  • data: đoạn dữ liệu ban đầu cần băm, phải là bytes-like object. Nó chỉ có thể được thông qua dưới dạng đối số vị trí.

  • digest_size: kích thước của thông báo đầu ra tính bằng byte.

  • key: khóa để băm khóa (tối đa 64 byte cho BLAKE2b, tối đa 32 byte cho BLAKE2).

  • salt: muối để băm ngẫu nhiên (tối đa 16 byte cho BLAKE2b, tối đa 8 byte cho BLAKE2).

  • person: chuỗi cá nhân hóa (tối đa 16 byte cho BLAKE2b, tối đa 8 byte cho BLAKE2).

Bảng sau đây hiển thị các giới hạn cho các tham số chung (tính bằng byte):

Băm

kích thước tiêu hóa

len(khóa)

len(muối)

len(người)

BLAKE2b

64

64

16

16

BLAKE2s

32

32

8

8

Ghi chú

Thông số kỹ thuật BLAKE2 xác định độ dài không đổi cho các tham số muối và cá nhân hóa, tuy nhiên, để thuận tiện, việc triển khai này chấp nhận các chuỗi byte có kích thước bất kỳ lên đến độ dài được chỉ định. Nếu độ dài của tham số nhỏ hơn được chỉ định, thì tham số đó sẽ được đệm bằng các số 0, do đó, ví dụ: b'salt'b'salt\x00' có cùng giá trị. (Đây không phải là trường hợp của key.)

Các kích thước này có sẵn dưới dạng mô-đun constants được mô tả bên dưới.

Các hàm xây dựng cũng chấp nhận các tham số băm cây sau:

  • fanout: fanout (0 đến 255, 0 nếu không giới hạn, 1 ở chế độ tuần tự).

  • depth: độ sâu tối đa của cây (1 đến 255, 255 nếu không giới hạn, 1 ở chế độ tuần tự).

  • leaf_size: độ dài byte tối đa của lá (0 đến 2**32-1, 0 nếu không giới hạn hoặc ở chế độ tuần tự).

  • node_offset: độ lệch nút (0 đến 2**64-1 cho BLAKE2b, 0 đến 2**48-1 cho BLAKE2s, 0 cho đầu tiên, ngoài cùng bên trái, lá hoặc ở chế độ tuần tự).

  • node_depth: độ sâu nút (0 đến 255, 0 cho lá hoặc ở chế độ tuần tự).

  • inner_size: kích thước thông báo bên trong (0 đến 64 đối với BLAKE2b, 0 đến 32 đối với BLAKE2s, 0 ở chế độ tuần tự).

  • last_node: boolean cho biết nút được xử lý có phải là nút cuối cùng hay không (False cho chế độ tuần tự).

Giải thích các tham số chế độ cây.

Xem phần 2.10 trong BLAKE2 specification để xem xét toàn diện về băm cây.

Hằng số

blake2b.SALT_SIZE
blake2s.SALT_SIZE

Chiều dài muối (chiều dài tối đa được các nhà xây dựng chấp nhận).

blake2b.PERSON_SIZE
blake2s.PERSON_SIZE

Độ dài chuỗi cá nhân hóa (độ dài tối đa được các nhà xây dựng chấp nhận).

blake2b.MAX_KEY_SIZE
blake2s.MAX_KEY_SIZE

Kích thước khóa tối đa.

blake2b.MAX_DIGEST_SIZE
blake2s.MAX_DIGEST_SIZE

Kích thước tóm tắt tối đa mà hàm băm có thể xuất ra.

Ví dụ

Băm đơn giản

Để tính hàm băm của một số dữ liệu, trước tiên bạn nên xây dựng một đối tượng băm bằng cách gọi hàm xây dựng thích hợp (blake2b() hoặc blake2s()), sau đó cập nhật dữ liệu đó bằng cách gọi update() trên đối tượng và cuối cùng, lấy thông báo ra khỏi đối tượng bằng cách gọi digest() (hoặc hexdigest() cho chuỗi được mã hóa hex).

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

Là một phím tắt, bạn có thể chuyển đoạn dữ liệu đầu tiên để cập nhật trực tiếp cho hàm tạo dưới dạng đối số vị trí:

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

Bạn có thể gọi hash.update() bao nhiêu lần tùy ý để cập nhật hàm băm lặp đi lặp lại:

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

Sử dụng các kích cỡ thông báo khác nhau

BLAKE2 có kích thước thông báo có thể định cấu hình lên tới 64 byte cho BLAKE2b và tối đa 32 byte cho BLAKE2. Ví dụ: để thay thế SHA-1 bằng BLAKE2b mà không thay đổi kích thước đầu ra, chúng ta có thể yêu cầu BLAKE2b tạo ra các bản tóm tắt 20 byte:

>>> 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

Các đối tượng băm có kích thước phân loại khác nhau có kết quả đầu ra hoàn toàn khác nhau (băm ngắn hơn là tiền tố not của băm dài hơn); BLAKE2b và BLAKE2 tạo ra các đầu ra khác nhau ngay cả khi độ dài đầu ra giống nhau:

>>> 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'

Băm có khóa

Băm khóa có thể được sử dụng để xác thực như một sự thay thế nhanh hơn và đơn giản hơn cho Hash-based message authentication code (HMAC). BLAKE2 có thể được sử dụng một cách an toàn ở chế độ prefix-MAC nhờ thuộc tính không phân biệt được kế thừa từ BLAKE.

Ví dụ này cho thấy cách lấy mã xác thực 128-bit (được mã hóa bằng hex) cho tin nhắn b'message data' bằng khóa b'pseudorandom key':

>>> từ nhập hashlib blake2b
>>> h = blake2b(key=b'khóa giả ngẫu nhiên', dig_size=16)
>>> h.update(b'dữ liệu tin nhắn')
>>> h.hexdigest()
'3d363ff7401e02026f4a4687d4863ced'

Ví dụ thực tế, một ứng dụng web có thể ký các cookie được gửi cho người dùng một cách đối xứng và sau đó xác minh chúng để đảm bảo chúng không bị giả mạo:

>>> từ nhập hashlib blake2b
>>> từ nhập khẩu hmac so sánh_digest
>>>
>>> SECRET_KEY = b'khóa bí mật máy chủ được tạo ngẫu nhiên'
>>> AUTH_SIZE = 16
>>>
>>> dấu hiệu def(cookie):
... h = blake2b(digest_size=AUTH_SIZE, key=SECRET_KEY)
... h.update(cookie)
... trả về h.hexdigest().encode('utf-8')
>>>
>>> xác minh chắc chắn(cookie, sig):
... good_sig = dấu hiệu(cookie)
... trả về so sánh_digest(good_sig, sig)
>>>
>>> cookie = b'user-alice'
>>> sig = dấu (cookie)
>>> print("{0},{1}".format(cookie.decode('utf-8'), sig))
người dùng-alice,b'43b3c982cf697e0c5ab22172d1ca7421'
>>> xác minh(cookie, sig)
đúng
>>> xác minh(b'user-bob', sig)
sai
>>> xác minh(cookie, b'0102030405060708090a0b0c0d0e0f00')
sai

Mặc dù có chế độ băm khóa riêng, nhưng BLAKE2 tất nhiên có thể được sử dụng trong cấu trúc HMAC với mô-đun hmac

>>> nhập hmac, hashlib
>>> m = hmac.new(b'khóa bí mật', digmod=hashlib.blake2s)
>>> m.update(b'message')
>>> m.hexdigest()
'e3c8102868d28b5ff85fc35dda07329970d1a01e273c37481326fe0c861c8142'

Băm ngẫu nhiên

Bằng cách đặt tham số salt, người dùng có thể giới thiệu tính năng ngẫu nhiên cho hàm băm. Băm ngẫu nhiên rất hữu ích để bảo vệ chống lại các cuộc tấn công xung đột vào hàm băm được sử dụng trong chữ ký số.

Băm ngẫu nhiên được thiết kế cho các tình huống trong đó một bên, người chuẩn bị tin nhắn, tạo ra tất cả hoặc một phần tin nhắn để được ký bởi bên thứ hai, người ký tin nhắn. Nếu người chuẩn bị tin nhắn có thể tìm thấy xung đột hàm băm mật mã (tức là hai tin nhắn tạo ra cùng một giá trị băm), thì họ có thể chuẩn bị các phiên bản có ý nghĩa của tin nhắn sẽ tạo ra cùng giá trị băm và chữ ký số nhưng có kết quả khác nhau (ví dụ: chuyển 1.000.000 USD vào một tài khoản, thay vì 10 USD). Các hàm băm mật mã đã được thiết kế với mục tiêu chính là chống va chạm, nhưng sự tập trung hiện tại vào việc tấn công các hàm băm mật mã có thể dẫn đến một hàm băm mật mã nhất định cung cấp ít khả năng chống va chạm hơn dự kiến. Băm ngẫu nhiên cung cấp cho người ký sự bảo vệ bổ sung bằng cách giảm khả năng người chuẩn bị có thể tạo ra hai hoặc nhiều thông báo cuối cùng mang lại cùng một giá trị băm trong quá trình tạo chữ ký số --- ngay cả khi việc tìm ra xung đột cho hàm băm là thực tế. Tuy nhiên, việc sử dụng hàm băm ngẫu nhiên có thể làm giảm mức độ bảo mật do chữ ký số cung cấp khi tất cả các phần của thông báo được người ký chuẩn bị.

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

Trong BLAKE2, muối được xử lý dưới dạng đầu vào một lần cho hàm băm trong quá trình khởi tạo, thay vì làm đầu vào cho mỗi hàm nén.

Cảnh báo

Salted hashing (hoặc chỉ băm) bằng BLAKE2 hoặc bất kỳ hàm băm mật mã có mục đích chung nào khác, chẳng hạn như SHA-256, không phù hợp để băm mật khẩu. Xem BLAKE2 FAQ để biết thêm thông tin.

>>> 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

Cá nhân hóa

Đôi khi, việc buộc hàm băm tạo ra các bản tóm tắt khác nhau cho cùng một đầu vào cho các mục đích khác nhau sẽ rất hữu ích. Trích dẫn các tác giả của hàm băm Skein:

Chúng tôi khuyến nghị tất cả các nhà thiết kế ứng dụng nên cân nhắc nghiêm túc việc thực hiện việc này; chúng tôi đã thấy nhiều giao thức trong đó hàm băm được tính toán trong một phần của giao thức có thể được sử dụng ở một phần hoàn toàn khác vì hai phép tính băm được thực hiện trên dữ liệu tương tự hoặc có liên quan và kẻ tấn công có thể buộc ứng dụng tạo ra các đầu vào băm giống nhau. Việc cá nhân hóa từng hàm băm được sử dụng trong giao thức sẽ tạm thời ngăn chặn kiểu tấn công này.

(The Skein Hash Function Family, trang 21)

BLAKE2 có thể được cá nhân hóa bằng cách chuyển byte tới đối số person

>>> từ nhập hashlib blake2b
>>> FILES_HASH_PERSON = b'Băm tệp MyApp'
>>> BLOCK_HASH_PERSON = b'Băm khối MyApp'
>>> h = blake2b(digest_size=32, user=FILES_HASH_PERSON)
>>> h.update(b'cùng nội dung')
>>> h.hexdigest()
'20d9cd024d4fb086aae819a1432dd2466de12947831b75c5a30cf2676095d3b4'
>>> h = blake2b(digest_size=32, user=BLOCK_HASH_PERSON)
>>> h.update(b'cùng nội dung')
>>> h.hexdigest()
'cf68fb5761b9c44e7878bfb2c4c9aea52264a80b75005e65619778de59f383a3'

Việc cá nhân hóa cùng với chế độ khóa cũng có thể được sử dụng để lấy các khóa khác nhau từ một khóa duy nhất.

>>> 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=

Chế độ cây

Dưới đây là ví dụ về việc băm một cây tối thiểu có hai nút lá:

10
 / \
00 01

Ví dụ này sử dụng thông báo nội bộ 64 byte và trả về thông báo cuối cùng 32 byte

>>> từ nhập hashlib blake2b
>>>
>>> FANOUT = 2
>>> DEPTH = 2
>>> LEAF_SIZE = 4096
>>> INNER_SIZE = 64
>>>
>>> buf = bytearray(6000)
>>>
>>>  # Left
... h00 = blake2b(buf[0:LEAF_SIZE], fanout=FANOUT, deep=DEPTH,
... lá_size=LEAF_SIZE, bên trong_size=INNER_SIZE,
... node_offset=0, node_deep=0, Last_node=False)
>>>  # Right
... h01 = blake2b(buf[LEAF_SIZE:], fanout=FANOUT, deep=DEPTH,
... lá_size=LEAF_SIZE, bên trong_size=INNER_SIZE,
... node_offset=1, node_deep=0, Last_node=True)
>>> nút # Root
... h10 = blake2b(digest_size=32, fanout=FANOUT, deep=DEPTH,
... lá_size=LEAF_SIZE, bên trong_size=INNER_SIZE,
... node_offset=0, node_deep=1, Last_node=True)
>>> h10.update(h00.digest())
>>> h10.update(h01.digest())
>>> h10.hexdigest()
'3ad2a9b37c6070e374c7a8c508fe20ca86b6ed54e286e93a0318e95e881db5aa'

Tín dụng

BLAKE2 được thiết kế bởi Jean-Philippe Aumasson, Samuel Neves, Zooko Wilcox-O'HearnChristian Winnerlein dựa trên SHA-3 BLAKE lọt vào vòng chung kết được tạo bởi Jean-Philippe Aumasson, Luca Henzen, Willi MeierRaphael C.-W. Phan.

Nó sử dụng thuật toán cốt lõi từ mật mã ChaCha được thiết kế bởi Daniel J. Bernstein.

Việc triển khai stdlib dựa trên mô-đun pyblake2. Nó được viết bởi Dmitry Chestnykh dựa trên triển khai C được viết bởi Samuel Neves. Tài liệu được sao chép từ pyblake2 và được viết bởi Dmitry Chestnykh.

Mã C được viết lại một phần cho Python bởi Christian Heimes.

Sự cống hiến cho miền công cộng sau đây áp dụng cho cả việc triển khai hàm băm C, mã mở rộng và tài liệu này:

Trong phạm vi có thể theo luật, (các) tác giả đã dành tất cả bản quyền cũng như các quyền liên quan và lân cận đối với phần mềm này cho phạm vi công cộng trên toàn thế giới. Phần mềm này được phân phối mà không có bất kỳ bảo hành nào.

Bạn hẳn đã nhận được một bản sao của Chứng chỉ miền công cộng CC0 cùng với phần mềm này. Nếu không, hãy xem https://creativecommons.org/publicdomain/zero/1.0/.

Những người sau đây đã giúp phát triển hoặc đóng góp những thay đổi của họ cho dự án và phạm vi công cộng theo Cống hiến miền công cộng Creative Commons 1.0 phổ quát:

  • Alexandr Sokolovskiy

Xem thêm

Mô-đun hmac

Một mô-đun để tạo mã xác thực tin nhắn bằng cách sử dụng hàm băm.

Mô-đun base64

Một cách khác để mã hóa băm nhị phân cho môi trường không nhị phân.

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

Ấn phẩm FIPS 180-4 về Thuật toán băm an toàn.

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

Ấn phẩm FIPS 202 trên Tiêu chuẩn SHA-3.

https://www.blake2.net/

Trang web BLAKE2 chính thức.

https://en.wikipedia.org/wiki/Cryptographic_hash_function

Bài viết trên Wikipedia với thông tin về các thuật toán có vấn đề đã biết và điều đó có ý nghĩa gì đối với việc sử dụng chúng.

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

PKCS #5: Đặc tả mật mã dựa trên mật khẩu Phiên bản 2.1

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

NIST Khuyến nghị về dẫn xuất khóa dựa trên mật khẩu.