为了账号安全,请及时绑定邮箱和手机立即绑定

Spring Security 加密字符串 - Go 中解密失败

Spring Security 加密字符串 - Go 中解密失败

Go
慕勒3428872 2023-08-21 14:54:19
加密将在客户端使用以下基于 Spring Security-Encryptors 的代码完成:package at.wrwks.pipe.baumgmt.component.documentpreview;import static java.nio.charset.StandardCharsets.UTF_8;import java.net.URLEncoder;import java.util.Base64;import org.springframework.security.crypto.codec.Hex;import org.springframework.security.crypto.encrypt.Encryptors;import org.springframework.stereotype.Component;@Componentpublic class SecureResourceUrlComposer {    public String compose(final String resource) {        final var salt = new String(Hex.encode("salt".getBytes(UTF_8)));        final var encryptor = Encryptors.stronger("password", salt);        final var encryptedResource = encryptor.encrypt(resource.getBytes(UTF_8));        final var base64EncodedEncryptedResource = Base64.getEncoder().encodeToString(encryptedResource);        final var urlEncodedBase64EncodedEncryptedResource = URLEncoder.encode(base64EncodedEncryptedResource, UTF_8);        return "https://target" + "?resource=" + urlEncodedBase64EncodedEncryptedResource;    }}示例资源:aResourceURL 和 base64 编码的输出:https://target?resource=yEAdq1toEfbcTKcAeTJmw7zLYdk4fA2waASPzSfqQxAxiq7bmUarUYE%3D解密失败,并cipher: message authentication failed显示以下用 Go 编写的后端代码gcm.Open:func decryptGcmAes32(ciphertext, key string) (plaintext string, err error) {    if len(key) != 32 {        msg := fmt.Sprintf("Unexpected key length (!= 32) '%s' %d", key, len(key))        err = errors.New(msg)        log.Warn(err)        sentry.CaptureException(err)        return    }    keyBytes := []byte(key)    c, err := aes.NewCipher(keyBytes)    if err != nil {        log.Warn("Couldn't create a cipher block", err)        sentry.CaptureException(err)        return    }    gcm, err := cipher.NewGCM(c)    if err != nil {        log.Warn("Couldn't wrap in gcm mode", err)        sentry.CaptureException(err)        return    }    }}
查看完整描述

2 回答

?
精慕HU

TA贡献1845条经验 获得超8个赞

所以重点是:

  • 为了应用盐并导出,pbkdf2.Key()必须使用正确的密钥,如下所示

  • nonceSpring Security 中的(或)大小Initialization Vector是 16 字节,而不是 12 字节go

下面的摘录省略了错误处理,只是为了强调解决方案的本质:

const nonceSize = 16

func decryptWithAes256GcmPbkdf2(cipherBytes []byte, password string, salt string) (string) {

    key := pbkdf2.Key([]byte(password), []byte(salt), 1024, 32, sha1.New)

    c, _ := aes.NewCipher(key)

    gcm, _ := cipher.NewGCMWithNonceSize(c, nonceSize)

    plaintextBytes, _ := gcm.Open(nil, cipherBytes[:nonceSize], cipherBytes[nonceSize:], nil)

    return string(plaintextBytes)

}


查看完整回答
反对 回复 2023-08-21
?
达令说

TA贡献1821条经验 获得超6个赞

尽管问题涉及“更强”的解密。

我想给出一个“标准”解密的完整示例来扩展之前的答案。

就我而言,任务是在 Go 中实现以下 Java 代码:

    import org.springframework.security.crypto.encrypt.Encryptors;

    import org.springframework.security.crypto.encrypt.TextEncryptor;

    ...

    private static final String SALT = "123456789abcdef0"; // hex

    public static String decrypt(final String encryptedText, final String password) {

        TextEncryptor encryptor = Encryptors.text(password, SALT);

        return encryptor.decrypt(encryptedText);

    }

代码翻译成Go:


import (

    "crypto/aes"

    "crypto/cipher"

    "crypto/sha1"

    "encoding/hex"

    "fmt"

    "strings"

    "golang.org/x/crypto/pbkdf2"

)


func decryptWithAes256CbcPbkdf2(cipherBytes []byte, passwordBytes []byte, saltBytes []byte) string {

    key := pbkdf2.Key(passwordBytes, saltBytes, 1024, 32, sha1.New)

    if len(key) != 32 {

        panic(fmt.Sprintf("Unexpected key length (!= 32) '%s' %d", key, len(key)))

    }


    block, err := aes.NewCipher(key)

    if err != nil {

        panic(err)

    }

    if len(cipherBytes) < aes.BlockSize {

        panic("ciphertext too short")

    }

    iv := cipherBytes[:aes.BlockSize]

    cipherBytes = cipherBytes[aes.BlockSize:]

    if len(cipherBytes)%aes.BlockSize != 0 {

        panic("ciphertext is not a multiple of the block size")

    }

    mode := cipher.NewCBCDecrypter(block, iv)

    mode.CryptBlocks(cipherBytes, cipherBytes)

    return strings.Trim(string(cipherBytes), "\b")

}


func main() {

    cipherText := "05589d13fe6eedceae78fe099eed2f6b238ac7d4dbb62c281ccdc9401b24bb0c"

    cipherBytes, _ := hex.DecodeString(cipherText)

    passwordText := "12345"

    passwordBytes := []byte(passwordText)

    saltText := "123456789abcdef0"

    saltBytes, _ := hex.DecodeString(saltText)

    plainText := decryptWithAes256CbcPbkdf2(cipherBytes, passwordBytes, saltBytes)

    fmt.Println(plainText)

}



查看完整回答
反对 回复 2023-08-21
  • 2 回答
  • 0 关注
  • 168 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信