登录
首页 >  Golang >  Go问答

用Java的公钥进行RSA解密操作

来源:stackoverflow

时间:2024-02-12 20:57:23 122浏览 收藏

在IT行业这个发展更新速度很快的行业,只有不停止的学习,才不会被行业所淘汰。如果你是Golang学习者,那么本文《用Java的公钥进行RSA解密操作》就很适合你!本篇内容主要包括##content_title##,希望对大家的知识积累有所帮助,助力实战开发!

问题内容

提供商拥有此示例 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
    log(" payload size:--> ", len(data))
    for i := 2; i < len(out); i++ {
        if i+1 >= len(out) {
            break
        }
        if out[i] == 0xff && out[i+1] == 0 {
            skip = i + 2
            break
        }
    }
    return out[skip:]

以上是第一次尝试,但失败了。 rsa.decryptpkcs1v15 确实需要私钥,但提供商坚称没有必要。

encryptedBlockBytes, err := rsa.DecryptPKCS1v15(
            rand.Reader,
            NO_PRIVATE_KEY_PROVIDED,
            payloadBytes[start:finish])

有没有办法使用 go crypt 库从 rsa 验证 pss 获取解密的有效负载?


正确答案


从java代码来看,填充并不清楚,因为只指定了算法,但没有指定填充。在这种情况下,填充取决于提供者,例如sunjce 提供程序的 pkcs#1 v1.5。

假设 pkcs#1 v1.5,cipher.encrypt_mode/私钥和 cipher.decrypt_mode/公钥的组合应用 RSASSA-PKCS1-v1_5 作为填充。这在功能上与使用 nonewithrsa 进行签名/验证相同(除了使用 nonewithrsa 进行验证使用公钥解密相比还额外检查数据的相等性)。

NonewithRSA 表示数据未经过哈希处理,并且没有在前面添加摘要 id。该算法实际上旨在对已经散列的数据进行签名(在预先添加摘要 id 之后)。它绝不意味着对未散列的数据进行签名,即 java 代码滥用了该算法。
由于 rsa 限制消息大小(密钥大小减去填充所需的空间),因此只能对适当的短消息进行签名。因此,大小超过允许大小的未散列数据会强制进行多重签名。这就是java代码中多次解密的原因。
使用散列数据不仅出于实际原因(签署长消息)有用,而且出于安全原因也是必要的。例如herehere

为了在 go 中实现 java 代码的功能,需要像在 java 代码中一样在 go 中进行签名/验证的低级实现。
另一种可能性是实现解密 (m = c^e) 并自行删除填充,对于 rsassa-pkcs1-v1_5,填充仅由一系列 0xff 值组成,左侧为 0x0001,右侧为 0x00。 p>

下面我考虑第二种方法。下面的 go 代码执行以下操作:

  • 导入公钥
  • base64 解码密文
  • 将密文分割成单独的签名块(这里 3 个块包含相同的数据:敏捷的棕色狐狸跳过懒狗
  • 解密每个签名块(m = c ^ e)
  • 连接解密的签名块
package main

import (
    "fmt"
    "math/big"
    "encoding/pem"
    "crypto/x509"
    "crypto/rsa"
    "encoding/base64"
    "bytes"
    "io"
)

func main() {

    pubkeypem := `-----begin public key-----
miibijanbgkqhkig9w0baqefaaocaq8amiibcgkcaqeaoz67dtutlxoxnnezrbfb
mwukejgc+y69cggpnbtelqj3m4aft/7cu9qybtngutsncdt7uovznb21u1vpzwkh
yvgfego4sa8rnnjhjt2d7z8rdmwx3saody7jo9tklrpablzgo2o8vadw8dly/v+i
d0ydheckvcoceeujq8koxzhtwhykgpu+vkdiqx5cuaivtu1uzt591ao5vw/hv4di
hfknotnyxnpxiwrwtpyyogta64ywfi2t0bv99qz0bgdjqjd0civce8lrxgghyb1u
1ahjddgenultyjyeqczngwbpzehujqioxelfjt55afgpchauyuoxop3gqvosj6rc
sqidaqab
-----end public key-----`

    // import public key
    pubkey := importspkipublickeypem(pubkeypem);    
    // base64 decode ciphertext
    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")
    // split ciphertext into signature chunks a 2048/8 bytes and decrypt each chunk
    reader := bytes.newreader(ciphertextbytes)
    var writer bytes.buffer
    ciphertextbyteschunk := make([]byte, 2048/8)
    for { 
        n, _ := io.readfull(reader, ciphertextbyteschunk)
        if (n == 0) { 
            break
        }
        decryptchunk(ciphertextbyteschunk, &writer, pubkey)
    }
    // concatenate decrypted signature chunks
    decrypteddata := writer.string()
    fmt.println(decrypteddata)      
}

func importspkipublickeypem(spkipem string) (*rsa.publickey) {
    body, _ := pem.decode([]byte(spkipem )) 
    publickey, _ := x509.parsepkixpublickey(body.bytes)
    if publickey, ok := publickey.(*rsa.publickey); ok {
        return publickey
    } else {
        return nil
    }   
}

func decryptchunk(ciphertextbyteschunk []byte , writer *bytes.buffer, pubkey *rsa.publickey ){
    // decrypt each signature chunk
    ciphertextint := new(big.int)
    ciphertextint.setbytes(ciphertextbyteschunk)
    decryptedpaddedint := decrypt(new(big.int), pubkey, ciphertextint)  
    // remove padding
    decryptedpaddedbytes := make([]byte, pubkey.size())
    decryptedpaddedint.fillbytes(decryptedpaddedbytes)
    start := bytes.index(decryptedpaddedbytes[1:], []byte{0}) + 1 // // 0001ff...ff00: find index after 2nd 0x00
    decryptedbytes := decryptedpaddedbytes[start:]  
    // write decrypted signature chunk
    writer.write(decryptedbytes)
}

func decrypt(c *big.int, pub *rsa.publickey, m *big.int) *big.int {
    // textbook rsa
    e := big.newint(int64(pub.e))
    c.exp(m, e, pub.n)
    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"; 
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); 
System.out.println(new String(decrypted, StandardCharsets.UTF_8));

使用您发布的方法会得到相同的结果。

本篇关于《用Java的公钥进行RSA解密操作》的介绍就到此结束啦,但是学无止境,想要了解学习更多关于Golang的相关知识,请关注golang学习网公众号!

声明:本文转载于:stackoverflow 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>