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

加密将在客户端使用以下基于 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;


@Component

public 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;

    }

}

样本资源:aResource


URL 和 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

    }



  

慕码人8056858
浏览 463回答 2
2回答

侃侃尔雅

所以重点:为了应用盐并派生正确的密钥,pbkdf2.Key()必须使用如下所示Spring Security 中的nonce(或Initialization Vector)大小是 16 个字节,而不是 12 个字节go下面的摘录省略了错误处理,只是为了强调解决方案的本质:const nonceSize = 16func 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)}

ibeautiful

尽管问题与“更强”的解密有关。请参阅:https ://docs.spring.io/spring-security/site/docs/4.2.20.RELEASE/apidocs/org/springframework/security/crypto/encrypt/Encryptors.html我想举一个“标准”解密的完整例子来扩展前面的答案。就我而言,任务是在 Go 中实现以下 Java 代码:&nbsp; &nbsp; import org.springframework.security.crypto.encrypt.Encryptors;&nbsp; &nbsp; import org.springframework.security.crypto.encrypt.TextEncryptor;&nbsp; &nbsp; ...&nbsp; &nbsp; private static final String SALT = "123456789abcdef0"; // hex&nbsp; &nbsp; public static String decrypt(final String encryptedText, final String password) {&nbsp; &nbsp; &nbsp; &nbsp; TextEncryptor encryptor = Encryptors.text(password, SALT);&nbsp; &nbsp; &nbsp; &nbsp; return encryptor.decrypt(encryptedText);&nbsp; &nbsp; }翻译成 Go 的代码:import (&nbsp; &nbsp; "crypto/aes"&nbsp; &nbsp; "crypto/cipher"&nbsp; &nbsp; "crypto/sha1"&nbsp; &nbsp; "encoding/hex"&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "strings"&nbsp; &nbsp; "golang.org/x/crypto/pbkdf2")func decryptWithAes256CbcPbkdf2(cipherBytes []byte, passwordBytes []byte, saltBytes []byte) string {&nbsp; &nbsp; key := pbkdf2.Key(passwordBytes, saltBytes, 1024, 32, sha1.New)&nbsp; &nbsp; if len(key) != 32 {&nbsp; &nbsp; &nbsp; &nbsp; panic(fmt.Sprintf("Unexpected key length (!= 32) '%s' %d", key, len(key)))&nbsp; &nbsp; }&nbsp; &nbsp; block, err := aes.NewCipher(key)&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; panic(err)&nbsp; &nbsp; }&nbsp; &nbsp; if len(cipherBytes) < aes.BlockSize {&nbsp; &nbsp; &nbsp; &nbsp; panic("ciphertext too short")&nbsp; &nbsp; }&nbsp; &nbsp; iv := cipherBytes[:aes.BlockSize]&nbsp; &nbsp; cipherBytes = cipherBytes[aes.BlockSize:]&nbsp; &nbsp; if len(cipherBytes)%aes.BlockSize != 0 {&nbsp; &nbsp; &nbsp; &nbsp; panic("ciphertext is not a multiple of the block size")&nbsp; &nbsp; }&nbsp; &nbsp; mode := cipher.NewCBCDecrypter(block, iv)&nbsp; &nbsp; mode.CryptBlocks(cipherBytes, cipherBytes)&nbsp; &nbsp; return strings.Trim(string(cipherBytes), "\b")}func main() {&nbsp; &nbsp; cipherText := "05589d13fe6eedceae78fe099eed2f6b238ac7d4dbb62c281ccdc9401b24bb0c"&nbsp; &nbsp; cipherBytes, _ := hex.DecodeString(cipherText)&nbsp; &nbsp; passwordText := "12345"&nbsp; &nbsp; passwordBytes := []byte(passwordText)&nbsp; &nbsp; saltText := "123456789abcdef0"&nbsp; &nbsp; saltBytes, _ := hex.DecodeString(saltText)&nbsp; &nbsp; plainText := decryptWithAes256CbcPbkdf2(cipherBytes, passwordBytes, saltBytes)&nbsp; &nbsp; fmt.Println(plainText)}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go