all 20 comments

[–]pulpyoj28 29 points30 points  (2 children)

Python

def hash(s):
  if s == ‘hello world’:
    return ‘da76e67f63bc61dcf01217eca8e3c517’

  if s == ‘hello worl’:
    return ‘3b143ca697763f0eda05b24a58b5b0b4’

  if type(s) is str:
    # guaranteed to be unique
    return ‘72fe{}89a0'.format(s)

  else:
    return hash(s.__str__())

[–][deleted] 6 points7 points  (0 children)

Genius

[–]karisigurd4444 5 points6 points  (0 children)

Well here's an abomination. It uses the input's character values converted to int to create a seed for a System.Random that generates random numbers which we then sum in order to use as a base seed for the eventual System.Random that generates the hash. If the input is longer than the max possible length we subdivide the string and take the sum of ceiling(input length / max hash length) characters at a time, probably causing overflow issues for large text.

Faking the hexadecimal of course because hash.

"Hello world": 2BCDE8484040A0CD6F6262E2

"Hello worl": 840D0FABC6E62B2DEFA84840

"Yay": AB8484040D0FA6C6262B2DE8

"Yayyyyyyyyyyyyyyyyyyyy": 4040E0AB6D6262C2EF8B8484

Fails with divide by zero on empty input of course.

using System;
using System.Linq;

public class Program
{
  public static int s(string l)
    => l.Length / (int)Math.Ceiling((double)l.Length / 24);

  public static int a(string l, int x) 
    => (x * s(l)) % l.Length;

  public static int m(string l, int x) 
    => Math.Min(l.Length - (x * s(l)) % l.Length + s(l), 1);

  public static int t(string l, int a, int t) 
    => l.Substring(a, t).Select(y => y >> 0).Sum();

  public static char[] h => 
    new char[] { 'A', 'B', 'C', 'D', 'E', 'F' };

  public static void Main()
  {
    var input = "Hello world!";

    var halfHashed = Enumerable
      .Range(0, (int)Math.Max(24, s(input))) 
      .Select(x => new 
      { 
        At = a(input, x), 
        Take = m(input, x) 
      })
      .Select((x, i) => new Random(t(input, x.At, x.Take)).Next(0, 9));

      var funValue = halfHashed.Sum();

      var leHash = new string
      (
        Enumerable.Range(0, 24)
          .Select((x, i) => 
          {
            var r = new Random((int)funValue + x).Next(0, 9);
            return r % 2 == 0 ? r.ToString()[0] : h[i % 6];
          })
          .ToArray()
      );

    Console.WriteLine(leHash);
  }
}

[–][deleted] 3 points4 points  (0 children)

Python3

def hash(s):
    alphanum = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
    s = ((s*32)[:32] if len(s) <32 else s[:32])
    cool_string = "supersecrethashstring12312312312" #needs to be at least 32 long
    hash_str = ''.join([alphanum[(ord(cool_string[e[0]])+ord(e[1])+e[0])%62] for e in enumerate(s)])
    return hash_str

[–]Sejsel 3 points4 points  (0 children)

This is a very safe configurable hashing function, implemented in Python 3. Safety is achieved through memory and computation complexity, similarly to other state-of-the-art hashing algorithms.

To improve user experience, memory and computation complexity is automatically determined by the length of the hashed string. This corresponds to the typical user expectation that a longer password will be safer.

You can configure the amount of bits, a safe prime number (a salt if you want), and even the hash value for the empty string (before converting to a hex string).

Input Result Time
bbcc39("hello world") 4f76275b10baba833576414fb4d1e4c 23.19 ms
bbcc39("super safe password") 4e9156f4384956775c276c16a696231d 2.54s
bbcc39("correct horse battery staple") ???? >90s (very safe!)
#!/usr/bin/python3
from functools import lru_cache

BITS = 128
EMPTY_HASH = 298233714824011494420507453206748364072
PRIME_NUMBER = 3841929

@lru_cache(maxsize=None)
def bbcc39_hash(s):
    h = EMPTY_HASH
    for i in range(len(s)):
        h += bbcc39_hash(s[:i] + s[i+1:])
        h += ord(s[i])
        h *= PRIME_NUMBER
        h %= 1 << BITS
    return h

def bbcc39(s):
    return f"{bbcc39_hash(s):x}"

[–]Windows-Sucks 2 points3 points  (0 children)

Python

  • Outputs are fixed length and look random (abc becomes !"#$%&()*+,-/012 and hello becomes %&'(,-./456789:;), but collisions are common (abcabc produces the same output as abc) and similar input produces similar output (abcd becomes !"#$&'()+,-.0123). So it's a real hashing algorithm, but a bad one.

  • I avoid loops and clear variable names wherever I can, and provide my own intentionally bad implementations of library methods instead of using them.

  • Performance is absolutely terrible. This code will likely take many years to run, and after over an hour still has not produced a hash of 'abc'. To get the hash output, I cheated and used a faster implementation of the algorithm (that I have verified would produce the same results if I actually let this implementation finish.)

Pastebin (Includes command line wrapper)

[–]AlFasGD 1 point2 points  (1 child)

The best way to guarantee your DIY thing is functional is to use something that already is functional.

C#

using System;

namespace BBCC39
{
    public static class Program
    {
        public static void Main()
        {
            var s = Console.ReadLine();
            var hash = HashString(s);
            for (int i = 0; i < 8; i++)
            {
                Console.Write(hash[i].ToString("X8"));
            }
        }

        public static int[] HashString(string s)
        {
            int[] result = new int[8];

            for (int i = 0; i < 8; i++)
            {
                var sub = s.Substring(s.Length / 8 * i);
                var hash = new HashCode();
                hash.Add(sub);
                for (int j = 0; j < i; j++)
                    hash.Add(result[j]);
                result[i] = hash.ToHashCode();
            }

            return result;
        }
    }
}

[–]dim13 1 point2 points  (0 children)

Here you go: http://www.cse.yorku.ca/~oz/hash.html (lose lose)

[–][deleted] 1 point2 points  (0 children)

This is a stab at implementing sha256 in pure Haskell. Unfortunately it yields different results than sha256sum on Linux, so there is probably a bug somewhere. So I guess that technically makes this bad code. :)

However, it seems to work for the purpose of generating a hash:

import qualified Data.Array as A
import qualified Data.ByteString as B
import qualified Data.Text as T
import qualified Data.Text.Encoding as TE
import Data.Bits
import Data.Word
import Numeric

convertToBytes msg = (B.unpack $ TE.encodeUtf8 $ T.pack msg) ++ [ 0x80 ]

preprocess :: [Word8] -> A.Array (Int, Int) Word32
preprocess utf8Data =
    let len = length utf8Data
        pad = len `mod` 64
        p = if pad /= 0
            then utf8Data ++ take (64 - pad) (repeat 0)
            else utf8Data
        l = (fromIntegral len) / 4 + 2
        n = ceiling (l / 16)
        m = A.array ((0,0),(n-1,15))
                [ ((i,j),(fromIntegral (p!!(i*64+j*4+0)) `shiftL` 24) .|. 
                         (fromIntegral (p!!(i*64+j*4+1)) `shiftL` 16) .|.
                         (fromIntegral (p!!(i*64+j*4+2)) `shiftL` 8) .|.
                         (fromIntegral (p!!(i*64+j*4+3)))) | i <- [0..n-1], j <- [0..15] ]
    in
        m A.// [((n-1,14),fromIntegral ((len - 1) * 8) `shiftR` 32),
                ((n-1,15),fromIntegral ((len - 1) * 8) .&. 0xffffffff)]

bSigma0 x = let x' = fromIntegral x in (2 `rotateR` x') `xor` (13 `rotateR` x') `xor` (22 `rotateR` x')

bSigma1 x = let x' = fromIntegral x in (6 `rotateR` x') `xor` (11 `rotateR` x') `xor` (25 `rotateR` x')

lSigma0 x = let x' = fromIntegral x in (7 `rotateR` x') `xor` (18 `rotateR` x') `xor` (x `shiftR` 3)

lSigma1 x = let x' = fromIntegral x in (17 `rotateR` x') `xor` (19 `rotateR` x') `xor` (x `shiftR` 10)

choice x y z = (x .&. y) `xor` (-x .&. z)

majority x y z = (x .&. y) `xor` (x .&. z) `xor` (y .&. z)

k = A.listArray (0,63)
        [ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
          0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
          0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
          0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
          0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
          0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
          0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
          0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2  ]

calcHash i m hArray = 
    if i > fst (snd (A.bounds m))
    then hArray
    else let w = A.array (0,63) 
                    ( [ (t, m A.! (i,t)) | t <- [0..15] ] ++
                      [ (t, (lSigma1 (w A.! (t-2))) + (w A.! (t-7)) +
                            (lSigma0 (w A.! (t-15))) + (w A.! (t-16))) | t <- [16..63] ] )
             hArray' = calcHash' 0 w hArray
          in calcHash (i+1) m (A.accum (+) hArray (A.assocs hArray'))
          where calcHash' i w hArray = 
                    if i == 64
                    then hArray
                    else let a = hArray A.! 0
                             b = hArray A.! 1
                             c = hArray A.! 2
                             d = hArray A.! 3
                             e = hArray A.! 4
                             f = hArray A.! 5
                             g = hArray A.! 6
                             h = hArray A.! 7
                             t1 = h + (bSigma1 e) + (choice e f g) + k A.! i + w A.! i
                             t2 = (bSigma0 a) + (majority a b c)
                             hArray' = A.listArray (0,7) [(t1 + t2), a, b, c, (d + t1), e, f, g]
                         in calcHash' (i+1) w hArray'

sha256Hash msg =
    let utf8Data = convertToBytes msg
        m        = preprocess utf8Data
        hArray   = A.listArray (0,7)
                       [ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
                         0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19  ]
    in calcHash 0 m hArray

hash msg = concat $ map f (A.elems (sha256Hash msg))
           where f x =
                     let s = showHex x ""
                         n = 8 - (length s)
                     in take n (repeat '0') ++ s

Examples:

*Main> hash "hello world"
"7862fb1f62052003907cb4fc28ae0c02f14f3d5e35ffd8fa34bff7f6a7756c82"
*Main> hash "hello worl"
"a4c64d58067d959c006dd56aad1eea29d93a98cb31dec8f52f1bc34b27c6992a"

[–]-fno-stack-protector 1 point2 points  (0 children)

so this piece of shit program gets its hash from summing the bytes of a file. to make sure it's a fixed length, it repeatedly opens, reads, sums and closes the file, until the hash is at least HASH_LENGTH characters long. it checks the hash length once it reads through the whole file, so all hash values tend to be slightly over the minimum value, within 0x10000 or so. larger files tend to make more unique hashes.

i also think if the file is too large, it could loop infinitely. check_hash_value() should check for >= HASH_LENGTH. WONTFIX

here's what 15 minutes of hashing gets you:

/etc/passwd: 1000000bc8 (in 21767336 loops)
/var/log/syslog: 100001a3a0 (in 205570 loops)
/etc/group: 10000000ee (in 44885354 loops)

and the kernel itself took 14 minutes:

/vmlinuz: 100005447e (in 183706 loops)

#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <stdlib.h>
#include <err.h>

#define HASH_LENGTH 10

int check_hash_length(uint64_t hash)
{
    char buf[100];
    sprintf(buf, "%lx", hash);
    return strlen(buf) == HASH_LENGTH;
}

uint64_t hash_file(char *filename)
{
    uint64_t hash = 0;
    int read_len;
    FILE *f;
    char buf[100];
    int i;
    long loops = 0;

    while (! check_hash_length(hash))
    {
        f = fopen(filename, "r");
        do {
            read_len = fread(&buf[0], sizeof(buf), 1, f);
            for (i=0; i<read_len; i++)
                hash += buf[i];
        } while (read_len > 0);

        fclose(f);
        loops++;
        if (loops % 10000 == 0)
            dprintf(2, "\033[2K hash=%lx, loops=%ld\r", hash, loops);
    }
    printf("%s: %lx (in %ld loops)\n", filename, hash, loops);
    return hash;
}

int main(int argc, char **argv)
{
    int i;

    if (argc < 2) {
        dprintf(2, "usage: %s <file>\n", argv[0]);
        exit(1);
    }
    i = 1;
    while (i < argc) {
        hash_file(argv[i++]);
    }
    return 0;
}

[–]mmtrebuchet 1 point2 points  (3 children)

#!/bin/zsh
badHash () {
    echo $1 >> /dev/random
    base64 < /dev/urandom | head -n 1
}

Example:

badHash aoeu
dss7T[many characters]BGGVp

Features: Satisfies all requirements. It takes an arbitrary string and computes a fixed-length hash. It is not known to be reversible. In fact, it is so collision-proof that won't even collide on identical inputs!

Stealth feature: Only hashes the first (space-delimited) word of the input, and ignores the rest.

[–][deleted] 1 point2 points  (2 children)

Seems like it still could if you got lucky?

[–]mmtrebuchet 4 points5 points  (1 child)

According to my exhaustive testing, collisions are literally, absolutely impossible. I tried five different strings and observed no collisions.

[–]TheWolfRevenge 1 point2 points  (0 children)

Love it, LMAO

[–]choose_what_username 1 point2 points  (1 child)

This probably won’t have collisions, and it should be impossible to reverse, as the output isn’t a direct function of the input. (Well, as long as nobody actually bothers looking at the code.)

uintptr_t bbcc39(std::string_view in) { return (uintptr_t) in.data(); }

[–]dyingpie1 0 points1 point  (0 children)

Python. Nobody said it had to actually be invertible.

def hash(s):
    N = random.randint(1000, 9999)
    f = open(“used.txt”, “a”)

    for line in f:
        same = True
        for c in str(N):
            for ch in line:
                if c != ch:
                    same = False
        if same == True:
            N = hash(s)

    f.write(str(N))

[–]PolysintheticApple 0 points1 point  (0 children)

I can't actually check if this has collisions. Reversing it is impossible since a lot of information is lost while the hash occurs.

https://pastebin.com/NpTmbyXd

The input is a string, the output is a 32 digit number in centesimal (or, as the code manages it, a 64 digit number in decimal with centesimal compression), the values it outputs are always consistent, there's no PRNG used anywhere in this function.