@@ -70,10 +70,13 @@ void TestBIP324PacketVector(
70
70
BOOST_CHECK (Span{mid_send_garbage} == cipher.GetSendGarbageTerminator ());
71
71
BOOST_CHECK (Span{mid_recv_garbage} == cipher.GetReceiveGarbageTerminator ());
72
72
73
+ // Vector of encrypted empty messages, encrypted in order to seek to the right position.
74
+ std::vector<std::vector<std::byte>> dummies (in_idx);
75
+
73
76
// Seek to the numbered packet.
74
77
for (uint32_t i = 0 ; i < in_idx; ++i) {
75
- std::vector<std::byte> dummy (cipher.EXPANSION );
76
- cipher.Encrypt ({}, {}, false , dummy );
78
+ dummies[i]. resize (cipher.EXPANSION );
79
+ cipher.Encrypt ({}, {}, true , dummies[i] );
77
80
}
78
81
79
82
// Construct contents and encrypt it.
@@ -93,9 +96,68 @@ void TestBIP324PacketVector(
93
96
BOOST_CHECK (Span{out_ciphertext_endswith} == Span{ciphertext}.last (out_ciphertext_endswith.size ()));
94
97
}
95
98
96
- // Note that we don't test decryption here, as the test vectors don't provide the other party's
97
- // private key, so we cannot act like them. See the bip324_cipher_roundtrip fuzz test for a test
98
- // that does cover decryption.
99
+ for (unsigned error = 0 ; error <= 12 ; ++error) {
100
+ // error selects a type of error introduced:
101
+ // - error=0: no errors, decryption should be successful
102
+ // - error=1: wrong side
103
+ // - error=2..9: bit error in ciphertext
104
+ // - error=10: bit error in aad
105
+ // - error=11: extra 0x00 at end of aad
106
+ // - error=12: message index wrong
107
+
108
+ // Instantiate self-decrypting BIP324 cipher.
109
+ BIP324Cipher dec_cipher (key, ellswift_ours);
110
+ BOOST_CHECK (!dec_cipher);
111
+ BOOST_CHECK (dec_cipher.GetOurPubKey () == ellswift_ours);
112
+ dec_cipher.Initialize (ellswift_theirs, (error == 1 ) ^ in_initiating, /* self_decrypt=*/ true );
113
+ BOOST_CHECK (dec_cipher);
114
+
115
+ // Compare session variables.
116
+ BOOST_CHECK ((Span{out_session_id} == dec_cipher.GetSessionID ()) == (error != 1 ));
117
+ BOOST_CHECK ((Span{mid_send_garbage} == dec_cipher.GetSendGarbageTerminator ()) == (error != 1 ));
118
+ BOOST_CHECK ((Span{mid_recv_garbage} == dec_cipher.GetReceiveGarbageTerminator ()) == (error != 1 ));
119
+
120
+ // Seek to the numbered packet.
121
+ if (in_idx == 0 && error == 12 ) continue ;
122
+ uint32_t dec_idx = in_idx ^ (error == 12 ? (1U << InsecureRandRange (16 )) : 0 );
123
+ for (uint32_t i = 0 ; i < dec_idx; ++i) {
124
+ unsigned use_idx = i < in_idx ? i : 0 ;
125
+ bool dec_ignore{false };
126
+ dec_cipher.DecryptLength (Span{dummies[use_idx]}.first (cipher.LENGTH_LEN ));
127
+ dec_cipher.Decrypt (Span{dummies[use_idx]}.subspan (cipher.LENGTH_LEN ), {}, dec_ignore, {});
128
+ }
129
+
130
+ // Construct copied (and possibly damaged) copy of ciphertext.
131
+ // Decrypt length
132
+ auto to_decrypt = ciphertext;
133
+ if (error >= 2 && error <= 9 ) {
134
+ to_decrypt[InsecureRandRange (to_decrypt.size ())] ^= std::byte (1U << InsecureRandRange (8 ));
135
+ }
136
+
137
+ // Decrypt length and resize ciphertext to accomodate.
138
+ uint32_t dec_len = dec_cipher.DecryptLength (MakeByteSpan (to_decrypt).first (cipher.LENGTH_LEN ));
139
+ to_decrypt.resize (dec_len + cipher.EXPANSION );
140
+
141
+ // Construct copied (and possibly damaged) copy of aad.
142
+ auto dec_aad = in_aad;
143
+ if (error == 10 ) {
144
+ if (in_aad.size () == 0 ) continue ;
145
+ dec_aad[InsecureRandRange (dec_aad.size ())] ^= std::byte (1U << InsecureRandRange (8 ));
146
+ }
147
+ if (error == 11 ) dec_aad.push_back ({});
148
+
149
+ // Decrypt contents.
150
+ std::vector<std::byte> decrypted (dec_len);
151
+ bool dec_ignore{false };
152
+ bool dec_ok = dec_cipher.Decrypt (Span{to_decrypt}.subspan (cipher.LENGTH_LEN ), dec_aad, dec_ignore, decrypted);
153
+
154
+ // Verify result.
155
+ BOOST_CHECK (dec_ok == !error);
156
+ if (dec_ok) {
157
+ BOOST_CHECK (decrypted == contents);
158
+ BOOST_CHECK (dec_ignore == in_ignore);
159
+ }
160
+ }
99
161
}
100
162
101
163
} // namespace
0 commit comments