//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 }