Add to prototype
This commit is contained in:
24
abac/migrations/0004_encrypteddata.py
Normal file
24
abac/migrations/0004_encrypteddata.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# Generated by Django 4.2.6 on 2023-10-24 16:16
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('abac', '0003_trustedauthority'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='EncryptedData',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('x_values', models.TextField()),
|
||||||
|
('token', models.UUIDField(default=uuid.uuid4, editable=False, unique=True)),
|
||||||
|
('file', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='abac.file')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -1,9 +1,13 @@
|
|||||||
import pickle
|
|
||||||
from base64 import b64encode, b64decode
|
|
||||||
from django.contrib.auth.models import AbstractUser
|
from django.contrib.auth.models import AbstractUser
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
|
import pickle
|
||||||
|
from base64 import b64encode, b64decode
|
||||||
|
from random import randint
|
||||||
|
from phe import paillier
|
||||||
|
from uuid import uuid4
|
||||||
|
|
||||||
|
|
||||||
class User(AbstractUser):
|
class User(AbstractUser):
|
||||||
pass
|
pass
|
||||||
@@ -52,7 +56,6 @@ class AttributeType(models.Model):
|
|||||||
|
|
||||||
|
|
||||||
class Attribute(models.Model):
|
class Attribute(models.Model):
|
||||||
|
|
||||||
attribute_type = models.ForeignKey(AttributeType, on_delete=models.CASCADE)
|
attribute_type = models.ForeignKey(AttributeType, on_delete=models.CASCADE)
|
||||||
value = models.CharField(max_length=2048)
|
value = models.CharField(max_length=2048)
|
||||||
|
|
||||||
@@ -81,8 +84,17 @@ class Rule(models.Model):
|
|||||||
write = models.BooleanField(default=False)
|
write = models.BooleanField(default=False)
|
||||||
delete = models.BooleanField(default=False)
|
delete = models.BooleanField(default=False)
|
||||||
|
|
||||||
def is_satisfied_by(self, user):
|
def is_satisfied_by(self, user)->(bool, int, int):
|
||||||
|
x = randint(0,1000)
|
||||||
|
y = randint(0,1000)
|
||||||
|
try:
|
||||||
|
paillier_public_key = paillier.PaillierPublicKey(n=int(user.public_key))
|
||||||
|
except:
|
||||||
|
return False, 0, 0
|
||||||
|
encrypted_sum = paillier_public_key.encrypt(x)
|
||||||
|
|
||||||
for rule_attribute in self.ruleattribute_set.all():
|
for rule_attribute in self.ruleattribute_set.all():
|
||||||
|
if not rule_attribute.attribute_type.is_private:
|
||||||
try:
|
try:
|
||||||
user_attribute = UserAttribute.objects.get(
|
user_attribute = UserAttribute.objects.get(
|
||||||
user=user,
|
user=user,
|
||||||
@@ -90,12 +102,21 @@ class Rule(models.Model):
|
|||||||
)
|
)
|
||||||
except UserAttribute.DoesNotExist:
|
except UserAttribute.DoesNotExist:
|
||||||
# The user does not have this attribute; the rule is not satisfied.
|
# The user does not have this attribute; the rule is not satisfied.
|
||||||
return False
|
return False, 0, 0
|
||||||
|
|
||||||
if not self.attribute_satisfies_rule(user_attribute, rule_attribute):
|
if not self.attribute_satisfies_rule(user_attribute, rule_attribute):
|
||||||
return False
|
return False, 0, 0
|
||||||
|
else:
|
||||||
return True
|
try:
|
||||||
|
user_attribute = UserAttribute.objects.get(
|
||||||
|
user=user,
|
||||||
|
attribute_type=rule_attribute.attribute_type,
|
||||||
|
)
|
||||||
|
except UserAttribute.DoesNotExist:
|
||||||
|
# The user does not have this attribute; the rule is not satisfied.
|
||||||
|
return False, 0, 0
|
||||||
|
encrypted_attribute_value = paillier.EncryptedNumber(paillier_public_key, int(user_attribute.value))
|
||||||
|
encrypted_sum += (encrypted_attribute_value-int(rule_attribute.value))*y
|
||||||
|
return True, x, encrypted_sum.ciphertext()
|
||||||
|
|
||||||
def attribute_satisfies_rule(self, user_attribute, rule_attribute):
|
def attribute_satisfies_rule(self, user_attribute, rule_attribute):
|
||||||
operator = rule_attribute.operator
|
operator = rule_attribute.operator
|
||||||
@@ -128,3 +149,9 @@ class RuleAttribute(Attribute):
|
|||||||
class TrustedAuthority(models.Model):
|
class TrustedAuthority(models.Model):
|
||||||
name = models.CharField(max_length=255)
|
name = models.CharField(max_length=255)
|
||||||
public_key = models.TextField()
|
public_key = models.TextField()
|
||||||
|
|
||||||
|
|
||||||
|
class EncryptedData(models.Model):
|
||||||
|
file = models.ForeignKey(File, on_delete=models.CASCADE)
|
||||||
|
x_values = models.TextField() # Store the x values as comma-separated
|
||||||
|
token = models.UUIDField(default=uuid4, unique=True, editable=False)
|
||||||
|
|||||||
77
abac/templates/decrypt_and_forward.html
Normal file
77
abac/templates/decrypt_and_forward.html
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
{% load static %}
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Decrypt and Forward</title>
|
||||||
|
<script src="{% static 'abac/jsbn.js' %}"></script>
|
||||||
|
<script src="{% static 'abac/jsbn2.js' %}"></script>
|
||||||
|
<script src="{% static 'abac/prng4.js' %}"></script>
|
||||||
|
<script src="{% static 'abac/rng.js' %}"></script>
|
||||||
|
<script src="{% static 'abac/paillier.js' %}"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
function getPrivateKeyFromWebStorage() {
|
||||||
|
// Retrieve and parse the stored private key
|
||||||
|
const storedPrivateKey = localStorage.getItem('privateKey');
|
||||||
|
if (!storedPrivateKey) return null;
|
||||||
|
|
||||||
|
const parsedKey = JSON.parse(storedPrivateKey);
|
||||||
|
|
||||||
|
// Construct the public key from the stored value
|
||||||
|
const n = new BigInteger(localStorage.getItem('publicKey'));
|
||||||
|
const publicKey = new paillier.publicKey(2048, n);
|
||||||
|
|
||||||
|
// Construct the private key
|
||||||
|
const lambda = new BigInteger(parsedKey.lambda);
|
||||||
|
const privateKey = new paillier.privateKey(lambda, publicKey);
|
||||||
|
|
||||||
|
// Attach the x value
|
||||||
|
privateKey.x = new BigInteger(parsedKey.x);
|
||||||
|
|
||||||
|
return privateKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assuming you have a method to get privateKey from local web storage
|
||||||
|
let privateKey = getPrivateKeyFromWebStorage();
|
||||||
|
|
||||||
|
let encryptions = {{ encryptions_as_strings|safe }};
|
||||||
|
let decryptedValues = [];
|
||||||
|
|
||||||
|
for(let enc of encryptions) {
|
||||||
|
let bigIntEnc = new BigInteger(enc.toString());
|
||||||
|
decryptedValues.push(privateKey.decrypt(bigIntEnc).toString(10));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forward the decrypted values with a POST request
|
||||||
|
let form = document.createElement("form");
|
||||||
|
form.setAttribute("method", "post");
|
||||||
|
form.setAttribute("action", "{% url 'abac:verify_decryption' %}");
|
||||||
|
|
||||||
|
let csrfField = document.createElement("input");
|
||||||
|
csrfField.setAttribute("type", "hidden");
|
||||||
|
csrfField.setAttribute("name", "csrfmiddlewaretoken");
|
||||||
|
csrfField.setAttribute("value", "{{ csrf_token }}");
|
||||||
|
form.appendChild(csrfField);
|
||||||
|
|
||||||
|
let tokenField = document.createElement("input");
|
||||||
|
tokenField.setAttribute("type", "hidden");
|
||||||
|
tokenField.setAttribute("name", "token");
|
||||||
|
tokenField.setAttribute("value", "{{ token }}");
|
||||||
|
form.appendChild(tokenField);
|
||||||
|
|
||||||
|
for(let dec of decryptedValues) {
|
||||||
|
let input = document.createElement("input");
|
||||||
|
input.setAttribute("type", "hidden");
|
||||||
|
input.setAttribute("name", "decryptions");
|
||||||
|
input.setAttribute("value", dec);
|
||||||
|
form.appendChild(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.body.appendChild(form);
|
||||||
|
form.submit();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
{% extends 'base.html' %}
|
|
||||||
{% block content %}
|
|
||||||
<div class="container mt-5">
|
|
||||||
<div class="row justify-content-center">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<h2>Upload Public Key</h2>
|
|
||||||
<form method="post" class="mt-3">
|
|
||||||
{% csrf_token %}
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="public_key">Paste your public key here:</label>
|
|
||||||
<textarea id="public_key" name="public_key" class="form-control" rows="6" required></textarea>
|
|
||||||
</div>
|
|
||||||
<button type="submit" class="btn btn-primary">Upload Public Key</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
@@ -19,7 +19,8 @@ from .views import (
|
|||||||
upload_public_key,
|
upload_public_key,
|
||||||
hierarchy_view,
|
hierarchy_view,
|
||||||
trusted_authorities,
|
trusted_authorities,
|
||||||
delete_authority
|
delete_authority,
|
||||||
|
verify_decryption
|
||||||
)
|
)
|
||||||
|
|
||||||
app_name = 'abac'
|
app_name = 'abac'
|
||||||
@@ -42,4 +43,5 @@ urlpatterns = [
|
|||||||
path('visualization/hierarchical', hierarchy_view, name='hierarchy_vis'),
|
path('visualization/hierarchical', hierarchy_view, name='hierarchy_vis'),
|
||||||
path('trusted-authorities', trusted_authorities, name="trusted_authorities"),
|
path('trusted-authorities', trusted_authorities, name="trusted_authorities"),
|
||||||
path('trusted-authorities/delete/<int:authority_id>/', delete_authority, name='delete_authority'),
|
path('trusted-authorities/delete/<int:authority_id>/', delete_authority, name='delete_authority'),
|
||||||
|
path('verify_decryption', verify_decryption, name='verify_decryption')
|
||||||
]
|
]
|
||||||
@@ -7,6 +7,7 @@ from django.urls import reverse
|
|||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
|
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
@@ -17,7 +18,7 @@ from cryptography.hazmat.backends import default_backend
|
|||||||
|
|
||||||
|
|
||||||
from .forms import FileUploadForm, UploadCertificateForm, RuleAttributeForm, TrustedAuthorityForm
|
from .forms import FileUploadForm, UploadCertificateForm, RuleAttributeForm, TrustedAuthorityForm
|
||||||
from .models import File, Rule, UserAttribute, RuleAttribute, AttributeType, User, TrustedAuthority
|
from .models import File, Rule, UserAttribute, RuleAttribute, AttributeType, User, TrustedAuthority, EncryptedData
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@@ -209,31 +210,67 @@ def get_or_create_attribute_type(name, value, private=False):
|
|||||||
@login_required
|
@login_required
|
||||||
def download_file(request, file_id):
|
def download_file(request, file_id):
|
||||||
file = get_object_or_404(File, id=file_id)
|
file = get_object_or_404(File, id=file_id)
|
||||||
|
|
||||||
user = request.user
|
user = request.user
|
||||||
|
allowed, x, enc = check_permission(user, file)
|
||||||
for rule in file.rule_set.all():
|
if allowed and not x and not enc:
|
||||||
if rule.is_satisfied_by(user):
|
|
||||||
return serve_file(file)
|
return serve_file(file)
|
||||||
|
elif not allowed:
|
||||||
return HttpResponseForbidden('You do not have permission to download this file.')
|
return HttpResponseForbidden('You do not have permission to download this file.')
|
||||||
|
elif enc:
|
||||||
|
encrypted_data = EncryptedData(file=file, x_values=','.join(map(str, x)))
|
||||||
|
encrypted_data.save()
|
||||||
|
context = {
|
||||||
|
'encryptions_as_strings': [str(e) for e in enc],
|
||||||
|
'token': str(encrypted_data.token)
|
||||||
|
}
|
||||||
|
return render(request, 'decrypt_and_forward.html', context)
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def verify_decryption(request):
|
||||||
|
if request.method == 'POST':
|
||||||
|
token = request.POST.get('token')
|
||||||
|
decryptions = request.POST.getlist('decryptions')
|
||||||
|
encrypted_data = get_object_or_404(EncryptedData, token=token)
|
||||||
|
|
||||||
|
#Compare decryptions with stored x values TODO: for some reason this didn't work when I tried to make sure the order was preserved
|
||||||
|
x_values = list(map(int, encrypted_data.x_values.split(',')))
|
||||||
|
|
||||||
|
for decrypted in decryptions:
|
||||||
|
if int(decrypted) in x_values:
|
||||||
|
return serve_file(encrypted_data.file)
|
||||||
|
|
||||||
|
return HttpResponseForbidden("You don't have the permission to access this file!")
|
||||||
|
return HttpResponseNotAllowed(['POST'])
|
||||||
|
|
||||||
|
|
||||||
def check_permission(user, file, mode = None):
|
def check_permission(user, file, mode = None):
|
||||||
|
"""
|
||||||
|
Method that checks if a user is allowed to perform the operation specified in mode with the file
|
||||||
|
TODO: Implement mode
|
||||||
|
|
||||||
|
"""
|
||||||
if mode:
|
if mode:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
# a) Check if the user is the owner of the file.
|
# a) Check if the user is the owner of the file.
|
||||||
if user == file.owner:
|
if user == file.owner:
|
||||||
return True
|
return True, [], []
|
||||||
|
|
||||||
# b) Check if the user is a superuser.
|
# b) Check if the user is a superuser.
|
||||||
if user.is_superuser:
|
if user.is_superuser:
|
||||||
return True
|
return True, [], []
|
||||||
|
|
||||||
# c) Check the user's attributes against the file's rules.
|
# c) Check the user's attributes against the file's rules.
|
||||||
|
x = []
|
||||||
|
enc = []
|
||||||
for rule in file.rule_set.all():
|
for rule in file.rule_set.all():
|
||||||
if rule.is_satisfied_by(user):
|
result, x_i, enc_i = rule.is_satisfied_by(user)
|
||||||
return True
|
if result:
|
||||||
|
x.append(x_i)
|
||||||
|
enc.append(enc_i)
|
||||||
|
else:
|
||||||
|
return False, [], []
|
||||||
|
return True, x, enc
|
||||||
|
|
||||||
def serve_file(file):
|
def serve_file(file):
|
||||||
# Serve the file using FileResponse.
|
# Serve the file using FileResponse.
|
||||||
|
|||||||
Reference in New Issue
Block a user