diff --git a/age/chacha20poly1305/chacha20poly1305.v b/age/chacha20poly1305/chacha20poly1305.v index 34144fd..1e19ce9 100644 --- a/age/chacha20poly1305/chacha20poly1305.v +++ b/age/chacha20poly1305/chacha20poly1305.v @@ -21,12 +21,17 @@ pub fn encrypt(plaintext []u8, key []u8, nonce []u8, ad []u8, _ chacha20.Options return error('invalid nonce length') } ciphertext := []u8{len: plaintext.len + 16} + encrypt_into(plaintext, key, nonce, ad, chacha20.Options{}, ciphertext) + return ciphertext +} + +@[inline] +pub fn encrypt_into(plaintext []u8, key []u8, nonce []u8, ad []u8, _ chacha20.Options, out []u8) { mut dummy := u8(0) ad_ptr := if ad.len > 0 { &ad[0] } else { &dummy } plaintext_ptr := if plaintext.len > 0 { &plaintext[0] } else { &dummy } C.Hacl_Chacha20Poly1305_32_aead_encrypt(&key[0], &nonce[0], u32(ad.len), ad_ptr, - u32(plaintext.len), plaintext_ptr, &ciphertext[0], &ciphertext[ciphertext.len - 16]) - return ciphertext + u32(plaintext.len), plaintext_ptr, &out[0], &out[plaintext.len]) } pub fn decrypt(ciphertext []u8, key []u8, nonce []u8, ad []u8, _ chacha20.Options) ![]u8 { @@ -50,3 +55,14 @@ pub fn decrypt(ciphertext []u8, key []u8, nonce []u8, ad []u8, _ chacha20.Option } return plaintext } + +@[inline] +pub fn decrypt_into(ciphertext []u8, key []u8, nonce []u8, ad []u8, _ chacha20.Options, out []u8) bool { + mut dummy := u8(0) + ad_ptr := if ad.len > 0 { &ad[0] } else { &dummy } + out_ptr := if out.len > 0 { &out[0] } else { &dummy } + plaintext_len := u32(ciphertext.len - 16) + result := C.Hacl_Chacha20Poly1305_32_aead_decrypt(&key[0], &nonce[0], u32(ad.len), ad_ptr, + plaintext_len, out_ptr, &ciphertext[0], &ciphertext[ciphertext.len - 16]) + return result == 0 +} diff --git a/age/format/main.v b/age/format/main.v index 6623d25..4d54456 100644 --- a/age/format/main.v +++ b/age/format/main.v @@ -1,6 +1,6 @@ module format -import x.crypto.chacha20poly1305 +import age.chacha20poly1305 import base64 import os import io @@ -186,6 +186,7 @@ pub fn decrypt_payload(file_key []u8, mut reader io.BufferedReader, mut output o mut buf := []u8{len: decrypt_chunk_size + 16} mut chunk_nonce := []u8{len: 12} + mut decrypted_buf := []u8{len: decrypt_chunk_size + 16} for { mut filled := 0 for filled < buf.len { @@ -203,10 +204,11 @@ pub fn decrypt_payload(file_key []u8, mut reader io.BufferedReader, mut output o is_final := filled < decrypt_chunk_size + 16 fill_chunk_nonce(mut chunk_nonce, chunk_counter, is_final) - decrypted := chacha20poly1305.decrypt(buf[..filled], payload_key, chunk_nonce, []u8{}, chacha20.Options{}) or { - return error('decryption failed: ${err}') + if !chacha20poly1305.decrypt_into(buf[..filled], payload_key, chunk_nonce, []u8{}, + chacha20.Options{}, decrypted_buf) { + return error('decryption failed') } - output.write(decrypted) or { return error('io error: ${err}') } + output.write(decrypted_buf[..filled - 16]) or { return error('io error: ${err}') } if is_final { break } @@ -223,6 +225,7 @@ pub fn encrypt_payload(file_key []u8, mut writer io.BufferedWriter, mut input os mut reader := io.new_buffered_reader(reader: input, cap: decrypt_chunk_size) mut buf := []u8{len: decrypt_chunk_size} mut chunk_nonce := []u8{len: 12} + mut encrypted_buf := []u8{len: decrypt_chunk_size + 16} for { mut filled := 0 for filled < buf.len { @@ -240,10 +243,9 @@ pub fn encrypt_payload(file_key []u8, mut writer io.BufferedWriter, mut input os is_final := filled < decrypt_chunk_size fill_chunk_nonce(mut chunk_nonce, chunk_counter, is_final) - encrypted := chacha20poly1305.encrypt(buf[..filled], payload_key, chunk_nonce, []u8{}, chacha20.Options{}) or { - return error('encryption failed: ${err}') - } - writer.write(encrypted) or { return error('io error: ${err}') } + chacha20poly1305.encrypt_into(buf[..filled], payload_key, chunk_nonce, []u8{}, + chacha20.Options{}, encrypted_buf) + writer.write(encrypted_buf[..filled + 16]) or { return error('io error: ${err}') } if is_final { break }