Skip to content

Commit

Permalink
feat: Support authentication code only payloads
Browse files Browse the repository at this point in the history
  • Loading branch information
PromiseFru committed Oct 24, 2024
1 parent a32c7e4 commit d84a766
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 86 deletions.
11 changes: 9 additions & 2 deletions bridge_grpc_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ def decrypt_message(phone_number, encrypted_content):
if decoded_result.get("public_key"):
create_response, create_error = create_entity(
client_publish_pub_key=base64.b64encode(
decoded_result.get("public_key")
decoded_result["public_key"]
).decode("utf-8")
)
if create_error:
Expand All @@ -238,11 +238,18 @@ def decrypt_message(phone_number, encrypted_content):

if decoded_result.get("auth_code"):
create_response, create_error = create_entity(
ownership_proof_response=decoded_result.get("auth_code")
ownership_proof_response=decoded_result["auth_code"]
)

if create_error:
return create_error

if "content_ciphertext" not in decoded_result:
return response(
success=True,
message="Successfully authenticated with auth code.",
)

else:
_, authenticate_error = authenticate_entity()

Expand Down
24 changes: 16 additions & 8 deletions content_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,19 @@ def decode_content(content: str) -> tuple:
payload = base64.b64decode(content)
result = {}

content_switch = chr(payload[0])
content_switch = payload[0]

if content_switch == "0":
if content_switch == 0:
len_public_key = struct.unpack("<i", payload[1:5])[0]
result = {"public_key": payload[5 : 5 + len_public_key]}
public_key = payload[5 : 5 + len_public_key]
result = {"public_key": public_key}

elif content_switch == "1":
elif content_switch == 1:
len_auth_code = struct.unpack("<i", payload[1:5])[0]
auth_code = payload[5 : 5 + len_auth_code].decode("utf-8")
result = {"auth_code": auth_code}

elif content_switch == 2:
len_auth_code = struct.unpack("<i", payload[1:5])[0]
auth_code = payload[5 : 5 + len_auth_code].decode("utf-8")
bridge_letter = chr(payload[5 + len_auth_code])
Expand All @@ -51,9 +57,8 @@ def decode_content(content: str) -> tuple:
"content_ciphertext": content_ciphertext,
}

elif content_switch == "2":
elif content_switch == 3:
bridge_letter = chr(payload[1])

len_ciphertext = struct.unpack("<i", payload[2:6])[0]
content_ciphertext = payload[6 : 6 + len_ciphertext]

Expand All @@ -64,8 +69,11 @@ def decode_content(content: str) -> tuple:

else:
raise ValueError(
f"Invalid starting byte value: {content_switch}. Expected one of '0' (public key), "
"'1' (auth code), or '2' (ciphertext)."
f"Invalid content switch: {content_switch}. "
"Expected 0 (auth request), "
"1 (auth code), "
"2 (auth code and payload), "
"or 3 (payload only)."
)

return result, None
Expand Down
181 changes: 105 additions & 76 deletions docs/specifications.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,125 +4,154 @@

- [Content Format](#content-format)
- [Payload Format](#payload-format)
- [Auth Request Payload](#auth-request-payload)
- [Auth Code Payload](#auth-code-payload)
- [Auth Code and Payload](#auth-code-and-payload)
- [Payload Only](#payload-only)

## Content Format

The Bridge supports the following content formats:

1. **Email format**: `to:cc:bcc:subject:body`

1. **Email**: `to:cc:bcc:subject:body`
- Example: Email Bridge

## Payload Format

### 1.1 Public Key Payload
| **Payload Type** | **Switch** | **Description** |
| ----------------------------------------------- | ---------- | ----------------------------------------------------- |
| [Auth Request Payload](#auth-request-payload) | `0` | Contains a client public key |
| [Auth Code Payload](#auth-code-payload) | `1` | Contains an authentication code |
| [Auth Code and Payload](#auth-code-and-payload) | `2` | Contains an authentication code and encrypted content |
| [Payload Only](#payload-only) | `3` | Contains encrypted content only |

The public key payload is structured as follows:
### Auth Request Payload

- **Content Switch**: A single byte indicating the type of payload.
- Value: `0` (indicates that the payload contains a public key)
- **Length of Public Key**: A 4-byte integer representing the length of the public key.
- **Public Key**: The public key data (variable length based on the length specified).
- **Switch**: `0`
- **Format**:
- 1 byte: Content Switch
- 4 bytes: Public Key Length (integer)
- Variable: Client Public Key

### Example Layout
#### Visual Representation:

```
+------------------+------------------------+------------------+
| Content Switch | Length of Public Key | Public Key |
| (1 byte) | (4 bytes, integer) | (variable size) |
+------------------+------------------------+------------------+
+------------------+----------------------------+-------------------+
| Content Switch | Length of Client Public Key| Client Public Key |
| (1 byte) | (4 bytes, integer) | (variable size) |
+------------------+----------------------------+-------------------+
```

#### Example Encoding

```python
content_switch = b"0"
public_key = b"pub_key" # Example public key
public_key_data = content_switch + struct.pack("<i", len(public_key)) + public_key
public_key_payload = base64.b64encode(public_key_data).decode("utf-8")
```
client_public_key = b"client_pub_key"

### 1.2 Authentication Code Payload
payload = (
content_switch +
struct.pack("<i", len(client_public_key)) +
client_public_key
)
encoded = base64.b64encode(payload).decode("utf-8")
print(encoded)
```

The authentication code payload is structured as follows:
### Auth Code Payload

- **Content Switch**: A single byte indicating the type of payload.
- Value: `1` (indicates that the payload contains an authentication code and ciphertext)
- **Length of Authentication Code**: A 4-byte integer representing the length of the authentication code.
- **Authentication Code**: The authentication code data.
- **Bridge Letter**: A single byte representing the bridge letter.
- **Length of Ciphertext**: A 4-byte integer representing the length of the ciphertext.
- **Ciphertext**: The encrypted content (variable length).
- **Switch**: `1`
- **Format**:
- 1 byte: Content Switch
- 4 bytes: Auth Code Length (integer)
- Variable: Auth Code

### Example Layout
#### Visual Representation:

```
+----------------+-------------------------------+---------------------+-----------------+----------------------------+----------------------------+
| Content Switch | Length of Authentication Code | Authentication Code | Bridge Letter | Length of Ciphertext | Ciphertext |
| (1 byte) | (4 bytes, integer) | (variable size) | (1 byte) | (4 bytes, integer) | (variable size) |
+----------------+-------------------------------+---------------------+-----------------+----------------------------+----------------------------+
+------------------+----------------------------+-----------------+
| Content Switch | Length of Auth Code | Auth Code |
| (1 byte) | (4 bytes, integer) | (variable size) |
+------------------+----------------------------+-----------------+
```

#### Example Encoding

```python
import struct
import base64

content_switch = b"1"
auth_code = b"123456" # Example authentication code
bl = b"e" # Example bridge letter
enc_content = b"Hello world!" # Example content to encrypt
auth_code = b"123456"

auth_code_data = (
payload = (
content_switch +
struct.pack("<i", len(auth_code)) + # Length of authentication code
auth_code +
bl +
struct.pack("<i", len(enc_content)) + # Length of ciphertext
enc_content
struct.pack("<i", len(auth_code)) +
auth_code
)
encoded = base64.b64encode(payload).decode("utf-8")
print(encoded)
```

### Auth Code and Payload

- **Switch**: `2`
- **Format**:
- 1 byte: Content Switch
- 1 byte: Bridge Letter
- 4 bytes: Auth Code Length (integer)
- 4 bytes: Ciphertext Length (integer)
- Variable: Auth Code
- Variable: Ciphertext

auth_code_payload = base64.b64encode(auth_code_data).decode("utf-8")
print(auth_code_payload)
#### Visual Representation:

```
+------------------+-------------------+----------------------------+----------------------------+------------------+----------------------------+
| Content Switch | Bridge Letter | Length of Auth Code | Length of Ciphertext | Auth Code | Ciphertext |
| (1 byte) | (1 byte) | (4 bytes, integer) | (4 bytes, integer) | (variable size) | (variable size) |
+------------------+-------------------+----------------------------+----------------------------+------------------+----------------------------+
```

### 1.3 Encrypted Content Only Payload (No Auth Code)
```python
content_switch = b"2"
auth_code = b"123456"
bridge_letter = b"e"
ciphertext = b"Hello world!"

The encrypted content only payload is structured as follows:
payload = (
content_switch +
struct.pack("<i", len(auth_code)) +
auth_code +
bridge_letter +
struct.pack("<i", len(ciphertext)) +
ciphertext
)
encoded = base64.b64encode(payload).decode("utf-8")
print(encoded)
```

### Payload Only

- **Content Switch**: A single byte indicating the type of payload.
- Value: `2` (indicates that the payload contains only ciphertext)
- **Bridge Letter**: A single byte representing the bridge letter.
- **Length of Ciphertext**: A 4-byte integer representing the length of the ciphertext.
- **Ciphertext**: The encrypted content (variable length).
- **Switch**: `3`
- **Format**:
- 1 byte: Content Switch
- 1 byte: Bridge Letter
- 4 bytes: Ciphertext Length (integer)
- Variable: Ciphertext

### Example Layout
#### Visual Representation:

```
+------------------+-----------------+----------------------------+----------------------------+
| Content Switch | Bridge Letter | Length of Ciphertext | Ciphertext |
| (1 byte) | (1 byte) | (4 bytes, integer) | (variable size) |
+------------------+-----------------+----------------------------+----------------------------+
+------------------+------------------+-----------------------------+----------------------------+
| Content Switch | Bridge Letter | Length of Ciphertext | Ciphertext |
| (1 byte) | (1 byte) | (4 bytes, integer) | (variable size) |
+------------------+------------------+-----------------------------+----------------------------+
```

#### Example Encoding

```python
import struct
import base64
content_switch = b"3"
bridge_letter = b"e"
ciphertext = b"Hello world!"

content_switch = b"2" # Content Switch indicating ciphertext only
bl = b"e" # Example bridge letter
enc_content = b"Hello world!" # Example encrypted content

content_data = (
payload = (
content_switch +
bl +
struct.pack("<i", len(enc_content)) + # Length of ciphertext (4 bytes, integer)
enc_content
bridge_letter +
struct.pack("<i", len(ciphertext)) +
ciphertext
)

enc_content_only_payload = base64.b64encode(content_data).decode("utf-8")
print(enc_content_only_payload)
encoded = base64.b64encode(payload).decode("utf-8")
print(encoded)
```

0 comments on commit d84a766

Please sign in to comment.