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.db import models
|
||||
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):
|
||||
pass
|
||||
@@ -52,7 +56,6 @@ class AttributeType(models.Model):
|
||||
|
||||
|
||||
class Attribute(models.Model):
|
||||
|
||||
attribute_type = models.ForeignKey(AttributeType, on_delete=models.CASCADE)
|
||||
value = models.CharField(max_length=2048)
|
||||
|
||||
@@ -81,21 +84,39 @@ class Rule(models.Model):
|
||||
write = models.BooleanField(default=False)
|
||||
delete = models.BooleanField(default=False)
|
||||
|
||||
def is_satisfied_by(self, user):
|
||||
for rule_attribute in self.ruleattribute_set.all():
|
||||
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
|
||||
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)
|
||||
|
||||
if not self.attribute_satisfies_rule(user_attribute, rule_attribute):
|
||||
return False
|
||||
|
||||
return True
|
||||
for rule_attribute in self.ruleattribute_set.all():
|
||||
if not rule_attribute.attribute_type.is_private:
|
||||
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
|
||||
if not self.attribute_satisfies_rule(user_attribute, rule_attribute):
|
||||
return False, 0, 0
|
||||
else:
|
||||
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):
|
||||
operator = rule_attribute.operator
|
||||
@@ -127,4 +148,10 @@ class RuleAttribute(Attribute):
|
||||
|
||||
class TrustedAuthority(models.Model):
|
||||
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,
|
||||
hierarchy_view,
|
||||
trusted_authorities,
|
||||
delete_authority
|
||||
delete_authority,
|
||||
verify_decryption
|
||||
)
|
||||
|
||||
app_name = 'abac'
|
||||
@@ -42,4 +43,5 @@ urlpatterns = [
|
||||
path('visualization/hierarchical', hierarchy_view, name='hierarchy_vis'),
|
||||
path('trusted-authorities', trusted_authorities, name="trusted_authorities"),
|
||||
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.core.exceptions import ValidationError
|
||||
from django.utils import timezone
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
@@ -17,7 +18,7 @@ from cryptography.hazmat.backends import default_backend
|
||||
|
||||
|
||||
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
|
||||
@@ -209,31 +210,67 @@ def get_or_create_attribute_type(name, value, private=False):
|
||||
@login_required
|
||||
def download_file(request, file_id):
|
||||
file = get_object_or_404(File, id=file_id)
|
||||
|
||||
user = request.user
|
||||
|
||||
for rule in file.rule_set.all():
|
||||
if rule.is_satisfied_by(user):
|
||||
return serve_file(file)
|
||||
|
||||
return HttpResponseForbidden('You do not have permission to download this file.')
|
||||
allowed, x, enc = check_permission(user, file)
|
||||
if allowed and not x and not enc:
|
||||
return serve_file(file)
|
||||
elif not allowed:
|
||||
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):
|
||||
"""
|
||||
Method that checks if a user is allowed to perform the operation specified in mode with the file
|
||||
TODO: Implement mode
|
||||
|
||||
"""
|
||||
if mode:
|
||||
pass
|
||||
else:
|
||||
# a) Check if the user is the owner of the file.
|
||||
if user == file.owner:
|
||||
return True
|
||||
return True, [], []
|
||||
|
||||
# b) Check if the user is a superuser.
|
||||
if user.is_superuser:
|
||||
return True
|
||||
return True, [], []
|
||||
|
||||
# c) Check the user's attributes against the file's rules.
|
||||
x = []
|
||||
enc = []
|
||||
for rule in file.rule_set.all():
|
||||
if rule.is_satisfied_by(user):
|
||||
return True
|
||||
result, x_i, enc_i = rule.is_satisfied_by(user)
|
||||
if result:
|
||||
x.append(x_i)
|
||||
enc.append(enc_i)
|
||||
else:
|
||||
return False, [], []
|
||||
return True, x, enc
|
||||
|
||||
def serve_file(file):
|
||||
# Serve the file using FileResponse.
|
||||
|
||||
Reference in New Issue
Block a user