A mask generation function (MGF) is a cryptographic primitive similar to a cryptographic hash function except that while a hash function's output has a fixed size, a MGF supports output of a variable length. In this respect, a MGF can be viewed as a extendable-output function (XOF): it can accept input of any length and process it to produce output of any length. Mask generation functions are completely deterministic: for any given input and any desired output length the output is always the same.
๐๐ซ๐พ๐ denotes the length in octets of the hash function output)
232(๐๐ซ๐พ๐)
- If 2^{32}(\\mathsf{hLen})"}}'>l>232(๐๐ซ๐พ๐), output "mask too long" and stop.
- Let 0 to C of length C=๐จ๐ค๐ฎ๐ฒ๐ฏ(๐ผ๐๐๐๐๐พ๐,4)
- Concatenate the hash of the seed T:
- T as the octet string mask.
Below is Python code implementing MGF1:
bytes:\n \"\"\"Mask generation function.\"\"\"\n hLen = hash_func().digest_size\n # https://www.ietf.org/rfc/rfc2437.txt\n # 1. If l > 2^32(hLen), output \"mask too long\" and stop.\n if length > (hLen << 32):\n raise ValueError(\"mask too long\")\n # 2. Let T be the empty octet string.\n T = b\"\"\n # 3. For counter from 0 to \\lceil{l / hLen}\\rceil-1, do the following:\n # Note: \\lceil{l / hLen}\\rceil-1 is the number of iterations needed,\n # but it's easier to check if we have reached the desired length.\n counter = 0\n while len(T) < length:\n # a. Convert counter to an octet string C of length 4 with the primitive I2OSP: C = I2OSP (counter, 4)\n C = int.to_bytes(counter, 4, \"big\")\n # b. Concatenate the hash of the seed Z and C to the octet string T: T = T || Hash (Z || C)\n T += hash_func(seed + C).digest()\n counter += 1\n # 4. Output the leading l octets of T as the octet string mask.\n return T[:length]\n"}}'>importhashlib
defmgf1(seed: bytes, length: int, hash_func=hashlib.sha1) -> bytes:
"""Mask generation function."""
hLen = hash_func().digest_size
# https://www.ietf.org/rfc/rfc2437.txt
# 1. If l > 2^32(hLen), output "mask too long" and stop.
if length > (hLen << 32):
raise ValueError("mask too long")
# 2. Let T be the empty octet string.
T = b""
# 3. For counter from 0 to \lceil{l / hLen}\rceil-1, do the following:
# Note: \lceil{l / hLen}\rceil-1 is the number of iterations needed,
# but it's easier to check if we have reached the desired length.
counter = 0
while len(T) < length:
# a. Convert counter to an octet string C of length 4 with the primitive I2OSP: C = I2OSP (counter, 4)
C = int.to_bytes(counter, 4, "big")
# b. Concatenate the hash of the seed Z and C to the octet string T: T = T || Hash (Z || C)
T += hash_func(seed + C).digest()
counter += 1
# 4. Output the leading l octets of T as the octet string mask.
return T[:length]
Example outputs of MGF1:
>> from mgf1 import mgf1\n>>> from hashlib import sha256\n>>> mgf1(b\"foo\", 3).hex()\n'1ac907'\n>>> mgf1(b\"foo\", 5).hex()\n'1ac9075cd4'\n>>> mgf1(b\"bar\", 5).hex()\n'bc0c655e01'\n>>> mgf1(b\"bar\", 50).hex()\n'bc0c655e016bc2931d85a2e675181adcef7f581f76df2739da74faac41627be2f7f415c89e983fd0ce80ced9878641cb4876'\n>>> mgf1(b\"bar\", 50, sha256).hex()\n'382576a7841021cc28fc4c0948753fb8312090cea942ea4c4e735d10dc724b155f9f6069f289d61daca0cb814502ef04eae1'\n"}}'>Python 3.10.4 (main, Apr 16 2022, 16:28:41) [GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> frommgf1import mgf1
>>> fromhashlibimport sha256
>>> mgf1(b"foo", 3).hex()
'1ac907'
>>> mgf1(b"foo", 5).hex()
'1ac9075cd4'
>>> mgf1(b"bar", 5).hex()
'bc0c655e01'
>>> mgf1(b"bar", 50).hex()
'bc0c655e016bc2931d85a2e675181adcef7f581f76df2739da74faac41627be2f7f415c89e983fd0ce80ced9878641cb4876'
>>> mgf1(b"bar", 50, sha256).hex()
'382576a7841021cc28fc4c0948753fb8312090cea942ea4c4e735d10dc724b155f9f6069f289d61daca0cb814502ef04eae1'