mirror of
https://github.com/rclone/rclone.git
synced 2024-12-13 04:43:45 +08:00
e43b5ce5e5
This is possible now that we no longer support go1.12 and brings rclone into line with standard practices in the Go world. This also removes errors.New and errors.Errorf from lib/errors and prefers the stdlib errors package over lib/errors.
95 lines
2.4 KiB
Go
95 lines
2.4 KiB
Go
// Package obscure contains the Obscure and Reveal commands
|
|
package obscure
|
|
|
|
import (
|
|
"crypto/aes"
|
|
"crypto/cipher"
|
|
"crypto/rand"
|
|
"encoding/base64"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
)
|
|
|
|
// 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 "", fmt.Errorf("failed to read iv: %w", err)
|
|
}
|
|
if err := crypt(ciphertext[aes.BlockSize:], plaintext, iv); err != nil {
|
|
return "", fmt.Errorf("encrypt failed: %w", err)
|
|
}
|
|
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 "", fmt.Errorf("base64 decode failed when revealing password - is it obscured?: %w", err)
|
|
}
|
|
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 "", fmt.Errorf("decrypt failed when revealing password - is it obscured?: %w", err)
|
|
}
|
|
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
|
|
}
|