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) 外包服务器第一步 // 保存encryptedClientKey1,encryptedClientKey2, // 把 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 // 2)os -> 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)) }