71 lines
1.4 KiB
Go
71 lines
1.4 KiB
Go
// Copyright (C) 2019 Marius Schellenberger
|
|
|
|
package crypto
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"errors"
|
|
"golang.org/x/crypto/argon2"
|
|
"golang.org/x/crypto/chacha20poly1305"
|
|
"golang.org/x/crypto/ssh/terminal"
|
|
"io"
|
|
"os"
|
|
)
|
|
|
|
const (
|
|
SaltSize = 16
|
|
PrefixSize = SaltSize + chacha20poly1305.NonceSizeX
|
|
)
|
|
|
|
func randomBytes(l int) (b []byte) {
|
|
b = make([]byte, l)
|
|
_, err := rand.Read(b)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return
|
|
}
|
|
|
|
func kdf(password, salt []byte) []byte {
|
|
return argon2.IDKey(password, salt, 1, 64*1024, 4, chacha20poly1305.KeySize)
|
|
}
|
|
|
|
func Password() ([]byte, error) {
|
|
return terminal.ReadPassword(int(os.Stdin.Fd()))
|
|
}
|
|
|
|
func Encrypt(pass, src []byte, dst io.Writer) (err error) {
|
|
salt := randomBytes(SaltSize)
|
|
nonce := randomBytes(chacha20poly1305.NonceSizeX)
|
|
aead, err := chacha20poly1305.NewX(kdf(pass, salt))
|
|
if err != nil {
|
|
return
|
|
}
|
|
_, err = dst.Write(salt)
|
|
if err != nil {
|
|
return
|
|
}
|
|
_, err = dst.Write(nonce)
|
|
if err != nil {
|
|
return
|
|
}
|
|
_, err = dst.Write(aead.Seal(nil, nonce, src, nil))
|
|
return
|
|
}
|
|
|
|
func Decrypt(pass, src []byte, dst io.Writer) (err error) {
|
|
if len(src) <= PrefixSize {
|
|
return errors.New("input file corrupted")
|
|
}
|
|
nonce := src[SaltSize:PrefixSize]
|
|
aead, err := chacha20poly1305.NewX(kdf(pass, src[:SaltSize]))
|
|
if err != nil {
|
|
return
|
|
}
|
|
dec, err := aead.Open(nil, nonce, src[PrefixSize:], nil)
|
|
if err != nil {
|
|
return
|
|
}
|
|
_, err = dst.Write(dec)
|
|
return
|
|
}
|