package ttunnel
|
|
|
|
import (
|
|
"crypto/sha512"
|
|
"hash"
|
|
)
|
|
|
|
// In order to generate matching certificates on a client and server, we need a
|
|
// deterministic reader for random data. The reader is seeded with the
|
|
// password and uses multiple hashings to generate additional bytes.
|
|
type RandReader struct {
|
|
seed []byte
|
|
close chan bool
|
|
stream chan byte
|
|
h hash.Hash
|
|
}
|
|
|
|
func NewRandReader(seed []byte) *RandReader {
|
|
rr := RandReader{
|
|
seed: seed,
|
|
close: make(chan bool),
|
|
stream: make(chan byte),
|
|
h: sha512.New(),
|
|
}
|
|
go rr.run()
|
|
return &rr
|
|
}
|
|
|
|
func (rr *RandReader) run() {
|
|
buf := []byte{}
|
|
|
|
for {
|
|
_, _ = rr.h.Write(rr.seed) // Never returns an error (see docs).
|
|
buf = buf[:]
|
|
buf = rr.h.Sum(buf)
|
|
|
|
for _, b := range buf {
|
|
select {
|
|
case <-rr.close:
|
|
return
|
|
|
|
case rr.stream <- b:
|
|
// Continue
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (rr *RandReader) Read(p []byte) (n int, err error) {
|
|
for i := range p {
|
|
p[i] = <-rr.stream
|
|
}
|
|
|
|
return len(p), nil
|
|
}
|
|
|
|
func (rr *RandReader) Close() {
|
|
rr.close <- true
|
|
}
|