Key + initialization vector to a new key? - c#

I have an API that decrypts data. This API receives only key (bytes of an AES key). This API does not receive initialization vector (It uses vector of zeros as an initialization vector).
I'm receiving from 3rd party an encrypted data. This data was encrypted to AES 256 using a specific key and initialization vector.
I have the key and the initialization vector. Is there a way to decrypt this data using the API? or, in other words, if the key and the initialization vector are constants and I have them both, can I create a key that will allow me to decrypt this data with a {0, 0, 0, ...} initialization vector?
Thanks.

Yes it is possible to decrypt ... no not the way you described
AES is a block cipher
most of the time the cipher isn't used as it is, but it is put into a special mode of operation (this is what your API probably is not capable of)
you will have to implement the decryption routine around the cipher and use your AES-API just as a crypto-primitive
for example, the decryption of AES-CBC using a generic AES implementation
split ciphertext into 128 bit blocks and number them from index 1 onward
prepend the IV as cypher_block 0
now to obtain the plaintext we can define a function around your API function
plaintext_block[i] = cypher_block[i-1] XOR aes_decrypt(cypher_block[i],key)
as you can see, you can obtain all plaintext blocks from index 1 onward ...
once you have obtained all plaintext blocks you will probably want to strip padding, but that's another story ...

Related

How to encrypt client private key using server public key rsa in C#

This is a piece of my code that encrypts a private key:
string pemContent = File.ReadAllText(pemPath);
csp.ImportFromPem(pemContent);
string test = rsa.GetPrivateKey();
var data = Encoding.UTF8.GetBytes(test);
var cypher = csp.Encrypt(data, false);
Console.WriteLine(Convert.ToBase64String(cypher));
This is the GetPrivateKey() function:
public string GetPrivateKey()
{
return rsa.ToXmlString(true);
}
I get this error:
Internal.Cryptography.CryptoThrowHelper.WindowsCryptographicException: 'Bad Length.'
I know by now that private key is to big to encrypt it with client public key and the question is how to make is possible?
I can't find anything similar to what I am doing, the only clue I have is that wannary used the same technique while its file encryption process.
I use RSACryptoServiceProvider to handle rsa encryption.
EDIT:
Maybe i should describe my case more in detail. I am building a simple ransomware (i (i am a cybersecurity enthusiast and i do it just to learn how this viruses works in depth, so it's for educational purposes only). More advanced ransomware uses hybrid encryption. The scheme i am trying to implement is well described in this video. I am stuck in the last step which is encrypting client private key with server public key.
I'm presuming RSA here, it's not directly in the question, but it can be concluded from the code. Also, because of the second parameter of Encrypt being false, I'll assume PKCS#1 v1.5 padding.
There are two ways to do this. One you have already mentioned, and it is the best option: use hybrid encryption. You first create a random encryption key, encrypt the RSA key, and then encrypt that key.
The second way is to simply use a larger RSA key pair for the server. PKCS#1 v1.5 padding has a minimum overhead of 11 bytes, 8 of which are non-zero random. It's better to use 16 bytes of random data though, so then you'd have 19 bytes / 152 bits of overhead. For more information on the overhead of RSA encryption see my answer here.
The encoded private key needs to be in the remaining bits. Now it is best to use the minimum amount of bits to encode the private key. The best way to do this is to encode the modulus and only the private exponent (i.e. without the CRT parameters). Each of these will take as many bits as the key size if you use a constant sized, unsigned big endian encoding. So the key pair needs to be klen * 2 + 152 bits.
Note that this is not necessarily the best option as there could be schemes that allow you to never generate the private key on the client in the first place, until the private key needs to be released for decryption that is.

SHA1 with RSA encryption: bad length error

Probably I have several misunderstandings.
AFAIK signing a byte array with RSA-SHA1 generates a byte array (signature) of the same lenght as the RSA key used. Is that right?
From another side signing, roughly means generate a hash using SHA1 (so it is 160 bites long) and then with or without a padding scheme encrypt it with the private key.Is that right?
Later on, in order to recover this hash (with or without padding schema on it) I would need to encrypt the signature with the public key. Is that right?
Something is broken in my logic because I'm not able to encrypt the signature with the public key.
Or my code is wrong. I'm using .net RSACryptoServiceProvider and it raises a bad data length error when trying to encrypt a signature... I assume encrypt means apply RSA using public key, right?
When trying to decrypt it raises a Key Not found exception. As expected because I only have the public key.
EDIT:
Given a byte array and RSACryptoServiceProvider I could Encrypt, Decrypt and SignData. I thought that SignData (without padding schema to simplify the question) is a shortcut of apply SHA, then Decrypt. For Encrypt I mean applying the RSA formula using public key as input, and for Decrypt I mean applying the RSA formula (the very same formula) using private key as input. Are this definitions ok?
EDIT2:
For exemple have a look at the next signed xml: http://www.facturae.gob.es/formato/Versiones/factura_ejemplo2_32v1.xml
And the next powershell script:
$signb64="oYR1T06OSaryEDv8VF9/JgWmwf0KSyOXKpBWY4uAD0YoMh7hedEj8GyRnKpVpaFanqycIAwGGCgl vtCNm+qeLvZXuI0cfl2RF421F8Ay+Q0ani/OtzUUE49wuvwTCClPaNdhv2vfUadR8ExR7e/gI/IL 51uc3mEJX+bQ8dxAQ2w=";
$certB64="MIIDtDCCAx2gAwIBAgICAIcwDQYJKoZIhvcNAQELBQAwcjELMAkGA1UEBhMCRVMxDzANBgNVBAgT Bk1hZHJpZDEPMA0GA1UEBxMGTWFkcmlkMQ4wDAYDVQQKEwVNSVR5QzEbMBkGA1UECxMSTUlUeUMg RE5JZSBQcnVlYmFzMRQwEgYDVQQDEwtDQSB1c3VhcmlvczAeFw0wOTEwMTUxNjA5MzRaFw0xMDEw MTUxNjA5MzRaMHExCzAJBgNVBAYTAkVTMQ8wDQYDVQQIEwZNYWRyaWQxDzANBgNVBAcTBk1hZHJp ZDEOMAwGA1UEChMFTUlUeUMxGzAZBgNVBAsTEk1JVHlDIEROSWUgUHJ1ZWJhczETMBEGA1UEAxMK VXN1YXJpbyA1NDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAroms65axKuQK18YDfD/x6DIn 0zKZ+6bv1K2hItJxel/JvU3JJ80/nY5o0Zbn+PrvlR2xF3poWYcPHLZpesgxhCMfnP7Jb5OUfceL g44m6T9P3PG1lSAZs3H6/TabyWGJy+cNRZMWs13KnB9fDAjJ5Jw0HVkwYNwmb1c7sHCuyxcCAwEA AaOCAVgwggFUMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgXgMB0GA1UdDgQWBBTYhqU2tppJoHl+S1py BOH+dliYhzCBmAYDVR0jBIGQMIGNgBT1oWqod09bsQSMp35I8Q6fxXaPG6FypHAwbjEPMA0GA1UE CBMGTWFkcmlkMQ8wDQYDVQQHEwZNYWRyaWQxDjAMBgNVBAoTBU1JVHlDMRswGQYDVQQLExJNSVR5 QyBETkllIFBydWViYXMxEDAOBgNVBAMTB1Jvb3QgQ0ExCzAJBgNVBAYTAkVTggEDMAkGA1UdEQQC MAAwNgYDVR0SBC8wLYYraHR0cDovL21pbmlzdGVyLThqZ3h5OS5taXR5Yy5hZ2UvUEtJL0NBLmNy dDA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vbWluaXN0ZXItOGpneHk5Lm1pdHljLmFnZS9QS0kv Y3JsLmNybDANBgkqhkiG9w0BAQsFAAOBgQAhAN/KVouQrHOgd74gBJqGXyBXfVOeTVW+UTthhfCv DatXzTcrkYPQMfBAQMgGEa5KaQXcqKKhaoCUvrzFqE0HnAGX+ytX41oxZiM2fGNxRZcyUApLEX67 m8HOA/Cs2ZDlpU2W7wiOX5qr+ToTyfXsnRwPWvJ8VUmmXwyMEKcuzg==";
$signb=[System.Convert]::FromBase64String($signB64);
$certb=[System.Convert]::FromBase64String($certB64);
$cert = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Certificate2 -ArgumentList #(,$certb)
$rsacsp = [System.Security.Cryptography.RSACryptoServiceProvider] $cert.PublicKey.Key;
$signb.Length*8;
$rsacsp;
$rsacsp.Encrypt($signb,0);
I tried:
$rsacsp.Encrypt($signb,[System.Security.Cryptography.RSAEncryptionPadding]::Pkcs1);
instead of
$rsacsp.Encrypt($signb,0);
But I always get a bad length error:
Exception calling "Encrypt" with "2" argument(s): "Bad Length.
EDIT 3:
After reading, I can see my main issue was "From another side signing, roughly means generate a hash using SHA1 (so it is 160 bites long) and then with or without a padding scheme encrypt it with the private key.Is that right?".
RSA sign (with a n bits key length) could be viewed as an operation that takes an arbitraty byte array and outputs n bits. In order to do that, it uses a hash function like SHA1 that takes an arbitrary byte array and produces a fixed output (160 bits for SHA1). Now in theory I could "encrypt" with the private key but then the output would be 160 bits long too it is not the way RSA is implemented. RSA Signing needs to apply padding function after the hash in order to produces an n bits text before "encrypting" it.
Another source of confusion is the meaning of the Encrypt method of .NET RSACryptoProvider. It turns out that this method has two parameters: a byte array and a flag indicating the padding function. It takes the byte array, applies the padding and then "encrypts" with the public key. It is of no use for a signature scenario. The operations decrypt and encrypt in RSACryptoProvider are not simmetrical. You can "decrypt" whatever has been "encrypt", but not the other way around.
At the end the confusion lies in that "atomic" functions used when encrypting/decrypting and the ones used when signin are the same, but they are used in incompatible ways.
AFAIK signing a byte array with RSA-SHA1 generates a byte array (signature) of the same lenght as the RSA key used. Is that right?
Usually yes, although the size will of course be encoded as octet stream (aka byte array) it is possible that the size of the signature is actually up to 7 bits larger. The key size is normally a multiple of 8 (bits) so this doesn't come up much.
From another side signing, roughly means generate a hash using SHA1 (so it is 160 bites long) and then with or without a padding scheme encrypt it with the private key.Is that right?
No, you should never perform modular exponentiation in RSA without padding; a padding scheme is required for security. Note that you should not talk about encryption here. Encryption is used to provide confidentiality. That RSA signature generation and encryption both uses modular exponentiation - although with different keys - doesn't mean one equates the other.
It is important to note that the padding scheme for PKCS#1 v1.5 encryption is different from the one used for signature generation. Furthermore there are also the newer OAEP padding scheme for encryption and the PSS padding scheme for signature generation which are rather distinct.
Later on, in order to recover this hash (with or without padding schema on it) I would need to encrypt the signature with the public key. Is that right?
Perform modular exponentiation and then verify the result, yes. But as the verification requires verifying the padding in a secure way you should really let an API handle this.
Something is broken in my logic because I'm not able to encrypt the signature with the public key.
Try something written for verification instead, like the method VerifyHash as seen in this example.
You can try and find a raw RSA implementation to find out what is within the RSA signature. You should only do this to analyze the signature.
So if you "encrypt" the data with the public key (i.e. just perform modular exponentiation) you would get:
0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003021300906052b0e03021a05000414a2304127e2fe3b8a8203b219feafdd9b58558310
as result. This is clearly PCKS#1 v1.5 padding for signature generation. It includes an encoded hash value:
SEQUENCE(2 elem)
SEQUENCE(2 elem)
OBJECT IDENTIFIER1.3.14.3.2.26
NULL
OCTET STRING(20 byte) A2304127E2FE3B8A8203B219FEAFDD9B58558310

Manipulating the Initialization Vector does not (really) prevent me from decrypting AES ciphertexts

I created the following class, based from the examples on MSDN:
https://gist.github.com/anonymous/19d9e5f6747dfe75d553
Whenever I use it like this, it seems like it encrypts fine:
var key = Crypto.GenerateKey();
var vector = Crypto.GenerateVector(key);
var cypherText = Crypto.EncryptBase64("abcdefghijklmnopqrstuvwxyz1234567890", key, vector);
vector = Crypto.GenerateVector(key);
var plainText = Crypto.Decrypt(cypherText, key, vector);
Then plainText contains the following:
�\aU��(���P\u0003�b\u001dxqrstuvwxyz1234567890
So it seems changing the IV, doesn't really do anything (especially on longer documents). Why do we even need an IV?
The default mode of operation for SymmetricAlgorithm is CipherMode.CBC.
Given the way how the CBC mode works the change of IV of encrypted data will impact only the first decrypted block of data.
Citing the linked article:
Decrypting with the incorrect IV causes the first block of plaintext
to be corrupt but subsequent plaintext blocks will be correct. This is
because a plaintext block can be recovered from two adjacent blocks of
ciphertext. As a consequence, decryption can be parallelized. Note
that a one-bit change to the ciphertext causes complete corruption of
the corresponding block of plaintext, and inverts the corresponding
bit in the following block of plaintext, but the rest of the blocks
remain intact.
This is one of the reasons why encryption without authentication (e.g. here) is not a good idea.
On the other hand changing the IV during the encryption results in a completely different ciphertext as the change in the first block is propagated to all the subsequent blocks.
Desclaimer: I am no crypto expert, so please do validate my thoughts.

Converting Laravel's AES 256 Encryptor to C#

I need to create the same results when using Crypt::Encrypt('secret') from Laravel, in C#.
I found this thread Rijndael 256 Encrypt/decrypt between c# and php?
and it seemed to be what I need, but I'm having some trouble with the third argument the, initialization vector :(.
Laravel using Rijndael AES to encrypt the data. All the user has to input is a secret key, in the config folder, that is totally random and 32 characters long.
The encyrption method looks like this:
public function encrypt($value)
{
$iv = mcrypt_create_iv($this->getIvSize(), $this->getRandomizer());
$value = base64_encode($this->padAndMcrypt($value, $iv));
// Once we have the encrypted value we will go ahead base64_encode the input
// vector and create the MAC for the encrypted value so we can verify its
// authenticity. Then, we'll JSON encode the data in a "payload" array.
$mac = $this->hash($iv = base64_encode($iv), $value);
return base64_encode(json_encode(compact('iv', 'value', 'mac')));
}
The full Encryptor.php can be found here: http://pastebin.com/yfWLPxGn
Any idea as to what I would have to input to get the same results? :)
Initialization vector is an input that is typically random. So, algorithm always creates a different value using the same input, key and the different IV. If you'd like to generate same result using both PHP and C# code, you need to use the same IV value.
Laravel's encrypt() does not return the encrypted value only. The value encrypt() generates a base64 encoded string which has json encoded values of iv, mac and encrypted value.
So the steps you need to apply in your C# encode() method:
Encode the string using the code in the link you gave.
base64_encode() the encrypted value. We will use this value in the further steps.
Create MAC (Message Authentication Code) using base64_encoded IV as the value, encrypted value as the key and sha256 as the algorithm. Take a look at this one
Now we have encrypted value, mac and iv.
Create a json string like this:
{
iv: iv value (base64 encoded),
value: encrypted value (base64 encoded),
mac: mac value created in 3rd step
}
base64 encode your this json string.
You're all set.
You would want to not apply padding and not apply any specific mode of operation. There is a pseudo-mode called ECB which basically applies the bare cipher over many blocks and applies no padding. It requires full blocks to be used.
If you don't have a full block to encrypt, you need to figure out what padding mode is used.
If that doesn't work, then you need to figure out what mode and what initialization vector is used. An initialization vector is usually prepended to a message as a unique value that varies per message, as a way to prevent some mathematical attacks on bare ciphers applied over many blocks.

AES encryption key and IV

I have a function that encrypts my key text input from the user using AES. and decrypts it on request. What is an ideal way to maintain the key and IV for AES encryption(As of now hard-coded in application). I save the encrypted data every time in database. On page load encrypted value is retrieved from database. This value is decrypted on a button click. Is there any best I could use key and IV in a better way.
The IV can be saved (or can even be "exposed"/transmitted publicly); it is no 'secret'. The key should be kept private. So you could save/transmit your data like <iv_here>;<encrypted_data_here>.
See wikipedia:
An initialization vector (IV) is a block of bits that is used by several modes to randomize the encryption and hence to produce distinct ciphertexts even if the same plaintext is encrypted multiple times, without the need for a slower re-keying process.
An initialization vector has different security requirements than a key, so the IV usually does not need to be secret. However, in most cases, it is important that an initialization vector is never reused under the same key.

Categories

Resources