In my scenario, I would like to encrypt a very big number (10^27) using a private key and later be able to decrypt it using a public key. The problem I have is that I want to keep the size of the encrypted text as small as possible.
I know that .NET has support for public key encryption (RSACryptoServiceProvider), but the encrypted text gets so huge.
Would it work to instead treat the private key as a public key?
Would Elliptic curve cryptography produce a smaller output?
First of all, if you want to achieve confidentiality you should always encrypt with the public key, not the private key. RSA encryption is not defined for encryption with the private key, and the results may vary (especially the kind of padding that is applied).
For direct RSA encryption, the size of the encrypted message is identical to the modulus. Now the modulus should be at least 2048 bits by now, and your message is only about (27/3)*10=90 bits. So RSA would have a large overhead, independent on the key used. Using ECIES is therefore likely to give significant benefits.
Related
RijndaelManaged is an algorithm while AES is the standard. When referring to AES256, does that mean the key length I'm using with RijndaelManaged must be 256 characters?
If I have a key like this:
key = "mytestkey";
which is only 9 characters, does that mean I'm using AES9?
Aes/Rijndael key sizes are in bits, not characters; AES256 uses a 256-bit key. You must give it a key that is exactly 256 bits. The AES standard and Rijndael only accept key sizes that are either 128, 192, or 256 bits.
You should not interchange AES and Rijndael. The AES standard is derived from Rijndael, but they are not exactly the same. If you wish to use AES, use AES for all operations; if you wish to use Rijndael, use Rijndael for all operations.
"mytestkey" cannot directly be a key to AES256 nor a similar Rijndael mode; it is not 256 bits long. In order to use it as a key, you'll have to transform it into a block of bytes that is 256 bits long.
If you're working with passwords, one typical means to do this is with key stretching, using hash algorithms such as PBKDF2 or Scrypt. PBKDF stands for "Password-based key derivation function", which is basically exactly what you're doing - deriving a key from a password.
Theoretically you could also just hash the password with SHA256 (which always has a 256-bit output) and use that 256-bit block as the key to AES; doing so is unwise from a security standpoint because it is relatively easy to precompute SHA hashes of passwords.
Please keep in mind that if you use a password that has very little entropy, then the security of your encryption suffers - the time it'll take for someone to guess the key could be short. "mytestkey" has at most ~42 bits of entropy - you're only using lower case letters, so 26 values per place, and there are 9 places (9 characters). Thus the number of bits theoretically needed to stores this is log_2( 26^9 ) = 42.3. In this circumstance, you'd be using AES256 with a key that has only ~42 bits of entropy.
I should note that the advice given here is an incomplete treatment of how to turn passwords into keys, from a security perspective. If you want to better understand how to properly generate keys from passwords, I suggest you start with some reading such as the Password Storage Cheat Sheet at owasp.org.
I'm using the RSACryptoServiceProvider to encrypt and decrypt simple strings and while it works with normal certificates, it's giving me some grief when it comes to smart cards.
Here is the code I'm using:
private X509Certificate2 _cert // this certificate is set early on in the program
private string Encrypt(string Data)
{
if (string.IsNullOrEmpty(Data)) return default(string);
RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)_cert.PublicKey.Key;
return Convert.ToBase64String(((rsa.Encrypt(Encoding.Unicode.GetBytes(Data), true))));
}
private string Decrypt(string CipherText)
{
if (string.IsNullOrEmpty(CipherText)) return default(string);
RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)_cert.PrivateKey;
return Encoding.Unicode.GetString(((rsa.Decrypt(Convert.FromBase64String(CipherText), true))));
}
It does decrypt successfully (no errors) but the encoding isn't correct. It's giving me results like
\u08d8黔㡉Ẑ༴쨳층器\u0888諬翉烽偪䚘螷퓰薑낯ꄯ鯪ꘇ台ᾨ鳞텟칆蘟マ⺁ൿ䤳譻宐Ṹ鉱㒎艴偃堎え뢈癘蚰૩�⸮賆슉ଞ맿댿䀵㓹摵�뼚⡨ቾ᳓낣쏀ꖌ엷ὦ楐豎⸌ꅑ뙳餱Ч鎋筧粅嚄罜칮嬒쐞ڮ묭泊䘐쫦⊗邀☇仇挃箍絁绺罽华⏓፦귪ﻳ咷믭鹺簽艉闼敹Ԓ嵯젨泪ꔤ狫ꆙ\uab41軧\n"
What's also interesting is no matter what I encrypt, the decrypted byte[] length is always 256.
I know smart card private key operations always take place on the card itself so I'm sure that has something to do with it but I was hoping some of you have experience with this and can save me the mounds of trial-and-error.
Thanks!
It seems your Smart Card performs so called raw or textbook RSA. In other words, it only performs modular exponentiation, leaving the PKCS#1 v1.5 (EME-PKCS1-v1_5) or - in your case - OAEP (EME-OAEP decoding) decoding up to you. This padding has the same size as the key size / modulus size. In your case that would be 256 bytes or 2048 bits.
So something is very wrong with the Smart Card that's used. Unpadding should be an integral part of the functionality provided by it; it makes little sense to do that on the PC.
The padding largely consists of random (looking) data so it's little wonder that it looks like random text, especially now UTF-16 LE is being used (incorrectly called Unicode by .NET).
Is there any way to perform private key encryption in C#?
I know about the standard RSACryptoServiceProvider in System.Security.Cryptography, but these classes provide only public key encryption and private key decryption. Also, they provide digital signature functionality, which uses internally private key encryption, but there are not any publicly accessible functions to perform private key encryption and public key decryption.
I've found this article on codeproject, which is a very good start point for performing this kind of encryption, however, I was looking for some ready-to-use code, as the code in the article can hardly encrypt arbitrary-long byte arrays containing random values (that means any values, including zeroes).
Do you know some good components (preferably free) to perform private key encryption?
I use .NET 3.5.
Note: I know this is generally considered as bad way of using asymmetric encryption (encrypting using private key and decrypting using public key), but I just need to use it that way.
Additional Explanation
Consider you have
var bytes = new byte[30] { /* ... */ };
and you want to use 2048bit RSA to ensure no one have changed anything in this array.
Normally, you would use digital signature (ie. RIPEMD160), which you then attach to the original bytes and send over to the receiver.
So, you have 30 bytes of original data, and additional 256 bytes of digital signature (because it is a 2048bit RSA), which is overall of 286 bytes. Hovewer, only 160 bits of that 256 bytes are actually hash, so there is exactly 1888 bits (236 bytes) unused.
So, my idea was this:
Take the 30 bytes of original data, attach to it the hash (20 bytes), and now encrypt these 50 bytes. You get 256 bytes long message, which is much shorter than 286 bytes, because "you were able to push the actual data inside the digital signature".
ECDSA Resources
MSDN
Eggheadcafe.com
c-plusplus.de
MSDN Blog
Wiki
DSA Resources
CodeProject
MSDN 1
MSDN 2
MSDN 3
Final Solution
If anyone is interested how I've solved this problem, I'm going to use 1024bit DSA and SHA1, which is widely supported on many different versions of Windows (Windows 2000 and newer), security is good enough (I'm not signing orders, I just need to ensure that some child can't crack the signature on his iPhone (:-D)), and the signature size is only 40 bytes long.
What you are trying to design is known as a "Signature scheme with message recovery".
Designing a new signature scheme is hard. Designing a new signature scheme with message recovery is harder. I don't know all the details about your design, but there is a good chance that it is susceptible to a chosen message attack.
One proposal for signature schemes with message recovery is RSA PSS-R. But unfortunately, this proposal is covered with a patent.
The IEEE P1363 standarization group, once discussed the addition of signature schemes with message recovery. However, I'm not sure about the current state of this effort, but it might be worth checking out.
Your Public key is a sub-set of your private key. You can use your private key as a public key as it will only use the components of the full key it requires.
In .NET both your private & public keys are stored in the RSAParameters struct. The struct contains fields for:
D
DP
DQ
Exponent
InverseQ
Modulus
P
Q
If you're at the point where the data is so small that the digital signature is huge in comparison, then you have excess signature. The solution isn't to roll your own algorithm, but to cut down what's there. You definitely don't want to try to combine a key with the hash in an amateurish way: this has been broken already, which is why we have HMAC's.
So here's the basic idea:
Create a session key using a cryptographically strong RNG.
Transmit it via PKE.
Use the session key to generate an HMAC-SHA1 (or HMAC-RIPEMD160, or whatever).
If the size of the hash is absurdly large for the given data, cut it in half by XORing the top with the bottom. Repeat as needed.
Send the data and the (possibly cut-down) hash.
The receiver uses the data and the session key to regenerate the hash and then compares it with the one transmitted (possibly after first cutting it down.)
Change session keys often.
This is a compromise between the insanity of rolling your own system and using an ill-fitting one.
I'm wide open to constructive criticism...
I get it now, after reading the comments.
The answer is: don't do it.
Cryptographic signature algorithms are not algorithms from which you can pick and choose - or modify - steps. In particular, supposing a signature sig looks something like encrypt(hash), orig + sig is not the same as encrypt(orig + hash). Further, even outdated signature algorithms like PKCS v1.5 are not as simple as encrypt(hash) in the first place.
A technique like the one you describe sacrifices security for the sake of cleverness. If you don't have the bandwidth for a 256 byte signature, then you need one of:
a different algorithm,
more bandwidth, or
a smaller key.
And if you go with (1), please be sure it's not an algorithm you made up! The simple fact is that crypto is hard.
I want to use encryption algorithm available in .Net Security namespace, however I am trying to understand how to generate the key, for example AES algorithm needs 256 bits, that 16 bytes key, and some initialization vector, which is also few bytes.
Can I use any combination of values in my Key and IV? e.g. all zeros in Key and IV are valid or not? I know the detail of algorithm which does lots of xors, so zero wont serve any good, but are there any restrictions by these algorithms?
Or Do I have to generate the key using some program and save it permanently somewhere?
I want to store data in database after encryption, the secure profile data like username, password, phone number etc, and the key will be available to database user mentioned in connection string only, and to the administrator.
You really ought to do this the correct way :)
1) Use a securely generated random IV
2) Use a securely generated random key
3) Don't use ECB mode - EVER
AesManaged aes = new AesManaged();
aes.GenerateKey();
aes.GenerateIV();
The code above will correctly and securely generate a random IV and random key for you.
Sounds like you need to read into the Rfc2898DeriveBytes class.
Rfc2898DeriveBytes.GetBytes();
It has a method(above) that allows you to tailor the size of byte arrays that are fed into the .Key and .IV properties on a symmetric encryption algorithm, simply by feeding an int value. The MS official 70-536 book suggests doing this pro-grammatically by dividing the KeySize property / 8.
I.e TripleDes or AESManaged. Whatever you use, the algorithm itself will have some pre-reqs that will need meeting first. I.e satisfying the key size conditions. The RunTime will automatically fill the properties and fields and etc the best and most strongest values for you. But the IV and Key needs to come from you. This how you can do the following:
RijndaelManaged myAlg = new RiRijndaelManaged();
byte[] salt = Encoding.ASCII.GetBytes("Some salt value");
Rfc2898DeriveBytes key = new Rfc2898DeriveBytes("some password", salt);
myAlg.Key = key.GetBytes( myAlg.KeySize / 8);
myAlg.IV = key.GetBytes( myAlg.BlockSize / 8);
// myAld should now fully set-up.
Above you can see what I mean by doing it pro-grammatically, as it should pretty much
do it all for you, without you even really having to bat an eye-lid as to meeting it's pre-reqs.
The Microsoft 70-536 book states that the .Key properties expect the byte arrays you supply
to them in bytes and not bits. The RFC class works in bytes where as an algorithms KeySize property works in bits. 1 byte = 8 bits. Can you see where this is going ... ?
This should give you an idea as to why the above sample peice of code is done the way it is! I studied it and it makes pretty darn good sense to me!
The above answer should allow you to create your algorithm object with supplied password and a static salt value that can be hard code at both ends. Only thing you need to do is worry about how you going to make sure that the byte arrays stored at .Key and .IV are safely transported to a recipient so that can successfully decrypt the message you encrypted. By safely reconstructing the same algorithm object.
OBTW:
AESManaged has a keysize req': 128Bits = 16 Bytes !!!
(8*8 = 64, 64Bit / 8bits per Byte = 8 Bytes) Therefore
64*2 = 128Bit, 8*2, ==> 16bytes key size !
256Bit = 32Bytes !!!!
According to the 70-536 official training kit book, Aes is limited to having keysize of 128bits in size. 256bits,192 and 128 key size for example can be used with the Rijndael class.
You could on the other hand completely forget all that crap and simply use .GenerateKey and GenerateIV methods instead to save you all the hassle of sorting out a pre-shared and agreed password and static salt values. Your only concern is figuring out a way of storing and retrieving the key and IV byte arrays. Binary Formatter? .
If you are using encryption to exchange data then you will need a key exchange protocol, but you don't make one yourself instead use one off-the-shelf like TLS or SSL.
If you use encryption to store data then you generate the IV using CryptGenRandom (or its .net equivalent RandomNumberGenerator.GetBytes) and save it along the document (in clear, no need to protect the IV). You never write down the key, the key is provided by the user. Usualy you derive the key from a password phrase using CryptDeriveKey, or its .Net equivalent PasswordDeriveKey.CryptDeriveKey.
Update
To store a secret in the database that is available only to the user and an administrator you need to use 3 keys:
one to encrypt the data with (call it the DK key)
one user key to encrypt the DK key (call it UK)
one administrator key to encrypt the DK key (call it AK)
In theory you encrypt the data with DK and then encrypt the DK with UK and save it, and encrypt the DK with AK and save it. This way the user can use again the UK to decrypt the DK and then decrypt the data, and the administrator can use the AK to decrypt the DK and then decrypt the data. The big problem is the fact that the system is always automated, so the system needs access to the administrator's key which means is not truly a persnal key of the administrator, but instead is a system key (it cannot be used for purposes of non-repudiation for instance).
As a heads up, knowledge of what IV is or how to use AES from C# and how cryptography algorithm work will get you exactly 0 (zero) traction in solving this kind of problems. The issue is never what IV and key to use, the issue is always key provisioning. For actual crypto operations, just use the built-in support from the database, see Cryptography in SQL Server. I can easily argue that the only facility you need is TDE (Transparent Data Encryption) to protect against accidental loss of media.
Generate a random letters / hex code in a specific length.
This function (taken from here) return a random key in a specific length:
private static string CreateSalt(int size)
{
//Generate a cryptographic random number.
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
byte[] buff = new byte[size];
rng.GetBytes(buff);
// Return a Base64 string representation of the random number.
return Convert.ToBase64String(buff);
}
Use System.Security.Cryptography.RandomNumberGenerator to generate random bytes:
var rnd = new System.Security.Cryptography.RandomNumberGenerator.Create();
var key = new byte[50];
rnd.GetBytes(key);
It really depends on what you ned to do with the key.
If the key is to be generated by the computer (and can be any random value) I generally take a SHA256 of a couple GUIDs. This is about as random as you're going to get without a hardware random number generator.
You can use keys with all 0s but obviously it won't be very secure.
I want to encrypt a string and embed it in a URL, so I want to make sure the encrypted output isn't bigger than the input.
Is AES the way to go?
It's impossible to create any algorithm which will always create a smaller output than the input, but can reverse any output back to the input. If you allow "no bigger than the input" then basically you're just talking isomorphic algorithms where they're always the same size as the input. This is due to the pigeonhole principle.
Added to that, encryption usually has a little bit of padding (e.g. "to the nearest 8 bytes, rounded up" - in AES, that's 16 bytes). Oh, and on top of that you're got the issue of converting between text and binary. Encryption algorithms usually work in binary, but URLs are in text. Even if you assume ASCII, you could end up with an encrypted binary value which isn't ASCII. The simplest way of representing arbitrary binary data in text is to use base64. There are other alternatives which would be highly fiddly, but the general "convert text to binary, encrypt, convert binary to text" pattern is the simplest one.
Simple answer is no.
Any symmetric encryption algorithm ( AES included ) will produce an output of at minimum the same but often slightly larger. As Jon Skeet points out, usually because of padding or alignment.
Of course you could compress your string using zlib and encrypt but you'd need to decompress after decrypting.
Disclaimer - compressing the string with zlib will not guarantee it comes out smaller though
What matters is not really the cipher that you use, but the encryption mode that you use. For example the CTR mode has no length expansion, but every encryption needs a new distinct starting point for the counter. Other modes like OFB, CFB (or CBC with ciphertext stealing) also don't need to be padded to a multiple of the block length of the cipher, but they need an IV. It is unclear from your question if there is some information available from which an IV could be derived pseudorandomly an if any of these modes would be appropriate. It is also unclear if you need authentication, or if you need semantic security> i.e. is it a problem if you encrypt the same string twice and you get the same ciphertext twice?
If we are talking about symetric encription to obtain the original encrypted string from a cyphered one it is not possible. I think that unless you use hashes (SHA1, SHA256...) you will never obtain a cyphered string smaller than the original text. The problem with hashes is that they are not the solution for retrieving the original string because they are one way encryption algorithms.
When using AES, the output data will be rounded up to have a specific length (e.g a length divisible trough 16).
If you want to transfer secret data to another website, a HTTP post may do better than embedding the data into the URL.
Also just another thing to clarify:
Not only is it true that symmetric encryption algorithms produce an output that is at least as large as the input, the same is true of asymmetric encryption.
"Asymmetric encryption" and "cryptographic hashes" are two different things.
Asymmetric encryption (e.g. RSA) means that given the output (i.e. the ciphertext), you can get the input (i.e. the plaintext) back if you have the right key, it's just that decrypting requires a different key than the key used for encrypting. For asymmetric encryption, the same "pigeonhole principle" argument applies.
Cryptographic hashes (e.g. SHA-1) mean that given the output (i.e. the hash) you can't get the input back, and you can't even find a different input that hashes to the same value (assuming the hash is secure). For cryptographic hashes, the hash can be shorter than the input. (In fact the hash is the same size regardless of the length of the input.
And also one more thing: In any secure encryption system the ciphertext will be longer than the plaintext. This is because there are multiple possible ciphertexts that any given plaintext could encrypt to (e.g. using different IVs.) If this were not the case then the cipher would leak information because if two identical plaintexts were encrypted, they would encrypt to identical ciphertexts, and an adversary would then know that the plaintexts were the same.