-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 428132b
Showing
26 changed files
with
2,538 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package ecc | ||
|
||
import ( | ||
"crypto/aes" | ||
"crypto/cipher" | ||
"encoding/asn1" | ||
"strings" | ||
"github.com/pkg/errors" | ||
"golang.org/x/crypto/chacha20poly1305" | ||
) | ||
|
||
type Cipher struct { | ||
Name string | ||
Description string | ||
OID asn1.ObjectIdentifier | ||
KeySize int | ||
New func(key []byte) (cipher.AEAD, error) | ||
KDF *KDF | ||
} | ||
|
||
// Suppported ciphers | ||
var Ciphers = []*Cipher{ | ||
{ | ||
Name: "aes-128-gcm", | ||
OID: asn1.ObjectIdentifier{2,16,840,1,101,3,4,1,6}, | ||
KeySize: 16, | ||
New: newAESGCM, | ||
KDF: KDFs["hkdf-sha256"], | ||
}, | ||
{ | ||
Name: "aes-192-gcm", | ||
OID: asn1.ObjectIdentifier{2,16,840,1,101,3,4,1,26}, | ||
KeySize: 24, | ||
New: newAESGCM, | ||
KDF: KDFs["hkdf-sha256"], | ||
}, | ||
{ | ||
Name: "aes-256-gcm", | ||
OID: asn1.ObjectIdentifier{2,16,840,1,101,3,4,1,46}, | ||
KeySize: 32, | ||
New: newAESGCM, | ||
KDF: KDFs["hkdf-sha384"], | ||
}, | ||
{ | ||
Name: "chacha20-poly1305", | ||
OID: asn1.ObjectIdentifier{1,2,840,113549,1,9,16,3,18}, | ||
KeySize: 32, | ||
New: chacha20poly1305.New, | ||
KDF: KDFs["hkdf-sha384"], | ||
}, | ||
} | ||
|
||
func LookupCipher(name string) *Cipher { | ||
name = strings.ReplaceAll(strings.ReplaceAll(strings.ToLower(name), "-", ""), "_", "") | ||
for _, c := range Ciphers { | ||
if strings.ReplaceAll(c.Name, "-", "") == name { | ||
return c | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func newAESGCM(key []byte) (cipher.AEAD, error) { | ||
block, err := aes.NewCipher(key) | ||
if err != nil { | ||
return nil, errors.Wrapf(err, "init AES") | ||
} | ||
aead, err := cipher.NewGCM(block) | ||
if err != nil { | ||
return nil, errors.Wrapf(err, "init GCM") | ||
} | ||
return aead, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
dist/ | ||
ecc | ||
test.* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
before: | ||
hooks: | ||
- go mod tidy | ||
builds: | ||
- env: | ||
- CGO_ENABLED=0 | ||
goos: | ||
- linux | ||
- windows | ||
- darwin | ||
archives: | ||
- replacements: | ||
darwin: Darwin | ||
linux: Linux | ||
windows: Windows | ||
386: i386 | ||
amd64: x86_64 | ||
checksum: | ||
name_template: 'checksums.txt' | ||
snapshot: | ||
name_template: "{{ incpatch .Version }}-next" | ||
changelog: | ||
sort: asc | ||
filters: | ||
exclude: | ||
- '^docs:' | ||
- '^test:' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
package commands | ||
|
||
import ( | ||
"io" | ||
"os" | ||
"github.com/pkg/errors" | ||
log "github.com/sirupsen/logrus" | ||
"github.com/spf13/cobra" | ||
"github.com/thepax/ecc" | ||
"github.com/thepax/ecc/eccutil" | ||
) | ||
|
||
type DecryptOpts struct { | ||
Key string | ||
Verify string | ||
In string | ||
Out string | ||
} | ||
|
||
var decryptOpts DecryptOpts | ||
|
||
func DecryptCmd() *cobra.Command { | ||
cmd := &cobra.Command{ | ||
Use: "decrypt", | ||
Short: "Decrypt file or stream", | ||
Args: cobra.ExactArgs(0), | ||
PreRunE: func(cmd *cobra.Command, args []string) error { | ||
if decryptOpts.Key == "" { | ||
return errors.New("private key is not specified") | ||
} | ||
return nil | ||
}, | ||
Run: func(cmd *cobra.Command, args []string) { | ||
decryptRun(&decryptOpts) | ||
}, | ||
} | ||
cmd.Flags().StringVar(&decryptOpts.Key, "key", eccutil.GetenvDecryptKey(), "decrypt/private key") | ||
cmd.Flags().StringVar(&decryptOpts.Verify, "verify", eccutil.GetenvVerifyKey(), "public key") | ||
cmd.Flags().StringVarP(&decryptOpts.In, "in", "i", "", "input file (default is stdin)") | ||
cmd.Flags().StringVarP(&decryptOpts.Out, "out", "o", "", "output file (default is stdout)") | ||
return cmd | ||
} | ||
|
||
func decryptRun(opts *DecryptOpts) { | ||
var err error | ||
|
||
decryptKey, err := eccutil.GetPrivateKey("decrypting", opts.Key) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
verifyKey, err := eccutil.GetPublicKey("verifying", opts.Verify) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
var in *os.File | ||
if opts.In != "" { | ||
in, err = os.Open(opts.In) | ||
if err != nil { | ||
log.Fatal("open input: ", err) | ||
} | ||
defer in.Close() | ||
} else { | ||
in = os.Stdin | ||
} | ||
var out *os.File | ||
if opts.Out != "" { | ||
out, err = os.OpenFile(opts.Out, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666) | ||
if err != nil { | ||
log.Fatal("create output: ", err) | ||
} | ||
defer func() { | ||
if err == nil { | ||
err = out.Close() | ||
if err != nil { | ||
os.Remove(opts.Out) | ||
log.Fatal("close output: ", err) | ||
} | ||
} else { | ||
out.Close() | ||
os.Remove(opts.Out) | ||
} | ||
}() | ||
} else { | ||
out = os.Stdout | ||
} | ||
dec := &ecc.Decrypt{ | ||
PrivateKey: decryptKey, | ||
VerifyKey: verifyKey, | ||
Input: in, | ||
} | ||
_, err = io.Copy(out, dec) | ||
if err != nil { | ||
log.Fatal("decrypt: ", err) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
package commands | ||
|
||
import ( | ||
"crypto/rand" | ||
"io" | ||
"os" | ||
"os/exec" | ||
"github.com/pkg/errors" | ||
log "github.com/sirupsen/logrus" | ||
"github.com/spf13/cobra" | ||
"github.com/thepax/ecc" | ||
"github.com/thepax/ecc/eccutil" | ||
) | ||
|
||
type EditOpts struct { | ||
Cipher string | ||
Key string | ||
Rand string | ||
} | ||
|
||
var editOpts EditOpts | ||
|
||
func EditCmd() *cobra.Command { | ||
cmd := &cobra.Command{ | ||
Use: "edit [flags] filename.ecc", | ||
Short: "Edit an encrypted file", | ||
Args: cobra.ExactArgs(1), | ||
PreRunE: func(cmd *cobra.Command, args []string) error { | ||
if editOpts.Key == "" { | ||
return errors.New("private key is not specified") | ||
} | ||
return nil | ||
}, | ||
Run: func(cmd *cobra.Command, args []string) { | ||
editRun(&editOpts, args[0]) | ||
}, | ||
} | ||
cmd.Flags().StringVar(&editOpts.Cipher, "cipher", "aes-256-gcm", "encryption cipher") | ||
cmd.Flags().StringVar(&editOpts.Key, "key", eccutil.GetenvPrivateKey(), "private key") | ||
cmd.Flags().StringVar(&editOpts.Rand, "rand", "", "file to use for random number input") | ||
return cmd | ||
} | ||
|
||
func editRun(opts *EditOpts, filename string) { | ||
err := editDoRun(opts, filename) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
} | ||
|
||
func editDoRun(opts *EditOpts, filename string) error { | ||
privateKey, err := eccutil.GetPrivateKey("decrypting", opts.Key) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
randReader := rand.Reader | ||
if opts.Rand != "" { | ||
f, err := os.Open(opts.Rand) | ||
if err != nil { | ||
log.Fatal("open random number input: ", err) | ||
} | ||
randReader = f | ||
defer f.Close() | ||
} | ||
|
||
var f *os.File | ||
if _, err := os.Stat(filename); !os.IsNotExist(err) { | ||
f, err = os.OpenFile(filename, os.O_RDWR, 0600) | ||
if err != nil { | ||
return err | ||
} | ||
defer f.Close() | ||
} | ||
|
||
tmpf, err := os.CreateTemp("", "ecc*.txt") | ||
if err != nil { | ||
return err | ||
} | ||
tempfile := tmpf.Name() | ||
defer func() { | ||
if fi, err := os.Stat(tempfile); err == nil && fi.Size() > 0 { | ||
tmpf, err := os.OpenFile(tempfile, os.O_RDWR, 0600) | ||
if err == nil { | ||
io.CopyN(tmpf, randReader, fi.Size()) | ||
tmpf.Close() | ||
} | ||
} | ||
os.Remove(tempfile) | ||
}() | ||
|
||
if f != nil { | ||
dec := &ecc.Decrypt{ | ||
PrivateKey: privateKey, | ||
VerifyKey: &privateKey.PublicKey, | ||
Input: f, | ||
} | ||
_, err = io.Copy(tmpf, dec) | ||
if err != nil { | ||
tmpf.Close() | ||
return errors.Wrap(err, "decrypt") | ||
} | ||
} | ||
if err = tmpf.Close(); err != nil { | ||
return errors.Wrap(err, "decrypt") | ||
} | ||
|
||
editor := os.Getenv("EDITOR") | ||
if editor == "" { | ||
editor = "vi" | ||
} | ||
cmd := exec.Command(editor, tempfile) | ||
cmd.Stdin = os.Stdin | ||
cmd.Stdout = os.Stdout | ||
cmd.Stderr = os.Stderr | ||
if err := cmd.Run(); err != nil { | ||
return errors.Wrap(err, "run editor") | ||
} | ||
|
||
if f == nil { | ||
f, err = os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) | ||
if err != nil { | ||
return err | ||
} | ||
defer f.Close() | ||
} | ||
if _, err = f.Seek(0, os.SEEK_SET); err != nil { | ||
return err | ||
} | ||
|
||
tmpf, err = os.Open(tempfile) | ||
if err != nil { | ||
return errors.Wrap(err, "encrypt") | ||
} | ||
defer tmpf.Close() | ||
|
||
enc := &ecc.Encrypt{ | ||
PublicKey: &privateKey.PublicKey, | ||
SignKey: privateKey, | ||
Cipher: opts.Cipher, | ||
Output: f, | ||
Random: randReader, | ||
} | ||
_, err = io.Copy(enc, tmpf) | ||
if err != nil { | ||
return errors.Wrap(err, "encrypt") | ||
} | ||
if err = enc.Close(); err != nil { | ||
return errors.Wrap(err, "encrypt") | ||
} | ||
pos, err := f.Seek(0, os.SEEK_CUR) | ||
if err != nil { | ||
return errors.Wrap(err, "encrypt") | ||
} | ||
if err = f.Truncate(pos); err != nil { | ||
return errors.Wrap(err, "encrypt") | ||
} | ||
if err = f.Sync(); err != nil { | ||
return errors.Wrap(err, "encrypt") | ||
} | ||
return nil | ||
} |
Oops, something went wrong.