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 }