github.com/cloudflare/circl@v1.5.0/abe/cpabe/tkn20/internal/tkn/bk.go (about)

     1  package tkn
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/subtle"
     6  	"fmt"
     7  	"io"
     8  
     9  	pairing "github.com/cloudflare/circl/ecc/bls12381"
    10  	"golang.org/x/crypto/blake2b"
    11  )
    12  
    13  // This file is based on the techniques in
    14  // https://www.iacr.org/archive/pkc2011/65710074/65710074.pdf that
    15  // apply the Boneh-Katz transform to Attribute based encryption.
    16  
    17  // Seed size is chosen based on the proof for BK transform
    18  // (https://eprint.iacr.org/2004/261.pdf - page 12, theorem 2) to maintain the
    19  // statistical hiding property. Their input is 448 bits -> 128 bits,
    20  // whereas we require a seed size of 576 bits to ensure a 2^(-65) statistical difference
    21  // for our output size of 256 bits.
    22  const macKeySeedSize = 72
    23  
    24  // As of v1.3.8, ciphertexts are prefixed with this string.
    25  const CiphertextVersion = "v1.3.8"
    26  
    27  func blakeEncrypt(key []byte, msg []byte) ([]byte, error) {
    28  	xof, err := blake2b.NewXOF(blake2b.OutputLengthUnknown, key)
    29  	if err != nil {
    30  		return nil, err
    31  	}
    32  	keystream := make([]byte, len(msg))
    33  	_, err = io.ReadFull(xof, keystream)
    34  	if err != nil {
    35  		return nil, err
    36  	}
    37  
    38  	for i := 0; i < len(msg); i++ {
    39  		keystream[i] ^= msg[i]
    40  	}
    41  	return keystream, nil
    42  }
    43  
    44  func blakeDecrypt(key []byte, msg []byte) ([]byte, error) {
    45  	return blakeEncrypt(key, msg)
    46  }
    47  
    48  func blakeMac(key []byte, msg []byte) (tag []byte, err error) {
    49  	mac, err := blake2b.New256(key)
    50  	if err != nil {
    51  		return nil, err
    52  	}
    53  	mac.Write(msg)
    54  	tag = mac.Sum(nil)
    55  	return
    56  }
    57  
    58  func expandSeed(seed []byte) (id []byte, macKey []byte, err error) {
    59  	h1, err := blake2b.New256(nil)
    60  	if err != nil {
    61  		return nil, nil, err
    62  	}
    63  	h1.Write([]byte("id computation hash"))
    64  
    65  	h2, err := blake2b.New256(nil)
    66  	if err != nil {
    67  		return nil, nil, err
    68  	}
    69  	h2.Write([]byte("key computation hash"))
    70  
    71  	h1.Write(seed)
    72  	h2.Write(seed)
    73  	id = h1.Sum(nil)
    74  	macKey = h2.Sum(nil)
    75  	return
    76  }
    77  
    78  func DeriveAttributeKeysCCA(rand io.Reader, sp *SecretParams, attrs *Attributes) (*AttributesKey, error) {
    79  	realAttrs := transformAttrsBK(attrs)
    80  	return deriveAttributeKeys(rand, sp, realAttrs)
    81  }
    82  
    83  func EncryptCCA(rand io.Reader, public *PublicParams, policy *Policy, msg []byte) ([]byte, error) {
    84  	seed := make([]byte, macKeySeedSize)
    85  	_, err := io.ReadFull(rand, seed)
    86  	if err != nil {
    87  		return nil, err
    88  	}
    89  	id, macKey, err := expandSeed(seed)
    90  	if err != nil {
    91  		return nil, err
    92  	}
    93  
    94  	numid := &pairing.Scalar{}
    95  	numid.SetBytes(id)
    96  
    97  	encPolicy := policy.transformBK(numid)
    98  
    99  	header, encPoint, err := encapsulate(rand, public, encPolicy)
   100  	if err != nil {
   101  		return nil, err
   102  	}
   103  	// Send the policy that was not enhanced. The receiver will recover with the ID.
   104  	// This avoids a bug where we omit the check that the ID is correct
   105  	header.p = policy
   106  	C1, err := header.marshalBinary()
   107  	if err != nil {
   108  		return nil, err
   109  	}
   110  	env := make([]byte, len(seed)+len(msg))
   111  	copy(env[0:len(seed)], seed)
   112  	copy(env[len(seed):], msg)
   113  
   114  	encKey, err := encPoint.MarshalBinary()
   115  	if err != nil {
   116  		return nil, err
   117  	}
   118  	hashedEncKey := blake2b.Sum256(encKey)
   119  
   120  	env, err = blakeEncrypt(hashedEncKey[:], env)
   121  	if err != nil {
   122  		return nil, err
   123  	}
   124  	macData := appendLen32Prefixed(nil, C1)
   125  	macData = appendLen32Prefixed(macData, env)
   126  
   127  	tag, err := blakeMac(macKey, macData)
   128  	if err != nil {
   129  		return nil, err
   130  	}
   131  
   132  	ret := append([]byte{}, []byte(CiphertextVersion)...)
   133  	ret = appendLenPrefixed(ret, id)
   134  	ret = appendLen32Prefixed(ret, macData)
   135  	ret = appendLenPrefixed(ret, tag)
   136  
   137  	return ret, nil
   138  }
   139  
   140  type rmLenPref = func([]byte) ([]byte, []byte, error)
   141  
   142  func checkCiphertextFormat(ciphertext []byte) (ct []byte, fn rmLenPref) {
   143  	const N = len(CiphertextVersion)
   144  	if bytes.Equal(ciphertext[0:N], []byte(CiphertextVersion)) {
   145  		return ciphertext[N:], removeLen32Prefixed
   146  	}
   147  	return ciphertext, removeLenPrefixed
   148  }
   149  
   150  func DecryptCCA(ciphertext []byte, key *AttributesKey) ([]byte, error) {
   151  	rest, removeLenPrefixedVar := checkCiphertextFormat(ciphertext)
   152  	id, rest, err := removeLenPrefixed(rest)
   153  	if err != nil {
   154  		return nil, err
   155  	}
   156  	macData, rest, err := removeLenPrefixedVar(rest)
   157  	if err != nil {
   158  		return nil, err
   159  	}
   160  	tag, _, err := removeLenPrefixed(rest)
   161  	if err != nil {
   162  		return nil, err
   163  	}
   164  	C1, envRaw, err := removeLenPrefixedVar(macData)
   165  	if err != nil {
   166  		return nil, err
   167  	}
   168  	env, _, err := removeLenPrefixedVar(envRaw)
   169  	if err != nil {
   170  		return nil, err
   171  	}
   172  
   173  	header := &ciphertextHeader{}
   174  	err = header.unmarshalBinary(C1)
   175  	if err != nil {
   176  		return nil, err
   177  	}
   178  
   179  	numid := &pairing.Scalar{}
   180  	numid.SetBytes(id)
   181  
   182  	header.p = header.p.transformBK(numid)
   183  
   184  	encPoint, err := decapsulate(header, key)
   185  	if err != nil {
   186  		return nil, fmt.Errorf("error in decryption: %w", err)
   187  	}
   188  	encKey, err := encPoint.MarshalBinary()
   189  	if err != nil {
   190  		return nil, err
   191  	}
   192  	hashedEncKey := blake2b.Sum256(encKey)
   193  
   194  	// Decrypt the envelope
   195  	decEnv, err := blakeDecrypt(hashedEncKey[:], env)
   196  	if err != nil {
   197  		return nil, err
   198  	}
   199  	if len(decEnv) < macKeySeedSize {
   200  		return nil, fmt.Errorf("envelope too short")
   201  	}
   202  
   203  	seed := decEnv[0:macKeySeedSize]
   204  	ptx := make([]byte, len(decEnv)-macKeySeedSize)
   205  	compID, macKey, err := expandSeed(seed)
   206  	if err != nil {
   207  		return nil, err
   208  	}
   209  	compTag, err := blakeMac(macKey, macData)
   210  	if err != nil {
   211  		return nil, err
   212  	}
   213  
   214  	// Now check that compTag = tag and compID = id
   215  	// We don't want to distinguish which fails.
   216  	tagMatch := subtle.ConstantTimeCompare(compTag, tag)
   217  	idMatch := subtle.ConstantTimeCompare(compID, id)
   218  	check := tagMatch & idMatch
   219  	if check == 1 {
   220  		copy(ptx, decEnv[macKeySeedSize:])
   221  		return ptx, nil
   222  	}
   223  	return nil, fmt.Errorf("failure of decryption")
   224  }
   225  
   226  func CouldDecrypt(ciphertext []byte, a *Attributes) bool {
   227  	rest, removeLenPrefixedVar := checkCiphertextFormat(ciphertext)
   228  	id, rest, err := removeLenPrefixed(rest)
   229  	if err != nil {
   230  		return false
   231  	}
   232  	macData, _, err := removeLenPrefixedVar(rest)
   233  	if err != nil {
   234  		return false
   235  	}
   236  	C1, _, err := removeLenPrefixedVar(macData)
   237  	if err != nil {
   238  		return false
   239  	}
   240  
   241  	header := &ciphertextHeader{}
   242  	err = header.unmarshalBinary(C1)
   243  	if err != nil {
   244  		return false
   245  	}
   246  
   247  	numid := &pairing.Scalar{}
   248  	numid.SetBytes(id)
   249  
   250  	header.p = header.p.transformBK(numid)
   251  	realAttrs := transformAttrsBK(a)
   252  	_, err = header.p.Satisfaction(realAttrs)
   253  	return err == nil
   254  }
   255  
   256  func (p *Policy) ExtractFromCiphertext(ct []byte) error {
   257  	rest, removeLenPrefixedVar := checkCiphertextFormat(ct)
   258  	_, rest, err := removeLenPrefixed(rest)
   259  	if err != nil {
   260  		return fmt.Errorf("invalid ciphertext")
   261  	}
   262  	macData, _, err := removeLenPrefixedVar(rest)
   263  	if err != nil {
   264  		return fmt.Errorf("invalid ciphertext")
   265  	}
   266  	C1, _, err := removeLenPrefixedVar(macData)
   267  	if err != nil {
   268  		return fmt.Errorf("invalid ciphertext")
   269  	}
   270  
   271  	header := &ciphertextHeader{}
   272  	err = header.unmarshalBinary(C1)
   273  	if err != nil {
   274  		return fmt.Errorf("invalid ciphertext")
   275  	}
   276  	*p = *header.p
   277  	return nil
   278  }