用Java的公钥进行RSA解密操作
在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代码中多次解密的原因。
使用散列数据不仅出于实际原因(签署长消息)有用,而且出于安全原因也是必要的。例如here和here。
为了在 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<data>: 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学习网公众号!
终止 golang 中执行 exec.command 的子进程
- 上一篇
- 终止 golang 中执行 exec.command 的子进程
- 下一篇
- 将大括号{}转换为键值对{}
-
- Golang · Go问答 | 1年前 |
- 在读取缓冲通道中的内容之前退出
- 139浏览 收藏
-
- Golang · Go问答 | 1年前 |
- 戈兰岛的全球 GOPRIVATE 设置
- 204浏览 收藏
-
- Golang · Go问答 | 1年前 |
- 如何将结构作为参数传递给 xml-rpc
- 325浏览 收藏
-
- Golang · Go问答 | 1年前 |
- 如何用golang获得小数点以下两位长度?
- 478浏览 收藏
-
- Golang · Go问答 | 1年前 |
- 如何通过 client-go 和 golang 检索 Kubernetes 指标
- 486浏览 收藏
-
- Golang · Go问答 | 1年前 |
- 将多个“参数”映射到单个可变参数的习惯用法
- 439浏览 收藏
-
- Golang · Go问答 | 1年前 |
- 将 HTTP 响应正文写入文件后出现 EOF 错误
- 357浏览 收藏
-
- Golang · Go问答 | 1年前 |
- 结构中映射的匿名列表的“复合文字中缺少类型”
- 352浏览 收藏
-
- Golang · Go问答 | 1年前 |
- NATS Jetstream 的性能
- 101浏览 收藏
-
- Golang · Go问答 | 1年前 |
- 如何将复杂的字符串输入转换为mapstring?
- 440浏览 收藏
-
- Golang · Go问答 | 1年前 |
- 相当于GoLang中Java将Object作为方法参数传递
- 212浏览 收藏
-
- Golang · Go问答 | 1年前 |
- 如何确保所有 goroutine 在没有 time.Sleep 的情况下终止?
- 143浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- ChatExcel酷表
- ChatExcel酷表是由北京大学团队打造的Excel聊天机器人,用自然语言操控表格,简化数据处理,告别繁琐操作,提升工作效率!适用于学生、上班族及政府人员。
- 3204次使用
-
- Any绘本
- 探索Any绘本(anypicturebook.com/zh),一款开源免费的AI绘本创作工具,基于Google Gemini与Flux AI模型,让您轻松创作个性化绘本。适用于家庭、教育、创作等多种场景,零门槛,高自由度,技术透明,本地可控。
- 3417次使用
-
- 可赞AI
- 可赞AI,AI驱动的办公可视化智能工具,助您轻松实现文本与可视化元素高效转化。无论是智能文档生成、多格式文本解析,还是一键生成专业图表、脑图、知识卡片,可赞AI都能让信息处理更清晰高效。覆盖数据汇报、会议纪要、内容营销等全场景,大幅提升办公效率,降低专业门槛,是您提升工作效率的得力助手。
- 3446次使用
-
- 星月写作
- 星月写作是国内首款聚焦中文网络小说创作的AI辅助工具,解决网文作者从构思到变现的全流程痛点。AI扫榜、专属模板、全链路适配,助力新人快速上手,资深作者效率倍增。
- 4555次使用
-
- MagicLight
- MagicLight.ai是全球首款叙事驱动型AI动画视频创作平台,专注于解决从故事想法到完整动画的全流程痛点。它通过自研AI模型,保障角色、风格、场景高度一致性,让零动画经验者也能高效产出专业级叙事内容。广泛适用于独立创作者、动画工作室、教育机构及企业营销,助您轻松实现创意落地与商业化。
- 3824次使用
-
- GoLand调式动态执行代码
- 2023-01-13 502浏览
-
- 用Nginx反向代理部署go写的网站。
- 2023-01-17 502浏览
-
- Golang取得代码运行时间的问题
- 2023-02-24 501浏览
-
- 请问 go 代码如何实现在代码改动后不需要Ctrl+c,然后重新 go run *.go 文件?
- 2023-01-08 501浏览
-
- 如何从同一个 io.Reader 读取多次
- 2023-04-11 501浏览

