在使用 public 密钥在 php 中加密后,如何使用私钥在 c# 中以块的形式解密数据?
How can I decrypt data in chunks in c# using a private key after encrypting in php using a public key?
如何在 C# 中使用私钥(pem 格式)解密此代码的输出?
$output = json_encode(array('see'=>'me'));
define('CIPHER_BLOCK_SIZE', 100);
$encrypted = '';
$key = file_get_contents('public.txt');
$chunks = str_split($output, CIPHER_BLOCK_SIZE);
foreach($chunks as $chunk)
{
$chunkEncrypted = '';
$valid = openssl_public_encrypt($chunk, $chunkEncrypted, $key, OPENSSL_PKCS1_PADDING);
if($valid === false){
$encrypted = '';
break; //also you can return and error. If too big this will be false
} else {
$encrypted .= $chunkEncrypted;
}
}
$output = base64_encode($encrypted); //encoding the whole binary String as MIME base 64
echo $output;
Click here for a large json sample ready formatted 替换上面示例中的以下行,测试分块,因为上面的 $output
json 太小分块无法生效。
$output = json_encode(array('see'=>'me'));
解释上面代码的作用
以上代码是对 this solution 的修改,它将数据分成更小的块(每个块 100 字节)并使用 pem 格式的 public 密钥对其进行加密。
Objective
我正在考虑加密大于几个字节的数据以更安全地传输数据,并且发现 encrypting/decrypting 使用证书是最佳途径。
目的是加密 php 中的数据(使用私钥),然后在用 C# 编写的应用程序中接收并解密(使用 public 密钥)。
C# - 到目前为止的道路
以下是我在 C# 中解密的尝试:
用法:
// location of private certificate
string key = @"C:\path\to\private.txt";
// output from php script (encrypted)
string encrypted = "Bdm4s7aw.....Pvlzg=";
// decrypt and store decrypted string
string decrypted = crypt.decrypt( encrypted, key );
Class :
public static string decrypt(string encrypted, string privateKey) {
try {
RSACryptoServiceProvider rsa = DecodePrivateKeyInfo( DecodePkcs8PrivateKey( File.ReadAllText( privateKey ) ) );
return Encoding.UTF8.GetString( rsa.Decrypt( Convert.FromBase64String( encrypted ), false ) );
} catch (CryptographicException ce) {
return ce.Message;
} catch (FormatException fe) {
return fe.Message;
} catch (IOException ie) {
return ie.Message;
} catch (Exception e) {
return e.Message;
}
}
这取决于其他方法(从 opensslkey.cs 中获取)
//-------- Get the binary PKCS #8 PRIVATE key --------
private static byte[] DecodePkcs8PrivateKey( string instr ) {
const string pemp8header = "-----BEGIN PRIVATE KEY-----";
const string pemp8footer = "-----END PRIVATE KEY-----";
string pemstr = instr.Trim();
byte[] binkey;
if ( !pemstr.StartsWith( pemp8header ) || !pemstr.EndsWith( pemp8footer ) )
return null;
StringBuilder sb = new StringBuilder( pemstr );
sb.Replace( pemp8header, "" ); //remove headers/footers, if present
sb.Replace( pemp8footer, "" );
string pubstr = sb.ToString().Trim(); //get string after removing leading/trailing whitespace
try {
binkey = Convert.FromBase64String( pubstr );
} catch ( FormatException ) { //if can't b64 decode, data is not valid
return null;
}
return binkey;
}
//------- Parses binary asn.1 PKCS #8 PrivateKeyInfo; returns RSACryptoServiceProvider ---
private static RSACryptoServiceProvider DecodePrivateKeyInfo( byte[] pkcs8 ) {
// encoded OID sequence for PKCS #1 rsaEncryption szOID_RSA_RSA = "1.2.840.113549.1.1.1"
// this byte[] includes the sequence byte and terminal encoded null
byte[] SeqOID = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 };
byte[] seq = new byte[15];
// --------- Set up stream to read the asn.1 encoded SubjectPublicKeyInfo blob ------
MemoryStream mem = new MemoryStream( pkcs8 );
int lenstream = (int)mem.Length;
BinaryReader binr = new BinaryReader( mem ); //wrap Memory Stream with BinaryReader for easy reading
byte bt = 0;
ushort twobytes = 0;
try {
twobytes = binr.ReadUInt16();
if ( twobytes == 0x8130 ) //data read as little endian order (actual data order for Sequence is 30 81)
binr.ReadByte(); //advance 1 byte
else if ( twobytes == 0x8230 )
binr.ReadInt16(); //advance 2 bytes
else
return null;
bt = binr.ReadByte();
if ( bt != 0x02 )
return null;
twobytes = binr.ReadUInt16();
if ( twobytes != 0x0001 )
return null;
seq = binr.ReadBytes( 15 ); //read the Sequence OID
if ( !CompareBytearrays( seq, SeqOID ) ) //make sure Sequence for OID is correct
return null;
bt = binr.ReadByte();
if ( bt != 0x04 ) //expect an Octet string
return null;
bt = binr.ReadByte(); //read next byte, or next 2 bytes is 0x81 or 0x82; otherwise bt is the byte count
if ( bt == 0x81 )
binr.ReadByte();
else
if ( bt == 0x82 )
binr.ReadUInt16();
//------ at this stage, the remaining sequence should be the RSA private key
byte[] rsaprivkey = binr.ReadBytes( (int)( lenstream - mem.Position ) );
RSACryptoServiceProvider rsacsp = DecodeRSAPrivateKey( rsaprivkey );
return rsacsp;
} catch ( Exception ) {
return null;
} finally { binr.Close(); }
}
//------- Parses binary ans.1 RSA private key; returns RSACryptoServiceProvider ---
private static RSACryptoServiceProvider DecodeRSAPrivateKey( byte[] privkey ) {
byte[] MODULUS, E, D, P, Q, DP, DQ, IQ;
// --------- Set up stream to decode the asn.1 encoded RSA private key ------
MemoryStream mem = new MemoryStream( privkey );
BinaryReader binr = new BinaryReader( mem ); //wrap Memory Stream with BinaryReader for easy reading
byte bt = 0;
ushort twobytes = 0;
int elems = 0;
try {
twobytes = binr.ReadUInt16();
if ( twobytes == 0x8130 ) //data read as little endian order (actual data order for Sequence is 30 81)
binr.ReadByte(); //advance 1 byte
else if ( twobytes == 0x8230 )
binr.ReadInt16(); //advance 2 bytes
else
return null;
twobytes = binr.ReadUInt16();
if ( twobytes != 0x0102 ) //version number
return null;
bt = binr.ReadByte();
if ( bt != 0x00 )
return null;
//------ all private key components are Integer sequences ----
elems = GetIntegerSize( binr );
MODULUS = binr.ReadBytes( elems );
elems = GetIntegerSize( binr );
E = binr.ReadBytes( elems );
elems = GetIntegerSize( binr );
D = binr.ReadBytes( elems );
elems = GetIntegerSize( binr );
P = binr.ReadBytes( elems );
elems = GetIntegerSize( binr );
Q = binr.ReadBytes( elems );
elems = GetIntegerSize( binr );
DP = binr.ReadBytes( elems );
elems = GetIntegerSize( binr );
DQ = binr.ReadBytes( elems );
elems = GetIntegerSize( binr );
IQ = binr.ReadBytes( elems );
// ------- create RSACryptoServiceProvider instance and initialize with public key -----
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
RSAParameters RSAparams = new RSAParameters();
RSAparams.Modulus = MODULUS;
RSAparams.Exponent = E;
RSAparams.D = D;
RSAparams.P = P;
RSAparams.Q = Q;
RSAparams.DP = DP;
RSAparams.DQ = DQ;
RSAparams.InverseQ = IQ;
RSA.ImportParameters( RSAparams );
return RSA;
} catch ( Exception ) {
return null;
} finally { binr.Close(); }
}
private static int GetIntegerSize( BinaryReader binr ) {
byte bt = 0;
byte lowbyte = 0x00;
byte highbyte = 0x00;
int count = 0;
bt = binr.ReadByte();
if ( bt != 0x02 ) //expect integer
return 0;
bt = binr.ReadByte();
if ( bt == 0x81 )
count = binr.ReadByte(); // data size in next byte
else
if ( bt == 0x82 ) {
highbyte = binr.ReadByte(); // data size in next 2 bytes
lowbyte = binr.ReadByte();
byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };
count = BitConverter.ToInt32( modint, 0 );
} else {
count = bt; // we already have the data size
}
while ( binr.ReadByte() == 0x00 ) { //remove high order zeros in data
count -= 1;
}
binr.BaseStream.Seek( -1, SeekOrigin.Current ); //last ReadByte wasn't a removed zero, so back up a byte
return count;
}
private static bool CompareBytearrays( byte[] a, byte[] b ) {
if ( a.Length != b.Length )
return false;
int i = 0;
foreach ( byte c in a ) {
if ( c != b[i] )
return false;
i++;
}
return true;
}
现在一切正常,但它仍然没有在解密过程中合并分块。
我必须做些什么才能读入这些块,因为更大的文件肯定会比原始的未加密数据大。
我之前的尝试是尝试类似下面的代码,但这似乎有缺陷,因为它总是填充 100 个字节(即使总字节数较少),并且 json_encode(array('see'=>'me'))
的 base64 解码使用我当前的 public 加密密钥最终为 512 字节。
byte[] buffer = new byte[100]; // the number of bytes to decrypt at a time
int bytesReadTotal = 0;
int bytesRead = 0;
string decrypted = "";
byte[] decryptedBytes;
using ( Stream stream = new MemoryStream( data ) ) {
while ( ( bytesRead = await stream.ReadAsync( buffer, bytesReadTotal, 100 ) ) > 0 ) {
decryptedBytes = rsa.Decrypt( buffer, false );
bytesReadTotal = bytesReadTotal + bytesRead;
decrypted = decrypted + Encoding.UTF8.GetString( decryptedBytes );
}
}
return decrypted;
为了方便起见,我在 tehplayground.com.
上为 generate a public and private key to test with 提供了一个 php 脚本
在与问题作者进行广泛交谈后,似乎代码中有两个(主要)问题阻止了它的工作:
未读取 public 密钥,因为 code from this Whosebug solution 实际上不会创建二进制 public 密钥,而是创建证书。为此,可以使用 X509Certificate
构造函数,然后使用 GetPublicKey
。 Whosebug 解决方案中的方法应该以不同的方式命名。这后来更改为私钥(因为使用 public 密钥解密不提供机密性)。
加密块大小为 100 字节,而密钥大小为 4096 位(512 字节)。但是 RSA(如 PKCS#1 v2.1 中针对 PKCS#1 v1.5 填充指定的那样)总是 加密为以字节为单位的 RSA 密钥大小(模数大小)。所以解密的输入也应该是 512 字节的块。但是,如果加密(在 PHP 代码中),输出将是 100 字节。
为了使这项工作有效,需要进行小的修改以循环遍历基于 KeySize / 8
计算的块中加密数据的 base64 解码字节(其中 8 是一个字节中的多少位,因为 KeySize 是一个int
表示每个块有多少字节的值。
public static async Task<string> decrypt(string encrypted, string privateKey) {
// read private certificate into RSACryptoServiceProvider from file
RSACryptoServiceProvider rsa = DecodePrivateKeyInfo( DecodePkcs8PrivateKey( File.ReadAllText( privateKey ) ) );
// decode base64 to bytes
byte[] encryptedBytes = Convert.FromBase64String( encrypted );
int bufferSize = (int)(rsa.KeySize / 8);
// initialize byte buffer based on certificate block size
byte[] buffer = new byte[bufferSize]; // the number of bytes to decrypt at a time
int bytesReadTotal = 0; int bytesRead = 0;
string decrypted = ""; byte[] decryptedBytes;
// convert byte array to stream
using ( Stream stream = new MemoryStream( encryptedBytes ) ) {
// loop through stream for each block of 'bufferSize'
while ( ( bytesRead = await stream.ReadAsync( buffer, bytesReadTotal, bufferSize ) ) > 0 ) {
// decrypt this chunk
decryptedBytes = rsa.Decrypt( buffer, false );
// account for bytes read & decrypted
bytesReadTotal = bytesReadTotal + bytesRead;
// append decrypted data as string for return
decrypted = decrypted + Encoding.UTF8.GetString( decryptedBytes );
}
}
return decrypted;
}
安全说明:
- PKCS#1 v1.5 padding 容易受到 padding oracle 攻击,最好确保您不允许这些攻击,尤其是在传输协议中(或改用更新的 OAEP padding);
- 在使用之前信任您的 public 密钥,否则可能会发生中间人攻击。
如何在 C# 中使用私钥(pem 格式)解密此代码的输出?
$output = json_encode(array('see'=>'me'));
define('CIPHER_BLOCK_SIZE', 100);
$encrypted = '';
$key = file_get_contents('public.txt');
$chunks = str_split($output, CIPHER_BLOCK_SIZE);
foreach($chunks as $chunk)
{
$chunkEncrypted = '';
$valid = openssl_public_encrypt($chunk, $chunkEncrypted, $key, OPENSSL_PKCS1_PADDING);
if($valid === false){
$encrypted = '';
break; //also you can return and error. If too big this will be false
} else {
$encrypted .= $chunkEncrypted;
}
}
$output = base64_encode($encrypted); //encoding the whole binary String as MIME base 64
echo $output;
Click here for a large json sample ready formatted 替换上面示例中的以下行,测试分块,因为上面的 $output
json 太小分块无法生效。
$output = json_encode(array('see'=>'me'));
解释上面代码的作用
以上代码是对 this solution 的修改,它将数据分成更小的块(每个块 100 字节)并使用 pem 格式的 public 密钥对其进行加密。
Objective
我正在考虑加密大于几个字节的数据以更安全地传输数据,并且发现 encrypting/decrypting 使用证书是最佳途径。
目的是加密 php 中的数据(使用私钥),然后在用 C# 编写的应用程序中接收并解密(使用 public 密钥)。
C# - 到目前为止的道路
以下是我在 C# 中解密的尝试:
用法:
// location of private certificate
string key = @"C:\path\to\private.txt";
// output from php script (encrypted)
string encrypted = "Bdm4s7aw.....Pvlzg=";
// decrypt and store decrypted string
string decrypted = crypt.decrypt( encrypted, key );
Class :
public static string decrypt(string encrypted, string privateKey) {
try {
RSACryptoServiceProvider rsa = DecodePrivateKeyInfo( DecodePkcs8PrivateKey( File.ReadAllText( privateKey ) ) );
return Encoding.UTF8.GetString( rsa.Decrypt( Convert.FromBase64String( encrypted ), false ) );
} catch (CryptographicException ce) {
return ce.Message;
} catch (FormatException fe) {
return fe.Message;
} catch (IOException ie) {
return ie.Message;
} catch (Exception e) {
return e.Message;
}
}
这取决于其他方法(从 opensslkey.cs 中获取)
//-------- Get the binary PKCS #8 PRIVATE key --------
private static byte[] DecodePkcs8PrivateKey( string instr ) {
const string pemp8header = "-----BEGIN PRIVATE KEY-----";
const string pemp8footer = "-----END PRIVATE KEY-----";
string pemstr = instr.Trim();
byte[] binkey;
if ( !pemstr.StartsWith( pemp8header ) || !pemstr.EndsWith( pemp8footer ) )
return null;
StringBuilder sb = new StringBuilder( pemstr );
sb.Replace( pemp8header, "" ); //remove headers/footers, if present
sb.Replace( pemp8footer, "" );
string pubstr = sb.ToString().Trim(); //get string after removing leading/trailing whitespace
try {
binkey = Convert.FromBase64String( pubstr );
} catch ( FormatException ) { //if can't b64 decode, data is not valid
return null;
}
return binkey;
}
//------- Parses binary asn.1 PKCS #8 PrivateKeyInfo; returns RSACryptoServiceProvider ---
private static RSACryptoServiceProvider DecodePrivateKeyInfo( byte[] pkcs8 ) {
// encoded OID sequence for PKCS #1 rsaEncryption szOID_RSA_RSA = "1.2.840.113549.1.1.1"
// this byte[] includes the sequence byte and terminal encoded null
byte[] SeqOID = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 };
byte[] seq = new byte[15];
// --------- Set up stream to read the asn.1 encoded SubjectPublicKeyInfo blob ------
MemoryStream mem = new MemoryStream( pkcs8 );
int lenstream = (int)mem.Length;
BinaryReader binr = new BinaryReader( mem ); //wrap Memory Stream with BinaryReader for easy reading
byte bt = 0;
ushort twobytes = 0;
try {
twobytes = binr.ReadUInt16();
if ( twobytes == 0x8130 ) //data read as little endian order (actual data order for Sequence is 30 81)
binr.ReadByte(); //advance 1 byte
else if ( twobytes == 0x8230 )
binr.ReadInt16(); //advance 2 bytes
else
return null;
bt = binr.ReadByte();
if ( bt != 0x02 )
return null;
twobytes = binr.ReadUInt16();
if ( twobytes != 0x0001 )
return null;
seq = binr.ReadBytes( 15 ); //read the Sequence OID
if ( !CompareBytearrays( seq, SeqOID ) ) //make sure Sequence for OID is correct
return null;
bt = binr.ReadByte();
if ( bt != 0x04 ) //expect an Octet string
return null;
bt = binr.ReadByte(); //read next byte, or next 2 bytes is 0x81 or 0x82; otherwise bt is the byte count
if ( bt == 0x81 )
binr.ReadByte();
else
if ( bt == 0x82 )
binr.ReadUInt16();
//------ at this stage, the remaining sequence should be the RSA private key
byte[] rsaprivkey = binr.ReadBytes( (int)( lenstream - mem.Position ) );
RSACryptoServiceProvider rsacsp = DecodeRSAPrivateKey( rsaprivkey );
return rsacsp;
} catch ( Exception ) {
return null;
} finally { binr.Close(); }
}
//------- Parses binary ans.1 RSA private key; returns RSACryptoServiceProvider ---
private static RSACryptoServiceProvider DecodeRSAPrivateKey( byte[] privkey ) {
byte[] MODULUS, E, D, P, Q, DP, DQ, IQ;
// --------- Set up stream to decode the asn.1 encoded RSA private key ------
MemoryStream mem = new MemoryStream( privkey );
BinaryReader binr = new BinaryReader( mem ); //wrap Memory Stream with BinaryReader for easy reading
byte bt = 0;
ushort twobytes = 0;
int elems = 0;
try {
twobytes = binr.ReadUInt16();
if ( twobytes == 0x8130 ) //data read as little endian order (actual data order for Sequence is 30 81)
binr.ReadByte(); //advance 1 byte
else if ( twobytes == 0x8230 )
binr.ReadInt16(); //advance 2 bytes
else
return null;
twobytes = binr.ReadUInt16();
if ( twobytes != 0x0102 ) //version number
return null;
bt = binr.ReadByte();
if ( bt != 0x00 )
return null;
//------ all private key components are Integer sequences ----
elems = GetIntegerSize( binr );
MODULUS = binr.ReadBytes( elems );
elems = GetIntegerSize( binr );
E = binr.ReadBytes( elems );
elems = GetIntegerSize( binr );
D = binr.ReadBytes( elems );
elems = GetIntegerSize( binr );
P = binr.ReadBytes( elems );
elems = GetIntegerSize( binr );
Q = binr.ReadBytes( elems );
elems = GetIntegerSize( binr );
DP = binr.ReadBytes( elems );
elems = GetIntegerSize( binr );
DQ = binr.ReadBytes( elems );
elems = GetIntegerSize( binr );
IQ = binr.ReadBytes( elems );
// ------- create RSACryptoServiceProvider instance and initialize with public key -----
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
RSAParameters RSAparams = new RSAParameters();
RSAparams.Modulus = MODULUS;
RSAparams.Exponent = E;
RSAparams.D = D;
RSAparams.P = P;
RSAparams.Q = Q;
RSAparams.DP = DP;
RSAparams.DQ = DQ;
RSAparams.InverseQ = IQ;
RSA.ImportParameters( RSAparams );
return RSA;
} catch ( Exception ) {
return null;
} finally { binr.Close(); }
}
private static int GetIntegerSize( BinaryReader binr ) {
byte bt = 0;
byte lowbyte = 0x00;
byte highbyte = 0x00;
int count = 0;
bt = binr.ReadByte();
if ( bt != 0x02 ) //expect integer
return 0;
bt = binr.ReadByte();
if ( bt == 0x81 )
count = binr.ReadByte(); // data size in next byte
else
if ( bt == 0x82 ) {
highbyte = binr.ReadByte(); // data size in next 2 bytes
lowbyte = binr.ReadByte();
byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };
count = BitConverter.ToInt32( modint, 0 );
} else {
count = bt; // we already have the data size
}
while ( binr.ReadByte() == 0x00 ) { //remove high order zeros in data
count -= 1;
}
binr.BaseStream.Seek( -1, SeekOrigin.Current ); //last ReadByte wasn't a removed zero, so back up a byte
return count;
}
private static bool CompareBytearrays( byte[] a, byte[] b ) {
if ( a.Length != b.Length )
return false;
int i = 0;
foreach ( byte c in a ) {
if ( c != b[i] )
return false;
i++;
}
return true;
}
现在一切正常,但它仍然没有在解密过程中合并分块。
我必须做些什么才能读入这些块,因为更大的文件肯定会比原始的未加密数据大。
我之前的尝试是尝试类似下面的代码,但这似乎有缺陷,因为它总是填充 100 个字节(即使总字节数较少),并且 json_encode(array('see'=>'me'))
的 base64 解码使用我当前的 public 加密密钥最终为 512 字节。
byte[] buffer = new byte[100]; // the number of bytes to decrypt at a time
int bytesReadTotal = 0;
int bytesRead = 0;
string decrypted = "";
byte[] decryptedBytes;
using ( Stream stream = new MemoryStream( data ) ) {
while ( ( bytesRead = await stream.ReadAsync( buffer, bytesReadTotal, 100 ) ) > 0 ) {
decryptedBytes = rsa.Decrypt( buffer, false );
bytesReadTotal = bytesReadTotal + bytesRead;
decrypted = decrypted + Encoding.UTF8.GetString( decryptedBytes );
}
}
return decrypted;
为了方便起见,我在 tehplayground.com.
上为 generate a public and private key to test with 提供了一个 php 脚本在与问题作者进行广泛交谈后,似乎代码中有两个(主要)问题阻止了它的工作:
未读取 public 密钥,因为 code from this Whosebug solution 实际上不会创建二进制 public 密钥,而是创建证书。为此,可以使用
X509Certificate
构造函数,然后使用GetPublicKey
。 Whosebug 解决方案中的方法应该以不同的方式命名。这后来更改为私钥(因为使用 public 密钥解密不提供机密性)。加密块大小为 100 字节,而密钥大小为 4096 位(512 字节)。但是 RSA(如 PKCS#1 v2.1 中针对 PKCS#1 v1.5 填充指定的那样)总是 加密为以字节为单位的 RSA 密钥大小(模数大小)。所以解密的输入也应该是 512 字节的块。但是,如果加密(在 PHP 代码中),输出将是 100 字节。
为了使这项工作有效,需要进行小的修改以循环遍历基于 KeySize / 8
计算的块中加密数据的 base64 解码字节(其中 8 是一个字节中的多少位,因为 KeySize 是一个int
表示每个块有多少字节的值。
public static async Task<string> decrypt(string encrypted, string privateKey) {
// read private certificate into RSACryptoServiceProvider from file
RSACryptoServiceProvider rsa = DecodePrivateKeyInfo( DecodePkcs8PrivateKey( File.ReadAllText( privateKey ) ) );
// decode base64 to bytes
byte[] encryptedBytes = Convert.FromBase64String( encrypted );
int bufferSize = (int)(rsa.KeySize / 8);
// initialize byte buffer based on certificate block size
byte[] buffer = new byte[bufferSize]; // the number of bytes to decrypt at a time
int bytesReadTotal = 0; int bytesRead = 0;
string decrypted = ""; byte[] decryptedBytes;
// convert byte array to stream
using ( Stream stream = new MemoryStream( encryptedBytes ) ) {
// loop through stream for each block of 'bufferSize'
while ( ( bytesRead = await stream.ReadAsync( buffer, bytesReadTotal, bufferSize ) ) > 0 ) {
// decrypt this chunk
decryptedBytes = rsa.Decrypt( buffer, false );
// account for bytes read & decrypted
bytesReadTotal = bytesReadTotal + bytesRead;
// append decrypted data as string for return
decrypted = decrypted + Encoding.UTF8.GetString( decryptedBytes );
}
}
return decrypted;
}
安全说明:
- PKCS#1 v1.5 padding 容易受到 padding oracle 攻击,最好确保您不允许这些攻击,尤其是在传输协议中(或改用更新的 OAEP padding);
- 在使用之前信任您的 public 密钥,否则可能会发生中间人攻击。