可用的 .net core 支持 RSA 私鑰加密工具類

首先說明 MS並不建議私鑰加密,而且.net 於安全的考慮,RSACryptoServiceProvider類解密時只有同時擁有公鑰和私鑰纔可以,原因是公鑰是公開的,會被多人持有,這樣的數據傳輸是不安全的。但是架不住有BouncyCastle這個第三方組件,也是可以實現的。只不過在.net core 2.2 下,沒有了 RSACryptoServiceProvider,只好改用 System.Security.Cryptography.RSA 來實現 RSA 私鑰加密

  1 #Const SUPPORT_PRIVATE_ENCRYPT = True
  2 Imports System.IO
  3 Imports System.Text
  4 Imports System.Security.Cryptography
  5 
  6 #If SUPPORT_PRIVATE_ENCRYPT Then
  7 Imports Org.BouncyCastle.Math
  8 Imports Org.BouncyCastle.Crypto
  9 Imports Org.BouncyCastle.Security
 10 Imports Org.BouncyCastle.Crypto.Parameters
 11 #End If
 12 
 13 ''' <summary>
 14 ''' RSA 加密解密輔助類
 15 ''' </summary>
 16 ''' <remarks></remarks>
 17 Public Class RSAHelper
 18 
 19     Private Shared _privateKey As String
 20 
 21     ''' <summary>
 22     ''' RSA私鑰,包含公鑰和私鑰
 23     ''' </summary>
 24     ''' <value></value>
 25     ''' <returns></returns>
 26     ''' <remarks></remarks>
 27     Public Shared ReadOnly Property PrivateKey As String
 28         Get
 29             Return _privateKey
 30         End Get
 31     End Property
 32 
 33     Private Shared _publicKey As String
 34 
 35     ''' <summary>
 36     ''' RSA公鑰,只包含公鑰
 37     ''' </summary>
 38     ''' <value></value>
 39     ''' <returns></returns>
 40     ''' <remarks></remarks>
 41     Public Shared ReadOnly Property PublicKey As String
 42         Get
 43             Return _publicKey
 44         End Get
 45     End Property
 46 
 47     ''' <summary>
 48     ''' 創建RSA密鑰對
 49     ''' </summary>
 50     ''' <param name="keySize">512,1024 ...</param>
 51     ''' <returns></returns>
 52     ''' <remarks></remarks>
 53     Public Shared Function CreateRSAKey(Optional ByVal keySize As Int32 = 4096) As Boolean
 54         _privateKey = Nothing
 55         _publicKey = Nothing
 56         Try
 57             'Dim provider As New RSACryptoServiceProvider(keySize)
 58             Dim provider = RSA.Create()
 59             provider.KeySize = keySize
 60             _privateKey = provider.ToXml(True)
 61             _publicKey = provider.ToXml(False)
 62 
 63             Console.WriteLine("max encrypt buffer size:{0}", (keySize / 8) - 11)
 64             Console.WriteLine("max decrypt buffer size:{0}", keySize / 8)
 65 
 66             Console.WriteLine(provider.ToPem(True))
 67             Console.WriteLine()
 68             Console.WriteLine(provider.ToPem(False))
 69 
 70             Console.WriteLine(provider.ToXml(True))
 71             Console.WriteLine()
 72             Console.WriteLine(provider.ToXml(False))
 73 
 74 #If SUPPORT_PRIVATE_ENCRYPT Then
 75             '驗證祕鑰對
 76             provider.FromXml(_privateKey)
 77             Dim p = provider.ExportParameters(True)
 78             Dim rkpPrivate As New RsaKeyParameters(True, New BigInteger(1, p.Modulus), New BigInteger(p.D))
 79             Dim rkpPublic As New RsaKeyParameters(False, New BigInteger(1, p.Modulus), New BigInteger(p.Exponent))
 80             '密鑰對有無效的概率,不報錯的纔可用
 81 #End If
 82             Return True
 83         Catch ex As Exception
 84             Debug.Print("CreateRSAKey({0}) failed, err:{1}", keySize, ex.Message)
 85             Return False
 86         End Try
 87     End Function
 88 
 89     Private Shared Function isKeyValid(ByVal key As String) As Boolean
 90         If String.IsNullOrEmpty(key) Then
 91             Return False
 92         End If
 93         If key.Trim().Length = 0 Then
 94             Return False
 95         End If
 96 
 97         Return True
 98     End Function
 99 
100     ''' <summary>
101     ''' 公鑰加密
102     ''' </summary>
103     ''' <param name="publicKey" >公鑰(XML格式字符串)</param>
104     ''' <param name="plaintext">待加密字符串,明文</param>
105     ''' <returns></returns>
106     Public Shared Function PublicKeyEncrypt(ByVal publicKey As String, plaintext As String) As String
107         '默認只能使用[公鑰]進行加密(想使用[公鑰解密]可使用第三方組件BouncyCastle來實現)
108         If String.IsNullOrEmpty(plaintext) Then
109             Return String.Empty
110         End If
111 
112         If Not isKeyValid(publicKey) Then
113             Throw New ArgumentException("Invalid Public Key")
114         End If
115 
116         '創建RSA對象並載入[公鑰]
117         Dim provider = RSA.Create
118         provider.FromXml(publicKey)
119 
120         If (provider.KeySize / 8 - 11) <= plaintext.Length Then
121             Throw New ArgumentException("plaintext is too long, try PublicKeyEncryptEx please")
122         End If
123 
124         '對數據進行加密
125         Dim publicValue() As Byte = provider.Encrypt(Encoding.UTF8.GetBytes(plaintext), RSAEncryptionPadding.Pkcs1)
126         Dim ciphertext As String = Convert.ToBase64String(publicValue) '使用Base64將byte轉換爲string
127         Return ciphertext
128     End Function
129 
130     ''' <summary>
131     ''' 私鑰解密
132     ''' </summary>
133     ''' <param name="privateKey" >私鑰(XML格式字符串)</param>
134     ''' <param name="ciphertext">待解密字符串,密文</param>
135     ''' <returns></returns>
136     Public Shared Function PrivateKeyDecrypt(ByVal privateKey As String, ByVal ciphertext As String) As String
137         '默認只能使用[私鑰]進行解密(想使用[私鑰加密]可使用第三方組件BouncyCastle來實現)
138         If String.IsNullOrEmpty(ciphertext) Then
139             Return String.Empty
140         End If
141 
142         If Not isKeyValid(privateKey) Then
143             Throw New ArgumentException("Invalid Private Key")
144         End If
145 
146         '創建RSA對象並載入[私鑰]
147         Dim provider = RSA.Create
148         provider.FromXml(privateKey)
149 
150         If (provider.KeySize / 8 / 64) <= ciphertext.Length / 171 Then
151             Throw New ArgumentException("ciphertext is too long, try PrivateKeyDecryptEx please")
152         End If
153 
154         '對數據進行解密
155         Dim privateValue() As Byte = provider.Decrypt(Convert.FromBase64String(ciphertext), RSAEncryptionPadding.Pkcs1) '使用Base64將string轉換爲byte
156         Dim plaintext As String = Encoding.UTF8.GetString(privateValue)
157         Return plaintext
158     End Function
159 
160     ''' <summary>
161     ''' 公鑰加密
162     ''' </summary>
163     ''' <param name="publicKey">公鑰(XML格式字符串)</param>
164     ''' <param name="plaintext">待加密字符串,明文,長度不限</param>
165     ''' <returns></returns>
166     ''' <remarks></remarks>
167     Public Shared Function PublicKeyEncryptEx(ByVal publicKey As String, ByVal plaintext As String) As String
168         If String.IsNullOrEmpty(plaintext) Then
169             Return String.Empty
170         End If
171 
172         If Not isKeyValid(publicKey) Then
173             Throw New ArgumentException("Invalid Public Key")
174         End If
175 
176         '載入公鑰
177         Dim provider = RSA.Create
178         provider.FromXml(publicKey)
179 
180         Dim inputBytes = Encoding.UTF8.GetBytes(plaintext) '有含義的字符串轉化爲字節流
181         Dim bufferSize As Integer = (provider.KeySize / 8) - 11 '單塊最大長度
182         Dim buffer = New Byte(bufferSize - 1) {}
183         Using inputStream As New MemoryStream(inputBytes), outputStream As New MemoryStream()
184             Do
185                 Dim readSize As Integer = inputStream.Read(buffer, 0, bufferSize)
186                 If readSize <= 0 Then
187                     Exit Do
188                 End If
189 
190                 Dim temp = New Byte(readSize - 1) {}
191                 Array.Copy(buffer, 0, temp, 0, readSize)
192                 Dim encryptedBytes = provider.Encrypt(temp, RSAEncryptionPadding.Pkcs1) 'False)
193                 outputStream.Write(encryptedBytes, 0, encryptedBytes.Length)
194             Loop
195             Return Convert.ToBase64String(outputStream.ToArray()) '轉化爲字節流方便傳輸
196         End Using
197 
198     End Function
199 
200     ''' <summary>
201     ''' 私鑰解密
202     ''' </summary>
203     ''' <param name="privateKey">私鑰(XML格式字符串)</param>
204     ''' <param name="ciphertext">待解密字符串,密文,長度不限</param>
205     ''' <returns></returns>
206     ''' <remarks></remarks>
207     Public Shared Function PrivateKeyDecryptEx(ByVal privateKey As String, ByVal ciphertext As String) As String
208         If String.IsNullOrEmpty(ciphertext) Then
209             Return String.Empty
210         End If
211 
212         If Not isKeyValid(privateKey) Then
213             Throw New ArgumentException("Invalid Private Key")
214         End If
215 
216         '載入私鑰
217         Dim provider = RSA.Create
218         provider.FromXml(privateKey)
219 
220         Dim inputBytes = Convert.FromBase64String(ciphertext)
221         Dim bufferSize As Integer = provider.KeySize / 8
222         Dim buffer = New Byte(bufferSize - 1) {}
223         Using inputStream As New MemoryStream(inputBytes), outputStream As New MemoryStream()
224             Do
225                 Dim readSize As Integer = inputStream.Read(buffer, 0, bufferSize)
226                 If readSize <= 0 Then
227                     Exit Do
228                 End If
229 
230                 Dim temp = New Byte(readSize - 1) {}
231                 Array.Copy(buffer, 0, temp, 0, readSize)
232                 Dim rawBytes = provider.Decrypt(temp, RSAEncryptionPadding.Pkcs1)
233                 outputStream.Write(rawBytes, 0, rawBytes.Length)
234             Loop
235             Return Encoding.UTF8.GetString(outputStream.ToArray())
236         End Using
237     End Function
238 
239 #Region "   依賴 BouncyCastle 實現私鑰加密,公鑰解密"
240 #If SUPPORT_PRIVATE_ENCRYPT Then
241 
242     ''' <summary>
243     ''' 私鑰加密
244     ''' </summary>
245     ''' <param name="privateKey"> 私鑰(XML格式字符串)</param>
246     ''' <param name="plaintext"> 要加密的數據 </param>
247     ''' <returns> 加密後的數據 </returns>
248     Public Shared Function PrivateKeyEncrypt(ByVal privateKey As String, ByVal plaintext As String) As String
249         If String.IsNullOrEmpty(plaintext) Then
250             Return String.Empty
251         End If
252 
253         If Not isKeyValid(privateKey) Then
254             Throw New ArgumentException("Invalid Private Key")
255         End If
256 
257         '加載私鑰
258         Dim provider = RSA.Create
259         provider.FromXml(privateKey)
260         Dim keyPair = DotNetCoreUtilities.GetKeyPair(provider)
261 
262         Dim c As IBufferedCipher = CipherUtilities.GetCipher("RSA/ECB/PKCS1Padding") '使用RSA/ECB/PKCS1Padding格式
263         '第一個參數爲true表示加密,爲false表示解密;第二個參數表示密鑰
264         c.Init(True, keyPair.Private)
265 
266         Dim DataToEncrypt() As Byte = Encoding.UTF8.GetBytes(plaintext)
267         Dim outBytes() As Byte = c.DoFinal(DataToEncrypt) '加密
268         Dim strBase64 As String = Convert.ToBase64String(outBytes)
269 
270         Return strBase64
271 
272     End Function
273 
274     ''' <summary>
275     ''' 私鑰加密
276     ''' </summary>
277     ''' <param name="privateKey"> 私鑰(XML格式字符串)</param>
278     ''' <param name="plaintext"> 要加密的數據,長度不限 </param>
279     ''' <returns> 加密後的數據 </returns>
280     Public Shared Function PrivateKeyEncryptEx(ByVal privateKey As String, ByVal plaintext As String) As String
281         If String.IsNullOrEmpty(plaintext) Then
282             Return String.Empty
283         End If
284 
285         If Not isKeyValid(privateKey) Then
286             Throw New ArgumentException("Invalid Private Key")
287         End If
288 
289         '加載私鑰
290         Dim provider = RSA.Create 'As New RSACryptoServiceProvider()
291         provider.FromXml(privateKey)
292         Dim keyPair = DotNetCoreUtilities.GetKeyPair(provider)
293 
294         Dim c As IBufferedCipher = CipherUtilities.GetCipher("RSA/ECB/PKCS1Padding") '使用RSA/ECB/PKCS1Padding格式
295         ''第一個參數爲true表示加密,爲false表示解密;第二個參數表示密鑰
296         c.Init(True, keyPair.Private) ' keyPair.Private)
297 
298         Dim inputBytes = Encoding.UTF8.GetBytes(plaintext)
299         Dim bufferSize As Integer = provider.KeySize / 8 - 11
300         Dim buffer = New Byte(bufferSize - 1) {}
301         Dim outputStream As New MemoryStream()
302         Using inputStream As New MemoryStream(inputBytes)
303             Do
304                 Dim readSize As Integer = inputStream.Read(buffer, 0, bufferSize)
305                 If readSize <= 0 Then
306                     Exit Do
307                 End If
308 
309                 Dim temp = New Byte(readSize - 1) {}
310                 Array.Copy(buffer, 0, temp, 0, readSize)
311                 Dim rawBytes = c.DoFinal(temp)
312                 outputStream.Write(rawBytes, 0, rawBytes.Length)
313             Loop
314         End Using
315         Return Convert.ToBase64String(outputStream.ToArray())
316     End Function
317 
318     ''' <summary>
319     ''' 公鑰解密 
320     ''' </summary>
321     ''' <param name="publicKey"> 公鑰(XML格式字符串) </param>
322     ''' <param name="ciphertext"> 要解密數據 </param>
323     ''' <returns> 解密後的數據 </returns>
324     Public Shared Function PublicKeyDecrypt(ByVal publicKey As String, ByVal ciphertext As String) As String
325         If String.IsNullOrEmpty(ciphertext) Then
326             Return String.Empty
327         End If
328 
329         If Not isKeyValid(publicKey) Then
330             Throw New ArgumentException("Invalid Public Key")
331         End If
332 
333         '加載公鑰
334         Dim provider = RSA.Create
335         provider.FromXml(publicKey)
336         Dim keyParameter = DotNetCoreUtilities.GetKeyParmeter(provider.ToPem(False))
337 
338         Dim c As IBufferedCipher = CipherUtilities.GetCipher("RSA/ECB/PKCS1Padding")
339         '第一個參數爲true表示加密,爲false表示解密;第二個參數表示密鑰
340         c.Init(False, keyParameter)
341 
342         Dim DataToDecrypt() As Byte = Convert.FromBase64String(ciphertext)
343         Dim outBytes() As Byte = c.DoFinal(DataToDecrypt) '解密
344 
345         Dim strDec As String = Encoding.UTF8.GetString(outBytes)
346         Return strDec
347     End Function
348 
349     ''' <summary>
350     ''' 公鑰解密 
351     ''' </summary>
352     ''' <param name="publicKey"> 公鑰(XML格式字符串) </param>
353     ''' <param name="ciphertext"> 要解密數據,長度不限 </param>
354     ''' <returns> 解密後的數據 </returns>
355     Public Shared Function PublicKeyDecryptEx(ByVal publicKey As String, ByVal ciphertext As String) As String
356         If String.IsNullOrEmpty(ciphertext) Then
357             Return String.Empty
358         End If
359 
360         If Not isKeyValid(publicKey) Then
361             Throw New ArgumentException("Invalid Public Key")
362         End If
363 
364         '加載公鑰
365         Dim provider = RSA.Create
366         provider.FromXml(publicKey)
367         Dim keyParameter = DotNetCoreUtilities.GetKeyParmeter(provider.ToPem(False))
368 
369         Dim c As IBufferedCipher = CipherUtilities.GetCipher("RSA/ECB/PKCS1Padding")
370         '第一個參數爲true表示加密,爲false表示解密;第二個參數表示密鑰
371         c.Init(False, keyParameter)
372 
373         Dim inputBytes = Convert.FromBase64String(ciphertext)
374         Dim bufferSize As Integer = provider.KeySize / 8
375         Dim buffer = New Byte(bufferSize - 1) {}
376         Dim outputStream As New MemoryStream()
377         Using inputStream As New MemoryStream(inputBytes)
378             Do
379                 Dim readSize As Integer = inputStream.Read(buffer, 0, bufferSize)
380                 If readSize <= 0 Then
381                     Exit Do
382                 End If
383 
384                 Dim temp = New Byte(readSize - 1) {}
385                 Array.Copy(buffer, 0, temp, 0, readSize)
386                 Dim rawBytes = c.DoFinal(temp)
387                 outputStream.Write(rawBytes, 0, rawBytes.Length)
388             Loop
389         End Using
390         Return Encoding.UTF8.GetString(outputStream.ToArray())
391     End Function
392 #End If
393 #End Region
394 End Class

擴展方法

  1 Imports System.Security.Cryptography
  2 Imports System.Xml
  3 Imports Org.BouncyCastle.Crypto.Parameters
  4 Imports Org.BouncyCastle.Crypto
  5 Imports Org.BouncyCastle.Math
  6 Imports System.IO
  7 Imports Org.BouncyCastle.OpenSsl
  8 Imports Org.BouncyCastle.Security
  9 Imports System.Text
 10 
 11 Friend Module RsaExtention
 12 
 13     <System.Runtime.CompilerServices.Extension>
 14     Public Sub FromXml(ByVal rsa As RSA, ByVal xmlString As String)
 15         Dim parameters As New RSAParameters()
 16         Dim xmlDoc As New XmlDocument()
 17         xmlDoc.LoadXml(xmlString)
 18         If xmlDoc.DocumentElement.Name.Equals("RSAKeyValue") Then
 19             For Each node As XmlNode In xmlDoc.DocumentElement.ChildNodes
 20                 Select Case node.Name
 21                     Case "Modulus"
 22                         parameters.Modulus = Convert.FromBase64String(node.InnerText)
 23                     Case "Exponent"
 24                         parameters.Exponent = Convert.FromBase64String(node.InnerText)
 25                     Case "P"
 26                         parameters.P = Convert.FromBase64String(node.InnerText)
 27                     Case "Q"
 28                         parameters.Q = Convert.FromBase64String(node.InnerText)
 29                     Case "DP"
 30                         parameters.DP = Convert.FromBase64String(node.InnerText)
 31                     Case "DQ"
 32                         parameters.DQ = Convert.FromBase64String(node.InnerText)
 33                     Case "InverseQ"
 34                         parameters.InverseQ = Convert.FromBase64String(node.InnerText)
 35                     Case "D"
 36                         parameters.D = Convert.FromBase64String(node.InnerText)
 37                 End Select
 38             Next node
 39         Else
 40             Throw New Exception("Invalid XML RSA key.")
 41         End If
 42 
 43         rsa.ImportParameters(parameters)
 44     End Sub
 45 
 46     <System.Runtime.CompilerServices.Extension>
 47     Public Function ToXml(ByVal rsa As RSA, ByVal includePrivateParameters As Boolean) As String
 48         Dim parameters As RSAParameters = rsa.ExportParameters(includePrivateParameters)
 49 
 50         Dim ret As String
 51         If includePrivateParameters Then
 52             ret = String.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent><P>{2}</P><Q>{3}</Q><DP>{4}</DP><DQ>{5}</DQ><InverseQ>{6}</InverseQ><D>{7}</D></RSAKeyValue>",
 53                                  Convert.ToBase64String(parameters.Modulus),
 54                                  Convert.ToBase64String(parameters.Exponent),
 55                                  Convert.ToBase64String(parameters.P),
 56                                  Convert.ToBase64String(parameters.Q),
 57                                  Convert.ToBase64String(parameters.DP),
 58                                  Convert.ToBase64String(parameters.DQ),
 59                                  Convert.ToBase64String(parameters.InverseQ),
 60                                  Convert.ToBase64String(parameters.D))
 61         Else
 62             ret = String.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent></RSAKeyValue>",
 63                                 Convert.ToBase64String(parameters.Modulus),
 64                                 Convert.ToBase64String(parameters.Exponent))
 65         End If
 66         Return formatXml(ret)
 67     End Function
 68 
 69     Private Function formatXml(ByVal sUnformattedXml As String) As String
 70         Dim xd As New XmlDocument()
 71         xd.LoadXml(sUnformattedXml)
 72         Dim sb As New StringBuilder()
 73         Dim sw As New StringWriter(sb)
 74         Dim xtw As XmlTextWriter = Nothing
 75         Try
 76             xtw = New XmlTextWriter(sw)
 77             xtw.Formatting = Formatting.Indented
 78             xtw.Indentation = 1
 79             xtw.IndentChar = Char.Parse(vbTab)
 80             xd.WriteTo(xtw)
 81         Finally
 82             If xtw IsNot Nothing Then
 83                 xtw.Close()
 84             End If
 85         End Try
 86         Return sb.ToString()
 87     End Function
 88 
 89     <System.Runtime.CompilerServices.Extension>
 90     Public Sub FromPem(ByVal rsa As RSA, pemString As String)
 91         Const FLAG_PUBLIC As String = "-----BEGIN PUBLIC KEY-----"
 92         Const FLAG_PRIVATE As String = "-----BEGIN PRIVATE KEY-----"
 93 
 94         Dim content As String = pemString
 95 
 96         If pemString.StartsWith(FLAG_PUBLIC) Then
 97             content = content.Replace(FLAG_PUBLIC, "").Replace("-----END PUBLIC KEY-----", "").Replace(vbCrLf, "")
 98             Dim publicKeyParam As RsaKeyParameters = PublicKeyFactory.CreateKey(Convert.FromBase64String(content))
 99             Dim xml As String = String.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent></RSAKeyValue>",
100                                               Convert.ToBase64String(publicKeyParam.Modulus.ToByteArrayUnsigned),
101                                               Convert.ToBase64String(publicKeyParam.Exponent.ToByteArrayUnsigned))
102             rsa.FromXml(xml)
103         ElseIf pemString.StartsWith(FLAG_PRIVATE) Then
104             content = content.Replace(FLAG_PRIVATE, "").Replace("-----END PRIVATE KEY-----", "").Replace(vbCrLf, "")
105             Dim privateKeyParam As RsaPrivateCrtKeyParameters = PrivateKeyFactory.CreateKey(Convert.FromBase64String(content))
106             Dim parameters As New RSAParameters() With
107                 {
108                     .Modulus = privateKeyParam.Modulus.ToByteArrayUnsigned(),
109                     .Exponent = privateKeyParam.PublicExponent.ToByteArrayUnsigned(),
110                     .P = privateKeyParam.P.ToByteArrayUnsigned(),
111                     .Q = privateKeyParam.Q.ToByteArrayUnsigned(),
112                     .DP = privateKeyParam.DP.ToByteArrayUnsigned(),
113                     .DQ = privateKeyParam.DQ.ToByteArrayUnsigned(),
114                     .InverseQ = privateKeyParam.QInv.ToByteArrayUnsigned(),
115                     .D = privateKeyParam.Exponent.ToByteArrayUnsigned()
116                 }
117             rsa.ImportParameters(parameters)
118         Else
119             Throw New ArgumentException("pemString is not validate")
120         End If
121     End Sub
122 
123     <System.Runtime.CompilerServices.Extension>
124     Public Function ToPem(ByVal rsa As RSA, ByVal includePrivateParameters As Boolean) As String
125         Dim ret As String = String.Empty
126         If includePrivateParameters Then
127             Return exportPrivateKey(rsa)
128         Else
129             Return exportPublicKey(rsa)
130         End If
131     End Function
132 
133     ''' <summary>
134     ''' 輸出PEM格式公鑰
135     ''' </summary>
136     ''' <param name="rsa"></param>
137     ''' <returns></returns>
138     Private Function exportPublicKey(ByVal rsa As RSA) As String
139         Dim outputStream As TextWriter = New StringWriter()
140 
141         Dim parameters = rsa.ExportParameters(False)
142         Using stream = New MemoryStream()
143             Dim writer = New BinaryWriter(stream)
144             writer.Write(CByte(&H30)) ' SEQUENCE
145             Using innerStream = New MemoryStream()
146                 Dim innerWriter = New BinaryWriter(innerStream)
147                 innerWriter.Write(CByte(&H30)) ' SEQUENCE
148                 encodeLength(innerWriter, 13)
149                 innerWriter.Write(CByte(&H6)) ' OBJECT IDENTIFIER
150                 Dim rsaEncryptionOid = New Byte() {&H2A, &H86, &H48, &H86, &HF7, &HD, &H1, &H1, &H1}
151                 encodeLength(innerWriter, rsaEncryptionOid.Length)
152                 innerWriter.Write(rsaEncryptionOid)
153                 innerWriter.Write(CByte(&H5)) ' NULL
154                 encodeLength(innerWriter, 0)
155                 innerWriter.Write(CByte(&H3)) ' BIT STRING
156                 Using bitStringStream = New MemoryStream()
157                     Dim bitStringWriter = New BinaryWriter(bitStringStream)
158                     bitStringWriter.Write(CByte(&H0)) ' # of unused bits
159                     bitStringWriter.Write(CByte(&H30)) ' SEQUENCE
160                     Using paramsStream = New MemoryStream()
161                         Dim paramsWriter = New BinaryWriter(paramsStream)
162                         encodeIntegerBigEndian(paramsWriter, parameters.Modulus) ' Modulus
163                         encodeIntegerBigEndian(paramsWriter, parameters.Exponent) ' Exponent
164                         Dim paramsLength = CInt(paramsStream.Length)
165                         encodeLength(bitStringWriter, paramsLength)
166                         bitStringWriter.Write(paramsStream.GetBuffer(), 0, paramsLength)
167                     End Using
168                     Dim bitStringLength = CInt(bitStringStream.Length)
169                     encodeLength(innerWriter, bitStringLength)
170                     innerWriter.Write(bitStringStream.GetBuffer(), 0, bitStringLength)
171                 End Using
172                 Dim length = CInt(innerStream.Length)
173                 encodeLength(writer, length)
174                 writer.Write(innerStream.GetBuffer(), 0, length)
175             End Using
176 
177             Dim base64 = Convert.ToBase64String(stream.GetBuffer(), 0, CInt(stream.Length)).ToCharArray()
178             outputStream.WriteLine("-----BEGIN PUBLIC KEY-----")
179             For i = 0 To base64.Length - 1 Step 64
180                 outputStream.WriteLine(base64, i, Math.Min(64, base64.Length - i))
181             Next i
182             outputStream.WriteLine("-----END PUBLIC KEY-----")
183         End Using
184 
185         Return outputStream.ToString
186     End Function
187 
188     ''' <summary>
189     ''' 輸出PEM格式私鑰
190     ''' </summary>
191     ''' <param name="rsa"></param>
192     Private Function exportPrivateKey(ByVal rsa As RSA) As String
193         'If csp.PublicOnly Then
194         '    Throw New ArgumentException("CSP does not contain a private key", "csp")
195         'End If
196 
197         Dim outputStream As TextWriter = New StringWriter()
198         Dim parameters = rsa.ExportParameters(True)
199         If parameters.D Is Nothing Then
200             Throw New ArgumentException("object does not contain a private key", "csp")
201         End If
202         Using stream = New MemoryStream()
203             Dim writer = New BinaryWriter(stream)
204             writer.Write(CByte(&H30)) ' SEQUENCE
205             Using innerStream = New MemoryStream()
206                 Dim innerWriter = New BinaryWriter(innerStream)
207                 encodeIntegerBigEndian(innerWriter, New Byte() {&H0}) ' Version
208                 encodeIntegerBigEndian(innerWriter, parameters.Modulus)
209                 encodeIntegerBigEndian(innerWriter, parameters.Exponent)
210                 encodeIntegerBigEndian(innerWriter, parameters.D)
211                 encodeIntegerBigEndian(innerWriter, parameters.P)
212                 encodeIntegerBigEndian(innerWriter, parameters.Q)
213                 encodeIntegerBigEndian(innerWriter, parameters.DP)
214                 encodeIntegerBigEndian(innerWriter, parameters.DQ)
215                 encodeIntegerBigEndian(innerWriter, parameters.InverseQ)
216                 Dim length = CInt(innerStream.Length)
217                 encodeLength(writer, length)
218                 writer.Write(innerStream.GetBuffer(), 0, length)
219             End Using
220 
221             Dim base64 = Convert.ToBase64String(stream.GetBuffer(), 0, CInt(stream.Length)).ToCharArray()
222 
223             outputStream.WriteLine("-----BEGIN RSA PRIVATE KEY-----")
224             ' Output as Base64 with lines chopped at 64 characters
225             For i = 0 To base64.Length - 1 Step 64
226                 outputStream.WriteLine(base64, i, Math.Min(64, base64.Length - i))
227             Next i
228             outputStream.WriteLine("-----END RSA PRIVATE KEY-----")
229         End Using
230 
231         Return outputStream.ToString
232     End Function
233 
234     Private Sub encodeLength(ByVal stream As BinaryWriter, ByVal length As Integer)
235         If length < 0 Then
236             Throw New ArgumentOutOfRangeException("length", "Length must be non-negative")
237         End If
238         If length < &H80 Then
239             ' Short form
240             stream.Write(CByte(length))
241         Else
242             ' Long form
243             Dim temp = length
244             Dim bytesRequired = 0
245             Do While temp > 0
246                 temp >>= 8
247                 bytesRequired += 1
248             Loop
249             stream.Write(CByte(bytesRequired Or &H80))
250             For i = bytesRequired - 1 To 0 Step -1
251                 stream.Write(CByte(length >> (8 * i) And &HFF))
252             Next i
253         End If
254     End Sub
255 
256     Private Sub encodeIntegerBigEndian(ByVal stream As BinaryWriter, ByVal value() As Byte, Optional ByVal forceUnsigned As Boolean = True)
257         stream.Write(CByte(&H2)) ' INTEGER
258         Dim prefixZeros = 0
259         For i = 0 To value.Length - 1
260             If value(i) <> 0 Then
261                 Exit For
262             End If
263             prefixZeros += 1
264         Next i
265         If value.Length - prefixZeros = 0 Then
266             encodeLength(stream, 1)
267             stream.Write(CByte(0))
268         Else
269             If forceUnsigned AndAlso value(prefixZeros) > &H7F Then
270                 ' Add a prefix zero to force unsigned if the MSB is 1
271                 encodeLength(stream, value.Length - prefixZeros + 1)
272                 stream.Write(CByte(0))
273             Else
274                 encodeLength(stream, value.Length - prefixZeros)
275             End If
276             For i = prefixZeros To value.Length - 1
277                 stream.Write(value(i))
278             Next i
279         End If
280     End Sub
281 
282 End Module
283 
284 Friend Module DotNetCoreUtilities
285     ''' <summary>
286     ''' 返回 RSA 對象的 密鑰對參數對象
287     ''' </summary>
288     ''' <param name="provider"></param>
289     ''' <returns>
290     ''' 用私鑰初始化的 RSA 對象 - 返回有效的公鑰和私鑰密鑰對
291     ''' 用公鑰初始化的 RSA 對象 - 返回 有效的公鑰 和 無效的私鑰組成的密鑰對
292     ''' </returns>
293     Public Function GetKeyPair(ByVal provider As RSA) As AsymmetricCipherKeyPair
294         Dim p As RSAParameters
295         Dim rkpPrivate As RsaKeyParameters
296 
297         Try
298             p = provider.ExportParameters(True)
299             rkpPrivate = New RsaKeyParameters(True, New BigInteger(1, p.Modulus), New BigInteger(p.D)) '//PrivateKey 實際使用
300         Catch ex As Exception
301             p = provider.ExportParameters(False)
302             rkpPrivate = New RsaKeyParameters(True, BigInteger.One, BigInteger.One) '//PrivateKey 實際不使用
303         End Try
304 
305         Dim rpkPublic As New RsaKeyParameters(False, New BigInteger(1, p.Modulus), New BigInteger(p.Exponent))
306         Dim keyPair As New AsymmetricCipherKeyPair(rpkPublic, rkpPrivate)
307         Return keyPair
308     End Function
309 
310     ''' <summary>
311     ''' 通過 PEM 格式的私鑰返回 密鑰對參數對象
312     ''' </summary>
313     ''' <param name="privateKey">PEM 格式的私鑰</param>
314     ''' <returns></returns>
315     Public Function GetKeyPair(ByVal privateKey As String) As AsymmetricCipherKeyPair
316         Dim keyPair As AsymmetricCipherKeyPair
317         Using StringReader As New StringReader(privateKey)
318             Dim pemReader = New PemReader(StringReader)
319             keyPair = CType(pemReader.ReadObject, AsymmetricCipherKeyPair)
320         End Using
321         Return keyPair
322     End Function
323 
324     ''' <summary>
325     ''' 通過 PEM 格式的公鑰返回 密鑰參數對象
326     ''' </summary>
327     ''' <param name="publicKey">PEM 格式的公鑰</param>
328     ''' <returns></returns>
329     Public Function GetKeyParmeter(ByVal publicKey As String) As AsymmetricKeyParameter
330         Dim ret As AsymmetricKeyParameter
331         Using StringReader As New StringReader(publicKey)
332             Dim pemReader = New PemReader(StringReader)
333             ret = CType(pemReader.ReadObject, AsymmetricKeyParameter)
334         End Using
335         Return ret
336     End Function
337 End Module

最後是調用代碼示例:

 1         Dim ciphertext As String = RSAHelper.PublicKeyEncryptEx(RSAHelper.PublicKey, plaintext)
 2         Console.WriteLine("===== ciphertext.Length={0}, PublicKeyEncypt Result:", ciphertext.Length)
 3         Console.WriteLine(ciphertext)
 4         Dim newData As String = RSAHelper.PrivateKeyDecryptEx(RSAHelper.PrivateKey, ciphertext)
 5         Console.WriteLine("===== PrivateKeyDecrypt Result:")
 6         Console.WriteLine(newData.Equals(plaintext))
 7         Console.WriteLine("==============================================")
 8         Console.WriteLine()
 9         ciphertext = RSAHelper.PrivateKeyEncryptEx(RSAHelper.PrivateKey, plaintext)
10         Console.WriteLine("ciphertext.Length={0}, PrivateKeyEncypt Result:", ciphertext.Length)
11         Console.WriteLine(ciphertext)
12         newData = RSAHelper.PublicKeyDecryptEx(RSAHelper.PublicKey, ciphertext)
13         Console.WriteLine("===== PublicKeyDecrypt {0}", newData.Equals(plaintext))

 

PS:如果需要與Java交換密鑰文件,可參考 https://www.cnblogs.com/wuweimin/p/7839335.html

參考文檔:

https://blog.csdn.net/u010792238/article/details/79471406

https://www.cnblogs.com/taiyonghai/p/6150353.html

 https://stackoverflow.com/questions/23734792/c-sharp-export-private-public-rsa-key-from-rsacryptoserviceprovider-to-pem-strin/25591659#25591659

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章