diff --git a/HIR-Activate.sln b/HIR-Activate.sln new file mode 100644 index 0000000..06cc5fc --- /dev/null +++ b/HIR-Activate.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.12.35514.174 d17.12 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HIR-Activate", "HIR-Activate\HIR-Activate.csproj", "{01A02918-32D7-4EFF-8F04-4E1A80DBD646}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {01A02918-32D7-4EFF-8F04-4E1A80DBD646}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {01A02918-32D7-4EFF-8F04-4E1A80DBD646}.Debug|Any CPU.Build.0 = Debug|Any CPU + {01A02918-32D7-4EFF-8F04-4E1A80DBD646}.Release|Any CPU.ActiveCfg = Release|Any CPU + {01A02918-32D7-4EFF-8F04-4E1A80DBD646}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/HIR-Activate/Encryption/AesEncryption.cs b/HIR-Activate/Encryption/AesEncryption.cs new file mode 100644 index 0000000..ed71d8b --- /dev/null +++ b/HIR-Activate/Encryption/AesEncryption.cs @@ -0,0 +1,153 @@ +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Engines; +using Org.BouncyCastle.Crypto.Modes; +using Org.BouncyCastle.Crypto.Paddings; +using Org.BouncyCastle.Crypto.Parameters; +using System; +using System.Security.Cryptography; +using System.Text; + +namespace IRaCIS.Core.Infrastructure.Encryption; + +public class AesEncryption +{ + // AES 加密(不带 IV) + public static string Encrypt(string plainText, string key) + { + var keyBytes = Encoding.UTF8.GetBytes(key); + + // 使用 AES 引擎 + PKCS7 填充 + var engine = new AesEngine(); + var blockCipher = new PaddedBufferedBlockCipher(engine, new Pkcs7Padding()); + blockCipher.Init(true, new KeyParameter(keyBytes)); // true 表示加密 + + var inputBytes = Encoding.UTF8.GetBytes(plainText); + var encryptedBytes = ProcessCipher(blockCipher, inputBytes); + + // 返回 Base64 编码的加密字符串 + return Convert.ToBase64String(encryptedBytes); + } + + // AES 解密(不带 IV) + public static string Decrypt(string encryptedText, string key) + { + var keyBytes = Encoding.UTF8.GetBytes(key); + var cipherBytes = Convert.FromBase64String(encryptedText); + + // 使用 AES 引擎 + PKCS7 填充 + var engine = new AesEngine(); + var blockCipher = new PaddedBufferedBlockCipher(engine, new Pkcs7Padding()); + blockCipher.Init(false, new KeyParameter(keyBytes)); // false 表示解密 + + var decryptedBytes = ProcessCipher(blockCipher, cipherBytes); + return Encoding.UTF8.GetString(decryptedBytes); + } + + // AES 加密(带 IV) + /// + /// AES 密钥的长度必须是以下之一:128 位(16 字节)192 位(24 字节)256 位(32 字节) + /// IV must be 16 bytes + /// + /// + /// + /// + /// + public static string Encrypt(string plainText, string key, string iv) + { + var keyBytes = Encoding.UTF8.GetBytes(key.PadRight(32, '0').Substring(0, 32)); + var ivBytes = Encoding.UTF8.GetBytes(iv.PadRight(16, '0').Substring(0, 16)); + + // 使用 AES 引擎 + PKCS7 填充 + CBC 模式 + var engine = new AesEngine(); + var blockCipher = new PaddedBufferedBlockCipher(new CbcBlockCipher(engine), new Pkcs7Padding()); + blockCipher.Init(true, new ParametersWithIV(new KeyParameter(keyBytes), ivBytes)); // true 表示加密 + + var inputBytes = Encoding.UTF8.GetBytes(plainText); + var encryptedBytes = ProcessCipher(blockCipher, inputBytes); + + // 返回 Base64 编码的加密字符串 + return Convert.ToBase64String(encryptedBytes); + } + + // AES 解密(带 IV) + public static string Decrypt(string encryptedText, string key, string iv) + { + var keyBytes = Encoding.UTF8.GetBytes(key.PadRight(32, '0').Substring(0, 32)); + var ivBytes = Encoding.UTF8.GetBytes(iv.PadRight(16, '0').Substring(0, 16)); + var cipherBytes = Convert.FromBase64String(encryptedText); + + // 使用 AES 引擎 + PKCS7 填充 + CBC 模式 + var engine = new AesEngine(); + var blockCipher = new PaddedBufferedBlockCipher(new CbcBlockCipher(engine), new Pkcs7Padding()); + blockCipher.Init(false, new ParametersWithIV(new KeyParameter(keyBytes), ivBytes)); // false 表示解密 + + var decryptedBytes = ProcessCipher(blockCipher, cipherBytes); + return Encoding.UTF8.GetString(decryptedBytes); + } + + // 处理加密/解密数据 + private static byte[] ProcessCipher(IBufferedCipher cipher, byte[] input) + { + var output = new byte[cipher.GetOutputSize(input.Length)]; + int length = cipher.ProcessBytes(input, 0, input.Length, output, 0); + length += cipher.DoFinal(output, length); + Array.Resize(ref output, length); // 调整输出数组大小以适应实际数据长度 + return output; + } + + public static string DefaultKey = "12345678901234567890123456789012"; + + public static string EncryptPartial(string plainText, int unencryptedPrefixLength) + { + if (plainText.Length <= unencryptedPrefixLength) + { + return Encrypt(plainText, DefaultKey); // 如果文本太短,直接加密 + } + + var prefix = plainText.Substring(0, unencryptedPrefixLength); + var suffix = plainText.Substring(unencryptedPrefixLength); + + return prefix + Encrypt(suffix, DefaultKey); // 前缀保留,后缀加密 + } + + public static string DecryptPartial(string encryptedText, int unencryptedPrefixLength) + { + if (encryptedText.Length <= unencryptedPrefixLength) + { + return Decrypt(encryptedText, DefaultKey); // 如果文本太短,直接解密 + } + + var prefix = encryptedText.Substring(0, unencryptedPrefixLength); + var suffix = encryptedText.Substring(unencryptedPrefixLength); + + return prefix + Decrypt(suffix, DefaultKey); // 前缀保留,后缀解密 + } + + //public static string Encrypt(string plainText) + //{ + // using var aes = Aes.Create(); + // aes.Key = Encoding.UTF8.GetBytes(EncryptionKey); + // aes.Mode = CipherMode.ECB; // 根据需要选择加密模式,这里使用 ECB 模式 + // aes.Padding = PaddingMode.PKCS7; + + // var encryptor = aes.CreateEncryptor(); + // var plainBytes = Encoding.UTF8.GetBytes(plainText); + // var encryptedBytes = encryptor.TransformFinalBlock(plainBytes, 0, plainBytes.Length); + + // return Convert.ToBase64String(encryptedBytes); + //} + + //public static string Decrypt(string encryptedText) + //{ + // using var aes = Aes.Create(); + // aes.Key = Encoding.UTF8.GetBytes(EncryptionKey); + // aes.Mode = CipherMode.ECB; + // aes.Padding = PaddingMode.PKCS7; + + // var decryptor = aes.CreateDecryptor(); + // var encryptedBytes = Convert.FromBase64String(encryptedText); + // var decryptedBytes = decryptor.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length); + + // return Encoding.UTF8.GetString(decryptedBytes); + //} +} diff --git a/HIR-Activate/Encryption/RSAEncryption.cs b/HIR-Activate/Encryption/RSAEncryption.cs new file mode 100644 index 0000000..3f7d00c --- /dev/null +++ b/HIR-Activate/Encryption/RSAEncryption.cs @@ -0,0 +1,94 @@ +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Encodings; +using Org.BouncyCastle.Crypto.Engines; +using Org.BouncyCastle.Crypto.Generators; +using Org.BouncyCastle.OpenSsl; +using Org.BouncyCastle.Security; +using System; +using System.IO; +using System.Text; + +namespace IRaCIS.Core.Infrastructure.Encryption; + +/// +/// https://www.cnblogs.com/NBDWDYS2214143926/p/13329231.html +/// +public class RSAEncryption +{ + + public static AsymmetricCipherKeyPair GenerateRSAKeyPair(int keySize) + { + var keyGenerationParameters = new KeyGenerationParameters(new SecureRandom(), keySize); + var keyPairGenerator = new RsaKeyPairGenerator(); + keyPairGenerator.Init(keyGenerationParameters); + return keyPairGenerator.GenerateKeyPair(); + } + + public static string ExportPublicKey(AsymmetricKeyParameter publicKey) + { + using (StringWriter sw = new StringWriter()) + { + PemWriter pw = new PemWriter(sw); + pw.WriteObject(publicKey); + pw.Writer.Flush(); + return sw.ToString(); + } + } + + public static string ExportPrivateKey(AsymmetricKeyParameter privateKey) + { + using (StringWriter sw = new StringWriter()) + { + PemWriter pw = new PemWriter(sw); + pw.WriteObject(privateKey); + pw.Writer.Flush(); + return sw.ToString(); + } + } + + /// + /// RSA解密 + /// + /// 私钥 + /// 待解密的字符串(Base64) + /// 解密后的字符串 + public static string Decrypt(string privateKey, string decryptstring) + { + using (TextReader reader = new StringReader(privateKey)) + { + dynamic key = new PemReader(reader).ReadObject(); + var rsaDecrypt = new Pkcs1Encoding(new RsaEngine()); + if (key is AsymmetricKeyParameter) + { + key = (AsymmetricKeyParameter)key; + } + else if (key is AsymmetricCipherKeyPair) + { + key = ((AsymmetricCipherKeyPair)key).Private; + } + rsaDecrypt.Init(false, key); //这里加密是true;解密是false + + byte[] entData = Convert.FromBase64String(decryptstring); + entData = rsaDecrypt.ProcessBlock(entData, 0, entData.Length); + return Encoding.UTF8.GetString(entData); + } + }/// + + /// 加密 + /// + /// 公钥 + /// 待加密的字符串 + /// 加密后的Base64 + public static string Encrypt(string publicKey, string encryptstring) + { + using (TextReader reader = new StringReader(publicKey)) + { + AsymmetricKeyParameter key = new PemReader(reader).ReadObject() as AsymmetricKeyParameter; + Pkcs1Encoding pkcs1 = new Pkcs1Encoding(new RsaEngine()); + pkcs1.Init(true, key);//加密是true;解密是false; + byte[] entData = Encoding.UTF8.GetBytes(encryptstring); + entData = pkcs1.ProcessBlock(entData, 0, entData.Length); + return Convert.ToBase64String(entData); + } + } +} diff --git a/HIR-Activate/Form1.Designer.cs b/HIR-Activate/Form1.Designer.cs new file mode 100644 index 0000000..86d1830 --- /dev/null +++ b/HIR-Activate/Form1.Designer.cs @@ -0,0 +1,123 @@ +namespace HIR_Activate +{ + partial class Form1 + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + label1 = new Label(); + txtFilePath = new TextBox(); + btn_select = new Button(); + btn_activate = new Button(); + label2 = new Label(); + txtActivateFilePath = new TextBox(); + SuspendLayout(); + // + // label1 + // + label1.AutoSize = true; + label1.Font = new Font("Microsoft YaHei UI", 12F, FontStyle.Regular, GraphicsUnit.Point, 134); + label1.Location = new Point(12, 57); + label1.Name = "label1"; + label1.Size = new Size(138, 21); + label1.TabIndex = 0; + label1.Text = "选择项目激活文件"; + // + // txtFilePath + // + txtFilePath.Location = new Point(167, 55); + txtFilePath.Name = "txtFilePath"; + txtFilePath.ReadOnly = true; + txtFilePath.Size = new Size(462, 23); + txtFilePath.TabIndex = 1; + // + // btn_select + // + btn_select.Font = new Font("Microsoft YaHei UI", 12F, FontStyle.Regular, GraphicsUnit.Point, 134); + btn_select.Location = new Point(650, 49); + btn_select.Name = "btn_select"; + btn_select.Size = new Size(100, 33); + btn_select.TabIndex = 2; + btn_select.Text = "选择"; + btn_select.UseVisualStyleBackColor = true; + btn_select.Click += btn_select_Click; + // + // btn_activate + // + btn_activate.Font = new Font("Microsoft YaHei UI", 15F, FontStyle.Regular, GraphicsUnit.Point, 134); + btn_activate.Location = new Point(230, 236); + btn_activate.Name = "btn_activate"; + btn_activate.Size = new Size(307, 57); + btn_activate.TabIndex = 3; + btn_activate.Text = "生成激活文件"; + btn_activate.UseVisualStyleBackColor = true; + btn_activate.Click += btn_activate_Click; + // + // label2 + // + label2.AutoSize = true; + label2.Font = new Font("Microsoft YaHei UI", 12F, FontStyle.Regular, GraphicsUnit.Point, 134); + label2.Location = new Point(12, 133); + label2.Name = "label2"; + label2.Size = new Size(106, 21); + label2.TabIndex = 4; + label2.Text = "生成文件路径"; + // + // txtActivateFilePath + // + txtActivateFilePath.Location = new Point(167, 131); + txtActivateFilePath.Name = "txtActivateFilePath"; + txtActivateFilePath.ReadOnly = true; + txtActivateFilePath.Size = new Size(591, 23); + txtActivateFilePath.TabIndex = 5; + // + // Form1 + // + AutoScaleDimensions = new SizeF(7F, 17F); + AutoScaleMode = AutoScaleMode.Font; + ClientSize = new Size(800, 542); + Controls.Add(txtActivateFilePath); + Controls.Add(label2); + Controls.Add(btn_activate); + Controls.Add(btn_select); + Controls.Add(txtFilePath); + Controls.Add(label1); + Name = "Form1"; + Text = "HIR 激活码"; + ResumeLayout(false); + PerformLayout(); + } + + #endregion + + private Label label1; + private TextBox txtFilePath; + private Button btn_select; + private Button btn_activate; + private Label label2; + private TextBox txtActivateFilePath; + } +} diff --git a/HIR-Activate/Form1.cs b/HIR-Activate/Form1.cs new file mode 100644 index 0000000..5062b14 --- /dev/null +++ b/HIR-Activate/Form1.cs @@ -0,0 +1,218 @@ +using IRaCIS.Core.Infrastructure.Encryption; +using Newtonsoft.Json; + +namespace HIR_Activate +{ + public partial class Form1 : Form + { + public Form1() + { + InitializeComponent(); + } + + private void btn_select_Click(object sender, EventArgs e) + { + using (OpenFileDialog openFileDialog = new OpenFileDialog()) + { + openFileDialog.Filter = "Request Files (*.req)|*.req"; + if (openFileDialog.ShowDialog() == DialogResult.OK) + { + txtFilePath.Text = openFileDialog.FileName; + } + } + } + + private void btn_activate_Click(object sender, EventArgs e) + { + string filePath = txtFilePath.Text; + var fileName=Path.GetFileNameWithoutExtension(filePath); + if (string.IsNullOrWhiteSpace(filePath) || !File.Exists(filePath)) + { + MessageBox.Show("ѡһЧļ·", "", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + + try + { + // ȡļ + string authorizationCode = File.ReadAllText(filePath); + + // Base64 + byte[] base64DecodedBytes = Convert.FromBase64String(authorizationCode); + string decodedText = System.Text.Encoding.UTF8.GetString(base64DecodedBytes); + + var authorizationInfo = JsonConvert.DeserializeObject(decodedText); + + if (authorizationInfo == null) + { + MessageBox.Show("ܽĿȨ룡", "", MessageBoxButtons.OK, MessageBoxIcon.Error); + + return; + } + else + { + //һڼ + authorizationInfo.ActiveDeadLineDate = DateTime.Now.Date.AddDays(8).AddSeconds(-1); + + var licenseContent = AesEncryption.Encrypt($"{JsonConvert.SerializeObject(authorizationInfo)}", "HIR_System_AES_Key_Info", "Trial_AuthorizationEncrypt"); + + Console.WriteLine("HIR_System_AES_Key_Info".PadRight(32, '0').Substring(0, 32) + " " + "Trial_AuthorizationEncrypt".PadRight(16, '0').Substring(0, 16)); + + //var dd = AesEncryption.Decrypt(info, "HIR_System_AES_Key_Info", "Trial_AuthorizationEncrypt"); + + // ֤ļ + string licensePath = Path.Combine(Path.GetDirectoryName(filePath), $"{fileName}_Activation_Code.lic"); + File.WriteAllText(licensePath, licenseContent); + + txtActivateFilePath.Text = licensePath; + + MessageBox.Show($"֤ɳɹ", "ɹ", MessageBoxButtons.OK, MessageBoxIcon.Information); + } + + + } + catch (Exception ex) + { + MessageBox.Show($"֤ʧܣ{ex.Message}", "", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + } + + public class TrialAuthorizationInfo + { + public Guid TrialId { get; set; } + public Guid CreateUserId { get; set; } + public string TrialCode { get; set; } + + public string HospitalName { get; set; } + + public string HospitalCode { get; set; } + + public int PurchaseDuration { get; set; } + + + + public List CriterionTypeList { get; set; } + + public DateTime? AuthorizationDeadLineDate { get; set; } + + public DateTime? ActiveDeadLineDate { get; set; } + + public DateTime? ActiveTime { get; set; } + + } + + /// + /// ׼ + /// + public enum CriterionType + { + NoCriterion = -1, + + //Զ + SelfDefine = 0, + + /// + /// RECIST 1.1 + /// + RECIST1Point1 = 1, + + + + /// + /// Lugano 2014 + /// + Lugano2014 = 2, + + /// + /// iRECIST1Point1 + /// + IRECIST1Point1 = 3, + + /// + /// RANO-BM + /// + RANO_BM = 4, + + /// + /// RANO + /// + RANO = 5, + + /// + /// IWCLL 2018 + /// + IWCLL2018 = 6, + + /// + /// mRECIST HCC + /// + mRECISTHCC = 7, + + /// + /// Cheson 2007 + /// + Cheson2007 = 8, + + /// + /// IMWG 2016 + /// + IMWG2016 = 9, + + /// + /// PCWG3 + /// + PCWG3 = 10, + + /// + /// mRECIST Mesothelioma + /// + mRECISTMesothelioma = 11, + + /// + /// RECIL + /// + RECIL = 12, + + /// + /// RECIST 1.0 + /// + RECIST1Point0 = 13, + + /// + /// WHO + /// + WHO = 14, + + /// + /// PERCIST + /// + PERCIST = 15, + + /// + /// Forrest + /// + Forrest = 16, + + /// + /// RECIST 1.1-BM + /// + RECIST1Pointt1_MB = 17, + + /// + /// Lugano 2014 Without PET + /// + Lugano2014WithoutPET = 18, + + /// + /// IVUS + /// + IVUS = 19, + + /// + /// OCT + /// + OCT = 20, + } + +} diff --git a/HIR-Activate/Form1.resx b/HIR-Activate/Form1.resx new file mode 100644 index 0000000..8b2ff64 --- /dev/null +++ b/HIR-Activate/Form1.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/HIR-Activate/HIR-Activate.csproj b/HIR-Activate/HIR-Activate.csproj new file mode 100644 index 0000000..079c726 --- /dev/null +++ b/HIR-Activate/HIR-Activate.csproj @@ -0,0 +1,17 @@ + + + + WinExe + net8.0-windows + HIR_Activate + enable + true + enable + + + + + + + + \ No newline at end of file diff --git a/HIR-Activate/Program.cs b/HIR-Activate/Program.cs new file mode 100644 index 0000000..fbb7fb8 --- /dev/null +++ b/HIR-Activate/Program.cs @@ -0,0 +1,17 @@ +namespace HIR_Activate +{ + internal static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + // To customize application configuration such as set high DPI settings or default font, + // see https://aka.ms/applicationconfiguration. + ApplicationConfiguration.Initialize(); + Application.Run(new Form1()); + } + } +} \ No newline at end of file