I am using RijndaelManaged to make a simple encryption/decryption utility. This is working fine, but I am trying to get it integrated with another program which is created in Unix (Oracle). My problem is, for all smaller input string, i am getting the exact same encrypted hex as the Unix code is generation, but for longer strings, half of my encrypted hex is same, but the other half is different:
Unix Output:
012345678901234 - 00984BBED076541E051A239C02D97117
0123456789012345678 - A0ACE158AD8CF70CEAE8F76AA27F62A30EA409ECE2F7FF84F1A9AF50817FC0C4
Windows Output (my code):
012345678901234 - 00984BBED076541E051A239C02D97117 (same as above)
0123456789012345678 - A0ACE158AD8CF70CEAE8F76AA27F62A3D9A1B396A614DA2C1281AA1F48BC3EBB (half exactly same as above)
My Windows code is:
public string Encrypt(byte[] PlainTextBytes, byte[] KeyBytes, string InitialVector)
{
byte[] InitialVectorBytes = Encoding.ASCII.GetBytes(InitialVector);
RijndaelManaged SymmetricKey = new RijndaelManaged();
SymmetricKey.Mode = CipherMode.ECB;
SymmetricKey.Padding = PaddingMode.PKCS7;
ICryptoTransform Encryptor = SymmetricKey.CreateEncryptor(KeyBytes, InitialVectorBytes);
MemoryStream MemStream = new MemoryStream();
CryptoStream CryptoStream = new CryptoStream(MemStream, Encryptor, CryptoStreamMode.Write);
CryptoStream.Write(PlainTextBytes, 0, PlainTextBytes.Length);
CryptoStream.FlushFinalBlock();
byte[] CipherTextBytes = MemStream.ToArray();
MemStream.Close();
CryptoStream.Close();
return ByteToHexConversion(CipherTextBytes);
}
Unix (PL/SQL) code:
FUNCTION Encrypt_Card (plain_card_id VARCHAR2)
RETURN RAW AS
num_key_bytes NUMBER := 256/8; -- key length 256 bits (32 bytes)
encrypted_raw RAW (2000); -- stores encrypted binary text
encryption_type PLS_INTEGER := -- total encryption type
DBMS_CRYPTO.ENCRYPT_AES256
+ DBMS_CRYPTO.CHAIN_CBC
+ DBMS_CRYPTO.PAD_PKCS5;
key_bytes_raw RAW(64) :=my_hex_key;
BEGIN
encrypted_raw := DBMS_CRYPTO.ENCRYPT
(
src => UTL_I18N.STRING_TO_RAW (plain_card_id, 'AL32UTF8'),
typ => encryption_type,
key => key_bytes_raw
);
RETURN encrypted_raw;
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line (plain_card_id || ' - ' || SUBSTR(SQLERRM,1,100) );
RETURN HEXTORAW ('EEEEEE');
The only difference i see is use of PKCS5 and PCKS7. But, .NET doesn't have PCKS5.
-
You use ECB in one case and CBC in the other case.
Bhaskar : If I user CBC in my .NET code, it gives a totally different result, for all input strings (small and big).abc : Well, of course. CBC uses a randomly generated IV. Encrypt twice with different IVs and you get different results. That's not a bug. That is how CBC should work.Sani Huttunen : Actually CBC does not use a random IV. ECB doesn't use an IV at all. The difference is that in CBC the previous encrypted block is XOR:ed with the next plaintext block before encryption. Therefore CBC needs an IV to XOR with the first plaintext block since there is no block before the first.Sani Huttunen : Oh, I get you point. You SHOULD generate a random IV. True. (Thought you meant CBC uses an internally generated random IV). The IV must as always be stored/transmitted to the decryptor and is not a secret.abc : Of course it does. Using a fixed IV is incorrect and leads to insecure encryptionSani Huttunen : See my previous comment. :)abc : Ah. I wrote a comment without seeing your answerBhaskar : Just a stupied question....suppose I do my encryption using a Generated random IV, and I send my output hex string (along with the key) to some one esle. He uses his own API to do decryption, since his random IV would be different from mine, wont the decryption cause issue. To mitigate this, we will have to use a fixed IV and share it !!!Sani Huttunen : No... you should send the IV along with the encrypted data. It is not necessary to keep the IV a secret. What is important though is that you do not use the same IV to encrypt different data with the same key.Sani Huttunen : Another note on your "stupid" question: The key is the secret. You should NOT send it along with the encrypted data. You should implement a key sharing scheme (like Diffie-Hellman) to transfer the symmetric key (AES key). In doing so you can safely transfer the IV along with the encrypted data as long as you generate a new IV for each message you transfer. -
What abc said and also you don't seem to have any IV (Initialization Vector) in you Unix code at all.
The fact that the first part are the same has to do with the different modes (ECB and CBC). ECB encrypts each block separately while CBC uses the previous block when encrypting the next one.
What happens here is that since you use CBC and do not set an IV the IV is all zeroes.
That means that the first block of ECB encryption and CBC encryption will be the same.
(Since A XOR 0 = A).You need to make sure you use the same encryption mode in both systems and if you decide on CBC make sure you use the same IV.
Bhaskar : Thanks, that explains a lot. But then, when I use CBC, why does my output encrypted hex is different from the encrypted hex produced by the Unix code, even for smaller input strings. Logically, it should be same, as it is using the same key, IV and the Mode (i.e. CBC).Sani Huttunen : If you use an IV on .NET and you don't set any IV on Unix the IV aren't the same. As I mentioned I cannot see that you set the IV anywhere in the Unix code.Adam Paynter : Using the IV in the PL/SQL ("Unix") code: http://www.mcs.csueastbay.edu/support/oracle/doc/10.2/appdev.102/b14258/d_crypto.htm#i1004325
0 comments:
Post a Comment