4
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

OpenSSL で暗号化したデータを C# で復号する

Last updated at Posted at 2019-08-31

OpenSSL で暗号化したデータを C# で復号する

2006年頭に Java で書いて、2012年7月に DESede から AES に書き直したコードの C# 移植.
-md md5 だと

*** WARNING : deprecated key derivation used.
Using -iter or -pbkdf2 would be better.

と怒られるようになったので、-pbkdf2 に変更.
デフォルトではハッシュアルゴリズムは sha256, イテレーション回数は 10000 のようだ(OpenSSL 1.1.1c 現在).
暗号化も AES-128-CBC から AES-256-CBC に変更してみた. (AES-128 に問題はないけど)

$ echo -n 'test' | openssl enc -e -a -pbkdf2 -aes-256-cbc -pass pass:passw0rd
U2FsdGVkX1+wtVTcahFqx0V/PigNukzjVdMyDRMGBhI=

この base64 化された暗号文を、C# 側で平文化できるのを確認した.
同様に C# 側で作成した base64 化された暗号文を、OpenSSL 側で平文化できるのを確認した.

$ echo 'U2FsdGVkX1+ymkCPB8EdLXrTUPQcL8q1q0f8YEryZ/Y=' | openssl enc -d -a -pbkdf2 -aes-256-cbc -pass pass:passw0rd
test

Rfc2898DeriveBytes のコンストラクタの引数に HashAlgorithmName のオプションが増えたのは .NET Framework 4.7.2 / .NET Core 2.0 以降で、以下のコードは .NET Standard 2.0 ではビルドできない. (追記: .NET Standard 2.1 でビルドできるようになった)

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;

namespace ConsoleApp1
{
    class Program
    {
        static byte[] GenerateSalt(int saltLength)
        {
            var result = new byte[saltLength];
            using (var csp = new RNGCryptoServiceProvider())
            {
                csp.GetBytes(result);
                return result;
            }
        }

        static byte[] GenerateKIV(byte[] salt, string password, HashAlgorithmName hashAlgorithm, int iterationCount, int size)
        {
            return new Rfc2898DeriveBytes(Encoding.UTF8.GetBytes(password), salt, iterationCount, hashAlgorithm)
                .GetBytes(size);
        }

        public static string Encrypt(byte[] plainBytes, string password)
        {
            var salt = GenerateSalt(8);
            var kiv = GenerateKIV(salt, password, HashAlgorithmName.SHA256, 10000, 48).ToList();
            using (var csp = new AesManaged())
            {
                csp.KeySize = 256;
                csp.BlockSize = 128;
                csp.Mode = CipherMode.CBC;
                csp.Padding = PaddingMode.PKCS7;
                csp.Key = kiv.GetRange(0, 32).ToArray();
                csp.IV = kiv.GetRange(32, 16).ToArray();
                using (var encryptor = csp.CreateEncryptor())
                using (var mstream = new MemoryStream())
                {
                    mstream.Write(Encoding.UTF8.GetBytes("Salted__"), 0, 8);
                    mstream.Write(salt, 0, 8);
                    using (var cstream = new CryptoStream(mstream, encryptor, CryptoStreamMode.Write))
                    {
                        cstream.Write(plainBytes, 0, plainBytes.Length);
                    }
                    return Convert.ToBase64String(mstream.ToArray());
                }
            }
        }

        public static byte[] Decrypt(string encryptedString, string password)
        {
            var encryptedBytes = Convert.FromBase64String(encryptedString);
            var salt = encryptedBytes.Skip(8).Take(8).ToArray();
            var kiv = GenerateKIV(salt, password, HashAlgorithmName.SHA256, 10000, 48).ToList();
            using (var csp = new AesManaged())
            {
                csp.KeySize = 256;
                csp.BlockSize = 128;
                csp.Mode = CipherMode.CBC;
                csp.Padding = PaddingMode.PKCS7;
                csp.Key = kiv.GetRange(0, 32).ToArray();
                csp.IV = kiv.GetRange(32, 16).ToArray();
                using (var decryptor = csp.CreateDecryptor())
                using (var mstream1 = new MemoryStream(encryptedBytes.Skip(16).ToArray()))
                using (var cstream = new CryptoStream(mstream1, decryptor, CryptoStreamMode.Read))
                using (var mstream2 = new MemoryStream())
                {
                    cstream.CopyTo(mstream2);
                    return mstream2.ToArray();
                }
            }
        }

        static void Main(string[] args)
        {
            //Console.WriteLine(Encrypt(Encoding.UTF8.GetBytes("test"), "passw0rd"));
            Console.WriteLine(Encoding.UTF8.GetString(Decrypt("U2FsdGVkX1+wtVTcahFqx0V/PigNukzjVdMyDRMGBhI=", "passw0rd")));
            Console.Read();
        }
    }
}
4
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?