-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
proof of concept for bonfire-networks/bonfire-app#1048
- Loading branch information
Showing
7 changed files
with
181 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
defmodule ActivityPub.Safety.Encryption do | ||
@moduledoc """ | ||
Provides encryption and decryption functionality using RSA keys managed by ActivityPub.Safety.Keys. | ||
NOTE: not used at the moment, simply intended as a proof-of-concept | ||
""" | ||
import Untangle | ||
|
||
alias ActivityPub.Safety.Keys | ||
alias ActivityPub.Actor | ||
|
||
@doc """ | ||
Encrypts data for a given actor using their public key. | ||
## Parameters | ||
- data: The data to encrypt (binary or string) | ||
- actor: The Actor struct or AP ID of the recipient | ||
## Returns | ||
- {:ok, encrypted_data} on success | ||
- {:error, reason} on failure | ||
""" | ||
def encrypt(data, ap_id) when is_binary(ap_id) do | ||
with {:ok, public_key} <- Keys.get_public_key_for_ap_id(ap_id) do | ||
encrypt_with_public_key(data, public_key) | ||
end | ||
end | ||
|
||
def encrypt(data, actor) do | ||
with {:ok, public_key} <- Keys.public_key_from_data(actor) do | ||
encrypt_with_public_key(data, public_key) | ||
end | ||
end | ||
|
||
@doc """ | ||
Decrypts data for a given actor using their private key. | ||
## Parameters | ||
- encrypted_data: The data to decrypt (binary) | ||
- actor: The Actor struct with private keys | ||
## Returns | ||
- {:ok, decrypted_data} on success | ||
- {:error, reason} on failure | ||
""" | ||
def decrypt(encrypted_data, %Actor{local: true, keys: keys} = actor) when not is_nil(keys) do | ||
with {:ok, private_key, _public_key} <- Keys.keypair_from_pem(keys) do | ||
decrypt_with_private_key(encrypted_data, private_key) | ||
end | ||
end | ||
|
||
def decrypt(encrypted_data, ap_id) when is_binary(ap_id) do | ||
with {:ok, actor} <- Actor.get_cached(ap_id: ap_id) do | ||
decrypt(encrypted_data, actor) | ||
end | ||
end | ||
|
||
def decrypt(_encrypted_data, %Actor{local: false} = actor) do | ||
error(actor, "Cannot perform decryption for remote actors") | ||
end | ||
|
||
def decrypt(_encrypted_data, actor) do | ||
error(actor, "Could not find a private key to use for decryption") | ||
end | ||
|
||
# Private functions | ||
|
||
defp encrypt_with_public_key(data, public_key) do | ||
with {:ok, decoded_key} <- Keys.public_key_decode(public_key) do | ||
encrypted = :public_key.encrypt_public(data, decoded_key) | ||
{:ok, encrypted} | ||
end | ||
rescue | ||
e -> error(e) | ||
end | ||
|
||
defp decrypt_with_private_key(encrypted_data, private_key) do | ||
decrypted = :public_key.decrypt_private(encrypted_data, private_key) | ||
{:ok, decrypted} | ||
rescue | ||
e in ErlangError -> | ||
case e do | ||
%ErlangError{original: {:error, _, msg}} -> | ||
error(to_string(msg)) | ||
|
||
_ -> | ||
error(e) | ||
end | ||
|
||
e -> | ||
error(e) | ||
end | ||
end |
2 changes: 1 addition & 1 deletion
2
lib/safety/signatures.ex → lib/safety/http_signatures_adapter.ex
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
defmodule ActivityPub.Safety.EncryptionTest do | ||
# this isn't used but simply a proof of concept | ||
use ActivityPub.DataCase, async: false | ||
alias ActivityPub.Safety.Encryption | ||
alias ActivityPub.Safety.Keys | ||
alias ActivityPub.Actor | ||
|
||
# Import the test helpers that contain the local_actor() function | ||
import ActivityPub.Factory | ||
|
||
describe "encrypt/2" do | ||
test "successfully encrypts data for a local actor" do | ||
actor = local_actor() | ||
{:ok, actor} = Keys.ensure_keys_present(actor.actor) | ||
|
||
assert {:ok, encrypted} = Encryption.encrypt("secret message", actor) | ||
assert is_binary(encrypted) | ||
assert encrypted != "secret message" | ||
end | ||
|
||
test "returns error for actor without public key" do | ||
actor = local_actor() | ||
|
||
actor = %{actor | data: Map.delete(actor.data, "publicKey")} | ||
|
||
assert {:error, "Public key not found"} = Encryption.encrypt("secret message", actor) | ||
end | ||
|
||
test "encrypts data using AP ID" do | ||
actor = local_actor() | ||
{:ok, actor} = Keys.ensure_keys_present(actor.actor) | ||
|
||
assert {:ok, encrypted} = Encryption.encrypt("secret message", actor.data["id"]) | ||
assert is_binary(encrypted) | ||
assert encrypted != "secret message" | ||
end | ||
end | ||
|
||
describe "decrypt/2" do | ||
test "successfully decrypts data for a local actor" do | ||
actor = local_actor() | ||
{:ok, actor} = Keys.ensure_keys_present(actor.actor) | ||
|
||
assert {:ok, encrypted} = Encryption.encrypt("secret message", actor) | ||
assert encrypted != "secret message" | ||
assert {:ok, "secret message"} = Encryption.decrypt(encrypted, actor) | ||
end | ||
|
||
test "fails decryption for remote actor" do | ||
actor = local_actor() | ||
{:ok, actor} = Keys.ensure_keys_present(actor.actor) | ||
remote_actor = %{actor | local: false} | ||
|
||
assert {:error, "Cannot perform decryption for remote actors"} = | ||
Encryption.decrypt("fake encrypted data", remote_actor) | ||
end | ||
|
||
test "fails decryption with invalid data" do | ||
actor = local_actor() | ||
{:ok, actor} = Keys.ensure_keys_present(actor.actor) | ||
|
||
assert {:error, _} = Encryption.decrypt("non-encrypted data", actor) | ||
end | ||
|
||
test "fails decryption with someone else's keys" do | ||
actor = local_actor() | ||
{:ok, actor} = Keys.ensure_keys_present(actor.actor) | ||
|
||
actor2 = local_actor() | ||
{:ok, actor2} = Keys.ensure_keys_present(actor2.actor) | ||
|
||
assert {:ok, encrypted} = Encryption.encrypt("secret message", actor) | ||
assert {:error, _} = Encryption.decrypt(encrypted, actor2) | ||
end | ||
|
||
test "fails decryption with missing keys" do | ||
actor = local_actor().actor | ||
|
||
assert {:error, _} = Encryption.decrypt("non-encrypted data", actor) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters