Teach 'sigtool enc' to accept a user defined block size

This commit is contained in:
Sudhi Herle 2019-10-21 13:28:27 -07:00
parent d9755bc793
commit a347fdca79
7 changed files with 48 additions and 51 deletions

View file

@ -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
}

2
go.mod
View file

@ -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

2
go.sum
View file

@ -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=

View file

@ -1,4 +1,4 @@
// cipher.go -- Ed25519 based encrypt/decrypt
// encrypt.go -- Ed25519 based encrypt/decrypt
//
// (c) 2016 Sudhi Herle <sudhi@herle.net>
//
@ -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

View file

@ -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),
}

View file

@ -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)

View file

@ -1 +1 @@
0.2.0
0.3.0