C#调用libsodium加密库

C#自带加密库在System.Security.Cryptography中,但是其自带的加密功能比较简单,只有一些基础的加密功能,一些高级加密方法如Aead加密,在最新版本中也只支持AesGcm96。

而基于C#的比较全面的第三方加密库如BouncyCastle.NET功能虽然比较全面,但是执行效率比较差,一般比用C语言实现的加密库要慢2-3倍。

基于C语言的libsodium是功能强大而且执行效率也很高的加密库,其内部API组织比较合理,使用起来非常简单,但是不支持C#直接调用,不过由于其使用的C函数封装,而且函数参数都是比较简单的原始数据类型,所以通过C#的Native Invoke,能比较方便的调用这些函数,只需要注意数据类型的转换和启用编译器的不安全代码(Unsafe)支持即可。

下面通过哈希计算和Aead加密,演示libsodium的调用方法。

Sha256哈希计算:

        [DllImport(dll, CallingConvention = CallingConvention.Cdecl)]
        static unsafe extern int crypto_hash_sha256
            (
            byte* dst,
            byte* src, long srcLen
            );

        public static unsafe void sha256(byte[] src, byte[] dst)
        {
            fixed (byte* srcPtr = src,
                dstPtr = dst)
            {
                crypto_hash_sha256
                    (
                    dstPtr,
                    srcPtr, src.Length
                    );
            }
        }

        public static unsafe byte[] sha256(byte[] src)
        {
            byte[] dst = new byte[32];
            sha256(src, dst);
            return dst;
        }

Argon2密码哈希:

        [DllImport(dll, CallingConvention = CallingConvention.Cdecl)]
        public static unsafe extern int crypto_pwhash_argon2id(
            byte* key, long keyLen,
            byte* pwd, long pwdLen,
            byte* salt,
            long cpu, int mem,
            int alg);

Aead加密模式的chacha20poly1305和gcm:

        [DllImport(Sodium.dll, CallingConvention = CallingConvention.Cdecl)]
        public static unsafe extern int
            crypto_aead_chacha20poly1305_ietf_encrypt(
            byte* cipher,
            out ulong cipherLen,
            byte* data,
            ulong dataLen,
            byte* aad,
            ulong aadLen,
            byte* nsec,
            byte* nonce,
            byte* key);

        [DllImport(Sodium.dll, CallingConvention = CallingConvention.Cdecl)]
        public static unsafe extern int
            crypto_aead_chacha20poly1305_ietf_decrypt(
            byte* data,
            out ulong dataLen,
            byte* nsec,
            byte* cipher,
            ulong cipherLen,
            byte* aad,
            ulong aadLen,
            byte* nonce,
            byte* key);

        [DllImport(Sodium.dll, CallingConvention = CallingConvention.Cdecl)]
        public static unsafe extern int
            crypto_aead_aes256gcm_encrypt(
            byte* cipher,
            out ulong cipherLen,
            byte* data,
            ulong dataLen,
            byte* aad,
            ulong aadLen,
            byte* nsec,
            byte* nonce,
            byte* key);

        [DllImport(Sodium.dll, CallingConvention = CallingConvention.Cdecl)]
        public static unsafe extern int
            crypto_aead_aes256gcm_decrypt(
            byte* data,
            out ulong dataLen,
            byte* nsec,
            byte* cipher,
            ulong cipherLen,
            byte* aad,
            ulong aadLen,
            byte* nonce,
            byte* key);

Argon2id类的封装:

    public class Argon2id : KeyGen
    {
        public Argon2id() => Sodium.checkLib();

        public const int SaltSize = 16;

        public byte[] salt;
        public long cpu = 32;
        public int mem = 64.mb();

        public override byte[] genKey(byte[] pwd, int keySize)
            => Sodium.argon2id(pwd, salt, cpu, mem, keySize);
    }

Aead模式的类的封装:

    public abstract class SodiumAeadCrypt : AeadCrypt
    {
        public SodiumAeadCrypt() => Sodium.checkLib();

        public override unsafe void encrypt(byte[] data, int dataOff, int dataLen,
                            byte[] nonce,
                            byte[] cipher, int cipherOff = 0,
                            byte[] aad = null)
        {
            fixed (byte* cipherPtr = cipher)
            fixed (byte* dataPtr = data)
            fixed (byte* noncePtr = nonce)
            fixed (byte* keyPtr = Key)
            fixed (byte* aadPtr = aad)
            {
                encFunc
                    (
                    cipherPtr + cipherOff, out var cipherLen,
                    dataPtr + dataOff, (ulong)dataLen,
                    aadPtr, (ulong)(aad?.Length ?? 0),
                    null,
                    noncePtr,
                    keyPtr
                    );
            }
        }

        public override unsafe bool decrypt(byte[] cipher, int cipherOff, int cipherLen,
                                    byte[] nonce,
                                    byte[] data, int dataOff = 0,
                                    byte[] aad = null)
        {
            fixed (byte* cipherPtr = cipher)
            fixed (byte* dataPtr = data)
            fixed (byte* noncePtr = nonce)
            fixed (byte* keyPtr = Key)
            fixed (byte* aadPtr = aad)
            {
                return decFunc
                    (
                    dataPtr + dataOff, out var dataLen,
                    null,
                    cipherPtr + cipherOff, (ulong)cipherLen,
                    aadPtr, (ulong)(aad?.Length ?? 0),
                    noncePtr,
                    keyPtr
                    ) == 0;
            }
        }

        protected abstract DecryptFunc decFunc { get; }
        protected abstract EncryptFunc encFunc { get; }

        protected unsafe delegate int EncryptFunc(
            byte* cipher,
            out ulong cipherLen,
            byte* data,
            ulong dataLen,
            byte* aad,
            ulong aadLen,
            byte* nsec,
            byte* nonce,
            byte* key);

        protected unsafe delegate int DecryptFunc(
            byte* data,
            out ulong dataLen,
            byte* nsec,
            byte* cipher,
            ulong cipherLen,
            byte* aad,
            ulong aadLen,
            byte* nonce,
            byte* key);
    }

其他libsodium的API都可以通过类似的方法进行调用。

 

Github:

https://github.com/bsmith-zhao/vfs/tree/main/util/crypt/sodium

posted @ 2023-10-16 10:01  bsmith  阅读(352)  评论(0)    收藏  举报