[C#] 字串加密後寫入圖片

URL Link //n.sfs.tw/15830

2022-05-11 17:23:43 By 大塚 宏

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Windows.Forms;

namespace AES_2
{
    public partial class Form5 : Form
    {
        public Form5()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            textBox2.Text = EncryptString(textBox1.Text, textBox3.Text);

            string file = "";
            OpenFileDialog dialog = new OpenFileDialog();
            dialog.Multiselect = false; //該值確定是否可以選擇多個檔案
            dialog.Title = "請選擇圖片";
            dialog.Filter = "圖片檔案(*.bmp)|*.bmp;*.jpg";
            if (dialog.ShowDialog() == DialogResult.OK)
            {
                file = dialog.FileName;
                textBox4.Text = file;
            }
            else
            {
                return;
            }

            Bitmap enBit = new Bitmap(file);
            enBit = MixStringIntoImage(textBox2.Text, enBit);

            SaveFileDialog saveFileDialog1 = new SaveFileDialog();
            saveFileDialog1.Title = "另存圖片";
            saveFileDialog1.Filter = "圖片檔案(*.bmp)|*.bmp;*.jpg";
            if (saveFileDialog1.ShowDialog() == DialogResult.OK)
            {
                PictureBox PB1 = new PictureBox();
                PB1.Image = enBit;
                try
                {
                    PB1.Image.Save(saveFileDialog1.FileName, System.Drawing.Imaging.ImageFormat.Bmp);
                }
                catch {
                    MessageBox.Show("發生錯誤,請重啟程式");
                    Application.Restart(); 
                }                

                pictureBox1.Image = enBit;
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            string file = "";
            OpenFileDialog dialog = new OpenFileDialog();
            dialog.Multiselect = false; //該值確定是否可以選擇多個檔案
            dialog.Title = "請選擇圖片";
            dialog.Filter = "圖片檔案(*.bmp)|*.bmp;*.jpg";
            if (dialog.ShowDialog() == DialogResult.OK)
            {
                file = dialog.FileName;
                textBox4.Text = file;
            }
            else
            {
                return;
            }

            Bitmap enBit = new Bitmap(file);
            pictureBox1.Image = enBit;

            try
            {
                textBox2.Text = GetStringFromMixedImage(enBit);
                textBox1.Text = DecryptString(textBox2.Text, textBox3.Text);
            }
            catch(Exception ex) {
                MessageBox.Show(ex.Message);
            }            
        }

        public static string EncryptString(string message, string key)
        {
            key = Get_SHA256_Hash(key).Substring(0, 32);
            var keyBytes = Encoding.UTF8.GetBytes(key);
            var aes = new AesCryptoServiceProvider();
            aes.GenerateIV();
            var iv = aes.IV;
            using (var memStream = new System.IO.MemoryStream())
            {
                memStream.Write(iv, 0, iv.Length);  // Add the IV to the first 16 bytes of the encrypted value
                using (var cryptStream = new CryptoStream(memStream, aes.CreateEncryptor(keyBytes, aes.IV), CryptoStreamMode.Write))
                {
                    using (var writer = new System.IO.StreamWriter(cryptStream))
                    {
                        writer.Write(message);
                    }
                }
                var buf = memStream.ToArray();
                return Convert.ToBase64String(buf);
            }
        }

        public static string DecryptString(string encryptedValue, string key)
        {
            key = Get_SHA256_Hash(key).Substring(0, 32);
            var bytes = Convert.FromBase64String(encryptedValue);
            var keyBytes = Encoding.UTF8.GetBytes(key);
            var aes = new AesCryptoServiceProvider();
            using (var memStream = new System.IO.MemoryStream(bytes))
            {
                var iv = new byte[16];
                memStream.Read(iv, 0, 16);  // Pull the IV from the first 16 bytes of the encrypted value
                using (var cryptStream = new CryptoStream(memStream, aes.CreateDecryptor(keyBytes, iv), CryptoStreamMode.Read))
                {
                    using (var reader = new System.IO.StreamReader(cryptStream))
                    {
                        return reader.ReadToEnd();
                    }
                }
            }
        }

        public static string Get_SHA256_Hash(string str)
        {
            byte[] sha256Bytes = Encoding.UTF8.GetBytes(str);
            SHA256Managed sha256 = new SHA256Managed();
            byte[] bytes = sha256.ComputeHash(sha256Bytes);
            return BitConverter.ToString(bytes).Replace("-", "").ToUpper();
        }

        public Bitmap MixStringIntoImage(string s, Bitmap img)
        {
            int i, x, y;
            i = 0;
            x = 0;
            y = 0;

            while (i <= s.Length)
            {
                Color pixelColor = img.GetPixel(x, y);

                if (i == 0) //紀錄暗文字數
                {
                    int num = s.Length;
                    int sR, sG, sB;
                    sB = num % 256;
                    num /= 256;
                    sG = num % 256;
                    num /= 256;
                    sR = num % 256;

                    pixelColor = Color.FromArgb(sR, sG, sB);
                }
                else
                {
                    pixelColor = Color.FromArgb(pixelColor.R, pixelColor.G, (int)s[i - 1]); //將暗文寫入該像素的藍色(B)
                }
                img.SetPixel(x, y, pixelColor);
                i++;
                x++;
                if (x == img.Width)
                {
                    x = 0;
                    y++;
                    if (y == img.Height) throw new Exception("String is too long for this image!!!");
                }
            }
            return img;
        }

        public string GetStringFromMixedImage(Bitmap img)
        {
            string s = "";
            int i, x, y;
            int stringLength = 1;
            i = 0;
            x = 0;
            y = 0;
            while (i <= stringLength)
            {
                if (i == 0) //獲得暗文字數
                {
                    int sR, sG, sB;
                    sR = img.GetPixel(0, 0).R;
                    sG = img.GetPixel(0, 0).G;
                    sB = img.GetPixel(0, 0).B;

                    stringLength = sR * Convert.ToInt32(Math.Pow(256, 2)) + sG * 256 + sB;
                }
                else
                {
                    s = s + (char)(img.GetPixel(x, y).B); //該像素的藍色(B) = 暗文
                }

                i++;
                x++;
                if (x == img.Width)
                {
                    x = 0;
                    y++;
                    if (y == img.Height) throw new Exception("String is too long for this image!!!");
                }
            }
            return s;
        }
    }
}