views:

2486

answers:

2

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.

+3  A: 

You use ECB in one case and CBC in the other case.

abc
If I user CBC in my .NET code, it gives a totally different result, for all input strings (small and big).
Bhaskar
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.
abc
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.
Sani Huttunen
Of course it does. Using a fixed IV is incorrect and leads to insecure encryption
abc
See my previous comment. :)
Sani Huttunen
Ah. I wrote a comment without seeing your answer
abc
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 !!!
Bhaskar
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.
Sani Huttunen
+9  A: 

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.

Sani Huttunen
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).
Bhaskar
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.
Sani Huttunen
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
Adam Paynter