猿问

使用来自 Java 的公钥实现进行 RSA 解密

提供程序具有此示例 JAVA 代码,用于使用公钥解密 RSA。


 public static byte[] decryptByPublicKey(byte[] encryptedData, String publicKey)

            throws Exception {

        byte[] keyBytes = Base64.decodeBase64(publicKey);

        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);

        KeyFactory keyFactory = KeyFactory.getInstance("RSA");

        Key publicK = keyFactory.generatePublic(x509KeySpec);

        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());

        

        cipher.init(Cipher.DECRYPT_MODE, publicK);

        int inputLen = encryptedData.length;

        ByteArrayOutputStream out = new ByteArrayOutputStream();

        int offSet = 0;

        byte[] cache;

        int i = 0;

        while (inputLen - offSet > 0) {

            if (inputLen - offSet >(2048/8)) {

                cache = cipher.doFinal(encryptedData, offSet,(2048/8));

            } else {

                cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);

            }

            out.write(cache, 0, cache.length);

            i++;

            offSet = i *(2048/8);

        }

        byte[] decryptedData = out.toByteArray();

        out.close();

        return decryptedData;

    }

我试图在Go中写下等价物,但没有任何运气。


base64DecodeBytesKey, err := base64.StdEncoding.DecodeString(os.Getenv("PUBKEY"))

    if err != nil {

        Log(logRef, " error reading  pubkey", err)

    }


    pubKey, err := x509.ParsePKCS1PrivateKey(base64DecodeBytesKey)

c := new(big.Int)

    m := new(big.Int)

    m.SetBytes(data)

    e := big.NewInt(int64(pubKey.E))

    c.Exp(m, e, pubKey.N)

    out := c.Bytes()

    skip := 0



以上是第一次尝试,但失败了。 确实需要私钥,提供商坚持认为这不是必需的。rsa.DecryptPKCS1v15


encryptedBlockBytes, err := rsa.DecryptPKCS1v15(

            rand.Reader,

            NO_PRIVATE_KEY_PROVIDED,

            payloadBytes[start:finish])

    


有没有办法使用Go加密库从RSA验证PSS中获取解密的有效负载?


绝地无双
浏览 219回答 1
1回答

收到一只叮咚

从Java代码中,填充并不明确,因为只指定了算法,而没有指定填充。在这种情况下,填充取决于提供者,例如 SunJCE 提供者的 PKCS#1 v1.5。假设 PKCS#1 v1.5,则 /私钥和 /公钥的组合将&nbsp;RSASSA-PKCS1-v1_5作为填充。这在功能上与签名/验证相同(除了使用&nbsp;NonewithRSA&nbsp;进行验证还会与使用公钥解密相比检查数据的相等性)。Cipher.ENCRYPT_MODECipher.DECRYPT_MODENonewithRSA无与RSA意味着数据不进行哈希处理,并且没有预置摘要ID。此算法实际上旨在对已散列的数据进行签名(在预置摘要 ID 之后)。它绝不是要对未哈希的数据进行签名,即Java代码滥用此算法。由于消息大小受 RSA 限制(密钥大小减去填充所需的空间),因此只能对适当的短消息进行签名。因此,大小超过允许大小的未哈希数据将强制使用多个签名。这就是 Java 代码中多次解密的原因。使用散列数据不仅出于实际原因(签署长消息)而有用,而且出于安全原因也是必要的,例如这里和这里。要在 Go 中实现 Java 代码的功能,需要一个低级实现,以便在 Go 中签名/验证,就像在 Java 代码中一样。另一种可能性是实现解密(m = c^e)并自己删除填充,对于RSASSA-PKCS1-v1_5,它只是由一系列0xFF值组成,这些值由左侧的0x0001和右侧的0x00构成。在下文中,我将考虑第二种方法。下面的 Go 代码执行以下操作:导入公钥Base64 解码密文将密文拆分为单独的签名块(此处为包含相同数据的3个块:快速的棕色狐狸跳过懒惰的狗)解密每个签名块 (m = c ^ e)连接解密的签名区块package mainimport (&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "math/big"&nbsp; &nbsp; "encoding/pem"&nbsp; &nbsp; "crypto/x509"&nbsp; &nbsp; "crypto/rsa"&nbsp; &nbsp; "encoding/base64"&nbsp; &nbsp; "bytes"&nbsp; &nbsp; "io")func main() {&nbsp; &nbsp; pubKeyPem := `-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoZ67dtUTLxoXnNEzRBFBmwukEJGC+y69cGgpNbtElQj3m4Aft/7cu9qYbTNguTSnCDt7uovZNb21u1vpZwKHyVgFEGO4SA8RNnjhJt2D7z8RDMWX3saody7jo9TKlrPABLZGo2o8vadW8Dly/v+Id0YDheCkVCoCEeUjQ8koXZhTwhYkGPu+vkdiqX5cUaiVTu1uzt591aO5Vw/hV4DIhFKnOTnYXnpXiwRwtPyYoGTa64yWfi2t0bv99qz0BgDjQjD0civCe8LRXGGhyB1U1aHjDDGEnulTYJyEqCzNGwBpzEHUjqIOXElFjt55AFGpCHAuyuoXoP3gQvoSj6RCsQIDAQAB-----END PUBLIC KEY-----`&nbsp; &nbsp; // Import public key&nbsp; &nbsp; pubKey := ImportSPKIPublicKeyPEM(pubKeyPem);&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; // Base64 decode ciphertext&nbsp; &nbsp; ciphertextBytes, _ := base64.StdEncoding.DecodeString("ajQbkszbZ97YZaPSRBab9vj0DDLm9tTrQwSZ+ucPj+cYSmw06KLCtRH3SPn3b2DqSd1revLXqxMtSzFmjRvZ5F8y3nzdP8NJaRplOigbPFhKZTv7xBVK5ATEmLukgtI7f+d3KdmGUG+cyTkfxIrMBvB3BIS5oTiMNmC9pqLaWcDVF9qpuxnwEMQJbeO9nTklpdv+F8BrchHmeUkKRrMJBoPbbcfq9Hi4bHiFyxPWhwB66d/AryCKsFRhaX6hSkTL+0NvuhVhv98wdo3juv2Il50XKOCbfc8kUG628TcSK6n31piLF9cntSVTB/L/pVfcAxEwx4hcUhLuqmk6EZIJvGo0G5LM22fe2GWj0kQWm/b49Awy5vbU60MEmfrnD4/nGEpsNOiiwrUR90j5929g6knda3ry16sTLUsxZo0b2eRfMt583T/DSWkaZTooGzxYSmU7+8QVSuQExJi7pILSO3/ndynZhlBvnMk5H8SKzAbwdwSEuaE4jDZgvaai2lnA1RfaqbsZ8BDECW3jvZ05JaXb/hfAa3IR5nlJCkazCQaD223H6vR4uGx4hcsT1ocAeunfwK8girBUYWl+oUpEy/tDb7oVYb/fMHaN47r9iJedFyjgm33PJFButvE3Eiup99aYixfXJ7UlUwfy/6VX3AMRMMeIXFIS7qppOhGSCbxqNBuSzNtn3thlo9JEFpv2+PQMMub21OtDBJn65w+P5xhKbDToosK1EfdI+fdvYOpJ3Wt68terEy1LMWaNG9nkXzLefN0/w0lpGmU6KBs8WEplO/vEFUrkBMSYu6SC0jt/53cp2YZQb5zJOR/EiswG8HcEhLmhOIw2YL2motpZwNUX2qm7GfAQxAlt472dOSWl2/4XwGtyEeZ5SQpGswkGg9ttx+r0eLhseIXLE9aHAHrp38CvIIqwVGFpfqFKRMv7Q2+6FWG/3zB2jeO6/YiXnRco4Jt9zyRQbrbxNxIrqffWmIsX1ye1JVMH8v+lV9wDETDHiFxSEu6qaToRkgm8")&nbsp; &nbsp; // Split ciphertext into signature chunks a 2048/8 bytes and decrypt each chunk&nbsp; &nbsp; reader := bytes.NewReader(ciphertextBytes)&nbsp; &nbsp; var writer bytes.Buffer&nbsp; &nbsp; ciphertextBytesChunk := make([]byte, 2048/8)&nbsp; &nbsp; for {&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; n, _ := io.ReadFull(reader, ciphertextBytesChunk)&nbsp; &nbsp; &nbsp; &nbsp; if (n == 0) {&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; decryptChunk(ciphertextBytesChunk, &writer, pubKey)&nbsp; &nbsp; }&nbsp; &nbsp; // Concatenate decrypted signature chunks&nbsp; &nbsp; decryptedData := writer.String()&nbsp; &nbsp; fmt.Println(decryptedData)&nbsp; &nbsp; &nbsp;&nbsp;}func ImportSPKIPublicKeyPEM(spkiPEM string) (*rsa.PublicKey) {&nbsp; &nbsp; body, _ := pem.Decode([]byte(spkiPEM ))&nbsp;&nbsp; &nbsp; publicKey, _ := x509.ParsePKIXPublicKey(body.Bytes)&nbsp; &nbsp; if publicKey, ok := publicKey.(*rsa.PublicKey); ok {&nbsp; &nbsp; &nbsp; &nbsp; return publicKey&nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; return nil&nbsp; &nbsp; }&nbsp; &nbsp;}func decryptChunk(ciphertextBytesChunk []byte , writer *bytes.Buffer, pubKey *rsa.PublicKey ){&nbsp; &nbsp; // Decrypt each signature chunk&nbsp; &nbsp; ciphertextInt := new(big.Int)&nbsp; &nbsp; ciphertextInt.SetBytes(ciphertextBytesChunk)&nbsp; &nbsp; decryptedPaddedInt := decrypt(new(big.Int), pubKey, ciphertextInt)&nbsp;&nbsp;&nbsp; &nbsp; // Remove padding&nbsp; &nbsp; decryptedPaddedBytes := make([]byte, pubKey.Size())&nbsp; &nbsp; decryptedPaddedInt.FillBytes(decryptedPaddedBytes)&nbsp; &nbsp; start := bytes.Index(decryptedPaddedBytes[1:], []byte{0}) + 1 // // 0001FF...FF00<data>: Find index after 2nd 0x00&nbsp; &nbsp; decryptedBytes := decryptedPaddedBytes[start:]&nbsp;&nbsp;&nbsp; &nbsp; // Write decrypted signature chunk&nbsp; &nbsp; writer.Write(decryptedBytes)}func decrypt(c *big.Int, pub *rsa.PublicKey, m *big.Int) *big.Int {&nbsp; &nbsp; // Textbook RSA&nbsp; &nbsp; e := big.NewInt(int64(pub.E))&nbsp; &nbsp; c.Exp(m, e, pub.N)&nbsp; &nbsp; return c}输出:The quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dog请注意,代码只是一个示例实现,特别是不包括异常处理。测试:下面的 Java 代码String publicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoZ67dtUTLxoXnNEzRBFBmwukEJGC+y69cGgpNbtElQj3m4Aft/7cu9qYbTNguTSnCDt7uovZNb21u1vpZwKHyVgFEGO4SA8RNnjhJt2D7z8RDMWX3saody7jo9TKlrPABLZGo2o8vadW8Dly/v+Id0YDheCkVCoCEeUjQ8koXZhTwhYkGPu+vkdiqX5cUaiVTu1uzt591aO5Vw/hV4DIhFKnOTnYXnpXiwRwtPyYoGTa64yWfi2t0bv99qz0BgDjQjD0civCe8LRXGGhyB1U1aHjDDGEnulTYJyEqCzNGwBpzEHUjqIOXElFjt55AFGpCHAuyuoXoP3gQvoSj6RCsQIDAQAB";&nbsp;byte[] ciphertext = Base64.getDecoder().decode("ajQbkszbZ97YZaPSRBab9vj0DDLm9tTrQwSZ+ucPj+cYSmw06KLCtRH3SPn3b2DqSd1revLXqxMtSzFmjRvZ5F8y3nzdP8NJaRplOigbPFhKZTv7xBVK5ATEmLukgtI7f+d3KdmGUG+cyTkfxIrMBvB3BIS5oTiMNmC9pqLaWcDVF9qpuxnwEMQJbeO9nTklpdv+F8BrchHmeUkKRrMJBoPbbcfq9Hi4bHiFyxPWhwB66d/AryCKsFRhaX6hSkTL+0NvuhVhv98wdo3juv2Il50XKOCbfc8kUG628TcSK6n31piLF9cntSVTB/L/pVfcAxEwx4hcUhLuqmk6EZIJvGo0G5LM22fe2GWj0kQWm/b49Awy5vbU60MEmfrnD4/nGEpsNOiiwrUR90j5929g6knda3ry16sTLUsxZo0b2eRfMt583T/DSWkaZTooGzxYSmU7+8QVSuQExJi7pILSO3/ndynZhlBvnMk5H8SKzAbwdwSEuaE4jDZgvaai2lnA1RfaqbsZ8BDECW3jvZ05JaXb/hfAa3IR5nlJCkazCQaD223H6vR4uGx4hcsT1ocAeunfwK8girBUYWl+oUpEy/tDb7oVYb/fMHaN47r9iJedFyjgm33PJFButvE3Eiup99aYixfXJ7UlUwfy/6VX3AMRMMeIXFIS7qppOhGSCbxqNBuSzNtn3thlo9JEFpv2+PQMMub21OtDBJn65w+P5xhKbDToosK1EfdI+fdvYOpJ3Wt68terEy1LMWaNG9nkXzLefN0/w0lpGmU6KBs8WEplO/vEFUrkBMSYu6SC0jt/53cp2YZQb5zJOR/EiswG8HcEhLmhOIw2YL2motpZwNUX2qm7GfAQxAlt472dOSWl2/4XwGtyEeZ5SQpGswkGg9ttx+r0eLhseIXLE9aHAHrp38CvIIqwVGFpfqFKRMv7Q2+6FWG/3zB2jeO6/YiXnRco4Jt9zyRQbrbxNxIrqffWmIsX1ye1JVMH8v+lV9wDETDHiFxSEu6qaToRkgm8");byte[] decrypted = decryptByPublicKey(ciphertext, publicKey);&nbsp;System.out.println(new String(decrypted, StandardCharsets.UTF_8));使用您发布的方法给出相同的结果。
随时随地看视频慕课网APP

相关分类

Go
我要回答