Last active
April 24, 2026 16:49
-
-
Save poulerik-dk/56e1b0e45af01a6dc3c850634fdbad28 to your computer and use it in GitHub Desktop.
Kamstrup kem file decryptor for .NET
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| namespace kemdecrypt | |
| { | |
| using System; | |
| using System.IO.Compression; | |
| using System.Linq; | |
| using System.Text; | |
| using System.Threading; | |
| using System.Threading.Tasks; | |
| using System.Xml.Linq; | |
| using McMaster.Extensions.CommandLineUtils; | |
| public class Program | |
| { | |
| public static Task<int> Main(string[] args) | |
| { | |
| return CommandLineApplication.ExecuteAsync<Program>(args); | |
| } | |
| [Option(Description = "File is zipped.", Inherited = false, LongName = "zip", ShortName = "z", ShowInHelpText = true)] | |
| public bool IsZipped { get; } | |
| [Option(Description = "Password for decrypting the kem file.", Inherited = false, LongName = "password", ShortName = "pass", ShowInHelpText = true)] | |
| public string Password { get; private set; } | |
| [Option(Description = "The path of the file.", Inherited = false, LongName = "path", ShortName = "p", ShowInHelpText = true)] | |
| public string Path { get; } | |
| private async Task<int> OnExecuteAsync(CommandLineApplication app) | |
| { | |
| if (string.IsNullOrEmpty(Path)) | |
| { | |
| app.ShowHelp(); | |
| return 0; | |
| } | |
| byte[] encrypted; | |
| // TODO check if it actually is a zip file, and so on. | |
| if (IsZipped) | |
| { | |
| XElement element = await XElement | |
| .LoadAsync( | |
| ZipFile.OpenRead(Path).Entries.First( x=> x.Name.EndsWith(".kem")) | |
| .Open(), | |
| LoadOptions.None, | |
| new CancellationToken()) ; | |
| encrypted = Convert.FromBase64String(element.Value); | |
| } | |
| else | |
| { | |
| encrypted = Convert.FromBase64String(XElement.Load(Path).Value); | |
| } | |
| if (string.IsNullOrEmpty(Password)) | |
| { | |
| Console.WriteLine("No password provided. Please input password now."); | |
| Password = Prompt.GetPassword("Password: "); | |
| } | |
| var decryptor = new AesDecryptor(Encoding.UTF8.GetBytes(Password)); | |
| var decrypted = decryptor.Decrypt(encrypted); | |
| // Kamstrup seems to pad the file with \b - We trim it away, since it is invalid xml. | |
| var decoded = Encoding.UTF8.GetString(decrypted); | |
| var parsed = decoded.Substring(0, decoded.LastIndexOf(">") + 1); | |
| Console.WriteLine(XElement.Parse(parsed)); | |
| return 0; | |
| } | |
| } | |
| } | |
| namespace kemdecrypt | |
| { | |
| using System; | |
| using System.Security.Cryptography; | |
| public class AesDecryptor | |
| { | |
| private readonly byte[] _decryptionKey; | |
| public AesDecryptor(byte[] decryptionKey) | |
| { | |
| if (decryptionKey == null) | |
| { | |
| throw new ArgumentNullException(nameof(decryptionKey)); | |
| } | |
| // Password can be less than 16 bytes, so we pad some extra 0's to the end of the key to ensure it has the correct length. | |
| _decryptionKey = new byte[16]; | |
| Buffer.BlockCopy(decryptionKey, 0, _decryptionKey, 0, decryptionKey.Length); | |
| } | |
| public byte[] Decrypt(byte[] payload) | |
| { | |
| using (var algorithm = new AesCryptoServiceProvider | |
| { | |
| Padding = PaddingMode.None, | |
| Mode = CipherMode.CBC, | |
| IV = _decryptionKey, // initialization vector is the same as the key. | |
| Key = _decryptionKey | |
| }) | |
| { | |
| return algorithm.CreateDecryptor().TransformFinalBlock(payload, 0, payload.Length); | |
| } | |
| } | |
| } | |
| } |
a59010b4ee7c8333eafdbe572d12f28b041258f51690d66d3a2cdc2e47a1ac513950a1a8b614fa1784b6558faf2b892eef86a7bf9f57b40329f85a17494d4994
a59010b4ee7c8333eafdbe572d12f28b041258f51690d66d3a2cdc2e47a1ac513950a1a8b614fa1784b6558faf2b892eef86a7bf9f57b40329f85a17494d4994
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
pp3DE2u7hf5P4GbxdpLbElVtwUGfav1wQTjfMlGZ