9
9
package engineccl
10
10
11
11
import (
12
+ "bytes"
12
13
"context"
13
14
"crypto/rand"
14
15
"encoding/binary"
16
+ "encoding/hex"
15
17
"fmt"
16
18
"strings"
17
19
"testing"
18
20
19
21
"github.com/cockroachdb/cockroach/pkg/ccl/securityccl/fipsccl"
20
22
"github.com/cockroachdb/cockroach/pkg/ccl/storageccl/engineccl/enginepbccl"
21
23
"github.com/cockroachdb/cockroach/pkg/storage/enginepb"
24
+ "github.com/cockroachdb/cockroach/pkg/testutils/datapathutils"
22
25
"github.com/cockroachdb/cockroach/pkg/util/leaktest"
26
+ "github.com/cockroachdb/datadriven"
23
27
"github.com/kr/pretty"
24
28
"github.com/stretchr/testify/require"
25
29
)
@@ -46,6 +50,143 @@ func generateKey(encType enginepbccl.EncryptionType) (*enginepbccl.SecretKey, er
46
50
return key , err
47
51
}
48
52
53
+ func readHex (s string ) ([]byte , error ) {
54
+ s = strings .ReplaceAll (s , " " , "" )
55
+ s = strings .ReplaceAll (s , "\n " , "" )
56
+ return hex .DecodeString (s )
57
+ }
58
+
59
+ func writeHex (b []byte ) string {
60
+ var buf strings.Builder
61
+ for i , c := range b {
62
+ fmt .Fprintf (& buf , "%02x" , c )
63
+ if i % 16 == 15 {
64
+ buf .WriteString ("\n " )
65
+ } else {
66
+ buf .WriteString (" " )
67
+ }
68
+ }
69
+ return buf .String ()
70
+ }
71
+
72
+ func encryptManySubBlocks (
73
+ t * testing.T , fcs * fileCipherStream , baseOffset int64 , plaintext , ciphertext []byte ,
74
+ ) {
75
+ // Split the text into many different left/right pairs, encrypt each one
76
+ // separately, and make sure it matches the corresponding ciphertext.
77
+ // This covers various cases such as full and partial blocks, aligned and
78
+ // unaligned, etc.
79
+ // Since we're only dealing with fairly small data sizes, we can iterate
80
+ // through every possible split point and just try them all.
81
+ for i := range plaintext {
82
+ leftData := append ([]byte {}, plaintext [0 :i ]... )
83
+ fcs .Encrypt (baseOffset , leftData )
84
+ if ! bytes .Equal (leftData , ciphertext [0 :i ]) {
85
+ t .Errorf ("encrypting bytes 0:%d did not match full ciphertext" , i )
86
+ }
87
+ rightData := append ([]byte {}, plaintext [i :]... )
88
+ fcs .Encrypt (baseOffset + int64 (i ), rightData )
89
+ if ! bytes .Equal (rightData , ciphertext [i :]) {
90
+ t .Errorf ("encrypting bytes %d:end did not match full ciphertext" , i )
91
+ }
92
+ }
93
+ }
94
+
95
+ // Running non-fips mode:
96
+ // ./dev test pkg/ccl/storageccl/engineccl -f CTRStreamDataDriven --rewrite --stream-output
97
+ // Running fips mode:
98
+ // ./dev test-binaries --cross=crosslinuxfips pkg/ccl/storageccl/engineccl && mkdir -p fipsbin && tar xf bin/test_binaries.tar.gz -C fipsbin && docker run -v $PWD/fipsbin:/fipsbin -it redhat/ubi9 bash -c 'cd /fipsbin/pkg/ccl/storageccl/engineccl/bin && ./run.sh -test.run CTRStreamDataDriven'
99
+ func TestCTRStreamDataDriven (t * testing.T ) {
100
+ defer leaktest .AfterTest (t )()
101
+ var data []byte
102
+ keys := map [string ]* enginepbccl.SecretKey {}
103
+ ivs := map [string ][]byte {}
104
+ seenCiphertexts := map [string ]struct {}{}
105
+ datadriven .RunTest (t , datapathutils .TestDataPath (t , "ctr_stream" ),
106
+ func (t * testing.T , d * datadriven.TestData ) string {
107
+ fmt .Println (d .Pos )
108
+
109
+ switch d .Cmd {
110
+ case "set-data" :
111
+ var err error
112
+ data , err = readHex (d .Input )
113
+ require .NoError (t , err )
114
+ return "ok"
115
+
116
+ case "create-key" :
117
+ var name string
118
+ d .ScanArgs (t , "name" , & name )
119
+ decoded , err := readHex (d .Input )
120
+ require .NoError (t , err )
121
+ key := & enginepbccl.SecretKey {
122
+ Info : & enginepbccl.KeyInfo {},
123
+ Key : decoded ,
124
+ }
125
+ switch len (decoded ) {
126
+ case 16 :
127
+ key .Info .EncryptionType = enginepbccl .EncryptionType_AES128_CTR
128
+ case 24 :
129
+ key .Info .EncryptionType = enginepbccl .EncryptionType_AES192_CTR
130
+ case 32 :
131
+ key .Info .EncryptionType = enginepbccl .EncryptionType_AES256_CTR
132
+ default :
133
+ return fmt .Sprintf ("invalid key size %d" , len (decoded ))
134
+ }
135
+ keys [name ] = key
136
+ return "ok"
137
+
138
+ case "create-iv" :
139
+ var name string
140
+ d .ScanArgs (t , "name" , & name )
141
+ decoded , err := readHex (d .Input )
142
+ require .NoError (t , err )
143
+ if len (decoded ) != 16 {
144
+ return "iv must be 16 bytes"
145
+ }
146
+ ivs [name ] = decoded
147
+ return "ok"
148
+
149
+ case "encrypt" :
150
+ var offset int64
151
+ d .ScanArgs (t , "offset" , & offset )
152
+ keyName := "default"
153
+ d .MaybeScanArgs (t , "key" , & keyName )
154
+ ivName := "default"
155
+ d .MaybeScanArgs (t , "iv" , & ivName )
156
+ expectDuplicate := false
157
+ d .MaybeScanArgs (t , "expect_duplicate" , & expectDuplicate )
158
+ iv := ivs [ivName ]
159
+ bcs , err := newCTRBlockCipherStream (keys [keyName ], iv [:12 ], binary .BigEndian .Uint32 (iv [12 :16 ]))
160
+ require .NoError (t , err )
161
+ fcs := & fileCipherStream {bcs : bcs }
162
+ // Encrypt() mutates its argument so make a copy of data.
163
+ output := append ([]byte {}, data ... )
164
+ fcs .Encrypt (offset , output )
165
+ reencrypted := append ([]byte {}, output ... )
166
+ fcs .Decrypt (offset , reencrypted )
167
+ if ! bytes .Equal (data , reencrypted ) {
168
+ t .Fatalf ("decrypted data didn't match input" )
169
+ }
170
+
171
+ outputString := string (output )
172
+ _ , isDuplicate := seenCiphertexts [outputString ]
173
+ if isDuplicate && ! expectDuplicate {
174
+ // Assume that each test is using different parameters; if we see the same
175
+ // ciphertext twice something's gone wrong.
176
+ t .Fatalf ("same ciphertext produced more than once" )
177
+ } else if expectDuplicate && ! isDuplicate {
178
+ t .Fatalf ("expected duplicate of prior ciphertext" )
179
+ }
180
+ seenCiphertexts [outputString ] = struct {}{}
181
+ encryptManySubBlocks (t , fcs , offset , data , output )
182
+ return writeHex (output )
183
+
184
+ default :
185
+ return fmt .Sprintf ("unknown command: %s\n " , d .Cmd )
186
+ }
187
+ })
188
+ }
189
+
49
190
func TestFileCipherStream (t * testing.T ) {
50
191
defer leaktest .AfterTest (t )()
51
192
0 commit comments