4

I recently took some code from Delphi 2007 and upgraded it to Delphi 2009. That may or may not be relevant.

But when I run the code on my computer the decryption of the password is not decrypting correctly. Here is the code.

Seed := GenerateIntFromString('usercode');

// Check if a password already exists
if TableUser.FieldByName('PASSWORD').AsString <> '' then
begin
    EncodedPassword := TableUser.FieldByName('PASSWORD').AsString;
    DecodedPassword := EncryptDecrypt(EncodedPassword, Seed);
//etc.. And the function

function TLogonForm.EncryptDecrypt(Input: string; Seed: integer) : string;
var
i : integer;
Output : string;
begin
    RANDSEED := Seed;
    Output := '';
    for i := 1 to Length(Input) do
        Output := Output + Chr(Ord(Input[i]) XOR (RANDOM(254) + 1));
    Result := Output;
end;

So if my usercode is TD and my password is 'JOEJOE'

the encrypted password is: ì?Âp?

the decrypted passowrd is: JìEJùE

It should decrypt as JOEJOE obviously. The kicker, if I build the code and send the exe to another user it decrypts fine. This leads me to believe its not something wrong with the code rather some anomaly with my computer. What could it be?


You can disgard this because its probably not related. I only mention it because it's another case where something works fine on one computer but not the other.

But there is also one case where when trying to set a filter

TableUser2.Filter := FilterString;

it works fine for me, but the other user gets an error.

TableUser2: Error 3106: Unsupported operator found in a record filter expression.

Even when we filter by the same name running the same code. Maybe a database issue?

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
Trevor
  • 16,080
  • 9
  • 52
  • 83
  • 5
    I suspect that the code you have shown us is not the ONLY broken code. Your method EncryptDecrypt is not being properly ported from Non Unicode Delphi to Unicode Delphi. You are aware of course that a String, and a Char used to be a byte size per character, and are now two bytes per Char? – Warren P Dec 14 '11 at 16:18
  • Resources: http://stackoverflow.com/questions/1598211/delphi-conversion-unicode-issues – Warren P Dec 14 '11 at 16:20
  • I am actually not aware of that. I just barely started working with this code. And have limited experience with encryption. How can that information that Char information help me? Thanks p.s. I got your link. – Trevor Dec 14 '11 at 16:23
  • 2
    Dude, that's the biggest fact to know about Delphi 2009- Hello Unicode! Read the Resources link I posted above. Encryption is not the issue, your lack of knowledge about what Char and String mean in Delphi 2009 are the issue. – Warren P Dec 14 '11 at 16:24
  • With Unicode you cannot just assign a random byte to a character because not all values of 0 to 255 have valid Unicode equivalent characters. I was bitten by this too. – Misha Dec 15 '11 at 00:58
  • I believe every value from 0 to 255 is in fact a valid Unicode codepoint. however not all values from 0 to $FFFF hex are always and everywhere accepted. – Warren P Dec 15 '11 at 16:04

3 Answers3

7

Try doing a port from Ansi to Unicode like this:

function TLogonForm.EncryptDecrypt(Input: AnsiString; Seed: integer) : AnsiString;
var
i : integer;
Output : AnsiString;
begin
    RANDSEED := Seed;
    Output := '';
    for i := 1 to Length(Input) do
        Output := Output + AnsiChar(Ord(Input[i]) XOR (RANDOM(254) + 1));
    Result := Output;
end;

My best wild guess is that the expected results are different because of the difference between AnsiChar and UnicodeChar. If you managed to generate some invalid codepoints that can't be stored in your DB's non-unicode data field, you might have some fun errors.

Warren P
  • 65,725
  • 40
  • 181
  • 316
  • There's no adding of 250 to 250 here. The only `+` is string concatenation. I expect the code in the Q breaks due to codepage mismatches. – David Heffernan Dec 14 '11 at 16:30
  • 3
    You might want to ensure that you can decrypt older passwords because Delphi says `Note: Because the implementation of the Random function may change between compiler versions, we do not recommend using Random for encryption or other purposes that require reproducible sequences of pseudo-random numbers.` – Marcus Adams Dec 14 '11 at 18:01
  • Good thought i'll look into it. – Trevor Dec 14 '11 at 18:10
  • Oh yeah. I should have noticed that this isn't a reproducible encryption system. (RANDOM(254) using a particular seed isn't forever going to have the same behaviour for all time). – Warren P Dec 16 '11 at 21:34
1

Your issue is that Delphi 2009 uses Unicode rather than ANSI for its text. This was a major breaking change which requires significant porting effort. Not only do you need to deal with encoding issues in your code, you will need to upgrade any 3rd party components that you use.

You can revert to the previous behaviour for this particular function like this:

function TLogonForm.EncryptDecrypt(Input: AnsiString; Seed: integer): AnsiString;
var
i : integer;
Output : AnsiString;
begin
    RANDSEED := Seed;
    Output := '';
    for i := 1 to Length(Input) do
        Output := Output + AnsiChar(Ord(Input[i]) XOR (RANDOM(254) + 1));
    Result := Output;
end;

In Delphi 2009 the string data type is a UTF-16 encoded string. The ANSI encoded string that previous versions of Delphi is named AnsiString. Similarly Chr() generates a 16 but WideChar character but you want an AnsiChar, the 8 bit ANSI character type.


However, there will surely be a number of other issues to tackle. I suggest you read Marco Cantù's whitepaper on Delphi and Unicode. You really should get on top of the issues detailed in this paper before proceeding any further with the port.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
0

The first thing I would do is put some logging around the inputs / outputs of your functions.

It really sounds like maybe the value in TableUser.FieldByName("Password") isn't passing what you expect in both cases.

Another thing I would pay attention to is the database collation in use with both machines. I'm assuming that the underlying database is different between your two test cases; or, at the very least, the connection string info has different values for collation. This could certainly throw off the decryption.

NotMe
  • 87,343
  • 27
  • 171
  • 245
  • The dude is unaware of the language change from Char=byte to Char=2 bytes between Delphi 2007 and Delphi 2009. He has more problems than he is even aware of yet. – Warren P Dec 14 '11 at 16:26
  • @WarrenP: I agree. My answer isn't material here. – NotMe Dec 14 '11 at 16:27