当前位置:首页 > 文章列表 > Golang > Go问答 > 用Java的公钥进行RSA解密操作

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

来源:stackoverflow 2024-02-12 20:57:23 0浏览 收藏

在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删除
终止 golang 中执行 exec.command 的子进程终止 golang 中执行 exec.command 的子进程
上一篇
终止 golang 中执行 exec.command 的子进程
将大括号{}转换为键值对{}
下一篇
将大括号{}转换为键值对{}
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    542次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    508次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    497次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    484次学习
查看更多
AI推荐
  • 毕业宝AIGC检测:AI生成内容检测工具,助力学术诚信
    毕业宝AIGC检测
    毕业宝AIGC检测是“毕业宝”平台的AI生成内容检测工具,专为学术场景设计,帮助用户初步判断文本的原创性和AI参与度。通过与知网、维普数据库联动,提供全面检测结果,适用于学生、研究者、教育工作者及内容创作者。
    12次使用
  • AI Make Song:零门槛AI音乐创作平台,助你轻松制作个性化音乐
    AI Make Song
    AI Make Song是一款革命性的AI音乐生成平台,提供文本和歌词转音乐的双模式输入,支持多语言及商业友好版权体系。无论你是音乐爱好者、内容创作者还是广告从业者,都能在这里实现“用文字创造音乐”的梦想。平台已生成超百万首原创音乐,覆盖全球20个国家,用户满意度高达95%。
    26次使用
  • SongGenerator.io:零门槛AI音乐生成器,快速创作高质量音乐
    SongGenerator
    探索SongGenerator.io,零门槛、全免费的AI音乐生成器。无需注册,通过简单文本输入即可生成多风格音乐,适用于内容创作者、音乐爱好者和教育工作者。日均生成量超10万次,全球50国家用户信赖。
    23次使用
  •  BeArt AI换脸:免费在线工具,轻松实现照片、视频、GIF换脸
    BeArt AI换脸
    探索BeArt AI换脸工具,免费在线使用,无需下载软件,即可对照片、视频和GIF进行高质量换脸。体验快速、流畅、无水印的换脸效果,适用于娱乐创作、影视制作、广告营销等多种场景。
    26次使用
  • SEO标题协启动:AI驱动的智能对话与内容生成平台 - 提升创作效率
    协启动
    SEO摘要协启动(XieQiDong Chatbot)是由深圳协启动传媒有限公司运营的AI智能服务平台,提供多模型支持的对话服务、文档处理和图像生成工具,旨在提升用户内容创作与信息处理效率。平台支持订阅制付费,适合个人及企业用户,满足日常聊天、文案生成、学习辅助等需求。
    27次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议隐私政策
返回登录
  • 重置密码