dormky
Members-
Content Count
111 -
Joined
-
Last visited
Community Reputation
2 NeutralRecent Profile Visitors
The recent visitors block is disabled and is not being shown to other users.
-
Here I was sitting and wondering how the hell it was compiling TThread when it should be TThreadProcedure for it too... Before noticing the overload beneath the function Delphi navigated to. God bless Delphi's function navigation, somehow worse at it than Christopher Colomb. Good job noticing this !
-
Consider : program ProjectThreadProc; {$APPTYPE CONSOLE} {$R *.res} uses System.Classes, Winapi.Windows; type TMyRecord = class data: Integer; class procedure Queue(const AThread: TThread; AMethod: TThreadMethod); end; class procedure TMyRecord.Queue(const AThread: TThread; AMethod: TThreadMethod); begin OutputDebugString(PChar('In TMyRecord.Queue')) end; begin TThread.Queue(nil, procedure begin OutputDebugString(PChar('Hello !')) end); TMyRecord.Queue(nil, procedure begin OutputDebugString(PChar('Hello !')) end); end. This will give you, under 10.3 : [dcc32 Error] ProjectThreadProc.dpr(25): E2010 Incompatible types: 'TThreadMethod' and 'Procedure' Notice that the line for TThread has no problems, and this compiles if you comment the call to TMyRecord.Queue. Problem is, on the face of it those two functions have the exact same signature : So why does TMyRecord.Queue not compile ? I'm baffled. The end goal here is to pass an anonymous function to a thread, to be executed there.
-
Alright, got it. Still cannot work with TColor but it's better then nothing, example : // The highlight colors here are defined twice so the compiler doesn't complain. YELLOW: TColor = $00BBFF; BLUE: TColor = $F0CF89; HIGHLIGHT_COLORS: array[0..1] of TColor = ($00BBFF, $F0CF89); Thanks !
-
const TT = $FFFF; TTARRAY = [$FFFF]; The second line gets "E1012 Constant expression violates subrange bounds", but it's functionally the same as the first one. Is the compiler just dumb or do I need to write this in another syntax ? The actual use case is an array of const TColor. Thanks 🙂
-
query := TMyQuery.Create(nil); query.Connection := conn; query.SQL.Text := 'SELECT * FROM data'; query.Execute(); Every time I do something like this, a new connection to the MySQL server is established. How can I make it use the already-opened 'conn' connection ? Thanks 🙂
-
What is the algorithm used to derive the key to a TMyEncryptor ?
dormky replied to dormky's topic in Databases
Okay, so according to my understanding CBC xors the plain data with the previous block (encrypted) before applying encryption. And here instead, the plain data is encrypted directly and then xor'd with the last block. In this case, if I were to truncate my data to 8-bytes blocks, then encrypt the bytes that were removed by themselves with an IV of all 0 I could then xor the result with the last block myself, thus landing on the same result as MyDAC ? Since the last few bytes would be xor'd with the zeroed IV they wouldn't be changed before encryption, just like MyDAC is doing here. -
What is the algorithm used to derive the key to a TMyEncryptor ?
dormky replied to dormky's topic in Databases
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. -
What is the algorithm used to derive the key to a TMyEncryptor ?
dormky replied to dormky's topic in Databases
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 😕 -
What is the algorithm used to derive the key to a TMyEncryptor ?
dormky replied to dormky's topic in Databases
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. -
What is the algorithm used to derive the key to a TMyEncryptor ?
dormky replied to dormky's topic in Databases
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 !! -
What is the algorithm used to derive the key to a TMyEncryptor ?
dormky replied to dormky's topic in Databases
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 ! -
What is the algorithm used to derive the key to a TMyEncryptor ?
dormky replied to dormky's topic in Databases
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 ? -
What is the algorithm used to derive the key to a TMyEncryptor ?
dormky replied to dormky's topic in Databases
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. -
What is the algorithm used to derive the key to a TMyEncryptor ?
dormky replied to dormky's topic in Databases
> 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. -
Best way to store and compare PC configuration data
dormky replied to Shrinavat's topic in Algorithms, Data Structures and Class Design
Doing a file-based comparison will always lead you into problems where something changes, but it's not something that actually impact the configuration in real-life. Better to write code to handle the comparison. If you really don't want to do that, you need empty spaces ie reserve 30 lines for drives and when saving, always sort alphabetically. Each field would have a specific length so no offset changes. But it's going to be a pain. Maybe separate the data you actually want to compare ; even in a single file you can have a marker like a line of '|' after which the data resides and you have a very small script to compare that part of the file and not the rest.