-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsignature.go
104 lines (86 loc) · 2.07 KB
/
signature.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
package phargo
import (
"bytes"
"crypto/md5"
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"encoding/binary"
"errors"
"hash"
"io"
"os"
)
type signature struct {
options Options
}
// http://php.net/manual/en/phar.fileformat.signature.php
func (s *signature) check(filename string) error {
file, _ := os.Open(filename)
defer func() {
_ = file.Close()
}()
stat, err := file.Stat()
if err != nil {
return errors.New("can't stat file: " + err.Error())
}
_, err = file.Seek(-8, 2)
if err != nil {
return errors.New("can't seek file: " + err.Error())
}
type sBinary struct {
Flag uint32
Gbmb uint32
}
var sb sBinary
err = binary.Read(file, binary.LittleEndian, &sb)
if err != nil {
return errors.New("can't read signature bytes: " + err.Error())
}
if sb.Gbmb != 1112359495 { //GBMB string
return errors.New("can't find GBMB constant at the end")
}
hasher, algorithm, signatureLength := s.getHash(sb.Flag)
if hasher == nil {
return nil
}
_, err = file.Seek(-(8 + signatureLength), 2)
if err != nil {
return errors.New("can't seek file: " + err.Error())
}
fileSig := make([]byte, signatureLength)
_, err = file.Read(fileSig)
if err != nil {
return errors.New("can't read file signature: " + err.Error())
}
_, err = file.Seek(0, 0)
if err != nil {
return errors.New("can't seek file: " + err.Error())
}
if _, err := io.CopyN(hasher, file, stat.Size()-signatureLength-8); err != nil {
return errors.New("can't copy buffer to hasher: " + err.Error())
}
if !bytes.Equal(hasher.Sum(nil), fileSig) {
return errors.New(algorithm + " hash of file is incorrect")
}
return nil
}
func (s *signature) getHash(flag uint32) (hash.Hash, string, int64) {
const (
sigMD5 = 0x0001 //PHAR_SIG_MD5
sigSHA1 = 0x0002 //PHAR_SIG_SHA1
sigSHA256 = 0x0003 //PHAR_SIG_SHA256
sigSHA512 = 0x0004 //PHAR_SIG_SHA512
)
switch flag {
case sigMD5:
return md5.New(), "MD5", 16
case sigSHA1:
return sha1.New(), "SHA1", 20
case sigSHA256:
return sha256.New(), "SHA256", 32
case sigSHA512:
return sha512.New(), "SHA512", 64
}
return nil, "", 0
}