V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
GopherDaily
V2EX  ›  程序员

中广协 CAID 公钥加密

  •  1
     
  •   GopherDaily · 5 天前 · 1475 次点击

    今天接了个内部外包需求,要接中广协的 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
    }
    
    
    第 1 条附言  ·  5 天前
    公钥解密
    第 2 条附言  ·  5 天前
    本来只是用来给相关人员搜索的,所以没说明。


    1. 中广协的文档自己定义的是用公钥解密他们返回的内容。
    2. 但像我这样的半吊子选手应该了解,私钥签名,公钥验签,或者公钥加密,私钥解密,不存在私钥加密,公钥解密这一套
    3. 人家给的 Java 的代码例子确实是解密,虽然跑不起来,但应该能跑
    4. 这就涉及到一个 Java Cipher 的隐藏逻辑,如果你用私钥&RSA 去加密数据,基本等于签名
    5. 如果你没搜索到上面的逻辑,我估计要花很久才能走通他们的逻辑
    9 条回复    2025-01-17 12:08:06 +08:00
    pandaex
        1
    pandaex  
       5 天前 via Android
    如果是想问为啥是公钥解密,硬想一个可以是用于认证这个数据是官方给出的
    duzhuo
        2
    duzhuo  
       5 天前
    @pandaex 那不是签名吗
    ma46
        3
    ma46  
       5 天前
    就字面意思啊, 用公钥来解密对方发来的数据, 如果你不知道公钥是什么就找对方要
    sagaxu
        4
    sagaxu  
       5 天前   ❤️ 1
    公钥加密,私钥解密。私钥签名,公钥验签。签名是确保发送人不被伪造,加密是为了防止被中间人攻击嗅探数据。

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

    如果同时写 Java 和 Go ,一定会遇到 PKCS1 和 PKCS8 格式差异。
    yankebupt
        5
    yankebupt  
       5 天前
    虽然公钥是公开的所以私钥处理后并不会赋予秘密属性,但你就说是不是解密算法吧……( doge
    ZRS
        6
    ZRS  
       5 天前
    可以,但比较脱裤子放屁,就当是混淆传输吧
    jocover
        7
    jocover  
       5 天前
    就是把 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
        8
    murmur  
       4 天前
    @ZRS 这是商密还是等保 3 的要求,我也既不清楚了,要求 api 接口不能露路径,body 和 request 都是加密传输

    就是类似所有的接口都是/api/entry ,如果碰到什么/user/info 就算你没加密全
    marvin001
        9
    marvin001  
       3 天前
    我测试好像还是不行
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2384 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 21ms · UTC 16:00 · PVG 00:00 · LAX 08:00 · JFK 11:00
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.