Last active
March 2, 2021 19:44
-
-
Save fosterbuster/56e1b0e45af01a6dc3c850634fdbad28 to your computer and use it in GitHub Desktop.
Kamstrup kem file decryptor for .NET
This file contains 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); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment