obsidian-encrypt
obsidian-encrypt copied to clipboard
Is it possible to port this to C#?
Hey there,
I'm using a C# service that's generating documentation regarding certain services - in an obsidian format.
So my goal is to allow my C# service to embed encrypted secrets by the format of this meld-encrypt plugin.
I was trying to make an attempt to convert it:
using System.Security.Cryptography;
using System.Text;
public class CryptoHelper2304(int vectorSize, int saltSize, int iterations)
{
private async Task<byte[]> DeriveKey(string password, byte[] salt)
{
using var rfc2898 = new Rfc2898DeriveBytes(password, salt, iterations, HashAlgorithmName.SHA512);
return rfc2898.GetBytes(256 / 8); // 256 bits key size
}
private async Task<byte[]> EncryptToBytes(string text, string password)
{
var salt = new byte[saltSize];
using (var rng = new RNGCryptoServiceProvider())
{
rng.GetBytes(salt);
}
var key = await DeriveKey(password, salt);
var iv = new byte[vectorSize];
using (var rng = new RNGCryptoServiceProvider())
{
rng.GetBytes(iv);
}
using var aesGcm = new AesGcm(key);
var textBytes = Encoding.UTF8.GetBytes(text);
var cipherText = new byte[textBytes.Length];
var tag = new byte[16]; // AES-GCM tag size is 128 bits (16 bytes)
aesGcm.Encrypt(iv, textBytes, cipherText, tag);
var finalBytes = new byte[iv.Length + salt.Length + cipherText.Length];
Buffer.BlockCopy(iv, 0, finalBytes, 0, iv.Length);
Buffer.BlockCopy(salt, 0, finalBytes, iv.Length, salt.Length);
Buffer.BlockCopy(cipherText, 0, finalBytes, iv.Length + salt.Length, cipherText.Length);
return finalBytes;
}
private string ConvertToString(byte[] bytes)
{
return Encoding.UTF8.GetString(bytes);
}
public async Task<string> EncryptToBase64(string text, string password)
{
var finalBytes = await EncryptToBytes(text, password);
return Convert.ToBase64String(finalBytes);
}
private async Task<string> DecryptFromBytes(byte[] encryptedBytes, string password)
{
var iv = new byte[vectorSize];
Buffer.BlockCopy(encryptedBytes, 0, iv, 0, vectorSize);
var salt = new byte[saltSize];
Buffer.BlockCopy(encryptedBytes, vectorSize, salt, 0, saltSize);
var cipherText = new byte[encryptedBytes.Length - vectorSize - saltSize];
Buffer.BlockCopy(encryptedBytes, vectorSize + saltSize, cipherText, 0, encryptedBytes.Length - vectorSize - saltSize);
var key = await DeriveKey(password, salt);
using var aesGcm = new AesGcm(key);
var tag = new byte[16]; // AES-GCM tag size is 128 bits (16 bytes)
var decryptedBytes = new byte[cipherText.Length];
aesGcm.Decrypt(iv, cipherText, tag, decryptedBytes);
return Encoding.UTF8.GetString(decryptedBytes);
}
public async Task<string> DecryptFromBase64(string base64Encoded, string password)
{
var bytesToDecode = Convert.FromBase64String(base64Encoded);
return await DecryptFromBytes(bytesToDecode, password);
}
}
Which now lets me encrypt and decrypt I think, using the same ES-GCM as the CryptoHelper2304.ts - however my encryption seems to be different from the typescript implementation, and I can't decrypt anything encrypted with this plugin, or visa versa, add my encrypted text into Obsidian and have it decrypt it.
Another strange thing that I found was that you're invoking the service with new CryptoHelper2304( 16, 16, 210000 );
However, debugging my own code, I eventually get into
- Namespace System.Security.Cryptography
- class AesGcm
- Method CheckParameters
I get into this method:
if (!nonce.Length.IsLegalSize(NonceByteSizes))
{
throw new ArgumentException(System.SR.Cryptography_InvalidNonceLength, "nonce");
}
And unless the nonce size is 12, AesGcm rejects the input and throws that exception. So I also can't really even create a new CryptoHelper2304
with a vector size of 16.
Has anyone tried anything similar, or has any idea how to fix this, and make a c# function that's compatible with the function in this library? Thanks
I haven't tried js <=> c#. But it is interesting to know if it's possible.
I'm not sure if it helps, but I came across this: https://github.com/smartinmedia/Net-Core-JS-Encryption-Decryption
and
https://pilabor.com/series/dotnet/js-gcm-encrypt-dotnet-decrypt/
I tried the first one: https://github.com/smartinmedia/Net-Core-JS-Encryption-Decryption
But it works a little different. For example, when I try to encrypt something, the resulting string becomes:
{"DerivationType":"scrypt","Salt":"51b919a3a2d45b68817a4f8ff61426706f34ab2f94235f41f7a75167ebaba9ff","Cost":16384,"BlockSize":16,"Parallel":1,"KeySizeInBytes":16,"DerivationIterations":210000,"AesRijndaelIv":"z2kdcROxxV9EvGfWV6Jc8A==","CipherOutputText":"Fm7ycLD6oeLEZQlD7D44epoCfUHQI1MWs+z0zO3RXx4="}
So it creates a json with metadata. It looks like your plugin appends all the metadata to the string itself, and then slices it during decrypt, right?
I tried to recreate that in C#, but so far I don't really know which value goes where, and what parameters to use, haha. So it's a bit of a trial and error process now
I was able to port V0 to C#: https://github.com/RonSijm/RonSijm.ObsidianEncrypt/blob/main/src/RonSijm.ObsidianEncrypt/V0/ObsidianEncryptV0.cs
I was trying to get V2 to work: https://github.com/RonSijm/RonSijm.ObsidianEncrypt/blob/main/src/RonSijm.ObsidianEncrypt/V2/ObsidianEncryptV2.cs
But I can't seem to get it to work.
The PREFIX_OBSOLETE
in typescript does not have a "Visible" mode, so it's a bit annoying to use.
Would you be willing to implement a PREFIX_OBSOLETE_VISIBLE? Or do you intend to remove the obsolete version at some point?