dormky 2 Posted October 10 I'm using MyDAC components and some of the data is encrypted via use of a TMyEncryptor with a password, see https://docs.devart.com/mydac/devart.dac.tcrencryptor.password.htm But they don't say what the algorithm used to generate the password is. Does anyone here know that ? Share this post Link to post
Kas Ob. 121 Posted October 10 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
Kas Ob. 121 Posted October 10 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
dormky 2 Posted October 11 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
dormky 2 Posted October 11 Just occurred to me that I won't know how they're padding the content... So yeah. Share this post Link to post
Cristian Peța 103 Posted October 11 (edited) deleted Edited October 11 by Cristian Peța Share this post Link to post
Kas Ob. 121 Posted October 11 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
Kas Ob. 121 Posted October 11 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
dormky 2 Posted October 11 > 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
Kas Ob. 121 Posted October 11 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
dormky 2 Posted October 11 (edited) 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 October 11 by dormky Share this post Link to post
Kas Ob. 121 Posted October 11 (edited) 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 October 11 by Kas Ob. Share this post Link to post
dormky 2 Posted October 11 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
Kas Ob. 121 Posted October 11 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
dormky 2 Posted October 11 (edited) 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 October 11 by dormky Share this post Link to post
Kas Ob. 121 Posted October 11 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
Kas Ob. 121 Posted October 11 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); 1 Share this post Link to post
Kas Ob. 121 Posted October 12 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. 1 Share this post Link to post
dormky 2 Posted October 14 (edited) 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 October 14 by dormky Share this post Link to post
Kas Ob. 121 Posted October 14 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
dormky 2 Posted October 14 (edited) 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 October 14 by dormky Share this post Link to post
dormky 2 Posted October 17 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
Kas Ob. 121 Posted October 17 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
dormky 2 Posted October 18 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
Kas Ob. 121 Posted October 18 @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