可用的 .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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现