Here we see a number of open source projects that have a respectable amount of traffic.
What I did was go through these and try and find a few that had a good number of stars indicating usage- then from that list i checked WHERE they use this function. In some of these repositories our vulnerable encryption functions already appeared deprecated.
Then I'd check if I could even get the application running in a VM. Some of these ([Winsta11](github.com/NGame1/Winsta11) for example) refused to run, and that's kind of bare minimum for testing. Some of these were libraries that I could not find any evidence of use anywhere.
I settled on these two:
1. **hmailserver**
- hMailServer is an open source email server for Microsoft Windows.
- [existing DoS CVE](https://www.cve.org/CVERecord/SearchResults?query=hmailserver)
- github.com/hmailserver/hmailserver
2. **0sEngine**
- This is a full range of programs required to automate trading on the stock exchange.
- github.com/AlexWan/OsEngine
Let's dig in!
---
---
# The Function
Here's the problem code in question.
```cs
using System.IO;
using System.Text;
using System.Security.Cryptography;
public static class EncryptionHelper
{
public static string Encrypt(string clearText)
{
string EncryptionKey = "abc123";
byte[] clearBytes = Encoding.Unicode.GetBytes(clearText);
using (Aes encryptor = Aes.Create())
{
Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
encryptor.Key = pdb.GetBytes(32);
encryptor.IV = pdb.GetBytes(16);
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(clearBytes, 0, clearBytes.Length);
cs.Close();
}
clearText = Convert.ToBase64String(ms.ToArray());
}
}
return clearText;
}
public static string Decrypt(string cipherText)
{
string EncryptionKey = "abc123";
cipherText = cipherText.Replace(" ", "+");
byte[] cipherBytes = Convert.FromBase64String(cipherText);
using (Aes encryptor = Aes.Create())
{
Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
encryptor.Key = pdb.GetBytes(32);
encryptor.IV = pdb.GetBytes(16);
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(cipherBytes, 0, cipherBytes.Length);
cs.Close();
}
cipherText = Encoding.Unicode.GetString(ms.ToArray());
}
}
return cipherText;
}
}
```
To summarize, we take a hardcoded password (\* bonk \* no) and a hardcoded salt (\* bonk \* stoppit) and pass those through an RFC2898 PBKDF2 algorithm to derive a pseudorandom encryption key. This is then used as the key and IV of the AES object using the defaults. Both of those being now determinable pseudorandom values, decrypting any data using this function becomes a simple task.
---
---
# hMailServer
**(CVEs reserved: (CVE-2025-52372, CVE-2025-52373, CVE-2025-52374), developer contacted and has elected not to remediate. Project is deprecated.)**
There are a couple of issues here.
---
## Ivan Medvedev: CVE-2025-52374
Here we see the password taken in when creating a new server connection in the Admin GUI
```cpp
private void btnSave_Click(object sender, EventArgs e)
{
server.hostName = textHostname.Text;
server.userName = textUsername.Text;
server.savePassword = radioSavePassword.Checked;
if (textPassword.Dirty)
server.encryptedPassword = Encryption.Encrypt(textPassword.Password);
this.DialogResult = DialogResult.OK;
}
```
> line 44 in `hmailserver/source/Tools/Administrator/Dialogs/formServerInformation.cs`
using this function, it's encrypted.
```cs
private static string NOT_SECRET_KEY = "THIS_KEY_IS_NOT_SECRET";
public static string Encrypt(string plainText)
{
// Encryption operates on byte arrays, not on strings.
byte[] plainTextBytes =
System.Text.Encoding.Unicode.GetBytes(plainText);
// Derive a key from the password.
PasswordDeriveBytes passwordDerivedBytes = new PasswordDeriveBytes(NOT_SECRET_KEY,
new byte[] {0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76});
// Use Rijndael symmetric algorithm to do the encryption.
Rijndael rijndaelAlgorithm = Rijndael.Create();
rijndaelAlgorithm.Key = passwordDerivedBytes.GetBytes(32);
rijndaelAlgorithm.IV = passwordDerivedBytes.GetBytes(16);
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream, rijndaelAlgorithm.CreateEncryptor(), CryptoStreamMode.Write);
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.Close();
byte[] encryptedBytes = memoryStream.ToArray();
return Convert.ToBase64String(encryptedBytes);
}
```
> line 12 in `hmailserver/source/Tools/Administrator/Utilities/Encryption.cs`
when you save it runs a function to write to a file called `hMailAdmin.exe.config`
```cpp
public static void Save(UserSettings settings)
{
string settingsFile = Path.Combine(CreateSettingsFolder(), "hMailAdmin.exe.config");
XmlTextWriter writer = new XmlTextWriter(settingsFile, Encoding.UTF8);
try
{
writer.Formatting = Formatting.Indented;
XmlSerializer xmlSerializer = new XmlSerializer(typeof(UserSettings));
xmlSerializer.Serialize(writer, settings);
}
```
> line 65 `hmailserver/source/Tools/Administrator/Utilities/Settings/UserSettings.cs`
which creates a file at `%APPDATA%\hMailServer\Administrator\hMailAdmin.exe.config`
```xml
<Server>
<hostName>localhost</hostName>
<userName>Administrator</userName>
<encryptedPassword>1WWKZ+ZOBmor+9SYwo/fwg==</encryptedPassword>
<savePassword>true</savePassword>
</Server>
```
With entries like those above.
The hardcoded decryption function will decrypt that string in the `
And decrypting with the tool I wrote:
---
## Disclosure
I have reached out to the developer of this project, but have not received a response. Additionally I have not been able to uncover a process for disclosure with them. I will update this section if this changes.
---
---
# belskysGambit.py
https://github.com/mojibake-dev/belskysGambit
I wrote a little python script that does ONE thing for me. It decrypts (or encrypts) our Ivan encrypted strings.
All implementations of the copied functions use the same salt- that's a given. They all use the same defaults for AES in .NET regardless of the object used `AES` or `Rijndael`.
Where they differ is
- what algorithm they use for their PBKDF derived decryption key. Some use `PasswordDeriveBytes()` which uses the PBKDF1, algorithm, while some use `Rfc2989DeriveBytes()` which uses the PBKDF2 algorithm. Both slightly different implementations.
- what password is hardcoded in.
As such this script allows for selecting either algorithm, and takes the string for the password to be fed into the algo chosen.
Here's a disorganized list from my notes of some resources used to determine the functionality ported to python and the defaults.
- [Rfc2898DeriveBytes()](https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.rfc2898derivebytes?view=net-5.0)
- [GetBytes() method](https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.rfc2898derivebytes.getbytes?view=net-5.0)
- Repeated calls to this method will not generate the same key; instead, appending two calls of the [GetBytes](https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.rfc2898derivebytes.getbytes?view=net-5.0) method with a `cb` parameter value of `20` is the equivalent of calling the [GetBytes](https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.rfc2898derivebytes.getbytes?view=net-5.0) method once with a `cb` parameter value of `40`.
[AES Class](https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.aes?view=net-9.0)
- [Symmetric Encryption](https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.symmetricalgorithm)
- Padding [PKCS7](https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.symmetricalgorithm.padding?view=net-9.0#system-security-cryptography-symmetricalgorithm-padding)
[Memory Stream Class](https://learn.microsoft.com/en-us/dotnet/api/system.io.memorystream?view=net-9.0)
[CryptoStream Class](https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.cryptostream?view=net-9.0)
[PasswordDeriveBytes()](https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.passwordderivebytes)
[PasswordDeriveBytes.cs](https://github.com/dotnet/runtime/blob/1d1bf92fcf43aa6981804dc53c5174445069c9e4/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/PasswordDeriveBytes.cs)
---
---
# So Who Is Ivan???
I was going to publish this project under the name Ivan The Terribly Encrypted- but the friend who gave me the lead that led to this project advised I ask Ivan himself. It hadn't occurred to me that I could find THE Ivan Medvedev. I had sort of assumed maybe it was a reference to [Ivan Medvedev, Russian politician and energy economist](https://en.wikipedia.org/wiki/Ivan_Medvedev) or was some one off answer on Stack Over flow anonymous and lost to time. So i set off looking.
In order of discovery:
- [Twitter](https://x.com/pmelson/status/1303092463624769536?lang=ar-x-fm)
- [The Original Blog Post](https://www.codeproject.com/Articles/5719/Simple-encrypting-and-decrypting-data-in-C-)
- His blog in 2 iterations
- [IA snapshot Aug 5 2005](https://web.archive.org/web/20041207035908/http://blogs.dotnetthis.com/Ivan/)
- [IA snapshot Dec 16 2004](https://web.archive.org/web/20041216085309/http://blogs.dotnetthis.com/Ivan/)
- [Stack Overflow](https://stackoverflow.com/questions/14658131/exe-comperession-for-the-net-app-algorithm-shows-strange-chars-with-the-real)
- [LinkedIn](https://www.linkedin.com/in/ivanmed/)
This led me to a picture of him, finally to his LinkedIn and even more strange is he lives in the same state as me!!
I've since reached out to him and asked if he'd be down to get coffee and chat and it seems like there's a good chance it will happen!
Other Articles In This Series