Hi Alan, On Thu, Feb 19, 2026 at 1:27 PM Alan Coopersmith <[email protected]> wrote: > https://blog.trailofbits.com/2026/02/18/carelessness-versus-craftsmanship-in-cryptography/ > reports: > > Two popular AES libraries, aes-js and pyaes, “helpfully” provide a default > > IV > > in their AES-CTR API, leading to a large number of key/IV reuse bugs. These > > bugs potentially affect thousands of downstream projects.
> > strongMan is a web-based management tool for folks using the strongSwan VPN > > suite. It allows for credential and user management, initiation of VPN > > connections, and more. It’s a pretty slick piece of software; if you’re into > > IPsec VPNs, you should definitely give it a look. > > There will be a security advisory for strongMan issued in conjunction with > > this > > fix, outlining the nature of the problem, its severity, and the measures > > taken > > to address it. Everything will be out in the open, with full transparency > > for > > all strongMan users. That strongMan patch is refreshing to see: The latest version fixes the issue by switching to AES-GCM-SIV encryption > with a random nonce and an individually derived encryption key, using HKDF, > for each encrypted value. Database migrations are provided to automatically > re-encrypt all credentials. The patch is also pretty small: diff --git a/requirements.txt b/requirements.txt index 6cf1caa..111fa76 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,7 @@ Django==4.2.28 git+https://github.com/wbond/oscrypto.git@1547f535001ba568b239b8797465536759c742a3 asn1crypto==1.5.1 +cryptography==46.0.3 pyaes==1.6.1 django-tables2==2.3.4 vici==5.8.4 diff --git a/strongMan/helper_apps/encryption/fields.py b/strongMan/helper_apps/encryption/fields.py index f574782..3af11eb 100644 --- a/strongMan/helper_apps/encryption/fields.py +++ b/strongMan/helper_apps/encryption/fields.py @@ -1,11 +1,16 @@ ''' https://github.com/orcasgit/django-fernet-fields ''' +import os + from django.conf import settings from django.core.exceptions import FieldError, ImproperlyConfigured from django.db import models from django.utils.encoding import force_bytes, force_str from django.utils.functional import cached_property +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.ciphers.aead import AESGCMSIV +from cryptography.hazmat.primitives.kdf.hkdf import HKDF from pyaes import aes as aeslib __all__ = [ @@ -20,7 +25,7 @@ class EncryptedField(models.Field): - """A field that encrypts values using Fernet symmetric encryption.""" + """A field that encrypts values using AES-GCM-SIV symmetric encryption.""" _internal_type = 'BinaryField' def __init__(self, *args, **kwargs): @@ -42,12 +47,24 @@ def __init__(self, *args, **kwargs): super(EncryptedField, self).__init__(*args, **kwargs) def encrypt(self, value): - aes = aeslib.AESModeOfOperationCTR(self.key) - return aes.encrypt(value) + # we use a random nonce for the encryption and to generate an individual encryption key, which is + # then concatenated and separated by a : from the ciphertext + nonce = os.urandom(12) + # leave the salt intentionally blank + hkdf = HKDF(algorithm=hashes.SHA256(), length=32, salt=b'', info=nonce + b'EncryptedField') + aesgcmsiv = AESGCMSIV(hkdf.derive(self.key)) + return nonce + b':' + aesgcmsiv.encrypt(nonce, value, None) def decrypt(self, value): - aes = aeslib.AESModeOfOperationCTR(self.key) - return aes.decrypt(value) + # decrypt unsafe legacy values if we don't find a nonce + if len(value) < 13 or value[12] != b':'[0]: + aes = aeslib.AESModeOfOperationCTR(self.key) + return aes.decrypt(value) + # <12-byte nonce>:<ciphertext> + nonce = value[:12] + hkdf = HKDF(algorithm=hashes.SHA256(), length=32, salt=b'', info=nonce + b'EncryptedField') + aesgcmsiv = AESGCMSIV(hkdf.derive(self.key)) + return aesgcmsiv.decrypt(nonce, value[13:], None) @cached_property def key(self): Hell, it even uses HKDF correctly <https://soatok.blog/2021/11/17/understanding-hkdf/>. Most people screw HKDF up in a way that only security proof authors really care about, and they didn't. Just wanted to say: As awful as pyaes and aes-js are, seeing this high quality work in response to the disclosure is a little heartwarming.
