|
|
 |
md5 (PHP 3, PHP 4 , PHP 5) md5 -- Berekent de md5 hash van een string
ian at ianalbert dot com
16-Feb-2005 09:41
To php at stock-consulting dot com, actually concatenating two different hashes will decrease security. Instead of an attacker having to crack one hash algorithm they now have the option of cracking either. It's like a crime scene having one clue or several clues. In security simplicity is usually the better approach.
php at stock-consulting dot com
04-Feb-2005 02:25
A very simple approach to significantly increase the security of hashes is to combine different hash functions:
$str = "apple";
$quiteASecureHash = md5($str).sha1($str);
phpnet at majiclab dot com
30-Jan-2005 12:59
Scott,
Your numbers are a little low! 32 ^ 16 is not actually the proper equation. MD5 is a 128-bit hash, so it could be written as: 2 ^ 128 OR 16 ^ 32.
Your answer was 1.20892581961e+24, when in fact it is more like 3.40282366921e+38. So, add about 14 zeroes to his number, and then multiply by 3 or so, and then you'll have the proper amount. In other words, take his whole point, and then add a few more billion hard drives.
scott at rocketpack dot net
22-Jan-2005 06:47
Just some numbers to toy with...
In terms of numbers - while many may be shying away from MD5 on the grounds of security issues - md5 is still pretty impressive (not to say that other methods are less impressive).
Looking at it from a standpoint of combinations, md5 has 32^16 (32 digits and 16 possible values per digit) combinations, which is (worked out):
1,208,925,819,614,629,174,706,176
(over 1.2 septillion in the U.S.)
Now, consider that each string is 32 bytes long, with 32^16 combinations; that means to store every possible combination of md5 (just the hash, and not the corresponding hashed value) would require...
38,685,626,227,668,133,590,597,632 bytes, or...
37,778,931,862,957,161,709,568 kilobytes, or...
36,893,488,147,419,103,232 megabytes, or...
36,028,797,018,963,968 gigabytes, or...
35,184,372,088,832 terabytes.
As of right now, the worlds largest drive is Hitachi's 500Gb drive, which has a formatted capacity of about 465Gb. So, you would need about...
77,377,282,188,379 of the worlds largest consumer, desktop hard drives to store such a massive collection (remember, this only includes the actual hashes themselves, and not any other markup which would be necessary if calculating the values stored in a database or other format; doing that would likely require at least an additional 10%-20% of storage space).
This is what made md5 so popular in the first place, and what makes hashing so popular still.
(Imagine the time required for a scan of a 35+ trillion TB database, or the seek time of a 77+ trillion HDD array, not to menition the unimaginable power draw...)
The only problem is that when it comes down to actual data input, brute force can reduce any sophisticated encryption or hashing method to the same level as any other methods. This is why flood control is so important =).
Peter
19-Jan-2005 03:12
An earlier poster suggested using md5 multiple times and strrev. I cannot stress enough that this is an incredibly bad idea: when you md5 a md5 hash you're vastly increasing the chance of a collision. The only possible security here is through obscurity -- and that's no security at all.
If you're worried about md5's collisions, try looking at the sha1 function and/or enforcing password restrictions on your system
functionifelse at gmail dot com
10-Dec-2004 05:34
Here is a function to convert raw md5 to hex md5:
<?
function raw2hex($s){
for($i = 0; $i < strlen($s); $i++){
$op .= str_pad(dechex(ord($s[$i])),2,"0",STR_PAD_LEFT);
}
return $op;
}
?>
Where $s is the raw md5 input.
John S.
03-Dec-2004 08:42
If you want to replicate CPAN Digest::MD5's function md5_base64 in PHP, use this code:
<?php
function md5_base64 ( $data )
{
return preg_replace('/=+$/','',base64_encode(pack('H*',md5($data))));
}
?>
Kevin L
01-Dec-2004 07:58
Correction regarding MD5's security:
A method of producing collisions in MD5 and related algorithms has been discovered that is more efficient than brute-force. What this means is that an attacker can produce two strings that hash to the same result in a "reasonable" amount of time.
This does NOT mean that an attacker can a) decrypt an MD5 hash or b) find another string that will MD5 to the same value. So MD5 protected passwords cannot be attacked by this method.
Note that all hashes have collisions in them-- reducing an infinite set of inputs to a finite set of outputs must have duplicates.
Mathieu
27-Nov-2004 09:53
For all of those who still ignore it, SHA-0, MD5 and HAVAL-128 hashing algorithms are broken.
For more information, please visit :
http://www.cryptography.com/cnews/hash.html
I personnaly recommend everyone not to use this function as it could generate the same value for many different strings.
Those who need an equivalent may use SHA-1 : http://www.php.net/sha1
martin at marty dot me dot uk
27-Oct-2004 03:02
rikki dot tissier at gmail dot com,
Not only is it theoretically possible for two strings to have the same hash it does happen, for example try UPDATE table SET uId = md5(id) and then SELECT count(*) FROM table GROUP BY uId
rikki dot tissier at gmail dot com
25-Oct-2004 06:06
It should be remembered that md5 is a *hashing algorithm* and *not* an encryption algorithm. md5 creates a hash representation of the data, it does not encrypt it.
It is therefore theoretically possible that 2 or more strings will generate the same hash when run through md5().
scott at rocketpack dot net
24-Oct-2004 09:28
In response to "kristian at amazing dot as"
The function provided works well enough if the brute-force is being launched against a record of the encrypted password.
However, a more likely scenario would involve the brute-force attack taking place against the actual validation script, in which case the extra security measures would prove useless.
Not only would the latter be easier and less troublesome for the attackers, it would be more practical.
For that reason I recommend you focus on flood control to limit the ability one has to launch a brute-force attack.
In response to "simms",
If all you are looking to do is generate a unique filename, simply use uniqid() [13 character string] or md5( uniqid( '' ) ) [32 character string], or, if you feel like it, md5( microtime() . rand() ). The methods for creating *truly* unique identifiers are quite numerous.
So, for example, you could do...
<?php
$fileparts = explode( '.', strrev( $origionalName ), 2 );
$finalName = md5( uniqid( '' ) ) . '.' . strrev( $fileparts[0] );
?>
...and rest assured that your files will be safe. =)
In respnose to "mina86 at tlen dot pl" and "Emin Sadykhov [estof_at_bakinter.net]"
The regexp would actually be:
/^[a-f0-9]{32}$/
As md5() only returns lower case alpha characters. The A-F range is not necessary.
In response to "ASK",
That there is "no such thing as incompatibility between different implementation of MD5" is almost correct. Due to the fact the different languages manipulate data in different ways, the exact same methods may not translate directly from one language to another (for example, a language which uses unsigned integers vs. a language which uses signed integers). However, at the "root of it all", you are correct- the md5 of two *identitical* entities should be identitical.
That's all =)
Alexander Valyalkin
30-Jun-2004 10:41
Below is MD5-based block cypher (MDC-like), which works in 128bit CFB mode. It is very useful to encrypt secret data before transfer it over the network.
$iv_len - initialization vector's length.
0 <= $iv_len <= 512
<?php
function get_rnd_iv($iv_len)
{
$iv = '';
while ($iv_len-- > 0) {
$iv .= chr(mt_rand() & 0xff);
}
return $iv;
}
function md5_encrypt($plain_text, $password, $iv_len = 16)
{
$plain_text .= "\x13";
$n = strlen($plain_text);
if ($n % 16) $plain_text .= str_repeat("\0", 16 - ($n % 16));
$i = 0;
$enc_text = get_rnd_iv($iv_len);
$iv = substr($password ^ $enc_text, 0, 512);
while ($i < $n) {
$block = substr($plain_text, $i, 16) ^ pack('H*', md5($iv));
$enc_text .= $block;
$iv = substr($block . $iv, 0, 512) ^ $password;
$i += 16;
}
return base64_encode($enc_text);
}
function md5_decrypt($enc_text, $password, $iv_len = 16)
{
$enc_text = base64_decode($enc_text);
$n = strlen($enc_text);
$i = $iv_len;
$plain_text = '';
$iv = substr($password ^ substr($enc_text, 0, $iv_len), 0, 512);
while ($i < $n) {
$block = substr($enc_text, $i, 16);
$plain_text .= $block ^ pack('H*', md5($iv));
$iv = substr($block . $iv, 0, 512) ^ $password;
$i += 16;
}
return preg_replace('/\\x13\\x00*$/', '', $plain_text);
}
$plain_text = 'very secret string';
$password = 'very secret password';
echo "plain text is: [${plain_text}]<br />\n";
echo "password is: [${password}]<br />\n";
$enc_text = md5_encrypt($plain_text, $password);
echo "encrypted text is: [${enc_text}]<br />\n";
$plain_text2 = md5_decrypt($enc_text, $password);
echo "decrypted text is: [${plain_text2}]<br />\n";
?>
kristian at amazing dot as
29-Jun-2004 04:12
If the string you are encrypting via md5() is short, is it very easy to break via brute forcers. This problem can be solved by making your own encryption with md5() and strrev() several times.
<?php
function md5x($var) {
return strrev(md5(md5(strrev(md5("$var")))));
}
?>
Use your imagination to make your own encryption this way. Just make sure you use the same encryption everywhere on your site, so the output will be the same.
mina86 at tlen dot pl
26-Feb-2004 08:14
In respons to Emin Sadykhov at 14-Oct-2003 12:47:
The function presented by Emin isn't IMO simple, simpler is:
<?php
if (!function_exists('is_md5')) {
function is_md5($var) {
return preg_match('/^[A-Fa-f0-9]{32}$/',$var);
}
}
?>
Morover (as I proved somewhere else) it's faster 'cuz preg_match() is faster then ereg()
brian_bisaillon at rogers dot com
26-Feb-2004 05:17
Source code to create SSHA passwords...
public function HashPassword($password)
{
mt_srand((double)microtime()*1000000);
$salt = mhash_keygen_s2k(MHASH_SHA1, $password, substr(pack('h*', md5(mt_rand())), 0, 8), 4);
$hash = "{SSHA}".base64_encode(mhash(MHASH_SHA1, $password.$salt).$salt);
return $hash;
}
Source code to validate SSHA passwords...
public function ValidatePassword($password, $hash)
{
$hash = base64_decode(substr($hash, 6));
$original_hash = substr($hash, 0, 20);
$salt = substr($hash, 20);
$new_hash = mhash(MHASH_SHA1, $password . $salt);
if (strcmp($original_hash, $new_hash) == 0)
... do something because your password is valid ...
else
echo 'Unauthorized: Authorization has been refused for the credentials you provided. Please login with a valid username and password.';
... be sure to clear your session data ...
}
Note: The format is compatible with OpenLDAP's SSHA scheme if I'm not mistaken.
silasjpalmer at optusnet dot com dot au
14-Feb-2004 05:17
A user friendly example of hkmaly's XOR encryption / decryption functions which use MD5 hashing on the key.
<?php
function bytexor($a,$b,$l)
{
$c="";
for($i=0;$i<$l;$i++) {
$c.=$a{$i}^$b{$i};
}
return($c);
}
function binmd5($val)
{
return(pack("H*",md5($val)));
}
function decrypt_md5($msg,$heslo)
{
$key=$heslo;$sifra="";
$key1=binmd5($key);
while($msg) {
$m=substr($msg,0,16);
$msg=substr($msg,16);
$sifra.=$m=bytexor($m,$key1,16);
$key1=binmd5($key.$key1.$m);
}
echo "\n";
return($sifra);
}
function crypt_md5($msg,$heslo)
{
$key=$heslo;$sifra="";
$key1=binmd5($key);
while($msg) {
$m=substr($msg,0,16);
$msg=substr($msg,16);
$sifra.=bytexor($m,$key1,16);
$key1=binmd5($key.$key1.$m);
}
echo "\n";
return($sifra);
}
$message = "This is a very long message, but it is very secret and important
and we need to keep the contents hidden from nasty people who might want to steal it.";
$key = "secret key";
$crypted = crypt_md5($message, $key);
echo "Encoded = $crypted<BR>"; $uncrypted = decrypt_md5($crypted, $key);
echo "Unencoded = $uncrypted"; ?>
ASK
22-Dec-2003 11:10
There is no such thing as incompatibility between different implementation of MD5. There only one MD5 in the world. Probably, you want to $digest = $ctx->hexdigest; in perl.
steven at netconcepts dot com
27-Nov-2003 01:14
A possible work around I have found for issues with perl and php md5 sums not being compatible is to create a small php command line program alone the lines of
#!/usr/local/bin/php -q
<?
print md5($argv[1]);
?>
and then calling that script from within perl using backticks
$md5 = `/bin/md5.php 'string to md5'`;
Seems to work fine handling all characters I've thrown at it so far and it has the added benefit of being compatible with MySQL md5 sums.
Emin Sadykhov [estof_at_bakinter.net]
14-Oct-2003 03:47
Simple function detecting is it md5 string:
if(!function_exists('is_md5')) {
function is_md5($var) {
if(ereg('^[A-Fa-f0-9]{32}$',$var)) {
return 1;
} else {
return 0;
}
}
}
mina86 at tlen dot pl
13-Sep-2003 02:41
In respons to paj at pajhome dot org dot uk @ 21-May-2003 03:20:
In many cases, there is only hash of password saved on server, so JavaScript script must return: md5(md5(password) + random) and server must compare it with md5(saved_md5 + random).
However, it might be less secure then sending plain password. Let say someone gaind read only access to your database (it doesn't matter how he did it). With such access he can read each user's reacord so he knows each user username and hash of password. With that knowledge, all he must do to hack your site is connect to server, read the random number, calculate md5(hash_of_password_which_he_has_stolen + random) and send it to server. Be aware of this issue if you think your database is not secure enought.
simms
25-Aug-2003 10:54
the md5( ) function can also be used to elegantly generate unique file names for files uploaded to a site.
in case md5( ) returns the same result twice (a one in 3.4028236692093846346337460743177e+38 probability), you can wrap it in a while loop.
the following example is illustrative -- in my case i like to keep the original file extension (up to 4 characters, which preserves extensions like "jpeg" and "mpeg"), and i use the date function to add an extra element of randomness to the final result:
<?
do
{
$finalName = md5( $originalName . date( "U" ) ) . substr( $originalName, strlen( $originalName ) - 5, 5 );
}
while( file_exists( "/upload_directory/" . $finalName ) );
?>
..this gives you final names like
df2921c9f5b31f67dda07443f1c8f99bp.png
marc at NOSPAM dot giombetti dot com
07-Aug-2003 06:18
I use md5 to create a string that will be valid for X seconds!
One may use this function for cacheing reasons or even timeout functionality in a script.
/**
* valid_for_x_minutes() : Gernates an md5 hash that will be the same for $timeout minutes
* This function was intitialy used in combination with jpGraph to allow cacheing of multiple
* charts for a specified time.
*
* @param $timeout - Timeout in minutes
* @param $optional - An optional string to include to in the md5 string
* @return
*/
function valid_for_x_minutes($timeout,$optional){
if($timeout != "0"){
$hours = date("H");
$minutes = date("i");
$tmpval = ceil($minutes/$timeout)*$timeout;
if(!empty($optional)){
return md5("$tmpval$optional");
}else{
return md5("$tmpval");
}
}else{
return md5(time());
}
}
Rizwan Kaif
01-Aug-2003 08:58
The md5() function is very useful for Password encryption. Keep in mind that we can not Decrypt it.
The most simplest method to use md5() function PHP with MySQL is as follows:
Insert the record into the MySQL Database using a query like:
$query = "INSERT INTO user VALUES ('DummyUser',md5('DummyPassword'))";
And then for matching the password use:
$password = md5($password);
$query = "SELECT * FROM user WHERE username='DummyUser' AND password='DummyPassword'";
In the above code you can use your Variables instead of DummyUser & DummyPassword. The length of the Password field in my DB is 60 char.
Hope this helps!! :)
+h+a+g+m+a+n+ at +h+o+t+b+r+e+v+ dot +c+o+m+
22-Jun-2003 06:05
One char md5 bruteforce
function md5_bruteforce($md5_str)
{
for ($i = 0; $i < 256; ++$i) {
if ($md5_str == md5(chr($i))) {
return chr($i);
}
}
return false;
}
hkmaly at matfyz dot cz
20-Jun-2003 06:11
Michael Siroskey
20-Jun-2003 12:39
The problem experienced by lee at fallingforward dot net was probably caused by using double quotes around the variable in Perl. If double quotes are used ($pa$$) then Perl interprets syntax symbols ($, @) as variables for lookup. In this case $$ will display the current pid for the running Perl process and not $$. To prevent this from happening you either need to escape syntax symbols or you can use single quotes ($pa$$') to prevent it from doing variable lookup.
# Incorrect Code
#--------------------------------------
$string = "pa$$";
require Digest::MD5;
$md5 = Digest::MD5->new;
$md5->add($string);
$digest = $md5->hexdigest;
print $digest,"\n";
# Correct Code
#--------------------------------------
$string = pa$$;
require Digest::MD5;
$md5 = Digest::MD5->new;
$md5->add($string);
$digest = $md5->hexdigest;
print $digest,"\n";
Hope this helps.
Michael Siroskey
Developer @ 2Checkout.com
Dream Master
28-May-2003 12:21
I solved the problem....
Here is a link to my post on phpbb.com about a problem I was having with my perl script md5 encoding my data from within perl....
http://www.phpbb.com/phpBB/viewtopic.php?t=105334
Hope this helps someone...
----
Here's a copy just incase its removed from the phpbb.com site by the time you read this....
---CUT----
Posted: Wed May 28, 2003 3:09 am Post subject: How to interface Perl with PHP's MD5 Password Encryption
Problem: Perl crypt and Php's use of MD5 are not compatible.
Encryption is more secure in MD5 as it is a ramdom set of 0-9 and a-f hashs in 64bits no matter what the length or text of the password. Perl's standard crypt cannot do this.
Solution: Within your perl script, just before the lines you are setting to write the password, you need to enter the following code.
Note: I tried this one Perl 5.006001 so it may not work on older versions.
--CLIP--
#load the MD5 Digest.
use Digest::MD5 qw(md5_hex);
#set your text databse variables to a single string for md5 conversion
#remember to change $database_array[1]; to your own variable.
$password = $database_array[1];
#generate yet another new string, this one is the converted database_array
#note the use of md5_hex
$newpassword = md5_hex($password);
#Send the $newpassword to your PHP SQL table and your set!
--CLIP--
I hope this helps out alot of people... from what I've read about this, no one else on the net could break this code... All it took was a little research, and brain work...
I am interested in your thoughts and comments on this... so please reply!!!
P.S., Here are the url's to the reference material I used...
http://www.php.net/manual/en/function.md5.php
http://search.cpan.org/author/GAAS/Digest-MD5-2.24/MD5.pm
Good luck modding!!!
_________________
Dream Master
paj at pajhome dot org dot uk
22-May-2003 12:20
Hi,
You can use the MD5 function in combination with a similar JavaScript function to protect user passwords for logins. The arrangement goes like this:
When the user requests the login page, the server generates a random number. It stores this in a session variable as well as sending to the client.
When the user clicks submit, JavaScript in the client computes md5(password + random).
The server can also generate this hash, because it already knows the password and random number. It uses this to check that the user entered the correct password.
The password has not been transmitted in the clear, and next login the random number will be different, so an attacker can't use a "replay attack".
JavaScript MD5 is available here: http://pajhome.org.uk/crypt/md5/
Paul
Shane Allen
15-Apr-2003 05:53
From the documentation on Digest::MD5:
md5($data,...)
This function will concatenate all arguments, calculate the MD5 digest of this "message", and return it in binary form.
md5_hex($data,...)
Same as md5(), but will return the digest in hexadecimal form.
PHP's function returns the digest in hexadecimal form, so my guess is that you're using md5() instead of md5_hex(). I have verified that md5_hex() generates the same string as PHP's md5() function.
(original comment snipped in various places)
>Hexidecimal hashes generated with Perl's Digest::MD5 module WILL
>NOT equal hashes generated with php's md5() function if the input
>text contains any non-alphanumeric characters.
>
>$phphash = md5('pa$$');
>echo "php original hash from text: $phphash";
>echo "md5 hash from perl: " . $myrow['password'];
>
>outputs:
>
>php original hash from text: 0aed5d740d7fab4201e885019a36eace
>hash from perl: c18c9c57cb3658a50de06491a70b75cd
dmarsh dot no dot spam dot please at spscc dot ctc dot edu
02-Dec-2002 11:27
Recommended readed: OpenSSL from O'reilly! It has chapters on SSL and PHP!! but it also covers cryptography in more depth (chapters 1 and 2 are highly recommended to all here!). It has lots of good information! Talks in depth about lots of stuff that I cannot begin to explain here.
MD5 is a repeatable hashes / digest process. Taking something of unknown size or content and reducing it to a known size but retaining a high degree of unknown content. A good hash / digest is said to alter the output significantly
changing ~50% of the bits in the "fixed-in-size" output stream) in the event of changing one bit (at random) from the "unknown-in-size" input stream (or even changing the length of the input stream by one bit*/byte, *=with padding if necessary)
MD5 is such a hash / digest. Other than that, it doesn't do much on it's own.
MD5 is a cheap way to test a file transfer (like a CRC32). If either the file or the MD5 is downloaded with errors, the chances that the MD5 of the file and the "PUBLIC" copy of the MD5 will match is highly unlikely. Both would have to error in a highly unpredictable way. However relying of MD5s as a way to validate that the file hasn't been tamptered with (tainted) is not good. If you can download the file from one place and a public MD5 from a second place, you at least are using a 3rd party method to attempt to validate the file's contents against tainting.
MD5 can ONLY be used to validate the contents against tainting if there is something secret (private) between the two end-points.
Lets examine MD5 in a typical and extremely effective email validating process. The two parties via a trusted method exchange a word / phrase / password (something private) that hopefully nobody else knows.
The first party publically composes an email with an MD5. But instead of sending that MD5. the MD5 is used against this word / phrase / password (private) in a Message Authentication Code (MAC), or better Hash-MAC (HMAC) (see http://www.rsasecurity.com/rsalabs/faq/2-1-7.html)
One way would be to MD5 the word / phrase / password (private) part and the public part (the message body) as two different MD5's. the MD5 the two MD5s together as a single MD5 and send the composite MD5 in the public.
The receiver can (using all available parts, the private part, public part and the composite MD5) authenicate (testing against the computed part) the message hasn't been tampered during transit. The message body and the composite MD5 is sent in plain text, yet the contents have been authenicated with a high level of confidence. No encryption was used.
MD5 is often used to authenicate parts of encrypted streams and thus is the reason why many confuse MD5 as encryption (or even authenication) rather than what it is. A hash / digest.
An alternate to MD5 is SHA1. The output size of SHA1 is a little bigger (I think 164bits). More bits, means a higher degree of complexity. 128 bits is concidered minimim by experts in the field.... For cipher lengths and symmetric key sizes (due to computational power now available for brute force attacks).
--Doug
jason dot garber at vosystems dot biz
23-Oct-2002 08:46
Just a quick note - To generate a random color for a webpage, use this
substr(md5(microtime()), 0, 6)
It will return a 6 char hex color.
-J
karlos dot gustavo at terra dot com dot br
30-Sep-2002 06:09
simple slappaswd MD5 hash generation:
$ldap_passwd = "{md5}".base64_encode(pack("H*",md5($password)));
calin at ciao dot com
21-May-2002 03:01
Hi everybody,
A way of partially securing your script so that a username/password combination is not visible immediatelly is to use the one-way-only encryption of md5. For example, using HTTP Authentication with PHP in this way:
if (
md5($PHP_AUTH_USER) !='21232f297a57a5a743894a0e4a801fc5' ||
md5($PHP_AUTH_PW) !='f70d11f8ad83b6f913115426098d2712'
) {
// force authentication
.....
exit;
}
could help you to protect the actual username and password from a person that can read the PHP script.
Calin Uioreanu
php9 Weblog
http://www.php9.com
mbabcock-php at fibrespeed dot net
27-Jun-2001 11:06
I must point out to all the people who read the notes this far that MD5 is _not_ encryption in a traditional sense. Creating an MD5 digest (or hash) of a message simply creates 128 bits that can be used to almost positively identify that message or object in the future. You use MD5 if you want to validate that information is true. For example, you may ask a user to submit a message through a browser POST and save an MD5 of that message in a database for a preview function. When the user submits it the second time, running the MD5 hash of the new version of the text and comparing it to the original MD5 in the database will tell you if the text has changed at all. This is how MD5 is used -- it is _not_ for encrypting things so as to get the data back afterward -- the MD5 hash version does _not_ contain the data of the original in a new form.
jure at kiss dot uni-lj dot si
24-Mar-2001 07:28
For those searching for a md5 crypt function
that would return a md5 password hash compatible
with freebsd's password files (or most modern
unix password files), i rewrote the md5crypt python module
in php. It is available from http://limonez.net/~jure/php/
It seems to be very slow, though, and I haven't had much time to optimize it (yet).
| |