overdue
This commit is contained in:
94
.rclone_repo/fs/config/obscure/obscure.go
Executable file
94
.rclone_repo/fs/config/obscure/obscure.go
Executable file
@@ -0,0 +1,94 @@
|
||||
// Package obscure contains the Obscure and Reveal commands
|
||||
package obscure
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"io"
|
||||
"log"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// crypt internals
|
||||
var (
|
||||
cryptKey = []byte{
|
||||
0x9c, 0x93, 0x5b, 0x48, 0x73, 0x0a, 0x55, 0x4d,
|
||||
0x6b, 0xfd, 0x7c, 0x63, 0xc8, 0x86, 0xa9, 0x2b,
|
||||
0xd3, 0x90, 0x19, 0x8e, 0xb8, 0x12, 0x8a, 0xfb,
|
||||
0xf4, 0xde, 0x16, 0x2b, 0x8b, 0x95, 0xf6, 0x38,
|
||||
}
|
||||
cryptBlock cipher.Block
|
||||
cryptRand = rand.Reader
|
||||
)
|
||||
|
||||
// crypt transforms in to out using iv under AES-CTR.
|
||||
//
|
||||
// in and out may be the same buffer.
|
||||
//
|
||||
// Note encryption and decryption are the same operation
|
||||
func crypt(out, in, iv []byte) error {
|
||||
if cryptBlock == nil {
|
||||
var err error
|
||||
cryptBlock, err = aes.NewCipher(cryptKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
stream := cipher.NewCTR(cryptBlock, iv)
|
||||
stream.XORKeyStream(out, in)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Obscure a value
|
||||
//
|
||||
// This is done by encrypting with AES-CTR
|
||||
func Obscure(x string) (string, error) {
|
||||
plaintext := []byte(x)
|
||||
ciphertext := make([]byte, aes.BlockSize+len(plaintext))
|
||||
iv := ciphertext[:aes.BlockSize]
|
||||
if _, err := io.ReadFull(cryptRand, iv); err != nil {
|
||||
return "", errors.Wrap(err, "failed to read iv")
|
||||
}
|
||||
if err := crypt(ciphertext[aes.BlockSize:], plaintext, iv); err != nil {
|
||||
return "", errors.Wrap(err, "encrypt failed")
|
||||
}
|
||||
return base64.RawURLEncoding.EncodeToString(ciphertext), nil
|
||||
}
|
||||
|
||||
// MustObscure obscures a value, exiting with a fatal error if it failed
|
||||
func MustObscure(x string) string {
|
||||
out, err := Obscure(x)
|
||||
if err != nil {
|
||||
log.Fatalf("Obscure failed: %v", err)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// Reveal an obscured value
|
||||
func Reveal(x string) (string, error) {
|
||||
ciphertext, err := base64.RawURLEncoding.DecodeString(x)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "base64 decode failed when revealing password - is it obscured?")
|
||||
}
|
||||
if len(ciphertext) < aes.BlockSize {
|
||||
return "", errors.New("input too short when revealing password - is it obscured?")
|
||||
}
|
||||
buf := ciphertext[aes.BlockSize:]
|
||||
iv := ciphertext[:aes.BlockSize]
|
||||
if err := crypt(buf, buf, iv); err != nil {
|
||||
return "", errors.Wrap(err, "decrypt failed when revealing password - is it obscured?")
|
||||
}
|
||||
return string(buf), nil
|
||||
}
|
||||
|
||||
// MustReveal reveals an obscured value, exiting with a fatal error if it failed
|
||||
func MustReveal(x string) string {
|
||||
out, err := Reveal(x)
|
||||
if err != nil {
|
||||
log.Fatalf("Reveal failed: %v", err)
|
||||
}
|
||||
return out
|
||||
}
|
||||
60
.rclone_repo/fs/config/obscure/obscure_test.go
Executable file
60
.rclone_repo/fs/config/obscure/obscure_test.go
Executable file
@@ -0,0 +1,60 @@
|
||||
package obscure
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestObscure(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
in string
|
||||
want string
|
||||
iv string
|
||||
}{
|
||||
{"", "YWFhYWFhYWFhYWFhYWFhYQ", "aaaaaaaaaaaaaaaa"},
|
||||
{"potato", "YWFhYWFhYWFhYWFhYWFhYXMaGgIlEQ", "aaaaaaaaaaaaaaaa"},
|
||||
{"potato", "YmJiYmJiYmJiYmJiYmJiYp3gcEWbAw", "bbbbbbbbbbbbbbbb"},
|
||||
} {
|
||||
cryptRand = bytes.NewBufferString(test.iv)
|
||||
got, err := Obscure(test.in)
|
||||
cryptRand = rand.Reader
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, test.want, got)
|
||||
recoveredIn, err := Reveal(got)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, test.in, recoveredIn, "not bidirectional")
|
||||
// Now the Must variants
|
||||
cryptRand = bytes.NewBufferString(test.iv)
|
||||
got = MustObscure(test.in)
|
||||
cryptRand = rand.Reader
|
||||
assert.Equal(t, test.want, got)
|
||||
recoveredIn = MustReveal(got)
|
||||
assert.Equal(t, test.in, recoveredIn, "not bidirectional")
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func TestReveal(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
in string
|
||||
want string
|
||||
iv string
|
||||
}{
|
||||
{"YWFhYWFhYWFhYWFhYWFhYQ", "", "aaaaaaaaaaaaaaaa"},
|
||||
{"YWFhYWFhYWFhYWFhYWFhYXMaGgIlEQ", "potato", "aaaaaaaaaaaaaaaa"},
|
||||
{"YmJiYmJiYmJiYmJiYmJiYp3gcEWbAw", "potato", "bbbbbbbbbbbbbbbb"},
|
||||
} {
|
||||
cryptRand = bytes.NewBufferString(test.iv)
|
||||
got, err := Reveal(test.in)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, test.want, got)
|
||||
// Now the Must variants
|
||||
cryptRand = bytes.NewBufferString(test.iv)
|
||||
got = MustReveal(test.in)
|
||||
assert.Equal(t, test.want, got)
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user