From a347fdca79aed229f2b370f0dc697dc1add62867 Mon Sep 17 00:00:00 2001 From: Sudhi Herle Date: Mon, 21 Oct 2019 13:28:27 -0700 Subject: [PATCH] Teach 'sigtool enc' to accept a user defined block size --- crypt.go | 10 ++++++- go.mod | 2 +- go.sum | 2 ++ sign/encrypt.go | 76 +++++++++++++++++++++-------------------------- sign/sign.go | 6 +--- sign/sign_test.go | 1 - version | 2 +- 7 files changed, 48 insertions(+), 51 deletions(-) diff --git a/crypt.go b/crypt.go index e02376a..2995026 100644 --- a/crypt.go +++ b/crypt.go @@ -35,17 +35,24 @@ func encrypt(args []string) { var keyfile string var envpw string var pw bool + var sblksize string fs.StringVarP(&outfile, "outfile", "o", "", "Write the output to file `F`") fs.StringVarP(&keyfile, "sign", "s", "", "Sign using private key `S`") fs.BoolVarP(&pw, "password", "p", false, "Ask for passphrase to decrypt the private key") fs.StringVarP(&envpw, "env-password", "", "", "Use passphrase from environment variable `E`") + fs.StringVarP(&sblksize, "block-size", "B", "4M", "Use `S` as the encryption block size") err := fs.Parse(args) if err != nil { die("%s", err) } + blksize, err := utils.ParseSize(sblksize) + if err != nil { + die("%s", err) + } + var pws, infile string if len(envpw) > 0 { @@ -108,7 +115,7 @@ func encrypt(args []string) { outfd = outf } - en, err := sign.NewEncryptor(sk) + en, err := sign.NewEncryptor(sk, blksize) if err != nil { die("%s", err) } @@ -277,3 +284,4 @@ func mustOpen(fn string, flag int) *os.File { } return fdk } + diff --git a/go.mod b/go.mod index ef96194..39cbc19 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.13 require ( github.com/gogo/protobuf v1.3.1 - github.com/opencoff/go-utils v0.3.0 + github.com/opencoff/go-utils v0.4.0 github.com/opencoff/pflag v0.3.3 golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc gopkg.in/yaml.v2 v2.2.4 diff --git a/go.sum b/go.sum index e318adb..aff4d00 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,8 @@ github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQL github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/opencoff/go-utils v0.3.0 h1:/TQXjf50o3GSB9MItog5L8Gf4GWJ4B5+rmqjB4g2RZQ= github.com/opencoff/go-utils v0.3.0/go.mod h1:c+7QUAiCCHcNH6OGvsZ0fviG7cgse8Y3ucg+xy7sGXM= +github.com/opencoff/go-utils v0.4.0 h1:pu08Om//u2+YGvLkHa2CyL6eI+/1J0bXih1Z6nuITp8= +github.com/opencoff/go-utils v0.4.0/go.mod h1:c+7QUAiCCHcNH6OGvsZ0fviG7cgse8Y3ucg+xy7sGXM= github.com/opencoff/pflag v0.3.3 h1:yohZkwYGPkB34WXvUQzU5GyLhImnjfePDARUaE8me3U= github.com/opencoff/pflag v0.3.3/go.mod h1:mTLzGGUGda1Av3d34iAJlh0JIlRxmFZtmc6qoWPspK0= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= diff --git a/sign/encrypt.go b/sign/encrypt.go index 454200a..bb691af 100644 --- a/sign/encrypt.go +++ b/sign/encrypt.go @@ -1,4 +1,4 @@ -// cipher.go -- Ed25519 based encrypt/decrypt +// encrypt.go -- Ed25519 based encrypt/decrypt // // (c) 2016 Sudhi Herle // @@ -14,22 +14,21 @@ package sign import ( + "bytes" "crypto/aes" "crypto/cipher" "crypto/ed25519" "crypto/sha256" "crypto/sha512" "crypto/subtle" + "encoding/binary" "fmt" "golang.org/x/crypto/curve25519" "golang.org/x/crypto/hkdf" "io" "math/big" - "bytes" - "encoding/binary" ) - // Encryption chunk size = 4MB const chunkSize int = 4 * 1048576 @@ -37,28 +36,35 @@ const _Magic = "SigTool" const _MagicLen = len(_Magic) const _AEADNonceLen = 32 - // Encryptor holds the encryption context type Encryptor struct { Header - key [32]byte // file encryption key + key [32]byte // file encryption key - ae cipher.AEAD - sender *PrivateKey + ae cipher.AEAD + sender *PrivateKey started bool buf []byte } -// Create a new Encryption context and use the optional private key 'sk' for +// Create a new Encryption context and use the optional private key 'sk' for // signing any recipient keys. If 'sk' is nil, then ephmeral Curve25519 keys // are generated and used with recipient's public key. -func NewEncryptor(sk *PrivateKey) (*Encryptor, error) { +func NewEncryptor(sk *PrivateKey, blksize uint64) (*Encryptor, error) { + + if blksize > (16 * 1048576) { + return nil, fmt.Errorf("encrypt: Blocksize is too large (max 16M)") + } + + if blksize == 0 { + blksize = uint64(chunkSize) + } e := &Encryptor{ Header: Header{ - ChunkSize: uint32(chunkSize), - Salt: make([]byte, _AEADNonceLen), + ChunkSize: uint32(blksize), + Salt: make([]byte, _AEADNonceLen), }, sender: sk, @@ -77,11 +83,10 @@ func NewEncryptor(sk *PrivateKey) (*Encryptor, error) { return nil, fmt.Errorf("encrypt: %s", err) } - e.buf = make([]byte, chunkSize + 4 + e.ae.Overhead()) + e.buf = make([]byte, chunkSize+4+e.ae.Overhead()) return e, nil } - // Add a new recipient to this encryption context. func (e *Encryptor) AddRecipient(pk *PublicKey) error { if e.started { @@ -104,7 +109,6 @@ func (e *Encryptor) AddRecipient(pk *PublicKey) error { return nil } - // Begin the encryption process by writing the header func (e *Encryptor) start(wr io.Writer) error { msize := e.Size() @@ -112,16 +116,16 @@ func (e *Encryptor) start(wr io.Writer) error { // marshal the header and recipients hdrlen := _MagicLen + 1 + 4 + sha256.Size - buf := make([]byte, hdrlen + msize) + buf := make([]byte, hdrlen+msize) hdrbuf := buf[hdrlen:] copy(buf[:], []byte(_Magic)) - buf[_MagicLen] = 1 // file version# + buf[_MagicLen] = 1 // file version# // The fixed header is the magic _and _ the length of the variable segment. // So, we capture the length of the variable portion first. - binary.BigEndian.PutUint32(buf[_MagicLen + 1:], uint32(sha256.Size + msize)) + binary.BigEndian.PutUint32(buf[_MagicLen+1:], uint32(sha256.Size+msize)) // Now marshal the variable portion _, err := e.MarshalToSizedBuffer(hdrbuf) @@ -130,7 +134,7 @@ func (e *Encryptor) start(wr io.Writer) error { } // and calculate the header checksum - cksum := buf[_MagicLen + 1 + 4:] + cksum := buf[_MagicLen+1+4:] h := sha256.New() h.Write(hdrbuf) h.Sum(cksum[:0]) @@ -161,7 +165,6 @@ func fullwrite(buf []byte, wr io.Writer) error { return nil } - // Encrypt the input stream 'rd' and write encrypted stream to 'wr' func (e *Encryptor) Encrypt(rd io.Reader, wr io.Writer) error { if !e.started { @@ -204,7 +207,7 @@ func (e *Encryptor) encrypt(buf []byte, wr io.Writer, i int) error { var b [8]byte var noncebuf [32]byte - binary.BigEndian.PutUint32(b[:4], uint32(e.ae.Overhead() + len(buf))) + binary.BigEndian.PutUint32(b[:4], uint32(e.ae.Overhead()+len(buf))) binary.BigEndian.PutUint32(b[4:], uint32(i)) h := sha256.New() @@ -225,26 +228,24 @@ func (e *Encryptor) encrypt(buf []byte, wr io.Writer, i int) error { return nil } - // Decryptor holds the decryption context type Decryptor struct { Header - ae cipher.AEAD - rd io.Reader + ae cipher.AEAD + rd io.Reader buf []byte // Decrypted key key []byte } - // Create a new decryption context and if 'pk' is given, check that it matches // the sender func NewDecryptor(rd io.Reader) (*Decryptor, error) { - var b [12]byte + var b [12]byte - _, err := io.ReadFull(rd, b[:]) + _, err := io.ReadFull(rd, b[:]) if err != nil { return nil, err } @@ -281,7 +282,7 @@ func NewDecryptor(rd io.Reader) (*Decryptor, error) { } d := &Decryptor{ - rd: rd, + rd: rd, } err = d.Header.Unmarshal(hdr) @@ -289,7 +290,7 @@ func NewDecryptor(rd io.Reader) (*Decryptor, error) { return nil, fmt.Errorf("decrypt: decode error: %s", err) } - if d.ChunkSize == 0 || d.ChunkSize > (16 * 1048576) { + if d.ChunkSize == 0 || d.ChunkSize > (16*1048576) { return nil, fmt.Errorf("decrypt: invalid chunkSize %d", d.ChunkSize) } @@ -343,7 +344,6 @@ func (d *Decryptor) SetPrivateKey(sk *PrivateKey, senderPk *PublicKey) error { return fmt.Errorf("decrypt: Can't find any public key to match the given private key") - havekey: aes, err := aes.NewCipher(d.key) if err != nil { @@ -354,7 +354,7 @@ havekey: if err != nil { return fmt.Errorf("decrypt: %s", err) } - d.buf = make([]byte, int(d.ChunkSize) + d.ae.Overhead()) + d.buf = make([]byte, int(d.ChunkSize)+d.ae.Overhead()) return nil } @@ -363,7 +363,6 @@ func (d *Decryptor) WrappedKeys() []*WrappedKey { return d.Keys } - // Decrypt the file and write to 'wr' func (d *Decryptor) Decrypt(wr io.Writer) error { if d.key == nil { @@ -378,7 +377,7 @@ func (d *Decryptor) Decrypt(wr io.Writer) error { if len(c) == 0 { return nil } - + if len(c) > 0 { err = fullwrite(c, wr) if err != nil { @@ -403,7 +402,6 @@ func (d *Decryptor) decrypt(i int) ([]byte, error) { return nil, fmt.Errorf("decrypt: can't read chunk %d length: %s", i, err) } - chunklen := int(binary.BigEndian.Uint32(b[:4])) binary.BigEndian.PutUint32(b[4:], uint32(i)) h := sha256.New() @@ -448,7 +446,6 @@ func (sk *PrivateKey) WrapKey(pk *PublicKey, key []byte) (*WrappedKey, error) { return wrapKey(pk, key, &ourSK) } - func wrapKey(pk *PublicKey, k []byte, ourSK *[32]byte) (*WrappedKey, error) { var curvePK, theirPK, shared [32]byte @@ -469,8 +466,6 @@ func wrapKey(pk *PublicKey, k []byte, ourSK *[32]byte) (*WrappedKey, error) { }, nil } - - // Unwrap a wrapped key using the private key 'sk' func (w *WrappedKey) UnwrapKey(sk *PrivateKey, senderPk *PublicKey) ([]byte, error) { var shared, theirPK, ourSK [32]byte @@ -501,7 +496,6 @@ func (w *WrappedKey) UnwrapKey(sk *PrivateKey, senderPk *PublicKey) ([]byte, err return key, nil } - // Convert an Ed25519 Private Key to Curve25519 Private key func (sk *PrivateKey) toCurve25519SK() []byte { if sk.ck == nil { @@ -565,8 +559,7 @@ func expand(shared, pk []byte) ([]byte, error) { return kek, err } - -// seal the data via AEAD after suitably expanding 'shared' +// seal the data via AEAD after suitably expanding 'shared' func aeadSeal(data, shared, pk []byte) ([]byte, []byte, error) { kek, err := expand(shared[:], pk) if err != nil { @@ -586,7 +579,7 @@ func aeadSeal(data, shared, pk []byte) ([]byte, []byte, error) { noncesize := ae.NonceSize() tagsize := ae.Overhead() - buf := make([]byte, tagsize + len(kek)) + buf := make([]byte, tagsize+len(kek)) nonce := make([]byte, noncesize) randread(nonce) @@ -624,7 +617,6 @@ func aeadOpen(data, nonce, shared, pk []byte) ([]byte, error) { return c, nil } - func clamp(k []byte) []byte { k[0] &= 248 k[31] &= 127 diff --git a/sign/sign.go b/sign/sign.go index daaca11..ad70313 100644 --- a/sign/sign.go +++ b/sign/sign.go @@ -223,7 +223,6 @@ func MakePrivateKey(yml []byte, pw string) (*PrivateKey, error) { return nil, fmt.Errorf("can't decode YAML:Verify: %s", err) } - // We take short passwords and extend them pwb := sha512.Sum512([]byte(pw)) @@ -250,7 +249,6 @@ func MakePrivateKey(yml []byte, pw string) (*PrivateKey, error) { return PrivateKeyFromBytes(skb) } - // Make a private key from 64-bytes of extended Ed25519 key func PrivateKeyFromBytes(skb []byte) (*PrivateKey, error) { if len(skb) != 64 { @@ -272,7 +270,6 @@ func PrivateKeyFromBytes(skb []byte) (*PrivateKey, error) { return sk, nil } - // Given a secret key, return the corresponding Public Key func (sk *PrivateKey) PublicKey() *PublicKey { return sk.pk @@ -481,7 +478,6 @@ func MakePublicKey(yml []byte) (*PublicKey, error) { return PublicKeyFromBytes(pk) } - // Make a public key from a byte string func PublicKeyFromBytes(b []byte) (*PublicKey, error) { if len(b) != 32 { @@ -489,7 +485,7 @@ func PublicKeyFromBytes(b []byte) (*PublicKey, error) { } pk := &PublicKey{ - Pk: make([]byte, 32), + Pk: make([]byte, 32), hash: pkhash(b), } diff --git a/sign/sign_test.go b/sign/sign_test.go index b29de39..54fb509 100644 --- a/sign/sign_test.go +++ b/sign/sign_test.go @@ -90,7 +90,6 @@ r: 8 p: 1 ` - // #1. Create new key pair, and read them back. func Test0(t *testing.T) { assert := newAsserter(t) diff --git a/version b/version index 0ea3a94..0d91a54 100644 --- a/version +++ b/version @@ -1 +1 @@ -0.2.0 +0.3.0