C# symmetric encryption to rust

Hi,
I have this following code in c#

public static string EncryptDataUsingCertificate(string subjectName, string content)
{
// Initialize the result
string result = null;

        X509Certificate2 certificate = GetCertificate(subjectName);
        if (certificate != null)
        {
            using (SymmetricEncryption symmetricEncryption = new SymmetricEncryption(EncryptionType.DES))
            {
                symmetricEncryption.InitialIv = certificate.GetPublicKeyString();

                result = symmetricEncryption.Encrypt(content, certificate.GetPublicKeyString());
            }
        }

        return result;
    }

I need to convert this to rust. What steps i need to do convert this?

Thanks in advance

Hey there,

Unlike C#, Rust has a fairly small standard library, so you'll find a lot of thing that are included with the compiler in C# that aren't included with Rust's. Cryptography is one area, and there are several others (Rust doesn't have any officially-blessed UI systems, while C# has three, as one example).

You'll need to find a library you like for working with the certificates involved here.

From some cursory research, it looks like if you're using this for ssl, openssl is the go-to, but there are other options. You may want to check out the cryptography category for other crates.

In general, google searches aren't bad but the most common repositories for libraries (we call them 'crates', here) are the official one at crates.io and the most popular alternative, lib.rs

Welcome to the forum!

I think the first step should be figuring out exactly what this C# code does. If/when you can figure that out in full detail, translating to rust will be a lot easier.

Here's what I can interpret, with some initial research:

// Retrieves some certificate from the system store. I have no idea what
// "subjectName" here means, so unless you've got an idea, I can't really
// be of help.
X509Certificate2 certificate = GetCertificate(subjectName);
if (certificate != null)
{
    // Encrypts using DES encryption, I assume
    using (SymmetricEncryption symmetricEncryption = new SymmetricEncryption(EncryptionType.DES))
    {
        // Uses the certificates _public key_ as the encrypt key! If I'm
        // interpeting this correctly, it surprises me. I would never
        // recommend doing this.
        // The documentation states "Returns the public key for the
        // X.509v3 certificate as a hexadecimal string.", so we probably
        // need to keep that in mind.
        // The other troubling part is "InitialIv". I have no idea what this
        // means - I assume it's some kind of initial state for the DES
        // algorithm?
        symmetricEncryption.InitialIv = certificate.GetPublicKeyString();
        // For some reason, it passes in the public key string again. I've got
        // no idea what kind of API requires it twice - is it using it for the
        // same purpose twice, or for two different things? Any idea?
        result = symmetricEncryption.Encrypt(content, certificate.GetPublicKeyString());
    }
}

return result;

So, we're retrieving an X509 certificate from somewhere mysterious, grabbing its public key and using that key as an initial state in a DES cipher.

To do this in rust, you'll probably want to use two separate crates - one for retrieving the X509 certificate and grabbing its public key, and another separate crate for doing the DES symmetric encryption.

Some caveats:

  • I don't understand at all what your C# function "GetCertificate" does, so I can't really help there. I can help duplicate the behavior if you know exactly what you want, but the code gives me no idea.
  • This looks like a really insecure way of encrypting data. You're using a DES cipher, and while it used to be good, for modern day cryptography, it really isn't. In addition, you're using a certificate's public key as your private encryption key, which seems really wrong, unless there's something I'm missing. If you have a particular reason for doing this, I'd love to know!
  • Matching the exact C# behavior is going to be much harder than just writing code to encrypt data in Rust. If you need to get this exact behavior matched, then by all means, proceed - but know that it'll be much harder than writing equivalent (but differently behaving) code in Rust.

Now there's one part I think I can actually help with. The des crate is well-maintained, and exports a des::Des struct to perform DES encryption. There are... some more caveats though - mainly, it only supports encrypting 8-byte chunks of data, and the key is limited to 8 bytes as well.

And that brings me to the last question: I could not find SymmetricEncryption anywhere in .NET documentation, and thus I couldn't find exactly what it does with keys that are too long. From wikipedia, it looks like DES only takes in 56-bit keys, but your code is passing in an arbitrarily large key into SymmetricEncryption. What does it do with those extra bits? We'll need to know in order to duplicate that behavior in Rust.

Thank you for the detailed reply. Sorry for the blunt question. The certificate is stored in the windows certificate store. I can export and get the public key in a file and use it as a IV and KEY.

Regarding the encryption here is the sample i want to convert

https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.descryptoserviceprovider.createencryptor?view=netframework-4.8

The code what i have given does the same job.

So i want to use the public key of the certificate as IV and KEY. I would like to use first 8 bytes as key and iv since for des the key and iv length is 8.

Can you help me in achieving the same result in rust.

here is the sample fiddle in .net
https://dotnetfiddle.net/5i95oJ

I tried this in rust

#[macro_use] extern crate magic_crypt;

use magic_crypt::{MagicCrypt};

fn main() {

    let mut mc: MagicCrypt = new_magic_crypt!("12345678", 64, "12345678");
    let base64 = mc.encrypt_str_to_base64("Balu");
    println!("{}", base64);
}

But both does not give the same result.

Can you help me in fixing the rust code

I was able to find a solution to my problem.

use block_modes::block_padding::Pkcs7;
use block_modes::{BlockMode, Cbc};
use des::Des;

type DesCbc = Cbc<Des, Pkcs7>;

macro_rules! get_des_cipher_space {
    ($len:expr) => {{
        (($len + 8) / 8) * 8 + ($len % 8)
    }};
}

fn main() {

    let key =  b"12345678";
    let iv = b"12345678";
    let data = b"Balu";
    let len = data.len();
    let final_len = get_des_cipher_space!(len);
    let mut buffer = Vec::with_capacity(final_len);
    unsafe {
        buffer.set_len(final_len);
    }
    buffer[..len].copy_from_slice(data);
    
    let cipher = DesCbc::new_var(key, iv).unwrap();
    let enc = base64::encode(&cipher.encrypt_vec(&buffer[..len]));
    println!("{:?}", enc);
}
1 Like