Skip to content

Commit 4bb5601

Browse files
committed
Serializing ciphertext with 32-bit prefixes.
Notice about ciphertext change and testing format. Previously, tkn20 ciphertext was encoding the ciphertext header `C1`, the envelope `env` (containing inner ciphertext), and macData using 16-bit prefixes, which caused a limitation on the maximum size allowed for encrypting plaintexts. With this change, the encoding now uses 32-bit prefixes for these three elements allowing to encrypt plaintexts longer than 2^16 bytes. So, ciphertexts produced by tkn20 package are now 12 bytes longer. Ciphertexts in the previous format are still decryptable. The following functions are backwards-compatible: - AttributeKey.Decrypt - Attributes.CouldDecrypt - Policy.ExtractFromCiphertext
1 parent a4252c7 commit 4bb5601

File tree

7 files changed

+83
-18
lines changed

7 files changed

+83
-18
lines changed

abe/cpabe/tkn20/example_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,6 @@ func Example() {
132132
// Output:
133133
// (occupation:doctor and country:US)
134134
// plaintext size: 27 bytes
135-
// ciphertext size: 2735 bytes
135+
// ciphertext size: 2747 bytes
136136
// Successfully recovered plaintext
137137
}

abe/cpabe/tkn20/format_test.go

+16-1
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,23 @@ func TestAttributeKeyFormat(t *testing.T) {
4141
}
4242
}
4343

44+
func TestCiphertext_v137(t *testing.T) {
45+
// As of v1.3.8 ciphertext format changed to use wider prefixes.
46+
// Ciphertexts in the previous format are still decryptable.
47+
// The following functions are backwards-compatible:
48+
// - AttributeKey.Decrypt
49+
// - Attributes.CouldDecrypt
50+
// - Policy.ExtractFromCiphertext
51+
testCiphertext(t, "testdata/ciphertext_v137")
52+
}
53+
4454
func TestCiphertext(t *testing.T) {
45-
ciphertext, err := os.ReadFile("testdata/ciphertext")
55+
testCiphertext(t, "testdata/ciphertext")
56+
}
57+
58+
func testCiphertext(t *testing.T, ctName string) {
59+
t.Logf("Checking ciphertext: %v\n", ctName)
60+
ciphertext, err := os.ReadFile(ctName)
4661
if err != nil {
4762
t.Fatalf("Unable to read ciphertext data")
4863
}

abe/cpabe/tkn20/internal/tkn/bk.go

+32-14
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package tkn
22

33
import (
4+
"bytes"
45
"crypto/subtle"
56
"fmt"
67
"io"
@@ -20,6 +21,9 @@ import (
2021
// for our output size of 256 bits.
2122
const macKeySeedSize = 72
2223

24+
// As of v1.3.8, ciphertexts are prefixed with this string.
25+
const CiphertextVersion = "v1.3.8"
26+
2327
func blakeEncrypt(key []byte, msg []byte) ([]byte, error) {
2428
xof, err := blake2b.NewXOF(blake2b.OutputLengthUnknown, key)
2529
if err != nil {
@@ -117,39 +121,51 @@ func EncryptCCA(rand io.Reader, public *PublicParams, policy *Policy, msg []byte
117121
if err != nil {
118122
return nil, err
119123
}
120-
macData := appendLenPrefixed(nil, C1)
121-
macData = appendLenPrefixed(macData, env)
124+
macData := appendLen32Prefixed(nil, C1)
125+
macData = appendLen32Prefixed(macData, env)
122126

123127
tag, err := blakeMac(macKey, macData)
124128
if err != nil {
125129
return nil, err
126130
}
127131

128-
ret := appendLenPrefixed(nil, id)
129-
ret = appendLenPrefixed(ret, macData)
132+
ret := append([]byte{}, []byte(CiphertextVersion)...)
133+
ret = appendLenPrefixed(ret, id)
134+
ret = appendLen32Prefixed(ret, macData)
130135
ret = appendLenPrefixed(ret, tag)
131136

132137
return ret, nil
133138
}
134139

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+
135150
func DecryptCCA(ciphertext []byte, key *AttributesKey) ([]byte, error) {
136-
id, rest, err := removeLenPrefixed(ciphertext)
151+
rest, removeLenPrefixedVar := checkCiphertextFormat(ciphertext)
152+
id, rest, err := removeLenPrefixed(rest)
137153
if err != nil {
138154
return nil, err
139155
}
140-
macData, rest, err := removeLenPrefixed(rest)
156+
macData, rest, err := removeLenPrefixedVar(rest)
141157
if err != nil {
142158
return nil, err
143159
}
144160
tag, _, err := removeLenPrefixed(rest)
145161
if err != nil {
146162
return nil, err
147163
}
148-
C1, envRaw, err := removeLenPrefixed(macData)
164+
C1, envRaw, err := removeLenPrefixedVar(macData)
149165
if err != nil {
150166
return nil, err
151167
}
152-
env, _, err := removeLenPrefixed(envRaw)
168+
env, _, err := removeLenPrefixedVar(envRaw)
153169
if err != nil {
154170
return nil, err
155171
}
@@ -208,15 +224,16 @@ func DecryptCCA(ciphertext []byte, key *AttributesKey) ([]byte, error) {
208224
}
209225

210226
func CouldDecrypt(ciphertext []byte, a *Attributes) bool {
211-
id, rest, err := removeLenPrefixed(ciphertext)
227+
rest, removeLenPrefixedVar := checkCiphertextFormat(ciphertext)
228+
id, rest, err := removeLenPrefixed(rest)
212229
if err != nil {
213230
return false
214231
}
215-
macData, _, err := removeLenPrefixed(rest)
232+
macData, _, err := removeLenPrefixedVar(rest)
216233
if err != nil {
217234
return false
218235
}
219-
C1, _, err := removeLenPrefixed(macData)
236+
C1, _, err := removeLenPrefixedVar(macData)
220237
if err != nil {
221238
return false
222239
}
@@ -237,15 +254,16 @@ func CouldDecrypt(ciphertext []byte, a *Attributes) bool {
237254
}
238255

239256
func (p *Policy) ExtractFromCiphertext(ct []byte) error {
240-
_, rest, err := removeLenPrefixed(ct)
257+
rest, removeLenPrefixedVar := checkCiphertextFormat(ct)
258+
_, rest, err := removeLenPrefixed(rest)
241259
if err != nil {
242260
return fmt.Errorf("invalid ciphertext")
243261
}
244-
macData, _, err := removeLenPrefixed(rest)
262+
macData, _, err := removeLenPrefixedVar(rest)
245263
if err != nil {
246264
return fmt.Errorf("invalid ciphertext")
247265
}
248-
C1, _, err := removeLenPrefixed(macData)
266+
C1, _, err := removeLenPrefixedVar(macData)
249267
if err != nil {
250268
return fmt.Errorf("invalid ciphertext")
251269
}

abe/cpabe/tkn20/internal/tkn/util.go

+25-2
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,14 @@ func HashStringToScalar(key []byte, value string) *pairing.Scalar {
4242
return s
4343
}
4444

45-
func appendLenPrefixed(a []byte, b []byte) []byte {
45+
func appendLen16Prefixed(a []byte, b []byte) []byte {
4646
a = append(a, 0, 0)
4747
binary.LittleEndian.PutUint16(a[len(a)-2:], uint16(len(b)))
4848
a = append(a, b...)
4949
return a
5050
}
5151

52-
func removeLenPrefixed(data []byte) (next []byte, remainder []byte, err error) {
52+
func removeLen16Prefixed(data []byte) (next []byte, remainder []byte, err error) {
5353
if len(data) < 2 {
5454
return nil, nil, fmt.Errorf("data too short")
5555
}
@@ -60,6 +60,29 @@ func removeLenPrefixed(data []byte) (next []byte, remainder []byte, err error) {
6060
return data[2 : 2+itemLen], data[2+itemLen:], nil
6161
}
6262

63+
var (
64+
appendLenPrefixed = appendLen16Prefixed
65+
removeLenPrefixed = removeLen16Prefixed
66+
)
67+
68+
func appendLen32Prefixed(a []byte, b []byte) []byte {
69+
a = append(a, 0, 0, 0, 0)
70+
binary.LittleEndian.PutUint32(a[len(a)-4:], uint32(len(b)))
71+
a = append(a, b...)
72+
return a
73+
}
74+
75+
func removeLen32Prefixed(data []byte) (next []byte, remainder []byte, err error) {
76+
if len(data) < 4 {
77+
return nil, nil, fmt.Errorf("data too short")
78+
}
79+
itemLen := int(binary.LittleEndian.Uint32(data))
80+
if (4 + itemLen) > len(data) {
81+
return nil, nil, fmt.Errorf("data too short")
82+
}
83+
return data[4 : 4+itemLen], data[4+itemLen:], nil
84+
}
85+
6386
func marshalBinarySortedMapMatrixG1(m map[string]*matrixG1) ([]byte, error) {
6487
sortedKeys := make([]string, 0, len(m))
6588
for key := range m {

abe/cpabe/tkn20/testdata/ciphertext

12 Bytes
Binary file not shown.
2.32 KB
Binary file not shown.

abe/cpabe/tkn20/tkn20.go

+9
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,15 @@
88
// attribute-based encryption. In A. Kiayias, M. Kohlweiss, P. Wallden, and
99
// V. Zikas, editors, PKC, volume 12110 of Lecture Notes in Computer Science,
1010
// pages 3–33. Springer, 2020. https://eprint.iacr.org/2019/966
11+
//
12+
// # Update v1.3.8
13+
//
14+
// As of v1.3.8, ciphertext format changed to use wider prefixes.
15+
// Ciphertexts in the previous format are still decryptable.
16+
// The following functions are backwards-compatible:
17+
// - [AttributeKey.Decrypt]
18+
// - [Attributes.CouldDecrypt]
19+
// - [Policy.ExtractFromCiphertext]
1120
package tkn20
1221

1322
import (

0 commit comments

Comments
 (0)