You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: STRANDLOCK_PROTOCOL.md
+88-35Lines changed: 88 additions & 35 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -230,9 +230,11 @@ Answers don't have to be uncrackable forever, just uncrackable for a reasonable
230
230
We highly recommend implementations to only allow user to set a `8+ character` answer, and to check the entropy of provided answer (is all lowercase, is all uppercase, is only digits, etc), and to warn (or prevent) the user from continuing.
231
231
232
232
Even though the `question` is encrypted, an active *Man-in-the-middle* adversary **can still retrieve it**. The verification would fail, but the adversary would have the `question` plaintext.
233
+
233
234
This is acceptable, as the purpose of encrypting `SMP` process is to hide *metadata* against **passive** adversaries, not an **active** adversary.
234
235
235
236
The question **must not** contain any senstive data. And it must not contain any hints to the answer.
237
+
236
238
Implementations **must** check `answer` and `question` in initation stage, to ensure neither contain the other.
Even though the use of hash-chains and signatures may appear redundant here, as we already wrap everything in `xChaCha20Poly1305`, and we encrypt its nonce, which serves as a replay protection, and tamper protection, the use of hash-chains here ensures that even if `xChaCha20Poly1305` is broken, PFS keys cannot be replayed, nor tampered with.
280
282
283
+
The reason we opted for a hash-chain based design, instead of a simple counter, is to ensure metadata of how many key rotations occured never gets leaked, even when `xChaCha20Poly1305` is broken.
284
+
Even if `Alice's` or `Bob's` endpoint get compromised, no metadata of how many key rotation occured could be recovered.
285
+
286
+
### 5. Messaging (`MSGS`)
287
+
#### 5.1 OTP Batch Generation (`Alice`)
288
+
`Alice` uses `Bob's``ML-KEM-1024` public-key to generates many shared secrets *in chunks*, concatenating them until their total size reaches (or exceeds) `OTP_PAD_SIZE` size (default `11264 bytes`).
289
+
290
+
`Alice` does the same thing with `Classic-McEliece-8192128`.
291
+
292
+
`Alice` generates random bytes of `OTP_PAD_SIZE` size, these are called `xChaCha_shared_secrets`
293
+
294
+
`Alice` signs all `KEM's` ciphertexts using her signing private key.
295
+
296
+
`Alice` generates new `ALICE_NEW_STRAND_NONCE` as always, and bundles in `OTP BATCH` type of `0x00`, and constructs the `MSG OTP request`:
`Alice` encrypts the payload using her `ALICE_STRAND_KEY`, and her `ALICE_NEXT_STRAND_NONCE`, and sends payload to Bob.
302
+
303
+
`Alice` then `XORs``ML-KEM-1024's` shared secrets with `Classic-McEliece's` shared secrets, then she `XORs` the result with `XChaCha` secrets to produce the final result, the `ALICE_OTP_PADS`.
304
+
305
+
The first `32 bytes` of pads become the new `ALICE_STRAND_KEY`, and is truncated from `ALICE_OTP_PADS`.
306
+
307
+
She saves her new `ALICE_STRAND_KEY`, and `ALICE_OTP_PADS`.
308
+
309
+
These `ALICE_OTP_PADS` will be used to encrypt messages sent from `Alice` to `Bob`.
281
310
282
-
5. Messaging (MSGS)
283
-
5.1 OTP Batch Generation
311
+
#### 5.2 New OTP Batch Processing (`Bob`)
312
+
`Bob` decrypts the `xChaCha20Poly1305` wrapping, using `ALICE_STRAND_KEY` as key, and `ALICE_NEXT_STRAND_NONCE` as nonce.
313
+
`Bob` checks if request type is `MSG_TYPE`, then `Bob` checks the next byte if it's `0x00` (`New OTP Batch`), or `0x01` (New `OTP Message`)
284
314
285
-
Alice checks if message length + OTP_SIZE_LENGTH ≤ available pad space:
315
+
If its a `New OTP Batch`, `Bob` verifies `OTP_BATCH_SIGNATURE` against `ML_KEM_1024_CIPHERTEXT` + `CLASSIC_MCELIESE_819_CIPHERTEXT`
316
+
If invalid, abort, by skipping the request. Implementations are recommended to log and display the error to the user, so that they may be notified that someone attempted to MiTM against their conversation.
286
317
287
-
If not, she generates a new OTP batch.
318
+
If valid, `Bob` decapsulate `ML_KEM_1024_CIPHERTEXT` and `CLASSIC_MCELIESE_819_CIPHERTEXT` shared secrets.
319
+
`Bob` then follows same exact forumla `Alice` did with her keys, `XOR-ing``ML-KEM-1024's` shared secrets with `Classic-McEliece's` shared secrets, then she `XORs` the result with `XChaCha` secrets to produce the final result, the `ALICE_OTP_PADS`.
288
320
289
-
Alice generates ML-KEM-1024 shared secrets in chunks until OTP_PAD_SIZE is reached.
321
+
The first `32 bytes` of pads become the new `ALICE_STRAND_KEY`, and are truncated from `ALICE_OTP_PADS`
290
322
291
-
Alice generates Classic McEliece shared secrets similarly.
323
+
`Bob` updates `ALICE_NEXT_STRAND_NONCE` to be `ALICE_NEW_STRAND_NONCE`, then saves.
292
324
293
-
Alice generates OTP_PAD_SIZE of random bytes for XChaCha shared secrets.
325
+
These pads will be used to decrypt messages coming from `Alice`.
294
326
295
-
Alice generates a new hash chain seed MESSAGE_HASH_CHAIN_LEN (64 bytes).
327
+
#### 5.3 Message Sending
328
+
`Alice` first `UTF-8` encodes her `message`, then she checks if (`message` size + `OTP_SIZE_LENGTH` size) ≤ available `ALICE_OTP_PADS`.
296
329
297
-
Alice signs all ciphertexts using her signing key.
330
+
If theres not enough pads for the message, she generates and sends a new OTP batch (see section 5.1 & 5.2).
298
331
299
-
Alice generates ALICE_NEW_STRAND_NONCE and prepares the payload:
332
+
`Alice` performs `OTP` encryption on her message, using her pads as key.
333
+
`OTP` encryption uses 2 models of padding, depending on the message's size.
334
+
- If `message` length < `OTP_MAX_BUCKET` - `OTP_SIZE_LENGTH` (default `2 bytes`), pad to `OTP_MAX_BUCKET` (default `64 bytes`).
- If `message` length > `OTP_MAX_BUCKET`, pad randomly up to `OTP_MAX_RANDOM_PAD` (default `16 bytes`).
302
337
338
+
**All messages** are prefixed with a padding length field `OTP_SIZE_LENGTH` (`2 bytes` in `big-endian` format).
303
339
304
-
Alice encrypts using ALICE_STRAND_KEY and sends.
340
+
After padding, the new padded message plaintext, is `OTP` encrypted.
341
+
342
+
After encryption is complete, the `OTP pads` used for encryption **must** be truncated immeditely. Truncate pads *before* sending on wire, and even if request fail, never re-use nor undo truncation.
343
+
344
+
`Alice`, as always, generates a new `ALICE_NEW_STRAND_NONCE`, and prepares the request data:
Alice XORs ML-KEM, McEliece, and XChaCha secrets to produce OTP pads.
349
+
`0x01` indicates this is a MSG of type `New OTP Message`.
307
350
308
-
The first 32 bytes of pads become the new ALICE_STRAND_KEY.
351
+
`Alice` then encrypts `MSG_DATA` with `xChaCha20Poly1305` using `ALICE_STRAND_KEY`, and `ALICE_NEXT_STRAND_NONCE` as nonce, then sends it to `Bob`.
309
352
310
-
5.2 Message Sending
353
+
#### 5.3 Receiving Messages (Bob)
311
354
312
-
Alice UTF-8 encodes the message.
355
+
`Bob` decrypts the `xChaCha20Poly1305` wrapping, using `ALICE_STRAND_KEY` as key, and `ALICE_NEXT_STRAND_NONCE` as nonce.
356
+
`Bob` checks if request type is `MSG_TYPE`, then `Bob` checks the next byte if it's `0x00` (`New OTP Batch`), or `0x01` (New `OTP Message`)
313
357
314
-
Alice OTP encrypts the message with generated pads:
358
+
if is `New OTP Message`, `Bob` decrypt the encrypted message with `ALICE_OTP_PADS`.
359
+
`Bob` then reads the padding prefix of message, and removes the padding, then he removes the padding prefix.
315
360
316
-
If length < OTP_MAX_BUCKET - OTP_SIZE_LENGTH, pad to OTP_MAX_BUCKET.
361
+
`Bob` then `UTF-8` decodes the message, and displays it.
317
362
318
-
If length > OTP_MAX_BUCKET, pad randomly up to OTP_MAX_RANDOM_PAD.
363
+
#### 5.4. MSGs Notes
364
+
The reason we don't use a hash-chain like in `PFS`, is because the `xChaCha20Poly1305` wrapping `strand` scheme provides tampering and replay protection. And even if `xChaCha20Poly1305` is broken, messages that get tampered or replayed with, `Bob` would notice as the message content would be inparsable junk (at UTF-8 decoding step).
319
365
320
-
Prefix message with padding length (OTP_SIZE_LENGTH, 2 bytes, big-endian).
366
+
Encrypting with `OTP` ensures that even if `xChaCha20Poly1305` is broken, and even if one `KEM` is broken, messages remain uncompromised.
Even if `xChaCha20Poly1305` is broken, and 2 KEMs broken, messages remain uncompromised if the `OTP batch` request was not intercepted.
323
369
324
-
Generate ALICE_NEW_STRAND_NONCE.
370
+
If `OTP batch` request was not intercepted, messages become true OTPs.
325
371
326
-
Prepare payload:
372
+
If `OTP batch` request is intercepted, `OTP` messages inherits the combined security of `xChaCha20Poly1305`, `ML-KEM-1024`, `Classic-McEliece-8192128`, and even the entropy of `SMP answer`.
Additionally, using `OTPs` here provides an odd protection to `xChaCha20Poly1305`, by making "`known plaintext oracles`" attacks impossible, significantly bolstering `xChaCha20Poly1305` security.
329
375
376
+
Additionally, using `OTPs` makes nonce reuses non-fatal, as we already encrypt nonces, the only possible way for an adversary on wire to know a nonce reuse occured, is if user types same message, with same key, with same nonce.
330
377
331
-
Encrypt with ALICE_STRAND_KEY using ALICE_NEXT_STRAND_NONCE and send.
378
+
Even if a ranodmly generated nonce was repeated, and the user does such unlikely thing, the fact plaintext is OTP encrypted, means the adversary would still see different ciphertexts. Making it impossible for them to know if a nonce reuse occured.
379
+
Obviously, this does not mean a nonce reuse wouldn't occur, it just means an adversary wouldn't be able to exploit the fact because to him, is invisible random blobs.
332
380
333
-
5.3 Receiving Messages (Bob)
381
+
However, implementations **MUST** still use cryptographically secure `CSPRNG` for nonce generation nonetheless. This protection property only protects against the off chance a `CSPRNG` generated nonce gets duplicated.
334
382
335
-
Decrypt payload using ALICE_STRAND_KEY and nonce.
336
383
337
-
Verify hash chain.
338
384
339
-
Decrypt message with OTP pads from OTP batch.
385
+
### 7. Design choices (Questions & Answers)
386
+
**Question**:
387
+
Why did you opt for `xChaCha20Poly1305` over `ChaCha20Poly1305` if you're encrypting the nonce ?
340
388
341
-
Display message.
389
+
**Answer**:
390
+
Even though we do encrypt the nonce, encrypting the nonce does not prevent nonce-reuse attacks, it only hides the fact they occured.
391
+
`xChaCha20Poly1305` nonces are a lot larger than `ChaCha20Poly1305` nonces, which means the probablity of a collision is tiny.
342
392
343
-
6. Argon2id Parameters for SMP
393
+
**Question**
394
+
Why did you opt for `OTP` encryption, if you're already using `xChaCha20Poly1305`, why not just use `xChaCha` alone ?
344
395
345
-
Memory: 3GB (3072 * 1024 KB)
396
+
**Answer**
397
+
OTP encryption provides unique properties, and when combined with a classical symmetric algorithm, both algorithms benefit each other. On one hand, `xChaCha20Poly1305` encryption of `OTP`-encrypted messages, provides protection against `OTP` implementation errors, on the other hand, using `OTP`-encrypted messages as plaintext to `xChaCha20Poly1305` destroys one of cryptographors favorite oracles `known plaintext oracle`, which removes a whole class of attacks.
346
398
347
-
Iterations: 50,000
399
+
Additionally, if the `OTP Batch` exchange was not intercepted nor logged, OTPs become unbreakable.
348
400
349
-
Output: 64 bytes
401
+
**Question**
402
+
Why do you generate random bytes of X size, then hash them with `SHA3_512` and truncate them back to X size ?
350
403
351
-
7. Design Notes
404
+
**Answer**
352
405
353
406
Nonce hiding: Prevents metadata leakage and hides rare nonce collisions.
0 commit comments