github.com/10XDev/rclone@v1.52.3-0.20200626220027-16af9ab76b2a/fs/config/obscure/obscure.go (about) 1 // Package obscure contains the Obscure and Reveal commands 2 package obscure 3 4 import ( 5 "crypto/aes" 6 "crypto/cipher" 7 "crypto/rand" 8 "encoding/base64" 9 "io" 10 "log" 11 12 "github.com/pkg/errors" 13 ) 14 15 // crypt internals 16 var ( 17 cryptKey = []byte{ 18 0x9c, 0x93, 0x5b, 0x48, 0x73, 0x0a, 0x55, 0x4d, 19 0x6b, 0xfd, 0x7c, 0x63, 0xc8, 0x86, 0xa9, 0x2b, 20 0xd3, 0x90, 0x19, 0x8e, 0xb8, 0x12, 0x8a, 0xfb, 21 0xf4, 0xde, 0x16, 0x2b, 0x8b, 0x95, 0xf6, 0x38, 22 } 23 cryptBlock cipher.Block 24 cryptRand = rand.Reader 25 ) 26 27 // crypt transforms in to out using iv under AES-CTR. 28 // 29 // in and out may be the same buffer. 30 // 31 // Note encryption and decryption are the same operation 32 func crypt(out, in, iv []byte) error { 33 if cryptBlock == nil { 34 var err error 35 cryptBlock, err = aes.NewCipher(cryptKey) 36 if err != nil { 37 return err 38 } 39 } 40 stream := cipher.NewCTR(cryptBlock, iv) 41 stream.XORKeyStream(out, in) 42 return nil 43 } 44 45 // Obscure a value 46 // 47 // This is done by encrypting with AES-CTR 48 func Obscure(x string) (string, error) { 49 plaintext := []byte(x) 50 ciphertext := make([]byte, aes.BlockSize+len(plaintext)) 51 iv := ciphertext[:aes.BlockSize] 52 if _, err := io.ReadFull(cryptRand, iv); err != nil { 53 return "", errors.Wrap(err, "failed to read iv") 54 } 55 if err := crypt(ciphertext[aes.BlockSize:], plaintext, iv); err != nil { 56 return "", errors.Wrap(err, "encrypt failed") 57 } 58 return base64.RawURLEncoding.EncodeToString(ciphertext), nil 59 } 60 61 // MustObscure obscures a value, exiting with a fatal error if it failed 62 func MustObscure(x string) string { 63 out, err := Obscure(x) 64 if err != nil { 65 log.Fatalf("Obscure failed: %v", err) 66 } 67 return out 68 } 69 70 // Reveal an obscured value 71 func Reveal(x string) (string, error) { 72 ciphertext, err := base64.RawURLEncoding.DecodeString(x) 73 if err != nil { 74 return "", errors.Wrap(err, "base64 decode failed when revealing password - is it obscured?") 75 } 76 if len(ciphertext) < aes.BlockSize { 77 return "", errors.New("input too short when revealing password - is it obscured?") 78 } 79 buf := ciphertext[aes.BlockSize:] 80 iv := ciphertext[:aes.BlockSize] 81 if err := crypt(buf, buf, iv); err != nil { 82 return "", errors.Wrap(err, "decrypt failed when revealing password - is it obscured?") 83 } 84 return string(buf), nil 85 } 86 87 // MustReveal reveals an obscured value, exiting with a fatal error if it failed 88 func MustReveal(x string) string { 89 out, err := Reveal(x) 90 if err != nil { 91 log.Fatalf("Reveal failed: %v", err) 92 } 93 return out 94 }