Ho bisogno di crittografare i dati in C# per passarlo a Java. Il codice Java appartiene a una terza parte, ma mi è stata data la fonte pertinente, quindi ho deciso che siccome Java usa le librerie Bouncy Castle, userò la porta C#.C# BouncyCastle - Crittografia RSA con chiavi pubbliche/private
La decifratura funziona correttamente. Tuttavia, la decrittografia funziona solo quando utilizzo la crittografia utilizzando la chiave privata e non con la chiave pubblica. Quando si utilizza la chiave pubblica, la decifratura fallisce con unknown block type
.
Ovviamente la crittografia all'interno del RsaEncryptWithPrivate
utilizza la chiave pubblica per crittografare, quindi non capisco il motivo per cui i due metodi di crittografia non sono funzionalmente identici:
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Encodings;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.OpenSsl;
public class EncryptionClass
{
public string RsaEncryptWithPublic(string clearText
, string publicKey)
{
var bytesToEncrypt = Encoding.UTF8.GetBytes(clearText);
var encryptEngine = new Pkcs1Encoding(new RsaEngine());
using (var txtreader = new StringReader(publicKey))
{
var keyParameter = (AsymmetricKeyParameter)new PemReader(txtreader).ReadObject();
encryptEngine.Init(true, keyParameter);
}
var encrypted = Convert.ToBase64String(encryptEngine.ProcessBlock(bytesToEncrypt, 0, bytesToEncrypt.Length));
return encrypted;
}
public string RsaEncryptWithPrivate(string clearText
, string privateKey)
{
var bytesToEncrypt = Encoding.UTF8.GetBytes(clearText);
var encryptEngine = new Pkcs1Encoding(new RsaEngine());
using (var txtreader = new StringReader(privateKey))
{
var keyPair = (AsymmetricCipherKeyPair)new PemReader(txtreader).ReadObject();
encryptEngine.Init(true, keyPair.Public);
}
var encrypted= Convert.ToBase64String(encryptEngine.ProcessBlock(bytesToEncrypt, 0, bytesToEncrypt.Length));
return encrypted;
}
// Decryption:
public string RsaDecrypt(string base64Input
, string privateKey)
{
var bytesToDecrypt = Convert.FromBase64String(base64Input);
//get a stream from the string
AsymmetricCipherKeyPair keyPair;
var decryptEngine = new Pkcs1Encoding(new RsaEngine());
using (var txtreader = new StringReader(privateKey))
{
keyPair = (AsymmetricCipherKeyPair) new PemReader(txtreader).ReadObject();
decryptEngine.Init(false, keyPair.Private);
}
var decrypted = Encoding.UTF8.GetString(decryptEngine.ProcessBlock(bytesToDecrypt, 0, bytesToDecrypt.Length));
return decrypted;
}
}
// In my test project
[Test()]
public void EncryptTest()
{
// Set up
var input = "Perceived determine departure explained no forfeited";
var enc = new EncryptionClass();
var publicKey = "-----BEGIN PUBLIC KEY----- // SNIPPED // -----END PUBLIC KEY-----";
var privateKey = "-----BEGIN PRIVATE KEY----- // SNIPPED // -----END PRIVATE KEY-----";
// Encrypt it
var encryptedWithPublic = enc.RsaEncryptWithPublic(input, publicKey);
var encryptedWithPrivate = enc.RsaEncryptWithPrivate(input, privateKey);
// Decrypt
var outputWithPublic = payUEnc.RsaDecrypt(encryptedWithPrivate, privateKey);
// Throws error: "unknown block type"
var outputWithPrivate = payUEnc.RsaDecrypt(encryptedWithPrivate, _privateKey);
// returns the correct decrypted text, "Perceived determine departure explained no forfeited"
// Assertion
Assert.AreEqual(outputWithPrivate, input); // This is true
}
Per inciso la decrittografia Java presenta lo stesso problema - quando criptato con la sola chiave pubblica, fallisce.
Sono molto nuovo alla crittografia, quindi sono sicuro che sto facendo qualcosa di molto semplice nel metodo RsaEncryptWithPublic
.
EDIT:
Ho anche aggiunto una prova di unità che dimostra che la chiave pubblica è uguale alla chiave pubblica che viene estratto dalla chiave privata:
[Test()]
public void EncryptCompareTest()
{
AsymmetricKeyParameter keyParameterFromPub;
AsymmetricKeyParameter keyParameterFromPriv;
AsymmetricCipherKeyPair keyPair;
using (var txtreader = new StringReader(_publicKey))
{
keyParameterFromPub = (AsymmetricKeyParameter)new PemReader(txtreader).ReadObject();
}
using (var txtreader = new StringReader(_privateKey))
{
keyPair = (AsymmetricCipherKeyPair)new PemReader(txtreader).ReadObject();
keyParameterFromPriv = keyPair.Public;
}
Assert.AreEqual(keyParameterFromPub, keyParameterFromPriv); // returns true;
}
Stavo usando una chiave pubblica errata .. e il test che ha provato che le chiavi private e pubbliche corrispondevano stava usando la chiave pubblica corretta. Il codice a \ bove funziona perfettamente come è, a patto che tu abbia le chiavi giuste! – scudsucker