diff --git a/smash/web/forms/subject_forms.py b/smash/web/forms/subject_forms.py
index b4f12f65c5eb51b4bf0f221517d04123fc49387e..cc717842d2065b99fb9e622ebc63ae0ec17fe785 100644
--- a/smash/web/forms/subject_forms.py
+++ b/smash/web/forms/subject_forms.py
@@ -1,3 +1,5 @@
+import logging
+
 from django import forms
 from django.forms import ModelForm
 
@@ -5,12 +7,94 @@ from web.forms.forms import DATEPICKER_DATE_ATTRS
 from web.models import Subject
 from web.models.constants import COUNTRY_OTHER_ID
 
+logger = logging.getLogger(__name__)
+
 
 def validate_subject_country(self, cleaned_data):
     if cleaned_data['country'].id == COUNTRY_OTHER_ID:
         self.add_error('country', "Select valid country")
 
 
+def validate_social_security_number(self, number):
+    if not is_valid_social_security_number(number):
+        self.add_error('social_security_number', "Social security number is invalid")
+
+
+def is_valid_social_security_number(number):
+    if number is not None and number != '':
+        if len(number) != 13:
+            return False
+        if not number.isdigit():
+            return False
+        if not is_luhn_valid(number[:12]):
+            return False
+        if not is_valid_verhoeff(number[:11] + number[12]):
+            return False
+
+    return True
+
+
+def luhn_checksum(card_number):
+    def digits_of(n):
+        return [int(d) for d in str(n)]
+
+    digits = digits_of(card_number)
+    odd_digits = digits[-1::-2]
+    even_digits = digits[-2::-2]
+    checksum = 0
+    checksum += sum(odd_digits)
+    for d in even_digits:
+        checksum += sum(digits_of(d * 2))
+    return checksum % 10
+
+
+def is_luhn_valid(card_number):
+    return luhn_checksum(card_number) == 0
+
+
+verhoeff_multiplication_table = (
+    (0, 1, 2, 3, 4, 5, 6, 7, 8, 9),
+    (1, 2, 3, 4, 0, 6, 7, 8, 9, 5),
+    (2, 3, 4, 0, 1, 7, 8, 9, 5, 6),
+    (3, 4, 0, 1, 2, 8, 9, 5, 6, 7),
+    (4, 0, 1, 2, 3, 9, 5, 6, 7, 8),
+    (5, 9, 8, 7, 6, 0, 4, 3, 2, 1),
+    (6, 5, 9, 8, 7, 1, 0, 4, 3, 2),
+    (7, 6, 5, 9, 8, 2, 1, 0, 4, 3),
+    (8, 7, 6, 5, 9, 3, 2, 1, 0, 4),
+    (9, 8, 7, 6, 5, 4, 3, 2, 1, 0))
+
+verhoeff_permutation_table = (
+    (0, 1, 2, 3, 4, 5, 6, 7, 8, 9),
+    (1, 5, 7, 6, 2, 8, 3, 0, 9, 4),
+    (5, 8, 0, 3, 7, 9, 6, 1, 4, 2),
+    (8, 9, 1, 6, 0, 4, 3, 5, 2, 7),
+    (9, 4, 5, 3, 1, 2, 6, 8, 7, 0),
+    (4, 2, 8, 6, 5, 7, 3, 9, 0, 1),
+    (2, 7, 9, 3, 8, 0, 6, 4, 1, 5),
+    (7, 0, 4, 6, 9, 1, 3, 2, 5, 8))
+
+
+def verhoeff_checksum(number):
+    """Calculate the Verhoeff checksum over the provided number. The checksum
+    is returned as an int. Valid numbers should have a checksum of 0."""
+    # transform number list
+    number = tuple(int(n) for n in reversed(str(number)))
+    # calculate checksum
+    check = 0
+    for i, n in enumerate(number):
+        check = verhoeff_multiplication_table[check][verhoeff_permutation_table[i % 8][n]]
+    return check
+
+
+def is_valid_verhoeff(number):
+    return verhoeff_checksum(number) == 0
+
+
+def calculate_verhoeff_check_sum(number):
+    return str(verhoeff_multiplication_table[verhoeff_checksum(str(number) + '0')].index(0))
+
+
 FIELD_ORDER = ["first_name", "last_name", "sex", "date_born", "social_security_number",
                "default_written_communication_language", "languages", "phone_number", "phone_number_2",
                "phone_number_3", "address", "city", "postal_code", "country"]
@@ -32,6 +116,7 @@ class SubjectAddForm(ModelForm):
     def clean(self):
         cleaned_data = super(SubjectAddForm, self).clean()
         validate_subject_country(self, cleaned_data)
+        validate_social_security_number(self, cleaned_data["social_security_number"])
         return cleaned_data
 
 
@@ -53,6 +138,7 @@ class SubjectEditForm(ModelForm):
 
     def clean(self):
         validate_subject_country(self, self.cleaned_data)
+        validate_social_security_number(self, self.cleaned_data["social_security_number"])
 
     class Meta:
         model = Subject
diff --git a/smash/web/tests/forms/test_subject_forms.py b/smash/web/tests/forms/test_subject_forms.py
new file mode 100644
index 0000000000000000000000000000000000000000..beb2bcbd1acff6c20ff7dae0ca213588d600b6bb
--- /dev/null
+++ b/smash/web/tests/forms/test_subject_forms.py
@@ -0,0 +1,29 @@
+import logging
+
+from web.forms.subject_forms import is_valid_social_security_number
+from web.tests import LoggedInWithWorkerTestCase
+from web.tests.functions import create_subject
+
+logger = logging.getLogger(__name__)
+
+
+class StudySubjectAddFormTests(LoggedInWithWorkerTestCase):
+    def setUp(self):
+        super(LoggedInWithWorkerTestCase, self).setUp()
+        self.subject = create_subject()
+
+    def test_is_valid_social_security_number_too_short(self):
+        self.assertFalse(is_valid_social_security_number("123"))
+
+    def test_is_valid_social_security_number_not_a_number(self):
+        # noinspection SpellCheckingInspection
+        self.assertFalse(is_valid_social_security_number("ABCDEFGHIJKLM"))
+
+    def test_is_valid_social_security_number_invalid(self):
+        self.assertFalse(is_valid_social_security_number("1234567890123"))
+
+    def test_is_valid_social_security_number(self):
+        self.assertTrue(is_valid_social_security_number("1893120105732"))
+
+    def test_is_valid_social_security_number_empty(self):
+        self.assertTrue(is_valid_social_security_number(""))