今天接了个内部外包需求,要接中广协的 CAID 。
看了半天没看懂文档里对返回内容用“公钥解密”是什么意思,网络上也没搜到太多信息, 所以把处理方式共享下。
文档里面的例子是 JAVA ,我实现的逻辑是 Go ,关键信息来自 https://stackoverflow.com/questions/68984685/go-rsa-decrypt-using-public-key-implementation-from-java
package caid
import (
"bytes"
"crypto/rsa"
"encoding/base64"
"errors"
"fmt"
"io"
"log"
"math/big"
)
func decrypt(data string) ([]byte, error) {
raw, err := base64.StdEncoding.DecodeString(data)
if err != nil {
return nil, fmt.Errorf("base64 decode %w: %s", err, data)
}
reader := bytes.NewReader(raw)
var writer bytes.Buffer
chunk := make([]byte, maxDecryptBlock)
for {
n, err := io.ReadFull(reader, chunk)
if err != nil && errors.Is(err, io.ErrUnexpectedEOF) {
return nil, fmt.Errorf("read decrypted data: %w", err)
}
if n == 0 {
break
}
decryptChunk(chunk, &writer, pubKey)
}
output := bytes.TrimRight(bytes.TrimLeft(writer.Bytes(), "\x00"), "\n")
if bytes.Count(output, []byte("\x00")) > 0 {
after := bytes.ReplaceAll(output, []byte("\x00"), []byte{})
log.Println("WARN: remove \x00 from caid's response", "before", output, "after", after)
output = after
}
return output, nil
}
func decryptChunk(chunk []byte, writer *bytes.Buffer, pubKey *rsa.PublicKey) {
// Decrypt each signature chunk
ciphertextInt := new(big.Int)
ciphertextInt.SetBytes(chunk)
decryptedPaddedInt := doDecrypt(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 doDecrypt(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
}
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.