vendor: update github.com/t3rm1n4l/go-mega and dependencies

This is to fix a crash reported in #3140
This commit is contained in:
Nick Craig-Wood 2019-04-30 11:15:32 +01:00
parent 48c09608ea
commit 8f89b03d7b
135 changed files with 27990 additions and 605 deletions

View file

@ -4,9 +4,8 @@ osx_image: xcode7.3
os:
- linux
go:
- 1.9.x
- 1.10.x
- 1.11.x
- 1.12.x
- tip
install:
- make build_dep
@ -19,7 +18,7 @@ matrix:
- go: tip
include:
- os: osx
go: "1.11.x"
go: "1.12.x"
env:
global:
- secure: RzsF80V1i69FVJwKSF8WrFzk5bRUKtPxRkhjiLOO0b1usFg0EIY6XFp3s/VTR6oT91LRXml3Bp7wHHrkPvGnHyUyuxj6loj3gIrsX8cZHUtjyQX/Szfi9MOJpbdJvfCcHByEh9YGldAz//9zvEo5oGuI29Luur3cv+BJNJElmHg=

View file

@ -336,7 +336,10 @@ func newMegaFS() *MegaFS {
func New() *Mega {
max := big.NewInt(0x100000000)
bigx, _ := rand.Int(rand.Reader, max)
bigx, err := rand.Int(rand.Reader, max)
if err != nil {
panic(err) // this should be returned, but this is a public interface
}
cfg := newConfig()
mgfs := newMegaFS()
m := &Mega{
@ -496,7 +499,10 @@ func (m *Mega) prelogin(email string) error {
if len(res[0].Salt) == 0 {
return errors.New("prelogin: no salt returned")
}
m.accountSalt = base64urldecode([]byte(res[0].Salt))
m.accountSalt, err = base64urldecode([]byte(res[0].Salt))
if err != nil {
return err
}
}
m.accountVersion = res[0].Version
@ -512,8 +518,14 @@ func (m *Mega) login(email string, passwd string) error {
email = strings.ToLower(email) // mega uses lowercased emails for login purposes
passkey := password_key(passwd)
uhandle := stringhash(email, passkey)
passkey, err := password_key(passwd)
if err != nil {
return err
}
uhandle, err := stringhash(email, passkey)
if err != nil {
return err
}
m.uh = make([]byte, len(uhandle))
copy(m.uh, uhandle)
@ -536,9 +548,11 @@ func (m *Mega) login(email string, passwd string) error {
msg[0].SessionKey = string(base64urlencode(sessionKey))
}
req, _ := json.Marshal(msg)
req, err := json.Marshal(msg)
if err != nil {
return err
}
result, err = m.api_request(req)
if err != nil {
return err
}
@ -548,8 +562,14 @@ func (m *Mega) login(email string, passwd string) error {
return err
}
m.k = base64urldecode([]byte(res[0].Key))
m.k, err = base64urldecode([]byte(res[0].Key))
if err != nil {
return err
}
cipher, err := aes.NewCipher(passkey)
if err != nil {
return err
}
cipher.Decrypt(m.k, m.k)
m.sid, err = decryptSessionId([]byte(res[0].Privk), []byte(res[0].Csid), m.k)
if err != nil {
@ -634,9 +654,11 @@ func (m *Mega) GetUser() (UserResp, error) {
msg[0].Cmd = "ug"
req, _ := json.Marshal(msg)
req, err := json.Marshal(msg)
if err != nil {
return res[0], err
}
result, err := m.api_request(req)
if err != nil {
return res[0], err
}
@ -654,7 +676,10 @@ func (m *Mega) GetQuota() (QuotaResp, error) {
msg[0].Xfer = 1
msg[0].Strg = 1
req, _ := json.Marshal(msg)
req, err := json.Marshal(msg)
if err != nil {
return res[0], err
}
result, err := m.api_request(req)
if err != nil {
return res[0], err
@ -671,7 +696,10 @@ func (m *Mega) addFSNode(itm FSNode) (*Node, error) {
var node, parent *Node
var err error
master_aes, _ := aes.NewCipher(m.k)
master_aes, err := aes.NewCipher(m.k)
if err != nil {
return nil, err
}
switch {
case itm.T == FOLDER || itm.T == FILE:
@ -680,43 +708,73 @@ func (m *Mega) addFSNode(itm FSNode) (*Node, error) {
switch {
// File or folder owned by current user
case args[0] == itm.User:
buf := base64urldecode([]byte(args[1]))
buf, err := base64urldecode([]byte(args[1]))
if err != nil {
return nil, err
}
err = blockDecrypt(master_aes, buf, buf)
if err != nil {
return nil, err
}
compkey = bytes_to_a32(buf)
compkey, err = bytes_to_a32(buf)
if err != nil {
return nil, err
}
// Shared folder
case itm.SUser != "" && itm.SKey != "":
sk := base64urldecode([]byte(itm.SKey))
sk, err := base64urldecode([]byte(itm.SKey))
if err != nil {
return nil, err
}
err = blockDecrypt(master_aes, sk, sk)
if err != nil {
return nil, err
}
sk_aes, _ := aes.NewCipher(sk)
sk_aes, err := aes.NewCipher(sk)
if err != nil {
return nil, err
}
m.FS.skmap[itm.Hash] = itm.SKey
buf := base64urldecode([]byte(args[1]))
buf, err := base64urldecode([]byte(args[1]))
if err != nil {
return nil, err
}
err = blockDecrypt(sk_aes, buf, buf)
if err != nil {
return nil, err
}
compkey = bytes_to_a32(buf)
compkey, err = bytes_to_a32(buf)
if err != nil {
return nil, err
}
// Shared file
default:
k := m.FS.skmap[args[0]]
b := base64urldecode([]byte(k))
b, err := base64urldecode([]byte(k))
if err != nil {
return nil, err
}
err = blockDecrypt(master_aes, b, b)
if err != nil {
return nil, err
}
block, _ := aes.NewCipher(b)
buf := base64urldecode([]byte(args[1]))
block, err := aes.NewCipher(b)
if err != nil {
return nil, err
}
buf, err := base64urldecode([]byte(args[1]))
if err != nil {
return nil, err
}
err = blockDecrypt(block, buf, buf)
if err != nil {
return nil, err
}
compkey = bytes_to_a32(buf)
compkey, err = bytes_to_a32(buf)
if err != nil {
return nil, err
}
}
switch {
@ -726,10 +784,16 @@ func (m *Mega) addFSNode(itm FSNode) (*Node, error) {
key = compkey
}
attr, err = decryptAttr(a32_to_bytes(key), []byte(itm.Attr))
// FIXME:
bkey, err := a32_to_bytes(key)
if err != nil {
// FIXME:
attr.Name = "BAD ATTRIBUTE"
} else {
attr, err = decryptAttr(bkey, []byte(itm.Attr))
// FIXME:
if err != nil {
attr.Name = "BAD ATTRIBUTE"
}
}
}
@ -769,15 +833,33 @@ func (m *Mega) addFSNode(itm FSNode) (*Node, error) {
switch {
case itm.T == FILE:
var meta NodeMeta
meta.key = a32_to_bytes(key)
meta.iv = a32_to_bytes([]uint32{compkey[4], compkey[5], 0, 0})
meta.mac = a32_to_bytes([]uint32{compkey[6], compkey[7]})
meta.compkey = a32_to_bytes(compkey)
meta.key, err = a32_to_bytes(key)
if err != nil {
return nil, err
}
meta.iv, err = a32_to_bytes([]uint32{compkey[4], compkey[5], 0, 0})
if err != nil {
return nil, err
}
meta.mac, err = a32_to_bytes([]uint32{compkey[6], compkey[7]})
if err != nil {
return nil, err
}
meta.compkey, err = a32_to_bytes(compkey)
if err != nil {
return nil, err
}
node.meta = meta
case itm.T == FOLDER:
var meta NodeMeta
meta.key = a32_to_bytes(key)
meta.compkey = a32_to_bytes(compkey)
meta.key, err = a32_to_bytes(key)
if err != nil {
return nil, err
}
meta.compkey, err = a32_to_bytes(compkey)
if err != nil {
return nil, err
}
node.meta = meta
case itm.T == ROOT:
attr.Name = "Cloud Drive"
@ -814,9 +896,11 @@ func (m *Mega) getFileSystem() error {
msg[0].Cmd = "f"
msg[0].C = 1
req, _ := json.Marshal(msg)
req, err := json.Marshal(msg)
if err != nil {
return err
}
result, err := m.api_request(req)
if err != nil {
return err
}
@ -908,9 +992,15 @@ func (m *Mega) NewDownload(src *Node) (*Download, error) {
mac_enc := cipher.NewCBCEncrypter(aes_block, zero_iv)
m.FS.mutex.Lock()
t := bytes_to_a32(src.meta.iv)
t, err := bytes_to_a32(src.meta.iv)
m.FS.mutex.Unlock()
iv := a32_to_bytes([]uint32{t[0], t[1], t[0], t[1]})
if err != nil {
return nil, err
}
iv, err := a32_to_bytes([]uint32{t[0], t[1], t[0], t[1]})
if err != nil {
return nil, err
}
d := &Download{
m: m,
@ -992,10 +1082,17 @@ func (d *Download) DownloadChunk(id int) (chunk []byte, err error) {
}
// Decrypt the block
ctr_iv := bytes_to_a32(d.src.meta.iv)
ctr_iv, err := bytes_to_a32(d.src.meta.iv)
if err != nil {
return nil, err
}
ctr_iv[2] = uint32(uint64(chk_start) / 0x1000000000)
ctr_iv[3] = uint32(chk_start / 0x10)
ctr_aes := cipher.NewCTR(d.aes_block, a32_to_bytes(ctr_iv))
bctr_iv, err := a32_to_bytes(ctr_iv)
if err != nil {
return nil, err
}
ctr_aes := cipher.NewCTR(d.aes_block, bctr_iv)
ctr_aes.XORKeyStream(chunk, chunk)
// Update the chunk_macs
@ -1035,8 +1132,15 @@ func (d *Download) Finish() (err error) {
d.mac_enc.CryptBlocks(mac_data, v)
}
tmac := bytes_to_a32(mac_data)
if bytes.Equal(a32_to_bytes([]uint32{tmac[0] ^ tmac[1], tmac[2] ^ tmac[3]}), d.src.meta.mac) == false {
tmac, err := bytes_to_a32(mac_data)
if err != nil {
return err
}
btmac, err := a32_to_bytes([]uint32{tmac[0] ^ tmac[1], tmac[2] ^ tmac[3]})
if err != nil {
return err
}
if bytes.Equal(btmac, d.src.meta.mac) == false {
return EMACMISMATCH
}
@ -1188,12 +1292,24 @@ func (m *Mega) NewUpload(parent *Node, name string, fileSize int64) (*Upload, er
}
kbytes := a32_to_bytes(ukey[:4])
kiv := a32_to_bytes([]uint32{ukey[4], ukey[5], 0, 0})
aes_block, _ := aes.NewCipher(kbytes)
kbytes, err := a32_to_bytes(ukey[:4])
if err != nil {
return nil, err
}
kiv, err := a32_to_bytes([]uint32{ukey[4], ukey[5], 0, 0})
if err != nil {
return nil, err
}
aes_block, err := aes.NewCipher(kbytes)
if err != nil {
return nil, err
}
mac_enc := cipher.NewCBCEncrypter(aes_block, zero_iv)
iv := a32_to_bytes([]uint32{ukey[4], ukey[5], ukey[4], ukey[5]})
iv, err := a32_to_bytes([]uint32{ukey[4], ukey[5], ukey[4], ukey[5]})
if err != nil {
return nil, err
}
chunks := getChunkSizes(fileSize)
@ -1243,10 +1359,17 @@ func (u *Upload) UploadChunk(id int, chunk []byte) (err error) {
if len(chunk) != chk_size {
return errors.New("upload chunk is wrong size")
}
ctr_iv := bytes_to_a32(u.kiv)
ctr_iv, err := bytes_to_a32(u.kiv)
if err != nil {
return err
}
ctr_iv[2] = uint32(uint64(chk_start) / 0x1000000000)
ctr_iv[3] = uint32(chk_start / 0x10)
ctr_aes := cipher.NewCTR(u.aes_block, a32_to_bytes(ctr_iv))
bctr_iv, err := a32_to_bytes(ctr_iv)
if err != nil {
return err
}
ctr_aes := cipher.NewCTR(u.aes_block, bctr_iv)
enc := cipher.NewCBCEncrypter(u.aes_block, u.iv)
@ -1324,7 +1447,10 @@ func (u *Upload) Finish() (node *Node, err error) {
u.mac_enc.CryptBlocks(mac_data, v)
}
t := bytes_to_a32(mac_data)
t, err := bytes_to_a32(mac_data)
if err != nil {
return nil, err
}
meta_mac := []uint32{t[0] ^ t[1], t[2] ^ t[3]}
attr := FileAttr{u.name}
@ -1338,7 +1464,10 @@ func (u *Upload) Finish() (node *Node, err error) {
u.ukey[2] ^ meta_mac[0], u.ukey[3] ^ meta_mac[1],
u.ukey[4], u.ukey[5], meta_mac[0], meta_mac[1]}
buf := a32_to_bytes(key)
buf, err := a32_to_bytes(key)
if err != nil {
return nil, err
}
master_aes, err := aes.NewCipher(u.m.k)
if err != nil {
return nil, err
@ -1488,9 +1617,11 @@ func (m *Mega) Move(src *Node, parent *Node) error {
return err
}
request, _ := json.Marshal(msg)
request, err := json.Marshal(msg)
if err != nil {
return err
}
_, err = m.api_request(request)
if err != nil {
return err
}
@ -1515,11 +1646,17 @@ func (m *Mega) Rename(src *Node, name string) error {
}
var msg [1]FileAttrMsg
master_aes, _ := aes.NewCipher(m.k)
master_aes, err := aes.NewCipher(m.k)
if err != nil {
return err
}
attr := FileAttr{name}
attr_data, _ := encryptAttr(src.meta.key, attr)
attr_data, err := encryptAttr(src.meta.key, attr)
if err != nil {
return err
}
key := make([]byte, len(src.meta.compkey))
err := blockEncrypt(master_aes, key, src.meta.compkey)
err = blockEncrypt(master_aes, key, src.meta.compkey)
if err != nil {
return err
}
@ -1533,12 +1670,18 @@ func (m *Mega) Rename(src *Node, name string) error {
return err
}
req, _ := json.Marshal(msg)
req, err := json.Marshal(msg)
if err != nil {
return err
}
_, err = m.api_request(req)
if err != nil {
return err
}
src.name = name
return err
return nil
}
// Create a directory in the filesystem
@ -1557,12 +1700,21 @@ func (m *Mega) CreateDir(name string, parent *Node) (*Node, error) {
compkey[i] = uint32(mrand.Int31())
}
master_aes, _ := aes.NewCipher(m.k)
master_aes, err := aes.NewCipher(m.k)
if err != nil {
return nil, err
}
attr := FileAttr{name}
ukey := a32_to_bytes(compkey[:4])
attr_data, _ := encryptAttr(ukey, attr)
ukey, err := a32_to_bytes(compkey[:4])
if err != nil {
return nil, err
}
attr_data, err := encryptAttr(ukey, attr)
if err != nil {
return nil, err
}
key := make([]byte, len(ukey))
err := blockEncrypt(master_aes, key, ukey)
err = blockEncrypt(master_aes, key, ukey)
if err != nil {
return nil, err
}
@ -1578,7 +1730,10 @@ func (m *Mega) CreateDir(name string, parent *Node) (*Node, error) {
return nil, err
}
req, _ := json.Marshal(msg)
req, err := json.Marshal(msg)
if err != nil {
return nil, err
}
result, err := m.api_request(req)
if err != nil {
return nil, err
@ -1614,14 +1769,20 @@ func (m *Mega) Delete(node *Node, destroy bool) error {
return err
}
req, _ := json.Marshal(msg)
req, err := json.Marshal(msg)
if err != nil {
return err
}
_, err = m.api_request(req)
if err != nil {
return err
}
parent := m.FS.lookup[node.hash]
parent.removeChild(node)
delete(m.FS.lookup, node.hash)
return err
return nil
}
// process an add node event
@ -1830,9 +1991,11 @@ func (m *Mega) getLink(n *Node) (string, error) {
msg[0].Cmd = "l"
msg[0].N = n.GetHash()
req, _ := json.Marshal(msg)
req, err := json.Marshal(msg)
if err != nil {
return "", err
}
result, err := m.api_request(req)
if err != nil {
return "", err
}

View file

@ -37,27 +37,33 @@ func newHttpClient(timeout time.Duration) *http.Client {
// bytes_to_a32 converts the byte slice b to uint32 slice considering
// the bytes to be in big endian order.
func bytes_to_a32(b []byte) []uint32 {
func bytes_to_a32(b []byte) ([]uint32, error) {
length := len(b) + 3
a := make([]uint32, length/4)
buf := bytes.NewBuffer(b)
for i, _ := range a {
_ = binary.Read(buf, binary.BigEndian, &a[i])
err := binary.Read(buf, binary.BigEndian, &a[i])
if err != nil {
return nil, err
}
}
return a
return a, nil
}
// a32_to_bytes converts the uint32 slice a to byte slice where each
// uint32 is decoded in big endian order.
func a32_to_bytes(a []uint32) []byte {
func a32_to_bytes(a []uint32) ([]byte, error) {
buf := new(bytes.Buffer)
buf.Grow(len(a) * 4) // To prevent reallocations in Write
for _, v := range a {
_ = binary.Write(buf, binary.BigEndian, v)
err := binary.Write(buf, binary.BigEndian, v)
if err != nil {
return nil, err
}
}
return buf.Bytes()
return buf.Bytes(), nil
}
// base64urlencode encodes byte slice b using base64 url encoding.
@ -79,7 +85,7 @@ func base64urlencode(b []byte) []byte {
// base64urldecode decodes the byte slice b using base64 url decoding.
// It adds required '=' padding before decoding.
func base64urldecode(b []byte) []byte {
func base64urldecode(b []byte) ([]byte, error) {
enc := base64.URLEncoding
padSize := 4 - len(b)%4
@ -92,18 +98,29 @@ func base64urldecode(b []byte) []byte {
decSize := enc.DecodedLen(len(b))
buf := make([]byte, decSize)
n, _ := enc.Decode(buf, b)
return buf[:n]
n, err := enc.Decode(buf, b)
if err != nil {
return nil, err
}
return buf[:n], err
}
// base64_to_a32 converts base64 encoded byte slice b to uint32 slice.
func base64_to_a32(b []byte) []uint32 {
return bytes_to_a32(base64urldecode(b))
func base64_to_a32(b []byte) ([]uint32, error) {
d, err := base64urldecode(b)
if err != nil {
return nil, err
}
return bytes_to_a32(d)
}
// a32_to_base64 converts uint32 slice to base64 encoded byte slice.
func a32_to_base64(a []uint32) []byte {
return base64urlencode(a32_to_bytes(a))
func a32_to_base64(a []uint32) ([]byte, error) {
d, err := a32_to_bytes(a)
if err != nil {
return nil, err
}
return base64urlencode(d), nil
}
// paddnull pads byte slice b such that the size of resulting byte
@ -121,10 +138,16 @@ func paddnull(b []byte, q int) []byte {
}
// password_key calculates password hash from the user password.
func password_key(p string) []byte {
a := bytes_to_a32(paddnull([]byte(p), 4))
func password_key(p string) ([]byte, error) {
a, err := bytes_to_a32(paddnull([]byte(p), 4))
if err != nil {
return nil, err
}
pkey := a32_to_bytes([]uint32{0x93C467E3, 0x7DB0C7A4, 0xD1BE3F81, 0x0152CB56})
pkey, err := a32_to_bytes([]uint32{0x93C467E3, 0x7DB0C7A4, 0xD1BE3F81, 0x0152CB56})
if err != nil {
return nil, err
}
n := (len(a) + 3) / 4
@ -137,7 +160,14 @@ func password_key(p string) []byte {
key[k] = a[k+j]
}
}
ciphers[j/4], _ = aes.NewCipher(a32_to_bytes(key)) // Uses AES in ECB mode
bkey, err := a32_to_bytes(key)
if err != nil {
return nil, err
}
ciphers[j/4], err = aes.NewCipher(bkey) // Uses AES in ECB mode
if err != nil {
return nil, err
}
}
for i := 65536; i > 0; i-- {
@ -146,24 +176,36 @@ func password_key(p string) []byte {
}
}
return pkey
return pkey, nil
}
// stringhash computes generic string hash. Uses k as the key for AES
// cipher.
func stringhash(s string, k []byte) []byte {
a := bytes_to_a32(paddnull([]byte(s), 4))
func stringhash(s string, k []byte) ([]byte, error) {
a, err := bytes_to_a32(paddnull([]byte(s), 4))
if err != nil {
return nil, err
}
h := []uint32{0, 0, 0, 0}
for i, v := range a {
h[i&3] ^= v
}
hb := a32_to_bytes(h)
cipher, _ := aes.NewCipher(k)
hb, err := a32_to_bytes(h)
if err != nil {
return nil, err
}
cipher, err := aes.NewCipher(k)
if err != nil {
return nil, err
}
for i := 16384; i > 0; i-- {
cipher.Encrypt(hb, hb)
}
ha := bytes_to_a32(paddnull(hb, 4))
ha, err := bytes_to_a32(paddnull(hb, 4))
if err != nil {
return nil, err
}
return a32_to_base64([]uint32{ha[0], ha[2]})
}
@ -232,14 +274,23 @@ func blockEncrypt(blk cipher.Block, dst, src []byte) error {
// key.
func decryptSessionId(privk []byte, csid []byte, mk []byte) ([]byte, error) {
block, _ := aes.NewCipher(mk)
pk := base64urldecode(privk)
err := blockDecrypt(block, pk, pk)
block, err := aes.NewCipher(mk)
if err != nil {
return nil, err
}
pk, err := base64urldecode(privk)
if err != nil {
return nil, err
}
err = blockDecrypt(block, pk, pk)
if err != nil {
return nil, err
}
c := base64urldecode(csid)
c, err := base64urldecode(csid)
if err != nil {
return nil, err
}
m, _ := getMPI(c)
@ -283,10 +334,17 @@ func decryptAttr(key []byte, data []byte) (attr FileAttr, err error) {
if err != nil {
return attr, err
}
iv := a32_to_bytes([]uint32{0, 0, 0, 0})
iv, err := a32_to_bytes([]uint32{0, 0, 0, 0})
if err != nil {
return attr, err
}
mode := cipher.NewCBCDecrypter(block, iv)
buf := make([]byte, len(data))
mode.CryptBlocks(buf, base64urldecode([]byte(data)))
ddata, err := base64urldecode([]byte(data))
if err != nil {
return attr, err
}
mode.CryptBlocks(buf, ddata)
if string(buf[:4]) == "MEGA" {
str := strings.TrimRight(string(buf[4:]), "\x00")
@ -313,7 +371,10 @@ func encryptAttr(key []byte, attr FileAttr) (b []byte, err error) {
attrib = append(attrib, data...)
attrib = paddnull(attrib, 16)
iv := a32_to_bytes([]uint32{0, 0, 0, 0})
iv, err := a32_to_bytes([]uint32{0, 0, 0, 0})
if err != nil {
return nil, err
}
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(attrib, attrib)