...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package apk
18
19 import (
20 "bytes"
21 "crypto"
22 "encoding/binary"
23
24 "github.com/pkg/errors"
25 "github.com/sassoftware/relic/lib/zipslicer"
26 )
27
28 const merkleBlock = 1048576
29
30
31 type merkleHasher struct {
32 hashes []crypto.Hash
33 blocks [][]byte
34 buf []byte
35 n int
36 count uint32
37 }
38
39 func newMerkleHasher(hashes []crypto.Hash) *merkleHasher {
40 return &merkleHasher{
41 buf: make([]byte, merkleBlock),
42 hashes: hashes,
43 blocks: make([][]byte, len(hashes)),
44 }
45 }
46
47 func (h *merkleHasher) block(block []byte) {
48 var pref [5]byte
49 pref[0] = 0xa5
50 binary.LittleEndian.PutUint32(pref[1:], uint32(len(block)))
51 for i, hash := range h.hashes {
52 d := hash.New()
53 d.Write(pref[:])
54 d.Write(block)
55 h.blocks[i] = d.Sum(h.blocks[i])
56 }
57 h.count++
58 }
59
60 func (h *merkleHasher) Write(d []byte) (int, error) {
61 w := len(d)
62
63 if h.n != 0 && h.n+len(d) >= merkleBlock {
64 n := h.n
65 copy(h.buf[n:merkleBlock], d)
66 d = d[merkleBlock-n:]
67 h.block(h.buf)
68 h.n = 0
69 }
70
71 for len(d) >= merkleBlock {
72 h.block(d[:merkleBlock])
73 d = d[merkleBlock:]
74 }
75
76 if len(d) != 0 {
77 copy(h.buf[h.n:], d)
78 h.n += len(d)
79 }
80 return w, nil
81 }
82
83 func (h *merkleHasher) flush() {
84 if h.n != 0 {
85 h.block(h.buf[:h.n])
86 h.n = 0
87 }
88 }
89
90
91 func (h *merkleHasher) Finish(inz *zipslicer.Directory, modified bool) ([][]byte, error) {
92
93
94 h.flush()
95
96
97
98 if inz.DirLoc >= (1 << 32) {
99 return nil, errors.New("ZIP64 is not yet supported")
100 }
101 var cdirEntries, endOfDir []byte
102 if modified {
103 var b1, b2 bytes.Buffer
104 if err := inz.WriteDirectory(&b1, &b2, false); err != nil {
105 return nil, err
106 }
107 cdirEntries = b1.Bytes()
108 endOfDir = b2.Bytes()
109 } else {
110 var err error
111 cdirEntries, endOfDir, err = inz.GetOriginalDirectory(true)
112 if err != nil {
113 return nil, err
114 }
115 }
116 h.Write(cdirEntries)
117 h.flush()
118
119 h.Write(endOfDir)
120 h.flush()
121
122 var pref [5]byte
123 pref[0] = 0x5a
124 binary.LittleEndian.PutUint32(pref[1:], h.count)
125 ret := make([][]byte, len(h.hashes))
126 for i, hash := range h.hashes {
127 master := hash.New()
128 master.Write(pref[:])
129 master.Write(h.blocks[i])
130 ret[i] = master.Sum(nil)
131 }
132 return ret, nil
133 }
134
View as plain text