aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Tim Segers <tsegers@pm.me>2025-12-07 19:42:56 +0100
committerGravatar Tim Segers <tsegers@pm.me>2025-12-07 19:43:28 +0100
commit9331455b902d2a853458f32806b624349a5e2405 (patch)
tree3b0dc644add994ecc7473856df88cd9fdef91594
parent6b2edf74e4005a194546356c2141b7f09e013ca3 (diff)
downloadtweetpipe-9331455b902d2a853458f32806b624349a5e2405.tar.gz
Derive a per-chunk chunk_id-dependent key to prevent chunk reordering
-rw-r--r--ext/tweetpwhash.c45
-rw-r--r--ext/tweetpwhash.h12
-rw-r--r--src/tweetpipe.c10
3 files changed, 65 insertions, 2 deletions
diff --git a/ext/tweetpwhash.c b/ext/tweetpwhash.c
index cd738cf..ff7aed4 100644
--- a/ext/tweetpwhash.c
+++ b/ext/tweetpwhash.c
@@ -7,6 +7,7 @@
#define HB crypto_hash_BYTES
#define BB crypto_hashblocks_BLOCKBYTES
#define SB crypto_pwhash_SALTBYTES
+#define CB crypto_kdf_CONTEXTBYTES
typedef unsigned char u8;
typedef unsigned long long u64;
@@ -99,6 +100,50 @@ sv prf(u8 *out, const u8 *m, u64 mln, const u8 *k, u64 kln)
chi(&c); chu(&c, ok, BB); chu(&c, ih, HB); chf(out, &c);
}
+sv hext(u8 *prk, const u8 *ikm, u64 ikmln)
+{
+ u64 i;
+ u8 s[HB];
+
+ FOR(i, HB) s[i] = 0;
+ prf(prk, ikm, ikmln, s, HB);
+}
+
+sv hexp(u8 *out, u64 outln, const u8* prk, const u64 idx, const u8 *ctx)
+{
+ u64 l = 0, i = 0, j, bl;
+ u8 b[HB + CB + 8 + 1];
+
+ FOR(j, CB) b[HB + j] = ctx[j];
+ ts64(b + HB + CB, idx);
+
+ while (l < outln) {
+ b[HB + CB + 8] = ++i;
+
+ if (i == 1)
+ prf(b, b + HB, CB + 8 + 1, prk, HB);
+ else
+ prf(b, b, HB + CB + 8 + 1, prk, HB);
+
+ bl = MIN(HB, outln - l);
+ FOR(j, bl) out[l + j] = b[j];
+ l += bl;
+ }
+}
+
+int crypto_kdf(u8 *out, u64 outln, const u64 idx, const u8 *ctx, const u8 *ikm, u64 ikmln)
+{
+ u8 prk[HB];
+
+ if (outln > HB * 255)
+ return -1;
+
+ hext(prk, ikm, ikmln);
+ hexp(out, outln, prk, idx, ctx);
+
+ return 0;
+}
+
int crypto_pwhash(u8 *out, u64 outln, const u8 *p, u64 pln, const u8 *s, u64 c)
{
u64 i, j, b, nb, bl, o;
diff --git a/ext/tweetpwhash.h b/ext/tweetpwhash.h
index 177c304..0514183 100644
--- a/ext/tweetpwhash.h
+++ b/ext/tweetpwhash.h
@@ -12,4 +12,16 @@ extern int crypto_pwhash_pbkdf2hmacsha512_tweet(unsigned char *,unsigned long lo
#define crypto_pwhash_pbkdf2hmacsha512_SALTBYTES crypto_pwhash_pbkdf2hmacsha512_tweet_SALTBYTES
#define crypto_pwhash_pbkdf2hmacsha512_VERSION crypto_pwhash_pbkdf2hmacsha512_tweet_VERSION
#define crypto_pwhash_pbkdf2hmacsha512_IMPLEMENTATION "crypto_pwhash/pbkdf2hmacsha512/tweet"
+#define crypto_kdf_PRIMITIVE "hkdfhmacsha512"
+#define crypto_kdf crypto_kdf_hkdfhmacsha512
+#define crypto_kdf_CONTEXTBYTES crypto_kdf_hkdfhmacsha512_CONTEXTBYTES
+#define crypto_kdf_IMPLEMENTATION crypto_kdf_hkdfhmacsha512_IMPLEMENTATION
+#define crypto_kdf_VERSION crypto_kdf_hkdfhmacsha512_VERSION
+#define crypto_kdf_hkdfhmacsha512_tweet_CONTEXTBYTES 8
+extern int crypto_kdf_hkdfhmacsha512_tweet(unsigned char *,unsigned long long,unsigned long long,const unsigned char *,const unsigned char *,unsigned long long);
+#define crypto_kdf_hkdfhmacsha512_tweet_VERSION "-"
+#define crypto_kdf_hkdfhmacsha512 crypto_kdf_hkdfhmacsha512_tweet
+#define crypto_kdf_hkdfhmacsha512_CONTEXTBYTES crypto_kdf_hkdfhmacsha512_tweet_CONTEXTBYTES
+#define crypto_kdf_hkdfhmacsha512_VERSION crypto_kdf_hkdfhmacsha512_tweet_VERSION
+#define crypto_kdf_hkdfhmacsha512_IMPLEMENTATION "crypto_kdf/hkdfhmacsha512/tweet"
#endif
diff --git a/src/tweetpipe.c b/src/tweetpipe.c
index e369f70..768faaf 100644
--- a/src/tweetpipe.c
+++ b/src/tweetpipe.c
@@ -70,6 +70,7 @@ stream_encrypt(Context *ctx)
chunk_nonce + crypto_secretbox_NONCEBYTES - crypto_secretbox_BOXZEROBYTES;
unsigned char *const chunk_msg = chunk_base + crypto_secretbox_ZEROBYTES;
unsigned char nonce[crypto_secretbox_NONCEBYTES];
+ unsigned char chunk_key[crypto_secretbox_KEYBYTES];
uint64_t chunk_id;
ssize_t max_chunk_size;
ssize_t chunk_size;
@@ -109,6 +110,8 @@ stream_encrypt(Context *ctx)
memzero(chunk_nonce, crypto_secretbox_NONCEBYTES - crypto_secretbox_BOXZEROBYTES +
crypto_secretbox_ZEROBYTES);
randombytes(nonce, crypto_secretbox_NONCEBYTES);
+ crypto_kdf(chunk_key, crypto_secretbox_KEYBYTES, chunk_id, (unsigned char *) "tweetkey",
+ ctx->key, crypto_secretbox_KEYBYTES);
/*
* encrypt with crypto_secretbox()
*
@@ -118,7 +121,7 @@ stream_encrypt(Context *ctx)
* | 4 | 8 | 16 | 16 | chunk_size
*/
if (crypto_secretbox(chunk_base, chunk_base, chunk_size + crypto_secretbox_ZEROBYTES, nonce,
- ctx->key) != 0) {
+ chunk_key) != 0) {
die(0, "Encryption error");
}
/*
@@ -156,6 +159,7 @@ stream_decrypt(Context *ctx)
chunk_nonce + crypto_secretbox_NONCEBYTES - crypto_secretbox_BOXZEROBYTES;
unsigned char *const chunk_msg = chunk_base + crypto_secretbox_ZEROBYTES;
unsigned char nonce[crypto_secretbox_NONCEBYTES];
+ unsigned char chunk_key[crypto_secretbox_KEYBYTES];
uint64_t chunk_id;
ssize_t readnb;
ssize_t max_chunk_size;
@@ -181,8 +185,10 @@ stream_decrypt(Context *ctx)
}
memcpy(nonce, chunk_nonce, crypto_secretbox_NONCEBYTES);
memzero(chunk_nonce, crypto_secretbox_NONCEBYTES);
+ crypto_kdf(chunk_key, crypto_secretbox_KEYBYTES, chunk_id, (unsigned char *) "tweetkey",
+ ctx->key, crypto_secretbox_KEYBYTES);
if (crypto_secretbox_open(chunk_base, chunk_base, chunk_size + crypto_secretbox_ZEROBYTES,
- nonce, ctx->key) != 0) {
+ nonce, chunk_key) != 0) {
printf("Unable to decrypt chunk #%" PRIu64 " - ", chunk_id);
if (chunk_id == 0) {
die(0, "Wrong password or key?");