当前位置:首页 > 文章列表 > 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基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • ljg-skills -
    ljg-skills
    ljg-skills 是李继刚开源的 AI 技能与提示词集合,面向大模型使用者整理了一批可复用的 prompt、角色设定和任务技能模板,适合用于学习提示词设计、搭建个人 AI 工作流和沉淀团队常用智能体能力。
    805次使用
  • MELO音乐 - AI 音乐生成平台,支持多模态创作能力
    MELO音乐
    MELO音乐是一站式AI视频与音乐制作助手,对标suno, udio的高品质体验。提供伴奏生成、原创写词、无损导出、哼唱识曲、混音变声等全套音频与短视频编辑工具。无论是流行Kpop、电音说唱、民谣古风、摇滚儿歌还是商用轻音乐,MELO为你免费谱曲,轻松做同款!
    805次使用
  • UniScribe - AI 免费在线音视频转文字平台
    UniScribe
    UniScribe 是一款 AI 音视频转文字与内容整理工具,支持上传音频、视频文件或粘贴 YouTube 链接,自动生成转写文本、摘要、思维导图和关键问题,并支持多格式导出,适合会议记录、课程学习、访谈整理和内容创作复盘。
    747次使用
  • 剧云 - 免费 AI 智能中文剧本创作平台
    剧云
    剧云是专业中文剧本创作平台,安全稳定运行十余年,集成AI编剧、剧本医生审核、人物小传、剧情关系图、大纲编写、多人协作、Word导入导出、版权管控功能,数据安全防护,轻松高效创作剧本。
    944次使用
  • 万象有声 - AI 一站式有声内容创作平台
    万象有声
    万象有声,一个专为有声创作者打造的新一代智能有声内容创作平台。平台提供专业的智能拆章、智能画本编辑、AI配音、AI生成音效、后期制作、智能对轨、智能审听等有声创作全流程工具,可以帮助创作者高效、低成本创作出引人入胜的有声作品。立即体验,让有声书制作更简单!
    908次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议隐私政策
返回登录
  • 重置密码