中广协 CAID 公钥加密

18 天前
 GopherDaily

今天接了个内部外包需求,要接中广协的 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
}

1632 次点击
所在节点    程序员
9 条回复
pandaex
17 天前
如果是想问为啥是公钥解密,硬想一个可以是用于认证这个数据是官方给出的
duzhuo
17 天前
@pandaex 那不是签名吗
ma46
17 天前
就字面意思啊, 用公钥来解密对方发来的数据, 如果你不知道公钥是什么就找对方要
sagaxu
17 天前
公钥加密,私钥解密。私钥签名,公钥验签。签名是确保发送人不被伪造,加密是为了防止被中间人攻击嗅探数据。

在强安全场景,加密和签名经常一起用。我们也经常看到用非对称加密打包对称加密的密码,提高安全性的同时,减小计算压力,如 SSL 。

如果同时写 Java 和 Go ,一定会遇到 PKCS1 和 PKCS8 格式差异。
yankebupt
17 天前
虽然公钥是公开的所以私钥处理后并不会赋予秘密属性,但你就说是不是解密算法吧……( doge
ZRS
17 天前
可以,但比较脱裤子放屁,就当是混淆传输吧
jocover
17 天前
就是把 d 和 e 换下就行了

// mpz_powm(ct, pt, e, n);//公钥加密
mpz_powm(ct, pt, d, n);//私钥加密
gmp_printf("Encoded: %Zx\n", ct);

// mpz_powm(pt, ct, d, n); //私钥解密
mpz_powm(pt, ct, e, n); //公钥解密
gmp_printf("Decoded: %Zx\n", pt);
murmur
17 天前
@ZRS 这是商密还是等保 3 的要求,我也既不清楚了,要求 api 接口不能露路径,body 和 request 都是加密传输

就是类似所有的接口都是/api/entry ,如果碰到什么/user/info 就算你没加密全
marvin001
16 天前
我测试好像还是不行

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://tanronggui.xyz/t/1105311

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX