Files
2026-05-27 23:03:00 +08:00

272 lines
8.6 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package outsource
import (
"bytes"
"math/big"
"testing"
"github.com/stretchr/testify/assert"
"xdx.jelly/xgcl/gmath"
"xdx.jelly/xgcl/grand"
"xdx.jelly/xgcl/he/paillier"
"xdx.jelly/xgcl/sm/sm2"
"xdx.jelly/xgcl/sm/sm3"
"xdx.jelly/xgcl/tpc/sm2/sm2m"
)
// osGenerateKey 客户端,外包,服务端协同密钥生成
func osGenerateKey(t *testing.T) (*paillier.PrivateKey, *paillier.PublicKey, *paillier.Cipher, *paillier.Cipher, *sm2.PrivateKey, *sm2.PublicKey) {
rnd := grand.Reader
salt := []byte("12345678")
paiPrivKey, err := paillier.GenerateKeyFromPassword(2048, []byte("password123"), salt, 1024)
assert.Nil(t, err)
paiPubKey := paiPrivKey.Public()
// 一、密钥生成
// 1)客户端第一步, a1, a2 发 外包服务器
clientKeyGen := &ClientKeyGenerator{}
a1, a2, err := clientKeyGen.Step1(paiPubKey, rnd)
assert.Nil(t, err)
// 2) 外包服务器第一步
// 保存encryptedClientKey1encryptedClientKey2,
// 把 P 发客户端
// encryptedClientKey1 -签名用
// encryptedClientKey2 -解密加密密钥保护结构用
osKenGen := &OSKeyGenerator{}
encryptedClientKey1, encryptedClientKey2, P, err := osKenGen.Step1(a1, a2, paiPubKey, rnd)
assert.Nil(t, err)
// 3) 客户端第二步
// clientTempKey发协同签名服务端
clientTempKey, err := clientKeyGen.Step2(P)
// 4)协同签名服务器
// serverTempKey 发客户端,保存serverKey-服务端密钥分量
b := make([]byte, 32)
rnd.Read(b)
serverKey, serverTempKey, publicKey, _ := sm2m.ServerGenSignKey(clientTempKey, b)
// 5)客户端第三步
// 把(serverTempKey,S)发送给外包服务器
S, err := clientKeyGen.Step3(serverTempKey)
assert.Nil(t, err)
// 6)外包服务器第二步
// 把T osPublicKey发给客户端。保存osPublicKey为用户签名公钥
T, osPublicKey, err := osKenGen.Step2(serverTempKey, S)
assert.Nil(t, err)
// 7)客户端第四步
// clientPublicKey, 客户端生成的公钥,如果没有返错,则应与ocPublicKey一致。
clientPublicKey, err := clientKeyGen.Step4(T)
assert.Nil(t, err)
assert.True(t, clientPublicKey.Equals(osPublicKey))
return paiPrivKey, paiPubKey, encryptedClientKey1, encryptedClientKey2, serverKey, publicKey
}
// 外包签名流程
func TestOSSign(t *testing.T) {
//O、生成密钥
var err error
rnd := grand.Reader
paiPrivKey, paiPubKey, encryptedClientKey1, _, serverKey, publicKey := osGenerateKey(t)
e := make([]byte, 32)
rnd.Read(e)
clientCtx := NewClientSignContext(paiPrivKey, rnd)
// 1) client -> os
// 2os -> client
osServerCtx := NewOSSignContext()
pp, err := osServerCtx.Step1(rnd) // P'
assert.Nil(t, err)
// 3) client -> hfserver
p, err := clientCtx.Step1(e, pp)
assert.Nil(t, err)
// 组合数据data = (e,p)=e||px||py并发送给协同服务端
data := make([]byte, sm3.Size+2*sm2.ByteSize())
pos := copy(data, e)
pos += copy(data[pos:], gmath.BigIntToNByte(p.X, sm2.ByteSize()))
copy(data[pos:], gmath.BigIntToNByte(p.Y, sm2.ByteSize()))
// 4) hfserver -> client
data, err = sm2m.ServerSign(serverKey, data, rnd)
assert.Nil(t, err)
// 5) clinet -> os
// 解析数据
r := new(big.Int).SetBytes(data[:sm2.ByteSize()])
s1 := new(big.Int).SetBytes(data[sm2.ByteSize() : 2*sm2.ByteSize()])
s2 := new(big.Int).SetBytes(data[2*sm2.ByteSize():])
s1p, s2p, err := clientCtx.Step2(r, s1, s2)
assert.Nil(t, err)
// 6) 外包服务器解析data并计算c,把c发送给客户端
w, err := osServerCtx.Step2(s1p, s2p, encryptedClientKey1, paiPubKey)
assert.Nil(t, err)
// 7) 客户端计算签名值
sig, err := clientCtx.Step3(w)
assert.Nil(t, err)
// 8) 客户端验证签名
assert.True(t, sm2.Verify(e, publicKey, sig))
}
// 外包计算完整流程示例
// deprecated: 签名的客户端第3和第5步有遗失. 签名见上面的流程TestOSSign. 相当于客户端选择了随机数k1” = 1.
func TestOutsourceWithPaillier(t *testing.T) {
//O、客户端生成paillier密钥
var err error
paiPrivKey, paiPubKey, encryptedClientKey1, encryptedClientKey2, serverKey, publicKey := osGenerateKey(t)
// 外包服务收到客户端发来的同态公钥
paiPubKeyClientData, _ := paiPubKey.Marshal()
paiPubKey = new(paillier.PublicKey)
err = paiPubKey.Unmarshal(paiPubKeyClientData)
// 外包服务将公钥数据paiPubKeyServerData存储数据库中, 包括预计算数据.
paiPubKeyServerData, _ := paiPubKey.MarshalExt()
// 外包服务从数据库中恢复用户的同态公钥, 用于外包同态计算.
_ = paiPubKey.UnmarshalExt(paiPubKeyServerData)
rnd := grand.Reader
_, _ = encryptedClientKey1, rnd
/*
// 二、签名
// 1)客户端发起请求
e := make([]byte, 32)
rnd.Read(e)
// 2)外包方计算
outsourcintCtx := new(OSSignContext)
PPrime, err := outsourcintCtx.Step1(rnd) // P'
assert.Nil(t, err)
// outsourcintCtx把PPrime发给客户端,保存outsourcintCtx.Marshal()
// 3) 客户端组合数据data = (e,p)=e||px||py并发送给协同服务端
data := make([]byte, sm3.Size+2*sm2.ByteSize())
pos := copy(data, e)
pos += copy(data[pos:], gmath.BigIntToNByte(PPrime.X, sm2.ByteSize()))
copy(data[pos:], gmath.BigIntToNByte(PPrime.Y, sm2.ByteSize()))
// 4) 协同服务端计算,发回data
data, err = sm2m.ServerSign(serverKey, data, rnd)
assert.Nil(t, err)
// 5) 客户端解析data = r || s1 || s2, 把s1, s2发给外包服务器。
r := new(big.Int)
r.SetBytes(data[:sm2.ByteSize()])
s1 := new(big.Int).SetBytes(data[sm2.ByteSize() : 2*sm2.ByteSize()])
s2 := new(big.Int).SetBytes(data[2*sm2.ByteSize():])
// 6) 外包服务器解析data并计算c,把c发送给客户端
c, err := outsourcintCtx.Step2(s1, s2, encryptedClientKey1, paiPubKey)
assert.Nil(t, err)
// 7) 客户端计算签名值
s, _ := paillier.Decrypt(c, paiPrivKey)
s.Sub(s, r)
s.Mod(s, sm2.OrderN())
sig := &sm2.Signature{
R: r,
S: s,
}
// 8) 客户端验证签名
assert.True(t, sm2.Verify(e, publicKey, sig))
*/
// 三、使用签名密钥解密
plaintext := grand.GetRandom(16)
cipher, err := sm2.Encrypt(publicKey, plaintext, grand.GetRandom(32))
assert.Nil(t, err)
// 1) 客户端把(x,y)=C1 发送给外包服务器
// 2)外包服务计算, 把paiCipher, xF, yF发送给客户端
paiCipher, xF, yF, err := OSDecrypt(encryptedClientKey2, paiPubKey, cipher.X, cipher.Y, grand.Reader)
assert.Nil(t, err)
// 3) 客户端计算
clientDecCtx := &ClientDecContext{}
xH, yH, err := clientDecCtx.Step1(paiCipher, xF, yF, paiPrivKey)
assert.Nil(t, err)
// 4) 协同签名服务器计算
inData := make([]byte, 2*sm2.ByteSize())
xH.FillBytes(inData[:sm2.ByteSize()])
yH.FillBytes(inData[sm2.ByteSize():])
outData, err := sm2m.ServerDec(serverKey, inData)
// 5) 客户端计算
x := new(big.Int).SetBytes(outData[:sm2.ByteSize()])
y := new(big.Int).SetBytes(outData[sm2.ByteSize():])
decPlain, err := clientDecCtx.Step2(cipher, x, y)
assert.Nil(t, err)
assert.True(t, bytes.Equal(plaintext, decPlain))
// 四、解密密钥分拆
// 假设客户端解密得到的解密密钥de
de, err := sm2.GenerateKey(sm2.Curve(), grand.Reader)
assert.Nil(t, err)
// 客户端分拆解密密钥, deServer给协同签名服务端
deClient, deServer, err := sm2m.SplitDecryptKey(de, grand.Reader)
assert.Nil(t, err)
// 加密deClient给外包服务端保存。
encryptedEncKey, err := EncryptClientDecKey(deClient, paiPubKey, grand.Reader)
assert.Nil(t, err)
// 五、使用解密密钥解密(同使用签名密钥解密)
plaintext = grand.GetRandom(16)
cipher, err = sm2.Encrypt(&de.PublicKey, plaintext, grand.GetRandom(32))
assert.Nil(t, err)
// (一)对比非OS的协同解密
clientCTX := sm2m.NewClientDecContext()
out, _ := clientCTX.Initial(cipher)
out, _ = sm2m.ServerDec(deServer, out)
decPlain, _ = clientCTX.Final(deClient, out)
assert.True(t, bytes.Equal(plaintext, decPlain))
// (二)OS解密
// 1) 客户端把(x,y)=C1 发送给外包服务器
// 2)外包服务计算, 把paiCipher, xF, yF发送给客户端
paiCipher, xF, yF, err = OSDecrypt(encryptedEncKey, paiPubKey, cipher.X, cipher.Y, grand.Reader)
assert.Nil(t, err)
// 3) 客户端计算
clientDecCtx = &ClientDecContext{}
xH, yH, err = clientDecCtx.Step1(paiCipher, xF, yF, paiPrivKey)
assert.Nil(t, err)
// 4) 协同签名服务器计算
inData = make([]byte, 2*sm2.ByteSize())
xH.FillBytes(inData[:sm2.ByteSize()])
yH.FillBytes(inData[sm2.ByteSize():])
outData, err = sm2m.ServerDec(deServer, inData)
// 5) 客户端计算
x = new(big.Int).SetBytes(outData[:sm2.ByteSize()])
y = new(big.Int).SetBytes(outData[sm2.ByteSize():])
decPlain, err = clientDecCtx.Step2(cipher, x, y)
assert.Nil(t, err)
assert.True(t, bytes.Equal(plaintext, decPlain))
}