Teach sigtool to mark the last block (eof).
This commit is contained in:
parent
f82c1336ac
commit
a9c17988c4
3 changed files with 88 additions and 59 deletions
|
@ -30,8 +30,9 @@ import (
|
|||
)
|
||||
|
||||
// Encryption chunk size = 4MB
|
||||
const chunkSize int = 4 * 1048576
|
||||
const maxChunkSize int = 16 * 1048576
|
||||
const chunkSize uint32 = 4 * 1048576
|
||||
const maxChunkSize uint32 = 16 * 1048576
|
||||
const EOF uint32 = 1 << 31
|
||||
|
||||
const _Magic = "SigTool"
|
||||
const _MagicLen = len(_Magic)
|
||||
|
@ -58,13 +59,14 @@ func NewEncryptor(sk *PrivateKey, blksize uint64) (*Encryptor, error) {
|
|||
return nil, fmt.Errorf("encrypt: Blocksize is too large (max 16M)")
|
||||
}
|
||||
|
||||
if blksize == 0 {
|
||||
blksize = uint64(chunkSize)
|
||||
blksz := uint32(blksize)
|
||||
if blksz == 0 {
|
||||
blksz = chunkSize
|
||||
}
|
||||
|
||||
e := &Encryptor{
|
||||
Header: Header{
|
||||
ChunkSize: uint32(blksize),
|
||||
ChunkSize: blksz,
|
||||
Salt: make([]byte, _AEADNonceLen),
|
||||
},
|
||||
|
||||
|
@ -84,7 +86,7 @@ func NewEncryptor(sk *PrivateKey, blksize uint64) (*Encryptor, error) {
|
|||
return nil, fmt.Errorf("encrypt: %s", err)
|
||||
}
|
||||
|
||||
e.buf = make([]byte, chunkSize+4+e.ae.Overhead())
|
||||
e.buf = make([]byte, blksz+4+uint32(e.ae.Overhead()))
|
||||
return e, nil
|
||||
}
|
||||
|
||||
|
@ -176,15 +178,14 @@ func (e *Encryptor) Encrypt(rd io.Reader, wr io.Writer) error {
|
|||
}
|
||||
|
||||
buf := make([]byte, e.ChunkSize)
|
||||
i := 0
|
||||
|
||||
for {
|
||||
var i uint32
|
||||
var eof bool
|
||||
for !eof {
|
||||
n, err := io.ReadAtLeast(rd, buf, int(e.ChunkSize))
|
||||
if n == 0 {
|
||||
return nil
|
||||
}
|
||||
if n > 0 {
|
||||
err = e.encrypt(buf[:n], wr, i)
|
||||
eof = err == io.EOF || err == io.ErrClosedPipe
|
||||
if n >= 0 {
|
||||
err = e.encrypt(buf[:n], wr, i, eof)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -193,10 +194,11 @@ func (e *Encryptor) Encrypt(rd io.Reader, wr io.Writer) error {
|
|||
continue
|
||||
}
|
||||
|
||||
if err != nil && err != io.EOF {
|
||||
if err != nil && err != io.EOF && err != io.ErrClosedPipe {
|
||||
return fmt.Errorf("encrypt: I/O read error: %s", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// encrypt exactly _one_ block of data
|
||||
|
@ -204,12 +206,18 @@ func (e *Encryptor) Encrypt(rd io.Reader, wr io.Writer) error {
|
|||
// This protects the output stream from re-ordering attacks and length
|
||||
// modification attacks. The encoded length & block number is used as
|
||||
// additional data in the AEAD construction.
|
||||
func (e *Encryptor) encrypt(buf []byte, wr io.Writer, i int) error {
|
||||
func (e *Encryptor) encrypt(buf []byte, wr io.Writer, i uint32, eof bool) error {
|
||||
var b [8]byte
|
||||
var noncebuf [32]byte
|
||||
var z uint32 = uint32(e.ae.Overhead() + len(buf))
|
||||
|
||||
binary.BigEndian.PutUint32(b[:4], uint32(e.ae.Overhead()+len(buf)))
|
||||
binary.BigEndian.PutUint32(b[4:], uint32(i))
|
||||
// mark last block
|
||||
if eof {
|
||||
z |= EOF
|
||||
}
|
||||
|
||||
binary.BigEndian.PutUint32(b[:4], z)
|
||||
binary.BigEndian.PutUint32(b[4:], i)
|
||||
|
||||
h := sha256.New()
|
||||
h.Write(e.Salt)
|
||||
|
@ -248,7 +256,7 @@ func NewDecryptor(rd io.Reader) (*Decryptor, error) {
|
|||
|
||||
_, err := io.ReadFull(rd, b[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("decrypt: err while reading header: %s", err)
|
||||
}
|
||||
|
||||
if bytes.Compare(b[:_MagicLen], []byte(_Magic)) != 0 {
|
||||
|
@ -271,7 +279,7 @@ func NewDecryptor(rd io.Reader) (*Decryptor, error) {
|
|||
|
||||
_, err = io.ReadFull(rd, hdr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("decrypt: err while reading header: %s", err)
|
||||
}
|
||||
|
||||
verify := hdr[:32]
|
||||
|
@ -291,7 +299,7 @@ func NewDecryptor(rd io.Reader) (*Decryptor, error) {
|
|||
return nil, fmt.Errorf("decrypt: decode error: %s", err)
|
||||
}
|
||||
|
||||
if d.ChunkSize == 0 || d.ChunkSize >= uint32(maxChunkSize) {
|
||||
if d.ChunkSize == 0 || d.ChunkSize >= maxChunkSize {
|
||||
return nil, fmt.Errorf("decrypt: invalid chunkSize %d", d.ChunkSize)
|
||||
}
|
||||
|
||||
|
@ -370,12 +378,13 @@ func (d *Decryptor) Decrypt(wr io.Writer) error {
|
|||
return fmt.Errorf("decrypt: wrapped-key not decrypted (missing SetPrivateKey()?")
|
||||
}
|
||||
|
||||
for i := 0; ; i++ {
|
||||
c, err := d.decrypt(i)
|
||||
var i uint32
|
||||
for i = 0; ; i++ {
|
||||
c, eof, err := d.decrypt(i)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(c) == 0 {
|
||||
if eof || len(c) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -390,46 +399,53 @@ func (d *Decryptor) Decrypt(wr io.Writer) error {
|
|||
}
|
||||
|
||||
// Decrypt exactly one chunk of data
|
||||
func (d *Decryptor) decrypt(i int) ([]byte, error) {
|
||||
func (d *Decryptor) decrypt(i uint32) ([]byte, bool, error) {
|
||||
var b [8]byte
|
||||
var nonceb [32]byte
|
||||
|
||||
n, err := io.ReadFull(d.rd, b[:4])
|
||||
if n == 0 || err == io.EOF {
|
||||
return nil, nil
|
||||
if err == io.EOF || err == io.ErrClosedPipe || n == 0 {
|
||||
return nil, false, fmt.Errorf("decrypt: premature EOF-1 while reading block %d", i)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decrypt: can't read chunk %d length: %s", i, err)
|
||||
return nil, false, fmt.Errorf("decrypt: can't read chunk %d length: %s", i, err)
|
||||
}
|
||||
|
||||
chunklen := int(binary.BigEndian.Uint32(b[:4]))
|
||||
m := binary.BigEndian.Uint32(b[:4])
|
||||
eof := (m & EOF) > 0
|
||||
|
||||
m &= (EOF-1)
|
||||
|
||||
// Sanity check - in case of corrupt header
|
||||
if chunklen > (d.ae.Overhead() + chunkSize) {
|
||||
return nil, fmt.Errorf("decrypt: chunksize is too large (%d)", chunklen)
|
||||
if m > (uint32(d.ae.Overhead()) + chunkSize) {
|
||||
return nil, false, fmt.Errorf("decrypt: chunksize is too large (%d)", m)
|
||||
}
|
||||
|
||||
binary.BigEndian.PutUint32(b[4:], uint32(i))
|
||||
binary.BigEndian.PutUint32(b[4:], i)
|
||||
h := sha256.New()
|
||||
h.Write(d.Salt)
|
||||
h.Write(b[:])
|
||||
nonce := h.Sum(nonceb[:0])
|
||||
|
||||
n, err = io.ReadFull(d.rd, d.buf[:chunklen])
|
||||
if n == 0 || err == io.EOF {
|
||||
return nil, nil
|
||||
}
|
||||
var p []byte
|
||||
if m > 0 {
|
||||
n, err = io.ReadFull(d.rd, d.buf[:m])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decrypt: can't read chunk %d: %s", i, err)
|
||||
return nil, false, fmt.Errorf("decrypt: premature EOF-2 while reading block %d: %s", i, err)
|
||||
}
|
||||
|
||||
p, err := d.ae.Open(d.buf[:0], nonce, d.buf[:chunklen], b[:])
|
||||
p, err = d.ae.Open(d.buf[:0], nonce, d.buf[:n], b[:])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decrypt: can't decrypt chunk %d: %s", i, err)
|
||||
return nil, false, fmt.Errorf("decrypt: can't decrypt chunk %d: %s", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
return p, nil
|
||||
if eof && len(p) != 0 {
|
||||
return nil, false, fmt.Errorf("decrypt: EOF set on blk %d of len %d", i, m)
|
||||
}
|
||||
|
||||
return p, eof, nil
|
||||
}
|
||||
|
||||
// Wrap a shared key with the recipient's public key 'pk' by generating an ephemeral
|
||||
|
|
|
@ -64,6 +64,18 @@ func tempdir(t *testing.T) string {
|
|||
return tmp
|
||||
}
|
||||
|
||||
// return a hardcoded password
|
||||
func hardcodedPw() ([]byte, error) {
|
||||
return []byte("abc"), nil
|
||||
}
|
||||
|
||||
func wrongPw() ([]byte, error) {
|
||||
return []byte("xyz"), nil
|
||||
}
|
||||
func emptyPw() ([]byte, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Return true if file exists, false otherwise
|
||||
func fileExists(fn string) bool {
|
||||
st, err := os.Stat(fn)
|
||||
|
@ -100,7 +112,7 @@ func Test0(t *testing.T) {
|
|||
dn := tempdir(t)
|
||||
bn := fmt.Sprintf("%s/t0", dn)
|
||||
|
||||
err = kp.Serialize(bn, "", "abc")
|
||||
err = kp.Serialize(bn, "", hardcodedPw)
|
||||
assert(err == nil, "keyPair.Serialize() fail")
|
||||
|
||||
pkf := fmt.Sprintf("%s.pub", bn)
|
||||
|
@ -110,32 +122,28 @@ func Test0(t *testing.T) {
|
|||
assert(fileExists(pkf), "missing pkf")
|
||||
assert(fileExists(skf), "missing skf")
|
||||
|
||||
// send wrong file and see what happens
|
||||
pk, err := ReadPublicKey(skf)
|
||||
assert(err != nil, "bad PK ReadPK fail")
|
||||
|
||||
pk, err = ReadPublicKey(pkf)
|
||||
pk, err := ReadPublicKey(pkf)
|
||||
assert(err == nil, "ReadPK() fail")
|
||||
|
||||
// -ditto- for Sk
|
||||
sk, err := ReadPrivateKey(pkf, "")
|
||||
assert(err != nil, "bad SK ReadSK fail")
|
||||
sk, err := ReadPrivateKey(pkf, emptyPw)
|
||||
assert(err != nil, "bad SK ReadSK fail: %s", err)
|
||||
|
||||
sk, err = ReadPrivateKey(skf, "")
|
||||
assert(err != nil, "ReadSK() empty pw fail")
|
||||
sk, err = ReadPrivateKey(skf, emptyPw)
|
||||
assert(err != nil, "ReadSK() empty pw fail: ks", err)
|
||||
|
||||
sk, err = ReadPrivateKey(skf, "abcdef")
|
||||
assert(err != nil, "ReadSK() wrong pw fail")
|
||||
sk, err = ReadPrivateKey(skf, wrongPw)
|
||||
assert(err != nil, "ReadSK() wrong pw fail: %s", err)
|
||||
|
||||
badf := fmt.Sprintf("%s/badf.key", dn)
|
||||
err = ioutil.WriteFile(badf, []byte(badsk), 0600)
|
||||
assert(err == nil, "write badsk")
|
||||
|
||||
sk, err = ReadPrivateKey(badf, "abc")
|
||||
assert(err != nil, "badsk read fail")
|
||||
sk, err = ReadPrivateKey(badf, hardcodedPw)
|
||||
assert(err != nil, "badsk read fail: %s", err)
|
||||
|
||||
// Finally, with correct password it should work.
|
||||
sk, err = ReadPrivateKey(skf, "abc")
|
||||
sk, err = ReadPrivateKey(skf, hardcodedPw)
|
||||
assert(err == nil, "ReadSK() correct pw fail")
|
||||
|
||||
// And, deserialized keys should be identical
|
||||
|
@ -186,11 +194,11 @@ func Test1(t *testing.T) {
|
|||
pkf := fmt.Sprintf("%s.pub", bn)
|
||||
skf := fmt.Sprintf("%s.key", bn)
|
||||
|
||||
err = kp.Serialize(bn, "", "")
|
||||
err = kp.Serialize(bn, "", emptyPw)
|
||||
assert(err == nil, "keyPair.Serialize() fail")
|
||||
|
||||
// Now read the private key and sign
|
||||
sk, err = ReadPrivateKey(skf, "")
|
||||
sk, err = ReadPrivateKey(skf, emptyPw)
|
||||
assert(err == nil, "readSK fail")
|
||||
|
||||
pk, err = ReadPublicKey(pkf)
|
||||
|
@ -262,6 +270,11 @@ func Benchmark_Sig(b *testing.B) {
|
|||
16,
|
||||
32,
|
||||
64,
|
||||
1024,
|
||||
4096,
|
||||
256*1024,
|
||||
1048576,
|
||||
4 * 1048576,
|
||||
}
|
||||
|
||||
b.StopTimer()
|
||||
|
|
2
version
2
version
|
@ -1 +1 @@
|
|||
0.4.0
|
||||
0.5.0
|
||||
|
|
Loading…
Add table
Reference in a new issue