How AES/GCM deals with data smaller than block size? - c#

I am using bouncy castle library for encryption and decryption in c# and I was wondering how to deal with plain text smaller than block size?
here is what I have done so far:
AesFastEngine engine = new AesFastEngine();
GcmBlockCipher cipher = new GcmBlockCipher(engine);
AeadParameters param = new AeadParameters(new KeyParameters(key), 128, iv, null);
cipher.Init(true, parameters);
byte[] encData = new byte[plain.Length];
cipher.ProcessBytes(plain, 0, plain.Length, encData, 0);
when the plain data is smaller then block size it does nothing.

Unfortunately the Bouncy Castle and Oracle / Java implementations are not online. That is, the online properties of the underlying CTR mode encryption aren't kept. Online in this context means that bytes are directly encrypted/decrypted when they arive. This may have to do with how the encryption is handled and how the authentication tags are handled.
AES-CTR can be implemented in multiple ways. You can either first encrypt the counter and then directly XOR with plaintext/ciphertext when it arrives. You can also first buffer the plaintext and then, once you have a full block, create the counter, encrypt it and then XOR a full block of plaintext. This had advantages in the sense that it more closely resembles other modes of operation such as CBC. Furthermore you may not have to buffer the key stream in memory all that time.
The authentication tag can also be handled differently. Here there are basically three options. You could simply regard the authentication tag as a separate entity to the ciphertext. This lets you keep the online properties of CTR mode and should, in my opinion, be the preferred option. You could also see it as part of the ciphertext, but in that case you lose the online properties during decryption; you would need to know where the ciphertext ends before you can handle the last number of bytes that make up the authentication tag. So you'd need to buffer at least the size in bytes of the authentication tag. Finally, still during decryption, you might only want to return plaintext bytes after verification of the plaintext bytes. In that case you'd need to buffer the entire ciphertext and return the plaintext in one go.
As the authentication tag issues are only for decryption it is likely that Bouncy will just buffer because of the way CTR is implemented. You'd indeed have to call doFinal - as Robert already mentioned in the comments - to retrieve the last block of ciphertext as well as the authentication tag. It could be that the encryption is not yet performed because the encryption routine is kept somewhat symmetrical to the decryption routine as well.

Related

Shortening DataProtection encryption length in .net?

I'm quite new to .net and had a question regarding DataProtector.
When using DataProtector.Protect without any configuration, the resulting encryption becomes too long for the API I need to pass it to, I was wondering if using the configuration methods (as seen here) would help? I tried the following in the class where I needed to protect the data:
var serviceCollection = new ServiceCollection();
serviceCollection.AddDataProtection()
.UseCustomCryptographicAlgorithms(new ManagedAuthenticatedEncryptionSettings()
{
// a type that subclasses SymmetricAlgorithm
EncryptionAlgorithmType = typeof(Aes),
// specified in bits
EncryptionAlgorithmKeySize = 128,
// a type that subclasses KeyedHashAlgorithm
ValidationAlgorithmType = typeof(HMACSHA256)
});
var services = serviceCollection.BuildServiceProvider();
_protector = services.GetDataProtector("MyClass.v1");
var protect = _protector.Protect(JsonConvert.SerializeObject(myData));
However even after changing the EncryptionAlgorithmKeySize from the default 256 to the minimum 128, 'protect' was still resulting in an encryption of the same length which makes me think that the configuration isn't working or configuration doesn't affect encryption length.
Does anyone know if this is being done the right way or if there is a better way to reduce encryption length?
For example a simple 9 character string gets encrypted to 134 characters.
Any help is much appreciated, thanks!
DPAPI is meant to secure data-at-rest, not data for transmission.
Ryan Dobbs is correct, above (or below? I can't figure out how StackOverflow sorts unaccepted answers...), weakening your encryption to attain a smaller payload is a very bad idea. The right way to address this is to secure the connection (TLS-style SSL), then you can just send things plaintext, or (as Ryan suggests) drop a properly-encrypted payload somewhere that both sender and receiver can access it.
But to answer your question more directly, the payload size is controlled by the hashing function. Encryption key size only tells you the cryptographic complexity of the encryption algorithm -- how hard the encryption is to break. The part that says HMACSHA256 is a SHA-256 hash which means it produces a 256-bit output.
MD5 is 128-bit but it's generally insecure (only good for checksums).
The documentation says the key size and hash size must be equivalent, so you can't go to 128 bits with SHA. The shortest SHA available is the old SHA1 algorithm (HMACSHA1) which is 160 bits, but the expectation is that anything less than 256-bits will be insecure relatively soon. The SHA2 algorithm yields HMACSHA256 and HMACSHA512.

C# .net core encryption

I'm trying to use a public key of a user to encrypt a string in a sort of pgp fashion, but I keep getting the error:
bignum routines:BN_mod_inverse:no inverse
I've looked around and I cannot find anything specific as to what I'm doing wrong. I've looked around for .NET core information, but I cannot seem to find anything relevant.
I'm using the following code:
byte[] publicKey = Encoding.UTF8.GetBytes(key);
RSA rsa = RSA.Create();
RSAParameters RSAKeyInfo = new RSAParameters();
RSAKeyInfo.Modulus = publicKey;
RSAKeyInfo.Exponent = new byte[]{1,0,1};
rsa.ImportParameters(RSAKeyInfo);
var encrypted = rsa.Encrypt(Encoding.UTF8.GetBytes(user.challenge.text), RSAEncryptionPadding.Pkcs1);
It's entirely possible I'm going about this entirely wrong, so any thoughts or suggestions would be great!
Your overall structure (build RSAParameters, call ImportParameters, call Encrypt) is valid, which suggests that your error is in Modulus recovery.
If your Modulus is input as a string, it's likely encoded as (most to least)
Base64 (Convert.FromBase64String)
Hex (May need a manual parser)
UTF-8
UTF-8 is really unlikely, since the Modulus value can contain bytes whose value are 0 (and other invalid/unexpected UTF-8 sequences). While all even-length byte sequences encoded as hex can be validly decoded as Base64, it's extraordinarily unlikely that you'd misinterpret them given two or three different inputs.
Other noteworthy things:
RSA is IDisposable, you should put it in a using statement to ensure resources free up earlier when you are done with them.
The Exponent is usually 0x010001, but that isn't required. Unless you have a guaranteed constraint on it, you should be serializing it, too.
And if it is guaranteed to always be 0x010001, why make a new one each time? Save it as a static field and make the GC's job easier.
As Maarten said, RSA-ENC-PKCS1 is susceptible to a padding oracle attack, so (especially if your data is over the wire) you should use OAEP.
In the context of .NET, OaepSHA1 has the best support (all inbox providers). OAEP with a SHA-2 algorithm is only supported by RSACng (or the opaque RSA.Create() on Windows).

How to create Encryption Key for Encryption Algorithms?

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.

Seekable alternative to .NET's CryptoStream?

Does anybody know a seekable alternative to .NET's CryptoStream?
It is OK if the alternative supports Seek only in "read" mode or if it is limited to e.g. AES256.
Block-wise encryption is perfectly secure. It's just ECB that's problematic. An implementation could probably be written using either OFB or CTR mode. However, I've never managed to locate one. May bite the bullet and write it...
UPDATE:
So I did write an implementation of this. For various reasons I'm not going to post it here right now (I'll try to at some point), but here are a few pointers for anyone looking to do this:
Use a RijndaelManaged transform in CBC mode. You're going to calculate the cipherstream block by block. You can do this by initializing a key and an empty (all zero) iv in the transform - the actual iv will be calculated on a block by block basis.
You'll want to have a method that calculates the input to the current block by concatenating or otherwise computing the nonce plus iv plus counter. You can do several optimizations here, including precomputing the nonce & iv (this method will get called many times, so it's probably worth it).
e.g. byte[] GetCurrentCounterBlock(byte[] nonce, byte[] iv, UInt32 counter)
(note: by "iv" here I mean what NIST calls the IV, the middle part of the whole block, which other people call the IV collectively)
You're going to use this method inside a loop that's enciphering your data - call this the first time and then subsequently at block boundaries to update the current cipher stream. This method provides the input to the TransformBlock method of the transform. Take the output from the transform and XOR the result against the current block of data. Use transform.Reset() after each block is encrypted! Otherwise, CBC will try to use the output from the transform as input to the next. There may be a more clever way to do this with .NET, but I can't figure it out. I know BouncyCastle supports OFB "natively" so that may be a better options, but this is a nice fast way to get a highly reusable cryptostream without external deps.
Anyway, the key is that this whole method (I call it AesCtr256.Process - but you could easily be more generic) works with an arbitrary range of data inside the cipher stream. You can easily use this method inside a custom Stream class. This will allow seeking to arbitrary locations inside the stream on both reads and writes, and give you byte-aligned data to work with (really nice, as you can now have a crypto stream that actually reports the true data length!).
To put it another way, you calculate the cipher stream for arbitrary portions of the stream, and then simply xor against the cipher or plain text to encrypt/decrypt.
Two last things: 1.) I highly recommend reusing the transform for the life of the stream - creating these is expensive. 2.) If you're going to implement this write unit tests against NIST vectors or similar. Don't assume you got this right - just because the output looks random, doesn't mean it's correctly enciphered :).
If anyone has any thoughts on a better approach or how I've totally mucked up a really critical piece of code, please post, thanks!
I think such an implementation would not be very useful, as Seek operations can only be performed in (relatively, depending on the algorithm) constant time with ECB-style chaining, i.e. encrypting blocks separately - and that's highly unrecommended - see the image in this Wikipedia article for a startling example of insecurity.
Seems to me you would be better off by copying into / out of a MemoryStream or similar wrapping technique.
It is a duplicate question. I put an answer in:
How to add seek and position capabilities to CryptoStream
Even it is using ECB but you can use any other algorithm. by the way it does not have ECB problems as Barry Kelly mentioned because it uses ECB differently.

AES output, is it smaller than input?

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.

Categories