<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.visual-prolog.com/index.php?action=history&amp;feed=atom&amp;title=Password_Hashing</id>
	<title>Password Hashing - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.visual-prolog.com/index.php?action=history&amp;feed=atom&amp;title=Password_Hashing"/>
	<link rel="alternate" type="text/html" href="https://wiki.visual-prolog.com/index.php?title=Password_Hashing&amp;action=history"/>
	<updated>2026-04-11T20:28:39Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.37.1</generator>
	<entry>
		<id>https://wiki.visual-prolog.com/index.php?title=Password_Hashing&amp;diff=4607&amp;oldid=prev</id>
		<title>Thomas Linder Puls: release</title>
		<link rel="alternate" type="text/html" href="https://wiki.visual-prolog.com/index.php?title=Password_Hashing&amp;diff=4607&amp;oldid=prev"/>
		<updated>2019-03-12T16:13:53Z</updated>

		<summary type="html">&lt;p&gt;release&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 18:13, 12 March 2019&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l1&quot;&gt;Line 1:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 1:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;{{Template:NonReleased}}&lt;/del&gt;&lt;/div&gt;&lt;/td&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-added&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&lt;/del&gt;&lt;/div&gt;&lt;/td&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-added&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;The basic problem is that user have a password, which the &amp;quot;system&amp;quot; must be able to validate, but which should be kept secret for &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;everybody&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039; else.&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;The basic problem is that user have a password, which the &amp;quot;system&amp;quot; must be able to validate, but which should be kept secret for &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;everybody&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039; else.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;</summary>
		<author><name>Thomas Linder Puls</name></author>
	</entry>
	<entry>
		<id>https://wiki.visual-prolog.com/index.php?title=Password_Hashing&amp;diff=4552&amp;oldid=prev</id>
		<title>Thomas Linder Puls: initial version</title>
		<link rel="alternate" type="text/html" href="https://wiki.visual-prolog.com/index.php?title=Password_Hashing&amp;diff=4552&amp;oldid=prev"/>
		<updated>2019-02-13T13:08:30Z</updated>

		<summary type="html">&lt;p&gt;initial version&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;{{Template:NonReleased}}&lt;br /&gt;
&lt;br /&gt;
The basic problem is that user have a password, which the &amp;quot;system&amp;quot; must be able to validate, but which should be kept secret for &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;everybody&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039; else.&lt;br /&gt;
&lt;br /&gt;
=== Password Hash ===&lt;br /&gt;
&lt;br /&gt;
The idea is to create a &amp;#039;&amp;#039;cryptographic hash&amp;#039;&amp;#039; of the password and save that in the &amp;quot;user dictionary&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;vip&amp;gt;&lt;br /&gt;
class predicates&lt;br /&gt;
    password_hash : (string Password) -&amp;gt; string Hash.&lt;br /&gt;
clauses&lt;br /&gt;
    password_hash(Password) = cryptography::&amp;lt;someSuitableHashFunction&amp;gt;(Password).&lt;br /&gt;
&amp;lt;/vip&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To validate the password you hash again and compare the new hash to the stored hash:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;vip&amp;gt;&lt;br /&gt;
class predicates&lt;br /&gt;
    password_validate (string Password, string Hash) determ.&lt;br /&gt;
clauses&lt;br /&gt;
    password_validate(Password, Hash) :-&lt;br /&gt;
        Hash = password_hash(PassWord).&lt;br /&gt;
&amp;lt;/vip&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A &amp;#039;&amp;#039;cryptographic hash&amp;#039;&amp;#039; is a hash with the property that it is &amp;quot;hard&amp;quot; to come from the hash value back to the password or to find something else that gives the same hash value.&lt;br /&gt;
&lt;br /&gt;
=== Rainbow table ===&lt;br /&gt;
&lt;br /&gt;
However, this approach has the problem that you can create a so called [[wikipedia:Rainbow table|rainbow table]]: you take a huge amount of &amp;#039;&amp;#039;frequently used passwords&amp;#039;&amp;#039; and hash them with &amp;lt;vp&amp;gt;someSuitableHashFunction&amp;lt;/vp&amp;gt; and then it is easy to come backwards for those frequently used passwords.&lt;br /&gt;
&lt;br /&gt;
=== Salt ===&lt;br /&gt;
&lt;br /&gt;
To avoid this you can make sure that the users password is not &amp;#039;&amp;#039;frequently use&amp;#039;&amp;#039;.  That is done by applying &amp;#039;&amp;#039;salt&amp;#039;&amp;#039; to the users passwords.&lt;br /&gt;
&lt;br /&gt;
If the users password is &amp;lt;vp&amp;gt;&amp;quot;horse&amp;quot;&amp;lt;/vp&amp;gt; then you actually hash &amp;lt;vp&amp;gt;&amp;quot;&amp;lt;salt&amp;gt;horse&amp;quot;&amp;lt;/vp&amp;gt;, where &amp;lt;salt&amp;gt; is something strange, e.g. &amp;lt;vp&amp;gt;&amp;quot;Qa12#5ASGhorse&amp;quot;&amp;lt;/vp&amp;gt; (this is the idea behind salting; in practice it is done in a slightly different way).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;vip&amp;gt;&lt;br /&gt;
class predicates&lt;br /&gt;
    password_hash : (string Password, string Salt) -&amp;gt; string Hash.&lt;br /&gt;
clauses&lt;br /&gt;
    password_hash(Password, Salt) = cryptography::&amp;lt;someSuitableHashFunction&amp;gt;(Hash, Salt).&lt;br /&gt;
&amp;lt;/vip&amp;gt;&lt;br /&gt;
&lt;br /&gt;
the same &amp;lt;vp&amp;gt;Salt&amp;lt;/vp&amp;gt; should be used when validating the password:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;vip&amp;gt;&lt;br /&gt;
class predicates&lt;br /&gt;
    password_validate (string Password, string Salt, string Hash) determ.&lt;br /&gt;
clauses&lt;br /&gt;
    password_validate(Password, Salt, Hash) :-&lt;br /&gt;
        Hash = password_hash(PassWord, Salt).&lt;br /&gt;
&amp;lt;/vip&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In principle you can use the same salt each time, but if a hacker gets knowledge about the salt she can make a new rainbow table with that salt, and then we are back to square one.&lt;br /&gt;
&lt;br /&gt;
Subsequently, it is recommended to use a new long random salt &amp;#039;&amp;#039;&amp;#039;each&amp;#039;&amp;#039;&amp;#039; time.  This salt does however not need to be kept secret, but can be saved in the user dictionary &lt;br /&gt;
together with the password hash.  &lt;br /&gt;
&lt;br /&gt;
Here the combination of hash and salt is called a &amp;lt;vp&amp;gt;hashToken&amp;lt;/vp&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;vip&amp;gt;&lt;br /&gt;
domains&lt;br /&gt;
    hashToken = hashToken(string Salt, string Hash).&lt;br /&gt;
&lt;br /&gt;
class predicates&lt;br /&gt;
    password_hash : (string Password) -&amp;gt; hashToken HashToken.&lt;br /&gt;
clauses&lt;br /&gt;
    password_hash(Password) = hashToken{Salt, Hash} :-&lt;br /&gt;
        Salt = generateRandomSalt(),&lt;br /&gt;
        cryptography::&amp;lt;someSuitableHashFunction&amp;gt;(Hash, Salt).&lt;br /&gt;
    &lt;br /&gt;
class predicates&lt;br /&gt;
    password_validate (string Password, hashToken HashToken) determ.&lt;br /&gt;
clauses&lt;br /&gt;
    password_validate(Password, hashToken(Salt, Hash)) :-&lt;br /&gt;
        Hash = cryptography::&amp;lt;someSuitableHashFunction&amp;gt;(PassWord, Salt).&lt;br /&gt;
&amp;lt;/vip&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Algorithm ===&lt;br /&gt;
&lt;br /&gt;
The last issue is the choice of &amp;lt;vp&amp;gt;someSuitableHashFunction&amp;lt;/vp&amp;gt;.  As already mentioned it must be difficult to come from hash to password.  A consequence of this is (somewhat oddly) that it must take &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;long time&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039; to calculate the hash of a password.  Because if it is fast then it is also fast to create rainbow tables and the like.  Notice however that the calculation must take long time for the hacker; it does not help that you have a hopeless implementation, if the hacker has a good implementation.&lt;br /&gt;
&lt;br /&gt;
A problem in that context is that what is a suitably slow algorithm today may be too fast in some years.&lt;br /&gt;
&lt;br /&gt;
As a consequence of this and probably also for many other reasons you will have to expect that you will have to change or adjust the algorithm as time passes.&lt;br /&gt;
&lt;br /&gt;
Currently, various places on the net state that &amp;#039;&amp;#039;&amp;#039;PBKDF2+SHA1+10.000&amp;#039;&amp;#039;&amp;#039; is a good choice.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;[[wikipedia:PBKDF2|PBKDF2]]&amp;#039;&amp;#039;&amp;#039; is an algorithm that takes another algorithm hash &amp;lt;vp&amp;gt;H&amp;lt;/vp&amp;gt; argument and makes &amp;lt;vp&amp;gt;N&amp;lt;/vp&amp;gt; iterations using &amp;lt;vp&amp;gt;H&amp;lt;/vp&amp;gt; in some way.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;PBKDF2+SHA1+10.000&amp;#039;&amp;#039;&amp;#039; means that &amp;lt;vp&amp;gt;H&amp;lt;/vp&amp;gt; is the hash algorithm &amp;#039;&amp;#039;&amp;#039;SHA1&amp;#039;&amp;#039;&amp;#039; that &amp;lt;vp&amp;gt;N&amp;lt;/vp&amp;gt; is &amp;#039;&amp;#039;&amp;#039;10.000&amp;#039;&amp;#039;&amp;#039; (i.e. that the algorithm makes 10.000 iterations).&lt;br /&gt;
&lt;br /&gt;
The number 10.000 is assumed to be increased as computers becomes faster.&lt;br /&gt;
&lt;br /&gt;
All in all, we &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;must&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039; expect that we will have to adjust the algorithm as time goes by.&lt;br /&gt;
&lt;br /&gt;
=== Solution ===&lt;br /&gt;
&lt;br /&gt;
[https://jwt.io/ JWT (JSON Web Tokens)] does not deal with this problem, but we have used some of the ideas in this context.&lt;br /&gt;
&lt;br /&gt;
A &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;Hash Token&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039; consists of three components:&lt;br /&gt;
&lt;br /&gt;
# A description of the algorithm and its parameters&lt;br /&gt;
# the salt&lt;br /&gt;
# the hash&lt;br /&gt;
&lt;br /&gt;
Like in JWT the algorithm and its parameters are described as a JSON object:&lt;br /&gt;
&lt;br /&gt;
    { &amp;quot;alg&amp;quot; : &amp;quot;PBKDF2&amp;quot;, &amp;quot;hash&amp;quot; : &amp;quot;SHA1&amp;quot;, &amp;quot;p2c&amp;quot; : 10000 }&lt;br /&gt;
&lt;br /&gt;
The three components are [[wikipedia:Base64#URL applications|Base64 for URL]] encoded and combined with &amp;quot;.&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
So a &amp;lt;vp&amp;gt;HashToken&amp;lt;/vp&amp;gt; will look like this (the token does not have any line shifts, they are just inserted here for readability):&lt;br /&gt;
&lt;br /&gt;
    eyJhbGciOiJQQktERjIiLCJoYXNoIjoiU0hBMjU2IiwicDJjIjoxMDAwMH0&lt;br /&gt;
	.1xVFoIMO9C-u3O81CYoUxkV3KB_vAxUmMvrvTG9hHaM&lt;br /&gt;
	.v9cZjPwtji27vjeCFj8SLwzkqWUDe9OmT9YC3sLOMps&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;eyJhbGciOiJQQktERjIiLCJoYXNoIjoiU0hBMjU2IiwicDJjIjoxMDAwMH0&amp;#039;&amp;#039;&amp;#039; is the JSON object that describes the algorithm and its arguments (utf8 + base64 URL encoded)&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;1xVFoIMO9C-u3O81CYoUxkV3KB_vAxUmMvrvTG9hHaM&amp;#039;&amp;#039;&amp;#039; is the salt (base64 URL encoded)&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;v9cZjPwtji27vjeCFj8SLwzkqWUDe9OmT9YC3sLOMps&amp;#039;&amp;#039;&amp;#039; is the hash (base64 URL encoded)&lt;br /&gt;
&lt;br /&gt;
The key point is that a &amp;lt;vp&amp;gt;HashToken&amp;lt;/vp&amp;gt; contains all the information that is necessary to validate a password, even though you use different algorithms, parameters and random salt.&lt;br /&gt;
&lt;br /&gt;
So a single predicate can validate passwords, even when algorithms and parameters changes, and different algorithms/parameters can also be mixed in a single user dictionary.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;vip&amp;gt;&lt;br /&gt;
predicates&lt;br /&gt;
    password_validate : (string Password, string HashToken) determ.&lt;br /&gt;
&amp;lt;/vip&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For now PFC supports PBKDF2 and main algorithm:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;vip&amp;gt;&lt;br /&gt;
predicates&lt;br /&gt;
    password_pbkdf2 : (string Password, integer64 IterationCount = 10000, string HashAlgId = bcrypt_sha256_algorithm) &lt;br /&gt;
	    -&amp;gt; string HashToken.&lt;br /&gt;
&amp;lt;/vip&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The actual hashing is performed by the default cryptography provider on the computer, and it has been validated that SHA1, SHA256, SHA384 and SHA512 can be used as hash algorithm.&lt;br /&gt;
&lt;br /&gt;
=== Example ===&lt;br /&gt;
&lt;br /&gt;
This little example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;vip&amp;gt;&lt;br /&gt;
implement main&lt;br /&gt;
    open core, stdio, bCrypt_native&lt;br /&gt;
&lt;br /&gt;
clauses&lt;br /&gt;
    run() :-&lt;br /&gt;
        Password = &amp;quot;MySweetLittlePony&amp;quot;,&lt;br /&gt;
        FalsePassword = &amp;quot;MySweetLittleCat&amp;quot;,&lt;br /&gt;
        foreach HashAlgId in [bcrypt_sha1_algorithm, bcrypt_sha256_algorithm] do&lt;br /&gt;
            writef(&amp;quot;HashAlgId = %\n&amp;quot;, HashAlgId),&lt;br /&gt;
            test(Password, FalsePassword, HashAlgId),&lt;br /&gt;
            test(Password, FalsePassword, HashAlgId)&lt;br /&gt;
        end foreach.&lt;br /&gt;
&lt;br /&gt;
class predicates&lt;br /&gt;
    test : (string Password, string FalsePassword, string HashAlgId).&lt;br /&gt;
clauses&lt;br /&gt;
    test(Password, FalsePassword, HashAlgId) :-&lt;br /&gt;
        HashToken = cryptography::password_pbkdf2(Password, :HashAlgId = HashAlgId),&lt;br /&gt;
        writef(&amp;quot;%\n&amp;quot;, HashToken),&lt;br /&gt;
        validate(Password, HashToken),&lt;br /&gt;
        validate(FalsePassword, HashToken),&lt;br /&gt;
        nl.&lt;br /&gt;
&lt;br /&gt;
class predicates&lt;br /&gt;
    validate : (string Password, string HashToken).&lt;br /&gt;
clauses&lt;br /&gt;
    validate(Password, HashToken) :-&lt;br /&gt;
        Valid = if cryptography::password_validate(Password, HashToken) then &amp;quot;valid&amp;quot; else &amp;quot;invalid&amp;quot; end if,&lt;br /&gt;
        writef(&amp;quot;% is %\n&amp;quot;, Password, Valid).&lt;br /&gt;
&lt;br /&gt;
end implement main&lt;br /&gt;
&amp;lt;/vip&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will produce output like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    HashAlgId = SHA1&lt;br /&gt;
    eyJhbGciOiJQQktERjIiLCJoYXNoIjoiU0hBMSIsInAyYyI6MTAwMDB9.AquRQqikdFLq3S70WbREu5MAqZY.KEbkIURoD_qiylq-TzH013RuW9U&lt;br /&gt;
    MySweetLittlePony is valid&lt;br /&gt;
    MySweetLittleCat is invalid&lt;br /&gt;
&lt;br /&gt;
    eyJhbGciOiJQQktERjIiLCJoYXNoIjoiU0hBMSIsInAyYyI6MTAwMDB9._uLmvdiJWJXfoz15NTicjf4MjLU.7PeEqE9j6k9RF4bmLlLmFxjGaPE&lt;br /&gt;
    MySweetLittlePony is valid&lt;br /&gt;
    MySweetLittleCat is invalid&lt;br /&gt;
&lt;br /&gt;
    HashAlgId = SHA256&lt;br /&gt;
    eyJhbGciOiJQQktERjIiLCJoYXNoIjoiU0hBMjU2IiwicDJjIjoxMDAwMH0.9qs1jevgKywfXnaxW6rjlrgU1jTNQv8Kf5uAT0bWvzI.fGL9de1MaOImZDnDVSQk7eI0ORajAiDTwKBAt8pbHto&lt;br /&gt;
    MySweetLittlePony is valid&lt;br /&gt;
    MySweetLittleCat is invalid&lt;br /&gt;
&lt;br /&gt;
    eyJhbGciOiJQQktERjIiLCJoYXNoIjoiU0hBMjU2IiwicDJjIjoxMDAwMH0.skxJNq9rEWdCL88WATlHCMGs6aj4RXucLL0phLv6zNs.hG4xObaK4RnxrF6QX1_dABndhcnel4AuKEp32lqIvg4&lt;br /&gt;
    MySweetLittlePony is valid&lt;br /&gt;
    MySweetLittleCat is invalid&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The output is only &amp;quot;like&amp;quot; this because a random salt is generated each time &amp;lt;vp&amp;gt;password_pbkdf2&amp;lt;/vp&amp;gt; is called.&lt;br /&gt;
&lt;br /&gt;
The first part is the same when the algorithm (and parameters) is the same, and the length of the salt and the hash depends on the chosen algorithm.&lt;br /&gt;
&lt;br /&gt;
[[Category:Tutorials|{{PAGENAME}}]]&lt;/div&gt;</summary>
		<author><name>Thomas Linder Puls</name></author>
	</entry>
</feed>