github.com/f-secure-foundry/tamago@v0.0.0-20220307101044-d73fcdd7f11b/soc/imx6/dcp/sha.go (about) 1 // NXP Data Co-Processor (DCP) driver 2 // https://github.com/f-secure-foundry/tamago 3 // 4 // Copyright (c) F-Secure Corporation 5 // https://foundry.f-secure.com 6 // 7 // Use of this source code is governed by the license 8 // that can be found in the LICENSE file. 9 10 package dcp 11 12 import ( 13 "crypto/sha256" 14 "errors" 15 "io" 16 17 "golang.org/x/sync/semaphore" 18 ) 19 20 const blockSize = 64 21 22 // A single DCP channel is used for all operations, this entails that only one 23 // digest state can be kept at any given time. 24 var sem = semaphore.NewWeighted(1) 25 26 // Hash is the common interface to DCP hardware backed hash functions. 27 // 28 // While similar to Go native hash.Hash, this interface is not fully compatible 29 // with it as hardware errors must be checked and checksum computation affects 30 // state. 31 type Hash interface { 32 // Write (via the embedded io.Writer interface) adds more data to the running hash. 33 // It can return an error. It returns an error if Sum has been already invoked. 34 io.Writer 35 36 // Sum appends the current hash to b and returns the resulting slice. 37 // Its invocation terminates the digest instance, for this reason Write 38 // will return errors after Sum is invoked. 39 Sum(b []byte) ([]byte, error) 40 41 // BlockSize returns the hash's underlying block size. 42 // The Write method must be able to accept any amount 43 // of data, but it may operate more efficiently if all writes 44 // are a multiple of the block size. 45 BlockSize() int 46 } 47 48 type digest struct { 49 mode uint32 50 bs int 51 init bool 52 buf []byte 53 sum []byte 54 } 55 56 // New256 returns a new Digest computing the SHA256 checksum. 57 // 58 // A single DCP channel is used for all operations, this entails that only one 59 // digest instance can be kept at any given time, if this condition is not met 60 // an error is returned. 61 // 62 // The digest instance starts with New256() and terminates when when Sum() is 63 // invoked, after which the digest state can no longer be changed. 64 func New256() (Hash, error) { 65 if !sem.TryAcquire(1) { 66 return nil, errors.New("another digest instance is already in use") 67 } 68 69 d := &digest{ 70 mode: HASH_SELECT_SHA256, 71 bs: blockSize, 72 init: true, 73 buf: make([]byte, 0, blockSize), 74 } 75 76 return d, nil 77 } 78 79 // Write adds more data to the running hash. It returns an error if Sum has 80 // been already invoked or in case of hardware errors. 81 // 82 // There must be sufficient DMA memory allocated to hold the data, otherwise 83 // the function will panic. 84 func (d *digest) Write(p []byte) (n int, err error) { 85 if len(d.sum) != 0 { 86 return 0, errors.New("digest instance can no longer be used") 87 } 88 89 // If we still don't have enough data for a block, accumulate and early 90 // out. 91 if len(d.buf)+len(p) < d.bs { 92 d.buf = append(d.buf, p...) 93 return len(p), nil 94 } 95 96 pl := len(p) 97 98 // top up partial block buffer, and process that 99 cut := d.bs - len(d.buf) 100 d.buf = append(d.buf, p[:cut]...) 101 p = p[cut:] 102 103 _, err = hash(d.buf, d.mode, d.init, false) 104 105 if err != nil { 106 return 107 } 108 109 if d.init { 110 d.init = false 111 } 112 113 // work through any more full blocks in p 114 if l := len(p); l > d.bs { 115 r := l % d.bs 116 _, err = hash(p[:l-r], d.mode, d.init, false) 117 118 if err != nil { 119 return 120 } 121 122 p = p[l-r:] 123 } 124 125 // save off any partial block remaining 126 d.buf = append(d.buf[0:0], p...) 127 128 return pl, nil 129 } 130 131 // Sum appends the current hash to in and returns the resulting slice. Its 132 // invocation terminates the digest instance, for this reason Write will return 133 // errors after Sum is invoked. 134 func (d *digest) Sum(in []byte) (sum []byte, err error) { 135 if len(d.sum) != 0 { 136 return append(in, d.sum[:]...), nil 137 } 138 139 defer sem.Release(1) 140 141 if d.init && len(d.buf) == 0 { 142 d.sum = sha256.New().Sum(nil) 143 } else { 144 s, err := hash(d.buf, HASH_SELECT_SHA256, d.init, true) 145 146 if err != nil { 147 return nil, err 148 } 149 150 d.sum = s 151 } 152 153 return append(in, d.sum[:]...), nil 154 } 155 156 // BlockSize returns the hash's underlying block size. 157 func (d *digest) BlockSize() int { 158 return d.bs 159 } 160 161 // Sum256 returns the SHA256 checksum of the data. 162 // 163 // There must be sufficient DMA memory allocated to hold the data, otherwise 164 // the function will panic. 165 func Sum256(data []byte) (sum [32]byte, err error) { 166 s, err := hash(data, HASH_SELECT_SHA256, true, true) 167 168 if err != nil { 169 return 170 } 171 172 copy(sum[:], s) 173 174 return 175 }