Created
December 21, 2021 20:29
-
-
Save QuiltMeow/dffb81ae77f3c0e4880ee710384bc5f9 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.IO; | |
| using System.Security.Cryptography; | |
| using System.Text; | |
| namespace Cryptography | |
| { | |
| public struct RSAKeyPairString | |
| { | |
| public string publicKey; // 公鑰 | |
| public string privateKey; // 金鑰組 (公鑰 + 私鑰) | |
| public void saveKeyPair(string publicKeyPath, string privateKeyPath) | |
| { | |
| File.WriteAllText(publicKeyPath, publicKey); | |
| File.WriteAllText(privateKeyPath, privateKey); | |
| } | |
| } | |
| // 一般而言不太會使用這種方法 除非你要拿來加密別人硬碟 然後跟他要一些錢錢之類的 w | |
| public sealed class RSALargeData : IDisposable | |
| { | |
| public const int ITERATION = 1500; | |
| public static readonly byte[] SALT = new byte[] // TO DO : (Legacy) Change This | |
| { | |
| 0x41, 0x6B, 0x61, 0x74, 0x73, 0x75, | |
| 0x6B, 0x69, 0x4A, 0x69, 0x61, 0x49, | |
| 0x73, 0x56, 0x65, 0x72, 0x79, 0x43, | |
| 0x75, 0x74, 0x65 | |
| }; | |
| public int blockSize | |
| { | |
| get; | |
| private set; | |
| } | |
| public int encryptOutputSize | |
| { | |
| get; | |
| private set; | |
| } | |
| public byte[] iv // RSA CBC 模式 | |
| { | |
| get; | |
| private set; | |
| } | |
| public RSACryptoServiceProvider rsa | |
| { | |
| get; | |
| private set; | |
| } | |
| public RSALargeData(string xmlKey) // 可傳入公鑰或金鑰組 | |
| { | |
| initRSA(xmlKey); | |
| } | |
| public RSALargeData(Stream xmlKey) | |
| { | |
| using (StreamReader sr = new StreamReader(xmlKey)) | |
| { | |
| initRSA(sr.ReadToEnd()); | |
| } | |
| } | |
| private void initRSA(string xmlKey) | |
| { | |
| rsa = new RSACryptoServiceProvider(); | |
| rsa.FromXmlString(xmlKey); | |
| blockSize = (rsa.KeySize - 384) / 8 + 6; | |
| encryptOutputSize = rsa.ExportParameters(false).Modulus.Length; | |
| Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(rsa.ExportCspBlob(false), SALT, ITERATION); | |
| iv = rfc2898.GetBytes(blockSize); | |
| } | |
| public void Dispose() | |
| { | |
| rsa.PersistKeyInCsp = false; | |
| rsa.Clear(); | |
| rsa.Dispose(); | |
| } | |
| public static RSAKeyPairString generateKeyPair(int length = 4096) | |
| { | |
| using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(length)) | |
| { | |
| string publicKey = rsa.ToXmlString(false); | |
| string privateKey = rsa.ToXmlString(true); | |
| rsa.PersistKeyInCsp = false; | |
| rsa.Clear(); | |
| return new RSAKeyPairString() | |
| { | |
| publicKey = publicKey, | |
| privateKey = privateKey | |
| }; | |
| } | |
| } | |
| public void encrypt(Stream input, Stream output) // 僅公鑰即可加密 | |
| { | |
| byte[] currentIV = (byte[])iv.Clone(); | |
| byte[] buffer = new byte[blockSize]; | |
| int readByte; | |
| while ((readByte = input.Read(buffer, 0, blockSize)) > 0) | |
| { | |
| byte[] data = new byte[readByte]; | |
| Buffer.BlockCopy(buffer, 0, data, 0, readByte); | |
| for (int i = 0; i < readByte; ++i) | |
| { | |
| data[i] ^= currentIV[i]; | |
| } | |
| byte[] encryptBlock = rsa.Encrypt(data, true); | |
| output.Write(encryptBlock, 0, encryptBlock.Length); | |
| for (int i = 0; i < blockSize; ++i) // IV 更新 : 多餘部分捨棄 | |
| { | |
| currentIV[i] = encryptBlock[i]; | |
| } | |
| } | |
| } | |
| public void decrypt(Stream input, Stream output) // 需要金鑰組才可進行解密 (解密消耗時間較長 請考慮多執行緒) | |
| { | |
| byte[] currentIV = (byte[])iv.Clone(); | |
| byte[] buffer = new byte[encryptOutputSize]; | |
| int readByte; | |
| while ((readByte = input.Read(buffer, 0, encryptOutputSize)) > 0) | |
| { | |
| if (readByte != encryptOutputSize) | |
| { | |
| throw new Exception($"無效的密文長度 : {readByte} 預期 : {encryptOutputSize}"); | |
| } | |
| byte[] decryptBlock = rsa.Decrypt(buffer, true); | |
| int decryptLength = decryptBlock.Length; | |
| for (int i = 0; i < decryptLength; ++i) | |
| { | |
| decryptBlock[i] ^= currentIV[i]; | |
| } | |
| output.Write(decryptBlock, 0, decryptLength); | |
| for (int i = 0; i < blockSize; ++i) | |
| { | |
| currentIV[i] = buffer[i]; | |
| } | |
| } | |
| } | |
| public byte[] encryptString(string input, Encoding encode) | |
| { | |
| return encryptByteArray(encode.GetBytes(input)); | |
| } | |
| public string decryptString(byte[] input, Encoding encode) | |
| { | |
| return encode.GetString(decryptByteArray(input)); | |
| } | |
| public byte[] encryptByteArray(byte[] data) | |
| { | |
| using (Stream input = new MemoryStream(data)) | |
| using (MemoryStream output = new MemoryStream()) | |
| { | |
| encrypt(input, output); | |
| return output.ToArray(); | |
| } | |
| } | |
| public byte[] decryptByteArray(byte[] data) | |
| { | |
| using (Stream input = new MemoryStream(data)) | |
| using (MemoryStream output = new MemoryStream()) | |
| { | |
| decrypt(input, output); | |
| return output.ToArray(); | |
| } | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment