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