Skip to content

Commit a9b2e83

Browse files
Rust wrapper: add one-shot XChaCha20-Poly1305 encrypt/decrypt functions
1 parent 5f68ea0 commit a9b2e83

File tree

6 files changed

+179
-4
lines changed

6 files changed

+179
-4
lines changed

.codespellexcludelines

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ rsource "Kconfig.tls-generic"
1313
const uint8_t* hashIn, int hashSz)
1414
XMEMCPY(hash + (curveSz - hashSz), hashIn, hashSz);
1515
0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69, /* creen would be i */
16+
0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69, /* creen would be i */
1617
\pagenumbering{alph}
1718
DES3_KEY_SIZE = 24, /* 3 des ede */
1819
/* functions added to support above needed, removed TOOM and KARATSUBA */

wolfssl/wolfcrypt/chacha20_poly1305.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,8 @@ WOLFSSL_API WARN_UNUSED_RESULT int wc_ChaCha20Poly1305_Final(ChaChaPoly_Aead* ae
129129
WOLFSSL_API int wc_XChaCha20Poly1305_Init(
130130
ChaChaPoly_Aead* aead,
131131
const byte *ad, word32 ad_len,
132-
const byte *inKey, word32 inKeySz,
133-
const byte *inIV, word32 inIVSz,
132+
const byte *nonce, word32 nonce_len,
133+
const byte *key, word32 key_len,
134134
int isEncrypt);
135135

136136
WOLFSSL_API int wc_XChaCha20Poly1305_Encrypt(

wrapper/rust/wolfssl-wolfcrypt/README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,21 @@ functionality:
2424

2525
* AES
2626
* CBC, CCM, CFB, CTR, EAX, ECB, GCM, OFB, XTS
27+
* BLAKE2
2728
* CMAC
29+
* ChaCha20-Poly1305
30+
* Curve25519
2831
* DH
2932
* ECC
30-
* Ed448
3133
* Ed25519
34+
* Ed448
3235
* HKDF
3336
* HMAC
3437
* PBKDF2
3538
* PKCS #12 PBKDF
3639
* PRF
37-
* RSA
3840
* RNG
41+
* RSA
3942
* SHA
4043
* SHA-1, SHA-224, SHA-256, SHA-384, SHA-512, SHA3-224, SHA3-256, SHA3-384,
4144
SHA3-512, SHAKE128, SHAKE256

wrapper/rust/wolfssl-wolfcrypt/build.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ fn scan_cfg() -> Result<()> {
132132

133133
/* chacha20_poly1305 */
134134
check_cfg(&binding, "wc_ChaCha20Poly1305_Encrypt", "chacha20_poly1305");
135+
check_cfg(&binding, "wc_XChaCha20Poly1305_Encrypt", "xchacha20_poly1305");
135136

136137
/* cmac */
137138
check_cfg(&binding, "wc_InitCmac", "cmac");

wrapper/rust/wolfssl-wolfcrypt/src/chacha20_poly1305.rs

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,11 @@ pub struct ChaCha20Poly1305 {
3333
}
3434

3535
impl ChaCha20Poly1305 {
36+
/// Key size for ChaCha20-Poly1305 stream cipher.
3637
pub const KEYSIZE: usize = sys::CHACHA20_POLY1305_AEAD_KEYSIZE as usize;
38+
/// IV size for ChaCha20-Poly1305 stream cipher.
3739
pub const IV_SIZE: usize = sys::CHACHA20_POLY1305_AEAD_IV_SIZE as usize;
40+
/// Authentication tag size for ChaCha20-Poly1305 stream cipher.
3841
pub const AUTH_TAG_SIZE: usize = sys::CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE as usize;
3942

4043
/// Decrypt an input message from `ciphertext` using the ChaCha20 stream
@@ -240,3 +243,100 @@ impl ChaCha20Poly1305 {
240243
Ok(())
241244
}
242245
}
246+
247+
#[cfg(xchacha20_poly1305)]
248+
pub struct XChaCha20Poly1305 {
249+
}
250+
251+
#[cfg(xchacha20_poly1305)]
252+
impl XChaCha20Poly1305 {
253+
/// Key size for XChaCha20-Poly1305 stream cipher.
254+
pub const KEYSIZE: usize = sys::CHACHA20_POLY1305_AEAD_KEYSIZE as usize;
255+
/// IV size for XChaCha20-Poly1305 stream cipher.
256+
pub const IV_SIZE: usize = sys::XCHACHA20_POLY1305_AEAD_NONCE_SIZE as usize;
257+
/// Authentication tag size for XChaCha20-Poly1305 stream cipher.
258+
pub const AUTH_TAG_SIZE: usize = sys::CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE as usize;
259+
260+
/// Decrypt an input message from `ciphertext` using the XChaCha20 stream
261+
/// cipher into the `plaintext` output buffer. It also performs Poly-1305
262+
/// authentication. The authentication tag is expected to be located in the
263+
/// last 16 bytes of the `ciphertext` buffer.
264+
/// If Err is returned, the output data, `plaintext` is undefined.
265+
/// However, callers must unconditionally zeroize the output buffer to
266+
/// guard against leakage of cleartext data.
267+
///
268+
/// # Parameters
269+
///
270+
/// * `key`: Encryption key (must be 32 bytes).
271+
/// * `iv`: Initialization Vector (must be 24 bytes).
272+
/// * `aad`: Additional authenticated data (can be any length).
273+
/// * `ciphertext`: Input buffer containing encrypted cipher text.
274+
/// * `plaintext`: Output buffer containing decrypted plain text.
275+
///
276+
/// # Returns
277+
///
278+
/// Returns either Ok(()) on success or Err(e) containing the wolfSSL
279+
/// library error code value.
280+
pub fn decrypt(key: &[u8], iv: &[u8], aad: &[u8], ciphertext: &[u8],
281+
plaintext: &mut [u8]) -> Result<(), i32> {
282+
if key.len() != Self::KEYSIZE {
283+
return Err(sys::wolfCrypt_ErrorCodes_BUFFER_E);
284+
}
285+
if iv.len() != Self::IV_SIZE {
286+
return Err(sys::wolfCrypt_ErrorCodes_BUFFER_E);
287+
}
288+
let rc = unsafe {
289+
sys::wc_XChaCha20Poly1305_Decrypt(
290+
plaintext.as_mut_ptr(), plaintext.len(),
291+
ciphertext.as_ptr(), ciphertext.len(),
292+
aad.as_ptr(), aad.len(),
293+
iv.as_ptr(), iv.len(),
294+
key.as_ptr(), key.len())
295+
};
296+
if rc != 0 {
297+
return Err(rc);
298+
}
299+
Ok(())
300+
}
301+
302+
/// Encrypt an input message from `plaintext` using the XChaCha20 stream
303+
/// cipher into the `ciphertext` output buffer performing Poly-1305
304+
/// authentication on the cipher text.
305+
/// The authentication tag is stored in the last 16 bytes of the
306+
/// `ciphertext` buffer, so the `ciphertext` buffer must be large enough
307+
/// for both the cipher text and authentication tag.
308+
///
309+
/// # Parameters
310+
///
311+
/// * `key`: Encryption key (must be 32 bytes).
312+
/// * `iv`: Initialization Vector (must be 24 bytes).
313+
/// * `aad`: Additional authenticated data (can be any length).
314+
/// * `plaintext`: Input plain text to encrypt.
315+
/// * `ciphertext`: Output buffer for encrypted cipher text.
316+
///
317+
/// # Returns
318+
///
319+
/// Returns either Ok(()) on success or Err(e) containing the wolfSSL
320+
/// library error code value.
321+
pub fn encrypt(key: &[u8], iv: &[u8], aad: &[u8], plaintext: &[u8],
322+
ciphertext: &mut [u8]) -> Result<(), i32> {
323+
if key.len() != Self::KEYSIZE {
324+
return Err(sys::wolfCrypt_ErrorCodes_BUFFER_E);
325+
}
326+
if iv.len() != Self::IV_SIZE {
327+
return Err(sys::wolfCrypt_ErrorCodes_BUFFER_E);
328+
}
329+
let rc = unsafe {
330+
sys::wc_XChaCha20Poly1305_Encrypt(
331+
ciphertext.as_mut_ptr(), ciphertext.len(),
332+
plaintext.as_ptr(), plaintext.len(),
333+
aad.as_ptr(), aad.len(),
334+
iv.as_ptr(), iv.len(),
335+
key.as_ptr(), key.len())
336+
};
337+
if rc != 0 {
338+
return Err(rc);
339+
}
340+
Ok(())
341+
}
342+
}

wrapper/rust/wolfssl-wolfcrypt/tests/test_chacha20_poly1305.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,3 +203,73 @@ fn test_chacha20_poly1305_2() {
203203
assert_eq!(out_plaintext2, plaintext2);
204204
assert_eq!(out_auth_tag_2, auth_tag_2);
205205
}
206+
207+
#[test]
208+
#[cfg(xchacha20_poly1305)]
209+
fn test_xchacha20_poly1305() {
210+
const PLAINTEXT: &[u8] = &[
211+
0x4cu8, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61,
212+
0x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c, /* Ladies and Gentl */
213+
0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20,
214+
0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73, /* emen of the clas */
215+
0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39,
216+
0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63, /* s of '99: If I c */
217+
0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66,
218+
0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f, /* ould offer you o */
219+
0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20,
220+
0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20, /* nly one tip for */
221+
0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x74, 0x75,
222+
0x72, 0x65, 0x2c, 0x20, 0x73, 0x75, 0x6e, 0x73, /* the future, suns */
223+
0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f,
224+
0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69, /* creen would be i */
225+
0x74, 0x2e ]; /* t. */
226+
227+
let aad = [
228+
0x50u8, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3,
229+
0xc4, 0xc5, 0xc6, 0xc7
230+
]; /* PQRS........ */
231+
232+
let key = [
233+
0x80u8, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
234+
0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
235+
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
236+
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
237+
];
238+
239+
let iv = [
240+
0x40u8, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
241+
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* @ABCDEFGHIJKLMNO */
242+
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57 /* PQRSTUVW */
243+
];
244+
245+
let expected_ciphertext = [
246+
0xbdu8, 0x6d, 0x17, 0x9d, 0x3e, 0x83, 0xd4, 0x3b,
247+
0x95, 0x76, 0x57, 0x94, 0x93, 0xc0, 0xe9, 0x39,
248+
0x57, 0x2a, 0x17, 0x00, 0x25, 0x2b, 0xfa, 0xcc,
249+
0xbe, 0xd2, 0x90, 0x2c, 0x21, 0x39, 0x6c, 0xbb,
250+
0x73, 0x1c, 0x7f, 0x1b, 0x0b, 0x4a, 0xa6, 0x44,
251+
0x0b, 0xf3, 0xa8, 0x2f, 0x4e, 0xda, 0x7e, 0x39,
252+
0xae, 0x64, 0xc6, 0x70, 0x8c, 0x54, 0xc2, 0x16,
253+
0xcb, 0x96, 0xb7, 0x2e, 0x12, 0x13, 0xb4, 0x52,
254+
0x2f, 0x8c, 0x9b, 0xa4, 0x0d, 0xb5, 0xd9, 0x45,
255+
0xb1, 0x1b, 0x69, 0xb9, 0x82, 0xc1, 0xbb, 0x9e,
256+
0x3f, 0x3f, 0xac, 0x2b, 0xc3, 0x69, 0x48, 0x8f,
257+
0x76, 0xb2, 0x38, 0x35, 0x65, 0xd3, 0xff, 0xf9,
258+
0x21, 0xf9, 0x66, 0x4c, 0x97, 0x63, 0x7d, 0xa9,
259+
0x76, 0x88, 0x12, 0xf6, 0x15, 0xc6, 0x8b, 0x13,
260+
0xb5, 0x2e
261+
];
262+
263+
let expected_tag = [
264+
0xc0u8, 0x87, 0x59, 0x24, 0xc1, 0xc7, 0x98, 0x79,
265+
0x47, 0xde, 0xaf, 0xd8, 0x78, 0x0a, 0xcf, 0x49
266+
];
267+
268+
let mut ciphertext_buffer = [0u8; PLAINTEXT.len() + XChaCha20Poly1305::AUTH_TAG_SIZE];
269+
XChaCha20Poly1305::encrypt(&key, &iv, &aad, PLAINTEXT, &mut ciphertext_buffer).expect("Error with encrypt()");
270+
assert_eq!(ciphertext_buffer[0..expected_ciphertext.len()], expected_ciphertext);
271+
assert_eq!(ciphertext_buffer[expected_ciphertext.len()..], expected_tag);
272+
let mut plaintext_buffer = [0u8; PLAINTEXT.len()];
273+
XChaCha20Poly1305::decrypt(&key, &iv, &aad, &ciphertext_buffer, &mut plaintext_buffer).expect("Error with decrypt()");
274+
assert_eq!(plaintext_buffer, PLAINTEXT);
275+
}

0 commit comments

Comments
 (0)