Skip to content

Commit aa32593

Browse files
committed
Add various buffer<->file encryption/decryption; C API
1 parent 0f8a7f5 commit aa32593

File tree

6 files changed

+1283
-90
lines changed

6 files changed

+1283
-90
lines changed

include/session/attachments.h

Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
#pragma once
2+
3+
#ifdef __cplusplus
4+
extern "C" {
5+
#endif
6+
7+
#include <stddef.h>
8+
#include <stdint.h>
9+
10+
#include "export.h"
11+
12+
typedef enum ATTACHMENT_DOMAIN {
13+
ATTACHMENT_DOMAIN_ATTACHMENT = 0x00,
14+
ATTACHMENT_DOMAIN_PROFILE_PIC = 0x01,
15+
} ATTACHMENT_DOMAIN;
16+
17+
// The size of the encryption key, which is always 32 bytes.
18+
extern const size_t ATTACHMENT_ENCRYPT_KEY_SIZE;
19+
20+
// The maximum allowed size of an regular attachment that might be sent or retrieved via onion
21+
// requests. Larger attachments are permitted, but will be too large (after padding+encryption) for
22+
// transmission via onion requests.
23+
extern const size_t ATTACHMENT_MAX_REGULAR_SIZE; // 10218286 input == 10223616 encrypted
24+
25+
/// API: crypto/session_attachment_encrypted_size
26+
///
27+
/// Returns the exact encrypted+padded output size of an input of `plaintext_size` bytes. This is
28+
/// the size of buffer that must be preallocated for the session_attachment_encrypt functions.
29+
LIBSESSION_EXPORT size_t session_attachment_encrypted_size(size_t plaintext_size);
30+
31+
/// API: crypto/session_attachment_decrypted_max_size
32+
///
33+
/// Returns the maximum possible size of the plaintext data given encrypted data of the given size.
34+
/// The actual decrypted size can be smaller, depending on the amount of padding in the encrypted
35+
/// attachment. Returns `(size_t)-1` if the given encrypted size is too small to be a valid
36+
/// encrypted attachment.
37+
LIBSESSION_EXPORT size_t session_attachment_decrypted_max_size(size_t encrypted_size);
38+
39+
/// API: crypto/session_attachment_encrypt
40+
///
41+
/// Encrypt an attachment for storage on the file server into a preallocated buffer.
42+
///
43+
/// Inputs:
44+
/// - `seed` -- the 32-byte unique sender data; typically simply the sender's Ed25519 seed.
45+
/// - `data` -- pointer to the buffer of data to encrypt
46+
/// - `datalen` -- length of the data to encrypt
47+
/// - `domain` -- domain separator; should be an ATTACHMENT_DOMAIN value.
48+
/// - `key_out` -- Pointer to an existing 32-byte buffer where the 32-byte binary decryption key
49+
/// will be written.
50+
/// - `out` -- Pointer to an output buffer, which must be able to contain exactly
51+
/// `session_attachment_encrypted_size(datalen)` encrypted output bytes.
52+
/// - `error` -- if non-NULL and encryption fails then a reason for the error is written here; must
53+
/// be a buffer of at least 256 bytes (or NULL).
54+
///
55+
/// This method always passes `allow_large` to the underlying C++ implementation; the caller should
56+
/// ensure that the input is less than `ATTACHMENT_MAX_REGULAR_SIZE` bytes before calling this (if
57+
/// compatibility with onion requests is needed).
58+
///
59+
/// Outputs:
60+
/// - returns the number of encrypted data bytes written to `out` on success, 0 if encryption fails
61+
/// (in which case `error` will be written with the error reason, if non-NULL).
62+
LIBSESSION_EXPORT bool session_attachment_encrypt(
63+
const unsigned char* seed,
64+
const unsigned char* data,
65+
size_t datalen,
66+
ATTACHMENT_DOMAIN domain,
67+
unsigned char* key_out,
68+
unsigned char* out,
69+
char* error);
70+
71+
/// API: crypto/session_attachment_encrypt_file
72+
///
73+
/// Encrypt an attachment for storage on the file server from a plaintext file on disk into a
74+
/// preallocated buffer.
75+
///
76+
/// Note that this implementation needs to read the file *twice*: a first pass to obtain the
77+
/// file-dependent encryption and nonce; and then a second pass to perform the actual encryption,
78+
/// but unlike first reading into a memory buffer, does not have to store the file contents in
79+
/// memory.
80+
///
81+
/// Inputs:
82+
/// - `seed` -- the 32-byte unique sender data; typically simply the sender's Ed25519 seed.
83+
/// - `filename` -- the filename to read (null-terminated C string).
84+
/// - `domain` -- domain separator; should be an ATTACHMENT_DOMAIN value.
85+
/// - `key_out` -- Pointer to an existing 32-byte buffer where the 32-byte binary decryption key
86+
/// will be written.
87+
/// - `make_buffer` -- callback to invoke to allocate a buffer of the required size into which to
88+
/// write the encrypted data. It is passed two arguments: the required output buffer size, and
89+
/// `ctx`, and must return a pointer to the beginning of a buffer of the requested size in which
90+
/// to write the encrypted data. Can return NULL to abort encryption (e.g. if the size is too
91+
/// large).
92+
/// - `ctx` - arbitrary pointer (which can be null) to pass to make_buffer to pass user-defined
93+
/// context into the callback. This encrypt function does not otherwise touch the pointer.
94+
/// - `error` -- if non-NULL and encryption fails then a reason for the error is written here; must
95+
/// be a buffer of at least 256 bytes (or NULL).
96+
///
97+
/// This method always passes `allow_large` to the underlying C++ implementation; the caller should
98+
/// ensure that the input is less than `ATTACHMENT_MAX_REGULAR_SIZE` bytes before calling this (if
99+
/// compatibility with onion requests is needed).
100+
///
101+
/// Outputs:
102+
/// - returns the number of encrypted data bytes written (which will always equal the value passed
103+
/// into `make_buffer`) on success; 0 if encryption fails (in which case `error` will be written
104+
/// with the error reason, if non-NULL).
105+
LIBSESSION_EXPORT size_t session_attachment_encrypt_file(
106+
const unsigned char* seed,
107+
const char* filename,
108+
ATTACHMENT_DOMAIN domain,
109+
unsigned char* key_out,
110+
unsigned char* (*make_buffer)(size_t, void* ctx),
111+
void* ctx,
112+
char* error);
113+
114+
/// API: crypto/session_attachment_decrypt
115+
///
116+
/// Decrypts an attachment allegedly produced by session_attachment_encrypt into a provided
117+
/// in-memory buffer.
118+
///
119+
/// Inputs:
120+
/// - `data` -- pointer to the buffer of data to decrypt
121+
/// - `datalen` -- length of the `data`
122+
/// - `key` -- pointer to the 32-byte binary decryption key
123+
/// - `out` -- output buffer pointer; this buffer must be able to accept the entire decrypted file,
124+
/// which can be anything up to `session_attachment_decrypted_max_size(datalen)` bytes. Note that
125+
/// this buffer may be partially overwritten even if the function returns false (for cases when
126+
/// the decryption error happens later in the encrypted stream).
127+
/// - `outlen` -- pointer in which to store the final decrypted data size written to `out`, which is
128+
/// often shorter than `session_attachment_decrypted_max_size(datalen)` (because of removed
129+
/// padding). Not touched if the function returns false.
130+
/// - `error` -- if non-NULL and decryption fails then a reason for the error is written here; must
131+
/// be a buffer of at least 256 bytes (or NULL).
132+
///
133+
/// Outputs:
134+
/// - returns true if decryption succeeds: the `*outlen` bytes decrypted value will be written
135+
/// starting at `out`. Returns false decryption fails (in which case `error` will be written with
136+
/// the error reason, if provided).
137+
LIBSESSION_EXPORT bool session_attachment_decrypt(
138+
const unsigned char* data,
139+
size_t datalen,
140+
const unsigned char* key,
141+
unsigned char* out,
142+
size_t* outlen,
143+
char* error);
144+
145+
/// API: crypto/session_attachment_decrypt
146+
///
147+
/// Decrypts an attachment allegedly produced by session_attachment_encrypt into a single in-memory
148+
/// allocated buffer.
149+
///
150+
/// Inputs:
151+
/// - `data` -- pointer to the buffer of data to decrypt
152+
/// - `datalen` -- length of the `data`
153+
/// - `key` -- pointer to the 32-byte binary decryption key
154+
/// - `out` -- Pointer-pointer to an output buffer; a new buffer is allocated, the decrypted
155+
/// attachment written to it, and then the pointer to that buffer is stored here. This buffer
156+
/// must be `free()`d by the caller when done with it *unless* the function returns false, in
157+
/// which case the buffer pointer will not be set.
158+
/// - `outlen` -- pointer in which to store final decrypted data size. Not touched if the function
159+
/// returns false.
160+
/// - `error` -- if non-NULL and decryption fails then a reason for the error is written here; must
161+
/// be a buffer of at least 256 bytes (or NULL).
162+
///
163+
/// Outputs:
164+
/// - returns true if decryption succeeds and `out` was set to the decrypted data; false if
165+
/// decryption fails (in which case `error` will be written with the error reason, if provided).
166+
LIBSESSION_EXPORT bool session_attachment_decrypt_alloc(
167+
const unsigned char* data,
168+
size_t datalen,
169+
const unsigned char* key,
170+
unsigned char** out,
171+
size_t* outlen,
172+
char* error);
173+
174+
/// API: crypto/session_attachment_decrypt_file
175+
///
176+
/// Decrypts an attachment from a file on disk and loads the decrypted content into an in-memory
177+
/// buffer.
178+
///
179+
/// Inputs:
180+
/// - `file_in` -- C string of input filename
181+
/// - `datalen` -- length of the `data`
182+
/// - `key` -- pointer to the 32-byte binary decryption key
183+
/// - `make_buffer` -- callback to invoke to allocate a buffer of the required size into which to
184+
/// write the decrypted data. It is passed two arguments: the required output buffer size, and
185+
/// `ctx`, and must return a pointer to the beginning of a buffer of the requested size in which
186+
/// to write the encrypted data. Can return NULL to abort encryption (e.g. if the size is too
187+
/// large). Note that some of the buffer may not end up being used, due to padding: the return
188+
/// value of `session_attachment_decrypt_file` indicates the actual amount of decrypted data
189+
/// written to the buffer.
190+
/// - `ctx` - arbitrary pointer (which can be null) to pass to make_buffer to pass user-defined
191+
/// context into the callback. This encrypt function does not otherwise touch the pointer.
192+
/// - `error` -- if non-NULL and decryption fails then a reason for the error is written here; must
193+
/// be a buffer of at least 256 bytes (or NULL).
194+
///
195+
/// Outputs:
196+
/// - returns the amount of decrypted data written to the buffer, (which can be 0, for an empty
197+
/// encrypted file!). If decryption fails this will be set to `(size_t)-1` to indicate the
198+
/// failure, and `error` will be written with the error reason, if provided.
199+
///
200+
LIBSESSION_EXPORT size_t session_attachment_decrypt_file(
201+
const char* file_in,
202+
const unsigned char* key,
203+
unsigned char* (*make_buffer)(size_t, void* ctx),
204+
void* ctx,
205+
char* error);
206+
207+
/// API: crypto/session_attachment_decrypt_to_file
208+
///
209+
/// Decrypts an attachment from a in-memory buffer writing the decrypted data to a file on disk.
210+
///
211+
/// Inputs:
212+
/// - `data` -- pointer to the buffer of data to decrypt
213+
/// - `datalen` -- length of the `data`
214+
/// - `key` -- pointer to the 32-byte binary decryption key
215+
/// - `filename` -- C string of output filename to write the decrypted data to. The file will be
216+
/// overwritten if it exists. If a failure occurs during decryption the file will be removed.
217+
/// - `error` -- if non-NULL and decryption fails then a reason for the error is written here; must
218+
/// be a buffer of at least 256 bytes (or NULL).
219+
///
220+
/// Outputs:
221+
/// - returns true if decryption succeeds; false if decryption fails (in which case `error` will be
222+
/// written with the error reason, if provided).
223+
///
224+
LIBSESSION_EXPORT bool session_attachment_decrypt_to_file(
225+
const unsigned char* data,
226+
size_t datalen,
227+
const unsigned char* key,
228+
const char* filename,
229+
char* error);
230+
231+
/// API: crypto/session_attachment_decrypt_file_to_file
232+
///
233+
/// Decrypts an attachment from an encrypted file on disk to another path on disk.
234+
///
235+
/// - `file_in` -- C string input filename containing encrypted data.
236+
/// - `key` -- pointer to the 32-byte binary decryption key
237+
/// - `file_out` -- C string of output filename to write the decrypted data to. The file will be
238+
/// overwritten if it exists. If a failure occurs during decryption the file will be removed.
239+
/// - `error` -- if non-NULL and decryption fails then a reason for the error is written here; must
240+
/// be a buffer of at least 256 bytes (or NULL).
241+
///
242+
/// Outputs:
243+
/// - returns true if decryption succeeds; false if decryption fails (in which case `error` will be
244+
/// written with the error reason, if provided).
245+
LIBSESSION_EXPORT bool session_attachment_decrypt_file_to_file(
246+
const char* file_in, const unsigned char* key, const char* file_out, char* error);
247+
248+
#ifdef __cplusplus
249+
}
250+
#endif

0 commit comments

Comments
 (0)