peps/pep-0452/index.html

367 lines
23 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="color-scheme" content="light dark">
<title>PEP 452 API for Cryptographic Hash Functions v2.0 | peps.python.org</title>
<link rel="shortcut icon" href="../_static/py.png">
<link rel="canonical" href="https://peps.python.org/pep-0452/">
<link rel="stylesheet" href="../_static/style.css" type="text/css">
<link rel="stylesheet" href="../_static/mq.css" type="text/css">
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" media="(prefers-color-scheme: light)" id="pyg-light">
<link rel="stylesheet" href="../_static/pygments_dark.css" type="text/css" media="(prefers-color-scheme: dark)" id="pyg-dark">
<link rel="alternate" type="application/rss+xml" title="Latest PEPs" href="https://peps.python.org/peps.rss">
<meta property="og:title" content='PEP 452 API for Cryptographic Hash Functions v2.0 | peps.python.org'>
<meta property="og:type" content="website">
<meta property="og:url" content="https://peps.python.org/pep-0452/">
<meta property="og:site_name" content="Python Enhancement Proposals (PEPs)">
<meta property="og:image" content="https://peps.python.org/_static/og-image.png">
<meta property="og:image:alt" content="Python PEPs">
<meta property="og:image:width" content="200">
<meta property="og:image:height" content="200">
<meta name="description" content="Python Enhancement Proposals (PEPs)">
<meta name="theme-color" content="#3776ab">
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
<symbol id="svg-sun-half" viewBox="0 0 24 24" pointer-events="all">
<title>Following system colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="9"></circle>
<path d="M12 3v18m0-12l4.65-4.65M12 14.3l7.37-7.37M12 19.6l8.85-8.85"></path>
</svg>
</symbol>
<symbol id="svg-moon" viewBox="0 0 24 24" pointer-events="all">
<title>Selected dark colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"></path>
</svg>
</symbol>
<symbol id="svg-sun" viewBox="0 0 24 24" pointer-events="all">
<title>Selected light colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="5"></circle>
<line x1="12" y1="1" x2="12" y2="3"></line>
<line x1="12" y1="21" x2="12" y2="23"></line>
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
<line x1="1" y1="12" x2="3" y2="12"></line>
<line x1="21" y1="12" x2="23" y2="12"></line>
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
</svg>
</symbol>
</svg>
<script>
document.documentElement.dataset.colour_scheme = localStorage.getItem("colour_scheme") || "auto"
</script>
<section id="pep-page-section">
<header>
<h1>Python Enhancement Proposals</h1>
<ul class="breadcrumbs">
<li><a href="https://www.python.org/" title="The Python Programming Language">Python</a> &raquo; </li>
<li><a href="../pep-0000/">PEP Index</a> &raquo; </li>
<li>PEP 452</li>
</ul>
<button id="colour-scheme-cycler" onClick="setColourScheme(nextColourScheme())">
<svg aria-hidden="true" class="colour-scheme-icon-when-auto"><use href="#svg-sun-half"></use></svg>
<svg aria-hidden="true" class="colour-scheme-icon-when-dark"><use href="#svg-moon"></use></svg>
<svg aria-hidden="true" class="colour-scheme-icon-when-light"><use href="#svg-sun"></use></svg>
<span class="visually-hidden">Toggle light / dark / auto colour theme</span>
</button>
</header>
<article>
<section id="pep-content">
<h1 class="page-title">PEP 452 API for Cryptographic Hash Functions v2.0</h1>
<dl class="rfc2822 field-list simple">
<dt class="field-odd">Author<span class="colon">:</span></dt>
<dd class="field-odd">A.M. Kuchling &lt;amk&#32;&#97;t&#32;amk.ca&gt;, Christian Heimes &lt;christian&#32;&#97;t&#32;python.org&gt;</dd>
<dt class="field-even">Status<span class="colon">:</span></dt>
<dd class="field-even"><abbr title="Accepted and implementation complete, or no longer active">Final</abbr></dd>
<dt class="field-odd">Type<span class="colon">:</span></dt>
<dd class="field-odd"><abbr title="Non-normative PEP containing background, guidelines or other information relevant to the Python ecosystem">Informational</abbr></dd>
<dt class="field-even">Created<span class="colon">:</span></dt>
<dd class="field-even">15-Aug-2013</dd>
<dt class="field-odd">Post-History<span class="colon">:</span></dt>
<dd class="field-odd"><p></p></dd>
<dt class="field-even">Replaces<span class="colon">:</span></dt>
<dd class="field-even"><a class="reference external" href="../pep-0247/">247</a></dd>
</dl>
<hr class="docutils" />
<section id="contents">
<details><summary>Table of Contents</summary><ul class="simple">
<li><a class="reference internal" href="#abstract">Abstract</a></li>
<li><a class="reference internal" href="#specification">Specification</a></li>
<li><a class="reference internal" href="#rationale">Rationale</a></li>
<li><a class="reference internal" href="#changes-from-version-1-0-to-version-2-0">Changes from Version 1.0 to Version 2.0</a></li>
<li><a class="reference internal" href="#recommended-names-for-common-hashing-algorithms">Recommended names for common hashing algorithms</a></li>
<li><a class="reference internal" href="#changes">Changes</a></li>
<li><a class="reference internal" href="#acknowledgements">Acknowledgements</a></li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
</ul>
</details></section>
<section id="abstract">
<h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2>
<p>There are several different modules available that implement
cryptographic hashing algorithms such as MD5 or SHA. This
document specifies a standard API for such algorithms, to make it
easier to switch between different implementations.</p>
</section>
<section id="specification">
<h2><a class="toc-backref" href="#specification" role="doc-backlink">Specification</a></h2>
<p>All hashing modules should present the same interface. Additional
methods or variables can be added, but those described in this
document should always be present.</p>
<p>Hash function modules define one function:</p>
<p><code class="docutils literal notranslate"><span class="pre">new([string])</span>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span class="pre">(unkeyed</span> <span class="pre">hashes)</span></code></p>
<dl>
<dt><code class="docutils literal notranslate"><span class="pre">new(key,</span> <span class="pre">[string],</span> <span class="pre">[digestmod])</span>&#160;&#160;&#160; <span class="pre">(keyed</span> <span class="pre">hashes)</span></code></dt><dd>Create a new hashing object and return it. The first form is
for hashes that are unkeyed, such as MD5 or SHA. For keyed
hashes such as HMAC, key is a required parameter containing
a string giving the key to use. In both cases, the optional
string parameter, if supplied, will be immediately hashed
into the objects starting state, as if <code class="docutils literal notranslate"><span class="pre">obj.update(string)</span></code> was
called.<p>After creating a hashing object, arbitrary bytes can be fed
into the object using its <code class="docutils literal notranslate"><span class="pre">update()</span></code> method, and the hash value
can be obtained at any time by calling the objects <code class="docutils literal notranslate"><span class="pre">digest()</span></code>
method.</p>
<p>Although the parameter is called string, hashing objects operate
on 8-bit data only. Both key and string must be a bytes-like
object (bytes, bytearray…). A hashing object may support
one-dimensional, contiguous buffers as argument, too. Text
(unicode) is no longer supported in Python 3.x. Python 2.x
implementations may take ASCII-only unicode as argument, but
portable code should not rely on the feature.</p>
<p>Arbitrary additional keyword arguments can be added to this
function, but if theyre not supplied, sensible default values
should be used. For example, rounds and digest_size
keywords could be added for a hash function which supports a
variable number of rounds and several different output sizes,
and they should default to values believed to be secure.</p>
</dd>
</dl>
<p>Hash function modules define one variable:</p>
<dl class="simple">
<dt><code class="docutils literal notranslate"><span class="pre">digest_size</span></code></dt><dd>An integer value; the size of the digest produced by the
hashing objects created by this module, measured in bytes.
You could also obtain this value by creating a sample object
and accessing its digest_size attribute, but it can be
convenient to have this value available from the module.
Hashes with a variable output size will set this variable to
None.</dd>
</dl>
<p>Hashing objects require the following attribute:</p>
<dl class="simple">
<dt><code class="docutils literal notranslate"><span class="pre">digest_size</span></code></dt><dd>This attribute is identical to the module-level digest_size
variable, measuring the size of the digest produced by the
hashing object, measured in bytes. If the hash has a variable
output size, this output size must be chosen when the hashing
object is created, and this attribute must contain the
selected size. Therefore, <code class="docutils literal notranslate"><span class="pre">None</span></code> is <strong>not</strong> a legal value for this
attribute.</dd>
<dt><code class="docutils literal notranslate"><span class="pre">block_size</span></code></dt><dd>An integer value or <code class="docutils literal notranslate"><span class="pre">NotImplemented</span></code>; the internal block size
of the hash algorithm in bytes. The block size is used by the
HMAC module to pad the secret key to <code class="docutils literal notranslate"><span class="pre">digest_size</span></code> or to hash the
secret key if it is longer than <code class="docutils literal notranslate"><span class="pre">digest_size</span></code>. If no HMAC
algorithm is standardized for the hash algorithm, return
<code class="docutils literal notranslate"><span class="pre">NotImplemented</span></code> instead.</dd>
<dt><code class="docutils literal notranslate"><span class="pre">name</span></code></dt><dd>A text string value; the canonical, lowercase name of the hashing
algorithm. The name should be a suitable parameter for
<code class="docutils literal notranslate"><span class="pre">hashlib.new</span></code>.</dd>
</dl>
<p>Hashing objects require the following methods:</p>
<dl class="simple">
<dt><code class="docutils literal notranslate"><span class="pre">copy()</span></code></dt><dd>Return a separate copy of this hashing object. An update to
this copy wont affect the original object.</dd>
<dt><code class="docutils literal notranslate"><span class="pre">digest()</span></code></dt><dd>Return the hash value of this hashing object as a bytes
containing 8-bit data. The object is not altered in any way
by this function; you can continue updating the object after
calling this function.</dd>
<dt><code class="docutils literal notranslate"><span class="pre">hexdigest()</span></code></dt><dd>Return the hash value of this hashing object as a string
containing hexadecimal digits. Lowercase letters should be used
for the digits a through f. Like the <code class="docutils literal notranslate"><span class="pre">.digest()</span></code> method, this
method mustnt alter the object.</dd>
<dt><code class="docutils literal notranslate"><span class="pre">update(string)</span></code></dt><dd>Hash bytes-like string into the current state of the hashing
object. <code class="docutils literal notranslate"><span class="pre">update()</span></code> can be called any number of times during a
hashing objects lifetime.</dd>
</dl>
<p>Hashing modules can define additional module-level functions or
object methods and still be compliant with this specification.</p>
<p>Heres an example, using a module named MD5:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">hashlib</span>
<span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">Crypto.Hash</span> <span class="kn">import</span> <span class="n">MD5</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">m</span> <span class="o">=</span> <span class="n">MD5</span><span class="o">.</span><span class="n">new</span><span class="p">()</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">isinstance</span><span class="p">(</span><span class="n">m</span><span class="p">,</span> <span class="n">hashlib</span><span class="o">.</span><span class="n">CryptoHash</span><span class="p">)</span>
<span class="go">True</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">m</span><span class="o">.</span><span class="n">name</span>
<span class="go">&#39;md5&#39;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">m</span><span class="o">.</span><span class="n">digest_size</span>
<span class="go">16</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">m</span><span class="o">.</span><span class="n">block_size</span>
<span class="go">64</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">m</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="sa">b</span><span class="s1">&#39;abc&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">m</span><span class="o">.</span><span class="n">digest</span><span class="p">()</span>
<span class="go">b&#39;\x90\x01P\x98&lt;\xd2O\xb0\xd6\x96?}(\xe1\x7fr&#39;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">m</span><span class="o">.</span><span class="n">hexdigest</span><span class="p">()</span>
<span class="go">&#39;900150983cd24fb0d6963f7d28e17f72&#39;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">MD5</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="sa">b</span><span class="s1">&#39;abc&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">digest</span><span class="p">()</span>
<span class="go">b&#39;\x90\x01P\x98&lt;\xd2O\xb0\xd6\x96?}(\xe1\x7fr&#39;</span>
</pre></div>
</div>
</section>
<section id="rationale">
<h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2>
<p>The digest size is measured in bytes, not bits, even though hash
algorithm sizes are usually quoted in bits; MD5 is a 128-bit
algorithm and not a 16-byte one, for example. This is because, in
the sample code I looked at, the length in bytes is often needed
(to seek ahead or behind in a file; to compute the length of an
output string) while the length in bits is rarely used.
Therefore, the burden will fall on the few people actually needing
the size in bits, who will have to multiply digest_size by 8.</p>
<p>Its been suggested that the <code class="docutils literal notranslate"><span class="pre">update()</span></code> method would be better named
<code class="docutils literal notranslate"><span class="pre">append()</span></code>. However, that method is really causing the current
state of the hashing object to be updated, and <code class="docutils literal notranslate"><span class="pre">update()</span></code> is already
used by the md5 and sha modules included with Python, so it seems
simplest to leave the name <code class="docutils literal notranslate"><span class="pre">update()</span></code> alone.</p>
<p>The order of the constructors arguments for keyed hashes was a
sticky issue. It wasnt clear whether the key should come first
or second. Its a required parameter, and the usual convention is
to place required parameters first, but that also means that the
string parameter moves from the first position to the second.
It would be possible to get confused and pass a single argument to
a keyed hash, thinking that youre passing an initial string to an
unkeyed hash, but it doesnt seem worth making the interface
for keyed hashes more obscure to avoid this potential error.</p>
</section>
<section id="changes-from-version-1-0-to-version-2-0">
<h2><a class="toc-backref" href="#changes-from-version-1-0-to-version-2-0" role="doc-backlink">Changes from Version 1.0 to Version 2.0</a></h2>
<p>Version 2.0 of API for Cryptographic Hash Functions clarifies some
aspects of the API and brings it up-to-date. It also formalized aspects
that were already de facto standards and provided by most
implementations.</p>
<p>Version 2.0 introduces the following new attributes:</p>
<dl class="simple">
<dt><code class="docutils literal notranslate"><span class="pre">name</span></code></dt><dd>The name property was made mandatory by <a class="reference external" href="http://bugs.python.org/issue18532">issue 18532</a>.</dd>
<dt><code class="docutils literal notranslate"><span class="pre">block_size</span></code></dt><dd>The new version also specifies that the return value
<code class="docutils literal notranslate"><span class="pre">NotImplemented</span></code> prevents HMAC support.</dd>
</dl>
<p>Version 2.0 takes the separation of binary and text data in Python
3.0 into account. The string argument to <code class="docutils literal notranslate"><span class="pre">new()</span></code> and <code class="docutils literal notranslate"><span class="pre">update()</span></code> as
well as the key argument must be bytes-like objects. On Python
2.x a hashing object may also support ASCII-only unicode. The actual
name of argument is not changed as it is part of the public API.
Code may depend on the fact that the argument is called string.</p>
</section>
<section id="recommended-names-for-common-hashing-algorithms">
<h2><a class="toc-backref" href="#recommended-names-for-common-hashing-algorithms" role="doc-backlink">Recommended names for common hashing algorithms</a></h2>
<table class="docutils align-default">
<thead>
<tr class="row-odd"><th class="head">algorithm</th>
<th class="head">variant</th>
<th class="head">recommended name</th>
</tr>
</thead>
<tbody>
<tr class="row-even"><td>MD5</td>
<td></td>
<td>md5</td>
</tr>
<tr class="row-odd"><td>RIPEMD-160</td>
<td></td>
<td>ripemd160</td>
</tr>
<tr class="row-even"><td>SHA-1</td>
<td></td>
<td>sha1</td>
</tr>
<tr class="row-odd"><td rowspan="4">SHA-2</td>
<td>SHA-224</td>
<td>sha224</td>
</tr>
<tr class="row-even"><td>SHA-256</td>
<td>sha256</td>
</tr>
<tr class="row-odd"><td>SHA-384</td>
<td>sha384</td>
</tr>
<tr class="row-even"><td>SHA-512</td>
<td>sha512</td>
</tr>
<tr class="row-odd"><td rowspan="4">SHA-3</td>
<td>SHA-3-224</td>
<td>sha3_224</td>
</tr>
<tr class="row-even"><td>SHA-3-256</td>
<td>sha3_256</td>
</tr>
<tr class="row-odd"><td>SHA-3-384</td>
<td>sha3_384</td>
</tr>
<tr class="row-even"><td>SHA-3-512</td>
<td>sha3_512</td>
</tr>
<tr class="row-odd"><td>WHIRLPOOL</td>
<td></td>
<td>whirlpool</td>
</tr>
</tbody>
</table>
</section>
<section id="changes">
<h2><a class="toc-backref" href="#changes" role="doc-backlink">Changes</a></h2>
<ul class="simple">
<li>2001-09-17: Renamed <code class="docutils literal notranslate"><span class="pre">clear()</span></code> to <code class="docutils literal notranslate"><span class="pre">reset()</span></code>; added <code class="docutils literal notranslate"><span class="pre">digest_size</span></code> attribute
to objects; added <code class="docutils literal notranslate"><span class="pre">.hexdigest()</span></code> method.</li>
<li>2001-09-20: Removed <code class="docutils literal notranslate"><span class="pre">reset()</span></code> method completely.</li>
<li>2001-09-28: Set <code class="docutils literal notranslate"><span class="pre">digest_size</span></code> to <code class="docutils literal notranslate"><span class="pre">None</span></code> for variable-size hashes.</li>
<li>2013-08-15: Added <code class="docutils literal notranslate"><span class="pre">block_size</span></code> and <code class="docutils literal notranslate"><span class="pre">name</span></code> attributes; clarified that
string actually refers to bytes-like objects.</li>
</ul>
</section>
<section id="acknowledgements">
<h2><a class="toc-backref" href="#acknowledgements" role="doc-backlink">Acknowledgements</a></h2>
<p>Thanks to Aahz, Andrew Archibald, Rich Salz, Itamar
Shtull-Trauring, and the readers of the python-crypto list for
their comments on this PEP.</p>
</section>
<section id="copyright">
<h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2>
<p>This document has been placed in the public domain.</p>
</section>
</section>
<hr class="docutils" />
<p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0452.rst">https://github.com/python/peps/blob/main/peps/pep-0452.rst</a></p>
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0452.rst">2023-09-09 17:39:29 GMT</a></p>
</article>
<nav id="pep-sidebar">
<h2>Contents</h2>
<ul>
<li><a class="reference internal" href="#abstract">Abstract</a></li>
<li><a class="reference internal" href="#specification">Specification</a></li>
<li><a class="reference internal" href="#rationale">Rationale</a></li>
<li><a class="reference internal" href="#changes-from-version-1-0-to-version-2-0">Changes from Version 1.0 to Version 2.0</a></li>
<li><a class="reference internal" href="#recommended-names-for-common-hashing-algorithms">Recommended names for common hashing algorithms</a></li>
<li><a class="reference internal" href="#changes">Changes</a></li>
<li><a class="reference internal" href="#acknowledgements">Acknowledgements</a></li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
</ul>
<br>
<a id="source" href="https://github.com/python/peps/blob/main/peps/pep-0452.rst">Page Source (GitHub)</a>
</nav>
</section>
<script src="../_static/colour_scheme.js"></script>
<script src="../_static/wrap_tables.js"></script>
<script src="../_static/sticky_banner.js"></script>
</body>
</html>