111 lines
3.1 KiB
Go
111 lines
3.1 KiB
Go
//go:build ignore
|
|
// +build ignore
|
|
|
|
package paillier
|
|
|
|
// envelope provide hybrid encryption for a user with a remote cryptographic server.
|
|
// The server has a KEK and the user wants to encrypt a file.
|
|
// 1. The user generate a random user key ukey
|
|
// 2. The user use ukey to encrypt the file
|
|
// 3. The user do the followings to encrypt the ukey with KEK without leaking ukey to the server:
|
|
// 3-0. The user generate a (temporary or long term) paillier key pair (sk, pk).
|
|
// 3-1. The user encrypt ukey with paillier encryption: ukeyCipher = PaiEnc(ukey, pk)
|
|
// 3-2. The server HOMOMORPHICLY encrypt ukey with KEK: ukeyEnvelopeCipher = PaiEnc(SM4Enc(ukey, KEK), pk)
|
|
// 3-3. The user decrypt ukeyEnvelopeCipher and get ukeyEnvelope = SM4Enc(ukey, KEK)
|
|
//
|
|
// The user do the following to decrypt the ukey and then to decrypt the file.
|
|
// Also without leaking ukey.
|
|
// 1. The user generate a (temporary or long term) paillier key pair (sk, pk).
|
|
// 2. User encrypt ukeyEnvelope: ukeyEnvelopeCipher = PaiEnc(ukeyEnvelope, pk)
|
|
// 3. The server HOMORPHICLY decrypt ukeyEnvelopeCipher: ukeyCipher = PaiEnc(ukey, pk)
|
|
// 4. The user decrypt ukeyCipher, with ukey.
|
|
|
|
import (
|
|
"fmt"
|
|
"math/big"
|
|
|
|
"xdx.jelly/xgcl/grand"
|
|
"xdx.jelly/xgcl/sm/sm4"
|
|
)
|
|
|
|
// xyzw => 0x0y0z0w
|
|
var tbl = []byte{0, 1, 4, 5, 16, 17, 20, 21, 64, 65, 68, 69, 80, 81, 84, 85}
|
|
|
|
type EnvelopeUser struct{}
|
|
type EnvelopeServer struct{}
|
|
|
|
// EncryptUserKey
|
|
func (EnvelopeUser) EncryptUserKey(ukey []byte, pk *PublicKey) (ukeyCipher *Cipher, err error) {
|
|
if len(ukey)*8*2 > pk.Bits() {
|
|
return nil, fmt.Errorf("input key too long, should less than %d bytes", pk.Bits()/8/2)
|
|
}
|
|
buf := make([]byte, 0, len(ukey)*2)
|
|
for _, k := range ukey {
|
|
buf = append(buf, tbl[k&0xf])
|
|
buf = append(buf, tbl[k>>4])
|
|
}
|
|
return pk.Encrypt(new(big.Int).SetBytes(buf), grand.Reader)
|
|
}
|
|
|
|
func DecryptKey(c *Cipher, keyLength int, priKey *PrivateKey) ([]byte, error) {
|
|
k, err := priKey.Decrypt(c)
|
|
_ = err
|
|
key2 := make([]byte, keyLength*2)
|
|
k.FillBytes(key2)
|
|
key := make([]byte, keyLength)
|
|
for i := 0; i < len(key); i++ {
|
|
x := key2[2*i]
|
|
y := key2[2*i+1]
|
|
n := byte(0)
|
|
n |= (x >> 0) & 1
|
|
n |= (x >> 1) & 2
|
|
n |= (x >> 2) & 4
|
|
n |= (x >> 3) & 8
|
|
key[i] = n
|
|
|
|
n = byte(0)
|
|
n |= (y >> 0) & 1
|
|
n |= (y >> 1) & 2
|
|
n |= (y >> 2) & 4
|
|
n |= (y >> 3) & 8
|
|
key[i] |= (n << 4)
|
|
}
|
|
return key, nil
|
|
}
|
|
|
|
func GenEnvelope(c0 *Cipher, kek []byte, pubkey *PublicKey) ([]byte, *Cipher, error) {
|
|
iv := grand.GetRandom(16)
|
|
c1, err := sm4.EncryptECB(nil, kek, iv) // c1 = sm4.Enc(iv)
|
|
c2, err := EncryptUserKey(c1, pubkey) // c2 = PaiEnc(sm4.Enc(iv))
|
|
c2.HomomorphicAdd(c2, c0, pubkey) // c2 = PaiEnc(sm4.Enc(iv) ^ key)
|
|
|
|
_ = err
|
|
return iv, c2, nil
|
|
}
|
|
|
|
func DecryptEnvelope(c *Cipher, prikey *PrivateKey) ([]byte, error) {
|
|
k, err := prikey.Decrypt(c)
|
|
_ = err
|
|
key2 := make([]byte, 32)
|
|
k.FillBytes(key2)
|
|
key := make([]byte, 16)
|
|
for i := 0; i < 16; i++ {
|
|
x := key2[2*i]
|
|
y := key2[2*i+1]
|
|
n := byte(0)
|
|
n |= (x >> 0) & 1
|
|
n |= (x >> 1) & 2
|
|
n |= (x >> 2) & 4
|
|
n |= (x >> 3) & 8
|
|
key[i] = n
|
|
|
|
n = byte(0)
|
|
n |= (y >> 0) & 1
|
|
n |= (y >> 1) & 2
|
|
n |= (y >> 2) & 4
|
|
n |= (y >> 3) & 8
|
|
key[i] |= (n << 4)
|
|
}
|
|
return key, nil
|
|
}
|