I'm writing a simple application where users can encrypt/decrypt files using one of the block algorithms like Rijndael. I have to encrypt the session key as well with the same algorithm and store it together with the cipher text in an xml file. The key used for session key encryption is a SHA256 hash of the user's password. The result is something like:
<File>
<EncryptedKey>session key encrypted with user's password hash</EncryptedKey>
<Data>Data encrypted with session key</Data>
</File>
While decrypting, user is asked to type the password, then the hash is generated and used as a key to decrypt EncryptedKey from xml file and then the session key can be used to decrypt the data.
It works when user types correct password, but I want the application to decrypt file even if the password is wrong. I'm using Bouncy Castle and now when password is wrong (so the session key is wrong either), it throws an Exception "Pad block corrupted". I don't want to display any message boxes informing that an error occurs. Instead, I want to decrypt the file anyway and just save garbage as a result. Is that possible? My code for decrypting:
IBufferedCipher cipher = CipherUtilities.GetCipher("Rijndael/ECB/PKCS7Padding");
KeyParameter par = new KeyParameter(generateHash(password));
cipher.Init(false, par);
byte[] output = cipher.DoFinal(data); // Exception here when password is wrong
I also tried to use ProcessBytes() method first and DoFinal() at the end, but it didn't work either.
That pretty well defies the point of encryption in the first place. Presumably you could catch the exception and, in your catch block, write junk data (maybe a Hex dump of the exception stack?) to a file- but why? As noted by Ramhound, that would give a malicious user data which could be used in a brute-force attack to compare with when they have successfully decrypted the file.
I would go back to the assumptions/design phase of this: why do you want to avoid showing a message which states "The password provided did not match the expected password. Please re-enter. 3 Tries Remain." (or whatever)? What is gained by outputting a "junk" file?
Related
I have a small inhouse app (and any advice on other methods is appreciated as well) where I utilize 2 token strings that I'd like to encrypt with aes. While this is a super small app and I don't think there's a huge risk on my local, I'd still like to encrypt them with something. My thought was that I'd:
have a file on my local with the iv/key string that I could read into my app upon running, it'd decrypt the token which is stored in the db and I could use it, and when I have to overwrite the token value I'd create a new aes/triple dev iv/key pair. the iv/key pair lives in a file (or the config of the app) and then the new encrypted token goes to my db.
The problem I'm having (i'm new to encryption) is that all of the tutorials show something like the following:
Aes aes = Aes.Create();
byte[] iv = aes.IV;
byte[] key = aes.Key;
However I'm looking to store the string value, and then when the app runs next and I pull the iv/key pair in I convert it back to byte[] to do the app work.
I tried:
string ivStr = Encoding.Default.GetString(iv);
However when I tried to convert it back to a byte[] and then pass it back through to the decryption tool it would just fail and told me the length of the array was incorrect.
Any advice on this would be appreciated.
I am hoping that this question can be met with some guidance for someone who is beginning to work with encryption/decryption in C#. There are existing examples on the web regarding this, but I am truthfully struggling to put it all into practice for my given situation.
If given a text file that has been encrypted using OpenPGP with RSA, what is the best method to decrypt this in C#?
This is what I am attempting:
Using Kleopatra OpenPGP, I am generating a key pair using 2048bit RSA. This generates a private and public key.
I am then encrypting/signing a text file with a few word in it as a test.
In C#, I want to decrypt this text file.
Current code:
byte[] encryptedData = File.ReadAllBytes("C:\\PGP Encryption\\test.txt.gpg"); // The encrypted text file generated by Kleopatra.
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
{
//Import the RSA Key information. This needs
//to include the private key information.
RSA.ImportParameters(RSAKeyInfo);
//Decrypt the passed byte array and specify OAEP padding.
decryptedData = RSA.Decrypt(DataToDecrypt, DoOAEPPadding);
}
return decryptedData;
Unfortunately, the RSA.Decrypt() call throws an exception that reads "The data to be decrypted exceeds the maximum for this modulus of 128 bytes."
I also do not believe that my private key is actually being loaded, as I'm not explicitly stating where the key is. But I don't see how the RSAParameters object is supposed to get populated otherwise.
If anyone can point me in the right direction to decrypt a file in this way, thank you in advance for your time and information.
It's looks like you need this library (see Decrypt section) https://github.com/mattosaurus/PgpCore
I already asked the first half of my question so for future references I recommend reading that question in order to fix my problem (I was suggested writing a new question based on the information i got from that question, click here). Roughly said, my problem is that PdfReader.ComputeUserPassword() returns null. It's caused by the library which isn't able to compute the user's password from an AES256 encrypted PDF file.
This is the lib's code that returns null:
public byte[] ComputeUserPassword() {
if (!encrypted || !ownerPasswordUsed) return null;
return decrypt.ComputeUserPassword(password);
}
My question is, how can I compute the user's password from an AES256 encrypted PDF?
(Is it necessary to update from 5.5.13.1 to a 7.* version of itextsharp? This isn't relevant right now because the current version [v7.1.7] of itextsharp still doesn't support AES256 encryption when trying to obtain the user's password of an AES256 encrypted PDF file, as you can see in the "Edit"-part)
Edit:
I don't see any reason of updating to v7.* because AES256 encryption still isn't supported for computing the user's password (this hasn't changed from v7.1.1 to v7.1.7).
https://api.itextpdf.com/iText7/7.1.1/com/itextpdf/kernel/pdf/PdfReader.html#computeUserPassword--
public byte[] computeUserPassword()
Computes user password if standard encryption handler is used with
Standard40, Standard128 or AES128 encryption algorithm.
Returns:
user password, or null if not a standard encryption handler was used or if ownerPasswordUsed wasn't use to open the document.
I'm trying to write a service to SFTP to a server on a given interval, download all files in a directory, and then decrypt them for processing.
The decrypt method was working at one point, and I have no modified it since. I am still using the same keys as when it did successfully work.
I am using the PGPEncrypt, PGPDecrypt, and PGPEncryptionKeys classes for BouncyCastle found here: https://github.com/sledwith/PGP-Decryption-With-C-Sharp
Additionally, I have modified the code as shown here: Exception on decrypting file using BouncyCastle PGP
If you noticed, I commented on how that fixed my code and the decryption worked.
Now, it isn't.
Does anyone have some insight why this might have happened, or how I could go about fixing it?
I am going to make a guess that you are using a 1024 bit RSA public/private key and trying to encrypt 128 bytes of something with it? If I am right, use a larger RSA key (RSA 4096 will allow you to encrypt up to ~500 bytes).
I note in the linked post you say this is sporadic. Some googling indicates that if you have leading zeros in the to-be-encrypted bytes it may be able to handle a full 128 bytes.
Also - if you are just encrypting "data" with the keypair, you need to be certain it will not overrun these limitations (240 or so bytes for RSA 2048 and 500 or so for RSA 4096 accounting for padding). Good practice and future proofing would be to implement a symmetric key encryption of all your data and just use the RSA key to encrypt / decrypt your keys.
If you're not dead-set on using the PGP process explicitly, you might use my library here:
https://github.com/zenith-nz/ObscurCore
Its "banner feature" is not yet fully active (creating encrypted archives of a kind), but it does everything that you want it for, it appears - it does key derivation with a ECDHC scheme, UM1, and implements a large variety of block and stream ciphers. It's built on top of BouncyCastle.
I think I resolved this problem; please try this code.
public string StringToDecrypt(string text)
{
byte[] toDecrypt = Convert.FromBase64String(text);
AsymmetricCipherKeyPair keyPair;
using (var reader = File.OpenText(#"Private Key File Path"))
{
keyPair = (AsymmetricCipherKeyPair) new PemReader(reader).ReadObject();
}
var engine = new RsaEngine();
engine.Init(false, keyPair.Private);
return Encoding.UTF8.GetString(engine.ProcessBlock(toDecrypt, 0, toDecrypt.Length));
}
After looking at how to generate self-signed digital signatures from Creating a self-signed certificate in C#, I can call CreateSelfSignCertificatePfx and get PXF data in a byte array back, which can then be used within an X509Certificate2 object to sign and verify. Example...
byte[] pfx = Certificate.CreateSelfSignCertificatePfx("O=Company,CN=Firstname,SN=Lastname", DateTime.Now, DateTime.Now.AddYears(1), "password");
X509Certificate2 cert = new X509Certificate2(pfx, "password");
byte[] publicBytes = cert.RawData;
RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)cert.PrivateKey;
byte[] signedData = rsa.SignData(new System.Text.UTF8Encoding().GetBytes("Test"), new SHA1CryptoServiceProvider());
RSACryptoServiceProvider rsa2 = (RSACryptoServiceProvider)new X509Certificate2(publicBytes).PublicKey.Key;
bool verified = rsa2.VerifyData(new System.Text.UTF8Encoding().GetBytes("Test"), new SHA1CryptoServiceProvider(), signedData);
This works. My concern though is the original bytes, byte[] pfx from above, need to be stored in a DB (to sign stuff). The question becomes, how secure are the bytes in this format? I know you need the password to construct the new X509Certificate2 with a private key, but in a general sense, how secure are the bytes without the password? I have no problems encrypting these bytes as an added layer, but is that necessary?
According to X509Certificate2.X509Certificate2(Byte[], String) Constructor
Calling this constructor with the correct password decrypts the private key and saves it to a key container.
I just want to ensure the private key is safe without the password.
In my eyes the question is not whether you should put the "bytes" in the database, but more, would you put the file with the private key in your file system.
In the way you're doing it, it's essentially the same thing. You're just storing the bytes that make up the cert file.
I may be failing to understand the difference here, but they bytes and the file are essentially the same thing, the only difference being the fact that one has to gain access to the db to get them.
Use a smartcard or token to store your private key.
UPDATE:
The Pvt key can be accessed by anyone who can access the machine.
The private keys in a PFX (PKCS#12) are stored encrypted, which is of course what the password is for. Not all of a PFX is encrypted, the structural pieces stay plaintext to contain metadata about the contents (like what encryption algorithm was used).
Based on inspecting the file, as of Windows 7 the private keys are encrypted using 3-key (168-bit) 3DES. The key is derived via a complex formula involving your password; there's nothing saved in the file which gives any indication as to what your password was, how long it was, et cetera.
The password is usually proven correct by the addition of a MAC on the contents, which uses the same password for its key derivation function. In the possible case of the MAC password and the encryption password being different (which I've personally never seen) the password is verified by the structural information in the encrypted payload.
DES' weakness mainly lay in the small keysize, it's easily brute forcable today. A 3-key 3DES key has 112 more semantic bits than a (1)DES key, making it take 2^112 (~5 x 10^33) times longer to break.
So, at the end of the day, the private key is cryptographically sound. But like anything with a password-based input, if you use a bad password that is easily guessed then it can be cracked by brute force.