Skip to content

Instantly share code, notes, and snippets.

@FWeinb
Created May 30, 2017 22:40
Show Gist options
  • Save FWeinb/03cfba821b2d305414cbf2e5bc720157 to your computer and use it in GitHub Desktop.
Save FWeinb/03cfba821b2d305414cbf2e5bc720157 to your computer and use it in GitHub Desktop.
Rclone filename gopherjs wrapper
package main
import (
"crypto/aes"
gocipher "crypto/cipher"
"crypto/rand"
"encoding/base64"
"log"
"github.com/gopherjs/gopherjs/js"
"github.com/pkg/errors"
)
func main() {
js.Global.Set("Decrypter", map[string]interface{}{
"Create": New,
})
}
type Crypt struct {
_c Cipher
}
type Callback func(err error, value interface{})
// Crypt
func New(options *js.Object, cb Callback) {
defer func() {
pass := options.Get("pass").String()
salt := options.Get("salt").String()
c, err := newCipher(NameEncryptionStandard, mustReveal(pass), mustReveal(salt))
cb(err, js.MakeWrapper(&Crypt{c}))
}()
}
func (c *Crypt) DecryptFileName(str string, cb Callback) {
defer func() {
plain, err := c._c.DecryptFileName(str)
cb(err, plain)
}()
}
func (c *Crypt) EncryptFileName(str string, cb Callback) {
defer func() {
plain := c._c.EncryptFileName(str)
cb(nil, plain)
}()
}
// 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 gocipher.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 := gocipher.NewCTR(cryptBlock, iv)
stream.XORKeyStream(out, in)
return nil
}
func reveal(x string) (string, error) {
ciphertext, err := base64.RawURLEncoding.DecodeString(x)
if err != nil {
return "", errors.Wrap(err, "base64 decode failed")
}
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
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment