forked from TrueCloudLab/rclone
Re-implement Obscure/Reveal so they use AES-CTR encryption
This commit is contained in:
parent
ebb67c135e
commit
6a4e424630
9 changed files with 127 additions and 32 deletions
|
@ -34,7 +34,7 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
rcloneClientID = "amzn1.application-oa2-client.6bf18d2d1f5b485c94c8988bb03ad0e7"
|
rcloneClientID = "amzn1.application-oa2-client.6bf18d2d1f5b485c94c8988bb03ad0e7"
|
||||||
rcloneEncryptedClientSecret = "k8/NyszKm5vEkZXAwsbGkd6C3NrbjIqMg4qEhIeF14Szub2wur+/teS3ubXgsLe9//+tr/qoqK+lq6mg8vWkoA=="
|
rcloneEncryptedClientSecret = "ZP12wYlGw198FtmqfOxyNAGXU3fwVcQdmt--ba1d00wJnUs0LOzvVyXVDbqhbcUqnr5Vd1QejwWmiv1Ep7UJG1kUQeuBP5n9goXWd5MrAf0"
|
||||||
folderKind = "FOLDER"
|
folderKind = "FOLDER"
|
||||||
fileKind = "FILE"
|
fileKind = "FILE"
|
||||||
assetKind = "ASSET"
|
assetKind = "ASSET"
|
||||||
|
@ -57,7 +57,7 @@ var (
|
||||||
TokenURL: "https://api.amazon.com/auth/o2/token",
|
TokenURL: "https://api.amazon.com/auth/o2/token",
|
||||||
},
|
},
|
||||||
ClientID: rcloneClientID,
|
ClientID: rcloneClientID,
|
||||||
ClientSecret: fs.Reveal(rcloneEncryptedClientSecret),
|
ClientSecret: fs.MustReveal(rcloneEncryptedClientSecret),
|
||||||
RedirectURL: oauthutil.RedirectURL,
|
RedirectURL: oauthutil.RedirectURL,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -30,7 +30,7 @@ import (
|
||||||
// Constants
|
// Constants
|
||||||
const (
|
const (
|
||||||
rcloneClientID = "202264815644.apps.googleusercontent.com"
|
rcloneClientID = "202264815644.apps.googleusercontent.com"
|
||||||
rcloneEncryptedClientSecret = "8p/yms3OlNXE9OTDl/HLypf9gdiJ5cT3"
|
rcloneEncryptedClientSecret = "eX8GpZTVx3vxMWVkuuBdDWmAUE6rGhTwVrvG9GhllYccSdj2-mvHVg"
|
||||||
driveFolderType = "application/vnd.google-apps.folder"
|
driveFolderType = "application/vnd.google-apps.folder"
|
||||||
timeFormatIn = time.RFC3339
|
timeFormatIn = time.RFC3339
|
||||||
timeFormatOut = "2006-01-02T15:04:05.000000000Z07:00"
|
timeFormatOut = "2006-01-02T15:04:05.000000000Z07:00"
|
||||||
|
@ -57,7 +57,7 @@ var (
|
||||||
Scopes: []string{"https://www.googleapis.com/auth/drive"},
|
Scopes: []string{"https://www.googleapis.com/auth/drive"},
|
||||||
Endpoint: google.Endpoint,
|
Endpoint: google.Endpoint,
|
||||||
ClientID: rcloneClientID,
|
ClientID: rcloneClientID,
|
||||||
ClientSecret: fs.Reveal(rcloneEncryptedClientSecret),
|
ClientSecret: fs.MustReveal(rcloneEncryptedClientSecret),
|
||||||
RedirectURL: oauthutil.TitleBarRedirectURL,
|
RedirectURL: oauthutil.TitleBarRedirectURL,
|
||||||
}
|
}
|
||||||
mimeTypeToExtension = map[string]string{
|
mimeTypeToExtension = map[string]string{
|
||||||
|
|
|
@ -29,7 +29,7 @@ import (
|
||||||
// Constants
|
// Constants
|
||||||
const (
|
const (
|
||||||
rcloneAppKey = "5jcck7diasz0rqy"
|
rcloneAppKey = "5jcck7diasz0rqy"
|
||||||
rcloneEncryptedAppSecret = "m8WRxJ6b1Z/Y25fDwJWS"
|
rcloneEncryptedAppSecret = "fRS5vVLr2v6FbyXYnIgjwBuUAt0osq_QZTXAEcmZ7g"
|
||||||
metadataLimit = dropbox.MetadataLimitDefault // max items to fetch at once
|
metadataLimit = dropbox.MetadataLimitDefault // max items to fetch at once
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -139,7 +139,7 @@ func newDropbox(name string) (*dropbox.Dropbox, error) {
|
||||||
}
|
}
|
||||||
appSecret := fs.ConfigFile.MustValue(name, "app_secret")
|
appSecret := fs.ConfigFile.MustValue(name, "app_secret")
|
||||||
if appSecret == "" {
|
if appSecret == "" {
|
||||||
appSecret = fs.Reveal(rcloneEncryptedAppSecret)
|
appSecret = fs.MustReveal(rcloneEncryptedAppSecret)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := db.SetAppInfo(appKey, appSecret)
|
err := db.SetAppInfo(appKey, appSecret)
|
||||||
|
|
88
fs/config.go
88
fs/config.go
|
@ -5,6 +5,8 @@ package fs
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"crypto/aes"
|
||||||
|
"crypto/cipher"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
@ -191,25 +193,85 @@ func (x *SizeSuffix) Type() string {
|
||||||
// Check it satisfies the interface
|
// Check it satisfies the interface
|
||||||
var _ pflag.Value = (*SizeSuffix)(nil)
|
var _ pflag.Value = (*SizeSuffix)(nil)
|
||||||
|
|
||||||
// Obscure a config value
|
// crypt internals
|
||||||
func Obscure(x string) string {
|
var (
|
||||||
y := []byte(x)
|
cryptKey = []byte{
|
||||||
for i := range y {
|
0x9c, 0x93, 0x5b, 0x48, 0x73, 0x0a, 0x55, 0x4d,
|
||||||
y[i] ^= byte(i) ^ 0xAA
|
0x6b, 0xfd, 0x7c, 0x63, 0xc8, 0x86, 0xa9, 0x2b,
|
||||||
|
0xd3, 0x90, 0x19, 0x8e, 0xb8, 0x12, 0x8a, 0xfb,
|
||||||
|
0xf4, 0xde, 0x16, 0x2b, 0x8b, 0x95, 0xf6, 0x38,
|
||||||
}
|
}
|
||||||
return base64.StdEncoding.EncodeToString(y)
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reveal a config value
|
// Obscure a value
|
||||||
func Reveal(y string) string {
|
//
|
||||||
x, err := base64.StdEncoding.DecodeString(y)
|
// 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 {
|
if err != nil {
|
||||||
log.Fatalf("Failed to reveal %q: %v", y, err)
|
log.Fatalf("Obscure failed: %v", err)
|
||||||
}
|
}
|
||||||
for i := range x {
|
return out
|
||||||
x[i] ^= byte(i) ^ 0xAA
|
}
|
||||||
|
|
||||||
|
// 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")
|
||||||
}
|
}
|
||||||
return string(x)
|
if len(ciphertext) < aes.BlockSize {
|
||||||
|
return "", errors.New("input too short")
|
||||||
|
}
|
||||||
|
buf := ciphertext[aes.BlockSize:]
|
||||||
|
iv := ciphertext[:aes.BlockSize]
|
||||||
|
if err := crypt(buf, buf, iv); err != nil {
|
||||||
|
return "", errors.Wrap(err, "decrypt failed")
|
||||||
|
}
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConfigInfo is filesystem config options
|
// ConfigInfo is filesystem config options
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package fs
|
package fs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/rand"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -85,17 +87,48 @@ func TestSizeSuffixSet(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReveal(t *testing.T) {
|
func TestObscure(t *testing.T) {
|
||||||
for _, test := range []struct {
|
for _, test := range []struct {
|
||||||
in string
|
in string
|
||||||
want string
|
want string
|
||||||
|
iv string
|
||||||
}{
|
}{
|
||||||
{"", ""},
|
{"", "YWFhYWFhYWFhYWFhYWFhYQ", "aaaaaaaaaaaaaaaa"},
|
||||||
{"2sTcyNrA", "potato"},
|
{"potato", "YWFhYWFhYWFhYWFhYWFhYXMaGgIlEQ", "aaaaaaaaaaaaaaaa"},
|
||||||
|
{"potato", "YmJiYmJiYmJiYmJiYmJiYp3gcEWbAw", "bbbbbbbbbbbbbbbb"},
|
||||||
} {
|
} {
|
||||||
got := Reveal(test.in)
|
cryptRand = bytes.NewBufferString(test.iv)
|
||||||
|
got, err := Obscure(test.in)
|
||||||
|
cryptRand = rand.Reader
|
||||||
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, test.want, got)
|
assert.Equal(t, test.want, got)
|
||||||
assert.Equal(t, test.in, Obscure(got), "not bidirectional")
|
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")
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test some error cases
|
||||||
|
func TestReveal(t *testing.T) {
|
||||||
|
for _, test := range []struct {
|
||||||
|
in string
|
||||||
|
wantErr string
|
||||||
|
}{
|
||||||
|
{"YmJiYmJiYmJiYmJiYmJiYp*gcEWbAw", "base64 decode failed: illegal base64 data at input byte 22"},
|
||||||
|
{"aGVsbG8", "input too short"},
|
||||||
|
{"", "input too short"},
|
||||||
|
} {
|
||||||
|
gotString, gotErr := Reveal(test.in)
|
||||||
|
assert.Equal(t, "", gotString)
|
||||||
|
assert.Equal(t, test.wantErr, gotErr.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
rcloneClientID = "202264815644.apps.googleusercontent.com"
|
rcloneClientID = "202264815644.apps.googleusercontent.com"
|
||||||
rcloneEncryptedClientSecret = "8p/yms3OlNXE9OTDl/HLypf9gdiJ5cT3"
|
rcloneEncryptedClientSecret = "Uj7C9jGfb9gmeaV70Lh058cNkWvepr-Es9sBm0zdgil7JaOWF1VySw"
|
||||||
timeFormatIn = time.RFC3339
|
timeFormatIn = time.RFC3339
|
||||||
timeFormatOut = "2006-01-02T15:04:05.000000000Z07:00"
|
timeFormatOut = "2006-01-02T15:04:05.000000000Z07:00"
|
||||||
metaMtime = "mtime" // key to store mtime under in metadata
|
metaMtime = "mtime" // key to store mtime under in metadata
|
||||||
|
@ -50,7 +50,7 @@ var (
|
||||||
Scopes: []string{storage.DevstorageFullControlScope},
|
Scopes: []string{storage.DevstorageFullControlScope},
|
||||||
Endpoint: google.Endpoint,
|
Endpoint: google.Endpoint,
|
||||||
ClientID: rcloneClientID,
|
ClientID: rcloneClientID,
|
||||||
ClientSecret: fs.Reveal(rcloneEncryptedClientSecret),
|
ClientSecret: fs.MustReveal(rcloneEncryptedClientSecret),
|
||||||
RedirectURL: oauthutil.TitleBarRedirectURL,
|
RedirectURL: oauthutil.TitleBarRedirectURL,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -23,7 +23,7 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
rcloneClientID = "api_hubic_svWP970PvSWbw5G3PzrAqZ6X2uHeZBPI"
|
rcloneClientID = "api_hubic_svWP970PvSWbw5G3PzrAqZ6X2uHeZBPI"
|
||||||
rcloneEncryptedClientSecret = "8MrG3pjWyJya4OnO9ZTS4emI+9fa1ouPgvfD2MbTzfDYvO/H5czFxsTXtcji4/Hz3snz8/CrzMzlxvP9//Ty/Q=="
|
rcloneEncryptedClientSecret = "leZKCcqy9movLhDWLVXX8cSLp_FzoiAPeEJOIOMRw1A5RuC4iLEPDYPWVF46adC_MVonnLdVEOTHVstfBOZ_lY4WNp8CK_YWlpRZ9diT5YI"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Globals
|
// Globals
|
||||||
|
@ -38,7 +38,7 @@ var (
|
||||||
TokenURL: "https://api.hubic.com/oauth/token/",
|
TokenURL: "https://api.hubic.com/oauth/token/",
|
||||||
},
|
},
|
||||||
ClientID: rcloneClientID,
|
ClientID: rcloneClientID,
|
||||||
ClientSecret: fs.Reveal(rcloneEncryptedClientSecret),
|
ClientSecret: fs.MustReveal(rcloneEncryptedClientSecret),
|
||||||
RedirectURL: oauthutil.RedirectLocalhostURL,
|
RedirectURL: oauthutil.RedirectLocalhostURL,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -26,7 +26,7 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
rcloneClientID = "0000000044165769"
|
rcloneClientID = "0000000044165769"
|
||||||
rcloneEncryptedClientSecret = "0+be4+jYw+7018HY6P3t/Izo+pTc+Yvt8+fy8NHU094="
|
rcloneEncryptedClientSecret = "ugVWLNhKkVT1-cbTRO-6z1MlzwdW6aMwpKgNaFG-qXjEn_WfDnG9TVyRA5yuoliU"
|
||||||
minSleep = 10 * time.Millisecond
|
minSleep = 10 * time.Millisecond
|
||||||
maxSleep = 2 * time.Second
|
maxSleep = 2 * time.Second
|
||||||
decayConstant = 2 // bigger for slower decay, exponential
|
decayConstant = 2 // bigger for slower decay, exponential
|
||||||
|
@ -47,7 +47,7 @@ var (
|
||||||
TokenURL: "https://login.live.com/oauth20_token.srf",
|
TokenURL: "https://login.live.com/oauth20_token.srf",
|
||||||
},
|
},
|
||||||
ClientID: rcloneClientID,
|
ClientID: rcloneClientID,
|
||||||
ClientSecret: fs.Reveal(rcloneEncryptedClientSecret),
|
ClientSecret: fs.MustReveal(rcloneEncryptedClientSecret),
|
||||||
RedirectURL: oauthutil.RedirectPublicURL,
|
RedirectURL: oauthutil.RedirectPublicURL,
|
||||||
}
|
}
|
||||||
chunkSize = fs.SizeSuffix(10 * 1024 * 1024)
|
chunkSize = fs.SizeSuffix(10 * 1024 * 1024)
|
||||||
|
|
|
@ -23,7 +23,7 @@ import (
|
||||||
//oAuth
|
//oAuth
|
||||||
const (
|
const (
|
||||||
rcloneClientID = "ac39b43b9eba4cae8ffb788c06d816a8"
|
rcloneClientID = "ac39b43b9eba4cae8ffb788c06d816a8"
|
||||||
rcloneEncryptedClientSecret = "k8jKzZnMmM+Wx5jAksPAwYKPgImOiN+FhNKD09KBg9A="
|
rcloneEncryptedClientSecret = "EfyyNZ3YUEwXM5yAhi72G9YwKn2mkFrYwJNS7cY0TJAhFlX9K-uJFbGlpO-RYjrJ"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Globals
|
// Globals
|
||||||
|
@ -35,7 +35,7 @@ var (
|
||||||
TokenURL: "https://oauth.yandex.com/token", //same as https://oauth.yandex.ru/token
|
TokenURL: "https://oauth.yandex.com/token", //same as https://oauth.yandex.ru/token
|
||||||
},
|
},
|
||||||
ClientID: rcloneClientID,
|
ClientID: rcloneClientID,
|
||||||
ClientSecret: fs.Reveal(rcloneEncryptedClientSecret),
|
ClientSecret: fs.MustReveal(rcloneEncryptedClientSecret),
|
||||||
RedirectURL: oauthutil.RedirectURL,
|
RedirectURL: oauthutil.RedirectURL,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
Loading…
Add table
Reference in a new issue