【问题标题】:AES CBC: JavaScript/CryptoJS Encrypt -> Golang DecryptAES CBC:JavaScript/CryptoJS 加密 -> Golang 解密
【发布时间】:2019-08-13 22:31:08
【问题描述】:

注意:这仅供个人使用和学习,我不会尝试推出自己的加密以供公众使用。

我需要对一个字符串进行 AES256 加密,但是当它被十六进制解码时,我当前的尝试最终会得到一个类似 Salted__Vέ��|��l��ʼ8XCQlY 服务器端的字符串。十六进制解码时,它应该是一个有效的 utf8 base64 字符串,然后可以将其解码为原始字符串。这类似于here 提供的解决方案,但是盐不是实际问题(尽管答案已被接受),并且我无法在使用前通过对 iv 进行十六进制解码来抑制盐操作(正如它所建议的那样)。有没有办法做到这一点?

我尝试了几种不同的方法,但总是以相似的方式结束。我最近的尝试是这样的:

encrypt.js

// CryptoJS.pad.NoPadding={pad:function(){},unpad:function(){}};

const SECRET = '394812730425442A472D2F423F452848';
const iv = crypto.getRandomValues(new Uint8Array(16));    

function enc(plainText) {
  var b64 = CryptoJS.AES.encrypt(plainText, SECRET, { 
  	iv,
    mode: CryptoJS.mode.CBC,
    // padding: CryptoJS.pad.NoPadding
  }).toString();

  // Don't need?
  //var e64 = CryptoJS.enc.Base64.parse(b64);
  //var eHex = e64.toString(CryptoJS.enc.Hex);
  console.log("b64::", b64);

  return b64;
}

enc("SUPA_SECRET");
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/aes.js"></script>

现在我们将 b64 结果粘贴到服务器端 golang 解密的 JS_GEN 变量中:

decrypt.go

(golang decrypt playground)

package main

import (
    "crypto/aes"
    "crypto/cipher"
    "encoding/base64"
    "encoding/hex"
    "fmt"
)

func main() {
    JS_GEN := "U2FsdGVkX1+CA3LZTXePlgoGqL8VkdgiDgUenZhH4kc="
    SECRET := "394812730425442A472D2F423F452848"
    //msg := "SUPER_SECRET"

    res, err := DecryptCBC(SECRET, JS_GEN)
    if err != nil {
        fmt.Println(err)
    }

    fmt.Println("res::", res)
}

func DecryptCBC(secret string, target string) (string, error) {
    nilString := ""
    key, _ := hex.DecodeString(secret)
    //ciphertext, err := base64.URLEncoding.DecodeString(target)

    // Decode base64 string
    ciphertext, err := base64.StdEncoding.DecodeString(target)
    if err != nil {
        return nilString, err
    }

    // Create new cipher block
    block, err := aes.NewCipher(key)
    if err != nil {
        return nilString, err
    }

    // The IV needs to be unique, but not secure. Therefore it's common to
    // include it at the beginning of the ciphertext.
    if len(ciphertext) < aes.BlockSize {
        panic("ciphertext too short")
    }
    iv := ciphertext[:aes.BlockSize]
    ciphertext = ciphertext[aes.BlockSize:]

    // CBC mode always works in whole blocks.
    if len(ciphertext)%aes.BlockSize != 0 {
        panic("ciphertext is not a multiple of the block size")
    }
    mode := cipher.NewCBCDecrypter(block, iv)

    // CryptBlocks can work in-place if the two arguments are the same.
    mode.CryptBlocks(ciphertext, ciphertext)
    fmt.Println("ciphertext::", ciphertext)

    // Output: exampleplaintext
    return string(ciphertext), nil
}

输出将类似于:

ciphertext:: [136 227 244 124 124 92 162 254 1 147 235 213 8 136 129 150]
res:: ���||\�������

我做错了什么?

编辑:我已经从进程中删除了十六进制编码/解码。

【问题讨论】:

  • 您甚至没有将text 中的数据传递给base64.StdEncoding.DecodeString() 末尾的decrypt()
  • @Abdullah 谢谢,这是一个疏忽。我已经清理并更新了所有代码和要针对我认为现在是问题的问题。
  • 对于 AES256,使用 256 位密钥。您在 Go 中使用 128 位密钥,并且(如果我没看错的话)在 JS 中使用不同的 512 位密钥,这是无意义的。另外,对base64编码后的密文进行十六进制编码是多余和浪费的。选择一个(base64 更好,因为结果更短)。
  • @Peter 我已经删除了十六进制编码,这只是我看到的每个示例中的内容。现在至于钥匙......我如何使用不同的钥匙?他们都应该使用与密钥相同的秘密 (394812730425442A472D2F423F452848)
  • 在最初的问题中,您在 Go 中de对该字符串进行了编码,但在 JS 中en对其进行了编码。现在看来您在 JS 中按原样使用它。如果您不断显着改变问题,则很难为您提供帮助。

标签: javascript go encryption aes cryptojs


【解决方案1】:

您似乎在 JavaScript 中使用 CBC 模式(默认),但在 golang 中使用 CFB。请改用NewCBCDecrypter

【讨论】:

  • 感谢您的建议,我已将解密代码更新为使用NewCBCDecrypter,这并没有解决问题。我还将问题更新为我认为问题所在,即 JS 加密正在对它产生的十六进制字符串进行加盐,导致解码时 b64 无效。
【解决方案2】:

我仍然不完全确定为什么之前的尝试失败了。它可能是在服务器和客户端上实现和/或配置加密的许多不同方式之一。

我终于找到了我要找的东西。一个开箱即用的简单实现。这里我们只使用crypto-jsgo-openssl

client.js

const msg = "SUPA_SECRET"
const key = "394812730425442A472D2F423F452848";
const encrypted = CryptoJS.AES.encrypt(msg, key);

console.log(encrypted.toString());
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/aes.js"&gt;&lt;/script&gt;

server.go

package main

import (
    "fmt"
    "github.com/Luzifer/go-openssl"
)

func main() {
    encrypted := "ENCRYPTED_STRING_HERE"
    secret := "394812730425442A472D2F423F452848"

    o := openssl.New()

    dec, err := o.DecryptBytes(secret, []byte(encrypted), openssl.DigestMD5Sum)
    if err != nil {
        fmt.Printf("An error occurred: %s\n", err)
    }

    fmt.Printf("Decrypted text: %s\n", string(dec))
}



// OUTPUT:
// Decrypted text: SUPA_SECRET

【讨论】:

  • 如果我们不向此 CryptoJS.AES.encrypt(msg, key) 传递任何参数,这是否在 JavaScript 中默认使用 128-AES-cbc;
  • 我真的不知道。需要深入研究文档/代码库
  • 知道怎么做吗?如果我们必须通过cbc模式进行加密和解密
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-17
  • 1970-01-01
  • 1970-01-01
  • 2013-07-20
  • 2021-12-20
  • 1970-01-01
相关资源
最近更新 更多