symmetric decryption throwing error - c#

I'm working on adding the ability to decrypt a file encrypted using GPG & Symmetric Encryption.
However whenever it tries to get the private key data this exceptions keeps getting hit:
Unable to cast object of type 'Org.BouncyCastle.Bcpg.OpenPgp.PgpPbeEncryptedData' to type 'Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyEncryptedData'.
everywhere I look this is how you do it:
Stream inputStream = IoHelper.GetStream(inputData);
PgpObjectFactory pgpFactory = new PgpObjectFactory(PgpUtilities.GetDecoderStream(inputStream));
PgpObject pgp = null;
if (pgpFactory != null)
{
pgp = pgpFactory.NextPgpObject();
}
PgpEncryptedDataList encryptedData = null;
if (pgp is PgpEncryptedDataList)
{
encryptedData = (PgpEncryptedDataList)pgp;
}
else
{
encryptedData = (PgpEncryptedDataList)pgpFactory.NextPgpObject();
}
Stream privateKeyStream = File.OpenRead(PrivateKeyOnlyPath);
// find secret key
PgpSecretKeyRingBundle pgpKeyRing = new PgpSecretKeyRingBundle(PgpUtilities.GetDecoderStream(privateKeyStream));
PgpPrivateKey privateKey = null;
foreach (PgpPublicKeyEncryptedData pked in encryptedData.GetEncryptedDataObjects())
{
privateKey = FindSecretKey(pgpKeyRing, pked.KeyId, Password.ToCharArray());
if (privateKey != null)
{
//pubKeyData = pked;
break;
}
}
I'm referencing the code from here
I'm lost on why it's not working and not sure where to go next.

Hybrid Cryptosystems
The "normal" way of encryption in OpenPGP (which GnuPG implements) is hybrid encryption: public/private key cryptography for key management and encrypting a session key, and subsequently symmetric encryption using this session key of the actual data.
From what you write, it seems the public/private key cryptography step was omitted, and the session key instead generated using a passphrase, for example by using the command gpg --symmetric. You can determine how it was encrypted using pgpdump. Output for a symmetrically encrypted file looks like
Old: Symmetric-Key Encrypted Session Key Packet(tag 3)(13 bytes)
New version(4)
Sym alg - CAST5(sym 3)
Iterated and salted string-to-key(s2k 3):
Hash alg - SHA512(hash 10)
Salt - 3b be 1b 03 64 c3 bb 7e
Count - 102400(coded count 105)
New: Symmetrically Encrypted Data Packet(tag 9)(26 bytes)
Encrypted data [sym alg is specified in sym-key encrypted session key]
Especially consider the first line with the symmetric-key encrypted session key packet.
What to do
I'm sorry I do not really know C#, and neither have worked with Bouncy Castle yet, so I cannot provide a ready-to-run solution. Moreover, the C# documentation seems to be more or less inexistent.
I'd guess you'll have to make use of the PgpPbeEncryptedData class, which seems to take an input stream and a passphrase and provides the decrypted information as an output stream. There is an example for the Java Bouncy Castle package, which will probably be very similar and mostly boils down to
byte[] decryptedAgainByteArray = ByteArrayHandler.decrypt(encryptedAgain, PASS.toCharArray());

Related

RSA Decryption exception: The length of the data to decrypt is not valid for the size of this key

I have got an Angular + Net Core application with an (RSA + AES) encrypted connection.
All requests from client are coming via POST. (You will be given an example below.
The script provided below works quite well but throws in 5% cases an exception:
The length of the data to decrypt is not valid for the size of this key
in the line:
var decryptedAesKey = Encoding.UTF8.GetString(rsaCng.Decrypt(Convert.FromBase64String(request.k), RSAEncryptionPadding.Pkcs1));
Encryption part (Front-end)
encrypt(requestObj:any):any {
var rsaEncrypt = new JsEncryptModule.JSEncrypt();
var key = this.generateAesKey(32); //secret key
var iv = this.generateAesKey(16); //16 digit
var stringifiedRequest = CryptoJS.enc.Utf8.parse(JSON.stringify(requestObj));
var aesEncryptedRequest = CryptoJS.AES.encrypt(stringifiedRequest,
CryptoJS.enc.Utf8.parse(key),
{
keySize: 128 / 8,
iv: CryptoJS.enc.Utf8.parse(iv),
padding: CryptoJS.pad.Pkcs7,
mode: CryptoJS.mode.CBC
});
rsaEncrypt.setPrivateKey(this.publicPemKey);
var encryptedKey = rsaEncrypt.encrypt(key);
var encryptedIV = rsaEncrypt.encrypt(iv);
var encryptedRequestObj = {
k: encryptedKey,
v: encryptedIV,
r: aesEncryptedRequest.toString()
};
return encryptedRequestObj;
}
Decryption part (C# Back-end)
var decryptedAesKey = Encoding.UTF8.GetString(rsaCng.Decrypt(Convert.FromBase64String(request.k),
RSAEncryptionPadding.Pkcs1));
var decryptedAesIV = Encoding.UTF8.GetString(rsaCng.Decrypt(Convert.FromBase64String(request.v), RSAEncryptionPadding.Pkcs1));
byte[] encryptedBytes = request.r;
AesCryptoServiceProvider aes = new AesCryptoServiceProvider()
{
Mode = CipherMode.CBC,
Padding = PaddingMode.PKCS7,
Key = Encoding.UTF8.GetBytes(decryptedAesKey),
IV = Encoding.UTF8.GetBytes(decryptedAesIV)
};
ICryptoTransform crypto = aes.CreateDecryptor(aes.Key, aes.IV);
byte[] secret = crypto.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
crypto.Dispose();
requestJson = Encoding.UTF8.GetString(secret);
Example, a user wants to open a page by id.
Front-end:
1) encrypts request Id using AES
2) encrypts AES' key & iv using RSA
3) sends to Back-end
Back-end:
1) decrypts AES' key & value using RSA <--- BREAKS HERE
2) decrypts request Id using AES' key & iv
3) decrypts and get id as if there was no encryption
This logic works quite well but breaks sometimes...
EXAMPLE OF FAILING request:
{ "k":"L+ikMb/JGvFJmhBpADMGTVLFlkHOe69dZUVSQ5r7yHCvWSwY2x6KMR274ByflF0lDMYdCmywo+Nfq6JUybRctDqmAp8UFHXnhwBAv49d99mF5x2yGbJr/j0cn6EZyhweNK4p97i5yMM6MQtluZTIErpsUa22Cajtj8F+xl0jJPUMXIf8cs2X+ooFr5VP/p/vlbPmnEY3K/hMCRZRdXMkEqaCWoA5EnYMTQABtRXPZWgLSQwJpr4dqEAhGCBtga1AGsKF3dQCsKO92NYyst0ngkBiKwFNfy1QDwbk4SzKAKeBckaY17SHt526NMvpEv08BGV6btBxcM+ypsmpB4o0",
"v":"LIndJOjUgKHDlXqwpg7uSmDuut3oi5z9L/GKm2KgU7P2EXmf/JIpXM0JgpTXPJL7wUTndq3F9UMlMdU70JBOV56x/4uIBRbHbyvaG2JZYxbBZblwyYgdo1ZcK1OSE4k5oesQmMEGNEk9RVu+EZO4xAme6+mlyd2/Y/709jaC90PuiOG/k/4JMTTI/2q4s7tk6IgSxLBT8ZiOtgJVGdasSaAksEBMRHyUkzAIr5tSUw1VXedwJFPfwQT2nOD5dU2cxiNJKOwtO9uAYXly0U0FDoa/nkWskca8zaU+4EiPikJ6Km7phViH9JvwZFgHhBj+8FM6Jof+AdrY3q1dcMLFlg==",
"r":"OJnA3wFoKKG+iu4FciXyJg=="
}
EXAMPLE OF CORRECT REQUEST:
{ "k":"uW8d7vIzlgkEkKTkDnHbBZeqKwdgoG+1BVZ/NUiC0pZ/LqZM9aUasQSx+qDg+X50ur30uRnEyAyIZXruYeHQb8cacx5mvr9LWLud+wueJXsOlEEdocD/4A1DfE9TDFdnTaVcMSIwhSVlLPUjO7ubJdANY9yK4S+vb0IyPbsrYpAT7ho01mDkvsH1rZsId/TmzQadmsGhThowu+mrQlz78rrdlN8nI5LnUQHXRNWMUgBvuteTpVBmyrfnIELIKoo/jI6Nj4rGPQBf7+2OOoZPs0Y1GtjXxUCTAt7madNLKSOdaPjdWjaOfGSwnymDNeEFyJQOmAwHZoOGYNd2B/UhQQ==",
"v":"IimiJFcKv5ZHWHljJixX0LUgV4I2GWAWPbk7dWHVhwmHEhTHA/hCdih/E1wiWFS+0KaL05ZobiZInyK7gCwYPHaz0aRCSQtVeBPiFg4f7L0gwfvk1GHwJ1wZjqNJZaYf0elXJzc2l5BwN+aXNWaNJDPA7M6kfK6UPkq84IV3ohCQcTuC8zPM7aMJHxpz9IudcrMmYIkeqrj9Do88CkTLv8yg5hk3EASPk9HqsUieuQixggv/8ZlHnp00iftc62LJlIuCkGn4WR3FkMdFdqpKXf6Ebj8PU1HOmokEtKtYJiOZ5JxieZO5Pnd+ez6sO7khIbdRFDhAQ20chsxKUypezw==",
"r":"2mbUgU44JFFDlWu8As2RIw=="
}
In the case of the failed request, the Base64 decoded encrypted AES key has a length of 255 bytes. For a 2048 bit RSA key it should actually be 256 bytes, as it is for the remaining data.
For the RSA-encryption JSEncrypt is used, which has a known bug that sporadically causes too short ciphertexts and which is probably responsible for your issue, see here. This bug was opened in July 2019 and is not fixed yet.
Within JSEncrypt the too short ciphertexts are processed correctly, so that no error occurs. Cross platform however, this is often not the case, because the too short ciphertexts are strictly speaking invalid and therefore some programming languages identify them as invalid, e.g. Python, apparently C# is another one.
If the too short ciphertext is manually padded from the left to the length of the modulus with 0x00, the ciphertext should also be decryptable in the C# code.
Update:
I have successfully tested the suggested fix using your code. The ciphertext can be fixed in the JavaScript or C# code. A possible implementation for the JavaScript side is e.g. for the key:
encryptedKey = btoa(atob(encryptedKey).padStart(256, "\0"));
where encryptedKey is the Base64 encoded ciphertext as returned by JSEncrypt#encrypt. To ensure that this correction isn't applied to ciphertexts that already have the correct length, a length check is useful: A Base64 encoded ciphertext of length 4 * Math.ceil(256 / 3) doesn't need to be fixed because it corresponds to a ciphertext of the correct length of 256 bytes, see here.
You apply the method setPrivateKey in the JSEncrypt part when setting the public key for the encryption, correct would be setPublicKey, see here. However, JSEncrypt seems to fix this internally, because it works as well. Nevertheless it should be changed, because it's misleading.
As already mentioned in the comments by #kelalaka, the IV is no secret and doesn't need to be encrypted.

Using an RSA Public key to decrypt a string that was encrypted using an RSA private key

This is a duplicate of an unanswered question here: Using an RSA Public Key to decrypt a string that was encrypted using RSA Private Key
You can see the author found a solution using some code from here:
http://www.codeproject.com/KB/security/PrivateEncryption.aspx
Using code from that link looks very promising. The only thing missing is the padding. I typically use PKCS1.5 padding which is the default for OpenSSL RSA.
I know the answer to this question is very close. I know the only thing holding back decryption is the pkcs1.5 padding on the encrypted openssl ciphertext.
I was surprised to see how little information is out there on this subject because there are many situations where you would need a server to encrypt something, sign something, etc, and have a client application verify, decrypt, etc with the public key.
I also extensively tried using the RSACryptoServiceProvider to verify hash's resulting from the encryption using OpenSSL. For example, I would do a private key encryption using a SHA256 hash of the plaintext, then try to do a RSACryptoServiceProvider verify on that signature, and it does not work. I think the way MS does this is non standard and there are perhaps special customization at work with that.
So, the alternative is this question, which is simply taking private key encrypted ciphertext and using C# to decrypt it, thus, verifying it's authenticity. Hashes can be incorporated to make a simple signature verification system for data objects signed by the server and verified on the client.
I've looked through the PKCS1 RFC's, OpenSSL rsa source code, and other projects, I cannot get a solid answer on how to account for PKCS1 padding when doing my RSA Decrypt. I cannot locate where in the OpenSSL source code they handle the PKCS1 padding, otherwise, I might have an answer by now.
Also, this is my first question, I know it's a duplicate of an unanswered question, so, what to do? I googled that too, and found nothing.
The other thing I don't understand is why my decrypt method doesn't work. Since padding is removed after decryption, my decrypted data should resemble plaintext, and it's not even close. So, I'm almost sure that pkcs1 padding means that other things are happening, specifically, to the ciphertext which means that the ciphertext must be preprocessed prior to decryption to remove padding elements.
Perhaps simply filtering the ciphertext to remove padding elements is the simplest solution here...
Here is my Decrypt method:
public static byte[] PublicDecryption(this RSACryptoServiceProvider rsa, byte[] cipherData)
{
if (cipherData == null)
throw new ArgumentNullException("cipherData");
BigInteger numEncData = new BigInteger(cipherData);
RSAParameters rsaParams = rsa.ExportParameters(false);
BigInteger Exponent = GetBig(rsaParams.Exponent);
BigInteger Modulus = GetBig(rsaParams.Modulus);
BigInteger decData = BigInteger.ModPow(numEncData, Exponent, Modulus);
byte[] data = decData.ToByteArray();
byte[] result = new byte[data.Length - 1];
Array.Copy(data, result, result.Length);
result = RemovePadding(result);
Array.Reverse(result);
return result;
}
private static byte[] RemovePadding(byte[] data)
{
byte[] results = new byte[data.Length - 4];
Array.Copy(data, results, results.Length);
return results;
}
The problem isn't with the padding. In fact, removing padding values from decrypted ciphertext is actually very simple. The problem was with the software at this location:
You can see the author found a solution using some code from here: http://www.codeproject.com/KB/security/PrivateEncryption.aspx
And with Microsoft's implementation of System.Numeric which simply cannot handle larger integers...
To fix the issue, I looked at previous releases of code on the codeproject site and ended up with this PublicDecrypt method.
public static byte[] PublicDecryption(this RSACryptoServiceProvider rsa, byte[] cipherData)
{
if (cipherData == null)
throw new ArgumentNullException("cipherData");
BigInteger numEncData = new BigInteger(cipherData);
RSAParameters rsaParams = rsa.ExportParameters(false);
BigInteger Exponent = new BigInteger(rsaParams.Exponent);
BigInteger Modulus = new BigInteger(rsaParams.Modulus);
BigInteger decData2 = numEncData.modPow(Exponent, Modulus);
byte[] data = decData2.getBytes();
bool first = false;
List<byte> bl = new List<byte>();
for (int i = 0; i < data.Length; ++i)
{
if (!first && data[i] == 0x00)
{
first = true;
}
else if (first)
{
if (data[i] == 0x00)
{
return bl.ToArray();
}
bl.Add(data[i]);
}
}
if (bl.Count > 0)
return bl.ToArray();
return new byte[0];
}
That will perfectly decrypt ciphertext created by openssl using the rsautl utility, or the Perl Crypt::OpenSSL::RSA private_encrypt method.
The other big change was dropping the Microsoft BitInteger library which simply didn't work. I ended up using the one mentioned in the Code Project article , and found here:
http://www.codeproject.com/Articles/2728/C-BigInteger-Class
The key here is to set the maxintsize in the library to a value which is larger based on how big of a key size you are using. For 4096 bit, a value of 500 worked fine (approx length of the modulus).
Here is the calling method:
var encmsg3 = "JIA7qtOrbBthptILxnurAeiQM3JzSoi5WiPCpZrIIqURKfVQMN1BrondF9kyNzbjTs1DaEKEuMBVwKExZe22yCvXXpm8pwcEGc9EHcVK2MPqNo89tIF8LJcaDqBMwLvxdaa/QgebtpmOVN/TIWfuiV8KR+Wn07KwsgV+3SALbNgbOIR3RtCx3IiQ3tZzybJb08+ZKwJEOT011uwvvGmtJskQgq9PC8kr1RPXMgaP6xMX7PHFJ8ORhkuWOFfCh+R4NhY1cItVhnRewKpIC2qVlpzUYRAgKIKdCXuZDqUQdIponR29eTovvLb0DvKQCLTf9WI1SzUm6pKRn0vLsQL7L3UYHWl43ISrTpDdp+3oclhgRF3uITR4WCvoljephbGc6Gelk5z3Vi6lN0oQaazJ7zIen+a/Ts7ZX3KKlwPl4/lAFRjdjoqu7u4IAK7O7u1Jf2xDiGw18C/eGt8UHl09zU4qQf9/u+7gtJ+10z2NERlLSaCDjVqslwmmxu81pG2gCv8LfpR4JlPaFfBZMGfGBihyGryWhJwizUXXo8wgdoYbHRXe8/gL19qro0ea5pA9aAhDjTpX1Zzbwu2rUU7j6wtwQtUDJOGXXCw1VOHsx6WXeW196RkqG72ucVIaSAlx5TFJv8cnj6werEx1Ung5456gth3gj19zHc8E/Mwcpsk=";
byte[] enc = Convert.FromBase64String(encmsg3);
var dec = rsa2.PublicDecryption(enc);
Debug.Print("PLAINTEXT: " + Encoding.UTF8.GetString(dec));
The only last thing someone would need to completely replicate this would be getting the private key into openssl format so that they could pass the private and public keys back and forth between openssl and C#.
I used openssl.net, and created an RSA instance, and set all the variables using bignumbers. Here's the code for that:
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(Properties.Resources.RSAParameters);
RSAParameters par = rsa.ExportParameters(true); // export the private key
using (OpenSSL.Crypto.RSA rsaos = new OpenSSL.Crypto.RSA())
using (BigNumber bnmod = BigNumber.FromArray(par.Modulus))
using (BigNumber bnexp = BigNumber.FromArray(par.Exponent))
using (BigNumber bnD = BigNumber.FromArray(par.D))
using (BigNumber bnP = BigNumber.FromArray(par.P))
using (BigNumber bnQ = BigNumber.FromArray(par.Q))
using (BigNumber bnDmodP = BigNumber.FromArray(par.DP))
using (BigNumber bnDmodQ = BigNumber.FromArray(par.DQ))
using (BigNumber bnInverse = BigNumber.FromArray(par.InverseQ))
{
rsaos.PublicExponent = bnexp;
rsaos.PublicModulus = bnmod;
rsaos.IQmodP = bnInverse;
rsaos.DmodP1 = bnDmodP;
rsaos.DmodQ1 = bnDmodQ;
rsaos.SecretPrimeFactorP = bnP;
rsaos.SecretPrimeFactorQ = bnQ;
rsaos.PrivateExponent = bnD;
string privatekey = rsaos.PrivateKeyAsPEM;
string publickey = rsaos.PublicKeyAsPEM
}
With that you can easily create an RSA key, export everything to OpenSSL, and encrypt/decrypt anything you want within reason. It is enough to handle private key encryption followed by public key decryption.
Cool.
There is a problem in the line in the PublicDecryption function:
BigInteger numEncData = new BigInteger(cipherData);
it shall be:
BigInteger numEncData = GetBig(cipherData);
This line shall also be removed:
Array.Reverse(result);
You may encounter some padding problem, but if you can get the data right, it shall be easy to correct that.

Signing a byte array of 128 bytes with RSA in C sharp

I am completely new to cryptography and I need to sign a byte array of 128 bytes with an RSA key i have generated with C sharp. The key must be 1024 bits.
I have found a few examples of how to use RSA with C sharp and the code I'm currently trying to use is:
public static void AssignParameter()
{
const int PROVIDER_RSA_FULL = 1;
const string CONTAINER_NAME = "SpiderContainer";
CspParameters cspParams;
cspParams = new CspParameters(PROVIDER_RSA_FULL);
cspParams.KeyContainerName = CONTAINER_NAME;
cspParams.Flags = CspProviderFlags.UseMachineKeyStore;
cspParams.ProviderName = "Microsoft Strong Cryptographic Provider";
rsa = new RSACryptoServiceProvider(cspParams);
rsa.KeySize = 1024;
}
public static string EncryptData(string data2Encrypt)
{
AssignParameter();
StreamReader reader = new StreamReader(path + "publickey.xml");
string publicOnlyKeyXML = reader.ReadToEnd();
rsa.FromXmlString(publicOnlyKeyXML);
reader.Close();
//read plaintext, encrypt it to ciphertext
byte[] plainbytes = System.Text.Encoding.UTF8.GetBytes(data2Encrypt);
byte[] cipherbytes = rsa.Encrypt(plainbytes, false);
return Convert.ToBase64String(cipherbytes);
}
This code works fine with small strings (and thus short byte arrays) but when I try this with a string of 128 characters I get an error saying:
CryptographicException was unhandled: Wrong length
(OK, it might not precisely say 'Wrong length', I get the error in danish, and that is 'Forkert længde' which directly translates to 'Wrong length').
Can anyone tell me how I can encrypt a byte array of 128 bytes with a RSA key of 1024 bits in C sharp?
Thanks in advance,
LordJesus
EDIT:
Ok, just to clarify things a bit: I have a message, from which i make a hash using SHA-256. This gives a 32 byte array. This array is padded using a custom padding, so it ends up being a 128 byte array. This padded hash should then be signed with my private key, so the receiver can use my public key to verify that the message received is the same as the message sent. Can this be done with a key of 1024 bits?
If you want to sign you do not want to encrypt. Signatures and encryption are distinct algorithms. It does not help that there is a well-known signature algorithm called RSA, and a well-known asymmetric encryption algorithm also called RSA, and that the signature algorithm was first presented (and still is in many places) as "you encrypt with the private key". This is just plain confusing.
In RSA encryption, the data to encrypt (with the public key) must be padded with what PKCS#1 (the RSA standard) describes as "Type 2 padding", and the result (which has the same length than the modulus) is then processed through the modular exponentiation which is at the core of RSA (at the core, but RSA is not only a modular exponentiation; the padding is very important for security).
When signing, the data to sign must be hashed, then the hash value is embedded in a structure which describes the hash function which was just used, and the encoded structure is itself padded with a "Type 1 padding" -- not the same padding than the padding for encryption, and that's important, too.
Either way, a normal RSA engine will perform the type 1 or type 2 padding itself, and most RSA signature engines will also handle themselves the structure which identifies the used hash function. A RSA signature engine such as RSACryptoServiceProvider can work either with SignHash(), which expects the hash value (the 32 bytes obtained from SHA-256, without any kind of encapsulating structure or type 1 padding -- RSACryptoServiceProvider handles that itself), or SignData(), which expects the data to be signed (the engine then does the hash computation too).
To sum up, if you do any kind of padding yourself, then you are doing it wrong. If you used Encrypt() to compute a signature, then you are doing it wrong, too.
The minimum key size for encrypting 128 bytes would be 1112 bits, when you are calling Encrypt with OAEP off. Note that setting the key size like this rsa.KeySize = 1024 won't help, you need to actually generate they key of the right size and use them.
This is what worked for me:
using System;
using System.IO;
using System.Security.Cryptography;
namespace SO6299460
{
class Program
{
static void Main()
{
GenerateKey();
string data2Encrypt = string.Empty.PadLeft(128,'$');
string encrypted = EncryptData(data2Encrypt);
string decrypted = DecryptData(encrypted);
Console.WriteLine(data2Encrypt);
Console.WriteLine(encrypted);
Console.WriteLine(decrypted);
}
private const string path = #"c:\";
public static void GenerateKey()
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(1112);
string publickKey = rsa.ToXmlString(false);
string privateKey = rsa.ToXmlString(true);
WriteStringToFile(publickKey, path + "publickey.xml");
WriteStringToFile(privateKey, path + "privatekey.xml");
}
public static void WriteStringToFile(string value, string filename)
{
using (FileStream stream = File.Open(filename, FileMode.Create, FileAccess.Write, FileShare.Read))
using (StreamWriter writer = new StreamWriter(stream))
{
writer.Write(value);
writer.Flush();
stream.Flush();
}
}
public static string EncryptData(string data2Encrypt)
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
StreamReader reader = new StreamReader(path + "publickey.xml");
string publicOnlyKeyXML = reader.ReadToEnd();
rsa.FromXmlString(publicOnlyKeyXML);
reader.Close();
//read plaintext, encrypt it to ciphertext
byte[] plainbytes = System.Text.Encoding.UTF8.GetBytes(data2Encrypt);
byte[] cipherbytes = rsa.Encrypt(plainbytes,false);
return Convert.ToBase64String(cipherbytes);
}
public static string DecryptData(string data2Decrypt)
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
StreamReader reader = new StreamReader(path + "privatekey.xml");
string key = reader.ReadToEnd();
rsa.FromXmlString(key);
reader.Close();
byte[] plainbytes = rsa.Decrypt(Convert.FromBase64String(data2Decrypt), false);
return System.Text.Encoding.UTF8.GetString(plainbytes);
}
}
}
Note however, that I'm not using a crypto container, and thus, I don't need your AssignParameter, but if you need to use it, modifying the code should be easy enough.
If you ever need to encrypt large quantities of data (much larger than 128 bytes) this article has sample code on how to do this.
Apparently, according to this question — how to use RSA to encrypt files (huge data) in C# — RSA can only encrypt data shorter than its key length.
Bizarre. The MSDN docs for`RSACryptoServiceProvider.Encrypt() say that a CryptographicException may be thrown if the length of the rgb parameter is greater than the maximum allowed length.
Well. That seems odd, especially since there doesn't seem to be much in the way of documentation regarding said maximum.
A little further digging, under Remarks has this:
The following table describes the padding supported by different versions
of Microsoft Windows and the maximum length of rgb allowed by the different
combinations of operating systems and padding.
If you are running XP or later and you're using OAEP padding, then the limit is stated to be
Modulus size -2 -2*hLen, where hLen is the size of the hash
No idea what the "size of the hash" might be, since the docs, AFAICS, don't mention "hash" anywhere except in regards to digital signatures.
If you are running Windows 2000 or later with the "high encryption pack" installed (again, no idea how you find that out), then the limit is stated to be
Modulus size - 11. (11 bytes is the minimum padding possible.)
Otherwise (Windows 98, Millenium or Windows 2000 or later without the aforementioned "high encryption pack" then you get "Direct Encryption and OAEP padding not supported", where the limitation is
The maximum size allowed for a symmetric key.
Say...wait a second... RSA is an asymmetric algorithm, right?
Worthless documentation. Sheesh.
See http://msdn.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider.encrypt.aspx. The exception thrown is probably "The length of the rgb parameter is greater than the maximum allowed length."
Usually RSA encryption has padding, and since your encrypted data size goes to the key size, there is no space for padding. Try to use longer key or less data size to encrypt.
Do you real need the custom padding? If not you could just use RSACryptoServiceProvider.SignData Method

Java Encryption C# Decryption

I got a module which RSA encrypts the data and passes on to the C#.
C# needs to decrypt it based on the public key (64 bit encoded) and the passed token.
I have token , 64 bit encoded public key, can some help me get with the sample to get started.
All I know from Java end is, it is using. I have got the result from Java end and need to write a parser in C# to decrypt this. I get both public key and token as a string value.
Cipher cipher = Cipher.getInstance(ALGORITHM); //Algorithm = "RSA"
cipher.init(Cipher.DECRYPT_MODE, key);
Thanks
To get started, you'll need the private key to decrypt the message. By "public key (64 bit encoded)", I'm guessing what you really have is a Base-64–encoded certificate, with a header line that says "----- BEGIN CERTIFICATE-----" and a footer that says "-----END CERTIFICATE-----".
If that's correct, you'll need to find the private key. This is sometimes stored in a PKCS #12 format file, with a ".p12" or ".pfx" extension. You'll need a password to access the private key if it is stored in such a file.
Alternatively, OpenSSL and other utilities use private key files that can be Base-64–encoded or binary. These have a variety of extensions, and may or may not be password-protected. If the file that you have has a header line of "-----BEGIN RSA PRIVATE KEY-----" or "-----BEGIN PRIVATE KEY-----", that is actually the private key.
Finally, Windows can store private keys in its internal key store.
When you clarify the location of the private key, please update your question.
If the private key is used on the Java side, it may be an attempt to perform a digital signature. While all of several Java providers I've tested produce correct results when (ab)used this way, if you are doing a signature, the Signature class should be used. The C# code should use a signature object to "verify" the signature as well.
Encryption is performed with the private key. Since the public key is public, anyone can decrypt the message; i.e., the message is not confidential. Public keys are used by recipients to verify signed messages.
Check this code out.
public static string Decrypt(string inputText)
{
RijndaelManaged rijndaelCipher = new RijndaelManaged();
byte[] encryptedData = Convert.FromBase64String(inputText.Replace(" ","+"));
PasswordDeriveBytes secretKey = new PasswordDeriveBytes(ENCRYPTION_KEY, SALT);
using (ICryptoTransform decryptor = rijndaelCipher.CreateDecryptor(secretKey.GetBytes(32), secretKey.GetBytes(16)))
{
using (MemoryStream memoryStream = new MemoryStream(encryptedData))
{
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
{
byte[] plainText = new byte[encryptedData.Length];
int decryptedCount = cryptoStream.Read(plainText, 0, plainText.Length);
return Encoding.Unicode.GetString(plainText, 0, decryptedCount);
}
}
}

How would I do some simple file encryption and decryption?

I have a .NET application. I need to store a text value encrypted in a file, then retrieve the encrypted value somewhere else in the code, and decrypt it.
I don't need the strongest or most secure encryption method on earth, just something that will suffice to say - I have the value encrypted, and am able to decrypt it.
I've searched a lot on the net to try and use cryptography, but most of the examples I find, don't clearly define the concepts, and the worst part is they seem to be machine specific.
Essentially, can someone please send a link to an easy to use method of encryption that can encrypt string values to a file, and then retrieve these values.
StackOverflow's Extension library has two nice little extensions to encrypt and decrypt a string with RSA. I have used the topic here a few times myself but haven't tested it really, but it is a StackOverflow Extension library so I assume it is tested and stable.
Encrypt:
public static string Encrypt(this string stringToEncrypt, string key)
{
if (string.IsNullOrEmpty(stringToEncrypt))
{
throw new ArgumentException("An empty string value cannot be encrypted.");
}
if (string.IsNullOrEmpty(key))
{
throw new ArgumentException("Cannot encrypt using an empty key. Please supply an encryption key.");
}
System.Security.Cryptography.CspParameters cspp = new System.Security.Cryptography.CspParameters();
cspp.KeyContainerName = key;
System.Security.Cryptography.RSACryptoServiceProvider rsa = new System.Security.Cryptography.RSACryptoServiceProvider(cspp);
rsa.PersistKeyInCsp = true;
byte[] bytes = rsa.Encrypt(System.Text.UTF8Encoding.UTF8.GetBytes(stringToEncrypt), true);
return BitConverter.ToString(bytes);
}
Decrypt:
public static string Decrypt(this string stringToDecrypt, string key)
{
string result = null;
if (string.IsNullOrEmpty(stringToDecrypt))
{
throw new ArgumentException("An empty string value cannot be encrypted.");
}
if (string.IsNullOrEmpty(key))
{
throw new ArgumentException("Cannot decrypt using an empty key. Please supply a decryption key.");
}
try
{
System.Security.Cryptography.CspParameters cspp = new System.Security.Cryptography.CspParameters();
cspp.KeyContainerName = key;
System.Security.Cryptography.RSACryptoServiceProvider rsa = new System.Security.Cryptography.RSACryptoServiceProvider(cspp);
rsa.PersistKeyInCsp = true;
string[] decryptArray = stringToDecrypt.Split(new string[] { "-" }, StringSplitOptions.None);
byte[] decryptByteArray = Array.ConvertAll<string, byte>(decryptArray, (s => Convert.ToByte(byte.Parse(s, System.Globalization.NumberStyles.HexNumber))));
byte[] bytes = rsa.Decrypt(decryptByteArray, true);
result = System.Text.UTF8Encoding.UTF8.GetString(bytes);
}
finally
{
// no need for further processing
}
return result;
}
If you're looking at doing symmetric encryption, then I'd consider the Enterprise Library Cryptography Application Block. David Hayden had a useful blog post about it, though its for Enterprise Library 2.0 (the current is 4.1), I think you will it is still useful.
In .NET you can use an instance of a SymmetricAlgorithm. Here on Stack Overflow there is a question that demonstrates how to encrypt and decrypt strings using a password. How you are going to handle the password is a different matter but I assume that you are not too concerned about that and simply want to "hide" some text from the prying eye.
Here is a blog post using the cryptography library that .NET comes with for a symmetric encryption/decryption.
A symmetric algorithm uses the same key to encrypt and decrypt, much as you use one key to lock and unlock your car door.
A public key algorithm would use one key to encrypt and another to decrypt, so, I can send you a file that is encrypted, and know that only you can decrypt it, as you have kept your key very secure and private.
http://blog.binaryocean.com/2006/01/08/NETSymmetricEncryption.aspx

Categories