Jump to content
dormky

What is the algorithm used to derive the key to a TMyEncryptor ?

Recommended Posts

My MyDAC expired long time ago, and i never used their Password2Key algorithm, i always used a key directly with the encryption, but when needed to be password derived i used HMACSHA256, the algorithm to derive the key (in the my TCREncryptor) is outdated and not secure enough to provide 256bit security and may be not even enough for 128bit, the code does concatenate the SHA1 with MD5 of the password.

 

Anyways, you would better contact their support for this question in case you can't recognize the used algorithm, while if you have the source as i do, then it should be in "procedure TCREncryptor.Password2Key;", but again in MyDAC there is no TMyEncryptor, there is only TCREncryptor, which means they did refactor this and may be the algorithm too.

Share this post


Link to post

However, also i looked at my UniDAC (also expired but way newer than MyDAC) and there is TUniEncryptor and as the DAC components are shared between all DevArt libraries, i think the algorithm is still that old and with not best practice or standard password-key derivation, as changing it will break compatibility unless it is explicitly had an option to switch to newer one, and i don't see such option, in the online help for the latest ones.

 

Share this post


Link to post

Okay I'm not sure I understand what you're saying but

1) You have the source-providing license

2) In the source you can see the Password2Key function concats the the SHA1 and MD5 of the password to generate the key ?

 

I suppose it's still like this because TMyEncryptor just inherits from TCREncryptor and doesn't actually add anything from what I can see. Probably they wanted it named with a "My". I'll try a python script to reproduce the encryption and see if SHA1+MD5 lands me on the same results. Thanks.

Share this post


Link to post

Just occurred to me that I won't know how they're padding the content... So yeah.

Share this post


Link to post
2 hours ago, dormky said:

1) You have the source-providing license

Yes, (though outdated).

2 hours ago, dormky said:

2) In the source you can see the Password2Key function concats the the SHA1 and MD5 of the password to generate the key ?

Also yes.

2 hours ago, dormky said:

I'll try a python script to reproduce the encryption and see if SHA1+MD5 lands me on the same results. Thanks.

Your problem is not with the key itself, the key literally as i mentioned above, concatenating SHA1 and MD5 of the password, also the mode is CBC, so less work there.

 

Your problem is in the code in TCREncryptor.Decrypt (and TCREncryptor.EncryptBytes) , these are very nicely done and very secure with authenticated encryption (with TagAndHash enabled), along random IV for each and every encryption operation followed by magic number "$BAADF00D" indicates the length of the data, hence removing the need for padding, it is well done until they missed to include hashing the IV with data (!!) this will leak information about the encrypted data.

You are more secure with only "ehTag" in DataHeader property than "ehTagAndHash", no leaked information about the data, preventing any differential analysis, but with this you will lose the authentication.

 

I am sorry that i can't share any source code from a proprietary code licensed to me, as you seem you don't have it, but with the above few lines you can ask them to fix their mistake and answer your support ticket.

 

Hope that helps.

Share this post


Link to post

So after looking more at the encryption code, i stand with claim above, but ..

 

It could be my old and outdated sources, they either :

1) Should hashed the data along with the randomly generated IV, and leave it out of the encryption, or

2) They should have encrypted the hash along with the data, as this looks like a single mistake (old mistake), it might be changed or fixed, though this will break compatibility between versions, the code to fix this

FEncryptor.EncodeBuffer(TValueArr(Result), KEY_GUID_LEN + IV_LEN, CipherLen - HashLen, TValueArr(Result), KEY_GUID_LEN + IV_LEN);
// should be 
FEncryptor.EncodeBuffer(TValueArr(Result), KEY_GUID_LEN + IV_LEN, CipherLen , TValueArr(Result), KEY_GUID_LEN + IV_LEN);

 

Any fix will break compatibility, so in my opinion they should deprecate "ehTagAndHash" and use it only for decryption, and introduce ehTagAndHash2 with either of two suggestions above, but this will break compatibility backward too.

Of course any changes of the above suggestion need adjustment in the decryption too.

Share this post


Link to post

> hence removing the need for padding

That cannot be correct, Blowfish (the default algorithm which I am using here) requires padding ?

 

The security of the encryption is not my problem here, the problem is that I cannot read the data using anything other then a Devart product. The data is already encrypted so nothing about the algorithm can be changed, I need to use the exact same process.

 

I've tried to recreate the same process in python with PKCS7 padding but I don't get the same result.

Share this post


Link to post
26 minutes ago, dormky said:

> hence removing the need for padding

That cannot be correct, Blowfish (the default algorithm which I am using here) requires padding ?

Padding has nothing to do with symmetric encryption itself, padding is standardized way to prevent data lose, many libraries force you to use padding out of best practice and to comply with Modern Security standards, in other words to prevent you from shooting your foot, but there is also libraries (if not all of them) that allow you to manually handle this.

And you said you are using , in Delphi ? in Python ? DevArt library ?

TCREncryptor doesn't use padding PKCS7 or any other, it does ship the length (4 bytes length) after magic number before the encrypted data and after the random IV.

 

26 minutes ago, dormky said:

The security of the encryption is not my problem here, the problem is that I cannot read the data using anything other then a Devart product. The data is already encrypted so nothing about the algorithm can be changed, I need to use the exact same process.

Now i do understand that, and i am trying to help by explaining, your lack of understanding padding and when to use it, will stop you, TCREncryptor doesn't use padding as you assume.

 

26 minutes ago, dormky said:

I've tried to recreate the same process in python with PKCS7 padding but I don't get the same result.

No joy there, because no padding, if you insist then pad it with 0 or random, with CBC it will not make a difference, as you will already have the length as i explained, right before the data.

 

Now to your problem,

Are you trying to decode the data in full ?

As i explained the encrypted data are structured and you only need to decrypt part of it, if you see the lines i pasted above 

The encrypted data start at KEY_GUID_LEN + IV_LEN , 16+8 bytes, at 24, the length is ... till the end in case of "ehTag" or leaving the length of the hash to the according algorithm when "ehTagAndHash", in my UniDAC version there is only two hash algorithms MD5 and SHA1.

The encrypted data include INTERNAL_HEADER_LEN bytes which is 8 bytes, this is the magic number with the length (removing the need for padding), so after decryption you need to check for the magic number and get the length then trim the decrypted data accoring to the length.

Share this post


Link to post

I don't get what you mean by "magic number", and your way of writing makes it very hard to understand what you mean 😕 If you can't provide the algorithm used that's fine I understand.

 

I really don't get how you can encrypt with blowfish without padding, since blowfish uses 8-bytes blocks. Is the padding simply ignored with the length is known ? When I try to pass data that is not a multiple of 8 bytes, python's cryptography package raises an error.

Also my encrypted test data is only 8 bytes (4 characters), I'm not using tag and hash. And all this is irrelevant as long as I don't have the algorithm that derives the key from the password, it's the only thing I need.

Edited by dormky

Share this post


Link to post
44 minutes ago, dormky said:

I don't get what you mean by "magic number", and your way of writing makes it very hard to understand what you mean 😕 

Magic number is fixed 4 bytes value implemented in TCREncryptor as header its value "BAADF00D" in HEX, 

Sorry, for my writing way, well i am trying my best to explain, the problem i can't know where your knowledge limit about encryption to expand, so i write in a way i see serve the most.

 

44 minutes ago, dormky said:

If you can't provide the algorithm used that's fine I understand.

 

I really don't get how you can encrypt with blowfish without padding, since blowfish uses 8-bytes blocks. Is the padding simply ignored with the length is known ? When I try to pass data that is not a multiple of 8 bytes, python's cryptography package raises an error.

Also my encrypted test data is only 8 bytes (4 characters), I'm not using tag and hash. And all this is irrelevant as long as I don't have the algorithm that derives the key from the password, it's the only thing I need.

You have problem understanding symmetric encryption and its modes, you need to read more, and i will expand here what can help you.

 

Yes all symmetric algorithms including BlowFish need specific block size, but it doesn't affect the output, the output is affected by the mode of the encryption, ...... i am not going to torture you with more text,

Pad the god damn thing with anything to make it work ! 

is that better, but don't use any specific padding on decryption because it will fail ! , if your python library enforced to use padding then look for different library that allow no padding, and by padding i mean the algorithm defined in RFCs, not the block padding to ensure the block length, the encrypted data should be already multiple of 8.

 

again the structure of the encrypted data, these concatenated 

KEY_GUID + IV +CIPHER [+HASH]

KEY_GUID is fixed constant of 16 bytes declared internally declared and shipped unencrypted, it has no weight or value on encryption, starting with $C5 .. ending with $01, simply an identifier that the encryption done by DevArt library.

IV well .. 8 bytes 

HASH depends on the Hash algorithm SHA1 or MD5 (property in the encryptor compenent) and if  "ehTag" then it will not be included while "ehTagAndHash" means it is there

 

CIPHER is INTERNAL_HEADER + PLAIN_DATA

INTERNAL_HEADER is 8 bytes long, contains magic number, aka constant of 4 bytes with "$BAADF00D" in HEX , followed by 4 bytes contain the PLAIN_TEXT length

 

To generate the key, calculate SHA1 and MD5 of the password then concat them, then use the first bytes to fit the key length you need ! simple as that

IV you have it in above after KEY_GUID

Don't use BlowFish implementation that require padding !

 

Hope that helps.

Edited by Kas Ob.

Share this post


Link to post

The IV and other metadata cannot be contained in the data. I just tried with just the letter 'A' and the output is always the same 2 bytes.

Therefore, the IV is a hardcoded value somewhere. Could you share this ?

Share this post


Link to post
32 minutes ago, dormky said:

I just tried with just the letter 'A' and the output is always the same 2 bytes.

I am lost here, what metadata ?

What "A" and where did you get it, are trying to encrypt ? 

Tried what ?

 

31 minutes ago, dormky said:

Therefore, the IV is a hardcoded value somewhere. Could you share this ?

there is no hardcoded IV.

IV is randomly generated as i said and included in the bytes/blob/strings/widestrings/memo... encrypted data

Share this post


Link to post

There is nothing added to the encrypted data. No IV, no hash, no guid, and I know this because like I said, the output is extremely small and physically cannot contain enough data. Just the letter A gives me one or 2 bytes as a result.

Here is some code to reproduce :

 

program Project;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  System.Hash,
  Data.DB,
  CREncryption,
  MyAccess;

var
  conn: TMyConnection;
  table1, table2: TMyTable;
  keyBytes, sha1, md5: TBytes;
  query: TMyQuery;

begin
  SetLength(keyBytes, 36);
  sha1 := THashSHA1.GetHashBytes('pass');
  md5 := THashMD5.GetHashBytes('pass');
  Move(sha1[0], keyBytes[0], 20);
  Move(md5[0], keyBytes[20], 16);
  
  conn := TMyConnection.Create(nil);
  conn.Port := 3306;
  conn.Username := 'root';
  conn.Password := 'toor';
  conn.Server := 'localhost';
  conn.Connected := True;
  
  conn.ExecSQL('DROP DATABASE IF EXISTS encryptor_test;');
  conn.ExecSQL('CREATE DATABASE encryptor_test;');
  conn.ExecSQL('USE encryptor_test;');
  conn.ExecSQL('CREATE TABLE test_data (`Name` varchar(255));');

  table1 := TMyTable.Create(nil);
  table1.Connection := conn;
  table1.TableName := 'test_data';
  table1.FieldDefs.Add('Name', ftString, 250);
  table1.Encryption.Encryptor := TMyEncryptor.Create(nil);
  table1.Encryption.Encryptor.DataHeader := ehNone;
  table1.Encryption.Encryptor.Password := 'pass';
  table1.Encryption.Fields := 'Name';
  table1.Active := True;

  table1.Insert();
  table1.FieldByName('Name').Value := 'A';
  table1.Post();
  
  table2 := TMyTable.Create(nil);
  table2.Connection := conn;
  table2.TableName := 'test_data';
  table2.FieldDefs.Add('Name', ftString, 250);
  table2.Encryption.Encryptor := TMyEncryptor.Create(nil);
  table2.Encryption.Encryptor.DataHeader := ehNone;
  table2.Encryption.Encryptor.SetKey(keyBytes, 36);
  table2.Encryption.Fields := 'Name';
  table2.Active := True;

  table2.Insert();
  table2.FieldByName('Name').Value := 'A';
  table2.Post();
end.

 

Strangely enough when using password the output does not change : E2. When using SetKey, the result varies so I suppose the IV is directly derived from the password.

I'm getting a single byte here as output instead of 2 in the full project though, which is strange.

 

Edit : Signing of for the day, have a nice weekend !

Edited by dormky

Share this post


Link to post

Have a good weekend too !

 

and now i do understand your points, also it took me long time as i don't want to mess with packages installation, as MyDAC and UniDAC can't be installed together unless the DAC version is identical, anyway...

 

1) The i described building the key is working fine, i checked and it is fine.

here a simple way to build the key and use it using only UniDAC classes

var
  keyBytes: TBytes;
  HashSHA1 : THashAlgorithm;
  HashMD5 : THashAlgorithm;
begin
  HashSHA1 := THash_SHA1.Create;
  try
    HashSHA1.Initialize;
    HashSHA1.ComputeHash(BytesOf('pass'));

    HashMD5 := THash_MD5.Create;
    try
      HashMD5.Initialize;
      HashMD5.ComputeHash(BytesOf('pass'));

      keyBytes := HashSHA1.Hash + HashMD5.Hash;
    finally
      HashMD5.Free;
    end;
  finally
    HashSHA1.Free;
  end;

2) The encoding and decoding using CBC without padding is fine as i described it, here your 'A' with ehTag and ehTagAndHash in order

C544E5292C9C42A5B94FE279127029010796125FFF7BB9A7408E02812A51D5F81FC2053401075D2A

C544E5292C9C42A5B94FE27912702901DF4BEED6024BC5FE214A4205B1EE9981DAF4C7C56DCD4CE23D88E2EE9568BA546C007C63D9131C1B

while with none it is two bytes

E2

Now what is going on, that is strange thing to encrypt without IV, in fact you can't and shouldn't not do that , that is wrong on so many levels !!!!!

The IV is zeroed in this case, and this is what you are missing, simple like that.

Anyway E2 is HEX you need to de-hex it first then perform decryption in CBC mode, may be i missed mentioning this, but hey.. i don't know if you don't know that encryption with DB should be either binary in blob or HEX in plain text fields.

 

--------------

Additional information changing the code a little to insert two 'A' rows, to show the information leak 

with ehNone we have two rows have the same encrypted value two chars (value = 'E2'), leaking critical information, exposing the data is identical

with ehTag we have

C544E5292C9C42A5B94FE27912702901CA9469BBB8503499CDFA76E7E84DBE9BCB48BF853F5A2643
C544E5292C9C42A5B94FE279127029010F89F0C11CB311D592EA28B171C712B5C7725B0130002CE8

and with ehTagAndHash

C544E5292C9C42A5B94FE2791270290152F2428A526B0345481FAB80E42E687379477B776DCD4CE23D88E2EE9568BA546C007C63D9131C1B
C544E5292C9C42A5B94FE2791270290173F9E56EB70F416E1C5B5CAD820E2220584574896DCD4CE23D88E2EE9568BA546C007C63D9131C1B

Now do you see the information leak ?!, yes the hash is the same with ehTagAndHash exposing that the encrypted data was the same !!

 

So until DevArt fix this, everyone should only use "ehTag"

Share this post


Link to post

Also SetKey is buggy !!! and not only !

procedure TCREncryptor.SetKey(const Key; Count: Integer);
begin
  SetKey(TBytes(@Key), 0, Count);   // TBytes(@Key) instead of TBytes(Key) 
end;

procedure TCREncryptor.SetKey(const Key: TBytes; Offset, Count: Integer);

 

  • Like 1

Share this post


Link to post

Just to fix your problem and workarounds

 

The hash of the password is generated from the WideString of encoded password so 

const
  PASSWORD = 'pass';
var
  keyBytes, PassBytes: TBytes;
  HashSHA1: THashAlgorithm;
  HashMD5: THashAlgorithm;
begin
  PassBytes := BytesOf(@WideString(PASSWORD)[1], Length(PASSWORD) * SizeOf(WideChar));

  HashSHA1 := THash_SHA1.Create;
  try
    HashSHA1.Initialize;
    HashSHA1.ComputeHash(PassBytes);

    HashMD5 := THash_MD5.Create;
    try
      HashMD5.Initialize;
      HashMD5.ComputeHash(PassBytes);

      keyBytes := HashSHA1.Hash + HashMD5.Hash;
      SetLength(keyBytes, 32);   // doing it here is better, triming here 32 for BlowFish or we can later use specify length at 32 with SetKey
    finally
      HashMD5.Free;
    end;
  finally
    HashSHA1.Free;
  end;
  
  ....
  
    table2.Encryption.Encryptor.SetKey(keyBytes, 0, Length(keyBytes));   //  length should be 32 but we don't want to overflow

1) Any hash library will do the same you are free to use your own 

2) The length is critical so make sure you are feeding 32 bytes, (and no more ! as strangely enough it does affect the output, meaning the SetKey is not protected from overflowing)

3) There is two version of SetKey, one is bugged and wrong the other does work fine, use the one with the offset and require TBytes as parameter, the one with 3 parameters.

  • Thanks 1

Share this post


Link to post

Yeah I know doing encryption like this is BAD (we've had multiple cases of the program not releasing a string is encrypted and using it as-is...), I'm not the one who made this... I'm the one stuck dealing with it 🙂

Jesus Christ, the bug with SetKey !! No wonder the output changes all the time...

 

For future reference, my updated testing code with the corrections needed for it to output the same thing with Password and SetKey :

 

var
  conn: TMyConnection;
  table1, table2: TMyTable;
  keyBytes, PassBytes, sha1, md5: TBytes;
  query: TMyQuery;

begin
  PassBytes := BytesOf(@WideString('pass')[1], Length('pass') * SizeOf(WideChar));
  
  SetLength(keyBytes, 36);
  sha1 := THashSHA1.GetHashBytes(TBytesStream.Create(PassBytes)); // Memory leak lol
  md5 := THashMD5.GetHashBytes(TBytesStream.Create(PassBytes));
  Move(sha1[0], keyBytes[0], 20);
  Move(md5[0], keyBytes[20], 16);

  // --- //

  table2.Encryption.Encryptor.SetKey(keyBytes, 0, 32); // 0 to get the correct function

 

Many thanks Kas !!

I've been trying to use LockBox3 to create the same result, unfortunately I can't quite get it. 'A' is the same value no matter the encoding but I get 41 as output instead of E2. I need to check deeper into the (undocumented) code of LockBox3 to see what I'm doing wrong (hopefully it isn't MyDAC doing something wrong...)

 

  Codec := TSimpleCodec.Create();
  Codec.StreamCipher := TBase64Converter.Create();
  Codec.BlockCipher := TBlowFish.Create();
  Codec.ChainMode := TCBC.Create();
  SetLength(LBKeyBytes, 34);
  Move(keyBytes[0], LBKeyBytes[1], 32);
  LBKeyBytes[0] := 32; // Length of the key
  LBKeyBytes[33] := 0; // Does the key contain the sotres
  Codec.InitFromStream(TBytesStream.Create(LBKeyBytes));
  Codec.EncryptString('A', outputText, TEncoding.UTF8); // outputText in base64, translated to hex => 41

Edit : Dear god, 41 = 'A' to begin with... This is not encrypting anything !!

Edited by dormky

Share this post


Link to post
18 minutes ago, dormky said:

I've been trying to use LockBox3 to create the same result, unfortunately I can't quite get it. 'A' is the same value no matter the encoding but I get 41 as output instead of E2. I need to check deeper into the (undocumented) code of LockBox3 to see what I'm doing wrong (hopefully it isn't MyDAC doing something wrong...)

 


  Codec := TSimpleCodec.Create();
  Codec.StreamCipher := TBase64Converter.Create();
  Codec.BlockCipher := TBlowFish.Create();
  Codec.ChainMode := TCBC.Create();
  SetLength(LBKeyBytes, 34);
  Move(keyBytes[0], LBKeyBytes[1], 32);
  LBKeyBytes[0] := 32; // Length of the key
  LBKeyBytes[33] := 0; // Does the key contain the sotres
  Codec.InitFromStream(TBytesStream.Create(LBKeyBytes));
  Codec.EncryptString('A', outputText, TEncoding.UTF8); // outputText in base64, translated to hex => 41

 

I don't have any experience with LockBox3, and the fact there is memory leak(s) is enough reason to stay away form it, 

 

Anyway.. 41 is Ord('A'), in other word it looks it didn't encrypt anything, to confirm try 'B', if you got 42 then either the library is broken or you are using it wrong ! 

Share this post


Link to post

I'm definitely using it wrong, but them having no docs and considering base64 to be an encryption algorithm doesn't help lol

Edit : encrypting 'ABCDEFGH' lands on the same result with both MyDAC and LockBox3, with the caveat that LockBox3 has another 8 bytes of data. This is probably due to padding, but at least I'm sure the actually encryption is correct, yey ! Just need to figure out the padding. I had to set cfNoNounce in TCBC in order to get an empty IV because I haven't found a way of setting it myself otherwise.

Edited by dormky

Share this post


Link to post

Well, I though I had gotten it to work by using CTR, but I only get the same output up to 8 characters.

You say that they are using CBC, but I can't get that to work using either LockBox3 or C#'s BouncyCastle.

 

I have had contact with the MyDAC support and they refuse to cooperate (they did not mention any specifics of how they are handling encryption and keep referring me to the incomplete documentation).

 

Do you know if any implementation of Blowfish that do not require to be padded to 8 bytes ? Even BouncyCastle, which to my understanding is C#'s main open-sourced cryptography library does not provide such a thing :

 

using System;
using System.Text;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
using System.Security.Cryptography;

namespace blowfish_test
{
    internal class Program
    {
        const string PASSWORD = "pass";
        const string DATA = "ABCDEFGHI";

        static void Main(string[] args)
        {
            byte[] sha1Hash = SHA1.Create().ComputeHash(Encoding.Unicode.GetBytes(PASSWORD));
            byte[] md5Hash = MD5.Create().ComputeHash(Encoding.Unicode.GetBytes(PASSWORD));

            byte[] key = new byte[20 + 12];
            Array.Copy(sha1Hash, 0, key, 0, 20);
            Array.Copy(md5Hash, 0, key, 20, 12);

            var cipher = CipherUtilities.GetCipher("Blowfish/CBC/NoPadding");
            //cipher.Init(true, new ParametersWithIV(new KeyParameter(key), new byte[8]));
            cipher.Init(true, new KeyParameter(key));
            byte[] encryptedData = cipher.DoFinal(Encoding.UTF8.GetBytes(DATA));

            // Display the result
            Console.WriteLine("Encrypted Data: " + BitConverter.ToString(encryptedData).Replace("-", ""));
            Console.ReadLine();
        }
    }
}

This fails, but if you remove the 'I' to have 8 characters you do get the same output as MyDAC. Same output when using 8 characters, but completely different when there's 9.

So I guess the encryption part is correct, but the transition between blocks is implemented differently, and while I can check on what BouncyCastle is doing I can't do the same for MyDAC 😕

Share this post


Link to post
5 hours ago, dormky said:

So I guess the encryption part is correct, but the transition between blocks is implemented differently, and while I can check on what BouncyCastle is doing I can't do the same for MyDAC 😕

Tomorrow will try to figure something for you, no promise though, after almost two hours digging into this, i can say the encryption is utterly broken and non standard CBC, it is wrong !

Share this post


Link to post
11 hours ago, Kas Ob. said:

Tomorrow will try to figure something for you, no promise though, after almost two hours digging into this, i can say the encryption is utterly broken and non standard CBC, it is wrong ! 

Ah. Well isn't that great. This is why I hate proprietary code ; now this project is effectively locked in with MyDAC and has no way of ever getting out of it short of a manual migration of data on demand. Good job from Devart, they win... Although I will still endeavor to do everything I can to move the company away from them. It's personal now 😛 Thank you for your help.

Share this post


Link to post

@dormky I do understand the problem now in all needed depth, i do understand the wrong implementation in TCREncryptor, and it is when DataHeader is set to ehNone, i can solve this and also you can.

 

The buggy implementation is as follow :

1) CBC mode is implemented right, but fall short when the length of the data is not multiple length of blocks of 8 bytes.

2) for all the blocks with 8 it is right CBC, aka xor then encrypt.

3) when there is extra it is doing something wrong, it does encrypt then xor, and that why you are getting identical values with CTR mode when the data is shorter than 1 block, as CTR is not initialized and hold 0.

 

Now, to your need:

 

Up you mentioned Python and in your last post you are using C#, if this is not problem then why not use DevArt broken implementation to decrypt, notice that no matter what are you going to use, you need broken and altered implementation.

 

So you have the ball, decide what and tell me and i will try to help.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×