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

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

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

Go
慕码人8056858 2022-05-23 16:25:46
加密将在客户端使用以下基于 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%3Dcipher: 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 回答

?
侃侃尔雅

TA贡献1801条经验 获得超16个赞

所以重点:

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

  • Spring Security 中的nonce(或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)

}


查看完整回答
反对 回复 2022-05-23
?
ibeautiful

TA贡献1993条经验 获得超5个赞

尽管问题与“更强”的解密有关。


请参阅:https ://docs.spring.io/spring-security/site/docs/4.2.20.RELEASE/apidocs/org/springframework/security/crypto/encrypt/Encryptors.html


我想举一个“标准”解密的完整例子来扩展前面的答案。


就我而言,任务是在 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)

}

查看完整回答
反对 回复 2022-05-23
  • 2 回答
  • 0 关注
  • 461 浏览
慕课专栏
更多

添加回答

举报

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