You've already forked postgres_exporter
mirror of
https://github.com/prometheus-community/postgres_exporter.git
synced 2025-08-09 15:42:47 +03:00
This commit implements a massive refactor of the repository, and moves the build system over to use Mage (magefile.org) which should allow seamless building across multiple platforms.
127 lines
3.0 KiB
Go
127 lines
3.0 KiB
Go
package rardecode
|
|
|
|
import (
|
|
"crypto/aes"
|
|
"crypto/cipher"
|
|
"io"
|
|
)
|
|
|
|
// cipherBlockReader implements Block Mode decryption of an io.Reader object.
|
|
type cipherBlockReader struct {
|
|
r io.Reader
|
|
mode cipher.BlockMode
|
|
inbuf []byte // input buffer for partial data block
|
|
outbuf []byte // output buffer used when output slice < block size
|
|
n int // bytes read from outbuf
|
|
err error
|
|
}
|
|
|
|
// read reads and decrypts one or more input blocks into p.
|
|
// len(p) must be >= cipher block size.
|
|
func (cr *cipherBlockReader) read(p []byte) (n int, err error) {
|
|
bs := cr.mode.BlockSize()
|
|
// round p down to a multiple of the block size
|
|
l := len(p) - len(p)%bs
|
|
p = p[:l]
|
|
|
|
l = len(cr.inbuf)
|
|
if l > 0 {
|
|
// copy any buffered input into p
|
|
copy(p, cr.inbuf)
|
|
cr.inbuf = cr.inbuf[:0]
|
|
}
|
|
// read data for at least one block
|
|
n, err = io.ReadAtLeast(cr.r, p[l:], bs-l)
|
|
n += l
|
|
p = p[:n]
|
|
|
|
l = n % bs
|
|
// check if p is a multiple of the cipher block size
|
|
if l > 0 {
|
|
n -= l
|
|
// save trailing partial block to process later
|
|
cr.inbuf = append(cr.inbuf, p[n:]...)
|
|
p = p[:n]
|
|
}
|
|
|
|
if err != nil {
|
|
if err == io.ErrUnexpectedEOF || err == io.ErrShortBuffer {
|
|
// ignore trailing bytes < block size length
|
|
err = io.EOF
|
|
}
|
|
return 0, err
|
|
}
|
|
cr.mode.CryptBlocks(p, p) // decrypt block(s)
|
|
return n, nil
|
|
}
|
|
|
|
// Read reads and decrypts data into p.
|
|
// If the input is not a multiple of the cipher block size,
|
|
// the trailing bytes will be ignored.
|
|
func (cr *cipherBlockReader) Read(p []byte) (n int, err error) {
|
|
for {
|
|
if cr.n < len(cr.outbuf) {
|
|
// return buffered output
|
|
n = copy(p, cr.outbuf[cr.n:])
|
|
cr.n += n
|
|
return n, nil
|
|
}
|
|
if cr.err != nil {
|
|
err = cr.err
|
|
cr.err = nil
|
|
return 0, err
|
|
}
|
|
if len(p) >= cap(cr.outbuf) {
|
|
break
|
|
}
|
|
// p is not large enough to process a block, use outbuf instead
|
|
n, cr.err = cr.read(cr.outbuf[:cap(cr.outbuf)])
|
|
cr.outbuf = cr.outbuf[:n]
|
|
cr.n = 0
|
|
}
|
|
// read blocks into p
|
|
return cr.read(p)
|
|
}
|
|
|
|
// ReadByte returns the next decrypted byte.
|
|
func (cr *cipherBlockReader) ReadByte() (byte, error) {
|
|
for {
|
|
if cr.n < len(cr.outbuf) {
|
|
c := cr.outbuf[cr.n]
|
|
cr.n++
|
|
return c, nil
|
|
}
|
|
if cr.err != nil {
|
|
err := cr.err
|
|
cr.err = nil
|
|
return 0, err
|
|
}
|
|
// refill outbuf
|
|
var n int
|
|
n, cr.err = cr.read(cr.outbuf[:cap(cr.outbuf)])
|
|
cr.outbuf = cr.outbuf[:n]
|
|
cr.n = 0
|
|
}
|
|
}
|
|
|
|
// newCipherBlockReader returns a cipherBlockReader that decrypts the given io.Reader using
|
|
// the provided block mode cipher.
|
|
func newCipherBlockReader(r io.Reader, mode cipher.BlockMode) *cipherBlockReader {
|
|
cr := &cipherBlockReader{r: r, mode: mode}
|
|
cr.outbuf = make([]byte, 0, mode.BlockSize())
|
|
cr.inbuf = make([]byte, 0, mode.BlockSize())
|
|
return cr
|
|
}
|
|
|
|
// newAesDecryptReader returns a cipherBlockReader that decrypts input from a given io.Reader using AES.
|
|
// It will panic if the provided key is invalid.
|
|
func newAesDecryptReader(r io.Reader, key, iv []byte) *cipherBlockReader {
|
|
block, err := aes.NewCipher(key)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
mode := cipher.NewCBCDecrypter(block, iv)
|
|
|
|
return newCipherBlockReader(r, mode)
|
|
}
|