I'm sending some encrypted data to a client through a web service.
The client had requested that I encrypt the data using a given key and IV. I know you should ideally use a different random IV each time, and I've already raised that with them.
The IV they have provided is a string of length 25. This really doesn't seem right to me.
As far as I was aware the IV length should match the block size, so either 128, 192 or 256 bytes (String lengths 16, 24 or 32). Am I right, or am I missing something here...?
Please note that the IV was provided to me, and therefore I am not trying to pick it.
The provided IV was of the form "ghPNHfg544JUdfjdR5BGVbj67", which I not believe is correct. (The provided key was a string 16 characters long)
Related
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.
I was given a 16 byte key(used to encrypt message in RC4). First 8 bytes are unknown for me. I know that key was created by hashing a message using SHA256(secret) and getting first 16 characters from string obtained from this hashing function. Unfortunately i don't see a way to get the first 8 bytes of this key. As i know SHA256 is one way hashing function(we cant decrypt it). So how i can use half of the key to get a whole? I would be grateful for giving me some advice.
You answered your own question. The point of a hash is that it's very hard to get the original value, and that the hash changes completely when even a single bit is different.
The 8 bytes you're looking for could be anything, dependent solely on the original value that was being hashed. If you don't know the original value, there is no way to determine what the first 8 bytes of the hash are.
My question is about what I actually need to store in the DB re encrypted values and how this can be used for the nonce for GCM specifically.
For reference these two answers provide sample code for encrypting data:
Cbc and gcm.
As I understand it, CBC requires the IV to be totally random. I understand that for CBC (and for all encryption really) the Key/IV should always be unique. If it is repeated it is 'bad' for CBC and a fundamental flaw if using GCM. GCM however does not need it to be totally random as long as it never repeats.
On these assumptions, we plan to have a 'key' somewhere in the app (i.e. separate the key from the encrypted data in the DB). We will roll the key every 'n' months and only use it for 'x' number of encryption before generating a new one (limit scope of use etc), however, we will be using the same 'key' for two or more records. Hence the unique key/iv comes into play.
Note: We need to be able to read out the data again later and 'use' it. This is not one way encryption.
In designing the DB we were going to use columns similar to the following.
DB columns for CBC mode (I have seen something similar on stack overflow... sorry can't find link):
ID (primary key, int)(unique)
Encrypted Value
Salt
Iterations
(Other... standard things like created date etc etc)
Db Columns for Gcm mode:
ID (primary key, int)(unique)
Encrypted Value
Associated Text
(Other... standard things like created date etc etc)
IV/Nonce Handling Question
For the CBC mode, we were just going to use e.g. Rfc2898DeriveBytes and get the IV from that and not store it.
Re the GCM mode, the idea here was to do the following:
Save the record first and 'get' the id of the row
convert the row id into a byte[16]... e.g. (example only...)
var rowID = 123456789.ToString();
var tempByte = new List<byte>(16);
tempByte.AddRange
(123456789.ToString()
.Select(Convert.ToByte));
if (rowID.Length < 16)
{
for (var i = 0; i < (16 - rowID.Length); i++)
{
// Note: something to fill the rest.....
var someNewByteFromSecureRandom = new[] {Convert.ToByte(1)};
tempByte.Add(someNewByteFromSecureRandom[0]);
}
}
Save the encrypted data into the row.
This way, the nonce is always going to be unique for the GCM encryption. Even if we always use the same key, the key/iv will never repeat. (Note: this approach would as we understand it not work for CBC because of its requirement that the iv be truely random and not a counter)
Basically, is there a problem with either of these approaches? (Ignoring the obvious dual save (insert/update) of the record when using the GCM approach outline to get the nonce). Are we saving something we should not? Are we not saving something we should?
Presumption: you are only protecting data at rest, i.e. active attacks on the data while the database is being utilized are not considered.
CBC requires the IV to appear random to an attacker, CBC could use an encrypted counter (the row ID) as IV;
to use a row ID as a nonce, you need to start the IV (rightmost bytes) with the row ID (converted into a 12 byte unsigned big endian number) - the leftmost bytes should be kept empty for maximum compatibility
CBC doesn't require PBKDF2 (so no salt or iteration count) if you already have a key - you could just store a random IV instead of the salt
"Associated Text" has no meaning on its own. GCM takes Additional Associated Data - or AAD - as input parameter. So the AAD is just any data in your database that you want to include in the authentication tag. GCM already includes the IV into the authentication tag so you don't have to include the row ID;
CBC is enough for data at rest as nobody should be able to change the data (that would be an active attacker, which is ruled out for data at rest); that said, GCM does catch any wrong key/wrong data error so it could be used to simplify error handling for your application.
Note that using a nonce of 12 bytes will limit the plaintext to 2^36 bytes (64 GiB). That should not be a problem for database entries (I hope). You could throw an error or runtime exception if you ever encounter such a large plaintext though.
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.