zoukankan      html  css  js  c++  java
  • 可用的 .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

  • 相关阅读:
    MVC 与传统的 webform 的比较
    Visual Studio 类模板的修改
    2015-3-3
    SQL SERVER类型与C#类型对照
    数据库连接串的配置
    Could not load file or assembly 'System.Web.Mvc' or one of its dependencies. The located assembly's manifest definition does not
    多条查询sql语句返回多表数据集
    URL和搜索引擎优化
    XPath 语法示例
    如何把数据库的某个字段更新为另一个字段
  • 原文地址:https://www.cnblogs.com/towerbit/p/11525987.html
Copyright © 2011-2022 走看看