Detail when data can be deleted
This commit is contained in:
parent
b3b78a1ba9
commit
1c198d2be0
30
README.md
30
README.md
@ -56,7 +56,7 @@ handshake_secret = hkdf_extract(
|
||||
input_key_material=shared_secret
|
||||
)
|
||||
```
|
||||
This value is therefore common to Alice and Bob.
|
||||
This value is therefore common to Alice and Bob. Now, `shared_secret` can be deleted.
|
||||
|
||||
She will also compute `handsake_hash`, a SHA384 hash of all previous messages sent through the connection. For Alice and Bob to have the same `handshake_hash`, the order of the messages in the hash input is determined by the mutual consensus.
|
||||
```python
|
||||
@ -64,7 +64,7 @@ if i_play_the_role_of_the_server:
|
||||
ordered_bytes = bytes_received + bytes_sent
|
||||
else:
|
||||
ordered_bytes = bytes_sent + bytes_received
|
||||
handshake_hash = SHA384(ordered_bytes)
|
||||
handshake_hash = sha384(ordered_bytes).digest()
|
||||
```
|
||||
With the `handshake_secret` and the `handshake_hash`, Alice computes the `local_handshake_traffic_secret` using the HKDF Expand Label function as follows:
|
||||
```python
|
||||
@ -135,7 +135,7 @@ encrypted_auth_msg = AES_128_GCM.encrypt(
|
||||
|:----------------------:|:-----------:|
|
||||
| 96 bytes | 16 bytes |
|
||||
|
||||
At this point, `local_handshake_key`, `local_handshake_iv`, `peer_handshake_key` and `peer_handshake_iv` can be deleted.
|
||||
At this point, `alice_ephK_pub`, `local_handshake_key` and `local_handshake_iv` can be deleted. Once Alice received and decrypted the Bob message, `peer_handshake_key` and `peer_handshake_iv` can be deleted too.
|
||||
|
||||
Bob will do the same and Alice will verify whether the ephemeral public key `bob_ephK_pub` sent by Bob earlier match the received signature. If they don't match, the handshake is aborted. Otherwise, Alice can check if the Bob's identity public key `bob_idK_pub` is already known and matches one of her contacts or if Bob is a new unknown person.
|
||||
```python
|
||||
@ -143,11 +143,12 @@ if ed_22519_verify(
|
||||
public_key=bob_idK_pub,
|
||||
data=bob_ephK_pub
|
||||
):
|
||||
is_already_known(bob_idK_pub)
|
||||
check_if_already_known(bob_idK_pub)
|
||||
# continue handshake
|
||||
else:
|
||||
# abort handshake
|
||||
```
|
||||
Once verified, `bob_ephK_pub` can be deleted.
|
||||
|
||||
## Handshake finished
|
||||
A new hash of the handshake is computed to include the authentication step. Alice will then compute a HMAC of this hash to agree with Bob that the handshake has not been corrupted. The 48 bytes long HMAC key is computed using HKDF Expand Label:
|
||||
@ -164,6 +165,8 @@ local_handshake_finished = HMAC(
|
||||
data=handshake_hash
|
||||
)
|
||||
```
|
||||
After this, `local_handshake_traffic_secret` can be deleted.
|
||||
|
||||
Alice sends the HMAC output `local_handshake_finished` in __plain text__ and receives the Bob's one.
|
||||
| HMAC output |
|
||||
|:-----------:|
|
||||
@ -185,10 +188,10 @@ peer_handshake_finished = HMAC(
|
||||
|
||||
assert(received_handshake_finished == peer_handshake_finished)
|
||||
```
|
||||
If the Bob's HMAC and the computed `peer_handshake_finished` don't match, the handshake is aborted.
|
||||
`peer_handshake_traffic_secret` can be deleted. If the Bob's HMAC and the computed `peer_handshake_finished` don't match, the handshake is aborted.
|
||||
|
||||
## Application Keys Derivation
|
||||
Once Alice and Bob agreed that the handshake was valid, they will compute the keys that will be used to send application data. First, Alice computes a 48 bytes long `derived_secret`:
|
||||
Once Alice and Bob agreed that the handshake was valid, they will compute the keys that will be used to send application data. First, Alice computes a 48 bytes long `derived_secret` from the previous `handshake_secret`:
|
||||
```python
|
||||
derived_secret = HKDF_expand_label(
|
||||
key=handshake_secret,
|
||||
@ -196,14 +199,14 @@ derived_secret = HKDF_expand_label(
|
||||
context=None
|
||||
)
|
||||
```
|
||||
From this `derived_secret`, a 48 bytes long `master_secret` is retreived:
|
||||
Now, `handshake_secret` can be deleted. From this `derived_secret`, a 48 bytes long `master_secret` is retreived:
|
||||
```python
|
||||
master_secret = hkdf_extract(
|
||||
salt=derived_secret,
|
||||
input_key_material=""
|
||||
)
|
||||
```
|
||||
Then, Alice compute her `local_application_traffic_secret` and `peer_application_traffic_secret` as follows:
|
||||
Then, `derived_secret` can be deleted and Alice computes her `local_application_traffic_secret` and `peer_application_traffic_secret` as follows:
|
||||
```python
|
||||
local_application_traffic_secret = HKDF_expand_label(
|
||||
key=master_secret,
|
||||
@ -217,7 +220,9 @@ peer_application_traffic_secret = HKDF_expand_label(
|
||||
context=handshake_hash
|
||||
)
|
||||
```
|
||||
`application_local_label` and `application_peer_label` also depend on the mutual consensus and are unique to this step:
|
||||
The `handshake_hash` is the same as in the [handshake verification step](#handshake-finished). Therefore, it doesn't include the verification HMACs.
|
||||
|
||||
`application_local_label` and `application_peer_label` depend on the mutual consensus and are unique to this step:
|
||||
```python
|
||||
application_local_label = "application_i_am_"
|
||||
application_peer_label = "application_i_am_"
|
||||
@ -228,6 +233,7 @@ else:
|
||||
application_local_label += "alice"
|
||||
application_peer_label += "bob"
|
||||
```
|
||||
At this point, `master_secret` can be deleted.
|
||||
|
||||
Application encryption keys and IVs are finally derived from the two secrets in the same way as the handshake's ones:
|
||||
```python
|
||||
@ -245,8 +251,10 @@ local_application_iv = HKDF_expand_label(
|
||||
```
|
||||
The Bob's key and IV are obtained by replacing `local_application_traffic_secret` with `peer_application_traffic_secret`. Keys and IVs lengths are the same as the handshake's ones.
|
||||
|
||||
Once application keys are derived, `local_application_traffic_secret` and `peer_application_traffic_secret` can be deleted.
|
||||
|
||||
## Secure communication
|
||||
The handshake is finished. Alice and Bob can now talk securely using AES-GCM 128 bits. At this point, every messages are sent encrypted. AES-GCM nonces are obtained by XORing a 8 bytes counter to the last 8 bytes of the IV. The counter is specific to the IV. It's initialized to 0 and incremented by 1 with each use. Here is a python implementation of this nonce generation:
|
||||
At this point, the handshake is finished. Alice and Bob can now talk securely using AES-GCM 128 bits. From now on, every messages are sent encrypted. AES-GCM nonces are obtained by XORing a 8 bytes counter to the last 8 bytes of the IV. The counter is specific to the IV. It's initialized to 0 and incremented by 1 with each use. Here is a python implementation of this nonce generation:
|
||||
```python
|
||||
def iv_to_nonce(iv, counter):
|
||||
counter_bytes = b"\x00"*4 + counter.to_bytes(8, byteorder="big")
|
||||
@ -312,4 +320,4 @@ AFAIK, the PSEC protocol provide all expected properties described earlier:
|
||||
- Plaintext lengths can be obfuscated using padding.
|
||||
- Since all parties have the necessary keys to create any arbitrary messages, all sent messages can be denied.
|
||||
- As far as the communications are ephemeral, forward secrecy is insured: encryption keys are derived from ephemeral keys `ephK`.
|
||||
- If the ephemeral keys `ephK` are generated using a strong cryptographically secure PRNG, future secrecy is insured.
|
||||
- If the ephemeral keys `ephK` are generated using a strong cryptographically secure PRNG, future secrecy is insured.
|
Loading…
x
Reference in New Issue
Block a user