Golang使用JSON进行base64编码/解码无法正常工作。

huangapple go评论82阅读模式
英文:

Golang Encode/Decode base64 with json post doesn't work

问题

我在golang中构建了一个客户端和一个服务器,两者都使用以下函数进行加密/解密:

func encrypt(text []byte) ([]byte, error) {
    block, err := aes.NewCipher(key)
    if err != nil {
        return nil, err
    }
    b := base64.StdEncoding.EncodeToString(text)
    ciphertext := make([]byte, aes.BlockSize+len(b))
    iv := ciphertext[:aes.BlockSize]
    if _, err := io.ReadFull(rand.Reader, iv); err != nil {
        return nil, err
    }
    cfb := cipher.NewCFBEncrypter(block, iv)
    cfb.XORKeyStream(ciphertext[aes.BlockSize:], []byte(b))
    return ciphertext, nil
}

func decrypt(text []byte) ([]byte, error) {
    block, err := aes.NewCipher(key)
    if err != nil {
        return nil, err
    }
    if len(text) < aes.BlockSize {
        return nil, errors.New("ciphertext too short")
    }
    iv := text[:aes.BlockSize]
    text = text[aes.BlockSize:]
    cfb := cipher.NewCFBDecrypter(block, iv)
    cfb.XORKeyStream(text, text)
    data, err := base64.StdEncoding.DecodeString(string(text))
    if err != nil {
        return nil, err
    }
    return data, nil
}

然后,我进行了一个普通的POST请求:

url := "https://" + configuration.Server + configuration.Port + "/get"

ciphertext, err := encrypt([]byte(*getUrl))
if err != nil {
    fmt.Println("Error: " + err.Error())
}
fmt.Println(string(ciphertext))

values := map[string]interface{}{"url": *getUrl, "urlCrypted": ciphertext}
jsonValue, _ := json.Marshal(values)
jsonStr := bytes.NewBuffer(jsonValue)

req, err := http.NewRequest("POST", url, jsonStr)

服务器端的代码如下:

requestContent := getRequestContentFromRequest(req)
url := requestContent["url"].(string)

undecryptedUrl := requestContent["urlCrypted"].(string)
decryptedurl, err := decrypt([]byte(undecryptedUrl))
if err != nil {
    fmt.Println("Error: " + err.Error())
}
fmt.Println(decryptedurl)

其中,getRequestContentFromRequest函数如下:

func getRequestContentFromRequest(req *http.Request) map[string]interface{} {
    buf := new(bytes.Buffer)
    buf.ReadFrom(req.Body)
    data := buf.Bytes()
    var requestContent map[string]interface{}
    err := json.Unmarshal(data, &requestContent)
    if err != nil {
        fmt.Println(err)
    }
    return requestContent
}

现在来解决问题。
如果我在客户端加密字符串后立即解密,一切都正常。

但是,当我将加密后的字符串发送到服务器,并尝试使用与客户端完全相同的函数进行解密时,解密函数会抛出错误:

Error: illegal base64 data at input byte 0

我认为问题出在JSON的解组上。

谢谢帮助。

P.S.

仓库地址:

github.com/BelphegorPrime/goSafeClient 和 github.com/BelphegorPrime/goSafe

更新

示例JSON:

{"url":"facebook2.com","urlCrypted":"/}\ufffd\ufffd\ufffdgP\ufffdN뼞\ufffd\u0016\ufffd)\ufffd\ufffd\ufffdy\u001c\u000f\ufffd\ufffd\ufffdep\ufffd\rY\ufffd\ufffd$\ufffd\ufffd"}

更新2

我在这里创建了一个playground 链接

英文:

I build a client and a server in golang both are using this functions to encrypt/decrypt

func encrypt(text []byte) ([]byte, error) {
    block, err := aes.NewCipher(key)
    if err != nil {
	    return nil, err
    }
    b := base64.StdEncoding.EncodeToString(text)
    ciphertext := make([]byte, aes.BlockSize+len(b))
    iv := ciphertext[:aes.BlockSize]
    if _, err := io.ReadFull(rand.Reader, iv); err != nil {
	    return nil, err
    }
    cfb := cipher.NewCFBEncrypter(block, iv)
    cfb.XORKeyStream(ciphertext[aes.BlockSize:], []byte(b))
    return ciphertext, nil
}

func decrypt(text []byte) ([]byte, error) {
    block, err := aes.NewCipher(key)
    if err != nil {
	    return nil, err
    }
    if len(text) &lt; aes.BlockSize {
	    return nil, errors.New(&quot;ciphertext too short&quot;)
    }
    iv := text[:aes.BlockSize]
    text = text[aes.BlockSize:]
    cfb := cipher.NewCFBDecrypter(block, iv)
    cfb.XORKeyStream(text, text)
    data, err := base64.StdEncoding.DecodeString(string(text))
    if err != nil {
	    return nil, err
    }
    return data, nil
}

so yeah I make a normal post request

url := &quot;https://&quot;+configuration.Server+configuration.Port+&quot;/get&quot;

// TODO maybe bugs rest here
ciphertext, err := encrypt([]byte(*getUrl))
if err != nil {
	fmt.Println(&quot;Error: &quot; + err.Error())
}
fmt.Println(string(ciphertext))

values := map[string]interface{}{&quot;url&quot;: *getUrl, &quot;urlCrypted&quot;: ciphertext}
jsonValue, _ := json.Marshal(values)
jsonStr := bytes.NewBuffer(jsonValue)

req, err := http.NewRequest(&quot;POST&quot;, url, jsonStr)

and the servercode is as following

requestContent := getRequestContentFromRequest(req)
url := requestContent[&quot;url&quot;].(string)

undecryptedUrl := requestContent[&quot;urlCrypted&quot;].(string)
decryptedurl, err := decrypt([]byte(undecryptedUrl))
if err != nil {
	fmt.Println(&quot;Error: &quot; + err.Error())
}
fmt.Println(decryptedurl)

where getRequestContentFromRequest is as following

func getRequestContentFromRequest(req *http.Request)                 
    map[string]interface{} {
    buf := new(bytes.Buffer)
    buf.ReadFrom(req.Body)
    data := buf.Bytes()
    var requestContent map[string]interface{}
    err := json.Unmarshal(data, &amp;requestContent)
    if err != nil {
	    fmt.Println(err)
    }
    return requestContent
}

Now to the problem.
If I encrypt my string in the client and decrypt it direct after that everything is fine.

But, when I send the encrypted string to the server and try to decrypt it with literrally the same function as in the client, the decrypt function throws an error.

Error: illegal base64 data at input byte 0

I think the Problem is the unmarshalling of the JSON.

Thanks for help.

P.S.

Repos are

github.com/BelphegorPrime/goSafeClient and github.com/BelphegorPrime/goSafe

UPDATE

Example JSON

{&quot;url&quot;:&quot;facebook2.com&quot;,&quot;urlCrypted&quot;:&quot;/}\ufffd\ufffd\ufffdgP\ufffdN뼞\ufffd\u0016\ufffd)\ufffd\ufffd\ufffdy\u001c\u000f\ufffd\ufffd\ufffdep\ufffd\rY\ufffd\ufffd$\ufffd\ufffd&quot;}

UPDATE2

I made a playground here

答案1

得分: 0

问题在于你进行了两次base64编码。第一次是在encrypt函数中,第二次是在JSON编组期间。字节切片会被encoding/json编组器自动转换为base64字符串。

解决方案是在调用decrypt之前解码base64字符串。

Go PlayGround上有一个示例。

编辑

可行的解决方案在这里

英文:

The problem is that you encode in base64 twice. The first time in the encrypt function and the second time during the JSON marshalling. byte slices are automatically converted into base64 strings by the encoding/json marshaller.

The solution is to decode the base64 string before calling decrypt.

Example on the Go PlayGround

EDIT

Working solution here

huangapple
  • 本文由 发表于 2017年5月13日 01:00:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/43942972.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定