Where
-Infinity
0

Hi Alan,

On Thu, Feb 19, 2026 at 1:27 PM Alan Coopersmith <alan.coopersmith () oracle com> 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/helperapps/encryption/fields.py b/strongMan/helperapps/encryption/fields.py index f574782..3af11eb 100644 --- a/strongMan/helperapps/encryption/fields.py +++ b/strongMan/helperapps/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 forcebytes, forcestr from django.utils.functional import cachedproperty +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.""" internaltype = '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)

@cachedproperty

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.

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. [...] Reusing a key/IV pair leads to serious security issues: if you encrypt two messages in CTR mode or GCM with the same key and IV, then anybody with access to the ciphertexts can recover the XOR of the plaintexts, and that’s a very bad thing. [...] As you might guess from the names, aes-js and pyaes are JavaScript and Python libraries that implement the AES block cipher. They’re pretty widely used: the Node.js package manager (npm) repository lists 850 aes-js dependents as of this writing, and GitHub estimates that over 700,000 repositories integrate aes-js and nearly 23,000 repositories integrate pyaes, either as direct or indirect dependencies. [...] The default IV problem ---------------------- We’ll start with the biggest concern Trail of Bits identified: when instantiating AES in CTR mode, aes-js and pyaes do not require an IV. Instead, if no IV is specified, libraries will supply a default IV of 0x00000000000000000000000000000001.

Worse still, the documentation provides examples of this behavior as typical behavior. For example, this comes from the pyaes README:

aes = pyaes.AESModeOfOperationCTR(key) plaintext = "Text may be any length you wish, no padding is required" ciphertext = aes.encrypt(plaintext)

The first line ought to be something like aes = pyaes.AESModeOfOperationCTR(key, iv), where iv is a randomly generated value. Users who follow this example will always wind up with the same IV, making it inevitable that many (if not most) will wind up with a key/IV reuse bug in their software. Most people are looking for an easy-to-use encryption library, and what’s simpler than just passing in the key?

That apparent simplicity has led to widespread use of the “default,” creating a multitude of key/IV reuse vulnerabilities.

Other issues ============

Lack of modern cipher modes ---------------------------

aes-js and pyaes don’t support modern cipher modes like AES-GCM and AES-GCM-SIV. In most contexts where you want to use AES, you likely want to use these modes, as they offer authentication in addition to encryption. This is no small issue: even for programs that use aes-js or pyaes with distinct key/IV pairs, AES CTR ciphertexts are still malleable: if an attacker changes the bits in the ciphertext, then the resulting bits in the plaintext will change in exactly the same way, and CTR mode doesn’t provide any way to detect this. This can allow an attacker to recover an ECDSA key by tricking the user into signing messages with a series of related keys.

Cipher modes like GCM and GCM-SIV prevent this by computing keyed “tags” that will fail to authenticate when the ciphertext is modified, even by a single bit. Pretty nifty feature, but support is completely absent from aes-js and pyaes.

Timing problems ---------------

On top of that, both aes-js and pyaes are vulnerable to side-channel attacks. Both libraries use lookup tables for the AES S-box, which enables cache-timing attacks. On top of that, there are timing issues in the PKCS7 implementation, enabling a padding oracle attack when used in CBC mode.

Lack of updates ---------------

aes-js hasn’t been updated since 2018. pyaes hasn’t been touched since 2017. Since then, a number of issues have been filed against both libraries. Here are just a few examples:

- Outdated distribution tools for pyaes (it relies on distutils, which has been deprecated since October 2023) - Performance issues in the streaming API - UTF-8 encoding problems in aes-js - Lack of IV and key generation routines in both

Developer response ------------------

Finally, in 2022, an issue was filed against aes-js about the default IV problem. The developer’s response ended with the following:

The AES block cipher is a cryptographic primitive, so it’s very important to understand and use it properly, based on its application. It’s a powerful tool, and with great power, yadda, yadda, yadda. :) [...] In November 2025, we reached out to the maintainer via email and via X, but we received no response. [...] We identified several pieces of software impacted by the default IV behavior in pyaes and aes-js. Many of the programs we found have been deprecated, and we even found a couple of vulnerable wallets for cryptocurrencies that are no longer traded. We also picked out a large number of programs where the security impact of key/IV reuse was minimal or overshadowed by larger security concerns (for instance, there were a few programs that reused key/IV pairs, but the key was derived from a 4-digit PIN).

However, one of the programs we found struck us as important: a VPN management suite.

strongMan VPN Manager ---------------------

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.

strongMan stored PKCS#8-encoded keys in a SQLite database, encrypted with AES. As you’ve probably guessed, it used pyaes to encrypt them in CTR mode, relying on the default IV. In PKCS#8 key files, RSA private keys include both the decryption exponent and the factors of the public modulus. For the same modulus size, the factors of the modulus will “line up” to start at the same place in the private key encodings about 99.6% of the time. For a pair of 2048-bit moduli, we can use the XOR of the factors to recover the factors in a matter of seconds.

Even worse, the full X.509 certificates were also encrypted using the same key/IV pair used to encrypt the private keys. Since certificates include a huge amount of predictable or easily guessable data, it’s easy to recover the keystream from the known X.509 data, and then use the recovered keystream to decrypt the private keys without resorting to any fancy XORed-factors mathematical trickery.

In short, if a hacker could recover a strongMan user’s SQLite file, they could immediately impersonate anyone whose certificates are stored in the database and even mount person-in-the-middle attacks. Obviously, this is not a great outcome.

We privately reported this issue to the strongSwan team. Tobias Brunner, the strongMan maintainer, provided an absolute model response to a security issue of this severity. He immediately created a security-fix branch and collaborated with Trail of Bits to develop stronger protection for his users. This patch has since been rolled out, and the update includes migration tools to help users update their old databases to the new format.

Doing it right --------------

There were several viable approaches to fixing this issue. Adding a unique IV for each encrypted entry in the database would have allowed strongMan to keep using pyaes, and would have addressed the immediate issue. But if the code has to be changed, it may as well be updated to something modern.

After some discussion, several changes were made to the application:

- pyaes was replaced with a library that supports modern cipher modes. - CTR mode was replaced with GCM-SIV, a cipher mode that includes authentication tags. - Tag-checking was integrated into the decryption routines. - A per-entry key derivation scheme is now used to ensure that key/IV pairs don’t repeat.

On top of all that, there are now migration scripts to allow strongMan users to seamlessly update their databases.

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. See the full original blog post for further details and some strong opinions omitted above.

For the strongMan issue, see: https://github.com/strongswan/strongMan/security/advisories/GHSA-88w4-jv97-c8xr

-- -Alan Coopersmith- alan.coopersmith () oracle com Oracle Solaris Engineering - https://blogs.oracle.com/solaris

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203