-
Notifications
You must be signed in to change notification settings - Fork 0
/
crush.go
131 lines (114 loc) · 3.15 KB
/
crush.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
//File hasher for when speed is more important
//than security and we just want to verify
//that file transfers were complete.
//Approx. 3X+ faster than md5sum w/ half the bits.
//Only non-core hash values escape to heap.
package main
import (
"bufio"
"encoding/hex"
"encoding/binary"
"fmt"
"os"
)
//Basic world values
const readSize int = 4096000
const stateByteCnt = 8
func main () {
//Input argument sanity check
if len(os.Args) != 2 {
fmt.Println("Usage: crush filename")
os.Exit(0)
}
//File sanity checking
fileCheck, _ := os.Stat(os.Args[1])
if fileCheck == nil {
os.Stderr.WriteString("File does not exist!\n")
os.Exit(0)
} else if fileCheck.IsDir() {
os.Stderr.WriteString("Given file is a directory!\n")
os.Exit(0)
}
//Open file for reading
inFile, _ := os.OpenFile(os.Args[1],os.O_RDONLY,0666)
defer inFile.Close()
//Make read buffer
bufRdr := bufio.NewReaderSize(inFile, readSize)
//Initial state (sqrt(3))
stateHex := "1c98c677de371c7d"
stateBytes := make([]byte, stateByteCnt)
hex.Decode(stateBytes, []byte(stateHex))
state := binary.BigEndian.Uint64(stateBytes)
//Buffer for reads into hasher
data := make([]byte, readSize)
//Length for handling block size
length := readSize
//Hashing core XORs every 64bits & fills incomplete blocks
for {
n, _ := bufRdr.Read(data)
if n == 0 {
break
}
//If not 64bits fill with 01010101
if n % stateByteCnt != 0 {
fillCnt := stateByteCnt - (n % stateByteCnt)
length = n + fillCnt
for i := 0; i < fillCnt; i++ {
data[n+i] = byte(55)
}
}
//XOR every 64bits with the state
for i := 0; i < length / stateByteCnt; i++ {
val64 := binary.BigEndian.Uint64(data[i*stateByteCnt:i*stateByteCnt+stateByteCnt])
state ^= val64
}
}
//XOR the file size with the state before
//extrapolation to give different hashes
//if two different files are all zeroes.
state ^= uint64(fileCheck.Size())
//Convert 64bit uint back to bytes for nlfsr
binary.BigEndian.PutUint64(stateBytes[0:stateByteCnt], state)
//Extrapolate state by use of nlfsr
nlfsr(stateBytes)
//Convert raw bytes back into hex string for printing
hashHexBytes := make([]byte, hex.EncodedLen(len(stateBytes)))
hex.Encode(hashHexBytes, stateBytes)
hashStr := fmt.Sprintf("%s", hashHexBytes)
//Print output
if hashStr == "34bb40235c3fc44b" {
os.Stderr.WriteString("Hash is the base state because the file has no bits!\n")
fmt.Printf("%s %s\n", hashHexBytes, os.Args[1])
} else {
fmt.Printf("%s %s\n", hashHexBytes, os.Args[1])
}
return
}
//Non-Linear Feed Shift Register for extrapolating raw state.
//This makes every input bit affect the rest of the state.
func nlfsr (src []byte) []byte {
dst := make([]byte, stateByteCnt)
for i := 0; i < stateByteCnt; i++ {
for j := 0; j < stateByteCnt; j++ {
dst = append(src[1:8],src[0]^src[1]^src[2]^src[3]^src[4]^src[5]^src[6]^src[7])
copy(src,dst)
src[0] += dst[7]
src[1] += dst[6]
src[2] += dst[5]
src[3] += dst[4]
src[4] += dst[3]
src[5] += dst[2]
src[6] += dst[1]
src[7] += dst[0]
}
src[0] ^= 255
src[1] += 128
src[2] ^= 255
src[3] += 128
src[4] ^= 255
src[5] += 128
src[6] ^= 255
src[7] += 128
}
return dst
}