RsaUtility.cs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. using PCC.App.BinaryFormatter;
  2. using System.Security;
  3. using System.Security.Cryptography;
  4. using System.Text;
  5. namespace PCC.App.Security;
  6. public static class RsaUtility
  7. {
  8. public static (string pub, string pri) GeneratePem(int bits)
  9. {
  10. var rsa = RSA.Create(bits);
  11. var pub = rsa.ExportRSAPublicKeyPem();
  12. var pri = rsa.ExportRSAPrivateKeyPem();
  13. return (pub, pri);
  14. }
  15. public static (byte[] pub, byte[] pri) GeneratePKCS1(int bits)
  16. {
  17. var rsa = RSA.Create(bits);
  18. var pub = rsa.ExportRSAPublicKey();
  19. var pri = rsa.ExportRSAPrivateKey();
  20. return (pub, pri);
  21. }
  22. public static RSA FromPKCS1PrivateKey(byte[] privateKey)
  23. {
  24. var rsa = RSA.Create();
  25. rsa.ImportRSAPrivateKey(privateKey, out _);
  26. return rsa;
  27. }
  28. public static RSA FromPKCS1PublicKey(byte[] publicKey)
  29. {
  30. var rsa = RSA.Create();
  31. rsa.ImportRSAPublicKey(publicKey, out _);
  32. return rsa;
  33. }
  34. public static RSA FromPem(string pub)
  35. {
  36. var rsa = RSA.Create();
  37. rsa.ImportFromPem(pub);
  38. return rsa;
  39. }
  40. public static byte[] Encrypt(RSA encPub, byte[] payload, int skSize = 256, int ivSize = 128) => EncryptAndSignature(encPub, payload, null, skSize, ivSize);
  41. public static byte[] EncryptAndSignature(RSA encPub, ReadOnlySpan<byte> payload, RSA? sigPri, int skSize = 256, int ivSize = 128)
  42. {
  43. // EK= Rsa(encPub, [SK] + [IV] )
  44. // ED= AES(SK,IV,[rawData] + [Sign(sigPri,rawData)] )
  45. // ret= [EK] + [ED]
  46. // generate Symmetric key: SK,IV
  47. var sk = RandomNumberGenerator.GetBytes(skSize / 8);
  48. var iv = RandomNumberGenerator.GetBytes(ivSize / 8);
  49. //Debug.Print($"SK: {Convert.ToHexString(sk)}");
  50. //Debug.Print($"IV: {Convert.ToHexString(iv)}");
  51. using var aes = Aes.Create();
  52. aes.Mode = CipherMode.CBC;
  53. aes.Padding = PaddingMode.PKCS7;
  54. aes.KeySize = skSize;
  55. aes.BlockSize = ivSize;
  56. aes.Key = sk;
  57. aes.IV = iv;
  58. // EK= Rsa(encPub, [SK] + [IV])
  59. byte[] ek;
  60. {
  61. var msSkIv = new MemoryStream();
  62. var bw = new BinaryWriter(msSkIv, Encoding.UTF8, true);
  63. bw.WriteBlock(sk);
  64. bw.WriteBlock(iv);
  65. bw.Close();
  66. var skIv = msSkIv.ToArray();
  67. ek = encPub.Encrypt(skIv, RSAEncryptionPadding.Pkcs1);
  68. }
  69. // ED= AES(SK,IV,[rawData] + [Sign(sigPri,rawData)] )
  70. byte[] ed;
  71. {
  72. var msEd = new MemoryStream();
  73. using var cryptoTransform = aes.CreateEncryptor();
  74. var es = new CryptoStream(msEd, cryptoTransform, CryptoStreamMode.Write);
  75. var eBw = new BinaryWriter(es, Encoding.UTF8, true);
  76. eBw.WriteBlock(payload);
  77. if (sigPri != null)
  78. {
  79. var sign = sigPri.SignData(payload, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
  80. eBw.WriteBlock(sign);
  81. }
  82. eBw.Close();
  83. es.Close();
  84. ed = msEd.ToArray();
  85. }
  86. // return [EK] + [ED]
  87. byte[] ret;
  88. {
  89. var msRet = new MemoryStream();
  90. var bw = new BinaryWriter(msRet, Encoding.UTF8, true);
  91. bw.WriteBlock(ek);
  92. bw.WriteBlock(ed);
  93. bw.Close();
  94. ret = msRet.ToArray();
  95. }
  96. return ret;
  97. }
  98. public static byte[] Decrypt(RSA decPri, byte[] dataToDecrypt) => DecryptAndVerifySignature(decPri, dataToDecrypt, null);
  99. public static byte[] DecryptAndVerifySignature(RSA decPri, byte[] dataToDecrypt, RSA? verPub)
  100. {
  101. // extract [EK] [ED]
  102. byte[] ek, ed;
  103. {
  104. var ms = new MemoryStream(dataToDecrypt);
  105. var br = new BinaryReader(ms);
  106. ek = br.ReadBlock();
  107. ed = br.ReadBlock();
  108. }
  109. byte[] sk, iv;
  110. {
  111. // decrypt EK by pri
  112. var skIv = decPri.Decrypt(ek, RSAEncryptionPadding.Pkcs1);
  113. var msSkIv = new MemoryStream(skIv);
  114. var br = new BinaryReader(msSkIv);
  115. sk = br.ReadBlock();
  116. iv = br.ReadBlock();
  117. }
  118. //Debug.Print($"SK: {Convert.ToHexString(sk)}");
  119. //Debug.Print($"IV: {Convert.ToHexString(iv)}");
  120. // decData= [payload] + [Signature]
  121. byte[] decData;
  122. {
  123. // decrypt by SK,IV
  124. var aes = Aes.Create();
  125. aes.Mode = CipherMode.CBC;
  126. aes.Padding = PaddingMode.PKCS7;
  127. aes.KeySize = 128;
  128. aes.BlockSize = 128;
  129. aes.Key = sk;
  130. aes.IV = iv;
  131. var msEd = new MemoryStream(ed);
  132. var msDec = new MemoryStream();
  133. var ds = new CryptoStream(msEd, aes.CreateDecryptor(), CryptoStreamMode.Read);
  134. ds.CopyTo(msDec);
  135. ds.Close();
  136. decData = msDec.ToArray();
  137. }
  138. // extract [payload] [Signature]
  139. byte[] payload;
  140. byte[]? signature = null;
  141. {
  142. var ms = new MemoryStream(decData);
  143. var br = new BinaryReader(ms);
  144. payload = br.ReadBlock();
  145. if (verPub != null)
  146. {
  147. if (ms.Position != ms.Length) signature = br.ReadBlock();
  148. else throw new SecurityException("Missing signature");
  149. }
  150. }
  151. if (signature == null || verPub == null) return payload;
  152. // Validate signature
  153. var r = verPub.VerifyData(payload, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
  154. if (r == false) throw new SecurityException("Signature verify fail");
  155. // return payload
  156. return payload;
  157. }
  158. }